Files
agcore/design/pdd/15-phase8-mvp-integration.md
徐涛 28ca43ccb2 chore(docs): 将设计文档从 docs 移至 design 目录
将 note、pdd、prd、roadmap 四类文档分别归入 `design/` 下对应子目录中,并新增 `.gitkeep` 占位文件
2026-07-23 05:45:53 +08:00

26 KiB
Raw Permalink Blame History

Phase 8 — MVP 集成出口实现方案

  • 文档编号15
  • 标题Phase 8 — MVP 集成出口实现方案
  • 日期2026-07-05
  • 状态:已定稿
  • 涉及模块:全局(llm/types、agent、tools、memory、prompt、examples
  • 关联文档roadmap.md(§Phase 8)、14-phase7-sqlite-store.md

1. 背景与目标

Phase 5-7 已交付 P0 功能闭环:ProviderConfig from_env()Phase 5)、ToolDef IR 正式化(Phase 6)、SqliteStore 持久化(Phase 7)。当前 200 个测试全绿、clippy 0 警告,但缺乏一个"可被人依赖"的集成出口。

Phase 8 的目标是完成 API 稳定性扫尾 + Quick Start 示例 + 端到端示例,产出 v0.2.0-rc.1 标签。三个 Step 分别对应三类用户群体:

Step 受众 交付物
8.1 存量升级者(v0.1 → v0.2 API 稳定性扫尾 + CHANGELOG
8.2 新用户评估者("30 秒决定要不要用" Quick Start 示例
8.3 技术决策者("这框架能跑真实场景吗") 端到端集成示例

2. 当前状态

度量 数值
cargo test --all-targets 200 passed / 0 failed
cargo clippy --all-targets -- -D warnings 0 警告
已存在 #[non_exhaustive] 枚举 4 个(StopReason / FinishReason / EvictionPolicy / ProviderType
已存在 #[deprecated] 3 个(ChatResponse / ToolDefinition / task_agent_demo 中旧类型使用)
已有示例 8 个
StepStatus::Completed 使用类型 ChatResponse(已 #[deprecated]

2.1 关键技术债

// agent/task.rs —— StepStatus 当前使用已废弃类型
#[allow(deprecated)]
pub enum StepStatus {
    Completed(ChatResponse),   // ← ChatResponse 已在 0.1.0 标记 #[deprecated]
    ...
}

task_agent_demo.rs 中同时使用了 ChatResponse / OpenaiChatMessage / FinishReason 三个废弃类型,入口处有 #![allow(deprecated)]


3. 实施方案

3.1 Step 8.1 — API 稳定性扫尾

拆为 4 个增量 commit

Commit 内容 涉及文件
commit 1 14 个公开枚举追加 #[non_exhaustive] 各枚举定义文件(详见 §3.1.1
commit 2 StepStatus::Completed(ChatResponse)Completed(MessageResponse) + task_agent_demo.rs 清理全部 3 个废弃类型(ChatResponse / OpenaiChatMessage / FinishReason),移除 #![allow(deprecated)] src/agent/task.rsexamples/task_agent_demo.rs
commit 3 CHANGELOG v0.2 条目 + Cargo.toml version → 0.2.0-rc.1 + README 更新 CHANGELOG.mdCargo.tomlREADME.md
commit 4 验证:cargo test + clippy + cargo doc 零告警 无代码改动

3.1.1 #[non_exhaustive] 追加清单(14 个枚举)

按优先级分级:

优先级 枚举 模块路径 理由
P0 核心 Message llm/types/message.rs 核心 IR 类型,未来可能新增变体(MultiModal 扩展)
ContentBlock llm/types/message.rs 同上
ContentBlockType llm/types/message.rs 同上
StreamEvent llm/types/response_v2.rs 流式事件集,Provider 扩展可能新增事件
HookEvent llm/hooks.rs 生命周期钩子,框架扩展需要新增事件点
P0 Error AgentError agent/error.rs 顶层错误,下游 match 需保护
LlmError llm/error.rs LLM 调用错误
ToolError tools/error.rs 工具系统错误
MemoryError memory/error.rs 记忆系统错误
PromptError prompt/error.rs 提示词工程错误
P1 其他 MemoryStrategy memory/conversation.rs 对话策略,未来可扩展(如 Summarize)
StepStatus agent/task.rs 步骤状态机,可扩展(如 Cancelled)
ToolChoice llm/types/request.rs Provider 工具选择策略
ResponseFormat llm/types/shared.rs 响应格式枚举

明确不加的

类别 枚举 原因
内部 wire-format OpenaiChatMessage / OpenaiTool / OpenaiToolCall / ContentField / OpenaiContentPart / LegacyStreamEvent 内部转换层,不构成公共 API 契约
语义稳定 Role / ServiceTier / Modality / ImageDetail / AudioFormat / StopSequence 语义已收敛,协议层无新增变体预期
使用面窄 TemplateValue / Permission / McpTransport / ContentBlockBuilder / ExtraError 内部实现细节或使用频率极低,下游不直接 match

#[non_exhaustive] 的不可逆性:一旦 v0.2.0-rc.1 发布,以下游代码可能依赖 _ => 通配分支。在 v0.3+ 中移除 #[non_exhaustive] 将构成 semver breaking change(新增变体不再触发编译警告,下游 match 可能遗漏新变体),因此当前追加的标记应视为永久 API 契约。

3.1.2 StepStatus 迁移细节

// 变更前
#[allow(deprecated)]
pub enum StepStatus {
    Completed(ChatResponse),   // ChatResponse 已 #[deprecated]
    ...
}

// 变更后
#[non_exhaustive]
pub enum StepStatus {
    Completed(MessageResponse),
    ...
}

字段映射差异MessageResponse 不是 ChatResponse 的简单改名——两者结构不同,迁移需要做字段适配:

ChatResponse 字段 类型 MessageResponse 字段 类型 映射方式
message OpenaiChatMessage message Message 类型替换:OpenaiChatMessage::assistant_text(t)Message::Assistant { content: vec![ContentBlock::Text { text: t.into() }] }
usage Usage usage Usage 同类型,直接迁移
stop_reason Option<FinishReason> stop_reason StopReason 类型替换:Some(FinishReason::Stop)StopReason::Stop;无 Option 包裹
id String 新增必填字段,使用空字符串 "" 占位
model String 新增必填字段,使用 "mock" 或空字符串占位
extra HashMap<String, Value> 新增字段,使用 HashMap::new() 占位

迁移示例task_agent_demo.rs 的构造代码):

// 旧代码(3 个废弃类型)
StepStatus::Completed(ChatResponse {
    message: OpenaiChatMessage::assistant_text("天气:晴,22°C"),
    usage: Usage::from_input_output(10, 5),
    stop_reason: Some(FinishReason::Stop),
})

// 新代码(纯 MessageResponse
StepStatus::Completed(MessageResponse {
    id: String::new(),
    model: "mock".into(),
    message: Message::assistant("天气:晴,22°C"),
    usage: Usage::from_input_output(10, 5),
    stop_reason: StopReason::Stop,
    extra: HashMap::new(),
})

涉及文件:

  • src/agent/task.rs:枚举定义 + #[allow(deprecated)] 移除 + #[non_exhaustive] 追加
  • examples/task_agent_demo.rsChatResponse{...}MessageResponse{...} 构造替换,同时替换 OpenaiChatMessage / FinishReason 引用,移除 #![allow(deprecated)]

3.2 Step 8.2 — Quick Start 示例

属性
文件 examples/quick_start.rs
规模 ~36 行
Provider MockProviderFIFO 单响应队列)
工具 EchoTool(回传 "收到: {input}",完整 JSON Schema 参数声明)
执行 submit_turn("你好") → 验证输出包含 "收到"
验证 cargo run --example quick_start exit 0

设计要点:

  • 展示四层抽象:Agent trait / BaseTool 自定义 / AgentBuilder 装配 / AgentSession 执行
  • 无外部依赖、无 API key、零配置

3.3 Step 8.3 — 端到端示例

属性
文件 examples/end_to_end.rs
规模 ~160 行(最小可行边界:3 工具 + 3 轮 + 持久化验证,防止实施中进一步膨胀)
Provider 自动检测 AG_LLM_*from_env()fallback 到 MockProvider
工具组合 EchoTool(回显)+ CalcTool(四则运算,本地执行)+ NoteTool(笔记,通过 MemoryStore trait 操作 SessionMemory
持久化 tempfile::TempDir + SqliteStoredrop 后重建连接验证数据不丢
对话 3 轮:计算 → 记笔记 → 回忆
验证 cargo run --example end_to_end exit 0(无需任何外部配置)

真实 Provider 切换:示例在文件顶部注释中说明 "设置 AG_LLM_BASE_URL / AG_LLM_API_KEY / AG_LLM_MODEL 环境变量即可使用真实 LLM Provider(支持 OpenAI / Ollama 等);未设置时自动降级为 MockProvider,零配置可运行。"

from_env() 部分环境变量策略from_env() 要求完整的三件套({prefix}_BASE_URL + {prefix}_API_KEY + {prefix}_MODEL)。当环境变量部分设置时,示例整体降级到 MockProvider——不在"半配置"状态下尝试部分初始化。日志输出形如 "AG_LLM_* 环境变量不完整(检测到: {found_vars}),回退到 MockProvider"

架构亮点:

                    ┌─────────────────────────┐
                    │   AgentSession          │
                    │   (submit_turn × 3)     │
                    └────┬──────┬──────┬──────┘
                         │      │      │
                    ┌────┘      │      └──────┐
                    ▼           ▼              ▼
              ┌──────────┐ ┌────────┐ ┌──────────┐
              │ EchoTool │ │CalcTool│ │ NoteTool │
              │ (回显)   │ │(四则)  │ │ (记忆)   │
              └──────────┘ └────────┘ └────┬─────┘
                                           │
                                    ┌──────▼──────┐
                                    │ SessionMemory│
                                    │ (MemoryStore)│
                                    └──────┬──────┘
                                           │
                                    ┌──────▼──────┐
                                    │ SqliteStore  │
                                    │ (temp dir)   │
                                    └─────────────┘

NoteTool 展示 MemoryStore trait 解耦能力:不绑定 SqliteStore,上层 AgentSession 通过 SessionMemory 操作,底层可互换。


4. 否决项记录

否决方案 否决原因
#[non_exhaustive] 仅加 5 个核心类型 全面覆盖 Error enums 为零运行时成本,对下游更友好。Error 枚举是下游 match 最密集的地方,漏标会在 v0.3 引入 breakage
StepStatus::Completed 留到 v0.3 再修 rc.1 前清理 deprecated 类型污染最划算——越晚 migration cost 越高,且当前仅 1 个示例 + 1 个测试引用
Quick Start 纯文本路线(不展示自定义工具) 含 EchoTool 展示核心差异化,仅多 5 行代码但传递了"可以自定义工具"的关键信息
端到端仅 Echo + Calc(无 NoteTool NoteTool 展示 MemoryStore trait 解耦能力是架构亮点,跳过后新用户无法理解 memory 如何集成到 Agent 流程
持久化仅注释说明不实际运行(方案 Y 进程内实操验证(create → drop → reopen → assert)比注释更有说服力,增加约 15 行代码

5. 关键假设

  1. MockProvider FIFO 队列满足 auto-tool-loop 消费顺序MockProvider 的 pop() 按预设顺序弹出。当 LLM 返回多个 tool call 时队列消费顺序与预设一致,无需额外同步
  2. StepStatus 切换需做字段适配ChatResponse(3 字段) 到 MessageResponse(6 字段) 存在字段类型差异(message 类型不同、stop_reason 类型 + Option 有无不同、id/model/extra 为新增必填字段),消费者需按字段映射表提供占位值。但消费者仅 1 个(task_agent_demo.rs)+ 1 个内联测试,手动适配工作量极小。StepStatusis_terminal() / is_pending() 行为不受影响
  3. 所有 10 个示例零外部配置 exit 0:已有 8 个示例已验证,新增 2 个(quick_start + end_to_end)均使用 MockProvider fallback,无需 API key
  4. #[non_exhaustive] × 14 不触发额外 clippy warning:当前无代码对以上枚举做 exhaustive match(不含 _),追加 #[non_exhaustive] 是纯安全标记

6. 实施顺序与验证标准

6.1 提交顺序

Step 8.1 (4 commits)
  → commit 1: #[non_exhaustive] × 14
  → commit 2: StepStatus 修复(Completed(ChatResponse) → Completed(MessageResponse)
  → commit 3: CHANGELOG v0.2 + Cargo.toml version 0.2.0-rc.1 + README 更新
  → commit 4: 验证(test / clippy / doc 零告警)

Step 8.2
  → commit 5: examples/quick_start.rs~36 行)

Step 8.3
  → commit 6: examples/end_to_end.rs~160 行)

最终验证
  → cargo test --all-targets
  → cargo clippy --all-targets -- -D warnings
  → cargo doc --no-deps
  → git tag v0.2.0-rc.1

6.2 验收标准

指标 要求
cargo test --all-targets 全绿
cargo clippy --all-targets -- -D warnings 0 警告
cargo doc --no-deps 0 warning
所有 10 个示例 cargo run --example <name> exit 0
Cargo.toml version 0.2.0-rc.1
CHANGELOG v0.2 条目完整(Added / Changed / Deprecated / Fixed / Removed 各节)
README 示例列表 + 版本号更新
git tag v0.2.0-rc.1

7. 参考来源

  • roadmap.md — Phase 8 原始定义(Step 8.1/8.2/8.3)、依赖关系(Phase 5/6/7 → Phase 8
  • src/agent/task.rsStepStatus 当前实现,Completed(ChatResponse) 类型
  • src/llm/types/message.rsMessage / ContentBlock / ContentBlockType 枚举定义
  • src/llm/types/response_v2.rsStreamEvent / StopReason 枚举定义(StopReason 已有 #[non_exhaustive]
  • src/llm/types/shared.rsResponseFormat / Role / FinishReason 等枚举(FinishReason 已有 #[non_exhaustive]
  • src/llm/types/request.rsToolChoice 枚举定义
  • src/llm/hooks.rsHookEvent 枚举定义
  • src/llm/error.rsLlmError 枚举定义
  • src/agent/error.rsAgentError 枚举定义
  • src/tools/error.rsToolError 枚举定义
  • src/memory/error.rsMemoryError 枚举定义
  • src/memory/conversation.rsMemoryStrategy 枚举定义
  • src/prompt/error.rsPromptError 枚举定义
  • examples/task_agent_demo.rs — 当前使用 #[allow(deprecated)] + ChatResponse 的示例

8. 实施计划

8.1 实施步骤

Step 8.1 — API 稳定性扫尾

拆为 4 个增量 commit,依次提交。

commit 1: #[non_exhaustive] × 14
属性
涉及文件 14 个枚举定义所在文件(见下方清单)
前置依赖
预估工作量 S<1h
风险等级

在每个目标枚举定义处的 pub enum 之前加一行 #[non_exhaustive],纯文本属性追加,无逻辑变更。

目标枚举 文件路径 行号附近
Message src/llm/types/message.rs pub enum Message (L22)
ContentBlock src/llm/types/message.rs pub enum ContentBlock (L99)
ContentBlockType src/llm/types/message.rs pub enum ContentBlockType (L134)
StreamEvent src/llm/types/response_v2.rs pub enum StreamEvent (L167)
HookEvent src/llm/hooks.rs pub enum HookEvent (L9)
AgentError src/agent/error.rs pub enum AgentError (L20)
LlmError src/llm/error.rs pub enum LlmError (L10)
ToolError src/tools/error.rs pub enum ToolError (L6)
MemoryError src/memory/error.rs pub enum MemoryError (L8)
PromptError src/prompt/error.rs pub enum PromptError (L3)
MemoryStrategy src/memory/conversation.rs pub enum MemoryStrategy (L14)
StepStatus src/agent/task.rs pub enum StepStatus (L59)
ToolChoice src/llm/types/request.rs pub enum ToolChoice (L14)
ResponseFormat src/llm/types/shared.rs pub enum ResponseFormat (L70)

注意StepStatus 在 commit 2 中会同时被修改(variant 类型替换 + 移除 #[allow(deprecated)])。commit 1 仅追加 #[non_exhaustive] 属性,commit 2 再处理变体变更和清理。

验收条件cargo build --all-targets 通过

commit 2: StepStatus 修复 + 废弃类型清理
属性
涉及文件 src/agent/task.rsexamples/task_agent_demo.rs
前置依赖 commit 1StepStatus 先标记 #[non_exhaustive],此处改 variant 时一并保留,无实际冲突)
预估工作量 S<1h,约 20 行改动)
风险等级

两步操作:

  1. src/agent/task.rsL59-L71):

    • StepStatus::Completed(ChatResponse)Completed(MessageResponse)
    • 移除 #[allow(deprecated)](第 13、59 行两处)
  2. examples/task_agent_demo.rs

    • 替换 3 个废弃类型:ChatResponseMessageResponseOpenaiChatMessage::assistant_text(t)Message::assistant(t)FinishReason::StopStopReason::Stop
    • 补充 id: String::new()model: "mock".into()extra: HashMap::new() 占位字段
    • 移除 #![allow(deprecated)](第 26 行)
    • 移除 use 中的 ChatResponseOpenaiChatMessageFinishReason
    • 添加 use std::collections::HashMapuse agcore::llm::types::{Message, MessageResponse, StopReason}(注意:Message::assistant_text(t) 不存在,需使用 Message::assistant(t))

字段映射参见 §3.1.2 的字段映射表和迁移示例。

验收条件cargo build --all-targets 通过,零 deprecated warning

commit 3: CHANGELOG + 版本号 + README
属性
涉及文件 CHANGELOG.mdCargo.tomlREADME.md
前置依赖 commit 1+2CHANGELOG 需记录实际变更)
预估工作量 S<1h
风险等级
  1. CHANGELOG.md:新增 [0.2.0-rc.1] 条目,包含:

    • AddedSqliteStore 持久化 / OllamaProvider / ProviderConfig::from_env / ToolDef IR / Quick Start 和 end_to_end 示例
    • ChangedMessageRequest.tools 切换 ToolDef / StepStatus::Completed 类型替换
    • DeprecatedChatResponse / with_system_prompt() / with_client()
    • Non-exhaustive14 个枚举标记清单
  2. Cargo.toml:第 3 行 version = "0.1.0"version = "0.2.0-rc.1"

  3. README.md:更新示例列表从 7 个改为 10 个(含新增 2 个),版本号同步

验收条件:人工 review CHANGELOG + git diff 确认版本号

commit 4: 验证
属性
涉及文件 无代码改动
前置依赖 commit 3
预估工作量 S<1h,主要等待编译)
风险等级

运行三条命令:

cargo test --all-targets
cargo clippy --all-targets -- -D warnings
cargo doc --no-deps 2>&1 | grep "^warning:" && echo "WARNINGS FOUND" || echo "0 warnings"

验收条件:前两条 0 错误,第三条输出 0 warnings

Step 8.2 — Quick Start 示例

commit 5: examples/quick_start.rs
属性
涉及文件 examples/quick_start.rs
前置依赖 无(可从 Phase 7 独立创建)
预估工作量 S<1h
风险等级

新文件 examples/quick_start.rs~36 行,结构如下:

 1- 6   use 块(agcore 类型 + Arrow/std 类型)
 7- 8   struct Greeter + impl Agentname / system_prompt
 9-14   struct EchoTool + #[async_trait] impl BaseTool(完整 JSON Schema 带 text 参数)
15-20   fn mock_response() -> MessageResponse 辅助函数(构造纯文本响应)
21-33   #[tokio::main] async fn main():
          - ToolRegistry::new() + register EchoTool
          - MockProvider 预设 1 条 mock_response
          - AgentBuilder::new() + provider + tool_registry + hook_executor → build
          - AgentSession::new + submit_turn("你好")
          - println!("{}", response.text())

设计约束

  • EchoTool 的 parameters() 返回完整 JSON Schema{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}
  • 无外部依赖、无 API key、零配置
  • 展示四层抽象:Agent trait / BaseTool 自定义 / AgentBuilder 装配 / AgentSession 执行

验收条件cargo run --example quick_start exit 0,输出包含 "收到"

Step 8.3 — 端到端示例

commit 6: examples/end_to_end.rs
属性
涉及文件 examples/end_to_end.rs
前置依赖 commit 5(示例编写模式已建立);SqliteStorePhase 7 已完成)
预估工作量 M1-4h
风险等级

新文件 examples/end_to_end.rs,~160 行,最小可行边界(3 工具 + 3 轮 + 持久化验证)。

Provider 初始化策略

if env::var("AG_LLM_BASE_URL").is_ok() && env::var("AG_LLM_API_KEY").is_ok() {
    // 使用真实 ProviderAG_LLM_MODEL 非必填,from_env 内部会处理默认值)
    let provider: Arc<dyn LlmProvider> = Arc::from(create_provider(
        ProviderType::OpenaiChat, ProviderConfig::from_env("AG_LLM").unwrap()
    )?);
} else {
    // MockProvider fallback,预设 4 条响应序列
    let found = ["AG_LLM_BASE_URL", "AG_LLM_API_KEY"].iter()
        .filter(|k| env::var(k).is_ok()).collect::<Vec<_>>();
    eprintln!("AG_LLM_* 环境变量不完整(检测到: {:?}),回退到 MockProvider", found);
}

工具定义

工具 功能 关键技术点
EchoTool 回显输入 基础工具注册模式
CalcTool 本地执行四则运算 手动解析算术表达式(ponytail:基础 +-*/ 运算无需引入 rhai 依赖)
NoteTool 通过 MemoryStore trait 读写笔记 直接持有 Arc<dyn MemoryStore>key 前缀 "note:"save 用 MemoryStore::save(MemoryItem { id: "note:{key}", content, .. })query 用 MemoryStore::list(MemoryFilter { prefix: Some("note:"), .. })

持久化验证

let dir = tempfile::TempDir::new()?;
let db_path = dir.path().join("agcore.db");
let backend = Arc::new(SqliteStore::open(&db_path)?);
// ... 构建 RuntimeBundle + AgentSession,写入数据 ...
drop(bundle);   // 释放所有对 backend 的 Arc 引用
drop(session);
// 此时 backend 无活跃引用,SQLite 连接自动关闭
let backend2 = Arc::new(SqliteStore::open(&db_path)?);  // 重建连接
// assert 数据仍在

输出示范

=== agcore 端到端演示 ===
🔄 Provider: MockProvider (离线回退模式)
💾 SqliteStore: /tmp/agcore_XXXXX/agcore.db
🔧 注册工具: echo, calc, note

第 1 轮 用户: 帮我算 25 * 4
  → 调用 calc(...) → 100
  → 回答: 25 * 4 = 100

第 2 轮 用户: 记下来:结果是 100
  → 调用 note(save, ...)
  → 回答: 已记录

第 3 轮 用户: 我刚才算了什么?
  → 调用 note(query)
  → 回答: 您刚才的计算结果是 100

📊 用量: prompt=XX, completion=XX

=== 持久化验证 ===
✓ 跨连接数据存活验证通过

✓ 端到端演示完成

设计约束

  • 文件顶部注释说明 AG_LLM_* 环境变量切换真实 Provider
  • 零外部配置可运行(Mock fallback
  • 最小可行边界:3 工具 + 3 轮 + 持久化验证,不膨胀

验收条件cargo run --example end_to_end exit 0(零外部配置)

8.2 并行机会

commit 1 和 commit 5 可以并行执行(零文件重叠)。commit 5 也可与 commit 2 并行。commit 6 实质上也仅依赖「代码库状态稳定」而非某个具体 commit。

并行组 commit A commit B 前提
1 commit 1#[non_exhaustive] commit 5Quick Start 零文件重叠
2 commit 2StepStatus 修复) commit 5Quick Start 零文件重叠
3 commit 5Quick Start commit 6(端到端) 零文件重叠,但存在知识依赖——commit 6 需参考 commit 5 的 MessageResponse 构造、MockProvider 用法、AgentBuilder 装配模式。推荐 commit 5 先行或实施前同步这些模式

8.3 风险与应对

风险 影响 可能性 应对
MockProvider 响应序列与 tool-loop 消费顺序不匹配 commit 6 端到端示例不通过 按 §5 假设 1:设计响应队列时确保每条 Mock 响应的 stop_reason 与 ToolUse/Stop 匹配。出现不匹配时改用完整 MessageResponse 构造显式控制
NoteTool 与 AgentSession 的数据传递路径需要扩展现有 API commit 6 需要修改 session.rs ponytail 方案:NoteTool 直接持有 Arc<dyn MemoryStore> 引用,在 execute 时直接操作 MemoryStore::save/get,绕过 AgentSession 的 session_memory 封装
#[non_exhaustive] 在某个 enum 上导致 crate 内 match 编译失败 commit 1 不通过 实施前先运行 `rg "match.*(Message

8.4 测试策略

commit 测试 方式
commit 1 编译测试 cargo build --all-targets
commit 2 编译 + 单测 + 无 deprecated warning cargo build --all-targets && cargo test
commit 3 人工 review git diff
commit 4 全量自动化 cargo test + clippy + doc
commit 5 示例运行 cargo run --example quick_start
commit 6 示例运行 cargo run --example end_to_end
最终 全量回归 全部三项 + 所有 10 个示例