硕士校招生进入大模型领域工作,选预训练还是SFT?
引言
大语言推理模型常见的两个痛点:一是“答不对”,二是“答不规范”。前者意味着推理链条断裂或迁移失效,后者则让后续评估与系统对接步步惊心。
在这篇 How‑to 指南里,我们用 GSM8K 的标准数据与明确的评估规则,让 Qwen/Qwen2.5-Math-1.5B 通过 SFT 后,能力迁移到不同的数据集上, 学会“思考→作答”的结构化输出:不仅更常答对,也更懂规范。结果来自实测,正确率由 1.56% 提升到 62.9%,格式遵循由 18.9% 提升到 100%.
为什么零样本推理和“格式遵循”都很难?
- 零样本推理难在“迁移”:模型虽见过大量文本,但缺少对“分步算术、单位处理、等式化简”的系统化经验,容易在多步推理或细节规范上出错。
- 格式遵循难在“约束学习”:即使模型知道答案,若不按系统约定的输出协议(例如必须有
<think>...</think> <answer>...</answer>),评估与下游解析都会失败。 - 两者耦合:不遵循格式会直接“判零分”,即使答案正确;而缺少分步推理(think)又会影响最终答案(answer)的稳定性。
一个好比喻:把模型想象成一个聪明但散漫的学生。零样本时,它能“蒙”对少数题;SFT 就像班主任的“规范化带教”,教它先写草稿()再交最终答案(),且必须按卷面格式来——这样既能提高质量,也能让阅卷更可靠。
核心概念与评估口径
- 监督微调(SFT):用标注样本(这里是 GSM8K 的“问题 + 推理过程 + 最终答案”)对模型做下一 token 预测训练。通过标签掩码,只对“推理与答案”部分计算损失,指导模型输出完整的思维链与答案。
- Prompt 架构:我们采用 R1 风格模板,强制输出
<think>和<answer>标签,保证格式可解析: <think> ... </think>:推理过程<answer> ... </answer>:最终答案- 训练目标(Loss Target):标准自回归语言模型(next-token LM)损失,但只在“回应(think+answer)”区间计算,避免模型学习到重复的“系统提示与问题”的 token 序列。
- 评估指标:
- “推理准确率”:按每条样本的 答案是否正确(数学同值、LaTeX 等价、数值等价,详见 grader)计分 0/1,最后取平均。
- “格式遵循率”:按每条样本 是否包含合法的
<think>...</think> <answer>...</answer>标签计分 0/1,最后取平均。
我们在 alignment/drgrpo_grader.py 中实现了严格的格式检查与宽容但可靠的数学等价判断(符号化、数值化与 LaTeX 解析的组合),是本文准确率与格式遵循的核心评估逻辑。
方案与架构
本文的流水线架构如下:从 GSM8K JSONL 到 Prompt 构造,再到 SFT 训练与 vLLM 推理评估,最后汇总指标(准确率/格式遵循)。
flowchart LR
A["GSM8K JSONL 数据集"] --> B["R1PromptTemplate 构造 Prompt"]
B --> C["SFT 训练 (next-token LM)"]
C --> D["保存 Checkpoint"]
D --> E["vLLM 推理评估"]
E --> F["r1_zero_reward_fn 计算格式与正确性"]
F --> G["输出指标: 准确率 & 格式遵循"]
关键路径对应的源码均在 alignment 目录下:dataset.py(数据加载)、r1_prompt.py(模板)、sft.py(训练)、evaluate.py(评估)、drgrpo_grader.py(格式与答案打分)。
可复现配置与注意事项
- 模型与精度:默认使用 Qwen/Qwen2.5-Math-1.5B,dtype 默认 bfloat16(见 alignment/args.py)。
- 设备与显存:alignment/sft.py 通过 accelerate 的
infer_auto_device_map自动切分模型到多卡(--sft_device),并设置--max_sft_gpu_memory_use(默认 31GiB/卡)。评估使用 vLLM 独立进程(--eval_device)。 - 随机性:
--seed默认 42。不同环境(驱动、库版本、显存压力)与随机种子可能导致轻微波动。 - 批次与累积:
--batch_size与--gradient_accumulation_steps控制有效批次大小,训练日志会打印累计后的损失。 - 提示模板:
alignment/prompts/r1_zero.prompt强制<think>/<answer>标签,保证格式可检。
实践步骤:从数据到评估与训练
- 下载 GSM8K(train/test)到本地 data 目录(可根据你的项目目录调整):
cd dataset
wget https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/train.jsonl
wget https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl
建议将文件移动/复制为仓库约定路径:data/gsm8k/train.jsonl 与 data/gsm8k/test.jsonl(alignment/args.py 默认如此)。
- 微调前的零样本评估(使用 vLLM + R1 模板 + 严格格式与答案打分):
uv run -m alignment.evaluate
- 执行 SFT 训练并在测试集上评估(训练中每个 epoch 结束都会评估并保存 checkpoint):
uv run -m alignment.sft
代码讲解:数据加载与样本构造(包含 / 标签)
首先用 R1 模板将问题转为 Prompt,将“推理过程 + 最终答案”打包为监督信号。alignment/dataset.py 与 r1_prompt.py 如下:
# alignment/dataset.py
from torch.utils.data import Dataset
import json
from .r1_prompt import R1PromptTemplate
class Gsm8kDataset(Dataset):
def __init__(self, data_path: str, promt_template_path: str):
template = R1PromptTemplate(promt_template_path)
self.data = []
self.label = []
self.ground_truth = []
with open(data_path, "r") as f:
lines = f.readlines()
for line in lines:
qa = json.loads(line)
question = qa["question"]
answer_think = qa["answer"]
think, answer = answer_think.split("####")
think, answer = think.strip(), answer.strip()
self.data.append(template.gen_prompt(question))
self.label.append(template.gen_response(think, answer))
self.ground_truth.append(answer)
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
return self.data[idx], self.label[idx], self.ground_truth[idx]
# alignment/r1_prompt.py(关键:强制 <think>/<answer> 标签)
class R1PromptTemplate:
def __init__(self, template_path: os.PathLike):
with open(template_path, "r") as f:
self.template = f.read().strip()
def gen_prompt(self, question: str) -> str:
return self.template.replace(r"{question}", question)
def gen_response(self, think: str, answer: str) -> str:
return think + "</think>" + " <answer>" + answer + " </answer>"
模板文件 alignment/prompts/r1_zero.prompt:
A conversation between User and Assistant... <think> reasoning process here </think> <answer> answer here </answer>.
User: {question}
Assistant: <think>
这保证了训练时模型学习“先写 <think> 再写 <answer>”,评估时也能稳定抽取并验证答案。
代码讲解:SFT 训练循环与标签掩码(只对回应部分计算损失)
在 alignment/sft.py,我们将 prompt + completion 拼接,对 prompt 区间的 label 置为 -100,从而让交叉熵只在“回应(think + answer)”上回传梯度:
# alignment/sft.py(节选)
model.train()
for epoch in range(args.epochs):
for i, batch in enumerate(train_data_loader):
prompts, completions, _ = batch
full_texts = [p + c + tokenizer.eos_token for p, c in zip(prompts, completions)]
inputs = tokenizer(
full_texts,
return_tensors="pt",
padding=True,
truncation=True,
max_length=args.max_seq_len,
).to(model.device)
# 计算每个样本的 prompt token 长度
prompt_tokens = tokenizer(list(prompts), add_special_tokens=False)
prompt_lengths = [len(ids) for ids in prompt_tokens.input_ids]
labels = inputs.input_ids.clone()
for idx in range(len(prompts)):
prompt_len = prompt_lengths[idx]
labels[idx, :prompt_len] = -100 # 对 prompt 部分不计 loss
# Mask padding tokens
labels[labels == tokenizer.pad_token_id] = -100
outputs = model(
input_ids=inputs.input_ids,
attention_mask=inputs.attention_mask,
labels=labels,
)
loss = outputs.loss
loss = loss / args.gradient_accumulation_steps
loss.backward()
if (i + 1) % args.gradient_accumulation_steps == 0:
print(f"Epoch {epoch}, Iteration {i}, Loss: {loss.item() * args.gradient_accumulation_steps}")
optimizer.step()
optimizer.zero_grad()
# 评估:将策略权重加载到 vLLM 并在测试集上跑评估
load_policy_into_vllm_instance(model, eval_model)
evaluate_math(
eval_model,
args.prompt_template_path,
args.sft_test_data,
args.batch_size,
log_sample=True,
)
model.save_pretrained(args.checkpoint_path)
这段逻辑实现了标准的 SFT:用“回应”作为监督目标,配合累积梯度与分卡策略,保证 1.5B 规模模型在可控显存与吞吐下完成训练。
代码讲解:评估与指标计算(准确率与格式遵循)
评估由 alignment/evaluate.py 驱动,调用 r1_zero_reward_fn 计算每条样本的格式与答案得分:
# alignment/evaluate.py(核心)
from collections.abc import Callable
from vllm import LLM, SamplingParams
from .drgrpo_grader import r1_zero_reward_fn
def evaluate_vllm(vllm_model: LLM,
reward_fn: Callable[[str, str], dict[str, float]],
prompts: list[str],
ground_truths: list[str],
eval_sampling_params: SamplingParams,
log_sample: bool) -> dict:
outputs = vllm_model.generate(prompts, eval_sampling_params)
generated_texts = [output.outputs[0].text for output in outputs]
rewards = [reward_fn(generated_text, ground_truth)
for generated_text, ground_truth in zip(generated_texts, ground_truths)]
avg_format_rewards = sum([r["format_reward"] for r in rewards]) / len(prompts)
avg_answer_rewards = sum([r["answer_reward"] for r in rewards]) / len(prompts)
avg_all_rewards = sum([r["reward"] for r in rewards]) / len(prompts)
print(f"avg_format_rewards: {avg_format_rewards}")
print(f"avg_answer_rewards: {avg_answer_rewards}")
print(f"avg_all_rewards: {avg_all_rewards}")
return {
"avg_format_rewards": avg_format_rewards,
"avg_answer_rewards": avg_answer_rewards,
"avg_all_rewards": avg_all_rewards,
}
奖励函数严格要求格式标签,并对答案进行多重等价校验:
# alignment/drgrpo_grader.py(节选)
def r1_zero_reward_fn(response, ground_truth, fast=True):
# 格式严格:必须包含 </think> <answer> ... </answer>
if "</think> <answer>" in response and "</answer>" in response:
model_answer = response.split("<answer>")[-1].replace("</answer>", "")
# 允许 \boxed{...} 的答案形式并抽取
if "\\boxed" in model_answer:
model_answer = extract_answer(model_answer)
if model_answer is None:
return {"format_reward": 1.0, "answer_reward": 0.0, "reward": 0.0}
# 字符串、数值、LaTeX、SymPy 等价综合判断
is_correct = grade(model_answer, str(ground_truth), fast)
if is_correct:
return {"format_reward": 1.0, "answer_reward": 1.0, "reward": 1.0}
else:
return {"format_reward": 1.0, "answer_reward": 0.0, "reward": 0.0}
else:
# 不符合格式:直接判 0 分(同时 answer_reward 也为 0)
return {"format_reward": 0.0, "answer_reward": 0.0, "reward": 0.0}
因此:
- 格式遵循率 = 所有样本的
format_reward平均值。 - 推理准确率 = 所有样本的
answer_reward平均值(在格式正确的前提下计算答案是否等价)。
数据读取与 Ground Truth 解析(alignment/evaluate.py):
# alignment/evaluate.py(节选)
def get_gsm8k_test_data(test_data_path: os.PathLike) -> list[dict]:
data = []
with open(test_data_path, "r") as f:
for line in f.readlines():
obj = json.loads(line.strip())
ts = obj["answer"].split("####")
if len(ts) != 2:
print(f"invalid answer: {obj['answer']}")
continue
data.append({"question": obj["question"],
"think": ts[0].strip(),
"answer": ts[1].strip()})
return data
结果与讨论
在同一评估口径下,我们在 GSM8K 上得到如下对比(报告值):
| 指标 | 微调前(零样本) | SFT 微调后 |
|---|---|---|
| 推理准确率 | 1.56% | 62.9% |
| 格式遵循率 | 18.9% | 100% |
说明:
- 上述结果是在 alignment.evaluate 与 alignment.sft 的评估框架下得到的报告值。不同硬件/软件环境与随机种子可能引起轻微差异。
- “格式遵循率”达到 100% 的关键是训练时的模板约束与监督信号覆盖
<think>/<answer>,并在奖励函数中严格判定标签存在性。
常见问题与优化建议
- 训练不收敛或损失震荡:适当降低学习率(如 1e‑5 → 5e‑6)、增大
gradient_accumulation_steps,或提高max_seq_len以覆盖完整推理链。 - 显存不足:增加
--sft_device的卡数或调大--max_sft_gpu_memory_use,必要时裁剪序列长度或使用更小 batch。 - 评估速度慢:调小
SamplingParams的max_tokens;但过小的生成长度会影响完整<think>/<answer>输出与正确率。 - 格式仍偶发不合规:检查模板与数据是否一致(是否始终以
<think>开头),并确保 SFT 标签覆盖足量样本。
结论
通过对 Qwen/Qwen2.5-Math-1.5B 在 GSM8K 上的监督微调,我们实现了两条主线的同步提升:
- 推理链条更稳,零样本正确率从 1.56% 提升到 62.9%;
- 输出规范更强,格式遵循率从 18.9% 提升到 100%。
这背后的关键是“结构化输出模板 + 只对回应部分计损失 + 严格但宽容的评估规则”。如果你也在做数学推理或其他需要“思考‑答案二段式”输出的任务,强烈建议复用本文的架构与代码。
行动号召:现在就下载 GSM8K,跑一遍 uv run -m alignment.evaluate 与 uv run -m alignment.sft,观察你本地的改进幅度吧! 可以参考 llm-from-scratch 仓库中 alignment 模块,对照进行学习。
开放问题:在你的场景里,是否遇到过“答案正确但格式导致系统解析失败”的案例?你是如何设计模板与评估逻辑来避免它的?欢迎在评论区分享你的经验与挑战。
我推荐选 pretrain,理由如下:
pretrain 提高工程能力,sft 提高认知能力
作为校招新人,你的当务之急只有一条:**提升工程代码能力!**我们拆解一下两个团队所需要的技能,你判断下哪个提升代码能力更快。
在 pretrain 团队,你的必修课有:爬取互联网数据,大规模数据清洗与去重(hadoop、spark等),配置各种 torch 和 cuda 环境,搞懂、修改、优化 megatron 的代码,熟练 debug 多机通讯报错,成熟的炼丹技巧(数据配比,学习率,优化器,课程学习,分析 loss 曲线、scaling_law),跑通各 benchmark 验证模型能力;
在 sft 团队,训练框架和炼丹技巧只属于选修课,往往公司不给你时间学习,你的必修课大概只包含以下内容:手动标数据,用 gpt4 标数据,教会标注人员标数据,利用用户反馈标数据,根据实验结果优化数据,参考论文去合成数据。
pretrain 转 sft 的难度,小于 sft 转 pretrain 的难度
基于两个方向的必修课不一样,pretrain 团队的同学能轻松上手 sft 的工作,sft 团队的同学则不能快速接手 pretrain 的工作。毕竟,两个团队核心技术不同:
- pretrain 的核心技术:训练代码
- sft 的核心技术:训练数据
所以,当你从 pretrain 转去做 sft,花一天时间看一下训练数据,就可以开始干活了;但当你从 sft 转去做 pretrain,你可能得花两周时间学习 megatron,才能开始干活。
pretrain 的杂活比 sft 的杂活更能锻炼新人
前面列举了两个方向的工作内容,假设你作为新人只配去做数据工作这种杂活,那我们就再来仔细看下两个团队的杂活都是什么?
- pretrain 的杂活是从海量较脏的互联网数据中清洗出有意义的、干净的训练数据。大概包括:训个小模型给数据打分,写大量规则去除网页文档里的垃圾语料,研究某个 domain 数据的数据特征并想办法过滤该 domain 数据;
- sft 的杂活大概是:手动标数据,不断拿 GPT4 试出效果最好的 prompt 来标数据。
言尽于此,哪个杂活更能锻炼人我就不再分析了。
新人应该选最难的工作
pretrain 方向的最大痛点是什么?
短期内没有收益、长期训不过 llama、qwen,老板会选择拥抱开源。但是,你是校招新人,他不敢裁你。趁着你有“校招生”这个护身符,去做最难的工作、快速成长自己,丰满羽翼,有社会舆论和国家政策保护在,你只要别乱执行 rm -rf *,就都是安全的。
再过三两年,可能你就不能选有技术的活,而只能选有收益的活了。
我并没有说 sft 都是标数据的没意义的工作,我曾在另一个回答中力挺 sft 是有技术含量的。我只不过是认为,pretrain 能快速提升工程能力,这对新人非常可贵。成熟一点的程序员,写 hadoop、训 BERT 已经玩得滚瓜烂熟了,多跑一些 sft,找一找大模型的 feel 非常重要,但新人只需要去学习扎实的基本功。
很多人都说,新人只会被分配去打杂,与其去 pretrain 洗数据,不如去 sft 拿收益。但是,孟母三迁的故事并没有过时,人是有眼有腿的啊,可以主动去学习的,在 pretrain 团队,老板不让你做 scaling_law,但是总不能不让你看 scaling_law 的 wiki 吧,总不能不让你请教同事吧。(这段话同样说给选 sft 工作的新人,我们是可以主动去选择学习 pretrain 相关的知识的,不要被工作内容桎梏了眼界和学习范围)
我并没有说 sft 都是标数据的没意义的工作,我曾在另一个回答中力挺 sft 是有技术含量的。我只不过是认为,pretrain 能快速提升工程能力,这对新人非常可贵。成熟一点的程序员,写 hadoop、训 BERT 已经玩得滚瓜烂熟了,多跑一些 sft,找一找大模型的 feel 非常重要,但新人只需要去学习扎实的基本功。
很多人都说,新人只会被分配去打杂,与其去 pretrain 洗数据,不如去 sft 拿收益。但是,孟母三迁的故事并没有过时,人是有眼有腿的啊,可以主动去学习的,在 pretrain 团队,老板不让你做 scaling_law,但是总不能不让你看 scaling_law 的 wiki 吧,总不能不让你请教同事吧。(这段话同样说给选 sft 工作的新人,我们是可以主动去选择学习 pretrain 相关的知识的,不要被工作内容桎梏了眼界和学习范围)
不管选择哪个团队,记得抱紧大佬同事大腿,多学多问,“喊声爸爸,换一份 megatron 的训练代码与教程”,这买卖不亏,我就干过。
普通人如何抓住AI大模型的风口?
为什么要学习大模型?
在DeepSeek大模型热潮带动下,“人工智能+”赋能各产业升级提速。随着人工智能技术加速渗透产业,AI人才争夺战正进入白热化阶段。如今近**60%的高科技企业已将AI人才纳入核心招聘目标,**其创新驱动发展的特性决定了对AI人才的刚性需求,远超金融(40.1%)和专业服务业(26.7%)。餐饮/酒店/旅游业核心岗位以人工服务为主,多数企业更倾向于维持现有服务模式,对AI人才吸纳能力相对有限。

