oh-my-pi 逐 Hunk AI 智能暂存:解读 `git-ai-stage-hunk.md` 判定提示词的实现原理与调用链
发布时间:2026/9/12 4:50:07 作者:尧图编辑部 阅读量:1,286

oh-my-pi 逐 Hunk AI 智能暂存解读git-ai-stage-hunk.md判定提示词的实现原理与调用链【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi导读本文聚焦 oh-my-pi 编码代理中 AI 辅助选择性暂存AI-assisted selective staging的核心判定环节——系统提示词模板 git-ai-stage-hunk.md。该模板以极简的三段式结构驱动小模型对工作区中的每一个 diff hunk 做出独立yes/no裁决从而只把符合用户自然语言指令的改动加入暂存区。读完本文你将掌握模板的字段设计与语义、它在文件级 Hunk 级两阶段 AI 暂存流水线中的具体位置、模型输出的容错解析策略以及底层通过git apply --cached完成精确暂存的实现机制。模板本体一个是/否单字裁决器packages/coding-agent/src/prompts/system/git-ai-stage-hunk.md全文只有 8 行但它承载了整个逐 Hunk 智能暂存功能的判定语义A git hunk in {{path}} changes these lines: {{changed}} The user only wants to stage: {{instruction}} Is this change what the user asked for? Reply exactly one word: yes or no.它由三个模板变量和一个硬性输出约束构成{{path}}当前被判定 hunk 所属文件的仓库相对路径用于向模型交代改的是哪个文件{{changed}}该 hunk 的实际变更内容——注意它不是完整 hunk 原文而是仅由新增行开头与删除行-开头组成的精简片段详见下文上下文过滤一节{{instruction}}用户在 Git TUI 中输入的、未经修改的自然语言指令如只暂存登录功能相关的改动输出约束要求模型只回复一个单词yes 或 no。这个硬性格式约束直接服务于下游极简解析器parseVerdict。之所以选择极简的yes/no二元裁决是因为该功能刻意选用tiny/smol 级别的小模型来执行判定见 ai-stage.ts 中的resolveRoleSelection([tiny, smol], ...)以换取低延迟与低成本。与小模型打交道的提示词越少要求其输出结构化内容输出就越稳定可靠。工作流定位文件级与 Hunk 级两阶段流水线git-ai-stage-hunk.md并不是孤立使用的。它在 ai-stage.ts 的aiStage()函数中作为第二阶段Hunk 级判定的提示词被注入其上游还有一个使用 git-ai-stage-files.md 的第一阶段文件级挑选。整体流水线如下触发入口用户在 Git TUI 的 unstaged 侧边栏点击 AI 暂存wand pill调用aiStage()见 index.ts 中的case stage-ai传入cwd、用户指令instruction与当前未暂存文件列表。文件级挑选file pass将未暂存文件列表每行形如- path (kind, N −M)由describeCandidate生成一次性交给模型要求其逐字复制所有匹配路径、不匹配则回复none。文件列表每批最多 80 个FILE_BATCH 80大变更树会按批并行扇出。Hunk 级判定hunk pass对被选中文件matched中的每一个 hunk并行构建一条基于git-ai-stage-hunk.md的独立判定请求模型逐条回答 yes/no。执行暂存根据判定结果组装VcsHunkSelectionall或indices调用原生层repo.stageHunks(...)完成真正的暂存未跟踪文件则整文件stageFiles。Hunk 上下文过滤为什么{{changed}}只有 /− 行在向模板填充{{changed}}之前ai-stage.ts 做了关键预处理const changed hunk.content .split(\n) .filter(line line.startsWith() || line.startsWith(-)) .join(\n); if (changed.length 0) continue;源码注释明确解释了原因小模型容易把未变更的上下文行误读为变更内容Small judges misread unchanged context as part of the change因此只把真正的增删行喂给模型。同时过滤后的内容如果为空例如纯上下文 hunk则跳过该 hunk 不做判定。此外内容还受HUNK_CHARS 2400的头部截断保护bound(job.changed, HUNK_CHARS)超过 2400 字符的变更片段被截断并追加…防止超长 hunk 撑爆小模型的输入窗口。Hunk 本身来自 diff.ts 的parseFileHunks()——它按头部解析出每个 hunk 的index0 基、起止行号与原始内容。注意一个容易踩的坑模板侧使用的job.index是 1 基hunk.index 1因为底层HunkSelection的索引约定是 1 基代码注释特别标注了这一差异。裁决解析parseVerdict的鲁棒性设计模型输出并不总是干净的yes或no。因此 ai-stage.ts 提供了容错解析器export function parseVerdict(text: string): boolean { const lower text.toLowerCase(); const yes lower.search(/\byes\b/); if (yes 0) return false; const no lower.search(/\bno\b/); return no 0 || yes no; }规则是最早的裸yes优先只要yes出现在任何no之前就判为通过找不到yes一律判为拒绝。这兼容了模型输出yes, please stage之类的自然语言变体同时把不确定性收敛为安全的不暂存。判定的执行采用逐 hunk 并行扇出 单点容错judgeAll一个请求失败只拒绝该 hunk不会让整个流程崩溃但若所有请求全部失败则认为后端故障抛出首个错误。此外所有补全请求使用temperature: 0、disableReasoning: true、maxTokens: 4096SAFE_MAX_TOKENS兼顾 Anthropic 方言的thinking.budget_tokens下限见 ai-stage.ts进一步压缩输出随机性。底层暂存机制从裁决到git apply --cachedHunk 判定完成后ai-stage.ts 组装选择结果并调用repo.stageHunks(selections, rawDiff || null, signal)。该 API 是原生层crates/pi-natives/src/vcs.rs中stage_hunks的封装其 Rust 实现在 crates/pi-vcs/src/git/patch.rs优先使用ai-stage.ts传入的原始 worktree diffrawDiff为空时才自行生成diff_text解析 patch按路径建立by_path索引对每个选择项二进制文件或HunkSpec::All直接取整文件 patch指定索引的则用select_hunks精挑出对应 hunk并复用原文件头extract_file_header重新拼装成子 patch拼接后调用apply_patch并以cached: true等价git apply --cached、three_way: false应用到索引从而只更新暂存区、不动工作区。也就是说从模型裁决到最终落盘是一条解析 diff → 模型逐 hunk 判定 → 重拼子 patch → 应用到索引的完整链路全程不依赖调用git add -p之类的交互式命令而是用 git 格式 patch 机制精确控制暂存内容。值得强调的是该实现还有一处针对指令粒度的兜底策略如果文件级挑选有结果fileScopeAuthoritative但所有 hunk 判定全部为nostagedHunks 0代码将其解释为用户指令是主题性的如 git stuff无法在行级区分此时会整文件暂存被选中的文本文件wholeFileScope而如果文件级挑选本身无结果常见于只改注释这类无法用路径表达的指令则不做任何整文件暂存交由 hunk 级判定全权裁决。这种分级权威file-scope authoritative / hunk-scope authoritative设计让两阶段模型能力互补。测试与正确性保障crates/pi-vcs为暂存逻辑提供了多组测试可作为理解语义边界的佐证patch.rs 的patch_stage_hunks_stages_intent_to_add_and_preserves_unrelated_promise验证在 intent-to-addgit add -N场景下stage_hunks能正常暂存且不污染无关内容stage_hunks_commit_split_survives_unadvanced_index_mtime验证连续stage_hunkscommit_create复用同一句柄时拆分提交在索引 mtime 未推进的情况下依然成立patch_stage_hunks_selects_indices_and_lines验证按索引与行选择 hunk 的正确性。这些测试从索引一致性拆分提交稳定性索引/行选择精度三个角度锁定了逐 Hunk 暂存的行为契约间接保障了 AI 判定结果能被忠实落盘。小结与使用建议git-ai-stage-hunk.md虽然只是一个 8 行的提示词文件却是 oh-my-pi 将 LLM 引入版本控制工作流的精巧缩影极简二元裁决、上下文过滤防误导、格式容错解析、分级权威兜底、原生层精确落盘。如果你要基于本仓库扩展或定制 AI 暂存能力可以重点改动以下三个位置调整判定语义修改 git-ai-stage-hunk.md 的指令描述与输出约束但需同步保证parseVerdict的解析规则仍成立调整输入口径HUNK_CHARShunk 文本截断阈值与FILE_BATCH文件批量大小均在 ai-stage.ts 顶部定义直接影响模型输入规模与扇出并发度调整暂存精度select_hunks与apply_patch(cached: true)位于 crates/pi-vcs/src/git/patch.rs是控制暂存什么、不动工作区的最终落点。需要说明的前提限制该提示词专为 tiny/smol 级别模型的二元判定设计若替换为更大模型或要求结构化输出需同步调整模板与解析器所有源码引用均以当前仓库packages/coding-agent与crates/pi-vcs的实现为准。【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考