news 2026/9/1 2:53:02

LLM与经典机器学习协同实战:从特征工程到文本分类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LLM与经典机器学习协同实战:从特征工程到文本分类

最近在做一个文本风控项目时,团队里争论了一个很有意思的问题:既然大语言模型(LLM)已经能读懂长文本、能写摘要、能做情感分析,那我们为什么还要保留 XGBoost、逻辑回归这些经典机器学习模型?干脆全换成 LLM 不就行了?

实际做下来,结论恰恰相反。LLM 并没有“取代”经典机器学习,反而在很多场景里是 LLM 在给经典模型“喂数据”“喂特征”。本文会围绕这个主题展开,先讲清楚 LLM 与 Classical ML 的定位差异,再通过两个完整实战案例,演示如何用 LLM 做特征生成、Embedding 提取,然后把结果输入 XGBoost、逻辑回归等经典模型完成分类任务。

本文适合三类读者:

  • 已经在用 LLM 做业务,但觉得 API 成本高、效果不稳定的人;
  • 熟悉经典机器学习,想了解怎么把 LLM 融入现有特征工程的人;
  • 正在做技术选型,纠结“全上 LLM”还是“LLM + 经典模型”的人。

读完你会掌握:LLM 与经典模型的边界划分、四种常见的 LLM 辅助经典模型的方式、可直接运行的 Python 代码,以及一套混合架构的工程落地建议。

1. 背景:LLM 与 Classical ML 不是“替代关系”

1.1 什么是 Classical ML

经典机器学习通常指依赖人工特征工程和统计学习算法的模型,比如线性回归、逻辑回归、决策树、随机森林、XGBoost、LightGBM、SVM、KNN 等。

这类模型有几个共同特点:

  • 输入是结构化特征:数值、类别、稀疏向量,而不是原始的整段自然语言;
  • 训练依赖高质量标签:需要人工标注或者规则抽取得到标签;
  • 推理速度快、资源占用低:单条样本预测通常在毫秒级别,甚至可以部署在低配 CPU 上;
  • 可解释性相对好:树模型可以输出特征重要性,线性模型可以直接看系数。

经典模型最大的短板是“吃不到非结构化信息”。比如一段售后工单,里面有大量自由文本,如果只靠人工抽几个关键词当特征,信息损失很大。过去解决这个问题的办法是 TF-IDF、Word2Vec、主题模型,但这些方法对语义的理解都比较浅。

1.2 什么是 LLM

大语言模型(Large Language Model,LLM)是基于 Transformer 架构、在海量文本上预训练的深度神经网络模型,比如 ChatGPT、ChatGLM、Qwen、LLaMA 等。

LLM 的能力特点是:

  • 理解自然语言:能做摘要、翻译、情感分析、实体抽取、意图识别;
  • 零样本 / 少样本学习:给几条示例就能完成新任务,不需要专门训练;
  • 生成能力:可以写文案、生成 SQL、生成合成样本;
  • 复杂推理:能够根据上下文进行多步推理。

但 LLM 也有明显问题:

  • 推理成本高:单次调用消耗大量算力,尤其是长文本;
  • 响应不稳定:同一个问题,温度参数调高后每次输出可能不一样;
  • 延迟高:单次推理可能几百毫秒到几秒,不适合高并发低延迟场景;
  • 幻觉风险:模型会生成看起来合理但事实错误的内容;
  • 依赖外部 API 或 GPU 资源:部署和运维成本比经典模型高一个量级。

1.3 为什么说 LLM 在“喂养”经典机器学习

回到我开头的项目。我们的目标是判断一段客服工单是否属于“高危投诉”。一开始尝试直接用 LLM 做分类,Prompt 写得再详细,效果在测试集上也只有 92% 左右,而且每次调参、换版本结果都有波动。更麻烦的是,我们每秒要处理几十条工单,如果全部走 LLM,成本完全扛不住。

后来我们换了一个思路:用 LLM 把非结构化文本转成结构化特征,再用 XGBoost 做最终分类。结果准确率提升到 96%,推理延迟从几百毫秒降到十几毫秒。

