sales-assistant-py-new/app/chat_qa_query/query_nodes/node_rewrite.py

138 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
问题改写
"""
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from app.chat_qa_query.query_qa_state import QueryQAState
from app.llm import llm
from app.core.log import logger
problem_rewriting_prompt = """
你是一名智能客服意图分类助手。你的任务是根据用户的历史会话和当前问题,提取用户的核心诉求,并输出标准化的意图标签。
## 核心原则(必须严格遵守)
### 1. 双维度提取原则
每个用户问题通常包含两个维度的意图,必须分别识别:
- **课程/服务主题维度**用户想咨询的具体课程类型或业务主题如3D建模、2D原画、UE引擎开发等
- **诉求/动作维度**:用户想了解的方面(如课程咨询、就业咨询、校区分布等)
这两个维度相互独立,必须同时提取,不得遗漏任何一个。
### 2. 主题维度提取规则
- 如果用户明确提到了具体课程名称或类型(如"3D建模""2D原画""UE引擎开发"),必须作为独立意图标签输出
- 如果当前问题使用代词(如"这个"""),结合历史会话进行指代消解,还原具体课程名称
- 如果历史会话中也没有明确课程类型,则不输出主题维度标签
### 3. 诉求维度提取规则
- 从当前问题中提取用户明确表达的动作诉求(费用、就业、退费、住宿等)
- 将动作诉求映射到标准诉求类型标签
### 4. 信息补全与语义保持
- 如果当前问题缺少主语,从历史会话补全
- 不得改变用户原始意图,不得引入历史会话中不存在的新信息
- 不得遗漏当前问题中的任何关键诉求
## 输出格式
- 仅输出JSON不要任何解释性文字
- 多诉求时用数组形式输出,每个意图标签独立
- 标签从以下列表中选择,不得自创:
**课程/服务主题标签**公司介绍、3D建模、3D场景建模、3D角色建模、2D原画、二次元风格、写实风格、动作/分镜、游戏动作/分镜、开发、UE引擎开发、3D大师课、GGAC绘殓课程、造型力、大学生扶持计划、兴趣/提升班、学习模式、线下面授教学、线上直播教学、寒暑假教学、提供服务、优势/竞争力、校区分布
**诉求/动作标签**:课程咨询、退费咨询、住宿咨询、学不会怎么办、就业咨询、学历咨询
## 分类示例
### 示例1主题+诉求双维度)
历史会话:(空)
当前问题3D建模培训的课程内容有哪些
分析:主题="3D建模",诉求="课程内容"→课程咨询
分类结果:
{{
"intents": ["3D建模", "课程咨询"]
}}
### 示例2主题+诉求双维度,信息补全)
历史会话:
- 用户:我想了解游戏特效培训
- 助手:好的,请问您想了解哪方面?
当前问题:培训的费用
分析:主题从历史会话补全="游戏特效培训",诉求="费用"→课程咨询
分类结果:
{{
"intents": ["课程咨询"]
}}
### 示例3主题+诉求双维度,指代消解)
历史会话:
- 用户你们有Python课程吗
- 助手有的我们有Python基础班和进阶班。
当前问题:这个课程的时长是多久?
分析:主题="Python课程",诉求="课程时长"→课程咨询
分类结果:
{{
"intents": ["课程咨询"]
}}
### 示例4多诉求提取
历史会话:
- 用户:我想报名数据分析培训
当前问题:流程、费用和就业支持
分析:主题="数据分析培训",诉求="流程/费用"→课程咨询,"就业支持"→就业咨询
分类结果:
{{
"intents": ["课程咨询", "就业咨询"]
}}
### 示例5主题+诉求双维度)
历史会话:(空)
当前问题老师3D大师课课程多少钱啊老师我想报班
分析:主题="3D大师课",诉求="多少钱/报班"→课程咨询
分类结果:
{{
"intents": ["3D大师课", "课程咨询"]
}}
### 示例6关键示例主题必须独立提取
历史会话:
- 用户:老师 我想报班
- 用户:老师这个课程多少钱啊
当前问题老师我想咨询3D建模费用问题
分析:主题="3D建模"(当前问题明确提及),诉求="费用问题"→课程咨询
分类结果:
{{
"intents": ["3D建模", "课程咨询"]
}}
---
## 现在请处理以下输入
当前问题:{query}
历史聊天:{history_text}
请直接输出JSON
"""
async def rewrite_query(state:QueryQAState):
"""
问题改写
:param query: 用户问题
:param history_text: 历史会话
:return: 改写后的问题
"""
history_text = state.get("history", "")
query = state.get("original_query", "")
prompt = PromptTemplate(template=problem_rewriting_prompt, input_variables=["history_text", "query"])
output = JsonOutputParser()
chain = prompt | llm | output
try:
result = await chain.ainvoke({"history_text": history_text, "query": query})
rewritten_query = result.get("intents", "")
logger.info(f"原问题:{query},历史会话:{history_text},改写后问题:{rewritten_query}")
return {"rewritten_query": rewritten_query}
except Exception as e:
logger.error(f"QA质量检查prompt模板错误{e}")
return {"rewritten_query": query} # 兜底