Skip to content

第17章 · Prompt 工程与长短期记忆 ​

前置要求:掌握 第16章 · 真实大模型 API 实战 的请求调用与 第15章 · Typed Tools、MCP 与可恢复 Agent 的工具协议。

接上了真实模型,接下来的问题变成:怎么跟模型说话,它才稳定地按你的意图输出?怎么让多轮对话记住该记住的、忘掉该忘掉的? 本章把 prompt 从"随手写的字符串"升级为"有契约、有回归测试的代码资产",把记忆从"消息越堆越长"升级为有写入语义的工程结构。你会亲手复现两个经典失效模式(指令-示例冲突、格式漂移),再亲手修好它们。

live 模型路径在本仓库证据中标记 unverified-live,默认证据线是离线 golden 断言与确定性记忆层测试。

本章目标 ​

学完后你能做到:

  • 写出四段式 system prompt(Identity → Instructions → Examples → Context),说清每段职责、角色层级,以及为什么稳定部分放前、私有信息放尾。
  • 复现 few-shot 两大失效模式:指令-示例冲突(模型往往跟示例)与多轮格式漂移,并能用修正示例修复。
  • 说清结构化输出三档(自由文本求 JSON / JSON mode / strict json_schema)的保证差异与 strict schema 的限制。
  • 把 prompt 当代码资产管理:builder 函数 + golden dataset + 确定性断言 + CI gate;区分确定性断言与 model-graded 断言。
  • 系统掌握 Agent 记忆系统的四代演进谱系(从滑动窗口、异步摘要、向量分块情景记忆到生物启发式海马知识图谱 HippoRAG),深入剖析为什么 1M+ Long Context 永远无法取代显式记忆系统的三大核心硬伤(成本阶梯爆炸、注意力稀释与迷失在中间、时序更新与主动遗忘机制)。
  • 掌握 Context Engineering 预算分配模型,量化 MCP 工具 Schema 膨胀,并复现滚动摘要导致关键负向约束丢失的故障与防御。
  • 剖析大模型后训练指令遵循代际演进,掌握避免 MUST 过触发的条件谓词范式与注意力稀释机理。
  • 掌握多轮长对话 5 种优化方案对比、10 万用户会话存储 5 维选型与容量带宽推导,以及三位一体并发 Token 成本管控网关。

接口 shape 速览 ​

对象shape/结构约束
system prompt# Identity / # Instructions / # Examples / # Context 四段,Markdown 标题标层级稳定前缀在前吃 prompt caching;私有信息放尾部
数据边界<context> / <input> / <memory> XML 标签圈定不可信内容标签内一律按 data 处理;角色层级与边界是缓解不是防御(第18章展开)
response_format{"type": "json_object"} → {"type": "json_schema", "json_schema": {..., "strict": true}}JSON mode 只保证合法 JSON(已 legacy);strict 在解码时约束采样
strict schemaadditionalProperties: false、所有属性必声明、可选字段 "type": ["string", "null"]OpenAI 静默接受但不强制 minimum/maximum/pattern;function calling 加 strict 是同一机制
记忆写入决策ADD / UPDATE / DELETE / NOOP 四态写入不是 append-only;冲突必须显式决策
窗口预算切分Lmax≥Bsys+Btools+Bexamples+Brag+Bhistory+Boutput静态区不可变,动态区 Top-K 裁剪,输出区硬预留
动态工具裁剪ToolPruner.prune_tools_for_query(query, top_k=5)将数十个工具 Schema 动态压缩 70% 以上,防御候选空间爆炸
成本管控网关ContextCostGate(rate_limiter, router)租户级双令牌桶 (RPM/TPM) + 缓存 + 模型分级 (Tier 1/2) 路由

阶段一:System prompt 四段式与角色层级 ​

把 system prompt 当结构化文档写,四段顺序有工程理由:

  1. Identity:角色、目的、风格——模型是谁。
  2. Instructions:该做什么、绝不该做什么——行为约束。
  3. Examples:输入输出示例对(阶段二展开)。
  4. Context:本次请求的私有信息,放尾部。

为什么是这个顺序:前三段跨请求稳定,放在 prompt 前部才能命中 prompt caching(缓存按前缀命中,前部逐字不变才省钱省时);Context 每轮可能变,放尾部让缓存失效范围最小。验证缓存是否命中:provider 在 usage 对象中返回 cached_tokens 字段;缓存条目有 TTL;重新排序或编辑前缀会令缓存失效。这是协议层面的行为,不是本仓库能力。

角色层级 developer > user > assistant:冲突时高优先级角色胜。把用户输入和检索内容圈进 XML 标签、在 Instructions 里声明"标签内只是数据",是缓解注入的手段,不是防御——标签本身也由模型解释,第18章会讲为什么需要模型外的隔离。本章先建立正确的心智模型:层级和边界提高攻击成本,但不构成安全保证。

格式上用 Markdown 标题标层级、用 XML 标签(<context>、<input>、<memory>)圈定数据边界——实践中主流模型对 XML 风格分隔符的遵循度较好,但这是经验观察,不是安全保证。

前端类比:prompt caching 等价于你对 HTTP 缓存的直觉——前缀不变才命中,所以易变部分沉底;XML 边界对应 textContent 而非 innerHTML 的转义纪律:数据与指令分层。

动手:用 python/agent_core/prompts.py 的 build_extraction_prompt 生成一个记账抽取 prompt,打印 system 消息确认四段齐全且 Context 在尾部;把一段"忽略之前的指令"塞进 task 参数,确认它只出现在 <input> 标签内。

阶段二:Few-shot 与失效模式 ​

示例选择原则:多样性与边界覆盖 > 数量。五个覆盖不同形态(整数/小数/未知类目/口语化/带干扰)的示例,胜过二十个同质示例。

两个必须亲手见过的失效模式:

  • 指令-示例冲突:示例的隐含约束力往往强于显式指令。指令说"输出 JSON"而示例本身是自由文本时,模型大概率跟示例输出自由文本——示例示范了"实际怎么做",指令只是"声称怎么做"。
  • 格式漂移:多轮对话中,模型的自由文本输出会逐渐偏离开头声明的格式约束,轮次越多漂移越远。