这就是“LLM 喂养经典模型”的核心含义:LLM 不直接承担最终预测任务,而是充当一个“特征引擎”或“数据加工厂”,把原始文本变成经典模型能理解的特征、标签、样本或者向量。经典模型负责最终的高频、低成本、可解释预测。

可以这样理解两者的关系:

  • LLM 负责“理解”:消化非结构化信息,输出结构化结果;
  • Classical ML 负责“决策”:基于结构化特征做稳定、快速、可解释的预测。

在后面的章节里,我会把这套思想拆解成具体方案和代码。

2. 环境准备与版本说明

2.1 运行环境

本文的示例代码使用 Python 编写,推荐环境如下:

  • 操作系统:Windows 10/11、macOS 或 Linux 均可;
  • Python 版本:3.9 或以上;
  • 内存:至少 8GB,推荐 16GB;
  • 网络:需要能访问 LLM API 或本地推理服务。

如果你本地没有可用的 LLM API,也可以使用 OpenAI 兼容接口的本地框架(如 vLLM、Ollama)启动本地模型。本文代码里所有调用 LLM 的地方都会封装成一个函数,方便你替换成自己的服务地址和模型名称。

2.2 安装依赖

需要安装以下 Python 库:

库名用途安装命令
pandas数据处理pip install pandas
scikit-learn经典模型与评估pip install scikit-learn
xgboostXGBoost 分类器pip install xgboost
requests调用 LLM HTTP 接口pip install requests
openai调用 OpenAI 兼容接口pip install openai

建议先创建一个独立的虚拟环境:

python -m venv llm_classical_env source llm_classical_env/bin/activate # Windows 下使用 llm_classical_env\Scripts\activate

然后批量安装:

pip install pandas scikit-learn xgboost requests openai

2.3 项目结构

实战部分会用到以下文件结构:

llm_feed_classical/ ├── config.py # 全局配置,包含 API 地址、模型名、参数 ├── llm_client.py # LLM 调用封装 ├── feature_extractor.py # 用 LLM 提取结构化特征 ├── embedding_utils.py # 用 LLM 生成文本 Embedding ├── train_xgb.py # 训练 XGBoost 模型 ├── train_embedding_clf.py # 训练 Embedding + 逻辑回归模型 └── data/ ├── samples.csv # 原始文本样本 └── features.csv # 生成的中间数据

3. LLM 为 Classical ML 提供能力的四种方式

在动手写代码之前,先梳理清楚 LLM 到底能为经典模型提供哪些能力。根据我实践中的经验,最常见的有四种模式。

3.1 特征工程:把非结构化文本变成结构化特征

这是最直接、也最常用的一种方式。

经典模型无法直接读取“用户投诉说订单一直不到货,客服也不理人”这样的文本。传统做法是 TF-IDF 或关键词匹配,但语义理解非常有限。

LLM 可以承担这个转换过程。比如让 LLM 输出:

{ "是否涉及物流": 1, "是否涉及客服态度": 1, "是否提及退款": 0, "情绪强度": 0.8, "紧急程度": 0.7 }

这段 JSON 就是经典模型的标准输入特征。LLM 在这里扮演的是一个“语义特征抽取器”。

这种方式的优点是特征含义明确、可解释性强;缺点是调用成本与文本长度成正比,所以建议只对原始文本做一次离线或准实时的特征生成,然后缓存结果。

3.2 标签生成与数据标注

经典机器学习非常依赖高质量标签,但人工标注成本高、速度慢。

LLM 可以辅助生成标签候选。比如先让 LLM 给一批无标签文本打标,再用人工抽检的方式修正错误样本。这样做的本质是“LLM 先标注,人来复核,经典模型再训练”。

其中有一个关键点需要特别注意:LLM 生成的标签不能直接当 gold label 用,必须经过抽样评估。因为 LLM 存在系统性偏差,比如对不同类别可能有偏好,直接采用会把偏差带入训练集。

3.3 数据增强与合成数据

当某一类别的样本太少时,经典模型很容易过拟合。传统办法是 SMOTE 之类的采样方法,但作用有限。

LLM 可以用来生成同分布的合成样本。例如,现有 100 条“物流投诉”样本,可以让 LLM 基于这些样本改写生成 500 条新的、语义相似但不重复的样本,然后合并进训练集。

