Главная / Статьи / Практические заметки: Ментальная модель LangGraph: руководство по стандартизированной архитектуре

Практические заметки: Ментальная модель LangGraph: руководство по стандартизированной архитектуре

Пошаговое руководство по использованию практических заметок: Ментальная модель LangGraph: руководство по стандартизированной архитектуре: контракты, проверки и готовые блоки кода для команд, использующих эту модель.

5383 слов

В следующих заметках описывается практический подход к изучению «LangGraph Mental Model: Руководство по стандартизированной архитектуре для любого агента, который вы когда-либо создадите». Основное внимание уделяется контрактам, проверкам и местам для вставки кода, а не мотивирующим аспектам. При изучении обзора сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой список поможет сохранять честность при последующих изменениях кода. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Если какой-то шаг не сработает, причина неудачи должна указывать на конкретную ответственность, а не на запутанную цепочку операций.

Введение: Почему код LangGraph кажется сложным, даже если сама концепция — нет

Введение: Почему код LangGraph кажется сложным, даже если сама концепция работает хорошо при рассмотрении её как измеримой поверхности. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма задачи. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия создаваемым элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задачи. Установите лимит токенов на каждый ход и на всю сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения предотвращают появление неожиданных счетов во время демонстраций.

Общая картина: четыре модуля, определённый порядок файлов

Общая картина: формат «Четыре модуля, один порядок файлов» работает наилучшим образом, если рассматривать его как измеримую структуру. Сначала соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объём работ. Записывайте время выполнения операций, а также стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе помогает избежать неожиданных счётов при переходе от демо-версии к общим средам. Определите лимит токенов на один ход и на одну сессию. Инструменты типа агентов активно расширяют объём обрабатываемой информации; жесткие ограничения предотвращают появление неожиданных счетов при демонстрации функций.

langgraph_agent.py
│
├── MODULE 1: IMPORTS & CONFIGURATION
│   └── All your libraries, API keys, model setup
│
├── MODULE 2: STATE
│   └── The TypedDict that defines your agent's memory
│
├── MODULE 3: TOOLS (optional, but common)
│   └── Functions decorated with @tool that the LLM can call
│
├── MODULE 4: NODES
│   └── Functions that do the actual work at each graph step
│
├── MODULE 5: EDGES & ROUTING
│   └── Functions that decide what happens next
│
├── MODULE 6: GRAPH ASSEMBLY
│   └── Where you build, wire, and compile the graph
│
└── MODULE 7: ENTRYPOINT
    └── The __main__ block or invoke() call that runs everything

Модуль 1: Импорт и настройка

Модуль 1: Импорт и настройка работают наилучшим образом, если рассматривать их как измеримые элементы. Соберите один эталонный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Храните настройки вне кода приложения. Файлы среды, хранилища конфиденциальных данных и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за раунд и сессию. Инструменты типа агентов активно расширяют контекст; жёсткие ограничения предотвращают появление неожиданных счетов во время демонстраций.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг не срабатывает, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример выполнения, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успешного выполнения и не соглашайтесь на молчаливое частичное завершение работы. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют объем контекста; строгие ограничения предотвращают появление неожиданных счетов.

# --- Standard Library ---
import os
from typing import TypedDict, Annotated, Literal
# --- LangChain Core ---
from langchain_openai import ChatOpenAI          # or ChatAnthropic, ChatGroq, etc.
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage, BaseMessage
from langchain_core.tools import tool
# --- LangGraph Core ---
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages  # The message reducer
from langgraph.prebuilt import ToolNode            # Pre-built node for tool execution
from langgraph.checkpoint.memory import MemorySaver
# --- Configuration ---
# Always name your model variable 'llm' - it's the standard in every node
llm = ChatOpenAI(
    model="gpt-4o",         # or "claude-3-5-sonnet-20241022", etc.
    temperature=0,          # 0 = deterministic; raise for creativity
    api_key=os.environ.get("OPENAI_API_KEY")
)

Почему именно такая структура

