1 · 零基础前置知识

这一章不讲 Hermes,也不讲 Claude Code。它只做一件事:把后面十二章需要用到的所有概念,从零建立起来

如果你已经知道什么是大语言模型、什么是 token、什么是提示词缓存,可以快速扫过。但如果你对其中任何一个概念不确定,请完整读完这一章 —— 后面所有的设计分析都建立在这些概念之上,跳过会导致后面每一章都似懂非懂。

1.1 大语言模型是什么

「大语言模型」的英文是 Large Language Model,业内常缩写成 LLM。为了不制造理解障碍,这份文档后面一律写「大语言模型」全称,不用缩写。

抛开所有数学细节,一个大语言模型在使用时只做一件事:

你给它一段文字,它预测这段文字之后最可能出现的下一个字。然后把这个字接在后面,再预测下一个。如此反复,直到它认为该停了。

就这么简单。它不是数据库,不会「查询」;它不是搜索引擎,不会「检索」。它是一个极其庞大的、通过阅读海量文本训练出来的「文字续写器」。

这个简单的机制之所以能产生看起来像思考的行为,是因为训练它的文本里包含了大量的推理过程、对话记录、代码和解释。当它续写「问题:1+1 等于几?答案:」的时候,训练数据告诉它接下来最可能出现的是「2」。

最关键的一条性质:它完全没有记忆

这是整份文档最重要的前置认知,请务必理解清楚:

大语言模型在两次调用之间不保留任何信息。它不记得你上一句说了什么,不记得五分钟前的对话,甚至不记得三秒钟前它自己刚说过的话。

每一次调用,对它来说都是人生中第一次也是唯一一次被使用。

可以用一个类比来理解这件事:

想象有一位学识极其渊博的专家,但他患有一种特殊的失忆症 —— 每次谈话结束后,他会彻底忘记刚刚发生的一切

你想和他进行一场持续两小时的深入讨论,唯一的办法是:每说一句新话之前,先把前面已经发生的全部对话,从头到尾重新念给他听一遍。念完之后,再补上你的新问题。他听完全部内容,回答一句。然后他又忘了。你下一句话之前,得把包括他刚才那句回答在内的全部内容,再念一遍。

这个「每次都要重念全部历史」的机制,是理解后面所有设计的钥匙。它直接导致了三个后果,我们接下来逐个解释:

1.2 token 是什么

「token」这个词很难翻译,业内通常直接用英文,或者译作「词元」。这份文档保留英文 token,因为它已经是事实上的标准术语。

token 是大语言模型处理文字的最小单位,也是计费的单位。

模型不是按「字」处理文字的,也不是按「单词」。它用一套专门的切分规则,把文字切成一个个 token。大致的规律是:

文字大约几个 token说明
英文单词 hello1 个常见的短单词通常是 1 个 token
英文单词 unbelievable3~4 个长单词会被切成 un + believ + able 这样的片段
中文「你好」2~3 个中文通常一个汉字就占 1 个甚至更多 token,所以中文比英文贵
一段 100 字的中文约 150~200 个粗略估算可以按「汉字数 × 1.5~2」
一段 100 词的英文约 130 个粗略估算可以按「英文单词数 × 1.3」

为什么要关心 token?因为使用大语言模型的费用是按 token 计算的,而且分成两种价格:

一个反直觉但至关重要的结论

虽然输出 token 的单价更贵,但在智能体系统里,总花销的大头几乎总是输入 token

原因就是 1.1 讲的「每次都要重念全部历史」。假设一场对话进行了 50 轮,那么第 50 轮要重念前 49 轮的全部内容。整场对话下来,第 1 轮的内容被重复付费了 50 次,第 2 轮被付费了 49 次……而每一轮的输出只付费一次。

所以后面你会看到,两套系统都花了极大的工程力气去压缩「要重念的内容」。这不是吝啬,这是主要成本项。

1.3 上下文与上下文窗口是什么

「上下文」(context)指的就是你这一次念给模型听的全部内容。包括:系统设定、历史对话、工具执行的结果、以及你的新问题。它是一个纯文本序列。

「上下文窗口」(context window)指的是模型一次最多能接受多少 token。这是一个硬性上限,由模型本身决定,用户无法调整。

常见的上下文窗口大小:

可以把上下文窗口想象成一张固定大小的桌子。你要讨论的所有材料都必须摊在这张桌子上,模型才能看到。桌子摊满了,就再也放不下新东西 —— 这时候你只有两个选择:拿掉一些旧材料,或者把几份材料压缩成一份摘要

