文章目录

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程传送门http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

我们团队内部有个不太正经的统计:一个创作者做完一支三十秒的短片,平均要在对话框里敲十七次“继续”。

剩下三次是问“你还在吗”。

这个数字后来成了我改架构的第一推动力。不是因为它刺眼,是因为它准确得让人想提交离职申请。

所以下面这些内容,不是一份漂亮的架构图解说,是我把一个“会自己干活的创作代理”从纸面搬到线上时,被现实反复上课的记录。哪些是真的跑起来了,哪些还在试,我会分开说。

1 会话这个东西,人类其实不怎么维护

先问一个很小的问题:为什么 Agent 一定要以“会话”为中心?

我用过的大多数产品都是这个范式——你自己建会话、自己起名字、自己找回来。轻量用户没感觉,重度用户很快进入一种状态:左边栏拉到第三屏,还是没找到上周那组海报。

我见过最诚实的一组会话命名是这样的:“新建会话”“新建会话(2)”“新建会话(37)”。

这不是用户懒。这是产品把一件本该机器做的事,外包给了人。

1.1 用户不该兼职做上下文管理员

现实里没人维护“会话”。我们会随时换话题,也会隔三天突然想起一件没做完的事,然后一句“那个再改改”就想接着聊。

如果系统要求你先找到那个会话、再想起当时叫什么名字、再确认是不是同一个项目——那它其实是在收“记忆税”。

所以我们的做法是:把用户侧的会话概念直接弱化掉。用户只有一个入口,想说什么说什么。任务识别、上下文隔离、历史关联,系统自己扛。

1.2 拆成三层,别让一锅粥互相污染

但“交给系统”这四个字很好说,做起来是两个方向的坑。

所有任务共用一份上下文,不同目标互相干扰,模型的窗口迅速塞满,最后它在第五轮开始聊三周前那只猫。

完全按会话隔离,历史又断了。用户说“上次那套”,系统一脸茫然,像刚入职三天的实习生。

我们最后分成三层:

1.2.1 交互入口

用户在哪表达需求。统一主线,不新建、不切换、不命名。

1.2.2 执行上下文

哪些信息该一起喂给模型。按目标建独立事项,各有边界,各算各的账。

1.2.3 长期记忆

跨事项、跨时间哪些东西值得留。来源可追溯的画像、事实、情景摘要,按需召回,不搞全量灌输。

顺手说一句:自动识别一定会出错。所以我们保留了显式事项入口和纠错通道;目标明确时优先走确定性路由,能不用模型判断就不用。让模型去猜一件本来就知道的事,属于花钱买延迟。

2 一个让人血压升高的周三

周一,用户说:“帮我做一组复古风格的品牌海报。”

Agent 整理需求,开始生成参考图。

中途用户插一句:“顺便把昨天那只猫做成五秒视频。”

周三,用户回来了:“之前那组海报再暖一些,文字位置也调一下。”

“之前那组”这四个字,是人类沟通的日常,也是系统的噩梦。我自己听到这句都得先愣两秒,何况一个只有上下文窗口的模型。

2.1 不是每个请求都配得上一个独立执行空间

多 Agent 最容易掉进去的坑是:既然能拆,那就全拆。

但每一个独立执行空间都要养自己的上下文、状态、消息路由。开得越多,协调开销越大,最后你得到一群各自很忙、整体很乱的员工。

我们的分法是两类。

2.1.1 轻量事项

一次生成、一个状态、一张结果卡片。用完就走,不长期占着用户的任务列表。

2.1.2 正式事项

有完整生命周期,能持续收消息、排计划、等外部任务,隔天甚至隔周还能接着干。

判断标准很土但有效:用户会不会围绕它继续改。会,就升级;不会,就让它安静地结束。

顺便说,这也是对去会话化的补丁。我们不想让用户管理会话,当然也不想最后只是把“会话列表”换成“任务列表”,让用户从拉左边栏改成拉右边栏。

3 消息路由:那句“换成蓝色”到底指哪张图

统一入口带来的第一个副作用,是把一件原本用户自己完成的工作交给了系统:这条消息该给谁。

用户刚生成一张图,接着说:“把刚才那个换成蓝色。”

“那个”可能是最新这张,也可能是三小时前某组海报里的素材。判错一次,轻则多建一个事项,重则把人家满意的作品改成事故现场。

3.1 能靠关系确定的,别让模型猜

我们的原则朴素得像食堂打菜:有明确关系的,程序直接处理;实在没归属的,才让模型做语义判断。

三层的顺序是这样的。

3.1.1 结构化身份,直接投递

用户在某个事项面板里回复、点了卡片上的按钮、对着明确绑定的作品提修改——系统本来就知道这是谁的活。这时候再叫模型判断一次归属,纯属给自己加延迟和误判。

3.1.2 主线来的自然语言,交给路由

可能是主线能直接答的小问题,可能是一次轻量生成,可能是某个已有事项的后续,也可能是全新目标,还可能歧义到必须反问。

