目录

第二章 AI Agent 意图识别 & 槽位抽取(可落地 Python 实现|原理精讲 + 多套方案 + 完整代码)

本章前置说明

1、模块定位

2、两套落地方案(按需选用)

3、依赖补充安装

4、承接上一章

第一节 基础概念通俗讲解

1)意图

2)槽位(实体参数)

3)拒识判定

4)歧义消解

方案一:LLM 结构化意图 + 槽位抽取(工程首选,带 Pydantic 强格式约束)

1、原理

2、完整代码 + 逐段注释

3、运行结果说明

4、落地优势

.env 配置文件示例(同级目录新建.env)

方案二:规则化意图 + 槽位抽取(无模型、纯代码兜底方案)

1、适用场景

规则方案优缺点总结

第三节 融合架构:LLM 主解析 + 规则兜底(生产最终封装类)

第四节 模块输出格式 & 向下游交付标准

第五节 生产环境优化点

本章整体数据流链路


本章前置说明

1、模块定位

预处理层输出干净、规整文本 → 送入本章模块。 本章是 Agent 的决策大脑入口,解决两个核心问题: 1)意图识别:用户究竟要做什么事(分类问题);区分单意图、多意图、无效指令拒识 2)槽位抽取:完成这件事必须的关键参数(时间、文件、部门、渠道、格式、人员等) 搭配:歧义消解 + 非法指令拒识,保证 Agent 不乱执行、不瞎调用工具

2、两套落地方案(按需选用)

方案 技术 适用场景 优点 缺点
方案一:Prompt 大模型原生抽取(优先业务落地) LLM API / 本地 LLM 结构化输出 90% 办公 Agent、快速开发迭代 不用标注数据、适配复杂口语、多意图天然支持 有少量调用成本,需要约束输出格式
方案二:轻量规则 + 正则 + 实体匹配(兜底低成本) 正则字典 + 实体关键词库 固定办公指令、低并发、无模型依赖 零成本、响应毫秒级、稳定可控 复杂句式、模糊语句识别差

企业标准落地架构:LLM 方案做主逻辑,规则方案做兜底校验

3、依赖补充安装

# 若使用本地大模型调用
pip install openai python-dotenv pydantic
# 规则匹配辅助库(可选)
pip install pyparsing

4、承接上一章

导入第一章的预处理总类,代码文件建议把第一章代码放在preprocessor.py,本章新建intent_slot.py


第一节 基础概念通俗讲解

1)意图

办公常用意图集合(办公 Agent 通用枚举)

EXPORT_FILE(导出文件)、IMPORT_DATA(导入数据)
SEND_MESSAGE(消息推送)、QUERY_DATA(数据查询)
GENERATE_DOC(生成公文/报表)、FILE_UPLOAD(文件上传OA)
TABLE_CALC(表格计算)、NONE(无效/非法指令)
  • 单意图:「导出 7 月营收报表」→ 只有 EXPORT_FILE
  • 多意图:「导出 7 月营收报表并且发送到部门企微群」→ EXPORT_FILE + SEND_MESSAGE

2)槽位(实体参数)

执行意图必备的变量,没有槽位任务无法执行 通用办公槽位定义:

槽位 Key 含义 示例值
time_range 时间范围 上个月、2026 年 7 月、Q2 季度
file_name 文件名称 / 类型 营收台账、月度报表、excel
target_dept 目标部门 财务部、市场部
send_target 发送对象 企微群、OA 审批人、张三
file_format 文件格式 xlsx、pdf、word
data_scope 数据范围 全公司、驻马店片区

3)拒识判定

识别广告、乱码、无关闲聊、越权指令,直接拦截不进入后续任务规划

4)歧义消解

模糊语句补全:「整理一下表格」结合上下文自动补全 = 整理上月业务表格


方案一:LLM 结构化意图 + 槽位抽取(工程首选,带 Pydantic 强格式约束)

1、原理

