☰
从脚本到平台:Agent编排、多供应商与MCP/SKILL/RAG工程实践
2026/10/2 5:09:06 网站建设 项目流程

把团队里的Agent项目从一套临时脚本迁到XXL-AI平台,比我想象中要折腾。起初我以为只是把提示词和大模型API调用整理一下,真正动手才发现,Agent应用的复杂度根本不在“调模型”,而在编排、工具接入、知识检索、并发和安全这些工程问题上。这篇文章就围绕XXL-AI的Agent编排、多供应商接入,以及MCP、SKILL、RAG三种扩展机制,聊聊我是怎么理解这套平台的,以及在实际搭售前问答Agent时踩过的坑。如果你正在做Agent开发,或者纠结要不要上平台,这篇文章应该能给你一些参考。

先说结论:XXL-AI不是又一个模型封装SDK,它把Agent运行拆成了“编排状态机 + 多供应商路由 + 可插拔扩展 + 工程化底座”四个核心层。下面我从实际问题出发,逐层拆解。

1. 从“连续调用模型”到“编排Agent”:XXL-AI想解决的问题

1.1 Agent业务与单次大模型调用的本质差距

很多人第一次做Agent项目,习惯性把大模型API调用包一层,然后写一个循环:收到用户问题,拼接提示词,调模型,拿结果,再拼接一轮。这样跑通一个Demo很快,但一旦需求变成“问题可能涉及多个工具、多轮决策、中途需要等待用户确认、某个工具调用失败了要重试”,这段代码就会迅速失控。

我最早做过一个行程规划Agent,需求是帮助用户规划出差路线。看起来简单,实际需要同时调天气API、地图路程计算、日历查询,还要根据用户预算给出方案。用裸脚本写,第一版功能是能跑,但每次改动都像在给一锅粥加料:“如果地图服务超时怎么办”“如果天气接口返回异常怎么办”“如果用户临时改变目的地怎么办”。这些异常和分支逻辑堆在业务代码里,和提示词搅在一起,最后根本没法让团队其他人接手。

Agent业务和单次模型调用的本质差距在于:单次调用是“输入文本 → 输出文本”,而Agent是一个带状态的执行过程。它内部有记忆、有工具调用、有分支决策、有异常恢复。这个过程必须被显式建模,否则代码复杂度会随需求线性爆炸。

1.2 编排层真正管理的:状态、工具与异常恢复

XXL-AI引入Agent编排层后,我最直观的感受是,业务逻辑终于从“大模型调用的夹缝中”抽出来了。编排层负责维护一次任务的完整生命周期,比如状态是idle、tool_calling、waiting_user还是finished、error。每次调用大模型只是状态机里的一个Step,工具执行是另一个Step,不同Step之间通过事件驱动流转。

这样做有个很实际的好处:执行过程可以被持久化,中断后能从最近一个稳定状态恢复。有一次我们线上环境发版,正在跑的一批Agent任务被中断,以前裸脚本只能全部重头跑一遍;换成XXL-AI之后,任务从tool_calling状态恢复,继续执行后续步骤即可。这个能力不是花哨功能,在真实生产环境里非常值钱。

还有人问过“harness和agent区别是什么”。按我的理解,Harness是Agent运行时的执行夹具,负责调用、监控、资源隔离;Agent本身是决策体。XXL-AI的编排运行时就是一种Harness,Skill可以理解成注入到Harness里的可复用决策包。两者配合,而不是对立。

1.3 平台与框架的边界:为什么需要一个底座

框架和平台的区别,我是在多人协作了三个Agent项目之后才真正想明白的。框架给你类和函数,平台给你运行时、控制台、权限、计费、可观测。当团队里五个人同时往一个Agent项目里塞技能和工具时,如果没有统一底座,很快会因为提示词格式不统一、工具权限没人管、日志格式各写各的而炸掉。

XXL-AI把这类公共能力收敛成底座:模型路由走统一出口,工具通过MCP协议注册,知识通过RAG服务挂载,技能以SKILL形式共享。每个人只写自己负责的那个SKILL,平台负责调度和治理。对我来说,这套东西解决的不是“能不能做出Agent”,而是“能不能持续稳定地做出一堆Agent”。

2. 多供应商接入的工程实践:协议统一、路由与故障转移

2.1 为什么AI应用必须做多供应商抽象

如果你只在Demo里用一个模型,多供应商确实是多余设计。但一旦上线,单点依赖的风险立刻暴露:供应商限流、价格波动、某个模型在某类任务上表现突然变差,都需要能快速切换。我甚至遇到过因为并发过高,被供应商临时降到最低配,导致整批任务超时的极端情况。

