Prompt Engineering Codex Β· CH 19

Chapter 19: Prompt Engineering for RAG Systems

⏱️ 4 min read·Updated Jul 2026

RAG Is a Multi-Prompt System

A RAG (Retrieval-Augmented Generation) system is not one prompt β€” it is three or four distinct prompts working together:

    • Query transformation prompt: Converts the user's question into an optimal search query
    • Retrieval grading prompt: Evaluates whether retrieved documents are actually relevant
    • Generation prompt: Synthesises retrieved context into an answer
    • Citation and verification prompt: Adds sources and checks for hallucination
Each needs to be engineered separately. Getting one wrong breaks the whole pipeline.

---

Prompt 1: Query Transformation

Users rarely ask questions in the format that retrieves the best results. Their language is conversational. The database expects precise, information-rich queries.

javascript
async function transformQuery(userQuestion) {
  const response = await client.chat.completions.create({
    model: 'gpt-4o-mini',
    messages: [{
      role: 'user',
      content: 'Transform this conversational question into an optimal search query for a vector database.\n\nRules:\n- Remove filler words (what, how, can you, please, etc.)\n- Keep only the information-bearing terms\n- Add synonyms or related terms that might help retrieve relevant documents\n- If the question contains multiple sub-questions, produce multiple queries\n\nOutput JSON: { "queries": string[] }\n\nQuestion: ' + userQuestion
    }],
    response_format: { type: 'json_object' },
    temperature: 0.0,
  });
  
  const { queries } = JSON.parse(response.choices[0].message.content);
  return queries;
}

// Example transformation:
// Input: "Hey, can you tell me what the refund policy is if I cancel my subscription?"
// Output: ["subscription cancellation refund policy", "cancel subscription money back", "subscription refund terms conditions"]

Multi-Query Retrieval

javascript
async function multiQueryRetrieval(userQuestion, limit = 5) {
  const queries = await transformQuery(userQuestion);
  
  const allResults = await Promise.all(
    queries.map(query => searchVectorDb(query, limit))
  );
  
  // Deduplicate by document ID, keeping highest similarity score
  const seen = new Map();
  for (const results of allResults) {
    for (const result of results) {
      if (!seen.has(result.id) || seen.get(result.id).similarity < result.similarity) {
        seen.set(result.id, result);
      }
    }
  }
  
  return Array.from(seen.values())
    .sort((a, b) => b.similarity - a.similarity)
    .slice(0, limit);
}

---

Prompt 2: Retrieval Grading

Not all retrieved documents are relevant. Add a relevance grading step that filters out poor matches before passing context to the generation model:

javascript
async function gradeRelevance(question, documents) {
  const gradingPromises = documents.map(doc =>
    client.chat.completions.create({
      model: 'gpt-4o-mini',
      messages: [{
        role: 'user',
        content: 'Is this document relevant to answering the question?\n\nQuestion: ' + question + '\n\nDocument: ' + doc.content + '\n\nOutput JSON: { "relevant": boolean, "reason": string }'
      }],
      response_format: { type: 'json_object' },
      temperature: 0.0,
    })
  );
  
  const grades = await Promise.all(gradingPromises);
  
  return documents.filter((doc, i) => {
    const grade = JSON.parse(grades[i].choices[0].message.content);
    return grade.relevant;
  });
}

This filter step reduces hallucination significantly β€” the model cannot be led astray by irrelevant documents it is forced to cite.

---

Prompt 3: Grounded Generation

The generation prompt must enforce strict grounding:

javascript
function buildGenerationPrompt(question, relevantDocs) {
  const context = relevantDocs.map((doc, i) => 
    '[Document ' + (i+1) + '] (Source: ' + (doc.metadata.source || 'Unknown') + ')\n' + doc.content
  ).join('\n\n---\n\n');
  
  return [
    'You are a precise question-answering assistant. Answer the user\'s question based ONLY on the provided context documents.',
    '',
    'STRICT RULES:',
    '1. Only use information explicitly stated in the provided documents',
    '2. If the documents do not contain enough information, say: "The available documents do not contain sufficient information to answer this question fully."',
    '3. Do not use any knowledge from your training data β€” only the provided documents',
    '4. For every factual claim, cite the document number in brackets like [1] or [2]',
    '5. If documents contain conflicting information, acknowledge the conflict explicitly',
    '6. Do not speculate beyond what the documents say',
    '',
    'Context Documents:',
    context,
    '',
    'Question: ' + question,
    '',
    'Answer (with citations):'
  ].join('\n');
}

---

Prompt 4: Hallucination Detection

After generation, add a verification step that checks the output against the source documents:

javascript
async function verifyAnswer(question, answer, sourceDocs) {
  const verification = await client.chat.completions.create({
    model: 'gpt-4o',
    messages: [{
      role: 'user',
      content: 'Verify this answer against the source documents. Identify any claims in the answer that are not supported by the provided documents.\n\nQuestion: ' + question + '\n\nAnswer to verify:\n' + answer + '\n\nSource documents:\n' + sourceDocs.map((d, i) => '[' + (i+1) + '] ' + d.content).join('\n\n') + '\n\nOutput JSON: { "verified": boolean, "unsupported_claims": string[], "confidence": "high"|"medium"|"low", "recommendation": "use_as_is"|"add_caveats"|"regenerate" }'
    }],
    response_format: { type: 'json_object' },
    temperature: 0.0,
  });
  
  return JSON.parse(verification.choices[0].message.content);
}

---

Handling Knowledge Gaps Gracefully

When the system cannot answer a question from the available documents, the response matters. A RAG system that gracefully admits knowledge gaps is far more trustworthy than one that hallucinates answers.

javascript
function handleKnowledgeGap(question, context) {
  if (context.length === 0 || allDocumentsLowRelevance(context)) {
    return {
      answer: 'I don\'t have information about this topic in my current knowledge base. ' + getSuggestion(question),
      sources: [],
      knowledge_gap: true,
    };
  }
  
  return generateWithCaveats(question, context);
}

Finished reading this chapter?

Mark it completed to update your AI Builder skill profile score on your dashboard.

πŸ“‹

Download Printable Chapter Checklist

Get a print-friendly, formatted checklist of workspace actions to apply this chapter offline.