AI 碎片问句:规则前置过滤、LLM 语义补全与 JointBERT 联合抽取

结论先行:碎片问句处理不是让一个大模型包揽全部工作,而是用一套分层组合方案落地。先用零成本、毫秒级的规则过滤器拦截大部分流量;再把少数存在歧义、信息残缺的短句交给私有化小模型做语义补全和指代消解;最后让 JointBERT 一次推理同步完成意图分类与槽位抽取。

在智能客服、AI 问数、企业知识库问答、投研 AI 助手、AI 报告生成这类业务里,用户输入并不总是结构完整、语句通顺的标准问句,里面会混杂大量半截表述、简写缩写和指代模糊的短句。典型形态包括“它多少钱?”“什么时候发货?”“帮我查”这类内容。

如果直接把碎片文本送入 NLU 模型做识别,经常出现识别失败或结果偏移,下游数据查询、工具调用、报告生成链路会跟着异常。下面把整条链路每个环节的职责、设计考量和线上容易踩到的坑展开说明。

一、碎片问句为什么难

1.1 常见碎片输入类型

碎片文本的形态可以归纳为几类:

  • 超短无主体问句:“多少钱?”“产量呢?”,文本里缺少查询对应的目标对象。
  • 代词悬空:“它、这个、那个”单独出现,没有前置上下文,无法确定代词绑定的业务实体。
  • 半截名词片段:“明天上海到北京”“帮我查下”,句子语义没有收尾,用户诉求表达不完整。
  • 缺主体疑问句:“什么时候发车?”,自带疑问诉求,但文本内没有标注询问的目标载体。
  • 截断复制文本:末尾附着逗号、顿号、“和”这类连接词,代表输入中途中断,语句本身不闭合。

JointBERT 这类联合建模方案,需要依托完整句子的全局语义,才能稳定完成意图判定和实体边界定位。碎片文本普遍缺失主体信息,容易造成实体漏识别、代词绑定错乱,进而影响意图分类和整条下游链路。

1.2 单一模型方案各自的短板

纯关键词规则只能匹配固定话术模板,用户调整措辞后就无法识别诉求。仅靠 JointBERT 承载意图识别加槽位抽取,在完整问句上指标稳定,但面对碎片输入时 F1 会明显下滑。全链路大模型端到端方案虽然能力更强,但调用成本高、推理等待长,实体边界波动大,结果复现性差。

更合适的工程思路是把能力解耦分工:

完整问句

少量歧义碎片

用户输入

规则层
承载绝大多数常规请求

JointBERT
低延迟 / 低成本

私有化小 LLM
只做语义补全

结构化意图 + 槽位

这也是行业里比较经典的 BERT + LLM 两级架构:BERT 承接多数常规请求,保障低延迟、低成本;LLM 只处理少量歧义碎片和长尾难例。

二、整体链路:先过滤、后补全、再抽取

整条流水线分为三个阶段:

信息完备、实体明确

碎片文本、语义歧义

实体来自原文或历史

出现新增实体

用户原始输入

前置规则过滤器
特征打分 + 阈值判断
零成本 / 毫秒级响应

JointBERT
意图分类 + 槽位抽取

私有化小 LLM
语义补全 / 指代消解

补全后实体校验

标准化完整问句

丢弃 LLM 输出
使用原始文本

意图标签 / 置信度 / 结构化槽位

意图路由 / 工具调用 / 数据查询 / 报告生成

规则层管控流量规模、压低整体运行成本;LLM 只负责歧义补全这一项工作;JointBERT 稳定输出结构化的意图与槽位结果。三者的边界越清晰,线上问题越容易定位。

三、阶段一:前置规则过滤,第一道成本防线

规则模块本质上是特征打分机制加阈值判定逻辑,不加载任何 AI 模型,只依赖字符串匹配、词表匹配和文本长度统计完成运算,响应时长维持在毫秒级。

它的定位是优先放行不需要补全的正常问句,减少 LLM 调用总量。规则体系无法覆盖全部隐性歧义场景,漏判样本会沉淀为坏案例,后续再依托坏案例持续迭代规则。

