前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、token

Token 是 AI 模型工作方式的基本组成部分。在输入时,模型将单词转换为 token。在输出时,它们将 token 转换回单词。

  • 英文:平均 1 个单词 ≈ 1-2 个 Token
  • 中文:平均 1 个汉字 ≈ 1-2 个 Token
  • 代码:根据语言和复杂度,差异较大

1、token 拆分

就像我们阅读时会将句子拆分成词语来理解,AI 将文本拆分成 Token 来处理。一个 Token 可能是:

  • 一个完整的词(如 “AI”)
  • 一个词的一部分(如 “understand” 可能被拆成 “under” + “stand”)
  • 一个标点符号(如 “,”)
  • 甚至是一个空格

2、token 视角

1)它是 AI 的“消化单位” (技术视角)

AI 并不像人类一样直接阅读“单词”或“句子”。它只能处理数字序列。

  • 原文:“模型将单词转换为 token… 一个 token 大致相当于一个单词的 75%”
  • 通俗理解
    • 想象 AI 吃东西(文本),它不能一口吞下一整块牛排(一句话),它必须把肉切成小块(Token)才能消化。
    • 切分规则:在英语中,一个 Token 大约等于 4-5 个字母,或者 0.75 个单词。
      • 比如单词 “Spring” 可能是一个 Token。
      • 比如单词 “Artificial Intelligence” 可能会被切分成 “Art”, “ificial”, “ Int”, “elligence” 几个 Token。
    • 中文语境:虽然文档主要讲英语,但在中文里,通常一个汉字或者一个常用词(如“你好”)大约对应 1-2 个 Token。

2)它是 AI 的“计价货币” (商业视角)

  • 原文:“Tokens = 金钱… 输入和输出都计入总 token 数量”
  • 通俗理解
    • 使用 AI 模型(特别是商业模型如 GPT-4)就像打车或者用水用电
    • 计费方式:不是按“次”收费,而是按“量”收费。
    • 双向收费:你发给 AI 的内容(提示词)要算钱(输入 Token),AI 回复你的内容也要算钱(输出 Token)。
    • 省钱技巧:你的提示词越精简,或者你要求 AI 回答得越简短,花费的 Token 就越少,账单也就越便宜。

3)它是 AI 的“短期记忆” (能力视角)

  • 上下文窗口就是 AI“工作台大小”或者“瞬时记忆力”
  • 限制AI 一次只能“看”这么多 Token。如果你的书有 100 万字,但模型的窗口只有 8K Token(约 6000 个单词),AI 就无法一次性读完这本书。
  • 后果:超出限制的内容,AI 会直接“遗忘”或截断,根本处理不了。
  • 对比
    • GPT-3 (4K):像是一个只能记几句话的小纸条。
    • Claude (100K+):像是一本厚小说,可以一次性读完。

3、Token 优化实战技巧

1)提示词优化

  • 去除冗余词汇(”请你”、”帮我”、”详细”)
  • 使用简洁的结构化表达
  • 避免重复说明

2)上下文管理策略

a、策略 1:定期清理对话历史

  • 每 5-10 轮对话后,总结关键信息,开启新对话
  • 只保留必要的上下文

b、策略 2:使用系统提示词(System Prompt)

  • 将固定的角色设定、规则放在系统提示词中
  • 避免每次对话都重复说明

c、策略 3:分段处理长文本

❌ 一次性处理:
"分析这10篇文章..." [10,000 tokens]

✅ 分段处理:
1. "总结文章1的要点" [1,000 tokens]
2. "总结文章2的要点" [1,000 tokens]
...
10. "综合前9篇的总结,给出结论" [500 tokens]

d、策略 4:选择合适的模型

根据任务复杂度选择模型:

e、策略 5:缓存机制利用

将常用的系统提示词、文档等内容缓存起来,后续请求时不重复计费。

节省比例: 在 Agent 执行中,可减少 50-95% 的输入 Token 成本。

二、上下文工程

1、什么是”上下文工程”?

上下文工程解决的是“让模型在合适的时刻看到合适的信息

1)定义

a、工作定义

上下文工程,是一门为 LLM 构建和管理”信息环境”的工程方法,决定模型”看到什么、忽略什么、什么时候看到”,从而在有限的上下文窗口内稳定完成任务。

b、核心任务

你可以简单地把它理解成三件事:

  • 整理信息:对输入信息进行筛选和组织

  • 控制窗口:管理上下文窗口的大小和内容

  • 管理成本:优化 Token 使用,控制调用成本

c、典型应用场景

● 对话型Agent和客服机器人

