drAbreu commited on
Commit
f2f9139
·
1 Parent(s): ff61745

Added writer agent to generate answers

Browse files
Files changed (2) hide show
  1. agents/llama_index_agent.py +105 -3
  2. app.py +75 -12
agents/llama_index_agent.py CHANGED
@@ -1,4 +1,7 @@
1
- from llama_index.core.agent.workflow import ReActAgent
 
 
 
2
  from llama_index.core.llms import LLM
3
  import os
4
  from typing import Optional, List, Any
@@ -61,6 +64,10 @@ class GaiaAgent(ReActAgent):
61
  # Use default system prompt if not provided
62
  if system_prompt is None:
63
  system_prompt = self._get_default_system_prompt()
 
 
 
 
64
 
65
  # Initialize the parent ReActAgent
66
  super().__init__(
@@ -69,6 +76,7 @@ class GaiaAgent(ReActAgent):
69
  llm=llm,
70
  system_prompt=system_prompt,
71
  tools=tools,
 
72
  **kwargs
73
  )
74
 
@@ -84,9 +92,9 @@ class GaiaAgent(ReActAgent):
84
 
85
  else:
86
  raise ValueError(f"Unsupported model provider: {model_provider}. "
87
- f"Supported providers are: openai, anthropic, cohere, huggingface, llama")
88
 
89
- def _get_default_system_prompt(self) -> str:
90
  """Return the default system prompt for GAIA benchmark tasks."""
91
  return """
92
  You are the lead coordinator for a team of specialized AI agents tackling the GAIA benchmark. Your job is to analyze each question with extreme precision, determine the exact format required for the answer, break the task into logical steps, and either solve it yourself or delegate to the appropriate specialized agents.
@@ -136,3 +144,97 @@ class GaiaAgent(ReActAgent):
136
 
137
  IMPORTANT: Your value is in providing PRECISELY what was asked for - not in showing your work or explaining how you got there.
138
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from llama_index.core.agent.workflow import (
2
+ ReActAgent,
3
+ FunctionAgent
4
+ )
5
  from llama_index.core.llms import LLM
6
  import os
7
  from typing import Optional, List, Any
 
64
  # Use default system prompt if not provided
65
  if system_prompt is None:
66
  system_prompt = self._get_default_system_prompt()
67
+
68
+ can_handoff_to = [
69
+ "writer_agent"
70
+ ]
71
 
72
  # Initialize the parent ReActAgent
73
  super().__init__(
 
76
  llm=llm,
77
  system_prompt=system_prompt,
78
  tools=tools,
79
+ can_handoff_to=can_handoff_to,
80
  **kwargs
81
  )
82
 
 
92
 
93
  else:
94
  raise ValueError(f"Unsupported model provider: {model_provider}. "
95
+ f"Supported providers are: openai, anthropic")
96
 
97
+ def _get_default_system_prompt_legacy(self) -> str:
98
  """Return the default system prompt for GAIA benchmark tasks."""
99
  return """
100
  You are the lead coordinator for a team of specialized AI agents tackling the GAIA benchmark. Your job is to analyze each question with extreme precision, determine the exact format required for the answer, break the task into logical steps, and either solve it yourself or delegate to the appropriate specialized agents.
 
144
 
145
  IMPORTANT: Your value is in providing PRECISELY what was asked for - not in showing your work or explaining how you got there.
