Harness:查清这次慢在哪、贵在哪
第一轮很轻快,聊到后面却越来越慢。模型读了什么,工具跑了多久,审批又等了多久?这一篇给一次运行摊开两本账,让你拿着报告就能顺着开销往回查。
完整历史可以保存,但每次送给模型的上下文必须有预算、有清单、有证据。 否则长会话会悄悄变慢、变贵,而且你无法解释是哪一步造成的。
状态:实现建议。字段名是示意,未接入当前 runtime。资料核对:2026-10-24。
| 账本 | 保存什么 | 用途 |
|---|---|---|
| 完整历史 | 全部事件、工具结果、artifact 引用 | 恢复、审计、导出、对账 |
| 本次上下文 | 这次真正发给模型的内容 | 控制 token、保持工具调用成对、留出输出空间 |
“历史里有”不等于“这次要发给模型”。把所有历史每轮重发,会把成本、延迟和上下文超限一起放大。
上下文装配规则
Section titled “上下文装配规则”第一版可以按固定规则装配:
- 当前任务与明确约束。
- 最近 N 个完整交互轮次;不要从一轮中间切断。
- 与当前任务相关的工具请求和结果,必须成对保留。
- 大输出只保留有界摘要 + artifact 引用。
- 为模型输出、工具 schema 和下一次工具结果预留空间。
- 无法构造合法上下文时停止,并显示原因;不要原样重试到超限。
接近预算时,先裁剪可重建的日志,再考虑摘要。摘要要标记覆盖范围,原始记录仍然保留;摘要不是无损压缩。
以上是内容保留的优先级。最终装配仍须保持接口要求的角色与时序,避免每轮把当前任务搬到历史前部而制造额外的前缀变化。
context.manifest
Section titled “context.manifest”每次请求前生成一份清单,说明“为什么发送这些内容”:
{ "runId": "r-7", "estimatedInputTokens": 18400, "reservedOutputTokens": 4096, "included": [ "current-task", "constraints", "turn-8..turn-12", "tool-pair-31" ], "excluded": [ { "reason": "older-than-window", "count": 24 }, { "reason": "artifact-summary-only", "count": 3 } ], "artifacts": ["art-3", "art-5"], "method": "chars-div-4-with-10-percent-margin"}清单本身也是事件。它让你在复盘时看到:模型当时到底看到了什么,哪些内容被排除,估算依据是什么。
run.report
Section titled “run.report”每次 Run 结束生成一份报告,单独保存为 artifact:
{ "runId": "r-7", "status": "succeeded", "modelRequests": 3, "toolCalls": 4, "approvalWaitMs": 12000, "estimatedTokens": 27100, "actualUsage": { "prompt": 24000, "completion": 3100 }, "resultBytes": 81234, "errors": [], "cancelledAt": null, "durationMs": 48300}字段按你的供应商能力取舍。关键是让报告能回答:
- 慢在哪:模型请求、工具执行、审批等待,还是持久化?
- 贵在哪:输入、输出、重试,还是重复发送历史?
- 失败在哪:网络、限流、工具错误、上下文超限,还是取消?
- 上下文是否接近预算:估算值与预留空间还剩多少?
缓存命中也按单次请求记账
Section titled “缓存命中也按单次请求记账”缓存能减少重复处理输入的工作,仍要把它包含在上下文规模里。为每次模型请求保留原始 usage、供应商和模型,再统一统计口径:DeepSeek 的 prompt_tokens 已包含命中输入,Pi 的 input 则将缓存读取和写入另列。字段未报告时保留未知,避免静默补成一次确定的未命中。
跨请求汇总命中率时,用命中 token 总数除以对应的有效输入 token 总数,并报告有多少请求具备用量;不要直接平均每轮百分比。压缩、换模型与工具清单变化分别留记录,才能解释下一轮的前缀为何变化。
具体对照见 DeepSeek 缓存用量、DeepSeek Harness 请求投影与 Pi 用量归一化。这些是后续观测建议,尚未接入当前 runtime。
小挑战:聊到第 100 轮,再查一次账
Section titled “小挑战:聊到第 100 轮,再查一次账”合成一条包含 100 轮交互和多次大工具输出的会话:
- 每轮都重新装配上下文,记录
context.manifest。 - 检查 token 估算是否保持在预算内,而不是随历史线性增长。
- 检查每个 tool call 和它的结果是否仍然成对。
- 检查待审批、
unknown工具结果和取消记录没有被摘要裁掉。 - 在接近预算时触发一次超限,确认系统停止并说明原因。
- 只看
run.report,能说清这次 Run 的时间、token 和失败点。 - 100 轮合成会话不会无界增长;超出预算时停止,不原样重试。
- 上下文清单能解释“模型看到了什么、没看到什么”。
- 估算 token 与实际 usage 分开记录;差异大时能看到估算方法。
- 估算不是账单。 字符数除以 4 只是粗略估计;供应商的 tokenizer 和计费口径不同。记录方法并留余量。
- 摘要不是事实。 摘要可能漏掉关键条件;需要精确信息时回查 artifact 或原始事件。
- 不要静默截断用户产物。 用户要求保存的文件、报告和证据不能被日志清理策略悄悄删除。
- 不要把待审批和未知结果裁掉。 它们影响下一步决策,不能因为“太旧”就消失。
- 报告本身也要限额。 失败时不要递归生成巨大的错误报告。
和现有文档的关系
Section titled “和现有文档的关系”- 上下文与持久化建议:Mac 本地 Harness 第 7.1、10 节
- 事件与输出边界:PROTOCOL.md
- 场景实验的计量口径:十五个 Harness 场景
返回上一篇 · 总览 · 下一篇Harness:场景回归。