跳到主要内容

第 6 课 · 历史会越堆越长:摆在哪、砍哪些

读这一课前你需要会什么:读过第 1、3、4 课。 你需要知道:它脑子里什么都不存、所以每轮要把过去整个重发一遍(第 1、3 课), 以及那个循环会转很多圈(第 4 课)。 出现的每一个新词都会当场用大白话讲清。讲不清楚的地方就是我的问题,请直接标出来。

这一课结束时你会

  1. 说得出为什么「摆在哪」比「写什么」更值钱——而且知道那个差距有多大;
  2. 说得出为什么改一个字会让账单翻倍;
  3. 说得出历史堆不下时该按什么顺序砍,以及哪一种砍法是错的。

1. 先看第 4 课那个循环转久了会怎样

第 4 课那个例子只转了三圈。把问题换成「帮我比一遍这 20 个城市的天气」呢?

第 1 圈:发出去 ~200 个 token
第 2 圈:发出去 ~400 个 ← 上一圈的调用和结果都要跟着发
第 3 圈:发出去 ~600 个
……
第 20 圈:发出去 ~15000 个

每一圈发出去的东西都包含前面所有圈。 这是第 1 课那条「它脑子里什么都不存」的账单版本。

两个后果同时发生:

后果表现
越来越贵、越来越慢第 20 圈发出去的东西是第 1 圈的 75 倍
迟早装不下它一次能看的量是有上限的

这一课讲怎么对付这两件事。而且这两件事的解法方向相反—— 一个要「别改」,一个要「多砍」。


2. 顶层全景:两件事,不是一件

很多人把这一课的内容笼统叫「上下文管理」,其实是两件不同的事:

┌─ 摆在哪 ──────────────────────────────────┐
│ 同样这些内容,按什么顺序排 │
│ 管的是:它听不听话 + 账单 │
│ 规矩:稳定的排前面,变的排后面,前面别动 │
└───────────────────────────────────────────┘
┌─ 砍哪些 ──────────────────────────────────┐
│ 装不下的时候扔什么 │
│ 管的是:塞不塞得下 + 会不会失忆 │
│ 规矩:一条从不花钱到花钱的阶梯,先便宜后贵 │
└───────────────────────────────────────────┘

图说:这两件事经常打架——砍东西会动到前面,而动到前面就毁了账单。
§4.6 讲这个冲突怎么解。

先给一个词,后面全靠它:

上下文窗口 = 它一次最多能看多少个 token。

超过这个量,请求直接被拒。但没超也不等于没事——这一点 §4.4 会讲。


3. 主走查:那 20 个城市,每一层在哪里介入

盯住那个 20 城市的例子,看一段文字从 200 涨到 15000 的路上,各层怎么管它。 下面的数字是我为了讲清楚编的量级,不是实测值。

第 1 圈:200 个 token,一切正常

┌─ 稳定的部分 ────────────────┐
│ 系统提示 ~80 │ ← 每一圈都一模一样
│ 工具定义 ~60 │ ← 每一圈都一模一样
└─────────────────────────────┘
┌─ 变的部分 ──────────────────┐
│ 用户那句话 ~30 │
└─────────────────────────────┘

这时候要做的唯一一件事:把稳定的排前面。 为什么,§4.3 讲。

第 8 圈:约 3000 个 token,第一层开始工作

这时候历史里已经有 7 组「调用 + 结果」。 假设其中一个城市的天气接口返回了一大段原始数据:

工具:call_007 → {…这一条就有 4000 个 token…}

第一层介入:单条结果太大,落盘,只留一小段预览 + 一句「想看全的去这儿取」。

这一层的做法,有一份资料的说法最好记(依据:本库摘录 · dexter):

把窗口当内存,把一个只能往后追加的暂存文件当磁盘。 内存必须精简、有界;但所有工具结果的完整原文都先落磁盘,一份不丢。