● 代码/文档助手

● 多轮工具调用和长流程编排

2)为什么聊着聊着,它就忘事,还越来越贵?

  • 聊到一半,模型突然“忘记”之前说过的关键条件;
  • 长对话里,前后回答自相矛盾,很难保持同一套设定;
  • 对话轮次一多,账单像打车计价一样不断往上走。

面对这些挑战,单纯依靠“写好提示词”已经捉襟见肘。我们需要一套更系统的工程方法,来在有限的窗口和预算内,让模型始终获得最关键的信息。这正是上下文工程试图解决的问题。

a、问题现象

上下文难以保持一致:对话一长,前后语义容易脱节

关键事实容易丢失:早期给出的信息在后续轮次中难以被准确引用

调用成本持续上升:每一轮都要重新处理大量历史内容

b、可能的成因

视野仅限当前调用:模型只能依赖这一轮提供的上下文

信息缺乏结构化组织:重要信息与次要细节混在一起

历史内容反复计算:大量固定前缀在多轮对话中被一遍遍重新处理

c、带来的影响

回答质量不稳定:对话越长,模型越难保持一致性

成本难以预估:每轮上下文大小高度波动

难以工程化落地:缺乏明确的上下文管理策略

3)从”血泪教训”说起:Manus 团队踩过的坑

本章案例来自 Manus(一款通用 AI Agent)。 与普通对话不同,Manus 需要自主规划并调用工具完成长任务(涉及几十甚至上百轮交互)。

这带来了核心矛盾:

  • 如果不记:关键信息丢失,任务中断。
  • 全记:成本和延迟爆炸,甚至超出窗口限制。

Manus 团队经历过多次架构重构,才明白一个道理:上下文不能只靠“写”,而要靠“设计”。

a、四次重构教会我们什么?

核心领悟不是记得越多越好,而是记得越巧越好

阶段 遇到的问题 当时的想法 结果
第一次 AI 聊着聊着就忘事 “多写点提示词就好了” 越写越长,越写越贵
第二次 重要信息总被挤掉 “把重要的多复制几遍” 文本更长,成本更高
第三次 账单高得吓人 “能不能复用之前的计算?” 找到降低重复计算成本的方式
第四次 长文档处理不了 “能不能需要时再查?” 建立“图书馆+按需检索”的方案

b、AI 的”记性”到底像什么?

Manus 的经验小黑板要用得省,用得巧,别用来存百科全书

传统电脑内存 = 硬盘

  • 容量大:可以长期保存大量数据;
  • 价格低:存放一年成本较低;
  • 读写速度相对较慢,查找信息需要一定时间。

AI 的上下文 = 小黑板

  • 读写快:模型可以在一次调用中直接看到全部上下文;
  • 容量有限:写满后不得不擦除旧内容;
  • 每写入一个 token 都会带来额外计算与费用。

4)上下文工程的本质

从实践来看:不是记得越多越好,而是记得越有结构、越有选择性越好。

从成本视角看

  • 大部分浪费来自对固定前缀的重复计算,需要通过前缀稳定和缓存机制解决;
  • 重要信息被误删,往往源于“一视同仁”的滑动窗口,需要通过信息分级与钉住策略解决;
  • 面对超长文档和知识库时,仅依赖增大上下文窗口并不现实,必须结合检索与压缩机制。

2、第一步:认识成本 - 你的每一分钱花在哪?

1)为什么要先看成本?

让我们看看一次典型的 AI 对话,你的钱是怎么花的:

💰 成本构成(一次对话):
├─ 70% 重复看旧内容("刚才聊了什么?")
├─ 20% 处理新内容("现在说什么?")  
└─ 10% 生成回复("怎么回答?")

2)什么是 KV Cache?(前缀复用)

在讨论价格之前,我们得先搞懂一个核心技术概念:KV Cache(键值缓存)。 别被这个技术名词吓到,它其实就是 AI 的“短期记忆速查表”。

  • 没有 KV Cache:AI 每次都要像第一次看到这篇文章一样,从第一个字开始重新阅读、理解、计算。
  • 有了 KV Cache:AI 会把看过的部分(Pre-fill)计算结果存下来。下次如果开头的内容没变,它就直接调取记忆,不用重新算了。

这就好比:你去考场考试。

  • 情况 A:每次都要把整本教材从头读一遍,再开始答题。(慢、累、贵)
  • 情况 B:教材内容你已经背滚瓜烂熟了(Cache),坐下直接答题。(快、轻松、便宜)

