模式矩阵 /模式白皮书/P1
P1 · Context Triage · 上下文分诊
| 字段 | 值 |
|---|---|
| 双轴坐标 | 感知 Perception × 路由 Route(选) |
| 成本档 | ②(一次轻量优先级判断,不额外起推理链) |
| 课程对应 | 02-02 |
| 目录归属 | 全集 33 模式之一 · 感知模块 4 模式之一 |
| 一句话 | 候选信息总量超出 context 窗口预算时,决定谁先进、谁等门外、谁压根不预加载。 |
它解决什么问题
生产级 Agent 的常态不是信息不够,而是信息太多。一个中等 codebase 加三周 git 历史扔进去就是 180K token 起步,企业知识库更是远超任何窗口。当候选信息装不下,最朴素的截断(按文件名排序砍后半段)会留下过期材料、丢掉关键证据,Agent 看着"完整一套"给出错误结论。
上下文分诊把这件事工程化:把所有候选信息分成 P0/P1/P2/P3 四级,从高到低塞,塞到 token 预算耗尽。它管的是单次请求的窗口分配,目标不是"喂给 Agent 完整信息",而是"保证最关键的信息不被淹没"。这两个目标听起来接近,工程做出来差很多。
为什么坐标是「感知 × 路由」
- 纵轴 · 感知:分诊决定 Agent 看什么、不看什么,是感知端的注意力管理。它处理的是信息进入推理之前的环节,不是输出格式的调整,也不是跨会话的记忆。
- 横轴 · 路由:不同优先级的信息走不同处理路径——高优进 context、中优压成摘要、低优只挂句柄等按需拉取。这是基于信息特征做的一次路由决策,不是链式串联也不是循环迭代。
核心机制
一次分诊把候选信息按优先级分层,再用 token 预算切一刀:
| 级别 | 典型内容 | 加载策略 |
|---|---|---|
| P0 永远加载 | system prompt、安全规则、当前任务、业务身份(tenant_id) | 占预算 5-10%,超预算也进 |
| P1 有空间就加载 | 当前文件、最近 tool 结果、错误堆栈 | 占预算 20-30% |
| P2 压缩后加载 | 历史对话、背景文档 | 压成摘要,占 10-20% |
| P3 只挂句柄 | 可访问但不预加载的资源 | 0 预算,通过工具按需拉 |
三个工程要点决定分诊的成败。第一,优先级判定的来源有两条路:人工分诊(如 Claude Code 的五级 CLAUDE.md hierarchy,开发者本人把安全规则放 P0、个人偏好放 P2)和算法分诊(如 Aider 的 RepoMap 用 tree-sitter 抽符号、按图算法打分)。第二,错误堆栈受特殊保护,永远不被分诊掉——它是 Agent 的反馈回路,丢了 Agent 会反复犯同一个错。第三,每次分诊决策必须落 trace,否则线上无法判断关键文件是被分诊扔了还是压根没发现。
适合的生产场景
- 多租户 SaaS 客服 Agent:一个 Agent 服务上百家租户,每家知识库 30 万 token 量级,合计远超窗口。tenant_id 必须做成 P0 硬约束,其余知识按四级分诊。
- 面对陌生 codebase 的代码 Agent:用户每次给一个不同仓库,无法要求每人都写 CLAUDE.md,必须走算法自动符号抽取这条路。
- 长期服务同一团队的工程 Agent:投资人工写 200 行 CLAUDE.md 换分诊准确度,效率比算法路线更高。
- 接入文件系统、知识库或会跑超过 5 轮的任何 Agent:一旦信息有可能超窗,分诊就不可避免。
容易出错的地方
- 优先级误判:把一个文件标成 P3,结果它正是 bug 的关键,Agent 推到一半得额外跑一次检索循环把它拉回来,多烧 5K-10K token 还增加级联错误风险。拿不准就升级,多带一份小文件比多跑一次循环便宜。
- 分诊过激:为省 token 把 budget 卡得太死,关键依赖链全被挂起,Agent 反复"我需要再读一下这个文件",重读率(re-read ratio)飙升——你以为在省 token,实际在烧 token。
- P3 句柄命名含混:
doc://manual-page-3这种名字让 Agent 不知道该不该取。句柄名要自带"是什么"信号,走"层级 + 主题 + 时间"三段式。 - 跨租户串数据:P3 句柄取错租户的数据塞进 context 就是数据泄露事件。带租户前缀的资源在加载时必须强制校验与 P0 tenant_id 一致。
- trace 被采样掉:用 1% 采样控制存储看不出"某租户一直跨租户串数据"。分诊 trace 走全量结构化日志,用计数而非采样控制存储。
关键指标
- 重读率 re-read ratio(健康区 < 5%):Agent 推理中途要求重读已挂起文件的比例。超过 10% 是分诊过激的明确信号,每次重读都是一次完整推理循环。
- dropped_count 的 p99(关注长尾而非均值):均值掩盖问题,p99 能暴露"1% 的请求触发分诊雪崩、Agent 几乎啥都看不见"的长尾故障。
- P3 命中率 p3_hit_rate(健康区 10-30%):P3 句柄中实际被取的比例。低于 5% 说明句柄挂太宽浪费 token;高于 50% 说明该升 P2 的东西被错降到 P3。
最小骨架
对候选信息按优先级排序(P0 > P1 > P2 > P3,错误堆栈额外加分):
逐条塞入:
P3 → 进句柄池,不预加载
其余 + 未超预算 → 进 context,累加 token
其余 + 超预算 → 丢弃(但错误堆栈强制保留)
返回 (进 context 的, 挂句柄的, 一条 TriageDecision)
TriageDecision 留下:时间戳 / 预算 / selected / deferred / dropped / tokens_used
工程落地三处必改:token 估算换成真 tokenizer(len // 4 对中文误差大);错误识别要按领域补关键词;TriageDecision 必须落到 ELK 或 Datadog,每天看 dropped_count 趋势。
企业落地一例
一家区域银行的贷款评审 Agent,标准消费贷(8 份文档)跑得很准。直到一笔商业贷款申请堆进 43 份文档,context 装不下,Agent 按文件名排序做了一刀朴素截断,砍掉的那摞里有 2024 年的抵押物估值报告,留下的那摞里有一份 2019 年早已过期的工商登记拍照件。Agent 看着剩下的"完整一套"给出"建议批准",两周后这笔贷款进入坏账。重写后改为四级分诊:抵押物估值、当前财报这类强证据进 P0/P1,历史登记件按时间衰减降级,并强制保护所有"异常/缺失"标记不被丢弃。问题的根因不是推理不够强,是没教 Agent 谁该先进门。
与其他模式的关系
- 语义压缩(P2):互补且常配合。分诊管"哪些信息进 context"(未来 token),压缩管"已经进的怎么压不丢关键"(过去 token),P2 级"压缩后加载"正是两者的衔接点。
- 渐进发现(P3):天然耦合。分诊的 P3 句柄就是渐进发现按需拉取的对象,一个被动选、一个主动找。
- 分层记忆(Memory 模块):共用同一套句柄命名规范,但 TTL 不同。代码、文档类句柄永远指向当前版本归分诊管;用户偏好、对话状态类有版本演化归记忆管。建议把 P3 句柄分
immutable://和versioned://两类标记。
一句话记住它
上下文分诊不是 prompt 调优,而是操作系统进程调度在 LLM 时代的回响——context window 是稀缺的 CPU 时间,分诊算法就是那个保证最重要的进程不被饿死的调度器。
本页属于 ADPS 33 模式白皮书。返回 模式矩阵与白皮书目录, 或查看配套 可运行代码目录。