第 14 圈:约 8000 个 token,第二层介入

这时候没有哪一条特别大,但加起来多了。第二层是「不花模型钱」的那些:

① 把 10 圈之前那些工具结果换成一句「已清除」的占位话
② 保留最近 4 条不动

这一层的关键是它不调模型,所以不花钱、不花时间。

第 18 圈:约 13000 个 token,第三层介入

到这里前两层不够用了,才轮到花钱的那一层:调一个便宜的模型, 把旧历史摘成一段结构化的摘要。

第 20 圈:逼近上限,最后一层

假设它的窗口是 16000。这时候剩给我们的空间不多了,而且还得留给「最后这次回答」。

这一层的做法有两种,我们选后者:

做法结果
硬砍最旧的几轮信息真丢了
改写最后一条,逼它现在就用手头的信息交卷答案不完整但完整成句,而且基于全部证据

停一下:刚才那四层的顺序

花不花模型钱有没有损
① 单条结果落盘不花无损(原文在磁盘上)
② 旧结果换占位话不花半损(能从磁盘找回)
③ 摘要(用便宜模型)有损
④ 逼它交卷不花不损历史,但任务提前结束

这个顺序不是我排的,是四份资料撞出来的同一个形状,§4.5 讲。


4. 拆开看:六件事

4.1 摆在哪:同一句话换个位置,遵从率能差三倍

先看证据,再讲原理。

有一份资料记了一次实验:同一条「如果发现需要更多信息,鼓励你继续调用工具」的指令——

放哪儿结果
系统提示里讲工具的那一节所有模型都照做
挪到提示开头,哪怕只隔一段话经常被忽略

遵从率从九成掉到三成(依据:本库摘录 · onyx)。

这个数字要带一个限定:它出自那个项目的工程笔记,不是源码里的事实。 拆解文档专门标注了这一点,我们引用时保留这个限定。

另一份资料做了一组更系统的对照(依据:本库摘录 · shen-ru-li-jie-ai-agent):

只改什么结果
语气与风格(专业中立 / 夸张自信 / 轻松加表情)影响相对有限
打乱信息组织(内容全保留,只去掉标题层次,把有序流程拆成无序规则)成功率下降超过三成
移除工具说明文字(保留函数名和参数)调用错误率增加四成五

为什么打乱组织这么致命? 那份资料给的解释很具体: 规则以无序方式呈现时,它难以识别其中的优先级和依赖—— 比如「先验证身份再处理退款」这条被拆散后,它有时就跳过验证直接退款。

原理:两个效应叠出一个凹陷区

为什么位置有这么大影响? 有一份资料给了机制(依据:本库摘录 · prompt-engineering-for-llms):

效应一:越靠近这段文字的末尾,影响越大
效应二:开头和末尾都好回忆,塞在中间的容易被略过

两个叠加 → 开头 [强] ── 前中段 [弱] ── 末尾 [强]

那份资料管这块叫「凹陷区」

图说:所有模型都有这个凹陷区,深浅和位置因模型而异。
关键内容放在凹陷区之外,可有可无的背景才放中间。

那份资料明说没有完美解法,只给了两条对策: 把关键的、高质量的内容放在凹陷区之外;以及过滤内容,让整段尽量短。

第二条把这一课的两半连起来了:砍东西不只是为了塞得下,也是为了别把好东西埋进凹陷区。

三条能直接照做的

做法出处
三明治:开头和结尾各说一遍你要它做什么;结尾那次是把注意力从铺垫拉回问题上(依据:本库摘录 · prompt-engineering-for-llms)
最后必须硬转弯:从「说明问题」转到「解决问题」,否则它会继续往下编更多背景而不作答(依据:本库摘录 · prompt-engineering-for-llms)
按插槽分类,不要凭感觉插(依据:本库摘录 · lobehub)

最后那条的插槽表值得抄下来:

