- DSH
- 0.1.1-rc.2
- 风险
- medium
先看结论
DSH Session 不是一份简单聊天记录,而是一条由类型化事件组成的仅追加日志。用户消息、模型输出、工具调用、工具结果、轮次边界和运行时请求状态都从这条日志形成可回放历史;LLM 消息不是另外保存的一份副本。
恢复、Fork 和 Compaction 解决三个不同问题:恢复让持久化会话重新变成可运行 Agent;Fork 从已完成轮次的稳定前缀创建子会话;Compaction 用摘要替换模型当前可见的旧上下文,但不删除底层事件,也不会撤销外部副作用。本文依据官方 dsh-v0.1.1-rc.2 源码复核。
一次任务怎样写进 Session
DSH 把一次用户任务称为一个 turn,一个 turn 可以包含多个 step。每个 step 包含一次模型请求,以及该请求触发的工具执行。常见事件顺序可简化为:
turn/start
→ user/message
→ step/start
→ request/header
→ assistant/message 或 tool/call
→ tool/result
→ step/end
→ 需要时进入下一 step
→ turn/end
事件带有连续的 seq 和时间戳。tool/call 与 tool/result 通过 callId 配对;模型流式分片也会保留,以支持逐步回放。插件可以增加自己的事件类型,因此 Session 同时也是审批、压缩、Hook 等子系统的审计载体。
“唯一真源”对用户意味着什么
模型下一次请求看到的历史是由 Session 的可见 surface 派生出来的。请求配置、模型、系统提示和工具 schema 则以完整的 request/header 快照记录。这样恢复或回放时不需要猜测当时模型看到了什么。
但“日志完整”不等于“世界状态可逆”。命令已经改过的文件、发出的网络请求、数据库更新和外部消息不会因为回放旧事件而自动回滚。对这些副作用仍应使用 Git、备份、事务、测试环境和审批策略。
持久化和恢复如何工作
内存 Session 与持久化是两个子系统。持久化后端订阅事件并批量写入;显式 flush 会取消等待并排空待写数据,dispose 时也会执行最终排空。
如果进程在一个 turn 中途崩溃,冷加载不会截断已经落盘的事件。后端会追加一个合成的 turn/end,原因标记为 interrupted,把遗留轮次配平后再供恢复使用。活跃会话不会被另一个加载流程擅自修复;若当前 turn 仍开放,加载会拒绝操作。
恢复持久化会话与简单读取日志不同。官方接口通过 ctx.agents.resume({ resumeSessionId }) 恢复可运行 Agent;恢复时还要使用 Session header 中的工作目录、血统、Agent preset 和格式版本等元数据。
Resume、Replay 和 Fork 的区别
| 操作 | 输入 | 结果 | 适用目的 |
|---|---|---|---|
| Resume | 已持久化 Session | 重新得到可运行 Agent | 继续未完成或跨进程任务 |
| Replay | 同一组事件 | 重建历史或展示 | 审计、调试、读取 transcript |
| Fork | 源 Session 的稳定事件前缀 | 带父会话血统的新 Session | 从某个节点尝试不同方案 |
普通 Fork 默认复制到源 Session 当前最后一条事件,也可以显式指定包含边界。被选择的前缀必须结束在没有开放 turn 的位置;如果边界落在进行中的轮次里,API 会拒绝,而不是悄悄截断。子会话会继承 cwd,并记录 parentSession 与 seedLength。
因此,想比较两个实现方案时,先让当前 turn 完整结束,再从对应 turn/end 位置 Fork。不要把复制工作目录、复制 Session 历史和回滚文件状态混为一谈:Fork 继承事件上下文,不会替你创建独立 Git 分支或文件快照。
Compaction 是否会删除历史
不会。Compaction 的目标是缩小模型可见上下文:它选出一段平衡的 surface,把摘要作为新的可见节点替换那段内容,同时在仅追加日志中记录开始、摘要和结束事件。原始事件仍保留在底层日志里。
选择范围时必须保持工具调用与结果成对,避免摘要后只剩一半工具语义。自动压缩可由上下文压力或模型确认的上下文溢出触发;手动压缩也可能因为 Session 忙碌、范围变化、摘要失败、持久化失败或取消而停止。
压缩有三个重要限制:
- 摘要是有损表示,后续模型看到的是摘要而非全部旧 surface;
- 压缩不会删除审计日志,也不是隐私擦除功能;
- 压缩不会撤销工具已经产生的文件或外部系统副作用。
升级时为什么要关注 Session 格式
Session header 包含磁盘格式版本。0.1.1-rc.2 的持久化实现会拒绝无法可靠理解的更旧或更新格式,而不是猜测迁移。SQLite 后端也有独立 schema 版本,并明确拒绝旧 schema,而非自动迁移。
升级 DSH 前应:
- 停止新任务并等待当前 turn 结束;
- 正常关闭进程,让持久化队列完成 flush;
- 备份
$DSH_HOME、项目工作区和重要 Session 数据; - 阅读目标 Release Notes 中的 Session、persistence、SQLite 与 compaction 变化;
- 先用副本验证能否列出、读取和恢复旧会话;
- 保留原版本和回滚路径,不直接覆盖唯一数据副本。
如何验证一次 Session 是否可复核
完成一个最小任务后,检查以下证据:
- 用户输入、模型结果和工具调用是否按顺序显示;
- 每个工具调用是否有对应结果或明确中断;
- turn 是否正常结束,崩溃恢复时是否标记
interrupted; - 恢复后使用的工作目录和 Agent preset 是否仍正确;
- Fork 的子会话是否记录父会话血统,并从预期边界开始;
- Compaction 前后的当前上下文是否保持工具调用/结果配对;
- Session 日志中是否含有不应长期保留的敏感内容。
Session 可能保存用户输入、工具参数、输出片段和工作目录等信息。不要把含凭据或客户数据的原始 transcript 直接公开;用于排障时应先脱敏,并说明 DSH 版本、持久化后端和验证日期。
想理解 Session 在整体插件树中的位置,阅读DeepSeek Harness 架构解析;想控制工具执行范围,阅读DSH 权限与沙箱指南;第一次运行则从DeepSeek Harness 中文入门开始。
常见问题
恢复 Session 会重新执行以前的工具吗
事件回放本身用于重建历史,不应被理解为重放外部副作用。后续 Agent 是否再次调用工具,取决于新的请求与执行流程。
Fork 会复制工作目录里的文件吗
不会。Fork 继承 Session 的 cwd 元数据和事件前缀,不等于复制目录或创建 Git 分支。
Compaction 能否用来删除敏感信息
不能。它替换模型可见 surface,但底层事件日志仍是仅追加记录。敏感信息处理需要凭据轮换、数据清理和存储层处置流程。
来源与维护信息
本文根据以下原始资料整理。版本变化后,请以官方资料和页面标注的验证日期为准。
- https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.1-rc.2/docs/subsystems/session.zh.md
- https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.1-rc.2/docs/subsystems/persistence.zh.md
- https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.1-rc.2/docs/subsystems/compaction.zh.md