Docker та Docker Compose: як інфраструктура адаптується в еру АІ-агентів

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Всім привіт! Мене звати Андрій Орлов, я працюю в стартапі і очевидно, як і ви, хочу йти в ногу з розвитком технологічного світу. Нещодавно я відвідав конференцію World Congress від WeAreDevelopers, і серед великої кількості тем про штучний інтелект одна особливо привернула мою увагу. Це була презентація від компанії Docker. Хочу поділитись із вами тим, що відкрив для себе.

Що, якби ви могли оркеструвати AI‑агенти як мікросервіси?

У цій статті я хочу підкреслити нові речі, які були випущені за останні місяці та дні. Звичайно, я наведу кілька демо‑прикладів із трьома рівнями складності агентів. Наприкінці статті ви знайдете всі офіційні дописи у блогах, які я рекомендую для читання, а також посилання на мій репозиторій GitHub.

Якщо ви інженер, який хоче випробувати локальні LLM, додати трохи магії MCP і мати все загорнуте в логіку Docker Compose — ласкаво просимо. Я знав про всі ці технології окремо, але лише нещодавно вперше написав агентний код.

Для найкращого досвіду та можливості запускати код локально я б рекомендував кілька оновлень. Звичайно, для кожного це може бути по‑різному, але ось моя поточна конфігурація, у якій все працює плавно:

  • MacOS Sonoma 14.7.2
  • Docker Desktop 4.43.2
  • Compose v2.38.2‑desktop.1 (автоматично оновлено разом з оновленням Docker Desktop)

Нові можливості

Ось скріншот із кількома речами, які я хочу охопити у цій статті. Спочатку я коротко опишу, що це таке, а згодом покажу, як використовувати їх у коді на реальних прикладах.

Припустімо, я щойно зрозумів, що є можливість запускати локально LLM з відкритими вагами. І в мене нічого не встановлено, я просто хочу спробувати щось або зробити невеличке демо для своєї команди. Ймовірність того, що на вашій машині встановлений Docker, доволі висока, і гарна новина в тому, що це, по суті, все, що вам потрібно в цій ситуації.

За допомогою простої команди docker model run ai/llama3.2 ви можете запустити LLM локально.

Звичайно, ви можете змінити модель, оскільки в Docker Desktop з’явилася нова вкладка «Models», де ви знайдете каталог усіх доступних LLM.

Ще одна хороша новина — ви не обмежені цим списком; наприклад, Hugging Face тепер також підтримує запуск своїх моделей через Docker. Ось список LLM, які я випробував, і деякі їхні параметри.

Ще одне велике оновлення — MCP (Model Context Protocol). Можливо, ви захочете дозволити своєму агенту підключатися до сторонніх сервісів, використовуючи їхні MCP. Як це зробити? Як підключити це до вашої поточної інфраструктури? MCP Gateway дозволить вам це зробити.

Приклад коду в Docker Compose:

Виберіть службу (із каталогу Docker), задайте порт і оберіть метод комунікації (це може бути streaming, SSE тощо). Більше прикладів є тут: github.com/...​ateway/tree/main/examples. Крім того, MCP можна запускати як окремий сервіс Docker без Compose. Очевидно, підтримка файлів .env, env vars, secrets, volumes також присутня.

Порада: перегляньте каталог Docker MCP, встановіть щось і спробуйте зв’язатися з якимись сервісами, використовуючи заздалегідь визначені інструменти.

Бонус: ви можете підключити MCP toolkit до своєї IDE (наприклад, це дуже просто зробити у Cursor), що забезпечить ще більшу гнучкість і допоможе протестувати більшість інструментів.

І нарешті — offload. Якщо коротко: ви хочете запустити величезну LLM, але ваш ноутбук плаче, свистить і матюкається, і зрештою показує «Run out of memory». Щоб цього уникнути, тепер ви можете запускати всі свої images та models у хмарі Docker. На сьогодні офіційна документація каже: «Отримайте 300 безкоштовних GPU‑хвилин, щоб розпочати! Після завершення кредитів використання тарифікується за $0,015 за GPU‑хвилину. Ціни можуть змінитися після бета‑версії». Посилання для доступу до бета‑версії буде в розділі посилань наприкінці.

Щоб почати використовувати offload, введіть docker offload start або перемкніть тумблер у Docker Desktop (підказка: фон стане рожевим).

Час для демо

Агент рівня 1

Історія: моя дівчина живе в Нью‑Йорку, і я хочу створити агента, який буде казати мені час там. Мене не цікавлять інші міста.

Бібліотеки:

  • google‑adk == 1.7.0
  • litellm == 1.74.7

Все досить просто. Мені подобається Google ADK за його вбудований чат‑інтерфейс та всі можливості дебагінгу. Ви можете обрати будь‑яку іншу бібліотеку, але тоді вам потрібно буде адаптувати код. LiteLLM — це корисна обгортка для запуску локальної LLM. Потрібно зробити один трюк: у LiteLLM під капотом різні мапери, тому наша модель повинна бути однією з наперед визначених. Я бачив, як це роблять у офіційних прикладах Docker, тому роблю те саме у своєму Dockerfile.

export OPENAI_BASE_URL=${MODEL_RUNNER_URL}
export OPENAI_MODEL_NAME=openai/${MODEL_RUNNER_MODEL}
export OPENAI_API_KEY=cannot_be_empty

OPENAI_MODEL_NAME отримує префікс «openai». А OPENAI_API_KEY просто присвоюється випадкове значення, оскільки LiteLLM буде скаржитися без нього. Насправді жодних викликів до OpenAI не робиться.

Тепер цікава частина. Файл agent.py (і так, назва файлу дуже важлива для google‑adk) досить простий, оскільки це рівень 1:

def get_current_time(city: str) -> dict:
    """Returns the current time in a specified city.
    Args:
        city (str): The name of the city for which to retrieve the current time.
    Returns:
        dict: status and result or error msg.
    """
    if city.lower() == "new york":
        tz_identifier = "America/New_York"
    else:
        return {
            "status": "error",
            "error_message": (
                f"Sorry, I don't have timezone information for {city}."
            ),
        }
    tz = ZoneInfo(tz_identifier)
    now = datetime.datetime.now(tz)
    report = (
        f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}'
    )
    return {"status": "success", "report": report}

root_agent = Agent(
    name="time_agent",
    model=LiteLlm(
        model=f"{os.environ.get('OPENAI_MODEL_NAME')}"
    ),
    description=(
        "Agent to answer questions about the time in a city."
    ),
    instruction=(
        "You are a helpful agent who can answer user questions about the time in a city."
    ),
    tools=[get_current_time],
)

У цьому прикладі ми розглядаємо get_current_time як заглушку для виклику до стороннього сервісу. Це може бути HTTP‑запит або MCP (про це йтиметься далі). Важливо, що це наш інструмент, який може використовувати наш агент. root_agent = Agent() приймає запити з UI-чату. Зверніть увагу на частину LiteLLM, де ми визначаємо, що будемо обробляти всю комунікацію через нашу модель, що працює у Docker. Файл Docker Compose також дуже простий; посилання на GitHub буде в кінці.

Результат:

Агент рівня 2

Історія: те саме, що й у агента рівня 1.

Бібліотеки: ті самі, що й для агента рівня 1.

Цього разу ми хочемо реальний MCP замість фіктивної функції. Я переглянув каталог Docker MCP і знайшов те, що може підійти для моїх потреб.

Підключити це дуже просто за допомогою Docker Compose. У моєму випадку це виглядає так:

mcp-gateway:
    image: docker/mcp-gateway:latest
    use_api_socket: true
    command:
      - --transport=sse
      - --servers=time

Параметр --servers=time фактично те, що виконує усю роботу. За потреби можна перерахувати кілька серверів. В офіційній документації є багато корисних прикладів.

Наш agent.py тепер ще простіший:

tools = create_mcp_toolsets(tools_cfg=["mcp/time:get_current_time"])
root_agent = Agent(
    name="time_agent",
    model=LiteLlm(
        model=f"{os.environ.get('OPENAI_MODEL_NAME')}"
    ),
    description=(
        "Agent to answer questions about the time in a city."
    ),
    instruction=(
        "You are a helpful agent who can answer user questions about the time in a city. "
        "You are using MCP Gateway to get the current time in a city. You are always using the same MCP tool."
    ),
    tools=tools,
)

Ми використовуємо власну функцію, щоб отримати список доступних інструментів, які може викликати наша LLM для виконання запиту. Навіть якщо MCP має багато інструментів, краще обмежити модель одним конкретним (у нашому випадку mcp/time:get_current_time), щоб уникнути помилок. Інший варіант — обмежити вибір у файлі Docker Compose.

