ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

图解AI应用架构设计:从模型接入到可观测层的六层工程实践

图解AI应用架构设计:从模型接入到可观测层的六层工程实践

1. 为什么现在聊AI应用架构设计正当时

过去一年半,我参与过三个从零到一的AI应用项目,也接手过两个“Demo很惊艳、上线就崩盘”的烂摊子。踩完这些坑之后,我越来越确信一件事:AI应用架构设计和传统后端架构设计,根本就是两套思维。传统架构里,你关心的是数据库连接池、缓存命中率、服务拆分粒度;而在AI应用里,你首先要面对的是不确定性——模型的输出不确定、延迟不确定、成本不确定,甚至连用户会怎么用你的产品都不确定。

这就是“图解AI应用架构设计”这个主题的价值所在。它不是教你画一张漂亮的架构图去汇报,而是帮你建立一套能扛住真实流量、能控制成本、能快速迭代的工程化思维。我见过太多团队把LLM当成一个普通的RPC接口来调,结果上线第一天就被并发打爆,或者月底看到账单直接傻眼。

这篇文章适合三类人:第一类是有后端基础但刚接触AI应用的工程师,你需要知道哪些传统经验可以复用、哪些必须推倒重来;第二类是正在做AI产品落地的技术负责人,你要在架构层面做取舍,而不是等出了问题再打补丁;第三类是对Agent、MCP这些概念还比较模糊的开发者,我会用实际项目中的例子把这些东西讲清楚。

整篇内容我会围绕一张我反复打磨过的AI应用分层架构图来展开,从最底层的模型接入层,到中间的编排层、记忆层、工具层,再到最上面的应用层和可观测层。每一层我都会讲清楚:它解决什么问题、常见方案有哪些、我实际用下来哪个更稳、以及最容易踩的坑在哪里。

2. 一张图看懂AI应用的分层架构

2.1 从“调API”到“做架构”的认知升级

很多人对AI应用的理解还停留在“前端发个请求,后端调一下OpenAI的接口,把结果返回去”。这种模式在Demo阶段没问题,但一旦要上生产,问题就会像多米诺骨牌一样倒下来。

我画过一张对比图,左边是“玩具架构”,右边是“生产架构”。玩具架构就是一条直线:用户输入 → 拼接Prompt → 调用LLM → 返回结果。生产架构则是一个多层协作系统,每一层都有明确的职责边界。

为什么需要分层?因为AI应用的本质是用不确定的组件构建确定的系统。LLM本身是不确定的,但你的产品体验必须是确定的。分层就是为了把不确定性“关进笼子里”,让每一层只处理自己该处理的问题。

2.2 六层架构的职责划分

我总结的AI应用架构分为六层,从下往上依次是:

模型接入层:负责和各家LLM打交道,包括OpenAI、Claude、通义千问、本地部署的Llama等。这一层的核心任务是统一接口、故障转移、成本控制。你不能让业务代码直接依赖某一家SDK,否则换模型的时候你会想哭。

编排层:这是AI应用的大脑,负责决定“什么时候调模型、调哪个模型、传什么参数、拿到结果后怎么处理”。Agent、Workflow、Chain这些概念都发生在这一层。编排层做得好不好,直接决定了你的应用是“智能”还是“智障”。

记忆层:包括短期记忆(对话历史)和长期记忆(向量数据库、知识图谱)。没有记忆层的AI应用,每次对话都是“初次见面”,用户体验极差。

工具层:让LLM能够调用外部能力,比如查数据库、调API、执行代码。MCP协议就是这一层最近最火的话题,它试图标准化“模型怎么调用工具”这件事。

应用层:面向用户的界面和业务逻辑,包括Web、App、API等。这一层要处理的是流式输出、多轮对话管理、用户反馈收集等。

可观测层:贯穿所有层的监控、日志、追踪、评估体系。没有可观测层的AI应用,就像在黑暗中开车——你根本不知道下一秒会发生什么。

