const OPENROUTER_API_KEY = '<OPENROUTER_API_KEY>';
const EMBEDDING_MODEL = 'openai/text-embedding-3-small';
const RERANK_MODEL = 'cohere/rerank-v3.5';
const CHAT_MODEL = '~openai/gpt-mini-latest';
const BASE_URL = 'https://openrouter.ai/api/v1';
function getHeaders() {
return {
'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
'Content-Type': 'application/json',
};
}
async function embed(texts: string[]): Promise<number[][]> {
const response = await fetch(`${BASE_URL}/embeddings`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ model: EMBEDDING_MODEL, input: texts }),
});
const data = await response.json();
return data.data.map((item: { embedding: number[] }) => item.embedding);
}
function cosineSimilarity(a: number[], b: number[]): number {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
const magA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
const magB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
return dot / (magA * magB);
}
function retrieve(
queryEmbedding: number[],
docEmbeddings: number[][],
topN = 10,
): { index: number; score: number }[] {
const scored = docEmbeddings.map((emb, i) => ({
index: i,
score: cosineSimilarity(queryEmbedding, emb),
}));
scored.sort((a, b) => b.score - a.score);
return scored.slice(0, topN);
}
async function rerank(query: string, documents: string[], topN = 3) {
const response = await fetch(`${BASE_URL}/rerank`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({
model: RERANK_MODEL,
query,
documents,
top_n: topN,
}),
});
const data = await response.json();
return data.results as { index: number; relevance_score: number; document: { text: string } }[];
}
async function generate(query: string, contextDocs: string[]): Promise<string> {
const context = contextDocs
.map((doc, i) => `[${i + 1}] ${doc}`)
.join('\n\n');
const response = await fetch(`${BASE_URL}/responses`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({
model: CHAT_MODEL,
instructions:
"Answer the user's question using only the provided context. " +
'Cite sources with [n]. If the context is insufficient, say so.',
input: `Context:\n${context}\n\nQuestion: ${query}`,
}),
});
const data = await response.json();
return [...data.output]
.reverse()
.find((item: { type: string }) => item.type === 'message')
.content.find((part: { type: string }) => part.type === 'output_text').text;
}
// --- Pipeline ---
// 1. Index: chunk your knowledge base and embed
const chunks = [
'OpenRouter is a unified API gateway for LLMs. It aggregates models from multiple providers into a single OpenAI-compatible interface.',
'RAG stands for Retrieval-Augmented Generation. It retrieves relevant documents and uses them as context for LLM generation.',
'Embeddings convert text into high-dimensional vectors where semantically similar texts are closer together.',
'Reranking uses a cross-encoder to compare each document directly against the query, producing more accurate relevance scores than embedding similarity alone.',
'Vector databases like Pinecone, Weaviate, and Qdrant are optimized for storing and querying embedding vectors at scale.',
'Prompt caching reduces costs by reusing computations for repeated prompt prefixes across requests.',
'OpenRouter supports provider routing to control which upstream providers serve your requests based on cost, latency, or privacy preferences.',
];
const docEmbeddings = await embed(chunks);
// 2. Retrieve: embed the query and find similar chunks
const query = 'How does RAG improve LLM responses?';
const queryEmbedding = (await embed([query]))[0];
const topMatches = retrieve(queryEmbedding, docEmbeddings, 5);
const retrievedTexts = topMatches.map((m) => chunks[m.index]);
// 3. Rerank: re-score with a cross-encoder for better precision
const reranked = await rerank(query, retrievedTexts, 3);
const contextTexts = reranked.map((r) => r.document.text);
// 4. Generate: produce a grounded answer
const answer = await generate(query, contextTexts);
console.log(`Q: ${query}\nA: ${answer}`);