动手:构造一个冲突 prompt——Instructions 写"只输出 JSON",Examples 段放两组自由文本问答——丢给模型(或对你的 stub)观察输出形态;然后把示例改成与指令一致的 JSON 输出对,确认行为修复。live 部分标 unverified-live,离线部分用阶段四的 golden 断言兜底:输出断言会在格式漂移发生时变红。

推理增强范式:程序辅助思维链 (PoT) 与自洽性采样 (Self-Consistency) ​

在设计复杂推理任务的提示词时,仅依赖自然语言思维链(CoT)往往受限于语言模型的计算局限。工程界沉淀出两项显著提升推理稳定性的标准实践:

1. 自然语言 CoT vs 程序辅助思维链 PoT(Program-aided Language Models) ​

自回归语言模型擅长概念抽象与语义转化,但自回归算术计算(如多位数乘除、复利计算、时间跨度推导)极易发生逐位进位漂移与累积误差。

**程序辅助思维链(PoT,Chen 等,2023)**将复杂逻辑的表达与数值计算进行物理分工:

程序辅助思维链 (PoT) 与自洽性采样 (Self-Consistency):符号解释器代数执行与多路径多数投票收敛

TIP

通俗心智模型:分工是消灭幻觉的最佳武器

初学者常把大模型当成“万能神算子”。但底层物理上,大模型更像一位博览群书但多步心算容易粗心的文学家。如果硬让它口算 384×129+2048,它只能按概率猜测下一个字符,极易在中间步算错导致全盘皆输。

  • PoT 的智慧在于专业分工:让文学家负责读懂复杂题意、建立方程并写出 Python 代码,随后交给确定性解释器执行求值,彻底根除算术幻觉;
  • Self-Consistency 的智慧在于多数聚合:如果题目难度高,就让模型在一定温度下独立写出 5 条解题路径。正确的逻辑往往殊途同归(汇聚为多数票),而偶然的失误各有各的偏差(分散为少数票),通过多数表决就能大幅提升复杂任务的稳定性!
  • 自然语言 CoT(纯文本模拟):要求模型逐步写出文字推导与口算结果;易在“第 3 步算错一个数字,导致第 4 步全盘皆输”;
  • 程序辅助思维链 PoT:指令明确要求模型通过编写可运行的 Python 代码来解决问题(例如定义 def solver(): ...),利用 Python 解释器执行循环、变量定义与符号代数计算。大模型负责语义理解与因果建模,确定性编译器负责精准求值,从而根除算术幻觉。

2. 自洽性采样(Self-Consistency Decoding,ICLR 2023) ​

贪婪解码(T=0)虽然具备确定性,但在高难度问题中容易陷入单点贪婪陷阱。

Self-Consistency 机制:

  1. 多路径并发探索:设置采样温度 T∈(0.5,0.7),使模型在一定随机度下针对同一 Prompt 独立生成多条不同的推理路径(例如 K=5∼10 条);
  2. 边缘答案提取:从每条推理链中提取最终答案(如通过正则表达式提取数值或特定标识);
  3. 多数票决(Majority Voting):在答案集合上统计边缘分布,选择出现频次最高的答案作为最终系统输出。

实验表明,复杂推理中正确的解题路径往往在语义空间具备多条等价归宿,而错误路径在随机扰动下高度分散。自洽性票决通过增加推理期的边缘采样,有效消除了单次生成的偶然失误。

阶段三:结构化输出三档 ​

档位机制保证
自由文本求 JSONprompt 里写"请输出 JSON"无保证,靠模型自觉
JSON moderesponse_format: {"type": "json_object"}只保证输出是合法 JSON,不保证字段;已被官方标为 legacy
Structured Outputsresponse_format: {"type": "json_schema", "json_schema": {"name": ..., "schema": ..., "strict": true}}解码时约束采样,token 级保证输出符合 schema

三档的区别用一句话说:第一档是"口头约定",第二档是"格式合法就行",第三档是"解码时约束采样,把输出限制在符合 schema 的 JSON 结构内"。注意这保证的是结构合法,不是语义正确:数值范围、枚举 membership、跨字段一致性等语义约束不由 grammar 强制,仍需要输出侧断言兜底。

strict schema 的限制(面试追问级细节):必须 additionalProperties: false;所有属性必须在 required 里声明,可选字段用 "type": ["string", "null"] 表达;OpenAI 对 minimum/maximum/pattern 等约束静默接受但不强制——别把数值范围校验寄托在 schema 上。function calling 的 strict: true 是同一套解码约束机制。Python 侧工程实践:用 Pydantic 模型当 response_format(SDK 自动转 schema),解析失败即类型错误而不是运行时的 KeyError。

strict schema 的三种漏网模式:(a)中途 content-filter 拦截可能返回空或截断输出,只要 schema 允许 nullable 字段就能通过语法校验——输出侧断言是唯一能拦住它的手段;(b)tool calling 加 strict 有 provider 特定的参数/层级限制,超出时行为因实现而异;(c)token limit 截断可能产出语法合法但字段丢失的 JSON,只有输出侧断言能发现。

动手:把阶段一的记账 prompt 接上三档对比——离线用 run_output_assertions(python/agent_core/prompts.py)验证"自由文本档"的输出断言会抓到缺字段与超长;有 key 时按第16章的客户端发三次请求对照三档行为,无 key 则标 unverified-live。

阶段四:Prompt 即代码资产 ​

OpenAI 正在废弃 API 侧的可复用 prompt 对象(v1/prompts 端点 2026-11-30 关停),官方建议的方向正是 prompt as code:prompt 是 builder 函数 + 类型化参数,进 code review、进版本管理、pin 模型快照,改动必须过 golden dataset 回归与 CI gate。

断言分两类:

  • 确定性断言:合法 JSON、必含字段、长度上限、契约结构(四段齐全、XML 边界在位)。课程主线用这类,pytest 手写即可(promptfoo 等专用工具一句话提及,不引入依赖)。
  • Model-graded 断言:LLM-as-judge 按 rubric 打分。用于语气、完整性等无确定性判据的维度;live-only,本课标 unverified-live。

前端类比:你写过的表单校验就是确定性断言的同构物——schema 先行、错误即红。

参考实现把 golden 回归拆成离线可跑的两半:check_prompt_contract 检查 builder 产物的结构不变量(改坏 prompt 立即红),run_output_assertions 对 golden 录制的模型输出跑确定性断言;live 模型重放同一数据集是显式开关。

