Migrate to pluggable providers

Available on NAMS: No. The procedure on this page needs the Bolt backend. With the hosted NAMS backend its operations are unavailable: depending on the call, the client raises NotSupportedError, AttributeError or TypeError, or ignores a Bolt-only setting or argument (NAMS manages embedding and extraction server-side). See the backend capabilities reference for what NAMS provides instead.

Replace legacy EmbeddingConfig and LLMConfig objects with the provider API in neo4j-agent-memory 0.7.0.

The provider API introduced in v0.3 makes the LLM and embedding model pluggable. MemorySettings.embedding and MemorySettings.llm now accept three shapes: legacy EmbeddingConfig / LLMConfig (deprecated), a provider-string shorthand, or a fully-constructed Provider instance. This guide walks each migration pattern with side-by-side code.

Prerequisites

  • Install the extras for each selected provider and configure its credentials. Quote package extras in shell commands, for example pip install 'neo4j-agent-memory[openai]==0.7.0'.

  • Use a dedicated AuraDB instance and export NEO4J_URI, NEO4J_USERNAME, and NEO4J_PASSWORD as shown in the Aura connection setup. These examples use the bolt backend; NEO4J_DATABASE defaults to neo4j when omitted.

  • Model identifiers below illustrate adapter routing. Confirm the chosen model is available to your account before making a live request; successful provider construction does not verify model access.

  • Run snippets containing await in an async function. The provider, messages, and connected client in later fragments come from your application’s setup.

Procedure

  1. Choose a string, explicit adapter, or framework pass-through from the options below.

  2. Configure both the LLM and embedding provider; changing one does not configure the other.

  3. Run the verification at the end before applying the configuration to an existing graph.

Compatibility summary

  • In 0.7.0, MemorySettings still accepts legacy EmbeddingConfig and LLMConfig objects. Each explicit legacy object emits a DeprecationWarning, not a FutureWarning.

  • The warning text names a planned removal in v0.5.0, but both types are still present in 0.7.0. Treat the warning as a migration notice.

  • Run your own representative examples after migrating. This guide does not establish that every historical example runs unmodified.

Pattern 1: Drop in a provider-string shorthand

The simplest migration. Replace the legacy config with a single string.

Before (legacy objects; explicit fields emit deprecation warnings)
import os
from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.config.settings import (
    EmbeddingConfig, EmbeddingProvider, LLMConfig, LLMProvider,
)

settings = MemorySettings(
    backend="bolt",
    neo4j={
        "uri": os.environ["NEO4J_URI"],
        "username": os.environ["NEO4J_USERNAME"],
        "password": os.environ["NEO4J_PASSWORD"],
        "database": os.getenv("NEO4J_DATABASE", "neo4j"),
    },
    embedding=EmbeddingConfig(
        provider=EmbeddingProvider.OPENAI,
        model="text-embedding-3-small",
    ),
    llm=LLMConfig(
        provider=LLMProvider.OPENAI,
        model="gpt-4o-mini",
    ),
)
After (provider strings)
import os
from neo4j_agent_memory import MemoryClient, MemorySettings

settings = MemorySettings(
    backend="bolt",
    neo4j={
        "uri": os.environ["NEO4J_URI"],
        "username": os.environ["NEO4J_USERNAME"],
        "password": os.environ["NEO4J_PASSWORD"],
        "database": os.getenv("NEO4J_DATABASE", "neo4j"),
    },
    embedding="openai/text-embedding-3-small",
    llm="openai/gpt-4o-mini",
)

Strings are resolved via neo4j_agent_memory.llm.from_provider. The factory does native-first dispatch: with both [openai] and [litellm] installed, an "openai/…​" model uses the native adapter; unsupported providers fall through to LiteLLM.

Pattern 2: Switch provider entirely (OpenAI → Anthropic)

import os
from neo4j_agent_memory import MemoryClient, MemorySettings

settings = MemorySettings(
    backend="bolt",
    neo4j={
        "uri": os.environ["NEO4J_URI"],
        "username": os.environ["NEO4J_USERNAME"],
        "password": os.environ["NEO4J_PASSWORD"],
        "database": os.getenv("NEO4J_DATABASE", "neo4j"),
    },
    embedding="openai/text-embedding-3-small",
    llm="anthropic/claude-3-5-sonnet-latest",
)

Install both providers used above: pip install 'neo4j-agent-memory[anthropic,openai]==0.7.0'. Set ANTHROPIC_API_KEY and OPENAI_API_KEY for the LLM and embeddings respectively.

Pattern 3: Local embeddings + Anthropic LLM (no OpenAI dependency)

import os
from neo4j_agent_memory import MemoryClient, MemorySettings

settings = MemorySettings(
    backend="bolt",
    neo4j={
        "uri": os.environ["NEO4J_URI"],
        "username": os.environ["NEO4J_USERNAME"],
        "password": os.environ["NEO4J_PASSWORD"],
        "database": os.getenv("NEO4J_DATABASE", "neo4j"),
    },
    embedding="BAAI/bge-small-en-v1.5",  # local sentence-transformers
    llm="anthropic/claude-3-5-sonnet-latest",
)

Install: pip install 'neo4j-agent-memory[anthropic,sentence-transformers]==0.7.0'.

This pattern is appealing for cost, privacy, and offline workflows: embeddings stay on your machine; LLM calls still use the configured cloud service; download and cache the local embedding model before an offline deployment. See the tutorial for a full walk-through.

Pattern 4: Construct a Provider instance directly (full control)

When you need to pass an api_base (vLLM, Ollama, an internal endpoint) or provider-specific kwargs, construct the adapter explicitly:

import os
from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.llm.adapters.litellm import LiteLLMProvider
from neo4j_agent_memory.llm.adapters.openai import OpenAIEmbeddingProvider

settings = MemorySettings(
    backend="bolt",
    neo4j={
        "uri": os.environ["NEO4J_URI"],
        "username": os.environ["NEO4J_USERNAME"],
        "password": os.environ["NEO4J_PASSWORD"],
        "database": os.getenv("NEO4J_DATABASE", "neo4j"),
    },
    embedding=OpenAIEmbeddingProvider("openai/text-embedding-3-small"),
    llm=LiteLLMProvider(
        "ollama/llama3.2",
        api_base="http://localhost:11434",
    ),
)

This is identical to the string shorthand but lets you set adapter-specific options. Provider instances also bypass the native-first dispatch of from_provider — you get exactly what you asked for.

Pattern 5: Pass through a framework-native model

Already configured a LangChain / Pydantic AI / LlamaIndex / CrewAI / Strands / Microsoft Agent model? Hand it directly to the matching pass-through helper:

import os
from langchain_anthropic import ChatAnthropic
from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.integrations.langchain import (
    llm_provider_from_langchain,
)

chat = ChatAnthropic(model_name="claude-3-5-sonnet-latest")

settings = MemorySettings(
    backend="bolt",
    neo4j={
        "uri": os.environ["NEO4J_URI"],
        "username": os.environ["NEO4J_USERNAME"],
        "password": os.environ["NEO4J_PASSWORD"],
        "database": os.getenv("NEO4J_DATABASE", "neo4j"),
    },
    llm=llm_provider_from_langchain(chat),
)

These integration packages expose a llm_provider_from_<framework> helper:

  • from neo4j_agent_memory.integrations.langchain import llm_provider_from_langchain

  • from neo4j_agent_memory.integrations.pydantic_ai import llm_provider_from_pydantic_ai

  • from neo4j_agent_memory.integrations.llamaindex import llm_provider_from_llamaindex

  • from neo4j_agent_memory.integrations.crewai import llm_provider_from_crewai

  • from neo4j_agent_memory.integrations.openai_agents import llm_provider_from_openai_agents

  • from neo4j_agent_memory.integrations.microsoft_agent import llm_provider_from_microsoft_agent

  • from neo4j_agent_memory.integrations.google_adk import llm_provider_from_google_adk

  • from neo4j_agent_memory.integrations.strands import llm_provider_from_strands

Pattern 6: No LLM at all (unchanged)

MemorySettings.llm=None disables LLM construction when extraction settings do not require an LLM — see Run without an LLM.

Embedding dimensions and existing vector indexes

If you change embedding model — for example, OpenAI’s 1536-dim model to a 384-dim sentence-transformers model — MemoryClient.connect() will detect the mismatch against existing Neo4j vector indexes and raise EmbeddingDimensionMismatchError. Choose a complete migration or restore the original model. Dropping indexes does not remove stored embedding properties and does not regenerate them. A same-dimension model change also requires a backfill, although dimension validation cannot detect it.

See Migrate to a new embedding model for the index-rebuild runbook.

Validating your migration

After updating, this should hold:

import os
import warnings

from neo4j_agent_memory import MemorySettings

with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always", DeprecationWarning)
    settings = MemorySettings(
        backend="bolt",
        neo4j={
            "uri": os.environ["NEO4J_URI"],
            "username": os.environ["NEO4J_USERNAME"],
            "password": os.environ["NEO4J_PASSWORD"],
            "database": os.getenv("NEO4J_DATABASE", "neo4j"),
        },
        embedding="openai/text-embedding-3-small",
        llm="anthropic/claude-3-5-sonnet-latest",
    )

assert not [w for w in caught if issubclass(w.category, DeprecationWarning)]

If any DeprecationWarning fires, search the message text — it identifies the field (embedding or llm) and points back to this guide.

Suppressing the warning during transition

If you must keep the legacy types for a release cycle while migrating other code, the standard warnings.filterwarnings call works:

import warnings

warnings.filterwarnings(
    "ignore",
    message=".*EmbeddingConfig.*deprecated.*",
    category=DeprecationWarning,
)

This is intentionally not the default — silent deprecations make migrations slip.

Behind the scenes

For the _resolve_providers model-validator and _ProviderToEmbedderAdapter implementation walkthrough, see Why the provider protocol? — How migration resolves provider settings.

A clean warning check confirms configuration shape only. Verify a completion, an embedding vector, and representative retrieval using your selected providers. Use the embedding migration runbook before changing an existing graph’s model.

See also