PRODمنصة BaaS الأوروبية السياديةافتح لوحة المعلومات →

الذكاء الاصطناعي الأصلي · 10 دقيقة للقراءة

وكيل Postgres آمن مع استدعاء الوظائف (البرنامج التعليمي)

Affane Daylami · Fondateur · 21 مارس 2026

العودة إلى بلوق

يسأل الوكيل الذي يستعلم عن Postgres سؤال أمان محددًا قبل السطر الأول من الكود: ما هي الوظيفة التي تعرضها للنموذج؟ إذا كانت الأداة التي يمكن لـ LLM الاتصال بها مباشرة تنفذ SQL التي كتبتها بنفسها، فإن السؤال الغامض أو الحقن الفوري يكفي لقراءة أي جدول في المشروع.

تم إنشاء هذا النص الإنجليزي تلقائيًا من النص الأصلي الفرنسي ولم تتم مراجعته بعد.
تمت ترجمة هذه الصفحة تلقائيًا. النسخة الإنجليزية موثوقة.

يقوم هذا البرنامج التعليمي بإنشاء وكيل مع استدعاء الوظائف حيث لا تقوم الأداة المعرضة للنموذج أبدًا بتنفيذ SQL عشوائي. فهو يجمع بين آليتين تم التحقق منهما بالفعل في كود Aurabase: مدقق NL2SQL ومعاملة Postgres للقراءة فقط، وهما قالبان من الذكاء الاصطناعي الأصليمدمجان في الواجهة الخلفية. المتطلبات الأساسية: مشروع Aurabase، ومفتاح service_roleالخاص به، وحساب مع أحد موفري LLM الأصليين الثلاثة (OpenAI، وAnthropic، وGemini).

الأساسيات

  • الخطر الحقيقي ليس استدعاء الوظيفة نفسها، ولكن الأداة المكشوفة للنموذج: execute_sql(query) الخام يمنحها وصولاً كاملاً إلى SQL.
  • تعرض البنية الآمنة أداة query_database(question) التي تفوض إلى مدقق شجرة بناء الجملة (SELECT فقط، LIMIT محدود، مخطط معزول) بدلاً من التنفيذ المباشر.
  • يعرض Aurabase أداة التحقق هذه محليًا (/nl2sql): يؤدي إعادة استخدامها كتطبيق للأداة إلى تجنب الاضطرار إلى إعادة ترميز التحقق من صحة SQL بنفسك.
  • يتم بعد ذلك تنفيذ SQL الملتزم من خلال aura.db.sql() في وضع readOnly: true، وهي معاملة Postgres فعلية للقراءة فقط، وليست مرشحًا نصيًا بسيطًا.
  • لا تقبل نقطة نهاية /chat الأصلية لـ Aurabase بعد دورًا tool ولا معلمة tools (تم التحقق منها في الكود): يتم تشغيل حلقة الوكيل حاليًا عبر SDK الخاص بموفر LLM، وليس عبر وكيل Aurabase.
  • يتجاوز المفتاح service_role RLS حسب التصميم: يجب ألا يغادر الواجهة الخلفية لديك أبدًا، ويرث الوكيل وصولاً أوسع من المستخدم المعتمد النموذجي.
#
الهدف

ماذا ستبني

ستقوم بإنشاء وكيل يجيب على أسئلة اللغة الطبيعية المتعلقة بالبيانات في مشروع Postgres، دون السماح للنموذج بكتابة SQL الذي يتم تنفيذه كما هو. يستدعي النموذج أداة اسمها query_database، تقوم هذه الأداة بترجمة السؤال إلى SQL تم التحقق من صحته عبر NL2SQL، ثم تنفذ SQL للقراءة فقط وتعيد الأسطر إلى النموذج بحيث يقوم بصياغة إجابته.

معلومات

يستخدم هذا البرنامج التعليمي @aurabase/aurabase-js JavaScript SDK على جانب الخادم (ليس من جانب المتصفح أبدًا، يجب ألا يتم عرض المفتاح service_role للعميل) ووظيفة OpenAI التي تستدعي واجهة برمجة التطبيقات لحلقة الوكيل. ينطبق نفس المبدأ على Anthropic أو Gemini SDK.

