当前位置: 首页 > news >正文

HagiCode 中 AI 提交使用的提示词:设计思路与实现拆解

背景

用 AI 辅助开发这事,其实也算是经历了一整天敲代码的疲惫了吧。攒了一堆没提交的改动,配置文件、文档、业务逻辑、测试用例全混在一起,看着就让人头疼。手动分组、手写符合规范的 commit message、再切分支 push 一遍——光是这些"收尾活",半小时就这么没了。

其实这事儿自然就有了诉求——能不能一次性把未提交的改动扔给 AI,让它自己分析、分组、写 message、甚至直接 commit + push?

想法是好的,真做起来坑可不少。AI 很容易只改--author不改 Committer,提交历史里作者对了、提交者错了,看着就撕裂;它可能自由发挥写一堆花里胡哨的 message,完全不对齐你仓库的风格;它可能擅自切到主干分支把事情搞砸;它可能漏掉Co-Authored-By,或者乱加Signed-off-by触发合规问题。

这一个个坑,踩下来也都是教训罢了。为了填平这些痛点,我们把"AI 提交"做成了一个参数化的 Agent 任务契约。这份契约长什么样、为什么这么设计,就是这篇文章想聊清楚的事。

关于 HagiCode

本文分享的方案来自我们在 HagiCode 项目里的实践。HagiCode 是一个面向开发者工作流的 AI 代码助手,把 Git 提交、代码审查、构建发布这些日常环节都做成了 AI 可参与的任务。下文拆解的提示词系统,正是 HagiCode 后端里真实在跑的那一套。说到底,也只是想把那点琐碎的"收尾活"交给 AI 罢了。

提示词的真实形态:模板加元数据,而不是一段写死的字符串

很多人以为"提示词"就是一段写死的自然语言,丢给模型就完事了。其实 HagiCode 的做法完全不是这样。

真正驱动"AI 提交"的提示词叫auto-compose-commit,对应代码里的PromptScenario.AutoComposeCommit。它位于repos/hagicode-core/src/PCode.Web/Resources/Prompts/下,结构是这样的:

Resources/Prompts/
├── auto-compose-commit.en-US.hbs # 英文 Handlebars 模板
├── auto-compose-commit.en-US.json # 英文元数据(参数 schema、版本、标签)
├── auto-compose-commit.zh-CN.hbs # 中文模板
└── auto-compose-commit.zh-CN.json # 中文元数据

也就是说,一个提示词是一份 Handlebars 模板 + 一份 JSON 元数据的组合,按 locale 平铺成多套。

为什么要这么拆呢?其实背后有几个考量。

第一,元数据和提示词正文解耦。JSON 描述参数 schema——参数叫什么、什么类型、是否必填、默认值是什么;.hbs只管"这段话怎么说"。这样一来,前端可以在完全不知道模板正文的前提下,依据 JSON 自动渲染出正确的输入表单:Git 身份选择器、Co-Authored-By 模式、目标分支策略、要不要 push……这些控件都是 JSON 驱动出来的。

第二,多语言平铺,而不是用 i18n key 做翻译。每个 locale 一整套完整的.hbs+.json,避免了"翻译 key 漂移"。不同语言不只是把词替换掉,连分组示例、命令示例都可以本地化。中英文仓库的提交习惯本就不同,硬塞进一套模板再翻译,反而别扭罢了。

第三,从 Scriban 迁到 Handlebars,是为了性能HandlebarsTemplateRenderer选用了Handlebars.Net,因为它能"compile templates directly to IL bytecode",比解释执行快得多。迁移过程中还做了个有意思的兼容处理:把渲染结果里的True/False替换成true/false,兼容旧 Scriban 的布尔输出习惯——这种细节不留意,旧测试会全红。

提示词长成这样,背后有五个关键决策

auto-compose-commit.zh-CN.hbs拆开看,骨架大致是:

非交互模式说明
├── <task> 任务定义:分析变更、智能分组、多提交
├── <context> 上下文:projectPath + push 控制 + 目标分支控制
├── <working_directory>
├── <git_profile> 身份:Author 加 Committer 双写
├── <tools> 工具白名单
├── <requirements> 硬性要求(分支、分组、Co-Authored-By、Signed-off-by、Conventional Commits)
├── <historical_format_analysis> 历史一致性
├── <constraints> 约束(禁止 reset、忽略 .gitignore)
├── <workflow> 分步执行流程
├── <output_format> 严格的 `---` 分隔输出
└── <final_instruction>

下面挑五个最能体现设计意图的点展开聊聊。

决策一:直接执行,而不是只生成计划

提示词里反复强调一句话:直接使用 Git 命令执行每个提交,不返回计划,直接操作。

这是"Auto Compose Commit"区别于早期方案的根本不同。早期的ai-git-commit-message-generator(对应 OpenSpec 里的ai-commit-message-generation规范)只做一件事:调一个POST /api/git/generate-commit-message,返回一段 commit message 字符串,剩下的用户自己手动去提交。

可是auto-compose-commit不一样,它是一个Agent 自动任务。模型必须自己调用Bash(git:*)工具,把 add → commit → push 的全链路跑完。这一区别,就决定了整段提示词的基调——它不能只描述"要写什么样的 message",还得规定"按什么流程操作、用什么工具、出错怎么办"。

决策二:为什么 Git 身份要写得这么啰嗦

<git_profile><requirements>里有一大段关于 Author 与 Committer 的说明,乍看挺冗余:

- `--author="Name <email>"` 只会修改 Author
- `git -c user.name="Name" -c user.email="email" commit ...` 只会修改这一次命令的 Committer
- 对于每一个生成的提交,你都必须同时把 Author 和 Committer 设置为选定身份
- 首选命令形式:
git -c user.name="..." -c user.email="..." commit --author="... <...>" ...