动手:为阶段三的记账 prompt 跑 python/tests/fixtures/w10b_golden_prompts.json 的 5 条 golden 回归;然后把 builder 里"只输出 JSON"那行指令删掉,确认 test_prompt_contract_catches_regression 同款断言变红,再修回去。这个"改一处挂一条"的循环就是 prompt 回归的日常形态。

阶段五:Agent 记忆演进四代谱系与显式海马长效记忆 ​

1. Token 计数现实与上下文预算边界 ​

Token 计数现实:本课 message_tokens() 用 ~4 字符/token 的近似值做预算记账,明确标注非计费用。真实 provider 按自有 tokenizer 计费,CJK 场景下 proxy 严重失真——一个汉字通常约 1 token 而非 ~4,导致中文 prompt 的实际费用可能数倍于 proxy 预测。需要精确计数时使用 tiktoken 类 BPE tokenizer 按模型家族取精确值。proxy 仅用于内部预算分配,不能用于成本估算。


2. Agent 记忆系统四代演进谱系图(从线性硬截断到生物启发海马图谱) ​

在构建工业级自主智能体(Autonomous Agents)时,记忆系统经历了一场从“粗暴丢弃”到“生物脑启发拓扑构建”的深刻范式演进:

第 1 代:滑动窗口与硬截断 (Sliding Window & Hard Truncation) ​

  • 架构机理:维护固定大小的 FIFO 消息队列或严格受控的 Token 预算。当总上下文达到上限时,最老的消息被硬性丢弃。
  • 致命缺陷:
    1. 前置约束丢失:早期由用户或系统确立的不可变全局业务红线(如“单笔退款不得超过 50 元”)随轮次推进被生硬淘汰;
    2. 协议断裂崩溃:若截断发生时恰好切断了 assistant tool_calls 与对应 tool 执行结果的配对,下一轮 API 请求将直接抛出 400 协议格式错误。
  • 适用边界:单轮或极短会话兜底。

第 2 代:对话历史异步摘要压缩 (Periodic Summary & Compaction) ​

  • 架构机理:设置动态触发阈值,当对话达到一定长度时,由后台异步 LLM 将早期轮次折叠为一段浓缩的 Running Summary(阶段摘要)。
  • 致命缺陷:
    1. 信息有损压缩(Lossy Compression):摘要算法天然青睐正向主干动作(“用户咨询了订票”),极易过滤掉精细数值、订单号、错误代码与前置负向约束;
    2. 误差雪崩累积:一旦单轮摘要出现幻觉或归纳偏差,该错误会作为后续摘要的输入,在多轮对话中呈指数级级联放大。
  • 适用边界:长会话且仅需大体轮廓的闲聊或通用客服。

第 3 代:向量分块情景记忆 (Vector-based Episodic Memory / Memory RAG / Mem0) ​

  • 架构机理:引入外置持久化向量数据库。对话发生时,抽取器将对话切分成独立的原子事实(Atomic Facts),转为 Dense Embedding 存入向量索引;写入层引入 ADD / UPDATE / DELETE / NOOP 四态冲突解决状态机;检索时计算当前 Query 的向量余弦相似度,将 Top-K 相关事实作为 <memory> 标签注入上下文。
  • 致命缺陷:
    1. 多跳逻辑断裂:事实在向量库中只是彼此孤立的几何离散点。面对“A 是 B 的母公司,B 控股了 C,C 涉及制裁,A 是否合规”这种需要跨多个跨期会话的多跳因果推断时,中间桥梁因缺乏直接查询词发生语义断崖(Recall 暴跌);
    2. 伪相似度污染:句式结构相似但实体不同的历史记忆容易被误召回,污染当前推理。
  • 适用边界:跨会话的用户稳定画像、单点事实精准回忆。

第 4 代:生物启发式海马知识图谱长效记忆 (Biologically-inspired Hippocampal KG Memory / HippoRAG) ​

  • 架构机理(吸收 UC Berkeley CS294-280 / Yu Su 教授 CLS 互补学习系统理论):
    1. 双轨认知协同:预训练大模型自身充当新皮层(Neocortex),沉淀泛化语言常识与抽象推理;外置的知识图谱拓扑网络充当海马体(Hippocampus),专司单次情景记忆的高敏锐度拓扑索引;
    2. 开放三元组实时构图:从持续对话中抽取(主-谓-宾)实体与关系边,无模式(Schema-free)编织出动态演进的知识拓扑网络;
    3. Personalized PageRank (PPR) 联想激活:查询到来时,密集链接定位种子实体节点,在图拓扑上运行带阻尼系数 α 的随机游走扩散。概率波在图的流形上穿透传播,实现神经动力学层面的模式分离(Pattern Separation,消除相似混叠)与模式补全(Pattern Completion,由局部残缺线索联想唤醒完整因果链);
    4. 显式可解释与动态剪枝:实体节点与边权具有物理意义,支持基于半衰期的突触衰减(Synaptic Pruning)与确定性增量修改。
  • 适用边界:复杂决策 Agent、跨越数月多会话的长程因果推断、高精度企业级智能体。

3. 四代 Agent 记忆架构全景对比矩阵 ​

演进代际核心数据结构与架构生物认知机制对应跨会话多跳推理能力事实增量更新与冲突解决关键失效模式计算与存储开销代表框架与系统
第 1 代:滑动窗口环形 Buffer / Token 队列短暂感官暂存 (Sensory Buffer)无(仅局部时空保留)物理丢弃,无法解决冲突截断点破坏工具配对、前置约束丢失存储极低,0 计算早期 ChatBot, 原生 SDK
第 2 代:滚动摘要层次化折叠文本 / Running Summary工作记忆粗糙压缩 (Working Memory Chunking)极弱(仅宏观大意轮廓)覆盖式压缩,极易抹平旧细节关键数字/代码脱落、摘要幻觉级联放大周期性触发 LLM 摘要调用LangChain ConversationSummaryBuffer
第 3 代:向量分块记忆向量数据库 + 四态决策机情景记忆单点检索 (Episodic Embedding)弱(多跳时遭遇语义断崖)ADD/UPDATE/DELETE/NOOP 显式判定向量近邻幻觉、无法执行拓扑跳跃向量索引存储,离线 Embedding 计算MemGPT (RAM/Disk 分层), Mem0
第 4 代:海马拓扑图谱开放三元组图谱 + PPR 联想扩散互补学习系统 (CLS 海马体)极强(拓扑流形多跳模式补全)图拓扑动态剪枝 + 实体边权半衰期更新图谱抽取质量依赖提取器精度图拓扑存储,毫秒级稀疏矩阵游走HippoRAG, CS294-280 前沿 Agent

