sales-assistant-py-new/app/chat_qa/classification/text_intent.py

107 lines
5.7 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.

import json
from typing import List
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from app.llm import llm
from app.repository.milvus.intent_classification_repository import IntentClassificationRepository
intent_prompt = """
你是一个专业的意图提取专家。请分析以下文本内容,并结合当前已有的意图标签,判断是否符合;若不符合则生成一个新意图,符合则直接返回原意图。
## 输入说明
- **文本内容**`{text}`
- **目前的意图**`{intent}`(可能为空)
## 核心规则
### 1. 意图提取与对比规则
- 首先从文本中提取1个核心意图提取方法见下方“意图提取规则”
- 将提取出的意图与给定的`{{intent}}`进行对比:
- 若两者**完全相同**(字符串完全一致),则最终输出意图为原意图`{{intent}}`。
- 若两者不同,或`{{intent}}`为空,则最终输出意图为新提取的意图。
- 无论采用原意图还是新意图,都必须来自或可扩充自“意图分类体系”。
### 2. 意图提取规则(用于从文本中提取核心意图)
- 若文本包含用户明确的问题,提取其核心诉求对应的意图。
- 若文本为销售介绍/陈述内容,**聚焦于其最想传达的核心功能或核心信息**,提取总结性意图。**不得将补充说明信息(如附带提到的地点、时间等)误判为核心意图。**
- 例如:文本为“线上课程后期可以转到线下,我们线下校区在上海”,核心是“线上转线下”这一功能,而非“校区分布”,因此应扩充为“线上转线下”,而不是使用“校区分布”。
- 意图必须基于实际内容,不编造。
- 仅提取1个意图标签。
### 3. 单意图选择规则(关键)
**只能输出一个意图标签,不能以顿号、逗号或“和”分隔多个意图。**
当内容可能对应多个意图时,按以下优先级选择唯一意图:
| 优先级 | 选择规则 | 说明 |
|-------|---------|------|
| **P0** | **优先匹配已有意图标签** | 必须优先从已有意图体系(含扩展示例)中选择最匹配的标签。**若已有标签中无准确对应,则按扩充规则创建新标签,严禁使用仅部分相关或语义模糊的已有标签。** 当销售单方面介绍课程内容无用户明确提问直接使用对应的主题标签如“3D场景建模”若主题为已有标签未覆盖的功能/服务(如“线上转线下”),则应扩充新标签,不得强行归类为“校区分布”等。 |
| **P1** | **核心诉求优先** | 选择最能代表文本核心诉求的意图,**忽略次要的补充信息**。例如:文本“线上课程可转线下,校区在上海” → 核心是“线上转线下”,而非“校区分布”;报名流程说明 → “报名咨询”,而非“线上直播教学”。 |
| **P2** | **主题维度优先于动作维度** | 当主题和动作诉求冲突时优先选择主题维度。例如3D建模费用 → “3D建模”主题 |
| **P3** | **直接提及优先于间接关联** | 文本明确说出的核心意图优先于推断出的意图 |
| **P4** | **去重合并** | 多个子诉求属于同一类别时,只输出一个意图标签 |
### 4. 意图分类体系(必须从中选择或基于其扩充)
{intent_list}
**扩充规则:** 当文本核心意图无法被已有标签准确覆盖时,必须创建更精准的新标签。创建时:
- 新标签应简洁体现核心语义(如“线上转线下”)。
- 严格对比已有标签,确保无重复语义。
- **示例**:文本“线上课程后期可以转到线下” → 已有标签无对应,扩充为“线上转线下”;文本“原画好就业吗” → 扩充为“原画就业”。
### 5. 多意图处理
若同一段文本明确涉及多个不重叠的核心意图仅选择最能代表核心内容的1个意图。
## 输出格式要求
- 输出纯JSON不要任何解释、不要markdown标记、不要注释
- 确保所有字符串用双引号包裹
- 输出格式固定为:
{{
"intent": "最终的意图标签(原意图或新意图,只能有一个)"
}}
"""
from app.core.log import logger
class TextIntent:
async def intent_message(self, text:str, intent:str, intent_list:list[str]) -> str:
prompt_template = PromptTemplate(template=intent_prompt, input_variables=["text","intent","intent_list"])
chain = prompt_template | llm
result = await chain.ainvoke({"text": text,"intent":intent,"intent_list": str(intent_list)})
res_new = str(result.content) if hasattr(
result, 'content') else str(result)
intent:str=""
try:
data = json.loads(res_new)
intent = data.get("intent", "")
except (json.JSONDecodeError, AttributeError):
logger.info(f"无法解析JSON{res_new}")
return intent
def _extract_jsons(self, content: str) -> List[str]:
results = []
start = 0
while start < len(content):
brace_start = content.find("{", start)
if brace_start == -1:
break
depth = 0
end = brace_start
for i in range(brace_start, len(content)):
if content[i] == "{":
depth += 1
elif content[i] == "}":
depth -= 1
if depth == 0:
end = i + 1
break
if end > brace_start:
results.append(content[brace_start:end])
start = end
else:
start = brace_start + 1
return results