Showing
5 changed files
with
99 additions
and
144 deletions
| @@ -19,7 +19,7 @@ from .nodes import ( | @@ -19,7 +19,7 @@ from .nodes import ( | ||
| 19 | ReportFormattingNode | 19 | ReportFormattingNode |
| 20 | ) | 20 | ) |
| 21 | from .state import State | 21 | from .state import State |
| 22 | -from .tools import TavilyNewsAgency, TavilyResponse | 22 | +from .tools import BochaMultimodalSearch, BochaResponse |
| 23 | from .utils import Config, load_config, format_search_results_for_prompt | 23 | from .utils import Config, load_config, format_search_results_for_prompt |
| 24 | 24 | ||
| 25 | 25 | ||
| @@ -40,7 +40,7 @@ class DeepSearchAgent: | @@ -40,7 +40,7 @@ class DeepSearchAgent: | ||
| 40 | self.llm_client = self._initialize_llm() | 40 | self.llm_client = self._initialize_llm() |
| 41 | 41 | ||
| 42 | # 初始化搜索工具集 | 42 | # 初始化搜索工具集 |
| 43 | - self.search_agency = TavilyNewsAgency(api_key=self.config.tavily_api_key) | 43 | + self.search_agency = BochaMultimodalSearch(api_key=self.config.bocha_api_key) |
| 44 | 44 | ||
| 45 | # 初始化节点 | 45 | # 初始化节点 |
| 46 | self._initialize_nodes() | 46 | self._initialize_nodes() |
| @@ -53,7 +53,7 @@ class DeepSearchAgent: | @@ -53,7 +53,7 @@ class DeepSearchAgent: | ||
| 53 | 53 | ||
| 54 | print(f"Deep Search Agent 已初始化") | 54 | print(f"Deep Search Agent 已初始化") |
| 55 | print(f"使用LLM: {self.llm_client.get_model_info()}") | 55 | print(f"使用LLM: {self.llm_client.get_model_info()}") |
| 56 | - print(f"搜索工具集: TavilyNewsAgency (支持6种搜索工具)") | 56 | + print(f"搜索工具集: BochaMultimodalSearch (支持5种多模态搜索工具)") |
| 57 | 57 | ||
| 58 | def _initialize_llm(self) -> BaseLLM: | 58 | def _initialize_llm(self) -> BaseLLM: |
| 59 | """初始化LLM客户端""" | 59 | """初始化LLM客户端""" |
| @@ -103,46 +103,40 @@ class DeepSearchAgent: | @@ -103,46 +103,40 @@ class DeepSearchAgent: | ||
| 103 | except ValueError: | 103 | except ValueError: |
| 104 | return False | 104 | return False |
| 105 | 105 | ||
| 106 | - def execute_search_tool(self, tool_name: str, query: str, **kwargs) -> TavilyResponse: | 106 | + def execute_search_tool(self, tool_name: str, query: str, **kwargs) -> BochaResponse: |
| 107 | """ | 107 | """ |
| 108 | 执行指定的搜索工具 | 108 | 执行指定的搜索工具 |
| 109 | 109 | ||
| 110 | Args: | 110 | Args: |
| 111 | tool_name: 工具名称,可选值: | 111 | tool_name: 工具名称,可选值: |
| 112 | - - "basic_search_news": 基础新闻搜索(快速、通用) | ||
| 113 | - - "deep_search_news": 深度新闻分析 | ||
| 114 | - - "search_news_last_24_hours": 24小时内最新新闻 | ||
| 115 | - - "search_news_last_week": 本周新闻 | ||
| 116 | - - "search_images_for_news": 新闻图片搜索 | ||
| 117 | - - "search_news_by_date": 按日期范围搜索新闻 | 112 | + - "comprehensive_search": 全面综合搜索(默认) |
| 113 | + - "web_search_only": 纯网页搜索 | ||
| 114 | + - "search_for_structured_data": 结构化数据查询 | ||
| 115 | + - "search_last_24_hours": 24小时内最新信息 | ||
| 116 | + - "search_last_week": 本周信息 | ||
| 118 | query: 搜索查询 | 117 | query: 搜索查询 |
| 119 | - **kwargs: 额外参数(如start_date, end_date, max_results) | 118 | + **kwargs: 额外参数(如max_results) |
| 120 | 119 | ||
| 121 | Returns: | 120 | Returns: |
| 122 | - TavilyResponse对象 | 121 | + BochaResponse对象 |
| 123 | """ | 122 | """ |
| 124 | print(f" → 执行搜索工具: {tool_name}") | 123 | print(f" → 执行搜索工具: {tool_name}") |
| 125 | 124 | ||
| 126 | - if tool_name == "basic_search_news": | ||
| 127 | - max_results = kwargs.get("max_results", 7) | ||
| 128 | - return self.search_agency.basic_search_news(query, max_results) | ||
| 129 | - elif tool_name == "deep_search_news": | ||
| 130 | - return self.search_agency.deep_search_news(query) | ||
| 131 | - elif tool_name == "search_news_last_24_hours": | ||
| 132 | - return self.search_agency.search_news_last_24_hours(query) | ||
| 133 | - elif tool_name == "search_news_last_week": | ||
| 134 | - return self.search_agency.search_news_last_week(query) | ||
| 135 | - elif tool_name == "search_images_for_news": | ||
| 136 | - return self.search_agency.search_images_for_news(query) | ||
| 137 | - elif tool_name == "search_news_by_date": | ||
| 138 | - start_date = kwargs.get("start_date") | ||
| 139 | - end_date = kwargs.get("end_date") | ||
| 140 | - if not start_date or not end_date: | ||
| 141 | - raise ValueError("search_news_by_date工具需要start_date和end_date参数") | ||
| 142 | - return self.search_agency.search_news_by_date(query, start_date, end_date) | 125 | + if tool_name == "comprehensive_search": |
| 126 | + max_results = kwargs.get("max_results", 10) | ||
| 127 | + return self.search_agency.comprehensive_search(query, max_results) | ||
| 128 | + elif tool_name == "web_search_only": | ||
| 129 | + max_results = kwargs.get("max_results", 15) | ||
| 130 | + return self.search_agency.web_search_only(query, max_results) | ||
| 131 | + elif tool_name == "search_for_structured_data": | ||
| 132 | + return self.search_agency.search_for_structured_data(query) | ||
| 133 | + elif tool_name == "search_last_24_hours": | ||
| 134 | + return self.search_agency.search_last_24_hours(query) | ||
| 135 | + elif tool_name == "search_last_week": | ||
| 136 | + return self.search_agency.search_last_week(query) | ||
| 143 | else: | 137 | else: |
| 144 | - print(f" ⚠️ 未知的搜索工具: {tool_name},使用默认基础搜索") | ||
| 145 | - return self.search_agency.basic_search_news(query) | 138 | + print(f" ⚠️ 未知的搜索工具: {tool_name},使用默认综合搜索") |
| 139 | + return self.search_agency.comprehensive_search(query) | ||
| 146 | 140 | ||
| 147 | def research(self, query: str, save_report: bool = True) -> str: | 141 | def research(self, query: str, save_report: bool = True) -> str: |
| 148 | """ | 142 | """ |
| @@ -231,7 +225,7 @@ class DeepSearchAgent: | @@ -231,7 +225,7 @@ class DeepSearchAgent: | ||
| 231 | print(" - 生成搜索查询...") | 225 | print(" - 生成搜索查询...") |
| 232 | search_output = self.first_search_node.run(search_input) | 226 | search_output = self.first_search_node.run(search_input) |
| 233 | search_query = search_output["search_query"] | 227 | search_query = search_output["search_query"] |
| 234 | - search_tool = search_output.get("search_tool", "basic_search_news") # 默认工具 | 228 | + search_tool = search_output.get("search_tool", "comprehensive_search") # 默认工具 |
| 235 | reasoning = search_output["reasoning"] | 229 | reasoning = search_output["reasoning"] |
| 236 | 230 | ||
| 237 | print(f" - 搜索查询: {search_query}") | 231 | print(f" - 搜索查询: {search_query}") |
| @@ -241,41 +235,27 @@ class DeepSearchAgent: | @@ -241,41 +235,27 @@ class DeepSearchAgent: | ||
| 241 | # 执行搜索 | 235 | # 执行搜索 |
| 242 | print(" - 执行网络搜索...") | 236 | print(" - 执行网络搜索...") |
| 243 | 237 | ||
| 244 | - # 处理search_news_by_date的特殊参数 | 238 | + # 处理特殊参数(新的工具集不需要日期参数处理) |
| 245 | search_kwargs = {} | 239 | search_kwargs = {} |
| 246 | - if search_tool == "search_news_by_date": | ||
| 247 | - start_date = search_output.get("start_date") | ||
| 248 | - end_date = search_output.get("end_date") | ||
| 249 | - | ||
| 250 | - if start_date and end_date: | ||
| 251 | - # 验证日期格式 | ||
| 252 | - if self._validate_date_format(start_date) and self._validate_date_format(end_date): | ||
| 253 | - search_kwargs["start_date"] = start_date | ||
| 254 | - search_kwargs["end_date"] = end_date | ||
| 255 | - print(f" - 时间范围: {start_date} 到 {end_date}") | ||
| 256 | - else: | ||
| 257 | - print(f" ⚠️ 日期格式错误(应为YYYY-MM-DD),改用基础搜索") | ||
| 258 | - print(f" 提供的日期: start_date={start_date}, end_date={end_date}") | ||
| 259 | - search_tool = "basic_search_news" | ||
| 260 | - else: | ||
| 261 | - print(f" ⚠️ search_news_by_date工具缺少时间参数,改用基础搜索") | ||
| 262 | - search_tool = "basic_search_news" | 240 | + if search_tool in ["comprehensive_search", "web_search_only"]: |
| 241 | + # 这些工具支持max_results参数 | ||
| 242 | + search_kwargs["max_results"] = 10 | ||
| 263 | 243 | ||
| 264 | search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs) | 244 | search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs) |
| 265 | 245 | ||
| 266 | # 转换为兼容格式 | 246 | # 转换为兼容格式 |
| 267 | search_results = [] | 247 | search_results = [] |
| 268 | - if search_response and search_response.results: | 248 | + if search_response and search_response.webpages: |
| 269 | # 每种搜索工具都有其特定的结果数量,这里取前10个作为上限 | 249 | # 每种搜索工具都有其特定的结果数量,这里取前10个作为上限 |
| 270 | - max_results = min(len(search_response.results), 10) | ||
| 271 | - for result in search_response.results[:max_results]: | 250 | + max_results = min(len(search_response.webpages), 10) |
| 251 | + for result in search_response.webpages[:max_results]: | ||
| 272 | search_results.append({ | 252 | search_results.append({ |
| 273 | - 'title': result.title, | 253 | + 'title': result.name, |
| 274 | 'url': result.url, | 254 | 'url': result.url, |
| 275 | - 'content': result.content, | ||
| 276 | - 'score': result.score, | ||
| 277 | - 'raw_content': result.raw_content, | ||
| 278 | - 'published_date': result.published_date # 新增字段 | 255 | + 'content': result.snippet, |
| 256 | + 'score': None, # Bocha API不提供score | ||
| 257 | + 'raw_content': result.snippet, | ||
| 258 | + 'published_date': result.date_last_crawled # 使用爬取日期 | ||
| 279 | }) | 259 | }) |
| 280 | 260 | ||
| 281 | if search_results: | 261 | if search_results: |
| @@ -324,7 +304,7 @@ class DeepSearchAgent: | @@ -324,7 +304,7 @@ class DeepSearchAgent: | ||
| 324 | # 生成反思搜索查询 | 304 | # 生成反思搜索查询 |
| 325 | reflection_output = self.reflection_node.run(reflection_input) | 305 | reflection_output = self.reflection_node.run(reflection_input) |
| 326 | search_query = reflection_output["search_query"] | 306 | search_query = reflection_output["search_query"] |
| 327 | - search_tool = reflection_output.get("search_tool", "basic_search_news") # 默认工具 | 307 | + search_tool = reflection_output.get("search_tool", "comprehensive_search") # 默认工具 |
| 328 | reasoning = reflection_output["reasoning"] | 308 | reasoning = reflection_output["reasoning"] |
| 329 | 309 | ||
| 330 | print(f" 反思查询: {search_query}") | 310 | print(f" 反思查询: {search_query}") |
| @@ -332,41 +312,27 @@ class DeepSearchAgent: | @@ -332,41 +312,27 @@ class DeepSearchAgent: | ||
| 332 | print(f" 反思推理: {reasoning}") | 312 | print(f" 反思推理: {reasoning}") |
| 333 | 313 | ||
| 334 | # 执行反思搜索 | 314 | # 执行反思搜索 |
| 335 | - # 处理search_news_by_date的特殊参数 | 315 | + # 处理特殊参数 |
| 336 | search_kwargs = {} | 316 | search_kwargs = {} |
| 337 | - if search_tool == "search_news_by_date": | ||
| 338 | - start_date = reflection_output.get("start_date") | ||
| 339 | - end_date = reflection_output.get("end_date") | ||
| 340 | - | ||
| 341 | - if start_date and end_date: | ||
| 342 | - # 验证日期格式 | ||
| 343 | - if self._validate_date_format(start_date) and self._validate_date_format(end_date): | ||
| 344 | - search_kwargs["start_date"] = start_date | ||
| 345 | - search_kwargs["end_date"] = end_date | ||
| 346 | - print(f" 时间范围: {start_date} 到 {end_date}") | ||
| 347 | - else: | ||
| 348 | - print(f" ⚠️ 日期格式错误(应为YYYY-MM-DD),改用基础搜索") | ||
| 349 | - print(f" 提供的日期: start_date={start_date}, end_date={end_date}") | ||
| 350 | - search_tool = "basic_search_news" | ||
| 351 | - else: | ||
| 352 | - print(f" ⚠️ search_news_by_date工具缺少时间参数,改用基础搜索") | ||
| 353 | - search_tool = "basic_search_news" | 317 | + if search_tool in ["comprehensive_search", "web_search_only"]: |
| 318 | + # 这些工具支持max_results参数 | ||
| 319 | + search_kwargs["max_results"] = 10 | ||
| 354 | 320 | ||
| 355 | search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs) | 321 | search_response = self.execute_search_tool(search_tool, search_query, **search_kwargs) |
| 356 | 322 | ||
| 357 | # 转换为兼容格式 | 323 | # 转换为兼容格式 |
| 358 | search_results = [] | 324 | search_results = [] |
| 359 | - if search_response and search_response.results: | 325 | + if search_response and search_response.webpages: |
| 360 | # 每种搜索工具都有其特定的结果数量,这里取前10个作为上限 | 326 | # 每种搜索工具都有其特定的结果数量,这里取前10个作为上限 |
| 361 | - max_results = min(len(search_response.results), 10) | ||
| 362 | - for result in search_response.results[:max_results]: | 327 | + max_results = min(len(search_response.webpages), 10) |
| 328 | + for result in search_response.webpages[:max_results]: | ||
| 363 | search_results.append({ | 329 | search_results.append({ |
| 364 | - 'title': result.title, | 330 | + 'title': result.name, |
| 365 | 'url': result.url, | 331 | 'url': result.url, |
| 366 | - 'content': result.content, | ||
| 367 | - 'score': result.score, | ||
| 368 | - 'raw_content': result.raw_content, | ||
| 369 | - 'published_date': result.published_date | 332 | + 'content': result.snippet, |
| 333 | + 'score': None, # Bocha API不提供score | ||
| 334 | + 'raw_content': result.snippet, | ||
| 335 | + 'published_date': result.date_last_crawled | ||
| 370 | }) | 336 | }) |
| 371 | 337 | ||
| 372 | if search_results: | 338 | if search_results: |
| @@ -34,9 +34,7 @@ output_schema_first_search = { | @@ -34,9 +34,7 @@ output_schema_first_search = { | ||
| 34 | "properties": { | 34 | "properties": { |
| 35 | "search_query": {"type": "string"}, | 35 | "search_query": {"type": "string"}, |
| 36 | "search_tool": {"type": "string"}, | 36 | "search_tool": {"type": "string"}, |
| 37 | - "reasoning": {"type": "string"}, | ||
| 38 | - "start_date": {"type": "string", "description": "开始日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"}, | ||
| 39 | - "end_date": {"type": "string", "description": "结束日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"} | 37 | + "reasoning": {"type": "string"} |
| 40 | }, | 38 | }, |
| 41 | "required": ["search_query", "search_tool", "reasoning"] | 39 | "required": ["search_query", "search_tool", "reasoning"] |
| 42 | } | 40 | } |
| @@ -79,9 +77,7 @@ output_schema_reflection = { | @@ -79,9 +77,7 @@ output_schema_reflection = { | ||
| 79 | "properties": { | 77 | "properties": { |
| 80 | "search_query": {"type": "string"}, | 78 | "search_query": {"type": "string"}, |
| 81 | "search_tool": {"type": "string"}, | 79 | "search_tool": {"type": "string"}, |
| 82 | - "reasoning": {"type": "string"}, | ||
| 83 | - "start_date": {"type": "string", "description": "开始日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"}, | ||
| 84 | - "end_date": {"type": "string", "description": "结束日期,格式YYYY-MM-DD,仅search_news_by_date工具需要"} | 80 | + "reasoning": {"type": "string"} |
| 85 | }, | 81 | }, |
| 86 | "required": ["search_query", "search_tool", "reasoning"] | 82 | "required": ["search_query", "search_tool", "reasoning"] |
| 87 | } | 83 | } |
| @@ -147,41 +143,34 @@ SYSTEM_PROMPT_FIRST_SEARCH = f""" | @@ -147,41 +143,34 @@ SYSTEM_PROMPT_FIRST_SEARCH = f""" | ||
| 147 | {json.dumps(input_schema_first_search, indent=2, ensure_ascii=False)} | 143 | {json.dumps(input_schema_first_search, indent=2, ensure_ascii=False)} |
| 148 | </INPUT JSON SCHEMA> | 144 | </INPUT JSON SCHEMA> |
| 149 | 145 | ||
| 150 | -你可以使用以下6种专业的新闻搜索工具: | 146 | +你可以使用以下5种专业的多模态搜索工具: |
| 151 | 147 | ||
| 152 | -1. **basic_search_news** - 基础新闻搜索工具 | ||
| 153 | - - 适用于:一般性的新闻搜索,不确定需要何种特定搜索时 | ||
| 154 | - - 特点:快速、标准的通用搜索,是最常用的基础工具 | 148 | +1. **comprehensive_search** - 全面综合搜索工具 |
| 149 | + - 适用于:一般性的研究需求,需要完整信息时 | ||
| 150 | + - 特点:返回网页、图片、AI总结、追问建议和可能的结构化数据,是最常用的基础工具 | ||
| 155 | 151 | ||
| 156 | -2. **deep_search_news** - 深度新闻分析工具 | ||
| 157 | - - 适用于:需要全面深入了解某个主题时 | ||
| 158 | - - 特点:提供最详细的分析结果,包含高级AI摘要 | 152 | +2. **web_search_only** - 纯网页搜索工具 |
| 153 | + - 适用于:只需要网页链接和摘要,不需要AI分析时 | ||
| 154 | + - 特点:速度更快,成本更低,只返回网页结果 | ||
| 159 | 155 | ||
| 160 | -3. **search_news_last_24_hours** - 24小时最新新闻工具 | 156 | +3. **search_for_structured_data** - 结构化数据查询工具 |
| 157 | + - 适用于:查询天气、股票、汇率、百科定义等结构化信息时 | ||
| 158 | + - 特点:专门用于触发"模态卡"的查询,返回结构化数据 | ||
| 159 | + | ||
| 160 | +4. **search_last_24_hours** - 24小时内信息搜索工具 | ||
| 161 | - 适用于:需要了解最新动态、突发事件时 | 161 | - 适用于:需要了解最新动态、突发事件时 |
| 162 | - - 特点:只搜索过去24小时的新闻 | 162 | + - 特点:只搜索过去24小时内发布的内容 |
| 163 | 163 | ||
| 164 | -4. **search_news_last_week** - 本周新闻工具 | 164 | +5. **search_last_week** - 本周信息搜索工具 |
| 165 | - 适用于:需要了解近期发展趋势时 | 165 | - 适用于:需要了解近期发展趋势时 |
| 166 | - - 特点:搜索过去一周的新闻报道 | ||
| 167 | - | ||
| 168 | -5. **search_images_for_news** - 图片搜索工具 | ||
| 169 | - - 适用于:需要可视化信息、图片资料时 | ||
| 170 | - - 特点:提供相关图片和图片描述 | ||
| 171 | - | ||
| 172 | -6. **search_news_by_date** - 按日期范围搜索工具 | ||
| 173 | - - 适用于:需要研究特定历史时期时 | ||
| 174 | - - 特点:可以指定开始和结束日期进行搜索 | ||
| 175 | - - 特殊要求:需要提供start_date和end_date参数,格式为'YYYY-MM-DD' | ||
| 176 | - - 注意:只有这个工具需要额外的时间参数 | 166 | + - 特点:搜索过去一周内的主要报道 |
| 177 | 167 | ||
| 178 | 你的任务是: | 168 | 你的任务是: |
| 179 | 1. 根据段落主题选择最合适的搜索工具 | 169 | 1. 根据段落主题选择最合适的搜索工具 |
| 180 | 2. 制定最佳的搜索查询 | 170 | 2. 制定最佳的搜索查询 |
| 181 | -3. 如果选择search_news_by_date工具,必须同时提供start_date和end_date参数(格式:YYYY-MM-DD) | ||
| 182 | -4. 解释你的选择理由 | 171 | +3. 解释你的选择理由 |
| 183 | 172 | ||
| 184 | -注意:除了search_news_by_date工具外,其他工具都不需要额外参数。 | 173 | +注意:所有工具都不需要额外参数,选择工具主要基于搜索意图和需要的信息类型。 |
| 185 | 请按照以下JSON模式定义格式化输出(文字请使用中文): | 174 | 请按照以下JSON模式定义格式化输出(文字请使用中文): |
| 186 | 175 | ||
| 187 | <OUTPUT JSON SCHEMA> | 176 | <OUTPUT JSON SCHEMA> |
| @@ -219,23 +208,21 @@ SYSTEM_PROMPT_REFLECTION = f""" | @@ -219,23 +208,21 @@ SYSTEM_PROMPT_REFLECTION = f""" | ||
| 219 | {json.dumps(input_schema_reflection, indent=2, ensure_ascii=False)} | 208 | {json.dumps(input_schema_reflection, indent=2, ensure_ascii=False)} |
| 220 | </INPUT JSON SCHEMA> | 209 | </INPUT JSON SCHEMA> |
| 221 | 210 | ||
| 222 | -你可以使用以下6种专业的新闻搜索工具: | 211 | +你可以使用以下5种专业的多模态搜索工具: |
| 223 | 212 | ||
| 224 | -1. **basic_search_news** - 基础新闻搜索工具 | ||
| 225 | -2. **deep_search_news** - 深度新闻分析工具 | ||
| 226 | -3. **search_news_last_24_hours** - 24小时最新新闻工具 | ||
| 227 | -4. **search_news_last_week** - 本周新闻工具 | ||
| 228 | -5. **search_images_for_news** - 图片搜索工具 | ||
| 229 | -6. **search_news_by_date** - 按日期范围搜索工具(需要时间参数) | 213 | +1. **comprehensive_search** - 全面综合搜索工具 |
| 214 | +2. **web_search_only** - 纯网页搜索工具 | ||
| 215 | +3. **search_for_structured_data** - 结构化数据查询工具 | ||
| 216 | +4. **search_last_24_hours** - 24小时内信息搜索工具 | ||
| 217 | +5. **search_last_week** - 本周信息搜索工具 | ||
| 230 | 218 | ||
| 231 | 你的任务是: | 219 | 你的任务是: |
| 232 | 1. 反思段落文本的当前状态,思考是否遗漏了主题的某些关键方面 | 220 | 1. 反思段落文本的当前状态,思考是否遗漏了主题的某些关键方面 |
| 233 | 2. 选择最合适的搜索工具来补充缺失信息 | 221 | 2. 选择最合适的搜索工具来补充缺失信息 |
| 234 | 3. 制定精确的搜索查询 | 222 | 3. 制定精确的搜索查询 |
| 235 | -4. 如果选择search_news_by_date工具,必须同时提供start_date和end_date参数(格式:YYYY-MM-DD) | ||
| 236 | -5. 解释你的选择和推理 | 223 | +4. 解释你的选择和推理 |
| 237 | 224 | ||
| 238 | -注意:除了search_news_by_date工具外,其他工具都不需要额外参数。 | 225 | +注意:所有工具都不需要额外参数,选择工具主要基于搜索意图和需要的信息类型。 |
| 239 | 请按照以下JSON模式定义格式化输出: | 226 | 请按照以下JSON模式定义格式化输出: |
| 240 | 227 | ||
| 241 | <OUTPUT JSON SCHEMA> | 228 | <OUTPUT JSON SCHEMA> |
| 1 | """ | 1 | """ |
| 2 | 工具调用模块 | 2 | 工具调用模块 |
| 3 | -提供外部工具接口,如网络搜索等 | 3 | +提供外部工具接口,如多模态搜索等 |
| 4 | """ | 4 | """ |
| 5 | 5 | ||
| 6 | from .search import ( | 6 | from .search import ( |
| 7 | - TavilyNewsAgency, | ||
| 8 | - SearchResult, | ||
| 9 | - TavilyResponse, | 7 | + BochaMultimodalSearch, |
| 8 | + WebpageResult, | ||
| 10 | ImageResult, | 9 | ImageResult, |
| 10 | + ModalCardResult, | ||
| 11 | + BochaResponse, | ||
| 11 | print_response_summary | 12 | print_response_summary |
| 12 | ) | 13 | ) |
| 13 | 14 | ||
| 14 | __all__ = [ | 15 | __all__ = [ |
| 15 | - "TavilyNewsAgency", | ||
| 16 | - "SearchResult", | ||
| 17 | - "TavilyResponse", | 16 | + "BochaMultimodalSearch", |
| 17 | + "WebpageResult", | ||
| 18 | "ImageResult", | 18 | "ImageResult", |
| 19 | + "ModalCardResult", | ||
| 20 | + "BochaResponse", | ||
| 19 | "print_response_summary" | 21 | "print_response_summary" |
| 20 | ] | 22 | ] |
| @@ -14,7 +14,7 @@ class Config: | @@ -14,7 +14,7 @@ class Config: | ||
| 14 | # API密钥 | 14 | # API密钥 |
| 15 | deepseek_api_key: Optional[str] = None | 15 | deepseek_api_key: Optional[str] = None |
| 16 | openai_api_key: Optional[str] = None | 16 | openai_api_key: Optional[str] = None |
| 17 | - tavily_api_key: Optional[str] = None | 17 | + bocha_api_key: Optional[str] = None |
| 18 | 18 | ||
| 19 | # 模型配置 | 19 | # 模型配置 |
| 20 | default_llm_provider: str = "deepseek" # deepseek 或 openai | 20 | default_llm_provider: str = "deepseek" # deepseek 或 openai |
| @@ -44,8 +44,8 @@ class Config: | @@ -44,8 +44,8 @@ class Config: | ||
| 44 | print("错误: OpenAI API Key未设置") | 44 | print("错误: OpenAI API Key未设置") |
| 45 | return False | 45 | return False |
| 46 | 46 | ||
| 47 | - if not self.tavily_api_key: | ||
| 48 | - print("错误: Tavily API Key未设置") | 47 | + if not self.bocha_api_key: |
| 48 | + print("错误: Bocha API Key未设置") | ||
| 49 | return False | 49 | return False |
| 50 | 50 | ||
| 51 | return True | 51 | return True |
| @@ -65,7 +65,7 @@ class Config: | @@ -65,7 +65,7 @@ class Config: | ||
| 65 | return cls( | 65 | return cls( |
| 66 | deepseek_api_key=getattr(config_module, "DEEPSEEK_API_KEY", None), | 66 | deepseek_api_key=getattr(config_module, "DEEPSEEK_API_KEY", None), |
| 67 | openai_api_key=getattr(config_module, "OPENAI_API_KEY", None), | 67 | openai_api_key=getattr(config_module, "OPENAI_API_KEY", None), |
| 68 | - tavily_api_key=getattr(config_module, "TAVILY_API_KEY", None), | 68 | + bocha_api_key=getattr(config_module, "BOCHA_API_KEY", None), |
| 69 | default_llm_provider=getattr(config_module, "DEFAULT_LLM_PROVIDER", "deepseek"), | 69 | default_llm_provider=getattr(config_module, "DEFAULT_LLM_PROVIDER", "deepseek"), |
| 70 | deepseek_model=getattr(config_module, "DEEPSEEK_MODEL", "deepseek-chat"), | 70 | deepseek_model=getattr(config_module, "DEEPSEEK_MODEL", "deepseek-chat"), |
| 71 | openai_model=getattr(config_module, "OPENAI_MODEL", "gpt-4o-mini"), | 71 | openai_model=getattr(config_module, "OPENAI_MODEL", "gpt-4o-mini"), |
| @@ -92,7 +92,7 @@ class Config: | @@ -92,7 +92,7 @@ class Config: | ||
| 92 | return cls( | 92 | return cls( |
| 93 | deepseek_api_key=config_dict.get("DEEPSEEK_API_KEY"), | 93 | deepseek_api_key=config_dict.get("DEEPSEEK_API_KEY"), |
| 94 | openai_api_key=config_dict.get("OPENAI_API_KEY"), | 94 | openai_api_key=config_dict.get("OPENAI_API_KEY"), |
| 95 | - tavily_api_key=config_dict.get("TAVILY_API_KEY"), | 95 | + bocha_api_key=config_dict.get("BOCHA_API_KEY"), |
| 96 | default_llm_provider=config_dict.get("DEFAULT_LLM_PROVIDER", "deepseek"), | 96 | default_llm_provider=config_dict.get("DEFAULT_LLM_PROVIDER", "deepseek"), |
| 97 | deepseek_model=config_dict.get("DEEPSEEK_MODEL", "deepseek-chat"), | 97 | deepseek_model=config_dict.get("DEEPSEEK_MODEL", "deepseek-chat"), |
| 98 | openai_model=config_dict.get("OPENAI_MODEL", "gpt-4o-mini"), | 98 | openai_model=config_dict.get("OPENAI_MODEL", "gpt-4o-mini"), |
| @@ -147,7 +147,7 @@ def print_config(config: Config): | @@ -147,7 +147,7 @@ def print_config(config: Config): | ||
| 147 | print(f"LLM提供商: {config.default_llm_provider}") | 147 | print(f"LLM提供商: {config.default_llm_provider}") |
| 148 | print(f"DeepSeek模型: {config.deepseek_model}") | 148 | print(f"DeepSeek模型: {config.deepseek_model}") |
| 149 | print(f"OpenAI模型: {config.openai_model}") | 149 | print(f"OpenAI模型: {config.openai_model}") |
| 150 | - print(f"最大搜索结果数: {config.max_search_results}") | 150 | + |
| 151 | print(f"搜索超时: {config.search_timeout}秒") | 151 | print(f"搜索超时: {config.search_timeout}秒") |
| 152 | print(f"最大内容长度: {config.max_content_length}") | 152 | print(f"最大内容长度: {config.max_content_length}") |
| 153 | print(f"最大反思次数: {config.max_reflections}") | 153 | print(f"最大反思次数: {config.max_reflections}") |
| @@ -158,5 +158,5 @@ def print_config(config: Config): | @@ -158,5 +158,5 @@ def print_config(config: Config): | ||
| 158 | # 显示API密钥状态(不显示实际密钥) | 158 | # 显示API密钥状态(不显示实际密钥) |
| 159 | print(f"DeepSeek API Key: {'已设置' if config.deepseek_api_key else '未设置'}") | 159 | print(f"DeepSeek API Key: {'已设置' if config.deepseek_api_key else '未设置'}") |
| 160 | print(f"OpenAI API Key: {'已设置' if config.openai_api_key else '未设置'}") | 160 | print(f"OpenAI API Key: {'已设置' if config.openai_api_key else '未设置'}") |
| 161 | - print(f"Tavily API Key: {'已设置' if config.tavily_api_key else '未设置'}") | 161 | + print(f"Bocha API Key: {'已设置' if config.bocha_api_key else '未设置'}") |
| 162 | print("==================\n") | 162 | print("==================\n") |
| @@ -12,8 +12,8 @@ import json | @@ -12,8 +12,8 @@ import json | ||
| 12 | # 添加src目录到Python路径 | 12 | # 添加src目录到Python路径 |
| 13 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '.')) | 13 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '.')) |
| 14 | 14 | ||
| 15 | -from QueryEngine import DeepSearchAgent, Config | ||
| 16 | -from config import DEEPSEEK_API_KEY, TAVILY_API_KEY | 15 | +from MediaEngine import DeepSearchAgent, Config |
| 16 | +from config import DEEPSEEK_API_KEY, BOCHA_Web_Search_API_KEY | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | def main(): | 19 | def main(): |
| @@ -98,19 +98,19 @@ def main(): | @@ -98,19 +98,19 @@ def main(): | ||
| 98 | 98 | ||
| 99 | # 自动使用配置文件中的API密钥 | 99 | # 自动使用配置文件中的API密钥 |
| 100 | deepseek_key = DEEPSEEK_API_KEY | 100 | deepseek_key = DEEPSEEK_API_KEY |
| 101 | - tavily_key = TAVILY_API_KEY | 101 | + bocha_key = BOCHA_Web_Search_API_KEY |
| 102 | 102 | ||
| 103 | # 创建配置 | 103 | # 创建配置 |
| 104 | config = Config( | 104 | config = Config( |
| 105 | deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None, | 105 | deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None, |
| 106 | openai_api_key=openai_key if llm_provider == "openai" else None, | 106 | openai_api_key=openai_key if llm_provider == "openai" else None, |
| 107 | - tavily_api_key=tavily_key, | 107 | + bocha_api_key=bocha_key, |
| 108 | default_llm_provider=llm_provider, | 108 | default_llm_provider=llm_provider, |
| 109 | deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat", | 109 | deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat", |
| 110 | openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini", | 110 | openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini", |
| 111 | max_reflections=max_reflections, | 111 | max_reflections=max_reflections, |
| 112 | max_content_length=max_content_length, | 112 | max_content_length=max_content_length, |
| 113 | - output_dir="query_engine_streamlit_reports" | 113 | + output_dir="media_engine_streamlit_reports" |
| 114 | ) | 114 | ) |
| 115 | 115 | ||
| 116 | # 执行研究 | 116 | # 执行研究 |
-
Please register or login to post a comment