01、卸载龙虾的命令是什么?
“王哥,你这个问题问得好。很多人以为卸载就是跑一条 npm uninstall -g openclaw,错。”
这样卸载不干净,残留文件会藏在系统的各个角落,下次重装的时候各种报错——端口被占用、配置冲突、插件加载失败,一堆莫名其妙的问题。
正确的卸载姿势分三步。
第一步:停止 Gateway 服务
openclaw gateway stop
如果 Gateway 正在跑任务,强制停止可能会丢数据。建议先检查状态:
openclaw gateway status
确认显示 stopped 再继续。
第二步:执行官方卸载命令
openclaw uninstall
这个命令会弹出一个交互界面,让你选择要删除哪些内容。用空格键全选,然后回车确认。它会帮你:
- 停止并卸载 Gateway 服务
- 删除
~/.openclaw/状态目录 - 清理工作区配置
- 移除插件和缓存
第三步:移除全局 CLI 包
npm rm -g openclaw
如果你用的是 pnpm 或 bun,对应换成:
pnpm rm -g openclaw
bun rm -g openclaw
遇到权限错误就加 sudo。
老王点点头:“那卸载后怎么验证干净?”
我说:“执行以下命令,确认没有残留:”
# 检查全局包
npm list -g openclaw
# 检查目录
ls ~/.openclaw/
# 检查端口占用
lsof -i:18789
全部返回空或“not found”,才算卸载干净。
老王听完点点头:“行,卸载这块确实熟。那我追问一下,~/.openclaw/ 目录里都有什么?为什么删这个目录这么重要?”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,蔚来和机器人公司的日常实习拿下,恭喜这位球友。
02、龙虾的架构了解吗?
“王哥,你这是要考我架构啊。”
~/.openclaw/ 是 OpenClaw 的“神经中枢”,里面存放着所有配置和状态。
~/.openclaw/
├── openclaw.json # 全局配置文件
├── gateway/ # Gateway 相关
│ ├── config.json # Gateway 配置
│ ├── logs/ # 日志目录
│ └── pid # 进程 ID 文件
├── plugins/ # 插件目录
│ ├── @openclaw/ # 官方插件
│ └── @wecom/ # 第三方插件
├── workspaces/ # Agent 工作区
│ ├── default/ # 默认 Agent
│ └── paigit/ # 自定义 Agent
├── skills/ # 技能包
├── cache/ # 缓存目录
└── .env # 环境变量
老王继续追问:“这里面的每个目录都有什么用?你挑重点讲。”
2-1 openclaw.json有什么用?
这是 OpenClaw 的“大脑配置中心”。
{
"version": "2026.3.2",
"gateway": {
"port": 18789,
"auth": "token",
"host": "0.0.0.0"
},
"channels": {
"feishu": {
"appId": "cli_xxx",
"appSecret": "xxx"
},
"wecom": {
"botId": "xxx",
"secret": "xxx"
}
},
"model": {
"provider": "glm",
"profile": "coding-plan",
"defaultModel": "glm-5"
},
"plugins": [
"@openclaw/feishu-plugin",
"@wecom/wecom-openclaw-plugin"
]
}
里面记录了:
- Gateway 配置:监听端口、认证方式、绑定地址
- IM 通道配置:飞书、企微等应用的凭证
- 大模型配置:提供商、套餐、默认模型
- 插件列表:已安装的插件及其加载顺序
王哥追问:“Gateway 配置里的 auth: "token" 是什么意思?Gateway 到底是干什么的?”
2-2 Gateway有什么用?
“王哥,Gateway 是 OpenClaw 架构里最关键的设计。”
很多人用 OpenClaw,只知道装完跑 openclaw gateway start,但不知道 Gateway 到底在干啥。
简单说,Gateway 是一个常驻后台的消息路由服务。
它的职责有三层:
第一层:接收消息
你在飞书群里@机器人,飞书会把消息推送到 Gateway。Gateway 收到后,解析消息内容,识别是哪个 Agent、哪个会话。
第二层:分发任务
Gateway 把消息路由给对应的 Agent 处理。如果你配置了多个 Agent(比如一个负责代码审核,一个负责会员审批),Gateway 会根据消息来源判断该交给谁。
第三层:返回结果
Agent 处理完任务后,把结果交给 Gateway,Gateway 再通过 IM 通道发回飞书。
飞书消息 → Gateway → Agent → 大模型 → Agent → Gateway → 飞书回复
老王听完眼睛一亮:“小伙子有水平啊。为什么要这样分层?Gateway 和 Agent 为什么不耦合在一起?”
我说:“解耦。Gateway 负责 IM 通信,Agent 负责任务执行。这样你可以一个 Gateway 挂多个 Agent,每个 Agent 用不同的模型、跑不同的任务,互不干扰。”
老王点点头:“那如果 Gateway 挂了怎么办?有没有高可用方案?”
我说:“王哥,你这问题越来越深了。目前 OpenClaw 官方没有提供高可用方案,Gateway 是单点的。如果要上生产,我的建议是:”
- Gateway 集群部署,用负载均衡器分发请求
- 会话状态下沉到 Redis,Gateway 无状态
- 多实例之间用分布式锁协调任务执行
老王若有所思:“那插件呢?OpenClaw 的插件机制是怎么跑的?”
2-3 插件体系了解吗?
我说:“OpenClaw 采用的是微内核架构。”
核心只提供最基础的能力——消息收发、任务调度、工具调用。其他功能全部通过插件扩展。
- 飞书支持?插件。
- 企微支持?插件。
- 文档处理?插件。
插件安装在 ~/.openclaw/plugins/ 目录下,每个插件是一个独立的 npm 包。
# 安装飞书插件
openclaw plugins install @openclaw/feishu-plugin
# 安装企微插件
openclaw plugins install @wecom/wecom-openclaw-plugin
# 查看已安装插件
openclaw plugins list
老王追问:“插件加载的时机是什么?Gateway 启动的时候?如果两个插件对同一条消息都想处理,怎么解决冲突?”
我说:“对,Gateway 启动时会扫描 plugins 目录,按 openclaw.json 里的顺序加载所有插件。每个插件会注册自己的消息处理器和工具函数。”
“冲突解决靠优先级机制——openclaw.json 里可以设置插件优先级,优先级高的先处理。另外每个插件有自己的命名空间,互不干扰。”
老王满意地点点头:“架构这块讲清楚了。那我再问你——Gateway 的生命周期管理是怎样的?启动、停止、重启流程是什么?中间有什么坑?”
2-4 Gateway 的生命周期了解吗?
我说:“王哥,这个问题很实用,很多人踩过坑。”
启动 Gateway
openclaw gateway start
启动时会做几件事:
- 加载
openclaw.json配置 - 扫描并加载插件
- 初始化 IM 通道(连接飞书、企微等)
- 启动 HTTP 服务监听端口
- 写入 pid 文件
检查 Gateway 状态
openclaw gateway status
会显示:
- 运行状态(running / stopped)
- 进程 ID
- 监听端口
- 已加载的插件数量
停止 Gateway
openclaw gateway stop
如果 Gateway 卡住,可以强制停止:
openclaw gateway stop --force
或者直接杀进程:
kill $(cat ~/.openclaw/gateway/pid)
重启 Gateway
修改配置后需要重启:
openclaw gateway restart
2-5 启动时报错怎么排查?
老王追问:“启动的时候常见的报错有哪些?怎么排查?”
我说:“最常见的有三个问题。”
问题一:端口被占用
Error: Port 18789 is already in use
解决方法:
# 查看谁占用了端口
lsof -i:18789
# 杀掉占用进程
kill -9 <PID>
问题二:插件加载失败
Error: Failed to load plugin @openclaw/feishu-plugin
解决方法:
# 重新安装插件
openclaw plugins uninstall @openclaw/feishu-plugin
openclaw plugins install @openclaw/feishu-plugin
问题三:配置文件损坏
Error: Invalid JSON in openclaw.json
解决方法:检查 JSON 格式,或者直接删掉重新配置。
老王点点头:“那消息流转呢?当你在飞书群里@机器人时,消息是怎么流转到 Agent 并返回结果的?整个链路涉及哪些组件?”
2-6 消息是怎么从飞书到龙虾再返回呢?
我说:“王哥,是这样的。”
第一步:事件订阅
飞书把消息推给 Gateway。这需要在飞书开放平台配置事件订阅,开启 im.message.receive_v1 事件。
第二步:消息解析
Gateway 收到消息后,解析消息内容,识别来源(哪个群、哪个用户)和意图(要干什么)。
第三步:路由分发
根据 bindings 配置,把消息发给对应的 Agent。如果你配置了多个 Agent,Gateway 会根据消息来源判断该交给谁。
第四步:执行任务
Agent 调用大模型处理任务。如果是复杂任务,Agent 会拆解成多个步骤,一步步执行。
第五步:结果返回
Gateway 把结果通过 IM 通道返回给飞书。
2-7 龙虾有记忆吗?
老王追问:“那状态是怎么维护的?多轮对话的上下文存在哪里?”
我说:“会话上下文存在 ~/.openclaw/workspaces/<agent>/memory/ 目录下。每次对话会序列化保存,Gateway 重启后可以恢复。多轮对话用 session_id 标识,防止串台。”
2-8 并发处理能力如何?
老王接着问:“如果同时有 100 个用户@机器人,Gateway 怎么处理并发?”
我说:“Gateway 用异步非阻塞 IO 处理请求。每个消息生成唯一 request_id,防止混淆。Agent 执行队列化,避免资源竞争。”
老王点点头:“那 Agent 响应很慢怎么办?有没有优化方案?”
我说:“有几种优化思路:”
- 换更快的模型(比如 GPT-5.4)
- 简化 BOOT.md 里的指令
- 用流式输出,边生成边返回
- 复杂任务后台异步执行,先返回 ACK
老王听完感慨:“你这理解得够深的。那我再问你一个实际应用的问题,你用 OpenClaw 干过什么真实的业务场景?别给我整那些 demo。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,腾讯暑期实习拿下,恭喜这位球友。
03、你用OpenClaw都干过什么?
我说:“王哥,这个问题问到我心坎里了。”
讲一个真实的场景——技术派(paicoding.com)的 gitcode 账号审核。
技术派加入的会员需要开通 gitcode 代码仓库的访问权限。以前这个流程是这样的:
- 会员申请加入
- 我收到通知
- 手动打开 gitcode 后台
- 搜索用户昵称
- 添加到对应的项目组
- 发消息通知会员审核通过
一个账号还好,如果一次来 20 个呢?光这个流程就要折腾半小时。
现在呢?我把这个任务交给了 OpenClaw。
第一步:创建一个专属 Agent
openclaw agents add PaiGit --workspace ~/openclaw-workspaces/paigit
第二步:配置 BOOT.md 告诉 Agent 它的职责
# PaiGit 职责
你是技术派的 gitcode 账号审核助手。
当收到飞书消息包含用户昵称时:
1. 登录 gitcode 后台
2. 搜索用户
3. 添加到技术派-会员组
4. 回复审核结果
第三步:绑定飞书通道
在飞书群里,我直接发消息:
帮我审核以下用户:张三、李四、王五
OpenClaw 收到消息后,自动执行整个审核流程。20 个账号,1 分钟搞定。
老王听完眼睛都直了:“这效率提升有点狠啊。”
我说:“还不止。我还给它设了定时任务,每天早上 9 点自动检查有没有新的待审核申请,有的话直接处理,处理完推送到飞书群。”
老王来了兴趣:“还有没有别的场景?”
3-1 飞书群消息同步搞过吗?
我又给他讲了一个——飞书群消息同步。
技术派有好几个飞书群:开发群、运营群、会员群。有时候一个群里发的消息需要同步到其他群,比如新功能上线通知。
以前的做法是:手动复制粘贴,或者用飞书的转发功能。但转发格式不好看,而且容易漏。
现在我用 OpenClaw 搞定了这个流程。
配置 Webhook
每个飞书群都有一个 Webhook 地址,可以在群设置里找到。
把这些 Webhook 地址告诉 OpenClaw:
记住以下群的 Webhook 地址:
发送同步指令
在开发群、运营群、会员群同时发送:派聪明 v2.0 今天上线了,新增了 AI 面试助手功能,大家快去体验!
OpenClaw 会自动调用 Webhook,把消息发到三个群。
老王点点头:“这个场景实用,省得一个个群转发。”
3-2 定时任务推送搞过吗?
“定时任务呢?你刚才说的每天早上 9 点给你推送最新的 hacknews 消息,是怎么实现的?”
OpenClaw 支持用自然语言创建定时任务。
直接告诉它:
每天早上 9 点,检查有 hacknews 有没有好玩的AI讯息,整理一下发送给我。
OpenClaw 会创建一个定时任务,到点自动执行。
定时任务的底层实现是 cron。OpenClaw 会把自然语言转成 cron 表达式,然后在后台调度执行。
老王追问:“定时任务如果执行失败了怎么办?有没有重试机制?”
我说:“目前 OpenClaw 没有内置重试机制,但可以通过 BOOT.md 里加错误处理逻辑来实现。比如告诉 Agent:'如果任务执行失败,等待 5 分钟后重试,最多重试 3 次'。”
“另外,定时任务执行结果会记录到日志里,可以在 ~/.openclaw/gateway/logs/ 目录下查看。”
老王听完感慨:“这三个场景都挺实用的,不是那种为了用工具而用工具。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,京东云和华为春招拿下,恭喜这位球友。
04、使用龙虾过程中遇到过哪些问题?
老王话锋一转:“那我再问你一个方向——OpenClaw 需要调用大模型 API,在实际使用中,你遇到过哪些问题?比如 token 限制、响应延迟、费用控制。你是怎么解决的?”
我说:“王哥,这个问题太实际了,我踩过不少坑。”
04-1 token 如何优化?
OpenClaw 烧 token 是真的快。一个稍微复杂的任务,Agent 在后台可能调用十几轮甚至几十轮大模型。
我的优化方法:
- prompt 压缩:去除冗余信息,只传必要上下文
- 上下文裁剪:只保留最近 N 轮对话
- 结果缓存:相同问题直接返回缓存结果
04-2 响应慢怎么办?
大模型响应慢是通病。我的方案:
- 流式输出:边生成边返回,减少用户等待
- 异步处理:复杂任务后台执行,先返回 ACK
- 模型选择:简单任务用 Lite 模型,复杂任务用 Pro 模型
04-3 费用控制怎么做?
这个最头疼。我的做法:
- 配额管理:每天/每月设置 token 上限
- 成本追踪:记录每个任务的 token 消耗
- 自动降级:额度用完时切换到便宜模型
老王追问:“如果大模型 API 挂了怎么办?有没有降级方案?”
我说:“有。大模型挂了,切换到本地模型(比如 Qwen)。网络不通,用缓存兜底。超时处理,返回友好提示而非报错。”
04-4 如果让你把 OpenClaw 部署到生产环境,你会考虑哪些问题?
老王最后问了一个很实际的问题:“如果让你把 OpenClaw 部署到生产环境,你会考虑哪些问题?”
我说:“王哥,这个问题我能讲半小时。我挑重点说。”
高可用
- Gateway 集群部署,用负载均衡器分发请求
- 会话状态下沉到 Redis,Gateway 无状态
- 多实例之间用分布式锁协调任务执行
监控
- Gateway 层:监听端口、连接数、QPS
- Agent 层:任务执行成功率、平均响应时间
- 模型层:token 消耗、费用统计、模型调用成功率
日志
- 按模块分割日志(gateway.log、agent.log、plugin.log)
- 关键操作记录审计日志
- 日志轮转和归档(保留 30 天)
安全
- API Key 加密存储,支持动态轮换
- 插件白名单机制,只允许官方插件
- 网络隔离,Gateway 只对外暴露必要端口
老王点点头:“最后一个问题——你在用 OpenClaw 的过程中踩过什么坑?怎么排查的?”
04-5 使用过程中踩过哪些坑?
我说:“我挑几个最典型的说。”
Gateway 启动后收不到消息怎么办?
老王问:“这个怎么排查?”
我说:“分三步走。”
第一步:检查日志
cat ~/.openclaw/gateway/logs/error.log
看有没有报错信息。常见错误有:飞书 App ID 填错、权限没开通、事件订阅没配置。
第二步:检查通道状态
openclaw channels status
看飞书/企微通道是不是正常连接。
第三步:检查飞书配置
去飞书开放平台,确认:
- 事件订阅已开启
im.message.receive_v1事件已添加- 长链接模式已启用
模型调用失败怎么办?
老王问:“这个呢?”
我说:“模型调用失败一般是三个原因:”
原因一:API Key 无效或过期
去大模型平台检查 API Key 状态,必要时重新生成。
原因二:额度用尽
如果是 Coding Plan 套餐,检查本月额度是否用完。用完了要么等下个月,要么升级套餐。
原因三:网络问题
# 测试网络连通性
curl -I https://open.bigmodel.cn
如果连不上,检查代理配置或防火墙设置。
Agent 响应很慢怎么办?
老王问:“响应慢怎么优化?”
我说:“分情况处理。”
如果是模型推理慢:
- 换更快的模型(Doubao-Seed-2.0-Lite 比 Pro 快 30%)
- 简化 prompt,减少 token 数量
- 开启流式输出,边生成边返回
如果是任务执行慢:
- 拆分大任务,分批执行
- 用缓存减少重复计算
- 后台异步执行,先返回 ACK
如果是网络延迟:
- 用离你最近的模型服务节点
- 检查网络链路,优化代理配置
多 Agent 消息串台怎么办?
老王问:“这个我遇到过,怎么解决?”
我说:“多 Agent 串台是因为 bindings 配置不清晰。”
在 openclaw.json 里用 bindings 字段明确指定每个 Agent 对应的通道:
{
"bindings": [
{
"agentId": "PaiGit",
"match": {
"channel": "feishu",
"appId": "cli_xxx"
}
},
{
"agentId": "PaiReview",
"match": {
"channel": "feishu",
"appId": "cli_yyy"
}
}
]
}
这样 Gateway 收到消息时,会根据 App ID 精准路由到对应 Agent,不会串台。
老王听完感慨:“你这排查思路挺清晰的,不是那种遇到问题就懵的人。”
04-6 飞书多应用接入了解吗?
老王没让我铺垫太久,直接追问:“为什么要一个飞书应用跑一个 Agent?”
我说:“因为隔离。企业场景里最怕的不是配不起来,而是权限、路由、审计和故障域全搅在一起。一个 Agent 对应一个飞书应用,边界才清楚。”
多应用配置的核心逻辑了解吗?
OpenClaw 的飞书插件支持多应用配置,核心在于defaultAccount字段。当你在openclaw.json里配置了多个飞书应用时,必须指定一个默认应用:
{
"channels": {
"feishu": {
"defaultAccount": "app1",
"accounts": [
{
"appId": "cli_xxx1",
"appSecret": "xxx",
"encryptKey": "xxx",
"verificationToken": "xxx"
},
{
"appId": "cli_xxx2",
"appSecret": "xxx",
"encryptKey": "xxx",
"verificationToken": "xxx"
}
]
}
}
}
老王打断我:“等会儿,这个defaultAccount到底起什么作用?”
我说:“当 Gateway 收到一条消息时,如果无法通过 bindings 规则匹配到特定 Agent,就会用 defaultAccount 指定的应用来响应。它是兜底策略。”
配对策略了解吗?
老王继续追问:“配对我知道。我想听的不是名词解释,而是它在企业场景里到底解决什么问题?”
我说:“配对是 OpenClaw 的一个安全机制。默认情况下,机器人不会响应任何消息,除非你主动完成配对。”
配对的方式有两种:
第一种,私聊配对。你在飞书里搜机器人,发一条私聊消息,机器人会回复一个配对码。把这个配对码告诉OpenClaw,你们就建立了一对一关系。
openclaw pairing approve feishu xxx
第二种,群组配对。把机器人拉到群里,@它发送配对指令。机器人会识别群 ID,把这个群加入白名单。
老王问:“为什么要这么麻烦?直接让机器人响应所有消息不行吗?”
我说:“安全第一。你想想,如果机器人对所有人开放,万一有人恶意刷接口,你的 token 分分钟被烧光。配对机制相当于加了一层访问控制。”
如果让你在生产环境里部署龙虾你会怎么考虑多Agent?
如果让我做企业级部署,我会这样规划:
- 开发环境:一个飞书应用,绑定测试群组
- 生产环境:一个飞书应用,绑定正式群组
- **专用 Agent:**每个业务场景单独一个应用,比如代码审核 Agent、运维 Agent、客服 Agent
老王点点头:“这样确实清晰。那如果两个应用都加了同一个群,消息会发给谁?”
我说:“这就涉及到路由优先级了。OpenClaw 采用'最具体优先'原则——如果 bindings 里明确指定了群 ID 绑定到某个 Agent,就按 bindings 走;如果没指定,就用 defaultAccount 兜底。但两个应用同时响应同一个群,这种情况要尽量避免,容易乱。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,华为和阿里云春招拿下,恭喜这位球友。
05、多 Agent 路由机制了解吗?
老王放下茶杯:“刚才你说到 bindings,这个多 Agent 路由到底是怎么工作的?”
我说:“这里最核心的不是名词,而是组合关系。真正决定多 Agent 路由的,就是 dmPolicy 和 bindings 这两个点。”
05-1 dmPolicy 了解吗?
dmPolicy 全称 Direct Message Policy,控制机器人如何处理私信。有三种策略可选:
{
"dmPolicy": {
"app1": "allow", // 允许所有私信
"app2": "deny", // 拒绝所有私信
"app3": "pairing" // 只允许配对过的用户私信
}
}
老王问:“实际场景中怎么选?”
我说:“看场景。如果是内部工具,用allow最方便;如果是面向外部用户的客服机器人,必须用pairing,防止被滥用;deny一般用于纯群组场景的 Agent。”
05-2 bindings 精准路由规则了解吗?
bindings 是 OpenClaw 多 Agent 路由的核心机制。它定义了消息应该如何分配给不同的 Agent。
{
"bindings": [
{
"agentId": "CodeReview",
"match": {
"channel": "feishu",
"accountId": "cli_xxx1",
"peer": {
"type": "group",
"id": "oc_xxx"
}
}
},
{
"agentId": "DevOps",
"match": {
"channel": "feishu",
"accountId": "cli_xxx2"
}
}
]
}
老王指着配置问:“字段名我认识。你直接说,这几个字段是怎么参与路由匹配和优先级判断的?”
我说:“channel是消息来源,比如 feishu、wecom;accountId是飞书应用的 App ID;peer是发送者信息,type可以是 user 或 group,id是对应的 ID。”
“王哥,注意这个路由规则的优先级——bindings 采用最具体优先原则。如果一条消息同时匹配了两个 bindings,哪个 match 条件更具体,就用哪个。”
举个例子:
- Binding A:只指定了 channel=feishu
- Binding B:指定了 channel=feishu + accountId=cli_xxx
- Binding C:指定了 channel=feishu + accountId=cli_xxx + peer.id=oc_xxx
如果消息来自 feishu 的 cli_xxx 应用的 oc_xxx 群,会优先匹配 Binding C,因为它最具体。
05-3 groupPolicy:群组策略了解吗?
除了 dmPolicy,还有 groupPolicy 控制群组行为:
{
"groupPolicy": {
"requireMention": true, // 群组中是否需要@机器人
"allowAnonymous": false // 是否允许匿名消息
}
}
老王问:“requireMention 这个我遇到过。有时候群里@机器人它不理我,就是这个配置的问题?”
我说:“对。默认情况下,机器人在群里只响应被@的消息。如果你希望它监听所有消息,把requireMention设为 false。但要注意,这样会增加 token 消耗,也可能带来隐私问题。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,又一位鹅厂暑期实习拿下,恭喜这位球友。
06、Gateway 网关架构说说吧?
老王把茶杯往桌上一放:“配置层面先放一边。Gateway 才是核心,你从底层给我拆。”
我说:“Gateway 是 OpenClaw 的'神经中枢',负责三件事:”
整个链路是这样的:
飞书消息 → Gateway → Agent → 大模型 → Agent → Gateway → 飞书回复
06-1 Gateway 和飞书之间到底怎么通信?
老王继续追问:“Gateway 和飞书之间到底怎么通信?别只说长连接,把关键链路讲清楚。”
我说:“WebSocket 长连接。飞书开放平台提供了事件订阅机制,Gateway 启动时会向飞书注册一个 WebSocket 连接。之后飞书有消息就会主动推过来。”
认证方式用的是 Token 机制。在openclaw.json里配置的verificationToken和encryptKey,就是用来验证消息来源和解密消息内容的。
{
"gateway": {
"port": 18789,
"auth": "token",
"host": "0.0.0.0"
}
}
老王问:“这个 auth 字段除了 token 还能填什么?”
我说:“目前主要是 token 认证。如果是企业内网部署,还可以配合 IP 白名单、TLS 证书等方式加强安全。”
06-2 高可用架构设计了解吗?
老王继续压问:“如果真上生产,Gateway 单点怎么处理?你别跟我说‘官方以后会支持’。”
我说:“OpenClaw 官方目前没有提供原生高可用方案,Gateway 是单点的。但我们可以通过架构设计来实现高可用:”
方案一:Gateway 集群+负载均衡
部署多个 Gateway 实例,前面挂一个负载均衡器(如 Nginx)。飞书的 WebSocket 连接可以分发到不同实例。
飞书 → 负载均衡器 → Gateway集群(多实例)
方案二:会话状态下沉
把会话状态从本地磁盘迁移到 Redis,这样 Gateway 实例就变成无状态的了。任何一个实例挂掉,其他实例可以接管会话。
{
"memory": {
"storage": "redis",
"redis": {
"host": "localhost",
"port": 6379,
"db": 0
}
}
}
方案三:任务队列化
对于耗时任务,用消息队列(如 RabbitMQ)做缓冲,避免 Gateway 被阻塞。
老王点点头:“这些方案实施起来复杂吗?”
我说:“看团队能力。如果是小团队,建议先用单实例+监控告警;业务量大起来后,再考虑集群方案。不要过早优化。”
06-3 会话管理与压缩机制了解吗?
老王没放过这个细节:“多轮对话的上下文到底落在哪里?Gateway 重启以后为什么还能接上?”
我说:“会话数据默认存在~/.openclaw/workspaces/<agent>/memory/目录下。每次对话会序列化保存,用 session_id 标识。Gateway 重启后可以恢复会话状态。”
但这里有个坑——会话数据会越积越多,尤其是长对话场景。OpenClaw 提供了压缩机制:
{
"memory": {
"compression": true,
"maxHistory": 20, // 保留最近20轮对话
"summarizeThreshold": 10 // 超过10轮后自动摘要
}
}
老王问:“自动摘要是什么意思?”
我说:“当对话轮数超过 threshold 时,Agent 会把前面的内容压缩成一段摘要,只保留关键信息。这样可以控制 token 消耗,也能避免上下文窗口溢出。”
06-4 上下文窗口爆了,怎么办?
老王继续追问:“别只讲压缩配置。上下文窗口真要爆了,线上你怎么兜?”
经验一:分层记忆设计
把记忆分成三层:
- 短期记忆:最近 5 轮对话,完整保留
- 中期记忆:6-20 轮对话,压缩存储
- 长期记忆:超过 20 轮,只保留关键摘要
{
"memory": {
"layers": [
{"type": "short", "rounds": 5, "compression": "none"},
{"type": "medium", "rounds": 15, "compression": "light"},
{"type": "long", "compression": "heavy"}
]
}
}
经验二:关键信息提取
在 BOOT.md 里告诉 Agent,哪些信息必须记住,哪些可以丢弃:
## 记忆策略
必须记住的信息:
- 用户身份和偏好
- 当前任务的上下文
- 关键的业务参数
可以丢弃的信息:
- 礼貌用语
- 重复确认的内容
- 临时性的中间结果
经验三:定期清理机制
设置定时任务,自动清理过期的会话数据:
openclaw memory cleanup --before 7d
# 清理特定Agent的会话
openclaw memory cleanup --agent CodeReview --before 3d
老王听完感慨:“这些细节官方文档可不会写,都是踩坑踩出来的。”
06-5 Gateway 的生命周期了解吗?
老王继续压问:“别只讲命令。Gateway 的启动、停止、重启,底层生命周期你给我拆开说。”
老王问:“如果 Gateway 崩溃了,会话会丢吗?”
我说:“看配置。如果开启了持久化,会话数据会定期写入磁盘,崩溃后可以恢复。但正在处理中的任务可能会中断。”
- 停止接收新连接
- 等待现有连接处理完成(默认 30 秒超时)
- 保存会话状态
- 清理资源后退出
# 优雅关闭
kill -TERM <pid>
# 强制关闭(不推荐)
kill -9 <pid>
老王问:“如果 30 秒内任务还没完成怎么办?”
我说:“超时后会强制退出,未完成的任务会丢失。所以复杂任务最好设计成可重入的,支持断点续传。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,京东和字节暑期实习拿下,恭喜这位球友。
07、OpenClaw 的核心组件是什么?
老王推了推眼镜,继续问:“说说 OpenClaw 的核心组件吧。”
我回答。
**LLM:**这是 Agent 的大脑,负责理解指令、规划任务、生成回复。OpenClaw 支持多种模型,Claude、GPT、GLM 都可以接。
任务规划:把用户的自然语言需求,拆解成可执行的任务步骤。比如“帮我查天气”,会拆解成:调用天气 API → 解析返回数据 → 生成回复。
工具执行器:负责调用外部工具,比如搜索、文件操作、数据库查询等。每个工具都有明确的输入输出定义。
记忆管理器:管理 Agent 的短期记忆(Session)和长期记忆(Memory)。这是 Agent 能持续对话的关键。
技能加载器:动态加载 Skills,扩展 Agent 的能力。Skills 本质上是封装好的 Prompt 和工具组合。
老王点点头:“这些组件之间怎么通信?”
07-1 组件之间如何通信?
我说:“OpenClaw 采用了基于消息总线的轻量级通信机制。”
“每个组件都是独立的,通过消息总线交换数据。这种设计的优点是:”
- 解耦:组件之间不直接依赖,方便替换和扩展
- 异步:消息可以异步处理,不会阻塞主流程
- 可观测:所有消息都经过总线,便于调试和监控
面试官追问:“消息总线具体是怎么实现的?”
消息总线具体怎么实现?
我说:“消息总线本质上是一个事件队列。”
“当组件 A 需要调用组件 B 时,不是直接调用,而是发送一个消息到总线。消息包含:”
- **目标组件 ID:**消息要发给谁
- 消息类型:是什么类型的消息(请求、响应、事件)
- 消息内容:具体的数据
- 回调地址:响应应该发给谁
“组件 B 从总线中读取消息,处理完成后,发送响应消息到总线。组件 A 从总线中读取响应,继续执行。”
“这种设计的好处是:”
第一,组件之间完全解耦。组件 A 不需要知道组件 B 的存在,只需要知道消息格式。你可以随时替换组件 B,只要消息格式不变,组件 A 就感知不到变化。
第二,支持异步处理。组件 A 发送消息后,不需要等待响应,可以继续做其他事情。等响应到达时,再处理。
第三,便于扩展。新增一个组件 C,只需要让它监听总线上的消息,不需要修改其他组件。
老王追问:“那 Agent 本身是怎么运行的?是常驻进程吗?”
07-2 Agent 是常驻进程吗?
我说:“不是,Agent 是 per-session 的瞬态实例。”
老王挑了挑眉:“什么意思?”
我解释:“每个对话都是一次完整的加载-执行-销毁循环。”
“当用户发起一个对话时:”
- 加载阶段:读取 AGENTS.md、SOUL.md 等配置文件,初始化 Agent 的人格和能力
- 执行阶段:接收用户输入,调用 LLM 生成回复,执行工具,返回结果
- 销毁阶段:对话结束,保存 Session 到磁盘,释放资源
“这种设计有两个好处:”
第一,资源节省。Agent 不用一直占用内存,只有对话时才加载。
第二,配置实时生效。每次 run 都会重新读取 workspace 文件,改配置不用重启服务。
老王问:“那 Session 是怎么管理的?”
07-3 Session 是怎么实现按需加载的?
我说:“Session 的加载是懒加载机制。”
“当消息到达,路由到 SessionKey 之后,OpenClaw 会查找 sessions.json 获取当前 SessionId,然后把 SessionId 对应的.jsonl 文件加载到 Agent 中。”
老王问:“Session 太长,会不会挤爆 LLM 的 Context?”
07-4 Session 优化机制了解吗?
我说:“OpenClaw 在 Session 加载到 LLM 感知阶段,会做两件事:”
A. 压缩持久化
当 Session 接近 context 上限时,OpenClaw 会自动提示 Agent 写入 Memory,然后压缩 Session。压缩后的内容会保存到磁盘,不会丢失。
具体来说,Compaction 会:
- 分析 Session 中的所有消息
- 识别重要信息(用户明确陈述的事实、对话结论等)
- 把这些信息写入 Memory
- 把原始消息压缩成摘要,减少 token 占用
B. 修剪
在发送给 LLM 之前,临时裁剪旧的 tool 结果。比如一个搜索工具返回了 100 条结果,但 LLM 只需要前 10 条,后面的就会被裁剪掉。
修剪的策略包括:
- 只保留最近的 N 条消息
- 只保留工具调用的结果摘要,不保留完整输出
- 合并相似的消息
老王问:“Compaction 和 Pruning 有什么区别?”
我说:“Compaction 是持久化的,会把重要信息写入 Memory,长期保存。Pruning 是临时的,只是临时裁剪发送给 LLM 的内容,不会修改 Session 文件。”
“打个比方:Compaction 是把重要笔记抄到笔记本上,永久保存。Pruning 是临时把草稿纸上的无关内容划掉,方便阅读。”
老王问:“Agent 是怎么决策使用 Memory 的?”
07-5 Memory 机制了解吗?
我说:“Memory 是 OpenClaw 最核心的机制之一,它让 Agent 有了‘记忆’的能力。”
短期记忆(Session):当前对话的上下文,存储在内存中。包括用户输入、Agent 回复、工具调用结果等。
长期记忆(Memory):跨对话的持久化记忆,存储在磁盘上。包括用户偏好、历史事实、重要结论等。
老王问:“这两种记忆是怎么协作的?”
两种记忆是怎么协作?
我说:“Memory 的工作分为三个阶段:”
阶段一:写入 Memory
当 Session 接近 context 上限时,OpenClaw 会触发 Compaction 机制。Agent 会分析当前 Session 的内容,提取重要信息,写入 Memory。
写入的内容包括:
- 用户明确陈述的事实(“我喜欢王二”)
- 对话中的重要结论(“项目采用微服务架构”)
- Agent 生成的有价值信息(“搜索结果显示...”)
阶段二:存储 Memory
写入的 Memory 会存储在 memory.sqlite 文件中.
每条 Memory 包含:content:记忆内容、timestamp:写入时间、importance:重要程度(1-10)、tags:标签,用于检索。
阶段三:读取 Memory
当新的对话开始时,OpenClaw 会根据当前对话内容,检索相关的 Memory,加载到 Agent 的上下文中。
检索策略包括:
- 关键词匹配:根据用户输入的关键词检索
- 语义相似度:使用向量检索,找到语义相关的 Memory
- 时间衰减:越新的 Memory 优先级越高
老王问:“怎么避免 Memory 爆炸?”
07-6 Memory 优化策略了解吗?
我说:“Memory 管理不好,确实会导致检索效率下降。OpenClaw 有几个优化策略:”
1. 重要性评分。写入 Memory 时,Agent 会给每条 Memory 打分。只有重要程度超过阈值的 Memory 才会被保留。
2. 定期清理。OpenClaw 会定期清理过期的 Memory。默认保留 30 天,可以通过配置调整。
**3. 合并相似 Memory。**如果多条 Memory 内容相似,OpenClaw 会自动合并,避免重复。
4. 分层存储。高频访问的 Memory 放在内存,低频访问的 Memory 放在磁盘,平衡性能和容量。
老王问:“Agent 使用 Memory 有两种方式,你说说看?”
07-7 说说sessions_send 和 sessions_spawn 的区别?
我说:“Agent 使用 Memory 有两种方式:sessions_send 和 sessions_spawn。”
**sessions_send:**发送消息给另一个 Agent,等待回复。类似于函数调用,同步阻塞。
**sessions_spawn:**派生一个新的 Agent 实例,独立运行。类似于多线程,异步非阻塞。
老王问:“这两种方式分别适合什么场景?”
我说:
- sessions_send适合需要协作完成的任务。比如一个 Agent 负责搜索,另一个 Agent 负责总结,搜索 Agent 把结果 send 给总结 Agent。
- sessions_spawn适合需要并行处理的任务。比如同时监控多个数据源,每个数据源用一个 Agent 处理,互不干扰。
老王问:“sessions_send 通话的内容有过期机制吗?”
我说:“有。OpenClaw 会定期清理过期的 Session 数据,默认保留 7 天。可以通过配置调整保留时间。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,同花顺暑期实习拿下,恭喜这位球友。
08、说说龙虾的 8 个配置文件?
老王问:“你刚才提到 AGENTS.md、SOUL.md,这些配置文件都是干嘛的?”
我说:“每个 Agent 都有其对应的 workspace,里面有 8 个核心配置文件。”
“这 8 个文件构成了 Agent 的完整人格,缺一不可。”
**AGENTS.md:**定义 Agent 的能力边界。包括 Agent 的名称、描述、系统 Prompt、行为约束等。这是最重要的配置文件。
**SOUL.md:**注入 Agent 的灵魂。定义 Agent 的性格、语气、价值观。比如让 Agent 变得幽默、严谨、或者专业。
**TOOLS.json:**划定 Agent 的工具禁区。定义 Agent 可以使用哪些工具,每个工具的参数和返回值。
**SKILLS.json:**配置 Agent 加载的 Skills。可以精确控制加载哪些 Skills,避免 Skills 过多导致 Context 爆炸。
**MEMORY.json:**配置长期记忆的存储和检索策略。
**SESSION.json:**配置 Session 的管理策略,包括压缩阈值、保留时间等。
**ROUTER.json:**配置消息路由规则,决定消息由哪个 Agent 处理。
**CONFIG.json:**其他杂项配置,比如 LLM 模型选择、API Key 等。
我说:“AGENTS 定义能力边界,SOUL 注入灵魂,TOOLS 划定禁区,这 8 个文件构成 Agent 的完整人格。”
老王问:“AGENTS.md 具体包含什么内容?”
08-1 AGENTS.md 里写了什么?
我说:“AGENTS.md 这个文件,堪称 OpenClaw 最核心的 Prompt 文件。”
“它详细介绍了一个 Agent 的启动流程、Memory 管理的流程。”
启动流程:定义 Agent 启动时执行的步骤,包括加载配置、初始化 Memory、注册工具等。
Memory 管理流程:定义什么时候写入 Memory、什么时候读取 Memory、如何压缩 Session。
AGENTS.md 里会明确写出:
- 当 Session 长度超过多少 token 时,触发 Compaction
- 写入 Memory 时,如何评估重要性
- 读取 Memory 时,如何排序和筛选
工具调用规范:定义工具调用的格式、错误处理、超时机制。
包括:
- 工具调用的 JSON 格式
- 工具执行失败时的重试策略
- 工具执行超时的处理
安全约束:定义 Agent 不能做什么,比如不能删除系统文件、不能访问敏感数据。
老王问:“SOUL.md 是干嘛的?”
08-2 SOUL.md 是干嘛的?
我说:“如果说 AGENTS.md 定义了 Agent 的能力,那 SOUL.md 就定义了 Agent 的性格。”
“SOUL.md 里可以定义:”
- 语气风格:正式、随意、幽默、严肃
- 价值观:用户优先、效率优先、安全优先
- 行为准则:主动确认、谨慎操作、透明沟通
“比如你可以让 Agent 变得像一个经验丰富的老程序员,说话直接、不绕弯子。也可以让 Agent 变得像一个耐心的老师,解释详细、循序渐进。”
“这就是 SOUL.md 的价值:让同样的能力,呈现出不同的人格。”
老王问:“Skills 是怎么加载的?”
08-3 Skills 太多会不会有性能问题?
我说:“Skills 太多确实会给 Agent 造成 Context 负担,甚至错误的 Skills 会导致 Agent 错误调用工具。”
“所以我们要对 Agent 进行精细化的管控。”
我说:“比如 brave_search 这个 Skill,属于让 Agent 进行高效的联网检索,它就应该属于基础通用 Skill。”
“而像代码审查这种 Skill,只有开发场景的 Agent 才需要加载。”
老王问:“怎么避免低质 Skills 爆炸?”
我说:“三个原则:”
-
精简原则:只加载必要的 Skills,不要贪多。一般来说,一个 Agent 加载 5-10 个 Skills 就够了。
-
评估原则:用 Evals 机制测试 Skills 的质量。写一个测试用例,让 Agent 执行,看结果是否符合预期。不合格的 Skills 不用。
-
版本原则:Skills 版本化管理,避免冲突。比如 brave_search 有 v1 和 v2,要确保 Agent 加载的是正确的版本。
老王问:“TOOLS.json 和 SKILLS.json 有什么区别?”
我说:“这两个文件容易混淆,但其实职责不同。”
**TOOLS.json:**定义 Agent 可以使用的工具。工具是底层能力,比如文件读取、网络请求、数据库查询等。
**SKILLS.json:**定义 Agent 加载的 Skills。Skills 是高层封装,比如搜索、代码审查、数据分析等。一个 Skill 可能调用多个 Tool。
“打个比方:Tools 是‘手脚’,Skills 是‘技能’。”
“比如‘搜索’这个 Skill,可能调用了‘网络请求’Tool 和‘内容解析’Tool。”
老王问:“MEMORY.json 和 SESSION.json 呢?”
我说:“这两个文件配置 Memory 和 Session 的管理策略。”
MEMORY.json:
- 存储路径:Memory 文件保存在哪里
- 最大容量:最多保存多少条 Memory
- 保留时间:Memory 保留多久
- 检索策略:如何根据输入检索相关 Memory
SESSION.json:
- 压缩阈值:Session 长度超过多少 token 时触发 Compaction
- 保留时间:Session 文件保留多久
- 修剪策略:如何裁剪旧的 tool 结果
“这两个配置直接影响 Agent 的‘记忆力’。配置得好,Agent 能记住重要信息;配置得不好,Agent 要么忘事,要么 Context 爆炸。”
老王问:“ROUTER.json 是干嘛的?”
08-4 ROUTER.json 是干嘛的?
我说:“ROUTER.json 配置消息路由规则,决定消息由哪个 Agent 处理。”
“在多 Agent 系统中,可能有多个 Agent 同时运行。ROUTER.json 定义了路由规则,比如:”
- 包含“代码”关键词的消息,路由给 CodeAgent
- 包含“搜索”关键词的消息,路由给 SearchAgent
- 默认路由给 GeneralAgent
“这样用户发一条消息,系统能自动找到最合适的 Agent 来处理。”
老王问:“CONFIG.json 呢?”
08-5 CONFIG.json 是干嘛的?
我说:“CONFIG.json 是其他杂项配置,包括:”
- LLM 模型选择:用 Claude 还是 GPT 还是 GLM
- API Key:各个模型的 API Key
- 日志级别:DEBUG、INFO、WARN、ERROR
- 超时时间:各种操作的超时设置
“这些配置比较通用,不同 Agent 的配置可能差不多。”
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,春招中国铁塔总部直属研究院+中国工商银行北京分行拿下,恭喜这位球友。
09、Memory 和 Session 的区别?
“王哥,Memory 是 OpenClaw 最核心的机制之一,它让 Agent 有了‘记忆’的能力。”
09-1 说说短期记忆?
短期记忆存储在~/.openclaw/agents/{agentId}/sessions/*.jsonl文件中,自动记录。
每次和龙虾对话,OpenClaw 就会自动将对话内容追加到 JSONL 格式的会话日志文件中,这是最原始的、未经处理过的记忆。
09-2 说说长期记忆?
长期记忆存储在~/.openclaw/workspace/MEMORY.md和memory/*.md文件中,可以手动创建,但一般交给 OpenClaw 自动生成。
可以理解成是从短期的琐碎记忆中提炼出来的需要 OpenClaw 重点记住的内容,比如用户的性格、身份信息、回答偏好等。
举个例子,你告诉 Agent:“我是 Java 后端开发,回答问题时请用 Java 相关技术栈。”这句话就会被提炼成长期记忆,存储在 Markdown 文件中。下次对话时,龙虾会自动检索到这条记忆,按照你的偏好回答。
老王追问:“那长期记忆和短期记忆之间是怎么转换的?”
我说:“王哥,有研究啊。”
09-3 记忆是如何自动转换的?
“记忆转换有两种触发机制。”
机制一:session-memory Hook
当用户执行/new命令重置会话时,OpenClaw 会触发 session-memory Hook,自动将上一个会话的关键内容转换为 Markdown 文件。
这个过程是自动化的,不需要手动干预。系统会分析 JSONL 文件中的对话内容,提取出关键信息,比如用户的偏好、重要的上下文、需要长期记住的事实等,然后写入memory/YYYY-MM-DD.md文件。
机制二:Memory Flush
这是一个非常关键的自动化机制。
当 Session 接近 context 上限时,OpenClaw 会触发 Compaction 机制。Agent 会分析当前 Session 的内容,提取重要信息,写入 Memory。
老王点点头:“那这些 Markdown 文件是怎么被检索的?总不能每次都遍历所有文件吧?”
09-4 Memory 的索引到底是怎么建起来的?
“王哥,真正难的不是‘记下来’,而是‘下次还能在几百份文件里把它找回来’。”
OpenClaw 是这样处理 Memory 的:
- Markdown 文件是记忆本体,也就是 source of truth。
- SQLite 是加速层,负责把这些 Markdown 变成“可检索”的东西。
不了解的人会以为 SQLite 就是 Memory 本身,但其实不是。
那些 markdown 文件才是 Memory 本身,其中
MEMORY.md:记录的是长期记忆,偏“结论”和“偏好”memory/YYYY-MM-DD.md属于日记式记忆,偏“当天发生了什么”
OpenClaw 不是“每次查询时去扫描一遍目录”,而是提前把 Markdown 切块、建索引、落到 SQLite 文件里。等 Agent 真要查历史时,直接查索引就行,不仅可以查关键字,还可以查语义,这样的 Agent 就很智能。
从命令行看也更直观:
openclaw memory status
这条命令会告诉我们现在 Memory 能不能用,正在用什么模型,索引建了多少,库文件放在哪,全文检索和向量检索是不是正常。
我这台机器当前看到的是:
Provider: openai (requested: openai)
Model: nomic-embed-text
Store: ~/.openclaw/memory/paismart.sqlite
Indexed: 8/8 files · 14 chunks
Vector: ready
FTS: ready
Provider: openai (requested: openai) 表示memory 用的 embedding 提供方是 openai 这一套接口。
Model: nomic-embed-text 说明实际拿来做向量的模型,是 nomic-embed-text。
Store: ~/.openclaw/memory/paismart.sqlite 表示 memory 索引实际存在这个 SQLite 文件里。
Indexed: 8/8 files · 14 chunks 意思是一共发现了 8 个 memory 文件,这 8 个都已经建好索引,总共切成了 14 个文本块。
Vector: ready 表示向量检索正常,也就是语义搜索这部分是能工作的。
FTS: ready 表示全文检索也正常。FTS 就是 Full-Text Search,全局文本搜索。
老王对我的信任感倍增,接着问:“Embedding时到底做了什么?”
09-5 建索引时到底做了什么?
可以分成四步。
第一步,发现。
OpenClaw 会监控 MEMORY.md 和 memory/*.md 的变化。新增了文件,或者文件内容有更新,就把这个文件标记成 dirty,准备重新建索引。
第二步,切块。
把markdown切成多个 chunk,让“一个块只表达一小段相对完整的意思”。
第三步,索引。
每个 chunk 不只会走一遍 embedding,还会同时走全文检索:
- 一路进入 向量索引,负责“意思差不多也能搜出来”
- 一路进入 FTS 全文索引,负责“关键词命中要准确”
也就是说,OpenClaw 不是只做向量检索,也不是只做关键词检索,而是混合检索。
第四步,落库。
最后这些 chunk、元信息、全文索引、向量索引,都会放到本地的 SQLite 中。
老王点点头:“那检索时到底怎么查?是纯向量,还是关键词?”
我说:“混合检索。”
09-6 混合检索为什么比纯向量靠谱?
举个最简单的例子。
如果我们搜的是:memory_search("nomic-embed-text")
这类查询的关键,不是“语义接近”,而是“这个字符串必须命中”。
如果只靠向量检索,它可能把“embedding 模型”“本地向量索引”“OpenAI provider”这些语义都捞出来,但偏偏把最关键的关键字匹配丢掉。
如果搜的是:
上次说过的那个文章写作偏好是什么来着?
这时候关键词检索就不够用了,因为用户未必会原样说出“娓娓道来”“少用你、多用大家和我们”这些固定字眼。
所以 OpenClaw 的思路是:
- FTS5 + BM25 负责精确词项命中
- sqlite-vec 负责语义相似召回
- 最后再把两边的结果做融合,返回结果
为什么是 FTS5?
因为 SQLite 的 FTS5,本质上就是一个轻量级全文搜索引擎。
它比 LIKE '%xxx%' 快,还知道“哪些词更重要,哪些结果应该排前面”。
BM25 的价值就在这。
一个词出现 10 次不一定比出现 2 次更重要,而是会结合:
- 词频
- 文档长度
- 这个词在整个语料里稀不稀有
于是像 memory_flush、session-memory、nomic-embed-text 这种比较稀缺的词,权重天然就更高。
为什么还要 sqlite-vec?
因为 FTS5 主要解决的“字面命中”的问题,解决不了语义匹配的问题:
- “上次那个事”
- “之前你记住的偏好”
- “我不是说过不要那种爆款腔吗”
这种问法,字面上未必能正好撞到原文,但语义是接近的。这时候 embedding 的价值就出来了。
它先把 query 向量,再和每个 chunk 的向量做近邻比较,把语义接近的片段拉出来。可以粗暴理解成:
query
↓
embedding(query)
↓
和 chunks_vec 里的每个向量算距离
↓
取 top-k
这套东西要是放到 SaaS 产品里,需要一个单独的向量数据库,比如说派聪明RAG用的就是ElasticSearch。
但 OpenClaw 没这么干。
它用 sqlite-vec 这类 SQLite 扩展,把向量检索能力放进了本地的 SQLite 里。
老王听到这儿笑了:“行,概念算你讲明白了。那 Agent 自己到底怎么用这些 Memory?”
09-7 检索到记忆之后,Agent 是怎么把它用起来的?
“王哥,这一步才是 Memory 真正发挥价值的地方。”
很多人以为 Memory 系统的终点是“查到了”。其实不是。
OpenClaw 主要给 Agent 暴露了两个工具:
1)memory_search
当 Agent 发现问题涉及过去的决策、偏好、历史上下文,它不会把整个 memory/ 目录读一遍,而是先发起一次语义搜索。
例如:
memory_search("二哥的文章写作偏好")
返回的不是整篇内容,而是最相关的若干 snippet + 文件路径 + 行号范围。
这样做有两个好处:
- 控制 token,不要把整个历史一口气塞进上下文
- 先粗召回,找到“值得展开读”的位置
2)memory_get
如果 memory_search 返回说,关键信息在:
MEMORY.md#L1-L16memory/2026-03-19.md#L20-L48
那 Agent 下一步就可以用 memory_get 去读具体的行段。
注意,这里面有个特别容易被忽略的点:
Memory 文件本身不是每回合全量注入。
memory/*.md 这种 daily 文件默认并不会塞进上下文窗口,而是通过 memory_search 和 memory_get 按需读取。
这就解释了为什么 OpenClaw 的 Memory 能够“越记越多”,但又不会把上下文撑爆的原因。
Memory flush 为什么是这个体系里的关键一环?
OpenClaw 在会话接近 compaction 之前,会触发一次 silent memory flush。
也就是说,当 session 接近自动压缩时,系统会发起一个静默回合,提醒模型把值得长期保留的内容写进 memory/YYYY-MM-DD.md。
老王听完感慨:“你这理解得够深的。那我再问你一个实际应用的问题,你用 OpenClaw 的 Memory 干过什么真实的场景?”
09-8 讲一个Memory 的最佳实践?
“王哥,我给你讲一个真实的场景。”
我有一个 Agent 是专门帮我审核 gitcode 账号的。如果没有Memory,每次审核的时候,我都要告诉它一些重复的信息,比如:
- 审核完成后发消息到哪个飞书群
- 添加到哪个 gitcode 项目组
- 审核结果用什么格式回复
这些信息每次都要重复说,很烦。把这些写进 Memory就没事了:
# 用户偏好
## gitcode 审核
- 审核完成后发消息到“技术派-运营群”
- 添加到项目组:技术派-会员组
- 回复格式:@用户 审核通过,已添加到技术派-会员组
## 其他偏好
- 我是 Java 后端开发,回答问题请用 Java 技术栈
- 回复时请简洁,不要废话
这样每次审核,Agent 就会自动检索这些偏好,按照我的要求执行。
老王听完眼睛一亮:“这个场景实用。”
我说:“还不止。我还让 Agent 记住了我的工作习惯。比如我喜欢在早上处理审核任务,Agent 会在每天早上主动提醒我有多少待审核的申请。”
来,直接让龙虾帮我们现场演示一个。
直接这条命令 openclaw memory search "nomic-embed-text"
返回里直接命中了这两类内容:memory/2026-03-19.md、MEMORY.md
而且都正好包含:nomic-embed-text、embedding 模型、memory 搜索配置
这说明关键词搜索是起效的。
第二次,我们执行 openclaw memory search "上次说过不要那种爆款腔的写法"
注意,这句话里没有直接写“不要硬做爆款腔”、“娓娓道来”、“二哥味”
但返回找到了这些和“写作风格、表达偏好、memory 原理”接近的内容,比如:memory/memory-system-deep.md、memory/memory-system.md
这就证明向量检索也是可用的。
memo:更新与3月26日,顺带给大家分享一下二哥编程星球的喜报,智谱社招拿下,base涨了不少,恭喜这位球友。
真诚点赞 诚不我欺
回复