← 返回 Blog

Blog

Agent 到底是什么:LLM、Runtime 与因果记忆

如果先不谈现有框架,一个 Agent 至少要满足什么条件?我目前更愿意把答案落在这几件事上:LLM、Runtime、See / Act / Evaluate,以及按因果拓扑更新的记忆。

过去一段时间,我越来越不满意“Agent = LLM + 一堆工具”这个说法。它听起来没错,问题是太容易把最关键的东西藏掉。

一个模型会写代码、会调 API、会搜索网页,当然已经很强了。但如果它记不住昨天答应了什么,不知道这次执行有没有真的成功,也不能在失败后修正自己的状态,那它更像一次性自动补全,不像一个持续存在的系统。

所以如果必须先把问题压到最小,我现在更愿意从这里开始:

Agent = LLM + Runtime

这不是为了写一个更漂亮的公式,而是为了把讨论从“模型还能再接几个工具”拉回到“它到底怎样活”。

一、先把定义收紧:LLM 负责聪明,Runtime 负责活着

我一直觉得,把 LLM 看成一个“冰封的天才”并不算坏的类比。

它当然聪明,甚至经常聪明得吓人;但它停在训练完成的那一刻。它不天然知道今天发生了什么,不天然记得昨天答应了什么,也不会替此刻的结果负责。你把它唤醒一次,它做一次推理;推理结束,世界继续流动,它自己并不会跟着流动。

Runtime 不一样。Runtime 负责状态持有、执行能力、约束机制,以及和外部世界打交道的接口。它决定这个系统是不是能在时间里持续存在,而不是每次都像刚出生一样。

graph LR
    subgraph Agent["Agent"]
        LLM["LLM<br/>推理引擎"]
        Runtime["Runtime<br/>状态 / 执行 / 约束"]
    end
    LLM <-->|互补| Runtime

这也是为什么我不太认同“Agent 就是更会用工具的模型”。工具只是手,Runtime 才是身体。没有 Runtime,再高的推理能力也只是一次性的智力表现,不是一个真正持续行动的 agent。

如果借人脑做类比,LLM 更像前额叶皮层,负责推理、规划和语言;Runtime 更像感官、运动神经、记忆系统和身体本身。前额叶可以想“我要把杯子拿起来”,但没有手,它拿不起来;手可以执行动作,但没有前额叶,它也不知道该拿杯子还是砸杯子。

二、闭环不是 Prompt Engineering,而是 See / Act / Evaluate

如果继续往下拆,我现在更愿意把 Agent 的最小闭环压成三件事:

  • See:读环境、搜状态、拿证据。
  • Act:写环境、调执行器、真正改变世界。
  • Evaluate:判断这次行动到底算成功、失败,还是应该重试。
graph TB
    See["See<br/>read + search"] --> LLM["LLM 决策"]
    LLM --> Act["Act<br/>write + exec"]
    Act --> World["外部世界"]
    World --> See
    See --> Evaluate["Evaluate<br/>judge + reflect"]
    Act --> Evaluate
    Evaluate -->|"通过"| State["正式状态"]
    Evaluate -->|"失败 / 重试"| LLM

这三条里,最容易被低估的是 Evaluate

很多系统会把 Evaluate 写成“模型再想一想自己做得对不对”。这当然比没有强,但远远不够。一个 Agent 如果只能靠“我感觉我这次做得不错”来给自己打分,迟早会滑向自我证优。

真正能拍板的,必须是外部反馈:代码是不是编译通过,测试有没有变绿,接口是不是返回 200,用户是不是明确接受,预算有没有爆掉,审计日志是不是完整。代码没过测试,Agent 说自己已经完成,没有任何意义。

这也是为什么我越来越把 Evaluate 看成一条垂直于执行平面的轴。没有它,系统只是会自动跑的脚本;有了它,系统才开始从现实里学东西。

三、约束要写在物理层,不要写在祈祷里

一个像样的 Runtime,至少要把下面几件事写成硬约束,而不是写成 prompt 里的“请你自律”:

  • 预算上限:token、时间、成本都要有硬顶。
  • append-only trace:所有 SeeAct 最好都留下可审计轨迹。
  • 准入门槛:没有通过 Evaluate 的动作,不应修改正式状态。

这几条看起来像工程细节,其实决定了系统有没有“宪法”。

