Перейти к содержанию

Что создает AI Developer

Шаг 1

Представьте утро оператора службы поддержки. За ночь пришло сто обращений. Одни клиенты спрашивают о доставке, другие хотят вернуть товар, третьи присылают длинное описание непонятной ошибки.

Оператору нужно прочитать каждое сообщение, понять его тему, найти важные детали и подготовить ответ. Значительная часть времени уходит не на решение проблемы, а на чтение и перенос информации.

А теперь представим функцию в виде кода, которая за несколько секунд:

  • определяет тему обращения
  • делает краткое содержание
  • выделяет номер заказа и другие данные
  • показывает, какой информации не хватает
  • предлагает черновик ответа

Оператор проверяет результат и принимает решение. Именно разработкой таких функций занимается AI Developer, или AI-разработчик.

Кто такой AI Developer простыми словами?

AI Developer — это программист, который добавляет возможности искусственного интеллекта в сайты, ботов, мобильные приложения и внутренние системы компаний. Он не просто задает вопрос модели и копирует ответ. Его задача — сделать так, чтобы модель стала частью работающего приложения.

Для этого разработчик должен:

  1. понять проблему пользователя
  2. определить, чем может помочь модель
  3. написать Python-код для обращения к модели
  4. передать ей только нужные данные
  5. получить и обработать ответ
  6. проверить возможные ошибки
  7. показать результат пользователю

Поэтому результат работы AI-разработчика — не красивый промпт и не один удачный ответ. Его результат — это полезная функция продукта.

Какие продукты создают AI-разработчики?

Помощники службы поддержки. Они разбирают обращения, находят нужную инструкцию и готовят черновик ответа.

Сервисы работы с документами. Пользователь загружает договор, отчет или резюме, а приложение извлекает нужные поля и составляет краткое содержание.

Поиск по внутренним знаниям. Сотрудник задает вопрос обычным языком и получает ответ на основе документов компании.

Помощники для сотрудников. Они помогают написать письмо, подготовить план встречи, оформить заметки или преобразовать текст в нужный формат.

Функции для интернет-магазинов. AI может создавать описания товаров, группировать отзывы и отвечать на вопросы о характеристиках.

Мультимодальные приложения. Современные модели работают не только с текстом, но и с изображениями, аудио и документами. Например, приложение может прочитать фотографию чека или описать содержимое изображения.

При этом AI-разработчику не нужно обучать свою модель, он использует крупные модели, которые уже обучены и доступны через API. Разработчик отправляет запрос удаленному сервису и получает ответ.

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

При этом AI-разработчику недостаточно уметь писать промпты, ведь промпт — это инструкция для модели. Конечно, хорошая инструкция действительно важна, но вокруг нее остается много инженерной работы. Представим, что модель правильно разбирает девять обращений из десяти. Что произойдет с десятым? Сможет ли программа заметить отсутствие обязательного поля? Что увидит пользователь при недоступности API? Сколько стоит обработка тысячи документов? Можно ли безопасно записать ошибку в лог? А на все эти вопросы отвечает не промпт, а код приложения.

Важно помнить: модель работает вероятностно. Одинаковые запросы могут давать немного разные ответы, а сгенерированный текст может содержать ошибку. Поэтому модель не должна без проверки:

  • переводить деньги
  • изменять права доступа
  • сообщать выдуманный статус заказа
  • принимать окончательное медицинское или юридическое решение
  • удалять важные данные

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

Подводя итог, можно сказать, что AI Developer — это разработчик, который берет готовую модель и превращает ее в полезную функцию приложения. Он отвечает не только за запрос к модели, но и за данные, ошибки, проверки и пользовательский результат.

В следующем шаге мы подробно разберем, какие задачи подходят для AI, а где обычный код будет дешевле, быстрее и надежнее.

Шаг 2

После знакомства с языковыми моделями легко увидеть AI-задачу в каждой функции. Кажется, что модель может заменить поиск, условия, формулы и даже всю бизнес-логику.

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

