在开发 AdamI 的过程中,有一件事越来越清楚:

“想接下来该做什么”和“真正去做这件事”,不应该被当成同一件事。

一开始,很容易把 Agent 的工作流程想得很简单:

Goal → Model → Action

模型拿到任务,理解目标,判断下一步,然后调用工具执行。

做 demo 的时候,这通常已经够用了。

但一旦 Agent 开始长时间运行,这种结构很快就会让人不安。

问题并不是模型不会规划。

而是:

规划本质上只是一个想法。

执行会真正改变外部世界。

这两者的区别听起来很显然,但当 Agent 开始接触文件、工具、API、任务队列、凭证,以及任何可能产生实际副作用的东西之后,这个区别会带来很多后果。

在开发 AdamI 的过程中,我越来越习惯用一句很简单的话来理解这件事:

A plan is a proposal. Execution is a commitment.

规划只是提议。

执行才是承诺。

它们不应该拥有同样的权限。

这件事之所以重要,是因为模型天生很擅长给出“看起来合理的下一步”。

只要给模型一个目标,再提供足够的上下文,它通常就能生成一套很顺的步骤:

先查看代码仓库。

然后修改文件。

运行测试。

根据报错继续修正。

最后提交结果。

作为“计划”,这当然很有价值。

但这几个步骤实际上处在完全不同的操作环境里。

读取文件,不等于修改文件。

修改文件,不等于执行 Shell 命令。

运行测试,也不等于把代码推送出去。

模型可能会把这些动作理解成一条连续的工作链。

系统不能这样理解。

这正是我现在越来越在意的区别。

模型可以从“下一步应该做什么”这个角度思考。

但 runtime 必须从另一个角度判断:

“下一步到底允许做什么?”

这也是为什么 AdamI 没有把 reasoning、routing、planning 和 execution 全部压进同一个步骤里。

系统里存在不同的部分,分别处理请求应该去哪里、任务应该怎么拆解,以及真正的工作应该怎样执行。

这种分离,并不是为了让架构看起来更复杂。

而是为了给系统留下“中断自己”的空间。

这其实非常重要。

如果规划和执行耦合得太紧,Agent 很容易从:

“我认为下一步应该这么做”

直接滑到:

“那我现在就去做。”

中间几乎没有空间再问:

当前状态还是有效的吗?

这个动作需要额外权限吗?

计划生成之后,有没有什么事情发生变化?

系统现在是不是应该先等待?

工具是否可用?

这个动作是不是已经尝试过?

如果重复执行,会不会产生问题?

这些问题,本来就应该存在于“规划”和“执行”之间。

这也和我最近一直在思考的 persistent agents 有直接关系。

一个短时运行的聊天机器人,可以默认同一轮回复期间,外部世界大体不会发生太多变化。

但一个持续运行的 Agent 不行。

十分钟前生成的计划,可能已经过时。

昨天生成的计划,更应该重新检查。

也许某个文件已经被改过了。

也许另一个任务提前完成了。

也许用户改变了目标。

也许凭证过期了。

也许系统刚刚重启。

也许任务本身仍然有效,但其中某一步已经不再成立。

所以我并不希望 AdamI 把一份生成出来的 plan 当成一段可以一路执行到底的脚本。

计划应该始终可以被修正。

执行应该始终带有条件。

Agent 运行得越久,这一点就越重要。

我喜欢把规划和执行分开的另一个原因,是它让失败更容易被理解。

如果 Agent 做错了一件事,而规划和执行完全混在一起,我们很难判断真正的问题到底发生在哪里。

是 reasoning 错了?

是 routing 错了?

是计划本身没问题,但环境后来变了?

是这个动作本来就不应该被允许?

还是动作本身对,只是参数错了?

这些其实是完全不同的故障类型。

如果架构把它们分开,我们就能拿到更有价值的证据。

我们可以检查模型提出了什么计划。

可以检查执行前的系统状态。

可以检查系统最终允许了什么动作。

也可以检查动作执行之后真正发生了什么。

这比一句简单的:

“Agent failed”

有用得多。

这件事对于 replay 也尤其重要。

我并不希望所谓的 replay 只是重新阅读模型说过什么。

我希望它能够真正重建一条链路:

系统当时知道什么?

模型提出了什么?

runtime 允许了什么?

真正执行了什么?

返回了什么结果?

后续状态发生了什么变化?

如果这些边界足够清楚,replay 就会变成真正有价值的调试工具。

如果这些边界混在一起,replay 最终很容易变成一种“事后讲故事”。

这是完全不同的两件事。

Guardian 这一层也很自然地会进入这个设计。

模型可以提出一个动作。

但这并不意味着模型因此就自动获得执行这个动作的权限。

听起来像是一个很小的架构选择,但我越来越觉得,这可能是自主系统里最重要的选择之一。

模型能力越强,我反而越不愿意让它拥有一条从 reasoning 直接通往外部副作用的直线。

更好的 reasoning,并不会让 control 变得不再重要。

某种程度上,反而会让 control 更重要。

一个能力较弱的系统,通常只能犯有限的错误。

一个能力很强的系统,却可能非常高效地执行一个错误假设。

所以我的目标,并不是阻止模型大胆规划。

相反,我希望它尽可能探索可能性。

真正需要避免的是:

探索能力和执行权限变成同一件事。

这也改变了我对 autonomy 的理解。

我们经常把“自主”理解成:

把人类从流程里拿掉。

但我现在觉得,这个定义并不够好。

一个系统完全可以非常自主,同时仍然拥有很强的内部边界。

它可以自由规划,但行动前重新验证。

它可以持续任务,但在状态不确定的时候停下来。

它可以调用工具,但只在定义好的权限范围内。

它可以从失败中恢复,但不能偷偷把失败重新解释成成功。

这种 autonomy,比单纯让 Agent 一路不停地跑下去更有意思。

AdamI 在这方面还远没有完成。

目前系统里已经存在 routing、planning、workflow execution、task state,以及与安全控制有关的不同组件。

但组件存在,并不意味着这些边界已经被证明是正确的。

接下来真正有价值的工作,是去测试这些“转换点”。

如果一份原本有效的计划,在执行前已经失效,会发生什么?

任务中断后恢复时会发生什么?

如果某个工具在规划阶段可用,但执行阶段不可用,会发生什么?

如果计划里的某一步超出了当前权限范围,会发生什么?

如果系统根本不确定前一个步骤有没有完成,又该怎么办?

这些情况才是真正重要的。

不是因为它们在 demo 里看起来很酷。

而是因为,只要架构太容易相信自己,长期运行的 Agent 就最容易在这些地方出问题。

越是围绕这个问题继续做下去,我越觉得:

把 planning 和 execution 分开,并不只是一个实现细节。

它其实是 control model 的一部分。

模型应该可以大胆地思考。

系统应该谨慎地行动。

这样,我们才有空间把:

validation

permission checks

state checks

waiting

recovery

replay

这些能力插进真正的执行链里。

而不需要让模型自己成为所有事情的最终裁决者。

最后,我还是会回到这句话:

Agent 越自主,就越需要把“它想做什么”和“系统真正允许它做什么”分开。

这也是我希望 AdamI runtime 接下来继续前进的方向。

AdamI Architecture Note #7 —— 一次解决一个工程问题,逐步构建能够持续运行的 AI 系统。