服务发现:Agent 如何找到依赖
核心论点:本文讲"发现"这一分布式动作在两层的不同解法——① 网络层服务发现(解决依赖地址动态变化);② 工具/能力发现(
SkillRegistry自动注册,同形不同层)。Shop-Agent(本文示例的客服 Agent 系统)对内走ToolService直连,只在对外暴露时用 MCP(Model Context Protocol,模型上下文协议)。
三种模式:DNS、Consul、Kubernetes Service
多节点部署后依赖地址随时变(扩缩容、重启、漂移),硬编码等于埋雷——所以才有下面这些动态发现机制:
| 模式 | 机制 | 适合 |
|---|---|---|
| DNS | 域名解析到多个 A 记录,客户端轮询 | 简单、最终一致,无健康检查 |
| Consul / Nacos | 中心注册表 + 健康检查 + 服务目录(Nacos 另含配置中心,国内 Spring 生态常用) | 多环境、需健康感知、跨云或国内团队 |
| K8s(Kubernetes) Service | 集群内虚拟 IP + kube-proxy 负载均衡 | 已上 K8s,声明式 |
选哪个取决于你有没有 K8s、要不要跨云、健康检查的粒度要求。三问即可定位:
选型决策树:三问定模式
第一问先卡 K8s:上了就直接用 Service,不引入额外组件;没上再问"要不要配置中心"——国内 Spring 团队顺手用 Nacos 把注册表与配置中心一并解决;两者都不是就问"是否跨云 / 要 mesh"——是则 Consul,否则 DNS 轮询最轻。
注意这棵树回答的是"当你需要(网络层)服务发现时怎么选"。Shop-Agent 的特殊之处在于:内部工具/能力发现不靠上述任何一种,而是 SkillRegistry 自动注册(见下节)——它用"放一个文件"解决了"工具清单不用硬编码"这个**与服务发现同构、但层级不同(能力层 vs 网络层地址)**的问题,所以本篇重点是模式思想,不是推某个注册中心。Shop-Agent 真·找其他 Agent 节点的服务发现发生在 A2A 层,见《Agent 间通信与协作》。
两者常被名字里的"发现 / 注册"搞混,但层级与要解决的问题完全不同:
| 维度 | 网络层服务发现 | 工具/能力发现(SkillRegistry) |
|---|---|---|
| 发现对象 | 依赖的网络地址(IP:port) | 可用的工具/能力(tool 名 + schema) |
| 发生层级 | 跨进程 / 跨节点 | 进程内 |
| 典型机制 | DNS / Consul / K8s Service / A2A | 扫描 skills/<名称>/SKILL.md 自动注册 |
| Shop-Agent 用法 | 找其他 Agent 节点(A2A 层) | 内部工具暴露,对外走 MCP |
| 解决的核心问题 | 地址动态变化,避免硬编码地址 | 工具清单动态变化,避免改代码 |
工具/能力发现:SkillRegistry 自动注册(能力层,非网络服务发现)
Shop-Agent 的工具体系(ToolService / SkillRegistry)有一条规定:MCP 对外,不对内。
- 内部调用(Agent → Tool)走
ToolService.dispatch()直连,不经过 MCP Server,省一层序列化(serialization,数据转网络字节流的开销); - 对外暴露(给 Claude Desktop、n8n 等外部客户端)才用
FastMCP起 MCP Server。
关键是自动注册:SkillLoader 在启动时把 skills/ 目录下每个 SKILL.md 加载进 SkillRegistry;create_mcp_server() 随后遍历 SkillRegistry,对每个 Skill 用 _make_tool_fn() 动态生成带类型注解的 async 工具函数,并自动推断 inputSchema。新增一个 Skill 只需在 skills/<skill-名称>/ 下新建 SKILL.md,重启即暴露,零代码改动。
# 自动注册的本质:扫描 SkillRegistry → 动态生成工具
mcp = create_mcp_server() # 遍历 SkillRegistry(数据由 SkillLoader 从 skills/ 加载)
# 外部客户端 tools/list 即可拿到完整 JSON Schema
这和服务发现同理——都是"解耦消费者与硬编码依赖",但发生在工具能力层而非网络地址层("放一个文件"新增 Skill 的方式见上文)。
健康检查:主动探测 vs 被动熔断
两种思路:
- 主动探测:定时 ping 依赖,标记健康/不健康。Shop-Agent 提供
GET /a2a/health(a2a = Agent-to-Agent,Agent 间通信协议),返回各依赖状态:
{"llm": "healthy", "vector_db": "unknown", "redis": "unavailable", "mcp_server": "disabled"}
- 被动熔断:不主动探,靠调用失败(超时、锁冲突)触发降级。例如纠纷锁已被占用时直接返回"处理中",就是一种被动熔断。
实战中两者并用:主动探测用于"我知道你挂了",被动熔断用于"我没探到但调用就是失败"。
核心要点
- 服务发现解决"依赖地址动态变化",避免硬编码埋雷。
- DNS / Consul / K8s 三种模式按环境与健康检查粒度选型。
- Shop-Agent **工具/能力发现(能力层)**靠
SkillRegistry自动注册,新增 Skill 零代码改动;真·服务发现(找其他 Agent 节点)在 A2A 层。 - 对内直连(
ToolService)、对外 MCP,边界清晰也保延迟。 - 主动探测 + 被动熔断并用,故障兜底不靠阻塞。
更多推荐

所有评论(0)