ekabaruh commited on
Commit
3addd53
·
verified ·
1 Parent(s): 4b91f0c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -111
app.py CHANGED
@@ -39,12 +39,12 @@ class BasicAgent:
39
  FINAL ANSWER: [YOUR FINAL ANSWER]"
40
  """
41
 
42
- def __init__(self, model_name: str = "gpt-4.1", api_key: str = None):
43
  """
44
  Initialize the BasicAgent with the specified LLM.
45
 
46
  Args:
47
- model_name: The name of the model to use (defaults to gpt-4.1)
48
  api_key: OpenAI API key (defaults to environment variable)
49
  """
50
  # Use the provided API key or fall back to the environment variable
@@ -55,56 +55,20 @@ class BasicAgent:
55
 
56
  self.llm = ChatOpenAI(
57
  model=model_name,
58
- temperature=0.2,
59
  api_key=api_key
60
  )
61
 
62
- # Create state graph for agent
63
- self.workflow = self._create_workflow()
64
  print(f"BasicAgent initialized with model: {model_name}")
65
 
66
- def _create_workflow(self) -> StateGraph:
67
- """Create the agent workflow using LangGraph."""
68
-
69
- # Define our state
70
- class AgentState(BaseModel):
71
- question: str = Field(description="The original question")
72
- thoughts: List[str] = Field(default_factory=list, description="Agent's thoughts")
73
- final_answer: Optional[str] = Field(default=None, description="The final answer")
74
- need_calculator: bool = Field(default=False, description="Whether we need to use a calculator")
75
- math_expression: Optional[str] = Field(default=None, description="Math expression to evaluate")
76
-
77
- # Create the graph
78
- workflow = StateGraph(AgentState)
79
-
80
- # Define nodes
81
- workflow.add_node("analyze_question", self._analyze_question)
82
- workflow.add_node("solve_math", self._solve_math)
83
- workflow.add_node("reasoning", self._reasoning)
84
- workflow.add_node("format_answer", self._format_answer)
85
-
86
- # Define simple edges - this approach avoids conditional routing
87
- # All requests go through analyze_question -> solve_math -> reasoning -> format_answer
88
- # The solve_math step will be essentially a no-op if no calculation is needed
89
- workflow.add_edge("analyze_question", "solve_math")
90
- workflow.add_edge("solve_math", "reasoning")
91
- workflow.add_edge("reasoning", "format_answer")
92
- workflow.add_edge("format_answer", END)
93
-
94
- # Set entry point
95
- workflow.set_entry_point("analyze_question")
96
-
97
- # Compile the graph
98
- return workflow.compile()
99
-
100
- def _analyze_question(self, state: Dict[str, Any]) -> Dict[str, Any]:
101
  """Analyze the question to determine its type and approach."""
102
  prompt = [
103
  HumanMessage(content=f"""
104
  You are an expert problem analyzer. Examine the following question to determine its type
105
  and if it requires mathematical calculation.
106
 
107
- Question: {state.question}
108
 
109
  Determine if this question requires mathematical calculation. If yes, extract the
110
  mathematical expression that needs to be calculated.
@@ -122,64 +86,36 @@ class BasicAgent:
122
  response = self.llm.invoke(prompt)
123
  try:
124
  result = json.loads(response.content)
125
- state.thoughts.append(f"Analysis: {result.get('thought', 'No analysis provided')}")
126
- state.need_calculator = result.get('need_calculator', False)
127
- state.math_expression = result.get('math_expression')
 
128
  except json.JSONDecodeError as e:
129
  # Fallback in case of JSON parsing error
130
- state.thoughts.append(f"Couldn't parse the analysis response as JSON: {e}")
131
- state.thoughts.append(f"Raw response: {response.content[:100]}...")
132
- state.need_calculator = False
133
  except Exception as e:
134
  # Fallback for any other parsing error
135
- state.thoughts.append(f"Error processing response: {str(e)}")
136
- state.need_calculator = False
137
  except Exception as e:
138
  # Fallback for LLM invocation error
139
- state.thoughts.append(f"Error invoking language model: {str(e)}")
140
- state.need_calculator = False
141
-
142
- return state
143
 
144
- def _solve_math(self, state: Dict[str, Any]) -> Dict[str, Any]:
145
  """Evaluate the mathematical expression."""
146
- # Skip calculation if not needed
147
- if not state.need_calculator:
148
- state.thoughts.append("No mathematical calculation required.")
149
- return state
150
-
151
- # Skip if no expression provided
152
- if not state.math_expression:
153
- state.thoughts.append("Math calculation was indicated but no expression was provided.")
154
- return state
155
-
156
  try:
157
  # Simple math expression evaluator
158
- # This is a basic implementation - in production, you'd want more robust validation
159
- result = eval(state.math_expression)
160
- state.thoughts.append(f"Calculated {state.math_expression} = {result}")
161
- state.calc_result = result
162
  except Exception as e:
163
- state.thoughts.append(f"Error calculating expression: {e}")
164
-
165
- return state
166
 
167
- def _reasoning(self, state: Dict[str, Any]) -> Dict[str, Any]:
168
  """Perform step-by-step reasoning to solve the problem."""
169
- # Build calculation context if available
170
- calc_context = ""
171
- if state.need_calculator and hasattr(state, "calc_result") and state.calc_result is not None:
172
- calc_context = f"""
173
- Mathematical calculation was needed for this problem.
174
- Expression: {state.math_expression}
175
- Calculation result: {state.calc_result}
176
- """
177
-
178
  prompt = [
179
  HumanMessage(content=f"""
180
  You are a general AI assistant. Solve the following question using careful step-by-step reasoning.
181
 
182
- Question: {state.question}
183
 
184
  {calc_context}
185
 
@@ -190,22 +126,20 @@ class BasicAgent:
190
 
191
  try:
192
  response = self.llm.invoke(prompt)
193
- state.thoughts.append(response.content)
194
  except Exception as e:
195
- state.thoughts.append(f"Error during reasoning step: {str(e)}")
196
-
197
- return state
198
 
199
- def _format_answer(self, state: Dict[str, Any]) -> Dict[str, Any]:
200
  """Format the final answer according to Gaia Benchmark requirements."""
201
- all_thoughts = "\n".join(state.thoughts)
202
 
203
  prompt = [
204
  HumanMessage(content=f"""
205
  You are a general AI assistant. Based on the following reasoning, provide a concise
206
  final answer to the question. The final answer format is extremely important.
207
 
208
- Question: {state.question}
209
 
210
  Reasoning:
211
  {all_thoughts}
@@ -229,23 +163,18 @@ class BasicAgent:
229
  # Extract the final answer using regex
230
  final_answer_match = re.search(r'FINAL ANSWER:\s*(.*?)(?:\n|$)', response.content)
231
  if final_answer_match:
232
- state.final_answer = final_answer_match.group(1).strip()
233
- else:
234
- # If regex fails, try to extract anything after "FINAL ANSWER:"
235
- if "FINAL ANSWER:" in response.content:
236
- parts = response.content.split("FINAL ANSWER:")
237
- if len(parts) > 1:
238
- state.final_answer = parts[1].strip()
239
- else:
240
- state.final_answer = "Error: Malformed answer format."
241
  else:
242
- # Fallback in case the model didn't follow the format at all
243
- state.final_answer = response.content.strip()
 
244
  except Exception as e:
245
- state.final_answer = f"Error formatting answer: {str(e)}"
246
-
247
- return state
248
-
249
  def __call__(self, question: str) -> str:
250
  """
251
  Process the question and return a formatted response according to Gaia requirements.
@@ -258,19 +187,40 @@ class BasicAgent:
258
  """
259
  print(f"Agent received question (first 50 chars): {question[:50]}...")
260
 
261
- # Initialize state
262
- initial_state = {"question": question}
263
 
264
- # Execute the workflow
265
  try:
266
- result = self.workflow.invoke(initial_state)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
  # Format the response according to Gaia requirements
269
  formatted_response = "You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template:\nFINAL ANSWER: [YOUR FINAL ANSWER]\n\n"
270
- formatted_response += "\n\n".join(result.thoughts)
271
- formatted_response += f"\n\nFINAL ANSWER: {result.final_answer}"
272
 
273
- print(f"Agent returning answer with final part: {result.final_answer}")
274
  return formatted_response
275
  except Exception as e:
276
  print(f"Error running agent workflow: {e}")
 
39
  FINAL ANSWER: [YOUR FINAL ANSWER]"
40
  """
41
 
42
+ def __init__(self, model_name: str = "gpt-3.5-turbo", api_key: str = None):
43
  """
44
  Initialize the BasicAgent with the specified LLM.
45
 
46
  Args:
47
+ model_name: The name of the model to use (defaults to gpt-3.5-turbo)
48
  api_key: OpenAI API key (defaults to environment variable)
49
  """
50
  # Use the provided API key or fall back to the environment variable
 
55
 
56
  self.llm = ChatOpenAI(
57
  model=model_name,
58
+ temperature=0,
59
  api_key=api_key
60
  )
61
 
 
 
62
  print(f"BasicAgent initialized with model: {model_name}")
63
 
64
+ def analyze_question(self, question: str):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  """Analyze the question to determine its type and approach."""
66
  prompt = [
67
  HumanMessage(content=f"""
68
  You are an expert problem analyzer. Examine the following question to determine its type
69
  and if it requires mathematical calculation.
70
 
71
+ Question: {question}
72
 
73
  Determine if this question requires mathematical calculation. If yes, extract the
74
  mathematical expression that needs to be calculated.
 
86
  response = self.llm.invoke(prompt)
87
  try:
88
  result = json.loads(response.content)
89
+ thought = f"Analysis: {result.get('thought', 'No analysis provided')}"
90
+ need_calculator = result.get('need_calculator', False)
91
+ math_expression = result.get('math_expression')
92
+ return thought, need_calculator, math_expression
93
  except json.JSONDecodeError as e:
94
  # Fallback in case of JSON parsing error
95
+ return f"Couldn't parse the analysis response as JSON: {e}", False, None
 
 
96
  except Exception as e:
97
  # Fallback for any other parsing error
98
+ return f"Error processing response: {str(e)}", False, None
 
99
  except Exception as e:
100
  # Fallback for LLM invocation error
101
+ return f"Error invoking language model: {str(e)}", False, None
 
 
 
102
 
103
+ def solve_math(self, math_expression):
104
  """Evaluate the mathematical expression."""
 
 
 
 
 
 
 
 
 
 
105
  try:
106
  # Simple math expression evaluator
107
+ result = eval(math_expression)
108
+ return f"Calculated {math_expression} = {result}", result
 
 
109
  except Exception as e:
110
+ return f"Error calculating expression: {e}", None
 
 
111
 
112
+ def reasoning(self, question, calc_context=""):
113
  """Perform step-by-step reasoning to solve the problem."""
 
 
 
 
 
 
 
 
 
114
  prompt = [
115
  HumanMessage(content=f"""
116
  You are a general AI assistant. Solve the following question using careful step-by-step reasoning.
117
 
118
+ Question: {question}
119
 
120
  {calc_context}
121
 
 
126
 
127
  try:
128
  response = self.llm.invoke(prompt)
129
+ return response.content
130
  except Exception as e:
131
+ return f"Error during reasoning step: {str(e)}"
 
 
132
 
133
+ def format_answer(self, question, thoughts):
134
  """Format the final answer according to Gaia Benchmark requirements."""
135
+ all_thoughts = "\n".join(thoughts)
136
 
137
  prompt = [
138
  HumanMessage(content=f"""
139
  You are a general AI assistant. Based on the following reasoning, provide a concise
140
  final answer to the question. The final answer format is extremely important.
141
 
142
+ Question: {question}
143
 
144
  Reasoning:
145
  {all_thoughts}
 
163
  # Extract the final answer using regex
164
  final_answer_match = re.search(r'FINAL ANSWER:\s*(.*?)(?:\n|$)', response.content)
165
  if final_answer_match:
166
+ return final_answer_match.group(1).strip()
167
+ elif "FINAL ANSWER:" in response.content:
168
+ parts = response.content.split("FINAL ANSWER:")
169
+ if len(parts) > 1:
170
+ return parts[1].strip()
 
 
 
 
171
  else:
172
+ return "Error: Malformed answer format."
173
+ else:
174
+ return response.content.strip()
175
  except Exception as e:
176
+ return f"Error formatting answer: {str(e)}"
177
+
 
 
178
  def __call__(self, question: str) -> str:
179
  """
180
  Process the question and return a formatted response according to Gaia requirements.
 
187
  """
188
  print(f"Agent received question (first 50 chars): {question[:50]}...")
189
 
190
+ # Initialize an empty list to collect thoughts
191
+ thoughts = []
192
 
 
193
  try:
194
+ # Step 1: Analyze the question
195
+ analysis_thought, need_calculator, math_expression = self.analyze_question(question)
196
+ thoughts.append(analysis_thought)
197
+
198
+ # Step 2: Calculate if needed
199
+ calc_result = None
200
+ calc_context = ""
201
+ if need_calculator and math_expression:
202
+ calc_thought, calc_result = self.solve_math(math_expression)
203
+ thoughts.append(calc_thought)
204
+ if calc_result is not None:
205
+ calc_context = f"""
206
+ Mathematical calculation was needed for this problem.
207
+ Expression: {math_expression}
208
+ Calculation result: {calc_result}
209
+ """
210
+
211
+ # Step 3: Perform reasoning
212
+ reasoning_output = self.reasoning(question, calc_context)
213
+ thoughts.append(reasoning_output)
214
+
215
+ # Step 4: Format final answer
216
+ final_answer = self.format_answer(question, thoughts)
217
 
218
  # Format the response according to Gaia requirements
219
  formatted_response = "You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template:\nFINAL ANSWER: [YOUR FINAL ANSWER]\n\n"
220
+ formatted_response += "\n\n".join(thoughts)
221
+ formatted_response += f"\n\nFINAL ANSWER: {final_answer}"
222
 
223
+ print(f"Agent returning answer with final part: {final_answer}")
224
  return formatted_response
225
  except Exception as e:
226
  print(f"Error running agent workflow: {e}")