16. 客户端 SDK、社区 Skill 与开发者体验

本章说明客户端层如何为资源提供方、调用方和节点运营者提供不同入口:oan-sdk-ts 面向程序化集成,社区技能包面向智能体辅助的资源整理、注册、发现和验证,官网提供浏览器交互。三者复用 OpenAgenet (OAN) 协议,不改变 DID、控制证明、注册 VC、根平台可信发布证明或治理状态的语义。主体私钥、资源控制私钥和本地身份备份留在客户端,服务端只接收公开材料和必要证明。

入口 主要使用者 核心职责 不承担的职责
TypeScript SDK 应用开发者、平台集成者 类型、请求构造、注册发现调用、验证辅助 替用户作出信任决定
社区技能包 资源提供方、智能体操作者 整理资源、辅助注册发现、解释结果 持有治理密钥或替代节点服务
官网 浏览器用户 交互式注册、发现、预览和本地下载 托管用户私钥或保证端点安全
运维辅助 节点运营者 构建、配置检查、部署与烟测 自动决定生产密钥和回滚策略

16.1 TypeScript SDK 范围

TypeScript SDK 由协议类型、HTTP 客户端、治理读取和工作流辅助组成,适合 Node.js、浏览器构建环境及兼容 fetch 的运行时。调用方可分别配置注册服务节点、发现服务节点、根平台和内容分发平台地址。SDK 负责序列化、请求和响应解析,不替调用方决定资源是否可信。

代码组织上,packages/protocol-types 提供 ResourceRegistrationSubmissionResourcePackage、发现查询和治理响应等共享类型;packages/client-ts 提供 OanClient 及各节点 HTTP 调用;packages/sdk-ts 提供 DID文档草稿、资源包绑定、哈希格式、信任摘要和生命周期判断;packages/governance-ts 面向链下信任索引器的治理读取。这样的分层使应用可以只依赖 HTTP 客户端,也可以在需要时组合资源校验和生命周期辅助,而不必复制协议结构。

能力域 SDK 提供 调用方仍需负责
DID 与资源模型 类型、解析和构造辅助 确认资源内容和控制关系
注册 请求构造、提交和状态读取 保管私钥、确认提交目标
发现 DID 精确查询、语义查询和结果解析 判断相关性是否满足业务需求
验证 证明字段读取和验证辅助 制定授权策略与最终调用决策
生命周期 汇总登记、发布、分发和可见性状态 处理超时、重试和业务补偿

SDK 的端点选择有两种常见方式:面向官网和社区用户时传入一个 baseUrl,由客户端派生官方网关下的服务地址;进行多节点或第三方节点测试时,分别传入 registrarEndpointdiscoveryEndpointrootEndpointcdnEndpoint。端点配置只决定请求发送到哪里,不会替调用方完成节点授权、资源控制证明或治理判断。

16.2 SDK 中的 DID 身份与密钥操作

身份和密钥操作在客户端完成。SDK 生成主体身份、资源 DID 和验证方法,使用私钥签署控制 challenge、资源版本或请求,并将公钥写入 DID文档。备份可包含主体和资源控制材料,但不得进入日志、HTTP 请求或索引;导入时应验证结构、DID 与公钥关系及签名能力。

Node.js 场景可以使用 identity-store-node 将主体、智能体和节点身份分桶保存到本地目录;浏览器场景则由网页状态或浏览器存储承载当前会话,并通过用户操作导出备份。两种实现的共同边界是:DID文档可以公开传播,私钥只能用于客户端签名;服务端收到的是已经签名的控制证明或节点请求包络,而不是原始私钥。

  • [x] 私钥生成、签名和备份导出发生在客户端。
  • [x] 注册请求只携带公开 DID文档、资源信息和必要控制证明。
  • [x] 导入备份前校验格式、版本、DID、公钥和签名能力。
  • [ ] 不得把私钥写入 URL、日志、遥测或服务端存储。

16.3 注册流程示例

注册流程应依次准备本地身份、资源 DID、DID文档、元数据、资源包、哈希和控制证明,再调用注册服务节点。下面只展示客户端调用边界,submission 应由经过本地校验和签名的实际数据构造:

import { OanClient } from "@openagenet/oan-sdk-ts/client";

const client = new OanClient({
  registrarEndpoint: "https://registrar.example.org",
});
const result = await client.registerResource(submission);

console.log({
  resourceDid: result.resourceDid,
  registrationVc: result.registrationVc ?? null,
});

