CodeGraph Agent 评测三反馈指标实战:Residual Occupancy、Explore Sufficiency 与 Allocation Efficiency
CodeGraph 的 agent-eval 评测框架在每次运行时固定输出三个反馈指标:残差上下文占用(Residual Context Occupancy,CG-7)、探索充分性(Explore Sufficiency,CG-8)与分配效率(Allocation Efficiency,CG-9)。它们不是同一个数字的三种视图,而是分别回答"这次检索为后续回合留下了多少上下文负担""检索结果是否足以让 Agent 停止翻查""返回的字节有多少真正被答案引用"三个独立问题,一次检索改动可能只移动其中一个而不动其他两个。本文围绕 入口文档 讲解如何为不同评测目的选择 harness、如何读输出表、三个指标各自的坑,并结合 scripts/agent-eval/parse-run.mjs 的源码说明每个指标是如何从既有 stream-json 转录日志中解析出来的。读完你可以独立运行这三套评测、解读 ARM COMPARISON 表,并在数字异动时定位到具体该修哪一段检索逻辑。
三个指标:各答一个问题,互不替代
入口文档给出的核心分工如下表。三者都是 harness-only 指标:全部从评测框架自己写出的转录日志中解析而来,产品侧不输出任何遥测数据,数据也不离开本机。
| 指标 | 回答的问题 | 深入文档 |
|---|---|---|
| Residual context occupancy(CG-7) | 运行结束时,该臂的检索结果还占着窗口里的多少 token——即后续每一轮都要在多大的剩余空间里工作 | residual-context-occupancy.md |
| Explore sufficiency(CG-8) | 响应够不够?读 Agent 紧接着做了什么:再 explore、Read 文件,还是直接作答 | explore-sufficiency.md |
| Allocation efficiency(CG-9) | 响应花掉的字节里,有多大比例给了答案真正引用的文件 | explore-allocation-efficiency.md |
入口文档还强调了一个阅读纪律:"Efficiency is not value, and occupancy is not sufficiency." 一个响应可以 100% 高效却毫无用处(比如只有一个被顺带提到的小文件),残差小也只是在答案仍然正确的前提下才有意义。把三个指标接在同一次运行里输出,正是为了强制三者一起读。
选择 harness:按你要问的问题挑
三个指标在两套 A/B harness 中都会打印,按问题类型选择:
1. 隔离一次检索改动:ab-new-vs-baseline.sh
新构建(HEAD)对比基线构建(任意 git ref),两臂都挂载 codegraph,跑同一个实现任务。这是这三个指标的设计目标场景——两臂 codegraph 都在,所有数字度量的都是"改动本身",而不是"有没有用 codegraph"。
RUNS=3 scripts/agent-eval/ab-new-vs-baseline.sh /tmp/codegraph-corpus/express \
"Add a charset option to res.send and wire it through" main
从 ab-new-vs-baseline.sh 的脚本实现看,它的运行机制有几个关键点:
- 脚本先把目标仓库
rsync出两份干净副本(t-new/t-base,排除 node_modules/.git/dist/.codegraph),分别用 HEAD 构建和基线 ref 构建各自索引并运行;基线臂通过逐文件git checkout <ref> -- <file>还原旧构建,src/无差异时会直接拒绝运行("nothing to A/B"); - 每次运行前对目标副本 预温热一个常驻 codegraph daemon 并等待
daemon.sock出现,同时用CODEGRAPH_WASM_RELAUNCHED=1跳过启动再执行。这一步"load-bearing,不可删除":没有它,Agent 会在 codegraph 完成约 2–3 秒启动前就扑向 Read/grep,整次运行测的是 attach 延迟而不是检索质量; - 两臂都设置
CODEGRAPH_NO_PROMPT_HOOK=1,禁用环境里 ambient 的 UserPromptSubmit 前置钩子——否则会经第二条不受控通道注入上下文,污染工具调用计数; RUNS环境变量控制每臂运行次数(默认 1)。由于两臂各自只构建/索引一次,提高RUNS远比重新调用脚本便宜,而运行间方差很大,文档明确要求RUNS>=2并报告区间。
2. 有无 codegraph 对比:run-all.sh
Codegraph-on 臂(仅 codegraph MCP)对比空 MCP 配置臂。它回答的是另一个问题:位移(displacement)与采用(adoption),而非改动效果。内置 Read/Grep/Bash 在两臂中均可用,所以"without"臂获取同样字节的方式是读文件和搜索。
scripts/agent-eval/run-all.sh /tmp/codegraph-corpus/gin \
"How does gin route requests through its middleware chain?||\
Where is the 404 / no-route case handled in that same chain?"
多回合语法是 || 分隔:第一回合正常运行,后续每个回合用 --resume 续接同一 session,前一回合的工具输出仍在窗口里——这正是残差占用真正被"记账"的地方,单问题运行结构性地看不到这个成本。从 run-all.sh 源码看,每段落在 run-<label>.jsonl、run-<label>.t2.jsonl… 中,parse-run.mjs 会把它们拼回一个 session(--resume 不重放历史消息,所以各段可干净拼接)。CG_ARMS=with|without 可只重跑一臂而不重做另一臂,对比表仍会对着 $AGENT_EVAL_OUT(默认 /tmp/agent-eval)中已有的日志渲染。
3. 完整战役:bench-readme.sh
7 个 README 仓库(vscode、excalidraw、django、tokio、okhttp、gin、alamofire),每个 3 回合,每臂 RUNS 次,全部经由 run-all.sh 驱动——因此战役中每次运行都携带三个指标。从 bench-readme.sh 看,仓库需预先克隆并索引到 $CORPUS(默认 /tmp/codegraph-corpus),每行固定为"主问题 + 两个不离开同一流程的追问",CG_TURNS=1 可退回原始单问题 A/B。聚合用 parse-bench-readme.mjs:
CORPUS=/tmp/codegraph-corpus RUNS=2 scripts/agent-eval/bench-readme.sh
node scripts/agent-eval/parse-bench-readme.mjs /tmp/ab-readme
已运行过一次战役:2026-08-05 基线(sonnet,3 回合,每臂 4 次)。文档提醒:比较任何东西之前先读它上面的 regime box,且注意它不是 README 表格发布时所用的 regime。
4. 已有日志:随时可解析
parse-run.mjs <run.jsonl> [run.tN.jsonl …]对任意 stream-json 日志打印三个指标块;--brief去掉带编号的调用转录,保留其余;--envelope额外报告 explore 响应在文件间的字节分配,--answer <glob>(可重复)标记真正答题的文件;parse-session.mjs <project-dir>对交互式 session 做 sufficiency 和 allocation;compare-arms.mjs <out-dir> <label>…随时从磁盘日志构建对比表,任意标签。
模型策略(两套 harness 通用,不可协商):每臂都用 --model sonnet --effort high,两臂同模型。Sonnet 是有意的下限——能在它上面落地的 affordance 可以上泛到任何宿主模型;只在更强模型上有效的改动,无法下泛到多数用户实际拥有的 Agent。
读懂输出:对比表回答"动没动",逐运行块回答"为什么"
每次运行先打印自己的三个指标块(块形状见各指标文档),然后一张表把两臂并排。这是真实的 CG-22 express 运行输出,也是三个指标一起读的完整示例:
====== ARM COMPARISON — /private/tmp/cg22/ab-express ======
new baseline
runs 3 3
behavior
duration (s) 24 [18–35] 26 [24–30]
Read 0 1
codegraph calls 2 [1–2] 2
residual context occupancy (CG-7) — tokens still resident at end of run
codegraph residual (tok) 11,549 [7,193–12,591] 10,388 [10,373–10,447]
file-access residual (tok) 231 [0–242] 1,661 [1,306–1,663]
→ retrieval residual (tok) 11,780 [7,193–12,833] 12,034 [11,753–12,051]
→ share of final context 23.3% [15.8%–24.9%] 23.8% [23.4%–23.9%]
explore sufficiency (CG-8) — pooled over every answered explore call
answered explore calls 5 6
explore again 2 40% 3 50%
Read a file we returned 0 0% 3 50%
Read a file we did not return 0 0% 0 0%
Grep/Glob 0 0% 0 0%
moved on / answered 3 60% 0 0%
explore allocation efficiency (CG-9) — share of returned bytes the answer cited
pooled efficiency 96.9% 82.0%
per-run efficiency 100.0% [92.5%–100.0%] 81.9% [81.9%–82.0%]
contamination — the CLI must never be how codegraph is reached
CLI calls that RETURNED output 0 0
CLI attempts blocked 0 0
这个例子的读法:基线臂把 18% 的 envelope 花在了一个答案从未引用的文件上,因此 Agent 在 6 次调用中的 3 次里 Read 了我们已经返回过的文件,整次运行以 82% 效率收场;新构建送出了正确的字节——该桶 5 次中 0 次、96.9%——而残差大体相当。只看 occupancy 会判定两臂等价,这正是三指标并排的价值。
对比表是"did it move?";逐运行块才是"why?"。只有逐运行块会指出哪个 query 落了空、Agent 转而去读了哪个文件,通常足以用 scripts/agent-eval/probe-explore.mjs 复现一次 miss。compare-arms.mjs 的表格统一按 median [min–max] 渲染,原因见下文"小样本"一节。
哪个桶指向哪个修复
Sufficiency 的桶被刻意设计成每个桶对应一个不同的修复方向,其中两个直接挂钩其他指标:
Read a file we returned→ allocation(分配)问题:文件对了,字节错了(被裁掉了)。同一批运行上预期 allocation efficiency 也偏低。注意不对称性——效率指标会给一个"被引用但裁剪掉了部分内容、Agent 不得不去读"的文件其 section 记 100% 分,这个桶就是为此而设的捕获器。Read a file we did not return/Grep/Glob→ recall(召回)问题:文件根本没浮出来。Allocation efficiency 对此完全失明——envelope 只是缺了一块。explore again→ 构造上就是模糊的。它说明响应没有回答,但不说明是分配还是召回问题;后续 query 通常能分辨。moved on / answered→ sufficient(充分),但充分不等于正确。
指标实现原理(源码级补充)
以下三点是读懂指标块里那些数字的前提,均在 parse-run.mjs 中实现。
Occupancy:测的是真 token,不是估算。 对每个 assistant 请求,ctx_k = input_tokens + cache_read_input_tokens + cache_creation_input_tokens 是该请求完整 prompt 的精确 token 数,相邻请求之差 gap_k 就是新追加内容的量,按字符比例把 gap 拆给其中的各 tool_result。chars/token 比值只在"字符 ≥80% 为工具结果"的 gap 上校准(避免 assistant 输出在转录中欠代表时把整个 delta 记到某个小结果上),实测 explore 输出约 2.2–2.3 chars/token,bytes/4 的经验值会低估约 40%。内容离开窗口有两条路,都被跟踪:compact_boundary 事件清空此前的驻留集;micro-compaction 下按 FIFO 逐出最老的 tool result(短缺超过 max(200 tok, 5%) 容差才算逐出,真实 shed 是数千 token 量级)。
Sufficiency:Agent 的"下一步动作"是免费的地面真值。 分类器把每次已应答的 codegraph_explore 按其后的第一个实质动作分桶,并有三条保真规则:同一条 assistant 消息里与 explore 并发发出的 Read 不构成裁决(响应还不存在,单独计为 concurrent);ToolSearch/TodoWrite 这类无信号工具被跳过;subagent 的调用是独立线程(转录里以 parent_tool_use_id 交错标记),父线程的裁决是对"委派本身"的判断——按子 Agent 第一个实质动作来评,否则会把子 Agent 的 grep 误记成父线程对某次 explore 的裁决。Bash 命令还会被意图解析:sed -n 100,200p file 读作 Read,grep/rg/find 读作搜索,带重定向/here-doc 的写文件命令不算读。
Allocation:按引用归因,两个通道。 computeAllocation 从渲染后的 markdown(而非诊断 sidecar——sidecar 只存在于较新构建,无法测基线臂)解析出 explore 的 per-file section,然后从 Agent 的最终答案中提取引用:PATH 通道(答案点出文件,含 lib/response.js:126-220 与裸 basename——裸名只在扩展名确实出现在 envelope 中时放行,避免 res.send 被误认作文件)和 SYMBOL 通道(代码 span 中的符号,且该符号只由目标文件的 section 头列为定义才计分;出现在 ≥3 个返回文件中的名字过于通用,弃用——否则 send/get 会把半个 envelope 标成"已用",而乐观偏差是这个指标唯一不能倾斜的方向)。被返回两次的文件计两次——因为它占用了窗口两次。
汇总视图下仍然成立的注意事项
各指标文档有完整清单,以下是会改变你对表格本身的读法的那几条:
- Allocation efficiency 是相对量,不是绝对量。 归因靠引用,而 Agent 可以"用了但从未点名"一个文件(用它来排除,或据此建立模型)。误差单向,只能在同一问题上比较构建,绝不能把数字引用为"codegraph 浪费了 N% 的返回内容"。语料中位数落在 80% 区间,是因为这些 flow 类问题的答案要遍历整条链;区分度在 p25 及以下。
- Occupancy 的占比不跨宿主迁移。 基准是 Claude Code、名义 200k 窗口(
CG_WINDOW_TOKENS可覆盖)。窗口大小、系统提示、压缩策略在别处都不同;能迁移的是两臂之间的比值,百分比不是对 Cursor 的主张。 - 比对的必须是正确的一对。 在 with/without A/B 中,是 codegraph 残差对 without 臂的 file-access 残差(Read + Grep/Glob + Bash)——Agent 把同样字节读进脑子的两种方式。只数 Read 工具,会把经 Bash
cat取文件的运行记成"没读任何东西"。 - 充分不等于正确,一次 Read 是"票"不是"证明"。桶仍是对的信号——Agent 去读,说明有东西缺失——但单次调用有噪声。
- 小样本,永远。 一次运行只有 1–5 次 explore 调用,单运行的百分比很粗。表格打印
median [min–max]正是为此:报告区间。RUNS>=2,下结论用战役。 - Subagent 上下文不计入 occupancy——
Task子 Agent 有自己的窗口,只有摘要回流。而 sufficiency 会跟随子 Agent 线程(委派按子 Agent 的第一个动作评判)。两个指标对委派的差异化处理是刻意的。 - 延迟工具 schema 计入 occupancy 的
base:codegraph_explore是延迟加载的,ToolSearch稍后拉取 schema,那次注入不是工具结果;fixed-overhead 行只计价一开始就存在的部分。
Contamination:先看这一行
两套 harness 都让每个臂运行在一个屏蔽 codegraph CLI 的环境里:PATH 中把二进制符号链接摘除的净化目录,外加一个 PreToolUse 钩子拦截绝对路径调用(no-cli-shim.sh,两套 harness 共用)。两层都必要——曾有 Agent 在 PATH 上拿不到 codegraph 后执行 find / -iname "*codegraph*",找到二进制并用绝对路径调起。
Contamination 行是检测的一半,与预防的一半不冗余:预防在下一次二进制落到新位置时会静默失效,计数器不会。
- 在 with/without A/B 中,一次 CLI 调用意味着 without 臂并非"without"。某次 7 仓库遍历中 15 次 without 臂运行有 14 次通过 Bash 跑了
codegraph explore——shim 之前的所有旧结果都应假定已被污染。 - 在 new/baseline A/B 中,两臂都是 codegraph-on,CLI 调用不是泄漏而是归因失败,会同时破坏三个指标:经 Bash 到达的输出在 occupancy 表里被记到 Bash 头上;经 CLI 发出的 explore 根本不是工具调用,永远到不了 sufficiency 分类器和 allocation 解析。运行会静默地把调用从上方每个数字里丢掉。
CLI attempts blocked 是良性的——Agent 试了,但没有任何内容进入窗口。CLI calls that RETURNED output 不是。parse-run.mjs 用只匹配命令位置(而非任意提及)的正则识别 CLI 调用:grep codegraph x、ls .codegraph、which codegraph 都是"看"而不是"用",放行。
测试
指标数学本身的回归用内建 selftest 覆盖:
node scripts/agent-eval/parse-run.mjs --selftest # 68/68
它对带已知答案的合成转录做断言:occupancy 的完整算术(校准、FIFO 逐出、compaction 清空)、sufficiency 的每个桶以及 same-message/thread/delegation 三条规则、allocation 的引用通道及其守卫(歧义上限、prose 不计引用、per-call 与 pooled 的口径)。selftest 特意放在 parse-run.mjs 内部而不是独立测试文件——新写的 scripts/agent-eval/*.mjs 会进入 self-query eval fixture 自己的语料,污染被评测对象。各指标的用例清单见对应指标文档。
小结
这套三指标体系的设计逻辑一句话概括:occupancy 管"留了多少",sufficiency 管"够不够",allocation 管"送得准不准",三者接在同一次运行上互相制衡——任一指标单独向好都可能被另外两个证伪。运行侧记住三件事即可:按问题选 harness(隔离改动用 ab-new-vs-baseline.sh,采用/位移用 run-all.sh,战役用 bench-readme.sh),RUNS>=2 并报区间,输出表先看 contamination 行再看其余数字。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00