# LLM Probe - LLM 服务验证 CLI 工具架构设计文档

## 1. 文档概述

| 项目 | 内容 |
|------|------|
| 文档版本 | V1.1 |
| 创建日期 | 2026-03-12 |
| 项目名称 | **llm-probe** (LLM 探针) |
| 开发语言 | Rust |
| 目标平台 | Windows / macOS / Linux |
| 核心依赖 | crate:llm  (v1.3.7) (a rust crate named:llm )|

---

> 说明：当前代码已升级到 `llm 1.3.8`，并计划引入多 provider profile、OpenAI endpoint/dialect 分层和 legacy reasoning 方言隔离。新的优化设计见 [架构优化方案.md](./架构优化方案.md)。

## 2. 系统架构总览

### 2.1 分层架构

```
┌─────────────────────────────────────────────────────────────────┐
│                      CLI Interface Layer                        │
│                      (命令行交互层)                               │
│                    参数解析 · 命令路由 · 帮助信息                 │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Command Handler Layer                       │
│                       (命令处理层)                               │
│                                                                 │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│  │  Call Cmd   │ │  List Cmd   │ │  Init Cmd   │ │Convert Cmd│ │
│  │  (LLM调用)  │ │  (模型列表)  │ │  (初始化)    │ │ (格式转换) │ │
│  └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Configuration Layer                          │
│                      (配置管理层)                                │
│                                                                 │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ Config Loader│  │Config Merger │  │Env Resolver │          │
│  │ (文件加载)    │  │(优先级合并)   │  │(环境变量解析)│          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
│                                                                 │
│  ┌──────────────┐  ┌──────────────┐                            │
│  │Config Validator│ │Config Converter│                          │
│  │ (配置验证)     │  │ (格式转换)     │                          │
│  └──────────────┘  └──────────────┘                            │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                       Provider Layer                            │
│                      (服务商适配层)                              │
│                                                                 │
│  ┌────────────────────────────────────────────────────────┐    │
│  │              LLMBackend Trait (统一抽象接口)             │    │
│  │                                                         │    │
│  │   • chat_completion()   • stream_chat()                │    │
│  │   • list_models()                                       │    │
│  └────────────────────────────────────────────────────────┘    │
│              ▲                    ▲                    ▲       │
│              │                    │                    │       │
│     ┌────────────────┐  ┌────────────────┐  ┌────────────────┐│
│     │ OpenAI Backend │  │ Gemini Backend │  │  (可扩展...)    ││
│     │  (llm crate)   │  │  (llm crate)   │  │                ││
│     └────────────────┘  └────────────────┘  └────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                        Output Layer                             │
│                       (输出展示层)                               │
│                                                                 │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │ Stream Output│  │ Normal Output│  │ Error Display│          │
│  │ (实时流式)    │  │ (格式化输出)  │  │ (错误提示)    │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
└─────────────────────────────────────────────────────────────────┘
```

### 2.2 核心数据流

```
                    ┌─────────────────┐
                    │    用户输入      │
                    │ (CLI / Config)  │
                    └────────┬────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
              ▼              ▼              ▼
        ┌──────────┐  ┌──────────┐  ┌──────────┐
        │CLI Args  │  │Config File│  │Env Vars  │
        │(高优先级) │  │(低优先级)  │  │(中优先级) │
        └────┬─────┘  └─────┬────┘  └────┬─────┘
             │              │              │
             └──────────────┼──────────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │  Config Merger  │
                   │  (按优先级合并)   │
                   └────────┬────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │ RuntimeConfig   │
                   │ (运行时配置)     │
                   └────────┬────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │ Provider Factory│
                   │ (选择后端实现)   │
                   └────────┬────────┘
                            │
              ┌─────────────┼─────────────┐
              │             │             │
              ▼             ▼             ▼
        ┌──────────┐  ┌──────────┐  ┌──────────┐
        │ OpenAI   │  │ Gemini   │  │  ...     │
        │ Backend  │  │ Backend  │  │          │
        └────┬─────┘  └────┬─────┘  └────┬─────┘
             │             │             │
             └─────────────┼─────────────┘
                           │
                           ▼
                   ┌─────────────────┐
                   │   LLM API 调用   │
                   │ (Stream/Normal) │
                   └────────┬────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │   Output Layer  │
                   │ (结果展示)       │
                   └─────────────────┘
```