在云厂商的计费表里,“背过的书”(Cache Hit通常比“新看的书”(Cache Miss便宜 90% 以上

3)避坑指南:别让时间戳毁了你的“缓存”

很多开发者习惯把“当前时间”写在 System Prompt 的第一句,觉得这样很严谨。 但这其实是上下文工程中最大的反模式之一。

想象一下:你背了一整本历史书(System Prompt),结果书的第一行写的是“现在的秒数”。 如果这行字每秒都在变,那你上一秒背的所有内容,下一秒就全废了——你得从头再背一遍。

这就是前缀复用(KV Cache的死穴:只要开头变了,后面全都要重算。

a、错误示范:把动态信息放前面

System: 现在是 2024-01-01 12:00:01。你是助手...
(一分钟后)
System: 现在是 2024-01-01 12:01:01。你是助手...

后果:虽然只变了几个字,但因为在开头,导致后续 99% 的固定内容无法复用缓存,每次请求都像第一次一样慢且贵。

b、正确姿势:动静分离

System: 你是助手... (这里放几千字的固定规则、知识库)
User: (在这里通过工具调用或用户消息传入当前时间)

好处:前面的几千字规则永远不变,AI 只需要“背”一次。后续请求直接调用记忆,速度极快。

3、第二步:滑动窗口 - 当”记性”变成”成本”

随着对话越来越长,最先遇到的问题就是:窗口满了怎么办?

1)为什么“先进先出”会出问题?

最简单的记忆管理是滑动窗口(Sliding Window)新的进来,旧的出去。 这听起来很公平,但在实际任务中却是个灾难。

场景重现

对话记录:
[1] 用户:我是张三,负责支付系统  
[2] 用户:项目用 Go 语言开发
[3] 用户:数据库是 PostgreSQL
...
[20] 用户:帮我写个接口

结果:当聊到第 20 句时,第 1 句“我是张三”已经被挤出了窗口。AI 彻底忘了你是谁,也不知道你在负责什么系统。

问题本质:这种策略把重要信息(身份、技术栈)和废话(“好的”、“收到”)同等对待,一起被踢了出去。

2)”中间失忆症” - 为什么 AI 总看不到关键信息?

除了“忘得快”,AI 还有一个怪癖:它也会“看漏”。 研究发现:AI 对开头和结尾最敏感,中间最容易被忽略。这就是著名的 Lost in the Middle(中间迷失)现象。

U 型记忆曲线

位置:开头 → 中间 → 结尾
记忆: 高  →  低  →  高

a、应对策略

  • 排序优先:把核心任务描述或最高相关文档放在开头,总结性提醒放在结尾。
    • 例如,要求总结报告时,开头写明“请总结以下内容”,结尾再追加“现在请给出你的总结”。
  • 结构重组:需要整合多篇文档时,将最相关的两篇分别置于上下文最前与最后,次相关按降序填充中间,人为制造“头尾重要、中间次要”的排列。
  • 提示锚点:在文本中段刻意插入强化标记(如 ⚠️ 重要提醒),或重复核心指令(例如“再次强调,回答必须为 JSON 格式”),重新捕获模型注意力。
  • 工程压缩:利用检索增强(RAG)只提取高相关片段,缩短上下文;或对超长文档分块摘要,用摘要替代原文,压缩中间区域。

b、举例说明

一个具体对照 有助于把策略落到实处。假设你要让模型基于三篇文档回答用户问题,文档 D1 是关键依据,D2 是补充背景,D3 只是边缘参考:

text
❌ 错误排列(重要信息沉没在中间):
[用户问题]
[文档 D2]
[文档 D1]   ← 最关键文档被夹在中间,极易被忽略
[文档 D3]
[指令:根据以上文档回答]

✅ 正确排列(头尾重点,中间填充):
[指令:请仔细阅读并严格依据以下文档回答]
[文档 D1]   ← 最高优先级放在开头
[文档 D2]
[用户问题]  ← 问题放在接近末尾,保证模型看到
[文档 D3]
[关键提示:回答必须引用 D1 中的具体段落]

4、第三步:选择性保留 - 如何”钉”住关键信息?

上下文窗口是流动的,新消息不断涌入,旧信息被挤向边缘。若对所有信息一视同仁,真正要紧的约束、事实很快就会随波逐流,我们需要一套分层与钉住机制,让关键内容像钉子一样牢牢固定在模型的可见区域内。

1)等级划分

不再平等对待每条信息,而是根据重要程度决定它们的去留:

核心思想用 25% 的成本增加,换取 90% 的关键信息保留

