110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from datetime import datetime
|
|
from typing import TYPE_CHECKING
|
|
|
|
from utils.metrics_tracker import emit as metrics_emit
|
|
from core.post_ops import auto_tag, detect_discount, detect_price, record_deal_fail
|
|
|
|
if TYPE_CHECKING:
|
|
from core.pydantic_ai_agent import AgentResponse, ConversationState, CustomerMessage, CustomerServiceAgent
|
|
|
|
|
|
async def finalize_ai_reply(
|
|
agent: "CustomerServiceAgent",
|
|
*,
|
|
message: "CustomerMessage",
|
|
state: "ConversationState",
|
|
reply_text: str,
|
|
) -> "AgentResponse":
|
|
from core.pydantic_ai_agent import AgentResponse, TRANSFER_MESSAGE
|
|
|
|
try:
|
|
from utils.content_filter import should_block_reply
|
|
|
|
blocked, fallback = should_block_reply(reply_text)
|
|
if blocked:
|
|
print("[Agent] 敏感词拦截,使用兜底回复")
|
|
reply_text = fallback or "好的,您稍等,我帮您确认一下"
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
from utils.api_cost_tracker import record
|
|
|
|
record("openai_chat", count=1)
|
|
except Exception:
|
|
pass
|
|
|
|
detect_price(reply_text, state)
|
|
detect_discount(message.msg, state)
|
|
asyncio.create_task(auto_tag(message, state))
|
|
|
|
need_transfer = False
|
|
transfer_msg = ""
|
|
transfer_keywords = ["TRANSFER_REQUESTED", "[转移会话]", "转移会话", "转人工", "转接"]
|
|
if reply_text and any(kw in reply_text for kw in transfer_keywords):
|
|
need_transfer = True
|
|
transfer_msg = TRANSFER_MESSAGE
|
|
metrics_emit("transfer_to_human", customer_id=message.from_id, acc_id=message.acc_id)
|
|
|
|
evo_hit = agent._evolution_enabled_for_customer(message.from_id)
|
|
if evo_hit and agent._is_service_risk_inquiry(message.msg):
|
|
if agent._evolution_has_proposal("policy-risk-transfer"):
|
|
need_transfer = True
|
|
transfer_msg = TRANSFER_MESSAGE
|
|
metrics_emit("evolution_force_transfer", customer_id=message.from_id, acc_id=message.acc_id)
|
|
if agent._evolution_has_proposal("tone-empathy-pack"):
|
|
reply_text = "抱歉让您不舒服了,这边先为您转接人工专员马上处理。"
|
|
metrics_emit("evolution_empathy_reply", customer_id=message.from_id, acc_id=message.acc_id)
|
|
|
|
customer_text, _ = agent._split_customer_text(message.msg)
|
|
no_convert_keywords = ["算了", "不要了", "不做了", "下次再说", "先不弄了"]
|
|
if customer_text and state.last_price and state.last_price > 0:
|
|
if any(kw in customer_text for kw in no_convert_keywords):
|
|
reason = "嫌贵放弃" if any(k in customer_text for k in ["贵", "贵了", "便宜"]) else "放弃"
|
|
asyncio.create_task(
|
|
record_deal_fail(
|
|
customer_id=message.from_id,
|
|
customer_name=message.from_name,
|
|
acc_id=message.acc_id,
|
|
platform=message.acc_type,
|
|
reason=reason,
|
|
)
|
|
)
|
|
|
|
should_reply = bool(reply_text and reply_text.strip()) and not need_transfer
|
|
if evo_hit and need_transfer and agent._evolution_has_proposal("tone-empathy-pack"):
|
|
should_reply = True
|
|
|
|
if should_reply:
|
|
reply_text = await agent._rewrite_reply_with_ai(
|
|
message=message,
|
|
state=state,
|
|
reply=reply_text,
|
|
scene="final_reply",
|
|
)
|
|
|
|
if should_reply:
|
|
state.last_reply_at = datetime.now()
|
|
print(f"{agent.C_REPLY}[REPLY->CUSTOMER]{agent.C_RESET} {reply_text}")
|
|
else:
|
|
print(f"{agent.C_MUTED}[REPLY->CUSTOMER]{agent.C_RESET} <静默/不发送>")
|
|
|
|
agent._activity_log(
|
|
"agent_outbound_decision",
|
|
customer_id=message.from_id,
|
|
should_reply=should_reply,
|
|
need_transfer=need_transfer,
|
|
reply=reply_text or "",
|
|
transfer_msg=transfer_msg,
|
|
)
|
|
|
|
return AgentResponse(
|
|
reply=reply_text or "",
|
|
should_reply=should_reply,
|
|
need_transfer=need_transfer,
|
|
transfer_msg=transfer_msg,
|
|
)
|