一旦约束真的落在 Runtime 里,记忆对象也会自然分裂成两类:

类型 例子 处理方式
信念记忆 “用户偏好短答案” 能更新,也能被推翻
事实记忆 “2026-03-14 改了 site.css 不能改写,只能追加

Agent 可以修正自己对世界的理解,但不能重写已经发生过的事实。前者是学习,后者是造假。

四、记忆不是时间轴,而是因果拓扑

我越来越不相信“越新越重要”这种记忆直觉。

一年前的一个关键设计决策,只要还在支撑你今天的行动,它在拓扑上就是近的。五分钟前的一句闲聊,如果和当前任务没有关系,它在拓扑上就是远的。很旧,不等于很远;很新,也不等于很近。

graph TB
    Goal["当前目标"] --> Task["子任务"]
    Task --> Decision["一年前的决策"]
    Goal --> Chat["五分钟前的闲聊"]

如果一定要给“因果距离”找个朴素定义,我目前更倾向于按引用链来算:一条信息距离“当前行动理由”有几跳,它就离当前系统有多近。

这也是为什么我不太愿意把记忆理解成聊天记录的线性堆积。真正有价值的记忆更新,更像一次贝叶斯修正:

\[P(\text{Knowledge} \mid \text{Evidence}) \propto P(\text{Evidence} \mid \text{Knowledge}) \cdot P(\text{Knowledge})\]

放在这里不是为了显得硬核,只是想说明一件很朴素的事:Agent 的成长不是“记了更多”,而是“旧信念在新证据冲击下被重估了”。没有外部证据,所谓长期记忆很多时候只是废话堆积。

如果再往前走一步,我会把记忆粗分成四层:

graph TB
    subgraph Memory["记忆分层"]
        L0["L0 即时状态"]
        L1["L1 近端因果"]
        L2["L2 稳定模式"]
        L3["L3 系统不变量"]
    end

    L0 --> L1
    L1 --> L2
    L2 --> L3

L0 / L1 / L2 应该频繁变化,L3 变化最慢,它更接近系统的宪法。一个好的记忆系统不是“尽量多留”,而是把真正构成当前行动理由的那部分东西留下来。

五、Skill 是推理缓存,不是永久资产

我现在越来越把 Skill 看成推理缓存,而不是长期资产。

有些事情,LLM 理论上每次都能重新想出来;问题是那样做太慢、太贵,也太不稳定。于是我们把高频推理路径固化成代码、模板、协议或者工具,换来吞吐、成本和稳定性。这就是 Skill 的现实价值。

大致可以分成两类:

类型 特征 示例 命运
效率型 Skill 模型能做,但每次现想太贵 prompt 模板、编排策略 模型变强后会退役
必要型 Skill 模型不可能预知的私有知识 用户偏好、私有 API、项目状态 长期存在,但持续更新

但 Skill 真正有意义的地方,不是“写出来了”,而是“它能不能自己消化一轮局部失败”。文件写失败、API 返回 500、参数不对,这些局部噪声没有必要每次都把上层推理打断。Skill Runner 最有价值的事,是在底层先吸收一轮 Act + Evaluate

可问题也在这里:每一行被固化下来的代码都有保质期。今天节省下来的推理成本,很容易变成明天的系统债务。

所以 Skill 还应该有退役机制。一个 Skill 如果持续被 Evaluate 判成脆弱、低效、负贡献,Runtime 最终应该触发一次“反编译”:把那段固化逻辑还原回更底层的推理,让模型重新接管。多数 Skill 的真实宿命不是沉淀,而是过期。

结语

如果现在只让我先留下最少的一组概念,我会留下这几样:

  • LLM + Runtime
  • See / Act / Evaluate
  • 写在物理层的约束
  • 按因果拓扑更新的记忆
  • 作为推理缓存、随时准备退役的 Skill

框架名字会换,术语会换,市场上的主流包装也会换。但这几件事如果不成立,系统再热闹,也更像一次性自动化,而不是一个真正持续行动的 agent。

至少在我现在看到的大多数系统里,决定 Agent 成败的,已经越来越不是模型名字,而是 Runtime 怎样看、怎样动、怎样记,以及怎样被现实纠正。

Runtime 的意义,说到底,就是让那个冰封的天才,在流动的因果里活过来。

讨论

评论

直接在本站留言交流。

评论正在加载…