深入解析 open-code-review 的语义文件分组:`grouping_task_system.md` 提示词与 `GROUPING_TASK` 管线原理

深入解析 open-code-review 的语义文件分组:`grouping_task_system.md` 提示词与 `GROUPING_TASK` 管线原理 深入解析 open-code-review 的语义文件分组grouping_task_system.md提示词与GROUPING_TASK管线原理【免费下载链接】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 负责语义理解与评论生成。语义文件分组Semantic File Grouping正是这套流水线中承上启下的关键环节——它用一次廉价的 LLM 调用把一批无结构的变更文件按应该一起审查的语义聚成小组让后续每个审查子任务都能在有限上下文里聚焦一个完整主题。本文以 internal/config/template/prompts/grouping_task_system.md 为核心结合其配套的 grouping_task_user.md、底层实现 internal/agent/grouping.go 与模板加载器 internal/config/template/template.go完整讲解分组提示词的设计意图、JSON 输出协议、阈值决策链与降级兜底策略。读完本文你将理解分组阶段的全部规则与参数并能在自己的场景中调整GROUPING_MIN_FILES、GROUPING_BUNDLE_LINE_THRESHOLD等关键旋钮。分组任务在整体流水线中的位置在 pages/src/content/docs/en/architecture.md 描述的架构图中ocr review的流水线依次经过 bootstrap解析 LLM 端点、加载模板与系统规则→ diff providergit diff/ls-files/show产出[]model.Diff→ filter rules五道过滤器剔除二进制、排除路径与不支持扩展名→semantic grouping一次 LLM 调用按文件元数据聚合相关文件每组最多 10 个→ subtask dispatch按组并行派发每组一个 Plan 阶段 多轮 Main 循环→ output writer。分组编排位于 internal/agent/agent.go在派发前Agent.Run会先过滤掉被删除的文件d.IsDeleted再调用groupDiffs对剩余文件做语义分组把结果存入a.fileGroups供 JSON 输出并将本次分组调用的 token 用量记录进 runner。由此可见分组是并行派发的前置必经步骤它决定了哪些文件进入同一个审查子任务直接关系到评论上下文的质量与 token 开销。grouping_task_system.md分组提示词的精确定义grouping_task_system.md 全文如下它是分组任务的 system 角色提示词You are a file grouping assistant for code review. Group changed files into semantically related clusters that should be reviewed together. Files in the same group typically: - Belong to the same module/feature - Have producer/consumer relationships (e.g. interface and implementation) - Are i18n/config variants of the same resource (e.g. message_en.properties and message_zh.properties) - Share the same directory and work together on a single concern Rules: - Every file must appear in exactly one group. - A group may contain 1 file if it is unrelated to others. - Maximum 10 files per group. - Output ONLY a JSON array, no other text.逐条拆解其设计语义角色声明模型被定位为文件分组助手职责是把变更文件聚成语义相关、应当一起审查的簇这是整个提示词的行为锚点。同类文件判据提示词给出了四类典型的分组理由——属于同一模块/特性存在生产者-消费者关系如接口与实现是同一资源的 i18n/配置变体如message_en.properties与message_zh.properties共享同一目录并共同服务单一关注点。这四条判据直接映射到 internal/agent/agent.go 中一个分组可能横跨多个规则集如 Go 清单与 XML 清单混在一个组的处理逻辑。硬性约束每文件恰好属于一组Every file must appear in exactly one group、无关文件可单独成组、每组上限 10 个文件、只输出 JSON 数组。其中每文件恰好一组与最多 10 个文件在实现中被硬编码兜底见下文输出协议的容错与兜底。配套的 user 消息 grouping_task_user.md 定义了调用方的输入输出格式Group the following changed files: {{file_list}} Respond with a JSON array: [{label: short theme description, files: [path1, path2]}]其中{{file_list}}是模板占位符运行期被替换为buildFileList生成的变更文件清单。buildFileList复用formatDiffEntry见 internal/agent/agent.go每行形如STATUS path (N/-M)与 other-changed-files 块共用同一格式保证所有枚举文件的提示词呈现一致internal/agent/grouping_test.go 的TestBuildFileMetadataTable精确锁定了该格式ADDED a.go (10/-0) DELETED b.go (0/-5) RENAMED c.go (2/-1) MODIFIED d.go (3/-4)模板加载GROUPING_TASK如何被解析进运行时分组提示词并不是硬编码字符串而是作为模板清单manifest中的GROUPING_TASK条目被加载。查看 internal/config/template/task_template.jsonGROUPING_TASK: { messages: [ { role: system, prompt_file: grouping_task_system.md }, { role: user, prompt_file: grouping_task_user.md } ] }internal/config/template/template.go 中Template结构体的GroupingTask *LlmConversation字段承载该配置并通过go:embed//go:embed task_template.json prompts/*见 template.go把prompts/目录下的全部.md提示词文件打进二进制。LoadDefault调用resolveOptionalConversation读取prompts/grouping_task_system.md与grouping_task_user.md并裁剪尾部空白strings.TrimRight(string(data), \r\n)最终构成两段消息system 角色是本文主角user 角色携带占位符。调用分组 LLM 时callGroupingLLMinternal/agent/grouping.go运行期会用真实文件清单执行strings.ReplaceAll(m.Content, {{file_list}}, fileList)完成占位符替换。分组请求同样受 token 上限约束CompletionTokenLimit()返回MAX_COMPLETION_TOKENS默认 16384见 task_template.json若模板未设置则回退到MAX_TOKENS当maxTokens 0时实现兜底为 4096。值得注意的是grouping_test.go 的TestCallGroupingLLM_UsesTemplateMaxTokens明确说明MAX_TOKENS必须是模板自身的值而非硬编码 4096否则启用了 Anthropic extended thinkingextra_body.thinking 更大的budget_tokens的配置会因max_tokens过小而失败。JSON 输出协议与容错兜底system 提示词要求只输出一个 JSON 数组。运行时在 parseGroupingResponse 中对模型输出做了多层容错剥离 markdown 围栏若输出以 开头去掉首尾围栏行后再解析。JSON 解析失败即报错无法解析时返回错误外层groupDiffs捕获后回退为每个文件独立成组。未知路径忽略模型中出现的路径若不在diffByPath按NewPath建立中则直接跳过如TestParseGroupingResponse_UnknownFile所验证。重复文件去重同一文件出现在多个组时只保留第一个出现的组seen集合标记TestParseGroupingResponse_DuplicateFile验证了这一行为。未覆盖文件兜底模型漏掉的任何文件都会被追加为以文件路径为 label 的单文件组。分组完成后还会经过两道硬性阀门internal/agent/grouping.goenforceMaxFilesPerGroupmaxFilesPerGroup 10超出 10 个文件的组按 10 个一批切分——这是对提示词Maximum 10 files per group的代码级强制TestEnforceMaxFilesPerGroup_Split验证 25 个文件切成 10105 三块。enforceGroupTokenBudget若一组 diff 的总 token 数llm.CountTokens(d.Diff)求和超过tokenLimit则该组按文件拆分为单文件组label 追加(split: path)标记TestEnforceGroupTokenBudget_Split验证。分组结果的结构定义在 internal/agent/grouping.goFileGroup{Label string, Diffs []model.Diff}是内部表示FileGroupInfo{Label, Files}是其 JSON 导出形态最终通过Agent.FileGroups()进入 JSON 输出见 agent.go。决策链何时调用 LLM、何时本地兜底并非所有变更集都要花一次 LLM 调用做分组。groupDiffsinternal/agent/grouping.go的决策顺序是单文件短路len(diffs) 1时无条件跳过分组直接返回单文件组label 用文件路径而非smallChangeSetLabel此时不打印任何终端信息但会通过emitGroupingSkipped上报 telemetry。策略选择tpl.GroupingPlan(fileCount, totalChanged)决定走哪条路。策略定义见 internal/config/template/effort.go同目录下 template.go 中的GroupingPlanfunc (t Template) GroupingPlan(fileCount int, totalChanged int64) GroupingStrategy { if t.GroupingMinFiles 0 || fileCount t.GroupingMinFiles { return GroupingViaLLM } if t.GroupingBundleLineThreshold 0 totalChanged int64(t.GroupingBundleLineThreshold) { return GroupingBundleAll } return GroupingPerFile }LLM 路径文件数达到GROUPING_MIN_FILES时走GroupingViaLLM若GroupingTask未配置消息则回退单文件组LLM 调用失败会打印[ocr] LLM grouping failed (...) falling back to per-file dispatch并回退。本地兜底路径groupWithoutLLM负责GroupingBundleAll低变更量打成一个组label 为small change set与GroupingPerFile每个文件独立成组并打印[ocr] Skipping LLM grouping for N file(s), M changed line(s) — ...说明实际形状。两个阈值参数的含义与默认值internal/config/template/task_template.json参数默认值作用GROUPING_MIN_FILES4文件数低于该值时分组的解空间极小LLM 调用不带来信息增量跳过 LLM达到该值含等于则走 LLMGROUPING_BUNDLE_LINE_THRESHOLD200文件数不足时若总变更行数低于该值则整体打包成一组高于该值则每个文件独立成组避免一轮审查注意力被分散两条阈值各自独立GROUPING_MIN_FILES 0使分组无条件走 LLMGROUPING_BUNDLE_LINE_THRESHOLD 0则永不打包。这些边界行为均有测试覆盖TestGroupDiffs_AtFileThresholdCallsLLM恰好等于阈值也调用 LLM、TestGroupDiffs_SmallLowChurnBundles低文件数 低变更量不调用 LLM 且打包成一组、TestGroupDiffs_SmallHighChurnPerFile低文件数 高变更量逐文件分组、TestGroupDiffs_BundleDisabledFallsToPerFile阈值 0 禁用打包。分组与后续阶段的衔接分组结果直接决定后续的 Plan 判定与子任务派发Plan 阶段PlanRequiredinternal/config/template/template.go以组为单位判断是否需要规划阶段——组内最大文件变更行数达到PLAN_MODE_LINE_THRESHOLD默认 50或组内 2 个以上文件合计变更行数达到PLAN_MODE_GROUP_LINE_THRESHOLD默认 100时进入 Plan这些语义在 pages/src/content/docs/en/faq.md 中有对应说明。规则注入每个组派发时resolveGroupSystemRuleinternal/agent/agent.go会为组内文件解析系统规则若组横跨多个规则集则用rules for...标签标注每个规则块归属的文件这一设计的直接诱因正是分组提示词会产出接口实现、i18n/配置变体混合组这一场景。会话记录callGroupingLLM支持通过groupingSessionOpts把分组请求/响应写入 session 历史__grouping__文件会话键internal/agent/grouping.go使分组调用在重试报告与 viewer 中可见。小结grouping_task_system.md以极简的提示词定义了文件分组的完整语义契约语义相关的聚类判据、每文件恰一组、每组上限 10 文件、严格 JSON 输出。在 open-code-review 中这份提示词由 task_template.json 的GROUPING_TASK条目加载由 internal/agent/grouping.go 执行占位符替换、响应解析、去重兜底与 token/文件数双重阀门并由GROUPING_MIN_FILES与GROUPING_BUNDLE_LINE_THRESHOLD两个阈值控制 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),仅供参考