这里有个容易忽略的成本点:路由不需要读所有事项的完整历史。给目标、摘要、最近状态、相关对象引用就够;识别出候选,再按需深读。

否则事项一多,路由自己就变成另一个不断膨胀的上下文——你在解决一个膨胀问题的时候,亲手造了第二个。

3.1.3 建之前先查重

最常见的错误不是路由错,是“把续集当成新片”。所以正式事项创建前,我们会跟最近五十个进行中的事项做一次相似度比对,把最像的几个候选丢给模型:沿用,还是新建。

这招能拦住一部分重复劳动,但拦不住所有歧义。证据不足的时候,问用户比自作聪明可靠。毕竟多建一个事项还能合并,改错一张交付图不能。

3.2 送到了,不等于马上开工

这是我最想给同行划重点的地方:消息归属和消息执行,是两个阶段。

Agent 正在跑视频生成,用户补一句:“背景改成室内。”

此时请求可能已经在对方服务器上排队了。系统该做的不是立刻冲上去改,而是先把这句话存进事项的持久化收件箱,等 Worker 走到安全边界,再结合当前进度决定怎么办。

// 消息只入队,不抢占正在执行的 Step
await inbox.append({
  taskId,
  turnId: currentTurn.id,
  payload: msg,
  status: "pending",
});

// Worker 在安全边界统一消费,并记录被哪个 Step 用掉
const batch = await inbox.claim(taskId, { turnId: nextTurn.id });
await turn.commit({ inputs: batch, consumedAtStep: 0 });

这么拆之后,几种状态就能分清楚:

还没被消费的,可以撤回、可以替换;已经进了推理的,等当前边界;已经提交给上游的,撤不回来,只能等边界再决定是否重做,或者把新约束落到后续步骤。

这跟人上班一样。同事正在会上讲方案,你在群里发“第三条改一下”,他不会当场把 PPT 改了,他会在会后看。

3.3 路由对了,也不代表可以动手

我们把“归属判断”和“执行授权”彻底分开。

前者决定这活给谁,后者独立检查权限和钱。删素材、忘记忆这种不可撤销的,每次都要确认;付费生成先给报价,超出免确认额度或当日上限,再要确认。

理由很现实:路由错一次,最坏是多一个事项;授权错一次,最坏是一张不该删的素材消失,或者一笔不该花的钱出去了。

4 持久化执行:进程可以死,事实不能丢

普通 Chat Completion,几秒到几十秒,请求完了就完了。

创作 Agent 不是。一次视频制作可能包含多轮推理、几十次工具调用、好几个要等几分钟的外部任务,中间用户还可能随时改需求、按停止。

于是出现一种很古典的故障:请求已经提交,上游其实已经建好任务,就在拿到响应前那一刻,进程重启了。

像表白消息发出去了,对方没回。你不知道是没看到,还是看到了不想回。而这两种情况,处理方式完全不同。

4.1 先落决策,再调工具

传统 Agent Loop 是:读上下文、推理、调工具、拿结果、继续推理。短任务里这么写没问题,跨进程之后每一环都可能留下不一致。

我们把执行切成 Step:一个 Step 包含一次模型推理,以及它提出的一组工具调用。关键改动是在真正执行工具之前,先把模型的决定和待执行调用落库。

// 同一个事务里:保存决策 + 待执行调用 + 已消费的消息
await db.transaction(async (tx) => {
  await tx.turns.insert({
    id: turnId,
    taskId,
    epoch,            // 执行代次
    status: "running",
    decision: stepDecision,
  });
  for (const call of stepDecision.calls) {
    await tx.toolCalls.insert({
      key: `${turnId}:${stepNo}:${call.seq}`,   // 稳定业务标识
      status: "pending",
      input: call.input,
    });
  }
});

恢复时不用重新让模型再猜一次刚才想干什么,直接看台账:哪些完成了,哪些能重试,哪些得先跟外部核对。

这里省下的不只是钱,还有一种更贵的东西——同一次执行里,模型前后两次给出的方案不一样,用户会以为你在梦游。

4.2 幂等:别为同一段视频付两次钱

假设用户批准生成一段视频,网络超时导致同一请求重复提交。理想结果是一笔订单、一段视频。现实可能是一段视频、两笔扣费,然后财务来找你喝咖啡。

支持幂等键的下游,用稳定标识去重;平台内部的订单和计费,用调用 ID、订单 ID 加唯一约束兜住。

但有一类接口既不支持幂等键,也查不到结果。这时候别硬吹“恰好一次”——那是做不到的。

我们的处理是分岔:可幂等的,沿用原调用标识重放;不可幂等的,如果台账里是 started 却始终没有结果,不直接重跑,而是把带 outcome_unknown 的结果交给模型,让它先看状态再决定。

UPDATE tool_calls
   SET status = 'done', result = $2
 WHERE call_key = $1
   AND status = 'started'
