Isateles commited on
Commit
7adb281
·
1 Parent(s): 512bc6b

update workflow error

Browse files
Files changed (3) hide show
  1. app.py +68 -45
  2. requirements.txt +4 -57
  3. tools.py +2 -1
app.py CHANGED
@@ -182,8 +182,8 @@ class GAIAAgent:
182
 
183
  # Import tools from our tools.py file
184
  try:
185
- from tools import create_all_tools
186
- tool_list = create_all_tools()
187
  tools.extend(tool_list)
188
  logger.info(f"✅ Loaded {len(tool_list)} tools from tools.py")
189
  except ImportError as e:
@@ -191,18 +191,6 @@ class GAIAAgent:
191
  except Exception as e:
192
  logger.warning(f"⚠️ Error loading tools from tools.py: {e}")
193
 
194
- # Import RAG tool from our retriever.py file
195
- try:
196
- from retriever import create_persona_tool
197
- persona_tool = create_persona_tool()
198
- if persona_tool:
199
- tools.append(persona_tool)
200
- logger.info("✅ Loaded persona RAG tool from retriever.py")
201
- except ImportError as e:
202
- logger.error(f"❌ Could not import retriever.py: {e}")
203
- except Exception as e:
204
- logger.warning(f"⚠️ Error loading RAG tool from retriever.py: {e}")
205
-
206
  # Check if we have any tools
207
  if not tools:
208
  error_msg = "❌ No tools available! Check tools.py and retriever.py"
@@ -213,18 +201,18 @@ class GAIAAgent:
213
  for tool in tools:
214
  logger.info(f" - {tool.metadata.name}: {tool.metadata.description[:50]}...")
215
 
216
- # Step 3: Create the agent workflow
217
  try:
218
- from llama_index.core.agent.workflow import AgentWorkflow
219
 
220
- # Create the agent with a GAIA-optimized system prompt
221
  self.agent = AgentWorkflow.from_tools_or_functions(
222
  tools_or_functions=tools,
223
  llm=self.llm,
224
  system_prompt=self._create_system_prompt()
225
  )
226
 
227
- logger.info("✅ Agent workflow created successfully")
228
 
229
  except ImportError as e:
230
  error_msg = f"❌ Could not import AgentWorkflow: {e}"
@@ -285,14 +273,13 @@ class GAIAAgent:
285
 
286
  def __call__(self, question: str) -> str:
287
  """
288
- Process a GAIA question and return an answer.
289
 
290
- This is the main method that the evaluation system calls.
291
- It handles the entire question-answering pipeline:
292
- 1. Logs the incoming question
293
- 2. Runs the agent workflow asynchronously
294
- 3. Extracts and cleans the response
295
- 4. Returns a properly formatted answer
296
 
297
  Args:
298
  question (str): The GAIA question to answer
@@ -303,16 +290,35 @@ class GAIAAgent:
303
  logger.info(f"📝 Processing GAIA question: {question[:100]}...")
304
 
305
  try:
306
- # Run the agent asynchronously
307
- # GAIA questions can be complex and may require multiple tool calls
 
 
308
  loop = asyncio.new_event_loop()
309
  asyncio.set_event_loop(loop)
310
 
311
  try:
312
- # Execute the agent workflow
313
- result = loop.run_until_complete(
314
- self.agent.run(user_msg=question)
315
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
  # Extract the response from the result object
318
  answer = self._extract_response(result)
@@ -335,10 +341,10 @@ class GAIAAgent:
335
 
336
  def _extract_response(self, result: Any) -> str:
337
  """
338
- Extract the text response from the agent workflow result.
339
 
340
- Agent workflows can return different types of objects.
341
- This method handles various result formats robustly.
342
 
343
  Args:
344
  result: The result object from the agent workflow
@@ -346,18 +352,35 @@ class GAIAAgent:
346
  Returns:
347
  str: Extracted response text
