从去年开始,我算是亲眼看着LLM应用开发从“调API的玩具脚本”慢慢长成了正经的软件工程。最开始大家写一个问答机器人,无非是拿OpenAI的接口封装一层,prompt里塞点背景,能聊就行。可一旦要做到知识库问答、多工具调用、带记忆的Agent,代码规模瞬间膨胀,逻辑散落在各处,改一处崩三处。
后来我把整套项目按分层思路重新拆了一遍,才发现LLM应用真的和传统后端分层异曲同工。无论你是刚接触AIGC的入门者,还是已经在写Agent的老手,脑子里有没有一张“架构地图”,决定了你的项目能走多远。这篇文章我把自己的实践和盘托出,围绕LLM应用开发五层架构逐个展开,顺带整理我真实用过的工具箱。不吹不黑,全部是踩过坑之后留下的。
1. 先看清全局:LLM应用为什么需要“分层”思维
1.1 从单体脚本到分层架构的演进
刚接触LLM开发的人最常见的状态是:一个main.py文件走天下。读用户输入、拼prompt、调模型、解析输出,最后返回给前端,全部堆在一个文件里。如果只是做个demo,这种方式完全没问题,毕竟五分钟就能跑通。
但业务场景一复杂,问题就出来了。以最简单的知识库问答为例,你至少要做文档加载、文本切分、向量化、存储、检索、重排、提示词构造、模型调用、引用溯源、会话管理。这些东西全部绞在一起,其实是把“数据层”“模型层”“编排层”混为一谈了。你今天想换一个向量库,要改数据库连接、改数据同步、改检索逻辑、改返回格式,牵一发动全身。
我自己的转折点是在做一个模拟项目X的客服助手时——需求不断叠加,代码从几百行膨胀到几千行,调试一个上下文丢失的问题,查了两天才发现根源不在模型,而在记忆模块的状态维护。那一刻我意识到,LLM应用开发要先解决复杂度的组织问题,再谈智能化。
1.2 五层架构速览:一句话讲清每一层
我把自己的项目反复整理后,最终沉淀出一套实用的五层架构。它不是某本教科书上的标准定义,而是从大量实践里长出来的通用骨架:
| 层级 | 核心职责 | 一句话总结 |
|---|---|---|
| 第一层 交互层 | 用户界面、输入输出、渠道适配 | 让用户能“用起来” |
| 第二层 编排层 | Agent逻辑、工作流、提示词管理、任务规划 | 决定模型“干什么、怎么干” |
| 第三层 模型层 | 模型选型、多模型路由、推理参数、微调接入 | 决定“由谁思考” |
| 第四层 数据层 | RAG检索、向量库、记忆、知识库、缓存 | 给模型“喂什么” |
| 第五层 支撑层 | 评测、监控、安全、成本治理 | 让应用“跑得稳” |
这五层不是物理隔离的微服务概念,而是逻辑分层。也就是说,你写代码时不必拆成五个独立服务,但头脑里必须清楚:这段逻辑属于哪一层?它的依赖方向是什么?上层能否直接绕过下层去访问数据?
这个分层方法最大的好处是“替换友好”。数据层的向量库从Chroma换成Milvus,代码改动被限制在数据层内部;模型层从A模型切到B模型,只要接口协议不变,编排层可以完全不动。对我来说,分层思维带来的效率提升,远大于任何单一工具。
2. 逐层拆解:从交互到基础设施到底在做什么
2.1 第一层 交互层:别把界面当作附属品
很多做LLM应用的人天然轻视交互层,觉得“反正核心是模型,前端随便写写就行”。这个观念我建议尽早纠正。交互层是用户与模型能力的触点,它直接决定了用户对你产品的第一印象。
交互层不只是聊天窗口。它包含的内容很杂:Web页面、小程序、钉钉/飞书/企微机器人、命令行CLI、语音助手,甚至可以把LLM能力嵌入到传统的表单系统里。每一种渠道都有不同的交互范式,背后对应的是不同的消息解析和响应格式处理。
这个层级的核心技术点有三个:
- 流式输出:LLM推理耗时长,如果不做SSE流式返回,用户干等几秒到几十秒,体感非常差。流式输出的难点在于中间态的处理——用户看到一半输出就想点“停止”,前后端协议要做好配合。
- 会话上下文管理:用户刷新页面、切走再回来,对话历史能不能恢复?这牵扯到session的存储和后端接口设计,很多团队是在这层把多轮对话能力初步做上去的。
- 交互友好性:比如引用标注、思维链可视化、token消耗展示。这些虽然不影响模型能力,但对用户建立信任感很有帮助。
我在做客服助手时,光是用户消息的“多模态输入”就折腾了很久。用户发来一张截图,里面有问题文字,系统要先调用视觉模型识别,再进入文本问答流程。这在交互层就要做好消息类型的分流。
提示:不要把交互层的状态管理想得太简单。尤其是流式输出和“用户关闭页面后重新进入”的场景,状态恢复方案要在设计阶段预留,否则后期补会非常痛苦。
2.2 第二层 编排层:提示词、工作流与Agent的核心地带
如果说交互层是“皮肤”,编排层就是LLM应用的“大脑中枢”。它可以简单到一句话:把用户请求拼接成prompt发给模型;也可以复杂到:让模型自主规划任务、调用多个工具、根据结果自我修正。
编排层最核心的组件是提示词管理和工具调用协议。
提示词管理不是把prompt写在代码字符串里这么简单。我见过太多项目,prompt散落在各种文件里,改一个语气描述要全局搜索替换。规范做法是把prompt模板化管理——按场景拆分system prompt、user prompt、few-shot示例,存成独立配置,甚至做版本管理。每次改动prompt,都要对应一个可回溯的版本号,这样才能评估改动对效果的影响。
工具调用是编排层的另一个重头戏。当Agent需要查询数据库、调用计算器、访问外部API时,模型本身不具备这些能力,只能通过Function Call或Tool Use机制来间接完成。编排层要做的,是把工具清单和参数描述传给模型,模型决定调用哪个工具,编排层再执行该工具、把结果回传给模型继续生成。
这里有个经常被忽略的细节:工具描述本身就是一种“提示词”,它的质量直接影响模型的选择准确率。好的工具描述要包含功能说明、适用场景、参数含义和典型示例。我自己调试过的一个案例——一个库存查询工具,描述写得太泛,结果模型老是让用户去查“所有商品”,却忽略了用户输入的筛选条件。把工具描述改精确,准确率立竿见影。
再往上,就是复杂Agent的编排:思维链分解任务、子任务派发、结果合并、多轮反思修正。这个方向能力上限很高,但复杂度也成指数级上升。我的建议是:新手不要一上来就冲Complex Agent,先把“单工具调用-多工具协作-自主规划”这条路一步步走通,再把复杂度加上去。
2.3 第三层 模型层:选型、路由与推理参数
模型层是整个架构里最容易被“玄学化”的一层,但落到实处,无非是三个决策:选哪个模型、怎么控制推理参数、不同场景怎么分配模型资源。
模型选型的关键不是“哪个最强”,而是“哪个最合适”。强模型往往意味着高成本和高延迟,如果一个小任务非要上最强的旗舰模型,经济账完全算不过来。我常用的策略是任务分级:简单分类、信息抽取任务用轻量模型;复杂推理、创意生成用旗舰模型;极端敏感的场景再考虑私有化部署的开源模型。
多模型路由是模型层的进阶玩法。比如设置一个路由器,先让轻量模型判断任务类型,然后动态转发给对应的模型。这个过程听起来高大上,实际上核心就是“分类 + 转发”。路由判断既要看意图分类,也可以结合用户输入的关键词、上下文长度、甚至成本预算来做综合决策。
推理参数的控制也值得认真对待。temperature、top_p、max_tokens、presence_penalty、frequency_penalty,每一个参数都有明确的行为含义:temperature控制随机性,越高越有发散性;top_p控制候选集累积概率;presence_penalty抑制重复内容。很多人调参靠感觉,我建议先搞懂参数的数学含义,再结合任务场景设定基线,最后用评测数据来迭代。
模型层还包含一个隐性任务:统一接口和降级处理。由于模型服务会有限流、超时、间歇性不可用,模型层要设计好重试机制、熔断降级和备用模型切换。这些工程细节在demo里可以不管,但在生产环境里就是保命绳。
2.4 第四层 数据层:RAG、向量库与记忆
数据层是我投入精力最多的一层,也是决定LLM应用是否能“专业”的关键。LLM自己的知识有截止日期,无法覆盖私有业务数据,而数据层就是解决“信息如何进入模型决策链”的问题。
RAG是目前最主流的技术方案。它的核心思想——并不把所有知识塞进模型,而是在回答前先检索相关信息,然后拼接进prompt让模型参考。这个“先检索再生成”的流程,把知识更新成本从“重新训练模型”降到了“更新知识库索引”,工程上要可控得多。
RAG的技术链条不短:文档导入 -> 文本切分 -> 向量化(Embedding) -> 向量存储 -> 检索召回 -> 重排序 -> 生成。每个环节做不好,都会直接拉低回答质量。
文本切分是最容易被低估的环节。切得太短,语义不完整;切得太长,向量检索精度下降,还容易超过上下文窗口。我的经验是:结构化文档(表格、合同)要按结构边界切,长文本按语义段落切,同时做好重叠区,确保跨段信息不丢失。
向量库的选择也是一门学问。Chroma、FAISS适合轻量场景和快速原型;Milvus、Qdrant适合大规模生产;PGVector则适合你想省去额外基础设施、直接复用PostgreSQL的场景。没有绝对好坏,关键看你的数据规模、并发要求和团队技术栈。
记忆机制其实也属于数据层。短期记忆是对话历史的管理,要处理“截断、摘要、关键信息持久化”三个问题;长期记忆则是把用户偏好、项目历史等结构化保存,需要时再注入prompt。这个模块我强烈建议单独建模,它和RAG虽然共享存储设施,但读写模式和更新策略完全不同,混在一起后期会很乱。
2.5 第五层 支撑层:评估、观测、安全与成本治理
支撑层是很多人做LLM应用时“以后再说”的部分,但它恰恰是应用能不能长期稳定运营的分水岭。小demo可以没有支撑层,稍微上点规模的应用,少了支撑层等于裸奔。
LLM应用的评测与传统软件测试完全不同。传统测试有明确的输入、预期输出和断言,而LLM的输出有大量合法变体。评测体系至少包含三个层次:单轮问答的准确性、多轮对话的一致性、下游任务的成功率。我自己维护了一套评测集,每条用例标注了“标准答案”和“评分标准”,每次改动模型、提示词或RAG链路,都跑一遍回归评测,用分数说话而不是凭感觉。
可观测性在LLM应用里的范畴也比普通后端更广。我们不仅要监控服务器指标(CPU、内存、错误率),还要追踪一次完整请求内部的链路:用户输入是什么、检索出了哪些文档、最终拼出的prompt是什么、模型返回了什么。这些日志是定位问题的第一手材料。
安全方面,最基础的是prompt注入防护——用户输入里可能包含恶意指令试图覆盖系统提示词。这类问题没有百分百的解决方案,只能做多层防御:输入侧过滤、prompt结构加固、输出侧合规检查、敏感操作二次确认。
成本治理本质上是个技术问题。LLM的cost跟token数强相关,优化方向包括:上下文压缩、语义缓存、局部任务用小模型、把频繁使用的模型响应结果固化成预计算结果。我见过最夸张的项目,就是没做语义缓存,一个月token费用翻了几十倍。
3. 实战工具箱推荐:小白到进阶的选型清单
3.1 编排框架:降低开发门槛的“脚手架”
我经常被问到一个问题:“新手学LLM应用,要不要用框架?”我的答案始终是:先徒手调几次API,感受一下完整链路,然后再用框架提速。如果一上来就套框架,你只学会了框架的API,没有建立起底层直觉。
编排框架现在有很多,我最常用的是LangChain和LlamaIndex。LangChain的生态最丰富,链式组装、工具调用、记忆模块、Agent机制都有成熟实现,但它的抽象层次很多,新手很容易迷失在各类概念中。LlamaIndex则在数据索引和RAG方向做到了很深,文档加载器、索引结构、检索策略都很完善,特别适合做知识库问答。
如果你更倾向于“少写代码、多拉配置”,Dify和Flowise这类低代码平台也很能打。它们把Agent、知识库、工作流可视化集成在一起,很适合快速验证业务想法。不过低代码平台也存在扩展受限和黑盒化的问题,长期维护要留意。
我的建议组合是:个人研究阶段用LangChain或直接徒手写;团队产品阶段自定义一套轻量编排框架,只保留自己真正需要的组件。框架是好工具,但别让它牵着走。
3.2 模型接入与网关:统一入口化解碎片化
当你同时使用多家模型服务时,模型网关就特别重要。每家厂商的接口协议略有不同,如果业务代码直接耦合,后续换模型要改动的地方太多。
我建议在模型层引入统一的调用抽象层。比如定义一个通用的chat_completion接口,输入是messages和params,输出是content和usage,内部封装各家供应商的实现。这个抽象不需要多复杂,一个客户端库加几个适配器就够,但它的价值会在模型切换时瞬间体现出来。
如果你需要更完善的功能——限流、重试、多租户配额、成本统计、模型路由策略,可以考虑直接部署开源的模型网关服务。这类中间件通常支持把OpenAI、Anthropic、国产模型等统一在一个面板下管理,运维效率高很多。
3.3 向量库与数据处理:RAG的关键地基
数据准备工具同样不可忽视。文档解析尤其要选好——PDF、Word、Excel、PPT,每种格式都有各自的解析难点。表格类文档尤其闹心,直接按文本读会丢掉二维结构,我做过测试,同样的表格数据,结构化解析后再embedding,检索准确率比普通文本解析高出一大截。
文本切分我推荐结合语义自动切分工具,不要只用固定字符数硬切。固定切分做demo没问题,但真实文档结构复杂,硬切会把语义割裂得厉害。重排序环节也很重要,初召回可能有一堆无关文档,先粗召回再精排,效果提升非常明显。
3.4 可观测与评测:给应用装上“仪表盘”
上线之后,我最依赖的是可观测工具。它们可以记录每次请求的全链路trace:prompt是什么、检索了哪些chunk、模型返回了什么、token消耗多少。没有这套系统,线上问题排查基本靠猜。
评测这块,建议尽早搭建自己的回归评测集,把典型问题、边界情况、Bad Case全部记录下来。我自己的习惯是每个项目维护一个JSON格式的评测集,字段包含:输入、标签、预期行为、评分维度。哪怕最初只有五十条用例,也比完全没有强得多。迭代时跑一遍,用对比报告看效果变化,这是对抗“prompt玄学”的最有效手段。
4. 一个真实的完整Demo:从0到1搭一个知识问答应用
4.1 需求定义和架构选型
拿一个实际做过的场景举例:给某个内部团队做一个“产品知识库问答机器人”,希望员工直接用自然语言查询产品文档、FAQ和操作手册。
需求拆解下来很简单:用户提问,系统检索知识库相关段落,模型结合检索结果生成回答,需要标引用来源。在五层架构里看,就是完整走一遍:交互层做Web页面,编排层做RAG问答流程,模型层接入主力模型,数据层建文档索引和存储,支撑层放日志与评测。
这里我没有直接用重型框架,而是保持轻量自定义。数据层用向量库做语义索引,编排层手工写一个“检索-拼接-回答”的流程,模型层统一封装调用入口。这样做的原因是项目规模不大,框架引入的额外复杂度会超过收益。
4.2 数据准备与Embedding
这一步是整个项目最花时间的环节。文档从多个来源汇集过来,有PDF手册、有网页版FAQ、还有几十篇内部实践总结。我先做了文档格式归一化,全部转成纯文本或结构化Markdown,然后再切分。
切分时我用了分层策略:每个文档先按章节拆成逻辑块,块过长的再按段落切,段落的长度在200到500字之间,重叠20到50个字。切完之后,我给每个chunk补了元数据:来源文件名、章节路径、更新时间。这些元数据在后续“引用溯源”功能里直接排上了用场。
Embedding模型我选了一个性价比高的本地向量化方案。跑通流程后我特别留意了一个问题:文档里的专业缩略词,向量检索对它们不敏感。比如用户问“订单超时怎么处理”,文档里写的是“交易流程异常”,虽然语义相关但字面差异大,初召回效果不好。后面靠扩展同义词和重排序才补救回来。
4.3 编排与模型调用
编排层我做了一个简单但稳定的流水线:
- 对用户问题做意图判断(是否与知识库相关)。
- 改写问题,生成更适合检索的查询词。
- 向量检索Top K个相关chunk。
- 用重排序模型对召回结果精排。
- 构造带引用标注的prompt。
- 调用模型生成最终回答。
其中问题改写这个步骤很关键。用户的日常提问比较口语化,直接拿原文去检索,效果往往不如改写后的结构化查询。比如“这个软件到底咋收费的”,改写为“软件收费模式、价格策略”,检索结果质量就上来了。
模型调用时,我对temperature设了0.2,保持回答稳定性;max_tokens限制在500以内,避免无意义的扩散。同时做了超时重试和备用模型降级。
4.4 交互与测试
交互层最核心的体验是流式输出。我用SSE把模型输出实时推送到前端,用户等待时间从“干等几秒”变成了“看着字蹦出来”,体感提升非常明显。引用来源做成下划线标注,用户点击就能看到原始文档片段,这个功能上线后好评率意外地高。
测试阶段暴露的问题很多。最典型的一次:文档里某段落说“支持在线支付”,另一段说“暂不支持自动扣款”,两个chunk都召回了,模型直接把两句信息拼在一起,生成了一个自相矛盾的回答。我后来在prompt里加了“请识别检索内容之间的矛盾,并以最具体的信息为准”,矛盾率降了不少,但没有完全根除。这也说明,LLM应用不能追求完美,要接受一定比例的错误,靠流程和提示词不断优化。
4.5 上线后的踩坑实录
上线初期,真金白银换来的教训主要是三个。
第一个坑是上下文爆炸。用户连续问几十个问题后,历史记录把上下文窗口占满了,新知识放不进去,回答效果断崖式下跌。后来做了“滑动窗口+历史摘要”结合的策略:完整历史放最近几轮,更早的压缩成摘要。
第二个坑是检索结果质量波动。某次修改了文档,没有重新跑embedding,导致新旧版本内容混杂,检索返回了大量过时信息。我在数据管线上加了一道“文档变更即触发增量索引”的自动化流程,才止住了这个问题。
第三个坑是评测不足导致回归。一次升级模型配置,离线看单例回答都正常,上线后才发现大量边缘case的处理变了味。原因就是没有及时跑回归评测。那次之后,我养成了每次变更都跑评测集、看对比报告的习惯。
5. 新手最容易踩的坑与避坑指南
5.1 提示词万能论的误区
新玩家最常见的迷思是“只要prompt写得好,模型什么都干得好”。说实话,prompt确实能解决很多问题,但它的能力边界是有限的。业务逻辑、工具调用、数据准确性、多轮一致性,本质上要靠架构和工程手段来保证,prompt只能做“临门一脚”。
我自己就遇到过一个案例,想靠prompt约束模型“必须从给定文档中提取答案,不许自己编”,但在没有强制引用机制的情况下,模型还是会编。最后是引入了“回答必须附引用chunk id”的要求,再在拦截层校验引用是否真实存在,才算解决。这就是典型的“越过prompt改架构”。
5.2 向量库的“幻觉”
很多人以为RAG就是“把文档扔进向量库,然后查询”,实际上向量检索本身是模糊匹配,召回结果会包含大量无关或弱相关片段。我见过有人觉得“反正模型能判断,喂多一点没关系”,结果主流模型在长上下文里对大量无关信息确实会“选择性失明”,回答被噪音带偏。
正确做法是控制好召回数量,优先保证精度。宁可少召回几段,也要保证召回的段落高度相关。对于关键业务场景,重排序环节不能省,初召回Top 50,精排后保留Top 5,效果和直接用Top 5完全不一样。
5.3 把评测当作了可选项
如果你问我:一个LLM应用项目哪个环节最容易被偷工减料?答案一定是评测。因为它不直接产出用户可见的功能,又需要持续投入。
但没有评测的迭代就是原地打转。今天改个prompt感觉效果好,明天换个模型感觉更好了,到底好在哪里?有没有引入回归问题?全凭感觉说了算。我强烈建议从第一天就开始建评测集,不用多,几十条关键场景就够起步。关键变更是先跑评测,再上生产,这个习惯能帮你躲掉一大半线上事故。
5.4 成本失控:没人告诉你token会烧得这么快
成本问题往往在项目做大后才爆发。每轮对话都携带完整历史,用户一多,token消耗呈线性甚至超线性增长。我给出的建议非常具体:实现语义缓存,把常见问题和标准回答缓存起来,命中直接返回;对话历史做动态裁剪,超过一定长度就摘要化;优先用轻量模型处理简单请求;定期分析token消耗报表,找出Top级别的消耗场景,定向优化。
6. 五层架构之外:我的工程经验与学习路径建议
6.1 分层架构的本质是管理复杂度
聊到这里,你可能会发现,所谓的LLM应用开发五层架构,本质上不是什么惊天动地的创新,它就是在说一件事——把复杂系统拆成职责清晰的模块,让每一部分都能独立演进、独立替换、独立测试。
不要觉得分层是过度设计。哪怕你只是写一个个人工具,用分层思维去组织代码,也会更清爽。我的经验是:交互层和编排层至少要在代码目录上分开;编排层和数据层的接口契约先定好;支撑层的评测从第一天就开始写。这样一来,后续迭代和新需求加入,永远是在局部做加法,而不是在泥潭里翻锅。
6.2 给新玩家的路径建议
如果你刚刚接触LLM应用开发,我建议的学习顺序是这样的:
第一步,先徒手调通一个大模型API,理解prompt和参数的含义,感受token的消耗。第二步,用Python写一个最朴素的RAG脚本:加载文档、切分、embedding、检索、拼prompt、生成答案。第三步,给脚本穿上Web交互外衣,实现流式输出。第四步,引入状态管理和记忆机制,把单轮问答升级成多轮对话。第五步,再回头看LangChain、LlamaIndex这类框架,你会发现它们的很多设计都似曾相识。
最后一句话送给大家:不要被层出不穷的模型和工具搅乱心神,模型会换代,工具会过时,但分层架构的方法论会一直在。把自己的项目当成一个工程系统去搭建,而不是一次次地拼prompt碰运气,这才是稳定产出高质量AIGC应用的真正路径。