☰
AI Agent分层交付架构:从模型接入到交互输出的四层设计实践
2026/11/3 20:26:56 网站建设 项目流程

1. 为什么“一锅炖”的 Agent 迟早会崩

我见过太多团队做 AI Agent 的方式,就是把系统提示词、工具定义、业务规则、记忆管理、输出格式约束全部塞进一个巨大的 Prompt 里,然后祈祷模型能“理解一切”。这种做法在 Demo 阶段确实能跑通,甚至效果还不错,但一旦进入真实业务场景,问题就会像多米诺骨牌一样接连倒下。

最典型的症状是:你改了一句话术,结果工具调用的准确率掉了;你加了一个新工具,结果原本稳定的输出格式开始漂移;你想给某个环节加个重试逻辑,发现根本找不到该在哪里加。整个系统像一团被猫玩过的毛线球,牵一发而动全身。

这就是我所说的“把智能糊进一锅”。它的问题不在于模型能力不够,而在于架构层面缺少分层。Agent 不是一个“更聪明的函数”,它是一个由多个职责不同的模块协同工作的系统。如果你不把这些职责拆开,你就无法独立地调试、替换、优化任何一个部分。

分层交付的核心思路其实很朴素:让每一层只关心一件事,并且只通过明确定义的接口与相邻层交互。这跟传统软件工程里的分层架构没有本质区别,只不过 Agent 系统里多了一个“不确定性”的维度——模型的输出是概率性的,所以每一层的边界定义需要比传统系统更严格。

我拿一个真实场景来说明。假设你要做一个“合同审查助手”,用户上传一份合同,Agent 需要识别关键条款、比对内部合规规则、标记风险点、生成审查报告。如果一锅炖,你的 Prompt 大概会长这样:你是一个合同审查专家,请阅读以下合同内容,识别其中的付款条款、违约条款、保密条款,然后根据以下规则判断是否存在风险……最后按照以下格式输出报告……

这段 Prompt 在合同简单、规则少的时候能跑。但合同一复杂,模型就开始漏条款、错判风险、格式跑偏。更致命的是,你没法知道它到底在哪一步出了问题——是条款识别漏了?还是规则比对错了?还是格式生成时丢了信息?

分层之后,这个系统应该长成什么样?我画不出图,但可以用文字描述清楚:最底层是模型接入层,负责与 LLM 的通信、重试、降级;往上是能力层,包含条款抽取、规则匹配、风险评分等独立能力单元;再往上是编排层,决定什么时候调用哪个能力、按什么顺序、失败了怎么办;最上面是交互层,处理用户输入输出、格式转换、多轮对话状态。每一层只跟相邻层打交道,层与层之间通过结构化数据传递信息,而不是靠自然语言“传话”。

这样做的好处是显而易见的。条款抽取不准?我只调能力层里的抽取模块,换模型、改 Prompt、加 Few-shot 示例,不影响其他部分。规则匹配逻辑要更新?我只改规则引擎,编排层完全不用动。输出格式要调整?我只改交互层的格式化模板。每一层的变更都是局部的、可控的、可回滚的。

但分层不是没有代价的。最大的代价是信息损耗。当你在层与层之间传递结构化数据时,一些在自然语言里隐含的上下文信息可能会丢失。比如模型在抽取条款时“感觉”这个条款有点奇怪,但这种“感觉”很难结构化地传给下一层。所以分层设计的关键难点在于:如何定义层间接口,使得关键信息不丢失,同时又不至于让接口变得过于复杂。

我的经验是,层间接口应该传递“事实”和“置信度”,而不是“判断”。比如条款抽取层输出的是“第 3.2 条,付款条款,内容为……,置信度 0.87”,而不是“第 3.2 条是付款条款,没问题”。判断留给编排层或专门的决策层去做。这样每一层都只对自己最擅长的事情负责,决策逻辑集中在一处,便于审计和调整。

