Spaces:
Sleeping
Sleeping
| from langgraph.checkpoint.memory import MemorySaver | |
| from langgraph.graph import StateGraph, START | |
| from langchain_groq import ChatGroq | |
| from agent_graph.tool_chinook_sqlagent import query_chinook_sqldb | |
| from agent_graph.tool_travel_sqlagent import query_travel_sqldb | |
| from agent_graph.tool_lookup_policy_rag import lookup_swiss_airline_policy | |
| from agent_graph.tool_tavily_search import load_tavily_search_tool | |
| from agent_graph.tool_stories_rag import lookup_stories | |
| from agent_graph.load_tools_config import LoadToolsConfig | |
| from agent_graph.agent_backend import State, BasicToolNode, route_tools, plot_agent_schema | |
| TOOLS_CFG = LoadToolsConfig() | |
| def build_graph(): | |
| """ | |
| Builds an agent decision-making graph by combining an LLM with various tools | |
| and defining the flow of interactions between them. | |
| This function sets up a state graph where a primary language model (LLM) interacts | |
| with several predefined tools (e.g., databases, search functions, policy lookup, etc.). | |
| The agent can invoke tools based on conditions and use their outputs to inform | |
| further decisions. The flow involves conditional tool invocation, returning back | |
| to the chatbot after tool execution to guide the next step. | |
| Steps: | |
| 1. Initializes the primary language model (LLM) with tool-binding functionality. | |
| 2. Defines nodes in the graph where each node represents a specific action: | |
| - Chatbot node: Executes the LLM with the given state and messages. | |
| - Tools node: Runs the tool invocations based on the last message in the input state. | |
| 3. Implements conditional routing between the chatbot and tools: | |
| - If a tool is required, it routes to the tools node. | |
| - Otherwise, the flow ends. | |
| 4. Establishes connections between the chatbot and tools nodes to form the agent loop. | |
| 5. Uses a memory-saving mechanism to track and save checkpoints in the graph. | |
| Returns: | |
| graph (StateGraph): The compiled state graph that represents the decision-making process | |
| of the agent, integrating the chatbot, tools, and conditional routing. | |
| Components: | |
| - `primary_llm`: The primary language model responsible for generating responses. | |
| - `tools`: A list of tools including SQL queries, search functionalities, policy lookups, etc. | |
| - `tool_node`: A node responsible for handling tool execution based on the chatbot's request. | |
| - `chatbot`: A function that takes the state as input and returns a message generated by the LLM. | |
| - `route_tools`: A conditional function to determine whether the chatbot should call a tool. | |
| - `graph`: The complete graph with nodes and conditional edges. | |
| """ | |
| primary_llm = ChatGroq(model=TOOLS_CFG.primary_agent_llm, | |
| temperature=TOOLS_CFG.primary_agent_llm_temperature) | |
| graph_builder = StateGraph(State) | |
| # Load tools with their proper configs | |
| search_tool = load_tavily_search_tool(TOOLS_CFG.tavily_search_max_results) | |
| tools = [search_tool, | |
| lookup_swiss_airline_policy, | |
| lookup_stories, | |
| query_travel_sqldb, | |
| query_chinook_sqldb, | |
| ] | |
| # Tell the LLM which tools it can call | |
| primary_llm_with_tools = primary_llm.bind_tools(tools) | |
| def chatbot(state: State): | |
| """Executes the primary language model with tools bound and returns the generated message.""" | |
| return {"messages": [primary_llm_with_tools.invoke(state["messages"])]} | |
| graph_builder.add_node("chatbot", chatbot) | |
| tool_node = BasicToolNode( | |
| tools=[ | |
| search_tool, | |
| lookup_swiss_airline_policy, | |
| lookup_stories, | |
| query_travel_sqldb, | |
| query_chinook_sqldb, | |
| ]) | |
| graph_builder.add_node("tools", tool_node) | |
| # The `tools_condition` function returns "tools" if the chatbot asks to use a tool, and "__end__" if | |
| # it is fine directly responding. This conditional routing defines the main agent loop. | |
| graph_builder.add_conditional_edges( | |
| "chatbot", | |
| route_tools, | |
| # The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node | |
| # It defaults to the identity function, but if you | |
| # want to use a node named something else apart from "tools", | |
| # You can update the value of the dictionary to something else | |
| # e.g., "tools": "my_tools" | |
| {"tools": "tools", "__end__": "__end__"}, | |
| ) | |
| # Any time a tool is called, we return to the chatbot to decide the next step | |
| graph_builder.add_edge("tools", "chatbot") | |
| graph_builder.add_edge(START, "chatbot") | |
| memory = MemorySaver() | |
| graph = graph_builder.compile(checkpointer=memory) | |
| plot_agent_schema(graph) | |
| return graph | |