塞在哪后果
系统消息全局约束,但改一个字就让整段前面失效
第一条用户消息之前内容稳定的东西(知识、记忆)放这儿,前面可复用
最后一条用户消息之后反映当前状态的(进度、页面内容),必须最新
每条用户消息上逐条绑定的东西

还有一条打破直觉的:人设不一定该写进系统提示。 有一份实现把自定义提示做成了一条用户消息放在最后一句提问之前, 理由是塞进系统提示时遵从很差,而且当它和系统提示矛盾时会拖垮整体表现 (依据:本库摘录 · onyx)。

4.2 那个翻倍的账单:前缀缓存是怎么回事

先看故事(依据:本库摘录 · shen-ru-li-jie-ai-agent):

某团队的客服 agent 每天处理十万次对话。工程师为了让它「知道」当前时间, 在系统提示里加了一行实时时间戳。

第二天:所有对话的首个词延迟从 0.5 秒涨到 3 到 5 秒,月度推理账单几乎翻倍。

代码没问题,模型也没换。

先给这两个词:

前缀缓存 = 厂商把你上次发过的那段文字的中间计算结果存了下来, 这次只要开头那部分一模一样,就直接拿来用,不重算。

稳定前缀 = 那段每次都一模一样、能命中缓存的开头。

这件事我们实测过,而且数字比想象中夸张。

跑一整组题(11 道,每道都带同样的系统提示和 5 个工具说明),统计输入 token:

token
总输入24772
其中命中缓存的22656
真正重新算的2116

91.5% 的输入是从缓存里拿的(依据:本库实验 · 001-agent-loop/baseline-anthropic-2)。

为什么这么高:那 11 道题的开头完全一样——同一段系统提示、同一份工具清单。 只有最后那句问题不同。

现在把那一行时间戳加进系统提示,想一下会发生什么:每道题的开头都不一样了, 那 22656 个 token 全部要重算。

为什么加一行时间戳就毁了它? 台阶走一遍:

  1. 缓存是**按「逐字节相同的开头」**匹配的;
  2. 系统提示是整段文字里最靠前、最长的一块;
  3. 时间戳每秒都不一样 → 系统提示每次都不一样;
  4. 开头就对不上 → 后面全部作废 → 每次都从头重算;
  5. 重算的部分照样算钱、照样花时间。

这条规律在这一行反复出现,四份资料各自撞上:

做法出处
请求硬切成两段:字节稳定的前缀 + 可随便改的尾巴(依据:本库摘录 · kun)
每轮都变的东西(时间、任务、剩余空间)追加在末尾,不改系统提示(依据:本库摘录 · agentscope)
三段切分:永不改动的前缀 + 只追加的历史 + 永不进请求的便签,命中约 98%(依据:本库摘录 · whale)
系统提示拼一次就冻住整场会话,连时间戳都只精确到天(依据:本库摘录 · hermes-agent)

最后那条最狠,而且它给的理由值得记: 分钟级精度会让每一条重建路径都拿到不同的字符串,缓存必然失效; 它真需要精确时间时可以调工具查。

可以定成一句规矩:凡是每轮都变的内容,只能追加在末尾,不能改前面。

还有一条容易忽略的:工具定义也在前缀里。 所以改一个工具的说明,同样会让缓存失效——这就是为什么工具清单不该频繁变动。

段落顺序该怎么排

有一份实现的顺序是写死的,而且理由就是缓存(依据:本库摘录 · aider):

系统提示 → 示例 → 只读文件 → 仓库地图 → 历史 → 会话文件 → 本轮 → 提醒
└────────── 越靠前越稳定,越该被缓存 ──────────┘ └─ 每轮在变 ─┘

另一份的顺序是七段,而且「提醒」永远是最后一条(依据:本库摘录 · onyx)。

两份的形状一样:稳定的在前,变的在后,提醒压轴。

4.3 分歧:冻住,还是每轮重建

上一节说「前面别动」。但有一份实现每一轮都把系统提示从磁盘重读重建。