RETURNING id;
-- 影响行数为 0,说明这次提交已经过期或已被人做过,直接丢弃

还有一层更保守:如果生成请求提交结果不明,我们直接判失败,不自动再打一次上游。两个都叫“结果未知”,一个是在恢复 Agent 的工具调用,一个是在避免重复创建真正收费的任务。名字一样,代价差一个量级。

4.3 栅栏令牌:别让复活的旧 Worker 抢方向盘

持久化解决的是进程死了怎么办,还有一种更阴的情况:它没死。

Worker A 网络抖动,系统判定超时,让 Worker B 接管。几秒后 A 恢复连接,兴高采烈地提交自己刚才算出来的结果。

此刻系统里有两个都觉得自己在开车的司机。

所以我们给任务加执行代次。每次被接管就 +1,Worker 提交状态必须带自己手里的代次,对不上就拒绝。

// 提交前校验代次;代次不匹配说明自己已经是过期执行者
const ok = await db.query(
  `UPDATE turns SET state = $3, epoch = epoch
     WHERE id = $1 AND epoch = $2 AND status = 'running'`,
  [turnId, myEpoch, nextState]
);
if (ok.rowCount === 0) throw new StaleEpochError(turnId, myEpoch);

但要说清楚它的边界:它保护的是系统内部状态,撤不回已经发到外部的请求。用户点了停止,之前提交的生成可能还在跑,钱也可能照扣。迟到的完成事件不会把已停止的事项叫醒。

这就像你已经把快递寄出去了,事后取消订单只能退款,不能把包裹从路上拽回来。

4.4 队列丢了怎么办

还有一个很少有人第一版就想到的洞:数据库已经记下“有待执行的工作”,负责唤醒 Worker 的队列消息却丢了。

我们没上事务性 Outbox,而是把数据库当成执行事实的唯一来源,队列只负责敲门。轮次提交后再发调度消息;发失败就让后台看门狗按数据库状态重新发现任务。

看门狗每十秒扫一次,主要看租约过期、久排队、有未处理消息却没有活动轮次这几类。

翻译成人话:门铃坏了不要紧,我每十秒自己上楼看一眼。

代价是恢复有延迟。我们接受这个延迟,换一个更简单、更少活动部件的调度。

5 异步生成:等五分钟,但别占着人

创作用于的模型,天生一半是异步的。图像几秒,视频和 3D 几分钟起。

提交完只拿到一个任务 ID,结果要靠轮询或回调。

如果让 Worker 一直干等,等于让一个程序员抱着手机盯进度条,五分钟里什么也没干,还占着工位。

5.1 提交完就挂起

工具先提交请求,拿到任务标识;运行时保存任务和事项的关联,包括 ID、等待状态、恢复所需的信息;然后 Worker 挂起,不必维持一个长推理请求。

等待期间,生成服务的进度可以直接推给前端,事项卡片上滚动展示。完成之后,运行时再判断后续步骤是否依赖这个结果,决定要不要叫醒 Worker。

好处很直接:那几分钟里,系统只维护状态和处理事件,不烧推理资源。用户也能实时看到进度,而不是对着一个转圈的菊花怀疑人生。

5.2 事件也会撒谎

改成事件驱动之后,新的问题来了:事件本身不可靠。

重复推送、回调失败、多个任务的事件乱序到达,都很常见。

所以不能写成“收到回调就继续”。要以持久化的任务状态为准去更新,保证重复事件不会造成重复写入、重复计费、重复唤醒;乱序事件不能拿旧进度盖掉最终结果——任务已经完成了,又来一条延迟的“生成中”,状态不能倒回去。

长时间没消息的,用任务 ID 去上游查询核对,必要时补偿轮询。

这套东西和前面说的持久化执行是一对:运行时维护可信状态,异步系统把外部的变化翻译成可恢复的业务事件。

5.3 不是每次完成都要叫醒模型

这是成本上最容易被忽略的一刀。

用户说“生成一张猫图”,生成完直接展示就结束了。没必要再叫模型出来描述一遍它刚生成的图。那不叫智能,那叫复读。

但用户说“做一组风格统一的品牌海报”,当前结果就是下一步的输入,需要检查产物、读清单、判断继续生成还是等确认。

所以生成完成事件和 Agent 续跑决策是分开的。生成服务只负责报结果;运行时结合计划、等待关系、授权、当前状态判断要不要恢复 Worker。

一个跑五分钟的视频任务,上游可能产生几十条状态变化,绝大多数只值得更新前端,不值得触发一次推理。把每条事件都喂给模型,是最贵的一种“我在认真工作”。

6 上下文工程:别把三个月的聊天塞进脑子

一个持续几天的事项,可能积累几百条消息、几十次工具调用、一堆图像视频和工作流状态。

窗口再大,全塞进去也不现实。一方面 token 和延迟顶不住;另一方面,太多历史会干扰模型对当前目标的判断——尤其用户改过好几次需求,早期已经失效的约束还混在里面,模型会一本正经地执行一个已经作废的方案。

