从去年开始,我一直在做一个偏底层的智能体基础设施项目,代号"Agent-Reach"。这个项目的起因很朴素:智能体(Agent)单体演示都好做,但一旦到了多智能体协作、跨部门复用、甚至跨团队交接的场景,连接和触达就成了最大的瓶颈。本文不是一篇项目宣传稿,而是把我在设计 Agent-Reach 过程中踩过的坑、做过的取舍、以及最终沉淀下来的架构思路完整梳理一遍。如果你正在构建多 Agent 系统,或者正准备给现有的单 Agent 项目加一层协作底座,这篇内容应该能帮你省掉不少试错时间。
我先直接说清楚 Agent-Reach 是什么:它不是一个 Agent 框架,不负责智能体的思考与决策;它是一层"连接与触达"基础设施,解决的是 Agent 之间"如何被发现、如何被信任、如何可靠地把任务送达到位"的问题。在设计上,它借鉴了微服务领域成熟的服务注册、负载均衡、熔断限流等思想,但针对智能体的动态性、不确定性和语义多样性做了大量适配改造。下面我从需求拆解开始,一步步聊到架构细节、协议设计、部署落地和避坑经验。
1. 为什么需要 Agent-Reach:智能体协作的卡点不在"聪明",而在"连接"
1.1 智能体孤岛:各搞各的 Agent,谁也找不到谁
先描述一个我实际遇到的场景。某业务方有多个独立的智能体能力:客服助手、订单查询、售后处理、库存查询。每个 Agent 都是单独项目组开发,各自暴露一套 HTTP 接口,各有各的鉴权方式,有的接口是同步返回,有的是异步回调。表面上看"四个 Agent 部署上线了",可真要让其中的主控 Agent 在用户问一句"我想退掉昨天买的那双鞋"时,同时调起订单查询 Agent、售后 Agent、库存 Agent,问题就来了:
- 主控 Agent 怎么知道售后 Agent 有个
create_refund能力?靠硬编码 URL 和手工维护文档。 - 订单查询 Agent 返回的是明文 JSON,售后 Agent 要求带上签名头,谁能负责这个适配?
- 某 Agent 半夜升级重启,主控 Agent 还在往旧的地址上发请求,等超时重试才发现对方已经换了实例。
这些问题本质上不是"智能"问题,而是连接与触达的工程问题。智能体越做越多,协作的复杂度就从"单个 Agent 的推理能力"转移到了"Agent 之间的链路质量"上。Agent-Reach 就是在这个背景下立项的:先别管 Agent 内部怎么想,先解决 Agent 之间"找得到、连得上、传得稳、算得清"。
1.2 四个核心目标:注册、发现、路由、审计
我把 Agent-Reach 的需求收敛成四个核心目标,后面所有的架构决策都围绕这四个点盘旋:
- 注册(Registry):每一个智能体接入平台时,都要登记自己的身份信息、能力描述、接入端点、运行状态。这个注册不是简单存一个 IP 和端口,而是要保存机器可读的"能力元数据",比如"我能处理订单退款,需要的入参是 order_id 和 reason"。
- 发现(Discovery):任意一个 Agent 想调用另一个 Agent 时,不是靠查文档,而是通过平台按能力语义去查询匹配。调用方只需要表达"我想找个能干退款活的",剩下交给 Agent-Reach。
- 路由与触达(Reach):找到目标之后,请求怎么送过去?是同步 HTTP、异步消息、还是流式响应?要不要做负载均衡、重试、熔断?Agent-Reach 提供统一的路由层,让调用方不需要关心目标 Agent 的具体部署形态。
- 审计与观测(Observability):每次跨 Agent 调用的入参、出参、耗时、结果、失败原因都要有完整记录。多 Agent 系统一旦出问题,没有调用链追踪,排查起来会非常痛苦。
这样设计的好处是把"能力"和"位置"解耦:Agent 的能力是相对稳定的,位置却可能随时变化。Agent-Reach 把位置信息收归平台管理,能力信息通过注册协议开放给整个协作网络,等于给每个 Agent 发了一张动态更新的名片。
2. 核心架构拆解:注册中心、发现服务、路由引擎三层模型
Agent-Reach 的整体架构遵循一个简单的三层模型,这也是我刻意保持克制的部分:能用成熟方案就不自己造轮子,但轮子之间的"胶水层"必须自研,因为这部分才是领域壁垒所在。
2.1 注册中心:Agent 的"身份证"和"能力简历"放在哪
第一层是注册中心,我建议直接基于 Etcd 或 Consul 构建,不要自己写存储。选型的核心考量是:Agent 注册信息对读写时延的容忍度很低,但数据量并不大——假设企业内有几百上千个 Agent,每个 Agent 的元数据撑死也就几 KB,总量不会超过几十 MB。这种体量下,Etcd 的 watch 机制和强一致性非常合适,能让我们在实例上下线时第一时间感知。
比较关键的是注册信息的结构设计。我只存三类东西:
- 身份组(identity):agent_id、版本号、所属命名空间(namespace)、负责人。命名空间这个概念很重要,它天然解决了多个团队各管各的 Agent 时的权限隔离问题,比如
order-domain和after-sales-domain各管各的,互不可见,除非显式授权。 - 能力组(capability):一份统一的 JSON Schema,描述这个 Agent 能干什么、入参出参长什么样。比如“退款创建”能力就是
capability.create_refund,入参order_id、reason、amount,出参refund_id、status。 - 接入组(endpoint):协议类型(http/grpc/mq)、目标地址、超时建议值、支持的并发上限、QPS 水位。接入组允许配置多个地址,用于多副本负载均衡,也允许配置权重。
我在实现时给注册数据加了一个ttl字段,默认 30 秒。执行方式是 Agent 客户端定期心跳续租,每次续租会把 TTL 重置。这比靠 TCP 长连接判断存活更简单可靠,因为 Agent 可能因为 GC 停顿、阻塞调用等导致假死,TTL 机制能保证这类异常实例自动被清理。
这里有一个非常容易踩的坑,我先提前说:不要为了省事把 Agent 的能力描述写成人话。很多团队第一版注册上去的是“处理订单退款”这种自然语言描述,看起来方便,但后续做语义匹配时机器很难处理同义表达,比如“办理退钱”“我要退货”都可能对应同一个能力。Agent-Reach 强制要求能力描述使用结构化的 JSON Schema,并且鼓励在 schema 里带examples字段,给每个参数给一两个典型取值,这样下游做样例匹配和在线调试都方便得多。
2.2 发现服务:基于能力语义的匹配,而不是字符串相等
第二层是发现服务。大多数微服务场景的发现都是精确匹配:拿着服务名查实例列表。但智能体场景有个很大的差异——调用方经常不知道目标 Agent 的准确名字,只能描述"我要什么"。所以我做了两级发现:
- 第一级:能力名匹配。调用方声明需要
create_refund能力,Agent-Reach 去注册中心查所有声明了capability.create_refund的 Agent。这一级基本等价于传统的服务发现,速度快,适合确定性的内部调用。 - 第二级:语义匹配兜底。当调用方没法给准确能力名,只能给一段意图描述(比如"用户想退款,帮我找一个能干这事的 Agent"),Agent-Reach 会把注册中心里的能力 Schema 连同
examples送到一个本地 Embedding 模型做向量相似度检索,召回 Top-N 候选。这个方案在实测中把自然语言意图到能力的匹配准确率做到了可用的水平,而且完全内网部署,避免把业务意图数据送到外部。
我后来回顾这个设计,觉得第二级语义发现是 Agent-Reach 区别于普通 RPC 服务框架的最大亮点。但要注意,语义发现只适合"候选推荐",绝对不能让 Agent 在无人工干预的情况下直接按自然语言匹配结果做生产调用,风险太大。正确姿势是:语义发现的结果作为建议路由展示给编排层,编排层如果拿不准,回退到让用户确认。
2.3 路由引擎:同步、异步、流式三种触达模式一次收编
第三层是路由引擎,也是整个 Agent-Reach 里坑最密集的地方。先明确它的职责:拿到调用方的请求和目标 Agent 的端点信息,按协议转发、追踪、返回结果,并在失败时执行重试或熔断策略。
我在设计路由模式时遇到的第一道坎:不同 Agent 的通信模式完全不同。有的 Agent 接口是同步的,2 秒内给结果;有的 Agent 是异步的,先返回一个task_id,跑完再回调;还有的 Agent 更适合长连接流式返回,比如实时生成内容的 Agent,逐字逐句往外吐。把这三类模式统一收编,是路由层设计成败的关键。
我的最终方案是定义三种路由类型,通过route_mode字段区分:
sync: 路由引擎阻塞等待目标 Agent 返回,这是默认模式,适合确定性任务。async: 路由引擎只负责把请求送达,目标 Agent 立即返回task_id,后续结果通过 Agent-Reach 的 Webhook/消息通道回收。stream: 路由引擎和 Agent 建立长连接,以 SSE(Server-Sent Events)或 gRPC 流式协议持续下发结果,适合 Token 流式输出场景。
为了统一处理,Agent-Reach 内部把所有跨 Agent 通信都封装成一个"触达请求"(Reach Request)对象,里面包含请求 ID、调用方身份、目标能力、载荷数据、路由模式、超时时间、幂等键。不管底层是 HTTP 还是 gRPC 还是消息队列,对外暴露的 API 风格一致,调用方 Agent 不需要感知底层差异。这是一个非常重要的编码体验设计,否则每接入一个新的 Agent,调用方就要写一套不同的客户端适配代码。
2.4 与 MCP / 智能体框架生态的关系:做减法而不是做竞争
做 Agent-Reach 的时候,MCP(Model Context Protocol)还没像今天这样普及。等到社区里 MCP 生态热闹起来,团队内部也讨论过:既然有 MCP 了,还有必要自研一个 Agent-Reach 吗?
我的判断是,两者并不冲突,但边界要划清楚。MCP 解决的是"智能体如何标准化地调用外部工具"的问题,它规定的是一份工具清单和调用协议;Agent-Reach 解决的是"智能体之间如何动态互找、互信、互通"的问题,它关注的是整个 Agent 网络的组织形态和可靠性。映射到网络分层,MCP 更像是智能体的"应用层协议",而 Agent-Reach 更像是智能体的"基础设施层协议"。
所以在实现上,Agent-Reach 对 MCP 生态做了一层适配:一个 Agent 既可以直接通过 Agent-Reach SDK 接入,也可以暴露成标准 MCP Server,由 Agent-Reach 的 MCP 网关统一代理。这样,企业内部已有的 MCP 工具不需要改造就能接入 Agent-Reach 的网络,反过来 Agent-Reach 上的 Agent 也能被外部的 MCP 客户端调用。这块适配层代码量不大,但价值极高,等于给两套生态之间修了一座桥。
3. 协议与消息设计:Agent 之间对话,如何做到不丢、不乱、不串
架构定了之后,真正烧脑的是通信协议。智能体协作和普通 RPC 有很大不同:调用链可能很长、每跳都可能由 LLM 参与决策、结果可能是不确定性的(有时成功、有时失败、有时给不出结论)。所以消息协议的设计必须为这些特性留出余量。
3.1 触达信封(Envelope):每个请求都自带"护照"和"行程单"
我把跨 Agent 消息的统一格式叫 Envelope(信封),它承担了两个职责:认证与追踪。Envelope 的关键字段如下:
| 字段 | 含义 | 设计考量 |
|---|---|---|
request_id | 全局唯一请求 ID | 用 UUID,不可重复 |
trace_id | 链路追踪 ID | 整条调用链共享,跨 Agent 传递 |
span_id | 当前跳 ID | 每次触达生成新的 span,父 span 由parent_span_id引用 |
tenant_id | 租户/命名空间 | 用于隔离与鉴权 |
agent_id | 发起方 Agent 标识 | 接收入方校验白名单 |
auth_token | 短期访问令牌 | JWT,TTL 控制在 5 分钟,动态刷新 |
idempotency_key | 幂等键 | 由调用方生成,目标 Agent 用于去重 |
route_mode | 同步/异步/流式标记 | 决定路由引擎的处理方式 |
payload | 业务载荷 | 结构化 JSON |
信封设计有一条铁律:业务载荷必须能脱离信封独立理解。也就是说,目标 Agent 拿到payload后,即使不看其他字段,也应该能正确处理业务。这保证了消息可以被持久化、重放、离线分析,也为将来接入消息队列做异步批处理留了后路。
3.2 一次触达的完整生命周期:从发起到确认的六步
以一次同步调用为例,我把 Agent-Reach 的一次触达拆成六个阶段,每个阶段都有明确的状态记录:
- Route 阶段:调用方 SDK 向路由引擎发起触达请求,附带目标能力名和载荷。
- Match 阶段:路由引擎查询注册中心,筛选出满足条件的 Agent 实例列表,并按健康状态和当前负载排序。
- Dispatch 阶段:路由引擎按负载均衡策略选中一个实例,把 Envelope 通过适配的协议发送出去。
- Ack 阶段:目标 Agent SDK 接收 Envelope,先做鉴权和幂等去重,然后立即返回一个 "Received" 确认。这个确认不代表任务完成,只代表消息安全抵达。
- Execute 阶段:目标 Agent 执行业务逻辑,可能涉及内部多步骤推理。
- Response 阶段:目标 Agent 把执行结果封装成响应 Envelope 原路返回(同步模式)或通过回调通道投递(异步模式)。
我把 Ack 和 Response 分离,是因为智能体任务的执行时间极不稳定:有的任务 200ms 返回,有的要跑 5 分钟。如果调用方等一个完整响应才算成功,中间一旦超时它根本不知道对方到底是没收到消息还是在慢慢算。有了 Ack 之后,路由引擎可以明确区分"消息没送到"和"在跑但还没跑完",这两种情况的重试策略完全不同——前者可以立刻换实例重试,后者只能耐心等或交给上层编排决策。
3.3 超时治理:单一固定超时在多 Agent 场景下没法用
超时设计是 Agent-Reach 里最容易翻车的地方,我前后改了三版才收敛。第一版用了全局统一超时(5 秒),很快就发现用户体验极差:有些 Agent 跑到 3 秒才刚完成第一步的 LLM 调用,5 秒一到大任务直接失败。第二版改成"不限制超时",结果一个下游 Agent 挂起时,整条调用链全被拖死。
最终方案是分三层超时控制:
- 连接超时(connect_timeout):默认 2 秒,控制路由引擎到目标 Agent 的网络建连时间,快速失败。
- 响应超时(response_timeout):调用方根据业务预期设置,比如普通查询类任务设 10 秒,时间长任务设 60 秒。
- 总控超时(total_timeout):由编排层给整条链路设一个预算,所有下游调用累加不能超出预算。
更重要的是,我把超时和幂等绑定在一起:每次重试都带同一个idempotency_key,目标 Agent SDK 在收到重复键时直接返回上一次的结果,不再重复执行。这个机制避免了重试导致下游重复退款、重复发货之类的事故。幂等结果我建议在 Agent 本地做内存缓存,缓存时间不低于 1 小时,防止重试窗口期跨过缓存失效。
4. 部署形态与落地实践:从单机 Demo 到多域联邦
架构和协议聊完了,接下来是落地。Agent-Reach 的部署我推荐从轻到重分三步走,不适合一上来就上全功能集群。
4.1 最小可跑形态:Docker Compose 一键拉起
对于研发环境或小规模试用,一个 Docker Compose 编排就足够了,包含四个容器:
etcd(注册中心存储)reach-core(路由引擎 + 发现服务 API)reach-console(管理控制台,Web UI)reach-mcp-gateway(MCP 兼容网关)
这个形态可以支撑几十个 Agent 的接入,足够开发联调和内部试用。我强烈建议在这个阶段就把调用链追踪的日志输出到本地的 OpenTelemetry Collector,因为后续问题排查的数据习惯要从第一天建立,等 Agent 多了之后再补观测系统,历史数据缺失会非常被动。
最小形态下有一个很重要的配置项是auth.mode。如果只在受信内网环境跑,可以先用native模式,内部颁发短期令牌;但如果 Agent 部署在跨部门、跨机房环境,我建议直接用mtls模式,双向 TLS 加租户隔离。这个选择纯粹由信任边界决定,越早想清楚越好,换模式的改造成本不小。
4.2 集群化要点:路由引擎无状态,注册存储是核心
一旦 Agent 规模上到几百个,或者有跨机房容灾需求,就要部署高可用形态。边界非常清晰:路由引擎(reach-core)是无状态的,前面挂负载均衡随便扩;有状态的是注册中心 Etcd,需要按奇数节点组集群,建议 3 节点起步。控制台和网关同理都是无状态服务。
在集群化过程中还有一个容易被忽视的设计:路由引擎的本地缓存。每一个 reach-core 实例启动后会从 Etcd watch 全量注册数据并维护一份本地内存视图,所有路由查询先走本地缓存,只有缓存未命中和实例变更事件才访问 Etcd。这样做的最大好处是路由过程不会因为注册中心的抖动而阻塞,代价是本地缓存与真实状态存在秒级延迟,但配合 TTL 心跳机制,这个延迟基本无害。
4.3 多域联邦:跨团队协作时的"最小信任边界"
再往上走,就到了多域联邦的形态。假设一个集团下有电商、金融、物流三个子域,每个子域各自部署了一套 Agent-Reach,但某些场景需要跨域调用(比如电商主控 Agent 要调物流域的运单查询能力)。这个需求靠拉一张大网把所有 Agent 塞进同一套注册中心是行不通的,信任、网络、权限都不允许。
Agent-Reach 的做法是"域间桥接"(Domain Bridge):每个域可以指定一批对外公开的 Agent 能力,对外发布"域目录";域之间的调用必须经过双方网关的双向验证,并且在消息信封里打上跨域标记。跨域调用的鉴权粒度比域内更粗——我只开放能力级授权,不开放任意 Agent 级调用。这么设计是故意的:跨域协作毕竟是低频事件,安全合规优先级高于灵活便捷。链路追踪方面,跨域时会生成新的 trace 段,但保留同一个trace_id,这样排障时能看到请求从哪里来、经过哪个域、最终落在哪个实例。
实际落地中我发现一个很有价值的配套动作:定期生成域间调用报告。每个季度导出一次跨域调用的频次、失败率、平均耗时,既能让管理层知道协作的真实情况,也能暴露一些"当初说有需求但实际没人用"的僵尸能力,推动各方把冗余 Agent 下线。这个报告也是争取预算和资源的好材料,因为数字摆在那里,比拍脑袋规划有说服力得多。
5. 避坑实录:Agent-Reach 开发中踩过的五个有代表性的坑
这块我放最真实的内容。Agent 基础设施和普通后端基础设施有个本质区别:Agent 的行为带有概率性,失败模式特别多。我们在开发和压测过程中踩了不少坑,有些坑修复后回头看其实非常低级,但当时排查了很久。
5.1 坑一:用消息队列当路由层,导致跨 Agent 调用无从追踪
第一版路由引擎为了实现异步解耦,直接把所有触达请求投到 Kafka,由下游 Agent 各自消费。听起来很干净,但问题立刻暴露:Kafka 的消费语义是"消息被拉走即视为成功",而 Agent 拿到消息后可能要调 LLM、要查数据库、可能要等外部接口响应,中间任何一步失败,这条消息就等于"消费了但没执行"。我们不得不做一套复杂的补偿机制去检测"假消费",最后还是觉得不划算,放弃了这条路线。
教训很简单:消息队列适合做"必须送达"的异步任务流,但不太适合做"需要确认执行结果"的智能体触达。Agent 调用的核心诉求是结果确认,而不是消息转发。最终方案改回 HTTP/gRPC 同步为主、队列只做结果回传通道,问题迎刃而解。守住架构边界比引入最新技术重要。
5.2 坑二:超时重试把下游打挂,原因是幂等没做全
这个坑是布线上线的第一个大事故。某个订单查询 Agent 响应偏慢,路由引擎的默认重试策略是"失败后换一个实例重试",结果下游数据库连接池被打满,服务直接雪崩。事后排查发现两个问题叠加:
- 一是重试只判断"HTTP 层错误",对业务层的"正在处理"(HTTP 200 但业务状态为 pending)没有识别,导致目标 Agent 明明还在算,路由层却认为失败并重复发起。
- 二是当时幂等方案没完全落地,多份重复请求同时进入业务逻辑,本来能撑住的系统被并发击穿。
修复后的策略调整为:重试前必须检查目标 Agent 的健康水位;业务层 pending 状态不触发重试;所有重试请求严格复用幂等键。自那以后我再也不相信"只要做了幂等就能随便重试"这种说法——重试要建立在"明确知道对方没在执行"的前提下,否则只会放大故障。
5.3 坑三:语义发现召回一堆同义能力,结果匹配优先级一团糟
语义匹配做出来之后,我们自己内部试用时遇到一个场景:调用方说要"退换货",语义层同时召回了create_refund、exchange_item、return_item三个能力,置信度都差不多。路由引擎按置信度排序选了第一个,结果目标 Agent 不是同一个部门的,权限校验直接失败。
这个问题让我意识到,语义发现必须结合"关系上下文"做加权:如果调用方和目标能力属于同一个业务域、或者在过往调用历史中经常配合使用,权重就该调高。我把这个逻辑做成一个简单的 Ranker 组件,综合语义相似度、历史共现频率、租户匹配度三个信号,效果比纯向量检索好太多。这个组件也值得单独说一句:智能体协作里的"推荐"绝不是纯算法问题,工程经验和业务约束对这些场景的约束力强得多。
5.4 坑四:Agent 大量部署在 K8s 里,注册消息风暴引发 Etcd 抖动
云原生环境下 Agent 用 Deployment 管理,每天发布升级、扩缩容频繁,每次变更都会触发注册与注销。量小的时候 Etcd 毫无压力,但当 Agent 数量过百、配合上多个环境同时发布时,注册中心的 watch 事件量突然暴增,出现过短暂的写入超时。
后来我们做了两级削峰:一是 Agent SDK 内置了"注册冷却窗口"——同一个 Agent 在 10 秒内最多发一次注册请求,中间的状态变化由本地上报而不是每次全量推送;二是路由引擎的本地缓存把 watch 事件从"逐条处理"改成"批量合并后定时刷新",把瞬时抖动平滑掉了。经过这个优化,Etcd 的压力基本可以忽略不计。
5.5 坑五:观测数据齐全了但没法用,因为缺了"业务语义"标签
最后一个坑是关于可观测性的。早期我们埋的日志字段都是标准化的(耗时、状态、trace_id),数据量很大但排障效率很低。有一次定位一次跨 Agent 的失败调用,要从日志里反推"这个请求是哪个用户发起的、处理的是哪个订单",非常痛苦。
后来我们在 Envelope 里增加了biz_tags字段,上游 Agent 可以附带业务标签,比如user_id=12345、order_id=AB123。所有日志、追踪、审计系统都把这个标签作为索引字段,排障时先按业务对象筛,再按调用链展开,定位速度快了不止一个量级。这个改动很小,但效果是全局性的,我建议所有做 Agent 平台的人都尽早把业务标签纳入日志规范。
6. 性能表现与压测数据:Agent-Reach 到底能扛多少 QPS
光说架构不说数据等于耍流氓。我们在一套标准测试环境上做了多轮压测,测试环境规格:路由引擎 2 核 4GB 内存单实例,目标 Agent 模拟服务部署在另一台 2 核 4GB 机器上,网络走内网千兆。结果如下:
| 场景 | 并发数 | 平均时延 | P99 时延 | 成功率 |
|---|---|---|---|---|
| 同步调用,简单 JSON 回声 | 50 | 8ms | 22ms | 99.99% |
| 同步调用,模拟 500ms 业务处理 | 50 | 530ms | 620ms | 99.97% |
| 异步调用,带 Webhook 回传 | 50 | 触达耗时 15ms | 触达耗时 45ms | 99.95% |
| 流式调用,SSE 推送 100 个 Token | 20 | 首包 60ms | 首包 110ms | 99.90% |
这个成绩说明路由引擎本身的转发开销非常小,主要延迟都消耗在业务处理和 LLM 调用上。单实例的极限大概在每秒 3000 次触达左右,再往上就得横向扩容。因为路由引擎无状态,扩容就是加实例的事,没有遇到什么架构瓶颈。
压测过程中还有一个有意思的发现:Agent 服务的耗时分布极其不稳定。同样是回声测试,纯后端服务的 P99/P50 比值大概在 2 倍左右;但带 LLM 调用的 Agent 服务,P99 可能是 P50 的 10 倍以上。这个特性直接影响了超时设计和容量规划——给 Agent 服务做容量评估时,不能用传统"平均耗时 × QPS"的公式,必须按 P99 或者 P95 来计算Buffer,否则一旦有慢请求堆积,整个链路的排队延迟会迅速恶化。
7. 一个可以立刻用起来的小技巧:给 Agent 能力做 "状态机注册"
最后分享一个对读者可能立刻有帮助的小技巧。在 Agent-Reach 的能力注册 Schema 里,除了描述入参出参,我还建议加一个state_machine字段,用状态机描述这个能力的生命周期。举个例子,create_refund的状态机可以是:pending → processing → success | failed | retryable。
为什么要加这个?因为下游 Agent 在执行长任务时,调用方经常需要轮询状态。如果能力一开始就把状态流转定义清楚,Agent-Reach 的路由引擎可以直接根据状态机做智能决策:遇到retryable状态自动重试,遇到failed状态直接返回失败,遇到processing状态则把请求转成异步轮询。
在实际落地中,存了状态机的能力在"快速失败"和"合理重试"之间的表现,比没有状态机的能力好得多。这个技巧不依赖任何复杂组件,只是一个注册 Schema 的设计规范,但给上层编排带来的确定性提升非常可观。
我做 Agent-Reach 最深的一个体会是:智能体协作的工程复杂度,往往被"只要大模型够聪明就能搞定"的叙事掩盖了。实际跑起来之后,连接可靠性、消息约束、超时治理、可观测性才是决定系统能不能稳定服务的关键。希望这篇梳理能给你提供一个可靠的设计参考,也欢迎你基于自己的场景做调整——如果卡在某一步,欢迎一起交流。