4. 深度剖析:长上下文窗口(Long Context 1M+ Tokens)为什么永远无法取代显式记忆系统? ​

随着 Gemini、Claude、GPT 系列将上下文窗口推高至 100 万甚至 200 万 Tokens,技术社区常出现一种浪漫主义的虚假设想:“既然模型能吃下整本书,为什么不把用户过去一年的所有交互记录、全部知识库一股脑塞给它?外置记忆系统是不是过时了?”

从计算第一性原理与现代工业工程实践审视,长上下文(Long Context)不仅无法替代显式记忆系统,反而在无节制堆叠时暴露出三大致命绝症:

痛点一:显存带宽瓶颈与推理成本的阶梯式/非线性爆炸 (Latency Cliff & Cost Explosion) ​

  1. KV Cache 内存墙推导: 在自回归解码中,历史 Token 的 Key 和 Value 向量必须完整驻留在 GPU 显存中:KV Cache Size (Bytes)=2×2×nlayers×dmodel×L×B以 70B 参数量级的现代开源旗舰模型(以 Llama-3-70B 为例,80 层,维度 8192,8 组 GQA 机制)计算:
    • 当单次请求的上下文长度 L 达到 100 万 Tokens 时,单并发用户仅存储 KV Cache 就需要吞噬约 16 GB ~ 20 GB 顶级 HBM3 显存!
    • 如果线上需要维持 100 个并发长会话,仅仅维护 KV Cache 就要霸占 20 张 80GB H100 显卡,留给模型参数权重与并发 Batch 的显存空间几乎归零;
  2. TTFT 延迟断崖: Prefill 阶段对 1M Tokens 的矩阵运算严重受限于显存带宽(Memory Bandwidth Bound)。首 Token 响应时间(TTFT)会被拉长到 15 ~ 30 秒以上,交互体验瞬间退化至不可用;
  3. Prompt Caching 的破产边界: 虽然 Prompt Caching 能大幅降低静态前缀费用,但缓存命中的绝对前提是前缀逐字恒定。在自主 Agent 的动态长会话中,每轮不仅追加新用户消息,还交织着动态工具调用结果、时间戳与环境观测。只要中间产生微小扰动,后续数万至数十万 Token 的缓存便全线击穿失效,按全额计费。长期运行下,企业的 Token 成本将呈指数级失控。

痛点二:自注意力稀释与“迷失在中间” (Attention Dilution & "Lost in the Middle") ​

  1. Softmax 分母均摊机理: 标准自注意力的权重计算为:αi=exp⁡(q⋅ki/d)∑j=1Lexp⁡(q⋅kj/d)当上下文长度 L 扩张至 105∼106 时,分母由上百万个指数项求和构成。除极少数与 Query 强共振的局部 Token 外,绝大部分上下文位置所分配到的注意力权重衰减为极限接近 1/L 的均匀白噪声。
  2. “大海捞针”假象 vs 多跳复合推理塌陷:
    • 商业评测中宣传的“1M 窗口全绿”的“大海捞针”(Needle In A Haystack)测试,本质上只是单一字面暗号的 1 跳特征匹配;
    • 真实工业业务所要求的是跨长跨度多事实聚合、矛盾证据仲裁、时序溯源与严格负向边界遵守。斯坦福等机构的多项权威实证表明:当关联证据链分布在超长文本的“中段(Middle)”时,长窗口大模型的推理准确率呈现显著的深 U 型塌陷。把一年的聊天日志一股脑倒进 Context,等于主动给模型投毒,诱发严重的决策幻觉与逻辑短路。

痛点三:跨会话增量学习的记忆更新、时序冲突解决与主动遗忘机制 (Incremental Learning & Active Forgetting) ​

  1. 时间之矢与事实变迁(Temporal Contradiction): 静态的 Long Context 是无状态因果机。假设用户在第 1 天说:“我的收货地址是杭州市西湖区”;在第 20 天说:“我搬到了上海市浦东新区”;在第 45 天对 Agent 说:“帮我买个手机支架寄到我家”。 若将这 45 天的所有交互未经过滤塞进 1M 上下文,模型内部必须在自注意力层面对两个彼此矛盾的“真命题”进行隐式仲裁。由于注意力波动,模型随机抓取杭州或上海,甚至出现“寄往杭州市浦东新区”的离谱幻觉。
  2. 人类大脑遗忘机制的计算工程映射: 人类如果没有主动遗忘(Active Forgetting)与突触修剪(Synaptic Pruning),大脑会在短时间内因神经连接过载而精神崩溃。 显式记忆系统之所以是唯一的长治久安之道,是因为它具备外置的状态机与生命周期治理:
    • 确定性冲突解决:通过 ADD / UPDATE / DELETE / NOOP 四态机,在写入时即刻完成“新地址覆盖旧地址”的时序决议,从物理层面抹去陈旧事实;
    • 艾宾浩斯与半衰期拓扑衰减:通过时间衰减权重 w(t)=w0⋅2−Δt/τ,自动淡化久未被激活的边缘记忆,定期修剪死节点;
    • GDPR 与被遗忘权(Right to be Forgotten):在企业合规场景中,用户要求删除其敏感个人信息时,外置记忆系统只需执行一行确定性 SQL 或图节点删除;而若塞进隐式 Long Context 或模型微调权重中,你永远无法从数学上证明该隐私信息已被彻底抹除!

5. 前沿理论深度链接:Grokked Transformers 与互联网世界模型 ​

