Appearance
2026-07-15 已接入方迁移指南
适用对象:已经接入知办AI
/api/external/v1/*、ZAP Runtime、A2A、Python / Go SDK 或应用单点登录的研发团队。
生效日期:2026-07-15。当前接口仍处于开发联调阶段,本次直接切换,不设置旧字段兼容期。
使用方式:可以把本文完整交给项目内的 Codex、Claude Code 或其他代码助手,让它先盘点调用点,再按文末验收清单修改和测试。
一、先看结论
本次迁移包含三部分:
- 资源标识字段统一:知办AI资源使用
id/<resource>_id,对方系统资源使用third_<resource>_id。 - SDK 和 ZAP/A2A 公共 API 同步改名:Python 属性、关键字参数以及 Go 结构体字段、方法参数都同步切换,不保留旧名称。
- 同日接入契约补齐:增加按数字员工检索关联知识库的入口、ZAP 标准健康检查,并补齐应用单点登录的 Token 与 ID Token 说明。
这是破坏性切换
- 请求只接受新字段,响应只返回新字段。
- 旧字段不再标记 deprecated,也不做 alias、双读、双写或回填。
- 请求携带旧字段或其他未知字段时,服务端返回 HTTP
400。 - 服务端和调用方必须约定同一联调窗口完成切换;错开部署时旧请求会失败。
这次只修改线缆字段和 SDK 公共接口名称。资源 ID 的实际值、URL 层级、鉴权方式、权限 Scope 和数据库历史列名没有因为改名而变化。
二、影响范围判断
| 你的项目使用了什么 | 是否要改 | 重点章节 |
|---|---|---|
| 原生 HTTP 调用通知、主动聊天、组织、知识库 | 是 | 第三节 |
runtime_access 换取 Session Token | 是 | 第三节“Runtime Access Token” |
| Python SDK | 是 | 第四节 |
| Go SDK | 是 | 第五节 |
| 自建 ZAP Runtime | 是 | 第六节 |
| A2A discover / invoke / edge | 是 | 第三节“A2A”及第四、五节 |
| 应用栏 H5 单点登录 | 需要核对 | 第七节 |
| 只使用 OAuth 标准字段或 Runtime 自己的本地 ID | 通常不改 | 第八节 |
三、HTTP / JSON 字段替换表
3.1 通用规则
| 含义 | 新字段 | 不再使用 |
|---|---|---|
| 当前资源自身的稳定标识 | id | uuid |
| 引用知办AI数字员工 | agent_id | agent_uuid / digital_employee_uuid |
| 引用知办AI用户 | user_id 或领域明确的 account_id | user_uuid / account_uuid |
| 引用知办AI会话 | conversation_id | conversation_uuid |
| 引用知办AI房间 | room_id | room_uuid |
| 引用知识库 | knowledge_base_id | kb_uuid |
| 引用文件 | file_id | file_uuid / drive_file_uuid |
| 对方系统自己的资源 | third_<resource>_id | external_id / external_code / employee_id |
所有知办AI资源 ID 都按不透明字符串处理。不得解析 UUID 版本、长度、前缀或生成算法,也不得由调用方自行生成。
3.2 通知与主动聊天
| 位置 | 新字段 | 删除字段 |
|---|---|---|
| 通知 / 主动聊天目标 | user_id、agent_id | account_uuid、user_uuid、agent_uuid |
| 通知的对方业务标识 | third_notification_id | external_id |
| 主动消息的对方业务标识 | third_message_id | external_id |
| 通知响应 | notification_id、conversation_id、room_id | notification_uuid、conversation_uuid、room_uuid |
| 主动消息响应 | message_id、conversation_id、room_id | message_uuid、conversation_uuid、room_uuid |
请求示例:
json
{
"user_id": "<知办用户ID>",
"agent_id": "<知办数字员工ID>",
"title": "审批待处理",
"description": "请确认处理方案",
"third_notification_id": "ticket-1024"
}third_notification_id / third_message_id 是调用方系统生成的业务标识,不是知办AI资源 ID。它们的唯一范围至少应包含“租户 + 接入来源”。
3.3 组织与人员
| 位置 | 新字段 | 删除字段 |
|---|---|---|
| 部门对象 | id、parent_id | uuid、parent_uuid |
| 部门的对方标识 | third_department_id | external_code |
| 成员对象 | account_id、department_id | account_uuid、department_uuid |
| 成员的对方标识 | third_user_id | employee_id |
| 职位对象 | id | uuid |
| 职位的对方标识 | third_position_id | external_code |
| 组织 Webhook | tenant_id、entity_id | tenant_uuid、entity_uuid |
成员没有独立的成员 UUID,account_id 承载知办账号的稳定标识。对方 HR / IAM / OA 中的员工编号应放在 third_user_id,不能放在 account_id。
路径参数名同步改为 {department_id}、{account_id}、{position_id}。URL 层级和值本身不变。
3.4 知识库
| 位置 | 新字段 | 删除字段 |
|---|---|---|
| 知识库对象 | id | uuid |
| 文档对象 | id、knowledge_base_id | uuid、kb_uuid |
| 单库检索响应 | knowledge_base_id、document_id | kb_uuid、document_uuid |
| 路径参数名 | {knowledge_base_id}、{document_id}、{user_id} | {uuid}、{doc_uuid}、{user_uuid} |
指定数字员工检索其已关联知识库,新增统一入口:
http
POST /api/external/v1/knowledge/retrieve
Authorization: Bearer <runtime_access 换出的 st_>
Content-Type: application/json
{
"agent_id": "<知办数字员工ID>",
"query": "年假如何折算?"
}返回结果使用 knowledge_base_id、document_id。调用方不需要先获取知识库 ID 列表;Agent Bus 会在 token 的租户和 Runtime 边界内解析该数字员工的知识库绑定。
指定某一个知识库检索仍使用:
http
POST /api/external/v1/knowledge-bases/{knowledge_base_id}/retrieve两者用途不同,不要把“按数字员工聚合检索”改回“由调用方遍历多个知识库”。
3.5 Runtime Access Token
| 位置 | 新字段 | 删除字段 |
|---|---|---|
| 换令牌请求的 Agent 绑定 | agent_id | agent_uuid |
| 换令牌请求的用户绑定 | account_id | account_uuid |
| 换令牌响应 | session_token_id、bound_agent_id、bound_account_id | session_token_uuid、bound_agent_uuid、bound_account_uuid |
请求示例:
json
{
"grant_type": "runtime_access",
"client_id": "agentsdk_xxx",
"client_secret": "***",
"tenant_id": "<租户范围>",
"agent_id": "<发起方数字员工ID>",
"account_id": "<可选的知办用户ID>"
}agent_id 仅在需要 Agent-bound token(例如 A2A)时传;account_id 仅在需要用户实例绑定时传。普通知识库、通知或记忆 backchannel 不要为了“字段齐全”盲目增加这两个字段。
3.6 ZAP 会话与身份
| 对象 / 位置 | 新字段 | 删除字段 |
|---|---|---|
user | tenant_id、user_id | tenant_uuid、account_uuid |
agent | agent_id | digital_employee_uuid / agent_uuid |
conversation_context_hint | tenant_id、user_id、conversation_id | account_id、conversation_uuid |
| 调试上下文 | debug_session_id | debug_session_uuid |
| A2A 会话上下文 | a2a_edge_id | a2a_edge_uuid |
| identity user | user_id、membership_id | account_uuid、membership_uuid |
| identity 路径参数 | {tenant_id}、{user_id} | {tenant_uuid}、{account_uuid} |
标准会话请求应类似:
json
{
"agent_key": "main",
"agent": { "agent_id": "<知办数字员工ID>" },
"user": {
"tenant_id": "<知办租户ID>",
"user_id": "<知办用户ID>"
},
"session_kind": "single",
"conversation_context_hint": {
"tenant_id": "<知办租户ID>",
"user_id": "<知办用户ID>",
"conversation_id": "<知办会话ID>",
"purpose": "production"
}
}ZAP SDK 现在严格拒绝未知 JSON 字段。继续发送旧的 tenant_uuid、account_uuid、agent_uuid 等字段会直接失败,不会被静默忽略。
3.7 A2A
| 位置 | 新字段 | 删除字段 |
|---|---|---|
| discover 候选 | agent_id | agent_uuid |
| invoke 目标 | to_agent_id | to_agent_uuid |
| invoke 上下文 | room_id、parent_edge_id | room_uuid、parent_edge_uuid |
| invoke 回执 | edge_id、approval_request_id | edge_uuid、approval_request_uuid |
| edge | edge_id、from_agent_id、to_agent_id | edge_uuid、from_agent_uuid、to_agent_uuid |
| SSE event | edge_id | edge_uuid |
| 可调用白名单 | agent_ids | agent_uuids |
| ZAP 编排 | orchestration_id、step_id、worker_agent_id、call_edge_id、trigger_message_id | orchestration_uuid、step_uuid、worker_agent_uuid、call_edge_uuid、trigger_msg_uuid |
edge_created_at 仍是 edge 分区查询的一部分,调用方必须把 invoke 返回的值原样传给 get / cancel / stream,不能截断小数秒。
3.8 EMP 消息与文件引用
| 新字段 | 删除字段 | 说明 |
|---|---|---|
message_id | message_uuid | 知办消息稳定标识 |
source_message_id | source_message_uuid | 引用的来源消息 |
file_id / file_ids | file_uuid / file_uuids / drive_file_uuid | 文件与附件引用 |
如果接入方会解析或回传 EMP file / image / 表单上传结果,必须同步修改本地 DTO、模板、日志字段和测试 fixture。
四、Python SDK 迁移
必须使用包含本次字段切换代码的发布 commit/tag。当前源码包版本字符串可能与之前相同,不能只看 0.5.0 就判断是否已经升级。
4.1 公共 API 改名
| 旧 Python 用法 | 新 Python 用法 |
|---|---|
kb.uuid | kb.id |
chunk.document_uuid | chunk.document_id |
result.kb_uuid | result.knowledge_base_id |
client.kb.get(uuid) | client.kb.get(knowledge_base_id) |
client.kb.list_documents(kb_uuid) | client.kb.list_documents(knowledge_base_id) |
client.kb.retrieve(uuid, ...) | client.kb.retrieve(knowledge_base_id, ...) |
client.kb.list_user_private(user_uuid) | client.kb.list_user_private(user_id) |
for_runtime_access(..., agent_uuid=..., account_uuid=...) | for_runtime_access(..., agent_id=..., account_id=...) |
provider.bound_agent_uuid | provider.bound_agent_id |
provider.bound_account_uuid | provider.bound_account_id |
notifications.agent_conversation(..., external_id=...) | notifications.agent_conversation(..., third_notification_id=...) |
chat.send_message(..., external_id=...) | chat.send_message(..., third_message_id=...) |
Department.uuid / parent_uuid / external_code | Department.id / parent_id / third_department_id |
Member.account_uuid / department_uuid / employee_id | Member.account_id / department_id / third_user_id |
Position.uuid / external_code | Position.id / third_position_id |
DiscoveredAgent.agent_uuid | DiscoveredAgent.agent_id |
InvokeAck.edge_uuid | InvokeAck.edge_id |
invoke(to_agent_uuid=..., room_uuid=..., parent_edge_uuid=...) | invoke(to_agent_id=..., room_id=..., parent_edge_id=...) |
get_edge(edge_uuid, ...) | get_edge(edge_id, ...) |
新增按数字员工聚合检索:
python
result = client.kb.retrieve_associated(
agent_id="<知办数字员工ID>",
query="年假如何折算?",
)
for item in result.items:
print(item.knowledge_base_id, item.document_id, item.content)4.2 Python ZAP handler 上下文
| 旧属性 | 新属性 |
|---|---|
ctx.tenant_uuid | ctx.tenant_id |
ctx.account_uuid | ctx.user_id |
ctx.agent_uuid | ctx.agent_id |
ctx.conversation_uuid | ctx.conversation_id |
ctx.a2a_edge_uuid | ctx.a2a_edge_id |
session.tenant_uuid | session.tenant_id |
session.account_uuid | session.user_id |
session.agent_uuid | session.agent_id |
推荐继续使用 SDK router:
python
from fastapi import FastAPI
from zhiban_agent_sdk.zap.fastapi import build_router
app = FastAPI()
app.include_router(build_router(runtime), prefix="/zap/v1")新版 router 自动提供带 Runtime bearer 鉴权的 GET /zap/v1/healthz,并对 ZAP 请求执行严格 JSON 字段校验。不要在业务项目里复制一套旧 router。
五、Go SDK 迁移
必须使用包含本次字段切换代码的发布 commit/tag。Go module 没有内嵌版本常量,不能继续沿用旧 tag 后只修改业务代码。
5.1 公共结构体与方法
| 旧 Go 用法 | 新 Go 用法 |
|---|---|
KnowledgeBase.UUID | KnowledgeBase.ID |
Document.UUID / KBUUID | Document.ID / KnowledgeBaseID |
RetrieveChunk.DocumentUUID | RetrieveChunk.DocumentID |
RetrieveResponse.KBUUID | RetrieveResponse.KnowledgeBaseID |
NewWithRuntimeAccess(..., agentUUID) | NewWithRuntimeAccess(..., agentID) |
NewWithRuntimeAccessContext(..., agentUUID, accountUUID) | NewWithRuntimeAccessContext(..., agentID, accountID) |
Client.BoundAgentUUID() | Client.BoundAgentID() |
Client.BoundAccountUUID() | Client.BoundAccountID() |
ExternalID | ThirdNotificationID 或 ThirdMessageID |
MessageUUID / ConversationUUID / RoomUUID | MessageID / ConversationID / RoomID |
DiscoveredAgent.AgentUUID | DiscoveredAgent.AgentID |
InvokeRequest.ToAgentUUID | InvokeRequest.ToAgentID |
InvokeRequest.RoomUUID / ParentEdgeUUID | InvokeRequest.RoomID / ParentEdgeID |
InvokeAck.EdgeUUID | InvokeAck.EdgeID |
Edge.EdgeUUID | Edge.EdgeID |
新增按数字员工聚合检索:
go
result, err := client.KB().RetrieveAssociated(ctx, agentID, "年假如何折算?")
if err != nil {
return err
}
for _, item := range result.Items {
fmt.Println(item.KnowledgeBaseID, item.DocumentID, item.Content)
}5.2 Go ZAP Runtime
| 旧字段 | 新字段 |
|---|---|
MessageContext.TenantUUID | MessageContext.TenantID |
MessageContext.AccountUUID | MessageContext.UserID |
MessageContext.ConversationUUID | MessageContext.ConversationID |
Session.TenantUUID | Session.TenantID |
Session.AccountUUID | Session.UserID |
Session.ConversationUUID | Session.ConversationID |
IdentityTenant.TenantUUID | IdentityTenant.TenantID |
IdentityUser.AccountUUID | IdentityUser.UserID |
IdentityAgentContext.DigitalEmployeeUUID | IdentityAgentContext.AgentID |
runtime.Handler("/zap/v1") 现在自动暴露 GET /zap/v1/healthz,并使用严格 JSON 解码。业务项目不应继续维护旧版手写 ZAP endpoint。
六、自建 Runtime / agent-example 对齐项
如果同事的项目是从旧版 agent-example 复制出来的,应逐项同步:
- 用新版 Python 或 Go ZAP SDK router,不复制 RuntimeCard、bearer 校验、session 和 SSE 编码。
- handler 中统一读取
tenant_id、user_id、agent_id、conversation_id、a2a_edge_id。 - A2A 调用统一使用
to_agent_id和edge_id,不要保留*_uuid回退。 - 附件和 EMP 文件统一读取、返回
file_id。 - Runtime 必须提供低成本、无副作用的
GET /zap/v1/healthz;健康检查不得调用 LLM、知识库或对方业务系统。 - 如果需要查询当前数字员工关联的知识库,调用
POST /api/external/v1/knowledge/retrieve或 SDK 的retrieve_associated,不要让 Runtime 自己猜绑定关系。 - 本地数据库列名可以继续叫
easyo_tenant_uuid、easyo_account_uuid;这是接入方内部存储,不属于线缆字段,不需要为了本次迁移改库。
runtime_identity.tenant_id/user_id/agent_instance_id 是接入方 Runtime 自己生成和管理的本地资源 ID,继续保持,不增加 third_ 前缀。
七、应用单点登录接入同步项
应用接入的产品名称统一叫“单点登录接入”,底层仍使用 Agent Bus 的 OAuth2 authorization_code 流程。它不依赖租户是否配置企业 OIDC。
7.1 Token 请求
正式请求格式改为标准表单:
http
POST /api/external/v1/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=...&client_id=...&client_secret=...服务端当前继续兼容已有应用的 JSON 请求体,但新代码和 SDK 应使用 application/x-www-form-urlencoded。成功响应保持 OAuth/OIDC 顶层字段,不套 Bus 业务响应信封:
json
{
"access_token": "...",
"id_token": "...",
"refresh_token": "...",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "kb.read contacts.read"
}7.2 ID Token Claim
应用后端完成 RS256、iss、aud、exp、iat 校验后,从 ID Token 读取:
- 标准用户字段:
sub、name、email、email_verified、phone_number; - 当前租户:
tenant.uuid、tenant.name; - 当前成员关系:
membership.employee_no、membership.title、membership.department; - 可选会话上下文:
zhiban_context.conversation_id、conversation_kind、peer。
本次明确:
- 不新增
/oauth/userinfo或“解码 ID Token”私有接口; - 不返回
auth_time; state/nonce当前只用于请求关联和协议兼容,不能宣称已完成登录 CSRF / replay 防护;- Discovery 和 JWKS 应按 TTL 缓存,遇到未知
kid时强制刷新一次; tenant.uuid、zhiban_context.peer.uuid是本次应用 ID Token 契约中的现有扩展字段,不要因本指南其他资源改成_id就自行重命名。
应用浏览器端不得解析或保存 ID Token、client_secret、Access Token、Refresh Token。换码、验签和业务 Session 必须全部在应用后端完成。
八、这些字段不要机械修改
| 字段 | 保持原因 |
|---|---|
OAuth client_id、client_secret、id_token、access_token、refresh_token | 标准协议字段 |
JWT sub、aud、iss、jti | 标准 Claim |
ZAP session_id、agent_key | ZAP 协议自身标识 |
request_id、event_id、trace_id、idempotency_key | 请求、事件和幂等语义 |
wukong_message_id | 已命名 provider 标识 |
runtime_identity.tenant_id/user_id/agent_instance_id | 接入方 Runtime 本地身份 |
接入方内部数据库的 *_uuid 列名 | 内部存储,不是 API 线缆 |
当前应用 ID Token 的 tenant.uuid、zhiban_context.peer.uuid | F04 应用 SSO 当前契约 |
不要执行全仓 uuid -> id 文本替换。应只修改 API DTO、序列化字段、SDK 公共属性、调用代码、fixture 和协议测试。
九、推荐迁移顺序
- 锁定版本:拿到包含本指南改动的 Agent Bus 环境和 SDK commit/tag。
- 盘点调用点:搜索旧 JSON 字段、SDK 属性、函数关键字参数和测试 fixture。
- 升级 SDK:先升级依赖,再处理编译错误、类型错误和测试失败。
- 修改原生 HTTP DTO:请求只发送新字段,响应只读取新字段。
- 修改 ZAP/A2A handler:更新上下文属性、invoke 入参、edge 回执和日志字段。
- 修改测试数据:fixture、mock response、快照、示例 curl 和 API schema 全部同步。
- 增加负向测试:至少验证一个旧字段会被服务端或 SDK router 以 HTTP
400拒绝。 - 联合部署:在约定窗口同步上线调用方和服务端,完成真实环境 smoke test。
十、交给 Codex / Claude Code 的执行指令
可把下面内容连同本文一起交给代码助手:
text
请按照《2026-07-15 已接入方迁移指南》迁移当前项目。
要求:
1. 先只读扫描当前项目,列出使用知办AI External API、ZAP、A2A、Python/Go SDK 的文件和调用点。
2. 识别每个 ID 的归属:知办AI资源使用 id/<resource>_id;对方系统资源使用 third_<resource>_id;标准协议字段保持不变。
3. 升级到平台方提供的、包含本次迁移的 SDK commit/tag;不要只根据旧版本字符串判断已经升级。
4. 删除旧字段和旧 SDK 属性的读取/写入,不添加兼容 alias、双读、双写或 fallback。
5. 同步修改请求 DTO、响应 DTO、业务代码、fixture、mock、快照、日志字段、示例和测试。
6. 如果项目是 ZAP Runtime,使用新版 SDK router,确认 GET /zap/v1/healthz 可用并带 bearer 鉴权;handler 改用 tenant_id/user_id/agent_id/conversation_id/a2a_edge_id。
7. 如果项目使用 A2A,改用 to_agent_id/edge_id/parent_edge_id/room_id,并原样保存 edge_created_at。
8. 如果项目使用应用单点登录,Token 请求改为 application/x-www-form-urlencoded;后端验签 ID Token 后读取 tenant/membership/zhiban_context,不新增 userinfo 或 decode-token 接口。
9. 运行项目现有 lint、类型检查和测试;新增新字段成功与旧字段被拒绝的覆盖。
10. 最后输出:修改文件、字段替换表、验证命令与结果、仍需平台方提供的配置或版本信息。
禁止:
- 全仓机械替换 uuid;
- 修改内部数据库列名;
- 保留旧字段兼容层;
- 在日志或浏览器输出 client_secret、bearer、ID Token、Access Token、Refresh Token;
- 绕过 Agent Bus 直接调用其他 Agent Runtime。十一、检索与验收清单
11.1 建议检索
在业务源码、测试和示例目录执行,排除依赖、构建产物和数据库 migration:
bash
rg -n 'tenant_uuid|account_uuid|user_uuid|agent_uuid|digital_employee_uuid|conversation_uuid|room_uuid|edge_uuid|parent_edge_uuid|kb_uuid|document_uuid|file_uuid|external_id|external_code|employee_id' \
src app tests examples搜索结果必须逐条分类:协议旧字段需要修改;内部数据库列名、历史 migration 或本文第八节列出的例外可以保留。
11.2 HTTP 验收
- 新字段请求成功;
- 任一已删除字段返回 HTTP
400; - 响应不再包含旧字段;
- 使用其他租户的资源 ID 仍按原有规则返回模糊的无权限 / 不存在错误;
- API Key、Session Token 和 Scope 行为没有变化。
11.3 SDK 验收
- Python 不再访问旧属性或传旧关键字参数;
- Go 不再引用旧结构体字段和旧方法名;
- Python / Go SDK 测试通过;
- 原生 HTTP mock 与 SDK 模型字段一致。
11.4 ZAP / A2A 验收
- 正确 bearer 请求
GET /zap/v1/healthz返回200,错误 bearer 返回401; - ZAP session 请求只使用新字段;
- 旧 ZAP 字段被严格拒绝;
- discover、invoke、get edge、cancel、stream 使用同一个
edge_id; edge_created_at原样传递;- A2A 仍由 Agent Bus 治理和转发,不直连被调 Runtime。
11.5 应用单点登录验收
- 授权码只能使用一次;
- Token Endpoint 接受标准 form 请求并返回顶层 token 字段;
- 后端完成 ID Token 验签后才能读取用户、租户和成员信息;
- Discovery / JWKS 有 TTL 缓存,未知
kid会刷新一次; - 浏览器端看不到任何服务端凭证或 Token。
十二、不受影响的内容
- API 路径版本仍是
/api/external/v1; - API Key、Session Token、OAuth2 换码和权限 Scope 不变;
- tenant、用户、数字员工、知识库的授权和可见性判断不变;
- 资源 ID 的实际值不因字段名变化而变化;
- 数据库历史列名、repository / domain 内部精确类型名不做机械改名;
- 应用 SSO 不要求租户配置企业 OIDC;
- 不新增 UserInfo、decode-id-token、PKCE 或 A2A 直连能力。