2.3 为什么是这六层而不是别的分法

市面上有各种分层方案,有三层的、有五层的、有七层的。我选择这六层,是因为它对应了六个必须独立解决的问题域。

模型接入层解决“用哪个模型”的问题;编排层解决“怎么用模型”的问题;记忆层解决“记住什么”的问题;工具层解决“能做什么”的问题;应用层解决“怎么呈现”的问题;可观测层解决“出了什么事”的问题。

这六个问题域之间的边界非常清晰,每一层都可以独立演进。比如你想从GPT-4切换到Claude,只需要改模型接入层;你想从简单的Prompt编排升级到Agent编排,只需要改编排层。这种可替换性是架构设计的核心价值。

3. 模型接入层:别让业务代码绑死在任何一家模型上

3.1 统一接口设计的三个关键决策

模型接入层最容易犯的错误,就是让业务代码直接调用某家厂商的SDK。我接手过一个项目,业务代码里到处都是openai.ChatCompletion.create(),后来因为成本原因要切换到国产模型,改了几百个地方,差点把团队逼疯。

正确的做法是定义一个统一的模型接口,所有业务代码只依赖这个接口。这个接口至少需要包含三个方法:chat()用于对话、embed()用于向量化、count_tokens()用于计算token数。

设计这个接口时有三个关键决策。第一,输入输出格式要统一。不同厂商的消息格式不一样,有的用role/content,有的用messages数组,你需要定义一个内部标准格式,在适配器里做转换。第二,错误处理要统一。不同厂商的错误码和重试策略不同,你需要在适配器层统一成一套错误体系。第三,流式输出要统一。有的厂商返回SSE,有的返回WebSocket,你需要统一成一种流式协议。

3.2 多模型路由与故障转移的实操方案

生产环境里,我强烈建议至少接入两家模型供应商。原因很简单:任何一家都可能出故障。我经历过OpenAI大面积超时、Claude突然限流、国产模型接口变更等各种情况,如果没有备用方案,你的应用就是单点故障。

多模型路由的策略有三种。优先级路由:主模型失败时自动切换到备用模型,适合对一致性要求不高的场景。成本路由:简单问题用便宜模型,复杂问题用贵模型,适合成本敏感的场景。能力路由:根据任务类型选择模型,比如代码生成用Claude、创意写作用GPT-4。

故障转移的实现要点是超时控制和熔断机制。我一般设置首token超时5秒、总超时30秒,连续失败3次就熔断该模型5分钟。这些参数需要根据你的业务场景调整,但核心原则是:宁可快速失败,也不要让用户干等。

3.3 成本控制的五个实战技巧

LLM的成本可以很吓人。我见过一个项目,因为没做token控制,一个月烧了十几万。后来我们做了几件事,成本直接降了70%。

第一,Prompt压缩。把冗余的system prompt精简,去掉重复的few-shot示例。第二,缓存命中。相同或相似的请求直接返回缓存结果,尤其是那些高频的FAQ类问题。第三,模型降级。简单任务用便宜模型,我实测下来,很多分类任务用7B模型和用GPT-4的效果差距不到5%。第四,输出长度限制。设置max_tokens,防止模型“话痨”。第五,批量处理。把多个小请求合并成一个大请求,减少调用次数。

注意:成本控制不能牺牲用户体验。我见过为了省钱把max_tokens设成50,结果模型话说到一半就断了,用户直接投诉。省钱的前提是保证核心体验。

4. 编排层:Agent和Workflow到底怎么选

4.1 Agent与Workflow的本质区别

这是被问得最多的问题之一。我的理解是:Workflow是确定性的流程编排,Agent是不确定性的自主决策。

Workflow就像工厂流水线,每一步都是预先定义好的:先做A,再做B,如果C条件满足就做D。Agent则像一个员工,你给他一个目标,他自己决定怎么做、用什么工具、做几步。

