AI应用开发平台是我这两年的主战场。从Agent编排到MCP、SKILL、RAG,再到多供应商接入和工程化底座,XXL-AI这套东西算是我把一堆碎片需求揉在一起之后的产物。它不是那种demo级的框架,而是真正给业务团队用的AI应用底座:业务方可以在上面搭一个客服Agent,也可以做一个内部知识库问答,还能让Agent调用现有系统里的工具,完成带流程的动作。这篇文章不是官方文档,而是我作为主要开发者的复盘记录,重点讲清楚为什么这么设计、怎么一步步落地,以及一些只有实跑才会踩到的坑。如果你正在做类似的平台,或者准备在公司内部引入Agent编排和RAG能力,这篇应该能帮你少走不少弯路。
核心方向与整体架构拆解
1. 项目定位:为什么要有XXL-AI
1.1 解决的不是“写个Demo”,而是“让AI在业务里真正跑起来”
我见过太多团队做AI功能,开头都是“接个API,调通就完事”。真正放到生产环境,问题立刻炸出来:模型供应商不统一,今天用这家明天换那家;业务流程需要多步决策,但逻辑散落在业务代码里;知识库要接私有文档,却不知道怎么分块和检索;出了问题只能靠人工看日志,连一次完整调用链都拼不出来。
XXL-AI最开始就是冲着这些问题去的。我的想法很简单:把所有AI应用开发里反复出现的基建问题沉淀成平台能力,让上层的业务流程开发只关心“Agent怎么编排”,而不是重新造一遍轮子。后来用下来的感受是,它确实改变了团队写AI应用的方式——原来一个能稳定运行的Agent要俩星期,现在更多时间花在业务梳理上,技术侧两三天就能把骨架搭出来。
1.2 四个核心支柱,撑起一个AI应用底座
我后来复盘时,把XXL-AI的能力抽象成四个支柱,正好对应项目标题里的几个关键词。
- Agent编排:把大模型调用、工具调用、条件分支、循环、子任务拆解串成一张有状态的执行图。这解决的是“一个Agent怎么把一个复杂任务完整跑下来”的问题。
- 多供应商接入:用一层统一接口把不同模型服务商包装进来,调用方完全不感知背后是哪家模型。流式输出、工具调用、Embedding、多模态输入这些差异,全部在适配层收敛。
- MCP + SKILL + RAG 扩展机制:MCP解决Agent“手不够长”的问题,SKILL解决“特定领域怎么稳定干活”的问题,RAG解决“私有知识怎么进入模型”的问题。三者组合起来,Agent就可以不仅仅是聊天,而是一个可扩展的业务执行体。
- 工程化底座:链路追踪、日志、评测、灰度、配置管理、权限控制。没有这层,前面三个再强也上不了生产。
这四个支柱不是独立存在的。Agent编排是执行引擎,多供应商是外部依赖,MCP、SKILL、RAG是能力扩展,工程化底座是运维保障。后文我会逐个展开,重点讲实操。
Agent编排:从单Agent到多Agent的落地
2. 为什么编排是AI应用的核心骨架
2.1 编排不是“流程图”,而是“决策路径图”
早期我做AI应用,习惯用一个巨大的Prompt让模型完成所有事。效果很不稳定:任务一复杂,模型要么忘记前面说了什么,要么在某个步骤上强行“自由发挥”。后来我意识到,LLM本身不适合做多步骤的确定性控制,它更适合做每一步里的“决策和生成”。
所以Agent编排的本质,是把一个任务拆成一个一个有明确输入输出的节点,节点之间用边连接,由编排引擎负责流转。这就像给模型搭了一个轨道,让它只能沿着轨道跑,每个岔路口才让它做一次选择。相比让模型从头到尾自由生成,这种方式的可控性高很多,也更容易定位问题。
2.2 编排引擎采用“节点 + 边”的图式模型
XXL-AI的编排引擎没有发明什么新概念,核心就是一个有向图。节点类型包括意图识别、Prompt调用、RAG检索、工具调用、条件判断、循环、聚合、子Agent调用。边上面可以带条件,类似“如果意图是查单,就走工具调用节点;如果意图是咨询,就走RAG检索节点”。
工程上我建议把图结构定义为一份JSON配置,而不是直接写死在代码里。原因有三点。第一,配置可以内置到后台管理界面,业务人员也能看懂流程;第二,图的调整不需要重新发版,灰度发布时可以动态切换配置;第三,一次运行会把图的执行记录落下来,后续做回放和排查非常方便。
下面是一个简化后的客服Agent编排配置示例:
{ "id": "customer_service_agent", "nodes": [ { "id": "intent", "type": "classifier", "config": { "prompt": "判断用户意图:咨询产品、查询订单、转人工", "output_var": "intent" } }, { "id": "search_kb", "type": "rag", "config": { "query_var": "user_input", "top_k": 5, "collection": "product_docs" } }, { "id": "query_crm", "type": "tool", "config": { "mcp_server": "internal_crm", "tool": "query_order", "input_map": {"orderId": "slot.order_id"} } }, { "id": "compose", "type": "prompt", "config": { "prompt": "根据上下文生成客服回复", "input_vars": ["intent", "kb_results", "order_result"], "output_var": "final_answer" } } ], "edges": [ {"from": "intent", "to": "search_kb", "condition": "intent == '咨询'"}, {"from": "intent", "to": "query_crm", "condition": "intent == '查询订单'"}, {"from": "search_kb", "to": "compose"}, {"from": "query_crm", "to": "compose"}, {"from": "compose", "to": "__end__"} ] }这个例子虽然简单,但能说明编排引擎的几个关键机制:
- 分类器节点先输出一个intent变量,后续边的条件依赖这个变量。
- RAG节点和工具节点可以分别取到知识库内容、CRM订单数据。
- 最终组合节点把多路结果拼进Prompt,生成回复。
- 不同的路径可以并行,也可以汇合,引擎按图的拓扑顺序执行。
实际平台里,我还支持子Agent调用。比如“投诉处理”这个节点可能不是一个普通Prompt,而是另一个独立的Agent流程。这样可以让单个Agent保持小而专业,再由上层Agent协调它们协作。这就是网上常说的多Agent编排。
3. 多Agent编排的协作模型与状态管理
3.1 中央协调器:一个“老板”指挥一群“员工”
多Agent编排最怕的是Agent之间互相抢话、上下文重叠、死循环。我试验过几种模型,最后稳定下来的是“中央协调器 + 专业子Agent”模式:一个主Agent负责拆任务、调度子Agent、汇总结果;子Agent只处理自己领域的那一小块,不直接互相通信。
比如做一个“项目周报生成Agent”,主Agent会先调用“需求管理Agent”拉取本周需求状态,再调用“工单Agent”获取未关闭工单,然后调用“指标Agent”获取发布成功率,最后汇总成周报。任何一个子Agent挂了,主Agent能感知到异常,选择重试或者跳过,而不是让整个流程卡死。
这种模式还有个好处:每个子Agent可以用不同的模型。简单分类甚至用不上大模型,规则也能处理;复杂总结才上强模型。成本控制也在编排层就解决了。
3.2 状态与记忆:别让Agent变“失忆症”
Agent执行过程中,上下文并不是无限长的。编排引擎需要维护一个“状态容器”,把每个节点的输出写进去,后续节点按需读取。同时要支持记忆分层次:短期记忆是当前对话轮次,长期记忆可以存用户偏好、历史订单,甚至通过RAG从向量库里召回“这个人上一次的需求”。
我在实际开发中踩过一个坑:所有候选结果全部拼进上下文,导致Prompt超过模型窗口上限。后来做了一套上下文管控机制,显式声明每个节点“读取哪些变量、不需要哪些变量”,只有被引用的变量才会进入模型,既省token,也不会让模型被干扰。
3.3 编排中的异常处理与超时控制
大模型接口天生不稳定,超时、断流、非法JSON都遇到过。编排引擎必须在每个节点上做超时控制和重试策略。重试不是无脑重试,要区分错误类型:限流错误等待退避后重试,参数错误立刻停止,上下文超限就自动清理历史再重试一次。
如果子Agent持续失败,编排图里应当有兜底节点,比如生成一条“当前服务繁忙”的话术。宁可让用户看到一句友好提示,也不能让整个流程挂在那里转圈。
MCP、SKILL、RAG:三种扩展机制的玩法与取舍
4. MCP:给Agent一双可以伸缩的手
4.1 为什么MCP协议是“AI应用的外设标准”
MCP(Model Context Protocol)把外部工具暴露给模型这件事标准化了。你可以把它理解成USB-C接口:过去每个外设都要专门一根线,现在统一接口,设备即插即用。放在AI场景里,MCP服务提供方把数据库查询、HTTP请求、文件读写、内部API等等封装成可被发现的工具,Agent通过MCP客户端动态获取工具列表和参数定义,再按需调用。
XXL-AI很早就决定支持MCP,因为我知道靠一个平台内置所有工具是不现实的。业务系统的工具五花八门,必须开放协议让团队自己接入。现在平台里跑的MCP服务有内部CRM、监控系统、文档库、设计稿标注工具等,都是团队各自开发好注册进来的。
4.2 MCP接入实战:从零注册一个工具服务
接入一个MCP服务,核心工作是实现一个“工具描述 + 业务执行”的标准化流程。以一个“查物流状态”的工具为例,伪代码如下:
def get_express_info(order_id: str) -> str: # 调用内部物流API return express_api.query(order_id) def register_to_mcp(): mcp_server.register_tool( name="get_express_info", description="根据订单号查询物流状态", parameters={ "order_id": {"type": "string", "description": "订单号"} }, handler=get_express_info )注册完成后,在XXL-AI的管理后台填上MCP服务的地址和认证信息,平台会自动拉取工具列表,之后Agent编排节点里就能直接选到这个工具。
我在排查“MCP连接不上”的问题时,发现绝大多数原因集中在两点:一是MCP服务地址填成了内网地址,外部执行容器访问不到;二是工具参数定义不规范,导致Agent从模型返回的参数无法正确解析。所以建议接入时先在MCP服务端打印完整的请求/响应报文,确认握手成功再接入平台。
4.3 MCP的安全边界:不能把所有工具都裸奔
这点要重点提醒。MCP给了Agent调用工具的能力,也会放大风险。平台侧必须做好三件事:工具白名单、参数校验、操作审计。白名单决定哪些Agent能调用哪些工具,参数校验防止模型生成越权参数,操作审计保证每次调用都有迹可循。
我见过有人把数据库写入操作也做成MCP工具,结果一个测试Agent乱改数据,复盘时连是谁调用的都查不到。所以工具接入时就要定义好“是否敏感操作”,敏感操作必须走人工审批后才能由Agent执行。
5. SKILL:沉淀“会干活”的领域技能
5.1 SKILL与MCP的区别:一个是能力,一个是工具
如果说MCP是给Agent接外部工具,那SKILL更像是Agent自身掌握的“肌肉记忆”。它包含一套完整的提示词模板、输入参数定义、示例输出、使用约束,甚至可以内置一小段前置处理逻辑。一个好的SKILL能让模型在特定任务上稳定输出,而不是每次靠大模型“现场发挥”。
举个例子:“客服投诉升级”SKILL,它不只是让模型写一段话,而是规定:先判断投诉等级,然后再判断是否需要生成工单,生成工单时字段格式是什么,回复语气要求是什么,哪些话术不能说。模型在这个SKILL约束下做事,出来的结果不会跑偏。
5.2 SKILL的最佳实践:从“提示词片段”升级到“小领域专家”
最开始我做SKILL只是把常用提示词存起来,发现复用率不高。后来改成“输入校验 + 提示词 + 输出规范 + 示例”四件套,效果才好起来。
- 输入校验:明确这个SKILL需要哪些参数,参数类型是什么。比如“打斗动作提示词SKILL”需要角色、场景、动作风格、强度等级,缺参数就直接要求补全,不让模型瞎猜。
- 提示词:把专业领域的方法论写成结构化的指导,让模型按步骤走。
- 输出规范:规定输出格式,比如必须是JSON,包含哪些字段。
- 示例:给至少两到三个高质量示例,模型会模仿示例的格式和深度。
在XXL-AI里,SKILL可以被任意Agent引用,也可以被用户直接当作“专家对话”触发。有些团队把内部业务SOP全部整理成SKILL,效果等同于给Agent做了岗位培训。
5.3 SKILL版本管理与评测
SKILL改一个字都可能影响输出质量,所以我把SKILL纳入版本管理和回归评测。修改之前先跑一遍评测集,对比新旧版本输出,防止“修了A,坏了B”。这件事在工程化章节会再展开。
6. RAG:让Agent“懂”私有知识
6.1 RAG不是单纯“接个向量数据库”
很多团队对RAG的理解就是“文档切一切,存进向量库,查出来拼进Prompt”。实际跑一圈就会发现,效果好不好,取决于很多细节:文档解析格式是否干净、分块策略是否合理、Embedding模型是否匹配领域、检索阈值是否合适、有没有做重排序。
XXL-AI的RAG模块把流程标准化成了五步:文档接入、内容解析、分块与向量化、索引管理、检索与重排。每一步都可以单独配置和优化,而不是一个黑盒。
6.2 分块与重排:效果提升的关键
分块策略我做过很多组实验。固定长度分块(比如512字符)对稳定检索有帮助,但容易切断语义,尤其技术文档里“参数说明”和“示例代码”容易分到两块;按标题段落分块效果更好,段落跨越标题的场景就把标题拼进块内容。重叠量一般设置10%左右,既能保证上下文衔接,又不至于浪费存储。
检索时只做向量相似度召回,效果一般。我建议召回top-20之后加一个重排模型,把真正相关的排到前面,最终只拿top-5拼进上下文。重排模型虽然增加一点耗时,但回答准确率提升非常明显,尤其是知识库内容多、相似片段多的时候。
6.3 RAG知识库能存图片吗?
这是我在社区里看到被问得很多的问题,实际答案是“能,但要想清楚怎么存”。如果Agent需要基于图片内容回答问题,可以走多模态流程:把图片解析成文字描述,和图片一起入库,检索时先按文字匹配,命中后再把图片和描述一起交给多模态模型。如果只是把图片当作附件展示,那就存图片URL或文件路径,和文字块走同一套索引。
更实用的做法是“图文分离再关联”:图片单独存储,在文字块的Metadata里记录关联图片ID,检索到文字块后顺带取出图片。这样既不会让向量索引被二进制数据污染,也能保证最终输出能带图。
6.4 多路召回的工程细节
纯靠向量召回会漏掉关键词精确匹配的场景。我在XXL-AI里做了“向量召回 + 关键词召回”双通道,然后统一重排合并。比如查“订单号ORD-2024-001”,向量检索可能把相似语义的文档都捞出来,关键词精确匹配却能直接锁定那条文档。双通道可以在高精度和高召回之间取一个平衡。
多供应商接入与模型治理
7. 多供应商不是“多套SDK”,而是“一个统一出口”
7.1 统一接口设计:调用方无感切换
平台面向业务开发暴露一个统一LLM接口,不区分具体供应商。实际项目中这个接口包含四个核心能力:文本生成(支持流式)、工具调用(返回结构化参数)、Embedding(向量化)、多模态输入(图片/文档)。每个供应商适配器负责把统一请求转换成自己的格式,再把响应转回统一结构。
业务调用时只需要指定“能力需求”和“模型等级”,比如“需要工具调用能力、质量等级high”,平台通过路由策略选择具体模型。这样模型替换对上层透明,合同到期或者评测不达标的模型随时能换掉。
7.2 路由策略与容灾降级
路由策略不能简单随机,要按场景分。我的经验是至少分三档:快速分类用低成本小模型,通用对话用中等模型,复杂推理和代码生成用大模型。平台配置里可以写路由规则,例如“意图识别节点永远用mini模型”,“代码生成节点如果用A供应商失败,自动切到B供应商的同等模型”。
这里要特别注意“供应商故障转移”的粒度。不能只按供应商整体做容灾,还要按模型和按接口类型做容灾。有时候A供应商的小模型在限流,但大模型是正常的;有时候Embedding接口抖了,但对话接口没问题。适配层要针对这些颗粒度做健康检查和熔断。
7.3 Token成本与配额治理
多供应商背后是真金白银的花费。平台月度账单里有几项必须统计清楚:每个Agent消耗的Token量、每个SKILL调用成本、每次运行成本。否则某个Agent在后台悄悄跑高价模型,月底账单让人肉痛。
我习惯在统一接口层强制记录三类数据:输入Token、输出Token、模型单价。每次请求结束后更新项目预算,超过阈值就自动切到低价模型或拦截请求。业务方想在“高成本模型”和“更稳定的结果”之间做选择,需要明确的成本数字支持,而这些数据都应该在平台上自助可查。
工程化底座:可观测、评测与发布
8. 为什么AI应用更需要工程化底座
8.1 全链路追踪:一次Agent运行的可视化回放
普通接口日志只记录“请求参数”和“返回结果”,但Agent编排的运行链路复杂得多:一个用户问题可能触发十多个节点,节点间有数据传递,还有模型调用和工具调用。排查问题不能靠“事后翻日志拼时间线”,必须靠全链路追踪。
XXL-AI里每次运行都会生成一个TraceID,从用户请求到最终回复,每个节点的执行耗时、输入输出摘要、Token消耗、命中的RAG文档、调用的MCP工具全部串在一条时间线上。可视化页面把图结构渲染出来,坏节点标红,点开就能看到当时的Prompt和模型返回值。
8.2 评测集与自动回归:防“模型漂移”和“配置漂移”
大模型版本升级、Prompt微调、SKILL改动,都可能导致原本正常的功能变差。我用两种评测:基于规则的断言(如必须包含订单号、回复长度小于500字)和基于LLM的打分(从准确性、完整性、语气三个维度评分)。每个需要稳定的Agent都配置一个评测集,每次改动配置后自动跑一遍,分数低于基线则可以直接阻止发布。
这个机制帮我挡下过很多次“肉眼觉得没问题但实际已退化”的变更。没有评测集的AI应用,就像一个没有单元测试的老项目,改起来心里没底。
8.3 灰度发布与配置管理
模型替换、SKILL更新、编排图变更,都不能全量直接上。平台里对每个Agent都支持“版本化灰度”,先让5%的流量跑到新配置上,对比错误率、耗时、用户举报率,再逐步放量。一旦异常指标超过阈值,自动回滚到上一个版本。
配置管理上,我把Agent配置、SKILL文件、MCP注册信息全部当成代码管,走Git仓库和CI。谁改了什么、为什么改、有没有过评测,全流程留痕。后来团队有人说这比“在后台网页里硬改配置”踏实太多,确实如此。
实操中的常见问题与排查技巧
9. 高频问题排查实录
我在开发和内部推广XXL-AI的过程中,积累了不少实际问题的排查经验。这里挑几个高频问题做成速查表,很多都是搜索引擎里也经常有人问的。
| 常见问题 | 典型表象 | 排查思路 | 最终解决方案 |
|---|---|---|---|
| 多Agent上下文混乱 | 子Agent回答内容串场,比如查工单的Agent回答了库存问题 | 检查状态容器变量名是否冲突、子Agent是否读取了本不该读的全局变量 | 严格限定每个子Agent只能声明读自己的输入变量,不允许访问全局状态 |
| MCP工具调用失败 | Agent报“找不到工具”或“参数解析失败” | 先手动执行MCP工具确认服务正常,再看平台拉取的工具描述是否准确,最后查模型返回的参数是否匹配定义 | 完善MCP工具描述,增加参数示例;对模型返回做一次schema的强制转换 |
| RAG查询召回不准 | 问了明确问题,检索出来的文档完全无关 | 排查Embedding模型是否与领域匹配,分块是否切碎了语义,阈值是否过严 | 换成领域微调后的Embedding模型;按标题/段落分块;增加重排模型 |
| SKILL不生效 | Agent没有按照SKILL里的要求输出 | 确认SKILL是否被正确引用到Agent配置里,检查输入的参数是否满足SKILL校验条件 | 在SKILL被触发时记录一条日志,输出当前参数快照;增加SKILL命中测试节点 |
| 模型限流导致运行失败 | 部分节点偶发超时,影响整个流程 | 看Trace确认是哪个节点失败,判断失败类型是限流还是服务端错误 | 对限流错误做指数退避重试,重试两次仍失败则走降级模型 |
10. 踩坑后的几条心得
10.1 不要过早追求“全自动Agent”
我在项目初期设计过一个“完全自主决策”的Agent,希望它自己决定调用哪些工具、怎么拆解任务。结果在真实业务里完全不可控。后来改用“编排图 + 局部自主决策”:主干流程用配置决定,模型只需要在节点内部做选择。稳定性和灵活性之间必须有取舍,至少现阶段,“半自动”才是生产可用的形态。
10.2 所有扩展能力都要“先有日志,再有功能”
MCP工具、SKILL、RAG接入后,第一件事不是调通效果,而是先确认平台能不能完整记录“谁在什么时候用了什么、输入输出是什么”。没有日志,出了问题就是黑盒,连排查方向都找不到。XXL-AI后期能快速定位问题,全靠很早就把全链路追踪建好了。
10.3 评测集是长期资产,不是一次性工作
每个Agent上线前,我都会花时间把评测集做得尽量贴近真实用户输入。后续每次迭代,这些评测集都会帮忙守住质量标准。除了“正确回答”这种正向用例,还要加“拒答用例”,比如用户问违禁内容,Agent必须有礼貌拒绝,而不是硬答。这类边界用例最容易暴露配置问题。
10.4 让SKILL和MCP工具走代码评审与CI
我个人最推荐的一条经验:所有SKILL和MCP工具定义,都不要在后台网页里直接改,而是放到代码仓库走评审和版本发布。项目初期团队图省事,直接在管理后台改了一个SKILL的提示词,结果一次误改导致生产环境输出严重偏离主题,排查了一个下午。后来把定义入库、生成Diff、强制关联评测结果,这类问题几乎绝迹。
后续扩展与个人体会
XXL-AI做到现在,核心价值已经不只是“一个平台”,而是一套AI应用开发的工程方法论。Agent编排让复杂任务可控,MCP让外部工具接入标准化,SKILL让领域经验可沉淀,RAG让私有知识可注入,工程化底座让这些能力敢上生产。每个团队的具体场景可能不一样,但底层的这条链路是可以复用的。
我自己的感受是,AI应用开发正在从“拼Prompt”走向“拼工程体系”。谁能更快地管理好模型供应商、更稳定地编排任务、更完整地观测运行过程,谁就能在AI落地上领先半个身位。
最后分享一个小技巧:当你不知道某个Agent为什么表现不稳定的原因时,把它的一次完整Trace导出来,用“回放模式”重新跑一遍,并且每到一个节点暂停一下,看看状态容器里的数据变化。这个习惯帮我找到了大量“看起来没有错但结果不对”的问题。希望大家也能用这个思路,把AI应用的稳定性真正握在自己手里。