Pi :上下文工程——Context Assembly、Compaction 与 Memor

这是本系列最重要的"横向能力"篇。前面所有篇都在讲"Agent 怎么运行",这一篇讲Agent 每轮调用 LLM 时,最终进入模型窗口的那堆 token 到底是怎么来的

每轮给模型构造的上下文,才是 Agent 的真正 CPU。 模型选错了可以换,上下文构造错了,Agent 会"越跑越傻"------这正是本系列一直强调"Context 是编译出来的"的完整展开。


〇、先建立全景:一次推理的上下文从哪里来

某一轮调用 LLM 时,进入窗口的内容可以画成一条流水线:

text 复制代码
用户输入
   ↓
System Prompt
   ↓
项目级 instructions(AGENTS.md / CLAUDE.md)
   ↓
Skill instructions(按需读取的 SKILL.md)
   ↓
历史 conversation(会话树 → 当前叶子路径)
   ↓
tool result(工具执行结果)
   ↓
文件内容(read 工具读进来的代码/文档)
   ↓
错误信息(bash 报错、测试失败输出)
   ↓
压缩 / 截断 / 摘要(compaction 检查点)
   ↓
最终 Context
   ↓
LLM

Pi 对这条链路的工程化,散在本系列各篇里;这篇把它们收拢成一个完整学科。记住:模型看到什么,决定模型做什么。上下文构造是 Agent 的隐性控制器。

一、Context Assembly:谁有资格进窗口

Pi 的上下文由这些来源组装(每个来源都有独立的生命周期和信任等级):

来源 Pi 的机制 生命周期
System Prompt 构建链:AGENTS.md → skills 目录 → 模板 → before_run 覆盖 每 run 构建,可覆盖
项目 instructions AGENTS.md/CLAUDE.md/.pi/SYSTEM.md(未信任也加载) 每会话加载
Skill instructions <available_skills> 目录 + 模型按需 read 全文 渐进式披露
历史对话 会话树 → 当前叶子到根的路径 append-only
工具结果 ToolResultMessage 随消息落账 每轮追加
运行时元数据 env 注入的 PI_SESSION_ID 每命令解析

关键原则(本系列反复出现):

  • 系统提示词保持极简:skills 只列描述不内联,因为"给模型多少判断原料"是预算。
  • 项目宪法优先AGENTS.md 在项目未信任时也加载------"这个仓库的规矩"优先级高于一切。
  • transform_context 是最后一道变换 :只改 provider 看到的、不改会话存的------"呈现层"和"存储层"分离,防止为临时目的污染永久记录。

二、Context Budget:窗口满了谁被扔

假设模型窗口 200k,Agent 跑久以后:

text 复制代码
历史消息      70k
代码          80k
tool output   50k
system         5k
----------------
             205k  ← 超了

"谁被扔"是决定 Agent 是否"越跑越傻"的关键决策。 候选策略(按信息价值从低到高):

策略 丢弃对象 代价
时间优先 最早的消息 可能丢"关键但早"的事实
重要度优先 低优先级消息(闲聊) 需要消息分级(总纲上下文篇)
工具结果优先 旧工具输出 模型可能"忘了"自己做过什么
system 永不删 系统提示词恒定 占固定预算
文件重读而非常驻 不保存文件内容,用时再 read 每次重新检索

Pi 的立场是"追加不变式 + 一次性失效":

Across the requests of a lane, provider context only grows at the tail. An insertion before the previous request's tail invalidates the provider's KV cache from that point on and multiplies token cost.

上下文只允许尾增长------因为中间插入会无效化 KV cache 并放大成本。所以:回合中途的写入推迟到 checkpoint 追加,compaction 是唯一一次刻意的缓存失效。

预算的硬护栏reserveTokens(默认 16k 留给响应)+ 溢出判定(显式超限错误 / 输入超窗口 / 可恢复 length)。预算要在发请求前就算好,超了就分类处理,事后才裁已经来不及。

三、Compaction:长周期运行的命脉

Compaction 是 Agent 长周期运行的核心技术。完整生命周期:

text 复制代码
Raw history
   ↓ 触发(阈值 / /compact 手动 / overflow 溢出)
Summary generation(LLM 摘要)
   ↓
Important state extraction(保留关键状态)
   ↓
Old messages replacement(CompactionEntry 落账)
   ↓
Continue execution(从 retainedTail 重建上下文)

Pi 的 CompactionEntry带三样东西:summary(摘要)、firstKeptEntryId(保留起点)、retainedTail(自包含检查点)。retainedTail 让重建可以从检查点直接往后走,不翻旧条目。

Compaction 的四个"能不能压"的判断,是工程精华:

  1. 摘要丢信息怎么办? 分级处理------普通对话可压,代码/SQL/合同这类"语义敏感"内容压了等于改语义。
  2. 工具执行事实能不能被 summary 覆盖? 危险。工具做了什么(改了哪个文件、结果是什么)是审计和继续推理的锚点,Pi 的 overflow compaction 明确把链接的那个响应从摘要准备中排除("exact overflow-response omission")------关键事实留原文。
  3. 文件修改记录该不该压缩? 不该。修改记录是"Agent 对世界做过的改变",压掉就无法审计/回滚。
  4. 用户约束是否允许压缩? 用户明确说的要求("不要改这个文件")是 CRITICAL 级,永不压(总纲上下文篇)。

