RAG Foundations: Chunking, Embeddings, and Vector Stores (AWS GenAI Developer Pro, Module 4)
This is Module 4 of AWS GenAI Pro Mastery, a free 16-module course that takes you from your first Amazon Bedrock call to AWS-certified.
A CloudCart customer asks Relay: “How do I export my order history before I downgrade my plan?” Relay answers in a confident paragraph: open the Orders page, click the Export menu, pick Orders → CSV, done. The customer follows it, finds no such button, and files an angrier ticket. The real export lives under Settings → Data & Privacy → Export data — a screen the model has never seen. Relay did not lie. It has the whole Module 3 integration layer — routing, streaming, resilience — and it knows nothing about CloudCart. An eloquent foundation model (FM) with no access to your data is a generator of confident, wrong answers.
This module fixes that the hard way. Before a managed service does retrieval for you in Module 5, you build it by hand: ingest the help-center docs, chunk them, embed them, store them in a vector store, and retrieve the right passages for a question. By the end, Relay finds the export doc instead of inventing a button.
In this module
- You’ll learn to justify retrieval-augmented generation (RAG) over fine-tuning for docs that change; compare three chunking strategies and their trade-offs; select an embeddings model by dimensionality, domain fit, and batch cost; architect a vector store from the AWS options; deploy one with metadata for filtering; and reason about vector-store performance at scale.
- You’ll build Relay’s hand-built retrieval: CloudCart docs chunked three ways, embedded with Amazon Titan Text Embeddings V2, stored in Amazon S3 Vectors, and a
compare_chunking.pythat ranks the strategies on real test questions. - Exam domains covered: D1 — Foundation Model Integration, Data Management, and Compliance — 31% (this module covers skills 1.4.1–1.4.3 and 1.5.1–1.5.3; the rest of Tasks 1.4/1.5 — document-system connectors and incremental sync (1.4.4/1.4.5), plus hybrid search, rerankers, query expansion, and consistent access patterns (1.5.4–1.5.6) — is Module 5).
- Prerequisites: Modules 1–3 (a secured account with
AWS_PROFILE, therelay/llm.pylayer, theTicket/Triageschemas). Region is us-east-1 throughout.
Where you are in the build
You are at Module 4 of 16. The destination is the AWS Certified Generative AI Developer - Professional (AIP-C01) exam; the vehicle is Relay, CloudCart’s support agent.
- ✅ M1 — secured account, budget alarm, first Converse call.
- ✅ M2 — triage: structured output, Prompt Management, a prompt test suite.
- ✅ M3 — the FM integration layer: model routing, streaming, retries, cross-Region fallback.
- 👉 M4 — RAG foundations: chunking, embeddings, S3 Vectors, and a raw-retrieval comparison.
- ⬜ M5–M16 — managed RAG, agents, safety, deployment, cost, evals, observability, capstone.
Relay before this module can talk but knows nothing about CloudCart — ask about the docs and it hallucinates. After it, the docs are ingested, chunked, embedded, and stored in S3 Vectors, and raw retrieval is benchmarked across three chunking strategies. There is no cited answer yet — that is Module 5. Here you are the judge: you read the retrieved chunks and decide whether they fit.
Why RAG, not fine-tuning
Relay’s knowledge is CloudCart’s documentation, and documentation changes — a new export screen, a renamed setting, a fresh error code. You have two ways to teach a model something it does not know: bake it into the weights (fine-tuning) or fetch the relevant text at request time and put it in the prompt (RAG). For a help center, RAG wins on three axes the exam returns to.
Cost. Fine-tuning re-trains on every meaningful doc change; RAG just re-ingests the edited file. Freshness is the same point from the customer’s side: edit a doc, re-ingest, and the next answer is current — the weights never move. Attribution is the one a support agent cannot live without: RAG cites the exact passage an answer came from, so a human can verify it; fine-tuning blends knowledge into the weights, where no source can be pointed at. Fine-tuning is the right tool for other problems — a fixed output format, a house style, a skill the base model lacks (the custom-model lifecycle Module 3 covered, skill 1.2.4) — not for facts that change weekly.
RAG is a pipeline with three stages: ingest → retrieve → generate. Ingest cuts and embeds your docs into a searchable store; retrieve finds the passages relevant to a question; generate hands those passages to a foundation model to write a grounded, cited answer. This module builds the first two stages and inspects the results by hand; Module 5 adds cited generation. The split is deliberate: you understand a managed Knowledge Base far better once you have built the retrieval it hides.
Chunking: the lever nobody tunes
A foundation model does not digest a 40-page manual in one shot, and — the part beginners miss — retrieval returns a chunk, not a file. How you cut the docs decides what retrieval can ever surface: cut badly and the right answer is in your store but unreachable. Chunking is the cheapest, highest-leverage knob in the pipeline, and almost nobody tunes it. Three strategies dominate, and the exam (skill 1.5.1) wants you to tell them apart by document shape.
Fixed-size chunking cuts every N characters with an overlap window that steps back a few hundred characters each time, so a sentence straddling a boundary survives in at least one chunk. Dead simple, works on anything, ignores structure entirely: a heading or sentence can land mid-chunk. It is the baseline. Overlap is its one real knob — too little and boundary facts vanish, too much and you pay to embed the same text twice.
Hierarchical chunking splits on document structure — here, Markdown headings. Each section becomes one chunk that keeps its heading trail (for example, Orders > Exporting your order history), so the chunk is a self-contained answer unit even out of context. For short, well-sectioned help articles, a section is almost exactly the unit a customer’s question maps to.
Semantic chunking groups text by meaning, breaking only on sentence boundaries. The lab uses a deterministic stand-in — pack whole sentences up to a size budget — respecting meaning units without an extra model call. It shines on continuous prose where headings are sparse and a fixed cut would slice an explanation in half.
| Strategy | How it works | Expected precision / recall | Embedding cost (chunk count) | Winning doc type | When the exam picks it |
|---|---|---|---|---|---|
| Fixed-size | Cut every N chars with an overlap window; ignores structure | Moderate — can split a fact across a boundary | Lowest, predictable — fewest, largest chunks | Uniform, unstructured text dumps | Simplest baseline; structure unknown or irrelevant |
| Hierarchical | Split on headings; each section = one chunk with its heading trail | High on well-sectioned docs — a section maps to a question | Medium — more, smaller chunks per doc | Short, structured help articles, manuals, FAQs | Long, clearly-sectioned documents |
| Semantic | Group by meaning; break only on sentence boundaries | High on prose; misses exact tokens | Variable — depends on density | Continuous prose, transcripts, articles | Flowing text with few headings |
My opinion, to be tested in the lab and not assumed: for CloudCart’s short, well-sectioned help articles, hierarchical chunking on Markdown headings beats fixed-size — but you only know after you measure, which is what the lab does. “It depends on the document” is not a dodge; it is the answer, and the exam rewards measuring over defaulting.
The ingestion pipeline you build: docs in S3, chunked, embedded with Titan, upserted into the vector index.
flowchart LR
A["data/docs/ (Markdown)"] --> B["upload to S3 relay-<account_id> under docs/"]
B --> C{"chunk: fixed | hierarchical | semantic"}
C --> D["embed each chunk (Titan Text Embeddings V2, 1024 dims)"]
D --> E["upsert {key, vector, metadata}"]
E --> F["index relay-docs in relay-vectors-<account_id>"]
Embeddings and vector stores: choosing both
Embeddings
An embedding is a list of numbers — a vector — that places text in a space where meaning becomes distance: texts that mean similar things land near each other. “How do I get my orders out?” and “Exporting your order history” map to nearby vectors though they share almost no words — which lets retrieval find a doc by intent, not keyword.
The number that defines an embedding model is its dimensionality — how many components each vector has. Relay uses Amazon Titan Text Embeddings V2 at 1024 dimensions. More dimensions capture more nuance but cost more to store and search; Titan V2 lets you trade down to 512 or 256 when storage and latency matter more than the last point of recall. We pin 1024 because that is the vector contract the index relay-docs is built on — Module 5’s Knowledge Base and Module 12’s semantic cache reuse this very Titan-1024 embedder (each on its own store), so the embedder and its dimensionality are never silently swapped. Mixing dimensions, or embedding corpus and query with different models, produces vectors that cannot be compared. Embed corpus and query with the same model, always.
A word on the Titan successor: amazon.nova-2-multimodal-embeddings-v1:0 exists as of June 2026 and is worth evaluating for a new index — it handles images and text together. But swapping the embedder re-embeds the corpus with vectors the existing 1024-dim relay-docs index cannot compare against — and that index is the pinned contract Module 5’s Knowledge Base and Module 12’s cache share. So it earns a comparison row, not a swap; the lab keeps Titan V2 pinned.
⚠️ Common misconception: a bigger context window means I can skip chunking and retrieval — just dump all the docs into the prompt. Wrong, for three reasons. Cost per token: you pay for the entire corpus on every request, not the handful of relevant passages. Relevance dilution (the “needle in a haystack” problem): accuracy drops as the context fills with text that does not answer the question. No attribution: without targeted retrieval there is no single source to cite, which a support agent must have. The 1M-token context of recent models (Module 3) does not delete retrieval — only makes it more forgiving.
One distinction the exam loves, separate from the box: the embeddings model and the generation model are two separate choices — you pick the embedder for recall, the generator for the answer, usually different models sized for different jobs.
Vector stores
A vector store holds your embeddings and answers nearest-neighbor queries fast. The choice is mostly an economics question — and where pre-2026 RAG tutorials went broke. The four stores worth comparing for a modern RAG build — OpenSearch, Aurora/RDS pgvector, and DynamoDB are the ones Tasks 1.4/1.5 name; Amazon S3 Vectors is the post-2025 cost default the v1.0 exam guide predates:
| Vector store | Idle cost | Typical latency | Scale (vectors) | When to choose |
|---|---|---|---|---|
| Amazon S3 Vectors | ~$0 — storage + per-query only | Tens to low hundreds of ms | Tens of millions per index | Cost-sensitive, spiky or low QPS, no ops team — the course default |
| OpenSearch Serverless | ~$174/month, billed 24/7 | Single-digit to low tens of ms | Very large, high QPS | Sustained high query volume, sub-50 ms p99, hybrid + advanced filtering |
| Aurora PostgreSQL (pgvector) | Cluster runs continuously | Low tens of ms | Millions, bounded by instance | Vectors already belong next to relational data you query together |
| DynamoDB (vectors + metadata) | On-demand, near-$0 idle | Single-digit ms key lookups | Huge by key, but no native ANN | Metadata lookups and small candidate sets; not a primary ANN engine |
Here is the opinion I will defend with numbers: Amazon S3 Vectors (GA December 2025) bills roughly $0 idle — about $0.06 per GB-month of storage and $2.50 per million queries, as of June 2026. OpenSearch Serverless starts around $174/month billed 24/7, whether or not a single query lands. That gap — an always-on cluster billed around the clock — is the #1 cost trap in pre-2026 RAG tutorials, which defaulted to OpenSearch because that is what the old Knowledge Base wizard provisioned. For a course-scale corpus, S3 Vectors wins before the first query. OpenSearch, Aurora, and Kendra are real answers at sustained scale, but they are exam theory here — named, compared, never provisioned. (Re-verify every figure on the Bedrock pricing page and the S3 pricing page the day you build.)
The lab’s setup.py creates the data bucket relay-<account_id> (with prefixes docs/, attachments/, vectors/), the vector bucket relay-vectors-<account_id>, and the index relay-docs — 1024 dimensions, cosine distance. These are the frozen resource names the managed Knowledge Base (M5) and the agent (M7) build on; they appear identically in the article, the code, and every downstream module.
Raw retrieval and its limits
Retrieval is symmetric: embed the query with the same model, then ask the store for the top-k nearest vectors. “Nearest” means cosine similarity — the cosine of the angle between two vectors, 1.0 when they point the same way, 0 when unrelated. S3 Vectors returns cosine distance; we report similarity (1 − distance), the way people reason about closeness. A kNN query for k=3 returns the three closest chunks, each with a similarity score and its metadata. You read them and decide if they answer the question.
Pure semantic similarity has a known blind spot: exact identifiers. A SKU, an order number, a CloudCart error code like ERR-402 — tokens a keyword search would pin instantly, but an embedding spreads their meaning across the sentence, so the exact code can rank below a “close” but wrong passage. The fix is hybrid search — combining semantic and keyword retrieval — which Module 5 adds. Here, you watch the gap rather than paper over it.
This is also where metadata filtering earns its keep (skill 1.4.2). Every vector carries metadata — category, source_uri, chunk_index. Filtering retrieval to category = "billing" narrows the search to billing docs before similarity even runs — fewer wrong candidates, sharper recall. The same mechanism does the heavy lifting in production: a tenant_id filter isolates one customer’s data in a shared index, a timestamp filter drops stale passages — one index serving many tenants and many freshness windows.
flowchart LR
Q["question text"] --> E["embed (Titan, 1024 dims)"]
E --> K["kNN top-k on index relay-docs"]
M["metadata filter: category / strategy"] --> K
K --> R["top-k chunks + scores + metadata"]
R --> H["human inspection (you are the judge)"]
Build it
The lab ingests the CloudCart docs under three chunking strategies, embeds them with Titan V2, stores them in S3 Vectors, and ranks the strategies on eight test questions. Full code is in the Module 4 lab; the excerpts below are the load-bearing parts.
Step 1 — provision storage. uv run python setup.py creates the data bucket, uploads the docs, and creates the vector bucket and index — but not an always-on cluster. The index creation pins the contract and keeps the human-readable snippet out of the filter structures:
s3v.create_index(
vectorBucketName=vector_bucket,
indexName=index_name, # relay-docs
dataType="float32",
dimension=config.EMBED_DIMENSIONS, # 1024 — the Titan V2 contract
distanceMetric=config.EMBED_DISTANCE_METRIC, # cosine
metadataConfiguration={"nonFilterableMetadataKeys": ["snippet"]},
)
It is idempotent — run it twice and it prints already exists. Reusing., changing nothing.
Step 2 — the chunkers. All three are deterministic (same doc → same chunks), which keeps the comparison fair. Each returns chunks carrying the canonical metadata {category, source_uri, chunk_index}. The hierarchical chunker flushes a chunk at every heading, prefixing the body with its heading trail:
def hierarchical(doc: Document) -> list[Chunk]:
"""Split on Markdown headings; each section is one chunk that keeps its trail."""
chunks, index, heading_stack, buffer = [], 0, [], []
for line in doc.body.splitlines():
m = _HEADING_RE.match(line.strip())
if m: # new section: flush, then update the trail
flush() # emits a Chunk with text = "trail\n\nbody"
buffer = []
level, title = len(m.group(1)), m.group(2).strip()
while heading_stack and heading_stack[-1][0] >= level:
heading_stack.pop()
heading_stack.append((level, title))
else:
buffer.append(line)
flush()
return chunks
This is abridged; the full version also emits a leading chunk titled by the doc (doc.title or "(intro)") for any body text before the first heading, so the opening paragraphs of an article are never dropped.
Step 3 — embed. This holds the one invoke_model call the whole course tolerates. The Converse API cannot produce embeddings — it returns text — so the embeddings path uses bedrock-runtime directly, returning a vector, never text; all generation stays on converse():
def embed_one(text: str, *, client=None) -> tuple[list[float], int]:
client = client or _runtime_client() # one client, reused across the batch
body = json.dumps({
"inputText": text,
"dimensions": config.EMBED_DIMENSIONS, # 1024, pinned
"normalize": True, # makes cosine well-behaved
})
response = client.invoke_model(modelId=config.EMBED_MODEL_ID, body=body,
accept="application/json",
contentType="application/json")
payload = json.loads(response["body"].read())
vector = payload["embedding"]
if len(vector) != config.EMBED_DIMENSIONS: # fail loud on dimension drift
raise ValueError(
f"Titan returned {len(vector)} dims, expected "
f"{config.EMBED_DIMENSIONS}.")
return vector, int(payload.get("inputTextTokenCount", 0))
Titan V2 embeds one text per call on the synchronous path, so “batch” here is a loop that reuses one client and sums the token count for one honest cost line. For a corpus of millions you fan out across Lambda; the lab does not.
Step 4 — ingest under each strategy. run.py chunks, embeds, and upserts every doc under a namespace per strategy, so all three coexist in one index:
uv run python -m ingest.run --strategy fixed
uv run python -m ingest.run --strategy hierarchical
uv run python -m ingest.run --strategy semantic
The hierarchical run printed (embed cost from the Titan token count, never guessed):
Ingested 6 docs with the 'hierarchical' chunker:
...
chunks total : 35
vectors upserted : 35 -> index 'relay-docs' (bucket relay-vectors-<account_id>)
embeddings : Titan Text Embeddings V2, 1024 dims
embed tokens : 3112
embed cost : $0.000062 (as of June 2026 — re-verify pricing)
Across the three strategies the live run produced 13 chunks (fixed), 35 (hierarchical), and 18 (semantic) — 66 vectors in one index, each keyed strategy#doc#chunk_index (e.g. hierarchical#orders-export#2). The embedding-cost lever from the table is visible here: hierarchical produced nearly three times the chunks of fixed, and so three times the upserts.
Step 5 — compare. uv run python compare_chunking.py embeds each of the eight questions with the same Titan model, runs a top-k kNN per strategy, and scores hits against the hand-labeled docs:
Question: "How do I export my order history?"
fixed hierarchical semantic
top-1 hit Y Y Y
top-k recall 1/1 1/1 1/1
best sim 0.824 0.867 0.771
On this corpus all three strategies hit top-1 on all eight questions — top-1 rate 1.00, mean recall 1.00 each — but hierarchical won the cosine score on every question. The export question is typical (0.867 vs 0.824 vs 0.771); the gap is widest where structure matters most — shipping-tracking scored 0.704 hierarchical against 0.384 and 0.374. Even ERR-402 landed: 0.758 hierarchical, 0.698 fixed, 0.684 semantic — close, a reminder that pure semantic similarity is near an exact code rather than certain, the wobble hybrid search removes. The opinion held: on CloudCart’s well-sectioned docs, hierarchical wins — measured, not assumed.
This is raw retrieval inspected by hand: no LLM-as-a-judge and no RAG-evaluation harness — relevance is the human label, the score is plain cosine similarity. Tooled RAG evaluation is Module 13. The fix for a passage that is in the index but not retrievable is to re-chunk, not to bump k or add a reranker (Module 5).
Step 6 — tests, then tear down. The offline suite runs with no credentials — deterministic chunkers, a stubbed Titan client, a moto S3 Vectors lifecycle, a stubbed kNN — and the cumulative M2–M4 suite passes 57 passed, 3 skipped (the skips are the opt-in live tests). The live suite (RELAY_LIVE_TESTS=1) ran 3 passed against real Bedrock on a sub-cent budget; the whole lab cost $0.01 on June 2026 prices. uv run python teardown.py deletes the index, the vector bucket, and (unless --keep-data) the data bucket — nothing idle-billed remains.
Try it yourself. (1) Sweep the fixed-size overlap (FIXED_OVERLAP_CHARS = 0, 100, 300), re-ingest --strategy fixed, and re-measure recall — more overlap rescues boundary-straddling facts at the cost of more chunks. (2) Drop the category from a billing question in data/questions.json, watch cross-category chunks compete, then add it back and watch the metadata filter sharpen recall — the multi-tenant skill made concrete.
In production
At lab scale every chunking choice is reversible. At corpus scale, two things change hard.
First, re-chunking is expensive. Change your strategy on a corpus of millions and you re-embed everything — a fresh Titan bill and a full index rebuild. Choose early and measure on a sample; the do-over is not free. This is also when the store decision flips: at tens of millions of vectors and sustained query volume, latency, sharding, and per-query cost start to matter, and the OpenSearch/Aurora options that idle-bill too much for a lab become defensible. The exam’s scale questions live here — corpus size, QPS, p99 latency, and ops budget decide the store, not a default.
Second, metadata carries the operational load. A tenant_id filter isolates each customer’s data in one shared index instead of one per tenant; a timestamp filter keeps a re-published doc from competing with its own old version; source_uri is what a cited answer points back to. You design the metadata schema when you design the index — retrofitting it means re-upserting every vector.
Module 5 hands all of this — ingestion, sync, hybrid search — to a managed Bedrock Knowledge Base. Module 14 will monitor vector-store health and retrieval drift.
Exam corner
What the exam tests here. This module covers D1’s vector-store skills (1.4.1 architecture, 1.4.2 metadata frameworks, 1.4.3 high-performance/at-scale design) and the segmentation-and-embeddings skills (1.5.1 document chunking, 1.5.2 embedding solutions, 1.5.3 deploying vector search). The rest of Tasks 1.4/1.5 — document-system connectors and incremental sync (1.4.4/1.4.5), and hybrid search, rerankers, query expansion, and consistent access patterns (1.5.4–1.5.6) — is Module 5; nothing below touches it.
Five scenario questions in the exam’s style; answers follow.
1. A team needs a vector store for a help-center corpus of ~100k chunks. Traffic is spiky, the budget is tight, and there is no dedicated ops team. Which fits best? A. OpenSearch Serverless — it is the standard vector store for RAG. B. Amazon S3 Vectors — it bills ~$0 idle (storage + per-query) and needs no cluster to operate. C. A self-managed OpenSearch cluster on EC2 for full control. D. Aurora PostgreSQL with pgvector, kept running 24/7.
2. Answers consistently miss a passage that you can confirm is in the corpus. Retrieval returns neighboring chunks but never the one with the fact. The best first fix?
A. Increase k from 3 to 20 so more chunks come back.
B. Add a reranker to reorder the results.
C. Re-chunk the source — adjust boundaries, size, or overlap so the fact lands in a retrievable chunk.
D. Switch to a higher-dimensional embedding model.
3. Your corpus is long, structured product manuals with clear headings and sections. You want each retrieved unit to map cleanly to a user’s question. Which chunking strategy fits best? A. Fixed-size chunking with a large overlap. B. Hierarchical chunking on the document headings. C. Semantic chunking on sentence boundaries only. D. One chunk per whole document.
4. You must embed a large, growing corpus on a tight budget and keep recall acceptable. Which approach is soundest? A. Use the highest-dimensional embedding model available, always. B. Choose an embedding model by dimensionality and domain fit, embed in batch to amortize cost, and reuse the same model for corpus and queries. C. Embed the corpus with one model and queries with a cheaper one to save money. D. Skip embeddings and put the whole corpus in the prompt.
5. A shared RAG index serves several customers, and answers for one customer must never surface another’s documents. Which design fits best?
A. Create a separate vector store per customer and route at the application layer only.
B. Attach a tenant_id to each vector’s metadata and apply a metadata filter on every query.
C. Rely on cosine similarity to keep customers’ documents apart.
D. Add the customer name to every chunk’s text so it ranks higher.
Answers. 1 → B. Spiky traffic, tight budget, no ops team is the exact S3 Vectors case — ~$0 idle, no cluster to run; OpenSearch Serverless (A) bills ~$174/month around the clock. 2 → C. If the fact is in the corpus but not retrievable, the chunk boundaries are wrong; re-chunk. A bigger k (A) and a reranker (B) only reorder what retrieval already surfaces — neither makes an unretrievable chunk appear. 3 → B. Long, well-sectioned docs are the hierarchical case: each section becomes a self-contained answer unit. 4 → B. Select the embedder by dimensionality and domain fit, batch to amortize cost, and use one model for both sides — mixing models (C) makes vectors incomparable; “always highest-dimensional” (A) wastes storage and latency. 5 → B. Metadata filtering on tenant_id is the multi-tenant pattern; one index plus filters beats one index per tenant, and similarity (C) provides no isolation guarantee.
Traps to avoid.
- Believing OpenSearch Serverless is mandatory for a vector store. It was the old Knowledge Base default and bills 24/7; for course-scale corpora, S3 Vectors (idle ~$0) is the right answer.
- Confusing the embeddings model with the generation model — two separate choices, sized for recall versus answer, usually two different models.
- Believing a reranker or a bigger
kfixes bad chunking. If the right passage is not in the index in a retrievable form, neither will surface it. The reranker is Module 5; here, you re-chunk.
Key takeaways
- RAG beats fine-tuning for docs that change — cost, freshness, and attribution all favor retrieval; fine-tuning answers a different problem (format, style, a missing skill).
- Chunking is the highest-leverage, least-tuned knob. Retrieval returns a chunk, not a file — cut badly and the answer is in the store but unreachable.
- Choose the embedder for recall, never “by default.” Match dimensionality and domain fit, and embed the corpus and the query with the same model.
- S3 Vectors idles at ~$0; OpenSearch Serverless bills 24/7. That gap is the #1 cost trap in pre-2026 RAG tutorials — the store choice is mostly an economics decision.
- Pure semantic retrieval wobbles on exact identifiers (SKUs, error codes); hybrid search is the fix, and it is Module 5.
- Metadata does the filtering and the multi-tenancy —
category/tenant_id/timestampon each vector serve many customers and many freshness windows from one index. - A bigger context window does not replace retrieval — it just makes it more forgiving; without it you still pay per token, dilute relevance, and lose attribution.
What’s next
You have built retrieval by hand and felt every bolt — now let AWS run it for you. Module 5 turns this into a managed Bedrock Knowledge Base with a reranker and automatic sync (and hybrid search as an exam concept — you’ll measure why it is unavailable on the S3 Vectors store), then benchmarks it against the DIY pipeline you just wrote. The Knowledge Base builds on the same vector bucket and the same 1024-dim Titan contract you pinned today — it ingests docs/ into its own KB-owned index (covered in Module 5), with your relay-docs index kept as the DIY benchmark it measures against.
Want the full AIP-C01 question bank and the next module in your inbox? Subscribe here — it’s free, like everything in this series.
Links: Module 4 lab · ← Module 3 · Course index · Module 5 →
References
- AWS Certified Generative AI Developer - Professional (AIP-C01) exam guide — Tasks 1.4 and 1.5, the vocabulary this module covers.
- Amazon S3 Vectors — vector buckets, indexes, distance metrics, and metadata filtering.
- Amazon Titan Text Embeddings models — Titan V2 dimensionality options (1024/512/256) and the request shape.
- Chunking and parsing for Knowledge Bases — fixed-size, hierarchical, and semantic chunking as the managed service exposes them.
- Amazon Bedrock pricing — re-verify the Titan embeddings per-token figure.
- Amazon S3 pricing — re-verify S3 Vectors storage and query pricing.