from typing import Any, Dict, List, Optional
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from duckduckgo_search import DDGS
import re
import math
class WebSearchTool:
def __init__(self):
self.search = DDGS()
def run(self, query: str, max_results: int = 3) -> str:
"""Perform a web search and return formatted results."""
try:
results = list(self.search.text(query, max_results=max_results))
formatted_results = []
for r in results:
formatted_results.append(f"Title: {r['title']}\nSnippet: {r['body']}\nURL: {r['link']}\n")
return "\n".join(formatted_results)
except Exception as e:
return f"Error performing web search: {str(e)}"
class Calculator:
def run(self, expression: str) -> str:
"""Evaluate mathematical expressions safely."""
try:
# Remove any characters that aren't numbers, operators, or parentheses
cleaned = re.sub(r'[^0-9+\-*/().\ ]', '', expression)
# Evaluate the expression
result = eval(cleaned, {"__builtins__": {}}, {"math": math})
return str(result)
except Exception as e:
return f"Error in calculation: {str(e)}"
class GaiaAgent:
def __init__(self):
# Initialize Qwen-7B model
self.model_name = "Qwen/Qwen-7B"
self.tokenizer = AutoTokenizer.from_pretrained(
self.model_name,
trust_remote_code=True
)
self.model = AutoModelForCausalLM.from_pretrained(
self.model_name,
device_map="auto",
trust_remote_code=True
).eval()
# Initialize tools
self.tools = {
"web_search": WebSearchTool(),
"calculator": Calculator()
}
# System prompt template
self.system_prompt = """You are a helpful AI assistant with access to the following tools:
1. web_search: Search the internet for current information
2. calculator: Perform mathematical calculations
To use a tool, respond with: tool_name|input
For example: calculator|2 + 2 or web_search|latest news about AI
If you don't need any tools to answer, just provide your response directly.
Always explain your reasoning before using tools or providing final answers."""
def _generate_response(self, prompt: str, max_length: int = 2048) -> str:
"""Generate a response using the Qwen model."""
try:
input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.model.device)
with torch.no_grad():
outputs = self.model.generate(
input_ids,
max_length=max_length,
num_return_sequences=1,
temperature=0.7,
do_sample=True,
pad_token_id=self.tokenizer.pad_token_id
)
response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
# Extract only the assistant's response
response = response.split(prompt)[-1].strip()
return response
except Exception as e:
return f"Error generating response: {str(e)}"
def _extract_tool_calls(self, response: str) -> List[Dict[str, str]]:
"""Extract tool calls from the response."""
tool_pattern = r'(.*?)\|(.*?)'
matches = re.finditer(tool_pattern, response)
tool_calls = []
for match in matches:
tool_name = match.group(1).strip()
tool_input = match.group(2).strip()
tool_calls.append({"name": tool_name, "input": tool_input})
return tool_calls
def _execute_tool_call(self, tool_call: Dict[str, str]) -> str:
"""Execute a single tool call and return the result."""
tool_name = tool_call["name"]
tool_input = tool_call["input"]
if tool_name not in self.tools:
return f"Error: Tool '{tool_name}' not found"
try:
result = self.tools[tool_name].run(tool_input)
return result
except Exception as e:
return f"Error executing {tool_name}: {str(e)}"
def process_question(self, question: str) -> str:
"""Process a single question and return the answer."""
# Construct the full prompt
full_prompt = f"{self.system_prompt}\n\nQuestion: {question}\n\nAnswer:"
# Get initial response
response = self._generate_response(full_prompt)
# Extract and execute any tool calls
tool_calls = self._extract_tool_calls(response)
if tool_calls:
# Execute each tool call and collect results
tool_results = []
for tool_call in tool_calls:
result = self._execute_tool_call(tool_call)
tool_results.append(f"Tool {tool_call['name']} result: {result}")
# Generate final response with tool results
tool_results_str = "\n".join(tool_results)
final_prompt = f"{full_prompt}\n{response}\n\nTool Results:\n{tool_results_str}\n\nFinal Answer:"
final_response = self._generate_response(final_prompt)
return final_response
return response
def get_answer(self, question_data: Dict[str, Any]) -> Optional[str]:
"""Process a question from the GAIA benchmark and return an answer."""
try:
# Extract the actual question from the question data
question = question_data.get("question", "")
if not question:
return None
# Process the question and get the answer
answer = self.process_question(question)
return answer
except Exception as e:
print(f"Error processing question: {str(e)}")
return None