Обычная логика программы хорошо выполняет точные инструкции. Например, если сумма заказа больше 10 000 рублей, применить скидку 5%. Если пароль неверен, отказать во входе. Если дата уже прошла, показать предупреждение.

Но это простая логика, а запрос человека не всегда можно разобрать такой простой логикой, ведь одну и ту же просьбу можно выразить десятками способов:

  • «Хочу вернуть товар»
  • «Покупка мне не подошла»
  • «Можно оформить возврат?»
  • «Размер оказался маленьким, что делать?»

Формулировки разные, а смысл похож, и вот именно такие задачи хорошо подходят языковой модели.

Шесть распространенных типов AI-функций

1. Классификация. Модель относит текст к одной из категорий. Например, определяет, относится обращение к доставке, оплате, возврату или технической проблеме.

2. Извлечение данных. Приложение получает свободный текст, а модель выделяет нужные поля: имя, организацию, дату, сумму, номер заказа или список навыков.

3. Краткое содержание. Большой документ, переписка или протокол встречи превращаются в несколько основных тезисов.

4. Преобразование текста. Модель переводит, упрощает, меняет стиль или приводит информацию к единому формату.

5. Генерация черновика. Модель предлагает ответ клиенту, письмо, описание товара или план документа. Ключевое слово — «черновик»: человек или программа должны проверить результат.

6. Ответы на вопросы. Модель объясняет информацию или отвечает на основе переданных документов. Позже в курсе мы увидим, как ограничивать ответ надежными источниками.

Разбираем реальные сценарии

Служба поддержки

На вход поступает сообщение клиента. Модель определяет тему, составляет выжимку и предлагает ответ. Обычный код получает сведения о заказе и проверяет правила возврата.

Польза AI — понять свободный текст. Польза кода — вернуть точные данные и выполнить действие.

Работа с резюме

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

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

Анализ договора

Модель может найти стороны, даты, суммы, обязанности и необычные пункты. Это ускоряет первичный просмотр. Окончательную юридическую оценку выполняет специалист.

Такая функция не заменяет юриста, но она уменьшает время на поиск информации и помогает не пропустить место, которое нужно проверить.

Интернет-магазин

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

Когда обычный код лучше

Модель не нужна, если задача имеет точный алгоритм и результат должен быть одинаковым при каждом запуске.

Задача Подход Почему
Рассчитать скидку Обычный код Есть точная формула
Получить статус заказа База данных и код Нужен реальный факт
Понять причину жалобы Модель Нужно понять свободный текст
Проверить обязательное поле Обычный код Достаточно простого условия
Сделать выжимку документа Модель Нужно обработать смысл текста
Списать деньги Платежная система и код Ошибка недопустима

То же самое мы можем выразить в виде схемы:

Перед подключением модели лучше всего перед подключением модели задать себе пять вопросов:

  1. Нужно ли понимать смысл неструктурированного текста, изображения или документа?
  2. Можно ли решить задачу обычным условием, формулой или запросом к базе?
  3. Какую пользу получит пользователь, например, экономию времени, новый интерфейс или более удобный результат?
  4. Что произойдет, если модель ошибется?
  5. Как приложение или человек смогут проверить ответ?

В реальных проектах смешанный подход встречается чаще всего. Например, рассмотрим полный сценарий возврата товара:

  1. Модель читает обращение и определяет, что клиент хочет оформить возврат.
  2. Код извлекает указанный номер заказа.
  3. База данных возвращает дату покупки и статус доставки.
  4. Код проверяет срок и правила возврата.
  5. Модель составляет понятный черновик ответа на основе результата проверки.
  6. И уже оператор подтверждает действие.

Если заменить все шаги одной просьбой «реши проблему клиента», модель может придумать статус заказа или неверно применить правило. Если убрать модель совсем, придется вручную описывать сотни вариантов человеческих формулировок. И вот как раз смешанный подход использует сильные стороны каждого компонента.

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

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

Шаг 3

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

