news 2026/9/18 7:58:54

ReviewHog 提示缓存成本治理实录:cache-aware 计量、网关缓存探针与 fork 规模评估(Gate 0)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ReviewHog 提示缓存成本治理实录:cache-aware 计量、网关缓存探针与 fork 规模评估(Gate 0)

ReviewHog 提示缓存成本治理实录:cache-aware 计量、网关缓存探针与 fork 规模评估(Gate 0)

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

导读

本文是 PostHog 开源仓库中 ReviewHog 自动代码评审产品(products/review_hog)在 2026 年 7 月执行的"提示缓存成本实验计划"(prompt-caching program)第 0 号门禁(Gate 0)的完整技术记录,主体文档为 PLAN.md。Gate 0 要回答三个问题:ReviewHog 每轮评审的真实 LLM 成本到底是多少(而非 naive 的 token 计价)两个不同的沙箱进程能否共享同一个 Anthropic 提示缓存、以及**"warm-up + fork"旗舰方案需要多大规模的测量支撑**。读完本文,你将掌握一套可直接复用的 cache-aware 成本计量方法(含完整 SQL 与 Python 实现依据)、一套带正负对照与速率报告的网关缓存探针实验设计,以及围绕 5 分钟滑动 TTL 做沙箱级并行调度的一系列实测结论。


1. 为什么必须引入 cache-aware 计量:naive 计价会夸大 4.8 倍

ReviewHog 的每轮评审由多个"沙箱单元"组成:每个 perspective(逻辑正确性、契约与安全、性能与可靠性)与每个 chunk 一个独立沙箱,外加每 chunk 一个盲点检查(blind-spot sweep),最后每 chunk 一个验证会话。这些单元全都通过products/tasks的共享基础设施(Task/TaskRun → TemporalProcessTaskWorkflow→ Modal/Docker 沙箱 → agent-server → Claude Code 会话)运行,见 ARCHITECTURE.md。由于每个单元都从零探索同一份 PR,它们会反复把几乎相同的前缀 token 发送给模型——其中绝大部分命中提示缓存。

核心问题$ai_input_tokens(网关返回的输入侧 token 总数)把 fresh 输入、cache write 和 cache read 全部混在一起。按统一输入单价计价(naive 方法)会严重高估真实成本。

Gate 0 的实测给出了决定性数字(runs/gate0-run1-pr68749-publish.md):

  • 单 chunk、4 个评审单元(3 个 perspective + 1 个盲点)、142 次 LLM 生成(gens)的一次真实运行:naive 计价 $47.52,cache-aware 真实成本 $9.90,相差 4.8 倍
  • 整个运行的 token 拆分:约 43% 是 cache read、33% 是 cache write、19% 是输出、仅 5% 是 fresh 输入——cache read 是真实成本里最大的桶

这也是 CANDIDATES.md 中"Measured facts"第 1 条的核心结论:naive token 数学高估真实成本约 4.8 倍,且识别这一点的计量工具已上线并通过校验(与网关 LiteLLM 成本在每个桶、每一侧都精确到 Δ +0.0% 匹配)。

Gate 0 的总体目标(PLAN.md 原文)按优先级排序为三部分:

  1. 让每一个未来的成本门禁都可计算、可诚实评估:扩展 dump 工具支持 cache-aware 拆分,发布修正后的基线,重锚候选方案 #4–#10 的美元估值;
  2. 通过 LLM 网关验证缓存共享基板:两个不同的客户端是否共享同一个缓存;
  3. 为 fork 旗舰方案做规模评估:基于既有运行数据测算探索重叠率s与前缀温暖度 TTL 时间线。

同时 PLAN.md 明确声明了非目标:不改管线、不跑 eval、不改 harness(PostHog Desktop 仓库)、不构建 #4/#8/#10,构造上零生产风险。


2. Gate 0 的三件交付物与最终结局

PLAN.md 在文档头部("Status" 一节)记录了 Gate 0 于 2026-07-06 运行一轮后即被用户对项目方向的重新框定(reframe,锁定 CANDIDATES.md 的约束 5–9)关闭。三部分的结局各不相同:

部分计划内容最终结局
Part 1(计量)cache-aware 拆分、true_usd/gw_usd、逐侧成本交叉校验、逐单元 turn-1 缓存读取分布已上线并通过实测校验dump_result.py产出缓存感知拆分,与网关 LiteLLM 成本在每一个桶、每一侧 Δ +0.0%(true $9.90 vs naive $47.52,4.8×)
Part 2(网关探针)5 个受控臂(arm)的跨客户端缓存共享探针,成本约 $0.25–0.60从未运行,降级为可选:基板已被实测证明两次(3 个 wave 单元中有 2 个读取了 leader 写入的完全相同的 27,618-token 前缀);fork 构建自身的机制门禁也覆盖了该检查
Part 3(fork 规模)探索重叠率s的 go/no-go 门槛 + 前缀温暖度 TTL 时间线从未运行,被降级:reframe 取消了 s-gate(不再以实测重叠率门禁构建);TTL/温暖度一半并入了 fork 构建,ENABLE_PROMPT_CACHING_1H成为已解析的杠杆(见 HARNESS.md "1h cache TTL")

