
Day 5: Lets Build a Chat App with Bedrock
turn our Knowledge Base into a chat app with Python and Streamlit. Follow-up questions, source references, also see new releasees
lets we build a small chat screen with:
- A text box and chat history
- Follow-up questions that continue the conversation
- Source files you can check under every answer
It's a small Python app. No web development experience needed.
Who does what?
Here's what happens when you type a question:
- Streamlit shows the chat box and sends your question to Bedrock.
- The Knowledge Base searches your notes and finds the most relevant chunks.
- The AI model reads those chunks and writes the answer.
- The answer comes back to Streamlit along with the source files it used.
| Piece | Its job |
|---|---|
| Amazon Bedrock | Provides the AI model and the Knowledge Base API |
| Knowledge Base | Finds the relevant parts of your notes |
| Streamlit | Draws the chat page |
| Conversation session | Lets follow-up questions build on earlier ones |

The app runs on your laptop, with your AWS credentials, and calls the Knowledge Base
Which Knowledge Base? This article uses the classic Knowledge Base from Day 4 , where we chose the embedding model and vector store. AWS also launched a Managed Knowledge Base in 2026, covered near the end.
Before you start
- A working Knowledge Base from Day 4 with a finished sync
- Python and AWS credentials set up from Day 1
- Your Knowledge Base ID and a model ARN or inference profile ARN that worked on Day 4
Step 1: Install Streamlit
Streamlit turns a Python file into a web page.
1
pip install --upgrade streamlit boto3Step 2: Write the app
Create a file called
app.py:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import boto3
import streamlit as st
from botocore.exceptions import ClientError
REGION = "YOUR_AWS_REGION"
KB_ID = "YOUR_KB_ID"
MODEL_ARN = "YOUR_MODEL_OR_INFERENCE_PROFILE_ARN"
client = boto3.client("bedrock-agent-runtime", region_name=REGION)
st.set_page_config(page_title="Chat with my notes")
st.title("Chat with my class notes")
if "messages" not in st.session_state:
st.session_state.messages = []
st.session_state.session_id = None
# Reset button: runs BEFORE the history is drawn
if st.button("Start a new chat"):
st.session_state.messages = []
st.session_state.session_id = None
def show_message(role, content, sources=None):
with st.chat_message(role):
st.markdown(content)
if sources:
with st.expander("View sources"):
for s in sources:
st.write(s)
for m in st.session_state.messages:
show_message(m["role"], m["content"], m.get("sources"))
question = st.chat_input("Ask something from your notes")
if question:
st.session_state.messages.append({"role": "user", "content": question})
show_message("user", question)
params = {
"input": {"text": question},
"retrieveAndGenerateConfiguration": {
"type": "KNOWLEDGE_BASE",
"knowledgeBaseConfiguration": {
"knowledgeBaseId": KB_ID,
"modelArn": MODEL_ARN,
},
},
}
if st.session_state.session_id:
params["sessionId"] = st.session_state.session_id
try:
with st.spinner("Searching your notes..."):
response = client.retrieve_and_generate(**params)
st.session_state.session_id = response["sessionId"]
answer = response["output"]["text"]
sources = sorted({
ref["location"]["s3Location"]["uri"]
for c in response.get("citations", [])
for ref in c.get("retrievedReferences", [])
if "s3Location" in ref.get("location", {})
})
except ClientError as e:
answer = f"Something went wrong: {e.response['Error']['Message']}"
sources = []
show_message("assistant", answer, sources)
st.session_state.messages.append(
{"role": "assistant", "content": answer, "sources": sources}
)Replace the three placeholders at the top with your own values.
Step 3: Run it
1
streamlit run app.pyYour browser opens a chat page. Ask a question from your notes.
Two kinds of "memory"
Our app remembers things in two different places, and they do different jobs.
1. Streamlit remembers what to show. Every time you send a message, Streamlit reruns the whole script. Without
st.session_state, the chat on screen would disappear after each question. This memory lives in your browser session. If you refresh the page, it starts fresh.2. Bedrock remembers what the conversation is about. Each response includes a
sessionId. When we send it back with the next question, Bedrock can understand follow-ups like "explain that in simpler words." It continues the conversation. It isn't a notebook of everything you've ever asked.| Memory | What it does | Limit |
|---|---|---|
st.session_state | Keeps the chat messages on screen | A page refresh starts a new session |
sessionId (Bedrock) | Gives the model context for follow-up | Only continues the conversation. |
Try this
- Ask: "What is a deadlock?"
- Then ask: "Explain that in simpler words."
- Click Start a new chat. This clears the messages on screen and the Bedrock
sessionId, so the next question starts a brand-new conversation. - Ask "Explain that in simpler words." again.
If step 2 makes sense and step 4 doesn't, the session memory is working.
Experiment: is your AI actually using your notes?
A working chat is exciting. But I wanted to know: did the answer come from my notes, or did the model already know it?
- Ask a question your notes answer clearly. Open View sources and check the file.
- Ask about a topic that isn't in your notes. Compare the answer and the sources.
- Create a small test file called
test-fact.txtcontaining only this line.
If the app finds your made-up fact, retrieval is working.
My takeaway: an answer can sound confident without being supported by your documents. A source helps you check, but it doesn't prove every claim is right.
My result: The app answered my questions and showed the source files, making it easier to check where the information came from.
What the errors mean
| What you see | What it means | What to try |
|---|---|---|
AccessDeniedException | A permissions problem | Check IAM and model access in your console |
ValidationException about the model | A model setup problem | Copy the exact model or inference profile ARN |
| No error, but "no information" answers | Retrieval found nothing useful | Check the sync status and whether the answer is in your notes |
What's new in 2026 (Managed Knowledge Base)
AWS launched Amazon Bedrock Managed Knowledge Base, a fully managed option. These updates are for the managed version. Our tutorial uses the classic one.
- June 17, 2026: generally available , with native connectors including Amazon S3
- September 4, 2026: automatic sync scheduling (daily, weekly, or monthly)
- September 23, 2026: Salesforce and Zendesk connectors

Classic vs Managed: they aren't interchangeable. Managed uses AWS-managed storage (no vector store choice), and its retrieval calls use a different configuration. Check Region availability and the current docs before switching. I kept this series on the classic version so you can see each building block.
Keep it safe and affordable
- No access keys in your code. Use
aws configure. - This app is for local learning. Sharing it with others would need hosting, login protection, and care for your AWS resources.
- Costs depend on the model you use, the retrievals, and the services behind your Knowledge Base. Check the current AWS pricing and set a budget alert in AWS Budgets before experimenting.
Summary
- A chat app is a small Streamlit page that calls your Knowledge Base
- Streamlit session state and Bedrock's
sessionIdare different kinds of memory - Always check the sources, and test with facts you control
- Classic and Managed Knowledge Bases are different options
Next: Day 6
Our bot will answer almost anything. Tomorrow we add Guardrails: block unsafe or off-topic questions and hide personal information.
What would you add to this chat app? Tell me below.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article