构建生产级 LLM 应用:实际会遇到什么问题
大多数 LLM 演示都能正常运行。但大多数生产环境中的 LLM 应用却并非如此——至少不稳定。一个引人注目的原型与能够承受真实用户流量的应用之间的差距,比我接触过的任何其他软件类别都要大,而且故障很少发生在你的预期之中。
这是一份关于容易出现故障的环节的指南:成本、一致性、组合和评估。这不是理论,而是导致团队在首次成功演示三个月后悄然搁置项目的具体问题。
核心问题:自然语言并非 API
传统软件是确定性的。使用相同的输入调用函数,会得到相同的输出。LLM 从根本上打破了这一约定。你可以指示模型返回具有特定模式的 JSON,它会照做——直到它不照做。你可以告诉它将响应限制在 200 字以内,它也会遵守——直到用户的输入触发了覆盖你指令的模式。
这不是你能修复的 bug。这是接口的本 质。
实际后果是,LLM 调用下游的一切都变得概率化。你的 JSON 解析器会遇到格式错误的 JSON。你的下游管道会收到截断的响应。你的 UI 会显示违反你模式约束的输出。这些都不会按预期发生;它以你必须衡量的方式发生。
那些在生产环境中取得成功的工程师很早就认识到了这一点。他们将每个 LLM 输出都视为用户输入:验证它,优雅地处理故障,并为 5% 结构错误的输出情况进行设计。
成本和延迟:无人预料的经济学
令大多数团队感到惊讶的数学:推理成本与生产流量的扩展方式不同于训练成本。
几百美元可以让你进行大量的提示词实验。但到了生产规模,经济状况会完全改变。如果你的应用程序每次用户操作都进行一次 LLM 调用,并且每次调用以当前 API 定价计算为 2,000 token,那么一个适度的 10 万日活跃用户可能会产生超出你整个基础设施预算的账单。在演示阶段给你留下深刻印象的模型往往是昂贵的。
延迟是问题的另一方面。输入 token 长度对延迟影响相对较小——模型并行处理输入。但输出生成是顺序的,逐个 token 进行,任何实质性响应的延迟底线约为 500 毫秒。具有实时要求的应用程序(聊天、语音、自动完成)会遇到这个瓶颈,无法通过工程手段规避,除非接受更短的输出或切换到更快、能力较弱的模型。
经受住生产环境考验的实用策略:
- 按复杂性路由。 对分类、提取和简单转换使用小型、快速的模型。将 大型模型保留给实际需要推理的任务。大多数任务不需要。
- 积极缓存。 语义缓存——存储先前查询的嵌入并为语义相似的输入返回缓存结果——对于具有自然重复模式的工作负载,可以降低 40-60% 的成本。
- 在延迟允许时进行批处理。 后台作业、报告生成、内容审核——任何不阻塞用户操作的任务都应该进行批处理,并以较低的优先级处理。
- 审查你的提示词长度。 团队经常发布带有 500 字系统指令的提示词,而这些指令本可以缩短到 100 字。在规模化应用中,每个 token 都很重要。
那些正确处理这个问题的团队从第一天起就把成本视为一个一流的工程指标,而不是以后才要解决的财务问题。
提示词工程、RAG 还是微调:做出正确选择
这三种方法存在于努力程度与性能的频谱上,错误的选择会浪费数月时间。
提示词工程是所有一切的起点。无需训练数据,即时迭代,足以胜任大多数任务。它的上限是模型已有的知识和上下文窗口。当你需要基础模型缺乏的特定领域知识、在对抗性输入下高度一致的格式,或显著的延迟/成本降低时,单独使用提示词工程就会失败。
检索增强生成 (RAG) 在无需重新训练的情况下解决了知识问题。你将文档嵌入,存储在向量数据库中,在查询时检索相关片段,然后将它们注入到上下文中。对于 企业用例——内部文档、客户支持、知识库——RAG 处理了 80% 单独使用提示词工程不足的情况。需要注意的陷阱:检索质量难以调优,相关片段不总能组合成连贯的上下文,并且随着文档的更改,嵌入管道需要维护。
微调在以下情况下有意义:你拥有大量高质量的标注数据,你需要模型内化难以在提示词中表达的模式,或者你需要通过显著缩短提示词来降低推理成本。一个经过良好微调的较小模型可以以一小部分每 token 成本胜过一个经过提示词工程的大型模型。但微调管道构建和维护成本高昂,随着基础模型更新,模型性能会下降,而且改进的反馈周期很慢。
一个有用的启发式方法是:首先尝试提示词工程。当你需要领域知识时,转向 RAG。当你拥有数据并且提示词工程无法弥补明显的性能差距时,转向微调。大多数应用程序永远不需要微调。
任务组合:多步骤应用崩溃之处
生产环境中,单提示应用是例外。大多数真实应用会串联多个 LLM 调用:分类输入、检索上下文、生成响应、验证输出、格式化显示。每个步骤都可能失败,并且故障会累积。
组合系统中的故障模式与单次调用故障不同:
单个步骤故障 是显而易见的情况——一次调用返回格式错误的输出并破坏整个管道。这些是可测试的。
组合性鸿沟 更难:每个步骤单独工作时都正确,但它们的输出未能组合成你想要的结果。分类器正确地路由了查询。检 索器返回了相关文档。生成器正确地综合了这些文档。但最终输出未能回答用户的实际问题,因为路由决策稍有偏差,而你的单元测试未能捕捉到这一点。
失控循环 会影响任何由 LLM 决定何时停止的智能体系统。如果没有对迭代次数的硬性限制,模型可能会进入循环,不断消耗 token,直到你外部终止它。
妥善处理这些问题需要:
- 集成测试,而不仅仅是针对单个提示的单元测试。使用代表性输入测试整个管道。
- 对任何可自主导向的循环或智能体设置硬性终止条件。
- 在组合边界处进行显式错误处理,并为每种故障模式设置回退行为。
- 在可能的情况下,在 API 层面强制执行结构化输出,而不仅仅是在提示中请求。
从单次调用到多步骤应用的转变,是大多数团队发现“在我的机器上工作”对于 LLM 来说与传统软件有所不同的地方。
评估:大多数团队直到为时已晚才开始做的事情
生产成功的唯一最可靠的预测因素是团队在产品发布前是否建立了评估框架。不是在出现问题之后——而是在之前。
LLM 的评估不是通过/失败。它是一个分布:输出多久能达到你的质量标准,该比率如何随输入类型变化,以及当你更新模型或提示时它如何变化?
建立一个有用的评估体系不需要研究团队:
- 收集代表性示例。 50-100 个带有预期输出的真实输入,涵盖你关心的分布。包括对抗性案例——你知道很难处理的输入。
- 定义质量标准。 对于你的应用,“正确”意味着什么?事实准确性?格式合规性?语气?明确列举出来。
- 用 Git 管理提示版本。 将提示视为代码。跟踪更改,衡量性能差异,并且在不运行评估的情况下,绝不部署提示更改。
- 自动化回归测试。 在每次提示更改后,部署前运行你的评估套件。LLM 作为评判者已经足够可靠:使用一个强大的模型自动根据你的标准评估输出。
跳过这一步的团队会发现,当出现性能下降时,他们没有基线可供参考。模型提供商会推送更新;你的应用在特定输入上的性能可能会在不知不觉中悄然恶化。评估是唯一的知情途径。
可观测性:基本要求,而非可选
到 2025 年,生产级 LLM 生态系统已经开发出足够的工具,使得可观测性变得简单直观——但团队仍然跳过它,因为在早期阶段,仪表化感觉像是额外的开销。
事实并非如此。记录生产环境中每次 LLM 调用的输入、输出、延迟和成本是最低要求。你需要这些来调试用户投诉(“模型给出了错误的答案”),检测隐性性能下降(“此查询类别的性能下降了 20%”),以及优化成本(“我们没有意识到 30% 的开销花在了这一个端点上”)。
除了基本日志记录,还要追踪多步骤管道中完整的请求路径。当复杂的智能体工作流失败时,你需要知道是哪个步骤失败了以及它的输入是什么——而不仅仅是最终输出是错误的。
可观测性数据反馈到评估数据集中。真实的生产故障成为测试案例。这种循环——发布、观测、改进评估、修复、再发布——是生产级 LLM 应用随着时间推移实际改进的方式。
哪些东西能经受住变化
工具和 API 持续变化。价格每周下降。新模型超越上个月的最新技术。新框架承诺解决编排问题。你读到的大部分内容将在六个月内过时。
不变的是:
- 在任何更改前后进行评估的需求
- 按任务复杂度进行路由的经济学原理
- 组合管道中的故障模式
- 将每个 LLM 输出视为不可信输入的价值
那些基于这些基本原理进行构建的工程师可以吸收表层变化,而无需从头开始重建。那些直接基于特定模型行为或框架 API 进行构建的团队,每次发生变化时都不得不重写大部分代码。
核心洞察是,LLM 应用工程与传统软件工程的相似度较低,而与分布式系统工作的相似度更高:你正在从不可靠的组件中构建可靠的行为,这种规范性来自于你对接口(或“缝隙”)施加的严格性,而不是来自任何单个组件的质量。
这种规范性是可以学习的。它只需要从一开始就刻意应用,在演示版成为产品之前。
