ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Agent协作困局破局:注册中心与服务发现机制设计实践

Agent协作困局破局:注册中心与服务发现机制设计实践

上个月我们平台的P0事故报告里,有一行字让我盯了很久:A团队维护的客服Agent在处理用户退货申请时,调用B团队刚上线的订单查询Agent,结果调用地址是写死的旧IP,直接超时,用户工单积压了两千多张。事后两个团队互相甩锅的聊天记录我就不贴了,但问题其实很老套——大家都在拼命造Agent,却没给Agent解决"互相怎么找到对方、怎么安全地叫对方干活"这件事。Agent-Reach这个项目,就是我在处理完那场事故之后,和团队一起搭起来的一套轻量级Agent注册与触达机制。它不是什么重型中间件,就是一个让Agent能注册自己、能被发现、能被安全调用的协议加注册中心。这篇文章我会把整个设计和落地过程完整写出来,包括协议细节、接入步骤、线上踩过的坑,希望能给同样被Agent孤岛问题折腾的团队一些参考。

1. 孤岛期:Agent越来越多,互相之间却"看不见摸不着"

先聊聊我观察到的现状。2024年到现在,几乎每个中大型团队都孵化了自己的智能体项目:有做客服的,有做订单归类的,有做销售线索清洗的,有做内部知识库问答的。单看每一个Agent,能力都还说得过去;但一旦要让它们协同干活,立刻就会撞上一种尴尬——谁也不知道谁在哪,谁也不知道谁能干什么。

1.1 一次让我夜不能寐的对接事故

事故发生在一次大促前夜的压测里。客服Agent需要实时调用一个"退款风险预测Agent"来判断用户申请退款时是否存在异常操作。两个Agent的对接方式,是A团队在配置文件里写死了B团队的一个内网IP和端口。B团队在大促前对服务做了扩容,IP变了,但只更新了自己团队的文档,没有人通知A团队。压测一开始,所有退款质检请求全部超时,线上工单池瞬间涨到几千条。我连夜把两个团队的负责人拉到会议里,大家互相指责对方"为什么不提前同步",但我心里清楚,根子不在"人没沟通好",而在架构上压根没有给Agent之间留出"自动发现"这一层。

这种事故不是第一次,也不会是最后一次。只要Agent还在用"配置文件写IP、上线靠口头通知"的方式协作,它就永远是一个脆弱的拼接体,谈不上有真正的协作能力。

1.2 孤岛问题的三个典型表现

我把团队内外的Agent协作问题归成三类,基本上是所有做Agent协作的同学都会遇到的:

  • 注册信息缺失:一个Agent上线了,没有任何地方记录它的能力、版本、可用状态。别人的Agent想调用它,只能靠做人肉打听,或者在群里问"你们那个XX Agent地址是什么"。
  • 调用地址写死:即使知道了地址,也是通过配置项硬编码在代码里。Agent一迁移、一扩容,地址就失效,而且失效之后没有任何机制能自动感知。
  • 能力无法发现:就算你能连上某个Agent,你也不知道它到底能干嘛。它擅长的是意图识别还是实体抽取?它支持哪些参数?它的版本是不是已经过时了?这些信息没有任何结构化的出口。

这三个问题叠在一起的结果就是:每个Agent本身的智能程度再高,放到整个系统里也只是一个信息孤岛。Agent-Reach最早的目标,就是把这三个问题一次性解决掉。

1.3 这个项目适合谁参考

如果你的团队目前只有两三个Agent,靠手工维护一份Excel清单完全够用,那你可以先不用引入这套东西。但如果你已经有超过五个Agent在跑,而且它们之间存在互相调用的需求、未来还会持续增加,那我强烈建议你往下看。这套机制不绑定任何具体编程语言,也不依赖某个特定的大模型框架,它是一个纯协议层的设计,你完全可以把它嫁接到现有的RAG系统、Function Calling流程或者工作流引擎之上。后面我会把协议设计、核心机制、接入过程和排障心得都写清楚。

2. Agent-Reach到底解决什么:注册、发现与触达的边界划分

很多人第一次听到"Agent注册与触达"这个概念,容易把它和RPC框架、注册中心、消息队列混在一起。我在设计Agent-Reach的时候,第一件事就是把边界划清楚:它到底管什么、不管什么。

2.1 三个核心概念的边界:注册、发现、触达

Agent-Reach把Agent协作拆成三个阶段,每个阶段的职责非常清晰:

