我去年接手一组内部AI项目时,印象最深的一件事:同一个团队的三套系统分别在各自代码里写死了不同厂商的SDK,有的直接调HTTP接口,有的套了一层很薄的封装。结果每次换模型、加工具,都要把业务代码翻一遍,改完还得重新回归老功能。后来我做了一个类似“XXL-AI”的平台,把LLM调用、Agent编排、工具接入和知识检索统一收口,才算真正把AI应用的迭代速度提上来。
这篇文章就围绕XXL-AI这套AI应用开发平台,把我搭建过程中的设计思路、核心模块拆解、工程化落地细节,以及踩过的坑一次性讲清楚。内容偏实操,适合正在做AI平台抽象、Agent应用编排或者想把RAG、MCP、Skill这些能力整合到业务系统里的同学参考。
1. 整体设计思路:为什么需要一个新的AI应用开发平台
1.1 平台要解决的真实痛点
做AI应用早期,大家都会经历一段“野蛮生长”。业务方提出一个智能问答需求,开发同学直接在服务里拼一个RAG流程;另一个团队要做数据分析助手,又自己写了一套Agent循环,调模型、调工具、处理上下文。单看每个demo都跑得挺欢,一旦进入生产环境,问题立刻暴露。
我梳理下来,核心痛点无非四类。
第一是模型供应商锁定。代码直接依赖某个厂商SDK之后,想换模型几乎等于重构。价格波动、新模型发布、供应商稳定性,全都变成不可控因素。
第二是工具接入方式混乱。有人用Function Calling,有人直接让模型生成JSON再自己解析,还有人把工具逻辑写死在Agent代码里。每加一个工具都要动主流程,代码越来越臃肿。
第三是知识库与Agent之间耦合过深。RAG的索引、切片、召回策略散落在业务代码中,Agent很难复用,也无法统一评估效果。
第四是缺少工程化底座。没有统一的链路追踪、测试集、灰度机制,出了问题只能靠“肉眼找日志”。
XXL-AI的定位不是再做一个“大模型套壳”,而是把这些零散能力抽象成平台层:上游统一对接多家模型供应商,中间提供Agent编排引擎,外围通过MCP、SKILL、RAG三种机制扩展能力,底层用一套工程化体系兜底。这样业务方只需要描述“我要一个什么Agent、用哪些工具、喂哪些知识”,平台负责把底座扛住。
1.2 为什么扩展体系偏偏选了MCP、SKILL、RAG这三件套
做平台前我调研过不少方案,见过很多人把“插件”“工具”“知识库”混在一起聊。落到实际开发,它们解决的问题完全不同,最好分开抽象。
MCP(Model Context Protocol)解决的是“Agent如何标准化地调用外部系统”。它相当于给Agent装了一个通用插座,数据库、浏览器、设计稿、内部API,这些原本各家有各家协议的资源,接上MCP之后统一成一套工具调用协议。
SKILL解决的是“多步过程如何沉淀复用”。比如“写一篇行业分析报告”这件事,可能要拆成查资料、列大纲、分章节撰写、风格校准、格式整理多个步骤。把这些步骤封装成一个SKILL,Agent遇到同类任务时直接按这套流程走,比每次从零推理稳定得多。
RAG解决的是“模型不知道的知识怎么补”。企业内部文档、产品手册、实时数据,通过索引和检索注入到生成上下文里,让模型在有限窗口内拿到最新、最相关的信息。
我习惯用一个类比:MCP是插座,SKILL是操作手册,RAG是资料室。Agent本身是那个干活的人,需要接电时用插座,需要按流程干活时翻手册,需要查资料时进资料室。三者职责清晰,组合起来才不打架。
2. 多供应商接入:把“换模型”变成改配置
2.1 供应商适配层怎么做才不出幺蛾子
平台第一个要收口的就是模型调用。我的做法是定义一层统一的Completion抽象,不同供应商各自实现适配器,业务侧只面对一个接口。
class LLMProvider(ABC): @abstractmethod def chat(self, messages, **kwargs) -> Message: pass @abstractmethod def embeddings(self, texts: list[str]) -> list[vector]: pass @abstractmethod def models(self) -> list[ModelInfo]: passOpenAI、通义、文心这些供应商各自写一个实现类,在内部完成消息格式转换、鉴权、重试逻辑。业务代码里永远只出现provider.chat(...),至于背后是哪个模型,全看配置中心的gateway参数。
这一步看起来简单,真正坑人的是细节。比如不同模型对上下文窗口的处理不同,有的需要显式声明max_tokens,有的会自动截断;有的返回里带reasoning_content,有的只会随时间补充信息。适配层必须把这些差异消化掉,对外输出统一的消息结构,否则上层Agent编排时很容易被这些边角情况带偏。
另外embedding模型也要统一接入。RAG通常只依赖一个向量模型,但不同索引库可能有不同的向量维度兼容性问题。适配层里我会把向量维度声明成provider的元数据,索引服务依托该元数据去选择是否重建向量库,省掉很多“为什么相似度变差了”的排查。
2.2 路由与降级策略:不只是做负载均衡
多供应商接入最大的红利是“能用路由策略控制成本和质量”。我在平台里建了一张路由表,规则大致如下。
| 场景 | 路由目标 | 原因 |
|---|---|---|
| 复杂推理、代码生成 | 旗舰模型 | 质量优先,出错成本高 |
| 摘要、分类等短任务 | 轻量模型 | 速度快,成本低 |
| 向量化文本 | 专用Embedding模型 | 性能和价格更优 |
| 供应商A超时或限流 | 自动切到供应商B | 保障可用性 |
| 凌晨低峰批处理任务 | 限价模型 | 对延迟不敏感,可接受离线排队 |
实现上我调整过不少轮次。早期简单按模型名硬编码路由,很快发现一个事实:同一个模型在不同时段的价格并不一样,某些供应商的按量计费深夜时段更低。后来把价格表也做成配置,路由时用“目标成本 + 质量权重”做综合打分,批处理任务在凌晨自动跑低价通道,日常对话保持高响应质量。
降级不能只靠路由,还要考虑任务类型。如果用户正在多轮对话中,突然从旗舰模型降到小模型,可能语气、格式都在逐步退化。我的做法是为会话绑定初始模型档位,只有当连续失败超过阈值时,才允许触发同档降级(比如从旗舰A降到旗舰B),而不是直接跳回小模型。
2.3 一个值得抄作业的切换案例
在我们的平台里,有一类需求很常见:客户说“我现在用OpenAI,想换成国内的模型”。以前遇到这种事,开发要改SDK、改prompt、改参数,一周起步。接入XXL-AI后,客户只需要在配置中心新建一个gateway条目,选好供应商和模型,然后跑一遍平台自带的评测集。
评测集里放了几十个典型问题,涵盖角色扮演、长文本总结、工具调用、拒答策略。系统自动对比新旧模型的输出质量,并给出达标率。如果新模型某些case表现不足,可以针对该case绑定一个SKILL或者调整路由,而不是回滚整个版本。这套“配置驱动 + 评测验收”的流程,让我换模型的时间从几天压缩到几小时。
3. Agent编排:从单轮对话走向多角色协作
3.1 编排引擎的核心抽象
模型接入只是第一步,真正让平台有想象空间的是Agent编排。我做的编排引擎只有三个核心概念:节点、连接、状态。
节点代表一个执行单元,可以是一次LLM调用、一个工具操作、一个条件判断,甚至是另一个子Agent。连接定义了节点之间的流转关系,支持顺序、分支、并行。状态是贯穿整个执行过程的共享上下文,记录每一步的输入输出、中间结果、token消耗。
class AgentNode: id: str type: str # llm / tool / condition / sub_agent config: dict next: list[str] class AgentGraph: nodes: dict[str, AgentNode] entry_points: list[str] state_store: dict很多朋友一开始纠结要不要用Prompt工程来搞定复杂任务,我的体会是:能用一个固定流程描述清楚的任务,就别让模型自由发挥。写一个“客服工单处理Agent”,如果放任模型自己决定调哪些工具、查哪些字段,结果通常是失败的,因为模型要么漏查,要么顺序颠倒。而用编排图明确画出“先查用户信息,再查订单状态,如果异常则转人工”,稳定性会成倍上升。
3.2 计划-执行-反思循环的落地方式
对于更开放的复杂任务,我通常采用“Plan-Execute-Reflect”循环。这不是让模型无脑递归,而是按阶段设计。
- Plan阶段:模型根据用户目标拆解出子任务列表,每个子任务标注所需工具、预期输出。
- Execute阶段:任务按计划依序执行,工具调用结果回填到状态。
- Reflect阶段:模型参照最终目标和已完成子任务,判断是否需要补充查询、修正方法或者直接收尾。
落地时我暴露了一个参数:max_iterations,默认5。因为不加限制的话,模型经常陷入“反思-再尝试-再失败-再反思”的死循环。我自己遇到的最高纪录是一个Agent连续反思14轮,每轮都在改写同一个工具参数。后来我在Reflect节点上加了“较上一次是否有变化”的判断,如果两轮生成的动作完全一致,直接终止并输出当前结果。
3.3 多Agent协作:主管与执行者模式
编排到后期自然会遇到多Agent协作。最稳妥的落地方式是“主管-执行者”模式:主管Agent负责拆解任务、派发、验收结果,执行者Agent各管一摊,比如有的擅长写代码,有的擅长查文档,有的擅长做结构化输出。
主管Agent接收需求 → 拆解为子任务(data_query, code_gen, doc_search ...) → 按子任务分发给对应执行者Agent → 收集执行结果 → 汇总、校验、生成最终回复这里面比较容易踩坑的是上下文隔离。执行者Agent不需要看到主管和别的Agent聊天的全过程,否则token消耗惊人,而且容易“信息过载导致跑偏”。我的做法是每个子任务构建独立的上下文片段,只传必要信息,执行结果的summary再回到主管的上下文中。这个细节让多Agent的稳定性提升非常明显。
4. MCP、SKILL、RAG三大扩展能力拆解
4.1 MCP:用统一协议接入五花八门的工具
MCP最大的价值是把“工具接入”从代码级变成配置级。以前让Agent查数据库,得自己写SQL执行函数、做结果格式化、处理鉴权。现在如果目标系统暴露了MCP服务端,Agent通过MCP客户端直接发现工具、读取工具描述、完成调用,整个过程对Agent来说是标准的。
一个典型的MCP工具信息如下:
{ "name": "query_order_status", "description": "查询订单当前状态,输入订单号,返回物流和相关时间信息", "input_schema": { "type": "object", "properties": { "order_id": {"type": "string"} }, "required": ["order_id"] } }MCP客户端的核心工作就是定期从服务端拉取这个工具列表,交给LLM的Function Calling机制,让模型自己决定何时调、传什么参数。
我在平台里专门做了一个MCP网关层,作用有两个:一是统一管理授权和可见范围,比如某个MCP服务只对特定Agent开放,避免工具被滥用;二是做工具结果的后处理,把过长的原始返回截断成摘要,避免撑爆上下文。
有朋友问过“根据上下文嵌入到Figma MCP怎么授权”,实操上无非三步:在MCP服务端配置你的应用标识和访问令牌,然后在客户端配置对应工具名映射,最后测试一下“列出画布节点”能否正常返回。很多“授权失败”其实是因为访问令牌的scope配少了,少了读权限自然拉不到数据。
另外一个值得表扬的做法是参考一些低代码平台合并MCP的方式:把MCP工具动态渲染成表单或者按钮,让运营人员可以配置“问题关键词→触发某个MCP工具”的规则,降低AI平台的使用门槛。
4.2 SKILL:把一段过程封装成可复用“手艺”
SKILL是我个人最喜欢的一个抽象。它本质上是一套“方法论的序列化描述”,告诉Agent在执行某类任务时应该分几步、每步注意什么、输出格式是什么。
一个SKILL文件通常包含三部分:
- 触发条件:什么样的任务适合用它。
- 执行步骤:有序的步骤清单,每个步骤附带工具调用建议或风格要求。
- 验收标准:怎么判断这个任务干得好不好。
举例来说,“写一份市场分析报告”这个SKILL可以这样描述:
- 明确分析对象和范围,列出必须覆盖的关键维度(市场规模、竞品动态、用户画像、趋势预测)。
- 调用搜索工具收集近3个月的公开资料。
- 用结构化表格整理信息源,标注发布时间和可信度。
- 按“现状-问题-机会-建议”的框架撰写初稿。
- 检查结论是否有信源支撑,避免空泛表述。
- 输出Markdown文档,含执行摘要。
SKILL的好处是让Agent从“每次靠prompt猜”变成“按已验证的一系列方法执行”。团队里恰好有人做得好时可以直接把流程沉淀成文件,新Agent挂载同一个SKILL即可复用。我反复提醒团队:SKILL不要写大而全的通用套话,聚焦“这个领域里真正管用的行动顺序”,比一堆形容词有价值得多。
4.3 RAG:知识库不只是“分期+向量化”
RAG是大家相对熟悉的,但做得好的RAG远不止“把文档切片、丢进向量库、检索TopK”。我在实战中总结过几个容易被忽略的关键点。
一是切片策略必须跟着文档结构走。我见过太多人按固定长度硬切,结果把表格拦腰砍断、把章节结论和依据切到两个块里,检索时只能召回一半内容。正确做法是先解析标题层级和表格结构,按语义段落切分,长度可以不等,但尽量保证每个切片是一个“可独立理解”的信息单元。
二是检索不能只靠向量。向量召回擅长语义相关,但不擅长“精确匹配”。比如用户搜一个平台的内网产品代号,向量召回往往不如关键词精确过滤。我在RAG检索层做的是“多路召回”:向量召回一路、关键词召回一路、结构化知识库查询一路,最后用rerank模型统一排序。
三是上下文组装要讲究。很多RAG效果差,不是检索没召回到正确答案,而是把不相关的块也塞进去,干扰了模型判断。我会做相关性阈值过滤,并且对召回块做摘要压缩,让最终进入Prompt的知识既精炼又足够。
RAG知识库能不能存图片?当然可以,但纯向量化“图片文件”没有意义。真正有效的是对图片做多模态解析,提取出图中文字信息或物体描述后再向量化。比如一份截图里包含产品操作流程,要先OCR和版面分析,把图片转化为可检索的文本描述,用户问“这个界面上的按钮在哪”,系统才能给到准确答案。
本地搭建简易RAG知识库,不少零基础教程都能跑通,但生产级RAG还要解决增量更新、弱引用、权限隔离、回答引用溯源这四个问题。尤其是引用溯源,用户看到AI回答得再漂亮,如果无法回到原始文档,可信度会大打折扣。
5. 工程化底座:把项目从“能跑”拉到“可靠”
5.1 可观测性:链路上每一跳都要看得见
AI应用调试起来难受,很大程度上是因为它的链路太长了:用户输入进来说自然语言,然后被解析成任务,触发工具调用,注入知识,生成模型输出。任何一环出问题,表面症状都可能是“回答不对”。
我做的可观测性体系围绕“Trace”展开,每一条用户请求生成一个全局TraceID,贯穿供应商调用、Agent节点执行、MCP工具返回、RAG检索结果。在平台看板上,可以看到这样的记录:哪个节点耗时多少、调用了哪个模型、消耗了多少token、召回了哪几个文档片段、工具执行是否报错。
这些数据不光用来排查问题,也是做成本分析的基础。我每周都会导出token消耗报表,按供应商、按Agent、按用户维度做透视。很多“模型叫得异常频繁”的情况就是这样抓出来的,比如某个Agent误把普通对话也路由到了旗舰模型,白白消耗预算。
5.2 评估与回归:没有评测集,重构就是赌运气
Agent应用最怕的是“这次改好了,上次的却坏了”。没有评测集做回归,这种问题几乎必然发生。
我的做法是维护三层测试资产:单轮问答集、多轮对话集、端到端任务集。单轮问答集主要验证知识问答和简单工具调用;多轮对话集验证上下文记忆和澄清机制;端到端任务集模拟真实业务流程,比如“用户发起退货请求,Agent完成身份验证、订单查询、退货单创建、结果通知”。
每次平台升级、模型切换、SKILL调整,都要跑一遍三层测试集。输出对比不只是看“回没回答出来”,还要看格式、引用、拒答合理性。实测下来这套机制帮我拦下了至少三次“感觉优化了,实际退步了”的上线事故。
5.3 发布与隔离:多环境各跑各的,互不干扰
工程化的另一块是环境治理。我在XXL-AI里划分了三个环境:
- 开发环境:连真实供应商的沙箱,AB测试很方便。
- 预发环境:使用完整生产数据副本,但对外不可访问。
- 生产环境:只有经过评估的配置才能进入。
三个环境共用一套代码库,差异只在配置中心的gateway和feature flag上。发布一个新SKILL,首先在开发环境跑评测,然后调整预发环境的label绑定,通过后再切换生产环境的路由灰度比例。这样做的好处是,模型供应商升级API版本这类外部变化,也能先在预发环境里验证完,再放量到生产。
6. 高频问题与排查技巧实录
6.1 高频问题速查表
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| Agent提示找不到MCP工具 | 工具列表未刷新/权限未开放 | 检查MCP网关是否成功拉取最新工具列表,核对Agent的可见工具白名单 |
| MCP授权失败 | 访问令牌scope缺失 | 逐项核对权限配置,先用“列出工具”做连通性测试 |
| RAG回答中出现了不相关内容 | 相关性阈值太低 | 检查rerank分数,提高召回过滤阈值,或者检查切块是否包含噪声段落 |
| Agent反复执行相同动作 | Reflect逻辑未判断动作变化 | 在两轮Reflect间做工具参数相似度比对,相同则终止循环 |
| 切换供应商后输出格式乱了 | 适配层没有统一system prompt风格 | 检查供应商适配器的默认prompt和参数映射 |
| 知识库新增文档后检索不到 | 增量索引未触发/向量库分片异常 | 查看索引任务日志,确认切片和向量化流程执行成功 |
| 模型回调token激增 | 上下文未裁剪/工具结果过长 | 开启工具结果摘要,压缩历史消息,限制max_iterations |
6.2 我踩过的三个“看着小、影响大”的坑
第一个坑是MCP工具描述写得太糙。早期为了让模型“自由发挥”,工具描述写得很模糊,结果模型经常用错参数。后来我把每个工具描述都改成交互式文档:什么时候用、参数边界在哪、返回值有哪些字段,模型误用率立刻降下来。
第二个坑是RAG索引缺少“文档生命周期管理”。有一次客户撤掉了一份旧版手册,但向量库里还留着,导致用户反复得到过时回答。后来我加了文档生效时间和状态字段,检索时过滤过期版本,这个体验问题才算根治。
第三个坑是Agent编排时过度并行。早期为了提升速度,把多个独立工具调用并行执行,结果发现某些接口有速率限制,反而整体更慢。后来我在编排引擎里加了“并发预算”,按工具级别控制最大并发数,响应时间反而更稳定。
7. 写在最后的实操体会
如果让我给后来者一个建议,那就是别一上来就追求大而全的Agent编排能力。先把你最常用的工具、知识库、流程固化成MCP、SKILL、RAG三件套,用最朴素的方式跑通,再逐步加编排复杂度。XXL-AI这套平台在我这里最大的价值不是“看起来智能化”,而是让每个AI能力的交付都有标准化路径:接入模型有统一适配器,扩展能力有规范载体,上线发布有评估和灰度。等到你习惯了这种工程化节奏,会发现自己已经在不知不觉中告别了“天天调prompt、天天改代码”的状态。