还有一个容易被忽视的点:分层不等于越多越好。我见过有人把 Agent 拆成七八层,结果层与层之间的通信开销比实际业务逻辑还大。一般来说,对于大多数业务场景,四到五层是比较合理的。再少,职责混在一起;再多,管理成本超过收益。具体怎么定,取决于你的业务复杂度和团队规模。

2. 拆层之前先想清楚:你的 Agent 到底在解决哪类问题

在动手拆层之前,有一个比“怎么拆”更重要的问题:你的 Agent 到底在解决哪类问题?这个问题不搞清楚,拆出来的层大概率是错的。

我把常见的 Agent 业务场景分成三类,每类对应的分层策略差异很大。

第一类是信息处理型。典型场景包括文档摘要、信息抽取、格式转换、内容分类。这类任务的特点是:输入输出相对明确,对“创造性”要求低,对“准确性”和“一致性”要求高。比如从合同里抽条款、从简历里抽关键信息、把会议记录转成待办事项。这类 Agent 的分层重点在于能力层的模块化和可测试性。你需要把每一种抽取能力做成独立的、可单独评测的单元,编排层反而可以很薄,因为流程基本是线性的。

第二类是决策辅助型。典型场景包括风险评估、方案推荐、合规审查、优先级排序。这类任务的特点是:需要综合多个信息源,依据一套规则或偏好做出判断,而且判断结果需要可解释。比如前面说的合同审查、信贷审批辅助、运维故障根因分析。这类 Agent 的分层重点在于规则引擎与模型推理的分离。模型负责“理解”和“抽取”,规则引擎负责“判断”和“打分”,编排层负责协调两者并处理冲突。这种分离让判断逻辑可审计、可追溯、可版本管理。

第三类是任务执行型。典型场景包括自动填表、多步骤操作、工具调用链、工作流自动化。比如自动处理报销单、自动生成周报并发送、自动排查服务器告警并执行修复脚本。这类任务的特点是:有明确的操作序列,每一步可能依赖前一步的结果,失败需要回滚或重试。这类 Agent 的分层重点在于编排层的状态管理和错误处理。能力层提供原子操作,编排层负责组合和调度,交互层负责与用户确认关键操作。

为什么要先分清楚这三类?因为不同类别的 Agent,分层的“重心”完全不同。信息处理型重能力层,决策辅助型重规则与模型的边界,任务执行型重编排层。如果你用任务执行型的思路去做信息处理型,你会把大量精力花在编排上,但实际业务逻辑很简单,纯属浪费。反过来,用信息处理型的思路去做任务执行型,你会低估状态管理和错误处理的复杂度,系统一跑就崩。

我自己的做法是,在项目启动阶段先回答三个问题:第一,这个 Agent 的输出是“信息”还是“动作”?第二,判断逻辑是“模型说了算”还是“规则说了算”?第三,失败后的恢复成本高不高?这三个问题的答案基本能定位你的 Agent 属于哪一类,从而决定分层策略。

还有一个现实问题:很多业务场景其实是混合型的。比如一个客服 Agent,既要理解用户问题(信息处理),又要判断该不该退款(决策辅助),还要执行退款操作(任务执行)。这种情况下,我的建议是按主流程归类,但允许层内嵌套。也就是说,整体架构按主流程的分层策略来搭,但在某个层内部,可以再嵌套一个子分层。比如编排层内部,可以再分“理解阶段”“决策阶段”“执行阶段”,每个阶段有自己的子编排逻辑。这样既保持了整体架构的清晰,又能应对混合场景的复杂性。

3. 四层架构的落地细节:从模型接入到交互输出

前面说了分层的必要性和分类思路,现在进入具体落地。我以最通用的四层架构为例,把每一层的职责、接口设计、常见坑点讲清楚。

3.1 模型接入层:别让重试和降级逻辑散落各处

模型接入层是最底层,也是最多人忽视的一层。很多团队直接在业务代码里调 LLM API,重试逻辑写一遍、超时处理写一遍、降级逻辑再写一遍,散落在十几个文件里。等到要换模型供应商或者加一个缓存层的时候,改到怀疑人生。

