第 8 章:实战 -- 项目架构设计

前七章我们一块一块地学了 SDK 的各个零件。从这一章开始,我们要把这些零件组装成一台真正的机器 -- MiniClaw,一个迷你版 CLI Agent 助手。


MiniClaw 是什么

你听说过 NanoClaw 吗?它是一个轻量级的开源 AI 助手,用 TypeScript 写的,大约 3900 行代码。它能接入 WhatsApp、支持容器隔离、有记忆系统,功能还挺齐全的。

MiniClaw 就是我们自己造的"Python 版迷你 NanoClaw"。但我们不走大而全的路线,我们走小而完整的路线:

对比项 NanoClaw MiniClaw
语言 TypeScript Python
交互方式 WhatsApp + Web CLI(命令行)
底层 直接调 API Claude Agent SDK
代码量 ~3900 行 ~500 行(目标)
定位 可部署的产品 可学习的教程项目

MiniClaw 的设计理念是:小到能完全理解

想象你去宜家买了个书架,打开包装,发现零件有 200 个,说明书有 40 页 -- 你大概会先叹口气。但如果零件只有 20 个,说明书 2 页 -- 你一杯咖啡的功夫就能装好,而且完全明白每个零件是干什么的。

MiniClaw 就是那个 20 个零件的书架。它虽然小,但五脏俱全:

本章我们先搭骨架 -- 把项目结构设计好,把认证和配置这两个"基础设施"先跑起来。


架构设计

MiniClaw 采用经典的分层架构。如果你写过 Web 应用,这套路你应该很熟悉:上层调下层,每层只管自己的事。

┌─────────────────────────────────┐
│     CLI 交互层 (cli.py)          │  <-- 用户看到的界面:输入、输出、美化
├─────────────────────────────────┤
│    对话引擎 (engine.py)          │  <-- 核心:ClaudeSDKClient 封装
├─────────────────────────────────┤
│     工具层 (tools/)              │  <-- SDK MCP 自定义工具
├─────────────────────────────────┤
│  存储层 (memory + config)        │  <-- SQLite 记忆 + JSON 配置
└─────────────────────────────────┘

打个比方:MiniClaw 就像一家小餐馆。

每层的职责:

文件 职责
CLI 交互层 cli.py 读取用户输入、格式化输出、命令解析
对话引擎 engine.py 管理 ClaudeSDKClient 生命周期、处理多轮对话
工具层 tools/ 注册和管理 MCP 工具、内置工具实现
存储层 memory.py + config.py SQLite 记忆存储、JSON 配置读写

为什么要分层?因为你可以单独替换任何一层。比如:


项目目录结构

miniclaw/
├── __init__.py        # 版本信息
├── __main__.py        # 入口: python -m miniclaw
├── auth.py            # 认证: API Key / 订阅自动检测
├── config.py          # 配置: ~/.miniclaw/config.json
├── cli.py             # CLI 交互层 (第 9 章实现)
├── engine.py          # 对话引擎 (第 9 章实现)
├── memory.py          # 记忆系统 (第 9 章实现)
├── tools/             # 工具目录 (第 10 章实现)
│   ├── __init__.py
│   ├── builtin.py     # 内置工具:文件摘要、代码分析等
│   └── registry.py    # 工具注册中心
├── scheduler.py       # 定时任务 (第 11 章实现)
└── agents.py          # 多 Agent 协作 (第 11 章实现)

你可能会问:为什么不一开始就把所有文件都写好?

因为软件开发有个原则叫 YAGNI -- "You Aren't Gonna Need It"(你现在用不到它)。我们一章一章往里填代码,每一章都只加当前需要的东西。这样你在任何一个时间点看到的代码,都是完整可运行的,而不是一堆写了一半的空壳。

本章我们只实现三个文件:

文件 本章实现 说明
__init__.py 完整 版本信息,一行搞定
__main__.py 完整 项目入口,加载配置 + 检测认证
auth.py 完整 双模式认证检测
config.py 完整 配置管理

双模式认证

还记得第 3 章讲的两种认证方式吗?API Key 模式和订阅模式。MiniClaw 需要两种都支持,而且要自动检测,不用用户手动选。

检测逻辑就像你进一家酒店:

  1. 先看你有没有带房卡(API Key) -- 有就直接进。
  2. 没房卡?看你有没有在前台登记过(claude login) -- 登记过也能进。
  3. 都没有?那对不起,请先办理入住。

用流程图表示:

开始
  │
  ▼
检查 ANTHROPIC_API_KEY 环境变量
  │
  ├── 有值 ──→ API Key 模式 ✓
  │
  └── 没有
        │
        ▼
      检查 claude 命令是否可用
        │
        ├── 可用 ──→ 订阅模式 ✓
        │
        └── 不可用 ──→ 报错,提示用户配置 ✗

这个逻辑实现在 auth.py 中。核心代码很短:

from miniclaw.auth import detect_auth_mode

auth = detect_auth_mode()
print(auth.mode)        # "api_key" 或 "subscription" 或 "none"
print(auth.display_key) # "sk-ant-api03-xxxx..." (脱敏显示)

