Ollama: تكامل LangChain
LangChain هو مايسترو تنسيق تطبيقات الذكاء الاصطناعي — النماذج هي الممثلون، والسلاسل هي النصوص، والوكلاء هم المخرجون.
💡 نصيحة: جوهر LangChain هو البنية ثلاثية الطبقات وكيل/سلسلة/أداة — السلسلة هي خط أنابيب ثابت (موجه→نموذج لغوي كبير→محلل)، والأداة هي قدرة خارجية قابلة للاستدعاء (الاستعلام عن قاعدة بيانات، البحث في المستندات)، والوكيل هو صانع قرار مستقل يختار ديناميكيًا أي أدوات يستدعيها. 90% من السيناريوهات تخدمها السلاسل جيدًا؛ استخدم الوكلاء فقط عند الحاجة إلى اتخاذ القرارات الديناميكية.
📋 المتطلبات المسبقة: يجب أن تتقن أولاً ما يلي
- الدرس 5: أساسيات REST API
- الدرس 7: تكامل Python SDK
1. ما ستتعلمه
- إعدادات اتصال LangChain + Ollama
- قالب الموجه + سلسلة لهندسة الموجهات المترابطة
- محلل الإخراج للإخراج المنظم
- وكيل استدعاء الأدوات
- وكيل تحليل مقاييس SaaS الخاص بـ Alice
2. قصة حقيقية من مدير تقنية شركة ناشئة
(1) المشكلة: التحليل اليدوي لـ 50 تقرير مؤشرات كل شهر
تتابع شركة Alice SaaS 50 مؤشرًا تجاريًا، وتتطلب تحليل الاتجاهات وكتابة التقارير يدويًا كل شهر. يقضي أحد المحللين 3 أيام لإكمال العمل، وغالبًا ما تُفقد إشارات الشذوذ المهمة.
(2) الحل: وكيل LangChain للتحليل الآلي
استخدام LangChain + Ollama لبناء وكيل ذكاء اصطناعي يقرأ بيانات المؤشرات تلقائيًا ويحدد الشذوذ ويُنشئ تقارير التحليل:
PYTHON
from langchain_ollama import ChatOllama
llm = ChatOllama(model="qwen2.5", temperature=0.2)
result = llm.invoke("Analyze the 20% drop in MRR last month")
3. اتصال LangChain + Ollama
💡 نصيحة: المعامل
base_url في ChatOllama يكون افتراضيًا http://localhost:11434. إذا كان Ollama مُنشرًا على مضيف آخر أو في حاوية دوكر، يجب تعيين base_url="http://ollama:11434" أو العنوان المقابل صراحةً.
(1) التثبيت والتهيئة
BASH
pip install langchain langchain-ollama langchain-community
(2) مكونان أساسيان
| المكون | الصنف | الغرض |
|---|---|---|
| نموذج المحادثة | ChatOllama | توليد المحادثات |
| التضمينات | OllamaEmbeddings | تحويل النص إلى متجهات |
flowchart TD
A[تطبيق LangChain] --> B[ChatOllama<br/>qwen2.5 / llama3.2]
A --> C[OllamaEmbeddings<br/>nomic-embed-text]
B --> D[خادم Ollama<br/>localhost:11434]
C --> D
| معامل ChatOllama | النوع | الافتراضي | الوصف |
|---|---|---|---|
| model | str | — | اسم النموذج |
| temperature | float | 0.8 | العشوائية |
| base_url | str | http://localhost:11434 | عنوان الخادم |
| num_ctx | int | 2048 | نافذة السياق |
(1) ▶ مثال: استدعاء ChatOllama الأساسي
PYTHON
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, SystemMessage
# Initialize ChatOllama
llm = ChatOllama(model="qwen2.5", temperature=0.3)
# Simple invocation
response = llm.invoke("What is RAG?")
print(response.content)
# With system message
response = llm.invoke([
SystemMessage(content="You are a data analyst. Be concise."),
HumanMessage(content="What causes MRR to drop?")
])
print(response.content)
الإخراج:
TEXT
# Execution successful
4. قالب الموجه + سلسلة
(1) هندسة الموجهات المترابطة
تجعل قوالب الموجهات الموجهات قابلة للمعاملات وقابلة لإعادة الاستخدام وقابلة للتكوين:
flowchart LR
A[متغيرات الإدخال] --> B[قالب الموجه]
B --> C[ChatOllama]
C --> D[محلل الإخراج]
D --> E[نتيجة منظمة]
| نوع السلسلة | الوصف | حالة الاستخدام |
|---|---|---|
| LLMChain | موجه → نموذج لغوي كبير → إخراج | استنتاج خطوة واحدة |
| SequentialChain | سلاسل متعددة بالتسلسل | تحليل متعدد الخطوات |
| RouterChain | توجيه بناءً على الإدخال | معالجة التفرع |
(2) ▶ مثال: قالب الموجه + سلسلة
PYTHON
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOllama(model="qwen2.5", temperature=0.3)
# Define prompt template
prompt = ChatPromptTemplate.from_messages([
("system", "You are a {role}. Be concise and professional."),
("human", "{input}")
])
# Build chain: prompt -> llm -> parser
chain = prompt | llm | StrOutputParser()
# Invoke with variables
result = chain.invoke({
"role": "customer service agent for e-commerce",
"input": "Customer wants to cancel order #12345"
})
print(result)
الإخراج:
TEXT
# Execution successful
5. محلل الإخراج للإخراج المنظم
⚠️ تحذير: النماذج الصغيرة (أقل من 3 مليارات معامل) تُنشئ هياكل JSON غير مستقرة، مما يتسبب في فشل تحليل
PydanticOutputParser. استخدم نموذج 8 مليارات+ مع format="json"، وأضف منطق إعادة المحاولة try/except في الكود.
(1) محللات الإخراج الشائعة
| المحلل | الغرض | تنسيق الإخراج |
|---|---|---|
| StrOutputParser | نص عادي | سلسلة |
| JsonOutputParser | كائن JSON | قاموس |
| PydanticOutputParser | نموذج Pydantic | كائن منظم |
| CommaSeparatedListOutputParser | قائمة مفصولة بفواصل | list[str] |
(2) مقارنة الإخراج المنظم بـ Pydantic
| الطريقة | المزايا | العيوب |
|---|---|---|
| format=json | بسيط | بدون التحقق من النوع |
| JsonOutputParser | لديه تلميحات المخطط | التحليل قد يفشل |
| PydanticOutputParser | تحقق كامل من النوع | يعتمد على التزام النموذج بالمخطط |
(3) ▶ مثال: الإخراج المنظم بـ Pydantic
PYTHON
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
# Define output schema
class CustomerIntent(BaseModel):
intent: str = Field(description="Customer intent category")
confidence: float = Field(description="Confidence score 0-1")
order_number: str | None = Field(description="Order number if mentioned")
# Create parser
parser = PydanticOutputParser(pydantic_object=CustomerIntent)
# Build chain with format instructions
llm = ChatOllama(model="qwen2.5", temperature=0.1, format="json")
prompt = ChatPromptTemplate.from_messages([
("system", "Classify the customer intent.\n{format_instructions}"),
("human", "{query}")
])
chain = prompt | llm | parser
# Invoke
result = chain.invoke({
"query": "I want to track my order #88765",
"format_instructions": parser.get_format_instructions()
})
print(f"Intent: {result.intent}")
print(f"Confidence: {result.confidence}")
print(f"Order: {result.order_number}")
الإخراج:
TEXT
# Execution successful
6. وكيل استدعاء الأدوات
⚠️ ملاحظة: قد ينتج الوكلاء إخراجًا غير مستقر — يمكن أن تؤدي حلقات استنتاج النماذج المحلية إلى "حلقات لا نهائية" (استدعاء نفس الأداة بشكل متكرر) أو "استدعاءات أدوات وهمية" (استدعاء أدوات غير موجودة). عيّن دائمًا
max_iterations=3-5 لتحديد عدد الحلقات، واستخدم temperature=0 لزيادة الحتمية. النماذج ذات 3 مليارات لديها قدرات وكيل محدودة؛ يُوصى بـ 8 مليارات+.
💡 نصيحة: قدرة استدعاء الدوال Function Calling في النماذج المحلية لـ Ollama ليست مستقرة مثل GPT-4. يُوصى باستخدام نمط وكيل ReAct + مزين
@tool بدلاً من استدعاء الدوال الأصلي لتحقيق توافق أفضل، ويمكن لـ temperature=0 تحسين حتمية استدعاء الأدوات.
(1) بنية الوكيل
flowchart TD
A[إدخال المستخدم] --> B[الوكيل]
B --> C{هل يحتاج أداة؟}
C -->|نعم| D[استدعاء أداة]
D --> E[نتيجة الأداة]
E --> B
C -->|لا| F[الإجابة النهائية]
| نوع الوكيل | الوصف | حالة الاستخدام |
|---|---|---|
| وكيل ReAct | حلقة استنتاج + إجراء | مهام معقدة تتطلب استدعاء أدوات |
| محادثة منظمة | استدعاء أدوات منظمة | أدوات متعددة، معاملات متعددة |
| دوال OpenAI | وضع استدعاء الدوال | مدعوم جزئيًا من Ollama |
(2) أنماط تعريف الأدوات
| طريقة التعريف | الوصف | مثال |
|---|---|---|
| مزين @tool | أداة بسيطة | @tool def func(...) |
| StructuredTool | أداة مع وصف | StructuredTool.from_function(...) |
| Pydantic + BaseTool | أداة منشأة بقوة | class MyTool(BaseTool) |
(4) ▶ مثال: وكيل ReAct في الممارسة
PYTHON
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
# Define tools
@tool
def get_order_status(order_id: str) -> str:
"""Get the status of an order by its ID."""
# Simulated database lookup
orders = {
"12345": "Shipped, arriving in 2 days",
"88765": "Processing, shipping tomorrow",
"99999": "Delivered on 2024-01-15"
}
return orders.get(order_id, f"Order {order_id} not found")
@tool
def check_product_stock(product_name: str) -> str:
"""Check if a product is in stock."""
stock = {
"wireless headphones": "In stock: 45 units",
"laptop stand": "Out of stock, restock in 3 days",
"usb cable": "In stock: 200 units"
}
return stock.get(product_name.lower(), f"Product '{product_name}' not found")
# Build agent
llm = ChatOllama(model="qwen2.5", temperature=0)
tools = [get_order_status, check_product_stock]
prompt = PromptTemplate.from_template(
"""Answer the following question. You have access to these tools:
{tools}
Use this format:
Question: the input question
Thought: what to do
Action: tool name (one of [{tool_names}])
Action Input: tool input
Observation: tool output
... (repeat Thought/Action/Action Input/Observation)
Thought: I know the final answer
Final Answer: the final answer
Question: {input}
{agent_scratchpad}"""
)
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Run agent
result = agent_executor.invoke({
"input": "What is the status of order 88765?"
})
print(result["output"])
الإخراج:
TEXT
# Function defined successfully
7. مثال شامل: وكيل تحليل مقاييس SaaS الخاص بـ Alice
ℹ️ معلومة: القيمة الافتراضية لـ
max_iterations في AgentExecutor الخاص بـ LangChain هي 15، لكن النماذج المحلية تستنتج ببطء أكبر. تعيينها إلى 3-5 يمنع الحلقات اللانهائية. أيضًا عيّن verbose=True لمراقبة عملية استنتاج الوكيل.
PYTHON
# ============================================
# Comprehensive: SaaS metrics analysis agent
# Uses LangChain + Ollama for automated analysis
# ============================================
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
import json
# Simulated metrics database
METRICS_DB = {
"mrr": {"current": 85000, "previous": 106250, "change": -20},
"churn_rate": {"current": 8.5, "previous": 5.2, "change": 63},
"arr": {"current": 1020000, "previous": 1275000, "change": -20},
"active_users": {"current": 12500, "previous": 11800, "change": 6},
"cac": {"current": 250, "previous": 180, "change": 39},
"ltv": {"current": 2400, "previous": 3200, "change": -25}
}
@tool
def get_metric(metric_name: str) -> str:
"""Get a SaaS metric value. Available: mrr, churn_rate, arr, active_users, cac, ltv."""
data = METRICS_DB.get(metric_name.lower())
if data:
return json.dumps(data)
return f"Metric '{metric_name}' not found. Available: {list(METRICS_DB.keys())}"
@tool
def compare_metrics(metric1: str, metric2: str) -> str:
"""Compare two metrics and identify correlations."""
m1 = METRICS_DB.get(metric1.lower())
m2 = METRICS_DB.get(metric2.lower())
if not m1 or not m2:
return "One or both metrics not found."
return json.dumps({
"metric1": {"name": metric1, **m1},
"metric2": {"name": metric2, **m2},
"correlation_note": "Both metrics show negative trends"
})
# Build analysis agent
llm = ChatOllama(model="qwen2.5", temperature=0.2)
tools = [get_metric, compare_metrics]
prompt = PromptTemplate.from_template(
"""You are a SaaS metrics analyst. Analyze data and provide insights.
Available tools: {tools}
Format:
Question: the input
Thought: what to do
Action: tool name from [{tool_names}]
Action Input: tool input
Observation: tool output
... (repeat as needed)
Thought: I have enough information
Final Answer: detailed analysis with actionable recommendations
Question: {input}
{agent_scratchpad}"""
)
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=5)
# Run analysis
if __name__ == "__main__":
result = executor.invoke({
"input": "MRR dropped 20% last month. Analyze the key metrics and identify likely causes with recommendations."
})
print("\n=== Analysis Report ===")
print(result["output"])
❓ أسئلة شائعة
س ما الفرق بين langchain-ollama وlangchain-community؟
ج
langchain-ollama هو حزمة تكامل Ollama الرسمية، وتحتوي على ChatOllama وOllamaEmbeddings. langchain-community يتضمن أيضًا تكاملات قديمة، لكن يُوصى بالحزمة الرسمية.س ماذا أفعل إذا كانت استدعاءات أدوات الوكيل غير مستقرة؟
ج اخفض temperature إلى 0، وتأكد من أن أوصاف الأدوات واضحة، واستخدم format=json لفرض الإخراج المنظم. النماذج الصغيرة (3 مليارات) لديها قدرات وكيل محدودة؛ يُوصى بـ 8 مليارات+.
س كيف أختار بين سلاسل LangChain والوكلاء؟
ج استخدم السلاسل لسير العمل الثابت (موجه → نموذج لغوي كبير → محلل)، والوكلاء لاتخاذ القرارات الديناميكية (اختيار الأدوات والخطوات بشكل مستقل). السلاسل تكفي لـ 90% من السيناريوهات.
س ماذا أفعل إذا فشل تحليل PydanticOutputParser؟
ج أضف
format="json" لفرض إخراج JSON. أضف تعليمات تنسيق صريحة في الموجه. ارجع إلى JsonOutputParser عند الفشل.س هل تدعم نماذج Ollama استدعاء الدوال Function Calling؟
ج جزئيًا. qwen2.5 وllama3.1 لديهما بعض قدرات Function Calling، لكنها ليست مستقرة مثل GPT-4. يُوصى باستخدام وكيل ReAct + مزين @tool كبديل.
س كيف يمكنني تصحيح أخطاء عملية استنتاج الوكيل؟
ج عيّن
verbose=True لعرض حلقة Thought/Action/Observation للوكيل. يمكن لـ LangSmith (tracelangchain.com) تصور سلسلة التنفيذ الكاملة.📖 ملخص
- ChatOllama هو الصنف الأساسي لربط LangChain بـ Ollama، ويدعم المحادثة والإخراج المتدفق
- قوالب الموجهات تجعل الموجهات قابلة للمعاملات؛ السلاسل تجعل سير العمل قابلًا للتكوين
- محللات الإخراج تحول نص النموذج اللغوي الكبير إلى بيانات منظمة (JSON/Pydantic/List)
- وكلاء ReAct ينفذون حلقة استنتاج + إجراء يمكنها استدعاء أدوات مخصصة
- استخدمت Alice وكيل LangChain لأتمتة تحليل مقاييس SaaS، مما قلل 3 أيام عمل إلى 3 دقائق
- الوكلاء يتطلبون نماذج 8 مليارات+ للاستقرار؛ النماذج ذات 3 مليارات تفتقر إلى قدرة استنتاج كافية
📝 تمارين
- أساسي (⭐): ابنِ سلسلة مع ChatOllama + قالب الموجه لتنفيذ تصنيف نية خدمة العملاء (الإخراج بتنسيق JSON).
- متوسط (⭐⭐): أنشئ وكيل ReAct مع أداتين (الاستعلام عن الطلب + التحقق من المخزون)، واختبر استدعاء الأدوات بـ 3 أسئلة مختلفة.
- متقدم (⭐⭐⭐): ابنِ وكيل تحليل مقاييس SaaS لـ Alice — يتضمن 4 أدوات على الأقل (الحصول على مؤشر، مقارنة المؤشرات، توليد وصف الرسم البياني، إرسال تنبيه)، مع إخراج تقرير تحليل منظم.