Skip to main content

LangChain integration for Apache AGE (graph) + pgvector (vector) on PostgreSQL

Project description

langchain-age

LangChain integration for Apache AGE (graph) + pgvector (vector) on PostgreSQL.

Drop-in replacement for langchain-neo4j — same API, runs on PostgreSQL instead of Neo4j.

from langchain_age import AGEGraph, AGEVector, AGEGraphCypherQAChain

v0.1.1 — Initial stable release. The public API (AGEGraph, AGEVector, AGEGraphCypherQAChain) is considered stable. Breaking changes in 0.1.x will be avoided where possible.

Tested with

  • Python 3.10–3.14
  • PostgreSQL 18 + Apache AGE 1.7.0 + pgvector 0.8.2

Known limitations

  • AGE does not support parameterised Cypher ($param) — langchain-age provides mogrify-based safe value escaping as a workaround
  • Async methods use run_in_executor wrapping (not native psycopg.AsyncConnection yet)

Installation

Three install modes depending on what you need:

# Graph only
pip install langchain-age

# Graph + Vector (everything)
pip install "langchain-age[all]"

The Apache AGE Python driver is vendored — no separate installation required. Graph features work out of the box with pip install langchain-age.

Quick Start

1. Start the database

cd docker
docker compose up -d

Single container: PostgreSQL 18 + Apache AGE 1.7.0 + pgvector.

2. Graph mode

from langchain_age import AGEGraph

graph = AGEGraph(
    "host=localhost port=5433 dbname=langchain_age user=langchain password=langchain",
    graph_name="my_graph",
)

graph.query("CREATE (:Person {name: 'Alice', age: 30})")
results = graph.query("MATCH (n:Person) RETURN n.name AS name")
# [{'name': 'Alice'}]

3. Vector mode

from langchain_age import AGEVector, DistanceStrategy

store = AGEVector(
    connection_string="host=localhost port=5433 dbname=langchain_age user=langchain password=langchain",
    embedding_function=my_embeddings,
    collection_name="docs",
    distance_strategy=DistanceStrategy.COSINE,
)

store.add_texts(["Apache AGE adds Cypher to PostgreSQL."])
results = store.similarity_search("graph database", k=5)

4. Graph + Vector (GraphRAG)

# Vectorise existing graph nodes
store = AGEVector.from_existing_graph(
    embedding=my_embeddings,
    connection_string="...",
    graph_name="my_graph",
    node_label="Document",
    text_node_properties=["title", "content"],
)

5. Cypher QA Chain

from langchain_age import AGEGraph, AGEGraphCypherQAChain
from langchain_openai import ChatOpenAI

chain = AGEGraphCypherQAChain.from_llm(
    ChatOpenAI(model="gpt-4o-mini"),
    graph=AGEGraph("...", "movies"),
    allow_dangerous_requests=True,
)
answer = chain.run("Which movies did Tom Hanks act in?")

6. Long-term Memory & Checkpointing

Uses the same PostgreSQL instance via langgraph-checkpoint-postgres:

from langgraph.store.postgres import PostgresStore

with PostgresStore.from_conn_string("host=localhost port=5433 ...") as store:
    store.setup()
    store.put(("users", "123"), "prefs", {"theme": "dark"})

AGE graph tables, pgvector tables, and LangGraph store tables coexist in the same database.

Features

Component Class Description
Graph AGEGraph GraphStore backed by Apache AGE. Cypher execution, schema introspection, GraphDocument upserts.
Vector AGEVector VectorStore backed by pgvector. Cosine/L2/IP distance, HNSW & IVFFlat indexes, hybrid search (vector + full-text via RRF), MMR.
Chain AGEGraphCypherQAChain LLM generates Cypher, executes against AGE, returns natural-language answer.

Security

  • SQL identifier validation at construction (validate_sql_identifier)
  • Cypher identifier backtick-quoting for all 25 AGE reserved words (escape_cypher_identifier)
  • OpenCypher-standard string escaping with '' doubling (escape_cypher_string)
  • allow_dangerous_requests gate on the QA chain
  • Double-quoted SQL table/index names throughout

langchain-neo4j API Compatibility

