dsh 延时任务

DeepSeek 的 token 计费分峰时和谷时,谷时价格只有峰时的一半。

我的工作大多不紧急,所以一直在把执行时间往谷时挪。

最后用的是 dsh 的自动化任务。

背景

需求是不紧急的活都放到谷时跑。

这些活不着急,晚几个小时没有影响。

官方价目表里,工作日(不含法定节假日)9 点到 12 点、14 点到 18 点是峰时,其余时段是谷时。

价格抄一份在下面,免得哪天链接失效。单位是每百万 token 的元数,2026 年 10 月的数据。表里沿用官方的「空闲」「高峰」,也就是文中的谷时和峰时。

价格 时段 deepseek-flash deepseek-v4-pro
百万 tokens 输入(缓存命中) 空闲时段 0.02 元 0.15 元
高峰时段 0.04 元 0.30 元
百万 tokens 输入(缓存未命中) 空闲时段 1 元 4.5 元
高峰时段 2 元 9.0 元
百万 tokens 输出 空闲时段 4 元 13.5 元
高峰时段 8 元 27.0 元

12 点和下午 6 点刚好是谷时的起点。

手动

最早的方案是手动。

先把提示词写好,到 12 点或者 6 点,自己执行。

执行完去吃饭,回来再看任务进度,决定要不要操作。

这个方案能省钱,但到点人得在。

不在,任务就往后拖。

插件

后来在 GitHub 上找过几个 dsh 的定时插件,比如 dsh-timer、dsh-timer-scheduler、dsh-timer-agent。

star 数最多的是 13 星,另外两个各 1 星,且都一两个月没提交。

star 数和活跃度都不值得信任,所以没装。

自动化任务

10 月 17 日,dsh 升级到 0.2.1-rc.2,新增了自动化任务。

它允许用自然语言描述一个自动化任务或定时任务,比如:

12 点执行某某任务。

现在的方案就是直接在 dsh 里写延时任务。

不用装插件,写一句话就行。

只是这句话得写对。

问题

说「12 点执行某某任务」,dsh 不会等到 12 点才动手。

它当场就开始思考,把要读的文件读了、要查的资料查了,到 12 点只做最后一步汇总。

本意是躲开峰时,结果最花 token 的那段还是在峰时跑的,省钱的效果打对折。

为什么

翻了下实现,到点的提醒是往当前会话里追加一条用户消息(followup),不是新开会话。

投递的内容长这样:

1
2
3
4
5
[SCHEDULE REMINDER]
This is a scheduled message from the user
schedule_id_json: "..."
occurrence_at: "2026-10-22T04:00:00.000Z"
reminder_prompt_json: "建任务时填的 prompt"

所以 12 点那轮的上下文,是从建任务到现在的全部对话。

建任务那轮查过的资料、写过的分析,到点照样在眼前,模型自然接着用,而不是从头来。

再加上「12 点执行」这句话本身没约束当下。

对模型来说这是一个已经交到手上的任务,能提前做的部分它就先做了。这是默认行为,不是 bug。

想少带点旧东西,只能新建一个会话再下任务。投递固定在同一会话,这一点改不了。

怎么写

要把「现在不做」写成硬约束,把「到点做什么」写成一段自包含的原文。

我现在的写法:

1
2
3
4
5
6
7
8
9
12 点执行下面的任务,现在只登记。

本轮禁止读文件、检索、跑命令、做分析、列计划。调用 schedule_create 后立刻结束,只回一句「已登记」。

prompt 字段填下一段,原样:

<到点要做什么、产出什么、有什么约束>

到点执行时按第一次收到这条请求处理,重新收集信息、重新分析。

两个要点。

一是把禁止的动作点名。只说「12 点执行」不够,模型会自己找活干;列出不许做的事,它才停得下来。

二是 prompt 里写需求,不写结论。「调研 xxx 写篇文章」可以;「基于上面整理的材料写篇文章」不行,后者把峰时的产出焊进了任务里,等于绕回原路。

例子

拿查广州天气试的。

这个例子省不了钱,两次调用加起来不到一分钱。但它的结果会过期,早上 9 点查到的气温,到 10 点就没意义了。

这类任务必须真到点才跑,也最容易看出「提前干活」的毛病。

提示词只要几行:

1
2
3
4
5
6
7
8
9
10 点查询广州的天气,现在只登记。

本轮禁止真实查询。调完 schedule_create 就结束。

prompt 字段填:

10 点查询广州的天气

这是定时投递,按第一次收到这条请求处理。

登记那轮只回任务信息,没有温度、没有风力,大意是:

已经登记完成,本轮没有执行真实查询。

定时任务:schedule-b8045b6f…

触发时间:10 月 24 日 10:00

prompt:10 点查询广州的天气

到 10 点,回复里才出现气温、风向、湿度和空气质量,还带了天气网和广州气象台的链接。

顺手给了几个时刻的实况:04:50 的 21℃、08 时的 23℃、11 时预报的 28℃。看得出来是 10 点现查的,不是 9 点攒下来的。

这也顺便说明了 prompt 为什么要写全。这里只有一句「10 点查询广州的天气」,城市、动作、时间都在里面,到点不需要回看前文也知道该干什么。

任务越简单,越容易写成「查一下」。到点模型看着这三个字,只能猜。

验收

创建完看当轮回复,只有任务信息、没有任务内容就算对了;出现气温、提纲、文件读取,就是没拦住。

到点那轮看回复底部的用量条,token 数和缓存命中都在上面,那个数就是账单的基数。

按上面的写法,到点那轮才真的像我刚发了条消息。