[控场AI]
· 6 分钟阅读· 3,103 字

让AI代理用确定性工具做代码分析:实践与思考

让AI代理用确定性工具做代码分析:实践与思考

让 AI 代理引用静态分析工具的确定性输出来调查代码库,并明确区分工具证据与 LLM 分析。

文章探讨如何让 AI 代理在调查陌生代码库时,优先引用 ripgrep、ast-grep、Serena、CodeQL 等确定性工具的输出作为证据,以避免上下文溢出并保证结果可复现。作者按采用难度和覆盖范围对工具做了分层选型,并通过实验发现:AI 在缺工具时会自建脚本,但自建工具同样需要审查;ripgrep 与 ast-grep 结果差异源于注释混入,交叉验证很重要;Serena 主要在类型判定和影响分析上辅助;LLM 在理解代码真实含义与不成文规则上仍有不可替代的价值。当前策略是让 LLM 写报告但引用工具证据,并与自身分析明确分开,同时为每个调查目标重新选工具。

当面对一个陌生的代码库时,如何回答"如果外部接口变了,我需要改哪些地方"这类问题?作者的做法是让 AI 代理去调查,但要求它引用确定性工具的输出作为证据,并将 LLM 自身的分析明确区分开来。

Visualizing Code: Making Use of Deterministic Computation

初始方向:让 AI 引用静态分析工具的输出

直接让 AI 读完整个代码库会导致上下文溢出,而且结果不可复现。作者的核心思路是:让代理引用静态分析工具的输出作为证据。

具体策略分两步:根据以往的人工调查经验确定调查步骤,然后为这些步骤准备执行确定性计算的工具,让调查尽可能基于这些工具的输出。

作者选定的工具是 ripgrep、ast-grep、Serena 和 CodeQL,按采用难度和覆盖范围做了筛选。

调查流程与工具选型

不同调查场景需要不同工具。作者将调查分为几种情况:从整体到细节、穷举匹配的字符串、列出引用某处的代码。

ripgrep 是快速便捷的 grep 版本,擅长穷举查找名称和字符串,也适合复核其他工具的结果。缺点是难以区分注释、字符串字面量和代码。需要按语法缩小范围时用 ast-grep,需要类型信息时用 Serena。

ast-grep 搜索 AST 节点,查询构建灵活。虽然名字里有 AST,但内部使用 CST(具体语法树),因此可以搜索注释。它还能提取宏和预处理定义,但不做展开。

Serena 通过 MCP 提供 IDE 背后运行的语言服务器(LSP)功能,如跳转定义和查找引用。优势是跟随准确引用并解析类型,但构建索引需要时间。

CodeQL 把代码转成数据库,提供多种分析。主要用于找漏洞和错误,也能做数据流分析和计算代码库关键指标。准备成本最高。

各工具支持的语言不同,老旧语言尤其困难。有些系统只能用 ripgrep,作者也实验了仅靠 ripgrep 能走多远。

静态分析指在不运行程序的前提下,通过解析源代码的语法结构、控制流或数据流来推导程序性质的技术。它与动态分析(运行程序观察行为)相对,优势是覆盖全代码、结果可复现,代价是无法捕捉运行期才出现的行为。文章中的 ripgrep 属于最轻量的文本层分析,ast-grep 上升到语法树层,Serena 借助语言服务器引入类型与符号解析,CodeQL 则把代码转为可查询的关系数据库,支持跨过程的污点追踪与数据流分析。四者正好构成从「字符串匹配」到「语义建模」的梯度:层级越高,能回答的问题越精确,但准备成本和语言支持门槛也越高。

AST(抽象语法树) 是编译器把源码解析后得到的树状结构,只保留语法上必要的节点,丢弃括号、分号等表面细节。CST(具体语法树) 则完整保留包括空白与注释在内的全部记号,因此可以精确定位注释和格式。ast-grep 虽以 AST 为名,内部却基于 CST,这正是它能搜索注释、字符串字面量的原因。CST 的另一代价是节点更细碎,书写查询模式时需要更贴近源码原貌。理解这一点有助于判断:当需要匹配「带参数调用的函数名」时用 AST 语义更自然,而当需要匹配「某段注释里的标记」时则只有 CST 层的工具才能胜任。

实验中的发现

没有工具时,AI 会自己造工具。 在调查老旧语言时,作者要求 AI 尽可能基于确定性计算构建报告。AI 自己编写并运行了分析脚本,用结果作为证据。需要注意的是,AI 造的工具也需要审查。

ripgrep 与 ast-grep 的差异符合预期。 用两者检测外部通信,结果不同。查看后发现 ripgrep 把注释也算进去了。这说明用多个工具交叉验证很重要。

Serena 主要扮演辅助角色。 在简单试验中,只用它来交叉检查 ast-grep 和补充结果验证。遇到了一些问题,比如需要转换字符编码、外部库缺少类型信息。但在严格检查 ast-grep 标记的疑似未调用方法、用类型信息判断是否真正使用、以及回答最初的"代码变更影响分析"问题上,Serena 应该会很有用。

LLM 在阅读代码上也有价值。 一开始只让 LLM 解释确定性结果,但报告变得用处不大。用 LLM 理解代码的真实含义、不成文规则和整体流程很有价值。输出需要审查,但价值远大于成本。

为每个调查目标重新选择工具比固定工具更好。 不同系统的源码和数据不同,读 Java 想要 Java 工具,读 JSON 想要 JSON 工具。固定工具集不够用,需要调研更广的工具范围。作者认为"找工具"和"用工具"应该分开。

LSP(语言服务器协议) 是编辑器与语言分析后端之间的标准通信协议,定义了「跳转到定义」「查找所有引用」「获取类型信息」等请求。Serena 通过 MCP(模型上下文协议)把这些能力暴露给 AI 代理,相当于让代理获得 IDE 的智能感知。其关键价值在于「引用」的准确性:纯文本搜索会把同名的无关符号、注释提及一并算入,而语言服务器基于类型与作用域解析,能区分真正指向同一实体。代价是首次索引耗时,且对缺少类型信息的外部库或冷门语言可能退化。这也解释了文章中「Serena 尚处于辅助角色」的观察——它的准确性优势在疑难判定时才充分体现。

当前策略

基于以上发现,作者当前的策略是:

  • 让 LLM 写报告,但尽可能引用确定性工具的结果作为证据
  • 同时包含 LLM 自身的代理代码分析,但与前一项明确分开
  • 对 AI 自建的工具,在报告中说明其功能并附上源码
  • 为每个调查目标重新选择工具,将工具调研和使用分开,调查前定义"什么目的用什么工具"
  • 当使用了 AI 自建工具时,寻找其他做同样事情的工具有,考虑更新工具定义

思考:证据与引用的重要性

作者之前构建过 RAG 系统,理解证据和引用有多重要。但把确定性计算作为工具交给 LLM,以缩小答案模糊性,是现在才意识到的。

以前遇到这类讨论,作者常认为"带 LLM 步骤的工作流"是出路。但这次希望代理能自己选择工具并深入挖掘,同时有些步骤绝不能跳过。因此需要一个流程:先运行必需步骤,把结果交给代理,再让代理自主调查。这是"工作流中嵌入代理"的模式。

另一方面,作者也觉得这可能过度工程化。近期较聪明的模型比人类更遵循指令。随着更多人感受到这一点,对概率性答案的担忧会逐渐变化。作者认为行业对容忍度的标准会在未来两三年出现。但在过渡期,偏向安全一侧是最佳实践。

未来,如何让 AI 输出有说服力很可能决定其有用性。作者会通过实验继续思考这一点,同时关注成本。而信任的第一步,仍然是清楚说明来源。

RAG(检索增强生成) 通过在生成前检索外部知识并注入上下文,缓解大模型的知识陈旧与幻觉问题。其核心工程原则与本文一致:把答案锚定在可追溯的外部证据上,并标注引用来源,使用户能自行核验。这里存在一个共通的权衡——检索结果越确定,答案的模糊性越低,但覆盖的问题范围也越窄;反之则灵活却难以信任。文章把这一逻辑从「检索文档」迁移到「运行分析工具」,即用确定性的程序输出而非自然语言片段充当证据。理解这一映射,就能看出「引用 ripgrep/CodeQL 输出」并非工程细节,而是把 RAG 的引用纪律移植到代码调查场景。

#AI代码分析#确定性计算#静态分析工具#ripgrep#ast-grep#CodeQL#LLM代理#代码调查
分享:

相关推荐