refactor: 单图方案重构 + 动态模型选择 + chat_services优化
All checks were successful
构建并部署 AI Agent 服务 / deploy (push) Successful in 12m9s
All checks were successful
构建并部署 AI Agent 服务 / deploy (push) Successful in 12m9s
## 核心改动 ### 1. 单图方案重构 - 删除了多图(self.graphs),改为单图(self.graph) - 新增 MainGraphState.current_model 字段用于运行时注入模型 - llm_call 节点改为动态选择模型(create_dynamic_llm_call_node) ### 2. chat_services 优化 - 添加 _cached_services 缓存,避免重复初始化 - 新增 get_cached_chat_services() 函数,用于单图注入 - 新增 _check_http_service_available() 统一HTTP探测逻辑 - 减少重复代码,LocalVLLMChatProvider和LocalSmallModelProvider共用探测方法 ### 3. AIAgentService 重构 - initialize() 只构建一次图,传入 chat_services 字典 - 新增 _resolve_model() 模型回退逻辑 - 新增 _build_invocation() 统一构建调用参数 - process_message() 和 process_message_stream() 改为注入 current_model - 流式处理代码拆分,增加可读性 ### 4. 新增和删除文件 - 新增:backend/app/main_graph/main_graph_builder.py(图构建) - 新增:backend/app/main_graph/subgraph_wrapper.py(子图封装) - 新增:tools/test/test_tavily_search.py(测试) - 删除:backend/app/main_graph/graph.py(旧图) - 删除:backend/app/main_graph/utils/main_graph_builder.py(旧构建器) - 删除:backend/app/main_graph/utils/__init__.py ### 5. 其他更新 - README.md:新增模型服务使用情况详解章节 - backend/app/model_services/__init__.py:新增 get_cached_chat_services 导出 ## 方案优势 - 内存优化:N张图 → 1张图 - 灵活性:运行时动态选择模型,支持同会话不同模型 - 性能:模型服务缓存,初始化仅一次 - 可维护性:减少重复代码,统一HTTP探测逻辑
This commit is contained in:
@@ -33,18 +33,29 @@ class WebSearchTool:
|
||||
|
||||
def search(self, query: str, max_results: Optional[int] = None) -> List[SearchResult]:
|
||||
"""
|
||||
使用多种方式搜索
|
||||
|
||||
使用多种方式搜索,按优先级尝试
|
||||
|
||||
Args:
|
||||
query: 搜索关键词
|
||||
max_results: 返回结果数量,默认使用初始化时的设置
|
||||
|
||||
|
||||
Returns:
|
||||
搜索结果列表
|
||||
"""
|
||||
num_results = max_results or self.max_results
|
||||
|
||||
# 方式 1: 尝试用 ddgs 包
|
||||
# 方式 1: Tavily (需要 API Key,质量最高)
|
||||
try:
|
||||
return self._search_tavily(query, num_results)
|
||||
except ImportError:
|
||||
print("[WebSearch] tavily 未安装,尝试其他搜索方式")
|
||||
except Exception as e:
|
||||
if "API_KEY" in str(e) or "未配置" in str(e):
|
||||
print(f"[WebSearch] Tavily API Key 未配置: {e}")
|
||||
else:
|
||||
print(f"[WebSearch] Tavily 搜索失败: {e}")
|
||||
|
||||
# 方式 2: 尝试用 ddgs 包
|
||||
try:
|
||||
from ddgs import DDGS
|
||||
print(f"[WebSearch] 使用 ddgs 搜索: {query}")
|
||||
@@ -65,29 +76,7 @@ class WebSearchTool:
|
||||
print("[WebSearch] ddgs 未安装,尝试 duckduckgo-search")
|
||||
except Exception as e:
|
||||
print(f"[WebSearch] ddgs 搜索失败: {e}")
|
||||
|
||||
# 方式 2: 尝试用旧的 duckduckgo-search 包
|
||||
try:
|
||||
from duckduckgo_search import DDGS
|
||||
print(f"[WebSearch] 使用 duckduckgo-search 搜索: {query}")
|
||||
with DDGS() as ddgs:
|
||||
results = list(ddgs.text(query, max_results=num_results))
|
||||
if results:
|
||||
search_results = []
|
||||
for r in results:
|
||||
search_results.append(SearchResult(
|
||||
title=r.get("title", ""),
|
||||
url=r.get("href", ""),
|
||||
snippet=r.get("body", ""),
|
||||
source="DuckDuckGo"
|
||||
))
|
||||
print(f"[WebSearch] duckduckgo-search 返回 {len(search_results)} 条结果")
|
||||
return search_results
|
||||
except ImportError:
|
||||
print("[WebSearch] duckduckgo-search 未安装")
|
||||
except Exception as e:
|
||||
print(f"[WebSearch] duckduckgo-search 搜索失败: {e}")
|
||||
|
||||
|
||||
# 方式 3: 尝试用简单 HTTP 请求
|
||||
try:
|
||||
return self._search_http(query, num_results)
|
||||
@@ -97,6 +86,34 @@ class WebSearchTool:
|
||||
# 方式 4: 返回模拟数据作为最后兜底
|
||||
return self._search_mock(query, num_results)
|
||||
|
||||
def _search_tavily(self, query: str, max_results: int) -> List[SearchResult]:
|
||||
"""使用 Tavily API 搜索"""
|
||||
from tavily import TavilyClient
|
||||
from app.config import TAVILY_API_KEY, TAVILY_MAX_RESULTS
|
||||
|
||||
if not TAVILY_API_KEY:
|
||||
raise ValueError("TAVILY_API_KEY 未配置")
|
||||
|
||||
client = TavilyClient(api_key=TAVILY_API_KEY)
|
||||
response = client.search(
|
||||
query=query,
|
||||
max_results=min(max_results, TAVILY_MAX_RESULTS or 5),
|
||||
include_answer=True,
|
||||
include_raw_content=False
|
||||
)
|
||||
|
||||
results = []
|
||||
for item in response.get("results", []):
|
||||
results.append(SearchResult(
|
||||
title=item.get("title", ""),
|
||||
url=item.get("url", ""),
|
||||
snippet=item.get("content", ""),
|
||||
source="Tavily"
|
||||
))
|
||||
|
||||
print(f"[WebSearch] Tavily 返回 {len(results)} 条结果")
|
||||
return results
|
||||
|
||||
def _search_http(self, query: str, max_results: int) -> List[SearchResult]:
|
||||
"""用简单 HTTP 请求搜索(备用方案)- 尝试多个国内源"""
|
||||
print(f"[WebSearch] 尝试 HTTP 搜索")
|
||||
|
||||
Reference in New Issue
Block a user