identity.md 21 KB

员工与数字人身份登记

每个新员工、每个新数字人先登记自己的档案,再创建工作坊会话。目录支持任意人数,不按姓名或特定机器人的角色分配固定槽。登记资料与平台认证分开:本流程不创建登录账号,accountAuthenticated 始终为 false。

本人提供的看板称呼

首次工作坊调用只进行必要的称呼与账号绑定确认;已绑定后不在入库、上传或阶段接续时重复追问。发送者登记、显示称呼、通讯录实名是三个独立事实,不把通讯录查询作为使用自报称呼的前置条件。

employee-name 只接受当前可信消息登记的员工profileKey和其已有会话;服务端校验服务owner、工作坊参与键派生关系及Agent。读取只用data:read;保存称呼或明确跳过使用既有ingest:write,无需identity:write或运维凭据。私有运行配置 workshopDisplayNames 按bot作用域+发送者摘要存储,跨工作坊复用,同名不合并。更新只涉及称呼注册表及操作审计,不改员工/Agent档案、会话索引、报告、项目或旧归属快照。

provided直接复用,skipped继续业务不再追问;promptState=not_asked只表示尚无记录,不授权Skill额外提问。用户主动改名时可更新。自报姓名与昵称均标source=self_reported、nameVerified=false,不写入employee.name,也不冒称企微显示名或实名。看板在employee.displayName展示称呼,标“本人提供的称呼 · 未经通讯录核验”;已有可信通讯录姓名优先。历史本地占位名可保持原样,不代表保存昵称失败。

网站账号与称呼

首次使用工作坊且没有已核验绑定时,先询问称呼和已开通的工作坊账号。已有信息只请本人确认;不询问密码、验证码、Token或无关个人资料。不从中文姓名猜拼音,不代建平台账号。账号不存在、企业不符或已有绑定冲突时,说明具体问题并请学员核对,不新建替代成员。独立研究可继续,成果暂不提交到看板。

学员自报账号只用于查找;受控名册只能证明账号存在,不能证明说话者就是本人。优先用当前消息宿主提供并经服务端验证的登录绑定;没有适用可信桥接时,使用服务合同声明的 ksfWorkshopAccount 首次确认链路:

  1. 复用当前员工的本地 profileKey;尚无档案时按已提供账号登记待核对档案,不创建业务会话或空报告。
  2. 先执行 account-status。已绑定则复用返回的 memberKey并告知学员正在沿用哪个账号,当前自报账号冲突时停止受影响写入;未绑定才执行 account-prepare,传本人提供的账号和称呼。prepare在服务端查已核验的注册名册,status查询持久绑定,后续本人登录再核实时平台账号;不要把模型记忆或客户端姓名匹配当作数据库查询。
  3. prepare返回awaiting_account_confirmation时,明确告知已找到该账号、尚待本人确认,再发送服务返回的confirmationUrl;不要提前说已绑定。学员在该页面登录本人平台账号并明确确认;页面直接与平台校验,密码与Token不进聊天或报告。仅回复“已绑定”不算成功。prepare若直接返回bound,按已绑定分支核对后复用,无需另开确认链接。
  4. 再执行 account-status,必须读到 status=bound、正确账号/企业和同一 memberKey,才告知学员当前对话已绑定该账号、称呼用于显示、后续相关成果将归该账号。随后用原 profileKey 执行 workshop-start;核其 accountBinding.status=bound、memberKey 与上述一致。当前学员的私有接续状态同时记录已核验账号、profileKey、memberKey与sessionId;不把别人的对话绑定沿用到当前发送者。
  5. 报告、机会卡、方案、项目及相关课堂提交沿用该账号对应的会话和memberKey,不以称呼或每次提交另建成员。每次保存后精确回读报告和公开看板,核会话、报告都映射至同一memberKey。提交仍使用现有受控服务授权,成果作者归属为已绑定学员,不能把服务账号当作学员。首次账号确认本身不产出报告。