把大模型供应商当成数据库驱动来做抽象,是工程上的基本常识。应用代码不直接依赖任何一家API,而是依赖一个统一的Provider接口。XXL-AI在这个接口上包了一层路由和容错,应用只声明“我需要一个支持工具调用的高智能模型”,由平台决定最终调谁。

2.2 Provider适配层与统一请求结构

XXL-AI的Provider适配层解决两类问题:接口差异和模型能力差异。不同供应商的请求结构不一样,比如OpenAI风格是messages + tools,Anthropic风格是messages + tools但字段定义不同。平台将这些统一成内部结构,我只需要面向这个结构开发:

字段说明是否必须
model模型标识,如gpt-4o、claude-3-5-sonnet是
messages对话消息数组,支持system/user/assistant/tool是
tools工具定义数组,统一格式描述否
temperature采样温度否
max_tokens输出上限否

工具调用的返回格式也被统一。我们在接入一个订单查询MCP工具时发现,有的模型会把工具参数输出成JSON字符串,有的直接输出对象,有的会在参数里夹带解释性文字。如果不做统一解析层,下游工具根本不敢直接消费这些参数。XXL-AI的运行时会在调用工具前对参数做一次schema校验和类型强制转换,这极大减少了“模型生成非法参数”导致的运行错误。

2.3 路由、配额与故障转移的落地配置

我实际配置多供应商路由时,主要设置了三种策略:优先级路由、权重路由和成本路由。

  • 优先级路由:优先使用主供应商,主供应商不可用时自动切到备选;适合对稳定性要求极高的场景。
  • 权重路由:按比例分配流量,比如主模型70%、备选模型30%,用于灰度验证新模型。
  • 成本路由:按任务场景区分,复杂推理走旗舰模型,普通问答走轻量模型,控制月度账单。

配置上类似这样:

provider: primary: type: openai base_url: https://api.example.com/v1 api_key_env: OPENAI_API_KEY weight: 70 priority: 1 secondary: type: anthropic api_key_env: ANTHROPIC_API_KEY weight: 30 priority: 2 failover: enabled: true max_retries: 3 circuit_breaker: error_threshold: 5 recovery_timeout_s: 30

这里有一个我踩过的坑:如果你只配置了故障转移,但没有配连续错误熔断,某家供应商开始持续超时的时候,系统会傻乎乎地把所有请求都重试到同一家,最后拖垮整体RT。加了熔断逻辑之后,连续报错5次就把该路由置为半开状态,等30秒再做一次探测,效果立竿见影。

3. “MCP + SKILL + RAG”扩展机制:选型逻辑与协同边界

3.1 MCP:给Agent工具层套上软件协议的壳

MCP的全称是Model Context Protocol,本质上是应用层软件协议。有人问“MCP是软件协议,那硬件协议那个概念叫什么来着”,简单说,硬件协议比如USB-C、HDMI是定义物理接口的电气规范和形态,而MCP定义的是程序之间如何用JSON-RPC交换上下文和工具调用数据。两者层级完全不同,MCP更像一个“软件层面的标准接口”。

我用MCP最大的感受是:工具接入终于有标准方式了。之前接一个企业内部订单系统,要么写一个自定义HTTP封装,要么把函数直接注册进系统,换一个项目又要重新接一遍。现在只要把订单查询封装成一个MCP Server,通过stdio或SSE暴露工具列表和调用方法,任何支持MCP Client的Agent平台都能直接复用。

实际项目中,团队最常用的是两类MCP Server:浏览器自动化类和业务系统类。比如浏览器自动化的场景,有人纠结“browser use MCP和playwright MCP有什么区别”。我两个都试过,简单区分:playwright MCP暴露的是“打开页面、点击、输入、截图”这类细粒度操作原语,适合你清楚每一步要做什么的自动化;browser use MCP则偏任务型,它会根据自然语言目标让模型自己规划点击路径,适合不确定操作步骤的探索场景。选型时看你要的是“可控的遥控器”还是“放权的执行者”。

MCP Server的典型实现并不复杂,我写过一个最小的订单查询服务,协议部分大致是:先声明工具列表,再监听调用请求,把结构化参数传进来,返回结果。平台侧只需要配置Server地址和允许暴露的工具白名单。

3.2 SKILL:把解题经验从“提示词”升级为可执行单元