3.1 落地可用的判断特征

特征 1:文本长度。

文本长度小于 6 个字为高风险碎片;6 到 15 个字为中风险;大于 15 个字为低风险。例如“多少钱?”只有 4 个字,属于高风险;“明天上海到北京的高铁”共 12 个字,承载的信息相对完整。

特征 2:孤立代词检测。

代词黑名单包括 ["它","这","那","这个","那个","它们","他","她","它的"]。句子里包含代词、同时没有业务实体时,代表上下文缺失,需要送入 LLM 补全。区分示例:

  • “它的发车时间?”包含代词、不存在实体,应流转至 LLM。
  • “上海到北京的高铁,它的发车时间?”代词搭配实体同步出现,可以直接放行。

特征 3:无核心诉求的半截短句。

维护业务诉求词白名单,例如 ["查","订","买","缴费","转账","查询","生成","介绍","时间","价格"]。短句内不存在诉求词,就判定为碎片样本。

特征 4:疑问词开头、缺少查询主体。

疑问词集合包括 ["为什么","怎么","多少","何时","哪","啥"]。例如“什么时候发车?”以疑问词开头,句子内部没有实体主体,属于碎片样本。

特征 5:业务实体词表匹配。

实体词表来自 NLU 对应的业务 schema,包含车次、地点、账单类型、账户类型等内容。句子命中实体时,上下文信息充足的概率更高;没有命中实体,同时叠加任意一类风险特征,就判定为碎片样本。

词表冷启动阶段可以直接复用 JointBERT 训练集里提取出来的实体;线上持续运行时,再自动扩充词表内容。

特征 6:末尾截断标记。

匹配句子末尾的逗号、顿号、“和”“以及”“还有”,代表输入存在截断。例如“上海到北京和”属于截断类型的碎片样本。

3.2 打分策略与阈值判定

初始分数 score = 0,按下面规则累加:

  • 文本长度小于 6:加 3。
  • 6 到 15 个字,并且没有命中实体:加 2。
  • 包含代词,并且没有实体:加 4。
  • 疑问词开头,并且没有实体:加 3。
  • 末尾存在截断标记:加 3。

阈值判断为总分大于等于 4 时送入 LLM 补全;低于 4 时直接放行给 JointBERT。

是

否

输入问句

score = 0

长度小于 6
+3

6~15 字且无实体
+2

代词且无实体
+4

疑问词开头且无实体
+3

末尾截断
+3

汇总 score

score 是否大于等于 4

送入私有化小 LLM 补全

直接送入 JointBERT

示例推演:

  • “它多少钱?”:长度小于 6 加 3,代词无实体加 4,总分 7,流转至 LLM。
  • “明天上海到北京的高铁”:命中实体,不存在风险特征,0 分,直接送入 JointBERT。
  • “什么时候发车?”:疑问词开头无实体加 3,总分 3,规则放行,属于规则覆盖盲区,后续依靠坏案例迭代优化。
  • “上海到北京和”:截断标记加 3,总分 3,分值贴近阈值,可按业务诉求调整。

阈值支持动态调整:想压低 LLM 调用量,可调整到 5 或 6;想减少漏判、接受更高 LLM 开销,可调整到 3。

3.3 参考伪代码

pronouns = {"它","这","那","这个","那个","它们","他","她","它的"}
question_words = {"为什么","怎么","多少","何时","哪","啥"}
cutoff_suffix = {"和","以及","还有",",",","}
entity_vocab = {"上海","北京","高铁","动车","电费","储蓄卡"}
threshold = 4

def need_llm_rewrite(text: str) -> bool:
    score = 0
    text = text.strip()
    l = len(text)

    # 长度打分
    if l < 6:
        score += 3
    elif 6 <= l <= 15:
        has_entity = any(ent in text for ent in entity_vocab)
        if not has_entity:
            score += 2

    # 代词 + 无实体
    has_pronoun = any(p in text for p in pronouns)
    has_entity = any(ent in text for ent in entity_vocab)
    if has_pronoun and not has_entity:
        score += 4

    # 疑问词开头无实体
    for qw in question_words:
        if text.startswith(qw) and not has_entity:
            score += 3
            break

    # 截断后缀
    for suf in cutoff_suffix:
        if text.endswith(suf):
            score += 3
            break

    return score >= threshold

