DeepSeek Harness 可观测性:用 OpenTelemetry 把会话遥测出去

DeepSeek Harness 可观测性:用 OpenTelemetry 把会话遥测出去

上一篇讲配置与 Patch,是「跑起来之前」的事。这一篇讲跑起来之后------Agent 在后台跑了几百个 turn,怎么知道它到底干得怎么样、有没有出错、用户会话都流向了哪?

答案在 Harness 的会话遥测(Session Telemetry)子系统。它把「会话里发生了什么」从会话日志里抽出来,交给 OpenTelemetry 的日志管线往外送。但这一篇我最想讲的不是「怎么接 OTel」,而是它凭什么设计得这么克制------这个子系统的边界感,比它暴露的功能更值得学。

一、先立边界:它是可选能力,不是主循环脊梁

官方文档第一段就把边界划死了:

它是一个可选能力,不是 agent-loop 脊梁的一部分 ,这里没有任何东西会到达模型请求。harness 的职责到 emit() 为止;批处理、重试、排队、丢失策略都归上报 SDK 管。

这句话信息量很大。翻译成人话:

  • 遥测不是 Agent 跑起来的必要条件,卸了它 Agent 照转;
  • 遥测数据绝不回流到模型请求里(不会污染上下文);
  • Harness 只负责「把记录交出去」这一个动作(emit()),之后网络怎么发、失败了怎么办,一概不管------那是 OTel SDK 自己的事。

这条「边界公理」是理解后面一切的前提。

二、逻辑记录:两个通道 + 三级严重度

Harness 交给后端的是统一的逻辑记录 SessionTelemetryRecord。它分两个通道:

  • ledger :会话日志的一一镜像 ------每个 session event 对应一条。带 session.id、event.type、event.seq 等身份属性;
  • ops :运行信号 ------比如 agent-error、shutdown 这种在日志里没有家的事件。它故意不带 event.seq 之类的身份,就是为了让人「永远别把它误当成 ledger 行」。

严重度在捕获时就预映射好了,接收方零配置就能告警:

  • error:事件自身的 outcome 标记为错(工具结果的 isError、turn/end 的错误原因),以及 agent-error 运行记录;
  • info:其余默认;
  • warn:留给 session-telemetry/record 策略和后端使用。

一个巧妙的细节:每个 (turn, step) 只发第一条 assistant/chunk (流开始的信号),其余的在捕获时就丢了。所以线上 seq 有缺口是常态,不是丢包信号------别看到 seq 不连续就拉警报。

三、redact waterfall:脱敏是扩展点,不是写死的

最值得说的一处:遥测出海前要过一条脱敏流水线 ------session-telemetry/record 这个 waterfall。

它的语义是:每条记录在投影和 emit() 之间,会经过这条 waterfall。监听器通过变换 next() 的返回值来叠加规则;返回而不调 next() 会替换掉下面的所有规则;抛异常则fail-closed------把这一条扣下不发。

关键在于:Harness 自己一条规则都不内置 。没有监听器挂载时,记录原样到达后端------「导出的数据有多干净,取决于你的部署挂了多干净的规则」。脱敏只作用于导出的副本,canonical 会话日志从不被改写。

ts 复制代码
// 概念示意:挂一条脱敏规则
ctx.on('session-telemetry/record', (record, next) => {
  const r = next()                       // 先让下层规则跑完
  if (r.channel === 'ledger' && r.attributes['event.type'] === 'tool/result') {
    return scrubSecretFrom(r)            // 再扣掉自己关心的 secret
  }
  return r
})

这是典型 Harness 式设计:把安全策略做成可插拔的 seam,而不是写死的 if 判断。

四、backend contract:emit / flush / shutdown

后端要满足的最小契约只有三个方法:

  • emit(record) :把一条记录交给后端管线。必须是非阻塞入队 ------因为协调器在 session/event 热路径上同步调用它,比入队慢一丁点都会拖累 agent 循环。这里抛错会被协调器吞掉、记日志,绝不回流到循环;
  • flush()(可选) :提示「一个 turn 结束了」,后端可以借此 flush。但官方建议多数后端别实现它,让 SDK 自己的批处理节奏管导出时机;
  • shutdown():把排队的都 flush 掉、进入静止状态。此前 emit 的一切都必须送达。