Почему именно такая структура работает наилучшим образом, когда рассматривается как измеримая поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Записывайте временные показатели, а также стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости на раннем этапе предотвращает неожиданные счёты при переходе от демо-версии к общедоступным средам. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения не позволяют демо-версиям превращаться в неожиданные счёты.

Модуль 2: Состояние

Модуль 2: Состояние лучше всего рассматривать как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентного типа активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов во время демонстраций.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; строгие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг терпит неудачу, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример выполнения, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задач. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов.

# ============================================================
# MODULE 2: STATE
# ============================================================
class AgentState(TypedDict):
    # 'messages' is the heartbeat of almost every LangGraph agent.
    # Annotated[list, add_messages] means: "this is a list, and when
    # a node writes to it, append - don't replace."
    messages: Annotated[list[BaseMessage], add_messages]

    # Add custom fields below for your specific agent's needs.
    # Fields without a reducer are REPLACED each time a node writes to them.

    # Example: a simple string field (gets replaced each write)
    current_task: str

    # Example: a list you want to accumulate (use operator.add as reducer)
    # results: Annotated[list[str], operator.add]

    # Example: a counter
    # iteration_count: int

Ментальная модель сокращения

Ментальная модель Reducer работает наилучшим образом, когда рассматривается как измеримая структура. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общедоступным средам. Установите лимит токенов на один ход и на одну сессию. Инструменты типа агентов активно расширяют контекст; жесткие ограничения не позволяют демо-версиям превращаться в неожиданные счета.

Модуль 3: Инструменты

Модуль 3: Инструменты работают наилучшим образом, когда их рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за раунд и за сессию. Инструменты с агентным подходом активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг не срабатывает, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример выполнения, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задач. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют объем контекста; строгие ограничения предотвращают появление неожиданных счетов.

# ============================================================
# MODULE 3: TOOLS
# ============================================================
@tool
def search_web(query: str) -> str:
    """Search the web for current information about a topic.

    Use this when you need real-time information that is not in
    your training data, such as recent news or live prices.

    Args:
        query: The search query string.

    Returns:
        A string containing search results.
    """
    # Your actual implementation here (e.g., Tavily, SerpAPI, etc.)
    # Placeholder for illustration:
    return f"Search results for: {query}"

@tool
def calculate(expression: str) -> str:
    """Evaluate a mathematical expression and return the result.

    Use this for any arithmetic, algebra, or numerical computation.

    Args:
        expression: A valid Python math expression as a string, e.g. '2 + 2 * 10'

    Returns:
        The computed result as a string.
    """
    try:
        return str(eval(expression))
    except Exception as e:
        return f"Error: {e}"

# Collect all tools into a list - this is the pattern you always follow
tools = [search_web, calculate]
# Bind tools to the LLM so it knows they exist and can choose to call them
llm_with_tools = llm.bind_tools(tools)
# Create the pre-built ToolNode that will execute tool calls automatically
tool_node = ToolNode(tools)

Документация инструмента имеет решающее значение

Документация инструмента типа «критически важна» работает наилучшим образом, когда рассматривается как измеримая основа. Сначала необходимо зафиксировать один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объем задачи. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общедоступным средам. Определите лимит токенов на один ход и на одну сессию. Инструменты с агентным подходом активно расширяют контекст; жесткие ограничения помогают избежать неожиданных счетов при демонстрации функций.

Модуль 4: Узлы

Модуль 4: Узлы работают наилучшим образом, когда их рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь граф. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентного типа активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов во время демонстраций.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг не срабатывает, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример выполнения, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задач. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов.

