Andrei Nazarov commited on
Commit
04eadcc
·
1 Parent(s): 3c12da1

updated the prompt, refactored

Browse files
Files changed (3) hide show
  1. __pycache__/tools.cpython-310.pyc +0 -0
  2. app.py +85 -96
  3. requirements.txt +2 -1
__pycache__/tools.cpython-310.pyc CHANGED
Binary files a/__pycache__/tools.cpython-310.pyc and b/__pycache__/tools.cpython-310.pyc differ
 
app.py CHANGED
@@ -10,7 +10,7 @@ from collections import deque
10
  import random
11
  from smolagents import CodeAgent, DuckDuckGoSearchTool, load_tool, tool
12
  from smolagents.models import Model, ChatMessage, MessageRole, Tool
13
- from tools import FinalAnswerTool, WikipediaSearchTool
14
  import google.generativeai as genai
15
 
16
  # (Keep Constants as is)
@@ -54,56 +54,79 @@ class GeminiModel(Model):
54
  self.model = genai.GenerativeModel('models/gemini-2.0-flash-lite')
55
  self.rate_limiter = RateLimiter(requests_per_minute=25)
56
 
57
- self.system_prompt = """You are a high-performance reasoning agent. Your goal is to answer questions by breaking them down into a series of logical steps.
58
 
59
- You are in a loop that has a limited number of turns. You must solve the problem efficiently.
 
 
 
 
60
 
61
  **YOUR WORKFLOW**
62
- 1. **Think (`Thought:`):** Analyze the user's question. What is the first piece of information you need? Create a plan.
63
- 2. **Act (`Code:`):** Write a SINGLE line of Python code to execute the first step of your plan. Use one of your tools: `web_search(query)` or `wikipedia_search(query)`.
64
- 3. **Observe (`Observation:`):** You will receive the result of your action.
65
- 4. **Repeat:** Go back to step 1. Analyze the observation. Do you have the final answer, or do you need more information? Continue this process until you have everything you need.
66
- 5. **Final Answer:** Once you are certain you have the correct answer, your final action MUST be a call to `final_answer("your answer")`.
67
 
68
  ---
69
- **GOLDEN PATH EXAMPLE: MULTI-STEP REASONING**
 
70
 
71
- *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.
 
 
 
 
 
 
72
 
73
- ---
74
- **Your Turn 1**
75
- Thought: I need to find Taishō Tamai's jersey number and his team. I will use `web_search` to find this information.
76
  Code:
77
  ```py
78
- web_search(query="Taisho Tamai jersey number and team July 2023")
79
  ```<end_code>
 
80
 
81
- ---
82
- *Observation from Turn 1:* `Taishō Tamai is a pitcher for the Orix Buffaloes, jersey number 61.`
 
 
 
 
83
 
84
  ---
85
- **Your Turn 2**
86
- Thought: The observation tells me his number is 61 and he plays for the Orix Buffaloes. Now I need to find the 2023 pitcher roster for that team to identify the players with numbers 60 and 62.
 
 
 
87
  Code:
88
  ```py
89
- web_search(query="Orix Buffaloes 2023 pitcher roster with jersey numbers")
90
  ```<end_code>
 
91
 
92
- ---
93
- *Observation from Turn 2:* `The Orix Buffaloes 2023 roster includes... Pitcher: K. Mizuno, #60... Pitcher: T. Onaga, #62...`
 
 
 
 
 
94
 
95
- ---
96
- **Your Turn 3**
97
- Thought: I have all the necessary information. The pitcher with the number before Taishō Tamai (#61) is K. Mizuno (#60). The pitcher after is T. Onaga (#62). The required format is "LastNameBefore, LastNameAfter".
98
  Code:
99
  ```py
100
- final_answer("Mizuno, Onaga")
101
  ```<end_code>
102
  """
103
 
