语音里的长列表

9 分钟读完

V25
实战手册 · 语音与实时智能体

十二条结果,一只耳朵:列表是一段来电者无法回放的独白。

你的检索没问题,转写也很干净,可通话偏偏死在智能体念到八个选项中第四个的那一刻——因为语音没有回滚条,而一个人大约只能记住大约四个组块。解法不是把列表变短,也不是把摘要写好:一个返回「排好序的结果集」的工具,交给智能体的是它根本说不出口的东西,所以工具必须改为返回一个答案或一个问题,而「匹配太多」必须是一种结果,不是一份载荷。

步骤 1先把账算出来,再去写提示词。

自然口语的速度约为每分钟 150 词,也就是每秒约 2.5 词。一个来电者真能分辨出来的选项,需要一个名称再加至少一项属性(时间、价格、门店、日期),把连接成分算进去就是八到十二个词。于是六个选项就是五十到七十个词,也就是二十到三十秒不间断的智能体语音——而在这种介质里,你正在拼命争取的800 毫秒本身就已经被听成一次停顿了。

然后是更难的那个数字。Cowan 在 2001 年发表于《Behavioral and Brain Sciences》的综述,把正常成年人的注意焦点定在约四个组块——这是对 Miller 那个「七」的刻意反驳,此后一直有争议,而且它是实验室数字,不是电话通话的数字。把它当作正确的量级而不是一个常数,这笔账依然落在同一个地方:一个被念出来的选项是两到三个组块,所以来电者能记住的,是正在听的那个选项,也许再加上前一个。你列表里更早的一切都没了——而且在你还没说完的时候就已经没了。

# what the caller retains from a six-item spoken list
items 1-3   overwritten
item  4     a fragment, maybe the price
item  5     held
item  6     held, and now the default answer

# the recency effect is not a preference signal.
# your conversion data will read it as one.

最后那一行是 bug 藏身之处。在你的分析数据里,一个「挑了最后听到的那个」的来电者,与一个真正「选择了它」的来电者完全无法区分。枚举失败不会以错误的形式浮现——它浮现为:对你的排序器恰好放在末尾的那个选项,呈现出可疑的强烈偏好。

步骤 2缺陷在工具签名里,不在提示词里。

标准解法是加一条指令:绝不要念超过三个选项。它站不住,而原因值得弄懂,因为在每一种技术栈里原因都一样。工具返回了十行。模型现在手里握着十行,外加一条「只说三个」的指令。结果里没有任何东西说明是哪三个,于是模型自己挑——通常按位置挑,这意味着你排序器里的并列打破规则,已经悄悄变成了你产品的推荐引擎,没有埋点,也没有评审。你并没有把列表变短,你只是把截断动作挪进了你拥有的、可观测性最差的那个组件里。

一个「可以返回结果集」的语音工具,是被规约错了的。来电者消费不了一个集合,所以必须有东西去把它收拢,而那个东西应该是工具——在那里你可以把这个决定记下来、测试它,并且不用发布提示词就能改它。这正是塑造工具结果里那个一般性论点在语音场景下的具体形态:结果的形状该匹配消费方用得上的形状,而不是你的查询恰好产出的形状。

# mis-specified: the caller cannot hear this, so the model improvises
find_appointments(...) -> { results: [ {...} x10 ] }

# speakable: three outcomes, each one a sentence, each one loggable
find_appointments(...) -> one of
  { kind: "answer",       slot: {...}, alternatives_held: 9 }
  { kind: "discriminate", axis: "part_of_day",
                            split: { morning: 4, afternoon: 6 } }
  { kind: "too_many",     count: 61, best_axis: "branch" }

第三种结果是团队最常漏掉、却最划得来的那一种。一次命中六十一行的查询不是列表问题,它是一个信号:智能体问错了问题;而诚实的回应是反问一句——不是把六十一行按字母序掐成三行。

步骤 3去问那个能区分的问题,而不是把集合念出来。

当工具返回 discriminate 时,智能体这一轮就是一句话,包含一个轴。该挑哪个轴?挑那个把候选集切得最均匀的——因为那是「每秒语音消除选项最多」的问题,和二分查找的逻辑一样,只不过作用在一条按秒计费的通道上。

  • 把切分算出来,不要猜。六个上午、四个下午,是个好问题。九个上午、一个下午,是个坏问题:你花掉一轮,只消掉了集合的十分之一。让工具把计数返回来,再据此挑轴。
  • 每轮一个轴。「上午还是下午,另外要哪家门店?」这是两个问题,来电者只会答一个——通常是第二个,而你并不知道他们指的是哪一个。
  • 点明两端,绝不要「或者其他」。一个开放的第三选项,会把你刚刚砍掉一半的集合重新打开。
  • 把计数悄悄带上。「这类我这边有十个——上午还是下午?」这句话让来电者明白自己为何被问,并让你白捡到下一个问题的机会。它并没有把十个都说出来。

