作者:少年弈
地址:
https://zhuanlan.zhihu.com/p/2003914477209413004
OpenClaw最近热度很高。体验下来,它除了是一个可以接管你电脑的通用Agent(Code Agent就是通用Agent)以外,另一点优势还在于你可以通过聊天软件遥控Agent帮你操作电脑。古早的时代我也用手机连过开发机,感到操作非常痛苦——主要是输入不方便。而接入Agent以后可以用简短的指令说明要求,剩下的Agent帮你代管了。
关于具体的实现,OpenClaw内部有个Gateway层用于接入各种IM聊天工具,各种IM工具里的消息发给Channel,然后串行被消费到,然后发送给Pi Agent(这是它内部的核心Agent),Agent输出以后再通过Channel+WebSocket给对应的IM工具发消息。
最近刷到了一些AI生成的OpenClaw的解析文章,发现有的部分和我想的有出入,所以决定自己看一下具体的实现,写篇文章拆解一下它的Agent Loop。
01
概述
本文跳过上文中简略提到的Gateway与Channel,先看一下在一个Session乃至在单轮的模型调用中,它的上下文管理策略是怎样的。
1. Session
Session是OpenClaw内部的用于区分不同上下文的会话概念。简单来说,一个Session类似你在Gemini开的一个会话窗口,不同Session的上下文是独立的。可以容易想到的是,不同的聊天窗口Session是隔离的,比如单聊和群聊。
你可以通过/new指令来新开一个会话。相对的,它有自动的Session切分策略:
1. 空闲的切分:如果一个会话长时间没继续,下次会开启新的会话。
2. 周期性的切分:每天凌晨4点以后发起的会话,相较于前一天会是一个新的会话。
单个Session中历史记录的存储路径是~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl,其中<agentId>通常是main,SessionId由openclaw自行生成uuid,同时还会有个~/ .openclaw/ agents/ <agentId>/ sessions/ sessions.jsonl用来管理session的元数据。
2. Workspace
在OpenClaw被初始化以后,它的工作区(workspace)会存在一些文件。这些文件的内容会影响Agent的行为,我们先感性地认知这些文件会被固定加载到上下文中。
BOOTSTAP.md: 提示Agent还没有完成初始化,这会让OpenClaw在第一次被使用时与用户进行一些简单的问答,比如:
Hey. I just came online. Who am I? Who are you?
SOUL.md: 指引Agent的行动方式,比如尽可能提供帮助,提问前先尝试自己寻找答案。(内容中提及如果Agent修改了该文件应当显式地告诉用户。
IDENTITY.md: Agent在聊天中的风格,比如自称、气质、喜欢用什么emoji。
USER.md: 用户的个人画像。
工作区的文件是可以由Agent自行修改和写入的,因此它可能会自行决策什么时候在这些文件中记录一些内容。
3. Pi Agent
OpenClaw并没有自己构造一个agent loop,相反它把Agent相关的事情都交给了Pi Agent,或者说OpenClaw整体来看就是Pi Agent套壳,Pi Agent对外暴露的包是
@mariozechner/pi-coding-agent(高级SDK)
@mariozechner/pi-agent-core (Agent Runtime)
@mariozechner/pi-ai (LLM API)
OpenClaw向Pi Agent提供了System Prompt, Tools, SessionManager(做一些零碎的控制),然后订阅Pi Agent运行过程中的一系列事件,处理流式文本和工具事件并分发给gateway。
注意:session存储到硬盘主要由 pi-coding-agent 的 SessionManager 在运行中完成,不是事件订阅器直接写入
Pi Agent是个非常简洁的Code Agent,只有Read, Edit, Write, Bash四个基础工具,并且Bash工具还被OpenClaw给替换了,其他工具都是在OpenClaw中提供的。
02
Context
1. Pi Agent的Context
如上文所说,OpenClaw的Agent能力是由Pi Agent实现的,因此我们先看看Pi Agent的上下文有哪些部分组成。
其中Messages里有用户输入、模型输出、工具调用结果等,一步步追加到Messages里。
Pi Agent有自己的上下文压缩策略:(1)上下文溢出以后会自动压缩并且重试 (2)到达一定窗口以后进行压缩。
压缩是使用了一段提示词summary,压缩后的消息由压缩后的内容+保留的最近的内容组成。
Tool Definition会由Pi Agent的适配层对OpenAI/Gemini/Anthropic和其他家的模型做适配,传入对应的模型API,然后由模型输出function call
2. OpenClaw的System Prompt
OpenClaw替换了Pi Agent的很多部分,比如System Prompt就给完全替换了,这里我们看一下OpenClaw的System Prompt。
OpenClaw的system prompt有两种模式,full是给主agent使用的,minimal模式是给子agent用的,minimal删减了一部分内容。
System Prompt的Tooling里还包含了一份tool的简要描述,实际上Pi Agent内部给模型又单独拼接了完整的tool schema给各家模型的API用于function call,可能System Prompt中的tool简要描述起一个强调的作用。
3. Open Claw对上下文的处理
上文所说, Pi Agent内部本身做了自己的上下文压缩,但是Open Claw又给在外面套了一层压缩策略。目前我没有搞清楚两套压缩策略是否会同时生效,需要实际Debug一下。
压缩(compaction)
当会话接近或超过模型的上下文窗口时,OpenClaw 会触发自动压缩,并可能使用压缩后的上下文重试原始请求。
压缩前的memory写入:当会话快接近自动压缩的阈值的时候,OpenClaw有个silent memory flush机制,可以让agent主动把会话中的关键信息记录到memory/YYYY-MM-DD.md
OpenClaw没有自己提供一个独立的提示词来压缩上下文,直接用了Pi Agent里的compact功能相关函数。
这里不讨论用户手动的/compact命令
裁剪(pruning)
Pruning是给Anthropic系列模型(包括OpenRouter的anthropic开头的模型)单独做的功能,对其他模型的请求不会在请求前进行pruning。
看官方文档,做pruning原因是Anthropic系列模型的提示缓存存在TTL。因此如果是提示缓存过期以后的请求,会考虑每次发起请求前把给模型的toolResult类型消息做裁剪(toolResult相对其他类型的消息更容易过大),最后的几条(可配置)toolResult会保留原状。
针对Anthropic系的API, 有两种裁剪策略:
Soft Trim: 保留头尾,中间插入....,会追加一个原始token长度的note
Hard Clear: 把整个工具结果用一个占位符替换。
优先使用Soft Trim,如果发现Soft Trim以后的toolResult依然过大,就会使用Hard Clear.图片消息永远不会被pruning(base64确实也不应该干掉部分,干掉以后干脆不可用了)
当然我觉得另一个原因是Claude模型卖的比较贵,要用得省一点。
03
Tool && Skills
OpenClaw内部集成了很多工具和Skill,这赋予了它很多能力。
1. Tool
对Tool可以进行分类如下
2. Skill
网上看到的openclaw接管Macmini帮用户做杂七杂八的事(比如写备忘录)基本都是通过Skill完成的,内置的Skill可以按照功能分类如下
04
跨会话的Memory
1. memory文件
在System Prompt中的memory:如前文所讲,MEMORY.md/memory.md会默认作为 contextFiles 被注入到system prompt。
跨session memory存储在<workspace>/memory/YYYY-MM-DD.md
agent主动写入:当用户说“请记住...”,agent可能会使用write工具写入<workspace>/memory/YYYY-MM-DD.md
被动记录:当触发新会话时,session-memory hook 会把最近会话保存为<workspace>/memory/YYYY-MM-DD.md。
压缩前记录memory: 见压缩一节的silent memory flush机制。
2. chunks表里的memory
OpenClaw用了sqlite存储chunk用于RAG
CREATETABLE chunks(
id TEXT PRIMARYKEY,
path TEXT,
source TEXT,
start_line INTEGER,
end_line INTEGER,
hash TEXT,
model TEXT,-- 嵌入模型
textTEXT,
embedding TEXT,-- JSON 数组
updated_at INTEGER
);
监听到memory文件夹变化的时候,会写入chunks表。此外还存在往chunks表定时同步的机制。
3. memory相关工具
memory_search工具可以使用RAG的方式搜索memory,
{
"name":"memory_search",
"description":"Mandatory recall step: semantically search MEMORY.md + memory/*.md before answering questions about prior work, decisions, dates, people, preferences, or todos",
"parameters":{
"query":"What did we decide about the API?",
"maxResults":6,
"minScore":0.35}
}
混合搜索:混合搜索是个实验特性,可以通过RAG+BM2.5两种方式共同搜索memory,取topK然后打分合并结果。具体合并策略可以看官方文档里的合并策略.
memory_get可以选择读取memory文件的部分内容(比如部分行)
{
"name":"memory_get",
"description":"Read specific lines from a memory file after memory_search",
"parameters":{
"path":"memory/2026-01-20.md",
"from":45,
"lines":15}
}
05
一些想法
整体来看,OpenClaw是对Code Agent的包装,Code Agent本身可以接管你的电脑,而它给Code Agent外接了更多工具。它实现了统一的往IM工具建立信道的协议,让用户可以通过聊天软件远程遥控它。同时也通过一些比较简单的人设定义文本(contextFiles)和memory机制,让OpenClaw跟用户聊天的时候更丝滑。
此外,作者可能是Anthropic的粉丝,比如在Safety一节,提到了遵循Anthropic的一些安全约定。
References
openclaw/openclaw - Githubgithub.com/openclaw/openclaw
badlogic/pi-mono - Githubgithub.com/badlogic/pi-mono
openclaw Documentdocs.openclaw.ai/
steipete.me/posts
How Clawdbot Remembers Everythingmanthanguptaa.in/posts/clawdbot_memory/