104
  def generate(
105
  self,
106
- messages: list[dict[str, str | list[dict]] | ChatMessage],
107
  stop_sequences: list[str] | None = None,
108
  response_format: dict[str, str] | None = None,
109
  tools_to_call_from: list[Tool] | None = None,
@@ -112,70 +135,40 @@ final_answer("Mizuno, Onaga")
112
  retry_count = 0
113
  delay = INITIAL_RETRY_DELAY
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  while True:
116
  try:
117
- # Wait if we need to due to rate limiting
118
  self.rate_limiter.wait_if_needed()
119
 
120
- # Handle different prompt types
121
- if isinstance(messages, list) and len(messages) > 0:
122
- last_message = messages[-1]
123
-
124
- if isinstance(last_message, dict) and 'content' in last_message:
125
- content = last_message['content']
126
- elif isinstance(last_message, ChatMessage) and last_message.content:
127
- content = last_message.content
128
- else:
129
- content = ""
130
- for msg in messages:
131
- if isinstance(msg, dict) and 'content' in msg:
132
- content += str(msg['content']) + "\n"
133
- elif isinstance(msg, ChatMessage) and msg.content:
134
- content += str(msg.content) + "\n"
135
- else:
136
- content += str(msg) + "\n"
137
- else:
138
- content = str(messages)
139
-
140
- # Ensure content is a simple string for Gemini API
141
- if isinstance(content, list):
142
- text_parts = []
143
- for part in content:
144
- if isinstance(part, dict):
145
- if 'text' in part:
146
- text_parts.append(part['text'])
147
- elif 'content' in part:
148
- text_parts.append(part['content'])
149
- else:
150
- text_parts.append(str(part))
151
- else:
152
- text_parts.append(str(part))
153
- content = "\n".join(text_parts)
154
- elif isinstance(content, dict):
155
- if 'text' in content:
156
- content = content['text']
157
- elif 'content' in content:
158
- content = content['content']
159
- else:
160
- content = str(content)
161
-
162
- # Combine system prompt with user content
163
- full_prompt = f"{self.system_prompt}\n\nTask: {content}"
164
-
165
- # Generate response
166
  response = self.model.generate_content(full_prompt)
167
 
168
- # Extract text from response
169
  if hasattr(response, 'text'):
170
  response_text = response.text
 
 
171
  elif isinstance(response, str):
172
  response_text = response
173
- elif hasattr(response, 'content'):
174
- response_text = response.content
175
  else:
176
  response_text = str(response)
177
 
178
- # Return ChatMessage object as expected by smolagents
179
  return ChatMessage(
180
  role=MessageRole.ASSISTANT,
181
  content=response_text,
@@ -216,37 +209,33 @@ class MyAgent:
216
  FinalAnswerTool(),
217
  DuckDuckGoSearchTool(),
218
  WikipediaSearchTool(),
 
219
  ],
220
  model=self.model,
221
- max_steps=7 # Increased to allow for multi-step reasoning
222
  )
223
 
224
- def clean_and_format_answer(self, answer: str, question: str) -> str:
225
- """Extracts the argument from the final_answer() call."""
226
- match = re.search(r'final_answer\((?:"(.*?)"|\'(.*?)\'|(.*?))\)', answer, re.DOTALL)
227
- if match:
228
- # The result could be in group 1 (double quotes), group 2 (single quotes), or group 3 (no quotes)
229
- result = match.group(1) or match.group(2) or match.group(3)
230
- return result.strip() if result else ""
231
- return ""
232
-
233
  def __call__(self, question: str) -> str:
234
  print(f"\n=== Processing Question: {question} ===")
235
-
236
  try:
237
- full_response = self.agent.run(question)
238
- print(f"\n=== Raw Response from Agent ===\n{full_response}\n===")
239
- answer = self.clean_and_format_answer(full_response, question)
240
-
241
- if answer:
 
242
  return answer
243
  else:
244
- print("Could not find a final_answer call in the agent's response.")
245
  return "I was unable to find a definitive answer."
246
 
247
  except Exception as e:
248
- print(f"Error processing question: {e}")
249
- return f"Error: {str(e)}"
 
 
 
 
250
 
251
  def run_and_submit_all( profile: gr.OAuthProfile | None):
252
  """
 
10
  import random
11
  from smolagents import CodeAgent, DuckDuckGoSearchTool, load_tool, tool
12
  from smolagents.models import Model, ChatMessage, MessageRole, Tool
13
+ from tools import FinalAnswerTool, WikipediaSearchTool, VisitWebpageTool
14
  import google.generativeai as genai
15
 
16
  # (Keep Constants as is)
 
54
  self.model = genai.GenerativeModel('models/gemini-2.0-flash-lite')
55
  self.rate_limiter = RateLimiter(requests_per_minute=25)
56
 
57
+ self.system_prompt = """You are a high-performance reasoning agent. Your goal is to answer questions by breaking them down into a series of logical steps using the tools provided.
58
 
59
+ **YOUR TOOLS**
60
+ - `web_search(query: str)`: Finds URLs and information.
61
+ - `visit_webpage(url: str)`: Reads the content of a URL.
62
+ - `wikipedia_search(query: str)`: Searches Wikipedia.
63
+ - `final_answer(answer: str)`: Submits your final answer.
64
 
65
  **YOUR WORKFLOW**
66
+ 1. **Think (`Thought:`):** Analyze the question and create a plan.
67
+ 2. **Act (`Code:`):** Execute ONE step of your plan.
68
+ 3. **Observe (`Observation:`):** Use the result to inform your next step.
69
+ 4. **Repeat** until you have the final answer.
70
+ 5. **Submit** your answer using `final_answer()`.
71
 
72
  ---
73
+ **EXAMPLE 1: Using `web_search` and `visit_webpage`**
74
+ *Question:* What is the surname of the equine veterinarian mentioned in 1.E Exercises from the chemistry materials licensed by Marisa Alviar-Agnew & Henry Agnew under the CK-12 license in LibreText's Introductory Chemistry materials as compiled 08/21/2023?
75
 
76
+ **Your Turn 1:**
77
+ Thought: I need to find the specific LibreText page. I'll use `web_search`.
78
+ Code:
79
+ ```py
80
+ web_search(query="LibreTexts Introductory Chemistry Agnew 1.E Exercises")
81
+ ```<end_code>
82
+ *Observation:* A search result shows the URL `https://chem.libretexts.org/.../1.E%3A_Exercises`.
83
 
84
+ **Your Turn 2:**
85
+ Thought: I have the URL. Now I need to read the content of the page to find the name.
 
86
  Code:
87
  ```py
88
+ visit_webpage(url="https://chem.libretexts.org/Courses/Some_College/Introductory_Chemistry_(Alviar-Agnew_and_Agnew)/01%3A_Introduction_to_Chemistry/1.E%3A_Exercises")
89
  ```<end_code>
90
+ *Observation:* The webpage content includes the text "...an equine veterinarian, Dr. Smith...".
91
 
92
+ **Your Turn 3:**
93
+ Thought: I've found the surname. It's Smith.
94
+ Code:
95
+ ```py
96
+ final_answer("Smith")
97
+ ```<end_code>
98
 
99
  ---
100
+ **EXAMPLE 2: Finding a specific count**
101
+ *Question:* How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)?
102
+
103
+ **Your Turn 1:**
104
+ Thought: I need to find a reliable discography for Mercedes Sosa. `wikipedia_search` is a good starting point.
105
  Code:
106
  ```py
107
+ wikipedia_search(query="Mercedes Sosa discography")
108
  ```<end_code>
109
+ *Observation:* The Wikipedia summary lists several albums.
110
 
111
+ **Your Turn 2:**
112
+ Thought: The summary is a good start, but I need a more detailed list with years to be sure. I will visit the Wikipedia page itself to get the full discography. The search result from the previous step implicitly gives me the URL.
113
+ Code:
114
+ ```py
115
+ visit_webpage(url="https://en.wikipedia.org/wiki/Mercedes_Sosa_discography")
116
+ ```<end_code>
117
+ *Observation:* The page content contains a "Studio albums" section with dates. I can read it and count: *Acústico* (2002), *Corazón libre* (2005), *Cantora 1* (2009), *Cantora 2* (2009).
118
 
