יצירת Agent ראשון

ארכיטקטורת Model + Harness ב-LangChain

createAgent, הפונקציה המרכזית ב-LangChain, מקבלת שני מרכיבים עיקריים: model — איזה מודל שפה מפעיל את ה-agent, ו-harness — כל מה שעוטף אותו: system prompt (הוראות), tools (כלים זמינים), ו-middleware (הרחבות שמתערבות בלולאה, כמו guardrails או ניהול context).

המבנה הזה שקוף בכוונה: אין "קסם" שמסתתר מאחורי הקריאה — כל agent הוא בפשטות מודל שקורא לכלים בלולאה עד שהמשימה מסתיימת, בדיוק כמו הלולאה האגנטית שהוגדרה בנושא AI Agents.

התקנה והגדרה בסיסית

כדי להתחיל צריך את חבילת ה-npm הראשית ומפתח API לספק מודל שבחרתם (למשל Anthropic או OpenAI), שנטען בדרך כלל ממשתנה סביבה.

bash
npm install langchain

# .env
ANTHROPIC_API_KEY=sk-...

יצירת Agent עם createAgent

הדוגמה הבאה יוצרת agent פשוט עם כלי אחד שמחזיר מזג אוויר: מגדירים את הכלי עם tool ו-schema של zod לאימות הפרמטרים, ואז מעבירים אותו יחד עם המודל וה-system prompt ל-createAgent.

TypeScript
import { createAgent, tool } from "langchain";
import { z } from "zod";

const getWeather = tool(
  async ({ city }: { city: string }) => `${city}: שמש, 22 מעלות`,
  {
    name: "get_weather",
    description: "מחזיר את מזג האוויר הנוכחי בעיר נתונה",
    schema: z.object({ city: z.string() }),
  }
);

const agent = createAgent({
  model: "anthropic:claude-sonnet-5",
  tools: [getWeather],
  systemPrompt: "אתה עוזר שמדווח על מזג אוויר בקצרה ובעברית.",
});

הרצת Agent: invoke, היסטוריית הודעות ו-thread persistence

מריצים agent עם agent.invoke, ומעבירים מערך messages בדיוק כמו בקריאה ישירה ל-API של מודל שפה — ה-agent דואג בעצמו להריץ את לולאת ה-tool calling עד שיש תשובה סופית.

כדי לשמר היסטוריית שיחה בין קריאות (למשל בצ'אט רב-שלבי), מעבירים thread_id קבוע דרך configurable — LangChain שומר את ההיסטוריה משויכת ל-thread הזה, כך שבקריאה הבאה ה-agent "זוכר" מה נאמר קודם, בלי שתצטרכו לנהל את זה ידנית.

TypeScript
const result = await agent.invoke(
  { messages: [{ role: "user", content: "מה מזג האוויר בתל אביב?" }] },
  { configurable: { thread_id: "chat-1" } }
);

console.log(result.messages.at(-1)?.content);
// → "תל אביב: שמש, 22 מעלות"

דוגמה מלאה: שיחה רב-שלבית עם אותו agent

כשקוראים שוב ל-agent.invoke עם אותו thread_id, ה-agent רואה את כל ההודעות הקודמות בשיחה, ולכן יכול לענות על שאלת המשך בלי שנחזור ונציין את ההקשר במפורש.

זה בדיוק ה-thread persistence שהוזכר למעלה: ה-state (כל ה-messages) משויך ל-thread_id ברקע, כך שקוד הצריכה שלכם נשאר פשוט — אתם רק שולחים את ההודעה החדשה, לא את כל ההיסטוריה בכל פעם.

TypeScript
const followUp = await agent.invoke(
  { messages: [{ role: "user", content: "ומה לגבי מחר?" }] },
  { configurable: { thread_id: "chat-1" } }
);

console.log(followUp.messages.at(-1)?.content);

שאלות נפוצות

איפה בפועל נשמרת ההיסטוריה של thread_id?

כדי שההיסטוריה תישמר, ה-agent צריך מנגנון שמירה מוגדר (ב-LangGraph הוא נקרא checkpointer). שמירה בזיכרון התהליך מתאימה לפיתוח, אבל ההיסטוריה נעלמת כשהשרת עולה מחדש, ולכן ב-production מגדירים אחסון קבוע כמו בסיס נתונים. האופן המדויק להגדרה משתנה בין גרסאות, אז כדאי לבדוק בתיעוד הרשמי.

מה קורה אם שני משתמשים מקבלים את אותו thread_id?

הם חולקים את אותה היסטוריה, כלומר כל אחד מהם רואה את ההקשר של השני. thread_id צריך להיות ייחודי לכל שיחה, וכדאי לייצר אותו בשרת (למשל UUID שמשויך למשתמש המחובר) ולא לקבל אותו כמו שהוא מהלקוח, כדי שאף משתמש לא יוכל לנחש thread של מישהו אחר.

מה מונע מ-agent להיתקע בלולאה אינסופית של קריאות לכלים?

LangChain מגביל את מספר הצעדים בכל הרצה, וכשהמגבלה נחצית ההרצה נעצרת עם שגיאה. אפשר לשנות את המגבלה בהגדרות ההרצה (השם המדויק משתנה בין גרסאות — בדקו בתיעוד), וב-middleware (פרק 8) אפשר להוסיף מגבלות משלכם, למשל על מספר הקריאות לכלי מסוים.