被计划文档明确定位为下一个实验的是:在冻结 PR #62096 上运行的 warm-up+fork 构建(候选 #8),使用自己的实验文件夹与自己的计划。本地运行任何实验的操作经验沉淀在 HARNESS.md 的 "Smoke-run lessons" 一节。


3. Part 1:dump_result.py的 cache-aware 扩展

3.1 工具现状与被扩展的列

计量工具是 products/review_hog/eval/scripts/dump_result.py。扩展前它只是把$ai_input_tokens$ai_output_tokens相加、没有缓存拆分(原文档描述为 lines ~50-61;当前实现中对应_spend_report内的聚合逻辑)。工具特性:OUT_DIR环境变量可覆盖输出目录、通过本地 ClickHouse 查询$ai_generation事件、通过manage.py shell运行(这样 Django 已配置好):

LABEL=C0-baseline RUN_SECONDS=812 RUN_START_EPOCH=1751... OUT_DIR=products/review_hog/eval/experiments/<exp>/runs \ python manage.py shell -c "exec(open('products/review_hog/eval/scripts/dump_result.py').read())"

扩展后,工具按(model × stage)维度输出每列(stage 由已有的ai_stage/task_title归属推断):

  • gens:生成次数;

  • fresh_in_tokens:fresh 输入(推导为input - read - write,即_spend_report中的fresh = max(0.0, tin - cread - cwrite));

  • cache_write_tokens$ai_cache_creation_input_tokens

  • cache_read_tokens$ai_cache_read_input_tokens

  • long_ctx_gens:prompt 超过 200K token 的生成次数(_LONG_CTX_TOKENS = 200_000)——注意这是诊断计数而非计价输入(文档注释明确:网关的 LiteLLM 价格表对这类模型按平价计费,所以>200K列不作为定价依据);

  • output_tokens:输出 token;

  • true_usd:按清单价回算(list-price back-calc)。当前实现中的_LIST_PRICES表(每 token 美元:fresh 输入、输出、cache read、cache write):

    • claude-sonnet-5:$2/M in、$10/M out、read $0.2/M、write $2.5/M(5m TTL 的 1.25×);
    • claude-opus-4-8:$5/M in、$25/M out、read $0.5/M、write $6.25/M;
    • claude-fable-5claude-haiku-4-5:同样镜像 LiteLLM 的价格映射(含 haiku);
    • claude-sonnet-4-6:一个"非固定模型",会话中途丢失模型固定(session-restart 类)时出现,按价定价以免污染运行总额。

    定价函数_price_for()支持日期后缀变体(re.sub(r"-\d{8}$", "", model))与包含匹配,保证$ai_model报告的实际型号都能取到价格行;

  • gw_usd:网关$ai_total_cost_usd的求和,作为常驻交叉校验列而非一次性检查。

实现里还有一个重要的细节(_spend_report注释):LiteLLM 的input_cost字段是整个输入侧(cache 已包含在内),这正是旧探针 "+28% 差异"的根源——那不是网关计价错误,而是测量工具的误解。

3.2 逐单元 turn-1 缓存读取分布:跨沙箱共享的"绊线"

除了聚合表,扩展还输出每个沙箱单元的 turn-1 缓存读取分布(per-unit 值 + 命中数)。这是跨沙箱共享的 tripwire(绊线):task_run_id唯一标识一个 TaskRun = 一个沙箱 = 一个会话(HARNESS.md 说明沙箱单元携带task_title形如[sandbox_prompt:issues-review-p{pass}-c{chunk}]/[sandbox_prompt:blind-spots-c{chunk}],且带唯一task_run_id);按时间戳取每个task_run_id的第一条$ai_generation(turn 1)。一个全新沙箱在 turn 1 就发生cache_read > 0,只能来自另一个进程的写入——这就是跨沙箱信号。

dump_result.py的实现细节:turn1字典在遍历(时间有序的)行时记录每个task_run_id的首条记录,同时用集合追踪该单元会话碰过的所有模型——集合大小 > 1 会暴露静默的中途换模型(如 overload rescue),它会破坏缓存共享与成本固定,报告里以⚠️SWITCHED标注。表尾固定输出一句纪律性提示:"units with turn-1 cache_read > 0:N/M(report the distribution, not a median)"。

