mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-30 13:01:06 +03:00
Docs: update zh-CN translations and pipeline
What: - update zh-CN glossary, TM, and translator prompt - regenerate zh-CN docs and apply targeted fixes - add zh-CN AGENTS pipeline guidance Why: - address terminology/spacing feedback from #6995 Tests: - pnpm build && pnpm check && pnpm test
This commit is contained in:
@@ -4,147 +4,143 @@ read_when:
|
||||
summary: 智能体循环生命周期、流和等待语义
|
||||
title: 智能体循环
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:03Z"
|
||||
generated_at: "2026-02-03T10:05:11Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 0775b96eb3451e137297661a1095eaefb2bafeebb5f78123174a46290e18b014
|
||||
source_path: concepts/agent-loop.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 智能体循环(OpenClaw)
|
||||
|
||||
智能体循环是智能体的一次完整"真实"运行:接收 → 上下文组装 → 模型推理 →
|
||||
工具执行 → 流式回复 → 持久化。它是将消息转化为操作和最终回复的权威路径,同时保持会话状态的一致性。
|
||||
智能体循环是智能体的完整"真实"运行:接收 → 上下文组装 → 模型推理 → 工具执行 → 流式回复 → 持久化。这是将消息转化为操作和最终回复的权威路径,同时保持会话状态的一致性。
|
||||
|
||||
在 OpenClaw 中,循环是每个会话的单次序列化运行,在模型思考、调用工具和流式输出时发出生命周期和流事件。本文档解释了这个完整循环是如何端到端连接的。
|
||||
在 OpenClaw 中,循环是每个会话的单次序列化运行,在模型思考、调用工具和流式输出时发出生命周期和流事件。本文档解释了这个真实循环是如何端到端连接的。
|
||||
|
||||
## 入口点
|
||||
|
||||
- Gateway网关 RPC:`agent` 和 `agent.wait`。
|
||||
- Gateway 网关 RPC:`agent` 和 `agent.wait`。
|
||||
- CLI:`agent` 命令。
|
||||
|
||||
## 工作原理(高层概述)
|
||||
## 工作原理(高层次)
|
||||
|
||||
1. `agent` RPC 验证参数,解析会话(sessionKey/sessionId),持久化会话元数据,立即返回 `{ runId, acceptedAt }`。
|
||||
2. `agentCommand` 运行智能体:
|
||||
- 解析模型 + thinking/verbose 默认值
|
||||
- 解析模型 + 思考/详细模式默认值
|
||||
- 加载 Skills 快照
|
||||
- 调用 `runEmbeddedPiAgent`(pi-agent-core 运行时)
|
||||
- 如果嵌入式循环未发出**生命周期 end/error** 事件,则补充发出
|
||||
- 如果嵌入式循环未发出**生命周期结束/错误**事件,则发出该事件
|
||||
3. `runEmbeddedPiAgent`:
|
||||
- 通过每会话 + 全局队列序列化运行
|
||||
- 解析模型 + 认证配置并构建 pi 会话
|
||||
- 解析模型 + 认证配置文件并构建 pi 会话
|
||||
- 订阅 pi 事件并流式传输助手/工具增量
|
||||
- 强制执行超时 -> 超时则中止运行
|
||||
- 返回载荷 + 使用量元数据
|
||||
- 返回有效负载 + 使用元数据
|
||||
4. `subscribeEmbeddedPiSession` 将 pi-agent-core 事件桥接到 OpenClaw `agent` 流:
|
||||
- 工具事件 => `stream: "tool"`
|
||||
- 助手增量 => `stream: "assistant"`
|
||||
- 生命周期事件 => `stream: "lifecycle"`(`phase: "start" | "end" | "error"`)
|
||||
5. `agent.wait` 使用 `waitForAgentJob`:
|
||||
- 等待 `runId` 的**生命周期 end/error**
|
||||
- 等待 `runId` 的**生命周期结束/错误**
|
||||
- 返回 `{ status: ok|error|timeout, startedAt, endedAt, error? }`
|
||||
|
||||
## 队列 + 并发
|
||||
|
||||
- 运行按会话键(会话通道)序列化,并可选择通过全局通道进行。
|
||||
- 运行按会话键(会话通道)序列化,可选择通过全局通道。
|
||||
- 这可以防止工具/会话竞争并保持会话历史的一致性。
|
||||
- 消息渠道可以选择队列模式(collect/steer/followup)来供给此通道系统。
|
||||
参见[命令队列](/concepts/queue)。
|
||||
- 消息渠道可以选择队列模式(collect/steer/followup)来馈送此通道系统。参见[命令队列](/concepts/queue)。
|
||||
|
||||
## 会话 + 工作区准备
|
||||
|
||||
- 工作区被解析并创建;沙箱运行可能会重定向到沙箱工作区根目录。
|
||||
- Skills 被加载(或从快照中复用)并注入到环境和提示中。
|
||||
- 引导/上下文文件被解析并注入到系统提示报告中。
|
||||
- 解析并创建工作区;沙箱隔离运行可能会重定向到沙箱工作区根目录。
|
||||
- 加载 Skills(或从快照中复用)并注入到环境和提示中。
|
||||
- 解析引导/上下文文件并注入到系统提示报告中。
|
||||
- 获取会话写锁;在流式传输之前打开并准备 `SessionManager`。
|
||||
|
||||
## 提示组装 + 系统提示
|
||||
|
||||
- 系统提示由 OpenClaw 的基础提示、Skills 提示、引导上下文和每次运行的覆盖项构建而成。
|
||||
- 强制执行模型特定的限制和压缩预留令牌数。
|
||||
- 参见[系统提示](/concepts/system-prompt)了解模型所看到的内容。
|
||||
- 系统提示由 OpenClaw 的基础提示、Skills 提示、引导上下文和每次运行的覆盖构建。
|
||||
- 强制执行模型特定的限制和压缩保留令牌。
|
||||
- 参见[系统提示](/concepts/system-prompt)了解模型看到的内容。
|
||||
|
||||
## 钩子点(可拦截的位置)
|
||||
## 钩子点(可以拦截的位置)
|
||||
|
||||
OpenClaw 有两个钩子系统:
|
||||
|
||||
- **内部钩子**(Gateway网关钩子):用于命令和生命周期事件的事件驱动脚本。
|
||||
- **插件钩子**:智能体/工具生命周期和 Gateway网关管道中的扩展点。
|
||||
- **内部钩子**(Gateway 网关钩子):用于命令和生命周期事件的事件驱动脚本。
|
||||
- **插件钩子**:智能体/工具生命周期和 Gateway 网关管道中的扩展点。
|
||||
|
||||
### 内部钩子(Gateway网关钩子)
|
||||
### 内部钩子(Gateway 网关钩子)
|
||||
|
||||
- **`agent:bootstrap`**:在系统提示最终确定之前构建引导文件时运行。
|
||||
用于添加/移除引导上下文文件。
|
||||
- **`agent:bootstrap`**:在系统提示最终确定之前构建引导文件时运行。用于添加/删除引导上下文文件。
|
||||
- **命令钩子**:`/new`、`/reset`、`/stop` 和其他命令事件(参见钩子文档)。
|
||||
|
||||
参见[钩子](/hooks)了解设置和示例。
|
||||
|
||||
### 插件钩子(智能体 + Gateway网关生命周期)
|
||||
### 插件钩子(智能体 + Gateway 网关生命周期)
|
||||
|
||||
这些在智能体循环或 Gateway网关管道内运行:
|
||||
这些在智能体循环或 Gateway 网关管道内运行:
|
||||
|
||||
- **`before_agent_start`**:在运行开始前注入上下文或覆盖系统提示。
|
||||
- **`agent_end`**:在完成后检查最终消息列表和运行元数据。
|
||||
- **`before_compaction` / `after_compaction`**:观察或标注压缩周期。
|
||||
- **`before_compaction` / `after_compaction`**:观察或注释压缩周期。
|
||||
- **`before_tool_call` / `after_tool_call`**:拦截工具参数/结果。
|
||||
- **`tool_result_persist`**:在工具结果写入会话记录之前同步转换工具结果。
|
||||
- **`tool_result_persist`**:在工具结果写入会话记录之前同步转换它们。
|
||||
- **`message_received` / `message_sending` / `message_sent`**:入站 + 出站消息钩子。
|
||||
- **`session_start` / `session_end`**:会话生命周期边界。
|
||||
- **`gateway_start` / `gateway_stop`**:Gateway网关生命周期事件。
|
||||
- **`gateway_start` / `gateway_stop`**:Gateway 网关生命周期事件。
|
||||
|
||||
参见[插件](/plugin#plugin-hooks)了解钩子 API 和注册详情。
|
||||
|
||||
## 流式传输 + 部分回复
|
||||
|
||||
- 助手增量从 pi-agent-core 流式传输并作为 `assistant` 事件发出。
|
||||
- 块流式传输可以在 `text_end` 或 `message_end` 时发出部分回复。
|
||||
- 分块流式传输可以在 `text_end` 或 `message_end` 时发出部分回复。
|
||||
- 推理流式传输可以作为单独的流或作为块回复发出。
|
||||
- 参见[流式传输](/concepts/streaming)了解分块和块回复行为。
|
||||
|
||||
## 工具执行 + 消息工具
|
||||
|
||||
- 工具的 start/update/end 事件在 `tool` 流上发出。
|
||||
- 工具结果在记录/发出之前会针对大小和图片载荷进行清理。
|
||||
- 消息工具的发送会被跟踪,以抑制重复的助手确认。
|
||||
- 工具开始/更新/结束事件在 `tool` 流上发出。
|
||||
- 工具结果在记录/发出之前会对大小和图像有效负载进行清理。
|
||||
- 消息工具发送会被跟踪以抑制重复的助手确认。
|
||||
|
||||
## 回复整形 + 抑制
|
||||
|
||||
- 最终载荷由以下内容组装:
|
||||
- 助手文本(及可选的推理内容)
|
||||
- 内联工具摘要(当 verbose + 允许时)
|
||||
- 最终有效负载由以下内容组装:
|
||||
- 助手文本(和可选的推理)
|
||||
- 内联工具摘要(当详细模式 + 允许时)
|
||||
- 模型出错时的助手错误文本
|
||||
- `NO_REPLY` 被视为静默令牌,从传出载荷中过滤。
|
||||
- 消息工具的重复项从最终载荷列表中移除。
|
||||
- 如果没有可渲染的载荷且工具出错,则发出回退的工具错误回复
|
||||
(除非消息工具已发送了用户可见的回复)。
|
||||
- `NO_REPLY` 被视为静默令牌,从出站有效负载中过滤。
|
||||
- 消息工具重复项从最终有效负载列表中移除。
|
||||
- 如果没有剩余可渲染的有效负载且工具出错,则发出回退工具错误回复(除非消息工具已经发送了用户可见的回复)。
|
||||
|
||||
## 压缩 + 重试
|
||||
|
||||
- 自动压缩发出 `compaction` 流事件,并可能触发重试。
|
||||
- 重试时,内存缓冲区和工具摘要会被重置以避免重复输出。
|
||||
- 自动压缩发出 `compaction` 流事件,可以触发重试。
|
||||
- 重试时,内存缓冲区和工具摘要会重置以避免重复输出。
|
||||
- 参见[压缩](/concepts/compaction)了解压缩管道。
|
||||
|
||||
## 事件流(当前)
|
||||
|
||||
- `lifecycle`:由 `subscribeEmbeddedPiSession` 发出(以及作为 `agentCommand` 的回退)
|
||||
- `assistant`:来自 pi-agent-core 的流式增量
|
||||
- `tool`:来自 pi-agent-core 的流式工具事件
|
||||
- `assistant`:从 pi-agent-core 流式传输的增量
|
||||
- `tool`:从 pi-agent-core 流式传输的工具事件
|
||||
|
||||
## 聊天渠道处理
|
||||
|
||||
- 助手增量被缓冲为聊天 `delta` 消息。
|
||||
- 在**生命周期 end/error** 时发出聊天 `final`。
|
||||
- 助手增量被缓冲到聊天 `delta` 消息中。
|
||||
- 在**生命周期结束/错误**时发出聊天 `final`。
|
||||
|
||||
## 超时
|
||||
|
||||
- `agent.wait` 默认值:30 秒(仅等待阶段)。`timeoutMs` 参数可覆盖。
|
||||
- `agent.wait` 默认:30 秒(仅等待)。`timeoutMs` 参数可覆盖。
|
||||
- 智能体运行时:`agents.defaults.timeoutSeconds` 默认 600 秒;在 `runEmbeddedPiAgent` 中止计时器中强制执行。
|
||||
|
||||
## 可能提前结束的情况
|
||||
|
||||
- 智能体超时(中止)
|
||||
- AbortSignal(取消)
|
||||
- Gateway网关断开连接或 RPC 超时
|
||||
- `agent.wait` 超时(仅等待阶段,不会停止智能体)
|
||||
- Gateway 网关断开连接或 RPC 超时
|
||||
- `agent.wait` 超时(仅等待,不会停止智能体)
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要解释智能体工作区或其文件布局
|
||||
- 你想要备份或迁移智能体工作区
|
||||
- 你想备份或迁移智能体工作区
|
||||
summary: 智能体工作区:位置、布局和备份策略
|
||||
title: 智能体工作区
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:05Z"
|
||||
generated_at: "2026-02-03T07:45:49Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 84c550fd89b5f2474aeae586795485fd29d36effbb462f13342b31540fc18b82
|
||||
source_path: concepts/agent-workspace.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 智能体工作区
|
||||
|
||||
工作区是智能体的主目录。它是文件工具和工作区上下文使用的唯一工作目录。请将其保持私密,并视为记忆来对待。
|
||||
工作区是智能体的家。它是文件工具和工作区上下文使用的唯一工作目录。请保持其私密性并将其视为记忆。
|
||||
|
||||
它与 `~/.openclaw/` 是分开的,后者存储配置、凭据和会话。
|
||||
这与 `~/.openclaw/` 是分开的,后者存储配置、凭证和会话。
|
||||
|
||||
**重要提示:** 工作区是**默认工作目录**,而非硬性沙箱。工具会基于工作区解析相对路径,但绝对路径仍然可以访问主机上的其他位置,除非启用了沙箱。如果你需要隔离,请使用 [`agents.defaults.sandbox`](/gateway/sandboxing)(和/或按智能体的沙箱配置)。当启用沙箱且 `workspaceAccess` 不是 `"rw"` 时,工具在 `~/.openclaw/sandboxes` 下的沙箱工作区中运行,而非你的主机工作区。
|
||||
**重要:** 工作区是**默认 cwd**,而不是硬性沙箱。工具会根据工作区解析相对路径,但绝对路径仍然可以访问主机上的其他位置,除非启用了沙箱隔离。如果你需要隔离,请使用
|
||||
[`agents.defaults.sandbox`](/gateway/sandboxing)(和/或每智能体沙箱配置)。
|
||||
当启用沙箱隔离且 `workspaceAccess` 不是 `"rw"` 时,工具在 `~/.openclaw/sandboxes` 下的沙箱工作区内操作,而不是你的主机工作区。
|
||||
|
||||
## 默认位置
|
||||
|
||||
- 默认:`~/.openclaw/workspace`
|
||||
- 如果设置了 `OPENCLAW_PROFILE` 且不是 `"default"`,则默认变为
|
||||
- 如果设置了 `OPENCLAW_PROFILE` 且不是 `"default"`,默认值变为
|
||||
`~/.openclaw/workspace-<profile>`。
|
||||
- 在 `~/.openclaw/openclaw.json` 中覆盖:
|
||||
|
||||
@@ -36,9 +38,9 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
`openclaw onboard`、`openclaw configure` 或 `openclaw setup` 将创建工作区,并在引导文件缺失时生成它们。
|
||||
`openclaw onboard`、`openclaw configure` 或 `openclaw setup` 将创建工作区并在缺失时填充引导文件。
|
||||
|
||||
如果你已经自行管理工作区文件,可以禁用引导文件创建:
|
||||
如果你已经自己管理工作区文件,可以禁用引导文件创建:
|
||||
|
||||
```json5
|
||||
{ agent: { skipBootstrap: true } }
|
||||
@@ -46,20 +48,21 @@ x-i18n:
|
||||
|
||||
## 额外的工作区文件夹
|
||||
|
||||
较旧的安装可能创建了 `~/openclaw`。保留多个工作区目录可能会导致认证或状态不一致的困惑,因为同一时间只有一个工作区处于活跃状态。
|
||||
旧版安装可能创建了 `~/openclaw`。保留多个工作区目录可能会导致混乱的认证或状态漂移,因为同一时间只有一个工作区是活动的。
|
||||
|
||||
**建议:** 保持单一活跃工作区。如果你不再使用额外的文件夹,请将其归档或移至回收站(例如 `trash ~/openclaw`)。如果你有意保留多个工作区,请确保 `agents.defaults.workspace` 指向活跃的那个。
|
||||
**建议:** 保持单个活动工作区。如果你不再使用额外的文件夹,请归档或移至废纸篓(例如 `trash ~/openclaw`)。
|
||||
如果你有意保留多个工作区,请确保 `agents.defaults.workspace` 指向活动的那个。
|
||||
|
||||
`openclaw doctor` 在检测到额外工作区目录时会发出警告。
|
||||
|
||||
## 工作区文件映射(每个文件的含义)
|
||||
|
||||
以下是 OpenClaw 在工作区中期望的标准文件:
|
||||
这些是 OpenClaw 在工作区内期望的标准文件:
|
||||
|
||||
- `AGENTS.md`
|
||||
- 智能体的操作指令以及它应如何使用记忆。
|
||||
- 智能体的操作指南以及它应该如何使用记忆。
|
||||
- 在每个会话开始时加载。
|
||||
- 适合放置规则、优先级和"行为方式"的详细说明。
|
||||
- 适合放置规则、优先级和"如何行为"的详细信息。
|
||||
|
||||
- `SOUL.md`
|
||||
- 人设、语气和边界。
|
||||
@@ -74,61 +77,62 @@ x-i18n:
|
||||
- 在引导仪式期间创建/更新。
|
||||
|
||||
- `TOOLS.md`
|
||||
- 关于本地工具和约定的说明。
|
||||
- 关于你本地工具和惯例的注释。
|
||||
- 不控制工具可用性;仅作为指导。
|
||||
|
||||
- `HEARTBEAT.md`
|
||||
- 可选的心跳运行小清单。
|
||||
- 保持简短以避免消耗令牌。
|
||||
- 可选的心跳运行小型检查清单。
|
||||
- 保持简短以避免 token 消耗。
|
||||
|
||||
- `BOOT.md`
|
||||
- 可选的启动清单,在启用内部钩子时于 Gateway网关重启时执行。
|
||||
- 保持简短;使用消息工具进行外发。
|
||||
- 当启用内部 hooks 时,在 Gateway 网关重启时执行的可选启动检查清单。
|
||||
- 保持简短;使用 message 工具进行出站发送。
|
||||
|
||||
- `BOOTSTRAP.md`
|
||||
- 一次性首次运行仪式。
|
||||
- 仅为全新工作区创建。
|
||||
- 仪式完成后请删除它。
|
||||
- 仪式完成后删除它。
|
||||
|
||||
- `memory/YYYY-MM-DD.md`
|
||||
- 每日记忆日志(每天一个文件)。
|
||||
- 建议在会话开始时读取今天和昨天的内容。
|
||||
- 建议在会话开始时读取今天 + 昨天的内容。
|
||||
|
||||
- `MEMORY.md`(可选)
|
||||
- 精选的长期记忆。
|
||||
- 仅在主要的私人会话中加载(不在共享/群组上下文中)。
|
||||
- 仅在主私密会话中加载(不在共享/群组上下文中)。
|
||||
|
||||
参见[记忆](/concepts/memory)了解工作流程和自动记忆刷写。
|
||||
参见 [记忆](/concepts/memory) 了解工作流程和自动记忆刷新。
|
||||
|
||||
- `skills/`(可选)
|
||||
- 工作区特定的 Skills。
|
||||
- 名称冲突时覆盖托管/内置 Skills。
|
||||
- 当名称冲突时覆盖托管/捆绑的 Skills。
|
||||
|
||||
- `canvas/`(可选)
|
||||
- 用于节点显示的 Canvas UI 文件(例如 `canvas/index.html`)。
|
||||
|
||||
如果任何引导文件缺失,OpenClaw 会在会话中注入"文件缺失"标记并继续运行。大型引导文件在注入时会被截断;可通过 `agents.defaults.bootstrapMaxChars`(默认:20000)调整限制。`openclaw setup` 可以重新创建缺失的默认文件而不会覆盖现有文件。
|
||||
如果任何引导文件缺失,OpenClaw 会在会话中注入"缺失文件"标记并继续。大型引导文件在注入时会被截断;使用 `agents.defaults.bootstrapMaxChars` 调整限制(默认:20000)。
|
||||
`openclaw setup` 可以重新创建缺失的默认值而不覆盖现有文件。
|
||||
|
||||
## 不在工作区中的内容
|
||||
## 工作区中不包含的内容
|
||||
|
||||
以下内容位于 `~/.openclaw/` 下,**不应**提交到工作区仓库:
|
||||
这些位于 `~/.openclaw/` 下,不应提交到工作区仓库:
|
||||
|
||||
- `~/.openclaw/openclaw.json`(配置)
|
||||
- `~/.openclaw/credentials/`(OAuth 令牌、API 密钥)
|
||||
- `~/.openclaw/agents/<agentId>/sessions/`(会话记录和元数据)
|
||||
- `~/.openclaw/skills/`(托管 Skills)
|
||||
- `~/.openclaw/credentials/`(OAuth token、API 密钥)
|
||||
- `~/.openclaw/agents/<agentId>/sessions/`(会话记录 + 元数据)
|
||||
- `~/.openclaw/skills/`(托管的 Skills)
|
||||
|
||||
如果你需要迁移会话或配置,请单独复制它们并将其排除在版本控制之外。
|
||||
如果你需要迁移会话或配置,请单独复制它们并将它们排除在版本控制之外。
|
||||
|
||||
## Git 备份(推荐,私有)
|
||||
|
||||
将工作区视为私有记忆。将其放入一个**私有** git 仓库中,以便备份和恢复。
|
||||
将工作区视为私密记忆。将其放入**私有** git 仓库以便备份和恢复。
|
||||
|
||||
在 Gateway网关运行的机器上执行以下步骤(工作区就在那里)。
|
||||
在运行 Gateway 网关的机器上执行这些步骤(工作区就在那里)。
|
||||
|
||||
### 1) 初始化仓库
|
||||
### 1)初始化仓库
|
||||
|
||||
如果安装了 git,全新的工作区会自动初始化。如果此工作区尚未是仓库,请运行:
|
||||
如果安装了 git,全新工作区会自动初始化。如果此工作区还不是仓库,请运行:
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace
|
||||
@@ -137,14 +141,14 @@ git add AGENTS.md SOUL.md TOOLS.md IDENTITY.md USER.md HEARTBEAT.md memory/
|
||||
git commit -m "Add agent workspace"
|
||||
```
|
||||
|
||||
### 2) 添加私有远程仓库(新手友好选项)
|
||||
### 2)添加私有远程(适合初学者的选项)
|
||||
|
||||
选项 A:GitHub 网页界面
|
||||
|
||||
1. 在 GitHub 上创建一个新的**私有**仓库。
|
||||
2. 不要使用 README 初始化(避免合并冲突)。
|
||||
1. 在 GitHub 上创建新的**私有**仓库。
|
||||
2. 不要用 README 初始化(避免合并冲突)。
|
||||
3. 复制 HTTPS 远程 URL。
|
||||
4. 添加远程仓库并推送:
|
||||
4. 添加远程并推送:
|
||||
|
||||
```bash
|
||||
git branch -M main
|
||||
@@ -152,7 +156,7 @@ git remote add origin <https-url>
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
选项 B:GitHub CLI (`gh`)
|
||||
选项 B:GitHub CLI(`gh`)
|
||||
|
||||
```bash
|
||||
gh auth login
|
||||
@@ -161,10 +165,10 @@ gh repo create openclaw-workspace --private --source . --remote origin --push
|
||||
|
||||
选项 C:GitLab 网页界面
|
||||
|
||||
1. 在 GitLab 上创建一个新的**私有**仓库。
|
||||
2. 不要使用 README 初始化(避免合并冲突)。
|
||||
1. 在 GitLab 上创建新的**私有**仓库。
|
||||
2. 不要用 README 初始化(避免合并冲突)。
|
||||
3. 复制 HTTPS 远程 URL。
|
||||
4. 添加远程仓库并推送:
|
||||
4. 添加远程并推送:
|
||||
|
||||
```bash
|
||||
git branch -M main
|
||||
@@ -172,7 +176,7 @@ git remote add origin <https-url>
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
### 3) 持续更新
|
||||
### 3)持续更新
|
||||
|
||||
```bash
|
||||
git status
|
||||
@@ -185,13 +189,13 @@ git push
|
||||
|
||||
即使在私有仓库中,也要避免在工作区中存储密钥:
|
||||
|
||||
- API 密钥、OAuth 令牌、密码或私有凭据。
|
||||
- API 密钥、OAuth token、密码或私有凭证。
|
||||
- `~/.openclaw/` 下的任何内容。
|
||||
- 聊天记录的原始转储或敏感附件。
|
||||
- 聊天的原始转储或敏感附件。
|
||||
|
||||
如果你必须存储敏感引用,请使用占位符并将真实密钥保存在其他地方(密码管理器、环境变量或 `~/.openclaw/`)。
|
||||
如果你必须存储敏感引用,请使用占位符并将真正的密钥保存在其他地方(密码管理器、环境变量或 `~/.openclaw/`)。
|
||||
|
||||
建议的 `.gitignore` 起始内容:
|
||||
建议的 `.gitignore` 起始配置:
|
||||
|
||||
```gitignore
|
||||
.DS_Store
|
||||
@@ -203,12 +207,13 @@ git push
|
||||
|
||||
## 将工作区迁移到新机器
|
||||
|
||||
1. 将仓库克隆到目标路径(默认 `~/.openclaw/workspace`)。
|
||||
1. 将仓库克隆到所需路径(默认 `~/.openclaw/workspace`)。
|
||||
2. 在 `~/.openclaw/openclaw.json` 中将 `agents.defaults.workspace` 设置为该路径。
|
||||
3. 运行 `openclaw setup --workspace <path>` 以生成任何缺失的文件。
|
||||
4. 如果你需要会话记录,请从旧机器单独复制 `~/.openclaw/agents/<agentId>/sessions/`。
|
||||
3. 运行 `openclaw setup --workspace <path>` 来填充任何缺失的文件。
|
||||
4. 如果你需要会话,请单独从旧机器复制 `~/.openclaw/agents/<agentId>/sessions/`。
|
||||
|
||||
## 高级说明
|
||||
## 高级注意事项
|
||||
|
||||
- 多智能体路由可以为每个智能体使用不同的工作区。参见[渠道路由](/concepts/channel-routing)了解路由配置。
|
||||
- 如果启用了 `agents.defaults.sandbox`,非主要会话可以使用 `agents.defaults.sandbox.workspaceRoot` 下的按会话沙箱工作区。
|
||||
- 多智能体路由可以为每个智能体使用不同的工作区。参见
|
||||
[渠道路由](/concepts/channel-routing) 了解路由配置。
|
||||
- 如果启用了 `agents.defaults.sandbox`,非主会话可以在 `agents.defaults.sandbox.workspaceRoot` 下使用每会话沙箱工作区。
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
---
|
||||
read_when:
|
||||
- 更改智能体运行时、工作区引导或会话行为
|
||||
- 更改智能体运行时、工作区引导或会话行为时
|
||||
summary: 智能体运行时(嵌入式 pi-mono)、工作区契约和会话引导
|
||||
title: 智能体运行时
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:02Z"
|
||||
generated_at: "2026-02-03T10:04:53Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 04b4e0bc6345d2afd9a93186e5d7a02a393ec97da2244e531703cb6a1c182325
|
||||
source_path: concepts/agent.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 智能体运行时 🤖
|
||||
|
||||
OpenClaw 运行一个源自 **pi-mono** 的单一嵌入式智能体运行时。
|
||||
OpenClaw 运行一个源自 **pi-mono** 的嵌入式智能体运行时。
|
||||
|
||||
## 工作区(必需)
|
||||
|
||||
OpenClaw 使用单一智能体工作区目录(`agents.defaults.workspace`)作为智能体工具和上下文的**唯一**工作目录(`cwd`)。
|
||||
OpenClaw 使用单一智能体工作区目录(`agents.defaults.workspace`)作为智能体**唯一**的工作目录(`cwd`),用于工具和上下文。
|
||||
|
||||
建议:使用 `openclaw setup` 创建 `~/.openclaw/openclaw.json`(如果不存在)并初始化工作区文件。
|
||||
建议:使用 `openclaw setup` 在缺失时创建 `~/.openclaw/openclaw.json` 并初始化工作区文件。
|
||||
|
||||
完整的工作区布局 + 备份指南:[智能体工作区](/concepts/agent-workspace)
|
||||
完整工作区布局 + 备份指南:[智能体工作区](/concepts/agent-workspace)
|
||||
|
||||
如果启用了 `agents.defaults.sandbox`,非主会话可以使用 `agents.defaults.sandbox.workspaceRoot` 下的按会话工作区覆盖此设置(参见 [Gateway网关配置](/gateway/configuration))。
|
||||
如果启用了 `agents.defaults.sandbox`,非主会话可以在 `agents.defaults.sandbox.workspaceRoot` 下使用按会话隔离的工作区覆盖此设置(参见 [Gateway 网关配置](/gateway/configuration))。
|
||||
|
||||
## 引导文件(注入)
|
||||
|
||||
在 `agents.defaults.workspace` 内,OpenClaw 期望这些用户可编辑的文件:
|
||||
在 `agents.defaults.workspace` 内,OpenClaw 期望以下用户可编辑的文件:
|
||||
|
||||
- `AGENTS.md` — 操作指令 + "记忆"
|
||||
- `SOUL.md` — 角色设定、边界、语气
|
||||
- `SOUL.md` — 人设、边界、语气
|
||||
- `TOOLS.md` — 用户维护的工具说明(例如 `imsg`、`sag`、约定)
|
||||
- `BOOTSTRAP.md` — 一次性首次运行仪式(完成后删除)
|
||||
- `IDENTITY.md` — 智能体名称/风格/表情符号
|
||||
- `USER.md` — 用户档案 + 首选称呼
|
||||
- `IDENTITY.md` — 智能体名称/风格/表情
|
||||
- `USER.md` — 用户档案 + 偏好称呼
|
||||
|
||||
在新会话的第一轮对话中,OpenClaw 会将这些文件的内容直接注入到智能体上下文中。
|
||||
在新会话的第一轮,OpenClaw 将这些文件的内容直接注入智能体上下文。
|
||||
|
||||
空白文件会被跳过。大文件会被裁剪和截断并附带标记,以保持提示词精简(阅读完整文件以获取全部内容)。
|
||||
空文件会被跳过。大文件会被修剪和截断并添加标记,以保持提示词精简(阅读文件获取完整内容)。
|
||||
|
||||
如果文件缺失,OpenClaw 会注入一行"文件缺失"标记(`openclaw setup` 会创建安全的默认模板)。
|
||||
如果文件缺失,OpenClaw 会注入一行"文件缺失"标记(`openclaw setup` 将创建安全的默认模板)。
|
||||
|
||||
`BOOTSTRAP.md` 仅在**全新工作区**(没有其他引导文件存在)时创建。如果你在完成仪式后删除了它,后续重启时不会重新创建。
|
||||
`BOOTSTRAP.md` 仅在**全新工作区**(没有其他引导文件存在)时创建。如果你在完成仪式后删除它,后续重启不应重新创建。
|
||||
|
||||
要完全禁用引导文件创建(用于预填充的工作区),请设置:
|
||||
要完全禁用引导文件创建(用于预置工作区),请设置:
|
||||
|
||||
```json5
|
||||
{ agent: { skipBootstrap: true } }
|
||||
@@ -53,24 +53,24 @@ OpenClaw 使用单一智能体工作区目录(`agents.defaults.workspace`)
|
||||
|
||||
## 内置工具
|
||||
|
||||
核心工具(read/exec/edit/write 及相关系统工具)始终可用,受工具策略约束。`apply_patch` 是可选的,由 `tools.exec.applyPatch` 控制。`TOOLS.md` **不**控制哪些工具存在;它是关于你希望如何使用这些工具的指导。
|
||||
核心工具(read/exec/edit/write 及相关系统工具)始终可用,受工具策略约束。`apply_patch` 是可选的,由 `tools.exec.applyPatch` 控制。`TOOLS.md` **不**控制哪些工具存在;它是关于*你*希望如何使用它们的指导。
|
||||
|
||||
## Skills
|
||||
|
||||
OpenClaw 从三个位置加载 Skills(名称冲突时工作区优先):
|
||||
|
||||
- 内置(随安装包附带)
|
||||
- 内置(随安装包提供)
|
||||
- 托管/本地:`~/.openclaw/skills`
|
||||
- 工作区:`<workspace>/skills`
|
||||
|
||||
Skills 可以通过配置/环境变量进行控制(参见 [Gateway网关配置](/gateway/configuration) 中的 `skills`)。
|
||||
Skills 可通过配置/环境变量控制(参见 [Gateway 网关配置](/gateway/configuration) 中的 `skills`)。
|
||||
|
||||
## pi-mono 集成
|
||||
|
||||
OpenClaw 复用了 pi-mono 代码库的部分内容(模型/工具),但**会话管理、发现和工具连接由 OpenClaw 负责**。
|
||||
OpenClaw 复用 pi-mono 代码库的部分内容(模型/工具),但**会话管理、设备发现和工具连接由 OpenClaw 负责**。
|
||||
|
||||
- 没有 pi-coding 智能体运行时。
|
||||
- 不会读取 `~/.pi/agent` 或 `<workspace>/.pi` 设置。
|
||||
- 无 pi-coding 智能体运行时。
|
||||
- 不读取 `~/.pi/agent` 或 `<workspace>/.pi` 设置。
|
||||
|
||||
## 会话
|
||||
|
||||
@@ -79,30 +79,31 @@ OpenClaw 复用了 pi-mono 代码库的部分内容(模型/工具),但**
|
||||
- `~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl`
|
||||
|
||||
会话 ID 是稳定的,由 OpenClaw 选择。
|
||||
**不会**读取旧版 Pi/Tau 会话文件夹。
|
||||
**不**读取旧版 Pi/Tau 会话文件夹。
|
||||
|
||||
## 流式传输期间的引导
|
||||
## 流式传输中的引导
|
||||
|
||||
当队列模式为 `steer` 时,入站消息会被注入到当前运行中。队列在**每次工具调用后**检查;如果存在排队消息,当前助手消息的剩余工具调用会被跳过(工具结果显示"Skipped due to queued user message."错误),然后在下一个助手响应之前注入排队的用户消息。
|
||||
当队列模式为 `steer` 时,入站消息会注入当前运行。
|
||||
队列在**每次工具调用后**检查;如果存在排队消息,当前助手消息的剩余工具调用将被跳过(工具结果显示错误"Skipped due to queued user message."),然后在下一个助手响应前注入排队的用户消息。
|
||||
|
||||
当队列模式为 `followup` 或 `collect` 时,入站消息会被保留直到当前轮次结束,然后使用排队的负载开始新的智能体轮次。参见[队列](/concepts/queue)了解模式 + 防抖/上限行为。
|
||||
当队列模式为 `followup` 或 `collect` 时,入站消息会保留到当前轮次结束,然后使用排队的载荷开始新的智能体轮次。参见 [队列](/concepts/queue) 了解模式 + 防抖/上限行为。
|
||||
|
||||
块流式传输在完成的助手块完成后立即发送;**默认关闭**(`agents.defaults.blockStreamingDefault: "off"`)。
|
||||
分块流式传输在助手块完成后立即发送;默认为**关闭**(`agents.defaults.blockStreamingDefault: "off"`)。
|
||||
通过 `agents.defaults.blockStreamingBreak` 调整边界(`text_end` 与 `message_end`;默认为 text_end)。
|
||||
使用 `agents.defaults.blockStreamingChunk` 控制软块分块(默认 800–1200 字符;优先段落分隔,其次换行;最后是句子)。
|
||||
使用 `agents.defaults.blockStreamingCoalesce` 合并流式块,以减少单行刷屏(基于空闲的合并后再发送)。非 Telegram 渠道需要显式设置 `*.blockStreaming: true` 以启用块回复。
|
||||
详细的工具摘要在工具启动时发出(无防抖);Control UI 在可用时通过智能体事件流式传输工具输出。
|
||||
使用 `agents.defaults.blockStreamingCoalesce` 合并流式块以减少单行刷屏(发送前基于空闲的合并)。非 Telegram 渠道需要显式设置 `*.blockStreaming: true` 以启用分块回复。
|
||||
工具启动时发出详细工具摘要(无防抖);Control UI 在可用时通过智能体事件流式传输工具输出。
|
||||
更多详情:[流式传输 + 分块](/concepts/streaming)。
|
||||
|
||||
## 模型引用
|
||||
|
||||
配置中的模型引用(例如 `agents.defaults.model` 和 `agents.defaults.models`)通过**第一个** `/` 进行拆分解析。
|
||||
配置中的模型引用(例如 `agents.defaults.model` 和 `agents.defaults.models`)通过在**第一个** `/` 处分割来解析。
|
||||
|
||||
- 配置模型时使用 `provider/model` 格式。
|
||||
- 如果模型 ID 本身包含 `/`(OpenRouter 风格),请包含提供商前缀(示例:`openrouter/moonshotai/kimi-k2`)。
|
||||
- 如果省略提供商,OpenClaw 会将输入视为别名或**默认提供商**的模型(仅在模型 ID 中没有 `/` 时有效)。
|
||||
- 配置模型时使用 `provider/model`。
|
||||
- 如果模型 ID 本身包含 `/`(OpenRouter 风格),请包含提供商前缀(例如:`openrouter/moonshotai/kimi-k2`)。
|
||||
- 如果省略提供商,OpenClaw 将输入视为别名或**默认提供商**的模型(仅在模型 ID 中没有 `/` 时有效)。
|
||||
|
||||
## 配置(最小化)
|
||||
## 配置(最小)
|
||||
|
||||
至少需要设置:
|
||||
|
||||
|
||||
@@ -1,123 +1,123 @@
|
||||
---
|
||||
read_when:
|
||||
- 处理 Gateway网关协议、客户端或传输层相关工作时
|
||||
summary: WebSocket Gateway网关架构、组件和客户端流程
|
||||
title: Gateway网关架构
|
||||
- 正在开发 Gateway 网关协议、客户端或传输层
|
||||
summary: WebSocket Gateway 网关架构、组件和客户端流程
|
||||
title: Gateway 网关架构
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:27Z"
|
||||
generated_at: "2026-02-03T07:45:55Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: c636d5d8a5e628067432b30671466309e3d630b106d413f1708765bf2a9399a1
|
||||
source_path: concepts/architecture.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Gateway网关架构
|
||||
# Gateway 网关架构
|
||||
|
||||
最后更新:2026-01-22
|
||||
|
||||
## 概述
|
||||
|
||||
- 单个长生命周期的 **Gateway网关** 管理所有消息接入面(通过 Baileys 接入 WhatsApp、通过 grammY 接入 Telegram、Slack、Discord、Signal、iMessage、WebChat)。
|
||||
- 控制面客户端(macOS 应用、CLI、Web UI、自动化)通过 **WebSocket** 连接到 Gateway网关,使用配置的绑定地址(默认 `127.0.0.1:18789`)。
|
||||
- **节点**(macOS/iOS/Android/无头模式)也通过 **WebSocket** 连接,但声明 `role: node` 并显式指定能力/命令。
|
||||
- 每台主机一个 Gateway网关;它是唯一打开 WhatsApp 会话的位置。
|
||||
- **画布主机**(默认 `18793`)提供智能体可编辑的 HTML 和 A2UI。
|
||||
- 单个长期运行的 **Gateway 网关**拥有所有消息平台(通过 Baileys 的 WhatsApp、通过 grammY 的 Telegram、Slack、Discord、Signal、iMessage、WebChat)。
|
||||
- 控制平面客户端(macOS 应用、CLI、Web 界面、自动化)通过配置的绑定主机(默认 `127.0.0.1:18789`)上的 **WebSocket** 连接到 Gateway 网关。
|
||||
- **节点**(macOS/iOS/Android/无头设备)也通过 **WebSocket** 连接,但声明 `role: node` 并带有明确的能力/命令。
|
||||
- 每台主机一个 Gateway 网关;它是唯一打开 WhatsApp 会话的位置。
|
||||
- **canvas 主机**(默认 `18793`)提供智能体可编辑的 HTML 和 A2UI。
|
||||
|
||||
## 组件和流程
|
||||
|
||||
### Gateway网关(守护进程)
|
||||
### Gateway 网关(守护进程)
|
||||
|
||||
- 维护提供商连接。
|
||||
- 暴露类型化的 WS API(请求、响应、服务端推送事件)。
|
||||
- 暴露类型化的 WS API(请求、响应、服务器推送事件)。
|
||||
- 根据 JSON Schema 验证入站帧。
|
||||
- 发出 `agent`、`chat`、`presence`、`health`、`heartbeat`、`cron` 等事件。
|
||||
- 发出事件如 `agent`、`chat`、`presence`、`health`、`heartbeat`、`cron`。
|
||||
|
||||
### 客户端(Mac 应用 / CLI / Web 管理端)
|
||||
### 客户端(mac 应用 / CLI / web 管理)
|
||||
|
||||
- 每个客户端一个 WS 连接。
|
||||
- 发送请求(`health`、`status`、`send`、`agent`、`system-presence`)。
|
||||
- 订阅事件(`tick`、`agent`、`presence`、`shutdown`)。
|
||||
|
||||
### 节点(macOS / iOS / Android / 无头模式)
|
||||
### 节点(macOS / iOS / Android / 无头设备)
|
||||
|
||||
- 连接到**同一个 WS 服务器**,声明 `role: node`。
|
||||
- 在 `connect` 中提供设备身份;配对是**基于设备**的(角色为 `node`),审批信息存储在设备配对存储中。
|
||||
- 暴露 `canvas.*`、`camera.*`、`screen.record`、`location.get` 等命令。
|
||||
- 以 `role: node` 连接到**同一个 WS 服务器**。
|
||||
- 在 `connect` 中提供设备身份;配对是**基于设备**的(角色为 `node`),批准存储在设备配对存储中。
|
||||
- 暴露命令如 `canvas.*`、`camera.*`、`screen.record`、`location.get`。
|
||||
|
||||
协议详情:
|
||||
|
||||
- [Gateway网关协议](/gateway/protocol)
|
||||
- [Gateway 网关协议](/gateway/protocol)
|
||||
|
||||
### WebChat
|
||||
|
||||
- 静态 UI,使用 Gateway网关 WS API 获取聊天历史和发送消息。
|
||||
- 静态界面,使用 Gateway 网关 WS API 获取聊天历史和发送消息。
|
||||
- 在远程设置中,通过与其他客户端相同的 SSH/Tailscale 隧道连接。
|
||||
|
||||
## 连接生命周期(单个客户端)
|
||||
|
||||
```
|
||||
Client Gateway网关
|
||||
Client Gateway
|
||||
| |
|
||||
|---- req:connect -------->|
|
||||
|<------ res (ok) ---------| (或 res error + 关闭)
|
||||
| (payload=hello-ok 携带快照:presence + health)
|
||||
|<------ res (ok) ---------| (or res error + close)
|
||||
| (payload=hello-ok carries snapshot: presence + health)
|
||||
| |
|
||||
|<------ event:presence ---|
|
||||
|<------ event:tick -------|
|
||||
| |
|
||||
|------- req:agent ------->|
|
||||
|<------ res:agent --------| (确认:{runId,status:"accepted"})
|
||||
|<------ event:agent ------| (流式传输)
|
||||
|<------ res:agent --------| (最终:{runId,status,summary})
|
||||
|<------ res:agent --------| (ack: {runId,status:"accepted"})
|
||||
|<------ event:agent ------| (streaming)
|
||||
|<------ res:agent --------| (final: {runId,status,summary})
|
||||
| |
|
||||
```
|
||||
|
||||
## 线路协议(摘要)
|
||||
|
||||
- 传输层:WebSocket,文本帧携带 JSON 负载。
|
||||
- 传输:WebSocket,带 JSON 载荷的文本帧。
|
||||
- 第一帧**必须**是 `connect`。
|
||||
- 握手完成后:
|
||||
- 握手后:
|
||||
- 请求:`{type:"req", id, method, params}` → `{type:"res", id, ok, payload|error}`
|
||||
- 事件:`{type:"event", event, payload, seq?, stateVersion?}`
|
||||
- 如果设置了 `OPENCLAW_GATEWAY_TOKEN`(或 `--token`),`connect.params.auth.token` 必须匹配,否则套接字将关闭。
|
||||
- 有副作用的方法(`send`、`agent`)需要幂等性键以安全重试;服务器维护一个短期去重缓存。
|
||||
- 如果设置了 `OPENCLAW_GATEWAY_TOKEN`(或 `--token`),`connect.params.auth.token` 必须匹配,否则套接字关闭。
|
||||
- 有副作用的方法(`send`、`agent`)需要幂等键以安全重试;服务器保持短期去重缓存。
|
||||
- 节点必须在 `connect` 中包含 `role: "node"` 以及能力/命令/权限。
|
||||
|
||||
## 配对与本地信任
|
||||
## 配对 + 本地信任
|
||||
|
||||
- 所有 WS 客户端(操作员 + 节点)在 `connect` 时包含**设备身份**。
|
||||
- 新设备 ID 需要配对审批;Gateway网关颁发**设备令牌**用于后续连接。
|
||||
- **本地**连接(local loopback 或 Gateway网关主机自身的 tailnet 地址)可以自动审批,以保持同主机用户体验的流畅性。
|
||||
- **非本地**连接必须对 `connect.challenge` nonce 签名,并需要显式审批。
|
||||
- Gateway网关认证(`gateway.auth.*`)仍适用于**所有**连接,无论本地还是远程。
|
||||
- 新设备 ID 需要配对批准;Gateway 网关为后续连接颁发**设备令牌**。
|
||||
- **本地**连接(loopback 或 Gateway 网关主机自身的 tailnet 地址)可以自动批准以保持同主机用户体验流畅。
|
||||
- **非本地**连接必须签名 `connect.challenge` nonce 并需要明确批准。
|
||||
- Gateway 网关认证(`gateway.auth.*`)仍适用于**所有**连接,无论本地还是远程。
|
||||
|
||||
详情:[Gateway网关协议](/gateway/protocol)、[配对](/start/pairing)、[安全](/gateway/security)。
|
||||
详情:[Gateway 网关协议](/gateway/protocol)、[配对](/start/pairing)、[安全](/gateway/security)。
|
||||
|
||||
## 协议类型定义与代码生成
|
||||
## 协议类型和代码生成
|
||||
|
||||
- TypeBox schema 定义协议。
|
||||
- 从这些 schema 生成 JSON Schema。
|
||||
- TypeBox 模式定义协议。
|
||||
- 从这些模式生成 JSON Schema。
|
||||
- 从 JSON Schema 生成 Swift 模型。
|
||||
|
||||
## 远程访问
|
||||
|
||||
- 推荐方式:Tailscale 或 VPN。
|
||||
- 备选方式:SSH 隧道
|
||||
- 推荐:Tailscale 或 VPN。
|
||||
- 替代方案:SSH 隧道
|
||||
```bash
|
||||
ssh -N -L 18789:127.0.0.1:18789 user@host
|
||||
```
|
||||
- 相同的握手 + 认证令牌适用于隧道连接。
|
||||
- 远程设置中可为 WS 启用 TLS + 可选的证书固定。
|
||||
- 远程设置中可以为 WS 启用 TLS + 可选的证书固定。
|
||||
|
||||
## 运维概览
|
||||
## 操作快照
|
||||
|
||||
- 启动:`openclaw gateway`(前台运行,日志输出到 stdout)。
|
||||
- 健康检查:通过 WS 发送 `health`(也包含在 `hello-ok` 中)。
|
||||
- 监管:使用 launchd/systemd 实现自动重启。
|
||||
- 启动:`openclaw gateway`(前台,日志输出到 stdout)。
|
||||
- 健康检查:通过 WS 的 `health`(也包含在 `hello-ok` 中)。
|
||||
- 监控:使用 launchd/systemd 自动重启。
|
||||
|
||||
## 不变量
|
||||
|
||||
- 每台主机恰好一个 Gateway网关控制单个 Baileys 会话。
|
||||
- 握手是强制的;任何非 JSON 或非 connect 的首帧将导致硬关闭。
|
||||
- 每台主机恰好一个 Gateway 网关控制单个 Baileys 会话。
|
||||
- 握手是强制的;任何非 JSON 或非 connect 的第一帧都会导致硬关闭。
|
||||
- 事件不会重放;客户端必须在出现间隙时刷新。
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想了解 OpenClaw 中"上下文"的含义
|
||||
- 你在调试为什么模型"知道"某些内容(或遗忘了它)
|
||||
- 你在调试为什么模型"知道"某些内容(或忘记了)
|
||||
- 你想减少上下文开销(/context、/status、/compact)
|
||||
summary: 上下文:模型看到的内容、如何构建以及如何检查
|
||||
title: 上下文
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:35Z"
|
||||
generated_at: "2026-02-03T07:46:15Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: b32867b9b93254fdd1077d0d97c203cabfdba3330bb941693c83feba8e5db0cc
|
||||
source_path: concepts/context.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 上下文
|
||||
|
||||
"上下文"是 **OpenClaw 在一次运行中发送给模型的所有内容**。它受模型的**上下文窗口**(token 限制)约束。
|
||||
|
||||
初学者心智模型:
|
||||
新手心智模型:
|
||||
|
||||
- **系统提示词**(由 OpenClaw 构建):规则、工具、Skills 列表、时间/运行时信息,以及注入的工作区文件。
|
||||
- **对话历史**:你的消息 + 助手在本次会话中的消息。
|
||||
- **系统提示词**(OpenClaw 构建):规则、工具、Skills 列表、时间/运行时,以及注入的工作区文件。
|
||||
- **对话历史**:你的消息 + 助手在此会话中的消息。
|
||||
- **工具调用/结果 + 附件**:命令输出、文件读取、图片/音频等。
|
||||
|
||||
上下文与"记忆"_不是同一回事_:记忆可以存储在磁盘上并在之后重新加载;上下文是当前模型窗口内的内容。
|
||||
上下文与"记忆"_不是同一回事_:记忆可以存储在磁盘上并稍后重新加载;上下文是模型当前窗口内的内容。
|
||||
|
||||
## 快速开始(检查上下文)
|
||||
|
||||
- `/status` → 快速查看"我的窗口还剩多少空间?"以及会话设置。
|
||||
- `/context list` → 查看注入了哪些内容及大致大小(按文件和总计)。
|
||||
- `/context detail` → 更深入的分解:按文件、按工具 schema 大小、按 Skills 条目大小,以及系统提示词大小。
|
||||
- `/usage tokens` → 在正常回复后附加每次回复的用量信息。
|
||||
- `/compact` → 将较早的历史记录总结为一个压缩条目,以释放窗口空间。
|
||||
- `/status` → 快速查看"我的窗口有多满?" + 会话设置。
|
||||
- `/context list` → 注入了什么 + 大致大小(每个文件 + 总计)。
|
||||
- `/context detail` → 更深入的分解:每个文件、每个工具 schema 大小、每个 Skills 条目大小和系统提示词大小。
|
||||
- `/usage tokens` → 在正常回复后附加每次回复的使用量页脚。
|
||||
- `/compact` → 将较旧的历史总结为紧凑条目以释放窗口空间。
|
||||
|
||||
另请参阅:[斜杠命令](/tools/slash-commands)、[Token 用量与费用](/token-use)、[压缩](/concepts/compaction)。
|
||||
另请参阅:[斜杠命令](/tools/slash-commands)、[Token 使用与成本](/token-use)、[压缩](/concepts/compaction)。
|
||||
|
||||
## 示例输出
|
||||
|
||||
@@ -83,33 +83,33 @@ Top tools (schema size):
|
||||
… (+N more tools)
|
||||
```
|
||||
|
||||
## 哪些内容计入上下文窗口
|
||||
## 什么计入上下文窗口
|
||||
|
||||
模型接收到的所有内容都会计入,包括:
|
||||
模型接收的所有内容都计入,包括:
|
||||
|
||||
- 系统提示词(所有部分)。
|
||||
- 对话历史。
|
||||
- 工具调用 + 工具结果。
|
||||
- 附件/转录内容(图片/音频/文件)。
|
||||
- 附件/转录(图片/音频/文件)。
|
||||
- 压缩摘要和修剪产物。
|
||||
- 提供商的"包装器"或隐藏头信息(不可见,但仍会计入)。
|
||||
- 提供商"包装器"或隐藏头部(不可见,仍然计数)。
|
||||
|
||||
## OpenClaw 如何构建系统提示词
|
||||
|
||||
系统提示词由 **OpenClaw 拥有**,每次运行时重新构建。它包括:
|
||||
系统提示词由 **OpenClaw 拥有**,每次运行时重建。它包括:
|
||||
|
||||
- 工具列表 + 简短描述。
|
||||
- Skills 列表(仅元数据;见下文)。
|
||||
- 工作区位置。
|
||||
- 时间(UTC + 如已配置则转换为用户时间)。
|
||||
- 运行时元数据(主机/操作系统/模型/思考模式)。
|
||||
- 在 **Project Context** 下注入的工作区引导文件。
|
||||
- 时间(UTC + 如果配置了则转换为用户时间)。
|
||||
- 运行时元数据(主机/操作系统/模型/思考)。
|
||||
- 在**项目上下文**下注入的工作区引导文件。
|
||||
|
||||
完整分解:[系统提示词](/concepts/system-prompt)。
|
||||
|
||||
## 注入的工作区文件(Project Context)
|
||||
## 注入的工作区文件(项目上下文)
|
||||
|
||||
默认情况下,OpenClaw 会注入一组固定的工作区文件(如果存在):
|
||||
默认情况下,OpenClaw 注入一组固定的工作区文件(如果存在):
|
||||
|
||||
- `AGENTS.md`
|
||||
- `SOUL.md`
|
||||
@@ -119,50 +119,50 @@ Top tools (schema size):
|
||||
- `HEARTBEAT.md`
|
||||
- `BOOTSTRAP.md`(仅首次运行)
|
||||
|
||||
大文件会按 `agents.defaults.bootstrapMaxChars`(默认 `20000` 字符)逐文件截断。`/context` 会显示**原始大小与注入大小**的对比,以及是否发生了截断。
|
||||
大文件按文件使用 `agents.defaults.bootstrapMaxChars`(默认 `20000` 字符)截断。`/context` 显示**原始 vs 注入**大小以及是否发生了截断。
|
||||
|
||||
## Skills:注入的内容与按需加载的内容
|
||||
## Skills:注入的内容 vs 按需加载的内容
|
||||
|
||||
系统提示词中包含一个紧凑的**Skills 列表**(名称 + 描述 + 位置)。此列表会产生实际开销。
|
||||
系统提示词包含一个紧凑的 **Skills 列表**(名称 + 描述 + 位置)。此列表有实际开销。
|
||||
|
||||
Skills 指令默认*不会*包含在内。模型应在**需要时**才 `read` Skills 的 `SKILL.md`。
|
||||
Skill 指令默认*不*包含。模型应该**仅在需要时**`read` Skill 的 `SKILL.md`。
|
||||
|
||||
## 工具:两种开销
|
||||
## 工具:有两种成本
|
||||
|
||||
工具以两种方式影响上下文:
|
||||
|
||||
1. 系统提示词中的**工具列表文本**(即你看到的"Tooling"部分)。
|
||||
2. **工具 schema**(JSON)。这些会发送给模型以便其调用工具。即使你看不到它们的纯文本形式,它们也会计入上下文。
|
||||
1. 系统提示词中的**工具列表文本**(你看到的"Tooling")。
|
||||
2. **工具 schema**(JSON)。这些发送给模型以便它可以调用工具。它们计入上下文,即使你看不到它们作为纯文本。
|
||||
|
||||
`/context detail` 会分解最大的工具 schema,让你了解哪些占用最多。
|
||||
`/context detail` 分解最大的工具 schema,以便你可以看到什么占主导。
|
||||
|
||||
## 命令、指令和"内联快捷方式"
|
||||
|
||||
斜杠命令由 Gateway网关处理。有几种不同的行为:
|
||||
斜杠命令由 Gateway 网关处理。有几种不同的行为:
|
||||
|
||||
- **独立命令**:仅包含 `/...` 的消息作为命令运行。
|
||||
- **指令**:`/think`、`/verbose`、`/reasoning`、`/elevated`、`/model`、`/queue` 会在模型看到消息之前被移除。
|
||||
- 仅含指令的消息会持久化会话设置。
|
||||
- 普通消息中的内联指令作为单次消息提示生效。
|
||||
- **内联快捷方式**(仅限白名单发送者):普通消息中的某些 `/...` 标记可以立即执行(例如:"hey /status"),并在模型看到剩余文本之前被移除。
|
||||
- **独立命令**:仅为 `/...` 的消息作为命令运行。
|
||||
- **指令**:`/think`、`/verbose`、`/reasoning`、`/elevated`、`/model`、`/queue` 在模型看到消息之前被剥离。
|
||||
- 仅指令消息会持久化会话设置。
|
||||
- 正常消息中的内联指令作为每条消息的提示。
|
||||
- **内联快捷方式**(仅允许列表中的发送者):正常消息中的某些 `/...` token 可以立即运行(例如:"hey /status"),并在模型看到剩余文本之前被剥离。
|
||||
|
||||
详情:[斜杠命令](/tools/slash-commands)。
|
||||
|
||||
## 会话、压缩和修剪(哪些内容会持久化)
|
||||
## 会话、压缩和修剪(什么会持久化)
|
||||
|
||||
跨消息持久化的内容取决于机制:
|
||||
什么在消息之间持久化取决于机制:
|
||||
|
||||
- **普通历史**会持久化在会话转录中,直到被策略压缩/修剪。
|
||||
- **压缩**会将摘要持久化到转录中,并保留最近的消息不变。
|
||||
- **修剪**会从运行的*内存中*提示词里移除旧的工具结果,但不会重写转录。
|
||||
- **正常历史**在会话记录中持久化,直到被策略压缩/修剪。
|
||||
- **压缩**将摘要持久化到记录中,并保持最近的消息不变。
|
||||
- **修剪**从运行的*内存中*提示词中删除旧的工具结果,但不重写记录。
|
||||
|
||||
文档:[会话](/concepts/session)、[压缩](/concepts/compaction)、[会话修剪](/concepts/session-pruning)。
|
||||
|
||||
## `/context` 实际报告的内容
|
||||
## `/context` 实际报告什么
|
||||
|
||||
`/context` 优先使用最新的**运行时构建的**系统提示词报告(如果可用):
|
||||
`/context` 在可用时优先使用最新的**运行构建的**系统提示词报告:
|
||||
|
||||
- `System prompt (run)` = 从上一次嵌入式(具有工具能力的)运行中捕获,并持久化在会话存储中。
|
||||
- `System prompt (estimate)` = 当不存在运行报告时(或通过不生成该报告的 CLI 后端运行时)即时计算。
|
||||
- `System prompt (run)` = 从最后一次嵌入式(具有工具能力的)运行中捕获,并持久化在会话存储中。
|
||||
- `System prompt (estimate)` = 当没有运行报告存在时(或通过不生成报告的 CLI 后端运行时)即时计算。
|
||||
|
||||
无论哪种方式,它都会报告大小和主要贡献者;它**不会**输出完整的系统提示词或工具 schema。
|
||||
无论哪种方式,它都报告大小和主要贡献者;它**不会**转储完整的系统提示词或工具 schema。
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
---
|
||||
read_when:
|
||||
- 更改群组消息规则或提及方式时
|
||||
summary: WhatsApp 群组消息处理的行为与配置(mentionPatterns 在各平台间共享)
|
||||
- 更改群组消息规则或提及设置时
|
||||
summary: WhatsApp 群组消息处理的行为和配置(mentionPatterns 在各平台间共享)
|
||||
title: 群组消息
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:33Z"
|
||||
generated_at: "2026-02-03T10:05:00Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 181a72f12f5021af77c2e4c913120f711e0c0bc271d218d75cb6fe80dab675bb
|
||||
source_path: concepts/group-messages.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 群组消息(WhatsApp 网页渠道)
|
||||
|
||||
目标:让 Clawd 驻留在 WhatsApp 群组中,仅在被提及时唤醒,并将该线程与个人私聊会话隔离。
|
||||
目标:让 Clawd 留在 WhatsApp 群组中,仅在被提及时唤醒,并将该对话线程与个人私信会话分开。
|
||||
|
||||
注意:`agents.list[].groupChat.mentionPatterns` 现在也被 Telegram/Discord/Slack/iMessage 使用;本文档重点介绍 WhatsApp 特定的行为。对于多智能体配置,请为每个智能体设置 `agents.list[].groupChat.mentionPatterns`(或使用 `messages.groupChat.mentionPatterns` 作为全局回退)。
|
||||
注意:`agents.list[].groupChat.mentionPatterns` 现在也被 Telegram/Discord/Slack/iMessage 使用;本文档重点介绍 WhatsApp 特定的行为。对于多智能体设置,为每个智能体设置 `agents.list[].groupChat.mentionPatterns`(或使用 `messages.groupChat.mentionPatterns` 作为全局回退)。
|
||||
|
||||
## 已实现的功能(2025-12-03)
|
||||
|
||||
- 激活模式:`mention`(默认)或 `always`。`mention` 需要一次提及(通过 `mentionedJids` 实现的 WhatsApp 原生 @提及、正则匹配,或消息文本中包含机器人的 E.164 号码)。`always` 会在每条消息时唤醒智能体,但智能体仅在能提供有价值的回复时才会响应;否则返回静默令牌 `NO_REPLY`。默认值可在配置中设置(`channels.whatsapp.groups`),也可通过 `/activation` 按群组覆盖。设置 `channels.whatsapp.groups` 后,它同时充当群组白名单(添加 `"*"` 以允许所有群组)。
|
||||
- 群组策略:`channels.whatsapp.groupPolicy` 控制是否接受群组消息(`open|disabled|allowlist`)。`allowlist` 使用 `channels.whatsapp.groupAllowFrom`(回退:显式的 `channels.whatsapp.allowFrom`)。默认为 `allowlist`(在添加发送者之前将被阻止)。
|
||||
- 按群组隔离会话:会话键格式为 `agent:<agentId>:whatsapp:group:<jid>`,因此 `/verbose on` 或 `/think high` 等命令(作为独立消息发送)仅作用于该群组;个人私聊状态不受影响。群组线程会跳过心跳。
|
||||
- 上下文注入:**仅待处理的**群组消息(默认 50 条)——即未触发运行的消息——会以 `[Chat messages since your last reply - for context]` 为前缀注入,触发消息则以 `[Current message - respond to this]` 为前缀。已在会话中的消息不会被重复注入。
|
||||
- 发送者标识:每个群组消息批次末尾会附加 `[from: Sender Name (+E164)]`,以便 Pi 知道发言者是谁。
|
||||
- 阅后即焚/一次性查看消息:我们在提取文本/提及之前先解包这些消息,因此其中的提及仍然会触发。
|
||||
- 群组系统提示词:在群组会话的第一轮(以及每次通过 `/activation` 更改模式时),我们会在系统提示词中注入一段简短说明,例如 `You are replying inside the WhatsApp group "<subject>". Group members: Alice (+44...), Bob (+43...), … Activation: trigger-only … Address the specific sender noted in the message context.` 如果元数据不可用,我们仍然会告知智能体这是一个群聊。
|
||||
- 激活模式:`mention`(默认)或 `always`。`mention` 需要被提及(通过 `mentionedJids` 的真实 WhatsApp @提及、正则表达式模式,或文本中任意位置的机器人 E.164 号码)。`always` 会在每条消息时唤醒智能体,但它应该只在能提供有意义价值时才回复;否则返回静默令牌 `NO_REPLY`。默认值可在配置中设置(`channels.whatsapp.groups`),并可通过 `/activation` 为每个群组单独覆盖。当设置了 `channels.whatsapp.groups` 时,它同时充当群组允许列表(包含 `"*"` 以允许所有群组)。
|
||||
- 群组策略:`channels.whatsapp.groupPolicy` 控制是否接受群组消息(`open|disabled|allowlist`)。`allowlist` 使用 `channels.whatsapp.groupAllowFrom`(回退:显式的 `channels.whatsapp.allowFrom`)。默认为 `allowlist`(在你添加发送者之前被阻止)。
|
||||
- 独立群组会话:会话键格式为 `agent:<agentId>:whatsapp:group:<jid>`,因此 `/verbose on` 或 `/think high`(作为独立消息发送)等命令仅作用于该群组;个人私信状态不受影响。群组线程会跳过心跳。
|
||||
- 上下文注入:**仅待处理**的群组消息(默认 50 条),即*未*触发运行的消息,会以 `[Chat messages since your last reply - for context]` 为前缀注入,触发行在 `[Current message - respond to this]` 下。已在会话中的消息不会重复注入。
|
||||
- 发送者显示:每个群组批次现在以 `[from: Sender Name (+E164)]` 结尾,让 Pi 知道是谁在说话。
|
||||
- 阅后即焚/一次性查看:我们在提取文本/提及之前会先解包这些消息,因此其中的提及仍会触发。
|
||||
- 群组系统提示:在群组会话的第一轮(以及每当 `/activation` 更改模式时),我们会向系统提示注入一段简短说明,如 `You are replying inside the WhatsApp group "<subject>". Group members: Alice (+44...), Bob (+43...), … Activation: trigger-only … Address the specific sender noted in the message context.` 如果元数据不可用,我们仍会告知智能体这是一个群聊。
|
||||
|
||||
## 配置示例(WhatsApp)
|
||||
|
||||
在 `~/.openclaw/openclaw.json` 中添加 `groupChat` 块,以便在 WhatsApp 去除文本正文中可见的 `@` 时,显示名称提及仍然有效:
|
||||
在 `~/.openclaw/openclaw.json` 中添加 `groupChat` 块,以便在 WhatsApp 剥离文本正文中的可视 `@` 时,显示名称提及仍能正常工作:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -55,37 +55,37 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
注意:
|
||||
|
||||
- 正则表达式不区分大小写;它们涵盖了 `@openclaw` 这样的显示名称提及,以及带或不带 `+`/空格的原始号码。
|
||||
- 当用户点击联系人时,WhatsApp 仍会通过 `mentionedJids` 发送规范提及,因此号码回退方式很少需要,但作为安全保障很有用。
|
||||
- 正则表达式不区分大小写;它们涵盖了像 `@openclaw` 这样的显示名称提及,以及带或不带 `+`/空格的原始号码。
|
||||
- 当有人点击联系人时,WhatsApp 仍会通过 `mentionedJids` 发送规范的提及,因此号码回退很少需要,但作为安全网很有用。
|
||||
|
||||
### 激活命令(仅限所有者)
|
||||
### 激活命令(仅所有者)
|
||||
|
||||
使用群聊命令:
|
||||
|
||||
- `/activation mention`
|
||||
- `/activation always`
|
||||
|
||||
只有所有者号码(来自 `channels.whatsapp.allowFrom`,未设置时使用机器人自身的 E.164 号码)可以更改此设置。在群组中发送 `/status` 作为独立消息即可查看当前激活模式。
|
||||
只有所有者号码(来自 `channels.whatsapp.allowFrom`,或未设置时使用机器人自己的 E.164)可以更改此设置。在群组中发送 `/status` 作为独立消息以查看当前激活模式。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 将你的 WhatsApp 账号(运行 OpenClaw 的账号)添加到群组。
|
||||
2. 发送 `@openclaw …`(或包含号码)。除非设置了 `groupPolicy: "open"`,否则只有白名单中的发送者才能触发。
|
||||
3. 智能体提示词将包含最近的群组上下文以及末尾的 `[from: …]` 标记,以便它能回复正确的人。
|
||||
4. 会话级指令(`/verbose on`、`/think high`、`/new` 或 `/reset`、`/compact`)仅适用于该群组的会话;请将它们作为独立消息发送以确保生效。你的个人私聊会话保持独立。
|
||||
2. 说 `@openclaw …`(或包含号码)。只有允许列表中的发送者才能触发,除非你设置 `groupPolicy: "open"`。
|
||||
3. 智能体提示将包含最近的群组上下文以及尾部的 `[from: …]` 标记,以便它能够回应正确的人。
|
||||
4. 会话级指令(`/verbose on`、`/think high`、`/new` 或 `/reset`、`/compact`)仅适用于该群组的会话;将它们作为独立消息发送以使其生效。你的个人私信会话保持独立。
|
||||
|
||||
## 测试 / 验证
|
||||
## 测试/验证
|
||||
|
||||
- 手动冒烟测试:
|
||||
- 在群组中发送 `@openclaw` 提及,确认回复中引用了发送者名称。
|
||||
- 再次发送提及,验证历史消息块已包含并在下一轮清除。
|
||||
- 检查 Gateway网关日志(使用 `--verbose` 运行)查看 `inbound web message` 条目,确认其显示 `from: <groupJid>` 和 `[from: …]` 后缀。
|
||||
- 在群组中发送 `@openclaw` 提及,确认收到引用发送者名称的回复。
|
||||
- 发送第二次提及,验证历史记录块被包含,然后在下一轮清除。
|
||||
- 检查 Gateway 网关日志(使用 `--verbose` 运行)以查看 `inbound web message` 条目,显示 `from: <groupJid>` 和 `[from: …]` 后缀。
|
||||
|
||||
## 已知注意事项
|
||||
|
||||
- 群组有意跳过心跳以避免嘈杂的广播。
|
||||
- 回声抑制使用组合的批次字符串;如果你在没有提及的情况下发送两次相同文本,只有第一次会收到响应。
|
||||
- 会话存储条目将以 `agent:<agentId>:whatsapp:group:<jid>` 的形式出现在会话存储中(默认为 `~/.openclaw/agents/<agentId>/sessions/sessions.json`);缺少条目仅表示该群组尚未触发过运行。
|
||||
- 回声抑制使用组合的批次字符串;如果你发送两次相同的文本但没有提及,只有第一次会得到响应。
|
||||
- 会话存储条目将在会话存储中显示为 `agent:<agentId>:whatsapp:group:<jid>`(默认为 `~/.openclaw/agents/<agentId>/sessions/sessions.json`);缺失条目只是意味着该群组尚未触发运行。
|
||||
- 群组中的输入指示器遵循 `agents.defaults.typingMode`(默认:未被提及时为 `message`)。
|
||||
|
||||
@@ -1,54 +1,53 @@
|
||||
---
|
||||
read_when:
|
||||
- 更改群聊行为或提及门控
|
||||
- 更改群聊行为或提及限制
|
||||
summary: 跨平台的群聊行为(WhatsApp/Telegram/Discord/Slack/Signal/iMessage/Microsoft Teams)
|
||||
title: 群组
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:08Z"
|
||||
generated_at: "2026-02-03T07:47:08Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: b727a053edf51f6e7b5c0c324c2fc9c9789a9796c37f622418bd555e8b5a0ec4
|
||||
source_path: concepts/groups.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 群组
|
||||
|
||||
OpenClaw 在各平台上统一处理群聊:WhatsApp、Telegram、Discord、Slack、Signal、iMessage、Microsoft Teams。
|
||||
|
||||
## 入门简介(2 分钟)
|
||||
## 新手入门(2 分钟)
|
||||
|
||||
OpenClaw "运行"在你自己的消息账户上。没有单独的 WhatsApp 机器人用户。
|
||||
如果**你**在某个群组中,OpenClaw 就能看到该群组并在其中回复。
|
||||
OpenClaw"运行"在你自己的消息账户上。没有单独的 WhatsApp 机器人用户。如果**你**在一个群组中,OpenClaw 就可以看到该群组并在其中回复。
|
||||
|
||||
默认行为:
|
||||
|
||||
- 群组受限(`groupPolicy: "allowlist"`)。
|
||||
- 除非你显式禁用提及门控,否则回复需要 @提及。
|
||||
- 除非你明确禁用提及限制,否则回复需要 @ 提及。
|
||||
|
||||
含义:允许列表中的发送者可以通过提及 OpenClaw 来触发它。
|
||||
解释:允许列表中的发送者可以通过提及来触发 OpenClaw。
|
||||
|
||||
> 简而言之
|
||||
>
|
||||
> - **私聊访问**由 `*.allowFrom` 控制。
|
||||
> - **私信访问**由 `*.allowFrom` 控制。
|
||||
> - **群组访问**由 `*.groupPolicy` + 允许列表(`*.groups`、`*.groupAllowFrom`)控制。
|
||||
> - **回复触发**由提及门控(`requireMention`、`/activation`)控制。
|
||||
> - **回复触发**由提及限制(`requireMention`、`/activation`)控制。
|
||||
|
||||
快速流程(群消息的处理过程):
|
||||
快速流程(群消息会发生什么):
|
||||
|
||||
```
|
||||
groupPolicy? disabled -> drop
|
||||
groupPolicy? allowlist -> group allowed? no -> drop
|
||||
requireMention? yes -> mentioned? no -> store for context only
|
||||
otherwise -> reply
|
||||
groupPolicy? disabled -> 丢弃
|
||||
groupPolicy? allowlist -> 群组允许? 否 -> 丢弃
|
||||
requireMention? 是 -> 被提及? 否 -> 仅存储为上下文
|
||||
否则 -> 回复
|
||||
```
|
||||
|
||||

|
||||
|
||||
如果你想要...
|
||||
| 目标 | 需要设置的内容 |
|
||||
如果你想...
|
||||
| 目标 | 设置什么 |
|
||||
|------|-------------|
|
||||
| 允许所有群组但仅在 @提及时回复 | `groups: { "*": { requireMention: true } }` |
|
||||
| 允许所有群组但仅在 @ 提及时回复 | `groups: { "*": { requireMention: true } }` |
|
||||
| 禁用所有群组回复 | `groupPolicy: "disabled"` |
|
||||
| 仅特定群组 | `groups: { "<group-id>": { ... } }`(无 `"*"` 键) |
|
||||
| 仅你可以在群组中触发 | `groupPolicy: "allowlist"`、`groupAllowFrom: ["+1555..."]` |
|
||||
@@ -56,32 +55,32 @@ otherwise -> reply
|
||||
## 会话键
|
||||
|
||||
- 群组会话使用 `agent:<agentId>:<channel>:group:<id>` 会话键(房间/频道使用 `agent:<agentId>:<channel>:channel:<id>`)。
|
||||
- Telegram 论坛主题会在群组 ID 后追加 `:topic:<threadId>`,使每个主题拥有独立的会话。
|
||||
- 私聊使用主会话(或按发送者分配,如已配置)。
|
||||
- 群组会话跳过心跳检测。
|
||||
- Telegram 论坛话题在群组 ID 后添加 `:topic:<threadId>`,因此每个话题都有自己的会话。
|
||||
- 私聊使用主会话(或按发送者配置时使用各自的会话)。
|
||||
- 群组会话跳过心跳。
|
||||
|
||||
## 模式:个人私聊 + 公开群组(单智能体)
|
||||
## 模式:个人私信 + 公开群组(单智能体)
|
||||
|
||||
可以——如果你的"个人"流量是**私聊**,"公开"流量是**群组**,这种方式效果很好。
|
||||
是的——如果你的"个人"流量是**私信**而"公开"流量是**群组**,这种方式效果很好。
|
||||
|
||||
原因:在单智能体模式下,私聊通常落在**主**会话键(`agent:main:main`)上,而群组始终使用**非主**会话键(`agent:main:<channel>:group:<id>`)。如果你启用沙箱并设置 `mode: "non-main"`,这些群组会话将在 Docker 中运行,而你的主私聊会话留在主机上。
|
||||
原因:在单智能体模式下,私信通常落在**主**会话键(`agent:main:main`)中,而群组始终使用**非主**会话键(`agent:main:<channel>:group:<id>`)。如果你启用 `mode: "non-main"` 的沙箱隔离,这些群组会话在 Docker 中运行,而你的主私信会话保持在主机上。
|
||||
|
||||
这为你提供了一个智能体"大脑"(共享工作区 + 记忆),但有两种执行姿态:
|
||||
这给你一个智能体"大脑"(共享工作区 + 记忆),但两种执行姿态:
|
||||
|
||||
- **私聊**:完整工具(主机)
|
||||
- **私信**:完整工具(主机)
|
||||
- **群组**:沙箱 + 受限工具(Docker)
|
||||
|
||||
> 如果你需要真正独立的工作区/角色("个人"和"公开"绝不能混合),请使用第二个智能体 + 绑定。参见[多智能体路由](/concepts/multi-agent)。
|
||||
|
||||
示例(私聊在主机上,群组沙箱隔离 + 仅消息工具):
|
||||
示例(私信在主机上,群组沙箱隔离 + 仅消息工具):
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
sandbox: {
|
||||
mode: "non-main", // groups/channels are non-main -> sandboxed
|
||||
scope: "session", // strongest isolation (one container per group/channel)
|
||||
mode: "non-main", // 群组/频道是非主 -> 沙箱隔离
|
||||
scope: "session", // 最强隔离(每个群组/频道一个容器)
|
||||
workspaceAccess: "none",
|
||||
},
|
||||
},
|
||||
@@ -89,7 +88,7 @@ otherwise -> reply
|
||||
tools: {
|
||||
sandbox: {
|
||||
tools: {
|
||||
// If allow is non-empty, everything else is blocked (deny still wins).
|
||||
// 如果 allow 非空,其他所有工具都被阻止(deny 仍然优先)。
|
||||
allow: ["group:messaging", "group:sessions"],
|
||||
deny: ["group:runtime", "group:fs", "group:ui", "nodes", "cron", "gateway"],
|
||||
},
|
||||
@@ -98,7 +97,7 @@ otherwise -> reply
|
||||
}
|
||||
```
|
||||
|
||||
想要"群组只能访问文件夹 X"而不是"无主机访问"?保持 `workspaceAccess: "none"` 并仅将允许的路径挂载到沙箱中:
|
||||
想要"群组只能看到文件夹 X"而不是"无主机访问"?保持 `workspaceAccess: "none"` 并仅将允许的路径挂载到沙箱中:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -120,20 +119,20 @@ otherwise -> reply
|
||||
}
|
||||
```
|
||||
|
||||
相关内容:
|
||||
相关:
|
||||
|
||||
- 配置键和默认值:[Gateway网关配置](/gateway/configuration#agentsdefaultssandbox)
|
||||
- 调试工具被阻止的原因:[沙箱 vs 工具策略 vs 提权](/gateway/sandbox-vs-tool-policy-vs-elevated)
|
||||
- 配置键和默认值:[Gateway 网关配置](/gateway/configuration#agentsdefaultssandbox)
|
||||
- 调试为什么工具被阻止:[沙箱 vs 工具策略 vs 提权](/gateway/sandbox-vs-tool-policy-vs-elevated)
|
||||
- 绑定挂载详情:[沙箱隔离](/gateway/sandboxing#custom-bind-mounts)
|
||||
|
||||
## 显示标签
|
||||
|
||||
- UI 标签在可用时使用 `displayName`,格式为 `<channel>:<token>`。
|
||||
- `#room` 保留给房间/频道;群聊使用 `g-<slug>`(小写,空格转为 `-`,保留 `#@+._-`)。
|
||||
- `#room` 保留用于房间/频道;群聊使用 `g-<slug>`(小写,空格 -> `-`,保留 `#@+._-`)。
|
||||
|
||||
## 群组策略
|
||||
|
||||
按渠道控制群组/房间消息的处理方式:
|
||||
控制每个渠道如何处理群组/房间消息:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -180,34 +179,34 @@ otherwise -> reply
|
||||
}
|
||||
```
|
||||
|
||||
| 策略 | 行为 |
|
||||
| ------------- | ------------------------------------- |
|
||||
| `"open"` | 群组绕过允许列表;提及门控仍然适用。 |
|
||||
| `"disabled"` | 完全阻止所有群组消息。 |
|
||||
| `"allowlist"` | 仅允许匹配已配置允许列表的群组/房间。 |
|
||||
| 策略 | 行为 |
|
||||
| ------------- | --------------------------------------- |
|
||||
| `"open"` | 群组绕过允许列表;提及限制仍然适用。 |
|
||||
| `"disabled"` | 完全阻止所有群组消息。 |
|
||||
| `"allowlist"` | 仅允许与配置的允许列表匹配的群组/房间。 |
|
||||
|
||||
注意事项:
|
||||
|
||||
- `groupPolicy` 与提及门控(要求 @提及)是分开的。
|
||||
- `groupPolicy` 与提及限制(需要 @ 提及)是分开的。
|
||||
- WhatsApp/Telegram/Signal/iMessage/Microsoft Teams:使用 `groupAllowFrom`(回退:显式 `allowFrom`)。
|
||||
- Discord:允许列表使用 `channels.discord.guilds.<id>.channels`。
|
||||
- Slack:允许列表使用 `channels.slack.channels`。
|
||||
- Matrix:允许列表使用 `channels.matrix.groups`(房间 ID、别名或名称)。使用 `channels.matrix.groupAllowFrom` 限制发送者;也支持按房间的 `users` 允许列表。
|
||||
- 群组私聊单独控制(`channels.discord.dm.*`、`channels.slack.dm.*`)。
|
||||
- Matrix:允许列表使用 `channels.matrix.groups`(房间 ID、别名或名称)。使用 `channels.matrix.groupAllowFrom` 限制发送者;也支持每个房间的 `users` 允许列表。
|
||||
- 群组私信单独控制(`channels.discord.dm.*`、`channels.slack.dm.*`)。
|
||||
- Telegram 允许列表可以匹配用户 ID(`"123456789"`、`"telegram:123456789"`、`"tg:123456789"`)或用户名(`"@alice"` 或 `"alice"`);前缀不区分大小写。
|
||||
- 默认为 `groupPolicy: "allowlist"`;如果你的群组允许列表为空,群组消息将被阻止。
|
||||
|
||||
快速心智模型(群消息的评估顺序):
|
||||
快速心智模型(群组消息的评估顺序):
|
||||
|
||||
1. `groupPolicy`(open/disabled/allowlist)
|
||||
2. 群组允许列表(`*.groups`、`*.groupAllowFrom`、渠道特定的允许列表)
|
||||
3. 提及门控(`requireMention`、`/activation`)
|
||||
2. 群组允许列表(`*.groups`、`*.groupAllowFrom`、渠道特定允许列表)
|
||||
3. 提及限制(`requireMention`、`/activation`)
|
||||
|
||||
## 提及门控(默认)
|
||||
## 提及限制(默认)
|
||||
|
||||
群消息需要提及才能触发,除非按群组覆盖。默认值位于 `*.groups."*"` 下的各子系统中。
|
||||
群组消息需要提及,除非按群组覆盖。默认值位于 `*.groups."*"` 下的每个子系统中。
|
||||
|
||||
回复机器人消息视为隐式提及(当渠道支持回复元数据时)。这适用于 Telegram、WhatsApp、Slack、Discord 和 Microsoft Teams。
|
||||
回复机器人消息被视为隐式提及(当渠道支持回复元数据时)。这适用于 Telegram、WhatsApp、Slack、Discord 和 Microsoft Teams。
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -248,18 +247,18 @@ otherwise -> reply
|
||||
注意事项:
|
||||
|
||||
- `mentionPatterns` 是不区分大小写的正则表达式。
|
||||
- 提供原生提及的平台仍然通过;模式匹配是备用方案。
|
||||
- 按智能体覆盖:`agents.list[].groupChat.mentionPatterns`(多个智能体共享一个群组时很有用)。
|
||||
- 提及门控仅在可以检测提及时生效(原生提及或已配置 `mentionPatterns`)。
|
||||
- Discord 默认值位于 `channels.discord.guilds."*"` 中(可按服务器/频道覆盖)。
|
||||
- 群组历史上下文在各渠道中统一包装,且为**仅待处理**(因提及门控跳过的消息);使用 `messages.groupChat.historyLimit` 设置全局默认值,使用 `channels.<channel>.historyLimit`(或 `channels.<channel>.accounts.*.historyLimit`)进行覆盖。设为 `0` 以禁用。
|
||||
- 提供显式提及的平台仍然通过;模式是回退。
|
||||
- 每个智能体覆盖:`agents.list[].groupChat.mentionPatterns`(当多个智能体共享一个群组时有用)。
|
||||
- 提及限制仅在提及检测可行时强制执行(原生提及或 `mentionPatterns` 已配置)。
|
||||
- Discord 默认值位于 `channels.discord.guilds."*"`(可按服务器/频道覆盖)。
|
||||
- 群组历史上下文在渠道间统一包装,并且是**仅待处理**(由于提及限制而跳过的消息);使用 `messages.groupChat.historyLimit` 作为全局默认值,使用 `channels.<channel>.historyLimit`(或 `channels.<channel>.accounts.*.historyLimit`)进行覆盖。设置 `0` 以禁用。
|
||||
|
||||
## 群组/频道工具限制(可选)
|
||||
|
||||
某些渠道配置支持限制**特定群组/房间/频道内**可用的工具。
|
||||
|
||||
- `tools`:为整个群组允许/拒绝工具。
|
||||
- `toolsBySender`:群组内按发送者覆盖(键为发送者 ID/用户名/邮箱/电话号码,取决于渠道)。使用 `"*"` 作为通配符。
|
||||
- `toolsBySender`:群组内的按发送者覆盖(键是发送者 ID/用户名/邮箱/电话号码,取决于渠道)。使用 `"*"` 作为通配符。
|
||||
|
||||
解析顺序(最具体的优先):
|
||||
|
||||
@@ -290,14 +289,14 @@ otherwise -> reply
|
||||
|
||||
注意事项:
|
||||
|
||||
- 群组/频道工具限制在全局/智能体工具策略之上额外应用(拒绝仍然优先)。
|
||||
- 某些渠道对房间/频道使用不同的嵌套结构(例如 Discord `guilds.*.channels.*`、Slack `channels.*`、Microsoft Teams `teams.*.channels.*`)。
|
||||
- 群组/频道工具限制在全局/智能体工具策略之外额外应用(deny 仍然优先)。
|
||||
- 某些渠道对房间/频道使用不同的嵌套结构(例如,Discord `guilds.*.channels.*`、Slack `channels.*`、MS Teams `teams.*.channels.*`)。
|
||||
|
||||
## 群组允许列表
|
||||
|
||||
当配置了 `channels.whatsapp.groups`、`channels.telegram.groups` 或 `channels.imessage.groups` 时,键充当群组允许列表。使用 `"*"` 允许所有群组,同时仍可设置默认提及行为。
|
||||
当配置了 `channels.whatsapp.groups`、`channels.telegram.groups` 或 `channels.imessage.groups` 时,键作为群组允许列表。使用 `"*"` 允许所有群组,同时仍设置默认提及行为。
|
||||
|
||||
常见意图(可直接复制粘贴):
|
||||
常见意图(复制/粘贴):
|
||||
|
||||
1. 禁用所有群组回复
|
||||
|
||||
@@ -322,7 +321,7 @@ otherwise -> reply
|
||||
}
|
||||
```
|
||||
|
||||
3. 允许所有群组但要求提及(显式)
|
||||
3. 允许所有群组但需要提及(显式)
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -350,31 +349,31 @@ otherwise -> reply
|
||||
|
||||
## 激活(仅所有者)
|
||||
|
||||
群组所有者可以切换按群组的激活方式:
|
||||
群组所有者可以切换每个群组的激活状态:
|
||||
|
||||
- `/activation mention`
|
||||
- `/activation always`
|
||||
|
||||
所有者由 `channels.whatsapp.allowFrom` 确定(未设置时使用机器人自身的 E.164 号码)。以独立消息发送该命令。其他平台目前忽略 `/activation`。
|
||||
所有者由 `channels.whatsapp.allowFrom` 确定(未设置时为机器人自身的 E.164)。将命令作为独立消息发送。其他平台目前忽略 `/activation`。
|
||||
|
||||
## 上下文字段
|
||||
|
||||
群组入站消息负载设置:
|
||||
群组入站负载设置:
|
||||
|
||||
- `ChatType=group`
|
||||
- `GroupSubject`(如已知)
|
||||
- `GroupMembers`(如已知)
|
||||
- `WasMentioned`(提及门控结果)
|
||||
- Telegram 论坛主题还包含 `MessageThreadId` 和 `IsForum`。
|
||||
- `GroupSubject`(如果已知)
|
||||
- `GroupMembers`(如果已知)
|
||||
- `WasMentioned`(提及限制结果)
|
||||
- Telegram 论坛话题还包括 `MessageThreadId` 和 `IsForum`。
|
||||
|
||||
智能体系统提示词在新群组会话的首轮包含群组简介。它提醒模型像人一样回复,避免 Markdown 表格,避免输入字面的 `\n` 序列。
|
||||
智能体系统提示在新群组会话的第一轮包含群组介绍。它提醒模型像人类一样回复,避免 Markdown 表格,避免输入字面量 `\n` 序列。
|
||||
|
||||
## iMessage 特定说明
|
||||
## iMessage 特定内容
|
||||
|
||||
- 路由或添加允许列表时优先使用 `chat_id:<id>`。
|
||||
- 路由或允许列表时优先使用 `chat_id:<id>`。
|
||||
- 列出聊天:`imsg chats --limit 20`。
|
||||
- 群组回复始终返回到同一个 `chat_id`。
|
||||
- 群组回复始终返回到相同的 `chat_id`。
|
||||
|
||||
## WhatsApp 特定说明
|
||||
## WhatsApp 特定内容
|
||||
|
||||
有关 WhatsApp 专有行为(历史注入、提及处理详情),请参阅[群消息](/concepts/group-messages)。
|
||||
参见[群消息](/concepts/group-messages)了解 WhatsApp 专有行为(历史注入、提及处理详情)。
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
---
|
||||
read_when:
|
||||
- 想了解记忆文件布局和工作流程
|
||||
- 想调整自动预压缩记忆刷写
|
||||
summary: OpenClaw 记忆的工作原理(工作区文件 + 自动记忆刷写)
|
||||
- 你想了解记忆文件布局和工作流程
|
||||
- 你想调整自动压缩前的记忆刷新
|
||||
summary: OpenClaw 记忆的工作原理(工作空间文件 + 自动记忆刷新)
|
||||
title: 记忆
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:24:01Z"
|
||||
generated_at: "2026-02-03T07:47:38Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: f3a7f5d9f61f9742eb3a8adbc3ccaddeadb7e48ceccdfb595327d6d1f55cd00e
|
||||
source_path: concepts/memory.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 记忆
|
||||
|
||||
OpenClaw 的记忆是**智能体工作区中的纯 Markdown 文件**。这些文件是唯一的事实来源;模型只"记住"写入磁盘的内容。
|
||||
OpenClaw 记忆是**智能体工作空间中的纯 Markdown 文件**。这些文件是唯一的事实来源;模型只"记住"写入磁盘的内容。
|
||||
|
||||
记忆搜索工具由活跃的记忆插件提供(默认:`memory-core`)。通过 `plugins.slots.memory = "none"` 可禁用记忆插件。
|
||||
记忆搜索工具由活动的记忆插件提供(默认:`memory-core`)。使用 `plugins.slots.memory = "none"` 禁用记忆插件。
|
||||
|
||||
## 记忆文件(Markdown)
|
||||
|
||||
默认工作区布局使用两个记忆层:
|
||||
默认工作空间布局使用两个记忆层:
|
||||
|
||||
- `memory/YYYY-MM-DD.md`
|
||||
- 每日日志(仅追加)。
|
||||
- 会话开始时读取今天和昨天的内容。
|
||||
- 在会话开始时读取今天和昨天的内容。
|
||||
- `MEMORY.md`(可选)
|
||||
- 精心整理的长期记忆。
|
||||
- **仅在主要的私人会话中加载**(不在群组上下文中加载)。
|
||||
- **仅在主要的私人会话中加载**(绝不在群组上下文中加载)。
|
||||
|
||||
这些文件位于工作区目录下(`agents.defaults.workspace`,默认 `~/.openclaw/workspace`)。完整布局参见[智能体工作区](/concepts/agent-workspace)。
|
||||
这些文件位于工作空间下(`agents.defaults.workspace`,默认 `~/.openclaw/workspace`)。完整布局参见[智能体工作空间](/concepts/agent-workspace)。
|
||||
|
||||
## 何时写入记忆
|
||||
|
||||
- 决策、偏好和持久性事实写入 `MEMORY.md`。
|
||||
- 日常笔记和运行上下文写入 `memory/YYYY-MM-DD.md`。
|
||||
- 如果有人说"记住这个",就写下来(不要只保留在内存中)。
|
||||
- 这个领域仍在发展中。提醒模型存储记忆会有帮助;它知道该怎么做。
|
||||
- 如果你想让某些信息持久保留,**让机器人把它写入**记忆。
|
||||
- 如果有人说"记住这个",就写下来(不要只保存在内存中)。
|
||||
- 这个领域仍在发展中。提醒模型存储记忆会有帮助;它会知道该怎么做。
|
||||
- 如果你想让某些内容持久保存,**请要求机器人将其写入**记忆。
|
||||
|
||||
## 自动记忆刷写(预压缩 ping)
|
||||
## 自动记忆刷新(压缩前触发)
|
||||
|
||||
当会话**接近自动压缩**时,OpenClaw 会触发一个**静默的智能体轮次**,提醒模型在上下文被压缩**之前**写入持久记忆。默认提示词明确表示模型*可以回复*,但通常 `NO_REPLY` 是正确的响应,这样用户不会看到这个轮次。
|
||||
当会话**接近自动压缩**时,OpenClaw 会触发一个**静默的智能体回合**,提醒模型在上下文被压缩**之前**写入持久记忆。默认提示明确说明模型*可以回复*,但通常 `NO_REPLY` 是正确的响应,因此用户永远不会看到这个回合。
|
||||
|
||||
这由 `agents.defaults.compaction.memoryFlush` 控制:
|
||||
|
||||
@@ -66,35 +66,35 @@ OpenClaw 的记忆是**智能体工作区中的纯 Markdown 文件**。这些文
|
||||
|
||||
详情:
|
||||
|
||||
- **软阈值**:当会话 token 估计值超过 `contextWindow - reserveTokensFloor - softThresholdTokens` 时触发刷写。
|
||||
- 默认**静默**:提示词包含 `NO_REPLY`,因此不会传递任何内容。
|
||||
- **两个提示词**:一个用户提示词加一个系统提示词附加提醒。
|
||||
- **每个压缩周期刷写一次**(在 `sessions.json` 中跟踪)。
|
||||
- **工作区必须可写**:如果会话以 `workspaceAccess: "ro"` 或 `"none"` 在沙箱中运行,则跳过刷写。
|
||||
- **软阈值**:当会话 token 估计超过 `contextWindow - reserveTokensFloor - softThresholdTokens` 时触发刷新。
|
||||
- 默认**静默**:提示包含 `NO_REPLY`,因此不会发送任何内容。
|
||||
- **两个提示**:一个用户提示加一个系统提示附加提醒。
|
||||
- **每个压缩周期刷新一次**(在 `sessions.json` 中跟踪)。
|
||||
- **工作空间必须可写**:如果会话以 `workspaceAccess: "ro"` 或 `"none"` 在沙箱中运行,则跳过刷新。
|
||||
|
||||
完整的压缩生命周期参见[会话管理 + 压缩](/reference/session-management-compaction)。
|
||||
|
||||
## 向量记忆搜索
|
||||
|
||||
OpenClaw 可以对 `MEMORY.md` 和 `memory/*.md`(以及你选择加入的任何额外目录或文件)构建小型向量索引,这样即使措辞不同,语义查询也能找到相关笔记。
|
||||
OpenClaw 可以在 `MEMORY.md` 和 `memory/*.md`(以及你选择加入的任何额外目录或文件)上构建小型向量索引,以便语义查询可以找到相关笔记,即使措辞不同。
|
||||
|
||||
默认设置:
|
||||
默认值:
|
||||
|
||||
- 默认启用。
|
||||
- 监视记忆文件变更(带防抖)。
|
||||
- 默认使用远程嵌入。如果未设置 `memorySearch.provider`,OpenClaw 会自动选择:
|
||||
- 监视记忆文件的更改(去抖动)。
|
||||
- 默认使用远程嵌入。如果未设置 `memorySearch.provider`,OpenClaw 自动选择:
|
||||
1. 如果配置了 `memorySearch.local.modelPath` 且文件存在,则使用 `local`。
|
||||
2. 如果可以解析到 OpenAI 密钥,则使用 `openai`。
|
||||
3. 如果可以解析到 Gemini 密钥,则使用 `gemini`。
|
||||
4. 否则记忆搜索保持禁用,直到完成配置。
|
||||
2. 如果可以解析 OpenAI 密钥,则使用 `openai`。
|
||||
3. 如果可以解析 Gemini 密钥,则使用 `gemini`。
|
||||
4. 否则记忆搜索保持禁用状态直到配置完成。
|
||||
- 本地模式使用 node-llama-cpp,可能需要运行 `pnpm approve-builds`。
|
||||
- 使用 sqlite-vec(可用时)加速 SQLite 内的向量搜索。
|
||||
- 使用 sqlite-vec(如果可用)在 SQLite 中加速向量搜索。
|
||||
|
||||
远程嵌入**需要**嵌入提供商的 API 密钥。OpenClaw 从认证配置文件、`models.providers.*.apiKey` 或环境变量中解析密钥。Codex OAuth 仅覆盖 chat/completions,**不满足**记忆搜索的嵌入需求。对于 Gemini,使用 `GEMINI_API_KEY` 或 `models.providers.google.apiKey`。使用自定义 OpenAI 兼容端点时,设置 `memorySearch.remote.apiKey`(以及可选的 `memorySearch.remote.headers`)。
|
||||
远程嵌入**需要**嵌入提供商的 API 密钥。OpenClaw 从身份验证配置文件、`models.providers.*.apiKey` 或环境变量解析密钥。Codex OAuth 仅涵盖聊天/补全,**不**满足记忆搜索的嵌入需求。对于 Gemini,使用 `GEMINI_API_KEY` 或 `models.providers.google.apiKey`。使用自定义 OpenAI 兼容端点时,设置 `memorySearch.remote.apiKey`(以及可选的 `memorySearch.remote.headers`)。
|
||||
|
||||
### 额外记忆路径
|
||||
|
||||
如果你想索引默认工作区布局之外的 Markdown 文件,添加显式路径:
|
||||
如果你想索引默认工作空间布局之外的 Markdown 文件,添加显式路径:
|
||||
|
||||
```json5
|
||||
agents: {
|
||||
@@ -106,12 +106,12 @@ agents: {
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- 路径可以是绝对路径或工作区相对路径。
|
||||
- 路径可以是绝对路径或工作空间相对路径。
|
||||
- 目录会递归扫描 `.md` 文件。
|
||||
- 仅索引 Markdown 文件。
|
||||
- 符号链接会被忽略(文件或目录)。
|
||||
- 符号链接被忽略(文件或目录)。
|
||||
|
||||
### Gemini 嵌入(原生)
|
||||
|
||||
@@ -131,13 +131,13 @@ agents: {
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- `remote.baseUrl` 是可选的(默认为 Gemini API 基础 URL)。
|
||||
- `remote.headers` 允许你在需要时添加额外的请求头。
|
||||
- `remote.headers` 让你可以在需要时添加额外的标头。
|
||||
- 默认模型:`gemini-embedding-001`。
|
||||
|
||||
如果你想使用**自定义 OpenAI 兼容端点**(OpenRouter、vLLM 或代理),可以在 OpenAI 提供商下使用 `remote` 配置:
|
||||
如果你想使用**自定义 OpenAI 兼容端点**(OpenRouter、vLLM 或代理),可以使用 `remote` 配置与 OpenAI 提供商:
|
||||
|
||||
```json5
|
||||
agents: {
|
||||
@@ -157,23 +157,23 @@ agents: {
|
||||
|
||||
如果你不想设置 API 密钥,使用 `memorySearch.provider = "local"` 或设置 `memorySearch.fallback = "none"`。
|
||||
|
||||
回退策略:
|
||||
回退:
|
||||
|
||||
- `memorySearch.fallback` 可以是 `openai`、`gemini`、`local` 或 `none`。
|
||||
- 回退提供商仅在主嵌入提供商失败时使用。
|
||||
|
||||
批量索引(OpenAI + Gemini):
|
||||
|
||||
- OpenAI 和 Gemini 嵌入默认启用批量索引。设置 `agents.defaults.memorySearch.remote.batch.enabled = false` 可禁用。
|
||||
- 默认行为等待批量完成;如需调整,请调节 `remote.batch.wait`、`remote.batch.pollIntervalMs` 和 `remote.batch.timeoutMinutes`。
|
||||
- 设置 `remote.batch.concurrency` 控制并行提交的批量作业数(默认:2)。
|
||||
- 批量模式在 `memorySearch.provider = "openai"` 或 `"gemini"` 时适用,并使用相应的 API 密钥。
|
||||
- Gemini 批量作业使用异步嵌入批量端点,需要 Gemini Batch API 可用。
|
||||
- OpenAI 和 Gemini 嵌入默认启用。设置 `agents.defaults.memorySearch.remote.batch.enabled = false` 以禁用。
|
||||
- 默认行为等待批处理完成;如果需要可以调整 `remote.batch.wait`、`remote.batch.pollIntervalMs` 和 `remote.batch.timeoutMinutes`。
|
||||
- 设置 `remote.batch.concurrency` 以控制我们并行提交多少个批处理作业(默认:2)。
|
||||
- 批处理模式在 `memorySearch.provider = "openai"` 或 `"gemini"` 时适用,并使用相应的 API 密钥。
|
||||
- Gemini 批处理作业使用异步嵌入批处理端点,需要 Gemini Batch API 可用。
|
||||
|
||||
为什么 OpenAI 批量又快又便宜:
|
||||
为什么 OpenAI 批处理快速又便宜:
|
||||
|
||||
- 对于大规模回填,OpenAI 通常是我们支持的最快选项,因为我们可以在单个批量作业中提交多个嵌入请求,让 OpenAI 异步处理。
|
||||
- OpenAI 为 Batch API 工作负载提供折扣定价,因此大规模索引运行通常比同步发送相同请求更便宜。
|
||||
- 对于大型回填,OpenAI 通常是我们支持的最快选项,因为我们可以在单个批处理作业中提交许多嵌入请求,让 OpenAI 异步处理它们。
|
||||
- OpenAI 为 Batch API 工作负载提供折扣定价,因此大型索引运行通常比同步发送相同请求更便宜。
|
||||
- 详情参见 OpenAI Batch API 文档和定价:
|
||||
- https://platform.openai.com/docs/api-reference/batch
|
||||
- https://platform.openai.com/pricing
|
||||
@@ -198,7 +198,7 @@ agents: {
|
||||
|
||||
工具:
|
||||
|
||||
- `memory_search` — 返回包含文件路径和行范围的片段。
|
||||
- `memory_search` — 返回带有文件 + 行范围的片段。
|
||||
- `memory_get` — 按路径读取记忆文件内容。
|
||||
|
||||
本地模式:
|
||||
@@ -209,65 +209,67 @@ agents: {
|
||||
|
||||
### 记忆工具的工作原理
|
||||
|
||||
- `memory_search` 对来自 `MEMORY.md` + `memory/**/*.md` 的 Markdown 分块(约 400 token 目标,80 token 重叠)进行语义搜索。返回片段文本(上限约 700 字符)、文件路径、行范围、分数、提供商/模型,以及是否从本地回退到了远程嵌入。不返回完整文件内容。
|
||||
- `memory_get` 读取特定的记忆 Markdown 文件(工作区相对路径),可选从起始行读取 N 行。`MEMORY.md` / `memory/` 之外的路径仅在 `memorySearch.extraPaths` 中显式列出时才允许访问。
|
||||
- 两个工具仅在 `memorySearch.enabled` 对智能体解析为 true 时启用。
|
||||
- `memory_search` 从 `MEMORY.md` + `memory/**/*.md` 语义搜索 Markdown 块(目标约 400 个 token,80 个 token 重叠)。它返回片段文本(上限约 700 个字符)、文件路径、行范围、分数、提供商/模型,以及我们是否从本地回退到远程嵌入。不返回完整文件内容。
|
||||
- `memory_get` 读取特定的记忆 Markdown 文件(工作空间相对路径),可选从起始行开始读取 N 行。`MEMORY.md` / `memory/` 之外的路径仅在明确列在 `memorySearch.extraPaths` 中时才允许。
|
||||
- 两个工具仅在智能体的 `memorySearch.enabled` 解析为 true 时启用。
|
||||
|
||||
### 索引内容(及时机)
|
||||
|
||||
- 文件类型:仅 Markdown(`MEMORY.md`、`memory/**/*.md`,以及 `memorySearch.extraPaths` 下的任何 `.md` 文件)。
|
||||
- 索引存储:每个智能体的 SQLite 位于 `~/.openclaw/memory/<agentId>.sqlite`(可通过 `agents.defaults.memorySearch.store.path` 配置,支持 `{agentId}` 占位符)。
|
||||
- 时效性:监视 `MEMORY.md`、`memory/` 和 `memorySearch.extraPaths` 的变更并标记索引为脏(防抖 1.5 秒)。同步在会话开始时、搜索时或按间隔调度,并异步运行。会话记录使用增量阈值触发后台同步。
|
||||
- 重新索引触发条件:索引存储嵌入的**提供商/模型 + 端点指纹 + 分块参数**。如果其中任何一项发生变化,OpenClaw 会自动重置并重新索引整个存储。
|
||||
- 索引存储:每个智能体的 SQLite 位于 `~/.openclaw/memory/<agentId>.sqlite`(可通过 `agents.defaults.memorySearch.store.path` 配置,支持 `{agentId}` 令牌)。
|
||||
- 新鲜度:监视器监视 `MEMORY.md`、`memory/` 和 `memorySearch.extraPaths`,标记索引为脏(去抖动 1.5 秒)。同步在会话开始时、搜索时或按间隔安排,并异步运行。会话记录使用增量阈值触发后台同步。
|
||||
- 重新索引触发器:索引存储嵌入的**提供商/模型 + 端点指纹 + 分块参数**。如果其中任何一个发生变化,OpenClaw 会自动重置并重新索引整个存储。
|
||||
|
||||
### 混合搜索(BM25 + 向量)
|
||||
|
||||
启用后,OpenClaw 结合以下两种方式:
|
||||
启用时,OpenClaw 结合:
|
||||
|
||||
- **向量相似度**(语义匹配,措辞可以不同)
|
||||
- **BM25 关键词相关性**(精确 token,如 ID、环境变量、代码符号)
|
||||
- **BM25 关键词相关性**(精确令牌如 ID、环境变量、代码符号)
|
||||
|
||||
如果你的平台上全文搜索不可用,OpenClaw 会回退到纯向量搜索。
|
||||
|
||||
#### 为什么用混合搜索?
|
||||
#### 为什么使用混合搜索?
|
||||
|
||||
向量搜索擅长"这表达的是同一个意思":
|
||||
向量搜索擅长"这意味着同一件事":
|
||||
|
||||
- "Mac Studio gateway 主机" vs "运行 gateway 的机器"
|
||||
- "防抖文件更新" vs "避免每次写入都索引"
|
||||
- "Mac Studio gateway host" vs "运行 gateway 的机器"
|
||||
- "debounce file updates" vs "避免每次写入都索引"
|
||||
|
||||
但对于精确的高信号 token 可能较弱:
|
||||
但它在精确的高信号令牌上可能较弱:
|
||||
|
||||
- ID(`a828e60`、`b3b9895a…`)
|
||||
- 代码符号(`memorySearch.query.hybrid`)
|
||||
- 错误字符串("sqlite-vec unavailable")
|
||||
|
||||
BM25(全文搜索)恰好相反:擅长精确 token,较弱于同义改写。混合搜索是务实的折中方案:**同时使用两种检索信号**,这样"自然语言"查询和"大海捞针"查询都能获得好结果。
|
||||
BM25(全文)正好相反:擅长精确令牌,弱于释义。
|
||||
混合搜索是务实的中间地带:**同时使用两种检索信号**,这样你可以在"自然语言"查询和"大海捞针"查询上都获得好结果。
|
||||
|
||||
#### 我们如何合并结果(当前设计)
|
||||
|
||||
实现概要:
|
||||
实现概述:
|
||||
|
||||
1. 从两端检索候选池:
|
||||
1. 从双方检索候选池:
|
||||
|
||||
- **向量**:按余弦相似度取前 `maxResults * candidateMultiplier` 个。
|
||||
- **BM25**:按 FTS5 BM25 排名取前 `maxResults * candidateMultiplier` 个(值越低越好)。
|
||||
- **BM25**:按 FTS5 BM25 排名取前 `maxResults * candidateMultiplier` 个(越低越好)。
|
||||
|
||||
2. 将 BM25 排名转换为 0..1 范围的分数:
|
||||
|
||||
- `textScore = 1 / (1 + max(0, bm25Rank))`
|
||||
|
||||
3. 按分块 ID 合并候选并计算加权分数:
|
||||
3. 按块 id 合并候选并计算加权分数:
|
||||
|
||||
- `finalScore = vectorWeight * vectorScore + textWeight * textScore`
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- 在配置解析时 `vectorWeight` + `textWeight` 会归一化到 1.0,因此权重表现为百分比。
|
||||
- 如果嵌入不可用(或提供商返回零向量),我们仍会运行 BM25 并返回关键词匹配结果。
|
||||
- 在配置解析中 `vectorWeight` + `textWeight` 归一化为 1.0,因此权重表现为百分比。
|
||||
- 如果嵌入不可用(或提供商返回零向量),我们仍然运行 BM25 并返回关键词匹配。
|
||||
- 如果无法创建 FTS5,我们保持纯向量搜索(不会硬失败)。
|
||||
|
||||
这不是"信息检索理论上的完美方案",但它简单、快速,在实际笔记上倾向于提升召回率/精确率。如果以后想更精细,常见的下一步是互惠排名融合(RRF)或混合前的分数归一化(最小/最大值或 z-score)。
|
||||
这不是"IR 理论完美"的,但它简单、快速,并且往往能提高真实笔记的召回率/精确率。
|
||||
如果我们以后想要更复杂的方案,常见的下一步是倒数排名融合(RRF)或在混合之前进行分数归一化(最小/最大或 z 分数)。
|
||||
|
||||
配置:
|
||||
|
||||
@@ -290,7 +292,7 @@ agents: {
|
||||
|
||||
### 嵌入缓存
|
||||
|
||||
OpenClaw 可以在 SQLite 中缓存**分块嵌入**,这样重新索引和频繁更新(特别是会话记录)不会重新嵌入未更改的文本。
|
||||
OpenClaw 可以在 SQLite 中缓存**块嵌入**,这样重新索引和频繁更新(特别是会话记录)不会重新嵌入未更改的文本。
|
||||
|
||||
配置:
|
||||
|
||||
@@ -309,7 +311,8 @@ agents: {
|
||||
|
||||
### 会话记忆搜索(实验性)
|
||||
|
||||
你可以选择索引**会话记录**并通过 `memory_search` 进行搜索。此功能受实验性标志控制。
|
||||
你可以选择性地索引**会话记录**并通过 `memory_search` 呈现它们。
|
||||
这由实验性标志控制。
|
||||
|
||||
```json5
|
||||
agents: {
|
||||
@@ -322,14 +325,14 @@ agents: {
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- 会话索引是**选择加入**的(默认关闭)。
|
||||
- 会话更新带防抖,在超过增量阈值后**异步索引**(尽力而为)。
|
||||
- `memory_search` 不会阻塞等待索引;在后台同步完成之前结果可能略有延迟。
|
||||
- 结果仍然只包含片段;`memory_get` 仍限于记忆文件。
|
||||
- 会话更新被去抖动并在超过增量阈值后**异步索引**(尽力而为)。
|
||||
- `memory_search` 永远不会阻塞索引;在后台同步完成之前,结果可能略有延迟。
|
||||
- 结果仍然只包含片段;`memory_get` 仍然仅限于记忆文件。
|
||||
- 会话索引按智能体隔离(仅索引该智能体的会话日志)。
|
||||
- 会话日志存储在磁盘上(`~/.openclaw/agents/<agentId>/sessions/*.jsonl`)。任何拥有文件系统访问权限的进程/用户都可以读取它们,因此应将磁盘访问视为信任边界。如需更严格的隔离,请在不同的操作系统用户或主机下运行智能体。
|
||||
- 会话日志存储在磁盘上(`~/.openclaw/agents/<agentId>/sessions/*.jsonl`)。任何具有文件系统访问权限的进程/用户都可以读取它们,因此将磁盘访问视为信任边界。对于更严格的隔离,在单独的操作系统用户或主机下运行智能体。
|
||||
|
||||
增量阈值(显示默认值):
|
||||
|
||||
@@ -350,7 +353,7 @@ agents: {
|
||||
|
||||
### SQLite 向量加速(sqlite-vec)
|
||||
|
||||
当 sqlite-vec 扩展可用时,OpenClaw 将嵌入存储在 SQLite 虚拟表(`vec0`)中,并在数据库内执行向量距离查询。这使搜索保持快速,无需将所有嵌入加载到 JS 中。
|
||||
当 sqlite-vec 扩展可用时,OpenClaw 将嵌入存储在 SQLite 虚拟表(`vec0`)中,并在数据库中执行向量距离查询。这使搜索保持快速,无需将每个嵌入加载到 JS 中。
|
||||
|
||||
配置(可选):
|
||||
|
||||
@@ -369,18 +372,18 @@ agents: {
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- `enabled` 默认为 true;禁用时,搜索回退到对存储嵌入进行进程内余弦相似度计算。
|
||||
- `enabled` 默认为 true;禁用时,搜索回退到对存储嵌入的进程内余弦相似度计算。
|
||||
- 如果 sqlite-vec 扩展缺失或加载失败,OpenClaw 会记录错误并继续使用 JS 回退(无向量表)。
|
||||
- `extensionPath` 覆盖捆绑的 sqlite-vec 路径(适用于自定义构建或非标准安装位置)。
|
||||
- `extensionPath` 覆盖捆绑的 sqlite-vec 路径(对于自定义构建或非标准安装位置很有用)。
|
||||
|
||||
### 本地嵌入自动下载
|
||||
|
||||
- 默认本地嵌入模型:`hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf`(约 0.6 GB)。
|
||||
- 当 `memorySearch.provider = "local"` 时,`node-llama-cpp` 解析 `modelPath`;如果 GGUF 文件缺失,会**自动下载**到缓存目录(或 `local.modelCacheDir`,如已设置),然后加载。下载在重试时可恢复。
|
||||
- 当 `memorySearch.provider = "local"` 时,`node-llama-cpp` 解析 `modelPath`;如果 GGUF 缺失,它会**自动下载**到缓存(或 `local.modelCacheDir`,如果已设置),然后加载它。下载在重试时会续传。
|
||||
- 原生构建要求:运行 `pnpm approve-builds`,选择 `node-llama-cpp`,然后运行 `pnpm rebuild node-llama-cpp`。
|
||||
- 回退:如果本地设置失败且 `memorySearch.fallback = "openai"`,我们会自动切换到远程嵌入(`openai/text-embedding-3-small`,除非被覆盖)并记录原因。
|
||||
- 回退:如果本地设置失败且 `memorySearch.fallback = "openai"`,我们自动切换到远程嵌入(`openai/text-embedding-3-small`,除非被覆盖)并记录原因。
|
||||
|
||||
### 自定义 OpenAI 兼容端点示例
|
||||
|
||||
@@ -403,7 +406,7 @@ agents: {
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- `remote.*` 优先于 `models.providers.openai.*`。
|
||||
- `remote.headers` 与 OpenAI 请求头合并;键冲突时 remote 优先。省略 `remote.headers` 则使用 OpenAI 默认值。
|
||||
- `remote.headers` 与 OpenAI 标头合并;键冲突时 remote 优先。省略 `remote.headers` 以使用 OpenAI 默认值。
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
---
|
||||
read_when:
|
||||
- 解释入站消息如何变为回复
|
||||
- 澄清会话、队列模式或流式传输行为
|
||||
- 记录推理可见性和用量影响
|
||||
summary: 消息流、会话、队列和推理可见性
|
||||
- 解释入站消息如何转化为回复
|
||||
- 阐明会话、队列模式或流式传输行为
|
||||
- 记录推理可见性和使用影响
|
||||
summary: 消息流程、会话、队列和推理可见性
|
||||
title: 消息
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:22:57Z"
|
||||
generated_at: "2026-02-03T10:05:22Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 147362b61bee21ee6e303654d970a052325f076ddb45814306053f70409737b5
|
||||
source_path: concepts/messages.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 消息
|
||||
|
||||
本页汇总了 OpenClaw 处理入站消息、会话、队列、流式传输和推理可见性的方式。
|
||||
本页汇总了 OpenClaw 如何处理入站消息、会话、队列、流式传输和推理可见性。
|
||||
|
||||
## 消息流(概览)
|
||||
## 消息流程(高层概述)
|
||||
|
||||
```
|
||||
入站消息
|
||||
-> 路由/绑定 -> 会话键
|
||||
-> 路由/绑定 -> 会话密钥
|
||||
-> 队列(如果有运行中的任务)
|
||||
-> 智能体运行(流式传输 + 工具)
|
||||
-> 出站回复(渠道限制 + 分块)
|
||||
```
|
||||
|
||||
关键配置项位于配置文件中:
|
||||
关键配置项在配置中:
|
||||
|
||||
- `messages.*` 用于前缀、队列和群组行为。
|
||||
- `agents.defaults.*` 用于块流式传输和分块默认值。
|
||||
- `agents.defaults.*` 用于分块流式传输和分块默认值。
|
||||
- 渠道覆盖(`channels.whatsapp.*`、`channels.telegram.*` 等)用于上限和流式传输开关。
|
||||
|
||||
完整配置结构请参见[配置](/gateway/configuration)。
|
||||
完整 schema 参见[配置](/gateway/configuration)。
|
||||
|
||||
## 入站去重
|
||||
|
||||
渠道在重新连接后可能会重新投递相同的消息。OpenClaw 维护一个短期缓存,以渠道/账号/对端/会话/消息 ID 为键,避免重复投递触发额外的智能体运行。
|
||||
渠道可能在重新连接后重复投递同一消息。OpenClaw 保持一个短期缓存,以渠道/账户/对端/会话/消息 ID 为键,因此重复投递不会触发另一次智能体运行。
|
||||
|
||||
## 入站防抖
|
||||
|
||||
来自**同一发送者**的快速连续消息可以通过 `messages.inbound` 合并为单个智能体轮次。防抖按渠道 + 对话维度隔离,并使用最新消息进行回复线程/ID 关联。
|
||||
来自**同一发送者**的快速连续消息可以通过 `messages.inbound` 批量合并为单个智能体轮次。防抖按渠道 + 会话为范围,并使用最近的消息进行回复线程/ID 处理。
|
||||
|
||||
配置(全局默认 + 按渠道覆盖):
|
||||
配置(全局默认 + 单渠道覆盖):
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -61,54 +61,54 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
注意事项:
|
||||
|
||||
- 防抖仅适用于**纯文本**消息;媒体/附件会立即发送。
|
||||
- 控制命令会绕过防抖,保持为独立消息。
|
||||
- 防抖仅适用于**纯文本**消息;媒体/附件会立即刷新。
|
||||
- 控制命令会绕过防抖,保持独立。
|
||||
|
||||
## 会话与设备
|
||||
## 会话和设备
|
||||
|
||||
会话由 Gateway网关管理,而非由客户端管理。
|
||||
会话由 Gateway 网关拥有,而非客户端。
|
||||
|
||||
- 私聊消息归并到智能体的主会话键。
|
||||
- 群组/频道拥有各自独立的会话键。
|
||||
- 会话存储和对话记录保存在 Gateway网关主机上。
|
||||
- 直接聊天合并到智能体主会话密钥。
|
||||
- 群组/渠道获得各自的会话密钥。
|
||||
- 会话存储和记录保存在 Gateway 网关主机上。
|
||||
|
||||
多个设备/渠道可以映射到同一个会话,但历史记录不会完全同步回每个客户端。建议:长对话使用一个主要设备,以避免上下文分歧。控制界面和 TUI 始终显示 Gateway网关端的会话记录,因此它们是权威数据源。
|
||||
多个设备/渠道可以映射到同一会话,但历史记录不会完全同步回每个客户端。建议:对长对话使用一个主设备,以避免上下文分歧。控制 UI 和 TUI 始终显示 Gateway 网关支持的会话记录,因此它们是事实来源。
|
||||
|
||||
详情请参见:[会话管理](/concepts/session)。
|
||||
详情:[会话管理](/concepts/session)。
|
||||
|
||||
## 入站消息体和历史上下文
|
||||
## 入站正文和历史上下文
|
||||
|
||||
OpenClaw 将**提示词体**与**命令体**分开处理:
|
||||
OpenClaw 将**提示正文**与**命令正文**分开:
|
||||
|
||||
- `Body`:发送给智能体的提示词文本。可能包含渠道信封和可选的历史包装。
|
||||
- `Body`:发送给智能体的提示文本。这可能包括渠道信封和可选的历史包装器。
|
||||
- `CommandBody`:用于指令/命令解析的原始用户文本。
|
||||
- `RawBody`:`CommandBody` 的旧版别名(保留以兼容)。
|
||||
- `RawBody`:`CommandBody` 的旧别名(为兼容性保留)。
|
||||
|
||||
当渠道提供历史记录时,使用共享的包装格式:
|
||||
当渠道提供历史记录时,使用共享包装器:
|
||||
|
||||
- `[Chat messages since your last reply - for context]`
|
||||
- `[Current message - respond to this]`
|
||||
|
||||
对于**非私聊**(群组/频道/房间),**当前消息体**会添加发送者标签前缀(与历史条目使用相同的格式)。这使得实时消息和排队/历史消息在智能体提示词中保持一致。
|
||||
对于**非直接聊天**(群组/渠道/房间),**当前消息正文**会加上发送者标签前缀(与历史条目使用的样式相同)。这使智能体提示中的实时消息和队列/历史消息保持一致。
|
||||
|
||||
历史缓冲区为**仅待处理消息**:它们包含未触发运行的群组消息(例如,提及门控的消息),并**排除**已在会话记录中的消息。
|
||||
历史缓冲区是**仅待处理的**:它们包含*未*触发运行的群组消息(例如,提及门控的消息),并**排除**已在会话记录中的消息。
|
||||
|
||||
指令剥离仅适用于**当前消息**部分,历史记录保持不变。包装历史记录的渠道应将 `CommandBody`(或 `RawBody`)设置为原始消息文本,并将 `Body` 保留为组合提示词。历史缓冲区可通过 `messages.groupChat.historyLimit`(全局默认)和按渠道覆盖进行配置,例如 `channels.slack.historyLimit` 或 `channels.telegram.accounts.<id>.historyLimit`(设置为 `0` 可禁用)。
|
||||
指令剥离仅适用于**当前消息**部分,因此历史记录保持完整。包装历史记录的渠道应将 `CommandBody`(或 `RawBody`)设置为原始消息文本,并将 `Body` 保留为组合提示。历史缓冲区可通过 `messages.groupChat.historyLimit`(全局默认)和单渠道覆盖(如 `channels.slack.historyLimit` 或 `channels.telegram.accounts.<id>.historyLimit`)进行配置(设置 `0` 表示禁用)。
|
||||
|
||||
## 队列与后续消息
|
||||
## 队列和后续消息
|
||||
|
||||
如果已有运行中的任务,入站消息可以排队、引导至当前运行,或收集用于后续轮次。
|
||||
如果运行已在进行中,入站消息可以排队、导入当前运行,或收集用于后续轮次。
|
||||
|
||||
- 通过 `messages.queue`(及 `messages.queue.byChannel`)进行配置。
|
||||
- 模式:`interrupt`、`steer`、`followup`、`collect`,以及 backlog 变体。
|
||||
- 通过 `messages.queue`(和 `messages.queue.byChannel`)配置。
|
||||
- 模式:`interrupt`、`steer`、`followup`、`collect`,以及积压变体。
|
||||
|
||||
详情请参见:[队列](/concepts/queue)。
|
||||
详情:[队列](/concepts/queue)。
|
||||
|
||||
## 流式传输、分块与批处理
|
||||
## 流式传输、分块和批处理
|
||||
|
||||
块流式传输在模型生成文本块时发送部分回复。分块遵循渠道文本限制,避免拆分代码围栏。
|
||||
分块流式传输在模型生成文本块时发送部分回复。分块遵循渠道文本限制,避免拆分围栏代码。
|
||||
|
||||
关键设置:
|
||||
|
||||
@@ -116,26 +116,26 @@ OpenClaw 将**提示词体**与**命令体**分开处理:
|
||||
- `agents.defaults.blockStreamingBreak`(`text_end|message_end`)
|
||||
- `agents.defaults.blockStreamingChunk`(`minChars|maxChars|breakPreference`)
|
||||
- `agents.defaults.blockStreamingCoalesce`(基于空闲的批处理)
|
||||
- `agents.defaults.humanDelay`(块回复之间的仿人类停顿)
|
||||
- `agents.defaults.humanDelay`(块回复之间的拟人化暂停)
|
||||
- 渠道覆盖:`*.blockStreaming` 和 `*.blockStreamingCoalesce`(非 Telegram 渠道需要显式设置 `*.blockStreaming: true`)
|
||||
|
||||
详情请参见:[流式传输 + 分块](/concepts/streaming)。
|
||||
详情:[流式传输 + 分块](/concepts/streaming)。
|
||||
|
||||
## 推理可见性与令牌
|
||||
## 推理可见性和 token
|
||||
|
||||
OpenClaw 可以显示或隐藏模型推理过程:
|
||||
OpenClaw 可以显示或隐藏模型推理:
|
||||
|
||||
- `/reasoning on|off|stream` 控制可见性。
|
||||
- 推理内容在模型生成时仍然计入令牌用量。
|
||||
- Telegram 支持将推理过程流式传输到草稿气泡中。
|
||||
- 当模型产生推理内容时,它仍计入 token 使用量。
|
||||
- Telegram 支持将推理流式传输到草稿气泡中。
|
||||
|
||||
详情请参见:[思考 + 推理指令](/tools/thinking) 和 [令牌用量](/token-use)。
|
||||
详情:[思考 + 推理指令](/tools/thinking)和 [Token 使用](/token-use)。
|
||||
|
||||
## 前缀、线程与回复
|
||||
## 前缀、线程和回复
|
||||
|
||||
出站消息格式集中在 `messages` 中管理:
|
||||
出站消息格式在 `messages` 中集中配置:
|
||||
|
||||
- `messages.responsePrefix`(出站前缀)和 `channels.whatsapp.messagePrefix`(WhatsApp 入站前缀)
|
||||
- 通过 `replyToMode` 和按渠道默认值进行回复线程关联
|
||||
- 通过 `replyToMode` 和单渠道默认值进行回复线程
|
||||
|
||||
详情请参见:[配置](/gateway/configuration#messages) 和各渠道文档。
|
||||
详情:[配置](/gateway/configuration#messages)和渠道文档。
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
read_when:
|
||||
- 诊断认证配置文件轮换、冷却期或模型回退行为
|
||||
- 诊断认证配置文件轮换、冷却时间或模型回退行为
|
||||
- 更新认证配置文件或模型的故障转移规则
|
||||
summary: OpenClaw 如何轮换认证配置文件并在模型之间进行故障回退
|
||||
summary: OpenClaw 如何轮换认证配置文件并在模型之间进行回退
|
||||
title: 模型故障转移
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:02Z"
|
||||
generated_at: "2026-02-03T07:46:17Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: eab7c0633824d941cf0d6ce4294f0bc8747fbba2ce93650e9643eca327cd04a9
|
||||
source_path: concepts/model-failover.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 模型故障转移
|
||||
@@ -20,78 +20,70 @@ OpenClaw 分两个阶段处理故障:
|
||||
1. 在当前提供商内进行**认证配置文件轮换**。
|
||||
2. **模型回退**到 `agents.defaults.model.fallbacks` 中的下一个模型。
|
||||
|
||||
本文档介绍运行时规则及其背后的数据。
|
||||
本文档解释运行时规则及其背后的数据。
|
||||
|
||||
## 认证存储(密钥 + OAuth)
|
||||
|
||||
OpenClaw 对 API 密钥和 OAuth 令牌都使用**认证配置文件**。
|
||||
|
||||
- 密钥存储在 `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`(旧版路径:`~/.openclaw/agent/auth-profiles.json`)。
|
||||
- 配置项 `auth.profiles` / `auth.order` **仅包含元数据和路由信息**(不含密钥)。
|
||||
- 旧版仅导入的 OAuth 文件:`~/.openclaw/credentials/oauth.json`(首次使用时导入到 `auth-profiles.json`)。
|
||||
- 密钥存储在 `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`(旧版:`~/.openclaw/agent/auth-profiles.json`)。
|
||||
- 配置 `auth.profiles` / `auth.order` **仅用于元数据和路由**(不含密钥)。
|
||||
- 旧版仅导入 OAuth 文件:`~/.openclaw/credentials/oauth.json`(首次使用时导入到 `auth-profiles.json`)。
|
||||
|
||||
更多详情:[/concepts/oauth](/concepts/oauth)
|
||||
|
||||
凭证类型:
|
||||
|
||||
- `type: "api_key"` → `{ provider, key }`
|
||||
- `type: "oauth"` → `{ provider, access, refresh, expires, email? }`(部分提供商还包含 `projectId`/`enterpriseUrl`)
|
||||
- `type: "oauth"` → `{ provider, access, refresh, expires, email? }`(某些提供商还有 `projectId`/`enterpriseUrl`)
|
||||
|
||||
## 配置文件 ID
|
||||
|
||||
OAuth 登录会创建不同的配置文件,以便多个账户共存。
|
||||
OAuth 登录创建不同的配置文件,以便多个账户可以共存。
|
||||
|
||||
- 默认值:当没有可用邮箱时为 `provider:default`。
|
||||
- 带邮箱的 OAuth:`provider:<email>`(例如 `google-antigravity:user@gmail.com`)。
|
||||
- 默认:当没有电子邮件可用时为 `provider:default`。
|
||||
- 带电子邮件的 OAuth:`provider:<email>`(例如 `google-antigravity:user@gmail.com`)。
|
||||
|
||||
配置文件存储在 `~/.openclaw/agents/<agentId>/agent/auth-profiles.json` 的 `profiles` 下。
|
||||
|
||||
## 轮换顺序
|
||||
|
||||
当一个提供商有多个配置文件时,OpenClaw 按如下方式选择顺序:
|
||||
当一个提供商有多个配置文件时,OpenClaw 按以下顺序选择:
|
||||
|
||||
1. **显式配置**:`auth.order[provider]`(如果已设置)。
|
||||
1. **显式配置**:`auth.order[provider]`(如果设置)。
|
||||
2. **已配置的配置文件**:按提供商过滤的 `auth.profiles`。
|
||||
3. **已存储的配置文件**:`auth-profiles.json` 中该提供商的条目。
|
||||
|
||||
如果未配置显式顺序,OpenClaw 使用轮询顺序:
|
||||
如果没有配置显式顺序,OpenClaw 使用轮询顺序:
|
||||
|
||||
- **主排序键:** 配置文件类型(**OAuth 优先于 API 密钥**)。
|
||||
- **次排序键:** `usageStats.lastUsed`(同类型内最旧的优先)。
|
||||
- **冷却中/已禁用的配置文件**被移到末尾,按最早到期时间排序。
|
||||
- **主键:** 配置文件类型(**OAuth 优先于 API 密钥**)。
|
||||
- **次键:** `usageStats.lastUsed`(每种类型中最旧的优先)。
|
||||
- **冷却/禁用的配置文件**会移到末尾,按最早过期时间排序。
|
||||
|
||||
### 会话粘性(缓存友好)
|
||||
|
||||
OpenClaw 会**在每个会话中固定选定的认证配置文件**,以保持提供商缓存活跃。
|
||||
它**不会**在每次请求时轮换。固定的配置文件会持续使用,直到:
|
||||
OpenClaw **为每个会话固定所选的认证配置文件**以保持提供商缓存热度。它**不会**在每个请求时轮换。固定的配置文件会被重用直到:
|
||||
|
||||
- 会话被重置(`/new` / `/reset`)
|
||||
- 压缩完成(压缩计数递增)
|
||||
- 配置文件处于冷却中/已禁用状态
|
||||
- 配置文件处于冷却/禁用状态
|
||||
|
||||
通过 `/model …@<profileId>` 手动选择会为该会话设置一个**用户覆盖**,
|
||||
在新会话开始前不会自动轮换。
|
||||
通过 `/model …@<profileId>` 手动选择会为该会话设置**用户覆盖**,在新会话开始之前不会自动轮换。
|
||||
|
||||
自动固定的配置文件(由会话路由器选择)被视为一种**偏好**:
|
||||
它们会优先尝试,但 OpenClaw 可能在遇到速率限制/超时时轮换到其他配置文件。
|
||||
用户固定的配置文件会锁定在该配置文件上;如果它失败且配置了模型回退,
|
||||
OpenClaw 会转移到下一个模型,而不是切换配置文件。
|
||||
自动固定的配置文件(由会话路由器选择)被视为**偏好**:它们会优先尝试,但 OpenClaw 可能在速率限制/超时时轮换到另一个配置文件。用户固定的配置文件会锁定到该配置文件;如果失败且配置了模型回退,OpenClaw 会移动到下一个模型而不是切换配置文件。
|
||||
|
||||
### 为什么 OAuth 可能"看起来丢失了"
|
||||
### 为什么 OAuth 可能"看起来丢失"
|
||||
|
||||
如果你对同一个提供商同时拥有 OAuth 配置文件和 API 密钥配置文件,轮询可能在消息之间切换它们(除非已固定)。要强制使用单个配置文件:
|
||||
如果你为同一个提供商同时拥有 OAuth 配置文件和 API 密钥配置文件,除非固定,否则轮询可能在消息之间切换它们。要强制使用单个配置文件:
|
||||
|
||||
- 通过 `auth.order[provider] = ["provider:profileId"]` 固定,或
|
||||
- 通过 `/model …` 使用按会话覆盖并指定配置文件(当你的 UI/聊天界面支持时)。
|
||||
- 使用 `auth.order[provider] = ["provider:profileId"]` 固定,或
|
||||
- 通过 `/model …` 使用每会话覆盖并指定配置文件覆盖(当你的 UI/聊天界面支持时)。
|
||||
|
||||
## 冷却期
|
||||
## 冷却时间
|
||||
|
||||
当配置文件因认证/速率限制错误(或看起来像速率限制的超时)而失败时,
|
||||
OpenClaw 会将其标记为冷却状态并移至下一个配置文件。
|
||||
格式/无效请求错误(例如 Cloud Code Assist 工具调用 ID
|
||||
验证失败)也被视为可故障转移的,并使用相同的冷却机制。
|
||||
当配置文件因认证/速率限制错误(或看起来像速率限制的超时)而失败时,OpenClaw 将其标记为冷却状态并移动到下一个配置文件。格式/无效请求错误(例如 Cloud Code Assist 工具调用 ID 验证失败)被视为值得故障转移的情况,使用相同的冷却时间。
|
||||
|
||||
冷却期使用指数退避:
|
||||
冷却时间使用指数退避:
|
||||
|
||||
- 1 分钟
|
||||
- 5 分钟
|
||||
@@ -112,9 +104,9 @@ OpenClaw 会将其标记为冷却状态并移至下一个配置文件。
|
||||
}
|
||||
```
|
||||
|
||||
## 计费禁用
|
||||
## 账单禁用
|
||||
|
||||
计费/额度失败(例如"额度不足"/"信用余额过低")被视为可故障转移的,但通常不是临时性的。OpenClaw 不会使用短冷却期,而是将配置文件标记为**已禁用**(使用更长的退避时间)并轮换到下一个配置文件/提供商。
|
||||
账单/额度失败(例如"insufficient credits"/"credit balance too low")被视为值得故障转移的情况,但它们通常不是暂时性的。OpenClaw 不使用短冷却时间,而是将配置文件标记为**禁用**(使用更长的退避时间)并轮换到下一个配置文件/提供商。
|
||||
|
||||
状态存储在 `auth-profiles.json` 中:
|
||||
|
||||
@@ -131,21 +123,18 @@ OpenClaw 会将其标记为冷却状态并移至下一个配置文件。
|
||||
|
||||
默认值:
|
||||
|
||||
- 计费退避从 **5 小时**开始,每次计费失败加倍,上限为 **24 小时**。
|
||||
- 如果配置文件在 **24 小时**内未失败,退避计数器将重置(可配置)。
|
||||
- 账单退避从 **5 小时**开始,每次账单失败翻倍,上限为 **24 小时**。
|
||||
- 如果配置文件 **24 小时**内没有失败,退避计数器会重置(可配置)。
|
||||
|
||||
## 模型回退
|
||||
|
||||
如果某个提供商的所有配置文件都失败,OpenClaw 会移至
|
||||
`agents.defaults.model.fallbacks` 中的下一个模型。这适用于认证失败、速率限制和
|
||||
耗尽配置文件轮换的超时情况(其他错误不会触发回退)。
|
||||
如果某个提供商的所有配置文件都失败,OpenClaw 会移动到 `agents.defaults.model.fallbacks` 中的下一个模型。这适用于认证失败、速率限制和耗尽配置文件轮换的超时(其他错误不会推进回退)。
|
||||
|
||||
当运行以模型覆盖(钩子或 CLI)启动时,回退仍会在尝试所有已配置的回退后
|
||||
止于 `agents.defaults.model.primary`。
|
||||
当运行以模型覆盖(钩子或 CLI)开始时,在尝试任何配置的回退之后,回退仍会在 `agents.defaults.model.primary` 处结束。
|
||||
|
||||
## 相关配置
|
||||
|
||||
参阅 [Gateway网关配置](/gateway/configuration) 了解:
|
||||
参阅 [Gateway 网关配置](/gateway/configuration) 了解:
|
||||
|
||||
- `auth.profiles` / `auth.order`
|
||||
- `auth.cooldowns.billingBackoffHours` / `auth.cooldowns.billingBackoffHoursByProvider`
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要按提供商查阅模型设置参考
|
||||
- 你需要按提供商分类的模型设置参考
|
||||
- 你需要模型提供商的示例配置或 CLI 新手引导命令
|
||||
summary: 模型提供商概览,包含示例配置和 CLI 流程
|
||||
summary: 模型提供商概述,包含示例配置和 CLI 流程
|
||||
title: 模型提供商
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:13Z"
|
||||
generated_at: "2026-02-03T07:46:28Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: b3940c91ce3aee3d701af7978284966a60ec8c669649cc4be48ba9472243e444
|
||||
source_hash: 14f73e5a9f9b7c6f017d59a54633942dba95a3eb50f8848b836cfe0b9f6d7719
|
||||
source_path: concepts/model-providers.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 模型提供商
|
||||
|
||||
本页介绍 **LLM/模型提供商**(非 WhatsApp/Telegram 等聊天渠道)。
|
||||
有关模型选择规则,请参见 [/concepts/models](/concepts/models)。
|
||||
本页介绍 **LLM/模型提供商**(不是 WhatsApp/Telegram 等聊天渠道)。
|
||||
关于模型选择规则,请参阅 [/concepts/models](/concepts/models)。
|
||||
|
||||
## 快速规则
|
||||
|
||||
- 模型引用使用 `provider/model` 格式(例如:`opencode/claude-opus-4-5`)。
|
||||
- 如果设置了 `agents.defaults.models`,它将成为白名单。
|
||||
- CLI 辅助命令:`openclaw onboard`、`openclaw models list`、`openclaw models set <provider/model>`。
|
||||
- 如果设置了 `agents.defaults.models`,它将成为允许列表。
|
||||
- CLI 辅助工具:`openclaw onboard`、`openclaw models list`、`openclaw models set <provider/model>`。
|
||||
|
||||
## 内置提供商(pi-ai 目录)
|
||||
|
||||
OpenClaw 自带 pi‑ai 目录。这些提供商**无需**配置 `models.providers`;只需设置认证并选择模型即可。
|
||||
OpenClaw 附带 pi-ai 目录。这些提供商**不需要** `models.providers` 配置;只需设置认证 + 选择模型。
|
||||
|
||||
### OpenAI
|
||||
|
||||
@@ -97,7 +97,7 @@ OpenClaw 自带 pi‑ai 目录。这些提供商**无需**配置 `models.provide
|
||||
- Gemini CLI OAuth 作为捆绑插件提供(`google-gemini-cli-auth`,默认禁用)。
|
||||
- 启用:`openclaw plugins enable google-gemini-cli-auth`
|
||||
- 登录:`openclaw models auth login --provider google-gemini-cli --set-default`
|
||||
- 注意:你**无需**将客户端 ID 或密钥粘贴到 `openclaw.json` 中。CLI 登录流程会将令牌存储在 Gateway网关主机的认证配置文件中。
|
||||
- 注意:你**不需要**将客户端 ID 或密钥粘贴到 `openclaw.json` 中。CLI 登录流程将令牌存储在 Gateway 网关主机的认证配置文件中。
|
||||
|
||||
### Z.AI (GLM)
|
||||
|
||||
@@ -105,7 +105,7 @@ OpenClaw 自带 pi‑ai 目录。这些提供商**无需**配置 `models.provide
|
||||
- 认证:`ZAI_API_KEY`
|
||||
- 示例模型:`zai/glm-4.7`
|
||||
- CLI:`openclaw onboard --auth-choice zai-api-key`
|
||||
- 别名:`z.ai/*` 和 `z-ai/*` 会规范化为 `zai/*`
|
||||
- 别名:`z.ai/*` 和 `z-ai/*` 规范化为 `zai/*`
|
||||
|
||||
### Vercel AI Gateway
|
||||
|
||||
@@ -137,14 +137,17 @@ Moonshot 使用 OpenAI 兼容端点,因此将其配置为自定义提供商:
|
||||
- 提供商:`moonshot`
|
||||
- 认证:`MOONSHOT_API_KEY`
|
||||
- 示例模型:`moonshot/kimi-k2.5`
|
||||
- Kimi K2 模型 ID:
|
||||
{/_ moonshot-kimi-k2-model-refs:start _/}
|
||||
- `moonshot/kimi-k2.5`
|
||||
- `moonshot/kimi-k2-0905-preview`
|
||||
- `moonshot/kimi-k2-turbo-preview`
|
||||
- `moonshot/kimi-k2-thinking`
|
||||
- `moonshot/kimi-k2-thinking-turbo`
|
||||
{/_ moonshot-kimi-k2-model-refs:end _/}
|
||||
|
||||
Kimi K2 模型 ID:
|
||||
|
||||
{/_ moonshot-kimi-k2-model-refs:start _/ && null}
|
||||
|
||||
- `moonshot/kimi-k2.5`
|
||||
- `moonshot/kimi-k2-0905-preview`
|
||||
- `moonshot/kimi-k2-turbo-preview`
|
||||
- `moonshot/kimi-k2-thinking`
|
||||
- `moonshot/kimi-k2-thinking-turbo`
|
||||
{/_ moonshot-kimi-k2-model-refs:end _/ && null}
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -182,7 +185,7 @@ Kimi Coding 使用 Moonshot AI 的 Anthropic 兼容端点:
|
||||
}
|
||||
```
|
||||
|
||||
### Qwen OAuth(免费版)
|
||||
### Qwen OAuth(免费层级)
|
||||
|
||||
Qwen 通过设备码流程提供对 Qwen Coder + Vision 的 OAuth 访问。
|
||||
启用捆绑插件,然后登录:
|
||||
@@ -197,11 +200,11 @@ openclaw models auth login --provider qwen-portal --set-default
|
||||
- `qwen-portal/coder-model`
|
||||
- `qwen-portal/vision-model`
|
||||
|
||||
详见 [/providers/qwen](/providers/qwen) 了解设置详情和注意事项。
|
||||
参见 [/providers/qwen](/providers/qwen) 了解设置详情和注意事项。
|
||||
|
||||
### Synthetic
|
||||
|
||||
Synthetic 在 `synthetic` 提供商下提供 Anthropic 兼容的模型:
|
||||
Synthetic 通过 `synthetic` 提供商提供 Anthropic 兼容模型:
|
||||
|
||||
- 提供商:`synthetic`
|
||||
- 认证:`SYNTHETIC_API_KEY`
|
||||
@@ -234,11 +237,11 @@ MiniMax 通过 `models.providers` 配置,因为它使用自定义端点:
|
||||
- MiniMax(Anthropic 兼容):`--auth-choice minimax-api`
|
||||
- 认证:`MINIMAX_API_KEY`
|
||||
|
||||
详见 [/providers/minimax](/providers/minimax) 了解设置详情、模型选项和配置片段。
|
||||
参见 [/providers/minimax](/providers/minimax) 了解设置详情、模型选项和配置片段。
|
||||
|
||||
### Ollama
|
||||
|
||||
Ollama 是一个本地 LLM 运行时,提供 OpenAI 兼容的 API:
|
||||
Ollama 是提供 OpenAI 兼容 API 的本地 LLM 运行时:
|
||||
|
||||
- 提供商:`ollama`
|
||||
- 认证:无需(本地服务器)
|
||||
@@ -246,7 +249,7 @@ Ollama 是一个本地 LLM 运行时,提供 OpenAI 兼容的 API:
|
||||
- 安装:https://ollama.ai
|
||||
|
||||
```bash
|
||||
# 安装 Ollama,然后拉取模型:
|
||||
# Install Ollama, then pull a model:
|
||||
ollama pull llama3.3
|
||||
```
|
||||
|
||||
@@ -258,7 +261,7 @@ ollama pull llama3.3
|
||||
}
|
||||
```
|
||||
|
||||
Ollama 在本地运行于 `http://127.0.0.1:11434/v1` 时会被自动检测。详见 [/providers/ollama](/providers/ollama) 了解模型推荐和自定义配置。
|
||||
当 Ollama 在本地 `http://127.0.0.1:11434/v1` 运行时会自动检测。参见 [/providers/ollama](/providers/ollama) 了解模型推荐和自定义配置。
|
||||
|
||||
### 本地代理(LM Studio、vLLM、LiteLLM 等)
|
||||
|
||||
@@ -304,7 +307,7 @@ Ollama 在本地运行于 `http://127.0.0.1:11434/v1` 时会被自动检测。
|
||||
- `cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }`
|
||||
- `contextWindow: 200000`
|
||||
- `maxTokens: 8192`
|
||||
- 建议:设置与你的代理/模型限制匹配的明确值。
|
||||
- 建议:设置与你的代理/模型限制匹配的显式值。
|
||||
|
||||
## CLI 示例
|
||||
|
||||
@@ -314,4 +317,4 @@ openclaw models set opencode/claude-opus-4-5
|
||||
openclaw models list
|
||||
```
|
||||
|
||||
另请参见:[/gateway/configuration](/gateway/configuration) 了解全部配置示例。
|
||||
另请参阅:[/gateway/configuration](/gateway/configuration) 了解完整配置示例。
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
---
|
||||
read_when:
|
||||
- 添加或修改模型 CLI(models list/set/scan/aliases/fallbacks)
|
||||
- 更改模型回退行为或选择体验
|
||||
- 更改模型回退行为或选择用户体验
|
||||
- 更新模型扫描探测(工具/图像)
|
||||
summary: 模型 CLI:列表、设置、别名、回退、扫描、状态
|
||||
title: 模型 CLI
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:26Z"
|
||||
generated_at: "2026-02-03T10:05:42Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: e8b54bb370b4f63a9b917594fb0f6ff48192e168196d30c713b8bbe72b78fef6
|
||||
source_path: concepts/models.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 模型 CLI
|
||||
|
||||
认证配置轮换、冷却时间以及与回退的交互方式请参见 [/concepts/model-failover](/concepts/model-failover)。
|
||||
提供商快速概览 + 示例:[/concepts/model-providers](/concepts/model-providers)。
|
||||
参见 [/concepts/model-failover](/concepts/model-failover) 了解认证配置文件轮换、冷却时间及其与回退的交互。
|
||||
快速提供商概述 + 示例:[/concepts/model-providers](/concepts/model-providers)。
|
||||
|
||||
## 模型选择的工作方式
|
||||
## 模型选择工作原理
|
||||
|
||||
OpenClaw 按以下顺序选择模型:
|
||||
|
||||
1. **主模型**(`agents.defaults.model.primary` 或 `agents.defaults.model`)。
|
||||
2. `agents.defaults.model.fallbacks` 中的**回退模型**(按顺序)。
|
||||
3. **提供商认证故障转移**在切换到下一个模型之前,会先在提供商内部进行。
|
||||
1. **主要**模型(`agents.defaults.model.primary` 或 `agents.defaults.model`)。
|
||||
2. `agents.defaults.model.fallbacks` 中的**回退**(按顺序)。
|
||||
3. **提供商认证故障转移**在移动到下一个模型之前在提供商内部发生。
|
||||
|
||||
相关说明:
|
||||
相关:
|
||||
|
||||
- `agents.defaults.models` 是 OpenClaw 可使用的模型白名单/目录(含别名)。
|
||||
- `agents.defaults.imageModel` **仅在**主模型无法处理图像时使用。
|
||||
- `agents.defaults.models` 是 OpenClaw 可使用的模型白名单/目录(加上别名)。
|
||||
- `agents.defaults.imageModel` **仅在**主要模型无法接受图像时使用。
|
||||
- 每个智能体的默认值可以通过 `agents.list[].model` 加绑定覆盖 `agents.defaults.model`(参见 [/concepts/multi-agent](/concepts/multi-agent))。
|
||||
|
||||
## 快速模型推荐(经验之谈)
|
||||
|
||||
- **GLM**:在编码/工具调用方面稍好。
|
||||
- **MiniMax**:在写作和风格表现方面更好。
|
||||
- **GLM**:在编程/工具调用方面稍好。
|
||||
- **MiniMax**:在写作和氛围方面更好。
|
||||
|
||||
## 设置向导(推荐)
|
||||
|
||||
如果不想手动编辑配置,可以运行新手引导向导:
|
||||
如果你不想手动编辑配置,请运行新手引导向导:
|
||||
|
||||
```bash
|
||||
openclaw onboard
|
||||
```
|
||||
|
||||
它可以为常见提供商设置模型和认证,包括 **OpenAI Code (Codex) 订阅**(OAuth)和 **Anthropic**(推荐使用 API 密钥;也支持 `claude setup-token`)。
|
||||
它可以为常见提供商设置模型 + 认证,包括 **OpenAI Code(Codex)订阅**(OAuth)和 **Anthropic**(推荐使用 API 密钥;也支持 `claude setup-token`)。
|
||||
|
||||
## 配置键(概览)
|
||||
## 配置键(概述)
|
||||
|
||||
- `agents.defaults.model.primary` 和 `agents.defaults.model.fallbacks`
|
||||
- `agents.defaults.imageModel.primary` 和 `agents.defaults.imageModel.fallbacks`
|
||||
- `agents.defaults.models`(白名单 + 别名 + 提供商参数)
|
||||
- `models.providers`(写入 `models.json` 的自定义提供商)
|
||||
|
||||
模型引用会被统一转为小写。提供商别名如 `z.ai/*` 会被规范化为 `zai/*`。
|
||||
模型引用会规范化为小写。提供商别名如 `z.ai/*` 会规范化为 `zai/*`。
|
||||
|
||||
提供商配置示例(包括 OpenCode Zen)请参见 [/gateway/configuration](/gateway/configuration#opencode-zen-multi-model-proxy)。
|
||||
提供商配置示例(包括 OpenCode Zen)在 [/gateway/configuration](/gateway/configuration#opencode-zen-multi-model-proxy)。
|
||||
|
||||
## "Model is not allowed"(以及为什么回复停止)
|
||||
|
||||
如果设置了 `agents.defaults.models`,它将成为 `/model` 和会话覆盖的**白名单**。当用户选择了不在白名单中的模型时,OpenClaw 会返回:
|
||||
如果设置了 `agents.defaults.models`,它将成为 `/model` 和会话覆盖的**白名单**。当用户选择不在该白名单中的模型时,OpenClaw 返回:
|
||||
|
||||
```
|
||||
Model "provider/model" is not allowed. Use /model to list available models.
|
||||
```
|
||||
|
||||
这发生在正常回复生成**之前**,因此消息看起来可能像是"没有响应"。修复方法是:
|
||||
这发生在正常回复生成**之前**,所以消息可能感觉像"没有响应"。修复方法是:
|
||||
|
||||
- 将该模型添加到 `agents.defaults.models`,或
|
||||
- 清除白名单(移除 `agents.defaults.models`),或
|
||||
- 将模型添加到 `agents.defaults.models`,或
|
||||
- 清除白名单(删除 `agents.defaults.models`),或
|
||||
- 从 `/model list` 中选择一个模型。
|
||||
|
||||
白名单配置示例:
|
||||
@@ -89,7 +89,7 @@ Model "provider/model" is not allowed. Use /model to list available models.
|
||||
|
||||
## 在聊天中切换模型(`/model`)
|
||||
|
||||
你可以在当前会话中切换模型而无需重启:
|
||||
你可以在不重启的情况下切换当前会话的模型:
|
||||
|
||||
```
|
||||
/model
|
||||
@@ -99,14 +99,14 @@ Model "provider/model" is not allowed. Use /model to list available models.
|
||||
/model status
|
||||
```
|
||||
|
||||
说明:
|
||||
注意事项:
|
||||
|
||||
- `/model`(和 `/model list`)是一个紧凑的编号选择器(模型系列 + 可用提供商)。
|
||||
- `/model`(和 `/model list`)是紧凑的编号选择器(模型系列 + 可用提供商)。
|
||||
- `/model <#>` 从该选择器中选择。
|
||||
- `/model status` 是详细视图(认证候选项,以及配置后的提供商端点 `baseUrl` + `api` 模式)。
|
||||
- 模型引用通过**第一个** `/` 进行分割解析。输入 `/model <ref>` 时请使用 `provider/model` 格式。
|
||||
- 如果模型 ID 本身包含 `/`(OpenRouter 风格),必须包含提供商前缀(例如:`/model openrouter/moonshotai/kimi-k2`)。
|
||||
- 如果省略提供商,OpenClaw 会将输入视为别名或**默认提供商**的模型(仅在模型 ID 中不含 `/` 时有效)。
|
||||
- `/model status` 是详细视图(认证候选项,以及配置时的提供商端点 `baseUrl` + `api` 模式)。
|
||||
- 模型引用通过在**第一个** `/` 处分割来解析。输入 `/model <ref>` 时使用 `provider/model`。
|
||||
- 如果模型 ID 本身包含 `/`(OpenRouter 风格),你必须包含提供商前缀(例如:`/model openrouter/moonshotai/kimi-k2`)。
|
||||
- 如果省略提供商,OpenClaw 将输入视为别名或**默认提供商**的模型(仅在模型 ID 中没有 `/` 时有效)。
|
||||
|
||||
完整命令行为/配置:[斜杠命令](/tools/slash-commands)。
|
||||
|
||||
@@ -137,7 +137,7 @@ openclaw models image-fallbacks clear
|
||||
|
||||
### `models list`
|
||||
|
||||
默认显示已配置的模型。常用标志:
|
||||
默认显示已配置的模型。有用的标志:
|
||||
|
||||
- `--all`:完整目录
|
||||
- `--local`:仅本地提供商
|
||||
@@ -147,12 +147,12 @@ openclaw models image-fallbacks clear
|
||||
|
||||
### `models status`
|
||||
|
||||
显示已解析的主模型、回退模型、图像模型,以及已配置提供商的认证概览。还会显示认证存储中找到的 OAuth 配置过期状态(默认在 24 小时内发出警告)。`--plain` 仅打印已解析的主模型。
|
||||
显示已解析的主要模型、回退、图像模型,以及已配置提供商的认证概述。它还显示认证存储中找到的配置文件的 OAuth 过期状态(默认在 24 小时内警告)。`--plain` 仅打印已解析的主要模型。
|
||||
OAuth 状态始终显示(并包含在 `--json` 输出中)。如果已配置的提供商没有凭证,`models status` 会打印 **Missing auth** 部分。
|
||||
JSON 包含 `auth.oauth`(警告窗口 + 配置文件)和 `auth.providers`(每个提供商的有效认证)。
|
||||
使用 `--check` 进行自动化检测(缺失/过期时退出码为 `1`,即将过期时为 `2`)。
|
||||
JSON 包括 `auth.oauth`(警告窗口 + 配置文件)和 `auth.providers`(每个提供商的有效认证)。
|
||||
使用 `--check` 进行自动化(缺失/过期时退出 `1`,即将过期时退出 `2`)。
|
||||
|
||||
推荐的 Anthropic 认证方式是 Claude Code CLI setup-token(可在任何地方运行;如有需要可粘贴到 Gateway网关主机上):
|
||||
首选的 Anthropic 认证是 Claude Code CLI setup-token(在任何地方运行;如需要在 Gateway 网关主机上粘贴):
|
||||
|
||||
```bash
|
||||
claude setup-token
|
||||
@@ -161,9 +161,9 @@ openclaw models status
|
||||
|
||||
## 扫描(OpenRouter 免费模型)
|
||||
|
||||
`openclaw models scan` 检查 OpenRouter 的**免费模型目录**,并可选择性地探测模型的工具和图像支持情况。
|
||||
`openclaw models scan` 检查 OpenRouter 的**免费模型目录**,并可选择性地探测模型的工具和图像支持。
|
||||
|
||||
主要标志:
|
||||
关键标志:
|
||||
|
||||
- `--no-probe`:跳过实时探测(仅元数据)
|
||||
- `--min-params <b>`:最小参数量(十亿)
|
||||
@@ -173,7 +173,7 @@ openclaw models status
|
||||
- `--set-default`:将 `agents.defaults.model.primary` 设置为第一个选择
|
||||
- `--set-image`:将 `agents.defaults.imageModel.primary` 设置为第一个图像选择
|
||||
|
||||
探测需要 OpenRouter API 密钥(来自认证配置或 `OPENROUTER_API_KEY`)。没有密钥时,使用 `--no-probe` 仅列出候选模型。
|
||||
探测需要 OpenRouter API 密钥(来自认证配置文件或 `OPENROUTER_API_KEY`)。没有密钥时,使用 `--no-probe` 仅列出候选项。
|
||||
|
||||
扫描结果按以下顺序排名:
|
||||
|
||||
@@ -185,12 +185,12 @@ openclaw models status
|
||||
输入
|
||||
|
||||
- OpenRouter `/models` 列表(筛选 `:free`)
|
||||
- 需要来自认证配置或 `OPENROUTER_API_KEY` 的 OpenRouter API 密钥(参见 [/environment](/environment))
|
||||
- 需要来自认证配置文件或 `OPENROUTER_API_KEY` 的 OpenRouter API 密钥(参见 [/environment](/environment))
|
||||
- 可选筛选器:`--max-age-days`、`--min-params`、`--provider`、`--max-candidates`
|
||||
- 探测控制:`--timeout`、`--concurrency`
|
||||
|
||||
在 TTY 中运行时,你可以交互式地选择回退模型。在非交互模式下,传入 `--yes` 以接受默认值。
|
||||
在 TTY 中运行时,你可以交互式选择回退。在非交互模式下,传递 `--yes` 接受默认值。
|
||||
|
||||
## 模型注册表(`models.json`)
|
||||
|
||||
`models.providers` 中的自定义提供商会被写入智能体目录下的 `models.json`(默认为 `~/.openclaw/agents/<agentId>/models.json`)。除非 `models.mode` 设置为 `replace`,否则此文件默认会被合并。
|
||||
`models.providers` 中的自定义提供商会写入智能体目录下的 `models.json`(默认 `~/.openclaw/agents/<agentId>/models.json`)。除非 `models.mode` 设置为 `replace`,否则此文件默认会被合并。
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
---
|
||||
read_when: 你希望在一个 Gateway网关进程中运行多个隔离的智能体(工作区 + 认证)。
|
||||
read_when: You want multiple isolated agents (workspaces + auth) in one gateway process.
|
||||
status: active
|
||||
summary: 多智能体路由:隔离的智能体、渠道账户和绑定
|
||||
title: 多智能体路由
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:55Z"
|
||||
generated_at: "2026-02-03T07:47:38Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 1848266c632cd6c96ff99ea9eb9c17bbfe6d35fa1f90450853083e7c548d5324
|
||||
source_path: concepts/multi-agent.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 多智能体路由
|
||||
|
||||
目标:在一个运行中的 Gateway网关中托管多个*隔离的*智能体(独立的工作区 + `agentDir` + 会话),以及多个渠道账户(例如两个 WhatsApp)。入站消息通过绑定路由到对应的智能体。
|
||||
目标:多个*隔离的*智能体(独立的工作区 + `agentDir` + 会话),加上多个渠道账户(例如两个 WhatsApp)在一个运行的 Gateway 网关中。入站消息通过绑定路由到智能体。
|
||||
|
||||
## 什么是"一个智能体"?
|
||||
|
||||
一个**智能体**是一个完全独立作用域的大脑,拥有自己的:
|
||||
|
||||
- **工作区**(文件、AGENTS.md/SOUL.md/USER.md、本地笔记、人设规则)。
|
||||
- **状态目录**(`agentDir`),用于存储认证配置文件、模型注册表和按智能体配置。
|
||||
- **会话存储**(聊天历史 + 路由状态),位于 `~/.openclaw/agents/<agentId>/sessions`。
|
||||
- **状态目录**(`agentDir`)用于认证配置文件、模型注册表和每智能体配置。
|
||||
- **会话存储**(聊天历史 + 路由状态)位于 `~/.openclaw/agents/<agentId>/sessions` 下。
|
||||
|
||||
认证配置文件是**按智能体隔离的**。每个智能体从自己的目录读取:
|
||||
认证配置文件是**每智能体独立的**。每个智能体从自己的位置读取:
|
||||
|
||||
```
|
||||
~/.openclaw/agents/<agentId>/agent/auth-profiles.json
|
||||
```
|
||||
|
||||
主智能体的凭证**不会**自动共享。切勿在智能体之间复用 `agentDir`(会导致认证/会话冲突)。如果你想共享凭证,请将 `auth-profiles.json` 复制到另一个智能体的 `agentDir` 中。
|
||||
主智能体凭证**不会**自动共享。切勿在智能体之间重用 `agentDir`(这会导致认证/会话冲突)。如果你想共享凭证,请将 `auth-profiles.json` 复制到另一个智能体的 `agentDir`。
|
||||
|
||||
Skills 通过每个工作区的 `skills/` 文件夹按智能体隔离,共享 Skills 可从 `~/.openclaw/skills` 获取。参阅[Skills:按智能体 vs 共享](/tools/skills#per-agent-vs-shared-skills)。
|
||||
Skills 通过每个工作区的 `skills/` 文件夹实现每智能体独立,共享的 Skills 可从 `~/.openclaw/skills` 获取。参见 [Skills:每智能体 vs 共享](/tools/skills#per-agent-vs-shared-skills)。
|
||||
|
||||
Gateway网关可以托管**一个智能体**(默认)或**多个智能体**并行运行。
|
||||
Gateway 网关可以托管**一个智能体**(默认)或**多个智能体**并行。
|
||||
|
||||
**工作区说明:** 每个智能体的工作区是**默认工作目录**,而非严格的沙箱。相对路径在工作区内解析,但绝对路径可以访问主机上的其他位置,除非启用了沙箱。参阅[沙箱](/gateway/sandboxing)。
|
||||
**工作区注意事项:** 每个智能体的工作区是**默认 cwd**,而不是硬性沙箱。相对路径在工作区内解析,但绝对路径可以访问主机的其他位置,除非启用了沙箱隔离。参见 [沙箱隔离](/gateway/sandboxing)。
|
||||
|
||||
## 路径(速查)
|
||||
## 路径(快速映射)
|
||||
|
||||
- 配置文件:`~/.openclaw/openclaw.json`(或 `OPENCLAW_CONFIG_PATH`)
|
||||
- 配置:`~/.openclaw/openclaw.json`(或 `OPENCLAW_CONFIG_PATH`)
|
||||
- 状态目录:`~/.openclaw`(或 `OPENCLAW_STATE_DIR`)
|
||||
- 工作区:`~/.openclaw/workspace`(或 `~/.openclaw/workspace-<agentId>`)
|
||||
- 智能体目录:`~/.openclaw/agents/<agentId>/agent`(或 `agents.list[].agentDir`)
|
||||
@@ -48,11 +48,11 @@ Gateway网关可以托管**一个智能体**(默认)或**多个智能体**
|
||||
|
||||
### 单智能体模式(默认)
|
||||
|
||||
如果你不做任何配置,OpenClaw 会运行单个智能体:
|
||||
如果你什么都不做,OpenClaw 运行单个智能体:
|
||||
|
||||
- `agentId` 默认为 **`main`**。
|
||||
- 会话键格式为 `agent:main:<mainKey>`。
|
||||
- 工作区默认为 `~/.openclaw/workspace`(设置了 `OPENCLAW_PROFILE` 时为 `~/.openclaw/workspace-<profile>`)。
|
||||
- 会话键为 `agent:main:<mainKey>`。
|
||||
- 工作区默认为 `~/.openclaw/workspace`(或当设置了 `OPENCLAW_PROFILE` 时为 `~/.openclaw/workspace-<profile>`)。
|
||||
- 状态默认为 `~/.openclaw/agents/main/agent`。
|
||||
|
||||
## 智能体助手
|
||||
@@ -65,27 +65,27 @@ openclaw agents add work
|
||||
|
||||
然后添加 `bindings`(或让向导完成)来路由入站消息。
|
||||
|
||||
验证方式:
|
||||
验证:
|
||||
|
||||
```bash
|
||||
openclaw agents list --bindings
|
||||
```
|
||||
|
||||
## 多智能体 = 多用户、多人设
|
||||
## 多个智能体 = 多个人、多种人格
|
||||
|
||||
使用**多个智能体**时,每个 `agentId` 都成为一个**完全隔离的人设**:
|
||||
使用**多个智能体**,每个 `agentId` 成为一个**完全隔离的人格**:
|
||||
|
||||
- **不同的手机号/账户**(按渠道 `accountId`)。
|
||||
- **不同的性格**(按智能体工作区文件,如 `AGENTS.md` 和 `SOUL.md`)。
|
||||
- **独立的认证 + 会话**(除非显式启用,否则无串扰)。
|
||||
- **不同的电话号码/账户**(每渠道 `accountId`)。
|
||||
- **不同的人格**(每智能体工作区文件如 `AGENTS.md` 和 `SOUL.md`)。
|
||||
- **独立的认证 + 会话**(除非明确启用,否则无交叉通信)。
|
||||
|
||||
这使得**多个用户**可以共享一台 Gateway网关服务器,同时保持各自的 AI "大脑"和数据隔离。
|
||||
这让**多个人**共享一个 Gateway 网关服务器,同时保持他们的 AI"大脑"和数据隔离。
|
||||
|
||||
## 一个 WhatsApp 号码,多个用户(私聊分流)
|
||||
## 一个 WhatsApp 号码,多个人(私信分割)
|
||||
|
||||
你可以将**不同的 WhatsApp 私聊**路由到不同的智能体,同时使用**同一个 WhatsApp 账户**。通过发送者的 E.164 格式号码(如 `+15551234567`)配合 `peer.kind: "dm"` 进行匹配。回复仍然从同一个 WhatsApp 号码发出(没有按智能体的发送者身份)。
|
||||
你可以将**不同的 WhatsApp 私信**路由到不同的智能体,同时保持**一个 WhatsApp 账户**。使用 `peer.kind: "dm"` 匹配发送者 E.164(如 `+15551234567`)。回复仍然来自同一个 WhatsApp 号码(无每智能体发送者身份)。
|
||||
|
||||
重要细节:私聊会折叠到智能体的**主会话键**,因此真正的隔离需要**每人一个智能体**。
|
||||
重要细节:直接聊天折叠到智能体的**主会话键**,因此真正的隔离需要**每人一个智能体**。
|
||||
|
||||
示例:
|
||||
|
||||
@@ -110,32 +110,32 @@ openclaw agents list --bindings
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
注意事项:
|
||||
|
||||
- 私聊访问控制是**按 WhatsApp 账户全局的**(配对/白名单),而非按智能体。
|
||||
- 对于共享群组,将群组绑定到一个智能体或使用[广播群组](/broadcast-groups)。
|
||||
- 私信访问控制是**每 WhatsApp 账户全局的**(配对/允许列表),而不是每智能体。
|
||||
- 对于共享群组,将群组绑定到一个智能体或使用 [广播群组](/broadcast-groups)。
|
||||
|
||||
## 路由规则(消息如何选择智能体)
|
||||
|
||||
绑定是**确定性的**,遵循**最精确匹配优先**原则:
|
||||
绑定是**确定性的**,**最具体的优先**:
|
||||
|
||||
1. `peer` 匹配(精确的私聊/群组/渠道 ID)
|
||||
1. `peer` 匹配(精确私信/群组/频道 id)
|
||||
2. `guildId`(Discord)
|
||||
3. `teamId`(Slack)
|
||||
4. `accountId` 匹配(按渠道)
|
||||
4. 渠道的 `accountId` 匹配
|
||||
5. 渠道级匹配(`accountId: "*"`)
|
||||
6. 回退到默认智能体(`agents.list[].default`,否则取列表第一项,默认值:`main`)
|
||||
6. 回退到默认智能体(`agents.list[].default`,否则列表中的第一个条目,默认:`main`)
|
||||
|
||||
## 多账户/多手机号
|
||||
## 多账户/电话号码
|
||||
|
||||
支持**多账户**的渠道(如 WhatsApp)使用 `accountId` 来标识每个登录。每个 `accountId` 可以路由到不同的智能体,这样一台服务器就可以托管多个手机号而不会混淆会话。
|
||||
支持**多账户**的渠道(如 WhatsApp)使用 `accountId` 来识别每个登录。每个 `accountId` 可以路由到不同的智能体,因此一个服务器可以托管多个电话号码而不混合会话。
|
||||
|
||||
## 概念
|
||||
|
||||
- `agentId`:一个"大脑"(工作区、按智能体认证、按智能体会话存储)。
|
||||
- `agentId`:一个"大脑"(工作区、每智能体认证、每智能体会话存储)。
|
||||
- `accountId`:一个渠道账户实例(例如 WhatsApp 账户 `"personal"` vs `"biz"`)。
|
||||
- `binding`:通过 `(channel, accountId, peer)` 以及可选的 guild/team ID 将入站消息路由到 `agentId`。
|
||||
- 私聊折叠到 `agent:<agentId>:<mainKey>`(按智能体的"主会话";`session.mainKey`)。
|
||||
- `binding`:通过 `(channel, accountId, peer)` 以及可选的 guild/team id 将入站消息路由到 `agentId`。
|
||||
- 直接聊天折叠到 `agent:<agentId>:<mainKey>`(每智能体"主";`session.mainKey`)。
|
||||
|
||||
## 示例:两个 WhatsApp → 两个智能体
|
||||
|
||||
@@ -161,12 +161,12 @@ openclaw agents list --bindings
|
||||
],
|
||||
},
|
||||
|
||||
// 确定性路由:第一个匹配生效(最精确的在前)。
|
||||
// 确定性路由:第一个匹配获胜(最具体的优先)。
|
||||
bindings: [
|
||||
{ agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
|
||||
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
|
||||
|
||||
// 可选的按对端覆盖(示例:将特定群组发送到 work 智能体)。
|
||||
// 可选的每对等方覆盖(示例:将特定群组发送到 work 智能体)。
|
||||
{
|
||||
agentId: "work",
|
||||
match: {
|
||||
@@ -177,7 +177,7 @@ openclaw agents list --bindings
|
||||
},
|
||||
],
|
||||
|
||||
// 默认关闭:智能体间消息传递必须显式启用 + 白名单。
|
||||
// 默认关闭:智能体到智能体的消息必须明确启用 + 加入允许列表。
|
||||
tools: {
|
||||
agentToAgent: {
|
||||
enabled: false,
|
||||
@@ -189,11 +189,11 @@ openclaw agents list --bindings
|
||||
whatsapp: {
|
||||
accounts: {
|
||||
personal: {
|
||||
// 可选覆盖。默认值:~/.openclaw/credentials/whatsapp/personal
|
||||
// 可选覆盖。默认:~/.openclaw/credentials/whatsapp/personal
|
||||
// authDir: "~/.openclaw/credentials/whatsapp/personal",
|
||||
},
|
||||
biz: {
|
||||
// 可选覆盖。默认值:~/.openclaw/credentials/whatsapp/biz
|
||||
// 可选覆盖。默认:~/.openclaw/credentials/whatsapp/biz
|
||||
// authDir: "~/.openclaw/credentials/whatsapp/biz",
|
||||
},
|
||||
},
|
||||
@@ -204,7 +204,7 @@ openclaw agents list --bindings
|
||||
|
||||
## 示例:WhatsApp 日常聊天 + Telegram 深度工作
|
||||
|
||||
按渠道分流:将 WhatsApp 路由到快速日常智能体,将 Telegram 路由到 Opus 智能体。
|
||||
按渠道分割:将 WhatsApp 路由到快速日常智能体,Telegram 路由到 Opus 智能体。
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -231,14 +231,14 @@ openclaw agents list --bindings
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
注意事项:
|
||||
|
||||
- 如果一个渠道有多个账户,请在绑定中添加 `accountId`(例如 `{ channel: "whatsapp", accountId: "personal" }`)。
|
||||
- 要将单个私聊/群组路由到 Opus 而其余保持在 chat 上,请为该对端添加 `match.peer` 绑定;对端匹配始终优先于渠道级规则。
|
||||
- 如果你有一个渠道的多个账户,请在绑定中添加 `accountId`(例如 `{ channel: "whatsapp", accountId: "personal" }`)。
|
||||
- 要将单个私信/群组路由到 Opus 而保持其余在 chat 上,请为该对等方添加 `match.peer` 绑定;对等方匹配始终优先于渠道级规则。
|
||||
|
||||
## 示例:同一渠道,将一个对端路由到 Opus
|
||||
## 示例:同一渠道,一个对等方到 Opus
|
||||
|
||||
将 WhatsApp 保持在快速智能体上,但将一个私聊路由到 Opus:
|
||||
保持 WhatsApp 在快速智能体上,但将一个私信路由到 Opus:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -265,11 +265,11 @@ openclaw agents list --bindings
|
||||
}
|
||||
```
|
||||
|
||||
对端绑定始终优先,因此请将它们放在渠道级规则之上。
|
||||
对等方绑定始终获胜,因此将它们放在渠道级规则之上。
|
||||
|
||||
## 绑定到 WhatsApp 群组的家庭智能体
|
||||
|
||||
将一个专用家庭智能体绑定到单个 WhatsApp 群组,使用提及控制和更严格的工具策略:
|
||||
将专用家庭智能体绑定到单个 WhatsApp 群组,使用提及限制和更严格的工具策略:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -314,12 +314,12 @@ openclaw agents list --bindings
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
注意事项:
|
||||
|
||||
- 工具允许/拒绝列表针对的是**工具**,而非 Skills。如果某个 Skills 需要运行二进制文件,请确保允许 `exec` 并且该二进制文件存在于沙箱中。
|
||||
- 要实现更严格的控制,请设置 `agents.list[].groupChat.mentionPatterns` 并为渠道启用群组白名单。
|
||||
- 工具允许/拒绝列表是**工具**,不是 Skills。如果 skill 需要运行二进制文件,请确保 `exec` 被允许且二进制文件存在于沙箱中。
|
||||
- 对于更严格的限制,设置 `agents.list[].groupChat.mentionPatterns` 并为渠道保持群组允许列表启用。
|
||||
|
||||
## 按智能体的沙箱和工具配置
|
||||
## 每智能体沙箱和工具配置
|
||||
|
||||
从 v2026.1.6 开始,每个智能体可以有自己的沙箱和工具限制:
|
||||
|
||||
@@ -331,7 +331,7 @@ openclaw agents list --bindings
|
||||
id: "personal",
|
||||
workspace: "~/.openclaw/workspace-personal",
|
||||
sandbox: {
|
||||
mode: "off", // 个人智能体不使用沙箱
|
||||
mode: "off", // 个人智能体无沙箱
|
||||
},
|
||||
// 无工具限制 - 所有工具可用
|
||||
},
|
||||
@@ -340,15 +340,15 @@ openclaw agents list --bindings
|
||||
workspace: "~/.openclaw/workspace-family",
|
||||
sandbox: {
|
||||
mode: "all", // 始终沙箱隔离
|
||||
scope: "agent", // 每个智能体一个容器
|
||||
scope: "agent", // 每智能体一个容器
|
||||
docker: {
|
||||
// 容器创建后的可选一次性设置
|
||||
setupCommand: "apt-get update && apt-get install -y git curl",
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
allow: ["read"], // 仅允许 read 工具
|
||||
deny: ["exec", "write", "edit", "apply_patch"], // 拒绝其他工具
|
||||
allow: ["read"], // 仅 read 工具
|
||||
deny: ["exec", "write", "edit", "apply_patch"], // 拒绝其他
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -356,14 +356,17 @@ openclaw agents list --bindings
|
||||
}
|
||||
```
|
||||
|
||||
注意:`setupCommand` 位于 `sandbox.docker` 下,在容器创建时运行一次。当解析的 scope 为 `"shared"` 时,按智能体的 `sandbox.docker.*` 覆盖会被忽略。
|
||||
注意:`setupCommand` 位于 `sandbox.docker` 下,在容器创建时运行一次。
|
||||
当解析的 scope 为 `"shared"` 时,每智能体 `sandbox.docker.*` 覆盖会被忽略。
|
||||
|
||||
**优势:**
|
||||
**好处:**
|
||||
|
||||
- **安全隔离**:限制不受信任的智能体的工具
|
||||
- **资源控制**:沙箱隔离特定智能体,同时让其他智能体在主机上运行
|
||||
- **灵活策略**:按智能体设置不同权限
|
||||
- **安全隔离**:限制不受信任智能体的工具
|
||||
- **资源控制**:沙箱隔离特定智能体同时保持其他智能体在主机上
|
||||
- **灵活策略**:每智能体不同的权限
|
||||
|
||||
注意:`tools.elevated` 是**全局的**且基于发送者;不能按智能体配置。如果你需要按智能体的边界,请使用 `agents.list[].tools` 来拒绝 `exec`。对于群组定向,请使用 `agents.list[].groupChat.mentionPatterns`,以便 @提及能准确映射到目标智能体。
|
||||
注意:`tools.elevated` 是**全局的**且基于发送者;不能按智能体配置。
|
||||
如果你需要每智能体边界,使用 `agents.list[].tools` 拒绝 `exec`。
|
||||
对于群组定向,使用 `agents.list[].groupChat.mentionPatterns` 使 @提及清晰地映射到目标智能体。
|
||||
|
||||
参阅[多智能体沙箱与工具](/multi-agent-sandbox-tools)获取详细示例。
|
||||
参见 [多智能体沙箱和工具](/multi-agent-sandbox-tools) 了解详细示例。
|
||||
|
||||
@@ -1,99 +1,99 @@
|
||||
---
|
||||
read_when:
|
||||
- 调试实例选项卡
|
||||
- 调试实例标签页
|
||||
- 排查重复或过期的实例行
|
||||
- 更改 Gateway网关 WebSocket 连接或系统事件信标
|
||||
summary: OpenClaw 在线状态条目的生成、合并与显示方式
|
||||
- 更改 Gateway 网关 WS 连接或系统事件信标
|
||||
summary: OpenClaw 在线状态条目如何生成、合并和显示
|
||||
title: 在线状态
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:31Z"
|
||||
generated_at: "2026-02-03T07:46:37Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: c752c76a880878fed673d656db88beb5dbdeefff2491985127ad791521f97d00
|
||||
source_path: concepts/presence.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 在线状态
|
||||
|
||||
OpenClaw 的"在线状态"是一个轻量级、尽力而为的视图,展示:
|
||||
OpenClaw"在线状态"是以下内容的轻量级、尽力而为的视图:
|
||||
|
||||
- **Gateway网关** 自身,以及
|
||||
- **连接到 Gateway网关的客户端**(Mac 应用、WebChat、CLI 等)
|
||||
- **Gateway 网关**本身,以及
|
||||
- **连接到 Gateway 网关的客户端**(mac 应用、WebChat、CLI 等)
|
||||
|
||||
在线状态主要用于渲染 macOS 应用的**实例**选项卡,并为操作人员提供快速可视化。
|
||||
在线状态主要用于渲染 macOS 应用的**实例**标签页,并为运维人员提供快速可见性。
|
||||
|
||||
## 在线状态字段(显示内容)
|
||||
## 在线状态字段(显示的内容)
|
||||
|
||||
在线状态条目是结构化对象,包含以下字段:
|
||||
在线状态条目是具有以下字段的结构化对象:
|
||||
|
||||
- `instanceId`(可选但强烈建议提供):稳定的客户端标识(通常为 `connect.client.instanceId`)
|
||||
- `host`:人类可读的主机名
|
||||
- `instanceId`(可选但强烈推荐):稳定的客户端身份(通常是 `connect.client.instanceId`)
|
||||
- `host`:人类友好的主机名
|
||||
- `ip`:尽力而为的 IP 地址
|
||||
- `version`:客户端版本字符串
|
||||
- `deviceFamily` / `modelIdentifier`:硬件提示信息
|
||||
- `deviceFamily` / `modelIdentifier`:硬件提示
|
||||
- `mode`:`ui`、`webchat`、`cli`、`backend`、`probe`、`test`、`node`,...
|
||||
- `lastInputSeconds`:"距上次用户输入的秒数"(如果已知)
|
||||
- `lastInputSeconds`:"自上次用户输入以来的秒数"(如果已知)
|
||||
- `reason`:`self`、`connect`、`node-connected`、`periodic`,...
|
||||
- `ts`:最后更新时间戳(自纪元以来的毫秒数)
|
||||
|
||||
## 生产者(在线状态的来源)
|
||||
## 生产者(在线状态来源)
|
||||
|
||||
在线状态条目由多个来源产生并进行**合并**。
|
||||
在线状态条目由多个来源生成并**合并**。
|
||||
|
||||
### 1)Gateway网关自身条目
|
||||
### 1)Gateway 网关自身条目
|
||||
|
||||
Gateway网关在启动时始终会创建一个"self"条目,这样即使在任何客户端连接之前,UI 也能显示 Gateway网关主机。
|
||||
Gateway 网关始终在启动时植入一个"self"条目,这样即使在任何客户端连接之前,UI 也能显示 Gateway 网关主机。
|
||||
|
||||
### 2)WebSocket 连接
|
||||
|
||||
每个 WebSocket 客户端都以 `connect` 请求开始。握手成功后,Gateway网关会为该连接更新插入一个在线状态条目。
|
||||
每个 WS 客户端都以 `connect` 请求开始。在成功握手后,Gateway 网关为该连接更新插入一个在线状态条目。
|
||||
|
||||
#### 为什么一次性 CLI 命令不会显示
|
||||
|
||||
CLI 通常只为短暂的一次性命令建立连接。为避免实例列表被频繁刷新,`client.mode === "cli"` **不会**被转换为在线状态条目。
|
||||
CLI 经常为短暂的一次性命令进行连接。为避免实例列表被刷屏,`client.mode === "cli"` **不会**被转换为在线状态条目。
|
||||
|
||||
### 3)`system-event` 信标
|
||||
|
||||
客户端可以通过 `system-event` 方法发送更丰富的周期性信标。Mac 应用使用此机制报告主机名、IP 和 `lastInputSeconds`。
|
||||
客户端可以通过 `system-event` 方法发送更丰富的周期性信标。mac 应用使用此方法报告主机名、IP 和 `lastInputSeconds`。
|
||||
|
||||
### 4)节点连接(role: node)
|
||||
|
||||
当节点通过 Gateway网关 WebSocket 以 `role: node` 连接时,Gateway网关会为该节点更新插入一个在线状态条目(与其他 WebSocket 客户端流程相同)。
|
||||
当节点通过 Gateway 网关 WebSocket 以 `role: node` 连接时,Gateway 网关为该节点更新插入一个在线状态条目(与其他 WS 客户端流程相同)。
|
||||
|
||||
## 合并与去重规则(为什么 `instanceId` 很重要)
|
||||
## 合并 + 去重规则(为什么 `instanceId` 很重要)
|
||||
|
||||
在线状态条目存储在单个内存映射中:
|
||||
|
||||
- 条目以**在线状态键**作为索引。
|
||||
- 最佳键是稳定的 `instanceId`(来自 `connect.client.instanceId`),可在重启后保持不变。
|
||||
- 条目以**在线状态键**为索引。
|
||||
- 最佳键是稳定的 `instanceId`(来自 `connect.client.instanceId`),它在重启后仍然有效。
|
||||
- 键不区分大小写。
|
||||
|
||||
如果客户端在没有稳定 `instanceId` 的情况下重新连接,可能会显示为**重复**行。
|
||||
如果客户端在没有稳定 `instanceId` 的情况下重新连接,它可能会显示为**重复**行。
|
||||
|
||||
## TTL 和大小限制
|
||||
## TTL 和有界大小
|
||||
|
||||
在线状态是有意设计为临时性的:
|
||||
在线状态是有意设计为短暂的:
|
||||
|
||||
- **TTL:**超过 5 分钟的条目将被清除
|
||||
- **最大条目数:**200(优先丢弃最旧的条目)
|
||||
- **TTL:** 超过 5 分钟的条目会被修剪
|
||||
- **最大条目数:** 200(最旧的优先删除)
|
||||
|
||||
这确保列表保持新鲜,避免无限制的内存增长。
|
||||
这使列表保持新鲜并避免无限制的内存增长。
|
||||
|
||||
## 远程/隧道注意事项(local loopback IP)
|
||||
## 远程/隧道注意事项(回环 IP)
|
||||
|
||||
当客户端通过 SSH 隧道/本地端口转发连接时,Gateway网关可能会将远程地址识别为 `127.0.0.1`。为避免覆盖客户端报告的有效 IP,local loopback 远程地址会被忽略。
|
||||
当客户端通过 SSH 隧道/本地端口转发连接时,Gateway 网关可能会看到远程地址为 `127.0.0.1`。为避免覆盖客户端报告的有效 IP,回环远程地址会被忽略。
|
||||
|
||||
## 消费者
|
||||
|
||||
### macOS 实例选项卡
|
||||
### macOS 实例标签页
|
||||
|
||||
macOS 应用渲染 `system-presence` 的输出,并根据最后更新的时间显示小型状态指示器(活跃/空闲/过期)。
|
||||
macOS 应用渲染 `system-presence` 的输出,并根据最后更新的时间应用一个小的状态指示器(活跃/空闲/过期)。
|
||||
|
||||
## 调试技巧
|
||||
|
||||
- 要查看原始列表,请对 Gateway网关调用 `system-presence`。
|
||||
- 如果看到重复条目:
|
||||
- 确认客户端在握手中发送了稳定的 `client.instanceId`
|
||||
- 要查看原始列表,对 Gateway 网关调用 `system-presence`。
|
||||
- 如果你看到重复项:
|
||||
- 确认客户端在握手中发送稳定的 `client.instanceId`
|
||||
- 确认周期性信标使用相同的 `instanceId`
|
||||
- 检查连接派生的条目是否缺少 `instanceId`(此时重复是预期行为)
|
||||
- 检查连接派生的条目是否缺少 `instanceId`(这种情况下重复是预期的)
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
---
|
||||
read_when:
|
||||
- 更改自动回复执行或并发机制
|
||||
summary: 序列化入站自动回复运行的命令队列设计
|
||||
- 更改自动回复执行或并发设置时
|
||||
summary: 用于序列化入站自动回复运行的命令队列设计
|
||||
title: 命令队列
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:48Z"
|
||||
generated_at: "2026-02-03T10:05:28Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 2104c24d200fb4f9620e52a19255cd614ababe19d78f3ee42936dc6d0499b73b
|
||||
source_path: concepts/queue.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 命令队列(2026-01-16)
|
||||
|
||||
我们通过一个轻量的进程内队列来序列化入站自动回复运行(所有渠道),以防止多个智能体运行发生冲突,同时仍允许跨会话的安全并行。
|
||||
我们通过一个小型进程内队列序列化入站自动回复运行(所有渠道),以防止多个智能体运行发生冲突,同时仍允许跨会话的安全并行。
|
||||
|
||||
## 原因
|
||||
## 为什么需要
|
||||
|
||||
- 自动回复运行可能开销很大(LLM 调用),当多条入站消息几乎同时到达时可能发生冲突。
|
||||
- 序列化可以避免争用共享资源(会话文件、日志、CLI 标准输入),并降低触发上游速率限制的概率。
|
||||
- 自动回复运行可能开销很大(LLM 调用),当多条入站消息接近同时到达时可能发生冲突。
|
||||
- 序列化可以避免竞争共享资源(会话文件、日志、CLI stdin),并降低上游速率限制的可能性。
|
||||
|
||||
## 工作原理
|
||||
|
||||
- 一个支持通道感知的 FIFO 队列以可配置的并发上限逐通道排空(未配置的通道默认为 1;main 默认为 4,subagent 默认为 8)。
|
||||
- `runEmbeddedPiAgent` 按**会话键**(通道 `session:<key>`)入队,以保证每个会话同一时间只有一个活跃运行。
|
||||
- 每个会话运行随后被排入**全局通道**(默认为 `main`),因此整体并行度受 `agents.defaults.maxConcurrent` 限制。
|
||||
- 启用详细日志时,如果排队的运行在启动前等待超过约 2 秒,会发出一条简短通知。
|
||||
- 输入指示器在入队时仍会立即触发(当渠道支持时),因此在等待期间用户体验不受影响。
|
||||
- 一个支持通道感知的 FIFO 队列以可配置的并发上限排空每个通道(未配置的通道默认为 1;main 默认为 4,subagent 为 8)。
|
||||
- `runEmbeddedPiAgent` 按**会话键**入队(通道 `session:<key>`),以保证每个会话只有一个活动运行。
|
||||
- 然后每个会话运行被排入**全局通道**(默认为 `main`),因此整体并行度受 `agents.defaults.maxConcurrent` 限制。
|
||||
- 启用详细日志时,如果排队运行在开始前等待超过约 2 秒,会发出简短通知。
|
||||
- 输入指示器仍在入队时立即触发(当渠道支持时),因此在等待轮次时用户体验不受影响。
|
||||
|
||||
## 队列模式(按渠道)
|
||||
|
||||
入站消息可以引导当前运行、等待后续轮次,或两者兼顾:
|
||||
|
||||
- `steer`:立即注入当前运行(在下一个工具边界后取消待执行的工具调用)。如果未在流式传输,则回退为 followup。
|
||||
- `followup`:在当前运行结束后排队等待下一个智能体轮次。
|
||||
- `steer`:立即注入当前运行(在下一个工具边界后取消待处理的工具调用)。如果未在流式传输,则回退到 followup。
|
||||
- `followup`:在当前运行结束后为下一个智能体轮次入队。
|
||||
- `collect`:将所有排队消息合并为**单个**后续轮次(默认)。如果消息针对不同的渠道/线程,它们会单独排空以保留路由。
|
||||
- `steer-backlog`(又名 `steer+backlog`):立即引导**并且**保留消息用于后续轮次。
|
||||
- `interrupt`(旧版):中止该会话的活跃运行,然后运行最新消息。
|
||||
- `queue`(旧版别名):等同于 `steer`。
|
||||
- `steer-backlog`(又名 `steer+backlog`):现在引导**并**保留消息用于后续轮次。
|
||||
- `interrupt`(旧版):中止该会话的活动运行,然后运行最新消息。
|
||||
- `queue`(旧版别名):与 `steer` 相同。
|
||||
|
||||
steer-backlog 意味着在引导运行之后你还能获得后续响应,因此流式传输界面可能看起来像重复内容。如果希望每条入站消息只获得一次响应,请优先使用 `collect`/`steer`。
|
||||
发送 `/queue collect` 作为独立命令(按会话生效),或设置 `messages.queue.byChannel.discord: "collect"`。
|
||||
steer-backlog 意味着你可以在被引导的运行之后获得后续响应,因此流式传输界面可能看起来像重复。如果你希望每条入站消息只有一个响应,请优先使用 `collect`/`steer`。
|
||||
发送 `/queue collect` 作为独立命令(按会话)或设置 `messages.queue.byChannel.discord: "collect"`。
|
||||
|
||||
默认值(配置中未设置时):
|
||||
|
||||
- 所有界面 → `collect`
|
||||
|
||||
通过 `messages.queue` 进行全局或按渠道配置:
|
||||
通过 `messages.queue` 全局或按渠道配置:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -65,30 +65,30 @@ steer-backlog 意味着在引导运行之后你还能获得后续响应,因此
|
||||
|
||||
## 队列选项
|
||||
|
||||
选项适用于 `followup`、`collect` 和 `steer-backlog`(以及 `steer` 回退为 followup 时):
|
||||
选项适用于 `followup`、`collect` 和 `steer-backlog`(以及当 `steer` 回退到 followup 时):
|
||||
|
||||
- `debounceMs`:在启动后续轮次前等待静默期(防止"继续,继续"的情况)。
|
||||
- `debounceMs`:在开始后续轮次前等待静默(防止"继续,继续")。
|
||||
- `cap`:每个会话的最大排队消息数。
|
||||
- `drop`:溢出策略(`old`、`new`、`summarize`)。
|
||||
|
||||
summarize 会保留一个被丢弃消息的简短要点列表,并将其作为合成的后续提示词注入。
|
||||
summarize 保留被丢弃消息的简短要点列表,并将其作为合成的后续提示注入。
|
||||
默认值:`debounceMs: 1000`、`cap: 20`、`drop: summarize`。
|
||||
|
||||
## 按会话覆盖
|
||||
|
||||
- 发送 `/queue <mode>` 作为独立命令,可将该模式存储到当前会话。
|
||||
- 选项可以组合使用:`/queue collect debounce:2s cap:25 drop:summarize`
|
||||
- 发送 `/queue <mode>` 作为独立命令,为当前会话存储该模式。
|
||||
- 选项可以组合:`/queue collect debounce:2s cap:25 drop:summarize`
|
||||
- `/queue default` 或 `/queue reset` 清除会话覆盖。
|
||||
|
||||
## 作用范围与保证
|
||||
## 范围和保证
|
||||
|
||||
- 适用于所有使用 Gateway网关回复管道的入站渠道的自动回复智能体运行(WhatsApp 网页版、Telegram、Slack、Discord、Signal、iMessage、网页聊天等)。
|
||||
- 默认通道(`main`)在进程范围内适用于入站消息和主心跳;设置 `agents.defaults.maxConcurrent` 以允许多个会话并行。
|
||||
- 可能存在其他通道(如 `cron`、`subagent`),以便后台任务可以并行运行而不阻塞入站回复。
|
||||
- 按会话通道保证同一时间只有一个智能体运行接触给定会话。
|
||||
- 无外部依赖或后台工作线程;纯 TypeScript + Promise 实现。
|
||||
- 适用于所有使用 Gateway 网关回复管道的入站渠道的自动回复智能体运行(WhatsApp 网页版、Telegram、Slack、Discord、Signal、iMessage、网页聊天等)。
|
||||
- 默认通道(`main`)对入站 + 主心跳是进程范围的;设置 `agents.defaults.maxConcurrent` 以允许多个会话并行。
|
||||
- 可能存在额外的通道(例如 `cron`、`subagent`),以便后台任务可以并行运行而不阻塞入站回复。
|
||||
- 按会话通道保证一次只有一个智能体运行触及给定会话。
|
||||
- 无外部依赖或后台工作线程;纯 TypeScript + promises。
|
||||
|
||||
## 故障排除
|
||||
|
||||
- 如果命令似乎卡住,启用详细日志并查找 "queued for …ms" 行,以确认队列正在正常排空。
|
||||
- 如果需要查看队列深度,启用详细日志并观察队列计时行。
|
||||
- 如果命令似乎卡住,启用详细日志并查找"queued for …ms"行以确认队列正在排空。
|
||||
- 如果你需要查看队列深度,启用详细日志并观察队列计时行。
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想减少工具输出导致的 LLM 上下文增长
|
||||
- 你正在调优 agents.defaults.contextPruning
|
||||
summary: 会话裁剪:通过修剪工具结果来减少上下文膨胀
|
||||
- 你正在调整 agents.defaults.contextPruning
|
||||
summary: 会话剪枝:工具结果修剪以减少上下文膨胀
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:23:53Z"
|
||||
generated_at: "2026-02-03T07:46:35Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 9b0aa2d1abea7050ba848a2db038ccc3e6e2d83c6eb4e3843a2ead0ab847574a
|
||||
source_path: concepts/session-pruning.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 会话裁剪
|
||||
# 会话剪枝
|
||||
|
||||
会话裁剪在每次 LLM 调用之前修剪内存上下文中的**旧工具结果**。它**不会**重写磁盘上的会话历史(`*.jsonl`)。
|
||||
会话剪枝在每次 LLM 调用之前从内存上下文中修剪**旧的工具结果**。它**不会**重写磁盘上的会话历史(`*.jsonl`)。
|
||||
|
||||
## 运行时机
|
||||
|
||||
- 当启用 `mode: "cache-ttl"` 且该会话的上次 Anthropic 调用时间超过 `ttl` 时触发。
|
||||
- 当启用 `mode: "cache-ttl"` 且该会话的最后一次 Anthropic 调用早于 `ttl` 时。
|
||||
- 仅影响该请求发送给模型的消息。
|
||||
- 仅对 Anthropic API 调用(以及 OpenRouter Anthropic 模型)生效。
|
||||
- 为获得最佳效果,请将 `ttl` 与模型的 `cacheControlTtl` 保持一致。
|
||||
- 裁剪后,TTL 窗口会重置,后续请求将继续使用缓存直到 `ttl` 再次过期。
|
||||
- 仅对 Anthropic API 调用(和 OpenRouter Anthropic 模型)生效。
|
||||
- 为获得最佳效果,请将 `ttl` 与你的模型 `cacheControlTtl` 匹配。
|
||||
- 剪枝后,TTL 窗口会重置,因此后续请求会保持缓存直到 `ttl` 再次过期。
|
||||
|
||||
## 智能默认值(Anthropic)
|
||||
|
||||
- **OAuth 或 setup-token** 配置文件:启用 `cache-ttl` 裁剪,并将心跳设置为 `1h`。
|
||||
- **API 密钥**配置文件:启用 `cache-ttl` 裁剪,将心跳设置为 `30m`,并将 Anthropic 模型的 `cacheControlTtl` 默认设为 `1h`。
|
||||
- **OAuth 或 setup-token** 配置文件:启用 `cache-ttl` 剪枝并将心跳设置为 `1h`。
|
||||
- **API 密钥**配置文件:启用 `cache-ttl` 剪枝,将心跳设置为 `30m`,并将 Anthropic 模型的 `cacheControlTtl` 默认为 `1h`。
|
||||
- 如果你显式设置了这些值中的任何一个,OpenClaw **不会**覆盖它们。
|
||||
|
||||
## 改善效果(成本 + 缓存行为)
|
||||
## 改进内容(成本 + 缓存行为)
|
||||
|
||||
- **为什么要裁剪:** Anthropic 提示缓存仅在 TTL 内生效。如果会话空闲超过 TTL,下一次请求将重新缓存完整提示,除非你先对其进行修剪。
|
||||
- **哪些费用会降低:** 裁剪减少了 TTL 过期后首次请求的 **cacheWrite** 大小。
|
||||
- **为什么 TTL 重置很重要:** 裁剪运行后,缓存窗口会重置,因此后续请求可以复用新缓存的提示,而不是再次重新缓存完整历史。
|
||||
- **它不会做什么:** 裁剪不会增加令牌或"翻倍"成本;它只改变 TTL 过期后首次请求的缓存内容。
|
||||
- **为什么要剪枝:** Anthropic 提示缓存仅在 TTL 内适用。如果会话空闲超过 TTL,下一个请求会重新缓存完整提示,除非你先修剪它。
|
||||
- **什么变得更便宜:** 剪枝减少了 TTL 过期后第一个请求的 **cacheWrite** 大小。
|
||||
- **为什么 TTL 重置很重要:** 一旦剪枝运行,缓存窗口会重置,因此后续请求可以重用新缓存的提示,而不是再次重新缓存完整历史。
|
||||
- **它不做什么:** 剪枝不会添加 token 或"双倍"成本;它只改变该 TTL 后第一个请求缓存的内容。
|
||||
|
||||
## 可裁剪的内容
|
||||
## 可以剪枝的内容
|
||||
|
||||
- 仅限 `toolResult` 消息。
|
||||
- 用户和助手消息**永远不会**被修改。
|
||||
- 最后 `keepLastAssistants` 条助手消息受保护;该截止点之后的工具结果不会被裁剪。
|
||||
- 如果助手消息数量不足以确定截止点,则跳过裁剪。
|
||||
- 包含**图片块**的工具结果会被跳过(永远不会被修剪/清除)。
|
||||
- 仅 `toolResult` 消息。
|
||||
- 用户 + 助手消息**永远不会**被修改。
|
||||
- 最后 `keepLastAssistants` 条助手消息受保护;该截止点之后的工具结果不会被剪枝。
|
||||
- 如果没有足够的助手消息来确定截止点,则跳过剪枝。
|
||||
- 包含**图像块**的工具结果会被跳过(永不修剪/清除)。
|
||||
|
||||
## 上下文窗口估算
|
||||
|
||||
裁剪使用估算的上下文窗口(字符数 ≈ 令牌数 × 4)。基础窗口按以下顺序解析:
|
||||
剪枝使用估算的上下文窗口(字符 ≈ token × 4)。基础窗口按以下顺序解析:
|
||||
|
||||
1. `models.providers.*.models[].contextWindow` 覆盖值。
|
||||
2. 模型定义中的 `contextWindow`(来自模型注册表)。
|
||||
3. 默认 `200000` 令牌。
|
||||
1. `models.providers.*.models[].contextWindow` 覆盖。
|
||||
2. 模型定义 `contextWindow`(来自模型注册表)。
|
||||
3. 默认 `200000` token。
|
||||
|
||||
如果设置了 `agents.defaults.contextTokens`,它将作为解析窗口的上限(取最小值)。
|
||||
如果设置了 `agents.defaults.contextTokens`,它将被视为解析窗口的上限(最小值)。
|
||||
|
||||
## 模式
|
||||
|
||||
### cache-ttl
|
||||
|
||||
- 仅当上次 Anthropic 调用时间超过 `ttl`(默认 `5m`)时才运行裁剪。
|
||||
- 仅当最后一次 Anthropic 调用早于 `ttl`(默认 `5m`)时才运行剪枝。
|
||||
- 运行时:与之前相同的软修剪 + 硬清除行为。
|
||||
|
||||
## 软裁剪与硬裁剪
|
||||
## 软剪枝 vs 硬剪枝
|
||||
|
||||
- **软修剪**:仅针对超大的工具结果。
|
||||
- 保留头部和尾部,插入 `...`,并附加一条包含原始大小的说明。
|
||||
- 跳过包含图片块的结果。
|
||||
- **软修剪**:仅用于过大的工具结果。
|
||||
- 保留头部 + 尾部,插入 `...`,并附加一个包含原始大小的注释。
|
||||
- 跳过包含图像块的结果。
|
||||
- **硬清除**:用 `hardClear.placeholder` 替换整个工具结果。
|
||||
|
||||
## 工具选择
|
||||
@@ -78,8 +78,8 @@ x-i18n:
|
||||
|
||||
## 与其他限制的交互
|
||||
|
||||
- 内置工具已经会截断自身的输出;会话裁剪是一个额外的保护层,防止长时间运行的对话在模型上下文中积累过多的工具输出。
|
||||
- 压缩是独立的:压缩会进行摘要并持久化,裁剪则是每次请求的临时操作。参见 [/concepts/compaction](/concepts/compaction)。
|
||||
- 内置工具已经截断自己的输出;会话剪枝是一个额外的层,防止长时间运行的聊天在模型上下文中累积过多的工具输出。
|
||||
- 压缩是独立的:压缩进行总结并持久化,剪枝是每个请求的临时操作。参阅 [/concepts/compaction](/concepts/compaction)。
|
||||
|
||||
## 默认值(启用时)
|
||||
|
||||
@@ -103,7 +103,7 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
启用 TTL 感知裁剪:
|
||||
启用 TTL 感知剪枝:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -113,7 +113,7 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
将裁剪限制为特定工具:
|
||||
限制剪枝到特定工具:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -126,4 +126,4 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
参见配置参考:[Gateway网关配置](/gateway/configuration)
|
||||
参阅配置参考:[Gateway 网关配置](/gateway/configuration)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
---
|
||||
read_when:
|
||||
- 添加或修改会话工具
|
||||
summary: 智能体会话工具:列出会话、获取历史记录和发送跨会话消息
|
||||
- 添加或修改会话工具时
|
||||
summary: 用于列出会话、获取历史记录和发送跨会话消息的智能体会话工具
|
||||
title: 会话工具
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:24:08Z"
|
||||
generated_at: "2026-02-03T07:46:54Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: cb6e0982ebf507bcf9de4bb17719759c2b6d3e519731c845580a55279084e4c8
|
||||
source_path: concepts/session-tool.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 会话工具
|
||||
|
||||
目标:提供小型、不易误用的工具集,使智能体能够列出会话、获取历史记录以及向其他会话发送消息。
|
||||
目标:小型、不易误用的工具集,使智能体能够列出会话、获取历史记录并向另一个会话发送消息。
|
||||
|
||||
## 工具名称
|
||||
|
||||
@@ -25,62 +25,62 @@ x-i18n:
|
||||
|
||||
## 键模型
|
||||
|
||||
- 主私聊桶始终使用字面键 `"main"`(解析为当前智能体的主键)。
|
||||
- 群聊使用 `agent:<agentId>:<channel>:group:<id>` 或 `agent:<agentId>:<channel>:channel:<id>`(传入完整键)。
|
||||
- 主直接聊天桶始终是字面键 `"main"`(解析为当前智能体的主键)。
|
||||
- 群聊使用 `agent:<agentId>:<channel>:group:<id>` 或 `agent:<agentId>:<channel>:channel:<id>`(传递完整键)。
|
||||
- 定时任务使用 `cron:<job.id>`。
|
||||
- 钩子使用 `hook:<uuid>`,除非显式设置。
|
||||
- 节点会话使用 `node-<nodeId>`,除非显式设置。
|
||||
- Hooks 使用 `hook:<uuid>`,除非明确设置。
|
||||
- Node 会话使用 `node-<nodeId>`,除非明确设置。
|
||||
|
||||
`global` 和 `unknown` 是保留值,永远不会被列出。如果 `session.scope = "global"`,我们会将其别名为 `main` 供所有工具使用,这样调用方永远看不到 `global`。
|
||||
`global` 和 `unknown` 是保留值,永远不会被列出。如果 `session.scope = "global"`,我们会将其别名为 `main` 用于所有工具,这样调用者永远不会看到 `global`。
|
||||
|
||||
## sessions_list
|
||||
|
||||
以行数组形式列出会话。
|
||||
将会话列为行数组。
|
||||
|
||||
参数:
|
||||
|
||||
- `kinds?: string[]` 过滤器:`"main" | "group" | "cron" | "hook" | "node" | "other"` 的任意组合
|
||||
- `limit?: number` 最大行数(默认:服务器默认值,上限如 200)
|
||||
- `activeMinutes?: number` 仅返回 N 分钟内更新的会话
|
||||
- `messageLimit?: number` 0 = 不返回消息(默认 0);>0 = 包含最近 N 条消息
|
||||
- `kinds?: string[]` 过滤器:`"main" | "group" | "cron" | "hook" | "node" | "other"` 中的任意一个
|
||||
- `limit?: number` 最大行数(默认:服务器默认值,限制如 200)
|
||||
- `activeMinutes?: number` 仅在 N 分钟内更新的会话
|
||||
- `messageLimit?: number` 0 = 无消息(默认 0);>0 = 包含最后 N 条消息
|
||||
|
||||
行为:
|
||||
|
||||
- `messageLimit > 0` 时会获取每个会话的 `chat.history` 并包含最近 N 条消息。
|
||||
- 列表输出中会过滤工具结果;使用 `sessions_history` 获取工具消息。
|
||||
- 在**沙箱隔离**的智能体会话中运行时,会话工具默认为**仅已生成可见**(见下文)。
|
||||
- `messageLimit > 0` 获取每个会话的 `chat.history` 并包含最后 N 条消息。
|
||||
- 工具结果在列表输出中被过滤;使用 `sessions_history` 获取工具消息。
|
||||
- 在**沙箱隔离**的智能体会话中运行时,会话工具默认为**仅生成的可见性**(见下文)。
|
||||
|
||||
行结构(JSON):
|
||||
|
||||
- `key`:会话键(字符串)
|
||||
- `kind`:`main | group | cron | hook | node | other`
|
||||
- `channel`:`whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown`
|
||||
- `displayName`(群组显示标签,如可用)
|
||||
- `displayName`(如果可用的群组显示标签)
|
||||
- `updatedAt`(毫秒)
|
||||
- `sessionId`
|
||||
- `model`、`contextTokens`、`totalTokens`
|
||||
- `thinkingLevel`、`verboseLevel`、`systemSent`、`abortedLastRun`
|
||||
- `sendPolicy`(会话覆盖,如已设置)
|
||||
- `sendPolicy`(如果设置的会话覆盖)
|
||||
- `lastChannel`、`lastTo`
|
||||
- `deliveryContext`(规范化的 `{ channel, to, accountId }`,如可用)
|
||||
- `transcriptPath`(根据存储目录 + sessionId 推导的尽力路径)
|
||||
- `deliveryContext`(可用时的规范化 `{ channel, to, accountId }`)
|
||||
- `transcriptPath`(从存储目录 + sessionId 派生的尽力路径)
|
||||
- `messages?`(仅当 `messageLimit > 0` 时)
|
||||
|
||||
## sessions_history
|
||||
|
||||
获取单个会话的对话记录。
|
||||
获取一个会话的记录。
|
||||
|
||||
参数:
|
||||
|
||||
- `sessionKey`(必需;接受会话键或来自 `sessions_list` 的 `sessionId`)
|
||||
- `limit?: number` 最大消息数(服务器限制上限)
|
||||
- `sessionKey`(必填;接受会话键或来自 `sessions_list` 的 `sessionId`)
|
||||
- `limit?: number` 最大消息数(服务器限制)
|
||||
- `includeTools?: boolean`(默认 false)
|
||||
|
||||
行为:
|
||||
|
||||
- `includeTools=false` 过滤 `role: "toolResult"` 的消息。
|
||||
- 以原始对话记录格式返回消息数组。
|
||||
- 当传入 `sessionId` 时,OpenClaw 会将其解析为对应的会话键(缺失的 ID 会报错)。
|
||||
- `includeTools=false` 过滤 `role: "toolResult"` 消息。
|
||||
- 以原始记录格式返回消息数组。
|
||||
- 当给定 `sessionId` 时,OpenClaw 将其解析为相应的会话键(缺失的 id 会报错)。
|
||||
|
||||
## sessions_send
|
||||
|
||||
@@ -88,8 +88,8 @@ x-i18n:
|
||||
|
||||
参数:
|
||||
|
||||
- `sessionKey`(必需;接受会话键或来自 `sessions_list` 的 `sessionId`)
|
||||
- `message`(必需)
|
||||
- `sessionKey`(必填;接受会话键或来自 `sessions_list` 的 `sessionId`)
|
||||
- `message`(必填)
|
||||
- `timeoutSeconds?: number`(默认 >0;0 = 即发即忘)
|
||||
|
||||
行为:
|
||||
@@ -98,28 +98,28 @@ x-i18n:
|
||||
- `timeoutSeconds > 0`:等待最多 N 秒完成,然后返回 `{ runId, status: "ok", reply }`。
|
||||
- 如果等待超时:`{ runId, status: "timeout", error }`。运行继续;稍后调用 `sessions_history`。
|
||||
- 如果运行失败:`{ runId, status: "error", error }`。
|
||||
- 通知投递在主运行完成后运行,属于尽力而为;`status: "ok"` 不保证通知已成功投递。
|
||||
- 通过 Gateway网关 `agent.wait`(服务器端)等待,因此重连不会中断等待。
|
||||
- 智能体间消息上下文会注入到主运行中。
|
||||
- 主运行完成后,OpenClaw 运行**回复往返循环**:
|
||||
- 第 2 轮及之后在请求方和目标智能体之间交替。
|
||||
- 回复 `REPLY_SKIP` 可停止来回往返。
|
||||
- 通告投递在主运行完成后运行,且为尽力而为;`status: "ok"` 不保证通告已投递。
|
||||
- 通过 Gateway 网关 `agent.wait`(服务器端)等待,因此重连不会丢失等待。
|
||||
- 智能体到智能体的消息上下文会为主运行注入。
|
||||
- 主运行完成后,OpenClaw 运行**回复循环**:
|
||||
- 第 2 轮及以后在请求者和目标智能体之间交替。
|
||||
- 精确回复 `REPLY_SKIP` 以停止来回。
|
||||
- 最大轮数为 `session.agentToAgent.maxPingPongTurns`(0–5,默认 5)。
|
||||
- 循环结束后,OpenClaw 运行**智能体间通知步骤**(仅目标智能体):
|
||||
- 回复 `ANNOUNCE_SKIP` 可保持静默。
|
||||
- 其他任何回复都会发送到目标渠道。
|
||||
- 通知步骤包含原始请求 + 第 1 轮回复 + 最新的往返回复。
|
||||
- 循环结束后,OpenClaw 运行**智能体到智能体通告步骤**(仅目标智能体):
|
||||
- 精确回复 `ANNOUNCE_SKIP` 以保持静默。
|
||||
- 任何其他回复都会发送到目标渠道。
|
||||
- 通告步骤包括原始请求 + 第 1 轮回复 + 最新的来回回复。
|
||||
|
||||
## Channel 字段
|
||||
|
||||
- 对于群组,`channel` 是会话条目上记录的渠道。
|
||||
- 对于私聊,`channel` 从 `lastChannel` 映射。
|
||||
- 对于定时任务/钩子/节点,`channel` 为 `internal`。
|
||||
- 如果缺失,`channel` 为 `unknown`。
|
||||
- 对于直接聊天,`channel` 从 `lastChannel` 映射。
|
||||
- 对于 cron/hook/node,`channel` 是 `internal`。
|
||||
- 如果缺失,`channel` 是 `unknown`。
|
||||
|
||||
## 安全 / 发送策略
|
||||
|
||||
基于策略的按渠道/聊天类型阻止(非按会话 ID)。
|
||||
基于策略的按渠道/聊天类型阻止(不是按会话 id)。
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -144,45 +144,45 @@ x-i18n:
|
||||
|
||||
执行点:
|
||||
|
||||
- `chat.send` / `agent`(Gateway网关)
|
||||
- `chat.send` / `agent`(Gateway 网关)
|
||||
- 自动回复投递逻辑
|
||||
|
||||
## sessions_spawn
|
||||
|
||||
在隔离会话中生成子智能体运行,并将结果通知回请求方的聊天渠道。
|
||||
在隔离会话中生成子智能体运行,并将结果通告回请求者聊天渠道。
|
||||
|
||||
参数:
|
||||
|
||||
- `task`(必需)
|
||||
- `task`(必填)
|
||||
- `label?`(可选;用于日志/UI)
|
||||
- `agentId?`(可选;如允许,在另一个智能体 ID 下生成)
|
||||
- `agentId?`(可选;如果允许,在另一个智能体 id 下生成)
|
||||
- `model?`(可选;覆盖子智能体模型;无效值会报错)
|
||||
- `runTimeoutSeconds?`(默认 0;设置后,N 秒后中止子智能体运行)
|
||||
- `runTimeoutSeconds?`(默认 0;设置时,在 N 秒后中止子智能体运行)
|
||||
- `cleanup?`(`delete|keep`,默认 `keep`)
|
||||
|
||||
允许列表:
|
||||
|
||||
- `agents.list[].subagents.allowAgents`:允许通过 `agentId` 使用的智能体 ID 列表(`["*"]` 允许任意)。默认:仅请求方智能体。
|
||||
- `agents.list[].subagents.allowAgents`:通过 `agentId` 允许的智能体 id 列表(`["*"]` 允许任意)。默认:仅请求者智能体。
|
||||
|
||||
发现:
|
||||
|
||||
- 使用 `agents_list` 发现哪些智能体 ID 可用于 `sessions_spawn`。
|
||||
- 使用 `agents_list` 发现哪些智能体 id 允许用于 `sessions_spawn`。
|
||||
|
||||
行为:
|
||||
|
||||
- 启动一个新的 `agent:<agentId>:subagent:<uuid>` 会话,设置 `deliver: false`。
|
||||
- 使用 `deliver: false` 启动新的 `agent:<agentId>:subagent:<uuid>` 会话。
|
||||
- 子智能体默认使用完整工具集**减去会话工具**(可通过 `tools.subagents.tools` 配置)。
|
||||
- 子智能体不允许调用 `sessions_spawn`(不允许子智能体生成子智能体)。
|
||||
- 子智能体不允许调用 `sessions_spawn`(无子智能体 → 子智能体生成)。
|
||||
- 始终非阻塞:立即返回 `{ status: "accepted", runId, childSessionKey }`。
|
||||
- 完成后,OpenClaw 运行子智能体**通知步骤**并将结果发布到请求方的聊天渠道。
|
||||
- 在通知步骤中回复 `ANNOUNCE_SKIP` 可保持静默。
|
||||
- 通知回复规范化为 `Status`/`Result`/`Notes`;`Status` 来自运行时结果(非模型文本)。
|
||||
- 子智能体会话在 `agents.defaults.subagents.archiveAfterMinutes`(默认:60)后自动归档。
|
||||
- 通知回复包含统计行(运行时间、token 数、sessionKey/sessionId、对话记录路径和可选费用)。
|
||||
- 完成后,OpenClaw 运行子智能体**通告步骤**并将结果发布到请求者聊天渠道。
|
||||
- 在通告步骤中精确回复 `ANNOUNCE_SKIP` 以保持静默。
|
||||
- 通告回复规范化为 `Status`/`Result`/`Notes`;`Status` 来自运行时结果(不是模型文本)。
|
||||
- 子智能体会话在 `agents.defaults.subagents.archiveAfterMinutes` 后自动归档(默认:60)。
|
||||
- 通告回复包含统计行(运行时间、token 数、sessionKey/sessionId、记录路径和可选成本)。
|
||||
|
||||
## 沙箱会话可见性
|
||||
|
||||
沙箱隔离的会话可以使用会话工具,但默认只能看到通过 `sessions_spawn` 生成的会话。
|
||||
沙箱隔离的会话可以使用会话工具,但默认情况下它们只能看到通过 `sessions_spawn` 生成的会话。
|
||||
|
||||
配置:
|
||||
|
||||
@@ -191,7 +191,7 @@ x-i18n:
|
||||
agents: {
|
||||
defaults: {
|
||||
sandbox: {
|
||||
// 默认: "spawned"
|
||||
// 默认:"spawned"
|
||||
sessionToolsVisibility: "spawned", // 或 "all"
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
---
|
||||
read_when:
|
||||
- 修改会话处理或存储时
|
||||
- 修改会话处理或存储
|
||||
summary: 聊天的会话管理规则、键和持久化
|
||||
title: 会话管理
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:24:31Z"
|
||||
generated_at: "2026-02-03T07:47:44Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 147c8d1a4b6b4864cb16ad942feba80181b6b0e29afa765e7958f8c2483746b5
|
||||
source_path: concepts/session.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 会话管理
|
||||
|
||||
OpenClaw 将**每个智能体一个私聊会话**视为主会话。私聊归并到 `agent:<agentId>:<mainKey>`(默认 `main`),而群组/频道聊天拥有各自独立的键。`session.mainKey` 会被遵循。
|
||||
OpenClaw 将**每个智能体的一个直接聊天会话**视为主会话。直接聊天折叠为 `agent:<agentId>:<mainKey>`(默认 `main`),而群组/频道聊天获得各自的键。`session.mainKey` 会被遵循。
|
||||
|
||||
使用 `session.dmScope` 控制**私信**的分组方式:
|
||||
使用 `session.dmScope` 控制**私信**如何分组:
|
||||
|
||||
- `main`(默认):所有私信共享主会话以保持连续性。
|
||||
- `per-peer`:按发送者 ID 跨渠道隔离。
|
||||
- `per-peer`:跨渠道按发送者 ID 隔离。
|
||||
- `per-channel-peer`:按渠道 + 发送者隔离(推荐用于多用户收件箱)。
|
||||
- `per-account-channel-peer`:按账号 + 渠道 + 发送者隔离(推荐用于多账号收件箱)。
|
||||
使用 `session.identityLinks` 将带提供商前缀的对端 ID 映射到规范身份,这样在使用 `per-peer`、`per-channel-peer` 或 `per-account-channel-peer` 时,同一个人可以跨渠道共享私信会话。
|
||||
- `per-account-channel-peer`:按账户 + 渠道 + 发送者隔离(推荐用于多账户收件箱)。
|
||||
使用 `session.identityLinks` 将带提供商前缀的对等 ID 映射到规范身份,这样在使用 `per-peer`、`per-channel-peer` 或 `per-account-channel-peer` 时,同一个人可以跨渠道共享私信会话。
|
||||
|
||||
## Gateway网关是权威数据源
|
||||
## Gateway 网关是唯一数据源
|
||||
|
||||
所有会话状态均由 **Gateway网关**("主" OpenClaw)管理。UI 客户端(macOS 应用、WebChat 等)必须向 Gateway网关查询会话列表和令牌计数,而不是读取本地文件。
|
||||
所有会话状态都**由 Gateway 网关拥有**("主" OpenClaw)。UI 客户端(macOS 应用、WebChat 等)必须向 Gateway 网关查询会话列表和令牌计数,而不是读取本地文件。
|
||||
|
||||
- 在**远程模式**下,你关心的会话存储位于远程 Gateway网关主机上,而不是你的 Mac 上。
|
||||
- UI 中显示的令牌计数来自 Gateway网关存储字段(`inputTokens`、`outputTokens`、`totalTokens`、`contextTokens`)。客户端不会解析 JSONL 记录来"修正"总数。
|
||||
- 在**远程模式**下,你关心的会话存储位于远程 Gateway 网关主机上,而不是你的 Mac 上。
|
||||
- UI 中显示的令牌计数来自 Gateway 网关的存储字段(`inputTokens`、`outputTokens`、`totalTokens`、`contextTokens`)。客户端不会解析 JSONL 对话记录来"修正"总数。
|
||||
|
||||
## 状态存储位置
|
||||
|
||||
- 在 **Gateway网关主机**上:
|
||||
- 在 **Gateway 网关主机**上:
|
||||
- 存储文件:`~/.openclaw/agents/<agentId>/sessions/sessions.json`(每个智能体)。
|
||||
- 对话记录:`~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl`(Telegram 话题会话使用 `.../<SessionId>-topic-<threadId>.jsonl`)。
|
||||
- 存储是一个 `sessionKey -> { sessionId, updatedAt, ... }` 的映射。删除条目是安全的;它们会按需重新创建。
|
||||
- 群组条目可能包含 `displayName`、`channel`、`subject`、`room` 和 `space`,用于在 UI 中标记会话。
|
||||
- 会话条目包含 `origin` 元数据(标签 + 路由提示),以便 UI 能够解释会话的来源。
|
||||
- OpenClaw **不会**读取旧版 Pi/Tau 会话文件夹。
|
||||
- 存储是一个映射 `sessionKey -> { sessionId, updatedAt, ... }`。删除条目是安全的;它们会按需重新创建。
|
||||
- 群组条目可能包含 `displayName`、`channel`、`subject`、`room` 和 `space` 以在 UI 中标记会话。
|
||||
- 会话条目包含 `origin` 元数据(标签 + 路由提示),以便 UI 可以解释会话的来源。
|
||||
- OpenClaw **不**读取旧版 Pi/Tau 会话文件夹。
|
||||
|
||||
## 会话修剪
|
||||
|
||||
OpenClaw 默认在 LLM 调用之前从内存上下文中修剪**旧的工具结果**。
|
||||
这**不会**重写 JSONL 历史记录。请参见 [/concepts/session-pruning](/concepts/session-pruning)。
|
||||
默认情况下,OpenClaw 在 LLM 调用之前从内存上下文中修剪**旧的工具结果**。
|
||||
这**不会**重写 JSONL 历史记录。参见 [/concepts/session-pruning](/concepts/session-pruning)。
|
||||
|
||||
## 压缩前记忆刷写
|
||||
## 压缩前记忆刷新
|
||||
|
||||
当会话接近自动压缩时,OpenClaw 可以运行一次**静默记忆刷写**轮次,提醒模型将持久笔记写入磁盘。这仅在工作区可写时运行。请参见[记忆](/concepts/memory)和[压缩](/concepts/compaction)。
|
||||
当会话接近自动压缩时,OpenClaw 可以运行一个**静默记忆刷新**轮次,提醒模型将持久性笔记写入磁盘。这仅在工作区可写时运行。参见[记忆](/concepts/memory)和[压缩](/concepts/compaction)。
|
||||
|
||||
## 传输层 → 会话键的映射
|
||||
## 传输到会话键的映射
|
||||
|
||||
- 私聊遵循 `session.dmScope`(默认 `main`)。
|
||||
- `main`:`agent:<agentId>:<mainKey>`(跨设备/渠道保持连续性)。
|
||||
- 多个电话号码和渠道可以映射到同一个智能体主键;它们充当一个对话的传输通道。
|
||||
- 直接聊天遵循 `session.dmScope`(默认 `main`)。
|
||||
- `main`:`agent:<agentId>:<mainKey>`(跨设备/渠道的连续性)。
|
||||
- 多个电话号码和渠道可以映射到同一个智能体主键;它们作为进入同一个对话的传输通道。
|
||||
- `per-peer`:`agent:<agentId>:dm:<peerId>`。
|
||||
- `per-channel-peer`:`agent:<agentId>:<channel>:dm:<peerId>`。
|
||||
- `per-account-channel-peer`:`agent:<agentId>:<channel>:<accountId>:dm:<peerId>`(accountId 默认为 `default`)。
|
||||
- 如果 `session.identityLinks` 匹配到带提供商前缀的对端 ID(例如 `telegram:123`),规范键将替换 `<peerId>`,使同一个人跨渠道共享会话。
|
||||
- 群聊隔离状态:`agent:<agentId>:<channel>:group:<id>`(房间/频道使用 `agent:<agentId>:<channel>:channel:<id>`)。
|
||||
- Telegram 论坛话题在群组 ID 后附加 `:topic:<threadId>` 以实现隔离。
|
||||
- 旧版 `group:<id>` 键仍被识别以支持迁移。
|
||||
- 入站上下文可能仍使用 `group:<id>`;渠道从 `Provider` 推断并规范化为 `agent:<agentId>:<channel>:group:<id>` 的规范形式。
|
||||
- 如果 `session.identityLinks` 匹配带提供商前缀的对等 ID(例如 `telegram:123`),则规范键替换 `<peerId>`,这样同一个人可以跨渠道共享会话。
|
||||
- 群组聊天隔离状态:`agent:<agentId>:<channel>:group:<id>`(房间/频道使用 `agent:<agentId>:<channel>:channel:<id>`)。
|
||||
- Telegram 论坛话题在群组 ID 后附加 `:topic:<threadId>` 以进行隔离。
|
||||
- 旧版 `group:<id>` 键仍被识别以进行迁移。
|
||||
- 入站上下文可能仍使用 `group:<id>`;渠道从 `Provider` 推断并规范化为规范的 `agent:<agentId>:<channel>:group:<id>` 形式。
|
||||
- 其他来源:
|
||||
- 定时任务:`cron:<job.id>`
|
||||
- Webhook:`hook:<uuid>`(除非由 hook 显式设置)
|
||||
- Webhooks:`hook:<uuid>`(除非由 hook 显式设置)
|
||||
- 节点运行:`node-<nodeId>`
|
||||
|
||||
## 生命周期
|
||||
|
||||
- 重置策略:会话持续复用直到过期,过期在下一条入站消息时评估。
|
||||
- 每日重置:默认为 **Gateway网关主机本地时间凌晨 4:00**。当会话的最后更新早于最近一次每日重置时间时,会话即为过期。
|
||||
- 空闲重置(可选):`idleMinutes` 添加一个滑动空闲窗口。当同时配置了每日重置和空闲重置时,**先到期的那个**强制创建新会话。
|
||||
- 旧版仅空闲模式:如果设置了 `session.idleMinutes` 但没有任何 `session.reset`/`resetByType` 配置,OpenClaw 会保持仅空闲模式以向后兼容。
|
||||
- 按类型覆盖(可选):`resetByType` 允许你为 `dm`、`group` 和 `thread` 会话覆盖策略(thread = Slack/Discord 线程、Telegram 话题、连接器提供的 Matrix 线程)。
|
||||
- 按渠道覆盖(可选):`resetByChannel` 覆盖特定渠道的重置策略(适用于该渠道的所有会话类型,优先级高于 `reset`/`resetByType`)。
|
||||
- 重置触发器:精确的 `/new` 或 `/reset`(加上 `resetTriggers` 中的额外项)会启动一个新的会话 ID,并将消息的剩余部分继续传递。`/new <model>` 接受模型别名、`provider/model` 或提供商名称(模糊匹配)来设置新会话的模型。如果单独发送 `/new` 或 `/reset`,OpenClaw 会运行一个简短的"问候"轮次来确认重置。
|
||||
- 手动重置:从存储中删除特定键或移除 JSONL 记录;下一条消息会重新创建它们。
|
||||
- 隔离的定时任务每次运行都会创建一个新的 `sessionId`(不复用空闲会话)。
|
||||
- 重置策略:会话被重用直到过期,过期在下一条入站消息时评估。
|
||||
- 每日重置:默认为 **Gateway 网关主机本地时间凌晨 4:00**。当会话的最后更新早于最近的每日重置时间时,会话即为过期。
|
||||
- 空闲重置(可选):`idleMinutes` 添加一个滑动空闲窗口。当同时配置每日和空闲重置时,**先过期者**强制新会话。
|
||||
- 旧版仅空闲模式:如果你设置了 `session.idleMinutes` 而没有任何 `session.reset`/`resetByType` 配置,OpenClaw 会保持仅空闲模式以保持向后兼容。
|
||||
- 按类型覆盖(可选):`resetByType` 允许你覆盖 `dm`、`group` 和 `thread` 会话的策略(thread = Slack/Discord 线程、Telegram 话题、连接器提供的 Matrix 线程)。
|
||||
- 按渠道覆盖(可选):`resetByChannel` 覆盖渠道的重置策略(适用于该渠道的所有会话类型,优先于 `reset`/`resetByType`)。
|
||||
- 重置触发器:精确的 `/new` 或 `/reset`(加上 `resetTriggers` 中的任何额外项)启动新的会话 ID 并传递消息的其余部分。`/new <model>` 接受模型别名、`provider/model` 或提供商名称(模糊匹配)来设置新会话模型。如果单独发送 `/new` 或 `/reset`,OpenClaw 会运行一个简短的"问候"轮次来确认重置。
|
||||
- 手动重置:从存储中删除特定键或删除 JSONL 对话记录;下一条消息会重新创建它们。
|
||||
- 隔离的定时任务总是每次运行生成新的 `sessionId`(没有空闲重用)。
|
||||
|
||||
## 发送策略(可选)
|
||||
|
||||
无需列出单个 ID 即可按特定会话类型阻止投递。
|
||||
阻止特定会话类型的投递,无需列出单个 ID。
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -98,27 +98,27 @@ OpenClaw 默认在 LLM 调用之前从内存上下文中修剪**旧的工具结
|
||||
}
|
||||
```
|
||||
|
||||
运行时覆盖(仅限所有者):
|
||||
运行时覆盖(仅所有者):
|
||||
|
||||
- `/send on` → 允许此会话发送
|
||||
- `/send off` → 禁止此会话发送
|
||||
- `/send on` → 为此会话允许
|
||||
- `/send off` → 为此会话拒绝
|
||||
- `/send inherit` → 清除覆盖并使用配置规则
|
||||
请将这些作为独立消息发送以确保生效。
|
||||
将这些作为独立消息发送以使其生效。
|
||||
|
||||
## 配置(可选的重命名示例)
|
||||
## 配置(可选重命名示例)
|
||||
|
||||
```json5
|
||||
// ~/.openclaw/openclaw.json
|
||||
{
|
||||
session: {
|
||||
scope: "per-sender", // 保持群组键独立
|
||||
dmScope: "main", // 私信连续性(共享收件箱请设置 per-channel-peer/per-account-channel-peer)
|
||||
scope: "per-sender", // keep group keys separate
|
||||
dmScope: "main", // DM continuity (set per-channel-peer/per-account-channel-peer for shared inboxes)
|
||||
identityLinks: {
|
||||
alice: ["telegram:123456789", "discord:987654321012345678"],
|
||||
},
|
||||
reset: {
|
||||
// 默认值:mode=daily,atHour=4(Gateway网关主机本地时间)。
|
||||
// 如果同时设置了 idleMinutes,先到期的优先。
|
||||
// Defaults: mode=daily, atHour=4 (gateway host local time).
|
||||
// If you also set idleMinutes, whichever expires first wins.
|
||||
mode: "daily",
|
||||
atHour: 4,
|
||||
idleMinutes: 120,
|
||||
@@ -141,26 +141,26 @@ OpenClaw 默认在 LLM 调用之前从内存上下文中修剪**旧的工具结
|
||||
## 检查
|
||||
|
||||
- `openclaw status` — 显示存储路径和最近的会话。
|
||||
- `openclaw sessions --json` — 转储所有条目(使用 `--active <minutes>` 进行筛选)。
|
||||
- `openclaw gateway call sessions.list --params '{}'` — 从运行中的 Gateway网关获取会话(使用 `--url`/`--token` 访问远程 Gateway网关)。
|
||||
- 在聊天中发送 `/status` 作为独立消息,可查看智能体是否可达、会话上下文使用了多少、当前的思考/详细模式开关,以及 WhatsApp 网页凭证的最后刷新时间(有助于发现需要重新链接的情况)。
|
||||
- 发送 `/context list` 或 `/context detail` 查看系统提示词和注入的工作区文件中的内容(以及最大的上下文贡献者)。
|
||||
- 发送 `/stop` 作为独立消息,可中止当前运行、清除该会话的排队后续消息,并停止由其生成的任何子智能体运行(回复中包含已停止的数量)。
|
||||
- 发送 `/compact`(可选指令)作为独立消息,可总结旧的上下文并释放窗口空间。请参见 [/concepts/compaction](/concepts/compaction)。
|
||||
- JSONL 记录可以直接打开以查看完整的对话轮次。
|
||||
- `openclaw sessions --json` — 导出每个条目(使用 `--active <minutes>` 过滤)。
|
||||
- `openclaw gateway call sessions.list --params '{}'` — 从运行中的 Gateway 网关获取会话(使用 `--url`/`--token` 进行远程 Gateway 网关访问)。
|
||||
- 在聊天中单独发送 `/status` 消息可查看智能体是否可达、会话上下文使用了多少、当前的思考/详细模式开关,以及你的 WhatsApp Web 凭证上次刷新时间(有助于发现重新链接需求)。
|
||||
- 发送 `/context list` 或 `/context detail` 查看系统提示中的内容和注入的工作区文件(以及最大的上下文贡献者)。
|
||||
- 单独发送 `/stop` 消息可中止当前运行、清除该会话的排队后续操作,并停止从中生成的任何子智能体运行(回复包含已停止的数量)。
|
||||
- 单独发送 `/compact`(可选指令)消息可总结旧上下文并释放窗口空间。参见 [/concepts/compaction](/concepts/compaction)。
|
||||
- 可以直接打开 JSONL 对话记录查看完整轮次。
|
||||
|
||||
## 提示
|
||||
|
||||
- 将主键专用于一对一对话;让群组保持各自独立的键。
|
||||
- 自动化清理时,删除单个键而不是整个存储,以保留其他地方的上下文。
|
||||
- 将主键专用于 1:1 通信;让群组保留各自的键。
|
||||
- 自动清理时,删除单个键而不是整个存储,以保留其他地方的上下文。
|
||||
|
||||
## 会话来源元数据
|
||||
|
||||
每个会话条目在 `origin` 中记录其来源(尽力而为):
|
||||
每个会话条目记录其来源(尽力而为)在 `origin` 中:
|
||||
|
||||
- `label`:人类可读标签(从对话标签 + 群组主题/频道解析)
|
||||
- `provider`:规范化的渠道 ID(包括扩展)
|
||||
- `from`/`to`:入站信封中的原始路由 ID
|
||||
- `accountId`:提供商账号 ID(多账号时)
|
||||
- `accountId`:提供商账户 ID(多账户时)
|
||||
- `threadId`:渠道支持时的线程/话题 ID
|
||||
来源字段为私信、频道和群组填充。如果连接器仅更新投递路由(例如,保持私信主会话活跃),它仍应提供入站上下文,以便会话保留其说明性元数据。扩展可以通过在入站上下文中发送 `ConversationLabel`、`GroupSubject`、`GroupChannel`、`GroupSpace` 和 `SenderName`,并调用 `recordSessionMetaFromInbound`(或将相同的上下文传递给 `updateLastRoute`)来实现。
|
||||
来源字段为私信、频道和群组填充。如果连接器仅更新投递路由(例如,保持私信主会话新鲜),它仍应提供入站上下文,以便会话保留其解释器元数据。扩展可以通过在入站上下文中发送 `ConversationLabel`、`GroupSubject`、`GroupChannel`、`GroupSpace` 和 `SenderName` 并调用 `recordSessionMetaFromInbound`(或将相同上下文传递给 `updateLastRoute`)来实现。
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
---
|
||||
read_when:
|
||||
- 解释流式传输或分块在渠道上的工作方式
|
||||
- 更改块流式传输或渠道分块行为
|
||||
- 调试重复/提前的块回复或草稿流式传输问题
|
||||
- 解释流式传输或分块在渠道上如何工作
|
||||
- 更改分块流式传输或渠道分块行为
|
||||
- 调试重复/提前的块回复或草稿流式传输
|
||||
summary: 流式传输 + 分块行为(块回复、草稿流式传输、限制)
|
||||
title: 流式传输与分块
|
||||
title: 流式传输和分块
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:24:24Z"
|
||||
generated_at: "2026-02-03T10:05:41Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: f014eb1898c4351b1d6b812223226d91324701e3e809cd0f3faf6679841bc353
|
||||
source_path: concepts/streaming.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 流式传输 + 分块
|
||||
|
||||
OpenClaw 有两个独立的"流式传输"层:
|
||||
|
||||
- **块流式传输(渠道):** 在助手生成内容时发送已完成的**块**。这些是普通的渠道消息(不是 token 增量)。
|
||||
- **类 Token 流式传输(仅 Telegram):** 在生成过程中用部分文本更新**草稿气泡**;最终消息在结束时发送。
|
||||
- **分块流式传输(渠道):** 在助手写入时发出已完成的**块**。这些是普通的渠道消息(不是令牌增量)。
|
||||
- **类令牌流式传输(仅限 Telegram):** 在生成时用部分文本更新**草稿气泡**;最终消息在结束时发送。
|
||||
|
||||
目前**没有真正的 token 流式传输**到外部渠道消息。Telegram 草稿流式传输是唯一的部分流式传输界面。
|
||||
目前**没有真正的令牌流式传输**到外部渠道消息。Telegram 草稿流式传输是唯一的部分流式传输界面。
|
||||
|
||||
## 块流式传输(渠道消息)
|
||||
## 分块流式传输(渠道消息)
|
||||
|
||||
块流式传输在助手输出可用时以粗粒度块发送。
|
||||
分块流式传输在助手输出可用时以粗粒度块发送。
|
||||
|
||||
```
|
||||
Model output
|
||||
模型输出
|
||||
└─ text_delta/events
|
||||
├─ (blockStreamingBreak=text_end)
|
||||
│ └─ chunker emits blocks as buffer grows
|
||||
│ └─ 分块器在缓冲区增长时发出块
|
||||
└─ (blockStreamingBreak=message_end)
|
||||
└─ chunker flushes at message_end
|
||||
└─ channel send (block replies)
|
||||
└─ 分块器在 message_end 时刷新
|
||||
└─ 渠道发送(块回复)
|
||||
```
|
||||
|
||||
图例:
|
||||
|
||||
- `text_delta/events`:模型流事件(对于非流式模型可能较为稀疏)。
|
||||
- `chunker`:`EmbeddedBlockChunker`,应用最小/最大边界 + 断点偏好。
|
||||
- `text_delta/events`:模型流事件(对于非流式模型可能稀疏)。
|
||||
- `chunker`:应用最小/最大边界 + 断点偏好的 `EmbeddedBlockChunker`。
|
||||
- `channel send`:实际的出站消息(块回复)。
|
||||
|
||||
**控制项:**
|
||||
|
||||
- `agents.defaults.blockStreamingDefault`:`"on"`/`"off"`(默认关闭)。
|
||||
- 渠道覆盖:`*.blockStreaming`(以及按账户的变体)可按渠道强制 `"on"`/`"off"`。
|
||||
- 渠道覆盖:`*.blockStreaming`(以及每账户变体)可为每个渠道强制设置 `"on"`/`"off"`。
|
||||
- `agents.defaults.blockStreamingBreak`:`"text_end"` 或 `"message_end"`。
|
||||
- `agents.defaults.blockStreamingChunk`:`{ minChars, maxChars, breakPreference? }`。
|
||||
- `agents.defaults.blockStreamingCoalesce`:`{ minChars?, maxChars?, idleMs? }`(发送前合并流式块)。
|
||||
- 渠道硬性上限:`*.textChunkLimit`(例如 `channels.whatsapp.textChunkLimit`)。
|
||||
- 渠道分块模式:`*.chunkMode`(默认 `length`,`newline` 在空行(段落边界)处分割,然后再按长度分块)。
|
||||
- Discord 软性上限:`channels.discord.maxLinesPerMessage`(默认 17)拆分过长的回复以避免 UI 裁剪。
|
||||
- 渠道硬上限:`*.textChunkLimit`(例如 `channels.whatsapp.textChunkLimit`)。
|
||||
- 渠道分块模式:`*.chunkMode`(默认 `length`,`newline` 在长度分块之前按空行(段落边界)分割)。
|
||||
- Discord 软上限:`channels.discord.maxLinesPerMessage`(默认 17)分割高度较大的回复以避免 UI 裁剪。
|
||||
|
||||
**边界语义:**
|
||||
|
||||
- `text_end`:分块器发出块后立即流式传输;在每个 `text_end` 时刷新。
|
||||
- `message_end`:等待助手消息完成后,再刷新缓冲输出。
|
||||
- `text_end`:分块器发出时立即流式传输块;在每个 `text_end` 时刷新。
|
||||
- `message_end`:等到助手消息完成,然后刷新缓冲的输出。
|
||||
|
||||
`message_end` 在缓冲文本超过 `maxChars` 时仍会使用分块器,因此可能在最后发出多个块。
|
||||
如果缓冲文本超过 `maxChars`,`message_end` 仍然使用分块器,因此可能在最后发出多个块。
|
||||
|
||||
## 分块算法(低/高边界)
|
||||
|
||||
@@ -68,66 +68,66 @@ Model output
|
||||
- **低边界:** 在缓冲区 >= `minChars` 之前不发出(除非强制)。
|
||||
- **高边界:** 优先在 `maxChars` 之前分割;如果强制,则在 `maxChars` 处分割。
|
||||
- **断点偏好:** `paragraph` → `newline` → `sentence` → `whitespace` → 硬断点。
|
||||
- **代码围栏:** 永远不在围栏内分割;当在 `maxChars` 处被强制分割时,关闭并重新打开围栏以保持 Markdown 有效。
|
||||
- **代码围栏:** 从不在围栏内分割;当在 `maxChars` 处强制分割时,关闭 + 重新打开围栏以保持 Markdown 有效。
|
||||
|
||||
`maxChars` 会被限制在渠道的 `textChunkLimit` 以内,因此不会超过按渠道的上限。
|
||||
`maxChars` 被限制在渠道 `textChunkLimit` 内,因此你无法超过每渠道的上限。
|
||||
|
||||
## 合并(合并流式块)
|
||||
|
||||
当块流式传输启用时,OpenClaw 可以在发送前**合并连续的块**。这减少了"单行刷屏"的情况,同时仍提供渐进式输出。
|
||||
启用分块流式传输时,OpenClaw 可以在发送前**合并连续的块分块**。这减少了"单行刷屏",同时仍提供渐进式输出。
|
||||
|
||||
- 合并会等待**空闲间隔**(`idleMs`)后再刷新。
|
||||
- 缓冲区受 `maxChars` 限制,超出时会刷新。
|
||||
- `minChars` 防止在积累足够文本之前发送微小片段(最终刷新始终发送剩余文本)。
|
||||
- 连接符由 `blockStreamingChunk.breakPreference` 派生(`paragraph` → `\n\n`,`newline` → `\n`,`sentence` → 空格)。
|
||||
- 渠道覆盖可通过 `*.blockStreamingCoalesce` 设置(包括按账户的配置)。
|
||||
- 除非覆盖,Signal/Slack/Discord 的默认合并 `minChars` 会提升至 1500。
|
||||
- 合并在**空闲间隙**(`idleMs`)后刷新。
|
||||
- 缓冲区受 `maxChars` 限制,超过时将刷新。
|
||||
- `minChars` 防止微小片段发送,直到累积足够文本(最终刷新始终发送剩余文本)。
|
||||
- 连接符从 `blockStreamingChunk.breakPreference` 派生(`paragraph` → `\n\n`,`newline` → `\n`,`sentence` → 空格)。
|
||||
- 渠道覆盖通过 `*.blockStreamingCoalesce` 可用(包括每账户配置)。
|
||||
- 除非覆盖,Signal/Slack/Discord 的默认合并 `minChars` 提高到 1500。
|
||||
|
||||
## 块之间的仿真人节奏
|
||||
## 块之间的类人节奏
|
||||
|
||||
当块流式传输启用时,你可以在块回复之间(第一个块之后)添加**随机停顿**。这让多气泡回复感觉更自然。
|
||||
启用分块流式传输时,你可以在块回复之间添加**随机暂停**(在第一个块之后)。这使多气泡响应感觉更自然。
|
||||
|
||||
- 配置:`agents.defaults.humanDelay`(通过 `agents.list[].humanDelay` 按智能体覆盖)。
|
||||
- 模式:`off`(默认)、`natural`(800–2500ms)、`custom`(`minMs`/`maxMs`)。
|
||||
- 仅适用于**块回复**,不适用于最终回复或工具摘要。
|
||||
|
||||
## "流式发送块还是一次性发送全部"
|
||||
## "流式传输块或全部内容"
|
||||
|
||||
对应关系:
|
||||
这映射到:
|
||||
|
||||
- **流式发送块:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(边生成边发送)。非 Telegram 渠道还需要设置 `*.blockStreaming: true`。
|
||||
- **结束时一次性发送:** `blockStreamingBreak: "message_end"`(刷新一次,如果内容很长可能产生多个块)。
|
||||
- **不使用块流式传输:** `blockStreamingDefault: "off"`(仅最终回复)。
|
||||
- **流式传输块:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(边生成边发出)。非 Telegram 渠道还需要 `*.blockStreaming: true`。
|
||||
- **最后流式传输全部内容:** `blockStreamingBreak: "message_end"`(刷新一次,如果很长可能有多个块)。
|
||||
- **无分块流式传输:** `blockStreamingDefault: "off"`(只有最终回复)。
|
||||
|
||||
**渠道说明:** 对于非 Telegram 渠道,块流式传输**默认关闭**,除非 `*.blockStreaming` 显式设置为 `true`。Telegram 可以通过 `channels.telegram.streamMode` 进行草稿流式传输,无需块回复。
|
||||
**渠道说明:** 对于非 Telegram 渠道,分块流式传输**默认关闭**,除非 `*.blockStreaming` 明确设置为 `true`。Telegram 可以在没有块回复的情况下流式传输草稿(`channels.telegram.streamMode`)。
|
||||
|
||||
配置位置提醒:`blockStreaming*` 默认值位于 `agents.defaults` 下,而非根配置。
|
||||
配置位置提醒:`blockStreaming*` 默认值位于 `agents.defaults` 下,而不是根配置。
|
||||
|
||||
## Telegram 草稿流式传输(类 Token)
|
||||
## Telegram 草稿流式传输(类令牌)
|
||||
|
||||
Telegram 是唯一支持草稿流式传输的渠道:
|
||||
|
||||
- 在**带话题的私聊**中使用 Bot API `sendMessageDraft`。
|
||||
- 在**带主题的私聊**中使用 Bot API `sendMessageDraft`。
|
||||
- `channels.telegram.streamMode: "partial" | "block" | "off"`。
|
||||
- `partial`:用最新的流式文本更新草稿。
|
||||
- `block`:以分块方式更新草稿(使用相同的分块器规则)。
|
||||
- `off`:不进行草稿流式传输。
|
||||
- `block`:以分块方式更新草稿(相同的分块器规则)。
|
||||
- `off`:无草稿流式传输。
|
||||
- 草稿分块配置(仅用于 `streamMode: "block"`):`channels.telegram.draftChunk`(默认值:`minChars: 200`,`maxChars: 800`)。
|
||||
- 草稿流式传输与块流式传输是分离的;块回复默认关闭,仅在非 Telegram 渠道通过 `*.blockStreaming: true` 启用。
|
||||
- 草稿流式传输与分块流式传输分开;块回复默认关闭,仅在非 Telegram 渠道上通过 `*.blockStreaming: true` 启用。
|
||||
- 最终回复仍然是普通消息。
|
||||
- `/reasoning stream` 将推理过程写入草稿气泡(仅 Telegram)。
|
||||
- `/reasoning stream` 将推理写入草稿气泡(仅限 Telegram)。
|
||||
|
||||
当草稿流式传输处于活跃状态时,OpenClaw 会禁用该回复的块流式传输,以避免双重流式传输。
|
||||
当草稿流式传输活跃时,OpenClaw 会为该回复禁用分块流式传输以避免双重流式传输。
|
||||
|
||||
```
|
||||
Telegram (private + topics)
|
||||
└─ sendMessageDraft (draft bubble)
|
||||
├─ streamMode=partial → update latest text
|
||||
└─ streamMode=block → chunker updates draft
|
||||
└─ final reply → normal message
|
||||
Telegram(私聊 + 主题)
|
||||
└─ sendMessageDraft(草稿气泡)
|
||||
├─ streamMode=partial → 更新最新文本
|
||||
└─ streamMode=block → 分块器更新草稿
|
||||
└─ 最终回复 → 普通消息
|
||||
```
|
||||
|
||||
图例:
|
||||
|
||||
- `sendMessageDraft`:Telegram 草稿气泡(不是真正的消息)。
|
||||
- `final reply`:普通的 Telegram 消息发送。
|
||||
- `final reply`:普通 Telegram 消息发送。
|
||||
|
||||
@@ -2,56 +2,56 @@
|
||||
read_when:
|
||||
- 编辑系统提示词文本、工具列表或时间/心跳部分
|
||||
- 更改工作区引导或 Skills 注入行为
|
||||
summary: OpenClaw 系统提示词的内容及其组装方式
|
||||
summary: OpenClaw 系统提示词包含的内容及其组装方式
|
||||
title: 系统提示词
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:24:17Z"
|
||||
generated_at: "2026-02-03T07:46:58Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: bef4b2674ba0414ce28fd08a4c3ead0e0ebe989e7df3c88ca8a0b2abfec2a50b
|
||||
source_path: concepts/system-prompt.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 系统提示词
|
||||
|
||||
OpenClaw 为每次智能体运行构建自定义系统提示词。该提示词由 **OpenClaw 自有**,不使用 p-coding-agent 的默认提示词。
|
||||
OpenClaw 为每次智能体运行构建自定义系统提示词。该提示词由 **OpenClaw 拥有**,不使用 p-coding-agent 默认提示词。
|
||||
|
||||
提示词由 OpenClaw 组装并注入到每次智能体运行中。
|
||||
该提示词由 OpenClaw 组装并注入到每次智能体运行中。
|
||||
|
||||
## 结构
|
||||
|
||||
提示词有意保持紧凑,使用固定的部分:
|
||||
该提示词设计紧凑,使用固定部分:
|
||||
|
||||
- **工具**:当前工具列表及简短描述。
|
||||
- **安全**:简短的护栏提醒,避免模型追求权力或绕过监督。
|
||||
- **Skills**(可用时):告诉模型如何按需加载 Skills 指令。
|
||||
- **OpenClaw 自更新**:如何运行 `config.apply` 和 `update.run`。
|
||||
- **工作区**:工作目录(`agents.defaults.workspace`)。
|
||||
- **文档**:OpenClaw 文档的本地路径(仓库或 npm 包)及查阅时机。
|
||||
- **工作区文件(注入的)**:表明引导文件包含在下方。
|
||||
- **沙箱**(启用时):表明沙箱隔离运行时、沙箱路径,以及是否可用提权执行。
|
||||
- **当前日期和时间**:用户本地时间、时区和时间格式。
|
||||
- **回复标签**:支持的提供商的可选回复标签语法。
|
||||
- **心跳**:心跳提示和确认行为。
|
||||
- **运行时**:主机、操作系统、Node、模型、仓库根目录(检测到时)、思考级别(一行)。
|
||||
- **推理**:当前可见性级别及 /reasoning 切换提示。
|
||||
- **Tooling**:当前工具列表 + 简短描述。
|
||||
- **Safety**:简短的防护提醒,避免追求权力的行为或绕过监督。
|
||||
- **Skills**(如果可用):告诉模型如何按需加载 Skill 指令。
|
||||
- **OpenClaw Self-Update**:如何运行 `config.apply` 和 `update.run`。
|
||||
- **Workspace**:工作目录(`agents.defaults.workspace`)。
|
||||
- **Documentation**:OpenClaw 文档的本地路径(仓库或 npm 包)以及何时阅读它们。
|
||||
- **Workspace Files (injected)**:表示下方包含引导文件。
|
||||
- **Sandbox**(启用时):表示沙箱隔离运行时、沙箱路径,以及是否可用提权执行。
|
||||
- **Current Date & Time**:用户本地时间、时区和时间格式。
|
||||
- **Reply Tags**:支持的提供商的可选回复标签语法。
|
||||
- **Heartbeats**:心跳提示词和确认行为。
|
||||
- **Runtime**:主机、操作系统、node、模型、仓库根目录(检测到时)、思考级别(一行)。
|
||||
- **Reasoning**:当前可见性级别 + /reasoning 切换提示。
|
||||
|
||||
系统提示词中的安全护栏是建议性的。它们引导模型行为但不强制执行策略。请使用工具策略、执行审批、沙箱隔离和渠道白名单进行硬性执行;操作人员可以按设计禁用这些功能。
|
||||
系统提示词中的安全防护是建议性的。它们指导模型行为但不强制执行策略。使用工具策略、执行审批、沙箱隔离和渠道允许列表进行硬性执行;运维人员可以按设计禁用这些。
|
||||
|
||||
## 提示词模式
|
||||
|
||||
OpenClaw 可以为子智能体渲染更小的系统提示词。运行时为每次运行设置一个 `promptMode`(非用户可配置项):
|
||||
OpenClaw 可以为子智能体渲染更小的系统提示词。运行时为每次运行设置一个 `promptMode`(不是面向用户的配置):
|
||||
|
||||
- `full`(默认):包含上述所有部分。
|
||||
- `minimal`:用于子智能体;省略**Skills**、**记忆召回**、**OpenClaw 自更新**、**模型别名**、**用户身份**、**回复标签**、**消息**、**静默回复**和**心跳**。工具、**安全**、工作区、沙箱、当前日期和时间(已知时)、运行时和注入的上下文仍然可用。
|
||||
- `none`:仅返回基础身份行。
|
||||
- `minimal`:用于子智能体;省略 **Skills**、**Memory Recall**、**OpenClaw Self-Update**、**Model Aliases**、**User Identity**、**Reply Tags**、**Messaging**、**Silent Replies** 和 **Heartbeats**。Tooling、**Safety**、Workspace、Sandbox、Current Date & Time(已知时)、Runtime 和注入的上下文仍然可用。
|
||||
- `none`:仅返回基本身份行。
|
||||
|
||||
当 `promptMode=minimal` 时,额外注入的提示词标记为**子智能体上下文**而非**群聊上下文**。
|
||||
当 `promptMode=minimal` 时,额外注入的提示词标记为 **Subagent Context** 而不是 **Group Chat Context**。
|
||||
|
||||
## 工作区引导注入
|
||||
|
||||
引导文件经过裁剪后附加在**项目上下文**下,使模型无需显式读取即可看到身份和配置上下文:
|
||||
引导文件被修剪后附加在 **Project Context** 下,这样模型无需显式读取即可看到身份和配置上下文:
|
||||
|
||||
- `AGENTS.md`
|
||||
- `SOUL.md`
|
||||
@@ -59,30 +59,30 @@ OpenClaw 可以为子智能体渲染更小的系统提示词。运行时为每
|
||||
- `IDENTITY.md`
|
||||
- `USER.md`
|
||||
- `HEARTBEAT.md`
|
||||
- `BOOTSTRAP.md`(仅在全新工作区时)
|
||||
- `BOOTSTRAP.md`(仅在全新工作区上)
|
||||
|
||||
大文件会被截断并附加标记。每个文件的最大大小由 `agents.defaults.bootstrapMaxChars` 控制(默认:20000)。缺失的文件会注入一个简短的缺失文件标记。
|
||||
大文件会带截断标记被截断。每个文件的最大大小由 `agents.defaults.bootstrapMaxChars` 控制(默认:20000)。缺失的文件会注入一个简短的缺失文件标记。
|
||||
|
||||
内部钩子可以通过 `agent:bootstrap` 拦截此步骤,以修改或替换注入的引导文件(例如将 `SOUL.md` 替换为备选人格)。
|
||||
内部钩子可以通过 `agent:bootstrap` 拦截此步骤以修改或替换注入的引导文件(例如将 `SOUL.md` 替换为其他角色)。
|
||||
|
||||
要查看每个注入文件的贡献量(原始 vs 注入、截断情况,以及工具模式开销),请使用 `/context list` 或 `/context detail`。参见[上下文](/concepts/context)。
|
||||
要检查每个注入文件贡献了多少(原始 vs 注入、截断,加上工具 schema 开销),使用 `/context list` 或 `/context detail`。参见[上下文](/concepts/context)。
|
||||
|
||||
## 时间处理
|
||||
|
||||
当用户时区已知时,系统提示词包含专门的**当前日期和时间**部分。为保持提示词缓存稳定,现在仅包含**时区**(不含动态时钟或时间格式)。
|
||||
当用户时区已知时,系统提示词包含专用的 **Current Date & Time** 部分。为保持提示词缓存稳定,它现在只包含**时区**(没有动态时钟或时间格式)。
|
||||
|
||||
当智能体需要当前时间时,请使用 `session_status`;状态卡片包含时间戳行。
|
||||
当智能体需要当前时间时使用 `session_status`;状态卡片包含时间戳行。
|
||||
|
||||
配置方式:
|
||||
|
||||
- `agents.defaults.userTimezone`
|
||||
- `agents.defaults.timeFormat`(`auto` | `12` | `24`)
|
||||
|
||||
详见[日期和时间](/date-time)了解全部行为细节。
|
||||
完整行为详情参见[日期和时间](/date-time)。
|
||||
|
||||
## Skills
|
||||
|
||||
当存在符合条件的 Skills 时,OpenClaw 会注入一个紧凑的**可用 Skills 列表**(`formatSkillsForPrompt`),其中包含每个 Skills 的**文件路径**。提示词指示模型使用 `read` 加载位于所列位置(工作区、托管或捆绑)的 SKILL.md。如果没有符合条件的 Skills,则省略 Skills 部分。
|
||||
当存在符合条件的 Skills 时,OpenClaw 注入一个紧凑的**可用 Skills 列表**(`formatSkillsForPrompt`),其中包含每个 Skill 的**文件路径**。提示词指示模型使用 `read` 加载列出位置(工作区、托管或内置)的 SKILL.md。如果没有符合条件的 Skills,则省略 Skills 部分。
|
||||
|
||||
```
|
||||
<available_skills>
|
||||
@@ -94,8 +94,8 @@ OpenClaw 可以为子智能体渲染更小的系统提示词。运行时为每
|
||||
</available_skills>
|
||||
```
|
||||
|
||||
这样可以保持基础提示词精简,同时仍然支持有针对性的 Skills 使用。
|
||||
这使基础提示词保持小巧,同时仍然支持有针对性的 Skill 使用。
|
||||
|
||||
## 文档
|
||||
|
||||
当可用时,系统提示词包含一个**文档**部分,指向本地 OpenClaw 文档目录(仓库工作区中的 `docs/` 或捆绑的 npm 包文档),并注明公共镜像、源代码仓库、社区 Discord 和 ClawHub (https://clawhub.com) 用于 Skills 发现。提示词指示模型在查询 OpenClaw 行为、命令、配置或架构时优先查阅本地文档,并在可能时自行运行 `openclaw status`(仅在无法访问时才询问用户)。
|
||||
如果可用,系统提示词包含一个 **Documentation** 部分,指向本地 OpenClaw 文档目录(仓库工作区中的 `docs/` 或打包的 npm 包文档),并注明公共镜像、源仓库、社区 Discord 和 ClawHub (https://clawhub.com) 用于 Skills 发现。提示词指示模型首先查阅本地文档了解 OpenClaw 行为、命令、配置或架构,并尽可能自己运行 `openclaw status`(仅在无法访问时询问用户)。
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
---
|
||||
read_when:
|
||||
- 更新协议模式或代码生成
|
||||
summary: TypeBox 模式作为 Gateway网关协议的唯一事实来源
|
||||
summary: TypeBox 模式作为 Gateway 网关协议的唯一事实来源
|
||||
title: TypeBox
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T20:24:36Z"
|
||||
generated_at: "2026-02-03T07:47:23Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 233800f4f5fabe8ed0e1b3d8aded2eca27252e08c9b0b24ea9c6293e9282c918
|
||||
source_path: concepts/typebox.md
|
||||
workflow: 14
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# TypeBox 作为协议的唯一事实来源
|
||||
# TypeBox 作为协议的事实来源
|
||||
|
||||
最后更新:2026-01-10
|
||||
|
||||
TypeBox 是一个 TypeScript 优先的模式库。我们用它来定义 **Gateway网关 WebSocket 协议**(握手、请求/响应、服务器事件)。这些模式驱动**运行时验证**、**JSON Schema 导出**以及 macOS 应用的 **Swift 代码生成**。一个事实来源;其他一切都是生成的。
|
||||
TypeBox 是一个 TypeScript 优先的模式库。我们用它来定义 **Gateway 网关 WebSocket 协议**(握手、请求/响应、服务器事件)。这些模式驱动**运行时验证**、**JSON Schema 导出**和 macOS 应用的 **Swift 代码生成**。一个事实来源;其他一切都是生成的。
|
||||
|
||||
如果你想了解更高层次的协议上下文,请从 [Gateway网关架构](/concepts/architecture) 开始。
|
||||
如果你想了解更高层次的协议上下文,请从 [Gateway 网关架构](/concepts/architecture)开始。
|
||||
|
||||
## 心智模型(30 秒)
|
||||
|
||||
每条 Gateway网关 WS 消息都是以下三种帧之一:
|
||||
每个 Gateway 网关 WS 消息都是以下三种帧之一:
|
||||
|
||||
- **请求**:`{ type: "req", id, method, params }`
|
||||
- **响应**:`{ type: "res", id, ok, payload | error }`
|
||||
- **事件**:`{ type: "event", event, payload, seq?, stateVersion? }`
|
||||
- **Request**:`{ type: "req", id, method, params }`
|
||||
- **Response**:`{ type: "res", id, ok, payload | error }`
|
||||
- **Event**:`{ type: "event", event, payload, seq?, stateVersion? }`
|
||||
|
||||
第一帧**必须**是 `connect` 请求。之后,客户端可以调用方法(如 `health`、`send`、`chat.send`)并订阅事件(如 `presence`、`tick`、`agent`)。
|
||||
第一个帧**必须**是 `connect` 请求。之后,客户端可以调用方法(例如 `health`、`send`、`chat.send`)并订阅事件(例如 `presence`、`tick`、`agent`)。
|
||||
|
||||
连接流程(最简):
|
||||
连接流程(最小):
|
||||
|
||||
```
|
||||
Client Gateway网关
|
||||
Client Gateway
|
||||
|---- req:connect -------->|
|
||||
|<---- res:hello-ok --------|
|
||||
|<---- event:tick ----------|
|
||||
@@ -41,46 +41,46 @@ Client Gateway网关
|
||||
|<---- res:health ----------|
|
||||
```
|
||||
|
||||
常见方法 + 事件:
|
||||
常用方法 + 事件:
|
||||
|
||||
| 类别 | 示例 | 备注 |
|
||||
| ---- | --------------------------------------------------------- | ----------------------------------- |
|
||||
| 核心 | `connect`、`health`、`status` | `connect` 必须在首位 |
|
||||
| 消息 | `send`、`poll`、`agent`、`agent.wait` | 有副作用的操作需要 `idempotencyKey` |
|
||||
| 聊天 | `chat.history`、`chat.send`、`chat.abort`、`chat.inject` | WebChat 使用这些 |
|
||||
| 会话 | `sessions.list`、`sessions.patch`、`sessions.delete` | 会话管理 |
|
||||
| 节点 | `node.list`、`node.invoke`、`node.pair.*` | Gateway网关 WS + 节点操作 |
|
||||
| 事件 | `tick`、`presence`、`agent`、`chat`、`health`、`shutdown` | 服务器推送 |
|
||||
| 类别 | 示例 | 说明 |
|
||||
| ---- | --------------------------------------------------------- | ------------------------------- |
|
||||
| 核心 | `connect`、`health`、`status` | `connect` 必须是第一个 |
|
||||
| 消息 | `send`、`poll`、`agent`、`agent.wait` | 有副作用的需要 `idempotencyKey` |
|
||||
| 聊天 | `chat.history`、`chat.send`、`chat.abort`、`chat.inject` | WebChat 使用这些 |
|
||||
| 会话 | `sessions.list`、`sessions.patch`、`sessions.delete` | 会话管理 |
|
||||
| 节点 | `node.list`、`node.invoke`、`node.pair.*` | Gateway 网关 WS + 节点操作 |
|
||||
| 事件 | `tick`、`presence`、`agent`、`chat`、`health`、`shutdown` | 服务器推送 |
|
||||
|
||||
权威列表位于 `src/gateway/server.ts`(`METHODS`、`EVENTS`)。
|
||||
权威列表在 `src/gateway/server.ts`(`METHODS`、`EVENTS`)中。
|
||||
|
||||
## 模式文件位置
|
||||
## 模式所在位置
|
||||
|
||||
- 源文件:`src/gateway/protocol/schema.ts`
|
||||
- 源码:`src/gateway/protocol/schema.ts`
|
||||
- 运行时验证器(AJV):`src/gateway/protocol/index.ts`
|
||||
- 服务器握手 + 方法分发:`src/gateway/server.ts`
|
||||
- 节点客户端:`src/gateway/client.ts`
|
||||
- 生成的 JSON Schema:`dist/protocol.schema.json`
|
||||
- 生成的 Swift 模型:`apps/macos/Sources/OpenClawProtocol/Gateway网关Models.swift`
|
||||
- 生成的 Swift 模型:`apps/macos/Sources/OpenClawProtocol/GatewayModels.swift`
|
||||
|
||||
## 当前流水线
|
||||
## 当前流程
|
||||
|
||||
- `pnpm protocol:gen`
|
||||
- 将 JSON Schema(draft‑07)写入 `dist/protocol.schema.json`
|
||||
- `pnpm protocol:gen:swift`
|
||||
- 生成 Swift Gateway网关模型
|
||||
- 生成 Swift Gateway 网关模型
|
||||
- `pnpm protocol:check`
|
||||
- 运行两个生成器并验证输出已提交
|
||||
|
||||
## 模式在运行时的使用方式
|
||||
|
||||
- **服务器端**:每个入站帧都通过 AJV 验证。握手仅接受参数匹配 `ConnectParams` 的 `connect` 请求。
|
||||
- **客户端**:JS 客户端在使用事件和响应帧之前进行验证。
|
||||
- **方法接口**:Gateway网关在 `hello-ok` 中公布支持的 `methods` 和 `events`。
|
||||
- **服务器端**:每个入站帧都用 AJV 验证。握手仅接受参数匹配 `ConnectParams` 的 `connect` 请求。
|
||||
- **客户端**:JS 客户端在使用之前验证事件和响应帧。
|
||||
- **方法表面**:Gateway 网关在 `hello-ok` 中公布支持的 `methods` 和 `events`。
|
||||
|
||||
## 示例帧
|
||||
|
||||
连接(第一条消息):
|
||||
Connect(第一条消息):
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -143,7 +143,7 @@ Hello-ok 响应:
|
||||
|
||||
## 最小客户端(Node.js)
|
||||
|
||||
最小可用流程:连接 + 健康检查。
|
||||
最小可用流程:connect + health。
|
||||
|
||||
```ts
|
||||
import { WebSocket } from "ws";
|
||||
@@ -183,7 +183,7 @@ ws.on("message", (data) => {
|
||||
});
|
||||
```
|
||||
|
||||
## 实战示例:端到端添加一个方法
|
||||
## 实践示例:端到端添加方法
|
||||
|
||||
示例:添加一个新的 `system.echo` 请求,返回 `{ ok: true, text }`。
|
||||
|
||||
@@ -217,7 +217,7 @@ export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;
|
||||
|
||||
2. **验证**
|
||||
|
||||
在 `src/gateway/protocol/index.ts` 中导出 AJV 验证器:
|
||||
在 `src/gateway/protocol/index.ts` 中,导出一个 AJV 验证器:
|
||||
|
||||
```ts
|
||||
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);
|
||||
@@ -225,10 +225,10 @@ export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEcho
|
||||
|
||||
3. **服务器行为**
|
||||
|
||||
在 `src/gateway/server-methods/system.ts` 中添加处理器:
|
||||
在 `src/gateway/server-methods/system.ts` 中添加处理程序:
|
||||
|
||||
```ts
|
||||
export const systemHandlers: Gateway网关RequestHandlers = {
|
||||
export const systemHandlers: GatewayRequestHandlers = {
|
||||
"system.echo": ({ params, respond }) => {
|
||||
const text = String(params.text ?? "");
|
||||
respond(true, { ok: true, text });
|
||||
@@ -236,7 +236,7 @@ export const systemHandlers: Gateway网关RequestHandlers = {
|
||||
};
|
||||
```
|
||||
|
||||
在 `src/gateway/server-methods.ts` 中注册(已合并 `systemHandlers`),然后将 `"system.echo"` 添加到 `src/gateway/server.ts` 的 `METHODS` 中。
|
||||
在 `src/gateway/server-methods.ts` 中注册(已合并 `systemHandlers`),然后将 `"system.echo"` 添加到 `src/gateway/server.ts` 中的 `METHODS`。
|
||||
|
||||
4. **重新生成**
|
||||
|
||||
@@ -252,28 +252,28 @@ pnpm protocol:check
|
||||
|
||||
Swift 生成器输出:
|
||||
|
||||
- 包含 `req`、`res`、`event` 和 `unknown` case 的 `Gateway网关Frame` 枚举
|
||||
- 带有 `req`、`res`、`event` 和 `unknown` 情况的 `GatewayFrame` 枚举
|
||||
- 强类型的 payload 结构体/枚举
|
||||
- `ErrorCode` 值和 `GATEWAY_PROTOCOL_VERSION`
|
||||
|
||||
未知帧类型保留为原始 payload 以实现前向兼容。
|
||||
未知的帧类型保留为原始 payload 以实现向前兼容。
|
||||
|
||||
## 版本控制 + 兼容性
|
||||
|
||||
- `PROTOCOL_VERSION` 位于 `src/gateway/protocol/schema.ts`。
|
||||
- 客户端发送 `minProtocol` + `maxProtocol`;服务器拒绝不匹配的版本。
|
||||
- `PROTOCOL_VERSION` 在 `src/gateway/protocol/schema.ts` 中。
|
||||
- 客户端发送 `minProtocol` + `maxProtocol`;服务器拒绝不匹配的。
|
||||
- Swift 模型保留未知帧类型以避免破坏旧客户端。
|
||||
|
||||
## 模式规范和约定
|
||||
## 模式模式和约定
|
||||
|
||||
- 大多数对象使用 `additionalProperties: false` 以实现严格的 payload。
|
||||
- `NonEmptyString` 是 ID 和方法/事件名称的默认类型。
|
||||
- 顶层 `Gateway网关Frame` 在 `type` 上使用**鉴别器**。
|
||||
- 有副作用的方法通常需要在参数中包含 `idempotencyKey`(示例:`send`、`poll`、`agent`、`chat.send`)。
|
||||
- `NonEmptyString` 是 ID 和方法/事件名称的默认值。
|
||||
- 顶层 `GatewayFrame` 在 `type` 上使用**鉴别器**。
|
||||
- 有副作用的方法通常需要在 params 中包含 `idempotencyKey`(示例:`send`、`poll`、`agent`、`chat.send`)。
|
||||
|
||||
## 实时 Schema JSON
|
||||
## 实时 schema JSON
|
||||
|
||||
生成的 JSON Schema 位于仓库的 `dist/protocol.schema.json`。已发布的原始文件通常可在以下位置获取:
|
||||
生成的 JSON Schema 在仓库的 `dist/protocol.schema.json` 中。发布的原始文件通常可在以下位置获取:
|
||||
|
||||
- https://raw.githubusercontent.com/openclaw/openclaw/main/dist/protocol.schema.json
|
||||
|
||||
|
||||
Reference in New Issue
Block a user