real-jiakai commited on
Commit
fa599aa
·
verified ·
1 Parent(s): 1320d0a

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +112 -94
agent.py CHANGED
@@ -25,7 +25,6 @@ from smolagents import (
25
  CodeAgent,
26
  DuckDuckGoSearchTool,
27
  PythonInterpreterTool,
28
- LiteLLMModel,
29
  tool,
30
  )
31
 
@@ -77,6 +76,108 @@ class RateLimiter:
77
  # Global rate limiter instance
78
  RATE_LIMITER = RateLimiter(requests_per_minute=25) # Keep below 40 for safety
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  # --------------------------------------------------------------------------- #
81
  # custom tool: fetch GAIA attachments
82
  # --------------------------------------------------------------------------- #
@@ -259,90 +360,6 @@ def analyze_excel_file(file_path: str, query: str) -> str:
259
  except Exception as e:
260
  return f"Error analyzing Excel file: {str(e)}"
261
 
262
- # --------------------------------------------------------------------------- #
263
- # Custom LiteLLM model with rate limiting and error handling
264
- # --------------------------------------------------------------------------- #
265
- # --------------------------------------------------------------------------- #
266
- # Custom LiteLLM model with rate limiting and error handling
267
- # --------------------------------------------------------------------------- #
268
- class RateLimitedClaudeModel:
269
- def __init__(
270
- self,
271
- model_id: str = "anthropic/claude-3-5-sonnet-20240620",
272
- api_key: Optional[str] = None,
273
- temperature: float = 0.1,
274
- max_tokens: int = 1024,
275
- max_retries: int = 3,
276
- retry_delay: int = 5,
277
- ):
278
- """
279
- Initialize a Claude model with rate limiting and error handling
280
-
281
- Args:
282
- model_id: The model ID to use
283
- api_key: The API key to use
284
- temperature: The temperature to use
285
- max_tokens: The maximum number of tokens to generate
286
- max_retries: The maximum number of retries on rate limit errors
287
- retry_delay: The initial delay between retries (will increase exponentially)
288
- """
289
- # Get API key
290
- if api_key is None:
291
- api_key = os.getenv("ANTHROPIC_API_KEY")
292
- if not api_key:
293
- raise ValueError("No Anthropic token provided. Please set ANTHROPIC_API_KEY environment variable or pass api_key parameter.")
294
-
295
- self.model_id = model_id
296
- self.api_key = api_key
297
- self.temperature = temperature
298
- self.max_tokens = max_tokens
299
- self.max_retries = max_retries
300
- self.retry_delay = retry_delay
301
-
302
- # Create the underlying LiteLLM model
303
- self.model = LiteLLMModel(
304
- model_id=model_id,
305
- api_key=api_key,
306
- temperature=temperature
307
- )
308
-
309
- def __call__(self, prompt: str, **kwargs) -> str:
310
- """
311
- Call the model with rate limiting and error handling
312
-
313
- Args:
314
- prompt: The prompt to generate from
315
-
316
- Returns:
317
- The generated text
318
- """
319
- # Make sure system_instruction is always present
320
- if "system_instruction" not in kwargs:
321
- system_instruction = """You are a concise, highly accurate assistant specialized in solving challenges.
322
- Your answers should be precise, direct, and exactly match the expected format.
323
- All answers are graded by exact string match, so format carefully!"""
324
- kwargs["system_instruction"] = system_instruction
325
-
326
- retries = 0
327
- while True:
328
- try:
329
- # Wait according to rate limiter
330
- RATE_LIMITER.wait()
331
-
332
- # Call the model
333
- return self.model(prompt, **kwargs)
334
-
335
- except Exception as e:
336
- # Check if it's a rate limit error
337
- if "rate_limit_error" in str(e) and retries < self.max_retries:
338
- retries += 1
339
- sleep_time = self.retry_delay * (2 ** (retries - 1)) # Exponential backoff
340
- print(f"Rate limit exceeded, retrying in {sleep_time} seconds (attempt {retries}/{self.max_retries})...")
341
- time.sleep(sleep_time)
342
- else:
343
- # If it's not a rate limit error or we've exceeded max retries, raise
344
- raise
345
-
346
  # --------------------------------------------------------------------------- #
347
  # GAIAAgent class
348
  # --------------------------------------------------------------------------- #
@@ -352,7 +369,6 @@ class GAIAAgent:
352
  api_key: Optional[str] = None,
353
  temperature: float = 0.1,
354
  verbose: bool = False,
355
- system_prompt: Optional[str] = None,
356
  max_tokens: int = 1024,
357
  ):
358
  """
@@ -362,12 +378,13 @@ class GAIAAgent:
362
  api_key: Anthropic API key (fetched from environment if not provided)
363
  temperature: Temperature for text generation
364
  verbose: Enable verbose logging
365
- system_prompt: Custom system prompt (optional)
366
  max_tokens: Maximum number of tokens to generate per response
367
  """