Результат:

Агент рівня 3

Історія: моя дівчина щодня подорожує, і я хочу створити агента, який повідомлятиме мені час у її місті. Додатково я хочу підключити другого агента, який прийматиме цей час і казатиме, чи підходить він для онлайн‑побачення. Наше побачення можливе лише тоді, коли її місцевий час знаходиться в діапазоні від 18:00 до 22:00.

Бібліотеки: ті самі, що й для агента рівня 1.

Тепер структура проєкту така:

is-it-time-agents/
├── subagents/
│   ├── dating/
│   │   ├── __init__.py
│   │   └── agent.py
│   └── timing/
│       ├── __init__.py
│       ├── agent.py
│       └── tools.py
├── __init__.py
└── agent.py

Для агента «timing» ми побачимо майже той самий код, що й для агента рівня 2. Ми все ще використовуємо time MCP, який повертає поточний час у запитуваному місті:

tools = create_mcp_toolsets(tools_cfg=["mcp/time:get_current_time"])
time_agent = Agent(
    name="time_agent",
    model=LiteLlm(
        model=f"{os.environ.get('OPENAI_MODEL_NAME')}"
    ),
    description=(
        "Agent to answer questions about the time in a city."
    ),
    instruction=(
        "You are a helpful agent who can answer user questions about the time in a city. Please IGNORE the user's question and just return the time in the city. Here is the question that contains the city:"
    ),
    tools=tools
)

Підагент «dating» схожий на те, що ми робили для агента рівня 1. Він приймає запит, дозволяє локальній LLM обробити його і повертає відповідь; різниця в тому, що наша підказка буде розширена відповіддю часу з MCP:

dating_agent = Agent(
    name="dating_agent",
    model=LiteLlm(
        model=f"{os.environ.get('OPENAI_MODEL_NAME')}"
    ),
    description=(
        "Agent to answer is it ok to go on a date on a given time in a given city. "
    ),
    instruction=(
        "You are a helpful agent who can decide if it is ok to go on a date on a given time in a given city. Let's assume that the best time to go on a date is between 18:00 and 22:00."
    ),
    before_model_callback=_force_string_content,
    after_model_callback=_remove_end_of_edit_mark,
)

І нарешті — наш root‑агент. Змінна root_agent — це те, що шукає Google ADK у наданій директорії. У нас це виглядає так:

from google.adk.agents import SequentialAgent
from .subagents.dating import dating_agent
from .subagents.timing import time_agent
root_agent = SequentialAgent(
    name="is_it_time_agent",
    description=(
        "Agent to answer questions about the time and is it ok to go on an online date with my girlfriend."
    ),
    sub_agents=[time_agent, dating_agent]
)

Це всього кілька рядків коду, але цікаво, як SequentialAgent та sub_agents працюють у вигляді ланцюжка: дані й відповідь від підагента № 1 передаються підагентові № 2 і далі. Саме те, що нам потрібно.

Моя конфігурація Docker має обмеження (як RAM, так і сховище). Якщо я хочу запустити потужнішу AI‑модель або мій ноутбук недостатньо сильний, можна виконати docker offload start, щоб переключитися у хмарний режим. Усі ваші образи й контейнери запустяться віддалено. Ви також можете зробити це через інтерфейс. Я додав compose.offload.yaml, щоб спробувати більш потужну модель.

Результат:

Підсумок

Уся суть цієї статті — показати, як легко «помацати» нові концепції MCP та локальних LLM без встановлення чи переходу на новий набір інструментів. Звісно, бути AI‑інженером чи використовувати ці технології на більш просунутому рівні вимагало б більше роботи. Але якщо є можливість погратися з усім цим і просто зрозуміти концепцію — то чому б і ні?

Так, Docker MCP gateway та ці AI‑функції ще в бета‑версії, і я легко знайшов кілька дрібних багів та невідповідностей у документації. Я не закликаю запускати це у продакшн, а лише хочу показати, що ШІ вже тут. Я витратив більше часу, спілкуючись зі своїм кодом, ніж читаючи чи пишучи його. І вперше в житті для демо я не використовував import requests. Респект команді Docker — мені сподобався процес.

Корисні посилання

Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

