context engineering 范式
B5 是整条 B1→B18 能力曲线从「会跑 eval」转向「会经营 agent 输入面」的拐点。
阶段: B5 · tool/context engineering + 指标树(Day 41-50) 标签: #context-engineering #token-budget #signal-to-noise #anthropic
今日导引(由浅入深)
B5 是整条 B1→B18 能力曲线从「会跑 eval」转向「会经营 agent 输入面」的拐点。
B4(Day 31-40)刚把「何时不用 agent」收敛成一张带 CI 的决策 gate——结论是:能简单就别复杂。今天起,对那些确实需要 agent 的场景,我们退一层问:既然 agent 要靠 context 工作,那 context 本身该怎么经营?
昨天度量的是「要不要 agent」,今天度量的是「agent 的输入里每个 token 值不值」。明天(Day 42)顺势把镜头对准 context 里最大的一块消费者——工具描述——拆解它的反模式。
今天的「最小可判定产出」是:用已绿的 tokenizer 把工具注册表逐工具编码计数,得到一份真实的 context-audit.md。
1. 机理精读
定义。 context engineering 把「喂给模型的全部输入」当作一个有限 token 预算来经营,而不是把 prompt 一次性塞满。
它的核心命题分两层:
- 第一,
context ≠ prompt——prompt 是人写的那段指令,context 是模型一次推理实际看到的全部 token(system + 工具声明 + 检索证据 + 对话历史 + 当前 prompt); - 第二,每个 token 都在稀释注意力,信号噪声比(signal-to-noise)直接决定 agent 的行为质量。
Anthropic《Effective context engineering for AI agents》(2025-09)把这套主张概括为「找最小的高信号 token 集」,而不是「填满上下文窗口」。
为什么这样设计。 长上下文窗口(200K、1M token)容易让人误以为「窗口大 = 可以多塞」。
但注意力是 softmax 归一化的:token 越多,单个关键 token 分到的注意力权重越被摊薄;且模型有经验性的「lost in the middle」——位于上下文中段的信息更易被忽略。于是「能放下」不等于「该放」。
context engineering 的设计动机就是把「放什么」变成一个显式预算决策,逼工程师对每一段输入问一句:它对当前这步决策的边际信号是正是负?
关键权衡:高信号 vs 完整性。 把所有可能相关的历史/文档都塞进去,看似更"安全",实则抬高了噪声底,反而让模型更易跑偏、更贵(token 即成本,见 Day 1 的 tokenizer→cost 链路)。
反过来过度裁剪又可能丢掉关键约束。所以 context engineering 不是「越少越好」的口号,而是「在给定预算下最大化信噪比」的优化问题——这与 Day 44 的 context-budget 表(四类配额 + 裁剪策略)是同一枚硬币的两面。
与相邻概念的边界。 它取代了早期 RAG-centric 的叙事——RAG 把问题框成「检索更多相关文档塞进 prompt」,而 context engineering 把检索只当作预算的一个消费项,与 system / tools / history 同级竞争同一份预算。
它也不同于单纯的 prompt engineering:后者优化「怎么措辞」,前者优化「整个输入面的构成与裁剪」。工具描述与对话历史是这份预算的主要消费者——这正是 Day 42(工具反模式)紧接今天的原因。
2. 推导 / 手算 / 代码走读
今天是代码日,走读 seed 引用的 src/agent/eval/tokenizer.ts(byte-level BPE,零依赖)与 src/agent/mcp/toolRegistry.ts。
trainBpe(corpus, numMerges) — 训练阶段:
- 在字节序列上贪心合并出现频次最高的相邻对,重复
numMerges次; - 并列时按最小 pair key 决胜以保证确定性(无随机、无时钟);
- 当最高频次
< 2(无重复对值得合并)时提前break; - 合并后的新 token id =
256 + rank(前 256 留给原始字节)。
encode(text, model) — 编码阶段:
- GPT-2 风格——反复找当前序列里rank 最低(最早学到)的可合并相邻对并合并;
- 直到无对可合(
bestRank === Infinity即 break); - 这保证编码顺序与训练学到的合并顺序一致。
decode(ids, model) — 解码阶段:
- 用
model.expand(id→[left,right])递归展开回字节,再TextDecoder还原字符串; - 是
encode的无损逆;这条无损往返是 tokenizer 单测的核心断言。
tokenReport(texts, model) — 今天要用的 harness:
- 对一组文本逐条
encode().length计 token; - 汇总
totalChars / totalTokens / meanCharsPerToken,返回每行{chars, tokens, charsPerToken}; - 把它喂给「每个工具的 description + inputSchema 序列化串」,即得逐工具 token 数。
src/agent/mcp/toolRegistry.ts 的 McpToolRegistry.list() — 工具来源:
- 返回按
name稳定排序的McpToolSpec[](每条含name / description / inputSchema); - 是 stateless 纯函数——遍历它就能拿到要计数的全部工具声明文本。
走读结论:今天不需要任何模型 key——tokenReport 是纯离线确定性函数,工具清单也来自进程内注册表。这正是「机制即代码,数字即报告」的离线可测产出。
逐工具审计的手算骨架(伪代码):
const model = trainBpe(corpus, 200) // 一次拟合,复用以便跨工具可比
const rows = registry.list().map(t => {
const descTok = encode(t.description, model).length
const schemaTok = encode(JSON.stringify(t.inputSchema), model).length
return { name: t.name, descTok, schemaTok, total: descTok + schemaTok }
})
const grandTotal = rows.reduce((s, r) => s + r.total, 0)
读法:grandTotal 就是「工具声明在 context 里的总占用」,是 Day 44 预算表里 tools 那一行的实测值;逐行 total 排序后,最大的几个工具就是 Day 42/45 重设计要优先瘦身的对象。注意若每工具单独 trainBpe 会导致计数跨工具不可比——所以这里一次拟合、全局复用。
3. 今日实战
- 打开
src/agent/mcp/toolRegistry.ts,确认要审计的工具来源是registry.list()输出的McpToolSpec[]。 - 写一段脚本(或在 vitest 里):遍历
list(),对每个工具把spec.description与JSON.stringify(spec.inputSchema)拼成一段文本。 - 用
src/agent/eval/tokenizer.ts的tokenReport()(先trainBpe出 BPE 模型,或复用已有 corpus 训练的模型)对这组文本编码计数。 - 把每工具的 token 数 + registry 总 token 占用累加,写入
agent-evals/context-audit.md:一张「工具名 | description token | schema token | 小计」的表 + 总和行。 - 由于 tokenizer 无需 key,整条管线离线可跑通;产出文件 commit。
4. 今日实测 / 产出
- tokenizer harness 本身已绿:measured 3536 chars → 1760 tokens,2.01 c/t(chars/token),vocab=456。
- 本日的「逐工具 token 清单 + 总和」为「待跑」——但离线即可(tokenizer 不需 key)。
- 产出
agent-evals/context-audit.md:每工具 token 数 + registry 总 token 占用。
(诚实状态:tokenizer 数字是真实测得的;逐工具清单尚未生成,标「待跑」,但无任何 key 阻塞,纯属待执行。)
5. 常见误区 / 陷阱
- 把窗口大小当预算:1M token 窗口不代表该塞 1M token;信噪比下降是连续的,不是到上限才出问题。
- 只数 prompt 不数 context:真正消费注意力的是 system + tools + 检索 + history 的总和,工具声明常被忽略却占大头(Day 44 会量化)。
- 用错 tokenizer 估 token:本仓 tokenizer 是教学用 byte-level BPE(2.01 c/t、vocab=456),与目标模型真实分词器不同;它用于相对比较与离线审计,不要拿它的绝对数当某商业模型的计费 token。
- 把 context engineering 等同于"少即是好":目标是信噪比最大化,过度裁剪丢约束同样有害。
6. 学习资源(每条带 YYYY-MM)
- Anthropic, Effective context engineering for AI agents(2025-09)——本日范式主线,提出「最小高信号 token 集」。
- Anthropic, Building Effective Agents(2024-12)——「能简单就别复杂」,context 经营的上位原则。
- Liu et al., Lost in the Middle: How Language Models Use Long Contexts(2023-07,TACL)——长上下文中段信息被忽略的经验证据,解释为何「放得下≠该放」。
- 本仓代码:
src/agent/eval/tokenizer.ts(byte-level BPE +tokenReport)、src/agent/mcp/toolRegistry.ts(list()工具发现)。
SOTA检查 (2026-06 更新)
- 当前主流方案:Anthropic context-engineering(2025-09)仍是 2026 的范式主线,持续被引;compaction(summarize)/ offload(外置到文件)/ prune(丢弃)三类裁剪策略为现行标准动作(Day 44 详述)。
- 是否仍 SOTA:是。2026 主流 agent 框架(如 Claude Agent SDK)已把 compaction 内建为默认能力。
- 过时黑名单(AVOID):纯 RAG-centric 叙事——「检索更多文档塞进 prompt」已被 context engineering 取代,检索降级为预算的一个消费项;不要再把「上下文越满越稳」当默认。
- 下次复查点:复查 Anthropic engineering blog 是否出 2026 版 context-engineering 更新;关注是否出现 KV-aware 的更细预算工具(与 Day 44 复查点联动)。
衔接
- 昨天:Day 40 — 何时不用 agent gate(B4 收口:带 CI 的多维 build-vs-buy 决策)。
- 今天:把 agent 的输入当有限 token 预算经营——信噪比决定行为质量,工具描述与历史是主要消费者。
- 明天:Day 42 — tool 设计反模式(把镜头对准 context 里最大的一块消费者:工具声明)。