这个「桌子满了怎么办」的问题,就是本文档第 6 章的全部内容,也是智能体系统里最难、最能体现工程水平的一块。

超出上限会发生什么

会直接报错。这个错误在两套系统的代码里出现频率极高,它有一个专门的名字:

prompt_too_long(提示词过长),对应的网络错误代码是 413

后面章节会反复出现「413」这个数字,它指的就是这个错误:你念给模型的内容超过了它的上下文窗口,模型拒绝处理。

1.4 智能体与聊天机器人的区别

「智能体」的英文是 Agent,也常被译作「代理」。这份文档统一使用「智能体」,或者在指代具体产品时用英文 Agent(比如 Claude Code 里有一个工具就叫 AgentTool)。

聊天机器人和智能体的区别可以用一句话概括:

聊天机器人只会说话。智能体会动手做事。

更准确地说:

聊天机器人智能体
能做什么 你问一句,它答一句。答完这一轮就结束。 你给一个任务,它自己拆解成多个步骤,调用外部工具去执行,看到执行结果后决定下一步,反复多轮,直到任务完成。
一次请求
调用模型几次
1 次 几次到几百次。每执行完一批工具,就要再调一次模型问「接下来干什么」。
上下文如何变化 基本不变 自己不断膨胀。每次工具执行都往上下文里塞进几千甚至几万个 token 的执行结果。
失败模式 答错了。用户重问一遍就行。 删错了文件、执行了危险命令、陷入死循环烧掉几千次 API 调用、上下文爆掉之后完全失忆。
这张表解释了这份文档为什么存在

做一个聊天机器人,核心工作是写好提示词。
做一个智能体,核心工作是处理上面「上下文如何变化」和「失败模式」这两行

后面的第 4 章讲失败模式(错误恢复),第 6 章讲上下文膨胀,第 7 章讲危险操作。这三章合起来,就是「做过智能体」和「只用过智能体」的分界线。

1.5 工具调用是什么,它到底怎么工作

这一节讲清楚智能体最核心的机制。很多人对这里有误解,所以我们讲得细一点。

第一个要纠正的误解:模型不能执行任何操作

大语言模型只会输出文字。它不能读文件,不能运行命令,不能上网。它被关在一个只有文字进出的盒子里。

那智能体是怎么读文件、跑命令的?答案是:模型写一张「便条」,外面的程序照着便条去执行,然后把执行结果作为文字念给模型听。

继续用 1.1 的那位失忆专家做类比:

这位专家被关在一个房间里,只能通过一个小窗口和外界交流。他不能出来。

但他可以写便条:「请帮我打开 config.json 这个文件,把内容念给我听。

窗口外的助理拿到便条,去打开文件,把文件内容抄下来,从窗口递进去。专家读完,可能又写一张新便条:「请把第 12 行改成这样……

专家自己什么也没做。所有实际操作都是助理做的。专家只是在写便条和读回复。

在技术上,这个「便条」有一个标准格式,叫做 tool_use(工具使用)。助理递回去的执行结果,叫做 tool_result(工具结果)。这两个词在后面章节里会频繁出现。

完整流程逐帧拆解

假设用户说「把 config.json 里的端口号改成 8080」。完整发生的事情是:

【第 1 帧】程序把这些内容拼成一段文字,发给模型: ├─ 系统设定:"你是一个编程助手,你可以使用以下工具……" ├─ 工具清单:read_file(读文件)、write_file(写文件)、bash(跑命令)…… │ 每个工具都附带它需要什么参数的说明 └─ 用户消息:"把 config.json 里的端口号改成 8080" 【第 2 帧】模型返回一张便条(tool_use): { 工具名: "read_file", 参数: { 路径: "config.json" } } 注意:模型自己没有读文件,它只是说"我想读这个文件" 【第 3 帧】程序(不是模型)真的去读了这个文件,拿到内容: { "host": "localhost", "port": 3000 } 【第 4 帧】程序把「全部历史 + 这次的执行结果」重新拼一遍,再发给模型: ├─ 系统设定(和第 1 帧一模一样,重发) ├─ 工具清单(和第 1 帧一模一样,重发) ├─ 用户消息(重发) ├─ 模型上一轮的便条(重发) └─ tool_result:'{ "host": "localhost", "port": 3000 }' ← 唯一的新内容 【第 5 帧】模型返回第二张便条: { 工具名: "write_file", 参数: { 路径: "config.json", 内容: '{ "host": "localhost", "port": 8080 }' } } 【第 6 帧】程序真的去写了文件,返回:"写入成功" 【第 7 帧】程序又把「全部历史 + 写入成功」重发给模型 【第 8 帧】模型这次不写便条了,直接返回一句人话: "已经把端口号改成 8080 了。" 没有便条 = 任务完成 = 循环结束
请注意第 4 帧和第 7 帧