一边另一边
拼一次冻住整场会话,连时间戳都降到天(依据:本库摘录 · hermes-agent)每一轮从磁盘重读重建——它改了自己的设定,下一句就生效(依据:本库摘录 · cowagent)
省钱、省延迟状态立刻可见
会话中途学到的东西这一场用不上前缀每轮都变,缓存全废

判据是:你更在乎「它立刻看到最新状态」,还是「账单」。

前一派还有一个折中值得学:记忆要立刻落盘,提示要一动不动—— 所以文件立刻写,而喂进提示的那份快照下次会话才换(依据:本库摘录 · hermes-agent)。

我们的原型选「冻住」这一侧。 便宜、简单; 等真出现「必须立刻看到」的状态时,再照 §4.1 那张插槽表把它单独追加到末尾。

4.4 塞不下不是唯一的失败:塞太满也会变笨

这一节纠正一个直觉。

很多人以为「上下文够用」= 「没超上限」。不对。

有一份资料把失败分成两种(依据:本库摘录 · dexter):

失败表现
塞不下直接报错,这一步作废
塞太满没报错,但它注意力被稀释,在一堆旧数据里找不到重点

第二种更危险,因为它不会报错。 你只会觉得「今天它好像笨了点」。

这一条和 §4.1 的凹陷区是同一件事的两种说法: 东西堆得越多,关键内容掉进凹陷区的概率越大。

4.5 砍哪些:一条从不花钱到花钱的阶梯

这是这一课最该抄的结构,因为五份出身完全不同的资料给出了同一个形状。

出处它的阶梯
(依据:本库摘录 · dexter)单条结果治理 → 微压缩(不花模型钱) → 全量摘要 → 硬截断
(依据:本库摘录 · hermes-agent)工具自己先截 → 单条落盘 → 整轮预算 → 工具按需披露 → 发送前预检 → 压缩
(依据:本库摘录 · browseros)剥掉二进制 → 剪旧调用 → 压工具输出 → 最后才调模型摘要
(依据:本库摘录 · opencode)把「总结」和「裁剪」拆成两件事,裁剪有明确的预算常量
(依据:本库摘录 · codex)撑爆时不报错退出,而是就地压缩后继续

共同形状一句话:

压缩不是一个动作,是一条按代价排序的阶梯。能用不花钱的办法解决,就别调模型。

第二行那个「工具自己先截」值得单独看:最便宜的那道防线不在循环里,在工具内部。 一个工具吐出五万行日志之前,它自己就该先截断。

几条具体的:

做法出处
单条太大 → 落盘 + 留预览;一轮里的总量超预算 → 大的先落盘(依据:本库摘录 · dexter)
单条太大的那一条,拼上一句「剩下的在这个文件里,需要就去取」(依据:本库摘录 · agentscope)
超阈值不砍历史,改写最后一条逼它交卷;阈值要给交卷本身留预算(依据:本库摘录 · tongyi-deepresearch)
超窗前主动退一步收尾,别等报错(依据:本库摘录 · mirothinker)

「一轮里的总量」这个维度很多实现没有:五个工具各返回一份不大不小的结果, 单看都没超,加起来就爆了。

压缩时有一条硬约束:调用和结果不能拆散

第 3 课那条配对不变量,在压缩这里会再撞一次。

有一份实现的做法是:切压缩边界时要反复推移,直到没有「有结果但没有对应调用」的孤儿。 为什么要反复而不是修一次:推移边界本身会制造新的孤儿 (依据:本库摘录 · agentscope)。

另一份是异步跑摘要,所以还得加一致性校验:必须正好找到配对的两条才替换, 否则只告警不动——避免把对话搞成半残(依据:本库摘录 · goose)。

4.6 取件号:砍掉但不丢

先给这个词:

取件号 = 大块结果不进那段文字,只留一句「它存在哪儿」,它想要就去取。

