架构总览¶
设计目标¶
Ethan 是一个运行在 Mac mini 上的个人 AI Agent,全程异步(asyncio + uvloop),长期常驻。核心目标:
- 多模型:同时支持 Claude(Anthropic 原生协议)和 GPT/本地模型(OpenAI 兼容协议)
- 记忆:跨会话的持久记忆 + 自动压缩
- Skill:可手写、可从经验自动生成的知识模块
- 调度:定时任务、心跳机制
- 工具:Shell、文件、Web、MCP 协议扩展
模块全景¶

各模块职责¶
Provider 层 (ethan/providers/)¶
负责与 LLM API 通信,屏蔽不同厂商协议的差异。对上层只暴露统一的 BaseProvider 接口。
→ 详见 providers.md
Core Agent Loop (ethan/core/agent.py)¶
系统的心脏。接收消息列表,驱动 ReAct 循环,协调 Provider、Tools、Memory、Skills。 → 详见 agent-loop.md
工具系统 (ethan/tools/)¶
定义 BaseTool 抽象,通过 ToolRegistry 注册,由 ToolExecutor 并发执行。
→ 详见 tools.md
记忆系统 (ethan/memory/)¶
三层结构:工作记忆(当前 context)、情节记忆(历史对话 SQLite)、持久记忆(用户画像 KV)。 → 详见 memory.md
Skill 系统 (ethan/skills/)¶
从 Markdown 文件加载 Skill,注入 system prompt。支持从经验自动生成新 Skill(Hermes 风格)。 → 详见 skills.md
调度器 (ethan/scheduler/)¶
基于 APScheduler,支持 cron 表达式和 interval。Job 持久化到 SQLite,重启后自动恢复。 → 详见 scheduler.md
Web UI (web/)¶
Next.js 16 App Router 构建的浏览器界面,通过 FastAPI SSE 与后端通信。路由包括 /chat、/chat/[id]、/memory、/knowledge、/schedule、/skills、/sessions、/settings、/channels。消息气泡显示 TTFT 耗时,流式工具调用过程实时渲染。
飞书 / Lark 集成 (ethan/interface/lark_events.py)¶
基于 WebSocket 长连接方案:ethan serve 启动时自动调用 lark-cli event consume im.message.receive_v1 建立长连接,无需公网 IP。收到消息后先加 THINKING 表情确认收到,随后流式回复——工具进度走 post 富文本气泡、最终回答走 interactive 卡片(流式编辑);ui_card 工具产出的自定义卡片(对比/排行/统计/时间轴)作为增量额外补发一条 interactive 卡片。chat_id → session_id 映射持久化到 JSON 文件。实现按职责拆分到同目录子模块:lark_render(消息渲染)、lark_send(收发 IO)、lark_stream(消息处理 + Agent 流式回复),lark_events 仅保留事件消费循环与 start/stop 生命周期并 re-export 公共符号。
→ 详见 interface.md
Fast-path Router¶
每轮对话开始时对用户输入做意图分类,决定走快轨(极简 prompt + 仅 fast_path 工具,最多 2 次迭代)还是慢轨(完整 prompt + 全量工具)。fast_path: true 的 Skill 的 trigger 关键词自动注入路由,无需手动配置。
→ 详见 routing.md
心跳系统 (ethan/core/heartbeat.py)¶
系统内部维护任务,启动时作为后台 asyncio 任务运行,每 N 分钟执行一次:对 facts.json 做 LLM 去重合并,并执行 ~/.ethan/system/heartbeat.md 中定义的周期性任务。与用户管理的 Scheduler(APScheduler)独立运行。
→ 详见 heartbeat.md
知识库 (ethan/memory/knowledge.py)¶
基于 sqlite-vec 的向量检索,文档写入时生成 embedding,查询时做余弦相似度检索。支持从 Web UI 上传、删除文档,Agent 可通过 knowledge_search 工具主动检索,也可通过 /knowledge/search HTTP 端点被外部服务调用。
Prompt Caching (ethan/providers/anthropic.py)¶
Anthropic Provider 在发送 system prompt 前自动将其按 Current time: 分界点拆分为稳定层(identity/soul/tools_reference)和动态层(时间、记忆、Skill 匹配)。稳定层打上 cache_control: ephemeral,5 分钟内重复调用成本降至 0.1×。
→ 详见 caching.md
数据流(一次对话)¶

