Alma ile artırılmış oluşturma (RAG)

Firebase Genkit, almayla geliştirilmiş nesil oluşturmanıza yardımcı olan soyutlamalar sunar (RAG) akışlarının yanı sıra ilgili araçlarla entegrasyon sağlayan eklentiler de sunar.

RAG nedir?

Alma ile artırılmış oluşturma, harici veya bağlantılı verileri toplamak için kullanılan bir bilgi kaynaklarını LLM'nin yanıtlarına dönüştürme. Proje hedeflerinizin Çünkü LLM'ler genellikle birçok farklı alanda eğitilirken LLM'lerin pratik kullanımı için genellikle belirli alan bilgisi (ör. Örneğin, müşterilerin deneyimlerine yanıt vermek için şu konularla ilgili sorular: .

Çözümlerden biri, daha ayrıntılı veriler kullanarak modelde ince ayar yapmaktır. Ancak bu hem işlem maliyeti hem de gereken çaba açısından pahalı olabilir. ve yeterli eğitim verisi hazırlamak için bu belgeyi kullanın.

Buna karşılık RAG, harici veri kaynaklarını aktarılma süresini gösterir. Mesela Arkadaş Bitkiler projesinin "What is Bart to Lisa?" (Bart'ın Leyla ile ilişkisi nedir?) genişletilebilir ("genişletilmiş") olabilir alakalı bilgiler bulunuyor ve "Homer ve Marge'ın çocuklarının adı Bart, Leyla ve Maggie. Bart'ın ilişkisi nedir? Leyla'ya mı göndermek istiyorsun?"

Bu yaklaşımın çeşitli avantajları vardır:

  • Modeli yeniden eğitmeniz gerekmeyeceğinden bu yöntem daha uygun maliyetli olabilir.
  • Veri kaynağınızı sürekli olarak güncelleyebilirsiniz. Böylece LLM hemen bilgileri nasıl kullanacağınızı öğreneceksiniz.
  • Artık LLM'nizin yanıtlarında referanslara atıfta bulunabilirsiniz.

Diğer yandan, RAG kullanımı doğal olarak daha uzun istemler ve bazı LLM API'leri anlamına gelir. hizmetleri, gönderdiğiniz her giriş jetonu için ücret alır. Sonuç olarak, satın alma süreci dengesini sağlayabilirsiniz.

RAG çok geniş bir alandır ve bunu başarmak için kullanılan birçok farklı RAG kalitesini artırırsınız. Temel Genkit çerçevesi, aşağıdakileri yapmak için iki ana soyutlama sunar: size yardımcı olacak:

  • Dizine ekleyenler: Bir "dizine" doküman ekleyin.
  • Katıştırıcılar: Dokümanları vektörel temsile dönüştürür
  • Toplayıcılar: Belirli bir sorguda "dizinden" doküman alma.

Genkit hakkında herhangi bir fikriniz olmadığı için bu tanımlar kasıtlı olarak geniş kapsamlıdır. "dizin" nedir nasıl alındığı veya tam olarak nasıl alındığı. Yalnızca Genkit bir Document biçimi sağlar ve diğer her şey, alıcı veya dizine ekleme aracı uygulama sağlayıcısıdır.

Dizine ekleyenler

Dizin, dokümanlarınızın kaydını tutmaktan sorumlu olur. Belirli bir sorgu verildiğinde ilgili dokümanları hızla alabilirsiniz. Bu, en çok genellikle belgelerinizi dizine eklemek için kullanılan bir vektör veritabanı çok boyutlu vektörlere yerleştiriyoruz. Metin yerleştirme (opak olarak) bir metin parçasıyla ifade edilen kavramları temsil eder. Bunlar üretilir makine öğrenimi modellerini kullanır. Yerleştirme kullanılarak metin dizine eklendiğinde, bir vektör veritabanı, kavramsal olarak ilişkili metinleri kümeleyip dokümanlar yeni bir metin dizesiyle (sorgu) ilişkilidir.

Belgeleri oluşturma amacıyla alabilmek için önce doküman dizininize alabilirsiniz. Tipik bir besleme akışı takip etmek için:

  1. Büyük dokümanları daha küçük dokümanlara bölün, böylece yalnızca alakalı dokümanlar bazı bölümler, istemlerinizi genişletmek için kullanılır ("parçalama"). Bu gerekli çünkü birçok LLM'nin sınırlı bir bağlam penceresi olduğundan bu dili bir istemle tüm dokümanları dahil edebilirsiniz.

    Genkit, yerleşik öbekleme kitaplıkları sağlamaz; ancak her halükarda Genkit ile uyumlu kaynak kitaplıklar var.

  2. Her parça için yerleştirmeler oluşturun. Kullandığınız veritabanına bağlı olarak bunu bir yerleştirme oluşturma modeliyle açıkça yapabilir veya veritabanı tarafından sağlanan yerleştirme oluşturucuyu kullanabilir.

  3. Metin parçasını ve dizinini veritabanına ekleyin.

Çalışıyorsanız besleme akışınızı nadiren veya yalnızca bir kez çalıştırabilirsiniz. istikrarlı bir veri kaynağına sahip olmalıdır. Öte yandan verilere dayalı sürekli değişen bir şey varsa besleme akışını ( (ör. Cloud Firestore tetikleyicisinde) bir belge güncellendiğinde.

Yerleştirme

Yerleştirme, içeriği (metin, görsel, ses vb.) alıp orijinal içeriğin anlamsal anlamını kodlayan sayısal bir vektör oluşturan bir işlevdir. Yukarıda belirtildiği gibi yerleştiriciler, dizine ekleme sürecinin bir parçası olarak kullanılır. Bununla birlikte, dizin içermeyen yerleştirmeler oluşturmak için bağımsız olarak da kullanılabilirler.

Toplayıcılar

Retriever, herhangi bir belgenin türüne ilişkin mantığı içeren bir kavramdır. içerir. En popüler alma durumları genellikle vektör depoları gibi Genkit'te bir retriever veri döndüren herhangi bir fonksiyon olabilir.

Bir retriever oluşturmak için, sağlanan uygulamalardan birini veya kendinizinkini oluşturun.

Desteklenen dizinleyiciler, alıcılar ve yerleştiriciler

Genkit, eklenti sistemi üzerinden dizinleyici ve retriever desteği sağlar. İlgili içeriği oluşturmak için kullanılan şu eklentiler resmi olarak desteklenmektedir:

Ayrıca Genkit, önceden tanımlanmış fonksiyonlar aracılığıyla aşağıdaki vektör depolarını da destekler. kod şablonlarını kullanarak veritabanı yapılandırmanız ve şema:

Model yerleştirme desteği aşağıdaki eklentiler aracılığıyla sağlanır:

Eklenti Modeller
Google Üretken Yapay Zeka Gecko metni yerleştirme
Google Vertex Yapay Zeka Gecko metni yerleştirme

RAG Akışı Tanımlama

Aşağıdaki örneklerde, restoran menüsüyle ilgili PDF dokümanları koleksiyonunu nasıl aktarabileceğiniz gösterilmektedir bunları bir vektör veritabanına aktarma ve hangi gıda öğelerinin mevcut olduğunu belirleyen bir akışta kullanmak üzere alma.

PDF'leri işlemek için bağımlılıkları yükleme

npm install llm-chunk pdf-parse
npm i -D --save @types/pdf-parse

Yapılandırmanıza yerel vektör deposu ekleme

import {
  devLocalIndexerRef,
  devLocalVectorstore,
} from '@genkit-ai/dev-local-vectorstore';
import { textEmbeddingGecko, vertexAI } from '@genkit-ai/vertexai';

configureGenkit({
  plugins: [
    // vertexAI provides the textEmbeddingGecko embedder
    vertexAI(),

    // the local vector store requires an embedder to translate from text to vector
    devLocalVectorstore([
      {
        indexName: 'menuQA',
        embedder: textEmbeddingGecko,
      },
    ]),
  ],
});

Dizine Ekleleyici Tanımlama

Aşağıdaki örnekte, PDF dokümanları koleksiyonunu aktarmak için dizinleyicinin nasıl oluşturulacağı gösterilmektedir yerel bir vektör veritabanında saklamanız gerekir.

Yerel dosya tabanlı Vektör benzerliği alicisini kullanır. Genkit'in, basit test ve prototip oluşturma için kullanıma hazır sunduğu verilere sahip olursunuz ( üretimde kullanılması)

Dizine ekleyici oluşturma

import { devLocalIndexerRef } from '@genkit-ai/dev-local-vectorstore';

export const menuPdfIndexer = devLocalIndexerRef('menuQA');

Parçalama yapılandırması oluşturma

Bu örnekte, dokümanları vektörleştirilebilen segmentlere ayırmak için basit bir metin ayırıcı sağlayan llm-chunk kitaplığı kullanılmaktadır.

Aşağıdaki tanım, 1000 ile 2000 karakter uzunluğunda, bir cümlenin sonuna bölünerek 100 karakterlik parçalar arasında çakışma olacak şekilde parçalama işlevini yapılandırır.

const chunkingConfig = {
  minLength: 1000,
  maxLength: 2000,
  splitter: 'sentence',
  overlap: 100,
  delimiters: '',
} as any;

Bu kitaplıkla ilgili daha fazla parçalama seçeneğini llm-chunk belgelerinde bulabilirsiniz.

Dizine ekleme akışınızı tanımlayın

import { index } from '@genkit-ai/ai';
import { Document } from '@genkit-ai/ai/retriever';
import { defineFlow, run } from '@genkit-ai/flow';
import { readFile } from 'fs/promises';
import { chunk } from 'llm-chunk';
import path from 'path';
import pdf from 'pdf-parse';
import * as z from 'zod';

export const indexMenu = defineFlow(
  {
    name: 'indexMenu',
    inputSchema: z.string().describe('PDF file path'),
    outputSchema: z.void(),
  },
  async (filePath: string) => {
    filePath = path.resolve(filePath);

    // Read the pdf.
    const pdfTxt = await run('extract-text', () =>
      extractTextFromPdf(filePath)
    );

    // Divide the pdf text into segments.
    const chunks = await run('chunk-it', async () =>
      chunk(pdfTxt, chunkingConfig)
    );

    // Convert chunks of text into documents to store in the index.
    const documents = chunks.map((text) => {
      return Document.fromText(text, { filePath });
    });

    // Add documents to the index.
    await index({
      indexer: menuPdfIndexer,
      documents,
    });
  }
);

async function extractTextFromPdf(filePath: string) {
  const pdfFile = path.resolve(filePath);
  const dataBuffer = await readFile(pdfFile);
  const data = await pdf(dataBuffer);
  return data.text;
}

Dizine ekleme akışını çalıştırma

genkit flow:run indexMenu "'../pdfs'"

indexMenu akışı çalıştırıldıktan sonra, vektör veritabanı belgelerle başlangıç noktası olarak ayarlanır ve alma adımlarıyla Genkit akışlarında kullanıma hazır hale gelir.

Alma ile bir akış tanımlama

Aşağıdaki örnek, RAG akışında bir retriever'ı nasıl kullanabileceğinizi gösterir. Beğenme örneğin, bu örnekte Genkit'in dosya tabanlı vector retriever'ını kullanır. ve üretimde kullanmamanız gerekir.

import { generate } from '@genkit-ai/ai';
import { retrieve } from '@genkit-ai/ai/retriever';
import { devLocalRetrieverRef } from '@genkit-ai/dev-local-vectorstore';
import { defineFlow } from '@genkit-ai/flow';
import { geminiPro } from '@genkit-ai/vertexai';
import * as z from 'zod';

// Define the retriever reference
export const menuRetriever = devLocalRetrieverRef('menuQA');

export const menuQAFlow = defineFlow(
  { name: 'menuQA', inputSchema: z.string(), outputSchema: z.string() },
  async (input: string) => {
    // retrieve relevant documents
    const docs = await retrieve({
      retriever: menuRetriever,
      query: input,
      options: { k: 3 },
    });

    // generate a response
    const llmResponse = await generate({
      model: geminiPro,
      prompt: `
    You are acting as a helpful AI assistant that can answer 
    questions about the food available on the menu at Genkit Grub Pub.
    
    Use only the context provided to answer the question.
    If you don't know, do not make up an answer.
    Do not add or change items on the menu.

    Question: ${input}
    `,
      context: docs,
    });

    const output = llmResponse.text();
    return output;
  }
);

Kendi dizinleyici ve alıcılarınızı yazma

Kendi retriever'ınızı da oluşturabilirsiniz. Bu, Dokümanlar, Genkit'te desteklenmeyen bir doküman deposunda yönetiliyor (ör. MySQL, Google Drive vb.). Genkit SDK'sı esnek yöntemler sunar. Dokümanları almak için özel kod sağlarsınız. Ayrıca özelleştirilebilir gelişmiş Alıcı'ların yerine daha geniş bir kitleye ulaşıp RAG tekniklerini (yeniden sıralama veya istem uzantısı gibi) incelemelisiniz.

Basit Toplayıcılar

Basit retriever'lar, mevcut kodu retriever'lara kolayca dönüştürmenizi sağlar:

import {
  defineSimpleRetriever,
  retrieve
} from '@genkit-ai/ai/retriever';
import { searchEmails } from './db';
import { z } from 'zod';

defineSimpleRetriever({
  name: 'myDatabase',
  configSchema: z.object({
    limit: z.number().optional()
  }).optional(),
  // we'll extract "message" from the returned email item
  content: 'message',
  // and several keys to use as metadata
  metadata: ['from', 'to', 'subject'],
} async (query, config) => {
  const result = await searchEmails(query.text(), {limit: config.limit});
  return result.data.emails;
});

Özel Toplayıcılar

import {
  CommonRetrieverOptionsSchema,
  defineRetriever,
  retrieve,
} from '@genkit-ai/ai/retriever';
import * as z from 'zod';

export const menuRetriever = devLocalRetrieverRef('menuQA');

const advancedMenuRetrieverOptionsSchema = CommonRetrieverOptionsSchema.extend({
  preRerankK: z.number().max(1000),
});

const advancedMenuRetriever = defineRetriever(
  {
    name: `custom/advancedMenuRetriever`,
    configSchema: advancedMenuRetrieverOptionsSchema,
  },
  async (input, options) => {
    const extendedPrompt = await extendPrompt(input);
    const docs = await retrieve({
      retriever: menuRetriever,
      query: extendedPrompt,
      options: { k: options.preRerankK || 10 },
    });
    const rerankedDocs = await rerank(docs);
    return rerankedDocs.slice(0, options.k || 3);
  }
);

(extendPrompt ve rerank, sizin uygulamanız gereken özelliklerdir, çerçeve tarafından sağlanmaz)

Şimdi de retriever'ınızı değiştirebilirsiniz:

const docs = await retrieve({
  retriever: advancedRetriever,
  query: input,
  options: { preRerankK: 7, k: 3 },
});