☰
模糊代词处理:人机对话中上下文管理与指代消解的核心机制
2026/10/28 5:45:00 网站建设 项目流程

1. 从一个让人抓狂的对话说起

你有没有遇到过这种场景:你对着语音助手说“帮我找一下附近评分高的川菜馆”,它回你一句“好的,已为你找到以下结果”,然后列出来一堆火锅店、串串香,甚至还有一家日料。你追问“它家有没有包间”,它反问你“请问您指的是哪一家”。你心里那个火啊——我上一句说的就是那家评分最高的川菜馆,你怎么就听不懂“它”是谁?

这个场景几乎每个做对话系统的人都遇到过。用户在用自然语言聊天时,天然会使用大量代词——“它”“这个”“那个”“上面说的”“刚才那个”——而机器在解析这些词的时候,如果没有足够的上下文锚定能力,就会陷入一种“我知道你在说代词,但我不知道代词指谁”的尴尬。标题里说的“AI说‘它’时在说什么”,表面上是问代词指代,往深了挖,其实是整个人机对话系统里上下文管理、指代消解、对话状态追踪这一整套机制的缩影。

我做了几年对话系统的落地项目,从最早的规则式问答机器人,到后来的检索式对话,再到这两年的生成式对话应用,代词指代这个问题始终是绕不过去的坎。它不像意图识别那样有明确的分类边界,也不像实体抽取那样有清晰的标注规范,它更像是一种“对话黏性”——用户说得越自然、越像跟人聊天,代词就越多,指代链就越长,系统出错的概率就越大。

这篇文章想聊的就是这件事:模糊代词在人机对话里到底意味着什么,系统该怎么处理它,以及为什么处理好了它,深度交互才真正成立。不管你是刚接触对话系统的新手,还是已经在做多轮对话产品的老手,下面这些拆解和实操细节应该都能给你一些参考。

2. 模糊代词为什么是人机对话的“暗礁”

2.1 代词不是语法问题,是对话状态问题

很多人第一反应会觉得,代词指代不就是 NLP 里的共指消解任务吗?学术上确实有这套东西,但落到实际对话系统里,它远比“把代词替换成先行词”复杂。原因在于:对话中的代词指代依赖的不是句子内部的语法结构,而是整个对话历史里累积的语义状态。

举个简单的例子。用户说“我想订一张去成都的机票”,系统确认后,用户接着说“它那边天气怎么样”。这里的“它”指成都,但这个指代关系在单句里根本不存在——成都出现在上一轮的用户话语里,而且是被嵌在“去成都的机票”这个短语里的。系统要正确解析“它”,必须做到三件事:第一,记住上一轮提到了成都;第二,判断成都属于“目的地”这个槽位;第三,把“天气”这个新意图挂到“目的地”这个实体上。这三步里任何一步断了,指代就失败了。

所以我在项目里从来不把代词处理当成一个独立的 NLP 模块来做,而是把它看作对话状态追踪的一部分。对话状态里存的不只是槽位和值,还应该存“当前焦点实体”和“最近提及实体列表”。代词解析的本质,就是拿代词去跟这个焦点列表做匹配。

2.2 用户越自然,代词越模糊

这里有个反直觉的规律:对话系统做得越“像人”,用户使用代词就越随意,指代消解的难度反而越大。早期那种“请说出您要查询的城市”的机械式交互,用户根本不会用代词,因为系统逼着他们把话说完整。但一旦系统开始支持自然语言,用户就会说“那它呢”“这个多少钱”“换一个”“就刚才那个”。

我做过一个统计,在一个支持自由输入的订票场景里,大约 23% 的用户话语包含至少一个代词或指示词,其中“它”“这个”“那个”占了七成以上。更麻烦的是,这些代词里有将近一半是跨轮指代——指代对象出现在两轮甚至三轮之前。如果系统的上下文窗口只保留最近一轮,这些指代全部会失败。

这里有个实操心得:不要指望用户按你的槽位设计来说话。用户说“它”的时候,脑子里想的是“我们刚才聊的那个东西”,而系统脑子里如果只有“当前轮输入”,两边根本不在一个频道上。

2.3 模糊代词带来的三类典型故障

把代词处理不好会出什么问题,我归纳成三类,基本覆盖了实际项目里遇到的大部分情况。

第一类是指代错位。用户说“帮我看看它有没有优惠”,系统把“它”解析成了上一轮提到的某个不相关的实体,给出完全驴唇不对马嘴的答案。这类故障最伤用户体验,因为用户会觉得“你根本没在听我说话”。

第二类是指代丢失。系统干脆不处理代词,把“它”当成一个未知实体,回复“请问您指的是什么”。这在单轮问答里还能忍,在多轮对话里就是灾难——用户已经说了三轮了,你还在问“您指的是什么”,对话直接崩掉。