查找与绑定结果必须反馈给学员:ACCOUNT_NOT_REGISTERED明确说明未在工作坊已开通账号中找到该账号,请核对输入或联系管理员,不自动注册或创建替代成员;COMPANY_FORBIDDEN或ACCOUNT_BINDING_CONFLICT说明企业或绑定不一致,不擅自改绑。接口不可用、超时或请求结果未知只能说明查询尚未完成,不能说账号不存在。学员纠正账号后重新核对;遇到已有绑定冲突不能通过新档案或换键绕过。

workshop.accountBinding是公开能力契约,workshop-start回执顶层accountBinding是安全绑定摘要,读取结果应保留二者;记录meta.attribution.accountBinding则是私有归属快照,仍须脱敏。若原始接口与受控命令的契约字段不同,先核调用链的本地转换,不据此认定服务未部署或重载平台。

工具命令沿既有受控凭据入口(仅在服务合同已声明支持时使用):

node <Skill根目录>/scripts/ksf-secure.mjs account-prepare --input <私有绝对路径JSON> --request-id <本次请求ID> --agent-profile <自身完整Agent档案键>

prepare JSON为 {"participant":{"profileKey":"当前员工完整档案键"},"username":"本人确认的账号","displayName":"本人提供的称呼"};status改用 account-status,JSON只保留participant。不要替学员调用confirm;服务身份不能冒充本人登录。链接过期可为同一profileKey重新prepare,不换员工键。

fmode平台公开App ID为 ncloudmaster,企业ID为 FKieRbIoGt,康师傅业务App ID为 FKieRbIoGt_main。平台稳定用户ID不能填进业务 participant.userId。已取得真实平台ID时放 account.accountId;未取得时不把用户名冒称用户ID。既有旧档案可由服务端已核验别名继续引用,不改旧档案/参与者键以“消除重复”。本地模块的accountAuthenticated=false仍表示它不执行平台认证;认证事实以服务端绑定回执为准。

同一平台用户ID+企业只对应一个 platform-account:<摘要> 注册成员。课题、会话、Agent、昵称变化可以增加会话或账号别名,不增加看板成员。多会话/旧参与者通过服务端显式memberKey关联;不按姓名或模型自报账号合并。已有报告保留原ID、正文、版本、来源及原始提交快照,仅补账号关联。公开页面不暴露平台ID、私有绑定凭据或会话原始标识。

没有适用的身份接口或可信宿主上下文时,报告“账号绑定待完成”,不能把聊天记忆、本地档案、网页登录成功或成员名册当作服务端绑定完成;不得伪造企微bot/sender来使用employee-name。既有企微发送者的登记仍按后续章节执行;若需与网站账号统一,必须取得受控账号关联,不能只凭同名合并。

取得真实身份字段

数字人优先读取当前执行实例的可信运行配置,渠道从当前消息上下文补充。先核实本环境实际提供的配置位置或接口,只提取下面的白名单,不扫描全盘凭据或输出配置原文。不能把聊天里提到的另一位机器人登记为自己,也不能声称已调用不存在的自动身份接口。

Agent 字段:name、role、runtimePlatform、channel、identityBasis;account 内仅 platform、tenantId、accountId、accountName、runtimeAgentId、wecomAppAgentId;可附 collectedAt(UTC ISO 时间)。role 描述用途,课堂执行者用 workshop,运维用 operations,其他数字人可登记其他角色;只有 workshop 可用课堂写命令,角色不是授权凭据。名称取当前实例真实配置,不使用模板名或其他数字人的名称。

员工字段:name、identityBasis、account;account 内为 platform、tenantId、accountId、accountName、employeeNumber;aibot 通道额外使用 identifierType、scopeId。可选 userId 只代表本应用已存在的 _User.objectId。通讯录成员 userId 填 account.accountId,corpId 填 tenantId,工号填 employeeNumber。aibot 的 from.userid 另按下节标注类型和作用域,不假定它等于通讯录成员 UserID。群聊会话键不能代替发送者 ID,运行时 Agent ID 与企微应用 agentId 也不能混用。

