Tomkuijpers2232 commited on
Commit
170232b
·
verified ·
1 Parent(s): 81917a3

Upload agent.py

Browse files
Files changed (1) hide show
  1. agent.py +157 -0
agent.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ from typing import TypedDict, Annotated
4
+ from langgraph.graph import START, StateGraph, MessagesState
5
+ from langgraph.graph.message import add_messages
6
+ from langchain_core.messages import AnyMessage, HumanMessage, AIMessage, SystemMessage
7
+ from langgraph.prebuilt import ToolNode
8
+ from langgraph.graph import START, StateGraph
9
+ from langgraph.prebuilt import tools_condition
10
+ from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace
11
+ from langchain_core.tools import tool
12
+ from langchain_community.document_loaders import WikipediaLoader
13
+ from langchain_google_genai import ChatGoogleGenerativeAI
14
+ from langchain_community.tools import DuckDuckGoSearchRun
15
+
16
+ load_dotenv()
17
+
18
+ # ReAct System Prompt
19
+ REACT_SYSTEM_PROMPT = """You are a helpful assistant tasked with answering questions using a set of tools.
20
+
21
+ You use the ReAct (Reasoning and Acting) methodology to solve problems.
22
+
23
+ For each user query, you should:
24
+ 1. **Thought**: Think step by step about what you need to do to answer the question
25
+ 2. **Action**: Use the appropriate tool(s) to gather information or perform calculations
26
+ 3. **Observation**: Analyze the results from your actions
27
+ 4. Repeat the Thought-Action-Observation cycle as needed until you have enough information to provide a complete answer
28
+
29
+ When you need to use tools:
30
+ - Think about which tool is most appropriate for the task
31
+ - Use tools to gather information or perform calculations
32
+ - Analyze the results and determine if you need additional information
33
+ - Continue until you can provide a comprehensive answer
34
+
35
+ Available tools:
36
+ - multiply, add, subtract, divide: For mathematical calculations
37
+ - wikidata_search: Search Wikipedia for factual information
38
+ - duckduckgo_search: Search the web for current information
39
+
40
+ Now, I will ask you a question. Report your thoughts, and finish your answer with the following template:
41
+ FINAL ANSWER: [YOUR FINAL ANSWER].
42
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings. 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. 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. 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.
43
+ Your answer should only start with "FINAL ANSWER: ", then follows with the answer.
44
+
45
+ Always explain your reasoning process and show your work step by step."""
46
+
47
+ @tool
48
+ def multiply(a:int, b:int) -> int:
49
+ """
50
+ Multiply two numbers
51
+ """
52
+ return a * b
53
+
54
+ @tool
55
+ def add(a:int, b:int) -> int:
56
+ """
57
+ Add two numbers
58
+ """
59
+ return a + b
60
+
61
+ @tool
62
+ def subtract(a:int, b:int) -> int:
63
+ """
64
+ Subtract two numbers
65
+ """
66
+ return a - b
67
+
68
+ @tool
69
+ def divide(a:int, b:int) -> int:
70
+ """
71
+ Divide two numbers
72
+ """
73
+ return a / b
74
+
75
+ @tool
76
+ def wikidata_search(query: str) -> str:
77
+ """
78
+ Search for information on Wikipedia and return maximum 2 results.
79
+
80
+ Args:
81
+ query: The search query.
82
+ """
83
+ loader = WikipediaLoader(query=query, load_max_docs=2)
84
+ docs = loader.load()
85
+ formatted_search_docs = "\n\n---\n\n".join(
86
+ [
87
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
88
+ for doc in docs
89
+ ])
90
+ return {"wiki_results": formatted_search_docs}
91
+
92
+ @tool
93
+ def duckduckgo_search(query: str) -> str:
94
+ """
95
+ Search for information on DuckDuckGo and return maximum 3 results.
96
+
97
+ Args:
98
+ query: The search query.
99
+ """
100
+ search = DuckDuckGoSearchRun()
101
+ # DuckDuckGo returns a string, so we need to format it differently
102
+ results = search.run(query)
103
+ formatted_search_docs = f'<Document source="DuckDuckGo Search" page=""/>\n{results}\n</Document>'
104
+ return {"web_results": formatted_search_docs}
105
+
106
+ tools = [multiply, add, subtract, divide, wikidata_search, duckduckgo_search]
107
+
108
+ def build_graph():
109
+ llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", api_key=os.getenv("GOOGLE_API_KEY"))
110
+ llm_with_tools = llm.bind_tools(tools)
111
+
112
+ def agent_node(state: MessagesState) -> MessagesState:
113
+ """This is the agent node with ReAct methodology"""
114
+ messages = state["messages"]
115
+
116
+ # Add system prompt if not already present
117
+ if not messages or not isinstance(messages[0], SystemMessage):
118
+ messages = [SystemMessage(content=REACT_SYSTEM_PROMPT)] + messages
119
+
120
+ return {"messages": [llm_with_tools.invoke(messages)]}
121
+
122
+
123
+
124
+ builder = StateGraph(MessagesState)
125
+ builder.add_node("agent", agent_node)
126
+ builder.add_node("tools", ToolNode(tools))
127
+
128
+
129
+ builder.add_edge(START, "agent")
130
+ builder.add_conditional_edges("agent", tools_condition)
131
+ builder.add_edge("tools", "agent")
132
+
133
+ return builder.compile()
134
+
135
+ class LangGraphAgent:
136
+ def __init__(self):
137
+ self.graph = build_graph()
138
+ print("LangGraphAgent initialized with tools.")
139
+
140
+ def __call__(self, question: str) -> str:
141
+ """Run the agent on a question and return the answer"""
142
+ try:
143
+ messages = [HumanMessage(content=question)]
144
+ result = self.graph.invoke({"messages": messages})
145
+ for m in result["messages"]:
146
+ m.pretty_print()
147
+ return result["messages"][-1].content
148
+ except Exception as e:
149
+ return f"Error: {str(e)}"
150
+
151
+ if __name__ == "__main__":
152
+ agent = LangGraphAgent()
153
+ question = ".rewsna eht sa \"tfel\" drow eht fo etisoppo eht etirw ,ecnetnes siht dnatsrednu uoy fI"
154
+ answer = agent(question)
155
+
156
+
157
+