
LLMs Dont Replace Classical ML – They Feed It这个观点我越用越认同。它不是在比较 LLM 和传统机器学习谁更强而是在说明一条真实业务流水线里两类工具的分工LLM 负责把非结构化文本变成结构化字段、向量和标签经典机器学习模型再在这些结构化信息上做稳定、可解释、可批量复用的预测。如果你正在犹豫要不要用 LLM 替换原来的机器学习方案这篇文章值得先看完。我会说清楚哪些问题应该继续用经典模型哪些环节适合交给 LLM并给出一条可以照着复现的最小流水线和排查链路。1. 先搞清 LLM 和经典模型各自的主场1.1 LLM 真正擅长的是“把文本变成信息”LLM 的核心能力不是预测而是理解和生成自然语言。在处理业务数据时它的价值更多体现在把一段杂乱文本转成有结构的要素从工单正文里提取问题类型、紧急程度、涉及的设备型号。从合同或公告中抽取日期、金额、责任主体。把不同写法的地址、单位名、产品名归一化成统一表达。判断一段评论里到底在说质量问题还是物流问题。这些任务的共同特点是规则多、写法灵活、上下文敏感。用正则和词典能覆盖一批但覆盖率和维护成本很快会成为瓶颈。LLM 在这里的优势是能根据语义做判断不需要把所有分支写死这是它的主战场。1.2 经典模型真正擅长的是“在表格上做预测”逻辑回归、随机森林、梯度提升树这类经典模型擅长处理固定维度的结构化特征。它们的特点是训练快推理更快单条样本的开销几乎可以忽略。对数值型、类别型特征都有成熟处理方法。训练和推理行为相对稳定相同输入基本得到相同输出。有特征重要性、SHAP 等成熟的解释工具。这在很多业务环节里很重要。风控、客服分流、工单优先级、库存预测、设备故障预警这些场景的决策链路往往需要稳定、可解释、可审计。经典模型在这方面仍然比端到端 LLM 分类更省心。1.3 大多数业务问题的真实形态是“先非结构化再结构化”一个典型的工单分类任务原始输入是“用户说了一大段话”但业务真正需要的是“风险等级问题类别处理部门”。前者是非结构化文本后者是结构化标签。最直接的做法是拿 LLM 对着原始文本直接输出最终标签这也是很多人第一时间想到的方案。但真落到生产环境时问题会一个个冒出来响应时间不稳定、输出偶尔不按格式、同一句话换个说法结果可能变、成本随调用量线性上涨、不好做灰度回滚。更稳的做法是分层LLM 只负责把文本抽成结构化要素和中间特征最终的业务判断交给经典模型。这样既利用了 LLM 的语义理解又保留了经典模型的稳定性和可解释性。这也正是标题里 Feed It 的意思——LLM 喂给经典模型的是更高质量的特征而不是一个包办所有事情的最终答案。2. 最小可复现流水线LLM 抽特征经典模型做预测下面用一个很常见的场景来演示客服工单预测优先级。目标是根据工单正文预测这条工单是“高、中、低”哪个优先级。这个任务很适合演示因为它既有文本理解也有结构化特征最后还要稳定分类。2.1 先定义任务和数据格式输入是一段工单文本例如“用户反馈连续三天无法登录尝试重启多次仍报错客户要求今天给出处理方案。”“用户询问如何修改发票抬头希望告知操作步骤。”输出是三级标签high / medium / low。在这个流水线里LLM 不直接输出最终优先级而是输出几个中间字段problem_type问题类别例如登录、发票、支付、账号。urgency_score0 到 1 的紧急程度。is_complaint是否是投诉或升级诉求。sentiment用户情绪negative / neutral / positive。这些字段加上原本就有的数值特征用户历史工单数、客户等级、渠道来源等一起进入经典分类模型。2.2 环境准备我一般建议先在一台普通的开发机上跑通不需要一开始就部署完整服务。只要满足以下几点Python 3.9 以上能装依赖。有一个可以调用的 LLM 接口或本地模型支持文本补全或对话格式。经典模型库用 scikit-learn、LightGBM、XGBoost 都行看你自己熟哪个。训练数据至少准备几百条带标签样本用来做经典模型的训练和验证。原始数据里如果有字段缺失先不急着补先把整条流水线跑通再做缺失值处理。2.3 第一步用 LLM 抽结构化字段这一步的提示词我建议写清楚三件事输入字段是什么输出格式是什么示例输出长什么样。不要只写一句“请抽取字段”。# 伪代码具体客户端方法以你接入的模型为准 def extract_fields(text: str): prompt f 从给定的工单文本中抽取以下字段输出 JSON problem_type: 问题类别取值只能从[登录,发票,支付,账号,其他]中选择 urgency_score: 0到1的数字表示紧急程度 is_complaint: true/false表示是否存在投诉或升级诉求 sentiment: negative/neutral/positive 工单文本 {text} 只输出 JSON不要输出其他说明。 raw llm_client.complete(prompt, temperature0.1) return parse_json(raw)几个关键点temperature 要调低一般 0 到 0.2。这个环节要的是稳定性不是创造性。必须要求 JSON 输出并且先做一次解析校验。解析失败时不要直接跳过要记录下原始输出后续分析格式问题。输出字段要固定。新增字段会影响下游特征维度最好不要频繁改。我这里用的是伪代码实际接入不同模型时客户端名称、超时参数、返回结构都可能不一样以你手上的模型文档为准。注意LLM 输出解析失败时不要直接重试同一个提示词先记录原始输出。很多时候是格式问题不是模型能力问题。2.4 第二步合并特征训练经典模型抽取完成之后把每个样本组成一张表格。我一般会把特征分成三类特征类型示例处理方式文本侧 LLM 特征problem_type、is_complaint、sentiment、urgency_score类别编码或直接作为数值/布尔特征原始结构化特征user_tier、channel、history_ticket_count数值归一化或类别编码文本向量特征LLM embedding降维后加入或单独模型对比然后正常划分训练集和验证集训练 LightGBM 或逻辑回归。这里有一个建议先用逻辑回归当基线再用梯度提升树。逻辑回归能告诉你特征是否真的和标签线性相关梯度提升树则更容易吃进复杂交互。如果逻辑回归的提升已经很明显说明特征抽取是有效的。from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler X_train, X_val, y_train, y_val train_test_split( feature_df, labels, test_size0.2, random_state42 ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_val_scaled scaler.transform(X_val) model LogisticRegression(max_iter1000) model.fit(X_train_scaled, y_train) print(model.score(X_val_scaled, y_val))注意这里不要求一次就把准确率拉得非常高关键是看特征方向是否有效。2.5 第三步结果怎么判断只盯着准确率不够。分类任务至少要看三个东西混淆矩阵高优先级样本被错分成中优先级和低优先级错分成高优先级代价完全不同。类别召回率如果高优先级只占 5%模型很容易靠“全预测成中或低”拿高准确率但没有意义。特征重要性确认 urgency_score、is_complaint 真的进入了模型并且重要性排在前列说明 LLM 抽取的特征不是噪音。我一般会先跑一个小样本集比如 100 到 200 条把流水线跑通再扩大到全部数据。这样能避免一开始就在全量数据上等上几小时结果发现是提示词解析出错。3. 实际落地时最容易踩的坑3.1 文本侧的参数temperature、max_tokens、输出格式temperature 是最容易被忽略的。在分类和抽取任务里temperature 超过 0.5 后同一个文本多次调用可能给出不同结果下游模型的预测自然不稳定。生产环境建议固定为 0 到 0.2。max_tokens 要设置得比预期输出长度大一点防止长文本被截断后 JSON 不完整。如果输出被截断解析必然失败。另外如果 LLM 返回的 JSON 里带了多余文字宁可让解析函数做一次容错也不要直接失败。抽取结果最好缓存下来。同一文本不要重复调用模型既省成本也避免结果漂移。缓存键就用文本的哈希值。3.2 表格侧的参数样本量、类别不平衡、特征稳定性经典模型再强也依赖足够多的有效样本。几百条数据能跑通但要做生产级别的优先级预测往往需要几千条甚至更多。数据不够时先不要上复杂模型先看特征本身是否稳定。类别不平衡是常态。高优先级的比例经常只有 5% 左右。这时候不要只看准确率建议用加权损失、过采样或者对少数类单独评估召回率。特征稳定性也要盯住。LLM 抽取字段的口径如果变了比如 problem_type 的枚举值从“支付”改成“付款”下游模型要重新编码线上效果可能立刻波动。所以字段枚举值尽量写成配置文件改的时候要通知整个链路。3.3 精度问题fp16、fp32、bf16 什么时候影响下游关于 LLM 的精度问题最近讨论比较多。简单说fp32精度最高显存和内存开销最大。fp16显存占用低推理快但表示范围小训练时容易出现溢出。bf16显存占用低指数范围接近 fp32训练更稳定但精度位少一些。对纯文本生成任务推理时精度差异对结果的影响通常不大。但如果 LLM 的输出是 embedding然后直接把 embedding 喂给下游模型就要小心不同精度下算出的 embedding 会有微小差异可能反映在余弦相似度的第三、四位小数上。这个差异有时候不会改变排序但在一些边界样本上可能改变最近邻结果或下游分类结果。我的建议是开发、测试、生产保持同一套精度设置不要一个环节用 fp16另一个环节用 bf16。否则特征分布变了你很难判断是模型变了还是精度变了。3.4 批量任务的并发、超时、重试和输出命名单条跑通之后批量处理是另一个世界。很多人一上来就开大并发结果就是服务端限流、超时、部分任务失败、没有日志可查。批量任务至少要处理好四件事并发数从小开始先 2 到 4 并发观察延迟和错误率再逐步调大。超时时间设一个合理上限。LLM 请求超时不一定是模型问题可能是输入太长、服务负载高、网络波动。重试策略对超时和限流做指数退避重试但不要无限重试。超过 3 次就落日志人工检查。输出命名每条样本要有唯一 ID输出文件和输入 ID 一一对应。不要只写“结果.csv”要写明批次时间方便回溯。前一段时间我处理一批文档抽取任务就是吃了输出命名的亏一批文件跑完发现部分结果对不上因为并发线程写文件时没有按输入 ID 隔离后面只能重跑。这种事早点遇到其实更好下次批量任务一开始就会把输入清单和输出命名定清楚。4. 三种更高级的协作模式4.1 用 LLM 生成标签经典模型负责学很多业务的数据不是没有文本而是没有标签。人工标注又贵又慢。一种常用做法是先用 LLM 做弱标注让 LLM 对一批未标注文本输出分类结果筛选置信度高的样本作为训练标签再训练经典模型。这里必须做质量校验。我一般会抽 10% 到 20% 的 LLM 标注结果做人工复核计算一个标注一致率。如果一致率低于 90%说明提示词或任务定义有问题不要急着拿这些标签训练。弱标签训练出的模型效果上限受制于标注质量但它有一个好处推理阶段完全不依赖 LLM成本和延迟都大幅下降。这正是“LLM 喂经典模型”的典型场景。4.2 用 LLM 做文本嵌入经典模型直接吃向量除了离散字段LLM 还可以把整段文本编码成向量。这个向量理论上携带语义信息可以直接作为特征喂给经典模型。但向量维度通常很高例如 768 到 1536 维。直接拼进表格会让经典模型训练变慢也容易过拟合。我一般会先用 PCA 或 UMAP 降到 32 到 128 维再和原始特征合并。降维后泛化能力往往更好。判断嵌入是否有效可以做一个快速实验只用原始结构化特征训练一个基线模型再用“原始特征降维向量”训练一个模型看验证集指标是否有明显提升。如果提升微弱说明文本语义信息对当前标签帮助有限就不需要为了嵌入增加额外计算成本。4.3 用 LLM 做数据增强但要注意分布偏移如果某类样本太少也可以用 LLM 生成同类文本做数据增强。比如用改写或扩写的方式生成更多“支付失败”的工单描述。但这里有个风险LLM 生成的文本可能和真实分布不一致特别是生成结果往往比真实用户描述更完整、更规范、更少错别字。拿这些数据训练出来的模型可能在真实场景里反而预测变差。我建议做数据增强时加一个约束生成时尽量模仿真实数据的风格包括用户的语病和口语化表达。生成后一定要做人工抽检或者做一次分布对比确认生成样本和真实样本在长度、关键词、标签分布上没有明显差异。4.4 和 LLM Agent / LLM wiki 式文档化流程的关系最近有一种叫 LLM wiki 的做法在社区里传播比较广核心思路是把提示词模板、输入输出规范、校验规则这些重复环节沉淀成文档再由 agent 按照文档来执行。它解决的是“LLM 使用过程怎么标准化”的问题比如 agent 要做哪些步骤、每步输入输出是什么、失败时怎么处理。这套思路和这条流水线并不冲突。在“LLM 抽特征经典模型做预测”的架构里LLM 侧的提示词、字段定义、解析规则同样适合写成文档或配置化文件而不是散落在代码里。这样每次调整字段枚举值、改输出格式都只需要改一处并且可以保留版本记录。个人知识库场景里经常用 Obsidian 结合 LLM wiki 来整理笔记和检索这种目标更偏信息组织和写作辅助和业务预测流水线不是一回事。但它提示了一个通用原则LLM 任务越复杂越需要把提示词、输入输出、校验、异常处理沉淀成可复用资产。否则每次换模型、换场景、换人维护都会重新踩一遍坑。5. 结果不对时按这个顺序排查LLM 加经典模型的流水线问题出现时最容易互相甩锅有人说文本没抽对有人说特征没建好有人说模型参数没调。我建议固定一套排查顺序先定位问题在哪一层。5.1 先判断现象属于哪一类完全没有输出通常是调用失败、超时、解析失败。输出是乱码或格式不对通常是解码、编码、提示词格式问题。LLM 字段抽出来了但模型预测不准通常是特征质量问题或模型训练问题。任务中途卡住先看资源占用、服务端状态、日志而不是先改参数。5.2 输入侧排查第一个要看的是原始文本本身。编码、换行、特殊符号、长度截断都会影响 LLM 抽取结果。比如超长文本被截断合同里的关键金额字段被砍掉抽出来自然不对。编码问题在 Windows 环境下特别常见建议统一用 UTF-8并且每次读取文件后做一次解码校验。然后在 LLM 层做一个最小验证直接拿 3 到 5 条文本调用一次打印原始返回结果。这一步能快速区分是提示词问题、模型问题还是解析问题。解析失败时把原始返回内容完整记录下来看看模型是否多输出了“好的我来帮你”这类废话或 JSON 里带了注释。这类问题可以通过更严格的提示词和更宽容的解析函数来缓解。5.3 环境与资源侧排查经典模型训练端出问题时先看样本量和特征列数。特征列太多而样本太少模型很容易过拟合。特征里有 NaN、无穷值也会让部分模型训练崩溃或异常。LLM 调用端出问题时先看服务端负载、超时时间和重试次数。request timed out 这类报错经常不是“模型能力不够”而是输入太长、并发太高或者服务没有在限定时间内返回。先降并发再看日志再看是否需要切分输入。5.4 判断到底是谁的问题一个比较简单的方法是做隔离实验把 LLM 抽取的字段固定住只改经典模型的参数和训练数据。如果预测效果大幅波动问题在表格侧。把 LLM 的提示词或模型换成另一个版本保持下游不变。如果预测效果明显变化问题在文本抽取侧。隔离实验不一定能一次定位但它能帮你把排查范围缩小。我在实际项目里发现至少一半的“模型效果不好”问题最终都定位在输入数据不一致、标签噪声大、特征拼接有 bug 这三类原因上而不是模型本身选错了。注意只要判断结果变了就要先固定输入和中间特征再动模型参数。这样定位问题时才不会把 LLM 波动和经典模型波动混在一起。6. 落地建议先跑小再跑大6.1 单条样本先验证不管目标是做个人实验还是生产系统都建议从一个最小样例开始。拿一条真实文本走完“LLM 抽取字段、拼接特征、经典模型预测”的完整链路确认每一步的输出都是预期格式。这一步不要用完整流程框架不要引入消息队列、任务调度、日志平台。就在一个脚本里写清楚能跑通就行。跑通了你对这个方案的技术可行性就有了基本判断。6.2 小批量验证稳定性单条跑通之后再扩展到 50 到 100 条样本。这一阶段主要看三件事并发调用下成功率和延迟是否可接受。LLM 输出格式的失败率有多高。经典模型在验证集上的指标是否稳定。如果小批量阶段失败率很高不要硬调经典模型先回头改 LLM 的提示词和输出校验逻辑。这里最容易踩的坑是连续跑几十条之后某种罕见的输入格式触发了解析崩溃但单条测试时没暴露。6.3 评估收益后再决定要不要产品化技术能跑通不等于值得产品化。需要算一笔账LLM 调用成本、处理延迟、维护成本对比原来的正则或纯规则方案收益是否明显。如果业务标签本身就是高频变动或者对解释性要求很高那经典模型加 LLM 特征的组合确实很合适。如果标签任务本身很简单规则已经覆盖 90% 的样本额外引入 LLM 可能只是增加成本不一定值得。6.4 哪些情况不建议走这条流水线最后说几个反例。如果原始文本很短、格式很固定例如设备状态码用正则或词典反而更简单。如果预测目标要求高吞吐、低延迟、毫秒级响应且对文本理解要求极低经典模型直接吃规则特征就够了不需要引入 LLM。如果完全没有标签数据而且连人工抽验条件都没有那“LLM 生成标签、经典模型学习”的方案也不适合因为无法评估标签噪声。如果 LLM 输出字段经常变化下游业务又要求高度稳定那反而应该先固化字段定义再考虑接入。我自己现在做这类需求时基本固定一个判断顺序先看输入是不是非结构化文本再看目标是不是稳定可解释的分类或回归最后决定 LLM 参与的程度。大多数情况下“LLM 抽特征、经典模型决策”的组合比任何单一模型都更适合落地。