refactor: split order handling and ai routing flow from agent

This commit is contained in:
2026-03-01 15:02:27 +08:00
parent e62b39e0c3
commit dff4a8baaa
3 changed files with 207 additions and 122 deletions

135
core/ai_reply_flow.py Normal file
View File

@@ -0,0 +1,135 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from core.pydantic_ai_agent import AgentDeps, ConversationState, CustomerMessage, CustomerServiceAgent
def select_target_agent(agent: "CustomerServiceAgent", message: "CustomerMessage", state: "ConversationState"):
msg_lower = message.msg.lower()
pricing_kw = ["多少钱", "多少一张", "报价", "给个价", "几块", "价位", "能便宜点吗"]
processing_kw = ["安排", "处理一下", "开始做", "做一下", "尽快", "加急", "付款了", "已付款"]
similar_kw = ["有一样的", "有一样吗", "一样的吗", "类似的", "类似的吗", "同款", "相似", "类似吗"]
order_markers = ["[系统订单信息]", "订单状态", "买家已付款"]
risk_kw = [
"黄色",
"擦边",
"色情",
"涉黄",
"涉政",
"政治",
"",
"不雅",
"天安门",
"政治人物",
"政治事件",
"领导人",
"党政",
"习近平",
"毛泽东",
"邓小平",
"江泽民",
"胡锦涛",
"特朗普",
"拜登",
"普京",
"泽连斯基",
"地图",
"地形图",
"行政区划图",
"卫星地图",
]
target_agent = agent.agent_after_sale if state.stage == "售后" else agent.agent
risk_hit = any(k in msg_lower for k in risk_kw) or agent._is_political_inquiry(message.msg) or agent._is_map_inquiry(message.msg)
if risk_hit:
return agent.agent_risk
if any(k in message.msg for k in order_markers):
return agent.agent_order
if any(k in msg_lower for k in processing_kw):
return agent.agent_processing
if any(k in msg_lower for k in pricing_kw):
return agent.agent_pricing
if any(k in msg_lower for k in similar_kw):
return agent.agent_similar
return target_agent
async def execute_ai_turn(
agent: "CustomerServiceAgent",
*,
message: "CustomerMessage",
state: "ConversationState",
user_prompt: str,
deps: "AgentDeps",
history: list,
) -> str:
target_agent = select_target_agent(agent, message, state)
result = await target_agent.run(user_prompt, deps=deps, message_history=history)
agent.message_histories[message.from_id] = result.all_messages()[-30:]
reply_text = agent._colloquialize_reply(agent._normalize_reply_text(result.output))
strategy_reply = agent._negotiation_strategy_reply(message.msg, state)
if strategy_reply:
reply_text = strategy_reply
try:
from config.config import MIN_PRICE_FLOOR
import re
offer = None
m = re.search(r"(\d{1,4})\s*(?:元|块|块钱|元钱)\b", message.msg)
if m:
offer = int(m.group(1))
else:
m2 = re.search(r"(?:能|可以|可否|能否)\s*(\d{1,4})\b", message.msg)
offer = int(m2.group(1)) if m2 else None
st = agent._get_conversation_state(message.from_id)
floor = st.last_min_price if isinstance(st.last_min_price, int) and st.last_min_price > 0 else MIN_PRICE_FLOOR
if offer is not None and offer < floor:
reply_text = "不好意思"
except Exception:
pass
try:
from config.config import MIN_PRICE_FLOOR
import re
st = agent._get_conversation_state(message.from_id)
floor = st.last_min_price if isinstance(st.last_min_price, int) and st.last_min_price > 0 else MIN_PRICE_FLOOR
def _adjust(text: str) -> str:
def _repl(m: Any):
num = int(m.group(1))
adj = max(floor, round(num / 5) * 5)
return m.group(0).replace(str(num), str(adj))
patterns = [
r"按(\d{1,4})元",
r"报价[:]\s*(\d{1,4})\s*元",
r"(\d{1,4})\s*元一张",
r"打包(\d{1,4})\s*元",
]
t = text
for p in patterns:
t = re.sub(p, _repl, t)
return t
reply_text = _adjust(reply_text or "")
except Exception:
pass
for msg in result.new_messages():
for part in getattr(msg, "parts", []):
part_type = type(part).__name__
if "ToolCall" in part_type:
print(
f"{agent.C_TOOL}[THINK/TOOL_CALL]{agent.C_RESET} "
f"{getattr(part, 'tool_name', '')}({getattr(part, 'args', '')})"
)
elif "ToolReturn" in part_type:
ret = str(getattr(part, "content", ""))[:120]
print(f"{agent.C_TOOL}[THINK/TOOL_RETURN]{agent.C_RESET} {ret}")
print(f"{agent.C_THINK}[THINK/RAW_OUTPUT]{agent.C_RESET} {repr(reply_text)}")
return reply_text