DeepSeek Harness 恢复会话报 {{model}} 没值:agents.resume 怎么修
程序里调用 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 恢复报错怎么确认:判据不是提示词写错
判据是「同一个会话在界面里能用、程序化恢复后每轮必错、错误只点名模板变量」。 四步核对:
- 用同一份会话,在界面里打开并选一次模型,发一条消息。预期:正常回复,说明会话数据没坏。
- 在脚本里用
agents.resume({ resumeSessionId })恢复,不传agentOptions。预期:第一条消息就报{{model}}没值。 - 看
turn/end事件。预期:reason.kind为error,不是 aborted 或 completed。 - 在恢复调用里补上
agentOptions: { model }再试。预期:错误消失,确认根因在恢复参数。
这个错误最迷惑人的地方是它长得像模板问题:报错点名 {{model}},而模板是内置的,你根本没改过。实际是绑定没值,不是语法错。
DeepSeek Harness 变量绑定机制与最小复现
因为 model 与 provider 两个变量都在请求组装时从 agent.options 取值,而不是从会话历史里取。 据社区核对源码,链路是:
- agent loop 注册
model变量,取值函数读取context.agent?.options.model。 provider变量同理,来自同一个 options 对象。- 正常创建 agent 时,
agentOptions会把这两个字段填上。 agents.resume允许省略agentOptions,省略后 agent 的 options 里没有模型。- 任何引用
{{model}}的提示词在严格插值下抛错,turn 立即结束。
影响面不止脚本:无头运行器、启动恢复类插件、自动化流水线,只要走程序化恢复且没带模型,都会得到一批「能创建但不能对话」的 agent。报告者说他们的启动恢复插件恢复中断的目标会话后,每一轮都错,直到在界面里重新选模型。如果你维护这类恢复插件,升级前可以先在 DSH Plugin Hub 核对宿主版本与兼容声明。
复现不需要复杂环境,一个持久化会话加三行调用就够;关键是「新进程」和「不传 agentOptions」两个条件同时满足。 五步:
- 在任意会话里发一条消息,确认它已持久化到磁盘。预期:重启后仍能在列表里看到。
- 完全退出 DSH,重新启动一个干净进程。预期:没有残留的 agent 实例。
- 调用
agents.resume({ resumeSessionId }),不要传agentOptions。预期:调用本身成功返回。 - 向恢复出的 agent 发一条消息或跑一轮。预期:立即失败,报
{{model}}没值。 - 换成带
agentOptions的调用再跑一次。预期:正常完成,对照成立。
DSH插件修法一:resume 时显式传 agentOptions
最直接的做法是把模型与提供方一起传进去,调用点本来就知道自己想用什么模型。 适合脚本、批处理、无头运行器。
- 在恢复调用里加上
agentOptions,至少包含model,需要时同时给provider。 - 确认传入的模型名与端点支持的能力匹配,不要随手填一个占位串。
- 跑一轮最小对话验证。预期:不再报变量没值,回复内容与所选模型一致。
- 把这段调用封装成一个函数,避免每个恢复点各写一份。预期:后续新增入口不会漏传。
const agent = await agents.resume({
resumeSessionId,
agentOptions: { model: 'deepseek-chat', provider: 'deepseek-official' },
})
DeepSeek Harness 路径二:从会话头恢复上次的模型选择
如果恢复的是别人的会话或历史任务,正确值不该由调用方猜,而应从会话记录里读最后一次模型选择。 这条路更接近界面恢复的行为。
- 读取会话元数据,找到最后一次模型或提供方选择事件。预期:拿到与当时一致的模型名。
- 用这组值构造
agentOptions,再调用agents.resume。预期:恢复后的 agent 与中断前一致。 - 会话里没有记录时,退回 profile 的默认模型,并在日志里标注这是回退。预期:不会静默用错模型。
- 给这条恢复路径补一条测试:无记录、有记录、记录损坏三种输入。预期:三种都有确定行为。
DeepSeek Harness 路径三:给变量绑定加 fallback
根治方向是在绑定层兜底:options.model 为空时,从会话记录或配置默认值取,而不是让插值抛错。 但要注意,兜底值必须真实,否则提示词会「说谎」。
- 在
model变量的取值函数里增加候选顺序:live options → 会话最后一次选择 → 配置默认值。预期:三层都为空才报错。 provider变量使用同一套候选顺序。预期:不会出现模型有了、提供方没值的半填状态。- 回退发生时记一条明确日志,包含会话 id 与实际取值来源。预期:排查时能看出用的是回退值。
- 补测试:只给 model、只给 provider、都不给三种情况。预期:前两种能继续,第三种给出可读错误。
- 复核提示词里对模型名的使用场景,确认回退值不会误导能力判断。预期:自我介绍与工具选择不出现明显偏差。
如果团队更希望「错得早」,可以在 agents.resume 入口直接校验模型,缺失就抛一条明确的参数错误,而不是让每一轮在提示词组装时失败。 四步:
- 在 resume 入口检查
agentOptions.model是否为空。预期:缺失时立即拒绝。 - 错误信息写清「恢复会话需要 model 或 agentOptions」,不要只提模板变量。预期:调用方能直接定位。
- 保留路径二的自动恢复作为默认行为,只在明确要求严格模式时启用早失败。预期:两种调用方都能接受。
- 把早失败的错误码固定下来,不要复用模板变量错误的文本。预期:调用方能按码分支处理。
改完按三步验证:
- 用不带
agentOptions的 resume 跑一轮。预期:在入口就被拒绝,错误信息点名 model。 - 用带
agentOptions的 resume 跑同一会话。预期:正常完成。 - 检查日志里是否记录了回退值。预期:能看出模型名来自会话头还是配置默认。
DeepSeek Harness 边界与注意
- 只补 model 不补 provider 可能引出下一个错误,两个变量来自同一个 options 对象,要一起考虑。
- 不要在恢复后靠「发一条消息试试」来探测模型是否正确,错误的模型会真实产生费用与上下文。
- 讨论里没有官方修复版本,0.2.1-rc.2 仍可复现;回复提到树内已有可复用的 fallback,方向是复用而不是再造一套。
- 界面恢复与程序化恢复的行为差异是根因的一部分,修完后两条路径应给出同一组默认值。相关模型继承问题另见 子代理模型继承。
常见问题
DeepSeek Harness 不是模板缺变量,而是 resume 没带模型选项。agent loop 在组装提示词时从当前 agent 的 options 里取 model 与 provider 绑定到变量;resume 省略 agentOptions 后这两个字段为空,任何引用 {{model}} 的内置提示词都会在组装阶段抛错,turn 直接以 error 结束。补上 agentOptions 或让恢复逻辑从会话记录取模型即可。
DeepSeek Harness 界面恢复会走一条带默认值的路径,选中模型后 agent 的 options 被填上;程序化 resume 的 agentOptions 是可选的,省略时不会触发任何默认填充。两条路径对「必填」的理解不一致,于是同一个会话在 GUI 能用、在脚本里每轮失败。
DeepSeek Harness 的 model 只是最先撞上的一个。provider 变量同样从 live options 取,如果提示词里引用了它,补完 model 后可能接着报 provider 没值。正确做法是把恢复会话所需的模型与提供方一起带上,而不是只填一个字段。
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
来源
- #10208 — agents.resume 不带 agentOptions 时每轮报 prompt variable {{model}} has no value· deepseek-ai(GitHub Discussions)
- DeepSeek Harness 官方仓库· deepseek-ai(GitHub)