Context、Memory 与 Skill:让 Agent 在正确的信息上行动
1. 第一性原理:上下文是决策所需的证据集合
上下文不是聊天记录的同义词。模型下一步行动的质量取决于它能否看到:当前目标、不可违反的约束、已确认事实、最近观察、可用能力和完成标准。
可以把 Context Builder 看成一个受预算约束的选择器:
选择信息集合 C
使得 Relevant(C) + Trust(C) + ConstraintCoverage(C)
最大化,同时 Cost(C) <= token_budget
因此“上下文窗口越大越好”是错误的。无关信息会稀释注意力,冲突信息会增加不确定性,过期信息会把 Agent 带向错误方向。
2. Context 的分层装配
一个可解释的上下文至少分为六层:
- System:系统行为边界和安全规则。
- Task Contract:目标、范围、验收标准、预算和禁止事项。
- Stable Knowledge:项目规则、用户偏好、Skill 摘要。
- Working State:当前计划、已完成节点、待办和失败记录。
- Evidence:代码片段、Tool response、测试输出和外部来源。
- Control Events:Steer、Followup、Interrupt、审批决定。
每一层都应有优先级、来源、版本、Token 成本和注入理由。ContextBuilder 每次输出 manifest,记录哪些区块被注入、哪些被裁剪、哪些敏感字段被脱敏。没有 manifest,出现“模型为什么做了这个决定”时就无法排查。
3. 检索、排序与注入
检索不是把相似度最高的若干文本塞进去。实用流程是混合召回:关键词找精确实体,向量找语义相似内容,结构索引找当前文件、模块和任务依赖;然后根据新鲜度、可信来源、作用域和冲突关系重排。
注入前需要做三次判断:
- 相关吗:是否直接影响当前行动。
- 可信并且新鲜吗:来源、版本和时间是否可靠。
- 会不会冲突:与系统规则、任务合同或已验证事实是否矛盾。
同一条 Memory 在不同 Session 中的作用域可能不同。用户偏好、项目规则、临时决定和测试结果不能放在同一层,否则一个局部事实可能污染所有任务。
4. Memory 是可持续状态系统
Memory 不是简单向量库,而是跨 Turn、跨 Session 维护的状态系统。一个 Memory item 至少需要:
内容、类型、作用域、来源、置信度、创建时间、更新时间、版本、状态、冲突集
生命周期可以是:
candidate → active → stale/conflicted → deprecated → deleted
写入时先抽取候选,再进行去重、敏感信息检查和冲突检测;读取时根据任务作用域和新鲜度注入;更新时尽量局部更新,并保留版本和来源;删除时同时处理事实、摘要、索引、缓存和派生规则。
冲突解决不能只比较相似度。直接证据优先于推测,用户显式指令优先于旧偏好,更具体的作用域优先于全局规则;无法判定时保留冲突并请求确认。
5. Memory 的评估与自进化
Memory 评估至少看四类指标:召回是否合理,注入后是否帮助决策,冲突是否被发现,更新是否只影响应该影响的局部范围。还要检查溯源:系统能否回答“这条信息从哪里来、何时变成 active、被哪些任务使用过”。
Self-improvement 不能等同于自动把所有对话写入 Memory。可以采用 memory rule:只有满足来源可信、重复验证、作用域明确和隐私允许的候选才进入巩固队列。夜间潮汐任务负责去重、过期、敏感扫描和索引维护;Dreaming 过程从成功和失败轨迹中提取可复用经验,但必须离线评估后再发布。
6. Skill 是 Experience 的编排
Skill 不是一段更长的 Prompt,也不是必须绑定 Sandbox 的脚本。它是某类任务的经验编排,包含触发条件、所需输入、步骤、可用 Tool、失败处理、验证规则和退出条件。
Skill 的生命周期是:
管理 → 发现 → 加载 → 注入 → 执行 → 验证 → 卸载
渐进式披露意味着不要一开始把所有细节注入上下文:先给名称和适用范围,匹配后加载操作摘要,真正需要时才加载步骤、示例和脚本。
卸载尤其重要:清除本轮 Skill 指令和临时变量,解除 Tool 权限和挂载资源,保存必要的结果引用,避免下一轮误以为能力仍然可用。常驻型 Skill 和一次性 Skill 的卸载策略不同,不能只删除 Prompt 文本。
Skill 可以嵌套和参数化,但必须有边界声明,避免多个 Skill 同时修改同一文件或互相覆盖策略。可控性可以通过伪代码和 CodeAct 实现:模型提出意图,Skill 负责把意图约束成可验证步骤。
7. Context Compression 的正确目标
压缩前先定义不可丢失集合:目标和版本、用户约束、已验证事实、失败原因、外部副作用、未完成动作和证据引用。再按三级处理:
- L1:去重和折叠日志。
- L2:结构化摘要,固定 Schema。
- L3:外置大对象,使用可恢复引用。
PreTurn 负责预算检查,MidTurn 处理异常大的 Tool 返回,PostTurn 固化本轮摘要。压缩完成后让独立检查器比较压缩前后的关键字段,而不是只检查摘要长度。
8. KV Cache 与 Context 的关系
推理分为 Prefill 和 Decode。Prefill 读取输入并建立 KV Cache,Decode 逐 Token 生成输出。Agent 如果每轮都修改前缀,缓存命中率会下降;因此应把稳定的系统指令、项目规则和 Skill 摘要放在稳定前缀,把频繁变化的状态和工具结果放在后面。
缓存优化不能破坏语义。缓存键需要包含模型版本、系统指令版本、工具 Schema 和权限边界;Context 压缩后必须使旧缓存失效或重新计算,不能把旧状态误当新状态。
9. 学习者练习
做一个 Context Builder,输出 manifest;准备一组带冲突的 Memory、过期规则和超长 Tool response;比较“全量注入、相似度注入、分层注入”三种策略。再实现一个 Skill,测试加载、嵌套、失败和卸载,重点观察卸载后权限和上下文是否真的恢复干净。