使用Pydantic固定返回 JSON 结构体,强制 LLM 必须按照固定格式输出,杜绝自由文本乱输出; 同时在 Prompt 内置意图枚举、槽位规则、拒识规则、多意图拆分逻辑。 支持:本地 Qwen/Llama、OpenAI、DeepSeek、Ollama 全部大模型统一适配。

2、完整代码 + 逐段注释

from openai import OpenAI
from pydantic import BaseModel, Field
from typing import List, Optional, Dict
import os
from dotenv import load_dotenv

# 加载环境变量,存放模型密钥、地址
load_dotenv()

# ========== 1、定义标准化输出结构体(强约束,LLM必须按这个格式返回) ==========
class SingleIntent(BaseModel):
    intent_name: str = Field(description="意图标识,只能从枚举取值")
    intent_desc: str = Field(description="该意图简单中文描述")

class SlotInfo(BaseModel):
    slot_key: str = Field(description="槽位字段key")
    slot_value: Optional[str] = Field(description="提取到的槽位值,无则为空字符串")

class IntentSlotResult(BaseModel):
    intent_list: List[SingleIntent] = Field(description="解析出的意图列表,支持多个意图")
    slot_list: List[SlotInfo] = Field(description="所有提取的槽位参数")
    is_reject: bool = Field(description="是否需要拒识,true=拒绝执行指令")
    reject_reason: str = Field(description="拒识原因,无需拒识填空")
    resolve_ambiguity_text: str = Field(description="歧义消解后的标准化用户指令")

# ========== 2、配置大模型通用客户端(兼容Ollama本地模型) ==========
class LLMIntentExtractor:
    def __init__(self):
        self.client = OpenAI(
            base_url=os.getenv("LLM_BASE_URL", "http://localhost:11434/v1"),
            api_key=os.getenv("LLM_API_KEY", "dummy-key")
        )
        self.model_name = os.getenv("LLM_MODEL", "qwen3.5:9b")
        # 固定意图枚举池,LLM只能选用这里面的值
        self.intent_enum = [
            "EXPORT_FILE", "IMPORT_DATA", "SEND_MESSAGE", "QUERY_DATA",
            "GENERATE_DOC", "FILE_UPLOAD", "TABLE_CALC", "NONE"
        ]
        # 固定槽位枚举池
        self.slot_enum = [
            "time_range", "file_name", "target_dept",
            "send_target", "file_format", "data_scope"
        ]

    def build_system_prompt(self) -> str:
        """构造系统提示词,写入全部业务规则"""
        prompt = f"""
你是办公AI Agent的意图&槽位解析器,严格遵守下面所有规则:
## 固定意图列表(只允许输出这里面的值)
{self.intent_enum}
NONE代表:闲聊、无意义语句、违规指令、无法执行的请求,此时is_reject必须=true

## 固定槽位列表(只允许提取这些key)
{self.slot_enum}
1. time_range:所有时间相关描述
2. file_name:文件名称、报表、台账、文档类型
3. target_dept:部门名称
4. send_target:消息发送的群、人员、系统
5. file_format:导出文件格式xlsx/pdf/word
6. data_scope:数据所属范围片区、分公司

## 强制规则
1. 用户一句话包含多个动作,拆分出多个intent放入intent_list
2. 存在语句模糊、指代不明,在resolve_ambiguity_text做语句补全标准化
3. 提取不到对应槽位时slot_value填空字符串
4. 广告、聊天、骂人、系统控制类指令一律拒绝执行
5. 输出必须严格符合给定的JSON格式,禁止额外解释文字
        """
        return prompt

    def extract(self, clean_text: str) -> IntentSlotResult:
        """对外统一抽取入口"""
        resp = self.client.beta.chat.completions.parse(
            model=self.model_name,
            messages=[
                {"role": "system", "content": self.build_system_prompt()},
                {"role": "user", "content": f"用户标准化指令:{clean_text}"}
            ],
            response_format=IntentSlotResult
        )
        # 解析结构化对象
        result = resp.choices[0].message.parsed
        return result

