乐于分享
好东西不私藏

Ai Agent意图识别方案设计

Ai Agent意图识别方案设计

背景

对于chatbot来说,意图识别的重要性不言而喻,相当于就是要识别用户聊天的意图,然后在做出回应,如果没有识别到用户的意图,做出来了的回应,大概率会让用户不满意。

方案设计

当前的方案实现属于方案4的简化版本:

规则匹配 + 轻量Prompt + LLM兜底,但是这个规则匹配呢,又有few-shot的使用

方案1:Few-shot +COT

Few-shot +COT, 用「给示例 + 思维链推理」的大模型方案,意图识别准确率确实很高.但是耗 token、响应慢、成本高,而且业务意图一多就容易乱、扛不住扩展.

1.1 Few-shot 是什么

就是少样本示例:你不是只给模型一条指令,而是手动塞3~10 条真实样例:用户问句 1 → 对应意图 A用户问句 2 → 对应意图 B……让模型照着你给的标准答案例子模仿分类。比如案例你现在负责用户意图分类,只能从下面5个意图里选一个:意图A:查询账户余额意图B:查询月度账单意图C:申请订单退款意图D:修改绑定手机号意图E:咨询优惠活动要求:先一步步推理分析用户诉求(CoT思维链),再输出最终意图。下面是参考示例(Few-shot 样例):【示例1用户:我想看看我卡里还有多少钱推理:用户核心是想知道自己账户剩余金额,不属于账单、退款、改手机号、活动,匹配查询余额最终意图:意图A【示例2用户:帮我看下这个月消费了多少账单推理:用户明确要看当月消费账单内容,不是查余额、退款、改手机、问活动,匹配查询月度账单最终意图:意图B【示例3用户:我买的东西不好用,我要退钱推理:用户诉求是对商品不满意,想要退款处理,匹配申请订单退款最终意图:意图C【示例4用户:我想把账号绑定的手机号换掉推理:用户需求是变更账号绑定的手机号码,匹配修改绑定手机号最终意图:意图D现在请按同样格式,处理新的用户问题:用户:最近平台有没有什么打折福利?

1.2 CoT 是什么

Chain of Thought 思维链:不让模型直接输出「意图结果」,而是要求它:先一步步分析理由,再给出最终意图。这一步相当于要求不能直接给出答案,必须先写推理思考过程。

1.3 为什么说准而且贵

  • :有样例 + 有推理,模糊口语、相近意图也不容易判错

  • 贵:

    • 示例里面的都要塞进去prompt,直接导致token变多

    • 模型还要输出一段推理文字,耗时更长,成本更高

    • 如果意图越来越多,prompt会越来越长,容易溢出,模型容易混淆

1.4 适用场景

chatbi里面的Nl2sql的实现

用户:统计每个省份昨天的订单量模型先推理:订单表是 order_table需要省份 province、订单 id、创建时间 dt过滤 dt = 昨天按省份分组、count 订单再输出完整 SQL。优势:不用写复杂 Prompt,小样本就能撑住几十种查询句式。

优势:不用写复杂 Prompt,小样本就能撑住几十种查询句式。

1.5 总结

  • 低成本快速MVP落地

  • 需要推理过程,可解释

  • 对意图识别准确性要求极高

方案2: 意图识别与槽位抽取串行

2.1 本质

  • 第一步:只做意图识别(先判断用户想干什么)

  • 第二步:按对应意图,专门抽取槽位参数(再提取需要的关键信息)

典型流水线 NLU 架构,是传统客服 / 对话系统最标准的落地范式

2.2 方案设计

步骤 1:第一轮 Prompt —— 只识别意图只给意图列表,不让模型抽参数,只输出意图名。你只负责识别用户意图,只能从下列列表选一个:1. 机票预订 2. 订单退款 3. 改手机号 4. 查账单只输出意图名称,不要多余内容。用户输入:我想明天从北京飞上海坐飞机步骤 2:后端映射槽位模板后台提前配置好:plaintext机票预订 = 必须槽位:出发地、目的地、日期、人数订单退款 = 必须槽位:订单号、退款原因步骤 3:第二轮 Prompt —— 只抽当前意图的槽位把当前意图 + 对应需要的槽位传给模型,专门做抽取:plaintext当前用户意图:机票预订需要抽取的字段:出发地、目的地、出行日期从用户句子里提取对应信息,输出JSON用户输入:我想明天从北京飞上海坐飞机整体链路(两轮LLM调用,两轮prompt)用户输入 → 调 LLM 判意图 → 后台匹配槽位配置 → 再调 LLM 抽槽位 → 结构化结果

2.3 完整落地实现

第 1 步:业务梳理
  1. 整理所有业务意图列表

  2. 每个意图定义专属槽位:必填、可选、默认值

  3. 定义槽位类型:地点、时间、手机号、订单号、金额等

