DeepSeek Harness 共享匿名用户 ID:Telemetry、Feedback 与 DeepSeek 请求的统一身份关联设计
人工智能AI AgentAgent 框架DeepSeek【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址https://gitcode.com/gh_mirrors/de/deepseek-harness点击查看免费下载本篇技术指南深入解析 DeepSeek HarnessEverything is a Plugin中的跨模块共享匿名用户 ID 机制deepseek-ai/dsh-anonymous-user-id包如何为同一 harness home 生成并持久化唯一匿名 UUID并被会话遥测导出、/feedback反馈确认、直连 DeepSeek 请求三个消费者共同使用使运维人员能够在不识别用户身份的前提下跨记录关联同一安装实例。读完本文你将掌握该身份存储契约$DSH_HOME/.anonymous-user-id的完整语义、三个消费者的接入方式、源码级并发与容错实现以及它在架构层面的边界与取舍。该设计源于仓库中的架构 Agent Note 2026-08-07-shared-feedback-telemetry-user-id.mdStatus: implemented并在 anonymous-user-id 包 中落地为正式实现。背景与问题为什么需要一个共享的匿名用户 ID三个消费者一份身份在引入共享 ID 之前OpenTelemetry 后端session-telemetry-otel已经会在$DSH_HOME/.anonymous-user-id中持久化一个匿名 UUID作为遥测导出的身份标识。随后出现的两个新需求打破了ID 仅存在于遥测后端内部的格局/feedback反馈命令需要同时报告接收反馈的 session id 和 user id运维人员才能把反馈确认信息与已导出的遥测记录关联起来直连 DeepSeek 请求需要在每个 provider 请求上携带身份以便按安装实例归因使用量。问题随之而来如果重复生成或独立生成一份身份反馈确认中的 user id 将与遥测记录无法关联失去报告意义而如果从session-telemetry-otel导入该工具函数则会让一个普通命令依赖可选导出的后端并且在遥测模块反过来挂载 feedback 导出时形成依赖环。关键决策抽取出独立的共享库deepseek-ai/dsh-anonymous-user-id作为匿名身份的唯一所有者。它既不属于遥测后端也不属于 feedback 或 LLM 适配器而是三者共同依赖的底层能力。决策与架构deepseek-ai/dsh-anonymous-user-id包包的职责划分deepseek-ai/dsh-anonymous-user-id拥有两项核心资产APIgetOrCreateAnonymousUserId()——返回 harness home 的匿名用户 ID首次调用时创建并持久化存储契约$DSH_HOME/.anonymous-user-id文件默认解析到~/.dsh。三个消费者各自以不同方式使用这份身份消费者使用位置承载方式会话遥测导出session-telemetry-otelsession-telemetry-otel/src/index.tsOTel Resource 属性user.id反馈确认command-feedbackcommand-feedback/src/index.ts成功确认信息的第二行Anonymous user: {userId}直连 DeepSeek 请求llm-deepseekllm-deepseek/src/adapter.tsHTTP 请求头x-deepseek-harness-user-id这一划分同时解决了依赖方向问题feedback 包只依赖身份能力本身而非遥测 seam 或 OTel SDK遥测导出 feedback 时也不会形成反向依赖环。被否决的替代方案架构 Note 明确记录了三个被评估后否决的方案及其理由被否决的方案理由从session-telemetry-otel导入工具函数将 feedback 耦合到可选的导出后端且一旦 telemetry 导出 feedback 就会形成反向依赖环在 feedback 中重复实现持久化辅助函数同一文件契约的两份实现可能漂移且并发、校验、失败语义各不相同为 feedback 单独生成一份 user id确认信息无法与 OTel Resource 关联无法满足报告目的存储契约$DSH_HOME/.anonymous-user-id的完整语义文件格式与位置解析ID 是一个随机 UUID v4以裸单行形式存储在 harness home 的.anonymous-user-id文件中无任何包装格式。位置解析遵循$DSH_HOME~/.dsh的优先级由deepseek-ai/dsh-home-paths的resolveDshHome提供见 home-paths 包。// packages/identity/anonymous-user-id/src/index.ts export const ANONYMOUS_USER_ID_FILE_NAME .anonymous-user-id const UUID_PATTERN /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i读取时对文件内容执行trim()后校验 UUID 格式不存在或不可读、格式损坏均视为无有效 ID由调用方铸造新 ID。身份的作用域与匿名性保证按 harness home 作用域而非按机器共享同一$DSH_HOME的所有进程报告相同 ID不同 home 之间 ID 永不相同、无法关联绝不从可识别来源派生ID 来自crypto.randomUUID()不从主机名、网络地址、git remote 或任何其他可识别信息推导——匿名性是铸造环节本身的属性参见包 README 的 Design philosophy删除即重生删除.anonymous-user-id文件后下次启动会铸造全新身份运行中的进程因内存 memo 保留当前 ID 直至退出。三个消费者接入方式与源码证据消费者一会话遥测导出的user.idResource 属性在 session-telemetry-otel/src/index.ts 中构建 OTelLoggerProvider时ID 被挂载到 Resource 属性上this.provider new LoggerProvider({ resource: resourceFromAttributes({ service.name: APP_IDENTITY.product, service.version: APP_IDENTITY.version, // OTel semconv 的标准用户属性随每次导出批次挂在 Resource 上而非每条记录 // collector 按 Resource 聚合且该 ID 在进程内本就稳定。 user.id: getOrCreateAnonymousUserId(), }), processors: [ /* BatchLogRecordProcessor OTLP/HTTP 日志导出器 */ ], })设计要点user.id挂在 Resource 上而非逐条记录上因为收集端按 Resource 聚合且 ID 进程内稳定。telemetry 的后端配置mode、exporter.url、processor、shutdownTimeoutMillis可参考 config-catalog.md 中的对应条目。消费者二/feedback确认信息中的匿名用户行在 command-feedback/src/index.ts 中/feedback命令的成功确认信息格式为text: Feedback recorded for session ${invocation.agent.session.id}\nAnonymous user: ${getOrCreateAnonymousUserId()}. ${sharingDisclosure(telemetry)}即第一行报告接收反馈的 session id第二行报告匿名用户 ID随后附上会话共享策略披露Session sharing is enabled./feedback-gated/disabled/not configured。需要注意的调用顺序保证无效反馈在解析 ID 之前即被拒绝。executeFeedbackCommand先检查rawInput是否为空并返回 usage error随后recordFeedback内部对 trim 后空文本抛出TypeErrorsrc/index.ts只有通过校验才会走到getOrCreateAnonymousUserId()。因此空命令不会产生.anonymous-user-id文件的副作用。此外反馈事件feedback/record是纯日志事件不进入模型上下文telemetry 处于FEEDBACK_ONLY模式时仅当反馈事件是会话日志中的 canonical 记录时才会触发会话捕获见 session-telemetry-otel/src/index.ts。消费者三直连 DeepSeek 请求的x-deepseek-harness-user-id请求头在 llm-deepseek/src/adapter.ts 中每个 provider 请求的头集合包含const headers { authorization: Bearer ${apiKey}, content-type: application/json, accept: text/event-stream, ...attributionHeaders(), x-deepseek-harness-user-id: String(userId), ...options.sessionId ! undefined ? { x-deepseek-harness-session-id: String(options.sessionId) } : {}, ...options.purpose compaction ? { x-deepseek-harness-compact: 1 } : {}, }同一请求还会视情况携带x-deepseek-harness-session-id与x-deepseek-harness-compact完整线协议说明见 deepseek-llm-api-wire-extensions.md。关键延迟解析设计在 llm-deepseek/src/index.ts 中ID 通过惰性求值注入适配器let userId: AnonymousUserId | undefined const resolveUserId (): AnonymousUserId userId ?? getOrCreateAnonymousUserId()resolveUserId仅在凭据解析成功之后、实际发送请求时才被调用。这意味着凭据失败MISSING_CREDENTIAL见 src/index.ts或任何未真正发起请求的路径都不会创建.anonymous-user-id文件——身份文件只在真正产生对外记录时产生。这也印证了架构 Note 中neither an empty command nor a credential failure creates.anonymous-user-id的承诺。实现细节并发、容错与进程内 memogetOrCreateAnonymousUserId()的实现src/index.ts体现了以下语义同步读写 按路径 memoize读和写均为同步操作启动期与命令期消费者可用同一 API结果按解析后的文件路径缓存于Mapstring, AnonymousUserId因此一个进程只触碰磁盘一次且运行中删除文件不会影响当前进程独占创建解决并发首启首个写入者使用flag: wxexclusive create写入并发竞争中的失败者会重读并采纳胜者的 IDEEXIST 分支同时覆盖了并发胜者与已存在损坏文件两种情况损坏则落入覆盖重写路径损坏替换读取时 UUID 校验失败即视为损坏走铸造新 ID 覆盖写入路径best-effort 持久化home 目录只读或不可写时写入失败仍返回一个可用的内存 ID保证当前运行的 feedback 与 telemetry 记录不中断write failure 不会阻塞身份报告。测试对契约的完整印证anonymous-user-id.spec.ts 用 9 组用例覆盖了全部核心契约首次使用创建并持久化裸 UUID 行、缺失时创建 home 目录、容忍周围空白的持久化 ID 复用、损坏文件覆盖重写、并发胜者采纳exclusive create 输给初始读取之后写入的 ID、home 不可写时返回可用 ID、按 home 的进程生命周期 memo单次读取、删除免疫、不同 home 保持不同 ID、默认读取process.env。为何 invariant 伴生是空安装器包还提供anonymous-user-id-invariant伴生插件src/invariant.ts。其安装器为空/** 无运行时 invariantAPI 只拥有一个私有 memo 和一份 best-effort 文件没有独立事件流或公开可变关系可供伴生比较——除非把创建身份作为副作用。 */ const install: InvariantInstaller () {}从源码结构看这正是架构 Note 中empty invariant companion explains why reading the private file is not a useful runtime relationship check的落点唯一的关系是私有文件与进程内 memo任何检查都会以创建身份为副作用因此该包不注册任何运行时关系检查仅通过ctx.invariants.register(PACKAGE_NAME, install)保留包所有权登记。对应测试见 tests/invariant.spec.ts。架构后果与边界设计带来的收益一个 harness home一份匿名身份feedback 确认、会话遥测导出、直连 DeepSeek 请求三者携带同一 ID运维方可将同一安装实例的三类记录完整关联解耦与无环feedback 包仅依赖身份能力不依赖遥测 seam 或 OTel SDK身份包的三个消费者使其实至名归地成为共享库模块依赖关系可参见 module-graph.md文档职责清晰原始 anonymous-user-id 架构 Note 继续对存储与隐私语义保持权威而本文所述 Note 只取代其OTel 本地所有权的决策部分。已知边界与注意事项删除文件无恢复路径丢失文件即铸造新身份这是刻意设计——恢复需要稳定的派生材料会削弱匿名性并发窗口的短暂不一致一个读取者若落在并发进程独占创建 → 完成写入的狭窄间隔内本次运行可能使用不同的内存 UUID后续启动会收敛到持久化值无跨 home 关联不同$DSH_HOME无法关联这既是隐私承诺也是能力边界自定义 DeepSeek 网关同样收到该 IDllm-deepseek会向其解析出的baseURL含部署覆盖发送稳定的x-deepseek-harness-user-id头与 telemetry 共享模式无关——使用自定义网关时需知晓该头会被发送删除文件不重置当前进程memo 使当前运行保留原 ID直到下次启动。如何在自有包中复用这份身份若你要构建一个需要共享安装实例匿名身份的新功能按 包 README 的用法 导入一次并复用即可与内置功能对齐import { getOrCreateAnonymousUserId } from deepseek-ai/dsh-anonymous-user-id const userId getOrCreateAnonymousUserId() // 进程生命周期内稳定无需安装或配置ID 在相关功能首次运行时自动出现跨重启保持稳定删除文件即铸造新 ID。该值进程内稳定与内置 telemetry、feedback、DeepSeek 功能使用的值一致即使 home 目录不可写当前运行仍可得到可用 ID保证记录持续流动。不要用它识别用户身份也不要期望它跨不同 home 关联记录——它是匿名且按 home 作用域的。进一步探索anonymous-user-id 包 README —— 包级契约、源码地图与维护者 Dev Note含文件格式演进的开放问题anonymous-user-id 实现 ——getOrCreateAnonymousUserId完整实现home-paths 包 ——$DSH_HOME与~/.dsh解析的归属方session-telemetry-otel 包 ——user.idResource 属性的报告方command-feedback 包 —— 反馈确认中的匿名用户行llm-deepseek 包 ——x-deepseek-harness-user-id请求头的发送方session-telemetry 子系统文档 —— telemetry seam 与后端契约deepseek-llm-api-wire-extensions.md —— 完整线协议扩展说明赞分享人工智能AI AgentAgent 框架DeepSeek【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址https://gitcode.com/gh_mirrors/de/deepseek-harness点击查看免费下载相关推荐DeepSeek Harness 会话共享策略披露/feedback 确认消息的透明化设计DeepSeek Harness 会话共享策略披露 /feedback 确认消息的透明化设计 /feedback 是 DeepSeek Harness 中记录人工智能AI AgentAgent 框架DeepSeekDeepSeek Harness 匿名用户标识设计解析$DSH_HOME/.anonymous-user-id 与 OTel Resource user.idDeepSeek Harness 匿名用户标识设计解析 $DSH_HOME/.anonymous user id 与 OTel Resource user.i人工智能AI AgentAgent 框架DeepSeekDeepSeek Harness Web Composer 共享宽度轴用单一 CSS 变量统一整列宽度体系DeepSeek Harness Web Composer 共享宽度轴用单一 CSS 变量统一整列宽度体系 导读 本文讲解 DeepSeek Harness人工智能AI AgentAgent 框架DeepSeek创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考