技术选型¶
| 用途 | 库 | 版本 | 理由 |
|---|---|---|---|
| 异步运行时 | asyncio + uvloop |
0.22+ | 性能,Mac aarch64 原生支持 |
| Claude API | anthropic |
0.109+ | 官方 SDK,streaming + tool_use |
| OpenAI 兼容 | openai |
2.41+ | base_url 可配置,覆盖 GPT/Ollama |
| 定时任务 | APScheduler |
3.x | 成熟,SQLite 持久化 |
| 数据持久化 | SQLite + aiosqlite |
— | 零依赖,本地足够 |
| 配置管理 | pydantic-settings |
2.x | 类型安全,支持 .env 覆盖 |
| HTTP API | FastAPI + uvicorn |
— | 异步,SSE/WebSocket streaming |
| 包管理 | uv |
0.11+ | 速度快,已安装 |
目录结构¶
ethan-ai/
├── ethan/
│ ├── core/
│ │ ├── agent.py # 主 Agent Loop(含 fast/full path 路由)
│ │ ├── config.py # 全局配置(Pydantic)
│ │ ├── heartbeat.py # 系统心跳(facts 去重 + heartbeat.md 任务)
│ │ └── onboarding.py # 新用户引导
│ ├── providers/
│ │ ├── base.py # 抽象 Provider 接口
│ │ ├── anthropic.py # Claude 原生 SDK(含 Prompt Caching)
│ │ ├── openai_compat.py # OpenAI 兼容协议
│ │ └── manager.py # Provider 路由
│ ├── memory/
│ │ ├── session.py # Session 持久化(SQLite)
│ │ ├── working.py # 三层工作记忆(hot/warm/cold)
│ │ ├── consolidator.py # 记忆压缩(廉价模型)
│ │ ├── facts.py # FactStore(跨 session 长期 facts)
│ │ ├── procedures.py # ProcedureStore(操作规范记忆)
│ │ ├── episodic.py # EpisodicStore(历史 session 摘要)
│ │ └── knowledge.py # 知识库(sqlite-vec 向量检索)
│ ├── skills/
│ │ ├── loader.py # 双来源加载(内置 + 用户)
│ │ ├── registry.py # 关键词匹配 + 语义补召回 + 注入
│ │ ├── router.py # 可选语义路由器(BGE INT8 + LR 头)
│ │ ├── generator.py # 从经验自动生成 Skill
│ │ ├── channels/ # 内置 Skill:渠道管理
│ │ ├── lark-im/ # 内置 Skill:飞书 IM 操作
│ │ └── home-assistant/ # 内置 Skill:智能家居控制
│ ├── tools/
│ │ ├── base.py # BaseTool 抽象
│ │ ├── registry.py # ToolRegistry + ToolExecutor
│ │ └── builtin/
│ │ ├── shell.py # Shell 命令执行
│ │ ├── file.py # 文件读写列出
│ │ ├── web.py # 网页抓取
│ │ ├── web_search.py # DuckDuckGo 搜索
│ │ ├── rg_search.py # ripgrep 全文搜索
│ │ ├── fd_find.py # fd 文件查找
│ │ ├── schedule.py # 定时任务管理
│ │ ├── knowledge.py # 知识库工具
│ │ └── acp.py # 委托 Coding Agent
│ ├── scheduler/
│ │ └── cron.py # APScheduler(SQLite 持久化)
│ ├── acp/
│ │ ├── __init__.py # ACP 复杂度判断 + 委托执行(三套 Coding Agent JSON 流 + 多轮续接)
│ │ └── mirror.py # 委派镜像会话(落 Ethan session + 注册 RunManager run 实时推送)
│ └── interface/
│ ├── cli.py # Typer CLI(含延迟导入优化)
│ ├── repl.py # 交互式 REPL(prompt_toolkit)
│ ├── api.py # FastAPI HTTP + SSE
│ ├── lark.py # 飞书 Bot(WebSocket 长连接)
│ └── commands/ # 子命令(model/provider/session/skill/schedule)
├── web/ # Next.js 16 Web UI
├── docs/ # 本文档体系
├── .env # API Key 配置(不入 git)
└── PLAN.md # 开发计划