示例配置表(后台配置化):

表格

意图
必填槽位
可选槽位
机票预订
出发地、目的地、日期
舱位、人数
订单退款
订单号
退款原因、金额
第 2 步:开发两层独立 Prompt / 模型
  • 层 1:意图识别专用 Prompt,只做分类

  • 层 2:槽位抽取通用 Prompt,动态传入当前意图 + 需要的槽位

第 3 步:开发后端调度逻辑
  1. 接收用户消息

  2. 第一次调用大模型,拿到意图

  3. 查配置表,拿到该意图所需槽位

  4. 第二次调用大模型,抽取槽位

  5. 做校验:缺失必填槽位 → 触发多轮追问

  6. 槽位齐全 → 交给业务接口执行

第 4 步:配置管理后台

支持可视化新增意图、新增槽位、绑定关系,不用改代码。

第 5 步:上线灰度 & 迭代

意图错了只优化意图 Prompt,槽位抽不准只优化抽取 Prompt,解耦维护

2.4 总结

  1. 两次 LLM 调用,延迟高、慢

  2. Token 消耗翻倍,调用成本变高

  3. 开发链路更长,比「一次 Prompt 搞定」重很多

  4. 当意图很少的时候,完全就复杂了

方案3:RAG 动态召回

3.1 本质

区别于方案 1 写死在 Prompt 里的静态 Few-shot

  • 方案 1:把所有意图示例全部硬塞进 Prompt,意图一多就超长、溢出、模型混淆崩盘;

  • 方案 3:把所有意图话术、历史问句、标准样例提前存进向量知识库,用户发一句,先语义检索召回最相似的 3~5 条真实案例(Top3查询)只把这几条相似案例动态塞进 Prompt,再让大模型判意图。

本质:不把所有例子全喂给模型,只喂和当前用户问题最像的几个例子,按需加载、动态匹配。

3.2 落地实现

