docs(voice): add agent output humanity task brief
咨询 prompt 九成禁令无 persona、Level 2 模板把温度压到审计表之后、 校正 agent 限一句话且用户可见文案全是工程腔硬编码——三源修复: voice 置顶、直接回应开场、承接放宽 2-4 句、文案集中重写加防回归词表。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# 任务书 · Agent 输出人味修复:语气是产品的一部分,不是正确性的牺牲品(2026-09-01)
|
||||
|
||||
基线:`origin/staging` @ `ff97de5e`。
|
||||
|
||||
## 0. 问题定性
|
||||
|
||||
用户反馈:Agent 输出"没有人味"。经排查这是**结构性**的,三个来源,全部在产品侧,均可在不动任何真实性红线的前提下修复:
|
||||
|
||||
1. **咨询系统提示配比失衡**(`mastra/index.ts` + `mastra/product-voice.ts`):约 60 条指令里 ~90% 是禁令与合同(Never/Do not/Treat as final),语气指引只有三句零星短语,无 persona、无共情原则、无正面语料示例。模型被挤成审计报告腔。
|
||||
2. **Level 2 模板把温度压到最后**(`product-voice.ts`):本命问题强制以"## 统一参数与原始结构"的度数表开场,"## 现代生活"在技法审计表之后垫底。用户问"我婚姻怎么样",第一眼是岁差和上升度数。
|
||||
3. **校正 agent 限一句话 + 硬编码文案无语气**(`mastra/agentic-rectification.ts` 指令"每轮正文只输出一句确认或承接";`method-followup.ts` / `answer-choice.ts` / `rectification-decision.ts` / route.ts 里的服务端直出字符串):用户在校正里读到的话大半是修 BUG-456/D-1 那几轮为正确性手写的字符串,公文腔("按同一规则计入当前区分题")、审讯腔("有没有记得住时间的收入变化、大笔支出或欠债?")、法务腔边界句每轮重复;答完 5 题把 30 分钟缩到 7 分钟,没有任何进度反馈。
|
||||
|
||||
**关键边界**:skill 10.0.14 文本只要求"正文只做承接与解释",并未限制一句话——"一句"是产品 prompt 自加的。问题槽服务端唯一所有、正文不得出题/复述题干、candidate/accepted/confirmed 语言边界、不得宣称唯一分钟:这些红线全部保留,本任务只改**语气与节奏**。
|
||||
|
||||
## 1. 硬红线
|
||||
|
||||
1. **真实性与合同边界一字不放宽**:技法审计表仍在正文文末;不得虚构;`REPRESENTATIVE_MINUTE_DISCLAIMER` 的**语义**必须保留(措辞可重写、频率可调,但交付轮必须完整出现一次"不是已确认的唯一出生分钟"语义);answer_policy / precise-timing 守卫不动。
|
||||
2. **问题槽归属不动**:服务端 focus 仍是唯一问题源;正文仍不得提问、复述、改写题干;选择卡仍由结构化槽位承载。放宽的只是承接正文的**长度与温度**(一句 → 2-4 句,可含进度感),不是职能。
|
||||
3. **不改 skill 包**(10.0.14 文本已兼容本任务;如发现某条硬编码文案被 skill 逐字锁定,先报告再动)。
|
||||
4. **禁止空洞暖场**:人味 ≠ 客套话轰炸。不得加"亲爱的""感谢你的信任"式填充;不得每轮重复问候;不得用 emoji。人味的定义见 §voice 原则。
|
||||
5. 既有测试断言若逐字锁定旧文案,允许同步更新断言文本,但**断言的语义约束**(如"必须含不可分区间语义""不得出现唯一分钟措辞")必须保留并改为语义级匹配;在 PR 里逐条列出改动的文案断言。
|
||||
6. `cd frontend && ./node_modules/.bin/tsc --noEmit` 通过(不要用 `npx tsc`);`rectification-*` / `consultation-*` / `consult-*` / `chat-*` 测试 fail=0。
|
||||
|
||||
## 2. Voice 原则(写进代码库作为持久参照)
|
||||
|
||||
新建 `frontend/docs/VOICE.md`(或 `frontend/src/lib/voice-guide.ts` 中的文档常量),至少包含:
|
||||
|
||||
- **人设**:一位懂行、可靠、说人话的占星师朋友——不是客服,不是法务,不是表单。
|
||||
- **五条原则**:先回应人再展开方法;说进度("我们已经把范围从 30 分钟缩到 7 分钟了");解释为什么问(一句就够);同一约束换着说(边界句不逐字复读);口语化但不轻佻。
|
||||
- **好/坏对照各 ≥5 组**,取材自真实文案(见 §任务 C 清单)。
|
||||
|
||||
## 任务 0(门控)· 快照当前腔调,先立对照
|
||||
|
||||
把事故 case `f83d9b42` 的完整 assistant 输出串(route 直出 + 硬编码文案)按当前代码复排一份存入 PR 描述,作为"改前"样本。改后用同一形状复排"改后"样本。这是本任务书唯一的"红→绿":主观质量靠对照呈现,不靠断言。
|
||||
|
||||
## 任务 A(P0)· 咨询 prompt 重构:voice 置顶,禁令收纳
|
||||
|
||||
`mastra/index.ts` / `mastra/product-voice.ts`:
|
||||
|
||||
1. `productConversationVoice` 开头新增 voice 段(人设 + 五原则 + 2 组好/坏对照),放在所有合同条款**之前**。
|
||||
2. Level 2 骨架**顺序不动**,但明确允许并要求:在 `## 统一参数与原始结构` 之前写一段 3-6 句、无标题的**直接回应**——先用人话回答用户问的事(方向性结论 + 一句共情/背景承接),再进入骨架。相应更新 "Do not shorten…" 措辞为"骨架不可省略,但必须以直接回应开场"。
|
||||
3. 禁令清单归并去重(内容不变,压缩语言密度),把散落的三句语气指令并入 voice 段。
|
||||
4. `generalJyotishInstructions` / onboarding 指令同样加 voice 段。
|
||||
|
||||
## 任务 B(P0)· 校正 agent 松绑到"2-4 句自然承接"
|
||||
|
||||
`mastra/agentic-rectification.ts`:
|
||||
|
||||
- "每轮正文只输出一句确认或承接" → "每轮正文 2-4 句:确认收到什么、(可选)一句为什么有用或当前进度、自然过渡到界面上的下一步。不提问、不复述题干、不预告选项。"
|
||||
- 新增进度感指引:当 dossier 显示候选区间较开场收窄时,允许且鼓励用一句自然语言说出(数字来自服务端投影,不得自算)。
|
||||
- 加 2 组好/坏对照(如 坏:"好的,记下了。" 好:"2016 年 9 月上大学,记下了——这类有明确月份的节点对校正特别有用。")。
|
||||
|
||||
## 任务 C(P1)· 硬编码文案人味重写(集中 + 逐条)
|
||||
|
||||
先把散落的用户可见字符串集中到一个 copy 模块(如 `lib/rectification-agentic/v9/user-copy.ts`),再逐条重写。**清单**(行号是线索,按符号定位;语义约束在括号里,必须保留):
|
||||
|
||||
| 现文案 | 位置 | 问题 | 方向 |
|
||||
|---|---|---|---|
|
||||
| "请先说一件你记得大概时间的人生经历,比如升学、入职、搬家、结婚或生病;只记得年份也可以。" | `method-followup.ts` GENERIC_COLLECT_QUESTION | 公文枚举 | "从你最容易想起来的开始就好——比如哪年上的大学、哪年换的工作,记得大概年份就行。" |
|
||||
| "有没有记得住时间的收入变化、大笔支出或欠债?" 等 USER_COLLECT_QUESTION 表 | `method-followup.ts` | 审讯式 | 每条加一层自然引子,去掉罗列感 |
|
||||
| "请点选下面的选项作答。点选和一句话回答会按同一规则计入当前区分题。" | route.ts | 内部规则外漏 | "直接点下面的选项就行,打字回答也一样算数。" |
|
||||
| "我没能确定这句话是否在回答当前问题。请点选下面的选项,或换一种说法。" | route.ts | 生硬 | "我不太确定这句是不是在回答上面的问题——点个选项,或者换个说法都行。" |
|
||||
| "当前可信区间是 X–Y,代表分钟 Z。代表分钟只是代表性候选,不是已确认的唯一出生分钟。" | `rectification-decision.ts` nonConvergingRangeNarration | 法务腔+每轮复读 | 交付轮完整版带进度感("从最初的 30 分钟缩到了 X–Y 这 7 分钟");中间轮允许省略边界句或用短版(语义约束:交付/采用轮必须含完整边界语义) |
|
||||
| "…可以从下面的时间里选一个采用。" | `answer-choice.ts` | 生硬 | 与上一条合并重写 |
|
||||
| "当前问题已更新,请刷新后重新作答。" | route.ts | 机器腔 | 口语化 |
|
||||
| "接下来请点选下面这一问。" 类占位 | turn-exit/答题链 | 占位残留 | 确认 Task C(上轮)已替换为真实题干后删除死文案 |
|
||||
| `UNVERIFIED_BIRTH_TIME_NOTICE` 等咨询侧 notice | `consultation-birth-time-mode.ts` | 与 TASK-consultation-birth-accuracy 的任务 D 协同,避免双改冲突 | 以该任务书为准,本轮跳过 |
|
||||
|
||||
重写要求:每条在 PR 里"旧 → 新 → 保留的语义约束"三栏列出。
|
||||
|
||||
## 任务 D(P2)· 防回归
|
||||
|
||||
- copy 模块导出集中后,加一条"机器腔词表"测试:用户可见文案不得包含 "按同一规则计入"、"请刷新后重新作答"、"当前状态为" 等词条(词表放测试文件,≥8 条,含本次清理的全部旧词)。
|
||||
- 交付/采用轮边界语义测试改为语义级:断言包含"不是已确认的唯一出生分钟"或等义白名单短语之一,而非逐字全句。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 任务 0 的改前/改后对照(事故 case 形状全程文案 + 一次婚姻主题咨询的开场三段)贴 PR。
|
||||
2. `tsc --noEmit` exit 0;四组前端测试 fail=0;改动的文案断言逐条三栏说明。
|
||||
3. 红线 1/2 的证明:交付轮输出仍含边界语义;正文仍不含题干(现有 server-focus/question-ownership 测试全绿)。
|
||||
4. `VOICE.md` 落库;机器腔词表测试落库。
|
||||
5. 未在真实环境验证的部分如实注明。
|
||||
Reference in New Issue
Block a user