# ============================================================
# MODULE 4: NODES
# ============================================================
# ── Node: Agent (the reasoning brain) ───────────────────────
def agent_node(state: AgentState) -> dict:
    """The central reasoning node. Calls the LLM and decides
    whether to respond or call a tool."""

    # Build the message list to send to the LLM.
    # Always include a system message to set behavior.
    system_prompt = SystemMessage(content=(
        "You are a helpful assistant. Use the available tools "
        "when you need real-time information or computation. "
        "Respond clearly and concisely."
    ))

    # The LLM receives the system prompt + all previous messages in state
    messages_to_send = [system_prompt] + state["messages"]

    # Call the LLM. Use llm_with_tools if you have tools; plain llm if not.
    response = llm_with_tools.invoke(messages_to_send)

    # Return the LLM's response as a state update.
    # add_messages will APPEND this AIMessage to state["messages"].
    return {"messages": [response]}

# ── Node: Summarizer (example of a non-LLM processing node) ─
def summarize_node(state: AgentState) -> dict:
    """Summarizes the conversation so far to keep context short.
    This shows that nodes don't have to call an LLM - they can
    do any Python processing."""

    all_messages = state["messages"]

    # Summarize with the LLM (a different prompt, same LLM)
    summary_prompt = [
        SystemMessage(content="Summarize the following conversation in 2-3 sentences."),
        HumanMessage(content=str(all_messages))
    ]

    summary_response = llm.invoke(summary_prompt)

    # Replace messages with a fresh start containing just the summary
    return {
        "messages": [AIMessage(content=f"[Summary] {summary_response.content}")]
    }

Ментальная модель узла

Модель мышления Node работает наилучшим образом, когда рассматривается как измеримая поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общедоступным средам. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентного типа активно расширяют контекст; жесткие ограничения не позволяют демо-версиям превращаться в неожиданные счета.

Модуль 5: Края и маршрутизация

Модуль 5: Работа с краями и маршрутизацией наилучшим образом функционирует, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за ход и за сессию. Инструменты с агентным подходом активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг не срабатывает, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример выполнения, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задач. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют объем контекста; строгие ограничения предотвращают появление неожиданных счетов.

# ============================================================
# MODULE 5: EDGES & ROUTING
# ============================================================
# Import the pre-built tool routing function
from langgraph.prebuilt import tools_condition
# ── Custom Routing Function Example ─────────────────────────
def should_continue(state: AgentState) -> Literal["tools", "summarize", "__end__"]:
    """Custom router for the agent node.

    Routing functions always:
    1. Receive the current state as input
    2. Return a string that maps to the next node (or END)

    The return values must match the keys in add_conditional_edges' mapping.
    """

    last_message = state["messages"][-1]  # Look at what the LLM just said

    # Case 1: The LLM decided to call a tool
    if hasattr(last_message, "tool_calls") and last_message.tool_calls:
        return "tools"

    # Case 2: The conversation is getting long - summarize before continuing
    if len(state["messages"]) > 20:
        return "summarize"

    # Case 3: The LLM gave a direct answer - we're done
    return "__end__"  # LangGraph's internal name for END

Ментальная модель маршрутизации

Ментальная модель маршрутизации работает наилучшим образом, когда рассматривается как измеримая структура. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Записывайте время выполнения операций, а также стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам. Установите лимит токенов на один ход и на одну сессию. Инструменты агентов активно расширяют контекст; жесткие ограничения не позволяют демо-версиям превращаться в неожиданные счета.

Модуль 6: Сборка графа

Модуль 6: Работа с графом наиболее эффективна, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь граф. Установите лимиты на количество токенов за ход и за сессию. Инструменты-агенты активно расширяют контекст; строгие ограничения предотвращают появление неожиданных счетов во время демонстраций.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг не срабатывает, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример результата, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия создаваемым элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задач. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют объем контекста; строгие ограничения предотвращают появление неожиданных счетов.