3.2.1 语料准备阶段
梳理全量业务意图每个意图收集 30~50 条 真实用户口语、变体话术{query:"我想查这个月账单", intent:"查询月度账单"}{query:"帮我看下最近花了多少钱", intent:"查询月度账单"}{query:"本月消费明细在哪看", intent:"查询月度账单"}人工标注 问句→意图 标准对请根据参考样例,判断用户意图,只能从业务意图列表选一个。参考相似案例:1. 帮我看下最近花了多少钱 → 查询月度账单2. 本月消费明细在哪看 → 查询月度账单3. 查一下我近几月的消费记录 → 查询月度账单用户当前问题:我想看看最近几个月总共花了多少请输出唯一意图:
    3.2.2  向量库构建
    • 选用开源 Embedding:bge-small /m3e-small 等

    • 把所有标注问句批量向量化

    • 存入向量库,建立索引,绑定意图标签

    3.2.3 接口开发链路

    用户请求 → 生成用户问句向量 → 向量库语义检索 Top3 → 拼接轻量化 Prompt → 调用 LLM → 返回意图

    3.2.4 线上迭代闭环(关键)
    • 线上识别错误的 case,人工修正标注

    • 自动回流追加到向量知识库

    • 不用改代码、不用改 Prompt,越用越准

    3.2.5 可调优参数

    • 召回数量:Top3 / Top5 够用

    • 相似度阈值:低于阈值就不召回,走默认兜底意图

    • 定期清理无效、重复语料

    3.3 总结

    • 支持海量意图,越复杂越合适

    • 口语泛化能力拉满,未知的话术也能搞定

    • Prompt 轻量化,Token 开销低。

    • 可自动迭代,错判案例回流入库,持续优化

    追求低成本、高泛化、易维护的意图识别架构,以及海量意图,就可以。

    方案4. 多轮优化终极版

    4.1 本质

    1,2,3的方案都是单论对话,就是没有太多的上下文,就是单论思维,完全只顾回答当时这个问题,而且也不看之前的回答。

    4.2 整体流程

    用户多轮聊天输入→ 加载会话上下文记忆(记住上一轮聊了什么)→ RAG 动态语义召回(复用方案 3,扛住海量意图不崩盘)→ 意图与槽位解耦抽取(复用方案 2,精准拆意图 + 抽参数)→ 会话状态机判断(现在走到业务哪一步了)→ 槽位完整性校验(必填参数齐不齐)

    • 不齐 → 自动生成追问话术,主动问用户要信息

    • 有歧义 → 主动反问澄清

    • 用户中途改需求 → 识别打断、重置会话状态→ 参数齐全 → 调用业务接口→ 保存本轮会话状态 + 上下文,等待下一轮对话

    4.3  落地核心模块

    • 会话上下文记忆模块

      • 用户历史聊天记录

      • 上一轮识别的意图

      • 已经收集到的槽位参数

      • 当前业务走到哪个节点

    • RAG 动态意图识别层

    • 意图 — 槽位解耦抽取层

    • 会话状态机核心

      • 初始状态

      • 待收集出发地

      • 待收集目的地

      • 待收集日期

      • 确认订单

      • 办理完成

    系统知道现在卡在哪个步骤,不会乱跳转。

    • 兜底 & 异常自愈

    4.4 总结

    • 架构最重要同时搭:向量库、记忆模块、状态机、追问引擎、会话存储、话术配置中心,组件非常多

    • 开发成本极高要设计:意图体系、槽位体系、状态流转、追问话术、歧义规则、会话存储逻辑,代码量大、周期长

    • 性能 & 成本开销大每一轮对话都要:向量检索 + LLM 意图 + LLM 槽位 + 上下文拼接,延迟更高、Token 消耗更大、调用费用更高

    • 运维配置繁琐要维护:向量库、会话数据、状态配置、话术模板、版本迭代

    • 唯一支持复杂多轮会话,能理解指代、省略、上下文关联

    当前方案实现

    规则+LLM兜底,可以理解为方案4的极简版 + 方案1的Few-shot思想。 —— 用规则解决高频确定性场景,用轻量Prompt+Few-shot兜底长尾场景

    规则层实现,条件组合

    ```python# Layer 1: 规则匹配(高频场景)if self.cr_intention_rule(content):  # "can i see"等关键词    return 'content_request'# Layer 2: LLM兜底(长尾场景)prompt = """## Task分析对话上下文,判断意图...## Intent(14种定义)1. content_request - 明确要求看内容2. ppv_inquiry - 询问PPV...## Input{conversation}"""response = await llm.generate(prompt, temperature=0.1)```
    def cr_intention_rule(self, content: str) -> bool:    '''    1. 当 fan 明确表示想看内容时,意图为 content request    '''    cr_f_pattern = "|".join(        map(re.escape, ["can i see""i wanna see""i'd like to see""let me see""show me"]))    return re.search(cr_f_pattern, content)def rtp_intention_rule(self, pre_content: str, now_content: str) -> bool:    '''    1. 当 creator 发送了内容预告,fan 回复了表示准备解锁的内容时,意图为 ready to purchase    '''    rtp_c_pattern = "|".join(        map(re.escape, ["wanna see""want to see""show you""are you ready""are u ready"]))    rtp_f_pattern = "|".join(map(re.escape,                                 ["please""yes""ok""okay""yeah""ready""si""sure""definitely",                                  "show me",                                  "i would love to""i do""alright""let's see""let me see""send me",                                  "of course""go on"]))    return re.search(rtp_c_pattern, pre_content) and re.search(rtp_f_pattern, now_content)

    静态Few-shot思想实现,prompt定义了每种意图的样例标准

    fan_intention_prompt: |  ## Task  You are an intent classification assistant. Your job is to analyze the entire dialogue context between a fan and a creator, then determine the intent expressed in the fan’s last message. You must also classify the intended scene—either "chat" or "sale"from the fan’s perspective.  Use the full context (including the creator’s replies) to make your judgment. Focus only on the fan’s final message when assigning the label.  ## Intent      1.    content request – Fan explicitly asks to see or receive specific paid content (often sexual or suggestive).      2.    ppv inquiry – Fan asks about a previously sent pay-per-view (PPV) item.      3.    content menu inquiry – Fan requests the general list of available paid content or services.      4.    preview request – Fan asks for a sneak peek before deciding to purchase.      5.    price inquiry – Fan asks how much a certain type of content costs (not tied to an existing PPV).      6.    ready to purchase – Fan shows clear intent to buy or unlock content immediately. Note: not every “yes” means unlocking; must be judged with conversation history.      7.    commit to purchase later – Fan commits to purchase at a specific future time or condition.      8.    negotiation offer – Fan proposes a discount, bundle, or alternative payment arrangement. Must occur after content sales context, not just casual chat.      9.    objection – Fan rejects or declines a purchase offer.      10.   tip – Fan mentions tipping or sending money without requesting specific content.      11.   complaint – Fan expresses dissatisfaction or negative feedback about purchased content. Must occur after content sales context, not casual chat.      12. bond – Friendly, caring, or romantic messages with no sexual undertones.      13. tease – Playful or flirtatious remarks with mild sexual undertones, not explicit.      14. sexting – Explicit sexual communication with vivid descriptions of sexual acts, simulating direct sexual interaction.

    已经实现的

    • 分层拦截架构 —— 规则+LLM+兜底,工程上稳健

    • 轻量Few-shot Prompt —— 14种意图定义清晰

    • 简单上下文感知 —— 取最近4轮对话

    • 硬规则优化高频Case —— 省钱省token(同时响应速度快,Latency** | 规则:<1ms;LLM:~200ms)

    • 极低温度参数 —— temperature=0.1保证分类稳定