---

## 3. 模块划分与职责

### 3.1 模块结构

```
llm-probe/
├── src/
│   ├── main.rs                    # 程序入口
│   │
│   ├── cli/                       # CLI 模块
│   │   ├── mod.rs                 # 模块导出
│   │   ├── args.rs                # 参数定义与解析
│   │   └── commands.rs            # 命令路由与分发
│   │
│   ├── config/                    # 配置模块
│   │   ├── mod.rs                 # 模块导出
│   │   ├── schema.rs              # 配置结构定义
│   │   ├── loader.rs              # 配置文件加载(YAML/JSON)
│   │   ├── merger.rs              # 多源配置合并(优先级处理)
│   │   ├── validator.rs          # 配置有效性验证
│   │   └── converter.rs          # YAML↔JSON格式转换
│   │
│   ├── provider/                  # 服务商适配模块
│   │   ├── mod.rs                 # 模块导出
│   │   ├── traits.rs              # LLMBackend trait定义
│   │   ├── openai.rs              # OpenAI兼容接口实现
│   │   ├── gemini.rs              # Gemini接口实现
│   │   └── factory.rs             # Provider工厂(按配置创建实例)
│   │
│   ├── output/                    # 输出模块
│   │   ├── mod.rs                 # 模块导出
│   │   ├── formatter.rs           # 输出格式化(响应内容、统计信息)
│   │   ├── stream.rs              # 流式输出处理(实时打印)
│   │   └── color.rs               # 终端彩色输出
│   │
│   ├── error/                     # 错误处理模块
│   │   ├── mod.rs                 # 模块导出
│   │   └── types.rs               # 自定义错误类型与用户友好提示
│   │
│   └── utils/                     # 工具模块
│       ├── mod.rs                 # 模块导出
│       ├── prompt.rs              # 交互式提示(覆盖确认等)
│       ├── secret.rs              # 敏感信息处理(API Key保护)
│       └── platform.rs            # 跨平台兼容性处理
│
├── tests/                         # 集成测试
├── docs/                          # 文档
└── Cargo.toml                     # 依赖配置
```

### 3.2 各模块详细设计

---

#### 3.2.1 CLI 模块 (`cli/`)

**职责**：命令行参数解析、命令路由、帮助信息展示

**核心逻辑**：

| 组件 | 职责 | 关键点 |
|------|------|--------|
| **Args Parser** | 解析命令行参数 | 使用 clap derive 宏；`--message` 支持多次传入；`-t` 接收1-2个路径参数 |
| **Command Router** | 根据参数路由到对应处理器 | 识别 4 种命令：Call / List / Init / Convert |
| **Help Generator** | 生成帮助信息 | 自动生成，包含参数说明与示例 |

**参数优先级实现逻辑**：

```
优先级判断顺序：
1. 检查命令行参数是否设置 → 最高优先级
2. 检查环境变量是否设置   → 中等优先级
3. 检查配置文件是否设置   → 较低优先级
4. 使用默认值             → 最低优先级

特殊处理：
- --message 参数：不覆盖，而是追加到配置文件 context 末尾
- --stream 参数：布尔标志，存在即为 true
```

**命令识别逻辑**：

| 参数组合 | 命令类型 | 说明 |
|----------|----------|------|
| `-i` 或 `--init` | Init | 初始化配置文件 |
| `-t` 或 `--convert` | Convert | 格式转换 |
| `-l` 或 `--list` | List | 列出模型 |
| 其他情况 | Call | 调用 LLM |

**`-t/--convert` 参数解析逻辑**：

```
参数形式：
├── llm-probe -t input.json          → 输出路径自动推断
└── llm-probe -t input.json out.yaml → 使用指定输出路径

自动推断输出路径规则：
├── 输入: config.json → 输出: config.yaml
├── 输入: config.yaml → 输出: config.json
└── 输入: config.yml  → 输出: config.json

实现方式：
├── 使用 clap 的 value_parser 接收 Vec<PathBuf>
├── 验证参数数量在 1-2 之间
└── 根据参数数量决定输出路径
```

---

#### 3.2.2 配置模块 (`config/`)

**职责**：配置文件加载、合并、验证、转换

**核心数据结构**：

