Files
langgraph/examples/configuration.ipynb
T

8.8 KiB

Configuration

Sometimes you want to be able to configure your agent when calling it. Examples of this include configuring which LLM to use. Below we walk through an example of doing so.

Base

First, let's create a very simple graph

In [7]:
import operator
from typing import Annotated, Sequence, TypedDict

from langchain_anthropic import ChatAnthropic
from langchain_core.messages import BaseMessage, HumanMessage

from langgraph.graph import END, StateGraph

model = ChatAnthropic(model_name="claude-2.1")


class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]


def _call_model(state):
    response = model.invoke(state["messages"])
    return {"messages": [response]}


# Define a new graph
workflow = StateGraph(AgentState)
workflow.add_node("model", _call_model)
workflow.set_entry_point("model")
workflow.add_edge("model", END)

app = workflow.compile()
In [8]:
app.invoke({"messages": [HumanMessage(content="hi")]})
Out [8]:
{'messages': [HumanMessage(content='hi'),
  AIMessage(content='Hello!', response_metadata={'id': 'msg_01YZj7CVCUSc76faX4VM9i5d', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 10, 'output_tokens': 6}}, id='run-d343db34-598c-46a2-93d6-ffa886d9b264-0')]}

Configure the graph

Great! Now let's suppose that we want to extend this example so the user is able to choose from multiple llms. We can easily do that by passing in a config. This config is meant to contain things are not part of the input (and therefore that we don't want to track as part of the state).

In [11]:
from langchain_openai import ChatOpenAI

openai_model = ChatOpenAI()

models = {
    "anthropic": model,
    "openai": openai_model,
}


def _call_model(state, config):
    m = models[config["configurable"].get("model", "anthropic")]
    response = m.invoke(state["messages"])
    return {"messages": [response]}


# Define a new graph
workflow = StateGraph(AgentState)
workflow.add_node("model", _call_model)
workflow.set_entry_point("model")
workflow.add_edge("model", END)

app = workflow.compile()

If we call it with no configuration, it will use the default as we defined it (Anthropic).

In [12]:
app.invoke({"messages": [HumanMessage(content="hi")]})
Out [12]:
{'messages': [HumanMessage(content='hi'),
  AIMessage(content='Hello!', response_metadata={'id': 'msg_01EedReFyXmonWXPKhYre7Jb', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 10, 'output_tokens': 6}}, id='run-1c6feaa0-bd6f-433a-8264-209d72c85db7-0')]}

We can also call it with a config to get it to use a different model.

In [13]:
config = {"configurable": {"model": "openai"}}
app.invoke({"messages": [HumanMessage(content="hi")]}, config=config)
Out [13]:
{'messages': [HumanMessage(content='hi'),
  AIMessage(content='Hello! How can I assist you today?', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 8, 'total_tokens': 17}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'stop', 'logprobs': None}, id='run-d41ffb62-e164-45a1-862c-d288c6ad100a-0')]}

We can also adapt our graph to take in more configuration! Like a system message for example.

In [18]:
from langchain_core.messages import SystemMessage


def _call_model(state, config):
    m = models[config["configurable"].get("model", "anthropic")]
    messages = state["messages"]
    if "system_message" in config["configurable"]:
        messages = [
            SystemMessage(content=config["configurable"]["system_message"])
        ] + messages
    response = m.invoke(messages)
    return {"messages": [response]}


# Define a new graph
workflow = StateGraph(AgentState)
workflow.add_node("model", _call_model)
workflow.set_entry_point("model")
workflow.add_edge("model", END)

app = workflow.compile()
In [19]:
app.invoke({"messages": [HumanMessage(content="hi")]})
Out [19]:
{'messages': [HumanMessage(content='hi'),
  AIMessage(content='Hello!', response_metadata={'id': 'msg_01Ts56eVLSrUbzVMbzLnXc3M', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 10, 'output_tokens': 6}}, id='run-f75a4389-b72e-4d47-8f3e-bedc6a060f66-0')]}
In [20]:
config = {"configurable": {"system_message": "respond in italian"}}
app.invoke({"messages": [HumanMessage(content="hi")]}, config=config)
Out [20]:
{'messages': [HumanMessage(content='hi'),
  AIMessage(content='Ciao!', response_metadata={'id': 'msg_01RzFCii8WhbbkFm16nUquxk', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 14, 'output_tokens': 7}}, id='run-9492f0e4-f223-41c2-81a6-6f0cb6a14fe6-0')]}
In [ ]: