和大模型聊得多了,总会觉得它虽然什么都懂,但又不够懂我。比如,我希望它能按照我团队的特定格式生成 Git 提交信息,但无论我怎么调整 Prompt,它总有出错的时候。

这时候,一个更优的解决方案浮出水面:微调(Fine-tuning)

微调就像是让一个博学的大学生(预训练的基础模型)专注于你的特定专业领域(你的数据集)进行深度学习,最终成为这个领域的专家。今天,我就将手把手带你完成一次完整的微调流程,打造一个能生成特定格式 Commit Message 的 AI 助手。

目标:训练一个 Git Commit Message 生成器

我们的目标是训练一个模型,它可以接收一段代码的 diff 作为输入,然后输出一段符合我们规范的 Commit Message,格式如下: feat(scope): 详细描述

第一步:准备数据集

微调的质量很大程度上取决于数据集的质量。我们需要一个“考题库”,让模型学习从问题(代码diff)到答案(Commit Message)的映射。

数据集通常是一个 JSONL 文件,每一行都是一个 JSON 对象,包含输入和输出。

  1. 收集数据:我从我自己的一个项目中,使用 git log --pretty=format:"%s"git show --pretty=format:"" 收集了大约100条提交记录和对应的代码diff。
  2. 格式化数据:将收集到的数据整理成如下格式,并保存为 commits.jsonl
{"prompt": "diff --git a/main.py b/main.py\n--- a/main.py\n+++ b/main.py\n@@ -1,3 +1,4 @@\n def hello():\n-    print(\"hello world\")\n+    print(\"hello universe\")\n+    # Add a comment", "completion": "feat(main): update greeting message and add comment"}
{"prompt": "diff --git a/utils.py b/utils.py\n--- a/utils.py\n+++ b/utils.py\n@@ -5,2 +5,5 @@\n # utility functions\n+def add(a, b):\n+    return a + b\n+", "completion": "feat(utils): implement adder function"}

提示:数据集是成功的关键。数据量越大、质量越高,模型的效果就越好。对于一个真实世界的任务,你可能需要成百上千条高质量的样本。

第二步:选择模型和工具

我们不需要从零开始训练。社区里有很多优秀的开源模型可供我们选择。

  • 模型:为了能在普通电脑上运行,我选择了 distilgpt2,这是一个小巧但功能强大的 GPT-2 变体。
  • 工具:我们将使用 Hugging Face 的 transformers 库,它是目前进行 AI 模型训练和推理的事实标准。

第三步:编写微调脚本

这是最核心的一步。我们将编写一个 Python 脚本来加载数据、配置模型并开始训练。

# finetune.py
import torch
from datasets import load_dataset
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    TrainingArguments,
    Trainer,
    DataCollatorForLanguageModeling,
)

# 1. 加载和预处理数据
def prepare_data(tokenizer, dataset_path):
    dataset = load_dataset('json', data_files=dataset_path, split='train')

    def tokenize_function(examples):
        # 将 prompt 和 completion 合并为一个字符串进行训练
        text = [p + " " + c for p, c in zip(examples['prompt'], examples['completion'])]
        return tokenizer(text, truncation=True, padding='max_length', max_length=128)

    tokenized_dataset = dataset.map(tokenize_function, batched=True, remove_columns=dataset.column_names)
    return tokenized_dataset

def main():
    model_name = "distilgpt2"
    dataset_path = "commits.jsonl"
    output_dir = "./results"

    # 2. 初始化 Tokenizer 和模型
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    # 设定 pad_token,否则会报错
    if tokenizer.pad_token is None:
        tokenizer.pad_token = tokenizer.eos_token
      
    model = AutoModelForCausalLM.from_pretrained(model_name)

    # 3. 准备数据集
    tokenized_dataset = prepare_data(tokenizer, dataset_path)
    data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

    # 4. 设置训练参数
    training_args = TrainingArguments(
        output_dir=output_dir,
        overwrite_output_dir=True,
        num_train_epochs=3, # 训练轮次
        per_device_train_batch_size=4, # 每个设备的批处理大小
        save_steps=10_000,
        save_total_limit=2,
        logging_dir='./logs',
    )

    # 5. 初始化并开始训练
    trainer = Trainer(
        model=model,
        args=training_args,
        data_collator=data_collator,
        train_dataset=tokenized_dataset,
    )

    print("开始微调...")
    trainer.train()

    # 6. 保存最终模型
    trainer.save_model(output_dir)
    tokenizer.save_pretrained(output_dir)
    print("微调完成,模型已保存至", output_dir)

if __name__ == "__main__":
    main()

在运行前,请确保已安装所需库:pip install torch datasets transformers

第四步:开始训练

finetune.pycommits.jsonl 放在同一个目录下,然后运行脚本: python finetune.py

你将看到训练过程的日志,包括 loss(损失)值的下降,这表明模型正在从你的数据中学习。

第五步:测试你的专属模型

训练完成后,你的模型就保存在 ./results 目录下了。现在,我们来测试一下它的效果。

# inference.py
from transformers import pipeline

model_dir = "./results"
generator = pipeline('text-generation', model=model_dir, tokenizer=model_dir)

diff_prompt = "diff --git a/README.md b/README.md\n--- a/README.md\n+++ b/README.md\n@@ -1 +1,2 @@\n # My Project\n+Add introduction."

# prompt 需要和训练时一致
result = generator(diff_prompt, max_length=50)
print(result[0]['generated_text'])

运行 python inference.py,你很可能会看到一个符合 feat(scope): ... 格式的、描述准确的 Commit Message。这,就是微调的魅力!

结语

微调打开了一扇通往真正“个性化AI”的大门。虽然这个例子很简单,但它展示了完整的流程。你可以将这个方法应用到任何你感兴趣的领域:写特定风格的诗歌、做特定格式的翻译、生成特定库的API调用代码……

这比单纯地“用”AI 又进了一步,变成了“创造”AI。这感觉,实在是太酷了。