DeepSeek Harness 恢复会话报 {{model}} 没值:agents.resume 怎么修

故障排查发布于 2026-10-20作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSHagents.resumeagentOptions{{model}}系统提示词会话恢复
DeepSeek Harness 的 agents.resume 不带 agentOptions 时,每轮都报 prompt variable {{model}} has no value。根因是 loop 从 live agent.options 绑定变量;本文给补 options、会话头恢复、绑定兜底三条路径。

程序里调用 agents.resume({ resumeSessionId }) 恢复一个会话,之后每一轮都立刻失败,报 prompt variable "{{model}}" has no value,turn/end 的 reason.kind 是 error。 会话本身没坏,历史也都在;坏的是「这个 agent 不知道自己该用哪个模型」。

DeepSeek Harness(DSH)的 agent loop 在组装提示词时,从当前 agent 的 live options 读取模型与提供方,再绑定到 {{model}} 与 {{provider}}。agents.resume 的 agentOptions 在调用签名上是可选的,省略之后没有任何默认填充,变量就空了。本文按「判据 → 机制 → 三条路」展开,最后补一个更省事的早失败选项。

DeepSeek Harness 恢复报错怎么确认:判据不是提示词写错

判据是「同一个会话在界面里能用、程序化恢复后每轮必错、错误只点名模板变量」。 四步核对:

  1. 用同一份会话,在界面里打开并选一次模型,发一条消息。预期:正常回复,说明会话数据没坏。
  2. 在脚本里用 agents.resume({ resumeSessionId }) 恢复,不传 agentOptions。预期:第一条消息就报 {{model}} 没值。
  3. 看 turn/end 事件。预期:reason.kind 为 error,不是 aborted 或 completed。
  4. 在恢复调用里补上 agentOptions: { model } 再试。预期:错误消失,确认根因在恢复参数。

这个错误最迷惑人的地方是它长得像模板问题:报错点名 {{model}},而模板是内置的,你根本没改过。实际是绑定没值,不是语法错。

DeepSeek Harness 变量绑定机制与最小复现

因为 model 与 provider 两个变量都在请求组装时从 agent.options 取值,而不是从会话历史里取。 据社区核对源码,链路是:

  1. agent loop 注册 model 变量,取值函数读取 context.agent?.options.model。
  2. provider 变量同理,来自同一个 options 对象。
  3. 正常创建 agent 时,agentOptions 会把这两个字段填上。
  4. agents.resume 允许省略 agentOptions,省略后 agent 的 options 里没有模型。
  5. 任何引用 {{model}} 的提示词在严格插值下抛错,turn 立即结束。

影响面不止脚本:无头运行器、启动恢复类插件、自动化流水线,只要走程序化恢复且没带模型,都会得到一批「能创建但不能对话」的 agent。报告者说他们的启动恢复插件恢复中断的目标会话后,每一轮都错,直到在界面里重新选模型。如果你维护这类恢复插件,升级前可以先在 DSH Plugin Hub 核对宿主版本与兼容声明。

复现不需要复杂环境,一个持久化会话加三行调用就够;关键是「新进程」和「不传 agentOptions」两个条件同时满足。 五步:

  1. 在任意会话里发一条消息,确认它已持久化到磁盘。预期:重启后仍能在列表里看到。
  2. 完全退出 DSH,重新启动一个干净进程。预期:没有残留的 agent 实例。
  3. 调用 agents.resume({ resumeSessionId }),不要传 agentOptions。预期:调用本身成功返回。
  4. 向恢复出的 agent 发一条消息或跑一轮。预期:立即失败,报 {{model}} 没值。
  5. 换成带 agentOptions 的调用再跑一次。预期:正常完成,对照成立。

DSH插件修法一:resume 时显式传 agentOptions

最直接的做法是把模型与提供方一起传进去,调用点本来就知道自己想用什么模型。 适合脚本、批处理、无头运行器。

  1. 在恢复调用里加上 agentOptions,至少包含 model,需要时同时给 provider。
  2. 确认传入的模型名与端点支持的能力匹配,不要随手填一个占位串。
  3. 跑一轮最小对话验证。预期:不再报变量没值,回复内容与所选模型一致。
  4. 把这段调用封装成一个函数,避免每个恢复点各写一份。预期:后续新增入口不会漏传。
ts
const agent = await agents.resume({
  resumeSessionId,
  agentOptions: { model: 'deepseek-chat', provider: 'deepseek-official' },
})

DeepSeek Harness 路径二:从会话头恢复上次的模型选择

如果恢复的是别人的会话或历史任务,正确值不该由调用方猜,而应从会话记录里读最后一次模型选择。 这条路更接近界面恢复的行为。

  1. 读取会话元数据,找到最后一次模型或提供方选择事件。预期:拿到与当时一致的模型名。
  2. 用这组值构造 agentOptions,再调用 agents.resume。预期:恢复后的 agent 与中断前一致。
  3. 会话里没有记录时,退回 profile 的默认模型,并在日志里标注这是回退。预期:不会静默用错模型。
  4. 给这条恢复路径补一条测试:无记录、有记录、记录损坏三种输入。预期:三种都有确定行为。

DeepSeek Harness 路径三:给变量绑定加 fallback