注册 VC 可能暂缺,客户端应保存资源 DID、请求 ID 和状态;网络超时不能直接判断注册未发生。应先确认明确成功或失败,再按请求 ID 或资源 DID查询状态,并区分注册服务节点受理、根平台发布和发现索引可见三个阶段。

提交前的最小检查可以归纳为“对象一致、摘要一致、控制有效、目标明确”:didDocument.id 必须等于 resourceDid,资源类型必须与 DID 主体编码一致,DID文档、元数据和资源包的摘要必须对应实际内容,控制证明必须由相应资源控制私钥生成,注册端点必须是用户明确选择的注册服务节点。技能包可以辅助发现缺失项,但最终提交仍由客户端或用户确认。

登记受理 -> 根平台接受 -> 内容分发完成 -> 发现索引可见
     |             |                |                 |
   Registrar      Root             CDN             Discovery

16.4 DID 精确发现示例

DID 精确发现以资源 DID 为定位键,不依赖名称相似度。客户端调用发现接口后,应核对返回 DID、版本、资源包和证明引用,再验证 DID文档、版本哈希、生命周期、根平台可信发布证明和端点策略。

const resourceDid = "did:oan:SKDM:example";
const resource = await client.getDiscoveryResource(resourceDid);
if (resource.resourceDid !== resourceDid) {
  throw new Error("discovery_did_mismatch");
}

精确命中只证明发现服务节点返回了对应标识的记录,不能单独证明版本仍有效、节点仍获授权或业务端点可以安全调用。

应用在取得候选结果后,可以先按 resourceDid 做一致性检查,再按请求的版本模式选择候选版本,最后加载资源包或 DID文档完成证据验证。若详情接口返回 404,通常表示发现索引中存在候选摘要但对应详情尚不可读;客户端应保留该差异并向调用方报告,而不是把候选结果直接当作完整可调用对象。

16.5 语义发现示例

语义发现可组合自然语言任务、能力标签和结构化条件。官网英文查询 “I need a tool that can search code repositories and summarize the project structure.” 可作为示例输入:

const discovery = await client.discoverResources({
  query: "I need a tool that can search code repositories and summarize the project structure.",
  resourceType: "tool",
  limit: 10,
});

for (const candidate of discovery.candidates) {
  console.log(candidate.resourceDid, candidate.score);
}

响应应保留命中字段、标签、资源类型、协议、索引版本、来源和匹配原因。语义相关性回答“可能适用”,结构化条件回答“满足显式筛选”,可信证据回答“当前版本是否可验证”,三者不能互相替代。

SDK 对 HTTP 响应的封装应保留协议阶段,而不是把不同接口都压缩成一个布尔成功值。注册调用至少需要保留注册服务节点的 status、资源 DID、注册 VC 和根平台响应;发现调用需要保留 discoveryDid、候选数组、创建时间和可选响应 proof;动态状态或解释响应应保留原始 JSON,供上层按实际字段处理。这样,SDK 才能区分“登记已受理”“根平台已验证并排队”“资源已被发现”和“证据已完成验证”。

语义查询的结果处理宜分成两步:先用查询文本、资源类型、标签或协议缩小候选范围,再对候选逐项检查生命周期、授权域、服务绑定和证明状态。发现服务节点可能使用语义索引,也可能在后端不可用时回退到关键词检索;调用方应关注返回的候选和解释信息,不应把某一种搜索后端名称写死为业务依赖。

16.6 验证与信任证据处理

验证应先检查 DID文档与资源 DID、公钥和控制证明,再分别检查注册 VC、根平台可信发布证明和节点授权 VC 的签发者、主体、版本、签名、有效期、状态、授权域和能力范围。关键证明缺失或过期时,客户端应标记不可确认或拒绝使用。

证据 主要证明的事实 不能证明的事实
控制证明 提交者能使用对应控制私钥 注册服务节点已受理或资源已发布
注册 VC 注册服务节点对登记事实的声明 根平台已发布或端点安全
根平台可信发布证明 特定资源版本通过根平台验证并进入发布流程 所有发现服务节点均已索引
节点授权 VC 节点在授权域和期限内具备相应资格 节点返回的每条业务数据都正确
治理状态 当前治理侧记录的状态事实 资源功能质量和业务适用性

