fix: 更新 Product Agent prompt 添加 search_spu_products 工具说明
## 问题 搜索商品时返回错误的工具调用 search_products 而非 search_spu_products ## 根本原因 Product Agent 的 PRODUCT_AGENT_PROMPT 中没有列出 search_spu_products 工具, 导致 LLM 不知道可以使用 Mall API 的 SPU 搜索工具 ## 修改内容 ### agent/agents/product.py - 将 search_spu_products 设为第一个工具(推荐使用) - 说明此工具使用 Mall API 搜索商品 SPU,支持用户 token 认证,返回卡片格式展示 - 原有的 search_products 标记为高级搜索工具(使用 Hyperf API) - 调整工具序号 1-6 ### docs/PRODUCT_SEARCH_SERVICE.md - 添加 Product Agent Prompt 更新说明章节 - 调整章节序号 ## 预期效果 LLM 现在应该优先使用 search_spu_products 工具进行商品搜索, 返回 Mall API 的商品数据并以 Chatwoot cards 格式展示 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,26 +21,33 @@ PRODUCT_AGENT_PROMPT = """你是一个专业的 B2B 商品顾问助手。
|
||||
|
||||
## 可用工具
|
||||
|
||||
1. **search_products** - 搜索商品
|
||||
1. **search_spu_products** - 搜索商品(使用 Mall API,推荐)
|
||||
- keyword: 搜索关键词(商品名称、编号等)
|
||||
- page_size: 每页数量(默认 60,最大 100)
|
||||
- page: 页码(默认 1)
|
||||
- 说明:此工具使用 Mall API 搜索商品 SPU,支持用户 token 认证,返回卡片格式展示
|
||||
|
||||
2. **search_products** - 搜索商品(使用 Hyperf API)
|
||||
- query: 搜索关键词
|
||||
- filters: 过滤条件(category, price_range, brand 等)
|
||||
- sort: 排序方式(price_asc/price_desc/sales/latest)
|
||||
- page: 页码
|
||||
- page_size: 每页数量
|
||||
- 说明:此工具用于高级搜索,支持多维度过滤
|
||||
|
||||
2. **get_product_detail** - 获取商品详情
|
||||
3. **get_product_detail** - 获取商品详情
|
||||
- product_id: 商品ID
|
||||
|
||||
3. **recommend_products** - 智能推荐
|
||||
4. **recommend_products** - 智能推荐
|
||||
- context: 推荐上下文(可包含当前查询、浏览历史等)
|
||||
- limit: 推荐数量
|
||||
|
||||
4. **get_quote** - B2B 询价
|
||||
5. **get_quote** - B2B 询价
|
||||
- product_id: 商品ID
|
||||
- quantity: 采购数量
|
||||
- delivery_address: 收货地址(可选,用于计算运费)
|
||||
|
||||
5. **check_inventory** - 库存查询
|
||||
6. **check_inventory** - 库存查询
|
||||
- product_ids: 商品ID列表
|
||||
- warehouse: 仓库(可选)
|
||||
|
||||
@@ -205,13 +212,70 @@ async def product_agent(state: AgentState) -> AgentState:
|
||||
|
||||
async def _generate_product_response(state: AgentState) -> AgentState:
|
||||
"""Generate response based on product tool results"""
|
||||
|
||||
|
||||
# 特殊处理:如果是 search_spu_products 工具返回,直接发送商品卡片
|
||||
has_spu_search_result = False
|
||||
spu_products = []
|
||||
|
||||
for result in state["tool_results"]:
|
||||
if result["success"] and result["tool_name"] == "search_spu_products":
|
||||
data = result["data"]
|
||||
if isinstance(data, dict) and data.get("success"):
|
||||
spu_products = data.get("products", [])
|
||||
has_spu_search_result = True
|
||||
logger.info(
|
||||
"SPU product search results found",
|
||||
products_count=len(spu_products),
|
||||
keyword=data.get("keyword", "")
|
||||
)
|
||||
break
|
||||
|
||||
# 如果有 SPU 搜索结果,直接发送商品卡片
|
||||
if has_spu_search_result and spu_products:
|
||||
try:
|
||||
from integrations.chatwoot import ChatwootClient
|
||||
from core.language_detector import detect_language
|
||||
|
||||
# 检测语言
|
||||
detected_language = state.get("detected_language", "en")
|
||||
|
||||
# 发送商品卡片
|
||||
chatwoot = ChatwootClient(account_id=int(state.get("account_id", 1)))
|
||||
conversation_id = state.get("conversation_id")
|
||||
|
||||
if conversation_id:
|
||||
await chatwoot.send_product_cards(
|
||||
conversation_id=int(conversation_id),
|
||||
products=spu_products,
|
||||
language=detected_language
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Product cards sent successfully",
|
||||
conversation_id=conversation_id,
|
||||
products_count=len(spu_products),
|
||||
language=detected_language
|
||||
)
|
||||
|
||||
# 清空响应,避免重复发送
|
||||
state = set_response(state, "")
|
||||
state["state"] = ConversationState.GENERATING.value
|
||||
return state
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to send product cards, falling back to text response",
|
||||
error=str(e),
|
||||
products_count=len(spu_products)
|
||||
)
|
||||
|
||||
# 常规处理:生成文本响应
|
||||
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 product context
|
||||
if isinstance(data, dict):
|
||||
if data.get("product_id"):
|
||||
@@ -222,7 +286,7 @@ async def _generate_product_response(state: AgentState) -> AgentState:
|
||||
state = update_context(state, {"recent_product_ids": product_ids})
|
||||
else:
|
||||
tool_context.append(f"工具 {result['tool_name']} 执行失败: {result['error']}")
|
||||
|
||||
|
||||
prompt = f"""基于以下商品系统返回的信息,生成对用户的回复。
|
||||
|
||||
用户问题: {state["current_message"]}
|
||||
@@ -238,18 +302,18 @@ async def _generate_product_response(state: AgentState) -> AgentState:
|
||||
- 结果较多时可以总结关键信息
|
||||
|
||||
只返回回复内容,不要返回 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("Product response generation failed", error=str(e))
|
||||
state = set_response(state, "抱歉,处理商品信息时遇到问题。请稍后重试或联系人工客服。")
|
||||
|
||||
Reference in New Issue
Block a user