Главная / Статьи / Практические заметки: Лучшая платформа для агентов в 2026 году: LangGraph против OpenAI Agents

Практические заметки: Лучшая платформа для агентов в 2026 году: LangGraph против OpenAI Agents

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

2343 слов

В этом руководстве показано, как пройти путь от сырья до рабочей системы для: Лучшая фреймворк-среда агентов в 2026 году: LangGraph против OpenAI Agents SDK против Claude Agent SDK. Основное внимание уделяется практическим шагам, четкой проверке и коду, который можно просто добавить в репозиторий без необходимости угадывать намерения. Для обзора определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не пытаясь угадать скрытое состояние. Записывайте время выполнения и стоимость токенов или запросов вместе с функциональными результатами. Отображение стоимости заранее помогает избежать неожиданных счетов при переходе от демо-версии к общим средам.

Три примитива

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

Убеждение, от которого стоит отказаться к 2025 году

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

# Install: pip install "openai-agents[litellm]"
# Env: export GEMINI_API_KEY=...
import os
from agents import Agent, Runner, function_tool
from agents.extensions.models.litellm_model import LitellmModel

@function_tool
def current_time_utc() -> str:
    """Return the current UTC time as an ISO-8601 string."""
    from datetime import datetime, timezone
    return datetime.now(timezone.utc).isoformat(timespec="seconds")

# OpenAI Agents SDK using Gemini via LiteLLM. No OpenAI key required.
gemini_model = LitellmModel(
    model="gemini/gemini-2.5-pro",
    api_key=os.environ["GEMINI_API_KEY"],
)

agent = Agent(
    name="time-agent",
    instructions="Answer time questions using the current_time_utc tool.",
    model=gemini_model,
    tools=[current_time_utc],
)

result = Runner.run_sync(agent, "What is the current UTC time?")
print(result.final_output)
# -> "The current UTC time is 2026-07-06T14:32:11+00:00."

Представляем Meridian

При работе над Introducing Meridian сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и что происходит при частичной неудаче. Такой чек-лист помогает сохранять честность при последующих изменениях кода. Предпочитайте небольшие, тестируемые модули большим скриптам. Если какой-то шаг не сработает, причина неудачи должна указывать на конкретную ответственность, а не на запутанную цепочку операций. Вносите контрольные точки после дорогостоящих шагов. Система возобновления работы не должна снова взимать плату за один и тот же вызов LLM при повторной попытке обработки последующего элемента. При работе над Introducing Meridian сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и что происходит при частичной неудаче. Такой чек-лист помогает сохранять честность при последующих изменениях кода. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости на ранних этапах предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам.

Задание 1: Голосовой ввод и потоковая передача в реальном времени

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

# Install: pip install openai-agents
# Env: export OPENAI_API_KEY=...
import asyncio
from agents import function_tool
from agents.realtime import RealtimeAgent, RealtimeRunner

@function_tool
def lookup_billing_balance(account_id: str) -> str:
    """Return the current outstanding balance for an account."""
    # In production, this hits the billing service. Here it is a stub.
    return "42.17 USD outstanding as of 2026-07-06."

voice_agent = RealtimeAgent(
    name="meridian-billing-voice",
    instructions=(
        "You are Meridian's billing voice assistant. Answer politely, briefly. "
        "Confirm the account_id before disclosing any balance."
    ),
    tools=[lookup_billing_balance],
)

async def main():
    runner = RealtimeRunner(
        starting_agent=voice_agent,
        config={"model_settings": {"model_name": "gpt-realtime-2.1"}},
    )

    # session handles the audio stream and tool calls
    session = await runner.run()

    async with session:
        # Wire the audio input source here via sounddevice or pyaudio
        async for event in session:
            if event.type == "history_updated":
                # The item contains the finalized transcript once the turn ends
                print(f"History updated with item: {event.item}")
            elif event.type == "error":
                print(f"Error: {event.error}")
                break

asyncio.run(main())

Нагрузка 2: Надёжная оркестрация нескольких агентов с использованием HITL

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

from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import interrupt, Command
from langchain_google_genai import ChatGoogleGenerativeAI

# LangGraph is provider-agnostic. Here it uses Gemini.
llm = ChatGoogleGenerativeAI(model="gemini-2.5-pro", temperature=0)

class RefundState(TypedDict):
    order_id: str
    amount_usd: float
    customer_reason: str
    fraud_risk: Literal["low", "medium", "high"] | None
    finance_decision: Literal["approved", "denied"] | None
    human_review_needed: bool

def fraud_check(state: RefundState) -> RefundState:
    """Run the LLM-backed fraud check against the customer's stated reason."""
    prompt = (
        f"Assess fraud risk for refund of ${state['amount_usd']:.2f}. "
        f"Customer reason: {state['customer_reason']!r}. "
        "Respond with one word: low, medium, or high."
    )
    verdict = llm.invoke(prompt).content.strip().lower()
    if verdict not in {"low", "medium", "high"}:
        verdict = "high"  # fail-closed on ambiguous LLM output
    return {**state, "fraud_risk": verdict}

def finance_approval(state: RefundState) -> RefundState:
    """Above $500 or medium risk, pause for a human. Otherwise auto-approve."""
    needs_human = state["amount_usd"] > 500 or state["fraud_risk"] in {"medium", "high"}
    if needs_human:
        # Pause the graph. On resume, interrupt returns the human's decision.
        human_decision = interrupt({
            "order_id": state["order_id"],
            "amount_usd": state["amount_usd"],
            "fraud_risk": state["fraud_risk"],
            "prompt": "Approve (yes/no)?",
        })
        return {**state, "human_review_needed": True, "finance_decision": human_decision}
    return {**state, "human_review_needed": False, "finance_decision": "approved"}

# Build the graph
graph = StateGraph(RefundState)
graph.add_node("fraud_check", fraud_check)
graph.add_node("finance_approval", finance_approval)
graph.add_edge(START, "fraud_check")
graph.add_conditional_edges(
    "fraud_check",
    lambda s: "finance_approval" if s["fraud_risk"] != "high" else END,
)
graph.add_edge("finance_approval", END)

# Checkpointer. For production, swap MemorySaver for PostgresSaver.
compiled = graph.compile(checkpointer=MemorySaver())

# Run it. Interrupt fires on the $850 refund and the graph pauses.
config = {"configurable": {"thread_id": "order-4291"}}
result = compiled.invoke(
    {
        "order_id": "4291",
        "amount_usd": 850.00,
        "customer_reason": "arrived damaged, no photo",
        "fraud_risk": None,
        "finance_decision": None,
        "human_review_needed": False,
    },
    config=config,
)

# Later, a human reviewer says yes. Resume with Command.
final = compiled.invoke(Command(resume="approved"), config=config)

Рабочая нагрузка 3: Ориентированная на программирование и файловую систему

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

# Install: pip install claude-agent-sdk
# Env: export ANTHROPIC_API_KEY=...
import anyio
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AgentDefinition,
    HookMatcher,
)

# PreToolUse hook: block Bash calls that look like rm -rf
async def block_dangerous_bash(input_data, tool_use_id, context):
    if input_data.get("tool_name") == "Bash":
        cmd = input_data.get("tool_input", {}).get("command", "")
        if "rm -rf" in cmd or "rm  -rf" in cmd:
            return {
                "hookSpecificOutput": {
                    "hookEventName": "PreToolUse",
                    "permissionDecision": "deny",
                    "permissionDecisionReason": "rm -rf blocked by policy",
                }
            }
    return {}

# Subagent: runs in isolated context to lint one file
lint_agent = AgentDefinition(
    description="Run linters on a single file and return a concise report.",
    prompt=(
        "You are the lint subagent. Given a file path, run the project's linter "
        "on it and return a one-paragraph summary of failures. Do not fix anything."
    ),
    tools=["Bash", "Read"], # Note: tools is deprecated in favor of skills in recent SDKs
)

options = ClaudeAgentOptions(
    system_prompt=(
        "You are Meridian's code migration agent. Walk the target directory, "
        "apply the migration, run tests, and open a PR. Prefer small commits."
    ),
    allowed_tools=["Bash", "Read", "Write", "Edit", "Glob", "Grep"],
    hooks={"PreToolUse": [HookMatcher(hooks=[block_dangerous_bash])]},
    agents={"lint": lint_agent},
    # resume="mig-run-2026-07-06-01",  # uncomment to resume a prior session
)

async def main():
    async with ClaudeSDKClient(options=options) as client:
        await client.query(
            "Migrate services/payments/ from Java 17 to Java 21. "
            "For every file you touch, delegate to the `lint` subagent afterward. "
            "Do NOT commit or open PRs yet. Stop after changes are on disk."
        )
        async for message in client.receive_response():
            print(message)

anyio.run(main)

Нагрузка 4: Оркестрация инструментов с активным использованием MCP

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

Матрица принятия решений

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

О CrewAI

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

Настоящий выбор

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

Чек-лист операционной деятельности

Чек-лист работает наилучшим образом, если рассматриваться как измеримая основа. Соберите один эталонный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ.

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

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

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

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

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

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

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

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

Подробность усиления безопасности 0/821: измеряйте время выполнения, класс ошибки и расход токенов для этого примечания, затем решайте, следует ли сохранять изменения, исходя из определённого набора критериев, а не из устных замечаний.

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

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