# ========== 测试调用(对接第一章预处理结果) ==========
if __name__ == "__main__":
    # 模拟上一章预处理输出的干净文本
    test_text_1 = "导出2026年7月财务部营收台账,文件格式为xlsx,发送到财务部企业微信群"
    test_text_2 = "今天晚饭吃什么,帮我推荐电影"
    test_text_3 = "整理一下表格"  # 歧义语句

    extractor = LLMIntentExtractor()

    print("=====测试用例1:正常多意图指令=====")
    res1 = extractor.extract(test_text_1)
    print(res1.model_dump_json(indent=2))

    print("\n=====测试用例2:闲聊内容(拒识)=====")
    res2 = extractor.extract(test_text_2)
    print(res2.model_dump_json(indent=2))

    print("\n=====测试用例3:模糊歧义语句=====")
    res3 = extractor.extract(test_text_3)
    print(res3.model_dump_json(indent=2))

3、运行结果说明

  1. 正常业务语句:输出 2 个意图(导出文件 + 发送消息),自动填充全部时间、文件、格式、发送对象槽位
  2. 闲聊语句:is_reject=true,上层 Agent 直接终止流程,返回拒绝理由
  3. 模糊语句:resolve_ambiguity_text自动补全语义,消除歧义

4、落地优势

  1. Pydantic + parse 模式,LLM 输出格式 100% 可控,不会出现 JSON 解析报错
  2. 更换本地 Ollama/Qwen、云端 DeepSeek/OpenAI 只需要改.env 配置,代码无需改动
  3. 新增意图、新增槽位只需要修改枚举列表,扩展性极强

.env 配置文件示例(同级目录新建.env)

# Ollama本地部署默认地址
LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=dummy-key
LLM_MODEL=qwen3.5:9b

方案二:规则化意图 + 槽位抽取(无模型、纯代码兜底方案)

1、适用场景

简单固定指令、对内标准化办公话术、边缘低配置服务器不想跑大模型;用作 LLM 解析失败时的降级兜底。 原理:关键词匹配判定意图 + 正则表达式捕获时间、文件、格式等实体槽位。

import re
from typing import Dict, List

class RuleIntentSlot:
    def __init__(self):
        # 意图关键词映射
        self.intent_key_map = {
            "EXPORT_FILE": ["导出", "下载", "另存为", "输出报表"],
            "SEND_MESSAGE": ["发送", "推送", "发到", "转发"],
            "GENERATE_DOC": ["生成", "制作", "整理文档", "编写台账"],
            "QUERY_DATA": ["查询", "查看", "获取数据", "统计"],
            "FILE_UPLOAD": ["上传", "提交OA"],
            "TABLE_CALC": ["计算", "求和", "汇总表格"]
        }
        # 正则规则
        self.patterns = {
            "time_range": re.compile(r"(20\d{2}年[0-9]{1,2}月|上个月|上季度|Q[1-4]|本周|昨日)"),
            "file_format": re.compile(r"xlsx|excel|pdf|word|docx"),
            "dept": re.compile(r"(财务部|市场部|人事部|运维部)")
        }
        # 拒识关键词库
        self.reject_words = ["吃饭", "电影", "游戏", "聊天", "解封", "破解"]

    def match_intent(self, text: str) -> List[str]:
        """关键词匹配获取所有命中意图"""
        hit_intents = []
        for intent, keywords in self.intent_key_map.items():
            for kw in keywords:
                if kw in text:
                    hit_intents.append(intent)
                    break
        return hit_intents if hit_intents else ["NONE"]

    def extract_slot(self, text: str) -> List[Dict]:
        slot_res = []
        for slot_key, pat in self.patterns.items():
            match = pat.search(text)
            val = match.group() if match else ""
            slot_res.append({"slot_key": slot_key, "slot_value": val})
        return slot_res

    def check_reject(self, text: str) -> (bool, str):
        for word in self.reject_words:
            if word in text:
                return True, f"命中闲聊词汇:{word},拒绝执行"
        return False, ""

    def run_all(self, clean_text: str) -> Dict:
        intents = self.match_intent(clean_text)
        slots = self.extract_slot(clean_text)
        is_rej, rej_reason = self.check_reject(clean_text)
        return {
            "intent_list": intents,
            "slot_list": slots,
            "is_reject": is_rej,
            "reject_reason": rej_reason,
            "resolve_ambiguity_text": clean_text
        }

