Files
Jyotisha/TASK-agent-voice-20260901.md
T
Jesse_ChenandClaude Fable 5 ebb7086601
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled
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
2026-09-01 15:27:52 +00:00

8.8 KiB
Raw Blame History

任务书 · 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 里"旧 → 新 → 保留的语义约束"三栏列出。

任务 DP2)· 防回归

  • copy 模块导出集中后,加一条"机器腔词表"测试:用户可见文案不得包含 "按同一规则计入"、"请刷新后重新作答"、"当前状态为" 等词条(词表放测试文件,≥8 条,含本次清理的全部旧词)。
  • 交付/采用轮边界语义测试改为语义级:断言包含"不是已确认的唯一出生分钟"或等义白名单短语之一,而非逐字全句。

验收标准

  1. 任务 0 的改前/改后对照(事故 case 形状全程文案 + 一次婚姻主题咨询的开场三段)贴 PR。
  2. tsc --noEmit exit 0;四组前端测试 fail=0;改动的文案断言逐条三栏说明。
  3. 红线 1/2 的证明:交付轮输出仍含边界语义;正文仍不含题干(现有 server-focus/question-ownership 测试全绿)。
  4. VOICE.md 落库;机器腔词表测试落库。
  5. 未在真实环境验证的部分如实注明。