6.1 分层,并且把稳定的东西放前面

我们把上下文分成几层:相对稳定的系统前缀、压缩过的历史、近期交互、当前步骤需要的动态状态。

顺序不只是排版问题。支持提示词缓存的服务会复用符合规则的前缀,所以系统规则、核心工具、相对稳定的画像放前面,每一步都可能变的任务状态放后面。

要是把高频变化的东西插在前缀开头,后面本来稳定的内容也跟着无法复用。相当于你把每天的天气写在合同第一页,整份合同每天都要重签。

不过缓存命中率还受服务商、路由策略影响,布局只是创造条件,收益得用真实调用数据验证。另外,稳定前缀不等于画像可以永不更新——用户改了偏好或者要求忘掉某些信息,快照必须及时失效,不然缓存会把过期信息一直喂下去。

6.2 工具按需加载,能力越多越贵

我们平台集成了图像、视频、3D、素材管理、文档编辑、可视化工作流。

把所有工具的名称、参数、说明都塞进每次请求,两个后果:token 涨;模型在几十个相似工具之间开始乱点,像一个刚入职就被塞了八份 SOP 的新人。

所以分两类:长期可见的核心工具,和按领域动态加载的工具。做分镜规划时给文档和素材相关;进入视频制作再加载视频生成与工作流。不活跃的领域,在压缩边界把详细定义摘掉。

代价是缓存命中率可能受影响,历史里的工具调用也可能跟当前可见的定义对不上。另一种做法是保持工具集稳定,靠约束当前可用动作来降低选择复杂度,更利于一致性和缓存。

两种都有适用条件。我们选动态加载,是因为创作平台的工具参数结构确实太胖。

补一句安全上的常识:工具是否出现在上下文里,只影响模型能选什么。真正的执行权限在服务端,别拿“Prompt 里看不到”当安全边界。

6.3 摘要不是事实的唯一来源

常见做法是不断让模型总结历史,然后拿最新摘要继续聊。

问题是摘要在反复压缩里会掉细节,更糟的是把模型自己的推测固化成“历史事实”。传到第三轮,模型开始引用自己编的东西,还引得很自信。

我们的做法是分段摘要:早期历史按区间压,近期交互保留完整;新摘要尽量追加到已有序列,不每次重写整段。

大型工具输出——素材列表、工作流节点、复杂生成结果——当前上下文只留摘要,全文放外部存储。需要查具体参数时再检索或分页读回来。

重点是那句话:摘要用来降负担,不该成为唯一事实来源。用户纠正过某个信息,或者某条约束已经失效,系统得能定位到原始依据,否则旧摘要会一直影响后面。

6.4 让当前目标始终在视野里

压缩解决的是“历史太长”,还有一个问题同样要命:Agent 干到一半,还记不记得自己要交什么。

长任务里模型很容易跑偏。用户要一套品牌海报,它把全部精力拿去优化一张参考图,细节感人,交付为零。

所以 Worker 的动态上下文里会持续带三样东西:当前任务书、执行清单、工作区状态。它们来自持久化运行时,不是模型对前面聊天的回忆。

任务书记录用户最后确认的方向,清单记录哪些步骤完成、哪些还在,工作区状态告诉它某个素材被换了、文档现在哪个版本。

用户直接改了工作流或共享文档,下一轮执行能收到变更提示,需要时读最新内容。这样即使部分历史被压缩,Agent 也不会靠猜继续。

7 记忆:忘记比记住难十倍

上下文解决的是“这一轮看什么”。记忆解决的是另一个更麻烦的问题:这段对话早就不在窗口里了,事项也结束了,系统到底该记住什么。

用户用了几个月,慢慢形成稳定的视觉偏好、常用流程、品牌规范。这些东西不该每次让他重讲一遍。

但偏好也会变。某个项目的临时风格,不该变成他后半生的审美;过去成立的品牌规范,可能一次改版就全废。

7.1 四层,各干各的

“我通常喜欢低饱和度的配色”,这可能是长期偏好。

“这次先试试高饱和的红”,这只是当前作品的局部要求。

两句都在说颜色,适用范围差了一个数量级。如果所有消息一股脑写进向量库再靠语义检索回填,长期偏好、临时要求、过期信息会搅成一锅。

7.1.1 原始证据

用户消息、来源、时间、有效状态。抽取、纠正、撤销都以它为底。

7.1.2 原子记忆

偏好、项目事实、常用习惯,带来源和版本,支持跨事项按需检索。

7.1.3 情景摘要

一段交流或一个阶段的概要。上周做了组海报,最后选了暖色,视频先搁置——这类信息未必进画像,但下次提起项目时有用。

7.1.4 用户画像

少量、稳定、高价值。它的职责是给日常协作提供低成本背景,不是另一份越滚越大的聊天记录。

