Files
Jyotisha/docs/tasks/TASK-consultation-daily-empty-answer-20260909.md
T

76 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK · 「深入看今日」计算完成却没有回答(empty_answer),且思考流漏出缺词英文(2026-09-09)
- 基线:`origin/staging` @ `ee6173e8`(staging 部署以健康接口为准)
- 分支:`codex/consultation-daily-empty-answer-20260909`,基于 `origin/staging`
- 执行方:coding agent;验收:Claude
- 涉及文件:`frontend/src/mastra/consultation-tools.ts``canonicalDomainPlan` L291、`AGENT_SLICE_MAX_STEPS` L56、`consultationSliceGenerationSettings` L73)、`frontend/src/app/api/consult/route.ts``composeSection` L1151、`retryForAnswer` L1128)、`frontend/src/lib/stream-agent-response.ts``composeByHeadings` L420、`consumeAttempt` L336)、`frontend/src/lib/consultation-thinking-plan.ts``natalConsultationThinkingPlan`)、`frontend/src/lib/consultation-entrypoint.ts``daily_starlanguage` 扩展 L7280)、`frontend/src/lib/public-thinking.ts`
- BUG 编号起点:**BUG-612**`docs/BUG_HISTORY.md` 最大已到 BUG-611`TASK-upstream-sync2-fix-20260909` 占用 609611
- 优先级:**P1**(首页入口"深入看今日"整条失败;不扣点是对的,但用户拿不到回答)
## 1. 事故实证(2026-09-09 staging,用户转录;只写结构)
活动区依次:读取分析方法 → 计算本命盘 → 先整理本盘的统一参数 → **接下来分析你的综合** → 用审计表收口后再落到生活("已完成 5 步")。随后思考区出现一段缺词英文(`The a for 2026-09-09 (, per). The is a - an, not a. … The be "" or "timing" - is a/trend. … Let me use: [""]. … "timing"? … Let me run-jyotish-.`),最后正文只有 `计算已完成,但这次没有生成回答,本次不会扣点。请再发送一次。``empty_answer`)。
## 2. 根因
### 2.1 BUG-612P1):入口定的是"时运",模型自己改成"综合";写作阶段想改回来时已经没有步数
1. 首页"深入看今日"发的是 `theme: "timing"` + `entrypoint: "daily_starlanguage"``page.tsx` L14661470),问题被扩展成"深入解读 ${日期} 的今日主题:今日趋势、适合推进、需要避开、一个行动建议"(`consultation-entrypoint.ts` L7280)。
2. `run-jyotish-consultation``canonicalDomainPlan``consultation-tools.ts` L291):模型**显式传了 `domains`** 就以模型为准,只有省略时才用路由选的 `theme`。活动区"接下来分析你的综合"证明本次执行的是 `general`,即模型把服务端定的 `timing` 改成了 `general`
3. 计算完成后进入按标题分段写作(`composeByHeadings`):标题来自 `natalConsultationThinkingPlan({domains: 已执行领域})` = 统一参数与原始结构 / **综合** / 技法审计表 / 现代生活。这套标题与"今日趋势 / 适合推进 / 避开 / 行动"完全对不上。思考流里模型正是在纠结这件事("is a daily/trend … 'timing'? … Let me use: [timing] … Let me run-jyotish-consultation")。
4. 每个分段调用 `maxSteps = AGENT_SLICE_MAX_STEPS = 1` 且**工具仍然可用**`streamOptions` 没有 `toolChoice: "none"`,分段提示只是文字上说"不要再调用排盘工具")。模型在分段里发起了第二次工具调用(想换 `timing`),一步用完,没有任何正文。四个分段全空 → `retryForAnswer` 再跑一次完整循环 → 仍空 → `empty_answer`。这是 BUG-280"计算成功、模型没写"的又一条来路,BUG-280 的重试救不了它,因为重试后模型面对的还是同一套错位标题。
### 2.2 BUG-613P2):思考流按 chunk 过滤,英文被削成词渣
`sanitizePublicThinkingText``public-thinking.ts`)对每个 `reasoning-delta` chunk 判断"含 ≥4 字母英文且无中文就丢"。流式 chunk 常常是一两个词:长词所在的 chunk 被丢、短词(The / a / for / is / to / Let me)和带中文的 chunk 被放行,拼出来就是用户看到的那段。工具名只剥了后缀(`run-jyotish-` 残留)。
## 3. 决策记录
1. **入口驱动的请求由服务端钉死领域。** `entrypoint` 存在(`daily_starlanguage` / `birth_time_rectification`)时,`canonicalDomainPlan` 忽略模型传的 `domains`,只执行路由 `theme`(本例 `timing`);模型传了不同值记 `plan_override_ignored` 到 receipt,不报错不扣步。普通问题维持现状(模型可选多领域)。
2. **"深入看今日"用自己的写作标题。** 新增 `dailyConsultationThinkingPlan()`:一节"今日趋势"、一节"适合推进 / 需要避开"、一节"一个行动 + 边界句"(边界句沿用扩展里的"探索性日提示,不是确定预测"),技法审计表折进最后一节。`natalConsultationThinkingPlan` 只用于非入口问题。
3. **分段写作禁用工具。** `composeSection``agent.stream``toolChoice: "none"`(计算已缓存,分段本来就不该调工具);某一段返回空正文时,同一段再试一次(仍 `toolChoice: "none"`,提示追加"上一段没有输出正文,请直接写这一节"),再空才进入既有 `retryForAnswer`
4. **思考流按句过滤。** `sanitizePublicThinkingText` 改成有状态的缓冲:按 `。!?\n` 或英文句号切句后再判定;纯英文句整句丢,工具名整个删(连前缀);未闭合的尾巴等下一个 chunk。对外仍只发 `thinking.delta`
5. 不动计费(空回答仍不扣点)、不动 `AGENT_MAX_STEPS = 8` / `AGENT_TIMEOUT_MS = 110s`、不动 Skill。
## 4. 任务分解
- 4.1 决策 1`consultation-tools.ts` + `route.ts``entrypoint``ConsultationAgentContext`;测试——`entrypoint=daily_starlanguage, theme=timing`,模型传 `domains:["general"]` → 执行 `timing`receipt 含 `plan_override_ignored`;无 entrypoint 时行为不变。
- 4.2 决策 2`consultation-thinking-plan.ts` 新增 daily 计划;`route.ts``daily_starlanguage` 分支用它;测试——标题序列为三节,正文以 `## 今日趋势` 开头;`applyThinkingSectionProgress` 能按新标题标 done。
- 4.3 决策 3`composeSection``toolChoice: "none"`,分段空正文重试一次;测试(`consultation-agentic-runtime.test.ts` 扩)——mock 某段模型只发 tool-call 无文本 → 该段重试后写出正文,`fullOutput` 非空、不触发 `retryForAnswer`;两次都空才 `answer-retry`。三栏:原值"分段可调工具"→ 新值"分段禁用"→ 决策 3。
- 4.4 决策 4`public-thinking.ts` 改缓冲实现;测试——把事故那段按 3–6 字符切成 chunk 喂入,输出不含任何 4 字母以上英文词、不含 `run-jyotish`,中文句完整;纯中文思考原样通过。
- 4.5 记录:`docs/BUG_HISTORY.md` BUG-612(复发关联 BUG-280:同一"计算成功、模型没写"现象,新来路是入口领域被改写 + 分段可调工具)、BUG-613;`CHANGELOG.md``PROGRESS-…``docs/testing/` 加"首页点『深入看今日』必须得到三节回答,思考区不得出现英文词渣"。触发链若执行方能从 staging `[agent-observability]` 日志取到该 run 的 `tool.input.domains``modelFinishReason`,写进 BUG-612 的验证段;取不到写 `investigating`,但决策 1–4 都是确定性缺陷,照做。
## 5. 让步顺序
4.3 与 4.1 先做(最小改动即可止血);4.2 必做;4.4 必做;4.5 不可省。
## 6. 开工前置命令
```bash
git fetch origin --prune
git worktree add -b codex/consultation-daily-empty-answer-20260909 .worktrees/consultation-daily-empty-answer-20260909 origin/staging
cd .worktrees/consultation-daily-empty-answer-20260909
ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules
cd frontend && ./node_modules/.bin/tsc --noEmit; npm run lint 2>&1 | tail -1
ls tests/consultation-*.test.ts tests/public-thinking*.test.ts tests/agent-*.test.ts 2>/dev/null | xargs npx tsx --test 2>&1 | grep -E "^# (tests|pass|fail)"
```
## 验收(Claude2026-09-09`origin/staging` @ `fef54b6e`staging 已部署同 SHA
| 门 | 结果 |
| --- | --- |
| tsc | 0 错 |
| lint | 0 error / 108 warning |
| 前端 rectification + consultation + session + home-bootstrap + public-thinking + voice + skill-registry(非 DB | 1400 / 0 |
| Python v5_services + event_probes + growth contract | 76 passed |
| 项 | 结论 |
| --- | --- |
| 4.1 入口钉死领域 | 通过。`pinsConsultationDomains(entrypoint)` 时只执行路由 theme,模型改写记 `planOverrideIgnored` |
| 4.2 今日三节标题 | 通过。`dailyConsultationThinkingPlan`,且 `getJyotishAgent` 在今日入口换成 daily 标题规则(额外做,合理) |
| 4.3 分段禁用工具 + 空段重试 | 通过。`toolChoice: "none"``section-empty-retry` |
| 4.4 思考流按句过滤 | 通过。`createPublicThinkingSanitizer`;偏离 2(英文前缀遇中文句起点切开)合理 |
| 真实环境 | 欠:首页点「深入看今日」得三节回答,见走查清单 |
结论:通过。