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 |
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, andNEO4J_PASSWORDas shown in the Aura connection setup. These examples use theboltbackend;NEO4J_DATABASEdefaults toneo4jwhen 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
awaitin an async function. Theprovider,messages, and connectedclientin later fragments come from your application’s setup.
Procedure
-
Choose a string, explicit adapter, or framework pass-through from the options below.
-
Configure both the LLM and embedding provider; changing one does not configure the other.
-
Run the verification at the end before applying the configuration to an existing graph.
Compatibility summary
-
In 0.7.0,
MemorySettingsstill accepts legacyEmbeddingConfigandLLMConfigobjects. Each explicit legacy object emits aDeprecationWarning, not aFutureWarning. -
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.
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",
),
)
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
-
Bring your own model — the headline how-to for choosing a provider.
-
Configuration reference — the canonical
MemorySettingsreference. -
Why the provider protocol? — design rationale.