3.4 规则缺陷与迭代方案

规则体系无法覆盖全部隐性歧义场景,难免出现漏判。拿“什么时候开始?”举例,计算得到的分值可能不满足阈值条件,系统直接放行,JointBERT 识别不到对应实体,整条链路就会失效。

处理方式是埋点采集日志,收集两类样本:

  • 规则放行、但 JointBERT 意图识别置信度偏低且槽位为空的样本,也就是规则没有捕获到的歧义句子。
  • 判定为碎片并进入 LLM 补全的样本,用于复盘规则触发是否合理。

定期复盘这批样本,补充实体词表、新增判断规则,或直接存入坏案例兜底池。实体词表冷启动时,可以临时下线实体匹配打分项,只靠长度、代词、疑问词判断,代价是 LLM 调用量上升;线上异步采集 JointBERT 识别出的实体后,再自动入库扩充词表。

3.5 可选进阶优化

常规业务场景下,这套打分规则的稳定程度已经足够。若需要进一步增强,可以接入轻量二分类模型,例如 FastText,用几百条标注样本训练,标签分为 0 = 无需补全、1 = 需要补全。这属于非必需优化,不改变主链路结构。

四、阶段二:LLM 语义补全,私有化小模型

只有被规则判定为碎片、存在歧义的输入,才会进入 LLM 语义补全模块。它的职责是依托用户原文补齐上下文、消除指代歧义,输出标准化问句,同时严格禁止编造原文不存在的业务信息。

这是整条链路里唯一的生成式环节,也是幻觉风险集中的位置。Prompt 的约束力度和输出校验逻辑,直接决定补全结果会不会对下游 JointBERT 抽取形成负面干扰。

4.1 Prompt 设计与约束:分域输入 + few-shot 样例

早期 Prompt 更适合大模型零样本调用,直接投喂给 1.5B 到 7B 的私有化小模型时,约束被击穿的概率偏高。主要问题有:

  • 没有把对话历史作为独立输入域,模型无法区分“可信上下文”和“禁止脑补的空白信息”。
  • 多条否定式约束堆叠,小参数模型对长负向指令的遗忘概率很高。
  • 缺少标准正负样例,容易出现过度改写、替换诉求词或凭空生成业务实体。
  • 没有强制极简输出,模型偶尔带出解释性文字,导致下游解析失败。

因此,需要把 Prompt 替换为分域输入加 few-shot 约束的版本,并配套低采样参数 temperature = 0.1、top_p = 0.3,再结合后端实体校验形成双层防护。

无

有

实体来自原文或历史

出现新增实体

碎片问句

是否有可信对话历史

单轮 Prompt
最小修改 / 禁止编造 / 极简输出

多轮 Prompt
历史上下文 + 指代消解

私有化小模型
1B~7B + 4bit 量化

规整问句

补全后实体校验

送入 JointBERT

丢弃 LLM 输出
使用原始文本

第一套是单轮版本,默认无历史上下文,绝大多数流量走这一条:

【System Prompt】
你的任务:碎片问句规范化、指代消解,仅做最小修改,禁止新增任何原文不存在的业务实体。
规则(严格按顺序执行):
(1) 只修改悬空代词,不新增地点、车次、金额、账单、时间等实体;没有可信上下文,就保留代词原样,绝不猜测指代对象;
(2) 不改动用户原始查询意图、不替换诉求动词;
(3) 只输出一句规整问句,不加任何解释、备注、引号、markdown;
(4) 如果信息不足无法消解指代,原样返回输入文本。

参考样例:
输入:它多少钱?
输出:它多少钱?
输入:什么时候发车?
输出:什么时候发车?
输入:上海到北京和
输出:上海到北京和
输入:这个订单什么时候发货?
输出:这个订单什么时候发货?

