Skip to content

Bedrock Knowledge Base Store

BedrockKnowledgeBaseStore is a MemoryStore backed by Amazon Bedrock Knowledge Bases.

Connect the store to a knowledge base you have already set up. Configure your store with its knowledge base ID and data source (see Data Source Types and Writability). A store with only a knowledge base ID is read-only. The store reaches Bedrock with the standard AWS credential chain, the same as the Amazon Bedrock model provider.

from strands import Agent
from strands.memory import MemoryManager
from strands.vended_memory_stores import BedrockKnowledgeBaseStore
store = BedrockKnowledgeBaseStore(
name="docs",
description="Company documentation and policies.",
config={"knowledge_base_id": "KB123"},
)
agent = Agent(memory_manager=MemoryManager(stores=[store]))

To enable writing memories through the add_memory tool or automatic extraction, mark the store writable and point it at a data source that accepts ingestion:

from strands.vended_memory_stores import BedrockKnowledgeBaseStore
store = BedrockKnowledgeBaseStore(
name="preferences",
description="User preferences and stable facts.",
writable=True,
config={
"knowledge_base_id": "KB123",
"data_source_type": "CUSTOM",
"data_source_id": "DS456",
},
)

scope isolates documents within a single knowledge base. It is stamped on every write (under scope_metadata_key scopeMetadataKey , default 'namespace') and applied as a metadata filter on search. Unlike name, scope is not a routing identity, so it never affects which store the MemoryManager targets. For per-tenant isolation, construct one store per scope; since they share a connection, this is cheap.

The outer BedrockKnowledgeBaseStoreConfig carries the per-store identity and behavior, plus the shared MemoryStore fields (name, description, max_search_results maxSearchResults , writable, extraction):

FieldPurpose
configThe knowledge base connection (see below). Reuse one across stores that differ only by scope.
scopeLogical namespace isolating documents. Applied as a metadata filter on search and stamped on writes.
filterExplicit retrieval filter; overrides the auto-generated scope filter on search.

The inner BedrockKnowledgeBaseConfig is the reusable connection: which knowledge base, which data source, and the clients used to reach them:

FieldPurpose
knowledge_base_id knowledgeBaseId The Bedrock Knowledge Base to query and ingest into. Required.
data_source_type dataSourceType 'CUSTOM', 'S3', or 'OTHER'. Governs whether and how the store can be written to.
data_source_id dataSourceId The data source to ingest into. Required for writes.
s3S3 ingestion settings (bucket, prefix). Required when the data source type is 'S3'.
scope_metadata_key scopeMetadataKey Metadata attribute key used for scope filtering. Defaults to 'namespace'.
runtime_client / agent_client runtimeClient / agentClient Pre-constructed AWS clients. When omitted, default clients are constructed using the standard credential chain (the agent client lazily, on first write).

Because the connection is a separate object, you build it once and vary only name and scope per store. This is the cheap way to give each tenant an isolated namespace over a single knowledge base:

from strands.vended_memory_stores import BedrockKnowledgeBaseStore
# Build the connection once, vary only name and scope per store.
connection = {
"knowledge_base_id": "KB123",
"data_source_type": "CUSTOM",
"data_source_id": "DS456",
}
alice = BedrockKnowledgeBaseStore(name="alice", writable=True, scope="user-alice", config=connection)
bob = BedrockKnowledgeBaseStore(name="bob", writable=True, scope="user-bob", config=connection)

Only data sources that accept direct ingestion can be written to. A store is writable only when you opt in and the backend supports ingestion: that is, the store is marked writable and the data source type is 'CUSTOM' or 'S3'.

Data source typeWritableHow writes work
CUSTOMYesIngests the content as inline text, with scope and metadata attached as inline attributes.
S3YesUploads the content to the configured s3 bucket and ingests that object. Requires an s3 config.
OTHERNoExternal backends such as Confluence, SharePoint, Salesforce, Web, or SQL/Redshift that sync from their own source or are query-only. Read-only.
omittedNoRead-only.

A writable CUSTOM store needs a data source ID. A writable S3 store needs a data source ID and an s3 config:

