首页
/ CodeGraph 互动式 A/B 实测:直接在主会话作答,还是委派给 Explore 子代理?

CodeGraph 互动式 A/B 实测:直接在主会话作答,还是委派给 Explore 子代理?

2026-09-05 22:41:00作者:段琳惟

本篇基于 CodeGraph 仓库中的实测报告 answer-directly-vs-explore-agent.md,拆解一个对 Claude Code 用户很关键的问题:当 agent 回答"X 是怎么工作的"这类结构性问题时,在主会话中直接调用 CodeGraph 作答,与把探索委派给一个一次性 Explore 子代理(用子转录吸收文件读取、保持主上下文精简),哪种方式更优?读完本篇,你将掌握:互动式 A/B 实验的完整方法论(为什么必须用 tmux 驱动 TUI 而不是 claude -p)、主会话上下文在 16 倍仓库规模下为何保持 ~50k 不变的预算机制(explore 输出的分层预算上限),以及这条结论如何直接改写了 CodeGraph 下发给 agent 的指令文案。

核心问题与结论先行

报告要回答的问题非常具体:直接在主会话用 CodeGraph 回答"how does X work?",会不会把主会话上下文撑爆?Claude Code 是不是应该把这类探索委派给 Explore 子代理(子代理在独立转录里读文件,主上下文因此保持精简)?更关键的是:当仓库规模远超 Excalidraw 时,结论会不会反转?

短答案是:不会反转。 有了 CodeGraph,主会话上下文大致是规模不变的(~50k)——因为检索是定向的、explore 的返回载荷有预算上限,仓库大 16 倍它也不会膨胀。直接作答在每一个规模上都赢:主上下文与委派路径相当甚至更精简、文件读取为 0、token 少约 28%。"为卫生而委派"的优势即使在大代码库上也只是边际性的。

重要警示:本报告的 token 数字未经复核(2026-08-05 标记)。该实验早于 parse-run.mjsresult.usage 修复(commit 04c0f8e),其"少 28% token"很可能取自一个只报告最后一个回合用量的字段——详见 call-sequence-analysis.md 中的踩坑记录。该误差会低估回合数更多的那一臂,因此如果委派臂跑得更长,真实差距大于 28%;如果两臂回合数相近,则数字大致正确。原始日志已丢失,无法重新推导——token 数字应视为指示性,而回合数、读取数、主上下文这些不依赖该字段的结论是可靠的。

实验方法论:为什么必须用互动式 TUI

方法学细节决定了这份报告的可信度,值得逐条拆解:

  • 测试框架: 通过 itrun.sh(tmux)驱动的互动式 Claude Code TUI,而不是 headless 的 claude -p。这一点至关重要:headless 模式派生 0 个 Explore 子代理,根本无法测量委派行为;只有互动 TUI 能复现用户实际看到的行为。脚本头部注释写得很直白:"headless print-mode picks the general-purpose subagent, while real interactive sessions delegate to the Explore subagent (or drive codegraph from the main thread). Only the interactive TUI reproduces the behavior users actually see."
  • 两臂(Arms): WITH = MCP 配置里启用 CodeGraph;WITHOUT = 空 MCP 配置(--strict-mcp-config)。
  • 模型: opus每臂 n = 3。主线程与子代理的转录都被解析(parse-session.mjs),Read/Bash 次数在主线程 + 所有子代理之间求和。
  • 仓库: Excalidraw(643 文件,中等规模)与 VS Code(约 10.7k 文件,大规模——约为 Excalidraw 的 16 倍)。
  • 构建版本: 0.9.4。日期: 2026-05-24。
  • 指标定义: "主会话上下文"指 TUI 上报的 Context X/Y主线程的值(子代理上下文不计入);"billable tokens" = 逐回合 assistant 用量求和(input + output + cache read + cache creation)。