这种方式适合文本分类任务,但生成的数据需要做质量过滤,建议用相似度计算或人工抽检来控制生成质量。

3.4 嵌入向量(Embedding)作为特征输入

LLM 的倒数第二层输出可以看作一段文本的向量表示,也就是 Embedding。这个向量保留了文本的语义信息,通常有几百到几千维。

经典模型可以直接把 Embedding 当作特征向量输入。例如:

  • 把用户问题转成 1536 维向量;
  • 输入逻辑回归或 XGBoost 进行分类。

这种方式不需要 LLM 输出结构化 JSON,只需要调用 API 的 embeddings 接口,速度比完整生成式调用快,成本也更低。

它的缺点是特征维度较高,需要配合降维或正则化处理;同时 Embedding 本身的可解释性不如“是否涉及物流”这种离散特征。

3.5 选型建议

业务需求推荐方案原因
需要明确解释为什么不通过LLM 特征 + XGBoost特征含义清晰,树模型可输出重要性
高并发、低延迟、文本语义强Embedding + 逻辑回归Embedding 接口快,逻辑回归稳定
正样本太少,无法训练LLM 生成合成样本扩充少数类,缓解类别不平衡
完全没有标注数据LLM 打标 + 人工复核降低标注成本,快速启动

4. 完整实战:LLM 特征生成 + XGBoost 二分类

下面进入完整实战。我们的任务是:判断一段客服工单是否属于“高危投诉”。

“高危投诉”定义为:用户表达了强烈不满,并且可能升级到媒体曝光、监管投诉或法律途径。

4.1 场景说明

原始数据是客服工单的文本记录,例如:

"你们的快递放驿站也不通知,我找了两天才找到,气死我了,再这样我就去12315投诉了!"

我们希望输出一个二分类标签:1 表示高危投诉,0 表示普通投诉。

整体流程分三步:

  1. 调用 LLM,从工单文本中抽取结构化特征;
  2. 用特征训练 XGBoost 分类器;
  3. 在测试集上评估效果。

4.2 全局配置

先写配置文件config.py

# 文件路径:llm_feed_classical/config.py LLM_API_BASE = "http://localhost:8000/v1" LLM_API_KEY = "EMPTY" LLM_MODEL_NAME = "Qwen2.5-7B-Instruct" # 特征抽取时使用的温度参数,越低越稳定 FEATURE_TEMPERATURE = 0.1 # 分类模型超参数 XGB_PARAMS = { "n_estimators": 300, "max_depth": 4, "learning_rate": 0.05, "subsample": 0.8, "colsample_bytree": 0.8, "eval_metric": "logloss", "use_label_encoder": False, "random_state": 42, }

这里说明两点:

  • LLM_API_BASE使用 OpenAI 兼容地址,可以替换为任意兼容服务,也可以换成https://api.openai.com/v1之类的线上接口;
  • XGB_PARAMS中的use_label_encoder在新版本 XGBoost 中可能不需要,如果报错可以去掉。

4.3 封装 LLM 客户端

新建llm_client.py,统一封装 LLM 调用:

# 文件路径:llm_feed_classical/llm_client.py import json from openai import OpenAI from config import LLM_API_BASE, LLM_API_KEY, LLM_MODEL_NAME, FEATURE_TEMPERATURE class LLMClient: def __init__(self): self.client = OpenAI(base_url=LLM_API_BASE, api_key=LLM_API_KEY) self.model = LLM_MODEL_NAME def extract_features(self, text: str) -> dict: """从一段文本中抽取结构化特征,返回 JSON 字典。""" prompt = f""" 你是一个文本特征抽取器。请阅读下面的客服工单文本,并输出一个 JSON 对象。 JSON 字段说明: - is_logistics_issue: 是否涉及物流问题,0 或 1 - is_service_attitude: 是否涉及客服态度问题,0 或 1 - is_refund_issue: 是否涉及退款问题,0 或 1 - emotion_intensity: 情绪强度,0 到 1 之间的小数 - urgency: 紧急程度,0 到 1 之间的小数 - contains_threat: 是否包含投诉威胁(如投诉、曝光、法律等),0 或 1 只输出 JSON,不要输出其他内容。 工单文本: {text} """ resp = self.client.chat.completions.create( model=self.model, messages=[{"role": "user", "content": prompt}], temperature=FEATURE_TEMPERATURE, ) content = resp.choices[0].message.content.strip() # 兼容模型输出可能包含 ```json 包裹的情况 if content.startswith("```"): content = content.strip("`") if content.startswith("json"): content = content[4:] try: result = json.loads(content) except json.JSONDecodeError: # 解析失败时返回空特征,后续可以用默认值兜底 return {} return result

这里需要注意几点:

  • 温度参数设成 0.1,是为了让输出尽量稳定。
  • 我在 Prompt 里明确要求“只输出 JSON”,但不同模型可能仍然会多输出一些解释文字,所以代码里做了兼容处理。
  • 解析失败时返回空字典,后续代码会用默认值兜底,避免单条数据异常导致整个流程中断。

4.4 批量生成特征

新建feature_extractor.py,读取原始文本,批量调用 LLM 生成特征并保存:

# 文件路径:llm_feed_classical/feature_extractor.py import time import pandas as pd from llm_client import LLMClient def build_feature_dataset(input_path: str, output_path: str, max_samples: int = None, batch_sleep: float = 0.2): df = pd.read_csv(input_path) if max_samples: df = df.head(max_samples) client = LLMClient() records = [] for idx, row in df.iterrows(): text = row["text"] features = client.extract_features(text) record = { "id": row.get("id", idx), "text": text, "label": row.get("label", None), "is_logistics_issue": features.get("is_logistics_issue", 0), "is_service_attitude": features.get("is_service_attitude", 0), "is_refund_issue": features.get("is_refund_issue", 0), "emotion_intensity": features.get("emotion_intensity", 0.0), "urgency": features.get("urgency", 0.0), "contains_threat": features.get("contains_threat", 0), } records.append(record) # 避免请求太快触发限流 time.sleep(batch_sleep) result_df = pd.DataFrame(records) result_df.to_csv(output_path, index=False) print(f"生成完成,共 {len(result_df)} 条,保存至 {output_path}") return result_df if __name__ == "__main__": # 示例:先对训练集前 100 条生成特征 build_feature_dataset( input_path="data/samples.csv", output_path="data/features.csv", max_samples=100, )

这里建议对 LLM 调用做缓存。如果任务失败重跑,可以先把已生成的特征保存好,下次跳过已处理的数据,避免重复花钱。

4.5 训练 XGBoost 模型

新建train_xgb.py

# 文件路径:llm_feed_classical/train_xgb.py import pandas as pd from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report, roc_auc_score import xgboost as xgb from config import XGB_PARAMS FEATURE_COLUMNS = [ "is_logistics_issue", "is_service_attitude", "is_refund_issue", "emotion_intensity", "urgency", "contains_threat", ] def main(): df = pd.read_csv("data/features.csv") # 丢弃没有标签的样本 df = df.dropna(subset=["label"]) X = df[FEATURE_COLUMNS].fillna(0.0) y = df["label"].astype(int) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) model = xgb.XGBClassifier(**XGB_PARAMS) model.fit(X_train, y_train) y_pred = model.predict(X_test) y_proba = model.predict_proba(X_test)[:, 1] print("=== 分类效果 ===") print(classification_report(y_test, y_pred)) print("AUC: {:.4f}".format(roc_auc_score(y_test, y_proba))) # 输出特征重要性 importance = pd.Series(model.feature_importances_, index=FEATURE_COLUMNS) print("\n=== 特征重要性 ===") print(importance.sort_values(ascending=False)) # 保存模型 model.save_model("xgb_hazard_model.json") print("\n模型已保存至 xgb_hazard_model.json") if __name__ == "__main__": main()

这段代码做的事情:

  1. 读取上一步生成的features.csv
  2. 剔除没有标签的行;
  3. 用 6 个 LLM 生成的特征训练 XGBoost;
  4. 在测试集上输出精确率、召回率、F1 和 AUC;
  5. 输出特征重要性,方便我们验证 LLM 抽取的特征是否真的有用。

4.6 运行与验证

