金句:通用 AI 像一个知识渊博的新员工——什么都懂一点,但不了解你的公司、你的代码风格、你的业务逻辑。Fine-tuning 是让 AI 成为真正"懂你"的老员工。
一、什么时候需要 Fine-tuning?
不需要 Fine-tuning 的情况(用 Prompt 就够了):
- 需要 AI 遵循特定格式输出
- 需要 AI 了解最新信息(应该用 RAG)
- 任务多样、不固定
适合 Fine-tuning 的情况:
- 需要 AI 持续输出特定风格(如公司的代码规范)
- 有大量重复的固定任务(如特定格式的代码生成)
- 需要减少提示词的长度(降低 API 成本)
- 需要提升特定任务的准确率
二、Fine-tuning 的三种方式
方式一:OpenAI Fine-tuning API(最简单)
适合:已有 GPT-3.5 或 GPT-4 的使用场景,预算有限
步骤:
1. 准备训练数据(JSONL 格式):
{"messages": [{"role": "system", "content": "你是一个代码审查助手,专注于 TypeScript 最佳实践。"}, {"role": "user", "content": "审查这段代码:const user = await db.query('SELECT * FROM users WHERE id = ' + userId)"}, {"role": "assistant", "content": "🔴 Critical - SQL 注入漏洞\n\n**问题**:直接字符串拼接 SQL 查询,存在严重的 SQL 注入风险。\n\n**修复**:\n```typescript\nconst user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);\n```\n\n**说明**:使用参数化查询,将用户输入作为参数传递,而不是直接拼接到 SQL 字符串中。"}]}
{"messages": [{"role": "system", "content": "你是一个代码审查助手,专注于 TypeScript 最佳实践。"}, {"role": "user", "content": "审查这段代码:async function getUser(id) { return db.findOne(id) }"}, {"role": "assistant", "content": "🟡 Warning - 缺少类型注解和错误处理\n\n**问题1**:参数 `id` 没有类型注解\n**问题2**:函数没有声明返回类型\n**问题3**:没有 try-catch 错误处理\n\n**修复**:\n```typescript\nasync function getUser(id: string): Promise<User | null> {\n try {\n return await db.findOne(id);\n } catch (error) {\n logger.error('Failed to get user', { id, error });\n throw new DatabaseException('User retrieval failed');\n }\n}\n```"}]}
2. 上传数据并开始训练:
import openai
client = openai.OpenAI()
# 上传训练数据
with open("training_data.jsonl", "rb") as f:
response = client.files.create(file=f, purpose="fine-tune")
file_id = response.id
print(f"文件已上传,ID: {file_id}")
# 开始 Fine-tuning
job = client.fine_tuning.jobs.create(
training_file=file_id,
model="gpt-3.5-turbo", # 或 gpt-4o-mini
hyperparameters={
"n_epochs": 3, # 训练轮数
}
)
print(f"训练任务已创建,ID: {job.id}")
print(f"状态:{job.status}")
3. 查看训练状态:
# 查看训练进度
job_status = client.fine_tuning.jobs.retrieve(job.id)
print(f"状态:{job_status.status}")
print(f"训练模型:{job_status.fine_tuned_model}") # 完成后显示
4. 使用训练好的模型:
# 使用 Fine-tuned 模型
response = client.chat.completions.create(
model="ft:gpt-3.5-turbo-0125:your-org::xxxxx", # Fine-tuned 模型 ID
messages=[
{"role": "system", "content": "你是一个代码审查助手"},
{"role": "user", "content": "审查这段代码:..."}
]
)
方式二:LoRA/QLoRA 开源模型 Fine-tuning
适合:有 GPU、需要完全控制、不想付 API 费用
# 使用 Hugging Face + PEFT 进行 LoRA Fine-tuning
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer
import torch
# 加载基础模型(以 CodeLlama 为例)
model_name = "codellama/CodeLlama-7b-hf"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
load_in_4bit=True, # QLoRA:4bit 量化,大幅减少显存
torch_dtype=torch.float16,
device_map="auto"
)
# LoRA 配置
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # LoRA 秩(越大,表达能力越强,显存越多)
lora_alpha=32, # LoRA 缩放系数
target_modules=["q_proj", "v_proj"], # 只训练 attention 层
lora_dropout=0.1,
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 输出:trainable params: 4,194,304 || all params: 6,742,609,920
# 只训练 0.06% 的参数,节省大量资源
# 训练配置
training_args = TrainingArguments(
output_dir="./code-review-model",
num_train_epochs=3,
per_device_train_batch_size=4,
learning_rate=2e-4,
fp16=True,
logging_steps=100,
save_steps=500,
)
# 开始训练
trainer = SFTTrainer(
model=model,
train_dataset=dataset, # 你的训练数据
args=training_args,
tokenizer=tokenizer,
dataset_text_field="text",
max_seq_length=2048,
)
trainer.train()
trainer.save_model()
三、训练数据收集策略
策略一:从人工审查记录中提取
# 从 GitHub PR 评论中提取高质量审查数据
import requests
def get_pr_reviews(repo: str, token: str) -> list:
"""获取 PR 中的代码审查评论"""
reviews = []
headers = {"Authorization": f"token {token}"}
# 获取 PR 列表
prs = requests.get(
f"https://api.github.com/repos/{repo}/pulls?state=closed&per_page=100",
headers=headers
).json()
for pr in prs:
# 获取 PR 中的 review 评论
comments = requests.get(
f"https://api.github.com/repos/{repo}/pulls/{pr['number']}/comments",
headers=headers
).json()
for comment in comments:
if len(comment['body']) > 100: # 只要详细的评论
reviews.append({
"code": comment.get('diff_hunk', ''),
"review": comment['body']
})
return reviews
策略二:数据增强
# 用 GPT-4 生成更多训练样本
def augment_training_data(existing_example: dict) -> list:
"""基于已有样本生成变体"""
prompt = f"""
基于以下代码审查示例,生成 5 个类似但不同的训练样本:
原始代码:{existing_example['code']}
原始审查:{existing_example['review']}
要求:
1. 保持相同类型的问题(如安全漏洞/性能问题/代码规范)
2. 使用不同的代码语言或场景
3. 保持审查风格一致
"""
# 调用 GPT-4 生成...
四、Fine-tuning 效果评估
def evaluate_fine_tuned_model(model_id: str, test_cases: list) -> dict:
"""评估 Fine-tuned 模型的性能"""
results = {
"format_accuracy": 0, # 输出格式是否符合规范
"relevance_score": 0, # 审查是否抓住关键问题
"false_positive_rate": 0 # 误报率
}
for test in test_cases:
response = client.chat.completions.create(
model=model_id,
messages=[{"role": "user", "content": test["input"]}]
)
output = response.choices[0].message.content
# 检查输出格式
if any(marker in output for marker in ["🔴", "🟡", "🟢"]):
results["format_accuracy"] += 1
# 检查是否发现了预期的问题
if test["expected_issue"].lower() in output.lower():
results["relevance_score"] += 1
n = len(test_cases)
results["format_accuracy"] /= n
results["relevance_score"] /= n
return results
章节小结:Fine-tuning 是让 AI 从"通用助手"进化为"专业搭档"的技术。OpenAI Fine-tuning API 提供了最低门槛的入口,适合大多数开发者;LoRA/QLoRA 则给予了完全控制权,适合有 GPU 资源的团队。关键是:先用高质量的少量数据(100-1000条)训练,评估效果,再决定是否扩大规模。