Kendra & Amazon Q
Kendra is managed enterprise search with 40+ connectors; Amazon Q is a ready-made assistant family. Both sit at the 'buy' end of the build-vs-buy spectrum.
- AWS credentials (
aws configure) +pip install boto3
Learning objectives
- Explain Kendra vs. a Bedrock Knowledge Base — managed enterprise search vs. RAG store.
- Query Kendra and read ranked results with connectors to enterprise sources.
- Explain what Amazon Q Developer and Q Business give you out of the box.
- Choose the right tool: Kendra, a KB, or Q.
code/aws12-kendra-q/ in the course, with a README on how to run it. Read here, run there — no need to copy-paste.Kendra vs. Knowledge Base advanced
Here's the mistake that costs a team three sprints. Someone is asked to "let employees ask questions over our internal docs," and — because they just finished the Knowledge Base chapter (W4) — they reach for a Bedrock Knowledge Base. They stand up a vector store, write an ingestion job, then discover the docs live in SharePoint and Confluence and ServiceNow, each behind its own permissions. Now they're writing connectors and re-implementing access control by hand — rebuilding, badly, a product AWS already sells. The lesson isn't "KBs are bad." It's that two services that both "search your documents" solve completely different jobs, and picking the wrong one means building the other one yourself.
Think of it as the difference between a library card catalog and a research assistant you're hiring and training. Amazon Kendra is the catalog: a managed enterprise search service you point at your existing systems. Its whole value is breadth and turnkey plumbing — 40+ connectors (SharePoint, S3, Confluence, ServiceNow, and more) that crawl those sources on a schedule, natural-language ranking so "how do I request prod access?" beats keyword matching, and — crucially — access control that respects who's allowed to see each document. You query Kendra; you don't build it. A Bedrock Knowledge Base is the assistant you're assembling: a vector store you own, that you wire into your own RAG generation loop, where you control the chunking, the embeddings, the prompt, and the model.
So the deciding question is not "which is better search?" — it's "am I buying search, or building a RAG application?" If the value is finding answers scattered across many enterprise systems, and you'd rather not own the ingestion/ACL machinery, that's Kendra. If the value is a custom RAG app where you need to shape retrieval and generation to your product, that's a Knowledge Base. The common trap is treating this as a capability comparison when it's really a build-vs-buy decision — and the two aren't even mutually exclusive: because Kendra is such a strong retriever, you can use it as the retrieval step and feed its ranked passages to Claude for generation. That hybrid is the best of both, and it's exactly what the lab and exercises below build toward.
Start at the top box — your question — then follow each blue arrow down into one of the two panels; they represent the two products you might choose between.
- The green panel on the left is Kendra (the "buy" choice): you point it at 40+ connectors, AWS keeps the index and access-control up to date, and you get back ranked source documents — you query it, you don't build it.
- The amber panel on the right is a Bedrock Knowledge Base (the "build" choice): you own the chunking, embeddings, vector store, and prompt, and it emits a generated, cited answer — more control, more machinery to maintain.
- The payoff is the split itself: both boxes accept the same question, so the decision is never "which searches better" — it is whether you want to buy managed search or build your own RAG app.
In short: one question, two jobs — Kendra finds and ranks (managed), a Knowledge Base is a store you generate answers from (owned).
| Need | Use |
|---|---|
| RAG store for an app you build | Bedrock Knowledge Base (W4) |
| Search across many enterprise systems | Kendra |
| A ready-made coding assistant | Amazon Q Developer |
| A ready-made assistant over company data | Amazon Q Business |
Query Kendra advanced
The first time you call Kendra, you'll expect a paragraph of answer and get a list of documents instead — and that surprise is the whole point. People who've only used chatbots assume every "ask a question" API hands back generated prose. Kendra doesn't. Ask it "how do I request production access?" and it returns ranked source documents with titles and matching excerpts — no invented sentences, no hallucinations, just the real passages that best answer you. If you were expecting a written reply, that feels underwhelming; once you understand why, it feels like a feature. Kendra is a retriever, not a generator, and keeping those two jobs separate is what lets you trust the results.
Picture the "very good internal Google" your company never built. You type a plain-English question; behind the scenes Kendra has already crawled your connected sources, indexed them into an index (identified by an IndexId), and now ranks every stored passage against your query — best-first, using natural-language understanding rather than raw keyword overlap. The call itself is deliberately small: you hand query() two things, the index to search and the QueryText, and it returns a dictionary whose ResultItems list is already sorted from most to least relevant. Each item carries a DocumentTitle and a DocumentExcerpt — the snippet of matching text — so you can show a human where the answer lives, not just what it might be.
The one habit worth forming early is defensive field access. Those nested fields (DocumentTitle.Text, DocumentExcerpt.Text) aren't guaranteed to be present on every hit, and reaching into a missing key throws an error that kills your loop mid-results. The fix you'll see in the lab is item.get("DocumentTitle", {}).get("Text", "") — ask for the field, but fall back to an empty default if it's absent, so one odd document can't crash the whole response. This is a small thing that separates a demo from something you'd run against a live index. And keep the mental model sharp: Kendra finds and ranks; it does not write. The moment you want a synthesized, cited answer, you take these top excerpts and pass them to a generation model like Claude — Kendra supplies the sources, the model supplies the wording. That separation is exactly the RAG-by-hand pattern the exercises build.
query() an IndexId and a QueryText; it returns ResultItems sorted best-first, each with a DocumentTitle and DocumentExcerpt. Generation is a separate, optional step you add by passing the top excerpts to Claude.
Follow the solid blue arrows left to right — that is one query() call travelling into Kendra and coming back out as ranked results.
- The blue box on the left is your call: just two inputs, the
QueryText(a plain-English question) and theIndexId(which index to search). - The middle box is the Kendra index — the documents it has already crawled from your connectors — which ranks every passage against your query using natural-language understanding, not keyword overlap.
- The green box is what comes back:
ResultItemsalready sorted best-first, each carrying aDocumentTitleand aDocumentExcerpt. Note it is documents, not a written answer. - The dashed arrow down to the purple box is the optional extra step: take those top excerpts and pass them to Claude to synthesize a cited reply. The dash marks it as "only if you want generation" — Kendra itself never writes.
In short: query in, ranked source documents out; add Claude only when you want the sources turned into prose.
kendra_query.pyimport boto3
kendra = boto3.client("kendra", region_name="us-east-1")
resp = kendra.query(
IndexId="index-abc123",
QueryText="how do I request production access?",
)
for item in resp["ResultItems"][:3]:
title = item.get("DocumentTitle", {}).get("Text", "")
excerpt = item.get("DocumentExcerpt", {}).get("Text", "")
print(f"- {title}: {excerpt[:80]}")
Kendra is Amazon's managed enterprise search — think of it as a smart search box wired into your company's documents (SharePoint, S3, Confluence, and so on). This little program asks Kendra a plain-English question and prints the three best matching documents. There is no AI text generation here — Kendra just finds and ranks real documents, the way a very good internal Google would.
import boto3loads the AWS SDK for Python — the library that lets your code talk to AWS services.boto3.client("kendra", region_name="us-east-1")opens a connection to the Kendra service in theus-east-1region and stores it in the variablekendra. (This needs AWS credentials to actually run — see the orange box at the top of the page.)kendra.query(...)is the actual search call.IndexId="index-abc123"names which Kendra index (the pre-built collection of your indexed documents) to search — that placeholder ID would be swapped for your real one.QueryText="how do I request production access?"is the natural-language question you're asking.- The reply comes back as a dictionary stored in
resp.resp["ResultItems"]is the list of matches, already ranked best-first by Kendra.[:3]is a slice that keeps only the first three, and thefor item in ...loop then handles each one in turn. - For each result,
item.get("DocumentTitle", {}).get("Text", "")safely digs out the document's title..get(key, default)returns the default instead of crashing when a field is missing — so a result with no title becomes an empty string""rather than an error. The same pattern pulls out a shortexcerpt(a snippet of the matching text). print(f"- {title}: {excerpt[:80]}")prints one line per result. Thef"..."is an f-string that drops the variables' values into the text, andexcerpt[:80]trims the snippet to its first 80 characters so each line stays short.
What the output means: Up to three lines, each starting with -, showing a document's title followed by the first 80 characters of the matching passage — for example - Prod Access Runbook: To request production access, open a ticket in.... These are real ranked search hits, not a generated answer.
Try this: Change QueryText to a different question your docs would cover, or change [:3] to [:5] to see the top five results instead of three. To turn this into a full answer, you'd feed those excerpts to Claude (see Exercise W12.1) — Kendra finds the sources, Claude writes the reply.
Amazon Q expert
Imagine leadership wants an internal help-desk assistant live in two weeks. You could build one from parts — wire Kendra to Claude, add auth, host a UI, handle retrieval and citations yourself — and in two weeks you'd have a fragile demo and a burned-out team. Or you could ask a different question: has AWS already built this? For a large class of "assistant over our stuff" and "AWS-aware coding help" needs, the answer is yes, and it's called Amazon Q. Reaching for Q instead of assembling the same thing by hand is often the difference between shipping and slipping — which is why this section sits at the far buy end of everything you've learned.
The key reframe: with Q, you configure, you don't build. It comes in two flavors aimed at two different audiences. Q Developer is a coding assistant that lives in your IDE and CLI, and its differentiator is that it's AWS-aware — it knows about your resources, IAM, and AWS APIs in a way a generic autocomplete doesn't; it sits in the same family as the tools you met in AI-Assisted Development. Q Business is the managed assistant over your connected company data: you point it at your sources and AWS handles the retrieval, the security and access control, and the chat UI. The parts you'd otherwise sweat over — ingestion, ACLs, a front end — come in the box.
Here's the way to hold the whole chapter in one line: it's a build-vs-buy spectrum, and every service you've seen has a place on it. At the far buy end sit Q Developer and Q Business — fastest to value, least control, someone else owns the plumbing. In the middle is Kendra — managed search you query but still assemble around. At the far build end is a Bedrock Agent (W5) — full control over tools and the reasoning loop, but you wire and maintain all of it. Neither end is "right"; the skill an interviewer is probing for is knowing which end a given problem wants. Zero code, tight deadline, "over our existing systems"? That's the buy end, almost always Q. Need custom actions, bespoke tools, or control over every hop? Now you've earned the extra work of building. The most senior answer is frequently phased: buy Q to go live fast, then migrate only the hot paths that genuinely need custom control to a Bedrock Agent later — you'll encode exactly that decision in the practice ladder.
Read the horizontal arrow first: it is a single spectrum running from BUY on the left to BUILD on the right, trading speed-to-value for control. The three boxes below sit at their place on that line.
- The green box on the left is Amazon Q — the buy end. Q Developer is an AWS-aware coding assistant in your IDE/CLI; Q Business is a managed assistant over your connected data. Least code, fastest to live.
- The blue box in the middle is Kendra — managed enterprise search you query but still assemble your app around. It is neither fully bought nor fully built.
- The amber box on the right is a Bedrock Agent (W5) — the build end, where you wire the tools and the reasoning loop yourself for full control.
- The payoff is the arrow itself: choosing well means picking the right point on the line for the problem — and a phased answer (buy Q now, build an Agent later for hot paths) moves right along it over time.
In short: left = buy speed, right = build control; Q, Kendra, and a Bedrock Agent are three fixed points on that one axis.
Exercise W12.1 — Kendra-backed Claude
Context: You have already built a Bedrock Knowledge Base RAG answer in an earlier week. Doing the same question through Kendra + Claude lets you feel the trade-offs between managed enterprise search and a KB you own — on identical inputs.
Your task: Query Kendra for a question, take the top 3 excerpts, feed them to Claude via converse to synthesize a cited answer, and compare the result to your earlier Knowledge Base answer on the same question.
Requirements:
- Query Kendra and take the top 3
ResultItems' excerpts as context - Prompt Claude via
converseto answer from those excerpts and cite which ones it used - Ensure every claim in the answer traces to a supplied excerpt (grounded, cited)
- Run the identical question through your earlier Bedrock KB pipeline
- Compare the two answers — grounding quality, citations, and effort to build
- Note when you'd pick Kendra (many connectors, turnkey search) vs. a KB (own the RAG)
💡 Hint: Hold the question fixed and only swap the retriever; the interesting differences are in citation quality and how much of the pipeline you had to build yourself.
🪜 Practice ladder beginner → industry
Six graded exercises, easy to real-world. Try each before opening its solution.
Context: Kendra is AWS's managed enterprise search: point it at your documents and ask natural-language questions, and it returns ranked passages with titles and excerpts — no embeddings or vector store to run yourself.
Your task: Use Kendra query with an index id and a natural-language question, and print each result's title and excerpt.
Requirements:
- Call
queryon aboto3kendraclient, passing anIndexIdand theQueryText - Iterate the ranked
ResultItemsthe response returns - Read the title from
DocumentTitle.Textand the snippet fromDocumentExcerpt.Text, guarding for missing keys - Print title and a trimmed excerpt for each hit
💡 Hint: Kendra already ranks the results; those nested DocumentTitle/DocumentExcerpt objects can be absent, so use .get defensively.
Show solution
Kendra returns ranked ResultItems; each carries a DocumentTitle and a DocumentExcerpt.
import boto3
kendra = boto3.client("kendra", region_name="us-east-1")
resp = kendra.query(
IndexId="index-abc123",
QueryText="how do I request production access?",
)
for item in resp["ResultItems"]:
title = item.get("DocumentTitle", {}).get("Text", "")
excerpt = item.get("DocumentExcerpt", {}).get("Text", "")
print(title, "::", excerpt[:60])
Context: Kendra and a Bedrock Knowledge Base look similar but solve different problems: Kendra is managed search across many enterprise connectors, while a KB is a vector store you build your own RAG generation on top of.
Your task: Write a short decision function that states when to reach for Kendra versus a Bedrock Knowledge Base. Runs offline.
Requirements:
- Take the deciding factors as inputs (e.g. whether you need many connectors, whether you are building your own RAG app)
- Return
"bedrock-knowledge-base"when you own the RAG generation and don't need broad connectors - Return
"kendra"when you need managed search across sources like SharePoint/S3 - Capture the core distinction: Kendra = search-as-a-service; KB = a vector store you generate answers from
💡 Hint: Frame it as buy-the-search vs. build-the-RAG: connectors and turnkey search point at Kendra; owning generation points at a Knowledge Base.
Show solution
Kendra is managed enterprise search across many connectors; a KB is a vector store you build a RAG app on.
def search_choice(need_many_connectors, building_rag_app):
if building_rag_app and not need_many_connectors:
return "bedrock-knowledge-base" # you own the RAG generation
if need_many_connectors:
return "kendra" # search across SharePoint/S3/etc.
return "kendra"
print(search_choice(True, False)) # kendra
print(search_choice(False, True)) # bedrock-knowledge-base
Context: Kendra finds the right passages; Claude phrases the answer. Wiring them together by hand — search hits as grounding context in a converse prompt — is RAG assembled from parts, giving you full control over the prompt.
Your task: Take Kendra excerpts and build a grounded prompt for Bedrock converse so Claude answers strictly from the search hits (Kendra + Claude = RAG by hand).
Requirements:
- Query Kendra for the question and take the top few
ResultItems' excerpts - Concatenate those excerpts into a single context block
- Build a prompt that supplies the context and the question and instructs the model to answer from the context only
- Send it via
converseon abedrock-runtimeclient and print the model's text reply - Keep search (Kendra) and generation (Claude) as two distinct steps
💡 Hint: Kendra supplies the passages, Claude supplies the wording; the "answer from context only" instruction is what keeps it grounded in the retrieved hits.
Show solution
Kendra finds passages; Claude phrases the answer. Concatenate the top excerpts as context.
import boto3
kendra = boto3.client("kendra", region_name="us-east-1")
brt = boto3.client("bedrock-runtime", region_name="us-east-1")
q = "What is the on-call escalation path?"
hits = kendra.query(IndexId="index-abc123", QueryText=q)["ResultItems"]
context = "\n---\n".join(h.get("DocumentExcerpt", {}).get("Text", "")
for h in hits[:3])
prompt = f"Context:\n{context}\n\nQuestion: {q}\nAnswer from context only."
r = brt.converse(modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role":"user","content":[{"text": prompt}]}])
print(r["output"]["message"]["content"][0]["text"])
Context: The AWS assistant landscape is a build-vs-buy spectrum. Amazon Q is the buy end (fastest, least control), a Bedrock Agent is the build end (full control, you wire the tools and loop), and Kendra sits in between as managed search.
Your task: Map Amazon Q (Developer / Business), Kendra, and a Bedrock Agent onto a build-vs-buy spectrum, then recommend one for ‘a managed assistant over our Confluence + ServiceNow with zero code’. Runs offline.
Requirements:
- Place each option on the spectrum with a one-line role: Q Business/Developer at the buy end, Kendra mid, Bedrock Agent at the build end
- Encode the recommendation as a function of the requirements (zero-code, over connected data)
- Recommend
q-businessfor the zero-code managed-assistant-over-connectors case - Fall back to
bedrock-agentwhen full control is required - Justify why Q Business fits: managed, connector-driven, no code to own
💡 Hint: Zero code plus "over our existing systems" is the tell for the buy end; reach for a Bedrock Agent only when you must own the tools and control loop.
Show solution
Q is the buy end (fastest, least control); a Bedrock Agent is the build end. Q Business fits a zero-code managed assistant over connectors.
SPECTRUM = {
"q-business": ("buy", "managed assistant over connected company data"),
"q-developer": ("buy", "AWS-aware coding assistant in the IDE/CLI"),
"kendra": ("mid", "managed enterprise search you query"),
"bedrock-agent": ("build","full control, you wire tools + loop"),
}
def recommend(zero_code, over_connectors):
if zero_code and over_connectors:
return "q-business"
return "bedrock-agent"
print(recommend(True, True)) # q-business
print(SPECTRUM["q-business"])
Context: Grounding an LLM on weak search hits is how you get confident nonsense. Kendra tags each result with a ScoreConfidence band (VERY_HIGH…LOW), so you can drop low-confidence passages before they ever reach the model.
Your task: Build a relevance gate over Kendra scores that keeps only HIGH-or-better results before handing context to Claude. Runs offline.
Requirements:
- Map the confidence bands (
VERY_HIGH,HIGH,MEDIUM,LOW) to an order so they can be compared - Read each item's band from
ScoreAttributes.ScoreConfidence, defaulting safely when it is missing - Keep only items at or above a minimum band (default
HIGH) - Return the surviving items so only strong hits become grounding context
- Demonstrate offline that a
LOWhit is dropped and aVERY_HIGHhit is kept
💡 Hint: Turn the ordinal bands into numbers so "HIGH+" is a simple >= comparison; filter the list before it reaches the prompt.
Show solution
Filtering low-confidence hits keeps the LLM from grounding on noise.
ORDER = {"VERY_HIGH": 4, "HIGH": 3, "MEDIUM": 2, "LOW": 1}
def strong_hits(items, min_conf="HIGH"):
floor = ORDER[min_conf]
out = []
for it in items:
conf = it.get("ScoreAttributes", {}).get("ScoreConfidence", "LOW")
if ORDER.get(conf, 0) >= floor:
out.append(it)
return out
items = [{"ScoreAttributes": {"ScoreConfidence": "VERY_HIGH"}},
{"ScoreAttributes": {"ScoreConfidence": "LOW"}}]
print(len(strong_hits(items))) # 1
Context: Leadership wants an internal help desk over SharePoint + ServiceNow live in two weeks, with room to add custom actions later. The pragmatic answer is phased: buy for speed now, keep a build path open for what buying can't do.
Your task: Encode the decision for a phased help-desk rollout — ship fast on the buy end, then migrate to a build option when custom actions are needed — and justify it. Runs offline.
Requirements:
- Take the deadline and whether custom actions are needed now as inputs
- Choose
q-businessfor phase 1 when the deadline is tight (connectors + zero code go live fast) - Reserve
bedrock-agentfor a later phase when custom actions are required, else ‘revisit later’ - Return a phased plan (phase 1 / phase 2) rather than a single tool
- Explain the rationale: buy first for speed, build later for control over hot paths
💡 Hint: Two weeks rules out building from scratch; let the deadline pick Q Business for phase 1 and gate the Bedrock Agent on a real need for custom actions.
Show solution
Start on the buy end for speed, keep a build path open for the custom actions Q can't do.
def plan(deadline_weeks, need_custom_actions_now):
phase1 = "q-business" # connectors + zero code -> live fast
phase2 = "bedrock-agent" if need_custom_actions_now else "revisit later"
fast = deadline_weeks <= 3
return {"phase1": phase1 if fast else "bedrock-agent",
"phase2": phase2}
print(plan(2, need_custom_actions_now=False))
# phase1 q-business (2 wks, connectors, no code);
# phase2 revisit later -> migrate hot paths to a Bedrock Agent when custom
# actions are needed. Buy first for speed, build later for control.
✓ Checkpoint — you can move on when you can…
- Explain when to use Kendra vs. a Bedrock Knowledge Base.
- Query Kendra and read ranked results.
- Describe what Q Developer and Q Business provide.
- Place Kendra, KB, and Q on the build-vs-buy spectrum.
Knowledge check check yourself
When should you reach for Kendra versus a Bedrock Knowledge Base?
Show answer
Place Amazon Q and a Bedrock Agent on the build-vs-buy spectrum, and note what Q Developer vs Q Business offer.