这些数字背后,是产业对AI能力的迫切渴求:互联网企业用大模型优化推荐算法,制造业靠AI提升生产效率,医疗行业借助大模型辅助诊断……而餐饮、酒店等以人工服务为核心的领域,因业务特性更依赖线下体验,对AI人才的吸纳能力相对有限。显然,AI技能已成为职场“加分项”乃至“必需品”,越早掌握,越能占据职业竞争的主动权
随着AI大模型技术的迅速发展,相关岗位的需求也日益增加。大模型产业链催生了一批高薪新职业:

人工智能大潮已来,不加入就可能被淘汰。如果你是技术人,尤其是互联网从业者,现在就开始学习AI大模型技术,真的是给你的人生一个重要建议!
如果你真的想学习大模型,请不要去网上找那些零零碎碎的教程,真的很难学懂!你可以根据我这个学习路线和系统资料,制定一套学习计划,只要你肯花时间沉下心去学习,它们一定能帮到你!
大模型全套学习资料领取
这里我整理了一份AI大模型入门到进阶全套学习包,包含学习路线+实战案例+视频+书籍PDF+面试题+DeepSeek部署包和技巧,需要的小伙伴文在下方免费领取哦,真诚无偿分享!!!
vx扫描下方二维码即可

部分资料展示
一、 AI大模型学习路线图
这份路线图以“阶段性目标+重点突破方向”为核心,从基础认知(AI大模型核心概念)到技能进阶(模型应用开发),再到实战落地(行业解决方案),每一步都标注了学习周期和核心资源,帮你清晰规划成长路径。

二、 全套AI大模型应用开发视频教程
从入门到进阶这里都有,跟着老师学习事半功倍。

三、 大模型学习书籍&文档
收录《从零做大模型》《动手做AI Agent》等经典著作,搭配阿里云、腾讯云官方技术白皮书,帮你夯实理论基础。

四、大模型大厂面试真题
整理了百度、阿里、字节等企业近三年的AI大模型岗位面试题,涵盖基础理论、技术实操、项目经验等维度,每道题都配有详细解析和答题思路,帮你针对性提升面试竞争力。

适用人群

第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

更多推荐
所有评论(0)