OpenClaw 完整调用原理
1 | |
关键源码文件对应关系
| 职责 | 源码位置 |
|---|---|
| CLI 入口 | openclaw.mjs → src/index.ts → src/cli/program.ts |
| Gateway WS 服务 | src/gateway/server.ts |
| 渠道适配(Telegram) | src/telegram/ (grammY) |
| 渠道适配(Discord) | src/discord/ (discord.js) |
| 统一路由分发 | src/auto-reply/reply.ts |
| 会话 Key 解析 | src/config/sessions.ts → resolveSessionKey() |
| Agent 推理主循环 | src/agents/piembeddedrunner.ts |
| System Prompt 组装 | src/agents/prompt-builder.ts |
| 工具执行 + 沙箱 | src/agents/sandbox.ts |
| 记忆搜索 | src/memory/(SQLite 存储) |
| 插件加载 | src/plugins/loader.ts |
| Schema 验证 | src/config/schema.ts(TypeBox) |
memory
OpenClaw Memory
OpenClaw 的记忆系统分成三层,这是它比普通 RAG 方案设计更完整的地方:
1 | |
完整流程
1 | |
- 什么是重要信息:取决于
AGENTS.md/SOUL.md里用户写的指令 - 会话历史 JSONL,格式是标准 JSONL,每行一条消息记录,内容包含 role(user/assistant/tool_result 等)、content、timestamp 等字段。全量保存,不会自动删除历史,只有执行
/reset或手动清理才会切换。 -
Markdown 文件按段落/语义边界切分,每个 chunk 截断到 700 字符,Session JSONL 按消息粒度切分(每条消息或几条消息一组)
- 长短期记忆
- 区分逻辑完全通过文件路径约定 + 模型行为引导实现。日常笔记(
memory/YYYY-MM-DD.md)是一个日志,适合记录几天内的连续性上下文,包含当天发生了什么、做了哪些决定。MEMORY.md更像一个画像文件,存放跨时间都应保持为真的内容,比如用户偏好、技术栈、项目结构,应该保持小而精
- 区分逻辑完全通过文件路径约定 + 模型行为引导实现。日常笔记(
- 模型context window
memory_search
向量搜索和关键词搜索并行执行,各自取top24
1 | |
example
1 | |
两个可选后处理阶段
MMR(Maximal Marginal Relevance):迭代选择能最大化 λ × relevance - (1-λ) × max_similarity_to_selected 的结果,防止返回一堆几乎相同内容的 chunks,默认关闭。Temporal Decay:对较老的 chunk 打指数衰减折扣,半衰期默认 30 天;但 MEMORY.md 和 memory/ 下没有日期的文件是 evergreen,永远不衰减,默认关闭。 DeepWiki
搜索结果还会按 (path, startLine, endLine) 元组去重,避免向量 + 关键词两边都命中同一个 chunk 后返回重复内容
1 | |
Memory 工程化
| 记忆层 | 内容 | 生命周期 | 载体/作用域 |
|---|---|---|---|
| Working Memory (工作记忆) | 当前消息、ReAct循环、临时变量 | 单次请求/推理期间 | AgentScope InMemoryMemory |
| Session Memory (会话记忆) | 完整对话历史、会话摘要 | 当前会话,历史可持久化 | Redis + MySQL |
| User Memory (用户记忆) | 用户偏好、背景、纠错历史 | 跨所有Agent共享,长期 | MemOS · user_profile |
| Agent Memory (Agent记忆) | 项目上下文、任务模式、技能与工具习惯 | Agent内跨会话复用,长期 | MemOS · agent_{id} |
并行加载,提升效率
- 降级与容错:长期记忆查询失败时,仅记录日志并返回空结果,不影响主对话流程,将其视为“增强能力”而非核心依赖
短期记忆:Redis 缓存 + MySQL 兜底
- 存储:采用 Redis 作为热点缓存(最新200条,TTL 7天),MySQL 作为持久化存储,确保数据不丢失。
- 读取:优先从 Redis 读取,未命中或异常时回退到 MySQL。
- 写入:采用双写策略,先写 MySQL,成功后异步写入 Redis;Redis 写入失败不回滚 MySQL 写入。
- Token 窗口控制:读取时进行 Token 窗口裁剪,并为摘要预留预算(约2000 tokens),避免上下文超限
长期记忆:MemOS 语义检索 + 智能写入
-
load
-
同时检索
user_profile和agent_{agentId}两个 Cube。 -
使用
fast模式、相似度阈值0.45、MMR 去重等参数控制召回质量。 -
检索后过滤低分(
score < 0.3)和过长(单条截断至1000字符)结果
-
-
write
- 会话结束后,异步触发
- 调用 LLM 判断新增消息是否值得记忆,并决定记忆的类别、scope 和重要性
- 去重与冲突处理:
- 本地预去重:使用精确匹配、包含、Jaccard(阈值0.7)、Levenshtein(阈值0.8)等方法。
- 冲突解决:调用冲突检测服务,决定是写入新记忆、跳过,还是标记旧记忆待删除。
- “先写后删”策略:为确保数据不丢失,先向 MemOS 写入新记忆,成功后再删除冲突的旧记忆;删除失败仅记录警告,不影响已写入的新记忆
预算控制:Token 精细化分配
- 长期记忆:默认总预算为 4000 tokens。其中
user_profile最多占 60%,剩余预算分配给 Agent 记忆。 - 截断算法:采用按行截断,尽量保留完整语义,避免拆散单条记忆
可靠性与可观测性
- 幂等与并发控制:使用Redis 分布式锁(10分钟)防止同一会话被并发处理;使用消息 Hash (MD5) 实现去重,TTL 为7天。
- 可观测性:提供运行概览、记忆类型分布、时间趋势、Top Agents 等查询能力,用于日常巡检和异常定位