未知账号字段填 null。密码、令牌、私钥、cookie 不属于身份资料。将身份摘要保存到 /opt/data 下的私有文件(0600),不包含配置中的其他字段。

先登记数字人

人工确认的最小摘要如下,替换成当前数字人的实际名称;取得真实字段时才补入。

{
  "name":"当前数字人的实际名称",
  "role":"workshop",
  "identityBasis":"operator_registration",
  "runtimePlatform":"hermes",
  "channel":"wecom",
  "account":{"platform":"wecom","tenantId":null,"accountId":null,"accountName":null,"runtimeAgentId":null,"wecomAppAgentId":null}
}
node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-identity.mjs status
node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-identity.mjs register --input /绝对路径/自身摘要.json
node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-identity.mjs check --agent-profile <返回的完整档案键> --input /绝对路径/自身摘要.json

runtime_config / channel_context 必须有可信稳定账号 ID;不得只凭名字使用这两种来源。无稳定 ID 时用 operator_registration,生成 agent-registration:UUID;有真实稳定 ID 时生成 agent-account:摘要。check 不因新 collectedAt 改变身份键,也不改旧档案。

同名同角色但无稳定 ID 时返回 needsReview=true 和 candidates,尚未登记成功。确认是原实例后,在摘要中明确填 reuseKey;确认是另一实例则填 confirmNew:true。两者不可并用。不静默覆盖、不删除旧档案。已有明确档案键时直接 check,不通过就停。

档案存于 /opt/data/ksf-workshop-state/agents/<键后缀>.json。原双槽版或更早的 agent-self.json 可用 adopt-agent --input /旧档案绝对路径 迁入通用目录;仅复制经验证的同一身份,原文件保留。旧 --slot 和 --agent-profile workshop 不再使用。

再登记员工

已取得企微 aibot 发送者时自动登记

此模式只在当前接入层实际提供可信aibot消息上下文时使用。发送者、机器人作用域和会话键分别核对;账号前缀不能证明账号类型、跨机器人同一性或当前通道已经接通。

自动登记必须通过无参数的进程内工具 ksf_register_current_employee。工具直接调用当前回合的 identity_bridge.current_identity(),核对维护人配置的 Agent 档案键与 botId 指纹,然后通过私有管道调用 Skill 的档案代码。只返回员工摘要、profile.key、agentProfileKey、invocationId 与是否新增;不把 botId/senderId 放进报告正文。

工具是否安装、是否能取得本条消息,均以当前环境的真实返回为准;历史登记成功不能代替本次身份核对。工具缺失或 ok=false 时停止,不换用人工登记绕过本次自动识别验收。wecom_identity_current 是身份诊断查询,不直接登记;把它的六字段由模型复制到文件不构成可信登记。

旧 register-channel-employee --context 及该命令的所有参数形式均返回 TRUSTED_IDENTITY_TOOL_REQUIRED。通用 register-employee 也拒绝 channel_context/aibot 账号输入,不能改走它复述通道身份。内部 ksf-identity-bridge.mjs 只由网关登记 handler 调用,不是模型可用的身份导入命令;stdin 本身不是身份认证,任意同 UID 代码执行不在本流程隔离保证内。

Agent 自身 account.accountId 必须是当前实例实际订阅 botId,channel/account.platform 均为 wecom,role=workshop。维护人需在受控配置中将真实 bot 账号对应到 Agent 名称和档案键,不能从包名、聊天自述或模板推导自身身份。

工具每次从本条消息取 senderId,群聊不能使用群 ID 当员工;单聊原始 chatId 可为 null,有效会话键校验可以使用 chatId 或 senderId,但不得反过来从会话键猜员工。没有姓名时显示待绑定标签。

自动登记 account 保存 platform=wecom、identifierType=wecom_aibot_sender、scopeId=真实botid、accountId=from.userid;tenantId、accountName、employeeNumber 未知则 null,userId=null。作用域是机器人实例,不冒称企业 corpId。稳定键只由机器人作用域和发送者构成,不包含聊天ID、消息ID、名字;同一发送者跨单聊/群聊复用,不同群成员分别登记,跨机器人先保留独立别名,不自动合并。

无姓名时本地登记生成“员工待绑定·摘要”标签并返回 needsNameBinding=true;这只表示本地档案没有姓名,不是企微实名查询的结论。无需员工回答账号问题即可建立发送者归属。上传服务可按下节取得通讯录姓名,不能凭 _User、报告 ownerName、历史 Agent 展示名或姓名相同来猜测身份。

该模式的 workshop-start 还须读到服务合同 channelIdentitySchema=ksf.wecom-aibot-sender.v1;缺少则写入前停。私人账号与作用域仅进私有快照;公开看板显示已核验姓名,未取得姓名时显示可识别的通道资料或待同步标签,不暴露原始 ID。本地自动登记成功不代表通讯录实名链路已上线,需新的真实消息验收。

上传时查询企业微信通讯录实名

本节为可选通讯录能力:只在维护人已启用通讯录配置时由上传服务查询;未配置则正常保存,返回pending,不阻塞前述自报称呼流程。不要为使用昵称主动运行employee-read或索要通讯录配置。

Skill 负责顺序与结果核对:当前消息可信登记 → 核对员工/Agent 与 session 绑定 → start 或 save → 核对员工回执 → 成果回读。不要另造“让员工先登录网页/手填企微账号”的前置步骤。续传前仍调用当前消息登记工具;本地状态须同时绑定员工键和 Agent 键,不能因为同处一个群或沿用上一次 session 就跳过发送者核对。

查询由 ksfStartWorkshopSession / ksfSaveWorkshopTask 服务端扩展执行。start 使用可信登记注入的账号,save 使用原 session 的私有归属快照。aibot 发送者须通过受控映射对应到通讯录 UserID,不能根据 wo/wr 前缀认定是通讯录账号。配置包含企微应用通讯录权限、企业范围和发送者映射,由维护人在私有运行配置中管理;Skill 不读取、不保存这些密钥,也不调用外部通讯录接口拼装姓名。

成功命令的业务结果增加以下字段;通过 ksf-secure 执行时查看 entryResult.result,直接调用运行库时查看返回对象:

{
  "employee": {
    "key": "employee:<服务返回的稳定摘要>",
    "name": "通讯录返回姓名",
    "departmentNames": ["通讯录返回部门"],
    "position": null,
    "source": "wecom_directory",
    "nameVerified": true,
    "verifiedAt": "服务返回的核验时间"
  },
  "employeeIdentity": {"automatic": true, "status": "verified"}
}

上述为字段示意,不可原样作为员工资料上传。实名通过条件为 status=verified、employee.nameVerified=true、employee.source=wecom_directory、姓名非空;记录实际稳定键、姓名和核验时间即可。通讯录姓名核验不代表员工本人正式确认报告,也不代表企业审批。

实际返回 处理
业务成功且实名通过 说明成果已保存、通讯录实名已取得,按返回编号回读成果
业务成功,status=pending,reason=WECOM_DIRECTORY_NOT_CONFIGURED 说明成果已保存、发送者归属已建立,实名待维护人配置;不重跑保存
业务成功,但没有 employee/employeeIdentity 或字段不一致 保留成功回执,说明实名能力尚未核实;交维护人检查版本,不推断已实名、不重存
查询权限不足、映射缺失或身份冲突报错 报告实际错误并停止;新版服务在业务保存前查询,但身份同步审计可能已写入,不声称零写入
网络失败或结果未知 保留原 requestId 与输入,先查回状态;不自动重试、不换键

本地工具的 needsNameBinding 与上传回执属于两层结果:本地标签可仍为“员工待绑定”,看板按服务端实名档案展示。不要直接修改本地档案、覆盖旧报告正文或再开 session 来使两者字符串相同。同一员工跨工作坊由稳定身份关联,原成果 ID 和版本保持不变;不同机器人作用域只在服务端有已核验映射时才可归到同一员工。

