
这项由北京航空航天大学软件工程团队主导的研究发表于2026年ISSTA国际软件测试与分析研讨会论文编号为arXiv:2606.26979有兴趣深入了解的读者可通过该编号查询完整原文。当你打开一张完全陌生城市的地图地图上密密麻麻都是路名却没有任何地标提示、没有这里是火车站、那边是医院的标注你该如何找到目的地你唯一的办法就是一条街一条街地搜索碰到岔路就随机选一条直到靠运气找到。现在的AI代码助手在帮程序员找Bug程序缺陷时面临的正是这种处境。这项研究的核心问题很简单如果我们在这张地图上加一些路标AI助手能更准确、更稳定地找到目的地吗一、为什么AI代码助手像个没有路标的迷路者要理解这项研究先得明白现代AI代码助手是怎么工作的。当一个程序员遇到Bug他可能会求助于Copilot Workspace、Claude Code这类AI助手。这些助手收到问题描述后会在整个代码仓库里搜索——这个过程有点像在图书馆里用关键词找书。它们用的核心工具叫grep一种按关键词匹配文本的命令行工具简单说就是哪里出现了这个词就去看哪里。这种方法在大多数情况下表现惊人地好。研究团队对比了一种基于图谱的代码定位工具LocAgent和基于关键词搜索的Codex代理结果发现关键词搜索的方式在找到正确函数这个指标上领先了23.7个百分点83.2%对比59.5%。换句话说单纯靠关键词搜索的AI已经相当能干了。但问题在于真实的代码库并不是一堆孤立的文字而是一张错综复杂的关系网。一个函数调用另一个函数一个类继承自另一个类一个配置文件的值会影响好几个完全不同的模块。这些关系就像城市里的道路连接单靠记住路名关键词是找不到的你还需要知道这条路通向哪里。研究团队举了一个生动的例子假如一个YAML配置文件里的超时时间参数改变了可能会同时影响数据库连接池、熔断器和负载均衡器而这三个模块分布在完全不同的代码文件里。一个有经验的工程师处理这种问题时会顺着依赖链一路追查先找到配置项再找所有用到它的地方再理解值是怎么传递的。而一个只会关键词搜索的AI助手每次都得重新猜下一步该看哪里效率低下而且每次运行的路径都可能不一样。更棘手的是AI的决策本身就带有随机性。同一个问题问两次AI可能走完全不同的路径看不同的文件得出不同的结论——哪怕最终都找到了答案。对于工程师来说这种不可预测性是个大麻烦如果今天AI找到了Bug明天却找不到你根本不知道是AI真的失败了还是只是运气不好。二、路标注释的设计思路轻量级、不改变AI的工作方式既然问题的根源是AI看不到代码的结构关系一个直觉上的解决方案是给AI专门建一个代码结构数据库让它查询。但研究团队做了一个小实验——他们给AI提供了一个可以查询函数调用关系的工具类似于编辑器里的查找所有引用功能结果AI几乎不用这个工具还是习惯性地用关键词搜索。这说明把结构信息放在一个需要主动查询的地方AI并不一定会去用。于是团队换了一个思路与其让AI主动去查不如把结构信息直接放在AI必然会看到的地方——代码文件本身里面以注释的形式嵌入。这就是CodeAnchor框架的核心设计。团队开发了一套工具在AI工作之前先对整个代码库做一次静态分析——就像给城市做一次勘测把所有道路连接关系记录下来——然后把这些关系以注释的形式写入代码文件。当AI后来用关键词搜索某个函数时它在搜索结果里不仅看到了函数代码本身还顺带看到了旁边的注释这个函数被A调用这个函数调用了B这个类继承自C。这就像在地图上标注了路标AI不需要改变任何工作习惯照常搜索但每次找到一个地方旁边就有路标告诉它下一步可以去哪里不需要再靠猜测。研究团队把这种机制称为检索短路——本来需要多次搜索才能发现的关联现在只需看一眼注释就能直接跳转。三、路标有哪些类型详细到什么程度才合适研究团队并没有一股脑把所有能分析出的关系都写进注释而是系统地比较了不同详细程度的路标效果。第一种是基础拓扑版本Anchor-Topo只包含四类最基本的结构关系这个文件包含哪些函数包含关系、这个文件导入了哪些其他文件导入关系、这个函数调用了哪些其他函数调用关系、这个类继承自哪个父类继承关系。注释格式非常简洁比如# 函数注释 # 函数名_get_locale_dirs# 被调用于fetch, lang_stats, update_catalogs# 函数注释结束 def _get_locale_dirs(resources, include_coreTrue):第二种是密集语义版本Anchor-Dense在基础拓扑之上额外加入了配置文件的使用关系哪段代码读取了哪个配置项、数据流关系值从哪里来、流向哪里、输入输出依赖这个函数操作了文件还是数据库、以及测试代码与生产代码的对应关系。这版本的注释更丰富但也更占空间。第三种是仅反向链接版本Anchor-Inv和基础拓扑版本的区别在于它只保留谁调用了我这个方向的链接而删掉了我调用了谁这个方向。换句话说它告诉你这个函数被哪些地方依赖着但不告诉你这个函数自己又调用了谁。这个设计是为了解决一个特殊问题后文会详细解释。四、实验是怎么做的给AI做同一道题多种答题条件对比研究团队使用了SWE-bench这个广泛认可的基准测试数据集里面收录了真实GitHub代码仓库里的Bug问题每个问题都有标准答案标注了真正需要修改哪个文件、哪个函数。实验在SWE-bench Lite274个问题和SWE-bench Verified500个问题两个子集上进行使用OpenAI的GPT-5.1-codex模型作为AI代理。为了让对比纯粹研究团队做了一件很重要的事四种版本的AI不加注释的基线版、基础拓扑版、密集语义版、仅反向链接版用的是完全一样的提示词模板提示词里完全没有提到CodeAnchor注释或者请参考注释导航之类的引导。唯一的区别就是AI看到的代码文件里有没有嵌入注释。这样做的目的是确保观察到的差异真的来自注释本身而不是来自人为的引导提示。衡量标准方面研究团队除了常规的找到了正确文件/函数的比例之外还专门设计了以下几个维度。一是交互轮次即AI平均要搜索多少次才能完成任务二是链接跟随率LFR即AI在每次导航到下一个文件时有多少比例是明确跟随了某条注释链接而不是随机搜索三是多次运行稳定性即同一个问题跑10次结果是否一致。五、基础路标的实验结果小改变实在的提升在最核心的对比——不加注释的基线版 vs. 基础拓扑注释版——上结果相当说明问题。在SWE-bench Lite274个问题上加了基础拓扑注释之后找到正确函数的比例从83.21%提升到了85.40%提升了2.2个百分点统计检验确认这不是偶然波动McNemar检验p值为0.041。同时AI完成一个任务平均需要的交互轮次从35.3轮降低到了33.7轮少了1.6轮。在SWE-bench Verified500个问题上效果相似但幅度略小找到正确函数的比例提升了1.2个百分点交互轮次减少了1.5轮。一个有趣的现象是加了注释之后在第一次搜索就直接命中正确文件的比例略有下降在Lite上降了1.5个百分点。这听起来像是退步但研究团队通过追踪轨迹发现这实际上是一种结构绕道现象AI看到注释后会先访问结构上相关的邻居文件然后顺着链接找到真正的目标函数。这些绕道的案例里有34%最终在3次打开文件之内还是找到了正确函数。本质上AI放弃了碰运气式的关键词命中换成了更扎实的结构式路径。为了验证定位准确性的提升是否真的能帮助修复Bug研究团队进一步做了一个控制实验筛选出基线版和拓扑版在推荐的前5个可疑函数上有分歧的80个问题让同一个修复AI在这80个问题上分别用两种定位结果来修复。结果拓扑版的定位让60%的问题得到了修复而基线版只有47.5%——差距达到12.5个百分点。而且有一个严格的超集性质每个基线版能修复的问题拓扑版也能修复拓扑版额外多修复了10个基线版失败的案例。六、路标太详细了反而有副作用既然基础路标有效那给路标加更多信息是不是更好密集语义版的实验结果给出了清醒的答案。在SWE-bench Lite上密集语义版和基础拓扑版在找到正确函数这个指标上完全相同都是85.40%但密集语义版的交互轮次反而比基础拓扑版多了4.9轮38.6轮 vs. 33.7轮消耗的输入词元数量也增加了18.8%530k vs. 446k。在SWE-bench Verified上密集语义版在Func10指标上微弱超出0.6389 vs. 0.6369但在Func5指标上反而略低0.6288 vs. 0.6308。密集语义版确实在一些特殊情况下发挥了作用在Lite的3个案例和Verified的15个案例中涉及复杂的隐式依赖传播比如Django的编码路径、Matplotlib的集合状态、SymPy的形状传播密集注释帮助AI找到了这些跨越多个模块的隐藏联系。但代价是密集注释让AI分心——丰富的注释会把一些本来并不关键的工具类函数放大成显眼的存在AI一看到它们就过去探索结果绕了更多弯路才到达真正的Bug所在地。这个现象可以用一个日常比喻来理解如果城市地图上每条路都标注了沿途的每家商店、每个建筑信息量太大反而让人分不清哪个才是真正的目的地。七、大型项目需要特殊的路标策略仅反向链接版的实验揭示了一个微妙但重要的规律路标的方向性对不同规模的项目影响截然不同。在SWE-bench Lite平均代码量约3.5万行的中型项目上去掉正向链接我调用了谁只保留反向链接谁调用了我会明显降低效果找到正确函数的比例从85.40%下降到82.42%交互轮次更是从33.7轮暴增到55.0轮。没有了下一步该去哪里的指引AI只能靠更多的关键词搜索来补充。但在SWE-bench Verified平均代码量约12万行的大型项目其中23%的函数是被大量其他函数调用的枢纽节点上情况完全相反仅反向链接版反而在找函数的准确率上达到了0.6329略好于基础拓扑版的0.6308而且消耗的词元数量和基础拓扑版几乎相同。为什么会有这种反转研究团队发现在大型项目里那些被大量其他函数调用的枢纽函数会积累大量的正向调用注释CALLS: foo.py:bar, baz.py:qux, ...还有20个。这些密集的注释文本在关键词搜索中大量出现导致AI看到搜索结果时枢纽函数的名字到处都是特别显眼。AI就被这些显眼的枢纽函数吸引一头扎进去探索在和Bug无关的工具函数和公共库里转了好几圈才能回到正轨。反向链接版去掉了这种正向噪音只告诉AI谁依赖着这个函数反而让搜索更精准。基于此研究团队提出了一个实用的部署建议先从代码仓库的调用图里算出平均的调用出度一个函数平均调用多少其他函数和枢纽节点比例调用出度超过10的函数占总函数的比例如果平均调用出度小于5用基础拓扑版如果大于8用仅反向链接版介于两者之间用基础拓扑版但对高度数节点做裁剪。更粗糙的判断标准是代码量5万行以下用完整拓扑10万行以上用仅反向链接。八、路标如何让AI的行为变得更稳定、更可预测研究团队对稳定性的分析是这篇论文中格外有价值的部分因为它触及了AI辅助工具在实际生产环境中的核心痛点。在轨迹行为方面研究团队对每一次AI的导航步骤做了分类如果AI从当前位置跳转到下一个位置时下一个位置出现在当前看到的注释里就算结构性跟随如果出现在当前看到的代码文本里非注释就算词汇性跟随其他情况算探索性随机跳转。链接跟随率就是前两种跳转的合计比例。在不加任何注释的基线版中链接跟随率为0.178也就是说约18%的导航步骤是跟随了某个在当前视野内出现过的线索剩余82%的步骤是随机探索。加了基础拓扑注释后链接跟随率提升到0.236结构性跟随贡献了其中的0.163。密集语义版的链接跟随率为0.212仅反向链接版为0.186。在SWE-bench Verified上所有带注释的版本都比基线版有所提升从0.147分别提升到0.174至0.212之间。更进一步研究团队计算了一个有效路标率在所有跟随注释链接的跳转中有多少比例最终落在了真正应该修复的函数上结果是Lite上27.1%Verified上26.6%。在实例层面55.2%的Lite任务和58.7%的Verified任务中至少有一次跟随注释的跳转直接命中了正确目标。这说明AI不只是机械地跟着注释走注释确实把它引向了正确的地方。在多次运行稳定性方面研究团队对每个版本、每个数据集各运行10次选取50个任务的子集共获得500组观测数据。结果显示在Lite数据集上基础拓扑版的Func5得分均值为0.7720标准差为0.022而基线版的均值为0.7400标准差为0.043。标准差几乎减半意味着每次运行结果的波动性大幅降低AI行为更加可预测。每个任务的方差均值也从0.0726降低到了0.0626高方差的反复横跳任务明显减少。在Verified数据集上带注释版的函数定位准确率均值提升标准差同样缩小Wilcoxon检验的p值为0.023统计显著。轨迹分析还发现带注释版本在不同任务之间的路径差异性用平均编辑距离衡量降低了7.2%意味着面对类似的代码结构AI会倾向于走相似的路径而不是每次各走各的。特别值得关注的是Passk指标——这个指标模拟的是只运行一次的实际使用场景。Pass1运行一次成功的概率在CodeAnchor版本中比基线版高了3.4个百分点0.776 vs. 0.742Pass3高2.3个百分点Pass5高1.3个百分点。Pass10两者相同都是0.900说明如果你愿意让AI跑10次两个版本最终都能以90%的概率找对。但实际上大多数工程师只会让AI跑一次在这个一次性场景下注释带来的稳定性提升最为明显。九、三个真实案例注释如何改变了AI的具体行为研究团队选取了三个有代表性的案例来说明注释的实际作用。第一个案例来自Django项目。问题是URL转换器抛出Http404异常时Django的调试视图会显示500错误而不是正确的技术性404页面。在没有注释的情况下AI搜索关键词resolve得到83条匹配结果开始在URLResolver.resolve函数里探索然后漂移到了base.py文件始终只找到了3个相关实体。加了注释之后AI一打开某个函数旁边的注释显示被调用于response_for_exceptionAI直接导航到exception.py找到了崩溃处理器再跟着注释里的CALLS找到RoutePattern.match总共找到8个相关实体搜索次数减少了28.6%。不过这个Django案例属于枢纽密集的大型项目注释本身消耗的词元增加了99.4%从222k到443k算是用更多输入换取更准确的探索的典型。第二个案例来自Matplotlib项目。问题是ImageGrid的坐标轴在特定设置下显示了错误的刻度标签需要修改Grid.__init__和Grid.set_label_mode两个函数。AI最初落到了私有的辅助函数_tick_only上搜索Grid __init__得到47条匹配但始终没找到正确的类。加了注释后AI看到当前函数旁边写着父类Grid被调用于Grid.__init__, Grid.set_label_mode直接沿着这条链向上追溯不需要大量搜索就找到了正确位置。这个案例中找到的函数数量从1个暴增到6个工具调用次数减少了26.7%。更有趣的是这个案例的注释反而让整体消耗的词元减少了17.8%从252k降到207k因为AI少走了大量弯路。这三个案例共同说明了一件事注释的价值在于压缩盲目探索的空间帮助AI从随机游走变成目标导向的路径跟随。十、这项研究的局限性路标也不是万能的研究团队对自身工作的局限性有清醒认识这些声明也很重要。首先所有实验都只在一种AI代理Codex上做基于Python语言的代码库。研究团队认为因为注释只是普通文本原则上任何能阅读文本的AI代理都应该能受益但这一点尚未在Claude Code、Cursor等其他主流工具上验证。其次他们的静态分析工具PyCG无法捕捉Python中的动态特性比如通过字符串动态访问属性、反射机制、运行时修改类的行为。不过他们统计了一下只有不到3%的目标函数显式使用了这类动态特性静态分析捕获了94.2%的可见导入关系和类继承关系。再者SWE-bench的问题大多数是涉及1到2跳的Bug研究团队猜测对于需要追踪更深依赖链的复杂Bug注释的帮助会更大但这需要专门设计的更难基准测试才能验证。最后在大型Hub密集项目上稳定性的提升比中型项目要弱Verified上的方差改善幅度小于LiteWilcoxon检验p值约0.11未达到显著性。说到底这项研究给了一个很实在的工程答案在强大的关键词搜索基础上加一层轻量的结构路标AI助手找Bug更准了、走的弯路更少了、每次运行的结果也更一致了而代价只是多消耗约10%的输入词元。研究的真正贡献不在于发明了一种全新的技术而在于测量清楚了加多少结构最划算——基础的调用和继承关系就够了加太多反而适得其反以及不同规模的项目需要不同方向的路标——中型项目双向路标更好大型项目只保留反向路标更好。对于那些需要AI辅助代码维护的团队来说这提供了一套具体可操作的部署指南根据代码库规模选择注释策略花最小的代价换取更可靠的AI行为。QAQ1CodeAnchor注释是怎么生成的需要人工编写吗A不需要人工编写。CodeAnchor框架包含一个离线静态分析流水线它会自动解析代码库中的所有源文件提取函数、类、配置项之间的调用关系、继承关系、导入关系等然后自动生成结构化注释并插入到对应的代码文件里。整个过程是全自动的与具体的Bug问题无关只需要针对每个代码库版本跑一次就够了。以四个Python代码库为例生成时间从6.8秒到133.4秒不等基本随代码量线性增长。Q2SWE-bench Lite和SWE-bench Verified是什么为什么要用这两个测试集ASWE-bench是一个广泛使用的代码能力评测基准它收录了真实GitHub代码仓库里的Bug问题每个问题都有标准答案标注了真正需要修改哪些文件和函数。Lite版包含274个相对简单的问题Verified版包含500个更难的问题更多跨文件依赖、多函数修改。选这两个测试集是因为它们来自真实项目、有可靠标注是评测代码理解能力的行业标准便于和其他工具做横向比较。Q3给代码加注释会不会破坏原有代码影响正常运行A不会。CodeAnchor注释是以语言特定的注释语法写入的Python用#Java/C用//本质上对代码执行没有任何影响。而且注释格式使用了统一的分隔符Annotation如果需要恢复原始代码一次正则表达式替换就能把所有注释批量删除完全可逆不留任何痕迹。