RetrieveAndGenerate vs Retrieve-Then-Prompt
Managed RAG orchestration vs building your own retrieval-augmentation loop.
Busca en todas las páginas de la documentación
Managed RAG orchestration vs building your own retrieval-augmentation loop.
Every Knowledge Base query eventually needs to turn retrieved passages into a generated answer. Bedrock gives you two ways to get there: let it manage the whole thing with RetrieveAndGenerate, or call Retrieve yourself and build the prompt with Converse. This page runs the same question through both so the trade-off is concrete, then gives you a rule for choosing.
Quick-reference recipe card - copy-paste ready.
# --- Python (boto3) ---
import boto3
agent_rt = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
# RetrieveAndGenerate: one call, managed prompt, built-in citations.
resp = agent_rt.retrieve_and_generate(
input={"text": "What is our refund policy?"},
retrieveAndGenerateConfiguration={
"type": "KNOWLEDGE_BASE",
"knowledgeBaseConfiguration": {
"knowledgeBaseId": kb_id,
"modelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-lite-v1:0",
},
},
)
print(resp["output"]["text"])// --- TypeScript (AWS SDK v3) ---
import { BedrockAgentRuntimeClient, RetrieveAndGenerateCommand } from "@aws-sdk/client-bedrock-agent-runtime";
const agentRt = new BedrockAgentRuntimeClient({ region: "us-east-1" });
// RetrieveAndGenerate: one call, managed prompt, built-in citations.
const resp = await agentRt.send(new RetrieveAndGenerateCommand({
input: { text: "What is our refund policy?" },
retrieveAndGenerateConfiguration: {
type: "KNOWLEDGE_BASE",
knowledgeBaseConfiguration: {
knowledgeBaseId: kbId,
modelArn: "arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-lite-v1:0",
},
},
}));
console.log(resp.output?.text);When to reach for each:
Here is the same question answered both ways: first the managed one-call path, then the two-step path where you build the Converse prompt yourself from raw retrieved passages.
# --- Python (boto3) ---
import boto3
agent_rt = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
brt = boto3.client("bedrock-runtime", region_name="us-east-1")
question = "What is our refund policy?"
# 1. RetrieveAndGenerate - managed prompt and generation in one call.
managed = agent_rt.retrieve_and_generate(
input={"text": question},
retrieveAndGenerateConfiguration={
"type": "KNOWLEDGE_BASE",
"knowledgeBaseConfiguration": {
"knowledgeBaseId": kb_id,
"modelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-lite-v1:0",
},
},
)
print("Managed:", managed["output"]["text"])
# 2. Retrieve-then-prompt - you own the prompt.
passages = agent_rt.retrieve(
knowledgeBaseId=kb_id,
retrievalQuery={"text": question},
retrievalConfiguration={"vectorSearchConfiguration": {"numberOfResults": 3}},
)["retrievalResults"]
context = "\n\n".join(p["content"]["text"] for p in passages)
prompt = (
f"Answer using only the context below. If the answer isn't there, say so.\n\n"
f"Context:\n{context}\n\nQuestion: {question}"
)
custom = brt.converse(
modelId="amazon.nova-lite-v1:0",
messages=[{"role": "user", "content": [{"text": prompt}]}],
inferenceConfig={"maxTokens": 300},
)
print("Custom:", custom["output"]["message"]["content"][0]["text"])// --- TypeScript (AWS SDK v3) ---
import { BedrockAgentRuntimeClient, RetrieveCommand, RetrieveAndGenerateCommand } from "@aws-sdk/client-bedrock-agent-runtime";
import { BedrockRuntimeClient, ConverseCommand } from "@aws-sdk/client-bedrock-runtime";
const agentRt = new BedrockAgentRuntimeClient({ region: "us-east-1" });
const brt = new BedrockRuntimeClient({ region: "us-east-1" });
const question = "What is our refund policy?";
// 1. RetrieveAndGenerate - managed prompt and generation in one call.
const managed = await agentRt.send(new RetrieveAndGenerateCommand({
input: { text: question },
retrieveAndGenerateConfiguration: {
type: "KNOWLEDGE_BASE",
knowledgeBaseConfiguration: {
knowledgeBaseId: kbId,
modelArn: "arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-lite-v1:0",
},
},
}));
console.log("Managed:", managed.output?.text);
// 2. Retrieve-then-prompt - you own the prompt.
const retrieved = await agentRt.send(new RetrieveCommand({
knowledgeBaseId: kbId,
retrievalQuery: { text: question },
retrievalConfiguration: { vectorSearchConfiguration: { numberOfResults: 3 } },
}));
const passages = retrieved.retrievalResults ?? [];
const context = passages.map((p) => p.content?.text).join("\n\n");
const prompt = `Answer using only the context below. If the answer isn't there, say so.\n\nContext:\n${context}\n\nQuestion: ${question}`;
const custom = await brt.send(new ConverseCommand({
modelId: "amazon.nova-lite-v1:0",
messages: [{ role: "user", content: [{ text: prompt }] }],
inferenceConfig: { maxTokens: 300 },
}));
console.log("Custom:", custom.output?.message?.content?.[0]?.text);What this demonstrates:
RetrieveAndGenerate never exposes the intermediate prompt - you get output.text and citations directly.Retrieve gives you raw passages (content.text, score, location) that you assemble into your own prompt string.bedrock-runtime (Converse) as a second, separate client from bedrock-agent-runtime - retrieval and generation are decoupled.RetrieveAndGenerate runs retrieval, builds a prompt that instructs the model to answer from the retrieved passages, calls the generation model, and parses citations that map parts of the answer back to specific retrieved passages. All of that - the prompt template, the citation extraction - is Bedrock's implementation, not yours to inspect or edit line by line. You configure what it retrieves from and which model generates, not the literal prompt text.
Calling Retrieve directly gives you the passages and nothing else - no prompt, no generation. You then own every subsequent decision: how to format the context, what system instructions to add, whether to include conversation history, whether to mix in results from a tool call or a second Knowledge Base, and which model (any Bedrock model, via Converse) actually generates the answer. This is strictly more work, and strictly more control.
RetrieveAndGenerate's citations array is a meaningful advantage - it maps generated text back to source passages automatically, which is exactly the kind of bookkeeping you'd otherwise have to build yourself (asking the model to cite sources reliably in free text is unreliable). If you go the retrieve-then-prompt route and need citations, budget time to build that yourself - for example, by asking the model to reference passage numbers you assign, then mapping them back in your own code.
RetrieveAndGenerate is scoped to what it retrieves from the configured Knowledge Base (or Knowledge Bases, if you configure more than one). It has no mechanism for injecting arbitrary extra context - a tool result, a user's account data fetched separately, prior conversation turns from a different system. Retrieve-then-prompt has none of that limitation, because you are building the final Converse messages array yourself and can put anything in it.
Both paths support streaming. RetrieveAndGenerateStream (or the stream variant of the same operation) streams the generated answer as it is produced; the retrieve-then-prompt path streams via ConverseStream after your own synchronous Retrieve call. Neither streams the retrieval step itself - retrieval is a fast, single round trip either way, and streaming benefits apply to the generation half.
bedrock-agent-runtime for Retrieve, bedrock-runtime for Converse. Fix: import and construct both clients; they are not interchangeable.| Approach | Use When | Don't Use When |
|---|---|---|
| RetrieveAndGenerate (managed) | Fastest path to a working RAG answer with citations | You need custom prompt structure or extra non-retrieved context |
| Retrieve then Converse (manual) | Custom prompts, mixed context, non-Bedrock generation, agent loops | You want the least code and citations built in |
| Retrieve then RetrieveAndGenerate together | You want raw passages for logging/debugging and a managed answer | You only need one or the other - calling both is redundant work |
| Agentic retriever orchestration | The question itself is multi-step and a single retrieval pass under-serves it | A single-fact question that either pattern already answers well |
RetrieveAndGenerate. It is one call, includes managed prompt construction, and gives you citations without extra work. Drop to retrieve-then-prompt for a concrete reason.
Not directly - the prompt template is Bedrock's implementation detail. If you need to control the exact prompt wording, use retrieve-then-prompt instead.
The response includes a citations array mapping parts of the generated answer back to specific retrievedReferences (passages and their source locations), built automatically.
Not with RetrieveAndGenerate alone - it only uses what it retrieves. Use retrieve-then-prompt to combine retrieved passages with tool results or other data in your own Converse call.
Both call bedrock-agent-runtime for retrieval. RetrieveAndGenerate handles generation internally; retrieve-then-prompt additionally calls bedrock-runtime (Converse) yourself.
Not inherently - both are billed by tokens for the generation step, and retrieval itself is not separately token-billed. Compare actual usage on your workload rather than assuming either is cheaper by default.
Retrieve and RetrieveAndGenerate calls.Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+). Bedrock Knowledge Bases' Agentic Retriever is a fast-evolving 2026 capability - verify exact parameters against current docs.
Revisado por Chris St. John·Última actualización: 24 jul 2026