给 AI Agent 的查询接口

本章要解决的问题

Agent 应该通过哪些结构化工具查询代码图谱?

读者读完应获得什么

  1. 能给出最小工具 schema。
  2. 能返回带来源与置信度的结果。
  3. 能记录 query_trace。

本章不讲什么

  • 不实现完整权限系统。
  • 不让 Agent 直接任意写图谱。

设计原则

  1. 输入明确、输出结构化
  2. 结果带来源证据
  3. 标注不确定性
  4. 查询可追踪
  5. 写操作与查询分离

接口设计的第一层挣扎:什么算“一个工具”

第一次给 Agent 开口时,容易掉进两个极端:要么只给一个“问仓库”的万能工具,要么把每个小查询都做成工具。前者等于没有契约,Agent 只是换了个方式读文本;后者会让 Agent 在选择工具上耗尽上下文——Anthropic 在 context engineering 里也强调“人类工程师说不清该用哪个工具时,模型只会做得更差”。

折中判据是看下游消费:一个查询结果要被哪些字段消费,就独立成一个工具。related_tests 之所以独立于 find_callers,是因为验证报告和测试门禁只吃 tests 字段;architecture_rules 独立,是因为 CI 门禁和 Review 证据只吃 rules。工具边界跟着消费端走,而不是跟着实现难度走。

对这 5 个工具,它们恰好覆盖了 Agent 改码周期的完整闭环:

定位(find_symbol)→ 扩展(find_callers/callees)→ 影响(impact_analysis)→ 验证(related_tests)→ 约束(architecture_rules)

少一个,闭环就断一环:没有 related_tests,Agent 就不知道要跑什么测试;没有 architecture_rules,它只会“看起来合理地”跨模块。

工具清单

find_symbol

{
 "name": "find_symbol",
 "input": {"query": "DiscountPolicy.apply"},
 "output": {
 "matches": [
 {
 "id": "method:DiscountPolicy#apply",
 "file": "src/main/java/com/minishop/pricing/DiscountPolicy.java",
 "start_line": 4,
 "end_line": 9
 }
 ]
 }
}

find_callers / find_callees

{
 "name": "find_callers",
 "input": {"symbol": "method:DiscountPolicy#apply", "depth": 3},
 "output": {
 "callers": [
 {"id": "method:PricingService#calculateTotal", "confidence": "high"}
 ]
 }
}

impact_analysis

输入 Diff 或 changed files,输出与影响面章节一致的结构。

related_tests

{
 "input": {"symbol": "method:DiscountPolicy#apply"},
 "output": {
 "tests": [
 "test:PricingServiceTest#shouldApplyVipDiscount",
 "test:OrderServiceTest#shouldCreateVipOrderWithDiscount"
 ]
 }
}

语义约定:返回直连该符号的 tests 边 ∪ 直连其调用方闭包的 tests 边。上例中 PricingServiceTest 直连 apply;OrderServiceTest 直连 calculateTotal(apply 的调用方),经闭包并入。金标 code-graph.json 中没有 OrderServiceTest -> apply 直连边,实现按闭包查询才能与影响面报告对齐;响应宜附命中层级,避免与“仅直连”语义混淆。

architecture_rules

{
 "input": {"module": "pricing"},
 "output": {
 "rules": [
 {
 "id": "rule:pricing-no-payment",
 "status": "pass"
 }
 ]
 }
}

查询轨迹

每次调用追加:

{
 "tool": "find_callers",
 "args": {"symbol": "method:DiscountPolicy#apply"},
 "summary": "1 caller found",
 "ts": "2026-07-22T12:00:00Z"
}

轨迹应进入上下文包与验证报告。

MCP / 本地 API 映射

可先实现 CLI:

cv-query find_symbol --q DiscountPolicy.apply
cv-query find_callers --id method:DiscountPolicy#apply

再包装为 MCP tools 或 HTTP JSON。

错误处理:失败必须结构化,否则会被当成“无影响”

接口最常见的隐性缺陷是:查询失败时返回一个空数组。Agent 收到 [] 后不会认为“查询出错了”,而会认为“没有相关信息”——这对 impact_analysis 是灾难性的:空影响面会被解读成“改动没有影响,可以合并”。

因此错误必须用结构区分于空结果:

空结果(真实)  : ok=true, result=[]
失败(系统性)  : ok=false, error=UNKNOWN_SYMBOL / INDEX_STALE / PERMISSION_DENIED

具体约定:

  • 未知符号:返回 ok=false + suggestion(如“是否指 DiscountPolicy.apply?”)
  • 低置信结果:confidence=low 且 needs_confirmation=true
  • 图未索引:明确错误,绝不用幻觉补全

一句话判断:如果失败被当成空结果会误导决策,就必须区分。 这是查询接口与普通 REST API 的关键差别——因为消费方是会把“空”当结论的 Agent。

验收

  • 对 mini-shop 图谱 5 类工具可用
  • 结果可被 Agent 直接序列化进上下文包
  • 轨迹完整

工具调用与轨迹

sequenceDiagram participant Agent participant API as Agent Query API participant Store as Graph/Reports Agent->>API: impact_analysis(changed_ids) API->>Store: reverse paths + tests + rules Store-->>API: result API-->>Agent: JSON + trace_id Note over Agent,API: 失败也要结构化,禁止空影响面伪装成功

查询接口章要把“Agent 会用工具”落成 API 合同:请求什么、返回什么、失败什么样、轨迹如何记录。最危险的实现是失败时返回空影响面——模型会把它解释成“无影响”,从而大胆合并。

请把错误视为一等公民:未知 ID、图过期、权限不足都应结构化返回。成功响应则至少能支撑上下文包与验证报告的字段填充。契约稳定后,换 MCP 还是 HTTP 都只是传输层选择。

局限

  • 接口不负责保证 Agent 一定正确使用结果。
  • 无权限模型时不适合直接暴露到公网。
  • 图不完整时,工具会诚实返回空/低置信,而不是编造。

小结

  1. 工具少而稳,胜过自由对话式乱读仓库。
  2. schema 与证据字段是接口核心。
  3. 查询轨迹是审计能力。
  4. 实现可从 CLI 平滑升级到 MCP。
  5. 失败必须与空结果结构化区分——Agent 会把“空”当结论。

安全与权限最小集

即便是教学系统,也建议预留:

  1. 只读查询默认开启
  2. 写操作(若有)与查询分离
  3. 返回体避免塞入密钥/本地绝对路径敏感信息
  4. 对超大结果强制 limit + pagination

示例:

{
 "ok": false,
 "error": "RESULT_TOO_LARGE",
 "hint": "reduce depth or add filter"
}

Agent 面对该错误应收缩查询,而不是改去全文读取仓库绕过图谱。

契约测试

为防止接口漂移,实践项目应为每个工具准备契约样例:

  • 输入 fixture
  • 期望输出关键字段
  • 在 mini-shop 图谱上的金标结果

例如 find_callers(DiscountPolicy.apply) 的金标应包含 PricingService.calculateTotal。

工具响应示例

impact_analysis 响应应可直接渲染:

{
  "tool": "impact_analysis",
  "input": {"changed": ["method:DiscountPolicy#apply"]},
  "result": {
    "paths": [["method:DiscountPolicy#apply", "method:PricingService#calculateTotal", "method:OrderService#createOrder", "method:OrderController#create"]],
    "related_tests": ["test:PricingServiceTest#shouldApplyVipDiscount"],
    "risk": "medium"
  },
  "trace_id": "q-17"
}

错误响应也要结构化(未知 ID、图过期、权限不足),避免 Agent 把失败当成空影响面。

关键要点复盘

围绕「给 AI Agent 的查询接口」,读者离开本章前应能做到:

  1. 实现核心工具响应 JSON
  2. 返回 trace_id
  3. 结构化错误(未知 ID/图过期)
  4. 与上下文包字段对齐
  5. 衔接到验证报告

若任一做不到,请先复习本章例子与练习,再继续向后读。

练习

  1. 为 find_callers 写 JSON schema(输入/输出)。
  2. 设计未知符号与低置信结果的错误返回。
  3. 记录 PR-42 的完整 query_trace(至少 4 步)。

常见问题:查询接口

REST 还是 MCP?

都能;关键是工具契约稳定与可审计轨迹。

图过期如何处理?

返回结构化错误并提示重建索引。

本章导航

延伸阅读与参考资料

results matching ""

    No results matching ""