ברוכים הבאים לתרגול מעשי זה, שבו נלמד את השלבים הבסיסיים של עבודה עם LangChain, אחת הספריות הפופולריות והחזקות ביותר לבניית אפליקציות מבוססות מודלי שפה (LLMs).
במהלך התרגול, אנו נלמד כיצד:
- להתחבר למודל שפה גדול (LLM) באמצעות חיבור ל-OpenAI.
- לבצע קריאה בסיסית למודל באמצעות הפקודה
.invoke(). - לשרשר יחד מספר שלבי עיבוד (פרומפט + מודל) באמצעות LCEL.
- לבנות סוכן (Agent) אינטראקטיבי המשתמש בכלים (Tools) ושומר על זיכרון (Memory).
בסוף התרגול, תהיה לכם הבנה מוצקה כיצד LangChain מאפשר בנייה מודולרית ומובנית של אינטראקציות מורכבות עם מודלי שפה.
שימו לב – תרגול זה מובנה מאוד והוא מהווה בסיס למחקר וללימוד דרך ״לכלוך הידיים״ בהמשך הדרך. חשוב להכיר את החלקים השונים בתרגול ובמערכת. עם זאת – בכל פרק וסעיף, הרגישו חופשי לחקור יותר לעומק ולסקור גם מושגים שונים ואפשרויות שונות שלא הוזכרו במפורש. נתקעתם? לא נורא – חזרו להוראות המקוריות, ותמיד אפשר להתחיל פרויקט חדש ונקי, ולהתנסות מראש הפרק הנוכחי.
בהצלחה!
1. התקנה והגדרות סביבה
בפרק זה נתקין את כל הספריות הנדרשות ונכין את קובצי התצורה של הפרויקט. ניצור קובץ פייתון אחד ונוסיף לו את כל המקטעים.
הכנה: יצירת סביבה וירטואלית
- פתחו טרמינל בתיקיית הפרויקט והקימו סביבת venv חדשה:
python3 -m venv .venv - הפעילו אותה (ב-Mac/Linux):
source .venv/bin/activate(ב-Windows):
.venv\Scripts\activate
-
התקנת ספריות LangChain
- כעת, כשהסביבה פעילה, התקינו את כל הספריות הנדרשות לפרויקט זה. אנו מתקינים את הספריות הראשיות של LangChain, את החיבור ל-OpenAI, ואת הכלים הנוספים שנשתמש בהם (langchainhub ו-duckduckgo):
pip install langchain langchain-openai python-dotenv langchainhub duckduckgo-search
- כעת, כשהסביבה פעילה, התקינו את כל הספריות הנדרשות לפרויקט זה. אנו מתקינים את הספריות הראשיות של LangChain, את החיבור ל-OpenAI, ואת הכלים הנוספים שנשתמש בהם (langchainhub ו-duckduckgo):
-
הגדרת מפתח API (קובץ
.env)
- צרו קובץ חדש בתיקייה הראשית של הפרויקט בשם .env (שימו לב לנקודה בהתחלה).
- פתחו את הקובץ והוסיפו שורה אחת עם מפתח ה-API שלכם מ-OpenAI:
OPENAI_API_KEY=sk-YourSecretKeyGoesHere
-
טעינת המשתנים בקוד
- צרו קובץ פייתון ראשי (לדוגמה,
main.py) והוסיפו את הקוד הבא בראש הקובץ. קוד זה טוען את משתני הסביבה מהקובץ שיצרנו:from dotenv import load_dotenv import os # load .env file into environment vars load_dotenv() # api key check api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise ValueError("OPENAI_API_KEY not found in .env file") print("OpenAI API Key loaded successfully.")
- צרו קובץ פייתון ראשי (לדוגמה,
2. הקריאה הפשוטה ביותר – .invoke()
הדרך הבסיסית ביותר "לדבר" עם מודל שפה היא באמצעות קריאת .invoke(). אנו פשוט שולחים טקסט ומקבלים טקסט בחזרה.
-
יצירת מודל וקריאה ראשונה
- הוסיפו את הקוד הבא לקובץ ה-Python שלכם. קוד זה מייבא את ChatOpenAI (החיבור המומלץ למודלי צ'אט), מאתחל אותו, ושולח לו שאלה פשוטה:
from langchain_openai import ChatOpenAI # 1. we'll use OpenAI model gpt-4o for this # temperature 0.7 - for some creativity llm = ChatOpenAI(model="gpt-4o", temperature=0.7) print("Sending 'invoke' request to LLM...") # 2. sending the request to the model response = llm.invoke("What is the capital of France") # 3. response printout print("\n--- LLM Response ---") print(response.content) print("--------------------") - הריצו את הקובץ וצפו בתשובה המתקבלת ישירות מהמודל.
- הוסיפו את הקוד הבא לקובץ ה-Python שלכם. קוד זה מייבא את ChatOpenAI (החיבור המומלץ למודלי צ'אט), מאתחל אותו, ושולח לו שאלה פשוטה:
3. בניית שרשרת פשוטה (LCEL)
הכוח האמיתי של LangChain טמון ב-LCEL (LangChain Expression Language), המאפשר לנו לשרשר רכיבים יחד באמצעות האופרטור | (pipe). השרשרת הפשוטה ביותר היא חיבור של תבנית פרומפט (Prompt Template) למודל עצמו.
-
שרשור פרומפט ומודל
- הוסיפו את הקוד הבא. אנו יוצרים תבנית פרומפט שמקבלת משתנה
{topic}, משרשרים אותה למודל, ואז מפעילים את השרשרת עם נושא לבחירתנו:from langchain_core.prompts import ChatPromptTemplate # 1. creating dynamic prompt template # the template defines a system-prompt (system) and a user-prompt (user) prompt_template = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant who is an expert on geography."), ("user", "Tell me a short fun fact about {topic}.") ]) # 2. constructing the Chain # chaining the input template to the processing LLM chain = prompt_template | llm print("Sending 'invoke' request to the Chain...") # 3. invoking the chain with the {topic} argument response_from_chain = chain.invoke({"topic": "Japan"}) print("\n--- Chain Response ---") print(response_from_chain.content) print("----------------------") - שימו לב כיצד הפעם לא היינו צריכים לכתוב את הפרומפט המלא בעצמנו, אלא רק סיפקנו את הנתונים המשתנים (במקרה זה, "Japan").
- הוסיפו את הקוד הבא. אנו יוצרים תבנית פרומפט שמקבלת משתנה
4. בניית סוכן (Agent) עם כלים וזיכרון
סוכן הוא מודל שפה שקיבל "כוחות-על": היכולת להשתמש בכלים חיצוניים (כמו חיפוש באינטרנט, הפעלת קוד, או קריאה ל-API) כדי לענות על שאלות.
-
הגדרת כלי (Tool)
- הוסיפו את הקוד הבא. אנו משתמשים ב-Decorator
@toolכדי להפוך פונקציית פייתון פשוטה לכלי שהסוכן יוכל להשתמש בו. במקרה זה, כלי לבדיקת מזג אוויר (מדומה):from langchain.tools import tool @tool def get_weather(city: str) -> str: """ Use this tool to get the current weather for a specific city. Returns a simple weather report as a string. """ print(f"--- ⚠️ Tool 'get_weather' called for {city} ---") # This is a mock function. In a real scenario, this would call a weather API. if "tel aviv" in city.lower(): return "The weather in Tel Aviv is sunny and 28 degrees." elif "london" in city.lower(): return "The weather in London is rainy and 12 degrees." else: return f"Sorry, I don't have weather data for {city}." # creating a list of tools for the agent tools = [get_weather] - חשוב: ה-Docstring (הטקסט בתוך המרכאות המשולשות) הוא קריטי. LangChain משתמש בו כדי להסביר ל-LLM מתי וכיצד להשתמש בכלי הזה.
- הוסיפו את הקוד הבא. אנו משתמשים ב-Decorator
-
יצירת הסוכן (Agent)
- כעת נרכיב את הסוכן. אנו צריכים "למשוך" פרומפט מוכן מראש מ-LangChain Hub (שמכיל הנחיות כיצד להשתמש בכלים) וליצור את הסוכן:
from langchain import hub from langchain.agents import create_openai_tools_agent # 1. pull a prompt from the hub # this prompt contains instructions for the different tools agent_prompt = hub.pull("hwchase17/openai-tools-agent") # 2. creating the agent itself # we provide the model, the toolset and the prompt agent = create_openai_tools_agent(llm, tools, agent_prompt)
- כעת נרכיב את הסוכן. אנו צריכים "למשוך" פרומפט מוכן מראש מ-LangChain Hub (שמכיל הנחיות כיצד להשתמש בכלים) וליצור את הסוכן:
-
יצירת ה-Agent Executor
- הסוכן (agent) הוא ה"מוח" שמחליט מה לעשות. ה-Executor הוא ה"פועל" שמריץ את ההחלטות האלה.
from langchain.agents import AgentExecutor # The Executor takes the agent and the tools and manages the conversation loop agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # Initial Executor test print("Testing Agent Executor...") test_response = agent_executor.invoke({"input": "What is the weather in Tel Aviv?"}) print(test_response) - אם תריצו כעת, תראו בפלט ה-
verboseאת "מחשבות" הסוכן: הוא יזהה שצריך להשתמש בכלי, יפעיל אתget_weather, יקבל את התוצאה, ואז ינסח תשובה סופית.
- הסוכן (agent) הוא ה"מוח" שמחליט מה לעשות. ה-Executor הוא ה"פועל" שמריץ את ההחלטות האלה.
-
הוספת זיכרון (Memory)
- כרגע, הסוכן לא זוכר שאלות קודמות. נוסיף לו זיכרון:
from langchain.memory import ConversationBufferMemory from langchain_core.messages import AIMessage, HumanMessage from langchain.agents.format_scratchpad.openai_tools import ( format_to_openai_tool_messages, ) from langchain.agents.output_parsers.openai_tools import ( OpenAIToolsAgentOutputParser, ) from langchain.prompts import MessagesPlaceholder # 1. create the memory object memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) # 2. update the prompt with a room for the memory # (this is not defined by default) agent_prompt_with_memory = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), MessagesPlaceholder(variable_name="chat_history"), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]) # 3. reconstructing the agent with the memory component agent_with_memory = create_openai_tools_agent( llm, tools, agent_prompt_with_memory ) # 4. reconstructing the Executor with the memory agent_executor_with_memory = AgentExecutor( agent=agent_with_memory, tools=tools, verbose=True, memory=memory # adding memory )
- כרגע, הסוכן לא זוכר שאלות קודמות. נוסיף לו זיכרון:
5. הפעלת הסוכן האינטראקטיבי
כעת, כשיש לנו סוכן שמסוגל להשתמש בכלים ולזכור שיחות, ניצור לולאת צ'אט אינטראקטיבית כדי שנוכל לדבר איתו.
-
לולאת שיחה אינטראקטיבית
- הוסיפו את הקוד הבא לסוף הקובץ. זוהי לולאת
whileפשוטה שממתינה לקלט מהמשתמש ומפעילה את הסוכן:print("\n--- Starting Interactive Chat Loop ---") print("Type 'exit' to exit.") while True: try: user_input = input("\nYou: ") if "exit" in user_input.lower(): print("\nAgent: bye!") break # running the agent with the input # the Executor automatically handles the memory response = agent_executor_with_memory.invoke({ "input": user_input }) print(f"\nAgent: {response['output']}") except Exception as e: print(f"An error occurred: {e}") break - הפעילו את הקובץ המלא!
- נסו לשאול: "מה מזג האוויר בלונדון?"
- לאחר מכן, נסו לשאול: "ומה בירת אנגליה?" (הוא אמור לדעת שדיברתם על לונדון).
- נסו לשאול: "ומה לגבי תל אביב?" (הוא אמור להפעיל שוב את הכלי).
- הוסיפו את הקוד הבא לסוף הקובץ. זוהי לולאת
6. תרגול פתוח
הבסיס קיים! כעת נסו "לשבור" או לשפר את הסוכן:
-
הוספת כלי חיפוש: הוסיפו כלי שני המשתמש ב-DuckDuckGo כדי לענות על שאלות כלליות שהכלי של מזג האוויר לא מכסה.
from langchain_community.tools import DuckDuckGoSearchRun search_tool = DuckDuckGoSearchRun() # ...and then add 'search_tool' to the tools list - שיפור הפרומפט: שנו את ה-System Prompt (בתרגיל 4, שלב 2) כדי לתת לסוכן אישיות. לדוגמה: "אתה עוזר וירטואלי בשם 'בוטי', ואתה תמיד עונה בחרוזים."
- בדיקת זיכרון: נהלו שיחה ארוכה ונסו לבדוק עד כמה אחורה הוא זוכר פרטים שציינתם.
סיכום: בתרגול זה למדנו כיצד להתחבר ל-LLM באמצעות LangChain, לבצע קריאות פשוטות, לבנות שרשראות עיבוד (Chains) באמצעות LCEL, להגדיר ולהשתמש בכלים, ולבסוף, ליצור סוכן אינטראקטיבי השומר על זיכרון ומסוגל לנהל שיחה מתמשכת.