Опубліковано 9 червня 2026 р.
Як створити свого першого AI-агента у 2026: повний гайд для початківців
Збери робочого AI-агента на чистому Python — без фреймворків і магії. Виклик LLM, інструменти, памʼять і цикл агента ти напишеш сам.
AI-агент — це цикл: ти надсилаєш повідомлення у велику мовну модель (LLM), вона або відповідає, або просить викликати інструмент, ти виконуєш інструмент і повертаєш результат — і так по колу, доки задача не розвʼязана. Ось і вся ідея, жодного фреймворка не треба. Скелет у три рядки:
while response.stop_reason == "tool_use": # модель хоче інструмент
result = run_tool(block.name, block.input) # ти його виконуєш
messages.append(tool_result(result)) # повертаєш результат, цикл повторюєтьсяНаприкінці гайда в тебе буде справжній агент на чистому Python: він скаже час, точно порахує математику й утримає діалог — зібраний із чотирьох примітивів, які ти зрозумієш рядок за рядком: виклик LLM, інструменти, памʼять і керуючий цикл. Візьмемо Anthropic Python SDK і дешеву модель, тож ціла розмова коштуватиме частку цента. А потім покажу, на який production-SDK переходити, коли концепція вкладеться в голові.
Навіщо будувати без фреймворка
У 2026 найгучніше радять «просто візьми фреймворк». Але розробники раз за разом обпікаються об магію — цього місяця завірусився тред про фрилансера, якому заплатили, щоб він прибрав AI з інструмента, бо в команді ніхто не розумів, що той робить. Фреймворк ховає цикл, а цикл, який ти не розумієш, неможливо налагодити о третій ночі.
Тому цикл зберемо самі. Це приблизно 60 рядків. Щойно ти їх напишеш, будь-який агентний фреймворк — Claude Agent SDK, OpenAI Agents SDK, Google ADK — перестає бути магією і стає «а, це ж те, що я вже зробив, лише з приємнішими типами». Це найшвидший спосіб реально зрозуміти агентів.
Крок 1: виклик LLM
Постав SDK і задай ключ:
pip install anthropic
export ANTHROPIC_API_KEY=sk-ant-... # ключ береться на console.anthropic.comМінімальний виклик — текст на вході, текст на виході:
from anthropic import Anthropic
client = Anthropic() # читає ANTHROPIC_API_KEY з оточення
response = client.messages.create(
model="claude-haiku-4-5", # дешево і швидко; пізніше зміниш на sonnet/opus
max_tokens=1024,
messages=[{"role": "user", "content": "Одним реченням: що таке AI-агент?"}],
)
print(response.content[0].text)Це чат-бот, а не агент. Різниця в тому, що агент вміє діяти — а для цього йому потрібні інструменти.
Крок 2: дай йому інструмент
LLM не вміє дивитися на годинник і надійно перемножувати великі числа — вона передбачає текст, а не обчислює. Тому ми видаємо їй інструменти: звичайні функції Python плюс опис у форматі JSON Schema, щоб модель знала, коли їх кликати.
TOOLS = [
{
"name": "get_current_time",
"description": "Return the current date and time. Call when the user asks the time or date.",
"input_schema": {"type": "object", "properties": {}},
},
]
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
tools=TOOLS,
messages=[{"role": "user", "content": "Котра зараз година?"}],
)
print(response.stop_reason) # -> "tool_use"Модель сама нічого не виконує. Вона зупиняється зі stop_reason == "tool_use" і блоком tool_use, який каже: «будь ласка, виклич get_current_time». Виконати — твоя задача. Це межа безпеки, і це плюс: ти вирішуєш, що реально запуститься.
from datetime import datetime
def get_current_time() -> str:
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")Далі ти повертаєш результат блоком tool_result з тим самим tool_use_id, і модель перетворює його на звичайне речення. Роби так у циклі — і отримаєш агента.
Крок 3: цикл агента (повністю)
Ось повний агент. Два інструменти, цикл, що їх виконує, і чат-REPL. Список messages — це і є памʼять: кожен хід у нього дописується, тому модель памʼятає розмову.
# agent.py — крихітний AI-агент на чистому Python. Без фреймворків.
# Setup: pip install anthropic && export ANTHROPIC_API_KEY=sk-ant-...
import ast
import operator
from datetime import datetime
from anthropic import Anthropic
client = Anthropic()
MODEL = "claude-haiku-4-5" # дешево; зміни на "claude-sonnet-4-6" або "claude-opus-4-8"
# --- 1. Інструменти: звичайні функції Python --------------------------------
def get_current_time() -> str:
"""The model has no clock — this gives it one."""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
_OPS = {
ast.Add: operator.add, ast.Sub: operator.sub,
ast.Mult: operator.mul, ast.Div: operator.truediv,
ast.Pow: operator.pow, ast.USub: operator.neg,
}
def _eval(node):
# A tiny, safe arithmetic evaluator — never eval() untrusted input.
if isinstance(node, ast.Constant):
return node.value
if isinstance(node, ast.BinOp):
return _OPS[type(node.op)](_eval(node.left), _eval(node.right))
if isinstance(node, ast.UnaryOp):
return _OPS[type(node.op)](_eval(node.operand))
raise ValueError("unsupported expression")
def calculate(expression: str) -> str:
"""Deterministic math — don't trust an LLM to multiply big numbers."""
return str(_eval(ast.parse(expression, mode="eval").body))
# --- 2. Описуємо інструменти для моделі (JSON Schema) ----------------------
TOOLS = [
{
"name": "get_current_time",
"description": "Return the current date and time. Call when the user asks the time or date.",
"input_schema": {"type": "object", "properties": {}},
},
{
"name": "calculate",
"description": "Evaluate a basic arithmetic expression like '23 * 47 + 10'. Call for any math.",
"input_schema": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "e.g. '2 ** 10 / 4'"},
},
"required": ["expression"],
},
},
]
def run_tool(name: str, tool_input: dict) -> str:
if name == "get_current_time":
return get_current_time()
if name == "calculate":
return calculate(tool_input["expression"])
return f"Unknown tool: {name}"
# --- 3. Цикл агента --------------------------------------------------------
def agent_turn(messages: list) -> str:
"""Run one user turn to completion, executing tools until the model is done."""
for _ in range(10): # жорсткий ліміт, щоб модель не зациклилася назавжди
response = client.messages.create(
model=MODEL,
max_tokens=1024,
tools=TOOLS,
messages=messages,
)
# Keep the assistant turn (incl. any tool_use blocks) in memory.
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
return "".join(b.text for b in response.content if b.type == "text")
# The model asked for tools. Run them, feed the results back, loop.
results = []
for block in response.content:
if block.type == "tool_use":
output = run_tool(block.name, block.input)
results.append({
"type": "tool_result",
"tool_use_id": block.id, # must match the tool_use block
"content": output,
})
messages.append({"role": "user", "content": results})
return "Stopped: too many tool calls."
# --- 4. Чат-цикл — розмова і Є памʼяттю -------------------------------------
if __name__ == "__main__":
messages = [] # уся розмова живе тут
print("Agent ready. Ctrl-C to quit.\n")
while True:
messages.append({"role": "user", "content": input("you> ")})
print(f"agent> {agent_turn(messages)}\n")Запусти python agent.py і спитай: «скільки буде 4871 помножити на 209 і котра зараз година?» — модель викличе обидва інструменти, отримає точні відповіді й відповість одним реченням. Ти щойно зібрав агента.
Памʼять між запусками
Зараз памʼять помирає, коли ти закриваєш скрипт. Щоб вона зберігалася, пиши messages у файл при виході й читай при старті — блоки content серіалізуються в JSON:
import json, pathlib
STORE = pathlib.Path("memory.json")
messages = json.loads(STORE.read_text()) if STORE.exists() else []
# ... після чат-циклу або при виході:
STORE.write_text(json.dumps(messages, default=lambda o: o.model_dump()))Це четвертий примітив. У реальних агентах плоский файл міняють на базу даних або векторне сховище, але ідея та сама: стан, який ти переносиш між викликами.
Стрімінг, щоб було приємніше
Для чат-інтерфейсів зазвичай хочеться, щоб токени зʼявлялися в міру генерації. Той самий виклик, але потоком:
with client.messages.stream(
model=MODEL,
max_tokens=1024,
messages=[{"role": "user", "content": "Поясни AI-агентів пʼятирічній дитині."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()На що переходити далі
Тепер ти розумієш кожну деталь. Production-SDK просто пакує ці примітиви в типи, ретраї і вбудований tool-runner, щоб цикл не писати руками:
| Що написав ти | Що дає SDK |
|---|---|
виклик messages.create | той самий виклик, повністю типізований |
цикл tool_use | автоматичний tool-runner |
список messages | хелпери для сесій і стану |
диспетчер run_tool | інструменти із сигнатур функцій |
Коли будеш готовий, природні наступні кроки — Claude Agent SDK, OpenAI Agents SDK або Google ADK. Берись за них, коли потрібна production-обвʼязка, не раніше. Для навчання ці 60 рядків сильніші за будь-який фреймворк.
Часті помилки (і як лагодити)
- Помилка: надіслати
tool_result, не дописавши спершу хід асистента зtool_use. Фікс: завжди додавайresponse.contentуmessagesдо результатів — API має бачити виклик, на який відповідає результат, інакше поверне 400. - Помилка:
tool_result, у якогоtool_use_idне збігається з блокомtool_use. Фікс: копіюйblock.idу результат дослівно. - Помилка: довіряти моделі обчислення чи знання поточного часу. Фікс: саме для цього й потрібні інструменти — детерміновану роботу тримай у коді.
- Помилка: проганяти ввід від моделі через
eval(). Фікс: валідуй та ізолюй кожен інструмент, ніколи не виконуй сирі вирази (див. безпечнийast-обчислювач вище). - Помилка: цикл без обмежувача. Фікс: стеля
range(10)не дасть агенту молотити рахунок нескінченно.
Що далі
Додай інструмент, який робить щось корисне особисто тобі — читає файл, смикає API, ходить у базу — і в тебе справжній асистент. Патерн не змінюється: опиши інструмент, виконай його, поверни результат. Коли плоского файлу під памʼять стане мало — це й є сигнал тягнутися за фреймворком.
Джерела
-
Anthropic Python SDK — виклик
messages.create, стрімінг і блоки tool-use, які ми використовуємо в усьому гайді. https://github.com/anthropics/anthropic-sdk-python -
Claude Tool Use (overview) — схема
tool_use/tool_result, обробкаstop_reasonі агентний цикл. https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview Дата звернення: 9 червня 2026. -
Claude Models Overview — актуальні ID моделей (
claude-haiku-4-5,claude-sonnet-4-6,claude-opus-4-8) і розміри контексту. https://platform.claude.com/docs/en/about-claude/models/overview Дата звернення: 9 червня 2026. -
Claude Pricing — Haiku 4.5 приблизно $1/$5 за 1M вхідних/вихідних токенів (звідси оцінка вартості; ціни в USD і змінюються — звіряйся з живою сторінкою). https://platform.claude.com/docs/en/pricing Дата звернення: 9 червня 2026.
Потрібен AI-агент під твій продукт? Почати проєкт — я будую AI-агентів, MCP-сервери та системи агентних платежів, що працюють на твоєму сервері.