| 结构 | 用途 | 说明 |
|------|------|------|
| **FileConfig** | 配置文件结构 | 与 YAML/JSON 一一对应，所有字段可选 |
| **RuntimeConfig** | 运行时配置 | 合并后的最终配置，所有字段必填 |
| **Message** | 对话消息 | role + content |

**配置字段规范**：

| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `provider` | String | 是 | - | 服务商：openai / gemini |
| `base_url` | String | 是 | - | API 基础地址 |
| `api_key` | String | 是 | - | API 密钥（建议用环境变量） |
| `model` | String | 是 | - | 模型名称 |
| `stream` | Boolean | 否 | false | 是否流式返回 |
| `context` | Array | 否 | [] | 对话上下文 |

**Context 结构**：

| 字段 | 类型 | 说明 |
|------|------|------|
| `role` | String | 角色：system / user / assistant |
| `content` | String | 消息内容 |

**配置合并流程**：

```
┌─────────────────────────────────────────────────────────────┐
│                    配置合并流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Step 1: 加载默认值                                         │
│  ├── provider: 无                                           │
│  ├── model: ""                                              │
│  ├── stream: false                                          │
│  └── context: []                                            │
│                                                             │
│  Step 2: 加载配置文件（如果存在）                            │
│  ├── 识别格式：YAML / JSON                                   │
│  ├── 解析文件内容                                           │
│  └── 合并到当前配置（覆盖默认值）                            │
│                                                             │
│  Step 3: 读取环境变量                                        │
│  ├── LLM_API_KEY → api_key                                  │
│  ├── LLM_PROVIDER → provider (可选扩展)                     │
│  ├── LLM_BASE_URL → base_url (可选扩展)                     │
│  └── LLM_MODEL → model (可选扩展)                           │
│                                                             │
│  Step 4: 应用命令行参数                                      │
│  ├── 覆盖所有可配置字段                                      │
│  └── --message 追加到 context 末尾（非覆盖）                │
│                                                             │
│  Step 5: 验证必填字段                                        │
│  ├── provider ✓ 必填                                        │
│  ├── base_url ✓ 必填                                        │
│  ├── api_key ✓ 必填                                         │
│  └── model ✓ 必填                                           │
│                                                             │
│  Step 6: 返回 RuntimeConfig                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

**格式转换逻辑**：

```
输入文件 → 自动识别格式（扩展名判断）
         ↓
    解析为 FileConfig
         ↓
    ┌────────────────┐
    │ 输出格式判断    │ ← 根据输出文件扩展名
    │ (json/yaml)    │   或默认相反格式
    └────────┬───────┘
             │
    ┌────────┴────────┐
    ▼                 ▼
序列化为 JSON    序列化为 YAML
```

**注释处理策略**：

```
格式转换时的注释处理：

YAML → JSON：
├── JSON 不支持注释，转换时注释会丢失
├── 在控制台输出警告提示用户
└── 数据内容完整保留

JSON → YAML：
├── 原文件无注释，生成的 YAML 也无注释
├── 可选择：生成带默认注释的模板格式
└── 数据内容完整保留

用户提示策略：
├── 转换前明确提示用户注释处理方式
├── 提供 --no-comment-warning 参数抑制警告
└── 转换后输出"注释已丢失"的摘要信息
```

**配置文件默认路径与搜索顺序**：

```
默认配置文件路径（初始化时未指定 --init-path）：
├── 当前目录 ./llm-probe.yaml（优先）
└── 用户配置目录
    ├── Linux/macOS: ~/.config/llm-probe/config.yaml
    └── Windows: %APPDATA%/llm-probe/config.yaml

配置文件搜索顺序（当未指定 -c 时）：
├── 1. 当前目录 ./llm-probe.yaml
├── 2. 当前目录 ./llm-probe.json
├── 3. 用户配置目录 ~/.config/llm-probe/config.yaml
└── 4. 用户配置目录 ~/.config/llm-probe/config.json
```

---

#### 3.2.3 服务商适配模块 (`provider/`)

**职责**：统一 LLM 服务调用接口，支持多服务商扩展

**核心抽象 - LLMBackend Trait**：

| 方法 | 功能 | 返回值 |
|------|------|--------|
| `chat_completion()` | 非流式对话调用 | ChatResponse (内容、耗时、Token统计) |
| `stream_chat()` | 流式对话调用 | 通过回调实时返回内容 |
| `list_models()` | 列出可用模型 | Vec<ModelInfo> |

**Provider 工厂逻辑**：

```
输入: provider 名称 + 配置信息
      │
      ▼
