Skip to content

定时任务(Cron Jobs)

当前阶段:仅 API + Tool,无独立管理界面

本特性的 REST API、调度器、智能体可调用工具均已实现,但前端管理页面尚未开发。当前可通过:

  • AI 在对话里使用 cronjob_tool 工具创建 / 列出 / 暂停 / 删除(最常见)
  • API 直接 POST /cron(运维 / 集成场景)

待 UI 上线后本页将更新。

让定时任务被一个 应用 + 编排器 自动触发——例如 "每天 9 点生成销售报告"、"每周一 8 点查邮件队列"。每次触发都会以指定的 prompt 调用对应编排器,把结果按渠道推送回原会话或指定接收人。

能调度什么

每个任务绑定到 一个 Application 或一个 Orchestrator(必须二选一)。触发时:

  • prompt 作为 user_message 发给 OrchestratorEngine.execute()
  • 结果按 deliver 字段推送

定时任务 ≠ 通用 LLM 调用

你不能让定时任务"自由发挥",它必须复用一个已经搭好的编排器。这避免了"权限通过定时任务被绕过"。

调度表达式

支持四种写法,按输入形态自动识别:

表达式类型示例
every <时长>intervalevery 30mevery 2hevery 1d
5 字段 cron(数字 + * - , /cron0 9 * * *0 9 * * 1-5
ISO 时间戳(含 TYYYY-MM-DDonce2026-04-20T10:00
裸时长(不含 everyonce(相对)30m2h1d

支持:

  • 标准 5 字段 cron(croniter 校验)
  • 时长单位:m / minh / hrd / day

不支持:

  • 7 字段 / Quartz 风格 / @daily 这类别名 (none found)
  • 秒级精度(最小调度粒度 60 秒)
  • 不同任务用不同时区——timezone 字段虽存在,调度器实际按服务端本地时区计算

最小频率没有强制

代码上没拦截 every 1m,但调度器本身每 60 秒一个 tick——比这更频繁也跑不起来。

投递(deliver)

deliver 字段是逗号分隔的多目标,常用值:

Token含义
origin推回创建任务时所在的会话(默认值)
local仅入库,不推
wecom:<user_id>推到指定企微用户
feishu:<open_id>推到指定飞书用户

failure_deliver 单独配置失败时的接收人——例如"日常推回员工,失败时同时通知运维群"。

执行流程

60 秒 tick


锁住 /tmp/sira/cron/.tick.lock (fcntl.flock)


扫描 next_run_at <= now 的启用任务


for 每条到期任务:
    更新 next_run_at(at-most-once)
    放入 ThreadPoolExecutor (max_workers=4)


释放锁,并发执行

   ▼ 单任务执行:
   ├─ Wake Gate 脚本(可选):跑 python <script>,30s 超时
   │     最后一行 stdout 是 {"wakeAgent": false} → 标记 SILENT 并跳过 LLM
   ├─ 拼 prompt = cron_hint + Script Output + job.prompt
   ├─ OrchestratorEngine.execute(...)(强制 disabled_tools=["cronjob_tool"] 防递归)
   ├─ 全文存到 /tmp/sira/cron/output/<job_id>/<timestamp>.md
   ├─ 检测 SILENT 标记 → 不推送
   └─ 按 deliver 推送到对应渠道

Wake Gate(可选)

某些任务只在特定条件下才有意义——例如"工单队列里有新工单时才汇报"。script 字段允许指定一个本地 Python 脚本预判:

  • 脚本路径必须在 /app/scripts/ 目录下(限定权限)
  • 30 秒超时(环境变量 SIRA_CRON_SCRIPT_TIMEOUT 可调)
  • 最后一行 stdout 解析为 JSON
  • {"wakeAgent": false} → 不调 LLM,标 SILENT 跳过

SILENT 抑制

执行结果中包含 [SILENT] 字符串时,不会推送给员工——适合"AI 判断没必要打扰"。

HITL(人工审批)行为

cron 是无人值守,命中 HITL × Card 中断时默认自动按"批准"续跑——没人在线,工具该跑就跑。

  • 自动 approve 续跑次数上限:SIRA_CRON_HITL_MAX_AUTO_RESUME(默认 10)
  • 超出仍中断 → job 标失败,error 信息为 HITL auto-resume exceeded N attempts(通常意味着编排器配置异常,agent 反复触发新 interrupt)
  • 不会推送 HITL 卡片到任何 channel(cron 没 target_user)

如果你不希望 cron 触发某些高危工具,请在编排器层面别把这些工具放进 tool_ids,而不是依赖 HITL 拒绝——HITL 在 cron 场景被设计成"全放过"。

执行失败 / 重试

情况行为
编排器抛异常consecutive_errors +1,构造 ⚠️ 定时任务「xxx」执行失败... 强制推送
超过 Grace Window 还没跑(机器宕机一段时间)once 任务直接 mark completed;interval/cron 任务 fast-forward next_run_at 跳过这一轮
重试策略(none found) ——失败不会自动重试
自动暂停阈值(none found) ——consecutive_errors 累加但不会自动停

Grace Window = clamp(period/2, 120s, 7200s)

API

所有路径都在 /cron 前缀下,全部要求登录,自动按 organization_id 过滤。

MethodPath用途
POST/cron创建(创建时会跑 prompt-injection scan,命中返回 400)
GET/cron列表(filters: application_id / state / 分页)
GET/cron/{id}详情
PATCH/cron/{id}修改
DELETE/cron/{id}软删除
POST/cron/{id}/run立即触发(设 next_run_at = now
POST/cron/{id}/pause暂停
POST/cron/{id}/resume恢复,重算 next_run_at
GET/cron/{id}/runs运行历史

创建示例

bash
curl -X POST https://your-sira/api/agent-system/cron \
  -H "Authorization: Bearer <token>" \
  -d '{
    "name": "每日工单汇总",
    "schedule_expr": "0 9 * * *",
    "prompt": "查询昨天新增的工单,按优先级排序输出 Markdown",
    "application_id": "<app-uuid>",
    "deliver": "wecom:user_123",
    "failure_deliver": "wecom:ops_group"
  }'

智能体工具:cronjob_tool

平台向 LangChain 编排自动注入一个名为 cronjob_tool 的结构化工具,让 AI 在对话里直接管理定时任务。当 context.cron_enabled 为真且未在 disabled_tools 中时启用。

支持动作:

action参数说明
createname, schedule, prompt, deliver创建任务
listlimit列出当前会话可见的任务
pausejob_id暂停
resumejob_id恢复
removejob_id删除(软)
runsjob_id, limit查看运行历史

会话级隔离

工具按 当前对话上下文 自动过滤可见任务:

  • 群聊:只能看 / 操作 origin_chat_id == 当前群 的任务
  • 单聊:只能看 / 操作 origin_user_id == 当前用户 AND origin_chat_id IS NULL 的任务

避免跨群 / 跨用户泄露任务。

防递归

定时任务自身的执行上下文里 disabled_tools = ["cronjob_tool"]——AI 不能让定时任务再创建定时任务。

数据模型

cron_jobs

记录任务定义和当前状态:schedule_kind (once/interval/cron)、schedule_exprnext_run_atenabledstate (scheduled/paused/completed)、total_runssuccessful_runsconsecutive_errorslast_statuslast_errorlast_delivery_erroroutput_file_path 等。

cron_job_runs

每次执行一条:status (running/ok/error/silent/skipped)、errorstarted_at / finished_at / duration_msdelivery_statusdelivered_to (JSON 数组)、summary (响应前 500 字)、output_file_pathtoken_usage (JSON)。

限制速查

项目
单 tick 并发4(ThreadPoolExecutor
调度粒度60 秒
Wake Gate 超时30 秒(SIRA_CRON_SCRIPT_TIMEOUT
任务 prompt创建 / 修改时强制 prompt-injection 扫描
多副本部署当前是文件锁,单实例安全;多 pod 部署需要后续替换为 Redis 锁
每组织最大任务数(none found)
Prometheus 指标(none found)

可观测性

  • 全文输出:/tmp/sira/cron/output/<job_id>/<timestamp>.md
  • 进程锁:/tmp/sira/cron/.tick.lock
  • 标准日志:失败、grace window fast-forward、锁竞争都打到 logger
  • 数据库:每次执行写 cron_job_runs,可走 GET /cron/{id}/runs 拉取

Apache-2.0 Licensed