# ============================================================
# MODULE 6: GRAPH ASSEMBLY
# ============================================================
# ── Step 1: Initialize ──────────────────────────────────────
# Always pass your State class to StateGraph
graph_builder = StateGraph(AgentState)
# ── Step 2: Register All Nodes ──────────────────────────────
# Format: add_node("node_name_as_string", node_function)
# The string name is what you use in ALL edge definitions
graph_builder.add_node("agent", agent_node)
graph_builder.add_node("tools", tool_node)      # The pre-built ToolNode from Module 3
graph_builder.add_node("summarize", summarize_node)
# ── Step 3: Set Entry Point ─────────────────────────────────
# Which node runs first when we invoke the graph?
graph_builder.set_entry_point("agent")
# ── Step 4: Wire the Edges ──────────────────────────────────
# Conditional edge from agent: check if we need tools, a summary, or we're done
graph_builder.add_conditional_edges(
    "agent",          # Source node
    should_continue,  # Routing function from Module 5
    {
        "tools": "tools",           # If router returns "tools" → go to tools node
        "summarize": "summarize",   # If router returns "summarize" → go to summarize node
        "__end__": END,             # If router returns "__end__" → stop the graph
    }
)
# Static edge: after tools run, always go back to agent (the ReAct loop)
graph_builder.add_edge("tools", "agent")
# Static edge: after summarization, always return to agent
graph_builder.add_edge("summarize", "agent")
# ── Step 5: Compile ─────────────────────────────────────────
# Without checkpointer: no persistent memory (stateless per invocation)
# With checkpointer: memory persists across turns (stateful conversations)
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)

Ментальная модель сборки

Ментальная модель сборки работает наилучшим образом, когда рассматривается как измеримая структура. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общедоступным средам. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентного типа активно расширяют контекст; жесткие ограничения не позволяют демо-версиям превращаться в неожиданные счета.

Модуль 7: Точка входа и вызов

Модуль 7: Entrypoint и процесс вызова работают наилучшим образом, когда их рассматривают как измеримые элементы. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за раунд и сессию. Инструменты агентного типа активно расширяют контекст; жесткие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Концепция

Концепция работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Документируйте одновременно успешный сценарий выполнения и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; строгие ограничения предотвращают появление неожиданных счетов при демонстрациях.

Ключевые термины, которые вам необходимо знать

Книга «Ключевые слова, которые вам нужно знать» работает наилучшим образом, если рассматривать её как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работы. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг терпит неудачу, причина сбоя должна указывать на конкретный элемент ответственности, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов.

Стандартный шаблон

Стандартная шаблонная структура работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один идеальный пример выполнения, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задач. Установите лимиты на количество операций за раз и за сессию. Инструменты агентов активно расширяют объем контекста; строгие ограничения предотвращают появление неожиданных счетов.

# ============================================================
# MODULE 7: ENTRYPOINT & INVOCATION
# ============================================================
if __name__ == "__main__":

    # ── Config: defines this conversation's memory session ──
    # Change thread_id to start a fresh conversation.
    # Keep the same thread_id to continue an existing one.
    config = {"configurable": {"thread_id": "user-session-001"}}

    # ── Single Invocation (synchronous) ─────────────────────
    user_input = "What is the current price of Bitcoin?"

    result = graph.invoke(
        input={"messages": [HumanMessage(content=user_input)]},
        config=config
    )

    # The result is the final state dictionary.
    # Access the last message to get the agent's final answer.
    final_answer = result["messages"][-1].content
    print(f"Agent: {final_answer}")

    # ── Streaming Invocation (for real-time output) ──────────
    for chunk in graph.stream(
        input={"messages": [HumanMessage(content=user_input)]},
        config=config,
        stream_mode="values"  # Yields the full state after each node runs
    ):
        # Each chunk is a state snapshot. The last message shows progress.
        latest = chunk["messages"][-1]
        if hasattr(latest, "content") and latest.content:
            print(f"[Streaming] {latest.content}")

    # ── Multi-turn Conversation Loop ─────────────────────────
    print("\n--- Starting Interactive Session ---")
    while True:
        user_text = input("You: ").strip()
        if user_text.lower() in ("exit", "quit", "bye"):
            break

        response = graph.invoke(
            input={"messages": [HumanMessage(content=user_text)]},
            config=config  # Same config = same memory thread
        )

        print(f"Agent: {response['messages'][-1].content}\n")

Полная каноническая шаблонная структура: полный файл

