news 2026/10/27 19:02:38

AI写代码只是上半场:用Skill构建可追溯证据链,让合并更稳

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI写代码只是上半场:用Skill构建可追溯证据链,让合并更稳

1. 为什么“AI 写完代码”只是上半场,真正卡脖子的是合并那一下

我最近半年在团队里推 AI 辅助编码,从最早的补全插件一路用到现在的 Agent 式改代码,感受特别深:生成代码这件事,门槛已经被拉得很低了。你给一个足够清晰的提示词,让它读一下仓库结构,再丢一个git diff过去,它能在几分钟内吐出一版看起来相当像样的实现。但真正让我在评审会上犹豫的,从来不是“它写得对不对”,而是“我敢不敢点那个 Merge 按钮”。

这个标题里说的“敢不敢合并”,其实戳中了一个很现实的问题:AI 生成的代码,缺少一条可追溯的证据链。人写代码的时候,哪怕写得烂,你至少能通过提交信息、分支命名、关联的 issue、评审评论,拼出一个“他为什么这么改”的上下文。而 AI 改代码,很多时候你拿到的是一个孤零零的 diff,它告诉你“我改了这三个文件”,但不告诉你“我为什么改这三个文件、依据是什么、有没有漏掉边界、有没有引入新的依赖”。

所以我后来做了一件事:把“代码评审”本身封装成一个Skill,让 Agent 在提交合并请求之前,先自己跑一遍带证据链的评审流程。这个 Skill 不负责写代码,它只负责回答一个问题——这次改动,凭什么可以被合并。它输出的不是一句“LGTM”,而是一份结构化的评审报告:改了哪些文件、每个改动对应什么意图、风险点在哪、测试覆盖到什么程度、有没有触碰敏感配置。

这篇文章我想把这个 Skill 的设计思路、核心实现、实操步骤和踩过的坑完整拆一遍。适合两类人看:一类是已经在用 AI 写代码、但每次合并都心里没底的开发者;另一类是想把 Agent 能力落到工程流程里、而不是停留在“聊天玩具”阶段的团队。我会尽量把每个设计决策背后的“为什么”讲清楚,让你看完能直接照着搭一套。

2. 这个代码评审 Skill 到底解决什么问题

2.1 先搞清楚:普通 AI 评审和“有证据链”的评审差在哪

很多人已经在用 AI 做代码评审了,做法通常是:把git diff复制粘贴给模型,问一句“帮我看看这段代码有没有问题”。这确实有用,但它有几个致命短板。

第一,它没有仓库上下文。模型只看到 diff,看不到这个函数被谁调用、这个配置项在别处怎么用、这个接口的契约是什么。它给出的建议往往是“这里可以加个空值判断”,但那个空值在上游已经被保证了,属于无效建议。

第二,它没有意图对齐。diff 只说明“改了什么”,不说明“本来想改什么”。如果 AI 改代码时理解偏了,评审 AI 也会跟着偏,因为它俩看的是同一份 diff,没有独立的“需求来源”去交叉验证。

第三,它没有证据留存。评审完就完了,结论散落在聊天记录里。等到上线出问题回头查,你找不到“当时为什么认为这个改动是安全的”。

我做的这个 Skill,核心就是补上这三块:注入仓库上下文、对齐改动意图、输出可留存的证据链。它把评审从“一次对话”变成“一次可复现的流程”。

2.2 证据链具体指什么:四个必须回答的问题

我把“证据链”拆成四个必须回答的问题,Skill 的整个流程就是围绕这四个问题设计的:

  • 改了什么:精确到文件、函数、行级别的变更清单,不是笼统的“修改了用户模块”。
  • 为什么改:每个变更块对应的意图,来源可以是提交信息、关联任务、或者 Agent 自己的推理,但必须显式写出来。
  • 风险在哪:识别出高风险改动,比如数据库 schema、鉴权逻辑、并发控制、外部依赖升级。
  • 验证到什么程度:哪些改动有测试覆盖,哪些没有,没覆盖的部分靠什么保证。

