Создаём ИИ-агента с нуля на Python: пошаговый гайд 2026 | AiManual
AiManual Logo Ai / Manual.
15 Июн 2026 Гайд

Создаём ИИ-агента с нуля на Python: цикл, LLM, контекст и пользовательский ввод

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

Реклама
cliv2

Почему свой агент, а не очередной фреймворк?

К 2026 году агенты стали мейнстримом. LangChain, CrewAI, AutoGPT — фреймворков горы. Но каждый раз, когда я открываю очередную абстракцию, чувствую себя в музее восковых фигур: красиво, но не дышит. За фасадом «простого API» скрываются тонны магии, которую невозможно отладить, когда что-то идёт не так.

Настоящий DevOps не верит в волшебство. Он верит в код, который можно прочитать и изменить. Поэтому я предлагаю собрать ИИ-агента с нуля. Минимум зависимостей, полный контроль, ясная архитектура. Всё, что вам нужно — Python 3.13+ и API-ключ от любой LLM (я возьму OpenAI, но вы легко переключитесь на локальную модель через Ollama).

Эта статья — прямой наследник нашего гайда по созданию Claude Code с нуля. Теперь мы идём ещё глубже: убираем всё лишнее и оставляем ядро — цикл, LLM, контекст и пользовательский ввод.

Архитектура агента за одну минуту

Агент — это просто бесконечный цикл, который:

  • Читает пользовательский ввод (или задачу из очереди)
  • Отправляет историю диалога в LLM
  • Получает ответ (текст или вызов инструмента)
  • Выполняет действие, обновляет контекст и повторяет

Всё. Никакой магии, никаких скрытых очередей. Три компонента: мозг (LLM), память (контекст) и руки (инструменты). Как в статье про Agent Skills, но без лишней сложности — мы начинаем с минимального набора.

Шаг 1. Подключаем LLM: без фреймворков, чистыми HTTP

Забудьте про LangChain. Мы будем использовать официальный клиент OpenAI (или любой совместимый). Установка:

pip install openai python-dotenv

Создайте файл .env с вашим ключом. Теперь напишем функцию вызова LLM:

import os
from openai import OpenAI
from typing import List, Dict, Optional, Callable

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

def get_llm_response(
    messages: List[Dict],
    model: str = "gpt-4o-2026-05-13",  # актуальная версия на июнь 2026
    tools: Optional[List[Dict]] = None
) -> Dict:
    try:
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            tools=tools,
            temperature=0.7
        )
        return response.choices[0].message.model_dump()
    except Exception as e:
        print(f"[ERROR] LLM call failed: {e}")
        # возвращаем fallback
        return {"role": "assistant", "content": "Произошла ошибка. Попробуйте позже."}

Типичная ошибка: использовать openai.ChatCompletion.create — это устаревший API. В версии 1.x клиент изменился, всегда проверяйте документацию.

Можно легко переключиться на локальную модель через Ollama — достаточно изменить base_url клиента и указать модель llama3.2 или mistral. Подробнее о локальных LLM мы писали в гайде по EdTech-агенту на чистом Python и Gemini.

Шаг 2. Главный цикл: while True без затей

Сердце агента — простой цикл. Он запрашивает ввод, вызывает LLM, обрабатывает результат и повторяет. Добавим поддержку завершения по команде exit.

def run_agent(system_prompt: str = "Ты — полезный ассистент."):
    messages = [{"role": "system", "content": system_prompt}]
    print("ИИ-агент запущен. Введите 'exit' для выхода.")
    while True:
        user_input = input("\n> ")
        if user_input.lower() == "exit":
            print("Завершение работы.")
            break
        messages.append({"role": "user", "content": user_input})
        response = get_llm_response(messages)
        assistant_msg = response["content"]
        print(f"Ассистент: {assistant_msg}")
        messages.append({"role": "assistant", "content": assistant_msg})

Уже работает. Но контекст будет расти бесконечно — рано или поздно вы упрётесь в токен-лимит и кошелёк. Нужно управлять длиной истории.

Шаг 3. Контекст: не даём агенту «забыть» всё

