Use Amazon Bedrock embeddings

Generate Titan V2 vectors, check their size, and persist a message through a MemoryClient using the same embedder. The selected path uses AWS credentials from the normal SDK credential chain and an explicitly configured region.

1. Prepare the selected environment

Install the AWS CLI before running the identity check below.

Use Python 3.10+ and a POSIX shell. Prepare a dedicated AuraDB instance; its existing vectors and indexes must match the selected model and dimensions. The program disables entity extraction and does not require a chat model. Follow the Aura connection setup for a dedicated test instance, then copy its URI, username and password into the exports below.

Create a local folder and virtual environment for the examples on this page. The commands reuse an existing environment without changing its files:

mkdir -p ~/agent-memory-tutorials
cd ~/agent-memory-tutorials
if [ -e .venv ]; then
  printf '%s\n' 'Using the existing virtual environment.'
else
  python3 -m venv .venv
fi
source .venv/bin/activate

Expected: ~/agent-memory-tutorials is your working directory and its virtual environment is active. Install the published SDK with the command below.

Each complete code block labelled Save as names a file to create in this folder using your editor. Copy the entire block, including imports and the entry point. Expand each helper disclosure and use Copy code to copy its full source. Keep all files together so their imports resolve.

When continuing from another tutorial or guide, retain the existing environment, configuration, session files, and .tutorial-state/. Reuse unchanged helper files; compare an existing file before replacing it, and finish any pending cleanup or recovery before changing the code that owns its state.

Configure an AWS profile, role or environment credentials before running the block below; its final command checks them. The identity must be allowed to invoke amazon.titan-embed-text-v2:0 in the selected region; successful STS identity lookup alone does not establish model access. The chosen model emits 1024-dimensional vectors in this adapter configuration.

python -m pip install 'neo4j-agent-memory[bedrock]==0.7.0'
export AWS_REGION='us-east-1'
export NEO4J_URI='neo4j+s://<instance-id>.databases.neo4j.io'
export NEO4J_USERNAME='neo4j'
export NEO4J_PASSWORD='replace-with-your-Aura-password'
export NEO4J_DATABASE='neo4j'
aws sts get-caller-identity

2. Read the complete recipe

Create the subdirectory below, then save both complete files under the displayed names. Run commands from agent-memory-tutorials/; Python resolves common from the script’s integrations/ directory.

mkdir -p integrations

The script imports this shared helper from the same directory. It supplies explicit database settings, closes clients through the calling context manager, and fails when expected records are absent. Task traces record the observable outcome of the call; they do not expose hidden model reasoning.

Complete integrations/common.py
Save as integrations/common.py
"""Shared Aura connection through Bolt and readback for integration recipes."""

import os


def settings(embedding=None):
    from neo4j_agent_memory import BoltSettings
    from neo4j_agent_memory.llm import from_provider

    return BoltSettings(
        neo4j={
            "uri": os.environ["NEO4J_URI"],
            "username": os.environ["NEO4J_USERNAME"],
            "password": os.environ["NEO4J_PASSWORD"],
            "database": os.getenv("NEO4J_DATABASE", "neo4j"),
        },
        embedding=embedding or from_provider("openai/text-embedding-3-small", kind="embedding"),
        extraction={"extractor_type": "none"},
    )


async def verify_messages(client, session_id, expected):
    conversation = await client.short_term.get_conversation(session_id)
    contents = [message.content for message in conversation.messages]
    if not all(text in contents for text in expected):
        raise RuntimeError(f"Message readback failed for {session_id}")
    print(f"Verified stored messages; session={session_id}")


async def recorded_turn(client, session_id, prompt, respond):
    """Record a task outcome; this does not claim to capture hidden model reasoning."""
    trace = await client.reasoning.start_trace(session_id=session_id, task=prompt)
    try:
        await client.short_term.add_message(session_id, "user", prompt, extract_entities=False)
        context = await client.get_context(prompt, session_id=session_id)
        reply = str(await respond(context))
        if not reply.strip():
            raise RuntimeError("The framework returned no text")
        await client.short_term.add_message(session_id, "assistant", reply, extract_entities=False)
        await verify_messages(client, session_id, [prompt, reply])
    except Exception as exc:
        await client.reasoning.complete_trace(
            trace.id, success=False, outcome=f"Run failed: {type(exc).__name__}"
        )
        raise
    await client.reasoning.complete_trace(
        trace.id, success=True, outcome="Reply stored and read back"
    )
    stored = await client.reasoning.get_trace_with_steps(trace.id)
    if stored is None or stored.success is not True:
        raise RuntimeError(f"Trace readback failed for {trace.id}")
    print(f"Verified task trace: {trace.id}")
    return reply