UC Berkeley CS294-280 (Spring 2025: Advanced LLM Agents, L03: Yu Su) 为我们理解显式记忆提供了前沿视界:

  1. Grokked Transformers(隐式图内化的顿悟现象): 研究发现,当 Transformer 在关系拓扑语料上进行超长时间训练时,会发生从“记住表面模式”到“顿悟”(Grokking)底层图拓扑回路的相变。然而,在模型部署后,其新皮层参数被静态冻结。面对瞬息万变的用户现实与动态业务逻辑,**显式外置海马知识图谱(HippoRAG)**是让冻结的大模型以极低边际成本获得持续、终身图推理能力的唯一解。
  2. World Models of the Internet (WebArena / Mind2Web): 智能体的长效记忆不仅仅是记录人类自然语言对话,更包括对环境状态演迁的世界模型建模。在互联网真实交互中,网页 DOM 树与动作转移构成了一张超大规模的图状态机。Agent 在执行长程复杂任务(如跨网站订票比价、多系统填报)时,海马拓扑记忆能够将历史交互轨迹与世界状态因果图沉淀下来,实现故障自愈与最优路径规划。

6. 概念对照与工业核心实践 ​

概念对照(心智模型):

  • LangGraph:短期记忆是 thread 级 checkpointer(第15章的 checkpoint 同构),长期记忆是跨 thread 的 store;两者接口分离。
  • MemGPT / Letta:OS 虚拟内存类比——main context 是 RAM,recall/archival storage 是磁盘,模型自己用 function call 做 paging(决定何时把什么换入换出)。
  • mem0:写入路径不是 append-only 日志,而是 ADD/UPDATE/DELETE/NOOP 的冲突解决状态机——新事实来了先和存量比对再决定怎么写。
  • HippoRAG:模拟海马-新皮层双轨协同,通过知识图谱拓扑与 Personalized PageRank 算法实现复杂长程因果联想。

为什么 append-only 是错的——跟着决策序列走一遍:用户先说"我的地址是杭州市西湖区"(存里没有 → ADD);重复说一遍(已在 → NOOP);接着说"我把地址改成上海市浦东新区"(同 key 冲突 → UPDATE 覆盖旧值);最后说"请删除我的地址"(DELETE)。如果只做 append,"改地址"后新旧并存,检索随机命中旧值——事实会过期,写入必须有冲突决策。

动手(本章核心编码任务,参考实现 python/agent_core/memory.py,stdlib-only):

  1. trim_to_token_budget:token 预算截断,按 group_tool_units 把 assistant tool_calls 与对应 tool 结果绑成原子单元,截断只发生在单元边界——配对永远完整。
  2. 穷人版事实记忆 FactStore:dict 存储 + 可注入抽取器(默认三条正则的玩具抽取器,诚实标注非 LLM)+ 关键词检索回注(<memory> XML 边界,按 data 处理)。亲手复现上面的"用户改地址"场景,实测决策序列 [ADD, NOOP, UPDATE, DELETE]。

阶段六:Context Engineering 预算模型、MCP 膨胀与负向约束防御 ​

1. 上下文窗口全局预算分配模型 ​

在构建工业级 Agent 时,切忌无节制向 prompt 塞入内容。总上下文窗口必须按硬性预算槽位进行静态切分与动态仲裁:

Lmax≥Bsys+Btools+Bexamples+Brag+Bhistory+Boutput
预算分级槽位名称典型占比/上限 (以 32k/128k 为例)变动特征缓存策略溢出处理与淘汰规则
Tier 0System & Core Identity500 ~ 1,500 tokens跨会话恒定强制前缀命中 (Prompt Cache)不可变(Immutable),绝对禁止截断
Tier 1Active Tool Definitions1,000 ~ 4,000 tokens随工具集配置变化紧随 System 之后保持稳定超限时触发动态工具按需裁剪(Tool Pruning)
Tier 2Few-shot Examples500 ~ 2,000 tokens任务内稳定参与前缀缓存预算受限时降级为零样本(0-shot)
Tier 3Dynamic Memory & RAG2,000 ~ 8,000 tokens随单轮请求动态检索位于易变区,不参与前缀缓存按相似度得分阈值截断(Top-K 动态截流)
Tier 4Conversation History弹性分配 (Lmax−∑Bi)随轮次线性递增局部尾部变化触发原子级 Tool Unit 滑动窗口或阶段摘要
Tier 5Output Reserve2,000 ~ 4,000 tokens输出硬预留预留解码显存必须硬预留,防止模型输出被截断导致 500/Malformed JSON

2. MCP 工具 Schema 上下文膨胀与两阶段动态裁剪 ​

企业级应用接入 Model Context Protocol (MCP) 时,开发者常一次性注册数十个微服务工具。一个包含 8 个字段与详细校验规则的 Typed JSON Schema 平均占用 150 ~ 300 tokens。当注册 40 个工具时,仅工具定义就会侵蚀 8,000 ~ 12,000 tokens:

  • 物理后果:首 Token 延迟(TTFT)大幅拉长(Prefill 显存带宽暴增);历史对话空间被压缩;工具选择候选空间(Candidate space)爆炸导致模型决策幻觉率陡增。
  • 工程解法(两阶段动态裁剪):维护轻量级工具索引(名称 + 单句意图摘要,单工具仅约 20 tokens)。用户输入到来时,先通过轻量分类器或词面/语义检索召回 Top-K(如 3~5 个)相关工具,仅将其完整 Schema 动态注入上下文,直接将 Schema 消耗降低 70% 以上(实现见 python/agent_core/context_cost.py::ToolPruner)。

3. Compaction 摘要导致关键负向约束丢失故障实验 ​

许多开发者误将安全边界(例如“退款绝对不能超过 50 元”)置于早期用户消息中。当长对话触发自动摘要(Compaction)时,摘要算法天生倾向于保留正向业务动作(“用户咨询了订单并沟通退款”),而极易丢弃条件性负向约束(Negative Constraints):

  • 故障注入与再现:第 1 轮声明负向约束;中间经过 6 轮普通问答;触发滚动摘要后生成概述;第 10 轮发起超额退款请求。由于摘要中关键负向约束丢失,模型毫无感知地直接触发执行工具,造成业务越权事故!
  • 不可变防御架构(System Guardrail Separation):所有安全与业务负向约束必须提升至 System Prompt 的专属防护区(<system_guardrails>),或由外部策略网关(Policy Engine)独立拦截,绝对禁止将安全红线混入可压缩的历史消息栈中。

阶段七:指令遵循代际演进与 MUST 过触发陷阱 ​