第三类是指代链断裂。用户说“A 不错,但 B 更好,它比它便宜”,这里两个“它”分别指 B 和 A,系统如果只维护一个焦点实体,必然搞混。这类情况在对比类、推荐类对话里特别常见。

故障类型典型表现根因影响
指代错位答非所问,实体张冠李戴焦点实体更新逻辑错误用户信任度骤降
指代丢失反复追问“您指什么”未做代词检测或上下文窗口过短对话无法推进
指代链断裂多个代词指向混乱只维护单一焦点,无实体栈复杂对话场景失效

3. 拆解“它”:指代消解的核心机制怎么搭

3.1 先解决“有没有代词”,再解决“指谁”

很多团队一上来就想做端到端的指代消解模型,结果发现效果不稳定,还不好排查。我的建议是分两步走:先做代词检测,再做指代解析。代词检测是个相对简单的任务——维护一个代词和指示词表(它、他、她、这个、那个、这些、那些、上面说的、刚才那个、该、其等),配合分词和词性标注就能覆盖大部分情况。这一步的召回率要做到很高,宁可多判不可漏判,因为漏掉一个代词,后面全错。

指代解析才是难点。我的做法是维护一个实体焦点栈,而不是单一焦点。具体来说,对话状态里存一个按时间倒序排列的实体列表,每个实体带上它的来源轮次、槽位类型、提及次数。当检测到代词时,按以下优先级匹配:

  1. 如果代词所在句子有明确的类型线索(比如“它家”通常指商家,“它那边”通常指地点),优先匹配对应槽位类型的实体;
  2. 否则取焦点栈顶的实体;
  3. 如果栈顶实体与当前意图明显不匹配(比如当前在问价格,栈顶是地点实体),往下找第一个类型匹配的实体;
  4. 都不匹配时,触发澄清追问。

这套逻辑听起来朴素,但在实际项目里比很多花哨的模型都稳,因为它的每一步都可解释、可调试。模型出错你只能看 attention,规则出错你直接看日志就知道哪一步判错了。

3.2 焦点栈怎么维护:更新时机比结构更重要

焦点栈的结构简单,难的是什么时候压栈、什么时候出栈、什么时候清空。我踩过的坑基本都在这。

压栈时机:用户话语里出现新的实体,且该实体被系统确认或用户明确提及,就压栈。注意,系统自己生成的实体(比如推荐列表里的商家)也应该压栈,因为用户下一句很可能就说“第一个它怎么样”。

出栈时机:这个话题结束、用户切换意图、或者栈深度超过阈值(我一般设 5 到 7 层)时,把最老的实体弹出。栈太深会导致指代匹配时引入过多噪声,实测 5 层左右是个平衡点。

清空时机:用户明确说“重新开始”“换个话题”,或者对话超时(比如超过 10 分钟无交互),直接清空。这里有个细节——不要因为一轮解析失败就清空栈,很多系统一遇到没听懂的就重置上下文,结果用户稍微绕一下弯,系统就“失忆”了,体验极差。

实操心得:焦点栈里每个实体建议带一个“热度分”,每次被提及加一分,被指代命中加两分,长时间未提及按轮次衰减。指代匹配时优先取热度高的,这样能自然处理“用户反复聊同一个东西”的情况,比单纯按时间排序更符合真实对话的注意力分布。

3.3 生成式对话里,代词处理反而更棘手

这两年生成式对话火了,很多人觉得大模型上下文窗口那么长,代词指代应该不是问题了吧?实际做下来,生成式系统在代词处理上有它自己的麻烦。

一方面,大模型确实能“看懂”长上下文里的指代关系,用户说“它”它基本能接上。但另一方面,大模型的输出不可控——它可能在回复里自己引入新的代词,而这些代词指代什么,系统内部并没有显式记录。比如模型回复“它家的招牌菜不错,不过它可能需要提前预约”,这里两个“它”分别指商家和预约这件事,如果下一轮用户说“那它贵吗”,系统要解析这个“它”,就得去解析模型上一轮的输出,而不是用户输入。这就把指代消解的范围从“用户话语”扩展到了“整段对话历史”,复杂度上了一个台阶。

我的处理办法是:在生成式系统里,对模型输出做一次轻量的实体回填——把模型回复里出现的代词,根据生成时的上下文,替换成显式实体再存进对话历史。这样下一轮做指代解析时,历史里全是明确实体,不用再去猜模型当时想指什么。这个回填不需要完美,覆盖主要实体就行,但做了之后指代链断裂的问题会少很多。

4. 从指代到深度交互:上下文管理才是真功夫

