Model setup recipes

Save and resume a local LLM workflow with LangGraph

A checkpointer saves graph state for one thread. Fix the local model endpoint and thread_id to inspect and resume work after a pause.

This example uses ChatOllama in Python to call an Ollama model at http://127.0.0.1:11434, then stores input and response messages from a LangGraph StateGraph in checkpoints.sqlite with SqliteSaver. Reuse the same configurable.thread_id on each call to continue that thread. An in-memory checkpointer disappears when the process ends; choose SQLite when you need restart recovery.

To continue a local-LLM conversation after restarting a program, save its questions and answers. A LangGraph checkpoint records graph execution state. The example stores conversation messages in SQLite and restores them with the same conversation ID.

Requirements and key details
  • A StateGraph receives and returns state; a checkpointer stores snapshots of execution steps.
  • The same thread_id selects the same conversation checkpoints; a different ID separates another workflow.
  • The local model call and checkpoint storage are separate: Ollama serves the model, while SQLite stores the checkpoints.

Separate the model call from graph-state storage

LangGraph represents processing steps as nodes and their connections as edges. Saving state in a checkpoint lets the next request resume with the same thread_id. Start here with one question-answering node and a local Ollama call.

Arrows lead from document, table, and mail icons to a robot beside a laptop
Represent the question and model call as graph nodes; let the checkpointer store state.

Prepare a virtual environment and local model endpoint

Start Ollama and note the chat model ID you already downloaded. In a Python virtual environment1, install langgraph, langgraph-checkpoint-sqlite, and langchain-ollama. Set ChatOllama's base_url to the default server at http://127.0.0.1:11434 and use the model ID shown by ollama list.

Create an environment and install packages
python -m venv .venv
source .venv/bin/activate
python -m pip install -U langgraph langgraph-checkpoint-sqlite langchain-ollama
Commands use a macOS/Linux shell. Keep Ollama running separately.

Build a state graph that answers a question

Use MessagesState and StateGraph to define one node that answers a user question. Open a SQLite saver as a context manager to store checkpoints in checkpoints.sqlite, then attach the saver when compiling the graph. Pass {'configurable': {'thread_id': 'demo-1'}} to the first and later invocations to continue that thread's messages.

SQLite checkpointer and Ollama graph
import sys
from langchain_ollama import ChatOllama
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.graph import START, END, MessagesState, StateGraph

model = ChatOllama(model="YOUR_OLLAMA_MODEL_ID", base_url="http://127.0.0.1:11434")
def answer(state: MessagesState):
    return {"messages": [model.invoke(state["messages"])]}

builder = StateGraph(MessagesState)
builder.add_node("answer", answer)
builder.add_edge(START, "answer")
builder.add_edge("answer", END)
config = {"configurable": {"thread_id": "demo-1"}}
mode = sys.argv[1]
with SqliteSaver.from_conn_string("checkpoints.sqlite") as checkpointer:
    graph = builder.compile(checkpointer=checkpointer)
    if mode == "start":
        question = "예제 문서: 장비 대여 규정의 시행일은 2026년 4월 1일이다. 이 문서의 시행일은 언제야?"
        graph.invoke({"messages": [("user", question)]}, config)
        print("saved messages:", len(graph.get_state(config).values["messages"]))
    elif mode == "resume":
        print("restored messages:", len(graph.get_state(config).values["messages"]))
        result = graph.invoke({"messages": [("user", "방금 답변에서 날짜만 다시 말해줘.")]}, config)
        print("messages after follow-up:", len(graph.get_state(config).values["messages"]))
        print(result["messages"][-1].content)
    else:
        raise SystemExit("Usage: python app.py start|resume")
Replace `YOUR_OLLAMA_MODEL_ID` with an ID from `ollama list` and save as `app.py`. `python app.py start` stores the fictional policy and date in SQLite and reports two messages. After that process exits, `python app.py resume` restores two messages from the same file and thread_id, then reports four after the follow-up.
Page cards follow arrows between a document stack, monitor, and server
Save graph state in the checkpointer to continue on the next request.

Call twice and check state, then test restart recovery

Send an initial and follow-up question with the same thread_id, then inspect the length of graph.get_state(config).values['messages'] and the last reply. For a meaningful continuity check, do not manually resend the earlier conversation in the second question. After ending the process, reopen the same SQLite file with the same thread_id to load the saved state.

InMemorySaver suits an in-process check, but its state disappears when the process exits. If the SQLite file is not updated, check that the graph received the checkpointer and that each call uses the exact same thread_id. A different ID starts a separate conversation.

If several people continue the same conversation or you switch devices mid-thread, local checkpoints2 alone do not solve it. Compare a setup that keeps state on a server separately.

A person at a monitor with check marks and document icons, beside a stack of papers
After restarting, review whether the saved state matches the conversation you expect.

Terminology notes

  1. Python virtual environment — An isolated space for installing Python packages per project, helping reduce package-version conflicts.

    Back to the text
  2. Checkpoint — A file containing saved model weights and related state. Versions or tasks in one model family may use different checkpoints.

    Back to the text

Frequently asked questions

What should you check first in this article?
This example uses `ChatOllama` in Python to call an Ollama model at `http://127.0.0.1:11434`, then stores input and response messages from a LangGraph `StateGraph` in `checkpoints.sqlite` with `SqliteSaver`. Reuse the same `configurable.thread_id` on each call to continue that thread. An in-memory checkpointer disappears when the process ends; choose SQLite when you need restart recovery.