real-jiakai commited on
Commit
66a0e23
Β·
verified Β·
1 Parent(s): 0aa600f

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +82 -72
agent.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- agent.py – Claude-smolagents based solution for GAIA challenge
3
  -----------------------------------------------------------
4
  Environment
5
  -----------
@@ -7,8 +7,6 @@ ANTHROPIC_API_KEY – API key from Anthropic (set in Hugging Face space secret
7
  GAIA_API_URL – (optional) override for the GAIA scoring endpoint
8
  """
9
 
10
- from __future__ import annotations
11
-
12
  import base64
13
  import mimetypes
14
  import os
@@ -16,20 +14,13 @@ import re
16
  import tempfile
17
  import time
18
  from typing import List, Dict, Any, Optional
19
- import json
20
  import requests
21
  from urllib.parse import urlparse
22
- import random
23
-
24
- from smolagents import (
25
- CodeAgent,
26
- DuckDuckGoSearchTool,
27
- PythonInterpreterTool,
28
- tool,
29
- )
30
 
31
  # --------------------------------------------------------------------------- #
32
- # constants & helpers
33
  # --------------------------------------------------------------------------- #
34
  DEFAULT_API_URL = os.getenv(
35
  "GAIA_API_URL", "https://agents-course-unit4-scoring.hf.space"
@@ -74,15 +65,74 @@ class RateLimiter:
74
  time.sleep(random.uniform(0.2, 1.0))
75
 
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__(
@@ -93,16 +143,7 @@ class FixedAnthropicModel:
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")
@@ -119,49 +160,18 @@ class FixedAnthropicModel:
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
- # Wait according to rate limiter
129
- RATE_LIMITER.wait()
130
-
131
- try:
132
- # Remove system_instruction if present in kwargs
133
- if 'system_instruction' in kwargs:
134
- del kwargs['system_instruction']
135
-
136
- # For Anthropic via LiteLLM, use the direct completion method
137
- from litellm import completion
138
-
139
- # Create a simple prompt with system instructions at the beginning
140
- # This avoids the nested message structure issue
141
- complete_prompt = f"{self.system_prompt}\n\n{prompt}"
142
-
143
- response = completion(
144
- model=self.model_id,
145
- messages=[{"role": "user", "content": complete_prompt}],
146
- api_key=self.api_key,
147
- temperature=self.temperature,
148
- max_tokens=self.max_tokens,
149
- **kwargs
150
- )
151
-
152
- # Extract the content from the response
153
- return response.choices[0].message.content
154
-
155
- except Exception as e:
156
- # Handle rate limit errors
157
- if "rate_limit" in str(e).lower():
158
- print(f"Rate limit error: {e}")
159
- print("Waiting 60 seconds before retrying...")
160
- time.sleep(60)
161
- return self.__call__(prompt, **kwargs)
162
- else:
163
- print(f"Error calling Anthropic API: {e}")
164
- raise
165
 
166
  # --------------------------------------------------------------------------- #
167
  # custom tool: fetch GAIA attachments
@@ -383,8 +393,8 @@ All answers are graded by exact string match, so format carefully!"""
383
  if self.verbose:
384
  print(f"Using Anthropic token: {api_key[:5]}...")
385
 
386
- # Initialize Claude model with our fixed wrapper
387
- self.model = FixedAnthropicModel(
388
  model_id="anthropic/claude-3-5-sonnet-20240620", # Use Claude 3.5 Sonnet
389
  api_key=api_key,
390
  temperature=temperature,
@@ -393,7 +403,7 @@ All answers are graded by exact string match, so format carefully!"""
393
  )
394
 
395
  if self.verbose:
396
- print(f"Initialized model: FixedAnthropicModel - claude-3-5-sonnet-20240620")
397
 
398
  # Initialize default tools
399
  self.tools = [
 
1
  """
2
+ agent.py – Simplified Claude implementation for GAIA challenge
3
  -----------------------------------------------------------
4
  Environment
5
  -----------
 
7
  GAIA_API_URL – (optional) override for the GAIA scoring endpoint
8
  """
9
 
 
 
10
  import base64
11
  import mimetypes
12
  import os
 
14
  import tempfile
15
  import time
16
  from typing import List, Dict, Any, Optional
17
+ import random
18
  import requests
19
  from urllib.parse import urlparse
20
+ from smolagents import CodeAgent, DuckDuckGoSearchTool, PythonInterpreterTool, tool
 
 
 
 
 
 
 
21
 
22
  # --------------------------------------------------------------------------- #
23
+ # Constants & helpers
24
  # --------------------------------------------------------------------------- #
25
  DEFAULT_API_URL = os.getenv(
26
  "GAIA_API_URL", "https://agents-course-unit4-scoring.hf.space"
 
65
  time.sleep(random.uniform(0.2, 1.0))
66
 
67
  # Global rate limiter instance
68
+ RATE_LIMITER = RateLimiter(requests_per_minute=15) # Reduced to be extra cautious
69
 
70
  # --------------------------------------------------------------------------- #
71
+ # Direct function to call Claude via LiteLLM
72
  # --------------------------------------------------------------------------- #
73
+ def call_claude(
74
+ prompt: str,
75
+ system_prompt: Optional[str] = None,
76
+ temperature: float = 0.1,
77
+ max_tokens: int = 1024,
78
+ model_name: str = "anthropic/claude-3-5-sonnet-20240620"
79
+ ) -> str:
80
  """
81
+ Call Claude through LiteLLM directly, following official LiteLLM documentation
82
+
83
+ Args:
84
+ prompt: The user's question
85
+ system_prompt: Optional system prompt
86
+ temperature: Temperature for generation
87
+ max_tokens: Max tokens to generate
88
+ model_name: Claude model to use
89
+
90
+ Returns:
91
+ The response text from Claude
92
+ """
93
+ from litellm import completion
94
+
95
+ # Respect rate limits
96
+ RATE_LIMITER.wait()
97
+
98
+ try:
99
+ # Build messages following exactly LiteLLM's documented format
100
+ messages = []
101
+
102
+ # Add system message if provided
103
+ if system_prompt:
104
+ messages.append({"role": "system", "content": system_prompt})
105
+
106
+ # Add user message - this is simple text only format
107
+ messages.append({"role": "user", "content": prompt})
108
+
109
+ # Make the API call exactly as documented
110
+ response = completion(
111
+ model=model_name,
112
+ messages=messages,
113
+ temperature=temperature,
114
+ max_tokens=max_tokens
115
+ )
116
+
117
+ # Extract just the text content from the response
118
+ return response.choices[0].message.content
119
+
120
+ except Exception as e:
121
+ if "rate_limit" in str(e).lower():
122
+ print(f"Rate limit hit: {e}")
123
+ # Wait 60 seconds and try again
124
+ time.sleep(60)
125
+ return call_claude(prompt, system_prompt, temperature, max_tokens, model_name)
126
+ else:
127
+ print(f"Error calling Claude API: {e}")
128
+ raise
129
+
130
+ # --------------------------------------------------------------------------- #
131
+ # Simple Claude Model wrapper for smolagents
132
+ # --------------------------------------------------------------------------- #
133
+ class SimpleClaudeModel:
134
+ """
135
+ A minimal wrapper around LiteLLM's direct call to Anthropic that works with smolagents
136
  """
137
 
138
  def __init__(
 
143
  max_tokens: int = 1024,
144
  system_prompt: Optional[str] = None,
145
  ):
146
+ """Initialize a minimal Claude model wrapper"""
 
 
 
 
 
 
 
 
 
147
  # Get API key from env if not provided
148
  if api_key is None:
149
  api_key = os.getenv("ANTHROPIC_API_KEY")
 
160
  Your answers should be precise, direct, and exactly match the expected format.
161
  All answers are graded by exact string match, so format carefully!"""
162
 
163
+ print(f"Initialized SimpleClaudeModel with {model_id}")
164
 
165
  def __call__(self, prompt: str, **kwargs) -> str:
166
+ """Call method to make this class callable by smolagents CodeAgent"""
167
+ # Directly use the call_claude function
168
+ return call_claude(
169
+ prompt=prompt,
170
+ system_prompt=self.system_prompt,
171
+ temperature=self.temperature,
172
+ max_tokens=self.max_tokens,
173
+ model_name=self.model_id
174
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  # --------------------------------------------------------------------------- #
177
  # custom tool: fetch GAIA attachments
 
393
  if self.verbose:
394
  print(f"Using Anthropic token: {api_key[:5]}...")
395
 
396
+ # Initialize Claude model with our simplified wrapper
397
+ self.model = SimpleClaudeModel(
398
  model_id="anthropic/claude-3-5-sonnet-20240620", # Use Claude 3.5 Sonnet
399
  api_key=api_key,
400
  temperature=temperature,
 
403
  )
404
 
405
  if self.verbose:
406
+ print(f"Initialized model: SimpleClaudeModel - claude-3-5-sonnet-20240620")
407
 
408
  # Initialize default tools
409
  self.tools = [