AI EngineeringZero to ProductionHome·About·Contact
AWS AI Automation · Chapter W12

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.

⏱️ ~1.5 hours🧪 1 lab🎯 Intermediate
⚙️ To run this for realThe code here is complete and correct as written. To actually execute it you'll need:
  • AWS credentials (aws configure) + pip install boto3
Reading and learning works without any of this — run when you're ready. IDs/ARNs in examples are placeholders; swap in your own.

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.
▶ Runnable companionEvery code block in this lesson is also a standalone file under 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

Both search your documents, but for different jobs. A Knowledge Base (W4) is a vector store you build RAG on. Kendra is a managed enterprise search service with 40+ connectors (SharePoint, S3, Confluence, ServiceNow…), natural-language ranking, and access control baked in. Use Kendra when the value is finding across many enterprise systems; use a KB when you are building a RAG app.

NeedUse
RAG store for an app you buildBedrock Knowledge Base (W4)
Search across many enterprise systemsKendra
A ready-made coding assistantAmazon Q Developer
A ready-made assistant over company dataAmazon Q Business

Query Kendra advanced

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
Lab W12.1
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]}")
▶ How this works

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.

  1. import boto3 loads 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 the us-east-1 region and stores it in the variable kendra. (This needs AWS credentials to actually run — see the orange box at the top of the page.)
  2. 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.
  3. 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 the for item in ... loop then handles each one in turn.
  4. 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 short excerpt (a snippet of the matching text).
  5. print(f"- {title}: {excerpt[:80]}") prints one line per result. The f"..." is an f-string that drops the variables' values into the text, and excerpt[: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.

Kendra as a retriever for ClaudeYou can use Kendra as the retrieval step and Claude as the generation step — a RAG app where Kendra's connectors and ACLs do the hard part. Bedrock KBs can even use Kendra as a data source.

Amazon Q expert

Amazon Q is AWS's ready-made assistant family — you configure, not build. Q Developer is a coding assistant (IDE + CLI, AWS-aware) comparable to the tools in AI-Assisted Development. Q Business is a managed assistant over your connected company data, with the retrieval, security, and UI handled.

Build vs. buyQ is the 'buy' end of the spectrum: fastest to value, least control. A Bedrock Agent (W5) is the 'build' end: full control, more work. Knowing both lets you recommend the right one.

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 converse to 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.

Exercise 1 · Query a Kendra indexBeginner

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 query on a boto3 kendra client, passing an IndexId and the QueryText
  • Iterate the ranked ResultItems the response returns
  • Read the title from DocumentTitle.Text and the snippet from DocumentExcerpt.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])
Exercise 2 · Kendra vs Knowledge BaseIntermediate

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
Exercise 3 · Fold Kendra results into a Claude promptAdvanced

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 converse on a bedrock-runtime client 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"])
Exercise 4 · Place products on the build-vs-buy spectrumExpert

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-business for the zero-code managed-assistant-over-connectors case
  • Fall back to bedrock-agent when 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"])
Exercise 5 · A relevance gate over Kendra scoresProfessional

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 LOW hit is dropped and a VERY_HIGH hit 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
Exercise 6 · Internal help desk: buy Q or build an Agent?Industry scenario

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-business for phase 1 when the deadline is tight (connectors + zero code go live fast)
  • Reserve bedrock-agent for 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

✓ Knowledge check

When should you reach for Kendra versus a Bedrock Knowledge Base?

Show answer
Use a Knowledge Base when you are building a RAG app and need a vector store you control. Use Kendra when the value is managed enterprise search across many systems -- it brings 40+ connectors (SharePoint, S3, Confluence, ServiceNow...), natural-language ranking, and access control baked in. Kendra can even serve as the retriever for Claude.
✓ Knowledge check

Place Amazon Q and a Bedrock Agent on the build-vs-buy spectrum, and note what Q Developer vs Q Business offer.

Show answer
Amazon Q is the 'buy' end -- fastest to value, least control: Q Developer is a ready-made AWS-aware coding assistant and Q Business is a managed assistant over your connected company data. A Bedrock Agent is the 'build' end: full control but more work.
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in