核心论点:本文讲"发现"这一分布式动作在两层的不同解法——① 网络层服务发现(解决依赖地址动态变化);② 工具/能力发现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、要不要跨云、健康检查的粒度要求。三问即可定位:

选型决策树:三问定模式

已上 Kubernetes?

K8s(Kubernetes) Service
集群内虚拟 IP + kube-proxy

要配置中心 /
国内 Spring 生态?

Nacos
注册表 + 配置中心

跨云 / 多数据中心
要 service mesh?

Consul
多环境 + 强健康 + mesh

DNS 轮询
最简单、无健康

第一问先卡 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 加载进 SkillRegistrycreate_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,边界清晰也保延迟。
  • 主动探测 + 被动熔断并用,故障兜底不靠阻塞。
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