资讯动态

从零搭建能干活儿的AI助手:持久任务、沙箱与多角色群聊实战

发布时间:2026/10/17 3:41:24 来源:尧图企业网站定制
1. 为什么我要自己搭一个AI助手市面上的对话工具用了一圈我最大的感受是它们都很聪明但都不太能干。你问它一个问题它答得头头是道你让它帮你把一件事从头跟到尾它就开始装傻。比如帮我盯着这个数据表每天汇总一次变化或者这段代码跑一下把报错贴给我再或者拉几个不同角色的助手一起讨论下这个方案——这些事现成的产品要么做不了要么得加钱上企业版要么干脆把你锁在它的生态里。所以从去年底开始我断断续续花了几个月从零搭了一套自己的AI助手系统。核心就三件事持久任务能记住、能定时、能长期跟进、沙箱能安全地跑代码、跑命令、读写文件、群聊多个不同角色的助手能在一个会话里协作。这套东西跑起来之后我日常大概有三分之一的事务性工作交给了它包括定时抓数据、跑脚本、整理文档、做多轮方案评审。这篇文章不讲虚的我会把整个搭建思路、关键选型、核心代码结构、踩过的坑全部摊开讲。适合两类人看一是有点编程基础、想自己动手搭一套的开发者二是产品或者技术负责人想搞清楚一个能干活儿的AI助手到底由哪些部件组成。哪怕你暂时不写代码看完也能明白这套系统的边界在哪、难点在哪。先给个整体印象这套系统不是一个模型而是一个调度中枢 一组工具 一层记忆 一个多角色会话层。模型只是其中最容易被替换的那块零件。真正决定它能不能干活儿的是外围这套骨架。2. 整体架构设计与核心思路拆解2.1 三个能力对应三套机制我把需求拆成三块每块对应一套独立机制互相之间通过统一的消息总线通信。这样设计的好处是任何一块出问题或者要替换都不会牵动全局。持久任务解决的是时间维度的问题。普通对话是即问即答一问一答结束就没了。持久任务要求系统能记住有这么一件事还没做完并且能在未来的某个时间点主动触发。这背后需要三样东西任务队列、调度器、持久化存储。我用的是最朴素的方案——SQLite存任务定义和执行历史一个常驻的调度循环每隔几秒扫一次到期任务。为什么不用Redis或者消息队列因为我的任务量级很小几十到几百个SQLite完全扛得住而且零运维重启不丢数据。这是典型的用够用的方案而不是用最潮的方案。沙箱解决的是执行维度的问题。模型能生成代码但生成的代码不能直接在你主机上跑——万一它写了个rm -rf呢所以必须有一个隔离的执行环境。我选的是容器化隔离每个任务在一个临时容器里跑跑完就销毁。容器里预装了Python、Node、常用命令行工具挂载一个临时工作目录。模型要执行代码就走生成代码 → 写入沙箱 → 执行 → 回传结果这个闭环。群聊解决的是协作维度的问题。单个助手能力再强视角也单一。群聊机制让多个不同系统提示词的助手在同一个会话里轮流发言比如一个负责提方案、一个负责挑毛病、一个负责落地细节。这里的关键不是让它们聊天而是发言顺序控制和上下文裁剪——不然几个助手会互相复读token烧得飞快。2.2 为什么是中枢 工具而不是大模型一把梭很多人第一反应是现在模型不是能调工具吗直接让它调不就行了我试过结论是能调但不能全靠它调。模型调工具有两个硬伤。第一是不可靠它可能忘记调、调错参数、或者在不该调的时候调。第二是不可控你没法保证它在执行危险操作前一定停下来问你。所以我采用的是中枢主导 模型建议的混合模式中枢负责决定现在该不该执行、执行哪个工具、参数合不合法模型只负责生成候选动作和理解执行结果。相当于模型是参谋中枢是司令。这个思路贯穿整套系统。比如持久任务里模型可以建议这个任务应该每天跑一次但真正把它写进调度表、计算下次触发时间、处理失败重试的是中枢的确定性代码。确定性的事情交给代码模糊判断交给模型这是我踩了很多坑之后总结出的第一条铁律。2.3 记忆分层短期、长期、任务态记忆这块我分了三层对应不同的生命周期。短期记忆就是当前会话的上下文滑动窗口管理超过阈值就压缩摘要。长期记忆是跨会话的事实性知识比如用户偏好用Python而不是JS、某个项目的数据库连接方式存在向量库里需要时检索注入。任务态记忆是持久任务专属的记录某个任务执行到哪一步、上次结果是什么、有没有异常这部分是结构化的直接存表里。为什么要分三层因为它们的读写频率、检索方式、失效策略完全不同。混在一起会导致要么检索太慢要么上下文被无关信息撑爆。分开之后每层各司其职调试起来也清晰——出问题先看是哪层记忆的锅。3. 持久任务系统的核心实现3.1 任务模型怎么设计一个持久任务我抽象成这么几个字段任务ID、任务描述、触发规则cron表达式或一次性时间点、执行动作要调哪个工具、传什么参数、状态待执行/执行中/成功/失败/暂停、重试策略、上次执行时间、下次执行时间、执行历史。这里有个设计决策值得说执行动作不存自然语言存结构化指令。比如每天早上九点汇总销售数据这个需求在创建任务时就会被翻译成{tool: run_script, params: {script_id: daily_sales_summary}}。为什么因为自然语言每次执行都要重新理解一遍既慢又不稳定。创建时翻译一次之后每次执行都是确定性的。翻译这一步由模型完成但翻译结果要经过校验才能入库。重试策略我用了指数退避第一次失败等1分钟第二次等5分钟第三次等30分钟超过三次标记为失败并通知。这个策略对网络抖动类的临时故障很有效对逻辑错误类的失败则快速暴露。3.2 调度循环怎么写才稳调度器是整个系统的心跳它必须足够简单、足够健壮。我的实现是一个单线程循环每5秒执行一次while True: now current_time() due_tasks query_tasks(next_run_at now, statuspending) for task in due_tasks: mark_running(task) result execute_with_timeout(task, timeout300) handle_result(task, result) sleep(5)看着简单但有几个坑必须处理。第一任务执行不能阻塞调度循环。如果某个任务跑了5分钟这5分钟里其他到期任务全被卡住了。我的做法是把执行丢到线程池里调度循环只负责派发不负责等待。派发后立即更新任务状态为执行中等执行线程回调再更新最终状态。第二要防止任务重复触发。如果一次调度扫描时任务A到期了派发出去但状态更新有延迟下一次扫描又扫到它怎么办我在派发前先做一次原子性的状态更新UPDATE ... WHERE statuspending只有更新成功的才派发。数据库的行锁保证了这一点。第三时间要用统一时区。我一开始混用了本地时间和UTC结果定时任务在夏令时切换那天全乱了。后来统一全部存UTC展示时再转本地时区。3.3 任务执行结果怎么回传和通知任务执行完结果要回到用户能看到的地方。我的设计是结果先写进执行历史表然后根据任务配置决定通知方式——可以是写进某个会话、发邮件、或者调一个webhook。这里有个细节长输出要截断。有些任务会产出几千行日志全塞进会话会把上下文撑爆。我的做法是结果超过2000字符就存全文到文件会话里只放摘要加文件引用。用户想看全文再单独拉。实操心得任务执行历史一定要保留原始输出哪怕会话里只显示摘要。我遇到过好几次任务报错了但摘要看不出原因全靠翻原始日志才定位到问题。4. 沙箱环境搭建与安全边界4.1 为什么必须上容器隔离我最初图省事直接在主机上用一个子进程跑模型生成的代码。结果有一次模型生成了一个死循环把CPU占满整台机器卡死。还有一次它试图写系统目录权限报错倒是拦住了但吓出一身冷汗。从那以后我坚定用容器隔离。每个执行请求起一个临时容器用最小化基础镜像只装必要的运行时。容器启动时挂载一个临时目录作为工作区执行完把工作区里的产出文件复制出来然后销毁容器。这样即使代码里有恶意操作影响范围也被限制在容器内。4.2 资源限制的具体参数容器不是起了就完事必须加资源限制否则一个失控的容器能把宿主机拖垮。我用的参数大致是限制项参数值说明CPU1核单任务够用防止跑满内存512MB大部分脚本足够超了直接OOM执行超时300秒超时强制kill磁盘写入100MB工作区配额防止写爆网络默认关闭需要联网的任务单独开白名单网络这块特别说一下。默认我是不给容器联网的因为大部分代码执行任务不需要网络。需要联网的比如抓数据走单独的配置并且限制只能访问指定的域名。这样即使代码里有外联行为也出不了圈。4.3 代码执行的完整闭环一次代码执行请求从模型生成到结果回传走这么几步模型生成代码附带语言标识和预期输出说明中枢校验代码长度、危险模式匹配比如检测到明显的文件删除、系统调用就拦截起容器把代码写入工作区在容器内执行捕获stdout、stderr、退出码收集工作区产出文件销毁容器把执行结果格式化后回传给模型或用户第2步的校验是道防线但不能全指望它。真正的安全靠的是容器隔离本身校验只是提前拦掉一些明显问题省得浪费资源起容器。注意不要试图用正则去穷举所有危险代码这是徒劳的。隔离才是根本校验只是优化。4.4 文件读写的处理沙箱里的文件读写有个容易忽略的点路径穿越。模型可能生成../../etc/passwd这样的路径。我的处理是在写入前对路径做规范化然后检查是否落在工作区目录内不在就拒绝。这个检查必须在容器内的执行层做不能只在调度层做因为容器内才是真正落盘的地方。产出文件的收集也有讲究。我一开始是把整个工作区打包出来结果有时候工作区里有临时文件、缓存文件一大堆没用的东西。后来改成只收集执行前后有变化的文件用文件哈希对比干净很多。5. 多角色群聊协作机制5.1 角色怎么定义群聊里的每个角色本质上是一套系统提示词加一组可用工具。比如我常配的几个角色方案助手擅长发散负责提思路、列选项评审助手擅长挑刺负责找漏洞、提反对意见执行助手擅长落地负责把方案拆成具体步骤总结助手负责在讨论到一定程度后收敛结论每个角色的提示词里会明确它的职责边界比如评审助手会被要求必须找出至少三个潜在问题不允许只夸奖。这种强制性的角色约束能让讨论真正产生张力而不是几个助手互相附和。5.2 发言顺序与轮次控制群聊最容易失控的地方是发言顺序。如果让模型自己决定谁发言它要么一直让同一个角色说要么陷入你说我说的死循环。我的做法是中枢控制轮次设定一个讨论轮数上限比如3轮每轮按固定顺序让各角色发言每轮结束后由总结助手判断是否达成共识达成则提前结束。每轮发言时其他角色的历史发言会作为上下文注入但会做裁剪——只保留最近两轮的关键内容更早的压缩成摘要。这样既保证角色之间能互相看到观点又不至于上下文无限膨胀。5.3 上下文裁剪的具体策略上下文管理是群聊能不能长期跑的关键。我的策略分三级完整保留当前轮次的所有发言摘要保留前一轮的发言压缩成要点丢弃两轮之前的发言只保留结论压缩用一个小模型来做成本低、速度快。实测下来一个5角色、5轮的讨论如果不做裁剪上下文能到几万token裁剪之后稳定在几千token成本降了一个数量级讨论质量几乎没损失。5.4 群聊和持久任务的结合这两个能力结合起来才是真正好用的地方。比如我配了一个每周方案评审的持久任务每周一早上自动触发拉取本周待评审的方案文档起一个群聊让方案助手、评审助手、执行助手过一遍最后总结助手输出评审意见写回文档。整个过程无人值守我周一上班直接看结论。这种定时触发 多角色协作的组合是我这套系统里用得最多的模式。6. 常见问题与排查技巧实录6.1 任务不触发怎么办这是最常见的问题。排查顺序我固定成这么几步排查项检查方法常见原因调度器是否在跑看进程和心跳日志进程挂了、被系统杀了任务状态查数据库status字段卡在running没释放下次触发时间查next_run_at时区算错、cron解析错是否被暂停查paused标记连续失败被自动暂停我遇到最多的是卡在running。原因是执行线程崩了但没更新状态。后来加了个兜底调度循环每次扫描时把running超过1小时的任务强制标记为失败并重试。6.2 沙箱执行超时或OOM超时和OOM通常意味着代码有问题但也可能是资源给少了。我的处理是先看是不是死循环或者内存泄漏如果是代码问题就反馈给模型让它改如果代码看着正常就把资源限制调大一档重试。同时记录这类case如果某个任务频繁超时说明它的资源需求就是大给它单独配更高的限额。6.3 群聊陷入复读几个助手开始互相复读我同意你的观点这种废话是群聊的典型失败模式。根因通常是角色提示词区分度不够或者轮次控制失效。我的解法有两个一是强化角色约束明确要求每个角色必须提出新信息二是在总结助手那里加一个检测复读的逻辑发现连续两轮没有新观点就提前终止讨论。6.4 成本失控多角色群聊加持久任务token消耗很容易失控。我踩过的坑包括群聊轮数没上限、任务执行结果全量注入上下文、长期记忆检索返回太多。后来定了几个硬规则群聊最多5轮、单次注入上下文不超过8000token、长期记忆每次最多检索5条。这几条一上成本直接降了七成。实操心得给每个能力都设一个预算上限超了就降级或者终止。宁可少做一点也不要账单爆炸。7. 我实际跑下来的一些体会这套系统从能跑到好用中间隔了大概两个月的调优。最大的体会是模型能力不是瓶颈工程细节才是。任务调度的时间处理、沙箱的资源限制、群聊的上下文裁剪这些看起来不起眼的地方才是决定系统能不能稳定干活的关键。另一个体会是确定性优先。凡是能用代码确定性地完成的事就不要交给模型。模型适合做模糊判断和内容生成不适合做状态管理和流程控制。把这两者分清楚系统的稳定性会有质的提升。最后分享一个我最近在用的扩展方向把这套系统接到消息平台上让持久任务的结果直接推到手机群聊讨论也能在手机上参与。这样它就从一个后台工具变成了一个随时能找到的助手。这个扩展本身不难难的是消息格式的适配和权限控制我还在慢慢磨。如果你也在搭类似的东西建议先把核心三件套跑通扩展的事后面再说别一上来就铺太大。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