Введение: от простых цепочек к агентам, которые действуют
Ещё пару лет назад типичное LLM-приложение выглядело как последовательная цепочка вызовов: взяли промпт, добавили контекст из векторной базы, отправили в модель, получили ответ. LangChain популяризировал эту парадигму — chains, retrievers, memory — и это работало для простых сценариев вроде «ответь на вопрос по документации».
Но бизнес-задачи редко укладываются в линейный пайплайн. Пользователь хочет не просто получить ответ, а чтобы система совершила действие: создала тикет в Jira, отправила письмо, запросила данные из CRM, проверила погоду и только потом сформулировала ответ. Именно здесь на сцену выходят AI-агенты — системы, которые не просто генерируют текст, а автономно принимают решение, какой инструмент вызвать, в каком порядке, и интерпретируют результат. Проблема в том, что до недавнего времени подключение каждого нового инструмента требовало написания «клея» — кастомных функций, обёрнутых в @tool декоратор LangChain, с ручным управлением аутентификацией, обработкой ошибок и сериализацией данных. Для продакшена это быстро превращалось в зоопарк нестандартных интеграций, который сложно поддерживать и масштабировать.
Model Context Protocol (MCP) от Anthropic решает эту проблему, предлагая единый стандарт для подключения инструментов и источников данных к LLM-приложениям. Вместо того чтобы для каждого API писать свой адаптер, мы просто запускаем MCP-сервер, который предоставляет инструменты по стандартизированному протоколу. Агент подключается к этому серверу через MCP-клиент и получает доступ ко всем инструментам без лишнего кода.
В этой статье мы соберём полноценного агента, который:
Умеет работать с внешним миром через MCP (узнавать погоду и создавать GitHub Issues);
Имеет доступ к внутренней базе знаний через RAG;
Принимает решения по ReAct-подходу с использованием LangGraph.
Теоретический минимум: что нужно знать перед погружением в код
AI-агент и ReAct-подход
В контексте LLM агент — это система, которая работает в цикле: Мысль → Действие → Наблюдение. Этот паттерн называется ReAct (Reasoning + Acting).
Агент получает задачу от пользователя.
Модель анализирует («думает»), какой инструмент нужно вызвать и с какими параметрами.
Агент вызывает инструмент и получает результат («наблюдение»).
Цикл повторяется, пока модель не решит, что информации достаточно для финального ответа.
Ключевое отличие от обычного chain — модель сама решает, когда и какие инструменты использовать, а не следует жёстко заданной последовательности.
RAG (Retrieval-Augmented Generation)
RAG — это техника, при которой перед генерацией ответа мы извлекаем из внешнего хранилища (векторной базы) релевантные документы и добавляем их в контекст модели. Для агента RAG — это просто ещё один инструмент. Когда агенту нужна информация из внутренней документации, он вызывает инструмент search_documentation, а не пытается ответить по памяти (и, возможно, галлюцинировать).
Model Context Protocol (MCP)
MCP — это открытый протокол, построенный поверх JSON-RPC, который стандартизирует взаимодействие между AI-приложениями и внешними источниками данных и инструментами. Архитектура включает три ключевых компонента:
MCP Host — AI-приложение (например, Claude Desktop или наш Python-агент).
MCP Client — компонент внутри хоста, который поддерживает соединение с одним MCP-сервером.
MCP Server — программа, которая предоставляет инструменты, ресурсы и промпты по стандартизированному протоколу.
Проще говоря: MCP делает для AI-агентов то же, что REST API сделал для веб-сервисов — универсальный способ взаимодействия, не зависящий от конкретной реализации.
Обзор стека: что и почему мы будем использовать
Компонент |
Выбор |
Обоснование |
|---|---|---|
Python |
3.11+ |
Поддержка |
Фреймворк агента |
LangGraph + LangChain |
LangGraph даёт явный контроль над циклом ReAct и состоянием; LangChain предоставляет удобные абстракции для инструментов и моделей- |
MCP-сервер |
FastMCP |
Высокоуровневая Python-библиотека, которая сводит создание MCP-сервера к декорированию функций. FastMCP 1.0 был включён в официальный MCP Python SDK, а версия 2.0 активно развивается и добавляет возможности клиента |
MCP-адаптер |
|
Официальная библиотека от LangChain, которая конвертирует MCP-инструменты в формат, понятный LangChain/LangGraph- |
Векторная БД |
ChromaDB |
Лёгкая, встраиваемая, отлично работает для прототипов и небольших проектов |
Эмбеддинги |
OpenAI |
Качественные и недорогие эмбеддинги |
LLM |
Claude (через Anthropic API) или GPT-4 |
Любая модель, поддерживающая function calling |
Практическая часть: пишем код
Часть 1. Создание MCP-сервера для работы с внешним миром
Начнём с создания MCP-сервера, который предоставит агенту два инструмента: получение погоды и создание GitHub Issue.
Установим FastMCP:
pip install fastmcp httpx
Создадим файл tools_server.py:
# tools_server.py import os import httpx from fastmcp import FastMCP # Инициализируем MCP-сервер с именем "ExternalTools" mcp = FastMCP("ExternalTools") # ========== Инструмент 1: Получение погоды ========== @mcp.tool() async def get_weather(city: str) -> str: """ Получает текущую погоду для указанного города. Args: city: Название города (например, "Moscow" или "London") Returns: Строка с описанием погоды """ # Используем бесплатный Open-Meteo API (не требует ключа) # Сначала получаем координаты города через geocoding API async with httpx.AsyncClient() as client: geo_response = await client.get( "https://geocoding-api.open-meteo.com/v1/search", params={"name": city, "count": 1, "language": "en", "format": "json"}, timeout=10.0 ) geo_response.raise_for_status() geo_data = geo_response.json() if not geo_data.get("results"): return f"Город '{city}' не найден" location = geo_data["results"][0] lat, lon = location["latitude"], location["longitude"] city_name = location["name"] # Получаем погоду по координатам weather_response = await client.get( "https://api.open-meteo.com/v1/forecast", params={ "latitude": lat, "longitude": lon, "current_weather": True, "timezone": "auto" }, timeout=10.0 ) weather_response.raise_for_status() weather_data = weather_response.json() current = weather_data["current_weather"] return ( f"Погода в {city_name}:\n" f"Температура: {current['temperature']}°C\n" f"Скорость ветра: {current['windspeed']} км/ч\n" f"Код погоды: {current['weathercode']}" ) # ========== Инструмент 2: Создание GitHub Issue ========== @mcp.tool() async def create_github_issue( repo: str, title: str, body: str, labels: list[str] | None = None ) -> str: """ Создаёт новый Issue в указанном GitHub-репозитории. Args: repo: Полное имя репозитория (например, "username/repo-name") title: Заголовок Issue body: Текст Issue (поддерживает Markdown) labels: Список меток (опционально) Returns: Строка с результатом операции """ github_token = os.environ.get("GITHUB_TOKEN") if not github_token: return "Ошибка: переменная окружения GITHUB_TOKEN не установлена" url = f"https://api.github.com/repos/{repo}/issues" headers = { "Authorization": f"Bearer {github_token}", "Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" } payload = {"title": title, "body": body} if labels: payload["labels"] = labels async with httpx.AsyncClient() as client: response = await client.post( url, json=payload, headers=headers, timeout=30.0 ) if response.status_code == 201: data = response.json() return f"Issue успешно создан: {data['html_url']}" elif response.status_code == 404: return f"Ошибка: репозиторий '{repo}' не найден или нет доступа" else: return f"Ошибка GitHub API: {response.status_code} - {response.text}" if __name__ == "__main__": # Запускаем сервер с транспортом stdio (стандартный ввод/вывод) # Это позволяет клиенту запускать сервер как подпроцесс mcp.run(transport="stdio")
Что здесь происходит:
Мы создаём экземпляр
FastMCPи декорируем функции@mcp.tool()— FastMCP автоматически генерирует JSON-схему для параметров на основе сигнатуры функции и docstring.get_weatherиспользует бесплатный Open-Meteo API (не требует API-ключа).create_github_issueтребует токен GitHub с правами на создание issues (создайте его в настройках GitHub с scoperepo).Сервер запускается с транспортом
stdio— это значит, что клиент будет запускать этот скрипт как подпроцесс и общаться с ним через стандартный ввод/вывод по протоколу JSON-RPC.
Запуск сервера (локально, для теста):
export GITHUB_TOKEN="your_github_personal_access_token" python tools_server.py
Для проверки можно использовать MCP Inspector, но мы сразу перейдём к интеграции с агентом.
Часть 2. Настройка RAG-модуля
Теперь создадим RAG-систему, которая будет индексировать PDF-документацию и предоставлять агенту инструмент для поиска.
Установим зависимости:
pip install langchain langchain-openai chromadb pypdf
Создадим файл rag_tool.py:
# rag_tool.py import os from pathlib import Path from langchain_openai import OpenAIEmbeddings from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import Chroma from langchain.tools import tool # Путь для хранения векторной базы CHROMA_PATH = "./chroma_db" DATA_PATH = "./data" # Папка с PDF-файлами def initialize_vector_store(force_reload: bool = False) -> Chroma: """ Инициализирует или загружает векторное хранилище ChromaDB. Args: force_reload: Если True, пересоздаёт базу заново из PDF-файлов Returns: Инстанс Chroma с загруженными документами """ embeddings = OpenAIEmbeddings(model="text-embedding-3-small") # Если база уже существует и не требуется перезагрузка — просто загружаем if os.path.exists(CHROMA_PATH) and not force_reload: return Chroma( persist_directory=CHROMA_PATH, embedding_function=embeddings ) # Иначе — создаём новую базу из PDF-файлов documents = [] data_folder = Path(DATA_PATH) if not data_folder.exists(): data_folder.mkdir(parents=True) print(f"Создана папка {DATA_PATH}. Поместите туда PDF-файлы и запустите снова.") # Возвращаем пустую базу return Chroma( persist_directory=CHROMA_PATH, embedding_function=embeddings ) for pdf_file in data_folder.glob("*.pdf"): loader = PyPDFLoader(str(pdf_file)) documents.extend(loader.load()) if not documents: print(f"В папке {DATA_PATH} нет PDF-файлов") return Chroma( persist_directory=CHROMA_PATH, embedding_function=embeddings ) # Разбиваем документы на чанки text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, separators=["\n\n", "\n", ". ", " ", ""] ) chunks = text_splitter.split_documents(documents) # Создаём и сохраняем векторную базу vector_store = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory=CHROMA_PATH ) # В новых версиях Chroma persist() вызывать не нужно — from_documents уже сохраняет print(f"Векторная база создана: {len(chunks)} чанков из {len(documents)} документов") return vector_store # Глобальный экземпляр векторного хранилища _vector_store: Chroma | None = None def get_vector_store() -> Chroma: """Ленивая инициализация векторного хранилища.""" global _vector_store if _vector_store is None: _vector_store = initialize_vector_store() return _vector_store @tool async def search_documentation(query: str) -> str: """ Ищет информацию во внутренней документации (базе знаний). Используй этот инструмент, когда нужно ответить на вопрос, требующий обращения к документации компании или техническим спецификациям. Args: query: Поисковый запрос на естественном языке Returns: Релевантные фрагменты из документации """ vector_store = get_vector_store() # Выполняем семантический поиск docs = vector_store.similarity_search(query, k=3) if not docs: return "В документации не найдено информации по вашему запросу." # Формируем ответ из найденных фрагментов results = [] for i, doc in enumerate(docs, 1): source = doc.metadata.get("source", "неизвестный источник") results.append(f"[Фрагмент {i} из {source}]\n{doc.page_content}\n") return "\n".join(results) # Функция для первоначальной загрузки документов (вызывается один раз при настройке) def setup_rag(): """Инициализирует RAG-систему, загружая все PDF из папки data/""" print("Инициализация RAG-системы...") store = initialize_vector_store(force_reload=True) print(f"Готово. В базе {store._collection.count()} документов.")
Ключевые моменты:
Мы используем
PyPDFLoaderдля загрузки PDF иRecursiveCharacterTextSplitterдля разбивки на чанки с перекрытием.Векторное хранилище сохраняется на диск в папке
chroma_db/— при повторных запусках не нужно переиндексировать документы.Инструмент
search_documentationобёрнут в декоратор@toolиз LangChain — это делает его совместимым с LangGraph-агентом.Важно: docstring инструмента — это часть промпта для модели. Чем точнее описано, когда и зачем использовать инструмент, тем лучше агент будет принимать решения.
Часть 3. Сборка агента с доступом к MCP
Теперь соберём всё вместе: агент на LangGraph, который использует и MCP-инструменты, и RAG. Установим оставшиеся зависимости:
pip install langchain-mcp-adapters langgraph langchain-anthropic
Создадим файл agent.py:
# agent.py import asyncio import os from pathlib import Path from langchain_anthropic import ChatAnthropic from langchain_mcp_adapters.client import MultiServerMCPClient from langgraph.prebuilt import create_react_agent # Импортируем наш RAG-инструмент from rag_tool import search_documentation, setup_rag async def main(): # ========== 1. Инициализация RAG ========== print("Загрузка RAG-системы...") setup_rag() # Индексирует PDF при первом запуске # ========== 2. Подключение к MCP-серверу ========== # MultiServerMCPClient управляет подключениями к нескольким MCP-серверам # В нашем случае сервер один, но архитектура позволяет легко добавлять новые mcp_client = MultiServerMCPClient( { "external_tools": { "transport": "stdio", # Сервер запускается как подпроцесс "command": "python", # Указываем абсолютный путь к нашему серверу "args": [str(Path(__file__).parent / "tools_server.py")], # Передаём переменные окружения в подпроцесс "env": { **os.environ, # Убеждаемся, что токен GitHub передаётся } } } ) # ========== 3. Получение инструментов ========== # Получаем инструменты из MCP-сервера mcp_tools = await mcp_client.get_tools() print(f"Загружено MCP-инструментов: {len(mcp_tools)}") for tool in mcp_tools: print(f" - {tool.name}: {tool.description[:50]}...") # Объединяем MCP-инструменты с нашим RAG-инструментом all_tools = mcp_tools + [search_documentation] print(f"Всего инструментов: {len(all_tools)}") # ========== 4. Создание агента ========== # Используем Claude Sonnet 4 — у него отличная поддержка function calling llm = ChatAnthropic( model="claude-sonnet-4-6", temperature=0, max_tokens=4096 ) # Для использования OpenAI можно раскомментировать: # from langchain_openai import ChatOpenAI # llm = ChatOpenAI(model="gpt-4.1", temperature=0) # create_react_agent из LangGraph создаёт готовый ReAct-агент # Под капотом — граф с узлами: agent (вызов LLM) -> tools (выполнение) -> agent agent = create_react_agent( model=llm, tools=all_tools, # Опционально: можно передать system prompt с дополнительными инструкциями # prompt=... ) # ========== 5. Запуск агента ========== print("\n" + "="*50) print("Агент готов к работе!") print("Примеры запросов:") print(" 1. Узнай погоду в Москве и создай тикет в GitHub") print(" 2. Поищи в документации, как настроить MCP сервер") print(" 3. Создай issue о баге в репозитории username/repo") print("Введите 'exit' для выхода") print("="*50 + "\n") while True: user_input = input("\n Ваш запрос: ") if user_input.lower() in ("exit", "quit", "выход"): break # Запускаем агента с историей сообщений # LangGraph автоматически управляет состоянием разговора result = await agent.ainvoke( {"messages": [{"role": "user", "content": user_input}]} ) # Извлекаем последнее сообщение от агента messages = result.get("messages", []) if messages: last_message = messages[-1] print(f"\n Ответ: {last_message.content}") else: print("\n Агент не вернул ответа") if __name__ == "__main__": asyncio.run(main())
Разбор ключевых моментов:
MultiServerMCPClient — центральный компонент для подключения к MCP-серверам. Он принимает конфигурацию, в которой для каждого сервера указывается транспорт (
stdioилиhttp) и параметры подключения.Транспорт stdio означает, что клиент запускает Python-скрипт как подпроцесс и общается с ним через стандартный ввод/вывод. Это удобно для локальной разработки. Для продакшена можно использовать HTTP-транспорт, запустив сервер отдельно.
create_react_agentиз LangGraph — это готовая реализация ReAct-агента. Под капотом создаётся граф с двумя узлами:
1. Agent Node: вызывает LLM с текущим состоянием и инструментами.
2. Tools Node: выполняет выбранные инструменты и возвращает результат.Агент работает асинхронно (
async/await), что важно для эффективной работы с внешними API.
Часть 4. Демонстрация работы
Поместим в папку data/ PDF-файл с документацией (например, руководство по работе с GitHub API или внутренний регламент создания тикетов) и запустим агента:
export ANTHROPIC_API_KEY="your_anthropic_api_key" export GITHUB_TOKEN="your_github_token" export OPENAI_API_KEY="your_openai_api_key" # для эмбеддингов python agent.py
Ваш запрос: Узнай погоду в Москве и создай тикет в репозитории myorg/docs с отчётом о погоде. Перед этим проверь в документации, как правильно оформлять такие тикеты.
[AGENT LOG] Thought: Мне нужно выполнить три действия:
Проверить документацию по оформлению тикетов
Узнать погоду в Москве
Создать тикет в GitHub с отчётом
Action: search_documentation Action Input: {“query”: “как оформлять тикеты о погоде”} Observation: [Фрагмент 1 из docs/internal-guide.pdf] Все отчёты о погоде должны содержать:
Город и дату
Температуру и скорость ветра
Рекомендации на основе погодных условий…
Thought: Теперь я знаю формат. Получу погоду в Москве.
Action: get_weather Action Input: {“city”: “Moscow”} Observation: Погода в Moscow: Температура: 18.5°C Скорость ветра: 12 км/ч…
Thought: Теперь создам тикет с отчётом.
Action: create_github_issue Action Input: { “repo”: “myorg/docs”, “title”: “Ежедневный отчёт о погоде в Москве”, “body”: “## Погода в Москве\n- Температура: 18.5°C\n- Ветер: 12 км/ч\n- Рекомендации: комфортная погода для прогулок”, “labels”: [“weather-report”, “automated”] } Observation: Issue успешно создан.
Ответ: Я выполнил все запрошенные действия:
Проверил документацию по оформлению тикетов — все отчёты должны включать температуру, ветер и рекомендации.
Узнал текущую погоду в Москве: 18.5°C, ветер 12 км/ч.
Создал тикет в репозитории myorg/docs.
Что произошло:
Агент самостоятельно спланировал последовательность действий.
Вызвал RAG-инструмент для получения правил оформления.
Вызвал MCP-инструмент для получения погоды.
Вызвал ещё один MCP-инструмент для создания Issue.
Синтезировал финальный ответ.
Сравнение с альтернативами и выводы
ритерий |
Классический подход ( |
Подход с MCP |
|---|---|---|
Интеграция нового API |
Писать функцию-обёртку, декорировать |
Запустить готовый MCP-сервер или написать свой с FastMCP |
Переиспользование |
Инструмент жёстко привязан к коду агента |
Один MCP-сервер могут использовать несколько агентов и даже разные AI-приложения (Claude Desktop, Cursor, etc.) |
Безопасность |
Ключи API хранятся в коде агента или его окружении |
MCP-сервер может работать в изолированном окружении со своими секретами |
Стандартизация |
Каждый инструмент — уникальная реализация |
Единый протокол JSON-RPC, понятная структура |
Сложность для простых задач |
Минимальная |
Требуется запуск отдельного процесса (для stdio) или HTTP-сервера |
Плюсы MCP
Масштабируемость: Экосистема MCP-серверов растёт — уже есть готовые серверы для GitHub, Slack, Google Drive, PostgreSQL и десятков других систем.
Разделение ответственности: Команда, отвечающая за интеграцию с внешними сервисами, может разрабатывать и поддерживать MCP-серверы независимо от команды, строящей агентов.
Единый стандарт: MCP поддерживается Anthropic, OpenAI (через Agents SDK) и другими крупными игроками-.
Минусы MCP
Дополнительная прослойка: Для простых прототипов запуск отдельного MCP-сервера может быть избыточным.
Молодость протокола: Спецификация всё ещё эволюционирует, могут быть breaking changes.
Отладка: Отлаживать взаимодействие через JSON-RPC сложнее, чем просто вызвать Python-функцию (хотя MCP Inspector частично решает эту проблему).
Заключение
Model Context Protocol — это не просто очередной фреймворк, а стандарт взаимодействия, который меняет подход к построению AI-агентов. Вместо того чтобы каждый раз изобретать велосипед для интеграции с очередным API, мы можем использовать готовые MCP-серверы или быстро создавать свои с помощью FastMCP.
В этой статье мы построили агента, который:
Использует внешние инструменты через стандартизированный MCP-протокол;
Имеет доступ к внутренней базе знаний через RAG;
Принимает решения автономно, следуя ReAct-паттерну.
Это архитектура, которая легко масштабируется: добавить поддержку нового сервиса — значит просто подключить ещё один MCP-сервер в конфигурации MultiServerMCPClient. Добавить новые документы — бросить PDF в папку data/.
Будущее за модульными AI-системами, и MCP — один из ключевых кирпичиков в этом фундаменте. Пора внедрять.
Комментарии (10)

L0NGMAN
20.04.2026 09:45В чём плюс использования MCP, если я, например, могу создать skill “create-github-issue”, где укажу, что агент может использовать уже настроенный gh cli tool и создавать issues?

5nook
20.04.2026 09:45Возьмите пример сложнее, где нет готового инструмента. И вам придется дописывать, додумывать внешнее апи, придумать обертку, процессы и логику.
И вы придете к тому что напиши свой mcp

ToniDoni
20.04.2026 09:45Зачем? Нет одного готового инструмента - ну значит просто будет инструкция как вызывать несколько инструментов с парой тройкой примеров использования.

exadmin
20.04.2026 09:45Да хоть тот же калькулятор. Мне кажется операцию извлечения квадратного корня без mcp уже не сделать. А возможно и сложения даже.

kardanShurup Автор
20.04.2026 09:45для одной задачи в пет-проекте CLI действительно проще. Но когда таких интеграций становится хотя бы десяток и они начинают жить в разных проекта?
MCP - это единый стандарт для подключения любых инструментов. Без него каждый скилл или функция превращается в уникальную интеграцию:
Где-то агент вызывает
subprocess.run(['gh', 'issue', 'create'])и парсит stdout.Где-то - дергает REST API.
Где-то - подключается к базе данных через SQL.
Когда таких инструментов 30, а моделей/агентов — 3, выходит
30 × 3 = 90уникальных связок, каждую из которых нужно писать, тестировать и поддерживать. MCP превращает это в30 + 3 = 33связки: каждый инструмент описывается один раз, и любой агент может его использовать по стандартной схеме.подходы MCP и CLI не исключают друг друга. Для локальной разработки и быстрых итераций CLI бывает эффективнее (меньше накладных расходов). А для корпоративных систем, где на первый план выходят безопасность, аудит и переиспользование, MCP - это безальтернативный вариант.

ToniDoni
20.04.2026 09:45У cli тоже логи есть не удаляйте их и будет вам аудит.
Если тула пойдёт в какой то сервис то аудит будет еше на стороне сервиса.
Про безопасности тоже не совсем понятно, как будто бы это пермиссиями решается, а ещё один микросервис в виде mcp как будто бы просто ещё одна точка отказа.
Создатель openclaw прямо говорит что mcp не нужен, агент лучше пусть юзает cli, а openclaw уже начинает появляться в enterprise.

ElPoncho
20.04.2026 09:45Вообще статья довольно странная, чувствуется очень сильный шлейф нейронки, как будто я попросил дипсик кратко рассказать как мне сделать ИИ-агента. Некоторые фразы по типу « MCP — один из ключевых кирпичиков в этом фундаменте. Пора внедрять. » очень сильно сильно это чувство подпитывают.
Также тема агентов весьма поверхностно раскрыта, все задето очень по верхам. Непонятно для каких целей создается этот агент, потому что по факту он почти ничего полезного не умеет, даже код не напишет, ведь у него нет инструментов, которые дадут ему это сделать. MCP позиционируется как что то новое, но в рамках современной скорости развития нейронок он уже давно существует, почти столько же сколько все популярные агенты, а про такой подход как скилы (SKILL.md) вообще не озвучено. RAG зачем-то интегрирован в самого агента, хотя наиболее логично делать его подключаемым, как раз через MCP, автор же и сам пишет про «модульность» агентов.
Тот же RAG имеет кучу нюансов, к примеру если мы хотим индексировать код. MCP тоже имеет свои нюансы. Все это не раскрыто или написаны какие то очевидные плюсы\минусы
Того что в начале обещал автор: «Собираем AI-агента нового поколения» и «В этой статье мы соберём полноценного агента» я тут не увидел. Статье не хватает более глубокой проработки какой то конкретной темы, в целом гайд по сборке абстрактного агента не очень полезен.
Это мое субъективное мнение, никого обидеть не хочу, вполне возможно что я не прав и сам дурак, просто хочется чего то интересного, информацию из статьи на хабре уже много раз видел.
kardanShurup Автор
20.04.2026 09:45Да, я не скрываю, что использовал LLM для помощи с формулировками и черновиками. разжёвывание очевидных вещей и красивые обороты помогал накидывать ИИ. Итоговый текст вычитывал вручную, но «стиль нейронки» местами всё равно пробивается.
Статья задумывалась как вводный туториал для разработчиков, которые вообще не работали с MCP. Если читатель уже собрал десяток агентов и сам пишет SKILL.md, статья ему вряд ли откроет что-то новое. Но для того, кто только смотрит в сторону MCP и хочет понять «как это вообще склеивается в коде», такой уровень детализации в полне себе оправдан.
спасибо за развёрнутую критику. Если будет желание обсудить что-то из затронутого подробнее - я открыт к диалогу.
valentinvvv
Мисье, вы все изложили в заключении, где основное "Молодость протокола". В прод такое пихать страшно. Завтра наказание обновление langchain, он напишнь deprecated in next release, а послезавтра будет перелопачивать всё взаимодействие. А без обнов страшно. AI среда слишком уязвима.
Так же, сразу видно, что вы используете ai для написания статьи и кода. Текст похож на chatgpt, но по коду вроде бы claude sonnet 3.6.
Python 3.11, как пример. Знак "+" - это конечно хорошо, но 3.11 не надо использовать. Он уже не поддерживается и имеет не пофикшееные уязвимости. Так что по этому нужно использовать хотя бы 3.12-slim.
kardanShurup Автор
Про «молодость протокола» и прод. Я специально вынес это в минусы - чтобы сразу подсветить риски. Статья не инструкция «внедрять завтра в продакшен», а туториал для знакомства с подходом. Идея MCP (стандартный интерфейс агента с инструментами) выглядит перспективной, но самому протоколу ещё взрослеть и взрослеть.
Про LangChain.
В статье намеренно использовал
langchain-mcp-adapters(официальную библиотеку) и LangGraph вместо старогоAgentExecutor. Сейчас это «рекомендованный путь», и ломают его не так часто, как ранние версии LangChain. Ну и фиксация версий вrequirements.txt.Есть такое. Статья - результат совместной работы: структуру и логику выстраивал я, код тестировал руками, а черновики текста помогал готовить AI. Считаю такой подход рабочим: LLM берёт на себя рутину с формулировками и docstring'ами, а живой разработчик отвечает за то, чтобы всё было корректно и не галлюцинировало. В 2026-м я считаю это нормальным.
Python 3.11+.
Я написал «3.11+» по инерции, потому что многие консервативные проекты до сих пор сидят на 3.11 из-за старых зависимостей. Но для нового кода рекомендовать нужно минимум 3.12.
Если после прочтения ты такой «ну его в пень, пусть полежит годик» - значит, я свою задачу выполнил: предупредил о рисках. А когда протокол устаканится (а судя по тому, как Anthropic и другие его форсят, это вопрос времени), у тебя уже будет готовая ментальная модель.