الوحدة 1 — ما يضيفه LangChain وما يعقّده
قبل أن نكتب سطرًا واحدًا، سؤال هادئ: لماذا نُدخِل إطار عمل بين تطبيقنا ونموذج لغويّ يُستدعى في سطر واحد؟ الإجابة النزيهة تُنجّينا لاحقًا من ورطات معماريّة معروفة، وتحدّد الوحدات التي سنقضي فيها وقتًا حقيقيًّا وتلك التي سنمرّ عليها مرورًا.
ماذا يقدّم LangChain فعلًا
يُقدّم LangChain ثلاثة أمور، لا أكثر ولا أقلّ، ومن يعتبره أكثر من ذلك يتعب سريعًا:
- تجريد موحّد للمزوّدين. يستقبل نموذج المحادثة في OpenAI و Anthropic و Mistral و Ollama رسائل بأسماء حقول مختلفة، ويُرجع مخرجات بشكل مختلف، ويُعبّر عن استدعاء الأدوات بطرق مخت لفة. تُخفي فئة
ChatModelهذه الاختلافات وراء واجهة واحدة، فيصبح تبديل المزوّد سطرًا واحدًا في الإعداد بدل إعادة كتابة النداء. - قابلات تشغيل قابلة للتركيب. كلّ مكوّن (نموذج، تعليمة، محلِّل، مسترجِع، أداة) يُنفّذ الواجهة
Runnable. تُركَّب هذه القابلات بأسلوب LCEL باستعمال المشغِّل|كما تُركَّب أنابيب shell، وتحصل مجّانًا على البثّ (streaming)، وتنفيذ الدُفعات (batch)، والتنفيذ غير المتزامن (async)، والتوازي. - نظام بيئي جاهز. حزم
langchain-openai،langchain-chroma،langchain-community… تجلب مئات المحمّلات والمخازن المتّجهية والمسترجِعات. وفوقها يقف LangGraph لبناء الوكلاء بحلقة تحكّم صريحة، وLangSmith لتتبّع كلّ استدعاء وتقييم النسخ.
ما يعقّده الإطار
لا يوجد تجريد مجّانيّ. حين تُغلَّف نداء بسيط داخل ثلاث طبقات، تصير الأخطاء غامضة، ويصير التنقيح مغامرة في أثر الاستثناء.
ثلاثة مخاطر يجب معرفتها من اليوم الأول. أوّلها، الأطر تتغيّر بسرعة: تغيّر LangChain كلّيًّا في 2024 حين فُصلت langchain-core عن التكاملات، وتُخصَّص الوكلاء اليوم في langgraph بدل langchain.agents القديم. ثانيها، طبقة التجريد تُضيف تأخيرًا وذاكرة: على استدعاء واحد لا يُلاحَظ الفرق، لكن على مسار وكيل بخمس دورات وأداتين يصبح الفرق واضحًا. ثالثها، رسائل الخطأ تُبعِدك عن السبب الحقيقيّ: مفتاح API غير صالح يظهر في أثر داخل AsyncRunnableSequence.__call__.
متى تكتب النداء بيدك
إليك قاعدة عمليّة تصلح للتقرير أمام فريقك:
- استدعاء واحد لنموذج بدون أدوات ولا مستندات، مع سلوك مُختبَر — يدويًّا عبر SDK المزوّد. لا حاجة لإطار.
- سلسلة قصيرة (تعليمة، نموذج، تحليل) قابلة للتغيير في الأسابيع القادمة — LangChain في LCEL يُبرّر نفسه بمكوّنَي البثّ والدُفعات.
- وكيل يستدعي أدوات، يتفرّع، يُعيد المحاولة، يحتاج مراقبة — LangGraph، والوحدة 8 مكرّسة لهذا الاختيار.
- منتج يعتمد بالكامل على مزوّد سحابيّ واحد ولا نيّة لتبديله — يمكن الاستغناء عن التجريد إن كنت مطمئنًّا لهذا القرار لعامين.
الخيط الأحمر يبدأ
يستقبل مساعد إدارة النفقات في هذه الوحدة سؤالًا واحدًا: «هل يمكنني استرداد مبلغ 47 يورو من عشاء عمل بتاريخ 3 مارس؟». الشيفرة أدناه لا تفعل شيئًا سوى نداء النموذج، بأسلوب LCEL منذ الآن، حتّى يُضاف المسترجِع والذاكرة والأدوات دون تعديل جوهريّ لاحقًا:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
modele = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tpl = ChatPromptTemplate.from_messages([
("system", "أنت مساعد إدارة نفقات. أجب بإيجاز."),
("human", "{sujet}"),
])
chaine = tpl | modele | StrOutputParser()
print(chaine.invoke({"sujet": "استرداد 47 يورو من عشاء عمل بتاريخ 3 مارس؟"}))
ستضيف الوحدة الثانية محلّلات مخرجات مُنَظَّمة، والثالثة تركيب سلاسل موازية، والرابعة تحميل المستندات… وستبقى بنية tpl | modele | ... قائمة إلى النهاية.
اسأل نفسك قبل جلب أيّ تجريد: «ما الذي سيتغيّر بعد ثلاثة أشهر؟». إن كانت الإجابة «لا شيء»، الإطار يُثقلك. إن كانت «المزوّد، أو الأدوات، أو مصادر البيانات، أو التركيب»، الإطار يوفّر عليك أسابيع.
الخلاصة
- LangChain يُقدّم تجريدًا للمزوّدين، وتركيبًا قابلًا للتشغيل، ونظامًا بيئيًّا واسعًا، ولا شيء غير ذلك.
- التجريد ليس مجّانيًّا: تأخير، ذاكرة، أخطاء أعمق في المكدّس، إطار يتغيّر بسرعة.
- يُكتَب النداء يدويًّا حين لا شيء يتغيّر؛ ويُستعمَل LCEL حين نتوقّع تطوّرًا؛ ويُستعمَل LangGraph لوكلاء لهم حلقات تحكّم.
- سنعتمد بنية
prompt | model | parserمنذ الوحدة الأولى لأنّ التوسّع لاحقًا يصير تركيبًا لا إعادة كتابة.