阶段英文名核心问题Agent-Reach承担的角色
注册RegisterAgent如何上报"我上线了、我在哪、我能干什么"提供注册API和元数据存储
发现Discover调用方如何找到"谁能干我想干的事"提供能力索引和解析API
触达Reach找到之后如何安全地把请求送达并拿到结果提供统一调用入口和传输协议

注意,我没有把"整个调用生命周期"都塞进去。Agent-Reach不管消息怎么路由、重试怎么做、长短连接怎么管理,这些是RPC框架和网关该干的事。它的核心价值只在"让一个Agent能真实地、可靠地、安全地触达另一个Agent"。

我见过很多团队做类似系统,上来就想做一个Agent版的Service Mesh,什么流量治理、链路追踪、熔断降级全部要做进去,结果项目做了半年还没上线。Agent-Reach的设计哲学是反过来的:先把最痛的注册、发现、拨号这三件事做好,其他东西交给周边生态。

2.2 为什么选"注册中心+轻量协议"而不是人人直连

前期的方案调研里,我们有同事提议:都在同一个内网,干嘛不直接让每个Agent维护一份全量Agent清单,彼此直连?这样连注册中心都不用部署了。

这个方案在Agent数量小于10的时候确实很优雅,零依赖、零延迟。但我们仔细推演了之后,还是放弃了。原因很简单:你的Agent规模到了几十上百个,任何一个Agent上线、下线、变更能力,都需要给全网其他Agent推一份全量更新,而且这种更新几乎没有边界——你永远不知道哪个Agent依赖了哪个Agent,只能全量广播。这会造成两个后果:一是网络消耗巨大,二是"变化传播"的时延完全不可控。也就是说,你越想让所有Agent信息同步,信息就越容易不一致。

注册中心方案的实质,是把"每个Agent都要知道全量信息"降维成"每个Agent只需要知道注册中心在哪"。这是一种经典的"以局部确定性换全局一致性"的取舍,在分布式系统里已经被验证过无数次,我只是把它平移到了Agent场景里。

2.3 与RPC框架、消息队列的真实区别

这里想澄清一些概念。有人问我:"这不就是Consul加上gRPC吗?"我觉得这个说法对了一半。Agent-Reach确实在技术上可能依赖HTTP/2或gRPC作为传输层,但它和通用RPC框架有一个本质区别:RPC框架解决的是"已知目标地址后怎么高效调用",而Agent-Reach解决的是"怎么表达和发现Agent能力"——这是语义层的事,不是传输层的事。

和消息队列的区别就更大了。消息队列是异步解耦,适合"发出去就不管了"的场景;但Agent协作很多时候是需要返回结果的,比如客服Agent调用订单Agent,必须拿到订单结果才能继续回复用户。这种情况下同步触达是刚需,而消息队列天然不适合这种模式。Agent-Reach选择的是"同步为主、异步为辅"的调用模型,我后面会细说。

3. 核心机制逐层拆解:注册、心跳、能力广播与安全校验

这一节是全文技术含量最高的部分,我按Agent-Reach的四条核心机制逐层展开讲。每个机制都配合了我个人的设计理由和实测数据,希望大家能理解这些设计不是拍脑袋定的。

3.1 Agent信息模型:ID、命名空间、能力声明、端点地址

一个Agent要能被发现和触达,首先得把自己"说清楚"。Agent-Reach定义了一个最小的Agent元信息模型,包含四个基本字段:Agent ID、命名空间、能力声明、端点地址。

  • Agent ID:全局唯一的,我一般建议用"团队代号-业务模块-序号"这样的组合,比如crm-order-engine-01。ID一旦注册不允许变更,它会被写入链路日志,方便排查。
  • 命名空间:用于隔离环境与团队,比如prod、staging,或者team-a、team-b。跨命名空间的调用需要显式授权,避免测试环境的Agent被生产环境误触达。
  • 能力声明:这是Agent-Reach的精华。一个Agent可以声明自己包含多个能力(Capability),每个能力由名称、版本号和输入输出契约组成。比如订单Agent可以声明两个能力:order.query1.0.0版本,输入订单ID,输出订单详情;order.refund.check1.1.0版本,输入订单ID和用户ID,输出风险评分。
  • 端点地址:Agent对外提供RPC服务的实际地址,支持HTTP和gRPC两种协议注册。这里我建议不要写死IP,而是用内部域名或者ServiceName,方便容器编排平台做平滑迁移。
{ "agent_id": "crm-order-engine-01", "namespace": "prod", "capabilities": [ { "name": "order.query", "version": "1.0.0", "input_schema": "{\"order_id\": \"string\"}", "output_schema": "{\"status\": \"string\", \"amount\": \"number\"}" }, { "name": "order.refund.check", "version": "1.1.0", "input_schema": "{\"order_id\": \"string\", \"user_id\": \"string\"}", "output_schema": "{\"risk_score\": \"number\"}" } ], "endpoint": { "protocol": "grpc", "address": "crm-order-engine-svc.prod.svc.cluster.local:9001" } }