146
  """
147
+
148
+ def _get_default_system_prompt(self) -> str:
149
+ """Return the default system prompt for GAIA benchmark tasks."""
150
+ return """
151
+ You are the lead coordinator for a team of specialized AI agents tackling the GAIA benchmark. Your job is to analyze questions and generate detailed analysis, which you'll pass to a specialized formatting agent for final answer preparation.
152
+
153
+ ## QUESTION ANALYSIS PROCESS
154
+ 1. First, carefully read and parse the entire question
155
+ 2. Identify the EXACT output format required (single word, name, number, comma-separated list, etc.)
156
+ 3. Note any special formatting requirements (alphabetical order, specific notation, etc.)
157
+ 4. Identify what type of task this is (research, audio analysis, video analysis, code execution, data analysis, etc.)
158
+ 5. Break the question into sequential steps
159
+
160
+ ## SOLVING METHODOLOGY
161
+ 1. For each question, thoroughly work through the reasoning step-by-step
162
+ 2. Use available tools (reverse_text_tool, search tools) when needed
163
+ 3. Document your full analysis, including all key facts, calculations, and relevant information
164
+ 4. Clearly identify what you believe the correct answer is
165
+ 5. Be extremely explicit about the required formatting for the final answer
166
+
167
+ ## DELEGATION TO WRITER AGENT
168
+ After completing your analysis, ALWAYS delegate the final answer preparation to the writer_agent with:
169
+ - query: The original question
170
+ - research_notes: Your complete analysis, all relevant facts, and what you believe is the correct answer
171
+ - answer_format: EXPLICIT instructions on exactly how the answer should be formatted (single word, comma-separated list, etc.)
172
+
173
+ Example handoff to writer_agent:
174
+ ```
175
+ I'll delegate to writer_agent to format the final answer.
176
+
177
+ query: What is the first name of the scientist who discovered penicillin?
178
+ research_notes: After researching, I found that Sir Alexander Fleming discovered penicillin in 1928. The full answer is "Alexander Fleming" but the question only asks for the first name, which is "Alexander".
179
+ answer_format: Return ONLY the first name, with no additional text, punctuation, or explanation.
180
+ ```
181
+
182
+ IMPORTANT: NEVER provide the final answer directly to the user. ALWAYS hand off to the writer_agent for proper formatting.
183
+ """
184
+
185
+
186
+ def create_writer_agent(model_config: Dict[str, Any]) -> ReActAgent:
187
+ """
188
+ Create a writer agent that formats final answers based on research notes.
189
+
190
+ Args:
191
+ model_config: Dictionary containing model_provider, model_name, and api_key
192
+
193
+ Returns:
194
+ A configured ReActAgent for formatting final answers
195
+ """
196
+ # Initialize LLM based on the provided configuration
197
+ model_provider = model_config.get("model_provider", "openai")
198
+ model_name = model_config.get("model_name", "gpt-4o")
199
+ api_key = model_config.get("api_key")
200
+
201
+ if model_provider.lower() == "openai":
202
+ llm = OpenAI(model=model_name, api_key=api_key or os.getenv("OPENAI_API_KEY"))
203
+ elif model_provider.lower() == "anthropic":
204
+ llm = Anthropic(model=model_name, api_key=api_key or os.getenv("ANTHROPIC_API_KEY"))
205
+ else:
206
+ raise ValueError(f"Unsupported model provider for writer agent: {model_provider}")
207
+
208
+ # Create and return the writer agent
209
+ return ReActAgent(
210
+ name="writer_agent",
211
+ description="Formats the final answer exactly as specified for GAIA benchmark questions",
212
+ system_prompt="""
213
+ You are a specialized formatting agent for the GAIA benchmark. Your ONLY job is to take the research from the main agent and format the answer EXACTLY as required by the benchmark question.
214
+
215
+ ## YOUR ROLE
216
+ You will receive:
217
+ - query: The original question
218
+ - research_notes: The main agent's complete analysis and reasoning
219
+ - answer_format: Specific formatting instructions for the final answer
220
+
221
+ ## CRITICAL RULES
222
+ 1. Your response MUST CONTAIN ONLY THE ANSWER - no explanations, no "the answer is" prefix
223
+ 2. Follow the answer_format instructions precisely
224
+ 3. Remove ALL unnecessary characters, spaces, punctuation, or wording
225
+ 4. If asked for a name, provide ONLY the name
226
+ 5. If asked for a number, provide ONLY the number
227
+ 6. If asked for a list, format it EXACTLY as specified (comma-separated, alphabetical, etc.)
228
+ 7. NEVER include your own thoughts or analysis
229
+ 8. NEVER add preamble or conclusion text
230
+
231
+ ## EXAMPLES OF CORRECT RESPONSES:
232
+ When asked for "first name only": Alexander
233
+ When asked for "comma-separated list in alphabetical order": apple, banana, cherry
234
+ When asked for "single number": 42
235
+ When asked for "opposite of word 'right'": left
236
+
237
+ REMEMBER: Your ENTIRE response should be just the answer - nothing more, nothing less.
238
+ """,
239
+ llm=llm
240
+ )
app.py CHANGED
@@ -3,8 +3,10 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
6
- from agents.llama_index_agent import GaiaAgent
7
  import asyncio
 
 
 
8
  # (Keep Constants as is)
9
  # --- Constants ---
10
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
@@ -23,34 +25,95 @@ OPENAI = {
23
  class BasicAgent:
24
  def __init__(
25
  self,
26
- model_provider="openai",
27
- model_name="gpt-4o",
28
- api_key=None
 
 
 
29
  ):
30
  """
31
- Initialize the BasicAgent with configurable model settings.
32
 
33
  Args:
34
- model_provider: LLM provider to use (openai, anthropic, etc.)
35
- model_name: Specific model to use
36
- api_key: Optional API key (defaults to environment variable)
 
 
 
