MimicLaw 系统架构
基于 MimicLaw 版本 0.1.0(commit 5bcb28a)。
整体数据流
用户 (Telegram / WebSocket / 串口 CLI)
│
▼
┌──────────────────────────────────────────────────┐
│ ESP32-S3 (MimicLaw) │
│ │
│ [输入通道 — Core 0] │
│ ├─ Telegram 轮询器 (长轮询, 30s 超时) │
│ ├─ WebSocket 服务器 (端口 18789) │
│ └─ 串口 CLI (USB, 115200 波特率) │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ 入站队列 (深度 8) │ FreeRTOS xQueue │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Agent 循环 — Core 1 │ │
│ │ │ │
│ │ 1. 加载会话历史(最近 20 条) │ │
│ │ 2. 构建系统提示词 │ │
│ │ SOUL.md + USER.md + MEMORY.md │ │
│ │ + 最近 3 天的每日笔记 │ │
│ │ 3. ReAct 循环(最多 10 次迭代): │ │
│ │ ├─ 调用 Claude API(带工具) │ │
│ │ ├─ 如果 tool_use → 执行工具 │ │
│ │ └─ 重复直到 end_turn │ │
│ │ 4. 保存到会话 JSONL │ │
│ │ 5. 推送响应到出站队列 │ │
│ └──────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ 出站队列 (深度 8) │ │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ │
│ [输出分发 — Core 0] │
│ ├─ telegram.sendMessage(超 4096 字符自动分段) │
│ └─ WebSocket.send │
└──────────────────────────────────────────────────┘
│
▼ HTTPS (esp_tls / 代理隧道)
Anthropic Claude API
Brave Search API
模块地图
main/
├── mimi.c # 入口 (app_main),编排初始化流程
├── mimi_config.h # 所有编译时常量和 NVS 键名
├── mimi_secrets.h # 编译时凭据(已 gitignore)
│
├── bus/ # 消息总线 — FreeRTOS 队列
│ └── message_bus.c # mimi_msg_t: channel, chat_id, content
│
├── wifi/ # WiFi STA 管理
│ └── wifi_manager.c # 连接、指数退避重连、NVS 凭据
│
├── telegram/ # Telegram Bot API 客户端
│ └── telegram_bot.c # 长轮询、代理支持、消息分段
│
├── llm/ # Anthropic Messages API 客户端
│ └── llm_proxy.c # 非流式、PSRAM 缓冲区、代理路径
│
├── agent/ # AI Agent 核心
│ ├── agent_loop.c # ReAct 循环(最多 10 次迭代)
│ └── context_builder.c # 系统提示词: 引导文件 + 记忆 + 工具
│
├── memory/ # 持久化存储
│ ├── memory_store.c # MEMORY.md + 每日笔记 (SPIFFS)
│ └── session_mgr.c # JSONL 会话 + 环形缓冲区 (20 条消息)
│
├── tools/ # 工具注册表 + 内置工具
│ ├── tool_registry.c # 注册工具,构建 JSON Schema
│ ├── tool_web_search.c # Brave Search API(直连 + 代理)
│ ├── tool_get_time.c # HTTP Date 头 → 系统时钟同步
│ └── tool_files.c # SPIFFS 文件操作: read/write/edit/list
│
├── proxy/ # HTTP CONNECT 代理隧道
│ └── http_proxy.c # TCP → CONNECT → TLS 隧道
│
├── gateway/ # WebSocket 服务器
│ └── ws_server.c # 端口 18789, JSON 协议, 最多 4 客户端
│
├── cli/ # 串口控制台
│ └── serial_cli.c # esp_console REPL, 17 个命令
│
└── ota/ # 空中升级
└── ota_manager.c # esp_https_ota 封装
总代码量: ~4,000 行 C 代码。
FreeRTOS 任务布局
设计原则: Core 0 处理所有网络 I/O,Core 1 专用于 Agent 循环。避免 I/O 延迟阻塞 Agent 处理。
Flash 分区布局
基于 partitions.csv(16MB Flash):
RAM 内存预算
策略: 小且频繁访问的数据放在内部 SRAM (512 KB)。大缓冲区 (32KB+) 通过 heap_caps_calloc(1, size, MALLOC_CAP_SPIRAM) 从 PSRAM 分配。
SPIFFS 存储布局
/spiffs/
├── config/
│ ├── SOUL.md # AI 人格定义
│ └── USER.md # 用户档案
├── memory/
│ ├── MEMORY.md # 长期持久化记忆
│ └── daily/
│ ├── 2026-02-20.md # 每日笔记(每天一个文件)
│ └── ...
└── sessions/
├── tg_12345.jsonl # 按对话存储的会话(Telegram)
└── ws_3.jsonl # 按客户端存储的会话(WebSocket)
会话格式(JSONL — 每行一个 JSON 对象):
{"role":"user","content":"你好","ts":1738764800}
{"role":"assistant","content":"你好!","ts":1738764802}
只保存 user + assistant 消息。中间的工具调用步骤不持久化,保持会话文件紧凑。
消息总线
消息总线使用两个 FreeRTOS 队列(各深度 8)解耦输入通道和 Agent 循环:
typedef struct {
char channel[16]; // "telegram", "websocket", "cli"
char chat_id[32]; // Telegram chat ID 或 "ws_<fd>"
char *content; // 堆分配的文本(所有权转移)
} mimi_msg_t;
所有权模型: 发送方用 strdup() 分配 content,队列接管所有权,接收方处理后必须 free()。
Claude API 集成
MimicLaw 直接调用 Anthropic Messages API(无 LiteLLM 抽象层):
端点: POST https://api.anthropic.com/v1/messages
与 OpenClaw 的关键差异:
- 非流式 — 接收完整 JSON 响应,不使用 SSE
- PSRAM 缓冲区 — 响应体累积在 PSRAM 支持的缓冲区中
- 代理路径 — 如已配置,通过 HTTP CONNECT 隧道路由
- 工具调用协议 — 使用 Anthropic 原生
tool_use / tool_result 格式(与 OpenClaw 相同)
agent_loop.c 中的 ReAct 循环:
for 每次迭代 (最多 10 次):
1. 向用户发送"思考中..."状态提示
2. 调用 llm_chat_tools(system_prompt, messages, tools_json)
3. 如果 stop_reason == "end_turn" → 完成
4. 如果 stop_reason == "tool_use":
a. 追加 assistant 消息(text + tool_use 块)
b. 通过 tool_registry 执行每个工具
c. 追加 user 消息(tool_result 块)
d. 继续循环
系统提示词构建
由 context_builder.c 构建:
# MimiClaw
You are MimiClaw, a personal AI assistant running on an ESP32-S3 device.
[人格 + 行为指引]
## Available Tools
[工具注册表中的工具描述]
## Memory
[主动使用文件工具持久化记忆的指令]
## Personality
[SOUL.md 内容]
## User Info
[USER.md 内容]
## Long-term Memory
[MEMORY.md 内容]
## Recent Notes
[最近 3 天的 daily/*.md]
核心设计: 系统提示词指导 Agent 主动使用 write_file / edit_file 工具来持久化记忆,实现了与 OpenClaw 记忆系统相同的"Agent 驱动记忆持久化"模式。
启动流程
app_main()
├── init_nvs()
├── init_spiffs() ← 挂载 /spiffs
├── message_bus_init() ← 创建入站 + 出站队列
├── memory_store_init()
├── session_mgr_init()
├── wifi_manager_init()
├── http_proxy_init() ← 加载代理配置
├── telegram_bot_init() ← 加载 Bot Token
├── llm_proxy_init() ← 加载 API Key + 模型
├── tool_registry_init() ← 注册工具,构建 JSON Schema
├── agent_loop_init()
├── serial_cli_init() ← 启动 REPL(无需 WiFi 即可使用)
│
├── wifi_manager_start() ← 连接(优先 NVS → 回退编译时凭据)
│ └── wait_connected(30s)
│
└── [如果 WiFi 已连接]
├── telegram_bot_start() ← 启动 tg_poll 任务 (Core 0)
├── agent_loop_start() ← 启动 agent_loop 任务 (Core 1)
├── ws_server_start() ← 启动 httpd (端口 18789)
└── outbound_dispatch() ← 启动分发任务 (Core 0)
如果 WiFi 连接失败,串口 CLI 仍可使用,用于诊断和重新配置。
网络:代理支持
MimicLaw 支持 HTTP CONNECT 代理隧道,适用于无法直接 HTTPS 访问的网络环境(在中国地区常见):
1. TCP 连接到代理服务器
2. 发送: CONNECT api.telegram.org:443 HTTP/1.1
3. 接收: HTTP/1.1 200 Connection established
4. 在隧道上进行 TLS 握手 (esp_tls)
5. 通过隧道发送/接收 HTTPS 数据
所有出站 HTTPS 调用均支持:Telegram API、Claude API、Brave Search API。
兼容 Clash Verge、V2Ray、Squid 等常见 HTTP 代理工具。