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, )