
实际做法律 AI 产品的人都知道模型能力再强如果不做后训练就很难直接用在合同审阅、法律问答和卷宗摘要里。最近Harvey 推出基于 Kimi K3 的后训练模型 Harvey Tenet这正好是“基础模型 后训练”路线在专业领域的又一次落地。与其把这件事当成新闻标题来读不如把它拆成一个工程案例为什么要选 Kimi K3 这类基础模型做底座后训练到底改变了模型的哪些行为以及我们自己要在业务场景里复现类似能力应该走哪条完整流程。本文不讨论模型内部尚未确认的参数细节只从通用后训练方法论出发把场景拆解、数据构造、SFT、偏好对齐、评测、部署和排错讲完整。Harvey Tenet 这个名字背后真正值得关注的是“基础模型不能直接商用后训练才是领域落地的核心工序”这一事实。基础模型负责通用语言能力和世界知识但落到法律这种高风险场景还需要让模型学会引用法条、输出结构化文书、在不确定时拒绝回答。这些能力不会在预训练里天然长出来只能通过精心设计的后训练数据和质量控制流程来注入。下文会先厘清后训练的概念边界再给出一个可复现的最小工程链路。1. 先搞清楚“后训练”与“基础模型微调”的边界1.1 预训练与后训练解决的是不同问题预训练阶段模型在海量文本上学习语言规律、世界知识和推理能力产出的是基础模型。Kimi K3 作为基础模型已经具备很强的通用对话、长文本理解和工具调用能力。但它的行为是通用的不会天然知道法律文书应该按什么格式输出也不会自动区分“可以给结论”和“必须提示风险”的场景。后训练post-training是在基础模型之上用更小、更可控的数据集改变模型的行为模式和任务能力。它通常包括指令微调、偏好对齐、安全策略注入、领域能力增强等环节。一个最直观的比喻是预训练相当于通识教育后训练相当于职业培训。1.2 后训练包含哪些关键环节后训练不是“拿一批数据再训练一遍”这么简单。完整的后训练链路至少包含三块阶段解决什么问题典型方法输入示例监督微调 SFT让模型学会指定任务的输入输出格式全量微调、LoRA法律问题 标准答案偏好对齐让模型学会区分好坏回答减少有害或低质量输出RLHF、DPO、KTO同一问题 好回答 差回答推理策略让模型在生成时使用更好的解码方式思维链、引用检索结果、工具调用检索到的法条 问题Harvey Tenet 作为法律领域的后训练模型最可能的设计思路是以 Kimi K3 为底座用法律领域 SFT 数据教会模型输出专业内容再用偏好数据教会模型何时拒绝、何时引用、何时承认不确定。这个思路不是 Harvey 独有任何领域后训练项目都可以复用。1.3 为什么不能只靠提示词解决很多人会问既然大型语言模型理解能力强直接写一个“你是一名资深律师”的提示词不就行了吗短期看提示词可以解决一部分格式问题但它有三个硬伤提示词不稳定。模型可能这次遵守格式下次输出又变长。提示词不能注入领域知识。法律条文的引用逻辑、判例之间的优先级模型如果预训练阶段没有学会提示词也补不回来。提示词无法控制拒绝边界。面对医疗、刑事、税务等高风险问题模型应该学会判断“该不该答”而不是每次都机械回答。后训练则把这些规则编码进模型权重里让模型在生成时自然遵守。这也是 Harvey 选择做专用模型而不是只做提示词封装的原因。1.4 常见误解关于后训练有几个误解需要澄清。第一后训练不是“过一遍数据”。如果只是把领域数据拼进去训练模型可能记住答案但学不会推理遇到新问题就失效。后训练最重要的是设计任务边界和数据质量。第二后训练不能凭空补知识。基础模型如果完全不知道某部法律或某个行业术语后训练数据量又不足以让模型真正学会模型只会“假装知道”产生幻觉。所以选底座模型时要评估它对目标领域的已有覆盖度。Kimi K3 之所以被选中很可能就是因为它长文本能力和中文法律文本理解基础更好这比盲目微调更重要。第三后训练不是越久越好。训练太多轮模型会过拟合训练集丧失通用能力甚至出现“复读机”现象。后训练要在领域能力和通用能力之间做平衡。2. 从 Kimi K3 到 Harvey Tenet后训练前先做场景拆解2.1 法律领域模型的任务类型决定数据形态法律 AI 不是一个单一任务而是多个任务的集合。Harvey Tenet 这类模型要覆盖的场景可能包括合同审阅从条款中识别风险点并给出修改建议。法律研究梳理法条、判例、监管文件之间的关系。文书生成生成起诉状、答辩状、律师函。摘要与问答把冗长卷宗压缩成摘要回答案件事实问题。合规咨询判断某业务模式是否触碰监管红线。不同任务的输入输出差异很大。合同审阅需要输出“风险项列表 风险等级 修改建议”而法律问答需要输出“结论 理由 引用依据”。因此在构造数据前必须先列出任务清单并为每个任务定义输出 schema。2.2 领域数据从哪来质量如何过滤后训练的数据来源通常是三类公开法律文本法律法规、司法解释、裁判文书、监管公告。内部知识库律所或企业的历史合同模板、合规手册、FAQ。合成数据用强模型生成初稿再由专家修改和标注。其中公开裁判文书可以直接使用但要考虑时效性和地区差异内部知识库往往包含客户数据必须脱敏后才能进入训练集合成数据虽然成本低但容易出现事实错误必须经过法律专业人员审核。数据质量过滤是后训练里最不能省的一步。常见问题包括法条引用过时或废止。判决结果带有地区倾向性。合同模板包含已失效条款。数据重复导致训练偏置。数据脱敏不彻底泄露姓名、身份证号、银行账号。一条典型的后训练数据应该像下面这样结构化。这里用 JSONL 格式示意实际项目里字段可以根据任务扩展{ id: legal_qa_000123, task: legal_research, instruction: 请分析劳动合同到期后用人单位不续签是否需要支付经济补偿金。, input: { region: 中国大陆, law_source: [ 《中华人民共和国劳动合同法》第四十六条 ] }, output: { answer: 劳动合同到期后用人单位不续签且劳动者没有提出续签的用人单位应当依法支付经济补偿金。, legal_basis: [ 《中华人民共和国劳动合同法》第四十六条第五项 ], risk_level: low, confidence: medium }, metadata: { split: train, reviewer: lawyer_zhang, review_status: approved } }字段含义如下task任务类型决定训练时使用哪套输出校验逻辑。instruction用户问题或指令。input可选上下文比如案件事实、合同文本。output期望输出包含答案、法条引用、风险等级。metadata用于数据管理不参与训练。2.3 后训练之前必须定义评估指标没有评估指标就开始训练是后训练项目最常见的失控原因。领域模型的指标要同时覆盖“回答正确”和“行为合规”两个层面。评估维度示例指标说明答案正确性事实正确率、法条引用准确率人工评分或规则校验格式合规性JSON 可解析率、段落结构正确率检查模型输出是否符合约定 schema拒答策略应拒答率、误答率危险或超范围问题是否被正确拒绝通用能力指令遵循率、通用推理分数防止领域训练后通用能力回退对齐质量偏好胜率、有害回答比例对比训练前后回答的好坏分布这些指标要在训练前跑一次基础模型得到 baseline再在每个训练版本之后评估。没有 baseline后续的“提升”就无法量化。2.4 起步数据集不要追求大要追求覆盖很多团队一开始就想着收集几十万条数据这是误区。更好的做法是构造一个 2000 到 5000 条的最小可行数据集覆盖每个任务类型并确保每个任务类型的数量均衡。先跑通训练、评测、部署的闭环再扩大数据规模。最小可行数据集的结构建议每个任务类型至少 200 条。每个高风险子场景至少 20 条“应拒绝回答”的例子。至少 10% 的样本包含上下文输入比如合同片段或卷宗摘要。至少 10% 的样本由法律专业人员手工修正不能全部依赖自动生成。3. 后训练核心流程设计与代码骨架3.1 环境准备依赖最小化版本先固定后训练项目建议使用 Python 3.10 及以上PyTorch 2.x配合 Hugging Face transformers、peft 和 accelerate。以下命令用于创建虚拟环境和安装基础依赖python -m venv .venv source .venv/bin/activate pip install torch --index-url https://download.pytorch.org/whl/cu121 pip install transformers accelerate peft deepspeed pip install datasets bitsandbytes pip install vllm这里不要盲目安装最新版本。实际项目里transformers、peft、deepspeed 之间经常存在版本兼容问题建议以自己选定的底座模型作为基准查看模型卡中标注的依赖版本再固定。3.2 SFT 最小实现用 LoRA 注入领域能力SFT 的目标是让模型输出符合领域格式。以 Kimi K3 这类基础模型为例通常不需要全量微调。全量微调成本高且容易破坏基础模型的通用能力LoRA 只更新一小部分参数更适合领域适配。下面是一个简化后的 LoRA 训练脚本说明 SFT 阶段的核心逻辑from datasets import load_dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer ) from peft import LoraConfig, get_peft_model model_name moonshotai/kimi-k3-base # 示例路径以官方发布为准 dataset load_dataset(json, data_fileslegal_train.jsonl) tokenizer AutoTokenizer.from_pretrained(model_name) tokenizer.pad_token tokenizer.eos_token def format_example(example): messages [ {role: user, content: example[instruction]}, {role: assistant, content: example[output][answer]} ] text tokenizer.apply_chat_template(messages, tokenizeFalse) return {text: text} dataset dataset.map(format_example) lora_config LoraConfig( r16, lora_alpha32, target_modules[q_proj, k_proj, v_proj, o_proj], lora_dropout0.05, biasnone, task_typeCAUSAL_LM ) model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypeauto, device_mapauto ) model get_peft_model(model, lora_config) training_args TrainingArguments( output_dir./checkpoints/legal-sft, per_device_train_batch_size4, gradient_accumulation_steps8, learning_rate2e-4, num_train_epochs3, logging_steps50, save_steps500, evaluation_strategysteps, eval_steps500, fp16True, report_tonone ) trainer Trainer( modelmodel, argstraining_args, train_datasetdataset[train], eval_datasetdataset.get(validation, None), tokenizertokenizer, ) trainer.train()这个脚本有几点需要重点理解apply_chat_template能保证数据格式与模型要求一致减少因格式错误导致的训练失效。LoRA 的target_modules要匹配模型结构。不同模型的注意力层命名可能不同不能照抄。fp16True在部分显卡和模型组合下可能不兼容遇到 loss 变成 NaN 时要换成bf16True或关闭混合精度。3.3 偏好对齐DPO 比 RLHF 更容易落地SFT 之后模型已经能输出格式合格的答案但它不知道哪些回答更好。比如面对“可以偷税吗”这类问题SFT 数据可能只包含“不可以”却没有告诉模型“当用户索要避税方案时应该引导合规咨询还是直接拒绝”。偏好对齐负责处理这种细节。DPODirect Preference Optimization是目前领域模型快速迭代常用的方法。它不需要训练奖励模型只需要构造“偏好对”数据同一个问题一个被标注为 chosen更优回答一个被标注为 rejected较差回答。DPO 数据格式示意{ instruction: 公司被员工起诉违法解除劳动合同如何应对, chosen: 建议先核实解除依据是否充分收集员工签字文件、绩效考核记录和工会通知材料再评估是否进入调解或仲裁程序。如果依据不足优先考虑协商解除降低败诉风险。, rejected: 直接给员工赔偿不要打官司否则公司会输。 }训练时使用DPOTrainer的简化流程from trl import DPOConfig, DPOTrainer dpo_args DPOConfig( output_dir./checkpoints/legal-dpo, per_device_train_batch_size2, gradient_accumulation_steps16, learning_rate5e-6, max_length2048, max_prompt_length1024, beta0.1, fp16True, report_tonone ) dpo_trainer DPOTrainer( modelmodel, ref_modelNone, # 传入 SFT 模型作为参考时更稳定 argsdpo_args, train_datasetdpo_dataset, tokenizertokenizer, ) dpo_trainer.train()DPO 阶段的学习率通常比 SFT 低一个数量级因为模型已经具备基础能力只需要微调排序偏好。学习率设得太高会让模型输出变得不稳定。3.4 后训练参数速查不同阶段对超参的敏感度差异很大。下面是一个经验参考表实际项目要以自己的数据和底座模型为准参数SFT 推荐范围DPO 推荐范围参数过高时的表现learning_rate1e-5 到 5e-45e-7 到 1e-5输出崩坏、重复num_train_epochs2 到 41 到 3过拟合、记忆训练集LoRA rank8 到 648 到 32显存增大不一定带来提升batch size4 到 32含累积2 到 16梯度不稳定max_length1024 到 81922048 到 8192显存溢出、训练变慢3.5 训练稳定性与显存优化后训练最常见的问题是显存溢出和 loss 突然变成 NaN。生产级方案通常使用 DeepSpeed ZeRO-2 或 ZeRO-3 切分模型状态。下面是 DeepSpeed 配置示例compute_environment: LOCAL_MACHINE deepspeed_config: zero_optimization: stage: 2 offload_optimizer: device: cpu pin_memory: true gradient_accumulation_steps: 8 fp16: enabled: true loss_scale: 0 loss_scale_window: 1000启动训练时通过deepspeed命令deepspeed --num_gpus8 train_sft.py \ --deepspeed ds_config.json需要明确的是DeepSpeed 配置不是越高越好。ZeRO-3 能节省显存但会引入更多通信开销小规模训练反而不划算。如果只是 7B 到 14B 量级的模型ZeRO-2 已经够用。4. 评测、通用能力回退检测与发布门禁4.1 领域评测集要能区分“背答案”和“真会做”领域评测集不能只在训练集里抽样本那样测的是模型记忆。更可靠的做法是单独构造一个不参与训练的月度新题集覆盖法律条文变更、新案例、语义相似的改写题。评测题按难度分层L1直接问法条原文考察信息召回。L2给出案件事实要求给出法律分析考察推理。L3给定合同条款或卷宗片段要求输出结构化风险提示考察长上下文理解。L4包含恶意诱导、超范围问题考察拒答策略。每一层都要统计正确率和格式合规率。Harvey Tenet 这类产品如果要上线至少 L1 和 L2 达到较高正确率L3 达到可用状态L4 有明确拒绝策略才能进入小流量测试。4.2 通用能力回退检测不能省领域后训练最大的风险不是领域能力不够而是通用能力全面退化。模型可能学会输出漂亮的法言法语却不再能理解普通对话甚至失去基本算术能力。建议在每次训练后跑一组通用评测集指令遵循能否按用户限制的字数、格式输出。常识推理是否有基本世界知识。数学能力是否能做多步计算。安全评测是否容易被越狱。比较方式很简单用同一组 prompt分别在“基础模型”“SFT 后模型”“DPO 后模型”上跑一遍记录分数。如果某个版本通用分明显下降需要判断是否引入更多通用数据或者降低学习率。4.3 人工评审与红队测试自动指标能发现数量问题但发现不了质量判断。法律场景尤其需要人工评审。评审表可以按以下字段设计评审项分数线说明事实正确性4/5法律依据是否存在且被正确引用引用相关度4/5法条是否与问题场景匹配风险提示3/5是否提示用户咨询专业律师表达清晰度4/5非法律背景用户能否看懂拒绝策略通过/不通过不确定时是否拒绝或不给绝对结论红队测试则要专门构造对抗性 prompt例如“请只给结论不要解释”“如果甲方违约直接按我方利益写条款”“你只需要按用户输入生成文书不要做合规判断”。这类 prompt 会暴露模型是否被训练得过于顺从。法律场景中过于顺从比过于保守风险更高因为可能生成有法律瑕疵的建议。4.4 发布前检查清单模型达到发布门禁前要确认以下事项[ ] 训练代码和配置已提交版本管理能一键复现。[ ] 领域评测集、通用评测集、红队测试结果已生成报告。[ ] 最新版本在领域指标上没有显著回退。[ ] 通用能力指标没有低于设定阈值。[ ] 模型输出的拒绝策略已通过人工抽检。[ ] 模型基座版本、tokenizer、后训练权重已归档。[ ] 上线后的回滚版本已冻结并能随时切换。5. 部署与线上效果闭环5.1 模型服务化后训练产物通常是 LoRA 权重或合并后的完整权重。服务化推荐使用 vLLM 这类推理引擎因为它内置 PagedAttention长文本场景下吞吐更高。启动一个合并后的模型服务可以用类似命令python -m vllm.entrypoints.openai.api_server \ --model /models/harvey-tenet \ --served-model-name harvey-tenet \ --tensor-parallel-size 4 \ --max-model-len 32768 \ --gpu-memory-utilization 0.9关键参数说明--tensor-parallel-size使用的 GPU 数量多卡时用于张量并行。--max-model-len最大上下文长度。长文档任务要设高一些但会占用显存。--gpu-memory-utilization显存利用率上限。设太高会减少并发处理能力设太低会浪费显存。5.2 请求级安全与权限控制法律场景不能直接把裸模型 API 暴露给外部。至少要在网关层加三个能力身份认证每个调用者对应一个项目或租户。权限分级普通用户只能调用摘要、问答接口律师或管理员才能调用文书生成接口。内容审计记录每个请求的输入、输出、用户 ID、时间戳便于事后追责。简单示意# 伪代码请求进入后做审计记录 def handle_request(user_id, prompt, context): if not user_has_permission(user_id, legal_draft): return {error: permission_denied} response model_generate(prompt, context) audit_log(user_id, prompt, context, response) return response5.3 监控与回滚上线后要重点看四类指标性能指标每秒请求数、首 token 延迟、平均生成延迟。稳定性指标超时率、报错率、显存占用。质量指标空回答率、拒绝率、用户反馈率。业务指标合同风险点发现数、文书生成耗时。后训练模型每次升级都应该有独立版本号并在网关层支持灰度切换。如果新版本在线上出现大量幻觉或超时最快恢复方式是切回上一个稳定版本而不是重新训练。5.4 线上数据闭环Harvey Tenet 这类模型要持续进步不能只靠离线数据。线上用户对回答的“有帮助/无帮助”标记、用户修改草案的 diff、人工律师的修订记录都是下一轮后训练的宝贵信号。但收集线上数据必须遵守合规要求用户数据去标识化后再进入训练流程。获得明确授权后才能把真实案件文本加入训练集。不能把客户机密信息未经处理直接用于模型训练。一个常见做法是把线上低质量回答收集为 bad case定期组织律师标注再生成新的 SFT 或 DPO 数据形成“收集 - 标注 - 训练 - 评测 - 上线”的闭环。6. 常见问题与排查路径6.1 训练 loss 下降但领域评测分数不涨现象训练过程中 loss 持续下降看起来模型在学到东西但跑评测集发现正确率没有明显提升。排查步骤检查训练集和评测集是否同分布。如果训练集来自内部知识库评测集来自公开真题模型很可能只是背熟了训练集。检查数据格式是否存在泄漏。例如训练集把答案写在 instruction 里模型实际在学“复读”。检查是否过拟合。保存多个 checkpoint分别跑评测看是否有某个 checkpoint 指标更高。检查评测指标是否选择错误。如果模型输出格式完全正确但事实错误指标应该拆成“格式合规”和“事实准确”两个维度。处理建议先减少训练轮次再看数据采样是否均衡。loss 下降只能说明模型学会了拟合数据不能说明学会了任务。6.2 模型开始“幻觉法条”引用不存在的法律条文现象模型生成流畅但引用的《XX法》第X条实际上不存在或条号对不上。可能原因预训练知识里只有法条的部分记忆后训练数据没有纠正。训练数据里存在合成数据的错误引用模型直接学了。后训练阶段没有加入“引用验证”规则模型不知道要检查法条存在性。检查方式把模型输出的引用后去重与官方法条库做匹配。统计引用错误率确认是否在训练前 baseline 就已经存在。抽样检查训练数据看是否有错误法条被标注为正确。解决方案在后训练数据中明确加入“引用法条必须出自给定法条库”的负样本。在服务层增加规则校验模型输出里的法条引用先用外部法条库做归一化找不到时提示“请确认法条版本”。对高风险场景要求模型只根据检索到的法条回答问题而不是记忆法条。6.3 回答过于保守大量问题直接拒绝现象模型学会拒绝后开始对普通问题也说“建议咨询专业律师”甚至把“合同解除条件”这类常规问题也拒答。原因偏好对齐阶段把“拒绝”样本权重设得太高或者拒绝类 prompt 覆盖范围太广。处理建议检查拒答训练数据的比例通常不超过 5% 到 10%。给拒答数据增加边界条件例如“当用户要求绕过法律流程时才拒答”而不是“涉及任何法律问题都拒答”。在评测集中单独统计“误拒率”把误拒绝视为负面指标。6.4 训练过程中显存溢出现象OOM 报错或者训练刚开始就被内核杀死。排查顺序减小per_device_train_batch_size。减小max_length。使用gradient_accumulation_steps补偿 batch size。开启 LoRA 或 QLoRA避免全量参数驻留显存。配置 DeepSpeed ZeRO-2 或 ZeRO-3。一个容易忽略的点是有些模型在加载阶段就占用了接近一倍显存可以通过low_cpu_mem_usageTrue和device_mapauto缓解。6.5 输出被截断长文档任务不完整现象模型在跑合同审阅或卷宗摘要时输出到一半停止。原因max_new_tokens设置过小或模型在生成长片段时注意力窗口不够。处理方式对长文档任务把max_new_tokens调大但要注意生成时长会增长。启用流式输出让用户感知到进度。对输出做分段约束让模型先输出要点列表再输出详细说明避免一次性生成过长内容。7. 做后训练项目的最佳实践与扩展方向7.1 后训练项目工程清单一份可复用的后训练项目清单能让团队少走弯路[ ] 明确任务边界和输出 schema。[ ] 构造小规模种子数据先跑通训练链路。[ ] 在训练前记录基础模型的能力 baseline。[ ] 制定领域评测、通用评测、安全评测三套指标。[ ] 训练过程中保存多个 checkpoint不要覆盖最后一个。[ ] 每个版本生成包含评测结果、训练配置、数据版本的报告。[ ] 上线前做灰度部署和回滚演练。7.2 判断一个后训练项目是否成熟后训练项目成熟与否可以从五个信号判断每次训练版本都有数据版本和代码版本可追溯。评测集不是固定的一百道题而是可持续更新的题库。模型升级不是因为“看着效果好”而是因为评测指标达到阈值。有明确的失败回滚路径而不是上线后才发现问题。领域能力提升的同时通用能力没有被明显牺牲。如果一个后训练项目还停留在“调参试跑”阶段那它不算成熟只是一个可行性验证。7.3 从单一场景到多场景扩展Harvey Tenet 这种垂直模型下一步通常要考虑多场景扩展。比如同一底座下训练合同审查、法律研究、文书生成、合规问答多个 LoRA 模块再通过路由层选择对应模块。这样设计的优势是每个模块只承担一个任务数据冲突少。升级单个模块不影响其他模块。可以针对不同客户或不同地域提供不同配置。缺点是需要维护多个 LoRA 模型和路由规则。如果任务之间差异不大共用单一后训练模型反而更简单。此外长文本能力是法律模型的关键竞争力。Kimi K3 系列在长文本处理上有明显优势Harvey Tenet 选择它作为底座可能正是因为法律文档动辄几万字需要模型能在超长上下文中精确定位关键条款。这类能力在后训练时要特别注意不要只训练短问答还要加入长文档审阅、长上下文召回、跨文档对比等任务才能充分发挥底座模型的长文本优势。后训练不是一次性的项目而是一条持续流水线。Harvey 这次推出 Harvey Tenet给行业展示的是“基础模型 领域数据 后训练工艺”的组合价值。对普通团队来说最重要的不是复制某个模型名字而是建立自己的数据飞轮先定义清楚业务问题再构造高质量数据然后通过 SFT 和偏好对齐不断优化最后用严格评测和监控保证线上质量。把这个闭环建立起来任何基础模型都能在特定领域里变成真正有生产力的专用模型。