# mini-openclaw
**Repository Path**: inca-vibration/mini-open
## Basic Information
- **Project Name**: mini-openclaw
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2026-02-08
- **Last Updated**: 2026-02-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# OpenClaw Mini
**OpenClaw 核心架构的极简复现,用于学习 AI Agent 的系统级设计。**
> "没有记忆的 AI 只是函数映射,有记忆 + 主动唤醒的 AI,才是会演化的'生命系统'"
## 为什么做这个项目
网上大多数 Agent 教程只讲 Agent Loop:
```python
while tool_calls:
response = llm.generate(messages)
for tool in tools:
result = tool.execute()
messages.append(result)
```
**这不是真正的 Agent 架构。** 一个生产级 Agent 需要的是"系统级最佳实践"。
OpenClaw 是一个超43w行的复杂Agent 系统,本项目从中提炼出核心设计与最小实现,帮助你理解:
- 为什么需要长期记忆?
- 如何实现按需上下文加载?
- 如何做上下文管理与压缩(裁剪 + 摘要)?
- 技能系统怎么设计才能扩展?
- 主动唤醒机制的真实实现是什么?
## 架构对照
```
┌──────────────────────────────────────────────────────────────────┐
│ OpenClaw Mini │
│ (本项目 · 精简核心版) │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Context │ │ Skills │ │ Heartbeat │ │
│ │ Loader │ │ Manager │ │ Manager │ │
│ │ │ │ │ │ ┌─────────────────┐ │ │
│ │ AGENTS.md │ │ SKILL.md │ │ │ HeartbeatWake │ │ │
│ │ SOUL.md │ │ 触发词匹配 │ │ │ (请求合并层) │ │ │
│ │ TOOLS.md... │ │ 内置+自定义 │ │ └────────┬────────┘ │ │
│ └──────┬──────┘ └──────┬──────┘ │ │ │ │
│ │ │ │ ┌────────▼────────┐ │ │
│ │ │ │ │ HeartbeatRunner │ │ │
│ │ │ │ │ (调度层) │ │ │
│ │ │ │ └────────┬────────┘ │ │
│ │ │ └───────────┼─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Agent Loop │ │
│ │ │ │
│ │ while (tool_calls) { │ │
│ │ response = llm.generate(system_prompt + messages) │ │
│ │ for (tool of tools) { result = tool.execute() } │ │
│ │ messages.push(result) │ │
│ │ } │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Session │ │ Memory │ │
│ │ Manager │ │ Manager │ │
│ │ (JSONL) │ │ (关键词检索) │ │
│ └─────────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
## 5 大核心子系统
| 子系统 | 本项目 | OpenClaw 源码 | 核心职责 |
|--------|--------|---------------|----------|
| **Session** | `session.ts` | `src/agents/session-manager.ts` | 会话持久化 (JSONL)、历史管理 |
| **Memory** | `memory.ts` | `src/memory/manager.ts` (76KB) | 长期记忆、语义检索 |
| **Context** | `context/loader.ts` | `src/agents/bootstrap-files.ts` | 按需加载 AGENTS/SOUL/TOOLS/IDENTITY/USER/HEARTBEAT/BOOTSTRAP/MEMORY |
| **Skills** | `skills.ts` | `src/agents/skills/` | 可扩展技能、触发词匹配 |
| **Heartbeat** | `heartbeat.ts` | `src/infra/heartbeat-runner.ts`
`src/infra/heartbeat-wake.ts` | 主动唤醒、事件驱动调度 |
---
## 深入解析
### 1. Session Manager - 会话持久化
**问题**:Agent 重启后如何恢复对话上下文?
**OpenClaw 方案**:
- JSONL 格式存储(每行一条消息,追加写入)
- 分布式锁防止并发写入
- 自动 compaction 压缩历史
**本项目实现** (`session.ts:45-62`):
```typescript
async append(sessionId: string, message: Message): Promise {
const filePath = this.getFilePath(sessionId);
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.appendFile(filePath, JSON.stringify(message) + "\n");
}
```
### 2. Memory Manager - 长期记忆
**问题**:如何让 Agent "记住"跨会话的信息?
**OpenClaw 方案** (`src/memory/manager.ts`):
- SQLite-vec 向量数据库做语义搜索
- BM25 做关键词搜索
- 混合排序 (Hybrid Search)
**本项目简化** (`memory.ts:85-118`):
```typescript
async search(query: string, limit = 5): Promise {
const queryTerms = query.toLowerCase().split(/\s+/);
for (const entry of this.entries) {
let score = 0;
// 关键词匹配得分
for (const term of queryTerms) {
if (text.includes(term)) score += 1;
if (entry.tags.some(t => t.includes(term))) score += 0.5;
}
// 时间衰减:越新的记忆分数越高
const recencyBoost = Math.max(0, 1 - ageHours / (24 * 30));
score += recencyBoost * 0.3;
}
}
```
### 3. Context Loader - 按需上下文
**问题**:如何注入项目级规范而不污染每次对话?
**OpenClaw 方案** (`src/agents/bootstrap-files.ts`):
- `AGENTS.md / SOUL.md / TOOLS.md / IDENTITY.md / USER.md / HEARTBEAT.md / BOOTSTRAP.md`
- `MEMORY.md`(或 `memory.md`)作为记忆补充
- 子代理仅允许 `AGENTS.md` + `TOOLS.md` 进入上下文
- 超长文件按 head+tail 截断并加标记
**本项目实现** (`context/loader.ts`):
```typescript
async buildContextPrompt(params?: { sessionKey?: string }): Promise {
const files = await this.loadBootstrapFiles(params);
const contextFiles = buildBootstrapContextFiles(files, { maxChars: this.maxChars });
// Project Context 输出(含 SOUL.md 特殊提示)
}
```
### 3.1 Context Pruning/Compaction - 上下文压缩
**OpenClaw 方案**:
- `src/agents/pi-extensions/context-pruning/*`:裁剪工具结果、保留最近上下文
- `src/agents/compaction.ts`:超长历史摘要压缩
**本项目实现**:
- `context/pruning.ts`:软裁剪 tool_result + 保留最近 assistant
- `context/compaction.ts`:触发阈值后生成“历史摘要”并注入
### 4. Skills Manager - 可扩展技能
**问题**:如何让用户自定义 Agent 能力?
**OpenClaw 方案** (`src/agents/skills/types.ts`):
- SKILL.md frontmatter 定义元数据
- 支持触发条件、安装脚本、参数校验
- 运行时动态加载
**本项目实现** (`skills.ts:125-170`):
```typescript
// SKILL.md 格式
// ---
// id: deploy
// name: 部署助手
// triggers: ["/deploy", "部署"]
// ---
// Prompt 内容...
async match(input: string): Promise {
for (const skill of this.skills.values()) {
for (const trigger of skill.triggers) {
if (input.startsWith(trigger)) {
return { skill, matchedTrigger: trigger };
}
}
}
}
```
### 5. Heartbeat Manager - 主动唤醒
**问题**:Agent 如何"主动"工作,而不只是被动响应?
**OpenClaw 方案** (`src/infra/heartbeat-runner.ts`, `src/infra/heartbeat-wake.ts`):
这是最复杂的子系统,包含两层架构:
```
┌─────────────────────────────────────────────────────────────┐
│ HeartbeatWake (请求合并层) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 多来源触发: │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ interval │ │ cron │ │ exec │ │ requested│ │
│ │ (定时器) │ │ (任务完成)│ │ (命令完成)│ │ (手动) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └─────────────┴──────┬──────┴─────────────┘ │
│ ▼ │
│ request({ reason }) │
│ │ │
│ ┌───────▼───────┐ │
│ │ 原因优先级合并 │ │
│ │ exec > cron │ │
│ │ > interval │ │
│ └───────┬───────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ schedule(250ms)│ ◄── 合并窗口 │
│ └───────┬───────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ if running: │ else: │ │
│ │ scheduled= │ setTimeout │ │
│ │ true (排队) │ execute() │ │
│ └─────────────┴─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ HeartbeatRunner (调度层) │
├─────────────────────────────────────────────────────────────┤
│ │
│ runOnce(request): │
│ │
│ 1. isWithinActiveHours() ─── 活跃时间窗口检查 │
│ │ (08:00-22:00, 支持时区) │
│ ▼ │
│ 2. parseTasks() ─── HEARTBEAT.md 解析 │
│ │ │
│ ▼ │
│ 3. 空内容检测 ─── 无任务时跳过 API 调用 │
│ │ (exec 事件除外) │
│ ▼ │
│ 4. 执行回调 ─── Agent 处理任务 │
│ │ │
│ ▼ │
│ 5. isDuplicateMessage() ─── 24h 内重复消息抑制 │
│ │ │
│ ▼ │
│ 6. scheduleNext() ─── setTimeout 精确调度 │
│ (lastRunAt + intervalMs) │
│ │
└─────────────────────────────────────────────────────────────┘
```
**关键设计决策**:
| 设计点 | 为什么这样做 |
|--------|-------------|
| setTimeout 而非 setInterval | 精确计算下次运行时间,避免漂移 |
| 250ms 合并窗口 | 防止多个事件同时触发导致的"呼吸急促" |
| 双重缓冲 | 运行中收到新请求不丢失,完成后立即处理 |
| 空内容检测 | 无任务时跳过 LLM 调用,节省成本 |
| 重复抑制 | 24h 内相同消息不重复发送,防止"纠缠" |
| 活跃时间窗口 | 避免半夜打扰用户 |
**本项目实现** (`heartbeat.ts:147-160`):
```typescript
private schedule(delayMs: number): void {
// 如果已在运行,标记为已排队(双重缓冲)
if (this.state.running) {
this.state.scheduled = true;
return;
}
// 如果已有定时器,不重复设置(合并)
if (this.state.timer) {
return;
}
this.state.timer = setTimeout(() => this.execute(), delayMs);
}
```
---
## 源码映射表
| 本项目文件 | OpenClaw 对应文件 | 说明 |
|-----------|-------------------|------|
| `agent.ts` | `src/agents/pi-embedded-runner/run.ts` | Agent Loop + run 生命周期 |
| `session.ts` | `src/agents/session-manager.ts` | JSONL 会话持久化 |
| `memory.ts` | `src/memory/manager.ts` | 记忆检索核心思路 |
| `context/loader.ts` | `src/agents/bootstrap-files.ts` | Bootstrap 文件加载 |
| `context/pruning.ts` | `src/agents/pi-extensions/context-pruning/pruner.ts` | 上下文裁剪 |
| `context/compaction.ts` | `src/agents/compaction.ts` | 历史摘要压缩 |
| `skills.ts` | `src/agents/skills/` | 技能系统 |
| `heartbeat.ts` | `src/infra/heartbeat-runner.ts`
`src/infra/heartbeat-wake.ts` | 主动唤醒 |
| `tools/*.ts` | `src/tools/` | 内置工具样例 |
---
## 快速开始
```bash
# 进入目录
cd examples/openclaw-mini
# 安装依赖
pnpm install
# 设置 API Key
export ANTHROPIC_API_KEY=sk-xxx
# 可选:指定 agentId
export OPENCLAW_MINI_AGENT_ID=main
# 启动交互式对话
pnpm dev chat
```
## 工作区模板(来自 OpenClaw 设计)
模板放在 `examples/openclaw-mini/workspace-templates/`(内容参考 `docs/reference/templates/` 的设计),运行时会从**当前工作区根目录**读取这些文件。
需要生效时,把模板复制到工作区根目录即可:
```bash
cp examples/openclaw-mini/workspace-templates/* examples/openclaw-mini/
```
## 使用示例
```typescript
import { Agent } from "openclaw-mini";
const agent = new Agent({
apiKey: process.env.ANTHROPIC_API_KEY,
agentId: "main",
workspaceDir: process.cwd(),
enableMemory: true, // 长期记忆
enableContext: true, // 上下文加载
enableSkills: true, // 技能系统
enableHeartbeat: false, // 主动唤醒(默认关闭)
// 工具策略与沙箱(示意)
toolPolicy: { deny: ["exec"] },
sandbox: { enabled: true, allowExec: false, allowWrite: true },
});
// 基本对话(传入 sessionId,会自动补全为 sessionKey)
const result = await agent.run("session-1", "请列出当前目录的文件");
// 使用技能
const review = await agent.run("session-1", "/review src/agent.ts");
// 也可以直接使用 sessionKey
const result2 = await agent.run("agent:main:session-1", "继续刚才的任务");
// 启动主动唤醒
agent.startHeartbeat((tasks, request) => {
console.log(`[${request.reason}] 检测到 ${tasks.length} 个待办任务`);
});
```
> 记忆使用提示:mini 版改为“工具化记忆”,在系统提示中引导模型先调用 `memory_search` 再 `memory_get` 拉取细节。
> 子代理:可通过 `sessions_spawn` 工具启动后台子代理,完成后会在 CLI 输出摘要,并写入父会话记录。
## 学习路径建议
1. **先读 `agent.ts`**:理解 Agent Loop 和子系统整合
2. **再读 `heartbeat.ts`**:这是最复杂的部分,理解事件驱动架构
3. **对照 OpenClaw 源码**:验证简化版是否抓住了核心
4. **尝试扩展**:添加新的技能、工具、或改进记忆检索
## 精华设计索引(必学 4 点)
1) **上下文的文件化结构**
- OpenClaw:`src/agents/workspace.ts`(bootstrap 文件清单)
- Mini:`openclaw-mini/src/context/bootstrap.ts`
2) **统一注入链路(Project Context)**
- OpenClaw:`src/agents/system-prompt.ts`
- Mini:`openclaw-mini/src/context/loader.ts`
3) **规模控制(截断 + 裁剪)**
- OpenClaw:`src/agents/pi-embedded-helpers/bootstrap.ts` + `src/agents/pi-extensions/context-pruning/pruner.ts`
- Mini:`openclaw-mini/src/context/bootstrap.ts` + `openclaw-mini/src/context/pruning.ts`
4) **压缩继承(摘要)**
- OpenClaw:`src/agents/compaction.ts`
- Mini:`openclaw-mini/src/context/compaction.ts`
## License
MIT
# openclaw-mini