这是「砍」和「别丢」之间的解法,四份资料都在用:

做法出处
大块或敏感结果留在框架里,只把一句「存哪了」喂给它(依据:本库摘录 · griptape)
有损压缩配一张带指纹的取货单,它想要就把原文换回来(依据:本库摘录 · headroom)
超大结果落盘换成一个指针(依据:本库摘录 · qwen-code)
不改原始历史,只做投影——窗口那侧四道防线,存盘那侧另治(依据:本库摘录 · deepagents)

最后那条引出一个更根本的分法,值得单独讲。

「历史里有」不等于「它看得到」

有一份实现给每条消息加了两个独立的开关:对用户可见、对模型可见 (依据:本库摘录 · goose)。

场景怎么设
压缩后的原始历史用户可见、模型不可见——你翻得到原文,它只看摘要
压缩摘要模型可见、用户不可见——它靠摘要续上,界面不被噪声打扰
命令的回执用户可见、模型不可见

那份资料的总结句:「历史里有」不等于「它看得到」。

几家用不同办法做到了同一件事:

  • 只留一条只能追加的日志当唯一事实,喂给模型的消息是从它算出来的(依据:本库摘录 · deepseek-harness);
  • 发给模型的是历史的一份副本,在最后一刻过一条「修复 + 压缩」流水线; 存盘的真实历史一字不动——那份资料的原则是对模型宽容,对存盘严格(依据:本库摘录 · nanobot)。

4.7 一个反面教材:直接删旧消息

这是这一课唯一一条「别这么做」。

直觉是:装不下了,把最旧的几条删掉。 有一份资料把这个判成了架构级的错误, 而且给了成本数字(依据:本库摘录 · headroom):

旧消息躺在厂商缓存里,读它只要 0.1 倍的钱

│ 你删掉中间一条

它后面所有内容的缓存全部作废,按 1.25 倍重写

图说:删一条省下的地方,和它引发的重算比起来微不足道。
那份实现因此只允许改「最新那条用户消息」这个窄窗口。

把这条和 §4.2 连起来:删中间的消息,等于把「稳定前缀」从中间剪断了。 代价和改系统提示是同一类。

正确的做法是上面那些:落盘留取件号、换占位话、摘要、或者干脆逼它交卷—— 这些都不动前面已经定型的部分。

4.8 工具太多也是一种「太长」

这一课到此讲的都是历史。但那段文字里还有一块会膨胀:工具清单。

挂五十个工具,光工具说明就能吃掉小模型一半的窗口。 解法叫按需披露:

系统提示里只留工具的名字和一句简述,完整说明等它开口要了再追加。

做法出处
折叠成三把元工具(搜工具 / 看工具 / 调工具),让它「先搜再调」(依据:本库摘录 · cherry-studio)
注册表懒加载,按需把说明塞给它(依据:本库摘录 · qwen-code)
上千个外部工具靠一个「按需检索」的开关,不一次性塞进去(依据:本库摘录 · whale)
三层加载:所有能力只常驻一行名字加描述,选中才加载正文,正文点名才加载资源(依据:本库摘录 · agent-skills-spec)

这一族最要紧的一条注意事项,来自第一行那份资料:折叠本身要先算划算。

除了「工具说明超过窗口一成」这个阈值,它还有两道闸:

说的是
可折叠的工具至少要有五个池子太小,「先搜再调」不比直接列出来划算
省下的量要超过三把元工具本身的开销否则折叠是净亏

这条要抄的不是那两个数,是那个思路: 任何「为了省资源而加的机制」本身也要花资源,要先算净收益再上。 压缩、折叠、摘要,三样都有这个陷阱。

还有一条留给谁的判断很关键:需要审批的工具永不被折叠。 理由不难想:它的完整说明必须在模型眼前,否则它不知道自己在申请什么。