这四个问题回答完,评审报告才算完整。你会发现,这其实和人类资深评审者脑子里转的东西是一样的,只是我们把它显式化、流程化了。

2.3 为什么用 Skill 而不是写个脚本

这里要解释一个选型问题。你完全可以用一个 Python 脚本调 API 来做这件事,为什么非要封装成 Skill?

因为Skill 的本质是“可被 Agent 调用的能力单元”,它和脚本的区别在于:脚本是你手动跑的,Skill 是 Agent 在需要的时候自己决定调用的。当你的编码 Agent 完成一次改动后,它可以自主触发这个评审 Skill,而不是等你记得去跑脚本。这个“自主触发”很关键,它把评审从“事后补救”变成了“流程内建”。

另外,Skill 通常带有明确的输入输出契约和描述信息,Agent 能理解“这个 Skill 是干嘛的、什么时候该用”。这比一个裸脚本对 Agent 友好得多。我在实际搭建时,就是把它注册成一个带description和参数 schema 的 Skill,Agent 在准备提交前会主动调用。

3. 核心设计拆解:证据链是怎么一步步建起来的

3.1 输入层设计:光有 git diff 远远不够

Skill 的输入设计是整个方案的地基。我最终确定的输入包含四部分,缺一不可:

{ "diff": "<git diff 的完整输出>", "commit_messages": ["<本次分支的所有提交信息>"], "repo_context": { "changed_files": ["<变更文件列表>"], "related_files": ["<与变更文件有引用关系的文件>"], "project_conventions": "<项目约定,如代码规范、目录结构说明>" }, "task_intent": "<这次改动对应的需求或任务描述>" }

为什么要commit_messages?因为提交信息里往往藏着意图。哪怕写得不规范,也能提供线索。为什么要related_files?因为这是补上下文的关键——通过静态分析找出引用了变更函数、或者被变更文件引用的文件,让评审 AI 能看到改动的影响面。

task_intent是最容易被忽略但最重要的一项。如果没有它,评审 AI 只能判断“代码本身有没有毛病”,无法判断“这个改动是不是解决了它该解决的问题”。我一般会把任务描述、验收标准一起塞进去。

提示:related_files不要无脑全量塞进去,否则 token 爆炸且引入噪音。我的做法是只取一层引用关系,并且按引用次数排序取前 20 个。

3.2 分析层设计:把评审拆成并行的四条线

一次性让模型评审整个 diff,效果往往一般,因为任务太杂。我把它拆成四条独立的分析线,每条线专注一件事,最后再汇总:

  • 变更意图线:把 diff 按逻辑块切分,为每个块标注意图,并和task_intent做对齐,找出“改了但和任务无关”或“任务要求了但没改”的部分。
  • 风险识别线:扫描高风险模式,比如 schema 变更、权限判断、异常吞掉、硬编码密钥、依赖版本变动。
  • 测试覆盖线:检查变更是否伴随测试改动,测试是否覆盖了新增分支,没覆盖的部分标记出来。
  • 一致性线:检查改动是否符合项目约定,命名、目录、错误处理风格是否统一。

这四条线可以并行跑,每条线用相对聚焦的提示词,输出质量比一次性评审高很多。这也是我踩过坑之后的调整——早期我图省事用一个大提示词,结果模型经常顾此失彼,风险识别做了但测试覆盖就敷衍了。

3.3 输出层设计:评审报告必须能被人快速扫读

输出格式我改了好几版,最终定成“结论先行 + 证据支撑”的结构:

## 评审结论 - 可合并性:建议合并 / 有条件合并 / 不建议合并 - 一句话理由:... ## 变更清单与意图 | 文件 | 变更块 | 意图 | 与任务对齐 | |------|--------|------|-----------| ## 风险点 | 风险等级 | 位置 | 描述 | 建议 | ## 测试覆盖 - 已覆盖:... - 未覆盖:... ## 待确认问题 - ...

