news 2026/9/28 3:46:30

pi-coding-agent 上下文优化全景:从 Prompt 缓存到动态工具集的 10 个成本与质量优化点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pi-coding-agent 上下文优化全景:从 Prompt 缓存到动态工具集的 10 个成本与质量优化点
  • 人工智能
  • AI Agent
  • 代码智能体
  • Agent 编排
  • CLI
  • AI 应用

【免费下载链接】gsd-2

A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture

项目地址:https://gitcode.com/gh_mirrors/gs/gsd-2
点击查看免费下载

本篇技术指南基于 gsd-2 仓库中 pi-context-optimization-opportunities.md 这一"研究专用(Research only)"文档展开。它梳理了 pi 引擎(packages/pi-coding-agent与packages/pi-agent-core)在上下文工程层面的 10 个优化机会:Prompt 缓存、观测掩码、提前压缩阈值、工具结果截断、上下文文件去重、技能懒加载、Token 估算精度、Markdown 化改造、动态工具集以及分阶段成本归因。文中将文档的核心提案与当前仓库源码逐一对照,读者读完可以掌握这套上下文成本与质量优化清单的原理、落点位置与实施优先级。


文档定位:一份"未排期实施"的上下文工程研究清单

原文档开篇即标注了三个关键约束:

  • Status: Research only — not planned for implementation.(仅研究,未计划实施)
  • Scope: 影响packages/pi-coding-agent与packages/pi-agent-core的基础设施。
  • 受益面: 这些改动将惠及 pi 引擎的每一个消费方,而不仅仅是 GSD 本身。

这意味着本文讨论的所有优化点,应当被理解为审计清单与设计蓝图,而非已经落地的功能描述。文章后续章节会对照当前仓库快照,指出哪些机会点已具备部分基础设施(例如 Anthropic 协议路径上的cache_control),哪些仍是纯提案。


1. Prompt 缓存(cache_control)——最高杠杆率的机会

现状描述

文档指出:在理想状态下,每次 LLM 调用都会为系统提示词、工具定义和上下文文件重新支付完整的输入 Token 成本,因为 API 调用路径上没有设置任何cache_control断点。

机会分析

Anthropic 的 KV 缓存对缓存命中的 Token 提供 90% 的成本削减(0.1x 输入费率)。Claude Code 通过将稳定内容置于易变内容之前,达成了 92–98% 的缓存命中率。

文档给出了三个埋点位置(原指packages/pi-ai/src/providers/anthropic.ts协议路径):

  1. 在最后一个工具定义块上设置cache_control: { type: "ephemeral" };
  2. 在静态系统提示词部分之后(基础样板 + 上下文文件)设置cache_control;
  3. 让每轮的用户消息保持不缓存(作为易变后缀)。

关键约束:断点必须位于"最后一块静态内容"之后

缓存断点必须放置在所有静态内容之后、任何动态内容(时间戳、按请求变化的变量)之前。把一个时间戳移到缓存断点之前,会让缓存每次调用都失效。

缓存层级关系为:tools → system → messages。任何工具定义的变更都会使 system 与 messages 的缓存失效,因此工具定义应当按字母序确定性排序,避免无谓的缓存抖动。

当前仓库对照