原始问句:{input_text}
输出规范问句:

第二套是多轮上下文版本,只有上游取出对话历史缓存并命中时才启用,分流小部分流量:

【System Prompt】
你的任务:依托提供的可信对话历史,对当前碎片问句做指代消解与规范化。
约束:
(1) 实体只能来自【对话历史】+【当前原始问句】,历史里没有的实体,绝对不能编造;
(2) 只替换悬空代词,最小改动句子,不改变用户诉求;
(3) 历史信息不足以确定指代对象时,原样返回原始问句,禁止脑补;
(4) 仅输出规整后的问句,无额外文字。

参考样例:
对话历史:用户刚才问了上海到北京的高铁
当前输入:它几点发车?
输出:上海到北京的高铁几点发车?

对话历史:无有效业务实体
当前输入:它多少钱?
输出:它多少钱?

【User Prompt】
对话历史(可信上下文):{context_history}
当前原始问句:{input_text}
输出规范问句:

推理参数固定如下,进一步压低幻觉概率:

temperature = 0.1
top_p = 0.3
max_new_tokens = 60
do_sample = False

配套示例:输入“它今天发车时间多少?”,在缺少上下文时,合规输出就是原样返回“它今天发车时间多少?”;如果上游存在缓存上下文可以匹配,才输出“上海到北京的高铁今天发车时间多少?”。

补全完成后必须配套实体校验:拿补全后的句子和原始输入、历史上下文实体集合比对,只要出现原文和历史都不存在的实体,就判定为幻觉,丢弃 LLM 输出,降级使用原始文本送入 JointBERT。

4.2 模型选型策略

这个任务属于短输入、短输出场景,不需要复杂推理和超长上下文,优先选择 1B 到 7B 参数规模模型,搭配 4bit 量化,上限锁定在 7B,不建议上 70B 规模的大模型。

量化优先选择 AWQ、GPTQ 4bit 方案,显存占用可以直接减半。具体选择如下:

模型适用场景
Qwen2-1.5B-Instruct(4bit)中文理解良好,显存占用 1~2GB,适合验证环境
Qwen2-7B-Instruct(4bit)复杂歧义处理更强,显存占用 4~5GB,适合线上生产
Llama3.2-3B、Gemma2-2B中文能力偏弱,一般适合英文业务场景
T5、Bart(Seq2Seq)推理成本更低,但需要针对性微调

34B、70B 大模型在短句补全场景里能力过剩,还会失去私有化部署降本的意义。

4.3 硬件与推理优化方案

以 Qwen2-1.5B-Instruct AWQ 4bit 为例:

  • 最低验证配置:单卡显存至少 2GB;CPU 只适合低流量测试,不能投入生产环境。
  • 线上并发:单张 RTX4090 可以支撑几十路短句补全请求。
  • 云服务器选型:优先选择 A10、T4、L4 推理卡,不需要选用昂贵的 A100。
  • 推理框架:优先使用 vLLM、SGLang、llama.cpp,不要直接使用原生 Transformers;vLLM 的 PagedAttention 在短生成场景中 QPS 提升明显。
  • 参数控制:max_new_tokens = 40~60,限制输出长度,规避冗余生成。
  • 缓存机制:重复碎片问句直接返回缓存结果,减少重复推理。

私有化部署对比商用 API:商用 API 按 token 或调用次数计费;私有化部署是一次性硬件投入,流量规模越大,单条请求分摊成本越低。高流量场景里,两者成本差距可以达到几十倍。

4.4 降本组合策略

  • 前置规则过滤保持不变,70% 以上流量可以直接跳过 LLM,这是最关键的降本抓手。
  • 严格限制生成 token 长度,降低算力消耗。
  • 量化加高性能推理框架组合,拉高单卡吞吐量。
  • 开启请求缓存,高频重复问句不再触发模型推理。
  • 开启动态批处理,短文本适合攒批推理,提升显卡利用率。

