ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

当万级标注流水线撞上 Pydantic:一次把 LLM 数据工程拉到生产级

当万级标注流水线撞上 Pydantic:一次把 LLM 数据工程拉到生产级 当万级标注流水线撞上 Pydantic:一次把 LLM 数据工程拉到生产级本文的公司名、工单和指标是脱敏合成案例,但状态机、失败模式和实现约束来自常见的生产数据工程实践。文中的阈值用于说明决策方法,不能不经校准直接复制到业务中。一家订阅制 SaaS 的售后团队每天收到约 12,000 条工单。团队希望用 LLM 将工单预标为billing、technical、other:一部分用于路由,一部分在人工审核后进入训练集。最初的实现只有一段“调用模型、从文本中提取 JSON、写库”的脚本。它能跑,也能出报表,却经不起模型切换、Kafka 重放和人工审核的共同冲击。本文记录这条流水线如何从“能跑”变为“可运营”:先通过一次事故说明隐患,再给出契约、PostgreSQL 状态机、Kafka/outbox、测试、质量度量和发布门禁。核心结论很简单:Pydantic 能挡住结构漂移,但不能替代幂等性、人工真值和发布治理。事故复盘:30 分钟内,静默错误如何进入训练候选集背景和旧实现在模型供应商切换前,系统的首轮“可解析率”约为 99.6%。旧代码为追求吞吐做了两件看似友好的事:# 旧实现:示意代码,不应在线上使用payload=re.search(r"\{.*\}",raw_response,re.S).group()label=json.loads(payload)confidence=float(label.get("confidence",0))category=label.get("category","other")它会忽略 JSON 前后的文字,将"0.92"静默转换为0.92,也会把缺失类别变成other。这意味着“解析成功”不代表模型遵守了契约,更不代表标签正确。时间线下列指标来自本案例的脱敏合成观测,用于展示处置过程:时间现象旧实现的结果新流程采取的动作09:00灰度切换 10% 流量到新模型无异常告警记录模型与提示词版本09:12新模型开始附加“以下是分类结果”正则仍提取 JSON,监控看不见—09:18confidence字段出现字符串float()静默转换—09:30原始 JSON/Schema 首轮失败率从 0.4% 升至 6.8%旧报表仍显示“解析成功”结构门禁告警,冻结自动候选发布09:36两个 worker 重启,部分 Kafka 消息重放同一工单重复调用、重复计费唯一键与租约吸收重放,异常任务隔离10:05回放固定金标集无法区分旧/新提示词结果按pipeline_version对比,决定回退事故暴露的不是一个解析函数,而是四个缺口:没有严格输出契约;没有可区分的错误码;没有外部调用的幂等状态机;没有“质量门禁失败即停止自动发布”的控制面。先定义身份、状态和不变量数据身份同一record_id的正文可能在 CRM 里被补充,因此它不是完整输入身份。本实现使用:名称定义解决的问题输入身份(record_id, input_version)同一工单正文更新后可重新标注内容指纹原始 UTF-8 文本 SHA-256上游错误复用版本号时拒绝混淆标注身份(record_id, input_version, pipeline_version)重放时只保留一个业务结果流水线版本model + prompt + schema + route的不可变组合新旧配置可以并存、对比和回退快照身份snapshot_id+ 成员清单哈希训练集可复现、不可被后续审核改变状态机review_pending对模型调用来说是终态,但对人工审核来说不是终态。rejected永远不能加入训练快照。
返回列表