从当前仓库快照看,Anthropic 协议路径已经具备一套完整的缓存控制基础设施,集中在 anthropic-shared.ts:

  • getCacheControl():解析缓存保留策略,默认short,兼容PI_CACHE_RETENTION=long环境变量;直连api.anthropic.com且为 long 时附加ttl: "1h";
  • convertTools():把cache_control打到最后一个工具上,覆盖整个工具块;
  • convertMessages():在最后一条用户消息与最近的压缩边界消息上各应用一次断点,并刻意控制在 Anthropic 4 个断点的上限内(system + tools + boundary + last user = 4,参见 PR #5027 注释);
  • buildParams():对 system prompt 块附加cache_control,OAuth 模式下仅让最后一个 system 块携带断点以避免浪费断点槽位。

此外仓库还配套了专门的断点测试 anthropic-shared.cache-breakpoint.test.ts。因此可以说:文档提出的"埋点位置"在当前代码中已部分落地(工具末块、system、压缩边界、末条消息),文档的价值更多体现在审计这些断点是否被动态内容破坏、以及工具排序是否确定性足够强。

预期收益

多轮会话中(GSD auto-mode 的主要成本形态),输入 Token 成本可降低 80–90%。


2. 消息管线中的观测掩码(Observation Masking)

现状描述

文档指出:agent-loop.ts在每一轮都把完整的context.messages数组传给 LLM。50 轮之前的工具结果在之后的每一次调用中都被完整重读。AgentContext上的transformContext钩子虽然存在且在每次 LLM 调用前触发,但没有默认实现——是否做裁剪完全由扩展自行负责。

当前仓库对照

transformContext在当前仓库中确实存在且接入了扩展运行时。在 sdk.ts 中可以看到:

transformContext: async (messages) => { const runner = extensionRunnerRef.current; if (!runner) return messages; return runner.emitContext(messages); },

即默认行为是"原样返回消息",只有当扩展注册了emitContext处理器时才会被改写——与文档描述完全一致:没有默认实现,扩展全权负责裁剪。

机会与数据

JetBrains Research 在 SWE-bench Verified(500 个任务,最长 250 轮轨迹)上的测试表明:

  • 相比未管理的历史,成本降低 50% 以上;
  • 性能与 LLM 摘要持平或略有超出;
  • 零额外开销(不需要额外的 LLM 调用)。

提议的默认实现

文档给出了一份可在pi-agent-core落地的默认transformContext实现:

// Keep last KEEP_RECENT_TURNS verbatim; mask older tool results const KEEP_RECENT_TURNS = 8; function defaultObservationMask(messages: AgentMessage[]): AgentMessage[] { const cutoff = findTurnBoundary(messages, KEEP_RECENT_TURNS); return messages.map((m, i) => { if (i >= cutoff) return m; if (m.type === "toolResult" || m.type === "bashExecution") { return { ...m, content: "[result masked — within summarized history]", excludeFromContext: false }; } return m; }); }

实现要点:

  • 保留最近KEEP_RECENT_TURNS(8 轮)的完整内容,只掩码更早的toolResult/bashExecution;
  • 用轻量占位符替换旧工具结果正文;
  • 掩码发生在 LLM 调用之前,不改写消息存储本身。

仓库中与excludeFromContext相关的机制可作参照:bashExecution消息已经支持excludeFromContext标记(!!前缀),在 agent-session.ts 与 convertToLlm() 中都会被过滤,说明消息级"对 LLM 隐身"的通道早已存在,观测掩码可以复用这套字段与语义。

与压缩的互补关系

观测掩码降低了 Token 的累积速率,从而推迟压缩阈值被触达。二者是互补的:掩码负责稳态,压缩负责罕见的超深会话。


3. 更早的压缩阈值(Earlier Compaction Threshold)

现状:基于固定保留 Token 的触发逻辑

当前常量定义在 constants.ts:

export const COMPACTION_RESERVE_TOKENS = 16_384; export const COMPACTION_KEEP_RECENT_TOKENS = 20_000; export const TOOL_RESULT_MAX_CHARS = 2_000;

按文档计算:对于 200K 上下文窗口,压缩在约 183K Token 处触发——91.5% 的利用率。保留空间COMPACTION_RESERVE_TOKENS = 16_384只是为"本次提示 + 本次响应"预留的余量。

问题:上下文漂移比耗尽更致命

文档引用的两个数据点:

  • 上下文漂移(Context drift,而非原始耗尽)导致约 65% 的企业 Agent 失败;
  • 根据 Zylos 的生产数据,超过约 30K Token 后性能开始可测地退化。

当前阈值意味着会话在压缩触发之前,会先在一个已经劣化的状态下运行很长一段距离。

提议:把触发点降到 70% 利用率

// Proposed COMPACTION_THRESHOLD_PERCENT = 0.70 // fire at 70% of contextWindow COMPACTION_RESERVE_TOKENS = contextWindow * (1 - COMPACTION_THRESHOLD_PERCENT)

对 200K 窗口:约在 140K Token 处压缩,比现状提前 43K Token。

权衡

  • 压缩更频繁,但每次发生时上下文里"新鲜内容"更多;
  • 摘要质量提升,因为每次切割需要丢弃的材料更少;
  • 仓库测试 compaction-threshold.test.ts 表明阈值是高度可参数化、可单测的行为,改动风险可控。

4. 工具结果在写入时截断(Tool Result Truncation at Write Time)

现状问题

TOOL_RESULT_MAX_CHARS = 2_000(constants.ts)只在压缩摘要期间生效,而不是在工具结果进入消息存储时生效。一个返回 50KB 日志输出的 bash 结果会被原样存储,并在压缩触发之前逐字逐句地反复重发。

从源码看,消息渲染层已经存在"输出被截断 + 指向完整输出文件"的模式:在 messages.ts 中可以看到[Output truncated. Full output: ${msg.fullOutputPath}]。也就是说,截断体验的基础设施(fullOutputPath 回链)已有雏形,缺的是在写入消息存储的那一刻就执行截断。

两种截断策略

策略做法适用
硬截断(Hard truncation)按 N 字符切片,追加"\n[truncated — {original_length} chars]"简单、零开销
语义头尾(Semantic head/tail)保留前 500 字符(上下文、命令回显)+ 最后 1000 字符(最终输出、错误)对 bash 结果更友好,因为错误通常在结尾

推荐方案

以语义头尾为默认策略,并按工具类型可配置:文件读取类结果受益于"头";bash/测试输出受益于"头 + 尾"。落点建议在 messages.ts 的convertToLlm()或工具结果处理器中。


5. 上下文文件去重与裁剪

现状:按路径去重,不按内容去重

loadProjectContextFiles()的实现位于 resource-loader.ts,核心行为:

  • 搜索顺序为:~/.gsd/agent/(agent 目录)→ 逐级向上遍历祖先目录 → cwd;
  • 候选文件名是AGENTS.md与CLAUDE.md(loadContextFileFromDir);
  • 去重基于seenPaths(文件路径 Set),不比较内容;
  • 整个文件内容被逐字拼接到系统提示词中,不做裁剪、不做摘要。

反模式示例

文档给出的反模式:如果项目在三个祖先层级(仓库根、工作区、家目录)各有AGENTS.md,三层全部注入;若它们共享通用样板内容,该内容就被重复注入多次。

三个优化方向

  1. 内容级去重:对段落级块做哈希,跳过任何在前面文件里已见过的块;
  2. 按章节感知加载:解析AGENTS.md中的##标题,只包含与当前任务类型相关的章节(例如只在运行测试时注入## Testing章节);
  3. Token 预算强制:若全部上下文文件超过 N Token,则对最旧/最远的文件做摘要而不是逐字注入。

仓库已在其他资源(prompts、themes)上实现了按名称去重的dedupeResources(resource-loader.ts),说明"去重"是工程团队认可的模式,只是尚未下沉到AGENTS.md的内容层面。


6. 技能(Skill)内容的懒加载与摘要

现状

当/skill:name被调用时,完整技能文件内容会被以内联<skill>...</skill>形式注入到用户消息中(参考 skills.ts 的formatSkillsForPrompt,技能清单确实以<available_skills>+<skill>XML 包裹)。没有分块、没有摘要。一个 10KB 的技能文件,在那一轮就增加约 2,500 Token。

三个机会

  1. 技能注入缓存:如果同一个技能在多个轮次中使用(少见但可能),每次都重新注入。可以在首次注入后用cache_control缓存;
  2. 技能摘要模式:首次引用时只注入 200 Token 的摘要;仅当模型通过get_skill_detail工具调用请求时才注入完整内容。对最终未被遵循的技能可显著降本;
  3. 技能预取:在已知的长会话开始前(例如 auto-mode 启动时),预先注入所有可能用到的技能并打上cache_control,使整个会话期间技能内容都命中缓存。

7. Token 估算精度

现状:chars / 4启发式

当前估算逻辑位于压缩管线(compaction.ts,以及 compaction/utils.ts 等),核心公式为Math.ceil(chars / 4)。

文档指出该启发式的两个系统性偏差:

  • 对英文散文高估(实际约 3.5 字符/Token);
  • 对短标识符代码或 Unicode 内容低估。

机会:引入真正的分词器

  • @anthropic-ai/tokenizer(tiktoken 兼容,随 SDK 分发):准确,但单次调用约 5ms;
  • 分层策略:展示用chars/4,只有在需要做压缩阈值决策的地方(准确率关键)才使用真正的分词器。

收益

更精确的压缩触发时机、更少的无谓压缩、COMPACTION_KEEP_RECENT_TOKENS边界放置更准确。


8. 格式:内部上下文用 Markdown 替代 XML

现状

消息管线在多处使用<skill>、<summary>、<compaction>等 XML 包裹(前述 skills.ts 即为实例),而系统提示词各章节大都是散文式 Markdown。

调研结论

  • XML 成对的开闭标签让同等语义内容多消耗15–40%的 Token;
  • 但 Claude 针对 XML 做过优化,在需要精确段落解析的任务上准确率更高。

建议的转换原则

转换到 Markdown 的场景:

  • 内容非嵌套(扁平指令、状态消息);
  • 面向人类可读而非被模型机器解析;
  • 不需要精确的边界检测。

保留 XML 的场景:

  • 边界模糊的 few-shot 示例;
  • 技能内容(需要与周围文本精确隔离);
  • 压缩摘要(模型必须将其视为权威历史)。

预估收益

系统提示词 Token 数降低5–15%。


9. 动态工具集交付(Dynamic Tool Set Delivery)

现状

所有工具定义都出现在每一次 LLM 请求中。在静态配置下,工具描述消耗输入 Token 的 60–80%;随着新扩展注册工具,基线线性增长。这解释了为何工具定义排序(见第 1 节)如此关键——任何工具变更都会波及 system 与 messages 缓存。

机会:三函数动态工具集模式

  1. search_tools(query)— 对工具目录做语义搜索;
  2. describe_tools(ids[])— 按需拉取完整 schema;
  3. execute_tool(id, params)— 执行保持不变。

文档引用 Speakeasy 的测量:Token 削减 91–97%,任务成功率 100%。代价是工具调用次数增加 2–3 倍、墙钟时间延长约 50%,但净成本显著下降。

对 pi 的可行性评估

文档认为工程主体在于语义搜索索引与describe_tools/search_tools两个工具的实现——前提是工具注册表已经把工具元数据与定义分离存储。需要注意:文档所引用的packages/pi-coding-agent/src/core/tool-registry.ts路径在当前仓库快照中未被确认到,建议以仓库实际结构为准核对(工具/命令的注册与冲突检测可见 resource-loader.ts 的detectExtensionConflicts实现)。


10. 成本归因与分阶段报告(Cost Attribution)

现状

SessionManager.getUsageTotals()(session-manager.ts)在整个会话层面累计成本,不保存任何分阶段或分 Agent 的细分。成本可见性仅限于 footer 总数与GSD_SHOW_TOKEN_COST=1的逐轮展示。

机会:结构化的成本检查点事件

interface CostCheckpointEvent { type: "cost_checkpoint"; label: string; // "discuss-phase", "execute-slice-3" deltaTokens: Usage; // tokens since last checkpoint cumulativeTokens: Usage; cumulativeCost: number; }

消费场景

GSD 扩展可以订阅这些事件,在/gsd stats中呈现每个里程碑的成本,并标记成本异常偏高的里程碑——从而实现预算感知的规划(budget-aware planning)。


实施优先级总览

文档末尾给出了如追求实施时的完整排序表:

优先级项目工作量预期影响
1Prompt 缓存(cache_control)低输入成本降低 80–90%
2提前压缩阈值(70%)极低降低长会话中的漂移
3工具结果写入时截断低压缩间隙之间的上下文膨胀更小
4上下文文件去重中不固定——多级 AGENTS.md 场景收益高
5观测掩码(默认transformContext)中长期运行的 Agent 成本降低 50%+
6Token 估算(真正分词器)低精度提升,成本影响较小
7Markdown 替代 XML 审计低系统提示词降低 5–15%
8技能cache_control缓存低技能密集型会话收益明显
9动态工具集交付高大型工具目录降低 90%+;重大架构变更
10分阶段成本归因事件中仅提升可见性;为未来预算路由铺路

不难看出一个清晰的模式:前三个项目都是低工作量、高收益的"立即可做"项,而动态工具集与成本归因属于中期架构级投入。结合第 1 节我们已验证的现状,cache_control基础设施在 Anthropic 协议路径上已经就位,接下来真正值得投入的是把断点纪律(静态内容在前、工具确定性排序)固化成可测试的约束,并推动 70% 压缩阈值与写入时截断这两个低成本的稳态优化。


延伸阅读

  • 完整原始研究文档:pi-context-optimization-opportunities.md
  • 压缩与保留相关常量:constants.ts
  • Anthropic 协议缓存控制实现与测试:anthropic-shared.ts / anthropic-shared.cache-breakpoint.test.ts
  • 消息存储与 LLM 转换:messages.ts
  • 上下文文件加载与去重:resource-loader.ts
  • 压缩触发与 Token 估算:compaction.ts
  • transformContext扩展钩子接线:sdk.ts
  • 会话成本累计:session-manager.ts

说明:本文所引文档标注为 Research only,所有"预期收益/降低百分比"均为文档引用或基于其调研来源的表述;当前仓库的实际行为以源码与测试为准,实施前建议按仓库最新代码重新核算。

  • 人工智能
  • AI Agent
  • 代码智能体
  • Agent 编排
  • CLI
  • AI 应用

【免费下载链接】gsd-2

A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture

项目地址:https://gitcode.com/gh_mirrors/gs/gsd-2
点击查看免费下载

相关推荐

上一篇:Mermaid Live Editor 免费在线图表编辑器完整指南:改图为什么能像改文档
下一篇:Czkawka:免费开源的磁盘清理工具,一次扫描找出重复文件、相似图片和空文件夹

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 3:44:36

把 AI 讲给人听,比把 AI 跑通更难:一位工程师的 AI 通识复盘

本文作者反思了技术人讲AI时的困境&#xff1a;懂原理不等于能讲清楚。通过清华大学《人工智能故事书》的启发&#xff0c;提出用16个类比&#xff08;如“外国人学汉字”“迷雾下山”&#xff09;将复杂模型转化为可理解的直觉锚点&#xff0c;辅以提示词工程背后的“需求工程…

作者头像 李华
网站建设 2026/9/28 3:35:50

RK3588部署YOLOv8实战:从PyTorch到C++推理全流程指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 3:31:14

剪映操作|人物发丝抠不干净怎么办

适用对象&#xff1a;图片与素材处理任务的创作者。本文只处理“人物发丝抠不干净怎么办&#xff1f;”这一件事。先确定这一条要解决什么最稳的做法是&#xff1a;处理“人物发丝抠不干净怎么办&#xff1f;”&#xff0c;先保留原图/原片&#xff0c;用一张或一小段做样&…

作者头像 李华