1. 从"能跑通"到"敢上线":企业级 LLM 到底卡在哪
很多人第一次接触 LLM 应用,都是从一个几十行的脚本开始的:调个 API,拼一段 prompt,本地跑通,效果惊艳,然后信心满满地跟老板说"这个能做"。结果真到了要接入公司业务系统、要面对真实用户、要处理敏感数据的时候,才发现事情完全不是那么回事——模型偶尔胡说八道、响应时快时慢、成本算不清楚、数据合规过不了审、出了问题根本不知道是哪一环崩的。
这就是"企业级 LLM"和"个人玩票 LLM"之间那道看不见的鸿沟。所谓企业级,核心不是模型参数有多大、榜单排名有多高,而是这套系统能不能在真实业务压力下稳定、可控、可观测、可追溯、可迭代。它要面对的是并发、是成本、是合规、是故障恢复,是"半夜三点报警了谁去处理"这种极其现实的问题。
我打算用几篇的篇幅,把企业级 LLM 从架构设计到落地运维的完整链路拆开讲清楚。这一篇先解决最顶层的问题:企业级 LLM 系统的整体架构应该怎么搭,各个模块的边界在哪里,以及为什么很多团队一开始就把方向搞错了。不管你是刚被安排去做公司大模型应用的工程师,还是正在评估要不要自建 LLM 平台的负责人,这篇都能帮你少走至少半年的弯路。
需要先说明一点:企业级 LLM 不是一个单一技术,而是一整套工程体系。它至少包含模型接入层、编排调度层、数据与知识层、评测与观测层、安全与权限层这几大块。下面我会逐块拆解,每一块都会讲清楚"为什么需要它""常见做法是什么""坑在哪里"。
2. 企业级 LLM 的架构分层:别把编排层和模型层搅在一起
2.1 为什么"一个脚本打天下"必然失败
我见过太多团队,第一版 LLM 应用就是一个 Flask 接口,里面直接写死了模型调用、prompt 拼接、业务逻辑、数据库查询。刚开始只有一两个功能,改起来还挺快。等到功能涨到十几个、模型从一家换成三家、prompt 要按用户角色动态调整的时候,这个文件就变成了没人敢动的"屎山"。
问题的根源在于职责没有分层。模型调用是会变的(今天用 A 家,明天可能换 B 家,或者本地部署),prompt 是会变的(业务方天天提需求),业务逻辑是会变的(产品经理的脑洞),但它们的变更频率和变更原因完全不同。把它们耦合在一起,任何一处改动都会牵一发动全身。
企业级架构的第一原则就是按变更频率分层。变更最频繁的放最上层,最稳定的放最底层。模型接入层相对稳定(除非你要频繁换供应商),编排层变化中等,业务逻辑层变化最快。分层之后,换模型不用动业务代码,改 prompt 不用重新部署整个服务。
2.2 五层架构的职责边界
我把企业级 LLM 系统拆成五层,从下往上说:
模型接入层(Model Gateway):这一层负责屏蔽底层模型的差异。不管是云端 API、私有化部署的开源模型,还是不同厂商的接口,统一收敛成一套内部协议。它的核心价值是可替换性——当某个供应商涨价、限流、或者服务不稳定时,你能在配置层面切换,而不是改代码。这一层还要处理重试、超时、限流、熔断这些基础的稳定性问题。
编排调度层(Orchestration):这是整个系统的"大脑"。它负责把用户请求拆解成一系列步骤——要不要检索知识库、要不要调用工具、要不要多轮推理、用哪个模型处理哪一步。现在流行的 Agent、Workflow、RAG 都发生在这一层。它的核心是把复杂任务拆成可控的原子操作,并且每一步都可观测、可干预。
数据与知识层(Data & Knowledge):企业级 LLM 和通用聊天机器人的最大区别,就是它要基于企业自己的数据回答问题。这一层包括向量库、文档处理管道、知识图谱、以及数据的更新和版本管理。它的难点不在技术选型,而在数据治理——文档格式五花八门、内容过期、权限复杂,这些才是真正耗时间的地方。
评测与观测层(Eval & Observability):这是最容易被忽略、但企业级最不能省的一层。没有评测,你根本不知道改了一版 prompt 之后效果是变好还是变差;没有观测,线上出了问题你只能靠猜。这一层要记录每一次调用的完整链路(输入、输出、耗时、token 消耗、命中的知识片段),并且有一套自动化的评测集来回归验证。
安全与权限层(Security & Governance):企业数据不能随便喂给外部模型,用户只能看到自己有权限的内容,输出不能包含敏感信息。这一层要处理数据脱敏、访问控制、内容审核、审计日志。很多团队做到一半才发现合规过不了,回头返工代价极大。
2.3 分层不是目的,解耦才是
需要强调的是,分层本身不是目的。小团队完全可以把前两层合并,甚至五层都塞进一个服务里,只要模块之间的接口是清晰的。我见过一个三人团队,用单体架构把 LLM 应用做得非常稳,因为他们把每个模块都写成了独立的类,接口定义得很干净,将来要拆随时能拆。
反过来,我也见过一上来就上微服务、上消息队列、上 K8s 的团队,结果因为人手不够,运维成本压垮了整个项目。架构的复杂度要匹配团队的规模和业务的真实需求,这是我在多个项目里反复验证过的经验。企业级不等于复杂,企业级等于"该有的都有,不该有的一个都不多"。
3. 模型接入层:把"换模型"变成改一行配置
3.1 统一协议是接入层的地基
模型接入层要解决的核心问题,是让上层代码不感知底层用的是哪家模型。做法是定义一套内部统一的请求和响应格式,所有外部模型都通过适配器(Adapter)转换到这套格式。
一个典型的内部请求结构大概长这样:
class LLMRequest: messages: list[dict] # 对话历史,统一成 role/content 结构 model_alias: str # 内部别名,如 "fast"、"smart"、"cheap" temperature: float max_tokens: int tools: list[dict] | None # 工具定义,统一格式 metadata: dict # 业务透传信息,如用户ID、会话ID注意这里用的是model_alias而不是具体的模型名。上层业务只说"我要一个快的"或者"我要一个聪明的",具体映射到哪个厂商的哪个模型,由配置决定。这样当你想把"smart"从 A 模型换成 B 模型时,只改配置,业务代码一行不动。
响应格式同理,要统一成包含content、tool_calls、usage、finish_reason这些字段的结构。不同厂商的字段名千奇百怪,适配器的工作就是把这些差异吃掉。
3.2 重试、超时、限流:稳定性三件套
模型调用是典型的不可靠外部依赖。网络会抖、供应商会限流、偶尔会返回 5xx。接入层必须把这些处理掉,不能让上层业务去操心。
超时要分层设置。连接超时短一点(比如 5 秒),读取超时长一点(比如 60 秒,因为大模型生成慢)。但要注意,流式输出(streaming)场景下超时逻辑不一样,不能用固定的读取超时,而应该用"两个 token 之间的最大间隔"来判断。
重试要区分错误类型。网络超时、5xx 可以重试;4xx(比如参数错误、余额不足)重试没意义,重试只会浪费时间和钱。重试要加指数退避,避免雪崩。我一般设置最多重试 2 次,间隔 1 秒、2 秒。
限流要双向做。一方面限制对上游供应商的调用速率,避免触发对方的限流;另一方面限制下游业务对模型的调用,避免某个业务把配额吃光。用令牌桶或者滑动窗口都行,关键是按业务维度隔离,别让一个业务拖垮所有业务。
# 简化的重试逻辑示意 def call_with_retry(request, max_retries=2): for attempt in range(max_retries + 1): try: return adapter.call(request, timeout=(5, 60)) except RetryableError as e: if attempt == max_retries: raise time.sleep(2 ** attempt) except NonRetryableError: raise3.3 成本核算:接入层顺手就做了
成本控制是企业级绕不开的话题。好消息是,成本核算放在接入层做最自然,因为所有调用都经过这里。每次调用记录下模型、输入 token 数、输出 token 数,乘以单价,就能算出这次调用的成本。
我建议在接入层就把成本算出来,写进响应的 metadata 里,透传给上层。这样业务侧可以按用户、按功能、按部门做成本归集。很多公司到了月底才发现账单爆炸,就是因为没有在调用发生时就记录成本。
提示:不同模型的计费方式差异很大,有的按输入输出分别计价,有的有缓存命中折扣,有的按图片/音频单独计费。接入层的成本计算模块要能配置这些规则,别写死。
3.4 一个容易踩的坑:别在接入层做业务判断
接入层要克制。它的职责就是"把请求可靠地送到模型,把结果可靠地带回来",不要在里面塞业务逻辑。我见过有人在接入层做"如果用户是 VIP 就用贵模型"这种判断,结果后来业务规则变了,改起来特别别扭。这类判断应该放在编排层,接入层只认model_alias。
4. 编排调度层:Agent 不是越自主越好
4.1 从固定流程到动态编排
编排层要回答的核心问题是:一个用户请求,应该经过哪些步骤才能得到答案。最简单的场景是"直接问模型",复杂一点的场景是"先检索知识库,再让模型基于检索结果回答",再复杂就是"模型自己决定要不要调用工具、调用哪个工具、调用几次"。
这三种对应了三种编排模式:直连、固定工作流(Workflow)、自主 Agent。很多团队一上来就想做自主 Agent,觉得这样最"智能"。但我的经验是,在企业场景里,固定工作流的性价比远高于自主 Agent。
原因很简单:企业业务大多是有明确流程的。报销就是报销,客服就是客服,这些流程的步骤是确定的,用工作流把步骤固定下来,可控、可测、可优化。自主 Agent 虽然灵活,但它的不确定性正是企业最怕的东西——同样的输入,今天走这条路,明天走那条路,出了问题很难复现,评测也很难做。
4.2 工作流编排的三种粒度
固定工作流也有粒度之分。最粗的是整链路固定,比如"检索→重排→生成→审核"四步写死。中等的是步骤内可选,比如检索这一步可以选向量检索或关键词检索。最细的是步骤内参数动态,比如根据问题类型动态调整检索的 top_k。
我一般建议从整链路固定开始,跑通了再逐步细化。因为一开始你根本不知道哪个环节是瓶颈,过早优化是浪费。等有了评测数据,发现"检索召回率不够"或者"生成阶段幻觉多",再针对性地调整那一步。
4.3 工具调用的边界设计
如果确实需要工具调用(比如查订单、发邮件、算数据),工具的设计有几个原则:
工具要少而精。给模型 20 个工具,它选择错误的概率会大幅上升。我一般控制在 5 个以内,超过就考虑分组或者用路由先分类。
工具描述要写清楚"什么时候用"。很多人只写工具功能,不写使用场景。模型不知道边界,就会乱用。好的描述应该包含:这个工具做什么、什么情况下该用、什么情况下不该用、参数的含义和格式。
工具要有幂等性和超时保护。模型可能会重复调用同一个工具,工具本身要能处理重复请求。工具执行也要有超时,不能让一个卡住的工具拖垮整个请求。
4.4 上下文管理:编排层的隐形战场
多轮对话、多步推理会产生大量上下文,而模型的上下文窗口是有限的。编排层要负责上下文的裁剪和压缩。
常见做法有几种:滑动窗口(只保留最近 N 轮)、摘要压缩(把早期对话总结成一段话)、关键信息提取(只保留实体和结论)。我实测下来,摘要压缩 + 关键信息提取的组合效果最好,但实现也最复杂。
这里有个反直觉的经验:不是上下文越长效果越好。太长的上下文会让模型注意力分散,反而降低回答质量,还增加成本。我一般会把上下文控制在模型窗口的 50% 到 70% 之间,留出空间给检索结果和工具返回。
5. 数据与知识层:RAG 的成败 90% 在数据治理
5.1 向量检索不是银弹
RAG(检索增强生成)现在几乎是企业 LLM 的标配。但很多人对它的理解停留在"把文档切块、embedding、存向量库、检索 top_k"这个层面,结果做出来的效果很差,然后得出结论"RAG 没用"。
问题不在 RAG,在于数据治理没做好。企业文档的实际情况是:格式混乱(Word、PDF、Excel、PPT、扫描件)、结构不一(有的有标题层级,有的是纯文本)、内容重复(同一份文档多个版本)、时效性差(三年前的制度还在库里)。这些脏数据直接切块入库,检索出来的东西自然不靠谱。
5.2 文档处理管道的四个关键环节
一个靠谱的文档处理管道,至少要经过四个环节:
解析:把各种格式转成纯文本,同时保留结构信息(标题、段落、表格)。PDF 解析是重灾区,扫描件要 OCR,复杂排版要版面分析。这块没有银弹,只能针对企业实际文档类型逐个攻克。
清洗:去掉页眉页脚、水印、乱码、重复内容。这一步很枯燥但极其重要,脏数据会污染整个检索结果。
切块:不是简单地按字数切。好的切块要按语义边界切,比如按标题层级、按段落。块的大小也要权衡:太小则信息不完整,太大则检索精度下降。我一般把块控制在 300 到 800 字之间,并且保留一定的重叠(overlap)来避免边界信息丢失。
元数据标注:给每个块打上来源、部门、时间、权限等标签。这些元数据在检索时可以用来过滤,比如"只检索用户有权限的部门文档""只检索最近一年的内容"。
5.3 混合检索:向量 + 关键词
纯向量检索有个明显短板:对精确匹配不敏感。用户问"XX-2024-001 号文件的第三条",向量检索可能找不相关的内容,因为它不理解这种精确的编号。
解决办法是混合检索:向量检索负责语义相似,关键词检索(BM25 之类)负责精确匹配,两路结果融合后重排。融合算法可以用 RRF(Reciprocal Rank Fusion),简单有效。
def hybrid_search(query, top_k=10): vector_results = vector_store.search(query, top_k=top_k) keyword_results = bm25_index.search(query, top_k=top_k) # RRF 融合 scores = {} for rank, doc in enumerate(vector_results): scores[doc.id] = scores.get(doc.id, 0) + 1 / (60 + rank) for rank, doc in enumerate(keyword_results): scores[doc.id] = scores.get(doc.id, 0) + 1 / (60 + rank) return sorted(scores.items(), key=lambda x: -x[1])[:top_k]5.4 重排:把好钢用在刀刃上
检索出来的 top_k 结果,顺序未必对。这时候用一个重排模型(Reranker)对结果重新排序,能显著提升最终效果。重排模型比 embedding 模型慢,但比大模型快得多,性价比很高。
我的做法是:检索阶段召回多一点(比如 20 个),重排阶段精选少一点(比如 5 个),最后喂给大模型。这样既保证了召回率,又控制了上下文长度。
5.5 数据更新:别让知识库变成"历史博物馆"
企业知识是不断更新的。制度改了、产品迭代了、价格调整了,知识库必须跟着更新。但很多团队的知识库是"一次性"的,建完就不管了,半年后里面的内容全过期了。
数据更新要解决两个问题:怎么知道要更新和怎么更新。前者可以靠文档管理系统的变更通知,或者定期全量扫描对比。后者要支持增量更新——新增文档入库、修改文档重新切块、删除文档清理索引。
这里有个坑:向量库的删除和更新往往比插入慢。如果更新频繁,要考虑用支持高效更新的向量库,或者用"版本化"的方式,新版本入库、旧版本标记失效,定期清理。
6. 评测与观测:没有度量就没有优化
6.1 为什么评测是企业级的门槛
个人玩 LLM,效果好不好靠"感觉"。企业级不行,因为你要对效果负责,要能回答"这版比上版好在哪里""为什么这个用户投诉了"。
评测体系要解决三个层次的问题:单点评测(某个 prompt 改动的效果)、链路评测(整个 RAG 或 Agent 流程的效果)、线上评测(真实用户场景的效果)。三个层次缺一不可。
6.2 构建评测集的实操方法
评测集不是随便找几个问题就行。好的评测集要满足:覆盖真实场景、有标准答案、有难度梯度。
我的做法是:从线上真实请求里采样,人工标注标准答案,按业务场景和难度分类。初期每个场景 20 到 50 条就够用,随着系统迭代逐步扩充。关键是评测集要冻结,不能因为某次评测结果不好就偷偷改评测集,那就失去意义了。
评测指标要分场景选。问答类看准确率和召回率,生成类看人工评分或 LLM-as-Judge,工具调用类看调用成功率。LLM-as-Judge 现在很流行,但要注意它本身也有偏差,最好和人工评分做校准。
6.3 全链路追踪:出问题能定位到具体环节
线上出问题时,最怕的是"不知道哪一步错了"。全链路追踪要记录每一次请求的完整链路:用户输入、编排决策、检索结果、模型调用、工具执行、最终输出,每一步的耗时和中间结果都要留痕。
技术上可以用 OpenTelemetry 这类标准方案,也可以用简单的日志表。关键是trace_id 要贯穿全链路,从入口到出口能串起来。我一般会在请求入口生成一个 trace_id,透传到每一层,所有日志都带上这个 id。
6.4 线上监控的几个关键指标
除了常规的 QPS、延迟、错误率,LLM 系统还要盯几个特有指标:
| 指标 | 含义 | 异常信号 |
|---|---|---|
| Token 消耗 | 每次调用的输入输出 token 数 | 突然飙升可能是 prompt 膨胀或死循环 |
| 检索命中率 | 检索结果被模型实际引用的比例 | 偏低说明检索质量差 |
| 工具调用成功率 | 工具执行成功比例 | 下降说明工具或依赖出问题 |
| 拒答率 | 模型拒绝回答的比例 | 突然升高可能是 prompt 或安全策略问题 |
| 用户反馈率 | 点赞点踩的比例 | 是效果的最直接信号 |
这些指标要配告警。比如 token 消耗超过阈值、错误率超过 5%、延迟 P99 超过 10 秒,都要触发告警。
7. 安全与权限:合规是底线不是上限
7.1 数据不出域:企业最硬的约束
很多企业(尤其是金融、医疗、政务)有硬性要求:数据不能出企业内网。这意味着不能用公有云的模型 API,必须私有化部署。私有化部署的代价是:模型能力可能不如云端最强模型、需要自己维护 GPU 集群、运维成本高。
如果确实要用云端模型,那就要做数据脱敏:把敏感信息(姓名、身份证、手机号、金额)在发送前替换成占位符,收到结果后再还原。但脱敏本身有风险,替换和还原的逻辑要非常严谨,否则会出错。
7.2 权限控制:用户只能看到他能看的
RAG 场景下,权限控制尤其重要。用户 A 不能通过提问获取到用户 B 或别的部门的数据。做法是在检索阶段就做权限过滤——每个文档块带权限标签,检索时只返回当前用户有权限的块。
这里有个坑:权限过滤要在检索前做,不能检索后再过滤。因为检索后再过滤,会导致返回结果数量不足,而且可能泄露"存在但无权访问"的信息。正确做法是把权限条件作为检索的硬性过滤条件。
7.3 输出审核:模型可能"口无遮拦"
模型输出可能包含敏感信息、不当言论、或者幻觉编造的内容。企业级系统必须有输出审核环节。审核可以是规则(关键词黑名单)、模型(用另一个模型判断)、或者两者结合。
审核的难点是平衡安全和体验。审核太严,正常问题也被拦,用户体验差;审核太松,风险内容漏出去。我的经验是分级处理:高风险内容直接拦截,中风险内容加提示,低风险内容放行。分级规则要根据业务场景调整。
7.4 审计日志:出了问题能追溯
企业级系统要能回答"谁在什么时候问了什么、系统回答了什么"。审计日志要完整记录请求和响应,并且不可篡改。日志本身也要做权限控制,不是谁都能看。
审计日志的存储要考虑成本和合规要求。一般热数据存几个月,冷数据归档。归档的数据要能按需检索,以备合规检查。
8. 落地节奏:别想一口吃成胖子
8.1 从最小可用闭环开始
我见过太多团队,一上来就想做一个"全能 LLM 平台",结果做了半年还没上线。正确的做法是先做一个最小可用闭环:选一个具体的业务场景,把从输入到输出的完整链路跑通,哪怕只有最基础的直连模型,先上线,拿到真实反馈。
这个最小闭环要包含:一个真实场景、一套基础评测、基本的日志记录。有了这个,你才能知道下一步该优化什么。没有真实反馈的优化都是瞎猜。
8.2 迭代的优先级排序
拿到真实反馈后,优化要有优先级。我的排序原则是:先解决"错得离谱"的问题,再解决"不够好"的问题。
比如检索完全找不到相关内容,这是"错得离谱",优先解决;回答风格不够正式,这是"不够好",可以往后放。很多团队把精力花在调 prompt 让回答更漂亮,却忽略了检索质量这个根本问题,本末倒置。
8.3 团队配置的现实建议
企业级 LLM 项目需要的能力包括:后端工程、数据处理、算法调优、运维。小团队不可能每个方向都配专人,但至少要有人能覆盖:一个人负责工程架构和稳定性,一个人负责数据和评测。算法调优可以后期再补,因为前期主要是工程问题,不是算法问题。
我特别想强调评测这个角色。很多团队没有专人做评测,导致优化全靠感觉。哪怕只有半个人力,也要把评测体系建起来,这是企业级和玩票的分水岭。
8.4 一个真实的踩坑教训
最后分享一个我踩过的坑。早期做 RAG 时,我们花大力气优化了 embedding 模型和检索算法,效果提升有限。后来发现真正的问题是文档切块——我们按固定字数切,把很多完整的语义单元切碎了。改成按标题和段落切之后,效果直接上了一个台阶。
这个教训是:在 LLM 系统里,数据质量的重要性往往高于算法。与其花时间调模型参数,不如先把数据管道做扎实。这个道理听起来简单,但真正做的时候,人总是倾向于去调那些"看起来更高级"的东西。
企业级 LLM 这条路,技术只是其中一部分,更多的是工程判断和取舍。下一篇我会具体讲编排层的实现细节,包括工作流引擎怎么选、Agent 的边界怎么定、以及多模型路由的实战策略。