What if you could build an AI assistant with access to your own data in under 40 lines of Java? That's now possible with my contribution to the just-released Spring AI 2.0.0 M2 - Amazon Bedrock Knowledge Base support. It's a fully managed RAG (Retrieval-Augmented Generation) service that handles document ingestion, embeddings, and vector storage for you - and now you can use it with Spring AI!
RAG lets AI models answer questions using your own documents instead of relying solely on their training data.
In this post, I'll show you how to build a working AI agent with RAG in minutes using JBang - no Maven project setup required. You'll have an AI assistant answering questions from your company documents with minimal code.
Why Bedrock Knowledge Base?
Three things make this integration compelling:
- Fully Managed: AWS handles document chunking, embeddings, and vector storage. No PGVector or OpenSearch to manage.
- Read-Only from Spring AI: Documents sync via AWS - your app just queries. Simple.
- Fast Setup: Connect S3, Confluence, or SharePoint as data sources. Sync and go.
Key features:
- Search Types: SEMANTIC uses vector similarity; HYBRID combines semantic with keyword search for better recall
- Reranking: Re-scores results using Bedrock reranking models to surface the most relevant documents
-
Metadata Filtering: Narrows results by document attributes (e.g.,
department == 'HR' && year >= 2024) - Similarity Threshold: Filters out low-relevance matches below a minimum score
For full configuration options, see the Spring AI Bedrock Knowledge Base documentation.
Prerequisites
You'll need:
- Java 21+ (Amazon Corretto 21)
- AWS CLI configured with Bedrock access
- JBang installed
What is JBang?
JBang lets you run Java files directly - no pom.xml, no project structure. Perfect for quick experiments and demos. Dependencies are declared as comments in the source file.
Install JBang:
# macOS
brew install jbang
# Linux/Windows
curl -Ls https://sh.jbang.dev | bash -s - app setup
AWS Credentials
Configure AWS CLI with credentials that have Bedrock access:
aws configure
Verify access:
aws bedrock list-foundation-models --query 'modelSummaries[0].modelId' --output text
The Knowledge Base
Let's create a Knowledge Base with sample company policies. Copy and run in terminal:
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text --no-cli-pager)
BUCKET="kb-demo-${ACCOUNT_ID}"
VECTOR_BUCKET="kb-demo-vectors-${ACCOUNT_ID}"
# Buckets
aws s3 mb s3://${BUCKET} --no-cli-pager 2>/dev/null || true
aws s3vectors create-vector-bucket --vector-bucket-name ${VECTOR_BUCKET} --no-cli-pager 2>/dev/null || true
aws s3vectors create-index --vector-bucket-name ${VECTOR_BUCKET} --index-name kb-demo-index \
--data-type float32 --dimension 1024 --distance-metric cosine --no-cli-pager 2>/dev/null || true
# Sample policies
echo "Travel: Europe accommodation €130/night. Manager approval required." | aws s3 cp - s3://${BUCKET}/travel.txt --no-cli-pager
echo "IT: Home office budget \$500/year. VPN required for remote work." | aws s3 cp - s3://${BUCKET}/it.txt --no-cli-pager
# IAM role
aws iam create-role --role-name kb-demo-role --no-cli-pager \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"bedrock.amazonaws.com"},"Action":"sts:AssumeRole"}]}' 2>/dev/null || true
aws iam attach-role-policy --role-name kb-demo-role --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess --no-cli-pager 2>/dev/null || true
aws iam attach-role-policy --role-name kb-demo-role --policy-arn arn:aws:iam::aws:policy/AmazonBedrockFullAccess --no-cli-pager 2>/dev/null || true
aws iam put-role-policy --role-name kb-demo-role --policy-name s3vectors \
--policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"s3vectors:*\",\"Resource\":\"arn:aws:s3vectors:us-east-1:${ACCOUNT_ID}:bucket/${VECTOR_BUCKET}/*\"}]}" --no-cli-pager
sleep 10
# Knowledge Base
KB_ID=$(aws bedrock-agent create-knowledge-base --name kb-demo --role-arn arn:aws:iam::${ACCOUNT_ID}:role/kb-demo-role \
--knowledge-base-configuration '{"type":"VECTOR","vectorKnowledgeBaseConfiguration":{"embeddingModelArn":"arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0"}}' \
--storage-configuration "{\"type\":\"S3_VECTORS\",\"s3VectorsConfiguration\":{\"vectorBucketArn\":\"arn:aws:s3vectors:us-east-1:${ACCOUNT_ID}:bucket/${VECTOR_BUCKET}\",\"indexName\":\"kb-demo-index\"}}" \
--no-cli-pager --query 'knowledgeBase.knowledgeBaseId' --output text)
sleep 30
DS_ID=$(aws bedrock-agent create-data-source --knowledge-base-id ${KB_ID} --name policies \
--data-source-configuration "{\"type\":\"S3\",\"s3Configuration\":{\"bucketArn\":\"arn:aws:s3:::${BUCKET}\"}}" \
--no-cli-pager --query 'dataSource.dataSourceId' --output text)
aws bedrock-agent start-ingestion-job --knowledge-base-id ${KB_ID} --data-source-id ${DS_ID} --no-cli-pager >/dev/null
echo "KB: ${KB_ID}"
This creates:
- S3 bucket with two policy documents
- S3 Vectors bucket for vector storage
- IAM role for Bedrock to access your data
- Knowledge Base with Titan embeddings
- Data source pointing to your S3 bucket
The script uses S3 Vectors - a cost-effective serverless vector storage option. You can also use OpenSearch Serverless or Aurora PostgreSQL.
The Application
Here's the complete AI agent - 40 lines of Java. Save as KbAgent.java:
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.springframework.boot:spring-boot-starter-web:4.0.1
//DEPS org.springframework.ai:spring-ai-starter-model-bedrock-converse:2.0.0-M2
//DEPS org.springframework.ai:spring-ai-starter-vector-store-bedrock-knowledgebase:2.0.0-M2
//DEPS org.springframework.ai:spring-ai-advisors-vector-store:2.0.0-M2
//JAVA_OPTIONS -Dspring.ai.bedrock.aws.region=us-east-1
//JAVA_OPTIONS -Dspring.ai.bedrock.converse.chat.options.model=global.anthropic.claude-sonnet-4-20250514-v1:0
package com.example;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@RestController
public class KbAgent {
private final ChatClient chatClient;
public KbAgent(ChatClient.Builder builder, VectorStore vectorStore) {
this.chatClient = builder
.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore).build())
.build();
}
@PostMapping("/chat")
public String chat(@RequestBody String prompt) {
return chatClient.prompt().user(prompt).call().content();
}
public static void main(String[] args) {
SpringApplication.run(KbAgent.class, args);
}
}
That's it. The JBang header declares dependencies, Spring AI auto-configures the VectorStore bean from the environment variable, and QuestionAnswerAdvisor handles RAG automatically.
Key Points
- No EmbeddingModel needed: Unlike PGVector, Bedrock KB handles embeddings internally. If you'd like to build RAG with PostgreSQL and PGVector instead, check out my previous post.
-
Auto-configuration: Just set
SPRING_AI_VECTORSTORE_BEDROCK_KNOWLEDGE_BASE_KNOWLEDGE_BASE_ID - QuestionAnswerAdvisor: Automatically retrieves relevant documents and adds them to the prompt
Run the Application
KB_ID=$(aws bedrock-agent list-knowledge-bases --query "knowledgeBaseSummaries[?name=='kb-demo'].knowledgeBaseId|[0]" --output text --no-cli-pager)
echo "KB: ${KB_ID}"
SPRING_AI_VECTORSTORE_BEDROCK_KNOWLEDGE_BASE_KNOWLEDGE_BASE_ID=${KB_ID} jbang KbAgent.java
JBang downloads dependencies on first run, then starts the Spring Boot application.
Test the Application
In another terminal:
# Test travel policy
curl -s -X POST http://localhost:8080/chat -H "Content-Type: text/plain" \
-d "What is the accommodation limit for Europe?"
# Test IT policy
curl -s -X POST http://localhost:8080/chat -H "Content-Type: text/plain" \
-d "What is the home office equipment budget?"
Expected output:
Based on the context information provided, the accommodation limit for Europe is €130 per night, and manager approval is required.
Based on the context information provided, the home office equipment budget is **$500 per year**.
The AI responds with information from your company documents - not generic training data.
Cleanup
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text --no-cli-pager)
KB_ID=$(aws bedrock-agent list-knowledge-bases --query "knowledgeBaseSummaries[?name=='kb-demo'].knowledgeBaseId|[0]" --output text --no-cli-pager)
[ "${KB_ID}" != "None" ] && aws bedrock-agent delete-knowledge-base --knowledge-base-id ${KB_ID} --no-cli-pager 2>/dev/null
aws s3 rb s3://kb-demo-${ACCOUNT_ID} --force --no-cli-pager 2>/dev/null
aws s3vectors delete-index --vector-bucket-name kb-demo-vectors-${ACCOUNT_ID} --index-name kb-demo-index --no-cli-pager 2>/dev/null
aws s3vectors delete-vector-bucket --vector-bucket-name kb-demo-vectors-${ACCOUNT_ID} --no-cli-pager 2>/dev/null
aws iam delete-role-policy --role-name kb-demo-role --policy-name s3vectors --no-cli-pager 2>/dev/null
aws iam detach-role-policy --role-name kb-demo-role --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess --no-cli-pager 2>/dev/null
aws iam detach-role-policy --role-name kb-demo-role --policy-arn arn:aws:iam::aws:policy/AmazonBedrockFullAccess --no-cli-pager 2>/dev/null
aws iam delete-role --role-name kb-demo-role --no-cli-pager 2>/dev/null
What's Next?
This demo uses S3 with text files, but Bedrock Knowledge Base supports:
- Multiple data sources: Confluence, SharePoint, Salesforce, web crawlers
- Advanced search: Hybrid search combining semantic and keyword matching
- Reranking: Improve relevance with Bedrock reranking models
- Metadata filtering: Filter results by document attributes
See the Spring AI documentation for configuration options.
Conclusion
With minimal setup - one Java file and a few shell commands - you have an AI assistant grounded in your own data. No vector database to manage, no embedding pipeline to build.
I'm proud to have contributed this integration to Spring AI 2.0.0 M2. The source is available on GitHub if you want to see how it works under the hood.
Top comments (0)