Содержание
- Чем AI-агент отличается от чат-бота
- Какой мотор взять, чтобы сделать своего AI-агента из России
- Что подготовить до первого запуска
- Код агента целиком
- Как выглядит прогон
- Сколько съедает один прогон
- Три ошибки, на которых спотыкается первый агент
- Когда своего AI-агента проще собрать без кода
- Что проверить перед тем, как отдать агента людям
- Чек-лист: как сделать своего AI-агента за вечер
- Частые вопросы
Как сделать своего AI-агента: 77 строк кода и прогон
Черновик готовит редакция с помощью ИИ. За стандарт издания отвечает главный редактор — Валерий Курземнек.
Материал редакции Зерокодера. Обновлено 14 сентября 2026 года.
Как сделать своего AI-агента: взять языковую модель, которая умеет вызывать инструменты, описать ей две-три функции и замкнуть цикл: модель просит инструмент, программа его вызывает, модель продолжает с результатом на руках. На YandexGPT такой агент занимает 77 строк Python, а один прогон укладывается в три обращения к модели и 623–626 токенов. Ниже код целиком, дословный лог обмена и измеренные числа.
Коротко, что показывает этот разбор:
- Рабочий агент — это цикл вокруг вызова инструментов, и он помещается в один файл на 77 строк.
- Из семи адресов моделей Yandex Foundation Models вызов инструментов приняли четыре, остальные три ответили ошибкой с конкретным текстом.
- Десять прогонов подряд: три обращения к модели в каждом, 623–626 токенов и 2,42–3,87 секунды на задачу.
- Тот же агент на чужом моторе, который сам возвращает стоимость, обошёлся в 0,000104 доллара за прогон.
- Три самые дорогие поломки новичка — модель без поддержки инструментов, чужой код на снятом методе библиотеки и молчаливый инструмент, вернувший строку вместо числа.
Чем AI-агент отличается от чат-бота
Чат-бот отвечает текстом на текст. AI-агент получает задачу, решает, какой внешний инструмент ему нужен, просит программу его вызвать, получает результат и продолжает рассуждение с этим результатом на руках. Технически разница помещается в одно поле запроса: вместе с сообщениями в модель уходит список функций с описаниями и параметрами, а модель в ответ присылает структуру с именем функции и аргументами вместо обычного текста.
Журнал «Код» Яндекс Практикума описывает этот механизм так: «Свежие модели поколения GPT-5, YandexGPT, последние открытые Llama/DeepSeek из коробки умеют в Tool Calling (он же Function Calling, он же вызов инструментов). Под капотом передача таких инструментов — это обычная отправка JSON-схемы с названием функции и её аргументами».
Практическое правило: агент начинается там, где программа отдаёт модели право выбирать действие; всё остальное — оболочка вокруг этого выбора. Разбор самого понятия — в материале кто такой ИИ-агент, а типы агентов — в обзоре применения.
Какой мотор взять, чтобы сделать своего AI-агента из России
Мотор агента — это модель, умеющая вызывать инструменты. 14 сентября 2026 года мы отправили один и тот же запрос со списком инструментов на семь адресов Yandex Foundation Models. Приняли четыре, и каждый вернул структуру toolCall вместо текста:
| Адрес модели | Ответ | Версия модели |
|---|---|---|
yandexgpt-lite/latest |
вызов инструмента | 25.03.2025 |
yandexgpt-lite/rc |
вызов инструмента | 25.03.2025 |
yandexgpt/latest |
вызов инструмента | 09.02.2025 |
yandexgpt/rc |
вызов инструмента | yagpt-5.1-2025-08 |
qwen3-235b-a22b-fp8/latest |
HTTP 400 | — |
llama-lite/latest |
HTTP 404 | — |
gpt-oss-120b/latest |
HTTP 404 | — |
Три отказа различаются по смыслу. Открытая Qwen3 ответила кодом 400 и телом «Model is not available via gRPC API. Please use HTTP OpenAI API instead.» — модель в каталоге есть, но её дают через другой протокол. Два других адреса вернули 404 «unknown model»: таких имён в каталоге просто нет. Вывод этого прогона лежит в нашем журнале probe_models.txt.
Выдачу по голове «ai агент» и пяти запросам кластера мы сняли 14 сентября 2026 года: 26 уникальных страниц, 25 снятых файлов, 22 прочитанных. Одна страница не отдалась по TLS, ещё три вернули JS-оболочку без текста, и в счёт ниже они не входят. Гайд chimitdorzhi.tech говорит про YandexGPT: «Поддерживает function calling начиная с определённых версий моделей» — и версии не называет. Из 22 прочитанных страниц выдачи конкретный адрес модели вида gpt://<каталог>/<модель> не приводит ни одна. Разница между обтекаемой формулировкой и списком из четырёх рабочих адресов — это разница между вечером чтения и десятью минутами работы.
Что подготовить до первого запуска
Скрипту нужны две вещи из консоли Yandex Cloud: идентификатор каталога (выглядит как b1g…) и API-ключ сервисного аккаунта. Ключ уходит в заголовок Authorization: Api-Key <ключ>, каталог подставляется в адрес модели gpt://<каталог>/yandexgpt-lite/rc. Обе величины скрипт читает из переменных окружения YC_API_KEY и YC_FOLDER_ID, чтобы ключ не попал в код и в историю правок.
Сразу про географию. Наша машина выходит в интернет через Швецию — замер ipinfo.io во время прогона дал 130.17.14.168, AS48040 Fornex Hosting S.L., Falkenberg. Поэтому наши собственные прогоны доказывают ровно одно: адрес ответил на запрос с европейского адреса. Доступность из России мы мерили чужими узлами check-host.net в Москве и Санкт-Петербурге: эндпоинт llm.api.cloud.yandex.net/foundationModels/v1/completion отдал обоим узлам HTTP 405 Method Not Allowed, то есть ответил и сообщил, что ждёт POST. Сайт Центробанка, откуда агент берёт курс, отдал обоим узлам 200, консоль console.yandex.cloud — 302. Ответ сервера узлу дата-центра не равен экрану живого пользователя: вход в аккаунт, оплата и генерация так не проверяются.
Код агента целиком
Ниже файл agent.py без сокращений: 77 строк, из них 70 непустых. Два инструмента — курс валюты с сайта Центробанка и калькулятор. Прогон этого кода показан ниже.
# -*- coding: utf-8 -*-
"""agent.py — простейший ИИ-агент: цикл «модель -> инструмент -> модель».
Мотор — Yandex Cloud Foundation Models, адрес yandexgpt-lite/rc, два инструмента:
курс ЦБ РФ и калькулятор. Ключ и каталог берутся из переменных окружения.
Запуск: python agent.py "во сколько рублей обойдутся 149 долларов по курсу ЦБ на сегодня"
"""
import os, sys, json, urllib.request, urllib.error, xml.etree.ElementTree as ET
API = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
KEY, FOLDER = os.environ["YC_API_KEY"], os.environ["YC_FOLDER_ID"]
def kurs_cb(valuta: str) -> str:
"""Курс валюты к рублю с сайта Центробанка на сегодня."""
xml = urllib.request.urlopen("https://www.cbr.ru/scripts/XML_daily.asp", timeout=30).read()
for v in ET.fromstring(xml).findall("Valute"):
if v.findtext("CharCode") == valuta.upper():
return f"{valuta.upper()}: {v.findtext('Value')} руб. за {v.findtext('Nominal')} ед."
return f"валюта {valuta} в справочнике ЦБ не найдена"
def schet(vyrazhenie: str) -> str:
"""Арифметика: сложение, вычитание, умножение, деление."""
razresheno = set("0123456789.,+-*/() ")
if set(vyrazhenie) - razresheno:
return "в выражении есть запрещённые символы"
return str(eval(vyrazhenie.replace(",", "."), {"__builtins__": {}}, {}))
INSTRUMENTY = {"kurs_cb": kurs_cb, "schet": schet}
OPISANIE = [
{"function": {"name": "kurs_cb", "description": kurs_cb.__doc__,
"parameters": {"type": "object", "properties": {
"valuta": {"type": "string", "description": "код валюты, например USD"}},
"required": ["valuta"]}}},
{"function": {"name": "schet", "description": schet.__doc__,
"parameters": {"type": "object", "properties": {
"vyrazhenie": {"type": "string", "description": "например 149*81.5"}},
"required": ["vyrazhenie"]}}},
]
def sprosit(messages):
body = {"modelUri": f"gpt://{FOLDER}/yandexgpt-lite/rc",
"completionOptions": {"temperature": 0.0, "maxTokens": 800},
"messages": messages, "tools": OPISANIE}
req = urllib.request.Request(API, data=json.dumps(body).encode(),
headers={"Authorization": "Api-Key " + KEY,
"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=90) as r:
return json.loads(r.read())
def agent(zadacha, max_shagov=6):
messages = [{"role": "system", "text": "Ты ассистент. Считай только инструментами."},
{"role": "user", "text": zadacha}]
itogo_tokenov = 0
for shag in range(1, max_shagov + 1):
otvet = sprosit(messages)
itogo_tokenov += int(otvet["result"]["usage"]["totalTokens"])
soobshchenie = otvet["result"]["alternatives"][0]["message"]
vyzovy = soobshchenie.get("toolCallList", {}).get("toolCalls", [])
if not vyzovy:
return soobshchenie.get("text", ""), shag, itogo_tokenov
messages.append(soobshchenie)
rezultaty = []
for v in vyzovy:
f = v["functionCall"]
argumenty = f.get("arguments") or {}
znachenie = INSTRUMENTY[f["name"]](**argumenty)
print(f" шаг {shag}: вызван {f['name']}({argumenty}) -> {znachenie}")
rezultaty.append({"functionResult": {"name": f["name"], "content": znachenie}})
messages.append({"role": "assistant", "toolResultList": {"toolResults": rezultaty}})
return "агент не уложился в лимит шагов", max_shagov, itogo_tokenov
if __name__ == "__main__":
sys.stdout.reconfigure(encoding="utf-8")
zadacha = sys.argv[1] if len(sys.argv) > 1 else "сколько рублей стоят 149 долларов по курсу ЦБ"
print("задача:", zadacha)
tekst, shagov, tokenov = agent(zadacha)
print("ответ:", tekst)
print(f"шагов: {shagov}; токенов: {tokenov}")
Файл делится на четыре части. kurs_cb и schet — руки агента, обычные функции Python. Список OPISANIE — то же самое словами для модели: имя, назначение, схема аргументов. sprosit отправляет в Foundation Models сообщения вместе с этим списком. agent крутит цикл: получила вызов — исполнила, вернула результат в переписку, спросила снова. Лимит max_shagov=6 останавливает агента, зациклившегося на инструменте.
Одна честная оговорка про schet: внутри eval с белым списком символов. Для демонстрации этого хватает, для боевого агента считать выражения нужно разбором, без eval.
Как выглядит прогон
Вот дословный обмен одного прогона 14 сентября 2026 года — то, что вернула модель на каждом шаге, и то, чем ответил инструмент:
--- шаг 1: 1.04 c, токенов 171, версия модели 25.03.2025
модель вернула: {"role": "assistant", "toolCallList": {"toolCalls": [{"functionCall":
{"name": "kurs_cb", "arguments": {"valuta": "USD"}}}]}}
инструмент kurs_cb{'valuta': 'USD'} вернул: USD: 84,2569 руб. за 1 ед.
--- шаг 2: 0.79 c, токенов 225, версия модели 25.03.2025
модель вернула: {"role": "assistant", "toolCallList": {"toolCalls": [{"functionCall":
{"name": "schet", "arguments": {"vyrazhenie": "149*84.2569"}}}]}}
инструмент schet{'vyrazhenie': '149*84.2569'} вернул: 12554.2781
--- шаг 3: 0.92 c, токенов 229, версия модели 25.03.2025
модель вернула: {"role": "assistant", "text": "149 долларов по курсу ЦБ на сегодня
обойдутся в 12554.2781 рубля."}
Задача была одна: «во сколько рублей обойдутся 149 долларов по курсу ЦБ на сегодня». Модель сама решила, что сначала нужен курс, а потом умножение, и сама выбрала аргументы. Курс 84,2569 рубля за доллар приехал в этот момент с сайта Центробанка мимо памяти модели — в этом и есть весь смысл инструментов.
Одна деталь, которая в описаниях цикла теряется. При temperature 0.0 десять прогонов подряд дали одинаковые вызовы инструментов и разную итоговую фразу: пять раз «12554.28 рублей» и пять раз «12554.2781 рубля». Нулевая температура делает предсказуемым выбор действия, а формулировку ответа она не фиксирует. Если следующий шаг вашей программы разбирает ответ агента текстом, закладывайтесь на этот разброс.
Сколько съедает один прогон
Десять прогонов одной задачи, двумя заходами по пять, мотор yandexgpt-lite/rc:
| Прогон | Заход | Шагов | Токенов | Секунд |
|---|---|---|---|---|
| 1 | первый | 3 | 624 | 2,87 |
| 2 | первый | 3 | 625 | 2,42 |
| 3 | первый | 3 | 623 | 3,01 |
| 4 | первый | 3 | 624 | 2,97 |
| 5 | первый | 3 | 624 | 2,97 |
| 6 | второй | 3 | 626 | 2,57 |
| 7 | второй | 3 | 625 | 3,04 |
| 8 | второй | 3 | 624 | 2,64 |
| 9 | второй | 3 | 623 | 3,22 |
| 10 | второй | 3 | 625 | 3,87 |
Разброс по токенам — три токена на медиану 624, по времени — полторы секунды. Агент платит за каждый круг цикла: три обращения к модели вместо одного. Это главная статья расхода, и считать её нужно на стадии проектирования.
Цену в рублях мы не приводим: страница цен Yandex Cloud нашей машине не открылась, она отдала проверку браузера, а число, которого мы не видели своими глазами, в текст не идёт. Зато цена измерена на моторе, который возвращает её сам. Тот же агент и та же задача через OpenRouter на openai/gpt-4o-mini: три обращения, 510 токенов, 3,55 секунды и поле cost в сумме 0,000104 доллара за прогон. Сто прогонов такого агента стоят около цента.
Для сравнения — единственный собственный замер денег, который встретился на 22 прочитанных страницах выдачи. Skillfactory Media собрала агента в OpenAI Agent Builder и написала под скриншотом расхода: «В этот день мы отправили 16 запросов, которые стоили 40 центов». Это 2,5 цента за запрос; весь наш прогон из трёх запросов обошёлся в 0,0104 цента. Разница объясняется задачей и моделью: там разбор вакансий с базой знаний на gpt-4.1, у нас два коротких вызова на gpt-4o-mini. Поэтому вопрос о цене прогона без названной задачи и модели ничего не значит.
Три ошибки, на которых спотыкается первый агент
Модель без поддержки инструментов. Список tools уходит, а в ответ приходит код 400 или 404. Наш прогон: qwen3-235b-a22b-fp8/latest вернул «Model is not available via gRPC API. Please use HTTP OpenAI API instead.», два несуществующих имени — 404 «unknown model». Лечится сменой адреса модели на один из четырёх рабочих; правка запроса и промпта тут бесполезна.
Чужой код на снятом методе библиотеки. Мы взяли блок кода из руководства developers.sber.ru и запустили его. Как напечатано, он не компилируется: тело функции идёт без отступа, а кавычки на странице отображаются сущностями " и «. После восстановления отступов и кавычек код компилируется и падает уже на вызове, под openai 2.53.0: «You tried to access openai.ChatCompletion, but this is no longer supported in openai>=1.0.0». Метод openai.ChatCompletion убран из библиотеки, и никакая правка промпта это не чинит. Вывод прогона — в нашем журнале probe_sber_code.txt. Вывод: перед копированием кода из гайда смотрите на версию библиотеки, под которую он написан.
Инструмент вернул строку, где модель ждала число. Ответ Центробанка приходит в формате 84,2569 с запятой, и если отдать его модели как есть, а потом попросить умножить — в выражение поедет запятая. В нашем коде schet заменяет запятую на точку первой же строкой. Такие швы между инструментом и моделью ломаются чаще, чем сама модель.
Та же мина у чужих провайдеров: запрос к google/gemini-2.0-flash-001 через OpenRouter вернул 404 «No endpoints found for google/gemini-2.0-flash-001.» — имя модели живое, а провайдер её в тот момент не отдавал.
Когда своего AI-агента проще собрать без кода
Код нужен там, где агент живёт внутри вашей программы и его логику вы меняете сами. Если задача — посадить агента на входящие сообщения или на расписание, быстрее собрать его в конструкторе: n8n, Yandex AI Studio, BotHelp, Botman. Skillbox Media, например, собрала агента-новостника в n8n и опубликовала результаты своих проверок скриншотами, включая честную подпись «Этот тест ИИ-агент провалил». Такой путь мы разбираем отдельно — в материале про сборку агента в Yandex AI Studio без разработчика и в сравнении AgentKit и n8n.
Граница простая. Конструктор быстрее до первого результата и упирается в потолок на нестандартной логике. Код медленнее на старте и дальше растёт вместе с задачей. Оба пути используют один и тот же механизм вызова инструментов, так что понимание цикла пригодится в любом случае.
Что проверить перед тем, как отдать агента людям
- Лимит шагов стоит и срабатывает: зацикленный агент обязан останавливаться сам.
- Каждый инструмент отвечает понятной строкой на плохой ввод. В нашем коде
kurs_cbна неизвестную валюту возвращает текст и не бросает исключение. - Ключ читается из переменной окружения и не лежит в файле с кодом.
- Есть журнал: какой инструмент вызван, с какими аргументами и что вернул. Без него разбирать поломку нечем.
- Действия, которые меняют чужие данные или тратят деньги, стоят под ручным подтверждением.
- Формулировка итогового ответа проверена на разброс: та же задача прогнана несколько раз подряд.
Чек-лист: как сделать своего AI-агента за вечер
| Шаг | Что делаете | Проверка |
|---|---|---|
| 1 | Завели каталог и API-ключ в Yandex Cloud | YC_API_KEY и YC_FOLDER_ID видны скрипту |
| 2 | Выбрали адрес модели с поддержкой инструментов | в ответ пришёл toolCall вместо текста |
| 3 | Написали две функции-инструмента | каждая возвращает строку и не падает на плохом вводе |
| 4 | Описали их для модели схемой параметров | описание совпадает с реальной сигнатурой функции |
| 5 | Замкнули цикл с лимитом шагов | агент останавливается сам |
| 6 | Прогнали задачу пять раз | шаги одинаковые, расход известен |
| 7 | Посчитали расход | токены и секунды на прогон записаны |
Частые вопросы
Нужно ли уметь программировать, чтобы сделать своего AI-агента?
Для пути с кодом хватает базового Python: весь агент в этом разборе — 77 строк, из которых 26 занимают два инструмента и их описание для модели. Для пути без кода программировать не нужно вовсе: агент собирается в конструкторе вроде n8n или Yandex AI Studio из готовых блоков.
Какие модели YandexGPT принимают вызов инструментов?
В нашем прогоне 14 сентября 2026 года список tools приняли четыре адреса: yandexgpt-lite/latest, yandexgpt-lite/rc, yandexgpt/latest и yandexgpt/rc. Все четыре вернули структуру toolCall с именем функции и аргументами. Адреса llama-lite/latest и gpt-oss-120b/latest ответили 404 «unknown model», а qwen3-235b-a22b-fp8/latest — 400 с текстом «Model is not available via gRPC API. Please use HTTP OpenAI API instead.».
Сколько стоит один прогон агента?
Наш агент на yandexgpt-lite/rc тратил 623–626 токенов за три обращения к модели. В рублях мы цену не называем: страница цен Yandex Cloud нашей машине не открылась и отдала проверку браузера. На моторе, который возвращает стоимость сам, тот же агент и та же задача обошлись в 0,000104 доллара за прогон — OpenRouter, модель openai/gpt-4o-mini, 510 токенов.
Работает ли всё это из России?
Наши прогоны сделаны с адреса в Швеции (130.17.14.168, Falkenberg), поэтому о доступности из России они не говорят ничего. Отдельный замер чужими узлами check-host.net в Москве и Санкт-Петербурге показал, что эндпоинт llm.api.cloud.yandex.net/foundationModels/v1/completion отвечает обоим узлам кодом 405 Method Not Allowed, то есть принимает соединение и ждёт POST. Вход в аккаунт, оплата и генерация таким замером не проверяются.
Сколько шагов делает агент на простой задаче?
В десяти прогонах подряд задача «во сколько рублей обойдутся 149 долларов по курсу ЦБ на сегодня» решалась ровно за три обращения к модели: вызов курса, вызов калькулятора, текстовый ответ. Каждый круг цикла — отдельный оплаченный запрос, поэтому число шагов стоит считать заранее.
Почему агент при temperature 0 даёт разные ответы?
Нулевая температура сделала предсказуемым выбор инструментов: во всех десяти прогонах модель вызвала kurs_cb, затем schet с одинаковыми аргументами. Итоговая формулировка при этом отличалась: пять раз «12554.28 рублей» и пять раз «12554.2781 рубля». Если следующий шаг программы разбирает ответ агента текстом, разброс нужно учитывать.