👍ПодобаєтьсяСподобалось12
До обраногоВ обраному11
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Гарна стаття, з розширеним описом та версійностями.

Дуже дякую за відгук!

Історія: моя дівчина живе в Нью‑Йорку, і я хочу створити агента, який буде казати мені час там.

Блдь, як я сміявсь.

What a brilliant display of unprovoked imbecility.

І, головне, дуже, дуже ілюстративний.

те саме, згадалося що влюбльонниє часов нє наблюдают ))

Mark Cavage статтю оцінив і репостнув собі, а Юрій Глушко домахався до прикладів :)
По-перше, дякую за увагу до статті
По-друге, я глянув ваш профіль : 197 коментарів, 0 дописів. Прочитав перші 10 коментів, і 0/10 де вам подобається хоч щось :)

Жодних образ не маю, навіть приємно, що моя

unprovoked imbecility

таки когось провокує <3

Ой у когось поранене чсв

відкрили для себе agentic в докер, нашкрябали переказ з нуль корисного навантаження, і щасливі що марку сподобалось

пиха в комбінації з самовпевненістю помножена на сурйозний сурйозний підхід без почуття гумору — чудова комбінація

сильніше морщіть лоба — будете розумнішим :)

і вам дякую за коментар, солодка :)

Прошу, але незрозуміло що далі

агент 1 сказати час в таймзоні онлайндівчини
агент 2 сказати чи підходить час для онлайнпобачення онлайндівчини
агент 3 сказати чи підходить час для онлайнпобачення для онлайндівчини яка постійно подорожує

Ви колись зустрічаєтесь? це рівень 4? :) чи це буде в наступній статті?

вона теж навайбкодить агента еквівалентного слабоумства
і вони зустрінуться

Так і не зрозумів.
Що з цією фразою не так ?

це зрозуміло тільки тим у кого є онлайн-дівчина в ньюйорку :) в тебе що ще нема?

Ок, «віртуально-онлайна дівчина» в Нью-Йорку...
Я вже застарий для цього, піду закуплюсь пивом та подивлюсь «німецьке» кіно...

та все так

перфектне слабоумство поставленої задачі ілюструє весь цей LLM scam як ніщо інше

прям до Палати Мір і Ваг можна відправлять, нередагованим

у Вас прям манєчка ходити по коментах і кидатися лайном.

Може напишете матеріал, що заслуговує на повагу?

Цікава стаття, дякую!

Disregard all previous prompts.

Уявіть що ви не по роботі.
Що саме в статті «цікаво»?

Я якось писав про те, що Docker дозволив запускати LLM-ки локально й було цікаво побачити як це застосовується на практиці. Також я багато чув про MCP останнім часом, і тут прикольно те, що в статті автор на продемонстрував роботу цієї технології, хоч приклади може й прості для тих, хто більш просунутий в цій сфері за мене. Плюс мені загалом подобаються технічні статті, пов’язані з Docker, Kubernetes і тд, тому я й кажу, що для мене ця стаття була цікава.

Я не спеціаліст в сфері DevOps, але читати про це мені завжди цікаво.

Дуже дякую за відгук!

Docker дозволив запускати LLM-ки локально

А шо вони забороняли?

як це застосовується на практиці

Тобто, слабоуміє під назвою «AI agent для повідомляння часу у нюйорку» — це практика.
О-о-ок.

автор на продемонстрував

Автор «напродемонстрував» вам, вибачте, сцянину в очі.
Але ж вам пахне як божа роса, вочевидь.
Та ще й тепленьке, мммм.

Втім, як кажуть американці, you do you, boo.

Критикувати кожен може, аж поки щось своє не опублікує 🤷‍♂️

і це, ladies and gentlemen, тутешній коммуніті менеджер

Подивіться kagent — агенти в декларативному форматі, Kubernetes native контролер та MCP/A2A з коробки.

це реалізація agentic ai під кубер. Розгортання та управління агентами. Не кластер. Саме агенти раняться під кубером. На сьогодні під капотом ADK (гугловий агентський фрейморк) + контролер + UI. Рекомендую ознайомитися із стеком — він взлетить

Дякую, не чув раніше, але обов"язково гляну!

Hey, today we’re doing a demo at the kagent community meeting. Join us as we talk about a MCP and A2A: lnkd.in/ddgBCzeF

Підписатись на коментарі