Humanlearning commited on
Commit
848db06
Β·
1 Parent(s): 05ecbdd

updated research agent

Browse files
__pycache__/langgraph_agent_system.cpython-310.pyc CHANGED
Binary files a/__pycache__/langgraph_agent_system.cpython-310.pyc and b/__pycache__/langgraph_agent_system.cpython-310.pyc differ
 
agents/__pycache__/research_agent.cpython-313.pyc CHANGED
Binary files a/agents/__pycache__/research_agent.cpython-313.pyc and b/agents/__pycache__/research_agent.cpython-313.pyc differ
 
agents/research_agent.py CHANGED
@@ -29,86 +29,94 @@ from tools import (
29
  load_dotenv("env.local")
30
 
31
 
32
- def create_research_tools() -> List[Tool]:
33
- """Create LangChain-compatible research tools"""
34
- tools = []
35
 
36
- try:
37
- # Import LlamaIndex tools and convert them
38
- from tools import get_tavily_tool, get_wikipedia_tool, get_arxiv_tool
39
-
40
- # Tavily web search
41
  try:
42
- tavily_spec = get_tavily_tool()
43
- if tavily_spec:
44
- # Convert to LangChain tool
45
- def tavily_search(query: str) -> str:
46
- try:
47
- tavily_tools = tavily_spec.to_tool_list()
48
- if tavily_tools:
 
49
  result = tavily_tools[0].call({"input": query})
50
- return str(result)
51
- except Exception as e:
52
- return f"Search error: {str(e)}"
53
- return "No search results found"
54
-
55
- tavily_tool = Tool(
56
- name="web_search",
57
- description="Search the web for current information and facts using Tavily API",
58
- func=tavily_search
59
- )
60
- tools.append(tavily_tool)
61
- print(f"βœ… Added Tavily web search tool")
62
  except Exception as e:
63
- print(f"⚠️ Could not load Tavily tools: {e}")
64
-
65
- # Wikipedia search
 
 
66
  try:
67
- wikipedia_tool = get_wikipedia_tool()
68
- if wikipedia_tool:
69
- def wikipedia_search(query: str) -> str:
 
 
70
  try:
71
- result = wikipedia_tool.call({"input": query})
72
- return str(result)
73
- except Exception as e:
74
- return f"Wikipedia search error: {str(e)}"
75
-
76
- wiki_tool = Tool(
77
- name="wikipedia_search",
78
- description="Search Wikipedia for encyclopedic information",
79
- func=wikipedia_search
80
- )
81
- tools.append(wiki_tool)
82
- print("βœ… Added Wikipedia tool")
83
  except Exception as e:
84
- print(f"⚠️ Could not load Wikipedia tool: {e}")
85
-
86
- # ArXiv search
 
 
87
  try:
88
- arxiv_tool = get_arxiv_tool()
89
- if arxiv_tool:
90
- def arxiv_search(query: str) -> str:
 
 
91
  try:
92
- result = arxiv_tool.call({"input": query})
93
- return str(result)
94
- except Exception as e:
95
- return f"ArXiv search error: {str(e)}"
96
-
97
- arxiv_lc_tool = Tool(
98
- name="arxiv_search",
99
- description="Search ArXiv for academic papers and research",
100
- func=arxiv_search
101
- )
102
- tools.append(arxiv_lc_tool)
103
- print("βœ… Added ArXiv tool")
104
  except Exception as e:
105
- print(f"⚠️ Could not load ArXiv tool: {e}")
 
106
 
107
- except Exception as e:
108
- print(f"⚠️ Error setting up research tools: {e}")
 
 
 
 
 
 
 
 
 
 
109
 
110
- print(f"πŸ”§ Research Agent loaded {len(tools)} tools")
111
- return tools
112
 
113
 
114
  def load_research_prompt() -> str:
@@ -133,15 +141,19 @@ When researching:
133
  - Cross-reference information across sources
134
  - Note any conflicting information found
135
 
 
 
 
136
  Format your response as:
137
- ### Research Results
138
- - **Source 1**: [findings]
139
- - **Source 2**: [findings]
140
- - **Source 3**: [findings]
 
141
 
142
  ### Key Facts
143
  - Fact 1
144
- - Fact 2
145
  - Fact 3
146
 
147
  ### Citations
@@ -150,6 +162,46 @@ Format your response as:
150
  """
151
 
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  def research_agent(state: Dict[str, Any]) -> Command:
154
  """
155
  Research Agent node that gathers information using available tools.
@@ -163,28 +215,21 @@ def research_agent(state: Dict[str, Any]) -> Command:
163
  # Get research prompt
164
  research_prompt = load_research_prompt()
165
 
166
- # Initialize LLM with tools
167
  llm = ChatGroq(
168
  model="llama-3.3-70b-versatile",
169
  temperature=0.3, # Slightly higher for research creativity
170
  max_tokens=2048
171
  )
172
 
173
- # Get research tools
174
- tools = create_research_tools()
175
-
176
- # Bind tools to LLM if available
177
- if tools:
178
- llm_with_tools = llm.bind_tools(tools)
179
- else:
180
- llm_with_tools = llm
181
- print("⚠️ No tools available, proceeding with LLM only")
182
 
183
  # Create agent span for tracing
184
  with agent_span(
185
  "research",
186
  metadata={
187
- "tools_available": len(tools),
188
  "user_id": state.get("user_id", "unknown"),
189
  "session_id": state.get("session_id", "unknown")
190
  }
@@ -198,65 +243,49 @@ def research_agent(state: Dict[str, Any]) -> Command:
198
  user_query = msg.content
199
  break
200
 
201
- # Build research request
202
- research_request = f"""
203
- Please research the following question using available tools:
 
 
 
 
 
 
204
 
205
- Question: {user_query}
 
206
 
207
  Current research status: {len(state.get('research_notes', ''))} characters already gathered
208
 
209
  Instructions:
210
- 1. Search for factual information relevant to the question
211
- 2. Use multiple sources if possible for verification
212
- 3. Focus on accuracy and currency of information
213
- 4. Provide clear citations and sources
214
- 5. Structure your findings clearly
215
 
216
- Please gather comprehensive information to help answer this question.
217
  """
218
 
219
- # Create messages for research
220
- research_messages = [
221
  SystemMessage(content=research_prompt),
222
- HumanMessage(content=research_request)
223
  ]
224
 
225
- # Get research response
226
- if tools:
227
- # Try using tools for research
228
- response = llm_with_tools.invoke(research_messages)
229
-
230
- # If the response contains tool calls, execute them
231
- if hasattr(response, 'tool_calls') and response.tool_calls:
232
- print(f"πŸ› οΈ Executing {len(response.tool_calls)} tool calls")
233
-
234
- # Execute tool calls and collect results
235
- tool_results = []
236
- for tool_call in response.tool_calls:
237
- try:
238
- # Find the tool
239
- tool = next((t for t in tools if t.name == tool_call['name']), None)
240
- if tool:
241
- result = tool.run(tool_call['args'])
242
- tool_results.append(f"**{tool.name}**: {result}")
243
- except Exception as e:
244
- print(f"⚠️ Tool {tool_call['name']} failed: {e}")
245
- tool_results.append(f"**{tool_call['name']}**: Error - {str(e)}")
246
-
247
- # Compile research results
248
- research_findings = "\n\n".join(tool_results) if tool_results else response.content
249
- else:
250
- research_findings = response.content
251
- else:
252
- # No tools available, use LLM knowledge only
253
- research_findings = llm.invoke(research_messages).content
254
 
255
  # Format research results
256
  formatted_results = f"""
257
  ### Research Iteration {state.get('loop_counter', 0) + 1}
258
 
259
- {research_findings}
 
 
 
260
 
261
  ---
262
  """
 
29
  load_dotenv("env.local")
30
 
31
 
32
+ def create_research_functions() -> List[callable]:
33
+ """Create simple research functions that can be called directly"""
 
34
 
35
+ def web_search(query: str) -> str:
36
+ """Search the web using Tavily API"""
 
 
 
37
  try:
38
+ with tool_span("tavily_search", metadata={"query": query}):
39
+ from tools import get_tavily_tool
40
+ tavily_spec = get_tavily_tool()
41
+ if tavily_spec:
42
+ tavily_tools = tavily_spec.to_tool_list()
43
+ if tavily_tools and len(tavily_tools) > 0:
44
+ # Try different parameter formats for Tavily
45
+ try:
46
  result = tavily_tools[0].call({"input": query})
47
+ except Exception:
48
+ try:
49
+ result = tavily_tools[0].call({"query": query})
50
+ except Exception:
51
+ result = tavily_tools[0].call(query)
52
+ return f"Web Search Results for '{query}':\n{str(result)}"
53
+ return "Web search tool not available"
 
 
 
 
 
54
  except Exception as e:
55
+ print(f"Web search failed: {e}")
56
+ return f"Web search not available: {str(e)}"
57
+
58
+ def wikipedia_search(query: str) -> str:
59
+ """Search Wikipedia for information"""
60
  try:
61
+ with tool_span("wikipedia_search", metadata={"query": query}):
62
+ from tools import get_wikipedia_tool
63
+ wiki_tool = get_wikipedia_tool()
64
+ if wiki_tool:
65
+ # Try different parameter formats for Wikipedia
66
  try:
67
+ result = wiki_tool.call({"query_str": query})
68
+ except Exception:
69
+ try:
70
+ result = wiki_tool.call({"input": query})
71
+ except Exception:
72
+ try:
73
+ result = wiki_tool.call({"query": query})
74
+ except Exception:
75
+ result = wiki_tool.call(query)
76
+ return f"Wikipedia Results for '{query}':\n{str(result)}"
77
+ return "Wikipedia tool not available"
 
78
  except Exception as e:
79
+ print(f"Wikipedia search failed: {e}")
80
+ return f"Wikipedia search not available: {str(e)}"
81
+
82
+ def arxiv_search(query: str) -> str:
83
+ """Search ArXiv for academic papers"""
84
  try:
85
+ with tool_span("arxiv_search", metadata={"query": query}):
86
+ from tools import get_arxiv_tool
87
+ arxiv_tool = get_arxiv_tool()
88
+ if arxiv_tool:
89
+ # Try different parameter formats for ArXiv
90
  try:
91
+ result = arxiv_tool.call({"query_str": query})
92
+ except Exception:
93
+ try:
94
+ result = arxiv_tool.call({"input": query})
95
+ except Exception:
96
+ try:
97
+ result = arxiv_tool.call({"query": query})
98
+ except Exception:
99
+ result = arxiv_tool.call(query)
100
+ return f"ArXiv Results for '{query}':\n{str(result)}"
101
+ return "ArXiv tool not available"
 
102
  except Exception as e:
103
+ print(f"ArXiv search failed: {e}")
104
+ return f"ArXiv search not available: {str(e)}"
105
 
106
+ # Add a simple fallback research function that doesn't use external APIs
107
+ def fallback_research(query: str) -> str:
108
+ """Provide basic context when external tools fail"""
109
+ return f"""
110
+ Fallback Research for '{query}':
111
+
112
+ This research uses general knowledge available in the system.
113
+ For comprehensive research, external API access (Tavily, Wikipedia) would be needed.
114
+
115
+ Basic information may be available through the language model's training data,
116
+ but current information would require working API connections.
117
+ """
118
 
119
+ return [web_search, wikipedia_search, arxiv_search, fallback_research]
 
120
 
121
 
122
  def load_research_prompt() -> str:
 
141
  - Cross-reference information across sources
142
  - Note any conflicting information found
143
 
144
+ Important: You have access to research functions, but you cannot call them directly.
145
+ Instead, specify what searches you would like to perform and the system will execute them for you.
146
+
147
  Format your response as:
148
+ ### Research Strategy
149
+ [Describe what searches are needed]
150
+
151
+ ### Analysis
152
+ [Analyze the information once gathered]
153
 
154
  ### Key Facts
155
  - Fact 1
156
+ - Fact 2
157
  - Fact 3
158
 
159
  ### Citations
 
162
  """
163
 
164
 
165
+ def perform_research_searches(query: str, research_functions: List[callable]) -> str:
166
+ """
167
+ Intelligently perform research searches based on the query
168
+ """
169
+ results = []
170
+
171
+ # Always try web search first for current info
172
+ web_search, wikipedia_search, arxiv_search, fallback_research = research_functions
173
+
174
+ print("🌐 Performing web search...")
175
+ web_result = web_search(query)
176
+ results.append(web_result)
177
+
178
+ # Try Wikipedia for encyclopedic info
179
+ print("πŸ“š Performing Wikipedia search...")
180
+ wiki_result = wikipedia_search(query)
181
+ results.append(wiki_result)
182
+
183
+ # For academic/technical queries, try ArXiv
184
+ academic_keywords = ['research', 'study', 'paper', 'algorithm', 'model', 'theory', 'analysis']
185
+ if any(keyword in query.lower() for keyword in academic_keywords):
186
+ print("πŸŽ“ Performing ArXiv search...")
187
+ arxiv_result = arxiv_search(query)
188
+ results.append(arxiv_result)
189
+
190
+ # Check if we got meaningful results, if not, use fallback
191
+ meaningful_results = []
192
+ for result in results:
193
+ if result and not ("not available" in result or "error" in result.lower()):
194
+ meaningful_results.append(result)
195
+
196
+ # If no meaningful results, add fallback research
197
+ if not meaningful_results:
198
+ print("πŸ”„ Using fallback research...")
199
+ fallback_result = fallback_research(query)
200
+ results.append(fallback_result)
201
+
202
+ return "\n\n---\n\n".join(results)
203
+
204
+
205
  def research_agent(state: Dict[str, Any]) -> Command:
206
  """
207
  Research Agent node that gathers information using available tools.
 
215
  # Get research prompt
216
  research_prompt = load_research_prompt()
217
 
218
+ # Initialize LLM without tool binding (we'll call tools manually)
219
  llm = ChatGroq(
220
  model="llama-3.3-70b-versatile",
221
  temperature=0.3, # Slightly higher for research creativity
222
  max_tokens=2048
223
  )
224
 
225
+ # Get research functions
226
+ research_functions = create_research_functions()
 
 
 
 
 
 
 
227
 
228
  # Create agent span for tracing
229
  with agent_span(
230
  "research",
231
  metadata={
232
+ "tools_available": len(research_functions),
233
  "user_id": state.get("user_id", "unknown"),
234
  "session_id": state.get("session_id", "unknown")
235
  }
 
243
  user_query = msg.content
244
  break
245
 
246
+ # Perform actual research searches
247
+ print(f"πŸ” Researching: {user_query}")
248
+ research_raw_results = perform_research_searches(user_query, research_functions)
249
+
250
+ # Now ask LLM to analyze and structure the results
251
+ analysis_request = f"""
252
+ Based on the research results below, provide a structured analysis to help answer the user's question.
253
+
254
+ Original Question: {user_query}
255
 
256
+ Research Results:
257
+ {research_raw_results}
258
 
259
  Current research status: {len(state.get('research_notes', ''))} characters already gathered
260
 
261
  Instructions:
262
+ 1. Analyze the search results for relevant information
263
+ 2. Extract key facts that help answer the question
264
+ 3. Note any important details or findings
265
+ 4. Identify if additional specific searches might be needed
266
+ 5. Structure your findings clearly with citations
267
 
268
+ Please provide a comprehensive analysis of the research findings.
269
  """
270
 
271
+ # Create messages for analysis
272
+ analysis_messages = [
273
  SystemMessage(content=research_prompt),
274
+ HumanMessage(content=analysis_request)
275
  ]
276
 
277
+ # Get analysis response
278
+ response = llm.invoke(analysis_messages)
279
+ analysis_content = response.content if hasattr(response, 'content') else str(response)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
  # Format research results
282
  formatted_results = f"""
283
  ### Research Iteration {state.get('loop_counter', 0) + 1}
284
 
285
+ {analysis_content}
286
+
287
+ ### Raw Search Results
288
+ {research_raw_results}
289
 
290
  ---
291
  """