compaction 的正确姿势:压缩的是"过程性的旧对话",保留的是"结论性的状态和约束"。

四、Working Memory vs Long-term Memory:五种不同的存储

很多 Agent 项目把"记忆"当成一个筐,但 Pi(和 CC 的对照)揭示了至少五种不同的存储,各有生命周期:

存储 生命周期 例子 谁来管
Conversation History 一次会话 会话树 引擎
Working Memory 一次 run 变量池/车道记录 运行时
Long-term Memory 跨会话 CC 的 memory 文件、项目事实 应用
Project State 随项目 .pi/settings.jsonAGENTS.md 应用
Artifact State 随产物 git 历史、生成文件 外部

关键区分(总纲上下文篇):知识进上下文靠检索(RAG),经验进行为靠记忆(memory 文件),事实靠状态存储(项目/产物)。 三件事别混进一个筐:

  • Pi 的会话账本是 Conversation History + Working Memory 的合体(append-only + lane records);
  • CC 的 memory 文件是 Long-term Memory(跨会话的身份/偏好/被纠正过的工作方式);
  • 项目文件本身就是 Project/Artifact State(Agent 不需要"记住",需要时 read)。

设计你自己的 Agent 时,先回答:这五种存储各归谁、各活多久、谁能写。 最常见的错误是把 Long-term Memory 塞进 Conversation History------一旦会话压缩,记忆跟着丢。

五、对照你的工程:上下文系统的设计清单

能力 做法 优先级
ContextBuilder 单一管道 所有模块不许自己拼 prompt(总纲) P0
组装顺序即策略 身份→检索→去重→排序→过滤→预算(总纲) P0
预算前置 发请求前算 token,超了分类处理 P0
追加不变式 上下文只尾增长,不中间插入 P0
compaction 分级 普通对话可压,约束/事实/敏感内容不压 P0
五种存储分离 对话/工作/长期/项目/产物各归其位 P1
transform_context 呈现层 改 provider 看的,不改会话存的 P1
文件重读而非常驻 大文件用时 read,不长期占窗口 P1

一句话收束:上下文工程的本质是"在有限的窗口里,决定模型每一轮该看到什么、不该看到什么"。 它比模型选择更决定 Agent 质量------因为再强的模型,喂错上下文也会胡说。


知识卡片(本节体系归档)

text 复制代码
┌──────────────────────────────────────────────────────────┐
│ 知识节点:上下文工程(Agent 的真正 CPU)                     │
│                                                          │
│ What  Context Assembly 流水线 + Budget(谁被扔)+           │
│       Compaction(压过程留结论)+ 五层记忆分离               │
│                                                          │
│ Why   一般原理:模型看到什么,决定模型做什么。不变量:         │
│       ① 上下文只尾增长(KV cache 不失效)                   │
│       ② 预算前置:发请求前算好,超了就分类处理               │
│       ③ compaction 压的是过程性的旧对话,留的是结论和约束     │
│                                                          │
│ How   校验动作:                                          │
│       画上下文流水线 + PaiFlow 预算前置                      │
│                                                          │
│ Pits  坑点:                                              │
│       越跑越傻 / 上下文灌爆 / 记忆混筐                      │
│                                                          │
│ Transfer 到 PaiFlow:ContextBuilder 预算前置 + 分级压缩     │
└──────────────────────────────────────────────────────────┘
相关推荐
vipbic1 小时前
网站升级了,我却有点舍不得
前端·vue.js·后端
IT_陈寒1 小时前
Java Stream并行处理让我数据库崩了两次
前端·人工智能·后端
恋猫de小郭1 小时前
Flutter 3.47 首坑,analysis_options 问题连环回归
android·前端·flutter
zhuyingxiao1 小时前
ChatGPT、Claude Code、Codex 能直接控制泵阀吗?AI Agent 液路监测的正确架构
人工智能·chatgpt·架构
童谣11 小时前
越华碳能:V3.0 多模态物联网碳核算微服务平台架构设计与落地实践
物联网·微服务·架构
YWL1 小时前
OpenLayers测距测面:完整测量工具
前端·javascript·vue.js·信息可视化·openlayers
zhanghaha13141 小时前
HTML系列教程:2_HTML 编辑器(零基础超详细讲解
前端·编辑器·html
半旧5181 小时前
【Java Web02】WEB服务器内部实现技术揭秘
java·服务器·前端
拿本唠嗑AI研究1 小时前
现代前端架构爬虫指南:从静态页面到 React/Vue 单页应用
前端·爬虫·架构
ZJU_统一阿萨姆2 小时前
【推理优化进阶】Hopper_Blackwell 微架构:从指令、流水线到真实性能上限
开发语言·人工智能·语言模型·架构·开源