| |
| import os |
| from dotenv import load_dotenv |
| from typing import TypedDict, List, Dict, Any, Optional, Annotated |
|
|
| from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint, HuggingFaceEmbeddings |
|
|
| from langgraph.graph import StateGraph, MessagesState, START, END |
| from langgraph.graph.message import add_messages |
| from langchain_core.messages import SystemMessage, HumanMessage, AnyMessage, AIMessage |
| from langchain_core.messages.ai import subtract_usage |
|
|
| from langchain.tools import Tool |
| from langchain_core.tools import tool |
| from langchain_community.tools import WikipediaQueryRun |
| from langchain_community.utilities import WikipediaAPIWrapper |
| from langchain_community.utilities import SerpAPIWrapper |
| from langchain_community.utilities import ArxivAPIWrapper |
| from langchain_community.retrievers import BM25Retriever |
|
|
| from langgraph.prebuilt import ToolNode, tools_condition |
|
|
|
|
| |
| load_dotenv() |
| HUGGINGFACEHUB_API_TOKEN = os.getenv("HUGGINGFACEHUB_API_TOKEN") |
|
|
|
|
| |
| @tool |
| def add(a:int, b:int) -> int: |
| """add two numbers. |
| args: |
| a: first int |
| b: second int |
| """ |
| return a + b |
|
|
|
|
| @tool |
| def subtract(a:int, b:int) -> int: |
| """subtract two numbers. |
| args: |
| a: first int |
| b: second int |
| """ |
| return a - b |
|
|
|
|
| @tool |
| def multiply(a:int, b:int) -> int: |
| """multiply two numbers. |
| args: |
| a: first int |
| b: second int |
| """ |
| return a * b |
|
|
|
|
| @tool |
| def divide(a:int, b:int) -> float: |
| """divide two numbers. |
| args: |
| a: first int |
| b: second int |
| """ |
| try: |
| |
| result = a / b |
| return result |
| except ZeroDivisionError: |
| |
| raise ValueError("Cannot divide by zero.") |
|
|
|
|
| @tool |
| def modulus(a:int, b:int) -> int: |
| """modulus remainder of two numbers. |
| args: |
| a: first int |
| b: second int |
| """ |
| return a % b |
|
|
|
|
| |
| @tool |
| def search_wiki(query: str) -> Dict[str, str]: |
| """search wikipedia with a query |
| args: |
| query: a search query |
| """ |
| docs = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()) |
| docs.run(query) |
| formatted_result = f'<Document source="{docs.metadata["source"]}" page="{docs.metadata.get("page", "")}"/>\n{docs.page_content}\n</Document>' |
| return {"wiki_results": formatted_result} |
|
|
|
|
| |
| @tool |
| def search_web(query: str) -> Dict[str, str]: |
| """search internet with a query |
| args: |
| query: a search query |
| """ |
| docs = SerpAPIWrapper() |
| docs.run(query) |
| formatted_result = f'<Document source="{docs.metadata["source"]}" page="{docs.metadata.get("page", "")}"/>\n{docs.page_content}\n</Document>' |
| return {"wiki_results": formatted_result} |
|
|
|
|
| |
| @tool |
| def search_arxiv(query: str) -> Dict[str, str]: |
| """search ArXiv for the paper with the given identifier |
| args: |
| query: a search identifier |
| """ |
| arxiv = ArxivAPIWrapper() |
| docs = arxiv.run(query) |
| formatted_result = f'<Document source="{docs.metadata["source"]}" page="{docs.metadata.get("page", "")}"/>\n{docs.page_content}\n</Document>' |
| return {"wiki_results": formatted_result} |
|
|
|
|
| |
| |
|
|
|
|
| |
| with open("system_prompt.txt", "r", encoding="utf-8") as f: |
| system_prompt = f.read() |
|
|
|
|
| |
| sys_msg = SystemMessage(content=system_prompt) |
|
|
|
|
| tools = [ |
| add, |
| subtract, |
| multiply, |
| divide, |
| modulus, |
| search_wiki, |
| search_web, |
| search_arxiv |
| ] |
|
|
|
|
| |
| def build_graph(): |
| |
| llm = HuggingFaceEndpoint( |
| repo_id = "microsoft/Phi-4-reasoning-plus", |
| huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, |
| ) |
|
|
| chat = ChatHuggingFace(llm=llm, verbose=False) |
|
|
| |
| chat_with_tools = chat.bind_tools(tools) |
|
|
| |
| class AgentState(TypedDict): |
| messages: Annotated[list[AnyMessage], add_messages] |
|
|
| def assistant(state: AgentState): |
| return { |
| "messages": [chat_with_tools.invoke(state["messages"])], |
| } |
|
|
| |
| builder = StateGraph(AgentState) |
|
|
| |
| builder.add_node("assistant", assistant) |
| builder.add_node("tools", ToolNode(tools)) |
|
|
| |
| builder.add_edge(START, "assistant") |
| builder.add_conditional_edges( |
| "assistant", |
| |
| |
| tools_condition, |
| ) |
| builder.add_edge("tools", "assistant") |
|
|
| return builder.compile() |
|
|
|
|
| if __name__ == "__main__": |
| question = "When was a picture of St. Thomas Aquinas first added to the Wikipedia page on the Principle of double effect?" |
| graph = build_graph() |
| messages = [HumanMessage(content=question)] |
| messages = graph.invoke({"messages": messages}) |
| for m in messages["messages"]: |
| m.pretty_print() |
|
|