Files
assistant/agent/agents/order.py
wl 3ad6eee0d9 feat: 初始化 B2B AI Shopping Assistant 项目
- 配置 Docker Compose 多服务编排
- 实现 Chatwoot + Agent 集成
- 配置 Strapi MCP 知识库
- 支持 7 种语言的 FAQ 系统
- 实现 LangGraph AI 工作流

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 19:25:22 +08:00

232 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Order Agent - Handles order-related queries and operations
"""
import json
from typing import Any
from core.state import AgentState, ConversationState, add_tool_call, set_response, update_context
from core.llm import get_llm_client, Message
from utils.logger import get_logger
logger = get_logger(__name__)
ORDER_AGENT_PROMPT = """你是一个专业的 B2B 订单服务助手。
你的职责是帮助用户处理订单相关的问题,包括:
- 订单查询
- 物流跟踪
- 订单修改
- 订单取消
- 发票获取
## 可用工具
1. **query_order** - 查询订单
- order_id: 订单号(可选,不填则查询最近订单)
- date_start: 开始日期(可选)
- date_end: 结束日期(可选)
- status: 订单状态(可选)
2. **track_logistics** - 物流跟踪
- order_id: 订单号
- tracking_number: 物流单号(可选)
3. **modify_order** - 修改订单
- order_id: 订单号
- modifications: 修改内容address/items/quantity 等)
4. **cancel_order** - 取消订单
- order_id: 订单号
- reason: 取消原因
5. **get_invoice** - 获取发票
- order_id: 订单号
- invoice_type: 发票类型normal/vat
## 工具调用格式
当需要使用工具时,请返回 JSON 格式:
```json
{
"action": "call_tool",
"tool_name": "工具名称",
"arguments": {
"参数名": "参数值"
}
}
```
当需要向用户询问更多信息时:
```json
{
"action": "ask_info",
"question": "需要询问的问题"
}
```
当可以直接回答时:
```json
{
"action": "respond",
"response": "回复内容"
}
```
## 重要提示
- 订单修改和取消是敏感操作,需要确认订单号
- 如果用户没有提供订单号,先查询他的最近订单
- 物流查询需要订单号或物流单号
- 对于批量操作或大金额订单,建议转人工处理
"""
async def order_agent(state: AgentState) -> AgentState:
"""Order agent node
Handles order queries, tracking, modifications, and cancellations.
Args:
state: Current agent state
Returns:
Updated state with tool calls or response
"""
logger.info(
"Order agent processing",
conversation_id=state["conversation_id"],
sub_intent=state.get("sub_intent")
)
state["current_agent"] = "order"
state["agent_history"].append("order")
state["state"] = ConversationState.PROCESSING.value
# Check if we have tool results to process
if state["tool_results"]:
return await _generate_order_response(state)
# Build messages for LLM
messages = [
Message(role="system", content=ORDER_AGENT_PROMPT),
]
# Add conversation history
for msg in state["messages"][-6:]:
messages.append(Message(role=msg["role"], content=msg["content"]))
# Build context info
context_info = f"用户ID: {state['user_id']}\n账户ID: {state['account_id']}\n"
# Add entities if available
if state["entities"]:
context_info += f"已提取的信息: {json.dumps(state['entities'], ensure_ascii=False)}\n"
# Add existing context
if state["context"].get("order_id"):
context_info += f"当前讨论的订单号: {state['context']['order_id']}\n"
user_content = f"{context_info}\n用户消息: {state['current_message']}"
messages.append(Message(role="user", content=user_content))
try:
llm = get_llm_client()
response = await llm.chat(messages, temperature=0.5)
# Parse response
content = response.content.strip()
if content.startswith("```"):
content = content.split("```")[1]
if content.startswith("json"):
content = content[4:]
result = json.loads(content)
action = result.get("action")
if action == "call_tool":
# Inject user context into arguments
arguments = result.get("arguments", {})
arguments["user_id"] = state["user_id"]
arguments["account_id"] = state["account_id"]
# Use entity if available
if "order_id" not in arguments and state["entities"].get("order_id"):
arguments["order_id"] = state["entities"]["order_id"]
state = add_tool_call(
state,
tool_name=result["tool_name"],
arguments=arguments,
server="order"
)
state["state"] = ConversationState.TOOL_CALLING.value
elif action == "ask_info":
state = set_response(state, result["question"])
state["state"] = ConversationState.AWAITING_INFO.value
elif action == "respond":
state = set_response(state, result["response"])
state["state"] = ConversationState.GENERATING.value
elif action == "handoff":
state["requires_human"] = True
state["handoff_reason"] = result.get("reason", "Complex order operation")
return state
except json.JSONDecodeError:
state = set_response(state, response.content)
return state
except Exception as e:
logger.error("Order agent failed", error=str(e))
state["error"] = str(e)
return state
async def _generate_order_response(state: AgentState) -> AgentState:
"""Generate response based on order tool results"""
# Build context from tool results
tool_context = []
for result in state["tool_results"]:
if result["success"]:
data = result["data"]
tool_context.append(f"工具 {result['tool_name']} 返回:\n{json.dumps(data, ensure_ascii=False, indent=2)}")
# Extract order_id for context
if isinstance(data, dict):
if data.get("order_id"):
state = update_context(state, {"order_id": data["order_id"]})
elif data.get("orders") and len(data["orders"]) > 0:
state = update_context(state, {"order_id": data["orders"][0].get("order_id")})
else:
tool_context.append(f"工具 {result['tool_name']} 执行失败: {result['error']}")
prompt = f"""基于以下订单系统返回的信息,生成对用户的回复。
用户问题: {state["current_message"]}
系统返回信息:
{chr(10).join(tool_context)}
请生成一个清晰、友好的回复,包含订单的关键信息(订单号、状态、金额、物流等)。
如果是物流信息,请按时间线整理展示。
只返回回复内容,不要返回 JSON。"""
messages = [
Message(role="system", content="你是一个专业的订单客服助手,请根据系统返回的信息回答用户的订单问题。"),
Message(role="user", content=prompt)
]
try:
llm = get_llm_client()
response = await llm.chat(messages, temperature=0.7)
state = set_response(state, response.content)
return state
except Exception as e:
logger.error("Order response generation failed", error=str(e))
state = set_response(state, "抱歉,处理订单信息时遇到问题。请稍后重试或联系人工客服。")
return state