模型接入层的核心职责就三个:统一调用接口、统一错误处理、统一可观测性。

统一调用接口意味着,不管底层用的是哪家模型、哪个版本、哪种调用方式(同步/流式/批量),上层看到的都是一个统一的函数签名。比如invoke(prompt, options) -> response,其中options包含温度、最大 token 数、超时时间等参数。这样上层完全不需要关心底层是 GPT 还是 Claude 还是本地模型。

统一错误处理意味着,所有重试、降级、熔断逻辑都在这一层完成。比如超时重试三次,三次都失败就降级到备用模型,备用模型也失败就返回一个结构化的错误对象。上层拿到错误对象后决定是继续等待、提示用户、还是走兜底逻辑。这里的关键是错误对象要结构化,包含错误类型、重试次数、最后一次的原始响应等信息,而不是一个简单的异常抛出。

统一可观测性意味着,每一次模型调用都要记录:输入 token 数、输出 token 数、延迟、模型版本、是否命中缓存、是否重试。这些数据是后续优化成本、排查问题、评估模型效果的基础。我见过太多团队等到账单爆炸了才开始查哪个环节在疯狂调模型,那时候已经晚了。

这一层还有一个容易踩的坑:流式输出的处理。如果你的 Agent 需要流式返回结果给用户,流式逻辑应该在这一层封装好,上层拿到的是一个统一的流式接口,而不是每家模型不同的流式协议。否则上层代码会被流式细节污染,换模型时又要改一遍。

3.2 能力层:每个能力单元都应该能单独跑测试

能力层是 Agent 的“肌肉”,负责执行具体的原子任务。条款抽取是一个能力,规则匹配是一个能力,风险评分是一个能力,摘要生成是一个能力。每个能力单元应该满足三个条件:输入输出明确、可独立测试、可独立替换。

输入输出明确意味着,每个能力单元的函数签名是清晰的。比如extract_clauses(text: str) -> List[Clause],其中Clause是一个结构化对象,包含条款类型、内容、位置、置信度。这样编排层拿到的是一个列表,而不是一段自然语言描述。

可独立测试意味着,你可以脱离整个 Agent 系统,单独拿一批测试数据来评测这个能力单元。比如条款抽取能力,你可以准备 100 份标注好的合同,跑一遍看抽取准确率和召回率。这样当效果下降时,你能快速定位是哪个能力出了问题,而不是笼统地说“Agent 变笨了”。

可独立替换意味着,如果某个能力用 Prompt 工程做效果不好,你可以换成微调模型、换成规则引擎、换成第三方 API,只要输入输出接口不变,上层完全无感。这是分层架构最大的价值之一:让技术选型变成局部决策,而不是全局重构。

能力层的一个常见误区是“能力粒度太粗”。比如把“合同审查”当成一个能力,那这个能力内部又包含了抽取、匹配、评分、生成,等于没拆。正确的做法是拆到“不可再分且可独立评测”的粒度。但也不能太细,太细会导致能力单元之间的协调成本上升。我的经验是,一个能力单元应该对应一个“可以用一句话描述清楚、并且可以用一个指标衡量好坏”的任务。

3.3 编排层:Agent 的“大脑”其实是个调度器

编排层是很多人认为的“Agent 核心”,但我的观点可能有点反直觉:编排层不应该太聪明。它的核心职责是调度和状态管理,而不是做复杂的推理。

编排层要做的事情包括:决定当前步骤该调用哪个能力、把上一个能力的输出转换成下一个能力的输入、处理能力调用失败时的重试或降级、维护整个任务的状态(进行中/已完成/已失败)、在关键节点决定是否需要人工介入。

为什么说编排层不应该太聪明?因为一旦编排层开始做复杂推理,它就会变得难以测试、难以调试、难以解释。你没法给一个“凭感觉调度”的编排层写单元测试。所以我的原则是:编排逻辑尽量用显式的规则或状态机来表达,能用 if-else 说清楚的就不要用模型来判断。

