تصميم أنظمة ذكاء اصطناعي بدون تقييد بمزود واحد: شو تجرّد وشو تخلّي
كيف تصمم بنية أنظمة ذكاء اصطناعي تتحمل تغيير المزود. طبقات التجريد، نقل البرومبتات، التوجيه متعدد النماذج، التطوير القائم على التقييم، ومتى يكون التقييد بالمزود القرار الصحيح.
فخ التقييد بالمزود
كل مشروع ذكاء اصطناعي يبدأ بمزود واحد. OpenAI أو Anthropic أو نموذج محلي. الـ SDK يدخل في الكود. ميزات خاصة بالمزود (صيغة Function Calling، وضع JSON، سلوك System Prompt) تنحفر في منطق العمل. بعد ستة شهور، تبي تغيّر المزود (تكاليف، أداء، امتثال) وتكتشف إن التغيير يتطلب إعادة كتابة نص التطبيق.
بنينا أنظمة ذكاء اصطناعي تستخدم عدة مزودين بنفس الوقت، وغيّرنا المزود بنص المشروع بدون ما نلمس منطق العمل. هالمقال يغطي البنية اللي تخلّي هالشي ممكن والـ trade-offs الحقيقية المرتبطة فيه.
لأنماط بنية الذكاء الاصطناعي الأشمل، شوف دليل أنظمة الذكاء الاصطناعي ودليل تنسيق الذكاء الاصطناعي.
شو اللي يسبب التقييد
| مصدر التقييد | مثال | الخطورة |
|---|---|---|
| ربط SDK | openai.chat.completions.create() في 50 ملف | عالية |
| صيغة البرومبت | برومبتات محسّنة لسلوك GPT-4، تفشل مع Claude | عالية |
| نماذج Fine-Tuned | نموذج متدرب على بياناتك، مستضاف عند المزود | عالية جدا |
| ميزات خاصة | Assistants API، صيغة Function Calling، وضع JSON | متوسطة |
| تقييد الـ Embedding | 100K وثيقة مضمّنة بـ text-embedding-3-small، غير متوافقة مع نماذج ثانية | عالية جدا |
| بنية Rate Limit | نظام مصمم حول Rate Limits و Batching الخاصة بـ OpenAI | منخفضة |
طبقة التجريد اللي فعلا تشتغل
طبقة تجريد جيدة عندها ثلاث مكونات: واجهة موحدة لاستدعاءات النماذج، طبقة إدارة البرومبتات، وإطار تقييم.
// واجهة LLM موحدة
interface LlmProvider {
generate(request: LlmRequest): Promise<LlmResponse>;
stream(request: LlmRequest): AsyncIterable<LlmChunk>;
embed(texts: string[]): Promise<number[][]>;
}
interface LlmRequest {
model: string;
messages: Message[];
temperature?: number;
maxTokens?: number;
responseFormat?: 'text' | 'json';
tools?: ToolDefinition[];
}
interface LlmResponse {
text: string;
usage: { promptTokens: number; completionTokens: number };
finishReason: string;
model: string;
provider: string;
latencyMs: number;
}
كل مزود يطبّق هالواجهة:
class OpenAiProvider implements LlmProvider {
async generate(request: LlmRequest): Promise<LlmResponse> {
const response = await this.client.chat.completions.create({
model: request.model,
messages: this.convertMessages(request.messages),
temperature: request.temperature,
max_tokens: request.maxTokens,
response_format: request.responseFormat === 'json'
? { type: 'json_object' } : undefined,
});
return this.convertResponse(response);
}
}
class AnthropicProvider implements LlmProvider {
async generate(request: LlmRequest): Promise<LlmResponse> {
const response = await this.client.messages.create({
model: request.model,
system: this.extractSystemMessage(request.messages),
messages: this.convertMessages(request.messages),
temperature: request.temperature,
max_tokens: request.maxTokens ?? 4096,
});
return this.convertResponse(response);
}
}
منطق العمل يستخدم الواجهة، ما يستخدم SDK المزود مباشرة أبدا:
// منطق العمل: مستقل عن المزود
async function generateCustomerResponse(ctx: Context, ticket: string): Promise<string> {
const provider = ctx.getLlmProvider(); // يتحدد من الإعدادات
const response = await provider.generate({
model: ctx.getModelForUseCase('customer-support'),
messages: [
{ role: 'system', content: SUPPORT_SYSTEM_PROMPT },
{ role: 'user', content: ticket },
],
temperature: 0.3,
});
return response.text;
}
التحويل من OpenAI لـ Anthropic: غيّر الإعدادات. صفر تعديلات كود في منطق العمل.
مشكلة نقل البرومبتات
البرومبتات مو قابلة للنقل بين النماذج. برومبت محسّن لـ GPT-4 ممكن يعطي نتائج أسوأ على Claude، والعكس صحيح. النماذج تفسر التعليمات بشكل مختلف، تتعامل مع الحالات الحدية بشكل مختلف، وعندها نقاط قوة مختلفة.
الحل: نسخ برومبت لكل عائلة نماذج.
const SUPPORT_PROMPTS: Record<string, string> = {
'openai': `You are a customer support assistant. Be concise and helpful.
When you don't know the answer, say so clearly.
Always reference the customer's order number.`,
'anthropic': `You are a customer support assistant.
<instructions>
- Be concise and helpful
- When you don't know the answer, say so clearly
- Always reference the customer's order number
</instructions>`,
'local': `### System
You are a customer support assistant.
### Rules
1. Be concise and helpful
2. When you don't know the answer, say so clearly
3. Always reference the customer's order number`,
};
function getPrompt(useCase: string, provider: string): string {
return PROMPTS[useCase][provider] || PROMPTS[useCase]['default'];
}
هالشي يضيف تكلفة صيانة (عدة نسخ من البرومبتات)، بس هي الواقع. برومبت واحد لكل النماذج يعني قبول تراجع بالجودة على نموذج واحد على الأقل.
التوجيه متعدد النماذج
المهام المختلفة عندها متطلبات مختلفة. التصنيف يحتاج سرعة. التوليد يحتاج جودة. الـ Embedding يحتاج ثبات. وجّه كل مهمة للنموذج المناسب.
const MODEL_ROUTING: Record<string, ModelConfig> = {
'classification': {
primary: { provider: 'openai', model: 'gpt-4o-mini' },
fallback: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
reason: 'سريع، رخيص، كافي للتصنيف',
},
'generation': {
primary: { provider: 'anthropic', model: 'claude-sonnet-4-20250514' },
fallback: { provider: 'openai', model: 'gpt-4o' },
reason: 'أفضل جودة للتوليد الطويل',
},
'embedding': {
primary: { provider: 'openai', model: 'text-embedding-3-small' },
fallback: null, // ما تقدر تبدّل نماذج الـ Embedding بدون إعادة تضمين كل شي
reason: 'الثبات: كل الـ Embeddings لازم تستخدم نفس النموذج',
},
'summarization': {
primary: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
fallback: { provider: 'openai', model: 'gpt-4o-mini' },
reason: 'سريع ورخيص للتلخيص',
},
};
إعدادات التوجيه منفصلة عن منطق العمل. تغيير أي نموذج يتعامل مع التلخيص هو تغيير إعدادات، مو تغيير كود.
تقييد الـ Embedding: الأصعب بالكسر
الـ Embeddings هي أقوى شكل من أشكال التقييد. بمجرد ما تضمّن 100K وثيقة بـ text-embedding-3-small، التحويل لنموذج Embedding ثاني يتطلب إعادة تضمين كل شي. المتجهات غير متوافقة بين النماذج (أبعاد مختلفة، فضاءات دلالية مختلفة).
التخفيفات:
- خزّن الوثائق المصدرية جنب الـ Embeddings (عشان تقدر تعيد التضمين)
- تتبّع أي نموذج Embedding استُخدم لكل وثيقة
- خصص ميزانية لإعادة التضمين لما تخطط لتغيير المزود
- فكّر بنماذج Embedding مفتوحة المصدر (sentence-transformers) للنقل
لمزيد عن بنيات الـ Embedding والبحث بالمتجهات، شوف دليل بنية البحث بالمتجهات ودليل أنظمة RAG للمؤسسات.
التطوير القائم على التقييم
المفتاح لتغيير مزود آمن: قيّم مقابل المهام، مو مقابل النماذج. إذا مجموعة التقييم عندك تختبر "هل الإجابة تعالج مشكلة العميل بشكل صحيح؟" بدل "هل المخرج يطابق صيغة GPT-4؟"، تقدر تغيّر النماذج بثقة.
interface EvalCase {
input: string;
expectedBehavior: string; // شو لازم المخرج يسوي، مو شو لازم يقول
criteria: EvalCriterion[];
}
interface EvalCriterion {
name: string;
check: (output: string, context: EvalCase) => boolean | number;
}
const SUPPORT_EVALS: EvalCase[] = [
{
input: "I haven't received my order #12345",
expectedBehavior: "Acknowledge the issue, reference order number, offer next steps",
criteria: [
{ name: 'references_order', check: (out) => out.includes('12345') },
{ name: 'acknowledges_issue', check: (out) => /sorry|apologize|understand/i.test(out) },
{ name: 'offers_action', check: (out) => /check|investigate|track|follow up/i.test(out) },
{ name: 'reasonable_length', check: (out) => out.length > 50 && out.length < 500 },
],
},
];
// شغّل التقييمات مقابل أي نموذج
async function runEvalSuite(provider: LlmProvider, model: string): Promise<EvalResults> {
const results = [];
for (const evalCase of SUPPORT_EVALS) {
const output = await provider.generate({
model,
messages: [
{ role: 'system', content: SUPPORT_SYSTEM_PROMPT },
{ role: 'user', content: evalCase.input },
],
});
const scores = evalCase.criteria.map(c => ({
name: c.name,
passed: c.check(output.text, evalCase),
}));
results.push({ input: evalCase.input, scores });
}
return summarize(results);
}
شغّل مجموعة التقييم قبل ما تغيّر النماذج. إذا النموذج الجديد نجح بدرجات مقبولة، التغيير آمن. إذا ما نجح، تعرف بالضبط أي سلوكيات تراجعت.
هالنمط مرتبط بشكل وثيق باللي نوصفه في دليل مراقبة الذكاء الاصطناعي ودليل حوكمة الذكاء الاصطناعي.
شو ما لازم تجرّد
مو كل شي لازم يتجرّد. التجريد الزائد يضيف تعقيد بدون فائدة.
| لا تجرّد | ليش |
|---|---|
| نموذج الـ Embedding (داخل المشروع) | المتجهات غير متوافقة. التجريد ما يساعد. |
| تفاصيل النماذج Fine-Tuned | الـ Fine-Tuning بطبيعته خاص بالمزود |
| تحسينات خاصة بالمزود | الـ Batching والـ Caching ومعالجة Rate Limit تختلف لكل مزود |
| تفاصيل صيغة الـ Streaming | عالجها في adapter المزود، مو في التجريد |
التجريد لازم يغطي: اختيار النموذج، توجيه البرومبتات، تحليل الاستجابة، تتبع التكاليف، ومنطق الـ Fallback. ما لازم يحاول يخلّي كل المزودين يتصرفون بنفس الطريقة. هم ما يسوون جذي، والتظاهر إنهم يسوون يخلق أخطاء.
إذا تبي تعرف كيف نطبق هالأنماط في أنظمة حقيقية، شوف دليل هندسة البرمجيات ودليل بنية الأنظمة.
متى يكون التقييد بالمزود القرار الصحيح
أحيانا، التقييد بمزود واحد هو القرار التجاري الصحيح:
- Fine-Tuning يتطلب التزام بمزود واحد. النموذج المتدرب مو قابل للنقل.
- خصومات الحجم من مزود واحد ممكن تقلل التكاليف بشكل كبير.
- الامتثال ممكن يتطلب مزود محدد (إقامة البيانات، الشهادات).
- سرعة الوصول للسوق تعني استخدام ميزات خاصة بالمزود بدون حمل التجريد الزائد.
الأساس: اتخذ قرار التقييد بوعي، مو بالصدفة. إذا اخترت تستخدم Assistants API من OpenAI لأنها توفر 3 شهور تطوير، هذا trade-off صحيح. إذا استخدمتها لأنك ما فكرت بالتجريد، هذا دين تقني.
لاعتبارات الامتثال، شوف دليل GDPR وتحليل امتثال الذكاء الاصطناعي مع GDPR. منهجيتنا توضح كيف ناخذ قرارات البنية هذي بسياق المشروع.
الأخطاء الشائعة
-
SDK المزود في منطق العمل.
openai.chat.completions.create()منتشر على 50 ملف يخلي التغيير مستحيل. استخدم طبقة تجريد. -
برومبت واحد لكل النماذج. البرومبتات خاصة بالنموذج. حافظ على نسخ لكل عائلة نماذج. اقبل تكلفة الصيانة.
-
تجريد كل شي. التجريد الزائد يضيف تعقيد. جرّد الواجهة، مو الداخليات.
-
بدون مجموعة تقييم. بدون تقييمات أوتوماتيكية، ما تقدر تعرف إذا تغيير النموذج خرّب الجودة لين المستخدمين يشتكون.
-
تجاهل تقييد الـ Embedding. تغيير نماذج الـ Embedding يتطلب إعادة تضمين كل وثيقة. خطط لهالتكلفة.
-
تقييد بالصدفة. أسوأ نوع. استخدام ميزات خاصة بالمزود بدون ما تنتبه إنك تخلق اعتمادية.
نوصف أنماط أخطاء مشابهة في دليل أنماط فشل الذكاء الاصطناعي ودليل الذكاء الاصطناعي مع الإنسان بالحلقة.
أهم النقاط
-
جرّد الواجهة، مو التطبيق. واجهة
LlmProviderموحدة مع adapters خاصة بكل مزود. منطق العمل يستدعي الواجهة. -
البرومبتات مو قابلة للنقل. حافظ على نسخ برومبت لكل عائلة نماذج. برومبت واحد لكل النماذج يعني تراجع بالجودة بمكان ما.
-
وجّه المهام المختلفة لنماذج مختلفة. التصنيف لنموذج سريع، التوليد لنموذج دقيق، الـ Embeddings لنموذج ثابت. مدفوع بالإعدادات، مو بالكود.
-
قيّم مقابل المهام، مو مقابل النماذج. إذا مجموعة التقييم تختبر السلوك ("هل يذكر رقم الطلب؟") بدل الصيغة، تقدر تغيّر النماذج بثقة.
-
الـ Embedding هو أصعب تقييد تكسره. خزّن الوثائق المصدرية. تتبّع أي نموذج استُخدم. خصص ميزانية لإعادة التضمين لما تغيّر.
-
أحيانا التقييد بالمزود هو الصح. Fine-Tuning وخصومات الحجم والامتثال ممكن يبررونه. خلّه قرار واعي.
نصمم بنيات ذكاء اصطناعي مستقلة عن المزود كجزء من خدمات الذكاء الاصطناعي وممارسة الاستشارات. شوف أيضا حلولنا وحالات الاستخدام. إذا تحتاج مساعدة ببنية الذكاء الاصطناعي، تواصل مع فريقنا أو اطلب عرض سعر.
المواضيع المغطاة
أدلة ذات صلة
الدليل الشامل لتنسيق الذكاء الاصطناعي
دليل تقني عملي لتنسيق نماذج ذكاء اصطناعي متعددة في الإنتاج. تعلم توجيه الطلبات، اختيار النماذج، استراتيجيات الاحتياط وأنماط موازنة الحمل اللي فعلاً تشتغل.
اقرأ الدليلالدليل الشامل لأنظمة الذكاء الاصطناعي الوكيلي
دليل تقني لأنظمة الذكاء الاصطناعي الوكيلي في بيئات الأعمال. تعرف على البنية والقدرات والتطبيقات العملية للوكلاء المستقلين.
اقرأ الدليلأنظمة الذكاء الاصطناعي والبنية الوكيلية
دليل شامل لبناء أنظمة الذكاء الاصطناعي للمؤسسات مع ملكية وتحكم كامل. تعلم عن البنية الوكيلية وأنظمة RAG واختيار النماذج وكيف تتجنب الارتباط بالموردين.
اقرأ الدليلجاهز لبناء أنظمة ذكاء اصطناعي جاهزة للإنتاج؟
فريقنا متخصص في بناء أنظمة ذكاء اصطناعي جاهزة للإنتاج. خلينا نحكي كيف نقدر نساعد.
ابدأ محادثة