from strands.vended_memory_stores import BedrockKnowledgeBaseStore
store = BedrockKnowledgeBaseStore(
name="preferences",
writable=True,
config={
"knowledge_base_id": "KB123",
"data_source_type": "S3",
"data_source_id": "DS789",
"s3": {"bucket": "my-agent-memories", "prefix": "memories/"},
},
)

An S3 document can’t carry metadata inline, so when a scope or metadata are present a single write produces two objects: the content as a .txt object, and a <object-key>.metadata.json sidecar beside it (Bedrock’s convention for attaching attributes to an S3 object). The uploads are not transactional, so if a later step fails, any already-uploaded objects remain in the bucket un-ingested, where a future sync may pick them up or you can clean them up out of band.

A write ingests its object directly, regardless of where the data source is configured to scan. A later data-source sync reconciles the index to the scanned location, so a memory written outside that location is treated as deleted and removed. If you run periodic syncs against this data source, upload to the bucket and prefix it scans (the s3 config) so directly-ingested memories survive them.

search runs the Bedrock Retrieve API and returns entries ordered by relevance, while add ingests new content and returns its document id:

from strands.memory.types import SearchOptions
from strands.vended_memory_stores import BedrockKnowledgeBaseStore
store = BedrockKnowledgeBaseStore(
name="preferences",
writable=True,
config={
"knowledge_base_id": "KB123",
"data_source_type": "CUSTOM",
"data_source_id": "DS456",
},
)
results = await store.search("what are my preferences?", SearchOptions(max_search_results=5))
for entry in results:
print(entry.content, entry.metadata.get("_relevance_score"))
# add returns the new document's id (a UUID for CUSTOM, an s3:// URI for S3)
result = await store.add("User prefers aisle seats", {"category": "travel"})
print(result.document_id)

The search result cap defaults to 10 when neither the call nor the store sets one. This 10 default applies only to direct calls on the store. Reached through a MemoryManager tool or its search method, the manager supplies its own per-call cap instead; set max_search_results maxSearchResults on the store to pin a value across both paths.

Each entry’s metadata carries the document’s own attributes plus two reserved synthetic keys: _relevance_score _relevanceScore (the Bedrock relevance score) and _source_location _sourceLocation (the retrieval location). When scope is set, search filters to that namespace automatically; an explicit filter overrides the scope-derived one. The asymmetry is deliberate: an explicit filter affects search only, while writes always scope by scope.

The document id from add is the generated UUID for a CUSTOM document, or the s3:// URI of the uploaded object for S3. Writes require a data source ID (and an s3 config for S3 data sources); a write against a missing or read-only configuration raises.

Ingestion is eventually consistent: a successful write does not mean the content is immediately searchable.

Enable automatic extraction on a writable store to capture memories from the conversation. By default it runs every 5 turns, distilling facts client-side with a ModelExtractor that uses the agent’s own model:

from strands.vended_memory_stores import BedrockKnowledgeBaseStore
store = BedrockKnowledgeBaseStore(
name="preferences",
writable=True,
extraction=True,
config={
"knowledge_base_id": "KB123",
"data_source_type": "CUSTOM",
"data_source_id": "DS456",
},
)

To change the cadence, swap the extractor, or extract server-side, see Automatic Extraction on the Memory page.

The credentials the store uses must allow the Bedrock operations it calls, plus S3 writes when using an S3 data source:

  • bedrock:Retrieve - for search.
  • bedrock:IngestKnowledgeBaseDocuments - for writes (CUSTOM and S3).
  • s3:PutObject - for writes to an S3 data source, on the configured bucket and prefix.

Here is a sample IAM policy for a writable store backed by a CUSTOM data source:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:Retrieve",
"bedrock:IngestKnowledgeBaseDocuments"
],
"Resource": "arn:aws:bedrock:*:*:knowledge-base/KB123"
}
]
}

For an S3 data source, add s3:PutObject on the bucket and prefix the store uploads to:

{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-agent-memories/memories/*"
}
  • Memory - the MemoryManager concept this store plugs into, including the tools, extraction, and injection it enables.
  • Amazon Bedrock - credential and region setup shared with the Bedrock model provider.