跳到主要内容

动手学大语言模型 — 本课题摘录

读了哪几章: 「提示工程」与「高级文本生成技术与工具」两章。 读的是我们自己的中文拆解(书库里已完成的那份),不是原文。

这本书对本课题的作用和别的材料不同:它不讲怎么做产品,它讲这件事最底下那一层为什么会是这样。前面读的三十多家都默认了"模型是无状态的""历史要自己拼",这本书是唯一一份把这两句话当成需要解释的现象来讲的。

它对本课题回答了什么

决定一最底层的那条理由:模型是无状态的

它做了一个极短的演示:

你:「你好,我叫 Maarten。1 + 1 等于几?」
它:「你好 Maarten!1 + 1 等于 2。」
你:「我叫什么名字?」
它:「抱歉,作为一个语言模型,我无法知道个人信息……」

上一句话它刚说过你的名字,下一句就不认识了。

原因很干脆:这些模型是无状态的——它们没有任何关于之前对话的记忆。 (依据:书 · 动手学大语言模型(Hands-On Large Language Models) §高级文本生成技术与工具 —— 书用一个两轮演示说明模型是无状态的——上一句刚说出用户名字,下一句就答「无法知道个人信息」,因为每次调用都是独立的一次、不带上一次的任何痕迹)

本课题第一个决定("一轮的输入怎么拼")的全部必要性,就来自这一句话。 不是我们想拼,是不拼就没有。

讲义应该用这个演示开篇——它比任何抽象说明都直接。

决定一:外挂记忆的三种做法,是同一条权衡线上的三个点

做法怎么弄好处代价
全量贴回把完整对话历史原样贴回提示里实现最简单,窗口内零信息丢失开销一路涨,迟早撞上长度上限;历史一大反而难从中找信息
只留最近 k 轮丢掉更早的开销可控,最近 k 轮零丢失k 轮之前的全丢
摘要用另一个模型把历史压成一段保住全程,省词元每一轮多一次模型调用,细节要靠推断

书的总结句:这是速度、记忆和准确性之间的权衡。 (依据:书 · 动手学大语言模型(Hands-On Large Language Models) §高级文本生成技术与工具 —— 外挂记忆的三种做法是全量缓冲、只留最近 k 轮、摘要,书把它们总结成「速度、记忆和准确性之间的权衡」;并顺带建议摘要用的模型不必和主模型是同一个,可以用更小更快的)

前面读的所有压缩方案(goose 的三招、dexter 的四道防线、hermes 的六级、browseros 的分级降级)都可以还原成这三个点的组合。 本课题讲义讲"历史怎么压"时,应该先摆这三个点,再讲各家怎么把它们拼起来。

一条实用建议:摘要用的模型不必和主模型是同一个,可以用一个更小更快的。

这跟 aider 的"用更弱更便宜的模型写提交信息"、dexter 的"用快模型做全量压缩"是同一条。 三份材料撞在一起,说明"辅助动作用便宜模型"是成熟做法。

决定二最有价值的一条:约束采样是事前,不是事后

要让输出永远合规,书给了三种治法:

治法怎么做效果
给示例把想要的格式当成示范塞进提示有效,但是否遵守仍然取决于模型自身
约束采样在挑下一个词那一刻就把不合规的选项掐掉最狠,能保证
微调拿符合格式的数据去训模型最贵

思路的关键在这个对比:

常规做法:让它自由生成 → 事后检查 → 不合格就重来
问题:它总有可能生成不合格的东西,你只能反复重试
约束采样:在「从可能性清单里挑一个」这一步就动手
把不合规的选项直接从清单里划掉,它想跑偏也跑不出去

(依据:书 · 动手学大语言模型(Hands-On Large Language Models) §提示工程 —— 让输出合规的三种治法是给示例、约束采样、微调;约束采样是在挑下一个 token 那一刻就把不合规的选项从候选里掐掉,书强调它管的是「不许挑什么」而不是「一定挑什么」,且仍受温度与候选名单长度影响)

这条解释了本课题第二个决定里一个此前没被讲清的东西: 厂商的"原生工具调用"和"结构化输出"为什么比我们自己发明格式可靠。 不是因为他们的提示词写得好,是因为他们能在挑词那一层动手,而我们只能在文本层动手。

这也解释了 beeai 那条降级路径为什么成立:"厂商不支持强制调工具时,用结构化输出逼出一次合法调用"—— 因为结构化输出走的也是这条事前掐灭的路。

书还提醒了一句:约束采样仍然受采样设定的影响——它管的是"不许挑什么",不是"一定挑什么"。

这条限定很重要:约束保证了格式合法,保证不了内容正确。 和 dong-shou-zuo-ai-agent 那条"保证合法但不保证匹配特定架构"是同一件事。