我在没有SKILL概念之前,复用Agent能力的方式是复制提示词。问题是提示词只是文本,没法携带参数校验、工具绑定和自检逻辑。比如我写了一个“客户跟进邮件生成”的提示词,换一个业务场景,提示词要改,调用哪个CRM模板要改,是否允许查历史订单也要改,全靠手动。

XXL-AI的SKILL机制把“一段提示词”扩展成了一个结构化技能包,我通常按下面几块来定义:

skill: name: sales_followup description: 根据客户历史订单和沟通记录生成跟进邮件 trigger: intents: [跟进, 催单, 回访] steps: - step: 获取客户历史订单 tool: order_mcp params: customer_id: $slot.customer_id - step: 获取最近沟通记录 tool: crm_mcp params: keyword: $slot.customer_name - step: 生成邮件正文 model: high_intelligence instruction: 基于以上订单和沟通记录生成专业、简短、无AI腔的跟进邮件 guardrails: - 禁止编造未发生的订单状态 - 如果缺少客户ID则主动提问 output: format: markdown

社区里现在很流行讨论“去AI味的skill”,我的体会是,单靠提示词写“不要客套、不要官方”没有用,真正有效的是在SKILL里增加结构化规则,比如:禁止使用“首先、其次、最后”这类连接词;邮件正文禁止超过三句话客套;必须包含具体数字或时间点。规则越结构化,模型越不容易往套路上飘。

还有人拿“book to skill”做实验,把一本书的解题方法论转成一个SKILL。我试过把一份售后服务手册转成SKILL,核心是把手册里的“判断条件→处理动作→反馈话术”抽取成状态表,而不是把整本手册塞进提示词。结果比直接RAG检索手册更稳定,因为SKILL里已经固化了决策路径。

3.3 RAG:知识库的检索质量、多模态与本地化部署

RAG是这个三件套里最容易被低估的。很多人以为RAG就是“PDF解析+向量库+相似度检索”,做完才发现召回质量一塌糊涂。我在XXL-AI里用RAG服务搭建知识库,第一步不是选向量库,而是梳理文档结构。

切分策略上,我按语义块切分而不是死板按字符数切分。产品手册有章节、表格、参数列表,如果一刀切512字符,表格会被拆得七零八落。我的做法是:表格按“标题+表头+行内容”整体打包;段落按Markdown标题层级优先合并;代码示例独立成块。文本块大小我控制在320到512 tokens之间,太长会稀释相关性,太短则上下文碎片化。

衡量RAG好不好,我盯的核心指标是rag hit rate,也就是检索Top-K结果中真正包含正确答案的比例。如果这个指标低于80%,不建议上生产。有个真实场景:我们上传了产品价格表和FAQ,线上用户问“A套餐包含哪些服务”,系统经常从那批FAQ里召回“套餐怎么退订”的内容,语义接近但答案方向完全不同。后来加了一个reranker重排层,把向量召回结果再按语义相关性精排一次,hit rate才从72%拉到89%。

关于“RAG知识库能存储图片吗”这个问题,答案是能,但要看你怎么用它。简单做法是把图片文件本身存文件系统或对象存储,向量库里只存图片的描述向量和元数据;复杂做法是用多模态模型抽取图片中的文字和表格,生成结构化文本后再走检索。我实际做售后知识库时,很多用户问题涉及“界面截图”,只用OCR文本召回效果一般,最后是让多模态模型给每张截图生成了功能描述,再和OCR文本一同做向量化,召回准确率才明显提升。

如果你对数据出域很敏感,可以走本地化RAG方案。比如用Ollama部署本地embedding模型和本地向量库,把整个RAG链路收在内网。做法不复杂:Ollama拉一个embedding模型,起一个向量库容器,把“切分→embedding→入库→检索”写成脚本。XXL-AI支持配置本地embedding端点,直接替换默认的云端embedding服务,实现知识检索不出内网。

3.4 三种扩展机制如何配合:一个售前场景的切片

MCP、SKILL、RAG不是三选一,而是各管一段。我常用的一句话总结:MCP连接外部世界,RAG引入内部知识,SKILL封装解题行为。

拿售前问答Agent举例:用户问“你们支持私有化部署吗”,Agent先从RAG知识库检索“部署模式”相关文档,如果没有现成答案,就通过MCP的CRM工具查询该客户的行业和规模,再结合SKILL里固化的“私有化部署评估流程”决定是否需要转人工。整个过程里,RAG负责给事实,MCP负责取动态业务数据,SKILL负责规定“先查什么、再判断什么、什么情况下转人工”。