119
+ **Your Turn 3:**
120
+ Thought: I have counted 4 studio albums in the specified period.
 
121
  Code:
122
  ```py
123
+ final_answer("4")
124
  ```<end_code>
125
  """
126
 
127
  def generate(
128
  self,
129
+ messages: list[ChatMessage],
130
  stop_sequences: list[str] | None = None,
131
  response_format: dict[str, str] | None = None,
132
  tools_to_call_from: list[Tool] | None = None,
 
135
  retry_count = 0
136
  delay = INITIAL_RETRY_DELAY
137
 
138
+ # The smol-agent framework prepares the full conversation history.
139
+ # We concatenate the content of all messages to provide full context.
140
+ conversation_history = []
141
+ for message in messages:
142
+ content = ""
143
+ if isinstance(message, ChatMessage) and message.content:
144
+ content = message.content
145
+ elif isinstance(message, dict) and 'content' in message:
146
+ content = str(message['content'])
147
+ else:
148
+ content = str(message)
149
+ conversation_history.append(content)
150
+
151
+ prompt = "\n".join(conversation_history)
152
+
153
+ # The system prompt comes first, followed by the full conversation.
154
+ full_prompt = f"{self.system_prompt}\n\n{prompt}"
155
+
156
  while True:
157
  try:
 
158
  self.rate_limiter.wait_if_needed()
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  response = self.model.generate_content(full_prompt)
161
 
162
+ response_text = ""
163
  if hasattr(response, 'text'):
164
  response_text = response.text
165
+ elif hasattr(response, 'parts') and response.parts:
166
+ response_text = "".join(part.text for part in response.parts if hasattr(part, 'text'))
167
  elif isinstance(response, str):
168
  response_text = response
 
 
169
  else:
170
  response_text = str(response)
171
 
 
172
  return ChatMessage(
173
  role=MessageRole.ASSISTANT,
174
  content=response_text,
 
209
  FinalAnswerTool(),
210
  DuckDuckGoSearchTool(),
211
  WikipediaSearchTool(),
212
+ VisitWebpageTool(),
213
  ],
214
  model=self.model,
215
+ max_steps=7 # Keep high for multi-step reasoning
216
  )
217
 
 
 
 
 
 
 
 
 
 
218
  def __call__(self, question: str) -> str:
219
  print(f"\n=== Processing Question: {question} ===")
 
220
  try:
221
+ # agent.run() executes the plan and returns the final answer.
222
+ answer = self.agent.run(question)
223
+ print(f"\n=== Final Answer from Agent ===\n{answer}\n===")
224
+
225
+ # If the agent returns a string, use it. Otherwise, indicate no answer was found.
226
+ if isinstance(answer, str) and answer:
227
  return answer
228
  else:
229
+ # This case might be hit if the agent finishes without a clear answer string.
230
  return "I was unable to find a definitive answer."
231
 
232
  except Exception as e:
233
+ error_message = str(e)
234
+ print(f"An error occurred while processing the question: {error_message}")
235
+ # Check for a timeout or max steps error from the agent.
236
+ if "Agent stopped after" in error_message and "final_answer" in error_message:
237
+ return "I was unable to find a definitive answer within the allowed steps."
238
+ return f"An error occurred: {error_message}"
239
 
240
  def run_and_submit_all( profile: gr.OAuthProfile | None):
241
  """
requirements.txt CHANGED
@@ -6,4 +6,5 @@ smolagents
6
  google-generativeai
7
  python-dotenv
8
  wikipedia-api
9
- duckduckgo-search
 
 
6
  google-generativeai
7
  python-dotenv
8
  wikipedia-api
9
+ duckduckgo-search
10
+ markdownify