Между моделью и пользователем всегда находится приложение. Представим, что языковая модель умеет составлять краткое содержание текста. Но у реального пользователя сразу появляются вопросы:

  • куда вставить текст
  • что произойдет, если отправить пустое сообщение
  • как долго ждать результат
  • что делать, если сервис модели недоступен
  • можно ли доверять полученному содержанию
  • куда сохранить результат
  • кто увидит исходный текст

Сама модель на эти вопросы не отвечает, а их решает приложение, а проектирует и программирует это поведение AI-разработчик.

Работу AI-разработчика можно разделить на три части.

1. Задача

Разработчик должен понимать, кому и зачем нужна функция. Формулировка «добавить AI» не описывает задачу. Формулировка «сократить время первичного разбора обращения» уже задает понятное направление.

На этом уровне определяются:

  • пользователь функции
  • данные на входе
  • ожидаемый результат
  • польза для человека или компании
  • допустимые и недопустимые ошибки

2. Программная реализация

Далее разработчик создает обычную программу: принимает данные, проверяет их, обращается к API модели, обрабатывает ответ и возвращает результат.

Здесь используются Python, функции, типы данных, HTTP, переменные окружения, библиотеки, базы данных и backend-фреймворки.

3. Надежность AI-функции

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

Разбираем работу на одном примере

Пусть службе поддержки нужна функция, которая определяет тему обращения и составляет краткое содержание.

Шаг 1. Уточнить результат

Недостаточно сказать модели: «Разбери сообщение». Приложению нужно понимать, что оно получит.

Например:

  • тема: доставка, оплата, возврат или другое
  • краткое содержание: одно или два предложения
  • номер заказа: если он присутствует в тексте
  • недостающие данные: что нужно уточнить у клиента

Так появляется понятный результат, который можно проверить.

Шаг 2. Подготовить примеры

Нужны не только удобные обращения. Следует проверить короткий текст, сообщение с ошибками, несколько проблем в одном письме, отсутствующий номер заказа и пустой ввод.

Шаг 3. Написать вызов модели

Python-программа создает запрос, передает инструкцию и текст обращения, затем получает ответ через API.

На этом шаге появляется первая работающая версия. Она доказывает, что идея технически выполнима, но еще не готова для пользователей.

Шаг 4. Проверить вход и ответ

Пустой текст отклоняется до обращения к API. Слишком большой документ обрабатывается отдельно. В ответе проверяются обязательные поля и допустимая категория. Если модель вместо категории вернула объяснение или пропустила поле, приложение должно заметить это.

Шаг 5. Обработать сбои

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

Шаг 6. Встроить функцию

После проверки эксперимент становится частью бэкенда. Фронтенд (или другой клиент) отправляет обращение, сервер вызывает AI-функцию и возвращает результат в понятном формате.

Шаг 7. Наблюдаем и улучшаем

Разработчик измеряет время ответа, число токенов и качество на подготовленных примерах. Неудачные случаи превращаются в новые тесты.

Чем AI Developer отличается от обычного backend-разработчика

У этих ролей много общего. Оба пишут серверный код, работают с API, данными, ошибками и тестами.

Отличие появляется в поведении модели. Обычная функция при одинаковых данных обычно возвращает предсказуемый результат. Языковая модель работает вероятностно: ответ может меняться, содержать неточность или не соответствовать ожидаемому формату.

Поэтому AI-разработчик дополнительно умеет:

  • формулировать инструкции для модели
  • управлять передаваемым контекстом
  • получать структурированные ответы
  • проверять качество на наборе примеров
  • учитывать токены, задержку и стоимость
  • ограничивать последствия ошибки модели

А теперь давайте поговорим про то, кто такие AI Developer, AI Engineer и ML Engineer. На самом деле названия должностей пересекаются, поэтому строгой границы нет. Однако общий ориентир выглядит так:

Роль Типичный фокус
AI Developer Прикладные функции продукта на основе готовых моделей
AI Engineer Архитектура и эксплуатация более крупных AI-систем
ML Engineer Обучение, адаптация и развертывание моделей машинного обучения

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

Насколько востребованы такие специалисты?