#
تحت غطاء محرك السيارة

لماذا تعتبر أداة "تشغيل SQL هذه" خطيرة

تحدد معظم البرامج التعليمية لوكلاء Postgres، بما في ذلك بعض الأدلة الرسمية، أداة واحدة: دالة execute_sql التي تأخذ سلسلة SQL كوسيطة وتنفذها كما هي. يكتب النموذج هذه السلسلة بنفسه، بناءً على سؤال المستخدم والمخطط المعطى له في السياق.

tool-schema-dangereux.json (مكافحة النمط)json
{
  "name": "execute_sql",
  "parameters": {
    "query": { "type": "string" }  // النموذج يكتب SQL مباشرة
  }
}

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

يكشف البديل المضمن في هذا البرنامج التعليمي عن أداة أضيق، query_database(question). لم يعد النموذج قادرًا على كتابة SQL مباشرة: يمكنه فقط طرح سؤال في استدعاء الأداة الخاص به. إنه محرك Aurabase NL2SQL الذي يترجم هذا السؤال إلى SQL، قبل تمريره عبر أداة التحقق من صحة الشجرة النحوية (حدد وحده، لا توجد استعلامات فرعية، عشر وظائف معتمدة، LIMIT محدود).

موجه النظام ليس فحصًا أمنيًا

تمنح أداة execute_sql(query: string) النموذج وصولاً كاملاً إلى SQL، بغض النظر عن مدى جودة مطالبة النظام لديك. تظل التعليمات ("تنفيذ التحديدات فقط") بمثابة تعليمات يمكن للنموذج اتباعها أو إساءة تفسيرها أو رؤيتها يتم التحايل عليها عن طريق حقنة تم إدخالها في سؤال المستخدم.

#
الخطوة 1

تحديد مخطط الأداة المكشوفة للنموذج

يقبل مقدمو خدمات LLM الثلاثة الأصليون في Aurabase (OpenAI وAnthropic وGemini) جدول تعريفات الأدوات بتنسيق مخطط JSON. أداة واحدة تكفي لهذا الوكيل: query_database، والتي تجيب على السؤال باللغة الطبيعية ولا شيء غير ذلك. لا يرى النموذج مخطط SQL ولا حقل query الذي يمكنه ملؤه بنفسه.

lib/agent-tools.tstypescript
export const tools = [
  {
    type: 'function',
    function: {
      name: 'query_database',
      description:
        "Interroge les données du projet en langage naturel. N'accepte pas de SQL : posez une question.",
      parameters: {
        type: 'object',
        properties: {
          question: {
            type: 'string',
            description: 'Question en français sur les données du projet.'
          },
        },
        required: ['question'],
        additionalProperties: false
      },
    },
  },
]
#
الخطوة 2

قم بتنفيذ الأداة: NL2SQL ثم للقراءة فقط

يعمل معالج الأداة على الواجهة الخلفية لديك، وليس في المتصفح أبدًا. إنه يحمل مفتاح المشروع service_role، الذي يتجاوز RLS حسب التصميم وبالتالي لا ينبغي أبدًا كشفه للعميل. يقوم بإجراء مكالمتين إلى Aurabase SDK.

الاستدعاء الأول يترجم السؤال إلى SQL تم التحقق من صحته عبر aura.ai.nl2sql(): SELECT فقط، LIMIT محدود، لا يمكن الوصول إلى كتالوج النظام. الثاني ينفذ SQL هذا الذي تم التحقق من صحته بالفعل عبر aura.db.sql()، مع خيار readOnly: true: ثم يرفض Postgres نفسه أي كتابة في هذه المعاملة، بشكل مستقل عن التحقق النصي المطبق بالفعل بواسطة NL2SQL المنبع.

server/tools/query-database.tstypescript
// تتم تهيئة العميل باستخدام مفتاح Service_role، وليس من جانب المتصفح أبدًا
import { aura } from '@/lib/aurabase'