4.1 深度交互的标志:用户敢省略,系统能补全

什么叫深度交互?我的判断标准很简单:用户敢不敢在对话里省略信息。如果用户每句话都得说完整——“我要查北京的天气”“我要查北京明天适不适合跑步”——那说明系统还停留在命令式阶段。真正的深度交互里,用户会说“北京明天天气怎么样”“那后天呢”“适合跑步吗”,第二句和第三句全靠上下文补全,系统能接住,交互才成立。

代词指代只是省略的一种形式。除此之外还有意图省略(“那后天呢”省略了“查天气”这个意图)、槽位省略(“换个便宜点的”省略了“换什么”)、主语省略(中文里尤其常见,“还行吗”“有吗”“多少钱”)。这些省略的处理逻辑和代词指代是相通的——都是拿当前输入去跟对话状态做匹配补全。所以我在架构上会把它们放在同一个上下文管理模块里统一处理,而不是每个问题单独打补丁。

4.2 对话状态设计:别只存槽位,要存“对话意图图”

传统的对话状态就是槽位-值对,比如{目的地: 成都, 日期: 明天}。这套东西处理订票、查天气这类任务型对话够用,但处理代词和省略就力不从心,因为它不记录“我们聊到哪了”“当前焦点是什么”“用户刚才在对比什么”。

我的做法是在槽位之外,额外维护一个轻量的对话意图图:节点是当前对话涉及的主要实体和话题,边是它们之间的关系(对比、递进、转折、补充)。用户说“它比它便宜”,系统能从这个图里找到两个对比实体,分别绑定两个“它”。用户说“那这个呢”,系统能顺着图找到当前话题节点,把“这个”绑上去。

这个图不需要很复杂,节点数量控制在十个以内,边用简单的类型标签就行。它的价值在于给指代消解提供一个结构化的候选池,比单纯的时间序列焦点栈多了一层语义关系,处理对比、并列类对话时效果提升明显。

4.3 澄清追问的设计:问得巧,别问得烦

指代解析不可能百分之百准确,总有匹配不上的时候。这时候澄清追问的设计就很关键。我见过太多系统一遇到不确定就问“请问您指的是什么”,用户被问两次就烦了。

好的澄清追问应该做到三点:给选项、带上下文、允许跳过。比如用户说“它有没有优惠”,系统不确定“它”指哪个商家,不要问“您指什么”,而是问“您是想问 A 家还是 B 家的优惠”。把候选实体直接摆出来,用户点一下或者回个“A”就行。如果候选太多,就取热度最高的两三个。如果用户还是不选,给一个“都不是”的出口,别把用户堵死。

注意:澄清追问的频率要控制。同一个对话里连续追问超过两次,用户流失率会明显上升。我的经验是,第一次不确定可以问,第二次不确定就降级处理——按最可能的候选给一个答案,同时附一句“如果您问的是另一个,请告诉我”,把选择权还给用户但不强制打断。

5. 实操落地:一套可复现的代词处理流程

5.1 整体流程与模块划分

把上面这些思路落成一个可跑的流程,我一般拆成五个模块,串行执行:

  1. 输入预处理:分词、词性标注、代词检测;
  2. 上下文加载:从对话状态里取出焦点栈和意图图;
  3. 指代解析:按优先级匹配候选实体,输出解析结果和置信度;
  4. 状态更新:把本轮实体压栈、更新热度分、刷新意图图;
  5. 回复生成与回填:生成回复,对输出里的代词做实体回填后存入历史。

这套流程的好处是每个模块职责单一,出问题好定位。代词检测漏了,看第一步;解析错了,看第三步的匹配日志;下一轮又错了,看第四步的状态更新对不对。比端到端模型的黑盒调试省心太多。

5.2 关键参数与阈值设定

几个我实际调过的参数,直接给参考值:

参数含义参考值调整建议
焦点栈深度最多保留的实体数5~7对话实体多则调大,噪声大则调小
热度衰减系数每轮未提及实体的热度衰减0.85衰减太快会丢失长距离指代,太慢会引入旧实体干扰
指代匹配置信阈值低于此值触发澄清0.6追求流畅可降到 0.5,追求准确可升到 0.7
上下文超时无交互多久清空状态10 分钟按业务场景调整,客服类可短,助手类可长
澄清追问上限单对话最多追问次数2 次超过则降级处理

这些值不是拍脑袋定的,是我在几个项目里 A/B 测出来的大致区间。具体到你的场景,建议先用默认值跑一批真实对话日志,看指代解析的准确率和澄清触发率,再微调。

5.3 一个完整的解析示例

拿开头那个川菜馆的例子走一遍流程。