┌─────────────────────┐
│  Provider Factory   │
│  (匹配 provider)    │
└──────────┬──────────┘
           │
     ┌─────┴─────┬─────────┬─────────┐
     │           │         │         │
     ▼           ▼         ▼         ▼
 "openai"     "gemini"   "claude"   ...
     │           │         │         │
     ▼           ▼         ▼         ▼
OpenAI       Gemini     Claude     ...
Backend      Backend    Backend
     │           │         │         │
     └─────┬─────┴─────────┴─────────┘
           │
           ▼
   返回 Box<dyn LLMBackend>
```

**OpenAI Backend 实现逻辑**（基于 llm crate）：

```
初始化阶段：
├── 接收 api_key 和 base_url
├── 创建 llm crate 的 OpenAI 客户端实例
└── 配置 base_url（如自定义）

chat_completion 调用：
├── 记录开始时间
├── 构建 messages 列表（从 context 转换）
├── 调用 llm 客户端的 chat 方法
├── 等待完整响应
├── 计算耗时
└── 返回 ChatResponse

stream_chat 调用：
├── 构建 messages 列表
├── 调用 llm 客户端的 stream 方法
├── 循环读取 chunk
├── 每收到 chunk 立即调用回调函数
└── 直到流结束

list_models 调用：
├── 调用 llm 客户端的 models().list() 方法
└── 返回模型列表
```

**Gemini Backend 实现逻辑**：

```
与 OpenAI 类似，使用 llm crate 的 Gemini 模块
需注意：
├── API 格式差异（认证方式、请求结构）
├── base_url 处理方式不同
└── 错误码映射
```

> **注意**：本架构中关于 llm crate 的具体 API 调用方式需要根据实际文档和示例代码进行调整。后续开发阶段将根据提供的样例进行验证和修正。

**扩展新 Provider 步骤**：

1. 创建新文件 `provider/xxx.rs`
2. 实现 `LLMBackend` trait
3. 在 `factory.rs` 中添加匹配分支
4. 更新配置 schema 添加 provider 枚举值（可选）

---

#### 3.2.4 输出模块 (`output/`)

**职责**：格式化输出、流式显示、错误提示

**输出类型**：

| 类型 | 场景 | 格式 |
|------|------|------|
| **响应输出** | LLM调用结果 | 分隔线 + 模型名 + 耗时 + 内容 + Token统计(可选) |
| **模型列表** | `-l` 命令 | 标题 + 模型列表（带归属信息） |
| **错误输出** | 异常情况 | 红色高亮 + 用户友好提示 |
| **流式输出** | `--stream` 模式 | 实时打印，无缓冲 |

**响应输出格式**：

```
┌────────────────────────────────────────┐
│ 模型: gpt-4                            │  ← 绿色
│ 耗时: 1234 ms                          │  ← 黄色
├────────────────────────────────────────┤  ← 分隔线
│ 响应内容...                            │
└────────────────────────────────────────┘

Token 统计（可选，仅当 API 返回时显示）：
├── 显示格式: [Token: 输入 xx, 输出 xx]
└── 颜色：暗灰色（辅助信息）
```

**流式输出处理**：

```
┌─────────────────────────────────────────────────────────────┐
│                    流式输出流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 打印开始提示                                             │
│     ├── 模型名称（绿色）                                     │
│     └── "流式响应中..."                                      │
│                                                             │
│  2. 接收 chunk                                              │
│     ├── 立即打印（不缓冲）                                   │
│     ├── 立即 flush stdout                                   │
│     └── 循环直到流结束                                       │
│                                                             │
│  3. 流结束后                                                 │
│     ├── 打印换行                                            │
│     └── 可选：打印总耗时                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

**彩色输出规则**：

| 元素 | 颜色 | 说明 |
|------|------|------|
| 模型名称 | 绿色 | 重要信息高亮 |
| 耗时统计 | 黄色 | 性能指标 |
| 错误信息 | 红色 | 需要关注 |
| 分隔线 | 暗灰色 | 视觉分隔 |
| Token统计 | 暗灰色 | 辅助信息（可选显示） |

---

#### 3.2.5 错误处理模块 (`error/`)

