Hazem Mohammed

Next.js 16Supabase pgvectorOpenAI EmbeddingsVercel AI SDKRetrieval-Augmented GenerationRAGServer ActionsVector Search

بناء تطبيقات الذكاء الاصطناعي التوليدي المعزز بالاسترجاع (RAG) باستخدام Next.js 16 و Supabase Vector و OpenAI

Hazem Mohammed
١٨ فبراير ٢٠٢٦
بناء تطبيقات الذكاء الاصطناعي التوليدي المعزز بالاسترجاع (RAG) باستخدام Next.js 16 و Supabase Vector و OpenAI

المقدمة

أحدثت تطبيقات الذكاء الاصطناعي التي تستخدم تقنية التوليد المعزز بالاسترجاع (RAG) ثورة في كيفية تفاعلنا مع المعلومات. بدلاً من الاعتماد فقط على المعرفة المدمجة في النموذج اللغوي الكبير (LLM)، تقوم تطبيقات RAG أولاً باسترداد المستندات أو البيانات ذات الصلة من قاعدة بيانات متخصصة ثم تستخدم هذه البيانات كـ "سياق" لتوليد إجابات أكثر دقة وملاءمة. في هذا الدليل التقني، سنتعمق في بناء تطبيق دردشة ذكي باستخدام أحدث التقنيات: Next.js 16 مع Server Actions، و Supabase مع امتداد pgvector لقاعدة البيانات المتجهة، و OpenAI لتوليد التضمينات (Embeddings) والإجابات، و Vercel AI SDK لتجربة بث سلسة.

ما هو RAG ولماذا هذا المزيج التقني؟

الـ Retrieval-Augmented Generation (RAG) هو نموذج يسمح للنماذج اللغوية الكبيرة بالوصول إلى بيانات خارجية وديناميكية. تعمل العملية على النحو التالي:

  1. التضمين (Embedding): يتم تحويل مستنداتك (نصوص، مقالات، إلخ) إلى تمثيلات رقمية تسمى "تضمينات متجهة" باستخدام نموذج تضمين مثل text-embedding-3-small من OpenAI.
  2. التخزين (Storage): يتم تخزين هذه المتجهات في قاعدة بيانات متجهة، وهنا يأتي دور Supabase مع pgvector.
  3. الاسترجاع (Retrieval): عندما يطرح المستخدم سؤالاً، يتم تحويله أيضاً إلى متجه. ثم يتم إجراء بحث تشابهي (similarity search) في قاعدة البيانات للعثور على المستندات الأكثر صلة بالسؤال.
  4. التوليد (Generation): يتم إرسال السؤال الأصلي والمستندات المسترجعة (السياق) إلى نموذج لغوي كبير مثل GPT-4، والذي يستخدم هذا السياق الإضافي لإنشاء إجابة دقيقة ومستنيرة.

لماذا هذا المزيج؟

  • Next.js 16 Server Actions: تتيح لنا تنفيذ منطق الخادم الآمن مباشرة من مكونات العميل، مما يبسط بنية الكود ويجعل التفاعل مع قاعدة البيانات وواجهات برمجة التطبيقات الخارجية سلساً.
  • Supabase & pgvector: يوفر Supabase قاعدة بيانات PostgreSQL قوية وقابلة للتطوير مع دعم أصلي للمتجهات عبر امتداد pgvector. هذا يجعل تخزين واستعلام المتجهات فعالاً للغاية.
  • OpenAI: توفر نماذج رائدة لتوليد تضمينات عالية الجودة وإكمال المحادثات.
  • Vercel AI SDK: تبسط التعامل مع استجابات الذكاء الاصطناعي المتدفقة (streaming responses) على الواجهة الأمامية، مما يحسن تجربة المستخدم بشكل كبير.

التنفيذ: دليل خطوة بخطوة

الخطوة 1: إعداد قاعدة بيانات Supabase

أولاً، قم بتمكين امتداد pgvector في مشروع Supabase الخاص بك. بعد ذلك، قم بتشغيل استعلام SQL التالي لإنشاء جدول لتخزين المستندات وتضميناتها، بالإضافة إلى دالة للبحث التشابهي.

-- Enable the pgvector extension
create extension if not exists vector with schema extensions;

-- Create the documents table
create table documents (
  id bigserial primary key,
  content text,
  embedding vector(1536) -- Matches OpenAI's text-embedding-3-small dimension
);

-- Create a function to search for similar documents
create or replace function match_documents (
  query_embedding vector(1536),
  match_threshold float,
  match_count int
)
returns table (
  id bigint,
  content text,
  similarity float
)
language plpgsql
as $$
#variable_conflict use_variable
begin
  return query
  select
    documents.id,
    documents.content,
    1 - (documents.embedding <=> query_embedding) as similarity
  from documents
  where 1 - (documents.embedding <=> query_embedding) > match_threshold
  order by documents.embedding <=> query_embedding
  limit match_count;
end;
$$

الخطوة 2: توليد وتخزين التضمينات (Seeding)