348
  """
349
- # Try different ways to extract the response
350
- if hasattr(result, 'response'):
351
- return str(result.response)
352
- elif hasattr(result, 'content'):
353
- return str(result.content)
354
- elif hasattr(result, 'message'):
355
- if hasattr(result.message, 'content'):
356
- return str(result.message.content)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  else:
358
- return str(result.message)
359
- else:
360
- # Fallback: convert whatever we got to string
 
 
 
361
  return str(result)
362
 
363
  def _clean_answer(self, answer: str) -> str:
 
182
 
183
  # Import tools from our tools.py file
184
  try:
185
+ from tools import get_all_tools
186
+ tool_list = get_all_tools()
187
  tools.extend(tool_list)
188
  logger.info(f"✅ Loaded {len(tool_list)} tools from tools.py")
189
  except ImportError as e:
 
191
  except Exception as e:
192
  logger.warning(f"⚠️ Error loading tools from tools.py: {e}")
193
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  # Check if we have any tools
195
  if not tools:
196
  error_msg = "❌ No tools available! Check tools.py and retriever.py"
 
201
  for tool in tools:
202
  logger.info(f" - {tool.metadata.name}: {tool.metadata.description[:50]}...")
203
 
204
+ # Step 3: Create the agent using AgentWorkflow (course approach)
205
  try:
206
+ from llama_index.core.agent.workflow import AgentWorkflow, ToolCallResult, AgentStream
207
 
208
+ # Create the agent with a GAIA-optimized system prompt (exactly like course)
209
  self.agent = AgentWorkflow.from_tools_or_functions(
210
  tools_or_functions=tools,
211
  llm=self.llm,
212
  system_prompt=self._create_system_prompt()
213
  )
214
 
215
+ logger.info("✅ AgentWorkflow created successfully")
216
 
217
  except ImportError as e:
218
  error_msg = f"❌ Could not import AgentWorkflow: {e}"
 
273
 
274
  def __call__(self, question: str) -> str:
275
  """
276
+ Process a GAIA question and return an answer using course approach.
277
 
278
+ This follows the exact pattern from the course notebook:
279
+ 1. Run the agent to get a handler
280
+ 2. Stream events asynchronously
281
+ 3. Extract the final response
282
+ 4. Clean and return the answer
 
283
 
284
  Args:
285
  question (str): The GAIA question to answer
 
290
  logger.info(f"📝 Processing GAIA question: {question[:100]}...")
291
 
292
  try:
293
+ # Import event types for processing
294
+ from llama_index.core.agent.workflow import ToolCallResult, AgentStream
295
+
296
+ # Run the agent asynchronously following course pattern
297
  loop = asyncio.new_event_loop()
298
  asyncio.set_event_loop(loop)
299
 
300
  try:
301
+ async def run_agent():
302
+ # Start the agent run (course pattern)
303
+ handler = self.agent.run(user_msg=question)
304
+
305
+ # Stream events and collect reasoning (optional for debugging)
306
+ reasoning_steps = []
307
+ async for ev in handler.stream_events():
308
+ if isinstance(ev, ToolCallResult):
309
+ step = f"Tool: {ev.tool_name}({ev.tool_kwargs}) => {ev.tool_output}"
310
+ reasoning_steps.append(step)
311
+ logger.info(f"🔧 {step}")
312
+ elif isinstance(ev, AgentStream):
313
+ # This is the agent's thought process
314
+ pass # We could log this for debugging
315
+
316
+ # Get the final response
317
+ resp = await handler
318
+ return resp
319
+
320
+ # Execute the agent
321
+ result = loop.run_until_complete(run_agent())
322
 
323
  # Extract the response from the result object
324
  answer = self._extract_response(result)
 
341
 
342
  def _extract_response(self, result: Any) -> str:
343
  """
344
+ Extract the text response from the AgentWorkflow result.
345
 
346
+ Based on the course notebook, AgentWorkflow returns an AgentOutput with this structure:
347
+ AgentOutput(response=ChatMessage(...), tool_calls=[], raw={...})
348
 
349
  Args:
350
  result: The result object from the agent workflow
 
352
  Returns:
353
  str: Extracted response text
354
  """
355
+ try:
356
+ # Handle AgentOutput format from course (most likely)
357
+ if hasattr(result, 'response'):
358
+ chat_message = result.response
359
+ if hasattr(chat_message, 'blocks'):
360
+ # Extract text from TextBlock(s)
361
+ for block in chat_message.blocks:
362
+ if hasattr(block, 'text'):
363
+ return str(block.text)
364
+ elif hasattr(chat_message, 'content'):
365
+ return str(chat_message.content)
366
+ else:
367
+ return str(chat_message)
368
+
369
+ # Fallback to other common formats
370
+ elif hasattr(result, 'content'):
371
+ return str(result.content)
372
+ elif hasattr(result, 'message'):
373
+ if hasattr(result.message, 'content'):
374
+ return str(result.message.content)
375
+ else:
376
+ return str(result.message)
377
  else:
378
+ # Final fallback: convert whatever we got to string
379
+ return str(result)
380
+
381
+ except Exception as e:
382
+ logger.warning(f"⚠️ Error extracting response: {e}")
383
+ # If extraction fails, try simple string conversion
384
  return str(result)
385
 
386
  def _clean_answer(self, answer: str) -> str:
requirements.txt CHANGED
@@ -45,13 +45,10 @@ llama-index-llms-huggingface-api
45
  # Requires HF_TOKEN in your Space secrets
46
 
47
  # ============================================================================
48
- # AGENT WORKFLOW SYSTEM
49
  # ============================================================================
50
- # This enables the agent functionality from the course
51
-
52
- llama-index-agent-workflow
53
- # Agent workflow system - allows creating agents that can use multiple tools
54
- # This is what orchestrates the web search, calculator, and RAG tools
55
 
56
  # ============================================================================
57
  # RETRIEVAL SYSTEMS (RAG) - Enhanced with Vector Embeddings
@@ -104,54 +101,4 @@ python-dotenv
104
  nest-asyncio
105
  # Allows running async code in environments that already have an event loop
106
  # Required for running LlamaIndex query engines in Jupyter/Gradio
107
- # Fixes "RuntimeError: This event loop is already running" errors
108
-
109
- # ============================================================================
110
- # OPTIONAL: ADDITIONAL USEFUL PACKAGES
111
- # ============================================================================
112
- # These might be helpful for specific GAIA questions but aren't required
113
-
114
- # numpy
115
- # For numerical computations if needed for advanced math questions
116
-
117
- # matplotlib
118
- # For creating charts/graphs if GAIA questions require visualizations
119
-
120
- # beautifulsoup4
121
- # For parsing HTML if web search results need detailed extraction
122
-
123
- # ============================================================================
124
- # DEVELOPMENT AND DEBUGGING (Optional)
125
- # ============================================================================
126
- # Uncomment these if you want enhanced debugging capabilities
127
-
128
- # jupyter
129
- # For interactive development and testing
130
-
131
- # ipywidgets
132
- # For enhanced Jupyter notebook widgets
133
-
134
- # rich
135
- # For beautiful terminal output and better logging
136
-
137
- # ============================================================================
138
- # INSTALLATION NOTES
139
- # ============================================================================
140
- #
141
- # To install all dependencies:
142
- # pip install -r requirements.txt
143
- #
144
- # For HuggingFace Spaces:
145
- # - This file should be in your Space root directory
146
- # - Dependencies are automatically installed when you deploy
147
- # - No manual installation needed
148
- #
149
- # API Keys Setup:
150
- # - Go to your Space Settings → Repository secrets
151
- # - Add OPENAI_API_KEY (for OpenAI) or HF_TOKEN (for HuggingFace)
152
- # - At least one is required for the agent to work
153
- #
154
- # Troubleshooting:
155
- # - If imports fail, check that all packages installed correctly
156
- # - Some packages may require specific versions for compatibility
157
- # - Check the Space logs for detailed error messages
 
45
  # Requires HF_TOKEN in your Space secrets
46
 
47
  # ============================================================================
48
+ # AGENT SYSTEM - Course Approach
49
  # ============================================================================
50
+ # AgentWorkflow is part of llama-index-core, no separate package needed
51
+ # This matches exactly what the course notebook uses
 
 
 
52
 
53
  # ============================================================================
54
  # RETRIEVAL SYSTEMS (RAG) - Enhanced with Vector Embeddings
 
101
  nest-asyncio
102
  # Allows running async code in environments that already have an event loop
103
  # Required for running LlamaIndex query engines in Jupyter/Gradio
104
+ # Fixes "RuntimeError: This event loop is already running" errors
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tools.py CHANGED
@@ -653,4 +653,5 @@ if __name__ == "__main__":
653
  print("\n=== Tools Testing Complete ===")
654
  print("\nTo use these tools in your agent:")
655
  print("from tools import get_all_tools")
656
- print("tools = get_all_tools()")
 
 
653
  print("\n=== Tools Testing Complete ===")
654
  print("\nTo use these tools in your agent:")
655
  print("from tools import get_all_tools")
656
+ print("tools = get_all_tools()")
657
+