1. 模型代际对齐严格化与“咆哮体”失效 ​

在早期模型代际(如 GPT-3 / 早期开源大模型)中,指令遵循能力相对涣散。开发者不得不使用强烈的祈使词甚至“Prompt 咆哮体”(如 YOU MUST ALWAYS、UNDER NO CIRCUMSTANCES、CRITICAL RULE)来强行拉高模型的注意力。

然而在现代强对齐模型(如 GPT-4o、Claude 3.5、DeepSeek-V3、Qwen-2.5)中,经历了多阶段严格的 RLHF、DPO 与针对指令违背(Instruction Violation)施加的严厉负向奖励惩罚。现代模型在注意力先验上对强语气词表现出极高的字面敏感性:

  • MUST 过触发(Over-triggering)灾难:当 Prompt 中注入形如 YOU MUST ALWAYS CALL search_tool TO VERIFY ANY FACTS 时,面对简单的“1+1等于几”或“你好”,模型为了规避对 MUST 的字面惩罚,会强行调用 search_web("1+1")。这导致简单请求的工具调用成本飙升 5~10 倍,端到端延迟增加数秒。
  • 正向工程范式:从咆哮体转向显式的前置判定谓词(Condition-based Constraints):
    • 反模式(咆哮强制):CRITICAL! YOU MUST ALWAYS CALL search_tool BEFORE ANSWERING ANY QUESTION NO MATTER WHAT!!
    • 正模式(条件约束):When answering queries requiring factual data from 2024 or later, invoke search_tool. For common arithmetic, reasoning, or chit-chat, reply directly without tools.

2. 注意力稀释与梯度惩罚的物理学推导 ​

从自注意力机理理解这一现象:

αi=exp⁡(q⋅ki/d)∑j=1Nexp⁡(q⋅kj/d)
  1. 长序列下的注意力稀释(Attention Dilution):当输入序列 N 扩展至 32k~128k 时,Softmax 分母项由数万个指数项累加。若 Query 与 Key 缺乏尖锐匹配,注意力权重将衰减为均摊噪声(1/N),导致中间上下文信息被模型“视而不见”(Lost in the Middle)。
  2. 极化权重对全局语义的压制:为了强行抗衡注意力稀释,SFT/RLHF 强化了对 MUST / ALWAYS 的梯度权重,使得 q⋅kMUST 数值被推向极端。在 Softmax 归一化后,概率分布呈现陡峭的狄拉克脉冲状,直接压制了上下文其他必要分支条件的注意力分配,形成过度激进触发。

阶段八:多轮长对话成本基准与 10 万用户存储容量估算 ​

1. LL-Context-1:长对话 5 种优化方案 20 轮基准对比 ​

在真实开发场景中,我们针对 20 轮连续研发对话(包含长文本排障、大工具结果返回)对 5 种上下文优化方案进行了严格的确定性仿真对拍(代码实测见 python/agent_core/context_cost.py):

优化策略20 轮累计 Input Tokens20 轮累计 Output Tokens前缀缓存命中率预估调用成本 (USD/百次)上下文保真度架构选型权衡
1. 全量追加 (Raw History)84,2006,4000%$0.220100%成本呈 O(n2) 爆炸,快速击穿窗口上限
2. 滑动窗口 (Window=4)18,6006,4000%$0.05635%成本低,但完全丢失早期需求与前置约定
3. 周期摘要 (Periodic Summary)28,4006,800 (含摘要)0%$0.08265%保留主干轮廓,但易丢失精细数值与负向边界
4. 工具结果折叠 (Tool Folding)36,8006,4000%$0.09890%保留最新工具输出、折叠历史长输出,性价比极高
5. 前缀缓存 + 折叠 (Hybrid)36,800 (其中 26,000 命中缓存)6,40070.6%$0.04190%生产最优解:利用前缀缓存 1 折优惠,兼顾保真与成本

2. LL-Context-2:10 万用户会话状态存储 5 维选型与容量推导 ​

5 维存储选型对比矩阵 ​

选型方案延迟 (P99)一致性保证综合基础设施成本 (TCO)持久化与灾难恢复水平跨实例共享生产推荐定位
A. 进程内存 / 本地 SQLite< 0.1 ms单机强一致,跨节点不可见极低(0 外部基建)弱(重启即失或单机磁盘单点)不支持(无法无状态横向伸缩)本地教学演示与单元测试
B. 分布式缓存 (Redis Cluster)< 2 ms最终一致 / 弱一致中高(纯内存存储成本)中(RDB/AOF 异步落盘,极端宕机可能丢毫秒数据)原生支持(天然适应无状态微服务集群)热会话活跃窗口首选
C. 分布式 NoSQL (DynamoDB/Mongo)5 ~ 15 ms可调一致性 (Eventual / Strong)中(按存储容量与读写单元计费)强(多可用区副本持久化)极优(开箱即用无状态共享)温冷会长会话与归档首选
D. 关系型数据库 (PostgreSQL)10 ~ 30 msACID 强事务一致中(需专门连接池与磁盘 IOPS 预算)强(完备的 WAL 与事务保障)良好(高并发下需读写分离)会话与业务交易紧密强绑定场景

10 万用户场景容量与带宽精算 ​

  • 明确基准假设:
    1. 注册用户 10 万,日活跃比例 DAU Ratio=30%→DAU=30,000。
    2. 集中在每日 10 小时内(36,000 秒),峰值集中系数取 2.5;每活跃用户平均 4 轮交互,每轮产生 800 字节,活跃会话保留 10 轮历史(单活跃会话净数据量约 8 KB ~ 10 KB)。
    3. 热会话(Redis)生命周期设为 2 小时无活动自动过期,并发活跃会话按活跃用户的 15% 计(约 4,500 个并发会话)。
    4. 冷会话持久化保留 90 天归档。
  • 推导计算结果:
    • 热内存占用 (Redis):4,500×10 KB×1.5(结构开销)≈67.5 MB!即使峰值并发达 2 万个会话,内存需求也仅约 300 MB。单台常规规格 Redis 实例即可轻松承载 10 万级用户的热会话状态。
    • 冷持久化存储需求 (90 天):每天产生全量增量 30,000×4×800 B≈96 MB/天。90 天累计历史仅需 ≈8.64 GB(含索引预留 ≈20 GB)。
    • 网络 IO 带宽:平均 QPS 约 6.7,峰值 QPS 约 16.8 req/s,峰值吞吐带宽仅 ≈168 KB/s(1.34 Mbps),完全不会对网络造成任何瓶颈。

