sqfoo commited on
Commit
806226d
·
verified ·
1 Parent(s): ea366ea

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +93 -81
agent.py CHANGED
@@ -2,11 +2,12 @@ import os
2
  from dotenv import load_dotenv
3
  from typing import TypedDict, List, Dict, Any, Optional
4
  from langgraph.graph import StateGraph, START, END, MessagesState
5
- from langchain.agents import create_tool_calling_agent, AgentExecutor, initialize_agent, create_react_agent
6
  from langchain_google_genai import ChatGoogleGenerativeAI
7
  from langchain_groq import ChatGroq
8
  from langchain_core.tools import tool
9
  from langchain_core.messages import HumanMessage, SystemMessage
 
10
  from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
11
  from langgraph.prebuilt import ToolNode
12
  from langgraph.prebuilt import tools_condition
@@ -237,19 +238,7 @@ def divide(a: float, b: float) -> float:
237
  # - subtract: Subtract A by B with passing A as the first argument
238
  # - divide: Divide A by B with passing A as the first argument
239
 
240
- # You have access to the following tools:
241
- # - serper_websearch: web search the content of the query by passing the query as input with Serper Search Engine
242
- # - duckduck_websearch: web search the content of the query by passing the query as input with DuckDuckGo Search Engine
243
- # - visit_webpage: visit the given webpage url by passing the url as input
244
- # - wiki_search: wiki search the content of the query by passing the query as input if the question asks for wiki search it
245
- # - text_splitter: split text into chunks
246
- # - youtube_transcript: fetch the transcript of the Youtube video by passing the video url as input if the question asks for watching a Youtube video
247
- # - read_file: read the content of the attached file by passing the TASK-ID as input
248
- # - excel_read: read the content of the attached excel file by passing the TASK-ID as input
249
- # - csv_read: read the content of the attached csv file by passing the TASK-ID as input
250
- # - mp3_listen: listen to the content of the attached mp3 file by passing the TASK-ID as input
251
- # - image_caption: understand the visual content of the attached image by passing the TASK-ID as input
252
- # - run_python: run the python code
253
 
254
  # ("human", f"Question: {question}\nReport to validate: {final_answer}")
255
  class BasicAgent:
@@ -257,21 +246,10 @@ class BasicAgent:
257
  self.model = ChatGoogleGenerativeAI(
258
  model="gemini-2.0-flash-lite",
259
  temperature=0,
260
- max_tokens=128,
261
- timeout=None,
262
- max_retries=2,
263
  google_api_key=os.getenv("GEMINI_API_KEY"),
264
- # other params...
265
  )
266
- # self.model = ChatGroq(
267
- # model="qwen-qwq-32b",
268
- # temperature=0,
269
- # max_tokens=128,
270
- # timeout=None,
271
- # max_retries=2,
272
- # groq_api_key=os.getenv("GROQ_API_KEY")
273
- # # other params...
274
- # )
275
  # System Prompt for few shot prompting
276
  self.sys_prompt = """"
277
  You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template:
@@ -282,48 +260,44 @@ class BasicAgent:
282
  If you are asked for a comma separated list, apply the above rules depending of whether the element to put in the list is a number or a string.
283
 
284
  You have access to the following tools:
285
- {tools}
286
- Here are the tools you can use: {tool_names}
 
 
 
 
 
 
 
 
 
 
 
287
  If Task ID is included in the question, remember to call the relevant read tools [ie. read_file, excel_read, csv_read, mp3_listen, image_caption]
288
  Note: python_tool is called when the question mentions the term "Python" or any math calculation.
289
-
290
- Follow this format in your response:
291
- THOUGHT: [Describe your reasoning here]
292
- ACTION: [Specify the action/tool to use and any relevant input]
293
- OBSERVATIOn: [Result of the action/tool, provided by the system]
294
- FINAL ANSWER: [Provide your final response to the user]
295
-
296
- User Input: {input}
297
- {agent_scratchpad}
298
  """
299
  self.tools = [duckduck_websearch, serper_websearch, visit_webpage, wiki_search, text_splitter, youtube_transcript, read_file, excel_read, csv_read, mp3_listen, image_caption, run_python]
300
- # self.model_with_tools = self.model.bind_tools(self.tools)
301
- # self.sys_msg = SystemMessage(content=self.sys_prompt)
302
-
 
 
 
303
  # self.prompt = ChatPromptTemplate.from_messages([
304
  # ("system", self.sys_prompt),
305
  # ("human", "{input}")
306
  # ])
307
- self.prompt = PromptTemplate(
308
- input_variables=["input", "tools", "tool_names", "agent_scratchpad"],
309
- template=self.sys_prompt
310
- )
311
  # self.agent = initialize_agent(
312
  # tools=self.tools,
313
  # llm=self.model,
314
  # agent="zero-shot-react-description", # ReAct agent type