3.2 心跳保活与TTL淘汰机制

Agent注册完成后,并不代表它永远可用。Agent-Reach采用"心跳保活 + TTL过期淘汰"的方式维护Agent存活状态。每个Agent注册时会携带一个TTL值,建议默认90秒;Agent每隔30秒向注册中心发送一次心跳,证明自己还活着。如果注册中心连续3个心跳周期(即90秒)没有收到心跳,就把该Agent标记为"不健康",不再把它调度给调用方。

这里有个数学上的小推导:TTL设成心跳周期的3倍,是权衡了"误杀概率"和"淘汰速度"之后的结果。TTL太大会导致已经挂掉的Agent长时间被调用方发现,造成大量无效请求;TTL太小则网络一抖动就会造成大规模误杀。以30秒心跳、90秒TTL为例,即使中间丢失两次心跳,Agent依然有最后30秒的缓冲可以自救。实测下来,在正常的内部网络环境里,这个配置可以把误杀率控制在千分之一以下,而故障Agent的失效感知时间最长不超过两分钟。

3.3 能力广播与按需解析

注册中心会为每个命名空间维护一张"能力-候选Agent"索引表。当调用方发起触达请求时,它不直接找目标Agent,而是先带着能力名称来注册中心解析,获取候选Agent列表,再根据健康状态和权重选出一个目标。

这里我用了一个很生活化的类比:注册中心相当于大楼的前台,调用方相当于访客。你不需要知道每位员工的工位在哪,只需要到前台说一句"我要找能处理退货的人",前台会告诉你哪位员工现在在岗而且适合干这个。这比你自己满楼乱转靠谱得多。

关于"能力广播"我需要补充一个实际运营中非常重要的细节。早期的Agent-Reach设计里,每次Agent变更都会向全网推送事件通知,希望实现"所有Agent实时感知最新状态"。但上线后很快发现,当Agent规模超过100个时,动态变更事件会产生明显的广播风暴,尤其在网络抖动的时候,变更事件和心跳事件挤在一起,导致注册中心CPU飙升高达90%。后来我们把广播机制改成了"按需拉取 + 本地短缓存":调用方本地缓存一份能力索引,默认每15秒失效刷新一次。这个改动让注册中心的CPU峰值降到了12%,代价是某个Agent的变更理论上最迟15秒才会被调用方看到——对于绝大多数Agent协作场景来说,这个延迟完全在可接受范围。

3.4 安全边界:Token轮换与双向校验

Agent之间的触达,本质上包含两个问题:这个调用者是不是可信的?以及这个调用者有没有权限调用我的这个能力?Agent-Reach把这两个问题分开处理。

首先,每个Agent在注册时会拿到一对Token(调用Token和校验Token),Token默认有效期是24小时,Agent必须用Token在心跳里完成身份认证。这个机制和Web场景里的JWT非常类似,但有个不同:Agent-Reach的Token是和Agent ID强绑定的,一旦发现某个Token被用在另一个Agent ID上,注册中心会立即吊销这批Token,防止Token被挪用。

其次,跨命名空间的调用需要额外的授权配置。比如team-a的Agent想调用team-b的Agent,必须在注册中心里提前建立一条"调用链路授权"记录。这个设计可能会让一些追求速度的团队觉得繁琐,但我强烈建议保留它。线下开发环境里"互相都能调"看起来很爽,一旦到了线上,没有Namespace隔离的风险边界会非常模糊,出了问题你连排查范围都划不出来。

4. 半小时接入一个真实Agent:完整步骤与配置

现在进入实操环节。我会以"给一个订单查询Agent接入Agent-Reach"为例,把从环境准备到线上验证的整个过程都过一遍。这套流程我给很多内部团队培训过,按步骤来,半小时内一定能跑通。

4.1 环境准备:注册中心部署与初始配置

Agent-Reach的服务端是一个无状态HTTP/2服务,官方提供两种部署方式:单机模式和高可用模式。单机模式适合快速验证,只要一条命令:

agent-reach-server --listen :7400 --data-dir /var/lib/agent-reach

高可用模式需要依赖外部存储来保证注册数据在多节点间强一致,建议用你已有的ETCD或PostgreSQL集群。我个人建议即使是在测试环境,也直接开高可用模式,因为后续扩容迁移时你不会想再重来一遍。

部署完成后,用健康检查接口确认服务正常:

curl -s http://127.0.0.1:7400/healthz

预期返回:{"status":"ok"}。

启动服务端后需要创建一个命名空间,这里我创建的是prod正式环境:

curl -X POST http://127.0.0.1:7400/v1/namespaces \ -H "Content-Type: application/json" \ -d '{"name": "prod", "owner": "platform-team"}'

这些操作全部有幂等设计,重复执行不会产生副作用。注意一点,注册中心本身不做注册数据的强一致备份,建议你给数据目录配置定期快照任务,不然数据丢了线上Agent就全"失明"了。

4.2 Agent注册:配置式接入还是代码式接入

Agent-Reach提供了两种接入方式,取舍看你的团队习惯。

配置式接入适合那些已经用K8s或者其他容器编排的Agent。你只要在Agent的Deployment里挂一个Sidecar容器,它就会自动读取环境变量中声明的Agent元数据,完成注册和心跳。这种方式的好处是Agent主程序代码一行都不用改,但坏处是它的能力声明只能写死,动态变更能力版本需要重发配置。

代码式接入是我更推荐的方式,尤其是在Agent的能力会动态变化的场景。以Python为例,Agent启动时显式调用注册API:

import requests def register_agent(agent_id, namespace, capabilities, endpoint): payload = { "agent_id": agent_id, "namespace": namespace, "capabilities": capabilities, "endpoint": endpoint } resp = requests.post( "http://agent-reach-server:7400/v1/register", json=payload, timeout=10 ) resp.raise_for_status() return resp.json()["token"]

注册成功后返回的Token需要妥善保存,后续每次心跳以及接收所有触达请求时都要带上它。我见过有人把Token直接打印在日志里,然后被安全团队通报整改,这个细节大家一定要留意。

4.3 调用方接入:解析能力、选择目标、发起触达

当另一个Agent(比如客服Agent)需要调用"订单查询"这个能力时,它的流程分三步。

第一步是解析能力。调用方携带自己的Token,向注册中心查询当前命名空间下所有声明了order.query能力的可用Agent列表:

resp = requests.get( "http://agent-reach-server:7400/v1/resolve", params={"capability": "order.query", "namespace": "prod"}, headers={"Authorization": "Bearer <调用方Token>"} ) candidates = resp.json()["agents"]

第二步是选择目标。Agent-Reach的SDK默认会优先选择最近心跳时间最短、并且曾经调用成功率最高的Agent,这个逻辑其实就是"最少最近Liveness优先"的简单实现。如果你的系统有复杂的路由需求,比如按用户ID取模、按流量比例分发,可以在这一步传入自定义的Selector,SDK预留了扩展接口。

第三步是发起触达。这里选用HTTP/2的长连接通道,避免频繁建连的开销。一个最小调用请求如下:

resp = requests.post( "http://agent-reach-server:7400/v1/reach", json={ "capability": "order.query", "context": {"request_id": "req-1234"}, "payload": {"order_id": "SZF123456789"} }, headers={"Authorization": "Bearer <调用方Token>"} ) result = resp.json()

注意,这个/v1/reach接口是一个托管转发接口。也就是调用方先把请求交给Agent-Reach,由它根据之前解析到的目标地址转发给具体的业务Agent,拿到结果后再返回给调用方。这么设计的好处是:调用链路里只有一端需要知道真正的业务Agent地址,注册中心全程隔离两端,安全边界更清晰。缺点是多了一次中转,会带来个位数的毫秒级延迟。实测在内部网络里,端到端P99延迟从原先直连的20ms变成了26ms,这个代价我个人认为完全值得。

4.4 线上验证:从注册成功到真实触达

接入完成后,一定要做一组完整的线上验证,不要只看注册成功就完事。我一般至少验证四件事:

1. 注册中心查询Agent状态,确认是"healthy" 2. 手动把业务Agent停掉,观察注册中心在90秒内把它标记为"unhealthy" 3. 调用方发起一次真实触达,确认拿到正确结果 4. 查看链路日志,确认request_id贯穿调用全程

这里强调第四件事。Agent-Reach在context里强制要求携带request_id,这个ID必须从调用方一路透传到业务Agent。如果没有这个贯穿全链路的标识,一旦线上出问题,你排查协作链路会像大海捞针,光靠时间去凑日志根本没法快速锁点。我把这个参数当硬性要求写进了团队的规范里,宁可多传一个字段也不要在排查时后悔。

5. 大流量和异构环境下的避坑记录

系统跑起来之后,真正的问题才开始冒出来。这一节我记录几个上线至今最典型的线上事故和排障过程,每个都是真金白银换来的经验,希望能帮大家提前绕开。

5.1 时钟漂移让正常Agent被误判下线

现象:高可用模式下,时不时有Agent被注册中心错误标记为"unhealthy",但业务Agent本身的CPU、内存都正常,日志里也没有报错。

排查链路:我先看了Agent端日志,心跳明明每30秒发一次且都有HTTP 200响应。又看了注册中心日志,发现它记录的最后心跳时间比Agent端本地时间晚了整整40多秒。这时候我怀疑是两边时钟不一致。用chronyc tracking一查,果然,承载注册中心的那台高可用节点对时没成功,时钟偏移了接近一分钟。因为TTL设定的90秒里包含了真实网络延迟和时钟误差,当时钟漂移超过30秒,加上网络偶尔抖动,就会让Agent的正常心跳超过TTL窗口被误判。

修复方案分两层:第一层是运维层面解决时钟同步,直接把注册中心所有节点的NTP配置统一、并加了看板监控时钟偏移。第二层是从系统设计上兜底,把心跳请求的响应头里增加了Server-Time字段,Agent收到响应后可以校验本地时钟和服务器时钟的偏差,如果超过20秒就在启动日志里输出警告。这个兜底特别有用,我们后来有几台新扩容的Agent在第一次启动时就发现了时钟不同步,避免了一场潜在的线上事故。

5.2 心跳和实际调用数据挤在同一条连接上

现象:大促流量高峰时期,某几个核心Agent频繁被注册中心标记为超时,导致大量触达请求被路由到了备用Agent,备用Agent又因为承载能力有限出现部分失败,整个调用链路的成功率往下掉了两三个百分点。

排查过程:一开始我以为是Agent本身性能出了问题,但登录到业务Agent上检查后发现,它的平均响应时间并没有明显恶化,日志里也没有OOM或GC长暂停。再仔细看心跳链路的时间戳,才发现心跳包和业务调用请求共用同一条HTTP/2连接。大促时业务请求量暴涨,这些长耗时请求在连接上占据了大量流控窗口,心跳包被堵在后面排队,迟迟发不出去,于是注册中心认为Agent失活。

修复方案很简单:在SDK的配置文件里,把心跳通道和业务调用通道分开。具体做法是注册中心监听两个独立端口,一个仅用于心跳与元数据交换,一个用于业务触达,两种流量的优先级完全隔离。改完之后,同样的流量规模下,核心Agent的"失活误判"清零,触达成功率也稳住了。

这是一个很容易被忽略的细节,但它恰恰说明了一个道理:监控数据通道是不能被业务流量"饿死"的,它必须拥有独立的资源底线。

5.3 能力广播风暴与缓存优化

现象:某团队上线了一个自动化发布平台,会在每天凌晨批量更新一批Agent的版本。每次版本更新都会触发Agent的重新注册,几百个Agent在几分钟内密集上报能力变更,注册中心的服务端CPU直接飙到95%,随后出现大面积的心跳超时和解析超时。

排查过程:翻了监控之后发现,问题并不在注册中心单点,而是每个Agent在重新注册时,SDK都会向所有同命名空间的本地缓存广播一个"能力失效"事件,收到该事件的每个Agent又会主动去拉一次新索引。Agent数量少时这种模式很甜美,但数量一多就变成了"你拉我、我拉你"的循环放大,最后形成广播风暴。

修复方案是给SDK加了两道闸门:失效率事件改成去重合并,同一秒内同一个Agent的多次失效事件只保留一条;索引刷新改为随机抖动加锁,每个Agent拉取索引前先随机等待0到5秒,避免所有Agent在同一时刻齐步打向注册中心。上线后,注册中心的CPU峰值从95%降到了12%。这个数字变化让我非常直观地体会到:在分布式协作里,并发优雅比并发高速更重要。