Секрет хорошего агента — правильное усечение контекста. Мы не можем хранить всю историю, но и терять суть нельзя. Решение — sliding window: храним system prompt и последние K сообщений.

MAX_HISTORY = 10  # сохраняем последние 10 сообщений

def trim_context(messages: List[Dict]) -> List[Dict]:
    if len(messages) - 1 <= MAX_HISTORY:  # минус system prompt
        return messages
    # оставляем system + последние MAX_HISTORY сообщений
    return [messages[0]] + messages[-MAX_HISTORY:]

Обновим цикл: после каждого обмена с LLM отрезаем лишнее.

Но есть нюанс: если агент возвращает вызов инструмента (function calling), мы должны обработать результат и снова передать его модели. Иначе агент «зависнет», не получив ответа инструмента.

Шаг 4. Инструменты: даём агенту руки

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

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_time",
            "description": "Возвращает текущую дату и время в формате ISO.",
            "parameters": {}
        }
    }
]

def execute_tool(tool_name: str, tool_args: dict) -> str:
    if tool_name == "get_current_time":
        from datetime import datetime
        return datetime.now().isoformat()
    return f"Инструмент {tool_name} не найден."

Теперь нужно изменить цикл, чтобы после вызова LLM проверять, не хочет ли модель вызвать инструмент. Если да — выполняем, результат передаём как сообщение с ролью tool и повторяем запрос к LLM.

def run_agent_with_tools():
    messages = [{"role": "system", "content": "Ты — ассистент. Можешь узнавать время."}]
    while True:
        user_input = input("\n> ")
        if user_input.lower() == "exit":
            break
        messages.append({"role": "user", "content": user_input})
        while True:  # цикл инструментов
            response = get_llm_response(messages, tools=tools)
            if response.get("tool_calls"):
                for tc in response["tool_calls"]:
                    tool_name = tc["function"]["name"]
                    tool_args = tc["function"]["arguments"]
                    result = execute_tool(tool_name, tool_args)
                    messages.append({
                        "role": "tool",
                        "tool_call_id": tc["id"],
                        "content": result
                    })
            else:
                assistant_msg = response["content"]
                print(f"Ассистент: {assistant_msg}")
                messages.append({"role": "assistant", "content": assistant_msg})
                break
        messages = trim_context(messages)

⚠️ Важно: никогда не пропускайте проверку tool_calls — иначе агент будет думать, что он вызвал инструмент, а ответа не получит. Типичная ошибка, из-за которой агенты «зацикливаются».

Шаг 5. Обработка ошибок и ограничений

Агент будет падать, если:

  • Кончились токены в API (rate limit)
  • Инструмент вернул ошибку
  • Модель сгенерировала некорректный JSON для вызова функции

Добавим простую retry-логику с экспоненциальной задержкой и обработчиками для инструментов:

import time
from openai import RateLimitError

def safe_llm_call(messages, tools=None, retries=3):
    for attempt in range(retries):
        try:
            return get_llm_response(messages, tools=tools)
        except RateLimitError:
            wait = 2 ** attempt
            print(f"Rate limit, ждём {wait}с...")
            time.sleep(wait)
        except Exception as e:
            print(f"Ошибка LLM: {e}")
            if attempt == retries - 1:
                return {"role": "assistant", "content": "Извините, ошибка."}

Шаг 6. Расширяем: память, RAG, мониторинг

Минимальный агент готов. Дальше можно надстраивать:

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

💡
Хотите создать полноценный coding assistant? Мы сделали это в туториале по Claude Code с нуля — там больше инструментов и работа с файлами.

Пара слов о качестве кода

Когда вы пишете ИИ-агента, особенно для продакшена, не забывайте о тестировании. Агенты с LLM — недетерминированные системы. Мы рекомендуем подход TDD и контроль через «контекстные файлы» вроде AGENTS.md. Это снижает количество сюрпризов.

Если вы хотите углубиться в архитектуру и узнать, как строить production-ready агентов с микросервисной логикой, обратите внимание на курс «Python-разработчик + ИИ» от Skillbox. Там разбирают и продвинутые паттерны, и практику работы с нейросетями.

Неочевидный совет напоследок

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

Подписаться на канал