37
  """
38
- self.agent = GaiaAgent(**OPENAI)
39
- print(f"BasicAgent initialized with {model_provider} {model_name}.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  def __call__(self, question: str) -> str:
42
  """Process a GAIA benchmark question and return the formatted answer."""
43
  print(f"Agent received question (first 50 chars): {question[:50]}...")
44
 
45
  async def agentic_main():
46
- response = await self.agent.run(question)
47
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  response = asyncio.run(agentic_main())
 
 
50
  final_answer = response.response.blocks[-1].text
51
  print(f"Agent returning answer: {final_answer}")
52
  return final_answer
53
 
 
54
  def run_and_submit_all( profile: gr.OAuthProfile | None):
55
  """
56
  Fetches all questions, runs the BasicAgent on them, submits all answers,
 
3
  import requests
4
  import inspect
5
  import pandas as pd
 
6
  import asyncio
7
+ from llama_index.core.agent.workflow import AgentWorkflow
8
+ from agents.llama_index_agent import GaiaAgent, create_writer_agent
9
+
10
  # (Keep Constants as is)
11
  # --- Constants ---
12
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
 
25
  class BasicAgent:
26
  def __init__(
27
  self,
28
+ model_provider="anthropic",
29
+ model_name="claude-3-7-sonnet-latest",
30
+ api_key=None,
31
+ use_separate_writer_model=True,
32
+ writer_model_provider="openai",
33
+ writer_model_name="gpt-4o"
34
  ):
35
  """
36
+ Initialize the BasicAgent with a multi-agent workflow.
37
 
38
  Args:
39
+ model_provider: LLM provider for main agent
40
+ model_name: Model name for main agent
41
+ api_key: API key for main agent
42
+ use_separate_writer_model: Whether to use a different model for the writer agent
43
+ writer_model_provider: LLM provider for writer agent (if separate)
44
+ writer_model_name: Model name for writer agent (if separate)
45
  """
46
+ # Configure the main reasoning agent
47
+ main_model_config = {
48
+ "model_provider": model_provider,
49
+ "model_name": model_name,
50
+ "api_key": api_key
51
+ }
52
+
53
+ # Configure the writer agent (either same as main or different)
54
+ if use_separate_writer_model:
55
+ writer_model_config = {
56
+ "model_provider": writer_model_provider,
57
+ "model_name": writer_model_name,
58
+ "api_key": api_key # Use same API key for simplicity
59
+ }
60
+ else:
61
+ writer_model_config = main_model_config
62
+
63
+ # Create the main agent
64
+ self.main_agent = GaiaAgent(**main_model_config)
65
+
66
+ # Create the writer agent
67
+ self.writer_agent = create_writer_agent(writer_model_config)
68
+
69
+ # Set up the agent workflow with shared context
70
+ self.agent_workflow = AgentWorkflow(
71
+ agents=[self.main_agent, self.writer_agent],
72
+ root_agent=self.main_agent.name,
73
+ initial_state={
74
+ "original_question": "",
75
+ "analysis_notes": "",
76
+ "format_requirements": "",
77
+ "next_agent": "",
78
+ "final_answer": ""
79
+ }
80
+ )
81
+
82
+ print(f"BasicAgent initialized with main agent: {model_provider} {model_name}")
83
+ if use_separate_writer_model:
84
+ print(f"Writer agent using: {writer_model_provider} {writer_model_name}")
85
+ else:
86
+ print(f"Writer agent using same model as main agent")
87
 
88
  def __call__(self, question: str) -> str:
89
  """Process a GAIA benchmark question and return the formatted answer."""
90
  print(f"Agent received question (first 50 chars): {question[:50]}...")
91
 
92
  async def agentic_main():
93
+ # Initialize context with the question
94
+ initial_state = {
95
+ "original_question": question,
96
+ "analysis_notes": "",
97
+ "format_requirements": "",
98
+ "next_agent": "",
99
+ "final_answer": ""
100
+ }
101
+
102
+ # Use the workflow to process the question
103
+ workflow_response = await self.agent_workflow.arun(
104
+ question,
105
+ initial_state=initial_state
106
+ )
107
+ return workflow_response
108
 
109
  response = asyncio.run(agentic_main())
110
+
111
+ # Extract the final answer from the writer agent's response
112
  final_answer = response.response.blocks[-1].text
113
  print(f"Agent returning answer: {final_answer}")
114
  return final_answer
115
 
116
+
117
  def run_and_submit_all( profile: gr.OAuthProfile | None):
118
  """
119
  Fetches all questions, runs the BasicAgent on them, submits all answers,