两三个这样的问题就能解决一个六十项的集合,而每个问题约花两秒语音,相对于枚举要花的二十五秒。你会听到的反驳是:盘问比列表的体验更糟。并非如此——一份来电者记不住的列表,听起来像是被一个压根没在听的人念菜单。关于同一招什么时候是错的,见澄清式提问:它错在「你本可以推断出答案」的时候,而候选计数不是一种推断。

步骤 4确实必须念出选项时,把区分点放在最前面。

有时候「三个」真的就是答案——三个航班、三个预约时段、三种套餐。那么每一句话内部的语序,就决定了来电者能不能用上它。把区分选项的那项属性放最前,把共有的名词放最后,因为来电者是在最前两个词里决定还要不要继续听。

bad  "There's a Dr Okonkwo appointment on Tuesday at 9:40,
      a Dr Okonkwo appointment on Tuesday at 2:15, and..."
      # the first six words of each are identical; by the time the
      # distinguishing part arrives the caller has stopped parsing

good "Tuesday morning, Tuesday afternoon, or Thursday morning.
      All with Dr Okonkwo."
      # the discriminator is the whole utterance; the shared part
      # is said once, at the end, where it costs nothing
  • 把共有部分提出去。如果三个选项的医生、门店和价格都相同,那就只说一次。列表只留下变化的那个轴。
  • 最多三个,而且要当真。如果第四个真的重要,它该排在一次 discriminate 之后,而不是接在一个「另外还有」后面。
  • 韵律是承重的。三个选项之间若没有停顿,它就是一个长名词短语。请插入真正的断点——只要你给出句末标点,多数TTS 引擎都会给你一个句末停顿,这比一个标记标签更便宜也更可靠。
  • 预期打断,并且欢迎它。一个在第二个选项上插话的来电者,选的就是第二个。你的轮次管理器必须把这次打断归到「它发生时真正可听见的那个选项」上——也就是已经说完的那个,而不是模型已经生成的那个。

步骤 5绝不要把序号念出来。

「请按 2」能用三十年,是因为 DTMF 是一条独立通道,字母表极小,且没有歧义。「请说二」不是同一招,而且它的三种失效方式会相互叠加。

  • 序号指向的那份列表可能已经不存在了。只要有任何重新查询——一次重试、一次回退的打断、一次重新排序的工具调用——第二位现在就是另一行了。「第二个」里没有稳定标识符,而你也发现不了这种错位,因为两者都是合法的选择。
  • 小数字的声学特征很差。英语里「two」与「to」「too」的区分,是识别器靠上下文解决的语言模型问题,而一个孤零零的数词没有上下文。把字母数字串念给智能体听里的那些失效模式,在这里以缩微版重演。
  • 它让来电者替你维护数据结构。他们现在除了要记住选项,还要记住一份映射——而那正是你本想保护的组块预算。

让内容本身充当句柄:「周二上午还是周四?」——来电者用事物本身来回答,你再把这个事物对着仍握在手里的候选集去解析,于是歧义变成了一次 discriminate,而不是一次无声的误选。把 DTMF 留给数字输入,正如替换一套 IVR所主张的那样——并且只留给数字输入。

有一类例外值得刻意保留:走中继服务、用读屏软件、或用语音转文字键盘的来电者,可能确实更偏好一份带编号的列表,因为他们那条通道是有回滚条的。请把「枚举加序号」这条路径做成按需可用,而不是直接删掉它,同时别把它放进默认路径。这段论述的其余部分在无障碍语音智能体里。

步骤 6给枚举埋点,因为没有别的东西会发现它。

这一切都不会出现在文字记录评测里——而这通常正是它带着毛病上线的原因。智能体的话术很流畅,选项也都准确,来电者选了一个,于是每一项文本层面的指标都是绿的。四项便宜的测量能抓住它。

  • 工具边界上的候选计数分布。在每一次调用上记录收拢之前的行数。尾部就是你的 bug 清单:如果 90 分位是十一,那你的智能体每小时都要在十一行深处临场挑选好几次。
  • 智能体最长的不间断话语,以秒为单位。一个数字,从合成时序里就能轻松算出,而且是整类失效最好的代理指标。给它设告警。在一个对话轮次上超过约八秒,就值得去看一眼。
  • 枚举期间与其他时段的打断率之比。智能体正在列举时打断率飙升,不是来电者没耐心;那是来电者在制止一段他用不上的独白。
  • 选择的位置偏倚。把被选位置的分布与你排序器的本意对照。若出现你的排序预测不了的强烈末位或首位偏斜,那就是 STEP 1 里的近因效应——以营收的形式显形。

在评估语音智能体的黄金集里加一行:一条合理地命中数十行的查询。给这一轮打分的依据是「智能体有没有反问」,而不是「它的列表准不准」。多数智能体第一次跑就过不了这个用例,而几乎没人把这个用例收进集子。

先做这件事:找出你流量最大的那个语音工具,把任何截断之前的行数记录一天,然后画出来。接着改掉这个工具的返回类型,让「结果集」在类型上就无法表达——只能是一个答案、一个带计数的区分性问题,或者一个「太多了」的结果。你本打算去做的那处提示词修改,是在绕过一份你本来有权编辑的签名。