315
  # verbose=True,
316
  # system_prompt=self.prompt,
317
- # handle_parsing_errors="Check your output and make sure it conforms, use the Action/Action Input syntax"
 
 
318
  # )
319
- self.agent = create_react_agent(
320
- llm=self.model,
321
- tools=self.tools,
322
- prompt=self.prompt
323
- )
324
- self.agent_exe = AgentExecutor(agent=self.agent, tools=self.tools, verbose=True,
325
- handle_parsing_errors="Check your output and make sure it conforms, use the Action/Action Input syntax")
326
- # self.graph = self.__graph_compile__()
327
  print("BasicAgent initialized.")
328
 
329
  def __call__(self, task: dict) -> str:
@@ -335,33 +309,71 @@ class BasicAgent:
335
  else:
336
  question = f"{question} with TASK-ID: {task_id}"
337
  # fixed_answer = self.agent.run(f'{question} with TASK-ID: {task_id}')
338
- # fixed_answer = "This is a default answer."
339
- # fixed_answer = self.agent.run(question)
340
- fixed_answer = self.agent_exe.invoke({"input": question})
341
- # human_message = [HumanMessage(content=question)]
342
- # messages = self.graph.invoke({"messages": human_message})
343
- # fixed_answer = messages['messages'][-1].content
344
- print(f"Agent returning fixed answer: {fixed_answer}")
345
- time.sleep(60)
 
 
 
 
 
 
 
 
 
 
346
  return fixed_answer
347
 
348
- def __graph_compile__(self):
349
- def assistant(state: MessagesState):
350
- """Assistant Node"""
351
- return {"message": [self.model_with_tools.invoke(state["messages"])]}
352
-
353
- builder = StateGraph(MessagesState)
354
- builder.add_node("assistant", assistant)
355
- builder.add_node("tools", ToolNode(self.tools))
356
- builder.add_edge(START, "assistant")
357
- builder.add_conditional_edges(
358
- "assistant",
359
- # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools
360
- # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END
361
- tools_condition,
362
- )
363
- builder.add_edge("tools", "assistant")
364
- # Compile graph
365
- return builder.compile()
366
 
367
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from dotenv import load_dotenv
3
  from typing import TypedDict, List, Dict, Any, Optional
4
  from langgraph.graph import StateGraph, START, END, MessagesState
5
+ from langchain.agents import create_tool_calling_agent, ConversationalAgent, AgentExecutor, initialize_agent, create_react_agent
6
  from langchain_google_genai import ChatGoogleGenerativeAI
7
  from langchain_groq import ChatGroq
8
  from langchain_core.tools import tool
9
  from langchain_core.messages import HumanMessage, SystemMessage
10
+ from langchain.memory import ConversationBufferMemory
11
  from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
12
  from langgraph.prebuilt import ToolNode
13
  from langgraph.prebuilt import tools_condition
 
238
  # - subtract: Subtract A by B with passing A as the first argument
239
  # - divide: Divide A by B with passing A as the first argument
240
 
241
+
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
  # ("human", f"Question: {question}\nReport to validate: {final_answer}")
244
  class BasicAgent:
 
246
  self.model = ChatGoogleGenerativeAI(
247
  model="gemini-2.0-flash-lite",
248
  temperature=0,
249
+ max_tokens=1024,
250
+ candidate_count=1,
 
251
  google_api_key=os.getenv("GEMINI_API_KEY"),
 
252
  )
 
 
 
 
 
 
 
 
 
253
  # System Prompt for few shot prompting
254
  self.sys_prompt = """"
255
  You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template:
 
260
  If you are asked for a comma separated list, apply the above rules depending of whether the element to put in the list is a number or a string.
261
 
262
  You have access to the following tools:
263
+ - serper_websearch: web search the content of the query by passing the query as input with Serper Search Engine
264
+ - duckduck_websearch: web search the content of the query by passing the query as input with DuckDuckGo Search Engine
265
+ - visit_webpage: visit the given webpage url by passing the url as input
266
+ - wiki_search: wiki search the content of the query by passing the query as input if the question asks for wiki search it
267
+ - text_splitter: split text into chunks
268
+ - youtube_transcript: fetch the transcript of the Youtube video by passing the video url as input if the question asks for watching a Youtube video
269
+ - read_file: read the content of the attached file by passing the TASK-ID as input
270
+ - excel_read: read the content of the attached excel file by passing the TASK-ID as input
271
+ - csv_read: read the content of the attached csv file by passing the TASK-ID as input
272
+ - mp3_listen: listen to the content of the attached mp3 file by passing the TASK-ID as input
273
+ - image_caption: understand the visual content of the attached image by passing the TASK-ID as input
274
+ - run_python: run the python code
275
+
276
  If Task ID is included in the question, remember to call the relevant read tools [ie. read_file, excel_read, csv_read, mp3_listen, image_caption]
277
  Note: python_tool is called when the question mentions the term "Python" or any math calculation.
 
 
 
 
 
 
 
 
 
278
  """