还有一条原则我盯得很紧:用户明确说的事实,和模型自己的推测,必须分开。

用户连生成几张赛博朋克图,模型推断他长期偏赛博朋克——这只能算候选判断,不能直接写成用户偏好。同理,网页内容、工具返回、Agent 自己写的摘要,也不能在没有可靠依据的情况下被包装成“用户的事实”。

7.2 一条记忆要有版本链

用户先说:品牌主色是蓝色。

后来补充:蓝配米白会更柔和。

系统很自然地整合成一条“偏好蓝与米白,整体偏柔和”。

然后用户说:忘掉最初关于蓝色的设定。

只删第一条原子记忆不够,整合后的版本里还带着它。

所以我们维护来源和派生关系,用版本链描述一条记忆是怎么演化来的。

-- v1:原始表达
INSERT INTO memory (id, content, origin, status)
VALUES ('m1', '主色为蓝色', 'ORIGIN', 'ACTIVE');

-- v2:补充米白搭配,v1 被取代但保留为来源
INSERT INTO memory (id, parent_id, content, origin, status)
VALUES ('m2', 'm1', '蓝配米白,整体柔和', 'REFINE', 'ACTIVE');
UPDATE memory SET status = 'SUPERSEDED' WHERE id = 'm1';

-- 撤销最初那条证据的使用资格,沿版本链失效派生记忆
UPDATE memory SET status = 'REVOKED' WHERE id IN ('m1', 'm2');

撤销还要往下游传播:画像条目失效就更新画像版本,受影响的摘要重新构建,对应的检索向量删掉,并抑制已删内容被再次抽出来。

还有一个尾巴:已经发出去的模型请求撤不回来。所以我们会追踪回复和工具结果所依据的消息与记忆,在后续推理里排除受影响的派生内容,避免被忘掉的东西通过 Agent 自己以前的话又溜回上下文。

这就是“忘记”的难点:你不是删了一个字段,你是在删一棵树的根,还要保证叶子不再长出来。

7.3 记忆服务挂了,任务不能跟着停

来源追踪和版本管理能提高可控性,但治不好模型的理解错误。

同一段对话里可能有好几个候选事实,一条符合保存条件,另一条只是模型误读的临时指令。如果把整批抽取结果当成不可拆的整体,一条异常就能带走全部有效记忆。

所以候选逐条校验,区分来源不支持、内容冲突、格式异常。

记忆服务故障时也别让创作任务停摆:召回超时就先跳过记忆补充,后台抽取失败稍后重处理,单条格式异常不牵连其他记录。

代价是这一轮可能没有完整历史偏好。但它还能靠当前任务书和已有执行状态继续干。宁可少一点背景,不要一个坏记忆毁掉整个任务。

8 自主推进:模型闭嘴之后,谁喊“继续”

前面那些机制让 Agent 能维护长任务、能恢复中断、能找到历史。但还有一个问题没解决:它怎么知道自己该不该继续工作。

用户要做一支品牌短片。Agent 写完剧本和分镜,给了一段漂亮的总结,然后本轮结束。

模型没错,它确实完成了当前阶段。但离用户想要的那支片子,还差着一条赤道。

早期 Demo 里我们就是这样,用户被迫反复输入“继续”。有人输到第七次开始怀疑是不是在跟一个需要上发条的玩具说话。

反过来,如果你简单粗暴要求“全部完成前不许停”,就得到另一个怪物:反复重试已经失败的操作,持续生成没人要的素材,或者在没确认的情况下自己扩大范围。

8.1 把计划变成一份能维护的清单

我们引入了结构化执行清单。它和模型在聊天里随口列的待办不一样,它是系统持久化维护的状态:每一步有执行状态、产物、完成证据、是否需要用户确认。

做一支短片,大致是:剧本与分镜、角色与场景、镜头生成、方案审阅、最终交付。每步都挂着“完成依据”——分镜文档加用户确认、素材与版本记录、外部生成任务与结果、用户反馈或授权的验收结果。

用户批准方案后,清单成为推进依据。Worker 按当前步骤规划调用,运行时在每轮结束后检查进度。

但清单不是钢板。用户在镜头生成阶段决定换角色设定,原有步骤和产物就得重排。计划要能被新指令改写,同时维护步骤和产物的关联。

清单真正的价值不在规划,在断点续命。上下文压缩了、异步等待了、进程恢复了,Agent 还能找到自己站在第几步。

8.2 停止检查:模型说完,不代表做完

每轮结束后,运行时要问四件事:还有没有待推进的步骤、有没有外部等待、需不需要用户确认、有没有撞到执行上限。

这里最容易被刷的是“实质进展”。

新增可用产物、完成清单某一步、成功提交新的生成任务,都算进展。

但反复改计划描述、把状态从“待办”切成“进行中”再切回来,这不算。有人在系统里疯狂挪便签,你会以为他在推进,其实他在表演。

所以进展检查加执行限制,专门治空转。

当然这套判断有局限:生成了新素材,只能证明操作执行了,不能证明素材能用。视觉一致性、镜头节奏、整体气质,还得多模态评估和人来兜。

8.3 人工把关点,以及那个忘了给按钮的 Agent

品牌视觉方向、角色设定、分镜方案、最终镜头,这些地方主观性很强。全交给 Agent 决定并一路生成,很容易产出一堆无效成本,还很自信。

所以设人工把关点,到点暂停自动推进,用结构化卡片展示当前方案、候选结果、建议操作。用户点“确认继续”或“调整方案”,系统按明确结果更新状态。

开发期演练里我们撞过一个特别典型的场景:Agent 已经进入待确认阶段,回了一句“请确认是否继续”,然后什么也没给。

没有按钮,没有卡片。用户只能自己打字“继续”。

像餐厅服务员说“请您点菜”,然后把菜单收走了。

后来我们在运行时加了兜底:停在把关点而模型没发起提问,系统自动补一张确认卡;用户批准后要执行的生成,如果清单还有待完成步骤,生成结束自动唤醒事项。

结论很硬:等待和恢复不能依赖模型的表演欲,得由运行时按状态保证。

8.4 自主度、预算、范围,三本账分开记

用户允许你自动执行,不等于同意无限调用付费模型。用户批了一笔预算,也不代表所有操作都能跳过审阅。

所以我们分别维护三个维度:自主程度(每步确认 / 关键节点确认 / 授权范围内自动执行)、预算控制(单次额度、计划预算、余额检查、追加确认)、目标授权(已批准的任务书、计划、明确修改)。

举个常见的翻车:用户批准做三条视频,允许在预算内自动完成。执行中发现需要额外出角色参考图。这算不算原计划?超没超预算?

模型的计划和模型自称的授权,都不能当作用户的真实授权。判断依据只能是用户在界面里的明确操作,加上服务端保存的授权状态。

不同工具还要分策略:只读查询风险低;文档写入要管版本和权限;付费生成先查预算;删除素材、撤销记忆这种不可逆的,严格确认。

相比写代码的 Agent,创作平台多一层麻烦:很多外部生成一旦提交,费用就已经产生。用户事后停止,也未必能完整撤回。所以预算和授权检查必须发生在真正产生副作用之前。

说到底,自主程度不是越高越好。该少打扰的地方少打扰,该让用户拍板的地方别替他拍板。

9 共享工作区:用户和 Agent 抢同一份文档

协作不只发生在聊天窗口里。

Agent 正按分镜生成视频,用户可能直接在右侧工作区改某个镜头的提示词、换参考素材、动工作流节点。

这些操作没经过对话,但它们真的改了作品。如果 Agent 还按旧上下文继续跑,就会用过时参数,甚至把用户刚改的东西盖掉。

9.1 让作品自己有一条命

对话式 Agent 里,生成结果常常挂在某条消息上。看、下、追问都行,但对话一长,作品管理就被会话结构卡住。

我们把对话上下文和创作产物分开:前者维护意图、过程、Agent 当前掌握的信息;后者保存需要持续编辑和交付的作品——对象身份、内容、版本、引用关系。

于是同一份分镜文档可以被两个执行空间在权限内引用,不用各存一份副本。某个事项结束了,它的产物还能被新工作流引用,不依赖原来的 Worker 是否还活着。

9.2 变更提示,但别每改一个字就叫醒 Agent

Agent 读过分镜 v3,准备按第二个镜头继续。就在这时候用户把它改成 v4。

只记聊天消息的话,Agent 下一轮根本不知道。

所以我们给共享对象维护版本,并记录关联事项上次看到的是哪一版。对象变了就留一条持久化变更提示:分镜已从 v3 更新到 v4,第二个镜头描述变化,继续执行前请读最新版本。

关键是我们没有让每次编辑都立刻触发推理。用户调工作流时经常连续拖节点、改参数、换素材,每个动作唤醒一次 Worker,等于在人家打字的时候不停弹窗。

变更提示的作用是让 Agent 下次执行时发现自己信息过期,而不是立刻冲进去。

工作流这种对象,也不必每轮读完整节点数据。先给简要变化,模型真需要处理某节点时再取最新内容。

9.3 乐观并发:版本对不上就别写

能感知变化还不够,并发写还得管。

Agent 读了 v3 准备改第三个镜头,用户同时把文档存成 v4。Agent 直接提交基于 v3 的修改,用户刚做的内容就没了。

所以用乐观并发控制:读的时候拿版本,写的时候带上所依据的版本,服务端写前校验。

// 提交时必须声明"我是基于哪一版改的"
const res = await docs.update({
  docId,
  baseVersion: 3,          // Agent 读到的版本
  patch,
});
if (res.conflict) {
  // 对象已被更新,拒绝覆盖,要求重新读取最新状态
  await docs.read(docId);
  return retryWithLatest();
}

