{"id":2277,"date":"2025-09-14T00:44:28","date_gmt":"2025-09-14T00:44:28","guid":{"rendered":"https:\/\/davidka.net\/ru\/?p=2277"},"modified":"2025-09-21T06:35:57","modified_gmt":"2025-09-21T04:35:57","slug":"complete-guide-any-agent-tavily","status":"publish","type":"post","link":"https:\/\/ru.davidka.net\/ru\/complete-guide-any-agent-tavily\/","title":{"rendered":"any-agent + Tavily \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u043c\u043d\u044b\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1158\" height=\"467\" src=\"https:\/\/davidka.net\/wp-content\/uploads\/2025\/09\/\u0421\u043d\u0438\u043c\u043e\u043a-\u044d\u043a\u0440\u0430\u043d\u0430-2025-09-21-073318.png\" alt=\"\" class=\"wp-image-3082\" srcset=\"https:\/\/ru.davidka.net\/wp-content\/uploads\/2025\/09\/\u0421\u043d\u0438\u043c\u043e\u043a-\u044d\u043a\u0440\u0430\u043d\u0430-2025-09-21-073318.png 1158w, https:\/\/ru.davidka.net\/wp-content\/uploads\/2025\/09\/\u0421\u043d\u0438\u043c\u043e\u043a-\u044d\u043a\u0440\u0430\u043d\u0430-2025-09-21-073318-300x121.png 300w, https:\/\/ru.davidka.net\/wp-content\/uploads\/2025\/09\/\u0421\u043d\u0438\u043c\u043e\u043a-\u044d\u043a\u0440\u0430\u043d\u0430-2025-09-21-073318-1024x413.png 1024w, https:\/\/ru.davidka.net\/wp-content\/uploads\/2025\/09\/\u0421\u043d\u0438\u043c\u043e\u043a-\u044d\u043a\u0440\u0430\u043d\u0430-2025-09-21-073318-768x310.png 768w\" sizes=\"auto, (max-width: 1158px) 100vw, 1158px\" \/><\/figure>\n\n\n\n<p class=\"has-neve-link-color-color has-text-color has-link-color has-medium-font-size wp-elements-6de6bc3e5d7ea21f48aaffbafcb36761 wp-block-paragraph\">\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c \u043c\u0438\u0440\u0435 \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u044b \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0434\u0430\u0442\u043e\u0439 \u0441\u0440\u0435\u0437\u0430 \u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445, \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0446\u0435\u043d\u0430\u0445 \u0438\u043b\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u044f\u0445.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u044f\u0437\u043a\u0438&nbsp;<strong>any-agent<\/strong>&nbsp;(\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0433\u0435\u043d\u0442\u0430\u043c\u0438 \u043e\u0442&nbsp;<a href=\"http:\/\/Mozilla.ai\">Mozilla.ai<\/a>) \u0438&nbsp;<strong>Tavily<\/strong>&nbsp;(\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0434\u043b\u044f \u0418\u0418).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<div id=\"rtoc-mokuji-wrapper\" class=\"rtoc-mokuji-content frame2 preset1 animation-fade rtoc_open default\" data-id=\"2277\" 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><ol class=\"rtoc-mokuji decimal_ol level-1\"><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-1-\u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e-\u0441-any-agent\">\u0427\u0430\u0441\u0442\u044c 1: \u0417\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 any-agent<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u0447\u0442\u043e-\u0442\u0430\u043a\u043e\u0435-any-agent\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 any-agent?<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435-\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f-\u0438-\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\">\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043f\u0435\u0440\u0432\u044b\u0439-\u043f\u0440\u0438\u043c\u0435\u0440-\u0430\u0433\u0435\u043d\u0442\u0430\">\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0430\u0433\u0435\u043d\u0442\u0430<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-2-\u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e-\u0441-tavily\">\u0427\u0430\u0441\u0442\u044c 2: \u0417\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 Tavily<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u0447\u0442\u043e-\u0442\u0430\u043a\u043e\u0435-tavily\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Tavily?<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438-tavily\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 Tavily:<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f-\u0438-\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435-api-\u043a\u043b\u044e\u0447\u0430\">\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 API-\u043a\u043b\u044e\u0447\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0431\u0430\u0437\u043e\u0432\u043e\u0435-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435-tavily\">\u0411\u0430\u0437\u043e\u0432\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Tavily<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430-\u043e\u0442\u0432\u0435\u0442\u0430-tavily\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 Tavily<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-3-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f-any-agent-\u0441-tavily\">\u0427\u0430\u0441\u0442\u044c 3: \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f any-agent \u0441 Tavily<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u043f\u043e\u0434\u0445\u043e\u0434-1-\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435-\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\">\u041f\u043e\u0434\u0445\u043e\u0434 1: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043f\u043e\u0434\u0445\u043e\u0434-2-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f-\u0447\u0435\u0440\u0435\u0437-langchain\">\u041f\u043e\u0434\u0445\u043e\u0434 2: \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 LangChain<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-4-\u043f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439-\u043f\u0440\u0438\u043c\u0435\u0440\">\u0427\u0430\u0441\u0442\u044c 4: \u041f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-5-\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435-\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\">\u0427\u0430\u0441\u0442\u044c 5: \u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#multi-agent-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\">Multi-Agent \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430-\u0433\u043b\u0443\u0431\u0438\u043d\u044b-\u043f\u043e\u0438\u0441\u043a\u0430\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043f\u043e\u0438\u0441\u043a\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f-\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432\">\u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-6-\u043b\u0443\u0447\u0448\u0438\u0435-\u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438-\u0438-\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438\">\u0427\u0430\u0441\u0442\u044c 6: \u041b\u0443\u0447\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c-\u0438-\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\">\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f-\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438\">\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430-\u043e\u0448\u0438\u0431\u043e\u043a\">\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433-\u0438-\u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\">\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0447\u0430\u0441\u0442\u044c-7-\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435-\u043a\u0435\u0439\u0441\u044b-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\">\u0427\u0430\u0441\u0442\u044c 7: \u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u0435\u0439\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u043a\u0435\u0439\u0441-1-\u043d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u0439-\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\">\u041a\u0435\u0439\u0441 1: \u041d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043a\u0435\u0439\u0441-2-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439-\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a\">\u041a\u0435\u0439\u0441 2: \u0418\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043a\u0435\u0439\u0441-3-\u0431\u0438\u0437\u043d\u0435\u0441-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\">\u041a\u0435\u0439\u0441 3: \u0411\u0438\u0437\u043d\u0435\u0441-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a<\/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><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430-1\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438-\u043f\u043e-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e\">\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u043f\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e:<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435-\u0448\u0430\u0433\u0438\">\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438:<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0430-\u043f\u043e\u043b\u043d\u044b\u0439-\u043a\u043e\u0434-\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e-\u0430\u0433\u0435\u043d\u0442\u0430\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0410: \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0431-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435-\u0444\u0430\u0439\u043b\u044b\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0411: \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#configagent_configjson\">config\/agent_config.json<\/a><\/li><li class=\"rtoc-item\"><a href=\"#dockerdockerfile\">docker\/Dockerfile<\/a><\/li><li class=\"rtoc-item\"><a href=\"#docker-composeyml\">docker-compose.yml<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0432-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0412: \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#teststest_production_agentpy\">tests\/test_production_agent.py<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435-\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438\">\u0417\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#1-\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435-\u0432-\u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435\">1. \u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435<\/a><\/li><li class=\"rtoc-item\"><a href=\"#2-\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\">2. \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/a><\/li><li class=\"rtoc-item\"><a href=\"#3-\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\">3. \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><\/li><li class=\"rtoc-item\"><a href=\"#4-\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433-\u0438-\u0430\u043b\u0435\u0440\u0442\u0438\u043d\u0433\">4. \u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438 \u0430\u043b\u0435\u0440\u0442\u0438\u043d\u0433<\/a><\/li><li class=\"rtoc-item\"><a href=\"#5-\u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f\">5. \u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/a><\/li><li class=\"rtoc-item\"><a href=\"#6-\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f-api\">6. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f API<\/a><\/li><\/ul><\/li><li class=\"rtoc-item\"><a href=\"#\u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0435-\u0432\u044b\u0432\u043e\u0434\u044b\">\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u0432\u044b\u0432\u043e\u0434\u044b<\/a><ul class=\"rtoc-mokuji mokuji_ul level-2\"><li class=\"rtoc-item\"><a href=\"#\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f:<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435-\u0432-\u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445-\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445\">\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445:<\/a><\/li><li class=\"rtoc-item\"><a href=\"#\u0431\u0443\u0434\u0443\u0449\u0435\u0435-\u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435\">\u0411\u0443\u0434\u0443\u0449\u0435\u0435 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435:<\/a><\/li><\/ul><\/li><\/ol><\/div><h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-1-\u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e-\u0441-any-agent\">\u0427\u0430\u0441\u0442\u044c 1: \u0417\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 any-agent<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0447\u0442\u043e-\u0442\u0430\u043a\u043e\u0435-any-agent\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 any-agent?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>any-agent<\/strong>&nbsp;\u2014 \u044d\u0442\u043e Python-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043e\u0442&nbsp;<a href=\"http:\/\/Mozilla.ai\">Mozilla.ai<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0430\u0433\u0435\u043d\u0442\u043d\u044b\u043c\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u2014 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 (AutoGen, CrewAI, LangGraph \u0438 \u0434\u0440.) \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u0423\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 API<\/strong>: \u043e\u0434\u0438\u043d \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432<\/li>\n\n\n\n<li><strong>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0442\u0440\u0435\u0439\u0441\u044b \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/li>\n\n\n\n<li><strong>\u041b\u0435\u0433\u043a\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435<\/strong>: \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0430\u0433\u0435\u043d\u0442\u043e\u0432<\/li>\n\n\n\n<li><strong>\u0420\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c<\/strong>: \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435-\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f-\u0438-\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\">\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f&lt;\/em&gt;\n&lt;em&gt;# Python 3.11+&lt;\/em&gt;\n\n&lt;em&gt;# \u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 (\u0442\u043e\u043b\u044c\u043a\u043e TinyAgent)&lt;\/em&gt;\npip install any-agent\n\n&lt;em&gt;# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u0432\u0441\u0435\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432&lt;\/em&gt;\npip install any-agent&#091;all]\n\n&lt;em&gt;# \u0418\u043b\u0438 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c&lt;\/em&gt;\npip install any-agent&#091;langchain]\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043f\u0435\u0440\u0432\u044b\u0439-\u043f\u0440\u0438\u043c\u0435\u0440-\u0430\u0433\u0435\u043d\u0442\u0430\">\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0430\u0433\u0435\u043d\u0442\u0430<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from any_agent import AnyAgent\nfrom any_agent.frameworks import TinyAgent\n\n&lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\nagent = AnyAgent(\n    framework=TinyAgent,\n    model=&quot;gpt-4&quot;,\n    tools=&#091;],\n    system_prompt=&quot;\u0412\u044b \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442&quot;\n)\n\n&lt;em&gt;# \u0417\u0430\u043f\u0443\u0441\u043a \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\nresult = agent.run(&quot;\u041f\u0440\u0438\u0432\u0435\u0442! \u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0438 \u043e \u0441\u0435\u0431\u0435.&quot;)\nprint(result)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0412\u0430\u0436\u043d\u043e \u0434\u043b\u044f Jupyter Notebook:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import nest_asyncio\nnest_asyncio.apply()\n&lt;em&gt;# \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c any-agent&lt;\/em&gt;\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-2-\u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e-\u0441-tavily\">\u0427\u0430\u0441\u0442\u044c 2: \u0417\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 Tavily<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0447\u0442\u043e-\u0442\u0430\u043a\u043e\u0435-tavily\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Tavily?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Tavily<\/strong>&nbsp;\u2014 \u044d\u0442\u043e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0430\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0438 RAG-\u0441\u0438\u0441\u0442\u0435\u043c. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c, Tavily \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445, \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0435\u0433\u043a\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u043c\u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438-tavily\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 Tavily:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0418\u0418<\/strong>: \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f LLM<\/li>\n\n\n\n<li><strong>\u0424\u043e\u043a\u0443\u0441 \u043d\u0430 \u0444\u0430\u043a\u0442\u0430\u0445<\/strong>: \u0430\u043a\u0446\u0435\u043d\u0442 \u043d\u0430 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c<\/li>\n\n\n\n<li><strong>\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c<\/strong>: \u0431\u044b\u0441\u0442\u0440\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/li>\n\n\n\n<li><strong>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434<\/strong>: JSON-\u0444\u043e\u0440\u043c\u0430\u0442 \u0441 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f-\u0438-\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435-api-\u043a\u043b\u044e\u0447\u0430\">\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 API-\u043a\u043b\u044e\u0447\u0430<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430&nbsp;<a href=\"https:\/\/app.tavily.com\/\">https:\/\/app.tavily.com\/<\/a><\/li>\n\n\n\n<li>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0430\u043a\u043a\u0430\u0443\u043d\u0442<\/li>\n\n\n\n<li>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 API-\u043a\u043b\u044e\u0447 \u0432 \u043b\u0438\u0447\u043d\u043e\u043c \u043a\u0430\u0431\u0438\u043d\u0435\u0442\u0435<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0431\u0430\u0437\u043e\u0432\u043e\u0435-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435-tavily\">\u0411\u0430\u0437\u043e\u0432\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Tavily<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430&lt;\/em&gt;\npip install tavily-python\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from tavily import TavilyClient\n\n&lt;em&gt;# \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430&lt;\/em&gt;\nclient = TavilyClient(api_key=&quot;tvly-YOUR_API_KEY&quot;)\n\n&lt;em&gt;# \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u043e\u0438\u0441\u043a&lt;\/em&gt;\nresponse = client.search(&quot;\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u043e Python 3.12&quot;)\n\nprint(f&quot;\u0417\u0430\u043f\u0440\u043e\u0441: {response&#091;&#039;query&#039;]}&quot;)\nprint(f&quot;\u041e\u0442\u0432\u0435\u0442: {response&#091;&#039;answer&#039;]}&quot;)\nprint(f&quot;\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438: {len(response&#091;&#039;results&#039;])} \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432&quot;)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430-\u043e\u0442\u0432\u0435\u0442\u0430-tavily\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 Tavily<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">{\n  &quot;query&quot;: &quot;\u0412\u0430\u0448 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441&quot;,\n  &quot;answer&quot;: &quot;\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438&quot;,\n  &quot;images&quot;: &#091;],\n  &quot;results&quot;: &#091;\n    {\n      &quot;title&quot;: &quot;\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430&quot;,\n      &quot;url&quot;: &quot;https:\/\/example.com&quot;,\n      &quot;content&quot;: &quot;\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435...&quot;,\n      &quot;score&quot;: 0.81025416,\n      &quot;favicon&quot;: &quot;https:\/\/example.com\/favicon.png&quot;\n    }\n  ],\n  &quot;auto_parameters&quot;: {\n    &quot;topic&quot;: &quot;general&quot;,\n    &quot;search_depth&quot;: &quot;basic&quot;\n  },\n  &quot;response_time&quot;: &quot;1.67&quot;\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-3-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f-any-agent-\u0441-tavily\">\u0427\u0430\u0441\u0442\u044c 3: \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f any-agent \u0441 Tavily<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043f\u043e\u0434\u0445\u043e\u0434-1-\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435-\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\">\u041f\u043e\u0434\u0445\u043e\u0434 1: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u0430\u043c\u044b\u0439 \u0433\u0438\u0431\u043a\u0438\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u2014 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043f\u043e\u0438\u0441\u043a\u0430:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import os\nfrom any_agent import AnyAgent\nfrom any_agent.frameworks import TinyAgent\nfrom tavily import TavilyClient\nfrom typing import Dict, Optional\n\nclass TavilySearchTool:\n    &quot;&quot;&quot;\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 Tavily&quot;&quot;&quot;\n    \n    def __init__(self, api_key: str):\n        self.client = TavilyClient(api_key=api_key)\n        self.name = &quot;tavily_search&quot;\n        self.description = &quot;\u041f\u043e\u0438\u0441\u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435&quot;\n    \n    def __call__(self, query: str, search_depth: str = &quot;basic&quot;) -&gt; Dict:\n        &quot;&quot;&quot;\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0438\u0441\u043a\u0430&quot;&quot;&quot;\n        try:\n            response = self.client.search(\n                query=query,\n                search_depth=search_depth\n            )\n            return {\n                &quot;success&quot;: True,\n                &quot;data&quot;: response\n            }\n        except Exception as e:\n            return {\n                &quot;success&quot;: False,\n                &quot;error&quot;: str(e)\n            }\n\n&lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 Tavily&lt;\/em&gt;\ntavily_tool = TavilySearchTool(api_key=&quot;tvly-YOUR_API_KEY&quot;)\n\nagent = AnyAgent(\n    framework=TinyAgent,\n    model=&quot;gpt-4&quot;,\n    tools=&#091;tavily_tool],\n    system_prompt=&quot;&quot;&quot;\n    \u0412\u044b \u0418\u0418-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.\n    \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 tavily_search \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0436\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.\n    \u0412\u0441\u0435\u0433\u0434\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432 \u0441\u0432\u043e\u0438\u0445 \u043e\u0442\u0432\u0435\u0442\u0430\u0445.\n    &quot;&quot;&quot;\n)\n\n&lt;em&gt;# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435&lt;\/em&gt;\nresult = agent.run(&quot;\u041d\u0430\u0439\u0434\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0418\u0418 \u043e\u0442 OpenAI&quot;)\nprint(result)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043f\u043e\u0434\u0445\u043e\u0434-2-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f-\u0447\u0435\u0440\u0435\u0437-langchain\">\u041f\u043e\u0434\u0445\u043e\u0434 2: \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 LangChain<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u0441 LangChain:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from langchain_tavily import TavilySearchAPIWrapper\nfrom any_agent import AnyAgent\n\n&lt;em&gt;# \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 LangChain&lt;\/em&gt;\nsearch_tool = TavilySearchAPIWrapper(\n    tavily_api_key=&quot;tvly-YOUR_API_KEY&quot;\n)\n\n&lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\nagent = AnyAgent(\n    framework=YourLangChainFramework,\n    model=&quot;gpt-4&quot;,\n    tools=&#091;search_tool],\n    system_prompt=&quot;\u0410\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u043f\u043e\u0438\u0441\u043a\u0443 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438&quot;\n)\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-4-\u043f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439-\u043f\u0440\u0438\u043c\u0435\u0440\">\u0427\u0430\u0441\u0442\u044c 4: \u041f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u043c\u0438 \u0430\u0433\u0435\u043d\u0442\u0430\u043c\u0438:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;## \\file src\/agents\/smart_search_agent.py&lt;\/em&gt;\n&lt;em&gt;# -*- coding: utf-8 -*-&lt;\/em&gt;\n&lt;em&gt;#! .pyenv\/bin\/python3&lt;\/em&gt;\n\n&quot;&quot;&quot;\n\u041c\u043e\u0434\u0443\u043b\u044c \u0443\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430\n==============================\n\n\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f any-agent \u0441 Tavily \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u0433\u0435\u043d\u0442\u0430\n\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.\n&quot;&quot;&quot;\n\nfrom typing import Dict, List, Optional\nfrom dataclasses import dataclass\nimport json\nfrom datetime import datetime\n\nfrom tavily import TavilyClient\nfrom any_agent import AnyAgent\nfrom any_agent.frameworks import TinyAgent\n\n\n@dataclass\nclass SearchResult:\n    &quot;&quot;&quot;\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043f\u043e\u0438\u0441\u043a\u0430&quot;&quot;&quot;\n    query: str\n    answer: str\n    sources: List&#091;Dict]\n    timestamp: str\n    response_time: float\n\n\nclass SmartSearchAgent:\n    &quot;&quot;&quot;\n    \u0423\u043c\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0435\u0439 Tavily\n    \n    \u0410\u0433\u0435\u043d\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438,\n    \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b.\n    &quot;&quot;&quot;\n    \n    def __init__(\n        self, \n        tavily_api_key: str, \n        model: str = &quot;gpt-4&quot;,\n        search_depth: str = &quot;basic&quot;\n    ):\n        &quot;&quot;&quot;\n        \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u0433\u0435\u043d\u0442\u0430\n        \n        Args:\n            tavily_api_key: API-\u043a\u043b\u044e\u0447 \u0434\u043b\u044f Tavily\n            model: \u041c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u0430\u0433\u0435\u043d\u0442\u0430\n            search_depth: \u0413\u043b\u0443\u0431\u0438\u043d\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 (&#039;basic&#039; \u0438\u043b\u0438 &#039;advanced&#039;)\n        &quot;&quot;&quot;\n        self.tavily_client = TavilyClient(api_key=tavily_api_key)\n        self.search_depth = search_depth\n        self.agent = self._create_agent(model)\n        self.search_history: List&#091;SearchResult] = &#091;]\n    \n    def _create_agent(self, model: str) -&gt; AnyAgent:\n        &quot;&quot;&quot;\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438&quot;&quot;&quot;\n        return AnyAgent(\n            framework=TinyAgent,\n            model=model,\n            tools=&#091;self._search_tool],\n            system_prompt=self._get_system_prompt()\n        )\n    \n    def _get_system_prompt(self) -&gt; str:\n        &quot;&quot;&quot;\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0434\u043b\u044f \u0430\u0433\u0435\u043d\u0442\u0430&quot;&quot;&quot;\n        return &quot;&quot;&quot;\n        \u0412\u044b \u2014 \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u043d\u044b\u0439 \u0418\u0418-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.\n        \n        \u0412\u0430\u0448\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438:\n        - \u041f\u043e\u0438\u0441\u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 Tavily\n        - \u0410\u043d\u0430\u043b\u0438\u0437 \u0438 \u0441\u0438\u043d\u0442\u0435\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432\n        - \u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432\n        \n        \u041f\u0440\u0438\u043d\u0446\u0438\u043f\u044b \u0440\u0430\u0431\u043e\u0442\u044b:\n        1. \u0412\u0441\u0435\u0433\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043f\u043e\u0438\u0441\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438\n        2. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0439\n        3. \u0415\u0441\u043b\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432\u0430, \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0430 \u044d\u0442\u043e\n        4. \u0411\u0443\u0434\u044c\u0442\u0435 \u0442\u043e\u0447\u043d\u044b\u043c\u0438 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c\u0438\n        5. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u043e\u0442\u0432\u0435\u0442\u044b \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u0438\u044f\u0442\u0438\u044f\n        &quot;&quot;&quot;\n    \n    def _search_tool(self, query: str) -&gt; Dict:\n        &quot;&quot;&quot;\n        \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043f\u043e\u0438\u0441\u043a\u0430 \u0434\u043b\u044f \u0430\u0433\u0435\u043d\u0442\u0430\n        \n        Args:\n            query: \u041f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\n            \n        Returns:\n            \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435\n        &quot;&quot;&quot;\n        try:\n            start_time = datetime.now()\n            \n            response = self.tavily_client.search(\n                query=query,\n                search_depth=self.search_depth\n            )\n            \n            end_time = datetime.now()\n            response_time = (end_time - start_time).total_seconds()\n            \n            &lt;em&gt;# \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u044e&lt;\/em&gt;\n            search_result = SearchResult(\n                query=query,\n                answer=response.get(&#039;answer&#039;, &#039;&#039;),\n                sources=response.get(&#039;results&#039;, &#091;]),\n                timestamp=datetime.now().isoformat(),\n                response_time=response_time\n            )\n            self.search_history.append(search_result)\n            \n            return {\n                &quot;success&quot;: True,\n                &quot;query&quot;: query,\n                &quot;answer&quot;: response.get(&#039;answer&#039;, &#039;&#039;),\n                &quot;sources&quot;: response.get(&#039;results&#039;, &#091;]),\n                &quot;source_count&quot;: len(response.get(&#039;results&#039;, &#091;])),\n                &quot;response_time&quot;: response.get(&#039;response_time&#039;, response_time)\n            }\n            \n        except Exception as e:\n            return {\n                &quot;success&quot;: False,\n                &quot;error&quot;: f&quot;\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430: {str(e)}&quot;,\n                &quot;query&quot;: query\n            }\n    \n    def search(self, query: str) -&gt; str:\n        &quot;&quot;&quot;\n        \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0430\u0433\u0435\u043d\u0442\u0430\n        \n        Args:\n            query: \u0417\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\n            \n        Returns:\n            \u041e\u0442\u0432\u0435\u0442 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439\n        &quot;&quot;&quot;\n        try:\n            result = self.agent.run(query)\n            return result\n        except Exception as e:\n            return f&quot;\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430: {str(e)}&quot;\n    \n    def get_search_history(self) -&gt; List&#091;SearchResult]:\n        &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&quot;&quot;&quot;\n        return self.search_history.copy()\n    \n    def clear_history(self):\n        &quot;&quot;&quot;\u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043f\u043e\u0438\u0441\u043a\u0430&quot;&quot;&quot;\n        self.search_history.clear()\n    \n    def export_history(self, filename: str):\n        &quot;&quot;&quot;\n        \u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 JSON \u0444\u0430\u0439\u043b\n        \n        Args:\n            filename: \u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430\n        &quot;&quot;&quot;\n        try:\n            history_data = &#091;\n                {\n                    &quot;query&quot;: result.query,\n                    &quot;answer&quot;: result.answer,\n                    &quot;sources&quot;: result.sources,\n                    &quot;timestamp&quot;: result.timestamp,\n                    &quot;response_time&quot;: result.response_time\n                }\n                for result in self.search_history\n            ]\n            \n            with open(filename, &#039;w&#039;, encoding=&#039;utf-8&#039;) as f:\n                json.dump(history_data, f, ensure_ascii=False, indent=2)\n            \n            print(f&quot;\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0432 {filename}&quot;)\n            \n        except Exception as e:\n            print(f&quot;\u041e\u0448\u0438\u0431\u043a\u0430 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430: {str(e)}&quot;)\n\n\n&lt;em&gt;# \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f&lt;\/em&gt;\ndef main():\n    &quot;&quot;&quot;\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0443\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430&quot;&quot;&quot;\n    \n    &lt;em&gt;# \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\n    agent = SmartSearchAgent(\n        tavily_api_key=&quot;tvly-YOUR_API_KEY&quot;,\n        model=&quot;gpt-4&quot;,\n        search_depth=&quot;basic&quot;\n    )\n    \n    &lt;em&gt;# \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&lt;\/em&gt;\n    queries = &#091;\n        &quot;\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 GPT-5&quot;,\n        &quot;\u0422\u0435\u043a\u0443\u0449\u0438\u0435 \u0446\u0435\u043d\u044b \u043d\u0430 Bitcoin \u0438 Ethereum&quot;,\n        &quot;\u0427\u0442\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0432 Python 3.12?&quot;,\n        &quot;\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043a\u0432\u0430\u043d\u0442\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043e\u0432&quot;\n    ]\n    \n    print(&quot;=== \u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0443\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430 ===\\n&quot;)\n    \n    for i, query in enumerate(queries, 1):\n        print(f&quot;\u0417\u0430\u043f\u0440\u043e\u0441 {i}: {query}&quot;)\n        print(&quot;-&quot; * 50)\n        \n        result = agent.search(query)\n        print(result)\n        print(&quot;\\n&quot; + &quot;=&quot;*80 + &quot;\\n&quot;)\n    \n    &lt;em&gt;# \u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0438\u0441\u0442\u043e\u0440\u0438\u0438&lt;\/em&gt;\n    agent.export_history(&quot;search_history.json&quot;)\n    \n    &lt;em&gt;# \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430&lt;\/em&gt;\n    history = agent.get_search_history()\n    print(f&quot;\u0412\u0441\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432: {len(history)}&quot;)\n    \n    if history:\n        avg_response_time = sum(r.response_time for r in history) \/ len(history)\n        print(f&quot;\u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u0432\u0435\u0442\u0430: {avg_response_time:.2f} \u0441\u0435\u043a&quot;)\n\n\nif __name__ == &quot;__main__&quot;:\n    main()\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-5-\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435-\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\">\u0427\u0430\u0441\u0442\u044c 5: \u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"multi-agent-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\">Multi-Agent \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">any-agent \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Multi-Agent \u0441\u0438\u0441\u0442\u0435\u043c, \u0433\u0434\u0435 \u0430\u0433\u0435\u043d\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class ResearchTeam:\n    &quot;&quot;&quot;\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str):\n        &lt;em&gt;# \u0410\u0433\u0435\u043d\u0442-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c&lt;\/em&gt;\n        self.researcher = SmartSearchAgent(\n            tavily_api_key=tavily_api_key,\n            model=&quot;gpt-4&quot;\n        )\n        \n        &lt;em&gt;# \u0410\u0433\u0435\u043d\u0442-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a&lt;\/em&gt;\n        self.analyst = AnyAgent(\n            framework=TinyAgent,\n            model=&quot;gpt-4&quot;,\n            system_prompt=&quot;&quot;&quot;\n            \u0412\u044b \u044d\u043a\u0441\u043f\u0435\u0440\u0442-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a. \u0412\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \n            \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0432\u043e\u0434\u044b.\n            &quot;&quot;&quot;\n        )\n        \n        &lt;em&gt;# \u0410\u0433\u0435\u043d\u0442-\u043f\u0438\u0441\u0430\u0442\u0435\u043b\u044c&lt;\/em&gt;\n        self.writer = AnyAgent(\n            framework=TinyAgent,\n            model=&quot;gpt-4&quot;,\n            system_prompt=&quot;&quot;&quot;\n            \u0412\u044b \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0438\u0441\u0430\u0442\u0435\u043b\u044c. \u0421\u043e\u0437\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \n            \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0435\u0442\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430.\n            &quot;&quot;&quot;\n        )\n    \n    def research_topic(self, topic: str) -&gt; str:\n        &quot;&quot;&quot;\u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u043c\u044b&quot;&quot;&quot;\n        \n        &lt;em&gt;# \u042d\u0442\u0430\u043f 1: \u041f\u043e\u0438\u0441\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438&lt;\/em&gt;\n        research_data = self.researcher.search(f&quot;\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e {topic}&quot;)\n        \n        &lt;em&gt;# \u042d\u0442\u0430\u043f 2: \u0410\u043d\u0430\u043b\u0438\u0437 \u0434\u0430\u043d\u043d\u044b\u0445&lt;\/em&gt;\n        analysis = self.analyst.run(f&quot;\u041f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439 \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e: {research_data}&quot;)\n        \n        &lt;em&gt;# \u042d\u0442\u0430\u043f 3: \u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0442\u0447\u0435\u0442\u0430&lt;\/em&gt;\n        report = self.writer.run(f&quot;\u0421\u043e\u0437\u0434\u0430\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430: {analysis}&quot;)\n        \n        return report\n\n&lt;em&gt;# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435&lt;\/em&gt;\nteam = ResearchTeam(&quot;tvly-YOUR_API_KEY&quot;)\nreport = team.research_topic(&quot;\u0412\u043b\u0438\u044f\u043d\u0438\u0435 \u0418\u0418 \u043d\u0430 \u0440\u044b\u043d\u043e\u043a \u0442\u0440\u0443\u0434\u0430 \u0432 2024 \u0433\u043e\u0434\u0443&quot;)\nprint(report)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430-\u0433\u043b\u0443\u0431\u0438\u043d\u044b-\u043f\u043e\u0438\u0441\u043a\u0430\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043f\u043e\u0438\u0441\u043a\u0430<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Tavily \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043f\u043e\u0438\u0441\u043a\u0430:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u043f\u043e\u0438\u0441\u043a (basic)&lt;\/em&gt;\nbasic_agent = SmartSearchAgent(\n    tavily_api_key=&quot;your-key&quot;,\n    search_depth=&quot;basic&quot;  &lt;em&gt;# \u0411\u044b\u0441\u0442\u0440\u0435\u0435, \u043c\u0435\u043d\u044c\u0448\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432&lt;\/em&gt;\n)\n\n&lt;em&gt;# \u0413\u043b\u0443\u0431\u043e\u043a\u0438\u0439 \u043f\u043e\u0438\u0441\u043a (advanced)&lt;\/em&gt;\nadvanced_agent = SmartSearchAgent(\n    tavily_api_key=&quot;your-key&quot;, \n    search_depth=&quot;advanced&quot;  &lt;em&gt;# \u041c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435, \u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432&lt;\/em&gt;\n)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f-\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432\">\u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">def create_specialized_search_tool(domains: List&#091;str] = None):\n    &quot;&quot;&quot;\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430&quot;&quot;&quot;\n    \n    def search_tool(query: str) -&gt; Dict:\n        client = TavilyClient(api_key=&quot;your-key&quot;)\n        \n        search_params = {\n            &quot;query&quot;: query,\n            &quot;search_depth&quot;: &quot;advanced&quot;\n        }\n        \n        &lt;em&gt;# \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u043f\u043e \u0434\u043e\u043c\u0435\u043d\u0430\u043c&lt;\/em&gt;\n        if domains:\n            search_params&#091;&quot;include_domains&quot;] = domains\n        \n        response = client.search(**search_params)\n        return response\n    \n    return search_tool\n\n&lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u043d\u0430\u0443\u0447\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c&lt;\/em&gt;\nscience_agent = AnyAgent(\n    framework=TinyAgent,\n    model=&quot;gpt-4&quot;,\n    tools=&#091;create_specialized_search_tool(&#091;\n        &quot;arxiv.org&quot;, \n        &quot;nature.com&quot;, \n        &quot;science.org&quot;\n    ])],\n    system_prompt=&quot;\u042d\u043a\u0441\u043f\u0435\u0440\u0442 \u043f\u043e \u043d\u0430\u0443\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438&quot;\n)\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-6-\u043b\u0443\u0447\u0448\u0438\u0435-\u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438-\u0438-\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438\">\u0427\u0430\u0441\u0442\u044c 6: \u041b\u0443\u0447\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c-\u0438-\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\">\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u26a0\ufe0f&nbsp;<strong>\u0412\u0430\u0436\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u0412\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b<\/strong>: \u0410\u0433\u0435\u043d\u0442\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0447\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b LLM<\/li>\n\n\n\n<li><strong>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0410\u0433\u0435\u043d\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/li>\n\n\n\n<li><strong>\u0421\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c<\/strong>: \u041a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0432\u044b\u0437\u043e\u0432 LLM \u0442\u0430\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442\u0441\u044f<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f-\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438\">\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class OptimizedSearchAgent:\n    &quot;&quot;&quot;\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str):\n        self.client = TavilyClient(api_key=tavily_api_key)\n        self.cache = {}  &lt;em&gt;# \u041a\u0435\u0448 \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&lt;\/em&gt;\n        self.rate_limit_delay = 1  &lt;em&gt;# \u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438&lt;\/em&gt;\n    \n    def search_with_cache(self, query: str) -&gt; Dict:\n        &quot;&quot;&quot;\u041f\u043e\u0438\u0441\u043a \u0441 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432&quot;&quot;&quot;\n        \n        &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u0435\u0448\u0430&lt;\/em&gt;\n        if query in self.cache:\n            print(f&quot;\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u0437\u044f\u0442 \u0438\u0437 \u043a\u0435\u0448\u0430 \u0434\u043b\u044f: {query}&quot;)\n            return self.cache&#091;query]\n        \n        &lt;em&gt;# \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0438\u0441\u043a\u0430&lt;\/em&gt;\n        time.sleep(self.rate_limit_delay)  &lt;em&gt;# \u0421\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 rate limits&lt;\/em&gt;\n        result = self.client.search(query)\n        \n        &lt;em&gt;# \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043a\u0435\u0448&lt;\/em&gt;\n        self.cache&#091;query] = result\n        \n        return result\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430-\u043e\u0448\u0438\u0431\u043e\u043a\">\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class RobustSearchAgent:\n    &quot;&quot;&quot;\u0423\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str, max_retries: int = 3):\n        self.client = TavilyClient(api_key=tavily_api_key)\n        self.max_retries = max_retries\n    \n    def search_with_retry(self, query: str) -&gt; Dict:\n        &quot;&quot;&quot;\u041f\u043e\u0438\u0441\u043a \u0441 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438&quot;&quot;&quot;\n        \n        for attempt in range(self.max_retries):\n            try:\n                return self.client.search(query)\n            \n            except Exception as e:\n                print(f&quot;\u041f\u043e\u043f\u044b\u0442\u043a\u0430 {attempt + 1} \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u0430: {str(e)}&quot;)\n                \n                if attempt == self.max_retries - 1:\n                    return {\n                        &quot;error&quot;: f&quot;\u041f\u043e\u0438\u0441\u043a \u043d\u0435 \u0443\u0434\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435 {self.max_retries} \u043f\u043e\u043f\u044b\u0442\u043e\u043a&quot;,\n                        &quot;query&quot;: query\n                    }\n                \n                time.sleep(2 ** attempt)  &lt;em&gt;# \u042d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430&lt;\/em&gt;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433-\u0438-\u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\">\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import logging\nfrom datetime import datetime\n\nclass MonitoredSearchAgent:\n    &quot;&quot;&quot;\u0410\u0433\u0435\u043d\u0442 \u0441 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u043e\u043c \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str):\n        self.client = TavilyClient(api_key=tavily_api_key)\n        self.setup_logging()\n        self.stats = {\n            &quot;total_searches&quot;: 0,\n            &quot;successful_searches&quot;: 0,\n            &quot;failed_searches&quot;: 0,\n            &quot;total_response_time&quot;: 0\n        }\n    \n    def setup_logging(self):\n        &quot;&quot;&quot;\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f&quot;&quot;&quot;\n        logging.basicConfig(\n            level=logging.INFO,\n            format=&#039;%(asctime)s - %(name)s - %(levelname)s - %(message)s&#039;,\n            handlers=&#091;\n                logging.FileHandler(&#039;search_agent.log&#039;),\n                logging.StreamHandler()\n            ]\n        )\n        self.logger = logging.getLogger(&#039;SearchAgent&#039;)\n    \n    def search_with_monitoring(self, query: str) -&gt; Dict:\n        &quot;&quot;&quot;\u041f\u043e\u0438\u0441\u043a \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u043e\u043c&quot;&quot;&quot;\n        start_time = datetime.now()\n        self.stats&#091;&quot;total_searches&quot;] += 1\n        \n        try:\n            self.logger.info(f&quot;\u041d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043f\u043e\u0438\u0441\u043a: {query}&quot;)\n            \n            result = self.client.search(query)\n            \n            end_time = datetime.now()\n            response_time = (end_time - start_time).total_seconds()\n            \n            self.stats&#091;&quot;successful_searches&quot;] += 1\n            self.stats&#091;&quot;total_response_time&quot;] += response_time\n            \n            self.logger.info(f&quot;\u041f\u043e\u0438\u0441\u043a \u0443\u0441\u043f\u0435\u0448\u0435\u043d \u0437\u0430 {response_time:.2f}c: {query}&quot;)\n            \n            return result\n            \n        except Exception as e:\n            self.stats&#091;&quot;failed_searches&quot;] += 1\n            self.logger.error(f&quot;\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 {query}: {str(e)}&quot;)\n            \n            return {&quot;error&quot;: str(e), &quot;query&quot;: query}\n    \n    def get_statistics(self) -&gt; Dict:\n        &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b&quot;&quot;&quot;\n        success_rate = (\n            self.stats&#091;&quot;successful_searches&quot;] \/ self.stats&#091;&quot;total_searches&quot;] * 100\n            if self.stats&#091;&quot;total_searches&quot;] &gt; 0 else 0\n        )\n        \n        avg_response_time = (\n            self.stats&#091;&quot;total_response_time&quot;] \/ self.stats&#091;&quot;successful_searches&quot;]\n            if self.stats&#091;&quot;successful_searches&quot;] &gt; 0 else 0\n        )\n        \n        return {\n            **self.stats,\n            &quot;success_rate&quot;: f&quot;{success_rate:.1f}%&quot;,\n            &quot;average_response_time&quot;: f&quot;{avg_response_time:.2f}s&quot;\n        }\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0447\u0430\u0441\u0442\u044c-7-\u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435-\u043a\u0435\u0439\u0441\u044b-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\">\u0427\u0430\u0441\u0442\u044c 7: \u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u0435\u0439\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u0435\u0439\u0441-1-\u043d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u0439-\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\">\u041a\u0435\u0439\u0441 1: \u041d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u0439 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class NewsAggregatorAgent:\n    &quot;&quot;&quot;\u0410\u0433\u0435\u043d\u0442 \u0434\u043b\u044f \u0430\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u043f\u043e \u0442\u0435\u043c\u0430\u043c&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str):\n        self.search_agent = SmartSearchAgent(tavily_api_key)\n    \n    def get_daily_digest(self, topics: List&#091;str]) -&gt; str:\n        &quot;&quot;&quot;\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e\u0439 \u0441\u0432\u043e\u0434\u043a\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439&quot;&quot;&quot;\n        \n        digest_parts = &#091;]\n        \n        for topic in topics:\n            query = f&quot;\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u0437\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f: {topic}&quot;\n            news = self.search_agent.search(query)\n            \n            digest_parts.append(f&quot;## {topic}\\n{news}\\n&quot;)\n        \n        return &quot;\\n&quot;.join(digest_parts)\n\n&lt;em&gt;# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435&lt;\/em&gt;\nnews_agent = NewsAggregatorAgent(&quot;your-api-key&quot;)\ndigest = news_agent.get_daily_digest(&#091;\n    &quot;\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0418\u0418&quot;,\n    &quot;\u041a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u044b&quot;, \n    &quot;\u041a\u043e\u0441\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f&quot;\n])\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u0435\u0439\u0441-2-\u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439-\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a\">\u041a\u0435\u0439\u0441 2: \u0418\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class ResearchAssistant:\n    &quot;&quot;&quot;\u041f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u0434\u043b\u044f \u043d\u0430\u0443\u0447\u043d\u044b\u0445 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0439&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str):\n        self.agent = SmartSearchAgent(tavily_api_key)\n    \n    def literature_review(self, topic: str, num_sources: int = 10) -&gt; Dict:\n        &quot;&quot;&quot;\u041e\u0431\u0437\u043e\u0440 \u043b\u0438\u0442\u0435\u0440\u0430\u0442\u0443\u0440\u044b \u043f\u043e \u0442\u0435\u043c\u0435&quot;&quot;&quot;\n        \n        queries = &#091;\n            f&quot;{topic} recent research 2024&quot;,\n            f&quot;{topic} scientific papers&quot;,\n            f&quot;{topic} review articles&quot;,\n            f&quot;{topic} latest findings&quot;\n        ]\n        \n        all_sources = &#091;]\n        \n        for query in queries:\n            result = self.agent.search(query)\n            &lt;em&gt;# \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0438\u0437 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430&lt;\/em&gt;\n            &lt;em&gt;# ... \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438&lt;\/em&gt;\n        \n        return {\n            &quot;topic&quot;: topic,\n            &quot;sources_found&quot;: len(all_sources),\n            &quot;summary&quot;: &quot;...&quot;,\n            &quot;key_findings&quot;: &quot;...&quot;,\n            &quot;sources&quot;: all_sources\n        }\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u0435\u0439\u0441-3-\u0431\u0438\u0437\u043d\u0435\u0441-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\">\u041a\u0435\u0439\u0441 3: \u0411\u0438\u0437\u043d\u0435\u0441-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class BusinessAnalyst:\n    &quot;&quot;&quot;\u0410\u0433\u0435\u043d\u0442 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u0430\u043d\u0430\u043b\u0438\u0437\u0430&quot;&quot;&quot;\n    \n    def __init__(self, tavily_api_key: str):\n        self.agent = SmartSearchAgent(tavily_api_key)\n    \n    def market_analysis(self, company: str, competitors: List&#091;str]) -&gt; str:\n        &quot;&quot;&quot;\u0410\u043d\u0430\u043b\u0438\u0437 \u0440\u044b\u043d\u043a\u0430 \u0438 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043e\u0432&quot;&quot;&quot;\n        \n        &lt;em&gt;# \u0410\u043d\u0430\u043b\u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438&lt;\/em&gt;\n        company_analysis = self.agent.search(\n            f&quot;\u0424\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 {company} 2024&quot;\n        )\n        \n        &lt;em&gt;# \u0410\u043d\u0430\u043b\u0438\u0437 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043e\u0432&lt;\/em&gt;\n        competitor_analyses = &#091;]\n        for competitor in competitors:\n            analysis = self.agent.search(\n                f&quot;\u0424\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b {competitor} \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 {company}&quot;\n            )\n            competitor_analyses.append(analysis)\n        \n        &lt;em&gt;# \u0421\u0438\u043d\u0442\u0435\u0437 \u043e\u0442\u0447\u0435\u0442\u0430&lt;\/em&gt;\n        report_query = f&quot;&quot;&quot;\n        \u0421\u043e\u0437\u0434\u0430\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043e\u0442\u0447\u0435\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:\n        \u041a\u043e\u043c\u043f\u0430\u043d\u0438\u044f: {company_analysis}\n        \u041a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u044b: {competitor_analyses}\n        &quot;&quot;&quot;\n        \n        return self.agent.search(report_query)\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 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<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f&nbsp;<strong>any-agent<\/strong>&nbsp;\u0441&nbsp;<strong>Tavily<\/strong>&nbsp;\u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0448\u0438\u0440\u043e\u043a\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u043c\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u042d\u0442\u0430 \u0441\u0432\u044f\u0437\u043a\u0430 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0434\u043b\u044f:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430-1\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u0410\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0432\u0435\u0436\u0435\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/li>\n\n\n\n<li><strong>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c<\/strong>: \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432<\/li>\n\n\n\n<li><strong>\u041d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0418\u0418<\/li>\n\n\n\n<li><strong>\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c<\/strong>: \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043c\u0443\u043b\u044c\u0442\u0438-\u0430\u0433\u0435\u043d\u0442\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438-\u043f\u043e-\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e\">\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u043f\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e:<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e<\/strong>: \u043e\u0441\u0432\u043e\u0439\u0442\u0435 \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u043f\u0435\u0440\u0435\u0434 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u043a \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c<\/li>\n\n\n\n<li><strong>\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u044c\u0442\u0435 \u0437\u0430\u0442\u0440\u0430\u0442\u044b<\/strong>: \u0441\u043b\u0435\u0434\u0438\u0442\u0435 \u0437\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c API \u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432<\/li>\n\n\n\n<li><strong>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/strong>: \u0430\u0433\u0435\u043d\u0442\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u043e\u0433\u0443\u0442 \u0432\u0435\u0441\u0442\u0438 \u0441\u0435\u0431\u044f \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e<\/li>\n\n\n\n<li><strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u0438\u0437\u0431\u0435\u0433\u0430\u0439\u0442\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438<\/li>\n\n\n\n<li><strong>\u041f\u043b\u0430\u043d\u0438\u0440\u0443\u0439\u0442\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a<\/strong>: \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0439\u0442\u0435 fallback-\u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435-\u0448\u0430\u0433\u0438\">\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u0418\u0437\u0443\u0447\u0438\u0442\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0435 any-agent<\/li>\n\n\n\n<li>\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u0433\u043b\u0443\u0431\u0438\u043d\u044b \u043f\u043e\u0438\u0441\u043a\u0430 Tavily<\/li>\n\n\n\n<li>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 (\u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, API \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432)<\/li>\n\n\n\n<li>\u0418\u0437\u0443\u0447\u0438\u0442\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0432\u0430\u0448\u0435\u0439 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u042d\u0442\u0430 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0432\u044f\u0437\u043a\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0418\u0418-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0430-\u043f\u043e\u043b\u043d\u044b\u0439-\u043a\u043e\u0434-\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e-\u0430\u0433\u0435\u043d\u0442\u0430\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0410: \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430<\/h2>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;## \\file src\/agents\/production_search_agent.py&lt;\/em&gt;\n&lt;em&gt;# -*- coding: utf-8 -*-&lt;\/em&gt;\n&lt;em&gt;#! .pyenv\/bin\/python3&lt;\/em&gt;\n&quot;&quot;&quot;\n\u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442\n===============================\n\u041f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0430\u0433\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435 \u0441 \u043f\u043e\u043b\u043d\u044b\u043c\n\u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439: \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433, \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a.\n&quot;&quot;&quot;\nimport asyncio\nimport json\nimport time\nimport hashlib\nfrom datetime import datetime, timedelta\nfrom pathlib import Path\nfrom typing import Dict, List, Optional, Any, Union\nfrom dataclasses import dataclass, asdict\nfrom enum import Enum\nimport logging\nfrom tavily import TavilyClient\nfrom any_agent import AnyAgent\nfrom any_agent.frameworks import TinyAgent\nclass SearchDepth(Enum):\n    &quot;&quot;&quot;\u0413\u043b\u0443\u0431\u0438\u043d\u0430 \u043f\u043e\u0438\u0441\u043a\u0430&quot;&quot;&quot;\n    BASIC = &quot;basic&quot;\n    ADVANCED = &quot;advanced&quot;\nclass SearchStatus(Enum):\n    &quot;&quot;&quot;\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n    SUCCESS = &quot;success&quot;\n    ERROR = &quot;error&quot;\n    CACHED = &quot;cached&quot;\n    RATE_LIMITED = &quot;rate_limited&quot;\n@dataclass\nclass SearchRequest:\n    &quot;&quot;&quot;\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n    query: str\n    depth: SearchDepth = SearchDepth.BASIC\n    timestamp: str = None\n    user_id: Optional&#091;str] = None\n    session_id: Optional&#091;str] = None\n    \n    def __post_init__(self):\n        if not self.timestamp:\n            self.timestamp = datetime.now().isoformat()\n    \n    def get_cache_key(self) -&gt; str:\n        &quot;&quot;&quot;\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043b\u044e\u0447\u0430 \u0434\u043b\u044f \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f&quot;&quot;&quot;\n        content = f&quot;{self.query}:{self.depth.value}&quot;\n        return hashlib.md5(content.encode()).hexdigest()\n@dataclass\nclass SearchResponse:\n    &quot;&quot;&quot;\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u043e\u0438\u0441\u043a\u0430&quot;&quot;&quot;\n    request: SearchRequest\n    status: SearchStatus\n    answer: str = &quot;&quot;\n    sources: List&#091;Dict] = None\n    error_message: str = &quot;&quot;\n    response_time: float = 0.0\n    from_cache: bool = False\n    \n    def __post_init__(self):\n        if self.sources is None:\n            self.sources = &#091;]\nclass CacheManager:\n    &quot;&quot;&quot;\u041c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043a\u0435\u0448\u0430 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&quot;&quot;&quot;\n    \n    def __init__(self, cache_dir: str = &quot;.\/cache&quot;, ttl_hours: int = 24):\n        self.cache_dir = Path(cache_dir)\n        self.cache_dir.mkdir(exist_ok=True)\n        self.ttl = timedelta(hours=ttl_hours)\n    \n    def _get_cache_file(self, cache_key: str) -&gt; Path:\n        &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043f\u0443\u0442\u0438 \u043a \u0444\u0430\u0439\u043b\u0443 \u043a\u0435\u0448\u0430&quot;&quot;&quot;\n        return self.cache_dir \/ f&quot;{cache_key}.json&quot;\n    \n    def get(self, cache_key: str) -&gt; Optional&#091;Dict]:\n        &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043a\u0435\u0448\u0430&quot;&quot;&quot;\n        cache_file = self._get_cache_file(cache_key)\n        \n        if not cache_file.exists():\n            return None\n        \n        try:\n            with open(cache_file, &#039;r&#039;, encoding=&#039;utf-8&#039;) as f:\n                data = json.load(f)\n            \n            &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 TTL&lt;\/em&gt;\n            cached_time = datetime.fromisoformat(data&#091;&#039;cached_at&#039;])\n            if datetime.now() - cached_time &gt; self.ttl:\n                cache_file.unlink()  &lt;em&gt;# \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0439 \u043a\u0435\u0448&lt;\/em&gt;\n                return None\n            \n            return data&#091;&#039;content&#039;]\n            \n        except Exception:\n            return None\n    \n    def set(self, cache_key: str, content: Dict):\n        &quot;&quot;&quot;\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043a\u0435\u0448&quot;&quot;&quot;\n        cache_file = self._get_cache_file(cache_key)\n        \n        try:\n            cache_data = {\n                &#039;cached_at&#039;: datetime.now().isoformat(),\n                &#039;content&#039;: content\n            }\n            \n            with open(cache_file, &#039;w&#039;, encoding=&#039;utf-8&#039;) as f:\n                json.dump(cache_data, f, ensure_ascii=False, indent=2)\n                \n        except Exception as e:\n            logging.warning(f&quot;\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043a\u0435\u0448: {e}&quot;)\n    \n    def clear_expired(self):\n        &quot;&quot;&quot;\u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u0433\u043e \u043a\u0435\u0448\u0430&quot;&quot;&quot;\n        for cache_file in self.cache_dir.glob(&quot;*.json&quot;):\n            try:\n                with open(cache_file, &#039;r&#039;, encoding=&#039;utf-8&#039;) as f:\n                    data = json.load(f)\n                \n                cached_time = datetime.fromisoformat(data&#091;&#039;cached_at&#039;])\n                if datetime.now() - cached_time &gt; self.ttl:\n                    cache_file.unlink()\n                    \n            except Exception:\n                continue\nclass RateLimiter:\n    &quot;&quot;&quot;\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u0435\u043b\u044c \u0447\u0430\u0441\u0442\u043e\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&quot;&quot;&quot;\n    \n    def __init__(self, max_requests: int = 60, time_window: int = 60):\n        self.max_requests = max_requests\n        self.time_window = time_window\n        self.requests = &#091;]\n    \n    def can_make_request(self) -&gt; bool:\n        &quot;&quot;&quot;\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n        now = time.time()\n        \n        &lt;em&gt;# \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&lt;\/em&gt;\n        self.requests = &#091;req_time for req_time in self.requests \n                        if now - req_time &lt; self.time_window]\n        \n        return len(self.requests) &lt; self.max_requests\n    \n    def register_request(self):\n        &quot;&quot;&quot;\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n        self.requests.append(time.time())\n    \n    def get_wait_time(self) -&gt; float:\n        &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u0434\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n        if not self.requests:\n            return 0.0\n        \n        oldest_request = min(self.requests)\n        wait_time = self.time_window - (time.time() - oldest_request)\n        \n        return max(0.0, wait_time)\nclass ProductionSearchAgent:\n    &quot;&quot;&quot;\n    \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442\n    \n    \u041f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0430\u0433\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435 \u0441:\n    - \u041a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432\n    - Rate limiting\n    - \u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u043e\u043c \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c\n    - \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043e\u043a\n    - \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u043e\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n    &quot;&quot;&quot;\n    \n    def __init__(\n        self,\n        tavily_api_key: str,\n        model: str = &quot;gpt-4&quot;,\n        cache_ttl_hours: int = 24,\n        rate_limit_per_minute: int = 60,\n        max_retries: int = 3,\n        log_level: str = &quot;INFO&quot;\n    ):\n        &lt;em&gt;# \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432&lt;\/em&gt;\n        self.tavily_client = TavilyClient(api_key=tavily_api_key)\n        self.cache_manager = CacheManager(ttl_hours=cache_ttl_hours)\n        self.rate_limiter = RateLimiter(max_requests=rate_limit_per_minute)\n        self.max_retries = max_retries\n        \n        &lt;em&gt;# \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f&lt;\/em&gt;\n        self.setup_logging(log_level)\n        \n        &lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\n        self.agent = self._create_agent(model)\n        \n        &lt;em&gt;# \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430&lt;\/em&gt;\n        self.stats = {\n            &quot;total_requests&quot;: 0,\n            &quot;successful_requests&quot;: 0,\n            &quot;cached_requests&quot;: 0,\n            &quot;failed_requests&quot;: 0,\n            &quot;rate_limited_requests&quot;: 0,\n            &quot;total_response_time&quot;: 0.0,\n            &quot;start_time&quot;: datetime.now().isoformat()\n        }\n    \n    def setup_logging(self, log_level: str):\n        &quot;&quot;&quot;\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f&quot;&quot;&quot;\n        logging.basicConfig(\n            level=getattr(logging, log_level.upper()),\n            format=&#039;%(asctime)s - %(name)s - %(levelname)s - %(message)s&#039;,\n            handlers=&#091;\n                logging.FileHandler(&#039;production_search_agent.log&#039;),\n                logging.StreamHandler()\n            ]\n        )\n        self.logger = logging.getLogger(&#039;ProductionSearchAgent&#039;)\n    \n    def _create_agent(self, model: str) -&gt; AnyAgent:\n        &quot;&quot;&quot;\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438&quot;&quot;&quot;\n        return AnyAgent(\n            framework=TinyAgent,\n            model=model,\n            tools=&#091;self._search_tool],\n            system_prompt=self._get_production_system_prompt()\n        )\n    \n    def _get_production_system_prompt(self) -&gt; str:\n        &quot;&quot;&quot;\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043f\u0440\u043e\u043c\u043f\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430&quot;&quot;&quot;\n        return &quot;&quot;&quot;\n        \u0412\u044b \u2014 \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0418\u0418-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \n        \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.\n        \u0412\u0430\u0448\u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b \u0440\u0430\u0431\u043e\u0442\u044b:\n        1. \u0422\u041e\u0427\u041d\u041e\u0421\u0422\u042c: \u0412\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 \u0444\u0430\u043a\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u043f\u043e\u0438\u0441\u043a\n        2. \u0418\u0421\u0422\u041e\u0427\u041d\u0418\u041a\u0418: \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0439\n        3. \u041e\u0411\u042a\u0415\u041a\u0422\u0418\u0412\u041d\u041e\u0421\u0422\u042c: \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f\n        4. \u0421\u0422\u0420\u0423\u041a\u0422\u0423\u0420\u0410: \u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0439\u0442\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043b\u043e\u0433\u0438\u0447\u043d\u043e\n        5. \u0410\u041a\u0422\u0423\u0410\u041b\u042c\u041d\u041e\u0421\u0422\u042c: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0432\u0435\u0436\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\n        \u0424\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0432\u0435\u0442\u0430:\n        - \u041a\u0440\u0430\u0442\u043a\u043e\u0435 \u0440\u0435\u0437\u044e\u043c\u0435 (2-3 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f)\n        - \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0441 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c\u0438\n        - \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0432\u044b\u0432\u043e\u0434\u044b\n        - \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u0434\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f\n        \u0415\u0441\u043b\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432\u0430 \u0438\u043b\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u0430 - \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043d\u0430 \u044d\u0442\u043e.\n        &quot;&quot;&quot;\n    \n    def _search_tool(self, query: str, depth: str = &quot;basic&quot;) -&gt; Dict:\n        &quot;&quot;&quot;\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043f\u043e\u0438\u0441\u043a\u0430 \u0441 \u043f\u043e\u043b\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043e\u043a&quot;&quot;&quot;\n        search_request = SearchRequest(\n            query=query,\n            depth=SearchDepth(depth)\n        )\n        \n        response = self._execute_search(search_request)\n        \n        if response.status == SearchStatus.SUCCESS:\n            return {\n                &quot;success&quot;: True,\n                &quot;query&quot;: query,\n                &quot;answer&quot;: response.answer,\n                &quot;sources&quot;: response.sources,\n                &quot;from_cache&quot;: response.from_cache,\n                &quot;response_time&quot;: response.response_time\n            }\n        else:\n            return {\n                &quot;success&quot;: False,\n                &quot;query&quot;: query,\n                &quot;error&quot;: response.error_message,\n                &quot;status&quot;: response.status.value\n            }\n    \n    def _execute_search(self, request: SearchRequest) -&gt; SearchResponse:\n        &quot;&quot;&quot;\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u0441 \u043f\u043e\u043b\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439&quot;&quot;&quot;\n        start_time = time.time()\n        self.stats&#091;&quot;total_requests&quot;] += 1\n        \n        try:\n            &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u0435\u0448\u0430&lt;\/em&gt;\n            cache_key = request.get_cache_key()\n            cached_result = self.cache_manager.get(cache_key)\n            \n            if cached_result:\n                self.stats&#091;&quot;cached_requests&quot;] += 1\n                self.logger.info(f&quot;\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0438\u0437 \u043a\u0435\u0448\u0430: {request.query}&quot;)\n                \n                return SearchResponse(\n                    request=request,\n                    status=SearchStatus.CACHED,\n                    answer=cached_result.get(&#039;answer&#039;, &#039;&#039;),\n                    sources=cached_result.get(&#039;sources&#039;, &#091;]),\n                    response_time=time.time() - start_time,\n                    from_cache=True\n                )\n            \n            &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 rate limit&lt;\/em&gt;\n            if not self.rate_limiter.can_make_request():\n                wait_time = self.rate_limiter.get_wait_time()\n                self.stats&#091;&quot;rate_limited_requests&quot;] += 1\n                self.logger.warning(f&quot;Rate limit exceeded. Wait time: {wait_time:.1f}s&quot;)\n                \n                return SearchResponse(\n                    request=request,\n                    status=SearchStatus.RATE_LIMITED,\n                    error_message=f&quot;Rate limit exceeded. Try again in {wait_time:.1f} seconds&quot;,\n                    response_time=time.time() - start_time\n                )\n            \n            &lt;em&gt;# \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u0441 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438&lt;\/em&gt;\n            result = None\n            last_error = None\n            \n            for attempt in range(self.max_retries):\n                try:\n                    self.rate_limiter.register_request()\n                    \n                    result = self.tavily_client.search(\n                        query=request.query,\n                        search_depth=request.depth.value\n                    )\n                    break\n                    \n                except Exception as e:\n                    last_error = e\n                    if attempt &lt; self.max_retries - 1:\n                        wait_time = (2 ** attempt) * 1  &lt;em&gt;# \u042d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430&lt;\/em&gt;\n                        self.logger.warning(f&quot;Attempt {attempt + 1} failed: {e}. Retrying in {wait_time}s...&quot;)\n                        time.sleep(wait_time)\n            \n            if result is None:\n                self.stats&#091;&quot;failed_requests&quot;] += 1\n                self.logger.error(f&quot;All search attempts failed for: {request.query}&quot;)\n                \n                return SearchResponse(\n                    request=request,\n                    status=SearchStatus.ERROR,\n                    error_message=f&quot;Search failed after {self.max_retries} attempts: {last_error}&quot;,\n                    response_time=time.time() - start_time\n                )\n            \n            &lt;em&gt;# \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430&lt;\/em&gt;\n            response_time = time.time() - start_time\n            self.stats&#091;&quot;successful_requests&quot;] += 1\n            self.stats&#091;&quot;total_response_time&quot;] += response_time\n            \n            &lt;em&gt;# \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043a\u0435\u0448&lt;\/em&gt;\n            cache_data = {\n                &#039;answer&#039;: result.get(&#039;answer&#039;, &#039;&#039;),\n                &#039;sources&#039;: result.get(&#039;results&#039;, &#091;])\n            }\n            self.cache_manager.set(cache_key, cache_data)\n            \n            self.logger.info(f&quot;Search successful in {response_time:.2f}s: {request.query}&quot;)\n            \n            return SearchResponse(\n                request=request,\n                status=SearchStatus.SUCCESS,\n                answer=result.get(&#039;answer&#039;, &#039;&#039;),\n                sources=result.get(&#039;results&#039;, &#091;]),\n                response_time=response_time,\n                from_cache=False\n            )\n            \n        except Exception as e:\n            self.stats&#091;&quot;failed_requests&quot;] += 1\n            self.logger.error(f&quot;Unexpected error during search: {e}&quot;, exc_info=True)\n            \n            return SearchResponse(\n                request=request,\n                status=SearchStatus.ERROR,\n                error_message=f&quot;Unexpected error: {str(e)}&quot;,\n                response_time=time.time() - start_time\n            )\n    \n    def search(self, query: str, depth: SearchDepth = SearchDepth.BASIC) -&gt; str:\n        &quot;&quot;&quot;\n        \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u0438\u0441\u043a\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\n        \n        Args:\n            query: \u041f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\n            depth: \u0413\u043b\u0443\u0431\u0438\u043d\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 (basic\/advanced)\n            \n        Returns:\n            \u041e\u0442\u0432\u0435\u0442 \u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439\n        &quot;&quot;&quot;\n        try:\n            self.logger.info(f&quot;Processing user query: {query}&quot;)\n            \n            &lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043b\u044f \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\n            search_context = f&quot;\u0412\u044b\u043f\u043e\u043b\u043d\u0438 \u043f\u043e\u0438\u0441\u043a \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441: {query}&quot;\n            if depth == SearchDepth.ADVANCED:\n                search_context += &quot; (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430)&quot;\n            \n            result = self.agent.run(search_context)\n            return result\n            \n        except Exception as e:\n            self.logger.error(f&quot;Error processing query: {e}&quot;, exc_info=True)\n            return f&quot;\u0418\u0437\u0432\u0438\u043d\u0438\u0442\u0435, \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430: {str(e)}&quot;\n    \n    def get_statistics(self) -&gt; Dict&#091;str, Any]:\n        &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b&quot;&quot;&quot;\n        uptime = datetime.now() - datetime.fromisoformat(self.stats&#091;&quot;start_time&quot;])\n        \n        success_rate = (\n            self.stats&#091;&quot;successful_requests&quot;] \/ self.stats&#091;&quot;total_requests&quot;] * 100\n            if self.stats&#091;&quot;total_requests&quot;] &gt; 0 else 0\n        )\n        \n        cache_hit_rate = (\n            self.stats&#091;&quot;cached_requests&quot;] \/ self.stats&#091;&quot;total_requests&quot;] * 100\n            if self.stats&#091;&quot;total_requests&quot;] &gt; 0 else 0\n        )\n        \n        avg_response_time = (\n            self.stats&#091;&quot;total_response_time&quot;] \/ self.stats&#091;&quot;successful_requests&quot;]\n            if self.stats&#091;&quot;successful_requests&quot;] &gt; 0 else 0\n        )\n        \n        return {\n            **self.stats,\n            &quot;uptime&quot;: str(uptime),\n            &quot;success_rate&quot;: f&quot;{success_rate:.1f}%&quot;,\n            &quot;cache_hit_rate&quot;: f&quot;{cache_hit_rate:.1f}%&quot;,\n            &quot;average_response_time&quot;: f&quot;{avg_response_time:.3f}s&quot;,\n            &quot;requests_per_hour&quot;: self.stats&#091;&quot;total_requests&quot;] \/ (uptime.total_seconds() \/ 3600) if uptime.total_seconds() &gt; 0 else 0\n        }\n    \n    def health_check(self) -&gt; Dict&#091;str, Any]:\n        &quot;&quot;&quot;\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b&quot;&quot;&quot;\n        try:\n            &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438&lt;\/em&gt;\n            test_response = self._execute_search(SearchRequest(&quot;test query&quot;))\n            \n            return {\n                &quot;status&quot;: &quot;healthy&quot;,\n                &quot;timestamp&quot;: datetime.now().isoformat(),\n                &quot;tavily_api&quot;: &quot;connected&quot;,\n                &quot;cache&quot;: &quot;operational&quot;,\n                &quot;rate_limiter&quot;: &quot;operational&quot;,\n                &quot;last_test_status&quot;: test_response.status.value\n            }\n            \n        except Exception as e:\n            return {\n                &quot;status&quot;: &quot;unhealthy&quot;,\n                &quot;timestamp&quot;: datetime.now().isoformat(),\n                &quot;error&quot;: str(e)\n            }\n    \n    def cleanup(self):\n        &quot;&quot;&quot;\u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b&quot;&quot;&quot;\n        self.logger.info(&quot;Starting cleanup process...&quot;)\n        \n        &lt;em&gt;# \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u0433\u043e \u043a\u0435\u0448\u0430&lt;\/em&gt;\n        self.cache_manager.clear_expired()\n        \n        &lt;em&gt;# \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438&lt;\/em&gt;\n        stats_file = Path(&quot;agent_statistics.json&quot;)\n        try:\n            with open(stats_file, &#039;w&#039;, encoding=&#039;utf-8&#039;) as f:\n                json.dump(self.get_statistics(), f, ensure_ascii=False, indent=2)\n            self.logger.info(f&quot;Statistics saved to {stats_file}&quot;)\n        except Exception as e:\n            self.logger.error(f&quot;Failed to save statistics: {e}&quot;)\n        \n        self.logger.info(&quot;Cleanup completed&quot;)\n&lt;em&gt;# \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435&lt;\/em&gt;\nasync def main():\n    &quot;&quot;&quot;\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430&quot;&quot;&quot;\n    \n    &lt;em&gt;# \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\n    agent = ProductionSearchAgent(\n        tavily_api_key=&quot;tvly-YOUR_API_KEY&quot;,\n        model=&quot;mistral\/mistral-small-latest&quot;,\n        cache_ttl_hours=12,\n        rate_limit_per_minute=30,\n        log_level=&quot;INFO&quot;\n    )\n    \n    try:\n        &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f&lt;\/em&gt;\n        health = agent.health_check()\n        print(f&quot;Agent health: {health&#091;&#039;status&#039;]}&quot;)\n        \n        &lt;em&gt;# \u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b&lt;\/em&gt;\n        test_queries = &#091;\n            &quot;\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043a\u0432\u0430\u043d\u0442\u043e\u0432\u044b\u0445 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439&quot;,\n            &quot;\u0422\u0435\u043a\u0443\u0449\u0438\u0435 \u0442\u0440\u0435\u043d\u0434\u044b \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0418\u0418 2024&quot;,\n            &quot;\u0412\u043b\u0438\u044f\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u043c\u0430\u0442\u0430 \u043d\u0430 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u043a\u0443&quot;,\n        ]\n        \n        print(&quot;\\n=== \u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430 ===\\n&quot;)\n        \n        for i, query in enumerate(test_queries, 1):\n            print(f&quot;\u0417\u0430\u043f\u0440\u043e\u0441 {i}: {query}&quot;)\n            print(&quot;-&quot; * 60)\n            \n            result = agent.search(query, SearchDepth.BASIC)\n            print(result&#091;:500] + &quot;...&quot; if len(result) &gt; 500 else result)\n            \n            print(f&quot;\\n\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430:&quot;)\n            stats = agent.get_statistics()\n            print(f&quot;- \u0412\u0441\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432: {stats&#091;&#039;total_requests&#039;]}&quot;)\n            print(f&quot;- \u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0445: {stats&#091;&#039;success_rate&#039;]}&quot;)\n            print(f&quot;- \u0418\u0437 \u043a\u0435\u0448\u0430: {stats&#091;&#039;cache_hit_rate&#039;]}&quot;)\n            print(f&quot;- \u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u0432\u0435\u0442\u0430: {stats&#091;&#039;average_response_time&#039;]}&quot;)\n            print(&quot;\\n&quot; + &quot;=&quot;*80 + &quot;\\n&quot;)\n        \n        &lt;em&gt;# \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430&lt;\/em&gt;\n        print(&quot;\u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430:&quot;)\n        final_stats = agent.get_statistics()\n        for key, value in final_stats.items():\n            print(f&quot;{key}: {value}&quot;)\n    \n    finally:\n        &lt;em&gt;# \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432&lt;\/em&gt;\n        agent.cleanup()\nif __name__ == &quot;__main__&quot;:\n    asyncio.run(main())\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0431-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435-\u0444\u0430\u0439\u043b\u044b\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0411: \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"configagent_configjson\">config\/agent_config.json<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">{\n  &quot;tavily&quot;: {\n    &quot;api_key&quot;: &quot;tvly-YOUR_API_KEY&quot;,\n    &quot;default_search_depth&quot;: &quot;basic&quot;,\n    &quot;timeout_seconds&quot;: 30\n  },\n  &quot;agent&quot;: {\n    &quot;model&quot;: &quot;gpt-4&quot;,\n    &quot;framework&quot;: &quot;TinyAgent&quot;,\n    &quot;max_tokens&quot;: 4000,\n    &quot;temperature&quot;: 0.1\n  },\n  &quot;cache&quot;: {\n    &quot;enabled&quot;: true,\n    &quot;ttl_hours&quot;: 24,\n    &quot;max_size_mb&quot;: 100,\n    &quot;directory&quot;: &quot;.\/cache&quot;\n  },\n  &quot;rate_limiting&quot;: {\n    &quot;enabled&quot;: true,\n    &quot;requests_per_minute&quot;: 60,\n    &quot;burst_allowance&quot;: 10\n  },\n  &quot;logging&quot;: {\n    &quot;level&quot;: &quot;INFO&quot;,\n    &quot;file&quot;: &quot;agent.log&quot;,\n    &quot;max_file_size_mb&quot;: 10,\n    &quot;backup_count&quot;: 5\n  },\n  &quot;monitoring&quot;: {\n    &quot;enabled&quot;: true,\n    &quot;metrics_interval_seconds&quot;: 300,\n    &quot;health_check_interval_seconds&quot;: 60\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"dockerdockerfile\">docker\/Dockerfile<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">FROM python:3.11-slim\n\nWORKDIR \/app\n\n&lt;em&gt;# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439&lt;\/em&gt;\nRUN apt-get update &amp;&amp; apt-get install -y \\\n    gcc \\\n    &amp;&amp; rm -rf \/var\/lib\/apt\/lists\/*\n\n&lt;em&gt;# \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439&lt;\/em&gt;\nCOPY requirements.txt .\n\n&lt;em&gt;# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Python \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439&lt;\/em&gt;\nRUN pip install --no-cache-dir -r requirements.txt\n\n&lt;em&gt;# \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f&lt;\/em&gt;\nCOPY . .\n\n&lt;em&gt;# \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439&lt;\/em&gt;\nRUN mkdir -p \/app\/cache \/app\/logs\n\n&lt;em&gt;# \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0435\u0437 root&lt;\/em&gt;\nRUN useradd -m -u 1000 agent &amp;&amp; \\\n    chown -R agent:agent \/app\nUSER agent\n\n&lt;em&gt;# \u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u043f\u043e\u0440\u0442\u043e\u0432&lt;\/em&gt;\nEXPOSE 8000\n\n&lt;em&gt;# \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430&lt;\/em&gt;\nCMD &#091;&quot;python&quot;, &quot;-m&quot;, &quot;src.agents.production_search_agent&quot;]\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"docker-composeyml\">docker-compose.yml<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">version: &#039;3.8&#039;\n\nservices:\n  search-agent:\n    build: .\n    container_name: production-search-agent\n    environment:\n      - TAVILY_API_KEY=${TAVILY_API_KEY}\n      - LOG_LEVEL=INFO\n    volumes:\n      - .\/cache:\/app\/cache\n      - .\/logs:\/app\/logs\n      - .\/config:\/app\/config\n    ports:\n      - &quot;8000:8000&quot;\n    restart: unless-stopped\n    healthcheck:\n      test: &#091;&quot;CMD&quot;, &quot;python&quot;, &quot;-c&quot;, &quot;import requests; requests.get(&#039;http:\/\/localhost:8000\/health&#039;)&quot;]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n\n  redis:\n    image: redis:7-alpine\n    container_name: agent-redis\n    ports:\n      - &quot;6379:6379&quot;\n    volumes:\n      - redis_data:\/data\n    restart: unless-stopped\n\n  prometheus:\n    image: prom\/prometheus:latest\n    container_name: agent-prometheus\n    ports:\n      - &quot;9090:9090&quot;\n    volumes:\n      - .\/monitoring\/prometheus.yml:\/etc\/prometheus\/prometheus.yml\n    restart: unless-stopped\n\nvolumes:\n  redis_data:\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0432-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0412: \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"teststest_production_agentpy\">tests\/test_production_agent.py<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import pytest\nimport asyncio\nfrom unittest.mock import Mock, patch\nfrom src.agents.production_search_agent import (\n    ProductionSearchAgent,\n    SearchRequest,\n    SearchDepth,\n    SearchStatus\n)\n\n\n@pytest.fixture\ndef mock_agent():\n    &quot;&quot;&quot;\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u0430\u0433\u0435\u043d\u0442\u0430&quot;&quot;&quot;\n    with patch(&#039;src.agents.production_search_agent.TavilyClient&#039;):\n        agent = ProductionSearchAgent(\n            tavily_api_key=&quot;test-key&quot;,\n            model=&quot;gpt-4&quot;\n        )\n        return agent\n\n\nclass TestProductionSearchAgent:\n    \n    def test_agent_initialization(self, mock_agent):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0433\u0435\u043d\u0442\u0430&quot;&quot;&quot;\n        assert mock_agent is not None\n        assert mock_agent.stats&#091;&quot;total_requests&quot;] == 0\n        assert mock_agent.max_retries == 3\n    \n    def test_search_request_creation(self):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n        request = SearchRequest(\n            query=&quot;test query&quot;,\n            depth=SearchDepth.BASIC\n        )\n        \n        assert request.query == &quot;test query&quot;\n        assert request.depth == SearchDepth.BASIC\n        assert request.timestamp is not None\n        \n        cache_key = request.get_cache_key()\n        assert len(cache_key) == 32  &lt;em&gt;# MD5 hash&lt;\/em&gt;\n    \n    @patch(&#039;src.agents.production_search_agent.TavilyClient&#039;)\n    def test_successful_search(self, mock_tavily, mock_agent):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430&quot;&quot;&quot;\n        &lt;em&gt;# \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043c\u043e\u043a\u0430&lt;\/em&gt;\n        mock_tavily_instance = Mock()\n        mock_tavily.return_value = mock_tavily_instance\n        mock_tavily_instance.search.return_value = {\n            &#039;answer&#039;: &#039;Test answer&#039;,\n            &#039;results&#039;: &#091;{&#039;title&#039;: &#039;Test&#039;, &#039;url&#039;: &#039;http:\/\/test.com&#039;}]\n        }\n        \n        &lt;em&gt;# \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0438\u0441\u043a\u0430&lt;\/em&gt;\n        request = SearchRequest(&quot;test query&quot;)\n        response = mock_agent._execute_search(request)\n        \n        &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0438&lt;\/em&gt;\n        assert response.status == SearchStatus.SUCCESS\n        assert response.answer == &#039;Test answer&#039;\n        assert len(response.sources) == 1\n        assert not response.from_cache\n    \n    def test_cache_functionality(self, mock_agent):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u043a\u0435\u0448\u0430&quot;&quot;&quot;\n        cache_key = &quot;test_key&quot;\n        test_data = {&quot;answer&quot;: &quot;cached answer&quot;, &quot;sources&quot;: &#091;]}\n        \n        &lt;em&gt;# \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043a\u0435\u0448&lt;\/em&gt;\n        mock_agent.cache_manager.set(cache_key, test_data)\n        \n        &lt;em&gt;# \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u043a\u0435\u0448\u0430&lt;\/em&gt;\n        cached_data = mock_agent.cache_manager.get(cache_key)\n        \n        assert cached_data is not None\n        assert cached_data&#091;&quot;answer&quot;] == &quot;cached answer&quot;\n    \n    def test_rate_limiting(self, mock_agent):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0447\u0430\u0441\u0442\u043e\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&quot;&quot;&quot;\n        rate_limiter = mock_agent.rate_limiter\n        \n        &lt;em&gt;# \u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043b\u0438\u043c\u0438\u0442\u0430&lt;\/em&gt;\n        for _ in range(rate_limiter.max_requests):\n            rate_limiter.register_request()\n        \n        &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438&lt;\/em&gt;\n        assert not rate_limiter.can_make_request()\n        \n        &lt;em&gt;# \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f&lt;\/em&gt;\n        wait_time = rate_limiter.get_wait_time()\n        assert wait_time &gt; 0\n    \n    def test_statistics_tracking(self, mock_agent):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438&quot;&quot;&quot;\n        initial_stats = mock_agent.get_statistics()\n        assert initial_stats&#091;&quot;total_requests&quot;] == 0\n        assert initial_stats&#091;&quot;success_rate&quot;] == &quot;0.0%&quot;\n        \n        &lt;em&gt;# \u0421\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&lt;\/em&gt;\n        mock_agent.stats&#091;&quot;total_requests&quot;] = 10\n        mock_agent.stats&#091;&quot;successful_requests&quot;] = 8\n        mock_agent.stats&#091;&quot;cached_requests&quot;] = 2\n        \n        updated_stats = mock_agent.get_statistics()\n        assert updated_stats&#091;&quot;total_requests&quot;] == 10\n        assert updated_stats&#091;&quot;success_rate&quot;] == &quot;80.0%&quot;\n        assert updated_stats&#091;&quot;cache_hit_rate&quot;] == &quot;20.0%&quot;\n    \n    def test_health_check(self, mock_agent):\n        &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b&quot;&quot;&quot;\n        health = mock_agent.health_check()\n        \n        assert &quot;status&quot; in health\n        assert &quot;timestamp&quot; in health\n        assert health&#091;&quot;status&quot;] in &#091;&quot;healthy&quot;, &quot;unhealthy&quot;]\n\n\n@pytest.mark.asyncio\nasync def test_async_functionality():\n    &quot;&quot;&quot;\u0422\u0435\u0441\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438&quot;&quot;&quot;\n    &lt;em&gt;# \u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438&lt;\/em&gt;\n    &lt;em&gt;# \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c&lt;\/em&gt;\n    pass\n\n\nif __name__ == &quot;__main__&quot;:\n    pytest.main(&#091;__file__, &quot;-v&quot;])\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435-\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438\">\u0417\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"1-\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435-\u0432-\u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435\">1. \u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 Docker \u0434\u043b\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433<\/strong>: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 (Prometheus + Grafana) \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (ELK stack \u0438\u043b\u0438 \u0430\u043d\u0430\u043b\u043e\u0433\u0438).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"2-\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\">2. \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 API \u043a\u043b\u044e\u0447\u0435\u0439&lt;\/em&gt;\nimport os\nfrom cryptography.fernet import Fernet\n\nclass SecureConfig:\n    &quot;&quot;&quot;\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439&quot;&quot;&quot;\n    \n    def __init__(self, key_file: str = &quot;.encryption_key&quot;):\n        self.key_file = key_file\n        self.key = self._load_or_create_key()\n        self.cipher = Fernet(self.key)\n    \n    def _load_or_create_key(self) -&gt; bytes:\n        &quot;&quot;&quot;\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f&quot;&quot;&quot;\n        if os.path.exists(self.key_file):\n            with open(self.key_file, &#039;rb&#039;) as f:\n                return f.read()\n        else:\n            key = Fernet.generate_key()\n            with open(self.key_file, &#039;wb&#039;) as f:\n                f.write(key)\n            return key\n    \n    def encrypt_api_key(self, api_key: str) -&gt; str:\n        &quot;&quot;&quot;\u0428\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 API \u043a\u043b\u044e\u0447\u0430&quot;&quot;&quot;\n        return self.cipher.encrypt(api_key.encode()).decode()\n    \n    def decrypt_api_key(self, encrypted_key: str) -&gt; str:\n        &quot;&quot;&quot;\u0420\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0430 API \u043a\u043b\u044e\u0447\u0430&quot;&quot;&quot;\n        return self.cipher.decrypt(encrypted_key.encode()).decode()\n\n&lt;em&gt;# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435&lt;\/em&gt;\nconfig = SecureConfig()\nencrypted_key = config.encrypt_api_key(&quot;tvly-YOUR_API_KEY&quot;)\n&lt;em&gt;# \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c encrypted_key \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435&lt;\/em&gt;\n&lt;em&gt;# \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438:&lt;\/em&gt;\napi_key = config.decrypt_api_key(encrypted_key)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-\u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\">3. \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# \u041f\u0440\u0438\u043c\u0435\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b&lt;\/em&gt;\nfrom fastapi import FastAPI, HTTPException, BackgroundTasks\nfrom pydantic import BaseModel\nimport uvicorn\n\napp = FastAPI(title=&quot;Search Agent API&quot;, version=&quot;1.0.0&quot;)\n\nclass SearchQuery(BaseModel):\n    query: str\n    depth: str = &quot;basic&quot;\n    user_id: str = None\n\nclass SearchResponse(BaseModel):\n    query: str\n    answer: str\n    sources: list\n    response_time: float\n    from_cache: bool\n\n&lt;em&gt;# \u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0430\u0433\u0435\u043d\u0442\u0430&lt;\/em&gt;\nagent = ProductionSearchAgent(tavily_api_key=os.getenv(&quot;TAVILY_API_KEY&quot;))\n\n@app.post(&quot;\/search&quot;, response_model=SearchResponse)\nasync def search_endpoint(query: SearchQuery, background_tasks: BackgroundTasks):\n    &quot;&quot;&quot;\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n    try:\n        result = agent.search(query.query, SearchDepth(query.depth))\n        \n        &lt;em&gt;# \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435&lt;\/em&gt;\n        background_tasks.add_task(log_search_request, query, result)\n        \n        return SearchResponse(\n            query=query.query,\n            answer=result,\n            sources=&#091;],  &lt;em&gt;# \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c\u0438&lt;\/em&gt;\n            response_time=0.0,  &lt;em&gt;# \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c&lt;\/em&gt;\n            from_cache=False  &lt;em&gt;# \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u043c&lt;\/em&gt;\n        )\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n@app.get(&quot;\/health&quot;)\nasync def health_check():\n    &quot;&quot;&quot;\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430&quot;&quot;&quot;\n    return agent.health_check()\n\n@app.get(&quot;\/stats&quot;)\nasync def get_statistics():\n    &quot;&quot;&quot;\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438&quot;&quot;&quot;\n    return agent.get_statistics()\n\ndef log_search_request(query: SearchQuery, result: str):\n    &quot;&quot;&quot;\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430&quot;&quot;&quot;\n    &lt;em&gt;# \u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443&lt;\/em&gt;\n    pass\n\nif __name__ == &quot;__main__&quot;:\n    uvicorn.run(app, host=&quot;0.0.0.0&quot;, port=8000)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433-\u0438-\u0430\u043b\u0435\u0440\u0442\u0438\u043d\u0433\">4. \u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438 \u0430\u043b\u0435\u0440\u0442\u0438\u043d\u0433<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# monitoring\/prometheus.yml&lt;\/em&gt;\nglobal:\n  scrape_interval: 15s\n\nscrape_configs:\n  - job_name: &#039;search-agent&#039;\n    static_configs:\n      - targets: &#091;&#039;search-agent:8000&#039;]\n    metrics_path: &#039;\/metrics&#039;\n    scrape_interval: 30s\n\nrule_files:\n  - &quot;alert_rules.yml&quot;\n\nalerting:\n  alertmanagers:\n    - static_configs:\n        - targets:\n          - alertmanager:9093\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# monitoring\/alert_rules.yml&lt;\/em&gt;\ngroups:\n  - name: search_agent_alerts\n    rules:\n      - alert: HighErrorRate\n        expr: (rate(search_agent_failed_requests_total&#091;5m]) \/ rate(search_agent_total_requests_total&#091;5m])) &gt; 0.1\n        for: 2m\n        labels:\n          severity: warning\n        annotations:\n          summary: &quot;High error rate detected&quot;\n          description: &quot;Error rate is {{ $value | humanizePercentage }}&quot;\n\n      - alert: SlowResponseTime\n        expr: search_agent_avg_response_time_seconds &gt; 5\n        for: 5m\n        labels:\n          severity: critical\n        annotations:\n          summary: &quot;Slow response time&quot;\n          description: &quot;Average response time is {{ $value }}s&quot;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-\u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f\">5. \u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# .github\/workflows\/ci.yml&lt;\/em&gt;\nname: CI\/CD Pipeline\n\non:\n  push:\n    branches: &#091;main, develop]\n  pull_request:\n    branches: &#091;main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v3\n      \n      - name: Set up Python\n        uses: actions\/setup-python@v4\n        with:\n          python-version: &#039;3.11&#039;\n      \n      - name: Install dependencies\n        run: |\n          pip install -r requirements.txt\n          pip install -r requirements-test.txt\n      \n      - name: Run tests\n        run: |\n          pytest tests\/ --cov=src --cov-report=xml\n      \n      - name: Upload coverage\n        uses: codecov\/codecov-action@v3\n\n  security:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v3\n      \n      - name: Run security scan\n        run: |\n          pip install bandit safety\n          bandit -r src\/\n          safety check\n\n  build:\n    needs: &#091;test, security]\n    runs-on: ubuntu-latest\n    if: github.ref == &#039;refs\/heads\/main&#039;\n    steps:\n      - uses: actions\/checkout@v3\n      \n      - name: Build Docker image\n        run: |\n          docker build -t search-agent:latest .\n      \n      - name: Push to registry\n        run: |\n          echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin\n          docker push search-agent:latest\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f-api\">6. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f API<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&lt;em&gt;# \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f FastAPI&lt;\/em&gt;\nfrom fastapi import FastAPI\nfrom fastapi.openapi.utils import get_openapi\n\ndef custom_openapi():\n    if app.openapi_schema:\n        return app.openapi_schema\n    \n    openapi_schema = get_openapi(\n        title=&quot;Smart Search Agent API&quot;,\n        version=&quot;2.0.0&quot;,\n        description=&quot;&quot;&quot;\n        ## \u0423\u043c\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0430\u0433\u0435\u043d\u0442 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0435\u0439 Tavily\n\n        \u042d\u0442\u043e\u0442 API \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0443\u043c\u043d\u043e\u043c\u0443 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u043c\u0443 \u0430\u0433\u0435\u043d\u0442\u0443,\n        \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.\n\n        ### \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438:\n        - \u041f\u043e\u0438\u0441\u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438\n        - \u041a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438\n        - \u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0447\u0430\u0441\u0442\u043e\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\n        - \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\n        - \u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b\n\n        ### \u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f:\n        \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 API \u043a\u043b\u044e\u0447 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 `X-API-Key`\n        &quot;&quot;&quot;,\n        routes=app.routes,\n    )\n    \n    openapi_schema&#091;&quot;info&quot;]&#091;&quot;x-logo&quot;] = {\n        &quot;url&quot;: &quot;https:\/\/example.com\/logo.png&quot;\n    }\n    \n    app.openapi_schema = openapi_schema\n    return app.openapi_schema\n\napp.openapi = custom_openapi\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"\u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0435-\u0432\u044b\u0432\u043e\u0434\u044b\">\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u0432\u044b\u0432\u043e\u0434\u044b<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f&nbsp;<strong>any-agent<\/strong>&nbsp;\u0441&nbsp;<strong>Tavily<\/strong>&nbsp;\u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043c\u043e\u0449\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0418\u0418-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u042d\u0442\u0430 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0432\u044f\u0437\u043a\u0430 \u0440\u0435\u0448\u0430\u0435\u0442 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435-\u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u044f:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ud83c\udfaf \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0415\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0430\u0433\u0435\u043d\u0442\u043d\u044b\u043c\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u26a1 \u0410\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0432\u0435\u0436\u0435\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ud83d\udd27 \u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c<\/strong>: \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u0442\u0430\u043a \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043c\u0443\u043b\u044c\u0442\u0438-\u0430\u0433\u0435\u043d\u0442\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ud83d\udcca \u041d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c<\/strong>: \u041f\u043e\u043b\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430: \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433, \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ud83d\ude80 \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c<\/strong>: \u0413\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u0435<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435-\u0432-\u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445-\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445\">\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u041a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u044b<\/strong>&nbsp;\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438<\/li>\n\n\n\n<li><strong>\u0421\u0438\u0441\u0442\u0435\u043c\u044b \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0440\u044b\u043d\u043a\u0430<\/strong>&nbsp;\u0434\u043b\u044f \u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0445 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0439<\/li>\n\n\n\n<li><strong>\u0418\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b<\/strong>&nbsp;\u0434\u043b\u044f \u043d\u0430\u0443\u0447\u043d\u044b\u0445 \u0443\u0447\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0439<\/li>\n\n\n\n<li><strong>\u041d\u043e\u0432\u043e\u0441\u0442\u043d\u044b\u0435 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u044b<\/strong>&nbsp;\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/li>\n\n\n\n<li><strong>\u041e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a\u0438<\/strong>&nbsp;\u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u043d\u0430\u043d\u0438\u044f\u043c\u0438<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"\u0431\u0443\u0434\u0443\u0449\u0435\u0435-\u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435\">\u0411\u0443\u0434\u0443\u0449\u0435\u0435 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0442\u0441\u044f. \u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f any-agent + Tavily \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u0440\u043e\u0447\u043d\u0443\u044e \u043e\u0441\u043d\u043e\u0432\u0443 \u0434\u043b\u044f \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0438 \u043a \u043d\u043e\u0432\u044b\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u0443\u044e \u0446\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0446\u0438\u0439 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><em>\u0414\u0430\u043d\u043d\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 &#8212; \u043e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0434\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0435\u0433\u043e \u043a\u0430\u043a \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0443\u043c\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0423\u0434\u0430\u0447\u0438 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435! \ud83e\udd16\u2728<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c \u043c\u0438\u0440\u0435 \u0418\u0418-\u0430\u0433\u0435\u043d\u0442\u043e\u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u044b \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0434\u0430\u0442\u043e\u0439 \u0441\u0440\u0435\u0437\u0430 \u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445, \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u0446\u0435\u043d\u0430\u0445 \u0438\u043b\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u044f\u0445.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u044f\u0437\u043a\u0438\u00a0any-agent\u00a0(\u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0433\u0435\u043d\u0442\u0430\u043c\u0438 \u043e\u0442\u00a0Mozilla.ai) \u0438\u00a0Tavily\u00a0(\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0434\u043b\u044f \u0418\u0418)<\/p>\n","protected":false},"author":1,"featured_media":3078,"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,308,169],"class_list":["post-2277","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-llm","tag-tag-ai-agent","tag-tag-artificial-intelligence","tag-169"],"acf":[],"_links":{"self":[{"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/posts\/2277","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=2277"}],"version-history":[{"count":0,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/posts\/2277\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/media\/3078"}],"wp:attachment":[{"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/media?parent=2277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/categories?post=2277"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ru.davidka.net\/ru\/wp-json\/wp\/v2\/tags?post=2277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}