Skip to content
Tech Blog
Go back

Running LangGraph with openGauss: Integration Guide

Edit page

Running LangGraph with openGauss

Table of Contents

Open Table of Contents

Overview

LangGraph applications depend on durable state. Once a graph needs memory, recovery, replay, or long-running execution, the database becomes part of the runtime model rather than just a log sink.

This document shows how to:

The guidance in this document is intentionally simple:

When to Choose PostgreSQL or openGauss

Use PostgreSQL when:

Use openGauss when:

Target Architecture

Architecture Diagram

flowchart TD
    A[Client or Service] --> B[LangGraph Application]
    B --> C[StateGraph]
    C --> D[OpenGaussSaver]
    D --> E[(openGauss Database)]

    E --> E1[checkpoints]
    E --> E2[checkpoint_blobs]
    E --> E3[checkpoint_writes]
    E --> E4[checkpoint_migrations]

Architecture Explanation

Install openGauss on Linux

The example below targets Rocky Linux 9.5 x86_64 using the official openGauss RPM repository.

Create the repository definition:

# /etc/yum.repos.d/opengauss.repo
[opengauss]
name=openGauss
baseurl=https://repo.opengauss.org/yum/redhat/9/opengauss-org/6.0.0/x86_64/
enabled=1
gpgcheck=0

Install openGauss:

dnf install -y opengauss

Enable and start the service:

systemctl enable --now opengauss
systemctl is-enabled opengauss
systemctl is-active opengauss

Verify the local installation:

sudo -u opengauss bash -lc 'source ~/.bash_profile; gsql -d postgres -c "select current_database(), current_user;"'

Expected output:

 current_database | current_user
------------------+-------------
 postgres         | opengauss

Apply a Lightweight Configuration

For a development or proof-of-concept environment, a conservative memory profile is sufficient.

Recommended settings:

shared_buffers = 256MB
max_connections = 50
work_mem = 4MB
maintenance_work_mem = 64MB
autovacuum_max_workers = 2
max_prepared_transactions = 50

This keeps resource usage predictable while allowing LangGraph checkpoint operations to run safely on a small host.

Create a LangGraph-Compatible Database

Create a database in PostgreSQL compatibility mode:

sudo -u opengauss bash -lc 'source ~/.bash_profile; gsql -d postgres -c "create database langgraph_demo_pg dbcompatibility '\''PG'\'';"'

Why this matters:

How LangGraph Persistence Maps to openGauss

LangGraph does not only store final results. It stores execution state.

The persistence layer maps to these openGauss tables:

Why these tables are useful

Connect LangGraph to openGauss

Once the database is ready, the LangGraph integration point is the custom OpenGaussSaver.

Minimal Example

from langgraph.graph import END, START, MessagesState, StateGraph
from langchain_core.messages import AIMessage, HumanMessage
from langgraph_checkpoint_opengauss import OpenGaussSaver


def assistant_node(state: MessagesState):
    human_messages = [
        message for message in state["messages"] if isinstance(message, HumanMessage)
    ]
    turn = len(human_messages)
    last_human = human_messages[-1].content if human_messages else ""
    return {"messages": [AIMessage(content=f"turn={turn}; echo={last_human}")]}


builder = StateGraph(MessagesState)
builder.add_node("assistant", assistant_node)
builder.add_edge(START, "assistant")
builder.add_edge("assistant", END)

conn_string = (
    "host=127.0.0.1 port=7654 "
    "dbname=langgraph_demo_pg user=opengauss password=YOUR_PASSWORD"
)

with OpenGaussSaver.from_conn_string(conn_string) as saver:
    saver.setup()
    graph = builder.compile(checkpointer=saver)
    result = graph.invoke(
        {"messages": [HumanMessage(content="hello")]},
        config={"configurable": {"thread_id": "demo-thread"}},
    )
    print(result)

Async Example

result = await graph.ainvoke(
    {"messages": [HumanMessage(content="status")]},
    config={"configurable": {"thread_id": "demo-thread"}},
)

What happens during execution

  1. LangGraph receives input for a specific thread_id.
  2. The graph runs one or more node steps.
  3. OpenGaussSaver persists checkpoints and channel writes.
  4. The same thread_id can later resume with prior state already loaded from openGauss.

What Problems This Integration Solved

1. Linux installation with a predictable memory profile

The database can be installed directly from the official RPM repository and tuned for local development without large memory overhead.

2. A LangGraph-compatible openGauss database layout

A dedicated PG compatibility database provides the correct foundation for checkpoint persistence.

3. A persistence adapter that matches LangGraph semantics

The custom saver preserves the LangGraph persistence model while allowing openGauss to act as the checkpoint backend.

4. Durable thread memory

Repeated invocations on the same thread_id recover prior state from openGauss, allowing memory and workflow continuity.

5. Recoverable execution state

The checkpoint model allows the graph to resume from persisted state rather than restarting from scratch.

6. Sync and async execution support

The same integration model works for both invoke() and ainvoke() application paths.

Example Stored Data

After a simple two-turn example, the logical application state looks like this:

Human: hello
AI:    turn=1; echo=hello
Human: status
AI:    turn=2; echo=status

That state is persisted through LangGraph checkpoint tables in openGauss.

At a high level:

This is what makes replay, recovery, and thread memory possible.

Operational Recommendation

Use this decision rule:

That recommendation keeps the architecture easy to reason about:

Appendix A: OpenGaussSaver

OpenGaussSaver is the persistence adapter that connects LangGraph checkpoint semantics to openGauss.

Responsibility

It provides:

Minimal usage pattern

from langgraph_checkpoint_opengauss import OpenGaussSaver

conn_string = (
    "host=127.0.0.1 port=7654 "
    "dbname=langgraph_demo_pg user=opengauss password=YOUR_PASSWORD"
)

with OpenGaussSaver.from_conn_string(conn_string) as saver:
    saver.setup()
    graph = builder.compile(checkpointer=saver)

Core methods

saver.setup()
saver.get_tuple(config)
saver.list(config, limit=10)
saver.put(config, checkpoint, metadata, new_versions)
saver.put_writes(config, writes, task_id)
saver.delete_thread(thread_id)

Async methods

await saver.aget_tuple(config)
async for item in saver.alist(config, limit=10):
    ...
await saver.aput(config, checkpoint, metadata, new_versions)
await saver.aput_writes(config, writes, task_id)
await saver.adelete_thread(thread_id)

With this adapter in place, LangGraph can use openGauss as a durable checkpoint backend while keeping the application-side graph programming model unchanged.


Edit page
Share this post on:

Previous Post
Building a Local Karmada Failover Demo: Multi-Cluster Kubernetes Traffic Switching on One Host
Next Post
How We Successfully Started Qwen3-Coder-Next on Huawei Ascend 910B with vLLM-Ascend 0.17