LLMOps 不是一个新造的名词游戏,而是工程团队在把大语言模型从演示脚本推向生产系统时,被迫长出来的一整套方法论与工具链。它承接了 MLOps 的很多思想,却在对象、失效模式与度量方式上发生了根本变化。本文从定义出发,逐层拆解 LLMOps 的边界、生命周期、挑战、成熟度与工具栈,并在最后给出一段可直接运行的 Python 健康度检查脚本。
阅读本文时建议先建立三个锚点:第一,LLM 应用的核心资产从「模型权重」变成了「模型 + 提示 + 检索 + 编排」的组合体;第二,LLM 的输出是非确定性的,这直接摧毁了传统软件「同输入同输出」的测试假设;第三,LLM 的失败往往是「看起来对但实际错」,这让质量保障必须依赖评测集而非断言。
LLMOps 的定义与边界
LLMOps(Large Language Model Operations)指的是围绕大语言模型应用的开发、部署、监控、评测与持续迭代的一整套工程实践。它覆盖的范围通常包括:
- 提示工程与提示版本管理(Prompt Versioning)
- 检索增强生成(RAG)的数据管道与索引治理
- 模型服务与推理优化(吞吐、延迟、显存)
- 评测体系(离线评测、在线评测、LLM as Judge)
- 可观测性(Trace、Token 计量、成本归因)
- 安全与合规(越狱防护、PII 脱敏、内容审核)
- 反馈闭环(用户反馈到评测集与提示迭代的回路)
如果把传统 Web 服务比作「确定性函数 + 可观测性」,那么 LLM 应用更像「概率分布 + 评测 + 成本控制」。这个类比决定了 LLMOps 的几乎所有特殊性。
与 MLOps 的本质差异之一:漂移的对象变了
传统 MLOps 关注的是数据漂移(Data Drift)与概念漂移(Concept Drift):线上输入分布偏离训练分布,或者输入与标签的关系发生变化,导致模型精度下降。检测手段是统计检验(PSI、KL 散度)加上标签回流后的精度监控。
LLMOps 的漂移对象完全不同。模型权重可能是你无法改动的 API,但你依赖的提示、检索语料、上游模型版本都在变:
| 漂移类型 | 触发原因 | 检测手段 | 典型后果 |
|---|---|---|---|
| 提示漂移 | 提示被频繁微调、拼接模板变更 | 提示版本 diff + 回归评测 | 行为突变、格式失配 |
| 模型漂移 | 供应商静默升级模型版本 | 固定评测集定期回归 | 输出风格、能力边界改变 |
| 检索漂移 | 语料更新、索引重建、分块策略变更 | 检索命中率与召回监控 | RAG 答非所问 |
| 数据漂移 | 用户提问分布变化 | 输入聚类与分布监控 | 长尾问题质量下滑 |
结论是:LLMOps 的漂移检测不能只盯着输入分布,而要盯住提示、模型版本、检索语料这三条独立演进的线。
与 MLOps 的本质差异之二:输出是非确定性的
同样的输入,LLM 两次调用可能给出不同答案。原因包括采样温度(temperature)、top-p、并发批处理导致的浮点累加顺序差异,甚至服务端版本更新。这带来三个工程后果:
- 单元测试失效。
assert output == expected几乎必然失败,必须改为断言属性(是否包含关键实体、是否符合 JSON schema、是否通过评判模型)。 - 回归测试成本上升。因为输出是分布,单次采样不足,需要多次采样统计通过率。
- 缓存策略复杂化。语义缓存(Semantic Cache)用相似度命中,会引入「命中错缓存」的新风险。
与 MLOps 的本质差异之三:评测本身是难题
传统模型的评测有明确指标(AUC、F1、RMSE)。LLM 的开放式生成没有唯一正确答案,于是评测演化出多条路径:
- 基于规则的评测:格式校验、关键词命中、JSON 可解析。
- 基于参考答案的评测:BLEU、ROUGE、BERTScore,对生成任务相关性弱。
- LLM as Judge:用强模型给弱模型打分,灵活但存在位置偏见、长度偏见。
- 人工评测:金标准,但昂贵且不可扩展。
没有一种评测是完美的,工程上的正确做法是分层组合:规则兜底、评判模型做主体、人工抽样校准。
LLM 应用的生命周期
一个 LLM 应用的生命周期可以拆成五个阶段,每个阶段都有对应的 LLMOps 能力要求。
阶段一 数据与提示资产
这一阶段的核心是把「数据」和「提示」当作一等公民管理起来。
- 提示要以代码形式入库,带版本号、作者、变更说明、关联评测结果。
- 提示的评测要能一键回归,避免「改了一个词,全站行为变化」。
- 如果是 RAG 应用,还要管理分块策略、嵌入模型版本、索引快照。
提示版本管理的最小可用方案是 Git + 结构化目录,进阶方案是专门的提示管理平台。若想深入提示与上下文的工程化,可参考 上下文工程 的实践。
阶段二 评测
评测不是上线前的一次性动作,而是贯穿始终的护栏。合理的评测体系包含三层:
- 开发期:小规模黄金集,快速反馈,几十到几百条。
- 上线前:完整回归集,覆盖边界与对抗样本,千条量级。
- 上线后:在线指标(点赞率、任务完成率、重试率)+ 抽样人工评估。
评测集要像代码一样做版本管理,每次提示或模型变更都要跑一遍。
阶段三 部署
部署阶段要回答:用哪家模型、自建还是托管、如何做灰度。
- 自建推理需要处理吞吐、显存、并发,这部分是 LLMOps 最重的工程,详见 推理引擎对比 。
- 托管 API 省去运维,但引入供应商锁定与成本不可控。
- 生产环境通常需要网关统一鉴权、限流、路由与成本归因。
阶段四 监控
监控要覆盖三层:
- 系统层:QPS、P99 延迟、TTFT(首 token 时间)、错误率、GPU 利用率。
- 质量层:输出格式合规率、拒答率、幻觉抽样检出率。
- 成本层:按用户/租户/功能的 Token 消耗与费用归因。
阶段五 反馈闭环
闭环是把线上信号转化为迭代输入的机制:
- 用户显式反馈(点赞、点踩、纠错)
- 隐式反馈(重试、复制、会话中断)
- 线上异常样本自动进入待标注队列
- 标注后回流评测集,驱动提示与检索迭代
闭环缺失是绝大多数 LLM 应用停在 Demo 阶段的根本原因。
生产化五大挑战
挑战一 成本
LLM 的成本结构与传统服务差异极大。传统服务成本主要是 CPU 与带宽,边际成本低;LLM 成本与 Token 数、上下文长度、模型规模强相关,边际成本高。
成本优化的杠杆按收益排序:
- 降低上下文长度(减少冗余检索、压缩历史)。
- 使用语义缓存与精确缓存。
- 模型降级路由(简单问题走小模型)。
- 量化与推理优化(FP8、INT4)。
- 批处理与离线化。
成本治理的系统性方法可参考 成本与 FinOps 。
挑战二 延迟
延迟由三部分组成:排队时间、首 token 时间(TTFT)、每 token 生成时间(TPOT)。用户感知最敏感的是 TTFT。
降低延迟的手段包括:连续批处理提升吞吐、投机解码加速生成、前缀缓存复用系统提示、地理就近部署减少网络往返。连续批处理的原理会在本组的连续批处理专题中详述。
挑战三 质量
质量问题是 LLM 应用最隐蔽的失败:输出流畅、语法正确、但事实错误。质量保障依赖三件事:
- 有代表性的评测集
- 能落地的评测方法(规则 + 评判模型 + 人工)
- 可追溯的变更记录
挑战四 安全
安全威胁包括提示注入、越狱、数据外泄、工具滥用。防护是纵深防御:
- 输入侧:注入检测、长度限制。
- 系统侧:工具调用白名单、最小权限。
- 输出侧:PII 脱敏、内容审核。
- 审计侧:完整 Trace 留存。
挑战五 可观测性
LLM 应用的可观测性远超传统 APM。它需要记录:
- 完整的调用链(检索、重排、生成、工具调用)
- 每次调用的 Token 明细与成本
- 输入输出全文(注意脱敏与合规)
- 评分与用户反馈
这构成了 Agent 可观测性专题的核心命题。
成熟度模型 L1 到 L4
可以用四级成熟度模型评估团队现状:
| 级别 | 名称 | 特征 | 关键缺口 | 升级动作 |
|---|---|---|---|---|
| L1 | 原型期 | 硬编码提示、手动测试、无监控 | 无版本、无评测 | 提示入库、建黄金集 |
| L2 | 受控期 | 提示版本化、有离线评测、基础监控 | 无闭环、成本不可见 | 接入 Trace、成本归因 |
| L3 | 生产期 | 自动评测、灰度发布、成本看板 | 闭环弱、安全薄弱 | 建反馈闭环、安全护栏 |
| L4 | 优化期 | 闭环驱动迭代、多模型路由、FinOps | 组织与流程协同 | 平台化、自助化 |
大多数团队在 L1 到 L2 之间,卡点通常是评测集建设与成本可见性。
LLMOps 的度量体系
成熟度升级的前提是「可度量」。LLMOps 的指标体系可以按四个维度组织,每个维度都要有明确的采集点与告警阈值。
| 维度 | 指标 | 采集点 | 参考阈值 |
|---|---|---|---|
| 性能 | TTFT P95 | 网关流式响应首个 token | 小于 800ms |
| 性能 | TPOT | 生成阶段每 token 耗时 | 小于 50ms |
| 性能 | 吞吐 | 每秒完成请求数 | 按容量规划 |
| 质量 | 格式合规率 | 输出 schema 校验 | 大于 99% |
| 质量 | 拒答率 | 内容审核标记 | 小于 5% |
| 质量 | 幻觉抽样率 | 人工与评判模型抽检 | 小于 3% |
| 成本 | 单请求 Token | Trace 中 usage 字段 | 按预算设定 |
| 成本 | 单请求费用 | Token 数乘单价 | 按预算设定 |
| 成本 | 缓存命中率 | 缓存层计数 | 大于 30% |
| 安全 | 注入拦截率 | 输入检测计数 | 监控趋势 |
| 安全 | PII 命中数 | 输出脱敏计数 | 应为 0 |
这套指标的价值在于:当有人问「这个模型能不能换」或「提示改动有没有变差」时,你有一张表可以回答,而不是靠直觉。
提示与模型的协同演进
LLMOps 的一个独特之处是「提示」与「模型」是两条独立演进的线,二者必须协同管理。
- 提示兼容性矩阵:同一个提示在不同模型版本上的表现可能差异巨大。工程上应维护一张矩阵,记录每个提示版本在每个候选模型上的评测分数,用于路由决策与迁移评估。
- 提示的抽象层次:把提示拆成「系统角色 + 任务模板 + 少样本示例 + 输出约束」四层,每层独立版本化,可以避免改一处而动全身。
- 模型迁移的灰度:切换模型时,先在影子流量上跑,比较新旧模型在同一评测集上的分数与成本,再决定放量比例。
一个常见的反模式是「提示与模型耦合」:提示里硬编码了某个模型的特有行为(比如依赖特定格式的 JSON 修复),一旦换模型就全面崩坏。防御手段是把输出约束用结构化方式表达(如 JSON Schema、函数调用),而非依赖模型自觉。
组织与协作
技术之外,LLMOps 的落地高度依赖组织协作模式。
- 谁负责提示:产品、算法还是工程?实践中常见的是「产品定目标、算法写提示、工程管发布」,但这要求三方共享评测集。
- 谁负责评测集:评测集是团队的核心资产,必须有明确 owner 与评审流程,否则会迅速腐化。
- 谁负责成本:成本需要 FinOps 角色或至少一个明确的责任人,否则会无人认领。
- 变更评审:提示变更、模型切换、检索策略调整都应走评审,附上评测对比。
一个健康的协作模式是:所有变更都产出一份「评测报告」,报告里同时包含质量、延迟、成本三项对比,评审者据此决策。
从 L1 到 L2 的最小落地清单
如果团队现在还在 L1,下面这份清单可以用最小的投入把成熟度推到 L2。
- 把所有提示从代码里抽出来,放进独立的提示目录,纳入 Git 管理。
- 建立 50 到 200 条黄金评测样本,覆盖主路径与典型边界。
- 写一个一键回归脚本,每次提示变更自动跑评测并输出分数对比。
- 在网关层记录每次请求的 Token 数与费用,按功能维度打标签。
- 接入一个 Trace 系统,至少能看到完整调用链与耗时分布。
- 为关键路径设置告警:错误率、TTFT P95、格式合规率。
- 建立用户反馈入口,把点踩样本定期抽样进评测集。
这七步不需要复杂的平台,用脚本加开源工具就能完成。完成后再考虑多模型路由、语义缓存、自动化评测等进阶能力。
工具栈全景
LLMOps 的工具栈可以按职能划分。下表给出各环节的代表性工具与选型建议:
| 职能 | 代表工具 | 定位 | 选型建议 |
|---|---|---|---|
| 推理引擎 | vLLM、TensorRT-LLM、SGLang | 高吞吐模型服务 | 通用选 vLLM,极致性能选 TensorRT-LLM |
| 网关 | LiteLLM、OpenRouter | 多模型统一接入与路由 | 需要多供应商时必备 |
| 评测 | Ragas、DeepEval、promptfoo | 离线评测与回归 | RAG 场景优先 Ragas |
| 可观测 | Langfuse、Phoenix、LangSmith | Trace 与成本分析 | 自建选 Langfuse |
| 向量库 | Milvus、Qdrant、pgvector | 检索索引 | 中小规模 pgvector 够用 |
| 编排 | LangGraph、LlamaIndex | 多步流程与 Agent | 有状态流程选 LangGraph |
| 提示管理 | PromptLayer、Git | 提示版本与回归 | 起步用 Git 即可 |
| 缓存 | GPTCache、Redis | 语义与精确缓存 | 高重复场景收益大 |
选型原则是:先用最小可用的组合跑通闭环,再按瓶颈替换单点,而不是一次性堆满工具。
实战 一个 LLMOps 健康度检查脚本
下面这段脚本检查一个 LLM 服务的关键健康指标:服务可达性、TTFT、输出格式合规率,以及一个基于 Ragas 的离线评测示例。脚本依赖 httpx 与 ragas,可以直接改造后接入你的 CI。
"""llmops_health_check.py:LLM 服务健康度检查,可接入 CI。"""
import time
import json
import statistics
from dataclasses import dataclass, field
import httpx
@dataclass
class HealthReport:
reachable: bool = False
ttft_ms: float = 0.0
p99_latency_ms: float = 0.0
schema_pass_rate: float = 0.0
samples: list = field(default_factory=list)
def as_dict(self):
return {
"reachable": self.reachable,
"ttft_ms": round(self.ttft_ms, 2),
"p99_latency_ms": round(self.p99_latency_ms, 2),
"schema_pass_rate": round(self.schema_pass_rate, 4),
}
def stream_once(base_url: str, api_key: str, prompt: str) -> tuple[float, str]:
"""返回 (TTFT 毫秒, 完整输出文本)。"""
payload = {
"model": "qwen2.5-7b-instruct",
"messages": [{"role": "user", "content": prompt}],
"stream": True,
"temperature": 0.2,
}
headers = {"Authorization": f"Bearer {api_key}"}
start = time.perf_counter()
first_token_at = None
chunks = []
with httpx.stream(
"POST", f"{base_url}/v1/chat/completions",
json=payload, headers=headers, timeout=60.0,
) as resp:
resp.raise_for_status()
for line in resp.iter_lines():
if not line or not line.startswith("data: "):
continue
body = line[len("data: "):]
if body.strip() == "[DONE]":
break
delta = json.loads(body)["choices"][0]["delta"]
text = delta.get("content")
if text:
if first_token_at is None:
first_token_at = time.perf_counter()
chunks.append(text)
ttft = (first_token_at - start) * 1000 if first_token_at else -1.0
return ttft, "".join(chunks)
def check_schema(text: str) -> bool:
"""要求输出是合法 JSON 且含 answer 字段。"""
try:
obj = json.loads(text)
except json.JSONDecodeError:
return False
return isinstance(obj, dict) and "answer" in obj
def run_health_check(base_url: str, api_key: str, n: int = 20) -> HealthReport:
report = HealthReport()
prompts = [
'请以 JSON 返回 {"answer": "..."},问题:中国的首都是哪里?'
for _ in range(n)
]
latencies, ttfts, passed = [], [], 0
for p in prompts:
t0 = time.perf_counter()
ttft, text = stream_once(base_url, api_key, p)
latencies.append((time.perf_counter() - t0) * 1000)
if ttft >= 0:
ttfts.append(ttft)
if check_schema(text):
passed += 1
report.samples.append({"ttft_ms": ttft, "schema_ok": check_schema(text)})
report.reachable = len(latencies) == n
report.ttft_ms = statistics.median(ttfts) if ttfts else 0.0
report.p99_latency_ms = (
sorted(latencies)[int(len(latencies) * 0.99) - 1] if latencies else 0.0
)
report.schema_pass_rate = passed / n
return report
if __name__ == "__main__":
rpt = run_health_check("http://localhost:8000", "EMPTY", n=20)
print(json.dumps(rpt.as_dict(), ensure_ascii=False, indent=2))
assert rpt.reachable, "服务不可达,检查 vLLM 进程与端口"
assert rpt.schema_pass_rate >= 0.95, "输出格式合规率低于 95%,需排查提示"
如果要评测 RAG 的检索与生成质量,可以叠加 Ragas 的三项核心指标:
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
data = Dataset.from_dict({
"question": ["什么是 PagedAttention?"],
"answer": ["PagedAttention 把 KV Cache 切分为固定大小的 block。"],
"contexts": [["PagedAttention 借鉴操作系统分页,将 KV Cache 分成 block 管理。"]],
"ground_truth": ["把 KV Cache 按 block 管理,减少显存碎片。"],
})
result = evaluate(
data,
metrics=[faithfulness, answer_relevancy, context_precision],
)
print(result)
print("判据:faithfulness 与 context_precision 均高于 0.85 才算可用")
这段评测把「质量」从主观感受变成了可回归的数字,是 LLMOps 从 L1 迈向 L2 的关键一步。
常见坑清单
坑一 没有评测集就开始调提示
没有评测集的提示优化是盲调。团队会陷入「感觉变好了」的循环,却无法证明任何一次变更的真实收益。起步阶段哪怕只有 50 条黄金样本,也远胜于零。
坑二 把成本监控放在最后做
成本是 LLM 应用最容易失控的维度。上下文长度翻倍、重试策略激进、缓存缺失,都会让账单数倍增长。成本归因应该在第一版上线时就接入。
坑三 忽略供应商的静默升级
托管模型的版本可能在你不察觉时更新,导致行为突变。防御手段是固定评测集定期回归,并对关键路径保留可回滚的模型版本。
坑四 只用平均延迟看性能
平均值会掩盖长尾。P99 延迟往往决定了用户投诉率。监控必须看分位数,尤其是 TTFT 的 P95 与 P99。
坑五 把日志当成可观测性
打印 prompt 与 response 只是日志,不是可观测性。真正的可观测性需要结构化 Trace、成本字段、评测分数与关联的用户反馈。
坑六 忽视安全护栏
提示注入与数据外泄是真实威胁。上线前至少要有输入检测、工具白名单与输出脱敏三道防线。
坑七 把提示当成一次性配置
提示是持续演进的资产,不是上线时写死的常量。没有版本管理与回归评测的提示,会在多次小改后积累出难以定位的行为退化。
坑八 评测集与线上分布脱节
用构造的干净样本训练的评测集,往往测不出真实用户的脏输入。定期用线上抽样补充评测集,才能让评测分数与真实体验对齐。
坑九 过早追求平台化
在只有一两个应用时就投入自建平台,通常是浪费。先用手工加脚本跑通闭环,等到应用数量与团队规模真正需要时再平台化,收益更高。
小结
LLMOps 的本质是把「非确定性的模型应用」变成「可度量、可回归、可控制成本的工程系统」。它与 MLOps 的差异集中在三点:漂移对象是提示与模型而非数据分布;输出非确定性使测试必须改为属性断言与统计评测;评测本身没有唯一答案,需要分层组合。
生产化的五大挑战(成本、延迟、质量、安全、可观测)互为约束:提升质量往往增加成本与延迟,降低成本可能损害质量。工程判断力体现在如何在这些约束下找到当前阶段的平衡点。
落地路径建议从 L1 起步:先把提示入库、建一个哪怕很小的黄金评测集、接入基础的 Trace 与成本字段,就能获得最大边际收益。随后再逐层补齐闭环、安全与多模型路由能力。推理侧的性能工程可以接着看本组的推理引擎对比与连续批处理专题,把吞吐与显存这两个最硬的约束先解决掉。
需要强调的是,LLMOps 的建设顺序不是「先搭平台再上应用」,而是「应用驱动、按瓶颈补齐」。每一个新增的工具与流程,都应该对应一个真实存在的痛点。脱离痛点的平台化,只会制造无人使用的内部系统。
最后,LLMOps 的能力边界会随模型能力一起演化。当模型自身越来越可靠、工具调用越来越标准时,一部分今天的工程复杂度会被上游吸收;但评测、成本、安全与可观测这四件事,因为涉及业务语义与组织责任,大概率会长期留在应用团队的职责范围内。
因此,投入 LLMOps 的顺序应该遵循「先度量、后优化、再自动化」:没有度量就无法判断优化是否有效,没有优化就谈不上自动化的收益。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。