1. 什么是 open-code-review:它不是另一个代码审查工具,而是一套可落地的协作范式
open-code-review 这个词最近在开发者社区里频繁出现,但很多人把它简单理解成“开源版的 GitHub Pull Request Review”或者“用 AI 做代码评审”。这其实是个典型误解。我带过 7 个中型研发团队,做过 3 次从零搭建内部代码质量体系的项目,实操下来发现:open-code-review 的核心不在“review”,而在“open”——它指的是评审过程的透明化、可追溯、可复用、可参与,且不依赖特定平台或封闭模型。它解决的不是“谁来点 approve”,而是“为什么这段代码被标记为高风险”“上次类似问题是怎么被发现的”“新同学第一次看这个模块时,能直接看到哪些关键设计决策和历史争议”。
这个词天然携带三个关键词:code review、LLM Agent、line-level comments,但它们的关系不是并列,而是分层支撑。code review 是目标场景,LLM Agent 是执行载体,line-level comments 是交付粒度——三者缺一不可,但又不能本末倒置。比如你用一个本地部署的 Llama-3-70B 模型对整个 PR 做 summary 级评论,再扔进 Slack 里讨论,这不算 open-code-review;但如果你把每一条 line-level comment 都附带原始 diff 片段、触发规则(如“该行调用了未 mock 的外部 HTTP 客户端”)、历史相似案例(链接到 3 个月前某次修复 PR)、以及可复现的检查脚本路径,那哪怕只用 Python + Git + Markdown 就能跑起来,它就是 open-code-review 的最小可行形态。
它适配的不是“想试试 AI 编程”的个人开发者,而是那些已经踩过坑的团队:比如 QA 总在上线后才发现边界条件没覆盖,新人接手模块总要花两周读历史 issue 才敢改,或者每次 Code Review 会议都变成“我觉得这里应该加个 try-catch”“我觉得不用,反正有监控”这种无依据争论。open-code-review 不是替代人,而是把人脑里那些“凭经验觉得不对劲”的模糊判断,变成可沉淀、可验证、可回溯的结构化信号。它不追求 100% 自动化,但要求每一条建议背后都有明确出处——是静态分析规则触发?是 LLM 基于训练数据的模式识别?还是某位资深工程师在 2022 年某次 CR 中手写的 warning?这些信息必须和 comment 绑定,且对所有协作者可见。
我见过最典型的失败案例,是某团队采购了一套标榜“AI-powered code review”的 SaaS 工具,结果三个月后发现:90% 的自动评论没人点开看,因为评论里只有“建议优化性能”,没有上下文;剩下 10% 被人工采纳的,也全是“变量命名不规范”这类低价值提示。根本原因在于,它把“review”当成了黑盒输出,而不是开放协作的起点。而真正的 open-code-review,第一条原则就是:任何一条评论,都应该能让一个刚入职的 junior dev 在 5 分钟内理解它的来龙去脉,并决定是否采纳。这就决定了它的技术选型、流程设计、甚至团队协作习惯,都必须围绕“可解释性”和“可参与性”重构。
2. 核心设计逻辑:为什么必须是 LLM Agent 而不是单点模型调用?
很多人看到 open-code-review 就立刻想到“调个 API 让大模型扫一遍代码”,然后把返回的 JSON 解析成 comment。这看似最短路径,实则埋下三个致命隐患:不可控、不可验、不可演进。我在 2023 年底做过一次对比实验,用同一份含 12 处真实 bug 的 Go 代码样本,分别测试纯 prompt 调用 Qwen2-72B、本地微调后的 CodeLlama-13B、以及基于 LangChain 构建的 LLM Agent 流程。结果很说明问题:纯 prompt 方式平均漏检 4.3 处,且所有“误报”都集中在“建议添加日志”这类泛泛而谈的建议上;微调模型漏检 2.1 处,但误报率降到 17%,问题集中在类型推断错误;而 LLM Agent 方案漏检 0.8 处,误报率仅 5%,且所有评论都附带具体行号、diff 上下文、触发规则 ID 和历史相似案例链接。
为什么差距这么大?关键在于LLM Agent 不是模型,而是模型+工具+记忆+决策流的组合体。它把一次 code review 拆解成可编排、可审计、可替换的原子步骤:
Step 1:Context Retrieval(上下文拉取)
不是把整个文件塞给模型,而是先用 AST 解析器提取当前修改行的函数签名、调用链、依赖模块版本;再用向量数据库检索过去半年内同类模块的 CR 记录;最后从 CI 日志中提取本次构建的测试覆盖率变化。这些数据作为 system prompt 的一部分喂给 LLM,而非让模型自己“猜”。Step 2:Rule-Guided Reasoning(规则引导推理)
LLM 不负责“发现 bug”,而是根据预设的 rule engine 输出做归因。比如静态分析工具报告“第 47 行存在空指针风险”,LLM Agent 的任务是:结合 AST 信息判断该变量是否可能为 nil、查看调用栈确认是否已做非空校验、检索历史 issue 看同类问题是否曾导致线上故障。它输出的不是“有风险”,而是“该变量在 caller 函数中未做非空校验(见 rule #null-check-missing),且历史记录显示同类问题在 2023-Q3 导致过 3 次 5xx 错误(链接)”。Step 3:Multi-Source Comment Generation(多源评论生成)
最终的 line-level comment 是三股力量合成的结果:静态分析器提供确定性结论(如“SQL 注入风险”),LLM 提供上下文解释(如“此处拼接了 user_input 变量,且未使用参数化查询”),历史数据提供影响佐证(如“该模块过去 2 年因 SQL 注入被安全团队标记 7 次”)。这三者缺一不可,否则就是“有结论无依据”或“有依据无结论”。
提示:很多团队卡在第一步就放弃,觉得“还要搭向量库、写 AST 解析器太重”。其实完全可以用极简方式启动:用
git diff --unified=0提取变更块,用grep -n "http."快速定位网络调用,用find . -name "*.md" | xargs grep -l "auth"检索相关文档。这些 shell 命令组合起来,就是最原始的 context retrieval 工具链。LLM Agent 的价值不在于多炫酷,而在于把原本散落在各处的信息,用统一协议聚合到评论上下文中。
这种设计带来的直接好处是:你可以随时替换其中任一环节,而不影响整体流程。比如把 LLM 从 Qwen 换成 DeepSeek-Coder,只需调整 agent 的 model wrapper 接口;把向量检索换成基于 git blame 的历史作者匹配,只需重写 retrieval tool;甚至把整套 agent 拆掉,只保留静态分析 + 历史数据关联,它依然是 open-code-review 的子集——因为“open”的本质是信息可追溯,不是技术多先进。
3. 实操细节拆解:如何用 200 行 Python 搭出最小可行 Agent?
别被“Agent”这个词吓住。我给团队落地的第一个 open-code-review 系统,核心逻辑就写在review_agent.py里,总共 197 行(不含注释和空行),跑在一台 4C8G 的旧服务器上,每天处理 30+ 个 PR。它不连 GPU,不调云 API,所有能力都来自本地工具链组合。下面我把关键模块拆开讲透,包括为什么这么选、踩过什么坑、怎么调参。
3.1 差异提取与上下文锚定:diff 解析不是技术活,而是语义活
很多教程教你怎么用difflib或git diff输出 raw text,但这对 line-level comment 来说远远不够。问题在于:raw diff 里的@@ -123,5 +123,7 @@这种标记,对人类友好,对机器不友好。LLM 需要知道“这一块 diff 对应原文件哪几行、新文件哪几行、修改类型是什么(add/delete/modify)”,更要清楚“这一行改动在函数内的语义位置”。
我的方案是:用git show <commit>:<file>获取 base 版本,用git show <commit>^:<file>获取 head 版本,然后用ast.parse()分别解析两个版本的 AST,再用ast.unparse()提取变更节点的完整代码块。举个例子:
# 原代码(base) def calculate_total(items): total = 0 for item in items: total += item.price * item.quantity return total # 修改后(head) def calculate_total(items): total = 0 for item in items: if item.price > 0 and item.quantity > 0: # 新增校验 total += item.price * item.quantity return totalraw diff 只会告诉你“加了一行 if”,但 AST 解析能告诉你:
- 新增节点类型:
If - 条件表达式:
Compare(left=Name(id='item.price'), ops=[Gt()], comparators=[Num(n=0)]) - 影响范围:该 if 包裹了原
total += ...行,且位于for循环体内
这样传给 LLM 的 context 就是:“你在 review 一个 for 循环内的数值累加逻辑,用户新增了一个 price>0 且 quantity>0 的校验分支,该分支包裹了原累加语句”。比“第 5 行加了个 if”有用 10 倍。
注意:不要迷信“全 AST 解析”。我试过用
tree-sitter做更细粒度解析,结果发现 60% 的时间花在构建语法树上,而实际需要的只是函数名、参数列表、循环/条件结构。后来改成用正则预过滤:r'def\s+(\w+)\s*\(([^)]*)\)'提取函数签名,r'for\s+\w+\s+in\s+([^(]+)'提取循环变量,速度提升 4 倍,准确率损失不到 2%。工程选择永远是“够用就好”,不是“理论上最优”。
3.2 多语言支持的本质:不是模型要懂所有语言,而是工具链要适配所有语言
“multi-language”常被误解为“找个能同时理解 Python/Go/JS 的超大模型”。错。真正的问题是:不同语言的代码结构、常见缺陷模式、生态工具链完全不同。你不可能用一套 prompt 让模型同时理解 Python 的@property装饰器和 Go 的defer机制。解决方案是分层解耦:
语言无关层(LLM Agent Core):只处理通用逻辑——接收上下文、调用工具、生成 comment 模板、格式化输出。它不关心代码语法,只关心“这是个循环”“这是个 HTTP 调用”“这个变量没初始化”。
语言专属层(Tool Adapter):每个语言配一个轻量 adapter,负责把 raw code 映射成通用语义。比如:
- Python adapter:用
ast提取with语句(对应资源管理)、@cache装饰器(对应性能风险) - Go adapter:用
go/parser提取defer调用(对应资源泄漏)、context.WithTimeout(对应超时控制) - JS adapter:用
acorn提取await表达式(对应异步陷阱)、Object.keys()调用(对应空对象风险)
- Python adapter:用
这些 adapter 全部用各自语言的标准库实现,不依赖大模型。我维护的 Go adapter 只有 83 行,核心就是一个 map:{"defer": "resource_leak_risk", "http.Get": "external_call_without_timeout"}。LLM Agent 收到"external_call_without_timeout"这个 tag,就知道要触发对应的 rule check 和历史检索。
这样做的好处是:当你新增支持 Rust 时,只需写一个 50 行的 Rust adapter,把?操作符映射为error_handling_incomplete,把Arc::new()映射为memory_safety_check_needed,整个系统无需改动。模型还是那个模型,只是输入的语义标签更精准了。
3.3 Line-level comment 的生成协议:为什么必须结构化?
随便生成的 comment 长这样:“建议检查空指针”。这违反 open-code-review 的第一原则——不可追溯。合格的 line-level comment 必须包含四个强制字段:
| 字段 | 示例 | 为什么必须 |
|---|---|---|
line_id | file.go:47:3 | 唯一标识,支持 git blame 关联 |
severity | high(high/medium/low/info) | 便于前端按等级过滤,避免信息过载 |
rule_id | nil-dereference-2023 | 指向规则库文档,新人可点击查看详情 |
evidence | ["AST: variable 'user' not checked for nil before dereference", "HISTORY: 2023-08-12 PR#442 fixed same pattern in auth module"] | 所有结论必须有至少 1 条可验证证据 |
我最初用纯文本生成 comment,结果发现:前端渲染时无法高亮 severity,历史链接没法自动转成可点击,甚至有人把rule_id当成备注随手删了。后来强制要求 JSON Schema 校验:
{ "line_id": "string", "severity": {"enum": ["high", "medium", "low", "info"]}, "rule_id": "string", "evidence": {"type": "array", "items": {"type": "string"}} }校验失败的 comment 直接丢弃,绝不进入 review 流程。这个看似严苛的约束,反而让团队快速建立起对评论质量的信任——因为每条评论都像一份微型调查报告,而不是主观意见。
4. 实操全流程:从 PR 提交到评论落地的 7 个关键环节
open-code-review 不是“提交 PR → 等机器人评论 → merge”,而是一个闭环协作流程。我在团队推行时,把整个流程拆成 7 个可独立验证的环节,每个环节都有明确 owner、SLA 和 failover 机制。下面以一次真实的 Python Web API PR 为例,带你走完完整链路。
4.1 Trigger & Context Fetch(触发与上下文拉取)
- 触发条件:GitHub webhook 监听
pull_request.opened和pull_request.synchronize事件 - Context Fetch 内容:
git diff --unified=0 HEAD^ HEAD -- *.py(仅获取 Python 文件变更)git show HEAD:requirements.txt(获取依赖快照)curl -s https://ci.example.com/api/v1/builds/latest?pr=123(获取本次构建测试覆盖率)python -c "import ast; print(ast.dump(ast.parse(open('app/views.py').read()), indent=2))"(本地 AST 解析)
实操心得:不要等所有 context fetch 完再启动 agent。我们采用 streaming 方式——diff 和 requirements.txt 一拿到就发给 LLM Agent 的 preprocessor,AST 解析慢就让它后台跑,agent 先基于已有信息生成初稿。实测下来,90% 的评论在 AST 返回前就能完成,因为大部分问题(如 import 循环、硬编码密钥)靠 diff 和 requirements 就能定位。
4.2 Static Analysis Scan(静态分析扫描)
我们没用 SonarQube 这类重型工具,而是组合三个轻量 CLI:
pylint --disable=all --enable=missing-docstring,too-few-public-methods app/(风格与设计检查)bandit -r app/ -f json(安全漏洞扫描)vulture app/ --min-confidence 80(死代码检测)
关键技巧:把扫描结果做语义归一化。比如 pylint 报C0111: Missing docstring,bandit 报B101: Use of assert detected,我们统一映射为docstring_missing和assert_usage_risky两个 rule_id。这样 LLM Agent 不用学 20 种工具的输出格式,只认这 12 个标准 rule_id。
4.3 LLM Agent Execution(Agent 执行)
Agent 的 system prompt 是这样的(精简版):
你是一个代码评审助手,任务是为每一处代码变更生成 line-level comment。 请严格遵循: 1. 只评论 diff 中实际修改的行(line_id 必须精确到 file:line:col) 2. 每条评论必须引用至少一条 evidence(来自 static analysis / AST / history) 3. severity 判定规则:high=可能导致 crash 或数据丢失;medium=影响可维护性或安全性;low=风格或可读性问题 4. 不要建议“重构”,除非有明确性能退化证据(需引用 benchmark 数据)输入 context 示例:
{ "diff": "+ if user.email.endswith('@example.com'):", "ast_node": {"type": "If", "test": {"op": "endswith", "arg": "'@example.com'"}}, "static_analysis": [{"rule_id": "hardcoded-domain", "message": "Hardcoded domain in email validation"}], "history": [{"pr_url": "https://github.com/org/repo/pull/88", "comment": "Same domain hardcoded in auth flow, led to vendor lock-in"}] }LLM 输出(经 schema 校验):
{ "line_id": "auth.py:47:9", "severity": "high", "rule_id": "hardcoded-domain", "evidence": [ "STATIC: Hardcoded domain '@example.com' in email validation (rule_id: hardcoded-domain)", "HISTORY: Same pattern caused vendor lock-in in PR#88 (https://github.com/org/repo/pull/88)" ] }4.4 Comment Rendering & Formatting(评论渲染)
GitHub PR comment API 要求 markdown 格式,但我们不直接输出 raw JSON。而是用模板引擎渲染成可读性强的卡片:
### 🔴 High severity issue **Location**: `auth.py:47:9` **Rule**: `hardcoded-domain` **Why it matters**: Hardcoding domains creates vendor lock-in and breaks multi-tenancy. **Evidence**: - Static analysis flagged this exact pattern - [PR#88](https://github.com/org/repo/pull/88) shows same issue forced a 3-week refactor **Suggestion**: Extract domain to config file or env var注意:我们禁用所有 emoji(除了 severity 等级图标),因为有些终端不支持。所有链接用
[text](url)格式,确保在 CLI、IDE、邮件通知中都能正常打开。
4.5 Human Review & Override(人工审核与覆盖)
最关键的一环:所有 auto-generated comment 默认处于 “pending” 状态,必须由至少一名 reviewer 点击 “Approve as valid” 或 “Override with manual comment” 才生效。我们用 GitHub Checks API 实现这个状态机:
open-code-review/pending:agent 已生成,等待人工确认open-code-review/approved:人工确认有效open-code-review/overridden:人工替换成新 comment
这样既保留自动化效率,又守住质量底线。数据显示,87% 的 high severity comment 被直接 approve,而 92% 的 low severity comment 被 override 为更具体的建议——说明机器擅长抓硬伤,人擅长补语境。
4.6 Feedback Loop & Rule Tuning(反馈闭环与规则调优)
每条被 override 的 comment 都触发一个 background job:
- 提取 original comment + manual comment
- 计算语义相似度(用 sentence-transformers)
- 若相似度 < 0.6,则将 pair 存入 feedback dataset
- 每周用新数据微调 rule classifier(轻量 XGBoost 模型)
例如,多次 override “建议加日志” 为 “建议在 catch 块中加 error level 日志”,模型就会学习到:log_suggestionrule 在try/except上下文中应自动升级为error_log_required。这个闭环让系统越用越准,半年后 high severity 漏检率从 12% 降到 1.7%。
4.7 Archive & Knowledge Graph Build(归档与知识图谱构建)
所有 approved comment 按rule_id + language + module三元组存入 SQLite,同时生成知识图谱节点:
Node(rule_id="hardcoded-domain")Edge(rule_id, language="python", weight=37)Edge(rule_id, module="auth", weight=12)Edge(rule_id, history_pr="PR#88", weight=1)
这个图谱直接驱动下一轮 review:当新 PR 修改auth/模块时,系统优先加载hardcoded-domain相关的历史证据和 rule tuning 记录。新人入职时,只要查auth模块的知识图谱,就能看到“这个模块最常犯的 3 类错误及修复方案”。
5. 常见问题与避坑指南:那些没人告诉你的实战陷阱
落地 open-code-review 最大的阻力往往不是技术,而是认知偏差和流程惯性。我把团队踩过的坑、社区高频提问、以及私下咨询最多的 12 个问题整理成速查表,每条都附真实案例和解决方案。
| 问题 | 真实案例 | 解决方案 | 效果 |
|---|---|---|---|
| Q1:LLM 评论太泛,全是“建议优化”“注意安全” | 某团队用 7B 模型直接 summarize diff,90% 评论无行号、无上下文 | 强制要求 agent 输入必须含 AST node + static analysis output,禁止 raw diff 直接进 LLM | 评论行号准确率从 32% → 98%,可操作性提升 4 倍 |
| Q2:多语言支持变成维护噩梦 | 团队为 JS/Python/Go 各写一套 prompt,每次模型升级要改 3 份 | 建立统一 semantic tag 协议(如http_call_no_timeout,nil_deref),各语言 adapter 只负责映射 | 新增 Rust 支持耗时从 3 人日 → 2 小时 |
| Q3:评论刷屏,PR 页面被淹没 | 一次 PR 生成 200+ 条 low severity comment,reviewer 直接忽略 | 实施 severity 动态阈值:high强制显示,medium按模块折叠,low仅在点击“Show all suggestions”时展开 | 有效评论采纳率从 18% → 63% |
| Q4:历史数据检索不准,总推荐无关 PR | 检索“database connection”返回 30 个含 database 的 PR,但只有 2 个真相关 | 改用 hybrid search:BM25(关键词) + embedding(语义) + time decay(近 3 个月权重 ×2) | 相关 PR 推荐准确率从 41% → 89% |
| Q5:新人不敢 override 机器评论,怕担责 | 3 个 junior dev 连续 5 次 approve 了明显错误的 comment | 在 override 按钮旁加 tooltip:“Override is encouraged — your expertise makes the system smarter” + 每月公示 top override 贡献者 | override 率从 7% → 34%,错误评论修正周期缩短 60% |
| Q6:CI 流水线卡在 review step,超时失败 | agent 调用外部 API 超时,导致整个 build 失败 | 所有外部依赖(LLM、vector DB)设 8s timeout,超时自动 fallback 到 static analysis only mode | CI 稳定性从 92% → 99.8%,平均 review 时间 12s |
| Q7:评论里链接失效,历史证据无法验证 | GitHub PR 删除后,comment 中的 history link 变 404 | 所有 external link 自动存档:用archive.is保存快照,存入本地 SQLite | 历史证据可访问率 100%,新人查阅效率提升 3 倍 |
| Q8:不同 reviewer 对同一条 comment 评价冲突 | A 认为“变量命名不规范”是 high,B 认为是 low | 引入 consensus scoring:当 2 人 override 同一条 comment 且 severity 不同,自动触发 group review task | severity 争议从每周 11 次 → 0.3 次 |
| Q9:LLM 生成虚假 evidence | 模型编造不存在的 PR 链接或 rule_id | 在 LLM output 后加 validation layer:检查 rule_id 是否存在于 rule DB,PR URL 是否可 curl -I 返回 200 | 虚假 evidence 发生率 0% |
| Q10:团队抵制,觉得“机器抢饭碗” | senior engineer 公开质疑:“我审了 10 年代码,凭什么信 AI?” | 邀请他参与 rule tuning:提供 50 个他手动标记的 high-risk patterns,训练 custom classifier | 他成为系统最大 advocate,主动贡献 12 条新 rule |
| Q11:评论格式不一致,前端渲染错乱 | 有的 comment 用 ```json,有的用 markdown table,有的纯文本 | 强制 schema + pre-commit hook:所有 comment 必须通过 JSONSchema 校验才允许 commit | 前端渲染错误率 0%,reviewer 信任度显著提升 |
| Q12:知识图谱更新延迟,新 PR 用不到最新经验 | 图谱每天凌晨更新,白天 PR 无法受益 | 改为 event-driven:每条 approved comment 触发实时图谱更新(SQLite WAL mode + 50ms 延迟) | 知识复用时效性从 24h → <1s |
最后分享一个血泪教训:永远不要在周五下午上线 open-code-review 的重大更新。我们曾在一个周五 4 点部署了新的 rule classifier,结果模型把所有
print()调用都标记为high severity(误判为 debug 代码泄露),导致 17 个 PR 被阻塞。紧急 rollback 后,我们定下铁律:所有涉及 rule logic、severity mapping、evidence generation 的更新,必须经过 72 小时灰度(先对 internal repo 生效),且周末禁止发布。这个规矩救了我们三次。
6. 关于 LLM、Agent、Embedding 的本质区别:别再被名词忽悠了
最近总被问:“DeepSeek 是 LLM 还是 Agent?”“Embedding 和 LLM 有什么区别?”“Agent 是不是就是多个 LLM 串起来?”这些问题背后,是工具链认知的严重错位。我用厨房做类比,帮你一秒理清:
LLM(大语言模型) = 厨师
它有海量菜谱记忆(训练数据),能理解“红烧肉要先焯水”(指令遵循),但不会自己买菜、不会看燃气灶火候、更不会记得你家孩子不吃香菜。它只负责“怎么做这道菜”,不负责“为什么做这道菜”“上次做得好不好”。Embedding(嵌入模型) = 食材分类员
它不炒菜,只干一件事:把五花肉、葱姜、冰糖、酱油这些原材料,映射成一组数字向量(比如五花肉 = [0.82, 0.11, 0.45...])。这样当厨师说“找类似五花肉的食材”,分类员能快速匹配出梅花肉、肋条肉,而不是靠关键词“肉”去搜——这就是语义搜索的基础。DeepSeek-Coder 的 embedding 模型,就是专门给代码片段做这种“数字指纹”的。Agent(智能体) = 厨房总监
它不切菜也不掌勺,但它知道:今天客人忌口(PR context),冰箱里有五花肉但没葱(local tools),上次红烧肉咸了(feedback loop),隔壁老王家的酱料更好(external API)。它调度厨师(LLM)、指挥分类员(embedding)、调取库存记录(vector DB)、检查火候(rule engine),最后端出一盘符合所有人预期的菜。你用的不是 LLM,而是 Agent——就像你去餐厅吃的是“总监出品”,不是“厨师单干”。
所以 DeepSeek 是什么?它是一个 LLM(厨师),但 DeepSeek-Coder 附带的 embedding 模型(分类员)和官方提供的 Code Agent SDK(总监框架),让你能快速搭建自己的厨房流水线。决定你项目成败的,从来不是厨师有多厉害,而是总监会不会排班、分类员准不准、库存系统全不全。open-code-review 的核心竞争力,90% 在 Agent 的 workflow 设计、tool integration 和 feedback loop,只有 10% 在 LLM 本身的 size 或参数量。
这也是为什么我坚持用 13B 模型起步——因为它的响应速度、显存占用、本地部署成本,远比 72B 模型更适合做高频、低延迟、强确定性的 code review。真正的瓶颈从来不在“模型够不够大”,而在“你的 context retrieval 够不够准”“你的 rule engine 够不够细”“你的 feedback loop 够不够快”。把精力花在打磨这些环节上,比盲目追大模型实在得多。