Files
hoelee-blog/src/content/posts/zh/slashing-agent-context-with-a-code-graph.md
T
hoelee 68771101ea edit(content): review batch-1 editorial pass across 24 posts (EN + ZH)
- voice: first-person throughout (we/our -> I/my), matching the post guideline
- privacy: internal LAN IPs replaced with placeholder hostnames
  (n8n.internal, gpu-node.internal); one compose volume path generalised
- ZH twins: Traditional -> Simplified characters (site serves zh-Hans),
  whole-file renormalisation where the twin was still Traditional
- dynamicCta: true on 12 posts so the contextual dual-track CTA renders
- long configs wrapped in <details class="tech-deep-dive"> with a summary
  naming the artefact and line count
- self-hosted-tts: token refresh now writes .tmp + atomic mv, with a note on
  the 401 race the old truncating redirect created
2026-10-27 03:29:03 +08:00

9.7 KiB
Raw Blame History

title, description, pubDate, updatedDate, category, blueprint, blueprintLayer, tags, ogImage, banner, draft, dynamicCta
title description pubDate updatedDate category blueprint blueprintLayer tags ogImage banner draft dynamicCta
别再把整个 Repo 喂给 Agent:用 Code Graph 斩断 Token 膨胀与遗忘陷阱 为什么盲目向 LLM 灌入源代码会导致 Token 账单爆炸与隐式 Bug?深度解析预索引 AST 代码知识图谱如何将上下文开销削减 80% 以上。 2026-04-28 2026-10-25 ai ai-agent-automation L2-llm-gateway-agents
ai
agents
ast
performance
architecture
/og/zh-slashing-agent-context-with-a-code-graph.jpg /banners/slashing-agent-context-with-a-code-graph.jpg false true

核心痛点

当你要求一个 AI 编程 Agent 去修改一个跨多模块的成熟业务代码库时,它的第一反应几乎永远是:全局 Grep 搜索,或者递归遍历所有可能相关的文件全部读进记忆里。

在一个拥有 5 万行代码的生产仓库中,这种暴力灌入的做法会直接引发 Token 破产与智力滑坡:

  1. 一次性把 25 个互相引用的源文件塞进上下文,单次交互就能轻易吞噬 35,000 到 50,000 个 Tokens。
  2. 随着多轮调试、运行测试与打补丁的推进,单次会话的上下文体积往往在 10 分钟内突破 150,000 Tokens。
  3. 伴随工作记忆的饱和,大模型的“大海捞针(Needle in a Haystack)”检索精度会发生断崖式下跌。它开始看漏核心的类型约束,甚至凭空臆造出根本不存在的方法签名。

Anthropic 在 2025 年年中的研究曾指出:多 Agent 协作消耗的 Token 是普通单轮交互的约 15 倍,而 Token 和算力的消耗能直接解释 80% 的模型表现差异。如果只是简单粗暴地向 Agent 灌注未经提炼的原始代码,你实际上是在付出高昂账单的同时,换来更差的推理能力。

这个问题的本质在于工程认知错位:代码是由强类型、抽象语法树与符号引用构成的复杂拓扑图,根本不是非结构化的白话文本。把代码当成自然语言小说塞给大模型,等于逼迫它在每一次交互中,都耗费巨量算力去“脑补”编译器本该负责的 AST 解析工作。


踩坑复盘:传统减负方案为何全军覆没

在正式引入代码知识图谱之前,我曾在实际项目中尝试过三种常规的上下文优化方案,但无一例外在复杂业务场景下暴露出致命短板:

1. 严格限制的 Ripgrep 全局正则匹配

我曾强制 Agent 只能使用 ripgrep,禁止直接列出或批量读取文件,要求它必须搜出精准的函数名。

翻车原因:文本正则完全没有语义感知能力。当 Agent 搜索 processOrder 时,它会瞬间检索出包含该名字的测试用例、Mock 对象、注释与几十个文件里的日志打印。Agent 依然需要打开十几个候选文件,人工甄别究竟哪一个才是生产环境中的真正实现。

2. 传统向量数据库切片(Embedding RAG)

我把代码按照 500 Tokens 切片向量化存入 pgvector,由 Agent 根据需求文本召回 Top-K 相关代码段。

翻车原因:向量搜索擅长处理模糊概念匹配(“找一下和用户鉴权相关的代码”),却完全无法处理确定性的调用调用链(Call Graph)。如果 AuthService 在内部调用了一个私有辅助函数 _verifyNonce(token),除非 Prompt 里明确提到 Nonce,否则向量检索根本找不到该辅助函数。Agent 经常写出参数数量错误、或调用了已被废弃重载的残缺代码。

3. 代码文件大纲骨架(Skeleton Outline)

在构建期自动抽取每个文件的 Class 与函数签名列表(去除实现代码),整合成一份几十页的项目骨架。

翻车原因:虽然大纲塞得进上下文,但它丢失了完整的内部调用拓扑。Agent 面对骨架依然要反复猜测调用方与被调用方的真实契约,最终为了看实现细节,又退化成疯狂调用 read_file 的旧路。


终极解法:预索引 AST 代码知识图谱(codegraph)

真正的治本之策,是在 Agent 接触代码之前,就通过静态分析器将整个代码库预先索引为确定性的抽象语法树(AST)知识图谱。

我引入了 colbymchenry/codegraph,并将标准图谱查询封装为 Agent 的底层原生工具。

┌─────────────────────────────────────────────────────────────┐
│                 源码代码库 (TypeScript / Python)             │
└──────────────────────────────┬──────────────────────────────┘
                               │ AST 语法树解析与符号链接
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                预索引代码知识图谱 (.codegraph.db)           │
│                                                             │
│   • 符号精确定义、签名与行号区间                             │
│   • 上游调用方 (Callers) / 下游被调方 (Callees) 关系边      │
│   • 类继承层次与接口实现映射                                 │
└──────────────────────────────┬──────────────────────────────┘
                               │
            ┌──────────────────┴──────────────────┐
            │ 精准微型符号查询 (单次仅 ~150 Tokens) │
            ▼                                     ▼
┌──────────────────────────────┐    ┌──────────────────────────────┐
│        主写 Agent            │    │       对抗式审查模型         │
│  (针对性修改目标业务代码)     │    │  (校验拓扑契约与防御性逻辑)   │
└──────────────────────────────┘    └──────────────────────────────┘

现在,Agent 不再需要下发诸如“请通读支付模块所有代码”这样耗资巨大的指令,而是执行确定性的符号图谱探索:

# 查询 OrderProcessor.charge 的完整定义与其真实调用链(深度为 1)
codegraph query "Symbol('OrderProcessor.charge').callers()" --depth 1

图谱工具直接返回结构极其精简、经过 AST 验证的 JSON:

{
  "symbol": "OrderProcessor.charge",
  "file": "src/billing/processor.ts",
  "line_range": [42, 68],
  "signature": "(customerId: string, amountCents: number): Promise<ChargeResult>",
  "callers": [
    { "caller": "CheckoutController.submit", "file": "src/controllers/checkout.ts", "line": 104 }
  ]
}

为什么这带来了质的飞跃

  1. 上下文极度轻量:原本需要读取 5 个完整文件、消耗约 12,000 Tokens 的信息量,被压缩为仅仅 140 个 Tokens 的高密度结构化数据。
  2. 零类型幻觉:Agent 看到的是真实编译器确认的参数签名。它绝不会胡乱臆造入参类型,也不会猜测一个异步函数到底返回的是不是 Promise。
  3. 精准打击的文件修改:Agent 只需针对 processor.ts:42-68 行号区间进行定向读取与打补丁,从头到尾不需要触碰无关的几千行上下文。

经验教训:不要在运行时动态建图

刚上线这套系统时,我曾把图谱解析放在 Agent 容器启动时动态运行。对于包含大量依赖的中型项目,每次调用 Agent 都会触发长达 45 秒的 AST 重建冷启动。

改进方案: 将图谱索引构建移入本地 Git Pre-commit 钩子或 CI 流水线中。索引产物以轻量级 SQLite 文件形式持久化(.codegraph.db)。Agent 启动时直接做只读查询,单次符号寻址耗时低于 10 毫秒,彻底消除了等待延迟。


真实生产实测收益

我们在业务后端的 20 个真实 Bug 修复与新特性开发任务中,对“传统全文正则搜索”与“AST 代码图谱方案”进行了严密的对照实验。

基准评测环境说明:测试统一采用 Claude 3.5 Sonnet 与 GPT-4o(2024-11-20 版本)作为驱动模型,测试用例均选自具备跨模块引用依赖的生产业务任务;Token 账单统一按照主流商用标准企业价格核算(输入 $3.00/1M Tokens,输出 $15.00/1M Tokens)。

评估指标 传统全局文本/Grep 检索 接入 AST 代码图谱 (codegraph) 优化幅度 / 效率倍数
任务初始 Prompt 体积 41,200 tokens 1,850 tokens 开销降低 95.5%
单任务累积消耗 Token 184,000 tokens 32,400 tokens 节省 82.4%(上下文信息密度提升 5.68×)
首次生成正确补丁交互轮数 7.4 轮交互 2.1 轮交互 轮数减少 71.6%(达成有效补丁提速 3.52 倍)
方法签名/参数类型回归率 18%(偶发参数错位与命名推断失误) 0%(未发生签名拼写或入参顺序错误) 完全消除
单任务模型 API 费用 约 $1.28 约 $0.19 成本削减 85.2%

让代码回到它原本的“拓扑图”属性,Agent 才能摆脱海量噪音干扰,将其宝贵的上下文与推理算力百分之百聚焦在真正的核心修改上。