前阵子把内部跑了大半年的 AI 应用开发平台做了次大版本重构,顺手把名字定成了 XXL-AI。同事说这名字像"加大号",倒也贴切——市面上做 Agent 编排、MCP 协议接入、RAG 知识库的工具不少,真到了生产环境,缺的不是某个单点方案,而是一个能把碎片方案粘合起来、扛得住线上流量的底座。
这篇文章把 XXL-AI 的定位思路和落地经验摊开讲:从 Agent 编排模型、多供应商适配层,到 MCP + SKILL + RAG 三种扩展机制的取舍,再到工程化底座里那些"不做会出事"的细节。适合正在自建 Agent 平台、或者纠结"要不要自己搞一套"的开发者和技术决策者参考。项目初期我们也就"要不要直接用现成低代码平台"纠结过,后面越做越清楚:不是工具不够好,而是每一家业务对编排自由度、数据管控、扩展方式的要求不一样,最终拼的还是底座能力。
1. 为什么我最终决定自己攒一个AI应用开发平台
1.1 从"调API"到"攒平台"的三个阶段
我们团队最早做 AI 功能时,跟大多数人一样,就是从调模型 API 开始的。最初就一个 Python 脚本,调 OpenAI 的接口,把 prompt 拼一拼,返回结果解析一下,就上线了。这个阶段很爽,因为单点功能见效快,老板也开心。
第二个阶段就有点难受了。业务方开始提需求:要接 Claude,要接国内云厂商的模型,要支持私有化部署的模型服务。这时候我发现每家 SDK 的调用方式、消息结构、工具调用格式都不一样。OpenAI 的 tool_calls、Anthropic 的 tool_use,字段名不同,嵌套结构不同,连流式返回的格式都各搞各的。我们开始写一堆适配代码,每接一家模型,就要在业务代码里加一堆 if-else。这让我意识到一个问题——模型供应商不该是业务代码里的 if-else,它是一个独立的架构问题。
第三个阶段更复杂:业务开始要 Agent 化。不是说一句"给我调个模型"就行,而是要一个能自己规划步骤、调用多个工具、在多个模型之间切换的完整流程。这时候原来的单体脚本彻底顶不住了。控制流、状态管理、上下文传递、工具调用后的结果回填,这些东西全混在一起,代码根本没法维护。
于是我们被迫重新思考:如果继续用"调 API + 堆业务代码"的方式,每次新需求都会把系统往崩溃边缘推一步。我们要的其实是一个平台——一个把模型接入、编排、扩展、运维统一收口的地方。
1.2 市面方案为什么不够用
当时我们也认真调研过市面上的低代码 AI 平台,像 Dify、Coze 这类。说实话,它们在小步快跑阶段非常香,拖拽节点,配置 prompt,几分钟一个应用就出来了。
但我们的情况有几个硬约束:
第一个是私有化部署和资产归属。我们有一些客户要求数据不出内网,模型调用记录、知识库文档都要放在自己的 Kubernetes 集群里。大部分低代码平台的私有化版本存在功能裁剪,而且升级周期不可控。
第二个是定制自由度和技术债。低代码平台把常用功能封装好了,但一旦你想做一个不常见的编排逻辑,比如"多个 Agent 并行探索后再融合结论",或者"人工审核通过后才允许 Agent 调用某个内网 API",往往就得等平台更新功能,或者被平台的抽象限制住手脚。我更喜欢"框架 + 代码"的模式:框架给通用的部分,特殊逻辑我可以写自定义节点。
第三个是集群内工具链的打通。我们的 Agent 需要调用内部的研发平台 API、数据库、工单系统。用低代码平台,大多通过内置的 HTTP 请求节点或者插件,要自己维护插件开发环境,跟我们的发布系统、监控体系、权限系统打通也很费劲。
所以最后结论很明确:不是现成工具不行,而是"拿别人的平台做深度定制、长期运维"的成本,比"自己搭一个更贴合业务的基础底座"更高。XXL-AI 就此立项。它不是一个要做成大而全的理想化平台,而是一个非常务实的工程化底座,目标就四个字:编排、扩展、可控。
2. Agent编排:从单轮调用到多角色协作
2.1 编排的本质是什么
Agent 编排这个词被用得很多,但我发现团队里很多人对它的理解停留在"把多个 LLM 调用串起来"。这不是编排,这是流水线。
编排的本质是状态管理:系统要知道当前 Agent 处于哪个阶段,下一个动作该由谁决定,在什么条件下跳转,在什么情况下终止。LLM 只是状态转移中的一部分决策者,真正的控制权应该在编排引擎手里,而不是把控制权完全交给模型自由发挥。
我在 XXL-AI 里实现了两种主流编排模式,对应不同场景。第一种是 ReAct 循环,思路很简单:给模型一个任务,让它循环执行"思考 - 调用工具 - 观察结果 - 再思考",直到它认为自己完成了任务或达到最大步数。这个模式适合工具调用密集、步骤不确定的任务,比如"帮我查一下这几个客户的订单状态并汇总异常项"。
第二种是 Plan-Execute 模式,先让模型生成一个整体计划,然后按照计划逐步执行。每个执行步骤可以是一个普通 LLM 调用、一个工具调用,也可以是子 Agent。这个模式更适合复杂项目,比如"写一份市场调研报告",需要先拆解出数据收集、分析框架、文本生成几个阶段。我在实际测试中发现,Plan-Execute 在长任务上的成功率明显高于纯 ReAct,因为模型在每步开始前有全局计划在约束自己,不容易跑偏。
2.2 XXL-AI的编排模型设计
我们的实现没有重新发明轮子,核心是一个有向图加节点注册表。图的节点类型我做了六种:LLM 节点、工具节点、条件分支节点、聚合节点、人工审核节点、子 Agent 节点。边负责传递数据,每条边可以带条件表达式,满足条件才通过。
这个设计的好处是:简单流程可以画成线性图,复杂流程可以走分支、循环、并发。举个实际的例子,我们的代码审查 Agent:
nodes: - id: parse_task type: llm prompt: "从需求描述中提取开发任务清单" - id: analyze type: sub_agent agent: "代码评审员" - id: human_review type: human_approval timeout: 3600 - id: execute_scan type: tool tool: "静态代码扫描" - id: merge_result type: aggregate join: [analyze, execute_scan]可以看到,这里不是一个简单的链式调用,它包含了子 Agent、人工审核、并行工具执行和结果合并。我把这些编排配置做成 YAML 而不是硬编码,产品同学和资深研发都可以直接修改,通过 Git 做版本管理,每次改完能审 diff,能回滚。
Agent 之间的协作方式,我们用的是"消息总线 + 共享画布"。所谓共享画布,是一个结构化的上下文对象,包含任务背景、中间产物、决策记录。多个 Agent 各自只读写自己职责范围内的字段,避免互相污染。比如需求解析 Agent 和编码 Agent 都能读任务描述,但只有编码 Agent 能写代码内容字段。这个设计后来救了我很多次,后面第 3 节的上下文坑会提到。
2.3 编排上的经典坑:死循环、Token失控、上下文污染
这部分是我最想分享的实战内容,全是踩出来的。
死循环是所有 Agent 项目躲不掉的坑。模型在 ReAct 循环里一旦陷入"调用工具 - 得到异常结果 - 重复调用"的循环,轻则浪费 token,重则把下游系统打挂。我们一开始也天真,以为设个最大步数就好了。后来发现不行,有些循环是"步数很多但每次行为略有不同",表面看没死循环,实际上在做无效功。最后我只能上两把锁:一是在循环内部检测"动作是否重复且结果是否一致",如果连续 N 步动作和结果高度相似,直接终止并触发替代流程;二是每个 Agent 有独立的预算计数器——不是步数,而是总 token 消耗,超了就停。项目上线后,被预算计数器救回来的任务比比皆是。
Token 消耗失控,这其实比死循环更阴险。我见过一个看起来运行正常的 Agent,单次任务消耗了 16 万 token,因为它的每轮循环都把前面所有对话历史反复发送。后来我们引入了一个"工作记忆"机制:每次循环只保留与当前动作相关的关键信息摘要,而不是把完整历史全量带上。实测这个改动让单任务 token 消耗平均下降 63%,速度也快了。生产环境就是这么做成本优化的,不是省 prompt 那点小钱,是省架构上浪费的巨款。
上下文污染则是多 Agent 场景的特有问题。早期版本我们为了省事,让所有 Agent 共享同一个全局上下文对象。结果一个 Agent 在中间修改了共同字段,另一个 Agent 读到的数据就变了,导致输出驴唇不对马嘴。排查得头皮发麻。后面学乖了,把共享画布按职责分成命名空间,每个 Agent 默认只读全局字段和写自己的私有字段,要跨 Agent 改数据必须显式声明。这种"显式优于隐式"的约束,让多 Agent 协作的稳定性上了一个大台阶。
3. 多供应商适配层:不把鸡蛋放在一个篮子里
3.1 为什么必须做多供应商,而不是"选一个最好的"
有段时间我们也想"只选最强模型,其他不管"。但做了半年生产环境之后,彻底投降。原因很现实:
第一是故障隔离。云厂商的模型 API 再稳,也出现过单区域故障。如果系统只绑一家,一个上游故障,整个平台的 Agent 全部瘫痪。多供应商的最直接价值是给系统装了一个"备用发动机"。
第二是成本结构。不同模型在不同任务上的性价比差异巨大。简单分类任务用大杯旗舰模型,纯属烧钱;复杂推理反而要用更强的模型,不然出错返工更浪费。合理路由能把整体成本打下来 40%。
第三是模型能力迭代。今天最强的模型,三个月后可能被别家超过。如果架构把供应商写死,换模型就变成动手术;如果从第一天就做了适配层,换模型只是一次配置变更。
3.2 Provider抽象:把各家API改造成统一接口
这块是整个平台的核心技术之一,务必讲透。我们的做法很简单:定义一个中间协议,把所有供应商先翻译成中间协议,再翻译成各家的原生格式。中间协议以 OpenAI 消息格式为基础,稍做扩展。所有上层应用只跟中间协议打交道,感受不到背后是哪个厂商。
class ChatProvider(abc.ABC): @abc.abstractmethod async def chat(self, request: ChatRequest) -> ChatResponse: pass @abc.abstractmethod async def stream_chat(self, request: ChatRequest) -> AsyncIterator[StreamChunk]: pass @abc.abstractmethod def to_tool_calls(self, raw) -> List[ToolCall]: pass每个供应商实现一套 Provider。OpenAI 一套,Anthropic 一套,国产模型如果兼容 OpenAI 格式,就直接走通用 OpenAI 通道,只改 base_url 和 model 名称。接入一个新供应商的平均工时,从最开始的 5 人天降到了半天到一天。
工具调用的协议转换是最坑的地方。OpenAI 的 tool_calls 返回里包含 id、type、function 对象,Anthropic 的 tool_use 是另一种嵌套结构。我们要在 Provider 内部把它们的差异抹平,统一输出ToolCall(function_name, arguments_dict, call_id)。这样上层编排引擎完全不需要关心模型来自哪家,直接拿着结构化参数去执行本地函数和外部工具。
多供应商还牵扯到一个模型路由问题。我实现了一个简易的路由策略,按任务类型和成本预算下发。比如:简单分类走快而便宜的模型,复杂推理走旗舰模型,流式需求走低延迟模型。路由表本身是外部配置,可以随时调整。
3.3 多供应商的真实成本:不是所有模型都听得懂同一句话
做多供应商最大的幻觉是"同样一个 prompt,换模型就能得到同样效果"。现实是,一个在 OpenAI 模型上表现优秀的 prompt,放到另一个模型上一言难尽。有个经典的业务场景——JSON 格式化输出。OpenAI 系模型对 JSON schema 指令理解得很好,输出基本规范;但某些开源模型你让它输出 JSON,它会给你输出带着 Markdown 代码块标记的 JSON,或者直接输出一段解释性文字。
这不是模型差,是"每个模型有自己的表达习惯和指令遵循水平"。我们的应对策略是:在 Provider 适配层之上,再做一个"提示词方言层"。每个模型接入时,附带一套针对该模型调优过的系统提示模板和输出解析器。比如对 JSON 输出不稳的模型,强制使用"只输出 JSON,不要多余文字"的模板,并在解析时不只做json.loads,还要处理代码块包裹、前后杂讯等情况。
还有一个常被忽略的问题:评测。既然支持多供应商、多模型,就得有能横向对比的评测机制。我们内部建立了一个"黄金评测集",包含几百条典型任务和期望输出。每次新接一个模型,或者升级模型的 prompt,都先跑一遍评测集,对比输出质量和成本。没有评测就做模型切换,等于闭眼跳伞。
4. MCP / SKILL / RAG 三种扩展机制怎么选
4.1 MCP:把外部能力变成Agent的"手"
MCP 全称是 Model Context Protocol,模型上下文协议。它解决的核心问题是:Agent 如何安全、标准化地调用外部工具和数据源。
我们团队自己最早集成外部工具时,方式是写无数次单独的 HTTP 调用。每对接一个外部系统,就得写一套鉴权、一套参数映射、一套错误处理。私有化部署之后这个工作量直接爆炸——每个客户的环境都不一样。
MCP 的方式是把工具能力封装成标准化的 Server,Agent 通过 MCP Client 发现工具列表、获取工具描述、发起调用。我把 XXL-AI 的 MCP 支持分了三层:
第一层是协议层,支持 SSE 和 stdio 两种传输方式,客户端和服务端通过 JSON-RPC 通信。第二层是工具注册层,MCP Server 暴露的每个工具都会自动注册到 XXL-AI 的工具中心。第三层是权限层,每个 MCP Server 可以配置可调用的范围和组织。
举个例子,我们接入的一个数据库查询 MCP Server:
{ "name": "mysql-query-server", "base_url": "http://internal-mcp-server:8090", "transport": "sse", "tools": [ "query_db", "get_schema", "analyze_index" ] }Agent 在编排中调用query_db,MCP 层把参数合法性和权限校验好,然后把结构化结果返回给模型。这个过程中模型只需要知道"有这么个工具,参数是这些",完全不需要知道 MySQL 在哪台机器上。这个抽象对内部系统安全非常重要,我们因此可以把数据库账号彻底藏在 MCP Server 内部,Agent 本身接触不到任何明文凭据。
4.2 SKILL:把经验固化成可复用的"打法"
SKILL 这个词在圈子里已被说得很多,但在 XXL-AI 里它的定义很具体:一个 SKILL 是一组提示词模板、工具调用序列、校验规则和回退策略的组合。它描述的是"某种场景下,Agent 应该怎么做"。
Skill 和 MCP 的区别,我用一个比喻:MCP 是工具箱里的一把把工具,SKILL 是老师傅的一整套操作流程。比如"客服接待"这个技能,它会告诉你:先礼貌问候,再查询订单信息,如果客户情绪激烈就触发安抚话术,如果要赔偿就转人工。这个流程里要用到查询订单的 MCP 工具,但 SKILL 本身描述的是流程,不是工具。
来看一个 SKILL 的配置结构:
skill: name: customer_service_handling trigger: intent.match: [after_sale, return_refund] steps: - prompt: "使用标准问候语开场,语气友好" next: query_order - tool: mcp:order/query output: order_info on_failure: fallback_human - condition: "用户情绪为愤怒" action: use_template:angry_customer_reply - tool: mcp:workorder/create output: ticket_no fallback: - action: transfer_human这种"工具 + 流程 + 兜底"的技能封装,比单纯写 prompt 更能保证输出稳定性。我们在实际业务中发现,SKILL 化之后,客服场景的 Agent 首次解决率从 61% 提升到了 84%。原因很简单:光是给模型一段 prompt,它不知道怎么调用工具、调用失败怎么办;SKILL 把所有路径都写清楚了。
SKILL 的管理需要用版本控制。每个 SKILL 都要有版本号、作者、变更记录,发布到生产前要经人审核。否则你无法回答"为什么上周这技能还好好的,这周突然不行了"——大概率是某个人改了一个 SKILL 模板,而你完全不知道。
4.3 RAG:不只是向量检索,而是知识注入管道
RAG 我在这篇文章里不想再重复 Anaconda 和向量数据库的概念普及。直接讲我们在工程化中怎么用的,以及 RAG 在 XXL-AI 里的定位。
RAG 不只是"把文档做 embeddings 存进去,到时候搜一下拼给模型",那是一套一条完整的管道。我们分五步:文档接入、解析与结构化、切分、索引、检索与生成。
文档接入是第一个被轻视的环节。我们一开始只接 PDF 和 Word,后来业务方要求接网页、数据库表、甚至图片里的文字。所以我给 XXL-AI 的 RAG 模块加了插件化解析器:每种格式对应一个 parser,解析结果统一成带页码、章节锚点的结构化块。实测解析 PPT 和扫描版 PDF 这种场景,没有单独的表格提取和 OCR 处理,做出来的检索质量惨不忍睹。
切分策略直接决定检索质量。我们一开始按固定字符数切,500 字一段,结果检索到的片段经常在句子中间断掉,拼给模型后上下文不伦不类。后来改成"按结构切分 + 语义切分"的组合策略:优先保留标题、段落、表格这些结构边界,边界内再用语义模型切。一个看似不起眼的变化,让检索命中率提升了不少。
关于很多人问的"RAG 知识库能不能存图片"——能,但别指望靠 embedding 图片本身解决。我们的方案是:图片先走 OCR 或多模态模型抽取文本描述,再把文本作为索引内容,图片作为附件返回。模型实际生成内容是依赖文本描述的,不是直接"看"图。
在 RAG 的检索环节,我强烈建议引入重排序(rerank)。第一轮用向量召回 Top 50,再用交叉编码器精排取 Top 5,准确率比直接取 Top 5 高很多。重排序有一个模型推理延迟,所以我会设一个 100ms 左右的预算,和业务方商量好。这一步容易被省略,但它确实是效果提升最大的一块。
4.4 三者分工与一个完整的组合案例
在 XXL-AI 里,MCP、SKILL、RAG 三者不是互斥的路线,是三个互补的维度。
我用一张表总结它们的定位:
| 维度 | MCP | SKILL | RAG |
|---|---|---|---|
| 解决什么问题 | Agent 怎么调用外部能力 | Agent 怎么做某件事 | Agent 靠什么回答问题 |
| 抽象层级 | 接口/工具层 | 方法/流程层 | 知识/数据层 |
| 类比 | 工具箱 | 老师傅的手法 | 参考资料库 |
| 典型更新方式 | 加 Server、加工具 | 改流程定义、加版本 | 增量导入文档、调索引 |
把它们合起来才是完整方案。拿我们的"智能售后工单助手"举例:"知识库里有清晰的产品文档和售后手册,SKILL 定义了标准接待流程,MCP 连接了订单中心和工单系统,RAG 在用户提问时检索相关文档,SKILL 调度 RAG 结果作为上下文,并在需要时通过 MCP 查询订单状态或创建工单。"一套下来,单轮会话的完整链路是:意图识别 -> 检索知识 -> 调工单工具 -> 生成回复。任何一个单独的技术点都不足以支撑这个应用,组合起来才能跑通。
5. 工程化底座:真正拉开生产级差距的部分
5.1 可观测性:没有Trace链路,你根本没法排查Agent问题
从工程化角度讲,Agent 有一个很讨厌的特性:不确定性。普通 API 接口,出错了看 error log 大概率能定位;Agent 应用的错误往往是"模型某一步决策不对,后面全跟着错了"。如果没有完整的可观测性,排查一次失败要花半天。
我在 XXL-AI 里做了全链路 Trace 机制。每次 Agent 执行分配一个 trace_id,所有 LLM 调用、工具调用、RAG 检索、分支决策全部带着这个 ID。日志结构上使用事件列表而非单行文本:每个事件记录时间、节点、输入摘要、输出摘要、token 消耗、延迟。这样回放时,整个 Agent 的思考过程就像一部电影一样展开。
这里有一个我自己强烈推荐的细节:Trace 不只是出事之后排查的工具,它也是 prompt 调优的基础数据。我们每次线上问题复盘,都会把 Trace 导出来看,找到那个"模型决策发生偏移的节点",然后针对那个节点的 prompt 做改进。可观测性做得好的团队,AI 应用迭代速度会快很多倍。
5.2 缓存与降级:省成本、保稳定两手抓
Agent 应用有大量相似请求。比如一张工单进来,多个 Agent 都需要初步判断工单类型。如果不加缓存,一个工单会触发好几次相同或高度相似的 LLM 调用。
我用的是语义缓存:在 embedding 层面做相似度匹配,命中率超过阈值的直接返回缓存答案,不再调 LLM。在客服场景里,语义缓存命中率能做到 25%-35% 左右,整体成本下降明显。要注意的是,缓存必须分场景隔离,带时效性的数据(比如库存查询)绝不能缓存太久,我一般默认 5 分钟 TTL,可配置。
降级链路更是多供应商架构里的关键。生产环境的策略是:主供应商失败后,自动切换备供应商;如果两个都不行,就触发模型降级——比如旗舰模型降级到次旗舰模型,保证"有响应但不保证最优质量";再不行就转人工兜底。这个降级策略写成了一张优先级表,线上发生过不止一次"主模型延迟飙高但未报错"的情况,靠这个表快速切到了备用供应商,用户几乎无感知。
5.3 权限、密钥安全与多环境管理
平台化的最后一块拼图是权限和安全。XXL-AI 的权限模型是按组织、项目、环境三层隔离。每个环境(dev / staging / prod)的配置完全独立,密钥存储在密钥管理系统,绝不落地到配置文件里。Agent 工具调用都有专门的审计日志,谁在什么时候通过哪个 Agent 调用了哪个 MCP 工具,全部留痕。
多环境隔离这个点必须强调:AI 应用因为不确定性,在 dev 环境调通的功能,到 prod 环境因为模型版本更新、知识库不同,很可能会出现行为漂移。我们做了配置包机制,每个环境有一份锁定的配置包,包含模型路由表、SKILL 版本、RAG 索引快照。发布新功能先在 staging 用"影子数据"跑测试,没问题再切流量到 prod。
6. 落地过程中的高频问题与解决思路
6.1 最常遇到的五个问题
我把团队在生产环境里遇到的高频问题整理成了一张速查表,供参考:
| 现象 | 根因 | 解决方案 |
|---|---|---|
| 模型返回的 JSON 不可解析 | 输出格式不稳定 | 加格式约束提示词 + 容错解析,解析失败重试并喂入错误信息让模型重新输出 |
| Agent 反复调用同一工具无进展 | 死循环 / 参数错误 | 连续 3 次同工具同参数触发强制终止,记录日志 |
| 长任务执行到一半上下文超限 | 上下文管理不当 | 工作记忆摘要 + 滑动窗口裁剪历史 |
| RAG 检索结果不相关 | 切分策略 / embedding 老旧 | 检查切分块完整性 + rerank 重排 |
| 多供应商模型输出口径不一 | 指令遵循差异 | 每个供应商维护独立 prompt 方言模板 |
6.2 一次线上知识库问答的上线复盘
说一个具体案例。有一家内部团队的知识库问答 Agent 在测试环境表现优秀,上线生产后第一天就出了乱子:用户问一个跨章节的综合问题,RAG 检索结果来自三个不同页面,模型拼出来的回答前后矛盾,而且引用的段落对不上。
排查过程:先把 Trace 调出来看,发现 RAG 检索引擎召回的 Top 3 段落确实来自不同章节,但我们生成答案时只把这三段平平地拼在了一起,没有建立它们之间的层次关系。修复方案分两个层面:一是在知识库侧增加了"章节间关联"预处理——在切分时保留父子标题链,检索结果携带层级上下文;二是生成侧加了"综合回答之前先检查引用一致性"的 SKILL 步骤。这轮的教训是:RAG 的知识组织方式,直接决定 Agent 生成质量的稳定下限,它比 prompt 调优更值得优先投入。
后来我们还发现这个 Agent 在高峰期经常超时,原因是每次请求都同步等 RAG 重排序模型返回。改成流式调用后,首字延迟大幅下降,用户体感好了一个量级。这个细节听起来小,但是生产环境体验的关键分水岭。
6.3 给准备自建平台的朋友几点实在建议
按我们踩坑的顺序,给几条实话:
第一,不要一上来就追求"全场景通用",找一个核心业务场景做深做透。我们第一个场景选了"售后服务问答 + 工单创建",因为它是刚需、边界清晰、能明显节省人工。场景跑通了,再横向复制到其他业务线,平台的价值会越来越清楚。
第二,先搭好可观测性,再做新功能。没有 Trace 之前你改一个 SKILL,出了问题都不知道是该调 prompt 还是该调工具调用顺序。有了 Trace,每一轮改进都能被量化验证,这个反馈闭环是 AI 应用开发效率的核心。
第三,AI 应用的工程化问题,本质上是成本和风险的控制问题。模型输出不稳定是常态,你能做的是把不稳定控制在局部,通过结构化的编排、缓存、降级、校验来兜底。换句话说:设计平台时就要假设模型会出错、外部服务会慢、返回格式会变,然后为这些"必然的意外"留好逃生通道。
这套东西做下来,XXL-AI 已经不只是我们内部业务的一个平台,它更像是一套方法论:把"模型能力"这件不确定的事情,通过工程化手段封装成相对可控的业务能力。过程里踩过的坑远比这篇文章写得多,但每一个坑都让后面跑得更稳。如果在软件工程和 Agent 工程化之间划一道线,XXL-AI 就是在努力把后者也变成一门可以复制、可以运维、可以持续迭代的工程学科。