 Добрый день, с вами Сергей Трощенков.  И вот спустя несколько месяцев такого радиомолчания  снова записываю для вас скринкаст.  Тем более, что есть интересный хороший повод для этого.  Не так давно GigaChat анонсировали,  что в их моделях теперь возможно вызывать функции.  А это значит, что используя модели GigaChat  можно создавать агентов.  Это достаточно горячая тема.  Изначально ее активно продвигали OpenAI.  Их модели были первые, кто реализовал этот функционал.  Другие разработчики языковых моделей,  Anthropic, Mistral и ряд других,  тоже со временем реализовали вызов функций  в своих моделях.  Но, как оказалось, реализации несколько отличаются.  И в ответ на это,  лангчейн библиотека,  форком которой в виде гигачейна мы с вами пользуемся,  реализовали такой более-менее универсальный обработчик  вызовов функций от разных моделей.  И, конечно же, мы получаем от них    для производства языковых моделей.  Так что практически бесшовно можно реализовывать  программный код, подставляя разные языковые модели. 

 для производства языковых моделей. Так что практически бесшовно можно реализовывать программный код, подставляя разные языковые модели. Чуть-чуть есть отличие, когда мы работаем с GigaChat.  Для GigaChat создана в GigaChain отдельная функция.  Мы на нее посмотрим потом.  Которая стыкует тоже вызов функций из именно модели GigaChat.  Но давайте, прежде чем уходить в эти технические детали,  проговорим, а что такое агент и почему сообщество  так активно заинтересовалось этой темой.  Дело в том, что вообще изначально языковые модели  были созданы для того, чтобы решать,  да, что нужно делать.  Языковые задачи.  И основная цель — генерировать текст.  Но оказалось, что посредством генерации текста  мы можем решать разнообразные задачки,  в том числе и генерируя текст, возможно,  через принятие решений осуществлять какие-то  ветвления в виде выборов разных вариантов.  Ну и воспользовавшись этим и тем, что помимо просто текстов,  в принципе, языковая модель может и генерировать код, 

 ветвления в виде выборов разных вариантов. Ну и воспользовавшись этим и тем, что помимо просто текстов, в принципе, языковая модель может и генерировать код, и выдавать не просто текст как последовательность  предложений, а, например, выдавать некий структурированный  ответ, когда в ответе присутствуют какие-то обязательные элементы,  да, и за счет этого мы эти элементы можем брать и  подставлять в программный код.  Оказалось, что можно реализовать инструменты, по сути, вот, функции,  питомцев, да, и, в принципе, это, в принципе, очень важно.  Ну и в том числе и держатьutter.  Естественно, если у вас на воспоминаниях есть какие-то  выборные tah.  Например, интересно, делали ли мы это Гуглов的时候   Нет, то есть мы нашли не те изменения, а в составе  입 categких взявшуюся, например, пробочную SIM-ки,  земляную PIN или DTP-ки еще нмное действующуюバ,   Ну и, например, устройство всё это оп mains еж.  Есть ли у него S denke, качественный ум 125 за typo  fishermen, вернее? 

 Ну и, например, устройство всё это оп mains еж. Есть ли у него S denke, качественный ум 125 за typo fishermen, вернее? Это сейчас, к примеру, он не спрашивает constructs или  esquany на чикagem, во-первых, код Probable per hobby,  Использовать инструменты из тех, которые ей предоставлены в доступе, она может использовать. То есть есть ряд действий, с которыми языковые модели справляются объективно не очень хорошо.  Они плохо считают, у них есть ограничения по тому объему информации, которой они владеют. То есть возможны галлюцинации, возможны ошибки при выдаче какой-то информации.  Ограничения, связанные с тем, что языковая модель не имеет доступа к актуальным новостям, актуальной повестке.  Все это.  Все это можно решить, используя вот эти дополнительные инструменты. 

 Ограничения, связанные с тем, что языковая модель не имеет доступа к актуальным новостям, актуальной повестке. Все это. Все это можно решить, используя вот эти дополнительные инструменты. То есть мы можем подключить функцию калькулятор, например, и сказать языковой модели, что когда ты будешь сталкиваться с математическими задачками, ты просто сформируй некий словарик, да, питонический, где будут аргументы в виде чисел, которые нужно посчитать.  И, допустим, название.  Математическая операция.  И далее мы вызовем функцию, подставив туда вот эти аргументы.  И тем самым сможем безошибочно, используя жесткие алгоритмы, посчитать правильно, какой должен получиться результат.  Или в силу ограничения доступа к информации давайте мы подключим инструмент, чтобы...  Программа могла...  Чтобы языковая модель могла искать информацию в интернете.  И тем самым мы обойдем ограничения, связанные с ограниченным объемом знаний, с, возможно, галлюцинациями. 

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

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

 Также здесь скажу. Значит, поскольку тема относительно новая, тот материал, который мы будем сегодня разбирать, он достаточно, во-первых, сложный. Во-вторых, я не претендую здесь на какую-то истину в последней инстанции.  Если в предыдущих туториалах...  То, что я показывал, было достаточно хорошо реализовано,  то здесь я не исключаю, что мною могут быть допущены какие-то...  Ну, не то что ошибки, а скорее недоработки.  Потому что эта тема на стыке, получается, и программирования,  и какого-то серьезного промп-инжиниринга,  и вообще понимания вот этой вот агентности.  Где, с одной стороны, есть инструменты,  с другой стороны, есть свобода выбора языковой моделью  каких-то стратегий и последовательности действий.  Ну и в силу того, что под GigaChat и GigaChain примеры даже не то,  что ограничены по пальцам одной руки,  там даже пальцев одной руки будет много,  возможно, где-то я что-то упускаю.  Если...  Если у вас есть опыт, и вы преуспели в реализации агентов,  и можете что-то подсказать, 

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

 Смысл в том, что он может просмотреть список этих заметок, просмотреть какую-то конкретную заметку, задав в качестве аргументов функцию названия этой заметки. Ну и создать новую заметку можно также.  Помимо вот такого хранилища информации,  у нас будет возможность поиска информации в интернете.  Мы для этого используем DuckDuckGo как поисковик.  В лонгчейне, гигачейне есть реализация и под Google Search,  но Google Search, насколько я знаю, там реализован через SERP API.  SERP API требует регистрации и, соответственно, ключа для доступа.  Чтобы зарегистрироваться, нужен нероссийский номер телефона.  Соответственно, мы этот вариант не берем сейчас.  А DuckDuckGo, поскольку это, в принципе, поисковик,  который работает на условиях, там, позиционировать, по крайней мере, себя,  что анонимности и не сбора какой-то информации о пользователях,  чтобы какие-то рекомендации более персонализированные выдавать,  то никакой регистрации там не требуется. 

 что анонимности и не сбора какой-то информации о пользователях, чтобы какие-то рекомендации более персонализированные выдавать, то никакой регистрации там не требуется. Помимо этого, у нас будет интересная, наверное, самая сложная функция.  Это поиск роликов.  По запросу на YouTube и выдаче информации про этот ролик.  То есть там будет извлекаться, если они есть, субтитры.  И эти субтитры будут саморизироваться, то есть выдаваться некая сжатая версия содержимого видеоролика.  Ну и для этого нам потребуется ряд библиотек.  Тут на самом деле самое сложное.  Это вот мишанка.  Это вот мишанина с YouTube.  Я в итоге использовал, собственно, для отправки запросов,  мы чуть дальше увидим, непосредственно тот инструмент, который есть в лонгчейне и гигачейне.  Но на самом деле он не очень хорошо работает.  По-хорошему надо сделать что-то свое.  И дальше мы все равно свой собственный код используем для извлечения субтитров и другой информации.   Метаданных, скажем так, о видеороликах. 

 И дальше мы все равно свой собственный код используем для извлечения субтитров и другой информации. Метаданных, скажем так, о видеороликах. Поэтому, наверное, стоило бы сделать и отдельный свой инструмент для именно просто запросов.  Но воспользуемся тем, что есть.  Тем более, что наша задача именно посмотреть больше на поведение языковой модели, нежели чем идеальную реализацию инструментов.  К языковой модели у нас будут некоторые вопросы.  Значит, ну что, нам потребуется доступ к ключам.  У меня есть обычный ключ, чтобы light модель использовать.  Ну и мы попробуем также другой ключ использовать для pro версии.  Так, библиотечки у меня, по-моему, все установлены.  Я сейчас поэтому эту ячейку с установкой перезапускать не буду.  Нам как раз нужно...  Как обычно потребуется класс gigachat для того, чтобы создать такой свой instance, да,  свою версию для подключения к API gigachat.  Сперва давайте используем light версию.  Поэтому запускаю вот эту ячейку. 

 свою версию для подключения к API gigachat. Сперва давайте используем light версию. Поэтому запускаю вот эту ячейку. Значит, на момент записи этого ролика доступ к модели,  у которой есть вызов функции, осуществляется по вот такому имени.  Возможно, как-то несколько позже вы будете также запускать этот программный код.  Скорее всего, уже можно будет писать просто gigachat.  То есть функцию...  Функционал вызова функции его поместят в основную модель.  И, соответственно, можно будет просто по имени gigachat вызывать.  Что дальше?  Давайте сперва мы посмотрим простейший пример,  где будут...  Элементарные функции будут использоваться.  Посмотрим, как это должно срабатывать, какой ответ выдают нам языковые модели.  А потом перейдем к нашему основному примеру с сложным ассистентом.  Значит, смысл в том, что...  В LangChainCore есть модуль Tools, и в нем есть инструмент Tools,  который выступает в роли такого декоратора.  То есть мы можем обозначать с помощью специального декоратора те функции, 

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

 Пусть у нас будут функции, которые выполняют математические операции. Первое просто у нас складывает два числа, то есть модель должна сделать словарик, в котором, во-первых, назовет ту функцию, которую нужно вызвать, во-вторых, передаст необходимые аргументы,  в данном случае аргументы A и B,  и укажет, что...   И укажет, что функции или, допустим, сложение, или умножение.  Мы вот это делаем вот так,  собираем те функции, которые будут выполнять роль инструментов в отдельный список,  и этот список мы в итоге должны связать с языковой моделью.  Сейчас мы это сделаем с помощью bindTools.  Это не совсем создание полноценного агента,  но...  Сделав вызов вот этого метода bindTools,  мы уже сможем добиться от языковой модели,  чтобы когда мы будем делать некий запрос,  который будет похож на то, что нужно обратиться к какой-то функции,  мы увидим, что ответ модели будет с использованием дополнительных аргументов,  указывающих, как если бы мы по-настоящему хотели сейчас вызвать...  вот эту функцию. 

 мы увидим, что ответ модели будет с использованием дополнительных аргументов, указывающих, как если бы мы по-настоящему хотели сейчас вызвать... вот эту функцию. Ну, давайте запустим вот эту ячейку с кодом.  Ну и дальше...  Дальше мы должны сделать некий запрос  и передать этот запрос...  Как правило, это делают с помощью метода invoke.  То есть наша вот эта языковая модель, снабженная инструментами,  по сути, это уже некая цепочка.  К ней обращаются...  С помощью метода invoke передавая запрос.  Ну вот, допустим, у нас есть запрос, есть две функции.  В принципе, можно сделать запрос там...  Привет, как дела?  И тогда никакой функции вызывать не нужно.  Модель ответит там...  Привет, хорошо, как у тебя?  А если мы зададим какой-то запрос,  который будет похож на то, что речь идет про вызов соответствующей функции,  то мы должны получить результат.  Для вызова этой функции.  Вот, смотрите, какая история получается.  Мы в ответ получаем AI-месседж. 

 Для вызова этой функции. Вот, смотрите, какая история получается. Мы в ответ получаем AI-месседж. Помним, да, из предыдущих наших туториалов, что такое AI-месседж.  AI-месседж — это одна из трех разновидностей сообщений,  которые есть у больших языковых моделей,  когда они через лангчейн или гигачейн вызываются.  Там у нас есть система,  там у нас есть human-месседж,  и вот AI-месседж — это ответ ассистента,  ответ искусственного интеллекта.  Значит, интересной особенностью AI-месседжа является...  При обращении к функции является то,  что в атрибуте вот этом content,  где обычно содержится, собственно, текстовое сообщение,  вот он здесь возвращается пустым,  зато появляется того, чего обычно у нас не было,  additional args, ну, additional quarks,  значит, получается вот эти именованные аргументы  в виде словарей, что какая функция будет вызываться.  Вот тут function call.  Мы видим здесь, что по этому запросу языковая модель поняла,  что мы вызываем функцию умножения, 

 Вот тут function call. Мы видим здесь, что по этому запросу языковая модель поняла, что мы вызываем функцию умножения, и что в качестве аргументов нужно передать два числа — 3 и 12.  Ну и дальше там различная служебная информация  про то, сколько было потрачено токенов.  Мы видим, что на ответ было потрачено 17 токенов,  а там сколько-то 116 токенов — это наш контекст,  наш запрос, потому что помимо вот этой информации,  у нас в контекстное окно еще помещаются вот эти вот описания.  Там дело в том, что за счет вот этого декоратора  происходит преобразование вот этой вот функции  в джейсоновский как бы формат,  который в языковой модели понятен,  что это вот название функции, это ее описание,  а вот такие аргументы нужно передать.  Тут есть некоторые различные аргументы,  которые, как я уже говорил,  могут быть вне значения между ланкчейном и гигачейном,  который обращается непосредственно к гигачату,  когда мы пользуемся гигачатом,  потому что вот в базовом примере на ланкчейн  там даже не так написано. 

 когда мы пользуемся гигачатом, потому что вот в базовом примере на ланкчейн там даже не так написано. Там написано, сколько будет, ну и допустим,  одна операция и другая операция.  Давайте мы тоже так попробуем написать.  Сколько будет, ну не знаю там, 47 плюс 20, например.  И если я вот такой запрос попробую задать,  то что мы получим?  Мы получим, что все равно  только первое действие выполнилось.  Да?  В то время как в ланкчейновских примерах  с языковыми моделями там от OpenAI  и других разработчиков,  там при вот каком-то таком запросе  перечисляется вызов нескольких функций.  То есть по факту в этом запросе мы попросили  выполнить два действия,  а он выдает нам одно действие.  Вот в этом как бы основная разница  текущего состояния GigaChat  и других языковых моделей,  что мы за раз можем попросить выполнить одно действие.  И более того, я так понимаю,  что немножечко не хватает  каких-то вот внимания или вычислительных  каких-то возможностей GigaChat,  если мы пробуем как-то сложно сформулировать 

 каких-то вот внимания или вычислительных каких-то возможностей GigaChat, если мы пробуем как-то сложно сформулировать этот запрос.  Вот мы там дальше попробуем реализовать  вот наши функции, которые я перечислял ранее.  И если мы будем как-то пробовать  помимо вызова функций еще какую-то  дополнительную информацию дать,  с этим будет туго.  Ну, давайте посмотрим, как это будет у нас на практике,  потому что дальше мы, собственно, создадим нашего  полноценного агента.  Так, для этого, да, то есть вот это сейчас был не агент,  это был просто вызов функции, да,  чтобы она выдавала нам ответ в формате  удобном для вызова функций.  Но агент чуть-чуть посложнее делается.  Давайте мы перезапустим сеанс,  чтобы он опять забыл все наши эти переменные.  И некоторые ячейки перезапустим заново,  там, допустим, где мы кликнули,  вот, например, в Google Cloud.   мы берем следующие ключи из секретов Google Клаба.  Собственно, импортируем класс для модели,  создадим экземпляр API для доступа к API у модели. 

 мы берем следующие ключи из секретов Google Клаба. Собственно, импортируем класс для модели, создадим экземпляр API для доступа к API у модели. Опять же, пока лайтовая модель.  Значит, это мы пропускаем, потому что это вот наш  неполноценный пример.  А теперь давайте перейдем к полноценному примеру.  Значит, в полноценном примере нам, во-первых,  нужно будет сделать сейчас отдельную папочку,  где будут храниться создаваемые заметки.  И нам нужен будет инструмент для доступа к этой папке  и выполнению действий внутри нее.  Для этого мы используем файл Management Toolkit из ланчейна.  Он же в GigaChain тоже есть, который позволяет выполнять  там что-то порядка шести, по-моему, действий.  Можно посмотреть, если что, в документации.  То есть он может посмотреть содержимое этой папки.  Это один инструмент.  Записать новый файл в эту папку, прочитать какой-то  конкретный файл, переименовать, переместить и так далее.  Но мы будем пользоваться записью, чтением и просмотром, 

 Записать новый файл в эту папку, прочитать какой-то конкретный файл, переименовать, переместить и так далее. Но мы будем пользоваться записью, чтением и просмотром, чтением отдельного файла, просмотром содержимого папки.  Соответственно, запустим вот эту ячейку с кода.  И благодаря использованию вот этих инструментов  мы будем изменять содержимое вот этой вот созданной папки.  Пока что она пустая.  По мере обращения мы будем получать внутри там некие заметки.  Теперь, собственно, обладая вот этим инструментом,  File Management Toolkit, а именно, да, у нас будет переменная File Tools,  давайте мы создадим отдельные функции, которые будут обращаться  к вот этой папке заметок.  Значит, первая функция, тут все должно быть понятно,  это функция получения содержимого папки заметок.  Так, тут это я экспериментировал, чтобы он мне выводил print.  Не нужно это.  То есть просто, что у нас происходит?  Мы из вот этого перечня инструментов, давайте, наверное, покажу как раз. 

 Не нужно это. То есть просто, что у нас происходит? Мы из вот этого перечня инструментов, давайте, наверное, покажу как раз. Значит, здесь есть вот такая опция Get Tools.  Вот перечень всех доступных нам инструментов.  Можно копировать файл, удалить файл и так далее.  Нас в первой функции будет интересовать  получение списка доступных файлов.  Это будет у нас вот этот вот List Directory Tool,  поэтому мы будем выхватывать последний инструмент,  как здесь и написано.  Причем обращаться к этому инструменту можно посредством метода Invoke.  И поскольку там дальше нужно передавать  во все эти инструменты словарь с аргументами,  для того чтобы посмотреть перечень файлов в привязанной директории,  никаких аргументов передавать не нужно, поэтому передается пустой словарь.  Но оно нам возвращает некую строчку,  а мы в дальнейшем будем эту строчку делить по переносу на новую строчку.  Дело в том, что, ну давайте сейчас покажу.  Сейчас он вернет, что нет файлов в папке. 

 а мы в дальнейшем будем эту строчку делить по переносу на новую строчку. Дело в том, что, ну давайте сейчас покажу. Сейчас он вернет, что нет файлов в папке. И, соответственно, несмотря на то, что не было переноса на новую строчку,  он создал нам словарь с одним элементом.  Мы будем использовать вот эту возможность,  чтобы считать количество элементов в папке для того,  чтобы, создавая новые заметки,  у нас у каждой заметки был как бы идентификатор в виде целого числа.  Получается, что когда папка пустая,  первая заметка будет иметь вот этот уникальный идентификатор 1.  Затем, когда в папке создастся одна заметка,  на самом деле там будет два файла.  Нам вот этот инструмент будет возвращать,  что там два файла.  Первый — это, собственно, заметка,  и второй — там некий служебный файлик,  который, скорее всего, даже скрытый,  но все равно этот инструмент будет его видеть,  и они будут выводиться, каждый файл, с новой строки,  и получится, что для того, чтобы создать вторую заметку, 

 но все равно этот инструмент будет его видеть, и они будут выводиться, каждый файл, с новой строки, и получится, что для того, чтобы создать вторую заметку, мы получим длину вот этого списка, равную двум,  и мы используем эту двойку для создания,  для создания очередной заметки с уникальным вот этим идентификатором.  Ну вот это можно будет увидеть в следующем инструменте записи заметки.  Вот мы будем использовать длину возвращаемого списка  в качестве дополнительного идентификатора.  Значит, ну, я думаю, что понятно с инструментом для получения списка заметок.  Это...  Значит, все инструменты вызываются через Invoke,  и в, допустим, инструменте для создания новой заметки  мы, помимо, собственно, инструмента для записи,  который предпоследний в списке общем,  мы также и последний вот этот инструмент,  возвращающий количество элементов,  тоже будем использовать, да,  для получения числа n, которое будет подставляться.  Дело в том, что для создания заметки 

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

 для чтения файла, вот он. И если, мало ли, при попытке прочитать файл у нас будет выводиться сообщение, что такого файла не существует, дело в том, что у нас есть файл, который будет выводиться сообщение, что такого файла не существует,  то нужно вот строго указывать название файла.  Языковая модель может порой с этим не справиться.  Чтобы у нас это все четко обрабатывалось, да,  мы здесь некий обработчик ошибки добавляем,  хотя, скорее всего, при попытке обращения к несуществующему файлу  выдастся просто уже там встроенный какой-то обработчик,  скорее всего, есть, выдастся просто сообщение, что такого файла нет.  Так, это мы, значит, разобрали.  Мы разобрались с инструментами по заметкам.  А дальше давайте создадим инструменты для доступа к внешним источникам информации.  То есть у нас будет внутреннее хранилище информации,  такой а-ля второй мозг, то, что называется сейчас, да, модным термином.  Будут еще доступы к внешним ресурсам.  Мы здесь, кстати, не реализуем RAC-систему, да, 

 такой а-ля второй мозг, то, что называется сейчас, да, модным термином. Будут еще доступы к внешним ресурсам. Мы здесь, кстати, не реализуем RAC-систему, да, систему вопросно-ответную, как бы,  когда запросы реализуются к некой базе данных.  В принципе, можно было бы вместо вот этой системы заметок  реализовать векторную базу данных и делать запросы туда,  но я хочу сделать как-нибудь отдельно ролик про RAC-системы,  поэтому оставим это на потом.  У нас просто будут текстовые заметки в папочке  и обращаться к заметке можно только по ее названию.  Хорошо, давайте посмотрим, что у нас дальше.  Дальше у нас инструмент по доступу к интернету.  Есть вот такой инструмент в ланкчейне.  DuckDuckGoSearch.run, по-моему, есть.  И есть DuckDuckGoSearchResults.  Они отличаются тем, что...  Results более гибкий, он там дополнительно некие метаданные дает  по результатам поиска, поэтому я использовал его.  Можно было бы использовать просто DuckDuckGoSearch, по-моему, run называется. 

 Results более гибкий, он там дополнительно некие метаданные дает по результатам поиска, поэтому я использовал его. Можно было бы использовать просто DuckDuckGoSearch, по-моему, run называется. Значит, тоже мы даем здесь описание, что этот инструмент делает.  Собственно, делаем запрос.  И можно было бы на этом вот сделать ReturnResult.  Но я здесь чуть-чуть подстраховываюсь в плане того, чтобы запрос не ушел в пустоту.  Мы увидим на примере вот этого инструмента и еще более, как бы,  плачевную ситуацию порой со следующим инструментом,  что результаты обращения к инструменту могут вполне потеряться.  Дело в том, что мы не будем видеть всю...  все происходящие моменты при обращении к той или иной функции.  Мы выведем это в виде некой служебной информации,  но эти результаты не пойдут в диалог.  В диалог пойдет только конечный ответ, который выдает модель.  И, соответственно, в памяти нашего общения окажется тоже этот результат. 

 но эти результаты не пойдут в диалог. В диалог пойдет только конечный ответ, который выдает модель. И, соответственно, в памяти нашего общения окажется тоже этот результат. И мы увидим, что порой наши ассистенты, когда мы их просим сделать запрос,  там, в интернет или в YouTube, они говорят,  «Да, я сделал запрос, там, кое-что нашлось, как бы, вот, все».  И получается, что запрос выполнен, какие-то токены на него потрачены,  а оно, как бы, в диалоге не появилось,  и если мы хотим про это что-то расспросить подробнее, языковую модель,  нам надо просить ее сделать запрос заново.  Это очень неудобно, поэтому...  Здесь реализован, как бы, механизм подстраховки.  В чем он заключается?  Он заключается в том, что тот результат, который будет осуществлен в ходе запроса в интернет,  он будет записан тоже в виде заметки в нашу папочку.  Это просто на самом деле...  На самом деле я изначально не хотел так делать,  но поэкспериментировав с ассистентом, я понял, что это разумная подстраховка. 

 Это просто на самом деле... На самом деле я изначально не хотел так делать, но поэкспериментировав с ассистентом, я понял, что это разумная подстраховка. Поэтому давайте запустим эту функцию.  И обратимся к следующей.  Вот тут сложная функция.  На ней стоит остановиться чуть подробнее.  Как видите, здесь гигантское количество импортов разнообразных,  потому что на самом деле здесь функция, которая делает достаточно много действий.  Давайте о них поговорим.  Значит, что нам здесь нужно?  Мы используем инструмент, который есть в GigaChain-е, логин.   В лэнгчейне, а именно YouTube Search Tool.  Он принимает на вход некую фразу-запрос и возвращает ссылки на самом деле.  Ссылки на YouTube ролики и больше ничего.  Если мы хотим эту информацию как-то обработать, использовать в дальнейшем,  нам нужны дополнительные инструменты.  Ну вот в данном случае мы из полученной вот этой вот...  полученных ссылок будем вытаскивать идентификатор.  То есть в YouTube видеоролике есть кусочек, 

 Ну вот в данном случае мы из полученной вот этой вот... полученных ссылок будем вытаскивать идентификатор. То есть в YouTube видеоролике есть кусочек, который является по сути уникальным идентификатором того или иного видеоролика.  Вот он нам будет нужен.  Мы его будем вытаскивать и подставлять дальше.  Также у нас вот здесь создается с помощью функции loadSummarizeChain.  Вот строчка импорта.  Это функция, которая создаст нам цепочку, chain,  который занимается самаризацией.  Там можно разные параметры задавать.  Мы сделаем самаризацию по методу MapReduce.  Смысл самаризации по методу MapReduce заключается в том,  что мы можем взять достаточно большой текст,  который может даже сильно вытаскивать,  или вообще сильно превышать размер контекстного окна языковой модели,  разделить его на то, что называется чанки,  то есть кусочки определенного размера.  Причем, как правило, эти кусочки делаются с некоторым перекрытием.  То есть в них есть повторяющиеся кусочки, 

 то есть кусочки определенного размера. Причем, как правило, эти кусочки делаются с некоторым перекрытием. То есть в них есть повторяющиеся кусочки, но это делается для того, чтобы не потерять какой-то контекст.  И дальше каждый из этих кусочков отдельно самаризируется.  Дальше они собираются вместе, самаризируются вместе,  если даже в ходе, значит,  Кусочков они все равно не все сразу влезают в контекстное окно, их собирают по частям так, чтобы они влезали.  И вот путем нескольких итераций у нас в итоге получается некоторое обобщение итогового текста.  Мы это будем использовать для того, чтобы вытащенные субтитры из видеоролика использовать для получения краткого содержания видеоролика.  Помимо этого, что у нас, собственно, в функции будет происходить?  Значит, мы будем делать вот это yt, это у нас, собственно, инструмент для запросов.  В ответ мы будем получать, значит... 

 Помимо этого, что у нас, собственно, в функции будет происходить? Значит, мы будем делать вот это yt, это у нас, собственно, инструмент для запросов. В ответ мы будем получать, значит... Строчку в JSON-овском формате, но не совсем правильном на самом деле, поэтому в ходе его преобразования в обычный список нам придется заменить там кавычки еще.  Но в результате мы получим список из ссылок.  По умолчанию он, по-моему, возвращает два видеоролика.  Ну, повторюсь, не очень удобный, ранее говорил уже, вот этот вот инструмент.  Лучше было бы реализовать что-то свое.  Но я уже не стал заморачиваться именно для просто поиска.  Хотя возможности для этого есть.  Там еще такой момент, что он не очень учитывает региональные возможности запросов.  То есть, ну вот когда мы там кириллицей чего-то будем прям запрашивать, он более-менее релевантно будет находить.  Если мы что-нибудь по-английски будем запрашивать, навряд ли он нам вернет что-то прям очень релевантное. 

 Там еще такой момент, что он не очень учитывает региональные возможности запросов. То есть, ну вот когда мы там кириллицей чего-то будем прям запрашивать, он более-менее релевантно будет находить. Если мы что-нибудь по-английски будем запрашивать, навряд ли он нам вернет что-то прям очень релевантное. Если нас интересует какое-то англоязычное название, но, допустим, российские какие-то видеоролики.  Но это как бы немножко выходит за рамки сегодняшнего вебинара.  Не вебинара, а туториала.  Значит, поэтому оставим как есть.  Дальше что?  Полученные вот эти вот ссылки, мы из них будем вытаскивать собственный идентификатор.  Этим занимаются вот эти две строчки на самом деле.  То есть мы разделим...  Мы разделим по знаку равенства.  Дело в том, что...  Ну, это же по сути ссылка URL.  В ссылке URL там есть ряд передаваемых параметров.  Собственно, видеоролик, какие-то другие служебные вещи. 

 Ну, это же по сути ссылка URL. В ссылке URL там есть ряд передаваемых параметров. Собственно, видеоролик, какие-то другие служебные вещи. Мы можем разделить по знаку равенства, потому что каждый параметр, да, он через знак равенства в строке запроса...  Ну, в адресной строке указывается.  И помимо этого нам от...  От получившегося кусочка нужно еще отделить следующий параметр.  Поэтому мы один раз разделяем по знаку равенства, второй по знаку end.  И дальше пробуем запросить субтитры.  Я указал, что мы будем запрашивать субтитры на русском или английском языке, если они есть.  Если нет, то...  Если нет, то мы вернем, что просто не удалось извлечь информацию.  А так, вытаскиваются субтитры.  Они там вытаскиваются в виде, по-моему, словаря.  И, соответственно, поскольку нас будет интересовать только текст, а не тайм-коды, мы извлекаем чистый текст.  Тайм-коды мы таким образом отбрасываем.  Здесь вот этот вот цикл, он именно для этого сделан.  Далее мы формируем документ.  Это класс из лангчейна. 

 Здесь вот этот вот цикл, он именно для этого сделан. Далее мы формируем документ. Это класс из лангчейна. Это лангчейна и гигачейна.  И этот документ мы помещаем в сплиттер.  То есть в разделитель для того, чтобы у нас четко все проходило в MapReduce.  Сделали мы размер вот этого chunk size, размер кусочка тысяча.  По-моему, он это по символам считает.  И с перекрытием в 100 символов.  По-моему, это речь про символы, не про токены.  Есть другие сплиттеры.  При желании можно с этим поэкспериментировать.  Но давайте оставим как есть.  И дальше мы, получается, если что, нам возвращается список вот этих документов.  То есть изначально оно создается как один документ лангчейновский.  Мы делаем его как список документов, чтобы зафиксировать длину, не превысив.  И помещаем набор этих документов в...  Цепь саморизации.  И получаем краткое содержание.  Или не получаем, если субтитры вытащить не удалось.  И дальше мы еще некую метаинформацию должны извлечь.  Это название видеоролика. 

 Или не получаем, если субтитры вытащить не удалось. И дальше мы еще некую метаинформацию должны извлечь. Это название видеоролика. Для этого мы используем другие инструменты.  Есть вот, получается, библиотечка, которая YouTube...  Нет, не YouTube.  YouTube Transcript API.  Это для извлечения субтитров.  Хороший инструмент.  И YouTube Search Python.  Он нужен для того, чтобы из видеоролика по идентификатору мы могли извлечь метаинформацию.  Вот этим мы будем здесь заниматься.  А именно извлекать информацию про заголовок видео, про название канала, на котором выпущен этот видеоролик,  и про продолжительность этого видеоролика.  Будем вытаскивать эту информацию.  Продолжительность видеоролика.  А, и еще дата публикации видеоролика.  Вот эту метаинформацию мы соберем.  Плюс краткое содержание.  И у нас получится вот такая выжимка про тот или иной видеоролик по запросу.  Ну, повторюсь, что из-за встроенного инструмента, который лангчейновский, 

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

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

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

 которые идут в лонгчейне, и то, что предоставлено в гигачейне. Дело в том, что, как правило, ну, во-первых, там своя функция create, не гигачат, а сейчас боюсь соврать, в общем, там своя функция. Мы можем открыть, в принципе, чтобы не бояться соврать,  открыть документацию и глянуть, глянуть, глянуть.  ChainStack.  Так, так, так.  Глянуть, где это реализовано.  Ну, вот тут, собственно, агенты.  CreateToolCallingAgent.  Вот такая функция там используется, то есть другое у нее название.  И в чем еще разница?  В том, что в примерах, которые приводятся в лонгчейновской документации,  вот можно видеть, что в эту функцию всегда подставляется  программистами prompt.  Здесь же, вот если посмотреть документацию лонгчейновскую,  гигачейновскую, то мы увидим, что при создании агента,  так, тут всякие инструменты, инструменты, вот у нас идет создание агента,  prompt не указывается.  Дело в том, что там есть значение prompt по умолчанию, то есть он там  автоматически формируется.  Мы можемiegoчейн. 

 Дело в том, что там есть значение prompt по умолчанию, то есть он там автоматически формируется. Мы можемiegoчейн. Я, соответственно, делал по гигачейновскому примеру, потому что  при моих попытках прописать prompt самостоятельно там возникали какие-то  сложности, я в итоге это дело забросил, ну, по крайней мере для того  примера, который вам показываю.  Ну и, соответственно, да, вот мы запустим нашего агента, сделаем.  Так, что-то, чего-то нам не хватает.  Чего нам не хватает?  А, я проговорил про вот эту большую-большую функцию и не запустил ее в итоге.  Так, хорошо.  Давайте еще раз попробуем.  Да, теперь выдает без ошибки.  Просто пропустил ячейку.  Дальше, собственно, можем приступать к тестированию нашего агента.  Для этого мы сделаем удобный красивый интерфейс, используя возможности Gradio.  Но при экспериментах с Gradio, видеоролик я вообще должен был записывать на день раньше,  выяснилось, что Gradio упал.  Вообще, это удобный инструмент, предназначенный для создания графических интерфейсов 

 Но при экспериментах с Gradio, видеоролик я вообще должен был записывать на день раньше, выяснилось, что Gradio упал. Вообще, это удобный инструмент, предназначенный для создания графических интерфейсов для всяких приложений с искусственным интеллектом.  Хотя можно и не...  Не про искусственный интеллект, а также какие-то веб-интерфейсы создавать в Gradio.  Выяснилось, что вчера он на протяжении трех с лишним часов лежал.  И, соответственно, не было возможности запускать.  Но, в целом, сервис очень удобный.  Он чем удобный?  Есть его аналоги, конкуренты, альтернативы.  Допустим, тот же Streamlet, который тоже позволяет...  В Python коде создавать графические интерфейсы.  Здесь удобно, что здесь из коробки идет также локальные туннели, то, что называется.  То есть возможность запустить приложение на своей машине,  ну или как вот здесь мы в коллабе запускаем,  и получить публичный веб-адрес.  То есть они там специальные гейты используют для того, чтобы мы могли поделиться внешней ссылкой, 

 ну или как вот здесь мы в коллабе запускаем, и получить публичный веб-адрес. То есть они там специальные гейты используют для того, чтобы мы могли поделиться внешней ссылкой, с сторонними пользователями, и они могли нашим приложением воспользоваться.  Это достаточно удобно.  Но вот повторюсь, что вчера в связи с тем, что это не работало,  в Gradio нормально воспользоваться было проблематично.  И вторая сложность Gradio, с которой я столкнулся.  Вот вчера в попытках его запустить у меня, помимо того, что оно не запускалось,  на протяжении трех с лишним часов из-за того, что сервис лежал,  возникла еще сложность тем, что Google Collab выдал мне сообщение о том,  что я пишу какой-то не такой код, который может нарушать требования Google Collab.  И я так понимаю, что доступ к Gradio ограничил того блокнота, который я использовал.  Все последующие мои попытки,  вроде Gradio запускают, но разрывают с ним соединения,  я в итоге весь вот этот вот код просто скопировал в отдельный Google Collab блокнот 

 Все последующие мои попытки, вроде Gradio запускают, но разрывают с ним соединения, я в итоге весь вот этот вот код просто скопировал в отдельный Google Collab блокнот и запустил заново, и тогда графический интерфейс у меня снова заработал.  То есть вот такая вещь тоже есть.  Давайте обсудим, что у нас в программном коде здесь.  Значит, здесь есть главная функция, которая представляет из себя элементы, блокс,  которые...  в Gradio, собственно, составляют, как правило, основу приложения.  Тут вообще вот такая структура, когда мы через with прописываем,  как будут располагаться у нас виджеты и механику, значит, вот вызовов, функций при взаимодействии с этими виджетами,  что должно происходить.  У нас, по сути, для отработки взаимодействия с пользователем  у нас будет, что здесь, чат-бот, собственно, графический интерфейс,  где сверху будут сообщения, снизу будет строка для ввода текста.  И вот этот текст-бокс.  И при нажатии кнопки Enter, да, у нас будет отправляться запрос к функции Respond. 

 где сверху будут сообщения, снизу будет строка для ввода текста. И вот этот текст-бокс. И при нажатии кнопки Enter, да, у нас будет отправляться запрос к функции Respond. Вот она у нас.  Суть ее в том, что при вызове этой функции,  у нас будет запускаться метод Invoke нашего агента,  и в виде словаря мы будем ему передавать историю нашего чата,  которая будет обновляться постепенно, и, собственно, текущее сообщение.  Текущее сообщение, на него будет выдаваться ответ,  и этот ответ мы будем, вот видите, тут Result Output,  мы будем добавлять в историю сообщений  вместе с пользовательским запросом.  Ну и также тут вот получается Chat History M,  это гигачейновский список с сообщениями,  то есть там будут чередоваться Human Message и AI Message,  а просто текстовая версия сообщений, она будет храниться в Chat History.  Это для Gradio нужно, чтобы отображался диалог в его графическом интерфейсе.  Соответственно, и все, значит, само приложение запускается методом Launch. 

 а просто текстовая версия сообщений, она будет храниться в Chat History. Это для Gradio нужно, чтобы отображался диалог в его графическом интерфейсе. Соответственно, и все, значит, само приложение запускается методом Launch. Я здесь использую атрибут Debug="true", для того чтобы,  если у нас возникают какие-то проблемы, мы здесь видели информацию об ошибках и предупреждениях.  Давайте запустим и посмотрим, как это будет работать.  Так, вот у нас запускается Gradio. Надеюсь, что сейчас запустится без проблем.  Если что, есть в декабре,  внешняя ссылка, но также при запуске в Colab он, в принципе, в аутпуте ячейки тоже это все отображает.  Ну что, давайте попробуем пообщаться с нашей языковой моделью.  Напишем ей сперва привет.  Давайте спросим, а что ты умеешь? Что ты умеешь?  Выдаст он нам какой-то...  Могу выполнять различные функции.  Искать информацию в интернете, писать код, отвечать вопросы пользователей.  Ну, не знаю по поводу вот этого всего. 

 Могу выполнять различные функции. Искать информацию в интернете, писать код, отвечать вопросы пользователей. Ну, не знаю по поводу вот этого всего. Давайте спросим, какие функции ты можешь вызывать.  Знает он про это что-нибудь?  Я могу вызывать следующие функции.  И как-то вот ничего нам не написал.  В предыдущих итерациях у меня как бы получалось.  Давайте попробуем использовать вот какую-то из предлагаемых функций.  Ну, допустим, давайте поищем в интернете.  Сейчас будут такие примеры с vanity search, что называется, да, или эго серфингом, да.  Попробую задавать запросы про себя любимого.  Вот.  Давайте попробуем найти про меня информацию в интернете.  Для этого сделаем...  Причем сейчас сформулирую запрос, да, в виде сообщения и попробую его прокомментировать.  Значит, используя функцию  найди в интернете...  Нет.  Информацию про...  И в кавычках напишу это.  Дело в том, что если...  Хотелось бы, чтобы можно было в формате такой свободной беседы задавать какие-то вопросы, 

 И в кавычках напишу это. Дело в том, что если... Хотелось бы, чтобы можно было в формате такой свободной беседы задавать какие-то вопросы, и языковая модель бы четко сама понимала, что в данном случае нужно просто от себя какой-то ответ,  когда там привет, как дела, а в другом случае, когда у пользователя какой-то вопрос возникает,  что нужно именно в интернете.  И в интернете поискать.  Но вот опыт показывает, что с гигачатом нужно очень четко формулировать, что вы хотите.  Давайте попробуем, выдаст он нам ответ на запрос или будет отсебятину какую-то придумывать.  Тут, конечно, немножко рулетка такая.  Так.  Ну вот мы видим, что он задал запрос.  Вот.  Благодаря тому, что мы...  Вербову струб оставили в нашем коде, когда создавали агент.  Мы видим, как бы, что происходит под капотом.  Что он обратился, да, search web — это наша функция для поиска в интернете, задал соответствующий запрос,  получил ответ, и посмотрим, что выдало нам.  Я нашел несколько упоминаний в интернете. 

 Что он обратился, да, search web — это наша функция для поиска в интернете, задал соответствующий запрос, получил ответ, и посмотрим, что выдало нам. Я нашел несколько упоминаний в интернете. Он может быть связан с образованиями.  Он может быть связан с технологиями и конкурсами.  Конечно, да, это вот такое обобщенное представление, но в принципе правильно, да.  То есть он там нашел релевантные куски.  Все нормально.  Но хотелось бы поподробнее, поэтому давайте мы попросим его посмотреть список заметок.  Давайте так.  Вызови функцию.  Вызови функцию заметок.  Просмотра заметок.  Списка заметок.  Ваш список находится вот здесь.  Да, давайте смотреть.  Список заметок он не запросил.  Да, то есть это он сочинил от себя.  Так.  Ладно.  Ладно.  Мы, если что, попробуем потом то же самое реализовать с Pro моделью.  Возможно, Pro модель будет лучше.  Давайте попробуем еще сделать запрос, опять же, про меня любимого, на YouTube.  Сделай.  Почему сделай?  Сделай запрос в YouTube.  Что ты там нашел?  7000 Akamanga. 

 Сделай запрос в YouTube. Что ты там нашел? 7000 Akamanga. Я заговорил где?   Оно не будет.  А-а...  Я не понял,ільки это слово. 自апровательно caterpillar.  При视 gh lynyle нет ничего нового.  Поэтому только вот это.   И с вот этим набором действий, по крайней мере, лайт-модель справляется не очень хорошо. Поэтому давайте просто спросим. Сейчас еще интересно вызовет он. Да, он сделал запрос нормально к соответствующей функции. Ждем какого-то ответа. Видимо, обработка занимает дольше времени.  Да, и вот видите, как я говорил, что он находит два видеоролика, возвращает эту информацию. Если что, мы подстраховались, эта информация сохраняется у нас в заметках. А вот интересно, что все равно получилось, что один.  Ну ладно, не страшно. У нас в итоге разные запросы. Видимо, все-таки в данном случае он не посчитал системный вот тот файл.  За заметку. Поэтому получилось вот так. Ну нормально все равно. 

 Да, и вот видите, как я говорил, что он находит два видеоролика, возвращает эту информацию. Если что, мы подстраховались, эта информация сохраняется у нас в заметках. А вот интересно, что все равно получилось, что один. Ну ладно, не страшно. У нас в итоге разные запросы. Видимо, все-таки в данном случае он не посчитал системный вот тот файл. За заметку. Поэтому получилось вот так. Ну нормально все равно. Так, я нашел два видео. Первое представляет собой короткометражный фильм, который он снял. А второе видео является подробным туториалом по работе с GigaChat API на Python.  Но как бы получается, что несмотря на вот эти запросы, вот значительная часть вот этой информации, да, она...  Ушла в никуда.  Это, конечно, печалит. То есть вот главная проблема, что мы делаем какие-то сложные функции, делаем сложные запросы, которые выдают нам в итоге промежуточные результаты в виде вот такого синенького текста.  И этот синенький текст не попадает в диалог. 

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

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

 Выдаст он нам тут перечень. Создание текстов. Нет, выдает какую-то общую информацию.  Ну, давайте попробуем его попросить.  Выведи список заметок.  Сможет он ответить нам в виде запроса.  Так, он выдал нам пустой почему-то список,  хотя выполнил запрос и, видите, нашел действительно сохраненные заметки.  Ладно.  Я думаю, что для того, чтобы это все хорошо работало,  нужно нормально прописать системный промп.  Если кто-то из вас уже с этим сталкивался и имеет некоторый опыт,  поделитесь, пожалуйста, было бы интересно.  Так, ну что, давайте попробуем сделать запрос в интернет.  Допустим, попросим найти, не знаю, про gigachat API.  Давайте про gigachain.  Найди в интернете информацию про gigachain.  Так, gigachain.  Ну, посмотрим.  С PRO-версии я в явном виде, видите, не пишу там,  сделай запрос к функции.  Сейчас посмотрим.  Ну, судя по тому, что он долго отвечает,  он все-таки запросил.  Давайте проверим.  Да, он запросил в интернете.  Нашел какие-то фрагменты с открытым исходным кодом, 

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

 Но это вопрос не к языковой модели, да, это вопрос к тому инструменту, который мы используем. И вот здесь у нас буквально правоilosversena. А вот здесь, например, это задача, которая соответствует motement graphicalization ллп.     Характеристики.      Прошу прощения.  Кстати, прежде всего хочу дать AddOther's perspective.  Это просто vara для самого вебинара.  Как раз над этим ноу- 밖에as a großeMPF jou �ер �ежеhting.  Нет то, что я вам поставил на мышку.   Потому что также я sixty وأ regionalaa выживу.  Часу.  Список заметок, которые у меня есть.  Видимо, он запросил, но не очень понимает, что для того, чтобы вывести что-то на экран, ему нужно самому это написать.  Вот он увидел и как бы продолжил вот этот вот текст.  Это, конечно, не очень, но что поделаешь.  Можно, в принципе, если бы опираться на вот эту особенность, наверное, можно сделать подстановку того, что то, что выдает нам та или иная функция, тот или иной инструмент, подставлять в AI-сообщение, AI-месседж, как часть этого AI-месседжа. 

 Вот он увидел и как бы продолжил вот этот вот текст. Это, конечно, не очень, но что поделаешь. Можно, в принципе, если бы опираться на вот эту особенность, наверное, можно сделать подстановку того, что то, что выдает нам та или иная функция, тот или иной инструмент, подставлять в AI-сообщение, AI-месседж, как часть этого AI-месседжа. И тогда оно становится частью контекста, частью диалога.  И даже если он там как-то ответил не очень.  Хорошо, можно потом что-то переспросить.  А так вот получается такой момент.  Вот.  Соответственно, ну, можем попросить.  Давайте попросим, возьмем название этой заметки.  Скопировать путь.  Нас интересует именно название, поэтому мы оттуда возьмем только кусочек.  Так.  Просмотри.  Содержимое.  Заметки.  Так.  И мы уберем все лишнее.  И возьмем название заметки в кавычке, чтобы было модели точно понятно.  Просмотри содержимое.  Не указываю, что это надо функцию вызвать.  Надеюсь, что он поймет.  Давайте попробуемalf frågor.  Так, ну, что же это такое.  Вот. 

 Давайте попробуемalf frågor. Так, ну, что же это такое. Вот. П gratefulив нечисто in boxи.  Мы видим wantedor с помощью спортивного урона на пэннинг.    Открыли мы у нас пэнч на счете.  Наш фазовое место�читывание вопроса.   Вот.  Наша форма.  Кнопки сложных особенностей.  Все.   Подсчет жд.  Получается, что я не кстати.  О.  Конечно, пока что агенты далеки от совершенства, но это интересный инструмент и интересное поле для дальнейшего исследования.  Надеюсь, что то, что мы сегодня посмотрели, оказалось вам полезно, любопытно.  И надеюсь, что тема агентов вызовет дальнейшие интересы, дальнейшее развитие.  Если есть вопросы, есть желание поделиться опытом каким-то, жду от вас комментариев.  Мне тоже эта тема достойна.  Достаточно интересная и она достаточно новая для меня.  Поэтому любая критика тоже принимается.  Спасибо, что посмотрели.  Получилось достаточно длинное видео, но, надеюсь, что содержательное.  Спасибо. До новых встреч. 

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

 Постараюсь делать какие-то относительно короткие, форматные, потому что обычно получаются довольно затянутые видео, когда снимаю скринкасты для каких-то конкретных образовательных целей. Ну и вот подумал, а с чего бы начать, чтобы заинтересовать аудиторию,  и решил, что давайте мы сегодня посмотрим, как стоит начинать работать с API для Гигачата,  API, API.  Напомню, что Гигачат — это большая языковая модель, в первую очередь,  и инфраструктура по доступу к этой большой языковой модели,  отечественная разработка от Сбера,  и простым людям, физическим лицам Гигачат предоставляется в бесплатные,  они называют это фирмы, которые используют Гигачат, в основном, для того, чтобы создать гигачат.  Фримиум-версии, в которой доступны по миллиону токенов на год.  Вот давайте мы сегодня попробуем разобраться, как получать доступ к API,  и посмотрим какие-то несложные примеры, что мы можем реализовывать с помощью доступа к Гигачату.  Будем использовать Python.  Ну, давайте потихоньку начинать. 

 и посмотрим какие-то несложные примеры, что мы можем реализовывать с помощью доступа к Гигачату. Будем использовать Python. Ну, давайте потихоньку начинать. Здесь для того, чтобы получить доступ к API, нужно зарегистрироваться,  или, если есть уже аккаунт, войти.  Нас перебрасывает, поскольку у меня уже есть аккаунт, в личное пространство разработчиков.  Вот видно, что это ресурс developers.sber.ru.  И здесь могут подключаться разные инструменты от Сбера,  нас сегодня будет интересовать Гигачат.  Там, возможно, если новый аккаунт, то нужно будет подключить именно Гигачат,  выбрать его как продукт.  Ну, а у меня уже он доступен, поэтому мы переходим сразу в информацию про Гигачат.  Здесь нам доступна информация про тариф, про токены.  Если бесплатные токены заканчиваются, есть возможность докупать дополнительно еще токены.  И самое главное, что здесь есть доступ к документации и информация про ключи доступа, которые нам понадобятся.  Ну, вот давайте, наверное, как раз с ключей доступа и начнем. 

 Если бесплатные токены заканчиваются, есть возможность докупать дополнительно еще токены. И самое главное, что здесь есть доступ к документации и информация про ключи доступа, которые нам понадобятся. Ну, вот давайте, наверное, как раз с ключей доступа и начнем. В открытую вам будут видны информация про Client ID.  Это вот идентификатор для доступа.  Но это не все.  Также здесь отображается scope, какой формат доступа у нас.  Либо мы являемся физическими,  как вот здесь, Гигачат, API, Perse.  Либо есть еще вариант для бизнеса, для юридических лиц.  Ну, скорее всего, если вы зашли посмотреть, вы относитесь к физическим лицам.  Помимо этого, помимо Client ID и вот этого scope, есть еще информация по секрету.  Мы ее сейчас зайдем, получим.  Получим заново.  То есть он, по идее, поменяет информацию таким образом.  Ну, давайте, я зайду.  Прятать не буду.  Я потом просто перезайду и еще раз как бы секретный ключ пересоздам.  Вот когда мы нажимаем сгенерировать новый Client Secret, 

 Прятать не буду. Я потом просто перезайду и еще раз как бы секретный ключ пересоздам. Вот когда мы нажимаем сгенерировать новый Client Secret, нам пишут предупреждение о том, что старый будет не валидным после этого.  Ну, нас это не беспокоит, поэтому мы переходим.  И вот здесь есть информация про два ключа, по сути, да.  Есть информация про Client Secret и авторизационные данные.  Вы можете на самом деле взять только авторизационные данные отсюда.  И больше, в общем-то, ничего вам особо не понадобится.  Ни Client ID, ни Client ID.   Ни Client Mind Secret.  То есть это как бы немножко взаимозаменяемые сущности.  Но я, наверное, дальше в программном коде как раз попробую это показать.  А пока, может быть, мы возьмем и сохраним вот эти credentials, по сути, да,  эти данные для авторизации в каком-нибудь файлике, чтобы было удобно.  И перейдем к следующему шагу.  Попробуем, используя вот эту информацию по авторизации,  используя документацию на API, 

 И перейдем к следующему шагу. Попробуем, используя вот эту информацию по авторизации, используя документацию на API, попробуем создать какое-нибудь простенькое приложение.  Теперь у нас есть ключи, которые мы получили в личном пространстве.  И мы можем переходить, собственно, к программированию, к применению API.  Я для...  демонстрации возможностей GigaChat'а сегодня использую Google Collab, да,  расширение для Google Диска, позволяющее создавать виртуальные машины  и писать программный код внутри таких Jupyter блокнотов в облаке, да,  не устанавливая никакого программного обеспечения на компьютер.  Ключи, которые мы взяли,  я поместил...  не так давно появилась опция секреты в Google Collab,  то есть можно хранить ключи и какие-то токены доступа  непосредственно в этой секции.  И, как мы уже посмотрели, у нас есть, по сути, три основных...  ...секции.  Элементы для авторизации у нас есть Client ID, у нас есть Secret,  и у нас есть еще некая авторизационная такая строчка. 

 ...секции. Элементы для авторизации у нас есть Client ID, у нас есть Secret, и у нас есть еще некая авторизационная такая строчка. Мы сейчас вот с ними как раз разберемся, для чего они нужны.  В ключах и в этих секретах есть возможность подгружать их...  ...в переменные, в среду разработки непосредственно,  используя импорт такого компонента, да,  такого объекта, как UserData.  Ну, наверное, это модуль, да, и у него есть функция get,  которая позволяет, используя вот те названия,  как некие константы в секретах, брать их и использовать  в своем программном коде.  Давайте мы их подгрузим.  И я уже упоминал, что Client ID и Secret можно использовать для авторизации,  но также дублируя их возможности, да, у нас есть вот эта вот  авторизационная строка отдельная.  Сейчас покажу, как из ID-шника и секретного ключа  получается вот эта общая авторизационная строка.  На самом деле, что нужно делать с Client и Secret,  чтобы передавать их...  дальше по API?  Нам нужно... 

 чтобы передавать их... дальше по API? Нам нужно... На самом деле, что нужно делать с Client и Secret,  если мы хотим их использовать для доступа к API?  Нужно записать их в общую строку, вот мы так ее форматируем, да,  через двоеточие,  и закодировать определенным образом.  Для этого мы будем использовать формат Base64.  Вообще, этот формат используется для того, чтобы  бинарные данные, байтовые, да, вот эти вот данные закодировать в виде текста  и передавать через интернет,  передавать через запросы.  Поэтому это формат, который получил широкое распространение.  64 он называется, потому что...  там используется 64 разных символа  для того, чтобы передавать вот эти бинарные, по сути, данные.  Мы что делаем?  Мы берем объединенную вот эту строку,  кодируем ее в UTF-8,  прогоняем через Base64 кодировку  и декодируем как UTF-8 обратно.  В результате у нас получается строка,  которую мы уже будем передавать дальше.  Но есть такая особенность, что  на самом деле  вот этот третий элемент,  который нам доступен, 

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

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

 В качестве аргументов функции мы передаем информацию о том, является ли наше обращение обращением как физического лица,  ну и либо как юридическое лицо.  И собственно токен,  который у нас есть вот эта авторизационная строка,  мы ее передаем вот здесь для получения временного токена по доступу.  И что нам нужно?  Мы указываем endpoint  и передаем всю необходимую информацию в заголовках  и собственно в теле запроса.  И имея все это на руках,  совершаем собственно пост-запрос.  Тут из особенностей, помимо того, что мы передаем тело запроса заголовок,  указываем endpoint,  мы еще указываем параметр, отвечающий за верификацию или неверификацию сертификатов шифрования.  Можно скачать сертификаты минцифры,  для того чтобы они опознавались как достоверные.  Но я этим не буду заниматься.  Я просто ставлю в запросах,  в пост-гет-запросах, везде ставлю verify="false".  Тогда не появляются ошибки и запросы отправляются.  Правда приходят сообщения с предупреждением,  что какие-то сертификаты непонятные. 

 Тогда не появляются ошибки и запросы отправляются. Правда приходят сообщения с предупреждением, что какие-то сертификаты непонятные. И в принципе все.  Возвращается нам ответ на запрос.  Мы посмотрим, как он выглядит.  Давайте запустим этот фрагмент кода.  Таким образом, Python запомнит нашу функцию.  Ну и дальше вызовем эту функцию.  Получим запрос, ответ на запрос.  И выведем этот ответ на экран.  И вытащим в переменную giga-token,  вытащим собственно сам токен для доступа.  Вот так вот.  Вот так выглядит токен для доступа.  Большая-большая-большая строка.  Большая строка.  И помимо этой строки еще и информация о моменте,  когда истекает срок действия.  Ну вот повторюсь, что там что-то порядка получаса,  если я ничего не путаю.  Значит вот мы получили этот временный токен.  И соответственно можем его использовать теперь  для создания запросов уже на какие-то действия с giga-чатом.  Ну, сперва пробно совершим запрос на получение перечня моделей. 

 И соответственно можем его использовать теперь для создания запросов уже на какие-то действия с giga-чатом. Ну, сперва пробно совершим запрос на получение перечня моделей. Для этого мы передаем по сути только токен по определенному endpoint.  endpoint, да, вот заканчивается у нас на моду, да, вот.  И запускаем его прямо.  И по сути мы делаем запрос на токен,  с указанием verify="false".  И давайте посмотрим, что из себя представляет набор вот этих моделей.  Вот здесь отображается, что есть giga-chat pro.  Есть giga-chat последняя версия.  И есть просто giga-chat.  Это вот три модели, которые были созданы на кодах.    к которым мы можем обращаться.  Мы будем обращаться либо к просто GigaChat версии,  либо к GigaChat Latest, последней версии.  Ну и во всех наших запросах, как я говорил,  что из-за того, что мы ставим Verify False,  приходит информация о том, что какой-то непроверенный сертификат шифрования применяется.  Имея представление о перечне моделей и имея на руках токен для доступа, 

 что из-за того, что мы ставим Verify False, приходит информация о том, что какой-то непроверенный сертификат шифрования применяется. Имея представление о перечне моделей и имея на руках токен для доступа, мы можем, собственно, приступить к генерации.  Мы будем делать запросы с помощью обычной библиотечки Request,  как только что и делали.  В последующих видеороликах я покажу,  что мы можем использовать более удобно,  как видны инструменты.  Ну а сейчас мы, используя библиотеку Request,  зато чуть более подробнее разберемся с тем,  что мы отправляем, что мы обратно получаем,  потому что таким образом здесь это все четче видно.  Мы для этого создадим функцию.  Я ее назвал GetChatCompletion.  В нее буду передавать, опять же, токен для...  подтверждения верификации, да, для подтверждения,  в смысле авторизации, вот этот вот на полчаса действующий,  и сообщение от пользователя, от нас на генерацию.  То есть это промт для того, чтобы сгенерировать  новое сообщение от гигачата.  Здесь у нас указывается... 

 То есть это промт для того, чтобы сгенерировать новое сообщение от гигачата. Здесь у нас указывается... Указываем модель, в нашем случае гигачат.  Здесь на самом деле структура абсолютно идентичная  той, которая есть у чат GPT.  Если вы с чатом GPT уже по API работали,  то, в общем-то, ничего нового здесь для вас не будет.  Мы передаем сообщение.  Наш промт, значит, сообщение для того,  чтобы организовывать в формате диалога взаимодействия с моделью языковой.  Сообщение передается в виде списка,  внутри которого находится...  Каждое отдельное сообщение представляет из себя словарь,  состоящий из двух элементов...  Ну, двух пар элементов, да.  У нас указывается роль.  Ролей у нас может быть три.  Это...  Системная роль, когда общая какая-то информация передается.  Чуть подробнее мы к системной роли обратимся попозже.  Есть пользователь, да, как роль.  Это человек, который взаимодействует с гигачатом.  Ну и, собственно, ответ от гигачата, он может фигурировать с указанием роли ассистента. 

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

 Ключевой, наверное, параметр, который играет для нас наибольшую роль, это параметр температуры. Он определяет, насколько случайный ответ будет в результате нашей генерации. Дело в том, что как работает вообще языковая модель.  Она предсказывает следующий токен.  Токен — это, по сути, часть слова.  Иногда это даже целое, может быть, небольшое слово.  Но чаще это кусочек.  Который является, по мнению нейросети, логичным продолжением того,  что мы отправили в виде промта.  Буквально следующий вот этот вот кусочек текста.  И если мы выставим значение параметра температура 0,  то будет выбираться только самый надежный результат.  То есть тот, который, по мнению нейросети,  наиболее подходящий.  Самый-самый подходящий 1.  То есть, когда температура 0,  мы всегда будем получать один и тот же ответ на нашу генерацию.  Если же мы ставим температуру выше.  Ну вот, например, 1.  Чаще всего между нулем и единицей,  но в принципе можно и больше ставить. 

 Ну вот, например, 1. Чаще всего между нулем и единицей, но в принципе можно и больше ставить. Есть примеры, когда до 2 вот этот параметр температуры выставляют.  Чем меньше, тем больше.    Чем больше значение, тем более детерминированный ответ.  Чем выше мы ставим температуру, тем более случайный получается ответ.  Если мы хотим большего разнообразия,  мы можем в ответах поставить температуру побольше.  Также за разнообразие у нас может отвечать topP параметр.  Количество возвращаемых ответов N.  Это то, что мы получаем.  По умолчанию и есть этот параметр.  Чаще всего вот эти параметры в явном виде не прописываются.  Есть еще параметр stream.  Это параметр, отвечающий за потоковую передачу результатов генерации.  То есть мы можем, вот как сейчас здесь потоковая передача ответов отключена,  мы можем ждать, пока языковая модель,  не сгенерирует полностью ответ.  Либо мы можем выставить stream равно true.  И тогда каждый появляющийся токен будет тут же отправляться пользователю. 

 не сгенерирует полностью ответ. Либо мы можем выставить stream равно true. И тогда каждый появляющийся токен будет тут же отправляться пользователю. И мы будем видеть генерацию текста в динамике.  В основном, когда мы через веб-интерфейс работаем,  будь то с чатом GPT или вот с Giga-чатом,  там стоит потоковая генерация.  То есть мы постепенно,  видим как появляется текст.  Сейчас мы сделали так,  что будет текст появляться только после того,  как закончится генерация.  Но благо, что Giga-чат очень быстро работает.  Буквально там в парочку секунд,  как правило, мы будем укладываться.  Также можно регулировать максимальное количество токенов в ответе.  Здесь стоит 512.  На самом деле это много.  Для наших примеров.  Штраф за повторение это параметр,  который можно ставить побольше,  чтобы чат GPT или Giga-чат не повторялись,  когда генерируют какие-то достаточно длительные последовательности.  Достаточно большие куски текста,  чтобы там не было каких-то повторений.  Выставляют этот параметр побольше. 

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

 мы спрашиваем GigaChat, как он может нам объяснить, как работает get-запрос. Давайте посмотрим, что из себя представляет ответ. Для этого мы ответ преобразуем с помощью метода JSON.  Для этого мы ответ преобразуем с помощью метода JSON.  Нам вернется благодаря этому словарь.  Ну и структура возвращаемого словаря.  Если что, ее описание можно подробнее посмотреть в документации.  А так, если что, здесь история аналогичная с чатом GPT.  Мы имеем ключ choices, внутри которого находится список сообщений.  Ну, список, в котором на самом деле одна сущность.  Так, вот я вижу скобочку здесь.  Ага, и вот она заканчивается вот здесь.  Там, собственно, сообщение.  Месседж, в котором словарь, в котором есть, ну, то, что нас больше всего интересует, это контент.  Это вот, собственно, ответ, который возвращает языковая модель.  Давайте мы выцепим этот текст отдельно.   Зная, какие ключи следуют друг за дружкой в наших словарях,  мы можем записать вот такую форму записи, 

 Зная, какие ключи следуют друг за дружкой в наших словарях, мы можем записать вот такую форму записи, что преобразуем в словарь с помощью JSON метода.  choices — это вот этот ключ.  Дальше у нас список.  Мы должны выцепить из него нулевой элемент,  обратиться в нем по ключу message,  в нем по ключу content,  и таким образом мы получим конечный текст.  Который выглядит следующим образом.  Вы можете использовать модуль requests  для выполнения get-запросов на Python.  Вот базовый пример.  И приводится пример и пояснение по нему.  Мы также можем чуть-чуть более наглядно показать,  как выглядит результат  с помощью markdown-разметки,  потому что вот мы видим, что вставка кода  здесь осуществляется в формате markdown.  Но это пример, когда мы делаем один запрос  и получаем всего лишь один ответ.  Если вы уже взаимодействовали с Giga-чатом,  с чатом GPT через веб-интерфейс,  вы видели, что там идет диалог.  Мы отправляем вопросы как некий промо-рекорд,  как фронты языковой модели.  Языковая модель нам отвечает. 

 Мы отправляем вопросы как некий промо-рекорд, как фронты языковой модели. Языковая модель нам отвечает. Мы снова можем задать какие-то вопросы.  И выстраивается диалог.  Давайте мы сделаем такую диалоговую систему.  Для этого нам придется усложнить наш код.  Мы будем передавать в нашу функцию  не только текущее сообщение от пользователя,  но и давайте также каждый раз добавлять историю сообщения.  У нас же не зря в предыдущем примере функции  был такой параметр как messages.  И он представлял из себя список сообщений.  Вот мы этот список будем передавать  и этот список будем пополнять.  Значит, список будет называться у нас  ConversationHistory  И изначально он будет пустым.  Мы туда будем добавлять словарь,  содержащий информацию о роли и о контенте.  Также указываем этот параметр  в параметрах, которые мы будем добавлять.  И в основном, мы будем добавлять  все параметры, которые пойдут в теле нашего запроса.  Ну а в остальном функция остается такой же.  Опять же, даже все вот эти параметры 

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

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

 как на Python сделать get-запрос, можно понять, что, автоматически в языковую модель уходит еще какая-то служебная информация,  потому что, если мы посмотрим,  мы увидим, что количество токенов,  передаваемых для Prompt,  вот в данном случае 224.  Это много, даже вот глядя сюда,  мы понимаем, что даже если в рамках одного слова  у нас будет несколько токенов,  их явно не 224,  и тем более, увидев,  что ответ в несколько раз больше,  чем наш вот этот вот запрос,  а количество затраченных на него токенов 93,  то есть меньше, чем токенов в нашем Prompt,  мы понимаем, что автоматически  к нашему вот этому сообщению,  а точнее перед ним,  что-то там прописывается,  прописываются некоторые инструкции,  эти инструкции связаны с правилами поведения с пользователем,  как я понимаю,  мы не знаем точно,  это является частью коммерческой тайны,  какой именно там Prompt прописан.  И, наверное, поскольку ChatGPT  может работать совместно с Кандинским,  то есть мы можем,  мы можем задать запрос, 

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

 мы можем указать роль, ну и какие-то правила, особенности поведения для чат-бота. Ну, например, давайте так,  несерьезно укажем, что  отвечай как бывалый пират,  пусть тебя зовут Генри Морган,  один из известнейших  реально существовавших пиратов.  Создадим, получается, вот такой теперь список  вместо того, который был.  И передадим этот список  в качестве аргумента,  обозначающего историю переписки.  И зададим вопрос.  Ну вот у меня уже в предыдущих запусках  был этот диалог, давайте я его уберу  и попробую запустить заново.  Вот, и поскольку мы попросили отвечать  как пират, он нам отвечает  Добрый вечер, капитан.  Какими ветрами занесло в эти края?  Отвечает он, кстати, одинаково почему-то.  Да, несмотря на то, что температура у нас стоит 1.  Температура у нас стоит 1.  Ну и вот это формат,  с помощью которого мы можем  выцепить непосредственно сообщение,  вытащив его из вот этой матрешки  вложенных друг в друга словарей.  Ну и, наверное, это будет последний пример на сегодня. 

 вытащив его из вот этой матрешки вложенных друг в друга словарей. Ну и, наверное, это будет последний пример на сегодня. Это работа с генератором картинок моделью Кандинский.  Генерация картинок это отдельная тема.  Может быть мы как-нибудь к ней подойдем в другой раз.  Сейчас мы просто рассмотрим функционал.  Интересно, что для генерации картинок  нам не нужно создавать какой-то принципиально отдельный запрос.  Мы используем, по сути, такой же запрос к тому же эндпойнту.  Единственное, большая языковая модель должна понять,  что мы просим нарисовать, сгенерировать картинку  и за счет этого понимания вызвать работу модели Кандинского.  Дело в том, что большие языковые модели,  генеративный интеллект, создающий тексты и генераторы картинок,  генеративный интеллект, работающий с изображением,  это принципиально разные нейросети,  поэтому они существуют немножко отдельно.  Но мы получаем к ним доступ через один и тот же интерфейс,  через интерфейс Гигачата.  И потом у нас будет отличаться этот пример. 

 Но мы получаем к ним доступ через один и тот же интерфейс, через интерфейс Гигачата. И потом у нас будет отличаться этот пример. В общем-то, ничем.  В принципе, ничем.  Просто обновим на всякий пожарный функцию.  Да, тут еще мы возвращаемся к предыдущей версии,  по сути, нашей функции.  Нам не нужно здесь держать историю сообщений,  потому что предполагается,  что мы...  Сразу задаем запрос, получаем картинку,  и на этом взаимодействие по поводу картинок заканчивается.  Поэтому вот так.  Ну и для примера давайте мы попробуем создать запрос,  в котором попросим нарисовать изображение робота с ноутбуком в руках,  ну и посмотрим, насколько хорошая получится картинка,  и как, собственно, эту картинку получить и сохранить.  Вот давайте делаем запрос.  Так.  Что-то пошло не так.  А что у нас пошло не так?  Сейчас разберемся.  У нас, наверное, истек срок действия вот этого токена,  поэтому давайте мы перевыпустим токен.  Скорее всего, дело в этом.  Поскольку я говорил, что там, скорее всего, полчаса, 

 поэтому давайте мы перевыпустим токен. Скорее всего, дело в этом. Поскольку я говорил, что там, скорее всего, полчаса, и заканчивается действие.  Поэтому сделаем новый токен.  И, наверное, можно перезапустить этот же запрос.  Будет так.  Обновляем на всякий пожарный функцию.  И делаем запрос.  Как видите, запросы на генерацию картинок занимают несколько больше времени.  Но тоже на самом деле не критично.  Вот.  И вот возвращается опять запрос.  И вот, в принципе, мы получаем ответ, что фотореалистичное изображение антропоморфного робота.  И, по сути, возвращается как будто html тег с указанием вот такого идентификатора картинки.  Нам надо этот идентификатор картинки вытащить.  И сделать еще один запрос уже на получение файла.  Чтобы он мог отобразиться.  Для того, чтобы вытащить идентификатор, поскольку это, по сути, html тег,  мы используем библиотечку bs4, beautiful soup.  И, по сути, спарсим вот этот html код.  Спарсим html код.  И выцепим из...  ...из... 

 Спарсим html код. И выцепим из... ...из... ...из этого image тега атрибут, отвечающий за вот этот идентификатор.  И дальше что?  Нам надо подставить полученный идентификатор в url endpoint.  И тогда в качестве ответа мы получим бинарник.  Этой картинки, которую мы сможем сохранить в виде файлика.  Ну и тогда увидеть результаты трудов Кандинского.  Давайте так и сделаем.  Выполним запрос.  Укажем здесь токен.  И правильный endpoint с указанием вот этого id-шника.  Длинной последовательности символов.  Вот мы выполнили.  Я надеюсь, что...  ...респонс у нас с кодом 200.  А тут не показывает.  Но неважно. Если что-то пошло не так, то мы сейчас не сможем сохранить.  А если все нормально, то мы благополучно сохраним содержимое нашей картинки.  Никаких ошибок. Видимо, картинка записалась в виде файла.  Мы использовали стандартную функцию open.  Стандартные атрибуты для записи бинарных файлов.  Коим...  ...является картинка в любом случае.  Ну и давайте посмотрим, как эта картинка будет выглядеть. 

 Коим... ...является картинка в любом случае. Ну и давайте посмотрим, как эта картинка будет выглядеть. Вот, что нам нарисовал Кандинский.  Антропоморфный робот.  Ноутбук.  Ну, мы говорили, на руках у него.  Но перед ним, да, и он за ним работает.  Вот. Мы сегодня, получается, рассмотрели функционал.  Отвечающий за создание запросов и получение ответов.  От Гигачата.  Смогли выстроить диалоговую систему.  Если мы захотим сделать полноценную диалоговую систему,  мы не просто сделаем парочку запросов,  а выстроим в виде бесконечного цикла, когда будут ожидаться сообщения от пользователя.  Но это мы сделаем в следующий раз.  И попробовали также поработать с Кандинским.  Получить результат в виде картинки.  В следующий раз мы попробуем использовать инструмент в виде библиотечки.  Ну, чуть-чуть переделанной библиотечки лангчейн.  Она называется Гигачейн.  Она адаптирована для работы с Гигачейном.   Там нам не придется расписывать вот такие длинные джейсона-образные структуры. 

 Она адаптирована для работы с Гигачейном. Там нам не придется расписывать вот такие длинные джейсона-образные структуры. Они там будут создаваться автоматически.  То есть это будет более удобно, более компактно.  Но это мы рассмотрим в следующий раз.  Попробуем различные применения.  Попробуем сделать, чтобы чат-бот пообщался с чат-ботом.  Попробуем пообщаться с чат-ботом.  Попробуем общаться в режиме реального времени с чат-ботом.  Ну и посмотрим, что из этого получится.  Спасибо, что посмотрели.  Надеюсь, было полезно, понятно.  Надеюсь, было полезно, понятно.  И если возникают вопросы, буду рад ответить, буду рад помочь. 

 Добрый день, с вами Сергей Трощенков.  Сегодня мы снова работаем с GigaChat,  а именно будем подключать его к Telegram Bot.  Ну и, кроме того, познакомимся с возможностями лангчейн в плане памяти.  Ну, обо всем по порядку.  Для того, чтобы реализовать программный код,  который будет у нас использоваться сегодня,  нам понадобится токен от Telegram Bot,  для этого нужно создать Telegram Bot,  ну или, если вы уже создавали,  можно использовать какой-то из уже у вас существующих.  Я подробно на этом моменте останавливаться не буду,  поскольку есть масса инструкций на этот счет.  Просто кратко скажу, что вам нужно зайти в бот Fathor,  это бот, который раздает доступы к другим ботам,  создать своего нового бота,  ну или найти там информацию для уже существовавших у вас ботов.  Маленькая ремарка относительно создания нового бота.  Там вы дадите боту имя,  и также нужно будет получить уникальный идентификатор.  Вот с уникальным идентификатором это самая, возможно, сложная часть, 

 Там вы дадите боту имя, и также нужно будет получить уникальный идентификатор. Вот с уникальным идентификатором это самая, возможно, сложная часть, поскольку все более-менее распространены,  имена под боты уже заняты,  а надо именно получить уникальное обозначение,  которое будет и в URL ссылки на вашего бота встречаться,  ну и в целом будет характеризовать его как отдельную сущность.  Это может занять у вас какое-то время.  В остальном ничего сложного.  Для реализации сегодняшнего программного кода  мы будем задействовать две библиотеки.  Одна из них будет нам нужна,  для Telegram-бота.  Я использую PyTelegram-бот API.  Это не самая лучшая с точки зрения дальнейшего использования,  возможно, библиотека,  но у меня уже есть некоторый опыт работы с ней,  я как-то к ней привык.  Вы при желании, если имеете опыт работы с другими библиотеками,  на самом деле, фреймворков для взаимодействия с ботами в Telegram на Python,  наверное, с доброй динамикой,  десяток точно наберется.  Вы можете выбрать любую другую. 

 наверное, с доброй динамикой, десяток точно наберется. Вы можете выбрать любую другую. Также нам понадобится уже знакомая нам по прошлому туториалу библиотечка GigaChain.  Напомню, что это на самом деле такая русифицированная адаптация  с включением класса GigaChat в качестве языковой модели.  Но на самом деле, смотрите сами,  можно использовать и оригинальные,  и оригинальный лангчейн.  Я вот тут предварительно заглянул.  В оригинальном лангчейне уже есть тоже класс для GigaChat,  поэтому на ваш выбор.  Ну, мы используем сберовский GigaChain,  который является ответвлением от лангчейна.  Итак, пока библиотеки устанавливаются, давайте посмотрим дальше.  Ну, поскольку мы будем пользоваться GigaChat и Telegram-ботом,  нам нужны credentials, нам нужны токены для одного и для другого.  Я, как обычно, храню секреты в соответствующей вкладочке в Google Colab.  Вы можете организовать доступ к ним как-то иначе.  Тоже запустим эту ячейку,  чтобы получить доступ к ним. 

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

 И таким образом мы можем в какой-то момент выйти за контекстное окно, во-первых. Во-вторых, ну, расход токенов постоянно увеличивается. Чтобы с этим работать, существует ряд хитростей. Например, у лангчейна, а вслед за этим и гигачейна,  есть несколько отдельных инструментов по организации памяти.  Они это называют memory.  Вот мы сегодня используем парочку из них.  Посмотрим, как они работают.  Посмотрим, как они нормально или ненормально будут взаимодействовать с гигачатом.  Ну, самая базовая память, которая может быть использована,  это conversation buffer memory.  В основном ее мы и будем использовать.  В сегодняшних примерах.  Для более подробного погружения в вопросы памяти  я рекомендую обратиться к документации.  Там довольно много примеров, в которых, если есть желание и время, можно разобраться.  Conversation buffer memory просто хранит сообщения последовательно друг за дружкой.  Единственное, какое преимущество оно дает в сравнении с тем,  как, допустим, в прошлом туториале мы делали, 

 Conversation buffer memory просто хранит сообщения последовательно друг за дружкой. Единственное, какое преимущество оно дает в сравнении с тем, как, допустим, в прошлом туториале мы делали, где записывали в список последовательности наших сообщений,  а сообщения представляли из себя...  Мы использовали специальные классы, во-первых, для того, чтобы хранить,  а еще до этого мы просто создавали словари.  Отличие здесь в том, что вы точно не выскочите за пределы контекстного окна.  Напомню, что это не значит, что вы не сможете высказать, что вы не сможете высказать, что вы не сможете высказать.  Это значит, что каждая языковая модель имеет то или иное ограничение по количеству токенов,  которые выделяются на, во-первых, prompt,  а во-вторых, в это же контекстное окно должна войти и ваша генерация,  то есть то, что модель выкатит вам в ответ на ваш prompt.  И этот объем строго ограничен, поэтому, если мы просто будем создавать списки с сообщениями, 

 а во-вторых, в это же контекстное окно должна войти и ваша генерация, то есть то, что модель выкатит вам в ответ на ваш prompt. И этот объем строго ограничен, поэтому, если мы просто будем создавать списки с сообщениями, мы рано или поздно упремся в то, что выйдем за пределы этого контекстного окна.  Здесь все организовано как-то более автоматизировано,  то есть там, в принципе, контекстное окно контролируется,  и, ну, видимо, подрезаются первые сообщения, как только мы подходим к пределу.  Также есть несколько других, ну вот мы сегодня еще коснемся conversation entity memory,  это интересный класс в том плане, что помимо, собственно, диалогов,  там еще будут храниться извлекаемые сущности,  то есть он будет использовать тот же самый giga-chat для того,  чтобы извлечь важные какие-то элементы,  ну, например, имена организации, какие-то термины,  которые употребляются в ходе разговора.  Чтобы не занимать время видео,  на остальных разновидностях памяти сейчас останавливаться не буду. 

 которые употребляются в ходе разговора. Чтобы не занимать время видео, на остальных разновидностях памяти сейчас останавливаться не буду. Если у вас возникнут какие-то вопросы,  или если эта тема кому-то будет очень интересна,  можно будет обсудить, и даже если будет спрос,  мы можем сделать отдельный видеоролик на эту тему.  Так, ну и вот, как сказал, планирую сегодня сравнить обычную память  и память, где помимо диалогов будут также извлекаться  и сохраняться некоторые важные сущности,  которые всплывают в ходе диалога.  Ну, сперва возьмем самую обычную память.  Нам для работы понадобится, как в прошлый раз,  класс для, собственно, giga-chata, да, framework, да,  интерфейс, наверное, стоит это назвать,  для взаимодействия с API-ями, да, и нашим программным кодом.  Также мы будем использовать класс conversation-chain.  Это удобная оболочка, которая позволяет поместить в себя,  допустим, собственно, класс языковой модели,  то есть соединить языковую модель, память, промты, 

 Это удобная оболочка, которая позволяет поместить в себя, допустим, собственно, класс языковой модели, то есть соединить языковую модель, память, промты, ну и некоторые другие сущности, но вот мы в основном будем работать,  вот этими двумя-тремя, собственно, языковая модель, память,  ну и иногда еще prompt.  В первом примере у нас отдельного никакого prompt мы не будем делать,  но он там есть, некоторый prompt по умолчанию.  Значит, что нам нужно?  Мы, как и в прошлый раз, создадим экземпляр giga-chata,  ну вот я назвал его LLM-кой вслед за документацией, да,  большая языковая модель.  Latch language model.  Мы указываем ключ, который нужен для подключения,  и не забываем, что если у нас не установлены сертификаты шифрования  от min-цифры, то мы должны выставлять параметр verify ssl certs  в значение false.  Также полезная опция здесь для того, чтобы увидеть, как все работает,  чтобы мы увидели все промпты, всю, как бы,  кухню происходящего процесса, мы будем выставлять verbose true, 

 Также полезная опция здесь для того, чтобы увидеть, как все работает, чтобы мы увидели все промпты, всю, как бы, кухню происходящего процесса, мы будем выставлять verbose true, и тогда, причем там раскрашенным образом, будут все сообщения у нас отображаться.  Ну, давайте попробуем.  То есть мы создаем conversation chain, помещаем в него экземпляр нашего giga-chata  и помещаем в него экземпляр нашей памяти.  Так, все. У нас все готово.  И дальше мы можем в этот conversation chain передавать наши сообщения  и смотреть, что будет получаться.  Делается это с помощью метода predict.  В методе predict мы задаем параметр input,  и в input передаем строчку с нашими сообщениями.  Ну, я тут несколько сообщений подготовил.  Давайте посмотрим, что giga-chat нам будет отвечать на наши запросы.  Итак, мы отправляем ему сообщение о том, как нас зовут, что мы делаем,  и видим, что все организуется следующим образом.  Видите, здесь есть некий системный или это, скорее всего, не в системный промпт записывается, 

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

 Дальше для того, чтобы искусственный интеллект продолжил написание, также подставляется, что следующее сообщение должно быть как бы от него. И вот ответ, который нам пришел в следующей итерации, этот ответ тоже окажется частью вот этого контекста, частью вот этого пункта «текущий разговор».  А вот он говорит, что приятно познакомиться, представляется сам, рассказывает, что он сделан в Сбире и так далее.  Давайте мы теперь спросим Гигачат, какая языковая модель самая лучшая.  Будет интересно, что он нам скажет.  Будет ли хвалить себя или, допустим, отдаст должное,  OpenAI-овским моделям. Давайте проверим.  Итак, вот мы видим, что и ответ искусственного интеллекта из прошлого взаимодействия,  и наш новый запрос, они попали вот в этот контекст, попали в составляющую текущего разговора.  Я думаю, что мы там на последующих примерах даже выведем,  где-то у меня там есть и кейс,  и кейс с кодом для того, чтобы вывести шаблон промта вот этого.  Но это чуть дальше будет. 

 где-то у меня там есть и кейс, и кейс с кодом для того, чтобы вывести шаблон промта вот этого. Но это чуть дальше будет. Скромно здесь отвечает нам Гигачат, что все зависит от разных особенностей,  и перечисляет некоторые модели, но почему-то не называя самые последние,  и используя достаточно такую старую уже,  информацию о языковых моделях.  Но тем не менее, вот дает нам такой ответ.  А мы задаем ему следующий вопрос,  а именно говорим, что мы хотим использовать языковую модель на русском,  и желательно, чтобы за это не приходилось платить.  Итак, мы запускаем, мы видим, что все наши запросы пошли как часть вот этого промта.  И вот, что нам выдает Гигачат.  Нужно понимать, что все ответы языковых моделей, они подвержены галлюцинациям.  Кроме того, есть вот ограничения по доступу к актуальной информации, да,  а языковые модели знают только ту информацию, на которой обучались.  Более новые, более актуальные сведения им неизвестны.  И мы...  Это...  Отдельная тема. 

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

 мы получаем правильный ответ. Это информация из одного из первых наших, вот, да, из первого нашего сообщения. Все работает нормально. Теперь попробуем немножко усложнить.  Для этого мы используем другой тип памяти,  а именно Conversation Entity Memory.  Это, значит, более сложная сущность,  которая будет делать, получается, уже не один, на самом деле, запрос к языковой модели,  а несколько.  То есть оно будет организовано как один,  а внутри на самом деле будут происходить разные запросы.  Что нам для реализации этого нужно?  Ну, нам понадобится Conversation Entity Memory Class.  И тут такая особенность, что попробуем подставить промт с параметром,  заложить вhindлеры,   и заставить эта пропаганда поместиться в настоящий Dios Turbo.  Так что там, да, она vertical. し  Да, этому крAN мне бы то и сходить,  наш этот кигачат. Можно было бы даже вот эту строчку с пересозданием LLM не прописывать,  подтянули бы просто эту переменную из предыдущих ячеек.  Но для порядка давайте оставим. 

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

 И точно так же будем использовать метод predict. Только тип памяти теперь у нас... Другой. А вопросы мы зададим абсолютно те же самые.  Ну и посмотрим, как будет нам отвечать языковая модель и что там добавится,  поскольку мы в виде зелененького вот этого текста получаем эту всю информацию.  Вот мы видим, что на самом деле гигачейн имеет просто переведенный, возможно, автоматическим образом промт,  поскольку как было в исходном промте OpenAI,  так вот OpenAI и осталось.  Будет, возможно, забавно, если в какой-то момент там именно в качестве ответа будет гигачат отвечать,  что он на самом деле от OpenAI из-за вот этого элемента промта.  Ну а так, здесь тоже инструкция относительно того, что из себя представляет вот этот помощник.  И вот дополнительные запросы, которые совершаются.  Мы написали, что зовут Сергей, и мы записываем видео про гигачат и Python.  Вот гигачат и Python вытащились как некий контекст.  На самом деле, наверное, плоховато здесь языковая модель отработала. 

 Мы написали, что зовут Сергей, и мы записываем видео про гигачат и Python. Вот гигачат и Python вытащились как некий контекст. На самом деле, наверное, плоховато здесь языковая модель отработала. То есть тут должен был быть ключ и какое-то значение, некий контекст, который уточняет,  что именно имеется в виду.  Здесь вот с этим не получилось.  Кроме того, очевидно же, наверное, что должно было и имя выхватиться,  но вот имя как-то он не схватил.  Ну ладно.  Тем не менее, исходя из просто диалога, да, он нам дает ответ,  что готов общаться дальше.  Давайте мы зададим тот же самый вопрос про большие языковые модели.  И что нам отвечает языковая модель?  Языковая модель отвечает нам, ну, примерно в том же ключе, что и в прошлый наш диалог.  Ну, там, возможно, с некоторыми нюансами.  Нюансами.  Так, что-то тут GPT-3 от OpenAI.  Нет, ну, в принципе, все так же отвечает.  Единственный еще момент, на который я обратил внимание только сейчас,  что диалоги строятся human и AI, 

 Нет, ну, в принципе, все так же отвечает. Единственный еще момент, на который я обратил внимание только сейчас, что диалоги строятся human и AI, а потом последняя переведенная часть человек и не AI, а ты.  Вот.  Может быть еще.  Немножко сбиваться все из-за вот этой путаницы в именах, в обращениях.  Наверное, это может немножко языковую модель тоже смущать.  Видимо, перевели промт, но не совсем корректно все отработано.  Ну, давайте посмотрим тогда следующий наш запрос.  Так, уже другой немножечко контекст добавляется.  Вот.  И за счет того, что в промте было прописано про OpenAI,  в итоге GigaChat нам тоже отвечает, что он на самом деле является большой языковой моделью,  обученной OpenAI.  Есть такой момент.  Ну, и он тут дает некоторые рекомендации, которые, наверное, не совсем актуальны.  Потому что, да, тот объем знаний, который у языковой модели есть,  он ограничен неким отсечением по времени, да,  а с тех пор произошло много интересного в области искусственного интеллекта. 

 Потому что, да, тот объем знаний, который у языковой модели есть, он ограничен неким отсечением по времени, да, а с тех пор произошло много интересного в области искусственного интеллекта. Ну, и снова попробуем обратиться к языковой модели,  чтобы из предыдущего контекста он нам ответил на какие-то вопросы.  Посмотрим, что он нам здесь подскажет.  Тебя зовут Сергей, и ты записываешь видео про GigaChat и Python.  В этот раз отработал нормально.  Готовясь к этому скринкасту, я запускал, и у меня не всегда выдавало правильный ответ.  Иногда за счет того, что он там путался в этих сущностях,  выдавало что-то странное.  Ну, и на самом деле вот те сохраняемые сущности,  их можно вывести отдельно на экран.  Ну, и как пометка на полях, что, наверное, лучше для извлечения сущностей  использовать либо какую-то более специализированную модель.  Есть модели, которые специально рассчитаны на извлечение сущностей,  или использовать, ну, просто более совершенную модель. 

 использовать либо какую-то более специализированную модель. Есть модели, которые специально рассчитаны на извлечение сущностей, или использовать, ну, просто более совершенную модель. То есть идеально здесь, наверное, использовать GPT-4.  Так, ну, и вот мы видим, что в памяти, помимо, собственно, диалога,  есть еще и информация про вот те сущности, которые GigaChat извлек из наших вот этих диалогов.  Не факт, что получившийся результат идеален, но, тем не менее,  какие-то вот такие сущности удалось извлечь.  Хорошо, вот мы немножко поигрались с памятью,  посмотрели, как работают вот все эти промты,  и теперь мы можем перейти к созданию чат-бота.  Итак, Telegram-бот.  Для того, чтобы наш бот...  взаимодействовал сразу со множеством пользователей,  и информация о диалогах и сообщениях не путалась,  нам нужно некоторое хранилище для всех диалогов  под каждого пользователя в отдельности.  Поэтому мы создадим словарь,  в котором будут помещаться все вот эти объекты памяти. 

 под каждого пользователя в отдельности. Поэтому мы создадим словарь, в котором будут помещаться все вот эти объекты памяти. В качестве объектов памяти мы будем использовать,  вот этот обычный стандартный Conversation Buffer Memory.  И как оно будет храниться?  В Telegram у каждого пользователя есть свой уникальный ID.  Это такой номер, не связанный с номером телефона,  это именно идентификатор конкретного пользователя.  И мы его будем использовать в качестве ключа,  а в качестве значения мы можем хранить в словарях все, что угодно.  Мы вот будем хранить, собственно, объекты,  которые будут иметь вот этот новый ключ,  и мы можем их вставлять в датчик,   И в этом случае, когда будет приходить новое сообщение в бота,  эта память будет извлекаться,  то есть будет смотреться, какой пользователь написал.  Если это новый пользователь,  то будет создаваться под него пара ключ-значения.  Если это существующий пользователь, то будет извлекаться вот эта память, 

 Если это новый пользователь, то будет создаваться под него пара ключ-значения. Если это существующий пользователь, то будет извлекаться вот эта память, диалог в объект чата да вот этот вот conversation чейн ну давайте попробуем что я вам рассказывал  запускаем значит создание словаря также поскольку нам надо соединить наш программный код с конкретным  ботом мы должны создать объект класса теле бот теле бот это основной класс в библиотеке которую  мы используем для взаимодействия с телеграмом туда нужно передать наш ключ ключ мы в самом  начале этого скринкаста вместе со сберовским ключом извлекали из секретов google коллаба  и дальше что мы подключаем  мы подготавливаем инструменты мы создаем объект conversation класса conversation чейн  куда помещаем информацию о том что мы будем использовать ллм-ку нашу gigachat будем все  равно выводить информацию сюда в блокнот несмотря на то что ответы будут отправляться пользователю  в чат-бота все равно интересно посмотреть 

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

 То есть наш бот будет общаться только если ему пишут текстовые сообщения, тогда он будет отправлять запрос к гигачату. Во всех остальных случаях он будет отвечать, что работает только с текстовыми сообщениями.  То есть если мы ему попытаемся голосовухи, фотографии отправлять, еще что-то,  он будет говорить, что это все не пойдет.  А если же...  Если же происходит взаимодействие с ботом...  Давайте, наверное, запустим эту ячейку.  Взаимодействие с ботом посредством текста,  то у нас запускается обработчик текстовых сообщений,  который извлекает ID пользователя, который прислал сообщение.  Этот ID ищется в нашем словаре со всеми переписками.  И если не находится...  Если находится, то создает новую пару ключ значений.  Если находится, то в наш объект conversation,  наш вот этот conversation chain,  в его атрибут memory помещается соответствующая память,  в которой хранится информация о диалоге с именно этим пользователем.  Ну и также что у нас здесь происходит?  Здесь у меня в виде... 

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

 Она нам выдает некоторый ответ, который мы достаем, получается, из памяти и отправляем в виде ответного сообщения. В виде ответного сообщения.  Причем в памяти они хранятся в виде специальных там вот этих вот объектов messages.  Мы вытаскиваем самое последнее сообщение.  Это то, что сгенерирует в ответ на запрос пользователя языковая модель.  И оттуда достаем именно контент.  Нам надо просто текст, просто строчка.  Вот мы ее таким образом вытаскиваем  и отправляем пользователю через функцию send message.  Там надо указать два обязательных атрибута.  Это ID-шник пользователя, с которым происходит общение, которому нужно отправить.  И, собственно, текст сообщения в виде строки.  Вот мы текст сообщения в виде строки извлекаем.  И мы его отправляем из памяти.  Ну и на всякий пожарный, поскольку я делал на самом деле этот пример  для демонстрации перед некоторой аудиторией школьников,  я для подстраховки сделал здесь небольшую задержку.  Дело в том, что в freemium версии нашего гигачата 

 для демонстрации перед некоторой аудиторией школьников, я для подстраховки сделал здесь небольшую задержку. Дело в том, что в freemium версии нашего гигачата там многопоточность никакая не подразумевается,  насколько я понимаю.  То есть можно только одно сообщение отправлять за раз  и до тех пор, пока не придет ответ, следующее отправлять нельзя.  Вот чтобы там не произошло каких-нибудь накладок,  добавлена вот эта вот задержка.  Ну, благо, что гигачат работает довольно быстро  и никаких проблем с этим не возникает.  Я пробовал вот этот пример на аудитории,  там порядка... аудитория была побольше,  но реально писала сообщение порядка 10 школьников,  и в принципе этот программный код с таким объемом справлялся.  То есть ну нужно, конечно, оговориться, что это пример именно такой учебный,  отладочный и так далее.  Это, конечно, нельзя использовать как полноценного бота для работы 24 на 7 под большой нагрузкой.  Но, тем не менее, для  Это мы просто объявили вот эти функции обработки, 

 Это, конечно, нельзя использовать как полноценного бота для работы 24 на 7 под большой нагрузкой. Но, тем не менее, для Это мы просто объявили вот эти функции обработки, если вы не особо до этого создавали программный код с ботами  и у вас есть вопросы про вот эти декораторы, что они делают и так далее,  можете спросить.  Если будет интересно, можем отдельный ролик про это сделать.  Ну и, собственно, запуск бота будет у нас происходить вот здесь,  путем запуска вот этого метода пулинг.  Вообще для работы с ботами есть два подхода в Телеграме.  Там есть вот этот вот пулинг.  Смысл его в том, что наша программа регулярно стучится таким образом в Телеграм  и спрашивает Телеграм, а пришли ли нам новые сообщения?  А теперь? А теперь?  И так вот происходит регулярно.  Это как бы ресурсозатратный процесс.  Боты, которые запускаются полноценно, они работают через веб-хуки,  но это более сложная история.  Вам нужен там какой-то адрес, по которому, значит, Телеграм может обращаться. 

 Боты, которые запускаются полноценно, они работают через веб-хуки, но это более сложная история. Вам нужен там какой-то адрес, по которому, значит, Телеграм может обращаться. Смысл веб-хуков в том, что не бот регулярно,  он не должен стучиться в Телеграм, а Телеграм только тогда,  когда приходят сообщения, сам стучится в бота и передает ему эти сообщения.  То есть более такой экономный режим работы с точки зрения бота.  Но он требует, чтобы у вас был свой адрес, настроено шифрование по обращению к этому адресу,  то есть там должно быть HTTPS-соединение и ряд других сложностей,  это нас сейчас не интересует.  Но вот бот у меня запущен, поэтому я могу, наверное, показать окошко Телеграма.  Тут я уже экспериментировал, взаимодействуя с ботом.  Ну а сейчас давайте снова запустим.  Значит, ну давайте какое-то сообщение просто напишем, там, привет, давай дружить.  Давай дружить.  Меня зовут Сергей.  Так, отправляю.  Я просто пишу с телефона, чтобы не клацать по клавиатуре.  Да, вот зовут Афина, интересно. 

 Так, отправляю. Я просто пишу с телефона, чтобы не клацать по клавиатуре. Да, вот зовут Афина, интересно. Такого в промте там нету.  Ну, это Гигачат взял и придумал себе.  Имя.  Расскажите немного о себе.  Я в свободное время записываю туториалы по Гигачату.  Какие темы ты обычно освещаешь в своих туториалах?  Работа с памятью языковых моделей,  подключение к ботам,  и так далее, все.             Telegram.  Пишет, что я тоже умею работать, могу тебе помочь.  А как ты подключаешься к ботам?  Ну, в общем, тут какой-то диалог у нас случается.  Я думаю, что продолжать в таком формате нет смысла.  Я хочу показать еще одну интересную вещь,  поэтому пока что мы возвращаемся в окошко нашего блокнота коллабовского.  А именно, интересно сделать какого-то узкоспециализированного бота,  чтобы он специализировался на какой-то тематике.  Для этого нам нужно прописать свой собственный шаблон,  темплейтинг.  Для промта я что-то такое попытался сделать.  Каким образом? 

 темплейтинг. Для промта я что-то такое попытался сделать. Каким образом? Я создал переменную template, в которую вписал, за основу взял текущий промт.  Текущий промт, вот мы видим, что дружественный разговор между человеком и искусственным интеллектом и все такое прочее.  И здесь я заменил на то, что описал персону, что теперь наш искусственный интеллект будет выступать в роли такого доктора исторических наук,  который будет отвечать на вопросы по истории.  А если будут задаваться какие-то другие вопросы, нужно как-то отвечать, что это нам не интересно, я на это не подписывался и все такое прочее.  Ну и также, как и в стандартных промтах,  я добавил вкладку в список.  Я добавил вот этот блок, что у нас есть текущий разговор, в который помещается история сообщений от человека и от искусственного интеллекта.  Хорошо.  Давайте этот шаблон используем и посмотрим, что у нас получится в результате.  Что у нас получится в результате.  Так, давайте посмотрим, как выглядит теперь наш промт. 

 Давайте этот шаблон используем и посмотрим, что у нас получится в результате. Что у нас получится в результате. Так, давайте посмотрим, как выглядит теперь наш промт. Вот. Промт в итоге выглядит таким образом, что здесь несколько сущностей.  Темплейт, который мы исправили.  То есть я создал сперва диалог со стандартным темплейтом, а потом просто, видите, этот темплейт подменил, присвоив значение атрибута template переменному.  И в итоге вот мы видим, что у нас сформировался такой промт.  Давайте мы с его помощью попробуем запустить нашего бота и снова пообщаться с ним.  Так, только для этого нужно отмотать наверх.  Мы, во-первых, очистим историю наших сообщений.  Если этого не сделать, то те сообщения, которые были до этого с Афиной, они у нас тоже сохранятся.  Почему Афина? Непонятно.   Также нам нужно обновить нашего бота, потому что когда мы после пулинга его вручную останавливаем,  если попытаться запустить ячейку с пулингом снова, он выдаст нам ошибку.  Поэтому мы как бы пересоздаем бота. 

 Также нам нужно обновить нашего бота, потому что когда мы после пулинга его вручную останавливаем, если попытаться запустить ячейку с пулингом снова, он выдаст нам ошибку. Поэтому мы как бы пересоздаем бота. Так, ну вот эту ячейку нам запускать не нужно, потому что conversation мы создали, а это он нам пересоздаст conversation по умолчанию.  Пересоздаем.  Пересоздаем вот эти функции на всякий пожарный, потому что бота-то мы обновили, соответственно, эти функции по-хорошему тоже надо перезапустить,  потому что текущая версия относится к предыдущему боту, скорее всего.  Так.  И, собственно, можем запускать нашего бота.  Запускаем нашего бота.  Он у нас снова готов общаться.  Мы снова открываем.  И давайте просто спросим привета от Иктуры.  Привет, кто?   А ты кто?  Так.  Что он нам отвечает?  Что он гигачат, но при этом у него тут есть...  Да, он говорит, что он не просто гигачат, а именно по вопросам истории.  Ну и давайте, давайте мы его спросим что-нибудь не про историю.  Как солить огурцы? 

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

 Кто такие монголо-татарские захватчики? Ну и вот он нам тоже дает некоторую историческую справку, исходя из своих знаний. Ну, вот это то, что я хотел, чтобы получилось. Мы создали узконаправленного Telegram-бота,  который пользуется возможностями языка,  языковых моделей для формирования персонализированных ответов конкретным пользователям.  И это будет работать, если мы будем обращаться с разных аккаунтов,  с каждым из пользователей, он будет вести отдельный диалог,  благодаря тому, что мы организовали разделение памяти под каждого конкретного пользователя.  Спасибо. Если кому-то интересны еще какие-то тематики, вы дайте знать.  Может быть интересно не про GigaChat, а про опенсорсные модели.  Тоже могу какие-то вещи показать.  Надеюсь на вашу обратную связь. Спасибо и до новых встреч. 

 здравствуйте с вами сергей трощенков а значит очередной видеоролик на тему больших языковых  моделей под каждым видеороликом практически и в каких-то личных переписках люди периодически  спрашивают вопросы такого плана что а можно ли обучить языковую модель каким-то своим текстом  можно ли языковой модели скормить большое количество книжек или каких-то других  источников и после этого общаться с ней чтобы она выдавала качественные ответы все это вопросы  справедливые и вот сегодня мы попробуем разобраться с тем как можно построить систему которая хотя бы  отчасти вот эти вопросы решала ну сразу скажу что обучение  где мы вы記ники на терминал но не Mirathlon но необходимо в виду также  четвертой связи 14 и участников мастеров и таких источников и у растений   и чтобы приходить к таким интересным念 Nelson для каждого из нас  эфира в том числе кошмарство иtır их нет 

 и чтобы приходить к таким интересным念 Nelson для каждого из нас эфира в том числе кошмарство иtır их нет До обучения языковых моделей под свои задачи. Это уже более посильная задача, хотя и тоже требующая определенной квалификации и содержащая в себе некоторые сложности, но она уже вполне может быть реализована на простейшем уровне даже какими-то любителями.  Но там другая проблема, что посредством вот такого дообучения, когда основные знания языковой модели копятся в ходе ее основного обучения, вот этот процесс дообучения, он не столько привносит новые знания в языковую модель, сколько учит ее отвечать определенным образом, определенным форматом,  учит ее на какие вопросы можно отвечать.  Какие вопросы пользователей нужно, например, обходить, потому что они что-нибудь нехорошее спрашивают и другие вот такие моменты обучают таким образом, чтобы модель выдавала, допустим, какие-то структурированные ответы, ответы по определенной форме и так далее. 

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

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

 Ну и, кроме того, большой проблемой языковых, больших, опять же, языковых моделей, как бы ни звучало это каламбурно, является галлюцинация. То есть то, что они по форме. Производят грамотный текст, но если мы возьмемся проверять фактологию, возьмемся проверять точность выдаваемого содержания, порой возникают ошибки. И вот как преодолевать эти ошибки?  Вот мы сегодня попробуем разобраться.  Основное решение для этого это создание так называемых вопросно-ответных систем.  И сегодня мы простейшую вопросно-ответную систему соберем.  Также эти системы называют RAC системами.  R-A-G, то есть Retrieval Augmented Generation.  Это система, которая пользуется преимуществами больших языковых моделей и старается свести на нет недостатки.  Каким образом?  Большие языковые модели хорошо...  Работают с текстом. 

 Каким образом? Большие языковые модели хорошо... Работают с текстом. Могут, если в запросе подавать тексты, содержащие определенную информацию, могут искать в этом тексте какие-то сущности, выхватывать их, обрабатывать, выдавать ответы именно на основе той информации, которая поступает к ним в запросе.  То есть если мы будем просить нашу большую языковую модель отвечать не на основе своих знаков.  А на основе той информации, которую мы ей в каждом запросе передаем, то у нас существенно повышается результативность.  Ну вот давайте рассмотрим, как можно реализовать систему, способную справиться именно с вот этой задачей.  Снабдить большую языковую модель помимо вашего запроса еще и релевантной информации.  Чтобы большая языковая модель на основе вот этого комплекса информации, получаемой ею в промпте, могла ответить так, чтобы это пользователя устраивало.  Как мы это можем реализовать?  Допустим, у нас есть какая-то информация в виде текстов.  Ну, на самом деле сейчас много различных... 

 Как мы это можем реализовать? Допустим, у нас есть какая-то информация в виде текстов. Ну, на самом деле сейчас много различных... В принципе, не только...  Чисто текстовых документов научились подавать на вход больших языковых моделей.  Но об этом, может быть, мы чуть позже коснемся в разговоре.  А пока давайте вот самый базовый пример, что у нас есть какие-то тексты.  Они содержатся в текстовых документах.  Это могут быть просто txt файлы, могут быть какие-то pdf, могут быть веб-странички.  Вот сегодня мы будем в частности...  Пробовать подгружать корпус текстов, представляющих из себя статейки, взятые с сайта.  И что должно происходить дальше?  Дело в том, что было бы хорошо, и некоторые языковые модели на это способны, было бы хорошо выдавать большой объем информации прямо в языковую модель в виде промпта.  И...  В...  В... 

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

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

 Промпт должен попадать в языковую модель, все это должно быть оформлено в какую-то цепочку. Поэтому давайте займемся генеративной частью. А именно нам надо авторизационные данные, я как обычно их храню в секретах Google коллаба. Дальше нам необходимо импортировать, мы будем использовать несколько функций, создающих цепочки.  Вот последовательность элементов определенным образом выстроенных, они в гигачейне, в лангчейне называются цепочками, чейнс.  И есть готовые...  Разновидности вот этих цепочек.  Мы будем использовать staff.documents.chain.  И мы будем использовать retrieval.chain сейчас.  Сейчас проговорим, зачем нам сразу два.  Но это чуть позже.  Вот, собственно, создадим экземпляр нашей генеративной модели.  Для этого используем класс gigachat.  И создадим промпт.  Как уже до этого упоминал, что промпт...  По сути, должен включать в себя несколько элементов.  Это инструкции.  Это контекст.  Собственно, вопрос.  Ну и дальше, видите, тут, чтобы языковая модель уже точно не ошиблась, 

 Это контекст. Собственно, вопрос. Ну и дальше, видите, тут, чтобы языковая модель уже точно не ошиблась, ей даже подготавливают кусочек, что ответ в двоеточие.  Чтобы дальше после двоеточия точно шел именно что ответ.  Дальше вот у нас подготовилась...  Необходимая часть под генерацию.  Мы должны это все поместить в цепочку, в chain.  Зачем нам надо две цепочки?  У нас получится, что одна цепочка создается,  и она будет являться частью другой цепочки.  Зачем нам две цепочки?  Это связано с тем, что вот это staff.documents.chain,  create staff.documents.chain создает нам удобную цепочку.  Вот нам надо помещать...  С вами будет контекст вот сюда.  В целом prompt — это строка, форматированная строка.  То есть здесь фигурные скобки для того, чтобы подставлять недостающие какие-то фрагменты.  И мы в качестве фрагментов будем извлекать из векторной базы данных элементы,  которые будут представлять из себя экземпляры класса document.  И нам тогда бы пришлось самостоятельно прописывать извлечение. 

 И мы в качестве фрагментов будем извлекать из векторной базы данных элементы, которые будут представлять из себя экземпляры класса document. И нам тогда бы пришлось самостоятельно прописывать извлечение. Вот мы видели где-то там.  Можем вернуться сейчас быстренько.  Извлечение именно атрибута page-content,  где, собственно, текстовая строка из статьи,  нужно было бы самому писать, как извлечь оттуда.  А есть готовая цепочка, которая автоматом это все делает  и подставляет...  Промпт уже готовые строчки.  Поэтому удобно.  Ну и чтобы это все работало именно как вопросно-ответная система или рак-система,  мы помещаем это все в retrieval chain.  Используем функцию createRetrievalChain.  И в принципе мы готовы для того, чтобы выполнить проверку нашей вопросно-ответной системы.  Ну, я...  Я мельком, значит, просмотрел статьи  и сформулировал буквально несколько вопросов из разных статей.  Давайте посмотрим, как у нас будет реагировать наша система на эти вопросы. 

 Я мельком, значит, просмотрел статьи и сформулировал буквально несколько вопросов из разных статей. Давайте посмотрим, как у нас будет реагировать наша система на эти вопросы. Например, там были статьи про китайские космические аппараты.  И давайте мы спросим как раз вопросно-ответную систему  о космических кораблях.  Или там аппараты какие-то.  Не корабли, наверное, все-таки.  Который запускал Китай в сторону Луны.  Вот что он нам ответит.  Мы здесь можем запускать цепочку следующим образом.  Мы пишем цепочка.invoke метод.  И подставляем необходимые значения.  В качестве необходимых значений у нас там...  Помните, два пропуска.  Это контекст и это input.  Собственно, вопрос.  Контекст у нас подставляется автоматически.  Он берется из результатов поиска по векторной базе данных.  А вот input — это недостающий компонент.  Мы его должны сюда подставлять.  Вот мы его в виде словаря берем и подставляем.  Давайте посмотрим, какой ответ нам сформулировала большая языковая модель. 

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

 наиболее близкие по смыслу к запросу. Ну как по смыслу? По векторному представлению. Наверное, наиболее корректно будет ответить так.  Ну и вот нам система выдает на основе вот этого контекста информацию про то,  что Китай запустил два космических аппарата к Луне.  Это Чанэ-4, Чанэ-6.  Не уверен, что я прям правильно произношу название космического.   Китайский.  Но видимо как-то так.  При этом мы можем увидеть, что в контексте здесь содержится информация  и про какие-то другие названия аппаратов.  Но видимо, проанализировав все кусочки и текст, его содержимое,  видимо, наша система решила, что какие-то названия не относятся непосредственно, да,  к Луне, да, а это какие-то, видимо, другие аппараты.  И, соответственно, не включила их.  Ну, допустим, да, здесь содержится информация про какой-то ракетоноситель с другим там названием.  Он в ответе не упомянут, да, а именно, что вот непосредственно к Луне полетели якобы вот эти два. 

 И, соответственно, не включила их. Ну, допустим, да, здесь содержится информация про какой-то ракетоноситель с другим там названием. Он в ответе не упомянут, да, а именно, что вот непосредственно к Луне полетели якобы вот эти два. Можете, если что, проанализировать, насколько правильные и неправильные эти два аппарата.  И, соответственно, если что, мы, если что, в последующих видео будем с вами разбираться,  как автоматизированно оценивать ответы подобного рода систем.  Но это уже немножко выходит за рамки.  А так можно было бы внимательно почитать те фрагменты, которые возвращены,  и вручную оценить, насколько качественный или не очень качественный получился ответ.  Давайте посмотрим следующий вопрос и как на него ответит система.  Там была какая-то статья про Хаббл, про то, что он там не работал какое-то время,  а потом бах и заработал.  Давайте мы спросим, когда Хаббл вернулся к работе.  Есть здесь что-то про это.  Космический телескоп Хаббл вернулся к научным наблюдениям 29 апреля 24 года. 

 Давайте мы спросим, когда Хаббл вернулся к работе. Есть здесь что-то про это. Космический телескоп Хаббл вернулся к научным наблюдениям 29 апреля 24 года. Можем даже заглянуть.  Так, давайте глянем непосредственно.  Статьи про космонавтику.  Где-то тут про Хаббл.  Вот есть статья, что он вернулся к работе.  И где-то тут написано, что вот он 29 апреля вернулся к научным наблюдениям  после выхода из безопасного режима, в который перешел 23 апреля.  Поскольку мы спросили только, когда вернулся,  не спросили, когда он вышел из рабочего состояния,  нам ответили именно на эту формулировку.  Так, ну вот посмотрим, что там дальше будет.  Есть ли какая-то информация в этих кусочках про неудачные запуски?  Давайте проверим, что нам ответит наша вопросно-ответная система.  Написал, что информация о неудачных запусках отсутствует.  Видимо, именно в силу того, что в вопросе запуск,  вот тут информация про сбой в Voyager,  но, видимо, это не воспринялось именно как информация про запуск.  Далее, что мы видим? 

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

 несмотря на то, что в контекстной части находятся подходящие кусочки, все равно может в итоге сбоить. Так, что дальше у нас? Еще пара вопросов.  Есть ли какая-то информация, связанная с именем древнегреческого математика?  Не знаю, что ответят.  Там про какой-то телескоп или что-то такое.  Эвклид.  Была статья.  Давайте посмотрим, найдет он нам что-нибудь про Эвклида.  Нет представленной информации.  Нет ничего про древнегреческих.  Но опять же, может быть это...  Хотя нет, вот смотрите, тут обсерватория Эвклид есть.  Но я вижу, что обсерватория Эвклид,  это в тайтле.  И возможно для поиска использовался именно тайтл.  Но нет, вот смотрите, есть Эвклид в тексте.  То есть тут, наверное, все-таки вопросики к генеративной модели,  которая не ухватила контекст, что я спрашивал про Эвклида.  Я просто увидел, что там статья про обсерваторию Эвклид,  и решил так завуалированно спросить,  не находил ли он что-нибудь про древнегреческих математиков.  Не поймал.  Обратите внимание, что экстрактивная модель поймала, 

 не находил ли он что-нибудь про древнегреческих математиков. Не поймал. Обратите внимание, что экстрактивная модель поймала, что древнегреческий математик и обсерватория Эвклид,  они где-то там контекстно близки вектора.  Косинус между ними.   Достаточно большой.  Угол маленький, а косинус большой.  Ну и последний вопрос.  И последний вопрос.  Дай информацию, связанную с лазерами.  Там что-то было точно про то ли лазерную передачу,  то ли что-то еще.  Давайте посмотрим.  Лазерная связь используется на станции такой-то  для передачи технических данных из глубокого космоса на Землю.  Вот прекрасно все получилось.  Хорошо.  То есть в данном случае сработало.  И что мы можем еще с вами рассмотреть сегодня?  Давайте заменим ретривер вот этот эмбэддинговый  на ретривер, построенный по принципу вот этому BM25,  который базируется на TF-IDF.  Если вы в курсе, что это такое,  то вы понимаете, что в отличие от эмбэддингового  здесь нам потребуется проводить предварительную  какую-нибудь хоть подготовку текста. 

 то вы понимаете, что в отличие от эмбэддингового здесь нам потребуется проводить предварительную какую-нибудь хоть подготовку текста. По-хорошему нужно, наверное, даже было бы задействовать  специализированные библиотечки, там какой-нибудь Pymorphia, например,  для того, чтобы приводить, помимо всего прочего,  слова в их исходную форму, инфинитивную форму.  Есть два подхода к тому, чтобы уменьшить количество форм  одних и тех же слов.  Можно было бы использовать стемминг, когда обрезаются окончания,  грубо говоря, всех слов, и таким образом вариативно,  чтобы разнообразность в словах уменьшается.  И есть вот лемматизация, когда мы приводим к исходной форме слова.  Здесь ничего такого нету.  Здесь просто убираются знаки пунктуации  и разделяется текст на отдельные, я так понимаю, слова.  Слова переводятся в нижний регистр.  И, соответственно, мы сейчас попробуем это сделать.  Что-то интересно, что почему-то красненьким подчеркивает.  А, красненьким подчеркивает, потому что оно с отступом здесь. 

 И, соответственно, мы сейчас попробуем это сделать. Что-то интересно, что почему-то красненьким подчеркивает. А, красненьким подчеркивает, потому что оно с отступом здесь. Вот так, наверное, не должен подчеркивать.  Ну ладно, мы уже запустили, уже все работает.  И вот мы можем попробовать проверить, как работает экстрактивный,  ну экстрактивная часть.  Здесь это я просто добавил, чтобы посмотреть экстрактивную часть.  То есть, используя метод getRelevantDocuments,  мы ретривер уже сделали.  Из документов, да, скормили наши фрагменты.  Для предобработки хоть какой-то и использовали функцию tokenize.  Говорим, что нам заинтересует пять наиболее близких,  близких фрагментов.  И, допустим, мы пятый вопрос, где про, про, про, что у нас там было,  информацию про лазеры.  Вот можем посмотреть.  Да, видите, все равно он какие-то кусочки именно про лазеры нам находит.  То есть вот, например, последний кусочек, мы видим, что он точно относится к статье той же,  где вот про лазеры. 

 Да, видите, все равно он какие-то кусочки именно про лазеры нам находит. То есть вот, например, последний кусочек, мы видим, что он точно относится к статье той же, где вот про лазеры. Вот эту станцию с лазерной связью.  Ну, не знаю, насколько прям релевантно содержимое,  потому что я вот смотрю, и по заголовкам вроде как релевантно,  а по содержимому, да, вот page content, там какие-то шапки или наоборот нижние части сайта попадают,  как будто бы в основном.  Так что, скорее всего, подставив их в контекст, мы толком ничего не найдем.  То есть когда мы ищем по BM25, он в том числе и заглядывает в, в метаинформацию,  не только, собственно, текст использует.  Ну, посмотрим, посмотрим.  Как это будет работать.  Давайте мы сделаем, опять же, retrieval chain,  только заменим эмбеддинговую модель на вот другой эмбеддинг.  Ну, и попробуем пробежаться по тем же вопросам, только вот с пятого начиная.  Сейчас посмотрим, получится ли у нас ответить на вопрос. 

 только заменим эмбеддинговую модель на вот другой эмбеддинг. Ну, и попробуем пробежаться по тем же вопросам, только вот с пятого начиная. Сейчас посмотрим, получится ли у нас ответить на вопрос. Вот он говорит, что информация о лазерах отсутствует.  То есть статьи он...  Местами даже правильные находят, но кусочки из них вытаскивает и в итоге неправильные.  Ну, вот это именно к такой информации и к таким запросам, как я делал, вот получается, что не находят подходящих кусочков.  Это может быть еще и недоработка в плане обработки исходного текста, потому что, да, часто, когда мы берем веб-страницу,  у нас есть несколько кусочков, которые находятся в верхней части, в нижней части,  какая-то несвязанная с содержанием интересующей темы текстовая информация.  Вот если бы в этапе предобработки нам эти кусочки вообще выкинуть и даже не викторизовать,  наверное, качество ответов в целом бы увеличилось.  Поэтому давайте посмотрим, что у нас будет по другим вопросам.  Четвертый вопрос. 

 наверное, качество ответов в целом бы увеличилось. Поэтому давайте посмотрим, что у нас будет по другим вопросам. Четвертый вопрос. Четвертый вопрос про древнегреческого математика.  Смотрим. В представленном контексте нет информации.  Но мы не нашли информации и с другим ретривером.  Здесь еще, ко всему прочему, я и не вижу подходящего фрагмента, честно говоря.  Поэтому понятно, что в итоге не нашлось.  Так, хорошо. Давайте следующий запрос.  Следующий запрос про неудачные пуски.  Там он нам тоже не нашел.  Здесь не нашел и подавно.  Хотя тут какие-то фрагменты про Hubble, про что-то там еще, про SpaceX.  Но, по крайней мере, мы видим, что разные ретриверы вытаскивают нам разные фрагменты.  Так, ну и посмотрим два оставшихся вопроса.  Я, видите, иду здесь в обратном порядке.  Когда Hubble вернулся к работе?  Вернулся 29 апреля.  Вот на этот вопрос и с этим ретривером тоже удалось ответить верно.  Ну и самый последний, он же самый первый вопрос.  Про космические аппараты.  Аппараты к Луне. 

 Ну и самый последний, он же самый первый вопрос. Про космические аппараты. Аппараты к Луне. В итоге при таком ретривере система нам ответила,  Китай запустил аппарат для связи будущих лунных миссий с Землей,  не указав название этих аппаратов, что интересно.  Видимо, несколько по-другому выстроился этот контекст.  И, видите, уже отвечает по-другому.  Хотя, в принципе, тут какую-то информацию именно про сами корабли,  про сами эти космические аппараты, вот она встречается вроде как здесь.  Но как ответил, так ответил.  Вот, мы таким образом с вами посмотрели, как работает вопросно-ответная система.  Я нарочно не задавал ей какие-то сложные вопросы.  То есть очевидно, что ей будет проблематично,  справиться с какими-то вопросами, касающимися всех текстов вместе.  То есть, например, перечисли, какие темы хранятся в твоей векторной базе данных,  какие темы есть в твоих текстах, ответ будет неправильным.  По крайней мере, для вот такой системы.  Там есть способы, с помощью которых пытаются бороться, 

 какие темы есть в твоих текстах, ответ будет неправильным. По крайней мере, для вот такой системы. Там есть способы, с помощью которых пытаются бороться, и добиваются того, чтобы на общего характера вопросы по всем текстам  тоже можно было находить ответы.  Ну, каким образом?  Например, мы можем тексты по частям саморизировать,  то есть давать более сжатую выжимку.  И такие фрагменты тоже добавлять к векторной базе данных.  И тогда мы можем...  Ну, по крайней мере, в теории, да, у нас должны извлекаться при запросах общего характера,  извлекаться в качестве фрагментов обобщения всех текстов в целом,  или какой-то промежуточной совокупности этих текстов.  То есть, например, можете на эту тему посмотреть Raptor.  Есть такой подход к созданию вопросно-ответных систем,  если кому-то интересно.  Вот он как раз-таки строится на том, что мы по частям, по частям должны обобщать,  и все кусочки, в том числе и обобщение,  на одинаковых основаниях добавлять в векторную базу данных. 

 Вот он как раз-таки строится на том, что мы по частям, по частям должны обобщать, и все кусочки, в том числе и обобщение, на одинаковых основаниях добавлять в векторную базу данных. Ну и на этом давайте будем завершать наш сегодняшний туториал.  В завершении давайте мы сохраним ответы,  получившиеся у нашей системы,  в отдельный файлик,  чтобы в дальнейшем была возможность воспользоваться этим файликом  и, например, проанализировать, насколько удачными или неудачными были ответы.  Мы будем с вами разбираться, каким образом можно автоматизированно,  применяя языковые модели и некоторые формулы поверх применения языковых моделей,  как можно оценивать эффективность языковых моделей  в вопросно-ответных системах в данном случае.  Как-нибудь мы обязательно это сделаем.  А сейчас мы возьмем получившиеся ответы  и сохраним их в DataFrame.  А получившийся DataFrame мы запишем в CSV файлик  и таким образом сохраним наши ответы.  И мы получим результаты для последующей обработки. 

 А получившийся DataFrame мы запишем в CSV файлик и таким образом сохраним наши ответы. И мы получим результаты для последующей обработки. Я даже возьму и на всякий пожарный файл,  сохраню получившиеся результаты  и в каком-нибудь последующем туториале мы ими воспользуемся.  И уже совсем завершая,  наверное, даже не буду запускать этот код,  если захотите, позапускайте самостоятельно,  здесь показан еще вариант построения вопросно-ответных,  ответной системы.  Вот мы посмотрели, что у нас может работать один ретривер,  другой ретривер.  Можно собрать систему, где оба ретривера будут использоваться  на разных принципах.  Это тоже как бы не единственный вариант,  как можно реализовать систему с несколькими ретриверами.  Бывают, например, делают цепочки,  где сперва вопрос подается большой языковой модели,  и ей предлагается ретривер,  и ей нужно решить, каким ретривером стоит обратиться  к векторной базе данных.  Для чего это делается?  Для того, чтобы определить. 

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

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

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

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

 есть и какие-то еще способы. Но для такого первичного понимания, я думаю, что мы неплохо сегодня погрузились. Вполне возможно, что у вас будет масса вопросов.  Не стесняйтесь, пишите в комментариях.  Буду стараться отвечать.  Также был запрос на объяснение,  как работать с табличными данными,  подаваемыми на вход к большой языковой модели.  Я думаю, что это тема для отдельного ролика,  где мы будем разбираться с разными загрузчиками.  Их довольно много.  Интегрировать большую языковую модель в какие-то приложения можно,  но не с какими источниками данных,  как локальными, так и облачными,  так и подключением каких-то сервисов.  Поэтому лучше мы посвятим этому один из следующих видеороликов.  Ну а на сегодня все.  Спасибо, что выдержали такой длинный видеоролик.  Увидимся в следующий раз. 

 Здравствуйте, меня зовут Сергей Трощенков, и мы сегодня будем продолжать работать с GigaChat API.  Попробуем снова из Python обратиться к GigaChat.  Но если в прошлый раз, разбираясь с основами этого процесса,  мы использовали библиотеку Requests и получали достаточно сложные и громоздкие конструкции,  то сегодня мы попробуем облегчить себе задачу для того, чтобы не заморачиваться с авторизацией,  не заморачиваться так с длинными сложными конструкциями в виде словарей,  относящихся к сообщениям.  Передавая...  ...в GigaChat.  И в этом нам поможет библиотечка GigaChain.  Что такое библиотечка GigaChain?  Давайте я запущу ее установку.  Сегодня я снова работаю в Google Collaboratory.  Библиотечка GigaChain есть не что иное, как немножечко переделанная библиотека LangChain.  И вот LangChain это по-настоящему мощный инструмент,  который позволяет выстраивать сложные цепочки по обработке данных из разных источников,  чтобы на каких-то этапах эти предобработанные данные передавать в большие языковые модели 

 И вот LangChain это по-настоящему мощный инструмент, который позволяет выстраивать сложные цепочки по обработке данных из разных источников, чтобы на каких-то этапах эти предобработанные данные передавать в большие языковые модели и использовать функционал языковых моделей.  То есть на самом деле это инструмент, который позволяет строить сложные приложения,  внутри которых время от времени...  ...происходит обращение к большим языковым моделям.  Но функционал огромен, там большое количество компонентов,  можно разные хранилища данных использовать,  использовать разные подключения к сторонним сервисам и многое-многое-многое другое.  Мы на самом деле только по краешку пройдемся.  Нас сегодня будет интересовать только использование класса GigaChat.  Это вот тот класс, который добавлен в оригинальный LangChain с Бером.  И вот названо это все GigaChain.  Это класс, который позволит нам, однажды объявив экземпляр этого класса,  просто передать один раз авторизационные данные, 

 И вот названо это все GigaChain. Это класс, который позволит нам, однажды объявив экземпляр этого класса, просто передать один раз авторизационные данные, и вся работа по авторизации автоматически будет осуществляться через вот этот...  ...экземпляр.  Ну и на самом деле передачу всех сообщений  мы тоже будем осуществлять через этот экземпляр класса GigaChat.  Нам понадобится для того, чтобы это все делать,  снова авторизационные данные, которые мы получали в прошлый раз  в личном пространстве, в личном кабинете на сайте Сбера.  Я эти... этот токен...  Можно его так назвать...  Храню в секретах блокнота в Google Collaboratory,  поэтому просто запускаю вот такой код,  и в итоге содержимое этого секрета хранится теперь у меня в соответствующий перемен.  Напомню кратенько, что мы в прошлый раз создавали диалоги,  отправляли их API,  и мы сделали вот такой вот...  И вот отдельные сообщения внутри этих диалогов выглядели как-то так.  Ну вот здесь у меня показана структура как раз одного из сообщений, 

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

 Ну, так или иначе, имитация, во всяком случае, человеческого какого-то ввода происходит, если у нас сообщение пользовательское. И третий вид — это то, что нам отвечает большая языковая модель,  сообщение ассистента, возвращаемое назад,  мы вот строя из вот этих трех разновидностей сообщений  можем создавать длинные сложные диалоги.  Но проблема в том, что если пользоваться оригинальной формой записи в виде словарей,  в каждом словаре есть по две пары ключей и значений,  да, роль и контент,  то получается довольно говно.  Это громоздко и плохо читаемо.  И тут нам на помощь как раз приходит лангчевейн в очередной раз,  потому что у него есть специальные классы,  называются они human message, system message и assistant message,  которые позволят несколько подсократить форму записи,  ну и удобнее обращаться к отдельным сообщениям  и удобнее их записывать в общие списки.  Ну, подробнее мы это увидим чуть дальше.  А пока мы просто осуществим импорт. 

 и удобнее их записывать в общие списки. Ну, подробнее мы это увидим чуть дальше. А пока мы просто осуществим импорт. Мы импортируем, собственно, соответствующие вот эти виды сообщений.  Ну, на самом деле мы импортируем только два из них,  потому что вручную прописывать assistant message мы нигде не будем,  но он даже без нашего импорта будет у нас там появляться чуть дальше,  если что покажу.  И помимо вот этих сообщений,  нам, собственно, понадобится вот этот вот класс gigachat,  про который я уже тоже сказал,  для осуществления авторизации и передачи и получения сообщений  по языковую модель и из языковой модели соответствия.  Значит, этот импорт я уже запустил.  Теперь давайте, собственно, осуществим авторизацию.  Я думаю, что вы помните, как мы осуществляли авторизацию в прошлый раз.  Это происходило не за...  один момент, да.  Мы должны были сперва отправлять запрос по одному endpoint для того,  чтобы получить действующий только полчаса ключ,  access token, и которым вот пользоваться для того, 

 Мы должны были сперва отправлять запрос по одному endpoint для того, чтобы получить действующий только полчаса ключ, access token, и которым вот пользоваться для того, чтобы непосредственно делать запросы к языковой модели.  Здесь это все тоже и есть, но оно где-то внутри, под капотом,  поэтому мы лишь один раз...  прописываем необходимую информацию.  Ну вот, в частности, указываем токен для авторизации,  указываем...  можно указать, какую модель именно мы используем,  хотя, если что, по умолчанию он там тоже модель выбирает.  Что важно указать, без чего нормально работать не будет?  Подобно тому, как в прошлый раз через библиотечку requests мы указывали,  значит, что не нужно проверять SSL сертификат,  сертификаты шифрования, также мы указываем это и здесь сейчас.  Можно заморочиться и по инструкциям в документации вместо этого скачать сертификаты минцифры,  но я это не делаю, тем более, что Google Colab каждый раз создает новую виртуальную машину, 

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

 Ну, у меня фантазий на что-то серьезное не хватило, поэтому у меня примеры будут сегодня из, так или иначе, из сказок про Винни-Пуха. Что-то мне сперва захотелось пообщаться, с меланхоличным осликом Иа, поэтому вот в системном сообщении  мы пропишем, что наш искусственный интеллект будет осликом Иа.  Создаем соответствующий список, вот так мы прописываем системное сообщение.  То, что оно системное, да, дает нам, что нам нужно только в итоге один параметр прописать,  да, если мы создавали бы словарь, то нам надо было прописывать роль,  а тут роль прописывается автоматически просто из-за того, что это класс системный.  Вот, я создаю этот список, ну и дальше давайте посмотрим,  как несложно можно осуществить организацию диалога с языковой моделью,  воспользовавшись вот этим классом GigaChat,  ну, соответственно, для других языковых моделей, если что, в ланкчейне есть свои классы.  Например, для того, чтобы с чатом GPT общаться, там есть класс для OpenAI также. 

 воспользовавшись вот этим классом GigaChat, ну, соответственно, для других языковых моделей, если что, в ланкчейне есть свои классы. Например, для того, чтобы с чатом GPT общаться, там есть класс для OpenAI также. Ну и на самом деле, я так понимаю, что разработчики Сбера взяли за основу вот этот как раз класс,  поменяли там немножечко содержимое, там endpoint указали,  там какие-то еще параметры поменяли, и вот оно теперь работает.  Значит, как мы здесь организуем? Здесь у нас реализован цикл, цикл бесконечный,  но с прерыванием на наличие, реакция на прерывание наличием стоп-слова, так сказать.  Ну, буквально слово stop, написанное пользователем с клавиатуры, будет приводить к тому,  что этот бесконечный цикл у нас будет работать.  То есть, он у нас разорвется, да, и выполнение программы остановится.  Предполагается, что внутри этого цикла пользователь будет вводить сообщение в появляющееся окошко для ввода.  Это сообщение будет проверяться на сравнение со строкой stop, написанной капсом. 

 То есть, он у нас разорвется, да, и выполнение программы остановится. Предполагается, что внутри этого цикла пользователь будет вводить сообщение в появляющееся окошко для ввода. Это сообщение будет проверяться на сравнение со строкой stop, написанной капсом. Если совпадает, то будет осуществляться выход.  Если не совпадает, то  введенному набору символов с клавиатуры будет, как бы, присвоен класс, ну, не совсем присвоен класс,  а именно, что будет эта комбинация символов передана в создаваемый, как бы, экземпляр класса  в качестве параметра content, и это сообщение человеческое, да, будет добавляться в список,  где у нас уже на сегодняшний, ну, на вот этот момент находится сообщение системное про то, что это у нас OSLIC.AI,  и, соответственно, у нас получается, что сообщение отправляется, вот мы список сообщений передаем в объект Giga, да, это экземпляр Giga-чата,  и что у нас происходит дальше?  Мы получаем ответ.  Получаем ответ.  Получаем ответ. 

 Мы получаем ответ. Получаем ответ. Получаем ответ. И этот ответ добавляем в наш список сообщений.  Ответ будет возвращаться в виде экземпляра класса AssistantMessage.  Мы этот класс не импортировали, но вот здесь у нас именно этого класса будет возвращаться сообщение.  И этого класса сообщений мы добавляем в общий список,  а на экран выводим только его сообщение.  Подписываем нормальюMale personal allow gilteter 해야 этоissen parlament bastion,  а на화� cuma для экземпляра class int этоса и  а таким образом мы можем говорить нажимаем кнопочку birth ber note,  и мы получаем ответ, да?  Норман오 « Harlem .»  И, соответственно, verl können статьoken part.  И Georgia considerism.  Нам ослик ИА.  Давайте попросим его рассказать о себе.  Расскажи о себе.  Я осел. Живу в лесу. Знакомлюсь с разными зверями.  Кто был твоим последним собеседником?  До меня.  Тигр говорит нам ослик.  Ну и поскольку мы там попросили в системном сообщении как бы не отвечать на какие-то сложные вопросы, 

 До меня. Тигр говорит нам ослик. Ну и поскольку мы там попросили в системном сообщении как бы не отвечать на какие-то сложные вопросы, которые явно не входят в компетенции осла, давайте что-нибудь спросим и проверим там.  Кто был первым эскмонавтом?  Будет интересно, если он ответит.  Да, отвечает. Интересно.  Ну, наверное, даже сказочные ослики тоже знают о Юрии Гагарине.  Я до записи пробовал какие-то вопросы задавать.  Такие.  Ну, вот давайте там.  С какими странами граничит Бразилия?  Граничит Бразилия.  У Бразилии нет соседей.  Да.  Ну вот и непонятно.  Это он так отвечает, потому что ослик не знает.  Потому что просто галлюцинация.  Ну, я думаю, что как-нибудь про галлюцинации мы сможем поговорить в отдельном ролике.  А сейчас давайте остановим эту демонстрацию.  Введу фразу стоп, и она будет служить командой для остановки работы цикла.  И теперь вот мы немножко пообщались с гигачатом.  В таком диалоговом режиме благодаря тому, что у нас написан код при помощи гигачейна. 

 Введу фразу стоп, и она будет служить командой для остановки работы цикла. И теперь вот мы немножко пообщались с гигачатом. В таком диалоговом режиме благодаря тому, что у нас написан код при помощи гигачейна. Теперь давайте попробуем рассмотреть пример, где у нас будет диалог двух ИИ-ассистентов.  Смысл в чем?  Мы зададим обоим...  Ну, как бы создадим два диалога.  В каждом диалоге будет свое системное сообщение.  И у нас есть экземпляр класса гигачат.  И по очереди мы будем эти диалоги передавать.  И смысл в том, что те сообщения, которые будут являться human message, да, сообщением пользователя в одном диалоге,  они будут...  Ассистент...  Ну, сообщениями ассистента, сообщениями ИИ в другом диалоге.  И наоборот.  То есть мы вот таким образом устроим общение двух сущностей.  И ту и другую роль будет играть у нас гигачат.  Ну, надеюсь, что понятно, что будет происходить.  Я, опять же, не уходил от...  Я не уходил от...  Тематики Винни-Пуха.  Но, значит, поместил их с Пятачком. 

 Я не уходил от... Тематики Винни-Пуха. Но, значит, поместил их с Пятачком. Правда, вот генерировал картинку с Винни-Пухом и Пятачком.  Пятачок не очень, мне кажется, похож на себя.  Хотя, может быть, просто сзади мы его так не узнаем.  Тем не менее, значит, я хочу поместить этих двух персонажей в необычную ситуацию.  Они, с одной стороны, Винни-Пух и Пятачок.  А с другой стороны, значит, Винни-Пух будет выполнять роль такого детектива.  А Пятачок будет в роли, значит, свидетеля.  И свидетеля чего?  Как будто бы где-то там произошло ограбление.  И Пятачок проводит...  Винни-Пух проводит, простите, опрос свидетеля Пятачка.  Что он видел.  Будет задавать какие-то вопросы.  А Пятачок постарается ему отвечать.  Ну, вот какая-то такая сценка.  Можно было бы придумать что-нибудь посерьезнее.  Но нам важно именно показать, как это все работает.  Поэтому давайте приступим.  Вот я создаю здесь два системных сообщения.  Добавляю их в соответствующей диалоге.  Это, значит, диалог Винни-Пуха. 

 Вот я создаю здесь два системных сообщения. Добавляю их в соответствующей диалоге. Это, значит, диалог Винни-Пуха. То есть Винни-Пух там является искусственным интеллектом.  А приходящие сообщения как бы от Пятачка, да, они рассматриваются как человеческие.  Как юзер сообщений, как human message.  А вот это у нас диалог, наоборот, Пятачка.  Здесь гигачат будет Пятачком.  А сообщения от нашего детектива Винни-Пуха будут человеческими сообщениями.  Ну, вот как-то так.  Давайте посмотрим.  Давайте запустим эти системные сообщения.  Создадим таким образом списки наших вот этих диалогов.  И что? Ну, нужно, чтобы кто-то начал.  При этом как бы всегда же начинает пользователь.  И, соответственно, у меня единственное в системном сообщении Винни-Пуха также помечено,  что Винни-Пух уже задал...  Задал...  Задал вопрос Пятачку про то, что он делал рядом с местом кражи.  И вот подобного рода сообщения как раз мы будем задавать Пятачку. 

 Задал... Задал вопрос Пятачку про то, что он делал рядом с местом кражи. И вот подобного рода сообщения как раз мы будем задавать Пятачку. А первое пользовательское сообщение, которое придет Винни-Пуху, ну, как бы должно быть,  если все нормально у нас пойдет, должно быть именно ответом на вот этот вопрос.  Так.  Ну, собственно, закидываем такое сообщение.  Так.  И мы добавим сообщение в диалог Пятачка, потому что Винни-Пух в нем является пользователем.  И дальше вот у нас здесь цикл.  Я сделал, что пусть у нас 7 кругов будет происходить.  И что будет происходить?  Мы добавили сообщение Винни-Пуха в диалог Пятачка.  И диалог Пятачка закидываем в геймплей.   И мы добавим его в гигачат.  В ответ мы получим ответ Пятачка.  Этот ответ Пятачка, а точнее его именно текстовое содержимое, выведем на экран через print.  И добавим в том виде, в котором оно вернулось нам из гигачата в список сообщений Пятачка.  Оно будет у нас в виде экземпляра класса AssistantMessage. 

 Этот ответ Пятачка, а точнее его именно текстовое содержимое, выведем на экран через print. И добавим в том виде, в котором оно вернулось нам из гигачата в список сообщений Пятачка. Оно будет у нас в виде экземпляра класса AssistantMessage. Это же сообщение мы будем добавлять и в диалог Винни-Пуха, но уже в качестве HumanMessage.  Для этого мы из AssistantMessage, который был возвращен, вытаскиваем содержимое, контент, и передаем в контент HumanMessage.  И добавляем в список.  И дальше этот список.  Мы передаем в гигачат.  И вызываем, соответственно, работу API, которая возвращает нам ответ AssistantMessage, но уже как бы от Винни-Пуха.  И выводим этот ответ, его именно текстовое содержимое, на экран.  В том виде, как оно есть, в виде AssistantMessage, мы добавляем его в диалог Винни-Пуха.  А в диалог Пятачка мы его добавим, но в качестве HumanMessage.  Вытащив именно текстовое содержимое и передав как текстовое содержимое в класс HumanMessage. 

 В том виде, как оно есть, в виде AssistantMessage, мы добавляем его в диалог Винни-Пуха. А в диалог Пятачка мы его добавим, но в качестве HumanMessage. Вытащив именно текстовое содержимое и передав как текстовое содержимое в класс HumanMessage. Ну и дальше это все по кругу у нас несколько раз повторяется.  Давайте запустим и почитаем, что нам напишет гигачат за одного и за другого персонажа.  Вот.  Читаем, значит, первое сообщение.  Привет, Пятачка.  Я расследую это преступление.  Расскажи, как ты тут оказался.  Здравствуй, Винни-Пух.  Я был в лесу, когда услышал шум и крики.  Я побежал посмотреть, что происходит, и увидел, как кто-то убегает с мешком.  Я попытался остановить его, но он ударил меня и убежал.  Пятачок, ты уверен, что видел именно кражу?  Да, я уверен, что это была кража.  Я видел, что кто-то убегал с мешком и пытался остановить его.  Что было в мешке?  Спрашивает как бы наш Винни-Пух.  Я не знаю, что было в мешке.  Я только видел, как кто-то убегал с ним. 

 Спрашивает как бы наш Винни-Пух. Я не знаю, что было в мешке. Я только видел, как кто-то убегал с ним. Ты можешь описать человека, который убегал?  Да, я могу описать его.  Это был высокий мужчина в черной одежде.  Спасибо, Пятачок.  Это очень важная информация для расследования.  Рад, что помог.  Не за что, Винни-Пух.  Да, я тоже.  Т-т-т.  Если ты вспомнишь, пожалуйста, сообщи.  Конечно, я обязательно сообщу.  Если вспомню, сообщу.   Я ценю помощь, всегда готов помочь.  Я верю в тебя.  Постараюсь сделать все возможное.  Ну, в конце диалог несколько портится.  Но на самом деле можно улучшить качество вот этого диалога.  Мы, потому что все инструкции, ну, на самом деле не совсем инструкции,  поместили в системное сообщение вообще.  Даже чат GPT.  Если помещать туда вот какие-то конкретные инструкции, как должен себя вести ассистент,  он не очень хорошо это отрабатывает.  Лучше все-таки инструкции подавать в пользовательское сообщение.  И на самом деле вот если посмотреть, что происходило у нас в прошлый раз, 

 он не очень хорошо это отрабатывает. Лучше все-таки инструкции подавать в пользовательское сообщение. И на самом деле вот если посмотреть, что происходило у нас в прошлый раз, мы отправляли запросы через request и получали ответы от GigaChat,  там видно, что мы отправляем небольшое сообщение,  а там написано, что prompt занимает больше места, чем ответ, да, в несколько раз.  Почему так?  Хотя мы написали там буквально небольшую фразу.  Это связано с тем, что вот не в системный prompt записываются конкретные инструкции,  а именно в пользовательское сообщение.  Вот если бы мы вот эту какую-то скрытную часть инструкции прописали бы там  пятачку, что он должен в Винни-Пуху, да и пятачку тоже можно что-нибудь было бы прописать,  что он должен задавать наводящие вопросы,  как-то ловить на противоречиях пятачка и так далее.  Ну, насчет ловли на противоречиях, может быть, GigaChat не очень к этому способен,  но вот задавать наводящие вопросы в пятачке,  вполне возможно, что он бы с этим справился. 

 Ну, насчет ловли на противоречиях, может быть, GigaChat не очень к этому способен, но вот задавать наводящие вопросы в пятачке, вполне возможно, что он бы с этим справился. Ну, а так, в целом, вот этот пример, мне кажется, интересный,  что можно выстраивать взаимодействие нескольких ассистентов.  Ну, проблема как бы в том, что все современные вот эти большие языковые модели,  они заточены на общении двух между собой.  Интересно бы было попробовать выстроить общение большего количества искусственных интеллектов.  Наверное, это можно тоже сделать, но надо вот как-то подумать,  как диалог многих перевести в отдельные диалоги пар, взаимодействующих друг с другом.  Может быть, мы на эту тему тоже как-нибудь сделаем видеоролик.  А сейчас давайте, наверное, на этом будем заканчивать.  Я постарался сегодня побыстрее рассказать.  Мы таким образом познакомились с GigaChain,  который является такой вот, ну, как бы, не знаю, не очень известным, но, наверное,  очень известными вариантами вариации лангчейна. 

 Мы таким образом познакомились с GigaChain, который является такой вот, ну, как бы, не знаю, не очень известным, но, наверное, очень известными вариантами вариации лангчейна. Мы к библиотекам GigaChain и лангчейн будем обращаться ещё неоднократно.  Я хочу в следующий раз показать, как можно организовывать память,  используя те компоненты, которые есть в этих библиотеках,  чтобы лучше управляться с контекстным окном.  Ну, и многое-многое другое там можно сделать.  Я надеюсь, что вот сегодняшние примеры помогут вам  выстраивать свои приложения с использованием больших языковых моделей,  и вы сможете сосредоточиться на творческой части, оставив вот техническую  часть, связанную с авторизацией и написанием вот этих сложных конструкций  словарей, помещаемых в списке, оставить их гигачи. Все, спасибо, надеюсь вам  понравилось и надеюсь увидимся в следующих видеороликах. 

 Здравствуйте, с вами Сергей Трощенков.  И сегодня хотелось бы подробнее рассмотреть один из аспектов RAC-систем.  Напомню, что такое RAC.  RAC — это вопросно-ответные системы,  когда большие языковые модели отвечают на запросы пользователей,  но отвечают они в этом случае не базируясь на своих собственных знаниях,  а на знаниях, извлеченных из специальных векторных баз данных.  На самом деле не только векторные бывают,  но в большинстве случаев рассматриваются именно они.  Так вот, из базы знаний, из базы данных  извлекаются релевантные запросу пользователя фрагменты,  и эти фрагменты используются для формирования  точного и правильного...  ответа на запрос пользователя уже генеративной модели.  Сегодня хотелось бы поговорить подробнее про ту часть,  которая связана с предобработкой и загрузкой наших документов,  которые мы будем использовать как такую своего рода базу знаний,  потому что на эту тему было много запросов,  много коллег спрашивало,  а как, если у меня есть большой набор книжек  или бумаги, 

 много коллег спрашивало, а как, если у меня есть большой набор книжек или бумаги, большой набор даже табличных данных,  вот с этим совсем все не так просто,  как быть, как заставить большую языковую модель  отвечать на запросы,  основываясь именно на вот этом содержимом.  Вот сегодня мы попробуем разобраться.  Мы, как обычно, будем использовать  возможности библиотеки GigaChain.  Дело в том, что в целом GigaChain,   и лангчейн, на которой она основана,  используют много различных компонентов  для формирования сложных приложений  с использованием больших языковых моделей.  И один из важных аспектов –  это подключение к различным источникам знаний,  различным источникам информации.  В прошлый раз, когда мы начинали вникать в вопросы RAC,  кстати, если не смотрели,  тот видеоролик, то настоятельно рекомендую его теперь посмотреть,  мы использовали в качестве источников  статьи в интернете,  ну и уже использовали соответствующий загрузчик,  который позволяет работать с веб-страничками. 

 статьи в интернете, ну и уже использовали соответствующий загрузчик, который позволяет работать с веб-страничками. Сегодня же мы попробуем посмотреть  на несколько других источников,  а именно мы попробуем поработать  немножко с текстовыми данными  и немножко с табличными данными.  Для иллюстрации работы с текстовыми данными  нам понадобятся файлы в формате docx и pdf,  ну, как одни из самых распространенных.  Понятное дело, что есть еще более простой,  обычный txt файл,  но он представляет из себя чистый текст,  с ним, в общем-то, ничего такого особенного,  ничего интересного не сделаешь.  А вот с word-овскими документами  и pdf-ами все немножечко сложнее  и, возможно, где-то интереснее.  В качестве документа,  который мы будем использовать сегодня,  мы возьмем статью, которую я писал  некоторое время назад с коллегами.  Тогда мы только начинали разбираться  вот с коллегами как раз  в возможностях языковых моделей  и возможности построения различных пайплайнов 

 вот с коллегами как раз в возможностях языковых моделей и возможности построения различных пайплайнов с использованием языковых моделей, ну, и, конечно,  это статья обобщала некоторый наш там такой промежуточный опыт.  Там мы, правда, использовали  high-stack и Lama Index,  а здесь вот мы используем  возможности гигачейна, лангчейна.  Будет одна и та же статья использоваться,  так, у нас там продолжают библиотечки еще устанавливаться,  будет использоваться одна и та же статья,  просто будет ее версия в docx и в pdf.  Вот так будет выглядеть docx-версия этой статьи.  То есть, ну, обычно оформлена статья в журнал  по требованиям, которые предъявлялись  как раз этим журналом.  Здесь, как видите, есть и табличная информация,  и картинки.  Ну, оговорюсь сразу,  что на самом деле обработка, допустим, картинок  или обработка, вот у нас есть еще pdf-ная версия,  бывает, что pdf не содержит в себе  непосредственно текста, как вот здесь,  а он присутствует в виде картинки,  еще необходимо распознавание, 

 непосредственно текста, как вот здесь, а он присутствует в виде картинки, еще необходимо распознавание, распознавание текстов с картинок и прочее.  Это все усложнения, это все тоже можно делать,  но мы сегодня попробуем какие-то более поверхностные вещи.  Ну, вот я вам просто показал,  что такой материал мы будем использовать,  и на основании этого материала  создадим векторную базу данных  и зададим буквально несколько вопросов по статье.  И посмотрим, будет ли какое-то отличие,  если мы будем задавать векторной базе данных  основы данных,  основанной на docx-документе  и основанной на pdf-документе.  Начнем мы с pdf-документа  в качестве загрузчика,  то есть вот такого компонента,  который будет принимать на вход pdf-файл  и извлекать из него текстовое содержимое,  помещая его в формат,  вот как мы в прошлый раз видели,  формат объекта класса document,  для этого мы будем использовать  unstructured pdf-loader.  Unstructured – это вообще такая библиотека,  которая позволяет работать с файлами 

 unstructured pdf-loader. Unstructured – это вообще такая библиотека, которая позволяет работать с файлами различных форматов,  вот в частности мы ее будем использовать  и для word-овских, и для excel-овских  файликов сегодня,  ну и вот pdf-ный файл тоже возьмем  и используем заодно.  Для этого нам надо было установить  саму эту библиотеку unstructured,  причем у нее есть еще дополнительные зависимости,  которые она, чтобы подтянула для работы  со всеми документами,  нужно именно указать,  что нас интересует all docs,  чтобы он все подтянул.  И вот мы будем использовать загрузчики.  В чем удобство загрузчиков,  которые есть в лонгчейне, гигачейне?  В принципе, можно было бы напрямую  воспользоваться библиотекой unstructured,  например, или еще какими-то инструментами,  но в чем удобство,  что здесь уже все сделано за нас  и по единым правилам,  по единому интерфейсу  мы пользоваться можем различными загрузчиками,  то есть вот как в предыдущем видеоролике  мы веб-странички подгружали, 

 мы пользоваться можем различными загрузчиками, то есть вот как в предыдущем видеоролике мы веб-странички подгружали, создаем объект загрузчика соответствующего класса,  и потом, что происходит?  После этого мы делаем,  после этого мы применяем метод load,  например, или load and split.  Вот в данном случае мы применим метод load and split,  чтобы сразу выполнить разбивку.  Насколько я помню, в прошлый раз  мы сперва подгружали документы,  а потом брали их и разделяли на кусочки.  Здесь мы сделаем чуть-чуть по-другому.  Мы сразу разделим на кусочки, на фрагменты.  Для этого мы используем вот такой объект,  объект splitter.  То есть он, напомню, разделяет большой текст  на кусочки поменьше заданного размера.  Это приблизительный размер здесь задается.  И приблизительный размер перекрытия.  Ну, приблизительный, почему?  Потому что в символах это все задается,  а в реальности, чтобы не обрубать там посредине слова  какую-то фразу, чтобы не было вот таких проблем, 

 Потому что в символах это все задается, а в реальности, чтобы не обрубать там посредине слова какую-то фразу, чтобы не было вот таких проблем, там происходит некоторое округление в меньшую сторону, скажем так.  Поэтому фрагменты никогда практически не бывают  ровно такого количества символов, как мы зададим.  Но что-то приблизительное будет у нас получаться.  Давайте мы выполним загрузку.  Мы здесь используем метод load and split  и укажем, собственно, вот этот разделитель.  Ну и давайте посмотрим.  Вот у нас там статья порядка 15 страничек PDF.  Получилось в итоге 47 фрагментов.  То есть весь текст разделился на такое количество фрагментов.  Напомню вообще, зачем мы делим на фрагменты.  Дело в том, что для того, чтобы вставлять именно релевантные небольшие кусочки,  в силу ограниченности также контекстного,  для того, чтобы мы не делали текст на большие фрагменты,  мы должны текст нарезать на вот такие фрагменты.  Более того, порой у нас очень много документов, 

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

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

 а также поиску релевантных фрагментов на запросы пользователя. То есть мы как бы создадим вопросно-ответную систему, но без генерации. То есть это у нас будет такая экстрактивная вопросно-ответная система. Для этого нам понадобятся векторные хранилища.  Мы, как и в прошлый раз, вот этот Faiz будем использовать.  Как и в прошлый раз, мы будем использовать такую же модель  для создания эмбеддингов.  Для этого нам понадобится класс, позволяющий скачивать  и работать с моделями с сайта HuggingFace.  Вот мы это сделаем.  И давайте сейчас мы попробуем создать...  Скачать векторное хранилище, скачать, значит,  скачать модель для создания эмбеддингов  и на ее основе векторизовать имеющиеся вот эти 47 фрагментов  и поместить их в векторную базу данных.  Это займет какое-то время.  Я на всякий пожарный поставил здесь волшебную команду,  которая укажет в конце, сколько времени у нас ушло,  на создание вот этой векторной базы данных.  Мы сможем это увидеть.  Вот у нас пошло скачивание. 

 на создание вот этой векторной базы данных. Мы сможем это увидеть. Вот у нас пошло скачивание. Скачивание тоже занимает какое-то время,  потому что модель весит больше гигабайта в целом.  Но векторизация, особенно учитывая, что для простоты  я примеры делаю в режиме CPU, конечно, это еще несколько замедляет.  Но мы подключили видеокарточку.  В принципе, это возможно в Google Collaboratory,  даже на вот этом бесплатном тарифе.  Но мы для простоты используем CPU.  Ну и вот по тексту статьи,  вот мы видим, что порядка минуты ушло на создание базы данных.  По получившимся фрагментам мы зададим несколько вопросов.  Из статьи, по содержанию статьи,  там будут вопросы два таких технических,  а третий как бы так, чтобы повеселее было.  Дело в том, что в статье в самом начале при объяснении,  что такое в целом вопросно-ответная система  и как это все работает,  мы там приводим пример с Лордом Байроном  и вопросом, когда он родился.  Соответственно, вот последний вопрос будет на тему, 

 мы там приводим пример с Лордом Байроном и вопросом, когда он родился. Соответственно, вот последний вопрос будет на тему, того, о какой английский писатель упоминается в статье.  Вот мы создадим три строки для того, чтобы делать запросы.  Ну и вот попробуем посмотреть,  какие релевантные или не очень релевантные фрагменты  будет возвращать нам ретривер.  Ну вот, по сути, наша система с векторными представлениями.  Напомню еще раз, да,  как это все работает,  что мы берем запрос,  его тоже векторизуем,  как и остальные, собственно, фрагменты.  И дальше запрос сопоставляется в векторном пространстве  с всеми фрагментами  и ищутся наиболее близкие по расстоянию,  да, вот в этом многомерном пространстве.  Я напомню, что наша эмбеддинговая модель  создает нам 768-мерное вот это вот пространство.  И в этом пространстве между векторами можно измерить угол.  А как правило используют вот косинусное сходство  для нахождения близких по смыслу фрагментов.  Ну и вот смотрите, правильный ответ по статье, 

 А как правило используют вот косинусное сходство для нахождения близких по смыслу фрагментов. Ну и вот смотрите, правильный ответ по статье, что framework high-stack,  это тоже такой набор инструментов  для создания pipeline с большими языковыми моделями.  Так вот, мы там пробовали нарезать кусочки, да, фрагменты текста  на разное количество токенов  и пришли к выводу, что там почти нет различия  в качестве ответов  в зависимости от размера вот этих кусочков.  И что мы видим?  Мы видим в тех фрагментах,  которые нам возвратил наш вот этот ретривер,  мы видим, что в принципе вот этот ответ про то,  что точность составляла 0.7 при разном размере фрагментов,  вот он вторым документом сюда попадает.  Надеемся, что этого достаточно для того,  чтобы затем генеративная часть, большая языковая модель, собственно,  получив в prompt вот эти четыре фрагмента,  смогла в их содержании найти ответ на вот этот вопрос.  По крайней мере, мы видим, что вот эта экстрактивная часть  в данном вопросе нормально сработала. 

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

 Второй вопрос про то, какими метриками пользовались для оценки эффективности генерации вот ответов на вопросы. И в статье на самом деле использовался там не какой-то сложный способ, а точное совпадение.  Ну и чтобы это проверить, мы давайте поищем релевантные кусочки  и посмотрим, нашлось ли то, что нам нужно.  Ну и вот мы видим, что вот этот exact match, точное совпадение, как метрика,  уже встречается в первом фрагменте.  То есть, в принципе, опять же, мы получили информацию,  которой, по идее, достаточно для того, чтобы ответить на поставленный вопрос.  Ну а дальше дело уже за большой языковой моделью,  сможет ли она хорошо понять контекст и вытащить нужную информацию.  Так, ну и последний вот этот вот более шуточный вопрос,  а именно, какой же писатель упоминается в этой статье,  писатель, не относящийся к компьютерным наукам.  Соответственно, давайте мы запустим этот запрос  и посмотрим, что у нас возвращается обратно.  И мы видим, что в принципе, в первом кусочке, который попался информации 

 Соответственно, давайте мы запустим этот запрос и посмотрим, что у нас возвращается обратно. И мы видим, что в принципе, в первом кусочке, который попался информации про этого писателя, нет.  Наверное, почему его выкинуло вперед, потому что в запросе говорится про писателя,  про статью, поэтому, видите, здесь фрагмент попался,  где что-то говорится про рецензируемую статью, автор и так далее.  Вот оно попало таким образом наверх.  Но во втором фрагменте мы видим, что Лорд Байрон упоминается,  то есть, в принципе, тоже ответ мы экстрактивно, во всяком случае, получили.  Хорошо, это мы посмотрели, как будет работать векторная база знаний на PDF-файлах.  Давайте попробуем тот же самый текст, только в Word-овском формате,  тоже подгрузить, посмотреть, будут ли различия в фрагментах.  И после этого попробуем те же самые вопросы задать в векторной базе,  но уже основанной на docx документах.  Посмотрим, сколько всего у нас получилось фрагментов.  45 против, по-моему, 47, которые у нас получались... 

 но уже основанной на docx документах. Посмотрим, сколько всего у нас получилось фрагментов. 45 против, по-моему, 47, которые у нас получались... Да, вот у нас было 47, а теперь тот же самый текст поделился на 45.  Но я думаю, что это связано с особенностями...  То информация, которая попадает или не попадает в качестве текстового содержания,  потому что есть, не знаю, колонн-титулы и прочие вещи,  возможно, они в одном формате прочитывались, в другом формате отбрасывались,  и поэтому мы получили при том же самом загрузчике, при том же самом разделителе текста,  вот этом сплиттере с теми же настройками,  мы получили немножко другое количество кусочков.  А что это значит?  Это значит, что у нас несколько будут отличаться...  Так, я сейчас проверю, как у нас разделенные кусочки назывались здесь...  Splitted data, да, так и назывались.  Все правильно, я просто засомневался, мало ли я какую-то не ту переменную записал сюда. 

 Так, я сейчас проверю, как у нас разделенные кусочки назывались здесь... Splitted data, да, так и назывались. Все правильно, я просто засомневался, мало ли я какую-то не ту переменную записал сюда. Да, так и назывались. Все правильно, я просто засомневался, мало ли я какую-то не ту переменную записал сюда.  Так, splitted data, вот можем посмотреть фрагмент 10, да,  ну или если по-человечески считать, то 11 фрагмент из 47 вот первого нашего варианта разделения.  Вот так он выглядит.  И при этом новое вот это разделение, docx-овское,  оно по тому же номеру дает нам совсем другой кусочек текста, если что.  То есть и нужно понимать, что если мы разделим тексты несколько по-разному,  разные слова попадут в разные кусочки, и общий как бы смысл немножечко будет меняться.  А значит, расположение векторов вот в этом многомерном векторном пространстве тоже несколько поменяется,  и соответственно немножко по-разному будут вытаскиваться фрагменты из базы знаний,  когда мы будем отправлять запросы. 

 А значит, расположение векторов вот в этом многомерном векторном пространстве тоже несколько поменяется, и соответственно немножко по-разному будут вытаскиваться фрагменты из базы знаний, когда мы будем отправлять запросы. Нужно это иметь в виду.  Ну и вот ближе к тому кусочку, который был у нас вот здесь в изначальном разделении,  в новом разделении, не точно такой же, но вот близкий по содержанию,  в силу того, что по-другому оно все нарезалось,  он имеет, видите, порядковый номер 12,  в то время как тот имеет еще один.  Имеет порядковый номер 10.  То есть вот такие моменты нужно иметь в виду.  Ну и давайте мы сравним два этих вектора,  чтобы было понятнее и нагляднее.  Два этих фрагмента, скажем так.  То есть мы сперва их преобразуем в векторы.  Вот для этого у нас же есть имбеддинговая модель.  Мы подадим на вход метода embedDocuments текстовое содержимое.  Обращаю внимание, что у нас список документов  представляет из себя список объектов вот этих документов, 

 Мы подадим на вход метода embedDocuments текстовое содержимое. Обращаю внимание, что у нас список документов представляет из себя список объектов вот этих документов, у которых текстовое содержание — это вот атрибут pageContent.  И, соответственно, мы два этих фрагмента из разных списков берем,  у которых есть пересечения, но они не полностью совпадают между собой.  И мы создаем их векторное представление.  Если посмотреть, как выглядит это,  это векторное представление.  Давайте я пока эти файлы закрою, они нам сейчас не нужны.  Мы увидим, что вот так выглядят эти векторы,  каждый из которых имеет 768 вот таких чисел.  И, соответственно, если их сравнивать между собой,  можно воспользоваться вот такой формулкой.  Да, где будет производиться произведение этих фрагментов,  то мы получим вот такой вот фрагмент.  И, соответственно, мы получим показатель их косинусного сходства.  Вот он получился 0.73.  Напомню, что косинус у нас для абсолютно совпадающих между собой текстов 

 И, соответственно, мы получим показатель их косинусного сходства. Вот он получился 0.73. Напомню, что косинус у нас для абсолютно совпадающих между собой текстов и двух векторов будет единичка.  Соответственно, 0.73 — это очень неплохой показатель,  в плане того, что определенное сходство точно-точно есть.  И, соответственно, если мы будем использовать это,  то мы получим 0.73.  Но до единички еще, в принципе, далеко.  Так что вот такое представление.  Так, что еще?  Давайте мы теперь попробуем создать векторное хранилище  для второй версии разделения документов,  для docx файлов.  Это тоже займет там какое-то небольшое время.  И, соответственно, мы можем сделать еще один фрагмент.  И попросим ответить на те же вопросы,  три вопроса,  и посмотрим, попадут ли фрагменты,  в которых есть информация для ответа,  попадут ли они в выборку вот эту получаемую.  Для этого мы можем, в принципе, уже запустить первый вопрос.  Да, вот запустили.  И первый вопрос у нас про то,  какой размер вот этих чанков. 

 Да, вот запустили. И первый вопрос у нас про то, какой размер вот этих чанков. То есть фрагментов оказался самым лучшим.  Ну и здесь мы видим, что при нарезке по-другому  все равно вот во втором, получается, документе есть вот этот фрагмент  про то, что при разных величинах кусочков  у нас точность получается более-менее одинаковая, 0.7.  Значит, на этот вопрос ответ все равно получили.  Но при этом помним, что чуть-чуть по-разному у нас текст поделился.  Так, смотрим.  Следующий вопрос,  где правильный ответ про метрики будет вот этот вот exact match.  Смотрим, встречается ли.  Да, в первом уже фрагменте у нас встречается кусочек с информацией  про метрику exact match.  Соответственно, нормально.  На этот вопрос тоже нашелся ответ.  Ну и про лорда Байрона посмотрим, находит или нет.  Также в первом кусочке не то.  Во втором кусочке, смотрю, тоже не то.  В третьем кусочке, вот у нас Байрон как раз-таки встречается.  То есть информация есть, но она как бы имеет меньшее вот это вот значение косинусное, 

 Во втором кусочке, смотрю, тоже не то. В третьем кусочке, вот у нас Байрон как раз-таки встречается. То есть информация есть, но она как бы имеет меньшее вот это вот значение косинусное, то есть это не то, что мы видим.   которые, по-моему, не имеют никакого сходства.  То есть они здесь ранжируются по своему сходству.  По вот этому показателю, как я только что показал,  определяется, насколько близки друг другу тексты.  То есть менее близки, чем при том разделении, но все равно ответ получен.  Что ж, на этом мы пока остановимся с текстовыми данными.  И можем перейти к табличным данным.  Для табличных данных я взял документ с сайта Росстата.  Это несколько табличек в рамках одного документа про зарплаты, затраты на работников.  Вот так выглядит этот набор таблиц.  Вот так выглядит этот набор таблиц.  Здесь есть и такие вот прям количественные таблички.  И есть одна страничка, да, один лист, посвященный терминологии,  используемой в этом документе. 

 Здесь есть и такие вот прям количественные таблички. И есть одна страничка, да, один лист, посвященный терминологии, используемой в этом документе. Соответственно, тоже нужно как-то разделить эту таблицу на отдельные кусочки  и попробовать позадавать определенные таблицы.   И посмотреть, как наша база знаний и ретривер будут с этим справляться.  А для того, чтобы работать с разными таблицами, мы рассмотрим CSV-формат и Excel-SX-формат.  То есть обычные разделенные запятыми таблички.  Да, почти текстовый файл.  И традиционные Excel-евские таблички.  Я буду использовать один и тот же документ, как и с текстовыми файлами.  С той особенностью, что нам надо из Excel-SX получить CSV.  Причем, поскольку у нас в одном Excel-евском файлике несколько листов,  по сути, нам надо каждый из этих файлов, каждый из этих листов в отдельный файл поместить.  Вот у меня исходный этот файл.  И небольшой здесь алгоритм, который в цикле берет по очереди каждый из листочков  и превращает их в отдельный CSV-файл. 

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

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

 Там вместо этого мы задаем нашему такому агенту запросы на человеческом языке. Он преобразует это в... SQL-запросы. И эти запросы, значит, обращаются к базе данных.  Или, если мы говорим про CSV или Excel-файлы,  там подобный же подход может использоваться,  что мы делаем запросы к большой языковой модели на обычном языке,  а она переводит это в питоновский код, в пандасовские команды,  получает какие-то ответы,  и эти ответы уже превращают опять в человеческий текст.  Мы, может быть, в одном из последующих видео посмотрим, попробуем такое сделать.  Но вот, наверное, тогда нужно делать это в виде какой-то базы данных,  потому что так получается с отдельным PDF-файлом не очень взаимодействовать.  Или надо как-то продумывать.  Все равно какой-то...  Какую-то структуру в этих PDF...  В этих CSV, там, Excel-евских файликах.  То есть, может быть, надо каждый файл обязательно каким-то сопровождать описанием.  В чем преимущество вот этих векторных представлений?  Это очень простой способ. 

 То есть, может быть, надо каждый файл обязательно каким-то сопровождать описанием. В чем преимущество вот этих векторных представлений? Это очень простой способ. Мы просто нарезаем на кусочки,  и эти кусочки, не задумываясь,  складываем в общую форму.  И потом по векторному представлению ищем в этой кучке.  Это максимально простой подход,  но из-за него у нас нет какой-то структуры.  То есть у нас все фрагментики равноценны,  и структурность какая-то отсутствует.  А все-таки таблицы — это структурированные данные.  Поэтому...  Ну, вот сейчас увидим, что...  Наши CSV-файлики не очень хорошо справляются.  Excel-евские — получше.  Но об этом чуть-чуть далее.  Итак, нам понадобится загрузить, опять же, файлы и разрезать их на фрагменты.  Теперь у нас не один файл, а тут целый наборчик этих файлов.  Мы собираем их в список.  И обычный загрузчик по умолчанию, значит, использует...  По одному файлу для загрузки за раз.  Поэтому мы здесь это сделаем в цикле.  Загрузим. 

 По одному файлу для загрузки за раз. Поэтому мы здесь это сделаем в цикле. Загрузим. И посмотрим, сколько у нас всего получилось файликов и фрагментов.  Потому что он сразу здесь нарезает на кусочки.  Там какая история, как правило, как это происходит,  разделяется на отдельные строки.  То есть получится, что всего нарезалось на 140...  Как бы каждая запись из таблицы, каждая строка из таблицы —  вот она как отдельная сущность с указанием ее обозначений.  То есть что там в шапке таблицы содержится.  Но в нашем случае, поскольку у нас не естественно CSV-шные файлы,  а полученные из таблицы, то есть файлы, которые мы получили,  из Excel-евского файла, у нас есть проблемы с заголовками.  Вот они здесь нормально не отобразились.  Поэтому качество нашего материала хуже.  Но, может быть, как-нибудь в другой раз попробуем нормальную CSV-шку  прогнать через нарезку и посмотреть.  Ну, кстати, мы сплиттер здесь никакой специальный не используем.  Там разделение на кусочки по файлу, 

 прогнать через нарезку и посмотреть. Ну, кстати, мы сплиттер здесь никакой специальный не используем. Там разделение на кусочки по файлу, по строчкам — оно происходит естественным путем, скажем так.  Да, и вот здесь видно, в метаданных даже сохраняется информация о том, какая это строка.  Что ж, давайте мы создадим тоже из этих кусочков векторную базу.  И здесь мы по вот этим скучным таблицам зададим скучные вопросы  из разных этих табличек про социальную защиту, сколько было потрачено,  процент общих затрат на зарплату в определенном году  и про конкретную отрасль.  Но вот в силу того, что у нас структурность будет потеряна,  мы увидим, что CSV-шка,  это не очень хорошо.  Вот у нас эти три вопроса.  Есть сразу ответы.  Мы попробуем в фрагменте найти вот это число.  Если оно попадает, то значит будем считать, что наша система сработала хорошо.  Если не попадает, то будем считать, что плохо сработало.  Ну вот давайте зададим первый из этих трех запросов.  Тут три вопроса.   

 Тут три вопроса. Получается, какая интересная особенность.  Там получается, что в одной ячейке вся текстовая информация с определениями содержится.  И поскольку мы задаем текстовые также запросы,  очень часто первым в ответ, в фрагментах будет попадать вот именно этот набор определений.  Это отдельный листик, да,  в котором в одной ячейке все вот так вот.  Это понаписано.  Поэтому здесь большой-большой кусок текстовой информации.  Но нас интересует, есть ли все-таки ответ на вопрос.  А для этого мне нужно вбить соответствующее число.  Только нужно иметь в виду, что это число должно через точку быть.  Потому что в Excel это оно...  ...  ...в виде запятой, а здесь все-таки в виде точки.  Но вот в итоге не показывает такого числа,  значит соответствующий фрагмент не попал в выборку.  Поэтому перейдем к следующему вопросу.  Здесь мы должны найти вот это вот число 76 и 6.  Я сразу его подставлю.  Так, сейчас.  Сразу подставлю.  Только надо, чтобы оно было не с запятой, а с точкой.  Вам, возможно, не видно. 

 Сразу подставлю. Только надо, чтобы оно было не с запятой, а с точкой. Вам, возможно, не видно. Я через Ctrl-F делаю запросы.  Возможно, вам не видно из-за того, что я транслирую только одну вкладку своего браузера.  Но это не принципиально, да.  Я думаю, что просто мы попробуем найти.  Есть ответ на вопрос?  Нет.  Тоже нету.  Тоже первым идет большой этот кусок с определениями.  Потом какие-то кусочки таблиц.  Но не соответствующие ответу на запрос.  Ну и последнее.  Нужно нам получить вот это число 79 и 5.  Когда там запросы про обрабатывающую промышленность.  В итоге поиск меня перекидывает куда-то не туда.  Приходится листать.  Это не так.   Это все мы уже пробежали.  Это тоже у нас уже было.  Мы последний вопрос для этих файлов задаем.  И что мы видим здесь?  Подсвечивается, не подсвечивается.  Вроде не подсвечивается.  Значит, опять же, да, не появилось.  Значит, не нашлось.  Не нашлось.  То есть в данном случае из-за того, я думаю, что у нас ненормально работает структура этих табличек, 

 Значит, не нашлось. Не нашлось. То есть в данном случае из-за того, я думаю, что у нас ненормально работает структура этих табличек, мы в итоге релевантные кусочки не нашли.  Имейте это в виду, если будете создавать вопросно-ответные системы с табличными данными.  И у вас исходные табличные файлики будут ненадолго.  И вы не получите ответы.  Вы ответы получать правильные не будете.  Ну и теперь давайте перейдем к последнему на сегодня формату.  А именно мы, собственно, xlsx файлы xl-евские возьмем.  Но чтобы выбрать подходящий формат их разделки, скажем так, мы используем несколько подходов.  Во-первых, мы можем попробовать.  Взять вот тот сплиттер, который у нас есть изначально.  Для нарезки текстовых файлов мы его использовали.  Давайте мы его попробуем.  Потом мы возьмем просто настройки по умолчанию.  И посмотрим сколько фрагментов и какие фрагменты получаются там.  И последнее, что мы сделаем, это попробуем использовать.  Есть еще такой дополнительный режим у загрузчика. 

 И посмотрим сколько фрагментов и какие фрагменты получаются там. И последнее, что мы сделаем, это попробуем использовать. Есть еще такой дополнительный режим у загрузчика. Который называется unstructured excel loader.  Тоже он завязан на библиотеку unstructured.  Он, как утверждает документация, если выставить mode elements, он выделяет отдельно странички.  Но мы сейчас увидим, что там не только странички отдельно выделяются.  И в итоге тоже нам, наверное, для вот этого примера не очень подойдет.  Значит, сперва вот этот вот загрузчик, который разделяет, используя текстовый вот тот разделитель.  Мы получаем 24 фрагмента.  Это, наверное, многовато для вот этих нескольких табличек.  Давайте посмотрим, как выглядит отдельный фрагмент.  Ну вот мы видим, что он получается довольно маленький.  И, соответственно, не всегда можно будет по нему найти подходящие ответы.  Поэтому мы возьмем и используем также настройки по умолчанию. 

 Ну вот мы видим, что он получается довольно маленький. И, соответственно, не всегда можно будет по нему найти подходящие ответы. Поэтому мы возьмем и используем также настройки по умолчанию. И посмотрим, сколько элементов у нас, сколько фрагментов у нас получится таким подходом.  6 вместо 24.  То есть, по сути, там практически по одной страничке.  Может быть, даже какие-то странички, вот листочки соединились вместе.  Потому что мне кажется, что даже больше.  Давайте проверим.  У нас 6 вот этих листочков, плюс у нас есть еще понятие и определение, и содержание.  8.  То есть там какие-то листики еще между собой соединились.  Тоже посмотрим отдельный фрагмент, как он выглядит.  Ну и мы видим здесь, что поскольку берется вся там табличка, а то и больше, чем вся табличка,  мы получаем такой цельный фрагмент, который...  Если будет нормально позволять контекстное окно, удобно использовать.  То есть мы из этой таблички ничего не потеряем. 

 мы получаем такой цельный фрагмент, который... Если будет нормально позволять контекстное окно, удобно использовать. То есть мы из этой таблички ничего не потеряем. А вот ту структуру там с переносами и со всем прочим, большая языковая модель, она разберется в ней.  Так, и тогда вот это разделение на отдельные листочки попробуем.  Я здесь не делаю lot and split.  Я делаю просто lot.  Но при этом он все равно там какую-то нарезку...  То есть в документации реально написано, что просто как будто бы делит на отдельные листочки.  Но мы сейчас увидим, что фрагментов у нас там даже больше, чем обычным этим текстовым разделителем.  Текстовым разделителем мы там понаделали 24 кусочка, а здесь аж целых 43.  То есть получается, что каждый кусочек он еще меньше.  Таким образом выловить там, наверное, вообще ничего не получится осмысленного.  Поэтому мы возьмем...  Мы возьмем нарезку по умолчанию и ее используем для создания векторной базы.  И также к векторной этой базе поделаем запросы. 

 Поэтому мы возьмем... Мы возьмем нарезку по умолчанию и ее используем для создания векторной базы. И также к векторной этой базе поделаем запросы. И вот здесь у нас уже должны попадаться нужные ответы.  Это не очень читаемо человеческим глазом.  Но вот я вижу, что число 22 и 6, относящиеся к расходам на социальную защиту работников,  оно попадает.  Вот я не уверен, что точно оно видно, что это 21 год.  Хотя, наверное, будет видно.  Но все зависит дальше от возможностей большой языковой модели.  Нормально ли она сможет интерпретировать вот всю эту структуру как таблицу?  И не съедет ли у нее там какой-нибудь столбец?  А так, в принципе, нужный кусочек нашелся при таком нарезании.  Поэтому такой вариант, наверное, получше.  Такой вариант получше.  Да, еще, наверное, не сказал одну вещь, про которую хотел сказать.  Нарезка на более мелкие кусочки у нас получилась.  Но интересно, что больше мета-информации зато в такой нарезке получается.  Иногда, возможно, это будет плюсом. 

 Нарезка на более мелкие кусочки у нас получилась. Но интересно, что больше мета-информации зато в такой нарезке получается. Иногда, возможно, это будет плюсом. Так, а мы перейдем к оставшимся вопросам.  Совсем чуть-чуть нам осталось.  Вот следующий вопрос про заработную плату в 2005 году.  И в ответе должно быть там что-то про 76,6%.  Поэтому давайте сюда заглянем.  И, по-моему, тоже оно находилось.  А может быть и нет.  Поэтому давайте я сейчас 76,6.  И сколько там? И 6.  Правильно.  Да, 76,6.  И что-то тут такое встречается.  Среднемесячные зарплаты на рабочую силу, называется.  Ну, видимо, это как раз-таки оно.  То есть тоже табличные данные в таком случае сработали.   Как надо.  Ну и последний вопрос.  Где в ответе должно быть там 79,5%.  Тоже давайте проверим.  79,5.  Так, только лишь заменим на точку.  Так, смотрим.  Нет, а вот такого фрагмента не нашлось.  Потому что 79,5.  Оказалось, что только при загрузке у нас на страничке такое какое-то сочетание символов. 

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

 Надеюсь, что вам стало понятнее. Если будут какие-то сложности и вопросы, можно... задавать вопросы в комментариях здесь. Можно писать в комментариях в Telegram.  Постараюсь помочь, постараюсь подсказать.  Ну, а дальше, наверное, мы в последующих видеороликах, если будем возвращаться к вопросно-ответным системам, должны поговорить про метрики оценки получаемых результатов.  Ну, мы, наверное, попробуем какие-то вот автоматизированные методы.  Методы оценки использовать.  Поговорим, какие показатели там встречаются.  Ну, а также в планах есть попробовать какие-то другие тематики еще.  Еще немножко про агентов.  Попробовать в какую-то мультимодальность.  А также, возможно, попробовать и какие-то open-source модели.  Но самое главное, чтобы хватило на все времени.  Все, спасибо, кто сегодня смотрел.  И увидимся в следующих видеороликах. 