顺带一条,同族的(依据:本库摘录 · agent-skills-spec): 「防压缩」被单列成一条规矩,因为指令被压没了不会报错,只会悄悄变笨。


5. 各家的分歧:一处,而且它是这门课最后一个要你拍板的

那段文字到底该不该有「唯一真相」

三种架构,差别在「哪一份是真的」:

架构哪一份是真的出处
就一份那个消息列表本身。改它就是改历史第 4 课那段代码
两份:真相 + 视图存盘那份是真的,发给模型的是投影出来的(依据:本库摘录 · deepagents)
一条日志 + 算出来的视图只有那条只能追加的日志是真的(依据:本库摘录 · deepseek-harness)

代价对照:

好处代价
就一份简单到不用想压缩就是毁掉原文,而且没法回头
两份压缩不丢东西,界面能看全要维护两套
日志能重放、能审计、能从任意点重建最重

我们的原型选第一种。 但要知道第二种存在—— 因为「压缩之后原文还在不在」这件事,决定了你能不能事后查清它当时到底看到了什么。

判断(无锚): 这是六个决定里第二难改的一个(最难改的是第 4 课那个分层)。 从「一份」改成「两份」要动所有写历史的地方。 但第一版真的用不上——我们的对话短到根本不会触发压缩。 如果错,会错在: 如果第一版就打算做「事后复盘它为什么答错」这件事, 那从第一天就该留原文,补记比重建便宜得多。


6. 动手:给第 5 课那段代码装上两层

这一课不做完整的压缩阶梯——我们的对话短到用不上第三、四层。 只装最便宜的那两层,而且它们都不花模型钱。

第一层:单条结果太大就落盘,只留预览(§3 第 8 圈、§4.6)

import { writeFileSync, mkdirSync } from "node:fs"
mkdirSync(".scratch", { recursive: true })

const MAX_RESULT_CHARS = 2000 // 单条结果的上限
let offloadSeq = 0

function offloadIfTooBig(result) {
const text = JSON.stringify(result)
if (text.length <= MAX_RESULT_CHARS) return result

const file = `.scratch/result-${++offloadSeq}.json`
writeFileSync(file, text) // ① 完整原文落盘,一份不丢
return {
preview: text.slice(0, 500), // ② 只留一小段预览
truncated: true,
hint: `内容太长,已省略。完整结果在 ${file},需要细节就用 read_file 工具去取。`,
} // ③ 取件号:告诉它去哪儿拿(§4.6)
}

用的时候包一层就行:

messages.push({
role: "tool",
tool_call_id: call.id,
content: JSON.stringify(offloadIfTooBig(result)),
})

第二层:每轮发送前先看看有多长(§4.4)

// 粗估:按字节数除以 4。对中文会高估,但它是保守的——宁可早报警(§4.4)
const estimate = (msgs) =>
Math.ceil(Buffer.byteLength(msgs.map((m) => JSON.stringify(m)).join(""), "utf8") / 4)

const WINDOW = 16_000
const RESERVE = 2_000 // ← 给「最后这次回答」留的预算(§4.5)

// 放在循环顶部,每圈开头
const used = estimate(messages)
if (used > WINDOW - RESERVE) {
// 不砍历史,改写最后一条逼它交卷(§4.5)
messages.push({
role: "user",
content: "上下文快满了。不要再调工具,请用现在已有的信息直接给出最终答案。",
})
const choice = await runOneTurn(messages)
console.log(`\n【最终答案(被迫提前)】${choice.message.content}`)
stopReason = `context_budget_forced_answer(${used}/${WINDOW})`
break
}

注意 RESERVE 那一行。 阈值定在 14000 而不是 16000, 因为「逼它交卷」这个动作本身也要占地方——不留就会在触发的那一刻超窗。

三个值得你亲手试的改动

