omp 会话 Token 效率审计:读懂 audit-prompt.md 的判定标准与落地实现
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
本文以 omp 项目(⌥ Coding agent with the IDE wired in)中 audit-prompt.md 为核心,解析这套用于指导 LLM 对 Agent 会话进行 Token 消耗审计的分类器系统提示词:它定义了会话卫生(session hygiene)、子代理(subagent/spawn)质量、浪费来源(waste sources)三大判定维度,并配合 audit.ts 的扫描与分类管线工作。读完本文,你将掌握 omp 审计工具的完整判定口径、digest 数据格式的每个字段含义,以及如何从一份会话摘要中量化定位 token 浪费并提出可落地的修复建议。
背景:为什么需要一份"审计分类器"提示词
omp 是终端编码 Agent,其每次会话都是一段与主 Agent 的连续对话。与一次性 API 调用不同,Agent 会话的上下文是只追加的:每个工具结果、用户消息、助手消息都会留在上下文中,并在后续每一次请求中重新发送(缓存前缀按输入价格约 10% 作为cache-read重新计费)。
这意味着"一条很大的工具结果出现在长会话早期"的实际成本远高于它自身的大小——它会随之后的每个请求被反复计费。为了把这种隐形成本显性化,omp 在 scripts/session-stats/ 目录下维护了一套会话统计与审计工具链:
- sync.py:增量解析
~/.omp/agent/sessions/下的会话 JSONL,灌入 SQLite 的ss_*表; - analyze.py:提供
tools | edits | followups等子命令做常规统计分析; - audit.ts:独立的两阶段审计脚本——阶段一扫描(无需 LLM)汇总真实用量,阶段二把最贵会话压缩成 digest 交给小模型评判;
- audit-prompt.md:阶段二分类器所使用系统提示词,即本文主体。
正如 README.md 所述,audit 的扫描阶段读取每条 assistant 消息中记录的真实per-request usage(input/output/cacheRead/cacheWrite + nominal cost),而不是重新做 tokenization;随后默认以anthropic/claude-sonnet-4-6(经由@oh-my-pi/pi-ai,凭据来自 omp 的 auth 存储)对开销最大的会话进行结构化评判。
提示词角色设定:只能通过工具返回结构化结果
audit-prompt.md将分类器定位为omp 的 token 效率审计员(token-efficiency auditor):
- 输入是单条会话记录的 digest,或多条会话判定结果的聚合(以
# AGGREGATE开头); - 输出必须通过调用
respond工具返回结构化分析,禁止输出普通文本。
这条约束在实现层面被严格执行。在 audit.ts 的completeStructured中(约 L1018-L1064),分类器调用被注入一个名为respond的工具:
const respond: Tool = { name: "respond", description: "Return your analysis by calling this tool with the requested structured fields.", parameters: schema as Tool["parameters"], strict: false, };并以toolChoice: { type: "tool", name: "respond" }强制模型走工具调用路径,返回后通过 JSON Schema(SESSION_SCHEMA,audit.ts)做字段校验,失败会带退避重试最多 3 次。headline被单独校验为非空单句——"空 headline 的响应无效,将被重试"。
核心认知一:omp 会话的 Token 是怎么花掉的
提示词第一部分给审计员建立了成本模型,这是所有判定的理论基础:
| 机制 | 含义 | 成本影响 |
|---|---|---|
| 上下文只追加 | 所有消息保留并在每次后续请求重新发送 | 早期的大结果被反复计费(cache-read 约 10% 输入价) |
residency指标 | 结果 token 数 × 后续请求数 | 近似度量"结果在上下文中驻留"的累计成本 |
task子代理 | 隔离上下文,只把最终报告合并回主上下文 | 是探索/批量编辑的省钱手段,中间工具流量不进入主上下文 |
compaction | 上下文超限后被总结压缩 | 会话过长/积累膨胀的强信号 |
/handoff | 总结后在新会话继续 | 换主题时避免旧主题上下文拖累新请求 |
其中residency的精确语义在 audit.ts 中实现:对每条工具结果记录requestIndex,扫描结束后按resultToks × max(0, requestCount - requestIndex)累加到对应工具的residency;对read工具还会按归一化路径(normalizeReadPath剥离:50-200、:raw等选择器)单独累计 per-path residency。该逻辑被 audit.test.ts 的合成会话测试精确验证:请求 1 落地的 100 token 结果被 2 个后续请求重新计费,residency 恰为 200。
subagent 何时是浪费(提示词给出的三条判据):
- 子代理重复发现父上下文已有的信息——任务提示词太薄,子代理把 token 烧在重新探索上;
- 工作量小到可以直接内联完成——spawn 开销(系统提示词 + 探索)超过了节省;
- 子代理失败/报错,父代理被迫重做。
核心认知二:digest 格式的每个字段意味着什么
提示词要求审计员正确解读 digest,并特意纠正了几个常见误判:
~标记的 token 数是估算值(chars/4);而billed-in、out、cost是 API 记录的真实数字;cache-read N%是输入中缓存命中的占比——长会话中低占比意味着缓存抖动(模型切换、分支编辑、并行分支),成本高;Turn flow逐条列出用户消息及其触发的工作;[synthetic/steering]表示系统注入而非用户键入;Repeated reads列出同一上下文中被读 ≥3 次的文件,每行带实测值:<path> ×N (~Xtok total, ~Y residency)——必须直接引用这些数字,不得自行推导重复读的 residency;ended: (no final text; last tool: X)不是失败——很多子代理通过 task 结果通道交付报告,从不输出结尾散文;判定失败要看[ERRORED]标志、(no output)或合并结果无用;merged result ~N是任务报告当前在主上下文中的样子;[Output truncated - N tokens]说明结果稍后被从上下文剪除——这是上下文节省特性在正常工作,不是数据丢失。
有趣的是,被剪除的结果大小在扫描期就能精确恢复:scanFile用正则TRUNCATED_RESULT_RE = /\[Output truncated - (\d+) tokens?\]/解析占位符,取占位符数字与文本估算的较大者([audit.ts](https://link.gitcode.com/i/d4ef01d09861dd309572368ecc438b2b#L241-L243, L474-L477))。测试中一个被剪为占位符的 task 结果因此精确恢复为 1993 token。
digest 的生成逻辑集中在buildDigest(audit.ts):依次输出会话元信息(模型、墙钟时长、主上下文总量、context peak、compactions、子代理开销占比)、前 40 个回合的 turn flow、主上下文工具流量 Top14、重复读 Top8、最大单次结果 Top8、编辑失败数与 spawn 详情,并控制总长不超过 26k token。
判定一:会话卫生(Session Hygiene)
审计员需要为每个会话输出 6 个字段:score、multiTopic、topics、shouldHaveSplit、handoffOpportunities。
判定口径:
- 主题切分:一个任务的顺序阶段(实现 → 测试 → 文档)算一个主题;但在功能会话里插入无关的 bugfix 就是第二个主题;
shouldHaveSplit必须保守:只有拆分/handoff 真的可能省钱时才置 true——例如主题 B 开始时上下文已持有主题 A 的 100k+ token;handoffOpportunities要点名具体回合:如"T7: new topic 'fix CI' while 180k of refactor context was loaded — fresh session would have started at ~10k";- 评分只针对 token 效率(不是任务成败):8–10 分是精简、委派得当的会话;4–7 分有明显浪费;0–3 分是重度浪费(多次 compaction、反复出现巨型结果、冗余重读、空转 spawn)。
判定二:子代理质量(Spawn Quality)
对每个值得评判的 spawn 组(跳过琐碎的,上限 10 个),给出五分类判定:
| 判定 | 含义 | 典型证据 |
|---|---|---|
good | 有意义的工作隔离在主上下文之外,提示词合理、报告有用 | — |
unnecessary | 工作小到可内联;spawn 开销超过节省 | — |
wrong-granularity | 应更多/更少并行,或应串行(子代理互相重复发现) | — |
context-transfer-failure | 任务提示词太薄,子代理明显重新探索父代理已知内容 | 子代理探索开销大、prompt 不足 ~1k token、子代理在问父代理已答过的问题 |
failed | 子代理报错/死亡/产出无用,父代理照样买单 | [ERRORED]、(no output) |
spawn 与子代理转录的关联实现在 digest 构建中:按baseLabel(剥离-2/-3重试后缀)把子代理文件分组匹配到task调用,未匹配的归入 "Other subagent runs"(如 eval agent()/irc 等非 task 通道)。endedStr按"最后有文本 → 最后工具调用 → 无输出"三档描述子代理结局(audit.ts)。
判定三:浪费来源(Waste Sources)
waste数组要求按量从大到小列出最具体的 token 沉没点,每项带source、estTokens、estUsd、fix,且必须锚定 digest 中的具体证据:
- residency 重的工具:结果在上下文中驻留过久;
- 重复读:同一文件反复整读;
- 巨型单次结果:整文件读取本可用范围读取替代、未过滤的测试输出;
- 编辑重试抖动:edit 失败后反复重试;
- 低 cache-read 占比:缓存抖动;
- synthetic 自动续写循环:系统注入的自动回合空转;
- 模型选择:机械性工作用了昂贵模型。
两个关键约束:
estTokens与estUsd必须互相一致;- 必须区分 residency token 与 billed token:residency 会在每次后续请求以约 10% 输入价(cache-read)被重新支付,因此基于 residency 推导的金额必须打折,绝不能按全价输入 token 计价。
最后一条硬性要求:"No generic advice ('use tools efficiently')",每条论断必须能追溯到 digest 的一行,引用回合号、文件路径、spawn 标签与 token 数字。
实现侧,normalizeVerdict会对模型返回的 verdict 做字段钳制与排序——waste 按美元降序、token 降序打破平局(audit.ts),保证渲染层永远不会碰到undefined。
聚合模式:从单会话判定到系统性发现
当输入以# AGGREGATE开头时,per-session 判定会以"每行一个紧凑 JSON"的形式(Per-session data (JSON, one per line):)提供给审计员,此时要求输出:
systemicIssues:跨会话反复出现的模式(issue + evidence + fix),而非一次性偶发;quickWins:按节省金额排序的一行式习惯改变;summary:2–4 句、直接面向用户的总结。
聚合阶段还有两条专门的反错误指引:
- 只能引用数据中实际存在的会话与数字,会话以其 title 称呼;
- 严禁把主上下文的回合误记为子代理开销——提示词明确记录了一次先例失败:一个 160 次请求的主上下文调试阶段曾被误报为"失控子代理"。
聚合请求的组装在 audit.ts:当 verdicts ≥ 2 时,把所有带判定的会话压成 JSON 行(含 id、title、costUsd、subagentPct、requests、contextPeak、compactions、score、headline、topics、shouldHaveSplit、spawnIssues、waste),再追加一条指令"Produce the cross-session aggregate…",用AGGREGATE_SCHEMA校验输出。
与工具链的协同:缓存、CLI 与测试
verdict 缓存:提示词变更自动失效
判定结果缓存在~/.omp/stats-audit-cache.json,缓存键由groupId + digest hash + model + SYSTEM_PROMPT hash组成(audit.ts),因此任何对audit-prompt.md的修改都会自动使旧缓存失效,无需手动清理;缓存只保留最新的 500 条。
CLI 用法
bun run stats:audit # 近一周,扫描 + LLM 分析 bun run stats:audit -- --no-llm # 仅扫描报告 bun run stats:audit -- --since 3d --folder Projects-pi bun run stats:audit -- --min-cost 5 --max-llm 8 --json /tmp/audit.json bun run stats:audit -- --digest-dir /tmp/digests # 导出喂给分类器的 digest bun run stats:audit -- --session parser # 按 id/标题分类(忽略 --min-cost) bun run stats:audit -- --no-cache # 强制全新 LLM 判定关键参数:--since <12h|3d|1w|1mo>(默认 1w)、--folder/--exclude、--model <prov/id>(默认anthropic/claude-sonnet-4-6)、--max-llm(默认 12)、--min-cost(默认 $1)、--concurrency(默认 4)。
测试保障
audit.test.ts 覆盖了审计管线的核心不变量:
parseSince的时间窗口解析(12h/3d/1w/2mo)与非法输入拒绝;normalizeReadPath对:50-200、:raw、:5-16,960-973等选择器的剥离,同时保留artifact://37、agent://h0qbtw5y/report这类内部 URL scheme 不被折叠;- 合成会话上的
scanFile契约:真实 usage 求和(input 700 / output 70 / cacheRead 900 / cacheWrite 50 / cost 3.5)、context peak、回合切分、spawn 恢复、per-path residency 计算等。
审计循环中的相邻机制
提示词提到的compaction与/handoff在 omp 中是第一类会话条目(CompactionEntry/BranchSummaryEntry),详见 compaction.md:compaction 把旧历史重写为摘要,branch summary 在/tree导航时捕获被弃分支的上下文,二者都在重建 LLM 输入时转换回用户角色消息。审计工具正是把这类事件的出现次数(compactions)当作会话健康度信号之一。
结语
audit-prompt.md的价值在于把"token 浪费"这种模糊感受变成了一套可执行的、可量化的、可追溯的判定协议:会话卫生看主题纯度与拆分时机,子代理质量看隔离收益与上下文传递,浪费清单看 residency 与 billed 的区分。配合 audit.ts 的扫描/分类/缓存/聚合管线,任何 omp 用户都可以定期对本地会话语料做一次"花费体检",用具体数字驱动更省钱的 Agent 使用习惯。
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考