Vinay Kerai commited on
Commit
d3dc6dc
·
1 Parent(s): cd3c1e5

simple react agent

Browse files
Files changed (3) hide show
  1. agent.py +108 -0
  2. app.py +13 -87
  3. system_prompt.txt +8 -0
agent.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from dotenv import load_dotenv
3
+
4
+ from langchain_core.tools import Tool, tool
5
+ from langchain_core.messages import AnyMessage, HumanMessage, SystemMessage
6
+ from langgraph.prebuilt import create_react_agent
7
+ #from langgraph.graph import START, StateGraph
8
+ #from langgraph.prebuilt import tools_condition, create_react_agent
9
+ from langchain_community.tools import DuckDuckGoSearchRun
10
+ from langchain_experimental.utilities import PythonREPL
11
+ from langchain_google_genai import ChatGoogleGenerativeAI
12
+ from langchain_ollama import ChatOllama
13
+ from langfuse.langchain import CallbackHandler
14
+
15
+ load_dotenv()
16
+ langfuse_handler = CallbackHandler()
17
+
18
+ # --- LLM ---
19
+ #llm = ChatOllama(model="qwen3:8b", temperature=0)
20
+ llm = ChatGoogleGenerativeAI(model='gemini-2.5-flash', temperature=0)
21
+
22
+ # --- System Prompt ---
23
+ with open('system_prompt.txt', 'r', encoding='utf-8') as f:
24
+ system_prompt = f.read()
25
+
26
+ # --- Tools ---
27
+
28
+ @tool
29
+ def search_web(query: str) -> str:
30
+ """
31
+ A tool to perform a search for a query using the web
32
+
33
+ Args:
34
+ query (str): query to search on the web
35
+
36
+ Returns:
37
+ str: web search result
38
+ """
39
+ try:
40
+ search = DuckDuckGoSearchRun()
41
+ search.invoke(query)
42
+ except Exception as e:
43
+ return f"An error occured using search_web tool: {e}"
44
+
45
+ # python REPL tool
46
+ python_repl = PythonREPL()
47
+ repl_tool = Tool(
48
+ name="python_repl",
49
+ description="A Python shell. Use this to execute python commands. "
50
+ "Input should be a valid python command. "
51
+ "If you want to see the output of a value, you should print it out with `print(...)`.",
52
+ func=python_repl.run,
53
+ )
54
+
55
+ @tool
56
+ def reverse_string(text: str) -> str:
57
+ """
58
+ Reverse the order of characters in a text string
59
+
60
+ Args:
61
+ text (str): text string to reverse
62
+
63
+ Returns:
64
+ str: reversed text string
65
+ """
66
+ try:
67
+ return text[::-1]
68
+ except Exception as e:
69
+ return f"An error occured using reverse_string tool: {e}"
70
+
71
+
72
+ tools = [search_web, reverse_string, repl_tool]
73
+
74
+ # --- LangGraph ---
75
+ agent = create_react_agent(
76
+ model=llm,
77
+ tools=tools,
78
+ prompt=system_prompt
79
+ )
80
+
81
+ class GAIAAgent:
82
+ def __init__(self):
83
+ print("GAIAAgent initialized.")
84
+
85
+ def __call__(self, question: str) -> str:
86
+ print(f"Agent received question: {question}")
87
+
88
+ messages = agent.invoke(
89
+ {"messages": [
90
+ #SystemMessage(content=system),
91
+ HumanMessage(content=question)
92
+ ]},
93
+ config={
94
+ "callbacks": [langfuse_handler],
95
+ "recursion_limit": 10
96
+ }
97
+ )
98
+
99
+ # extract answer
100
+ final_message = messages['messages'][-1].content
101
+ match = re.search(r"(?<=FINAL ANSWER:\s).*", final_message)
102
+ if match:
103
+ final_answer = match.group(0)
104
+ else:
105
+ final_answer = f"I don't know\n'{final_message}'"
106
+
107
+ print(f"Agent returning answer: {final_answer}")
108
+ return final_answer
app.py CHANGED
@@ -1,18 +1,9 @@
1
  import os
2
- import re
3
  import gradio as gr
4
  import requests
5
- import inspect
6
  import pandas as pd
7
 
8
- from typing import TypedDict, Annotated
9
- from langgraph.graph.message import add_messages
10
- from langchain_core.messages import AnyMessage, HumanMessage, AIMessage, SystemMessage
11
- from langgraph.prebuilt import ToolNode
12
- from langgraph.graph import START, StateGraph
13
- from langgraph.prebuilt import tools_condition
14
- from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace
15
- from langchain_community.tools import DuckDuckGoSearchRun
16
 
17
  # (Keep Constants as is)
18
  # --- Constants ---
@@ -20,83 +11,6 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
20
 
21
  # --- Basic Agent Definition ---
