Published @ AWS Builder Center
In this post, we will implement an Agentic Retrieval-Augmented Generation (Agentic RAG) system on AWS using Terraform, Amazon S3, Amazon Bedrock Knowledge Bases (KB), Amazon OpenSearch Serverless, AWS Strands Agents, and Amazon Bedrock AgentCore Runtime.
If you are new to RAG or want to understand how to build the underlying infrastructure, please check out my previous post:
I won't cover the RAG implementation details again in this post.
Instead, we will focus on how to use AI agents to retrieve information from Amazon Bedrock Knowledge Bases and how to improve RAG quality by combining Reranker models and Agentic RAG.
We will explore how a reranker improves retrieval precision by selecting the most relevant document chunks, while an AI agent dynamically generates retrieval queries, evaluates the retrieved context with agent-as-tool, and performs additional retrievals when necessary to improve answer completeness.
TLDR: We will build on top of the existing Simple RAG architecture and extend it with a Reranker model and Agentic RAG using Strands Agents and Amazon Bedrock AgentCore Runtime.
What is Agentic RAG?
Agentic Retrieval-Augmented Generation (Agentic RAG) is an AI architecture that combines Retrieval-Augmented Generation (RAG) with autonomous AI agents. Unlike traditional RAG, where the retrieval process follows a predefined sequence of steps, Agentic RAG allows an AI agent to decide when to retrieve information, which tools to use, and how to use the retrieved information to answer a user's question.
An AI agent can interact with external knowledge sources, execute retrieval tools, evaluate the retrieved information, and perform additional searches when the initial results are insufficient. This enables more flexible, iterative, and context-aware information retrieval.
Document Ingestion
- Upload documents → Amazon S3
- Split documents → Chunks
- Generate embeddings → Embedding Model
- Store embeddings + text + metadata → Vector Database
Agentic-RAG Query & Retrieval with Agent/s
- User submits a question
- AI Agent receives and analyzes the question
- Agent decides whether external knowledge is required
- Agent selects and invokes the appropriate retrieval tool
- Retrieve relevant document chunks → Amazon Bedrock Knowledge Bases
- Agent evaluates the retrieved context by calling another agent as tool
- Agent decides whether additional retrieval is needed
- If necessary, performs additional searches or tool calls
- Agent combines the retrieved information and reasoning
- Generate the final answer with relevant citations
- Traditional RAG: Follows a predefined retrieval pipeline (retrieve → augment → generate).
-
Agentic RAG: The agent dynamically
controls the retrieval process(decide → retrieve → evaluate → iterate → generate).
In this project, Amazon S3 acts as the document source, while Amazon Bedrock Knowledge Bases (KB) manages the document ingestion pipeline.
When an ingestion job is triggered, the following steps take place:
- User uploads a document through the Streamlit UI.
- The application writes the document directly to the S3 docs bucket.
- User clicks Sync Knowledge Base in the UI.
- The application triggers
Bedrock's StartIngestionJob API. - Bedrock KB reads the documents from S3 and splits their content into smaller pieces called
chunks. - Bedrock KB
generates embeddingsfor each chunk using the configured embedding model (Titan Text Embeddings v2). - Bedrock KB
stores the resulting vectors, together with the original text and document metadata, in Amazon OpenSearch Serverless for vector search.
At query/retrieval time, instead of relying on a single retrieval operation, we use an AI agent built with Strands Agents and deployed on Amazon Bedrock AgentCore Runtime.
- User submits a question through the Streamlit chat input.
- The application invokes the AgentCore Runtime agent.
- The
agent analyzes the questionand generates a focusedretrieval query. - The agent calls its
retrieve_kb(query)tool, which invokes the Bedrock Knowledge Bases Retrieve API. - Bedrock KB performs a
vector searchagainst OpenSearch Serverless,retrieves 20 candidate chunks, and applies the configured Reranker model (Amazon Rerank 1.0) to select the 5 most relevant chunks. - The agent calls its
critique_context(question)tool to evaluate whether the retrieved information is sufficient to answer the original question. - If the context is insufficient, the agent identifies missing aspects, reformulates the retrieval query, and performs another retrieval.
- This retrieval and evaluation loop can run up to
3 retrieval callsper question. - Once sufficient context is collected, the agent generates the final answer using the retrieved document chunks and includes source citations.
If you have read this far, we can go deeper 😊
Why Combine Reranking and Agentic RAG?
The Reranker model and Agentic RAG improve different aspects of the retrieval process:
- Reranker, Improves Precision: Vector search retrieves candidate chunks based on embedding similarity. The reranker evaluates the question and candidate chunks together, re-scores their relevance, and selects the most useful chunks. In our implementation, it reduces 20 candidates to the best 5.
- Agentic RAG, Improves Recall: Instead of relying on a single retrieval, the agent can generate multiple focused queries, evaluate the retrieved context, identify missing information, and perform additional retrievals when necessary.
By combining both approaches, we aim to retrieve more complete information while ensuring that the most relevant document chunks are passed to the generation model.
The key difference is that Simple RAG performs a single retrieval and reranking operation, while Agentic RAG dynamically controls an iterative retrieval and evaluation process, applying reranking to every retrieval.
Code GitHub Link: Project on GitHub
Whether you're exploring to build your own system, this will give you a clear, practical starting point 😉
Table of Contents
- Terraform: Bedrock AgentCore, ECR, CloudWatch, Bedrock KnowledgeBase, OpenSearch Serverless, S3, IAM
- Agent Dockerfile, Agent.py
- Streamlit App: Digesting & Querying
- All Code & Demo
- Conclusion
- References
Terraform: Bedrock AgentCore, ECR, CloudWatch, Bedrock KnowledgeBase, OpenSearch Serverless, S3, IAM
Bedrock AgentCore, ECR-Repository, Agent-Core Runtime, Runtime IAM Policy:
# AWS ECR to store Agent Docker Image
resource "aws_ecr_repository" "agent" {
name = "${var.project_name}-agent"
image_tag_mutability = "MUTABLE"
force_delete = true
image_scanning_configuration {
scan_on_push = true
}
}
# IAM Policy for AgentCore Runtime
data "aws_iam_policy_document" "agent_runtime_trust" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["bedrock-agentcore.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "aws:SourceAccount"
values = [data.aws_caller_identity.current.account_id]
}
condition {
test = "ArnLike"
variable = "aws:SourceArn"
values = ["arn:aws:bedrock-agentcore:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"]
}
}
}
resource "aws_iam_role" "agent_runtime_execution" {
name = "${var.project_name}-agent-runtime-role"
assume_role_policy = data.aws_iam_policy_document.agent_runtime_trust.json
}
data "aws_iam_policy_document" "agent_runtime_permissions" {
statement {
sid = "BedrockModelInvoke"
effect = "Allow"
actions = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"]
resources = [
"arn:aws:bedrock:*::foundation-model/*",
"arn:aws:bedrock:*:${data.aws_caller_identity.current.account_id}:inference-profile/*",
]
}
statement {
sid = "KnowledgeBaseRetrieve"
effect = "Allow"
actions = ["bedrock:Retrieve"]
resources = [aws_bedrockagent_knowledge_base.this.arn]
}
# Retrieve calls with a rerankingConfiguration also need Rerank on the caller.
statement {
sid = "Rerank"
effect = "Allow"
actions = ["bedrock:Rerank"]
resources = ["*"]
}
statement {
sid = "EcrPull"
effect = "Allow"
actions = ["ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "ecr:BatchCheckLayerAvailability"]
resources = [aws_ecr_repository.agent.arn]
}
statement {
sid = "EcrAuth"
effect = "Allow"
actions = ["ecr:GetAuthorizationToken"]
resources = ["*"]
}
statement {
sid = "Logs"
effect = "Allow"
# PutResourcePolicy lets AgentCore deliver the agent's spans into its own log group.
actions = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams", "logs:PutResourcePolicy"]
resources = ["arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:log-group:/aws/bedrock-agentcore/*"]
}
statement {
sid = "LogsDescribe"
effect = "Allow"
actions = ["logs:DescribeLogGroups"]
resources = ["arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:log-group:*"]
}
statement {
sid = "Xray"
effect = "Allow"
actions = ["xray:PutTraceSegments", "xray:PutTelemetryRecords", "xray:GetSamplingRules", "xray:GetSamplingTargets"]
resources = ["*"]
}
# AgentCore Observability metrics (sessions, latency, tokens) from ADOT.
statement {
sid = "Metrics"
effect = "Allow"
actions = ["cloudwatch:PutMetricData"]
resources = ["*"]
condition {
test = "StringEquals"
variable = "cloudwatch:namespace"
values = ["bedrock-agentcore"]
}
}
}
resource "aws_iam_role_policy" "agent_runtime_permissions" {
name = "${var.project_name}-agent-runtime-permissions"
role = aws_iam_role.agent_runtime_execution.id
policy = data.aws_iam_policy_document.agent_runtime_permissions.json
}
# AgentCore Runtime
resource "aws_bedrockagentcore_agent_runtime" "agent" {
count = var.agent_container_image_uri == "" ? 0 : 1
agent_runtime_name = replace("${var.project_name}_agent", "-", "_")
role_arn = aws_iam_role.agent_runtime_execution.arn
agent_runtime_artifact {
container_configuration {
container_uri = var.agent_container_image_uri
}
}
network_configuration {
network_mode = "PUBLIC"
}
environment_variables = {
AWS_REGION = var.aws_region
KNOWLEDGE_BASE_ID = aws_bedrockagent_knowledge_base.this.id
GENERATION_MODEL_ID = var.generation_model_id
RERANK_MODEL_ARN = var.enable_reranking ? local.rerank_model_arn : ""
}
}
# AgentCore Observability, CloudWatch
resource "aws_cloudwatch_log_delivery_source" "agent_traces" {
count = length(aws_bedrockagentcore_agent_runtime.agent)
name = "${var.project_name}-agent-traces"
log_type = "TRACES"
resource_arn = aws_bedrockagentcore_agent_runtime.agent[0].agent_runtime_arn
}
resource "aws_cloudwatch_log_delivery_destination" "agent_traces" {
count = length(aws_bedrockagentcore_agent_runtime.agent)
name = "${var.project_name}-agent-traces"
delivery_destination_type = "XRAY"
}
resource "aws_cloudwatch_log_delivery" "agent_traces" {
count = length(aws_bedrockagentcore_agent_runtime.agent)
delivery_source_name = aws_cloudwatch_log_delivery_source.agent_traces[0].name
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.agent_traces[0].arn
}
IAM Policies for Bedrock KnowledgeBase, Bedrock Invoke Models:
data "aws_iam_policy_document" "bedrock_kb_trust" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["bedrock.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "aws:SourceAccount"
values = [data.aws_caller_identity.current.account_id]
}
}
}
resource "aws_iam_role" "bedrock_kb" {
name = "${var.project_name}-kb-role"
assume_role_policy = data.aws_iam_policy_document.bedrock_kb_trust.json
}
data "aws_iam_policy_document" "bedrock_kb_permissions" {
statement {
sid = "S3Read"
actions = ["s3:GetObject", "s3:ListBucket"]
resources = [aws_s3_bucket.docs.arn, "${aws_s3_bucket.docs.arn}/*"]
}
statement {
sid = "InvokeEmbeddingModel"
actions = ["bedrock:InvokeModel"]
resources = ["arn:aws:bedrock:${var.aws_region}::foundation-model/${var.embedding_model_id}"]
}
# Reranking inside a Retrieve call runs as this service role (not the caller).
statement {
sid = "Rerank"
actions = ["bedrock:Rerank"]
resources = ["*"]
}
statement {
sid = "InvokeRerankModel"
actions = ["bedrock:InvokeModel"]
resources = [local.rerank_model_arn]
}
statement {
sid = "OpenSearchServerlessAccess"
actions = ["aoss:APIAccessAll"]
resources = [aws_opensearchserverless_collection.kb.arn]
}
}
resource "aws_iam_role_policy" "bedrock_kb" {
name = "${var.project_name}-kb-policy"
role = aws_iam_role.bedrock_kb.id
policy = data.aws_iam_policy_document.bedrock_kb_permissions.json
}
S3 Bucket, Bucket Policy:
resource "aws_s3_bucket" "docs" {
bucket = var.docs_bucket_name != null ? var.docs_bucket_name : "${var.project_name}-docs-${data.aws_caller_identity.current.account_id}"
}
resource "aws_s3_bucket_versioning" "docs" {
bucket = aws_s3_bucket.docs.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_public_access_block" "docs" {
bucket = aws_s3_bucket.docs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
Bedrock KnowledgeBase for Vector Database Config (embedding model, embedding dimensions, opensearch serverless collection, chunking), Data Source (S3 Bucket, Vector Ingestion, Chunking Strategy):
locals {
generation_model_arn = "arn:aws:bedrock:${var.aws_region}:${data.aws_caller_identity.current.account_id}:inference-profile/${var.generation_model_id}"
embedding_model_arn = "arn:aws:bedrock:${var.aws_region}::foundation-model/${var.embedding_model_id}"
rerank_model_arn = "arn:aws:bedrock:${var.aws_region}::foundation-model/${var.rerank_model_id}"
}
resource "aws_bedrockagent_knowledge_base" "this" {
name = "${var.project_name}-kb"
role_arn = aws_iam_role.bedrock_kb.arn
knowledge_base_configuration {
type = "VECTOR"
vector_knowledge_base_configuration {
embedding_model_arn = local.embedding_model_arn
embedding_model_configuration {
bedrock_embedding_model_configuration {
dimensions = var.embedding_dimension
}
}
}
}
storage_configuration {
type = "OPENSEARCH_SERVERLESS"
opensearch_serverless_configuration {
collection_arn = aws_opensearchserverless_collection.kb.arn
vector_index_name = opensearch_index.kb_vector_index.name
field_mapping {
vector_field = "bedrock-knowledge-base-default-vector"
text_field = "AMAZON_BEDROCK_TEXT_CHUNK"
metadata_field = "AMAZON_BEDROCK_METADATA"
}
}
}
depends_on = [aws_iam_role_policy.bedrock_kb, time_sleep.wait_for_index]
}
resource "aws_bedrockagent_data_source" "docs" {
knowledge_base_id = aws_bedrockagent_knowledge_base.this.id
name = "${var.project_name}-docs-source"
data_source_configuration {
type = "S3"
s3_configuration {
bucket_arn = aws_s3_bucket.docs.arn
}
}
vector_ingestion_configuration {
chunking_configuration {
chunking_strategy = "FIXED_SIZE"
fixed_size_chunking_configuration {
max_tokens = var.chunk_max_tokens
overlap_percentage = var.chunk_overlap_percentage
}
}
}
}
OpenSearch Serverless Config for security (encryption, network), VectorDB config (embedding dimension, hnsw, faiss, knn_vector):
resource "aws_opensearchserverless_security_policy" "encryption" {
name = "${var.project_name}-encrypt"
type = "encryption"
policy = jsonencode({
Rules = [{
ResourceType = "collection"
Resource = ["collection/${var.project_name}-kb"]
}]
AWSOwnedKey = true
})
}
resource "aws_opensearchserverless_security_policy" "network" {
name = "${var.project_name}-network"
type = "network"
policy = jsonencode([{
Rules = [{
ResourceType = "collection"
Resource = ["collection/${var.project_name}-kb"]
}]
AllowFromPublic = true
}])
}
resource "aws_opensearchserverless_collection" "kb" {
name = "${var.project_name}-kb"
type = "VECTORSEARCH"
depends_on = [
aws_opensearchserverless_security_policy.encryption,
aws_opensearchserverless_security_policy.network,
]
}
resource "aws_opensearchserverless_access_policy" "kb" {
name = "${var.project_name}-access"
type = "data"
policy = jsonencode([{
Rules = [
{
ResourceType = "collection"
Resource = ["collection/${var.project_name}-kb"]
Permission = ["aoss:*"]
},
{
ResourceType = "index"
Resource = ["index/${var.project_name}-kb/*"]
Permission = ["aoss:*"]
}
]
Principal = [
aws_iam_role.bedrock_kb.arn,
var.admin_principal_arn != null ? var.admin_principal_arn : data.aws_caller_identity.current.arn,
]
}])
}
resource "time_sleep" "wait_for_access_policy" {
depends_on = [aws_opensearchserverless_access_policy.kb]
create_duration = "60s"
}
provider "opensearch" {
url = aws_opensearchserverless_collection.kb.collection_endpoint
healthcheck = false
aws_region = var.aws_region
sign_aws_requests = true
}
resource "opensearch_index" "kb_vector_index" {
name = "${var.project_name}-index"
index_knn = true
mappings = jsonencode({
properties = {
"bedrock-knowledge-base-default-vector" = {
type = "knn_vector"
dimension = var.embedding_dimension
method = {
name = "hnsw"
engine = "faiss"
space_type = "l2"
}
}
"AMAZON_BEDROCK_TEXT_CHUNK" = { type = "text" }
"AMAZON_BEDROCK_METADATA" = { type = "text", index = false }
}
})
# Bedrock adds its own metadata fields to the mapping during ingestion
# (x-amz-bedrock-kb-*). Without this, every later apply would see drift and
# replace the index, wiping all embeddings.
lifecycle {
ignore_changes = [mappings]
}
depends_on = [time_sleep.wait_for_access_policy]
}
resource "time_sleep" "wait_for_index" {
depends_on = [opensearch_index.kb_vector_index]
create_duration = "30s"
}
Also, app_config.tf, providers.tf, variables.tf, output.tf implemented, you can reach from => Terraform Codes. We can run these TF files with terraform plan, apply, destroy.
Agent Dockerfile, Agent.py
Agent runs on Bedrock AgentCore as container. It has agent tools as functions: retrieve_kb(query: str), critique_context(question: str). It generally retrieves and reranks the chunks of data.
To run on Agentcore, needs to create Docker image with Arm64 based.
FROM --platform=linux/arm64 python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
# opentelemetry-instrument (ADOT) sends traces to AgentCore Observability.
CMD ["opentelemetry-instrument", "python3", "agent.py", "--serve"]
Only here the main part, please have a look from here for the details: Agent Code
Agent, System Prompt, Tools:
def run(question: str) -> dict:
state: dict = {"question": question, "trace": [], "chunks": []}
agent = Agent(
model=BedrockModel(
model_id=_config()["model_id"], temperature=0.2, region_name=_config()["region"]
),
tools=_make_tools(state),
system_prompt=(
"You are an agentic RAG assistant. Answer the user's question ONLY "
"using information retrieved via retrieve_kb.\n\n"
"Process:\n"
"1. Call retrieve_kb with a focused query. For compound questions "
"covering multiple topics, call it once per topic.\n"
"2. Call critique_context(question) to check if you have enough to "
"answer fully.\n"
"3. If not sufficient and you still have retrieval budget, "
"reformulate the query (or target a missing aspect) and retrieve "
"again, then critique again.\n"
"4. Once sufficient, or your retrieval budget is exhausted "
f"(max {MAX_RETRIEVALS} retrieve_kb calls total), write the final "
"answer using only retrieved content, citing sources by URI. If "
"nothing relevant was found, say so plainly instead of guessing."
),
)
answer = str(agent(question)).strip()
sources = sorted({c["uri"] for c in state["chunks"] if c["uri"]})
return {"answer": answer, "citations": sources, "trace": state["trace"]}
Agent Main:
if __name__ == "__main__":
if "--serve" in sys.argv:
from bedrock_agentcore.runtime import BedrockAgentCoreApp
app = BedrockAgentCoreApp()
@app.entrypoint
def _invoke(payload: dict, context=None) -> dict:
question = payload.get("question") or payload.get("prompt") or DEFAULT_QUESTION
result = run(question)
result["runtime"] = {
"session_id": getattr(context, "session_id", None),
"host": socket.gethostname(),
}
return result
app.run()
else:
result = run(" ".join(sys.argv[1:]) or DEFAULT_QUESTION)
print(json.dumps(result, indent=2))
Streamlit App: Uploading, Digest & Querying
App has 4 main parts as utils: agentcore_ops.py, aws_clients.py, bedrock_ops.py, s3_ops.py.
App Code that includes utils and main: App Code
Start_ingestion_job, get_ingestion_job_status, querying, vector_search with reranker model: bedrock-ops.py:
from utils.aws_clients import get_bedrock_agent_client, get_bedrock_agent_runtime_client, get_config
NUM_CANDIDATES = 20
NUM_RESULTS = 5
def start_ingestion_job() -> str:
cfg = get_config()
resp = get_bedrock_agent_client().start_ingestion_job(
knowledgeBaseId=cfg["knowledge_base_id"],
dataSourceId=cfg["data_source_id"],
)
return resp["ingestionJob"]["ingestionJobId"]
def get_ingestion_job_status(job_id: str) -> dict:
cfg = get_config()
resp = get_bedrock_agent_client().get_ingestion_job(
knowledgeBaseId=cfg["knowledge_base_id"],
dataSourceId=cfg["data_source_id"],
ingestionJobId=job_id,
)
job = resp["ingestionJob"]
return {"status": job["status"], "failure_reasons": job.get("failureReasons", [])}
def _vector_search_configuration() -> dict:
rerank_model_arn = get_config()["rerank_model_arn"]
if not rerank_model_arn:
return {"numberOfResults": NUM_RESULTS}
return {
"numberOfResults": NUM_CANDIDATES,
"rerankingConfiguration": {
"type": "BEDROCK_RERANKING_MODEL",
"bedrockRerankingConfiguration": {
"modelConfiguration": {"modelArn": rerank_model_arn},
"numberOfRerankedResults": NUM_RESULTS,
},
},
}
def query(question: str) -> dict:
cfg = get_config()
resp = get_bedrock_agent_runtime_client().retrieve_and_generate(
input={"text": question},
retrieveAndGenerateConfiguration={
"type": "KNOWLEDGE_BASE",
"knowledgeBaseConfiguration": {
"knowledgeBaseId": cfg["knowledge_base_id"],
"modelArn": cfg["generation_model_arn"],
"retrievalConfiguration": {
"vectorSearchConfiguration": _vector_search_configuration(),
},
},
},
)
citations = []
for citation in resp.get("citations", []):
for ref in citation.get("retrievedReferences", []):
uri = ref.get("location", {}).get("s3Location", {}).get("uri")
if uri:
citations.append(uri)
return {"answer": resp["output"]["text"], "citations": citations}
Query Agentic from agentcore_ops.py:
def query_agentic(question: str, session_id: str) -> dict:
cfg = get_config()
if not is_agentic_configured():
raise RuntimeError(
"AGENT_RUNTIME_ARN is not a Bedrock AgentCore runtime ARN. Deploy the agent "
"with ./deploy.sh; it writes the ARN into app/.env."
)
# The same runtimeSessionId for every question in one browser session, so
# AgentCore Observability groups them as one session.
started = time.monotonic()
resp = get_bedrock_agentcore_client().invoke_agent_runtime(
agentRuntimeArn=cfg["agent_runtime_arn"],
runtimeSessionId=session_id,
qualifier="DEFAULT",
payload=json.dumps({"question": question}).encode(),
)
result = json.loads(resp["response"].read())
# Proof of execution on AgentCore: IDs returned by the AWS API, plus what
# the agent reported from inside its container.
result["agentcore"] = {
"runtime_arn": cfg["agent_runtime_arn"],
"session_id": resp.get("runtimeSessionId", session_id),
"trace_id": resp.get("traceId"),
"request_id": resp["ResponseMetadata"]["RequestId"],
"status_code": resp.get("statusCode"),
"latency_s": round(time.monotonic() - started, 1),
"container": result.pop("runtime", None),
"console_url": (
f"https://{cfg['region']}.console.aws.amazon.com/bedrock-agentcore/observability"
f"?region={cfg['region']}"
),
}
return result
All Code & Demo
GitHub Link: Project on GitHub
Deploy.sh includes image build, push to ECR.
Details: deploy.sh
Run:
./deploy.sh
All images with better resolution
After applying the TF, view/copy outputs to link with app.py:

Uploading files (popular latest GenAI papers under docs/pdf):

DON't Forget to delete Resources:
Run:
./deploy.sh destroy
Conclusion
In this post, we mentioned:
- how to create Agentic RAG using Bedrock AgentCore, Agent DockerImage, ECR, Bedrock KnowledgeBase, S3, OpenSearch Serverless with Terraform,
- how to digest, query using simple streamlit app with embedding and reranker models,
- how agent calls agent-as-tool for critique evaluation,
- how to enable with permission roles,
- how to use AWS Claude models (e.g. Sonnet).
If you found the tutorial interesting, I’d love to hear your thoughts in the blog post comments. Feel free to share your reactions or leave a comment. I truly value your input and engagement 😉
For other posts 👉 https://dev.to/omerberatsezer 🧐
References
Your comments 🤔
I’d love to hear your experience and know-how.
- Do you know the detail of RAG that handled by Bedrock Knowledge Base
- How do you implement your RAG in production (e.g. Bedrock, LlamaIndex, LangChain, etc.)?
Drop your thoughts, feedback, or improvements in the comments, always curious to learn from different approaches. ☺️






Top comments (0)