**职责**：统一错误类型、用户友好提示

**错误类型分类**：

| 错误类型 | 场景 | 用户提示 |
|----------|------|----------|
| ConfigFormatError | 配置文件语法错误 | "配置文件格式错误，请检查 YAML/JSON 语法是否正确" |
| ConfigFileNotFound | 配置文件不存在 | "配置文件不存在: {path}" |
| InvalidApiKey | API Key 无效 | "API 密钥无效，请检查密钥是否正确或是否过期" |
| NetworkError | 网络连接失败 | "API 地址无法访问，请检查网络或地址是否正确" |
| ModelNotFound | 模型不存在 | "模型名称不存在，可通过 -l 参数查看当前服务商支持的模型列表" |
| UnsupportedProvider | 不支持的服务商 | "不支持的服务商: {provider}" |
| FileExists | 文件已存在 | 提示是否覆盖 |
| InputFileNotFound | 输入文件不存在 | "输入文件不存在，请检查路径是否正确" |
| LlmApiError | LLM API 错误 | 根据错误码映射友好提示 |

**HTTP 状态码映射规则**：

| HTTP 状态码 | 错误类型 | 用户提示 |
|-------------|----------|----------|
| 401 | InvalidApiKey | API 密钥无效，请检查密钥是否正确或是否过期 |
| 403 | InvalidApiKey | API 密钥无权限，请检查密钥权限范围 |
| 404 | ModelNotFound | 模型不存在，请检查模型名称或使用 -l 查看可用模型 |
| 429 | RateLimitError | 请求过于频繁，请稍后重试 |
| 500 | ServerError | 服务器内部错误，请稍后重试 |
| 502/503 | NetworkError | API 服务暂时不可用，请稍后重试 |
| 超时 | NetworkError | 请求超时，请检查网络连接或 API 地址 |

**错误处理流程**：

```
错误发生
    │
    ▼
转换为 LlmProbeError
    │
    ▼
调用 user_message() 获取用户友好提示
    │
    ▼
输出到 stderr（红色）
    │
    ▼
返回非零退出码
```

**敏感信息保护**：

- API Key 不出现在错误消息中
- API Key 不出现在日志中
- 使用 `SecretString` 包装敏感字段
- 仅在调用 API 时暴露

---

#### 3.2.6 工具模块 (`utils/`)

**职责**：交互式提示、文件操作辅助、跨平台兼容

**交互式提示**：

| 场景 | 提示内容 | 用户操作 |
|------|----------|----------|
| 覆盖确认 | "文件已存在，是否覆盖？[y/N]:" | 输入 y 确认，其他取消 |
| 初始化确认 | "将在 {path} 创建配置文件，是否继续？[y/N]:" | 输入 y 确认 |

**跨平台兼容性处理**：

```
终端颜色：
├── 使用 colored crate 自动处理
├── Windows 10+ 原生支持 ANSI 颜色
└── 旧版 Windows 自动降级为无颜色输出

路径处理：
├── 使用 PathBuf 而非字符串拼接
├── 配置文件路径使用 dirs crate 获取
└── 平台默认路径：
    ├── Windows: %APPDATA%/llm-probe/
    └── Linux/macOS: ~/.config/llm-probe/

换行符：
├── 使用 println! 宏自动处理
└── 文件写入时使用系统默认换行符
```

---

## 4. 核心流程设计

### 4.1 程序主流程

```
程序启动
    │
    ▼
解析命令行参数
    │
    ├── 检查 --version → 输出版本号 → 退出
    │
    ├── 检查 --help → 输出帮助信息 → 退出
    │
    ├── 检查 --init → 执行初始化命令 → 退出
    │
    ├── 检查 --convert → 执行转换命令 → 退出
    │
    ▼
加载并合并配置
    │
    ├── 加载配置文件（如果指定或自动搜索）
    ├── 读取环境变量
    ├── 应用命令行参数
    └── 验证必填字段
    │
    ▼
创建 Provider 实例
    │
    ├── 检查 --list → 列出模型 → 退出
    │
    ▼
调用 LLM 服务
    │
    ├── 检查 --stream → 流式调用
    │                  └── 实时输出
    │
    └── 否则 → 非流式调用
               └── 格式化输出
    │
    ▼
程序结束
```

### 4.2 配置合并流程

