对应 Maps to:CMU 17-630 Prompt Engineering(Prof. Travis Breaux),第 10 周 · Agents – Personas, Memory, Actions。原课 Schedule 对这一讲的说明(意译):智能体的关键概念与框架,包括角色(persona)的使用、ReAct 与 Reflexion 提示、AgentKit 和 AutoGen 框架,以及智能体的记忆管理策略。 依据说明:原课的 slides 和阅读清单不公开。Schedule 点名的六项——角色(§4)、ReAct(§2)、Reflexion(§3)、AgentKit 与 AutoGen(§6)、记忆管理(§5)——各占一节;§1(智能体循环)和 §7(动作空间)是讲义补充的背景。材料来自 Yao et al.(2023,ReAct)、Shinn et al.(2023,Reflexion)、Park et al.(2023,Generative Agents)、Packer et al.(2023,MemGPT)、Wu et al.(2025,LongMemEval)、Zheng et al.(2024)与 Gupta et al.(2024)的角色研究、Wu et al.(2024,AgentKit)、Wu et al.(2023,AutoGen)等;引用的数字都核对过原文。全部实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:
code/lecture14/(只用 Python 标准库;4 个模块 + 7 个脚本;不需要 API key;每个脚本 15 秒以内) 预计阅读时间:4 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 画出一个智能体循环(记录 → 模型 → 动作 → 环境 → 观察 → 记录),说出它和一次性调用的三个不同:反馈、错误累积、成本随步数增长;知道循环必须有哪些停止条件。
- 解释 ReAct 为什么有效:思考(thought)不改变环境,但把目标和进度重新写到上下文的最近处,并在动作失败时处理意外;也能说出思考怎样把智能体带偏。
- 说出 Reflexion 的三个部件(执行者、评估器、自我反思)和它依赖的条件:可靠的成功 / 失败信号、诊断对的反思;理解它在 ALFWorld 上”学到的”很大一部分是这个环境实例的信息。
- 判断角色提示能做什么、不能做什么:稳定地改变风格和视角;在客观题的准确率上效应很小、很不稳定;会有意想不到的副作用。会用配对检验、多重比较校正和分半一致性去评估一个角色。
- 比较几种长期记忆策略(窗口、摘要、检索、Generative Agents 的打分、MemGPT 的自我管理),知道它们分别在信息提取、知识更新、时间推理、跨会话计数、拒答这五类问题上怎样失败、花多少 token。
- 说出 AgentKit(自然语言节点组成的动态图)和 AutoGen(可对话的智能体 + 对话编程)在抽象层面做了什么,以及”用自然语言控制流程”的风险。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲只给直觉,后面再展开 Previewed only |
|---|---|
| 第 4 讲:思维链、self-consistency | 多智能体辩论、角色分工的协作(第 15 讲) |
| 第 7 讲:检索、BM25、lost in the middle | 评估设计的系统讲法(第 17 讲) |
| 第 8 讲:工具调用、ReAct 的工具版本 | |
| 第 10 讲:自我纠正需要外部反馈 | |
| 第 12 讲:最小权限、确认 | |
| 第 13 讲:规划、校验器、搜索 | |
| 前置讲 P3:配对检验、多重比较 |
0.3 本讲地图 Map
§1 智能体循环:记录、调用、执行、写回、停下 ← 代码 01
§2 ReAct:边想边做 ← 代码 02
§3 Reflexion:失败之后写一段反思 ← 代码 03
§4 角色(persona):它改变了什么、没改变什么 ← 代码 04
§5 记忆:上下文之外的"硬盘" ← 代码 05
§6 框架:AgentKit 与 AutoGen 在做什么 ← 代码 06
§7 行动:动作空间的设计
§8 在真实模型上 ← 代码 07(可选)
§9 小结 §10 常见误区 §11 练习 §12 延伸阅读 §13 下一讲预告
0.4 记号与术语 Notation & terms
| 术语 | 本讲义里的意思 |
|---|---|
| 智能体(agent) | 一个 LLM 放在循环里:反复读”到目前为止的记录”、输出下一步动作、看环境的反馈 |
| 环境(environment) | 智能体作用的对象:一个文字游戏、一个网站、一个代码仓库、一组工具 |
| 轨迹 / 记录(trajectory / transcript) | 循环到目前为止的全部内容:任务、每一步的动作和观察、思考 |
| 思考(thought) | ReAct 里模型写给自己的话,不改变环境(环境只回一句 “OK.”) |
| 反思(reflection) | Reflexion 里失败之后写的”下次怎么做”,带进下一次尝试 |
| 角色(persona) | 系统提示里给模型的身份:“You are a lawyer.” |
| 工作记忆 / 长期记忆 | 上下文窗口里的内容 / 存在上下文之外、需要时取回的内容 |
0.5 本讲的实验装置 · The setup
house_world.py 一个真实的文字家居环境(仿 ALFWorld):一个房间 17–25 个容器,物品藏在里面(40% 放在不寻常的地方)
五种任务:放置 / 清洗后放置 / 加热后放置 / 冷却后放置 / 放两个;命令与观察和 ALFWorld 的写法一致
agent_lab.py 智能体循环 run_episode;解析记录 parse_transcript;失败分类 failure_kind;Reflexion 的 reflect / run_trials
SimHouseLLM:只读记录的模拟模型;在"目标记错""状态记错"上犯错,犯错率随
"离上一次把目标 / 状态写进上下文过了几步"增长
memory_lab.py 20 次会话的聊天记录 + 七种记忆策略 + 用正则从上下文里抽答案的读者
persona_lab.py 40 个职业 / 人际关系类角色 + 对照;角色的真实效应很小、但每个(角色, 题目)有固定的提示扰动
环境、循环、解析、失败分类、检索、打分、统计检验都是真实的代码;“模型多容易记错""反思诊断得对不对""读者多容易看漏”是旋钮。所以,ReAct 比 Act 好、Reflexion 比重试好,是按机制设定的;每一节都给出论文在真实模型上的数字作对照。代码真正演示的是:每种做法为什么有效、代价是什么、在哪里失败。
1. 智能体循环 · The agent loop
1.1 直觉:一次调用 vs 一个循环
前面的讲大多是”一次调用”:问题进去,答案出来。第 8 讲的工具调用、第 13 讲的 LLM-Modulo 已经是小循环了。智能体就是把这个循环当成主角:
记录 = 任务 + 初始观察
重复:
回答 = LLM(系统提示, 记录) ← 模型只看得见记录
如果是思考:记录 += 思考 + "OK."
如果是动作:观察 = 环境.执行(动作);记录 += 动作 + 观察
如果完成 / 预算用完 / 陷入循环 / 调用太多:停
代码 01 的演示 1 在同一个环境里各跑一遍 Act(只行动)和 ReAct(边想边做)。任务是”put a hot plate in cabinet 6.”。Act 在第 5 步就开始反复执行 put plate 1 in cabinet 6——它根本没拿到盘子,环境每次都回答 “Nothing happens.”,它却不知道为什么,3 次之后循环检测把它停下。ReAct 先写了一句计划(找盘子 → 用微波炉加热 → 放进 6 号柜子,盘子更可能在哪些柜子里),然后一个个柜子找,找到、拿起、加热、放下,每个子目标完成后写一句”现在做到哪了、下一步做什么”。
1.2 循环和一次调用有什么不同
反馈。环境的观察是真实的外部信息(第 10 讲:“外部反馈”):东西藏在哪里只有看了才知道。代码 02 里有一个对照:只看初始观察、按常识猜物品在最可能的位置、一口气写完全部命令再执行——成功率只有 12.5%(目标物品恰好在第一个猜的位置时才成功);能看观察的 Act 是 46.7%。
错误累积。每一步都可能出错,而且错误会留在记录里,影响后面的每一步(第 9 讲的 p^k)。更麻烦的是,环境往往不告诉你为什么错:“Nothing happens.” 可能是没拿着东西、容器没打开、名字写错……
成本随步数增长。每次调用都要把全部记录再发一遍。代码 01 的演示 2:一局里第 1 次调用 233 个 token,第 34 次 977 个;单次输入随步数线性增长,一局的累计输入随步数平方增长。120 个环境里,调用 30–39 次的局平均累计 21,567 token,0–9 次的局 2,902 token(7.4 倍)——失败的局往往最长、也最贵。
记一个公式:第 1 次调用的输入是 个 token,每一步给记录加 个 token,跑 步,累计输入 。 翻倍,第二项翻四倍。真实 API 的提示缓存(prompt caching)能让重复的前缀便宜很多,但不能让上下文无限长——这是 §5 记忆管理的动机之一。
1.3 停止条件
一个循环至少要有四个出口:完成(环境说成功了,或者模型说完成了——后者不可靠)、预算(环境步数、token、费用、墙钟时间)、陷入循环、调用次数上限。
代码 01 的演示 3:Act 智能体在 120 个环境上,“连续 3 次同样的动作 + 同样的观察就停”时,失败的局平均 24.8 步、11,413 token 就停下;不检测循环时要跑满 30 步、14,350 token。不检测时成功率反而略高(50.8% vs 46.7%)——有 5 局的”循环”后来自己走出来了。所以早停是用一点成功率换成本;Reflexion(§3)就是在早停之后立刻反思、换个做法再来,这笔交换更划算。另一个例子:一个只思考、从不行动的病态模型永远不会用完环境步数预算,只能靠”调用次数上限”停下。
2. ReAct:边想边做 · Reasoning + Acting
2.1 直觉:人做事时的”内心独白”
ReAct 论文开头举了做饭的例子:两个具体动作之间,我们会在心里说”菜都切好了,该烧水了”(跟踪进度)、“没有盐了,用酱油代替”(处理意外、调整计划)、“面团怎么和?查一下”(意识到需要外部信息)。思维链(第 4 讲)只有推理、没有行动,会编造事实;只行动、不推理,又容易迷失。ReAct(Yao et al. 2023)把两者交错起来:
Thought: 我要找一个杯子,洗干净,放进 2 号柜子。杯子更可能在柜子、台面、架子上……
Action: go to cabinet 1
Observation: The cabinet 1 is closed.
Action: open cabinet 1
Observation: ... In it, you see a plate 1.
Thought: 1 号柜子里没有杯子,接下来看 countertop 1。
...
在 ALFWorld 里,思考是一个特殊的动作 think: ...,环境只回 “OK.”;思考是稀疏的,由模型自己决定什么时候写。在 HotpotQA 这类问答任务上,每一步都是”思考—动作—观察”(密集的思考)。
2.2 论文的结果
问答与事实核查(PaLM-540B,提示里 6 个 / 3 个人工写的示例轨迹;动作是一个很弱的维基百科 API:search[实体] 返回页面前 5 句、lookup[字符串] 返回下一句含该字符串的句子、finish[答案]):
| 方法 | HotpotQA(EM) | FEVER(准确率) |
|---|---|---|
| Standard(直接回答) | 28.7 | 57.1 |
| CoT | 29.4 | 56.3 |
| CoT-SC(21 个样本) | 33.4 | 60.4 |
| Act | 25.7 | 58.9 |
| ReAct | 27.4 | 60.9 |
| CoT-SC → ReAct | 34.2 | 64.6 |
| ReAct → CoT-SC | 35.1 | 62.0 |
ReAct 在 HotpotQA 上略低于 CoT(27.4 vs 29.4),在 FEVER 上更好。最好的是组合:ReAct 在规定步数(HotpotQA 7 步、FEVER 5 步)内没给出答案就退回 CoT-SC;或者 CoT-SC 的多数答案不到一半时改用 ReAct。
更有意思的是论文对 200 条轨迹的人工错误分析:CoT 的失败里 56% 是幻觉(编造事实),ReAct 是 0%;但 ReAct 的失败里 47% 是推理错误(包括反复生成同样的思考和动作、走不出来),CoT 是 16%;ReAct 还有 23% 是”搜索结果没用”。一句话:行动让回答有依据,但交错的结构也让推理更死板。
交互式决策:ALFWorld(134 个家务任务)上,ReAct 最好的一次 71%,Act 最好的一次 45%,模仿学习的 BUTLER 37%;ReAct 最差的一次(48%)也超过了另外两种方法最好的一次。WebShop(500 条购物指令)上成功率 ReAct 40.0%、Act 30.1%、模仿学习 29.1%,人类专家 59.6%。
2.3 为什么思考能帮助行动:把目标和进度写在最近处
ALFWorld 的任务要几十步。到第 20 步时,任务描述在上下文的开头,“我已经查过哪些柜子""我手里拿着什么""杯子洗过没有”散落在二十几条观察里。没有思考的 Act 要从这一大段记录里每一步重新推断这些状态,越往后越容易出错:忘了要先洗、回头重查、以为手里拿着东西。论文的定性观察正是:没有思考时,Act 不能把目标分解成子目标,或者丢失了对环境当前状态的跟踪。
ReAct 的思考做了三件事:开头分解目标、按常识列出先去哪找;每完成一个子目标写一句进度;动作失败时写一句处理意外。这些话不改变环境,但改变了上下文:目标和进度总在最近的几行里。
代码 02 的模拟模型正是按这个机制写的:犯错率随”离上一次把目标 / 状态写进上下文过了几步”增长。在 120 个环境上:
| 做法 | 成功率 | 平均调用 | 平均输入 token |
|---|---|---|---|
| Act | 46.7% | 19.3 | 8.1k |
| ReAct-IM(每步复述状态,不写目标) | 63.3% | 37.9 | 24.8k |
| ReAct | 70.8% | 24.1 | 13.4k |
| 先写完计划再执行 | 12.5% | 1 | – |
配对比较:Act 错 ReAct 对的环境 30 个,反过来 1 个(McNemar p = 3×10⁻⁸)。
思考的内容比数量重要。ReAct 论文做过一个消融:把思考换成 Inner Monologue(IM)式的密集反馈——只复述”我在哪、看到了什么”,不写高层的目标分解。结果 ReAct-IM 最好的一次 53%,ReAct 71%;ReAct-IM 常常搞不清子目标什么时候完成了、下一个子目标是什么。代码 02 里 IM 的思考最多(调用 37.9 次),成功率却不如 ReAct。
失败的样子(代码 02 演示 2,失败分类来自真实的记录分析):Act 的 64 个失败里 21 个是陷入循环、33 个是没找到目标物品;ReAct 没有一个陷入循环——动作没反应之后它会写”刚才没成功,我在哪、手里拿着什么、下一步做什么”。但 ReAct 仍有 14 个”没找到”:东西放在不寻常的地方时,两种做法都按常识的顺序找,都可能在找到之前用完步数。这类失败靠思考救不了——要靠 §3 的记忆。
2.4 思考也会把智能体带偏
思考是上下文的一部分,模型会相信自己写的话。代码 02 演示 3 的消融:
- 去掉”处理意外”的那类思考:70.8% → 68.3%,陷入循环 0 → 5 个;
- 让 30% 的进度思考写错(漏掉”先洗 / 加热 / 冷却”这一步):需要处理的任务成功率 73.6% → 63.9%;模型完全照着错的思考做时 → 56.9%。错的计划是自洽的:照着做完之后,它会接着写”任务完成了”,然后停在那里。
这和 ReAct 论文的错误分析一致:交错的结构让推理错误更难被纠正。让模型多想不是免费的:思考消耗调用和 token,也引入新的错误来源;它值得,是因为在长任务里它把目标和进度保持在上下文的最近处。
3. Reflexion:失败之后写一段反思 · Verbal reinforcement
3.1 直觉:不改参数的”学习”
强化学习靠成千上万次试错、用梯度更新参数。Reflexion(Shinn et al. 2023)问:能不能不改参数,让模型从几次失败里学到东西?做法是”口头的”强化学习:
第 t 次尝试:执行者(ReAct 智能体)跑一局 → 轨迹
评估器:成功了吗?(环境的二元信号 / 启发式 / 自己写的单元测试)
失败了 → 自我反思:读自己的轨迹,写一段"哪里错了、下次怎么做"
记忆:把反思存起来(最多 3 条),放进下一次尝试的提示里
ALFWorld 上的启发式评估:同样的动作得到同样的观察超过 3 次,或者动作超过 30 步,就判定失败、开始反思。
3.2 论文的结果
- ALFWorld(134 个任务,连续 12 次尝试):ReAct + Reflexion 完成 130/134(约 97%);只用 ReAct 重试的,成绩在第 6、7 次之间就不再提高,“以为自己拿着东西、其实没有”这类幻觉的比例停在 22%。论文指出两种帮助:长轨迹里一个早期的错误被识别出来;容器太多时,靠多次尝试的经验把房间”彻底搜一遍”。
- HotpotQA:只用 ReAct / CoT 以温度 0.7 重试,没有一道第一次失败的题被做对;加上 Reflexion 后显著提高(例如 ReAct + GPT-4 在 100 道题上 0.39 → 0.51)。
- HumanEval(Python):pass@1 91%,当时 GPT-4 的基线是 80.1%。代码任务的评估器是模型自己写的单元测试。在 50 道最难的 Rust 题上的消融:基线 60%;只反思、不生成测试 52%(比不反思还差——没有测试,模型判断不了当前的实现对不对,做了有害的修改);只生成测试、不反思 60%;两者都要 68%。
- 小模型不行:starchat-beta 在 HumanEval 上用了 Reflexion 也是 0.26 → 0.26。论文的结论是能写出有用的自我纠正,是更强、更大的模型才有的能力。
3.3 Reflexion 依赖什么
代码 03 在 120 个环境上让 ReAct 智能体最多试 10 次:
| 策略 | 第 1 次 | ≤ 2 次 | ≤ 3 次 | ≤ 10 次 | 输入 token 合计 |
|---|---|---|---|---|---|
| 重试(什么都不带) | 70.8% | 75.8% | 77.5% | 80.0% | 7.02M |
| Reflexion(最近 3 条反思) | 70.8% | 88.3% | 95.8% | 97.5% | 3.09M |
| 带上上一次的完整记录 | 70.8% | 77.5% | 84.2% | 94.2% | 4.00M |
一条典型的反思是这样的:“I checked countertop 1, …, drawer 1 and did not find a mug. Next time I should check drawer 2, fridge 1, microwave 1, … first.” 三点观察:
重试为什么停住。模型的常识是稳定的:同一个房间,它每次都先去同样的地方找。“东西放在意想不到的地方”是系统性的失败,重试几次都一样。(写代码时的教训:第一版模拟器让每次重试的查找顺序变化很大,结果重试也能到 97.5%——这等于假设模型在随机搜索,和论文的观察相反。)
反思是有损但有用的压缩。带上完整的旧记录也有帮助(信息都在里面),但上下文更长、每一步都更贵,模型也更难从一大段记录里找到有用的那一句。Reflexion 的总花费反而最少:成功得早,需要的尝试次数少。
它依赖三个条件:
- 评估器要可靠。代码 03 演示 3:评估器以 30% 的概率把失败误判为成功时,真实的累计成功率从 97.5% 降到 86.7%,而系统自己报告的是 100%——它以为成功了就停止尝试,而且不知道自己错了。论文在代码任务上看到了同样的事:MBPP 上自己写的测试的假阳性率是 16.3%、HumanEval 上只有 1.4%;Reflexion 在 HumanEval 上大幅提高,在 MBPP 上反而不如 GPT-4 基线。这就是第 10 讲的结论:自我改进的上限是评估器的可靠性。
- 反思要诊断对。代码 03 演示 2:第 2 次尝试后的累计成功率,在诊断准确率 1.0 / 0.85 / 0.5 / 0.0 时依次是 92.5% / 88.3% / 80.8% / 75.0%;全是空话(“下次我会更仔细”)时 10 次后 80.8%,和不带反思的重试一样。多试几次,诊断对一半也能追上——空话不帮忙但也不伤害,总有一次写对。
- 它学到的多半是”这个房间”。代码 03 演示 4 把反思带到新的房间:ReAct 智能体 69.2% → 68.3%,几乎没有收益;Act 智能体 46.7% → 35.8%,反而变差——“下次先查 X”在新房间里是错的指引;只带”必须先洗再放""动作没反应就检查手里有什么”这类关于任务的反思,Act 是 48.3%。
所以 Reflexion 在 ALFWorld 上很大一部分收益是”记住了这个实例”——它在同一个环境里反复尝试。在真实应用里,你很少能把同一个任务做 10 次;想要可迁移的经验,反思要写成一般性的规则,并且要有机制区分”这次的事实”和”以后都适用的教训”(这正是 §5 的记忆要解决的问题)。
4. 角色(persona):它改变了什么、没改变什么 · Personas
4.1 角色提示用来做什么
“You are a helpful assistant.”、“You are an experienced tax accountant.”——系统提示里写一个身份,几乎是最常见的提示技巧。它至少有四种用途:
- 风格与语气:像老师一样解释、像编辑一样挑错、简洁 / 正式 / 口语化;
- 视角与关注点:安全审查员会先看风险,产品经理会先看用户——让模型从某个角度审视同一个问题;
- 模拟人:Generative Agents(§5.3)给每个智能体一段身份描述(职业、性格、人际关系),让 25 个智能体在一个小镇里生活;
- 多智能体的分工:第 15 讲的辩论、评审团、软件公司式的协作,都靠给不同的智能体不同的角色。
4.2 它能提高准确率吗?
一个流行的说法是”告诉模型它是专家,它就会答得更好”。Zheng et al.(2024)系统地测了这件事:162 个角色(6 类人际关系、8 个专业领域),4 个开源模型家族,2,410 道 MMLU 题。结论:
- 和不加角色的对照相比,加角色整体上不提高客观题的准确率;
- 角色的种类、领域等因素会影响准确率,但每个角色的效应很大程度上是随机的;
- 每道题都用”最好的那个角色”(事后挑)能显著提高准确率;但自动地挑出最好的角色很难,常常不比随机挑好。
代码 04 用一个模拟模型复现这种局面:角色的真实效应很小,但换一句系统提示会让一批边界题”翻转”。40 个职业 / 人际关系类角色 + 对照,1,200 道题:
- 准确率从 58.2% 到 61.6%,对照 61.1%。看起来差了 3 个多点。
- 逐个和对照做配对检验(McNemar):不校正时 5 个 p < 0.05,Holm 校正后 0 个。每个角色和对照平均有 125 道题结果不同——大部分是边界题上的随机翻转。
- 40 个角色里只有 3 个高于对照,平均 60.1%——不是”加角色普遍变差”,而是对照本身也是一次带扰动的抽样,碰巧偏高。
- 20 次随机划分开发 / 测试集:开发集上挑出的”最好角色”平均高 1.0 点,到测试集上 −0.6 点,在测试集上平均排第 14.4 名(共 40 个)。
- 事后挑(只要有一个角色答对就算对)77.8%;能事先做的——随机挑 61.0%、按领域挑”对口”角色 60.7%、40 个角色多数投票 60.2%——都和对照差不多。
- 分半一致性:把题目分成两半,40 个角色的准确率效应在两半之间的相关系数是 −0.01;回答长度的相关系数是 +1.00。
最后一条是判断角色效应最实用的工具:一个真的效应应该在两半数据上都出现。准确率的”角色效应”不是角色的稳定属性;风格是。
一个数字:40 次比较、每次 α = 0.05,就算全是噪声,至少一个 p < 0.05 的概率是 。只报”最好的那个角色提高了 X 点”而不说试了多少个,就是第 10 讲的赢家诅咒。
4.3 角色的副作用
Gupta et al.(2024,ICLR)研究了给模型分配社会身份类的角色(种族、性别、宗教、残障、政治立场五类,共 19 个)对推理能力的影响:24 个推理数据集、4 个模型。模型在被直接问到时会明确拒绝刻板印象,但扮演某些角色时,会在推理题上表现出带偏见的错误假设——有时是明确的拒答(以角色身份为理由说自己答不了),更多时候是不明显的准确率下降。在 ChatGPT-3.5 上,80% 的角色表现出这种偏差,某些数据集上相对下降超过 70%;GPT-4-Turbo 最轻,但仍有 42% 的角色表现出偏差;用提示去纠正几乎无效。
这和 §4.2 是同一个教训的两面:角色是上下文的一部分,它会以你没有预料的方式改变模型的行为。
4.4 实用建议
- 用角色控制风格、语气、视角、输出格式——这些效应稳定、容易验证(写几个例子看看就知道)。
- 想用角色提高准确率,把它当成一个需要实验证明的假设:配对比较、多个角色就做多重比较校正、独立的测试集、分半一致性(第 17 讲)。
- 与其写”你是一位专家”,不如把专家会做的事写清楚:要检查哪些条件、按什么步骤、输出什么格式。具体的指令比身份标签更可控(第 3 讲)。
- 产品里给模型分配面向用户的身份时,要在多个用户群体上测试它的行为,而不只看平均准确率(第 6 讲)。
5. 记忆:上下文之外的”硬盘” · Memory
5.1 为什么需要记忆管理
一个智能体的”记忆”至少有四种(Sumers et al. 2024 的 CoALA 框架借用了认知科学的分类):工作记忆(这一刻上下文里的东西)、情景记忆(发生过的事:对话、轨迹)、语义记忆(关于世界和用户的事实)、程序性记忆(怎么做事:提示本身、代码、Reflexion 的经验)。
上下文窗口是工作记忆。它有三个问题:有上限(长对话、长任务装不下);贵(§1.2:每一步都要重发);越长越容易看漏(第 7 讲的 lost in the middle)。LongMemEval(Wu et al. 2025,ICLR)用 500 道题测了聊天助手的五种长期记忆能力——信息提取、跨会话推理、时间推理、知识更新、拒答——发现商用聊天助手和长上下文模型在持续的多轮交互里,记忆的准确率下降约 30%。
所以要把记忆放到上下文之外,需要时再取回来。问题变成:存什么、怎么存、什么时候取、取什么。
5.2 几种策略
| 策略 | 做法 | 典型的失败 |
|---|---|---|
| 滑动窗口 | 只留最近 W 个 token | 窗口之外的事全忘了 |
| 滚动摘要 | 每段对话结束后,把”旧摘要 + 新内容”压缩成新摘要 | 每次压缩都可能丢东西,丢了就补不回来;只留”现状”,丢掉”历史” |
| 检索式记忆 | 每一轮都存起来,提问时检索 top-k | 词对不上就检索不到;旧事实和新事实都被检索回来,分不清哪个是现在的 |
| Generative Agents 的打分 | 检索分 = 相关性 + 新近性 + 重要性 | 权重要按问题的分布调 |
| MemGPT 的自我管理 | 模型自己调用函数,把关键事实写进”核心记忆”、可以覆盖;全部原文另存可检索 | 写入会漏记;模型要学会管理自己的记忆 |
5.3 Generative Agents:记忆流、反思、计划
Park et al.(2023)在一个类似《模拟人生》的小镇里放了 25 个智能体。每个智能体有一个记忆流(memory stream):所有观察按时间存成一条条自然语言记录。需要时按三项打分检索:
- 新近性:按距离上次访问的游戏小时数指数衰减,衰减系数 0.995;
- 重要性:记录创建时让 LLM 打 1–10 分(论文的例子:“打扫房间”2 分,“约暗恋的人出去”8 分);
- 相关性:记录和当前情境的嵌入余弦相似度。
三项各自 min-max 归一化后相加(论文里权重都是 1),取分数最高、放得进上下文的那些。
此外还有反思:最近事件的重要性之和超过阈值(150)时,让 LLM 从最近 100 条记录里提出问题、归纳出更高层的看法(例如”Klaus 很投入他的研究”),反思本身也存进记忆流,可以再被反思——形成一棵反思树。实践中每个智能体每天反思两三次。计划则是把一天分解成几段、再逐级细化。
评估:100 名参与者对 5 种条件的回答按”像不像真人”排序,换算成 TrueSkill 分数:完整架构 29.89,去掉反思 26.88,去掉反思和计划 25.64,众包工人扮演 22.95,没有记忆、计划和反思 21.21。在小镇里,“Sam 要竞选镇长”这条消息的知晓者从 1 人(4%)扩散到 8 人(32%),“Isabella 要办情人节派对”从 1 人扩散到 13 人(52%);收到邀请的 12 个智能体里有 5 个真的到了。论文也记录了失败:随着记忆变多,检索最相关的信息越来越难,还有编造细节的情况。
5.4 MemGPT:把 LLM 当作操作系统
Packer et al.(2023)借用操作系统的虚拟内存:物理内存(上下文窗口)有限,靠在内存和磁盘之间换页,给程序一个”无限内存”的假象。MemGPT 的上下文分成系统指令、工作上下文(可编辑的关键事实)、先进先出的消息队列;上下文之外有回忆存储(全部历史消息)和档案存储(任意文本)。模型通过函数调用读写这些存储、修改自己的工作上下文。
一个关键机制是”内存压力”:提示的 token 超过上下文的 70% 时,系统插一条警告,让模型赶紧把重要信息写到工作上下文或档案里;到 100% 时,系统清掉一部分消息(例如上下文的 50%),并把它们和旧的递归摘要一起压缩成新的递归摘要——被清掉的消息仍然存在回忆存储里,可以检索回来。
论文的”深度记忆检索”任务(第 6 次会话问前 5 次会话里的细节):GPT-3.5 Turbo 38.7% → 加 MemGPT 66.9%;GPT-4 32.1% → 92.5%;GPT-4 Turbo 35.3% → 93.4%。
5.5 实验:七种策略 × 五类问题
代码 05 生成 40 个用户、每人 20 次会话(约 1.2 万 token)的聊天记录:用户在不同时候说过狗的名字、对什么过敏、住在哪(后来搬家一到两次)、做什么工作(后来换了)、去过哪些地方旅行;最后问 9 个问题。读者用真实的正则从上下文里抽取答案,看漏的概率随上下文长度增长。
| 策略 | 信息提取 | 知识更新 | 时间推理 | 跨会话计数 | 拒答 | 全部 | 每题上下文 token |
|---|---|---|---|---|---|---|---|
| 整段历史 | 79% | 90% | 65% | 50% | 69% | 74.4% | 12,007 |
| 滑动窗口 4k | 4% | 51% | 0% | 0% | 74% | 29.2% | 3,961 |
| 滚动摘要 + 最近 1k | 90% | 62% | 28% | 50% | 72% | 68.6% | 1,025 |
| 检索(BM25 top-5) | 56% | 6% | 5% | 0% | 79% | 38.1% | 408 |
| 检索 + 事实关键词 | 84% | 91% | 85% | 55% | 75% | 80.6% | 433 |
| Generative Agents 打分 | 63% | 60% | 5% | 0% | 70% | 50.6% | 472 |
| MemGPT 式核心记忆 + 档案 | 95% | 74% | 80% | 62% | 70% | 79.4% | 311 |
| 只给证据(上限) | 99% | 96% | 90% | 92% | 71% | 90.6% | 154 |
逐行读:
- 整段历史最省事,但每道题 1.2 万 token,而且看漏得多(比上限低 16 个点)。代码 05 演示 4:历史从 20 次会话增加到 40、60 次(事实都在前 20 次里说过),整段历史 76.7% → 63.3% → 50.0%,上下文涨到 3.6 万 token;检索 + 关键词(78.3 / 73.3 / 75.6%)和 MemGPT 式(81.7 / 82.2 / 78.3%)的上下文和准确率都基本不变。
- 滑动窗口的准确率几乎完全取决于事实离现在多远:窗口 2k / 4k / 8k 时全部 17.5% / 29.2% / 58.6%。
- 普通检索在知识更新上只有 6%。问题是”我现在住在哪”,搬家那句话是”我们搬到了 X”——词对不上,检索回来的反而是很早以前那句”我住在 Y”。“去过几个地方”和”我刚从 X 旅行回来”也对不上。
- 存的时候加事实关键词(让 LLM 给每一轮写”住址 城市 搬家”这类关键词):知识更新 6% → 91%,全部 38.1% → 80.6%。代价是写入时每轮一次 LLM 调用。这就是 LongMemEval 提出的”用事实扩展索引的键”(fact-augmented key expansion);它还提出了按会话拆分、按时间扩展查询等优化——记忆系统的设计分成索引、检索、读取三个阶段,每一段都可以优化。
- MemGPT 式的核心记忆始终在上下文里、搬家时覆盖旧值,所以每题只要 311 token;但写入会漏记,知识更新 74%(没覆盖成功就还是旧值)。
- 滚动摘要擅长保留”现状”(信息提取 90%),不擅长保留”历史”(时间推理 28%)——“以前住在哪”在一次次压缩里丢掉了。摘要上限从 60 放宽到 120 时,时间推理 5% → 28%;每次漏记 40% 时信息提取 90% → 67%:摘要一旦漏记,没有任何机制能补回来——这是 MemGPT 另存一份全部原文的原因。
- 拒答(从没说过的事)各种策略都在 69%–79%:这主要是读者的性质(什么都没找到时有一定概率编一个),记忆策略管不了——第 5 讲的幻觉换了个样子出现。
Generative Agents 打分的三项(代码 05 演示 2):只看相关性时知识更新 6%;加上新近性 21%(最近的”搬到了 X”即使词对不上,也因为”新”被捞上来),但信息提取 56% → 48%;加上重要性,信息提取 76%、知识更新 41%、时间推理 52%。三项都要反而只有 50.6%,不如”相关性 + 重要性”的 56.1%:新近性把久远的事挤了出去(时间推理 52% → 5%)。Generative Agents 的场景是”模拟一个人的日常”,最近发生的事最要紧;一个要记住用户长期信息的助手,权重就该不一样。
5.6 设计记忆时要回答的问题
- 写什么:原文全存(便宜、无损、难检索)还是让 LLM 提炼事实(贵、有损、好检索)?通常两者都要:提炼的事实做索引,原文做后备。
- 什么时候写:每一轮?每次会话结束?上下文快满时(MemGPT 的内存压力)?
- 怎么处理冲突和更新:新事实覆盖旧事实,还是两者都留、带上时间戳?“以前住在哪”这类问题要求保留历史。
- 什么时候取、取多少:每一步都检索(贵)还是让模型自己决定什么时候查(MemGPT 的函数调用)?
- 怎么忘:过时的信息、用户要求删除的信息。记忆里存的是用户的个人数据——最小化收集、让用户能查看和删除,和第 12 讲的最小权限是同一个原则。存进记忆的内容也会被未来的提示读到:来自不可信来源的内容写进长期记忆,就成了一个持久的注入面(第 12 讲)。
6. 框架:AgentKit 与 AutoGen 在做什么 · Frameworks
框架的价值不在于给模型新的能力,而在于把常见的结构写成可复用的抽象。代码 06 从零写了两个迷你版本,接在同一个家居环境上。
6.1 AgentKit:把思考过程画成图
AgentKit(Wu et al. 2024,COLM)的基本单位是节点:一个节点是一个子任务的自然语言提示。节点之间有依赖,组成一张有向无环图(DAG),像搭乐高一样拼出一个”思考流程”。每个节点执行时:把依赖节点的输出拼进自己的提示 → 调用 LLM → 后处理。整张图按拓扑顺序执行(论文用 Kahn 算法)。节点和依赖可以在运行时动态增删(例如某个节点发现上一步失败了,就加一个”诊断”节点);为了保证拓扑顺序有效,新加的边不能指向已经执行过的节点。
论文的卖点是可控和易用:一个基本的智能体可以简单到”一串子任务提示”,不会编程的人也能设计和调整。它在 Crafter(开放世界生存游戏)上的奖励比 SPRING(GPT-4-turbo)高 80%,和 SPRING(GPT-4)相当但便宜 45%;在 WebShop 上用一个 6 节点的零样本智能体比当时最好的方法高 5%(前 100 个样本)。
代码 06 演示 1:每一步执行一张 progress →(diagnose)→ action 的图,80.0%,ReAct 70.8%;调用 36.9 vs 24.1 次。图式智能体强制每一步都”先总结进度、再选动作”,目标和状态永远写在最近处——和 ReAct 的机制相同,只是从”模型自己决定什么时候想”变成”流程规定每一步都想”。输入 token 反而略少(12.6k vs 13.4k):这张图的进度说明每一步重新写、不留在记录里——“哪些中间结果留在上下文里”也是图的设计的一部分。
6.2 AutoGen:可对话的智能体
AutoGen(Wu et al. 2023,Microsoft)的核心抽象是可对话的智能体(ConversableAgent):能收发消息、能根据对话历史生成回复;回复可以来自 LLM、工具(执行代码)、人,或它们的组合。两个预置的子类:AssistantAgent(LLM 驱动,写代码、出主意)和 UserProxyAgent(执行代码、或代表人类输入;human_input_mode 控制什么时候问人)。应用写成智能体之间的对话——论文称之为对话编程(conversation programming):先定义有不同能力和角色的智能体,再定义它们怎样交互。
论文的几个应用:MATH 数据集 120 道最难的(level-5)题上,两个内置智能体直接组合就得到 69.48%,高于同实验里的纯 GPT-4 和几种商用插件方案;ALFWorld 上,在”助手 + 执行者”的基础上加一个 grounding 智能体——当助手连续 3 次输出同一个动作时,插一句常识(例如”要先找到并拿起物品,才能检查它”)——在 134 个任务上平均提高 15%(GPT-3.5-turbo)。
代码 06 演示 2 写了一个迷你 GroupChat:
- 助手 + 执行者(Act 提示)50.8%——和不做循环检测的循环逐个环境比较,120/120 个结果相同。群聊只是把”模型 → 环境 → 模型”换成了”智能体之间发消息”的写法,本身不带来能力。
- 加 grounding 智能体:Act 50.8% → 55.0%(插话 22 次),ReAct 72.5% → 72.5%(插话 5 次)。它帮的是最容易陷入循环的那种智能体。注意 AutoGen 论文里 grounding 智能体说的常识,是作者看了失败案例之后总结出来的——框架让”加一个角色”很容易,但加什么角色、它说什么,仍然要靠分析错误。
6.3 用自然语言控制流程的风险
AutoGen 同时支持两种控制流程的方式:自然语言(系统提示里要求”做完了就回复 TERMINATE”)和代码(max_consecutive_auto_reply、终止条件函数)。代码 06 演示 3:如果助手每轮只有 30% 的概率记得说 TERMINATE,任务完成后平均还要互相客套 2.55 轮(最多 17 轮),设了自动回复上限 3 之后 1.58 轮。每一轮都是一次带着整段历史的调用。
教训:自然语言的控制是软的,必须有代码层面的硬上限兜底。这和 §1.3 的”调用次数上限”是同一个道理,也是第 12 讲”不要让模型的输出直接决定权限”的同一个原则。今天的智能体框架形形色色,但核心抽象差不多就是这几样:循环、工具、记忆、图 / 状态机、多个智能体之间的消息;看一个新框架时,先找出它的这几样东西各是怎么实现的。
7. 行动:动作空间的设计 · Actions
原课这一讲的标题里有”Actions”。智能体能做什么,是由动作空间决定的,而动作空间是设计者写的——它和提示一样,是”提示工程”的一部分。前几讲已经从不同角度碰到过它,这里集中说几条:
- 动作要粒度合适。ALFWorld 的动作是高层的(
go to cabinet 1而不是”向左转 30 度”);ReAct 的维基百科 API 故意做得很弱(只能按精确的标题搜索),逼模型用语言推理去组织检索。第 11 讲的 SWE-agent 说明:为 LLM 专门设计的”智能体–计算机接口”(带行号的文件查看、带语法检查的编辑)比直接给它一个 shell 好得多。 - 反馈要有信息量。“Nothing happens.” 让智能体陷入循环;“你手里没有 plate 1”能让它立刻改正。在你能控制环境的地方(自己写的工具),错误信息要说清楚为什么失败、怎样修正(第 8 讲)。
- 动作要能被校验。在执行之前检查参数和前提条件(第 8 讲的参数校验、第 13 讲的计划校验器),比执行之后再收拾残局便宜。
- 动作要有权限边界。能读文件不等于能删文件;能发草稿不等于能发送。不可逆的、对外的动作要人确认;智能体处理不可信内容时,权限要收紧(第 12 讲的最小权限、数据流检查)。
- 思考也是一种动作。ReAct 把”思考”放进了动作空间;MemGPT 把”写记忆、读记忆”放进了动作空间;Reflexion 把”反思”放在两次尝试之间。把一个能力做成动作,模型就要学会什么时候用它——这本身会出错(§2.4)。
8. 在真实模型上 · On a real model
07_real_llm.py 把同一个循环接到真实的 Claude 上:5 个环境(每种任务一个),Act 和 ReAct 各跑一遍,系统提示里放一条示例轨迹(先查一个空柜子,再找到、拿起、清洗、放下;ReAct 版本带思考)。默认模型 claude-opus-5-5(effort = low),预算上限 2.00 美元;也可以用 --model 换一个便宜的模型。--toy 模式用模拟模型。
编写讲义时环境里没有安装 anthropic SDK,所以这里不报告真实模型的数字。建议读者运行后重点读记录(cache/ 里的日志):真实模型的思考写了什么?它会不会犯”以为拿着东西""跳过处理步骤”这些错误?强模型在这么小的环境里可能 Act 也几乎全对——那就把步数预算调小、换更弱的模型,或者让更多物品放在不寻常的地方(p_unusual),看差距是否出现。
9. 小结 · Summary
- 智能体 = LLM + 循环 + 环境。循环带来外部反馈,也带来错误累积和随步数平方增长的成本;必须有完成、预算、循环检测、调用次数上限这几个出口。
- ReAct 把思考和行动交错:思考不改变环境,但把目标和进度写在上下文的最近处、在动作失败时处理意外。思考的内容比数量重要;写错的思考会把智能体带偏。论文:ALFWorld 71% vs Act 45%;HotpotQA 上 CoT 的主要失败是幻觉,ReAct 的主要失败是推理错误。
- Reflexion 是不改参数的”学习”:失败 → 反思 → 带进下一次。它依赖可靠的评估器和诊断对的反思;在 ALFWorld 上,它学到的很大一部分是”这个房间”,换了房间就不灵了。
- 角色稳定地改变风格和视角,但在客观题的准确率上效应很小、很不稳定(Zheng et al. 2024),还可能带来副作用(Gupta et al. 2024)。评估一个角色要用配对检验、多重比较校正、独立测试集和分半一致性。
- 记忆:窗口会忘、摘要会丢历史、检索会词对不上、打分的权重要按问题调、自我管理会漏记。把记忆放到上下文之外是为了成本和可靠性——上下文越长,越贵也越容易看漏。
- 框架(AgentKit、AutoGen)把循环、节点图、多智能体对话写成可复用的抽象;它们带来结构和可控性,不带来新的能力。自然语言的控制是软的,要有代码层面的硬上限。
10. 常见误区 · Common pitfalls
- “让模型多想总是好的。” 思考消耗调用和 token,也会引入新的错误;只复述状态的密集思考(IM)不如写清目标和进度的稀疏思考(ReAct)。
- “一个智能体失败了,多试几次就好。” 系统性的失败(东西藏在意想不到的地方、模型的常识就是错的)重试多少次都一样;要么把失败的原因带进下一次(Reflexion),要么改环境或提示。
- “Reflexion 让模型学会了这类任务。” 在同一个环境实例里反复尝试,它学到的多半是这个实例的事实;换一个实例,“先去 X 找”可能是错的指引。
- “自我评估说成功了,那就是成功了。” 评估器的假阳性会让智能体提前停下,而且系统自己报告的成功率会虚高。能用外部的、可验证的信号就用外部的。
- “告诉模型它是专家,它就会答得更准。” 系统的研究表明整体上不会;你在开发集上看到的”最好角色”很可能只是噪声。
- “上下文窗口够大,就不需要记忆管理。” 放得下不等于看得见:上下文越长越容易看漏,也越贵。
- “检索式记忆能解决一切。” 词对不上就检索不到;旧事实和新事实一起被检索回来时,要有时间信息才能分清哪个是现在的。
- “用了多智能体框架,系统就更强了。” 群聊只是换了一种写法;收益来自加了什么角色、它提供了什么信息,而那要靠分析失败来设计。
- “系统提示里写了’做完就说 TERMINATE’,循环就会停。” 自然语言的控制是软的,必须有代码层面的上限。
11. 练习 · Exercises
练习 1(概念) 对下面三种做法,各说出一种最典型的失败方式,并说明它来自哪里:(a)只推理不行动(CoT);(b)只行动不推理(Act);(c)ReAct。
参考答案:(a)CoT:幻觉——需要的事实不在模型的知识里,它就编一个(ReAct 论文的错误分析里,CoT 的失败 56% 是幻觉);来自”没有外部信息”。(b)Act:丢失目标和状态——长任务里忘了子目标(没洗就放)、忘了查过哪里、以为手里拿着东西,动作失败后原样重试、陷入循环;来自”目标和状态散落在长记录里,没有被重新写出来”。(c)ReAct:推理错误——思考本身写错,模型照着错的思考做,或者反复生成同样的思考和动作走不出来(论文:ReAct 的失败 47% 是推理错误);来自”思考是上下文的一部分,模型会相信自己写的话”,以及交错的结构让推理不够灵活。
练习 2(计算) 一个智能体第 1 次调用的输入是 250 个 token,之后每一步给记录加 40 个 token。(a)跑 30 步,累计输入多少 token?(b)按每百万输入 token 4 美元算,一局多少钱?(c)如果用 Reflexion 最多试 3 次、每次都跑满 30 步,最坏情况多少钱?反思本身的调用忽略不计,记忆里的反思每条 50 token。
参考答案:(a)第 i 步(i 从 0 起)输入 250 + 40i,累计 token。(b) 美元。(c)第 1 次 24,900;第 2 次每步多 50 token(1 条反思),多 ,共 26,400;第 3 次多 2 条,共 27,900;合计 79,200 token,约 0.32 美元。注意第二项(40 × 435)占了大头——步数是成本的主要来源;而记忆里的几条反思相比之下很便宜,这是 Reflexion 比”带上完整的旧记录”省钱的原因(旧记录每条就有约 1,000–1,500 token)。
练习 3(动手) 把 03_reflexion.py 里 Reflexion 的记忆条数 memory_size 从 3 改成 1 和 10(run_trials(..., memory_size=1)),重新运行演示 1。结果怎样?为什么”记得越多”不一定越好?
参考答案:编写讲义时:第 3 次尝试后的累计成功率 memory_size = 1 / 3 / 10 依次是 92.5% / 95.8% / 95.8%;10 次后是 99.2% / 97.5% / 95.8%。前几次,多留几条反思有帮助(每条都告诉它一个新的”这里没有”);到后面,留得多反而略差:旧的反思和新的反思会互相矛盾(第 2 次说”先查 A、B”,第 4 次说”A 里没有,先查 C”),而且还有一些空话占着位置。论文把记忆截断到最近 3 条,理由是避免提示太长;这个实验说明还有另一个理由——过时的、互相矛盾的记忆会干扰判断。真实系统里要有机制合并、更新、淘汰记忆,而不是只往里加。(差别只有一两个环境,120 个环境上不显著;这里要看的是趋势和原因。)
练习 4(设计) 为一个客服智能体设计记忆:它要记住每个用户的订单、偏好(例如”不要在晚上打电话”)、以前投诉过的问题。(a)哪些放进”始终在上下文里”的核心记忆、哪些放进可检索的档案?(b)用户说”我搬家了,新地址是……”,怎样更新?(c)列出至少两条隐私方面的要求。
参考答案(一种可能):(a)核心记忆:当前的联系方式和地址、明确的偏好(“不要在晚上打电话”)、当前未解决的工单——每次对话都要用、数量少、要求准确;档案:历史对话原文、历史订单和已解决的投诉——偶尔需要、量大,按订单号 / 时间 / 关键词检索,索引时加上事实关键词(“地址 搬家""退款 投诉”)以免词对不上。(b)地址是会变的事实:覆盖核心记忆里的当前地址,同时在档案里保留带时间戳的旧地址(“某天之前住在 X”)——这样”寄到我以前的地址了”这类问题也能回答;更新时最好向用户复述确认。(c)隐私:只存提供服务需要的信息(最小化);用户能查看和删除自己的记忆;敏感信息(支付信息、证件号)不进入可被模型读到的记忆;不同用户的记忆严格隔离;对来自外部(例如用户转发的邮件)的内容,写进长期记忆之前要当作不可信数据处理(第 12 讲)。
练习 5(统计) 你测了 40 个角色,每个和对照做一次 α = 0.05 的检验,发现 3 个显著。(a)如果所有角色其实都没有效应,至少一个显著的概率是多少?期望有几个?(b)Holm 校正在做什么?(c)还有什么办法确认那 3 个角色是真的?
参考答案:(a)至少一个:;期望 个。看到 3 个显著和”全是噪声”并不矛盾。(b)Holm 把 p 值从小到大排序,第 i 小的(i 从 0 起)和 比较,一旦有一个不显著就停下;它保证”至少一个假阳性”的概率不超过 α(前置讲 P3)。代码 04 里不校正 5 个显著、校正后 0 个。(c)在一组新的题目上只测这 3 个角色(预先说好只测它们),看效应是否重现;或者看分半一致性——把题目分两半,效应在两半里方向是否一致;还可以换一个模型、换一种问法看是否稳健。
练习 6(批判) 一份报告说:“我们给编程智能体加了一个’资深工程师’角色,并接入了 AutoGen 的多智能体框架,在 50 个任务上成功率从 62% 提高到 66%。“指出至少四个问题。
参考答案:(1)50 个任务上 62% vs 66% 只差 2 个任务,95% 置信区间各有 ±13 个点左右,几乎肯定不显著;要报配对比较(McNemar)和区间。(2)同时改了两件事(角色和框架),不知道哪个起作用;要做消融。(3)没说试了多少个角色、多少种配置——如果试了很多个、报最好的那个,就是赢家诅咒;要在独立的测试集上确认。(4)没有报成本:多智能体框架往往多出很多调用,成功率提高 4 个点可能以几倍的 token 为代价。(5)“资深工程师”角色的效应按 Zheng et al. 的结果多半很小且不稳定;与其写身份,不如把资深工程师会做的检查(先跑测试、读错误信息、最小修改)写成具体的指令或节点。(6)没说失败是什么样的:如果剩下的失败都是”陷入循环”,加一个 grounding 式的提示或循环检测可能比换框架更有效。
12. 延伸阅读 · Further reading
行动与推理
- Yao et al. (2023). ReAct: Synergizing Reasoning and Acting in Language Models. ICLR.
- Shridhar et al. (2021). ALFWorld: Aligning Text and Embodied Environments for Interactive Learning. ICLR.
- Sumers, Yao, Narasimhan & Griffiths (2024). Cognitive Architectures for Language Agents(CoALA). TMLR.
从经验里学
- Shinn et al. (2023). Reflexion: Language Agents with Verbal Reinforcement Learning. NeurIPS.
角色
- Zheng et al. (2024). When “A Helpful Assistant” Is Not Really Helpful: Personas in System Prompts Do Not Improve Performances of Large Language Models. arXiv:2311.10054.
- Gupta et al. (2024). Bias Runs Deep: Implicit Reasoning Biases in Persona-Assigned LLMs. ICLR.
记忆
- Park et al. (2023). Generative Agents: Interactive Simulacra of Human Behavior. UIST.
- Packer et al. (2023). MemGPT: Towards LLMs as Operating Systems.
- Wu et al. (2025). LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory. ICLR.
框架
- Wu et al. (2024). AgentKit: Structured LLM Reasoning with Dynamic Graphs. COLM.
- Wu et al. (2023). AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation.
13. 下一讲预告 · Next lecture
这一讲的最后已经出现了”第二个智能体”:AutoGen 的 grounding 智能体在助手陷入循环时插一句提示。如果让多个智能体一起解决问题呢?第 15 讲继续原课第 11 周:多智能体:协作与辩论。
- 为什么多个智能体可能比一个好:多样性、相互检查、分工;
- 多智能体辩论(Du et al. 2024;Liang et al. 2024):几个模型各自作答、互相看答案、再修改,最后取多数或由裁判决定;
- 一个模型扮演多个角色(Solo Performance Prompting)、角色扮演协作(CAMEL)、软件公司式的分工(MetaGPT、ChatDev)、评审团(ChatEval);
- 什么时候辩论没用:模型之间太相似(错得一样)、从众、说服力和正确性无关,以及同样的调用次数下,self-consistency 往往就够了。