Agent Engineering 课程阅读
首页/课程七 · 智能体前沿/方法预热:读论文、拆源码、立基线

在 GitHub 查看原文

本页目录

Lesson 00 — 方法预热:读论文、拆源码、立基线

本课目标:建立前沿学习的三件工具——精读论文的方法、拆框架源码的方法、用基线对照实验的方法;并跑出贯穿全课程的「失忆基线」,作为之后每个机制收益的对照零点。

学完你能回答:「没有标准答案的前沿领域,你怎么学、怎么判断一个机制到底有没有用?」——答案是先有方法、再有结论。没有基线对照的「优化」都是玄学。


0. 为什么这门课开头不一样

前六门课(RAG/Agent/框架/多智能体/LLMOps/多模态文档智能)教的是已收敛的知识:RAG 怎么切块、ReAct 怎么写循环、SqliteSaver 怎么用——业界有标准答案,README 可以说「标准做法是……」。

这门课教的是未收敛的前沿:Agent 记忆怎么分层?反思到底有没有用?Code Agent 的沙箱做到什么级别才够?轨迹评估用什么指标?——业界没有标准答案,只有「几种流派 + 各自的取舍」。所以本课先立方法:怎么读论文、怎么拆源码、怎么用实验裁决。

🎯 核心认知:前沿领域的能力不是「学会别人的答案」,而是「在没有答案的地方自己找答案」。这门课的交付物不是「记住了几个机制」,而是「养成了一个会记忆、能反思、会写代码、跨会话进化的深度研究智能体,并且每一步改进都有数据支撑」。


1. 精读论文的三遍读法

前沿知识的一手来源是论文。但论文不是小说,不能从头读到尾。我用的方法是三遍读法——每一遍带着不同的目的,逐步深入。

第一遍:摘要 + 图表(5 分钟,判断值不值得读)

只看:标题 → 摘要 → 结论段 → 所有图表。目标:用 5 分钟判断这篇论文解决了什么问题、用了什么方法、结果好不好。不值得读的论文在这里就被筛掉。

第二遍:方法部分(30 分钟,搞懂怎么做)

重点读 Method/Approach 章节,搞懂:输入输出是什么 → 核心机制是什么 → 有哪些组件 → 组件之间怎么协作。这一遍不看实验细节,只追「它到底干了什么」

第三遍:带着复现意图读(1-2 小时,能不能复现)

带着「我要复现它的核心 idea」去读:实验怎么设置的?baseline 是什么?消融实验怎么做的(去掉某组件看掉多少)?哪些是核心贡献、哪些是工程 trick?这一遍读完,你应该能写出「最小复现计划」

带读:ReAct(Yao et al. 2022)

