Files
aha/docs/development.zh-CN.md
T
XiaoYang c582c4cd0a docs: update and optimize README and project documentation system
- Update README.md with improved formatting, logo, badges,
  and comprehensive documentation
- Add README.en.md with English translation of the documentation
- Include detailed quick start guide, CLI reference,
  and supported models table
- Add changelog information highlighting recent features
- Add script directory and adjust script file locations
2026-02-06 16:13:50 +08:00

12 KiB
Raw Blame History

开发指南

本指南涵盖为 AHA 做贡献,包括开发设置、添加新模型和提交贡献。

目录

开发设置

前置要求

  • Rust 1.85+ (edition 2024)
  • Git
  • 可选:CUDA Toolkit、Metal、FFmpeg(用于功能开发)

克隆和构建

# 克隆仓库
git clone https://github.com/jhqxxx/aha.git
cd aha

# 调试模式构建(编译更快)
cargo build

# 发布模式构建(性能更好)
cargo build --release

# 使用功能构建
cargo build --features "cuda,flash-attn"
cargo build --features "metal"
cargo build --features "ffmpeg"

开发工作流程

# 运行 CLI
cargo run -- -m qwen3-0.6b

# 运行测试
cargo test

# 运行特定测试
cargo test test_qwen3vl_generate

# 启用日志运行
RUST_LOG=debug cargo run -- -m qwen3-0.6b

# 检查代码而不构建
cargo check

# 格式化代码
cargo fmt

# 运行 linter
cargo clippy

项目结构

aha/
├── Cargo.toml              # 构建配置
├── src/
│   ├── main.rs             # CLI 入口点
│   ├── lib.rs              # 库导出
│   ├── api.rs              # HTTP API 处理程序
│   ├── exec/               # CLI 命令实现
│   │   ├── mod.rs
│   │   ├── cli.rs
│   │   ├── serv.rs
│   │   ├── download.rs
│   │   └── run.rs
│   ├── models/             # 模型实现
│   │   ├── mod.rs          # 模型工厂和导出
│   │   ├── common/         # 共享模型工具
│   │   │   ├── config.rs
│   │   │   └── mod.rs
│   │   ├── qwen3vl/        # Qwen3-VL 模型
│   │   │   ├── config.rs
│   │   │   ├── model.rs
│   │   │   ├── generate.rs
│   │   │   ├── processor.rs
│   │   │   └── mod.rs
│   │   ├── voxcpm/         # VoxCPM 模型
│   │   └── ...             # 其他模型
│   ├── tokenizer/          # 分词工具
│   ├── chat_template/      # 聊天模板处理
│   ├── position_embed/     # 位置编码
│   └── utils/              # 工具函数
│       ├── audio_utils.rs
│       ├── image_utils.rs
│       ├── download.rs
│       └── common.rs
├── tests/                  # 集成测试
│   ├── test_qwen2_5vl.rs
│   ├── test_qwen3vl.rs
│   └── ...
├── examples/               # 示例代码
└── docs/                   # 文档

添加新模型

本节提供了向 AHA 添加新模型的分步指南。

步骤 1:创建模型目录

src/models/ 下创建新目录:

mkdir -p src/models/newmodel

步骤 2:实现模型文件

src/models/newmodel/ 中创建以下文件:

config.rs

定义模型配置:

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct NewModelConfig {
    pub vocab_size: usize,
    pub hidden_size: usize,
    pub num_hidden_layers: usize,
    pub num_attention_heads: usize,
    // ... 其他配置字段
}