```
                    ┌─────────────┐
                    │   开始合并   │
                    └──────┬──────┘
                           │
                           ▼
                  ┌─────────────────┐
                  │ 初始化默认配置   │
                  │ provider=none   │
                  │ model=""        │
                  │ stream=false    │
                  └────────┬────────┘
                           │
                           ▼
              ┌────────────────────────┐
              │ 是否有配置文件？        │
              │ (自动搜索或指定)        │
              └────────┬───────┬───────┘
                    是 │       │ 否
                       ▼       │
              ┌──────────────┐ │
              │ 加载配置文件 │ │
              │ (YAML/JSON)  │ │
              └──────┬───────┘ │
                     │         │
                     ▼         │
              ┌──────────────┐ │
              │ 合并到当前   │ │
              │ 配置         │ │
              └──────┬───────┘ │
                     │         │
                     ◄─────────┘
                     │
                     ▼
              ┌─────────────────┐
              │ 读取环境变量     │
              │ LLM_API_KEY     │
              │ LLM_PROVIDER    │
              │ LLM_BASE_URL    │
              │ LLM_MODEL       │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ 应用命令行参数   │
              │ (逐字段覆盖)     │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ --message 参数  │
              │ (追加到context) │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ 验证必填字段     │
              │ provider ✓      │
              │ base_url ✓      │
              │ api_key ✓       │
              │ model ✓         │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ 返回运行时配置   │
              └─────────────────┘
```

### 4.3 LLM 调用流程

#### 4.3.1 非流式调用

```
┌─────────────────────────────────────────────────────────────┐
│                    非流式调用流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 准备阶段                                                 │
│     ├── 根据 provider 选择 Backend                          │
│     ├── 将 context 转换为 messages 格式                      │
│     └── 记录开始时间                                         │
│                                                             │
│  2. API 调用                                                 │
│     ├── 调用 backend.chat_completion()                      │
│     ├── 等待完整响应                                        │
│     └── 捕获可能的错误                                       │
│                                                             │
│  3. 响应处理                                                 │
│     ├── 计算总耗时                                          │
│     ├── 提取响应内容                                        │
│     └── 提取 token 使用统计（如 API 返回）                   │
│                                                             │
│  4. 输出展示                                                 │
│     ├── 打印分隔线                                          │
│     ├── 打印模型名称（绿色）                                 │
│     ├── 打印耗时（黄色）                                     │
│     ├── 打印分隔线                                          │
│     ├── 打印响应内容                                        │
│     └── 打印 token 统计（可选，暗灰色）                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

#### 4.3.2 流式调用

```
┌─────────────────────────────────────────────────────────────┐
│                    流式调用流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 准备阶段                                                 │
│     ├── 根据 provider 选择 Backend                          │
│     ├── 将 context 转换为 messages 格式                      │
│     └── 打印开始提示（模型名称）                             │
│                                                             │
│  2. 建立流连接                                               │
│     ├── 调用 backend.stream_chat()                          │
│     └── 获取 stream 对象                                     │
│                                                             │
│  3. 流式读取循环                                             │
│     ┌─────────────────────────────────────┐                │
│     │  while stream.has_next()            │                │
│     │  ├── 读取下一个 chunk               │                │
│     │  ├── 立即打印到 stdout              │                │
│     │  ├── 立即 flush stdout              │                │
│     │  └── 捕获流错误                     │                │
│     └─────────────────────────────────────┘                │
│                                                             │
│  4. 流结束处理                                               │
│     ├── 打印换行                                            │
│     └── 可选：打印总耗时                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

### 4.4 配置文件初始化流程

```
检查 --init 参数
    │
    ├── 参数值存在 → format = 参数值 (json/yaml)
    │
    └── 参数值不存在 → format = yaml (默认)
    │
    ▼
检查 --init-path 参数
    │
    ├── 存在 → output_path = 参数值
    │
    └── 不存在 → output_path = ./llm-probe.{format}
    │
    ▼
检查文件是否存在
    │
    ├── 存在 → 提示是否覆盖 → 用户确认 → 继续
    │           └── 用户取消 → 退出
    │
    └── 不存在 → 继续
    │
    ▼
生成默认配置内容
    │
    ├── 根据格式生成模板
    └── 添加详细注释
    │
    ▼
写入文件
    │
    ▼
输出成功提示
```

### 4.5 格式转换流程

