
1. 为什么“后台跑完就完”迟早会出问题如果你用 OpenClaw 跑过一段时间的自动化大概率遇到过这种场景早上配了一个 cron job 生成日报中午想起来去看结果翻遍聊天记录也没找到那条消息只能重新问一遍 AI“刚才那个任务跑完了吗”。更糟的是任务其实失败了但你完全不知道直到第二天发现数据没更新才后知后觉。这就是 OpenClaw 早期后台执行体系的核心痛点。exec 命令可以通过 yieldMs 让 shell 在后台运行subagent 能启动独立子会话干活cron 能按时间表周期触发ACP 协议允许外部进程远程调用——这些执行路径各自都能跑但跑完之后没有任何统一的记录。没有执行日志没有状态追踪没有失败回溯渠道。想知道“那个子任务到底成没成”唯一办法是回头翻聊天记录甚至重新问一遍 AI。Background Tasks 体系的出现改变了这个局面。它不是简单加了一条/tasks命令而是建立了一套独立的活动总账Activity Ledger所有脱离主会话的后台执行都会在 SQLite 持久层留下结构化的任务记录配有完整的生命周期管理、审计、维护和通知机制。一句话概括Tasks 是记账本不是调度器。它不负责“什么时候跑”那是 cron 和 heartbeat 的事但负责忠实记录“跑了什么、结果如何、什么时候跑的”。官方文档的定位很精准——Background tasks track work that runs outside your main conversation session它们是记录分离工作发生时间与成功与否的活动账本。这篇文章面向需要构建可靠异步任务系统的开发者我会从 TaskFlow 调度讲到 SQLite 持久化存储拆解任务队列、状态流转与失败重试的完整链路并给出可复制的配置片段和验证步骤。适合谁看如果你正在用 OpenClaw 做自动化或者想理解一个生产级后台任务系统该怎么设计这篇能帮你少踩坑。2. 前置准备TaoToken 接入与 OpenClaw 环境配置在深入 TaskFlow 和 SQLite 之前得先把运行环境搭好。OpenClaw 的模型调用需要接入大模型服务我实测下来用 TaoToken 比较顺手它的 API 兼容主流协议配置起来不折腾。2.1 获取 API Key 与 Base URL首先到 TaoToken 控制台创建一个 API Key。访问 https://taotoken.net/api-keys 登录后新建密钥复制保存好后面配置里要用。注意这个 Key 只在创建时显示一次丢了就得重新生成。Base URL 统一用https://taotoken.net/api不要加任何多余路径。模型 ID 根据你的需求选比如claude-sonnet-4-20250514适合复杂推理任务gpt-4o-mini适合高频轻量调用。具体可用模型列表可以在模型对话页面查看https://taotoken.net/models2.2 OpenClaw 配置文件写入OpenClaw 的模型配置通常放在~/.openclaw/config.json或项目级的openclaw.config.json。下面是一个可复制的最小配置片段路径和字段名保持与官方一致{ models: { default: { provider: openai-compatible, baseUrl: https://taotoken.net/api, apiKey: sk-your-taotoken-key-here, modelId: claude-sonnet-4-20250514, maxTokens: 8192, temperature: 0.3 } }, tasks: { stateDir: ~/.openclaw, sqlitePath: ~/.openclaw/tasks/runs.sqlite, sweeperIntervalMs: 60000, lostGracePeriodMs: 300000, cleanupAfterDays: 7 } }这里几个参数值得说明。sweeperIntervalMs是自动清扫器的执行间隔默认 60 秒负责 reconciliation、cleanup stamping 和 pruning。lostGracePeriodMs是运行时支撑丢失后的宽限期默认 5 分钟超过这个时间才会把任务标记为 lost。cleanupAfterDays控制终端任务记录保留多久默认 7 天后自动清理。如果你用的是 Claude Code 或 Cline 这类工具配置方式略有不同。Claude Code 需要在 settings.json 里指定环境变量{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-your-taotoken-key-here, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }Cline 的 MCP 配置则在cline_mcp_settings.json中{ mcpServers: { openclaw-tasks: { command: openclaw, args: [mcp, serve], env: { OPENCLAW_BASE_URL: https://taotoken.net/api, OPENCLAW_API_KEY: sk-your-taotoken-key-here, OPENCLAW_MODEL: claude-sonnet-4-20250514 } } } }三件套记住Base URL 是https://taotoken.net/apiKey 是你在控制台生成的sk-开头字符串Model ID 按任务复杂度选。这三个字段在任何接入场景里都不能少。2.3 初始化任务存储目录配置写好后确保状态目录存在mkdir -p ~/.openclaw/tasks mkdir -p ~/.openclaw/cronOpenClaw Gateway 启动时会自动在~/.openclaw/tasks/下创建runs.sqlite。如果你想手动初始化表结构可以执行openclaw tasks init --force这个命令会创建任务注册表所需的全部表和索引。正常情况下不需要手动跑Gateway 首次启动会自动完成。3. 可复制配置TaskFlow 与 SQLite 表结构实战理解了前置环境现在进入核心部分。TaskFlow 是任务之上的流程编排引擎SQLite 是持久化底座两者配合才能实现可靠的后台任务系统。3.1 TaskFlow 的两种同步模式配置TaskFlow 解决的是多步骤流程编排问题。比如生成周报需要三步数据收集、汇总分析、报告发送。没有 TaskFlow 时你只能手动创建 3 个 cron job 靠时间差顺序执行极其脆弱或者在 agent prompt 里用自然语言编排缺乏可靠性和可观测性。TaskFlow 提供两种模式。Managed 模式下TaskFlow 完全掌控流程生命周期按步骤创建任务每个步骤完成自动推动流程前进{ flow: { name: weekly-report, mode: managed, steps: [ { id: gather-data, task: { runtime: subagent, prompt: Collect raw metrics from the past 7 days, notifyPolicy: silent } }, { id: generate-report, dependsOn: [gather-data], task: { runtime: subagent, prompt: Analyze collected data and generate summary, notifyPolicy: done_only } }, { id: deliver, dependsOn: [generate-report], task: { runtime: cli, command: openclaw agent --message Send report to Slack, notifyPolicy: done_only } } ] } }Mirrored 模式下TaskFlow 不创建任务只观察外部已独立存在的任务把它们的进展映射到统一流程视图{ flow: { name: market-intel-mirror, mode: mirrored, watchTasks: [ cron:market-intel:gather, cron:market-intel:analyze, cron:market-intel:deliver ] } }Mirrored 模式适合你已经有一组独立 cron job想在不改动它们的前提下获得统一视图的场景。3.2 SQLite 表结构与索引Task Registry 的内存数据结构会同步写入$OPENCLAW_STATE_DIR/tasks/runs.sqlite。Gateway 启动时从 SQLite 加载到内存运行过程中所有状态变更实时写回。核心表结构如下CREATE TABLE IF NOT EXISTS task_runs ( run_id TEXT PRIMARY KEY, task_id TEXT NOT NULL, runtime TEXT NOT NULL CHECK(runtime IN (acp,subagent,cron,cli)), status TEXT NOT NULL CHECK(status IN (queued,running,succeeded,failed,timed_out,cancelled,lost)), owner_id TEXT, session_id TEXT, requester_origin TEXT, notify_policy TEXT NOT NULL DEFAULT done_only CHECK(notify_policy IN (done_only,state_changes,silent)), created_at INTEGER NOT NULL, started_at INTEGER, ended_at INTEGER, cleanup_after INTEGER, error_message TEXT, progress TEXT, revision INTEGER NOT NULL DEFAULT 1 ); CREATE INDEX IF NOT EXISTS idx_task_runs_status ON task_runs(status); CREATE INDEX IF NOT EXISTS idx_task_runs_runtime ON task_runs(runtime); CREATE INDEX IF NOT EXISTS idx_task_runs_cleanup ON task_runs(cleanup_after); CREATE INDEX IF NOT EXISTS idx_task_runs_owner ON task_runs(owner_id);几个字段设计要点。run_id是每次执行的唯一标识task_id是逻辑任务标识一个 task 可以有多次 run。runtime限定四种溯源类型与源码TaskRuntime定义一致。status的 CHECK 约束确保状态机不会写入非法值。cleanup_after是终端任务打上的清理时间戳等于ended_at 7天。revision用于版本追踪Gateway 重启后流程状态自动恢复靠的就是它。TaskFlow 的流程状态单独存一张表CREATE TABLE IF NOT EXISTS task_flows ( flow_id TEXT PRIMARY KEY, name TEXT NOT NULL, mode TEXT NOT NULL CHECK(mode IN (managed,mirrored)), status TEXT NOT NULL, current_step TEXT, revision INTEGER NOT NULL DEFAULT 1, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, cancel_intent INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS task_flow_steps ( flow_id TEXT NOT NULL, step_id TEXT NOT NULL, run_id TEXT, status TEXT NOT NULL, depends_on TEXT, PRIMARY KEY (flow_id, step_id), FOREIGN KEY (flow_id) REFERENCES task_flows(flow_id) );cancel_intent字段很关键。即使 Gateway 重启时还有子任务在跑取消意图也不会丢失恢复后会继续执行取消操作。3.3 状态流转与失败重试配置任务状态机定义了七个状态queued、running、succeeded、failed、timed_out、cancelled、lost。状态流转有严格约束终端状态不可降级。源码task-executor.d.ts中completeTaskRunByRunId的实现规定如果操作者已经取消了任务或者运行时已经记录了更强的终端状态如 failed、timed_out、lost后续的成功信号不会把状态降级回 succeeded。失败重试的配置在任务定义里{ task: { runtime: cron, retry: { maxAttempts: 3, backoffMs: 5000, backoffMultiplier: 2, retryOn: [failed, timed_out] }, timeoutMs: 1800000 } }maxAttempts是最大尝试次数backoffMs是首次重试延迟backoffMultiplier是退避倍数retryOn指定哪些终端状态触发重试。注意 lost 状态默认不重试因为它意味着运行时支撑已经丢失重试也没有意义。4. 验证请求确认任务真的跑通了配置写完不代表就能跑。这一节给出完整的验证步骤从创建任务到确认结果落库每一步都有可复制的命令和预期输出。4.1 创建一个测试任务先用最简单的 CLI 任务验证链路openclaw agent --message List the top 3 files in current directory by size --runtime cli --notify done_only这条命令会创建一个 cli 溯源的任务执行完把结果通知回来。执行后立刻查看任务列表openclaw tasks list --runtime cli --limit 5预期输出类似RUN_ID RUNTIME STATUS CREATED_AT ENDED_AT run_abc123 cli running 2026-05-02 09:00:01 -等几秒再查一次状态应该变成 succeededopenclaw tasks show run_abc123输出会包含完整的生命周期时间戳、状态变更记录和结果摘要。4.2 验证 SQLite 持久化任务跑完后直接查 SQLite 确认数据落库sqlite3 ~/.openclaw/tasks/runs.sqlite SELECT run_id, runtime, status, created_at, ended_at FROM task_runs ORDER BY created_at DESC LIMIT 5;如果能看到刚才那条记录说明持久化正常。再验证 WAL 文件状态ls -lh ~/.openclaw/tasks/runs.sqlite*正常情况下会看到runs.sqlite、runs.sqlite-wal、runs.sqlite-shm三个文件。WAL 文件大小应该可控不会无限膨胀因为系统会周期性执行 TRUNCATE checkpoint。4.3 验证任务中断恢复这是最关键的一步。模拟 Gateway 重启场景确认任务记录不丢失# 1. 启动一个耗时任务 openclaw agent --message Analyze all log files in /var/log and summarize errors --runtime subagent # 2. 记下 run_id openclaw tasks list --runtime subagent --status running # 3. 强制重启 Gateway openclaw gateway restart # 4. 重启后立即查询任务状态 openclaw tasks list --runtime subagent --limit 5预期结果任务记录依然存在状态可能是 running 或 lost。如果子会话在重启后重新建立连接状态会恢复为 running如果子会话彻底消失超过 5 分钟状态会变成 lost。无论哪种情况记录都不会凭空消失。再验证 cron 任务的恢复逻辑# 查看 cron 执行历史 openclaw cron runs --id job-id --limit 20 # 查看对应 task 记录 openclaw tasks list --runtime cron --status failedcron 恢复的优先级是持久化 run log durable run history 兜底的 lost。即使 Gateway 重启导致内存中活跃 job 集合被清空已完成的任务也不会被错误标记为 lost。4.4 验证通知交付任务完成后通知是否送达用审计命令检查openclaw tasks audit --code delivery_failed如果没有输出说明所有通知都成功交付。如果有输出会列出交付失败的任务 ID 和失败原因。直接交付失败时通知会作为系统事件排队写入发起任务的会话等下次 heartbeat 时作为未读消息呈现。5. 常见报错排查401、local proxy failed、reading choices、OAuth配置和验证过程中最容易卡在几个典型报错上。这一节对照真实错误信息给出排查路径。5.1 401 Unauthorized这是最常见的接入错误。完整报错通常长这样Error: 401 Unauthorized {error:{message:Invalid API key provided,type:invalid_request_error}}排查顺序第一确认 API Key 复制完整没有多余空格或换行。第二确认 Base URL 是https://taotoken.net/api不要写成https://taotoken.net/api/v1或带其他路径。第三确认 Key 没有过期或被撤销到控制台重新生成一个试试。第四如果用的是 Claude Code检查ANTHROPIC_API_KEY环境变量是否被其他配置覆盖。修复后重新验证curl -s https://taotoken.net/api/models \ -H Authorization: Bearer sk-your-key | head -20能返回模型列表就说明 Key 和 Base URL 都对了。5.2 local proxy failed这个报错通常出现在网络层Error: local proxy failed: connect ECONNREFUSED 127.0.0.1:7890意思是 OpenClaw 尝试走本地代理但连接被拒绝。排查检查环境变量HTTP_PROXY、HTTPS_PROXY是否指向了一个不存在的端口。如果有取消这些环境变量再试unset HTTP_PROXY HTTPS_PROXY ALL_PROXY openclaw gateway restart如果确实需要网络配置确保代理服务正常运行且端口正确。注意不要在配置里写任何不合规的网络工具名称。5.3 reading choices 报错这个报错说明 API 返回的响应结构不符合预期Error: reading choices: unexpected end of JSON input常见原因有三个。第一Base URL 配错了请求打到了错误的端点返回了 HTML 而不是 JSON。第二模型 ID 不存在API 返回了错误结构。第三响应被截断通常是 maxTokens 设置过大导致超时。排查# 确认模型 ID 有效 curl -s https://taotoken.net/api/models \ -H Authorization: Bearer sk-your-key | grep -o id:[^]* | head -20 # 用最小请求测试 curl -s https://taotoken.net/api/chat/completions \ -H Authorization: Bearer sk-your-key \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-20250514,messages:[{role:user,content:hi}],max_tokens:10}如果 curl 能正常返回说明是 OpenClaw 配置问题如果 curl 也报错说明 Key 或模型 ID 有问题。5.4 OAuth 相关报错如果你用的是需要 OAuth 的接入方式可能遇到Error: OAuth token expired or invalid排查检查 token 是否过期重新走一遍授权流程。如果是 Codex 的 auth.json 配置确认文件路径和字段名正确{ auth: { baseUrl: https://taotoken.net/api, apiKey: sk-your-key, model: claude-sonnet-4-20250514 } }三件套 Base URL、Key、Model ID 一个都不能少。如果用了 CC Switch 切换配置确认切换后的配置指向正确的端点。5.5 任务状态异常排查任务卡在 queued 超过 10 分钟或者 running 超过 30 分钟没结束用审计命令定位openclaw tasks audit --severity error openclaw tasks audit --code stale_queued openclaw tasks audit --code stale_runningstale_queued 说明任务创建了但 agent turn 一直没启动通常是 Gateway 负载过高或队列堵塞。stale_running 说明执行超时检查任务的 timeoutMs 配置是否合理。如果频繁出现 lost通常是底层会话被意外清理或超时配置过短而不是记账系统本身出错。6. 从记账到编排把 TaskFlow 用起来的正确姿势前面把配置、验证、排障都走了一遍最后聊聊怎么把 TaskFlow 真正用起来。很多人配完就放着其实 TaskFlow 的价值在于把离散的任务串成可靠的流程。6.1 分层架构推荐官方推荐的分层架构是这样的Cron 负责定时触发持久化 cron session 积累上下文Lobster 或类似确定性步骤包含审批门TaskFlow 做多步骤追踪与可视化。具体配置openclaw cron add \ --name Market intelligence brief \ --cron 0 7 * * 1-5 \ --tz Asia/Shanghai \ --session session:market-intel \ --message Run the market-intel Lobster workflow. Verify source freshness before summarizing. \ --announce \ --channel slack \ --to channel:C1234567890这条命令创建了一个工作日早 7 点执行的 cron job绑定到session:market-intel命名会话执行完通过 Slack 通知。配合 TaskFlow 的 managed 模式整个流程的每一步都有记录可查。6.2 通知策略选择通知策略直接影响使用体验。简单数据收集用 done_only只关心最终结果多步骤汇总报告也用 done_only等待最终汇总忽略中间噪声长时间训练或推理用 state_changes需要感知进度静默 cron 后台作业用 silent只通过 audit 在失败时发现正在调试的子任务用 state_changes观察每一步状态变化。动态修改通知策略openclaw tasks notify lookup state_changes这条命令可在任务运行期间实时调整。比如某个 subagent 跑太久你想临时看一眼进度就从 done_only 切换成 state_changes。6.3 运维巡检清单建议每周或遇到异常时跑一次openclaw status openclaw tasks audit openclaw tasks maintenance openclaw tasks maintenance --apply openclaw cron status openclaw doctoropenclaw status给快速健康概览检测到 error 级别问题时状态栏直接告警。openclaw tasks audit做任务审计。openclaw tasks maintenance先预览维护动作确认后加--apply执行修复。openclaw doctor做全量诊断包含系统依赖检查。6.4 存储位置与空间管理任务数据文件在$OPENCLAW_STATE_DIR/tasks/runs.sqlite默认 7 天自动清理一般无需手动调参。磁盘空间紧张时运行openclaw tasks maintenance --apply强制立即回收。SQLite WAL 文件会自动 checkpoint不会无限膨胀。cron 相关文件独立于 Tasks 但往往一起排查~/.openclaw/cron/jobs.json是 job 定义建议纳入版本控制~/.openclaw/cron/jobs-state.json是运行时状态不要版本控制。6.5 常见误区纠正最后澄清几个高频误区。/tasks不是聊天命令是 CLI 命令直接在终端执行。不是所有后台执行都产生任务记录只有 ACP、subagent、cron、CLI 四种明确溯源才记账heartbeat、普通聊天、exec 后台进程都不进入 Task Registry。lost 不是 bug是精心设计的兜底状态是 reconciliation 在所有可恢复手段都耗尽后的最终推断。TaskFlow 和 Background Tasks 不是同一层概念TaskFlow 位于 Background Tasks 之上前者是单工作单元的原子记录后者是多步骤流程的编排器。任务完成不一定通知你取决于通知策略silent 策略全程静默即使失败也不推送只能通过 audit 发现。当任务状态变得透明、可审计、可追溯时自动化才真正从黑盒脚本进化为可信赖的基础设施。这套体系的价值不在于多了一条命令而在于让每一次后台执行都有据可查。