几个设计要点:

1. API Key 脱敏显示

永远不要把完整的 API Key 打印到屏幕上。MiniClaw 只显示前 12 个字符加省略号。这是安全基本功。

2. 优雅降级

检测失败不抛异常,而是返回 mode="none" 和一条错误信息。让调用方决定怎么处理。这比直接 raise 更灵活 -- 比如你可能想在 UI 上显示一个友好的提示,而不是一段冷冰冰的堆栈跟踪。

3. CLI 路径记录

订阅模式下,我们记录 claude 命令的完整路径。这在调试的时候很有用 -- 用户可能装了多个版本的 CLI,知道具体用的哪个能帮你快速定位问题。

完整代码见本章的 miniclaw/auth.py


配置管理

每个像样的 CLI 工具都需要配置文件。MiniClaw 的配置存在 ~/.miniclaw/config.json

{
    "model": "sonnet",
    "system_prompt": "你是 MiniClaw,一个友好的 AI 助手。用中文回答问题。",
    "max_turns": 30,
    "max_budget_usd": 1.0,
    "tools_enabled": true,
    "memory_enabled": true,
    "verbose": false
}

配置管理的设计思路是默认配置 + 用户覆盖

  1. 代码里写好一套默认配置,保证即使没有配置文件也能正常运行。
  2. 如果用户创建了配置文件,就用用户的值覆盖默认值。
  3. 用户只需要写自己想改的项,不需要把所有配置都写一遍。

就像你新买了一台手机 -- 出厂设置已经能用了,你只需要改你在意的那几项(比如壁纸、铃声)。

from miniclaw.config import load_config

config = load_config()
print(config.model)          # "sonnet" (默认值)
print(config.max_budget_usd) # 1.0 (默认值)
print(config.config_path)    # "~/.miniclaw/config.json"

可配置项一览

配置项 类型 默认值 说明
model str "sonnet" 使用的模型
system_prompt str 见默认值 Claude 的角色设定
max_turns int 30 最大对话轮数
max_budget_usd float 1.0 单次对话预算上限(美元)
tools_enabled bool True 是否启用工具
memory_enabled bool True 是否启用记忆系统
verbose bool False 是否显示详细日志

首次运行自动创建

如果 ~/.miniclaw/ 目录和配置文件不存在,load_config() 会自动创建它们,并写入默认配置。这样用户第一次运行就有一个可编辑的配置文件模板,不用自己从零写起。

完整代码见本章的 miniclaw/config.py


跑起来看看

本章的代码已经可以运行了。在 miniclaw/ 目录的上级目录执行:

python -m miniclaw

如果你设置了 API Key,会看到类似这样的输出:

==================================================
  MiniClaw v0.1.0 - 迷你 AI Agent 助手
==================================================

配置文件: /Users/你的用户名/.miniclaw/config.json
认证模式: api_key
API Key: sk-ant-api03-...

项目骨架已就绪!后续章节将添加完整功能。
  - 第 9 章: 对话引擎 + 记忆系统
  - 第 10 章: 工具生态
  - 第 11 章: 高级特性

如果你用的是订阅模式(claude login 过了),会看到:

认证模式: subscription
CLI 路径: /usr/local/bin/claude

如果两个都没有,会看到错误提示并退出。


本章架构与 SDK 的对应关系

你可能会好奇:我们设计的这些层,跟之前学的 SDK API 是怎么对应的?

MiniClaw 层          对应的 SDK 概念               之前学过的章节
─────────────────────────────────────────────────────────────
CLI 交互层          receive_messages()             第 4 章
对话引擎            ClaudeSDKClient                第 4 章
工具层              create_sdk_mcp_server() / @tool 第 5 章
安全防护            hooks / can_use_tool           第 6、7 章
配置管理            ClaudeAgentOptions             第 3 章
认证检测            env / cli_path                 第 3 章

前七章的知识点,在接下来的实战中会全部用到。如果某个概念记不清了,随时翻回去看。


小结

这一章我们做了四件事:

  1. 明确了 MiniClaw 的定位 -- 纯 Python、CLI 交互、小而完整的 AI Agent 助手
  2. 设计了分层架构 -- CLI 层、引擎层、工具层、存储层,各司其职
  3. 实现了双模式认证 -- API Key 和订阅模式自动检测,优雅降级
  4. 实现了配置管理 -- 默认配置 + 用户覆盖,首次运行自动创建

目前 MiniClaw 还只是个"骨架" -- 能跑起来,能检测认证,能读配置,但还不能聊天。别急,下一章我们就给它装上"大脑"。

下一章: 第 9 章 - 实战:核心引擎与记忆 -- 用 ClaudeSDKClient 实现对话引擎,用 SQLite 实现记忆系统。MiniClaw 将真正能和你聊天,而且能记住之前的对话。


本章文件清单

08-实战-项目架构设计/
  README.md                    # 你正在读的这个文件
  miniclaw/
    __init__.py                # 版本信息
    __main__.py                # 项目入口
    auth.py                    # 双模式认证检测
    config.py                  # 配置管理