把 CMDC 当作一个会话级 Agent 引擎:调一次 create_agent/1 拿到 pid,
之后所有交互都通过这个 pid 异步推进,事件经 EventBus 广播给订阅者。
安装
def deps do
[
{:cmdc, "~> 0.4"}
]
end获取依赖:
mix deps.get
Hello World
最少 4 个调用就能完成一次完整对话——创建 → 提问 → 收回复 → 关闭:
{:ok, session} = CMDC.create_agent(
model: "anthropic:claude-sonnet-4-5",
api_key: System.get_env("ANTHROPIC_API_KEY")
)
CMDC.prompt(session, "你好,请用一句话介绍 Elixir 的优势。")
{:ok, reply} = CMDC.collect_reply(session)
IO.puts(reply)
CMDC.stop(session)prompt/2 是非阻塞的——它返回后 LLM 调用才开始;collect_reply/2 同步等
拿到本轮所有 assistant 文本拼接的字符串。需要边收边渲染请改用 subscribe/1。
流式订阅
订阅当前进程接收 {:cmdc_event, session_id, event} 消息:
{:ok, session} = CMDC.create_agent(model: "anthropic:claude-sonnet-4-5")
CMDC.subscribe(session)
CMDC.prompt(session, "数到 5。")
stream_loop = fn loop ->
receive do
{:cmdc_event, _sid, {:message_delta, %{delta: text}}} ->
IO.write(text)
loop.(loop)
{:cmdc_event, _sid, {:agent_end, _msgs, _usage}} ->
:done
after
30_000 -> {:error, :timeout}
end
end
stream_loop.(stream_loop)
CMDC.stop(session)完整事件清单见 CMDC.Event。订阅断网想补帧请用
Options.event_buffer_size 开启 ring buffer。
带工具的 Agent
CMDC 内置 11 个工具(读写文件 / shell / grep / glob / ls / 子代理派发 /
todo 跟踪 / 用户提问 / 上下文压缩 / 大结果分页)。声明 :tools
即可让 Agent 自主调用:
{:ok, session} = CMDC.create_agent(
model: "anthropic:claude-sonnet-4-5",
tools: [
CMDC.Tool.ReadFile,
CMDC.Tool.WriteFile,
CMDC.Tool.Shell,
CMDC.Tool.Grep
],
working_dir: "/tmp/agent-workspace"
)
CMDC.prompt(session, "读取 /tmp/agent-workspace/notes.md,把 TODO 抽出来写到 todos.md")
{:ok, reply} = CMDC.collect_reply(session)Shell / WriteFile 默认走 Sandbox.Local,所有文件路径限制在 working_dir
内(见 Sandbox)。生产环境强烈建议接 Backend.Filesystem
virtual_mode: true。
用 Plugin 加切面
Plugin 是把"切面逻辑"插入 Agent 13 个生命周期 hook 的标准方式:
defmodule MyApp.AuditPlugin do
@behaviour CMDC.Plugin
@impl true
def init(_opts), do: {:ok, %{count: 0}}
@impl true
def priority, do: 100
@impl true
def handle_event({:before_tool, name, args}, state, _ctx) do
IO.puts("[审计] 调用工具: #{name}, 参数: #{inspect(args)}")
{:continue, %{state | count: state.count + 1}}
end
def handle_event(_event, state, _ctx), do: {:continue, state}
end
{:ok, session} = CMDC.create_agent(
model: "anthropic:claude-sonnet-4-5",
tools: [CMDC.Tool.Shell],
plugins: [{MyApp.AuditPlugin, []}]
)CMDC 自带 16 个内置 Plugin(见 Plugins(安全与控制) 和 Plugins(优化与记忆)分组),覆盖审批 / 安全 / 内容拦截 / 长会话记忆 / 模型路由 / 大结果 offload / 反思 / 规划等典型场景。
中段干预(Steering)
发现方向不对想换条路?不需要 abort 重来——直接 steer/2 软中断:
{:ok, session} = CMDC.create_agent(
model: "anthropic:claude-sonnet-4-5",
tools: [CMDC.Tool.Shell]
)
CMDC.prompt(session, "帮我用 100 行 Python 实现快排。")
# 中途改主意
ref = make_ref()
CMDC.steer(session, ref, "停,改成用 Elixir 实现,别用 Python。")
{:ok, reply} = CMDC.collect_reply(session)正在执行的不可中断工具会跑完,可中断的工具被 brutal_kill,下一轮
LLM 调用看到合并后的新 prompt。完整选项见 CMDC 的 steer/2 与
CMDC.Agent 的状态行为表。
HITL 审批
让人类在 Agent 调危险工具前点头:
{:ok, session} = CMDC.create_agent(
model: "anthropic:claude-sonnet-4-5",
tools: [CMDC.Tool.Shell],
plugins: [
{CMDC.Plugin.Builtin.HumanApproval, [tools: ["shell"]]}
]
)
CMDC.subscribe(session)
CMDC.prompt(session, "在 /tmp 下创建一个 hello.txt 文件。")
receive do
{:cmdc_event, _sid, {:approval_required, %{id: id, tool: "shell", args: args}}} ->
IO.inspect(args, label: "Agent 想跑")
CMDC.approve(session, id) # 或 CMDC.reject(session, id)
end
{:ok, reply} = CMDC.collect_reply(session)approve_always 可把同类命令加入 session 白名单,详见
CMDC.Plugin.Builtin.HumanApproval。
下一步
跑通上面五段你已经覆盖了 80% 的日常用法。继续深挖请看:
- 核心概念 — Agent / Session / Plugin / Tool / Backend 七大概念
- Agent 状态机与事件 — 4 状态流转 + 完整事件清单
- 写一个 Plugin — 13 hook × 8 action 矩阵 + 5 个完整范例
- 写一个 Tool — Tool behaviour + Sandbox 代理 + 错误处理
- 常见配方 — 端到端组合范例(流式 UI / 长会话不失忆 / 多 Agent / Checkpoint / Telemetry)
- 升级指南 — v0.2 → v0.3 → v0.4 各版本兼容边界