那什么时候用Workflow,什么时候用Agent?我的经验是:流程固定、步骤明确的用Workflow;需要灵活决策、步骤不确定的用Agent。比如“根据用户问题查知识库并回答”这种,Workflow就够了;“帮用户规划一个旅行行程并预订”这种,就需要Agent。

很多人一上来就想做Agent,觉得Agent更“智能”。但实际上,Workflow的稳定性和可预测性在生产环境里更值钱。我现在的做法是:能用Workflow解决的,绝不用Agent;只有Workflow确实覆盖不了的场景,才上Agent。

4.2 Agent架构的核心组件拆解

一个完整的Agent架构包含四个核心组件:规划器、执行器、工具集、记忆。

规划器负责把大目标拆解成小步骤。常见方案有ReAct、Plan-and-Execute、Tree-of-Thought等。我实测下来,ReAct适合简单任务,Plan-and-Execute适合复杂任务,Tree-of-Thought适合需要探索的任务。

执行器负责调用工具并处理结果。这里的关键是错误处理——工具调用失败时,Agent应该能感知到并尝试其他方案,而不是直接崩溃。

工具集就是Agent能用的“武器”。工具的设计要遵循单一职责原则,一个工具只做一件事,描述要清晰,参数要明确。

记忆负责保存上下文。短期记忆就是对话历史,长期记忆需要向量数据库支持。

4.3 编排层的性能优化与并发处理

Agent应用怎么扛并发?这是很多人的痛点。我的经验是:Agent的并发瓶颈不在LLM调用,而在编排逻辑本身。

一个Agent请求可能包含多次LLM调用和工具调用,如果串行执行,延迟会非常高。优化的核心思路是并行化和异步化。

并行化:把没有依赖关系的步骤并行执行。比如Agent需要查三个数据源,这三个查询可以同时发起。

异步化:把耗时的操作放到后台队列,先返回一个“处理中”的状态,处理完再通知用户。这种方式适合那些不需要实时响应的场景。

还有一个技巧是预计算。对于高频的Agent请求,可以预先计算好部分结果,请求来了直接组装。我做过一个客服Agent,把常见问题的处理路径预计算好,响应时间从8秒降到了1.5秒。

5. 记忆层与工具层:让AI真正“记得住”和“做得了”

5.1 短期记忆与长期记忆的配合策略

没有记忆的AI应用,就像金鱼——每次对话都是全新的。记忆层要解决的核心问题是:在合适的时机,把合适的信息,以合适的形式,喂给模型。

短期记忆就是当前会话的上下文。这里的关键是上下文窗口管理。模型的上下文窗口有限,你不能把所有历史都塞进去。我的做法是:保留最近N轮对话的完整内容,更早的对话做摘要压缩。

长期记忆需要向量数据库支持。把历史对话、文档、知识库都向量化存储,需要的时候做相似度检索。这里有个坑:向量检索的召回率不等于准确率。我见过检索出来一堆相关但不有用的内容,反而干扰了模型。解决方案是加一层重排序,用交叉编码器对检索结果做精排。

5.2 MCP协议:工具调用的标准化尝试

MCP(Model Context Protocol)是最近很火的话题。简单说,它试图定义一套标准协议,让模型能够以统一的方式调用各种工具和数据源。

为什么需要MCP?因为现在工具调用的方式太乱了。每个框架都有自己的工具定义格式,换个框架就要重写一遍。MCP的目标就是一次定义,到处调用。

MCP的核心概念是Server和Client。Server暴露工具和数据,Client负责连接和调用。模型通过MCP Client发现可用的工具,然后决定调用哪个。

我实际用下来的感受是:MCP的理念很好,但生态还在早期。目前支持MCP的工具还不够多,而且不同实现的兼容性也有待验证。不过对于新项目,我建议按照MCP的思路来设计工具层,即使现在不用MCP,未来迁移也会容易很多。

5.3 工具设计中的常见陷阱

