# TASK · 生时校正每轮等待过长:埋点 + 分类超时 + 发出后立即反馈(2026-09-26) ## 基线 - `origin/staging` 当前 head。分支 `codex/rectification-latency-20260926`。 - **串行**:排在 `TASK-rectification-dup-question-20260926`(同样改校正面组件)之后。 ## 事故实证(产品 09-26 真机) 打字回答后「正在分析 / 正在处理…」要等很久才出正文。排查结论(`origin/staging` a57c4310,本地实测 + 代码阅读): - 一轮打字回答串行 **5 次模型调用**,全部开思考: 1. 开流前意图分类 `classifyTurnIntentWithRetry`(`v9/turn-intent-classifier.ts`;`agent/route.ts` 约 L453 / 534 / 643 / 751 调用),用会话模型、供应商默认开 thinking,**每次尝试无超时**、最多 2 次,且发生在 `new ReadableStream` 之前 → 用户看到的是一段没有任何字节的空等;L643 分支继续时 L751 还会再分类一次。 2–5. Agent 四步(`v9/agent-run.ts` `streamAttempt`,`agentGenerationSettings(..., { thinking: "enabled", thinkingTokens: 8192 })`):强制第 0 步 `rectification-read-case`(路由已读过档案)→ `record-evidence-batch`(含引擎重算)→ `set-focus`(改写服务端定好的下一问)→ 最终正文模板句。推理内容不下发(`stream-mapping.ts`),界面只显示「正在分析…」。 - 引擎:09-15 性能审计四单(BUG-721~726)**已全部落地**;本地实测 20 个候选 0.4–0.5 s、61 个候选 2.3–2.5 s、带 `refresh_probes` 5.8–6.1 s;cProfile 热点是 `build_refinement_packet`(57–73%),refresh 分支探针算两遍;交付阶段 `vedastro-validate` 串行调外网(≤12 s)。 - 收尾 `persistNextInterviewIfIdle` 在 `agent-run.ts` 与 route `finalizeSuccessfulTurnExit` 各调一次,第二次多为空转但会重读档案。 - `RectificationRunDiagnostic` 的 `inputTokens` / `reasoningTokens` 恒为 null,`stepCount` 实际是"用过几种工具",分类耗时只在失败时记录 → 线上无法核实各段耗时。 - 估计单轮 25–90 s,模型占 85–95%;evidence_not_written 重跑时翻倍。 ## 根因 串行多步 + 每步深度思考 + 开流前无超时空等 + 无进度反馈。 ## 决策记录(产品 2026-09-26) - D1 **不改**每轮最后两步(set-focus 改写与最终正文仍由模型生成,口吻不变)。 - D2 **分类保持深度思考与会话模型**(维持 09-15 决定),只给每次尝试加 **10 秒超时**;超时按现有失败路径处理(重试一次后走既有兜底),不得换模型、不得关思考。 - D3 **发出后立即反馈**:用户发出后 ≤ 300 ms 内在活动状态处出现确定性进度句,随后按阶段更新,替代一直不变的「正在分析 / 正在处理…」: - 发出即:「收到,正在对照你的档案…」 - 记录经历开始:「正在记下这件事…」 - 引擎重算:「正在重新对照盘面…」 - 准备下一问:「正在准备下一个问题…」 - 阶段信号来自现有 `persistCommittedPhase` / 工具调用事件,不新增模型调用。这些句子属于"流式生成中",不违反"揭幕后不得出现加载态";进度句不写入 `assistant_message`。 - 为此把分类移到流内:先建流、立刻推第一句进度,再做分类。 - D4 **补埋点**:每步开始 / 结束时间、每步推理 token(供应商能给则记)、分类耗时(成功也记)、引擎每次调用耗时,写入 `RectificationRunDiagnostic`(不含用户资料与模型原文,符合隐私红线)。 - D5 **无口吻影响的服务端优化**(输出必须逐位不变,A/B 证明): - refresh 分支里 `build_refinement_packet` 探针只算一遍; - `persistNextInterviewIfIdle` 第二次调用在第一次已完成时跳过; - 部署未配置时 `readV9EngineScoringIdentity` 的 `/v5/versions` 结果在进程内按版本号缓存(短 TTL)。 - D6 不在本单:去掉强制 read-case 第 0 步(需改 Skill 原文与回执不变量,另议);vedastro-validate 改后台(交付语义,另议)。 ## 硬红线 1. 不换分类模型、不关分类思考、不改 Agent 各步是否开思考;不改 Skill 文本与 VOICE 口吻(进度句除外,需进 VOICE)。 2. D5 每项:同一虚构输入改前改后结果逐位一致(Python 用同机 A/B,不写死跨机浮点哈希,见 BUG-985)。 3. 分类超时测试:模拟挂起的分类调用,10 秒后进入既有失败路径,不无限等待。 4. 进度句测试:发出后第一帧(或 ≤ 300 ms)出现第一句;阶段事件驱动更新;结算后进度句消失,不进入持久化正文。 5. `jyotish_api_server.py` 不增长;全量前端测试与基线逐条一致、新增 0;Python 快速门与定向测试通过;改动断言三栏。 6. 真实浏览器(CDP 假数据 + 人为延迟)截图:发出后立刻出现进度句并随阶段变化。 ## 任务分解 - T1 埋点(D4)。 - T2 分类移入流内 + 10 秒超时(D2、D3 前半)。 - T3 阶段进度句(D3)+ VOICE / DESIGN。 - T4 服务端无口吻优化(D5)+ A/B 证明。 - T5 记录:BUG-1047(每轮等待过长 / 开流前无反馈),关联 BUG-721~726、BUG-722;CHANGELOG;PROGRESS(各段耗时改前 / 改后估计,部署后用新埋点复核);`docs/testing/` 真机清单(打字回答后立刻出现「收到,正在对照你的档案…」并逐段变化;总耗时记录)。 ## BUG 编号 本单 **BUG-1047**(1045 / 1046 由重复问题单预留),开工时核对。