如果只挂一个RAG,Agent会变成“能说不能做”;如果只接MCP,它又缺乏对业务知识的理解;只有SKILL没有前两者,技能就只是空壳。三者叠起来,才是一个完整的可交付Agent能力。

4. 工程化底座:状态机、并发模型、可观测性与安全边界

4.1 状态机是Agent执行的核心骨架

Agent编排器要解决的第一个问题是“这个任务跑到哪一步了”。我用XXL-AI时,平台上每个Agent任务都会暴露当前状态和完整事件日志。比如一个售前Agent任务可以观察到:

  • processing.intent:意图识别完成
  • tool.order_mcp.call:正在调用订单查询工具
  • tool.order_mcp.result:拿到订单结果
  • rag.retrieve:正在检索知识库
  • model.generate:正在生成最终回答
  • finished:任务完成

事件驱动的好处是可以精准定位卡点。上次线上有个任务卡了十几秒没响应,通过日志发现是卡在工具调用等待上,因为目标MCP Server所在网络环境有抖动,触发了超时重试。如果是一个黑盒的Agent循环,这种问题根本无法排查。

4.2 扛并发:从同步调用到任务队列与Worker池

“AI Agent怎么扛并发”是社区里问得很多的问题。我的经验是:别让HTTP请求直接驱动Agent循环。线上真实场景中的Agent往往要多次调用模型和工具,单次请求耗时动辄5到20秒,如果每个用户请求都直接占一个工作线程,系统很快会被拖垮。

XXL-AI的做法是任务化。用户请求进入后先落一个任务队列,Worker池从队列里消费任务,执行Agent状态机。任务里保存了完整上下文,因此可以在任意状态暂停、恢复,也便于水平扩容。

我按常规实践总结了一套参数参考:任务队列容量设5000,Worker池32个,每个Worker并发处理8个Agent任务,单机大概能扛住400个同时在跑的Agent任务。如果任务里有流式输出需求,则通过SSE或WebSocket从Worker侧推给前端,不额外占用网关线程。

这里有个实际问题:模型供应商的并发限制往往比你的Worker池更早到瓶颈。所以必须做两层限流:一层在平台入口,按用户或按场景做令牌桶限流;另一层在Provider适配层,对每个供应商单独控制并发水位。比如某供应商账号最多支持50并发,平台侧就把对应Provider的并发数钳到40,给重试和突发流量留缓冲。

4.3 可观测与成本治理:Trace、计费和评估

Agent项目上线之后最怕什么?怕出了错不知道是模型的问题、工具的问题还是提示词的问题。XXL-AI对每次运行生成一条完整Trace,里面包含每一步的输入输出:模型调用时长、Token消耗、工具调用结果、RAG检索命中情况。我排查问题时,基本是先看Trace里哪个环节耗时最长、哪个环节出现了非预期结果。

成本治理是另一个必须早做的基础设施。每个Agent任务会产生多次模型调用,月度账单很容易吓人。我按场景建立了预算标签,比如“售前问答”和“售后工单”分账,再通过平台计费模块看到每个SKILL的平均单次成本。成本异常时优先检查是否出现“循环调用”:有一次Agent卡在工具调用失败和重试之间,同一个模型被调了十几次,这种必须靠Trace抓。

质量评估上,除了人工抽检,我还会配一个独立的“评测Agent”作为裁判,把用户问题、Agent回答、检索内容一起喂给它打分。这本质上是LLM-as-judge,跑批之后能看到不同SKILL、不同模型版本之间的质量差异,用来决定是否切换路由权重。

4.4 安全边界:工具白名单、防注入与数据脱敏

Agent安全是我最谨慎的一部分。平台上的工具越多,风险面越大。XXL-AI里每个MCP工具都必须声明允许访问的资源域和操作类型,比如一个订单查询工具只允许read,不允许write;一个“发送邮件”工具必须经过二次确认节点才能执行。

数据脱敏也要在平台侧做。日志中心不能直接打印用户手机号、身份证号、订单金额等敏感字段,我们在工具结果进入Trace之前统一做脱敏,这样排查问题时能看到数据结构但看不到敏感值。如果模型回复中需要展示订单金额,则由前端在拿到脱敏后的业务结果后自行格式化。

Prompt注入是我特别提醒团队注意的点。用户输入的内容是数据,不是指令。我们配置SKILL时会对用户输入里的“忽略以上指令”“执行系统命令”等模式做识别,更严格的是在工具参数校验阶段,禁止用户输入直接作为执行类工具的关键参数。比如“下单Agent”里,收货地址和金额必须来自CRM和商品库,而不是用户单方面提供,这能从根本上防止诱导改价之类的问题。