执行顺序如下:

cd llm_feed_classical python feature_extractor.py python train_xgb.py

如果一切正常,你会看到类似这样的输出:

=== 分类效果 === precision recall f1-score support 0 0.95 0.96 0.95 60 1 0.90 0.88 0.89 40 accuracy 0.93 100 macro avg 0.92 0.92 0.92 100 weighted avg 0.93 0.93 0.93 100 AUC: 0.9712 === 特征重要性 === contains_threat 0.35 emotion_intensity 0.27 urgency 0.18 is_logistics_issue 0.09 is_service_attitude 0.07 is_refund_issue 0.04

注意:这里的数字只是示例,实际结果取决于你的数据集、模型版本和 Prompt 设置。

4.7 结果说明

从特征重要性可以看出,“是否包含投诉威胁”和“情绪强度”这两个由 LLM 生成的特征,对“高危投诉”的判断贡献最大。这是符合业务直觉的:用户提到“12315 投诉”“曝光”“起诉”,往往是高危信号。

这套方案的价值在于:

  • 最终模型只有 6 维特征,XGBoost 训练和推理都非常快;
  • 特征有明确业务含义,可以解释为什么某条工单被判为高危;
  • 后续如果 LLM 升级,只需要重新生成特征,不需要重新设计整个分类流程。

5. 实战进阶:Embedding + 逻辑回归分类

第二种实战方案是用 LLM 的 Embedding 接口生成文本向量,然后输入逻辑回归模型。

5.1 为什么用 Embedding

结构化特征抽取适合“特征含义明确”的场景,但有些场景里我们不知道哪些特征是关键的。比如一条工单里可能隐含了复杂的语义关系,很难用几个离散字段覆盖。

Embedding 可以保留更完整的语义信息。缺点是特征维度高,而且不好直接解释。所以这里选用逻辑回归,它训练快、对高维稀疏特征有一定鲁棒性,也方便加 L2 正则化。

5.2 生成 Embedding

新建embedding_utils.py

# 文件路径:llm_feed_classical/embedding_utils.py import time import pandas as pd from openai import OpenAI from config import LLM_API_BASE, LLM_API_KEY, LLM_MODEL_NAME class EmbeddingGenerator: def __init__(self): self.client = OpenAI(base_url=LLM_API_BASE, api_key=LLM_API_KEY) self.model = LLM_MODEL_NAME def get_embedding(self, text: str): resp = self.client.embeddings.create( model=self.model, input=text, ) return resp.data[0].embedding def generate_embeddings(input_path: str, embedding_path: str, max_samples: int = 200, batch_sleep: float = 0.1): df = pd.read_csv(input_path) if max_samples: df = df.head(max_samples) generator = EmbeddingGenerator() vectors = [] for idx, row in df.iterrows(): vec = generator.get_embedding(row["text"]) vectors.append(vec) time.sleep(batch_sleep) if (idx + 1) % 20 == 0: print(f"已处理 {idx + 1} 条") embedding_df = pd.DataFrame(vectors) embedding_df.insert(0, "label", df["label"].values) embedding_df.insert(0, "text", df["text"].values) embedding_df.to_pickle(embedding_path) print(f"Embedding 已保存至 {embedding_path},维度:{len(vectors[0])}") if __name__ == "__main__": generate_embeddings( input_path="data/samples.csv", embedding_path="data/embeddings.pkl", max_samples=200, )

注意:Embedding 的维度与 LLM 模型有关。比如某些模型的 Embedding 是 1024 维、1536 维或者 4096 维,这与普通向量数据库里的向量维度含义一致。如果你的模型输出维度不稳定,请先打印一下len(vectors[0])确认。

5.3 训练逻辑回归分类器

新建train_embedding_clf.py

