# 开发指南 ## 环境要求 - Rust **1.95.0+**(见 `rust-toolchain.toml`) - Bun **1.3+**(Web 面板构建与开发) - `cmake`、`g++`、`libclang-dev`(编译 `wreq` 依赖的 BoringSSL) - `just` 命令运行器(用于 `just serve` / `just check` 等快捷命令) ## 首次启动 ```bash # 1. 复制配置 cp config.example.toml config.toml # 2. 构建 Web 前端(编译时嵌入二进制,每次前端变更需要重构建) cd web && bun install && bun run build && cd .. # 3. 运行开发服务器 just serve ``` 服务器启动后访问 `http://localhost:22217` 自动跳转到管理面板。 > **前端热更新开发**:同时运行 `cd web && bun run dev`(Vite HMR 模式) > 和 `just serve`,后端优先使用文件系统 `web/dist/` 目录中的静态文件。 > 无需每次前端改动都重构建二进制。 ## Release 构建 ```bash # 1. 构建 Web 前端 cd web && bun install && bun run build && cd .. # 2. 构建 Release 二进制 cargo build --release # 3. 运行(也可直接运行二进制,无需 web/dist/ 目录) ./target/release/ds-free-api ``` Release 二进制通过 `rust_embed` 编译时嵌入前端资源,`web/dist/` 目录不存在时 自动使用嵌入资源。发布版无需额外文件。 ## CI 自动构建 GitHub Actions(`.github/workflows/release.yml`)在 tag push 时自动执行: ``` build-frontend (bun install --frozen-lockfile + bun run build) ├── build-linux-gnu (cargo build) │ ├── build-linux-musl (musl-cross) │── release (tar.gz + zip) ├── build-macos (cargo build) │ └── build-windows (cargo build)│ └── docker (ghcr.io image) ``` `build-frontend` 产出 `web-dist` artifact,各编译 job 下载后再执行 `cargo build` / `cross build`,保证 `rust_embed` 嵌入真实前端文件。 Docker 镜像自动推送到 `ghcr.io/niyueee/ds-free-api:latest`。 ## Docker 部署(生产) 从 ghcr.io 拉取(推荐): ```bash # 确认已创建 docker/config/ 目录(自动创建或手动 mkdir) docker compose -f docker/docker-compose.yaml up -d ``` 容器首次启动时自动创建最小配置,无需提前准备 `config.toml`。 配置和数据通过 bind mount 持久化到宿主机的 `docker/config/` 和 `docker/data/`。 从源码构建本地 Docker 镜像: ```bash # 1. 构建前端 + 交叉编译二进制 cd web && bun install && bun run build && cd .. cargo zigbuild --release --target x86_64-unknown-linux-gnu # 2. 构建 Docker 镜像 docker build -f docker/Dockerfile -t ds-free-api . # 3. 导出并传输到服务器 docker save ds-free-api | gzip > ds-free-api.tar.gz scp ds-free-api.tar.gz user@server:/tmp/ # 4. 服务器加载并启动 ssh user@server docker load < /tmp/ds-free-api.tar.gz docker compose -f docker/docker-compose.yaml up -d ``` > 服务器原生 x86 环境可直接在服务器上执行上述构建,速度更快。 > Docker 镜像仅包含预编译二进制 + 嵌入的前端资源,无需在容器内编译。 ## 命令参考 ```bash # 一键检查(check + clippy + fmt + audit + unused deps) just check # 运行测试 cargo test --lib # 运行 HTTP 服务 just serve # 统一协议调试 CLI(内置对话/比较/并发等模式) just adapter-cli # 使用 e2e 专属配置启动服务 just e2e-serve ``` ## e2e 测试 `py-e2e-tests/` 是基于 JSON 场景驱动的端到端测试框架,无需 pytest 依赖。分为三层: | 层级 | 命令 | 覆盖范围 | | ---------- | ----------------- | ----------------------------------------------------- | | **Basic** | `just e2e-basic` | 基础功能场景(双端点 OpenAI + Anthropic),安全并发数 | | **Repair** | `just e2e-repair` | 工具调用异常格式修复专项(OpenAI 单端点),安全并发数 | | **Stress** | `just e2e-stress` | 全部场景 × 3 次迭代,安全并发数 + 1 并发 | 先启动服务端: ```bash just e2e-serve ``` 再在另一个终端运行 e2e 测试: ```bash # 基础场景测试 just e2e-basic # 工具修复测试 just e2e-repair ``` 场景文件在 `scenarios/` 中按类型独立存放: ``` py-e2e-tests/ ├── scenarios/ │ ├── basic/ │ │ ├── openai/ # 7 个基础场景(对话、推理、流式、工具调用、文件上传、图片上传、HTTP链接) │ │ └── anthropic/ # 7 个基础场景(对话、推理、流式、工具调用、文档上传、图片上传、HTTP链接) │ └── repair/ # 10 个工具损坏格式场景 ├── runner.py # 单次运行入口 ├── stress_runner.py # 多迭代压测入口 └── config.toml # e2e 专用服务端配置 ``` 每个场景为独立 JSON 文件,包含请求参数和校验规则: ```json { "name": "场景名称", "endpoint": "openai|anthropic", "category": "basic|repair", "models": ["deepseek-default", "deepseek-expert", "deepseek-vision"], "messages": [{"role": "user", "content": "..."}], "tools": [...], "tool_choice": "auto", "request": {"stream": false}, "checks": { "has_tool_calls": true, "tool_names": ["get_weather"], "finish_reason": "tool_calls", "no_error": true } } ``` ### e2e CLI 参数 **`just e2e-basic` 和 `just e2e-repair`(单次运行):** | 参数 | 作用 | |------|------| | `scenario_dir` | 场景目录,如 `scenarios/basic` 或 `scenarios/repair` | | `--endpoint` | 端点过滤:`openai` / `anthropic` | | `--model` | 模型过滤:`deepseek-default` / `deepseek-expert` | | `--filter` | 场景名称关键字过滤(多个用空格分隔,如 `--filter 文件 图片`)| | `--parallel` | 并行数,默认 `账号数 ÷ 2` | | `--show-output` | 显示模型回复摘要、工具调用、结束原因 | | `--report` | 输出 JSON 报告路径 | **`just e2e-stress`(压测):** | 参数 | 作用 | |------|------| | `--iterations` | 每场景迭代次数,默认 3 | | `--models` | 模型列表过滤 | | `--filter` | 场景名称关键字过滤(多个用空格分隔)| | `--parallel` | 并行数,默认 `账号数 ÷ 2 + 1` | | `--show-output` | 显示模型输出 | | `--report` | 输出 JSON 报告路径 | 使用示例: ```bash # 快速验证新加的文件上传场景 just e2e-basic --filter 文件 图片 --show-output # 仅查看 OpenAI 端点的 expert 模型 just e2e-basic --endpoint openai --model deepseek-expert # 串行调试 just e2e-basic --endpoint openai --parallel 1 --show-output # 压测:工具调用修复场景 × 5 次迭代 just e2e-stress --filter 修复 --iterations 5 # 输出 JSON 报告 just e2e-basic --report result.json ``` ## 更多文档 - [代码规范](code-style.md) - [日志规范](logging-spec.md) - [Prompt 注入策略](deepseek-prompt-injection.md)