На российском рынке спрос на навыки работы с AI растет, но профессия еще не получила одного общепринятого названия. Одни компании открывают вакансии AI Developer, другие ищут AI Engineer, LLM Engineer или Python-разработчика для AI-продукта.

Что показывают данные hh.ru

По данным hh.ru, в январе и феврале 2025 года на платформе было 9 378 вакансий, в которых требовалось владение AI. За тот же период 2026 года таких вакансий стало 10 777 — рост составил 15%. Для развивающегося направления это заметный рост.

Изменилась и доля таких предложений на рынке: с 0,5% всех вакансий в начале 2025 года до 0,8% в начале 2026-го. Это пока небольшая часть российского рынка труда, поэтому говорить, что AI нужен абсолютно везде, было бы преувеличением. Но направление растет даже на фоне общего сокращения числа опубликованных вакансий.

Внутри профессиональных областей динамика различается. В IT число вакансий с требованиями AI-навыков выросло на 13%, в маркетинге — на 16%, в продажах и обслуживании клиентов — на 38%. Это показывает, что AI становится не только отдельной технической специализацией, но и инструментом для разных бизнес-функций.

В 2025 году соискатели разместили на hh.ru более 200 тысяч резюме с упоминанием AI. То есть вместе со спросом работодателей растет и конкуренция со стороны кандидатов.

На hh.ru можно встретить следующие названия:

  • AI Developer
  • AI Engineer
  • AI/LLM Engineer
  • LLM Engineer
  • Python / AI Developer
  • разработчик AI-решений
  • backend-разработчик для LLM-сервисов

Российские вакансии AI/LLM Engineer описывают разработку ассистентов, поиск по корпоративным документам, интеграцию моделей с инструментами и создание отказоустойчивых web-сервисов. Это хорошо совпадает с направлением нашего курса: работодателю нужен не человек, который только составляет промпты, а разработчик, способный довести AI-функцию до работающего приложения.

Что даст этот курс?

Мы начнем с настройки Python-проекта и первого запроса. Затем научимся:

  • управлять сообщениями и параметрами модели
  • проверять конфигурацию и ошибки
  • получать структурированный результат
  • работать с документами и изображениями
  • предоставлять AI-функции через FastAPI
  • измерять токены, время и качество
  • писать автоматические тесты
  • подготавливать приложение к запуску в Docker

Этот курс является первой частью более длинного пути. Вскоре появится второй курс — «AI Engineer на Python: RAG, агенты, MCP и production-системы».

В текущем курсе мы учимся создавать отдельные надежные AI-функции и объединять их в backend-приложение. Это необходимая основа: без умения работать с API модели, структурированными ответами, ошибками, файлами, FastAPI и тестами переходить к сложным AI-системам слишком рано.

Во втором курсе фокус сместится с отдельной функции на архитектуру целой системы. Студенты будут:

  • создавать ingestion pipeline для документов
  • работать с PostgreSQL и pgvector
  • строить semantic, keyword и hybrid search
  • разрабатывать RAG с reranking и ссылками на источники
  • проектировать память и состояние диалога
  • создавать ограниченных AI-агентов
  • строить устойчивые workflow на LangGraph
  • подключать внешние возможности через MCP
  • использовать очереди, Redis и фоновые workers
  • внедрять observability, evals, regression testing и защиту AI-систем

Проект, созданный в первом курсе, станет основой проекта второго курса. Мы будем постепенно превращать прикладное приложение в корпоративную AI-систему с базой знаний, правами доступа, памятью, инструментами и контролируемыми агентами. Но сначала важно уверенно завершить уровень AI Developer: научиться создавать небольшие функции, понимать ограничения моделей и писать надежный Python-код. После этого переход к RAG, агентам и production-архитектуре будет последовательным, а не формальным знакомством с модными терминами.

Шаг 4

Сервис поддержки должен обработать сообщение: «Списали оплату дважды, верните деньги».

Как безопаснее распределить ответственность между LLM и обычным кодом?

Правильный ответ
  • ✅ LLM выделяет намерение и детали обращения, а код проверяет платежи и выполняет возврат по бизнес-правилам

Шаг 5