#改什么你会看到它验证的是
1RESERVE 改成 0触发交卷的那一次请求直接超窗被拒§4.5——阈值必须给收尾动作留预算
2让某个工具返回一大段文字(比如重复一万个字)历史里只留下预览和一句「完整结果在 …」,而那个文件真的在§4.6——落盘留取件号,砍掉但不丢
3在系统提示里加一行 当前时间:${new Date()}每次请求都比上次慢一点(如果你用的服务有前缀缓存)§4.2——那个翻倍账单的故事

第 3 条你多半看不出明显差别,因为我们的对话太短。 但把它记住:真实产品里,这一行代码就是那个翻倍的账单。


7. 可带走的

  1. 「上下文管理」是两件事:摆在哪(管听不听话和账单)、砍哪些(管塞不塞得下)。 这两件事经常打架,因为砍东西会动到前面。
  2. 同一句指令换个位置,遵从率能从九成掉到三成(工程笔记,不是源码事实); 只打乱信息组织、内容一字不改,成功率下降超过三成。
  3. 原理是两个效应叠出一个凹陷区:越靠末尾影响越大,而中间最容易被略过。 关键内容放两头,可有可无的放中间。
  4. 前缀缓存按「逐字节相同的开头」匹配。 在系统提示里加一行时间戳, 月账单几乎翻倍。
  5. 一条定则:凡是每轮都变的内容,只能追加在末尾,不能改前面。 有实现狠到连时间戳都只精确到天——它真要精确时间可以调工具查。
  6. 工具定义也在前缀里。 改一个工具说明,同样毁缓存。
  7. 塞不下会报错,塞太满不会报错——但它会变笨。 第二种更危险。
  8. 压缩不是一个动作,是一条按代价排序的阶梯: 工具自己先截 → 单条落盘 → 整轮预算 → 不花钱的替换 → 摘要 → 逼它交卷。 能用不花钱的办法解决就别调模型。
  9. 任何「为了省资源而加的机制」本身也要花资源,先算净收益再上。
  10. 「历史里有」不等于「它看得到」。 两个独立的可见开关能解决大半问题。
  11. 直接删旧消息是错的——省下的地方,和它引发的缓存重算比起来微不足道。
  12. 压缩时调用和结果不能拆散,而且推移边界本身会制造新的孤儿,要反复推到稳定。

8. 六课到这里讲完了

回头看一遍这六课在讲什么:

1 它只会接着往下写字 → 所以需要外面有个程序
2 它凭什么听得懂人话 → 所以我们能靠改 prompt 指挥它
3 一轮:它说要调工具时发生了什么 → 所以我们能给它接上手脚
4 很多轮:循环,和它什么时候停 → 所以它能自己干几步活
5 它会跑偏:错误该不该让它看见 → 所以它跑几十步也不会失控
6 历史会越堆越长:摆在哪、砍哪些 → 所以它跑得起、也跑得久

图说:每一课的结论,都是下一课的前提。
六课合起来就是一句话:agent = 一个循环 + 一段每轮重拼的文字。

你现在应该能回答开课时那三个问题了:

问题答案在哪一课
大模型凭什么能对话?第 1、2 课
凭什么能做成 AI Agent?第 2 课的指令遵循 + 第 3 课的工具 + 第 4 课的循环
我们要造的到底是什么?第 4 课那段代码,加上第 5、6 课的护栏

9. 我需要你的反馈

这六课是一整组,请当成一组来标。

标什么我会怎么改
哪一课整体读不下去那一课重写
哪一段读不下去那一段拆成更小的台阶
哪个词没解释清楚换一种解释法,或者干脆不用那个词
哪里嫌啰嗦删掉
哪个「后面会讲」没兑现补上,或者把那句许诺删掉

读懂之后请在每一课的开头把 humanStatus 改成 understood 卡住了就改成 stuck 并写一句卡在哪——那一段就是下一版必须重写的地方。

接下来该做的事:把第 4 到第 6 课那些代码真的跑起来。 那需要一个模型服务的账号和密钥,下一步我们一起配。