4.7 KiB
内部回归评测平台
与主 API(app/main.py)隔离进程部署,避免评测候选链路透出给消费者 App。
启动
一键脚本 internal-eval.sh 与 development.sh 不是重复各启一套主站:
development.sh |
internal-eval.sh |
|
|---|---|---|
| HTTP | 主站 main:app(默认 8000) |
仅评测 internal_app(默认 8001) |
| Celery | 会起一个 worker | 默认也会起一个 worker(可与下面「瘦启动」二选一) |
评测分析只需要 8001 上的 internal API;若你已经在跑 development.sh(DB/Redis/主站/已有 Celery),不必再起第二份基础设施和 worker:
cd api
chmod +x internal-eval.sh
# 确保 .env.development 或 .env 里有 INTERNAL_EVAL_API_KEY
SKIP_INFRA=1 SKIP_INSTALL=1 SKIP_CELERY=1 ./internal-eval.sh # 推荐:只多开 8001
全新机器、只跑评测栈时可直接 ./internal-eval.sh(会起 docker、uv sync、迁移、8001 + Celery)。默认会起 app-eval-web,并用 Vite --open 尝试打开浏览器(http://127.0.0.1:5174/)。不要前端时设 START_EVAL_WEB=0;只要前端但不要弹窗时设 OPEN_EVAL_WEB=0。
数据库与主服务共用;需配置环境变量后启动专用进程:
cd api
export INTERNAL_EVAL_API_KEY='your-long-random-secret'
export INTERNAL_EVAL_ENABLE_DOCS=1 # 可选,开 /docs
# GLM 评审(默认复用智谱 key,也可单独配置)
export EVAL_JUDGE_API_KEY='...' # 可选,默认 ZHIPU_API_KEY
export EVAL_JUDGE_MODEL='glm-4-flash'
uv run uvicorn app.internal_main:internal_app --host 0.0.0.0 --port 8001
Celery worker 需已包含 app.tasks.evaluation_tasks(仓库 celery_app.include 已注册)。跑实验前:
uv run celery -A app.tasks.celery_app worker -l info
前端(app-eval-web)
cd app-eval-web
npm install
VITE_EVAL_API_BASE=http://127.0.0.1:8001 VITE_EVAL_API_KEY=与上同 npm run dev
或使用仓库根目录 npm run eval-web(需本地已 npm install 在 app-eval-web)。
SSE / EventSource
浏览器 EventSource 无法带自定义 Header,流式端点支持 query ?key=,与 X-Internal-Eval-Key 等效。
评测 Web:两大模块
- 对话评测:选
api/tests/user_exports/*.md为基准 →「新建评测会话」或填写已有conversation_id→「执行回放」→「GLM 评审对话」。 - 回忆录章节:同一套 fixture 会带上导出 MD 中的
source_user_id与memoir_sections;「刷新库中章节/故事」拉 DB 快照 →「GLM 评审章节」(基线节选与当前成稿一并送评)。
真实链路透传回放(与 App 一致)
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/internal/api/evaluation/sessions/eval-sandbox |
无 body:新建临时用户(eval_ 伪手机号)+ 空白 conversation_id |
POST |
/internal/api/evaluation/sessions/replay-bootstrap |
body:{ "user_id" },在已有用户下返回新 conversation_id |
POST |
/internal/api/evaluation/replay/conversation |
body:conversation_id、fixture_filename 或 user_utterances;可选 flush_memoir_after(默认 true)、skip_tts(默认 true) |
每轮等价于 WebSocket 文本路径:create_user_segment → process_user_message(内部可 force_skip_tts)→ background_runner.queue_message。
- TTS:回放默认
skip_tts: true,不在评测台跑语音合成。 - Memory / 回忆录管线:
queue_message与末尾flush_pending依赖 Celery worker(process_memoir_phase1等);仅起 internal API 未起 worker 时,对话会落库但章节异步不会推进。
手动 GLM(不写 eval_runs 表)
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/internal/api/evaluation/judge/conversation |
body:{ "conversation_id" },返回轮次分 + 全文对话分 |
POST |
/internal/api/evaluation/judge/memoir-chapters |
body:{ "user_id", "baseline_sections"? },Chapter/Story 分项 |
GET |
/internal/api/evaluation/users/{user_id}/memoir-snapshot |
只读章节与故事正文快照 |
Fixture 详情扩展
GET /internal/api/evaluation/fixtures/user-exports/{filename} 在原有 turns 外增加:
source_user_id:导出抬头中的 User IDmemoir_sections:## 回忆录章节(生成正文)下按标题切分的基线正文(已去掉{{IMAGE:...}}占位)
门禁规则(v1)
- 所有 case 的合成均分:候选须 严格高于 基线。
is_protected=true的 case:合成份跌幅不得超过EVAL_GATE_PROTECTED_REGRESSION_THRESHOLD(默认 2 分)。
结果写入 eval_gate_verdicts,不影响 git;后续可接 pre-commit / CI。