
1. PR 评审为什么总在重复劳动LLM Agent Skills 落地场景拆解PR 代码评审这件事做过的人都懂真正花时间的不是写代码而是反复解释同一类问题。命名不规范、异常没处理、日志格式不统一、硬编码密钥——这些问题在每次 PR 里换个文件、换个函数名又出现一遍。资深工程师的时间被大量消耗在「重复发现同类问题」上而真正需要人类判断的架构设计、业务边界、性能取舍反而没精力细看。LLM Agent Skills 在这里的价值是把「可规则化的评审动作」从人脑里抽出来封装成一个可复用、可回归、可版本管理的技能单元。它不是一个泛泛的「AI 帮我看看代码」而是一套带目录结构、带脚本、带规范文档、带输出格式约束的完整能力包。Agent 拿到这个 Skill 后知道先做什么、再做什么、遇到什么情况该停下来问人、输出报告长什么样。我把它用在 PR 评审流水线里的定位是这样的Skill 负责「确定性检查 结构化建议」人负责「最终判断 业务决策」。静态检查脚本跑出候选问题模型结合团队规范做语义评审最后生成一份可以直接贴到评审系统的报告。整个过程通过统一的 Key/API 通道调用模型评审结果可复现、可回归。适合谁用三类人最直接受益一是团队里负责维护 CI/评审流程的工程师可以把 Skill 挂进流水线二是 Tech Lead想把团队规范固化成可执行的检查项三是正在探索 Agent 落地的开发者想找一个有明确输入输出、容易验证效果的场景练手。PR 评审的好处是边界清晰——输入是 diff输出是报告中间过程可观测不像开放式对话那样难以评估。这一篇我会给出完整的 Skill 目录结构、可直接改写的SKILL.md、静态检查脚本、接入配置片段以及一次完整的 PR 验证动作。目标不是让你「了解概念」而是照着做完就能在自己的仓库里跑起来。2. TaoToken 前置准备统一 Key 与 API 通道接入评审流水线Skill 本身是「能力描述 脚本 资源」它要真正跑起来需要一个稳定的模型调用通道。评审流水线里最怕的是 Key 管理混乱每个脚本各存一份、环境变量命名不统一、换模型要改一堆地方。我的做法是把模型调用统一收敛到一个 API 通道Skill 里只引用环境变量不硬编码任何凭证。TaoToken 在这里承担的就是这个统一通道的角色。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end API 基址是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数配置时直接用https://taotoken.net/api即可。前置准备分三步都不复杂第一步拿到 Key。进入控制台创建 API Key路径是 https://taotoken.net/console/api-keys 。创建后立刻复制保存页面刷新后完整 Key 不会再显示。建议按用途命名比如pr-review-skill方便后续在流水线里区分不同调用来源。第二步确认模型 ID。评审场景我一般用中等推理能力的模型既能理解代码语义又不至于每次评审成本过高。具体可用模型列表在模型对话页 https://taotoken.net/models 可以查到选一个你团队预算和效果都能接受的。第三步把 Key 和 Base URL 写进流水线的环境变量而不是写进 Skill 文件。这样 Skill 可以开源、可以共享、可以进版本库凭证始终留在运行环境里。评审流水线通常跑在 CI runner 上环境变量注入是最干净的方式。这里有个容易踩的坑很多人把 Base URL 写成带/v1或带其他路径的形式结果请求 404。TaoToken 的 API 基址就是https://taotoken.net/api具体端点由你使用的 SDK 或客户端拼接。如果你用的是 OpenAI 兼容的客户端通常配置base_url为这个地址即可客户端会自己补/chat/completions之类的路径。还有一点值得强调评审流水线里模型调用是「批量、可重试」的所以 Key 的权限和额度要单独规划。不要和线上业务共用一个 Key否则一次异常重试可能把额度打满影响生产。给评审 Skill 单独建一个 Key设置合理的额度上限出问题也容易定位。配置好之后你可以先用一个最小请求验证通道是否通。这一步不要跳过很多后续的「Skill 不工作」其实都是通道没通导致的。验证命令我放在下一节的配置片段里直接复制就能用。3. 可复制配置SKILL.md、静态检查脚本与 settings 片段这一节是全文的核心给出可以直接复制改造的三件套Skill 目录结构、SKILL.md模板、静态检查脚本以及模型调用的配置片段。先看目录结构。一个可维护的评审 Skill 建议这样组织code-review-skill/ ├── SKILL.md ├── scripts/ │ └── static_checks.py └── resources/ ├── coding_style_guide.md └── review_examples.mdSKILL.md是核心说明用 Markdown YAML frontmatter 写元数据和操作步骤。scripts/放确定性脚本比如静态检查、格式化。resources/放非执行性知识比如团队规范、优秀评审示例。这个划分的好处是Agent 知道哪些是「要跑的命令」哪些是「要读的参考」。下面是SKILL.md模板把公司名、规范要求、脚本命令换成你自己的即可--- name: code-review-assistant description: 协助审查 Pull Request 代码变更结合静态检查结果与团队代码规范给出结构化评审意见。 tags: - code-review - engineering - quality owner: Your Team Name version: 1.0.0 inputs: - name: diff_or_files description: 待审查的代码 diff 或文件内容建议按文件分块提供。 - name: context description: 可选需求背景、相关 issue 链接、重要设计约束。 outputs: - name: review_report description: 结构化的代码评审报告包含总体评价、问题列表与改进建议。 --- # 技能目标 你是一名严格但友善的高级代码审查工程师本技能用于 - 审查给定 PR 变更的代码质量与设计合理性。 - 结合静态检查脚本输出和团队代码规范指出问题并提出可执行的改进建议。 - 生成结构化的 review 报告便于直接贴到代码评审系统中。 优先级始终为正确性 可维护性 性能优化 风格一致性。 # 评审总体流程 1. 理解背景与目标阅读 PR 描述、issue 链接用 2-3 句话总结变更意图。关键信息缺失时先询问。 2. 运行静态检查脚本python scripts/static_checks.py path收集输出并分类为严重问题与一般问题。 3. 语义评审从正确性、可读性、接口依赖、异常日志四个维度检查。 4. 对照团队规范打开 resources/coding_style_guide.md引用相关章节。 5. 生成结构化报告包含概要、优点、问题列表严重程度 位置 描述 建议、总体建议。 # 输出格式与语气要求 - 使用简洁、专业的中文避免堆砌行话。 - 对严重问题保持明确态度避免模棱两可。 - 所有建议尽量配上「为什么」与「怎么改」两部分说明。静态检查脚本用 Python 写基于ast做基础检查不依赖第三方库方便在 CI 里跑#!/usr/bin/env python # coding: utf-8 简单静态检查示例脚本 用法python scripts/static_checks.py path/to/file.py 输出[SEVERITY] 文件:行号: 描述 import ast import sys from pathlib import Path MAX_FUNCTION_LENGTH 80 MAX_NESTING_DEPTH 4 class FunctionMetricsVisitor(ast.NodeVisitor): def __init__(self): self.issues [] def visit_FunctionDef(self, node): if hasattr(node, end_lineno) and hasattr(node, lineno): length node.end_lineno - node.lineno 1 if length MAX_FUNCTION_LENGTH: self.issues.append( (MAJOR, node.lineno, f函数 {node.name} 过长约 {length} 行考虑拆分。) ) depth self._compute_max_depth(node) if depth MAX_NESTING_DEPTH: self.issues.append( (MAJOR, node.lineno, f函数 {node.name} 嵌套过深约 {depth} 层可用早返回简化。) ) self.generic_visit(node) def _compute_max_depth(self, node, current0): CONTROL_NODES (ast.If, ast.For, ast.While, ast.With, ast.Try, ast.AsyncFor, ast.AsyncWith) if isinstance(node, CONTROL_NODES): current 1 max_depth current for child in ast.iter_child_nodes(node): max_depth max(max_depth, self._compute_max_depth(child, current)) return max_depth def check_for_secrets(source): issues [] SECRET_KEYWORDS [API_KEY, SECRET, TOKEN, PASSWORD] for idx, line in enumerate(source.splitlines(), start1): if any(k in line for k in SECRET_KEYWORDS) and in line: issues.append( (MAJOR, idx, 疑似硬编码敏感信息请改为配置或环境变量。) ) return issues def run_checks(path: Path): text path.read_text(encodingutf-8) root ast.parse(text) visitor FunctionMetricsVisitor() visitor.visit(root) issues list(visitor.issues) issues.extend(check_for_secrets(text)) return issues def main(): if len(sys.argv) 2: print(用法: python scripts/static_checks.py path/to/file.py, filesys.stderr) sys.exit(1) path Path(sys.argv[1]) if not path.exists(): print(f文件不存在: {path}, filesys.stderr) sys.exit(1) for severity, lineno, msg in run_checks(path): print(f[{severity}] {path}:{lineno}: {msg}) if __name__ __main__: main()接下来是模型调用的配置片段。评审流水线里我用一个settings.json统一管理Skill 脚本读环境变量配置文件只放非敏感项{ review_skill: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model_id: your-model-id, max_tokens: 4096, temperature: 0.2, timeout_seconds: 60 }, static_checks: { max_function_length: 80, max_nesting_depth: 4, secret_keywords: [API_KEY, SECRET, TOKEN, PASSWORD] } }注意api_key_env写的是环境变量名不是 Key 本身。CI 里通过 secrets 注入TAOTOKEN_API_KEY本地开发时用.env加载但.env必须进.gitignore。temperature设 0.2 是为了让评审结论稳定同一份 diff 多次运行输出差异小方便回归对比。如果你用的是 Claude Code 或类似的 Agent 客户端配置方式略有不同。以 Claude Code 为例需要在 settings 里指定 Base URL、Key 和 Model ID 三件套{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: your-key-here, ANTHROPIC_MODEL: your-model-id } }这三项缺一不可Base URL 决定请求发到哪Key 决定身份Model ID 决定用哪个模型。很多人只配了前两个结果客户端用默认模型名请求报模型不存在。Model ID 一定要和你账号下可用的模型对齐具体列表在模型对话页可以确认。配置完成后先用一个最小请求验证通道curl -s https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: your-model-id, messages: [{role: user, content: 回复 OK 两个字母}], max_tokens: 16 }返回里能看到choices数组且内容为 OK说明通道正常。这一步过了再往下接 Skill 才有意义。4. 验证请求与成功结果一次完整 PR 评审动作配置就绪后用一次真实的 PR 验证整个链路。我选一个包含典型问题的 diff函数过长、嵌套过深、硬编码了一个看起来像密钥的字符串。这种 diff 能同时触发静态检查和语义评审验证效果最直观。先准备一个测试文件demo_pr.pyimport os API_KEY sk-test-1234567890 def process_orders(orders): results [] for order in orders: if order.get(status) paid: if order.get(amount) 0: if order.get(user_id): for item in order.get(items, []): if item.get(stock) 0: if item.get(price) 0: results.append({ order_id: order[id], item: item[name], total: item[price] * item[quantity] }) return results这个函数嵌套了五层远超阈值同时第一行有硬编码的API_KEY。先跑静态检查python scripts/static_checks.py demo_pr.py预期输出类似[MAJOR] demo_pr.py:5: 函数 process_orders 嵌套过深约 5 层可用早返回简化。 [MAJOR] demo_pr.py:3: 疑似硬编码敏感信息请改为配置或环境变量。静态检查给出候选问题后把 diff 和脚本输出一起交给 Skill 做语义评审。调用时把SKILL.md的内容作为系统提示diff 和脚本输出作为用户输入。用 curl 模拟一次curl -s https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: your-model-id, messages: [ {role: system, content: SKILL.md 内容}, {role: user, content: PR diff:\ndiff 内容\n\n静态检查输出:\n[MAJOR] demo_pr.py:5: 嵌套过深\n[MAJOR] demo_pr.py:3: 硬编码敏感信息} ], temperature: 0.2, max_tokens: 4096 }成功返回的choices[0].message.content应该是一份结构化报告包含总体评价、优点、问题列表和合并建议。我实测下来报告里会明确指出嵌套可以用早返回或拆分函数解决硬编码密钥要移到环境变量并且会引用团队规范里的对应章节。这就是「可复现」的关键同样的输入因为 temperature 低、Skill 流程固定输出结构稳定可以直接进回归用例库。把这一步接进流水线的触发条件是PR 创建或更新时触发只对变更文件跑静态检查把 diff 和检查结果拼成请求发给模型报告作为 PR 评论回写。触发条件建议加两个过滤一是只对.py、.js、.ts等代码文件触发文档变更跳过二是 diff 行数超过阈值比如 2000 行时拆分成多个请求避免单次上下文过长导致截断。验证成功的标志有三个静态检查输出格式正确、模型返回结构化报告、报告里的问题位置和脚本输出能对应上。三个都满足说明 Skill 和通道都工作正常可以进入日常使用。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth接入过程中遇到的报错八成集中在四类。我把真实遇到过的现象和排查路径列出来对照着看能省不少时间。第一类401 Unauthorized。现象是请求返回{error: {message: Invalid API key}}或类似。原因通常是 Key 没注入、Key 复制时带了空格、或者环境变量名和配置里写的不一致。排查顺序先echo $TAOTOKEN_API_KEY确认变量有值且无多余空白再确认配置文件里api_key_env写的名字和实际环境变量名完全一致最后确认 Key 没有过期或被删除。如果用的是 Claude Code 这类客户端检查ANTHROPIC_API_KEY是否设置正确注意有些客户端读的是ANTHROPIC_AUTH_TOKEN两者别混。第二类local proxy failed。这个报错通常出现在客户端配置了本地代理但代理没启动或者 Base URL 指向了本地地址。排查时先确认ANTHROPIC_BASE_URL或base_url是不是https://taotoken.net/api而不是http://localhost:xxxx。如果确实需要本地转发确认转发进程在跑、端口没被占用。多数情况下把 Base URL 改回官方 API 地址就能解决。第三类reading choices 相关报错。现象是客户端报cannot read property choices of undefined或reading choices。这通常意味着返回体不是预期的 JSON 结构可能是请求路径错了比如 Base URL 多写了/v1导致 404返回的是 HTML 错误页也可能是模型 ID 不存在返回了错误对象。排查方法先用第 3 节的 curl 命令直接请求看原始返回。如果 curl 正常但客户端报错说明是客户端配置问题如果 curl 也报错看返回体里的error.message通常是模型名不对或路径不对。第四类OAuth 相关报错。有些客户端走 OAuth 流程而不是 API Key配置不当会报OAuth token invalid或authentication failed。如果你用的是 API Key 模式确认客户端没有强制走 OAuth如果确实需要 OAuth按客户端文档完成授权流程。评审流水线场景我建议统一用 API Key简单可控不依赖交互式授权。除了这四类还有一个隐蔽问题请求超时。评审大 diff 时模型响应可能超过 60 秒客户端默认超时太短会中断。解决办法是在配置里把timeout_seconds调到 120 或更高同时把大 diff 拆分成多个请求。拆分粒度建议按文件每个文件一个请求最后合并报告。排查时养成一个习惯先用 curl 验证通道再验证客户端配置最后验证 Skill 逻辑。三层分开测问题定位快很多。很多人一上来就怀疑 Skill 写得不对结果折腾半天发现是 Key 没注入。6. 把评审 Skill 接进日常Coding Plan 与长期迭代Skill 跑通一次不难难的是让它稳定进入日常评审流程并且随着团队规范演进而迭代。这里有两个实践点值得展开。第一把评审 Skill 纳入 Coding Plan 管理。评审不是一次性任务而是长期运行的工程能力。你需要规划它的调用频率、额度预算、模型选型、回归周期。比如每月用一批历史 PR 做回归对比报告质量有没有下降每季度 review 一次coding_style_guide.md把新出现的规范补进去。这些都属于 Coding Plan 的范畴有规划才不会让 Skill 变成「上线即弃」的玩具。相关入口在 https://taotoken.net/coding-plan 适合需要长期跑 Agent 任务的团队。第二建立回归用例库。每次发现 Skill 漏报或误报就把对应的 diff 存下来标注期望结果作为下次迭代的测试样本。我试过用 20 个历史 PR 做回归跑一遍大概几分钟能快速发现规则调整带来的副作用。这个库不需要复杂工具一个目录加一个清单文件就够。第三控制误报率。评审 Skill 最大的敌人不是漏报而是误报太多导致开发者直接忽略报告。静态检查的阈值要按项目实际情况调MAX_FUNCTION_LENGTH和MAX_NESTING_DEPTH不是越小越好。语义评审部分在SKILL.md里明确要求「只报有把握的问题不确定的放到建议区而不是问题区」能显著降低噪音。第四报告回写要克制。不要每个 PR 都刷一大段评论开发者会烦。建议只回写 Blocker 和 Major 级别的问题Minor 级别汇总成一行提示。报告里带上「本次评审由 Skill 生成仅供参考」的说明把最终判断权留给人。如果你还在选模型或对比不同通道的效果可以先用模型对话页做小样本测试确认评审质量符合预期再接入流水线。接入文档在 https://taotoken.net/doc 有更详细的参数说明和端点列表配置遇到不确定的地方可以对照查。最后说一个我踩过的坑一开始我把 Skill 的SKILL.md写得太长塞了太多规则结果模型注意力被分散反而漏掉了关键问题。后来精简到只保留核心流程和优先级把细节规范移到resources/里按需引用效果明显好转。Skill 不是越长越好结构清晰、重点突出才是关键。