# 核心概念
CMDC 的设计就是 7 个互不重叠的抽象搭积木。读完本章你能在脑里画出整个调用图。
---
## 一、Agent — gen_statem 状态机
每个会话对应一个 OTP 进程,跑 `:gen_statem` 状态机,4 个状态:
```
idle ─prompt──▶ running ─stream chunk──▶ streaming ─tool calls──▶ executing_tools
▲ │
└────────── 工具批次完成 / abort / agent_end ───────────────────────┘
```
外部代码不直接持 Agent struct,**只通过 pid 或 session_id 字符串交互**:
```elixir
{:ok, session} = CMDC.create_agent(model: "anthropic:claude-sonnet-4-5")
CMDC.prompt(session, "...") # 异步 cast,立即返回
CMDC.steer(session, ref, "...") # 中段干预
CMDC.abort(session) # 中止
CMDC.status(session) # 状态快照
CMDC.stop(session) # 终止 Supervisor 树
```
完整 API 矩阵见 [`CMDC`](CMDC.html),状态机详细行为见
[Agent 状态机与事件](agent-loop.html)。
---
## 二、Session — Supervisor Tree
`create_agent/1` 实际启动了一棵 Supervisor 树:
```
SessionServer (Supervisor :rest_for_one)
├── Agent (gen_statem)
└── SubAgent.Supervisor (DynamicSupervisor)
├── 子 Agent #1 (gen_statem)
└── 子 Agent #2 (gen_statem)
└── ...(孙 Agent 同样隔离)
```
子 Agent crash 不影响父 Agent;父 Agent crash 由 SessionServer 决定是否
重启全树。Stop 一个 session = 停整棵树。
---
## 三、EventBus — 唯一的对外合约
Agent 内部所有"事情发生了"都通过 `CMDC.Emitter` 广播到
[`CMDC.EventBus`](CMDC.EventBus.html),订阅者收到统一格式:
```
{:cmdc_event, session_id, event}
```
事件类型分七大类(`session` / `stream` / `tool` / `approval` / `subagent` /
`plugin_event` / `error`),完整清单见 [`CMDC.Event`](CMDC.Event.html)。
**消费方式**:
| 场景 | API |
|---|---|
| 当前进程订阅 | `CMDC.subscribe/2` |
| 重连补帧 | `CMDC.subscribe(session, since: last_index)`(需 `event_buffer_size > 0`)|
| Agent 崩溃监控 | `CMDC.monitor/1` → `{:cmdc_down, ref, sid, reason}` |
---
## 四、Plugin — 切面拦截器
Plugin 实现 [`CMDC.Plugin`](CMDC.Plugin.html) behaviour,在 13 个 hook 中
返回 8 种 action 之一:
| 关键 hook | 用途 | 常用 action |
|---|---|---|
| `:session_start / :session_end` | 资源初始化/清理 | `:emit` |
| `{:before_prompt, text}` | 用户 prompt 进 Agent 前 | `:intervene` 改写、`:abort` 拦截 |
| `{:before_request, messages}` | LLM 请求前 | `:switch_model` 路由模型 |
| `{:after_response, msg}` | LLM 回复后 | `:abort` / `:intervene` |
| `{:before_tool, name, args}` | 工具执行前 | `:block_tool` 拦截、`:replace_tool_args` 改参 |
| `{:on_tool_error, ...}` | 工具失败 | `:continue` 重试、`:abort` 放弃 |
| `{:after_tool, name, call_id, result}` | 单工具后 | `:replace_tool_result` 改 result |
| `{:before_compact, messages}` | 压缩前 | 持久化关键事实 |
完整矩阵 + 5 个范例见 [写一个 Plugin](plugins.html)。
---
## 五、Tool — Agent 可调用的能力
Tool 是 LLM 视角的"函数",实现 [`CMDC.Tool`](CMDC.Tool.html) behaviour:
```elixir
@callback name() :: String.t()
@callback description() :: String.t()
@callback parameters() :: map() # JSON Schema
@callback execute(args :: map(), ctx :: CMDC.Context.t()) ::
{:ok, String.t()} | {:error, String.t()} | {:effect, term()}
```
CMDC 内置 11 个:`ReadFile / WriteFile / EditFile / Shell / Grep / ListDir /
Glob / Task(子代理)/ WriteTodos / AskUser / CompactConversation`。
文件类工具默认走 [`CMDC.Sandbox`](CMDC.Sandbox.html) 代理,所有路径在
`working_dir` 内做边界校验。详见 [写一个 Tool](tools.html)。
---
## 六、Backend / Sandbox — 文件与执行的抽象
[`CMDC.Backend`](CMDC.Backend.html) 是文件 / 状态 / 远程存储的统一访问层
(10 callback:ls / read / write / edit / grep / glob / upload / download +
扩展的 execute / id),3 个内置实现:
| Backend | 用途 | 持久性 |
|---|---|---|
| `Backend.State` | 内存 ETS,单测 / 短会话 | 进程级 |
| `Backend.Filesystem` | 本地文件,CLI / 开发 | 跨进程 |
| `Backend.Composite` | prefix 路由组合,生产推荐 | — |
[`CMDC.Sandbox`](CMDC.Sandbox.html) 是 Backend 的子集 + 加 `execute`
(shell 命令)。`Sandbox.Local` 是默认实现。
**典型生产配置**(一个会话挂多套存储):
```elixir
backend = CMDC.Backend.Composite.new(
default: CMDC.Backend.Filesystem.new(root_dir: "/tmp/work", virtual_mode: true),
routes: %{
"/memories/" => MyApp.PgBackend.new(), # 长期记忆
"/conversation_history/" => CMDC.Backend.State.new() # 短期 ETS
}
)
{:ok, session} = CMDC.create_agent(model: "...", backend: backend)
```
---
## 七、Skill / Memory / Checkpoint — 三类持久化
CMDC 把"持久化"按时间尺度拆成三层,命名独立、互不重叠:
| 模块 | 时间尺度 | 用途 | 数据形态 |
|---|---|---|---|
| [`CMDC.Skill`](CMDC.Skill.html) | 永久 | 加载 SKILL.md 注入 system prompt | `.md` 文件 + frontmatter |
| [`CMDC.Memory`](CMDC.Memory.html) behaviour | 跨会话 | 语义记忆存储(store / search / similarity) | 由 backend 决定(ETS / Postgres + pgvector) |
| [`CMDC.Checkpoint`](CMDC.Checkpoint.html) | 单会话快照 | BEAM 重启 / 跨设备恢复 | `Snapshot` struct 序列化 |
**易混淆**:
- `Backend` 是「文件接口」(read_file 之类)
- `Memory` 是「语义记忆接口」(向量检索之类)
- `Checkpoint` 是「会话快照」(save / load / list)
详见 [`CMDC.Backend`](CMDC.Backend.html) / [`CMDC.Memory`](CMDC.Memory.html) /
[`CMDC.Checkpoint`](CMDC.Checkpoint.html) 三个模块文档。
### v0.5 新增 facade API
- **[`CMDC.checkpoint!/2`](CMDC.html#checkpoint!/2)** — 从运行中 session 抓快照
(内部走 `Agent.get_state` + `Checkpoint.save`,序列化策略自动剥离运行期字段)
- **[`CMDC.resume_session!/2`](CMDC.html#resume_session!/2)** — 从 snapshot 重建 session,
续 prompt 时 LLM 看到完整历史,无需自己拼装
- **[`CMDC.Checkpoint.Snapshot.redact/2`](CMDC.Checkpoint.Snapshot.html#redact/2)** —
backend 写前预处理 hook(接 Cloak / KMS / 任意脱敏函数)
- **[`CMDC.Plugin.Builtin.AutoCheckpoint`](CMDC.Plugin.Builtin.AutoCheckpoint.html)** —
内置 Plugin,按 turn / on_tools / on_events OR 触发自动存档 + max_checkpoints / ttl_seconds GC,
走 `CMDC.AsyncTaskSupervisor` 异步执行不阻塞 gen_statem
### v0.5 新增 Hibernate 配置
[`CMDC.Options.hibernate_after_ms`](CMDC.Options.html) —
Agent 进程空闲 N 毫秒后走 OTP 原生 `:hibernate_after` 自动 hibernate,
单进程 heap 8KB → 1.5KB(节省 ~80% 内存)。长会话多租户场景必备。
---
## 依赖关系一览
```
┌─────────────────┐
│ CMDC (facade) │
└────────┬────────┘
│
┌────────────┬───────┴────────┬────────────┐
▼ ▼ ▼ ▼
SessionServer EventBus Checkpoint Telemetry
│
┌────┴────┐
▼ ▼
Agent SubAgent.Supervisor
│
├── State / Stream / ToolRunner / Compactor ← @moduledoc false 私有
├── Plugin Pipeline
│ └── 16 内置 Plugin
├── Tool(11 内置)
│ └── Sandbox / Backend
├── Provider(req_llm 封装)
├── Skill / Memory / Blueprint
└── MCP(Bridge / Client / Supervisor)
```
层级规则:**只允许向下依赖,同层不互相依赖**。
---
## 下一步
- 想看 Agent 状态机怎么转:[Agent 状态机与事件](agent-loop.html)
- 想写第一个切面:[写一个 Plugin](plugins.html)
- 想加个外部能力:[写一个 Tool](tools.html)
- 想看常见组合:[常见配方](cookbook.html)