samoye16 commited on
Commit
189c56c
·
verified ·
1 Parent(s): 81917a3

Create agents.py

Browse files
Files changed (1) hide show
  1. agents.py +140 -0
agents.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+
4
+ from langgraph.graph import StateGraph, START, MessagesState
5
+ from langgraph.prebuilt import ToolNode, tools_condition
6
+
7
+ from langchain_google_genai import ChatGoogleGenerativeAI
8
+ from langchain_groq import ChatGroq
9
+ from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint, HuggingFaceEmbeddings
10
+
11
+ from langchain_community.tools.tavily_search import TavilySearchResults
12
+ from langchain_community.document_loaders import WikipediaLoader, ArxivLoader
13
+ from langchain_community.vectorstores import SupabaseVectorStore
14
+
15
+ from langchain_core.messages import SystemMessage, HumanMessage
16
+ from langchain_core.tools import tool
17
+ from langchain.tools.retriever import create_retriever_tool
18
+
19
+ from supabase.client import create_client, Client
20
+
21
+
22
+ # Load environment variables
23
+ load_dotenv()
24
+
25
+
26
+ # ---- Basic Arithmetic Utilities ---- #
27
+ @tool
28
+ def multiply(a: int, b: int) -> int:
29
+ """Returns the product of two integers."""
30
+ return a * b
31
+
32
+ @tool
33
+ def add(a: int, b: int) -> int:
34
+ """Returns the sum of two integers."""
35
+ return a + b
36
+
37
+ @tool
38
+ def subtract(a: int, b: int) -> int:
39
+ """Returns the difference between two integers."""
40
+ return a - b
41
+
42
+ @tool
43
+ def divide(a: int, b: int) -> float:
44
+ """Performs division and handles zero division errors."""
45
+ if b == 0:
46
+ raise ValueError("Division by zero is undefined.")
47
+ return a / b
48
+
49
+ @tool
50
+ def modulus(a: int, b: int) -> int:
51
+ """Returns the remainder after division."""
52
+ return a % b
53
+
54
+
55
+ # ---- Search Tools ---- #
56
+ @tool
57
+ def search_wikipedia(query: str) -> str:
58
+ """Returns up to 2 documents related to a query from Wikipedia."""
59
+ docs = WikipediaLoader(query=query, load_max_docs=2).load()
60
+ return {"wiki_results": "\n\n---\n\n".join(
61
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}'
62
+ for doc in docs
63
+ )}
64
+
65
+ @tool
66
+ def search_web(query: str) -> str:
67
+ """Fetches up to 3 web results using Tavily."""
68
+ results = TavilySearchResults(max_results=3).invoke(query=query)
69
+ return {"web_results": "\n\n---\n\n".join(
70
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}'
71
+ for doc in results
72
+ )}
73
+
74
+ @tool
75
+ def search_arxiv(query: str) -> str:
76
+ """Retrieves up to 3 papers related to the query from ArXiv."""
77
+ results = ArxivLoader(query=query, load_max_docs=3).load()
78
+ return {"arvix_results": "\n\n---\n\n".join(
79
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content[:1000]}'
80
+ for doc in results
81
+ )}
82
+
83
+
84
+ system_message = SystemMessage(content="""You are a helpful assistant tasked with answering questions using a set of tools. Now, I will ask you a question. Report your thoughts, and finish your answer with the following template:
85
+
86
+ FINAL ANSWER: [YOUR FINAL ANSWER]
87
+
88
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma-separated list of numbers and/or strings.
89
+ - If you are asked for a number, don't use a comma in the number and avoid units like $ or % unless specified otherwise.
90
+ - If you are asked for a string, avoid using articles and abbreviations (e.g. for cities), and write digits in plain text unless specified otherwise.
91
+ - If you are asked for a comma-separated list, apply the above rules depending on whether each item is a number or string.
92
+
93
+ Your answer should start only with "Responce: ", followed by your result.""")
94
+
95
+ toolset = [
96
+ multiply,
97
+ add,
98
+ subtract,
99
+ divide,
100
+ modulus,
101
+ search_wikipedia,
102
+ search_web,
103
+ search_arxiv,
104
+ ]
105
+
106
+
107
+ # ---- Graph Construction ---- #
108
+ def create_agent_flow(provider: str = "groq"):
109
+ """Constructs the LangGraph conversational flow with tool support."""
110
+
111
+ if provider == "google":
112
+ llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", temperature=0)
113
+ elif provider == "groq":
114
+ llm = ChatGroq(model="qwen-qwq-32b", temperature=0)
115
+ elif provider == "huggingface":
116
+ llm = ChatHuggingFace(llm=HuggingFaceEndpoint(
117
+ url="https://api-inference.huggingface.co/models/Meta-DeepLearning/llama-2-7b-chat-hf",
118
+ temperature=0
119
+ ))
120
+ else:
121
+ raise ValueError("Unsupported provider. Choose from: 'google', 'groq', 'huggingface'.")
122
+
123
+ llm_toolchain = llm.bind_tools(toolset)
124
+
125
+ # Assistant node behavior
126
+ def assistant_node(state: MessagesState):
127
+ response = llm_toolchain.invoke(state["messages"])
128
+ return {"messages": [response]}
129
+
130
+
131
+ # Build the conversational graph
132
+ graph = StateGraph(MessagesState)
133
+ graph.add_node("assistant", assistant_node)
134
+ graph.add_node("tools", ToolNode(toolset))
135
+ graph.add_edge(START, "retriever")
136
+ graph.add_edge("retriever", "assistant")
137
+ graph.add_conditional_edges("assistant", tools_condition)
138
+ graph.add_edge("tools", "assistant")
139
+
140
+ return graph.compile()