368
  # Set verbosity
369
  self.verbose = verbose
370
- self.system_prompt = system_prompt or """You are a concise, highly accurate assistant specialized in solving challenges for the GAIA benchmark.
 
 
371
  Unless explicitly required, reply with ONE short sentence.
372
  Your answers should be precise, direct, and exactly match the expected format.
373
  All answers are graded by exact string match, so format carefully!"""
@@ -376,21 +393,22 @@ All answers are graded by exact string match, so format carefully!"""
376
  if api_key is None:
377
  api_key = os.getenv("ANTHROPIC_API_KEY")
378
  if not api_key:
379
- raise ValueError("No Anthropic token provided. Please set ANTHROPIC_API_KEY environment variable or pass api_key parameter.")
380
 
381
  if self.verbose:
382
  print(f"Using Anthropic token: {api_key[:5]}...")
383
 
384
- # Initialize Claude model with rate limiting
385
- self.model = RateLimitedClaudeModel(
386
  model_id="anthropic/claude-3-5-sonnet-20240620", # Use Claude 3.5 Sonnet
387
  api_key=api_key,
388
  temperature=temperature,
389
  max_tokens=max_tokens,
 
390
  )
391
 
392
  if self.verbose:
393
- print(f"Initialized model: RateLimitedClaudeModel - anthropic/claude-3-5-sonnet-20240620")
394
 
395
  # Initialize default tools
396
  self.tools = [
@@ -457,7 +475,7 @@ All answers are graded by exact string match, so format carefully!"""
457
  if task_file_path:
458
  try:
459
  # Limit file content size to avoid token limits
460
- max_file_size = 10000 # Characters
461
  with open(task_file_path, 'r', errors='ignore') as f:
462
  file_content = f.read(max_file_size)
463
  if len(file_content) >= max_file_size:
@@ -594,7 +612,7 @@ Example: If asked "What is the capital of France?", respond just with "Paris".
594
  return answer
595
 
596
  # --------------------------------------------------------------------------- #
597
- # GeminiAgent class - Wrapper around GAIAAgent
598
  # --------------------------------------------------------------------------- #
599
  class ClaudeAgent:
600
  """Claude-enhanced agent for GAIA challenge"""
 
25
  CodeAgent,
26
  DuckDuckGoSearchTool,
27
  PythonInterpreterTool,
 
28
  tool,
29
  )
30
 
 
76
  # Global rate limiter instance
77
  RATE_LIMITER = RateLimiter(requests_per_minute=25) # Keep below 40 for safety
78
 
79
+ # --------------------------------------------------------------------------- #
80
+ # Fixed LiteLLM model for Anthropic
81
+ # --------------------------------------------------------------------------- #
82
+ class FixedAnthropicModel:
83
+ """
84
+ A wrapper around LiteLLM that properly handles Anthropic API calls
85
+ and avoids the "system_instruction: Extra inputs are not permitted" error
86
+ """
87
+
88
+ def __init__(
89
+ self,
90
+ model_id: str = "anthropic/claude-3-5-sonnet-20240620",
91
+ api_key: Optional[str] = None,
92
+ temperature: float = 0.1,
93
+ max_tokens: int = 1024,
94
+ system_prompt: Optional[str] = None,
95
+ ):
96
+ """
97
+ Initialize a model that properly handles system prompts for Anthropic via LiteLLM
98
+
99
+ Args:
100
+ model_id: Claude model ID to use
101
+ api_key: API key (will use ANTHROPIC_API_KEY env var if not provided)
102
+ temperature: Temperature for text generation
103
+ max_tokens: Maximum tokens to generate
104
+ system_prompt: System prompt to use
105
+ """
106
+ # Get API key from env if not provided
107
+ if api_key is None:
108
+ api_key = os.getenv("ANTHROPIC_API_KEY")
109
+ if not api_key:
110
+ raise ValueError("No Anthropic API key provided. Set ANTHROPIC_API_KEY env var.")
111
+
112
+ self.model_id = model_id
113
+ self.api_key = api_key
114
+ self.temperature = temperature
115
+ self.max_tokens = max_tokens
116
+
117
+ # Store the system prompt
118
+ self.system_prompt = system_prompt or """You are a concise, highly accurate assistant specialized in solving challenges.
119
+ Your answers should be precise, direct, and exactly match the expected format.
120
+ All answers are graded by exact string match, so format carefully!"""
121
+
122
+ print(f"Initialized FixedAnthropicModel with {model_id}")
123
+
124
+ def __call__(self, prompt: str, **kwargs) -> str:
125
+ """
126
+ Call the model with appropriate handling of system prompts for Anthropic
127
+
128
+ Args:
129
+ prompt: The prompt to send to the model
130
+ **kwargs: Additional arguments to pass to LiteLLM
131
+
132
+ Returns:
133
+ The model's response as a string
134
+ """
135
+ # Wait according to rate limiter
136
+ RATE_LIMITER.wait()
137
+
138
+ try:
139
+ # For Anthropic models, we need to modify how system prompts are handled
140
+ # We do this by using the 'messages' parameter directly with the system content
141
+
142
+ # Extract system_instruction from kwargs if it exists and remove it
143
+ # (to avoid the "Extra inputs are not permitted" error)
144
+ if 'system_instruction' in kwargs:
145
+ # We'll ignore it and use our stored system prompt instead
146
+ del kwargs['system_instruction']
147
+
148
+ # Create our messages array with the system message and user prompt
149
+ messages = [
150
+ {"role": "system", "content": self.system_prompt},
151
+ {"role": "user", "content": prompt}
152
+ ]
153
+
154
+ # Call LiteLLM with the proper message format for Anthropic
155
+ from litellm import completion
156
+ response = completion(
157
+ model=self.model_id,
158
+ messages=messages,
159
+ api_key=self.api_key,
160
+ temperature=self.temperature,
161
+ max_tokens=self.max_tokens,
162
+ **kwargs
163
+ )
164
+
165
+ # Extract the content from the response
166
+ return response.choices[0].message.content
167
+
168
+ except Exception as e:
169
+ if "rate_limit" in str(e).lower():
170
+ # Specific handling for rate limit errors
171
+ print(f"Rate limit error: {e}")
172
+ print("Waiting 60 seconds before retrying...")
173
+ time.sleep(60)
174
+ # Recursive retry after waiting
175
+ return self.__call__(prompt, **kwargs)
176
+ else:
177
+ # Re-raise other errors
178
+ print(f"Error calling Anthropic API: {e}")
179
+ raise
180
+
181
  # --------------------------------------------------------------------------- #
