chore: update gitignore; feat: 新增customer_agent业务模块与api路由
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""Anonymous customer-service orchestration without private customer access."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from inspect import isawaitable
|
||||
|
||||
from rag.intent import Intent
|
||||
|
||||
|
||||
class QueryTooLongError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
async def _config(config_getter, key: str, default: str):
|
||||
value = config_getter(key, default)
|
||||
if isawaitable(value):
|
||||
value = await value
|
||||
return value or default
|
||||
|
||||
|
||||
async def _maybe_await(value):
|
||||
return await value if isawaitable(value) else value
|
||||
|
||||
|
||||
class AnonymousCustomerAgent:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
context,
|
||||
rag_retrieve,
|
||||
intent_recognize,
|
||||
generate_answer,
|
||||
audit_writer,
|
||||
config_getter,
|
||||
):
|
||||
self.context = context
|
||||
self.rag_retrieve = rag_retrieve
|
||||
self.intent_recognize = intent_recognize
|
||||
self.generate_answer = generate_answer
|
||||
self.audit_writer = audit_writer
|
||||
self.config_getter = config_getter
|
||||
|
||||
async def handle(self, session_id: str, query: str, *, trace_id: str) -> dict:
|
||||
if len(query) > 2000:
|
||||
raise QueryTooLongError("query长度不能超过2000字符")
|
||||
await self.context.append(session_id, "user", query)
|
||||
if self._contains_sensitive_input(query):
|
||||
await _maybe_await(self.audit_writer(
|
||||
action="anon_sensitive_input",
|
||||
trace_id=trace_id,
|
||||
session_id=session_id,
|
||||
))
|
||||
|
||||
intent = await _maybe_await(self.intent_recognize(query))
|
||||
sources = []
|
||||
if intent is Intent.GUIDE_PURCHASE:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.guide_purchase",
|
||||
"请前往开户页面办理。",
|
||||
)
|
||||
elif intent is Intent.WANT_ADVISOR:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.guide_advisor",
|
||||
"如需基金推荐,请联系投资顾问。",
|
||||
)
|
||||
elif intent is Intent.KNOWLEDGE_QA:
|
||||
try:
|
||||
sources = await _maybe_await(self.rag_retrieve(query, None))
|
||||
except Exception:
|
||||
sources = []
|
||||
if not sources:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.fallback_human",
|
||||
"当前未找到匹配信息,请转人工客服。",
|
||||
)
|
||||
else:
|
||||
messages = await self.context.get(session_id)
|
||||
prompt = messages + [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "仅根据提供的知识来源回答,不得编造基金推荐。",
|
||||
},
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"知识来源:{json.dumps(sources, ensure_ascii=False)}",
|
||||
},
|
||||
]
|
||||
try:
|
||||
answer = await _maybe_await(self.generate_answer(prompt))
|
||||
except Exception:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.fallback_human",
|
||||
"当前服务繁忙,请转人工客服。",
|
||||
)
|
||||
else:
|
||||
answer = await _config(
|
||||
self.config_getter,
|
||||
"agent.customer.template.fallback_human",
|
||||
"当前未找到匹配信息,请转人工客服。",
|
||||
)
|
||||
|
||||
await self.context.append(session_id, "assistant", answer)
|
||||
return {
|
||||
"answer": answer,
|
||||
"sources": sources,
|
||||
"intent": intent.value,
|
||||
"trace_id": trace_id,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _contains_sensitive_input(query: str) -> bool:
|
||||
return bool(
|
||||
re.search(r"(?<!\d)1[3-9]\d{9}(?!\d)", query)
|
||||
or re.search(r"(?:客户|customer)[_ -]?(?:id|号)?\s*[::]?\s*[A-Za-z0-9_-]{4,}", query, re.I)
|
||||
)
|
||||
Reference in New Issue
Block a user