2036 lines
55 KiB
Plaintext
2036 lines
55 KiB
Plaintext
Тайм коды со слайдами
|
||
**слайд** обо мне [0:00:02 → 0:00:50]
|
||
**слайд** компании использующие AI [0:00:50 → 0:02:10]
|
||
**слайд** демонстрация работы сервиса gamma.app [0:02:10 → 0:03:12]
|
||
**слайд** задачи которые нужно решить чтобы сделать аналог [0:03:12 → 0:04:15]
|
||
**слайд** план создания презентации в видео строки [0:04:15 → 0:05:14]
|
||
**слайд** о langChain и langGraph [0:05:15 → 0:05:40]
|
||
**слайд** промт для генерации презентации [0:05:40 → 0:06:23]
|
||
**слайд** описание json схемы [0:06:23 → 0:08:00]
|
||
**слайд** описание работы парсера ответа от LLM [0:08:00 → 0:09:25]
|
||
**слайд** демонстрация распарсеного json [0:09:25 → 0:09:55]
|
||
**слайд** демонстрация аналога сервиса gamma.app [0:09:55 → 0:10:57]
|
||
**слайд** объяснение работы langGraph [0:10:57 → 0:26:20]
|
||
|
||
[0:00:00 → 0:00:01]
|
||
Смотрим, как они устроены.
|
||
|
||
[0:00:02 → 0:00:03]
|
||
Пару слов о себе.
|
||
|
||
[0:00:03 → 0:00:09]
|
||
Меня зовут Александр, около 10 лет опыта в IT и 6 из них это работа в Сбере, уже больше половины получается.
|
||
|
||
[0:00:10 → 0:00:14]
|
||
В Сбере я фронт-энд разработчик и мой основной инструмент это TypeScript.
|
||
|
||
[0:00:16 → 0:00:20]
|
||
Но кроме того, что я работаю в Сбере, я еще преподаю в университетах.
|
||
|
||
[0:00:21 → 0:00:28]
|
||
С коллегами моими используем учебную платформу самописную, на которой я как бы full-stack разработчик получается.
|
||
|
||
[0:00:28 → 0:00:31]
|
||
Там и фронт-энд, и бэк-энд, и ICD, база данных, в общем, все на мне.
|
||
|
||
[0:00:32 → 0:00:35]
|
||
И в этом году мы запустили курс по созданию AI-агентов.
|
||
|
||
[0:00:35 → 0:00:45]
|
||
И успешно с магистрами Казанского федерального университета прошли этот курс, они создали приложение с AI-агентами.
|
||
|
||
[0:00:46 → 0:00:48]
|
||
Вот, но о чем я хотел поговорить.
|
||
|
||
[0:00:48 → 0:00:52]
|
||
Хайповые AI-сервисы у Forbes, даже есть список на этот счет.
|
||
|
||
[0:00:52 → 0:00:58]
|
||
Топ 50 компаний, которые на AI-сервисах основаны.
|
||
|
||
[0:00:58 → 0:01:01]
|
||
Здесь не очень удобно, потому что они отсортированы по алфавиту.
|
||
|
||
[0:01:01 → 0:01:05]
|
||
Наверное, интереснее посмотреть по деньгам, если их пересортировать.
|
||
|
||
[0:01:05 → 0:01:09]
|
||
Вот видно, что OpenAI на первом месте, понятно.
|
||
|
||
[0:01:10 → 0:01:15]
|
||
Но здесь очень много компаний, которые вы наверняка слышали или пользовались их сервисами.
|
||
|
||
[0:01:22 → 0:01:25]
|
||
Создатели Bolt New, Cursor, все здесь.
|
||
|
||
[0:01:26 → 0:01:28]
|
||
Ну, меня заинтересовало.
|
||
|
||
[0:01:28 → 0:01:33]
|
||
Приложение, которое, точнее, компания, вот чуть ниже, Speak называется тоже.
|
||
|
||
[0:01:34 → 0:01:36]
|
||
Топ 50 входит.
|
||
|
||
[0:01:36 → 0:01:41]
|
||
Они разработали приложение для изучения иностранных языков с помощью искусственного интеллекта.
|
||
|
||
[0:01:41 → 0:01:43]
|
||
С помощью AI-агента, помощника.
|
||
|
||
[0:01:44 → 0:01:47]
|
||
Я его скачал, попробовал, в принципе, неплохо.
|
||
|
||
[0:01:47 → 0:01:52]
|
||
Но я вам так скажу, что наши студенты, в принципе, делают не хуже, уж точно, не хуже приложения.
|
||
|
||
[0:01:52 → 0:01:56]
|
||
Хотя здесь они, например, с 2016 года давно работали над ним.
|
||
|
||
[0:01:57 → 0:01:58]
|
||
Но вот сейчас.
|
||
|
||
[0:01:58 → 0:02:01]
|
||
Уже можно довольно быстро создавать такие вещи.
|
||
|
||
[0:02:01 → 0:02:04]
|
||
Давайте разбираться, как они делаются.
|
||
|
||
[0:02:04 → 0:02:07]
|
||
Как разрабатываются приложения с AI-агентами.
|
||
|
||
[0:02:07 → 0:02:11]
|
||
В качестве подобного я решил выбрать GumUp.
|
||
|
||
[0:02:12 → 0:02:13]
|
||
Вспомним, что такое GumUp.
|
||
|
||
[0:02:13 → 0:02:16]
|
||
Это приложение для создания презентаций.
|
||
|
||
[0:02:17 → 0:02:20]
|
||
Вот, вводим, что мы хотим, на какую тему мы хотим презентацию.
|
||
|
||
[0:02:20 → 0:02:26]
|
||
Она нам создает план презентации, где расписывает про каждый слайд, заголовок.
|
||
|
||
[0:02:26 → 0:02:27]
|
||
Ну и буллеты, коротко там.
|
||
|
||
[0:02:27 → 0:02:28]
|
||
Один, два, три просто.
|
||
|
||
[0:02:28 → 0:02:30]
|
||
О чем слайд должен быть.
|
||
|
||
[0:02:30 → 0:02:34]
|
||
После создания плана нажимаем создать презентацию и она создается.
|
||
|
||
[0:02:35 → 0:02:37]
|
||
Просто волшебство какое-то.
|
||
|
||
[0:02:37 → 0:02:39]
|
||
Каждый слайд появляется последовательно.
|
||
|
||
[0:02:39 → 0:02:42]
|
||
Для каждого слайда там почти для каждого.
|
||
|
||
[0:02:42 → 0:02:43]
|
||
Генерируется изображение.
|
||
|
||
[0:02:43 → 0:02:45]
|
||
Буллеты как-то оформляются.
|
||
|
||
[0:02:47 → 0:02:51]
|
||
Текст тоже как-то все красиво компонуется.
|
||
|
||
[0:02:52 → 0:02:55]
|
||
И вуаля, просто вот презентация готова.
|
||
|
||
[0:02:56 → 0:02:56]
|
||
Сгенерирована.
|
||
|
||
[0:02:56 → 0:02:59]
|
||
Причем довольно красиво получается.
|
||
|
||
[0:02:59 → 0:03:01]
|
||
В общем-то он все логично расписал.
|
||
|
||
[0:03:01 → 0:03:09]
|
||
То, что если хотим учиться фотографировать котят, нам нужно подумать об свете, о настройках камеры, выбор ракурса, в общем, такого.
|
||
|
||
[0:03:09 → 0:03:11]
|
||
Ну давайте декомпозировать.
|
||
|
||
[0:03:11 → 0:03:12]
|
||
Как такие вещи делать?
|
||
|
||
[0:03:12 → 0:03:13]
|
||
Значит, первое и второе.
|
||
|
||
[0:03:13 → 0:03:16]
|
||
Нам глобально надо решить две задачи.
|
||
|
||
[0:03:16 → 0:03:20]
|
||
Это генерировать план презентации.
|
||
|
||
[0:03:20 → 0:03:22]
|
||
Ну и саму презентацию на основе этого плана.
|
||
|
||
[0:03:23 → 0:03:24]
|
||
Вот такие две части.
|
||
|
||
[0:03:24 → 0:03:26]
|
||
Как разрабатывать план презентации?
|
||
|
||
[0:03:26 → 0:03:28]
|
||
Ну самый простой путь просто.
|
||
|
||
[0:03:28 → 0:03:34]
|
||
Берем, открываем любой чатик с искусственным интеллектом, просим его создать нам план презентации.
|
||
|
||
[0:03:34 → 0:03:36]
|
||
Довольно несложный промпт.
|
||
|
||
[0:03:36 → 0:03:38]
|
||
Вот я открыл гигачат, посмотрел.
|
||
|
||
[0:03:38 → 0:03:41]
|
||
Он мне генерирует, в принципе, примерно то же самое.
|
||
|
||
[0:03:42 → 0:03:46]
|
||
То есть какие-то слайды, темы для каждого слайда и буллеты.
|
||
|
||
[0:03:47 → 0:03:48]
|
||
О чем должен быть этот слайд?
|
||
|
||
[0:03:48 → 0:03:51]
|
||
И здесь, в принципе-то, и план такой же.
|
||
|
||
[0:03:51 → 0:03:53]
|
||
Может быть, чуть другая последовательность.
|
||
|
||
[0:03:53 → 0:03:55]
|
||
Подумать о композиции, ракурсе.
|
||
|
||
[0:03:56 → 0:03:57]
|
||
Настроить камеру, настроить свет.
|
||
|
||
[0:03:57 → 0:04:01]
|
||
Как-то договориться с котенком о том, что мы его будем фотографировать.
|
||
|
||
[0:04:01 → 0:04:02]
|
||
Ну, в таком плане.
|
||
|
||
[0:04:04 → 0:04:07]
|
||
Я разработал приложение, которое похоже на Gama App.
|
||
|
||
[0:04:07 → 0:04:11]
|
||
Можно сказать, клон Gama App, на основе которого я это все буду рассказывать.
|
||
|
||
[0:04:11 → 0:04:14]
|
||
И у меня в приложении промпт выглядит чуть больше.
|
||
|
||
[0:04:14 → 0:04:16]
|
||
Вообще, он выглядит вот так.
|
||
|
||
[0:04:16 → 0:04:17]
|
||
Это огромная-огромная строка.
|
||
|
||
[0:04:18 → 0:04:21]
|
||
Не пугайтесь, я сейчас разберу, из чего она состоит.
|
||
|
||
[0:04:21 → 0:04:25]
|
||
В общем-то, тут есть первая такая часть, где я уговариваю его.
|
||
|
||
[0:04:26 → 0:04:27]
|
||
Создать план.
|
||
|
||
[0:04:27 → 0:04:28]
|
||
Объясняю, что мы будем создавать план.
|
||
|
||
[0:04:31 → 0:04:34]
|
||
И расписываю, какие виды слайдов существуют.
|
||
|
||
[0:04:34 → 0:04:37]
|
||
Какие бывают, которые моя система готова.
|
||
|
||
[0:04:37 → 0:04:40]
|
||
Потом воспроизводить титульный слайд, там, контентный и так далее.
|
||
|
||
[0:04:41 → 0:04:45]
|
||
Потом довольно большая часть, которая относится к форматированию ответа.
|
||
|
||
[0:04:45 → 0:04:49]
|
||
Я хочу получить ответ, ну, не в формате текста или Markdown.
|
||
|
||
[0:04:49 → 0:04:51]
|
||
Мне будет удобнее работать с форматом JSON.
|
||
|
||
[0:04:53 → 0:04:55]
|
||
И здесь описывается этот формат.
|
||
|
||
[0:04:56 → 0:04:59]
|
||
Ну, и в конце я добавляю еще текущую дату.
|
||
|
||
[0:04:59 → 0:05:04]
|
||
Нейросетям неплохо бы в промптах добавлять информацию о текущей дате.
|
||
|
||
[0:05:04 → 0:05:08]
|
||
Чтобы он учитывал и понимал, что если просят что-то новенькое,
|
||
|
||
[0:05:08 → 0:05:10]
|
||
то нужно сходить в интернет и поискать.
|
||
|
||
[0:05:13 → 0:05:17]
|
||
Делаются такие вещи, в общем-то, не руками, а с помощью фреймворков.
|
||
|
||
[0:05:17 → 0:05:21]
|
||
Хотя, безусловно, все это и руками можно создать и отправить, но это неудобно.
|
||
|
||
[0:05:21 → 0:05:24]
|
||
При масштабировании уже становится понятно.
|
||
|
||
[0:05:25 → 0:05:26]
|
||
Сложно расти.
|
||
|
||
[0:05:26 → 0:05:30]
|
||
Нужно пользоваться фреймворками, которые как раз позволяют свое решение масштабировать.
|
||
|
||
[0:05:31 → 0:05:32]
|
||
Лонгчейн и лонгграф, в общем.
|
||
|
||
[0:05:34 → 0:05:37]
|
||
Для создания плана презентации нам будет достаточно лонгчейна.
|
||
|
||
[0:05:37 → 0:05:39]
|
||
А вот для самой презентации уже будем использовать лонгграф.
|
||
|
||
[0:05:40 → 0:05:46]
|
||
Как с помощью лонгчейна создать вот этот большой-большой промпт для генерации плана?
|
||
|
||
[0:05:46 → 0:05:49]
|
||
В общем-то, используется для этого шаблоны.
|
||
|
||
[0:05:49 → 0:05:52]
|
||
В лонгчейне есть такой механизм, как вот шаблоны.
|
||
|
||
[0:05:53 → 0:05:55]
|
||
Мы тут здесь описываем то,
|
||
|
||
[0:05:55 → 0:05:57]
|
||
что хотим описать, то, что статично,
|
||
|
||
[0:05:57 → 0:06:01]
|
||
а все вещи, которые будут потом должны быть заполнены,
|
||
|
||
[0:06:01 → 0:06:04]
|
||
мы обрамляем вот так, фигурные скобки, и название включаем.
|
||
|
||
[0:06:04 → 0:06:07]
|
||
То есть потом пользователь к нам придет с названием презентации,
|
||
|
||
[0:06:07 → 0:06:10]
|
||
и мы вот топик подменим на тему, которую он нам прислал.
|
||
|
||
[0:06:11 → 0:06:13]
|
||
И так далее, все в шаблоне заменим.
|
||
|
||
[0:06:13 → 0:06:14]
|
||
Это самое простое.
|
||
|
||
[0:06:14 → 0:06:17]
|
||
А вот насчет инструкций по форматированию, вот можно видеть,
|
||
|
||
[0:06:17 → 0:06:20]
|
||
что внизу есть вот такая вещь, формат instructions.
|
||
|
||
[0:06:21 → 0:06:24]
|
||
Вот ее нужно заполнить этими инструкциями для форматирования.
|
||
|
||
[0:06:24 → 0:06:25]
|
||
Как они делаются?
|
||
|
||
[0:06:26 → 0:06:30]
|
||
В общем-то, можно JSON-схему, конечно, положить туда руками,
|
||
|
||
[0:06:30 → 0:06:33]
|
||
но на разных языках это делается чуть по-разному.
|
||
|
||
[0:06:34 → 0:06:36]
|
||
Примерно всегда есть какая-то обертка.
|
||
|
||
[0:06:37 → 0:06:40]
|
||
На TypeScript у нас это Zot библиотечка,
|
||
|
||
[0:06:40 → 0:06:44]
|
||
которая очень популярна стала для описания форм объектов.
|
||
|
||
[0:06:45 → 0:06:47]
|
||
И вот здесь я как раз описываю, что у нас есть презентация.
|
||
|
||
[0:06:48 → 0:06:51]
|
||
Глобального презентации в целом есть какое-то заголовок,
|
||
|
||
[0:06:51 → 0:06:52]
|
||
какое-то описание.
|
||
|
||
[0:06:52 → 0:06:54]
|
||
Я это делаю, потому что, ну, по-моему,
|
||
|
||
[0:06:54 → 0:06:58]
|
||
пользователь может опечататься или как-то несуразно сформулировать тему,
|
||
|
||
[0:06:58 → 0:07:00]
|
||
которую, может быть, нейросеть решит переформулировать,
|
||
|
||
[0:07:01 → 0:07:02]
|
||
ну, плюс добавить описание.
|
||
|
||
[0:07:02 → 0:07:04]
|
||
Ну и когда мы генерируем план презентации,
|
||
|
||
[0:07:04 → 0:07:06]
|
||
в этот момент неплохо бы добавить что-то общее,
|
||
|
||
[0:07:06 → 0:07:09]
|
||
что будет актуально для всей презентации.
|
||
|
||
[0:07:09 → 0:07:11]
|
||
Например, общий стиль изображений.
|
||
|
||
[0:07:11 → 0:07:14]
|
||
Что гамап вы видели, что у меня, посмотрите,
|
||
|
||
[0:07:14 → 0:07:16]
|
||
что картинки генерируются в едином стиле,
|
||
|
||
[0:07:16 → 0:07:19]
|
||
едином и для всей презентации.
|
||
|
||
[0:07:19 → 0:07:22]
|
||
Вот здесь формируется этот стиль глобальный.
|
||
|
||
[0:07:22 → 0:07:23]
|
||
Ну, а потом каждый слайд.
|
||
|
||
[0:07:24 → 0:07:25]
|
||
У слайда должен быть заголовок,
|
||
|
||
[0:07:25 → 0:07:27]
|
||
у него может быть контентная часть,
|
||
|
||
[0:07:27 → 0:07:30]
|
||
но на этапе планирования, в общем-то, она не заполняется.
|
||
|
||
[0:07:31 → 0:07:34]
|
||
Буллеты — это как раз вот массив строк про то,
|
||
|
||
[0:07:34 → 0:07:36]
|
||
о чем слайд, первый, второй, третий,
|
||
|
||
[0:07:36 → 0:07:38]
|
||
ну и какие-то еще дополнительные вещи,
|
||
|
||
[0:07:38 → 0:07:40]
|
||
которые мы можем захотеть.
|
||
|
||
[0:07:40 → 0:07:43]
|
||
Естественно, мы это описываем не просто набором ключей,
|
||
|
||
[0:07:43 → 0:07:46]
|
||
а для каждого ключа описываем тип этого ключа
|
||
|
||
[0:07:46 → 0:07:51]
|
||
и через describe описываем, о чем этот ключ.
|
||
|
||
[0:07:51 → 0:07:53]
|
||
То есть если title — это строка, понятно,
|
||
|
||
[0:07:54 → 0:07:56]
|
||
то что это за строка описывается уже через describe,
|
||
|
||
[0:07:56 → 0:07:57]
|
||
как ее заполнять.
|
||
|
||
[0:07:58 → 0:07:59]
|
||
Вот.
|
||
|
||
[0:08:00 → 0:08:03]
|
||
После того, как мы эти вещи применим,
|
||
|
||
[0:08:03 → 0:08:05]
|
||
мы сможем получить финальный промт.
|
||
|
||
[0:08:05 → 0:08:06]
|
||
Как это делается?
|
||
|
||
[0:08:06 → 0:08:09]
|
||
Мы берем, тут пример из документации,
|
||
|
||
[0:08:10 → 0:08:13]
|
||
мы берем Structured Output Parser,
|
||
|
||
[0:08:14 → 0:08:17]
|
||
который инициализируем из этой ZOT-схемы.
|
||
|
||
[0:08:17 → 0:08:19]
|
||
Потом нам нужен промт,
|
||
|
||
[0:08:19 → 0:08:23]
|
||
в котором мы пометим какое-то место,
|
||
|
||
[0:08:23 → 0:08:27]
|
||
в которое попадет инструкция по форматированию в конечном итоге.
|
||
|
||
[0:08:27 → 0:08:29]
|
||
Вот такой формат instructions
|
||
|
||
[0:08:29 → 0:08:32]
|
||
где-то нужно разместить внутри нашего промта.
|
||
|
||
[0:08:33 → 0:08:35]
|
||
Затем туда добавляются модели parser,
|
||
|
||
[0:08:35 → 0:08:39]
|
||
то есть мы формируем chain для long chain.
|
||
|
||
[0:08:39 → 0:08:42]
|
||
Первым в этой цепочке получается template,
|
||
|
||
[0:08:42 → 0:08:44]
|
||
потом модель, потом parser,
|
||
|
||
[0:08:44 → 0:08:46]
|
||
который нам на выходе выдаст как раз JSON.
|
||
|
||
[0:08:47 → 0:08:48]
|
||
Вот.
|
||
|
||
[0:08:49 → 0:08:51]
|
||
Инструкции по форматированию получаются, ну,
|
||
|
||
[0:08:51 → 0:08:53]
|
||
вызовом метода getFormatInstructions.
|
||
|
||
[0:08:53 → 0:08:55]
|
||
Тут, в общем-то, тоже как бы магии нету.
|
||
|
||
[0:08:55 → 0:08:57]
|
||
В момент, когда мы запускаем цепочку,
|
||
|
||
[0:08:57 → 0:09:01]
|
||
мы этот ключ формат instructions заполняем вызовом этого метода
|
||
|
||
[0:09:02 → 0:09:02]
|
||
getFormatInstructions.
|
||
|
||
[0:09:03 → 0:09:07]
|
||
То есть getFormatInstructions просто выдает нам конкретное сообщение,
|
||
|
||
[0:09:07 → 0:09:11]
|
||
что там, пожалуйста, следуй вот такой JSON-схеме,
|
||
|
||
[0:09:11 → 0:09:16]
|
||
отдай мне ответ, строго соблюдая этот контракт.
|
||
|
||
[0:09:18 → 0:09:20]
|
||
Ну и, кроме того, можем заполнить дополнительные вещи,
|
||
|
||
[0:09:20 → 0:09:24]
|
||
то есть в моем случае пользователь приходит с темой презентации,
|
||
|
||
[0:09:24 → 0:09:26]
|
||
может быть, с каким-то дополнительным описанием,
|
||
|
||
[0:09:26 → 0:09:27]
|
||
я все это прокидываю в prompt.
|
||
|
||
[0:09:28 → 0:09:29]
|
||
Выглядит это вот таким образом.
|
||
|
||
[0:09:29 → 0:09:33]
|
||
Если это вызвать, то искусственный интеллект начинает нам возвращать
|
||
|
||
[0:09:33 → 0:09:36]
|
||
большую-большую строку, которая внутри содержит JSON.
|
||
|
||
[0:09:38 → 0:09:42]
|
||
В этом JSON просто вот заполнены те ключи, которые я описывал.
|
||
|
||
[0:09:42 → 0:09:44]
|
||
Ну, где-то он даже контент заполняет,
|
||
|
||
[0:09:44 → 0:09:46]
|
||
но потом я в любом случае контент формирую уже отдельно,
|
||
|
||
[0:09:46 → 0:09:49]
|
||
когда презентация целиком генерируется.
|
||
|
||
[0:09:50 → 0:09:53]
|
||
Вот. Значит, ну тут примерно то же самое.
|
||
|
||
[0:09:53 → 0:09:54]
|
||
Профотографирование котят.
|
||
|
||
[0:09:55 → 0:09:57]
|
||
Посмотрим, как это выглядит у меня.
|
||
|
||
[0:09:59 → 0:10:02]
|
||
Я закидываю тему презентации, прошу сгенерировать план,
|
||
|
||
[0:10:02 → 0:10:06]
|
||
и вот начинает прилетать этот JSON, который я показывал,
|
||
|
||
[0:10:06 → 0:10:08]
|
||
он разбирается, и мы генерируем план.
|
||
|
||
[0:10:09 → 0:10:11]
|
||
Ну, интересно, что в моем случае я решил,
|
||
|
||
[0:10:12 → 0:10:15]
|
||
что было бы неплохо ходить в интернет для некоторых тем,
|
||
|
||
[0:10:15 → 0:10:17]
|
||
а для некоторых слайдов,
|
||
|
||
[0:10:17 → 0:10:20]
|
||
если искусственный интеллект так решит,
|
||
|
||
[0:10:20 → 0:10:23]
|
||
если мой AI-агент захочет что-то поискать в интернете.
|
||
|
||
[0:10:23 → 0:10:26]
|
||
Ну и здесь я генерирую промпт для изображения
|
||
|
||
[0:10:26 → 0:10:28]
|
||
и негативный промпт для изображения,
|
||
|
||
[0:10:28 → 0:10:30]
|
||
чтобы потом диффузионной моделькой, собственно,
|
||
|
||
[0:10:30 → 0:10:33]
|
||
сгенерировать изображение с промптом и негативным промптом.
|
||
|
||
[0:10:34 → 0:10:37]
|
||
Вот. Затем нажимаем «Создать презентацию».
|
||
|
||
[0:10:37 → 0:10:39]
|
||
В принципе, с планом мы разобрались.
|
||
|
||
[0:10:39 → 0:10:43]
|
||
И вот как выглядит создание презентации.
|
||
|
||
[0:10:44 → 0:10:44]
|
||
Нажимаем.
|
||
|
||
[0:10:46 → 0:10:47]
|
||
Немножко подвисло.
|
||
|
||
[0:10:51 → 0:10:53]
|
||
Видео немножко подвисло, к сожалению.
|
||
|
||
[0:10:53 → 0:10:56]
|
||
Но можно сходить на сайт и посмотреть,
|
||
|
||
[0:10:56 → 0:10:57]
|
||
как оно там генерируется.
|
||
|
||
[0:10:58 → 0:11:02]
|
||
Как же генерировать вот такие более сложные вещи,
|
||
|
||
[0:11:02 → 0:11:03]
|
||
как слайды?
|
||
|
||
[0:11:03 → 0:11:05]
|
||
Это уже не просто план, где, в принципе,
|
||
|
||
[0:11:05 → 0:11:08]
|
||
одной текстовкой можно одним запросом обойтись.
|
||
|
||
[0:11:08 → 0:11:10]
|
||
А здесь вот, когда мы генерируем слайды,
|
||
|
||
[0:11:10 → 0:11:11]
|
||
каждый слайд — это какой-то контент,
|
||
|
||
[0:11:11 → 0:11:14]
|
||
тоже заголовок, изображение.
|
||
|
||
[0:11:14 → 0:11:16]
|
||
Может, надо сходить в интернет, чего-то поискать,
|
||
|
||
[0:11:16 → 0:11:18]
|
||
и всё это собрать в кучу.
|
||
|
||
[0:11:18 → 0:11:20]
|
||
В общем, здесь уже более сложные вещи.
|
||
|
||
[0:11:20 → 0:11:21]
|
||
Здесь нам поможет ланграф.
|
||
|
||
[0:11:22 → 0:11:25]
|
||
Как раз этот фреймворк позволяет уже более сложные вещи делать.
|
||
|
||
[0:11:27 → 0:11:30]
|
||
Когда мы пользуемся ланграфом,
|
||
|
||
[0:11:30 → 0:11:32]
|
||
мы описываем логику в форме нод,
|
||
|
||
[0:11:32 → 0:11:34]
|
||
в форме узлов логики,
|
||
|
||
[0:11:34 → 0:11:37]
|
||
каждый из которых является функцией
|
||
|
||
[0:11:37 → 0:11:38]
|
||
и делает что-то своё.
|
||
|
||
[0:11:39 → 0:11:41]
|
||
У такого графа будет какая-то входная нода
|
||
|
||
[0:11:41 → 0:11:42]
|
||
и какая-то выходная нода.
|
||
|
||
[0:11:43 → 0:11:44]
|
||
И между ними будет, конечно,
|
||
|
||
[0:11:44 → 0:11:46]
|
||
как-то распределяться логика.
|
||
|
||
[0:11:46 → 0:11:48]
|
||
То есть мы можем делать что-то последовательно.
|
||
|
||
[0:11:49 → 0:11:50]
|
||
Каждая нода делает что-то своё.
|
||
|
||
[0:11:51 → 0:11:53]
|
||
Может быть, генерирует изображение,
|
||
|
||
[0:11:53 → 0:11:54]
|
||
может быть, входит в интернет,
|
||
|
||
[0:11:54 → 0:11:55]
|
||
может быть, что-то ещё.
|
||
|
||
[0:11:55 → 0:11:59]
|
||
Не обязательно, чтобы путь,
|
||
|
||
[0:11:59 → 0:12:00]
|
||
по которому перемещается логика,
|
||
|
||
[0:12:00 → 0:12:02]
|
||
был именно таким последовательным.
|
||
|
||
[0:12:03 → 0:12:05]
|
||
Потому что это, в принципе, делает лангчейн.
|
||
|
||
[0:12:05 → 0:12:07]
|
||
А для более сложных вещей
|
||
|
||
[0:12:07 → 0:12:09]
|
||
у нас есть возможность описать роутинг
|
||
|
||
[0:12:09 → 0:12:13]
|
||
и по каким-то условиям ходить в одни ноды,
|
||
|
||
[0:12:13 → 0:12:14]
|
||
не ходить в другие.
|
||
|
||
[0:12:14 → 0:12:15]
|
||
В общем-то, менять путь.
|
||
|
||
[0:12:16 → 0:12:19]
|
||
При этом мы можем написать логику так,
|
||
|
||
[0:12:19 → 0:12:20]
|
||
что в конце у нас будет вариант
|
||
|
||
[0:12:21 → 0:12:23]
|
||
вернуться в самое начало.
|
||
|
||
[0:12:23 → 0:12:24]
|
||
У нас может быть какой-то
|
||
|
||
[0:12:24 → 0:12:26]
|
||
дополнительный агент-критик,
|
||
|
||
[0:12:26 → 0:12:28]
|
||
который посмотрит, что мы сделали,
|
||
|
||
[0:12:28 → 0:12:30]
|
||
то есть что сделал AI-агент наш.
|
||
|
||
[0:12:30 → 0:12:32]
|
||
Если ему что-то не понравится,
|
||
|
||
[0:12:32 → 0:12:33]
|
||
он скажет «переделай» и вернётся
|
||
|
||
[0:12:33 → 0:12:35]
|
||
на какой-то этап начала,
|
||
|
||
[0:12:36 → 0:12:38]
|
||
чтобы сделать заново, учитывая правки.
|
||
|
||
[0:12:39 → 0:12:42]
|
||
Весь этот граф, он работает
|
||
|
||
[0:12:42 → 0:12:44]
|
||
с единым состоянием.
|
||
|
||
[0:12:44 → 0:12:47]
|
||
Мы определяем изначальное состояние
|
||
|
||
[0:12:47 → 0:12:48]
|
||
и потом передаём его между нодами,
|
||
|
||
[0:12:48 → 0:12:50]
|
||
и каждая нода работает с этим состоянием,
|
||
|
||
[0:12:50 → 0:12:51]
|
||
что-то там обновляет.
|
||
|
||
[0:12:52 → 0:12:54]
|
||
По итогу работа AI-агента является
|
||
|
||
[0:12:55 → 0:12:56]
|
||
заполненное состояние,
|
||
|
||
[0:12:56 → 0:12:58]
|
||
которое мы потом снаружи считываем
|
||
|
||
[0:12:58 → 0:12:59]
|
||
и что-то с ним делаем.
|
||
|
||
[0:12:59 → 0:13:00]
|
||
Например, рисуем презентацию.
|
||
|
||
[0:13:02 → 0:13:03]
|
||
Когда я разрабатывал...
|
||
|
||
[0:13:03 → 0:13:05]
|
||
А, бывают более сложные схемы,
|
||
|
||
[0:13:05 → 0:13:06]
|
||
более интересные даже.
|
||
|
||
[0:13:07 → 0:13:09]
|
||
Когда у нас есть агент-супервайзер,
|
||
|
||
[0:13:09 → 0:13:12]
|
||
который сам принимает решение,
|
||
|
||
[0:13:12 → 0:13:13]
|
||
нужно ли ему воспользоваться
|
||
|
||
[0:13:13 → 0:13:15]
|
||
другим каким-то агентом,
|
||
|
||
[0:13:15 → 0:13:17]
|
||
и сам принимает решение,
|
||
|
||
[0:13:17 → 0:13:18]
|
||
когда ему закончить,
|
||
|
||
[0:13:18 → 0:13:21]
|
||
например, ему дали задачу нарисовать презентацию,
|
||
|
||
[0:13:21 → 0:13:22]
|
||
он может подумать так,
|
||
|
||
[0:13:22 → 0:13:24]
|
||
мне сейчас нужно пойти в агента
|
||
|
||
[0:13:24 → 0:13:25]
|
||
для поиска в интернете,
|
||
|
||
[0:13:25 → 0:13:26]
|
||
поискать информацию,
|
||
|
||
[0:13:26 → 0:13:28]
|
||
потом сходить к художнику нарисовать,
|
||
|
||
[0:13:28 → 0:13:31]
|
||
потом сходить там и контент нагенерировать.
|
||
|
||
[0:13:31 → 0:13:34]
|
||
Но при этом он сам принимает все эти решения
|
||
|
||
[0:13:34 → 0:13:35]
|
||
и самостоятельно решает,
|
||
|
||
[0:13:35 → 0:13:39]
|
||
куда пойти и какого агента сейчас задействовать.
|
||
|
||
[0:13:39 → 0:13:41]
|
||
Получается такая мультиагентная система.
|
||
|
||
[0:13:42 → 0:13:44]
|
||
В моем случае
|
||
|
||
[0:13:44 → 0:13:46]
|
||
настолько сложная вещь не понадобилась.
|
||
|
||
[0:13:47 → 0:13:49]
|
||
Я пошел по более простому пути.
|
||
|
||
[0:13:49 → 0:13:50]
|
||
Я рисовал графы.
|
||
|
||
[0:13:51 → 0:13:52]
|
||
У меня получилось несколько вариантов
|
||
|
||
[0:13:52 → 0:13:54]
|
||
в ходе разработки этого клона.
|
||
|
||
[0:13:56 → 0:13:59]
|
||
И сейчас я вам покажу финальный вариант.
|
||
|
||
[0:13:59 → 0:14:00]
|
||
Он получился довольно компактным,
|
||
|
||
[0:14:01 → 0:14:03]
|
||
довольно дешевым в использовании
|
||
|
||
[0:14:03 → 0:14:04]
|
||
и довольно быстрым.
|
||
|
||
[0:14:05 → 0:14:06]
|
||
Дело в том, что некоторые ноды
|
||
|
||
[0:14:06 → 0:14:08]
|
||
можно запускать параллельно,
|
||
|
||
[0:14:08 → 0:14:11]
|
||
одновременно работая над несколькими задачами.
|
||
|
||
[0:14:11 → 0:14:13]
|
||
Посмотрим поочередно.
|
||
|
||
[0:14:13 → 0:14:15]
|
||
Сначала шаг подготовка.
|
||
|
||
[0:14:15 → 0:14:18]
|
||
В моем случае, что такое подготовка?
|
||
|
||
[0:14:18 → 0:14:19]
|
||
Я просто прохожусь по слайдам,
|
||
|
||
[0:14:19 → 0:14:21]
|
||
сгенерированным на этапе планирования
|
||
|
||
[0:14:21 → 0:14:23]
|
||
и назначаю им ID.
|
||
|
||
[0:14:23 → 0:14:26]
|
||
Здесь будет неплохо показать,
|
||
|
||
[0:14:26 → 0:14:28]
|
||
как выглядит нода графа.
|
||
|
||
[0:14:28 → 0:14:29]
|
||
В общем-то,
|
||
|
||
[0:14:29 → 0:14:31]
|
||
это функция,
|
||
|
||
[0:14:31 → 0:14:33]
|
||
которая принимает состояние
|
||
|
||
[0:14:33 → 0:14:35]
|
||
и она должна обещать вернуть нам
|
||
|
||
[0:14:35 → 0:14:38]
|
||
какую-то часть состояния на апдейт.
|
||
|
||
[0:14:38 → 0:14:39]
|
||
Может целиком состояние обновить,
|
||
|
||
[0:14:39 → 0:14:41]
|
||
может какие-то конкретные ключи.
|
||
|
||
[0:14:42 → 0:14:43]
|
||
Поэтому, по итогу,
|
||
|
||
[0:14:43 → 0:14:45]
|
||
мы должны вернуть объект,
|
||
|
||
[0:14:45 → 0:14:47]
|
||
у которого будут заполнены ключи
|
||
|
||
[0:14:47 → 0:14:49]
|
||
состояния, в данном случае один ключ
|
||
|
||
[0:14:49 → 0:14:51]
|
||
Presentation, в котором уже лежит план
|
||
|
||
[0:14:51 → 0:14:53]
|
||
на этапе генерации.
|
||
|
||
[0:14:54 → 0:14:56]
|
||
Это планирование мы его создали
|
||
|
||
[0:14:56 → 0:14:57]
|
||
и когда приходим к генерации,
|
||
|
||
[0:14:57 → 0:14:59]
|
||
состояние заполняется этим планом.
|
||
|
||
[0:15:00 → 0:15:02]
|
||
Я прохожусь внутри плана
|
||
|
||
[0:15:02 → 0:15:03]
|
||
по всем слайдам и просто
|
||
|
||
[0:15:03 → 0:15:04]
|
||
генерирую ID.
|
||
|
||
[0:15:05 → 0:15:06]
|
||
Давайте дальше.
|
||
|
||
[0:15:06 → 0:15:09]
|
||
Нам нужно принять решение, куда пойти.
|
||
|
||
[0:15:09 → 0:15:10]
|
||
Либо на веб-ресерч,
|
||
|
||
[0:15:10 → 0:15:12]
|
||
либо на генерацию.
|
||
|
||
[0:15:13 → 0:15:15]
|
||
То есть нам нужно пройтись
|
||
|
||
[0:15:15 → 0:15:17]
|
||
по плану, по всем слайдам
|
||
|
||
[0:15:17 → 0:15:19]
|
||
и найти, есть ли такие слайды,
|
||
|
||
[0:15:19 → 0:15:21]
|
||
для которых есть промт поиска в интернете.
|
||
|
||
[0:15:21 → 0:15:22]
|
||
Для этого используется
|
||
|
||
[0:15:23 → 0:15:25]
|
||
Conditional Edge, так называемый.
|
||
|
||
[0:15:25 → 0:15:27]
|
||
Что это такое
|
||
|
||
[0:15:27 → 0:15:28]
|
||
Conditional Edge?
|
||
|
||
[0:15:29 → 0:15:31]
|
||
Тоже функция, она тоже принимает состояние,
|
||
|
||
[0:15:31 → 0:15:32]
|
||
но у нее задача вернуть
|
||
|
||
[0:15:32 → 0:15:34]
|
||
не апдейт состояния,
|
||
|
||
[0:15:34 → 0:15:35]
|
||
а куда пойти дальше.
|
||
|
||
[0:15:36 → 0:15:38]
|
||
И здесь я создаю
|
||
|
||
[0:15:40 → 0:15:42]
|
||
массив, куда можно пойти
|
||
|
||
[0:15:42 → 0:15:44]
|
||
после работы этой
|
||
|
||
[0:15:44 → 0:15:45]
|
||
предыдущей ноды.
|
||
|
||
[0:15:46 → 0:15:47]
|
||
И либо его заполняю,
|
||
|
||
[0:15:48 → 0:15:49]
|
||
либо, если он не заполнен, мы идем на exit.
|
||
|
||
[0:15:50 → 0:15:51]
|
||
Exit в данном случае имеется ввиду
|
||
|
||
[0:15:51 → 0:15:53]
|
||
пойти на to generate, то есть
|
||
|
||
[0:15:53 → 0:15:54]
|
||
презентацию генерировать,
|
||
|
||
[0:15:54 → 0:15:57]
|
||
как будто в поиск не потребовался.
|
||
|
||
[0:15:59 → 0:16:00]
|
||
Массив send-off я создаю
|
||
|
||
[0:16:00 → 0:16:01]
|
||
пустым,
|
||
|
||
[0:16:01 → 0:16:02]
|
||
а потом пытаюсь его заполнить.
|
||
|
||
[0:16:02 → 0:16:04]
|
||
Я пробегаюсь по всем слайдам,
|
||
|
||
[0:16:04 → 0:16:06]
|
||
ищу слайды, у которых заполнен
|
||
|
||
[0:16:06 → 0:16:07]
|
||
ключ websearch query.
|
||
|
||
[0:16:08 → 0:16:10]
|
||
На этапе планирования,
|
||
|
||
[0:16:10 → 0:16:11]
|
||
напомню, это происходит.
|
||
|
||
[0:16:11 → 0:16:13]
|
||
И если такой слайд нашелся,
|
||
|
||
[0:16:13 → 0:16:15]
|
||
то я его помещаю в push,
|
||
|
||
[0:16:16 → 0:16:18]
|
||
в sends, массив send-off,
|
||
|
||
[0:16:18 → 0:16:19]
|
||
ну и заполняю
|
||
|
||
[0:16:19 → 0:16:22]
|
||
с помощью специального класса send.
|
||
|
||
[0:16:23 → 0:16:26]
|
||
Send передается, какую ноду надо запустить,
|
||
|
||
[0:16:26 → 0:16:28]
|
||
в данном случае webresearch называется нода,
|
||
|
||
[0:16:28 → 0:16:29]
|
||
и какие данные в него прокинуть.
|
||
|
||
[0:16:30 → 0:16:31]
|
||
Можно прокидывать
|
||
|
||
[0:16:31 → 0:16:32]
|
||
хоть все состояние,
|
||
|
||
[0:16:32 → 0:16:34]
|
||
но довольно удобно
|
||
|
||
[0:16:34 → 0:16:36]
|
||
прокидывать только то, что нужно.
|
||
|
||
[0:16:36 → 0:16:38]
|
||
Например, один слайд, с которым
|
||
|
||
[0:16:38 → 0:16:40]
|
||
эта нода для research
|
||
|
||
[0:16:40 → 0:16:42]
|
||
будет работать. Ей, в общем-то, нужен
|
||
|
||
[0:16:42 → 0:16:44]
|
||
только websearch query, но чтобы сохранить
|
||
|
||
[0:16:44 → 0:16:46]
|
||
в состоянии информацию, понадобится
|
||
|
||
[0:16:46 → 0:16:48]
|
||
id-шник слайда, ну, в общем, проще
|
||
|
||
[0:16:48 → 0:16:50]
|
||
передать туда целиком слайд.
|
||
|
||
[0:16:50 → 0:16:52]
|
||
Внутри она считает id-шник и
|
||
|
||
[0:16:52 → 0:16:54]
|
||
websearch query. Как будет
|
||
|
||
[0:16:54 → 0:16:56]
|
||
websearch query работать? В общем-то,
|
||
|
||
[0:16:56 → 0:16:58]
|
||
есть разные способы, как
|
||
|
||
[0:16:58 → 0:17:00]
|
||
поискать в интернете, можно даже
|
||
|
||
[0:17:00 → 0:17:02]
|
||
самостоятельно написать краулер,
|
||
|
||
[0:17:02 → 0:17:04]
|
||
какой-нибудь, но я воспользовался
|
||
|
||
[0:17:04 → 0:17:06]
|
||
удобной утилитой Tavili,
|
||
|
||
[0:17:06 → 0:17:08]
|
||
которая позволяет искать
|
||
|
||
[0:17:08 → 0:17:09]
|
||
в интернете.
|
||
|
||
[0:17:10 → 0:17:12]
|
||
Вот напомню, что в Send мы отправляли
|
||
|
||
[0:17:12 → 0:17:14]
|
||
один слайд, поэтому
|
||
|
||
[0:17:14 → 0:17:16]
|
||
здесь функция принимает тоже
|
||
|
||
[0:17:16 → 0:17:17]
|
||
один слайд.
|
||
|
||
[0:17:18 → 0:17:20]
|
||
Внутри я инициирую этот
|
||
|
||
[0:17:20 → 0:17:22]
|
||
инструмент Tavili,
|
||
|
||
[0:17:22 → 0:17:24]
|
||
ну, а затем просто из слайда
|
||
|
||
[0:17:24 → 0:17:26]
|
||
беру websearch query и, в общем,
|
||
|
||
[0:17:26 → 0:17:28]
|
||
иду искать и жду, пока этот
|
||
|
||
[0:17:28 → 0:17:30]
|
||
инструмент мне найдет то, что нужно.
|
||
|
||
[0:17:31 → 0:17:32]
|
||
Затем я обновляю
|
||
|
||
[0:17:32 → 0:17:34]
|
||
состояние, специально
|
||
|
||
[0:17:34 → 0:17:36]
|
||
созданный для этого ключик
|
||
|
||
[0:17:36 → 0:17:38]
|
||
websearch-result, и по id-шнику слайда
|
||
|
||
[0:17:38 → 0:17:40]
|
||
сохраняю информацию, которую нашел в интернете.
|
||
|
||
[0:17:41 → 0:17:42]
|
||
Интересный моментик, вот с фигурными
|
||
|
||
[0:17:42 → 0:17:44]
|
||
скобками, если создавать презентации
|
||
|
||
[0:17:44 → 0:17:46]
|
||
на какие-то темы для программистов,
|
||
|
||
[0:17:46 → 0:17:48]
|
||
там наверняка будут блоки кода, блоки кода
|
||
|
||
[0:17:48 → 0:17:50]
|
||
содержат фигурные скобки, а лонгчейн
|
||
|
||
[0:17:50 → 0:17:52]
|
||
воспринимает фигурные скобки как
|
||
|
||
[0:17:52 → 0:17:54]
|
||
часть темплейта, которую надо заполнить
|
||
|
||
[0:17:54 → 0:17:56]
|
||
какими-то данными, и
|
||
|
||
[0:17:56 → 0:17:57]
|
||
будет ругаться, что
|
||
|
||
[0:17:58 → 0:18:00]
|
||
вы не предоставили мне данные
|
||
|
||
[0:18:00 → 0:18:02]
|
||
для заполнения этого ключа.
|
||
|
||
[0:18:03 → 0:18:04]
|
||
Поэтому я их
|
||
|
||
[0:18:05 → 0:18:06]
|
||
экранирую, я нахожу фигурные
|
||
|
||
[0:18:06 → 0:18:08]
|
||
скобки и
|
||
|
||
[0:18:08 → 0:18:10]
|
||
делаю двойными фигурными скобками,
|
||
|
||
[0:18:10 → 0:18:13]
|
||
в общем-то это способ заэкранировать
|
||
|
||
[0:18:13 → 0:18:13]
|
||
их.
|
||
|
||
[0:18:14 → 0:18:16]
|
||
Вот и все, то есть точно так же,
|
||
|
||
[0:18:17 → 0:18:18]
|
||
как и в prepare, в общем
|
||
|
||
[0:18:18 → 0:18:20]
|
||
я что-то делаю и кладу это
|
||
|
||
[0:18:20 → 0:18:22]
|
||
в состояние. Далее нам
|
||
|
||
[0:18:22 → 0:18:24]
|
||
надо принять решение, то есть мы, понятно,
|
||
|
||
[0:18:24 → 0:18:26]
|
||
уже идем на generate, и далее
|
||
|
||
[0:18:26 → 0:18:28]
|
||
надо понять, хотим ли мы сгенерировать
|
||
|
||
[0:18:28 → 0:18:31]
|
||
картинки или начинаем контент генерировать.
|
||
|
||
[0:18:32 → 0:18:34]
|
||
Что здесь происходит? Это тоже
|
||
|
||
[0:18:34 → 0:18:37]
|
||
роутер, он тоже принимает состояние
|
||
|
||
[0:18:37 → 0:18:38]
|
||
и должен вернуть, куда идем дальше.
|
||
|
||
[0:18:39 → 0:18:41]
|
||
Точно так же работает с массивом
|
||
|
||
[0:18:41 → 0:18:42]
|
||
sendов. Здесь есть
|
||
|
||
[0:18:42 → 0:18:44]
|
||
вот такой цикл,
|
||
|
||
[0:18:44 → 0:18:46]
|
||
я пробегаюсь по слайдам,
|
||
|
||
[0:18:47 → 0:18:48]
|
||
по каждому из них, потом
|
||
|
||
[0:18:48 → 0:18:50]
|
||
смотрю, есть ли там prompt на генерацию
|
||
|
||
[0:18:50 → 0:18:53]
|
||
изображения, и массив sendов заполняю
|
||
|
||
[0:18:53 → 0:18:54]
|
||
опять экземпляром класса
|
||
|
||
[0:18:54 → 0:18:56]
|
||
send, название нода, куда
|
||
|
||
[0:18:56 → 0:18:58]
|
||
нужно пойти, и информация, которая
|
||
|
||
[0:18:58 → 0:19:01]
|
||
нужна для генерации. Это слайд
|
||
|
||
[0:19:01 → 0:19:02]
|
||
с его image prompt и negative
|
||
|
||
[0:19:02 → 0:19:05]
|
||
image prompt, и также глобальный
|
||
|
||
[0:19:05 → 0:19:07]
|
||
стиль изображения, который тоже надо учесть,
|
||
|
||
[0:19:07 → 0:19:09]
|
||
чтобы во всей презентации
|
||
|
||
[0:19:09 → 0:19:11]
|
||
и во всех слайдах стили изображения
|
||
|
||
[0:19:11 → 0:19:12]
|
||
были в едином стиле.
|
||
|
||
[0:19:13 → 0:19:14]
|
||
Вот. Ну,
|
||
|
||
[0:19:14 → 0:19:16]
|
||
как генерировать картинки?
|
||
|
||
[0:19:16 → 0:19:18]
|
||
Я думаю, вы знаете, что есть
|
||
|
||
[0:19:18 → 0:19:20]
|
||
такая у нас нероссеть Кандинский,
|
||
|
||
[0:19:20 → 0:19:22]
|
||
которая умеет изображения генерировать,
|
||
|
||
[0:19:22 → 0:19:24]
|
||
и у нее недавно появилась такая кнопочка API
|
||
|
||
[0:19:24 → 0:19:25]
|
||
позволяющая
|
||
|
||
[0:19:27 → 0:19:29]
|
||
взаимодействовать программным способом
|
||
|
||
[0:19:29 → 0:19:31]
|
||
с Кандинским и генерировать изображения
|
||
|
||
[0:19:31 → 0:19:31]
|
||
изображения.
|
||
|
||
[0:19:33 → 0:19:34]
|
||
Ну, не стану
|
||
|
||
[0:19:35 → 0:19:36]
|
||
врать, в общем, кода получилось много,
|
||
|
||
[0:19:36 → 0:19:38]
|
||
здесь он вроде бы
|
||
|
||
[0:19:38 → 0:19:40]
|
||
даже весь. Я написал
|
||
|
||
[0:19:40 → 0:19:42]
|
||
обертку для работы с API
|
||
|
||
[0:19:44 → 0:19:44]
|
||
Кандинского,
|
||
|
||
[0:19:44 → 0:19:45]
|
||
назвал его собачка-броджия
|
||
|
||
[0:19:45 → 0:19:48]
|
||
это чисто обертка
|
||
|
||
[0:19:48 → 0:19:50]
|
||
над API,
|
||
|
||
[0:19:50 → 0:19:52]
|
||
позволяющая чуть более удобно с ней работать,
|
||
|
||
[0:19:52 → 0:19:54]
|
||
но даже с учетом такой обертки
|
||
|
||
[0:19:55 → 0:19:56]
|
||
кода получилось много.
|
||
|
||
[0:19:56 → 0:19:58]
|
||
Моя обертка над API
|
||
|
||
[0:19:59 → 0:19:59]
|
||
Кандинский
|
||
|
||
[0:20:01 → 0:20:02]
|
||
насосная, в общем, ее можно найти
|
||
|
||
[0:20:02 → 0:20:03]
|
||
на Gitverse,
|
||
|
||
[0:20:04 → 0:20:06]
|
||
если интересно, можете попробовать.
|
||
|
||
[0:20:08 → 0:20:08]
|
||
Внутри я просто
|
||
|
||
[0:20:08 → 0:20:10]
|
||
смотрю, что некоторые слайды
|
||
|
||
[0:20:10 → 0:20:11]
|
||
я хочу квадратные,
|
||
|
||
[0:20:12 → 0:20:14]
|
||
один к одному, иногда 16 к 9,
|
||
|
||
[0:20:14 → 0:20:16]
|
||
в зависимости от того, какой слайд.
|
||
|
||
[0:20:16 → 0:20:18]
|
||
В общем, сохраняю изображение в файловой
|
||
|
||
[0:20:18 → 0:20:20]
|
||
системе и сохраняю в состоянии
|
||
|
||
[0:20:20 → 0:20:22]
|
||
ссылку на это изображение.
|
||
|
||
[0:20:23 → 0:20:24]
|
||
В общем-то и все.
|
||
|
||
[0:20:25 → 0:20:26]
|
||
Идем дальше.
|
||
|
||
[0:20:26 → 0:20:29]
|
||
Ну, наконец-то, генерация контента.
|
||
|
||
[0:20:29 → 0:20:30]
|
||
Как же сгенерировать контент?
|
||
|
||
[0:20:31 → 0:20:32]
|
||
В общем-то, контент мне нужен, в принципе,
|
||
|
||
[0:20:32 → 0:20:35]
|
||
в Markdown, который я на UI
|
||
|
||
[0:20:35 → 0:20:36]
|
||
потом смогу красиво
|
||
|
||
[0:20:37 → 0:20:37]
|
||
отображать.
|
||
|
||
[0:20:38 → 0:20:40]
|
||
Я принял такое решение.
|
||
|
||
[0:20:40 → 0:20:42]
|
||
Но тут есть интересный момент.
|
||
|
||
[0:20:42 → 0:20:44]
|
||
Когда мы идем генерировать такие уже
|
||
|
||
[0:20:44 → 0:20:46]
|
||
более сложные вещи, мы будем
|
||
|
||
[0:20:46 → 0:20:48]
|
||
пользоваться блокчейном, и для начала
|
||
|
||
[0:20:48 → 0:20:50]
|
||
нам понадобится системный промт,
|
||
|
||
[0:20:50 → 0:20:51]
|
||
где мы описываем,
|
||
|
||
[0:20:52 → 0:20:53]
|
||
что мы сейчас будем генерировать.
|
||
|
||
[0:20:53 → 0:20:56]
|
||
Значит, слайды, контент для слайдов,
|
||
|
||
[0:20:56 → 0:20:58]
|
||
там внутри,
|
||
|
||
[0:20:59 → 0:21:00]
|
||
имея в виду, что на слайде
|
||
|
||
[0:21:01 → 0:21:02]
|
||
очень много текста влезает,
|
||
|
||
[0:21:02 → 0:21:03]
|
||
нам нужны какие-то буллеты,
|
||
|
||
[0:21:03 → 0:21:05]
|
||
ну, в общем, какое-то описание, как мы видим
|
||
|
||
[0:21:06 → 0:21:08]
|
||
генерацию этих контента для слайда.
|
||
|
||
[0:21:09 → 0:21:10]
|
||
Это системный промт.
|
||
|
||
[0:21:10 → 0:21:12]
|
||
Потом мы досылаем туда
|
||
|
||
[0:21:13 → 0:21:14]
|
||
запрос. Вот данные, сгенерируй
|
||
|
||
[0:21:14 → 0:21:15]
|
||
контент для слайда.
|
||
|
||
[0:21:16 → 0:21:18]
|
||
То есть, вот результат поиска в интернете
|
||
|
||
[0:21:18 → 0:21:20]
|
||
мы туда дописываем,
|
||
|
||
[0:21:20 → 0:21:23]
|
||
о чем у нас был этот слайд
|
||
|
||
[0:21:23 → 0:21:25]
|
||
на этапе планирования
|
||
|
||
[0:21:25 → 0:21:26]
|
||
названия, там буллеты,
|
||
|
||
[0:21:26 → 0:21:28]
|
||
в общем, все, что надо уже для слайда,
|
||
|
||
[0:21:28 → 0:21:30]
|
||
готовое мы туда складываем,
|
||
|
||
[0:21:30 → 0:21:31]
|
||
вот, сгенерируй нам, пожалуйста, слайд.
|
||
|
||
[0:21:32 → 0:21:33]
|
||
Нейросеть нам отвечает.
|
||
|
||
[0:21:33 → 0:21:35]
|
||
Хорошо, вот контент. И в Markdown, значит,
|
||
|
||
[0:21:35 → 0:21:36]
|
||
отдает контент.
|
||
|
||
[0:21:38 → 0:21:39]
|
||
После чего
|
||
|
||
[0:21:39 → 0:21:41]
|
||
мне хочется пойти немножко дальше
|
||
|
||
[0:21:41 → 0:21:43]
|
||
и сгенерировать не только контент,
|
||
|
||
[0:21:43 → 0:21:46]
|
||
но и описание, о чем этот слайд,
|
||
|
||
[0:21:46 → 0:21:47]
|
||
о чем думала нейросеть,
|
||
|
||
[0:21:48 → 0:21:49]
|
||
создавая этот слайд,
|
||
|
||
[0:21:49 → 0:21:51]
|
||
и о чем надо, собственно, рассказывать
|
||
|
||
[0:21:52 → 0:21:54]
|
||
тому, кто будет
|
||
|
||
[0:21:55 → 0:21:56]
|
||
презентацию показывать
|
||
|
||
[0:21:56 → 0:21:58]
|
||
и рассказывать что-то по ней.
|
||
|
||
[0:21:58 → 0:21:59]
|
||
Поэтому я решил
|
||
|
||
[0:21:59 → 0:22:01]
|
||
сделать так, что мне нужно пойти
|
||
|
||
[0:22:01 → 0:22:04]
|
||
в нейросеть и попросить ее сгенерировать.
|
||
|
||
[0:22:04 → 0:22:04]
|
||
Пожалуйста, теперь
|
||
|
||
[0:22:06 → 0:22:08]
|
||
комментарий для этого слайда,
|
||
|
||
[0:22:08 → 0:22:10]
|
||
где опиши, что рассказывать.
|
||
|
||
[0:22:10 → 0:22:12]
|
||
Я мог бы отдельно
|
||
|
||
[0:22:12 → 0:22:13]
|
||
создать для этого системный промт,
|
||
|
||
[0:22:13 → 0:22:16]
|
||
отдельно там запрос сделать,
|
||
|
||
[0:22:16 → 0:22:16]
|
||
но я делаю так.
|
||
|
||
[0:22:17 → 0:22:19]
|
||
В массив сообщений, которые
|
||
|
||
[0:22:20 → 0:22:21]
|
||
мне получился,
|
||
|
||
[0:22:21 → 0:22:23]
|
||
там системный промт изначальный,
|
||
|
||
[0:22:23 → 0:22:25]
|
||
первый запрос на генерацию
|
||
|
||
[0:22:26 → 0:22:28]
|
||
контента я тоже туда дописываю,
|
||
|
||
[0:22:28 → 0:22:29]
|
||
ответ нейросети хорошо,
|
||
|
||
[0:22:30 → 0:22:32]
|
||
контент я тоже в этот массив сообщений
|
||
|
||
[0:22:32 → 0:22:34]
|
||
складываю и далее добавляю
|
||
|
||
[0:22:34 → 0:22:35]
|
||
еще один запрос.
|
||
|
||
[0:22:35 → 0:22:37]
|
||
Теперь, пожалуйста, добавь комментарий для спикера.
|
||
|
||
[0:22:39 → 0:22:41]
|
||
Потом нейросеть не отвечает
|
||
|
||
[0:22:41 → 0:22:43]
|
||
и это получается уже
|
||
|
||
[0:22:43 → 0:22:46]
|
||
пятый элемент массива сообщений.
|
||
|
||
[0:22:46 → 0:22:48]
|
||
То есть я сохраняю себе
|
||
|
||
[0:22:48 → 0:22:49]
|
||
этот комментарий и далее
|
||
|
||
[0:22:49 → 0:22:52]
|
||
для следующих слайдов я поступаю точно так же.
|
||
|
||
[0:22:52 → 0:22:53]
|
||
Я донаращиваю
|
||
|
||
[0:22:54 → 0:22:55]
|
||
общий массив сообщений
|
||
|
||
[0:22:56 → 0:22:57]
|
||
при генерации контента
|
||
|
||
[0:22:57 → 0:22:59]
|
||
для всех слайдов всей презентации.
|
||
|
||
[0:23:00 → 0:23:02]
|
||
Получается, что у меня как бы
|
||
|
||
[0:23:02 → 0:23:04]
|
||
есть история общения с нейросетью,
|
||
|
||
[0:23:04 → 0:23:06]
|
||
где дописываются новые сообщения
|
||
|
||
[0:23:06 → 0:23:07]
|
||
и ее новые ответы
|
||
|
||
[0:23:07 → 0:23:08]
|
||
на мои сообщения.
|
||
|
||
[0:23:09 → 0:23:11]
|
||
Таким образом, если для
|
||
|
||
[0:23:11 → 0:23:13]
|
||
презентации нужно, чтобы мысль
|
||
|
||
[0:23:13 → 0:23:15]
|
||
как-то последовательно развивалась,
|
||
|
||
[0:23:15 → 0:23:17]
|
||
я сохраняю контекст предыдущих слайдов,
|
||
|
||
[0:23:17 → 0:23:19]
|
||
чтобы следующие при генерации
|
||
|
||
[0:23:19 → 0:23:20]
|
||
учитывали этот контекст.
|
||
|
||
[0:23:21 → 0:23:23]
|
||
При общении с нейросетью
|
||
|
||
[0:23:23 → 0:23:24]
|
||
у нас есть такая возможность
|
||
|
||
[0:23:24 → 0:23:27]
|
||
отправлять туда массив сообщений.
|
||
|
||
[0:23:27 → 0:23:29]
|
||
Надо просто помечать,
|
||
|
||
[0:23:29 → 0:23:30]
|
||
какой из них системный,
|
||
|
||
[0:23:30 → 0:23:31]
|
||
какой от пользователя,
|
||
|
||
[0:23:31 → 0:23:33]
|
||
а какой ответ от AI.
|
||
|
||
[0:23:34 → 0:23:36]
|
||
В общем-то, это и все.
|
||
|
||
[0:23:36 → 0:23:38]
|
||
И потом у нас остается только
|
||
|
||
[0:23:38 → 0:23:41]
|
||
собрать все эти ноды воедино.
|
||
|
||
[0:23:41 → 0:23:42]
|
||
Как это делается?
|
||
|
||
[0:23:43 → 0:23:45]
|
||
Каждая нода это функция.
|
||
|
||
[0:23:45 → 0:23:47]
|
||
Мы должны просто добавить
|
||
|
||
[0:23:47 → 0:23:48]
|
||
в наш State Graph.
|
||
|
||
[0:23:48 → 0:23:50]
|
||
State Graph прокидывается изначально
|
||
|
||
[0:23:50 → 0:23:52]
|
||
состояние, с которым мы хотим начать.
|
||
|
||
[0:23:53 → 0:23:55]
|
||
В этом состоянии можно еще и описать,
|
||
|
||
[0:23:55 → 0:23:56]
|
||
как именно обновляется каждый ключ.
|
||
|
||
[0:23:57 → 0:23:58]
|
||
Редюсеры добавить.
|
||
|
||
[0:23:59 → 0:24:00]
|
||
После чего,
|
||
|
||
[0:24:01 → 0:24:02]
|
||
получившемуся State Graph,
|
||
|
||
[0:24:02 → 0:24:04]
|
||
мы добавляем ноды.
|
||
|
||
[0:24:04 → 0:24:06]
|
||
Мы их как-то должны назвать,
|
||
|
||
[0:24:06 → 0:24:08]
|
||
как вы видели на графе,
|
||
|
||
[0:24:08 → 0:24:10]
|
||
и прокинуть функцию.
|
||
|
||
[0:24:12 → 0:24:13]
|
||
Затем
|
||
|
||
[0:24:13 → 0:24:15]
|
||
нам нужно добавить
|
||
|
||
[0:24:15 → 0:24:16]
|
||
описание, как мы будем
|
||
|
||
[0:24:16 → 0:24:18]
|
||
перемещаться между этими нодами.
|
||
|
||
[0:24:18 → 0:24:20]
|
||
От какой в какую можно пойти,
|
||
|
||
[0:24:20 → 0:24:22]
|
||
где начало и где конец.
|
||
|
||
[0:24:23 → 0:24:24]
|
||
Start это Prepare,
|
||
|
||
[0:24:24 → 0:24:26]
|
||
а Final это End.
|
||
|
||
[0:24:26 → 0:24:28]
|
||
Это означает, что работа
|
||
|
||
[0:24:29 → 0:24:30]
|
||
агента после выполнения
|
||
|
||
[0:24:30 → 0:24:33]
|
||
ноды Final будет завершена,
|
||
|
||
[0:24:33 → 0:24:34]
|
||
и он отдаст нам результат
|
||
|
||
[0:24:35 → 0:24:37]
|
||
генерации презентации.
|
||
|
||
[0:24:37 → 0:24:39]
|
||
Все, потом это дело компилируем.
|
||
|
||
[0:24:39 → 0:24:40]
|
||
В общем, работаем
|
||
|
||
[0:24:41 → 0:24:41]
|
||
с этим.
|
||
|
||
[0:24:43 → 0:24:45]
|
||
Там уже ничего сложного.
|
||
|
||
[0:24:45 → 0:24:47]
|
||
Можно посмотреть,
|
||
|
||
[0:24:47 → 0:24:49]
|
||
вот такая презентация
|
||
|
||
[0:24:49 → 0:24:51]
|
||
получилась на моем сервисе.
|
||
|
||
[0:24:51 → 0:24:53]
|
||
Можно тоже сходить
|
||
|
||
[0:24:53 → 0:24:55]
|
||
и попробовать посмотреть,
|
||
|
||
[0:24:55 → 0:24:56]
|
||
как они генерируются.
|
||
|
||
[0:24:57 → 0:24:59]
|
||
Вот такую презентацию
|
||
|
||
[0:24:59 → 0:25:01]
|
||
я сгенерировал.
|
||
|
||
[0:25:01 → 0:25:03]
|
||
Как видно, тут примерно
|
||
|
||
[0:25:03 → 0:25:05]
|
||
о том же.
|
||
|
||
[0:25:05 → 0:25:06]
|
||
В общем, тоже изображение
|
||
|
||
[0:25:06 → 0:25:07]
|
||
в едином стиле,
|
||
|
||
[0:25:07 → 0:25:10]
|
||
и на моем сайте можно
|
||
|
||
[0:25:11 → 0:25:12]
|
||
проиграть презентацию.
|
||
|
||
[0:25:13 → 0:25:14]
|
||
В общем,
|
||
|
||
[0:25:15 → 0:25:16]
|
||
это и все.
|
||
|
||
[0:25:17 → 0:25:18]
|
||
Основной вывод
|
||
|
||
[0:25:18 → 0:25:20]
|
||
это нужно пробовать,
|
||
|
||
[0:25:20 → 0:25:22]
|
||
делать это не какой-то
|
||
|
||
[0:25:22 → 0:25:23]
|
||
rocket science,
|
||
|
||
[0:25:24 → 0:25:26]
|
||
не только для ML
|
||
|
||
[0:25:26 → 0:25:28]
|
||
инженеров,
|
||
|
||
[0:25:28 → 0:25:29]
|
||
специалистов.
|
||
|
||
[0:25:29 → 0:25:31]
|
||
Сейчас я фронт-энд разработчик
|
||
|
||
[0:25:31 → 0:25:32]
|
||
в основном,
|
||
|
||
[0:25:32 → 0:25:34]
|
||
сделал вот такую вещь.
|
||
|
||
[0:25:35 → 0:25:37]
|
||
Соответственно, когда объединяются команды,
|
||
|
||
[0:25:37 → 0:25:39]
|
||
можно делать вещи более сложные
|
||
|
||
[0:25:39 → 0:25:40]
|
||
и интересные.
|
||
|
||
[0:25:40 → 0:25:43]
|
||
Это дело развивается очень интенсивно,
|
||
|
||
[0:25:44 → 0:25:46]
|
||
и всем стоит попробовать
|
||
|
||
[0:25:46 → 0:25:47]
|
||
залезть, посмотреть,
|
||
|
||
[0:25:47 → 0:25:49]
|
||
как эти вещи создаются,
|
||
|
||
[0:25:50 → 0:25:51]
|
||
может быть, создать что-то
|
||
|
||
[0:25:52 → 0:25:53]
|
||
крутое и интересное.
|
||
|
||
[0:25:53 → 0:25:56]
|
||
В любом случае, вы все,
|
||
|
||
[0:25:56 → 0:25:58]
|
||
кто это смотрит, слушает, читает,
|
||
|
||
[0:25:58 → 0:25:59]
|
||
будете
|
||
|
||
[0:26:00 → 0:26:02]
|
||
участвовать в разработке
|
||
|
||
[0:26:02 → 0:26:04]
|
||
чего-то, что связано и агентами.
|
||
|
||
[0:26:04 → 0:26:05]
|
||
Это уже неизбежно.
|
||
|
||
[0:26:06 → 0:26:08]
|
||
И я думаю, всем стоит
|
||
|
||
[0:26:08 → 0:26:10]
|
||
попробовать самостоятельно
|
||
|
||
[0:26:10 → 0:26:11]
|
||
эту историю поговорить,
|
||
|
||
[0:26:12 → 0:26:14]
|
||
чтобы, по крайней мере,
|
||
|
||
[0:26:14 → 0:26:15]
|
||
если даже вам эта идея не нравится,
|
||
|
||
[0:26:16 → 0:26:17]
|
||
просто быть знакомым
|
||
|
||
[0:26:17 → 0:26:19]
|
||
с тем, как такие вещи создаются.
|
||
|
||
[0:26:20 → 0:26:21]
|
||
Вот.
|
||
|
||
[0:26:21 → 0:26:23]
|
||
По QR-коду доступно
|
||
|
||
[0:26:23 → 0:26:25]
|
||
собственно мое приложение,
|
||
|
||
[0:26:25 → 0:26:27]
|
||
которое генерирует презентации,
|
||
|
||
[0:26:27 → 0:26:29]
|
||
но понятно, что генерация завязана
|
||
|
||
[0:26:29 → 0:26:32]
|
||
на потребление токенов,
|
||
|
||
[0:26:32 → 0:26:33]
|
||
которые стоят денег,
|
||
|
||
[0:26:33 → 0:26:35]
|
||
поэтому какое-то время
|
||
|
||
[0:26:35 → 0:26:36]
|
||
оно может быть доступно,
|
||
|
||
[0:26:36 → 0:26:38]
|
||
но потом я отключу.
|
||
|
||
[0:26:39 → 0:26:41]
|
||
На этом спасибо
|
||
|
||
[0:26:42 → 0:26:43]
|
||
и всем пока.
|