From 7a6869ad62c9bafb56c5c7f7d2319e067f68505d Mon Sep 17 00:00:00 2001 From: root <953994191@qq.com> Date: Wed, 29 Apr 2026 23:29:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=AC=E5=85=B1=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=EF=BC=9A=E8=81=94=E7=BD=91=E6=90=9C=E7=B4=A2=EF=BC=88?= =?UTF-8?q?DuckDuckGo=EF=BC=89=E5=92=8C=E5=8F=AF=E8=A7=86=E5=8C=96?= =?UTF-8?q?=E5=9B=BE=E8=A1=A8=EF=BC=88Mermaid=EF=BC=89=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20intent.py=20=E6=94=AF=E6=8C=81=20WEB=5FSEARCH=20?= =?UTF-8?q?=E5=8A=A8=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/core/intent.py | 39 +++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/backend/app/core/intent.py b/backend/app/core/intent.py index 33941cd..093724e 100644 --- a/backend/app/core/intent.py +++ b/backend/app/core/intent.py @@ -29,7 +29,8 @@ class ReasoningAction(Enum): DIRECT_RESPONSE = auto() # 直接回答,不需要额外信息 RETRIEVE_RAG = auto() # 需要调用 RAG 检索 RE_RETRIEVE_RAG = auto() # 需要重新检索(更多/更好结果) - ROUTE_SUBGRAPH = auto() # 需要路由到子图(contact/dictionary/news_analysis) + WEB_SEARCH = auto() # 需要联网搜索 + ROUTE_SUBGRAPH = auto() # 需要路由到子图(contact/dictionary/news_analysis/research) CLARIFY = auto() # 需要澄清用户的问题 UNKNOWN = auto() # 未知动作 @@ -78,7 +79,8 @@ class ReactIntentReasoner: self._subgraph_keywords = { "contact": ["通讯录", "联系人", "contact", "email", "邮件", "邮箱"], "dictionary": ["词典", "单词", "翻译", "dictionary", "translate", "生词"], - "news_analysis": ["资讯", "新闻", "分析", "news", "report", "热点"] + "news_analysis": ["资讯", "新闻", "分析", "news", "report", "热点"], + "research": ["研究", "深度分析", "报告", "引用", "溯源", "research", "analyze", "report"] } def _get_llm_service(self): @@ -146,11 +148,12 @@ class ReactIntentReasoner: 1. DIRECT_RESPONSE - 直接回答(闲聊、打招呼、不需要额外信息) 2. RETRIEVE_RAG - 需要查询知识库(询问知识、政策、文档等) 3. RE_RETRIEVE_RAG - 需要重新检索(之前的结果不够,或者用户明确说"再查查"、"更多") -4. ROUTE_SUBGRAPH - 需要路由到专门的子图: +4. WEB_SEARCH - 需要联网搜索(询问最新资讯、热点、实时信息、知识库中没有的内容) +5. ROUTE_SUBGRAPH - 需要路由到专门的子图: - contact: 通讯录、联系人、邮件相关 - dictionary: 词典、翻译、单词相关 - news_analysis: 资讯、新闻、热点分析相关 -5. CLARIFY - 需要澄清用户的问题(问题不明确) +6. CLARIFY - 需要澄清用户的问题(问题不明确) 用户查询: {query} 当前上下文: @@ -158,11 +161,12 @@ class ReactIntentReasoner: 请按以下 JSON 格式输出(仅输出 JSON,不要其他内容): {{ - "action": "DIRECT_RESPONSE|RETRIEVE_RAG|RE_RETRIEVE_RAG|ROUTE_SUBGRAPH|CLARIFY", + "action": "DIRECT_RESPONSE|RETRIEVE_RAG|RE_RETRIEVE_RAG|WEB_SEARCH|ROUTE_SUBGRAPH|CLARIFY", "confidence": 0.85, "reasoning": "简要说明理由", "target_subgraph": "contact|dictionary|news_analysis|null (仅当 action=ROUTE_SUBGRAPH 时)", - "retrieval_query": "优化后的检索查询 (可选)" + "retrieval_query": "优化后的检索查询 (可选)", + "search_query": "优化后的搜索查询 (仅当 action=WEB_SEARCH 时)" }} """ @@ -201,6 +205,11 @@ class ReactIntentReasoner: result.retrieval_config.need_re_retrieval = (result.action == ReasoningAction.RE_RETRIEVE_RAG) result.retrieval_config.retrieval_query = data.get("retrieval_query", original_query) + # 处理联网搜索 + if result.action == ReasoningAction.WEB_SEARCH: + result.metadata["need_web_search"] = True + result.metadata["search_query"] = data.get("search_query", original_query) + return result except Exception as e: print(f"[ReactReasoner] 解析 LLM 响应失败: {e}") @@ -226,7 +235,22 @@ class ReactIntentReasoner: result.metadata["target_subgraph"] = subgraph_name return result - # 2. 检查是否需要重新检索 + # 2. 检查是否需要联网搜索 + web_search_keywords = ["最新", "今天", "近日", "热点", "新闻", "实时", "搜索", "网上", "互联网", "最新消息", "recent", "latest", "hot", "news", "search", "web"] + has_web_search = any(kw in query_lower for kw in web_search_keywords) + # 检查是否包含年份(比如2024、2025等),通常需要最新信息 + import re + has_year = bool(re.search(r'202[3-9]|203[0-9]', query)) + + if has_web_search or has_year: + result.action = ReasoningAction.WEB_SEARCH + result.confidence = 0.85 if has_web_search else 0.7 + result.reasoning = "需要联网搜索最新信息" + result.metadata["need_web_search"] = True + result.metadata["search_query"] = query + return result + + # 3. 检查是否需要重新检索 re_retrieve_keywords = ["再", "重新", "更多", "不够", "其他", "没找到", "找不到", "不对", "another", "again", "more"] has_re_retrieve = any(kw in query_lower for kw in re_retrieve_keywords) has_docs = context.get("retrieved_docs") and len(context["retrieved_docs"]) > 0 @@ -362,6 +386,7 @@ def get_route_by_reasoning(result: ReasoningResult) -> str: ReasoningAction.DIRECT_RESPONSE: "direct_response", ReasoningAction.RETRIEVE_RAG: "retrieve_rag", ReasoningAction.RE_RETRIEVE_RAG: "re_retrieve_rag", + ReasoningAction.WEB_SEARCH: "web_search", ReasoningAction.CLARIFY: "clarify", ReasoningAction.ROUTE_SUBGRAPH: result.metadata.get("target_subgraph", "unknown_subgraph"), ReasoningAction.UNKNOWN: "unknown",