根治方向是在绑定层兜底:options.model 为空时,从会话记录或配置默认值取,而不是让插值抛错。 但要注意,兜底值必须真实,否则提示词会「说谎」。

  1. 在 model 变量的取值函数里增加候选顺序:live options → 会话最后一次选择 → 配置默认值。预期:三层都为空才报错。
  2. provider 变量使用同一套候选顺序。预期:不会出现模型有了、提供方没值的半填状态。
  3. 回退发生时记一条明确日志,包含会话 id 与实际取值来源。预期:排查时能看出用的是回退值。
  4. 补测试:只给 model、只给 provider、都不给三种情况。预期:前两种能继续,第三种给出可读错误。
  5. 复核提示词里对模型名的使用场景,确认回退值不会误导能力判断。预期:自我介绍与工具选择不出现明显偏差。

如果团队更希望「错得早」,可以在 agents.resume 入口直接校验模型,缺失就抛一条明确的参数错误,而不是让每一轮在提示词组装时失败。 四步:

  1. 在 resume 入口检查 agentOptions.model 是否为空。预期:缺失时立即拒绝。
  2. 错误信息写清「恢复会话需要 model 或 agentOptions」,不要只提模板变量。预期:调用方能直接定位。
  3. 保留路径二的自动恢复作为默认行为,只在明确要求严格模式时启用早失败。预期:两种调用方都能接受。
  4. 把早失败的错误码固定下来,不要复用模板变量错误的文本。预期:调用方能按码分支处理。

改完按三步验证:

  1. 用不带 agentOptions 的 resume 跑一轮。预期:在入口就被拒绝,错误信息点名 model。
  2. 用带 agentOptions 的 resume 跑同一会话。预期:正常完成。
  3. 检查日志里是否记录了回退值。预期:能看出模型名来自会话头还是配置默认。

DeepSeek Harness 边界与注意

  1. 只补 model 不补 provider 可能引出下一个错误,两个变量来自同一个 options 对象,要一起考虑。
  2. 不要在恢复后靠「发一条消息试试」来探测模型是否正确,错误的模型会真实产生费用与上下文。
  3. 讨论里没有官方修复版本,0.2.1-rc.2 仍可复现;回复提到树内已有可复用的 fallback,方向是复用而不是再造一套。
  4. 界面恢复与程序化恢复的行为差异是根因的一部分,修完后两条路径应给出同一组默认值。相关模型继承问题另见 子代理模型继承。

常见问题

DeepSeek Harness 程序化 resume 后报 {{model}} 没值,为什么每轮都失败?

DeepSeek Harness 不是模板缺变量,而是 resume 没带模型选项。agent loop 在组装提示词时从当前 agent 的 options 里取 model 与 provider 绑定到变量;resume 省略 agentOptions 后这两个字段为空,任何引用 {{model}} 的内置提示词都会在组装阶段抛错,turn 直接以 error 结束。补上 agentOptions 或让恢复逻辑从会话记录取模型即可。

为什么 DeepSeek Harness 界面里点一下模型就能恢复,程序化 resume 却每次失败?

DeepSeek Harness 界面恢复会走一条带默认值的路径,选中模型后 agent 的 options 被填上;程序化 resume 的 agentOptions 是可选的,省略时不会触发任何默认填充。两条路径对「必填」的理解不一致,于是同一个会话在 GUI 能用、在脚本里每轮失败。

给 DeepSeek Harness 的 agents.resume 补 model 就够了吗,还会报别的变量吗?

DeepSeek Harness 的 model 只是最先撞上的一个。provider 变量同样从 live options 取,如果提示词里引用了它,补完 model 后可能接着报 provider 没值。正确做法是把恢复会话所需的模型与提供方一起带上,而不是只填一个字段。

为什么 DeepSeek Harness 讨论里说只补 model 会让提示词「说谎」,该用什么值?

DeepSeek Harness 提示词里的模型名会参与自我介绍与能力判断,随手填一个默认模型会让模型以为自己是另一个模型。应优先用会话头里最后一次记录的模型选择,没有记录时再用配置默认值,并在日志里写明这是回退值。

相关术语

agents.resume
agents.resume 是 DeepSeek Harness 用于从持久化会话恢复 agent 的接口,可接受 resumeSessionId 与可选的 agentOptions。省略 agentOptions 时不会自动补齐模型与提供方。— https://github.com/deepseek-ai/deepseek-harness/discussions/10208
agentOptions
agentOptions 是创建或恢复 agent 时传入的配置集合,包含 model、provider 等运行参数。它决定 agent 的 live options,也是提示词变量绑定的取值来源。— https://github.com/deepseek-ai/deepseek-harness/discussions/10208
系统提示词变量
系统提示词变量是 DeepSeek Harness 在组装提示词时用运行上下文替换的占位符,例如 {{model}} 与 {{provider}}。占位符找不到值时,严格插值会直接抛错而不是留空。— https://github.com/deepseek-ai/deepseek-harness/discussions/10208
turn/end
turn/end 是 DeepSeek Harness 标记一轮对话结束的事件,带 reason.kind。kind 为 error 表示这一轮在组装或调用阶段失败,而不是正常完成。— https://github.com/deepseek-ai/deepseek-harness/discussions/10208

来源