ByteNoteByteNote
DeepSeek Harness 会话遥测:接缝两侧的设计
字

字节笔记本

2026年10月6日 · 约 6 分钟读完

DeepSeek Harness 会话遥测:接缝两侧的设计

API中转
¥120

DeepSeek Harness 是一个开源的 Agent 框架,运行中的每一步都会追加为会话事件,形成一份权威会话日志。有了日志,下一个自然的问题是对外上报:把事件接进可观测平台,供告警、审计与分析。常见的做法是在主循环里到处埋 SDK 调用,结果上报逻辑与业务逻辑缠在一起。该框架选择把会话上报拆成一项可选的能力接缝(capability seam),从结构上把这件事隔离在主干之外。

DeepSeek Harness 会话遥测:捕获侧与上报侧

一条接缝,两侧职责

接缝的捕获侧由 Service Definition 与捕获协调器承担,以 ctx.sessionTelemetry 暴露,拥有捕获点、固定分片投影、脱敏瀑布、交接游标与最小后端契约;上报侧则是部署方加载的 Service Provider,官方实现就是把 OpenTelemetry JS SDK 的日志流水线原样配置一遍。它是可选能力,不在 agent loop 主干上,也没有任何内容进入模型请求。

两边怎么分工,框架写成了一条边界公理:harness 的职责止于 emit()。协调器只负责把记录交给后端,之后的排队、批处理、重试与丢失策略,全部属于上报 SDK。连同被否决的替代方案一起,这套取舍都在设计阶段定案,避免后来者重新争论。

逻辑记录:接缝的全部词汇

协调器交给后端的东西叫逻辑记录,字段刻意精简:channel 区分 ledger 与 ops 两条通道,前者逐条镜像会话日志事件,后者承载 agent-error、shutdown 这类没有日志归属的运营信号;time 是毫秒时间戳;severity 只有 info、warn、error 三级,并且在捕获时就映射完毕:工具结果自带的 isError、turn/end 的错误原因与 agent-error 记录归为 error,其余捕获事件默认 info,warn 留给脱敏策略与后端使用。接收端因此可以零配置直接按级别告警。

一条遥测记录的结构与投递语义

attributes 同样刻意最小:ledger 记录带 session.id、event.type、event.seq,会话头部有则附带 session.cwd、session.parent_id、session.seed_length;ops 记录带 telemetry.op 与 session.id,agent-error 另加 agent.id、turn、step、error.name。凡是能从 body 恢复的信息都不在此重复。body 是完整载荷的深拷贝,交接之后不再变更。

投影规则只有一条值得注意:每个 (turn, step) 只发出第一条 assistant/chunk,作为流已开始的信号,其余分片在捕获时丢弃。所以传输中出现 seq 缺口是常态,绝不是丢失信号;除此之外的所有事件类型都完整透传,包括接缝从未听说过的插件合并事件。

尽力而为的投递契约

投递被明确设计为尽力而为:游标标记的是已交接,不是已送达,崩溃或重载窗口可能丢记录,无游标的重新接管与 SDK 重试可能造成重复。契约不假装可靠,而是把责任分配写清楚:接收端对 ledger 记录按 (session.id, event.seq) 去重;ops 记录刻意不带这类身份标识,它们是用来告警的信号,不是用来累加的条目,重复被容忍而非被去重。

后端契约:emit、flush 与 shutdown

后端要实现的接口只有三个成员。emit() 必须是非阻塞入队:协调器在 session/event 热路径上同步调用它,任何比队列推送慢的实现都会拖累 agent loop 或反馈处理;这里抛出的异常被协调器兜住并记日志,永远不会进入主循环。flush() 是可选的 turn 结束提示,fire-and-forget,大多数后端不应该实现它,让 SDK 自己的批处理节奏决定导出时机,官方 OTel 后端就刻意不实现,为的是避开并发 flush 与 shutdown 排空之间的纠缠。shutdown() 则必须清空队列并达到静默,连 flush 在途时入队的记录也要保证送达;协调器在应用卸载时等待它,失败只记警告,不阻断卸载。

每个上下文只允许挂载一个后端实现,重复加载直接抛错。

共享披露与脱敏瀑布

遥测牵涉隐私,框架把知情权也写进了契约:每个后端必须通过抽象成员 sharing 披露部署选择的会话共享策略,取值为 full、feedback-only 或 disabled;/feedback 命令的确认文本只有在没有挂载任何遥测服务时才显示未配置。披露只陈述当前策略,不承诺投递与留存。

每条记录在投影与 emit() 之间还要穿过 session-telemetry/record 脱敏瀑布。这条瀑布自带零条规则:不挂监听器时,记录以捕获时的原样到达后端,导出数据能干净到什么程度,恰恰取决于部署方挂载了什么规则。监听器通过变换 next() 的返回值逐层堆叠,不调用 next() 直接返回即替换其下方的全部逻辑;抛出异常的监听器会在协调器的隔离范围内以 fail-closed 方式扣下那一条记录。脱敏只作用于导出副本,权威会话日志永不改写。

值得借鉴的四点

一是语义在捕获端定死,严重度预映射加固定投影,让接收端零配置可用;二是把会丢会重写进契约,去重键交给接收端,而不是假装通道可靠;三是扩展点自带安全兜底,瀑布零规则起步、fail-closed、只改副本不动权威日志;四是可选能力不碰主干,上报慢了、挂了都不影响 agent loop。对一个要把会话数据交出去的框架来说,这四条组合起来,是一份相当克制的隐私与可靠性设计。

相关文章

分享: