LangGraph with SovereignEG

Goal: build a graph with one chatbot node, then upgrade it to a tool-using agent.

Time: 10 minutes.

LangGraph runs your LLM logic as a graph of nodes. The model itself is the same ChatOpenAI object from the LangChain guide.

Step 1 — Install

pip install langgraph langchain-openai

Step 2 — A one-node graph

Save as langgraph_hello.py:

import os
import time
 
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, MessagesState, START, END
 
llm = ChatOpenAI(
    model="SovereignEG/Qwen3.8-27B-FP8",
    base_url="https://backend.sovereigneg.com/v1",
    api_key=os.environ["SOVEREIGNEG_API_KEY"],
)
 
 
def chatbot(state: MessagesState):
    # The node receives the message list and returns new messages to append
    return {"messages": [llm.invoke(state["messages"])]}
 
 
builder = StateGraph(MessagesState)
builder.add_node("chatbot", chatbot)
builder.add_edge(START, "chatbot")
builder.add_edge("chatbot", END)
graph = builder.compile()
 
start = time.time()
result = graph.invoke({"messages": [("user", "Hello, who are you?")]})
elapsed = time.time() - start
 
response = result["messages"][-1]
print(response.content)
print(f"\nTime: {elapsed:.2f}s")
print(f"Tokens: {response.usage_metadata}")
python langgraph_hello.py

How it works: START → chatbot → END. MessagesState is a built-in state that keeps a list of messages and appends whatever each node returns.

Step 3 — A tool-using agent (ReAct)

The model supports tool calling, so you can use LangGraph's prebuilt agent. It calls tools in a loop until it has a final answer.

import os
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
 
llm = ChatOpenAI(
    model="SovereignEG/Qwen3.8-27B-FP8",
    base_url="https://backend.sovereigneg.com/v1",
    api_key=os.environ["SOVEREIGNEG_API_KEY"],
    temperature=0,
)
 
 
@tool
def get_weather(city: str) -> str:
    """Return today's weather for a city."""
    fake = {"Cairo": "34°C, sunny", "Alexandria": "29°C, windy"}
    return fake.get(city, "unknown city")
 
 
@tool
def add(a: float, b: float) -> float:
    """Add two numbers."""
    return a + b
 
 
agent = create_react_agent(llm, tools=[get_weather, add])
 
result = agent.invoke(
    {"messages": [("user", "What is the weather in Cairo, and what is 17 + 25?")]}
)
print(result["messages"][-1].content)

The model decides which tools to call, LangGraph runs them, feeds the results back, and the model writes the final answer.

You may see a warning that create_react_agent moved to langchain.agents. It still works. If you have the langchain package installed, the new form is from langchain.agents import create_agent (same arguments).

Step 4 — Memory across turns

Add a checkpointer and a thread_id so the agent remembers earlier messages:

from langgraph.checkpoint.memory import MemorySaver
 
agent = create_react_agent(llm, tools=[get_weather, add], checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "user-1"}}
 
agent.invoke({"messages": [("user", "My name is Sara.")]}, config)
out = agent.invoke({"messages": [("user", "What is my name?")]}, config)
print(out["messages"][-1].content)   # -> "Your name is Sara."

Troubleshooting

ProblemFix
Agent never calls toolsMake sure temperature=0 and the tool has a clear docstring (the model reads it)
KeyError: 'messages'Every node must return {"messages": [...]} when using MessagesState
Loops foreverAdd recursion_limit: agent.invoke(..., {"recursion_limit": 10})

Next: CrewAI