粒度要按对象类型调。

文档整篇重写,必须带版本;局部修改用精确且唯一的文本片段定位,所有预期替换都成立才提交。

工作流更细:用户调这个节点,Agent 改那个节点,如果只要文件变了就拒绝,频繁自动保存会让双方根本没法并行。所以只检查 Agent 要改的节点是否被改过——同节点被改就重读,改在别处就允许在最新版本上应用不冲突的修改,同时提示变化。

这不是自动合并两种意图,只是用合适的版本粒度让互不冲突的编辑各自完成。

另外提醒一句:乐观并发解决的是状态一致性,不解决创作意图的冲突。用户想要冷色调,Agent 按原计划继续暖色调,即使没有版本冲突,最后用哪个还得看最新意图。

10 能力编排:别让模型规划一个平台做不到的方案

生成一张图不难。做一支完整短片,涉及剧本、分镜、角色设定、场景参考、镜头生成、后期处理,每步可能用不同模型,前一步的结果直接决定后一步能做什么。

更麻烦的是:单个生成任务成功,不代表整个流程能出片。

Agent 规划了一套方案:先生成角色和背景,再把人物抠出来,最后合成到指定画面。如果平台当下没有对应的抠像或合成能力,前面素材做得再美,最后也拼不成作品。

这就像厨师照着菜谱买了顶级食材,才发现厨房没有灶。

10.1 让它在规划阶段就知道边界

我们把创作经验和工具能力约束整理成可按需读取的指引:角色一致性怎么维持、分镜怎么规划、参考素材怎么用、工作流怎么编排、平台当前支持哪些制作能力。

相关任务里才加载,不长期堆在系统 Prompt 里。这和上下文工程是一套逻辑:到哪个阶段,给哪部分知识。

但只靠模型读说明还不够。它可能提出一个听起来很专业、实际做不出来的方案。所以关键工具的能力、输入输出约束、执行条件,要由系统给出明确校验依据,不能靠语言模型的理解兜底。

10.2 依赖图:从线性清单到 DAG

结构化清单能管进度,但任务一复杂就不够用了。

一支短片多个镜头,共享同一套角色设定,场景和模型却各不相同。有些镜头能独立生成,有些必须等上游参考素材;用户改了角色形象,相关镜头要重做,无关场景不该跟着陪葬。

这种关系适合用制作 DAG 表达。节点是步骤或中间产物,边是依赖。

结构化之后能拿到几件事:依赖调度(上游就绪才跑下游)、并行生成(无依赖的在预算内并发)、变更传播(改了设定只定位受影响的下游)、增量制作(复用还有效的素材)。

代价是复杂度。创作里的依赖不一定确定:上游变了,下游到底要不要重生成,得看修改范围。而且依赖对了也不保证画面好看,角色一致性、镜头连贯、节奏仍然要独立的质量评估。

所以这块我们目前更多是演进方向。现阶段先保证 Agent 能在平台现有能力范围内跑通可执行的流程,把中间产物的成本和有效性控住。

11 怎么验证:故障注入和场景演练

Agent 系统有个很有性格的特点:每个模块单独跑都正常,合起来不一定靠谱。

消息路由对了,工具也返回了,但生成完成后 Agent 忘了继续;或者每一步都符合预期,最后产出三份重复文档,用户不知道哪份是终版。

这类问题,单测和几轮顺畅对话都发现不了。

11.1 让 Worker 在中间卡死

我们用故障注入专门打状态转换。覆盖的边界包括:执行中断与恢复、重复投递与网络超时、Worker 并发接管、取消与异步事件竞争、预算与授权变化、共享对象并发修改、记忆纠正与撤销。

模型输出能稳定复现的,用固定结果回放,重点验运行时的状态转换;外部生成服务模拟超时、重复回调、乱序事件,避免每次都烧真钱。

最有代表性的一条:让 Worker 在工具执行中途被人为挂起。它已经存了模型决策,把调用记成 started,然后停住。租约过期后第二个 Worker 接管,代次升到 2,从 checkpoint 继续——因为决策已存,它不需要重新推理,直接用同一个幂等键完成调用。最后把第一个 Worker 放回来,让它提交迟到的结果。

预期是:轮次最终 completed,代次为 2,模型只调了一次,工具结果只有一条,旧 Worker 的写入被拒。

跑通那一刻我挺高兴。不是因为设计优雅,是因为它证明系统在“有人装死又突然复活”的情况下不会出事。这在真实世界里发生的概率,比你想的高。

11.2 演练暴露的那些蠢问题

运行时测试能验异常状态,验不了协作体验。

比如 Agent 分镜做完了,下一阶段直接停住,等用户再输入“继续”。从程序角度看这不算故障,从用户角度看这叫半途而废。

所以我们在隔离环境里做场景演练:真实文本模型,模拟生成服务,预设行为的模拟用户,跑系列海报、短片制作、工作流修改、3D 创作、多事项切换、历史恢复、记忆纠正与遗忘。