用户第一轮:“帮我找一下附近评分高的川菜馆。”系统返回三家,焦点栈压入[川菜馆A, 川菜馆B, 川菜馆C],热度各 1 分,意图图建立“川菜馆”话题节点。

用户第二轮:“它家有没有包间?”代词检测命中“它家”,类型线索指向商家。焦点栈顶是川菜馆A,类型匹配,解析为川菜馆A,置信度 0.85,直接回答。同时川菜馆A热度加 2 分。

用户第三轮:“那B呢?”这里“那B呢”是省略式追问,意图图里找到“川菜馆”话题节点,B 是节点下的实体,补全意图为“查包间”,解析成功。

用户第四轮:“它比它便宜吗?”两个“它”,意图图里当前对比关系是 A 和 B,按出现顺序分别绑定 A 和 B,解析成功。

整个链条里,焦点栈负责单实体指代,意图图负责对比和省略,两者配合,四轮对话没有一次澄清追问,这就是我想要的深度交互体验。

6. 踩过的坑与排查清单

6.1 那些年指代解析翻过的车

说几个印象深的故障。有一次线上反馈说用户问“它支持退货吗”,系统回答了一个完全无关的商品政策。查日志发现,上一轮系统推荐了三个商品,焦点栈里三个实体热度相同,按时间排序取了栈顶,但用户实际指的是第二个——因为用户上一句说的是“第二个看着不错”。问题出在系统没有把用户对序号的提及转化为热度加权。修复方案很简单:用户话语里出现“第一个”“第二个”这类序数词时,对应实体热度直接加 3 分,压过其他候选。

还有一次是生成式系统里,模型回复“它可能需要预约”,下一轮用户问“那它收费吗”,系统把“它”解析成了预约这件事,而用户指的是商家。根因是模型输出回填时,把“它”回填成了“预约”这个动作实体,而不是商家。后来调整了回填规则:优先回填名词性实体,动作类实体降权,问题解决。

6.2 常见问题速查表

现象可能原因排查方向解决思路
代词反复解析错焦点栈更新时机不对看每轮压栈日志检查系统生成实体是否压栈
长距离指代丢失栈深度不够或衰减太快看指代对象距当前轮次调大栈深度、放缓衰减
对比场景指代混乱只维护单焦点看意图图是否有对比边引入意图图或双焦点机制
澄清追问过多置信阈值过高统计澄清触发率降阈值或增加候选匹配规则
生成式系统指代漂移模型输出未回填看历史里是否有裸代词对模型输出做实体回填

6.3 几条不太会写在文档里的经验

第一,代词处理的效果评估不能只看准确率。指代解析准确率 90% 听起来不错,但如果那 10% 的错误集中在高频代词“它”上,用户体验照样崩。要按代词类型分别看指标,高频词优先优化。

第二,别在冷启动阶段追求完美指代。新上线的对话系统,用户对话量少,焦点栈经常是空的,这时候代词解析失败很正常。与其硬猜,不如大方澄清,同时把澄清过程当成收集数据的机会——用户选了哪个候选,就是一条标注数据。

第三,中文的省略比代词更普遍。英文里用户会说 “what about tomorrow”,中文用户直接说“明天呢”,连“那”都省了。所以上下文管理模块里,省略补全的逻辑量级其实比代词解析更大,别把精力全押在代词上。

第四,测试集要专门构造指代密集的对话。常规的对话测试集里代词比例偏低,跑出来指标很好看,一上线就露馅。我一般会人工构造一批“每句都带代词或省略”的对抗性对话,专门压测上下文管理模块,这批数据往往能暴露八成以上的指代问题。

7. 往后看:指代处理会走向哪里

我个人在实际项目里的体会是,代词指代这件事,短期内不会被某个大模型“顺便解决掉”。大模型确实提升了单次指代解析的能力,但对话系统的指代问题本质上是状态管理问题,而状态管理需要显式的、可审计的结构,不能全靠模型隐式记忆。未来的方向我更看好“显式状态 + 模型解析”的混合架构——用焦点栈和意图图管住对话状态的骨架,用模型做候选匹配和置信度打分,两者各司其职。

另外一个小技巧分享给正在做这块的朋友:如果你不确定自己的指代处理够不够稳,拿一段真实用户对话日志,把里面所有代词圈出来,然后逐句问自己“系统在这一步能不能正确解析”,手工过一遍,比跑任何自动化指标都直观。我每次迭代上下文模块,都是先手工过五十条日志,再去看线上指标,两者对照着看,问题基本藏不住。

这个方向后续还可以往“跨会话指代”扩展——用户今天说“上次那个川菜馆”,系统能不能从历史会话里把实体捞回来。这就涉及长期记忆和短期上下文的衔接,是另一个值得单独拆开聊的话题了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询