export async function queryDatabase(question: string) {
  const { data: validated, error } = await aura.ai.nl2sql(
    question,
    undefined,
    { limit: 50 },
  )
  if (error) return { error: error.message }

  const { data: rows, error: execError } = await aura.db.sql(
    validated.sql,
    [],
    { readOnly: true },
  )
  if (execError) return { error: execError.message }

  return { sql: validated.sql, rows }
}
أسوس

readOnly: true يطلق معاملة Postgres حقيقية للقراءة فقط: يرفض المحرك الكتابة، ولا يتم تطبيق مرشح على نص الطلب. بالاشتراك مع التحقق من صحة التحديد فقط في NL2SQL، يحتوي الوكيل على طبقتين مستقلتين: إذا كان في إحداهما عيب، فإن الأخرى لا تزال قائمة.

#
الخطوة 3

حلقة الوكيل: استدعاء الوظيفة على جانب SDK الخاص بالمورد

تعرض Aurabase ثلاثة موفري LLM أصليين، لكن نقطة النهاية /chat الخاصة بها لا تقوم بعد بترحيل معلمة tools أو دور tool. ChatOptions يحمل فقط temperatureو max_tokens و model، وتقتصر الأدوار المقبولة على systemو user و assistant (تم التحقق منها في llm/mod.rs و handlers/chat.rs). وبالتالي، يتم تشغيل حلقة استدعاء الوظائف اليوم مباشرةً عبر SDK الخاص بالموفر، وليس عبر وكيل Aurabase.

القيد الحالي، وليس خيارا نهائيا

طالما أن Aurabase لا يقوم بتنسيق استدعاءات الأدوات بشكل أصلي، فيجب أن تدير الواجهة الخلفية لديك الحلقة نفسها باستخدام OpenAI أو Anthropic أو Gemini SDK. يظل تنفيذ NL2SQL وSQL هو استدعاءات Aurabase الكلاسيكية داخل هذه الحلقة.

server/agent.tstypescript
import OpenAI from 'openai'
import { tools } from './lib/agent-tools'
import { queryDatabase } from './tools/query-database'

const openai = new OpenAI()

export async function askAgent(question: string) {
  const messages = [{ role: 'user', content: question }]

  const first = await openai.chat.completions.create({
    model: 'gpt-4.1', messages, tools,
  })

  const call = first.choices[0].message.tool_calls?.[0]
  if (!call) return first.choices[0].message.content

  const args = JSON.parse(call.function.arguments)
  const result = await queryDatabase(args.question)

  const second = await openai.chat.completions.create({
    model: 'gpt-4.1',
    messages: [
      ...messages,
      first.choices[0].message,
      { role: 'tool', tool_call_id: call.id, content: JSON.stringify(result) },
    ],
  })

  return second.choices[0].message.content
}

يظل المبدأ كما هو إذا قمت بتنسيق الوكيل مع LangChain أو خدمة مثل Azure AI Agent: يجب أن تظل الأداة المعلنة في إطار العمل كما هي query_database، وليس منفذ SQL أوليًا أبدًا. تفاصيل المقارنة الخاصة بنا حيث يوفر LangChain وLlamaIndex قيمة حقيقية على Postgres، وحيث يضيفان تعقيدًا بشكل خاص: وكلاء Postgres مع LangChain أو LlamaIndex.

#
الخطوة 4

اختبار مع سؤال حقيقي

تم إرسال السؤال إلى الوكيل: "كم عدد العملاء المميزين الذين قدموا طلبًا هذا الشهر؟" ". يستدعي القالب query_database مع هذا السؤال كما هو، دون رؤية أو كتابة أي SQL. إليك نتيجة الاستدعاءين الداخليين اللذين أطلقتهما الأداة.

نتيجة الأداة (استخراج)json
{
  "sql": "SELECT count(*) FROM orders WHERE customer_plan = 'premium' AND created_at >= date_trunc('month', now()) LIMIT 50",
  "rows": [{ "count": 128 }]
}

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

#
الأمن

