اتصال LangChain و LangGraph به OpenAI از ایران
آموزش گامبهگام اتصال LangChain و LangGraph به OpenAI از داخل ایران: ساخت RAG، tool agent، LangGraph حالتمند با کد Python آماده.
CONTENTS · در این مقاله (۲۱)
- مرور سریع: LangChain در برابر LangGraph
- پیشنیازها
- نصب پکیجها
- گام ۱: سادهترین chain ممکن
- گام ۲: ساخت یک سیستم RAG واقعی
- گام ۳: اولین Tool Agent با LangChain
- گام ۴: ورود به دنیای LangGraph
- مثال: agent برنامهریز سفر
- گام ۵: Streaming برای UX بهتر
- گام ۶: Memory و persistence
- چند الگوی پیشرفته که در پروژههای واقعی استفاده میشوند
- ۱. Self-correcting RAG
- ۲. Multi-agent با LangGraph
- ۳. Human-in-the-loop
- ۴. Structured output
- عیبیابی: مشکلات رایج کاربر ایرانی
- خطای Connection Error
- خطای Authentication
- خطای ۴۲۹ Rate Limit
- کنترل هزینه در پروژههای LangChain
- جمعبندی
اگر در دنیای ساخت اپلیکیشن LLM فعال باشی، بدون شک با LangChain برخورد کردهای. این فریمورک پایتونی (که نسخهٔ JavaScript هم دارد) در دو سال گذشته به استاندارد دفاکتو برای ساخت RAG، agent، tool use و chainهای پیچیده تبدیل شده است. LangGraph، خواهر کوچکتر LangChain، به تو اجازه میدهد graphهای حالتمند بسازی — یعنی agentهایی که در طول مکالمه حافظه و وضعیت دارند. هر دو پروژه بهطور پیشفرض به api.openai.com وصل میشوند که از ایران در دسترس نیست. خبر خوب: بهخاطر پشتیبانی استاندارد LangChain از base_url، اتصال به یک پروکسی OpenAI-compatible مثل 1xAi دو خط کد بیشتر نیست. این مقاله گامبهگام نشان میدهد چطور هم برای شروع، هم برای پروژههای production این کار را انجام دهی.
مرور سریع: LangChain در برابر LangGraph
| LangChain | LangGraph | |
|---|---|---|
| تمرکز اصلی | chain خطی، RAG، tool use | workflow حالتمند، multi-agent |
| ساختار | زنجیره (chain) + LCEL | گراف جهتدار با node و edge |
| کنترل جریان | محدود به sequence | کامل (شرط، حلقه، parallel) |
| State | محدود (memory objects) | first-class |
| کاربرد ایدهآل | چت ساده، خلاصهسازی، Q&A | agent پیچیده، human-in-the-loop |
قاعدهٔ سرانگشتی: اگر workflow تو خطی است، LangChain کافی است. اگر نیاز داری branch بگیری، loop داشته باشی، یا در میانه از کاربر سؤال بپرسی، به LangGraph برو.
پیشنیازها
- پایتون ۳.۹ یا بالاتر.
- یک کلید 1xAi (یا هر پروکسی OpenAI-compatible دیگر). اگر هنوز نداری، در صفحهٔ ثبتنام چند دقیقهای ساخته میشود.
- حداقل ۱۰۰ هزار تومان شارژ.
اگر هنوز با مفهوم پروکسی API آشنا نیستی، اول مقالهٔ دسترسی به ChatGPT از داخل ایران را بخوان.
نصب پکیجها
pip install langchain langchain-openai langgraph
pip install python-dotenv # برای مدیریت متغیرها
یک فایل .env بساز:
OPENAI_API_KEY=1xai-xxxxxxxxxxxxxxxxxxxxxxxx
OPENAI_BASE_URL=https://1xai.ir/v1
نکتهٔ مهم: LangChain از این متغیرهای محیطی بهصورت خودکار استفاده میکند. اما برای روشن بودن کد، توصیه میشود base_url را صریح در کد هم بدهی.
گام ۱: سادهترین chain ممکن
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
llm = ChatOpenAI(
model="gpt-5-mini",
base_url="https://1xai.ir/v1",
temperature=0.3
)
prompt = ChatPromptTemplate.from_messages([
("system", "تو دستیار خلاصهساز فارسی هستی. متن را در ۲ جمله خلاصه کن."),
("user", "{text}")
])
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"text": "متن طولانی فارسی شما اینجا..."
})
print(result)
چه اتفاقی افتاد؟ سه قطعه (prompt، llm، parser) با عملگر | به هم وصل شدند. این LCEL یا «LangChain Expression Language» است که جایگزین مدرن chainهای قدیمی شده.
گام ۲: ساخت یک سیستم RAG واقعی
RAG یعنی Retrieval-Augmented Generation: مدل بهجای تکیه بر دانش داخلی خودش، اول از یک پایگاه دانش جستوجو میکند و بعد پاسخ میدهد. سناریو: یک ربات Q&A برای مستندات یک محصول.
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# 1. Load و split
docs = TextLoader("docs.txt", encoding="utf-8").load()
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100
)
chunks = splitter.split_documents(docs)
# 2. Embedding با 1xAi
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small",
base_url="https://1xai.ir/v1"
)
# 3. ساخت vector store
db = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")
retriever = db.as_retriever(search_kwargs={"k": 4})
# 4. Prompt RAG
template = """بر اساس context زیر به سؤال پاسخ بده. اگر پاسخ در context نیست، صادقانه بگو نمیدانی.
Context:
{context}
سؤال: {question}
پاسخ به فارسی:"""
prompt = ChatPromptTemplate.from_template(template)
# 5. مدل پاسخ
llm = ChatOpenAI(model="gpt-5-mini", base_url="https://1xai.ir/v1")
# 6. RAG chain
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
print(rag_chain.invoke("چگونه میتوانم پسوردم را تغییر دهم؟"))
این الگو در عمل قدرتمند است. برای تخمین هزینهٔ embedding و query، به مقالهٔ هزینهٔ ChatGPT API رجوع کن.
گام ۳: اولین Tool Agent با LangChain
Tool agent یعنی LLM که میتواند به صورت خودکار function call بزند. مثال: یک agent که میتواند آبوهوا چک کند و قیمت ارز بپرسد.
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
@tool
def get_weather(city: str) -> str:
"""وضعیت آبوهوای شهر را برمیگرداند."""
# اینجا فراخوانی API واقعی میرود
return f"آبوهوای {city}: آفتابی، ۲۵ درجه"
@tool
def get_exchange_rate(currency: str) -> str:
"""قیمت ارز را به تومان برمیگرداند."""
rates = {"USD": 60000, "EUR": 65000, "AED": 16500}
return f"قیمت {currency}: {rates.get(currency, 'نامشخص')} تومان"
tools = [get_weather, get_exchange_rate]
llm = ChatOpenAI(
model="gpt-5-mini",
base_url="https://1xai.ir/v1"
)
prompt = ChatPromptTemplate.from_messages([
("system", "تو دستیار هستی. از ابزارها برای پاسخ استفاده کن."),
("user", "{input}"),
("placeholder", "{agent_scratchpad}")
])
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
executor.invoke({
"input": "هوای تهران چطوره؟ و قیمت دلار رو هم بگو."
})
وقتی این را اجرا میکنی، میبینی که agent خودش تصمیم میگیرد هر دو function را فراخوانی کند، نتیجه را ترکیب کند و یک پاسخ یکپارچه بدهد. این قدرت function calling در GPT است.
گام ۴: ورود به دنیای LangGraph
LangGraph وقتی شکوفا میشود که نیاز به state داری: مثلاً یک agent که چند مرحله را طی میکند، در میانه از کاربر تأیید میگیرد، و بر اساس پاسخ مسیرش را تغییر میدهد.
مثال: agent برنامهریز سفر
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
class TravelState(TypedDict):
messages: Annotated[list, add_messages]
destination: str
budget: int
plan: str
llm = ChatOpenAI(
model="gpt-5-mini",
base_url="https://1xai.ir/v1"
)
def gather_requirements(state: TravelState) -> TravelState:
response = llm.invoke([
*state["messages"],
HumanMessage(content="مقصد و بودجهٔ کاربر را از مکالمه استخراج کن. JSON با کلیدهای destination و budget برگردان.")
])
# parse و ذخیره (سادهسازی شده)
return {"messages": [response], "destination": "تهران", "budget": 10000000}
def create_plan(state: TravelState) -> TravelState:
prompt = f"یک برنامهٔ سفر سهروزه به {state['destination']} با بودجهٔ {state['budget']} تومان بنویس."
response = llm.invoke([HumanMessage(content=prompt)])
return {"messages": [response], "plan": response.content}
def needs_more_info(state: TravelState) -> str:
if not state.get("destination") or not state.get("budget"):
return "gather"
return "plan"
# ساخت گراف
workflow = StateGraph(TravelState)
workflow.add_node("gather", gather_requirements)
workflow.add_node("plan", create_plan)
workflow.set_entry_point("gather")
workflow.add_conditional_edges("gather", needs_more_info, {
"gather": "gather",
"plan": "plan"
})
workflow.add_edge("plan", END)
app = workflow.compile()
result = app.invoke({
"messages": [HumanMessage(content="میخوام برم اصفهان، ۱۵ میلیون تومن دارم.")]
})
print(result["plan"])
این یک مثال ساده است، اما الگو را نشان میدهد: nodeها functionهایی هستند که state را تغییر میدهند، و edgeها مسیر بعدی را تعیین میکنند. میتوانی شرط بگذاری، حلقه بسازی، یا چندین node را بهصورت parallel اجرا کنی.
گام ۵: Streaming برای UX بهتر
اگر میخواهی پاسخ را token-به-token به کاربر نشان دهی (مثل خود ChatGPT)، LangChain بهصورت native از streaming پشتیبانی میکند:
llm = ChatOpenAI(
model="gpt-5-mini",
base_url="https://1xai.ir/v1",
streaming=True
)
for chunk in llm.stream([HumanMessage(content="یک شعر فارسی دربارهٔ تهران بگو.")]):
print(chunk.content, end="", flush=True)
1xAi streaming را روی همهٔ مدلها پشتیبانی میکند. اگر در محصول production هستی، streaming تأخیر perceived (یعنی آنچه کاربر حس میکند) را بهشدت کاهش میدهد.
گام ۶: Memory و persistence
برای چتباتی که باید مکالمات قبلی را بهخاطر بسپارد، سادهترین راه استفاده از RunnableWithMessageHistory است:
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
def get_session_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chain_with_memory = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history"
)
config = {"configurable": {"session_id": "user-123"}}
print(chain_with_memory.invoke(
{"input": "اسم من علی است."},
config=config
))
print(chain_with_memory.invoke(
{"input": "اسم من چی بود؟"},
config=config
)) # «اسم شما علی است»
برای production، InMemory را با Redis یا Postgres جایگزین کن. LangChain برای هر دو implementation آماده دارد.
چند الگوی پیشرفته که در پروژههای واقعی استفاده میشوند
۱. Self-correcting RAG
یک agent که اگر بازیابی اول نتیجهٔ کافی نداد، query را بازنویسی میکند و دوباره جستوجو میکند. در LangGraph بهسادگی با یک loop قابل پیادهسازی است.
۲. Multi-agent با LangGraph
دو agent: یکی researcher که اطلاعات جمع میکند، یکی writer که محتوا مینویسد. supervisor agent تصمیم میگیرد کدام را فراخوانی کند. این الگو در ابزارهایی مثل CrewAI هم محبوب شده.
۳. Human-in-the-loop
LangGraph از interrupt پشتیبانی میکند: agent میتواند در میانهٔ کار صبر کند تا انسان تأیید بدهد. برای اپلیکیشنهایی که agent دارد ایمیل میفرستد یا پول خرج میکند حیاتی است.
۴. Structured output
برای گرفتن JSON ساختاریافته بهجای متن آزاد:
from pydantic import BaseModel, Field
class Movie(BaseModel):
title: str = Field(description="نام فیلم")
year: int = Field(description="سال ساخت")
rating: float = Field(description="امتیاز از ۱۰")
structured_llm = llm.with_structured_output(Movie)
result = structured_llm.invoke("اطلاعات فیلم Inception را بده.")
print(result.title, result.year, result.rating)
عیبیابی: مشکلات رایج کاربر ایرانی
خطای Connection Error
معمولاً به این معنا که base_url را تنظیم نکردهای و LangChain دارد به api.openai.com میزند. چک کن متغیر محیطی OPENAI_BASE_URL و یا پارامتر base_url در ChatOpenAI درست تنظیم شده باشد.
خطای Authentication
کلید با 1xai- شروع شده؟ پشت سر آن فاصله نیست؟ از داشبورد کلید جدید بساز و امتحان کن.
خطای ۴۲۹ Rate Limit
تعداد درخواست همزمان از سقف عبور کرده. در 1xAi میتوانی از فرم تماس سقف را افزایش دهی. در کد هم میتوانی از RetryPolicy استفاده کنی:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=1, max=10))
def safe_invoke(query: str) -> str:
return chain.invoke(query)
کنترل هزینه در پروژههای LangChain
LangChain یک callback آماده به نام get_openai_callback دارد که مصرف توکن و هزینهٔ تخمینی را گزارش میدهد:
from langchain_community.callbacks.manager import get_openai_callback
with get_openai_callback() as cb:
result = rag_chain.invoke("سؤال طولانی شما...")
print(f"Tokens: {cb.total_tokens}")
print(f"Cost (USD): ${cb.total_cost:.4f}")
print(f"Cost (Toman): {cb.total_cost * 60000:.0f}")
این را در logger خودت اضافه کن تا هزینهٔ هر فراخوانی را track کنی. در production میتوانی کاربری که از سقف بودجه گذشت را rate-limit کنی.
جمعبندی
LangChain و LangGraph در سال ۱۴۰۵ به ابزارهای استاندارد ساخت اپلیکیشن LLM تبدیل شدهاند. خوشبختانه به خاطر معماری انعطافپذیر این فریمورکها، اتصال آنها از داخل ایران از طریق پروکسی OpenAI-compatible مثل 1xAi در عمل به یک پارامتر base_url خلاصه میشود. هیچ تفاوتی در عملکرد، استریم، function call، یا structured output نیست. اگر تازه شروع کردهای، یک RAG ساده روی مستندات داخلی بساز و ببین چطور کار میکند. اگر قبلاً تجربه داری، LangGraph دنیای جدیدی از معماریهای agent باز میکند که با LangChain خالص قابل پیادهسازی نبود. برای ساخت workflowهای بدون-کد به جای کد، آموزش n8n را ببین، و برای انتخاب درست مدل، مقایسهٔ GPT-5، GPT-4o و GPT-4.1 راهنمای کاملی است.
ABOUT THE AUTHOR · نویسنده
تیم 1xAi
تیمِ 1xAi پروکسیِ تخصصیِ مدلهای OpenAI، Claude و Gemini برای کاربرانِ ایرانی را اداره میکند — از زیرساختِ شبکه تا صورتحسابِ تومانی. هرچه اینجا مینویسیم بر اساسِ تجربهٔ روزانه با APIهای OpenAI، Anthropic و Google و نیازهای واقعیِ توسعهدهندگانِ داخلِ ایران است.
۸ دقیقه
اتصال n8n به OpenAI از داخل ایران — راهنمای گامبهگام
آموزش کامل اتصال n8n به OpenAI از ایران بدون VPN: تنظیم Credential، ساخت AI Agent، خلاصهساز ایمیل، چتبات تلگرام و کنترل هزینه.
۸ دقیقه
تبدیل صوت فارسی به متن با Whisper — دقت، هزینه، آموزش
همه چیز دربارهٔ Whisper و gpt-4o-transcribe برای فارسی: دقت واقعی، هزینهٔ تومانی، کد آماده، رفع محدودیت ۲۵MB و ترفندهای افزایش دقت.
۸ دقیقه
هزینهٔ واقعی ChatGPT API چقدر است؟ محاسبه با تومان
محاسبهٔ دقیق هزینهٔ ChatGPT API به تومان: قیمت مدلهای GPT-5، GPT-4o، Whisper و DALL-E با چهار سناریوی واقعی و چهار راه کاهش هزینه.