2026-07-06 的重要更新(写入 PLAN.md Part 1):基线不再是均匀的 0——harness 烟雾测试观察到 3 个 wave 单元中有 2 个通过自然抖动读取了 leader 写入的完全相同的 27.6K [tools+preset] 段;中位数会误导,必须报告分布。

3.3 验证锚点、差异归因与修正后的 Economics 表

Part 1 的任务清单(PLAN.md 原文)含五个子任务,其中四个在本轮内闭环:

  1. 验证锚点:opus-4-8 的true_usd必须与gw_usd在 1% 内匹配(2026-07-06 的探针匹配到 <0.1%)。若不匹配,在信任任何其他东西之前先停下调试价格表。实测(PR #68749 窗口):true $9.90 vs gw $9.90,每个桶每一侧 Δ +0.0%
  2. +28% sonnet 差异:探针发现 sonnet-5 的gw_usd比清单价回算高约 28%(隐含混合价约 $2.55/M)。计划要求逐一枚举假设并发布哪个假设关闭了差距:(a) >200K 长上下文分档;(b) 请求模型与实测模型的映射(allowlist,检查$ai_model);(c) Anthropic 5xx 时的 Bedrock 重路由计价;(d) 网关价格表对最近启用的 sonnet-5 行的错误;(e) 逐路径 token 记账约定差异。实测结论:该差异是测量工件(LiteLLM 的input_cost是整个输入侧,缓存已包含),未在逐生成对比网关 LiteLLM 成本时复现;并规定决策规则——若都关闭不了差距,则信任gw_usd作为评分的 ground truth、保留true_usd作为分解透镜并记录残差。
  3. 修正后的 Economics 表:把归档的 sonnet-5 臂(模型轮的 B1/B2;管线模型臂 C/F/G,若事件幸存)作为附加的 true-cost 列重算,放在 naive $ 旁边(绝不替换——保持跨轮连续性),按任务身份(task_title/run ids)而非原始时间窗圈定(本地其他 LLM 活动会污染时间窗)。实测结局:dead——2026-07-06 的 DB nuke 删除了事件,归档臂无法重算;基线从新运行的 control 中积累。
  4. T1 重写检测器:对 post-flip 运行(本地 team-1 + 2026-07-03 以来的 prod cloud),在一个task_run_id内按时间排序的连续 gens 中(subagent 交错会破坏朴素相邻性),标记cache_read < 0.05× prev(cr+cw+fresh)cache_creation >= 0.8× prevgap <= 120s;对部分重写把 creation 阈值从 0.8 扫到 0.5;区分 rewrite-after-write 与 session-restart/compaction 形状;对 Bedrock-fallback 重路由单独分段(相同签名——若有路由遥测就按路由分段,否则与窗口内 Anthropic 5xx 关联并声明有界混杂)。输出:重写次数/run、重写 token/run、按 sonnet 写价($2.50/M)的 $/run、turn 位置直方图。决策规则:>= $0.5/run 则带着证据向 Tasks 团队 ticket 施压;< $0.3/run 则降级该 ticket 并记录到 INVESTIGATION.md(2026-07-06 粗略探针:post-flip 约 $0.005/run,降级是预期结局)。这一项仍在开放,搭下一个实验的 control 运行顺带完成。
  5. 重锚 CANDIDATES.md:#4–#10 的 $ 估值需按修正后的 sonnet 时代桶重述(尤其 #4 的 fetch-choreography $/unit 与 #9/#10 的 $/turn,今天都是 opus 时代数字)。同样仍在开放。

3.4 报告里的逐侧交叉校验

dump_result.py输出的"gateway per-side cross-check"是常驻的可靠性机制:对每一侧(输入侧、其中 cache read、其中 cache write、其中 fresh(推导)、输出)打印网关成本、行数以及相对true回算的 Δ。若 write 侧超出 1.25× 回算的 5%,报告会提示"write-side excess over the 1.25× back-calc = 1h-TTL cache writes (billed 2×; the token split can't see the TTL)"——这是识别 1h 写计费的手段,因为 token 拆分本身看不到 TTL。


4. Part 2:网关缓存探针的 5 臂设计与解释纪律

Part 2 的脚本设计(原文档完整规格,虽然最终未运行、降级为可选)仍然值得完整保留,因为它是一份教科书级的"跨进程共享缓存"对照实验设计:

  • 脚本形态:一次性脚本(不提交进管线),用裸client.messages.create——不要用.parse(结构化输出会把 schema 字节注入请求);thinking 关掉(adaptive thinking 与max_tokens=64不兼容,且 thinking 配置会使 message-span 断点失效);走get_async_anthropic_gateway_client(product="review_hog", team_id=...)(与reviewer/sandbox/direct_llm.py同一路径,Bedrock fallback 已在该路径关闭);
  • 载荷:约 10K token 的文档块,以显式cache_control: {type: "ephemeral"}断点结尾,max_tokens=64
  • nonce 纪律每一个臂、每一次试验都要用唯一 nonce 给文档加盐,使各臂永远无法读到彼此的 warm 条目(因为读取会免费刷新滑动 TTL,静默污染 creation 基线);
  • 保持恒定:跨进程保持 metadata/user_id/extra headers 不变;记录response.usagecache_creation_input_tokenscache_read_input_tokens)并与$ai_generation的缓存字段交叉核对。
形状门禁
1(正对照)同一进程,相同请求间隔 2 分钟试验 2 的cache_read >= 0.95×试验 1 的cache_creation。FAIL → 网关在直连路径上剥离/忽略cache_control:给网关开 ticket,T2 落地后再用 CLI 驱动的沙箱会话对重探跨沙箱问题
2(主张本身)两个独立 OS 进程,间隔 2 分钟,用全新 nonce 复制 >= 3 次报告共享速率而非二元结果(网关若汇集多个上游 key/workspace 会概率性共享);门禁:进程 B 的cache_read >= 0.95×进程 A 的cache_creation(同一次试验)
3(allowlist 混杂因素)REVIEW_MODELvs 一个不在 allowlist 的模型名两侧都确认$ai_model;若名字被静默映射到同一被服务模型,HIT 是预期结局——模型身份、而非命中/未命中,才是发现
4(负对照)间隔 6 分钟、全新 nonce、保证零中间读取必须 MISS(滑动 TTL)
5(沙箱来源——任何跨沙箱放行前的强制臂)一对字节完全相同的请求,从沙箱内部以裸网关调用发出(网络来源/凭据/workspace 检查)同臂 2。不是Claude Code CLI 驱动的成对请求——CLI 请求今天无法做到字节相同(V1/V2),按构造必 miss

解释纪律(文档要求逐字诚实地写进报告):

  • 臂 1+2+5 全 PASS → 跨沙箱共享的 workspace 基板得到验证(且显式断点在直连路径上有效,对一次性 chunking/dedup 有用);
  • PASS 不等于"de-risk"跨沙箱计划:T2/T3 字节修复与 CLI 断点放置仍未证明;臂 5 只覆盖来源(origin);
  • 臂 1 通过、臂 2 持续失败 → 网关按客户端分区(字节或凭据):升级到网关/Tasks 团队(探针能证明这种分歧存在,但无法给出精确的线上差异),并停止所有跨请求候选方案。