比如“如果条款抽取置信度低于 0.6,就调用人工复核能力;否则继续走规则匹配”,这就是一条清晰的编排规则。你不需要让模型来决定“要不要人工复核”,因为这种决策用规则表达更可靠、更可审计。

编排层的另一个关键设计是状态管理。一个多步骤的 Agent 任务,状态可能包括:当前执行到哪一步、每一步的输入输出、中间结果的置信度、已经消耗的 token 数、已经花费的时间。这些状态需要被持久化,以便任务中断后能恢复、失败后能重试、完成后能审计。我见过很多 Agent 系统把状态存在内存里,服务一重启任务就丢了,这在生产环境是不可接受的。

3.4 交互层:用户看到的不是你的架构,而是你的输出

交互层是用户直接接触的部分,但它的职责远不止“把结果展示出来”。交互层需要处理:用户输入的解析和校验、多轮对话的状态维护、输出格式的转换、错误信息的友好呈现、以及必要时的用户确认流程。

用户输入的解析和校验经常被低估。用户可能上传一个 PDF、粘贴一段文字、发一条语音、点一个按钮,交互层需要把这些不同形态的输入统一成上层能处理的结构化数据。同时要校验输入是否合法、是否完整、是否超出处理范围。比如用户上传了一个 200 页的合同,交互层应该提示“文件过大,建议分段处理”,而不是直接把 200 页塞给模型然后超时。

多轮对话的状态维护是另一个难点。用户可能在审查过程中问“第三条的付款条件是什么”,Agent 需要知道“第三条”指的是当前正在审查的合同里的第三条,而不是上一份合同。这要求交互层维护一个对话上下文,并且能把这个上下文传递给编排层。但上下文不能无限增长,需要有策略地截断或摘要。

输出格式的转换看似简单,实则容易出问题。模型输出的可能是 Markdown、JSON、纯文本,但用户界面可能需要的是 HTML、表格、卡片。交互层需要做可靠的格式转换,并且在转换失败时有兜底方案。我踩过的坑是:模型输出了一个“看起来像 JSON 但实际不是”的字符串,解析直接报错,用户看到一片空白。后来我在交互层加了一层“格式修复”逻辑,先尝试解析,失败后用规则提取关键字段,再失败才展示原始文本并提示用户。

4. 层间接口设计:结构化数据怎么传才不丢信息

分层架构的成败,很大程度上取决于层间接口的设计。接口设计得好,每一层都能独立演化;设计得不好,层与层之间耦合比不分层还严重。

我的核心原则是:层间传递结构化数据,但保留原始引用。

什么意思?举个例子。能力层从合同里抽取了一个条款,输出给编排层的是一个结构化对象:{type: "payment", content: "甲方应在收到发票后 30 日内支付...", position: "第 3.2 条", confidence: 0.87, raw_text: "..."}。其中raw_text是原始文本片段,保留它是为了在需要时能回溯原文,避免结构化过程中丢失细节。

编排层拿到这个对象后,决定调用规则匹配能力。它传给规则匹配能力的是这个结构化对象,而不是把content重新拼成一段自然语言再传过去。规则匹配能力返回的也是一个结构化对象:{clause_ref: "第 3.2 条", matched_rules: ["PAY-001", "PAY-003"], risk_level: "medium", explanation: "付款期限超过内部标准 15 天"}。

这样一路传下来,每一层都在结构化数据上操作,信息不会在自然语言转换中丢失。同时,因为保留了raw_text和clause_ref,任何时候都能追溯到原始输入。

但结构化传递也有代价:接口会变得复杂。一个条款对象可能有十几个字段,规则匹配结果又有十几个字段,层与层之间的接口定义会越来越臃肿。我的应对策略是分层定义接口,按需传递。也就是说,不是所有字段都需要在所有层之间传递。能力层输出完整对象,编排层只提取它需要的字段传给下一个能力,交互层只拿最终需要的字段做展示。每一层只关心自己需要的部分,接口复杂度就可控了。

