كل فريق يطلق أكثر من ميزة ذكاء اصطناعي واحدة يصطدم في النهاية بالجدار نفسه. خدمة تستدعي Anthropic مباشرة، وأخرى تستدعي OpenAI، وثالثة تستخدم خادم Ollama محلياً. مفاتيح الـ API متناثرة في أربعة ملفات .env. ولا أحد يستطيع الإجابة عن سؤال «كم أنفقنا على الذكاء الاصطناعي الشهر الماضي، ولكل فريق؟» دون تصدير ثلاثة ملفات فوترة. وعندما يتعطل أحد المزودين، تفشل كل خدمة على حدة لعدم وجود بديل مشترك.
بوابة الذكاء الاصطناعي تحل هذه المشكلة بوضع نقطة وصول واحدة متوافقة مع OpenAI أمام كل النماذج التي تستخدمها. تطبيقاتك تتحدث إلى البوابة، والبوابة تتحدث إلى المزودين. التوجيه وإعادة المحاولة والميزانيات والتخزين المؤقت والسجلات، كلها في مكان واحد.
و LiteLLM Proxy هو الخيار مفتوح المصدر في هذا المجال. وعلى خلاف البوابات المُستضافة، فهو يعمل على بنيتك التحتية أنت — حاوية واحدة، وقاعدة بيانات Postgres، ونسخة Redis — وهو أمر مهم حين تتعامل مع بيانات عملاء تخضع لمتطلبات إقامة البيانات، أو حين لا ترغب ببساطة في وجود طرف ثالث بينك وبين كل استدعاء للنموذج.
في هذا الدرس ننشر بوابة LiteLLM بشكل قريب من بيئة الإنتاج، ثم نربط بها تطبيق TypeScript.
بوابة، لا إطار عمل. لا يحل LiteLLM Proxy محل إطار عمل الوكلاء لديك. ستستمر في استخدام Vercel AI SDK أو LangGraph أو حتى fetch مباشرة. البوابة تغيّر فقط عنوان الأساس والمفتاح اللذين تشير إليهما تلك المكتبات، ولهذا يمكن التبني تدريجياً، خدمة تلو الأخرى.
المتطلبات المسبقة
قبل البدء، تأكد من توفر:
- Docker وDocker Compose مثبّتين ويعملان
- Node.js الإصدار 20 أو أحدث لعميل TypeScript
- مفتاح API واحد على الأقل من أحد المزودين (Anthropic أو OpenAI أو Google أو خادم Ollama محلي)
- إلمام أساسي بـ متغيرات البيئة وصيغة YAML
- طرفية تتعامل مع
curl
لا حاجة لمعرفة بلغة Python. فرغم أن LiteLLM مكتوب بها، سنشغّله بالكامل كحاوية ونتفاعل معه عبر HTTP.
ما الذي ستبنيه
بوابة تقوم بما يلي:
- تعرض نقطة وصول واحدة متوافقة مع OpenAI على
http://localhost:4000 - توجّه الطلبات بين Claude وGPT ونموذج محلي خلف أسماء مستعارة مثل
smartوcheap - تتحول تلقائياً إلى بديل عندما يعيد أحد المزودين خطأً أو تنتهي مهلته
- تُصدر مفاتيح افتراضية لكل فريق، لكل منها ميزانية شهرية وحدود معدل خاصة
- تخزّن الطلبات المتطابقة مؤقتاً في Redis لخفض التكلفة
- تسجّل كل استدعاء — النموذج، الرموز، التكلفة، زمن الاستجابة — في Postgres مع واجهة إدارة مدمجة
ثم نستهلكها من TypeScript بطريقتين: عبر OpenAI SDK المباشر، وعبر Vercel AI SDK للبث المتدفق.
الخطوة 1: هيكل المشروع
أنشئ مجلداً مخصصاً للبوابة. يبقى منفصلاً عن شيفرة التطبيق، لأن البوابة بنية تحتية وليست جزءاً من تطبيق بعينه.
mkdir ai-gateway && cd ai-gateway
touch docker-compose.yml config.yaml .envأضف الأسرار في ملف .env. لا ترفع هذا الملف إلى المستودع أبداً.
# .env
LITELLM_MASTER_KEY=sk-master-استبدلها-بسلسلة-عشوائية-طويلة
LITELLM_SALT_KEY=سلسلة-عشوائية-طويلة-أخرى-لتشفير-مفاتيح-المزودين
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...
GEMINI_API_KEY=...
POSTGRES_PASSWORD=كلمة-مرور-قوية-لقاعدة-البياناتيستحق مفتاحان توضيحاً. LITELLM_MASTER_KEY هو بيانات اعتماد المدير — يمكنه إنشاء وإلغاء كل المفاتيح الأخرى، ولذلك يجب ألا يظهر داخل أي تطبيق. أما LITELLM_SALT_KEY فيشفّر بيانات اعتماد المزودين المخزّنة في قاعدة البيانات؛ وإذا غيّرته لاحقاً تصبح المفاتيح المخزّنة سابقاً غير قابلة للقراءة، فحدّده مرة واحدة واحتفظ بنسخة احتياطية منه.
الخطوة 2: Docker Compose مع Postgres وRedis
يعمل الوسيط دون قاعدة بيانات، لكنك تفقد كل ما هو مهم: المفاتيح الافتراضية والميزانيات وسجلات الإنفاق تتطلب جميعها Postgres. أما Redis فيشغّل التخزين المؤقت ويجعل حدود المعدل دقيقة عبر عدة نسخ من الوسيط.
# docker-compose.yml
services:
litellm:
image: ghcr.io/berriai/litellm:main-stable
ports:
- "4000:4000"
volumes:
- ./config.yaml:/app/config.yaml
command: ["--config", "/app/config.yaml", "--port", "4000"]
environment:
LITELLM_MASTER_KEY: ${LITELLM_MASTER_KEY}
LITELLM_SALT_KEY: ${LITELLM_SALT_KEY}
DATABASE_URL: postgresql://litellm:${POSTGRES_PASSWORD}@postgres:5432/litellm
REDIS_HOST: redis
REDIS_PORT: "6379"
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
OPENAI_API_KEY: ${OPENAI_API_KEY}
GEMINI_API_KEY: ${GEMINI_API_KEY}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: litellm
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
redis:
image: redis:7-alpine
command: ["redis-server", "--maxmemory", "512mb", "--maxmemory-policy", "allkeys-lru"]
restart: unless-stopped
volumes:
pgdata:سياسة الإخلاء في Redis مهمة. تعني allkeys-lru أنه عند امتلاء الذاكرة المؤقتة تُحذف أقل المدخلات استخداماً بدلاً من أن يرفض الخادم الكتابة — فالذاكرة المؤقتة التي تتوقف عن قبول المدخلات تحوّل بوابتك بصمت إلى مجرد ممر مكلف.
الخطوة 3: ملف الإعداد — النماذج والأسماء المستعارة والبدائل
في config.yaml تظهر القيمة الحقيقية للبوابة. الفكرة الجوهرية: تعرّف أسماء نماذج عامة تستخدمها تطبيقاتك، وتربط كل اسم بواحد أو أكثر من عمليات النشر الفعلية لدى المزودين.
# config.yaml
model_list:
# مستوى "smart" مدعوم بمزودين اثنين
- model_name: smart
litellm_params:
model: anthropic/claude-opus-4-8
api_key: os.environ/ANTHROPIC_API_KEY
rpm: 500
- model_name: smart
litellm_params:
model: openai/gpt-5.6
api_key: os.environ/OPENAI_API_KEY
rpm: 500
# مستوى "cheap" للتصنيف والتلخيص
- model_name: cheap
litellm_params:
model: anthropic/claude-haiku-4-5-20251001
api_key: os.environ/ANTHROPIC_API_KEY
# نموذج مُستضاف ذاتياً لكل ما يجب ألا يغادر الشبكة
- model_name: private
litellm_params:
model: ollama/qwen3:14b
api_base: http://host.docker.internal:11434
# التضمينات، كي تمر خطوط المعالجة المتجهية عبر البوابة أيضاً
- model_name: embed
litellm_params:
model: openai/text-embedding-3-large
api_key: os.environ/OPENAI_API_KEY
router_settings:
routing_strategy: usage-based-routing-v2
redis_host: os.environ/REDIS_HOST
redis_port: os.environ/REDIS_PORT
num_retries: 2
timeout: 60
fallbacks:
- smart: ["cheap"]
context_window_fallbacks:
- smart: ["smart"]
litellm_settings:
drop_params: true
set_verbose: false
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
database_url: os.environ/DATABASE_URLهناك عدة قرارات تستحق الشرح.
مدخلان يحملان الاسم smart. هذا مقصود، إذ يعامل LiteLLM المدخلات المتشابهة الاسم كمجموعة لتوزيع الحمل. ومع usage-based-routing-v2 يوزَّع المرور حسب الهامش المتبقي من حد المعدل لكل عملية نشر، ويُتتبع ذلك في Redis كي تتفق جميع النسخ.
الأسماء المستعارة تفصل التطبيقات عن المزودين. تطبيقك يطلب smart. وبعد ستة أشهر تستبدل النموذج الأساسي في ملف YAML واحد، وتعيد تشغيل الحاوية، فتُحدَّث كل الخدمات. لا إعادة نشر، ولا تغيير في الشيفرة، ولا اجتماع تنسيق.
الخيار drop_params: true يحذف بصمت المعاملات التي لا يدعمها مزود معيّن بدلاً من إعادة خطأ 400. وهذا ما يجعل مبدأ «الشيفرة نفسها بنموذج مختلف» قابلاً للتطبيق فعلاً.
البدائل تُفعَّل عند الأخطاء لا عند تدني الجودة. إذا فشلت كل عمليات نشر smart، يُعاد الطلب إلى cheap. الإجابة عندها أقل جودة، لكن إجابة أقل جودة أفضل من خطأ 500 في معظم الميزات التي يراها المستخدم. قرّر لكل مسار على حدة إن كانت هذه المقايضة مقبولة.
شغّل كل شيء:
docker compose up -d
docker compose logs -f litellmانتظر سطر السجل الذي يفيد بأن الخادم يعمل على المنفذ 4000، ثم تحقق:
curl http://localhost:4000/health/livelinessالخطوة 4: أول طلب
اختبر بالمفتاح الرئيسي أولاً، فقط للتأكد من أن التوجيه يعمل من طرف إلى طرف:
curl http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-d '{
"model": "smart",
"messages": [{"role": "user", "content": "أجب بالضبط: البوابة تعمل"}]
}'الاستجابة هي JSON قياسي لإكمال محادثة OpenAI، بغض النظر عن المزود الذي خدمها فعلياً. وهذا التوافق هو جوهر الفكرة: أي SDK أو أداة أو إضافة محرر تتحدث واجهة OpenAI صارت الآن تتحدث إلى كل النماذج التي أعددتها.
لا تُطلق المفتاح الرئيسي في الإنتاج أبداً. فهو يملك صلاحيات إدارية كاملة. من هذه النقطة فصاعداً، تحصل التطبيقات على مفاتيح افتراضية، ويبقى المفتاح الرئيسي في مدير الأسرار وفي طرفيتك أنت فقط.
الخطوة 5: المفاتيح الافتراضية والفرق والميزانيات
هذه هي الميزة التي تبرر الاستضافة الذاتية. المفتاح الافتراضي هو بيانات اعتماد تُصدرها عبر الـ API، محصورة بنماذج محددة، مع سقف إنفاق وحدود معدل مرتبطة بها.
أنشئ فريقاً أولاً، ثم مفتاحاً ينتمي إليه:
# إنشاء فريق بسقف شهري
curl http://localhost:4000/team/new \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"team_alias": "web-frontend",
"max_budget": 200,
"budget_duration": "30d",
"models": ["smart", "cheap", "embed"]
}'تتضمن الاستجابة team_id. استخدمه لإصدار مفتاح:
curl http://localhost:4000/key/generate \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"team_id": "ضع_معرف_الفريق_هنا",
"key_alias": "web-frontend-production",
"max_budget": 50,
"budget_duration": "30d",
"rpm_limit": 120,
"tpm_limit": 200000,
"metadata": {"service": "noqta-web", "env": "production"}
}'ستحصل على مفتاح يبدأ بـ sk-. تُطبَّق الآن ثلاثة حدود في آن واحد: ميزانية المفتاح نفسه البالغة 50 دولاراً، وميزانية الفريق البالغة 200 دولار، وسقفا الطلبات والرموز في الدقيقة. وعند تجاوز أي منها تعيد البوابة رمز 429 مع رسالة تسمّي الحد الذي انطلق — وهو أسهل بكثير في التشخيص من رفض عام صادر عن المزود.
ومن الممارسات الجديرة بالتبني: إصدار مفتاح واحد لكل خدمة ولكل بيئة، لا مفتاح لكل مطوّر. فعند تسريب مفتاح، تُلغي بيانات اعتماد خدمة واحدة وتستبدلها في مكان واحد:
curl http://localhost:4000/key/delete \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{"keys": ["sk-المفتاح-المسرَّب"]}'راجع الإنفاق في أي وقت:
curl "http://localhost:4000/key/info?key=sk-مفتاحك" \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"الخطوة 6: الاتصال من TypeScript
لأن البوابة متوافقة مع OpenAI، يعمل SDK الرسمي دون أي تعديل. يتغيّر فقط baseURL وapiKey.
npm install openai// lib/gateway.ts
import OpenAI from "openai";
export const gateway = new OpenAI({
baseURL: process.env.LITELLM_BASE_URL ?? "http://localhost:4000/v1",
apiKey: process.env.LITELLM_API_KEY!, // المفتاح الافتراضي، لا المفتاح الرئيسي
});
export async function summarise(text: string) {
const res = await gateway.chat.completions.create({
model: "cheap", // اسم مستعار، لا معرّف نموذج لدى مزود
messages: [
{ role: "system", content: "لخّص في ثلاث نقاط." },
{ role: "user", content: text },
],
});
return res.choices[0]?.message?.content ?? "";
}لاحظ أن لا شيء في هذا الملف يسمّي مزوداً. وهذه بالضبط الخاصية التي تشتريها: شيفرة تطبيق لا رأي لها في المختبر الذي درّب النموذج القائم خلفها.
البث المتدفق مع Vercel AI SDK
في تطبيقات Next.js، وجّه مزوّد AI SDK المتوافق مع OpenAI نحو البوابة:
npm install ai @ai-sdk/openai-compatible// app/api/chat/route.ts
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { streamText, convertToModelMessages } from "ai";
const gateway = createOpenAICompatible({
name: "litellm",
baseURL: process.env.LITELLM_BASE_URL!,
apiKey: process.env.LITELLM_API_KEY!,
});
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: gateway.chatModel("smart"),
messages: convertToModelMessages(messages),
// هذه البيانات الوصفية تصل إلى البوابة وتظهر في سجلات الإنفاق
headers: {
"x-litellm-tags": "feature:support-chat,tier:pro",
},
});
return result.toUIMessageStreamResponse();
}هذه الوسوم أنفع مما تبدو. فيتحول توزيع التكلفة من «تطبيق الويب أنفق 340 دولاراً» إلى «محادثة الدعم أنفقت 210 دولارات، والتهيئة 90 دولاراً» — وهي الدقة التي تحتاجها لتقرر ما الذي يستحق التحسين.
الخطوة 7: التخزين المؤقت
الطلبات المتطابقة أكثر شيوعاً مما تتوقع الفرق: إعادة المحاولات، وإعادة تحميل الصفحات، والمهام الدفعية التي تُعاد على صفوف لم تتغيّر. والتخزين المؤقت في Redis يحوّلها إلى استجابات مجانية وفورية.
أضف إلى config.yaml:
litellm_settings:
drop_params: true
cache: true
cache_params:
type: redis
host: os.environ/REDIS_HOST
port: os.environ/REDIS_PORT
ttl: 3600
supported_call_types: ["acompletion", "atext_completion", "aembedding"]أعد التشغيل بـ docker compose restart litellm. أرسل الطلب نفسه مرتين وقارن — تعود الاستجابة الثانية خلال أجزاء من الثانية وتسجّل تكلفة صفرية.
عطّل التخزين المؤقت لطلب بعينه حين يجب أن يكون الاستدعاء طازجاً دائماً:
const res = await gateway.chat.completions.create(
{ model: "cheap", messages },
{ headers: { "x-litellm-no-cache": "true" } },
);والتضمينات هي المجال الذي يؤتي فيه التخزين المؤقت أكبر ثماره. فإعادة فهرسة مجموعة مستندات تعني عادةً إعادة حساب متجهات نصوص لم تتغيّر؛ ومع ذاكرة مؤقتة أمامها، لا يصل إلى المزود سوى الأجزاء الجديدة فعلاً.
انتبه عند تخزين الطلبات المخصصة. إذا كان قالب الطلب لديك يدرج اسم المستخدم أو بيانات حسابه، فلن ينتج مستخدمان مختلفان طلباً متطابقاً أبداً، وبالتالي لن تُستخدم الذاكرة المؤقتة إطلاقاً. أما إذا كان القالب لا يدرج شيئاً خاصاً بالمستخدم بينما يُفترض أن تختلف الإجابات لكل مستخدم، فسيقدّم التخزين المؤقت إجابة مستخدم إلى آخر. راجع طريقة بناء الطلبات قبل التفعيل على نطاق واسع.
الخطوة 8: المراقبة والملاحظة
كل طلب يُسجَّل بالفعل في Postgres. وتعرض الواجهة المدمجة على http://localhost:4000/ui — سجّل الدخول بالمفتاح الرئيسي — الإنفاق لكل مفتاح وفريق ونموذج، إضافة إلى معدلات الأخطاء ومئينات زمن الاستجابة.
ولتتبّع أعمق، أضف دوال استدعاء تمرّر بيانات الطلبات إلى منصة مراقبة:
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]مرّر LANGFUSE_PUBLIC_KEY وLANGFUSE_SECRET_KEY كمتغيرات بيئة في ملف compose. عندها ينتج كل استدعاء عبر البوابة أثراً كاملاً يتضمن الطلب والإكمال وعدد الرموز والتكلفة وزمن الاستجابة — دون سطر واحد من أدوات القياس داخل تطبيقك. وإذا كنت تشغّل Langfuse بالفعل، فإن درس المراقبة مع Langfuse يغطي جانب لوحة التحكم.
وللتنبيهات، يمكن للبوابة إرسال إشعارات الميزانية والأخطاء إلى Slack:
general_settings:
alerting: ["slack"]
alerting_threshold: 300 # بالثواني؛ يُبلّغ عن الطلبات المتعثرةاختبار التنفيذ
نفّذ هذه الفحوص قبل توجيه حركة الإنتاج إلى البوابة.
التوجيه. استدعِ smart عشرين مرة وتأكد من الواجهة أن الطلبات تتوزع بين عمليتي النشر بدل أن تتركز على واحدة.
البديل. ضع مؤقتاً api_key غير صالح على مدخل Anthropic، وأعد التشغيل، ثم أرسل طلباً. يجب أن ينجح عبر OpenAI، وأن تُظهر السجلات إعادة محاولة.
تطبيق الميزانية. أصدر مفتاحاً بـ "max_budget": 0.01، وأرسل طلبات حتى يُستنفد، وتأكد من استلامك رمز 429 يسمّي الميزانية.
حدود المعدل. أصدر مفتاحاً بـ "rpm_limit": 2 وأطلق خمسة طلبات في حلقة:
for i in $(seq 1 5); do
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:4000/v1/chat/completions \
-H "Authorization: Bearer $TEST_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"cheap","messages":[{"role":"user","content":"مرحبا"}]}'
doneيُفترض أن ترى استجابتي 200 تليهما رموز 429.
التخزين المؤقت. أرسل طلباً متطابقاً مرتين وقارن زمن الاستجابة والتكلفة المسجلة.
حل المشكلات الشائعة
الحاوية تبدأ ثم تتوقف. السبب دائماً تقريباً قاعدة البيانات. راجع docker compose logs postgres وتأكد من أن DATABASE_URL يطابق بيانات اعتماد Postgres تماماً — فكلمة مرور غير متطابقة تنتج خطأ إقلاع مربكاً بدل فشل مصادقة واضح.
رسالة Invalid model name passed in. يجب أن يطابق اسم النموذج في طلبك قيمة model_name في config.yaml، لا معرّف النموذج لدى المزود. فطلب claude-opus-4-8 يفشل إذا كنت قد عرّفت الاسم المستعار smart. اعرض المتاح عبر curl http://localhost:4000/v1/models.
تعذّر الوصول إلى Ollama من داخل الحاوية. داخل Docker يشير localhost إلى الحاوية نفسها. استخدم http://host.docker.internal:11434 على macOS وWindows؛ وعلى Linux أضف extra_hosts: ["host.docker.internal:host-gateway"] إلى الخدمة.
الميزانيات لا تُعاد تصفيرها. القيمة budget_duration هي نافذة متحركة تبدأ من تاريخ إنشاء المفتاح، لا شهر تقويمي. فمفتاح أُنشئ في اليوم العشرين يُعاد تصفيره في اليوم العشرين.
الإنفاق يظهر صفراً لنموذج مخصص. يحسب LiteLLM التكلفة من جدول أسعار مدمج. والنماذج المُستضافة ذاتياً أو غير المألوفة تحتاج تسعيراً صريحاً:
- model_name: private
litellm_params:
model: ollama/qwen3:14b
api_base: http://host.docker.internal:11434
model_info:
input_cost_per_token: 0.0000001
output_cost_per_token: 0.0000002البث المتدفق يتوقف خلف وسيط عكسي. يخزّن Nginx الاستجابات مؤقتاً بشكل افتراضي، ما يعطّل أحداث الخادم المرسلة. أضف proxy_buffering off; إلى كتلة الموقع الخاصة بالبوابة.
الانتقال إلى الإنتاج
تفصل بضعة تغييرات بين الإعداد المحلي أعلاه وبين نظام تأتمنه على حركة حقيقية:
- أنهِ TLS عند الحافة. ضع الوسيط خلف Caddy أو Nginx أو موازن حمل. لا تعرّض المنفذ 4000 مباشرة أبداً.
- شغّل أكثر من نسخة. الوسيط عديم الحالة، وRedis يحافظ على اتساق حدود المعدل والذاكرة المؤقتة بين النسخ.
- استخدم Postgres مُدارة. سجل الإنفاق هو مستند الفوترة لديك، ويستحق نسخاً احتياطية حقيقية.
- ثبّت وسم الصورة. الوسم
main-stableيتغيّر. ثبّت إصداراً محدداً وحدّث بقرار واعٍ. - دوّر المفتاح الرئيسي دورياً وأبقِه خارج كل بيئات التطبيقات.
- اضبط تنبيهات على الميزانية لا على الأخطاء وحدها، فتجاوزات التكلفة صامتة عادةً.
الخطوات التالية
- مرّر وكلاءك الحاليين عبر البوابة — درسا Vercel AI SDK وMastra يستخدمان عناوين أساس قابلة للتهيئة
- أضف Langfuse لإدارة إصدارات الطلبات إلى جانب التتبع على مستوى البوابة
- قارن بالمسار المُدار في درس Vercel AI Gateway
- فعّل إضافات الحماية لإخفاء البيانات الشخصية قبل وصول الطلبات إلى المزودين الخارجيين
الخاتمة
نمط البوابة بنية تحتية غير براقة، لكنها تزيل بهدوء فئة كاملة من المشكلات. تتوقف مفاتيح المزودين عن الانتشار في شيفرتك. ويصير اختيار النموذج تغييراً في الإعدادات بدل أن يكون عملية نشر. ويصبح الإنفاق منسوباً إلى الميزة التي سببته. وتتدهور الخدمة بلطف بدل أن تتعطل عند الأعطال.
استضافة LiteLLM ذاتياً تكلّفك ساعة إعداد وحاوية إضافية للصيانة، وفي المقابل لا تمر مطالباتك وإكمالاتك أبداً عبر بنية تحتية لا تتحكم بها — وهو أمر لا يُعد تفضيلاً بل شرطاً بالنسبة للفرق التي تتعامل مع بيانات عملاء خاضعة لالتزامات الإقامة أو السرية.
ابدأ بخدمة واحدة. وجّهها إلى البوابة، وراقب السجلات لأسبوع، ثم رحّل التالية.