typescriptadvanced

RAG Pipeline Implementation

Build a retrieval-augmented generation pipeline that grounds LLM answers in your own documents.

typescript
import { openai } from './openai-client';

interface Document {
  id: string;
  content: string;
  embedding: number[];
  metadata: Record<string, string>;
}

function cosineSim(a: number[], b: number[]): number {
  let dot = 0, magA = 0, magB = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i];
    magA += a[i] ** 2;
    magB += b[i] ** 2;
  }
  return dot / (Math.sqrt(magA) * Math.sqrt(magB));
}

async function embed(text: string): Promise<number[]> {
  const res = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: text,
  });
  return res.data[0].embedding;
}

async function ragQuery(
  query: string,
  docs: Document[],
  topK = 3
): Promise<string> {
  const queryEmb = await embed(query);
  const ranked = docs
    .map(d => ({ ...d, score: cosineSim(queryEmb, d.embedding) }))
    .sort((a, b) => b.score - a.score)
    .slice(0, topK);

  const context = ranked.map(d => d.content).join('\n---\n');
  const res = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: `Answer using ONLY the context below:\n${context}` },
      { role: 'user', content: query },
    ],
  });
  return res.choices[0].message.content ?? '';
}

Use Cases

  • Grounding LLM answers in private documents
  • Building chatbots with domain-specific knowledge

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.