{"id":2473,"date":"2025-09-17T15:02:58","date_gmt":"2025-09-17T13:02:58","guid":{"rendered":"https:\/\/davidka.net\/ru\/?p=2473"},"modified":"2025-09-22T02:14:05","modified_gmt":"2025-09-22T00:14:05","slug":"ai-agent-with-mcp","status":"publish","type":"post","link":"https:\/\/ru.davidka.net\/ru\/ai-agent-with-mcp\/","title":{"rendered":"\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0441 LangGraph \u0438 MCP"},"content":{"rendered":"\n<p class=\"has-neve-link-color-color has-text-color has-link-color has-medium-font-size wp-elements-4f14459c04625fde3482aeabdfc3bf55 wp-block-paragraph\">\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0445 \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 Python. \u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0442\u0435\u043e\u0440\u0438\u044e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 LangChain \u0438 LangGraph. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043a\u043e\u0434\u0435, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0426\u0435\u043b\u044c:<\/strong>&nbsp;\u0421 \u043d\u0443\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u0432\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u0410\u0433\u0435\u043d\u0442-\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440:<\/strong>&nbsp;\u043c\u043d\u043e\u0433\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0439, \u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u043d\u043e \u0431\u0435\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.<\/li>\n\n\n\n<li><strong>\u0410\u0433\u0435\u043d\u0442-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442:<\/strong>&nbsp;\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0430\u0433\u0435\u043d\u0442 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0438 \u0432\u0435\u0431-\u043f\u043e\u0438\u0441\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b MCP, \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0435.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043b\u0443\u0447\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438: \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439, \u0432\u044b\u0431\u043e\u0440 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n\n\n\n<div id=\"rtoc-mokuji-wrapper\" class=\"rtoc-mokuji-content frame2 preset1 animation-fade rtoc_open default\" data-id=\"2473\" data-theme=\"Neve - Davidka\">\n\t\t\t<div id=\"rtoc-mokuji-title\" class=\"rtoc_btn_none rtoc_left\">\n\t\t\t\n\t\t\t<span>In Questo Articolo<\/span>\n\t\t\t<\/div><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u043a\u0440\u0430\u0442\u043a\u043e-\u043e-\u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438-\u0430\u0433\u0435\u043d\u0442-\u0438-\u043c\u043e\u0441\u0442-mcp\">\u041a\u0440\u0430\u0442\u043a\u043e \u043e \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438: \u0410\u0433\u0435\u043d\u0442 \u0438 \u043c\u043e\u0441\u0442 MCP<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-1-\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430-\u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0433\u043e-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\">\u0427\u0430\u0441\u0442\u044c 1: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/a><ul class=\"rtoc-mokuji mokuji_none level-3\"><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-1-\u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435-\u0438-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\">\u0428\u0430\u0433 1: \u0412\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-2-\u043f\u0440\u043e\u0435\u043a\u0442-1--\u0430\u0433\u0435\u043d\u0442-\u0434\u043b\u044f-\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438-\u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439\">\u0427\u0430\u0441\u0442\u044c 2: \u041f\u0440\u043e\u0435\u043a\u0442 1 \u2014 \u0410\u0433\u0435\u043d\u0442 \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439<\/a><ul class=\"rtoc-mokuji mokuji_none level-3\"><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-1-\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435-\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\">\u0428\u0430\u0433 1: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-2-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f-\u0443\u0437\u043b\u043e\u0432-\u0433\u0440\u0430\u0444\u0430\">\u0428\u0430\u0433 2: \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u0437\u043b\u043e\u0432 \u0433\u0440\u0430\u0444\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-3-\u0441\u0431\u043e\u0440\u043a\u0430-\u0438-\u0437\u0430\u043f\u0443\u0441\u043a-\u0433\u0440\u0430\u0444\u0430\">\u0428\u0430\u0433 3: \u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0433\u0440\u0430\u0444\u0430<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-3-\u043f\u0440\u043e\u0435\u043a\u0442-2--\u0430\u0433\u0435\u043d\u0442-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442-\u0441-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438-mcp\">\u0427\u0430\u0441\u0442\u044c 3: \u041f\u0440\u043e\u0435\u043a\u0442 2 \u2014 \u0410\u0433\u0435\u043d\u0442-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 (MCP)<\/a><ul class=\"rtoc-mokuji mokuji_none level-3\"><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-1-\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439\">\u0428\u0430\u0433 1: \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-2-\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435-\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f-\u0434\u043b\u044f-\u0434\u0438\u0430\u043b\u043e\u0433\u0430\">\u0428\u0430\u0433 2: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u043b\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-3-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f-\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e-\u0433\u0440\u0430\u0444\u0430\">\u0428\u0430\u0433 3: \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0448\u0430\u0433-4-\u0437\u0430\u043f\u0443\u0441\u043a-\u0438-\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\">\u0428\u0430\u0433 4: \u0417\u0430\u043f\u0443\u0441\u043a \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/li><\/ul><\/li><\/ol><\/div><h3 class=\"wp-block-heading\" id=\"\u043a\u0440\u0430\u0442\u043a\u043e-\u043e-\u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438-\u0430\u0433\u0435\u043d\u0442-\u0438-\u043c\u043e\u0441\u0442-mcp\">\u041a\u0440\u0430\u0442\u043a\u043e \u043e \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438: \u0410\u0433\u0435\u043d\u0442 \u0438 \u043c\u043e\u0441\u0442 MCP<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043a\u043e\u0434\u0443, \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c \u0434\u0432\u0430 \u043f\u043e\u043d\u044f\u0442\u0438\u044f:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u0418\u0418-\u0430\u0433\u0435\u043d\u0442:<\/strong>&nbsp;\u044d\u0442\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430, \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432\u043e\u043a\u0440\u0443\u0433 \u0446\u0438\u043a\u043b\u0430 \u00ab\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435-\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u00bb. \u041e\u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e LLM \u0440\u0435\u0448\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442), \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u0446\u0438\u043a\u043b, \u043f\u043e\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0430.<\/li>\n\n\n\n<li><strong>MCP (Model Context Protocol):<\/strong>&nbsp;\u044d\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043b\u0443\u0436\u0438\u0442&nbsp;<strong>\u043c\u043e\u0441\u0442\u043e\u043c<\/strong>&nbsp;\u043c\u0435\u0436\u0434\u0443 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u0430\u0433\u0435\u043d\u0442\u0430 \u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0430\u0433\u0435\u043d\u0442\u0443 \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438, API \u0438\u043b\u0438 \u043f\u043e\u0438\u0441\u043a\u043e\u043c, \u043d\u0435 \u0437\u0430\u0431\u043e\u0442\u044f\u0441\u044c \u043e \u0434\u0435\u0442\u0430\u043b\u044f\u0445 \u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-1-\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430-\u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0433\u043e-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\">\u0427\u0430\u0441\u0442\u044c 1: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-1-\u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435-\u0438-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\">\u0428\u0430\u0433 1: \u0412\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b&nbsp;<code class=\"\" data-line=\"\">requirements.txt<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\"># \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438\nlangchain\nlanggraph\n\n# \u0410\u0434\u0430\u043f\u0442\u0435\u0440\u044b \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439\nlangchain-openai\nlangchain-google-genai\nlangchain-mistralai\nlangchain-community # \u0414\u043b\u044f Ollama\n\n# \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b\nlangchain-mcp-adapters\nmcp\nollama\n\n# \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435\npython-dotenv\ntenacity # \u0414\u043b\u044f \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">pip install -r requirements.txt```\n\n&lt;em&gt;#### \u0428\u0430\u0433 2: \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f API-\u043a\u043b\u044e\u0447\u0435\u0439&lt;\/em&gt;\n\n\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b `.env` \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439:\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">OPENAI_API_KEY=&#187;sk-&#8230;&#187; GOOGLE_API_KEY=&#187;AIzaSy&#8230;&#187; MISTRAL_API_KEY=&#187;&#8230;&#187; BRAVE_API_KEY=&#187;&#8230;&#187; # \u0414\u043b\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0432\u0435\u0431-\u043f\u043e\u0438\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 MCP<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">\n#### \u0428\u0430\u0433 3: \u041f\u0430\u0442\u0442\u0435\u0440\u043d \u00ab\u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0435\u0439\u00bb\n\n\u0427\u0442\u043e\u0431\u044b \u0433\u0438\u0431\u043a\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u043c\u0438 \u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u043a\u043e\u0434 \u0430\u0433\u0435\u043d\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u00ab\u0444\u0430\u0431\u0440\u0438\u043a\u0430\u00bb.\n\n```python\n# llm_factory.py\nimport os\nfrom enum import Enum\nfrom dotenv import load_dotenv\nfrom langchain_openai import ChatOpenAI\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_mistralai import ChatMistralAI\nfrom langchain_community.chat_models import ChatOllama\n\nload_dotenv()\n\nclass ModelProvider(Enum):\n    OPENAI = &quot;openai&quot;\n    GEMINI = &quot;gemini&quot;\n    MISTRAL_API = &quot;mistral_api&quot;\n    OLLAMA = &quot;ollama&quot;\n\ndef get_llm(provider: ModelProvider, model_name: str = None):\n    &quot;&quot;&quot;\u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 LLM.&quot;&quot;&quot;\n    if provider == ModelProvider.OPENAI:\n        return ChatOpenAI(model=model_name or &quot;gpt-4o-mini&quot;, temperature=0)\n    elif provider == ModelProvider.GEMINI:\n        return ChatGoogleGenerativeAI(model=model_name or &quot;gemini-1.5-flash&quot;, temperature=0)\n    elif provider == ModelProvider.MISTRAL_API:\n        return ChatMistralAI(model=model_name or &quot;mistral-large-latest&quot;, temperature=0)\n    elif provider == ModelProvider.OLLAMA:\n        # \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u0430 Ollama \u0441 \u043d\u0443\u0436\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e\n        # docker exec -it ollama ollama pull mistral\n        return ChatOllama(model=model_name or &quot;mistral&quot;, temperature=0)\n    raise ValueError(f&quot;\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u043c\u043e\u0434\u0435\u043b\u0438: {provider}&quot;)\n\n# \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\nif __name__ == &quot;__main__&quot;:\n    # local_llm = get_llm(ModelProvider.OLLAMA)\n    openai_llm = get_llm(ModelProvider.OPENAI)\n    response = openai_llm.invoke(&quot;\u041e\u0431\u044a\u044f\u0441\u043d\u0438 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e RAG \u0432 \u0442\u0440\u0435\u0445 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445.&quot;)\n    print(response.content)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-2-\u043f\u0440\u043e\u0435\u043a\u0442-1--\u0430\u0433\u0435\u043d\u0442-\u0434\u043b\u044f-\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438-\u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439\">\u0427\u0430\u0441\u0442\u044c 2: \u041f\u0440\u043e\u0435\u043a\u0442 1 \u2014 \u0410\u0433\u0435\u043d\u0442 \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u042d\u0442\u043e\u0442 \u0430\u0433\u0435\u043d\u0442 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c LangGraph \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f&nbsp;<strong>\u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0430<\/strong>&nbsp;\u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e \u0442\u0440\u0451\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-1-\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435-\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\">\u0428\u0430\u0433 1: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u00ab\u043f\u0430\u043c\u044f\u0442\u044c\u00bb \u043d\u0430\u0448\u0435\u0433\u043e \u0433\u0440\u0430\u0444\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0443\u0437\u043b\u0430 \u043a \u0443\u0437\u043b\u0443.<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# vacancy_classifier.py&lt;\/em&gt;\nfrom typing import TypedDict, Dict\n\nclass ClassificationState(TypedDict):\n    &quot;&quot;&quot;\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430-\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430.&quot;&quot;&quot;\n    description: str          &lt;em&gt;# \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442&lt;\/em&gt;\n    job_type: str             &lt;em&gt;# \u0422\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b (\u043f\u0440\u043e\u0435\u043a\u0442\u043d\u0430\u044f\/\u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u044f)&lt;\/em&gt;\n    category: str             &lt;em&gt;# \u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u044f&lt;\/em&gt;\n    search_type: str          &lt;em&gt;# \u0426\u0435\u043b\u044c (\u0438\u0449\u0443 \u0440\u0430\u0431\u043e\u0442\u0443\/\u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044f)&lt;\/em&gt;\n    classification_log: list  &lt;em&gt;# \u041b\u043e\u0433 \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438&lt;\/em&gt;\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-2-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f-\u0443\u0437\u043b\u043e\u0432-\u0433\u0440\u0430\u0444\u0430\">\u0428\u0430\u0433 2: \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u0437\u043b\u043e\u0432 \u0433\u0440\u0430\u0444\u0430<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u041a\u0430\u0436\u0434\u044b\u0439 \u0443\u0437\u0435\u043b \u2014 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u0432\u043e\u044e \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import asyncio\nimport json\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom llm_factory import get_llm, ModelProvider\n\nclass VacancyClassifierAgent:\n    def __init__(self):\n        self.llm = get_llm(ModelProvider.OPENAI, model_name=&quot;gpt-4o-mini&quot;)\n\n    async def _classify_job_type(self, state: ClassificationState) -&gt; ClassificationState:\n        &quot;&quot;&quot;\u0423\u0437\u0435\u043b 1: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b.&quot;&quot;&quot;\n        prompt = ChatPromptTemplate.from_messages(&#091;\n            (&quot;system&quot;, &quot;\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438 \u0442\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b. \u041e\u0442\u0432\u0435\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c &#039;\u043f\u0440\u043e\u0435\u043a\u0442\u043d\u0430\u044f&#039; \u0438\u043b\u0438 &#039;\u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u044f&#039;.&quot;),\n            (&quot;human&quot;, &quot;\u0422\u0435\u043a\u0441\u0442 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438:\\n\\n{description}&quot;)\n        ])\n        chain = prompt | self.llm\n        result = await chain.ainvoke({&quot;description&quot;: state&#091;&quot;description&quot;]})\n        \n        state&#091;&quot;job_type&quot;] = result.content.strip()\n        state&#091;&quot;classification_log&quot;].append(&quot;\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u0442\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b.&quot;)\n        return state\n\n    async def _classify_category(self, state: ClassificationState) -&gt; ClassificationState:\n        &quot;&quot;&quot;\u0423\u0437\u0435\u043b 2: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u0438.&quot;&quot;&quot;\n        &lt;em&gt;# \u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0438\u043b\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445&lt;\/em&gt;\n        categories = &#091;&quot;Python-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a&quot;, &quot;\u0414\u0438\u0437\u0430\u0439\u043d\u0435\u0440&quot;, &quot;\u041c\u0430\u0440\u043a\u0435\u0442\u043e\u043b\u043e\u0433&quot;, &quot;3D-\u0430\u043d\u0438\u043c\u0430\u0442\u043e\u0440&quot;]\n        prompt = ChatPromptTemplate.from_messages(&#091;\n            (&quot;system&quot;, f&quot;\u0412\u044b\u0431\u0435\u0440\u0438 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0443\u044e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430: {&#039;, &#039;.join(categories)}.&quot;),\n            (&quot;human&quot;, &quot;\u0422\u0435\u043a\u0441\u0442 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438:\\n\\n{description}&quot;)\n        ])\n        chain = prompt | self.llm\n        result = await chain.ainvoke({&quot;description&quot;: state&#091;&quot;description&quot;]})\n        \n        state&#091;&quot;category&quot;] = result.content.strip()\n        state&#091;&quot;classification_log&quot;].append(&quot;\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f.&quot;)\n        return state\n\n    async def _classify_search_type(self, state: ClassificationState) -&gt; ClassificationState:\n        &quot;&quot;&quot;\u0423\u0437\u0435\u043b 3: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0446\u0435\u043b\u044c \u043f\u043e\u0438\u0441\u043a\u0430.&quot;&quot;&quot;\n        prompt = ChatPromptTemplate.from_messages(&#091;\n            (&quot;system&quot;, &quot;\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438 \u0446\u0435\u043b\u044c \u0430\u0432\u0442\u043e\u0440\u0430. \u041e\u0442\u0432\u0435\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c &#039;\u043f\u043e\u0438\u0441\u043a \u0440\u0430\u0431\u043e\u0442\u044b&#039; \u0438\u043b\u0438 &#039;\u043f\u043e\u0438\u0441\u043a \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044f&#039;.&quot;),\n            (&quot;human&quot;, &quot;\u0422\u0435\u043a\u0441\u0442 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438:\\n\\n{description}&quot;)\n        ])\n        chain = prompt | self.llm\n        result = await chain.ainvoke({&quot;description&quot;: state&#091;&quot;description&quot;]})\n        \n        state&#091;&quot;search_type&quot;] = result.content.strip()\n        state&#091;&quot;classification_log&quot;].append(&quot;\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u0446\u0435\u043b\u044c \u043f\u043e\u0438\u0441\u043a\u0430.&quot;)\n        return state\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-3-\u0441\u0431\u043e\u0440\u043a\u0430-\u0438-\u0437\u0430\u043f\u0443\u0441\u043a-\u0433\u0440\u0430\u0444\u0430\">\u0428\u0430\u0433 3: \u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0433\u0440\u0430\u0444\u0430<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0443\u0437\u043b\u044b \u0432 \u0435\u0434\u0438\u043d\u044b\u0439 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441.<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# ... \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 VacancyClassifierAgent ...&lt;\/em&gt;\nfrom langgraph.graph import StateGraph, END\n\n    def build_graph(self):\n        &quot;&quot;&quot;\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0433\u0440\u0430\u0444 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439.&quot;&quot;&quot;\n        workflow = StateGraph(ClassificationState)\n        \n        workflow.add_node(&quot;job_type_classifier&quot;, self._classify_job_type)\n        workflow.add_node(&quot;category_classifier&quot;, self._classify_category)\n        workflow.add_node(&quot;search_type_classifier&quot;, self._classify_search_type)\n        \n        workflow.set_entry_point(&quot;job_type_classifier&quot;)\n        workflow.add_edge(&quot;job_type_classifier&quot;, &quot;category_classifier&quot;)\n        workflow.add_edge(&quot;category_classifier&quot;, &quot;search_type_classifier&quot;)\n        workflow.add_edge(&quot;search_type_classifier&quot;, END)\n        \n        return workflow.compile()\n\nasync def main():\n    agent = VacancyClassifierAgent()\n    graph = agent.build_graph()\n    \n    description = &quot;\u0418\u0449\u0435\u043c \u043e\u043f\u044b\u0442\u043d\u043e\u0433\u043e Python-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043d\u0430 \u0444\u0443\u043b\u0442\u0430\u0439\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0432 \u0441\u0444\u0435\u0440\u0435 \u0444\u0438\u043d\u0442\u0435\u0445.&quot;\n    \n    initial_state = ClassificationState(\n        description=description,\n        job_type=&quot;&quot;, category=&quot;&quot;, search_type=&quot;&quot;,\n        classification_log=&#091;]\n    )\n    \n    final_state = await graph.ainvoke(initial_state)\n    \n    print(&quot;--- \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 ---&quot;)\n    print(json.dumps(final_state, indent=2, ensure_ascii=False))\n\nif __name__ == &quot;__main__&quot;:\n    asyncio.run(main())\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-3-\u043f\u0440\u043e\u0435\u043a\u0442-2--\u0430\u0433\u0435\u043d\u0442-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442-\u0441-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438-mcp\">\u0427\u0430\u0441\u0442\u044c 3: \u041f\u0440\u043e\u0435\u043a\u0442 2 \u2014 \u0410\u0433\u0435\u043d\u0442-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 (MCP)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u042d\u0442\u043e\u0442 \u0430\u0433\u0435\u043d\u0442 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442&nbsp;<strong>\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443<\/strong>, \u0433\u0434\u0435 \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-1-\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439\">\u0428\u0430\u0433 1: \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u0414\u043b\u044f \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043c\u0438\u0440\u043e\u043c, \u0432\u0430\u0436\u043d\u0430 \u043d\u0430\u0434\u0435\u0436\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f.<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# mcp_agent_config.py&lt;\/em&gt;\nfrom dataclasses import dataclass, field\nimport os\nfrom llm_factory import ModelProvider\n\n@dataclass\nclass AgentConfig:\n    workdir: str = &quot;.\/agent_workdir&quot;\n    model_provider: ModelProvider = ModelProvider.OLLAMA\n    \n    def __post_init__(self):\n        &quot;&quot;&quot;\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.&quot;&quot;&quot;\n        os.makedirs(self.workdir, exist_ok=True)\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-2-\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435-\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f-\u0434\u043b\u044f-\u0434\u0438\u0430\u043b\u043e\u0433\u0430\">\u0428\u0430\u0433 2: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u043b\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u0430<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# mcp_agent.py&lt;\/em&gt;\nfrom typing import TypedDict, Annotated, Sequence\nfrom langchain_core.messages import BaseMessage\nimport operator\n\nclass AgentState(TypedDict):\n    messages: Annotated&#091;Sequence&#091;BaseMessage], operator.add]\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-3-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f-\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e-\u0433\u0440\u0430\u0444\u0430\">\u0428\u0430\u0433 3: \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0430<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">\u0413\u0440\u0430\u0444 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0434\u0432\u0443\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432 \u0438 \u0443\u0441\u043b\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0446\u0438\u043a\u043b \u00ab\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435-\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u00bb.<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from langgraph.graph import StateGraph, END\nfrom langgraph.prebuilt import ToolExecutor\nfrom langchain_mcp_adapters.langchain import V1ToolExecutor\nfrom langchain_mcp_adapters.clients import MultiServerMCPClient\nfrom llm_factory import get_llm\nfrom mcp_agent_config import AgentConfig\n\nclass MCPAgent:\n    def __init__(self, config: AgentConfig):\n        self.config = config\n        self.llm = get_llm(config.model_provider)\n        self.tools = &#091;]\n        self.tool_executor = None\n\n    async def setup_tools(self):\n        &quot;&quot;&quot;\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 MCP.&quot;&quot;&quot;\n        mcp_config = {\n            &quot;filesystem&quot;: {\n                &quot;command&quot;: &quot;npx&quot;, &quot;args&quot;: &#091;&quot;-y&quot;, &quot;@modelcontextprotocol\/server-filesystem&quot;, self.config.workdir],\n                &quot;transport&quot;: &quot;stdio&quot;\n            },\n            &lt;em&gt;# \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 brave-search, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043a\u043b\u044e\u0447 BRAVE_API_KEY&lt;\/em&gt;\n        }\n        mcp_client = MultiServerMCPClient(mcp_config)\n        self.tools = await mcp_client.get_tools()\n        self.tool_executor = ToolExecutor(&#091;V1ToolExecutor(tool) for tool in self.tools])\n        \n        &lt;em&gt;# \u041f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043a \u043c\u043e\u0434\u0435\u043b\u0438&lt;\/em&gt;\n        self.llm = self.llm.bind_tools(self.tools)\n\n    def _should_continue(self, state: AgentState):\n        &quot;&quot;&quot;\u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434: \u0440\u0435\u0448\u0430\u0435\u043c, \u043d\u0443\u0436\u043d\u043e \u043b\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442.&quot;&quot;&quot;\n        last_message = state&#091;&#039;messages&#039;]&#091;-1]\n        if not last_message.tool_calls:\n            return &quot;end&quot;\n        return &quot;continue&quot;\n\n    def _call_model(self, state: AgentState):\n        &quot;&quot;&quot;\u0423\u0437\u0435\u043b 1: \u0412\u044b\u0437\u043e\u0432 LLM \u0434\u043b\u044f \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f.&quot;&quot;&quot;\n        response = self.llm.invoke(state&#091;&#039;messages&#039;])\n        return {&quot;messages&quot;: &#091;response]}\n\n    def _call_tool(self, state: AgentState):\n        &quot;&quot;&quot;\u0423\u0437\u0435\u043b 2: \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430.&quot;&quot;&quot;\n        last_message = state&#091;&#039;messages&#039;]&#091;-1]\n        tool_call = last_message.tool_calls&#091;0]\n        \n        action = {&quot;tool&quot;: tool_call&#091;&quot;name&quot;], &quot;tool_input&quot;: tool_call&#091;&quot;args&quot;], &quot;log&quot;: &quot;&quot;}\n        response = self.tool_executor.invoke(action)\n        \n        return {&quot;messages&quot;: &#091;response]}\n\n    def build_graph(self):\n        workflow = StateGraph(AgentState)\n        workflow.add_node(&quot;agent&quot;, self._call_model)\n        workflow.add_node(&quot;action&quot;, self._call_tool)\n        \n        workflow.set_entry_point(&quot;agent&quot;)\n        workflow.add_conditional_edges(\n            &quot;agent&quot;,\n            self._should_continue,\n            {&quot;continue&quot;: &quot;action&quot;, &quot;end&quot;: END}\n        )\n        workflow.add_edge(&quot;action&quot;, &quot;agent&quot;)\n        \n        return workflow.compile()\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"\u0448\u0430\u0433-4-\u0437\u0430\u043f\u0443\u0441\u043a-\u0438-\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\">\u0428\u0430\u0433 4: \u0417\u0430\u043f\u0443\u0441\u043a \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/h4>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# ... \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 mcp_agent.py ...&lt;\/em&gt;\nimport asyncio\nfrom langchain_core.messages import HumanMessage\nfrom tenacity import retry, stop_after_attempt, wait_fixed\n\n@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))\nasync def run_agent_task(graph, task):\n    &quot;&quot;&quot;\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043e\u043a.&quot;&quot;&quot;\n    return await graph.ainvoke({&quot;messages&quot;: &#091;HumanMessage(content=task)]})\n\nasync def main():\n    config = AgentConfig(model_provider=ModelProvider.OPENAI) &lt;em&gt;# \u0438\u043b\u0438 OLLAMA&lt;\/em&gt;\n    agent = MCPAgent(config)\n    await agent.setup_tools()\n    graph = agent.build_graph()\n    \n    task = &quot;\u0421\u043e\u0437\u0434\u0430\u0439 \u0444\u0430\u0439\u043b &#039;hello.txt&#039; \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0438 \u0437\u0430\u043f\u0438\u0448\u0438 \u0432 \u043d\u0435\u0433\u043e &#039;\u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0438\u0440!&#039;.&quot;\n    result = await run_agent_task(graph, task)\n    \n    print(&quot;\\n--- \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u0430\u0433\u0435\u043d\u0442\u0430 ---&quot;)\n    print(result&#091;&#039;messages&#039;]&#091;-1].content)\n\nif __name__ == &quot;__main__&quot;:\n    asyncio.run(main())\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440&nbsp;<code class=\"\" data-line=\"\">tenacity<\/code>&nbsp;\u0434\u043b\u044f \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u0438 \u2014 \u0435\u0441\u043b\u0438 \u0432\u044b\u0437\u043e\u0432 \u0430\u0433\u0435\u043d\u0442\u0430 \u0443\u043f\u0430\u0434\u0435\u0442 \u0438\u0437-\u0437\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438, \u043e\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0441\u044f.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0434\u0432\u0430 \u0442\u0438\u043f\u0430 \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u0433\u0440\u0430\u0444<\/strong>&nbsp;\u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u0441 \u0447\u0435\u0442\u043a\u043e\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u0448\u0430\u0433\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0438\u043b\u0438 \u043c\u043d\u043e\u0433\u043e\u044d\u0442\u0430\u043f\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437.<\/li>\n\n\n\n<li><strong>\u0426\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0433\u0440\u0430\u0444<\/strong>&nbsp;\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043e\u0432 \u0438 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u0445 \u0440\u0435\u0448\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u2014 \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043d\u0430 \u0443\u0437\u043b\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u043e\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u2014 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0445 \u0418\u0418-\u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041d\u0430\u0447\u0430\u0432 \u0441 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c, \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u044f \u0432\u0441\u0435 \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0438 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0432\u0430\u0448\u0438\u0445 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.&nbsp;<img decoding=\"async\" src=\"https:\/\/habr.com\/ru\/companies\/amvera\/articles\/929568\/\" alt=\"habr\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u044b\u0445 \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 Python. \u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0442\u0435\u043e\u0440\u0438\u044e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 LangChain \u0438 LangGraph. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043a\u043e\u0434\u0435, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[540],"tags":[104,863,864,108,169],"class_list":["post-2473","post","type-post","status-publish","format-standard","hentry","category-llm","tag-tag-ai-agent","tag-tag-langchain","tag-tag-langgraph","tag-tag-mcp","tag-169"],"acf":[],"_links":{"self":[{"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/posts\/2473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/comments?post=2473"}],"version-history":[{"count":0,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/posts\/2473\/revisions"}],"wp:attachment":[{"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/media?parent=2473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/categories?post=2473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/tags?post=2473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}