还有一个关键问题是置信度的传递。模型输出的置信度往往不准,但完全不用又不行。我的做法是:置信度只作为参考,不作为唯一决策依据。编排层可以设定阈值,比如“置信度低于 0.6 就触发人工复核”,但阈值需要根据实际数据调优,不能拍脑袋定。同时,置信度应该随着流程传递,让最终决策者知道哪些环节是“不确定”的。

最后说一个容易被忽视的接口设计问题:版本兼容。当你的能力层升级了,输出对象多了一个字段,编排层还没更新,会不会崩?我的做法是接口设计遵循“宽进严出”原则:输入时容忍多余字段,输出时保证必需字段。同时给接口加版本号,编排层调用能力时指定版本,能力层根据版本返回对应格式。这样升级可以灰度进行,不会一刀切。

5. 实测中的三个典型翻车场景与修复过程

分层架构听起来很美,但实际落地时踩的坑一点不少。我挑三个最有代表性的翻车场景,把排查过程和修复方案完整还原出来。

5.1 场景一:能力层“各自为政”,编排层拿到矛盾结果

有一次做信贷审批辅助 Agent,能力层有两个模块:一个负责从申请材料里抽取收入信息,一个负责从征信报告里抽取负债信息。两个模块单独测试都没问题,但上线后发现编排层经常拿到矛盾的结果:收入模块说月收入 2 万,负债模块说月还款 1.5 万,但征信报告里显示的月收入是 1.2 万。

排查过程是这样的:先看两个模块的原始输出,发现收入模块抽取的是“申请材料中填写的收入”,负债模块抽取的是“征信报告中记录的收入”。两个数据源本身就不一致,但两个模块都只输出了自己的结果,没有标注数据来源。编排层拿到两个数字,不知道哪个更可信,只能随便选一个或者都传给规则引擎,导致判断结果不稳定。

修复方案是在能力层的输出对象里强制增加source字段,标明数据来源。同时编排层增加一个“数据源优先级”配置,当多个来源冲突时,按优先级选择。这个改动很小,但效果立竿见影。后来我们还加了一个“冲突检测”逻辑,当不同来源的数据差异超过阈值时,自动触发人工复核。

这个坑的教训是:能力层不能只输出“结果”,还要输出“结果的来源和上下文”。否则编排层拿到一堆孤立的数据点,根本没法做可靠决策。

5.2 场景二:编排层状态丢失,任务中断后无法恢复

另一个项目是做多步骤的报销单处理 Agent。流程是:识别发票信息、校验发票真伪、匹配报销规则、生成报销单、提交审批。整个流程走完大概需要 30 秒到 2 分钟,取决于发票数量和规则复杂度。

问题出在:用户提交后如果刷新页面或者网络中断,任务就丢了。用户重新提交,系统从头开始跑,已经识别过的发票又识别一遍,浪费时间和 token。更糟糕的是,有时候任务跑到一半失败了,用户不知道失败在哪一步,只能重新提交,体验很差。

排查后发现,编排层的状态全部存在内存里,没有持久化。服务重启或者用户会话结束,状态就没了。修复方案是引入一个轻量级的状态存储,每一步执行完后把状态写进去,任务恢复时从最后一步继续。状态存储的 key 是任务 ID,value 是当前步骤、已完成步骤的输出、剩余步骤列表。

这个改动增加了系统的复杂度,但带来的收益很大:任务可恢复、可审计、可重试。后来我们还基于这个状态存储做了任务进度展示,用户能看到当前跑到哪一步了,体验提升明显。

5.3 场景三:交互层格式转换失败,用户看到“乱码”

这个坑最尴尬。模型输出的是一段 Markdown 格式的审查报告,交互层需要把它转成 HTML 展示。大部分时候没问题,但偶尔模型会输出一些“非标准 Markdown”,比如嵌套表格、特殊字符、不闭合的代码块,转换库直接抛异常,用户看到一片空白或者一堆乱码。

