# 教程:从零启动平台 ## 1. 同步依赖 ```bash uv sync ``` ## 2. 初始化数据库 ```bash ./scripts/init_db.sh ``` 该命令会升级到最新结构,并在不存在时创建管理员 `gly`,初始密码 `maxta2026`。命令可重复执行,不会覆盖已有 `gly` 的密码。 ## 3. 设置初始 `.env` 首次启动至少确认: - TARGET_BASE_URL - TARGET_MODEL - TARGET_AUTH_TYPE - TARGET_API_KEY - JUDGE_BASE_URL - JUDGE_MODEL - JUDGE_API_KEY 这些值是数据库尚无对应角色记录时的回退配置。启动并登录后,可改用 provider CRUD 持久化管理,无需重启。 ## 4. 启动服务 ```bash uv run uvicorn app.main:app --workers 1 ``` 当前运行调度使用进程内状态,必须保持单进程。仅本地开发需要热重载时使用 `uv run uvicorn app.main:app --reload`;不要配置多个 worker,也不要同时启动多个服务进程。 ## 5. 创建并登录用户 先设置 `AUTH_TOKEN_SECRET`(生产环境必须是随机长密钥),再使用初始化生成的管理员登录: ```bash curl -X POST http://127.0.0.1:8000/api/v1/auth/login \ -H 'Content-Type: application/json' \ -d '{"username":"gly","password":"maxta2026"}' ``` 除 `GET /api/v1/health` 和登录接口外,所有 `/api/v1/*` 请求都必须带上登录返回的令牌: ```bash curl http://127.0.0.1:8000/api/v1/providers/target/models \ -H 'Authorization: Bearer ' ``` Swagger 也可直接测试:打开 `/docs` 后,点击右上角 **Authorize**,在 `BearerAuth` 输入框粘贴登录响应里的 `access_token`(只粘贴令牌本身,不要手动写 `Bearer `),点击 Authorize 和 Close。之后所有带锁的接口会自动 携带 `Authorization: Bearer `;令牌过期或登出后,重新登录并重复该步骤。 管理员可管理用户:`POST /api/v1/auth/users` 创建用户,`GET /api/v1/auth/users` 列表, `PATCH /api/v1/auth/users/{id}` 启用或禁用用户,`DELETE /api/v1/auth/users/{id}` 永久删除用户。普通用户调用这些接口会得到 403;当前登录管理员不能禁用或删除自己。 已登录用户可用 `GET /api/v1/auth/me` 查看自己的账号和管理员标志。首次登录后立即调用 `PATCH /api/v1/auth/password`,提交 `{"current_password":"maxta2026","new_password":"至少8位的新密码"}` 修改本人密码。成功返回 204,并使本人所有旧令牌失效,随后用新密码重新登录。管理员仍可用 `PATCH /api/v1/auth/users/{id}/password` 无需旧密码地重置他人密码。 登出调用 `POST /api/v1/auth/logout`,被撤销的令牌会立即无法再访问 API。 管理员还可管理模型提供商配置:`POST /api/v1/providers` 创建,`GET /api/v1/providers` 与 `GET /api/v1/providers/{provider_id}` 查询,`PATCH /api/v1/providers/{provider_id}` 局部更新, `DELETE /api/v1/providers/{provider_id}` 删除。`provider_id` 是 `target` 或 `judge`;API Key 只在写入时提交,响应仅返回 `api_key_configured`。PATCH 未提供 `api_key` 时保留原密钥。 `GET /api/v1/providers` 始终返回当前生效的 `target` 与 `judge`:`source=env` 表示来自 `.env`, `source=database` 表示数据库记录覆盖了该角色的环境变量。 ## 6. 打开文档 - Swagger: `http://127.0.0.1:8000/docs` - ReDoc: `http://127.0.0.1:8000/redoc` - OpenAPI JSON: `http://127.0.0.1:8000/openapi.json` ## 7. 推荐调用顺序 1. `GET /api/v1/health` 2. `GET /api/v1/providers`(确认每个角色的 `source` 与密钥配置状态) 3. `GET /api/v1/providers/judge/models` 4. `POST /api/v1/providers/target/check` 5. `POST /api/v1/runs`(新 Run 内部先执行并保存能力探测结果) 6. `GET /api/v1/runs` 7. `GET /api/v1/runs/{run_id}` 8. `GET /api/v1/runs/{run_id}/results` 9. `GET /api/v1/reports` 10. `GET /api/v1/reports/{run_id}` 创建运行的网络重试应复用同一个 `Idempotency-Key` 请求头;同一键与同一请求只会创建一个运行。 若服务中断,确认原进程已停止后调用 `POST /api/v1/runs/{run_id}/resume`;已保存的能力探测结果和题目不会重复执行。 若终态是 `completed_with_errors`,调用 `POST /api/v1/runs/{run_id}/retry-errors`:成功结果保持不变,仅重跑 `execution_status=error` 的样例。逐条结果的 `verdict=fail` 是仲裁结论,不计入 Run 的 `error_count`,也不会被该接口重试。 若只需重跑某条已有结果,在 Run 进入 `completed` 或 `completed_with_errors` 后调用 `POST /api/v1/runs/{run_id}/results/{execution_id}/retry`,然后继续轮询该 Run。 ## 8. 创建并跟踪一次测试 `smoke` 最多执行 1 条单轮题;`all` 执行目标模型实际支持的全部题目。`auto_judge=false` 时仍会保存被测模型原始回复,但不会生成自动裁判结论。 ```bash curl -X POST http://127.0.0.1:8000/api/v1/runs \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -H 'Idempotency-Key: a-new-unique-key' \ -d '{"profile":"smoke","auto_judge":true}' ``` 新 Run 先探测并持久化基础能力,再按案例所需能力的交集筛选并异步执行;同一 Run 的恢复和重试复用探测结果。含 system 上下文或结构化附件的案例要求 `system_message`。响应中的 `selected_count` 初始为 `0`;使用 `GET /runs/{run_id}` 轮询, 直到 `terminal=true`,再获取逐条 `results` 和汇总 `reports`。 报告不单独保存:`POST /runs` 创建运行后即可查询实时报告,结果变化时报告自动重算,因此没有报告 POST/PATCH。删除终态 run 会同时删除其结果,之后对应报告返回 404。 运行结束后可将详细结果导出为 Markdown: ```bash uv run python scripts/export_run.py --run-id 42 ``` 默认导出全部样例到 `outputs/run_42_results.md`。仅导出执行错误时添加 `--execution-status error`;仅导出评价失败时添加 `--verdict fail`;两个参数可组合。脚本会交互请求用户名和密码,还可用 `--base-url`、`--username` 和 `--output` 指定服务地址、用户名和输出路径。 取消运行使用 `PATCH /api/v1/runs/{run_id}` 和 `{"status":"cancelled"}`。取消是协作式的:正在进行的单次模型请求结束后停止后续样例。终态运行可用 `DELETE /api/v1/runs/{run_id}` 删除,运行中删除返回 409。