# 文件路径:llm_feed_classical/train_embedding_clf.py import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from sklearn.metrics import classification_report, roc_auc_score from sklearn.pipeline import Pipeline def main(): df = pd.read_pickle("data/embeddings.pkl") y = df["label"].astype(int).values X = df.drop(columns=["label", "text"]).values X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 逻辑回归对特征尺度敏感,建议先标准化 pipeline = Pipeline([ ("scaler", StandardScaler()), ("clf", LogisticRegression(C=1.0, max_iter=1000, random_state=42)), ]) pipeline.fit(X_train, y_train) y_pred = pipeline.predict(X_test) y_proba = pipeline.predict_proba(X_test)[:, 1] print("=== Embedding + 逻辑回归效果 ===") print(classification_report(y_test, y_pred)) print("AUC: {:.4f}".format(roc_auc_score(y_test, y_proba))) if __name__ == "__main__": main()

这里使用StandardScaler做标准化,是因为逻辑回归使用梯度下降优化,特征尺度差异太大会影响收敛速度。

5.4 对比实验

在实际项目中,建议同时跑三套基线,对比效果:

方案特征优点缺点
基线:TF-IDF + XGBoostTF-IDF 稀疏向量无需外部依赖,成本低语义理解弱
方案一:LLM 特征 + XGBoost6 维结构化特征可解释性好、推理快依赖 LLM 抽取质量
方案二:Embedding + LR高维稠密向量语义信息完整可解释性差

判断一个方案是否适合上线,不能只看离线指标,还要看:

  • 线上推理延迟能否满足要求;
  • 单个样本的处理成本;
  • 特征漂移后如何快速恢复;
  • 出现误判时,能否快速定位原因。

在我的实践中,方案一适合需要解释的业务,方案二适合文本语义差异大、又要求自动化程度高的场景。

6. 常见问题与排查思路

在写这套代码和上线过程中,比较容易踩到下面几个坑。

问题现象常见原因解决思路
LLM 返回的内容不是 JSON,解析失败模型指令遵循能力不足,或温度过高降低温度;Prompt 中给出 JSON 示例;增加解析兜底逻辑
特征全部为 0,模型效果和随机差不多LLM 接口返回异常,或字段名不匹配打印原始返回内容,检查字段名是否与 Prompt 一致
调用 LLM 速度太慢,批量生成要跑几小时单条串行调用,且没有做并发使用线程池或异步并发;对已处理样本做缓存
Embedding 维度不同导致训练报错换了模型,向量维度变化固定模型版本;保存向量时确认维度
LLM 生成标签有偏差,模型学偏未做人工复核,直接把生成标签当 ground truth抽样检查,结合置信度过滤,必要时人工修正
线上成本过高每条请求都调用 LLM,且输入文本过长对输入做截断;对相同或相似文本做缓存;只对不确定样本走 LLM
API 请求超时网络不稳定或服务端负载高增加重试机制和超时时间;使用本地推理服务降低延迟

这里重点说一下 LLM 调用失败时的兜底策略。

千万不要让 LLM 返回异常直接中断整个流程。我的做法是:

# 文件路径:llm_feed_classical/llm_client.py 中的重试示例 import time from openai import OpenAI def extract_features_with_retry(self, text: str, max_retries: int = 3): for attempt in range(max_retries): try: return self.extract_features(text) except Exception as e: print(f"第 {attempt + 1} 次调用失败:{e}") if attempt < max_retries - 1: time.sleep(2 ** attempt) return {}

这个逻辑使用指数退避重试,最多尝试 3 次,最后一次失败时返回空字典,由下游用默认值填充。这样可以保证特征生成任务不会因为单条数据失败而整体失败。

另一个容易忽略的问题是“缓存”。

假设你有 100 万条历史工单需要生成特征,全部调用 LLM 是一笔不小的费用。如果中途失败重跑,已经成功的结果就浪费了。建议在特征生成前,先检查id是否已经在输出文件中存在,存在则跳过。

def load_existing_ids(output_path: str): import os if not os.path.exists(output_path): return set() df = pd.read_csv(output_path, usecols=["id"]) return set(df["id"].tolist())

在循环里加上判断:

existing_ids = load_existing_ids(output_path) for idx, row in df.iterrows(): if row["id"] in existing_ids: continue # 继续处理

这个改动看起来简单,但能省下大量重复调用成本。

7. 最佳实践与工程建议

7.1 明确 LLM 的职责边界

在混合架构里,一定要想清楚“什么任务交给 LLM,什么任务交给经典模型”。

