前言: 各位全栈练习生们,欢迎回来!👋 刚刚我们搞定了 RAG 知识库,是不是觉得 AI 的能力深不可测?
现在,请大家摸着良心问自己一个问题:你平时的 Git Commit Message 是怎么写的? 是
fix bug?update?还是111、asdf?🙈如果你是团队里的 Leader,看到这样的提交记录,血压是不是已经上来了?😤 其实,写好 Commit Message 不仅是为了显得专业,更是为了团队协作、自动化生成 Changelog 以及日后的代码回溯。
但是!人都是懒惰的。与其每天盯着规范文档抓耳挠腮,不如让 AI 来帮我们写! 今天下半场,我们就来做一个 AI Git Commit 助手,丢进去一坨
git diff,吐出来一行标准的 Conventional Commits!🚀
🧐 为什么要死磕 Commit 规范?
在开始写代码之前,我们先来聊聊“为什么”。
很多新手(甚至老手)觉得 Commit Message 只要自己看得懂就行。错!大错特错!❌ 想象一下,三个月后线上出了 Bug,你需要回滚代码,打开 Git Log 一看:
fix
fix bug
update
final fix
really final fix
这一刻,你是不是想穿越回去掐死那个写这些 Log 的自己?💀
📜 Conventional Commits 国际公约
为了解决这个问题,业界大神们制定了 Conventional Commits(约定式提交) 规范。它的标准格式长这样:
<type>(<scope>): <subject>
// 空一行
<body>
// 空一行
<footer>
看起来很复杂?其实核心就是第一行:
- type:告诉大家这次改动是什么类型的。
- scope:(可选) 改动了哪个模块,比如
user-service或login-page。 - subject:简短描述改了啥,不要超过 50 个字符,要言简意赅。
🏷️ 常用 Type 速查表
为了让 AI 能够精准工作,我们需要先把这些规则“喂”给它。根据我们的 README.md,这里有一份大厂通用的 Type 列表:
- ✨ feat: 新增功能 (Feature)
- 🐛 fix: 修复 Bug
- 📚 docs: 文档更新 (Documentation)
- 💅 style: 代码格式调整(不影响逻辑,比如空格、分号,不是 CSS 样式哦)
- ♻️ refactor: 代码重构(既不新增功能也不修 Bug)
- ⚡ perf: 性能优化 (Performance)
- ✅ test: 增加或修改测试用例
- 🏗️ build: 构建系统变动 (npm, webpack 等)
- 🔧 chore: 杂项(构建过程或辅助工具的变动)
- ⏪ revert: 回滚提交
我们的目标,就是让 AI 像一个资深代码审核专家一样,分析你的代码变更,自动生成符合上述规范的提交信息。🎯
🛠️ 前端实战:打造丝滑的工具入口
好,理论储备完毕,开工!
第一步:入口配置 - Mine.tsx
我们要把这个功能放在个人中心里。打开 frontend/notes/src/pages/Mine.tsx,在刚才 RAG 的下面,再加一个入口。
<div
className="flex justify-between items-center py-2 border-b last:border-b-0 cursor-pointer hover:bg-gray-50 transition-colors"
// 👇 点击跳转到 /git 路由
onClick={() => navigate('/git')}
>
<div className="flex items-center gap-2">
{/* 加个小图标,显得精致一点 */}
<span className="text-xl">🐙</span>
<span>AI Git 助手</span>
</div>
<span className="text-gray-400 text-sm">></span>
</div>
别忘了去路由配置文件(App.tsx 或 routes.tsx)里把 /git 指向我们要创建的 Git 组件哦!
第二步:极简交互页面 - Git.tsx
这个页面逻辑很简单:左边放代码 Diff,点击按钮,右边(或下面)出结果。
打开 frontend/notes/src/pages/Git.tsx。这里我们用了 shadcn/ui 的组件,配合 lucide-react 的图标,瞬间逼格满满。
// 篇幅原因,只展示核心逻辑,UI 代码大家可以直接 copy
import { useGitStore } from '@/store/git';
const Git: React.FC = () => {
// 🎣 从 Store 中获取状态
const { loading, diff, setDiff, getCommit, commit } = useGitStore();
const handleSubmit = async () => {
if (!diff.trim()) return;
// 🚀 触发 Store 中的 action
await getCommit(diff);
};
return (
// ... UI 布局代码 ...
<textarea
value={diff}
onChange={(e) => setDiff(e.target.value)} // 📝 双向绑定 Diff 输入
placeholder="请粘贴 git diff 后的内容..."
/>
<Button onClick={handleSubmit} disabled={loading}>
{loading ? 'AI 思考中...' : '生成 Commit 日志'}
</Button>
{/* ✨ 展示结果区域 */}
{commit && (
<div className="bg-gray-100 p-4 rounded">
<p className="font-mono text-green-700">{commit}</p>
{/* 一键复制功能 */}
<button onClick={() => navigator.clipboard.writeText(commit)}>复制</button>
</div>
)}
// ...
)
}
第三步:状态管理的艺术 - store/git.ts
前端的核心逻辑依然交给 Zustand。这里我们需要处理一个典型的异步流程:loading -> fetch api -> save result。
import { create } from 'zustand';
import { fetchCommit } from '@/api/git';
interface GitState {
loading: boolean;
diff: string; // 用户输入的 git diff 内容
commit: string; // AI 生成的结果
setLoading: (loading: boolean) => void;
setDiff: (diff: string) => void;
// ⚡ 核心 Action
getCommit:(diff: string) => Promise<void>;
}
export const useGitStore = create<GitState>((set, get) => ({
loading: false,
diff: '',
commit: '',
setLoading: (loading) => set({ loading }),
setDiff: (diff) => set({ diff }),
getCommit: async(diff: string) => {
// 1. 开始 Loading
set({ loading: true });
try {
// 2. 调用 API
const res = await fetchCommit(diff);
console.log('AI 生成结果:', res);
// 3. 存入 Store
set({ commit: res });
} catch (error) {
console.error(error);
} finally {
// 4. 无论成功失败,结束 Loading
set({ loading: false });
}
}
}))
💡 为什么要这么写? 把业务逻辑封装在 Store 里,View 层(页面)就只需要负责渲染和触发事件,完全不用关心“怎么发请求”、“怎么处理 loading 状态”这些脏活累活。这就是 关注点分离(Separation of Concerns)。
第四步:对接后端 - api/git.ts
import instance from "./config";
export const fetchCommit = async (diff: string) => {
// POST 请求,把 diff 传给后端
const res = await instance.post('/ai/git', { diff });
// 假设后端返回结构是 { result: "feat: add git ai tool" }
return res.result;
}
🧠 后端实战:LangChain 的链式魔法
现在压力来到了后端。我们要用 NestJS 接收这个 diff,然后让 LangChain 把它变成符合规范的 Commit Message。
第五步:路由配置 - ai.controller.ts
@Post('git')
// 接收前端传来的 { diff: string }
async git(@Body() { diff }: { diff: string }) {
// 调用 Service
return this.aiService.git(diff);
}
简单明了。👉
第六步:Prompt Engineering 与 LCEL - ai.service.ts
这里是全篇最硬核的地方!我们将使用 LangChain 的 LCEL (LangChain Expression Language) 语法来构建处理链。
我们需要做三件事:
- Prompt Template:定义“人设”和“任务”。
- LLM:调用大模型。
- OutputParser:把 AI 的输出转成字符串。
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
// ... Inside AiService class ...
async git(diff: string) {
// 1️⃣ 定义 Prompt 模板
// 这是 Prompt Engineering 的关键!告诉 AI 它是谁,要干嘛,有什么约束。
const prompt = ChatPromptTemplate.fromMessages([
["system", `你是资深代码审核专家。请根据用户提供的 git diff 内容生成一段
符合 Conventional Commits 规范的提交日志。
要求:
1. 格式为 <type>(<scope>): <subject>。
2. 保持简洁,不要废话。
3. 不要输出 markdown 格式(如 \`\`\`),只输出纯文本。
4. 如果改动很多,取最重要的一个。
`],
// {diff_content} 是一个占位符,稍后会被替换
["user", "{diff_content}"]
]);
// 2️⃣ 构建 Chain (链)
// 管道操作符 pipe 极其优雅:Prompt -> Model -> StringParser
// 数据像水流一样流过这个管道
const chain = prompt.pipe(this.chatModel).pipe(new StringOutputParser());
// 3️⃣ 执行 Chain
// 传入具体的 diff 内容
const result = await chain.invoke({
diff_content: diff
});
console.log('AI 生成的 Commit:', result);
// 4️⃣ 返回结果
return {
result // 直接返回字符串给 Controller
}
}
🔍 硬核解析:
-
System Message(系统提示词): 这是给 AI 的“上帝指令”。我们不仅设定了角色(资深代码审核专家),还明确了输出格式(Conventional Commits)。最重要的是,我们加了负面约束(Negative Constraints),比如“不要输出 markdown”,这对 LLM 非常重要,否则它经常会给你画蛇添足加个代码块包裹。
-
LCEL (Prompt.pipe.pipe): 如果你用过 Linux 管道命令(
|),对这个肯定不陌生。prompt负责把输入的diff塞进模板,生成完整的提示词对象。this.chatModel接收提示词对象,进行推理,吐出AIMessage对象。StringOutputParser把AIMessage里的 content 提取出来,转成纯字符串。 这种声明式的写法,比传统的await model.call(prompt)更加清晰、易读,也更容易扩展(比如中间加个日志记录、或者输出格式校验)。
🎉 效果演示与总结
开发完成后,让我们来试一下。
假设我在项目里修改了 README.md,加了一行关于 Git 工具的说明。
我在终端运行 git diff,复制内容,粘贴到我们的网页里,点击生成。
AI 可能会输出:
docs(readme): add introduction for AI git tool and conventional commits
完美!🎉
通过今天这个实战,我们不仅复习了 React + NestJS 的全栈流程,更深入实践了 Prompt Engineering 和 LangChain LCEL 语法。
从此以后,你的 Git Log 将变得整整齐齐,像军队一样规范。你的同事会夸你专业,你的 Leader 会给你点赞,甚至连你自己回顾代码时,都会被这份优雅感动!
全栈之路,道阻且长,但有 AI 相伴,我们不仅走得快,还能走得帅!😎
点个赞再走吧!下期见!👋
代码已在本地环境测试通过,Happy Coding!