4.5 模型短板与兜底策略

低成本小模型有两个明确短板:

  • 幻觉问题:模型容易编造实体。依靠 Prompt 约束加实体校验机制,校验不通过时直接降级返回原始文本。
  • 复杂歧义能力上限不足:多层指代、表述绕口的碎片样本,1.5B 模型容易出现补全错误。处理方案是增加质量校验逻辑,异常输出自动降级,并预留少量路由配额,把极少数高难度样本转发 7B 模型兜底。

4.6 分阶段上线路线

  • 验证期:Qwen2-1.5B-Instruct 4bit 加 llama.cpp 或 vLLM,低配资源部署,只处理碎片问句,统计补全效果和幻觉率。
  • 稳定生产:1.5B 模型效果不满足诉求时,升级 Qwen2-7B-Instruct 4bit。
  • 长期演进:积累足量“原始碎句 -> 标准问句”平行样本后,微调 T5 或 Bart 替换 LLM,推理成本可以贴近 JointBERT 水平。

这个场景只有少量流量会进入 LLM 补全环节,Qwen2-1.5B-Instruct 4bit 私有化方案性价比更高、硬件门槛偏低;追求更高稳定性时可升级 7B 版本,仍属于低成本私有化路线。

五、阶段三:JointBERT,一次推理完成意图分类与槽位抽取

输入经过放行或 LLM 补全后,语句完整、主体清晰,送入 JointBERT 开展意图识别与槽位抽取。这个模块是整条链路的 NLU 结构化出口,输出意图标签与 BIO 槽位,给下游工具调用、业务路由使用。

选择 JointBERT 而不是独立 BERT-NER 或 LLM 抽取,核心考量是低延迟、低成本以及双任务互相增益,适配高并发线上服务。

规整问句

共享 BERT / RoBERTa 编码器

[CLS] 句向量

token 向量

意图分类

BIO 序列标注

CRF 标签纠错

意图 / 置信度 / 结构化槽位

下游路由与业务调用

5.1 模型选型思路

JointBERT 属于多任务联合建模方案,共享同一个 BERT 或 RoBERTa 编码器,一套基座同时承载两项任务:

  • 提取句子向量,完成整句意图分类。
  • 提取每个 token 向量,完成 BIO 格式槽位序列标注,并叠加 CRF 模块完成标签语法纠错。

两项任务互相提供监督信号,通过自注意力机制实现语义互通,效果通常优于分开训练的独立模型,同时显存占用和推理延迟可以缩减一半。

模型选择建议:

  • 基线版本:chinese-roberta-wwm-ext 加 CRF,全词掩码机制对中文词汇识别更友好。
  • 长尾复杂样本:可选用 DeBERTa-v3-base。
  • 资源极度受限:可降级为 BiLSTM-CRF。

一般不建议用 LLM 做主链路 NLU,因为推理成本偏高、输出波动大,很难开展稳定指标回归。LLM 只保留作为低置信难例的兜底通道。

5.2 训练阶段要点

训练启动前先对齐业务 NLU schema,稳定意图标签和槽位定义,保障标签互斥、粒度可控。标注统一采用“文本 + 意图标签 + BIO 槽位标签”格式,样本优先取用线上真实日志,混入一部分经过 LLM 补全后的标准问句。

配套银行、订票场景的意图与槽位示例:

类型标签
意图标签query_balance、transfer、BookTrain、pay_bill
槽位标签amount、payee、depart_time、from_loc、to_loc、bill_type

训练配套数据增强时,可使用模板生成、同义词替换、大模型辅助扩充样本,但要控制增强带来的噪声。训练使用加权联合损失,搭配梯度裁剪和早停策略。训练完成后留存一套固定测试集,长期保持不变,后续每次迭代都在同一套测试集上运行意图准确率、槽位 P/R/F1,监控模型退化。

5.3 线上推理链路设计

