注册与发现中心
两层目录:先按 Agent Card 找到逻辑能力,再用服务端签名的路由句柄解析到具体实例;不新鲜、不健康的条目不会被发现。
依据 agent-solution 0.1.3 · main@bf702bc9(2026-11-03)核实
为什么需要注册中心
网关收到"找交期承诺智能体"的请求,得知道两件事:有没有这样的智能体、现在该打到哪台机器上。registry-discovery-center(下文简称 RDC)把这两件事分成两个平面:
| 平面 | 回答 | 接口 | 关键字段 |
|---|---|---|---|
| 逻辑 Agent Card | 谁能做这件事 | POST /api/registry/discover | 不含实例地址 |
| 运行时实例路由 | 现在打到哪个实例 | GET /instances/...、POST /route-handle/resolve | 不透明的 routeHandle |
数据存在 PostgreSQL,用行级安全(RLS)做租户隔离。
逻辑发现:层层过滤
一次 discover 请求要带租户,以及 agentId / serviceId / 技能 ID 至少一项,还可以带版本、技能标签等约束:
{
"context": { "tenantId": "sales", "callerRef": "gateway", "requestId": "req-1" },
"agentId": "delivery-promise",
"limit": 5,
"constraints": { "contractVersion": "1.0.0", "requiredSkillTags": ["order"] }
}
示意请求,字段结构取自 README,智能体名称是本站案例里的示例值。
发现引擎按这个顺序过滤,每一步落空都有明确的结果:
- 按选择器查登记 → 查不到:
NO_MATCH - 只留
REGISTERED→ 没有:NO_MATCH - 只留新鲜度为
FRESH的(排除STALE_CARD、STALE_SOURCE)→ 没有:NO_MATCH - 按版本约束过滤 → 没有:
VERSION_UNAVAILABLE - 按执行约束过滤 → 没有:
CONSTRAINT_UNAVAILABLE - 去重、分页 →
SUCCESS
区分"找不到""版本不对""约束不满足",调用方才能给用户一个准确的说法,而不是笼统的失败。
实例路由:只给句柄,不给地址
按智能体、按服务、按能力列实例时,响应里有 routeHandle 和健康状态,但不暴露 endpointUrl。能被列出来的实例要同时满足:
- 状态是
ONLINE或DEGRADED(DRAINING正在摘流,不再接新请求) - 最近 15 秒内有心跳
网关拿着句柄调 resolve,才得到真正的地址。统一 API 的句柄格式是:
rh1: + base64url(内容 JSON) + . + base64url(HMAC-SHA256 签名)
内容里带着租户。解析时与调用方租户比对,不一致就拒绝并审计。所以句柄伪造不了、改不了、跨租户用不了。
源码RouteHandleIssueragent-solution/common/agent-bus/registry-discovery-center/src/main/java/com/openjiuwen/rdc/core/RouteHandleIssuer.java:33@bf702bc9这也带来一条运维要求:签名密钥必须是至少 32 个字符的私有随机值,同一集群的副本共用,未配置或用了公开的开发默认值会拒绝启动;换密钥后,旧句柄全部失效,调用方要重新发现。
RDC 里还保留了一个旧版的 v2: 句柄编解码(没有签名),README 的 API 速查也还写着"仅接受 v2:"。统一 API 的签发器注释明确说旧格式"按设计不兼容"。接入时以你实际调用的接口版本为准。
实例从哪来
正式环境不靠实例自己"推送注册",而是由部署发现(DeploymentDiscoveryProvider)按对账周期(配置示例是 30 秒)从部署侧拉取;开启后,推送式 POST /register 直接返回 410。注册表以部署系统为唯一来源,健康状态再由探活更新。
小结
- 逻辑 Card 和实例路由分成两层:先找"谁能做",再找"打到哪"。
- 发现只返回已登记且新鲜的 Card;实例要在线且 15 秒内有心跳。
- 路由句柄由服务端签名、带租户,调用方只能拿来解析,不能伪造或跨租户使用。
源码出处
- agent-solution/common/agent-bus/registry-discovery-center/README.md两平面、API、密钥要求
- agent-solution/common/agent-bus/registry-discovery-center/src/main/java/com/openjiuwen/rdc/service/StructuredDiscoveryEngine.java:44
static DiscoveryResult discover(逻辑发现的过滤顺序 - agent-solution/common/agent-bus/registry-discovery-center/src/main/java/com/openjiuwen/rdc/model/DiscoveryOutcome.java:14
public enum DiscoveryOutcome四种发现结果 - agent-solution/common/agent-bus/registry-discovery-center/src/main/java/com/openjiuwen/rdc/repository/JdbcAgentRegistryRepository.java:105
DISCOVERY_VISIBILITY_FILTER =实例可见性:ONLINE/DEGRADED + 15 秒心跳窗口 - agent-solution/common/agent-bus/registry-discovery-center/src/main/java/com/openjiuwen/rdc/core/RouteHandleIssuer.java:33
public final class RouteHandleIssuerHMAC 签名的不透明路由句柄
链接指向固定提交,仓库后续更新不影响这里的行号。
过关测验
1. 逻辑发现接口 /api/registry/discover 会返回实例的访问地址吗?
2. 一个 Agent Card 被判为 STALE_CARD(数据已不可靠),发现时会怎样?
3. 为什么路由句柄要由服务端签名,并且把租户写进去?