传统的大模型应用把线上失败留在日志里:团队修提示词、补规则、扩大检索库,却很少让模型本身发生变化。Shopify 的案例展示了另一条路线——每天整理生产环境中的失败样本,将修正结果压缩进模型权重,再通过高吞吐推理引擎上线新版本。
来源摘要给出的结果很醒目:在特定业务质量指标上超过前沿模型,并将服务成本降低 96%。这里的关键不是简单地“每天微调一次”,而是建立一条可评估、可回滚、能抵御脏数据的持续学习流水线。
为什么要把失败变成训练数据
线上请求天然携带了静态数据集没有的信息:真实用户如何表达需求、模型在哪些边界条件下出错,以及哪些错误对业务最昂贵。
一个有效的反馈单元至少应包含:
- 原始请求及必要的业务上下文;
- 当时运行的模型、提示词和检索版本;
- 模型的错误输出;
- 失败类型,例如格式错误、事实错误、工具调用失败或策略违规;
- 经过人工确认或确定性程序验证的正确答案;
- 数据使用授权、脱敏状态和样本权重。
真正进入训练集的,不应是所有低评分对话。用户点踩可能来自界面延迟,自动判分器也可能误判。如果未经验证就让模型学习这些信号,持续学习很快会变成持续污染。
这个闭环可以概括为:
生产请求
-> 失败检测与抽样
-> 脱敏、去重、归因
-> 生成或人工确认修正答案
-> 与历史回放数据混合训练
-> 离线评估和安全门禁
-> vLLM 灰度发布
-> 继续采集失败
“压缩进权重”的价值在于,反复出现的领域模式不必每次都通过超长提示词、额外检索或昂贵的大模型调用来解决。一个经过针对性训练的小模型,可能在范围明确的业务任务上胜过更大的通用模型。但这不等于它拥有更强的通用智能;所谓质量领先,应限定在同一数据分布、同一评分规则和同一延迟约束下比较。
PyTorch 负责学习,vLLM 负责把经济账算通
持续学习系统通常将训练和推理解耦。
PyTorch 一侧处理参数更新。实际工程中可以采用全量微调,也可以使用 LoRA 等参数高效方法。每日增量样本数量有限时,LoRA 往往更容易存储、审核和回滚;如果数据分布已经发生大幅迁移,则可能需要周期性的全量再训练。
vLLM 一侧负责在线服务。连续批处理、KV Cache 管理以及高并发调度,可以提高 GPU 利用率。配合更小的领域模型或可切换的 LoRA 适配器,团队可以减少对高价外部模型的依赖。
96% 的成本下降不能直接复制到所有系统。它通常同时取决于模型尺寸、请求长度、批处理率、GPU 价格、流量稳定性,以及原方案是否频繁调用昂贵的前沿模型。迁移前应按每个成功任务的成本计算,而不是只比较每百万 Token 的标价:
单次成功任务成本 = 总推理成本 / 通过质量门槛的任务数量
如果便宜模型导致更多重试、人工接管或错误订单,Token 成本下降并不代表总成本下降。
一个可以改造的最小训练与部署示例
下面是一个教学性质的 LoRA 闭环,不代表 Shopify 的内部实现。它假设失败样本已由人工或可信程序修正,并保存为聊天消息。示例使用小模型方便验证流程;生产环境应替换模型、数据治理和评估逻辑。
准备 Linux、Python 3.10+ 和兼容 CUDA 的 GPU,然后安装依赖:
python -m venv .venv
source .venv/bin/activate
pip install torch transformers datasets peft accelerate vllm
创建 train.jsonl。生产数据进入这一步前必须完成脱敏、授权检查和去重:
{"messages":[{"role":"user","content":"订单已取消,是否还应收取配送费?"},{"role":"assistant","content":"不应收取。请撤销配送费,并在回复中说明退款到账时间。"}]}
{"messages":[{"role":"user","content":"请只返回 JSON:订单 42 的状态是已退款。"},{"role":"assistant","content":"{\"order_id\":42,\"status\":\"refunded\"}"}]}
创建 train.py:
import json
import torch
from datasets import Dataset
from peft import LoraConfig, get_peft_model
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
DataCollatorForLanguageModeling,
Trainer,
TrainingArguments,
)
BASE_MODEL = 'TinyLlama/TinyLlama-1.1B-Chat-v1.0'
with open('train.jsonl', encoding='utf-8') as f:
rows = [json.loads(line) for line in f if line.strip()]
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
texts = [
tokenizer.apply_chat_template(
row['messages'],
tokenize=False,
add_generation_prompt=False,
)
for row in rows
]
dataset = Dataset.from_dict({'text': texts})
def tokenize(batch):
return tokenizer(
batch['text'],
truncation=True,
max_length=512,
padding=False,
)
tokenized = dataset.map(tokenize, batched=True, remove_columns=['text'])
model = AutoModelForCausalLM.from_pretrained(
BASE_MODEL,
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
)
model.config.use_cache = False
model = get_peft_model(
model,
LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=['q_proj', 'k_proj', 'v_proj', 'o_proj'],
task_type='CAUSAL_LM',
),
)
args = TrainingArguments(
output_dir='artifacts/checkpoints',
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=2e-4,
logging_steps=1,
save_strategy='epoch',
report_to='none',
fp16=torch.cuda.is_available(),
)
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized,
data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False),
)
trainer.train()
model.save_pretrained('artifacts/daily-adapter')
tokenizer.save_pretrained('artifacts/daily-adapter')
运行训练:
python train.py
这个最小示例会对整段对话计算损失。生产版本通常会屏蔽用户提示部分,只在助理答案上计算损失,并混入历史高质量样本,以降低灾难性遗忘风险。
通过离线评估后,可以用 vLLM 挂载 LoRA:
vllm serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --enable-lora --lora-modules daily=./artifacts/daily-adapter --host 0.0.0.0 --port 8000
另开终端发送兼容 OpenAI Chat API 的请求:
curl http://localhost:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"daily","messages":[{"role":"user","content":"请只返回 JSON:订单 42 的状态是已退款。"}],"temperature":0}'
生产部署时不要让训练任务直接覆盖线上适配器。每个版本都应使用不可变标识,例如 support-2025-03-08,完成评估后再调整流量路由。这样才能在异常出现时迅速退回上一版本。
每日更新之前必须设置门禁
持续学习的难点并非启动训练,而是判断新权重是否值得上线。建议至少维护四类评估集:
- 新失败集:验证昨天的问题是否真的得到修复。
- 稳定回归集:确保常见任务没有退化。
- 安全与合规集:检查隐私泄露、越权操作和危险内容。
- 成本与性能集:测量吞吐、首 Token 延迟、整体延迟和 GPU 显存。
上线条件可以写成明确的机器规则,例如:
release_gate:
new_failure_fix_rate: ">= 0.90"
regression_score_drop: "<= 0.01"
safety_violations: 0
p95_latency_ms: "<= 800"
cost_per_successful_task_usd: "< current_production"
canary_traffic_percent: 5
automatic_rollback_on_error_rate_increase: true
这里的阈值只是示例,必须根据业务风险调整。客服建议和资金操作不能使用同一套发布标准。
还要特别防范三种反馈回路:模型输出被误当作正确答案再次训练;攻击者批量构造反馈实施数据投毒;只优化容易自动评分的指标,牺牲无法量化的用户体验。高风险样本应保留人工审核,训练数据也要能追溯到来源、修正者和授权记录。
采用这套方法时,先缩小闭环
不要一开始就让所有生产流量驱动每日训练。更稳妥的路径是选择一个答案可验证、失败成本可控的任务,例如结构化字段提取、固定策略问答或工具参数生成。
上线前可使用这份检查清单:
- 失败是否有可靠的判定标准,而不只是用户点踩;
- 修正答案是否经过验证、脱敏并获得训练授权;
- 新样本是否与历史回放数据混合;
- 质量结论是否来自固定、隔离且未泄漏的评估集;
- 模型、数据、提示词和适配器是否都有版本记录;
- vLLM 服务是否支持灰度、监控和一键回滚;
- 成本是否按成功任务衡量,并包含人工接管和重试;
- 是否为数据投毒、隐私泄露和灾难性遗忘设置告警。
持续学习的真正收益,是让每次线上失败都能成为一次有审计记录的系统改进,而不是让模型不受控制地自我更新。PyTorch 提供灵活的学习机制,vLLM 提供高效的服务层;决定闭环能否长期运行的,则是中间那套数据治理、评估门禁和发布纪律。