105 lines
3.7 KiB
Python
105 lines
3.7 KiB
Python
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"]
|
|
}
|
|
}
|