ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

open-code-review 内置工具深度解析:六大 Agent 工具、调用协议与自定义扩展实战

open-code-review 内置工具深度解析:六大 Agent 工具、调用协议与自定义扩展实战 open-code-review 内置工具深度解析六大 Agent 工具、调用协议与自定义扩展实战【免费下载链接】open-code-reviewFast, efficient, battle-tested at Alibabas scale. Hybrid architecture code review tool: deterministic pipelines LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, SQL injection), OpenAI Anthropic compatible.项目地址: https://gitcode.com/GitHub_Trending/op/open-code-reviewopen-code-review 为代码审查场景的 LLM Agent 预置了六个内置工具task_done、code_comment、file_read、file_read_diff、file_find、code_search分别承担结束循环、产出评论、读取文件、比对 diff、定位文件、全文检索的职责。本文基于仓库文档与源码逐一向你讲解每个工具的输入输出协议、阶段可用性、底层实现原理以及如何通过--tools自定义工具注册表让读者能够理解 Agent 在审查时的完整决策链路并针对团队场景裁剪工具集。工具总览六个内置工具与它们的职责边界工具注册表的内置定义位于 internal/config/toolsconfig/tools.json每个工具声明自己是否可用于规划阶段plan或主任务阶段main。下表摘自官方文档汇总了六个工具在两个阶段的可访问性工具规划阶段主任务阶段职责task_done✗✓报告审查完成终止循环code_comment✗✓生成带行号范围与修复建议的审查评论file_read✗✓读取修改后版本的指定文件区间file_read_diff✓✓读取其他文件的 diff验证跨文件假设file_find✓✓按文件名关键字定位文件code_search✓✓全仓库文本搜索普通文本或正则task_done与code_comment在规划阶段被有意禁用规划阶段是纯只读的不允许提前盖棺定论或产出评论。上下文工具 ≠ 评论目标。main_task提示词明确禁止对其他文件中的问题发表评论。file_read、file_read_diff、file_find、code_search只是帮助模型更好地理解当前文件的 diff在收集上下文过程中发现的问题会被有意忽略。跨文件问题只有当它们能从当前文件的 diff中可见时才会成为正式评论。从源码结构看阶段的过滤逻辑在 internal/config/toolsconfig/toolsconfig.go 的ToolDefsByPhase中实现planOnlytrue时只取plan_task:true的条目planOnlyfalse时只取main_task:true的条目。工具名与提供者的映射关系TaskDone、CodeComment、FileRead、FileFind、FileReadDiff、CodeSearch六个枚举及OfName解析则定义在 internal/tool/definitions.go。工具注册表tools.json 的结构与覆盖机制每个内置工具的 JSON 条目包含四个字段name工具名也是提供者在 Go 侧注册的键、plan_task、main_task两个阶段开关和definition符合 OpenAI/Anthropic 函数调用格式的完整 schema含description与parameters。要覆盖整个注册表向--tools path传入一个与内置文件结构相同的 JSON 文件即可ocr review --tools ./my-tools.json这可以实现三类目标禁用某个工具、修改工具描述以引导模型、在现有提供者基础上增加新工具。需要注意的是增加全新工具名需要在 Go 侧接线详见下文自定义与扩展工具一节仅靠 JSON 文件无法凭空添加新行为。task_done终止审查循环task_done的唯一职责是结束主循环。其入参{ name: task_done, input: { state: DONE } }字段必填取值state是DONE默认或FAILED。FAILED表示我确实无法用现有工具完成任务几乎永远不是正确选择当 Agent 返回task_done后循环立即停止 LLM 调用开始处理已累积的code_comment。值得强调的是task_done立即返回在写入会话日志之前因此state的值虽然被接受但不会被保存也不会影响进程退出码。换句话说这个工具纯粹是流程信号不是状态机。code_comment行级评论的核心产出工具这是整个审查流程的产出端模型发现的每一个问题最终都通过code_comment落成可定位到具体代码行块的评论。每个评论通过existing_code锚定到 diff 中的代码片段行号由 OCR 自动计算。输入 Schema{ name: code_comment, input: { path: string — optional, override the file path for this comment, comments: [ { content: string — the comment in the configured language, existing_code: string — snippet from the diff to anchor on, suggestion_code: string — optional fix snippet, thinking: string — optional, the models reasoning for this comment } ] } }comments是数组模型可以一次调用产出多条评论content与existing_code必填suggestion_code可选但强烈建议提供path是可选的顶层覆盖字段若缺省Agent 自动填入当前正在审查的文件即模型几乎不需要显式指定每条评论的thinking保存模型的推理过程OCR 会从模型在当前轮次输出的 reasoning 内容中提取并填充模型未输出则为空它会被写入 JSON 输出但不会显示在终端输出中。thinking仅存在于运行时。OCR 会解析并保存它但有意不将其包含在tools.json向模型声明的code_commentschema 中那里只有content、existing_code、suggestion_code。能输出thinking块的强模型会保存它多数模型不输出这完全正常。分类与严重级别从 internal/tool/code_comment.go 可以看到评论还支持category与severity两个枚举字段分类为bug/security/performance/maintainability/test/style/documentation/other严重级别为critical/high/medium/low。解析时normalizeCodeCommentCategory与normalizeCodeCommentSeverity会做小写归一化非法值分别回退为other与low。每个评论对象在解析后若缺少path或content会被跳过path缺失时使用传入的默认路径当前审查文件。锚定定位算法OCR 使用动态滑动窗口在 diff 中查找existing_code按以下顺序匹配片段的新侧——取上下文行 新增行的连续序列不含纯删除行得到新文件的行号若未命中再尝试旧侧上下文行 删除行得到旧文件行号。全量扫描新文件——若片段内无匹配则在整个修改后文件内容中逐行寻找连续匹配对应 internal/diff/resolver.go 中的resolveFromFileContent兜底。重新定位任务——若文本匹配仍然失败且 diff 非平凡OCR 会发起RE_LOCATION_TASK提示词请求模型重新给出锚定片段。匹配忽略空白差异行首尾会被裁剪、diff 的/-标记在比较前被移除因此不要求缩进完全一致。极端情况下评论会以start_line0输出向用户传达问题真实存在但需要自行定位。需要补充的是跨文件场景还有一道无模型的确定性兜底RelocateAcrossFilesinternal/diff/resolver.go会在纯字符串匹配命中唯一文件时把评论连同Path、StartLine、EndLine一起迁移到真正所属的文件零命中或多次命中都拒绝迁移避免把评论挂到错误位置。示例{ comments: [ { content: tx.Rollback() is never deferred — early returns leak the transaction., existing_code: tx, err : db.Begin()\nif err ! nil {\n return err\n}, suggestion_code: tx, err : db.Begin()\nif err ! nil {\n return err\n}\ndefer tx.Rollback() } ] }评论经 internal/tool/comment_collector.go 的CommentCollector线程安全地按 Agent 实例累积Add/Comments/CommentsForPath等供后续批处理去重、落盘与输出使用。file_read读取修改后的文件内容file_read读取文件在修改后版本中的指定行区间为模型提供 diff 之外的上文、下文或函数整体。输入 Schema{ name: file_read, input: { file_path: src/foo.go, start_line: 10, end_line: 80 } }字段必填默认值说明file_path是—相对仓库根目录的路径start_line否1行号从 1 开始end_line否文件末尾包含该行输出格式File: src/foo.go (Total lines: 220) IS_TRUNCATED: false LINE_RANGE: 10-80 10|package foo 11| 12|import ( 13| fmt …每行内容前都会带上从 1 计数的行号和|分隔符便于模型在后续code_comment中精确引用行号。输出还包含IS_TRUNCATED与LINE_RANGE元信息方便模型判断所读内容是否完整。限制单次调用最多 500 行。更长的区间会被截断置IS_TRUNCATED: true并在末尾追加Note: Results truncated to 500 lines. Please narrow your line range.常量fileReadMaxLines 500定义于 internal/tool/file_read.go。只能读取修改后的版本。要查看旧版本请改用file_read_diff。当模型需要周边上下文例如 diff 中只露出一部分的函数时应根据 diff 头 -x,y m,n 推算区间一般取m-50到mn50。底层实现上internal/tool/filereader.go 的FileReader根据审查模式决定数据来源工作区模式直接读磁盘range/commit 模式通过git show Ref:path读取指定 ref 下的文件并带有pathutil.WithinBase路径越界防护与 30 秒超时。file_read_diff检查同批次其他文件的改动当一条评论的成立与否取决于关联文件是否同步更新时例如改了接口签名却没改调用方模型可以用file_read_diff读取同一次改动集合中一个或多个其他文件的 diff。输入 Schema{ name: file_read_diff, input: { path_array: [src/api/handler.go, src/db/queries.go] } }输出格式 FILE: src/api/handler.go --- a/src/api/handler.go b/src/api/handler.go -10,1 10,2 - old line new line 1 new line 2 FILE: src/db/queries.go -5,1 5,1 - query : SELECT * query : SELECT id输出以 FILE: path 分隔每个文件随后是该文件的 git diff 原文。实现上internal/tool/file_read_diff.go 的DiffMap是在解析阶段构建的只读 diff 快照查询就是一次 O(1) 的 map 查找。错误语义如果某个路径不在改动集合中对应条目会被静默跳过如果所有请求路径都不在改动集合中工具返回Error: diff not found for the requested paths空path_array则返回Error: no files found。file_find按文件名或路径关键字定位文件file_find按相对路径或文件名关键字子串匹配在仓库中查找文件。输入 Schema{ name: file_find, input: { query_name: UserService, case_sensitive: false } }字段必填默认值说明query_name是—子串与每个文件的相对路径匹配/与\分隔符均支持case_sensitive否false设为true时区分大小写候选集与匹配策略候选文件列表的构建方式见 internal/tool/file_find.go工作区模式用git ls-files --cached --others --exclude-standard含未跟踪文件、尊重.gitignorerange/commit 模式用git ls-tree -r --name-only ref列出审查目标 ref 下的文件。非 git 目录下git ls-files失败时会退化为按文件系统遍历并同样应用.gitignore与排除目录黑名单listWalkFiles。无扩展名的文件会被跳过但Makefile、Dockerfile、LICENSE、Vagrantfile、Containerfile例外保留。匹配分两轮先按基本文件名匹配保持纯文件名查询的精确性若无结果再按完整相对路径匹配支持pkg/util这类目录级查询Windows 风格的反斜杠会被归一化为/。输出返回换行分隔的路径列表src/main/java/com/example/UserService.java src/test/java/com/example/UserServiceTest.java src/main/java/com/example/internal/UserServiceImpl.java若无文件匹配或query_name为空返回字面量// The file was not found。限制最多返回100个匹配常量fileFindMaxCount多余结果被静默丢弃。需要更宽泛的搜索时模型应改用code_search。code_search基于 git grep 的全仓库检索code_search提供全文检索底层基于git grep因此天然支持pathspec语法并尊重.gitignore。输入 Schema{ name: code_search, input: { search_text: TODO|FIXME, file_patterns: [*.go, :(exclude)vendor/], case_sensitive: false, use_perl_regexp: true } }字段必填默认值说明search_text是—普通字符串或 PCRE 模式取决于use_perl_regexpfile_patterns否整个仓库pathspec 数组用:(exclude)pat排除case_sensitive否false—use_perl_regexp否false为true时search_text按正则解释输出格式结果按文件分组每组以File: path和Match lines: n开头随后是逐条line|contentFile: path/to/example.java Match lines: 2 433| String name toolRequest.get().getName(); 438| logToolRequest(newPath, tool, toolRequest.get()); File: path/to/other.java Match lines: 1 22| var req new ToolRequest();无匹配时返回字面量No matches found。pathspec 实用配方目标file_patterns单个文件[src/main.go]所有 Go 文件[*.go]所有 Go 文件排除测试[*.go, :(exclude)*_test.go]仅某个目录[src/api/]多种类型且排除 vendor[*.go, *.ts, :(exclude)vendor/, :(exclude)node_modules/]限制与实现细节每个文件的匹配数被git grep --max-count 100限制为100因此多文件时总输出可能超过 100 条单个文件触顶时会在结果前追加Note: The results have been truncated. Only showing first 100 results.。空值或纯空白的search_text返回Error: search_text is blank不会展开为全部行。搜索目标工作区模式搜索当前工作树range/commit 模式把FileReader.Ref作为位置参数传给git grep即搜索指定 ref 下的内容internal/tool/code_search.go。命令默认带 10 秒超时非 git 目录下git grep退出码 128 时会以--no-index --exclude-standard模式重试使ocr scan对纯目录依然可用。file_patterns中含..路径穿越组件会被拒绝Error: file_patterns must not contain ..。执行模型与错误处理工具在 Agent 循环内同步执行但有两个例外见官方文档及 internal/tool/definitions.go 的注册表设计code_comment被提交给CommentWorkerPool异步处理行号解析与反射不会阻塞循环task_done立即终止处理流程并直接返回不经过提供者调用。错误处理遵循错误即工具结果的原则若工具执行失败网络故障、参数非法、文件未找到错误文本会像普通工具结果一样回传给模型例如Error: file not found: src/missing.go。随后由模型自行决定重试、换一个文件还是调用task_done收尾。如果模型调用的工具名不在注册表中OCR 不会崩溃而是返回常量tool.NotAvailableMsgError: Tool not found. ...见 internal/tool/definitions.go。这也是--tools能在运行时安全禁用工具的前提。自定义与扩展工具工具注册表支持两种轻量级扩展方式1. 禁用工具复制内置tools.json删除不需要的条目再传入--toolsocr review --tools ./my-tools.json例如想要一个只评论、不读上下文的审查器只保留code_comment与task_done即可。2. 修改工具描述保留nameGo 侧提供者按名字查找只改写description来引导模型。这是加入项目级建议最直接的手段例如使用file_read时至少读取改动周围 30 行。增加新的工具名需要在 Go 侧接线参考 internal/tool/definitions.go 中Tool/Provider接口与Registry的注册机制以及internal/tool/下各提供者的实现每个提供者实现Tool()与Execute(ctx, args)两个方法并通过Register挂入注册表Freeze后并发只读。仅仅修改 JSON 无法添加新行为。相关文档架构文档Agent 循环如何调用这些工具审查规则LLM 被引导关注哪些问题类型会话查看器如何查看过往审查中到底调用了哪些工具。【免费下载链接】open-code-reviewFast, efficient, battle-tested at Alibabas scale. Hybrid architecture code review tool: deterministic pipelines LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, SQL injection), OpenAI Anthropic compatible.项目地址: https://gitcode.com/GitHub_Trending/op/open-code-review创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表