```
解析 --convert 参数
    │
    ├── 获取输入文件路径
    └── 获取输出文件路径（可选）
    │
    ▼
检查输入文件是否存在
    │
    ├── 不存在 → 报错退出
    │
    └── 存在 → 继续
    │
    ▼
识别输入格式（扩展名判断）
    │
    ├── .json → JSON 格式
    └── .yaml/.yml → YAML 格式
    │
    ▼
解析输入文件为 FileConfig
    │
    ▼
确定输出格式
    │
    ├── 输出路径存在 → 根据输出路径扩展名判断
    │
    └── 输出路径不存在 → 使用与输入相反的格式
    │
    ▼
确定输出路径
    │
    ├── 输出路径存在 → 使用指定路径
    │
    └── 输出路径不存在 → 输入文件同目录，扩展名替换
    │
    ▼
检查输出文件是否存在
    │
    ├── 存在 → 提示是否覆盖 → 用户确认 → 继续
    │           └── 用户取消 → 退出
    │
    └── 不存在 → 继续
    │
    ▼
序列化为目标格式
    │
    ├── JSON → 直接序列化
    │
    └── YAML → 序列化（提示注释可能丢失）
    │
    ▼
写入输出文件
    │
    ▼
输出成功提示
    │
    ▼
提示注释处理结果
    ├── YAML→JSON: "注释已在转换中丢失"
    └── JSON→YAML: "已生成无注释的 YAML 文件"
```

---

## 5. 配置文件设计

### 5.1 配置文件示例

**YAML 格式** (`llm-probe.yaml`)：

```yaml
# LLM Probe 配置文件
# 服务商：openai / gemini（可扩展）
provider: "openai"

# API 基础地址
# OpenAI 兼容接口示例：https://api.openai.com/v1
base_url: "https://api.openai.com/v1"

# API 密钥
# 建议通过环境变量 LLM_API_KEY 设置，避免明文存储
api_key: ""

# 默认模型
model: "gpt-4"

# 是否流式返回
stream: false

# 对话上下文
context:
  - role: "system"
    content: "You are a helpful assistant."
  - role: "user"
    content: "Hello!"
```

**JSON 格式** (`llm-probe.json`)：

```json
{
  "provider": "openai",
  "base_url": "https://api.openai.com/v1",
  "api_key": "",
  "model": "gpt-4",
  "stream": false,
  "context": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "Hello!"
    }
  ]
}
```

---

## 6. 命令行参数设计

### 6.1 参数总览

| 短参数 | 长参数 | 参数类型 | 说明 |
|--------|--------|----------|------|
| `-c` | `--config` | PATH | 配置文件路径 |
| `-m` | `--model` | STRING | 模型名称 |
| `-l` | `--list` | FLAG | 列出模型 |
| | `--message` | STRING | 用户消息（可多次） |
| `-p` | `--provider` | STRING | 服务商 |
| `-u` | `--url` | STRING | API 地址 |
| `-s` | `--secret` | STRING | API Key |
| | `--stream` | FLAG | 流式返回 |
| `-i` | `--init` | [FORMAT] | 初始化配置 |
| | `--init-path` | PATH | 初始化路径 |
| `-t` | `--convert` | PATH [PATH] | 格式转换 |
| `-h` | `--help` | FLAG | 帮助信息 |
| `-v` | `--version` | FLAG | 版本信息 |

### 6.2 使用场景

| 场景 | 命令示例 |
|------|----------|
| 使用配置文件调用 | `llm-probe -c config.yaml` |
| 覆盖模型和启用流式 | `llm-probe -c config.yaml -m gpt-4 --stream` |
| 纯命令行调用 | `llm-probe -p openai -u https://api.xxx.com/v1 -s sk-xxx -m gpt-4` |
| 追加消息 | `llm-probe -c config.yaml --message "你好" --message "计算 1+1"` |
| 列出模型 | `llm-probe -c config.yaml -l` |
| 初始化配置 | `llm-probe -i yaml --init-path ~/config.yaml` |
| 格式转换 | `llm-probe -t config.json config.yaml` |

---

## 7. 扩展性设计

### 7.1 新增服务商

**步骤**：

1. 在 `provider/` 目录创建新文件（如 `claude.rs`）
2. 实现 `LLMBackend` trait 的所有方法
3. 在 `factory.rs` 中添加 provider 匹配分支
4. 更新文档和配置示例