Полная каноническая шаблонная структура: Для наилучшей работы «Полного файла» его следует рассматривать как измеримую поверхность. Сначала зафиксируйте один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объём работы. Записывайте временные показатели, а также стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счёты при переходе от демо-версии к общедоступным средам. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют контекст; жёсткие ограничения не позволяют демо-версиям превращаться в неожиданные счёты.

# ============================================================
# LANGGRAPH CANONICAL AGENT TEMPLATE
# Modules: Imports → State → Tools → Nodes → Edges → Assembly → Entrypoint
# ============================================================
# ── MODULE 1: IMPORTS & CONFIGURATION ───────────────────────
import os
from typing import TypedDict, Annotated, Literal
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage, BaseMessage
from langchain_core.tools import tool
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import MemorySaver
llm = ChatOpenAI(model="gpt-4o", temperature=0)

# ── MODULE 2: STATE ─────────────────────────────────────────
class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]
    # Add your custom fields here

# ── MODULE 3: TOOLS ─────────────────────────────────────────
@tool
def my_tool(input: str) -> str:
    """Describe clearly what this tool does and when the LLM should use it."""
    return f"Result for: {input}"
tools = [my_tool]
llm_with_tools = llm.bind_tools(tools)
tool_node = ToolNode(tools)

# ── MODULE 4: NODES ─────────────────────────────────────────
def agent_node(state: AgentState) -> dict:
    """The reasoning node. Calls the LLM, optionally triggers tool calls."""
    messages = [SystemMessage(content="You are a helpful assistant.")] + state["messages"]
    response = llm_with_tools.invoke(messages)
    return {"messages": [response]}

# ── MODULE 5: EDGES & ROUTING ───────────────────────────────
def should_continue(state: AgentState) -> Literal["tools", "__end__"]:
    """Decide: did the LLM call a tool, or did it give a final answer?"""
    last_message = state["messages"][-1]
    if hasattr(last_message, "tool_calls") and last_message.tool_calls:
        return "tools"
    return "__end__"

# ── MODULE 6: GRAPH ASSEMBLY ────────────────────────────────
graph_builder = StateGraph(AgentState)
graph_builder.add_node("agent", agent_node)
graph_builder.add_node("tools", tool_node)
graph_builder.set_entry_point("agent")
graph_builder.add_conditional_edges(
    "agent",
    should_continue,
    {"tools": "tools", "__end__": END}
)
graph_builder.add_edge("tools", "agent")
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)

# ── MODULE 7: ENTRYPOINT ────────────────────────────────────
if __name__ == "__main__":
    config = {"configurable": {"thread_id": "session-001"}}

    while True:
        user_text = input("You: ").strip()
        if not user_text or user_text.lower() in ("exit", "quit"):
            break
        response = graph.invoke(
            {"messages": [HumanMessage(content=user_text)]},
            config=config
        )
        print(f"Agent: {response['messages'][-1].content}\n")

Продвинутый модуль: многоагентные системы

Расширенный модуль: системы с множеством агентов работают наилучшим образом, когда их рассматривают как измеримую структуру. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентов активно расширяют контекст; жесткие ограничения предотвращают появление неожиданных счетов. Расширенный модуль: системы с множеством агентов работают наилучшим образом, когда их рассматривают как измеримую структуру. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг сбивается, причина сбоя должна указывать на конкретную ответственность, а не на запутанную цепочку операций.

Ключевые термины, которые вам необходимо знать (системы с множеством агентов)

Для ключевых терминов, которые необходимо знать (многоагентная система), определите входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия результатам работы, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задачи. При следующем шаге, представляющем собой код или вызов инструмента, отдавайте предпочтение структурированным результатам с проверкой по шаблону перед произвольными текстовыми описаниями.

Структурный шаблон многоагентной системы

Для многопроцессного структурного шаблона необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение стоимости заранее предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам. При следующем шаге, представляющем собой код или вызов инструмента, следует отдавать предпочтение структурированным выводам с проверкой схемы перед свободным текстом.