一个可复现的验证夹具至少包含:资源 DID、DID文档、资源包、对应摘要、控制证明或注册 VC,以及用于校验节点资格的节点 DID文档和授权材料。测试先使用未篡改材料确认通过,再分别修改 DID、版本、摘要、签发者或生命周期状态,确认 SDK 返回明确的验证错误。验证失败是否阻止使用取决于证据类型:控制证明或摘要失败通常应阻止登记,语义匹配不足则只影响候选排序,治理状态不确定则应阻止高风险调用或要求人工确认。

16.7 社区 Skill 包职责

社区技能包通过脚本和说明辅助资源整理、标签推荐、DID 生成、注册请求、发现查询、证据核验和结果解释。它不是注册服务节点、根平台或发现服务节点,不应持有治理密钥;用户确认、私钥使用、敏感路径和最终发布决定仍由用户或运营者控制。

典型交互遵循“读取材料 → 形成草稿 → 用户确认 → 本地签名 → 调用服务 → 解释结果”的顺序。技能包可以提示缺失字段、推荐语义标签和调用 SDK,但不得静默替换资源端点、扩大授权域或把推荐内容冒充资源提供方声明。

OanSkill 的公开工作流入口包括 draftRegistrationFromResourceDescription()registerFromResourceDescription()registerBatchFromResourceDescriptions()discover()lifecycle() 和只读治理辅助方法。资源描述工作流会返回候选信息、缺失输入、质量问题和建议动作;这使批量接入能够逐项修复,而不是因为一个资源失败就丢失整个批次的诊断结果。技能包默认使用官方公共网关,第三方节点只有在用户明确配置后才参与流程。

16.8 资源编写与注册辅助

资源编写辅助应统一处理智能体服务、技能包、MCP 服务和工具 API,并引导填写名称、描述、用例、端点、协议、版本、能力标签、授权域和资源包信息。推荐标签不是最终声明,生成前应检查 DID文档、元数据和资源包哈希一致性。

输入类别 最低检查内容 产出用途
身份与控制 主体 DID、资源 DID、验证方法 生成控制证明
能力语义 名称、描述、用例、能力标签 语义治理与发现
调用信息 协议、端点、认证提示 调用前筛选和协商
版本材料 版本、前序版本、资源包摘要 更新、幂等和完整性校验
治理边界 资源类型、授权域、生命周期 准入和发现过滤

资源整理时应把 authorizedDomainscapabilityTags 分开处理:前者是注册服务节点用于授权范围判断的机器可读域,后者是语义发现信号。技能包可以根据描述提出标签建议,但不能从 DID 主体编码、端点主机名或自然语言描述擅自推导授权域;无法确定时,应把缺失事实返回给用户补充。

16.9 节点运营者与部署辅助

节点运营辅助可执行依赖检查、配置检查、Rust 编译、服务启动、健康检查和部署后注册发现烟测。服务器、域名、密钥、生产配置及回滚由人工确认。

  • [x] 检查进程、监听端口和健康端点。
  • [x] 检查数据库连接与必要表结构。
  • [x] 检查链下信任索引器状态及同步序列是否持续推进。
  • [x] 验证注册结果结构、DID 精确发现和语义发现最小路径。
  • [ ] 不以单一健康端点成功代替完整业务烟测。

运维辅助的验收顺序应与业务传播顺序一致:先检查进程和健康端点,再检查数据库及节点授权状态,之后验证资源注册请求是否得到结构化响应,最后使用 DID 精确查询和语义查询确认发现链路。注册服务节点返回成功而根平台、内容分发平台或发现服务节点不可用时,应报告对应阶段,不应把整条链路压缩成一个“部署成功”结论。

16.10 包分发与兼容性管理

发布物必须包含运行入口、构建后的 JavaScript、类型声明、脚本、必要文档和依赖。社区技能包发布到 npm 时不得遗漏 SKILL.md、脚本或资源文件;SDK 发布前应从干净目录安装并验证导入、注册请求构造和发现请求构造。

发布验收至少包括:

  1. 预览实际入包文件,确认源码仓存在不等于发布包已包含。
  2. 在空目录安装待发布包,验证声明支持的模块入口。
  3. 运行最小注册、DID 精确发现和语义发现请求构造测试。
  4. 核对 README、类型声明、脚本和资源文件可从安装包访问。
  5. 对破坏性接口或协议语义变化提高主版本,并说明迁移边界。

对于社区技能包,npm 发布物还必须保留 SKILL.mdreferencesagentssrc 和构建后的 dist;不能只检查 TypeScript 编译成功。对于 SDK,应检查根入口及 ./client./governance./protocol-types./identity-store-node 等 exports 是否都指向实际存在的 JavaScript 和声明文件。发布验证应在未使用源码目录的空目录中执行,以便发现 package.jsonfiles、入口或依赖声明遗漏。