Команда превращает удачный прототип резюмирования обращений в функцию продукта.

Какие меры действительно нужны до запуска?

Правильный ответ
  • ✅ Обработать недоступность API, таймауты и ограничения провайдера
  • ✅ Валидировать ответ модели перед передачей следующему компоненту
  • ✅ Проверять пустой и некорректный вход до обращения к модели
  • ✅ Собирать метрики качества, задержки и расхода токенов

Шаг 6

Нужно рассчитать скидку: если сумма заказа больше 10 000 рублей, применить ровно 5%.

Какой подход лучше выбрать для основной логики?

Правильный ответ
  • ✅ Обычное условие и арифметика в коде

Шаг 7

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

Какие следующие действия полезны?

Правильный ответ
  • ✅ После изменения повторно прогнать старые и новые примеры
  • ✅ Сохранить обезличенные примеры ошибки для тестового набора
  • ✅ Проверить, достаточно ли модели входных данных и инструкции
  • ✅ Определить измеримый критерий правильного результата

Шаг 8

Очистка текста обращения

Перед отправкой обращения в модель приложение должно привести пользовательский ввод к аккуратному виду. Например, пользователь может добавить пробелы в начале строки, несколько пробелов между словами или переносы строк.

Задача

Реализуйте функцию normalize_request_text(value, max_length=500). Она должна проверить вход, убрать лишние пробельные символы и вернуть строку, которую уже можно передать AI-функции.

Требования

  • Для значения не типа str выбросьте TypeError.
  • max_length должен быть положительным целым числом; bool не допускается. Для недопустимого типа выбросьте TypeError, а для нуля или отрицательного значения — ValueError.
  • Удалите внешние пробелы и замените любые последовательности пробельных символов внутри строки одним пробелом.
  • Для пустого результата или текста длиннее max_length выбросьте ValueError.
  • Верните очищенную строку.

Пример результата

normalize_request_text("  Дважды\n  списали   деньги.  ")
# "Дважды списали деньги."

normalize_request_text("   ")
# ValueError

Заготовка кода уже находится в редакторе. Дополнительные сторонние библиотеки для решения не нужны.

Правильный ответ
def normalize_request_text(value: str, max_length: int = 500) -> str:
    if not isinstance(value, str):
        raise TypeError("value must be a string")
    if isinstance(max_length, bool) or not isinstance(max_length, int):
        raise TypeError("max_length must be an integer")
    if max_length <= 0:
        raise ValueError("max_length must be positive")
    normalized = " ".join(value.split())
    if not normalized:
        raise ValueError("text must not be empty")
    if len(normalized) > max_length:
        raise ValueError("text is too long")
    return normalized
def normalize_request_text(value: str, max_length: int = 500) -> str:
    if type(value) is not str or type(max_length) is not int:
        raise TypeError
    if max_length < 1:
        raise ValueError

    cleaned = " ".join(value.split())

    if len(cleaned) > max_length or len(cleaned) == 0:
        raise ValueError
    return cleaned
def normalize_request_text(value: str, max_length=500) -> str:
    if type(value) != str:
        raise TypeError
    if type(max_length) != int:
        raise TypeError
    if max_length <=0:
        raise ValueError
    if len(value) > max_length:
        raise ValueError
    res = ' '.join(value.split())
    if len(res) == 0:
        raise ValueError

    return res

Шаг 9

Выбор исполнителя задачи

В интернет-магазине появились три разных типа операций. Свободное сообщение клиента нужно понять с помощью LLM. Точную скидку следует рассчитать обычным кодом. Удаление данных клиента нельзя выполнять автоматически — его должен подтвердить человек.

Задача

Реализуйте функцию choose_processing_path(task_type). Аргумент task_type содержит не текст клиента, а служебное название типа операции. Функция должна вернуть служебную метку исполнителя: llm, code или human_review.

Требования

  • Принимайте только строку; для другого типа выбросьте TypeError.
  • Удалите внешние пробелы и приведите значение к нижнему регистру.
  • Для understand_free_text верните llm.
  • Для calculate_exact_discount верните code.
  • Для delete_customer_data верните human_review.
  • Для неизвестного типа выбросьте ValueError.

