- 人工智能
- 大模型
- LLM 网关
- AI Agent
- 即时通讯
【免费下载链接】openclaw-zero-token
OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi
本文基于 OpenClaw 仓库中的open-prose/skills/prose/state/sqlite.md展开,讲解 OpenProse VM 的实验性 SQLite 状态管理模式:如何以单文件state.db持久化多 Agent 工作流的执行位置、绑定值与 Agent 记忆,如何利用sqlite3CLI 完成原子事务写入、结构化查询和断点恢复,以及它与默认的 filesystem、in-context 状态的取舍边界。
一、什么是 OpenProse 的 SQLite 状态模式
OpenProse 是 OpenClaw 提供的"面向 AI 会话的编程语言":.prose程序由一个由 LLM 本身"具身化"(embody)的虚拟机组装执行,每条session语句通过 Task 工具派生真实的子 Agent 会话。详见 prose.md。VM 在执行过程中必须持续跟踪程序计数器(当前语句位置)、变量绑定(bindings)、并行分支状态、循环迭代次数和持久 Agent 记忆——这些统称为"执行状态"(execution state)。
OpenProse 支持四种状态后端,SQLite 是其中标记为experimental(实验性)的一种:
| 模式 | 适用场景 | 状态位置 |
|---|---|---|
| filesystem(默认) | 复杂程序、需要恢复与调试 | .prose/runs/{id}/下的文件 |
| in-context | 简单程序(<30 条语句),无需持久化 | 对话历史(narration 协议) |
| sqlite(实验性) | 可查询状态、原子事务、灵活 schema | .prose/runs/{id}/state.db |
| postgres(实验性) | 真并发写、外部集成、团队协作 | PostgreSQL 数据库 |
上表与 SKILL.md 中 "State Modes" 一节的定义一致。默认加载 prose.md 时会同时加载 filesystem.md;只有当用户显式传入--state=sqlite或说出 "use sqlite state" 时,才加载本文档对应的 sqlite.md。
核心设计原则(原文 Key principle):数据库是一个"灵活的共享工作区"(flexible workspace)——VM 与子 Agent 把它当作协调机制来共享使用,而不是把它当作一份刚性契约。
二、前置条件:sqlite3 CLI 与回退策略
SQLite 模式要求sqlite3命令行工具在 PATH 中可用:
| 平台 | 安装方式 |
|---|---|
| macOS | 预装(Pre-installed) |
| Linux | apt install sqlite3/dnf install sqlite3等包管理器 |
| Windows | winget install SQLite.SQLite或从 sqlite.org 下载 |
回退行为:如果sqlite3不可用,VM 会向用户发出警告,并回退到 filesystem 状态模式,而不是直接报错终止。这与 postgres.md 中psql缺失时"提议回退到 SQLite"的降级链相呼应:postgres → sqlite → filesystem构成了完整的可用性保障。
启用方式
从 SKILL.md 的命令路由表看,启用 SQLite 模式的触发方式是运行时声明:
prose run <file.prose> --state=sqlite # 或直接用自然语言:"use sqlite state"此外,标准库(lib)中的记忆类程序推荐另一种写法--backend sqlite+以获得跨 run 的持久化(如 lib/README.md 中的示例):
prose run lib/user-memory.prose --backend sqlite+ prose run lib/project-memory.prose --backend sqlite+三、数据库位置与 Agent 作用域
3.1 每次 run 一个单文件数据库
数据库位于标准的 run 目录内,一次运行 = 一个.db文件:
.prose/runs/{YYYYMMDD}-{HHMMSS}-{random}/ ├── state.db # SQLite 数据库(本模式的核心文件) ├── program.prose # 运行中程序的副本 └── attachments/ # 存不进数据库的大体积输出(可选)Run ID 格式与 filesystem 模式完全一致:{YYYYMMDD}-{HHMMSS}-{random6},例如.prose/runs/20260116-143052-a7b3c9/state.db。单文件可移植性是 SQLite 相对 filesystem 的关键优势——整个 run 状态可以作为一个文件被复制、归档、传输。
3.2 项目级与用户级 Agent 需要跨 run 存活
execution 作用域的 Agent(默认)记忆存放在每次 run 私有的state.db中,随 run 消亡。但persist: project与persist: user声明的持久 Agent 必须跨越 run 存活,因此使用独立数据库:
# 项目级 .prose/ ├── agents.db # 项目作用域 Agent 记忆(跨 run 存活) └── runs/ └── {id}/ └── state.db # 执行作用域状态(随 run 消亡) # 用户级 ~/.prose/ └── agents.db # 用户作用域 Agent 记忆(跨项目存活)agents与agent_segments表按作用域落位:项目级在.prose/agents.db,用户级在~/.prose/agents.db。VM 在首次使用时初始化这些数据库,并在派生子 Agent 时把正确的数据库路径告知对方。这一设计与 filesystem.md 中"Memory Scoping for Persistent Agents" 表格的作用域划分(execution / project / user / custom)一一对应,只是把目录结构换成了数据库文件。
四、职责分离:VM 与子 Agent 的契约
SQLite 模式沿用 postgres.md "Responsibility Separation" 一节定义的 VM/子 Agent 契约,仅存在 SQLite 特有的三处差异:
- VM 创建的是
state.db文件,而不是 PostgreSQL 的openproseschema; - 子 Agent 的确认消息指向本地数据库路径,例如
.prose/runs/<runId>/state.db; - 清理(cleanup)通常是
VACUUM或直接删除文件,而非 drop schema 对象。
契约的核心不变量是:VM 只跟踪"位置"(location),不持有完整值;子 Agent 直接把输出写入数据库,完成后只返回一条确认消息。文档中给出的 SQLite 风格确认消息示例:
Binding written: research Location: .prose/runs/20260116-143052-a7b3c9/state.db (bindings table, name='research', execution_id=NULL)Binding written: result Location: .prose/runs/20260116-143052-a7b3c9/state.db (bindings table, name='result', execution_id=43) Execution ID: 43与 filesystem 模式"返回文件路径"相比,这里返回的是"表 + 主键条件"形式的定位信息,语义完全等价——VM 的上下文保持精简,从而支持任意大体积的中间值。
五、核心 Schema:最小可用表的完整定义
VM 初始化时创建以下表。原文强调这是最小可用 schema(minimum viable schema),鼓励按需扩展。完整 DDL 如下:
-- Run metadata CREATE TABLE IF NOT EXISTS run ( id TEXT PRIMARY KEY, program_path TEXT, program_source TEXT, started_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), status TEXT DEFAULT 'running', -- running, completed, failed, interrupted state_mode TEXT DEFAULT 'sqlite' ); -- Execution position and history CREATE TABLE IF NOT EXISTS execution ( id INTEGER PRIMARY KEY AUTOINCREMENT, statement_index INTEGER, statement_text TEXT, status TEXT, -- pending, executing, completed, failed, skipped started_at TEXT, completed_at TEXT, error_message TEXT, parent_id INTEGER REFERENCES execution(id), -- for nested blocks metadata TEXT -- JSON for construct-specific data (loop iteration, parallel branch, etc.) ); -- All named values (input, output, let, const) CREATE TABLE IF NOT EXISTS bindings ( name TEXT, execution_id INTEGER, -- NULL for root scope, non-null for block invocations kind TEXT, -- input, output, let, const value TEXT, source_statement TEXT, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), attachment_path TEXT, -- if value is too large, store path to file PRIMARY KEY (name, IFNULL(execution_id, -1)) -- IFNULL handles NULL for root scope ); -- Persistent agent memory CREATE TABLE IF NOT EXISTS agents ( name TEXT PRIMARY KEY, scope TEXT, -- execution, project, user, custom memory TEXT, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); -- Agent invocation history CREATE TABLE IF NOT EXISTS agent_segments ( id INTEGER PRIMARY KEY AUTOINCREMENT, agent_name TEXT REFERENCES agents(name), segment_number INTEGER, timestamp TEXT DEFAULT (datetime('now')), prompt TEXT, summary TEXT, UNIQUE(agent_name, segment_number) ); -- Import registry CREATE TABLE IF NOT EXISTS imports ( alias TEXT PRIMARY KEY, source_url TEXT, fetched_at TEXT, inputs_schema TEXT, -- JSON outputs_schema TEXT -- JSON );5.1 Schema 设计要点逐表解读
run:一次运行的元数据。status取值running / completed / failed / interrupted;state_mode固定记录为'sqlite',用于多模式混用时的溯源。execution:执行位置与历史的"程序计数器表"。parent_id自引用外键构成块调用的调用树(call tree);metadata列以 JSON 文本承载构造特定的数据——循环迭代号、并行分支标识、重试次数都存这里,配合 SQLite 的json_extract/json_set函数使用。bindings:所有命名值(input / output / let / const)。主键(name, IFNULL(execution_id, -1))是一个值得注意的技巧:SQLite 不允许主键含 NULL,因此用IFNULL把根作用域的 NULL 映射为-1,从而让"同名绑定在不同执行帧中互不冲突"。agents+agent_segments:持久 Agent 的"当前记忆快照 + 历史分段"两表结构,对应 filesystem 模式中memory.md+{name}-NNN.md的文件对。imports:导入注册表,记录use语句拉取的程序别名、来源 URL 与输入/输出 schema(JSON 文本)。
5.2 Schema 约定
原文列出的七条书写约定:
| 约定 | 规则 |
|---|---|
| 时间戳 | ISO 8601 格式,默认datetime('now') |
| JSON 字段 | 结构化数据以 JSON 文本存于metadata、*_schema列 |
| 大值 | 绑定值超过约 100KB 时写入attachments/{name}.md,库中只存路径 |
| 扩展表 | 一律加x_前缀(如x_metrics、x_audit_log) |
| 匿名绑定 | 未显式捕获的session "..."自动生成anon_001、anon_002等名称 |
| 导入绑定 | 以导入别名为前缀限定作用域:research.findings、research.sources |
| 作用域绑定 | 用execution_id列——根作用域为 NULL,块内调用为非空 |
5.3 作用域解析查询(Scope Resolution)
对于递归块(recursive block),绑定值被限定在各自的执行帧内。变量解析需要沿调用栈向上回溯。原文给出的完整递归 CTE 版本:
-- Find binding 'result' starting from execution_id 43 WITH RECURSIVE scope_chain AS ( -- Start with current execution SELECT id, parent_id FROM execution WHERE id = 43 UNION ALL -- Walk up to parent SELECT e.id, e.parent_id FROM execution e JOIN scope_chain s ON e.id = s.parent_id ) SELECT b.* FROM bindings b LEFT JOIN scope_chain s ON b.execution_id = s.id WHERE b.name = 'result' AND (b.execution_id IN (SELECT id FROM scope_chain) OR b.execution_id IS NULL) ORDER BY CASE WHEN b.execution_id IS NULL THEN 1 ELSE 0 END, -- Prefer scoped over root s.id DESC NULLS LAST -- Prefer deeper (more local) scope LIMIT 1;如果已知作用域链,可以用更简单的直查版本:
-- Direct lookup: check current scope, then parent, then root SELECT * FROM bindings WHERE name = 'result' AND (execution_id = 43 OR execution_id = 42 OR execution_id IS NULL) ORDER BY execution_id DESC NULLS LAST LIMIT 1;这一逻辑与 filesystem.md 中"先查{name}__{current_execution_id}.md,再逐级向上,最后落到根作用域{name}.md,首个命中者胜出"的文件版作用域解析完全同构——只是把文件查找换成了 SQL 排序。
六、数据库交互:VM 侧与子 Agent 侧
VM 与子 Agent 都通过sqlite3CLI 交互,写权按表划分(VM 独占execution,子 Agent 写bindings/agents/agent_segments)。
6.1 VM 侧的典型操作
# Initialize database sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db "CREATE TABLE IF NOT EXISTS..." # Update execution position sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db " INSERT INTO execution (statement_index, statement_text, status, started_at) VALUES (3, 'session \"Research AI safety\"', 'executing', datetime('now')) " # Read a binding sqlite3 -json .prose/runs/20260116-143052-a7b3c9/state.db " SELECT value FROM bindings WHERE name = 'research' " # Check parallel branch status sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db " SELECT statement_text, status FROM execution WHERE json_extract(metadata, '$.parallel_id') = 'p1' "注意sqlite3 -json输出选项——VM 读取绑定值时以 JSON 格式取回,便于直接嵌入后续派生提示(prompt)。
6.2 子 Agent 侧的输出写入
VM 在派生 session 时把数据库路径和写入指令一并下发。根作用域(块调用之外)的写入指令:
Your output database is: .prose/runs/20260116-143052-a7b3c9/state.db When complete, write your output: sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db " INSERT OR REPLACE INTO bindings (name, execution_id, kind, value, source_statement, updated_at) VALUES ( 'research', NULL, -- root scope 'let', 'AI safety research covers alignment, robustness...', 'let research = session: researcher', datetime('now') ) "块调用内部(必须携带execution_id):
Execution scope: execution_id: 43 block: process depth: 3 Your output database is: .prose/runs/20260116-143052-a7b3c9/state.db When complete, write your output: sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db " INSERT OR REPLACE INTO bindings (name, execution_id, kind, value, source_statement, updated_at) VALUES ( 'result', 43, -- scoped to this execution 'let', 'Processed chunk into 3 sub-parts...', 'let result = session \"Process chunk\"', datetime('now') ) "execution 作用域的持久 Agent(如resume: captain):
Your memory is in the database: .prose/runs/20260116-143052-a7b3c9/state.db Read your current state: sqlite3 -json .prose/runs/20260116-143052-a7b3c9/state.db "SELECT memory FROM agents WHERE name = 'captain'" Update when done: sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db "UPDATE agents SET memory = '...', updated_at = datetime('now') WHERE name = 'captain'" Record this segment: sqlite3 .prose/runs/20260116-143052-a7b3c9/state.db "INSERT INTO agent_segments (agent_name, segment_number, prompt, summary) VALUES ('captain', 3, '...', '...')"项目级 Agent 改写.prose/agents.db,用户级 Agent 改写~/.prose/agents.db——表结构相同,只是数据库文件不同。
七、主线程的上下文保留:数据库不能替代叙述
原文用 "This is critical" 强调:数据库负责持久化与协调,但 VM 仍必须在主对话中叙述(narrate)关键事件。SQLite 模式下的叙述示例:
[Position] Statement 3: let research = session: researcher Spawning session, will write to state.db [Task tool call] [Success] Session complete, binding written to DB [Binding] research = <stored in state.db>叙述标记([Position]、[Success]、[Binding]等)与 in-context.md 中的 narration 协议共用一套词汇,只是[Binding]的内容从"值"变成了"库内位置"。两者的分工:
| 目的 | 机制 |
|---|---|
| 工作记忆(Working memory) | 对话叙述——VM 不重新查询即可"记住"的内容 |
| 持久状态(Durable state) | SQLite 数据库——跨越上下文限制,支持恢复 |
| 子 Agent 协调 | SQLite 数据库——共享访问点 |
| 调试 / 检查 | SQLite 数据库——可查询的历史 |
一句话概括:叙述是 VM 对执行的"心理模型",数据库才是恢复与检查的"事实来源"(source of truth)。
八、并行执行的分支追踪
对parallel块,VM 用execution.metadata的 JSON 字段追踪分支,且只有 VM 写execution表(子 Agent 只写bindings)。完整流程 SQL:
-- VM marks parallel start INSERT INTO execution (statement_index, statement_text, status, metadata) VALUES (5, 'parallel:', 'executing', '{"parallel_id": "p1", "strategy": "all", "branches": ["a", "b", "c"]}'); -- VM creates execution record for each branch INSERT INTO execution (statement_index, statement_text, status, parent_id, metadata) VALUES (6, 'a = session "Task A"', 'executing', 5, '{"parallel_id": "p1", "branch": "a"}'); -- Subagent writes its output to bindings table (see "From Subagents" section) -- Task tool signals completion to VM via substrate -- VM marks branch complete after Task returns UPDATE execution SET status = 'completed', completed_at = datetime('now') WHERE json_extract(metadata, '$.parallel_id') = 'p1' AND json_extract(metadata, '$.branch') = 'a'; -- VM checks if all branches complete SELECT COUNT(*) as pending FROM execution WHERE json_extract(metadata, '$.parallel_id') = 'p1' AND status != 'completed';要点:分支记录通过parent_id挂到parallel:语句的记录之下;完成判定不是靠 Task 工具的返回值直接写库,而是 Task 返回后由 VM 用json_extract按parallel_id + branch定位并更新;pending计数归零即 join 完成。
九、循环、错误处理与大输出
9.1 循环追踪
循环的迭代状态同样存于metadataJSON,用json_set原地更新:
-- Loop metadata tracks iteration state INSERT INTO execution (statement_index, statement_text, status, metadata) VALUES (10, 'loop until **analysis complete** (max: 5):', 'executing', '{"loop_id": "l1", "max_iterations": 5, "current_iteration": 0, "condition": "**analysis complete**"}'); -- Update iteration UPDATE execution SET metadata = json_set(metadata, '$.current_iteration', 2), updated_at = datetime('now') WHERE json_extract(metadata, '$.loop_id') = 'l1';9.2 错误处理
-- Record failure UPDATE execution SET status = 'failed', error_message = 'Connection timeout after 30s', completed_at = datetime('now') WHERE id = 15; -- Track retry attempts in metadata UPDATE execution SET metadata = json_set(metadata, '$.retry_attempt', 2, '$.max_retries', 3) WHERE id = 15;失败状态落在status/error_message,重试计数落在metadata——与 filesystem.md 中# <-- RETRYING (attempt 2/3)这类注释标注是同一语义的两种载体。
9.3 大输出(>100KB)走附件
当绑定值过大不便存库时,遵循三步:内容写入attachments/{binding_name}.md→ 路径存入attachment_path列 →value保留摘要或留空:
INSERT INTO bindings (name, kind, value, attachment_path, source_statement) VALUES ( 'full_report', 'let', 'Full analysis report (847KB) - see attachment', 'attachments/full_report.md', 'let full_report = session "Generate comprehensive report"' );十、断点恢复:用查询代替重读
恢复被中断的 run 时,VM 依次执行以下查询(定位当前位置 → 取回全部已完成的绑定 → 取回 Agent 记忆 → 检查并行块状态):
-- Find current position SELECT statement_index, statement_text, status FROM execution WHERE status = 'executing' ORDER BY id DESC LIMIT 1; -- Get all completed bindings SELECT name, kind, value, attachment_path FROM bindings; -- Get agent memory states SELECT name, memory FROM agents; -- Check parallel block status SELECT json_extract(metadata, '$.branch') as branch, status FROM execution WHERE json_extract(metadata, '$.parallel_id') IS NOT NULL AND parent_id = (SELECT id FROM execution WHERE status = 'executing' AND statement_text LIKE 'parallel:%');对比三种模式的恢复路径:filesystem 模式靠"读state.md+ 加载bindings/目录",in-context 模式靠"重读对话",SQLite 模式则靠"查询数据库"——这也是原文对比表中 "Resumption" 一行的内容。
十一、Schema 弹性:数据库就是你的工作区
与 filesystem 模式"文件结构即状态"的严格约定不同,SQLite 模式刻意不那么具规定性(less prescriptive):核心 schema 只是起点,鼓励:
- 给现有表加列(如
ALTER TABLE bindings ADD COLUMN token_count INTEGER); - 建
x_前缀的扩展表; - 存自定义指标(耗时、token 数、模型信息);
- 针对自己的查询模式建索引;
- 用 JSON 函数处理半结构化数据。
文档给出的扩展示例:
-- Custom metrics table CREATE TABLE x_metrics ( execution_id INTEGER REFERENCES execution(id), metric_name TEXT, metric_value REAL, recorded_at TEXT DEFAULT (datetime('now')) ); -- Add custom column ALTER TABLE bindings ADD COLUMN token_count INTEGER; -- Create index for common query CREATE INDEX idx_execution_status ON execution(status);十二、与其他状态模式的对比
原文对比表的完整内容(本文在 postgres.md 中核实到其同构表格,四模式版本多一列 PostgreSQL):
| 维度 | filesystem | in-context | sqlite |
|---|---|---|---|
| 状态位置 | .prose/runs/{id}/文件 | 对话历史 | .prose/runs/{id}/state.db |
| 可查询性 | 通过读文件 | 否 | 是(SQL) |
| 原子更新 | 否 | 不适用 | 是(事务) |
| Schema 灵活性 | 刚性的文件结构 | 不适用 | 灵活(可加表/列) |
| 恢复方式 | 读state.md | 重读对话 | 查询数据库 |
| 复杂度上限 | 高 | 低(<30 条语句) | 高 |
| 依赖 | 无 | 无 | sqlite3 CLI |
| 状态 | Stable | Stable | Experimental |
选择建议(综合 SKILL.md 与 in-context.md 的量化阈值):语句数 <30、并行分支 <5、无深度嵌套的小程序用 in-context;需要恢复/调试/大输出的复杂程序用默认 filesystem 或想要 SQL 查询能力时用 sqlite;当出现 >5 个并发写分支、外部看板查询或团队共享需求时,再考虑 postgres.md 描述的 PostgreSQL 模式。
十三、总结
SQLite 状态管理的设计契约可以浓缩为七点:
- 每次 run 使用单个数据库文件(
state.db),跨 run 的 Agent 记忆另存agents.db/~/.prose/agents.db; - VM 与子 Agent 之间有清晰的职责分离:VM 独占
execution表并只跟踪位置,子 Agent 直写自己的bindings; - 支持结构化查询检查状态(含递归 CTE 的作用域解析);
- 借助事务提供原子更新;
- 允许灵活的 schema 演进(
x_扩展表、加列、加索引); - 依赖sqlite3 CLI,缺失时回退 filesystem 模式并告警;
- 状态为experimental——预期会有变化。
核心契约一句话:VM 负责管理执行流并派生子 Agent,子 Agent 把自己的输出直接写进数据库;"发生的事都被记录,被记录的事都可以被查询"(what happens is recorded, and what is recorded can be queried)。
如需在 OpenClaw 中启用 OpenProse 能力,可参考 open-prose/README.md:在插件配置中启用open-prose并重启 Gateway 即可使用/prose命令与prose run ... --state=sqlite流程。
- 人工智能
- 大模型
- LLM 网关
- AI Agent
- 即时通讯
【免费下载链接】openclaw-zero-token
OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi
相关推荐
openJiuwen Checkpointer 检查点机制详解:Agent 与 Workflow 的状态持久化与中断恢复
openJiuwen Checkpointer 检查点机制详解:Agent 与 Workflow 的状态持久化与中断恢复 openJiuwen agent co
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习OpenClaw OpenProse 文件系统状态管理:用 .prose/ 目录实现可检查、可恢复的多 Agent 执行状态
OpenClaw OpenProse 文件系统状态管理:用 .prose/ 目录实现可检查、可恢复的多 Agent 执行状态 本文围绕 OpenClaw 仓库中
人工智能大模型LLM 网关AI Agent即时通讯SyncTV WebRTC通话功能详解:实现高质量语音通信
SyncTV WebRTC通话功能详解:实现高质量语音通信 SyncTV是一款集同步观看、影院模式、直播和视频功能于一体的开源项目,其内置的WebRTC通话功能
后端音视频直播
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考