3. LL-Context-3:高并发 Token 成本管控三位一体网关 ​

为防止异常流量或恶意重试击穿企业 Token 预算,生产网关必须集成三级拦截防线(代码见 python/agent_core/context_cost.py::ContextCostGate):

  1. 租户级双令牌桶限流(Tenant Rate Limiter):每个租户独立配置 RPM(每分钟请求数)与 TPM(每分钟 Token 配额),超限立即返回 429,阻止单个租户抢占全系统资源。
  2. 两级缓存(Exact & Semantic Cache):请求哈希命中时直接返回已有响应(0 Token 开销,响应延迟 <50 ms)。
  3. 模型分级智能路由(Model Tier Routing):简单意图、纯打招呼与格式转换自动分流至 Tier 1 经济模型(如 8B / Flash,成本仅旗舰模型的 1/10);长文本推理与复杂工具编排才分配至 Tier 2 旗舰模型。
  4. 多租户成本归因分析(Cost Attribution):实时记录每个租户的轻重模型消耗、缓存命中与折算美元成本,形成企业财务级用量对账单。

阶段九:动手实验 ​

把"prompt 即代码"、"记忆有写入语义"与"成本工程防护"钉成离线确定性证据:prompt 契约断言、5 条 golden 输出断言、tool 配对截断、负向约束丢失防范、多租户限流与 20 轮长对话成本基准全部由测试覆盖。

环境准备 ​

bash
cd <仓库根>
export PYTHONPATH="$PWD/python"

命令与预期输出 ​

bash
# 1) 运行上下文工程与成本管控全套单元测试
.venv/bin/python -m pytest python/tests/test_context_cost.py -v

# 2) 离线确定性测试(CI 默认线,无需 key、无网络)
.venv/bin/python -m pytest python/tests/test_memory.py -q

# 3) 记忆层场景演示:截断配对 / 冲突决策 / 检索回注 / 占位摘要
.venv/bin/python - <<'PY'
from agent_core.memory import FactStore, SummaryMemory, trim_to_token_budget, message_tokens

history = [{"role": "system", "content": "你是记账助手"}]
history.append({"role": "user", "content": "q0 " + "x" * 36})
history.append({"role": "assistant", "content": "", "tool_calls": [{"id": "call_1", "name": "lookup", "arguments": {"q": "x"}}]})
history.append({"role": "tool", "tool_call_id": "call_1", "content": "r1 " + "y" * 36})
history.append({"role": "user", "content": "q1 " + "x" * 36})
kept = trim_to_token_budget(history, 14 + message_tokens(history[3]) + message_tokens(history[4]) + 1)
print("trim_in:", len(history), "trim_out:", len(kept), "roles:", [m["role"] for m in kept])

store = FactStore()
store.ingest("我的地址是杭州市西湖区")
store.ingest("我的地址是杭州市西湖区")
store.ingest("后来搬家了, 我把地址改成上海市浦东新区")
store.ingest("请删除我的地址")
print("decisions:", [d for d, _ in store.history])

store2 = FactStore()
store2.ingest("我的地址是杭州市西湖区")
print("reinject:", repr(store2.render_for_prompt("收货地址填哪里")))

mem = SummaryMemory(recent=2)
msgs = [{"role": "user", "content": f"old {i}"} for i in range(4)] + [{"role": "user", "content": "new 0"}, {"role": "user", "content": "new 1"}]
out = mem.compress(msgs)
print("summary_first_line:", out[0]["content"].splitlines()[0])
print("summary_kept:", [m["content"] for m in out[1:]])
PY
text
....................                                                     [100%]
20 passed in 0.13s

trim_in: 5 trim_out: 2 roles: ['system', 'user']
decisions: ['ADD', 'NOOP', 'UPDATE', 'DELETE']
reinject: '<memory>\n- 地址: 杭州市西湖区\n</memory>'
summary_first_line: [占位摘要: 确定性截断拼接, 未经模型总结]
summary_kept: ['new 0', 'new 1']

判定信号:
  截断只丢整条 tool unit,输出里没有任何 stranded tool result
  改地址冲突走出 ADD → NOOP → UPDATE → DELETE,每 key 唯一当前值
  检索回注带 <memory> XML 边界;零重叠查询返回空串
  占位摘要自带诚实标记,绝不会被误引用为模型摘要
  golden 5 条全过;删掉 JSON 指令后契约断言恰好报 missing JSON-output instruction

live 核验(有 key 时自选,不计入本仓库证据):用第16章的客户端对阶段二冲突 prompt 与阶段三三档 response_format 各发一次请求,对照本章描述的行为,把结果记进你自己的学习者证据。

概念图 ​

故障注入与预期信号 ​

注入预期失败信号修复后证据
截断直接 messages[-N:] 不管角色截断点切断 tool 配对,下一轮请求 400(tool result 没有待应答的 call)按 tool unit 整体截断;配对不变量测试通过
指令说输出 JSON、示例是自由文本模型跟示例输出自由文本,下游 json.loads 崩示例与指令对齐;golden 输出断言兜底变绿
只开 JSON mode 就当有 schema 保证输出合法 JSON 但缺字段/多字段strict json_schema,或输出侧确定性断言抓缺字段
prompt 改一处文案无回归线上行为悄悄变化,事后才发现契约断言(四段/顺序/XML 边界/JSON 指令)+ 5 条 golden 进 CI
记忆只 append 不解决冲突"改地址"后新旧地址并存,检索随机命中旧值决策序列 [ADD, NOOP, UPDATE, DELETE];每 key 唯一当前值
盲目依赖 1M+ Long Context 堆叠全量历史显存 KV Cache 爆炸、中段注意力稀释深 U 塌陷、时空事实冲突幻觉显式海马知识图谱 (HippoRAG) + 四态决策机 + 半衰期拓扑剪枝
检索回注不带边界直接拼进 system记忆内容被当指令执行,注入面扩大<memory> XML 边界 + Instructions 声明按 data 处理
用占位截断文本冒充模型摘要evidence 把拼接字符串当模型能力引用占位摘要自带 [占位摘要: 确定性截断拼接, 未经模型总结] 标记;live 摘要标 unverified-live
40 个 MCP 工具全量塞入 system prompt消耗上万 token,TTFT 暴增,候选空间爆炸引发工具幻觉ToolPruner 动态检索 Top-K 工具 Schema,节省 70%+ token
滚动摘要压入会话导致负向约束丢失摘要丢弃“严禁超过 $50”负向边界,模型后续越权执行不变约束固定在 <system_guardrails>,不随历史压缩
盲目注入 MUST 咆哮体规则简单计算与问候强行调用 search_web,成本与延迟激增 5~10 倍显式前置判定谓词替代绝对语气词;条件式触发测试通过
突发高并发请求无租户级限流单租户死循环打爆全局 API TPM 配额,其余租户请求被连带阻断ContextCostGate 租户双令牌桶 (RPM/TPM) 拦截;429 降级测试通过
10 万用户会话全部存在单机内存实例重启或 Pod 漂移导致状态全部丢失,级联引发重新执行雪崩热状态外挂 Redis Cluster,冷会话归档 NoSQL,容量推导验证通过

