ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI应用开发底座实战:Agent编排、MCP与RAG扩展机制拆解

AI应用开发底座实战:Agent编排、MCP与RAG扩展机制拆解 XXL-AI 这个项目最初是给一个业务团队做的内部 AI 应用平台。他们当时的诉求很直白要能同时对接多个大模型供应商要允许运营同事自己编排业务流程还要把公司内部的业务系统、知识库全接进来。听起来不复杂但真正落地时牵扯到的内容比想象中多得多。这个平台本质上是一套 AI 应用开发底座——底层屏蔽供应商差异中间提供 Agent 编排能力上层通过 MCP、SKILL、RAG 三种扩展机制把工具、技能、知识装进去最后再配上工程化必要的配置、监控、日志和权限控制。这篇文章我想把平台的拆解过程、关键设计和实际踩过的坑按实战路线重新过一遍。不管是正在做智能客服、内部知识问答、流程自动化还是单纯想找一个 Agent 落地框架这个拆解应该都有参考价值。1. 平台定位与整体设计先把问题定义清楚1.1 这个平台到底解决的是哪一类问题如今写一个单轮大模型调用 demo 很简单一行client.chat()就能搞定。但真实业务系统不是单轮问答用户说“我要退货”你需要先调用用户服务确认订单再调物流服务查状态判断是否符合退货规则然后生成处理方案最后还要写一条工单记录。每一步都可能需要和不同模型、不同工具交互也可能要人工确认。XXL-AI 解决的就是这类多步骤、多工具、多决策点的 AI 应用问题。单模型调用只能做“输入到输出”的映射而 Agent 编排能做“流程定义与执行”。没有编排层业务逻辑就会泄漏到提示词里变成一团既不可测试、又不可维护的字符串拼接。所以这个平台的第一设计原则不是“把模型能力做大”而是“把模型的调用方式做成可编排的流程”。在这个前提下Agent 编排、多供应商、扩展机制和工程化底座都属于同一个目标让 AI 应用从“玩具”变成“业务系统”。1.2 整体架构编排层、模型层、扩展层、底座层XXL-AI 的分层很直接一共四层模型接入层统一封装所有大模型供应商的 API屏蔽请求格式、鉴权方式、流式解析差异。Agent 编排层负责流程定义、节点调度、状态传递、回退与人工审核。这是平台的“大脑”。扩展层通过 MCP 接入外部工具通过 SKILL 定义复杂技能通过 RAG 接入知识库。三者独立演进统一被编排层调用。工程化底座包含配置管理、密钥管理、日志、监控、权限、版本发布、任务队列。没有这一层前面做得越漂亮越上线越危险。这个分层的取舍在于每层都能被替换。模型层可以随时新增供应商编排层不感知工具细节扩展层只暴露统一接口底座层独立于业务逻辑。换供应商、换向量库、加新工具都不需要重写核心代码。很多团队一上来就集成 LangChain 或 Semantic Kernel但框架自带的设计假设未必适合你自己的业务。自建这四层以后我发现最大的好处是理解线路非常清楚出了问题你能一眼定位是模型问题、编排问题、工具问题还是知识库问题。2. Agent 编排引擎让多步骤任务真正自动跑起来2.1 节点模型与图结构设计Agent 编排的核心是图结构。我不会用“链表式”的线性流程而是把它建模成一张有向无环图DAG。每次执行都从一个入口节点开始沿着边向后传播直到走到终止节点。节点类型我固定为五类LLM 节点调用大模型做生成、推理、意图识别。工具节点调用 MCP 工具或者内部函数比如查订单、发邮件。条件节点根据前面输出做分支判断类似if/else。聚合节点并行执行多个分支后汇总结果类似join。人工节点暂停流程等待人工审核或补录信息。比如一个“售后退款”流程可以先放一个 LLM 节点做意图分类分类结果进入条件节点如果是退款同时并行调用“订单查询工具”“售后策略知识库检索”两个节点两个结果进入聚合节点再交给 LLM 节点生成退款建议最后到人工节点等主管确认。每个节点在配置层面就是一个 JSON 对象类似{ id: node_intent_classify, type: llm, model: vendor_a/model-xyz, prompt_template: templates/intent_classify_v2, output_variable: intent, next: { refund: node_refund_flow, exchange: node_exchange_flow, other: node_human_handoff } }这种设计的好处是可视化编辑器可以做命令行调度器也可以做。你甚至可以把整个流程保存为 JSON放进 Git 里做版本管理。线上运行的不是“人肉改完的代码”而是可回滚的流程配置。2.2 Agent 之间的消息传递和状态共享多 Agent 编排最常见的问题就是“上下文到底放在哪里”。我踩过的坑是把全部信息塞进同一个大上下文结果流程稍长一点模型就开始丢失前文的细节。XXL-AI 使用的方案是分域状态存储全局状态global_state存用户 ID、订单号、流程版本等所有节点共享的基础信息。节点局部状态local_state存当前节点产生的中间结果比如意图标签、查询出来的物流轨迹。消息日志每个节点的输入输出都完整落库方便回放和审计。节点之间的数据流不靠“把变量塞进 prompt”而是通过显式的input_map和output_map映射。比如聚合节点需要读取两个并行节点的结果就写明input_map: {order_info: node_order_query.output.data, policy: node_policy_retrieval.output.passages}。这样做的好处是每个 Agent 节点只看到自己的局部上下文系统复杂后不会互相污染。代价是要多写一点映射配置但对调试和定位问题来说这点成本远远值回票价。2.3 编排器里的容错、回退和人工审核点流程一旦进了生产会遇到各种意想不到的失败模型返回格式不对、工具接口超时、条件节点表达式报错、知识库检索不到内容。编排器必须有明确的失败策略。我给每个节点配置了三个策略字段retry重试次数和退避时间例如{max_retries: 3, backoff: exponential}。fallback_node当前节点失败后跳到哪个兜底节点。on_failure继续、失败终止、或者转人工。人工审核点也绝不是可选项。金融、客服、审批类流程里AI 能做的是“把信息准备好”最终决策要留给人。实现上是把节点状态置为waiting_for_human流程引擎挂起等外部系统通过 Webhook 回调后恢复。这一块我有非常深的体会最开始的全自动流程看似效率高但真正业务方根本不敢用。加了人工节点后他们才愿意把 AI 从“辅助提效”升级到“流程主力”。编排的第一原则不是全自动是该停的地方必须能停。3. 多供应商接入与统一模型路由3.1 统一调用层与流式协议多供应商接入最忌讳的就是直接散装调用各家 SDK。那样一旦后面要换供应商项目里几十个文件都要改。XXL-AI 做了一个非常薄的ModelGateway层只暴露四个方法generate(prompt, params) - Completionstream_generate(prompt, params) - AsyncIterator[Chunk]generate_with_tools(prompt, tools, params) - ToolCallResultembed(texts) - Vectors每个供应商只需要实现一个适配器。OpenAI Claude、通义、DeepSeek、Ollama 都是同一种姿势接入。流式是最容易出问题的地方。各家流式返回格式不一样有的返回增量文本有的返回完整片段有的还会在流里塞工具调用。统一层必须把流式内容重建成统一的chunk.text、chunk.tool_call、chunk.end_reason。否则下游做流式输出到文件、WebSocket 推送就会有一堆特判逻辑。3.2 路由策略成本、能力、可用性怎么权衡统一接入只是第一步真正有工程含量的是路由策略。我常用的策略有三个维度按能力路由有的模型工具调用稳定有的模型长上下文便宜有的模型中文指令理解更好。平台支持给每个节点指定model_selector规则而不是把所有请求派到同一个默认模型。按成本路由供应商之间的价格差异非常大。日报这种简单任务可以用便宜的模型复杂推理再切贵的模型。成本逻辑也要落到请求粒度平台里每一笔请求都会记录模型单价和消耗 token 数月末账单一眼能看清钱花在了哪里。按可用性路由供应商 A 超时了自动把流量切到供应商 B。这里的路由字段是fallback_models配合重试机制一起工作。多供应商的真正意义不是“比哪家模型更强”而是“任何一家挂了业务都还能跑”。3.3 调用链路的可观测性和成本账单没有可观测性的多供应商接入会很危险。每个请求我都要求至少记录以下几个字段请求 ID全链路追踪用携带的业务流程 ID 和节点 ID供应商、模型名、实际生效的模型路由首 token 延迟、总延迟、token 消耗错误码和错误信息摘要这些信息会写入独立的调用日志表并暴露 Prometheus 指标。日常排障时问“为什么这次回答这么慢”不再靠猜而是直接查链路是模型本身慢还是工具节点卡了还是知识库检索耗时。这也是工程化底座里最重要的一环。如果把多供应商接入比作“插座”统一路由层就是“插线板”。不同厂商的接口电压不同插线板帮你转换成统一标准路由策略则是“哪个电器走哪条线路”成本、速度、稳定性高度可控。4. 扩展机制三件套MCP、SKILL 与 RAG 的配合4.1 MCP把工具接入做成标准协议工具接入是 AI 应用最头疼的环节。内部系统有成百上千个接口每个接口参数、鉴权、返回结构都不一样。如果每个工具都用 hardcode 的方式绑进代码里Agent 编排会变得完全不可维护。MCPModel Context Protocol解决的是“工具接入标准化”的问题。工具提供方实现一个 MCP Server暴露工具名称、参数 Schema 和调用逻辑平台作为 MCP Client 统一发现工具、调用工具。加了新工具不用改 Agent 代码只需要在配置中心注册一个新的 MCP Server 地址。举一个实际例子。订单查询工具原来的调用方式是def fetch_order(order_id): resp requests.get(f{internal_url}/orders/{order_id}, headersauth_headers) return resp.json()接入 MCP 之后工具变成一个独立服务暴露的描述信息类似{ name: get_order_by_id, description: 根据订单ID查询基础订单信息, parameters: { type: object, properties: { order_id: {type: string} }, required: [order_id] } }Agent 层不再关心工具内部怎么实现只把它当成一个可调用的函数。MCP 一定要做超时控制和权限收敛不是所有暴露给 Agent 的工具都适合直接放生产权限。我见过团队把数据库查询工具直接挂给 Agent结果模型生成了一段危险的查询语句虽然没造成事故但也够吓人。4.2 SKILL可复用的业务技能包设计MCP 解决的是“单工具标准化”SKILL 解决的是“复杂流程复用”。打个比方MCP 像工具箱里的扳手、螺丝刀每个都是基础工具SKILL 像“更换轮胎的标准操作流程”需要按固定顺序调用好几个工具还要配合检查清单和提示词模板。一个 SKILL 通常包含四个方面触发条件什么样的输入会选中这个技能。步骤定义按什么顺序调用哪些 LLM 节点、MCP 工具、RAG 检索器。提示词模板当前技能专属的系统提示词和输出格式要求。参数约束哪些参数必填哪些可选输出要符合什么 JSON Schema。技能需要有编码和版本。XXL-AI 里的 SKILL 描述文件类似skill_id: SKILL-AFTER-SALE-001 version: 2.1.0 name: 售后处理技能 triggers: - intent after_sale steps: - action: rag_retrieve knowledge_base: after_sale_policy top_k: 5 - action: mcp_tool tool: get_order_by_id input_from: global_state.order_id - action: llm_generate prompt_template: templates/after_sale_answer_v2 output: global_state.reply_draft - action: node_human_review fallback_to: manualSKILL 和 MCP 的区别非常关键MCP Server 提供的是原子能力SKILL 是带业务语义的流程模板。同一个 “get_order_by_id” 工具在“售后技能”和“订单统计技能”里的调用方式、提示词、后续节点完全不同。只有 SKILL 层才能让业务能力沉淀下来而不是每次新建流程都重新写提示词。4.3 RAG知识库拆解、存储与检索的实战细节RAG 是最容易被低估的部分。很多人以为把文档切块、向量化、扔进向量库就结束了实际根本不是这样。这里我把重点拆成三个环节拆解。中文文档不能直接按 500 字硬切。表格、图片、标题层级、代码片段都要处理。我的经验是先按文档结构切“章节”再按段落切“分块”块之间保留 10-20 个字符的 overlap。每个块都要保留来源文档 ID、章节路径、标题摘要等元数据为后面检索过滤做准备。存储与图片问题。知识库能不能存图片能但要看检索方式。纯向量库直接存图片向量用户问“退货流程图是什么”召回效果并不好。更实用的方式是双通道存储图片本身可以存对象存储知识库里保存图片的文本描述、OCR 结果、图片地址和文字构建的向量。检索时如果命中文本描述再把图返回给前端。这样既保证召回准确也能在对话里显示图片。检索与 RAG 瓶颈。RAG 最大的瓶颈不是向量化模型不够强而是“召回筛选”太粗糙。向量召回只是初筛必须接重排序Rerank把 top 100 的结果压缩成 top 5。还要做混合检索向量召回 关键词召回 元数据过滤。否则客户问“退货时间”你可能会召回一堆关于“退货条件”的内容看起来相关实际答非所问。RAG 第二个典型瓶颈是知识冲突。多个文档对同一问题说法不一致时直接往上扔给模型模型很容易胡编。平台里必须做“证据引用”机制检索结果里把文档来源和原文片段一起传给模型并强制模型在回答后列出引用编号。用户点引用编号能看到原始出处这样既能提升可信度也方便排查知识库里的矛盾内容。4.4 MCP SKILL RAG 怎么组合而不是互相替代这三者经常被混淆但它们解决的问题完全不一样。MCP 管工具接入SKILL 管流程复用RAG 管知识引用。在 XXL-AI 里它们统一被编排层调度。一个典型的多轮任务是这样跑的用户输入“我要退款”。编排层先做意图分类选择“售后 SKILL”。SKILL 第一步触发 RAG 检索从售后政策知识库取回规则片段。第二步调用 MCP 工具查出订单信息和购买记录。第三步把规则片段、订单信息、用户提问拼在一起交给 LLM 节点。LLM 模型生成退款建议附带引用编号。最后进入人工节点等业务员确认后执行退款。这个流程里RAG 提供“规则依据”MCP 提供“数据操作能力”SKILL 负责把前两者组织成稳定流程。三者结合以后Agent 就不再是“嘴皮子选手”而是一个能查、能算、能判断的准业务系统。5. 工程化底座从能跑到能上线之间缺什么5.1 配置管理、密钥与多环境隔离AI 应用工程化和普通后端工程化最大的区别在于它充满了大量非代码配置。提示词模板、模型路由参数、MCP Server 列表、知识库映射、SKILL 版本都属于配置。如果这些配置散落在代码里每改一次都要发版线上协作会非常痛苦。XXL-AI 把配置统一放在配置中心按环境隔离。开发、测试、生产各一套密钥全部走密钥管理服务不写进代码仓库。平台启动时读取配置并缓存配置变更通过热更新接口生效不需要重启服务。多供应商的密钥管理更要小心。我用的是“供应商 用途”双层命名比如vendor_openai_chat_api_key、vendor_anthropic_admin_key。每个密钥字段必须有权限绑定不是所有服务都有权访问所有供应商密钥。审计日志里也要记录“哪个服务在什么时间调用了哪个密钥”避免密钥泄露后无法追踪。5.2 SDK 与 API 边界给业务方交付什么内部平台做得再好业务方接入不方便就等于零。XXL-AI 对外暴露两类接口同步 API 和异步任务 API。同步 API 用于在线问答、实时推理响应时间要求在秒级。异步 API 用于长耗时任务比如批量文档总结、客服工单自动生成。异步任务先提交到消息队列平台回调业务方提供的 Webhook并把结果写入任务表。同时我封装了一个精简版 SDK业务方只需要几行代码就能发起一次 Agent 流程from xxl_ai import XXLClient client XXLClient(api_key..., envprod) result client.run_flow( flow_idafter_sale_flow_v3, user_input订单 20250001 想退货, trace_idreq-abc-123 ) print(result.answer, result.citations)SDK 不是越复杂越好而是要让业务方 5 分钟内跑通第一个流程。很多团队的 AI 平台能力很强但 SDK 文档一塌糊涂最后业务方宁愿自己调模型 API也不愿意用平台。5.3 日志、监控和版本回滚AI 应用的日志不同于普通接口日志。除了请求参数和响应结果必须记录 token 消耗、模型名称、工具调用链、知识库命中的文档 ID。没有这些线上问题会变成“模型回答不正确但不知道为什么不正确”。监控方面我会重点盯三个指标端到端成功率整个流程跑完的比例不只是单次模型调用成功率。工具节点 P95 耗时MCP 工具超时往往拖垮整个流程。RAG 命中率检索后用户采纳回答的比例间接反映知识库质量。版本回滚也要纳入流程设计。流程配置和 SKILL 包都以 Git 仓库管理每次变更生成一个版本号。线上发布后发现效果变差一键回滚到上一版不用等代码重新构建部署。我见过太多平台死在“能跑但是不敢动”。如果每次更新都像拆炸弹业务方会越来越回避新能力。做好版本回滚是给团队上保险。5.4 项目目录与交付规范性XXL-AI 的代码目录遵循按层级划分的原则每层独立成包依赖方向只许向下不许上跳。这样编排层不会直接依赖某个供应商私有 SDK扩展层也不能反过来修改编排器内部状态。交付时还会带上一个“连通性自测脚本”。脚本模拟一次完整流程调用一个供应商模型、调用一个 MCP 工具、检索一次 RAG 知识库、跑通一个最短 Agent 流程。任何一项失败直接告警。这个脚本在出问题排障时也很有用先跑自测能快速判断是环境问题还是平台代码问题。6. 上线后的常见问题与排查记录6.1 最常见的六个坑表格整理如下现象可能原因排查方法供应商请求频繁超时路由策略没配超时和重试检查模型网关的超时参数开启 fallback 模型Agent 明明注册了工具却找不到工具MCP Server 连接失败或工具 schema 不合法先本地启动 MCP Server用命令行请求看返回RAG 答非所问拆块太粗、没有 rerank、关键词召回缺失查看检索结果文档 ID对比 query 和 chunk 的相关性上下文被工具返回内容撑爆工具节点把全量数据塞进局部上下文在工具节点做字段裁剪和摘要只保留必需字段切换供应商后输出格式不一致各模型对 JSON 输出的遵循程度不同统一用 structured output 约束并在编排层做 schema 校验线上改了 SKILL 配置没生效技能版本缓存未刷新检查配置中心缓存 TTL观察热更新日志第一个坑我印象最深。当时某供应商深夜抖动超时策略设置的 30 秒导致整个客服流程全部卡住。后来统一改成“2 次快速重试 5 秒超时 另一供应商兜底”再也没有出现过全流程不可用的情况。第二个坑也非常典型。MCP Server 本身在独立进程里Agent 编排服务启动时如果连接不成功平台的工具列表就是空的。很多现场问题不是代码 bug而是服务注册顺序不对。后来我在自测脚本里加了一个“MCP 健康检查”每 5 分钟检查一次所有注册工具是否存在。6.2 排查技巧与调试工具给 Agent 平台做调试最有效的不是看日志而是“回放”。我把每一次 Agent 流程的执行记录都存成可回放的 JSON包含每个节点的输入输出、模型调用参数、工具返回结果。排障时直接把流程 ID 输进去页面就会展示每一步发生了什么。流式输出截断是另一个高频问题。尤其是把模型流式输出持续写入文件或消息队列时客户端断开连接会导致写入中断。排查时先分清是“客户端断开了”还是“模型输出还没结束”。后来我在流式写入方法里加了“完成标识”和“最后一条 chunk 时间戳”既能判断截断点也能统计异常断流率。调试 MCP 工具时我有个习惯先在本地用命令行把 MCP Server 独立跑起来手动构造一次工具调用确认返回结构确实是{content: [...], metadata: {...}}再接入编排器。这样能过滤掉 80% 的“工具 schema 写错”“服务端路径不对”问题不用反复改业务代码。6.3 一些值得长期坚持的细则这个项目做下来我最想强调的倒不是某个算法多厉害而是几条很朴素的规则规则一提示词也是代码。所有 Prompt 模板必须进 Git 版本库必须标注作者、变更原因、效果对比。没有版本管理的提示词迟早变成“谁也不敢动”的黑洞。规则二模型输出必须做校验。不能假设模型一定返回合法 JSON。编排层在进入下一节点之前先做一次 Schema 校验不合法就重试或转人工。一次校验能避免后续所有节点连锁崩溃。规则三给业务方留后门。无论编排多么自动化都要支持人工介入。一个“人工审核”节点可能拖慢速度但它能保住系统底线。尤其是涉及资金、客诉、对外承诺的场景这条没有商量余地。规则四成本要日结。我每天固定看一次 token 消耗报表哪个流程贵、哪个用户调用频繁一目了然。AI 平台如果不控制成本最后账面上的花费会吓到所有人。这套平台上线以后业务方最大的反馈不是“AI 真聪明”而是“这个流程终于像一个正常的内部系统了”。我觉得这句话比任何技术指标都有价值。做一个 AI 应用开发平台真正难的从来不是接入几个大模型而是把 Agent、MCP、SKILL、RAG 这些能力组织成可维护、可回滚、可观测的工程系统。最后分享一个小技巧调试 MCP 工具的时候先在本地用命令行把服务端跑起来确认返回结构再接入编排器能省掉 80% 的排查时间。工具链越标准你的精力才越能花在真正的业务抽象上而不是每天都和接口格式搏斗。
返回列表