# Создаем своего агента

> [HTML-версия](https://learnvibecoding.ru/publiclessons/sozdaem-svoego-agenta) · [Индекс для LLM](https://learnvibecoding.ru/llms.txt) · [Политика использования материалов](https://learnvibecoding.ru/politika-materialov)
> Материалы защищены. Обучение LLM без согласия запрещено. При разрешённом использовании — обязательна прямая ссылка на страницу-источник.
> Изучим лёгкий Python-фреймворк, который даёт LLM-модели «агентность»: мыслить шагами (Thought), вызывать инструменты (Action), читать результаты (Observation) и делать многошаговые задачи

**Курс:** Создание своего агента

> Когда вы начинаете создавать проекты самостоятельно вам будет не привычно читать код, следовать инструкциям. Это нормально, со временем вы привыкнете.
> 

# Что такое smolagents (в 1 фразе)

**smolagents** — это лёгкий Python-фреймворк, который даёт LLM-модели «агентность»: мыслить шагами (*Thought*), вызывать инструменты (*Action*), читать результаты (*Observation*) и делать многошаговые задачи. Вы прописываете **инструменты** (функции), а фреймворк берёт на себя цикл «думай → действуй → наблюдай».

---

# 0) Где писать код, что открыть, что установить:

Открой, где ты будешь писать код, это должен быть какой-то помощник для кода:

- Открой Cursor и другие помощники по созданию кода

**Cursor/Codeium/Copilot/Codex**:

1. Создай репозиторий на GitHub → открой в Cursor.
    - далее расскажи помощнику, которого ты выбрал для кода, что ты планируешь сделать (какого агента)
2. В «инструкции» (Rules) опиши проект: «Создаю агента на smolagents, инструменты: погода».
3. помощник тебе предложит установить необходимое окружение для создания кода
4. Проси сгенерировать тесты, обёртки, requirements, Dockerfile.
5. Храни ключи в `.env`, подгружай через `python-dotenv`.

<aside>
💡

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

</aside>

---

# 1) Установка и ключи модели

smolagents умеет работать с разными LLM:

- **OpenAI** (если есть ключ `OPENAI_API_KEY`)
- **Hugging Face Inference** (если есть `HUGGING_FACE_HUB_TOKEN`)
- Opensource

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

## Плюсы/минусы провайдеров (кратко)

**Hugging Face Inference API**

- Часто дешевле/проще для опытов, много open-source моделей.
- Можно выбрать небольшие модели (быстрее/дешевле).
- Качество и стиль ответа зависят от выбранной модели; иногда требуется подобрать.

**OpenAI**

- Очень сильные модели (качество генерации, следование инструкциям).
- Удобные фичи экосистемы (vision, structured output и т.п.).
- Платно, возможны ограничения по странам/биллинг.

Поставим пакеты (выполни в терминале):

```bash
pip install "smolagents[litellm]" duckduckgo-search langchain-community langchain-text-splitters

```

это помогает установить протоколы для общения с llm

## Когда они нужны

- `duckduckgo-search` — если хотите, чтобы агент умел **искать в вебе** (инструмент DuckDuckGoSearchTool).
- `langchain-community` и `langchain-text-splitters` — если планируете **ретривер / разбиение документов на чанки** (RAG).
- `smolagents[litellm]` — этот мы оставили (в requirements) для работы с разными LLM-провайдерами через LiteLLM.

### Памятка: что к чему

| Функция | Пакет(ы) |
| --- | --- |
| Базовый агент + OpenAI | `smolagents[litellm]`, `openai` |
| HTTP API (UI ↔ агент) | `fastapi`, `uvicorn`, `python-dotenv` |
| Реальная погода | `requests` |
| Веб-поиск (инструмент) | `duckduckgo-search` |
| RAG/чанкование текстов | `langchain-community`, `langchain-text-splitters` |

---

Если используешь **OpenAI для решения своей задачи**:

Зарегистрироваться на https://platform.openai.com/settings/organization/api-keys и создать ключ для подключения к LLM

```bash
pip install openai
# и выставь переменную окружения:
# Linux/macOS:
export OPENAI_API_KEY="твой_ключ"
# Windows (Powershell):
setx OPENAI_API_KEY "твой_ключ"

```

Если используешь **Hugging Face Inference для решения своей задачи** :

Зарегистрироваться на **Hugging Face** и получить ключ к доступу агента

```bash
pip install huggingface_hub
# И залогинься (один раз):
huggingface-cli login

```

---

Если используешь **OpenRouter или AgentRouter** нужно:

1. Зарегистрироваться на [openrouter.ai](http://openrouter.ai/) и создать API-ключ (ключ нужно скопировать сразу, потом не будет видно) — это базовый шаг для аутентификации.
2. Для Cursor — установить MCP (Model Context Protocol) клиент, который использует OpenRouter. Обычно это делается так:
⦁ Склонировать репозиторий клиента
⦁ Вставить API-ключ в .env файл (переменная OPENROUTER_API_KEY)
⦁ Настроить файл mcp.json в конфигурации Cursor, чтобы он запускал клиента с этим ключом и моделью (пример в источнике ).
3. Перезапустить Cursor и выбрать или добавить клиент OpenRouter в настройках.

---

### ПРИМЕР

делаем **самого простого агента, который подключен к интерфейсу вашего сайта и отвечает на вопросы про информацию о погоде** на `smolagents` 

# Как будет выглядеть структура проекта

```
weather-agent/
 ├─ server.py              # HTTP-сервер (FastAPI) + сборка агента
 ├─ agent_tools.py         # инструменты агента (get_weather)
 ├─ .env                   # ваши ключи (не коммитим!)
 ├─ requirements.txt       # зависимости
 └─ .venv/                 # виртуальное окружение (создастся командой)

```

**`.env`** хранит приватные ключи (например, `OPENAI_API_KEY`, `OPENAI_MODEL`).

Его **никогда** не коммитим — добавьте в `.gitignore`.

### При работе с помощником

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

После того как вы опишете задачу для своего агента, помощник сам сгенерирует код и добавит его в файл **agent_weather.py**, который упоминался ранее.

Ваша задача — внимательно изучить этот файл и убедиться, что в нём корректно настроено всё, о чём говорилось в уроках:

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

---

## Что где настраивается (коротко)

- **Температура**: параметр `temperature=` в `OpenAIServerModel(...)` или `InferenceClientModel(...)`. Чем ниже (например, 0.1–0.3), тем детерминированнее ответы.
- **Модель**: через `OPENAI_MODEL` (OpenAI) или `HF_MODEL` (Hugging Face). Подбирайте удобную вам инструкционную модель, Opensource
- **Инструменты**: декоратор `@tool` над Python-функцией. Агент сам решает, когда её вызывать, основываясь на `SYSTEM_PROMPT`.

---

# Пример. Погодный агент на OpenAI

(по желанию можно указать модель, например `gpt-4o-mini`):

# 1) Установите зависимости

```bash
pip install "smolagents[litellm]" openai fastapi uvicorn python-dotenv requests
# если делаете без FastAPI/UI, можно без fastapi/uvicorn/python-dotenv

```

# 2) Задайте ключи окружения

```bash
# macOS / Linux
export OPENAI_API_KEY="ВАШ_КЛЮЧ"
export OPENAI_MODEL="gpt-4o-mini"  # или другой

# Windows (PowerShell)
setx OPENAI_API_KEY "ВАШ_КЛЮЧ"
setx OPENAI_MODEL "gpt-4o-mini"

```

# 3) Обновлённый старт файла `agent_weather_openai.py`

```python
# agent_weather_openai.py
# Погодный агент на smolagents + OpenAI + requests. Работает с Open-Meteo (без ключа).
import os
import sys
import requests
# ВАЖНО: сам пакет openai нужен для OpenAIServerModel (через smolagents[litellm])
import openai  # импортируем, чтобы убедиться, что пакет установлен

from smolagents import CodeAgent, tool, OpenAIServerModel

# --- проверки окружения ---
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
if not OPENAI_API_KEY:
    print("ERROR: Не найден OPENAI_API_KEY. Задайте переменную окружения.")
    sys.exit(1)

MODEL_ID = os.getenv("OPENAI_MODEL", "gpt-4o-mini")

# --- инструмент: погода через Open-Meteo ---
@tool
def get_weather(city: str) -> str:
    """Return current weather for a given city using Open-Meteo (no API key)."""
    if not isinstance(city, str) or not city.strip():
        return "Please provide a city name."

    try:
        r = requests.get(
            "https://geocoding-api.open-meteo.com/v1/search",
            params={"name": city, "count": 1, "language": "en", "format": "json"},
            timeout=15,
        )
        r.raise_for_status()
        data = r.json()
    } except Exception as e:
        return f"Geocoding error: {e}"

    if not data.get("results"):
        return f"Could not find coordinates for '{city}'."

    lat = data["results"][0]["latitude"]
    lon = data["results"][0]["longitude"]

    try:
        r2 = requests.get(
            "https://api.open-meteo.com/v1/forecast",
            params={"latitude": lat, "longitude": lon, "current_weather": True, "timezone": "auto"},
            timeout=15,
        )
        r2.raise_for_status()
        wx = r2.json().get("current_weather", {})
    } except Exception as e:
        return f"Weather API error: {e}"

    temp = wx.get("temperature")
    wind = wx.get("windspeed")
    code = wx.get("weathercode")
    descr_map = {
        0: "clear sky", 1: "mainly clear", 2: "partly cloudy", 3: "overcast",
        45: "fog", 48: "rime fog", 51: "light drizzle", 61: "slight rain",
        71: "slight snow", 80: "rain showers", 95: "thunderstorm"
    }
    descr = descr_map.get(code, "weather data")
    return f"Current weather in {city} ({lat:.2f},{lon:.2f}): {descr}, {temp}°C, wind {wind} km/h."

# --- системный промпт ---
SYSTEM_PROMPT = """You are a helpful weather assistant.
- If the user asks about weather, call the tool get_weather(city).
- Follow: Think -> Act (tool) -> Read Observation -> Answer clearly.
- If the city is missing, ask a brief clarifying question to get the city name.
"""

# --- модель OpenAI через smolagents ---
def build_model() -> OpenAISpecific := OpenAIServerModel(
    model_id=MODEL_ID,
    temperature=0.2,
    max_tokens=400,
)

def build_agent() -> CodeAgent:
    return CodeAgent(
        model=build_model(),
        tools=[get_weather],
        system_prompt=SYSTEM_PROMPT,
        max_steps=3,
        planning_interval=2,
    )

if __name__ == "__main__":
    print("OpenAI Weather Agent. Type your question (or 'exit').")
    agent = build_agent()
    while True:
        user = input("You> ").strip()
        if not user or user.lower() in {"exit", "quit"}:
            break
        print(agent.run(user))

```

---

## 4. Подключаем агента к интерфейсу (фронту)

Теперь, когда у вас есть работающий агент, его нужно **подключить к простому интерфейсу**, чтобы пользователь мог задавать вопрос — например:

> “Какая погода в Берлине?”
> 

Для этого агенту нужен **фронт-энд (интерфейс)** и **сервер**, который будет принимать запросы от пользователя и пересылать их в вашего агента.

Если вы работаете в **Cursor**, просто напишите ему что-то вроде:

> “Помоги мне подключить моего погодного агента к веб-странице, чтобы пользователь мог вводить вопрос и получать ответ.”
> 

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

1. **Создаётся сервер** (на Python, например с FastAPI).
    
    Этот сервер получает текст вопроса (“Какая погода в Берлине?”), отправляет его вашему агенту и возвращает готовый ответ обратно на сайт.
    
2. **Создаётся простая веб-страница (фронт)**.
    
    На ней есть поле ввода и кнопка “Спросить”. Пользователь вводит вопрос, нажимает кнопку — и получает ответ от агента.
    
3. **Запускается локальный сервер (localhost)**.
    
    После запуска вы увидите ссылку, например `http://127.0.0.1:8000` — это ваш сайт, работающий на вашем компьютере.
    
    Пока он запущен, вы можете открывать страницу и общаться с агентом.
    
    Если компьютер выключен — сайт перестаёт быть доступен.
    

Такой вариант нужен **для теста и обучения**.

<aside>
📌

Позже вы сможете развернуть сайт в интернете (например, на Render, Hugging Face Spaces или Vercel), чтобы он был доступен всем пользователям. Этот процесс называется деплоем проекта и его необходимо разбирать отдельно.

</aside>

Теперь ваш фронтенд, телеграм-бот, сайт и т.д. просто POST-ят `{"message": "Погода в Берлине?"}` на `http://localhost:8000/chat`, а вы возвращаете ответ. 

> Итого: в «лёгком» варианте ничего на стороне OpenAI отдельно настраивать не нужно (кроме API-ключа). Вопросы приходят из вашего UI/бота/сервера в ваш же код, а он уже дергает OpenAI.
> 

---

## 2) «Ассистенты OpenAI» (OpenAI **Assistants API**)

Если хотите, чтобы часть логики (память переписки, функция-коллы, код-интерпретатор, retrieval) выполнялась **на стороне OpenAI**, тогда создаётся **Assistant** https://platform.openai.com/assistants/ и **Thread**. Тут уже действительно есть «настройка на стороне OpenAI» — вы создаёте ассистента с инструкцией, списком инструментов и т.п.

Базовый пример (без инструментов), чтобы показать, откуда берётся вопрос:

```bash
pip install openai

```

```python
from openai import OpenAI
client = OpenAI()  # использует OPENAI_API_KEY из окружения

# 1) создаём ассистента (делается 1 раз, можно запомнить id)
assistant = client.beta.assistants.create(
    name="Weather Assistant",
    instructions="You are a helpful weather assistant.",
    model="gpt-4o-mini",
)

# 2) создаём новый тред (диалог)
thread = client.beta.threads.create()

# 3) Добавляем в тред сообщение пользователя — ВОТ ОТКУДА «вопрос»
client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="What's the weather in Berlin?"
)

# 4) Запускаем रन
run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id,
)

# 5) Ждём завершения (вариант: опрос статуса)
import time
while True:
    run_check = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
    if run_check.status in ("completed","failed","cancelled","expired"):
        break
    time.sleep(0.7)

# 6) Читаем ответы ассистента
msgs = client.beta.threads.messages.list(thread_id=thread.id)
for m in reversed(msgs.data):
    if m.role == "assistant":
        print(m.content[0].text.value)
        break

```

- Здесь **вопрос тоже приходить не «сам», а от вас**: вы добавляете user-сообщение в `thread`.
- Если подключаете **инструменты** (например, `function`/tool calling для `get_weather`), то в `assistant = create(...)` добавляете `tools=[{"type": "function", "function": {...schema...}}]`, а потом, когда run попросит выполнить функцию, вы **обрабатываете шаги** (Run Steps), вызываете реальный API погоды и возвращаете `submit_tool_outputs`. Это уже полноценный «серверный» воркфлоу на стороне OpenAI.

### **Когда нужен Assistants API?**

– Вам хочется, чтобы OpenAI сам держал «тред» (память), сам orchestration, встроенный код-интерпретатор/ретривал/функции;

– Вы хотите стриминг run-событий и webhooks;

– Хотите меньше собственного «агентного» кода.

### **Когда хватит нашего «лёгкого» варианта?**

– Нужен быстрый старт, всё под вашим контролем;

– Уже есть свой UI/бот/сервер, сами руливаете памятью и инструментами;

– Берёте любой LLM (OpenAI/Hugging Face/Together) через `smolagents` и сами делаете цикл «получил текст → вызвал agent.run → отдал ответ».

[Все уроки](https://learnvibecoding.ru/publiclessons.md) · HTML: https://learnvibecoding.ru/publiclessons