Andrei Nazarov commited on
Commit
f41535e
·
1 Parent(s): 9b6d6f3
Files changed (1) hide show
  1. app.py +55 -73
app.py CHANGED
@@ -55,63 +55,57 @@ class GeminiModel(Model):
55
  self.rate_limiter = RateLimiter(requests_per_minute=25) # Setting to 25 to be safe
56
 
57
  # System prompt for smolagents format
58
- self.system_prompt = """You are a highly intelligent AI assistant designed to answer questions by breaking them down into logical steps and using the available tools. For every question, you must first think about how to solve it and then write the code to execute your plan.
59
 
60
- **Workflow:**
61
- 1. **Thought:** First, explain your reasoning. Break down the user's question into smaller, manageable steps. Describe the search queries you will use and how you will process the results to arrive at the final answer.
62
- 2. **Code:** Write Python code to execute your plan. You have two tools available:
63
- * `web_search(query: str)`: Searches the web and returns information.
64
- * `final_answer(answer: str)`: Submits your final, formatted answer.
65
- 3. **Execution:** After your code is executed, you will see an "Observation" with the results. You can then continue with more `Thought` and `Code` blocks if needed.
66
- 4. **Final Answer:** Once you have the answer, you MUST call `final_answer()` with the correctly formatted response. Do not output the answer in any other way.
67
 
68
- **Examples:**
 
69
 
70
- **Question 1: Simple Fact Lookup**
71
- *User Question:* "Where were the Vietnamese specimens described by Kuznetsov in Nedoshivina's 2010 paper eventually deposited? Just give me the city name without abbreviations."
72
 
73
- *Your Response:*
74
- Thought: I need to find the 2010 paper by Kuznetsov and Nedoshivina about Vietnamese specimens. Then, I'll read the paper's details or related articles to find the deposition location of the type specimens. I will look for a city name.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  Code:
76
  ```py
77
- results = web_search(query="Kuznetsov Nedoshivina 2010 Vietnamese specimens deposited")
78
- # I will analyze the results. Let's assume a search result says "The type specimens are deposited at the Zoological Museum of Moscow University."
79
- final_answer("Moscow")
80
  ```<end_code>
81
 
82
- **Question 2: Multi-Step with Comparison**
83
- *User Question:* "What country had the least number of athletes at the 1928 Summer Olympics? If there's a tie for a number of athletes, return the first in alphabetical order. Give the IOC country code as your answer."
84
 
85
- *Your Response:*
86
- Thought: I need to find a list of countries and their athlete counts for the 1928 Summer Olympics. I'll search for a participant list. Then I will find the minimum number of athletes. If there is a tie, I will sort the tied countries alphabetically and pick the first one. Finally, I will find the IOC code for that country.
87
  Code:
88
  ```py
89
- results = web_search(query="countries by number of athletes at the 1928 Summer Olympics")
90
- # Observation from search: Haiti (2 athletes), Panama (1 athlete), Rhodesia (2 athletes).
91
- # The lowest number is 1, for Panama.
92
- # I need the IOC code for Panama.
93
- ioc_results = web_search(query="IOC code for Panama")
94
- # Observation from search: The IOC code for Panama is PAN.
95
- final_answer("PAN")
96
  ```<end_code>
97
 
98
- **Question 3: Multi-Step with Specific Formatting**
99
- *User Question:* "Who are the pitchers with the number before and after Taishō Tamai's number as of July 2023? Give them to me in the form Pitcher Before, Pitcher After, use their last names only, in Roman characters."
100
 
101
- *Your Response:*
102
- Thought: First, I need to find Taishō Tamai's jersey number and team as of July 2023. Then, I'll find that team's pitcher roster for 2023. I will look for the pitchers with jersey numbers immediately below and above his. Finally, I'll format their last names as requested.
103
  Code:
104
  ```py
105
- tamai_info = web_search(query="Taisho Tamai jersey number July 2023")
106
- # Observation: Taishō Tamai is number 61 for the Orix Buffaloes.
107
- roster_info = web_search(query="Orix Buffaloes pitchers roster 2023")
108
- # Observation: Pitcher roster includes... Mizuno (60), Tamai (61), Onaga (62)...
109
- # The pitcher before is Mizuno. The pitcher after is Onaga.
110
- # The format should be "LastNameBefore, LastNameAfter".
111
  final_answer("Mizuno, Onaga")
112
  ```<end_code>
113
-
114
- CRITICAL: Always follow the Thought -> Code -> final_answer workflow. Do not output an answer without using the `final_answer` tool."""
115
 
116
  def generate(
117
  self,
@@ -229,42 +223,17 @@ class MyAgent:
229
  DuckDuckGoSearchTool()
230
  ],
231
  model=self.model,
232
- max_steps=3
233
  )
234
 
235
  def clean_and_format_answer(self, answer: str, question: str) -> str:
236
- """Clean and format the answer to extract only the actual answer"""
237
- # First try to find a final_answer call
238
- final_answer_patterns = [
239
- r'final_answer\("([^"]+)"\)',
240
- r"final_answer\('([^']+)'\)",
241
- r'final_answer\(([^)\n]+)\)',
242
- ]
243
-
244
- for pattern in final_answer_patterns:
245
- match = re.search(pattern, answer)
246
- if match:
247
- return match.group(1).strip(' \'')
248
-
249
- # Fallback for answers that are not in final_answer
250
- # Remove code blocks and tool calls
251
- answer = re.sub(r'```.*?```', '', answer, flags=re.DOTALL)
252
- answer = re.sub(r'web_search\(.*?\)', '', answer)
253
- answer = re.sub(r'Thought:.*?\n', '', answer)
254
- answer = re.sub(r'Code:.*?<end_code>', '', answer, flags=re.DOTALL)
255
-
256
- # Clean up the answer
257
- lines = answer.split('\n')
258
- clean_lines = []
259
- for line in lines:
260
- line = line.strip()
261
- if line and not line.startswith(('Thought:', 'Code:', '#', 'web_search', 'final_answer', 'Out:')):
262
- clean_lines.append(line)
263
-
264
- if clean_lines:
265
- return " ".join(clean_lines).strip()
266
-
267
- return answer.strip()
268
 
