附录 E:参考部署与示例
本附录给出可用于开发、验证和运维交接的参考路径。规范要求关注角色边界、证据绑定、状态传播和接口语义;参考实现使用 Rust 节点、TypeScript SDK、社区技能包、PostgreSQL/NATS 及网站网关;具体域名、端口、密钥、数据库 URL、模型目录和系统服务名均属于环境配置。部署人员应先确认目标网络的信任根、授权域、节点 DID 和协议版本,再写入配置,不应复制示例中的私钥、令牌或线上地址。服务端编译产物、日志、缓存和数据库数据与源码归档分离,秘密只通过受保护的运行时配置注入。
采用版本化源码归档同步时,归档内容应来自已经确认的提交或发布版本,而不是工作区中未审查的文件。以下命令只表示一种通用的源码归档方式:
git archive --format=tar --prefix=release/ <COMMIT_OR_TAG> | gzip -c > <RELEASE_ARCHIVE>.tar.gz
该归档只代表源码交付物;构建目录、依赖缓存、数据库文件、运行时密钥和日志不应混入源码包。源码、构建产物、配置、运行数据和网站静态文件应分别存放在由部署环境定义的受控目录中,并通过发布记录关联其版本和摘要。目录名称、文件系统布局和传输方式属于环境实现,不是协议要求。
推荐的通用启动链路如下:
治理状态/节点授权
|
v
根平台验证与发布 -----> 内容分发平台 -----> 发现服务节点 -----> 调用方
^ ^ |
| | v
注册服务节点 --------------------+ 结构化/语义查询
^
|
资源控制方、SDK 或社区技能包
启动顺序应先满足数据库、消息系统和链下信任索引器等依赖,再启动根平台、注册服务节点、内容分发组件和发现服务节点,最后启动网站后端、静态前端和反向代理。关闭或升级时应先停止新的写入,再等待发布和分发队列达到可接受状态,保留数据库、游标、版本记录和脱敏日志后再替换程序。若某个依赖暂时不可用,服务应按照自身配置进行有限重试和退避,并对外报告 unknown、不可用或待同步,而不生成虚假的发布或授权事实。
E.1 官方网络部署
官方网络的参考分层是:注册服务节点承接资源接入,根平台执行网络级验证、发布和协调,内容分发平台传输根平台已验证的资源包和证明,发现服务节点建立授权域内的结构化与语义索引,链下信任索引器把治理事件投影为可查询状态,网站后端通过公共网关为前端提供展示和用户操作入口。网站不是信任权威;网站异常不应改变资源或节点的协议状态。
生产部署至少应核验以下链路:
- 数据库、消息系统和各节点监听地址已就绪,且外网只暴露经过反向代理保护的公共 HTTPS 入口。
- 根平台、注册服务节点、发现服务节点、内容分发平台和链下信任索引器分别通过
/health或其角色状态接口返回可解释状态。 - 注册服务节点能够完成受控的注册请求校验和根平台提交;注册烟测应使用专用测试资源或受控失败输入,不能污染生产资源目录。
- 根平台发布结果能被内容分发平台消费,发现服务节点能校验并索引,随后通过精确查询和语义查询观察可见性。
- 网站前端的
VITE_*端点指向当前公共网关,构建产物不得残留localhost或127.0.0.1;网站部署后执行注册、发现、Network、路由和浏览器控制台烟测。
部署记录应保存构建版本、配置摘要、服务切换时间、健康检查结果、注册和发现烟测结果、索引游标及失败重试信息。公共域名、节点地址和证书属于目标环境配置,迁移到其它环境时必须使用该环境经过授权的端点和证书。
各服务的发布应采用可回退的替换顺序:先验证新二进制和静态产物,再通过目标环境的服务管理器切换对应服务,最后通过公共入口检查路由。网站静态文件可先上传到受控的临时发布目录,完成文件数量、入口文件和端点引用检查后再切换当前版本;节点服务则应先保留旧二进制、配置和运行状态,再替换新版本。回退时只恢复已验证的旧版本,不重置数据库、发布游标或治理状态。
| 层次 | 典型观测 | 失败时的处理边界 |
|---|---|---|
| 进程层 | 服务管理器状态、监听端口、启动日志 | 修复配置或二进制后重启;不以进程存活代替业务可用 |
| 接口层 | /health、节点状态和公共路由状态码 |
区分反向代理、上游服务和请求格式问题 |
| 业务层 | 注册受理、根平台发布、发现查询 | 使用受控测试数据;失败时阻止发布或回退 |
| 数据层 | 数据库连接、游标、索引统计和版本记录 | 先保留现场和备份,不直接删除或重建业务数据 |
E.2 私有网络与联盟网络部署
私有或联盟网络可以把根平台、注册服务节点、发现服务节点和内容分发平台部署在组织内网或隔离网络中,但仍应保留相同的协议责任:根平台是网络级验证、信任授权、数据分发和语义治理枢纽,注册服务节点负责资源接入,发现服务节点只对已发布材料建立索引。网络隔离改变可达性,不改变 DID、控制证明、根平台可信发布证明、授权域和生命周期状态的判断规则。
典型配置边界如下:
| 配置项 | 私有/联盟网络处理方式 | 不应改变的事实 |
|---|---|---|
| 信任根 | 使用组织或联盟约定的根 DID、根密钥和治理流程,并通过安全配置注入。 | 节点授权必须可验证,不能只依赖网段或 IP 白名单。 |
| 资源可见性 | 通过授权域、发现节点分区和反向代理控制可见范围。 | 可见性过滤不能把域外资源伪装成域内资源。 |
| 数据分发 | 可使用内网 CDN、对象存储或节点间同步。 | 接收方仍需校验哈希、版本和根平台可信发布证明。 |
| 运维边界 | 将数据库、链下信任索引器和管理接口置于受控网络。 | 普通调用方不能因网络可达而获得私钥或治理写权限。 |
联盟成员接入时,应先提交节点身份、角色、端点、授权域和协议版本材料,再由治理权威授权;撤销或暂停应能够传播到根平台和发现服务节点。联调阶段使用独立数据库和测试域,避免将私有网络的测试资源误同步到官方公共网络。
联盟网络的边界还应体现在运维账号和数据备份上:节点运维人员可以管理进程、配置和日志,但不应从应用配置中读取资源控制方的私钥;资源发布者只提交公开 DID 文档、证明和资源包,不因网络位于内网而获得治理写权限。跨成员联调时,应为每个成员记录节点 DID、授权域、配置版本和撤销状态,测试结束后清理临时凭据和测试资源索引,但保留必要的审计摘要。
E.3 最小注册节点部署
最小注册服务节点只需要自身 DID文档和运行密钥、资源记录存储、根平台地址、根平台 DID 或受众、监听地址、CORS/网络策略和必要的数据库配置。参考 Rust 实现提供 /health、/registrar/did、/resources/register、兼容提交入口、注册状态、资源记录、能力标签树、标签建议和授权查询等接口;具体可用接口应以目标版本源码和配置为准。注册流程是:接收资源包,检查 DID 与资源类型、元数据、授权域、控制证明和哈希,生成面向根平台的签名请求,等待根平台验证和发布,再保存登记记录并返回注册凭证和根平台响应。
最小验证应包括:
curl -fsS "${REGISTRAR_BASE_URL}/health"
curl -fsS "${REGISTRAR_BASE_URL}/registrar/did"
curl -X POST "${REGISTRAR_BASE_URL}/resources/register" \
-H 'content-type: application/json' \
--data-binary @registration-request.json
${REGISTRAR_BASE_URL} 是由部署环境注入的示例变量,不是固定地址或端口要求。注册服务节点不得接收资源控制私钥;私钥在资源控制方的 SDK、浏览器或本地 Skill 中使用,节点只接收公钥、签名和公开证明。根平台不可达时,节点必须返回可区分的上游失败,不得把本地保存或受理显示为根平台已发布。
E.4 最小发现节点部署
最小发现服务节点需要自身身份和授权材料、根平台或内容分发平台同步端点、授权域、数据库、索引配置和监听地址。它先获取或接收根平台发布材料,验证根平台可信发布证明、资源包哈希、DID文档、版本和生命周期,再写入本地结构化索引;语义检索可在此基础上使用标签树、文本字段和向量索引,但不能跳过发布和授权验证。参考实现提供 /discovery/did、/discovery/resources/query、查询解释、查询建议、能力标签树、同步历史和索引统计等角色接口。
初始同步完成的判据不是“HTTP 请求成功”,而是:同步游标已记录,资源包的来源和哈希校验通过,授权域内资源进入索引,域外、暂停、撤销或协议不匹配资源被过滤,索引统计与同步记录一致。建议用固定资源集执行如下查询:
{
"query": "Find an MCP server for security audit",
"resourceType": "mcp_server",
"limit": 10
}
返回结果应能区分文本、标签、结构化条件和语义相关性等匹配来源,并保留资源 DID、版本、状态、来源和新鲜度字段。若根平台或内容分发平台暂时不可用,可以展示已知旧快照,但不得据此产生新的可信发布或授权结论。
发现服务节点的同步状态宜按下表区分,供 Network 页面、运维接口和告警规则共同使用:
| 状态 | 含义 | 可执行动作 |
|---|---|---|
ready |
游标推进、索引可查询且最近一次验证成功 | 允许正常查询 |
syncing |
正在全量或增量同步 | 可查询已确认数据,标明同步状态 |
stale |
仍有旧索引,但超过环境设定的新鲜度边界 | 降级展示或阻止敏感调用 |
unknown |
无法确认上游、游标或治理状态 | 不得据此确认资源可信或可调用 |
这里的状态是运维和展示层的观察结果,不是对资源生命周期状态的替代。具体新鲜度阈值应由部署环境和运维策略给出,不能从一次查询响应推导出协议固定时延。 最小注册服务节点的配置可抽象为以下环境配置示意;其中值均为占位值,不能直接用于生产:
REGISTRAR_LISTEN_ADDR=<LISTEN_ADDRESS>
ROOT_ENDPOINT=<AUTHORIZED_ROOT_ENDPOINT>
DATABASE_URL=<DATABASE_CONNECTION_REFERENCE>
NODE_DID=<NODE_DID>
AUTHORIZED_DOMAINS=<AUTHORIZED_DOMAIN_SET>
启动后至少要分别记录“节点可达”“请求被本地校验”“请求已提交根平台”三个结果。后两个结果不能由同一个 HTTP 200 状态码含混表示;如果根平台返回超时或未知,注册服务节点应保留可重试的请求关联信息,并把结果标为未知或待处理。
E.5 SDK 注册示例
SDK 示例应体现私钥只在调用方本地使用、DID文档与资源包绑定、注册请求由指定注册服务节点受理以及注册结果需要继续观察发布和发现状态。以下代码展示接口关系,端点、域名和资源内容须按环境替换:
import { createAgentIdentity, createRegistrationSubmissionFromIdentity } from "@openagenet/oan-sdk-ts";
import { OanClient } from "@openagenet/oan-sdk-ts/client";
const identity = await createAgentIdentity(
"Repository structure summarizer",
"skill",
undefined,
{
domainCode: "DM",
authorizedDomains: ["technology.software_engineering"],
manifestUrl: "https://example.invalid/skill/manifest.json",
description: "Searches code repositories and summarizes project structure.",
capabilityTags: ["code.repository", "analysis.summary"],
},
);
const submission = createRegistrationSubmissionFromIdentity(identity, {
endpoint: "https://example.invalid/skill/manifest.json",
packageVersion: "1.0.0",
packageHash: "sha256:replace-with-real-hash",
metadataHash: "sha256:replace-with-real-hash",
});
const client = new OanClient({
registrarEndpoint: process.env.OAN_REGISTRAR_ENDPOINT!,
});
const result = await client.registerResource(submission);
console.log(result.status, result.resourceDid, result.registrationCredential);
这是 SDK 流程示意,真实发布前必须使用实际包哈希、完整资源描述、可访问端点和 Registrar 接受的授权域;不能把 example.invalid 或占位哈希作为可发布材料。SDK 返回的 VC、根平台响应和资源 DID 应由调用方保存并按状态继续验证,SDK 不会替调用方保管私钥或自动授予业务调用权限。
注册结果处理时,应把网络异常、注册服务拒绝、注册服务已受理但根平台结果未知、以及根平台已发布分别记录。示意代码只展示结果分支,不把 result 的某个字段当作所有版本都存在的固定字段:
try {
const result = await client.registerResource(submission);
console.log("registrar response received", result);
// 由调用方继续读取并验证 VC、根平台发布状态和发现可见性。
} catch (error) {
console.error("registration transport or client error", error);
// 不要在无法确认结果时自动生成新的 DID 或无条件重复提交。
}
真实接入应把请求关联标识、资源 DID 和本地身份备份安全保存;错误日志只能保存脱敏摘要,不能输出签名私钥、本地身份备份全文或数据库连接串。
E.6 DID 与语义发现示例
DID 精确查询用于确认一个已知资源是否在指定发现服务节点的授权视图中可见;语义查询用于从任务描述出发寻找候选资源。两者都应返回候选资源的 DID、资源类型、版本、状态、能力标签、授权域、端点或端点引用、来源和验证摘要。调用方不能因为语义匹配分数高、标签命中或网站显示推荐,就跳过 DID文档、根平台可信发布证明、VC、生命周期和端点验证。
const exact = await client.discoverResources({
resourceDid: "did:oan:SKDM:replace-with-a-real-identifier",
limit: 1,
});
const semantic = await client.suggestDiscoveryQuery({
query: "Find an MCP server for security audit",
});
const candidates = await client.discoverResources({
query: "Find an MCP server for security audit",
resourceType: "mcp_server",
capabilityTags: semantic.capabilityTags,
limit: 10,
});
若实现支持查询解释,应进一步读取 explain 结果,说明查询如何转为结构化条件、标签或语义条件,以及候选为何被保留或过滤。没有命中时返回稳定空结果;查询过短、域外或非法筛选条件应返回受控错误。分页和去重应依据 DID 与版本规则处理,不能把同一资源的多个索引副本展示为多个独立资源。
精确查询和语义查询可以使用同一发现入口,但验收断言不同:精确查询重点检查唯一性、DID 完整匹配和版本选择;语义查询重点检查候选来源、过滤原因和排序解释。一个最小的人工验收记录可以写成:
queryType=semantic
query=Find an MCP server for security audit
resourceDid=did:oan:MC:example-identifier
matchedBy=capabilityTags,text
governanceState=active
source=authorized-discovery-index
verification=root-proof-and-package-hash
其中 example-identifier 只是占位值。若结果只有文本相似度而没有可验证的来源、治理状态或证明摘要,应视为候选推荐,不应直接作为可信调用对象。
E.7 资源验证示例
调用方收到发现结果后,应按“身份、绑定、来源、治理、端点”顺序验证:首先解析 did:oan 并检查 DID文档中的公钥、控制者和服务引用;然后检查资源包的资源 DID、类型、版本、DID文档哈希、元数据哈希和包哈希;再验证根平台可信发布证明及其生命周期状态;随后检查注册 VC 的签发者、主体、授权域、哈希绑定和证明;最后根据业务策略验证端点、协议、证书和调用权限。任何一项失败都应阻止高风险调用,并保存脱敏的失败原因。
import { verifyResourcePackageShape, assertUsableLifecycle } from "@openagenet/oan-sdk-ts";
verifyResourcePackageShape(resourcePackage);
assertUsableLifecycle(resourcePackage);
// 继续使用调用方自己的 VC、节点授权和端点验证策略。
SDK 的结构校验函数不能替代治理状态读取、网络新鲜度判断或业务授权。验证结果应记录所依据的版本、来源 URL、哈希、签发者、状态时间和验证组件版本;不要记录私钥、令牌或完整的敏感请求。
E.8 运维烟测示例
部署后烟测应按依赖顺序执行,并把“服务可达”“协议动作成功”“状态已收敛”分开记录。推荐检查序列为:健康接口和端口;数据库连接与迁移状态;根平台状态和治理/授权读取;注册服务节点健康与受控注册请求;内容分发队列和发布状态;发现服务节点同步游标、索引统计、精确查询和语义查询;链下信任索引器最新游标;网站后端健康、前端路由、注册/发现传输和浏览器控制台。部署流程应在公共端点、注册传输、发现查询、Network 摘要和浏览器路由检查通过后才视为完成。
一个烟测记录可采用以下结构:
{
"deploymentId": "2026-09-07T12:00:00Z-<commit>",
"environment": "<environment>",
"checks": [
{"name": "root-health", "status": "pass", "observedAt": "..."},
{"name": "registration-transport", "status": "pass", "resourceDid": "..."},
{"name": "discovery-query", "status": "pass", "candidateCount": 1},
{"name": "trust-indexer-freshness", "status": "unknown", "reason": "..."}
]
}
示例中的 DID、时间和状态为记录格式示意。烟测失败时,应先判断是网络传输、编译产物、配置、数据库、治理状态、同步延迟还是功能错误,再决定重试、回滚或阻止对外发布;不能通过删除日志、重置游标或跳过注册/发现检查来获得表面成功。
E.9 同 DID 更新示例
同 DID 更新必须由原资源控制方或明确获授权的控制方产生新的控制证明,DID 本身保持不变,资源包或 DID文档中的可更新内容形成新的版本和哈希。流程是:读取本地身份和当前版本,修改元数据或资源包,递增符合版本方案的版本号,重新计算元数据和包哈希,签署更新材料,提交注册服务节点,由根平台重新验证并形成新的根平台可信发布证明,再经内容分发平台和发现服务节点同步。发现服务节点默认以最新可用版本响应,但必须保留可审计的版本和状态信息。
更新测试应覆盖无控制证明、控制证明对应旧材料、版本回退、同版本内容冲突、更新后哈希不一致和旧版本重新发布等情况。失败更新不得覆盖当前有效版本,也不得因为注册服务节点返回 VC 就被发现节点当作新版本;注册凭证、根平台发布证明和发现状态应分别记录。
更新完成后的对照记录至少应包含:旧版本和新版本的资源 DID、DID 文档哈希、资源包哈希、控制证明摘要、根平台发布证明摘要、发现索引版本和查询时间。若内容未变化,客户端可以复用已有预览或幂等结果;若任一影响绑定关系的字段变化,则必须重新计算哈希并重新验证,不能只修改展示用的版本字符串。
E.10 资源暂停与恢复示例
暂停、撤销和恢复是生命周期事实,不等同于删除 DID 或抹除历史。治理权威或资源控制方按允许的治理流程产生状态变更,根平台和链下信任索引器读取并投影该事实,发现服务节点同步后过滤不可用资源,调用方在验证时重新检查状态。暂停通常表示暂时不可用,撤销表示当前凭证或资源状态不再可用;恢复必须有明确的恢复依据,不能由发现节点自行把资源改回 active。
状态变更事实 -> 治理事件/授权材料 -> 根平台与索引器读取
-> 发现服务节点更新过滤状态 -> 调用方重新验证后决定是否调用
审计记录应包括资源 DID、原状态、新状态、事实来源、事件或请求标识、观察时间、传播时间和执行结果。治理状态未同步或超过允许新鲜度时,敏感调用应 fail-closed;网站或旧快照可以展示“待同步”,但不能显示为当前可调用。
E.11 跨协议 A2A 与 MCP 映射示例
跨协议映射的目标是降低现有 Agent 平台、MCP 客户端和工具调用方接入 OpenAgenet (OAN) 的成本,不是把不同协议的对象强行视为同一个对象。映射时可将 OAN DID文档和资源描述中的名称、能力标签、用途、输入、输出、服务端点、协议绑定和版本映射到 A2A Agent Card、MCP 服务元数据或工具 API 描述;反向转换时必须保留原始 DID、原始字段、版本、来源和哈希。A2A Agent Card 或 MCP 元数据说明能力和连接方式,但不替代 OAN 的控制证明、VC、根平台可信发布证明、治理状态和授权域。
OAN DID文档/资源包
- id, resourceType, capabilityTags, useCases
- protocolBindings, service endpoint, version, hashes
|
+--> A2A Agent Card: identity reference, skills, interfaces
+--> MCP metadata: server capabilities, tools, transport
+--> Tool/API description: operation, schema, endpoint
映射器应明确字段来源和转换方向:能力名称可用于展示和检索,DID 和哈希用于身份与完整性追溯,签名和 VC 作为独立验证材料保留,端点映射只代表连接入口而不自动授权调用。若目标协议没有等价字段,应使用扩展字段或附加引用,并在结果中标明丢失信息;不得把语义相似、协议兼容或元数据转换成功解释为资源可信或业务可用。
下面的映射关系只说明信息如何被携带,不规定 A2A Agent Card、MCP 元数据或工具 API 描述必须采用 OAN 的字段名:
| OAN 信息 | 外部描述中的可能承载位置 | 保留要求 |
|---|---|---|
| 资源 DID、DID 文档来源 | 身份引用或扩展字段 | 保留原始 DID 和来源,不改写成普通名称 |
| 能力标签、用例和描述 | Agent Card skills、MCP capabilities 或工具说明 | 可用于展示和检索,不能替代证明 |
| 协议绑定、端点和输入输出 | 接口、传输和 schema 描述 | 保留版本和来源,端点可用性需另行验证 |
| VC、哈希和根平台可信发布证明 | 外部对象的验证附件或引用 | 不因转换成功而删除或覆盖原始证明 |
映射后的对象如果重新进入 OAN 注册或发现流程,应重新执行 DID、哈希、控制证明、授权域和生命周期检查;一个外部协议对象可作为接入材料,但不能单独成为 OAN 的发布事实。
参考来源
| 来源 | 类型 | 链接 |
|---|---|---|
oan-root-services |
代码仓:根平台部署和发布示例 | https://github.com/OpenAgenet/oan-root-services |
oan-registrar-node |
代码仓:注册服务部署和注册示例 | https://github.com/OpenAgenet/oan-registrar-node |
oan-discovery-node |
代码仓:发现服务部署、同步和查询示例 | https://github.com/OpenAgenet/oan-discovery-node |
oan-trust-indexer |
代码仓:信任索引器部署和治理同步示例 | https://github.com/OpenAgenet/oan-trust-indexer |
oan-sdk-ts |
代码仓:客户端集成示例 | https://github.com/OpenAgenet/oan-sdk-ts |
oan-community-skill |
代码仓:社区注册发现操作示例 | https://github.com/OpenAgenet/oan-community-skill |
| OAN Yellow Paper | arXiv 黄皮书:参考部署和端到端机制 | https://arxiv.org/abs/2606.03163 |
| OAN Resource Identity and Discovery | IETF 草案:资源身份和发现示例边界 | https://datatracker.ietf.org/doc/draft-xu-oan-resource-identity-discovery/ |