DeepSeek Harness `/feedback` 命令:零扰动会话反馈采集的设计、实现与源码验证
人工智能AI AgentAgent 框架DeepSeek【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址https://gitcode.com/gh_mirrors/de/deepseek-harness点击查看免费下载会话进行到一半用户发现不对劲却无处安放观察——这是 DeepSeek Harness 通过/feedback命令解决的核心问题。本文以仓库决策记录 2026-07-28-feedback-command.md 为骨架结合 packages/feedback/command-feedback 的源码与测试完整讲解这一「仅写日志、绝不扰动运行」的反馈采集通道命令如何注册、事件为何独立、模型为何永远看不到、持久化边界在哪里以及部署者如何确认反馈去向。读完本文你将掌握该命令的使用方式、架构决策背后的权衡以及如何基于仓库证据自行验证这些行为。问题会话中的观察无处安放用户在会话中途发现问题时传统上有几条路可走但每条都有代价告诉模型浪费一个轮次改变用户原本进行的对话还会把这条评论埋进派生历史后续读者无法定位它写到会话之外丢失让它有意义的上下文——它属于哪个会话、处于哪个时点、针对哪项工作什么都不做观察就此流失。因此采集接口必须满足两个硬约束即时可用必须能在用户产生不满的那一刻使用任何要求用户离开交互式客户端的方案都不可行零扰动不得干扰正在进行的运行——不消耗模型 token、不产生工作轮次、不改变用户正在等待的请求。这组约束直接推导出了最终方案一个全局斜杠命令 一个仅写日志的会话事件。决策概览一个全局命令与一个权威事件实现位于packages/feedback/command-feedback/包名为deepseek-ai/dsh-command-feedback见 package.json。其核心设计可以概括为三句话层面设计源码依据命令注册通过ctx.commands注册全局feedback命令仅注入commands无任何配置src/index.ts事件模型声明仅写日志的会话事件feedback/record { text }src/index.ts生产者导出recordFeedback(session, text)命令仅是它的薄封装src/index.ts/feedback text的行为/feedback text的成功确认文本包含三部分接收反馈的会话 id、harness home 的共享匿名用户 id、以及当前会话共享策略的一句披露。空输入或仅含空白的输入直接返回用法错误Feedback text is required. Usage: /feedback text处理函数是同步的src/index.ts只注入commands不声明对任何可选服务的依赖——这使得它在没有遥测后端挂载时依然能正常加载与运行。为什么反馈与遥测共享同一个匿名用户 id确认文本中的「匿名用户 id」来自deepseek-ai/dsh-anonymous-user-id提供的getOrCreateAnonymousUserId()它读写$DSH_HOME/.anonymous-user-id。这一共享 id 决策记录在 2026-08-07-shared-feedback-telemetry-user-id.mdOpenTelemetry 后端早已在该文件持久化一个匿名 UUID/feedback需要同时报告会话 id 和用户 id以便运维人员将确认文本与导出的遥测记录关联如果反馈包自行重复生成身份报告出的用户将无法与 OTel Resource 关联如果从session-telemetry-otel导入辅助函数则会让一个直接命令依赖可选的导出后端并在遥测导出反馈时形成反向依赖环。该包的源码实现session.append前先text.trim()、拒绝空串、恰好追加一个事件完整保留了随机 UUID、home 解析、进程内 memo、独占创建并发保护、损坏替换与尽力写入语义。为什么反馈拥有独立事件领域事实与触发方式分离原文档明确回答了一个关键设计问题反馈是领域事实/feedback只是其中一种触发方式。只把载荷保存在feedback/record中带来两个直接收益后续触发方式其他 UI、钩子、host 集成可以复用同一个事件无需重新发明消费方筛选反馈时不需要依赖命令名也无需解析command/run生命周期记录。因此包导出了命令无关的生产者recordFeedback(session, text)源码实现非常精简export function recordFeedback(session: Session, text: string): void { const normalized text.trim() if (normalized.length 0) throw new TypeError(feedback text must not be empty) session.append(feedback/record, { text: normalized }) }对应的测试command-feedback.spec.ts验证了独立生产者行为调用recordFeedback(session, recorded outside a command )后会话事件列表中恰好只有一条feedback/record文本被规范化而对 \n\t 调用则抛出feedback text must not be empty且不追加任何事件。recordInput: false避免双份权威副本dsh-commands仍会围绕/feedback写入command/run/command/done生命周期配对但该命令设置了recordInput: false。这意味着command/run携带命令身份与来源但不携带args反馈文本只存在于feedback/record中command/done携带确认结果success / error。这样做的原因是如果在command/run.args中也存一份文本同一条人类评价就会出现两个看起来都具有权威性的副本且没有任何实质区别。测试通过Object.hasOwn(commandRun.data, args) false锁定了这一点并断言整个会话事件 JSON 序列化后反馈文本只出现一次command-feedback.spec.ts。完整的事件序列由测试固化command-feedback.spec.tscommand/run → feedback/record → command/done为什么模型永远看不到反馈这是本设计最核心的边界。原文档给出了两层保障语义层面反馈是关于会话的而不是会话的输入。若通过agent.inject()将反馈作为 user 消息注入即/goal变更所走的路径会改变下一次模型请求让评论成为它所评论的那段对话的一部分——与「记录不得扰动运行」的要求全面冲突。机制层面command/run与command/done不属于SurfaceEventType因此它们不可能获得surfaceOp或进入派生历史即便出错也不行。测试对这一保证做了严格验证command-feedback.spec.ts运行/feedback invisible to the model后遍历所有会话事件断言每个事件都不含surfaceOp属性session.deriveEventMessage(event)返回nullfoldSurface(session.events).nodes为空session.surface.nodes为空session.deriveMessages()为空数组。也就是说反馈输入、feedback/record事件、确认文本三者都不进入模型请求记录反馈不会改变当前轮次剩余的请求也不会影响 KV Cache 复用它只追加会话日志不动已有的可复用请求前缀。原样文本去除空白但绝不解析/feedback对输入的处理只有一步丢弃前后空白。除此之外不做任何解析——没有截断、没有大小写折叠、没有命令解析。最典型的例子是/feedback /plan felt slow记录的是字面文本/plan felt slow开头的/plan是内容而不是嵌套命令。测试明确验证了这一点command-feedback.spec.ts输入 /plan felt SLOW\n\ttwice today 后记录值为/plan felt SLOW\n\ttwice today仅去除首尾空白内部空白保留。这一选择的反面参照是/goal使用的控制词语法若/feedback采用类别前缀、严重程度标记之类的控制词语法对应的字面反馈将无法表达——而这与采集接口的目的正好相反。原文档还补充了一个更深刻的论证原样文本是未来消费方可以收窄的最宽接口已被解析的接口无法事后放宽。包 README 的已知限制中也写明「没有结构化字段」与这一决策一脉相承。一个全新的包分组packages/feedback/packages/feedback/是本次变更新建的分组因为现有分组都不拥有「人类反馈」这一职责goal/负责目标状态session-title/负责标题core/是产品主干。分组内目前有两个互相独立的包见 packages/feedback/README.md包职责command-feedback/feedback命令一条命令记录一条自由文本的会话评论零模型轮次message-feedback单条助手消息的评分与备注通过messageFeedback服务提供给产品界面两类反馈的共同点是永不进入模型——它们是关于输出的信号绝不是对它的输入。分组设计原则是分组只放生产方包跨领域消费方留在各自所属的分组避免这个分组被迫膨胀。命令生命周期与确认文本中的共享披露三份日志记录围绕/feedback会产生三类会话记录全部仅写日志、非 surfacecommand/run——命令身份与来源不含argsfeedback/record——唯一的反馈文本载荷command/done——确认结果。这三份追加进入持久化的常规有界写入路径没有任何环节强制 flush因此确认文本报告的是「反馈已进入日志」而不是「已经落盘」。确认文本的共享披露句子确认文本会追加一句会话共享政策披露具体措辞由挂载的遥测服务决定src/index.ts披露状态确认文本中的句子fullSession sharing is enabled.feedback-onlySession sharing is feedback-gated; recording feedback uploads the session records not yet shared.disabledSession sharing is disabled.无遥测服务挂载Session sharing is not configured.实现上命令通过ctx.get(sessionTelemetry)在 handler 执行时读取可选服务而不是在inject中声明依赖——因为遥测是可选的声明式注入会在服务缺失时导致插件加载失败而命令必须无遥测也能工作。sharingSentence对状态枚举做了穷尽匹配未知状态走assertNever失败关闭fail closed。共享披露只报告当前政策绝不承诺反馈或会话已投递到任何地方。这一行为的完整论证见 2026-08-07-feedback-acknowledgement-sharing-disclosure.md握手handoff是后端非阻塞入队批量、重试与丢失策略属于后端 SDK后续重新配置也可能改变已共享的内容因此句子不声称任何关于「已到达采集器」或「未来留存」的事实。测试对四种披露状态逐一固定了确认文本command-feedback.spec.ts并通过假后端FakeTelemetry模拟三种共享状态与未挂载场景。反馈门控的会话遥测可选的 OTel 遥测包deepseek-ai/dsh-session-telemetry-otel是feedback/record的基础设施消费方见 2026-08-05-feedback-gated-session-telemetry.md它在两种模式下消费该事件而不改变反馈事件或命令路径FEEDBACK_ONLY模式feedback/record追加时从会话日志读取未释放的前缀通过该事件本身完成握手后续追加的记录保持本地直到下一条反馈事件DISABLED模式默认不构建 exporter、processor 或 logger provider仅在观察到feedback/record时打印「未共享任何内容、反馈保持本地」的警告FULL模式显式选择立即投递到配置的 OTel 管道。这印证了原文档的结论反馈事件对正在运行的 agent 与模型保持惰性inert所有下游行为都发生在可选的基础设施层。考虑过的替代方案六条被否决的路原文档记录了六条被认真考虑并否决的替代方案它们是理解最终设计边界的最好材料替代方案否决理由用command/run作为反馈记录反馈将与单一触发方式耦合消费方被迫靠命令名识别领域事实非命令生产者若不伪装执行命令就无法创建相同记录同时在feedback/record与command/run.args存储文本同一行为产生两个无实质区别的载荷副本通过agent.inject()将反馈作为 user 消息注入反馈对模型可见进入下一次请求、改变被评论的运行、消耗 token——三项「不得扰动」要求全部违反让/feedback成为真正的空操作使命令失去意义明确要求是让评论进入会话日志在packages/interaction/commands等现有包中注册ctx.commands是注册表而非任意命令实现的归属地且需求方明确要求独立包从文本中解析结构类别前缀、严重程度标记属于投机设计无消费方需要该结构控制词语法使对应字面反馈不可记录改为模型面向的工具而非斜杠命令反馈是人类直接观察经模型会消耗轮次、让模型改写用户原话、使记录取决于模型是否选择调用工具后果、部署影响与已知限制产品组装随附的dshbase 组合无条件挂载该命令无配置、不依赖 goal 栈Web 客户端通过命令适配器暴露该命令无头模式、ACPAgent Client Protocol与 JSON-RPC 不提供命令适配器因此/feedback在这些入口不可用。自定义应用若要获得该命令只需在cordis.yml中同时挂载命令注册表与本插件README.md 中的官方示例- id: commands name: deepseek-ai/dsh-commands - id: command-feedback name: deepseek-ai/dsh-command-feedback匿名用户 id 的创建时机$DSH_HOME/.anonymous-user-id只在首次接受反馈时才可能被创建被拒绝的空输入不会解析或创建 id。测试断言command-feedback.spec.ts空输入与纯空白输入都返回用法错误getOrCreateAnonymousUserId未被调用且command/done记录两条kind: error。持久化语义本包拥有一个独立的仅追加事件不存在跨事件关系或可变数据关系可供不变式伴生插件检查。因此invariant.ts中的安装器是一个空实现invariant.ts仅在deepseek-ai/dsh-invariants服务中注册包所有权。该事件遵循会话日志现有的回放、fork、持久化与崩溃尾部行为。已知限制与延期事项包 README 明确列出以下边界均为当前约束而非待办清单无检索或管理面可选 OTel 插件仅把事件用作共享触发器没有检索、聚合、分类或模型工具无结构化字段一条记录就是一个自由文本串无类别、严重程度或事件引用不支持修改或撤回日志仅追加且本包不新增 tombstone错误条目只能被后续条目覆盖无显式持久化屏障确认紧跟追加而非 flush崩溃前瞬间记录的条目可能随未 flush 的尾部丢失需要屏障的消费方应await ctx.sessions.flush(session)全新会话上无可见确认Web transcript 仅在会话激活后才渲染命令行因此在空白会话上记录反馈不会显示确认行首条消息后记录则正常仅 Web 入口可用无头、ACP、JSON-RPC 无命令适配器。从源码与测试验证行为插件入口源码解读apply函数src/index.ts是命令注册的全部export function apply(ctx: Context): void { ctx.commands.register({ name: feedback, description: record feedback about this session, input: { hint: text }, recordInput: false, handler: invocation executeFeedbackCommand(invocation, ctx), }) }包导出为name command-feedback、inject [commands]且无 default 导出保证 Loader 安全的具名导出插件 dispose 后命令即被注销。单元测试覆盖矩阵command-feedback.spec.ts 通过真实命令注册表边界ctx.commands.execute与 UI 适配器相同的入口验证了全局命令注册、记录recordInput: false、dispose 后注销成功路径确认文本 载荷恰好出现一次 command/run无args独立生产者与空文本拒绝事件顺序command/run → feedback/record → command/done空白规范化而不解析命令样内容多次记录各自独立、并发提交按派发顺序记录三种共享状态 无服务状态的披露句子模型排除surfaceOp缺失、deriveMessages()为空空输入/纯空白输入的用法错误与command/done.kind error已取消请求的派发被拒绝且不记录任何事件。真实 Loader 组合测试loader-composition.spec.ts 走的是真实 Loader 组合在临时目录写入cordis.yml通过deepseek-ai/cordis-plugin-loader加载dsh-agent、dsh-session、dsh-commands、dsh-command-feedback四个模块验证命令在组合后的注册表中可被发现commands.list(owner)包含feedback成功与失败的完整确认文本事件序列与单份载荷deriveMessages()与session.surface.nodes均为空——反馈确实从未到达模型。该测试还 stub 了DSH_HOME环境变量真实调用getOrCreateAnonymousUserId({ env: { DSH_HOME: root } })验证匿名用户 id 与确认文本的集成。延伸阅读packages/feedback/command-feedback/README.md——包级参考使用方式、实现内幕、模型体验与已知限制packages/feedback/README.md——feedback 包组全景会话评论与单条消息反馈的分工docs/subsystems/session-telemetry.md——SessionTelemetrySharingStatus词汇表与后端契约驱动确认文本中的披露句子docs/subsystems/persistence.md——追加事件如何持久化以及「flush 屏障」的含义packages/feedback/command-feedback/src/index.ts 与 packages/feedback/command-feedback/tests/command-feedback.spec.ts——生产者契约与行为固化的第一手证据2026-08-05-feedback-gated-session-telemetry.md 与 2026-08-07-feedback-acknowledgement-sharing-disclosure.md——反馈事件如何被遥测消费、披露句子如何被设计出来。赞分享人工智能AI AgentAgent 框架DeepSeek【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址https://gitcode.com/gh_mirrors/de/deepseek-harness点击查看免费下载相关推荐DeepSeek Harness 日志驱动的会话标题deepseek-ai/dsh-session-title 的设计与实现DeepSeek Harness 日志驱动的会话标题 deepseek ai/dsh session title 的设计与实现 会话标题是编辑器、终端与查询人工智能AI AgentAgent 框架DeepSeekDeepSeek Harness 会话缓存命中率TUI 页脚 cache N% 的设计与实现DeepSeek Harness 会话缓存命中率TUI 页脚 cache N% 的设计与实现 本篇技术笔记基于 DeepSeek Harness 归档的设计决人工智能AI AgentAgent 框架DeepSeekDeepSeek Harness 会话共享策略披露/feedback 确认消息的透明化设计DeepSeek Harness 会话共享策略披露 /feedback 确认消息的透明化设计 /feedback 是 DeepSeek Harness 中记录人工智能AI AgentAgent 框架DeepSeek创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考