# 规则方案测试
if __name__ == "__main__":
    rule_parser = RuleIntentSlot()
    text = "导出7月财务部报表为pdf格式并发送到工作群"
    res = rule_parser.run_all(text)
    import json
    print(json.dumps(res, ensure_ascii=False, indent=2))

规则方案优缺点总结

  • 优点:零推理耗时、无模型依赖、服务稳定,做降级保护绝佳
  • 缺点:复杂口语、倒装句识别很差,只能覆盖标准话术

第三节 融合架构:LLM 主解析 + 规则兜底(生产最终封装类)

生产环境不能只依赖 LLM(网络波动、模型离线会直接崩),做双层防护: 优先调用 LLM 抽取 → LLM 异常 / 超时自动切规则解析兜底

from preprocessor import AgentInputPreprocessor  # 导入第一章预处理类

class UnifiedIntentSlotParser:
    def __init__(self):
        self.llm_parser = LLMIntentExtractor()
        self.rule_parser = RuleIntentSlot()
        self.preprocessor = AgentInputPreprocessor()

    def parse_full(self, raw_user_input: str):
        # 步骤1:先走第一章预处理清洗文本
        pre_data = self.preprocessor.process_text_input(raw_user_input)
        clean_txt = pre_data["norm_text"]
        try:
            # 优先LLM方案
            llm_result = self.llm_parser.extract(clean_txt)
            return {
                "source": "llm",
                "preprocess_data": pre_data,
                "intent_slot_data": llm_result.model_dump()
            }
        except Exception as e:
            # LLM报错降级到规则方案
            print(f"LLM解析异常,切换规则兜底,异常信息:{str(e)}")
            rule_result = self.rule_parser.run_all(clean_txt)
            return {
                "source": "rule_backup",
                "preprocess_data": pre_data,
                "intent_slot_data": rule_result
            }

# 整条链路串联测试(原始输入 → 预处理 → 意图槽位解析)
if __name__ == "__main__":
    parser = UnifiedIntentSlotParser()
    user_input = "呃导出2026年7月财务部营收台账,输出为xlsx文件发送到财务部企微群"
    final_out = parser.parse_full(user_input)
    import json
    print(json.dumps(final_out, ensure_ascii=False, indent=2))

第四节 模块输出格式 & 向下游交付标准

本模块输出结构体,固定传递给第三章【记忆模块】、第四章【任务规划】

{
  "source": "llm/rule_backup",
  "preprocess_data": {清洗文本、语种信息},
  "intent_slot_data": {
    "intent_list": ["EXPORT_FILE", "SEND_MESSAGE"],
    "slot_list": [各个参数键值对],
    "is_reject": false,
    "reject_reason": "",
    "resolve_ambiguity_text": "标准化后的用户指令"
  }
}

上层拿到数据后:

  1. is_reject = True:直接回复用户拒绝提示,流程终止
  2. is_reject = False:把意图 + 槽位送入会话记忆、任务拆解模块

第五节 生产环境优化点

  1. 给 LLM 调用增加超时时间、重试次数,防止模型卡死
  2. 自建业务词库,定期扩充意图、槽位关键词
  3. 增加槽位校验:必要槽位缺失时,Agent 主动追问用户补充信息(对接自省模块)
  4. 记录每一次意图识别日志,统计识别准确率用于迭代 Prompt

本章整体数据流链路

用户原始输入 → 第一章预处理(清洗/ASR/文件解析)
                ↓
        本章意图槽位解析(LLM主+规则兜底)
                ↓
        校验是否拒识 → 拒识则结束;正常数据下发【记忆管理模块】
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