JointBERT 服务独立部署,和 LLM 补全服务解耦,分开扩缩容。预处理采用 FastTokenizer 加 offset 映射,解决子词拆分和原始文本位置对齐问题。模型导出 ONNX 格式,CRF 解码逻辑放到业务层执行,规避 ONNX 动态循环导出的限制;通过 ONNX Runtime 或 Triton 部署,支持动态 batch、FP16 加速,单条推理延迟控制在百毫秒以内。

输入是规整后的问句,输出结构化 JSON。以下面这条补全问句“帮我查下明天上海到北京的高铁”为例:

{
  "intent": "BookTrain",
  "score": 0.97,
  "slots": [
    {"text": "明天", "start": 4, "end": 6, "type": "depart_time", "score": 0.97},
    {"text": "上海", "start": 6, "end": 8, "type": "from_loc", "score": 0.97},
    {"text": "北京", "start": 9, "end": 11, "type": "to_loc", "score": 0.96},
    {"text": "高铁", "start": 12, "end": 14, "type": "train_type", "score": 0.96}
  ]
}

下游拿到意图和槽位后,填充业务槽位,调用订票接口获取数据。

置信度分流策略:

  • 高置信度:直接放行。
  • 中置信度:触发澄清追问。
  • 低置信度:送入 LLM 兜底识别。

5.4 监控与 badcase 回流

监控看板持续观测核心指标:意图识别准确率、槽位抽取空值率、各类槽位召回率、精确率、平均置信度、推理耗时。

识别失败、意图判错、槽位边界切错的样本自动落库作为 badcase。定期批量复盘,补充到标注池,增量微调 JointBERT。链路还需要兜底分支:低置信度样本自动切换到 LLM 识别;关键槽位缺失时返回友好提示,引导用户补充信息,尽量不直接抛异常。

5.5 评测标准

评估不能靠主观感受。固定测试集上重点看四项内容:

  • 意图分类是否准确。
  • 实体起止位置是否准确。
  • 实体分类是否正确。
  • 整体意图准确率与槽位 P/R/F1 指标。

六、上线高频坑点与应对方案

坑点应对方案
LLM 幻觉编造实体Prompt 约束加补全后实体校验,识别新增实体时直接降级
实体词表冷启动为空初期临时关闭实体匹配打分项,先验证链路;异步采集 JointBERT 识别结果扩充词表
阈值调优没有参考依据监控 LLM 触发率、槽位空识别占比、规则漏判率,依托线上数据迭代打分权重和阈值
子词对齐错误使用 BertTokenizerFast 加 return_offsets_mapping,通过字符 offset 完成槽位对齐
CRF 标签非法序列CRF 层自动学习标签转移规则,过滤 I 标签前置 O 的非法 BIO 序列
置信度阈值一刀切按验证集置信度分布划分高、中、低三档,中置信度触发澄清,低置信度流转 LLM 兜底

七、方案适用边界

适合场景:

  • 用户碎片化输入占比偏高。
  • 实体 Schema 固定。
  • 对延迟和成本敏感。
  • 需要稳定、可观测的抽取链路。
  • 典型业务包括 AI 问数、智能客服、知识库问答、订票缴费类对话系统。

不适合场景:

  • 业务实体变更频率很高。
  • 标注样本数量偏少。
  • 用户输入全部是完整问句,甚至可以移除 LLM 补全模块。
  • 需要快速验证原型的场景,直接采用 LLM 端到端抽取更省事。

AI 方案不存在绝对标准的答案,选型是否合适,需要依托测试集指标和线上真实数据验证。

结语

碎片问句处理是一套分层组合方案,而不是依靠一个大模型包揽全部工作:

削减 LLM 调用量

处理歧义补全

稳定输出

前置规则过滤

低成本 / 低延迟

私有化小模型

结构化输入质量

JointBERT

意图 + 槽位

可观测、可持续迭代的 NLU 链路

前置规则过滤削减 LLM 调用量,私有化小模型低成本处理歧义补全,JointBERT 稳定输出结构化意图与槽位。三者配合,才能在控制成本的同时,让碎片问句真正进入可运营、可迭代的工程体系。

Logo

更多推荐