279
  self.tools = [duckduck_websearch, serper_websearch, visit_webpage, wiki_search, text_splitter, youtube_transcript, read_file, excel_read, csv_read, mp3_listen, image_caption, run_python]
280
+ # Setup memory
281
+ self.memory = ConversationBufferMemory(
282
+ memory_key="chat_history",
283
+ return_messages=True
284
+ )
285
+ self.agent = self.__setup__agent__()
286
  # self.prompt = ChatPromptTemplate.from_messages([
287
  # ("system", self.sys_prompt),
288
  # ("human", "{input}")
289
  # ])
290
+
 
 
 
291
  # self.agent = initialize_agent(
292
  # tools=self.tools,
293
  # llm=self.model,
294
  # agent="zero-shot-react-description", # ReAct agent type
295
  # verbose=True,
296
  # system_prompt=self.prompt,
297
+ # handle_parsing_errors=True,
298
+ # max_iterations=30
299
+ # # "Check your output and make sure it conforms, use the Action/Action Input syntax"
300
  # )
 
 
 
 
 
 
 
 
301
  print("BasicAgent initialized.")
302
 
303
  def __call__(self, task: dict) -> str:
 
309
  else:
310
  question = f"{question} with TASK-ID: {task_id}"
311
  # fixed_answer = self.agent.run(f'{question} with TASK-ID: {task_id}')
312
+ fixed_answer = "This is a default answer."
313
+
314
+
315
+ max_retries = 3
316
+ base_sleep = 1
317
+ for attempt in range(max_retries):
318
+ try:
319
+ fixed_answer = self.agent.run(question)
320
+ print(f"Agent returning fixed answer: {fixed_answer}")
321
+ time.sleep(60)
322
+ return fixed_answer
323
+ except Exception as e:
324
+ sleep_time = base_sleep * (attempt + 1)
325
+ if attempt < max_retries - 1:
326
+ print(f"Attempt {attempt + 1} failed. Retrying in {sleep_time} seconds...")
327
+ time.sleep(sleep_time)
328
+ continue
329
+ return f"Error processing query after {max_retries} attempts: {str(e)}"
330
  return fixed_answer
331
 
332
+ def __setup__agent__(self) -> AgentExecutor:
333
+ PREFIX = """
334
+ You are a general AI assistant that can use various tools to answer question. I will ask you a question. Report your thoughts, and finish your answer with the following template:
335
+ FINAL ANSWER: [YOUR FINAL ANSWER].
336
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separared list of numbers and/or strings.
337
+ If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
338
+ If you are asked for a string, don't use articles, neither abbreviations (eg. for cities), and write the digits in plain text unless specified otherwise.
339
+ If you are asked for a comma separated list, apply the above rules depending of whether the element to put in the list is a number or a string.
 
 
 
 
 
 
 
 
 
 
340
 
341
+ NOTE:
342
+ - If Task ID is included in the question, remember to call the relevant read tools [ie. read_file, excel_read, csv_read, mp3_listen, image_caption]
343
+ - python_tool is called when the question mentions the term "Python" or any math calculation.
344
+ """
345
+ FORMAT_INSTRUCTION = """
346
+ To use a tool, use the following format:
347
+ Thought: Do I need to use a tool? Yes
348
+ Action: the action to take, should be one of [{tool_names}]
349
+ Action Input: the input to the action
350
+ Observation: the result of the action
351
+ When you have a response to say to the Human, or if you do not need to use a tool, you MUST use the format:
352
+ Thought: Do I need to use a tool? No
353
+ Final Answer: [your response here]
354
+ Begin! Remember to ALWAYS include 'Thought:', 'Action:', 'Action Input:', and 'Final Answer:' in your responses.
355
+ """
356
+ SUFFIX = """
357
+ Previous conversation history:
358
+ {chat_history}
359
+ New question: {input}
360
+ {agent_scratchpad}
361
+ """
362
+ agent = ConversationalAgent.from_llm_and_tools(
363
+ llm=self.model,
364
+ tools=self.tools,
365
+ prefix=PREFIX,
366
+ format_instructions=FORMAT_INSTRUCTIONS,
367
+ suffix=SUFFIX,
368
+ input_variables=["input", "chat_history", "agent_scratchpad", "tool_names"],
369
+ handle_parsing_errors=True
370
+ )
371
+ return AgentExecutor.from_agent_and_tools(
372
+ agent=agent,
373
+ tools=self.tools,
374
+ memory=self.memory,
375
+ max_iterations=5,
376
+ verbose=True,
377
+ handle_parsing_errors=True,
378
+ return_only_outputs=True # This ensures we only get the final output
379
+ )