重点观察的不是某一步成不成,而是这些变化之后它还能不能围绕原目标继续:该停的地方停没停、用户要不要反复按继续、有没有多余确认和重复生成、新消息有没有挂对事项、用户改完作品它有没有拿到最新状态、同一份作品有没有被拆成好几个副本、记忆撤销后旧信息还会不会影响协作。

演练抓到两个特别真实的 bug。

一个是英文系列海报。Main 正确理解了英文需求并建了事项,Worker 在后续规划里切回了中文。问题不在路由,在于事项只收到主线整理后的目标描述,丢了用户原始表达里的语言信息。后来我们改成让事项按用户实际输入维护回复语言,不再靠模型从描述里推。想象一下公司年会上翻译突然开始讲方言,你就懂那个场面了。

另一个在人工把关和异步生成的接缝:Agent 推进到待确认,却没给可操作的卡片;或者用户批准后外部任务正常完成,事项却没继续。于是加了确认卡兜底和生成完成后的自动唤醒。

这些都不算明显的执行故障,但用户感受到的是“这东西不太靠谱”。也让我更确定一件事:理解意图和规划步骤是模型的活;等待、授权、恢复执行这些关键状态,得由运行时给确定性保障。

11.3 一次协作好不好,怎么算

只看回答流不流畅、工具调用成不成功,衡量不了一个长期跑的 Agent。

用户真正在意的是:我要重复解释多少次?它记不记得已经定下的要求?隔几天能不能自然接着干?我改作品的时候它知不知道?

所以除了执行正确性,我们还盯任务连续性、介入成本、重复操作、产物一致性。

但这些不代表智能水平。流程跑完和作品好看是两件事。Agent 可以按计划生成全部镜头,仍然做出一个风格跳跃、角色忽胖忽瘦的片子。

这也是我现在的态度:一次顺畅的演示什么都证明不了,能证明东西的是故障恢复和端到端协作里那些难看的瞬间。

12 还没解决的,以及我不打算装懂的

多事项组织、持久化执行、上下文管理、共享工作区,这些基础能力有了。但离理想形态还有距离,几件事我列在这,免得下次评审又假装它们不存在。

跨事项协作。现在 Router/Worker 能让多个事项独立推进、按需访问共享产物。如果进一步允许 Worker 之间互相求助、委派、甚至协商预算,权限、状态同步、并发一致性都会更难。多 Agent 看起来很性感,但 Agent 多不等于效率高,协调开销和上下文传递可能把专业化收益吃掉。我想先从真实需求里找出真该拆的活,再扩范围。

创作流程的依赖管理。制作 DAG 是我比较在意的方向。显式依赖能支撑并行、增量和复用。但创作里的依赖不太确定:改了一个角色设定,哪些镜头必须重做、哪些能沿用,往往要看内容本身。

异步生成的可靠性。已经提交到上游的任务,现在还撤不回来;任务建了却在保存上游任务 ID 之前崩掉,也缺少反查和恢复关联的能力。这些有状态处理和费用兜底,但仍可能产生不必要的成本。

多模态质量验收。工具返回成功、清单步骤完成,只能证明操作做了。视觉一致性、运动连贯、音画同步、用户主观审美,是另一套问题。我希望能把这些评估逐步引进执行流程,让 Agent 判断什么时候该调、什么时候值得重做、什么时候把决定权还给用户。

还有记忆的准确性、路由的可靠性、主动跟进的边界。来源追踪和版本管理能提高可控性,治不好抽取错误和误召回;路由已经有索引、检索和查重,但事项越积越多,准确率和用户需要纠正的频率,还得靠真实数据说话。

主动跟进这件事尤其微妙。系统可能知道某个任务还有后续,却不知道用户此刻想不想被打扰。一个总在正确时刻出现的助手是帮手,一个总在错误时刻出现的助手是前任。

13 最后说点不那么架构的

做这套东西的过程中,我最大的感受不是“模型真强”,而是“模型再强,也强不过一个不肯把状态存下来的架构”。

过去我们设计软件,先定义功能、流程、边界,再让用户按规则操作。现在 AI 能理解意图、调用工具、自己做判断,很多原本压在用户身上的组织和协调工作,可以交给系统。

但模型能力只是其中一段。一个能长期协作的 Agent,得知道自己正在做什么、已经做过什么、哪些信息还有效、什么时候该继续、什么时候该停。它还得处理现实系统里那些不体面的东西:中断、并发、费用、权限,以及用户随时改主意。

我们现在的实现还在早期,很多设计得继续挨真实用户的教育。有些方案可能过两个月就被自己推翻,这种话写在文章里不太体面,但比写完就当真要好。

我还是愿意相信一件事:总有一天,我们不用再学怎么用一个软件,只需要告诉它我们想完成什么。

在那之前,先把它弄得不那么需要你敲十七次“继续”。

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 传送门http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

Logo

更多推荐