| | from langgraph.graph.message import add_messages |
| | from langchain_core.messages import AnyMessage, HumanMessage, AIMessage, SystemMessage |
| | from langgraph.prebuilt import ToolNode |
| | from langgraph.graph import START, StateGraph |
| | from langgraph.prebuilt import tools_condition |
| | from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace |
| | from tools import extract_text, describe_image |
| | from langchain_community.tools import DuckDuckGoSearchRun |
| | from langchain_openai import ChatOpenAI |
| | from typing import TypedDict, Annotated, Optional |
| |
|
| |
|
| | class AgentState(TypedDict): |
| | messages: Annotated[list[AnyMessage], add_messages] |
| |
|
| |
|
| | class BasicAgent(): |
| | def __init__(self, llm): |
| | chat = ChatHuggingFace(llm=llm, verbose=True) |
| | |
| | search_tool = DuckDuckGoSearchRun() |
| | vision_llm = ChatOpenAI(model="gpt-4o") |
| | self.tools = [extract_text, describe_image, search_tool] |
| | self.chat_with_tools = chat.bind_tools(self.tools) |
| | self._initialize_graph() |
| | print("BasicAgent initialized.") |
| |
|
| | |
| | def _initialize_graph(self): |
| | builder = StateGraph(AgentState) |
| |
|
| | |
| | builder.add_node("assistant", self.assistant) |
| | builder.add_node("tools", ToolNode(self.tools)) |
| |
|
| | |
| | builder.add_edge(START, "assistant") |
| | builder.add_conditional_edges("assistant",tools_condition) |
| | builder.add_edge("tools", "assistant") |
| |
|
| | |
| | self.agent = builder.compile() |
| |
|
| | |
| | def __call__(self, question: str) -> str: |
| | print(f"Agent received question: {question}.") |
| | messages=[HumanMessage(content=question)] |
| | response = self.agent.invoke({"messages":messages}) |
| | answer = response['messages'][-1].content |
| | print(f"Agent returning answer: {answer}") |
| | return answer |
| |
|
| | |
| | def assistant(self, state: AgentState): |
| | |
| | sys_msg = SystemMessage(content=f""" |
| | You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. |
| | 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. |
| | """) |
| | print("Calling assistant with state: ", state["messages"]) |
| | response = self.chat_with_tools.invoke(state["messages"]) |
| |
|
| | |
| | |
| | |
| | if response is None: |
| | raise RuntimeError("chat_with_tools.invoke returned None") |
| | |
| | |
| | if isinstance(response, list): |
| | updated_messages = response |
| | else: |
| | updated_messages = [response] |
| | |
| | return { |
| | "messages": updated_messages, |
| | } |
| |
|
| | |