论文:ReAct: Synergizing Reasoning and Acting in Language Models(Yao et al. 2022, arXiv:2210.03629

一句话说它证明了什么:让 LLM 在「推理(Thought)」和「行动(Act/调用工具)」之间交替,比纯推理(Chain-of-Thought)或纯行动(Act-only)都好——推理帮行动有方向,行动帮推理接地气。

  • 第一遍(摘要+图表):问题=LLM 只推理会幻觉(没有外部事实 grounding)、只行动会乱调工具(没有规划)。方法=Thought→Action→Observation 循环。图表显示 ReAct 在 HotpotQA/ALFWorld 上比 CoT 和 Act-only 成功率都高。
  • 第二遍(方法):核心是一个 prompt 模板,引导 LLM 按格式输出 Thought: ... Action: ... Observation: ...,Observation 是工具返回结果回注 prompt。就这么简单——没有训练,纯 prompt。
  • 第三遍(复现意图):最小复现 = 一个 while 循环 + 一个 prompt 模板 + 一个工具执行器。你在 agent-lessons/03 已经手写过,这就是 ReAct。消融实验的关键洞察:去掉 Thought(纯 Act)成功率明显下降——推理不是装饰,是行动的导航

带读:Reflexion(Shinn et al. 2023)

论文:Reflexion: Language Agents with Verbal Reinforcement Learning(Shinn et al. 2023, arXiv:2303.11366

一句话说它证明了什么:把失败转成「语言化的自我反思」存进记忆,下次重试时带上这段反思,能显著提升成功率——这被称为「不用梯度的强化学习」(用语言反馈代替参数更新)。

  • 第一遍:问题=ReAct 一次失败后,下一轮完全失忆,会犯同样的错。方法=失败后让 LLM 自评「为什么失败」生成反思文本,存入 episodic memory,下一轮 prompt 注入。图表显示带反思的重试成功率随轮次上升。
  • 第二遍:三组件——Actor(执行任务)、Evaluator(判成功失败)、Self-Reflection(生成反思)。关键:反思必须是具体的教训("搜索词太宽泛"),不是空泛检讨("我应该更仔细")。
  • 第三遍(复现意图):最小复现 = ReAct loop + 一个失败检测 + 一个反思生成 + 反思注入重试。L04 会手写。消融关键:把反思换成「随机文本」,成功率立刻回落——起作用的是反思内容,不是「多了一轮」这个动作本身

💡 三遍读法的本质:不是读三遍同样的内容,是三遍不同的目的。第一遍筛、第二遍懂、第三遍复现。读完拿不出复现计划的,等于没读第三遍。


2. 拆源码的方法:以 LangGraph Checkpoint 为例

前沿不仅是论文,还有快速演进的框架。拆源码的能力 = 理解「别人怎么解决的」并迁移到自己系统。我们拆一个你正在用但从没看进去的东西:LangGraph 的 Checkpointer

为什么拆 Checkpointer

我们的 research-assistant 正在用 AsyncSqliteSaver(见 persist.py)。任务书有个灵魂论断:「现有 checkpointer 只是对话状态持久化,不是记忆系统——这个区别正是 L01 的起点」。光看 API 文档理解不了这个论断,得看进去它到底存了什么。

拆解步骤

① 先看接口定义(它承诺什么)

LangGraph 的 BaseCheckpointSaver 定义了几个核心方法:

aget_tuple(config)         → 取一个 thread 的最新 checkpoint
alist(config)              → 列出某个 thread 的历史 checkpoint
aput(config, checkpoint)   → 存一个 checkpoint
aput_writes(config, writes)→ 存中间的写入记录

关键概念是 thread_id:一次「会话/线程」的标识。checkpoint 按 thread_id 隔离。

② 看存的数据结构(它实际存了什么)

一个 checkpoint 包含: - channel_values:图的 State 快照(你的 SystemState 序列化) - channel_versions:每个字段的版本号 - versions_seen:每个节点看过的版本(用于去重)

③ 得出结论:对话持久化 ≠ 记忆系统

┌─────────────── Checkpointer(现状)─────────────────┐
│  存的是:某个 thread 的【完整 State 快照】             │
│  能做:跨轮恢复对话(thread_id 相同 → 接着上次)      │
│  不能做:                                              │
│    🚫 检索 —— 没法按语义"查相关历史",只能按 thread 取 │
│    🚫 遗忘 —— 全量存,不会衰减,越堆越大              │
│    🚫 跨 thread 共享 —— A 会话的结论 B 会话用不上     │
│    🚫 提炼 —— 存的是原始 state,没有"经验沉淀"        │
└──────────────────────────────────────────────────────┘

┌─────────────── 记忆系统(L01 要建的)────────────────┐
│  存的是:提炼后的【经验/事实】,按语义可检索           │
│  能做:                                                │
│    ✅ 检索 —— 新任务前 recall 相关旧记忆              │
│    ✅ 遗忘 —— 时间衰减 + 频次保留                    │
│    ✅ 跨 thread —— 不同会话共享同一记忆库             │
│    ✅ 提炼 —— 不是录像,是"学到了什么"(L02)        │
└──────────────────────────────────────────────────────┘

🎯 这就是 L01 的起点:checkpoint 是「把对话状态原样存下来再原样恢复」,记忆是「把经验提炼存下来按需调回」。前者是日志,后者是大脑。research-assistant 现在只有日志,没有大脑。

拆源码的通用方法论

  1. 从你正在用的 API 往里钻:别从 __init__.py 开始读,从你调的那个方法开始追。
  2. 先看数据结构,再看逻辑dataclass/TypedDict 定义里藏着 80% 的设计意图。
  3. 问「它不能做什么」:API 文档告诉你能做什么,源码告诉你边界在哪。边界就是你要补的地方。

3. 流派对比:前沿领域的标准姿势

这门课每课都有「流派对比」小节——因为前沿没有标准答案,只有权衡。本课先示范一次:

问题:怎么学一个前沿新方向?

流派 做法 取舍
① 跟新闻 看 Twitter/公众号推文 ✅ 快;🚫 浅,二手转述,常带噱头,无法复现
② 只读论文 精读 arXiv ✅ 深,一手;🚫 慢,且论文常省工程细节
③ 只拆源码 直接读框架/仓库代码 ✅ 接地气,能跑;🚫 缺理论背景,知其然不知其所以然
④ 三件套(本课选它) 论文懂原理 + 源码看实现 + 基线验证收益 ✅ 全方位;🚫 贵(每个方向投入大),但前沿就该这么投入

选 ④ 的理由:前沿的每个结论都是实验性的,只读不验 = 盲信。任务书反复强调「诚实标注:本机跑出的数字要附复现命令,引用的结论要标来源,没跑过的明写未实测」——这个要求的前提就是「你要能跑」。


4. 硬任务定义:贯穿全程的试金石

前沿能力(记忆/反思/长任务)只有在足够难的任务上才显出差别。玩具任务("查一下天气")测不出失忆的痛——因为一次就答完了。本课程统一用这个任务作试金石:

「持续追踪研究」任务:让 research-assistant 跨多次运行持续追踪同一个技术主题(默认:「MCP 生态的演进」,可配置)。要求: - 第 2 次运行要记得第 1 次查过什么、结论是什么(记忆) - 发现新信息与旧结论冲突时要修正并说明为什么(反思) - 需要对比数据时能写代码算(Code Agent) - 每次运行产出「增量简报」而非从零重写(长任务)

为什么玩具任务测不出前沿能力

玩具任务("查 GLM-4 的参数")         硬任务("持续追踪 MCP 生态演进")
────────────────────────────         ─────────────────────────────────
一次搜索就答完                        需要跨多次运行累积
不需要记忆                            不记忆 = 每次从零重做,重复劳动
没有冲突                              新旧信息冲突时必须判断采信谁
不涉及计算                            对比发布节奏/版本数需要算
产出一次性                            产出增量,要标注"新增/修正/不变"

🎯 核心认知:评估一个机制有没有用,先要有一个「没有它就很痛」的任务。硬任务就是制造这个痛感——失忆的痛、不能反思的痛、口算出错痛、每次重来的痛。之后每个机制上线,痛感减轻多少就是它的价值。


5. 跑裸基线

现在跑一次硬任务的裸基线:用现状的 research-assistant(无记忆、无反思、无 code、无账本)连跑 2 次同一主题,看它有多失忆。

基线脚本设计

code.py 做三件事: 1. 用 mock 的假搜索结果(不烧 API、不依赖网络),模拟 research-assistant 跑「MCP 生态演进」这个主题两次 2. 把每次运行的轨迹(每步输入输出)存成 baseline_trace.jsonl 3. 打印对比报告:第 2 次有没有用到第 1 次的任何结果(剧透:没有,完全失忆)

预期结果(裸基线的病)

运行 #1:拆题 → 并行检索 → 汇总 → 写报告 → 审稿
         (从零开始,查了一堆,产了一份报告)

运行 #2:拆题 → 并行检索 → 汇总 → 写报告 → 审稿
         (完全从零开始,重复查了几乎一样的东西,
          完全不知道 #1 查过什么、结论是什么)

对比:两次轨迹高度重复,第 2 次零增量价值。

这个 baseline_trace.jsonl 会作为全程对照——L01 加记忆后看 recall 命中、L04 加反思后看冲突修正、L08 评估时拿它算基线指标。

⚠️ 诚实标注:本课的基线用 mock 搜索结果跑(不烧真实 API),目的是演示「失忆」这个结构性问题。真实 API 跑出的报告内容会不同,但「第 2 次完全失忆」这个结论不变——因为这是架构问题(无记忆系统),不是内容问题。


6. 落地清单

本课是方法课,无代码落地改动(不改 research-assistant 任何文件)。产出: - README.md(本文件):论文导读 + 源码拆解 + 方法论 - code.py:跑裸基线,产出 baseline_trace.jsonl - baseline_trace.jsonl:全程对照基线(L08 评估时复用) - exercise.md:练习

验收

# 1. 跑基线(生成轨迹文件)
cd frontier-lessons/00_method
python code.py

# 预期输出:
# - 打印两次运行的轨迹对比
# - 结论:第 2 次运行零增量、高度重复(失忆)
# - 生成 baseline_trace.jsonl

# 2. 验证轨迹文件存在且有内容
ls -la baseline_trace.jsonl
# 应看到非空文件

# 3. 验证能读出轨迹
python -c "import json; lines=open('baseline_trace.jsonl',encoding='utf-8').readlines(); print(f'{len(lines)} 条轨迹记录'); print(json.loads(lines[0])['run'])"

7. 本课在两条主线上的位置

  • 评估主线:本课立了基线——L08 的轨迹评估体系建立后,要回头量化 L01–L07 每个机制的收益,对照的就是本课存的 baseline_trace.jsonl。没有基线,"加了记忆更好"就是感觉,不是数据。
  • 上下文工程主线:本课拆 Checkpointer 时点明了「对话持久化 ≠ 记忆系统」——记忆的本质是「上下文的外置与按需调回」,这是整个上下文工程母题的第一块拼图(L01 正式动手)。

🎯 面试话术

「我读前沿论文用三遍法——一遍摘要图表筛、二遍方法懂、三遍带复现意图读,读完拿得出最小复现计划。拆源码我从正在用的 API 往里钻、先看数据结构、再问它不能做什么。而且我坚持先跑基线再谈改进——没有基线对照的『优化』都是玄学。比如我给研究助手加记忆前,先跑了一次失忆基线存档,之后每个机制的收益都拿它做对照。」