<a id="vs-langchain"></a>

# LangChain and CassIO Compatibility

ScyllaDB Vector Search is compatible with [LangChain](https://www.langchain.com/)
through the Cassandra connector, which is built on top of
[CassIO](https://reference.langchain.com/python/langchain-community/cache/CassandraSemanticCache). This lets you use the popular LangChain
`Cassandra` vector store — and other AI frameworks that integrate with
Cassandra or Astra DB through CassIO — against a ScyllaDB cluster with little
or no code changes.

This page explains how the compatibility layer works, what it requires, the
limitations you should be aware of, and provides a complete Retrieval-Augmented
Generation (RAG) example.

<a id="vs-langchain-how-it-works"></a>

## How Compatibility Works

In Cassandra, the native vector index type is the **Storage Attached Index
(SAI)**. Libraries such as CassIO, LangChain, and LlamaIndex generate
`CREATE CUSTOM INDEX` statements that reference the SAI class name when they
set up their schema. ScyllaDB’s native vector index type is instead called
`vector_index` (see [Vector Index Type](https://cloud.docs.scylladb.com/stable/vector-search/work-with-vector-search.md#vs-vector-index)).

To allow CassIO-based libraries to run unmodified, ScyllaDB recognizes the
Cassandra SAI class name in `CREATE CUSTOM INDEX` statements **on vector
columns** and transparently creates a native `vector_index` instead. The
following class names are accepted:

* `org.apache.cassandra.index.sai.StorageAttachedIndex` (exact case required)
* `StorageAttachedIndex` (case-insensitive)
* `SAI` (case-insensitive)

For example, the following Cassandra SAI statement is accepted by ScyllaDB:

```cql
CREATE CUSTOM INDEX ON my_table (embedding)
USING 'org.apache.cassandra.index.sai.StorageAttachedIndex'
WITH OPTIONS = {'similarity_function': 'COSINE'};
```

ScyllaDB treats it as equivalent to its native syntax:

```cql
CREATE CUSTOM INDEX ON my_table (embedding)
USING 'vector_index'
WITH OPTIONS = {'similarity_function': 'COSINE'};
```

The `similarity_function` option is supported by both Cassandra SAI and
ScyllaDB, so no translation is needed for it.

<a id="vs-langchain-metadata-map"></a>

### The CassIO Metadata-Map Pattern

CassIO also creates an SAI index on the **entries of a non-frozen map column**
(the column it uses to store document metadata). When ScyllaDB encounters an
SAI class name on `ENTRIES(map_column)`, it strips the SAI class and creates
a standard [secondary index](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-filtering.md)
instead. For example, CassIO issues this during schema setup:

```cql
CREATE CUSTOM INDEX ON my_table (ENTRIES(metadata_s))
USING 'org.apache.cassandra.index.sai.StorageAttachedIndex';
```

ScyllaDB creates the equivalent of:

```cql
CREATE INDEX ON my_table (ENTRIES(metadata_s));
```

A CQL warning is emitted noting possible behavioral differences from Cassandra
SAI metadata filtering. This rewrite requires the `enable_cassio_compatibility`
configuration option to be enabled (see [Requirements](#vs-langchain-requirements)).

#### NOTE
This rewrite provides compatibility for index *creation* only. The resulting
standard secondary index **cannot be used to filter the results of an**
`ANN OF` **similarity search**. To combine similarity search with metadata
constraints, use ScyllaDB’s native
[vector search filtering](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-filtering.md).
See [Limitations and Compatibility Gaps](#vs-langchain-limitations) for
details.

<a id="vs-langchain-requirements"></a>

## Requirements

To use LangChain and CassIO with ScyllaDB Vector Search, your environment must
meet the following requirements:

* **ScyllaDB 2026.2 or later**, with the [Vector Search feature](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-clusters.md) enabled on the cluster. The
  Approximate Nearest Neighbor (ANN) search itself is served by the ScyllaDB
  Vector Store service, which must be configured for the cluster.
* **The** `enable_cassio_compatibility` **configuration option must be
  enabled.** LangChain/CassIO automatic schema setup creates an SAI index on
  the metadata map column, and this option allows ScyllaDB to rewrite that
  statement into a standard secondary index.

<a id="vs-langchain-enable-flag"></a>

### Enabling CassIO Compatibility

The `enable_cassio_compatibility` option must be enabled on every node. It is
live-updatable, so you can enable it at runtime — without a restart — using the
following CQL statement:

```cql
UPDATE system.config SET value = 'true' WHERE name = 'enable_cassio_compatibility';
```

Self-managed deployments can alternatively pass `--enable-cassio-compatibility 1`
on the command line, or set `enable_cassio_compatibility: true` in
`scylla.yaml`.

#### NOTE
Changing cluster configuration requires appropriate permissions. If you are
using ScyllaDB Cloud and the option is not enabled on your cluster, contact
[ScyllaDB Support](https://cloud.docs.scylladb.com/stable/help-and-learning/get-help.html).

<a id="vs-langchain-limitations"></a>

## Limitations and Compatibility Gaps

The compatibility layer is designed to make CassIO-generated schema statements
work on ScyllaDB. Keep the following limitations in mind:

* **DDL-level compatibility.** Compatibility applies to the `CREATE CUSTOM
  INDEX` data-definition statements that CassIO and LangChain issue. The
  underlying vector index is a native ScyllaDB `vector_index`, and queries
  use ScyllaDB’s vector search implementation.
* **SAI is accepted only on vector columns and map entries.** SAI class names
  are recognized on **vector columns** (rewritten to `vector_index`) and on
  **ENTRIES of non-frozen map columns** (rewritten to a standard secondary
  index). Using an SAI class name on any other non-vector column (for example,
  `text` or `int`) results in an error. General SAI indexing is not
  supported; use a [secondary index](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-filtering.md)
  instead. Multi-column SAI targets are also rejected.
* **The** `source_model` **option is accepted but not used.** Cassandra
  client libraries such as CassIO may send a `source_model` option to tag the
  index with the name of the embedding model that produced the vectors (for
  example, `ada002`). Cassandra SAI rejects this as an unrecognized property;
  ScyllaDB accepts and preserves it in `DESCRIBE` output for compatibility,
  but does not act on it.
* **Combining metadata filtering with ANN queries requires native filtering.**
  The CassIO metadata-map SAI index is rewritten to a standard secondary index,
  which provides compatibility for index *creation* only. It does not make
  CassIO-style metadata filtering work together with similarity search: an
  `ANN OF` query combined with a metadata filter served through the rewritten
  secondary index will usually not work without custom integration. To combine
  similarity search with metadata constraints, use ScyllaDB’s native
  [vector search filtering](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-filtering.md)
  instead. The rewritten secondary index can serve metadata filtering only when
  it is *not* combined with an ANN query. ScyllaDB emits a CQL warning when it
  performs this rewrite.
* **Vector index feature limitations apply.** Vector indexes do not support all
  ScyllaDB features. Tracing, paging, and grouping are not supported on
  vector indexes regardless of whether the index was created through CassIO or
  native CQL.
* **The ANN index is built asynchronously.** After the table and index are
  created, the ScyllaDB Vector Store service builds the ANN index in the
  background. If the index is created on a table that already contains data,
  ScyllaDB scans the existing rows to build the HNSW graph. Until the build
  completes, a similarity search issued right after schema setup can briefly
  fail or return incomplete results, so applications should wait and retry the
  first query (see
  [Index build progress monitoring](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-troubleshooting.md#vs-index-build-progress)). This
  initial build is distinct from the incremental
  [write-to-query latency](https://cloud.docs.scylladb.com/stable/vector-search/work-with-vector-search.md#vs-write-to-query-latency) that applies to an
  already-built index.

<a id="vs-langchain-example"></a>

## Example: LangChain RAG with ScyllaDB

The following example uses LangChain’s `Cassandra` vector store against a
ScyllaDB deployment. It lets LangChain/CassIO create the vector table and
indexes automatically (`SetupMode.SYNC`), inserts a small set of documents,
waits for the asynchronously built ANN index to become ready, and runs a
similarity search.

The example uses a local [FastEmbed](https://github.com/qdrant/fastembed)
embedding model (`BAAI/bge-small-en-v1.5`, 384 dimensions), so it does not
require a paid embedding API. The model is downloaded on first use.

#### NOTE
This example is adapted from the
[LangChain RAG example](https://github.com/scylladb/vector-store/tree/master/docs/examples/langchain-rag)
in the ScyllaDB Vector Store repository. See that directory for the complete,
runnable project.

### Install Dependencies

Create and activate a Python virtual environment, then install the required
packages:

```sh
python3 -m venv .venv
. .venv/bin/activate
pip install \
  "cassio>=0.1,<0.2" \
  "cassandra-driver>=3.30,<4" \
  "fastembed>=0.8,<0.9" \
  "langchain-community>=0.4,<0.5" \
  "langchain-core>=1.4,<2"
```

### Connect and Build the Vector Store

First, connect to ScyllaDB and create the keyspace. Then build a LangChain
`Cassandra` vector store on top of the session. With `SetupMode.SYNC`,
LangChain/CassIO creates the table and its vector index up front, so you do not
have to write any CQL DDL yourself.

```python
from cassandra.auth import PlainTextAuthProvider
from cassandra.cluster import Cluster
from langchain_community.embeddings.fastembed import FastEmbedEmbeddings
from langchain_community.utilities.cassandra import SetupMode
from langchain_community.vectorstores import Cassandra
from langchain_core.documents import Document

KEYSPACE = "langchain_demo"
TABLE_NAME = "langchain_rag_demo"
# A small local embedding model. Its 384-dimensional output determines
# the size of the stored vectors. The same model must be used for both
# inserts and queries so the vectors live in the same space.
EMBEDDING_MODEL = "BAAI/bge-small-en-v1.5"

auth = PlainTextAuthProvider(username="scylla", password="YOUR_PASSWORD")
cluster = Cluster(
    contact_points=["node-0.your-cluster.cloud.scylladb.com"],
    port=9042,
    auth_provider=auth,
)
session = cluster.connect()

session.execute(
    f"""
    CREATE KEYSPACE IF NOT EXISTS {KEYSPACE}
    WITH replication = {{'class': 'NetworkTopologyStrategy', 'replication_factor': 1}}
    """
)
session.set_keyspace(KEYSPACE)

# SetupMode.SYNC creates the table and vector index synchronously if they
# do not already exist. This is the step that relies on CassIO
# compatibility being enabled on the cluster.
embeddings = FastEmbedEmbeddings(model_name=EMBEDDING_MODEL)
vector_store = Cassandra(
    embedding=embeddings,
    session=session,
    keyspace=KEYSPACE,
    table_name=TABLE_NAME,
    setup_mode=SetupMode.SYNC,
)
```

#### NOTE
Automatic schema setup with `SetupMode.SYNC` only works when you do **not**
need metadata filtering combined with `ANN OF` queries. As noted in
[Limitations and Compatibility Gaps](#vs-langchain-limitations), the
secondary index that CassIO’s schema setup creates provides index-creation
compatibility only and cannot filter ANN search results. If your application
needs to combine similarity search with metadata constraints, use
`SetupMode.OFF` instead, create the table and a native ScyllaDB
[vector index](https://cloud.docs.scylladb.com/stable/vector-search/work-with-vector-search.md) (with the
required filtering columns) manually to apply ScyllaDB’s native
[vector search filtering](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-filtering.md).

### Insert Documents

LangChain embeds each document’s content and stores the resulting vector.
Passing explicit ids makes inserts idempotent, so re-running the example updates
the same rows instead of creating duplicates.

```python
DEMO_DOCUMENTS = (
    ("vector-store-indexing",
     "ScyllaDB Vector Store indexes vector columns stored in ScyllaDB "
     "tables and serves approximate nearest-neighbor search for queries."),
    ("langchain-cassandra-connector",
     "LangChain's Cassandra vector store connector uses the Cassandra "
     "Query Language protocol and can exercise ScyllaDB through CassIO."),
    ("ann-search",
     "Approximate nearest-neighbor queries compare an embedded question "
     "with stored document embeddings and return the closest documents."),
)

documents = [
    Document(page_content=text, metadata={"id": doc_id})
    for doc_id, text in DEMO_DOCUMENTS
]
ids = [doc_id for doc_id, _ in DEMO_DOCUMENTS]
vector_store.add_documents(documents, ids=ids)
```

### Wait for the Index, Then Search

Because the ANN index is built asynchronously, a search issued immediately
after setup can briefly fail while the index is still being constructed. While
the index is not ready, the Vector Store service answers with HTTP status
`404` (index not created yet) or `503` (index still being built), and
ScyllaDB surfaces that status in the CQL error message. Probe once with retries,
then run searches directly.

```python
import time

def is_index_still_building(error: Exception) -> bool:
    message = str(error)
    return "HTTP status 404" in message or "HTTP status 503" in message

def wait_for_index(store: Cassandra, query: str, attempts: int = 30,
                   delay_seconds: int = 2) -> None:
    for _ in range(attempts):
        try:
            store.similarity_search_with_score(query, k=1)
            return
        except Exception as error:
            if not is_index_still_building(error):
                raise
            time.sleep(delay_seconds)
    raise RuntimeError("Vector Store did not finish building the ANN index in time")

query = "How does ScyllaDB support vector search?"
wait_for_index(vector_store, query)

results = vector_store.similarity_search_with_score(query, k=3)
for document, score in results:
    print(f"id={document.metadata.get('id')} score={score:.6f}")
    print(document.page_content)
```

Higher scores indicate closer (more similar) matches. The example prints the
retrieved documents and their scores; it does not run text generation, which
you would add as the “generation” step of a full RAG pipeline.

#### SEE ALSO
* [Working with Vector Search](https://cloud.docs.scylladb.com/stable/vector-search/work-with-vector-search.md)
  — vector data type, vector indexes, ANN queries, and driver integration.
* [Filtering Vector Search Results](https://cloud.docs.scylladb.com/stable/vector-search/vector-search-filtering.md)
  — combine similarity search with metadata constraints.
* [Example Applications](https://vector-search.scylladb.com/)
  — RAG applications, semantic caching, and integrations with LLM
  libraries such as LlamaIndex and LangChain.