这个结构的好处是,评审者三十秒内能抓到重点,需要深挖时再往下看。可合并性这个字段是给决策用的,待确认问题是给作者回应的,分工明确。

4. 实操搭建:从零把这个 Skill 跑起来

4.1 环境准备与依赖清单

我用的技术栈比较朴素,核心就是 Python 加一个支持工具调用的模型接口。依赖清单如下:

pip install pygit2 # 用于解析 git 仓库和 diff pip install tree-sitter tree-sitter-languages # 用于静态分析引用关系 pip install pydantic # 用于定义输入输出 schema

pygit2比直接调git命令更适合程序化处理,能拿到结构化的 diff 对象。tree-sitter用来做跨文件的引用分析,这是补上下文的关键工具。如果你不想引入 tree-sitter,退而求其次可以用正则做粗粒度匹配,但准确率会下降。

模型接口这块,我建议选支持长上下文和结构化输出的。因为 diff 加相关文件很容易超过几万 token,上下文窗口不够会截断,证据链就断了。

4.2 第一步:把 git diff 解析成结构化变更块

原始 diff 是文本,直接丢给模型不是不行,但模型容易在长 diff 里迷失。我先把 diff 解析成结构化的变更块:

import pygit2 def parse_diff(repo_path, base_ref, head_ref): repo = pygit2.Repository(repo_path) base = repo.revparse_single(base_ref) head = repo.revparse_single(head_ref) diff = repo.diff(base, head) changes = [] for patch in diff: file_path = patch.delta.new_file.path for hunk in patch.hunks: changes.append({ "file": file_path, "old_start": hunk.old_start, "new_start": hunk.new_start, "lines": hunk.lines, }) return changes

解析成块之后,每个块可以单独分析意图,最后再拼起来。这样做还有个好处:可以按块计算风险,而不是笼统地给整个 diff 打分。

4.3 第二步:用 tree-sitter 找出相关文件

这一步是补上下文的核心。思路是:对每个变更文件,解析出它定义和引用的符号,然后在仓库里找引用这些符号的文件。

from tree_sitter_languages import get_parser def find_related_files(repo_path, changed_files, max_related=20): parser = get_parser("python") # 1. 提取变更文件中定义的函数/类名 defined_symbols = set() for f in changed_files: with open(f, "rb") as fp: tree = parser.parse(fp.read()) # 遍历 AST 收集函数和类定义名 # ...(省略遍历细节) # 2. 全仓库扫描,找引用这些符号的文件 related = {} for root, _, files in os.walk(repo_path): for name in files: if not name.endswith(".py"): continue path = os.path.join(root, name) if path in changed_files: continue with open(path, "rb") as fp: content = fp.read() for sym in defined_symbols: if sym.encode() in content: related[path] = related.get(path, 0) + 1 # 3. 按引用次数排序取前 N 个 sorted_related = sorted(related.items(), key=lambda x: -x[1]) return [p for p, _ in sorted_related[:max_related]]

这段代码是简化版,实际用的时候要处理多语言、忽略测试文件和生成文件。但核心逻辑就是“找引用”,让评审 AI 能看到改动的影响面。

注意:相关文件不要全量塞进提示词,我一般只把每个相关文件里“引用了变更符号的那几行”截取出来,而不是整个文件。这样既保留了上下文,又控制了 token。

4.4 第三步:四条分析线的提示词设计

提示词是这个 Skill 的灵魂。我分享四条线的核心提示词骨架,你可以直接改。

变更意图线:

你是一个代码评审专家。下面是一次代码变更的 diff 和对应的任务描述。 请把 diff 按逻辑块切分,为每个块标注: 1. 这个块做了什么改动 2. 这个改动对应任务描述的哪一部分 3. 是否存在与任务无关的改动 任务描述:{task_intent} Diff:{diff}

风险识别线:

你是一个安全与稳定性评审专家。请扫描下面的 diff,识别高风险改动。 重点关注:数据库 schema 变更、鉴权与权限逻辑、并发与锁、异常处理、 外部依赖升级、硬编码配置、日志泄露。 对每个风险点给出等级(高/中/低)、位置、描述和建议。 Diff:{diff} 相关上下文:{related_context}

测试覆盖线:

下面是代码变更和对应的测试变更。请判断: 1. 新增或修改的逻辑是否有对应测试 2. 测试是否覆盖了新增的分支和边界 3. 哪些改动没有测试覆盖 代码变更:{diff} 测试变更:{test_diff}

一致性线:

下面是代码变更和项目约定。请检查改动是否符合项目约定: 命名规范、目录结构、错误处理风格、日志格式。 指出不符合的地方并给出修改建议。 项目约定:{project_conventions} Diff:{diff}

四条线跑完,把结果汇总成前面说的报告结构。汇总这一步我建议也交给模型做,但给它明确的模板,避免它自由发挥。

4.5 第四步:把 Skill 注册给 Agent

最后一步是让 Agent 能调用它。我用的是带工具调用能力的接口,把 Skill 描述成这样一个工具:

{ "name": "code_review_with_evidence", "description": "在提交代码合并请求前,对当前分支的改动进行带证据链的评审。返回结构化的评审报告,包含变更意图、风险点、测试覆盖和可合并性建议。当 Agent 完成代码修改、准备提交时应该调用此工具。", "parameters": { "type": "object", "properties": { "base_ref": {"type": "string", "description": "对比的基准分支,如 main"}, "head_ref": {"type": "string", "description": "当前分支"}, "task_intent": {"type": "string", "description": "本次改动对应的任务描述"} }, "required": ["base_ref", "head_ref", "task_intent"] } }

description里我特意写了“当 Agent 完成代码修改、准备提交时应该调用”,这是给 Agent 的触发提示。实测下来,写清楚触发时机,Agent 自主调用的准确率会高很多。

5. 实测效果与踩坑记录

5.1 一个真实案例:它抓出了我漏掉的权限问题

上周我用这个 Skill 评审一次改动,任务是“给导出接口加一个时间范围过滤”。AI 写的代码逻辑没问题,测试也加了。但风险识别线报了一个中风险:导出接口的权限判断被挪到了过滤逻辑之后。

我一看,确实是。原来的代码是先判断用户有没有导出权限,再执行导出。AI 重构时把权限判断和过滤逻辑合并了,导致过滤参数非法时会先抛异常,异常信息里可能泄露了内部字段名。这个问题人眼扫 diff 很容易漏,因为逻辑“看起来”是对的。这就是证据链的价值——它不只看逻辑对不对,还看改动有没有破坏原有的安全边界。

5.2 踩过的坑:相关文件找太多反而降智

早期我为了“上下文充分”,把相关文件全量塞进去,结果评审质量反而下降。模型被大量无关代码干扰,开始提一些莫名其妙的建议,比如“这个工具函数应该加类型注解”,而那个函数根本没在这次改动里。

后来我改成只截取“引用了变更符号的那几行”,并且限制在 20 个文件以内,质量立刻回升。这印证了一个经验:上下文不是越多越好,而是要精准。给评审 AI 的上下文,应该像给人类评审者的“变更影响面说明”,而不是把整个仓库倒给它。

5.3 踩过的坑:意图对齐不能只靠提交信息

我一开始以为提交信息够用了,结果发现团队里提交信息写得五花八门,有的就一个“fix”,根本提取不出意图。后来我强制要求调用 Skill 时必须传task_intent,并且这个字段从任务系统里自动拉取,不靠人手写。这样意图对齐的准确率从大概六成提到了九成以上。

5.4 常见问题速查表

问题现象可能原因解决办法
评审报告空洞,只说“建议加测试”测试覆盖线提示词太泛在提示词里要求指出具体未覆盖的分支
风险识别漏报相关上下文不足检查 related_files 是否包含调用方
报告太长没人看输出没做结论先行强制第一段输出可合并性和一句话理由
Agent 不主动调用 Skilldescription 没写触发时机在 description 里明确“准备提交时调用”
token 超限被截断相关文件全量塞入只截取引用行,限制文件数量

