尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从Demo到生产:AI应用平台的Agent编排、MCP与RAG实战拆解

从Demo到生产:AI应用平台的Agent编排、MCP与RAG实战拆解 过去两年我一直在折腾 AI 应用开发。最早的项目很简单一个聊天窗口接上大模型 API再丢几篇文档进向量库一天就能看到效果。可等你想把它从“能跑的 Demo”变成“团队每天都在用的生产系统”问题立刻就变味了Agent 编排逻辑应该写在哪一层同时接了三家模型厂商的 Key限流和成本怎么统一管MCP、SKILL、RAG 这些扩展到底是各做各的还是应该收拢到一个平台体系里没有工程底座兜底AI 应用越多烂账越多。XXL-AI 是我今年持续推进的一个 AI 应用开发平台项目目标是把 Agent 编排、多供应商模型接入、「MCP SKILL RAG」扩展能力以及权限、观测、灰度发布这类工程化底座都收拢到一个平台里。这篇文章不打算做概念科普我想以一个开发者的视角拆解这类平台在设计时真正花时间的地方在哪方案是怎么取舍的以及落地过程中踩过哪些坑。适合两类人看一类是想自建 AI 应用平台的团队另一类是正在集成 Agent、MCP、RAG 但总觉得代码越写越乱的开发者。1. 当 AI 应用从“单次对话”走向“Agent 任务流”平台要解决的第一个问题不是模型很多人以为做 AI 应用平台第一步是选模型。实际不是。模型能力当然重要但平台和 Demo 的区别首先体现在“让一次调用变成一条可稳定执行的任务链路”。1.1 从“对话应用”到“任务应用”复杂度发生的是数量级变化一个聊天机器人你只需要维护一个上下文窗口模型回什么就是什么。但一旦进入 Agent 场景系统要自己规划步骤、调用工具、根据结果决定下一步动作复杂度会爆炸式增长。我在 XXL-AI 里最先做的一件事不是写模型调用代码而是给“一次 Agent 执行”定义清晰的执行模型。简单说就是解决三个问题Agent 拿到用户目标后如何拆解出执行计划计划中的每一步调什么工具、用什么模型、传什么参数模型判断错误或工具执行失败时系统如何重试、降级还是终止。这三个问题之所以不能散落在业务代码里是因为它们出现的频率太高。每个 Agent 应用都会遇到而且处理逻辑高度相似。如果每个应用各写一套后面排错会非常痛苦。在 XXL-AI 里我把 Agent 执行抽象成一个循环器Agent Loop核心思路是让模型产出结构化决策由平台执行决定平台执行结果再回传给模型继续决策。这样做的好处是编排逻辑可以被统一观测坏处是需要严格约束模型的输出格式否则解析那一关就会挂掉。1.2 XXL-AI 的总体模块划分四层模型加一条扩展总线如果给 XXL-AI 画一张架构简图大概是这样的分层层级职责典型组件应用层面向业务场景的编排入口Agent 工作流、技能调用、知识问答编排层控制流、状态管理、多 Agent 协作编排引擎、会话仓储、任务队列扩展层接入外部能力和知识MCP 网关、SKILL 运行时、RAG 管线底座层通用工程能力权限、审计、观测、灰度、配置中心再加上一条横向的“多供应商模型网关”它不隶属任何一层而是所有层都需要调用的基础服务。这个划分并不是一开始就定的是在做了两三个业务应用之后发现重复代码全挤在一起才被迫拆出来的。我把经验总结成一句话AI 应用平台的架构工作本质上是给“模型的不可预测性”上保险而不是把模型能力包得越薄越好。模型调用只是起点决定平台上限的是编排、扩展和工程底座。2. Agent 编排层控制流、状态机与多 Agent 协作Agent 编排是整个 XXL-AI 最核心也最容易写乱的部分。这里我展开讲讲用到的三种关键机制编排循环、协作模式和状态管理。2.1 编排的本质把“模型决策”变成“可执行计划”我见过不少团队的 Agent 代码其实就是在一个 while 循环里反复调模型把工具调用结果拼进 prompt然后等模型下一次输出。这种写法在小 demo 里没问题但 Production 环境需要更严格的表达。XXL-AI 的编排循环大致长这样def run_agent(task, context): plan planner.plan(task, context) # 第一步模型产出计划 for step in plan.steps: if step.type tool: result execute_tool(step.tool_name, step.params) # 平台执行工具 context.add_step_result(step.id, result) elif step.type llm: output call_llm(step.prompt, context) # 模型生成内容 context.add_step_result(step.id, output) # 每次步骤结束后允许模型修正后续计划 plan planner.plan_with_feedback(task, context, plan) return plan.final_answer这段话简化了但你看到了重点计划、执行、反馈、再计划这个循环就是编排的本质。平台需要做的是给这个循环提供稳定的承载而不是让每个 Agent 都自己实现一遍。如果模型返回的工具调用意图不清晰我会在解析层多做一次校验必要时直接中断执行而不是盲目重试。这能避免很多脏数据。2.2 多 Agent 协作的三种模式顺序、路由、层级多 Agent 编排是热门词里高频出现的概念但很多人把多 Agent 想得太玄。实际落地时XXL-AI 里最常用的是三种协作模式顺序协作Agent A 的输出传给 Agent B适合流水线式处理比如先写大纲再写正文再润色。路由分发一个路由器 Agent 根据用户意图把任务分给不同的专家 Agent比如客服场景分给退款、售后、技术咨询这三个子 Agent。层级协作主管 Agent 拆解目标后分派给多个工人 Agent 并行执行最后汇总结果。适合研究分析类任务。这三种模式我一开始都想在编排引擎里做成可视化拖拽后来放弃了。原因很现实可视化编排适合固定流程但 Agent 的特点是流程会动态变化。最终方案是“固定骨架 动态步骤”骨架可以用可视化配置具体步骤由模型在运行时决定。2.3 状态管理与会话记忆必须独立的存储结构Agent 跑起来之后最容易被忽视的就是状态管理。一个任务执行到第三步模型输出了一段中间结果这时用户断开连接你怎么办进程重启了怎么办XXL-AI 的状态存储我采用的是独立会话仓储不放在内存里而是落库包含这几个字段字段说明session_id一次完整任务的唯一 IDtask_goal用户原始目标plan_snapshot当前计划的结构化快照step_history已执行步骤的输入输出context_window压缩后的上下文引用statuspending / running / waiting / success / failed这里有个细节context_window 不直接存全部历史消息而是存“摘要 关键消息引用”。因为多步执行后完整对话历史会超过模型上下文长度全量塞回去既浪费 token 又拉慢响应。我会提供一个压缩器在每轮后检查长度超限就生成摘要并丢弃中间细节。这个设计让长任务能稳定跑下去不会跑着跑着就“记忆溢出”。3. 多供应商模型网关统一接口后面的工程账本标题里写了“多供应商”这绝对是平台类项目里绕不开的硬骨头。XXL-AI 在接入模型供应商上的原则是对业务层隐藏供应商差异对运维层暴露全部细节。3.1 供应商抽象层接口、鉴权、流控、配额业务代码最怕的就是下一代模型出了到处要改参数。XXL-AI 的模型网关对外提供一个统一接口字段覆盖主流供应商的公共语义{ model: provider_model_name, messages: [{role: user, content: 你好}], temperature: 0.7, max_tokens: 2048, tools: [], stream: false }返回结构同样统一包括 content、tool_calls、usage(tokens)、latency_ms 等字段。在网关内部每个供应商都有一个适配器负责做三件事鉴权每个供应商的 Key 独立加密存储网关统一注入业务层永远拿不到原始 Key流控按供应商和模型维度做令牌桶限流避免一个应用的突发流量打爆另一个应用配额根据团队或项目的月度预算做配额控制超限后自动降级或拒绝。这套设计的核心价值不在于省事而在于可审计。谁在什么时间用哪个模型调了多少 token全部有记录。没有这道墙成本失控只是一夜之间的事。3.2 路由、自动降级与按任务分发策略多供应商最容易犯的错误是“平均主义”——这个模型便宜就全部用它那个模型聪明就全切过去。实际上应该按任务类型分发。XXL-AI 支持路由策略配置常用的一种做法是标签路由任务类型首选供应商降级链路代码生成A 模型A 模型 - B 模型 - 本地小模型长文总结B 模型B 模型 - A 模型 - C 模型工具调用A 模型A 模型 - D 模型实时对话C 模型C 模型 - A 模型网关在检测到首选供应商超时或返回特定错误码时自动切换到降级链路同时把降级事件写入监控日志。这个机制上线之后我用一个深夜流量高峰测试过首选供应商持续报错 5 分钟平台整体成功率只掉了 2%因为大部分请求都被自动切到了备选链路。3.3 成本观测token 计量和按项目分摊说了半天模型最后必须回到钱。XXL-AI 中有一个成本看板按项目维度统计每天的 token 消耗、费用估算和调用量趋势。这个看板的数据来源就是网关里每一笔请求的 usage 字段。我们会把字段归一化为统一的 token 单位再按供应商的报价表计算费用。这块的坑在于供应商对 token 的计费口径不一样有的按字符有的按 token有的按图像尺寸。归一化如果不做成本看板就是一堆对不上的数字。我这里主张在网关出口就完成归一化而不是把原始账丢给上层自行折算。另外token 浪费往往出在“无用的长上下文”我会定期拉出 token 消耗 Top 10 的会话看看到底是业务需要长上下文还是代码里把历史消息无脑全塞了。每次都优化出不少成本。4. MCP 扩展让 Agent 不挑工具的协议标准MCPModel Context Protocol是“工具太多、各自为政”这个困境的产物。接入 XXL-AI 之前的教训是每个 Agent 都定义自己的一套工具 JSON Schema同一个搜索引擎功能在客服 Agent 里写一遍在数据分析 Agent 里又写一遍维护成本直线上升。4.1 MCP 到底解决什么问题MCP 把工具调用协议标准化了Agent 平台和外部工具之间通过统一协议通信工具方只要实现一个 MCP Server任何支持 MCP 的客户端都能直接调用它。听起来很简单但意义很大因为它让“工具生态”不再是某个 Agent 的私有资产而是平台级的公共资源。在 XXL-AI 里我把 MCP 接入设计成一个独立网关服务而不是直接写在 Agent 代码里。这样 Agent 和工具之间是解耦的Agent 只知道工具名和入参不知道工具部署在哪里、怎么鉴权。4.2 MCP Server 接入设计生命周期、工具列表拉取、调用转发接入一个 MCP Server大致流程如下在平台后台录入 MCP Server 的连接信息SSE、Stdio 或 Streamable HTTP网关主动拉取 Server 声明的工具列表缓存下来并生成统一工具描述Agent 运行时加载工具列表把工具描述注入模型 Prompt 或作为 function schemaAgent 发起工具调用请求网关转发给目标 Server拿到结果后回传给 Agent。这里我遇到过最大坑是连接类型。很多入门教程只讲本地 Stdio 模式也就是从进程子进程拉起一个脚本适合开发和单机部署。但生产环境里工具往往分布在不同的服务器上必须用 HTTP/SSE 模式。我们后来把 Stdio 模式限定在开发环境线上全部走 HTTP否则服务一多网关的进程管理会变成噩梦。4.3 实操中容易翻车的三个细节超时设定MCP 工具调用不像本地函数外部服务可能很慢。如果不设超时Agent 会一直在等待工具返回整个任务卡死。我在网关层统一设了默认 30 秒超时长任务可以配置到 2 分钟超时后返回一个工具执行失败的错误给 Agent。鉴权令牌的过期问题MCP Server 常用短期令牌认证,令牌过期后网关不会自动知道。所以网关必须捕获 401/403 状态码并触发重新认证流程,而不是直接当作工具调用失败。JSON Schema 与模型的兼容性MCP 工具描述里的入参 Schema 可能非常复杂但模型对复杂嵌套 JSON Schema 的理解力有限。最好在网关层做一次 Schema 简化只暴露必填参数和简单枚举。这个步骤看着简单却能让工具调用的成功率提高一大截。5. SKILL 机制把可复用的“能力包”做成一等公民MCP 解决的是“工具被别人调用”的问题SKILL 解决的是“把一段常用能力沉淀下来”的问题。在 XXL-AI 中SKILL 是比 Tool 更上层的抽象它可能包含 Prompt、代码、参数校验和示例。5.1 什么是 SKILL从提示词片段到能力包最早的 SKILL 其实就是团队内部沉淀的提示词模板。比如“代码审查提示词”“竞品分析框架”每个成员复制到自己的项目里改一改就能用。问题是没有版本管理改了一版之后别人还在用旧版效果参差不齐。后来我们把 SKILL 做成一个可加载、可版本化、可组合的资源包。一个 SKILL 不只是一段文本它可以包含执行逻辑。比如“SQL 生成技能”这套 SKILL 内部可以定义生成步骤先判断数据表结构、再生成 SQL、再用校验器检查 SQL 是否包含危险操作、最后输出给用户。这些步骤完全由 SKILL 的代码决定。SKILL 的目录结构通常长这样skill_sql_generator/ ├── SKILL.md # 技能描述、适用场景、参数定义 ├── main.py # 技能主逻辑可调用模型与工具 ├── validators.py # 输出校验如 SQL 安全检查 ├── examples/ # few-shot 示例 ├── assets/ # 额外资料、参考文档 └── metadata.json # 版本、作者、依赖 SKILL 列表引入这套规范后团队里“贡献技能”变得特别自然。谁写成了一套好的分析 Prompt顺手就能打包成一个 SKILL 放到仓库里别人直接引用不需要看内部实现。5.2 SKILL 与 MCP、RAG 如何协同SKILL 不是孤立的。一个标准的数据分析 SKILL内部很可能会调用 MCP 暴露的数据库查询工具也可能会检索 RAG 知识库里存放的企业指标口径文档。这就是我把三者放在同一标题下的原因——它们是平台“扩展层”的三个支柱MCP 管“能调什么”SKILL 管“怎么调才能稳定产出”RAG 管“模型不知道但业务需要的知识从哪来”。实现上XXL-AI 在 Agent 运行时会对 SKILL 做依赖注入SKILL 声明它需要哪些 MCP 工具和哪个知识库运行时由平台自动装配。这样业务开发者写技能时不用关心 MCP Server 在哪、知识库索引怎么建只用声明式写法挂依赖即可。5.3 SKILL 市场与权限控制SKILL 多了之后需要做市场化的管理。我们建了内部技能市场展示技能列表、版本、作者和调用成功率。权限上每个 SKILL 可以指定可见范围按项目组隔离。这块经验是默认不公开显式授权才可见省去很多安全审核的麻烦。6. RAG 扩展知识库管线里最容易被高估的是“向量检索”RAG检索增强生成几乎是 AI 应用开发平台的标配但多数人对 RAG 的理解停留在“文档切碎 - 向量化 - 向量检索 - 拼进 Prompt”。真正落地时这条链路每一步都有坑而且向量相似度只是检索质量的下限保障。6.1 文档摄入链路解析、清洗、分块、嵌入、元数据XXL-AI 的知识库模块文档进入后的第一步不是切块而是解析和清洗。以 PDF 为例很多 PDF 是扫描件不先做 OCR 就切块进去的全是乱码。Word 和 HTML 同样有格式噪声需要消除比如页眉页脚、导航栏、广告区块。我自定义了一套摄入管线主要节点覆写了这几个能力解析按文档类型选择解析器PDF/Word/HTML/Markdown 各自独立处理清洗去掉页眉页脚、重复段落、乱码字符、无用超链接分块优先按语义边界标题、段落分块而不是固定的 512 字硬切增强元数据每块记录来源文档、页码、标题路径、更新时间嵌入按供应商能力选择 embedding 模型支持批量向量化异步索引文档更新后增量刷新索引而不是全库重建。分块是其中对效果影响最大的环节。我试过很多分块策略最终参考的指标是“检索命中后的问答效果”而不是分块字符数。有些场景固定分块比较好有些场景语义分块更好所以 XXL-AI 把分块策略做成可配置项不同的知识库可以用不同策略。6.2 检索增强的隐藏问题召回、排序和重排只做向量检索是不够的。向量检索对同义改写效果不错对专有名词和精确 ID 却常常失误。比如用户搜索“XXL-AI 的离线任务重启 API 参数”如果文档里写的是“restart_job(pool_name, job_id)”向量检索很可能召不回来但关键词检索能直接命中。所以生产系统普遍采用混合检索向量召回 关键词召回BM25再做融合。XXL-AI 的检索管线目前是同时执行向量检索和关键词检索各自取 Top N用 RRFReciprocal Rank Fusion或加权打分合并结果关键场景再上一路 Reranker 模型对候选结果重新排序按最终分数截断 TopK再拼进 Prompt。很多人问Reranker 是不是必须的我的经验是如果知识库规模小Top 20 以内直接拼 Prompt 也能接受但知识库一旦上千篇文档不重排就有大量低质量片段混入上下文模型会被错误信息带偏。Reranker 带来的提升不是一点半点。6.3 图片能进 RAG 知识库吗热门词里专门有人问“RAG 知识库能不能存图片”这是个好问题。答案是能存但要想清楚存什么。图片直接存二进制没有意义RAG 检索的是文本空间。当前可行的做法有两类图片 描述文本为每张图片生成说明文字检索时只匹配描述文本回答时把图片URL和描述一起给模型多模态嵌入用多模态模型同时把图片和文字映射到向量空间实现图文混合检索。第一种实现成本低检索精度可控第二种效果上限高工程复杂度和成本也明显更高。XXL-AI 当前默认走第一种图片入库时会自动调用视觉模型生成一段结构化描述并把图片地址作为元数据存储。这样既解决了检索问题又保留了图片本身。6.4 结构化知识为什么需要不同姿势纯文档型知识适合向量库但表格、条目、知识图谱这类结构化数据硬塞进向量库会失真。这就是“Ontology RAG”和“GraphRAG”这类方向的出发点。我们的经验是不要迷信一种方案很多企业知识库最大痛点恰恰是“文档里的表格字段对不上”这时候应该先做结构化抽取把表结构转成可检索的字段记录再配合文本检索一起进上下文。GraphRAG 适合关系密集型知识但对大多数团队来说第一版没有必要上这么重。7. 工程化底座权限、可观测、灰度与发布才是“平台”和“Demo”的分水岭这一章讲的是那些不性感但绝不能少的部分。Agent 应用比传统应用多了一层不确定性模型输出不可预期、外部工具不可控、知识库持续更新。没有工程底座任何一个不可预期都可能引发线上事故。7.1 统一工作空间、项目隔离与角色权限多个团队共用平台隔离是第一优先。XXL-AI 的资源模型是平台 - 团队 - 项目 - 应用/知识库/技能。每个项目有独立空间项目成员按角色分配权限角色Agent 编排模型接入知识库发布管理员读写读写读写发布开发读写只读读写发布运维只读读写只读发布访客只读只读只读不可权限控制的粒度可以讨论但底线原则是“开发权限和发布权限分离”。否则开发改了一段编排顺手就推到线上没有任何把关AI 应用的更新就会变成事故制造机。7.2 调用链追踪与可观测性Agent 应用的可观测性和普通接口不同。一个用户请求进来可能触发三四个模型调用、五六个工具调用、两三次知识库检索最后才生成答案。如果链路不能完整追踪故障排查基本靠猜。我在 XXL-AI 里强制要求每个 Agent 执行链路生成一个 trace_id所有模型调用、工具调用、知识库检索都带上这个 ID。日志中心按 trace_id 聚合就能看到“用户在 14:32 发起提问14:32:05 触发模型 A14:32:06 触发工具 MCP-B14:32:08 检索知识库 C14:32:09 返回结果”。任何一步慢或失败都能快速定位。另外还需要记录“模型输入了哪些上下文”。Agent 类应用的很多问题根源不是模型笨而是上下文中拼入的检索片段本身就是错的。有了 trace 就能回看当时模型到底看到了什么排查效率完全不一样。7.3 灰度发布、版本管理与回滚Agent 应用的发布最怕“改了提示词导致对话质量下降”。这类质量问题是隐性的单元测试覆盖不到。所以 XXL-AI 必须支持版本化发布开发的 Agent 应用每次保存都生成新版本并附 Release Note发布时将流量按百分比灰度到新版本比如先 5% 再 50%灰度期间对比新旧版本的核心指标包括调用成功率、工具调用成功率、平均耗时、用户反馈标记指标异常自动回滚到上一稳定版本。这里的关键是灰度指标必须有“质量面”不能只看“系统没报错”。我会让灰度应用的用户追加一个“这次回答满意吗”的反馈按钮即使只有 1% 的点击率也比没有任何反馈的指标强得多。AI 应用的可用性最终取决于使用者的主观感受这一点越早认识到越好。8. 落地几个月后我复盘的几个真实教训如果把这几个月在 XXL-AI 上的经历浓缩成几句话我想说是下面几条。它们不是理论推演都是被线上问题逼出来的。8.1 “能力不是越多越好”MCP 工具和 SKILL 产生决策噪声最初我们把 MCP Server 和 SKILL 一股脑全接进 Agent认为能力越全越聪明。结果模型面对几十个工具描述时经常选错工具或者犹豫不决。后来改成“按场景最小化注入”系统为每个 Agent 应用配置一份白名单只注入可能用到的工具和技能。效果立竿见影工具选择准确率明显回升。做平台要多提供可能性但 Agent 运行时要做减法。8.2 模型供应商“平均主义”行不通多供应商不是简单地把每个模型接入进来就完事。不同模型在代码、推理、摘要、工具调用上的表现差异很大。我在平台上维护了一个“模型能力评分表”按任务类型定期更新路由策略尽量基于这个评分表而不是价格。曾经为了省成本把代码生成流量全切到一个便宜模型上结果工具调用成功率跌了三成用户反馈全是“答非所问”。后来加回质量导向的模型整体体验才回来。省钱要从 token 优化里省不能从模型质量上省。8.3 测试 Agent 应用不能只测端到端Agent 应用输出是概率性的同样的输入可能得到不同的回答传统“一个测试用例管一条路径”的方式完全不适用。我现在的经验是分层测试单元层测试工具函数本身、Prompt 渲染逻辑、Skill 的校验器确定性测试用固定模型参数和历史快照验证输出结构是否稳定回放测试收集线上真实请求用新版本跑一遍对比旧版本的回答质量和工具调用人工评测抽检灰度的对话记录按标准打分。最后一项虽然最费人力但也最有价值。单纯依赖自动化测不出回答“合理但平庸”和“精准且优秀”的差别。8.4 平台建设是持续工程不是一次性项目XXL-AI 做到现在功能列表已经比最初设想的多了两倍。回头看真正让平台有价值的不是某个炫酷功能而是“能力沉淀 规范约束 可观测”这三件事。Agent 应用开发的门槛正在快速降低但把它做成能长期稳定运行的系统底座依然需要持续投入。如果你正在规划类似平台我个人的建议是先跑通一个最小闭环再逐层补位。先把单一供应商、单一 MCP 工具、一个知识库跑起来不要急着追求大而全。等慢慢感受到“东西多了以后到底哪里疼”再决定平台该往哪个方向延伸那时候加的功能才真正能消化掉。
返回列表