等级 信息类型 待遇 成本影响
VIP 系统设定、用户身份 永远保留 +15% 成本
重要 当前任务目标 任务期内保留 +10% 成本
一般 普通对话历史 最近 5 轮保留 基准成本
可弃 可检索的知识 用时再查 -60% 成本

2)三个信息层次

任何一条信息进入上下文前,先问一句:“它属于哪一层?” 然后按照该层的策略去放置和保护,而不是无差别地追加到对话历史。

层次 典型内容 生存周期 钉住方式
固定层 角色人设、核心格式约束、安全策略、领域知识库 整个会话(甚至跨会话) 固化在 System Prompt,结合 KV Cache 永远复用
会话层 当前任务目标、关键实体(订单号、用户等级)、重要中间结论 当前任务/多轮窗口内 每次请求末尾回填,或置于前缀固定区末端
临时层 当轮用户输入、工具返回结果、检索到的候选段落 本轮或接下来几轮 按“首尾优先”插入,过期可丢弃

3) 钉住(Pinning)的实现思路

  • 前缀固定区:把会话层的关键事实(如 重要约束:用户等级VIP,免除运费)放在 System Prompt之后、对话历史之前,确保每次请求都出现在模型视野的开头。只要前缀不变,KV Cache 就能持续复用。

  • 特殊标记强化:用 <critical>...</critical>⚠️必守规则 等醒目符号包裹关键约束,防止模型在长上下文中滑向遗忘。这些标记还可以作为后续自动检测“是否遵守”的锚点。

  • 末尾回填:对于本次请求最需要“最后一瞥”的事实(如刚刚查到的账户余额、上一轮提取的订单号),直接在用户消息或最后一条 assistant 消息之后追加一个简短的 [当前关键事实:余额 230 元,订单状态:待支付]。这比让模型在长长的历史里自己翻找可靠得多。

4)主动回填:别等模型忘,要主动喂

异步 Agent 或多轮业务流程中,可以设计一个简单的 “fact retriever” 触发器。每当检测到:

  • 需要引用 5 轮之前的某个实体;
  • 用户切换子任务,但共享相同约束;
  • 上下文长度超过预设阈值;

就从外部存储中提取对应的“会话层事实单”,回填到当前请求的末尾。这样做不是多花钱,而是把原本可能浪费在重复推理和纠错上的成本,转移到精准的信息注入上。

5)冲突裁决

当新的指令与旧的事实冲突时(例如用户说“现在取消VIP资格”,但之前钉住了“用户是VIP”),分层本身就能提供裁决规则:临时层 > 会话层 > 固定层。新指令属于临时层,自动覆盖旧的会话层信息。可以在代码中通过简单的匹配逻辑,将旧事实移除或打上“已失效”标记。

5、第四步:RAG - 当”记性”需要”图书馆”

有时候,我们要处理的信息太多了(比如几百页的技术文档),黑板根本写不下。这时候就需要外挂大脑——RAG(检索增强生成)

1)为什么“小黑板”不够用?

Manus 面对百万字级的技术文档时,对比了两种做法:

  1. 全量写入:所有内容一次性塞进上下文。
    • 后果:黑板瞬间被占满,处理极慢,而且根据“中间迷失”理论,AI 根本记不住中间的内容。
    • 成本:约 $50/次,等待 15 秒。
  2. 按需检索(RAG):先去图书馆(数据库)查,只把相关的几段话抄到黑板上。
    • 后果:黑板很清爽,AI 聚焦于关键信息。
    • 成本:约 $0.5/次,等待 2 秒。

省了 99% 的钱,87% 的时间!

2)”查资料”的最佳实践

Manus 的经验总结:

  • 每本书撕成多大片? 500-1000 字效果最好。
  • 一次查几本书? 3-5 本,多了反而干扰。
  • 多相关的书才查? 相似度 > 0.7,避免“硬凑”不相关的内容。

6、第五步:压缩 - 如何让”小黑板”写得更密?

如果信息都很重要,实在删不掉,又不想查资料怎么办? 那就只能把字写小点——这就是上下文压缩

1)什么时候需要”缩写”?

  • 检索回来的资料太厚(>2000 字)。
  • 对话历史太啰嗦(占了 >80% 黑板空间)。
  • 需要快速回答,不想让 AI 读长篇大论。

2)”缩写”的三种境界

压缩方式 压缩率 保留什么 适用场景 省钱效果
总结式 70% 主要意思 快速了解 省 30%
要点式 50% 关键要点 结构化输出 省 50%
表格式 30% 核心数据 程序处理 省 70%