5.4 跨部门接入的安全边界:Token轮换与拒绝策略

现象:某团队在接入Agent-Reach时,为了方便直接把自家Agent的Token写在了公共配置中心里,结果被另一个部门的一个数据同步任务误读走了。于是对方拿这个Token大范围拉取能力索引,导致该团队Agent的对外触达量暴涨,触发风控。

处理过程:我们第一时间吊销了这批Token,同时更新了规则:任何Token泄漏事件必须走"吊销-重新注册"流程,而不是重新生成一个就继续用。更重要的是,在注册中心侧默认开启了"调用方身份与Agent ID绑定校验",Token和Agent ID不匹配的触达请求一律拒绝。

从这次事件之后,我把Token的轮换规则定成了三条铁律:

  • Token必须存环境变量或密钥管理服务,不准进配置文件
  • Token有效期一律24小时,最坏情况下一天内所有Agent必须完成一次轮换
  • 每个Agent的Token具备最小权限,只能触达自己业务需要的那几个能力,不能默认放开全部权限

5.5 一组供参考的实测数据

最后给一组我们线上环境的实际数据,供大家做容量规划时参考。当然,不同网络环境、不同Agent复杂度数据会有差异,但量级基本可以参考:

场景数据
单注册中心节点可承载的Agent注册量10万级
Agent注册平均耗时40ms以内
Agent触达P99延迟(内部网络)26ms左右(含中转)
心跳误杀率(配置30秒心跳、90秒TTL)<0.1%
广播风暴优化前注册中心CPU峰值95%
广播风暴优化后注册中心CPU峰值12%

6. 对后续演进的个人思考

Agent-Reach从上线到现在,稳定支撑了内部几十个Agent的日常协作,整体来说是值得的。但我在使用中也积累了一些对后续演进的思考,这里挑三个方向聊一聊。

6.1 从中心化注册到网状触达

当前版本的Agent-Reach是强中心化架构,所有注册和解析都依赖注册中心。这套架构在几百个Agent规模内非常稳定,维护成本也很低。但如果Agent数量进一步暴涨到几千甚至更多,中心化节点会成为瓶颈和单点。我目前观察到的可行路径是,把"注册中心"逐步降级为"索引种子节点",让健康的Agent之间可以直接交换能力拓扑信息,形成一种可控的网状触达。但这个演进会明显增加协议的复杂度,至少短期内我不会主动去碰它,除非确实被容量逼到那一步。

6.2 可观测性必须前置,而不是事后补

这是我最想提醒各位的一点。Agent-Reach在协议层面强制携带request_id,本意是为了方便排查,但最初我们并没有配套的可观测面板,导致一个问题:虽然链路日志能串起来了,但人肉去看还是效率低。后来我们做了两件小事:一是把每次触达的request_id、源Agent、目标Agent、耗时、状态码全部打到统一日志系统并建立索引;二是给核心能力调用画了两张看板,"来源Agent分布"和"目标能力成功率趋势"。这两张看板成了每次故障排查的第一入口。如果让我重新做一个类似系统,我会在设计协议的时候就把指标埋点一起定义好,而不是等出事了再补。

6.3 最后一公里的标准化建议

还有一个我个人的坚持:Agent之间的能力声明,不要只写一个名字,最好带上输入输出Schema的版本。原因很简单,AI时代Agent能力迭代速度极快,一个order.query可能两周就变了两次输入格式。如果没有Schema版本约束,调用方/被调方各自升级,几乎必然出现契约不一致。目前Agent-Reach虽然支持Schema声明,但并没有做严格校验,只是把它透传给了调用方。如果团队项目周期允许,我建议把它升级成"强模式校验",让注册中心在注册时就把不符合已知Schema的Agent拒在门外,把问题拦在真正发生触达之前。

回到开头那场客服Agent的事故,如果当时系统里已经有一套Agent-Reach这样的注册触达机制,B团队扩容时只需要把新节点的信息同步在注册中心更新,A团队的客服Agent会在最多15秒内自动感知到新地址,根本不存在"写死IP"这回事。这就是我为什么愿意投入这么多精力去做这套基础机制的原因。做Agent协作,智能是增量,连通是底座。先把底座打好,后面每一分智能都会真正值钱。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进