Пример результата

choose_processing_path("understand_free_text")
# "llm" — понять свободный текст клиента

choose_processing_path("calculate_exact_discount")
# "code" — выполнить точный расчёт

choose_processing_path("delete_customer_data")
# "human_review" — запросить подтверждение человека

Заготовка кода уже находится в редакторе. Дополнительные сторонние библиотеки для решения не нужны.

Правильный ответ
def choose_processing_path(task_type: str) -> str:
    if not isinstance(task_type, str):
        raise TypeError("task_type must be a string")

    task_type = task_type.strip().lower()

    paths = {
        "understand_free_text": "llm",
        "calculate_exact_discount": "code",
        "delete_customer_data": "human_review",
    }

    if task_type not in paths:
        raise ValueError("unknown task type")

    return paths[task_type]
def choose_processing_path(task_type: str) -> str:
    if type(task_type) != str:
        raise TypeError("Task type must be valid string")
    task_type = task_type.strip().lower()

    match task_type:
        case "understand_free_text":
            return "llm"
        case "calculate_exact_discount":
            return "code"
        case "delete_customer_data":
            return "human_review"
        case _:
            raise ValueError("Unexpected task type!")
def choose_processing_path(task_type: str) -> str:
    if type(task_type) != str:
        raise TypeError
    task_type = task_type.strip().lower()
    if task_type == 'understand_free_text':
        return 'llm'
    if task_type == 'calculate_exact_discount':
        return 'code'
    if task_type == 'delete_customer_data':
        return 'human_review'
    raise ValueError

Шаг 10

Контроль опасных действий

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

Задача

Реализуйте функцию can_execute_action(action, approved_by_human). Где action — служебное имя действия, а approved_by_human сообщает, подтвердил ли его сотрудник.

Требования

  • action должен быть строкой, а approved_by_human — строго значением типа bool. Для другого типа выбросьте TypeError.
  • Перед проверкой удалите внешние пробелы из action.
  • Действия draft_reply и summarize разрешены без подтверждения.
  • Действия refund, delete_data и change_access разрешены только при approved_by_human=True.
  • Для неизвестного действия выбросьте ValueError.

Пример результата

can_execute_action("summarize", False)       # True
can_execute_action("refund", False)          # False
can_execute_action("refund", True)           # True
can_execute_action("unknown", True)          # ValueError

Заготовка кода уже находится в редакторе. Дополнительные сторонние библиотеки для решения не нужны.

Правильный ответ
def can_execute_action(action: str, approved_by_human: bool) -> bool:
    if type(action) != str or type(approved_by_human) != bool:
        raise TypeError

    clean_action = action.strip()

    protect_action = {
        "refund",
        "delete_data",
        "change_access",
    }

    open_action = {
        "draft_reply",
        "summarize",
    }
    all_action = protect_action | open_action

    if clean_action not in all_action:
        raise ValueError

    if clean_action in protect_action and not approved_by_human:
        return False

    return True
def can_execute_action(action: str, approved_by_human: bool) -> bool:
    # Напишите реализацию.
    if type(action) != str:
        raise TypeError("Action is not string")
    if type(approved_by_human) != bool:
        raise TypeError("approved_by_human is not bool")
    action = action.strip()

    if action in ("draft_reply", "summarize"):
        return True
    elif action in ("refund", "delete_data", "change_access"):
        return approved_by_human
    else:
        raise ValueError("Unexpected action value")
def can_execute_action(action: str, approved_by_human: bool) -> bool:
    should_be_approved = {'refund', 'delete_data', 'change_access'}
    shouldnt_be_approved = {'draft_reply', 'summarize'}

    if not isinstance(action, str):
        raise TypeError("The action should be a str")

    if not isinstance(approved_by_human, bool):
        raise TypeError("The approved_by_human should be a bool")

    action = action.strip()

    if action in shouldnt_be_approved:
        return True

    if action in should_be_approved:
        return approved_by_human

    raise ValueError()