别急着微调:先分清是资料问题、习惯问题,还是行李问题
「把我们的文档喂给模型微调一下。」技术群里每周都有人这么说。这句话里,文档多半该走 RAG,微调多半不该碰,真正该做的事藏在第三个词里,上下文工程。三个词都在回答「怎么让模型答得更好」,按错开关,钱和时间都白花。本文给你一张排查表,照着病根选手段,别再凭感觉。
三个词各自管哪一层
微调(fine-tuning)改的是模型本身。拿一批样本继续训练,让模型换一种方式干活,格式稳定成你要的样子,语气收成你的口吻,任务模式变成条件反射。它改的是习惯,不是记忆。
RAG(检索增强生成)改的是模型看到的资料。回答之前先检索你的知识库,把相关片段塞进提示词。模型本身一个字节没动,它只是开卷考试时翻到了正确的那几页。它补的是资料。
上下文工程(context engineering)改的是行李打包。每次请求,模型能看的内容有上限,历史、系统提示、检索片段、工具结果全要挤进这个窗口。谁进谁不进、谁排前面、谁被压缩,是这层的工作。
用后端的话翻译
微调像改框架源码。收益大,门槛高,改一次要重新编译发布,回滚也麻烦,动手前先问有没有别的办法。
RAG 像给服务加一层查询。模型是服务,知识库是数据源,检索是查询接口,召回质量决定答案质量。它有整套数据工程的活,切分、索引、召回调优,一样躲不掉。
上下文工程像管请求体预算。窗口就是请求体大小上限,历史是会话状态,检索片段是查询结果,工具回执是外部回调。塞爆了就丢东西,丢错了模型就翻车。
三个类比放一起,边界就清楚了。微调动权重,RAG 动内容,上下文工程动的是组织。
为什么会混用
三个手段的效果都长一个样,模型答得更好了,症状相似,病因却在不同层。业务文档喂不进去,模型答非所问,这是资料问题。模型懂业务但格式天天变,这是习惯问题。聊到第十轮忘了开头的约定,这是行李问题。把病根认对,手段才不会用错。
最常见的错配有两个。想靠微调灌业务知识,费钱费力还会随知识过期而失效,这类需求的正解是 RAG。想靠 RAG 修输出格式,检索回来的片段管不了行为习惯,这类需求的正解是提示词约束或者微调。
什么时候用哪个
| 你看到的症状 | 病根在哪层 | 先用什么 | 别用错 |
|---|---|---|---|
| 格式不稳定、语气不对、任务做不熟 | 模型的习惯 | 提示词约束,不行再微调 | 别用 RAG 修格式,检索片段管不了行为 |
| 不知道你的私有知识、答的是过时事实 | 模型的资料 | RAG | 别用微调灌知识,费钱还会随知识过期失效 |
| 聊久了忘约定、上下文经常爆 | 行李打包 | 上下文工程 | 别用微调治失忆,模型没忘,是行李被丢了 |
| 什么都差一点 | 多层都有 | 按下面的顺序逐个试 | 别一次全上,先修装箱再补资料最后动权重 |
一个装箱演示
下面用一段 Python 演示上下文工程的日常工作,检索片段和历史怎么挤进预算。核心思路是「检索管找块,装箱管取舍,每一块都有代价」。跑之前先记住预期输出:预算一紧,历史最先被丢,模型随后忘事。
# 模拟一次请求的上下文组装。
# RAG 负责找块,上下文工程负责在预算里装箱。
# 微调不在这段里,它发生在模型训练侧,装箱前就已定型。
BUDGET = 55 # 假装 token 约等于字符数,压到能看见取舍
DOCS = {
"退款": "退款规则:七天内无理由退款,超期按比例折算。",
"运费": "运费规则:满 99 包邮,偏远地区加收 20。",
"发票": "发票规则:订单完成后 30 天内可开电子发票。",
}
def retrieve(query: str, k: int = 2) -> list[str]:
"""关键词召回,模拟 RAG 的输出:一块块资料片段。"""
hits = [text for key, text in DOCS.items() if key in query]
return hits[:k]
def assemble(system: str, blocks: list[str], history: list[str], budget: int) -> dict:
"""装箱。优先级:系统提示 > 检索片段 > 历史。
装不下的历史从最旧开始丢,这是最常见的失忆来源。"""
kept = {"system": system, "blocks": [], "history": [], "dropped": []}
used = len(system) # 系统提示优先占位
for b in blocks:
if used + len(b) <= budget:
kept["blocks"].append(b)
used += len(b)
for h in history:
if used + len(h) <= budget:
kept["history"].append(h)
used += len(h)
else:
kept["dropped"].append(h)
return kept
if __name__ == "__main__":
system = "你是客服助手,回答要短。"
history = ["用户:我上周买的键盘想退", "助手:好的,我帮您查"]
blocks = retrieve("键盘退款怎么算")
result = assemble(system, blocks, history, BUDGET)
print("装进窗口的检索片段:", result["blocks"])
print("装进窗口的历史:", result["history"])
print("被丢掉的历史:", result.get("dropped", []))
print("结论:预算不够时,历史最先挨刀,模型随后忘事。")
跑完就能看见,预算一紧,历史最先被丢,模型失忆的锅往往不在模型。缓解办法在正文之外还有摘要压缩和分层检索,本篇不展开。
适用边界
三个词的定义在各家文档里不完全统一,有的厂商把提示词模板也叫上下文管理,按用途记比按名词记稳。三个手段可以组合用,顺序有讲究,先修装箱,再补资料,最后才动权重。判断表是排查顺序,不是教条。原则就一条:先问病根在哪层,再伸手拿手段。下次再听到「把文档喂给模型微调一下」,先反问一句:这是资料问题、习惯问题,还是行李问题?
340



被折叠的 条评论
为什么被折叠?



