数据库与模型:新增多版迁移(章节证据快照、对话血缘、记忆事实/时间线 lineage 等),把「成稿 ↔ 对话/记忆」的溯源信息落到表结构里。 业务链路:会话与 WS、回忆录/故事流水线、记忆写入与 enrichment 等跟着接上线索与快照;新增章节证据快照与评测侧 EvalTraceService 等模块,方便组评审用的证据包。 内部评测:自动化 run 与手工 memoir 评审共用可追溯证据;rubric/ judge 相关脚本与文档有配套调整。 app-eval-web:Memoir/实验详情里能展开看证据摘要与 evidence_trace(含对话轮次 id);Vite 代理与 development.sh 注入的 API 端口与当前默认内部评测端口一致,避免改端口后页面连错服务。 工程杂项:GitHub Actions / 仓库说明有更新;各适配器与支付/配额/plan 等多处为小改动或跟随主改动的收尾;新增/扩充了?
8.2 KiB
内部回归评测平台
与主 API(app/main.py)隔离进程部署,避免评测候选链路透出给消费者 App。
启动
推荐一条命令:internal-eval.sh 实际调用 development.sh,在同一进程树里启动主站 main:app(8000)、一份 Celery、内部评测 internal_app(默认 8001)以及 app-eval-web(默认 5174)。不需要再并行执行两份启动脚本。
单一命令 ./internal-eval.sh |
|
|---|---|
| HTTP | 主站 8000 + internal 8001 |
| Celery | 仅 一个 worker(与主站共用队列) |
| 前端 | 默认启动 app-eval-web(START_EVAL_WEB=0 可关) |
若 主站 + Celery 已在其他终端 由 ./development.sh 跑起来了,只在同一台机器上多开评测 HTTP 与前端、且 不再起第二份 Worker:
cd api
# 确保 .env.development / .env 含 INTERNAL_EVAL_API_KEY;:8000 已被主站监听
SKIP_INFRA=1 SKIP_INSTALL=1 EVAL_ATTACH_ONLY=1 ./internal-eval.sh
兼容旧写法:SKIP_CELERY=1 会映射为 EVAL_ATTACH_ONLY=1(仍要求 8000 已在监听)。
仅主业务、不要评测台时照旧:./development.sh(不设置 LIFE_ECHO_WITH_INTERNAL_EVAL)。
若你只需要 8001、刻意不启主站 8000,请用下文「手动 uvicorn」配合既有 Celery,不要用 ./internal-eval.sh(一键脚本会顺带拉起主站)。
默认会起 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-5 评审(默认复用智谱 key,也可单独配置)
export EVAL_JUDGE_API_KEY='...' # 可选,默认 ZHIPU_API_KEY
export EVAL_JUDGE_MODEL='glm-5' # 与 Settings 默认一致
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-5 评审对话」。 - 回忆录章节:同一套 fixture 会带上导出 MD 中的
source_user_id与memoir_sections;「刷新库中章节/故事」拉 DB 快照 →「GLM-5 评审章节」(基线节选与当前成稿一并送评)。
真实链路透传回放(与 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)。响应增加 segment_ids(本批创建的用户 segment,顺序与处理一致) |
GET |
/internal/api/evaluation/sessions/{conversation_id}/memoir-phase1-ready |
query:segment_ids 可重复(?segment_ids=id1&segment_ids=id2)。当所列 segment 均已写入 topic_category(Phase1 完成)时返回 ready: 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 时,对话会落库但章节异步不会推进。 - app-eval-web Playground:默认在每轮回放后轮询
memoir-phase1-ready,再发送下一轮;单轮等待默认最长 10 分钟(环境变量VITE_MEMOIR_PHASE1_WAIT_MAX_MS覆盖)。需 worker 正常消费任务。可通过「等待 Phase1」勾选关闭以做快速冒烟。中断或 Phase1 超时会将进度写入浏览器 localStorage,可在同一基线下用「继续未完成重放」接续同一conversation_id(含先补完未就绪的 segment)。
手动 GLM-5(不写 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 |
只读章节与故事正文快照 |
回忆录评审:可追溯证据闭包(lineage)
产品与 tier 口径(strict / partial / fallback)、synthetic vs library 分表、PM 对齐规则、backlog 见同目录 traceable-memoir-lineage.md。
手动 /judge/memoir-chapters 与自动化 eval_runs.judge_bundle_json 已按 artifact 绑定证据 组 prompt,而不再默认拼接「最近 N 个会话全文」:
lineage_tier:strict/partial/fallback(章节:有可解析 transcript 链 + 结构化记忆为 strict;仅有结构化记忆、无绑定 segment/transcript = partial,与标注口径一致)。故事侧以StoryEvidenceLink与章节推导为主;fallback= 显式降级最近会话 transcript,避免静默当 strict。evidence_trace:bundle 完整 JSON(segment / conversation / chunk / fact / timeline / summary、notes等)。内审计一般够用;若需按类型深链 UI 再排期。format_meta:truncated、dropped_sections、included_token_estimate等,区分「prompt 裁掉」与「库中无 lineage」。- 生产侧:叙事流水线在每次 Story 写入后覆盖
story_evidence_links,并在当前story_versions.prompt_meta.memoir_retrieval写入本轮检索到的稳定 id(见story_pipeline_sync._persist_story_lineage_sync)。 - 章节快照 Phase C:
chapter_evidence_snapshots+chapter_evidence_links,chapters.current_evidence_snapshot_id指向当前版本;evidence_bundle_json仍为镜像。评测读取顺序:表快照 → JSON → 现场source_segments(不一致时notes提示)。刷新见memoir/chapter_evidence_snapshot.py。历史库可选uv run python scripts/backfill_chapter_evidence_snapshots.py(旧数据不强制)。 - 对话 memory trace(Phase 八):访谈路由下,
conversation_messages.memory_retrieval_trace_json在配对 AI 消息上写入本轮HybridRetriever命中的 chunk/fact/timeline/summary/story 等 id(见memory/retrieval_trace.py)。
历史数据可无 link:评测仍可用 partial/fallback 跑通;可选离线 backfill 须在 job 中显式打标,不冒充 strict。
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。