MCP для агентаў ІІ: стандартизацыя інтеграціі інструментаў у LangGraph
У гэтай статыце пояснюецца, што саме стандартизуе MCP у системах агентнага ІІ, прагледваючы інтеграцію інструментаў на спецыяльныя задачы і тыя, што базуюцца на MCP у рамках оркестратора LangGraph.
Введэнне & падтварыджэнне
До канцо Часткі 2 система досягла справжняго координаванага стану: група спецыялізаваных агентоў, кожны з якіх адпавядае за вузкаю частку роботы, працуюцых у спяльным стане пад кераваннем оркестрабіста, який выбірае, што трэба запусціць далей. У кожным прыкладзе, аднак, прыймалася гіпотэза, што кожны агент вядома ўжо мае доступ да таго, што яму патрэбна ў тым спяльным стане, і можа яго чытаць калі толькі цэльнае.
Такое заўважэнне рэдка калі практыкуецца ў рэальных умовах. Агенту зазвычай патрэбна інфармацыя, якая знаходзіцца за межами графа: рэкорд з базы дадзеных, адпаведнае адказа з зовнішняй API, фрагмент тэксту з базы знаёмых дадзеных або іншы ресурс, які знаходзіцца за межамі самой системы. Калі агенту патрэбна такая інфармацыя зза меж, ёму трэбна савая дорага для яе отрымання, і якщо кожная з такіх дораг будуе ручна, то для кожнага агента і кожнага зовнішняга ресурса даведзецца практыкаваць аднаковыя процесы інтэграціі, толькі з незначнымі разлікамі.
Самэ гэта повтарэнне і ўсунуць праблема, якую рашае гэты матыял, і ён таксама поясняе, чаму MCP стала такой паспелай тэмай за апошні год. Перш чым вяршыць, чы рэальна його адпрыемка, корисна точна визначыць, якую праблему ён рашае, а таксама разглядзіць, што самэ включалася ў падключэнне інструмента да агента до таго, як з’явіўся MCP.
Проблема, якую стварае MCP
Даўнае раней MCP, каб даць агенту доступ да чаго-небудзь званічна, было неабходна ручнае стварэнне спецыяльной інтеграціі, прызначанай самэй той ресурс, якая формавалася так, як тады здавалася правильной. Адны ресурс могаў быць доступны через REST API, іншы — через кліента базы дадзеных, а ўсё іншае — через SDK, якое мела сваія правіла аутентыкацыі і обробкі памылак. Кожна з гэтых разніц неабходна была безпосередна адбіраць у самы код агента.
Это чырвае сарабаткаўкі, калі ёсць адзін агент, які вярбуецца з адным інструментам. Ён перестае быць чырвым, як толькі система расте ў будзь-якай з мернасцей. Якщо дадаць другі агент, якому патрэбны тыя ж ресурсы, то трэба альбо скопіюваць інтеграцыю, альбо хтось зрэшты вынесе яе у спяльны модуль, зазвычай толькі пасля таго, як уже з’явілася дуплікацыя. А якшо дадаць другі інструмент, тады код агента павінен адразу прымечваць два абсалютна разныя шаблоны інтеграцыі.
Этыя інтэграцыі рэдка калі падобяцца адна другай, таму што нічога не вымагало гэтага. Одна з абгарушчыкаў можа автаматычна прабаваць зноў выканаць неудачныы калл; іншая можа вовсе не прабаваць. Одна можа паказваць прычыны неудач у відпаведных асывтах; іншая можа сховваць іх у поле статусу, якое вызываючый должен памятаць пераканаць. Не існуе спакойнага падзэлу для таго, што на самай працы значыць «праянае агента да інструмента» — кожная інтэграцыя ў канечнасці адпавядае на гэты вопыт на сваіх умовах.
Гэта самэўсёльва тая прасоц, якую прагне закрыць MCP. Ён не прыносіць новых можлівасцей, якіх раней не было у агентаў; ён стандартызуе механізм адкрывання да вялікі ўжо існуючых можлівасцэй, так што падключэнне новага агента да існуючага інструмента, або новага інструмента да існуючага агента, больш не значыць пісання ўсё новай інтеграцыі з нуля. Чы рэальнае выкарыстоўванне MCP адпавядае гэтай обяцанні, стае набагато лёгкая для адгукнення, калі вы побачыце, як на самай працэ выглядае адсутняя стандартызаваная падход у коде — і самэлькі тут будзе продаважная дыскусыя.
До MCP: Падключэнне інструмента способам, які не ўсё час эфектыўны
Разглянем досыць звычайную інтеграцыю: агента, які павінен запытаць зовнішняю систему, які складаецца з коду-з’ёднання, які робіць такое з’єднанне можлівым.
import requests
class LookupToolClient:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url
self.api_key = api_key
def lookup(self, query: str) -> dict:
response = requests.get(
f"{self.base_url}/search",
params={"q": query},
headers={"Authorization": f"Bearer {self.api_key}"},
)
if response.status_code != 200:
return {"error": f"lookup failed: {response.status_code}"}
return response.json()
def agent_node(state: GraphState) -> dict:
client = LookupToolClient(base_url="https://internal-tool.example.com", api_key="...")
result = client.lookup(state["extracted_fields"]["query"])
return {"tool_result": result}
Сама по сабе гэта не мае нічога падобнага да прытворства. Це кампактны HTTP-кліент, адзін-два механізма карэткавання памылак і функцыя, якае ўтварае звязак з ім унутрь яго. Проблэмы пачынаюцца, калі ў групу працы включаецца яшчэ адна змена — на гэты раз не ўжо REST API, а кліент базы дадзеных з абсалютна іншай структурой:
import psycopg2
class RecordsClient:
def __init__(self, connection_string: str):
self.conn = psycopg2.connect(connection_string)
def fetch_record(self, record_id: str) -> dict:
with self.conn.cursor() as cur:
cur.execute("SELECT * FROM records WHERE id = %s", (record_id,))
row = cur.fetchone()
if row is None:
raise ValueError(f"no record found for {record_id}")
return dict(zip([desc[0] for desc in cur.description], row))
Эты два кліента не маюць спяльнага інтэрфейсу, ніякой правілы называння, нават не аднаковага спосабу сігналізацыі пра абяканне: адны вяртае словнік зі спісамі паканаў, а другі проста выклекчвае эксцэпцыю. Кожны агент, які павінен выкарыстоўваць оба, должны самастоятельна выучыць гэтыя особлівасці і врачуваць кожную з іх па своім прыему. Як толькі да гэтага дадаць кожны іншы инструмент, які системе згодна патрэбен — свой кліент, сваю схему аутантыкацыі, свой спосаб абякання — тады тое, што спачатку было каляком малых інтэграцый, ператвараецца на сапраўдны трыбут тыпавага адтрымання, пры чым няма спяльнай структуры, якая бы ўсё гэта з’едыніла.
Гэтае ўсё, што трэба памяцать: не паслаба напісаная інтэграцыя, а проста тыпавая, створаная так, як большасць інтэграцый інструментаў выглядае, калі нічога не прымусвае ўсё гэта мяць аднаковы формат.
Што на самай працэ запростаўляе MCP
З урачунам таго спецыяльнага прыкладу стае значна простэйша точная апісанне таго, каму служыць MCP, без неабяжнай падтрымкі шырэйшых, менавіцейшых тверджэнняў, якія часта прытрымваюцца ў зв’язку з яго.
У сваей сутнасі MCP визначае спакульны пратакол для адкрывання інструментаў для агента, незалежна ад таго, каму служыць інструмент усередзіне чы то якой мовай чы фрэймворкам ён быў створаны. У змену тому, каб кожны інструмент перавозіў свой сае спецыяльны кліент з адпаведными правіламі, ён адкрываецца через сервер MCP, який аанунсавае сваія можлівасці ў прыгадным, стандартным формате: назва, апісанне, схема вводу і схема выходу. Будзь-яны агент, які розумее пратакол, можа знайсці гэты інструмент і вызваць яго так сама, як і будзь-яны іншы інструмент, незалежна ад таго, чы ў основе знаходзіцца канецпункт REST, база дадзеных чы ўсё іншае.
Гэта стандартызацыя распрастраняецца толькі на тры сферы, і важна чыткая дэталізацыя якіх саме, адказна ўважаць, што сфера дзеяння MCP є шырэй, чым на самай праце.
- Адкрыцьце: Агент можа запытаць сервер MCP пра спіс інструментоў, якія ён робіць доступнымі, і атрымаць структураваны адказ, замест таго каб паслужыцца інформацыяй, якая ўвімкнутая жорсткааўказана гдзе-небудзь або задокументаваная окрэмна ад самай рэалізацыі.
- Выклік: Кожны вызов інструмента выконваецца за аднаковым шаблонам, незалежна ад таго, якім є інструмент — запыт з вялічынай, заданай раней, адказ з вялічынай, таксама заданай раней — замест таго каб кожны кліент сам визначаў свой сігнатуру методу і свой тип адказу.
MCP не пазбяглядае неабяжлівай роботы над стварэнням логіки інструмента, а таксама не гарантуе, што інструмент будзе працаваць правільна проста таму, што ён інтеграваны ў протакол. Ён стандартизуее кантракт між агентам і інструментам, але не якосць чы надзеяннае функціонаванне таго, што знаходзіцца за гэтым кантрактом — на гэту тэму статыя зноў вяртаецца пазней, калі практычныя порэванання ясна пакажуць разліку.
Структура сервера MCP
Усвядомляючы вышэўшую стандартазацію, варту паглядзець, калі самэўчынна ёй паўтараюцца. З структурнага точка зору сервер MCP — гэта проста набор адзінакоў, кожны з якіх мае савойшую схему, упакованых у шар протакола, які дазволяе агенту выкарыстоўваць іх у аднаковы спосаб.
Ў мінімуме, каб запрацаваць адзінак у серверы MCP, патрэбна декларацыя трохоў элементаў: назвы, якую агент выкарыстоўвае для ўсунення да яго, схемы, якая описвае апэктыўны вхід, і функцыі, якая запускаецца, калі адзінак фактычна выкананы.
from mcp.server import Server
from mcp.types import Tool
server = Server("lookup-tools")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="lookup",
description="Search for a record by query string",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"],
},
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> dict:
if name == "lookup":
return perform_lookup(arguments["query"])
raise ValueError(f"unknown tool: {name}")
Калі пораўняваць гэта з ранейшымі ад-хок кліентамі, тут выдзеляюця два аспекты. Першы — схема вхідных дадзеных прызначаецца явна з самага пачатку, а не выводзіцца з параметраў, якія прыймае функцыя; гэта значыць, што як агент, так і людзкий пераглядач можаць точна бачыць, калі саме патрэбны інструменты, не заглядаючы ў ўсё ўскладненне ўпрабавання. Другі аспект — серверу трэба выкліквачыць толькі два вхідных пункты: list_tools і call_tool, незалежна ад таго, сколькі інструментаў ён мае чы як адмініструюцься вони разна. Тое, чы інструмент lookup вяршыць роботу з REST API, запытвае базу дадзеных чы робіць ўсё іншае, залишаецца абэрнутым за гэтай двуфункцыйной паверхнею.
З боку агента, запяўленне з гэтым серверам выглядае аднакова, незалежна ад таго, якія інструменты ён выклікае:
from mcp.client import ClientSession
async def call_lookup_tool(query: str) -> dict:
async with ClientSession(server_params) as session:
result = await session.call_tool("lookup", {"query": query})
return result
Пораўняйце гэта з двумя тадышнімі кліентамі, аднам з яых створаны на requests, а другі — на psycopg2; кожны з іх мае свою унікальную структуру та правіла. У гэтым случае код агента застаецца тым самым, незалежна ад таго, як інструмент працюе внутршняя частка — ён вызывае session.call_tool з іменем та наборам параметраў, і ўсегда отрымае рэзультат у той самый формат. Гэта еднакавасць і є справжняй выгода архітектуры сервера, а не самай логіки інструмента, якую такі чынам даведзецца напісаць каму-небудзь.
Перэнастройка той самай інтеграцыі через MCP
Лепшы спосаб з’ясаваць практычныя разліки — это взяць абсолютна той самы інтеграцыйны прыемак, які быў створаны раней, адночасна інструмент для пошуку та кліент для працы з дакументамі, і перабудаваць яго з викорыстаннем MCP. Функцыянал застаецца тым самым, аднойчыныя системы таксама застаюцца тымі ж, зменяецца толькі інтерфейс.
Інструмент для пошуку, які спачатку быў самастоятельным кліентам на базе requests, тепер стае інструментам, зарэгістраваным на сервере MCP:
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="lookup",
description="Search for a record by query string",
inputSchema={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
),
Tool(
name="fetch_record",
description="Fetch a record by ID",
inputSchema={
"type": "object",
"properties": {"record_id": {"type": "string"}},
"required": ["record_id"],
},
),
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> dict:
if name == "lookup":
return perform_lookup(arguments["query"])
elif name == "fetch_record":
return fetch_record_from_db(arguments["record_id"])
raise ValueError(f"unknown tool: {name}")
Ніякой внутрэннай логіцы не было зменяна, perform_lookup як і раней запускае той самы зовнішні API, а fetch_record_from_db як і раней выконвае той самы запит да базы дадзеных. Разлік заключаецца у тым, што эты два інструменты, нават якія працуюць на абсалютна неспраўжніх системах, тепер заявленыя падольгу другі да другога, маюць ідэнтычную структуру схемы та є доступныя чераз тыя ж два входныя пункты.
Значныя візуальныя змены выражаюцца ў вузле, які адпавядае за вызыв іх, адтолькі ёму больш не трэбае інформацыя пра requests чыста psycopg2:
async def agent_node(state: GraphState) -> dict:
async with ClientSession(server_params) as session:
result = await session.call_tool(
"lookup", {"query": state["extracted_fields"]["query"]}
)
return {"tool_result": result}
Пораўняйце гэта з пакульнай версіяю, якая імпортавала конкрэтную бібліятэку HTTP, парсавала адпаведны формат памылак і вымагала абсалютна разлучанай схемы коду проста для вызыву fetch_record заместо lookup. У гэтай версіі вызыв другога інструмента выражаецца ў замене строкі і слоўніка аргументаў, а не у стварэнні другог кліента з яго сае сваясцямі.
Нічога з таго, што насправды робяць гэтыя інструменты, не зменілася. Зменілася толькі тое, што агент, який іх выкарыстоўвае, больш не патрабуе розумець ўсю іх рэалізацыю, а толькі ўпамінанне іх назвы і заявленага схематызму. Гэта тое стандартызаванне, пра якое говорылася раней у серыі; тепер гэта тое, на што можна сацягнуцца ў рэальным кодзе, а не проста пакладацца на веру.
Паралельна: Ad Hoc проты MCP
Колі оба падходы будуць цэлкам створаны, можна перастаць рассуждать пра тэаретычныя перавагі і замест таго безпосередньа паглядзець на тое, чым насправды разлічаюцца версія Ad Hoc і версія MCP.
- Прыткасць, якія трэбаецца для кожнага новага інструмента: У ад-хок падходзе кожны дапамоглівы інструмент прыносіў свага кліента, свою логіку аутэнтыкацыі, свой формат памылак і свой набор правілаў, якія трэба было выучыць, прытаму можна было яго абавяжана выкарыстоўваць. Пад MCP дадаванне інструмента значыць дадаванне ўсё новага элемента да
list_toolsі ўсё новай галінкі ўнутрьcall_tool, прытаму кожная з іх следуе той самым шаблону, як і паказваныя раней інструменты. - Што трэба разумець у кодзе, які выклікае: У вузелі агента ад-хок падходу трэба было імпортаваць конкрэтную бібліятэку кліента і кераваць спецыфічным форматам памылак той бібліятэкі. У вузелі агента MCP не імпортуецца нічога, што была б спецыфічна для інструмента; ён проста выклікае
session.call_toolз іменам і словнікам аргументаў, прытаму гэты выклік будзе аднаковы незалежна ад таго, чы ўоснове знаходзіцца REST-канцэнтр, база дадзеных чы ўсё інша.
LookupToolClient, і кожны агент, який ад него залежыць, автаматычна перадае гэтыя змены. MCP не пазбавляе нас гэтага тэхнічнага адтрымання, але ўзаемадзейнае яго: працэўнасць кожнага інструмента тепер адбываецца через две тыя ж функціі — list_tools і call_tool, замест таго, каб вона была розпытаная між рознымі форматамі кліентаў, якіх існуе столькі, сколькі інструментаў.Нічыя з гэтых рашчынакоў не спрасцавляе самай логікі інструмента. Функцыі perform_lookup і fetch_record_from_db все рава трэба напісаць і прыглядацца за тым, каб яны правільна працавалі. Зменяецца толькі все, што абоўязкова зв’язана з гэтай логікай: як яна адкрываецца, як яя запускаецца, як выяўляюцься абыякавасці, і як великі частак гэтага тыгара павінен несці сабестоячы код агента, у працоўнасці з автаматычным адрабаткам праз дапэўненне едзінага спаканаванага протаколу.
Інтеграцыя інструмента MCP у систему LangGraph (з 2-й часткі)
Да гэтага моманту кожны прыклад быў спрямованы на адзін агент, які ізольавана вызываў адзін інструмент. Цікава будзе запыліць гэты прыемак, пракінуўшы інструмент на адной MCP-паўазе назад у граф мнагах агентоў, створаны ў 2-й часткі, адкуль насправдзе сходзяцься ниткі з усіх трох артыкулаў гэтай серыі.
Памятаеце граф з 2-й часті: крок прыема даных, адразумеванне LLM, механізм правіл, представлены ў 1-й часті, і умовна рутаванне, якае направляе поток або да вузла паведамленняў, або на перагляд чалавеком. Уявіце, што тепер механізм правіл праграмаваецца так, каб перш чым выдаты рашэнне, ён пераканаліваўся з якой-небудзь званачайной системай — такая залежнасць раней вымагала стварэння спецыяльнага кліента, падобнага таму, які быў створаны раней у гэтым артыкуле, які быў падключаны безпосередна да таго вузла.
Калі сервер MCP адкрывае той самы механізм пошуку як інструмент, адпаведальнасці вузла практычна не зменшуюцца. Ён як і раней чытае даны з стану графа і як і раней запісвае сваё рашэнне назад у стан, проста ён праграмаваецца да званачайной системы за дапамою session.call_tool, а не через спецыяльны кліент:
async def rules_engine_node(state: GraphState) -> dict:
async with ClientSession(server_params) as session:
lookup_result = await session.call_tool(
"lookup", {"query": state["extracted_fields"]["category"]}
)
decision = evaluate_rules(state["extracted_fields"], lookup_result)
return {"decision": decision["decision"], "decision_reason": decision["reason"]}
Пазіцыя вузла ў загальнай структуре не параджыцца пад адным з гэтых фактораў. Ён продовжвае застацца на той жа пазіцыі — нижэй за llm_interpretation і вышэй за умовныя галузі, якія вже існавалі ў Частцы 2; яго дзеяння як і раней обмежваюцца мерамі дазволу, заданымі ў адпаведным разделе. Кроме таго, ён заўважваецца пад тым самым ID-ам следу, які описаны ў разделе пра можлівасць аналізу. Едынныя рэальныя змены — у спосабе, якім вузел вяршыць абмен з зовнішнім светам: уместа таго, каб павяржвацца на кліента, створанага спецыяльна для гэтага вузла, ён тепер выкананяе запыт да інструмента, які будзь-кі іншы вузел, чыя бы то ні было была ў графе або ў будучым, можа выкананіць праз той самы шлях.
Што ж, самэць тут, дзе трыя складовыя гэтай серыі з’едаюцца ў адно. Агент, які прымечае толькі тое, што яму чыста ўзначана прымечаць, які працуе ў межах графа, який координуе його разам з іншымі агентамі, і які прабывае да зовнішніх систем через той самы стандартизаваны інтэрфейс, які викорыстоўваюць усе агенты. Ніякой з трох практычных элементаў — механізма правіл, графа чыта MCP — не была патрэбна детальная інформацыя пра два іншыя. Їм было достатнька тэрпелівасці, якую гэта серыя падкрэсляла ўвесь час: вузькія абавязакі, чыста узначаныя контракты і нічога, што магло бы застацца на прыпущэннях.
Кост і затрымка: што на самай працэ аркестрацыі фактычна купуецца
Кожны слой, які дадаюцца ў гэтай серыі, дае певную канструкцыйную стабільнась, і жадная з гэтых стабільнасцей не даецца безкоштовна. Уместа таго, каб залиць вартась непазначанай, корыстна выявіць, што на самае праўда выканаеся з часам адпаведзі, калі запит праходзіць через усе элементы, якія былі описаны ўжо.
Разглянем адзін запит, які працюе праз граф, представлены ў Частцы 2, які тепер расширены за дапамою засоба пошуку на адвароте MCP, прыгаданага вышэй. Шлях адпрацоўкі запита выглядае прыбліжна так: модуль intake адмахоўвае лёгкае форматаванне без выклікаў на зворот, таму ўсё гэта коштае не больш каля калькі мілісэкунд. Этап аналізу LLM выклікае модель, каб тая выявіла структураваныя поля з необработанага запита, і гэта зазвычай являецца самым значным виткам часу ў усім шляху адпрацоўкі, часта дадаючы калькі сотняў мілісэкунд у залежнасці ад выбору моделі і дужыні запита. Выклік механізма правілаў да засоба пошуку через MCP даганяе ў сабе адзін раунд-трып праз сеть, дапамагаючы да часу, які сам засоб патрэбуе для адпаведзення; гэта значны витак, але зазвычай меншы за віток, які выкалікае LLM. Адгукаванне самых правілаў, адколі гэта проста детерміністычная логіка, практычна не коштае нічога. Этапы маршрутызацыі і надсылкі завершальнай паведамлення даганяюць толькі незначную кальку часу да гэтага.
Якшто склаць усія гэтыя показнікі, становіцца ясна карынта: запит, які выкаанаў толькі адна праба гэту модель і аднай званачку да інструмента, мае свой загальны час, які практычна цэлым выкаанаўся за рахунак гэтых двух операцый, пры чым сама коордынацыя графа практычна не вплывае. Вузлы, рэшткі і спяльны стан, представленыя ў Частцы 2, даюць структуру без стварэння рэальнага затрымлення: чытанне і запіс спяльнага об’екта стану є дышэўным. Тое, што насправдзе займае час, — гэта званачка да модель або зовнішняй системы.
Это перакантоввае спосаб прымкі да налагоджэнню выдатков. Дадзенне больш спакетаў, большых галузей маршрутацыі чы ўсё большых перакантрацый у графе практычна не вплывае на шваль, адколі гэта проста вызовы функцый і пошук у словніку. Тое, што насправды спамляе систему, — цэлком кожны вызов LLM і кожны вызов зовнішняго інструмента, які знаходзіцца на критычнай дорозе запросу. Система, пабудаваная з трох агентаў, кожны з якіх вызывае модель аднаго за іншым, будзе працаваць значна медленней, чым тая, якая вызывае модель толькі аднажды, незалежна ад таго, насколькі чыстае ўсё інша оркестрацыя.
Практычны вывад здесь просты: калі для рабочага процесу важна затрэмтанасць, не трэба спачатку аналізаваць форму графа. Спачатку трэба пісаць колькі разоў запускаецца модель і скількі вызоваў званых засобаў павінен прыйняць звычайны запит, перш чым ён завершыцца, і спытацца, чы не можна якія-небудзь з іх выконваць паралельна, а не па серіі, чы не можна ўзагалі іх адмаўляць запытам, якім яны не патрэбны.
Што MCP не рашае
Цікава будзе таксама чыста адказваць на пытанні пра межы MCP, як і пра яго перавагі, пра якія говорылася раней, адтолькі бо большасць матэрыялаў на эту тэму сфокусаваныя на перавагах і рэдка зупіняюцца на межах. Тые ж тры аспекты, якія обгавароўваліся там — адкрыць, запуск і карэнтаванне памылак — заслуговуюць на ўвагу з працоўнай стороны.
- Стандартызацыя процэсу адкрыціі та вызывання не выправляе практычна некачэнага інструмента: стандарт MCP стандартызуе спосаб прызначэння та вызывання інструмента, а не тое, што відбываецца ў яго ўнутранасці. Інструмент з медленным, ненадзеяным або паслаба структураваным рэалізаваннем залишаецца такім жа медленным, ненадзеяным та паслаба структураваным, калі ён знаходзится за серверам MCP. Протакол пераносіць гэтую некалякост, пераводзячы яе з коду вызывання ў самае рэалізаванне інструмента, але гэта не прычыняе ўсунення некалякості.
Нічыя з гэтых пунктаў не спрацоўвае проты адмацавання MCP. Цэта прыгадка пра тое, што выбор пратаколу не заменяе інжынерную работу, якая все ўсё трэба адрабатваць пад ягом. Змены, якія прыносіць MCP, рэальныя, як паказана ў паказваных раней раздзелах, але яны ўжошчыя, чым концэпція «агенты, якія праеўваюць з’язакі з інструментамі» в цэлыя, і важка будзе буць точным ў визначэнні таго, дзе самэў гэтыя межы, перш чым вырашаць, чыі адмацавання мае сэнс — гэта тое, чым займаецца наступны раздзел.
Калі варта адмацаваць MCP
Усвядомляючы вышэй пераказаныя компромісы, тут немае універсальнай адпаведзі — няма чыстага «всегда адмацавайце яго» чы «ніколі не трэба». Натоўп значнае — гэта перакананне ў нешырокім наборы конкрэтных умоваў пры выборе ўжывання яго ў конкрэтным системе.
- Большаму колькасці агентаў патрэбны будуць тыя ж засобы. Паўнае большасць выгод, якія описваліся раней, стаюць можлівымі заўдовжка павторнага выкорыстоўвання: другі агент можа падключыцца да вялікага сервера, які ўжо створены, замест таго, каб дублюваць кліента чы скарыгаваць яго пасля таго. Калі є толькі адзін агент і адзін засоб, такая выгода проста яшчэ не існуе — няма чаго дзеліць — і спосаб, описваны раней, застаецца простым выборам для такога конкрэтнага случая.
- Очакуецца, што колькасць засобаў будзе растуць. Стандартызаваны інтерфейс стае цэннейшым, калі за яго магчыма выкорыстоўваць больш засобаў. Калі є два чы тры засобы, запуск спецыяльнага сервера можа не будзьць цэнным з-за дадатковых витатаў. Калі ж працуеце з дзесяткам чы двумяццацю засобаў — кожны з якіх інакш патрэбаваў бы свайго сабскіпанага кліента — тырота з адтрымкай спосабу, описванага раней, пачынае стаць сэрйязным прытварам.
З іншай жа боку, гэта не падходзіць для аднаго агента, які вяршыць пераказваннё з адным стабільным, добра разумелым інструментам, які не будзе зменяцца. У такім случае стварэнне спецыяльнага кліента є быстрейшым рашэнням, адколі трэба падтрымваць менш элементаў, і коордынацыя, яку прыносіць MCP, не мае другог корыстніка, які мог бы ёю скорыстацца.
Практычныя тэсты, якія можна застосавіць у гэтым случае, супадаюць з тымі, якія раней викорыстоўваліся для самага механізма правіл: чы розглядная складнасць дапамагае распрацаваць проблему, з якой фактычна сталкаецца гэта система на ўжо існуючым етапе, чы ж яе прыймаюць проста таму, што гэта ў модзе як рашэння проблемы, якой у системы ўсё ще няма.
Вывад: Заканчэнне серыі
У трохім стацтутах пашаго чынам развивалася адна система, пры чым кожны слой будаваўся на базе паканяго. У першым выпуску быў створены адзін агент, які быў дастаткова надзеяны, каб яму могла быць дасунута рэальная прынятка рашэння, што было досягнуце строгым аддзеленнем інтэрпретаціі ад самага акту прынятка рашэння. У другім выпуску таму агенту была даўана кампанія – кальколька спецыялізаваных агентоў было з’еднанае ў граф, які дазволяў ім аднасабліва розпадзеляць стан, пры чым гэта было захавана за дапамогою ясных разрашэнняў і можлівасці адстежэння ўсьго процесу, так што кожны запит мог быць праследаваны з моменту його падачы да моменту выйшчы. У гэтым стацтуте была заполнена засталая праслед – як тыя агенты можаюць дзейваць за межамі графа – шляхом стандартазавання ўспрыемлівасці через MCP у тых ситуацыях, дзе гэта практычна мае сэнс, а таксама чыста і ясна было адзначана, дзе гэта не прыносіць практычных выгод.
Ні адзін з эўсёх трох галавных элементаў сам па сабе не ёсць выключна складным. Тое, што насправдзе робіць створаную систему надзеямай, — гэта адна прычынка, якая павтараецца на кожным роўні без выключэння: адпаведальнасці застаюцца часткамі, кантракты застаюцца яснымі, і нічога не залишаецца на прыпущэннях чы робіцца таямна на задньым плане. Гэта прычынка ёсць справжнім тэмайам гэтай серыі, больш ніж будзь-які конкрэтны інструмент — LangGraph і MCP проста яўляюцца фрэймворкамі, якія викорыстоўваюцца для ўпрактыкавання гэтых прынцыпаў, але базовыя прынцыпы застаюцца тымі ж, незалежна ад таго, якія інструменты вы выберазе.
Спадзяючыся на чытанне
- Агентныя AI: ад мовных модэляў да автонамных агентаў — структураваны апіс, як LLM-ы ператвараюцца ў агентныя системы за дапамогою інструментаў, памяці, планавання, архітектураў з калькама агентаў і інтэграцыі MCP.