5. 完整实战:在XXL-AI上搭建一个售前问答Agent

5.1 需求拆解与Agent拓扑

我以最近做的一个“售前问答Agent”为例,讲一下完整链路。业务需求是:潜在客户在官网提问,Agent要能解答产品功能、部署方式、报价相关常识;如果客户是留资用户,还可以查询订单或试用状态;客服主管需要能看到每一次对话的处理质量。

拆解下来,Agent需要三类能力:产品知识问答、订单状态查询、销售话术规范。对应到XXL-AI,就是三个SKILL:product_qa、order_status、sales_followup。这三个SKILL共享一个RAG知识库和一个订单MCP工具,但各自的触发条件和步骤不同。

整体拓扑很简单:

  • 用户提问先过意图识别,路由到对应SKILL;
  • product_qa主要走RAG检索,必要时用MCP查询用户所属行业模板;
  • order_status必走订单MCP,同时从RAG检索“订单状态含义”的解释文案;
  • sales_followup组合上述能力,按SKILL固化的邮件模板生成回复。

模型侧我做了两级路由:意图识别用轻量模型,最终回复生成用高智能模型。这是控制成本的关键手段。

5.2 MCP接通订单查询,RAG挂载知识库,SKILL固化销售链路

订单MCP Server的配置我之前已经写过。实际操作中,平台里只需要填Server地址、认证Token和允许暴露的工具名列表。业务系统那边不用改任何代码,只要暴露一个标准的MCP端点即可。

RAG知识库这边,我传了三类文档:产品手册、常见问题FAQ、报价规则。切分参数按语义块进行,表格整体打包,段落按标题层级合并。向量化用了通用embedding模型,文本块约400 tokens。为了处理“图片能存吗”的问题,我让多模态模型给每张产品截图生成了一句话描述,描述文本进入索引,图片源文件存在对象存储。

SKILL方面,我把销售链路固化成可执行步骤:先判断用户是否已有订单或试用记录,再决定推荐内容;如果用户是政府机构或重点企业,自动追加“支持私有化部署”的说明;邮件或在线回复必须避免空泛套话,要求至少包含一个具体的产品功能名称或数据指标。

5.3 实测中的四个典型坑与处理方式

说几个线上实际遇到的坑,都是常规文档里不会写的内容。

第一个坑是Agent反复调用MCP工具导致延迟增加。现象是一个简单问题,Agent为了确认信息连续调了三次订单接口,用户等得很不耐烦。解决方式是给工具调用加结果缓存,同一任务内相同参数的工具结果直接复用;同时在提示词里约束“只有在需要具体订单状态时才调用订单工具,不要为了一般性介绍调用”。

第二个坑是RAG检索到过期价格。产品调价后,老报价单还在知识库里,Agent偶尔会按旧价格回答。处理方式是在文档切分时把“版本号”和“生效日期”写入元数据,构造RAG查询时强制过滤生效日期 <= 当前日期,并在SKILL里约定“价格类问题必须引用最新版本文档”。

第三个坑是主模型故障后切换到备用模型,返回格式不稳定。原来主模型习惯了输出结构化JSON数组,备用模型有时输出Markdown列表,导致前端解析失败。后来我让平台在切换路由时不光换模型,还自动换掉对应的系统提示词模板,并在输出解析层做了“容错提取”兜底。

第四个坑是并发高峰期的供应商限流。演示日流量上来后,某供应商直接拒绝了一部分请求。我们靠两级限流加退避重试解决:平台入口按用户限流,Provider层按供应商并发钳制,同时给重试加入了指数退避而不是全部立即重试。

这些坑单独看都不大,但串在一起,恰恰说明了“Agent能跑通”和“Agent能稳定跑”之间的距离。XXL-AI给我的最大价值,就是把这些运维和工程层面的问题收拢进了平台,让我能把精力放回业务逻辑本身。

最后再分享一个小技巧。如果你也在做类似平台或Agent项目,建议每次上线前跑一轮“异常注入演练”:故意让某个MCP工具超时、让某个RAG索引失效、把某个供应商的密钥改成错的,看Agent是否能优雅降级。我做过几轮之后,系统从“一改配置就崩”变成了“最多提示用户稍后再试”,这才敢把它放到生产环境里持续服务。

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

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

立即咨询