**扩展点设计**：

```
LLMBackend Trait 方法：
├── chat_completion() → 核心方法，必须实现
├── stream_chat()     → 核心方法，必须实现
└── list_models()     → 核心方法，必须实现
```

### 7.2 新增配置字段

**向后兼容策略**：

- 新字段使用 `Option<T>` 类型
- 使用 `#[serde(default)]` 注解
- 旧配置文件自动使用默认值
- 命令行参数逐步添加新选项

### 7.3 新增输出格式

**扩展点**：

- 通过 trait 定义输出格式化接口
- 支持未来添加 JSON 输出、Markdown 输出等
- 通过命令行参数 `--output-format` 选择

---

## 8. 安全性设计

### 8.1 敏感信息保护

| 保护措施 | 实现方式 |
|----------|----------|
| API Key 不明文存储 | 配置文件中留空，提示用环境变量 |
| API Key 不出现在日志 | 使用 SecretString 包装 |
| API Key 不出现在错误信息 | 错误提示使用通用描述 |
| 环境变量优先 | LLM_API_KEY 环境变量 |

### 8.2 输入验证

| 验证项 | 验证逻辑 |
|--------|----------|
| provider 值 | 必须在支持列表中 |
| base_url 格式 | 必须是有效 URL |
| api_key 非空 | 必须提供 |
| model 非空 | 必须提供 |
| 配置文件格式 | YAML/JSON 语法正确 |

---

## 9. 依赖库清单

| 用途 | 依赖库 | 版本 | 说明 |
|------|--------|------|------|
| CLI 参数解析 | `clap` | 4.x | derive 宏简化参数定义 |
| 异步运行时 | `tokio` | 1.x | features: full |
| 序列化 | `serde` | 1.x | features: derive |
| JSON 支持 | `serde_json` | 1.x | JSON 解析 |
| YAML 支持 | `serde_yaml` | 0.9 | YAML 解析 |
| LLM 后端 | `llm` | 1.3.7 | 多服务商 LLM 接口 |
| 错误处理 | `thiserror` | 1.x | 错误类型定义 |
| 敏感信息 | `secrecy` | 0.8 | SecretString |
| 彩色输出 | `colored` | 2.x | 终端彩色输出 |
| 路径处理 | `dirs` | 6.x | 跨平台路径 |
| LLM调用 | `llm` | 1.3.x | 调用各种大模型服务 |

---

## 10. 项目里程碑

| 阶段 | 内容 | 产出 |
|------|------|------|
| **Phase 1** | 基础框架 | CLI 参数解析、配置加载、基本结构 |
| **Phase 2** | 核心功能 | OpenAI 后端、非流式调用、配置管理 |
| **Phase 3** | 完善功能 | 流式调用、Gemini 后端、模型列表 |
| **Phase 4** | 辅助功能 | 配置初始化、格式转换、错误优化 |
| **Phase 5** | 测试发布 | 单元测试、集成测试、文档完善、发布 |

---

## 11. 总结

本架构设计围绕以下核心原则：

| 原则 | 体现 |
|------|------|
| **模块化** | 清晰的模块划分，职责单一 |
| **可扩展** | Provider trait 抽象，易于新增服务商 |
| **用户友好** | 详细的错误提示、彩色输出、灵活配置 |
| **安全性** | 敏感信息保护、环境变量支持 |
| **鲁棒性** | 全面的错误处理、输入验证 |
| **跨平台** | Windows/macOS/Linux 兼容性处理 |

通过分层架构和模块化设计，**llm-probe** 具备良好的可维护性和可扩展性，能够满足当前需求并为未来功能扩展预留充足空间。


## 参考
https://github.com/graniet/llm/blob/main/examples/openai_example.rs
https://github.com/graniet/llm/blob/main/examples/openai_streaming_example.rs
https://github.com/graniet/llm/blob/main/examples/openai_reasoning_example.rs
https://github.com/graniet/llm/blob/main/examples/anthropic_example.rs
https://github.com/graniet/llm/blob/main/examples/anthropic_streaming_example.rs
https://github.com/graniet/llm/blob/main/examples/anthropic_thinking_example.rs
https://github.com/graniet/llm/blob/main/examples/tool_calling_example.rs
https://docs.rs/llm/latest/llm/backends/index.html