Complete integrations/cloud_embeddings_recipe.py
Save as integrations/cloud_embeddings_recipe.py
"""Check the selected cloud embedder, then store and read back one message."""

import argparse
import asyncio
import os
from uuid import uuid4

from common import settings, verify_messages


def build_embedder(provider):
    if provider == "bedrock":
        from neo4j_agent_memory.llm.adapters.bedrock import BedrockEmbeddingProvider

        return BedrockEmbeddingProvider(
            "bedrock/amazon.titan-embed-text-v2:0", aws_region=os.environ["AWS_REGION"]
        )
    from neo4j_agent_memory.llm.adapters.vertex_ai import VertexAIEmbeddingProvider

    return VertexAIEmbeddingProvider(
        "vertex_ai/gemini-embedding-001",
        project_id=os.environ["GOOGLE_CLOUD_PROJECT"],
        location=os.environ["GOOGLE_CLOUD_LOCATION"],
        dimensions=768,
    )


async def verify_vectors(embedder):
    texts = ["A fictional workshop in Denver", "A fictional workshop in Boston"]
    vectors = await embedder.embed(texts)
    if len(vectors) != len(texts) or any(len(v) != embedder.dimensions for v in vectors):
        raise RuntimeError(
            "Embedding count or vector dimensions did not match the selected configuration"
        )
    print(f"Verified {len(vectors)} vectors of {embedder.dimensions} dimensions")


async def main(provider):
    from neo4j_agent_memory import MemoryClient

    embedder = build_embedder(provider)
    await verify_vectors(embedder)
    async with MemoryClient(settings(embedding=embedder)) as client:
        session_id = f"docs-{provider}-{uuid4().hex[:8]}"
        text = "The fictional workshop takes place in Denver."
        await client.short_term.add_message(session_id, "user", text, extract_entities=False)
        await verify_messages(client, session_id, [text])


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("provider", choices=["bedrock", "vertex"])
    asyncio.run(main(parser.parse_args().provider))

3. Run and verify persistence

python integrations/cloud_embeddings_recipe.py bedrock

Expected: Verified 2 vectors of 1024 dimensions, then stored-message verification. An access, throttling or model-availability error must be resolved before the persistence step; do not substitute a vector of a different dimension into an existing index.

Troubleshooting and cleanup

Stop when the program raises an exception; a printed model response alone does not verify persistence. Check the configured database, provider access and vector dimensions before retrying. The program prints the session or trace IDs needed for inspection and closes the client. Retained example records remain in the dedicated database; follow the Aura tutorial’s cleanup procedure for that dedicated instance only when you no longer need them. Reusing a session groups records; it does not authorize a user to read them.

Adapt the integration

BedrockEmbeddingProvider accepts the model string, aws_region, optional aws_profile or explicit keys, dimensions, batch_size and normalize, and delegates to BedrockEmbedder. In 0.7.0, dimensions only declares the vector size used to create the index; it is not sent to Bedrock, so leave it unset (Titan V2 returns 1024) unless it matches the model’s actual output. The provider’s embed() call coordinates individual Titan requests in bounded groups; it is not a promise that Titan accepts a 25-document payload. Embedding execution is a remote API operation, not a CPU-bound Lambda workload by definition.

The adapter contains mappings for Titan V1/V2 and Cohere embedding models. Mapping a model ID is not proof that it is available in every AWS region or account. Check access for the selected model instead of relying on a static region list. Provider error codes distinguish authentication, access, throttling and invalid configuration; changing regions blindly can make the mismatch worse.

See Use with Strands for agent integration and Configure embeddings before changing an existing vector model. The recipe passes the provider object as embedding= in the shared settings, so OpenAI credentials are not required here.

See Backend capabilities and scoping before adding hosted or multi-user behavior. Neo4j Agent Memory is a Neo4j Labs project with community support.