22
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
23
-
24
- # Generate the AgentState and Agent graph
25
- class AgentState(TypedDict):
26
- messages: Annotated[list[AnyMessage], add_messages]
27
-
28
- # --- Agent ---
29
- class GAIAAgent:
30
- # --- LLM ---
31
- llm = HuggingFaceEndpoint(
32
- repo_id="Qwen/Qwen2.5-Coder-32B-Instruct"
33
- )
34
- chat = ChatHuggingFace(llm=llm, verbose=True)
35
-
36
- # --- Tools ---
37
- search_tool = DuckDuckGoSearchRun()
38
- tools = [search_tool]
39
-
40
- # --- System Prompt ---
41
- system = """
42
- You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your
43
- answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. YOUR FINAL ANSWER should
44
- be a number OR as few words as possible OR a comma separated list of numbers and/or strings. If
45
- you are asked for a number, don't use comma to write your number neither use units such as $ or
46
- percent sign unless specified otherwise. If you are asked for a string, don't use articles,
47
- neither abbreviations (e.g. for cities), and write the digits in plain text unless specified
48
- otherwise. If you are asked for a comma separated list, apply the above rules depending of
49
- whether the element to be put in the list is a number or a string.
50
- """.replace('\n', '')
51
-
52
- def __init__(self):
53
- self.build_graph()
54
- print("GAIAAgent initialized.")
55
-
56
- def build_graph(self):
57
- self.chat_with_tools = self.chat.bind_tools(self.tools)
58
-
59
- builder = StateGraph(AgentState)
60
-
61
- def assistant(state: AgentState):
62
- return {
63
- "messages": [self.chat_with_tools.invoke(state["messages"])],
64
- }
65
-
66
- # Define nodes: these do the work
67
- builder.add_node("assistant", assistant)
68
- builder.add_node("tools", ToolNode(self.tools))
69
-
70
- # Define edges: these determine how the control flow moves
71
- builder.add_edge(START, "assistant")
72
- builder.add_conditional_edges(
73
- "assistant",
74
- # If the latest message requires a tool, route to tools
75
- # Otherwise, provide a direct response
76
- tools_condition,
77
- )
78
- builder.add_edge("tools", "assistant")
79
- self.graph = builder.compile()
80
-
81
- def __call__(self, question: str) -> str:
82
- print(f"Agent received question (first 50 chars): {question[:50]}...")
83
-
84
- answer = self.graph.invoke(
85
- {"messages": [
86
- SystemMessage(content=self.system),
87
- HumanMessage(content=question)
88
- ]})
89
-
90
- # extract answer
91
- match = re.search(r"(?<=FINAL ANSWER:\s).*", answer)
92
- if match:
93
- final_answer = match.group(0)
94
- else:
95
- final_answer = "I don't know"
96
-
97
- print(f"Agent returning answer: {final_answer}")
98
- return final_answer
99
-
100
  class BasicAgent:
101
  def __init__(self):
102
  print("BasicAgent initialized.")
@@ -163,9 +77,21 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
163
  for item in questions_data:
164
  task_id = item.get("task_id")
165
  question_text = item.get("question")
 
166
  if not task_id or question_text is None:
167
  print(f"Skipping item with missing task_id or question: {item}")
168
  continue
 
 
 
 
 
 
 
 
 
 
 
169
  try:
170
  submitted_answer = agent(question_text)
171
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
 
1
  import os
 
2
  import gradio as gr
3
  import requests
 
4
  import pandas as pd
5
 
6
+ from agent import GAIAAgent
 
 
 
 
 
 
 
7
 
8
  # (Keep Constants as is)
9
  # --- Constants ---
 
11
 
12
  # --- Basic Agent Definition ---
13
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  class BasicAgent:
15
  def __init__(self):
16
  print("BasicAgent initialized.")
 
77
  for item in questions_data:
78
  task_id = item.get("task_id")
79
  question_text = item.get("question")
80
+ file_name = item.get("file_name")
81
  if not task_id or question_text is None:
82
  print(f"Skipping item with missing task_id or question: {item}")
83
  continue
84
+ if file_name:
85
+ # if question has an attached file, add the URL to the question prompt
86
+ file_url = f"{api_url}/files/{task_id}"
87
+ question_text += f'\nFile URL: "{file_url}"'
88
+
89
+ # add file type to prompt also
90
+ try:
91
+ ext = file_name.split('.')[-1]
92
+ question_text += f" (.{ext} file)"
93
+ except Exception as e:
94
+ print(f"Error getting file extension on {task_id}: {e}")
95
  try:
96
  submitted_answer = agent(question_text)
97
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
system_prompt.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template:
2
+
3
+ FINAL ANSWER: [YOUR FINAL ANSWER].
4
+
5
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
6
+ 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.
7
+ If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
8
+ If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.