一、先把两个概念放到同一张桌子上
很多人的第一反应是「微调更高级、提示词是糊弄」,这其实是个误解。提示词工程(Prompt Engineering) 是在模型权重不动的前提下,靠改写输入来引导模型行为;微调(Fine-tuning) 则是拿一批数据去更新模型的部分或全部权重,把行为「刻」进模型里。两者不是高低关系,而是解决同一问题的两种不同杠杆:一个改「问法」,一个改「脑子」。
理解它们的区别,关键看三件事:能力从哪来、改动花多少成本、错了好不好回退。提示词工程的成本是 token 和上下文窗口,改错了改回一句话就行;微调的成本是数据、GPU 和训练时间,模型训歪了要回滚就得重训。所以在实际工程里,它们更像一条流水线上的两个阶段,而不是二选一的单选题。
提示:把提示词工程当成「零样本调试手段」,把微调当成「把调好的行为固化下来的手段」。顺序几乎永远是:先用提示词把问题定义清楚,再考虑要不要固化。
二、各自擅长什么:一张能力对照表
提示词工程的强项在于快速试错和知识注入。比如你想让模型按你们公司的语气写周报、输出特定 JSON 结构、或者引用一份最新的产品文档,这些都可以通过 system prompt、少样本示例(few-shot)、RAG 立刻生效,改一行字就能上线。它尤其擅长「一次性」的、经常变化的要求。
微调的强项在于风格稳定性、输出格式的高一致性和领域术语/任务模式的内化。比如医疗报告生成、代码补全的特定方言(比如你们内部框架的 API 调用习惯)、或者需要在极短上下文里完成复杂指令的场景。微调过的模型往往可以用更短的提示词达到同样的效果,这会直接省下推理时的 token 开销。
- 想改「模型该说什么」→ 优先提示词 +
RAG - 想改「模型说话的方式/格式/口吻」→ 考虑微调
- 知识会频繁更新 → 提示词 + 检索,别微调(权重里的知识会过期)
- 任务稳定但要求极致一致 → 微调收益大
- 没有几百条以上的高质量标注数据 → 先别微调
三、决策流程:五个问题定方向
我自己的判断顺序是这样的:第一步,这件事能不能用一段清晰的提示词描述清楚?能就先写提示词。第二步,提示词是不是已经膨胀到几千 token,导致上下文吃紧或延迟过高?如果是,微调可以把这段「说明书」压缩进权重里。第三步,是否有足够且一致的标注数据?微调的质量上限基本由数据决定,垃圾数据只会让模型更自信地说错话。第四步,错误代价高不高?医疗、金融这类场景要格外谨慎,微调可能让模型产生「幻觉式自信」。第五步,你的预算和迭代速度允许多久改一次模型?提示词可以小时级迭代,微调通常以天计。
一个常见误区是拿微调去补「知识」。大模型的知识来自预训练,微调更擅长注入「模式」而非「事实」。如果你的目标是让模型知道你们公司的规章制度,正确做法是 RAG 检索 + 提示词注入;微调只适合让模型学会「按制度的格式和语气来回答」。
提示:经验法则——先提示词、后微调。如果你的提示词已经稳定运行一个月没怎么改,且占了大量上下文,那就是微调的信号。
四、动手对比:同一个任务的两种写法
假设任务是「把用户评论转成带 sentiment 字段的 JSON」。提示词方案长这样,靠示例约束格式:
prompt = """你是情感分析器。严格输出 JSON,字段只有 sentiment,取值为 positive/negative/neutral。
不要输出任何解释文字。
示例:
输入:这家店服务太差了,等了一个小时
输出:{"sentiment": "negative"}
输入:今天天气真好,心情愉快
输出:{"sentiment": "positive"}
输入:%s
输出:"""
同样的效果,用 transformers 做指令微调(LoRA)大概是这样。注意关键在于构造指令-回复对,而不是堆数据量:
from datasets import load_dataset
from trl import SFTTrainer, SFTConfig
from peft import LoraConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
dataset = load_dataset("json", data_files="reviews.jsonl")["train"]
lora = LoraConfig(r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"])
args = SFTConfig(output_dir="out", num_train_epochs=3, per_device_train_batch_size=4,
learning_rate=2e-4, max_seq_length=512)
trainer = SFTTrainer(model=model, args=args, train_dataset=dataset, peft_config=lora)
trainer.train()
微调后你会发现,推理时那段长长的示例可以删掉,直接一句「转 JSON」模型就能稳定输出。这正是微调最实在的收益:把上下文成本换成了训练成本。但代价是格式一变就得重训,而提示词改一行就行。
五、微调的几个实操坑
第一个坑是数据量幻觉。很多人以为要几万条才行,实际上对于风格迁移、格式约束这类任务,几百到几千条高质量、风格统一的数据就能看到明显效果,用 LoRA 甚至更少。数据质量远比数量重要,宁可 500 条干净的,不要 5000 条自相矛盾的。
第二个坑是灾难性遗忘(Catastrophic Forgetting)。全参数微调容易让模型在你的窄任务上表现变好,但在通用能力上退化。所以实践中优先用 LoRA / QLoRA 这类参数高效方法,只训练极小一部分参数,风险和成本都低得多。另外记得留一份通用测试集,每次训完都跑一遍,别只盯着自己的任务指标。
第三个坑是评估缺失。提示词工程的评估可以靠人眼看输出,微调必须有 held-out 验证集,否则你根本不知道模型是学会了还是背下来了。训练集和验证集的划分,以及「什么算好」的量化标准,都应该在动手前就定好。
六、实战里最常见的组合拳
多数成熟系统其实是「提示词 + RAG + 轻量微调」的三层结构:用 RAG 解决知识的时效性和私有性,用提示词定义任务和输出契约,用 LoRA 微调让模型在你们的领域语料上说得更地道、格式更稳定。这种分工让每层都可以独立升级——换知识库不动模型,改提示词不动权重,重训 LoRA 不动基座。
最后分享一个判断「该不该微调」的反向标准:如果你还在频繁改需求,就别微调。微调的本质是把一套已经确定的行为固化下来,需求没稳定就固化,等于把返工成本从「改一行字」放大到「重训一轮」。让提示词做你的试验田,让微调做你的定稿。
提示:做微调前先问自己一句——「我能不能用 10 条示例 + 一段说明把这个任务讲明白?」如果能,提示词通常就够了;如果你发现这段说明已经长到影响效果,那就是微调的入场券。