7、系统整合:打造 AI 的“记忆宫殿”

  • KV Cache:帮我们省钱
  • 滑动窗口:帮我们腾位置
  • 分级保留:帮我们留重点
  • RAG:帮我们开外挂

1)像盖房子一样组装上下文

不要把上下文看作一堆乱糟糟的文字,而要把它看作一座分层的建筑。每一层都有它独特的功能和“居住规则”。

image-20260526213424520

2)为什么这样设计最强?

地基(System Prompt)—— 解决“贵”的问题

  • 矛盾:系统设定(你是谁、规则是什么)最长,每次都要发。
  • 解法:把它放在最底层,利用 KV Cache 技术,只要不改动,AI 就能“背诵全文”。后续几百轮对话,这部分的计算成本几乎为 0

支柱(Task Context)—— 解决“忘”的问题

  • 矛盾:对话一长,AI 容易忘了最初的任务目标(比如“写一个贪吃蛇游戏”)。
  • 解法:利用分级保留策略,把任务目标“钉”在第二层。不管聊了多少轮,这层永远不删,确保 AI 不忘初心。

顶层(Chat & RAG)—— 解决“乱”的问题

  • 矛盾:又有新对话,又有查到的资料,混在一起容易晕。
  • 解法
    • 客厅(对话):用滑动窗口管理,只留最近 5-10 句热乎的。
    • 图书馆(RAG:资料用完即走,不占地方。

3)实战模板:直接抄作业

image-20260526213707245

8、拿来即用的实战设计

1)场景 1:全栈工程师 Agent(长程记忆型)

核心挑战:任务周期长,容易忘了最初的需求和项目背景。 解决策略:System 层(身份)+ Task 层(钉死目标)+ Chat 层(滑动窗口)。

1. 系统提示词 (Layer 1 & 2)

# Layer 1: 身份设定 (System Prompt) - 永远不变,利用 KV Cache
你是一名资深的全栈工程师,精通 Python 和 Vue3。
代码风格:
- 变量命名严格遵守 PEP8
- 关键逻辑必须包含注释
- 优先使用项目已有的工具函数

# Layer 2: 任务锁定 (Task Context) - 任务期间不许删
当前任务:重构支付模块 (payment_module)
核心约束:
1. 必须兼容旧版 API 接口 v1.0
2. 数据库迁移脚本必须是幂等的
3. 截止时间:本周五

2. 上下文组装逻辑 (Pseudo-Code)

def build_engineer_context(user_input, chat_history, task_info):
    context = []
    
    # 1. 地基层身份设定 (利用 KV Cache 缓存)
    # 这部分内容几百轮对话都不变计算成本几乎为 0
    context.append(SYSTEM_PROMPT)
    
    # 2. 支柱层任务锁定 (Pinned)
    # 无论对话多长这部分永远插入在 System 之后
    context.append(f"当前任务:{task_info}")
    
    # 3. 检索层代码片段 (RAG)
    # 根据用户的问题去代码库里找相关的代码
    relevant_code = search_codebase(user_input)
    if relevant_code:
        context.append(f"参考代码:\n{relevant_code}")
    
    # 4. 交互层对话历史 (Sliding Window)
    # 只取最近 10 避免撑爆上下文
    recent_chat = chat_history[-10:] 
    context.extend(recent_chat)
    
    # 5. 最新输入
    context.append(user_input)
    
    return context

2)场景 2:智能客服 Agent(精准问答型)

核心挑战:成本敏感,且绝对不能胡说八道。 解决策略:System 层(强约束)+ RAG 层(动态注入)。

1. 系统提示词 (Layer 1)

# Layer 1: 身份设定 (System Prompt)
你是一名专业的电商客服专员。
回复原则:
1. 语气温柔、专业、简洁
2. **绝对禁止**编造事实,只根据[参考资料]回答
3. 如果资料里没有答案,请直接回答“非常抱歉,这个问题我需要转接人工客服”

2. 上下文组装逻辑 (Pseudo-Code)

def build_support_context(user_input):
    context = []
    
    # 1. 地基层:身份设定
    context.append(SYSTEM_PROMPT)
    
    # 2. 图书馆层:动态检索 (RAG)
    # 只有客服场景,RAG 才是主角,放在中间位置
    docs = vector_db.search(user_input, top_k=3)
    
    context.append("【参考资料开始】")
    for doc in docs:
        context.append(doc.content)
    context.append("【参考资料结束】")
    
    # 3. 交互层:极短的历史
    # 客服通常不需要太久远的记忆,保留最近 3 轮即可
    context.extend(get_recent_chat(limit=3))
    
    context.append(user_input)
    
    return context

ContactAuthor