十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

人机协同对话系统:基于FastAPI的意图识别与人工接管实战

人机协同对话系统:基于FastAPI的意图识别与人工接管实战 做智能客服类项目时团队最容易掉进的坑是默认“机器人应该解决所有问题”。于是一轮一轮叠加意图、话术和兜底逻辑最后用户反馈却越来越差。后来我们换了一个思考角度自动化的目标不是取代所有客服人员而是把标准化、重复的对话处理掉让真人客服把时间留给真正需要情感和判断的对话。这个理念翻译成一句英文就是spend more time talking to humans。本文会围绕这句话完整实现一套“机器人自动应答 意图识别 置信度升级 人工接管 数据复盘”的人机协同对话系统。项目基于 Python FastAPI SQLite 实现不依赖复杂中间件本地可以直接运行适合想入门智能客服、对话系统、人机协同设计的开发者和产品同学参考。读完你可以得到一份能跑的工程骨架也能理解为什么“转人工”不是系统失败而是系统设计的一部分。1. 背景为什么我们要“把时间留给真人对话”1.1 一句话背后的工程问题在电商、SaaS、金融等行业客服机器人早已成为标配。但很多机器人给用户的体验是“进了死循环”问了半天查不到答案想转人工又被自动回复反复拦截最后用户愤怒值反而更高。问题出在系统设计目标上。如果我们把“机器人解决所有问题”当作成功标准就会刻意压低转人工比例结果是把用户困在自动化流程里。真正合理的标准应该是机器人把简单、重复的问题高性价比地解决掉把复杂、高情绪、需要判断的问题第一时间交给真人。所以“spend more time talking to humans”在工程上可以翻译成三层含义让真人客服把时间花在真正需要人的对话上而不是机械重复。让用户在最需要被理解的时候能快速找到真人而不是和机器人纠缠。让产品团队通过复盘“为什么转人工”持续优化机器人能力形成迭代闭环。1.2 人机协同对话系统的核心闭环一个完整的人机协同对话系统不能只有“聊天机器人”和“转人工按钮”两个模块。至少应该包含下面几个环节用户消息 ↓ 意图识别关键词兜底 大模型结构化判断 ↓ 升级决策是否需要真人介入 ├─ 不需要 → 机器人自动回复保存会话记录 └─ 需要 → 生成工单进入座席队列 ↓ 座席接单 → 查看上下文 → 人工回复 ↓ 会话复盘 → 沉淀标注数据 → 优化机器人哪个问题交给机器人哪个问题交给真人可以先用一张表来感受一下业务场景交给机器人交给真人查物流、改地址、开发票高频、标准化适合自动处理不需要退款争议、赠品缺失、个性化问题规则覆盖不全容易答错需要判断和安抚用户明确表达不满、投诉不适合机械回复需要情感沟通凌晨低峰时段可以先兜底记录按排班响应判断“交给谁”不能靠产品经理拍脑袋而是由意图识别、置信度评估、升级条件共同决定。这也是本文示例系统的核心部分。1.3 为什么不能只靠 if-else 判断转人工很多初版客服机器人会写一堆关键词规则比如包含“人工”就转人工包含“物流”就回复物流模板。这种方式简单但很脆弱用户表达方式多样“请问我的快递走到哪儿了”“东西发出来没有”“查一下单号”都指向同一个意图。情绪表达更难用关键词覆盖“你们这服务也太离谱了”这句话没有任何投诉关键词但已经不适合机器人硬答。如果加上大模型可以让意图识别更泛化但大模型也有不确定性所以还需要置信度机制兜底。因此示例项目采用“关键词确定性优先 大模型弱兜底 置信度决策”的混合方案。关键词能命中的场景直接走模板命中不了再让大模型判断最后根据置信度和升级条件决定是否转人工。2. 环境准备与版本说明2.1 运行环境本文示例在以下环境中验证通过版本可以按你的实际项目调整Python 3.10FastAPI 0.115.6Uvicorn 0.34.0httpx 0.28.1python-dotenv 1.0.1SQLitePython 内置无需单独安装如果安装时出现依赖版本冲突可以去掉版本号让 pip 安装当前最新兼容版本pip install fastapi uvicorn httpx python-dotenv pydantic2.2 技术选型说明组件用途选型理由FastAPI对外提供 HTTP 接口上手快、自带请求校验和文档适合快速搭建服务SQLite存储会话、消息、工单零部署本地演示成本最低httpx调用大模型接口同步异步都支持代码简洁LLM API意图识别与回复生成兼容 OpenAI 接口格式的服务都可以接入需要说明的是大模型接口不是必须的。示例代码里做了离线降级即使不配置大模型 API Key关键词命中的场景也能完整跑通方便你本地验证整体流程。2.3 项目结构建议按下面的目录组织代码spend-time-with-humans/ ├── requirements.txt ├── .env.example ├── app/ │ ├── __init__.py │ ├── config.py │ ├── llm_client.py │ ├── intent.py │ ├── escalation.py │ ├── store.py │ └── main.py └── data/ # 运行后自动生成存放 SQLite 文件3. 系统设计与核心原理拆解3.1 意图识别关键词兜底 LLM 结构化输出意图识别模块的目标是回答一个问题用户这条消息机器人能不能处理需要不需要转真人示例里把意图分成三类routine查物流、改地址、退换货、发票等标准化问题机器人可直接回答。emotional用户情绪激烈、表达不满需要人工介入。human_request用户明确要求转人工。为了保证系统在真实场景里“可解释、可兜底”我们先用关键词做确定性判断再用大模型做泛化补充。关键词命中时返回高置信度 0.95避免把确定性的问题误判成转人工关键词没有命中时大模型会输出一个结构化 JSON格式如下{ intent: routine, confidence: 0.87, need_human: false }confidence代表模型对判断结果的把握程度后面升级决策会用到。3.2 升级决策什么情况下把用户交给真人升级决策是整套系统最重要的地方。示例里维护了四个升级条件满足任意一个就转人工用户明确要求转人工包含“人工”“转人工”“真人”等关键词或大模型识别出human_request。大模型判断用户情绪激烈、表达不满。意图识别置信度低于阈值机器人都不知道自己在回答什么这时候硬答风险远大于转人工。同一会话连续多轮询问仍未解决说明自动回复没有命中用户需求。置信度阈值confidence_threshold是调整系统“性格”的核心参数阈值太高很多普通问题也会转人工真人客服压力大。阈值太低机器人会硬答不确定的问题用户满意度下降。建议从 0.6 起步上线后观察升级率和用户满意度再做针对性调整。3.3 转人工话术与上下文传递真正影响用户体感的不只是“转不转”还有“转的时候说什么”。好的转人工流程应该做到三点明确告知用户已经转接避免重复询问造成二次情绪反弹。保存历史消息让接单的座席能看到上下文不用用户重新复述。记录转人工原因方便后续分析是机器人能力不足还是业务本身复杂。对应到代码里就是三件事写入一条固定话术、把所有消息存进messages表、生成一张带原因标签的tickets工单。3.4 座席队列并发与防抢单真实客服系统一定有多位座席同时在线。这时“接单”必须防并发竞争一个工单不能被两个座席同时接走。SQLite 里可以这样保证原子性UPDATE tickets SET status accepted, agent_id ?, accepted_at ? WHERE ticket_no ? AND status pending;执行后检查rowcount是 1说明抢单成功。是 0说明工单已经被别人接走返回冲突提示。这种“条件更新 影响行数判断”的方案和 Redis 分布式锁效果不完全等价但对单机演示、中小并发场景已经足够也是理解抢单问题的很好切入点。4. 完整实战构建一个人机协同问答系统下面从零开始搭建项目。所有代码都会给出完整文件路径你可以直接复制到本地运行。4.1 创建项目结构与依赖先创建目录mkdir spend-time-with-humans cd spend-time-with-humans mkdir app data创建requirements.txtfastapi0.115.6 uvicorn[standard]0.34.0 httpx0.28.1 python-dotenv1.0.1 pydantic2.10.4安装依赖pip install -r requirements.txt4.2 配置文件与 .env创建.env.exampleLLM_BASE_URLhttps://api.openai.com/v1 LLM_API_KEY LLM_MODELgpt-4o-mini CONFIDENCE_THRESHOLD0.6 MAX_ROUNDS_BEFORE_HUMAN2 DB_PATHdata/chatbot.dbLLM_API_KEY可以为空留空时系统进入离线降级模式只使用关键词和模板回复。复制成.env并修改cp .env.example .env创建app/config.pyimport os from dataclasses import dataclass from dotenv import load_dotenv load_dotenv() dataclass class Settings: llm_base_url: str os.getenv(LLM_BASE_URL, https://api.openai.com/v1) llm_api_key: str os.getenv(LLM_API_KEY, ) llm_model: str os.getenv(LLM_MODEL, gpt-4o-mini) confidence_threshold: float float(os.getenv(CONFIDENCE_THRESHOLD, 0.6)) max_rounds_before_human: int int(os.getenv(MAX_ROUNDS_BEFORE_HUMAN, 2)) db_path: str os.getenv(DB_PATH, data/chatbot.db) settings Settings()注意如果使用其他兼容 OpenAI 接口的大模型服务只需要修改LLM_BASE_URL和LLM_MODEL代码不需要改动。4.3 大模型接口封装创建app/llm_client.py。这里用 httpx 直接调用兼容 OpenAI 格式的/chat/completions接口import httpx class LLMClient: def __init__(self, base_url: str, api_key: str, model: str): self.base_url base_url.rstrip(/) self.api_key api_key self.model model def chat( self, messages: list, temperature: float 0.2, timeout: float 30.0, ) - str: url f{self.base_url}/chat/completions headers {Authorization: fBearer {self.api_key}} payload { model: self.model, messages: messages, temperature: temperature, } response httpx.post( url, jsonpayload, headersheaders, timeouttimeout, ) response.raise_for_status() data response.json() return data[choices][0][message][content]如果LLM_API_KEY为空这个类不会被调用所以离线模式不影响系统启动。4.4 意图识别模块创建app/intent.pyimport json import re from llm_client import LLMClient # 确定性关键词兜底先判断是否转人工再判断业务意图 HUMAN_KEYWORDS [人工, 转人工, 真人, 投诉, 差评, 曝光, 气死, 骗子] ROUTINE
返回列表