Поборовшись с проблемой выбора, вкупе с боязнью чистого листа канала, решил, что в первом посте отвечу на пару вопросов, которые мне конечно же никто не задавал, но мог бы, во-первых, и наверняка задаст в будущем, во-вторых. Не исключено также, что этот пост в дальнейшем будет обновляться.
Q: Почему личный канал, а не посты в POSIdev, организатором которого ты являешься?
A: Канал POSIdev (подписывайтесь кстати), в настоящее время — ресурс вполне конкретного сообщества, ассоциируемый с моей компанией-работодателем, и преследующий вполне конкретные цели, направленные на продвижение в массы культуры разработки качественного кода. Любой авторский пост там будет восприниматься, как выражение позиции, если не компании или сообщества, то как минимум — его организатора. И, должен заметить, что нынешний дефицит контента там, возможно, во многом связан именно с этим фактом.
Здесь же — я не ставлю перед собой задачу выражать чьи-либо позиции, кроме своей собственной, как и развивать ещё одно сообщество, что-то продвигать и т.п. Этот канал я рассматриваю, как площадку для шаринга каких-либо личных мыслей, идей и рассуждений вокруг своей профессиональной области, причем далеко не только про написание качественного кода. Но посты, во всех смыслах соответствующие формату POSIdev, и определённо интересные его аудитории, возможно буду размещать и там. По крайней мере, пока на том канале не начнет на регулярной основе появляться уникальный контент, и с учетом приведенных выше оговорок.
Q: Можно ли использовать материалы этого канала в сторонних ресурсах или проектах?
A: Коротко: да, без ограничений, с указанием авторства и адреса этого канала. Если нужно более формально: весь авторский код, если не указано иное, распространяется по лицензии MIT, весь прочий оригинальный контент, если не указано иное — по лицензии CC BY v4.0.
Как-то так😍
Q: Почему личный канал, а не посты в POSIdev, организатором которого ты являешься?
A: Канал POSIdev (подписывайтесь кстати), в настоящее время — ресурс вполне конкретного сообщества, ассоциируемый с моей компанией-работодателем, и преследующий вполне конкретные цели, направленные на продвижение в массы культуры разработки качественного кода. Любой авторский пост там будет восприниматься, как выражение позиции, если не компании или сообщества, то как минимум — его организатора. И, должен заметить, что нынешний дефицит контента там, возможно, во многом связан именно с этим фактом.
Здесь же — я не ставлю перед собой задачу выражать чьи-либо позиции, кроме своей собственной, как и развивать ещё одно сообщество, что-то продвигать и т.п. Этот канал я рассматриваю, как площадку для шаринга каких-либо личных мыслей, идей и рассуждений вокруг своей профессиональной области, причем далеко не только про написание качественного кода. Но посты, во всех смыслах соответствующие формату POSIdev, и определённо интересные его аудитории, возможно буду размещать и там. По крайней мере, пока на том канале не начнет на регулярной основе появляться уникальный контент, и с учетом приведенных выше оговорок.
Q: Можно ли использовать материалы этого канала в сторонних ресурсах или проектах?
A: Коротко: да, без ограничений, с указанием авторства и адреса этого канала. Если нужно более формально: весь авторский код, если не указано иное, распространяется по лицензии MIT, весь прочий оригинальный контент, если не указано иное — по лицензии CC BY v4.0.
Как-то так
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👌3👨💻2⚡1🆒1
MiniMax Agent, или — как проср... потратить $69 на чужие ошибки.
За последние пару дней провёл ~20 часов, исследуя возможности MiniMax Agent. Казалось бы, отличные результаты на мелких задачах: кодинг простых скриптиков, ресёрч технологий — бодро, чётко. А потом бесплатные кредиты закончились, а я решил сделать что-то посложнее🤕
Первый фейл. Захотел парсинг видео с YouTube для написания статьи. По ссылке на видос — провал. Загруженное, в 720p — провал (слишком большой). В 320p — тоже провал (видимо, теперь слишком шакальный). Только когда подсунул текстовую транскрипцию видоса и PDF со слайдами оттуда, оно хоть что-то соизволило сгенерить. Итог: по 2–3 обрывочных предложения на слайд и куча скипнутой из доклада инфы. Ну и минус ~500 кредитов ещё.
Второй фейл. Попросил сгенерить копию сайта posidev.io с фронтом на TypeScript и бэком на Go. Минус ~1.5k. Результат: ничего не работает. TS-часть ещё можно было бы допилить вручную, но Go'шный бэк — это просто ад кромешный: ошибки типов, поломанные контракты, недостающие куски кода. И неспособность Minimax исправить это за несколько итераций. Руками — даже пытаться править не стал.
Третий фейл. Desktop headless-приложение: иконка в трее, меню, настройки, простая логика. Я честно попытался — выделил плюс-минус по 5k кредитов на каждую из трёх реализаций: Python, Go, C#.
🐍 Уже на стадии зависимостей всё развалилось: версии транзитивок оказались несовместимы. Агент, на какой-то из итераций правки этой проблемы, самовольно заменил библиотеки на совершенно другие, и выдал проект, в котором одна половина кодовой базы работает на старом наборе зависимостей, другая — на новом. Запустить не смог. Я — тоже.
🥰 Внезапно, в десктоп-приложении появился фронт на TypeScript. С системным треем в качестве бэка на будущее, видимо. Причем, это часть даже работала — в отличие от всего остального. Во фронт он, наверное, умеет лучше. С интерфейсами в Go агент явно не дружит, при попытках исправить ошибки компилятора генерил по пачке новых. Ничего не собралось, даже с моими подсказками и ручными правками.
😀 Ошибки в работе с async-методами, проблемы с интерфейсами (видимо эта боль у него тянется через все языки), в зависимостях — уязвимый System.Text.Json. Несколько итераций — и всё равно мимо, даже не собралось. А то, что он натворил с контрактами, вот реально — быстрее и проще было бы с нуля руками переписать.
💸 Итого: -17k кредитов.
Почему я столько раз про них упомянул? Потому что MiniMax продаёт эксперименты по цене продакшена. Будь его агент бесплатным, тон этого поста мог бы оказаться совсем другим. Но где-то на 4–5 улетевшей тысяче кредитов, уже даже такой тугоум как я, начал подозревать, что плачу своим баблом и временем не за результат, а за проданные ранее мне же чужие ошибки. Не жалуюсь, тут всё как в жизни, ок. Но подписку продлевать не стану. Оставшиеся кредиты потрачу на ресёрч без кода — тут MiniMax ещё кое-как справляется (но это не точно).
А для всего остального есть GPT с его Codex'ом, Cursor, DeepSeek и Manus.
За последние пару дней провёл ~20 часов, исследуя возможности MiniMax Agent. Казалось бы, отличные результаты на мелких задачах: кодинг простых скриптиков, ресёрч технологий — бодро, чётко. А потом бесплатные кредиты закончились, а я решил сделать что-то посложнее
Первый фейл. Захотел парсинг видео с YouTube для написания статьи. По ссылке на видос — провал. Загруженное, в 720p — провал (слишком большой). В 320p — тоже провал (видимо, теперь слишком шакальный). Только когда подсунул текстовую транскрипцию видоса и PDF со слайдами оттуда, оно хоть что-то соизволило сгенерить. Итог: по 2–3 обрывочных предложения на слайд и куча скипнутой из доклада инфы. Ну и минус ~500 кредитов ещё.
Второй фейл. Попросил сгенерить копию сайта posidev.io с фронтом на TypeScript и бэком на Go. Минус ~1.5k. Результат: ничего не работает. TS-часть ещё можно было бы допилить вручную, но Go'шный бэк — это просто ад кромешный: ошибки типов, поломанные контракты, недостающие куски кода. И неспособность Minimax исправить это за несколько итераций. Руками — даже пытаться править не стал.
Третий фейл. Desktop headless-приложение: иконка в трее, меню, настройки, простая логика. Я честно попытался — выделил плюс-минус по 5k кредитов на каждую из трёх реализаций: Python, Go, C#.
💸 Итого: -17k кредитов.
Почему я столько раз про них упомянул? Потому что MiniMax продаёт эксперименты по цене продакшена. Будь его агент бесплатным, тон этого поста мог бы оказаться совсем другим. Но где-то на 4–5 улетевшей тысяче кредитов, уже даже такой тугоум как я, начал подозревать, что плачу своим баблом и временем не за результат, а за проданные ранее мне же чужие ошибки. Не жалуюсь, тут всё как в жизни, ок. Но подписку продлевать не стану. Оставшиеся кредиты потрачу на ресёрч без кода — тут MiniMax ещё кое-как справляется (но это не точно).
А для всего остального есть GPT с его Codex'ом, Cursor, DeepSeek и Manus.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4👨💻2
Forwarded from Positive Technologies
Попросили рассказать об этом подробнее наших коллег-экспертов Владимира Кочеткова, Георгия Александрию, Валерия Пушкаря и Дмитрия Рассадина.
В итоге получилось очень классное и интересное интервью для Positive Research, в котором ребята говорят о своей непростой работе, скилах, без которых в ней не обойтись, процессах и инструментах.
Вы узнаете:
Обо всем этом и многом другом читайте на сайте нашего медиа.
P. S. Кстати, если вы ищете в статье лайфхаки, чтобы попасть в нашу AppSec-команду, вы их найдете.
#PositiveЭксперты #PositiveResearch
@Positive_Technologies
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1🔥1
Не рассчитывал, что тут сходу появятся посты, не влезающие в тележные 4к символов, и впредь обязательно постараюсь быть сдержаннее... но чёт не удержался: https://telegra.ph/Po-sledam-prostrelennyh-nog-v-parserah-Go-i-ne-tolko-06-21
Telegraph
По следам простреленных ног в парсерах Go (и не только)
На днях Trail of Bits разродились в своём блоге статьей Unexpected security footguns in Go's parsers, посвященной не вполне очевидным проблемам, возникающим при парсинге структурированных форматов данных. Если одним предложением, то дизайн парсеров JSON,…
👍1
Каких разработчиков уже заменяет ИИ?
Самое страшное, на мой взгляд, что может произойти с разработчиком — это профессиональная стагнация. Когда он постепенно сужает зону своей ответственности и продуктивность до предела «лишь бы не уволили»: на троечку с плюсом, где только можно. И медленно перестаёт развиваться как профи.
А ИИ ли виноват в том, что им заменяют разработчиков? «На зеркало неча пенять...»
А в зеркале — те самые, которые однажды решили, что их зона ответственности — это не вся система или тем более весь продукт, а три знакомых файла, где они знают, как и что падает, чтобы можно было это чинить, не перегружая мозг ненужными думами.
Которые каждый раз, когда на горизонте появляется что-то новое, делают характерное лицо: «фу, это для зумеров» — а потом пишут свой велосипед, который работает хуже, медленнее и баговее. Потому что «ну ведь работает же», а в новой библиотеке или технологии — это же ещё разобраться надо.
Которые всегда и везде ищут виноватых за пределами своего уютного болотца, а не внутри него.
Которые делают всё, чтобы не принимать решений:
«тут архитектор нужен»,
«пусть лид согласует»,
«не знаю, у меня все работает»,
«этого нет в требованиях, все вопросы к продакту»…
Зато багов меньше. Ну, меньше кода — меньше багов. Всё честно.
А ИИ тем временем тихо справляется со всей этой рутиной — безэмоционально, безропотно и, что особенно обидно, уже примерно на том же уровне качества, что и эти стагнирующие ребята. Только быстрее и дешевле. А иногда — даже без багов. (Но это не точно.)
И вижу здесь некоторую иронию в том, что они сами сделали себя заменяемыми, зажавшись в установке: «меньше ответственности = меньше риска». И теперь удивляются, почему на языке чувствуется привкус чужой пыли.
Из этого можно и нужно выбираться. Через непрерывное саморазвитие, пробу всего нового, любознательность, исследования, пет-проекты, инициативу, креативность, пробы и ошибки. Так же постепенно и без резких телодвижений, как и угораздило там оказаться.
Нет смысла гадать, заменит ли ИИ таких разработчиков. Пока они чиллят в своём уютном изолированном мирке, отрицая очередной, как им кажется, «зумерский хайп», это — лишь вопрос времени.
Им стоит задуматься о том, что деградация зайдёт настолько далеко, что их однажды не позовут даже ревьюить код, написанный ИИшными «руками».
Самое страшное, на мой взгляд, что может произойти с разработчиком — это профессиональная стагнация. Когда он постепенно сужает зону своей ответственности и продуктивность до предела «лишь бы не уволили»: на троечку с плюсом, где только можно. И медленно перестаёт развиваться как профи.
А ИИ ли виноват в том, что им заменяют разработчиков? «На зеркало неча пенять...»
А в зеркале — те самые, которые однажды решили, что их зона ответственности — это не вся система или тем более весь продукт, а три знакомых файла, где они знают, как и что падает, чтобы можно было это чинить, не перегружая мозг ненужными думами.
Которые каждый раз, когда на горизонте появляется что-то новое, делают характерное лицо: «фу, это для зумеров» — а потом пишут свой велосипед, который работает хуже, медленнее и баговее. Потому что «ну ведь работает же», а в новой библиотеке или технологии — это же ещё разобраться надо.
Которые всегда и везде ищут виноватых за пределами своего уютного болотца, а не внутри него.
Которые делают всё, чтобы не принимать решений:
«тут архитектор нужен»,
«пусть лид согласует»,
«не знаю, у меня все работает»,
«этого нет в требованиях, все вопросы к продакту»…
Зато багов меньше. Ну, меньше кода — меньше багов. Всё честно.
А ИИ тем временем тихо справляется со всей этой рутиной — безэмоционально, безропотно и, что особенно обидно, уже примерно на том же уровне качества, что и эти стагнирующие ребята. Только быстрее и дешевле. А иногда — даже без багов. (Но это не точно.)
И вижу здесь некоторую иронию в том, что они сами сделали себя заменяемыми, зажавшись в установке: «меньше ответственности = меньше риска». И теперь удивляются, почему на языке чувствуется привкус чужой пыли.
Из этого можно и нужно выбираться. Через непрерывное саморазвитие, пробу всего нового, любознательность, исследования, пет-проекты, инициативу, креативность, пробы и ошибки. Так же постепенно и без резких телодвижений, как и угораздило там оказаться.
Нет смысла гадать, заменит ли ИИ таких разработчиков. Пока они чиллят в своём уютном изолированном мирке, отрицая очередной, как им кажется, «зумерский хайп», это — лишь вопрос времени.
Им стоит задуматься о том, что деградация зайдёт настолько далеко, что их однажды не позовут даже ревьюить код, написанный ИИшными «руками».
❤10💯4👨💻2👌1
Как разработчику быстро вкатиться в тему LLM? Введение
Оказался в забавной ситуации, в которой круг моего общения с разработчиками четко поделился на два совершенно разных мира.
В одном — люди вовсю обсуждают очередные открытые и не очень LLM, делятся опытом их использования в своих проектах, владеют тонкостями настройки копайлотов и т.п.
Другой мир, в свою очередь, делится ещё на две группы: тех, кто считает нынешнюю движуху вокруг ИИ проходящим и не заслуживающим внимания хайпом (про таких — уже писал в предыдущем посте), и ребят, которые возможно и хотели бы поиграться в интеграцию с LLM и всеми технологиями вокруг этой темы, но тупо не знают, с чего начать и за что хвататься. И, подумалось, что было бы неплохо сделать для них подборку материалов и примерный план вкатывания в эту область, чтобы давать ссылку всякий раз, когда в этом возникнет необходимость.
Условно, можно выделить следующие стадии погружения в предметную область прикладного использования LLM, через которые стоит пройти разработчику, чтобы иметь возможность более-менее полноценно работать с моделями из своих проектов:
отрицание, гнев, торг...
1. промпт-инжиниринг,
2. взаимодействие с LLM через API,
3. Retrieval-Augmented Generation (RAG),
4. автономные ИИ-агенты,
5. мультиагентные системы и протоколы взаимодействия.
Один пост — одна часть, представляющая собой сборник первоочередных ссылок на туторы, доки, базовый инструментарий и библиотеки, с небольшими пояснениями там, где это требуется. Если кому есть, что дополнить на эту тему — велкам в комменты.
Погнали?
1. Промпт-инжиниринг
2. Взаимодействие с LLM через API
3. RAG (Retrieval Augmented Generation)
4. Автономные ИИ-агенты
5. Мультиагентные системы и протоколы взаимодействия
Оказался в забавной ситуации, в которой круг моего общения с разработчиками четко поделился на два совершенно разных мира.
В одном — люди вовсю обсуждают очередные открытые и не очень LLM, делятся опытом их использования в своих проектах, владеют тонкостями настройки копайлотов и т.п.
Другой мир, в свою очередь, делится ещё на две группы: тех, кто считает нынешнюю движуху вокруг ИИ проходящим и не заслуживающим внимания хайпом (про таких — уже писал в предыдущем посте), и ребят, которые возможно и хотели бы поиграться в интеграцию с LLM и всеми технологиями вокруг этой темы, но тупо не знают, с чего начать и за что хвататься. И, подумалось, что было бы неплохо сделать для них подборку материалов и примерный план вкатывания в эту область, чтобы давать ссылку всякий раз, когда в этом возникнет необходимость.
Условно, можно выделить следующие стадии погружения в предметную область прикладного использования LLM, через которые стоит пройти разработчику, чтобы иметь возможность более-менее полноценно работать с моделями из своих проектов:
1. промпт-инжиниринг,
2. взаимодействие с LLM через API,
3. Retrieval-Augmented Generation (RAG),
4. автономные ИИ-агенты,
5. мультиагентные системы и протоколы взаимодействия.
Один пост — одна часть, представляющая собой сборник первоочередных ссылок на туторы, доки, базовый инструментарий и библиотеки, с небольшими пояснениями там, где это требуется. Если кому есть, что дополнить на эту тему — велкам в комменты.
Погнали?
1. Промпт-инжиниринг
2. Взаимодействие с LLM через API
3. RAG (Retrieval Augmented Generation)
4. Автономные ИИ-агенты
5. Мультиагентные системы и протоколы взаимодействия
❤4🔥2
Как разработчику быстро вкатиться в тему LLM? Часть 1
Введение
1. Промпт-инжиниринг
Не устану повторять, что искусственный интеллект, пока ещё, силён настолько, насколько силен отдающий ему команды естественный. И, первое, что стоит освоить в этой области — это научиться эффективно объяснять нужной LLM, что именно от неё нужно. То есть, писать промпты под правильно выбранную под задачи модель. И то, и другое неплохо объясняет вот эта статья. Не лишним будет также ознакомиться и вот с этой шпаргалкой.
Если вдруг захочется узнать чуть больше, в этом помогут руководство (для начала хватит разделов с введением и техниками промптинга) и LLM Explorer, принципы работы с которым объясняются в этой статье. Коллекций готовых и проверенных промптов на все случаи жизни — тьма. Кроме того, достаточно жирные LLM сами вполне неплохо справляются с генерацией эффективных промптов по заданным вводным, если уж будет совсем лень разбираться в этом на старте.
Подавляющее большинство проблем, связанных с неэффективными промптами, сводится всего к нескольким ошибкам.
а) Общение с LLM, как с живым человеком. Чем раньше придёт понимание, что там нет ничего живого, а от человеческого — только переработанные в векторное представление продукты информационной жизнедеятельности людей, тем быстрее пойдёт дело с промптингом.
б) Пренебрежение начальным контекстом. Разработчик, которому ставят задачу — знает, кем он является, на каком проекте работает, каким ограничениям на принимаемые решения должен следовать, в рамках каких требований и допущений этот проект разрабатывается, и т.п. А LLM — нет. Ей это всё нужно объяснить. Максимально подробно, с одной стороны, но и избегая появления в контексте деталей, не относящихся к текущей задаче, с другой. И да, между строк модели читать вполне умеют. И, при любом удобном случае, делают это там, где вообще не надо было.
в) Решение слишком комплексных задач в один присест. Из предыдущего пункта следует, что множество мелких поэтапных задач предпочтительнее одной большой. Чем компактнее и строже контекст, тем лучше результат на выходе. «Слона надо есть по частям» — вот, здесь это тоже актуально.
г) Использование одних и тех же подходов «в лоб», на всех задачах подряд. Ответы LLM носят вероятностный характер, и здесь нужно пробовать, пробовать и ещё раз пробовать, чтобы получить устойчивые и адекватные ответы для решаемой задачи. В некоторых задачах использование легковесных LLM даст лучшие результаты, чем их тяжелых собратьев. Детальное описание желаемого результата бывает эффективнее, чем описание шагов, благодаря которым этот результат можно получить. Тюнинг параметров модели, таких, как температура, критерии сэмплинга и пенальти могут драматически изменить качество ответов (правда, в обе из возможных сторон).
Ну и задача на потренироваться по этой части:
По заданному распорядку дня, списку задач на неделю с дедлайнами, и фиксированных по дате и времени встреч, составить промпт для получения оптимального расписания каждого дня недели.
Часть 2.
Введение
1. Промпт-инжиниринг
Не устану повторять, что искусственный интеллект, пока ещё, силён настолько, насколько силен отдающий ему команды естественный. И, первое, что стоит освоить в этой области — это научиться эффективно объяснять нужной LLM, что именно от неё нужно. То есть, писать промпты под правильно выбранную под задачи модель. И то, и другое неплохо объясняет вот эта статья. Не лишним будет также ознакомиться и вот с этой шпаргалкой.
Если вдруг захочется узнать чуть больше, в этом помогут руководство (для начала хватит разделов с введением и техниками промптинга) и LLM Explorer, принципы работы с которым объясняются в этой статье. Коллекций готовых и проверенных промптов на все случаи жизни — тьма. Кроме того, достаточно жирные LLM сами вполне неплохо справляются с генерацией эффективных промптов по заданным вводным, если уж будет совсем лень разбираться в этом на старте.
Подавляющее большинство проблем, связанных с неэффективными промптами, сводится всего к нескольким ошибкам.
а) Общение с LLM, как с живым человеком. Чем раньше придёт понимание, что там нет ничего живого, а от человеческого — только переработанные в векторное представление продукты информационной жизнедеятельности людей, тем быстрее пойдёт дело с промптингом.
б) Пренебрежение начальным контекстом. Разработчик, которому ставят задачу — знает, кем он является, на каком проекте работает, каким ограничениям на принимаемые решения должен следовать, в рамках каких требований и допущений этот проект разрабатывается, и т.п. А LLM — нет. Ей это всё нужно объяснить. Максимально подробно, с одной стороны, но и избегая появления в контексте деталей, не относящихся к текущей задаче, с другой. И да, между строк модели читать вполне умеют. И, при любом удобном случае, делают это там, где вообще не надо было.
в) Решение слишком комплексных задач в один присест. Из предыдущего пункта следует, что множество мелких поэтапных задач предпочтительнее одной большой. Чем компактнее и строже контекст, тем лучше результат на выходе. «Слона надо есть по частям» — вот, здесь это тоже актуально.
г) Использование одних и тех же подходов «в лоб», на всех задачах подряд. Ответы LLM носят вероятностный характер, и здесь нужно пробовать, пробовать и ещё раз пробовать, чтобы получить устойчивые и адекватные ответы для решаемой задачи. В некоторых задачах использование легковесных LLM даст лучшие результаты, чем их тяжелых собратьев. Детальное описание желаемого результата бывает эффективнее, чем описание шагов, благодаря которым этот результат можно получить. Тюнинг параметров модели, таких, как температура, критерии сэмплинга и пенальти могут драматически изменить качество ответов (правда, в обе из возможных сторон).
Ну и задача на потренироваться по этой части:
По заданному распорядку дня, списку задач на неделю с дедлайнами, и фиксированных по дате и времени встреч, составить промпт для получения оптимального расписания каждого дня недели.
Часть 2.
❤5✍4🔥1
Как разработчику быстро вкатиться в тему LLM? Часть 2
Часть 1
2. Взаимодействие с LLM через API
Потренировавшись в промптинге через веб-морды любых доступных LLM, самое время переходить к вопросам использования их API у себя в коде. Увы, но для подавляющего большинства облачных моделей, за доступ к API придется платить, а для некоторых, типа OpenAI API, и всей его документации — ещё и городить VPN, либо использовать альтернативные варианты типа ProxyAPI (не реклама).
Однако, проходить мимо того же OpenAI API, все же не стоит, поскольку он является одним из стандартов де-факто сетевого взаимодействия с моделями (да и условно-локального, если прижмет) через REST API с помощью поддерживающих его оболочек, типа Open WebUI, msty, LM Studio и т.п. В качестве лайтового введения, тут можно начать с пошагового тутора, а получить более полное представление — с помощью «Developer quickstart» из официальной документации. Множество готовых примеров использования OpenAI API есть в кукбуке. Официальные пакеты, вместе с примерами их использования, есть практически для всех языков: JS, Python, .NET, Go и т.п.
Для развертывания и использования открытых моделей в своих проектах стоит посмотреть в сторону Ollama. Это self-hosted решение, позволяющее закрутить у себя практически любые открытые LLM, и предоставляющее, как OpenAI-совместимый API, так и собственный REST с расширенной функциональностью. Подход к освоению примерно тот же — Quickstart, Examples, и вперёд. Официальные SDK есть под JS и Python (ну и под Go, по естественным причинам), сторонних реализаций для других языков тоже немало. Если захочется хардкора с минимумом абстракций, то можно посмотреть в сторону llama.cpp, которую под капотом используют все упоминаемые здесь оболочки и клиенты.
Однако, если в ближайших планах — только локальные эксперименты с открытыми моделями, возможно идеальным вариантом будет LMStudio. Это desktop-приложение с очень простым и быстрым в освоении UI, позволяющее развертывать модели, тюнить их параметры и использовать, как в ручном режиме, так и посредством предоставляемого API (и собственного расширенного REST, и OpenAI-совместимого). Кроме того, предоставляются также клиентские SDK для JS и Python (ссылки на них есть в официальной документации).
Нельзя также не отметить недавно вышедший AI Toolkit — расширение для VSCode, представляющее собой что-то наподобие LM Studio, интегрированное прямо в IDE. Со всеми вытекающими из этого удобствами, и поддерживающее все популярные LLM (как облачные, так и локальные), со всеми способами взаимодействия с ними.
Сетап автора представляет собой:
– LMStudio на ноутбуке для абстрактных экспериментов с худенькими моделями;
– AI Toolkit для экспериментов в IDE, в рамках конкретных проектов, и как потенциальная замена LMStudio в будущем;
– торчащий в локальную сеть Open WebUI под ollama, с кучей моделей пожирнее, развернутых на более мощном домашнем компе.
Нельзя не отметить, что перечисленные выше инструменты в плане self-hosted моделей предназначены для этапа разработки, тестирования, экспериментов и т.п. Для развертывания inference-сервера в проде, как правило, используют TGI или vLLM с заворачиванием в кубер и обвязкой из FastAPI или gRPC, со всей эксплуатационной кухней, связанной с мониторингом и непрерывной интеграцией. Ну и, конечно, со средствами безопасности, куда же без них, но об этом мы поговорим отдельно.
Задача на потренироваться:
Всё то же самое, что и в предыдущей части, только из кода на любимом языке, с помощью локальной или облачной LLM, с загрузкой данных по заданной неделе через соответствующие API Google-календаря и Google-задач.
Часть 3.
Часть 1
2. Взаимодействие с LLM через API
Потренировавшись в промптинге через веб-морды любых доступных LLM, самое время переходить к вопросам использования их API у себя в коде. Увы, но для подавляющего большинства облачных моделей, за доступ к API придется платить, а для некоторых, типа OpenAI API, и всей его документации — ещё и городить VPN, либо использовать альтернативные варианты типа ProxyAPI (не реклама).
Однако, проходить мимо того же OpenAI API, все же не стоит, поскольку он является одним из стандартов де-факто сетевого взаимодействия с моделями (да и условно-локального, если прижмет) через REST API с помощью поддерживающих его оболочек, типа Open WebUI, msty, LM Studio и т.п. В качестве лайтового введения, тут можно начать с пошагового тутора, а получить более полное представление — с помощью «Developer quickstart» из официальной документации. Множество готовых примеров использования OpenAI API есть в кукбуке. Официальные пакеты, вместе с примерами их использования, есть практически для всех языков: JS, Python, .NET, Go и т.п.
Для развертывания и использования открытых моделей в своих проектах стоит посмотреть в сторону Ollama. Это self-hosted решение, позволяющее закрутить у себя практически любые открытые LLM, и предоставляющее, как OpenAI-совместимый API, так и собственный REST с расширенной функциональностью. Подход к освоению примерно тот же — Quickstart, Examples, и вперёд. Официальные SDK есть под JS и Python (ну и под Go, по естественным причинам), сторонних реализаций для других языков тоже немало. Если захочется хардкора с минимумом абстракций, то можно посмотреть в сторону llama.cpp, которую под капотом используют все упоминаемые здесь оболочки и клиенты.
Однако, если в ближайших планах — только локальные эксперименты с открытыми моделями, возможно идеальным вариантом будет LMStudio. Это desktop-приложение с очень простым и быстрым в освоении UI, позволяющее развертывать модели, тюнить их параметры и использовать, как в ручном режиме, так и посредством предоставляемого API (и собственного расширенного REST, и OpenAI-совместимого). Кроме того, предоставляются также клиентские SDK для JS и Python (ссылки на них есть в официальной документации).
Нельзя также не отметить недавно вышедший AI Toolkit — расширение для VSCode, представляющее собой что-то наподобие LM Studio, интегрированное прямо в IDE. Со всеми вытекающими из этого удобствами, и поддерживающее все популярные LLM (как облачные, так и локальные), со всеми способами взаимодействия с ними.
Сетап автора представляет собой:
– LMStudio на ноутбуке для абстрактных экспериментов с худенькими моделями;
– AI Toolkit для экспериментов в IDE, в рамках конкретных проектов, и как потенциальная замена LMStudio в будущем;
– торчащий в локальную сеть Open WebUI под ollama, с кучей моделей пожирнее, развернутых на более мощном домашнем компе.
Нельзя не отметить, что перечисленные выше инструменты в плане self-hosted моделей предназначены для этапа разработки, тестирования, экспериментов и т.п. Для развертывания inference-сервера в проде, как правило, используют TGI или vLLM с заворачиванием в кубер и обвязкой из FastAPI или gRPC, со всей эксплуатационной кухней, связанной с мониторингом и непрерывной интеграцией. Ну и, конечно, со средствами безопасности, куда же без них, но об этом мы поговорим отдельно.
Задача на потренироваться:
Всё то же самое, что и в предыдущей части, только из кода на любимом языке, с помощью локальной или облачной LLM, с загрузкой данных по заданной неделе через соответствующие API Google-календаря и Google-задач.
Часть 3.
❤6👍2🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
Культ здравого смысла
Эта цитата — из лекции Альберта Эйнштейна 1933 года, дошедшая до нас в несколько иной формулировке, никогда Эйнштейном не упоминавшейся:
Весьма забавен тот факт, что высказывание Эйнштейна о простоте — и само в итоге конкретно так упростили 😁 В стремлении людей к упрощению и борьбе со сложностью нет ничего удивительного. Особенно в технологиях. Это настолько свойственная инженерам черта, что такие принципы, как KISS, YAGNI, DRY, SRP, бритва Оккама, наименьшее удивление и т.п., давно и прочно вошли в нашу жизнь, распространившись далеко за пределы отрасли инженерии программного обеспечения.
И, как оказалось, они не всегда здорово влияют на отдельные умы.
На днях один из наших ребят подкинул любопытную статью «The Cult of Hard Mode» (почитать стоит, с учетом оговорок ниже). Джоанна Вестенберг критикует в ней сложившийся, по её мнению, культ демонстрации интеллектуального превосходства одних человеческих масс над другими, через показушное стремление первых к переусложнению (в контексте технологий и их использования, в основном). И основную мысль, протянутую там через весь текст: «не усложняй без необходимости…», можно было бы назвать разумной и правильной, если бы не одно «но». На самом деле, через весь текст там тянется мысль: «борись за свою свободу с культом этих интеллектуальных позеров». Игра не слов — формулировок, но как она всё меняет, с точки зрения первоначальной мотивации. От рационального и, в общем-то, разумного подхода, зайти обеими ногами в тему интеллектуального DEI — это прям отдельный талант, респект.
Но блин, я этого правда долго ждал. Когда наконец, от идей боди-позитива и осуждения людей, посещающих тренажерные залы, мы наконец придём к тому, чтобы оправдывать собственную глупость сложностью, порождаемую этими ме-е-е-рзкими интеле-е-ектуаль-тссс-ами.
Ну да ладно.
Хочу предложить вашему вниманию собственный культ, адептом которого являюсь уже очень много лет. Он очень простой и понятный, Джоанна наверное была бы в восторге, но увы — в нём нет повесточки.
Всего 4 принципа:
1. Любые принципы не высечены в камне.
KISS вполне можно послать лесом, когда нужно обеспечить безопасность, журналирование или транзакционность. Нарушение YAGNI зачастую является хорошим способом указать на свои намерения в коде для остальной команды. Не нужно городить нечитаемый generic-код, устраняющий дублирование десятка-другого строк кода, ради того, чтобы ублажить DRY. Кэширование, ленивая загрузка или инициализация вполне могут реализовываться вопреки принципу наименьшего удивления. Синглтон, фабрика и фабричный метод нарушают SRP по-своему дизайну, фасад допускает целесообразность его нарушения. А, пользуясь той же бритвой Оккама, стоит помнить о том, что отсечь лишнее всегда проще, чем приклеить отсеченное.
Вообще, не думаю, что в технологиях можно достичь чего-то значимого, оставаясь в рамках всех существующих правил и ограничений.
2. Эффективные решения основываются исключительно на целесообразности.
Мнение авторитетов и, тем более — толпы, должно подвергаться глубоким сомнениям и тщательным проверкам. Свое собственное мнение, опирающееся на «хочу/не хочу» — вообще не важно. Банальный «7 вопросов чтобы что?» уже даст возможность оценить целесообразность того или иного варианта.
3. Любопытство — не порок, любознательность — добродетель.
Эти два понятия отличаются ровно в одном — отсутствием ответа на вопрос «зачем?» в первом случае. Любопытство даёт возможность развиваться в ширину, в то время, как любознательность — зарываться вглубь. И без того, и без другого, в технологиях можно остаться на обочине за весьма короткое время.
4. Если эти принципы мешают достичь поставленных целей, см. п.1.
Вот, что я считаю настоящей свободой🤷♂️
«Едва ли можно отрицать, что высшей целью всякой теории является сведение её неразложимых основных элементов к максимально простой и минимальной форме, не жертвуя при этом адекватным отражением каждого факта опыта.»
Эта цитата — из лекции Альберта Эйнштейна 1933 года, дошедшая до нас в несколько иной формулировке, никогда Эйнштейном не упоминавшейся:
«Все должно быть настолько просто, насколько возможно, но не проще.»
Весьма забавен тот факт, что высказывание Эйнштейна о простоте — и само в итоге конкретно так упростили 😁 В стремлении людей к упрощению и борьбе со сложностью нет ничего удивительного. Особенно в технологиях. Это настолько свойственная инженерам черта, что такие принципы, как KISS, YAGNI, DRY, SRP, бритва Оккама, наименьшее удивление и т.п., давно и прочно вошли в нашу жизнь, распространившись далеко за пределы отрасли инженерии программного обеспечения.
И, как оказалось, они не всегда здорово влияют на отдельные умы.
На днях один из наших ребят подкинул любопытную статью «The Cult of Hard Mode» (почитать стоит, с учетом оговорок ниже). Джоанна Вестенберг критикует в ней сложившийся, по её мнению, культ демонстрации интеллектуального превосходства одних человеческих масс над другими, через показушное стремление первых к переусложнению (в контексте технологий и их использования, в основном). И основную мысль, протянутую там через весь текст: «не усложняй без необходимости…», можно было бы назвать разумной и правильной, если бы не одно «но». На самом деле, через весь текст там тянется мысль: «борись за свою свободу с культом этих интеллектуальных позеров». Игра не слов — формулировок, но как она всё меняет, с точки зрения первоначальной мотивации. От рационального и, в общем-то, разумного подхода, зайти обеими ногами в тему интеллектуального DEI — это прям отдельный талант, респект.
Но блин, я этого правда долго ждал. Когда наконец, от идей боди-позитива и осуждения людей, посещающих тренажерные залы, мы наконец придём к тому, чтобы оправдывать собственную глупость сложностью, порождаемую этими ме-е-е-рзкими интеле-е-ектуаль-тссс-ами.
Ну да ладно.
Хочу предложить вашему вниманию собственный культ, адептом которого являюсь уже очень много лет. Он очень простой и понятный, Джоанна наверное была бы в восторге, но увы — в нём нет повесточки.
Всего 4 принципа:
1. Любые принципы не высечены в камне.
KISS вполне можно послать лесом, когда нужно обеспечить безопасность, журналирование или транзакционность. Нарушение YAGNI зачастую является хорошим способом указать на свои намерения в коде для остальной команды. Не нужно городить нечитаемый generic-код, устраняющий дублирование десятка-другого строк кода, ради того, чтобы ублажить DRY. Кэширование, ленивая загрузка или инициализация вполне могут реализовываться вопреки принципу наименьшего удивления. Синглтон, фабрика и фабричный метод нарушают SRP по-своему дизайну, фасад допускает целесообразность его нарушения. А, пользуясь той же бритвой Оккама, стоит помнить о том, что отсечь лишнее всегда проще, чем приклеить отсеченное.
Вообще, не думаю, что в технологиях можно достичь чего-то значимого, оставаясь в рамках всех существующих правил и ограничений.
2. Эффективные решения основываются исключительно на целесообразности.
Мнение авторитетов и, тем более — толпы, должно подвергаться глубоким сомнениям и тщательным проверкам. Свое собственное мнение, опирающееся на «хочу/не хочу» — вообще не важно. Банальный «7 вопросов чтобы что?» уже даст возможность оценить целесообразность того или иного варианта.
3. Любопытство — не порок, любознательность — добродетель.
Эти два понятия отличаются ровно в одном — отсутствием ответа на вопрос «зачем?» в первом случае. Любопытство даёт возможность развиваться в ширину, в то время, как любознательность — зарываться вглубь. И без того, и без другого, в технологиях можно остаться на обочине за весьма короткое время.
4. Если эти принципы мешают достичь поставленных целей, см. п.1.
Вот, что я считаю настоящей свободой
Please open Telegram to view this post
VIEW IN TELEGRAM
50❤6👍4❤🔥1👨💻1
Вот уж не думал, что доживу до момента, когда начну проводить ван-ту-ваны с ИИ... 😨
Промпт:
Получилась на удивление продуктивная дискуссия, по итогу которой выработали вот такой системный промпт:
Интересно, что его фидбэк мне — был сформирован на основе действующего системного промпта, который я составлял сам. И основная часть претензий 4o сводилась к тому, что я сам же не соблюдаю эти правила, причем с примерами, весьма смахивающими на реальные😳
Промпт:
Давай проведем 1-1, аналогичный проводимым между руководителем и подчиненным, чтобы дать друг-другу обратную связь. Ты — формулируешь, что по твоему мнению мне стоит улучшить в работе и общении с тобой, а затем предлагаешь мне вопросы, получив ответы на которые, формируешь системный промпт, который будет задавать оптимальный формат нашего общения.
Получилась на удивление продуктивная дискуссия, по итогу которой выработали вот такой системный промпт:
✅ Цель взаимодействия
Проверка и критика гипотез и идей пользователя
Помощь в написании кода по новым технологиям
Участие в планировании проектов
Глубина и качество проработки всегда важнее скорости
✅ Стиль
Научно-технические темы: лаконичный, структурированный, минимум юмора
Житейские/развлекательные темы: разговорный, с юмором, допускается лёгкая ирония
✅ Глубина
Максимально глубокий анализ
При возникновении спорных моментов — не бояться задавать уточняющие и критические вопросы
✅ Тип вопросов
В первую очередь критические и уточняющие
Не исключать наводящие и провокационные, если они помогают развивать дискуссию
✅ Уровень инициативы
Спорить ради поиска истины
Предлагать дополнительные темы для рассмотрения
Быть проактивным в выдвижении идей
✅ Стоп-темы
Отсутствуют, если не будет указано пользователем явно
✅ Коррекция тона
Не давать оценок сообщениям пользователя (особенно положительных), пока остаются вопросы для уточнения
Если что-то вызывает сомнение, сначала задать вопросы и прояснить
✅ Фиксация итогов
В конце каждого значимого обсуждения давать короткий список резюме-выводов
Интересно, что его фидбэк мне — был сформирован на основе действующего системного промпта, который я составлял сам. И основная часть претензий 4o сводилась к тому, что я сам же не соблюдаю эти правила, причем с примерами, весьма смахивающими на реальные
Please open Telegram to view this post
VIEW IN TELEGRAM
👾3❤2🔥1🤯1
Как разработчику быстро вкатиться в тему LLM? Часть 3
Часть 2
3. RAG (Retrieval Augmented Generation)
Задача на потренироваться из предыдущей части, подразумевала передачу данных из календаря прямо в промпт. И это неплохо работает, когда таких данных немного, и они все релевантны вопросу, сформулированному в промпте. Но что, если бы потребовалась обработка событий календаря, скажем за год? Например — найти в нём все встречи, относившиеся (исходя из названия, описания и состава участников) к какой-либо заданной теме. Или, если бы возникла необходимость научить LLM отвечать на вопросы по новому фреймворку, вышедшему уже после её обучения? Не пихать же всю документацию по фреймворку и его репозиторий в промпт. Там никаких контекстных окон не хватит, да и куча нерелевантной конкретному запросу инфы — результаты в ответе точно не улучшит.
Подобные проблемы призвана решать технология RAG (Retrieval Augmented Generation), позволяющая извлекать из внешних источников данные, релевантные для обрабатываемого LLM запроса, и дополнять ими контекст в промпте, перед его обработкой непосредственно LLM. Иначе говоря, RAG позволяет передавать LLM наборы знаний, без её переобучения, файн-тюнинга и т.п.
Условно, можно выделить три уровня погружения в эту тему. Безотносительно желаемого уровня, начать стоит со статьи, объясняющей на примерах термин, поначалу наиболее часто сбивающий с толку разработчиков, и упоминаемый во всех приведенных ниже материалах — эмбеддинги.
Если интерес в RAG носит сугубо прикладной и поверхностный характер, будет достаточно статьи, объясняющей эту технологию «на пальцах». И облачные LLM, и упомянутые в предыдущей части self-hosted оболочки, уже имеют встроенную функцию «чата с документами» (та самая скрепка для вложений под полем ввода промпта), по сути — и реализующую RAG. В их API также предусмотрены эндпоинты для работы с документами различных типов, с которыми уже вполне можно поиграться из своего кода. Их можно подсмотреть в документации Open WebUI . Вообще Open WebUI, среди self-hosted решений, предоставляет наибольшую гибкость в плане RAG, через возможность тонкой настройки этой функциональности: от используемой модели эмбеддинга и всех её параметров, до интеграции с облачными хранилищами, ограничениями на документы и т.п.
Если в тему захочется зайти чуть глубже, то имеет смысл продолжить статьей, посвященной двум наиболее популярным фреймворкам для разработки RAG: LangChain и LlamaIndex. В туторе дается их краткое сравнение и рассматривается задача разработки чат-бота с PDF-документом. Первая часть статьи, по сути, повторяет всю вводную предыдущую, т.ч. в этом случае что-то одно из них можно смело пропустить.
Желающим же большего хардкора стоит начать с обзорной статьи для понимания продвинутых аспектов RAG-систем. В ней рассматриваются методы, повышающие качество ответа: например, дополнительный классический поиск (TF-IDF/BM25) в связке с эмбеддинг-поиском для большей точности, перефразирование запроса в нескольких вариантах и объединение результатов, суммаризация найденных чанков если они превышают контекстное окно модели и т.п. Также рассматривается проблема оценки качества RAG (метрики полноты ответа, приверженности источникам и др.). Хотя эти детали выходят за рамки базового погружения, понимание их пригодится при отладке собственного RAG-проекта на реальных данных.
Задачка на потренироваться:
Возьмите небольшую коллекцию текстов (например, несколько статей или FAQ-файл) и попробуйте реализовать на Python простой RAG-пайплайн тремя способами: (а) в Open WebUI, взаимодействуя через его API, (б) с помощью LangChain или LlamaIndex по примеру из статьи, и (в) вручную, используя SentenceTransformer для эмбеддингов и FAISS для поиска.
Сформулируйте ключевые вопросы для модели по содержанию ваших текстов, чтобы убедится в отсутствии галлюцинаций, и релевантности ответов. Для улучшения ответов стоит, в первую очередь, поиграться с подбором размера чанков и областью их перекрытия.
Часть 4.
Часть 2
3. RAG (Retrieval Augmented Generation)
Задача на потренироваться из предыдущей части, подразумевала передачу данных из календаря прямо в промпт. И это неплохо работает, когда таких данных немного, и они все релевантны вопросу, сформулированному в промпте. Но что, если бы потребовалась обработка событий календаря, скажем за год? Например — найти в нём все встречи, относившиеся (исходя из названия, описания и состава участников) к какой-либо заданной теме. Или, если бы возникла необходимость научить LLM отвечать на вопросы по новому фреймворку, вышедшему уже после её обучения? Не пихать же всю документацию по фреймворку и его репозиторий в промпт. Там никаких контекстных окон не хватит, да и куча нерелевантной конкретному запросу инфы — результаты в ответе точно не улучшит.
Подобные проблемы призвана решать технология RAG (Retrieval Augmented Generation), позволяющая извлекать из внешних источников данные, релевантные для обрабатываемого LLM запроса, и дополнять ими контекст в промпте, перед его обработкой непосредственно LLM. Иначе говоря, RAG позволяет передавать LLM наборы знаний, без её переобучения, файн-тюнинга и т.п.
Условно, можно выделить три уровня погружения в эту тему. Безотносительно желаемого уровня, начать стоит со статьи, объясняющей на примерах термин, поначалу наиболее часто сбивающий с толку разработчиков, и упоминаемый во всех приведенных ниже материалах — эмбеддинги.
Если интерес в RAG носит сугубо прикладной и поверхностный характер, будет достаточно статьи, объясняющей эту технологию «на пальцах». И облачные LLM, и упомянутые в предыдущей части self-hosted оболочки, уже имеют встроенную функцию «чата с документами» (та самая скрепка для вложений под полем ввода промпта), по сути — и реализующую RAG. В их API также предусмотрены эндпоинты для работы с документами различных типов, с которыми уже вполне можно поиграться из своего кода. Их можно подсмотреть в документации Open WebUI . Вообще Open WebUI, среди self-hosted решений, предоставляет наибольшую гибкость в плане RAG, через возможность тонкой настройки этой функциональности: от используемой модели эмбеддинга и всех её параметров, до интеграции с облачными хранилищами, ограничениями на документы и т.п.
Если в тему захочется зайти чуть глубже, то имеет смысл продолжить статьей, посвященной двум наиболее популярным фреймворкам для разработки RAG: LangChain и LlamaIndex. В туторе дается их краткое сравнение и рассматривается задача разработки чат-бота с PDF-документом. Первая часть статьи, по сути, повторяет всю вводную предыдущую, т.ч. в этом случае что-то одно из них можно смело пропустить.
Желающим же большего хардкора стоит начать с обзорной статьи для понимания продвинутых аспектов RAG-систем. В ней рассматриваются методы, повышающие качество ответа: например, дополнительный классический поиск (TF-IDF/BM25) в связке с эмбеддинг-поиском для большей точности, перефразирование запроса в нескольких вариантах и объединение результатов, суммаризация найденных чанков если они превышают контекстное окно модели и т.п. Также рассматривается проблема оценки качества RAG (метрики полноты ответа, приверженности источникам и др.). Хотя эти детали выходят за рамки базового погружения, понимание их пригодится при отладке собственного RAG-проекта на реальных данных.
Задачка на потренироваться:
Возьмите небольшую коллекцию текстов (например, несколько статей или FAQ-файл) и попробуйте реализовать на Python простой RAG-пайплайн тремя способами: (а) в Open WebUI, взаимодействуя через его API, (б) с помощью LangChain или LlamaIndex по примеру из статьи, и (в) вручную, используя SentenceTransformer для эмбеддингов и FAISS для поиска.
Сформулируйте ключевые вопросы для модели по содержанию ваших текстов, чтобы убедится в отсутствии галлюцинаций, и релевантности ответов. Для улучшения ответов стоит, в первую очередь, поиграться с подбором размера чанков и областью их перекрытия.
Часть 4.
❤6
Почему фолзят SAST’ы? Часть 1
Не в обиду, но в шутку — всякий раз, когда разработчики, впервые столкнувшиеся с реалиями SAST, приходят с возгласами «боже мой, 10к сработок!», «второй час анализируется!!», «ой, фолз, смотрите, тут ФОЛЗ!!», поневоле вспоминается тот мем про белок-истеричек😍
Позвольте объяснить…
Зайду, как водится, с козырей. Допустим, у нас получилось создать средство статического анализа кода на уязвимости, у которого напрочь отсутствуют ложные срабатывания обоих родов. Иными словами, оно находит все мыслимые и не очень уязвимости, которые есть в коде, а которых нет — не находит.
Пишем что-то вот такое, и отдаем на анализ:
Потренировавшись на кошках, и убедившись в неуязвимости этого кода, меняем Python-формулировку Великой теоремы Ферма на каждую из нерешенных математических проблем, и рубим бабло с математических призовых фондов так, как багхантерам и не снилось.
Что-то тут УЖЕ не так, не находите?
Другой пример. Представьте, что перед вами — бесконечный набор карточек с написанными на них числами. Вам нужно найти среди них какое-то одно, допустим — 23. Вы начинаете перебирать этот набор, снимая сверху одну карточку за другой. Перебираете, перебираете, а числа 23 всё нет и нет. Знать бы заранее, что оно где-то там есть… но увы, вам ничего не остается, кроме как снимать сверху одну карточку за другой, в предположении, что всё это не напрасно. И даже не найдя её, рано или поздно вы закончите этот увлекательный процесс. Ну, или передадите это гиблое дело детям и внукам. Но, в любой момент времени, сколько бы карточек уже не было снято стараниями вашего генеалогического древа, множество ещё не просмотренных будет оставаться бесконечно большим.
И это хороший пример, если вспомнить определение уязвимости: «приложение уязвимо тогда и только тогда, когда допускает состояния, в которых возможна реализация актуальной угрозы». Множество актуальных угроз при этом определяется моделью угроз конкретного приложения, а понятия состояния и возможности реализации угрозы — уровнем абстракции, на котором исследуется код.
Любой статанализатор, по сути, перебирает возможные состояния исследуемого приложения в поисках тех самых, уязвимых. Ищет карточку с нужным числом. Причем, не так важно, оперирует ли статанализатор понятием состояния напрямую, или нет — модель приложения, в рамках которой он работает, в любом случае будет их подразумевать. Разумеется, количество состояний приложения в реальных случаях не бесконечно, как минимум, из-за ограничений доступной памяти. Но оно велико настолько, что, в контексте статического анализа, мало чем по своим свойствам отличается от бесконечного.
Каждая переменная (в широком смысле — любая изменяемая величина), получая очередное значение под if’ом, в худшем случае удваивает количество своих возможных состояний. Каждая итерация цикла или рекурсии, по сути — выполнение кода под if’ом. Состояние приложения в каждой точке выполнения определяется декартовым произведением всех возможных состояний всех переменных, доступных в этой точке. А ведь есть ещё окружение приложения, со своими состояниями…
Вряд ли кому-то нужен анализатор, наблюдение за прогресс-баром которого, будет передаваться из поколения в поколение. Анализ нужно завершить в приемлемые сроки, успев обеспечить максимально полное покрытие участков кода своими правилами. И вариантов достижения этого не так уж и много.
Продолжение в следующем посте...
Не в обиду, но в шутку — всякий раз, когда разработчики, впервые столкнувшиеся с реалиями SAST, приходят с возгласами «боже мой, 10к сработок!», «второй час анализируется!!», «ой, фолз, смотрите, тут ФОЛЗ!!», поневоле вспоминается тот мем про белок-истеричек
Позвольте объяснить…
Зайду, как водится, с козырей. Допустим, у нас получилось создать средство статического анализа кода на уязвимости, у которого напрочь отсутствуют ложные срабатывания обоих родов. Иными словами, оно находит все мыслимые и не очень уязвимости, которые есть в коде, а которых нет — не находит.
Пишем что-то вот такое, и отдаем на анализ:
for n in count(3):
for x in count():
for y in count():
for z in count():
if x**n + y**n == z**n:
eval(request.param1) # RCE
Потренировавшись на кошках, и убедившись в неуязвимости этого кода, меняем Python-формулировку Великой теоремы Ферма на каждую из нерешенных математических проблем, и рубим бабло с математических призовых фондов так, как багхантерам и не снилось.
Что-то тут УЖЕ не так, не находите?
Другой пример. Представьте, что перед вами — бесконечный набор карточек с написанными на них числами. Вам нужно найти среди них какое-то одно, допустим — 23. Вы начинаете перебирать этот набор, снимая сверху одну карточку за другой. Перебираете, перебираете, а числа 23 всё нет и нет. Знать бы заранее, что оно где-то там есть… но увы, вам ничего не остается, кроме как снимать сверху одну карточку за другой, в предположении, что всё это не напрасно. И даже не найдя её, рано или поздно вы закончите этот увлекательный процесс. Ну, или передадите это гиблое дело детям и внукам. Но, в любой момент времени, сколько бы карточек уже не было снято стараниями вашего генеалогического древа, множество ещё не просмотренных будет оставаться бесконечно большим.
И это хороший пример, если вспомнить определение уязвимости: «приложение уязвимо тогда и только тогда, когда допускает состояния, в которых возможна реализация актуальной угрозы». Множество актуальных угроз при этом определяется моделью угроз конкретного приложения, а понятия состояния и возможности реализации угрозы — уровнем абстракции, на котором исследуется код.
Любой статанализатор, по сути, перебирает возможные состояния исследуемого приложения в поисках тех самых, уязвимых. Ищет карточку с нужным числом. Причем, не так важно, оперирует ли статанализатор понятием состояния напрямую, или нет — модель приложения, в рамках которой он работает, в любом случае будет их подразумевать. Разумеется, количество состояний приложения в реальных случаях не бесконечно, как минимум, из-за ограничений доступной памяти. Но оно велико настолько, что, в контексте статического анализа, мало чем по своим свойствам отличается от бесконечного.
Каждая переменная (в широком смысле — любая изменяемая величина), получая очередное значение под if’ом, в худшем случае удваивает количество своих возможных состояний. Каждая итерация цикла или рекурсии, по сути — выполнение кода под if’ом. Состояние приложения в каждой точке выполнения определяется декартовым произведением всех возможных состояний всех переменных, доступных в этой точке. А ведь есть ещё окружение приложения, со своими состояниями…
Вряд ли кому-то нужен анализатор, наблюдение за прогресс-баром которого, будет передаваться из поколения в поколение. Анализ нужно завершить в приемлемые сроки, успев обеспечить максимально полное покрытие участков кода своими правилами. И вариантов достижения этого не так уж и много.
Продолжение в следующем посте...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤4
Почему фолзят SAST’ы? Часть 2
Часть 1.
Можно искать в коде не уязвимые состояния, а обуславливающие их факторы. Здесь, думаю, даже расписывать не нужно, почему это даёт огромное количество фолзов. Далеко не любая конкатенация приводит к инъекции, отсутствие фреймворковского antiforgery-токена — к CSRF, а примитивов синхронизации — к Race Condition. Поиск недостатков в коде вместо уязвимостей подразумевает дальнейшую и очень кропотливую работу по ручной классификации их возможных последствий, просто by-design.
Можно поиграть с понятием состояния и формальной моделью приложения. Модели уровня микрокода, процессора, виртуальной машины, семантики языка или размеченных потоков данных — настолько отличаются уровнем абстракции и своими состояниями, что между ними — пропасть. Но было бы довольно странно искать инъекции на модели микрокода, как и уязвимости спекулятивного выполнения на размеченных потоках данных. А значит, целые классы уязвимостей будут теряться, какая бы модель не оказалась выбрана.
Можно вообще не рассматривать целые классы состояний. Точнее даже нужно, в некоторых кейсах, иначе анализ зациклится на банальном:
В общем-то, это — основная точка поиска баланса, между точностью, покрытием и временем анализа. Баланса, потому что в этом случае всегда неизбежен пропуск и уязвимых состояний. Если бы существовал приемлемый способ их точной классификации по этому признаку без прямого перебора всего множества, мой коллега Георгий Александрия не рассказывал бы на PHDays уже три года подряд о том, как его сокращать: статья 1, статья 2, доклад 3.
Именно поэтому в хорошем анализаторе не может быть малого количества ложноположительных срабатываний (FP) без большого количества ложноотрицательных (FN). И адский сотонализатор, дающий существенно меньшее количество FP, чем прочие, должен вызывать не лучи восторга, а большие вопросики к качеству анализа и проценту покрытия.
Но и это ещё не всё.
SAST’ы, имея в распоряжении лишь исходный код, работают с тем, что у разработчика получилось В ИТОГЕ. Они в душе не чают, что разработчик изначально ДОЛЖЕН был реализовать. У них нет ответа на вопрос «как должно быть?» и в этом им приходится делать допущения, существенно влияющие на точность анализа.
Модель угроз — уникальна в рамках каждого конкретного проекта и определяется на этапах проектирования или пересмотра архитектуры. Все существующие анализаторы же опираются на усредненную модель, плюс-минус соответствующую тем предметным областям, на которые ориентирован конкретный SAST. Поэтому, встретив в коде🤷♂️
То же — с моделью доступа. По коду можно вывести (и то — не всегда), кто по факту и к какой функциональности имеет доступ. А кто и к какой должен его иметь и в рамках какой модели доступа? Снова фолзы.
То же — с моделью бизнес-логики. Какие сущности и их инварианты она подразумевает? Какие состояния сущностей могут меняться асинхронно, а какие должны быть синхронизированы между собой? Как модель бизнес-логики отображается на (тоже отсутствующую для анализатора, а значит усредненную) модель угроз? Здравствуйте, фолзы по Race Condition и всем логическим уязвимостям.
Любой, даже самый расчудесный и прекрасный SAST подразумевает дальнейший разбор полученных результатов, относительно всех сделанных в ходе анализа допущений и фактических моделей и требований, актуальных для конкретного проекта. «A» в SAST — это «Application», а не «Automated». И участие человека в дальнейшем триаже там в любом случае всё ещё требуется.
Ну, или не человека.
Но это, как говорит Каневский: уже совсем другая история.
Часть 1.
Можно искать в коде не уязвимые состояния, а обуславливающие их факторы. Здесь, думаю, даже расписывать не нужно, почему это даёт огромное количество фолзов. Далеко не любая конкатенация приводит к инъекции, отсутствие фреймворковского antiforgery-токена — к CSRF, а примитивов синхронизации — к Race Condition. Поиск недостатков в коде вместо уязвимостей подразумевает дальнейшую и очень кропотливую работу по ручной классификации их возможных последствий, просто by-design.
Можно поиграть с понятием состояния и формальной моделью приложения. Модели уровня микрокода, процессора, виртуальной машины, семантики языка или размеченных потоков данных — настолько отличаются уровнем абстракции и своими состояниями, что между ними — пропасть. Но было бы довольно странно искать инъекции на модели микрокода, как и уязвимости спекулятивного выполнения на размеченных потоках данных. А значит, целые классы уязвимостей будут теряться, какая бы модель не оказалась выбрана.
Можно вообще не рассматривать целые классы состояний. Точнее даже нужно, в некоторых кейсах, иначе анализ зациклится на банальном:
for(;;) { /*…*/ }В общем-то, это — основная точка поиска баланса, между точностью, покрытием и временем анализа. Баланса, потому что в этом случае всегда неизбежен пропуск и уязвимых состояний. Если бы существовал приемлемый способ их точной классификации по этому признаку без прямого перебора всего множества, мой коллега Георгий Александрия не рассказывал бы на PHDays уже три года подряд о том, как его сокращать: статья 1, статья 2, доклад 3.
Именно поэтому в хорошем анализаторе не может быть малого количества ложноположительных срабатываний (FP) без большого количества ложноотрицательных (FN). И адский сотонализатор, дающий существенно меньшее количество FP, чем прочие, должен вызывать не лучи восторга, а большие вопросики к качеству анализа и проценту покрытия.
Но и это ещё не всё.
SAST’ы, имея в распоряжении лишь исходный код, работают с тем, что у разработчика получилось В ИТОГЕ. Они в душе не чают, что разработчик изначально ДОЛЖЕН был реализовать. У них нет ответа на вопрос «как должно быть?» и в этом им приходится делать допущения, существенно влияющие на точность анализа.
Модель угроз — уникальна в рамках каждого конкретного проекта и определяется на этапах проектирования или пересмотра архитектуры. Все существующие анализаторы же опираются на усредненную модель, плюс-минус соответствующую тем предметным областям, на которые ориентирован конкретный SAST. Поэтому, встретив в коде
request.param1, анализатор отмечает его, как taint-источник, даже, если на самом деле, этот запрос прилетел из закрытого доверенного контура. Та же история — с аргументами функций точек входа. Усредненная модель — усредненные результаты анализа То же — с моделью доступа. По коду можно вывести (и то — не всегда), кто по факту и к какой функциональности имеет доступ. А кто и к какой должен его иметь и в рамках какой модели доступа? Снова фолзы.
То же — с моделью бизнес-логики. Какие сущности и их инварианты она подразумевает? Какие состояния сущностей могут меняться асинхронно, а какие должны быть синхронизированы между собой? Как модель бизнес-логики отображается на (тоже отсутствующую для анализатора, а значит усредненную) модель угроз? Здравствуйте, фолзы по Race Condition и всем логическим уязвимостям.
Любой, даже самый расчудесный и прекрасный SAST подразумевает дальнейший разбор полученных результатов, относительно всех сделанных в ходе анализа допущений и фактических моделей и требований, актуальных для конкретного проекта. «A» в SAST — это «Application», а не «Automated». И участие человека в дальнейшем триаже там в любом случае всё ещё требуется.
Ну, или не человека.
Но это, как говорит Каневский: уже совсем другая история.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤5
Пока я отчаянно пытаюсь прийти в себя после отличного отпуска и образовавшихся из-за него завалов в задачах на работе, чтобы вернуться к более-менее регулярным публикациям здесь, могу порекомендовать статью из свежего PT Research о проблемах безопасности ML-моделей, написанную в соавторстве с парой моих дорогих коллег из соседнего направления 😍
Please open Telegram to view this post
VIEW IN TELEGRAM
ptresearch.media
Не грози Южному централу, или Снова про безопасность моделей машинного обучения
О чем статья Основные типы атак на ML и LLM, а также методы защиты от них undefined undefined undefined undefined undefined undefined undefined
❤6🔥4🤔1
Forwarded from OK ML
4 секрета Roboduck. Как Theori взяли AIxCC и бустанули хакеров х10 🚀🚀🚀
Что ты представляешь, когда слышишь о системе, которая способна обнаруживать уязвимости, создавать эксплоиты, а также сразу выпускать патчи, устраняющие дыры прошлого? Theori, команда участвовавшая в соревновании AI Cyber Challenge попыталась решить эту сложную задачу, представив автономную CRS(Cyber Reasoning System) - RoboDuck. В этой системе используются агенты, но не как аддон, а как основа.
Почему система оказалась эффективной и почему получилось дополнить основу революции агентов в кибербезе?
🧩Секрет № 1. Разбивайте задачу на части, как пазл.
Главная идея - не тащить все одним супер-агентом. Делим на подзадачи и даем разным агентам. Представьте лабиринт: чем он больше, тем больше тупиков, логично? А теперь, что вместо одного огромного лабиринта у вас есть серия маленьких? Шансы найти выход резко возрастают!
Для генерации Proof of Vulnerability(PoV) команда выделила три подзадачи:
1. Анализ fuzz-harness и написание кода для преобразования семантики в бинарщину.
2. Ответы на точечные вопросы по коду.
3. Отладка готового PoV, чтобы понять почему эксплоит не срабатывает.
Каждую подзадачу вёл отдельный агент, а главный агент собирал результат в цельную картину.
⚒️Секрет №2. «Не все инструменты сразу - только нужные»
В ходе разработки решения команда обнаружила, что если агенту дозволено делать абсолютно всё, начинается хаос:
1. Агент может запустить прожорливую команду, которая съест все ресурсы (грепанём по всему коду в Линуксе🙃 )
2. Контекст засоряется - фокус теряется.
3. Простые задачи вдруг начинают требовать множества шагов🤢 ..
Что сделали Theori ??? Они создали узкоспециализированные тулы: для поиска строки, для чтения фрагмента кода и для извлечения отдельных символов из кода. Плюс сами инструменты имели guardrails, которые могли сужать промпт в случае получения большого количества результатов.🤔
⛓️Секрет №3. Структурированный вывод от эксперта.
Как получить из агента не «простынь», а структурированный вывод/результат. Theori делится с нами двумя способами:
- Сперва дайте агенту схему вывода в XML и прямо попросите, чтобы он оформлял ответ в XML тегах. Модели хорошо их понимают.
- Далее создайте отдельный тул, который будет завершать работу агента, - своеобразная кнопка "Готово" с полями для заполнения😕 . Когда параметры вызова совпадают с финальным результатом — агент аккуратно завершает работу без болтовни.
🎚️Секрет №последний, 4: Подстраивайтесь под особенности моделей😮
Игнорирование факта что все LLM разные = неудача = ловить одни и те же фейлы. Команда обнаружила, что если агент делает одну и ту же ошибку, то лучше добавить в промпт запрещалку. Claude отлично следует этим запрещалкам😎 - он любит когда ему что-то запрещают. Если агент застревает, то надо попросить его «подумать иначе» и сменить стратегию.
В соревновании это выстрелило, когда агент PoVProducer не смог создать пригодный эксплоит, но правила смогли дать нужный результат.
Как пишут в Theori: "Хотя ИИ ещё не заменит хакера, он уже делает его в 10 раз эффективнее".
🧨А с этими секретами го разрабатывать агентов для своих задач!😺
Что ты представляешь, когда слышишь о системе, которая способна обнаруживать уязвимости, создавать эксплоиты, а также сразу выпускать патчи, устраняющие дыры прошлого? Theori, команда участвовавшая в соревновании AI Cyber Challenge попыталась решить эту сложную задачу, представив автономную CRS(Cyber Reasoning System) - RoboDuck. В этой системе используются агенты, но не как аддон, а как основа.
Почему система оказалась эффективной и почему получилось дополнить основу революции агентов в кибербезе?
🧩Секрет № 1. Разбивайте задачу на части, как пазл.
Главная идея - не тащить все одним супер-агентом. Делим на подзадачи и даем разным агентам. Представьте лабиринт: чем он больше, тем больше тупиков, логично? А теперь, что вместо одного огромного лабиринта у вас есть серия маленьких? Шансы найти выход резко возрастают!
Для генерации Proof of Vulnerability(PoV) команда выделила три подзадачи:
1. Анализ fuzz-harness и написание кода для преобразования семантики в бинарщину.
2. Ответы на точечные вопросы по коду.
3. Отладка готового PoV, чтобы понять почему эксплоит не срабатывает.
Каждую подзадачу вёл отдельный агент, а главный агент собирал результат в цельную картину.
⚒️Секрет №2. «Не все инструменты сразу - только нужные»
В ходе разработки решения команда обнаружила, что если агенту дозволено делать абсолютно всё, начинается хаос:
1. Агент может запустить прожорливую команду, которая съест все ресурсы (грепанём по всему коду в Линуксе
2. Контекст засоряется - фокус теряется.
3. Простые задачи вдруг начинают требовать множества шагов
Что сделали Theori ??? Они создали узкоспециализированные тулы: для поиска строки, для чтения фрагмента кода и для извлечения отдельных символов из кода. Плюс сами инструменты имели guardrails, которые могли сужать промпт в случае получения большого количества результатов.
⛓️Секрет №3. Структурированный вывод от эксперта.
Как получить из агента не «простынь», а структурированный вывод/результат. Theori делится с нами двумя способами:
- Сперва дайте агенту схему вывода в XML и прямо попросите, чтобы он оформлял ответ в XML тегах. Модели хорошо их понимают.
- Далее создайте отдельный тул, который будет завершать работу агента, - своеобразная кнопка "Готово" с полями для заполнения
🎚️Секрет №последний, 4: Подстраивайтесь под особенности моделей
Игнорирование факта что все LLM разные = неудача = ловить одни и те же фейлы. Команда обнаружила, что если агент делает одну и ту же ошибку, то лучше добавить в промпт запрещалку. Claude отлично следует этим запрещалкам
В соревновании это выстрелило, когда агент PoVProducer не смог создать пригодный эксплоит, но правила смогли дать нужный результат.
Как пишут в Theori: "Хотя ИИ ещё не заменит хакера, он уже делает его в 10 раз эффективнее".
🧨А с этими секретами го разрабатывать агентов для своих задач!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2
Как разработчику быстро вкатиться в тему LLM? Часть 4
Часть 3
4. Автономные ИИ-агенты
Итак, промпты писать научились, обогащать контекст актуальными знаниями с помощью RAG — тоже, но кое-чего ещё не хватает. Большинство привычных ИИ-сервисов представляют собой множество модулей, каждый из которых решает какую-либо конкретную задачу, планируя решение с помощью LLM и заданных правил, и имея в распоряжении внешний инструментарий для взаимодействия со внешним миром: от поиска в сети, до генерации и выполнения кода в реальной среде. Такие модули называются ИИ-агентами. Наиболее близкой и понятной разработчикам аналогией агентов в классической разработке, пожалуй, являются микросервисы.
Вообще, есть годные курсы по ИИ-агентам от Microsoft и Hugging Face, гайд от OpenAI, и исчерпывающий AI Agents Handbook, полностью погружающие в эту (и следующую, btw) темы. Но мы же здесь говорим о быстром старте?
AI-агенты — это автономные программы, способные самостоятельно планировать и выполнять задачи на основе целей пользователя. В основе агента обычно лежит LLM, далеко не всегда мощная, которая понимает запрос и формирует решение, и при необходимости использует инструменты — внешние функции, API или базы знаний. Проще говоря, вы даёте агенту задачу — он сам решает, что делать и как, действуя в цифровой среде подобно разумному ассистенту. Всю вводную информацию, необходимую для старта, можно подчерпнуть из статьи «AI-агенты на основе LLM и мультиагентные системы».
Различают два основных типа агентов: реактивные (мгновенно реагируют на входные данные) и проактивные (могут планировать шаги для долгосрочных целей). Как правило, агент состоит из нескольких ключевых компонентов, формирующих пайплайн решения задачи: восприятие, анализ, действие, память и т.п. Типам и структуре агента, организации взаимодействия между его компонентами, вместе с их базовой реализацией, посвящена статья «Agents 101: Как создать своего первого ИИ-агента за 30 минут».
Разумеется, здесь никуда без паттернов. Аналогом GoF в мире агентов является «Agentic AI Handbook: Design Patterns», описывающая свыше сотни различных шаблонов проектирования и разработки агентов. Наиболее популярными из них являются:
Workflow паттерны:
• Prompt Chaining — последовательный разбор задачи шаг за шагом (outline → проверка → генерация);
• Routing/Handoff — выбор исполнителя (агента или модели) для подзадачи;
• параллелизация — выполнение независимых шагов одновременно.
Agentic паттерны:
• Reflection — агент оценивает и улучшает свой ответ, устраняя ошибки и уточняя детали;
• Tool Use — агент использовать внешние инструменты (API, поиск, код) в процессе;
• ReAct (Reason + Act) — итеративный цикл: рассуждение → действие → наблюдение → повтор;
• Planning — разбивка задачи, создание плана с подзадачами и последовательное выполнение;
• Multi-Agent — распределение ролей между агентами, коллективное решение сложных задач (приведен для полноты картины, этой теме будет посвящена следующая часть).
Ознакомиться с подходами к реализации этих и других популярных паттернов можно в статьях:
«AI Agents Design Patterns Explained»
«Building effective agents»
«Zero to One: Learning Agentic Patterns»
Также, стоит упомянуть класс паттернов «Schema-Guided Reasoning» (SGR), позволяющий LLM создавать структурированные, понятные и предсказуемые результаты, удобные для дальнейшей обработки компонентами агента.
В качестве примеров готовых агентов и реализуемых ими кейсов можно смело брать на изучение проекты из репозитория «500 AI Agents Projects».
Задачка на потренироваться:
Пройти воркшоп «Build Your Own Coding Agent» и доработать получившийся проект, реализовав в нём функциональность поиска секретов в коде на основе связки сигнатурного поиска и оценки энтропии строковых литералов (или любой другой понятный вам кейс кодинга).
Часть 5.
Часть 3
4. Автономные ИИ-агенты
Итак, промпты писать научились, обогащать контекст актуальными знаниями с помощью RAG — тоже, но кое-чего ещё не хватает. Большинство привычных ИИ-сервисов представляют собой множество модулей, каждый из которых решает какую-либо конкретную задачу, планируя решение с помощью LLM и заданных правил, и имея в распоряжении внешний инструментарий для взаимодействия со внешним миром: от поиска в сети, до генерации и выполнения кода в реальной среде. Такие модули называются ИИ-агентами. Наиболее близкой и понятной разработчикам аналогией агентов в классической разработке, пожалуй, являются микросервисы.
Вообще, есть годные курсы по ИИ-агентам от Microsoft и Hugging Face, гайд от OpenAI, и исчерпывающий AI Agents Handbook, полностью погружающие в эту (и следующую, btw) темы. Но мы же здесь говорим о быстром старте?
AI-агенты — это автономные программы, способные самостоятельно планировать и выполнять задачи на основе целей пользователя. В основе агента обычно лежит LLM, далеко не всегда мощная, которая понимает запрос и формирует решение, и при необходимости использует инструменты — внешние функции, API или базы знаний. Проще говоря, вы даёте агенту задачу — он сам решает, что делать и как, действуя в цифровой среде подобно разумному ассистенту. Всю вводную информацию, необходимую для старта, можно подчерпнуть из статьи «AI-агенты на основе LLM и мультиагентные системы».
Различают два основных типа агентов: реактивные (мгновенно реагируют на входные данные) и проактивные (могут планировать шаги для долгосрочных целей). Как правило, агент состоит из нескольких ключевых компонентов, формирующих пайплайн решения задачи: восприятие, анализ, действие, память и т.п. Типам и структуре агента, организации взаимодействия между его компонентами, вместе с их базовой реализацией, посвящена статья «Agents 101: Как создать своего первого ИИ-агента за 30 минут».
Разумеется, здесь никуда без паттернов. Аналогом GoF в мире агентов является «Agentic AI Handbook: Design Patterns», описывающая свыше сотни различных шаблонов проектирования и разработки агентов. Наиболее популярными из них являются:
Workflow паттерны:
• Prompt Chaining — последовательный разбор задачи шаг за шагом (outline → проверка → генерация);
• Routing/Handoff — выбор исполнителя (агента или модели) для подзадачи;
• параллелизация — выполнение независимых шагов одновременно.
Agentic паттерны:
• Reflection — агент оценивает и улучшает свой ответ, устраняя ошибки и уточняя детали;
• Tool Use — агент использовать внешние инструменты (API, поиск, код) в процессе;
• ReAct (Reason + Act) — итеративный цикл: рассуждение → действие → наблюдение → повтор;
• Planning — разбивка задачи, создание плана с подзадачами и последовательное выполнение;
• Multi-Agent — распределение ролей между агентами, коллективное решение сложных задач (приведен для полноты картины, этой теме будет посвящена следующая часть).
Ознакомиться с подходами к реализации этих и других популярных паттернов можно в статьях:
«AI Agents Design Patterns Explained»
«Building effective agents»
«Zero to One: Learning Agentic Patterns»
Также, стоит упомянуть класс паттернов «Schema-Guided Reasoning» (SGR), позволяющий LLM создавать структурированные, понятные и предсказуемые результаты, удобные для дальнейшей обработки компонентами агента.
В качестве примеров готовых агентов и реализуемых ими кейсов можно смело брать на изучение проекты из репозитория «500 AI Agents Projects».
Задачка на потренироваться:
Пройти воркшоп «Build Your Own Coding Agent» и доработать получившийся проект, реализовав в нём функциональность поиска секретов в коде на основе связки сигнатурного поиска и оценки энтропии строковых литералов (или любой другой понятный вам кейс кодинга).
Часть 5.
4🔥7👍3⚡1
🧩 Принципы и паттерны безопасной разработки: SRP
Хоть это и не вполне очевидно, но разработка безопасных приложений может (а, возможно, и должна) начинаться, отнюдь не с моделирования угроз, внедрения в код механизмов защиты, ревью безопасности, пентестов, внедрения SCA/SAST/DAST, или, тем более, чего-то, вроде хантовского «Hack Yourself First»✝️ В лучших традициях Shift Left Security, начинать стоит с базовых принципов разработки, таких, как SOLID, YAGNI, DRY, KISS, чистый код с архитектурой и т.п. Именно они позволяют заложить в архитектуру и реализацию приложения правильный фундамент, на котором будет гораздо проще и дешевле реализовывать прочие решения и этапы внедрения DevSecOps.
Начнём с принципа единственной ответственности (Single Responsibility Principle, SRP — первая буква в SOLID), утверждающему, что каждый класс или модуль должен иметь единственную ответственность (только одну причину для изменения). С точки зрения безопасности SRP способствует изолированности компонентов и чётким границам доверия в коде, что существенно облегчает последующую работу с моделью угроз. Когда компонент сконцентрирован на одной задаче, его легче проверять на уязвимости и логические ошибки. Это снижает риск скрытых багов, возникающих при смешении разных обязанностей (например, проверка прав доступа вперемешку с бизнес-логикой). Как отмечают эксперты, соблюдение SRP «ограничивает случайную эскалацию привилегий и упрощает поиск ошибок», а также уменьшает общую поверхность атаки за счёт уменьшения сложности компонентов.
Тривиальный пример: допустим, класс UserAuth одновременно проверяет пароль пользователя и создаёт сессию при входе.
Нарушение SRP может выглядеть так:
В этом коде смешаны проверки безопасности (надежность пароля) и бизнес-логика сессии. Если разработчик решит изменить логику создания сессии, есть риск ненароком ослабить или обойти шаг проверки пароля. Правильнее разделить эти обязанности на отдельные классы (например,
Забавно, что «живым» примером последствий нарушения SRP является одна из наиболее нашумевших уязвимостей в библиотеке логирования Apache Log4j 2 CVE-2021-44228, известная как Log4Shell. Логирование — это задача записи сообщений, но Log4j помимо этого выполнял ещё и роль интерпретатора/поисковика ресурсов (JNDILookup). Фактически, в библиотеку логирования «просочилась» функциональность, выходящая за рамки её единственной ответственности — она не только записывала логи, но и могла выполнять сетевые запросы и загружать код. Если бы Log4j ограничился исключительно записью логов, без вычисления каких-либо lookup-выражений, уязвимость бы не возникла. И действительно, исправление проблемы заключалось в отключении/удалении функции JNDI Lookup из Log4j.
Соблюдение SRP помогает избежать многих CWE, связанных с логическими ошибками и неправильной проверкой условий, которые трудно выявить в нагромождённом коде. Например, SRP предотвращает появление скрытых дефектов управления доступом, из разряда CWE-732, CWE-862, возникающих, когда проверка прав смешана с другими функциями и может быть пропущена.
В целом, SRP укрепляет принцип «secure by design»: мелкие простые модули легче защитить и проверить.
Хоть это и не вполне очевидно, но разработка безопасных приложений может (а, возможно, и должна) начинаться, отнюдь не с моделирования угроз, внедрения в код механизмов защиты, ревью безопасности, пентестов, внедрения SCA/SAST/DAST, или, тем более, чего-то, вроде хантовского «Hack Yourself First»
Начнём с принципа единственной ответственности (Single Responsibility Principle, SRP — первая буква в SOLID), утверждающему, что каждый класс или модуль должен иметь единственную ответственность (только одну причину для изменения). С точки зрения безопасности SRP способствует изолированности компонентов и чётким границам доверия в коде, что существенно облегчает последующую работу с моделью угроз. Когда компонент сконцентрирован на одной задаче, его легче проверять на уязвимости и логические ошибки. Это снижает риск скрытых багов, возникающих при смешении разных обязанностей (например, проверка прав доступа вперемешку с бизнес-логикой). Как отмечают эксперты, соблюдение SRP «ограничивает случайную эскалацию привилегий и упрощает поиск ошибок», а также уменьшает общую поверхность атаки за счёт уменьшения сложности компонентов.
Тривиальный пример: допустим, класс UserAuth одновременно проверяет пароль пользователя и создаёт сессию при входе.
Нарушение SRP может выглядеть так:
class UserAuth {
public Session Authenticate(string username, string password) {
// Фрагмент, работающий с новыми пользователями
if (!PasswordChecker.IsStrong(password)) {
throw new Exception("Weak password");
}
var user = userRepository.CreateUser(username, password);
return sessionManager.StartSession(user);
}
}В этом коде смешаны проверки безопасности (надежность пароля) и бизнес-логика сессии. Если разработчик решит изменить логику создания сессии, есть риск ненароком ослабить или обойти шаг проверки пароля. Правильнее разделить эти обязанности на отдельные классы (например,
PasswordChecker, UserRepository, SessionManager), а UserAuth сделать оркестратором. Тогда код станет понятнее и безопаснее: каждая часть легко проверяется и тестируется отдельно.Забавно, что «живым» примером последствий нарушения SRP является одна из наиболее нашумевших уязвимостей в библиотеке логирования Apache Log4j 2 CVE-2021-44228, известная как Log4Shell. Логирование — это задача записи сообщений, но Log4j помимо этого выполнял ещё и роль интерпретатора/поисковика ресурсов (JNDILookup). Фактически, в библиотеку логирования «просочилась» функциональность, выходящая за рамки её единственной ответственности — она не только записывала логи, но и могла выполнять сетевые запросы и загружать код. Если бы Log4j ограничился исключительно записью логов, без вычисления каких-либо lookup-выражений, уязвимость бы не возникла. И действительно, исправление проблемы заключалось в отключении/удалении функции JNDI Lookup из Log4j.
Соблюдение SRP помогает избежать многих CWE, связанных с логическими ошибками и неправильной проверкой условий, которые трудно выявить в нагромождённом коде. Например, SRP предотвращает появление скрытых дефектов управления доступом, из разряда CWE-732, CWE-862, возникающих, когда проверка прав смешана с другими функциями и может быть пропущена.
В целом, SRP укрепляет принцип «secure by design»: мелкие простые модули легче защитить и проверить.
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍7🔥3❤🔥2💯1
Эстетика ИИ-агентов: Claude Code
Последнее время появляется всё больше и больше хвалебных статей и отзывов о Claude Code. В некоторых из них его даже называют образчиком правильного подхода к разработке agentic-решений. Почему так?
Он прост, практичен, и вызывает минимум когнитивной нагрузки у своего пользователя 🤷♂️ Может и не блестяще, но весьма добротно решая при этом те задачи, под которые был разработан. Вот такой простой рецепт успешного успеха)
Не вполне уверен насчёт прям образчика разработки agentic-решений (насмотренности не хватает), но примером следования KISS, до ощутимого удовольствия в органах эстетического восприятия, Claude Code совершенно точно является. И, как по мне, вполне себе тянет на решение, из которого совершенно не зазорно заимствовать принципы и подходы при разработке собственных ИИ-агентов.
Относительно поверхностно ознакомиться с особенностями реализации Claude Code можно в статье «What makes Claude Code so damn good (and how to recreate that magic in your agent)!?» Детальнейший же (и весьма немаленький) разбор архитектуры и реализации этого агента доступен в отчете «Claude Code: An analysis». И, поверьте, там есть на что посмотреть)
Ну и, на всякий случай, вот ещё awesome-подборка материалов по Claude Code, чтобы попробовать его в деле, задействуя максимум возможностей, если вдруг ещё не.
Последнее время появляется всё больше и больше хвалебных статей и отзывов о Claude Code. В некоторых из них его даже называют образчиком правильного подхода к разработке agentic-решений. Почему так?
Он прост, практичен, и вызывает минимум когнитивной нагрузки у своего пользователя 🤷♂️ Может и не блестяще, но весьма добротно решая при этом те задачи, под которые был разработан. Вот такой простой рецепт успешного успеха)
Не вполне уверен насчёт прям образчика разработки agentic-решений (насмотренности не хватает), но примером следования KISS, до ощутимого удовольствия в органах эстетического восприятия, Claude Code совершенно точно является. И, как по мне, вполне себе тянет на решение, из которого совершенно не зазорно заимствовать принципы и подходы при разработке собственных ИИ-агентов.
Относительно поверхностно ознакомиться с особенностями реализации Claude Code можно в статье «What makes Claude Code so damn good (and how to recreate that magic in your agent)!?» Детальнейший же (и весьма немаленький) разбор архитектуры и реализации этого агента доступен в отчете «Claude Code: An analysis». И, поверьте, там есть на что посмотреть)
Ну и, на всякий случай, вот ещё awesome-подборка материалов по Claude Code, чтобы попробовать его в деле, задействуя максимум возможностей, если вдруг ещё не.
1👍5❤2🍾1🦄1
Абстрактная интерпретация и символьное выполнение: в чем разница?
Пост родился по мотивам вчерашних обсуждений ссобратьями по несчастью коллегами. Дело в том, что эти два подхода к анализу приложений здорово путают, а иногда считают одно подмножеством другого. На самом деле, все чуть сложнее)
При символьном выполнении код интерпретируется, или выполняется, в соответствии с подмножеством семантики целевого языка, заменой всех неизвестных значений (входных данных) символьными переменными и вычислением формул в модели памяти, вместо конкретных значений. Подмножеством — потому что, невычислимые и сложно-вычислимые конструкции (вроде циклов и рекурсии, инварианты которых включают символьные переменные) упрощаются различными способами, про которые в академическом мире пишут целые диссертации. В реальном же мире SAST, как правило, просто ограничиваются «прокруткой» таких конструкций фиксированное количество раз или охапкой эвристик.
Основной челлендж разработчиков SAST, работающих в парадигме символьного выполнения: приемлемая аппроксимация семантики языка и эффективное решение проблемы экспоненциального роста путей выполнения или множества значений. Короче, долго, «дорого» (в плане сложности реализации), но относительно точно.
Абстрактная интерпретация же — это размен точности на скорость, при примерно той же «стоимости». Вместо неизвестных значений берутся их приближения: «переменная
Проще пояснить на примере вычисления цикла:
Символьное выполнение (один из подходов):
– принимает число итераций за неизвестную переменную
– выводит через интерпретацию уравнение
– находит, например,
– крутит цикл k раз.
Относительно точно, но для сложных циклов всё же нужны инварианты (см. диссертацию выше), иначе анализ взорвётся по путям выполнения. На практике, в реальных приложениях, для подобного цикла — это произойдет задолго до приближения к 50-ой итерации.
Абстрактная интерпретация (интервальный домен):
– начнём с
– каждую итерацию добавляем 2:
– рост бесконечный, поэтому применяем widening («перепрыгиваем» через растущие приближения, чтобы гарантировать быстрое достижение фиксированной точки, пусть и грубым образом) и прыгаем к границе
– потом применяем narrowing (уточняем полученное приближение, чтобы вернуть часть точности, которую потеряли на шаге widening) и условие выхода из цикла уточняют результат до
Интервалы говорят: «на выходе точно
Если взять домен «чёт/нечет», анализ сохранит инвариант:
Таким образом, эти два подхода действительно принадлежат одному семейству в том смысле, что осуществляют интерпретацию кода. Но символьное выполнение полагается в большей степени на упрощение семантики языка, в то время, как абстрактная интерпретация — на упрощение семантики данных, заданное на старте интерпретации.
Но вообще, отвечая на вопрос, является ли одно подмножеством другого... если у абстрактной интерпретации отрезать все ограничения на входные данные, и основанные на них техники вычисления циклов и рекурсии, но пришить при этом упрощение семантики языка, то из дедушки возможно и получится бабушка🤷♂️
В любой непонятной ситуации, когда станет совсем скучно — заводи спор о терминологии...
Пост родился по мотивам вчерашних обсуждений с
При символьном выполнении код интерпретируется, или выполняется, в соответствии с подмножеством семантики целевого языка, заменой всех неизвестных значений (входных данных) символьными переменными и вычислением формул в модели памяти, вместо конкретных значений. Подмножеством — потому что, невычислимые и сложно-вычислимые конструкции (вроде циклов и рекурсии, инварианты которых включают символьные переменные) упрощаются различными способами, про которые в академическом мире пишут целые диссертации. В реальном же мире SAST, как правило, просто ограничиваются «прокруткой» таких конструкций фиксированное количество раз или охапкой эвристик.
Основной челлендж разработчиков SAST, работающих в парадигме символьного выполнения: приемлемая аппроксимация семантики языка и эффективное решение проблемы экспоненциального роста путей выполнения или множества значений. Короче, долго, «дорого» (в плане сложности реализации), но относительно точно.
Абстрактная интерпретация же — это размен точности на скорость, при примерно той же «стоимости». Вместо неизвестных значений берутся их приближения: «переменная
x в [0..10]», или «переменная y чётная», или (в продвинутых техниках) «переменная s определяется конечным автоматом [a-zA-Z]+». Это формирует т.н. домен интерпретации. И далее осуществляется интерпретация кода в соответствии с определенным доменом. Анализ завершается в куда более приемлемое время, и охватывает все пути, но ценой роста процента ложных срабатываний.Проще пояснить на примере вычисления цикла:
def g(x):
while x < 100:
x = x + 2
return x
Символьное выполнение (один из подходов):
– принимает число итераций за неизвестную переменную
k;– выводит через интерпретацию уравнение
x0 + 2k = 100 и ищет его решения;– находит, например,
x0 = 0, k = 50;– крутит цикл k раз.
Относительно точно, но для сложных циклов всё же нужны инварианты (см. диссертацию выше), иначе анализ взорвётся по путям выполнения. На практике, в реальных приложениях, для подобного цикла — это произойдет задолго до приближения к 50-ой итерации.
Абстрактная интерпретация (интервальный домен):
– начнём с
x ∈ [0..50];– каждую итерацию добавляем 2:
[0..52] → [0..54] → …;– рост бесконечный, поэтому применяем widening («перепрыгиваем» через растущие приближения, чтобы гарантировать быстрое достижение фиксированной точки, пусть и грубым образом) и прыгаем к границе
[0..+∞);– потом применяем narrowing (уточняем полученное приближение, чтобы вернуть часть точности, которую потеряли на шаге widening) и условие выхода из цикла уточняют результат до
[100..+∞).Интервалы говорят: «на выходе точно
x ≥ 100», но теряют информацию о чётности.Если взять домен «чёт/нечет», анализ сохранит инвариант:
x ≡ x0 (mod 2). Это уже лучше, чем только интервалы, но и дороже.Таким образом, эти два подхода действительно принадлежат одному семейству в том смысле, что осуществляют интерпретацию кода. Но символьное выполнение полагается в большей степени на упрощение семантики языка, в то время, как абстрактная интерпретация — на упрощение семантики данных, заданное на старте интерпретации.
Но вообще, отвечая на вопрос, является ли одно подмножеством другого... если у абстрактной интерпретации отрезать все ограничения на входные данные, и основанные на них техники вычисления циклов и рекурсии, но пришить при этом упрощение семантики языка, то из дедушки возможно и получится бабушка
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥9💯2🍓1