impl Default for NewModelConfig {
    fn default() -> Self {
        Self {
            vocab_size: 32000,
            hidden_size: 2048,
            num_hidden_layers: 24,
            num_attention_heads: 32,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerationConfig {
    pub temperature: f64,
    pub top_p: f64,
    pub max_tokens: usize,
}

impl Default for GenerationConfig {
    fn default() -> Self {
        Self {
            temperature: 1.0,
            top_p: 1.0,
            max_tokens: 100,
        }
    }
}

model.rs

实现模型架构:

use candle::{Result, Tensor};
use candle_nn::{Module, VarBuilder};

use super::config::NewModelConfig;

pub struct NewModel {
    // 定义模型组件
    config: NewModelConfig,
}

impl NewModel {
    pub fn load(vb: VarBuilder, config: &NewModelConfig) -> Result<Self> {
        // 加载模型权重
        Ok(Self {
            config: config.clone(),
        })
    }

    pub fn forward(&self, input_ids: &Tensor) -> Result<Tensor> {
        // 实现前向传播
        Ok(input_ids.clone())
    }
}

generate.rs

实现 GenerateModel trait

use std::path::Path;
use anyhow::Result;
use candle::Device;

use super::config::{GenerationConfig, NewModelConfig};
use aha::models::common::GenerateModel;

pub struct NewModelGenerate {
    // 定义生成状态
    model: super::model::NewModel,
    config: GenerationConfig,
    device: Device,
}

impl GenerateModel for NewModelGenerate {
    type Config = NewModelConfig;
    type GenerateConfig = GenerationConfig;

    fn init(
        model_path: &str,
        config: Option<Self::Config>,
        generate_config: Option<Self::GenerateConfig>,
    ) -> Result<Self> {
        // 从磁盘加载模型
        let device = Device::Cpu;
        let config = config.unwrap_or_default();
        let generate_config = generate_config.unwrap_or_default();

        // 加载权重
        let model_path = Path::new(model_path);
        // ... 加载模型实现

        Ok(Self {
            model: todo!(),
            config: generate_config,
            device,
        })
    }

    fn generate(&mut self, prompt: &str) -> Result<String> {
        // 分词提示
        // 运行推理
        // 解码输出
        Ok(prompt.to_string())
    }
}

processor.rs(可选)

对于具有多模态输入的复杂模型:

use anyhow::Result;

pub struct NewModelProcessor {
    // 处理状态
}

impl NewModelProcessor {
    pub fn new() -> Self {
        Self {}
    }

    pub fn process_text(&self, text: &str) -> Result<Vec<String>> {
        // 处理文本输入
        Ok(vec![text.to_string()])
    }

    pub fn process_image(&self, image_path: &str) -> Result<Tensor> {
        // 处理图像输入
        todo!()
    }
}

mod.rs

导出模型:

mod config;
mod model;
mod generate;
pub mod processor;

pub use generate::NewModelGenerate;
pub use config::{GenerationConfig, NewModelConfig};

步骤 3:注册模型

更新 src/models/mod.rs

// 添加到导入
pub mod newmodel;

// 添加到 WhichModel 枚举
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
pub enum WhichModel {
    // ... 现有模型
    NewModel,
}

// 添加到模型加载
pub fn load_model(
    model_type: &WhichModel,
    model_path: &str,
    device: &Device,
) -> Result<Box<dyn common::GenerateModel>> {
    match model_type {
        // ... 现有模型
        WhichModel::NewModel => {
            Ok(Box::new(newmodel::NewModelGenerate::init(model_path, None, None)?))
        }
    }
}

步骤 4:更新 CLI

更新 src/main.rs 以在帮助文本和 CLI 选项中包含新模型(如果需要)。

步骤 5:添加测试

创建 tests/test_newmodel.rs

use anyhow::Result;

#[test]
fn test_newmodel_generate() -> Result<()> {
    let model_path = "path/to/test/model";
    let mut model = aha::models::newmodel::NewModelGenerate::init(model_path, None, None)?;
    
    let result = model.generate("测试提示")?;
    assert!(!result.is_empty());
    
    Ok(())
}

步骤 6:更新文档

更新以下文件:

  • README.md - 将模型添加到支持的模型列表
  • docs/cli.md - 将模型 ID 添加到模型列表
  • docs/api.md - 将模型添加到支持的模型部分
  • CHANGELOG.md - 为新模型添加条目

测试

单元测试

# 运行所有测试
cargo test

# 运行特定测试
cargo test test_newmodel_generate

# 启用输出运行
cargo test -- --nocapture

# 并行运行测试
cargo test -- --test-threads=4

集成测试

集成测试位于 tests/ 中:

# 运行特定集成测试
cargo test --test test_qwen3vl

手动测试

手动测试 CLI 和 API

# 测试 CLI
cargo run -- -m newmodel

# 测试 API
cargo run -- -m newmodel -p 8080
curl http://127.0.0.1:8080/chat/completions -d '{...}'

模型特定测试

每个模型都应该有涵盖以下内容的测试:

  • 模型加载
  • 基本推理
  • 边缘情况
  • 错误处理

代码风格

格式化

# 格式化所有代码
cargo fmt

# 检查格式化而不进行更改
cargo fmt --check

Linting

# 运行 clippy
cargo clippy

# 修复 clippy 警告
cargo clippy --fix

约定

  • 使用 4 个空格缩进
  • 对于错误,优先使用 Result<T> 而不是 Option<T>
  • 对于应用程序错误使用 anyhow::Result
  • 使用 rustdoc 注释记录公共 API
  • 保持函数专注和小型
  • 使用有意义的变量名

文档

/// 使用 NewModel 生成文本。
///
/// # 参数
///
/// * `prompt` - 输入提示文本
/// * `max_tokens` - 要生成的最大令牌数
///
/// # 返回
///
/// 生成的文本作为字符串
///
/// # 示例
///
/// ```no_run
/// let result = model.generate("你好")?;
/// ```
pub fn generate(&mut self, prompt: &str) -> Result<String> {
    // 实现
}

提交贡献

Pull Request 流程

  1. Fork 仓库
  2. 创建功能分支:
    git checkout -b feature/new-model
    
  3. 进行更改
  4. 添加测试
  5. 更新文档
  6. 确保所有测试通过:
    cargo test
    cargo clippy
    cargo fmt --check
    
  7. 提交并推送:
    git commit -m "添加 NewModel 支持"
    git push origin feature/new-model
    
  8. 在 GitHub 上创建 pull request

Pull Request 清单

  • 已添加/更新测试
  • 已更新文档
  • 已更新 CHANGELOG.md
  • 代码已格式化(cargo fmt
  • 已修复 Clippy 警告(cargo clippy
  • 所有测试通过(cargo test
  • 提交消息遵循约定

提交消息约定

遵循约定式提交:

feat: 添加 NewModel 支持
fix: 修正 Qwen3VL 中的张量维度
docs: 更新安装指南
test: 添加 VoxCPM 集成测试
refactor: 简化模型加载逻辑
perf: 将推理速度提高 20%

发布流程

版本升级

更新 Cargo.toml

[package]
version = "0.1.9"  # 升级版本

更新变更日志

将条目添加到 CHANGELOG.md

## [0.1.9] - 2025-02-06

### 新增
- NewModel 支持

### 修复
- 图像处理中的内存泄漏

### 更改
- 改进错误消息

创建发布

# 标记发布
git tag -a v0.1.9 -m "Release v0.1.9"
git push origin v0.1.9

# 构建发布产物
cargo build --release

# 发布到 crates.io(如果适用)
cargo publish

调试

日志

启用调试日志:

RUST_LOG=debug cargo run -- -m qwen3-0.6b

设置特定模块日志:

RUST_LOG=aha::models::qwen3vl=debug cargo run -- -m qwen3-0.6b

调试测试

# 打印测试输出
cargo test -- --nocapture

# 显示回溯
RUST_BACKTRACE=1 cargo test

常见问题

构建错误

  • 链接错误:安装所需的系统依赖
  • CUDA 错误:确保已安装 CUDA toolkit
  • Metal 错误:检查您是否在 Apple Silicon 上

运行时错误

  • 未找到模型:检查模型路径和下载
  • 内存不足:使用更小的模型或启用 GPU
  • 推理速度慢:启用 GPU 加速

资源

另见