工具设计有几个容易踩的坑。第一个坑是工具描述太模糊。模型是根据描述来决定是否调用工具的,如果描述不清楚,模型要么不调用,要么乱调用。我的经验是:工具描述要包含“什么时候用”和“什么时候不用”。

第二个坑是参数设计太复杂。模型生成复杂参数的成功率很低。尽量用简单的参数类型,避免嵌套结构。

第三个坑是工具粒度不对。太粗的工具模型不会用,太细的工具模型用不好。我一般按照“一个工具完成一个完整动作”的原则来设计。

第四个坑是没有错误处理。工具调用失败时,要返回清晰的错误信息,让模型知道发生了什么、可以怎么补救。

6. 可观测层:AI应用上线后怎么知道它“好不好”

6.1 传统监控在AI应用中的局限性

传统的APM工具监控的是响应时间、错误率、吞吐量这些指标。这些指标在AI应用里依然重要,但远远不够。

AI应用需要监控的是:模型输出的质量。一个请求返回了200,响应时间500ms,从传统监控看一切正常,但模型可能返回了一堆胡说八道。这种问题传统监控发现不了。

所以AI应用的可观测层需要增加质量评估维度。包括:输出相关性、事实准确性、有害内容检测、用户反馈等。

6.2 LLM as Judge:用模型评估模型

评估模型输出质量的一个实用方案是LLM as Judge——用一个模型来评估另一个模型的输出。

具体做法是:定义一个评估Prompt,包含评估标准(比如相关性、准确性、完整性),让Judge模型给输出打分。这个方案的好处是可扩展,你可以评估任意维度的质量。

但LLM as Judge也有局限。Judge模型本身可能有偏见,比如倾向于给长回答打高分。评估成本不低,每次评估都要调一次模型。一致性难以保证,同一个输出评估两次可能得到不同分数。

我的做法是:LLM as Judge用于粗筛,把明显有问题的输出挑出来;关键场景再用人工评估做精筛。两者结合,既保证覆盖率又保证准确性。

6.3 全链路追踪的落地实践

AI应用的全链路追踪比传统应用复杂得多。一个请求可能经过:用户输入 → Prompt组装 → 模型调用 → 工具调用 → 结果后处理 → 返回用户。每一步都可能出问题。

我一般用Trace ID贯穿整个链路,每个环节都记录输入输出和耗时。这样出问题时可以快速定位是哪一步出了问题。

追踪数据要包含几个关键信息:模型版本(不同版本行为可能不同)、Prompt内容(方便复现问题)、token消耗(成本分析)、工具调用记录(排查工具问题)。

实操心得:追踪数据不要只存日志,要存到可查询的数据库里。我见过把追踪数据打到日志文件里,出问题时用grep查,效率极低。用Elasticsearch或者ClickHouse存追踪数据,查询效率会高很多。

7. 常见问题与排查技巧实录

7.1 模型输出不稳定的排查思路

模型输出不稳定是最常见的问题。同样的输入,有时候回答很好,有时候答非所问。排查思路是从外到内逐层排除。

先检查温度参数。温度越高输出越随机,生产环境一般建议温度设在0.1到0.3之间。再检查Prompt是否稳定。如果Prompt里有动态内容(比如时间戳),可能导致输出波动。然后检查模型版本。有些厂商会静默更新模型,行为可能发生变化。最后检查上下文长度。上下文太长时,模型可能“忘记”前面的内容。

7.2 工具调用失败的常见原因

工具调用失败的原因五花八门,我整理了一个速查表:

问题现象可能原因解决方案
模型不调用工具工具描述不清晰优化描述,明确使用场景
调用参数错误参数定义太复杂简化参数结构,增加示例
工具超时工具执行太慢增加超时时间,优化工具实现
结果解析失败返回格式不标准统一返回格式,增加容错
循环调用模型陷入死循环设置最大调用次数限制

7.3 并发场景下的典型故障

Agent应用扛并发是个技术活。我遇到过几个典型故障。

