| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- from langchain_openai import ChatOpenAI
- from langchain_core.messages import SystemMessage, HumanMessage
- from app.tools.product_tools import search_product_by_keyword, search_activity_by_keyword, search_article_by_keyword
- from app.config import settings
- from app.monitoring import monitor_agent
- import json
- import logging
- from app.prompt_service import get_prompt
- logger = logging.getLogger(__name__)
- SYSTEM_PROMPT = """你是一个儿童成长营养推荐助手。根据用户的需求和营养标签, 推荐合适的商品、活动或文章。
- 推荐原则:
- 1. 首先尝试使用搜索工具查找匹配的内容
- 2. 如果搜索结果为空, 基于你的知识给出建议
- 3. 每项推荐必须附带推荐理由
- 4. 以 JSON 格式输出推荐结果
- 输出格式:
- {
- "items": [
- {
- "source": "tool" 或 "knowledge",
- "type": "product" / "activity" / "article",
- "id": 数字,
- "name": "名称",
- "description": "描述",
- "reason": "为什么推荐这个"
- }
- ]
- }
- """
- class RecommendAgent:
- def __init__(self):
- self.llm = ChatOpenAI(
- model=settings.llm_model,
- api_key=settings.llm_api_key,
- base_url=settings.llm_base_url,
- temperature=settings.llm_temperature,
- )
- self.tools = [
- search_product_by_keyword,
- search_activity_by_keyword,
- search_article_by_keyword,
- ]
- self.llm_with_tools = self.llm.bind_tools(self.tools)
- @monitor_agent("recommend")
- async def run(self, query: str, tags: list[str], limit: int = 5) -> dict:
- """执行推荐 Agent, 返回推荐结果"""
- # 如果传入了 tags, 构造搜索关键词
- search_query = query or " ".join(tags)
- messages = [
- SystemMessage(content=await get_prompt("recommend") or SYSTEM_PROMPT),
- HumanMessage(content=f"用户需求: {search_query}\n最大返回数量: {limit}\n请搜索并推荐合适的内容。"),
- ]
- # LangChain Tool calling 自动完成: LLM 决定调哪个 Tool → 工具返回结果 → LLM 组织回答
- response = await self.llm_with_tools.ainvoke(messages)
- # 尝试解析 JSON 输出
- content = response.content
- try:
- # 提取 JSON 块
- if "```json" in content:
- json_str = content.split("```json")[1].split("```")[0].strip()
- elif "```" in content:
- json_str = content.split("```")[1].split("```")[0].strip()
- else:
- json_str = content.strip()
- result = json.loads(json_str)
- return result
- except (json.JSONDecodeError, IndexError):
- # 非 JSON 输出, 包装为文本回答
- logger.warning("Agent 输出非 JSON, raw: %s", content[:200])
- return {"items": [], "text": content}
|