Smolagents / agent.py
Jovynne's picture
Create agent.py
72ef6a4 verified
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Try to import real smolagents, fallback to mock
try:
from smolagents import ToolCallingAgent, tool
from smolagents.models import LiteLLMModel
SMOLAGENTS_AVAILABLE = True
print("✅ smolagents framework loaded successfully!")
except ImportError:
print("⚠️ smolagents not found. Using mock implementation for demonstration.")
print(" To install: pip install git+https://github.com/huggingface/smolagents.git")
from mock_smolagents import ToolCallingAgent, tool, LiteLLMModel
SMOLAGENTS_AVAILABLE = False
# Define tools using the decorator (works with both real and mock)
@tool
def calculator(expression: str) -> str:
"""Evaluate a mathematical expression.
Args:
expression: A mathematical expression (e.g., '2 + 2 * 3')
Returns:
The result of the evaluation
"""
try:
# Safe evaluation
allowed_chars = set('0123456789+-*/(). ')
if not all(c in allowed_chars for c in expression):
return "Error: Only basic math operations allowed: numbers, +, -, *, /, (, ), ."
# Use eval with limited scope
result = eval(expression, {"__builtins__": {}}, {})
return f"Calculator: {expression} = {result}"
except Exception as e:
return f"Calculation error: {str(e)}"
@tool
def search_web(query: str) -> str:
"""Search the web for information.
Args:
query: Search query
Returns:
Search results summary
"""
try:
# Try to use duckduckgo if available
from duckduckgo_search import DDGS
results = []
with DDGS() as ddgs:
for r in ddgs.text(query, max_results=3):
results.append(f"• {r['title']}: {r['body'][:100]}...")
if results:
return f"Web search for '{query}':\n" + "\n".join(results)
return f"No web results found for '{query}'"
except ImportError:
return f"[Mock] Web search for '{query}':\n• Result 1: Information about {query}\n• Result 2: More details..."
except Exception as e:
return f"Search error: {str(e)}"
@tool
def get_hf_dataset_info(dataset_name: str = "mnist") -> str:
"""Get information about a Hugging Face dataset.
Args:
dataset_name: Name of the dataset (e.g., 'mnist', 'glue')
Returns:
Dataset information
"""
try:
from huggingface_hub import get_dataset_info
info = get_dataset_info(dataset_name)
response = f"📊 **Hugging Face Dataset: {info.id}**\n"
response += f"📥 Downloads: {info.downloads:,}\n"
response += f"📝 Description: {info.description[:250]}..."
return response
except ImportError:
datasets = {
"mnist": "MNIST: 70,000 handwritten digits (28x28 grayscale images), standard computer vision dataset",
"glue": "GLUE: General Language Understanding Evaluation benchmark for natural language understanding"
}
info = datasets.get(dataset_name.lower(), f"Dataset '{dataset_name}' not found in mock database")
return f"📊 **Dataset Info (Mock):**\n{info}"
except Exception as e:
return f"Error getting dataset info: {str(e)}"
@tool
def translate_text(text: str, target_language: str = "Spanish") -> str:
"""Translate text to another language.
Args:
text: Text to translate
target_language: Target language (default: Spanish)
Returns:
Translated text
"""
translations = {
"hello": {
"spanish": "hola",
"french": "bonjour",
"german": "hallo",
"italian": "ciao"
},
"world": {
"spanish": "mundo",
"french": "monde",
"german": "welt",
"italian": "mondo"
},
"goodbye": {
"spanish": "adiós",
"french": "au revoir",
"german": "auf wiedersehen",
"italian": "addio"
}
}
text_lower = text.lower()
lang_lower = target_language.lower()
if text_lower in translations and lang_lower in translations[text_lower]:
return f"Translation: '{text}' → {target_language}: '{translations[text_lower][lang_lower]}'"
else:
return f"No translation found for '{text}' to {target_language}. Try: 'hello', 'world', or 'goodbye'"
class MyHuggingFaceAgent:
def __init__(self, use_mock_model=False):
"""Initialize the agent.
Args:
use_mock_model: Use mock model instead of real API (for testing)
"""
self.use_mock_model = use_mock_model or not SMOLAGENTS_AVAILABLE
# Get all tools
self.tools = [calculator, search_web, get_hf_dataset_info, translate_text]
# Initialize the agent
self.agent = self._create_agent()
print(f"Agent initialized with {len(self.tools)} tools")
print(f"smolagents available: {SMOLAGENTS_AVAILABLE}")
def _create_agent(self):
"""Create the smolagents agent."""
try:
if self.use_mock_model or not SMOLAGENTS_AVAILABLE:
# Use mock model
model = LiteLLMModel(
model_id="mock-model",
api_key="mock-key"
)
else:
# Use real model (requires API key)
api_key = os.getenv("OPENAI_API_KEY") or os.getenv("HF_TOKEN")
if api_key and api_key != "not-provided":
model = LiteLLMModel(
model_id="gpt-3.5-turbo",
api_key=api_key
)
else:
print("⚠️ No API key found. Using mock model.")
model = LiteLLMModel(
model_id="mock-model",
api_key="mock-key"
)
# Create agent
agent = ToolCallingAgent(
model=model,
tools=self.tools,
max_steps=5,
verbose=True,
add_base_tools=False
)
return agent
except Exception as e:
print(f"Error creating agent: {e}")
# Return a basic agent as fallback
return None
def run(self, task: str) -> str:
"""Run the agent on a task."""
try:
if self.agent:
# Use smolagents agent
result = self.agent.run(task)
# Format the response
response = "🤖 **AI Agent Response (smolagents Framework)**\n\n"
response += f"{result}\n\n"
response += "---\n"
response += "🛠️ **Framework:** smolagents (Hugging Face)\n"
response += f"📊 **Status:** {'Using real framework' if SMOLAGENTS_AVAILABLE else 'Using mock for demonstration'}"
return response
else:
# Fallback to simple processing
return self._simple_agent(task)
except Exception as e:
return f"⚠️ **Agent Error:** {str(e)}\n\n{self._simple_agent(task)}"
def _simple_agent(self, task: str) -> str:
"""Simple fallback agent."""
response = "🔧 **Simple Agent Response**\n\n"
# Try each tool
for tool_func in self.tools:
tool_name = tool_func.name
if tool_name in task.lower():
try:
# Simple argument extraction
if tool_name == "calculator":
import re
expr = re.sub(r'[^\d\+\-\*\/\(\)\.\s]', '', task).strip()
if expr:
result = tool_func(expr)
else:
result = "Please provide a math expression"
elif tool_name == "search_web":
query = task.replace("search", "").replace("find", "").strip()
result = tool_func(query if query else task)
elif tool_name == "get_hf_dataset_info":
result = tool_func()
elif tool_name == "translate_text":
if " to " in task.lower():
parts = task.lower().split(" to ")
text = parts[0].replace("translate", "").strip()
lang = parts[1].strip().title()
result = tool_func(text, lang)
else:
result = tool_func("hello")
else:
result = tool_func(task)
response += f"**{tool_name.replace('_', ' ').title()}:**\n{result}\n\n"
break
except Exception as e:
response += f"Error using {tool_name}: {str(e)}\n\n"
else:
# No tool matched
response += """**I can help with:**
1. **Calculator** - Perform math calculations
Example: 'calculate 15 * 3' or 'what is 45 + 23?'
2. **Web Search** - Search for information
Example: 'search for AI news' or 'find machine learning tutorials'
3. **Dataset Info** - Get Hugging Face dataset information
Example: 'tell me about mnist dataset' or 'glue dataset info'
4. **Translation** - Translate words
Example: 'translate hello to Spanish' or 'translate goodbye to French'
Try one of these commands!"""
return response