从源码看,parse-session.mjs 的做法与报告完全对应:它读取 Claude Code 写入 ~/.claude/projects/<escaped-cwd>/ 的 session JSONL,tally() 函数统计主转录中每个 tool_use 块,子代理转录则从 <session>/subagents/*.jsonl 汇总——这正是"reads/bash 在 main + sub-agents 上求和"的实现。sumTokens() 按回合累加 output_tokensinput_tokens + cache_creation_input_tokens(新鲜输入)与 cache_read_input_tokens,最后以 gen + fresh 作为 billable 近似值,与报告"逐回合求和"的定义一致。

itrun.sh 本身也体现了互动式测量的工程细节:它通过 tmux send-keys 输入 prompt 并做"输入验证"(确认 prompt 前 24 个字符真的落进输入框),再按内容稳定性而非 spinner 字符串判断 agent 完成——因为某些模型流式输出最终答案时不渲染任何忙碌指示符,短阈值的中断判定会把答案截断。

结果一:Excalidraw(643 文件,中等规模)

问题:"How does Excalidraw render and update canvas elements?"

指标 WITH codegraph WITHOUT
Explore 子代理派生数 0 / 0 / 0 0 / 1 / 1(3 次中 2 次委派)
主会话上下文 51k / 49k / 50k(~50k) 48k / 34k / 26k(~36k)
总工具调用 4 / 4 / 4 16 / 55 / 37
Reads(主+子) 0 / 0 / 0 6 / 25 / 16
billable tokens ~127k ~175k

观察:没有 CodeGraph 时,Claude Code 在 3 次中的 2 次选择派生 Explore 子代理;派生与否直接决定了主上下文落在 26k 还是 48k——委派路径的主上下文收益是真实存在的,但代价是 16–55 次工具调用和 6–25 次文件读取

结果二:VS Code(约 10.7k 文件,约为 Excalidraw 的 16 倍)

问题:"How does the extension host communicate with the main process?"

指标 WITH codegraph WITHOUT
主会话上下文 47k / 43k / 50k(~47k) 54k / 29k / 31k(~38k)
Explore 子代理 0 / 0 / 0 0 / 1 / 1(2/3 委派)
codegraph 调用 ~8(search + explore×2–3 + context) 0
Reads(主+子) 0 / 1 / 0 6 / 26 / 19
billable tokens ~126k ~176k

16 倍规模的仓库,WITH 臂主上下文(~47k)与 Excalidraw(~50k)几乎一致。 这正是本报告最重要的发现。

为什么主上下文是"规模不变"的:预算上限的定向检索

报告的归因是:codegraph 的 explore 返回载荷是**有预算上限(budget-capped)且检索是定向(targeted)**的——回答一个问题只拉入相关的流/区域,不会因为仓库巨大就拉更多。因此 CodeGraph 让主会话上下文大致规模不变(~50k)。"为卫生而委派"的优势即使在大代码库上也只是边际性的——恰好与"规模上会变得重要"的预期相反。

这个归因可以在源码中得到印证。tools.ts 中定义了 ExploreOutputBudget——一个随项目规模自适应分层的输出预算("Adaptive output budget for codegraph_explore, scaled to project size"):小代码库获得更紧的总上限、更少的默认文件数、更小的单文件上限;getExploreBudget(indexedFileCount) 在每次 explore 调用时根据已索引文件数解析当前项目的预算,maxOutputChars 是总输出的硬上限,候选文件按相关性排序后按比例分摊这个预算(Split budget.maxOutputChars across ranked candidates in proportion to...)。也就是说,载荷大小由"本次问题的答案面"决定,而不是由仓库大小决定——这就是"~50k 主上下文在 643 文件与 10.7k 文件仓库上都不变"的机制来源。

报告还区分了两种"主上下文精简"路径:

  • Claude Code 自己也能做到(不用 CodeGraph):委派给 Explore 子代理(主上下文 29–31k),但代价是 17–26 次文件读取和约 28% 更多的 token。
  • CodeGraph 的方式更优:一个有上限的定向载荷——不委派、0 次读取

"Explore 子代理会用 codegraph"——复现失败

报告尝试复现一个流传的设想:Explore 子代理在委派后自己也会用 codegraph(既瘦主上下文、又低工作量)。结果:跨两个仓库共 6 次 with-codegraph 运行,Claude Code 一次都没有委派——每次都直接在主会话作答。Explore 子代理路径只出现在 WITHOUT 臂(因为那一臂的 MCP 配置里没有 codegraph,子代理用的是 grep/read)。

结论:在当前指令 + codegraph 在场的前提下,Claude Code 留在主会话——"经 Explore 子代理瘦主上下文"这个最佳情形实际并不会发生;发生的是"经有上限的 codegraph 瘦主上下文",而且它更便宜。

这个行为不是偶然,而是被指令文案主动引导的。server-instructions.ts 中随 MCP initialize 下发的指令明确写着:Codegraph 本身就是预建的搜索索引,"running your own grep + read loop, or delegating the lookup to a separate file-reading sub-task/agent, repeats work codegraph already did and costs more for the same answer"——即把查找委派给独立读文件的子任务会被视为重复劳动而被劝阻。instructions-template.ts 安装到 agent 指令文件中的 ## CodeGraph 区块也强调"用 MCP 工具或 codegraph explore CLI 直接作答",并且其注释记录了测量依据:强制委派场景下,没有该区块时子代理只有约 1/9 的运行会真正加载并使用 codegraph。README 中"Agent Tool Guidance"一节进一步说明:README 明确写道 "CodeGraph only helps when queried directly, so its instructions steer agents to answer directly rather than delegate exploration to file-reading sub-agents — otherwise a sub-agent reads files regardless and CodeGraph becomes overhead."

判决与对指令文案的改写

"直接用 codegraph 作答"对 Claude Code 同样全胜——在每一个规模上。 不需要按 agent 拆分;统一的"answer directly"指令对 Claude Code Codex / Cursor / opencode(这些工具没有 Explore 子代理机制,否则只能直接读文件)都是正确的。

这条结论直接驱动了 README 中 ## CodeGraph 示例块的更新:旧文案曾指示 agent "NEVER 直接调用 codegraph_explore / ALWAYS 派生一个 Explore 子代理"——那正是把 Claude Code 引向更差的路径(17–26 次读取、多 ~28% token)。当前仓库中的指令文案("answer directly"、"delegating the lookup to a separate file-reading sub-task/agent repeats work")就是这次实验的产物。

保留项:Explore 子代理 + codegraph 的组合为何暂不采纳

报告诚实地列出了唯一反方向的可能性:一个自己会用 codegraph 的 Explore 子代理,理论上能同时拿到瘦主上下文和低工作量。但报告给出三条不把它设为默认的理由:

  1. "answer directly" 指令在实际中阻止了委派(6 次运行 0 次委派),该路径当前根本不会发生;
  2. 主上下文收益是边际性的:~50k → ~30k,两者都只占 1M 窗口的几个百分点;
  3. 它增加一轮子代理往返。

因此结论是:值得做未来的实验,不值得设为默认。

复现与延伸阅读

本实验的原始日志已不可得(见开头警示),但仓库保留了完整的可复现工具链:

  • itrun.shitrun.sh <repo-path> <label> "<prompt>",tmux 驱动互动式 Claude Code 会话,要求 tmux 3.0+、已登录的 claude CLI 与配好的 codegraph MCP;输出目录由 AGENT_EVAL_OUT 控制(默认 /tmp/agent-eval)。
  • parse-session.mjsnode scripts/agent-eval/parse-session.mjs <project-dir>,输出主/子线程工具调用统计、billable token 估算,以及 explore 之后的充分性(sufficiency)与答案取材(allocation)分析。

延伸阅读(同目录下的对照报告,共享同一方法论与 result.usage 踩坑记录):

  • call-sequence-analysis.md:37 个 A/B 单元的调用序列分析,量化了 result.usage 只报最后一回合的字段缺陷(commit 04c0f8e 修复),并给出"读取得节省不转化为墙钟时间"的归因。
  • codegraph-ab-matrix.md:readings 减少 75% 而墙钟仅 ~16% 的 A/B 矩阵总表。

方法学上的三点经验(对做类似 A/B 的人)

  1. 测量委派行为只能用互动 TUI。 headless 模式不派生 Explore 子代理,测出来的是另一个问题。
  2. 指标定义必须跨主/子线程求和——否则子代理里的 25 次 Read 会直接从统计里消失(本实验 WITHOUT 臂的主力成本全在子转录里)。
  3. token 字段要先验证再使用。 本实验的 ~28% 差距来自一个只报末回合的字段;回合数、读取数这类计数型指标不受该缺陷影响,应作为主要判决依据。仓库后续报告在 call-sequence-analysis.md 中把"读逐回合 usage 求和,而非 result.usage"固化为了方法论规则。
登录后查看全文
热门项目推荐
相关项目推荐