我的经验是:

  • 适合 LLM 的任务:从非结构化文本中提取结构化信息、生成标签候选、生成合成样本;
  • 适合经典模型的任务:高频预测、低延迟决策、强解释性要求、资源受限环境。

一个比较合理的分工:LLM 离线加工特征,经典模型在线实时预测。这样既利用了 LLM 的语义理解能力,又保证了线上服务稳定可控。

7.2 严格控制 LLM 输出质量

LLM 的输出天然带有不确定性,不能默认它每次都能给出正确结果。

建议做到:

  1. 温度参数尽量低,特征抽取任务建议 0 到 0.2;
  2. 每次输出都做格式校验,解析失败要有兜底;
  3. 定期抽检特征质量,观察字段分布是否漂移;
  4. 对关键业务字段,设置合法值域检查,例如“0 或 1”的字段不允许出现 0.5。

在实践中,我发现最有效的做法是:先抽 100 条数据人工核对 LLM 输出特征,确认准确率达标后再全量生成。全量上线后,每周再随机抽 50 条做质量巡检。

7.3 特征一致性是工程核心

LLM 特征生成有一个容易被忽视的问题:不同时间、不同模型版本、不同 Prompt 版本生成的特征分布可能不一致。

比如上个月用 7B 模型,这个月换成了 70B 模型,emotion_intensity的分布可能完全不同。这样会导致未来数据送入旧模型时预测偏移。

解决办法:

  • 固定模型版本和 Prompt 版本,任何变更走版本管理;
  • 特征生成结果落库,记录模型名、Prompt 版本、生成时间;
  • 每次模型或 Prompt 升级,重新生成训练集,重新训练经典模型;
  • 线上监控特征的均值、方差、缺失率,发现异常及时报警。

7.4 成本与性能优化

LLM 调用是这套架构里最大的成本项。优化方向主要有四个:

  1. 批量处理:能离线算的特征不要在线算;
  2. 缓存:相同或相似文本直接命中缓存;
  3. 截断:只保留文本关键段落,减少 Token 消耗;
  4. 混合路由:简单文本用规则或 TF-IDF 处理,只有复杂文本才走 LLM。

这里给出一个简单的混合路由思路:

def route_to_llm(text: str, keyword_rules: dict) -> bool: """如果命中关键词规则,则直接走规则,不调用 LLM。""" for keyword_set in keyword_rules.values(): if any(kw in text for kw in keyword_set): return False return True

比如“包含 12315 / 投诉 / 曝光 / 起诉”等强关键词时,直接标记为候选高危,不需要再调用 LLM 抽取特征。这样可以大幅降低 LLM 调用量。

7.5 可解释性与模型监控

经典模型相对容易解释,这在风控、金融、医疗等场景是很大的优势。如果你选择了 LLM + 经典模型的方案,建议把“解释能力”做进去:

  • 树模型输出特征重要性;
  • 关键特征(如 contains_threat)单独记录并可视化;
  • 误判样本定期复盘,看是 LLM 特征错了,还是经典模型决策错了。

这个排查步骤非常重要:如果发现是 LLM 特征错了,需要调整 Prompt;如果是经典模型决策错了,需要调整阈值或换模型。两者的问题处理方式完全不同。

7.6 安全与权限边界

如果你在项目中使用 LLM API,需要注意几个安全事项:

  • API Key 不要明文写在代码里,使用环境变量或配置中心管理;
  • 发送给 LLM 的文本如果包含用户隐私,要做脱敏处理;
  • 对 LLM 返回内容做校验,防止模型被 Prompt 注入后输出恶意内容;
  • 涉及生产环境的数据处理链路,先在小规模测试集验证,再灰度上线。

特征生成属于数据加工链路,建议对输入的敏感字段(手机号、身份证、地址等)先做脱敏,再调用外部或内部 LLM 服务,避免隐私数据外泄。

8. 总结与下一步学习方向

本文的核心观点是:LLM 与经典机器学习不是替代关系,而是上下游关系。LLM 可以承担“理解文本、生成特征、产出标签、合成样本”这些经典模型不擅长的工作,而经典模型可以承担“高频、低成本、可解释”的最终预测任务。