16.11 示例资源与集成模板

最小集成流程为:创建或导入本地身份;生成资源 DID、DID文档、元数据、资源包和控制证明;提交注册服务节点;执行 DID 精确查询;执行自然语言、标签和结构化发现;调用前验证版本、证明、治理状态和端点。

flowchart LR
    A[创建或导入本地身份] --> B[准备四类资源之一]
    B --> C[生成 DID文档与资源包]
    C --> D[本地签名并提交注册]
    D --> E[查询生命周期状态]
    E --> F[DID 精确发现或语义发现]
    F --> G[验证证明与治理状态]
    G --> H[业务侧决定是否调用]

SDK 是程序化入口,技能包是操作辅助,官网是交互入口。四类模板可以共享身份、版本、语义和证明字段,但协议、端点和资源包内容必须体现各自差异。

四类资源可以复用同一套接入骨架,但其调用材料不同:智能体服务通常需要可调用服务端点,技能包需要清单或下载入口,MCP 服务需要 MCP 协议绑定,工具 API 需要 API 端点和输入输出模式。模板中的 protocolBindings、服务端点、资源描述和包信息应按实际资源填写;不能因为四类资源都可被发现,就把一种资源的协议字段复制到另一种资源。

16.12 客户端安全与秘密处理

私钥和身份备份只在客户端生成、使用和保存。VC、DID文档和资源包按公开性分别处理;日志只记录 DID、版本、请求 ID、状态和错误代码,不记录私钥、完整本地身份或未脱敏签名原文。

客户端安全边界: 能够被下载或导出的本地身份文件属于控制权材料,不因其由官网生成而成为公开文件。注册 VC、DID文档和资源包也应按各自公开策略处理,不能因为共同打包下载就获得相同的披露级别。

SDK 和技能包的测试不应把真实私钥写入固定夹具或提交记录。自动化测试可以使用临时目录、临时密钥和占位 DID;测试结束后清理身份文件,并检查请求体、异常文本和日志中没有私钥字段。若应用需要长期保存本地身份,应由使用者选择加密存储、操作系统凭据库或离线备份方案,SDK 不应默认为用户上传到远程服务。

16.13 浏览器注册与本地身份备份行为

浏览器注册页面把本地身份作为用户控制材料。用户可新建并下载带时间标记的 oan-registration-identity.bundle.<timestamp>.json,也可导入备份;浏览器只向注册服务节点发送公开 DID文档、资源数据和控制证明。注册结果包必须在提交成功且确认资源 DID 后生成。

用户动作 浏览器侧变化 服务端影响
新建并备份 生成身份、更新当前主体、触发下载
从本地导入 校验并加载用户选择的备份
预览 DID文档 按当前表单和身份生成或复用预览 无注册提交
提交注册 校验当前输入并发送公开材料和证明 产生注册请求
成功后下载 打包 DID文档、注册 VC 和本地身份 不产生第二次注册

16.13.1 浏览器端密钥生成

浏览器端使用 Web Crypto 或 SDK 实现生成密钥并建立 DID 与公钥绑定。页面不得把私钥放入 DOM、URL、公开 API 或错误消息;刷新或清理站点数据可能丢失未备份状态,应提示用户及时备份。

16.13.2 本地身份导入

导入操作读取用户明确选择的 JSON 文件,检查版本、主体配置、资源配置和私钥材料结构,并验证 DID文档与公钥关系。导入失败不能覆盖已有有效身份;成功后预览和提交使用导入身份并重新计算控制证明。

16.13.3 本地备份下载

本地备份下载使用浏览器标准下载能力,文件名包含 oan-registration-identity.bundle 和生成时间,避免覆盖旧备份。服务端不参与文件生成,用户应将其作为敏感密钥备份保管。不同浏览器和移动系统对自动下载的支持存在差异,下载失败不得把空文件或未完成状态标记为有效备份。

16.13.4 注册结果打包下载

注册结果打包下载仅在服务端明确返回成功且页面确认资源 DID 后触发。压缩包名将资源 DID 中的冒号替换为连字符,包含注册 VC、DID文档和已有本地身份文件;VC 为空可保留空项,但失败、超时或缺少 DID 时不得下载。

16.14 DID、VC 与资源包下载格式