通讯录查询成功、称呼保存和看板显示分别核对;不能用夹具姓名或历史回执替代当前员工的真实结果。缺接口或配置时说明具体缺项,不读取或复制维护人的私有运行配置。

只读取当前员工姓名用 employee-read:登记本条可信发送者后传入已有sessionId和participant.profileKey,Agent键沿用 --agent-profile。入口及服务端均核对员工与Agent归属,然后由 ksfReadWecomEmployee 以 data:read 权限查询通讯录。结果位于 entryResult.result.employee,readOnly=true、databaseWrites=0、employeeIdentity.persisted=false;成功仅说明本次姓名读取成功,不表示看板已同步。此路径不调用运维用的 ksfSyncWecomEmployee,也不需要其identity:write权限。

本地员工档案键与工作坊参与键原本就是不同层级。服务端 participantKey = "participant:" + SHA256(canonical([workshopKey, employeeProfileKey])),摘要为UTF-8输入的十六进制SHA256;不能将工作坊键当作旧算法并改写员工档案。缺本地会话索引时,先只读核对服务端记录、上述派生关系和Agent,再恢复私有索引;不据本地目录缺失推断服务端无会话。

无可信发送者时人工登记

仅在任务已明确要求人工登记并提供相应身份依据时使用。已有资料直接复用,缺少可信依据则标待核对,不另设询问显示名或账号的开场,也不以人工登记绕过既有可信身份冲突。

{
  "name":"实际员工显示名",
  "identityBasis":"participant_registration",
  "account":{"platform":"wecom","tenantId":null,"accountId":null,"accountName":null,"employeeNumber":null}
}
node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-identity.mjs register-employee --input /绝对路径/员工摘要.json
node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-identity.mjs lookup-employee --name 实际员工显示名
node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-identity.mjs check-employee --participant-profile <员工完整档案键> --input /绝对路径/员工摘要.json

channel_context 必须有稳定发送者账号(企微账号需 tenantId+accountId)或其他可校验稳定 ID;existing_record 必须有已有账号依据。无稳定 ID 时 participant_registration 生成 participant-registration:UUID,并在后续消息复用该键。稳定账号生成 participant-account:摘要;同账号同资料返回原键,不新增。

同名员工即使摘要内容相同也不能自动合并。needsReview=true 时先确认候选是同一人:明确复用才在摘要填 reuseKey;确认不同人填 confirmNew:true 新建。身份字段冲突则停,不通过换键绕过。姓名检索只用于找候选,不能证明身份。

员工档案位于 /opt/data/ksf-workshop-state/participants/<键后缀>.json。跨容器无法自动发现对方的本地 UUID;需受控核对和迁移同一档案后复用,不能按姓名推算同一 UUID。登记只写本地档案,数据库归属快照在 workshop-start 成功时才落库。

档案绑定到会话

workshop-start 输入使用 participant:{"profileKey":"员工完整档案键"};Agent 用命令行 --agent-profile <Agent完整档案键>。入口加载两份档案并自动注入名称、键、身份来源和账号快照。缺档案、姓名冲突、角色不符均在创建会话前停止。写入前还检查服务合同 identitySchema 是否为 ksf.agent-self.v1;没有则等待两函数升级。

本地状态记录真实上下文与这两个档案键的绑定,以及 workshopKey/sessionId/projectId/任务键版本,不保存凭据。换发送者或执行数字人需重新解析对应档案;多人群聊不能只用群会话键缓存一个员工。跨 Agent 延续项目需为当前执行者新建 session,再使用同一员工/小组的项目,不冒用另一位 Agent 的 session。

人工登记身份与业务 dataMode 无关。构造待查清单从 start 就用 sample;save 继承 session。账号信息只进私有归属快照,不放报告正文。CLI 和公开看板均不返回完整账号;远端落库核验由受控管理端完成。本地登记成功不能表述为企微认证或远端员工账号开通。