# ── MULTI-AGENT PATTERN ─────────────────────────────────────
# Each specialist is a compiled graph (a subgraph)

# Sub-agent 1: A researcher
researcher_graph = StateGraph(AgentState)
# ... (built with its own nodes, edges, and tools)
researcher = researcher_graph.compile()
# Sub-agent 2: A writer
writer_graph = StateGraph(AgentState)
# ... (built with its own nodes, edges, and tools)
writer = writer_graph.compile()

# ── SUPERVISOR NODE ─────────────────────────────────────────
def supervisor_node(state: AgentState) -> dict:
    """Decides which sub-agent should handle the current task."""
    # The supervisor LLM decides: "researcher" or "writer" or "FINISH"
    response = supervisor_llm.invoke(state["messages"])
    return {"messages": [response], "next_agent": response.content}

def route_to_agent(state: AgentState) -> Literal["researcher", "writer", "__end__"]:
    """Routes to the appropriate sub-agent based on supervisor's decision."""
    return state.get("next_agent", "__end__")

# ── SUPERVISOR GRAPH ────────────────────────────────────────
supervisor_builder = StateGraph(AgentState)
supervisor_builder.add_node("supervisor", supervisor_node)
supervisor_builder.add_node("researcher", researcher)  # Subgraph as a node!
supervisor_builder.add_node("writer", writer)          # Subgraph as a node!
supervisor_builder.set_entry_point("supervisor")
supervisor_builder.add_conditional_edges(
    "supervisor",
    route_to_agent,
    {"researcher": "researcher", "writer": "writer", "__end__": END}
)
supervisor_builder.add_edge("researcher", "supervisor")
supervisor_builder.add_edge("writer", "supervisor")
supervisor_graph = supervisor_builder.compile(checkpointer=MemorySaver())

Карточка справки по ключевым терминам

Для карточки справочных ключевых слов необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь кодовый граф. Предпочитайте структурированные выходные данные с проверкой схемы вместо свободного текста, когда следующим шагом является выполнение кода или вызов инструмента. Для карточки справочных ключевых слов необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое шага он должен указывать на конкретную причину, а не на сложную структуру обработки данных.

Заключение: «Мышечная память» LangGraph

При работе над разделом «Заключение: „Мышечная память“ LangGraph» сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и то, что происходит при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия элементам, определите критерии успешности и не допускайте беззвучного частичного выполнения задачи. Храните в кэше стабильные системные инструкции и схемы инструментов. Пересылка одинакового вступительного блока — частая причина избыточных нагрузок.

Чек-лист операций

Для чек-листа операций определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии системы.

Документируйте одновременно успешный сценарий работы и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не дополнительными улучшениями в последующем этапе.

Предпочитайте структурированный вывод с проверкой схемы вместо свободного текста, когда следующим шагом является написание кода или вызов инструмента.

Создавайте контрольные точки после дорогостоящих операций. Система возобновления работы не должна снова взимать плату за тот же вызов большой языковой модели, когда оператор пытается выполнить последующий шаг.

Фиксируйте версии зависимостей и сохраняйте хэш изображения, с использованием которого выполнялась демонстрация. Воспроизводимость важнее устного опыта команды.

Записывайте время выполнения, стоимость токенов или запросов вместе с функциональными результатами. Отображение стоимости на раннем этапе предотвращает неожиданные счета при переходе от демо-режима к общим средам.

Перед внедрением данной стек-технологии необходимо заморозить версии, сгенерировать эталонный отчет для критической части работы и уточнить шаги возврата к предыдущему состоянию. В совместных средах требуются ограничения на скорость работы, проверки принадлежности ресурсов и четко определенный ответственный за обновление секретов. Лучше выбирать надежность, даже если она кажется менее привлекательной, чем красивые одноразовые демонстрации.

Примечание для d02265f3bebf: не храните ключи поставщика в репозитории, установите лимит токенов на одну сессию и сохраняйте отчеты рядом с фиксами для оценки, чтобы последующие замены моделей оставались сопоставимыми.