2026-02-28 08:21:35 +00:00
|
|
|
|
# ════════════════════════════════════════════════════════════════
|
2026-03-09 05:37:29 +00:00
|
|
|
|
# tools/web_search.py
|
2026-02-28 08:21:35 +00:00
|
|
|
|
# ════════════════════════════════════════════════════════════════
|
2026-03-09 05:37:29 +00:00
|
|
|
|
"""网络搜索工具(从配置读取 max_results / engine / api_key)"""
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
import time
|
|
|
|
|
|
from tools.base_tool import BaseTool, ToolResult
|
2026-03-09 05:37:29 +00:00
|
|
|
|
from config.settings import settings
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
_MOCK_RESULTS: dict[str, list[dict]] = {
|
2026-03-09 05:37:29 +00:00
|
|
|
|
"天气": [{"title": "今日天气预报", "snippet": "晴转多云,气温 15°C ~ 24°C,东南风 3 级"},
|
|
|
|
|
|
{"title": "未来 7 天天气", "snippet": "本周整体晴好,周末有小雨"}],
|
|
|
|
|
|
"python":[{"title": "Python 官方文档", "snippet": "Python 3.12 新特性:改进的错误提示"},
|
|
|
|
|
|
{"title": "Python 教程", "snippet": "从零开始学 Python,包含 300+ 实战案例"}],
|
2026-02-28 08:21:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
_DEFAULT_RESULTS = [
|
|
|
|
|
|
{"title": "搜索结果 1", "snippet": "找到相关内容,请查看详情"},
|
|
|
|
|
|
{"title": "搜索结果 2", "snippet": "更多相关信息可通过链接访问"},
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WebSearchTool(BaseTool):
|
|
|
|
|
|
name = "web_search"
|
|
|
|
|
|
description = "在互联网上搜索信息,返回相关网页摘要"
|
|
|
|
|
|
parameters = {
|
2026-03-09 05:37:29 +00:00
|
|
|
|
"query": {"type": "string", "description": "搜索关键词"},
|
|
|
|
|
|
"max_results": {"type": "integer", "description": "返回结果数量"},
|
2026-02-28 08:21:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-09 05:37:29 +00:00
|
|
|
|
def __init__(self):
|
|
|
|
|
|
super().__init__()
|
|
|
|
|
|
cfg = settings.tools.web_search
|
|
|
|
|
|
self._default_max = cfg.max_results
|
|
|
|
|
|
self._engine = cfg.engine
|
|
|
|
|
|
self._api_key = cfg.api_key
|
|
|
|
|
|
self._timeout = cfg.timeout
|
|
|
|
|
|
self.logger.debug(
|
|
|
|
|
|
f"⚙️ WebSearch engine={self._engine}, "
|
|
|
|
|
|
f"max_results={self._default_max}, "
|
|
|
|
|
|
f"api_key={'***' if self._api_key else '(未设置)'}"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def execute(self, query: str, max_results: int | None = None, **_) -> ToolResult:
|
|
|
|
|
|
max_results = max_results or self._default_max
|
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
|
|
|
|
|
|
|
if self._engine != "mock" and self._api_key:
|
|
|
|
|
|
# 生产环境:调用真实搜索 API
|
|
|
|
|
|
# results = self._call_real_api(query, max_results)
|
|
|
|
|
|
pass
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
results = _DEFAULT_RESULTS
|
2026-03-09 05:37:29 +00:00
|
|
|
|
for kw, data in _MOCK_RESULTS.items():
|
|
|
|
|
|
if kw in query:
|
2026-02-28 08:21:35 +00:00
|
|
|
|
results = data
|
|
|
|
|
|
break
|
|
|
|
|
|
results = results[:max_results]
|
|
|
|
|
|
formatted = "\n".join(
|
|
|
|
|
|
f"[{i+1}] {r['title']}\n {r['snippet']}"
|
|
|
|
|
|
for i, r in enumerate(results)
|
|
|
|
|
|
)
|
|
|
|
|
|
return ToolResult(
|
|
|
|
|
|
success=True,
|
2026-03-09 05:37:29 +00:00
|
|
|
|
output=f"搜索「{query}」({self._engine}),共 {len(results)} 条:\n{formatted}",
|
|
|
|
|
|
metadata={"query": query, "engine": self._engine, "count": len(results)},
|
|
|
|
|
|
)
|