2026-07-06 的更新使其"存在性问题"获得生产级 PASS:两次(烟雾运行 2 与 PR #68749 发布运行)观察到两个全新沙箱通过完整栈(Modal → ngrok → 本地网关)读取了第三个沙箱写入的 27.6K 缓存段。但计划仍建议在受控臂(共享速率、allowlist 映射、TTL 健全性)需要时再运行探针,并把臂 2 失败视为需要调查的异常而非计划杀手。reframe 后,臂 5(沙箱来源成对)成为承重臂——它是所有跨沙箱共享(T2/T3/#8)的基板检查;直连路径断点结果现在只对一次性 chunking/dedup 调用有意义。


5. Part 3:fork 规模评估的规格与降级

Part 3 的完整规格在 CANDIDATES.md #3,执行时带上了批评者的修改(仅 wave 的 s、严格 3-of-3 / 宽松 2-of-3、盲点边际重叠单独报告、早窗口对账、TTL 门禁失败时的提高阈值规则)。两个离线分析:

(a) 重叠率s$ai_generation(时间戳、cache_creation)join 到任务的 ACP 日志以获取工具调用的参数——$ai_tools_called只带名称(已核实)。工具调用归一化(Read 路径、Grep 模式+范围、分类的 Bash),早窗口 = turns 2..ceil(0.4 × turns)(与"首个发现前的边界"作为扫描变体对账),按 next-gencache_creation减 prior-gen 输出加权;只对 3 个 wave 单元计算 s(严格 = 三者皆现;宽松 = 2-of-3);盲点的边际重叠单独报告(它喂给第 5 个 forker 的决策,而非 wave GO)。门禁:wave-fork GO 需要s_p50 >= ~0.55(严格)(审计显示把重读税定价后,原 0.40 边界的净值低于实质门槛)。

(b) 温暖度/TTL:按(run, chunk)计算 wave 并集上最大的连续 gen 间间隙(未刷新的最坏 TTL 窗口)与 last-wave-gen → first-blind-spot-gen 的间隙,报 p50/p95,外加 fork 时代调度表的模拟移位。门禁:wave 内部最大间隙 p95 < 4 分钟 → 不需要重调度构建;wave→盲点间隙 p95 < 4 分钟 → 盲点可成为第 5 个 forker(额外 +$0.8–1.1/run)。

执行注释还要求包含大型多 chunk 运行(例如现场 PR #67419 运行:3217 行新增、一次性 chunking、61 条原始发现),而非只测冻结的 #62096——大 PR 是计划的优先项,且 s 可能在其中不同(大 PR 的 chunk 若触碰共享模块,可能重叠更多,恰恰会在最需要的地方抬升 fork 价值)。按 chunk 数分桶报告 s。

最终结局(2026-07-06 晚):被锁定约束 7 降级——s 不再门禁构建(重构后的 warm-up 按设计让 s→1,价值随不受限的 perspective 数量扩展)。温暖度/TTL 一半并入 fork 构建(在其运行中测间隙,ENABLE_PROMPT_CACHING_1H是间隙超过 5m 时的杠杆);重叠分析仅作为可选的构建后诊断存续。


6. 两个决定性实测:跨沙箱缓存共享部分上线、TTL 默认是 5 分钟

6.1 跨沙箱缓存共享:基线不再是零

HARNESS.md 的烟雾运行 2(2026-07-06,现场 PR #68735,未打补丁的本地 main)给出了第一手证据:

单元首次 gent1 cache_readt1 cache_write
issues-review-p2-c1(leader)18:34:54059,423
issues-review-p3-c1+4s27,61831,801
issues-review-p1-c1+50s27,61831,806
blind-spots-c1+10min062,473

证据解读(文档原文要点):

  1. 跨沙箱缓存共享在当前 agent/SDK 上已部分上线:两个全新沙箱读取了 leader 写入的完全相同的 27,618-token 段——即 [tools + system-preset 块] 前缀;之所以能共享,是因为自然的供给抖动(4s、50s)使 p2 成为事实上的 leader。Task-Id追加(V1)只污染它之后的字节——前面的 preset 块共享无恙。2026-07-03 调查的"turn-1 cache_read 中位数 = 0"在当前构建上已过时(今天的中间值会是 27,618——因此要看分布,别看中位数)。
  2. 这是 Spike 1 跨客户端问题的生产级证据:两个不同沙箱进程通过完整栈(Modal 沙箱 → ngrok → 本地 llm-gateway)共享了同一个 Anthropic 缓存。
  3. wave→盲点的 TTL 间隙真实存在并被观测:单 chunk PR 上 10 分钟(沙箱供给 + 启动 + clone + checkout 就吃掉 5 分钟滑动 TTL),盲点因此全量重写。任何 fork 设计都必须按 chunk 排序并重新检查温暖度。
  4. 这不改变 T2 仍是 fork 的硬前置:跟随者 fork warm-up 的 transcript 需要整个前缀(含 system append)字节一致;每个任务的Task-Id仍在 append 处破坏这一点。约 27.6K 的 preset 共享每单元只值几分钱($/follower ≈ 27.6K × ~$2.3/M 差值 ≈ $0.06)——fork 的价值在于约 70K transcript 读取,它仍被 T2+T3 阻塞。

PR #68749 的正式发布运行再次复现了该 tripwire(runs/gate0-run1-pr68749-publish.md):leader 在 turn 1 写入 73.2K;两个跟随者在 +1s/+19s 读取了完全相同的 27,618-token [tools+preset] 段;盲点在 wave 之后 +12.5 分钟才触发并全量重写(TTL bust)。该运行 2/5 的单元有 turn-1 cache_read > 0。

6.2 TTL 真相:我们默认跑在 5 分钟上,1 小时只需一个环境变量

HARNESS.md "1h cache TTL" 一节用三种方式证明了沙箱路径默认是 5 分钟 TTL(回答"我们是不是默认就用 1 小时 TTL"的疑问:):

  1. 计费证明:PR #68749 运行的 cache-write 成本与 5m 费率(1.25×)精确到分匹配,且 LiteLLM 对 1h 写单独计价(cache_creation_input_token_cost_above_1hr= 2×,其成本计算会用到,因此 1h 写必然显现);
  2. 行为证明:两个独立的 >5m 间隙都造成了全前缀重写(#68749 运行盲点距最后一个 wave gen 5m52s;烟雾运行 2 的 10 分钟间隙);
  3. 机制(从 CLI bundle 反编译)packages/agent/dist/claude-cli/claude中,每次请求 CLI 设置ttl = CCH(querySource) ? "1h" : undefined并把它穿进每个缓存断点(同时推送extended-cache-ttl-2025-04-11beta 头)。CCH()的逻辑:FORCE_PROMPT_CACHING_5M环境变量 → 总是 5m;ENABLE_PROMPT_CACHING_1H环境变量 → 总是 1h(无条件);否则要求 first-party 认证(Nq(),在我们的网关 token/base-URL 路径上失败)后才咨询 statsig allowlist(tengu_prompt_cache_1h_config,默认["repl_main_thread*","sdk","auto_mode","memdir_relevance"])。所以交互式 Claude Code 与 first-party SDK 会话确实默认 1h——而我们经网关认证的沙箱穿透到 5m。这就调和了"我们默认用 1h"的直觉与实测的 5m 行为。

执行方式(无需补丁):在沙箱容器环境变量里设ENABLE_PROMPT_CACHING_1H=1——注入点在 products/tasks/backend/temporal/process_task/activities/provision_sandbox.py 的_build_environment_variablesenvironment_variables字典,在LLM_GATEWAY_URL一行附近;源码可见settings.SANDBOX_LLM_GATEWAY_URL会写入LLM_GATEWAY_URL)。它是按沙箱生效的,因此可以有选择地启用(例如只给 warm-up 单元:其 transcript 条目存活 1h,而跟随者写保持 5m)。两个仓库当前都没有设置这些变量(已验证)。

成本与剩余未知:1h 写按 2× 而非 1.25× 计费(在 #68749 运行形态上全面启用会增加约 $2.4/run 的写溢价——要选择性启用,不要全舰队启用)。ttl字段已 GA(按当前 Anthropic 文档无需头);CLI 的 beta 头推送在我们的路径上是否也触发(uk()门禁,未解码)是运行时验证的细节——首次启用运行的写侧成本(预期该单元约 +60%)与 >5m 间隙存活是经验确认手段。

6.3 Tripwire 验证 SQL

HARNESS.md 给出了完整的验证查询(通过manage.py shellsync_execute运行,即 dump_result.py 的模式)。它按task_run_id分组,取每个单元的首条 gen 的 turn-1 cache read/write,并按单元类型(blind-spot vs perspective)聚合,报告中位数与命中计数:

WITH unit_turn1 AS ( SELECT JSONExtractString(properties, 'task_run_id') AS task_run_id, extract(any(JSONExtractString(properties, 'task_title')), '\\[sandbox_prompt:([a-z0-9_-]+)\\]') AS step_name, count() AS gens, argMin(toFloat64OrZero(JSONExtractString(properties, '$ai_cache_read_input_tokens')), timestamp) AS turn1_cache_read, argMin(toFloat64OrZero(JSONExtractString(properties, '$ai_cache_creation_input_tokens')), timestamp) AS turn1_cache_creation FROM events WHERE event = '$ai_generation' AND timestamp >= %(run_start)s AND timestamp < %(run_end)s AND (JSONExtractString(properties, 'task_title') LIKE '[sandbox_prompt:issues-review-%' OR JSONExtractString(properties, 'task_title') LIKE '[sandbox_prompt:blind-spots-%') AND JSONExtractString(properties, 'task_run_id') != '' GROUP BY task_run_id ) SELECT multiIf(step_name LIKE 'blind-spots%', 'blind-spot', 'perspective') AS unit_kind, count() AS units, medianExact(turn1_cache_read) AS turn1_cache_read_median, countIf(turn1_cache_read > 0) AS units_with_turn1_hit, medianExact(turn1_cache_creation) AS turn1_cache_creation_median FROM unit_turn1 GROUP BY unit_kind WITH TOTALS ORDER BY unit_kind

两个重要注意点:沙箱单元走的是 harness 的网关产品(background_agents)——不要对沙箱单元按ai_product = 'review_hog'过滤(那只标注一次性 chunking/dedup 调用);以及报告分布(units_with_turn1_hit+ 逐单元值),永远别只报中位数

$ai_generation的缓存字段由网关捕获(services/llm-gateway/src/llm_gateway/callbacks/posthog.py 中$ai_cache_read_input_tokens/$ai_cache_creation_input_tokens,仅在存在时发出——缺失按 0 处理),本地 e2e 已证明这些字段落入本地 ClickHouse。


7. 运行日志:Gate 0 的一次实战复盘

PLAN.md 的 "Run log" 记录了 2026-07-06 的三条关键条目,是实验方法论的第一手教材:

2026-07-06(范围收窄会话:仅单 PR 评审 + 花费计算修复):DB 刚被 nuke,$ai_generation归档 = 0(归档臂重算不可能;修正基线必须来自新运行);team 1/user 1 在重新播种后幸存;GitHub 集成行丢失——通过GitHubIntegration.integration_from_installation_id("143741024", team_id=1)恢复。在带--publish的现场 PR #68749 上运行run_review(单 chunk:461 行原始新增,但可评审行在 400 门槛内)。烧出来的教训:运行中途编辑products/**/*.py会让 temporal worker(nodemon)重启并杀死第一次尝试的 wave;Temporal 重试工作流,从同一 head 已持久化的 (pass, chunk) 结果恢复——wave 没有重付,只有盲点重跑。运行完成(posthog-local-dev,20:45 UTC),漏斗 1 chunk / 4 单元 / 8 原始 / 8 去重 / 4 有效。

2026-07-06 深夜——TTL 调查、计划重框定、本轮关闭:证明沙箱路径跑在 5m 缓存 TTL 上(计费恰好 1.25×,>5m 间隙全量重写,CLI 的CCH()门禁在 allowlist 前要求 first-party 认证——从 CLI bundle 反编译得出);且沙箱环境里的ENABLE_PROMPT_CACHING_1H=1无条件强制 1h(注入点provision_sandbox.py;按单元;写 2×;FORCE_PROMPT_CACHING_5M是 kill switch)。用户锁定重框定(CANDIDATES.md 约束 6–9):warm-up = 有意的调查阶段、N 不受限、s-gate 取消、fixture #62096。Gate 0 关闭;下一个实验 = #8 fork 构建。

2026-07-06——Part-1 工具上线并通过实测验证eval/scripts/dump_result.py扩展完成;在 PR #68749 窗口验证(runs/gate0-run1-pr68749-publish.md):true $9.90 vs gw $9.90,每个桶每一侧 Δ +0.0%——旧探针的 +28% sonnet 差异未在逐生成对比网关 LiteLLM 成本时复现(错在探针的回算,而非网关价格表)。Naive 方法 = $47.52 =4.8× true(与 CANDIDATES.md 的实测事实一致)。本次运行的桶拆分:43% cache read / 33% cache write / 19% output / 5% fresh。Tripwire 复现了烟雾运行的发现:5 个单元中 2 个在 turn 1 读取了 leader 写入的完全相同的 27,618-token [tools+preset] 前缀;盲点在 wave 后 12.5 分钟启动(TTL bust,全量重写)。


8. 环境准备(Pre-flight)与评分决策

PLAN.md 的 Pre-flight 清单(在本地复现 Gate 0 类实验的实用前提):

  • flox 环境;本地 ClickHouse 可达且持有归档 eval 窗口的$ai_generation先检查——见紧迫性说明,保留期使这很脆弱,10 天探针窗口在 2026-07-06 几乎覆盖不到它们);
  • Part 3 需要任务的 ACP 日志(S3/对象存储)来获取工具调用参数——与 ClickHouse 检查一起确认访问与保留期;
  • 网关客户端凭据在 worker 环境中可用(get_async_anthropic_gateway_client);
  • 除 ClickHouse 外无需 dev 栈;除臂 5(一个一次性任务或进入既有沙箱镜像的 shell)外无需沙箱;
  • 本轮不触碰reviewer/管线代码或提示词。

紧迫性说明(Part 1 的第一行动):从本地 ClickHouse$ai_generation事件重算归档的 07-03 eval 臂——本轮的第一行动是确认这些事件仍然存在(保留期使这很脆弱)。如果已老化掉,修正基线必须来自下一轮的两个 control 运行,并记录在 run log 中继续其余部分。(实测结局:DB nuke 使该检查失败,基线改为从新运行积累。)

评分与决策(本轮输出约定):FINAL_REPORT.md(惯例:TL;DR、setup、结果含修正 Economics 表、探针臂表带速率、建议、成本合计),外加五项交付物:(1) 修正基线发布、naive-vs-true 并列;(2) T1 ticket 施压或降级(两种结果都记录到 INVESTIGATION.md);(3) 跨沙箱基板裁决(臂 2 + 臂 5 共享速率)与 fork go/no-go 输入发布(按 chunk 数分桶的 s、TTL 温暖度时间线、盲点第 5 forker 裁决);(4) CANDIDATES.md 重锚;(5) 下一轮建议(Round 1 默认 = #4 skill-body splice + #10 pre-pack;旗舰裁决 = 由 s + 基板给出的 fork 阶梯 GO/STOP)。

工作模式(2026-07-06 与用户锁定):实验迭代式、隔离式、一个接一个运行——本轮在signals/reviewhog之外单独开分支(建议signals/reviewhog-exp-caching-gate0);若后续实验的更改与前序矛盾,实验结束后 stash 工作,或更好的是每个实验保持独立分支,只有确定的赢家合并回主干。本轮唯一预期合并的持久工件:dump_result.py扩展(它是 eval 工具,不是管线代码)加上本文件夹的结果文档。


9. 与当前仓库状态的衔接

需要说明的时效性:本文描述的实验发生于 2026-07-06,是 2026-07-prompt-caching 实验文件夹中的历史记录(PLAN.md 自身标注 "round closed — this doc is the record")。当前仓库中:

  • dump_result.py仍然存在并保留了全部 cache-aware 扩展(fresh/write/read/output 拆分、true_usdvsgw_usd、逐侧交叉校验、turn-1 分布、以及为 warm-up+fork 臂预留的 fork 碰撞跟踪器——每个 chunk 报告"前缀写入者/读者"数量,1 个写入者是理想 fork 形态);
  • constants.py 中的模型固定已演进(评审臂为 Codexgpt-5.6-sol@ xhigh、验证/解决为claude-opus-5@ xhigh、chunking/dedup/oneshot 为claude-sonnet-5),MAX_CONCURRENT_SANDBOXES = 10FAN_OUT_FAILURE_FLOOR = 0.70对应 PLAN.md 中讨论的 fan-out 并发边界;文档引用的历史价格(sonnet-5 $2/$10、opus-4-8 $5/$25 per M)属于实验当时的清单价,应以网关实时价格表为准;
  • workflow.py 的ReviewPerspectivesWorkflow(fan-out 波 + 盲点)正是 INVESTIGATION.md 中 V0 违规("无 warm-up 阶段")所在的位置——按计划,warm-up 阶段就插在这里;
  • 沙箱环境变量注入点 provision_sandbox.py 的_build_environment_variablesENABLE_PROMPT_CACHING_1H的落地处。

从源码结构可以推断:cache-aware 计量的设计意图("以真实成本门禁所有未来实验")已沉淀为 CANDIDATES.md 中所有候选方案的统一成本门禁约定——"All cost gates are cache-aware and RELATIVE to the measured sonnet-era control"。这一原则在后续实验轮中持续生效,也是任何想为 ReviewHog 类多沙箱 agent 系统做成本工程的人最值得带走的结论:在缓存感知计量上线之前,任何成本决策都建立在高估 4.8 倍的数字之上


10. 核心要点速览

  1. naive token 计价会系统性高估成本:真实运行的 cache read 是最大成本桶(43%),naive 方法把全部输入按统一价计,高估 4.8 倍——先上 cache-aware 计量,再谈任何成本优化。
  2. 验证锚点纪律true_usd(清单价回算)必须与gw_usd(网关 LiteLLM)逐桶逐侧匹配(Gate 0 实测 Δ +0.0%),不匹配就先调试价格表再信任其他数据。
  3. 跨沙箱共享是真实且可观测的:turn-1 cache_read > 0 是唯一可信的跨沙箱信号(全新沙箱的首次读取只能来自他人写入);报告分布而非中位数。
  4. TTL 是成本设计的核心约束:沙箱路径默认 5m 滑动 TTL(写 1.25×),1h 需ENABLE_PROMPT_CACHING_1H=1(写 2×);wave→盲点的 5m52s–12.5min 间隙会全量重写,fan-out 必须立即调度并重叠供给。
  5. fork 的硬前置是字节一致性Task-Id插值(V1)与动态 system 段(V2)必须在整个前缀上消除,原始 JSONL 必须上传(T3),否则 fork 读取永远不会发生——这决定了"warm-up 以一次 settle 用户 turn 收尾、写出 stripped-form 缓存"的设计。

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

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

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

神经网络与卷积神经网络实战:从原理到Caffe模型训练

简介&#xff1a;《人工智能教程 神经网络算法教程 卷积神经网络介绍 Caffe模型介绍》是一份145页的中文PDF文档&#xff0c;面向希望入门深度学习和计算机视觉的开发者、学生及研究人员。教程系统梳理了神经网络核心算法&#xff0c;重点讲解卷积神经网络&#xff08;CNN&…

作者头像 李华
网站建设 2026/9/18 7:57:32

Python+Vue校园二手拍卖系统与人脸识别实践

1. 项目背景与核心价值校园二手交易一直是个高频刚需场景。每到毕业季&#xff0c;大量教材、电子产品、生活用品被低价处理甚至丢弃&#xff1b;而新生入学时又需要采购这些物品。传统的线下跳蚤市场受时间和空间限制&#xff0c;信息不对称严重。我们团队开发的这套"Pyt…

作者头像 李华
网站建设 2026/9/18 7:55:16

移动端列表容器四件套:List/Grid/Tabs/Swiper实战笔记

打卡第 11 天&#xff0c;终于开始系统啃移动端最常用的一类组件&#xff1a;列表容器。之前写页面总是拿到数据就往 Column 里堆 ForEach&#xff0c;滚动全靠 Scroll 包一层&#xff0c;页面一复杂就卡到想摔手机。今天把 List、Grid、Tabs、Swiper 四个容器全部过了一遍&…

作者头像 李华
网站建设 2026/9/18 7:53:10

前端导出CSV与Excel实战:编码、性能与安全全解析

前两年做后台管理系统的时候&#xff0c;几乎每个月都要被“导出”这个需求绊一跤。今天产品说要导出 CSV&#xff0c;明天客户指名要 Excel&#xff0c;后天又有人说“你们导出的文件打开乱码”&#xff0c;大后天又来一个“几十万行数据一导出浏览器就卡死”。前端导出 CSV 和…

作者头像 李华