决定二:工具存在的理由,以及 agent 的最小定义

它给的理由最朴素:大语言模型在处理数学问题时表现很差,经常在解决简单的数学任务时失败,但如果我们提供计算器,它们就能做得更多。

它给 agent 的定义:利用语言模型来决定应采取哪些行动以及以何种顺序执行的系统。

比"链"多两样东西:工具(用来完成它自身无法完成的事)、以及一种决定"用哪个工具、什么顺序"的办法。 (依据:书 · 动手学大语言模型(Hands-On Large Language Models) §高级文本生成技术与工具 —— 书给智能体的定义是「利用语言模型来决定应采取哪些行动以及以何种顺序执行的系统」,它比链多两样东西——工具、以及一种决定用哪个工具与什么顺序的办法)

"多两样东西"这个说法很好用:它把 agent 和普通的模型调用之间的差别压成了两条。 本课题的最小原型,就是要把这两条做出来。

循环还是那三步:想 → 做 → 看结果 → 回到想,直到它认为可以给最终答案为止。

一条藏在例子里的坑,拆解文档替书指出来了

书的例子:查一台笔记本的美元价格,再换算成欧元。系统只配了两个工具——网页搜索和计算器。

拆解文档指出:换算用的那个汇率没有出现在搜索结果里,也没有第二次搜索去取它,最可能是模型自己填进算式的。

换句话说:这条链上有一个数没有任何工具背书,而最终答案整个建立在它上面。 (依据:书 · 动手学大语言模型(Hands-On Large Language Models) §高级文本生成技术与工具 —— 书的 ReAct 例子里换算汇率 0.85 既没出现在第一轮搜索结果里也没有第二次搜索取它,最可能是模型自己填进算式的;这条链上有一个数没有任何工具背书而最终答案建立在它上面)

这是本课题"怎么知道它好不好"这一圈的一个具体病症,而且很隐蔽: 工具调用都成功了,结果也看起来合理,但中间有一个数是编的。

db-gpt 的"验证靠真执行"能抓住"跑不通"的错,抓不住这一类。 要抓住它,得追问"每个进入最终答案的数,是哪一步产生的"。

书自己点破的代价 —— 这句要原样进讲义

通过创建这种相对自主的行为,我们并未参与中间步骤。因此,没有人在流程中来判断输出或推理过程的质量。

书还给了两条补救方向:让它把找到价格的那个网址返回来,或者在每一步都问一下这一步的输出对不对。 (依据:书 · 动手学大语言模型(Hands-On Large Language Models) §高级文本生成技术与工具 —— 书在这一节末尾主动写下「没有人在流程中(human in the loop)来判断输出或推理过程的质量」,并给出两条补救——让模型返回信息来源的网址、或在每一步都问一下这一步的输出对不对)

拆解文档在这里加了一条我们该继承的判断:这一层真正缺的不是能力,是可观测性。 前面每一层你都能看到输入和输出、都能自己判断;到了这一层,中间发生了什么不翻日志就完全不知道。

这正好说明本课题划的第三圈("人怎么看见与插手")不是可选项。

书里还提到一个很实在的门槛:它全章用的那个小模型不足以运行这些示例,只好换成当时的商业模型。但它紧接着判断:这不意味着只有商业模型才行,随着领域发展小模型最终也会足以运行。

这条判断今天看是对的(deepanalyze 的 8B、agenticseek 的本地小模型都在跑),但它提醒了一件事:能不能跑 agent 循环是模型的一条能力门槛,不是所有模型都跨过了。

它没回答什么

  • 循环的护栏——没有轮数上限、没有打转检测、没有错误恢复。
  • 并发——它的例子一次只调一个工具。
  • 工具怎么描述——只说了"提供计算器",没讲工具说明该怎么写。
  • 状态怎么持久化——记忆三型讲的是"这一轮怎么拼",不是"关了程序还在"。

坑与代价

  • 书里那一节的具体代码今天不能照抄。 拆解文档明确标注:那套写法在书出版之前就被官方标注为弃用。 有价值的是概念(把模板和模型打包),不是那几行调用。
  • 它是教材,不是工程材料。 一切都停在"能跑通一个例子"的层面,长任务、错误恢复、成本封顶、并发全都不在。
  • "记忆三型"这个划分很干净,但它假设了历史是一条线。 真实产品里历史是有分支的(编辑过的消息拉出新分支),这时"只留最近 k 轮"要先回答"哪条线上的 k 轮"。

    判断(无锚): 对我们的最小原型,单线历史就够,分支是产品化之后的问题。 如果错,会错在: 如果第一版就要支持"回到某一步重来"(而这恰恰是调试原型最常用的动作),那分支从第一天就存在,用单线结构会很快改不动。