6. 关于“敢不敢合并”这件事,我的一点个人体会

搭完这套东西之后,我最大的感受是:AI 写代码的能力已经足够强,真正拖后腿的是我们对它的信任机制。信任不是靠“我觉得它写得不错”建立的,而是靠一条条可查的证据建立的。这个 Skill 做的,就是把信任从感觉变成证据。

我现在合并 AI 写的代码,流程是这样的:Agent 改完代码,自己触发评审 Skill,生成报告;我看报告里的可合并性结论和风险点;如果是有条件合并,我就重点看那几个待确认问题;确认没问题再合并。整个过程比之前快,而且心里踏实。因为我知道,如果出了问题,我能顺着报告里的证据链回溯,找到是哪一环的判断出了偏差。

这个 Skill 后续还能扩展。比如把评审报告自动附到合并请求的描述里,让人类评审者也能看到;比如把历史评审结论存起来,形成项目的“评审知识库”,下次遇到类似改动可以直接参考。我还在试的一个方向是,让评审 Skill 和测试 Skill 联动——评审发现测试没覆盖的分支,自动触发测试生成。这些等跑顺了再单独写。

如果你也在用 AI 写代码,我建议你先别急着追求“生成得更快”,先把“合并得更稳”这件事解决掉。毕竟代码写出来是要上线的,敢合并,才是真的生产力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 19:02:20

多智能体系统实战:DeepAgents、MCP、A2A、Skills四层架构搭建指南

多智能体系统这两年从论文里的概念一路卷到了工程落地&#xff0c;但真正动手搭过的人都知道&#xff0c;把几个Agent凑在一起跑通Demo只是起点&#xff0c;难的是让它们 可编排、可互通、可扩展 ——也就是标题里说的那三件事。DeepAgents、MCP、A2A、Skills这四个词放在一起…

作者头像 李华
网站建设 2026/10/27 19:02:25

FDE工程师实战指南:RAG与Agent协同落地方法论

1. 这不是“AI课”&#xff0c;而是FDE工程师的生存地图&#xff1a;从岗位能力到个人创造的真实断层 你刷到过太多标题带“AI产品”“Agent实战”“RAG速成”的课程&#xff0c;点进去发现要么是调用OpenAI API跑通一个demo就收工&#xff0c;要么是堆砌概念讲三天LangChain架…

作者头像 李华
网站建设 2026/10/27 19:02:20

MCP协议与LangGraph实战:多Server工具调用编排指南

1. 从一次多工具调用的踩坑说起 去年年底我接手了一个内部工具链整合的活儿&#xff0c;需求说起来很简单&#xff1a;让一个对话式助手能同时调用公司内部的代码仓库查询、数据库表结构读取、以及一个自研的部署状态检查接口。三个能力&#xff0c;三个不同的后端服务&#xf…

作者头像 李华
网站建设 2026/10/14 23:02:19

AI日报:多智能体协作、模型部署与创作工具链的工程化实践

今天的AI日报&#xff0c;我照例先把邮箱、技术社区和项目更新日志翻了一遍&#xff0c;再动手把几个热点工具各跑了十来分钟。整体感觉是&#xff1a;多智能体协作、AI编程助手、AI内容生产这三条线&#xff0c;今天都有能拆开细说的进展。这份文章不打算做新闻陈列&#xff0…

作者头像 李华
网站建设 2026/10/13 10:14:57

JSP+Access网上购物系统开发:从ODBC配置到部署迁移全攻略

简介&#xff1a;这是一套基于JSP与Access数据库的网上购物系统完整项目&#xff0c;采用浏览器/服务器模式&#xff0c;覆盖商品浏览、购物车、订单生成等主要业务流程&#xff0c;是Java Web课程设计或毕业设计的常见选题。面向需要完整体验项目开发过程、希望获得可运行范例…

作者头像 李华