Delphi'de RAG: Bir LLM'yi Kendi Belgelerinizle Temellendirin

· Bileşenler

Hızlı yanıt: Retrieval-Augmented Generation (RAG), birbirine yapıştırılmış iki fikirden oluşur. Önce belgelerinizi bir kez gömer ve ortaya çıkan vektörleri saklarsınız. Ardından, her soruda soruyu gömer, anlam bakımından en yakın parçaları getirir ve bunları bağlam olarak LLM'ye verirsiniz; böylece yanıt modelin eğitim belleği yerine sizin verilerinizden gelir. sgcWebSockets'te tüm hattı üç bileşen oluşturur: metni vektörlere dönüştürmek için TsgcAIOpenAIEmbeddings, bunları saklayıp aramak için TsgcAIDatabaseVectorFile veya TsgcAIDatabaseVectorPinecone ve nihai temellendirilmiş yanıtı yazmak için TsgcHTTP_API_OpenAI.

Genel amaçlı bir sohbet modeli dünya hakkında çok şey bilir, ancak ürün kılavuzunuz, destek talepleriniz veya geçen çeyreğin iç raporu hakkında hiçbir şey bilmez. Bunları sorduğunuzda ya reddeder ya da daha kötüsü, makul görünen bir şey uydurur. RAG bunu hiçbir şeyi yeniden eğitmeden düzeltir: modeli olduğu gibi tutar ve soru anında kendi derleminizden doğru pasajları ona verirsiniz. Aşağıda Delphi'de baştan sona tüm döngü, gerçek bileşen adlarıyla yer alıyor.

RAG aslında ne yapar

Bir gömme (embedding), bir metin parçasının anlamını yakalayan bir sayı listesidir. Aynı konu hakkındaki iki pasaj, hiç ortak anahtar sözcükleri olmasa bile bu sayısal uzayda birbirine yakın düşer. Bir vektör veritabanı bu sayıları saklar ve bir sorgu vektörü verildiğinde, benzerliğe göre sıralanmış en yakın girdileri döndürür. RAG bunları bir araya getirir:

AşamaNe olursgcWebSockets parçası
1. Alma (bir kez)Belgeleri parçalara bölün, her parçayı gömün, vektörleri saklayınTsgcAIOpenAIEmbeddings.CreateEmbeddingsFromFile
2. SaklamaVektörleri yerel bir dosyada veya bir bulut dizininde tutunTsgcAIDatabaseVectorFile · TsgcAIDatabaseVectorPinecone
3. Getirme (her soru için)Soruyu gömün, en yakın parçaları bulunGetEmbeddingQueryData
4. Yanıt vermeParçaları istemin içine koyun, modele sorunTsgcHTTP_API_OpenAI._CreateChatCompletion

Adım 1 ve 2, verileriniz değiştiğinde çalışır. Adım 3 ve 4 ise her kullanıcı sorusunda çalışır. Şimdi her birini kuralım.

Adım 1 — belgelerinizi gömün

Bir TsgcAIOpenAIEmbeddings oluşturun, ona bir OpenAI anahtarı verin, Database özelliğini bir vektör deposuna yönlendirin ve CreateEmbeddingsFromFile çağırın. Bu tek çağrı dosyayı okur, parçalara böler (EmbeddingsOptions.ChunkSize ile denetlenir), her parçayı gömer ve vektörleri sizin için BeginAddData / AddData / EndAddData dizisi aracılığıyla depoya yazar.

uses
  sgcAI, sgcAI_OpenAI_Embeddings,
  sgcAI_DB_Vector, sgcAI_DB_Vector_File, sgcAI_DB_Vector_Pinecone;

var
  Embeddings: TsgcAIOpenAIEmbeddings;
  DBFile: TsgcAIDatabaseVectorFile;
begin
  Embeddings := TsgcAIOpenAIEmbeddings.Create(nil);
  Embeddings.OpenAIOptions.ApiKey := 'sk-...';

  // local, file-based vector store
  DBFile := TsgcAIDatabaseVectorFile.Create(nil);
  DBFile.VectorFileOptions.InputFilename  := 'corpus.sgcif';
  DBFile.VectorFileOptions.VectorFilename := 'corpus.sgcvf';

  Embeddings.Database := DBFile;
  Embeddings.CreateEmbeddingsFromFile('docs.txt');
end;

Alma adımının tamamı budur. Bir kez, ya da belgeleriniz her değiştiğinde çalıştırın. Varsayılan gömme modeli text-embedding-3-small'dur; farklı bir tane gerekiyorsa EmbeddingsOptions.Model üzerinden değiştirin. Embeddings bileşeni sayfasında daha fazla ayrıntı var.

Adım 2 — vektörlerin nerede yaşayacağını seçin

Her iki arka uç da aynı temel bileşenden, TsgcAIDatabaseVector'dan türer, dolayısıyla birbirinin yerine kullanılabilirler: birini diğeriyle değiştirin, alma ve sorgu kodunuz değişmez. Tek fark verinin nerede durduğudur.

Bir masaüstü uygulaması, çevrimdışı bir araç veya daha küçük bir derlem için, TsgcAIDatabaseVectorFile her şeyi harici bir hizmet olmadan yerel bir dosyada tutar. Dizin büyük olduğunda, süreçler veya kullanıcılar arasında paylaşılması gerektiğinde ya da tek bir makinenin ötesine ölçeklenmesi gerektiğinde, her parçayı yönetilen Pinecone REST API'si aracılığıyla yükleyip güncelleyen (upsert) TsgcAIDatabaseVectorPinecone'a geçin:

var
  DBPinecone: TsgcAIDatabaseVectorPinecone;
begin
  DBPinecone := TsgcAIDatabaseVectorPinecone.Create(nil);
  DBPinecone.PineconeOptions.ApiKey         := 'pc-...';
  DBPinecone.PineconeIndexOptions.IndexName := 'sgc-embeddings';

  Embeddings.Database := DBPinecone;
  Embeddings.CreateEmbeddingsFromFile('docs.txt');
end;

Alma satırının Adım 1 ile aynı olduğuna dikkat edin. Paylaşılan temel sınıfın bütün amacı budur. Dosya arka ucu için Vektör Veritabanları sayfasına ve bulut için Pinecone sayfasına bakın.

Adım 3 — getirin ve yanıt verin

Şimdi soru başına yol. Kullanıcının sorusunu gömün ve en yakın saklanmış parçaları tek bir çağrıyla bulun: GetEmbedding metni gömer ve veritabanının QueryData işlevinden geçirerek derleminizdeki en alakalı pasajları döndürür. Bu pasajlar sizin bağlamınızdır. Bunları soruyla birleştirin ve tümünü sohbet modeline gönderin:

var
  Question, Context, Prompt, Answer: string;
  OpenAI: TsgcHTTP_API_OpenAI;
begin
  Question := 'How do I enable the WatchDog reconnect?';

  // retrieve the closest chunks from your own data
  Context := Embeddings.GetEmbedding(Question, '');

  // build a grounded prompt
  Prompt :=
    'Answer the question using only the context below.' + sLineBreak +
    'If the context does not contain the answer, say you do not know.' +
    sLineBreak + sLineBreak +
    'Context:' + sLineBreak + Context + sLineBreak + sLineBreak +
    'Question: ' + Question;

  // ask the model
  OpenAI := TsgcHTTP_API_OpenAI.Create(nil);
  OpenAI.OpenAIOptions.ApiKey := 'sk-...';
  Answer := OpenAI._CreateChatCompletion('gpt-4o-mini', Prompt);

  Memo1.Lines.Text := Answer;
end;

İşte RAG budur. Model belgelerinizi eğitim sırasında hiç görmedi, yine de onlardan yanıt verir, çünkü istek anında alakalı pasajları onun önüne koydunuz. Derlemi değiştirin, yanıtlar da onunla birlikte değişir, hiçbir ince ayar gerekmez. Bağlam boş olduğunda reddetme talimatı, modeli tahmin yürütmek yerine dürüst tutan şeydir.

Yerel ya da bulut, aynı kod

Tekrarlamaya değer bir ayrıntı: dosya deposu ile Pinecone arasındaki seçim geri alınabilirdir. TsgcAIDatabaseVectorFile ve TsgcAIDatabaseVectorPinecone aynı TsgcAIDatabaseVector temelini paylaştığı için, yerel dosyaya karşı prototip oluşturabilir (sıfır altyapı, çevrimdışı çalışır) ve daha sonra Embeddings.Database'e atadığınız bileşeni değiştirerek Pinecone'a geçebilirsiniz. Alma veya sorgu kodunuzda hiçbir şey değişmez. Sondaki LLM için de aynısı geçerlidir: TsgcHTTP_API_OpenAI üzerindeki _CreateChatCompletion, nihai yanıtı yazmak için farklı bir model tercih ederseniz Anthropic veya Gemini bileşeniyle değiştirilebilir.

Parçalama ve kalite üzerine bir not

Getirme kalitesi, belgelerinizin nasıl bölündüğüne bağlıdır. Daha küçük parçalar eşleşmeleri daha kesin yapar ama bağlamı yitirebilir; daha büyük parçalar bağlamı korur ama eşleşmeyi seyreltir. EmbeddingsOptions.ChunkSize bunu CreateEmbeddingsFromFile için denetler, bu nedenle malzemenize göre ayarlamaya değer. Daha ince denetim için, CreateEmbeddings ile tek tek dizgeleri gömebilir ve almadan önce parçaları kendiniz şekillendirebilirsiniz.

Başlarken

Üç bileşenin tamamı sgcWebSockets ile gelir. Ücretsiz denemeyi edinin, gömme ve vektör deposu bileşenlerini bir forma bırakın, bunları bir metin dosyasına yönlendirin ve yüz satırın çok altında çalışan bir RAG döngünüz olacak. AI & LLM bileşenleri merkezinde AI yapı taşlarının tam setine göz atın.

Bunu kendi derleminize uygulama hakkında sorularınız mı var? İletişime geçin — kodu yazan kişilerden yanıt alacaksınız.

İlgili