围绕这个思路,我们完整跑通了两套方案:

  • 第一套:LLM 抽取结构化特征(物流问题、客服态度、情绪强度、紧急程度等),输入 XGBoost 做分类;
  • 第二套:LLM 生成文本 Embedding,输入逻辑回归做分类。

同时,我整理了这套架构在工程落地时最需要注意的几个问题:LLM 输出不稳定、特征一致性、调用成本、缓存设计、模型监控和安全边界。

下一步,你可以继续深入研究这几个方向:

  • 特征抽取 Prompt 优化:用 few-shot 示例提升抽取准确率;
  • 多模态扩展:把语音转写文本、图片 OCR 文本也纳入特征生成链路;
  • 自动路由:用一个小模型判断“是否需要调用 LLM”,进一步降低成本;
  • 在线学习:经典模型上线后,结合新标注数据做增量更新。

我建议你拿自己手头的数据先跑一遍第 4 节的完整流程,哪怕只有几百条样本,也能直观感受到“LLM 特征 + 经典模型”相比“直接用 LLM 分类”在成本、稳定性和可解释性上的差异。技术在迭代,但“让合适的模型做合适的事”这个原则,短期之内不会变。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 2:52:31

Java Web商城项目实战:从解压部署到上线优化的完整指南

简介&#xff1a;一份基于Servlet、JSP、JDBC、jQuery和Ajax的Java Web商城项目&#xff0c;采用MVC分层与面向接口编程思想&#xff0c;适合初学JavaWeb的开发者作为综合练习、毕业设计或课程设计参考。项目覆盖商品展示、购物车、订单处理、用户登录注册、商品评论、新闻公告…

作者头像 李华
网站建设 2026/9/1 2:52:20

AI竞赛国奖项目复盘:YOLOv8目标检测与行为识别实战

简介&#xff1a;本资源是面向大学生人工智能竞赛选手的实战型备赛资料包&#xff0c;聚焦中国计算机设计大赛人工智能挑战赛核心赛题&#xff0c;涵盖移动物体检测、口罩识别、疲劳检测、安全帽识别等典型CV应用场景&#xff0c;提供从模型训练&#xff08;YOLOv3&#xff09;…

作者头像 李华
网站建设 2026/9/1 2:51:46

Hadoop+AI Agent:西藏旅游数据分析与智能规划系统实战

如果你正在准备大数据方向或 AI 方向的毕业设计&#xff0c;又不想只做一个“调包展示型 Demo”&#xff0c;那这次的系统应该很适合参考&#xff1a;基于 Hadoop 与 AI Agent 的西藏旅游数据分析及智能规划系统。它不是单纯写一个爬虫&#xff0c;也不是只调一个大模型接口&am…

作者头像 李华
网站建设 2026/9/1 2:50:42

佳能UFR II打印机驱动从安装到排查:文件名、版本与常见问题全解析

简介&#xff1a;佳能UFRII打印机驱动V1400中文版&#xff0c;面向六十四位Windows系统用户&#xff0c;解决系统无法正确识别打印机、打印任务响应缓慢等常见问题&#xff0c;适用于办公与家庭场景下的佳能设备驱动安装。压缩包共五百一十一个文件&#xff0c;大小约二十五兆字…

作者头像 李华
网站建设 2026/9/1 2:50:40

OPC Core Components x64 105.1解析:从OPC DA联调到排障实践

简介&#xff1a;这是OPC基金会官方发布的OPC Core Components Redistributable&#xff08;x64&#xff09;105.1核心组件再发行包&#xff0c;面向64位Windows系统下需要OPC客户端与OPC服务端稳定通信的工业软件开发者、MES/SCADA集成商及自动化设备调试人员。在COOX等机器人…

作者头像 李华
网站建设 2026/9/1 2:47:43

零代码平台入门实战:从表单设计到仪表盘搭建全流程解析

1. 先搞清楚简道云到底能帮你做什么如果你正在为团队协作、数据收集或流程审批寻找一个轻量级的工具&#xff0c;但又不想投入大量时间和成本去开发一个完整的系统&#xff0c;那么简道云这类零代码平台就值得你花时间了解一下。它不是一个需要你写代码的ERP&#xff0c;也不是…

作者头像 李华