Feature langchain-neo4j langchain-age
from_existing_graph() Neo4jVector.from_existing_graph() AGEVector.from_existing_graph()
from_existing_index() Neo4jVector.from_existing_index() AGEVector.from_existing_index()
similarity_search_with_relevance_scores() Yes Yes
as_retriever() Yes Yes
Hybrid search Lucene full-text PostgreSQL tsvector + RRF
include_types / exclude_types Yes Yes
add_graph_documents() Yes Yes
Context manager Yes Yes
Batch insert UNWIND ... IN TRANSACTIONS OF 1000 ROWS executemany with batch_size=1000

AGE vs Neo4j

Neo4j Apache AGE
Cypher execution Bolt protocol SQL-wrapped: SELECT * FROM cypher(...)
Connection neo4j:// PostgreSQL DSN
Vector search Native index pgvector extension
APOC Available Not available
Data types Native graph agtype (JSON superset)
Parameterised Cypher Yes ($param) mogrify-based (%s placeholders)

langchain-age handles SQL wrapping automatically — you write plain Cypher.

Documentation

Language Getting Started Tutorial API Reference
English getting-started.md tutorial.md api-reference.md
Korean getting-started.md tutorial.md api-reference.md

Notebooks

Notebook Description
01_graph.ipynb AGEGraph: Cypher CRUD, schema, GraphDocument
02_vector.ipynb AGEVector: similarity, hybrid, MMR, filters, HNSW
03_graph_vector.ipynb GraphRAG: from_existing_graph, QA chain

01 requires no API key. 02–03 use OpenAI via getpass.

Running Tests

# Unit tests (no DB required) — 65 tests
pytest tests/unit/

# Integration tests (requires Docker container) — 53 tests
export LANGCHAIN_AGE_TEST_DSN="host=localhost port=5433 dbname=langchain_age user=langchain password=langchain"
pytest tests/integration/

Project Structure

langchain-age/
├── docker/                          # PG18 + AGE + pgvector container
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── init/01_init_extensions.sql
├── langchain_age/
│   ├── __init__.py                  # Lazy imports (3-mode support)
│   ├── graphs/
│   │   └── age_graph.py             # AGEGraph (GraphStore)
│   ├── vectorstores/
│   │   └── age_vector.py            # AGEVector (VectorStore)
│   ├── chains/
│   │   └── graph_cypher_qa_chain.py # AGEGraphCypherQAChain
│   └── utils/
│       ├── agtype.py                # Vertex/Edge/Path → dict conversion
│       └── cypher.py                # SQL wrapping, escaping, validation
├── tests/
│   ├── conftest.py                  # Auto-skip integration when DSN unset
│   ├── unit/                        # 65 tests, no DB
│   └── integration/                 # 53 tests, live DB
├── pyproject.toml
├── LICENSE                          # MIT
├── CHANGELOG.md                     # Version history
└── .github/workflows/ci.yml        # Lint + unit (3.10–3.13) + integration

Python Support

Tested on Python 3.10, 3.11, 3.12, 3.13, 3.14.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langchain_age-0.1.2.tar.gz (71.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

langchain_age-0.1.2-py3-none-any.whl (55.4 kB view details)

Uploaded Python 3

File details

Details for the file langchain_age-0.1.2.tar.gz.

File metadata

  • Download URL: langchain_age-0.1.2.tar.gz
  • Upload date:
  • Size: 71.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for langchain_age-0.1.2.tar.gz
Algorithm Hash digest
SHA256 65f32fb172ccd3618aa932959a3d138ce109dff711ffdb3f06cbe1d74ec28cf5
MD5 94ba2c1b507341f9c674128999401727
BLAKE2b-256 203279c9e57adaa4b6b2d14b9e77c33ca2679c0cd11df85bb4412777927ce571

See more details on using hashes here.

File details

Details for the file langchain_age-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: langchain_age-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 55.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for langchain_age-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 98eac8bd59074373679a8242b8a3d0a19b26c13cb3fe9e6b289a449c85e4ee24
MD5 6e6c810d1f691ae5e6c24cd9b3ba0962
BLAKE2b-256 824500c887526005b40fb11bc77d2884d29b8476b7ba18cfc90761027705fe9c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page