每一轮都要把前面所有内容原封不动重发一遍。这就是 1.1 说的「每次都要重念全部历史」在实际系统里的样子。

这个例子只有 3 轮。真实的编程任务经常有 30 轮、100 轮。到第 100 轮时,你要重发前 99 轮的所有内容 —— 包括那 99 次工具执行的全部输出。如果其中有几次是「把整个文件读出来」,那就是几万个 token。

这就是为什么「上下文治理」是智能体系统里最重要的工程问题。

「没有便条就结束」是唯一的终止信号

请记住第 8 帧:模型这一轮没有写任何便条,只说了人话 —— 这就是任务完成的信号。

后面第 4 章你会看到,两套系统的主循环判断「要不要继续」的依据都是同一件事:这一轮的回复里有没有 tool_use。有就继续,没有就结束。

1.6 什么是流式输出

模型生成文字是一个字一个字往外吐的,不是憋足了一次性给你。这叫「流式输出」(streaming)。

你在使用各类 AI 聊天产品时看到文字一个个蹦出来,就是流式输出。这不是为了好看的动画效果,而是模型真实的工作方式 —— 它确实是一个 token 一个 token 生成的。

流式输出带来一个重要的优化机会,后面第 5 章会讲到:

如果模型这一轮要写三张便条,那么第一张便条写完的时候,第二张还没开始写

聪明的做法是:第一张便条一到手就立刻开始执行它,不用等三张全写完。这样工具执行的时间和模型生成的时间就重叠了。

Claude Code 有一个专门的组件干这件事,叫 StreamingToolExecutor(流式工具执行器)。

1.7 什么是 API

API 是 Application Programming Interface 的缩写,中文叫「应用程序接口」。这个缩写已经完全通用,后面直接用 API。

它的意思是:一个程序向另一个程序提供服务的约定好的方式。

在这份文档里,「调用 API」几乎总是指同一件事:你的程序通过网络,把上下文发送给 Anthropic(或 OpenAI 等)公司的服务器,服务器上的大语言模型处理后把结果通过网络返回给你。

几个后面会用到的相关说法:

1.8 提示词缓存 —— 全文最重要的技术概念

如果这一章你只能记住一个概念,请记住这个。Claude Code 里超过一半的「奇怪设计」都是为了保护提示词缓存。不理解这一节,后面第 5、6、8 章会有大量内容看起来莫名其妙。

它解决什么问题

回到 1.5 的第 4 帧和第 7 帧:每一轮都要重发全部历史。服务器每次都要把这些内容重新「读」一遍(技术上叫做处理 prompt,即计算注意力)。这个重复处理既慢又花钱。

供应商们注意到一件事:连续两次请求,开头的绝大部分内容是一模一样的。第 100 轮和第 99 轮的区别,只是末尾多了一轮对话。前面 99 轮完全相同。

于是有了「提示词缓存」(prompt cache):

服务器把上一次处理过的内容缓存起来。这一次请求进来时,从头开始逐字比对:只要开头这一段和缓存里的完全一致,就直接复用缓存的处理结果,跳过重新计算。

命中缓存的那部分 token,价格通常只有原价的 10%,而且不消耗处理时间。

还是用失忆专家的类比:

那位专家其实有一个笔记本,记着「上次你念到哪里」。

这次你开始念,他一边听一边对照笔记本。只要你念的和笔记本上记的一字不差,他就快速跳过(因为他已经理解过这部分了)。直到某个字对不上了 —— 从那个字开始,他必须重新认真听。

关键性质:它是「前缀匹配」,一字之差全盘失效

这是最容易被忽略、也是后面所有设计的根源:

缓存的比对是从最开头开始、逐字进行的。一旦某个位置对不上,从那个位置往后的全部内容都必须重新处理。

举例:你的上下文有 10 万个 token。你在第 100 个 token 的位置改了一个字 —— 哪怕只是把一个空格变成两个空格 —— 那么后面 99,900 个 token 全部要重新处理,缓存等于完全没用

这个性质导致了一系列在外行看来非常奇怪的工程决策,你在后面会遇到,现在先预告几个:

看起来很奇怪的做法真实原因在哪一章
给子智能体一堆它根本用不到的工具 工具清单是上下文开头的一部分。少给几个工具就改变了开头,缓存全废。宁可多给。 第 8 章
内建工具和外部工具分别排序后拼接,而不是混在一起统一排序 服务器在「最后一个内建工具」的位置放了缓存分界点。统一排序会让外部工具插进内建工具中间,把这个区间劈开,所有用户的缓存一起失效。 第 5 章
要删掉上下文里的旧内容,却一个字都不改本地数据,而是发一条特殊指令让服务器去删 改本地数据 = 改变了发出去的内容 = 缓存失效。省下的钱不如重建缓存的开销大。 第 6 章
要给日志补充一些字段,却只改一份复制品,绝不碰原件 原件是要发给 API 的。改一个字节,缓存就没了。 第 5 章

缓存有有效期,会「凉掉」

缓存不是永久的。常见的有效期是 5 分钟(也有 1 小时的付费选项)。超过有效期,缓存被清除,下次请求必须全部重新处理。

这引出了一个后面会看到的精妙设计:「缓存现在是热的还是凉的」应该成为决策的输入

同一个目标(清理旧内容),根据缓存冷热要走两条完全相反的路。绝大多数自己搭建智能体的团队完全没有「缓存冷热」这个概念,所以只有一套策略,在两种场景下各错一半。

1.9 还会遇到的几个词

这些词在后面章节里出现频率较高,先建立印象,不必现在完全掌握。第 13 章有完整术语表。

意思
系统提示词
system prompt
上下文最开头那一段,给模型设定身份和规则的文字。比如「你是一个编程助手,遵循以下规范……」。因为它在最开头,所以它是缓存最先比对的部分,绝对不能随意改动
轮次
turn
一次「调用模型 → 执行工具」的完整往复。1.5 的例子里有 3 轮。
压缩 / 摘要
compact
上下文快满时,让模型把前面一大段对话总结成一段短摘要,用摘要替换原文。这是有损的、不可逆的操作,所以是最后手段。
状态机
state machine
一种编程模式:把程序的运行状况归纳成有限的几个「状态」,并明确规定「在什么条件下从哪个状态跳到哪个状态」。第 4 章会详细讲。
幂等
idempotent
一个操作执行一次和执行多次的效果完全相同。在这份文档里主要用于「幂等锁」—— 一个标记,确保某个恢复动作在一轮里只做一次,防止无限循环。
沙箱
sandbox
一个被严格限制权限的隔离运行环境。程序在沙箱里跑,就算它想删除系统文件也删不掉,因为它根本没有那个权限。
正则表达式
regular expression
一种用特殊符号描述「文字模式」的写法。比如可以写一个模式来匹配「所有以 rm 开头、后面跟着 -rf 的命令」。第 7 章 Hermes 用了 59 条正则表达式来拦截危险命令。
抽象基类
Abstract Base Class,缩写 ABC
编程里的一种「插座标准」。它规定了「任何想接进来的东西必须提供哪几个功能」,但不规定这些功能怎么实现。这样第三方可以做出自己的实现插进来。Hermes 大量使用这个模式,这是它和 Claude Code 最大的架构差异。
中止信号
AbortController / abort signal
一个可以在程序各处传递的「取消开关」。用户按下 Ctrl+C 时,程序拉一下这个开关,所有正在进行的操作都能感知到并停下来。第 4 章会讲它的正确用法和一个致命陷阱。
这一章的核心,浓缩成五句话
  1. 大语言模型只会续写文字,而且完全没有记忆 —— 每次调用都要把全部历史重发一遍。
  2. 因此成本大头是输入 token,不是输出。压缩「要重发的内容」是核心工程问题。
  3. 模型自己不能执行任何操作,它只能写便条(tool_use)让外部程序去执行,然后读结果(tool_result)。
  4. 上下文窗口是硬性上限,撞上去就报 413 错误。「桌子满了怎么办」是第 6 章的全部内容。
  5. 提示词缓存是前缀匹配的,一字之差全盘失效。这一条解释了后面一半以上的「奇怪设计」。