269
  def __call__(self, question: str) -> str:
270
  print(f"\n=== Processing Question: {question} ===")
@@ -273,7 +242,20 @@ class MyAgent:
273
  full_response = self.agent.run(question)
274
  print(f"\n=== Raw Response from Agent ===\n{full_response}\n===")
275
  answer = self.clean_and_format_answer(full_response, question)
276
- return answer.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  except Exception as e:
278
  print(f"Error processing question: {e}")
279
  return f"Error: {str(e)}"
 
55
  self.rate_limiter = RateLimiter(requests_per_minute=25) # Setting to 25 to be safe
56
 
57
  # System prompt for smolagents format
58
+ self.system_prompt = """You are a reasoning agent. You are in a loop where you will alternate between thinking (Thought) and acting (Code).
59
 
60
+ Your goal is to answer the user's question.
 
 
 
 
 
 
61
 
62
+ **Step 1: Think**
63
+ In the `Thought:` block, analyze the user's question. Break it down into the smallest possible steps. If you need information, decide on a search query.
64
 
65
+ **Step 2: Act**
66
+ In the `Code:` block, write Python code to execute ONE step of your plan. You can use `web_search()` or `final_answer()`. Only perform one logical action at a time.
67
 
68
+ **Step 3: Observe**
69
+ After you act, you will receive an `Observation:`. This is the result of your code. Use this new information to plan your next step.
70
+
71
+ Repeat this process until you have the final answer.
72
+
73
+ **CRITICAL RULES:**
74
+ - Always use the `Thought:` and `Code:` blocks.
75
+ - **NEVER** put your final answer in the `Thought:` block.
76
+ - **ONLY** use `final_answer()` to provide the final answer.
77
+ - Keep your steps small. Do not try to do everything in one `Code:` block.
78
+
79
+ **Example: Multi-step question**
80
+ Question: Who are the pitchers with the number before and after Taishō Tamai's number as of July 2023? Give them to me in the form Pitcher Before, Pitcher After.
81
+
82
+ **Your Turn 1:**
83
+ Thought: I need to find Taishō Tamai's jersey number and team first.
84
  Code:
85
  ```py
86
+ web_search(query="Taisho Tamai jersey number and team July 2023")
 
 
87
  ```<end_code>
88
 
89
+ **Observation 1:** `(Result from web_search)`
90
+ Taishō Tamai is a pitcher for the Orix Buffaloes, jersey number 61.
91
 
92
+ **Your Turn 2:**
93
+ Thought: Now I have the team and number. I need to find the team's roster to find the pitchers with numbers 60 and 62.
94
  Code:
95
  ```py
96
+ web_search(query="Orix Buffaloes 2023 pitcher roster with jersey numbers")
 
 
 
 
 
 
97
  ```<end_code>
98
 
99
+ **Observation 2:** `(Result from web_search)`
100
+ ...Mizuno #60, ...Onaga #62, ...
101
 
102
+ **Your Turn 3:**
103
+ Thought: I have the names. The pitcher before is Mizuno and the one after is Onaga. I need to format the answer as "LastNameBefore, LastNameAfter".
104
  Code:
105
  ```py
 
 
 
 
 
 
106
  final_answer("Mizuno, Onaga")
107
  ```<end_code>
108
+ """
 
109
 
110
  def generate(
111
  self,
 
223
  DuckDuckGoSearchTool()
224
  ],
225
  model=self.model,
226
+ max_steps=5 # Increased max_steps to allow for multi-step reasoning
227
  )
228
 
229
  def clean_and_format_answer(self, answer: str, question: str) -> str:
230
+ """Extracts the argument from the final_answer() call."""
231
+ match = re.search(r'final_answer\((?:"(.*?)"|\'(.*?)\'|(.*?))\)', answer, re.DOTALL)
232
+ if match:
233
+ # The result could be in group 1 (double quotes), group 2 (single quotes), or group 3 (no quotes)
234
+ result = match.group(1) or match.group(2) or match.group(3)
235
+ return result.strip() if result else ""
236
+ return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
  def __call__(self, question: str) -> str:
239
  print(f"\n=== Processing Question: {question} ===")
 
242
  full_response = self.agent.run(question)
243
  print(f"\n=== Raw Response from Agent ===\n{full_response}\n===")
244
  answer = self.clean_and_format_answer(full_response, question)
245
+
246
+ if answer:
247
+ return answer
248
+ else:
249
+ print("Could not find a final_answer call in the agent's response.")
250
+ # As a fallback, check if the model just returned a simple response
251
+ # without following the format.
252
+ if "Thought:" not in full_response and "Code:" not in full_response:
253
+ cleaned_response = full_response.strip()
254
+ if 'final_answer' not in cleaned_response and 'web_search' not in cleaned_response:
255
+ return cleaned_response
256
+
257
+ return "I was unable to find a definitive answer."
258
+
259
  except Exception as e:
260
  print(f"Error processing question: {e}")
261
  return f"Error: {str(e)}"