Ви користуєтесь ChatGPT щодня. Вставляєте текст, отримуєте текст, відчуваєте себе продуктивним. Але на кожній техконференції 2026 року повторюють одне слово: агенти. Ваш PM каже 'нам потрібен агент'. Ваш CTO каже 'агенти — це майбутнє'. LinkedIn потопає в думках про агентів. А ви сидите і думаєте: 'Я навіть не знаю, що це означає'.
Ось у чому різниця. Чат-бот чекає, поки ви напишете, і пише у відповідь — як переписка з розумним другом. AI-агент — інша штука. У агента є мета, він сам обирає інструменти, обробляє помилки і працює, поки не завершить задачу або не вирішить, що це неможливо. Ніхто його за ручку не водить. Це різниця між 'запитати когось' і 'найняти когось робити роботу'.
Сьогодні ввечері ви цю різницю закриєте. Ви побудуєте справжнього агента — на Python, з нуля, без фреймворків — який шукає в інтернеті, аналізує інформацію, приймає рішення і зберігає дослідницький звіт на диск. До відбою ви зрозумієте точний патерн, на якому працюють Claude Code, Codex, Devin та кожен інший агентський продукт за $200/міс. Сам патерн — це приблизно 30 рядків.
Що ми будуємо
Дослідницький агент, який:
- Бере у вас тему
- Шукає релевантну інформацію в інтернеті
- Читає та аналізує знайдене
- Пише структуроване резюме дослідження
- Зберігає результат у файл
Це не іграшкове демо. Це та сама архітектура, що використовується в продакшн-агентах — tool use, reasoning loops, structured output. Єдина різниця між цим і 'продакшн-агентом' — обробка помилок та масштаб.
Крок 1: Налаштовуємо проєкт (10 хвилин)
mkdir research-agent && cd research-agent
python3 -m venv venv
source venv/bin/activate
pip install anthropic httpx
Дві залежності:
- anthropic — Python SDK (software development kit — готова бібліотека для спілкування з API Claude)
- httpx — для HTTP-запитів з Python
Вам також потрібен API-ключ Anthropic — по суті пароль, що дозволяє вашому коду спілкуватися з Claude. Отримайте на console.anthropic.com. Нові акаунти отримують $5 безкоштовних кредитів — цього вистачить, щоб запустити цього агента сотні разів.
export ANTHROPIC_API_KEY=sk-ant-...
touch agent.py
Крок 2: Визначаємо інструменти (15 хвилин)
Агент без інструментів — це просто чат-бот. Інструменти — це функції, що дозволяють агенту взаємодіяти з реальним світом: шукати в інтернеті, читати файли, викликати API (спосіб, яким програми кричать одна на одну через інтернет — щось типу SMS між машинами).
Ми дамо нашому агенту два інструменти:
# agent.py
import anthropic
import httpx
import json
import os
from datetime import datetime
client = anthropic.Anthropic()
MODEL = "claude-haiku-4.5"
# Визначення інструментів — вони кажуть Claude, що доступно
tools = [
{
"name": "web_search",
"description": "Search the web for information on a topic. Returns results with titles, URLs, and snippets.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query"
}
},
"required": ["query"]
}
},
{
"name": "save_file",
"description": "Save text content to a file on disk.",
"input_schema": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "Name of the file to save"
},
"content": {
"type": "string",
"description": "Content to write to the file"
}
},
"required": ["filename", "content"]
}
}
]
Ці визначення працюють як меню в ресторані. Claude читає описи і сам вирішує, коли який інструмент використати — ви не хардкодите порядок. Частина input_schema використовує JSON Schema — стандартний формат для опису структури даних, щоб Claude точно знав, які параметри очікує кожен інструмент. Так, ви описуєте формат даних за допомогою ще одного формату даних. Ласкаво просимо в програмування.
Крок 3: Реалізуємо інструменти (15 хвилин)
Визначення кажуть Claude, що існує. Тепер пишемо код, який реально виконується, коли Claude викликає інструмент. Це те місце, де гарні абстракції зустрічаються з брудною реальністю парсингу HTML, наче на дворі 2003-й:
def execute_tool(tool_name: str, tool_input: dict) -> str:
"""Execute a tool and return the result as a string."""
if tool_name == "web_search":
return do_web_search(tool_input["query"])
elif tool_name == "save_file":
return do_save_file(tool_input["filename"], tool_input["content"])
else:
return f"Error: Unknown tool '{tool_name}'"
def do_web_search(query: str) -> str:
"""Search using DuckDuckGo's HTML endpoint. No API key needed."""
try:
response = httpx.get(
"https://html.duckduckgo.com/html/",
params={"q": query},
headers={"User-Agent": "ResearchAgent/1.0"},
timeout=10.0,
)
response.raise_for_status()
text = response.text
results = []
parts = text.split('class="result__snippet"')
for part in parts[1:6]: # Grab up to 5 results
snippet_end = part.find("</a>")
if snippet_end > 0:
snippet = part[:snippet_end]
clean = snippet.replace("<b>", "").replace("</b>", "")
clean = clean.split(">")[-1] if ">" in clean else clean
if clean.strip():
results.append(clean.strip())
if results:
return "Search results:\n" + "\n".join(
f"- {r}" for r in results
)
return f"Search completed but no clear results for: {query}"
except Exception as e:
return f"Search error: {str(e)}"
def do_save_file(filename: str, content: str) -> str:
"""Save content to the output directory."""
os.makedirs("output", exist_ok=True)
filepath = os.path.join("output", filename)
try:
with open(filepath, "w") as f:
f.write(content)
return f"File saved successfully: {filepath}"
except Exception as e:
return f"Error saving file: {str(e)}"
Веб-пошук використовує HTML-ендпоінт DuckDuckGo — без API-ключа, без реєстрації, без грошей. HTML-парсинг тримається на скотчі й оптимізмі (ми скрейпимо сиру розмітку сторінки замість нормального фіду даних), але воно працює. Для продакшну ви б замінили це на Brave Search API (2 000 безкоштовних запитів/місяць) або self-hosted SearXNG.
Крок 4: Будуємо цикл агента (20 хвилин)
Це серце всієї конструкції. Кожен агентський продукт з красивим лендінгом і оцінкою в $50M працює на якійсь версії цих 30 рядків:
def run_agent(topic: str, max_turns: int = 10) -> str:
"""Run the research agent on a topic."""
print(f"\n{'='*60}")
print(f"Research Agent — Topic: {topic}")
print(f"{'='*60}\n")
system_prompt = """You are a research agent. Your job is to research a topic
thoroughly and produce a well-structured summary.
Your process:
1. Search for information on the topic (multiple searches with different angles)
2. Analyze what you find
3. Write a comprehensive research summary
4. Save the summary to a file
Be thorough — do at least 3 different searches to cover the topic well.
Be critical — evaluate sources and note conflicting information.
When done, save the final summary as a markdown file.
Current date: """ + datetime.now().strftime("%Y-%m-%d")
messages = [
{
"role": "user",
"content": f"Research this topic and produce a detailed summary: {topic}"
}
]
# Цикл агента
for turn in range(max_turns):
print(f"--- Turn {turn + 1} ---")
response = client.messages.create(
model=MODEL,
max_tokens=4096,
system=system_prompt,
tools=tools,
messages=messages,
)
print(f"Stop reason: {response.stop_reason}")
if response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
tool_name = block.name
tool_input = block.input
tool_id = block.id
print(f" Tool: {tool_name}")
print(f" Input: {json.dumps(tool_input, indent=2)[:200]}")
result = execute_tool(tool_name, tool_input)
print(f" Result: {result[:200]}...")
tool_results.append({
"type": "tool_result",
"tool_use_id": tool_id,
"content": result,
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
elif response.stop_reason == "end_turn":
final_text = ""
for block in response.content:
if hasattr(block, "text"):
final_text += block.text
print(f"\nAgent completed in {turn + 1} turns.")
return final_text
return "Agent did not complete within turn limit."
Розберемо цей цикл, бо це і є весь фокус:
- Відправляємо задачу Claude разом з визначеннями інструментів
- Claude думає і вирішує — або використати інструмент, або відповісти фінальним текстом
- Якщо tool_use — виконуємо інструмент і відправляємо результат назад як нове повідомлення
- Claude бачить результат і вирішує наступний крок
- Повторюємо, поки Claude не скаже
end_turn— тобто він закінчив
Ключовий інсайт: ви не хардкодили 'спочатку пошук, потім аналіз, потім написання'. Claude сам визначає послідовність дій на основі задачі. Це те, що відрізняє агента від скрипта. Скрипт виконує ваші інструкції. Агент виконує свої.
Поле stop_reason — ключове. API Claude повертає або "tool_use" (хочу викликати інструмент), або "end_turn" (я закінчив). Ваш цикл просто перевіряє, що саме, і діє відповідно.
Крок 5: Додаємо точку входу (5 хвилин)
Нудна частина. Але навіть нудні частини мають існувати, інакше нічого не запуститься — урок, який половина AI-демо на GitHub досі не засвоїла:
if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
topic = " ".join(sys.argv[1:])
else:
topic = input("Enter research topic: ")
result = run_agent(topic)
print(f"\n{'='*60}")
print("Research complete. Check the output/ directory.")
print(f"{'='*60}")
Крок 6: Запускаємо (5 хвилин)
python agent.py "current state of MCP protocol adoption in 2026"
Спостерігайте за терміналом. Ви побачите, як агент сам продумує задачу:
============================================================
Research Agent — Topic: current state of MCP protocol adoption in 2026
============================================================
--- Turn 1 ---
Stop reason: tool_use
Tool: web_search
Input: {"query": "MCP model context protocol adoption 2026"}
Result: Search results: - The MCP ecosystem has grown...
--- Turn 2 ---
Stop reason: tool_use
Tool: web_search
Input: {"query": "MCP servers enterprise production 2026"}
Result: Search results: - Amazon Bedrock AgentCore...
--- Turn 3 ---
Stop reason: tool_use
Tool: web_search
Input: {"query": "MCP protocol limitations challenges 2026"}
Result: Search results: - Stateful sessions fight with...
--- Turn 4 ---
Stop reason: tool_use
Tool: save_file
Input: {"filename": "mcp-research-2026.md", "content": "# MCP Protocol..."}
Result: File saved successfully: output/mcp-research-2026.md
--- Turn 5 ---
Stop reason: end_turn
Agent completed in 5 turns.
П'ять ітерацій. Три пошуки, одне збереження файлу, одне фінальне резюме. Ніхто не казав йому шукати з різних ракурсів — він вирішив це сам. Ось це — агентність, а не скриптинг.
Крок 7: Робимо розумнішим (30 хвилин)
Базовий агент працює. Тепер додамо три покращення, які перетворять його з демо на щось, чим ви реально будете користуватись.
Пам'ять між сесіями
Зараз кожен запуск починається з нуля. Дамо агенту просту пам'ять — JSON-файл (структурований текстовий формат, який програми легко читають і пишуть), що зберігає попередні дослідження:
from pathlib import Path
MEMORY_FILE = "memory.json"
def load_memory() -> list:
"""Load previous research topics and findings."""
if Path(MEMORY_FILE).exists():
with open(MEMORY_FILE) as f:
return json.load(f)
return []
def save_memory(topic: str, summary: str):
"""Save this research session to memory."""
memory = load_memory()
memory.append({
"date": datetime.now().isoformat(),
"topic": topic,
"summary": summary[:500],
})
memory = memory[-20:] # Зберігаємо останні 20 записів
with open(MEMORY_FILE, "w") as f:
json.dump(memory, f, indent=2)
Вбудовуємо пам'ять у system prompt — інструкційний текст, що формує поведінку Claude:
memory = load_memory()
if memory:
memory_context = "\n\nPrevious research sessions:\n"
for m in memory[-5:]:
memory_context += f"- [{m['date'][:10]}] {m['topic']}: {m['summary'][:100]}...\n"
system_prompt += memory_context
Тепер агент знає, що досліджував раніше. Може посилатись на попередні знахідки, уникати повторних пошуків і будувати на минулій роботі.
Інструмент для роздумів
Цей прийом — ніщо. Буквально. Додаємо інструмент, який не робить нічого:
tools.append({
"name": "think",
"description": "Use this tool to think through your approach before acting. Write out your reasoning and what you need to find out next.",
"input_schema": {
"type": "object",
"properties": {
"thought": {
"type": "string",
"description": "Your reasoning and plan"
}
},
"required": ["thought"]
}
})
У виконавці інструментів він просто повертає підтвердження:
elif tool_name == "think":
print(f" Thinking: {tool_input['thought'][:300]}")
return "Thought recorded. Continue with your plan."
Навіщо додавати інструмент, який нічого не робить? Бо він дає агенту структуроване місце для міркувань перед дією. Без нього Claude відразу стрибає до викликів інструментів. З ним — Claude зупиняється, планує, а потім виконує — з помітно кращими результатами. Anthropic документує цю техніку у своєму гайді по tool use, і продакшн-агенти на неї спираються.
Відновлення після помилок
def execute_tool_safe(tool_name: str, tool_input: dict) -> str:
"""Execute a tool with automatic retries."""
for attempt in range(3):
try:
result = execute_tool(tool_name, tool_input)
if "error" in result.lower() and attempt < 2:
print(f" Retry {attempt + 1}...")
continue
return result
except Exception as e:
if attempt < 2:
print(f" Error, retrying: {e}")
continue
return f"Tool failed after 3 attempts: {str(e)}"
Веб-запити падають. API лягають. Таймаути трапляються. Продакшн-агент повторює спробу перед тим, як здатись. Три спроби з фолбеком — це базовий мінімум.
Фінальна структура
research-agent/
├── agent.py # ~150 рядків Python
├── memory.json # Створюється автоматично, зберігає історію сесій
├── output/ # Створюється автоматично, зберігає звіти
│ └── *.md
└── requirements.txt # anthropic, httpx
Менше 200 рядків. Дві залежності. Жодного фреймворка.
Чому без фреймворка?
Можливо, ви думаєте: 'Чому не використати LangChain чи LlamaIndex?' (Обидва — популярні Python-фреймворки, що додають готові абстракції навколо LLM-викликів.)
Бо агентський цикл вище — це 30 рядків. LangChain додав би 15 залежностей і три шари абстракцій для того ж результату.
Використовуйте фреймворк, коли:
- Вам потрібно 10+ інструментів зі складною логікою роутингу
- Вам потрібна conversational memory, що масштабується на тисячі користувачів
- Вам потрібно кілька агентів, що координуються на одній задачі
- Ви переросли простий Python і потребуєте чужу архітектуру
Не використовуйте фреймворк, коли:
- Ви будуєте свого першого агента
- У вашого агента 2–5 інструментів
- Ви хочете розуміти кожен рядок того, що виконується
- 'Працює і я розумію' перемагає 'працює і я довіряю абстракції'
Станом на березень 2026, документація Anthropic SDK показує той самий мінімалістичний патерн циклу, який ми щойно побудували. Офіційна рекомендація — починати без фреймворка.
Що ви побудували за вечір
Підіб'ємо підсумки:
- Працюючий AI-агент — бере мету, досягає її автономно
- Tool use — агент викликає зовнішні системи (веб-пошук, файловий I/O)
- Reasoning loop — Claude вирішує наступну дію на основі результатів, а не захардкодженого скрипта
- Пам'ять — агент пам'ятає минулі сесії і будує на них
- Обробка помилок — повторює спроби перед тим, як здатись
- Збереження результатів — результати потрапляють у реальні файли на вашому диску
Це та сама базова архітектура, що й у Claude Code, Devin, OpenAI Codex та кожного іншого агентського продукту. У них кращі інструменти, більше обробки помилок і більші context windows — обсяг тексту, який модель може 'бачити' одночасно, щось на кшталт робочої пам'яті. Але цикл ідентичний тому, що ви щойно написали.
Куди далі
Тепер ви розумієте фундаментальний патерн. Все інше — це інженерія поверх нього:
- Більше інструментів — калькулятор, веб-скрейпер, конектор до бази даних, виконавець коду
- Краща пам'ять — vector databases (системи, що зберігають текст за значенням, а не лише за ключовими словами) для семантичного пошуку по минулих сесіях
- Паралельні виклики інструментів — запускати кілька пошуків одночасно замість послідовно
- Мультиагентні системи — другий агент, що перевіряє роботу першого, як code review
- MCP-інтеграція — Model Context Protocol, стандарт для підключення AI-агентів до зовнішніх інструментів, як USB, але для джерел даних
Ви вчите не чийсь фреймворк, який може здохнути через півроку. Ви вчите патерн. Той самий патерн, що працював у 2024, працює у 2026 і буде працювати у 2028 — бо базова механіка (модель вирішує → інструмент виконує → результат повертається) — це те, як функціонують усі агентські системи, незалежно від маркетингової назви.
'AI-агентська' індустрія хоче, щоб ви вірили: побудувати агента вимагає PhD і $100M Series B. Насправді потрібно розуміння одного циклу: викликаємо модель, перевіряємо, чи вона хоче інструмент, виконуємо інструмент, відправляємо результат назад, повторюємо. Ось і все. Все інше — це інженерія навколо цього циклу — і тепер у вас достатньо знань, щоб робити цю інженерію самостійно.