182
  # custom tool: fetch GAIA attachments
183
  # --------------------------------------------------------------------------- #
 
360
  except Exception as e:
361
  return f"Error analyzing Excel file: {str(e)}"
362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  # --------------------------------------------------------------------------- #
364
  # GAIAAgent class
365
  # --------------------------------------------------------------------------- #
 
369
  api_key: Optional[str] = None,
370
  temperature: float = 0.1,
371
  verbose: bool = False,
 
372
  max_tokens: int = 1024,
373
  ):
374
  """
 
378
  api_key: Anthropic API key (fetched from environment if not provided)
379
  temperature: Temperature for text generation
380
  verbose: Enable verbose logging
 
381
  max_tokens: Maximum number of tokens to generate per response
382
  """
383
  # Set verbosity
384
  self.verbose = verbose
385
+
386
+ # System prompt for all Claude interactions
387
+ self.system_prompt = """You are a concise, highly accurate assistant specialized in solving challenges for the GAIA benchmark.
388
  Unless explicitly required, reply with ONE short sentence.
389
  Your answers should be precise, direct, and exactly match the expected format.
390
  All answers are graded by exact string match, so format carefully!"""
 
393
  if api_key is None:
394
  api_key = os.getenv("ANTHROPIC_API_KEY")
395
  if not api_key:
396
+ raise ValueError("No Anthropic token provided. Please set ANTHROPIC_API_KEY environment variable.")
397
 
398
  if self.verbose:
399
  print(f"Using Anthropic token: {api_key[:5]}...")
400
 
401
+ # Initialize Claude model with our fixed wrapper
402
+ self.model = FixedAnthropicModel(
403
  model_id="anthropic/claude-3-5-sonnet-20240620", # Use Claude 3.5 Sonnet
404
  api_key=api_key,
405
  temperature=temperature,
406
  max_tokens=max_tokens,
407
+ system_prompt=self.system_prompt,
408
  )
409
 
410
  if self.verbose:
411
+ print(f"Initialized model: FixedAnthropicModel - claude-3-5-sonnet-20240620")
412
 
413
  # Initialize default tools
414
  self.tools = [
 
475
  if task_file_path:
476
  try:
477
  # Limit file content size to avoid token limits
478
+ max_file_size = 8000 # Characters - reduced further to help with token limits
479
  with open(task_file_path, 'r', errors='ignore') as f:
480
  file_content = f.read(max_file_size)
481
  if len(file_content) >= max_file_size:
 
612
  return answer
613
 
614
  # --------------------------------------------------------------------------- #
615
+ # ClaudeAgent class - Wrapper around GAIAAgent
616
  # --------------------------------------------------------------------------- #
617
  class ClaudeAgent:
618
  """Claude-enhanced agent for GAIA challenge"""