
能跑 10 分钟的 Agent和能上线 10 个月的 Agent差在哪系列导读本系列尝试回答一个具体问题——当 Agent 不再是一次请求而是一个可能持续几十分钟、会中断、会失败、要花钱、要被人看懂的有状态长事务时生产系统该一条一条补上什么。第一篇本文能跑 10 分钟和能上线 10 个月差在 Agent 是一笔有状态的长事务上线就是把这笔事务该有的东西补齐。第二篇向人提问时这一轮怎样提交成等待刷新和隔天再答都还能接上。第三篇子 Agent 删了三次因为它是另一笔事务多数能力只是当前这一轮里的过程。第四篇接入和执行拆开开单、回放和把这一轮跑完不再绑在同一个进程上。第五篇事实、传输、恢复点、执行现场分开存Checkpoint 不能当作数据库。第六篇成功、中断、取消、异常收成同一个提交点执行不能靠重试再做一遍。第七篇254KB 的记忆怎样烧掉十几万 token这笔预算取决于注入多少、何时注入、谁来写。第八篇轮次账本、租约、公平队列、能力评测、文档五处还没补上现状离那句话还有多远。内测刚开始那几天有个用户刷新了一下页面。半小时的对话只剩一半。前端贴了张截图刷新前四个工具卡片刷新后只剩一个。用户的原话是“你们这系统一刷新就没了。”数据库一条没少日志没有报错。实时流按 chunk 推历史回放按消息给前端只认前者。数据都在同一次执行没有同一份可读的形状。刷新只是这种系统的第一次体检。执行还在观看断了两边各交了一份对不上的记录。缺的是长事务里的一条中断之后过程还要能被人看懂。一、先看 demo 里怎么写任何人第一版都长这样app.post(/chat)asyncdefchat(req):forchunkinagent.stream(req.message):# 一轮 一次请求yieldsse(chunk)# 直接推给这条连接状态在进程里进度在这条连接上执行在这个函数里。三轮对话、一次工具调用、一张流程图跑得很好——demo 的成功标准里没有浏览器关了怎么办。对外测试第一周这段代码遇到四件事刷新。连接断了后半段输出再也拿不回来。开头那张截图是修完能补之后暴露的第二层补回来的格式和实时推的不一样。重启。发布滚动更新正在跑的那一轮连人带状态一起没了会话永远停在运行中。扩容。想加第二个副本发现这条连接绑在这个进程上加了只会让一半请求找不到自己的流。等待。它问了一句选哪个用户去开会两小时后回来。进程不可能挂两小时。四件事没有一件能靠代码写得更小心解决。它们各自要求系统补上一个东西。拿掉模型、提示词和框架剩下的是Agent 不是一次请求是一个可能持续几十分钟、会中断、会失败、要花钱、要被人看懂的有状态长事务。生产化就是一条一条把这种长事务该有的东西补齐。这句话拆开是五件事它比进程活得长所以有状态——状态得放在进程外面连接会断所以会中断——中断是正常路径执行会出错所以会失败——失败要落成终态上下文有硬上限所以要花钱——每一轮都要算预算过程要给人看所以要被人看懂——事件就是契约。长事务我们只取两样状态在进程之外提交点要明确。回滚和隔离级别留在数据库里。Agent 的失败不靠撤销靠终态写清楚Agent 的隔离不靠两个事务怎么读同一行靠执行现场分开。后面每一篇都是在补上面的某一项。这些项不成立提示词只优化那条没断过的路径。二、五件事逐项拆开上面四件事归起来是两条状态不能只活在进程里连接不能持有状态。另外三条是跑起来之后才疼的失败要收得住上下文有预算过程要能被看懂。五项缺了任何一项都会得到一种 demo 里不存在的故障。有状态进程会死状态不能只活在进程里也不能只存一份。一轮执行横跨多次发布。状态必须外置。外置到哪里由这份数据负责什么决定。我们拆成四种。介质可以重叠职责不能重叠职责放哪合错了会怎样可查询的事实消息、轮次、费用、审计数据库没有账就不能计费也不能对用户解释这一轮可丢失的传输队列、扇出、在途事件Redis把它当事实重启就丢对话框架恢复点图要接着跑的那份快照checkpoint把它当账本不可查询而且每次都整份读写执行现场代码真正读写的文件沙箱把它当共享磁盘租户互相看得见Checkpoint 经常就落在数据库里。这不使它变成账本。它是框架私有格式的整图快照不能按用户、轮次、金额去查长对话下每次触碰都是全量读写。巨型轮次收尾时的同步序列化我们测到能把新任务排队拖到 P90 55 秒。恢复点负责接着跑账本负责说得清。用同一份 blob 干两件事两边一起坏。会中断连接会断连接就不能持有状态。一条 SSE 推到底等于宣布连接还在这一轮才看得见。网络抖一下计算可能还在跑观众已经丢了后半段。开单和观看要分开。Submit 只受理这一轮落库、排队、返回。内容一律从 resume 读。在途事件可以走队列已经结束的轮次走已经落库的事实两边必须交出同一种事件。来源可以有两个形状只能有一个。客户端因此只有一种读法。刷新、断线重连、多端同时看都是换一个游标把这份契约再读一遍。文章开头那张截图——四个卡片变成一个——就是两种形状各说各话。会失败终态要写清楚执行现场要被挡住。失败先要有终态。一轮是完成、中断、取消还是失败必须写进账里。连接断了不等于这一轮没有结果。终态写清之后还要挡住失败的半径。这一轮的代码是模型现写的。它可能删文件可能读到别人的数据可能把密钥打进日志。Demo 里操作者和租户是同一个人。多租户里同一条删除命令就是事故。要隔离的不只是进程还有路径。容器里的真实路径一旦出现在提示词里模型会照着写把部署细节带进用户看得见的地方。要花钱工作记忆是预算不是缓冲区。传统后端内存不够就加机器。上下文加不了。硬上限到了调用失败没到费用已经按 token 计上了。有一次一张 317KB 的照片进了上下文单次调用到约 30 万 token吃掉窗口的六成。预算从什么允许进入这一轮开始管。等溢出再截断钱已经花了窗口也已经碎了。要被人看懂过程一旦被读走就是契约。用户要知道卡在哪一步前端要决定渲染哪一种卡片审计要追到谁授权了哪一次副作用。三方读的是同一份过程。事件一旦被前端读取就从内部跟踪变成契约。改一个字段就是改协议。有状态长事务有状态会中断会失败要花钱要被人看懂事实 / 传输 / 恢复点 / 现场开单与回放分离终态与沙箱上下文按预算装载事件是契约图 1长事务要补齐的五项。持续几十分钟是它们共同的寿命比进程长也比连接长。和 demo 的默认假设放在一起差在各自优化的目标Demo 在优化什么生产要优化什么一条连接跑到结束连接随时断计算继续观看可以重来状态留在框架的 checkpointer 里事实可查询、可审计、可计费恢复点只负责续跑沙箱等于本机进程执行的是不可信代码要隔离要留痕上下文装得下这次演示上下文是预算超了会失败没超也在花钱输出是一段文本输出是前端、审计和用户共用的事件契约三、为什么在 DeerFlow 上打补丁会越打越别扭起步时我们 clone 了 DeerFlow。它是一个好的研究型 Agent 项目图、人机中断、技能、子代理我们都是从那里跑通的。要改的是它的目标函数。DeerFlow 优化的是单租户、单进程、操作者可信尽快证明它能做。我们要优化的是多租户、多进程、执行不可信失败之后仍能说清它做了什么。这两组前提的梯度是反的。前一组上的局部最优会系统性破坏后一组。对外测试之后三个假设都是从主路径上爆的。一次会话 进程内的一条 SSE。一个人、一个浏览器、不刷新这是最短路径。网络一抖事件就丢worker 一重启这一轮的可见进度就没了gateway 要加副本会话还粘在原来的进程上。状态 checkpointer。图自己续跑这份快照够用。它不可查询、不可审计、不可计费还随消息线性增长。上面那个 P90 55 秒就是把恢复点当成账本之后付的钱。沙箱 本机进程用户可信。作者自己的电脑上成立。多租户下删除命令、漏进提示词的容器路径、同一台机器上互相可见的用户文件都从这里来。Demo 要证明能力存在。生产要证明能力用错时爆炸半径有限过程还查得到。两套目标的工程重点几乎不重叠。补丁因此会打在框架的反方向上。在连接即状态的主路径上补重连在私有快照上补审计在本机进程上补租户。每个补丁都在对抗这条路径当初被优化的方向。后来改掉的是这三句假设。四、四幕换掉的是什么可以当真下面四幕就是一条一条补齐的实际顺序。先补了人怎么用后补了事务怎么活下来。从仓库第一个提交算起现在有三千多个提交不少是跟上游同步。把它变成产品的是今年 6 月以后的一千四百多个。四幕里每一幕作废一批此前为真的假设。第一幕跟上游。头一年在同步 DeerFlow人机中断、搜索、Web UI、技能、子代理。学会了图怎么跑也原样收下了单进程、可信执行。第二幕平台化。今年上半年同一套运行时撑起十来个业务 Agent文档、数据、流程、分析。技能包加命令行确实能操作已有的内部系统。同一套进程假设也被复制了十来份每个业务都在自己的循环里持有状态。第三幕产品化。6 月到 7 月新一代产品立项两条原本独立的业务线收进一个 Agent再补上产品才要的交互向人提问、先出计划再执行、危险操作二次确认、任务堆积时提醒。两个月六百多个提交几乎全在交互上。人进入了回路等待和恢复仍绑在框架那一条执行循环上。第四幕工程化。8 月对外测试。故障从模型答错变成刷新、发布、排队和账单。换运行时拆开接入和执行修收尾压性能重做记忆补 trace。最近两个多月六百多个提交一百三十多个是 fix。第一幕 跟上游继承单进程假设第二幕 平台化假设复制到多个业务第三幕 产品化人进入回路恢复仍在框架循环里第四幕 工程化故障域变成进程、连接、账单图 2产品化在前工程化在后。债是这个顺序欠下的也只有这个顺序才看得清。我们是先让人用起来才知道地基错在哪。没有刷新丢卡片、排队 P90 55 秒、一张图片打满窗口这些现场第一幕结束时那套单进程结构看起来就是完整的。五、三次走错是同一种混淆子 Agent删了三次。5 月在一个业务 Agent 上删了一次7 月在它的流程能力上删了一次9 月把业务子 Agent 收成技能包又删了一次。跨两个产品线同一个判断犯了三遍把一次能力调用做成了一个新的执行域。子 Agent 自带状态、权限和账单。技能包是当前这一轮里的一段过程。要的是过程付的是一个新事务的成本。记忆换了四代。自己写的分桶 JSON然后是框架自带的文件方案然后是独立记忆服务最后把写权限从模型收回到轮次收尾。中间一次事故把方向钉死单个用户的记忆文件涨到 254KB每轮全量注入约 14 万 input token首个响应 chunk 延迟 25 到 40 秒。那是把记忆当成了提示词前缀。它应该按本轮问题检索写不写由系统在收尾时决定。工具契约两天改了四次。一个文件展示工具的入参四十八小时里变了四版。模型侧这是提示词调整。前端侧这是协议破坏卡片怎么渲染、历史怎么回放都绑在这组字段上。事件被 UI 读取之后schema 和对外 API 同一级别。三件事的共同错误把模型多做一步当成了局部改动。这一步落在状态、权限、费用或协议上就是长事务的边界。补的时候补错了位置。六、这个系列写什么不写框架教程也不写一份最佳实践清单。系统还在内测眼下的结构还不是标准答案。写每种故障的现场、当时的判断、后来的代价以及长事务的哪一项今天还没补完。这些故障不依赖具体业务。换一个框架该补的还是这几项。七、接下来七篇按踩坑的先后不按重要性《Agent 怎么向人提问》——提问、表单、计划确认、危险操作确认。等人的那段时间仍是一轮执行一样会断一样要能重放。《我们删了三次子 Agent》——能力是当前轮次里的过程还是一个新的执行域。《我们把 Agent 从框架的运行时里抠了出来》——接入层开单、回放执行层把这一轮跑完。粘在一起就无法扩也无法在发布时活下来。《Checkpoint 不是数据库》——恢复点、账本、在途传输为什么不能合成一份。断线重连和假死自愈从这里来。《一百三十个 bug 之后Agent 轮次的四种死法》——收尾是提交点。不收敛成一个函数每种死法都会把账做脏。《254KB 的记忆烧掉了 14 万 token》——上下文是预算。全量注入是把档案当寄存器。《我们还没解决的 5 个问题》——轮次账本、租约、公平队列、能力评测、文档漂移。八、可以带走的一句正在把 Agent demo 推向生产不必照搬我们的存储划分或进程划分。只要它不再是一次请求这几件事会自己出现刷新对不齐重启丢掉半轮工具副作用无法撤销上下文突然变贵前端跟不上字段。先让这句话成立再写 promptAgent 不是一次请求是一个可能持续几十分钟、会中断、会失败、要花钱、要被人看懂的有状态长事务。生产化就是一条一条把这种长事务该有的东西补齐。下一篇从最容易被当成小工具的地方开始Agent 停下来向人问一句话。6 月到 7 月和等人回答有关的提交有几十个。到上周这块还在改。为保护项目与客户信息文中系统名、工具名、业务场景和具体数值均做了抽象或区间化处理技术结论不受影响。这套系统还在内测判断若有漏洞欢迎直接指出。