故障一:连接池耗尽。LLM调用是长连接,并发高时连接池很快耗尽。解决方案是异步调用加连接复用。

故障二:内存暴涨。每个请求都保存完整的对话历史,并发高时内存直接爆掉。解决方案是限制历史长度,或者把历史存到外部存储。

故障三:成本失控。并发高时token消耗呈指数增长。解决方案是限流加预算控制,超过预算自动降级。

故障四:级联失败。一个工具挂了导致整个Agent链路崩溃。解决方案是熔断加降级,工具不可用时Agent应该能感知到并尝试其他方案。

7.4 我踩过的三个印象最深的坑

第一个坑:把Agent当Workflow用。早期我做一个客服系统,用Agent架构,结果发现Agent经常“自作主张”,该查知识库的时候去调别的工具。后来改成Workflow,稳定性大幅提升。教训是:不要为了用Agent而用Agent。

第二个坑:忽略Prompt的版本管理。Prompt改了之后没有记录,出问题回滚都不知道回滚到哪个版本。后来我们建立了Prompt版本管理机制,每次修改都记录变更内容和效果对比。

第三个坑:没有做输出过滤。模型有时候会输出一些不合适的内容,上线后被用户投诉。后来加了输出过滤层,对敏感内容做检测和拦截。

8. 从架构图到落地:我的实操建议

8.1 小团队如何快速搭建AI应用架构

小团队资源有限,不可能把六层都做得很完善。我的建议是先做最小可用架构,再逐步完善。

最小可用架构包含:模型接入层(统一接口+一家模型)、编排层(Workflow为主)、应用层(Web界面)。记忆层可以先用简单的对话历史,工具层先接一两个核心工具,可观测层先用日志。

等业务跑起来之后,再根据实际痛点逐步完善。比如发现成本太高,就加多模型路由;发现用户抱怨“记不住”,就加长期记忆;发现输出质量不稳定,就加评估体系。

8.2 技术选型的取舍原则

AI应用的技术选型变化很快,今天火的框架明天可能就没人维护了。我的选型原则是:优先选生态好的、优先选可替换的、优先选团队熟悉的。

生态好意味着遇到问题容易找到解决方案。可替换意味着不会被某个框架绑死。团队熟悉意味着上手快、维护成本低。

具体到框架选型,LangChain生态最全但比较重,LlamaIndex专注RAG场景,Dify适合快速搭建。我的建议是:先用Dify这类低代码平台验证想法,验证通过后再用代码重构。

8.3 架构演进路线图

AI应用架构不是一步到位的,我一般分三个阶段演进。

第一阶段:验证期。目标是快速验证产品想法。架构尽量简单,用现成的平台和工具,重点是把核心流程跑通。

第二阶段:优化期。目标是提升稳定性和用户体验。开始做分层架构,加缓存、加重试、加监控,把明显的性能瓶颈解决掉。

第三阶段:规模化期。目标是支撑大规模用户。做多模型路由、做成本控制、做全链路追踪,把架构的每个环节都打磨到生产级别。

每个阶段的重点不同,不要在第一阶段就做第三阶段的事。我见过太多团队在验证期就花大量时间做架构,结果产品方向变了,架构白做了。

8.4 关于AI应用架构,我最后想说的

做了这么多AI应用项目,我最大的体会是:架构设计的目标不是“先进”,而是“合适”。不要因为Agent火就上Agent,不要因为MCP新就用MCP。每个技术选择都要回答一个问题:它解决了我的什么实际问题?

另外,AI应用架构和传统架构最大的区别是变化快。模型在变、工具在变、用户需求也在变。所以架构要留好扩展点,让变化发生的时候,你只需要改一小部分,而不是推倒重来。

最后分享一个我常用的判断标准:如果你能用一张图把你的AI应用架构画清楚,并且每个模块的职责和边界都很明确,那这个架构基本就是靠谱的。如果画不清楚,或者模块之间职责重叠,那说明架构还需要调整。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进