Есть мнение, что разработка - это молодая отрасль. Этим часто объясняется ее несовершенство. Нет чётких законов, парадигмы меняются, всегда приходится идти на компромиссы. Как пример - те же принципы чистого кода нельзя понимать буквально, за что книгу часто критикуют.
Но посмотрим, когда появились некоторые ключевые идеи.
Закон Конвея, упомянутый ранее https://t.me/javaKotlinDevOps/301 - структура кода повторяет структуру организации - 1967 год. Практически 60 лет назад.
Спор о вреде go to (а это значит, что он уже активно использовался) начал Дейкстра в письме Go To Statement Considered Harmful практически тогда же - 1968 году. 58 лет назад. Дискуссии, к слову, тогда велись через письма в журналы. В рамках дискуссии о go to понятие спагетти-код стало общепринятым примерно в 1977 году. 49 лет назад.
В 1970 году сотрудник IBM Эдгар Кодд опубликовал статью «A Relational Model of Data for Large Shared Data Banks», которая стала фундаментом для всех реляционных баз данных. В 1979 году появилась первая коммерческая реляционная СУБД Oracle. 56 и 47 лет соответственно.
Мифический человеко-месяц был написан в 1975 году. Знаменитый закон Брукса: добавление разработчиков ближе к концу проекта лишь увеличивает его сроки. А на русский книга была переведена в 1979 году, соответственно, в СССР. Это 51 и 47 лет назад. Я ещё не родился)
Совершенный код (да, опять), первое издание - 1993 год. 33 года назад.
Java 1.0 (еще без collections, не говоря уже и стримах, generic, enum, JDBC и многого другого) появилась в 1996 - 30 лет в этом году.
В 1999 был сформирован DRY («Don't Repeat Yourself» — «Не повторяй себя») Эндрю Хантом и Дэвидом Томасом в книге The Pragmatic Programmer. 27 лет назад. Принцип KISS сильно моложе, но его снимем с дистанции - он появится в ВВС США.
Принципы SOLID были сформулированы на год позже Робертом Мартином в статье Design Principles and Design Patterns. 26 лет назад.
Тогда же вышла книжка Кента Бека про XP (экстремальное программирование, включая TDD). И в 2001 Agile Manifest, который с ним связан.
В 2001 году появилась IDEA и рефакторинг стал доступен всем. Ну почти всем , Community появилась на 8 лет позже и началось ее победное шествие. 25 лет назад.
И лишь Docker, Kafka, DevOps, Kotlin можно считать относительно новыми - 15-20 лет назад. K8s так вообще чуть больше 10 лет.
Т.е. отрасль все же достигла зрелости.
И тут пришёл AI и хочет ее отменить)
Но это уже другая история)
#it_history
Но посмотрим, когда появились некоторые ключевые идеи.
Закон Конвея, упомянутый ранее https://t.me/javaKotlinDevOps/301 - структура кода повторяет структуру организации - 1967 год. Практически 60 лет назад.
Спор о вреде go to (а это значит, что он уже активно использовался) начал Дейкстра в письме Go To Statement Considered Harmful практически тогда же - 1968 году. 58 лет назад. Дискуссии, к слову, тогда велись через письма в журналы. В рамках дискуссии о go to понятие спагетти-код стало общепринятым примерно в 1977 году. 49 лет назад.
В 1970 году сотрудник IBM Эдгар Кодд опубликовал статью «A Relational Model of Data for Large Shared Data Banks», которая стала фундаментом для всех реляционных баз данных. В 1979 году появилась первая коммерческая реляционная СУБД Oracle. 56 и 47 лет соответственно.
Мифический человеко-месяц был написан в 1975 году. Знаменитый закон Брукса: добавление разработчиков ближе к концу проекта лишь увеличивает его сроки. А на русский книга была переведена в 1979 году, соответственно, в СССР. Это 51 и 47 лет назад. Я ещё не родился)
Совершенный код (да, опять), первое издание - 1993 год. 33 года назад.
Java 1.0 (еще без collections, не говоря уже и стримах, generic, enum, JDBC и многого другого) появилась в 1996 - 30 лет в этом году.
В 1999 был сформирован DRY («Don't Repeat Yourself» — «Не повторяй себя») Эндрю Хантом и Дэвидом Томасом в книге The Pragmatic Programmer. 27 лет назад. Принцип KISS сильно моложе, но его снимем с дистанции - он появится в ВВС США.
Принципы SOLID были сформулированы на год позже Робертом Мартином в статье Design Principles and Design Patterns. 26 лет назад.
Тогда же вышла книжка Кента Бека про XP (экстремальное программирование, включая TDD). И в 2001 Agile Manifest, который с ним связан.
В 2001 году появилась IDEA и рефакторинг стал доступен всем. Ну почти всем , Community появилась на 8 лет позже и началось ее победное шествие. 25 лет назад.
И лишь Docker, Kafka, DevOps, Kotlin можно считать относительно новыми - 15-20 лет назад. K8s так вообще чуть больше 10 лет.
Т.е. отрасль все же достигла зрелости.
И тут пришёл AI и хочет ее отменить)
Но это уже другая история)
#it_history
Telegram
(java || kotlin) && devOps
Всем привет!
Разработка ПО - очень динамичная сфера. Мэйнфреймы, ассемблер, CSV, RDBMS, C, Delphi, Java, REST, MQ, git, DevOps, Docker, k8s, Kafka, noSQL, microservices, reactive programming, DataLake, GitOps, ChatGPT...
Но есть вещи, которые не меняются.…
Разработка ПО - очень динамичная сфера. Мэйнфреймы, ассемблер, CSV, RDBMS, C, Delphi, Java, REST, MQ, git, DevOps, Docker, k8s, Kafka, noSQL, microservices, reactive programming, DataLake, GitOps, ChatGPT...
Но есть вещи, которые не меняются.…
👍4❤1
Чем похожи LLM и blockchain?
И там, и там для генерации следующего элемента используют данные предыдущих. И LLM также не может изменить уже сгенерированные токены, даже если в какой-то момент поняла, что они не верны. Ну и ещё потому что у нас как правило стриминг и пользователь уже их увидел)
Разница конечно есть - в blockchain вся цепочка живёт вечно, а LLM ограничена длиной контекстного окна и возможностью чата/агента хранить историю
И эта особенность является одной из причин галлюцинаций LLM. Т.к. придя к неверному выводу модель опирается на него в дальнейших ответах.
#ai
Разница конечно есть - в blockchain вся цепочка живёт вечно, а LLM ограничена длиной контекстного окна и возможностью чата/агента хранить историю
И эта особенность является одной из причин галлюцинаций LLM. Т.к. придя к неверному выводу модель опирается на него в дальнейших ответах.
#ai
В продолжение предыдущего поста - почему модели галлюцинируют?
Попробую собрать все возможные причины:
1) как уже говорил - один раз сделав неверный вывод модель не может его исправить, он ложится в ее контекст, на основании которого выдаются все последующие ответы.
Да, не все токены из контекста выбираются при генерации ответа, только наиболее близкие (скалярное произведение векторов). И когда в диалоге появляются новые токены, более релевантные - например, "твой ответ неверный, обрати внимание на ..." - они "забивают" старые.
Иначе модель будет строить всю цепочку рассуждений опираясь на неверный вывод.
2) неверные данные от пользователя. Модель верит пользователю. Почему?
Модель обучалась на каких-то открытых документах. Форумы, новости, GitHub,... Сколько там неверной информации?
Она конечно есть, но в большинство документов содержит более менее актуальную информацию.
Модель, соответственно, ожидает, что пользователь тоже дает ей верную информацию.
Особенно в тех областях, по которым нет явно опровергающих это фактов.
Земля плоская - опровержений много. Я уже установил последнюю версию драйверов - как это проверить?) Есть OpenClaws, но я бы не рискнул ставить его на свой компьютер)
3) модель в принципе не оперирует понятиями ложь и правда. Она ищет наиболее вероятный следующий токен, из которых в итоге появляется фраза.
Вероятность зависит от данных обучения и предыдущего диалога. Т.е. ей нужен внешний арбитр, который знает - что правда, а что нет.
Это может быть другая модель - но в целом у нее те же проблемы. Или человек - т.е. информацию надо перепроверять.
4) И самое интересное.
Если точных данных нет, а это как раз самые интересные и сложные кейсы - модель их может угадать.
Может угадать, может не угадать.
Но на обучении - Supervised fine-tuning (SFT) и Reinforcement Learning (RL) - модель оценивают по проценту верных ответов.
Все бенчмарки для людей о том же - процент правильных ответов.
Т.е. для модели лучшая стратегия - что-то придумать, чем честно сказать "Я не знаю".
Об этом даже авторы OpenAI пишут и предлагают менять систему оценок: https://openai.com/ru-RU/index/why-language-models-hallucinate
В итоге имеем то, что имеем)
#ai
Попробую собрать все возможные причины:
1) как уже говорил - один раз сделав неверный вывод модель не может его исправить, он ложится в ее контекст, на основании которого выдаются все последующие ответы.
Да, не все токены из контекста выбираются при генерации ответа, только наиболее близкие (скалярное произведение векторов). И когда в диалоге появляются новые токены, более релевантные - например, "твой ответ неверный, обрати внимание на ..." - они "забивают" старые.
Иначе модель будет строить всю цепочку рассуждений опираясь на неверный вывод.
2) неверные данные от пользователя. Модель верит пользователю. Почему?
Модель обучалась на каких-то открытых документах. Форумы, новости, GitHub,... Сколько там неверной информации?
Она конечно есть, но в большинство документов содержит более менее актуальную информацию.
Модель, соответственно, ожидает, что пользователь тоже дает ей верную информацию.
Особенно в тех областях, по которым нет явно опровергающих это фактов.
Земля плоская - опровержений много. Я уже установил последнюю версию драйверов - как это проверить?) Есть OpenClaws, но я бы не рискнул ставить его на свой компьютер)
3) модель в принципе не оперирует понятиями ложь и правда. Она ищет наиболее вероятный следующий токен, из которых в итоге появляется фраза.
Вероятность зависит от данных обучения и предыдущего диалога. Т.е. ей нужен внешний арбитр, который знает - что правда, а что нет.
Это может быть другая модель - но в целом у нее те же проблемы. Или человек - т.е. информацию надо перепроверять.
4) И самое интересное.
Если точных данных нет, а это как раз самые интересные и сложные кейсы - модель их может угадать.
Может угадать, может не угадать.
Но на обучении - Supervised fine-tuning (SFT) и Reinforcement Learning (RL) - модель оценивают по проценту верных ответов.
Все бенчмарки для людей о том же - процент правильных ответов.
Т.е. для модели лучшая стратегия - что-то придумать, чем честно сказать "Я не знаю".
Об этом даже авторы OpenAI пишут и предлагают менять систему оценок: https://openai.com/ru-RU/index/why-language-models-hallucinate
В итоге имеем то, что имеем)
#ai
OpenAI
Почему языковые модели испытывают галлюцинации
Новая научная публикация OpenAI объясняет, почему языковые модели выдают галлюцинации. Результаты показывают, как улучшенные оценки могут повысить надежность, честность и безопасность ИИ.
Все AI dev агенты делятся на 2 категории по тому, как хранят свои правила.
Один файл:
Claude Code — CLAUDE.md
Gemini CLI — GEMINI.md
OpenAI Codex CLI — AGENTS.md
JetBrains Junie — .junie/guidelines.md
Папка с несколькими файлами:
Cursor — .cursor/rules/*.mdc
Windsurf — .windsurf/rules/*.md
Cline — .clinerules/*.md
Roocode — .roo/rules/*.md
GitHub Copilot — .github/instructions/*.instructions.md
JetBrains AI Assistant — .aiassistant/rules/*.md
Continue — .continue/rules/*.md
GigaCode - .gitverse/pr_rules/*.md (для версии на GitVerse)
Cline тут выделяется тем, что вообще говоря позволяет оба варианта - файл .clinerules или одноименный каталог.
Особенность Claude - кастомные команды, хранятся в кастомные команды в ~/.claude/commands/<name>.md. В принципе можно использовать и как аналог rule при явном указании в чате. Но без автозагрузки.
И еще сильнее выделяется OpenCode.
Он вначале пытается быть совместимым с OpenAI (AGENTS.md), если не нашел - с Claude Code (CLAUDE.md). А кроме того позволяет через customInstructions в opencode.json подключать произвольные файлы, включая загрузку по http, что является уникальной фичей.
Какие плюсы\минусы у этих подходов?
Один файл - простота.
Особенно учитывая тот факт, что практически ни один агент не дает менять имя файла\папки - т.е. имеем дело с convention over configuration во всей красе.
Пару слов про смену имени: единственное исключение - Gemini CLI, позволяет задать contextFileName в settings.json.
Еще в теории с этим подходом больше шансов получить непротиворечивые правила, но с ростом размера файла это преимущество нивелируется.
Каталог - а мне этот вариант кажется более удобным - имеет следующие плюсы:
1) если в репо лежит разнородный код, который пишут разные люди: фронт, бэк, devops, автотесты то удобнее, если у каждого будет свой файл с правилами. Да, AI способствует T-shape, но это пока что процесс, а не свершившийся факт.
2) несколько файлов точно легче читать и править человеку. А со слабыми моделями - возможно и LLM.
3) в теории при наличии нескольких файлов LLM исходя из текущей задачи сама могла бы выбрать только нужные, тем самым уменьшив расход токенов и контекстного окна и ускорив работу.
Обходной вариант для single rule агентов - можно указать в промте или rules: "прочитай инструкции из каталога xxx", - и т.об решить проблему. Но это менее надежно.
И главный вопрос - как избежать vendor lock и не нарушать DRY?
Делаем базовую папку с правилами, дале в Windows - создаем ссылку с помощью junction, в Linux - symlink.
И лучше добавить в .gitignore для надежности, чтобы случайно не задублировалось.
Для single rule агентов можно навайбкодить утилиту по склеиванию всех файлов в один, или использовать готовую cursor2claude.
Но вообще говоря эта область прям напрашивается на стандартизацию - либо через convention, либо через использование отдельного компонента.
#ai #ai_agents
Один файл:
Claude Code — CLAUDE.md
Gemini CLI — GEMINI.md
OpenAI Codex CLI — AGENTS.md
JetBrains Junie — .junie/guidelines.md
Папка с несколькими файлами:
Cursor — .cursor/rules/*.mdc
Windsurf — .windsurf/rules/*.md
Cline — .clinerules/*.md
Roocode — .roo/rules/*.md
GitHub Copilot — .github/instructions/*.instructions.md
JetBrains AI Assistant — .aiassistant/rules/*.md
Continue — .continue/rules/*.md
GigaCode - .gitverse/pr_rules/*.md (для версии на GitVerse)
Cline тут выделяется тем, что вообще говоря позволяет оба варианта - файл .clinerules или одноименный каталог.
Особенность Claude - кастомные команды, хранятся в кастомные команды в ~/.claude/commands/<name>.md. В принципе можно использовать и как аналог rule при явном указании в чате. Но без автозагрузки.
И еще сильнее выделяется OpenCode.
Он вначале пытается быть совместимым с OpenAI (AGENTS.md), если не нашел - с Claude Code (CLAUDE.md). А кроме того позволяет через customInstructions в opencode.json подключать произвольные файлы, включая загрузку по http, что является уникальной фичей.
Какие плюсы\минусы у этих подходов?
Один файл - простота.
Особенно учитывая тот факт, что практически ни один агент не дает менять имя файла\папки - т.е. имеем дело с convention over configuration во всей красе.
Пару слов про смену имени: единственное исключение - Gemini CLI, позволяет задать contextFileName в settings.json.
Еще в теории с этим подходом больше шансов получить непротиворечивые правила, но с ростом размера файла это преимущество нивелируется.
Каталог - а мне этот вариант кажется более удобным - имеет следующие плюсы:
1) если в репо лежит разнородный код, который пишут разные люди: фронт, бэк, devops, автотесты то удобнее, если у каждого будет свой файл с правилами. Да, AI способствует T-shape, но это пока что процесс, а не свершившийся факт.
2) несколько файлов точно легче читать и править человеку. А со слабыми моделями - возможно и LLM.
3) в теории при наличии нескольких файлов LLM исходя из текущей задачи сама могла бы выбрать только нужные, тем самым уменьшив расход токенов и контекстного окна и ускорив работу.
Обходной вариант для single rule агентов - можно указать в промте или rules: "прочитай инструкции из каталога xxx", - и т.об решить проблему. Но это менее надежно.
И главный вопрос - как избежать vendor lock и не нарушать DRY?
Делаем базовую папку с правилами, дале в Windows - создаем ссылку с помощью junction, в Linux - symlink.
И лучше добавить в .gitignore для надежности, чтобы случайно не задублировалось.
Для single rule агентов можно навайбкодить утилиту по склеиванию всех файлов в один, или использовать готовую cursor2claude.
Но вообще говоря эта область прям напрашивается на стандартизацию - либо через convention, либо через использование отдельного компонента.
#ai #ai_agents
Agile мир победил, микросервисы оказались сильней)
Вот данные из моей любимой книжки по разработке.
Медиану можно оценить ~9, среднее ~19, но среднее мало информативно из-за сильной правой асимметрии (маленьких команд сильно больше, чем больших).
Я бы из него сделал вывод, что микросервисы были всегда, просто раньше назывались по-другому — например, SOA (Service Oriented Architecture).
Но конечно ситуация меняется(хотел написать «не могла не измениться», но вспомнил свой же пост про двойное отрицание))) .
А вот более современные данные, не такие подробные.
Если сравнить 2003 и 2012 годы — медиана уменьшилась почти в 2 раза: 9 → 5.
Ещё есть данные опроса пользователей JetBrains (2024) https://www.jetbrains.com/lp/devecosystem-2024/
Медиана ≈ 6 человек, среднее ≈ 11. Примерно то же, что в 2012, только как ни странно числа стали чуть больше). Зато видно, что больших команд стало в 2+ раза меньше.
По моему опыту (кровавый enterprise) медианный размер команды на данный момент выше, ближе к 9. Но то, что 80% команд укладываются в 12 человек — сходится.
В 2003 году было ~60%.
Т.е. мы пока одной ногой шагнули в новую эру) enterprise требует жертв. Но тренд понятен.
О причинах — часть уже назвал: Agile и микросервисы. Ещё — улучшившийся инструментарий: IDE и фреймворки/библиотеки под любую потребность. А сейчас ещё и AI.
Так что думаю, что к 6 людям в команде мы все скоро придём. Будет ли меньше? В теории да: ВП, аналитик, 1–2 разработчика, тестировщик.
P.S. Т.к. в таблицах процент команд, а не процент людей - в командах более 12 человек все еще работает более 50% разработчиков. Было - более 80%. Интересно кто это?
P.P.S. Станет ли медианным значением 1 — ВП, который с помощью AI пилит и тестирует сервисы сам? ...Где-то да, уже сейчас. Но массово — может помешать Skynet. Или поспособствовать — сидишь себе в матрице, вайб-кодишь с AI микросервисы.
#book_review #agile #ai #microservices
Вот данные из моей любимой книжки по разработке.
Процентное соотношение проектов по размеру команды:
Размер команды | Доля
----------------|------
1–3 человека | 25%
4–10 человек | 30%
11–25 человек | 20%
26–50 человек | 15%
>50 человек | 10%
Источники: Beck and Perkins (1983), Highsmith (2002), Boehm and Turner (2003)
Медиану можно оценить ~9, среднее ~19, но среднее мало информативно из-за сильной правой асимметрии (маленьких команд сильно больше, чем больших).
Я бы из него сделал вывод, что микросервисы были всегда, просто раньше назывались по-другому — например, SOA (Service Oriented Architecture).
Но конечно ситуация меняется
А вот более современные данные, не такие подробные.
В исследовании Rodriguez et al. (JSS, 2012) на базе 951 проекта — 75% имели команду менее 10 человек. Медиана = 5, среднее ≈ 7.9.
Если сравнить 2003 и 2012 годы — медиана уменьшилась почти в 2 раза: 9 → 5.
Ещё есть данные опроса пользователей JetBrains (2024) https://www.jetbrains.com/lp/devecosystem-2024/
Размер команды | Доля
----------------|------
1 человек | 8%
2–7 человек | 49%
8–12 человек | 22%
13–20 человек | 10%
21–40 человек | 6%
>40 человек | 5%
Медиана ≈ 6 человек, среднее ≈ 11. Примерно то же, что в 2012, только как ни странно числа стали чуть больше). Зато видно, что больших команд стало в 2+ раза меньше.
По моему опыту (кровавый enterprise) медианный размер команды на данный момент выше, ближе к 9. Но то, что 80% команд укладываются в 12 человек — сходится.
В 2003 году было ~60%.
Т.е. мы пока одной ногой шагнули в новую эру) enterprise требует жертв. Но тренд понятен.
О причинах — часть уже назвал: Agile и микросервисы. Ещё — улучшившийся инструментарий: IDE и фреймворки/библиотеки под любую потребность. А сейчас ещё и AI.
Так что думаю, что к 6 людям в команде мы все скоро придём. Будет ли меньше? В теории да: ВП, аналитик, 1–2 разработчика, тестировщик.
P.S. Т.к. в таблицах процент команд, а не процент людей - в командах более 12 человек все еще работает более 50% разработчиков. Было - более 80%. Интересно кто это?
P.P.S. Станет ли медианным значением 1 — ВП, который с помощью AI пилит и тестирует сервисы сам? ...Где-то да, уже сейчас. Но массово — может помешать Skynet. Или поспособствовать — сидишь себе в матрице, вайб-кодишь с AI микросервисы.
#book_review #agile #ai #microservices
JetBrains: Developer Tools for Professionals and Teams
Software Developers Statistics 2024 - State of Developer Ecosystem Report
Explore key software developer statistics for 2024 in the State of Developer Ecosystem Report. Trends, insights, and tools shaping the developer world
👍1
Иногда кажется, что если попросить какую-то LLM модель проверить информацию, указав при этом, что получил ее от другой модели - она это делает с какой-то особой тщательностью)))
Скорее всего кажется - как проекция взаимоотношений создателей на их модели. Я про OpenAI, Claude, Grok и Gemini.
Но в любом случае это отличный быстрый способ проверки информации из LLM.
И тут хорош Perplexity, т.к. там все перечисленные модели есть.
#ai
Скорее всего кажется - как проекция взаимоотношений создателей на их модели. Я про OpenAI, Claude, Grok и Gemini.
Но в любом случае это отличный быстрый способ проверки информации из LLM.
И тут хорош Perplexity, т.к. там все перечисленные модели есть.
#ai
Как AI интегрируется в существующие программные продукты?
Пример.
Есть такое понятие как API шлюз - прокси, позволяющий согласовать API из разных источников, навесить туда аутентификацию и авторизацию, rate limiting, мониторинг и некоторые другие функции.
Один из самых известных open source шлюзов - Kong Gateway.
Где тут AI?
А вот https://developer.konghq.com/plugins/?category=ai
Что можно навесить на шлюз:
1) AI Proxy - API разных LLM моделей отличается, поэтому актуальной является конвертация API. Если быть точным: на вход OpenAI API, на выходе - другие модели.
Вот список https://developer.konghq.com/plugins/?category=ai
Почему на входе OpenAI формат думаю понятно, так работает большинство AI Proxy.
2) AI Prompt Decorator - добавляет текст в начало и конец промта. Область применения видится для случаев, когда есть некий AI чат-клиент и недостаточно функционала для AI агента (сервера).
Тогда данный компонент может сформировать системный промт или обогатить промт историей.
Еще важный момент - текст в начале и в конце промта (который мы добавляем таким образом) имеет больший вес для модели.
3) AI Request Transformer\AI Response Transformer - обогащение\преобразование промта с использованием ИИшки.
Например, добавить страну к каждому городу в промте.
Тут конечно важен вопрос скорости, прокси не должен тормозить запрос
4) AI Prompt Guard - ограничение доступных запросов по regexp. Не 100% гарантия, но зато быстро.
5) AI Prompt Template - создаем набор типовых запросов к модели, от клиента просим только заполнить {{параметры}}
Есть еще опции, требующие лицензии, среди них я бы отметил:
1) AI LLM as Judge - валидацию ответа LLM другой моделью из коробки
2) AI MCP Proxy - преобразование протокола MCP в HTTP или объединение нескольких MCP серверов в один + возможность навесить на MCP запрос все фичи API шлюза - аутентификацию, rate limiting, мониторинг. Видится полезным для быстрого подключения существующих сервисов компании как тулов для AI агента.
3) AI Prompt Compressor - сжатие пользовательского промта. Цель - снижение стоимости. Интересно, но обязательно надо тестировать качество получаемых ответов.
4) AI Semantic Cache - кэшируем в векторной БД ответы LLM опять же для снижения стоимости
Выводы.
- все вышеперечисленные плагины можно рассматривать как AI паттерны, которые можно реализовать или на отдельном шлюзе, или внутри сервиса
- AI-шка внедряется в традиционные стеки
#ai
Пример.
Есть такое понятие как API шлюз - прокси, позволяющий согласовать API из разных источников, навесить туда аутентификацию и авторизацию, rate limiting, мониторинг и некоторые другие функции.
Один из самых известных open source шлюзов - Kong Gateway.
Где тут AI?
А вот https://developer.konghq.com/plugins/?category=ai
Что можно навесить на шлюз:
1) AI Proxy - API разных LLM моделей отличается, поэтому актуальной является конвертация API. Если быть точным: на вход OpenAI API, на выходе - другие модели.
Вот список https://developer.konghq.com/plugins/?category=ai
Почему на входе OpenAI формат думаю понятно, так работает большинство AI Proxy.
2) AI Prompt Decorator - добавляет текст в начало и конец промта. Область применения видится для случаев, когда есть некий AI чат-клиент и недостаточно функционала для AI агента (сервера).
Тогда данный компонент может сформировать системный промт или обогатить промт историей.
Еще важный момент - текст в начале и в конце промта (который мы добавляем таким образом) имеет больший вес для модели.
3) AI Request Transformer\AI Response Transformer - обогащение\преобразование промта с использованием ИИшки.
Например, добавить страну к каждому городу в промте.
Тут конечно важен вопрос скорости, прокси не должен тормозить запрос
4) AI Prompt Guard - ограничение доступных запросов по regexp. Не 100% гарантия, но зато быстро.
5) AI Prompt Template - создаем набор типовых запросов к модели, от клиента просим только заполнить {{параметры}}
Есть еще опции, требующие лицензии, среди них я бы отметил:
1) AI LLM as Judge - валидацию ответа LLM другой моделью из коробки
2) AI MCP Proxy - преобразование протокола MCP в HTTP или объединение нескольких MCP серверов в один + возможность навесить на MCP запрос все фичи API шлюза - аутентификацию, rate limiting, мониторинг. Видится полезным для быстрого подключения существующих сервисов компании как тулов для AI агента.
3) AI Prompt Compressor - сжатие пользовательского промта. Цель - снижение стоимости. Интересно, но обязательно надо тестировать качество получаемых ответов.
4) AI Semantic Cache - кэшируем в векторной БД ответы LLM опять же для снижения стоимости
Выводы.
- все вышеперечисленные плагины можно рассматривать как AI паттерны, которые можно реализовать или на отдельном шлюзе, или внутри сервиса
- AI-шка внедряется в традиционные стеки
#ai
Kong Docs
Kong Plugin Hub | Kong Docs
Extend Kong Gateway and Kong Konnect with powerful plugins and easy integrations.
Магические 80% покрытия кода тестами.
Часто возникает вопрос - почему 80?
Краткий ответ - почему бы и нет)
А если серьезно: оценка может быть числовой (процент покрытия) или бинарной (достаточно или нет).
Бинарная плоха тем, что не документирована и зависит от мнения эксперта. Это может привести к проблемам на код-ревью.
А тут умные люди из SonarQube придумали метрику покрытия https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition#coverage
и дали её рекомендуемое значение. И это не 100%, т.е. запас есть.
Считаю, что от этой рекомендации стоит отталкиваться.
К тому же JaCoCo, обычно используемый для расчета покрытия, позволяет гибко настраивать сам процесс.
Следующий вопрос, который может возникнуть: "Почему ради достижения 80% я должен писать тесты на элементарный код?" Я про getter, setter и все, все, все https://t.me/javaKotlinDevOps/34
Ответ: "Нет, не нужны эти тесты".
Лишний код можно исключить из покрытия:
1) generated код исключается по умолчанию начиная с JaCoCo 0.8.2
2) generated код Lombok - через lombok.addLombokGeneratedAnnotation = true (жаль, что только для Lombok это можно сделать, но есть еще альтернатива - см. следующий абзац.)
3) тривиальный код - явно исключая классы или пакеты по маске через настройки JaCoCo. Если какой-то код не получается исключить таким образом - это повод задуматься о рефакторинге.
Еще вопрос: "Зачем писать модульные (unit) тесты ради покрытия на интеграционный код: сервисные классы или классы контроллеров, которые представляют линейную цепочку вызовов методов?"
Ответ: "Не обязательно писать unit тесты".
Для простых микросервисов является нормальной перевернутая пирамида тестирования - когда интеграционных тестов разработки больше, чем модульных.
Простой код можно покрыть интеграционными тестами, включив их в общее покрытие. JaCoCo позволяет это настроить. Единственная проблема может быть, если тесты находятся в одном модуле, а код для покрытия - в другом, но и она решается.
И тут может возникнуть самый главный вопрос - а это не читерство? Чем это лучше отсутствия цели по покрытию?
Ответ: лучше тем, что мы четко задаем - вот это код не нужно покрывать тестами, а остальной - нужно.
И смотря на паттерны исключения - на их состав и количество - можно их быстро оценить и при необходимости скорректировать.
Ну и если ничего не помогло - тогда уже стоит задуматься о новом Quality Gate в SonarQube с меньшим процентом покрытия.
Никакой магии нет - https://t.me/javaKotlinDevOps/403.
Но числовой показатель (80% по умолчанию), задокументированные исключения и цель покрыть максимум кода, в котором возможны ошибки, быть должны.
P.S. Еще AI можно попросить тесты написать, у него это неплохо получается)
#unittests #integration_tests #java
Часто возникает вопрос - почему 80?
Краткий ответ - почему бы и нет)
А если серьезно: оценка может быть числовой (процент покрытия) или бинарной (достаточно или нет).
Бинарная плоха тем, что не документирована и зависит от мнения эксперта. Это может привести к проблемам на код-ревью.
А тут умные люди из SonarQube придумали метрику покрытия https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition#coverage
и дали её рекомендуемое значение. И это не 100%, т.е. запас есть.
Считаю, что от этой рекомендации стоит отталкиваться.
К тому же JaCoCo, обычно используемый для расчета покрытия, позволяет гибко настраивать сам процесс.
Следующий вопрос, который может возникнуть: "Почему ради достижения 80% я должен писать тесты на элементарный код?" Я про getter, setter и все, все, все https://t.me/javaKotlinDevOps/34
Ответ: "Нет, не нужны эти тесты".
Лишний код можно исключить из покрытия:
1) generated код исключается по умолчанию начиная с JaCoCo 0.8.2
2) generated код Lombok - через lombok.addLombokGeneratedAnnotation = true (жаль, что только для Lombok это можно сделать, но есть еще альтернатива - см. следующий абзац.)
3) тривиальный код - явно исключая классы или пакеты по маске через настройки JaCoCo. Если какой-то код не получается исключить таким образом - это повод задуматься о рефакторинге.
Еще вопрос: "Зачем писать модульные (unit) тесты ради покрытия на интеграционный код: сервисные классы или классы контроллеров, которые представляют линейную цепочку вызовов методов?"
Ответ: "Не обязательно писать unit тесты".
Для простых микросервисов является нормальной перевернутая пирамида тестирования - когда интеграционных тестов разработки больше, чем модульных.
Простой код можно покрыть интеграционными тестами, включив их в общее покрытие. JaCoCo позволяет это настроить. Единственная проблема может быть, если тесты находятся в одном модуле, а код для покрытия - в другом, но и она решается.
И тут может возникнуть самый главный вопрос - а это не читерство? Чем это лучше отсутствия цели по покрытию?
Ответ: лучше тем, что мы четко задаем - вот это код не нужно покрывать тестами, а остальной - нужно.
И смотря на паттерны исключения - на их состав и количество - можно их быстро оценить и при необходимости скорректировать.
Ну и если ничего не помогло - тогда уже стоит задуматься о новом Quality Gate в SonarQube с меньшим процентом покрытия.
Никакой магии нет - https://t.me/javaKotlinDevOps/403.
Но числовой показатель (80% по умолчанию), задокументированные исключения и цель покрыть максимум кода, в котором возможны ошибки, быть должны.
P.S. Еще AI можно попросить тесты написать, у него это неплохо получается)
#unittests #integration_tests #java
Sonarsource
Understanding measures and metrics | SonarQube Server | Sonar Documentation
Measures and metrics used in SonarQube to evaluate your code.
Что такое Agile для разработчика?
Возьмем SCRUM, как наиболее типичный его вариант.
IMHO конечно.
Это не церемонии - Daily, планирование, ретро, демо.
Не наличие Scrum мастера в команде.
Это красивый burn-down chart и velocity.
Не poker planing и оценка в story point.
Не работа с досками.
И даже не работающий инкремент каждую неделю.
База - это две вещи:
1) навык декомпозиции задач.
Который приводит к небольшим инкрементам.
А конечные цели:
- минимум зависимостей от других
- маленькие PR = быстрое ревью и вливание
- инкрементная интеграция кода = возможность вливания в целевую ветку и отправку на тестирование без ожидания других доработок.
2) точность оценки задач.
Не важно в чем - в story point, человеко-днях или в конкретных датах.
Оценка, кстати, зависит от декомпозиции, т.к. мелкие задачи можно оценить точнее, а потом оценки просуммировать.
Конечная цель - совпадение прогнозируемых сроков с реальными.
В данном случае речь про сроки этапа разработки, за соблюдение сроков интеграции со смежниками отвечает PO, DL и команда в целом.
Не всегда эти цели достижимы на 100%, но ставить их нужно. Если их себе ставить, то навык рано или поздно появится.
И традиционные ответы на не заданные вопросы)
Вопрос: "А разве это не навыки сеньоров?"
Ответ: когда-то возможно да, но с учетом последних тенденций (не могу не вставить AI в пост) кажется всем надо повышать уровень "сеньорности".
#agile
Возьмем SCRUM, как наиболее типичный его вариант.
IMHO конечно.
Это не церемонии - Daily, планирование, ретро, демо.
Не наличие Scrum мастера в команде.
Это красивый burn-down chart и velocity.
Не poker planing и оценка в story point.
Не работа с досками.
И даже не работающий инкремент каждую неделю.
База - это две вещи:
1) навык декомпозиции задач.
Который приводит к небольшим инкрементам.
А конечные цели:
- минимум зависимостей от других
- маленькие PR = быстрое ревью и вливание
- инкрементная интеграция кода = возможность вливания в целевую ветку и отправку на тестирование без ожидания других доработок.
2) точность оценки задач.
Не важно в чем - в story point, человеко-днях или в конкретных датах.
Оценка, кстати, зависит от декомпозиции, т.к. мелкие задачи можно оценить точнее, а потом оценки просуммировать.
Конечная цель - совпадение прогнозируемых сроков с реальными.
В данном случае речь про сроки этапа разработки, за соблюдение сроков интеграции со смежниками отвечает PO, DL и команда в целом.
Не всегда эти цели достижимы на 100%, но ставить их нужно. Если их себе ставить, то навык рано или поздно появится.
И традиционные ответы на не заданные вопросы)
Вопрос: "А разве это не навыки сеньоров?"
Ответ: когда-то возможно да, но с учетом последних тенденций (не могу не вставить AI в пост) кажется всем надо повышать уровень "сеньорности".
#agile
👍3
Почему победил компактный стиль форматирования кода?
Я про сталь Oracle\Sun и очень похожий на него стиль Google:
vs
Базовый ответ - потому что он компактнее)
Но я бы накинул еще один аргумент. Рассуждение:
- стиль форматирования нужен человеку, и не нужен машине
- человеку важно понимать, где начало и конец логического блока кода или управляющей конструкции
- "железобетонный" способ это понять - четкие маркеры, хороший пример: begin-end в Delphi, If-End If в VB
- хороший, но не идеальный, т.к. слишком много символов - 8 вместо минимально возможных 2
- скобки на той же строке, что и управляющая конструкция, у Google\Sun - это по сути компактная эмуляция begin-end. Эмуляция потому что они не обязательны. Скобки как бы становятся частью управляющей конструкции - if, for, while, switch, try.
- а вот альтернативный вариант - это что-то странное, т.к. скобки по отступам находятся на уровне управляющей конструкции, но зачем тогда перенос на новую строку?
Тогда логичнее вот так:
Но это еще страннее смотрится.
Ну и напоследок каких целей должно достичь хорошее форматирование кода:
1) разделение логических блоков кода: пробелы, отступы, скобки
2) единообразие
3) улучшение читаемости
4) облегчение правок - возможность быстро понять, какой блок кода нужно перенести или удалить целиком
5) компактность. Причем как раз компактность с увеличением размера монитора становится менее
важна
P.S. Спонсор выпуска - Совершенный код, Стив Макконнелл)
#java #formating
Я про сталь Oracle\Sun и очень похожий на него стиль Google:
public class OrderService {
private static final int MAX_RETRIES = 3;
public String processOrder(Order order, boolean isPriority) {
if (order == null) {
...vs
public class OrderService
{
private static final int MAX_RETRIES = 3;
public String processOrder(Order order, boolean isPriority)
{
if (order == null)
{
...
Базовый ответ - потому что он компактнее)
Но я бы накинул еще один аргумент. Рассуждение:
- стиль форматирования нужен человеку, и не нужен машине
- человеку важно понимать, где начало и конец логического блока кода или управляющей конструкции
- "железобетонный" способ это понять - четкие маркеры, хороший пример: begin-end в Delphi, If-End If в VB
- хороший, но не идеальный, т.к. слишком много символов - 8 вместо минимально возможных 2
- скобки на той же строке, что и управляющая конструкция, у Google\Sun - это по сути компактная эмуляция begin-end. Эмуляция потому что они не обязательны. Скобки как бы становятся частью управляющей конструкции - if, for, while, switch, try.
- а вот альтернативный вариант - это что-то странное, т.к. скобки по отступам находятся на уровне управляющей конструкции, но зачем тогда перенос на новую строку?
Тогда логичнее вот так:
public class OrderService
{
private static final int MAX_RETRIES = 3;
public String processOrder(Order order, boolean isPriority)
{
if (order == null)
{
...
Но это еще страннее смотрится.
Ну и напоследок каких целей должно достичь хорошее форматирование кода:
1) разделение логических блоков кода: пробелы, отступы, скобки
2) единообразие
3) улучшение читаемости
4) облегчение правок - возможность быстро понять, какой блок кода нужно перенести или удалить целиком
5) компактность. Причем как раз компактность с увеличением размера монитора становится менее
важна
P.S. Спонсор выпуска - Совершенный код, Стив Макконнелл)
#java #formating
👍1
Почему LLM может писать хороший код, но плохо генерит JSON?
Может и плохой код писать, к слову, зависит от модели и задачи)
Я уже писал о том, что генерация JSON - не конёк LLM https://t.me/javaKotlinDevOps/484
Сейчас попробую расписать почему.
Возьмем ситуацию до появления паттерна structured output. LLM отвечает текстом, если нам нужно вызвать тулу и передать туда определенный набор параметров - можно описать этот набор JSON схемой.
JSON схема как валидатор объекта параметров.
Получался примерно такой запрос к модели на формирование вызова тулы:
Здесь две проблемы.
1) модель конечно знает что такое JSON, но она генерирует токены, а не текст по формату.
2) у агента\чата есть задача уменьшить контекст, поэтому даже если ему дать полную схему с minimum, minimum, pattern, minItems - он ее может порезать (и режет) для оптимизации.
Поэтому модель могла вернуть и некорректный по структуре JSON, и проигнорировать ряд атрибутов схемы. Первое реже, второе - всегда.
Когда появился structured json - модель же гарантирует корректность возвращаемого JSON (JSON = возвращаемый объект) проблема казалось бы должна уйти в прошлое?
В модель летит такой запрос:
Тут даже "additionalProperties": false есть. И required само собой. И это все даже работает)
Но в целом гарантии точному соответствию схеме нет.
Как в большинстве моделей реализуется structured output?
Схема превращается в набор т.наз. грамматик.
Например
превратится в что-то такое:
А далее по этим грамматикам строится state machine.
И при генерации очередного токена во внимание принимается не только его вероятность (как при обычном выводе), но и идет проверка на разрешенное состояние по этой state machine.
И если не разрешено - выбираем следующий.
Процесс называется constrained decoding, вот пример библиотеки, его реализующей: https://xgrammar.mlc.ai/
И я бы из ее описания обратил внимание на фразу:
Может и плохой код писать, к слову, зависит от модели и задачи)
Я уже писал о том, что генерация JSON - не конёк LLM https://t.me/javaKotlinDevOps/484
Сейчас попробую расписать почему.
Возьмем ситуацию до появления паттерна structured output. LLM отвечает текстом, если нам нужно вызвать тулу и передать туда определенный набор параметров - можно описать этот набор JSON схемой.
JSON схема как валидатор объекта параметров.
Получался примерно такой запрос к модели на формирование вызова тулы:
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "Создай заказ: 2 товара по цене 10"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "create_order",
"description": "Создание заказа",
"parameters": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"price": { "type": "number" },
"quantity": { "type": "integer" }
},
"required": ["price", "quantity"]
}
}
},
"required": ["items"]
}
}
}
]
}Здесь две проблемы.
1) модель конечно знает что такое JSON, но она генерирует токены, а не текст по формату.
2) у агента\чата есть задача уменьшить контекст, поэтому даже если ему дать полную схему с minimum, minimum, pattern, minItems - он ее может порезать (и режет) для оптимизации.
Поэтому модель могла вернуть и некорректный по структуре JSON, и проигнорировать ряд атрибутов схемы. Первое реже, второе - всегда.
Когда появился structured json - модель же гарантирует корректность возвращаемого JSON (JSON = возвращаемый объект) проблема казалось бы должна уйти в прошлое?
В модель летит такой запрос:
{
"model": "gpt-4.1",
"messages": [
{
"role": "user",
"content": "Создай заказ: 2 товара по цене 10"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "order_response",
"schema": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"price": { "type": "number" },
"quantity": { "type": "integer" }
},
"required": ["price", "quantity"],
"additionalProperties": false
}
},
"total": {
"type": "number",
"description": "Общая стоимость"
}
},
"required": ["items", "total"],
"additionalProperties": false
},
"strict": true
}
}
}Тут даже "additionalProperties": false есть. И required само собой. И это все даже работает)
Но в целом гарантии точному соответствию схеме нет.
Как в большинстве моделей реализуется structured output?
Схема превращается в набор т.наз. грамматик.
Например
"type": "array",
"items": { "type": "integer" }
превратится в что-то такое:
[ INT (, INT)* ]
А далее по этим грамматикам строится state machine.
И при генерации очередного токена во внимание принимается не только его вероятность (как при обычном выводе), но и идет проверка на разрешенное состояние по этой state machine.
И если не разрешено - выбираем следующий.
Процесс называется constrained decoding, вот пример библиотеки, его реализующей: https://xgrammar.mlc.ai/
И я бы из ее описания обратил внимание на фразу:
aiming at bring flexible zero-overhead structure generation everywhere
zero-overhead. Т.е. при генерации state machine под схему из схемы снова выкидывается все лишнее, для скорости. А скорость ответа для LLM критична.
Т.е. constrained decoding работает не так строго, как обычный валидатор JSON Schema в Java или Python.
И minimum, maximum, pattern, format снова не работают.
Зато быстро. Но все равно чуть медленнее, чем без structured output, т.к. и дополнительная валидация появляется, и перебор вариантов.
В теории можно было бы взять open-source движок инференса и прикрутить туда нормальный JSON валидатор. Но подозреваю LLM станет отвечать очень медленно.
Как с этим бороться?
Все уже придумано, паттерн Retry.
Да, и structured output - это все равно шаг вперед. Модель не генерирует как бы json, есть валидатор, проверяющий ну скажем 80-90% схемы.
#ai #llm
Т.е. constrained decoding работает не так строго, как обычный валидатор JSON Schema в Java или Python.
И minimum, maximum, pattern, format снова не работают.
Зато быстро. Но все равно чуть медленнее, чем без structured output, т.к. и дополнительная валидация появляется, и перебор вариантов.
В теории можно было бы взять open-source движок инференса и прикрутить туда нормальный JSON валидатор. Но подозреваю LLM станет отвечать очень медленно.
Как с этим бороться?
Все уже придумано, паттерн Retry.
MAX_RETRIES = 3
def generate_order(user_input: str):
prompt = f"Сформируй заказ в JSON: {user_input}"
last_error = None
for attempt in range(MAX_RETRIES):
raw = call_llm(prompt)
try:
order = Order.model_validate_json(raw)
return order
except ValidationError as e:
last_error = str(e)
# repair prompt
prompt = f"""
Ты вернул невалидный JSON.
Ошибка:
{last_error}
Твой предыдущий ответ:
{raw}
Исправь JSON строго по схеме.
Верни только JSON, без комментариев.
"""
raise Exception(f"Не удалось получить валидный ответ: {last_error}")
Да, и structured output - это все равно шаг вперед. Модель не генерирует как бы json, есть валидатор, проверяющий ну скажем 80-90% схемы.
#ai #llm
Telegram
(java || kotlin) && devOps
LLM как серебряная пуля?
Конечно же нет.
А если серьезно - что не умеет LLM?
1) выдавать актуальную информацию. Фиксится подключением веб-поиска
2) выдавать 100% точные ответы. LLM вероятностна по своей природе, поэтому даже самая мощная модель с огромным…
Конечно же нет.
А если серьезно - что не умеет LLM?
1) выдавать актуальную информацию. Фиксится подключением веб-поиска
2) выдавать 100% точные ответы. LLM вероятностна по своей природе, поэтому даже самая мощная модель с огромным…
Кто же изобрел ноутбуки (Jupiter notebook)?
Ранее уже писал, что это питонисты, а точнее ML инженеры питонисты.
Выяснилось, что это не совсем так.
Дональд Кнут Грамотное программирование, 2001. Тот самый, что написал 3 тома Искусства программирования.
Собственно концепция грамотного программирования - это писать код для людей, а не для машин. Т.е. в формате рассказа, где главный - текст.
Т.е не
а скорее
А код - это переменная, которую можно переиспользовать.
При нужны соответствующие правила форматирования и движок для рендера всего это в удобочитаемый вид.
Кнут предлагал его всем разработчикам, взяли только дата сатанисты) Но с развитием AI может и пошире распространится)
Плюс понятен - читаемость. Минус - сложнее (дольше) писать. Мы же вообще уходим от документации к самодокументирующемуся кода. Но для сложного кода кажется смысл в нем есть.
#python #notebooks
Ранее уже писал, что это питонисты, а точнее ML инженеры питонисты.
Выяснилось, что это не совсем так.
Дональд Кнут Грамотное программирование, 2001. Тот самый, что написал 3 тома Искусства программирования.
Собственно концепция грамотного программирования - это писать код для людей, а не для машин. Т.е. в формате рассказа, где главный - текст.
Т.е не
// Используем метод сортировки пузырьком, суть которого...
// Декларация метода:
void boubleSort(int[] array) {
...
а скорее
Используем метод сортировки пузырьком, суть которого...
Декларация метода:
@sort_method =
void (int[] array) {
...
@
А код - это переменная, которую можно переиспользовать.
При нужны соответствующие правила форматирования и движок для рендера всего это в удобочитаемый вид.
Кнут предлагал его всем разработчикам, взяли только дата сатанисты) Но с развитием AI может и пошире распространится)
Плюс понятен - читаемость. Минус - сложнее (дольше) писать. Мы же вообще уходим от документации к самодокументирующемуся кода. Но для сложного кода кажется смысл в нем есть.
#python #notebooks
Еще о форматировании.
Может показаться, что форматирование уже не критично, ведь весь код скоро будет писать AI, а мы все переквалифицируемся в архитекторы)
Насколько скоро - отдельный холиварный вопрос. Но не буду отвлекаться.
1) Факт номер раз: модель код (текст) превращает в токены. Токен с пробелом, табом, скобкой или переводом строки и без него - это разные токены.
Факт номер два: форматирование должно подчеркивать логическую структуру кода https://t.me/javaKotlinDevOps/559.
Следовательно, единообразное форматирование улучшает понимание кода моделью.
2) модель генерирует код по аналогии. Код проекта имеет больший приоритет, чем код, на котором ее обучали. Следовательно, какое форматирование на входе, такое и на выходе.
Далее повторяем 1) и 2) для каждой новой фичи и в итоге получаем, что хорошее форматирование кода может повысить шансы на выживание сервиса после его рефакторинга AI-шкой.
Да и при ревью человеком AI кода хорошее форматирование сильно поможет. А код-ревью нужно, сейчас так точно. Если смотреть в будущее - как опция, для сложных участков кода.
Итого - как раз таки для LLM, в отличие от компилятора, форматирование кода важно.
И видится плюс: если код пишет AI - форматированием и читаемость кода должны становится лучше при условии хорошей базы.
Модели легче сгенерировать пару лишних токенов, чем человеку поставить нужное число пробелов или скобок.
#ai #formating
Может показаться, что форматирование уже не критично, ведь весь код скоро будет писать AI, а мы все переквалифицируемся в архитекторы)
Насколько скоро - отдельный холиварный вопрос. Но не буду отвлекаться.
1) Факт номер раз: модель код (текст) превращает в токены. Токен с пробелом, табом, скобкой или переводом строки и без него - это разные токены.
Факт номер два: форматирование должно подчеркивать логическую структуру кода https://t.me/javaKotlinDevOps/559.
Следовательно, единообразное форматирование улучшает понимание кода моделью.
2) модель генерирует код по аналогии. Код проекта имеет больший приоритет, чем код, на котором ее обучали. Следовательно, какое форматирование на входе, такое и на выходе.
Далее повторяем 1) и 2) для каждой новой фичи и в итоге получаем, что хорошее форматирование кода может повысить шансы на выживание сервиса после его рефакторинга AI-шкой.
Да и при ревью человеком AI кода хорошее форматирование сильно поможет. А код-ревью нужно, сейчас так точно. Если смотреть в будущее - как опция, для сложных участков кода.
Итого - как раз таки для LLM, в отличие от компилятора, форматирование кода важно.
И видится плюс: если код пишет AI - форматированием и читаемость кода должны становится лучше при условии хорошей базы.
Модели легче сгенерировать пару лишних токенов, чем человеку поставить нужное число пробелов или скобок.
#ai #formating
Telegram
(java || kotlin) && devOps
Почему победил компактный стиль форматирования кода?
Я про сталь Oracle\Sun и очень похожий на него стиль Google:
public class OrderService {
private static final int MAX_RETRIES = 3;
public String processOrder(Order order, boolean isPriority) {
…
Я про сталь Oracle\Sun и очень похожий на него стиль Google:
public class OrderService {
private static final int MAX_RETRIES = 3;
public String processOrder(Order order, boolean isPriority) {
…
Что C++ унаследовал от Java?
Внимательный читатель должен сказать - стой, автор, ты ничего не перепутал? Может Java от C++?
Не перепутал)
Да, Java был создан как безопасная и легко портируемая альтернатива C++.
Но кое-что он вернул прародителю.
Как ни странно - это стандарт документирования кода. C++ изначально шел без стандарта документирования. Используйте что хотите. А JavaDoc с Java был изначально. По факту стандартной тулой для документации С++ стал Doxygen. А Doxigen взял за основу JavaDoc.
Такие дела)
#java #c++
Внимательный читатель должен сказать - стой, автор, ты ничего не перепутал? Может Java от C++?
Не перепутал)
Да, Java был создан как безопасная и легко портируемая альтернатива C++.
Но кое-что он вернул прародителю.
Такие дела)
#java #c++
Чем ещё может нам помочь AI?
Есть такая проблема - устаревание любой документации. Причина простая - код в большом числе случаев невозможно забыть исправить. Программа сломается, тесты сломаются. В худшем случае - ПРОМ сломается, но не будем о грустном)
А вот ошибка в документации никак себя не проявит, пока кто-то не начнёт эту документацию читать. И даже тогда ошибка может не бросаться в глаза, наоборот, ввести в заблуждение.
Как "заставить" разработчика всегда поддерживать актуальность документации?
Да никак.
Поэтому и стал популярным самодокументирующий код.
А вот AI как раз таки заставить можно. Одним промтом. Ещё один агент для мультиагентной системы. И опять же - в итоге тот же AI будет лучше понимать получившийся код.
#ai
Есть такая проблема - устаревание любой документации. Причина простая - код в большом числе случаев невозможно забыть исправить. Программа сломается, тесты сломаются. В худшем случае - ПРОМ сломается, но не будем о грустном)
А вот ошибка в документации никак себя не проявит, пока кто-то не начнёт эту документацию читать. И даже тогда ошибка может не бросаться в глаза, наоборот, ввести в заблуждение.
Как "заставить" разработчика всегда поддерживать актуальность документации?
Да никак.
Поэтому и стал популярным самодокументирующий код.
А вот AI как раз таки заставить можно. Одним промтом. Ещё один агент для мультиагентной системы. И опять же - в итоге тот же AI будет лучше понимать получившийся код.
#ai
Иногда лучше молчать, чем говорить - продолжение)
Я про auto complete в dev агентах в IDE, который не должен всегда выдавать хоть что-то. А должен выдавать что-то адекватное)
Чтд ... https://habr.com/ru/companies/tbank/articles/1012196/
Суть. Ребята из Т-банка сделали двойную фильтрацию подсказок с помощью LLM+ML с целью выбросить нерелевантные. И в итоге смогли сдвинуться с мертвой точки и улучшить процент принятых подсказок. Этот показатель у них вышел на плато и не двигался несколько лет.
Интересно, что им бизнес разрешил фильтровать не более 5% подсказок чтобы не ухудшить пользовательский опыт. Но даже в этом случае процент принятия увеличился на 5+%. И доверие к фиче, что более важно!
В статье достаточно много деталей реализации - кому интересно, почитайте.
P.S. Интересно, делают ли так другие агенты?)
P.P.S. часть первая https://t.me/javaKotlinDevOps/539
#ai #ai_agents
Я про auto complete в dev агентах в IDE, который не должен всегда выдавать хоть что-то. А должен выдавать что-то адекватное)
Чтд ... https://habr.com/ru/companies/tbank/articles/1012196/
Суть. Ребята из Т-банка сделали двойную фильтрацию подсказок с помощью LLM+ML с целью выбросить нерелевантные. И в итоге смогли сдвинуться с мертвой точки и улучшить процент принятых подсказок. Этот показатель у них вышел на плато и не двигался несколько лет.
Интересно, что им бизнес разрешил фильтровать не более 5% подсказок чтобы не ухудшить пользовательский опыт. Но даже в этом случае процент принятия увеличился на 5+%. И доверие к фиче, что более важно!
В статье достаточно много деталей реализации - кому интересно, почитайте.
P.S. Интересно, делают ли так другие агенты?)
P.P.S. часть первая https://t.me/javaKotlinDevOps/539
#ai #ai_agents
Хабр
AI Code Completion: как мы добавили умный фильтр и перестали показывать лишнее
Всем привет! На связи Александр и Артем — ML-инженеры из Т-Банка. Мы делаем copilot-инструмент для разработчиков. Статья будет не про агентов. Расскажем, как отрезали лишние и бесполезные подсказки в...
🔥1
Снова нападки на Scala)
Я уже немного писал про Scala когда говорил о выборе новых языков программирования https://t.me/javaKotlinDevOps/251
Но осталось чувство недосказанности. Сложный - да, о ведь функционально крутой. Может стоит набрать команду "спецназа" от разработки, пусть на Scala пишут ядро системы?
Я бы не стал. Сложность это полбеды. Сложность не там, где ей стоит быть - вот проблема.
Большиство предметных областей дают нам бизнесовую сложность. Если бы это было не так - вместо разработки стоило бы купить готовое решение. Или взять готовую библиотеку.
Сложность должна быть в бизнес-логике. А не в конструкциях языка.
Второй момент - основная задача разработчика (чего-то сложнее hello world) - борьба со сложностью. SOLID, DRY. переиспользование кода, микросервисы, уровни приложения, говорящие имена, читаемость кода, DDD, итеративная разработка... - все это помогает уменьшить сложность. А тут язык провоцирует ее увеличение.
И ещё пример. Google. Компания может позволить себе нанять наверное любого программиста. Популяризовать любой язык.
Но что она делает?
Видит проблему на backend.
C++ быстр, но не безопасен и сложен.
Java безопасная, попроще, но не идеал.
И придумывает Go: быстрый и простой. Ещё заточенный на многопоточность, но простую - goroutines.
Мобильная разработка - есть завязка на JDK. Почему так - тема отдельная. Базовый язык для JDK - Java, про Java см. выше. Тут появляется более простой Kotlin - и Google делает его стандартом Android разработки.
Итого - в обоих случаях Google сделал разработку проще. production подход. Хотя где-то у них используется Scala.
#java #kotlin #scala
Я уже немного писал про Scala когда говорил о выборе новых языков программирования https://t.me/javaKotlinDevOps/251
Но осталось чувство недосказанности. Сложный - да, о ведь функционально крутой. Может стоит набрать команду "спецназа" от разработки, пусть на Scala пишут ядро системы?
Я бы не стал. Сложность это полбеды. Сложность не там, где ей стоит быть - вот проблема.
Большиство предметных областей дают нам бизнесовую сложность. Если бы это было не так - вместо разработки стоило бы купить готовое решение. Или взять готовую библиотеку.
Сложность должна быть в бизнес-логике. А не в конструкциях языка.
Второй момент - основная задача разработчика (чего-то сложнее hello world) - борьба со сложностью. SOLID, DRY. переиспользование кода, микросервисы, уровни приложения, говорящие имена, читаемость кода, DDD, итеративная разработка... - все это помогает уменьшить сложность. А тут язык провоцирует ее увеличение.
И ещё пример. Google. Компания может позволить себе нанять наверное любого программиста. Популяризовать любой язык.
Но что она делает?
Видит проблему на backend.
C++ быстр, но не безопасен и сложен.
Java безопасная, попроще, но не идеал.
И придумывает Go: быстрый и простой. Ещё заточенный на многопоточность, но простую - goroutines.
Мобильная разработка - есть завязка на JDK. Почему так - тема отдельная. Базовый язык для JDK - Java, про Java см. выше. Тут появляется более простой Kotlin - и Google делает его стандартом Android разработки.
Итого - в обоих случаях Google сделал разработку проще. production подход. Хотя где-то у них используется Scala.
#java #kotlin #scala
Telegram
(java || kotlin) && devOps
Всем привет!
В развитие прошлого поста предлагаю поговорить про большие компании и новые языки программирования.
Вопросы, на который я постараюсь дать исчерпывающий ответ:
1) какие риски несет внедрение нового языка в enterprise?
2) нужно ли согласовывать…
В развитие прошлого поста предлагаю поговорить про большие компании и новые языки программирования.
Вопросы, на который я постараюсь дать исчерпывающий ответ:
1) какие риски несет внедрение нового языка в enterprise?
2) нужно ли согласовывать…
👍1
AI, везде AI)
Кажется назрел пост-глоссарий терминов. Сам иногда путаюсь)
ML модель - узкоспециализированная небольшая модель, как правило требующая обучения под конкретную задачу: классификация текстов, картинок или видео, определение тональности текста, преобразования Image\Audio в Text и обратно.
Существуют достаточно давно.
LLM - модель общего назначения, базово умеет продолжать текстовые фразы.
С конвертерами и тулами - принимать и генерировать любой контент, недостающие знания запрашивая из внешнего мира.
За универсальность приходится платить - LLM медленнее и требует более мощного железа.
промт - часть запроса к LLM. Почему часть? Как правило исходный запрос пользователя не попадает напрямую в LLM.
Исходный запрос - это пользовательский промт, а еще бывают системный и assistant.
Системный - это промт, "захардкоженный" внутри сервиса, взаимодействующего с LLM, и имеющий более высокий приоритет. Например, чата или агента.
assistant промт - прошлые ответы модели, добавленные в диалог.
tool - метод агента, имеющий четкое API и выполняющий некое действие\возвращающий некие данных.
Должен быть корректно описан, чтобы модель поняла зачем он нужен и вызывала его в случаях, когда сама не может выполнить какой-то запрос.
Как правило tool-ы встроенные, но иногда есть возможность создать пользовательские tool.
MCP - протокол клиент-сервер, позволяющий вынести tool-ы из агента.
Позволяет легко переиспользовать tool в разных агентах и разделить разработку логики агента и бизнесовых инструментов.
skill - навык агента. По сути более сложный tool, скорее сценарий, оркестрирующий вызовы нескольких тулов. Включает промт, документацию, схемы валидации, скрипты.
rule - правила работы, которые должны применяться при любом запросе к LLM.
RAG - статическая база знаний по узкой предметной области, содержащая данные, которых нет в LLM.
Контекст - набор данных, на основании которого LLM генерирует текст. В контекст имеет смысл включать:
а) промты
б) историю диалога и вызовов инструментов
в) полезные данные из RAG
г) список доступных tools, skills и MCP серверов
д) rules
Контекст привязан к клиентской сессии.
Контекстное окно - ограничение на размер контекста в сессии. Контекст хранится в памяти, память дорогая, приходится ограничивать. При достижении предела нужно принять два решения:
а) падать\ не падать (последнее - плавающее окно)
б) удалять \ сжимать старые данные.
Агент - сервис, с помощью AI способный самостоятельно понять и решить поставленную задачу.
В простейшем виде это бесконечный цикл вида:
а) ожидание входных данных
б) формирование данных, которые могут попасть в запрос к LLM
в) фильтрация этих данных
г) вызов LLM
д) получение дополнительных данных с помощью tool
е) валидация ответа
д) возврат ответа
В более сложных случаях - ациклический граф (DAG, не путать с RAG) или стейт-машина. Или даже циклический граф, для обработки ошибочного ответа.
Команды - по сути shortcut вида /execute для быстрого выполнения промта при общении с агентом в чате.
ACP - протокол для общения IDE и агента. Альтернатива MCP для вызова функций IDE из агента.
При использовании MCP агент просто вызывает функции IDE как тулы.
При использовании ACP - взаимодействие двухстороннее. Где это может понадобиться? Разве что для реализации единого окна чата в IDE для разных агентов.
Субагент - агент внутри агента. Ключевые характеристики - свой системный промт, свой набор тулов и свое контекстное окно. Простейший способ реализации мультиагентной системы.
Можно считать, что субагент - это развитый skill, имеющий свой контекст.
Обучение модели - в случае LLM по сути альтернатива RAG. Вместо того, чтобы хранить данные рядом с агентом - добавляем их в модель.
В целом LLM не требуют обучения, но иногда оно полезно.
Обучение дорогое - в случае LLM для него требуется множество GPU. Есть разные виды обучения, но это отдельная тема)
Инференс (inference) - обработка пользовательских запросов моделью. Инференс менее ресурсозатратный процесс, но для больших LLM также требует GPU.
ollama - самый популярный движок для локального инференса.
Кажется назрел пост-глоссарий терминов. Сам иногда путаюсь)
ML модель - узкоспециализированная небольшая модель, как правило требующая обучения под конкретную задачу: классификация текстов, картинок или видео, определение тональности текста, преобразования Image\Audio в Text и обратно.
Существуют достаточно давно.
LLM - модель общего назначения, базово умеет продолжать текстовые фразы.
С конвертерами и тулами - принимать и генерировать любой контент, недостающие знания запрашивая из внешнего мира.
За универсальность приходится платить - LLM медленнее и требует более мощного железа.
промт - часть запроса к LLM. Почему часть? Как правило исходный запрос пользователя не попадает напрямую в LLM.
Исходный запрос - это пользовательский промт, а еще бывают системный и assistant.
Системный - это промт, "захардкоженный" внутри сервиса, взаимодействующего с LLM, и имеющий более высокий приоритет. Например, чата или агента.
assistant промт - прошлые ответы модели, добавленные в диалог.
tool - метод агента, имеющий четкое API и выполняющий некое действие\возвращающий некие данных.
Должен быть корректно описан, чтобы модель поняла зачем он нужен и вызывала его в случаях, когда сама не может выполнить какой-то запрос.
Как правило tool-ы встроенные, но иногда есть возможность создать пользовательские tool.
MCP - протокол клиент-сервер, позволяющий вынести tool-ы из агента.
Позволяет легко переиспользовать tool в разных агентах и разделить разработку логики агента и бизнесовых инструментов.
skill - навык агента. По сути более сложный tool, скорее сценарий, оркестрирующий вызовы нескольких тулов. Включает промт, документацию, схемы валидации, скрипты.
rule - правила работы, которые должны применяться при любом запросе к LLM.
RAG - статическая база знаний по узкой предметной области, содержащая данные, которых нет в LLM.
Контекст - набор данных, на основании которого LLM генерирует текст. В контекст имеет смысл включать:
а) промты
б) историю диалога и вызовов инструментов
в) полезные данные из RAG
г) список доступных tools, skills и MCP серверов
д) rules
Контекст привязан к клиентской сессии.
Контекстное окно - ограничение на размер контекста в сессии. Контекст хранится в памяти, память дорогая, приходится ограничивать. При достижении предела нужно принять два решения:
а) падать\ не падать (последнее - плавающее окно)
б) удалять \ сжимать старые данные.
Агент - сервис, с помощью AI способный самостоятельно понять и решить поставленную задачу.
В простейшем виде это бесконечный цикл вида:
а) ожидание входных данных
б) формирование данных, которые могут попасть в запрос к LLM
в) фильтрация этих данных
г) вызов LLM
д) получение дополнительных данных с помощью tool
е) валидация ответа
д) возврат ответа
В более сложных случаях - ациклический граф (DAG, не путать с RAG) или стейт-машина. Или даже циклический граф, для обработки ошибочного ответа.
Команды - по сути shortcut вида /execute для быстрого выполнения промта при общении с агентом в чате.
ACP - протокол для общения IDE и агента. Альтернатива MCP для вызова функций IDE из агента.
При использовании MCP агент просто вызывает функции IDE как тулы.
При использовании ACP - взаимодействие двухстороннее. Где это может понадобиться? Разве что для реализации единого окна чата в IDE для разных агентов.
Субагент - агент внутри агента. Ключевые характеристики - свой системный промт, свой набор тулов и свое контекстное окно. Простейший способ реализации мультиагентной системы.
Можно считать, что субагент - это развитый skill, имеющий свой контекст.
Обучение модели - в случае LLM по сути альтернатива RAG. Вместо того, чтобы хранить данные рядом с агентом - добавляем их в модель.
В целом LLM не требуют обучения, но иногда оно полезно.
Обучение дорогое - в случае LLM для него требуется множество GPU. Есть разные виды обучения, но это отдельная тема)
Инференс (inference) - обработка пользовательских запросов моделью. Инференс менее ресурсозатратный процесс, но для больших LLM также требует GPU.
ollama - самый популярный движок для локального инференса.
👍3🔥1
embeddings - преобразование текста в вектора (набор чисел). LLM работает с векторами, RAG хранит данные в виде векторов, при поиске по RAG запрос также превращается в векторную форму. Для формирования embeddings есть специальные ML модели, меньшие и более быстрые.
Семантический поиск = векторный поиск. Суть в том, что ищет не похожие по написанию слова, а близкие слова в пространстве векторов.
#ai
Семантический поиск = векторный поиск. Суть в том, что ищет не похожие по написанию слова, а близкие слова в пространстве векторов.
#ai
👍1