交付是 best-effort 的:cursor 标记的是「已交接」,不是「已送达」。记录可能丢失(崩溃、reload 窗口),也可能重复(cursor 缺失重收、SDK 重试)。所以接收方要在 (session.id, event.seq) 上去重 ledger 记录;ops 记录故意不带这身份------它们是「用来告警的信号」,重复了也无所谓。

五、sharing disclosure:把分享策略摆到明面上

最后一块是分享披露 。每个后端必须通过 ctx.sessionTelemetry 上必需的 sharing 成员,披露部署选择的分享策略:

ts 复制代码
type SessionTelemetrySharingStatus = 'full' | 'feedback-only' | 'disabled'

消费方(比如 /feedback 命令的确认文案)把它渲染给用户。它披露的是当前策略,不是「送达或留存情况」------因为后者根本不在 harness 职责内。只有没有挂载任何遥测服务时,才显示「未配置」。这个设计把「我的会话数据会不会被分享」这个隐私问题,从「用户猜」变成了「系统明说」。

六、避坑清单

  1. 别拿 seq 缺口当丢包 。assistant/chunk 每 turn 只发第一条,seq 不连续是设计使然,不是事故。
  2. 去重只在接收方做 。harness 交付是 best-effort 且可能重复,接收方必须在 (session.id, event.seq) 上去重;ops 记录别拿去求和。
  3. 脱敏规则要自己挂 。harness 零内置脱敏,不挂 session-telemetry/record 规则就是「原样外发」,敏感数据要不要脱干净完全取决于你。
  4. emit 必须是纯入队 。后端实现里别在 emit 里做同步网络 IO,否则会拖慢 agent 循环;抛错也只会被吞掉,别指望它兜住你的网络故障。
  5. 遥测不回流模型。它是单向出海的能力,别把遥测数据再喂回 agent 上下文,那既污染上下文也违背它「不达模型」的边界。

小结

这一篇看似讲 OTel,其实讲的是 Harness 一贯的设计品味:边界划清楚、职责交干净。遥测子系统把「捕获」和「上报」硬生生切开------harness 负责把记录交出去,SDK 负责发出去,中间一条可插拔的脱敏 waterfall 负责「该不该让某条数据出去」。这种「到我为止,之后不归我管」的克制,正是它能在复杂场景里保持可维护性的原因。

到这里,「把 DSH 用进生产」的工程化拼图还差最后一块:Agent 要动你的文件、跑你的命令时,谁说了算? 下一篇讲权限与审批------给 Agent 上一个 human-in-the-loop 的安全阀。


参考:deepseek-ai/deepseek-harness 官方仓库 docs/subsystems/session-telemetry.md。

相关推荐
邵奈一8 小时前
2.5倍速不降智:Opus 5.5极速版开闸
大模型·ai编程·claude·opus5.5·极速模式
电子元件小说家8 小时前
2026年AI与汽车电子双轮驱动下,大感值贴片功率电感选型与替代观察
人工智能·汽车
七牛开发者9 小时前
从 Muse、dots 和 Grok Bot 看 Personal Agent:状态、记忆、授权与后台执行
人工智能
一枕槐安4879 小时前
AG 幻觉率从 24% 压到 4%:我把召回评估做成了流水线
人工智能·ai
北方的银狐-Zero9 小时前
OntoL本体产品生产案例分析-项目,合同,付款,本体交付案例
人工智能·本体论
二川bro9 小时前
wiki编译拆解
人工智能
迅为电子9 小时前
【迅为RK3588开发板与RK1828算力卡方案】工业异常检测:缺陷定位全流程演示
人工智能
YH_Analytics9 小时前
2026-2032 食品吸液垫行业市场规模与增长预测
大数据·网络·人工智能
我命由我123459 小时前
智能助手通用问答边界
人工智能·python·学习·ai·学习方法·ai编程·智能体