从零搭建AI应用开发平台:Agent编排、多供应商接入与RAG工程化实践 1. 为什么我会去折腾一个AI应用开发平台去年下半年开始我手头的项目里“AI功能”这四个字出现的频率越来越高。一开始只是接个对话接口后来变成要做知识库问答再后来客户直接甩过来一句“能不能让几个AI角色自己分工干活”。需求一层层加码代码库也跟着膨胀到最后我发现每个项目里都有一坨长得差不多但又不完全一样的“AI胶水层”模型调用、提示词拼装、上下文管理、工具注册、检索召回全是重复劳动。那段时间我试过几种做法。最粗暴的是每个项目复制一份改改参数就用结果就是同一个bug要在五个地方各修一遍。后来想抽个公共库但抽着抽着发现抽象层次没选对业务方要的“编排”和底层要的“调用”混在一起越抽越乱。真正让我下决心做一个平台化的东西是因为一个多角色协作的需求需要让一个负责检索的角色、一个负责总结的角色、一个负责校验的角色串起来跑还要能随时换模型供应商。如果继续用散装代码堆维护成本会直接失控。XXL-AI就是在这个背景下长出来的。它的定位很明确一个AI应用开发平台核心能力围绕四块展开——Agent编排、多供应商接入、MCP SKILL RAG三种扩展方式、以及一套能扛住真实项目的工程化底座。说人话就是它想解决的是“AI功能从demo到上线”这段路上那些又脏又累的活。适合谁来参考如果你正在做AI应用被模型切换、工具接入、知识库检索、多角色协作这些事反复折磨那这篇内容应该能帮你少走一些弯路。我下面会按我实际搭建和踩坑的顺序来讲不讲虚的架构图讲的是每个模块为什么这么设计、实际怎么落地、哪些地方容易翻车。2. 整体设计思路先把边界划清楚再动手2.1 平台要解决的三类核心矛盾在动手之前我把遇到的问题归了归类发现本质上就三类矛盾。第一类是模型供应商的碎片化。今天用这家明天客户要求换那家每家的接口参数、返回结构、流式协议都不一样。如果业务代码直接依赖某一家换供应商就等于重写。所以平台必须有一层统一的模型抽象把“调用一个模型”这件事标准化。第二类是能力扩展的多样性。AI应用要接的东西太多了要调外部工具、要读知识库、要执行特定技能。这些扩展的形态差异很大工具调用是实时的知识库检索是召回式的技能可能是预定义的一段逻辑。如果都用一种方式接要么表达力不够要么实现复杂。所以需要多种扩展机制并存。第三类是从实验到生产的工程落差。demo阶段一个脚本跑通就行生产阶段要考虑并发、超时、重试、日志、可观测性、配置管理。很多AI项目死在从demo到生产的路上就是因为工程化底座没打好。2.2 为什么选“编排”作为核心而不是“调用”一开始我也想过是不是做个统一的模型调用层就够了。但实际项目里单次调用能解决的问题很少。真实需求往往是多步骤的先理解用户意图再决定要不要检索检索完再生成生成完可能还要校验。这就是Agent编排要干的事。我把编排理解成“给AI定义工作流”。一个Agent不是一次调用而是一个有状态、有步骤、能根据中间结果决定下一步的执行单元。多个Agent之间可以串行、并行、条件分支。这样业务方描述需求时说的是“先做A再做B”而不是“调三次接口然后把结果拼起来”。抽象层次对了后面扩展才顺。2.3 三种扩展机制的分工逻辑MCP、SKILL、RAG这三个词现在很热但很多人搞不清它们各自该管什么。我在设计时给它们划了明确的边界。MCP我把它定位成“标准化的工具接入协议”。它解决的是“AI怎么调用外部能力”的问题比如查数据库、调API、操作文件。MCP的价值在于协议统一工具提供方按协议实现一次平台这边就能接进来。SKILL更像是“封装好的能力单元”。一个SKILL可能内部包含多次工具调用、一段提示词逻辑、甚至一个小型工作流。它面向的是“一类任务”比如“生成周报”“做数据清洗”。SKILL是可以被Agent直接调用的高层能力。RAG负责的是“知识注入”。模型本身不知道你公司的内部文档RAG通过检索把相关知识喂给模型。它解决的是知识时效性和私域知识的问题。这三者不是替代关系而是分层协作RAG提供知识MCP提供工具SKILL把知识和工具组合成可复用的能力Agent再把这些能力编排成完整流程。2.4 工程化底座为什么不能省我见过太多项目AI逻辑写得挺漂亮但一上线就各种问题模型超时没处理、并发上来就崩、出了问题查不到日志。工程化底座就是把这些“不性感但致命”的事兜住。具体包括统一的配置管理、调用链路追踪、超时与重试策略、限流熔断、以及一套能看清每次Agent执行过程的观测能力。这部分不做前面三块做得再好也上不了生产。3. 核心模块拆解与实操要点3.1 Agent编排从“调接口”到“定义工作流”Agent编排这块我踩的坑最多。最开始我设计得很复杂支持各种花哨的图结构结果业务方根本用不明白。后来我简化成“步骤 转移条件”的模型反而好用。一个Agent的定义大概长这样它有输入、有若干步骤、每个步骤可以是模型调用、工具调用或子Agent调用步骤之间有转移条件。执行时按条件走走到终止步骤就返回。这个模型足够表达绝大多数需求又不会让使用者懵。实操中几个关键点。第一状态管理要显式。Agent执行过程中的中间结果必须能传递和查看不能藏在闭包里。我一开始图省事把中间变量放在内存对象里结果调试时完全不知道某一步的输入是什么。后来改成每一步的输入输出都记录在上下文对象里排查问题效率高了一个量级。第二超时要分层设置。单个模型调用有超时单个步骤有超时整个Agent执行也有超时。三层超时都要有而且外层要大于内层之和否则内层还没超外层先挂了日志会很难看。第三循环要有硬上限。Agent之间互相调用很容易写出死循环尤其是条件判断写错的时候。我强制要求任何循环结构都必须设置最大迭代次数超过就中断并告警。这个限制救过我好几次。3.2 多供应商接入统一抽象的关键决策多供应商这块核心是设计一个足够抽象又不失表达力的接口。我最终定的模型调用接口包含这几个要素模型标识、消息列表、工具定义、生成参数、流式回调。返回结构统一成“内容 工具调用请求 结束原因”。这里有个关键决策要不要把各家特有的参数暴露出来。我的选择是“通用参数标准化特有参数透传”。比如温度、最大token这些通用参数走标准字段某家特有的什么惩罚系数就走一个扩展字段透传。这样既保证了通用场景的一致性又不至于为了统一而丢掉能力。供应商适配层的实现上我建议每个供应商一个适配器适配器只负责“翻译”——把统一请求翻译成该家格式把该家返回翻译回统一结构。适配器里不要写业务逻辑保持纯粹。这样新增供应商时工作量是可预期的。实测下来流式响应的适配是最麻烦的。各家的流式协议差异很大有的按token推有的按事件推结束标志也不一样。我的做法是在适配器里统一成“增量内容回调 结束回调”两个钩子上层不关心底层怎么推的。3.3 MCP接入协议统一带来的便利与限制MCP作为工具接入协议最大的好处是工具提供方和消费方解耦。工具方按协议实现平台方按协议调用中间不需要为每个工具写适配代码。接入MCP工具时我关注几个点。首先是工具描述的质量。模型是根据工具描述来决定调不调、怎么调的描述写得含糊模型就会乱调。我要求每个工具的描述必须包含“什么时候用”“参数含义”“返回什么”这三样缺一不可。其次是参数校验。模型生成的参数不一定合法MCP层要做基础校验非法参数直接返回错误让模型重试而不是把脏参数传给工具。这个校验能挡掉相当一部分模型幻觉导致的问题。限制也要说清楚。MCP适合“无状态、请求响应式”的工具如果工具本身有复杂状态或者需要长连接硬套MCP协议会很别扭。这种场景我一般用SKILL封装而不是硬塞进MCP。3.4 SKILL机制把复杂能力打包成可复用单元SKILL是我觉得最实用的扩展方式。它把“一类任务怎么做”固化下来业务方调用时只需要给输入不用关心中间步骤。一个SKILL的定义包括名称、描述、输入schema、输出schema、执行逻辑。执行逻辑可以是一段提示词模板、一串工具调用、或者一个小型Agent。关键是要有清晰的输入输出契约这样SKILL才能被组合。我踩过的坑是SKILL粒度。太细了业务方要组合一堆SKILL才能完成一件事还不如直接写代码太粗了复用性差稍微变个需求就得改SKILL。我的经验是一个SKILL对应“一个完整的、有明确业务含义的任务”比如“根据会议记录生成待办列表”就是一个合适的粒度。SKILL的版本管理也很重要。SKILL改了逻辑依赖它的Agent行为可能就变了。我给SKILL加了版本号Agent引用时指定版本这样升级SKILL不会意外影响已有流程。3.5 RAG落地检索质量决定一切RAG这块我花的时间最多因为检索质量直接决定最终效果。模型再强检索回来的东西不相关生成的内容就是胡扯。我的RAG流程是文档切分、向量化、存储、检索、重排、注入。每一步都有讲究。文档切分上固定长度切分是最省事但效果最差的。我后来改成按语义切分尽量保证一个切块是一个完整的语义单元。对于结构化文档按标题层级切分效果更好。向量化模型的选择上中文场景我实测下来通用多语言模型和中文专用模型差距明显中文专用模型召回质量高不少。这个不能省省了后面全白搭。检索环节混合检索比纯向量检索稳。向量检索擅长语义相似关键词检索擅长精确匹配两者结合能覆盖更多情况。我一般用向量检索召回一批再用关键词检索补一批合并后重排。重排这一步很多人省掉但我建议加上。用一个轻量的重排模型对召回结果重新排序能把最相关的顶到前面对最终效果提升明显。注入环节要注意上下文长度。检索回来的内容不能全塞进去要按相关性和长度做取舍。我的做法是设一个token预算按重排分数从高到低填填满为止。3.6 工程化底座那些不性感但保命的东西工程化底座我列几个实际做了的东西。配置管理所有模型、工具、SKILL、RAG的配置都走统一配置中心支持热更新。这样换模型、调参数不用重启服务。链路追踪每次Agent执行生成一个traceId所有模型调用、工具调用、检索操作都挂在这个trace下。出问题时能完整还原一次执行的每一步。超时与重试模型调用默认超时30秒重试2次退避策略用指数退避。工具调用超时按工具类型分别设置。重试要区分“可重试错误”和“不可重试错误”参数错误重试没意义。限流熔断对每个供应商的调用做限流防止某家挂了拖垮整个系统。熔断后走降级逻辑比如切换到备用供应商或返回缓存结果。可观测性关键指标包括调用量、成功率、延迟分布、token消耗。这些指标要能按供应商、按Agent、按SKILL维度看不然优化时找不到方向。4. 完整实操流程从零搭一个可用的Agent4.1 环境准备与基础配置假设从零开始第一步是把基础依赖装好。我用的技术栈是Java为主因为团队熟悉而且生态成熟。核心依赖包括一个Web框架、一个HTTP客户端、一个向量数据库客户端、以及JSON处理库。配置上我建了一个统一的配置文件把模型供应商的密钥、地址、默认参数都放进去。密钥不要硬编码在代码里走环境变量或配置中心。我见过把密钥提交到代码仓库的这种低级错误千万别犯。向量数据库我选的是支持混合检索的方案部署方式看规模小规模单机就够大规模再考虑集群。部署完先跑通一个“写入-检索”的最小闭环确认基础链路没问题再往上搭。4.2 接入第一个模型供应商先接一个供应商跑通全流程不要一上来就接一堆。我一般选一个文档齐全、接口规范的作为第一个。适配器实现分三步。第一步定义统一请求和响应结构。第二步写翻译逻辑把统一请求转成该家格式。第三步写一个测试用例用固定输入验证输出结构正确。这里有个实操技巧把原始响应也记录下来。适配器翻译后的结构是给上层用的但调试时经常需要看原始返回。我在适配器里加了个开关打开时把原始响应也存到日志里排查问题特别有用。跑通单次调用后再测流式。流式要验证增量内容能正确拼接、结束标志能正确识别、异常时能正确中断。4.3 定义并注册一个MCP工具接一个MCP工具先确认工具方是否已经按MCP协议实现。如果没有需要先做协议适配。注册工具时重点是写清楚工具描述。我一般按这个模板写这个工具做什么、什么时候应该调用、每个参数的含义和取值范围、返回值的结构。描述写好后我会实际让模型试几次看它能不能正确调用调不对就回来改描述。参数校验我建议用schema校验定义好每个参数的类型、是否必填、取值范围。模型给的参数先过校验不合法直接返回错误信息让模型根据错误信息重新生成。4.4 封装一个可复用的SKILL以一个实际SKILL为例比如“从一段文本中提取结构化信息”。输入是一段文本和期望的字段列表输出是结构化的JSON。执行逻辑我用了两段提示词第一段让模型识别文本类型和可能包含的字段第二段按字段逐个提取。两段之间加一个校验步骤检查提取结果是否符合预期格式。SKILL的输入输出schema要严格定义这样调用方知道该传什么、能拿到什么。schema也是文档比写一堆说明文字管用。封装完先单独测用各种边界输入测空文本、超长文本、格式混乱的文本。边界情况处理好了组合到Agent里才稳。4.5 搭建RAG知识库RAG搭建我按这个顺序准备文档、切分、向量化、入库、检索测试。文档准备阶段先把格式统一成纯文本或MarkdownPDF和Word先转格式。转格式会丢信息重要文档转完要人工检查。切分我用的策略是“按语义单元切超长再按长度切”。语义单元可以是段落、章节。切分后每个块加元数据比如来源文档、章节标题检索时可以按元数据过滤。向量化用中文专用模型批量处理注意控制并发别把服务打挂。入库时向量和原文、元数据一起存。检索测试是关键。准备一批典型问题看检索结果相不相关。不相关就回去调切分策略或换向量模型。这个过程要反复迭代别指望一次到位。4.6 编排一个多Agent协作流程最后把所有东西串起来。我以一个“智能客服”场景为例用户提问先由一个“意图识别Agent”判断问题类型如果是知识类问题走“RAG问答Agent”如果是操作类问题走“工具调用Agent”复杂问题走“多步推理Agent”。编排定义里每个Agent是一个节点节点之间有转移条件。意图识别Agent的输出决定走哪条分支。每个Agent内部可以调用SKILL、MCP工具、RAG检索。执行时traceId贯穿整个流程每一步的输入输出都记录。测试时先用固定问题跑确认分支正确、结果合理。再用一批真实问题跑统计成功率和延迟。4.7 上线前的工程化检查上线前我有一张检查清单。配置是否都走配置中心、密钥是否安全存储、超时重试是否配置、限流熔断是否生效、日志是否完整、监控指标是否上报、降级方案是否可用。这些逐项确认缺一项都不上。压测也要做。模拟并发请求看系统在压力下的表现。重点看模型调用的延迟分布和错误率以及限流熔断是否按预期工作。5. 常见问题与排查技巧实录5.1 模型调用类问题速查问题现象可能原因排查方向解决思路调用超时网络问题或模型服务过载看超时发生在连接阶段还是响应阶段连接超时查网络响应超时考虑换供应商或加超时返回内容为空提示词问题或模型拒绝看原始响应和结束原因调整提示词检查是否触发安全策略流式中断网络抖动或服务端问题看中断位置和错误码加重试记录中断点支持续传参数报错参数格式或取值不对看错误信息里的参数名对照供应商文档修正参数结果不稳定温度参数过高同一输入多次调用看差异降低温度或加校验步骤5.2 工具调用类问题排查工具调用最常见的问题是模型不调或乱调。不调一般是工具描述没写清楚模型不知道什么时候该用。乱调是描述太宽泛模型觉得什么都能用这个工具。排查时我先把工具描述打印出来自己读一遍看能不能明确判断“什么情况用、什么情况不用”。如果自己都判断不了模型更判断不了。参数错误也常见。模型生成的参数可能类型不对、缺必填项、取值超范围。这些靠schema校验挡校验失败时把具体错误返回给模型让它重试。实测下来给模型明确的错误信息它第二次调对的概率很高。5.3 RAG检索质量优化检索质量差的表现是“答非所问”。排查顺序先看检索回来的内容相不相关再看生成的内容有没有正确使用检索内容。检索不相关先查切分。切分太碎语义不完整切分太大噪声多。调整切分策略后重新入库测试。切分没问题就查向量模型。用几个典型query看召回结果如果明显不相关考虑换模型。中文场景一定要用中文优化的模型。召回相关但排序靠后加重排。重排模型能把相关的顶上来。生成没用检索内容查提示词。提示词里要明确要求“基于提供的资料回答”并给出资料的使用方式。5.4 编排流程的调试技巧编排流程调试最难的是定位是哪一步出了问题。我的做法是每一步都记录输入输出出问题时从后往前看找到第一个输出不符合预期的步骤。条件分支容易写错。我一般把条件表达式单独拿出来测用各种边界值验证分支走向。条件里涉及模型输出的要考虑到模型输出可能不规范加容错处理。循环问题前面说过硬上限必须有。另外循环内的状态要小心每次迭代的状态要正确更新不然容易死循环或结果错误。5.5 我踩过的几个典型坑第一个坑是上下文无限增长。多轮对话时把历史全带上几轮之后token就爆了。后来改成滑动窗口加摘要保留最近几轮原文更早的做摘要。第二个坑是工具调用结果太大。某个工具返回了几百KB的数据直接塞进上下文模型处理不了还浪费token。后来加了结果截断和摘要大结果先摘要再给模型。第三个坑是供应商切换后行为不一致。同一个提示词A家输出正常B家输出跑偏。这是因为各家对提示词的敏感度不同。后来我在适配器层加了提示词微调针对不同供应商做小幅调整。第四个坑是并发下的状态污染。早期实现里Agent的上下文对象是共享的并发时互相干扰。后来改成每次执行创建独立上下文问题解决。6. 一些关于扩展方向的个人想法这套东西搭起来之后我发现它的扩展性比预想的好。MCP、SKILL、RAG三种机制覆盖了大部分扩展需求新增能力时先想清楚属于哪一类然后按对应机制接入就行。后面我打算在几个方向继续打磨。一个是编排的可视化现在定义流程还是靠配置如果能拖拽生成会降低使用门槛。另一个是SKILL的市场化把常用SKILL沉淀下来新项目直接复用。还有RAG的自动化调优切分策略、检索参数这些现在靠人工调如果能根据效果反馈自动优化会省很多事。不过这些都是后话。眼下最重要的还是把基础能力做扎实编排稳定、供应商适配可靠、检索质量过关、工程化到位。这四样做好了上层怎么扩展都不会太离谱。我在实际项目里最大的体会是AI应用开发平台的价值不在于用了多新的技术而在于把那些重复的、易错的、需要经验积累的活标准化了。标准化之后业务方可以专注在业务逻辑上而不是每次都在模型调用和工具接入上重新造轮子。这个价值在项目少的时候不明显项目一多就体现出来了。