Bedrock Knowledge Bases: Chunking Strategies That Fit Code RAG

Bedrock Knowledge Bases: Chunking Strategies That Fit Code RAG

Fixed 300-token windows shred functions mid-signature. Pure markdown splitters worship READMEs and ignore the call graph. Code RAG on Bedrock Knowledge Bases only works when chunking respects symbols: one coherent unit per function/class (plus a thin caller hint), metadata for repo/language/path, and enough overlap that cross-file types still retrieve. This is the senior playbook for chunking that returns the right function — not a random docstring.

⚡ TL;DR: Prefer AST-aware chunks (tree-sitter / ts-morph) sized to symbols; fall back to semantic splits for prose docs; use fixed-size only for logs. Attach metadata (repo, path, symbol, language). Keep parent headers in every child chunk. Evaluate with hit-rate@k on real developer questions. Deep dive companions: RAG OpenSearch vs pgvector, Bedrock Agents guardrails.

Fixed-size: when it still wins

Fixed windows are fine for homogeneous prose and terrible for TypeScript services.

# ❌ Fixed-size on source — splits mid-function
def fixed_chunks(text: str, size: int = 800, overlap: int = 100):
    out = []
    i = 0
    while i < len(text):
        out.append(text[i : i + size])
        i += size - overlap
    return out
# ✅ Fixed-size only for runbooks / plain ADRs
def fixed_for_prose(path: str, text: str):
    if path.endswith((".md", ".txt")) and "/src/" not in path:
        return fixed_chunks(text, size=1200, overlap=150)
    raise ValueError("use_ast_chunker_for_code")

Semantic chunking for docs

Embed consecutive sentences; cut when cosine similarity drops. Good for ADRs and wiki pages feeding the same KB.

import numpy as np

def semantic_breaks(sentence_embeddings: list[np.ndarray], threshold: float = 0.55):
    breaks = [0]
    for i in range(1, len(sentence_embeddings)):
        sim = float(np.dot(sentence_embeddings[i - 1], sentence_embeddings[i]))
        if sim < threshold:
            breaks.append(i)
    breaks.append(len(sentence_embeddings))
    return breaks  # slice sentences[breaks[j]:breaks[j+1]]

AST-aware chunking for code (the default)

Parse with tree-sitter or ts-morph; emit one chunk per exported function/class with signature, body, and a one-line file path header.

// chunk-ts.ts — illustrative ts-morph chunker
import { Project } from "ts-morph";

export function chunkTypeScript(filePath: string, source: string) {
  const project = new Project({ useInMemoryFileSystem: true });
  const sf = project.createSourceFile(filePath, source);
  const chunks: { id: string; text: string; metadata: Record<string, string> }[] = [];

  for (const fn of sf.getFunctions()) {
    if (!fn.isExported()) continue;
    const name = fn.getName() ?? "anonymous";
    const start = fn.getStartLineNumber();
    const text = `// file: ${filePath}\n// symbol: ${name}\n${fn.getText()}`;
    // ✅ Symbol-bounded chunk with path breadcrumb
    chunks.push({
      id: `${filePath}::${name}`,
      text,
      metadata: { path: filePath, symbol: name, language: "typescript", start: String(start) },
    });
  }

  // ❌ Don’t embed import-only noise as its own retrieval unit
  return chunks.filter((c) => c.text.split("\n").length > 3);
}

Bedrock KB ingestion knobs that matter

When using Bedrock Knowledge Bases, set chunking strategy explicitly for each data source. For code, prefer ingesting pre-chunked objects (one S3 object or one document per symbol) so the service does not re-split your careful AST units. Put metadata attributes Bedrock can filter later (repo, language, team).

{
  "chunkingStrategy": "NONE",
  "comment": "Pre-chunked AST units already in S3; do not re-window"
}
# ✅ Upload one JSON/text object per symbol with metadata sidecar
aws s3 cp chunks/auth/getSession.json s3://kb-code/auth/getSession.json \
  --metadata language=typescript,repo=platform,symbol=getSession

Compare retrieval backends and when pgvector beats OpenSearch in RAG on AWS. Cache hot system prompts with Bedrock Prompt Caching.

Evaluate chunking, don’t argue about it

Metric Target (illustrative)
Hit-rate@5 on golden Qs ≥ 0.85 for symbol questions
Exact-symbol recall ≥ 0.9 when query names the function
Doc-only questions Prefer semantic chunks, not AST
Avg chunk tokens 200–800 for code; avoid 50-token crumbs
def hit_at_k(retrieved_ids: list[str], gold_ids: set[str], k: int = 5) -> float:
    return 1.0 if gold_ids.intersection(retrieved_ids[:k]) else 0.0

Closing checklist

✅ Dos
– ✅ AST-chunk code; semantic-chunk prose; fixed-size only for logs
– ✅ Prefix every chunk with file: + symbol:
– ✅ Use chunkingStrategy: NONE when pre-chunked
– ✅ Attach filterable metadata (repo, language, team)
– ✅ Measure hit-rate@k on real engineer questions

❌ Don’ts
– ❌ Don’t fixed-window TypeScript services
– ❌ Don’t index node_modules or generated clients
– ❌ Don’t let KB re-split careful AST units
– ❌ Don’t omit path breadcrumbs
– ❌ Don’t tune chunk size by vibes alone

Related reading

Last updated on September 11, 2026


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

1 Comment

Leave a Reply