排查过程比较曲折。一开始以为是模型输出不稳定,尝试用更严格的 Prompt 约束输出格式,但效果有限。后来发现根本原因是:交互层对模型输出做了“全有或全无”的假设,要么完整解析成功,要么完全失败。但模型输出本质上是概率性的,不可能 100% 符合格式。

修复方案是加一层“渐进式降级”:先尝试完整解析,失败后尝试提取关键字段用简单模板渲染,再失败就展示原始文本并提示“格式解析异常,以下是原始内容”。同时记录解析失败的样本,定期分析原因,反哺 Prompt 优化。

这个坑的教训是:交互层必须假设上游输出是不完美的,并且为不完美设计降级路径。不能把“格式正确”当成理所当然。

6. 分层之后,怎么衡量每一层到底有没有做好

分层不是目的,做好才是。但“做好”需要可衡量。我的做法是给每一层定义独立的指标,层与层之间的指标不混在一起。

模型接入层的核心指标是可用性和成本。可用性包括调用成功率、平均延迟、重试率。成本包括每千次调用的 token 消耗、缓存命中率。这些指标帮你判断模型接入层是否稳定、是否经济。

能力层的核心指标是准确率和召回率。每个能力单元都应该有对应的评测数据集和指标。比如条款抽取的准确率、规则匹配的召回率、风险评分的 AUC。这些指标帮你判断每个能力是否达标,以及升级后是否变好。

编排层的核心指标是任务完成率和平均步骤数。任务完成率包括首次成功率、重试后成功率、最终失败率。平均步骤数帮你判断编排逻辑是否高效,有没有多余的调用。如果平均步骤数突然上升,可能是某个能力输出不稳定导致编排层反复重试。

交互层的核心指标是用户满意度和交互轮次。满意度可以通过用户反馈或隐式行为(如是否采纳结果、是否重新提交)来衡量。交互轮次帮你判断用户是否容易理解和使用你的 Agent。如果平均交互轮次很高,可能是输出不够清晰或者错误提示不够友好。

这些指标需要定期 review,最好是每周或每两周一次。指标异常时,先定位是哪一层的问题,再深入排查具体原因。分层架构的好处在这里体现得很明显:问题定位从“整个 Agent 有问题”变成了“某一层的某个指标异常”,排查效率提升一个数量级。

7. 从分层交付到持续演进:一些个人体会

分层交付不是一次性的工作,而是一个持续演进的过程。我自己的体会是,第一版分层方案几乎不可能完美,重要的是先拆出一个“可运行、可观测、可调整”的结构,然后在实际运行中不断优化。

我通常会建议团队在项目初期就建立三个习惯。第一,每个能力单元必须有独立的测试集,哪怕只有几十条数据,也比没有强。第二,层间接口必须有文档和版本号,接口变更必须走评审,不能随手改。第三,每一层的指标必须可视化,让团队成员随时能看到自己负责的层表现如何。

还有一个反直觉的经验:不要过早追求“最优分层”。我见过团队花两个月设计“完美架构”,结果业务需求一变,架构全废。更好的做法是先按最粗的粒度拆(比如就拆成“模型调用”和“业务逻辑”两层),跑起来之后根据实际痛点再细分。痛点在哪里,分层就拆到哪里。

最后说一个关于“智能”的理解。很多人觉得 Agent 的“智能”来自于模型本身,但我的观察是,在生产环境里,Agent 的智能更多来自于架构的清晰度。一个分层清晰、接口明确、每层可独立优化的 Agent,即使底层模型不是最强的,实际表现也往往好过一个用最强模型但一锅炖的系统。因为前者能持续迭代,后者只能推倒重来。

这个系列后面还会继续聊 Agent 工程化的其他话题,比如评测体系怎么搭、工具调用怎么设计、多 Agent 协作怎么避免“三个和尚没水喝”。分层交付是所有这些话题的基础,这一层没打好,后面的都是空中楼阁。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询