تأمين الوكيل قبل الدخول في الإنتاج

  • لا يترك المفتاح service_role الواجهة الخلفية لديك أبدًا: لا في الموجه المرسل إلى النموذج، ولا في السجل، ولا في متغير البيئة من جانب العميل.
  • يظل readOnly: true نشطًا على aura.db.sql() لهذه الأداة المحددة، حتى إذا كان مشروعك يحتاج إلى الكتابة في مكان آخر في التطبيق.
  • service_role يتجاوز RLS حسب التصميم. إذا كان يجب على الوكيل الاستجابة بشكل مختلف اعتمادًا على المستخدم الذي يطرح السؤال، فقم بالتصفية بشكل صريح في SQL أو ارجع إلى نقاط نهاية PostgREST الكلاسيكية، التي تحترم RLS. راجع عزل RLS متعدد المستأجرين.
  • تسجيل كل استدعاء للأداة (السؤال المطروح، التحقق من صحة SQL، عدد الأسطر): هذا هو التتبع الوحيد القابل للاستخدام إذا أدى السؤال إلى نتيجة غير متوقعة.
  • يتم تطبيق حد معدل Aurabase والحصة الشهرية بالفعل لكل مشروع على /nl2sql: لا يمكن للوكيل الثرثار أن يتجاوز ميزانية الذكاء الاصطناعي الخاصة بك بصمت.
#
الصدق

الحدود الحالية التي يجب أن تكون على علم بها

ترث أداة query_database جميع قيود مدقق NL2SQL: لا توجد استعلامات فرعية، ولا CTE/WITH، ولا UNION، وقائمة مغلقة من عشر وظائف SQL. السؤال الذي يستدعي بشكل طبيعي استعلامًا فرعيًا ("العملاء الذين لم يطلبوا مطلقًا") يجب إعادة صياغته أو معالجته بواسطة أداة مخصصة ثانية بدلاً من فرضه على NL2SQL.

لا يوجد تنسيق لاستدعاءات الأدوات اليوم داخل وكيل Aurabase /chat: حلقة الوكيل الموضحة هنا موجودة في كود التطبيق الخاص بك، وليس في خدمة مُدارة. إذا كان يتعين على الوكيل ربط عدة أدوات (قاعدة بيانات ووثائق RAG، على سبيل المثال)، فإن الواجهة الخلفية لديك هي التي تنظم المكالمتين.

#
اذهب أبعد من ذلك

RAG واستدعاء الوظيفة مدمجان

يغطي هذا البرنامج التعليمي أسئلة منظمة حول البيانات العلائقية. بالنسبة للأسئلة حول المحتوى غير المنظم (المستندات، التذاكر، الملاحظات)، يمكن لنفس الوكيل الكشف عن أداة ثانية متصلة بـ RAG الأصلي لـ Aurabase (pgvector، بحث HNSW). تم تفصيل الإمكانيتين والتعبير عنهما على صفحة Native AI على Postgres.

#
الأسئلة المتداولة

الأسئلة الشائعة

هل يمكنني منح الوكيل حق الوصول للكتابة (إدراج/تحديث)؟+
من الناحية الفنية، نعم، عن طريق إزالة خيار القراءة فقط والإشارة إلى أداة منفصلة، ولكن هذا ليس ما يفعله NL2SQL اليوم: يسمح المدقق فقط باستعلامات SELECT، بغض النظر عن خيار التنفيذ المختار من جانب العميل. يطلب وكيل الكتابة مدققًا منفصلاً، مع القائمة البيضاء الخاصة به من الوظائف وربما تأكيدًا بشريًا قبل التنفيذ.
هل هو متوافق مع LangChain أو LlamaIndex أو خدمة مثل Azure AI Agent؟+
نعم: تقوم هذه الأطر بتنسيق حلقة استدعاء الوظائف نيابةً عنك، ولكن يظل تنفيذ الأداة ملكًا لك. نفس المعالج (NL2SQL ثم التنفيذ للقراءة فقط) يربط نفسه كوظيفة للأداة المعلنة في LangChain أو في وكيل Azure، بدلاً من السماح لهم بتنفيذ SQL الخام.

هل أنت جاهز للنشر؟

الواجهة الخلفية الخاصة بك في خمس دقائق.

لا حاجة لبطاقة ائتمان · 500 ميجابايت مجانًا · 50000 MAU