How to Build a RAG Pipeline with YouTube Transcripts
A working RAG pipeline over YouTube video transcripts: collect transcripts across a video list, chunk them, embed and store the vectors, retrieve the relevant chunks, and generate a cited answer - full code for every step, plus how to keep the index fresh.
00:09:00 · SEP 27, 2026
Hızlı yanıt
Transkriptleri toplayın
panelden bir anahtar alın (100 ücretsiz kredi, kart gerekmez) ve her videonun transkriptini id'sine göre alın. Krediler video dakikası başına değil, istek başına alınır, bu yüzden 3 saatlik bir ders 2 dakikalık bir klip ile aynı 1 krediye mal olur - bir kanalın tüm arşivini içeri aktarırken bu önemlidir:
async function fetchTranscript(videoId: string) {
const res = await fetch(
`https://getyoutubetranscript.com/api/v1/transcript?v=${videoId}`,
{ headers: { Authorization: `Bearer ${process.env.GETYOUTUBETRANSCRIPT_API_KEY}` } }
);
const json = await res.json();
if (!json.success) throw new Error(json.message);
return json.data as { video_id: string; title: string; transcript: string; word_count: number };
}
const videoIds = ['dQw4w9WgXcQ', 'jNQXAC9IVRw' /* ... */];
const videos = await Promise.all(videoIds.map(fetchTranscript));video_id ve title, transkript metniyle birlikte döner - 5. adımın yanıtı geri atıfladığı şey tam olarak budur.
Transkriptleri parçalara bölün
Her transkripti embedding'e dönüştürmeden önce üst üste binen pencerelere bölün - tüm videoyu tek bir embedding'e dönüştürmek belirli bir yanıtı almak için çok kaba olur ve bunun için hiçbir kütüphaneye gerek yoktur:
function chunkText(text: string, size = 1200, overlap = 200) {
const chunks: string[] = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + size, text.length);
chunks.push(text.slice(start, end));
start += size - overlap;
}
return chunks;
}
const records = videos.flatMap((video) =>
chunkText(video.transcript).map((text, chunkIndex) => ({
videoId: video.video_id,
title: video.title,
chunkIndex,
text,
}))
);Konuşma metinleri için 200 karakter örtüşmeli 1.200 karakterlik bir pencere makul bir varsayılandır - kısa, yoğun klipler için küçültün, daha fazla çevresel bağlamın yardımcı olduğu uzun ders tarzı içerikler için büyütün.
Embedding'e dönüştürün ve saklayın
Her parçayı embedding'e dönüştürün ve video id'sini ve başlığı vektörle birlikte saklayın, çünkü alınan bir parçayı daha sonra bir atıfa dönüştüren şey tam olarak budur:
import OpenAI from 'openai';
const openai = new OpenAI();
async function embed(text: string) {
const res = await openai.embeddings.create({ model: 'text-embedding-3-small', input: text });
return res.data[0].embedding;
}
const index = await Promise.all(
records.map(async (r) => ({ ...r, embedding: await embed(r.text) }))
);Bu, netlik için vektörleri bellekte tutar. Birkaç yüz parçadan sonra, diziyi pgvector, Pinecone veya başka bir vektör deposuyla değiştirin - aşağıdaki alma adımı yalnızca en yakın k vektörü döndüren bir fonksiyona ihtiyaç duyar, tam olarak bu şekle değil.
İlgili parçaları alın
Sorgu anında, soruyu aynı modelle embedding'e dönüştürün ve saklanan parçaları kosinüs benzerliğine göre sıralayın:
function cosineSimilarity(a: number[], b: number[]) {
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] ** 2;
normB += b[i] ** 2;
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
async function retrieve(query: string, k = 5) {
const queryEmbedding = await embed(query);
return index
.map((r) => ({ ...r, score: cosineSimilarity(r.embedding, queryEmbedding) }))
.sort((a, b) => b.score - a.score)
.slice(0, k);
}k=5 iyi bir başlangıç noktasıdır - çok az parça modelin tam olarak yanıt vermesi için yeterli bağlama sahip olmamasına, çok fazlası ise alakasız parçaların yanıtı sulandırmaya başlamasına yol açar.
Temellendirilmiş bir yanıt üretin
Alınan parçaları modele numaralandırılmış bağlam olarak verin ve yalnızca oradakinden yanıt vermesini ve kaynaklarına atıfta bulunmasını söyleyin - yanıtı modelin kendi genel bilgisi yerine gerçek bir videoya kadar izlenebilir kılan şey budur:
async function answer(query: string) {
const matches = await retrieve(query);
const context = matches
.map((m, i) => `[${i + 1}] From "${m.title}":\n${m.text}`)
.join('\n\n');
const completion = await openai.chat.completions.create({
model: 'gpt-4.1-mini',
messages: [
{
role: 'system',
content:
"Answer only using the numbered transcript excerpts below. Cite sources as [1], [2], etc. " +
"If the excerpts don't contain the answer, say so.",
},
{ role: 'user', content: `${context}\n\nQuestion: ${query}` },
],
});
return completion.choices[0].message.content;
}Bir zaman damgası uydurmak yerine video başlığına göre atıf yapmak, transkript API'sinin gerçekte döndürdüğü şeyle örtüşür - modelin kendisine hiç verilmemiş bir zaman damgası uydurmasına izin vermeyin.
Dizini güncel tutun
Yayın yapmaya devam eden bir kanal için, ücretsiz /channel/latest uç noktasıyla (0 kredi) yeni yüklemeleri belirli aralıklarla kontrol edin, zaten dizine eklediğiniz video id'lerini atlayın ve yalnızca yenilerini alın, parçalayın ve embedding'e dönüştürün. Böylece içe aktarma maliyeti her çalıştırmada tam bir yeniden indeksleme yerine yeni içerikle orantılı kalır.
Transkriptler RAG için neden iyi çalışır
Video, üzerinde arama yapılacak bir yapı kurmak için en zahmetli formatlardan biridir - bir videoda grep yapamazsınız. Bir transkript, kendi konuşmadan-metne işinizi çalıştırmanıza gerek kalmadan onu mevcut embedding ve alma yığınınızın zaten nasıl işleyeceğini bildiği metne geri dönüştürür. Ve istek başına ücretlendirilen bir transkript API'si video uzunluğuna göre ölçmediği için, uzun biçimli içeriklerden (podcast'ler, dersler, çok saatlik yayınlar) oluşan bir arşivi içeri aktarmak, kısa klipleri içeri aktarmaktan sistematik olarak daha pahalıya gelmez - ki bir RAG pipeline'ının genellikle aramak üzere kurulduğu arşiv tam olarak budur.
Tam endpoint referansı, kimlik doğrulama ve hız limitleri API belgelerinde yer alır. Bunu baştan sona denemek için panelden 100 ücretsiz kredi içeren bir anahtar alın.
RAG pipeline SSS
Bunu takip etmek için gerçek bir vektör veritabanına ihtiyacım var mı?
Hayır - bu kılavuzdaki bellek içi dizi birkaç yüz parçaya kadar sorunsuz çalışır ve pipeline'ı baştan sona doğrulamanın en hızlı yoludur. Bundan fazlasını dizine eklemeniz gerektiğinde veya dizinin yeniden başlatmalar arasında kalıcı olması gerektiğinde pgvector'a veya yönetilen bir vektör deposuna geçin.
Hangi embedding modelini kullanmalıyım?
text-embedding-3-small makul bir varsayılandır - ucuzdur ve çoğu transkript alma işi için yeterince iyidir. Yalnızca makul şekilde düzeltebileceği bir alma kalitesi sorunu görüyorsanız text-embedding-3-large'a geçin; çağrı başına daha pahalıdır.
Bir videonun hiç transkripti yoksa ne olur?
Transkript endpoint'i boş bir dize yerine net bir hata kodu döndürür (TRANSCRIPT_DISABLED veya TRANSCRIPT_NOT_FOUND) - o videoyu gerçek içerikmiş gibi boş bir dizeyi embedding'e dönüştürmek yerine success: false olup olmadığını kontrol edip atlayın.
Diyelim ki 200 videoyu dizine eklemenin maliyeti nedir?
2 dakikalık klipler mi yoksa 2 saatlik videolar mı olduğuna bakılmaksızın transkript alma işlemleri için 200 kredi - 100 ücretsiz kayıt kredisi tek başına 200 videoluk bir arşivin kabaca yarısını karşılar. Embedding maliyeti ayrıdır ve embedding sağlayıcınız tarafından faturalandırılır.
Sadece video başlığı yerine kesin bir zaman damgasına atıfta bulunabilir miyim?
Bu endpoint ile değil - genel transkript API'si zaman damgalı segmentler değil, düz metin döndürür, bu yüzden buradaki örnekler video başlığı ve id'sine göre atıf yapar. Zaman damgası düzeyinde atıf kullanım durumunuz için önemliyse, video düzeyindeki atfın olabildiğince kesin kalması için parçaları küçük tutun.
İlgili
- YouTube API Quota Exceeded: Causes and Fixes
- YouTube Transcript API Rate Limit: What It Is and How to Handle 429s
- YouTube Transcript MCP Server: Setup Guide for Claude and Other AI Tools
- YouTube Transcripts in n8n: HTTP Request Workflow Guide
- Migrating from Supadata: A Field Guide
- How to Get YouTube Transcripts in Python
- Migrating from TranscriptAPI.com: A Field Guide
- Build an AI YouTube Video Summarizer with LangChain and Next.js
- The Best YouTube Transcript APIs in 2026
- GetYouTubeTranscript ve TranscriptAPI karşılaştırması
- GetYouTubeTranscript ve youtubetotranscript.com karşılaştırması
- GetYouTubeTranscript ve youtube-transcript.io karşılaştırması
- GetYouTubeTranscript vs NoteGPT