本章验收 ​

不看资料,用 5–10 分钟回答:

  • 闭卷解释四段式 system prompt 各段职责;为什么 Context 放尾部?角色层级与 XML 边界为什么是缓解不是防御?
  • JSON mode 与 strict json_schema 的保证差异是什么?strict schema 的三条限制(additionalProperties、required 全声明、nullable 表可选)各解决什么?
  • 线上格式约束失效,你的排查顺序是什么?(是否根本没开约束 → 是否只开了 JSON mode → 指令与示例是否冲突 → 多轮格式漂移 → 输出侧断言兜底)
  • prompt 变更如何防回归?说出 golden dataset、确定性断言与 model-graded 断言的分工,以及 CI gate 卡什么。
  • 梳理 Agent 记忆系统的四代演进历程;为什么随着模型上下文窗口突破 1M+ Tokens,我们依然必须依赖显式外置记忆系统?从显存 KV Cache 成本、注意力稀释(Lost in the Middle)与时序事实变迁/主动遗忘三个物理与逻辑维度展开论证。
  • 解释神经生物学互补学习系统(CLS)中新皮层(Neocortex)与海马体(Hippocampus)在大模型记忆架构中的工程映射;说明 HippoRAG 如何通过模式分离与模式补全化解多跳跨文档推断失效。
  • 用户说"我搬家了",记忆系统应该怎么写?跟着 ADD/NOOP/UPDATE/DELETE 决策序列走一遍,说明为什么 append-only 是错的。
  • 用 OS 虚拟内存类比讲 MemGPT:main context、recall/archival、paging 各对应什么?记忆污染有哪些缓解手段?
  • 调试题:对照故障表第三行"只开 JSON mode 就当有 schema 保证",写一个输出侧断言,能捕获"合法 JSON 但缺少必填字段"的漏网情况;对比 strict schema + 输出侧断言双层防御为什么比单层更可靠。

规范与延伸 ​

前端/Agent 迁移 ​

记忆四模式你全见过:滑动窗口是环形 buffer,摘要是 lossy 压缩,记忆 RAG 是带召回的缓存,画像是单文档 JSON store。真正新的只有两点:约束的"执行者"是采样的模型而不是确定性代码,所以断言要放在输出侧兜底;记忆写入需要冲突决策,因为事实会过期。

资源 / 成本 / 隐私 ​

离线路径(测试与场景演示)gross cost 为 0、无网络。live 路径走第16章同一免费层与同一纪律:key 只走环境变量;用户私有信息(地址、预算等)属于 Context/记忆内容,发往 provider 前按第16章的数据边界声明自行判断。摘要记忆的默认实现是确定性占位,不调用任何模型。

Evidence ​

仓库当前机器证据(只读快照) ​

evidence/15-prompt-memory-v1.json 是当前 checkout 的脱敏机器运行记录,只覆盖离线路径:test_memory.py 20 项全部通过、5 条 golden prompt 回归、事实冲突决策序列 [ADD, NOOP, UPDATE, DELETE]、截断配对不变量。live 模型路径(指令-示例冲突实验、三档 response_format 对照、模型摘要、model-graded 断言)在无 key 环境下标记 unverified-live 并写入 known_failures。本模块已登记进 evidence/module-manifest-v1.json。

学习者提交模板(待填写,不是当前机器证据) ​

复制下面模板并填写自己的真实运行结果。所有 <...> 都是未填写状态;actual 和 artifacts 尤其不能被当作已运行或已通过。artifacts 必须替换为本次提交中真实存在的仓库相对路径。live 指标(若有)必须来自你自己的 key 的真实调用,并在 known_failures 注明数据边界。

yaml
schema: learn-llm.evidence.v1
module: 17-prompt-memory
commit: <learner-commit-sha>
verified_at: <iso-date>
environment: <sanitized-python-device>
seed: 10
commands:
  - PYTHONPATH=python python -m pytest python/tests/test_memory.py -q
metrics:
  - name: offline_tests_passed
    expected: 20
    actual: <recorded-value>
  - name: golden_prompt_cases_passed
    expected: 5
    actual: <recorded-value>
  - name: fact_conflict_decision_sequence
    expected: [ADD, NOOP, UPDATE, DELETE]
    actual: <recorded-value>
  - name: live_structured_outputs_comparison
    expected: unverified-live
    actual: <recorded-value-or-unverified-live>
artifacts:
  - <learner-repo-relative-artifact-path>
cost:
  gross_usd: 0
  credit_usd: 0
licenses:
  - source: <source>
    version: <version>
    license: <license>
    attribution: <attribution>
    redistribution: <redistribution>
known_failures:
  - <sanitized-failure-or-none>

只有 live 调用截图、没有 golden 回归与记忆冲突决策断言时,本章保持 gate。

下一步 ​

进入 第18章 · 生产编排:StateGraph 与 LangGraph 对拍:把手写 loop 映射到 LangGraph——StateGraph、checkpointer、interrupt 式 HITL 与五类 workflow 模式。

私有学习站 · 原理从零构建 · 勿提交个人隐私或密钥