fix:修改客服agent的意图识别
This commit is contained in:
+36
-17
@@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
@@ -12,32 +13,51 @@ class Intent(StrEnum):
|
||||
GUIDE_PURCHASE = "guide_purchase"
|
||||
WANT_ADVISOR = "want_advisor"
|
||||
NL2SQL_REQUEST = "nl2sql_request"
|
||||
COMPLAIN = "complain"
|
||||
KNOWLEDGE_QA = "knowledge_qa"
|
||||
COMPANY_INFO = "company_info"
|
||||
CHITCHAT = "chitchat"
|
||||
OFF_TOPIC = "off_topic"
|
||||
NO_MATCH = "no_match"
|
||||
|
||||
|
||||
INTENT_VALUES = frozenset(item.value for item in Intent)
|
||||
|
||||
# 按长度降序匹配,避免短标签误命中长标签的一部分
|
||||
_INTENT_PATTERN = re.compile(
|
||||
"|".join(re.escape(value) for value in sorted(INTENT_VALUES, key=len, reverse=True))
|
||||
)
|
||||
|
||||
INTENT_SYSTEM_PROMPT = (
|
||||
"你是华夏科技(一家基金代销金融机构)智能客服的意图分类器。"
|
||||
"请根据用户输入,从以下选项中选择最匹配的意图,并仅输出对应的英文标签(不输出任何其他内容):\n"
|
||||
"- guide_purchase: 用户询问如何购买基金、开户、注册等引导类问题\n"
|
||||
"- want_advisor: 用户希望获得个性化基金推荐或投资顾问服务\n"
|
||||
"- knowledge_qa: 用户询问基金相关的知识性问题,如净值、费率、风险、申赎规则等\n"
|
||||
"- company_info: 用户询问华夏科技公司本身的信息,如公司全称、成立时间、牌照、总部地址、"
|
||||
"客服电话、服务时间、官网、投诉渠道等\n"
|
||||
"- nl2sql_request: 用户要求查询具体数据或账户信息\n"
|
||||
"- chitchat: 普通寒暄,如问候、致谢、告别、询问你是谁/你能做什么、在吗等一两句话的闲聊\n"
|
||||
"- off_topic: 用户要求你实质性地处理与金融、基金、公司业务无关的事情,"
|
||||
"如写代码、讲笑话、写作文、问天气、聊政治、情感咨询、做数学题等\n"
|
||||
"- no_match: 无法归入以上任何一类\n"
|
||||
"注意:寒暄性质的一两句话归为 chitchat;一旦用户提出金融之外的实质性请求,归为 off_topic。\n"
|
||||
"仅输出一个小写英文标签,不要输出解释、标点或换行。"
|
||||
)
|
||||
|
||||
|
||||
def parse_intent(raw: str | None) -> Intent:
|
||||
"""从模型原始输出中提取第一个合法标签,提取不到则返回 NO_MATCH。"""
|
||||
if not raw:
|
||||
return Intent.NO_MATCH
|
||||
match = _INTENT_PATTERN.search(raw.lower())
|
||||
return Intent(match.group(0)) if match else Intent.NO_MATCH
|
||||
|
||||
|
||||
async def intent_recognize(query: str, *, llm_client) -> Intent:
|
||||
if not query or not query.strip():
|
||||
return Intent.NO_MATCH
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
"你是一个意图分类器。请根据用户输入,从以下选项中选择最匹配的意图,"
|
||||
"并仅输出对应的英文标签(不输出任何其他内容):\n"
|
||||
"- guide_purchase: 用户询问如何购买基金、开户、注册等引导类问题\n"
|
||||
"- want_advisor: 用户希望获得个性化基金推荐或投资顾问服务\n"
|
||||
"- knowledge_qa: 用户询问基金相关的知识性问题,如净值、费率、风险等\n"
|
||||
"- nl2sql_request: 用户要求查询具体数据或账户信息\n"
|
||||
"- complain: 用户表达不满或投诉\n"
|
||||
"- no_match: 以上都不匹配\n"
|
||||
"仅输出一个小写英文标签,不要输出解释、标点或换行。"
|
||||
),
|
||||
},
|
||||
{"role": "system", "content": INTENT_SYSTEM_PROMPT},
|
||||
{"role": "user", "content": query},
|
||||
]
|
||||
try:
|
||||
@@ -45,5 +65,4 @@ async def intent_recognize(query: str, *, llm_client) -> Intent:
|
||||
except Exception:
|
||||
logger.exception("intent recognition failed")
|
||||
return Intent.NO_MATCH
|
||||
value = raw.strip().strip('`').lower()
|
||||
return Intent(value) if value in INTENT_VALUES else Intent.NO_MATCH
|
||||
return parse_intent(raw)
|
||||
|
||||
@@ -54,19 +54,28 @@ class AnonymousCustomerAgent:
|
||||
|
||||
intent = await _maybe_await(self.intent_recognize(query))
|
||||
sources = []
|
||||
if intent is Intent.GUIDE_PURCHASE:
|
||||
if intent == Intent.GUIDE_PURCHASE:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.guide_purchase",
|
||||
"请前往开户页面办理。",
|
||||
)
|
||||
elif intent is Intent.WANT_ADVISOR:
|
||||
elif intent == Intent.WANT_ADVISOR:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.guide_advisor",
|
||||
"如需基金推荐,请联系投资顾问。",
|
||||
)
|
||||
elif intent is Intent.KNOWLEDGE_QA:
|
||||
elif intent == Intent.OFF_TOPIC:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.off_topic",
|
||||
"我是华夏科技的智能客服,只能解答基金与公司业务相关的问题,"
|
||||
"您可以问我基金知识、开户流程或公司信息~",
|
||||
)
|
||||
elif intent == Intent.CHITCHAT:
|
||||
answer = await self._chitchat(session_id)
|
||||
elif intent in (Intent.KNOWLEDGE_QA, Intent.COMPANY_INFO):
|
||||
try:
|
||||
sources = await _maybe_await(self.rag_retrieve(query, None))
|
||||
except Exception:
|
||||
@@ -112,6 +121,31 @@ class AnonymousCustomerAgent:
|
||||
"trace_id": trace_id,
|
||||
}
|
||||
|
||||
async def _chitchat(self, session_id: str) -> str:
|
||||
"""带对话历史调用 LLM 做受限闲聊,失败时退回固定话术。"""
|
||||
messages = await self.context.get(session_id)
|
||||
prompt = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
"你是华夏科技(基金代销金融机构)的智能客服助手。"
|
||||
"用户正在与你寒暄,请用一两句话简短、友好地回应,"
|
||||
"并自然地引导用户咨询基金知识、开户流程或公司信息。"
|
||||
"不得推荐任何基金产品,不得谈论具体收益,不得回答金融之外的实质性问题。"
|
||||
),
|
||||
},
|
||||
*messages,
|
||||
]
|
||||
try:
|
||||
return await _maybe_await(self.generate_answer(prompt))
|
||||
except Exception:
|
||||
return await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.chitchat_fallback",
|
||||
"您好,我是华夏科技的智能客服,很高兴为您服务!"
|
||||
"您可以问我基金知识、开户流程或公司信息~",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _contains_sensitive_input(query: str) -> bool:
|
||||
return bool(
|
||||
|
||||
Reference in New Issue
Block a user