سنقوم بإنشاء سكربت أو Server Action لمرة واحدة لقراءة بياناتك، وتوليد تضمينات لها باستخدام OpenAI، وتخزينها في Supabase. افترض أن لديك ملف data.ts يحتوي على مصفوفة من المحتوى.

// lib/seed.ts
import { createClient } from '@supabase/supabase-js';
import OpenAI from 'openai';
import { documentsToSeed } from './data'; // Your data source

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);

async function generateAndStoreEmbeddings() {
  for (const doc of documentsToSeed) {
    const embeddingResponse = await openai.embeddings.create({
      model: 'text-embedding-3-small',
      input: doc.content,
    });

    const [{ embedding }] = embeddingResponse.data;

    const { error } = await supabase.from('documents').insert({
      content: doc.content,
      embedding: embedding,
    });

    if (error) {
      console.error('Error inserting document:', error);
    } else {
      console.log(`Stored embedding for: ${doc.content.substring(0, 20)}...`);
    }
  }
}

// Run the function
generateAndStoreEmbeddings();

الخطوة 3: إنشاء Server Action لـ RAG

هذا هو جوهر التطبيق. سيقوم هذا الـ Server Action باستلام رسالة المستخدم، وإنشاء تضمين لها، والبحث عن السياق ذي الصلة في Supabase، ثم بث الإجابة النهائية من OpenAI.

// app/actions.ts
'use server';

import { createStreamableValue } from 'ai/rsc';
import { CoreMessage, streamText } from 'ai';
import OpenAI from 'openai';
import { createClient } from '@supabase/supabase-js';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);

export async function getAnswer(history: CoreMessage[]) {
  const stream = createStreamableValue();
  const lastUserMessage = history[history.length - 1].content as string;

  (async () => {
    // 1. Generate embedding for the user's question
    const embeddingResponse = await openai.embeddings.create({
      model: 'text-embedding-3-small',
      input: lastUserMessage,
    });
    const [{ embedding }] = embeddingResponse.data;

    // 2. Query Supabase for similar documents
    const { data: documents, error } = await supabase.rpc('match_documents', {
      query_embedding: embedding,
      match_threshold: 0.7,
      match_count: 5,
    });

    if (error) {
      console.error('Error matching documents:', error);
      // Handle error appropriately
      return;
    }

    const context = documents.map((doc: any) => doc.content).join('\n---\n');

    // 3. Augment the prompt and stream the response from OpenAI
    const prompt = `You are a helpful AI assistant. Use the following context to answer the user's question. If the answer is not in the context, say you don't know.\n\nContext:\n${context}\n\nQuestion: ${lastUserMessage}`;

    const result = await streamText({
      model: 'gpt-4o',
      messages: [{ role: 'user', content: prompt }],
    });

    for await (const delta of result.textStream) {
      stream.update(delta);
    }

    stream.done();
  })();

  return { object: stream.value };
}

الخطوة 4: بناء واجهة المستخدم مع useChat

أخيراً، نقوم بإنشاء مكون العميل الذي يستخدم useChat من Vercel AI SDK لإدارة حالة الدردشة واستدعاء الـ Server Action.

// app/page.tsx
'use client';

import { useChat } from 'ai/react';
import { getAnswer } from './actions';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: getAnswer // Point useChat to our Server Action
  });

  return (
    <div className="flex flex-col w-full max-w-md mx-auto stretch">
      <div className="flex-grow overflow-auto mb-4">
        {messages.map(m => (
          <div key={m.id} className="whitespace-pre-wrap">
            <strong>{m.role === 'user' ? 'User: ' : 'AI: '}</strong>
            {m.content}
          </div>
        ))}
      </div>

      <form onSubmit={handleSubmit}>
        <input
          className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
          value={input}
          placeholder="Ask something..."
          onChange={handleInputChange}
        />
      </form>
    </div>
  );
}

حالات الاستخدام في العالم الحقيقي

هذا النمط المعماري قوي للغاية ومناسب لمجموعة واسعة من التطبيقات:

  • "اسأل مستنداتك": اسمح للمستخدمين بالدردشة مع ملفات PDF، أو قواعد المعرفة، أو المستندات الداخلية.
  • روبوتات دعم العملاء: قم بتدريب الروبوت على وثائق المنتج والأسئلة الشائعة لتقديم إجابات فورية ودقيقة.
  • أدوات البحث الذكية: قم ببناء محركات بحث دلالية تفهم القصد من وراء الاستعلام بدلاً من مجرد مطابقة الكلمات الرئيسية.

الخاتمة

لقد أصبحت عملية بناء تطبيقات RAG المعقدة أسهل من أي وقت مضى بفضل التطورات في Next.js 16، وقوة Supabase pgvector، ونماذج OpenAI المتقدمة، وسهولة استخدام Vercel AI SDK. من خلال الجمع بين هذه التقنيات، يمكنك إنشاء تطبيقات ذكاء اصطناعي قوية ومستجيبة وقادرة على تقديم معلومات دقيقة وذات صلة بالسياق، مما يفتح الباب أمام جيل جديد من المنتجات والخدمات الذكية.

HM

Hazem Mohammed

مطور ويب متخصص في هندسة تطبيقات حديثة، سريعة، وقابلة للتوسع.