Building Production AI Agents: Lessons from Claude Code and Enterprise Deployments
anthropic · Tech · 2025 · source Agentic: no · promotional bias: med · source-backed · extracted with prompt 0.5.5 (schema v2)
Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.
Problem
Domain: Multi-tenant RAG knowledge bases for SaaS
The fetched source is an AWS chalk talk about cost-efficient, multi-tenant knowledge bases, not the Anthropic Claude Code case described in the metadata summary. The actual technical problem is how a SaaS application can let different tenants ingest and chat with documents while preserving tenant isolation, balancing latency/cost tiers, supporting multiple vector stores, and cleaning up stale indexed data.
Constraints:
- Tenant data must not spill across tenant boundaries during search or chat.
- Tenants may need different cost, latency, query-rate, capacity, and retention profiles.
- OpenSearch, pgVector/Aurora, and S3 Vector have different cost/latency/structured-data tradeoffs.
- The application should not need separate query code for every vector store.
- Document metadata must carry tenant, user, and file filters through ingestion and retrieval.
- Vector-store indexes need lifecycle cleanup when documents expire or are manually removed.
Architecture
The architecture uses a Bedrock Knowledge Bases abstraction in front of multiple vector-store backends. Users authenticate through Cognito, which places tenant identity into the JWT. A Lambda backend uses the tenant/user identity to ingest files from S3 into a custom Bedrock knowledge-base data source with metadata such as tenant ID, user ID, and file ID. Retrieval builds the same metadata filter in reverse, then calls Bedrock Agent Runtime retrieve-and-generate so query code does not need to know whether the backend is OpenSearch, Aurora/pgVector, or S3 Vector. A DynamoDB record tracks file ID, data source, knowledge base, and TTL; DynamoDB Streams trigger deletion from the knowledge base when the record expires or is removed.
Diagram confidence: explicit (topology described by the source).
flowchart LR tenant-user-interface["Tenant user interface"] --> cognito-identity-layer["Cognito identity layer"] tenant-user-interface --> lambda-backend["Lambda backend"] cognito-identity-layer --> lambda-backend lambda-backend --> s3-source-files["S3 source files"] lambda-backend --> bedrock-knowledge-base["Bedrock Knowledge Base"] lambda-backend --> dynamodb-ttl-index["DynamoDB TTL index"] bedrock-knowledge-base --> opensearch-vector-store["OpenSearch vector store"] bedrock-knowledge-base --> aurora-pgvector-store["Aurora pgVector store"] bedrock-knowledge-base --> s3-vector-bucket["S3 Vector bucket"] dynamodb-ttl-index --> dynamodb-streams-cleanup["DynamoDB Streams cleanup"] dynamodb-streams-cleanup --> bedrock-knowledge-base
Components
| Component | Role | Interacts with |
|---|---|---|
Tenant user interface |
Lets tenant users select files, ingest them, and chat with indexed documents. | Cognito identity layer, Lambda backend |
Cognito identity layer |
Authenticates users and places tenant membership into the JWT. | Tenant user interface, Lambda backend |
Lambda backend |
Runs ingestion, query, and cleanup logic using tenant/user/file metadata. | Cognito identity layer, S3 source files, Bedrock Knowledge Base, DynamoDB TTL index |
S3 source files |
Stores uploaded tenant documents and can retain originals after vector cleanup. | Lambda backend |
Bedrock Knowledge Base |
Abstracts retrieval and generation over the configured vector-store backend. | Lambda backend, OpenSearch vector store, Aurora pgVector store, S3 Vector bucket |
OpenSearch vector store |
Low-latency, hybrid-search vector backend for tenants that value performance. | Bedrock Knowledge Base |
Aurora pgVector store |
Low-latency vector backend integrated with structured Postgres data. | Bedrock Knowledge Base |
S3 Vector bucket |
Pay-per-query/pay-per-storage vector backend with higher latency and lower provisioned cost. | Bedrock Knowledge Base |
DynamoDB TTL index |
Tracks indexed file records, expiration, knowledge base ID, data source ID, and file ID. | Lambda backend, DynamoDB Streams cleanup |
DynamoDB Streams cleanup |
Triggers deletion of expired or manually removed file records from the knowledge base. | DynamoDB TTL index, Bedrock Knowledge Base |
Data flow
A tenant user logs into the UI through Cognito. The JWT carries the tenant ID to a Lambda function. During ingestion, selected S3 files are converted into custom data-source documents with file location and metadata for tenant/user/file filtering, then inserted into the relevant Bedrock knowledge base backed by the tenant's vector store. During chat, the Lambda builds a filter expression using the tenant ID, user ID, and selected file IDs, passes that filter in retrieval parameters, and calls Bedrock Agent Runtime retrieve-and-generate. A DynamoDB TTL record later drives cleanup by deleting indexed file records from the knowledge base while leaving the original S3 file available for re-ingestion.
4 supporting quotes
Why this architecture
The design puts Bedrock Knowledge Bases between application code and vector stores so tenants can use different backends without separate application logic. Tenant isolation is enforced through Cognito-derived metadata and retrieval filters rather than relying on prompts. DynamoDB TTL and streams provide a flexible lifecycle mechanism for expiring vector records while preserving source files.
4 supporting quotes
Models used: Amazon Bedrock LLM · Bedrock embedding model · Bedrock Agent Runtime retrieve-and-generate
Scale
- The talk explicitly targets cost-efficient multi-tenant knowledge bases.“we are going to talk about cost-efficient, multi-tenant knowledge bases.”transcript, stated
- OpenSearch is presented as very low latency with provisioned cost.“OpenSearch is a very popular vector store for the customers that I work with. It's very low latency.”transcript, stated
- S3 Vector is positioned as pay-per-query/pay-per-storage with higher latency per query.“you only pay for what you use, you pay per query, and for the data that's being stored.”transcript, stated“that does come at the cost of higher latency per query.”transcript, stated
- The demo contrasts Tenant A on S3 Vector and Tenant C on OpenSearch with more capacity and longer expiration.“Tenant A, which is an S3 vector store.”transcript, stated“Tenant C's on OpenSearch. They've got a lot more files they're allowed to ingest, a lot more file usage.”transcript, stated
- The cleanup example mentions expiration windows such as eight minutes, eight days, or 24 hours.“There's a, you know, it's an eight minute window, or eight day window or a day window, 24 hours, whatever it is.”transcript, stated
- An audience question reports OpenSearch document listing timing out with greater than about 10 documents.“that kind of times out if you have like even greater than like 10 documents or something.”transcript, stated
Alternatives considered (roads not taken)
Talk directly to each vector store.
Rejected because: That would require store-specific ingestion/query/filtering code for OpenSearch, pgVector, S3 Vector, and future stores.
3 supporting quotes
Use a single vector store for every tenant.
Rejected because: Different tenants need different latency, cost, structured-data, and retention tradeoffs.
Rely on prompts for tenant isolation.
Rejected because: Prompt injection should not be able to bypass metadata filters and tenant-scoped retrieval.
Bulk ingest everything from S3 whenever files exist.
Rejected because: The demo needs custom per-file ingestion and metadata so tenants can select files, apply retention, and clean indexes independently.
Patterns
rag-retrieval (retrieval)
The application ingests tenant-selected documents into Bedrock Knowledge Bases and calls retrieve-and-generate for tenant-scoped chat over those documents.
3 supporting quotes
hybrid-search (retrieval)
OpenSearch is called out as a backend that supports hybrid semantic and keyword search for tenants needing low-latency retrieval.
safety-policy-enforcement (security)
Tenant isolation is enforced through Cognito identity, tenant/user/file metadata at ingestion, and retrieval filters at query time.
3 supporting quotes
cost-aware-routing (operations)
Tenant tiers can map to vector stores with different provisioned cost, pay-per-query cost, latency, capacity, and query-rate profiles.
3 supporting quotes
data-quality-loop (data_lifecycle)
DynamoDB TTL and streams clean indexed vector records as documents expire or are manually deleted, keeping retrieval data fresh and reducing vector-store usage.
3 supporting quotes
Tradeoffs
Route tenants to different vector-store backends.
Chose OpenSearch, pgVector/Aurora, or S3 Vector based on tenant tier and workload over One universal vector store.
Rationale: This lets free/evaluation tiers optimize for pay-per-use while established customers can buy lower latency.
3 supporting quotes
Use Bedrock Knowledge Bases as an abstraction layer.
Chose One metadata/filter/query interface across stores over Store-specific query and ingestion code.
Rationale: The application can add tenant-specific stores without changing the retrieve-and-generate query path.
Use custom per-file data-source ingestion.
Chose Explicit custom documents with metadata and selected S3 file identifiers over Blind bulk S3 ingestion.
Rationale: Custom ingestion supports tenant/user/file filtering, selective indexing, and per-document lifecycle behavior.
Delete vector records while retaining source files.
Chose DynamoDB TTL-driven index cleanup only over Deleting original S3 files on expiration.
Rationale: The tenant can remove vector-store usage/cost while keeping source files available for re-ingestion.
Gotchas (what bit them)
The fetched transcript does not match the metadata summary.
Root cause: The transcript begins as an AWS SAS 412 chalk talk on multi-tenant knowledge bases rather than the Anthropic Claude Code enterprise-agent talk described in the summary.
Resolution: Treat the fetched transcript as authoritative for this extraction and mark the case as non-agentic/source-mismatched rather than inventing Claude Code claims.
Tenant isolation cannot be left to prompt behavior.
Root cause: A multi-tenant RAG system must prevent retrieval from another tenant even if the user asks or injects instructions.
Resolution: Store tenant/user/file metadata during ingestion and apply matching filter expressions during retrieval.
Vector-store choice affects cost, latency, and structured-data access.
Root cause: OpenSearch, pgVector, and S3 Vector have different pricing models, latency profiles, and data-model affordances.
Resolution: Abstract vector stores behind Bedrock Knowledge Bases while allowing tenant tiers to use different backends.
3 supporting quotes
Embedding and chunking can dominate retrieval quality.
Root cause: Accuracy depends heavily on data type, data size, embedding model, and chunking strategy, not just the vector database.
Resolution: Run performance tests on each customer's real data and tune embedding/chunking choices per knowledge base.
Chat context can grow after document updates.
Root cause: If users continue a chat while documents and embeddings change, prior conversation context still has to be passed forward and can lengthen.
Resolution: The talk points to summarization/compaction patterns but does not provide a complete solution.
3 supporting quotes
Evaluation
The talk does not present formal model evaluation results. It recommends tenant/workload-specific performance testing for vector-store, embedding, and chunking choices, and discusses latency/cost/accuracy tradeoffs qualitatively.
Metrics: Latency per query · Provisioned cost versus pay-per-query cost · Search quality from embedding and chunking choices · File capacity and file usage per tenant · Query rate per tenant · Expiration period per tenant · Document listing latency
4 supporting quotes
Outcomes
- The demo shows tenant-scoped document ingestion and chat over files with Tenant A on S3 Vector and Tenant C on OpenSearch.
- Bedrock Knowledge Bases abstracts retrieval across OpenSearch, Aurora/pgVector, and S3 Vector backends.
- Tenant isolation is enforced with Cognito JWT tenant identity plus tenant/user/file metadata filters.
- DynamoDB TTL and streams provide index lifecycle cleanup without deleting original S3 files.
- The source content is mismatched with the project metadata, so this extraction should be treated as a source-mismatch/non-agentic RAG case.
The source provides qualitative multi-tenant scale rather than production volume numbers. It discusses free/evaluation tiers versus established low-latency tenants, OpenSearch/pgVector/S3 Vector backend choices, per-tenant file usage/query-rate/expiration differences, example expiration windows of eight minutes/eight days/24 hours, and a reported timeout when listing more than about 10 documents in one audience member's OpenSearch Serverless setup.