from typing import List, Optional from models.debate import SearchResult, SearchEvidence class SearchService: """ Tavily web search wrapper for debate research. """ def __init__(self, api_key: str): from tavily import TavilyClient self.client = TavilyClient(api_key=api_key) def search(self, query: str, max_results: int = 5) -> List[SearchResult]: """ Perform a web search using Tavily and return structured results. """ try: response = self.client.search( query=query, max_results=max_results, search_depth="basic" ) results = [] for item in response.get("results", []): results.append(SearchResult( title=item.get("title", ""), url=item.get("url", ""), snippet=item.get("content", "")[:500], # Truncate to avoid token bloat score=item.get("score") )) return results except Exception as e: print(f"Tavily search error: {e}") return [] @staticmethod def format_results_for_context(evidence: SearchEvidence) -> str: """ Format search results into a string suitable for injecting into the LLM context. """ if not evidence or not evidence.results: return "" lines = [f"\n[网络搜索结果] 搜索词: \"{evidence.query}\""] for i, r in enumerate(evidence.results, 1): lines.append(f" {i}. {r.title}") lines.append(f" {r.snippet}") lines.append(f" 来源: {r.url}") lines.append("[搜索结果结束]\n") return "\n".join(lines) @staticmethod def generate_search_query(topic: str, last_opponent_argument: Optional[str] = None) -> str: """ Generate a search query from the debate topic and the opponent's last argument. """ if last_opponent_argument: # Extract key phrases from the opponent's argument (first ~100 chars) snippet = last_opponent_argument[:100].strip() return f"{topic} {snippet}" return topic @staticmethod def get_tool_definition() -> dict: """ Return the web_search tool definition for function calling. """ return { "type": "function", "function": { "name": "web_search", "description": "Search the web for current information relevant to the debate topic. Use this to find facts, statistics, or recent news that support your argument.", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "The search query to look up" } }, "required": ["query"] } } } @staticmethod def get_tool_definition_anthropic() -> dict: """ Return the web_search tool definition in Anthropic format. """ return { "name": "web_search", "description": "Search the web for current information relevant to the debate topic. Use this to find facts, statistics, or recent news that support your argument.", "input_schema": { "type": "object", "properties": { "query": { "type": "string", "description": "The search query to look up" } }, "required": ["query"] } }