DID文档、注册 VC、资源包和本地身份备份使用可识别的 JSON 文件名和稳定编码。公开文件不得混入私钥;导入方按内容字段验证 DID、版本和哈希,不应仅凭扩展名或文件名信任。

文件 建议内容 敏感级别 最低校验
DID文档 DID、公钥、服务与 OAN 元数据 公开 DID、验证方法、结构版本
注册 VC 签发者、主体、声明、签名与状态引用 按签发和披露策略 签发者、主体、签名、有效期
资源包 资源描述、端点、能力与版本材料 按资源策略 资源 DID、版本、摘要
本地身份备份 主体及资源控制私钥材料 高敏感 包版本、DID、公钥私钥对应关系

未知字段在兼容版本内可以保留,缺失必填字段、无法识别的结构版本、摘要不一致或私钥混入公开文件时必须拒绝导入或发布。

下面是一个用于说明字段关系的示例资源包,其中 DID、摘要、时间和签名值均为占位值,不代表线上资源。示例展示公开资源包如何同时引用 DID 文档、元数据摘要、资源包摘要和根平台可信发布证明;实际实现还可以保留协议类型允许的扩展字段。

{
  "packageVersion": "1.0.0",
  "resourceDid": "did:oan:SKDM:ExampleResourceDid00000000000000000000",
  "resourceType": "skill",
  "didDocument": {
    "@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/oan/v1"],
    "id": "did:oan:SKDM:ExampleResourceDid00000000000000000000",
    "verificationMethod": [
      {
        "id": "did:oan:SKDM:ExampleResourceDid00000000000000000000#key-1",
        "type": "Ed25519VerificationKey2020",
        "controller": "did:oan:SKDM:ExampleResourceDid00000000000000000000",
        "publicKeyMultibase": "zExamplePublicKey"
      }
    ],
    "authentication": [
      "did:oan:SKDM:ExampleResourceDid00000000000000000000#key-1"
    ],
    "oanMetadata": {
      "subjectType": "skill",
      "resourceType": "skill",
      "resourceDescription": {
        "name": "Example repository structure skill",
        "description": "Searches a code repository and summarizes its project structure.",
        "capabilityTags": ["code-repository", "project-structure"]
      },
      "capabilityTags": ["code-repository", "project-structure"]
    }
  },
  "didDocumentHash": "sha256:example-did-document-hash",
  "metadataHash": "sha256:example-metadata-hash",
  "packageHash": "sha256:example-package-hash",
  "hashAlgorithm": "sha-256",
  "metadata": {
    "resourceDid": "did:oan:SKDM:ExampleResourceDid00000000000000000000",
    "resourceType": "skill",
    "subjectType": "skill",
    "name": "Example repository structure skill",
    "description": "Searches a code repository and summarizes its project structure.",
    "capabilityTags": ["code-repository", "project-structure"],
    "lifecycleState": "active",
    "packageVersion": "1.0.0",
    "packageHash": "sha256:example-package-hash",
    "metadataHash": "sha256:example-metadata-hash",
    "hashAlgorithm": "sha-256",
    "updatedAt": "2026-01-01T00:00:00Z"
  },
  "rootProof": {
    "rootDid": "did:oan:INPT:ExampleRootDid00000000000000000000",
    "signature": "zExampleRootSignature",
    "hashAlgorithm": "sha-256"
  },
  "createdAt": "2026-01-01T00:00:00Z"
}

上述资源包可以作为公开发布和发现侧的输入,但不能替代本地身份备份。后者还包含主体或资源控制私钥,必须单独导出、导入和保管;把本地身份与资源包放进同一个注册结果压缩包,只表示下载操作集中,不改变两类材料的敏感级别和验证方式。下载格式的兼容判断应以内容结构为准,文件名中的时间戳和 DID 只用于人类识别和避免覆盖,不能作为真实性、签发者或控制权证明。

参考来源

来源 类型 链接
oan-sdk-ts 代码仓:DID、身份、资源包、注册和发现客户端能力 https://github.com/OpenAgenet/oan-sdk-ts
oan-community-skill 代码仓:社区 Skill、脚本和开发者工作流 https://github.com/OpenAgenet/oan-community-skill
oan-protocol-common 代码仓:SDK 使用的协议类型和错误契约 https://github.com/wolfbrother/oan-protocol-common
OAN Yellow Paper arXiv 黄皮书:客户端、资源发布和验证流程 https://arxiv.org/abs/2606.03163
OAN White Paper arXiv 白皮书:开发者生态和开放基础设施定位 https://arxiv.org/abs/2606.03161
On this page