这其实是真实踩坑换来的。Git 提交里有两个身份字段,模型很容易只改--author,结果 Committer 还是全局配置的那个身份。提交历史里"作者是对的、提交者是错的",看着就撕裂。所以提示词直接把首选命令模板贴出来,还要求模型用git log --format=fuller -1做自检。

类比一下,这就像你寄快递,"寄件人"和"实际经手人"是两张不同的单子。你只在一张单子上写了名字,另一张还印着公司的名字——快递是寄出去了,可记录对不上,终归是别扭罢了。

决策三:分组决策树加历史一致性

模型最擅长的就是"自由发挥",可自由发挥在提交分组这事上,往往是灾难。所以提示词给了一棵明确的决策树:配置文件单独一组、文档单独一组、同模块的代码改动合并、跨模块的改动看情况。还配了正例,比如src/auth/login.ts加上auth.service.ts应该进同一个提交。

更关键的是<historical_format_analysis>这一段。它要求模型:

  1. 使用git log -n 15 --pretty=format:"%H|%s|%b%n---%n"获取最近的提交历史
  2. 分析结构模式、语言模式、常用类型、特殊格式
  3. 生成遵循检测到的模式的提交信息

也就是说,模型不能想怎么写就怎么写,得先去对齐目标仓库已有的风格。HagiCode Mono 主仓用英文 + Conventional Commits,某些子仓库用中文段落式,AI 必须入乡随俗。这个能力对应归档提案2026-02-23-auto-commit-compose-history-consistency-optimization,是后来补上的优化。毕竟,谁也不希望自家提交历史像一锅乱炖罢了。

决策四:Co-Authored-By 和 Signed-off-by 的条件渲染

提示词里有大量嵌套的{{#if}},根据运行参数决定要不要加 trailer:

  • coAuthoredByIsNone时,完全不加Co-Authored-By
  • coAuthoredByIsCustom时,用用户给的自定义 trailer
  • signedOffByEnabled加上gitProfileName时,加Signed-off-by,缺失身份时必须报错而不是臆造一个

trailer 这块涉及署名归属和合规(DCO sign-off),必须由用户显式控制,绝不能让模型自作主张。HagiCode 在这块陆续落地了git-commit-coauthor-standardizationai-commit-consent-management等一系列提案,才把边界划清楚。这种事,宁可严一点,也不能含糊。

决策五:---分隔的输出契约

<output_format>规定每次返回必须用---分隔多个 commit 块,格式写死:

---
Commit 1: {hash}
{message}
---
Commit 2: {hash}
{message}
---

这可不是为了好看。模型一次任务可能产出 N 个提交,后端要靠这个分隔符把每条提交的 hash 和 message 解析出来,回传给前端展示。一旦输出协议松动,后端解析直接崩。所以---这条规则在<output_format><final_instruction>里被强调了两次——重要的事,本就该说三遍罢了。

提示词是怎么被组装和投递的

光看模板还不够,得知道它怎么跑起来。

加载与渲染

后端在PCodeClaudeHelperModule里注册了两个单例:

http://www.gsyq.cn/news/1603596.html

相关文章:

  • 前后端分离高校电动车租赁系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 如何在Amlogic电视盒上安装完整Linux系统:5个简单步骤实现电视盒变身全能服务器
  • MSPM0 FACTORY区域与BSLCRC校验:嵌入式硬件抽象与安全启动核心机制
  • Postman 常用断言脚本合集
  • 【STL】iostream 编程:输入/输出替换选项
  • 为什么92%的ChatGPT Plus订阅在第3个月自动降级?国内用户必须知道的OpenAI账户健康度监测协议(含自动续费预警脚本开源)
  • 基于Delaunay三角剖分与排斥算法的Fillinger智能填充技术深度解析
  • java se Java SE基础不牢?Eclipse这工具能让你从菜鸟飞成老鸟
  • DLSS Swapper终极指南:一键智能管理游戏图形技术,彻底释放显卡性能
  • Spring Boot 过滤器链执行顺序
  • 软件追踪管理中的分布式跟踪
  • 想要“无感知复用“?架构里必须有闲置计时器和会话保持机制
  • 理解 Agent 中的 Slash Command:从概念到自定义命令实践
  • 零基础非技术员工怕学不会AI?从日常办公任务自动化开始构建个人工作流的实战指南
  • 每月68元的专业版豆包值不值?实测:帮做网站、汇总信息,效率惊人!
  • C++ ODB ORM 完整使用指南(从入门到实战)
  • 服务治理实践
  • 3分钟搞定Mac Boot Camp驱动:跨平台自动下载安装完整指南
  • 如何永久保存网页记忆:Wayback Machine浏览器扩展终极指南
  • Groove音乐播放器:三分钟掌握跨平台音乐播放终极指南
  • Codex command not found 命令不存在解决教程
  • Go 语言语法完全指南
  • bilibili-linux开源项目:Linux平台B站客户端完整解决方案深度指南
  • 【MUJOCO实战指南】从XML到视觉:Geom几何体建模与可视化实战
  • Harness Engineering 是什么?AI 编程工程化的三次进化
  • Conda 环境一键搬家:用 conda-pack 打包带走,连网都不用
  • 如何在5分钟内快速上手OpenModScan:免费Modbus主站测试工具完全指南
  • 终极桌面分区管理神器NoFences:5分钟让你的Windows桌面焕然一新
  • 从零打通 MySQL → DataX → Doris:Windows 11 + Docker 本地环境搭建全记录
  • RFID资产管理系统实测:真的能提升盘点效率吗?