agency 是训练出来的,还是编排出来的?
本课一问:第 2 课说,agent 就是让模型决定下一步。可模型凭什么会「决定下一步」?这个能力是训练进模型里的,还是 harness 的代码编排出来的?如果是前者,workflow 那些预先写好的路还有什么意义?
这一课先不碰:怎么训练出这种能力(LLM 课 C12 第 8 课已经讲过);agent 循环的具体写法(A1)。
从已有出发
回到贯穿任务里那一步:T2 的 agent 轨在第 5 轮重跑测试,看见 datetime.date(2024, 2, 5) != datetime.date(2024, 3, 5),第 6 轮就去改 MONTHS.index 那一行。这一步里有两样东西:模型会读 traceback、会写出一个格式正确的 edit 调用;harness 给了它工具、替它跑了测试、把输出送回来。问题是哪一样算「agency」。
先自己设计:只听一边
最省事的读法是只听一边。本课的教学蓝本 learn-claude-code 在 README 的开头就把话说满了——照它说,agency 全在模型里,那 harness 的编排就无关紧要,换个更强的模型就是了:
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
接着它把矛头对准了另一类东西:
编排改变了结果:那条规则让模型在修完第一处之后接着重跑测试,于是看见了第二处(v1 最常见的失败,是修完第一处就宣布「测试通过」)。反过来也成立:模型没学会写工具调用,harness 写得再好也转不起来——Hermes Agent 的源码就专门警告,Nous 自家的 Hermes 3 / 4 模型不是 agentic 的(下文)。所以「agency 从哪来」和「系统怎么搭」是两个问题,要分开回答。下面把另一种立场和这个仓库自己后来的转向摆在一起。
立场一:agency 来自训练(learn-claude-code README)
上面那两段 README 就是立场一的全部依据:历史类比与论证。它没有否认 harness(第 11 行后半句:产品要模型和 harness 两样),它否认的是「把 LLM 调用用写死的路径串起来」能造出 agency(第 37–41 行)。
立场二:先找最简单的方案(Anthropic)
Anthropic 的《Building effective agents》站在另一边。它把 workflow(预先写好的代码路径)和 agent(模型动态决定流程)都归为 agentic systems,把五种 workflow 模式当作正经的设计模式逐一讲清;并且建议先找the simplest solution possible,只在需要时加复杂度,这might mean not building agentic systems at all——可能根本不建 agentic 系统 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条官方立场陈述(调研满票核实原文)。它是基于与客户合作的经验,不是实验。 出处Anthropic · Building effective agents(2024-12-19) ↗需联网 。
| learn-claude-code README(pin 0dcafa2) | Anthropic《Building effective agents》 | |
|---|---|---|
| 核心主张 | agency 来自训练;产品 = 模型 + harness | 先找最简单的方案;workflow 与 agent 各有适用处 |
| 对 workflow | 把 LLM 调用串成规则流水线「不是 agent」 | 五种 workflow 是一等公民;很多场景单次调用就够 |
| 依据 | 历史类比(DQN、OpenAI Five、AlphaStar……)与论证 | 与几十个团队合作的经验 |
| 有没有实验 | 没有 | 没有 |
| 适合拿来 | 提醒你:别指望靠堆规则让一个不会用工具的模型变聪明 | 提醒你:别把能写死的路交给模型 |
| 调研的定性 | 有力但极端的社区观点,与官方分类有真实张力 | 分野满票;「先直接调 API」2-1 非满票 |
两边其实在回答不同的问题:README 说的是「能力从哪来」,Anthropic 说的是「系统怎么搭」。张力出在 README 第 37–41 行:它把预先写好路径的编排整体判了出局,而 Anthropic 恰恰把这些当作首选。
转折:同一个仓库,后来加了 s16
pin 0dcafa2 里,learn-claude-code 的 17 章中多了一章 s16 Workflow Runtime,它在 README 章节表里的口号是:
它的做法是把一段保存好的编排脚本,做成 agent 工具池里的一个工具:
所以在同一个仓库里,两种说法并存了:README 开头说编排出不了 agency;s16 说编排形状固定就写进代码,再让 agent 在需要时调用它。放回第 2 课的光谱,s16 是个混合体——外层是 agent(模型决定调不调这个工具),工具里面是 workflow(脚本决定编排),而编排里的每一次 agent() 调用又是一次模型调用。这不是自相矛盾,是立场松动了:它没有收回「agency 来自训练」,但承认了有些路就该写死 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条源码直证:README.md:11、:41、:239 与 s16_workflow_runtime/code.py 均在 pin 0dcafa2 逐行核对。「立场松动」是本课的解读,仓库作者没有这样表述。 出处learn-claude-code README(pin 0dcafa2) ↗需联网 。
第三种声音:harness 里的假设会过时
Anthropic 在 2026-04-08 的工程文章《Scaling Managed Agents》里给了一个中间的说法:harness 里写进了「模型自己做不到什么」的假设,而这些假设要经常拿出来重新审视,因为模型在变。它举的例子是:为某一版模型在 harness 里加了上下文重置(那版模型临近上下文上限时会草草收尾),换到下一版模型上,这个行为消失了,重置成了累赘 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条官方自报的工程经验,一个例子,没有公开数据。 出处Anthropic · Scaling Managed Agents(2026-04-08) ↗需联网 。
这句话同时站在两边:训练让模型会的东西越来越多(learn-claude-code 的方向),所以 harness 里替模型兜底的编排要跟着删减;但在某个具体的模型上,哪些路该写死、哪些该交出去,仍是 harness 的设计(Anthropic 原文的方向)。
极小真数字:一条规则,十种配置
训练这一侧:Hermes Agent(一个通用 agent,岔路 B2 会细讲)的源码里专门有一条警告——Nous Research 自家的 Hermes 3、Hermes 4 模型不是 agentic 的,缺少 agent 工作流需要的工具调用能力,不适合配这个 harness 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条源码直证:hermes-agent@56dc01d9 hermes_cli/model_switch.py:206-211。这是作者的判断,文件里没有附测试数据。 出处Hermes · model_switch.py(pin 56dc01d9) ↗需联网 。harness 写得再好,模型没学会写工具调用,循环就转不起来。
编排这一侧:本课项目用同一个模型(Qwen3-8B)、同一套 10 种运行配置,把 harness 从 v1 换成 v2。v2 改了两处,一是在 system prompt 末尾加了这条完成规则:
Completion rule: never say the tests pass unless you have just seen them pass in a bash tool
result in this conversation. After every edit you MUST run the tests again before you finish.
One failing assertion can hide another one behind it.二是服务端丢弃调用时提醒模型重发(v1 直接当成模型停了)。逐个配置对照(验收由 harness 跑测试判定,不看模型自述;最后一列是除这两处之外、两次运行配置里还有的差别):
| 配置(A1 录制) | harness v1 | harness v2 | 其他差别 |
|---|---|---|---|
unlimited-s1 | ✗ · 5 轮 · no_tool_calls | ✗ · 8 轮 · no_tool_calls | — |
unlimited-s2 | ✗ · 5 轮 · no_tool_calls | ✓ · 6 轮 · no_tool_calls | — |
unlimited-s3 | ✗ · 5 轮 · no_tool_calls | ✓ · 7 轮 · no_tool_calls | — |
cap20-s1 | ✗ · 5 轮 · no_tool_calls | ✓ · 11 轮 · no_tool_calls | — |
cap4-s1 | ✗ · 4 轮 · max_rounds | ✗ · 4 轮 · max_rounds | — |
firstmatch-s1 | ✗ · 6 轮 · no_tool_calls | ✗ · 7 轮 · no_tool_calls | — |
truncate-s1 | ✗ · 7 轮 · no_tool_calls | ✗ · 8 轮 · no_tool_calls | budget_tokens、snip、summarize、collapse |
layered-s1 | ✗ · 5 轮 · no_tool_calls | ✓ · 21 轮 · no_tool_calls | budget_tokens、snip、summarize、collapse |
promptjson-s1 | ✓ · 10 轮 · length | ✓ · 9 轮 · no_tool_calls | — |
nothink-s1 | ✗ · 5 轮 · no_tool_calls | ✗ · 9 轮 · dropped_tool_call | — |
贯穿任务的验收通过数从 1 / 10(harness v1)变成 5 / 10(harness v2)。由没过变成通过的 4 对里,3 对(unlimited-s2、unlimited-s3、cap20-s1)的配置除了这两处一模一样,而重发开关在它们身上一次也没触发过——配置上真正起作用的差别只剩那条完成规则(每对只跑一次,结果里仍混着采样的随机性,见第 3 课的孪生运行) 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条项目实测:同一模型、同一任务、两组各 10 种配置、每种 1 次;逐对比较时,另外一对(layered)还调小了上下文预算。说明 harness 里的一句话能改变结果,不估计提升幅度。 出处本课项目 A1 的 20 次运行(A1 实验课) ↗ 。模型没变,变的只是 harness 告诉它的规矩。
那是一个有力但极端的社区立场,没有实验支撑;它和 Anthropic 把 workflow 当一等公民的分类有真实的张力,调研要求两者并陈、不当结论 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条深度调研 §14:3-0 满票核实的是「该仓库确实这样主张、且是社区立场」,不是主张本身成立。 出处learn-claude-code README(pin 0dcafa2) ↗需联网 。而且同一个仓库自己加了 s16,把固定的编排写进了代码。反过来也不对:Anthropic 说「先找最简单的方案」,不等于「别用 agent」——它同一篇文章里也写了 agent 适合什么。
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 分清「模型会不会决定下一步」与「系统让它在哪儿决定」,免得拿一个问题的答案去否定另一个 |
| ② 为什么可能有效? | 训练决定模型能不能可靠地写出调用、读懂反馈;编排决定这些能力被用在哪几条边上 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条本课的归纳;两方原文都是立场陈述。 出处learn-claude-code README:11(另一方见 Anthropic 原文) ↗需联网 |
| ③ 实验上呢? | 没有直接比较两种立场的实验;本课项目只提供旁证:同一模型只换 harness(主要是一条完成规则),通过数 1 → 5(10 种配置) 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条项目实测,样本很小。 出处本课项目 A1 的 20 次运行(A1 实验课) ↗ |
演进地图:你在这里
- 解决了只调一次模型,每一步都写在代码里:可预期、好测、便宜。卡在T2 workflow 轨 2 / 4 通过。parse_date 只改了报错指到的那一行,重跑才露出第二处(
datetime.date(2024, 2, 5) != datetime.date(2024, 3, 5));slugify 的回复只有函数片段,兜底规则把 130 字符的片段当整份文件写回(原文件 365 字符),丢了import re。 - 第一代 加步骤、加分支:五种 workflow 模式 prompt chaining · routing · parallelization · orchestrator-workers · evaluator-optimizer解决了每一类失败补一条预先写好的路径:测试没过就带着新报错再来一次(评估者是测试的退出码)、回复格式不对就拒绝写回。卡在分支要在设计时写出来,可真实路径是在运行时长出来的:T2 agent 轨 4 个任务走出 4 条不同的工具序列;同一配置重跑 4 次 parse_date(seed 1 / 2 / 3 / 1),走出 4 条。
- 解决了边在运行时长出来:T2 agent 轨 3 / 4 通过,包括 workflow 没修好的 parse_date 与 slugify。卡在代价:workflow 已经能解决的任务上 token word_freq ×5.3、leap_year ×4.5,其中 word_freq 的 agent 反而没修好;同配置、同 seed 重跑,2 / 4 个任务在中途分叉。
- 解决了录制前写下三条标准并逐个预测,录制后对照:预测对 3 / 4。卡在预测错的 slugify 不是任务本身需要 agent,而是 workflow 自己的写回规则出了错(回复没有
FILE:标记时的兜底)。每条轨道每个任务只跑 1 次:只能当例子,不能当比率。 - 解决了编排形状固定的部分(并行审查、逐条验证、断点续跑)写进脚本;模型只决定「要不要调这个 workflow、传什么参数」。卡在同一个仓库里两种说法并存:README
:11与:41说 agency 来自训练、不是编排;:239说编排形状固定就写进代码。界线画在哪,没有实验回答。 - 解决了同一个循环,识别出代码工作区后注入编码说明(约 577 token,Qwen3 tokenizer 计)与工作区快照;focus 模式才会收窄工具集与技能索引。卡在判定靠文件标记:本课任务仓单独拷出来(README.md、dateparse.py、test_dateparse.py,没有 .git)在默认 auto 下被判成 general;放在项目目录里原地跑,却因为往上 3 层有个
requirements.txt被判成 coding。姿态在会话开始解析一次,中途不变。
一句话
回主线
把决定权交给模型,代价是什么? → 第 3 课
你可能会问
- 「既然 README 这么说,为什么这门课还要讲 workflow?」 因为两件事都要会:A0 讲什么时候不必交出决定权,A1–A9 讲交出去之后 harness 要做的所有事。learn-claude-code 自己的 s16 也在做前一件事。
- 「s16 的 workflow 在光谱上算哪一档?」 外层看,模型决定要不要调 Workflow、传什么参数,是 ★★☆ Tool call 的形态;里面的编排是第 0 档的脚本;脚本里的每次
agent()调用各自是一次模型调用。三层叠在一起,所以说它是混合体。 - 「模型越来越强,workflow 会不会消失?」 能写死的路写死,永远更便宜、更可预期(第 3 课的账)。会变的是「哪些路写不死」:模型越强,交给它的边越多,harness 里替它兜底的规则越少——这正是 Managed Agents 那篇文章的意思。