Стек для швидкої розробки AI-агентів: Aspire, Agent Framework, DevUI, AG-UI, CopilotKit

Ще рік тому «зробити агента» означало приблизно таке: написати цикл виклику LLM, приліпити до нього парсинг тул-колів, підняти власний WebSocket, вигадати формат подій для фронтенду, зверху накрутити логування — і після двох тижнів роботи отримати демо, яке падає при першому ж паралельному користувачі.

Зараз ситуація інша. Зʼявився цілком зрозумілий набір інструментів, де кожен закриває свій шар, і вони чесно стикуються між собою. Якщо коротко:

  • Aspire — оркеструє всю систему: моделі, сервіси, бази, черги, фронтенд.
  • Microsoft Agent Framework — власне мізки агента: інструменти, памʼять, воркфлоу.
  • DevUI — «постман для агентів»: подивитися, як агент думає, ще до того, як зʼявився UI.
  • AG-UI — протокол, яким агент розмовляє з інтерфейсом.
  • CopilotKit — готовий фронтенд, який цей протокол розуміє.

Далі — по одному, з прикладами. Технічних подробиць мінімум, ідея важливіша за синтаксис.


Aspire: спочатку система, потім агент

Головна помилка, яку роблять команди на старті — починають з агента. Пишуть промпт, підключають модель, все працює локально в консолі. А потім виявляється, що агенту потрібен Redis для кешу, Postgres для стану, окремий Python-сервіс для ембедингів, і фронтенд, який має все це знайти. І починається - файл docker-compose.yml на 200 рядків та README з інструкцією «спочатку запусти оце, потім зачекай, потім оце».

Aspire знімає цей біль. Ви описуєте систему кодом — і вона запускається однією командою:

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");
var db = builder.AddPostgres("db").AddDatabase("agentdb");

var backend = builder.AddProject<Projects.AgentApi>("agent-api")
    .WithReference(cache)
    .WithReference(db)
    .WithExternalHttpEndpoints();

builder.Build().Run();

Ніяких рядків підключення в конфігах — Aspire сам роздає їх сервісам, сам вигадує порти, сам чекає, поки база підніметься.

Для AI-частини є окремі інтеграції. Наприклад, модель у Foundry і агент поруч із нею — інтеграція ставиться командою aspire add azure-ai-foundry (пакет Aspire.Hosting.Foundry, поки в preview):

var foundry = builder.AddFoundry("ai");
var project = foundry.AddProject("project");
var chat = project.AddModelDeployment("chat", FoundryModel.OpenAI.Gpt5Mini);

var supportAgent = builder.AddProject<Projects.SupportAgent>("support-agent")
    .WithReference(chat).WaitFor(chat);

А якщо частина системи написана на Python — це теж просто ще один ресурс у тому самому графі:

var weather = builder.AddUvicornApp("weather-agent", "./weather-agent", "main:app")
    .WithReference(chat).WaitFor(chat);

Практична цінність тут не в красі коду. Вона в тому, що новий розробник робить git clone, пише aspire run і за хвилину бачить дашборд, де живі всі сервіси, логи й трейси. Не «а що в тебе в .env?», а працююча система.

І ще одна деталь, яка стала актуальною саме у 2026: Aspire навчився дружити з кодовими агентами. У CLI зʼявився режим aspire run --detach (підняти систему у фоні), --isolated (окреме середовище з власними портами, щоб два агенти паралельно не билися за один порт 5432), команди aspire doctor для перевірки оточення і aspire docs для програмного доступу до документації, а aspire new та aspire init тепер кладуть у проєкт MCP-сервер, через який Copilot чи Claude може сам подивитися статус ресурсів і почитати логи замість того, щоб просити у вас скріншот.

До речі, про назву: з тринадцятої версії проєкт офіційно називається просто Aspire, без префікса «.NET» — саме тому, що він давно вміє не тільки в C#. Актуальна гілка на серпень 2026 — 13.4.x.

Тобто Aspire — це не тільки для вас. Це ще й для вашого AI-помічника.


Microsoft Agent Framework: мізки

Про сам фреймворк я вже писав детальніше, тому тут коротко і по суті — що саме прискорює роботу.

Агент створюється в кілька рядків, а інструмент для нього — це звичайна функція:

pip install agent-framework
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from typing import Annotated
from pydantic import Field

def get_order_status(
    order_id: Annotated[str, Field(description="Номер замовлення")],
) -> str:
    """Повертає статус замовлення."""
    return f"Замовлення {order_id}: у дорозі, доставка завтра."

agent = Agent(
    client=OpenAIChatClient(),
    name="SupportAgent",
    instructions="Ти підтримка інтернет-магазину. Відповідай коротко і по ділу.",
    tools=[get_order_status],
)

Ніяких схем JSON вручну — фреймворк читає сигнатуру функції й опис із Annotated. Це та частина, де раніше зникав день роботи.

Другий момент — композиція. Агент може бути інструментом іншого агента:

main_agent = Agent(
    client=OpenAIChatClient(),
    instructions="Ти головний асистент. Делегуй спеціалістам.",
    tools=[support_agent.as_tool(), billing_agent.as_tool()],
)

Це той рідкісний випадок, коли «мультиагентна система» не потребує окремого архітектурного документа.

Третій — воркфлоу. Коли процес має чіткі кроки (перевірити → узгодити → виконати), не треба сподіватися, що LLM сама здогадається про порядок. Ви описуєте граф, а агенти в ньому — просто вузли. З чекпоінтами, паузою на підтвердження людиною і можливістю продовжити з місця зупинки.

Правило вибору просте: відкрита задача — агент, чіткий процес — воркфлоу. І фраза з документації, яку варто памʼятати: якщо задачу можна вирішити звичайною функцією — напишіть функцію, а не агента.

Статус на серпень 2026: версія 1.0 для .NET і Python вийшла у квітні, тобто це вже не експеримент, а продукт із зобовʼязаннями щодо сумісності. Go досі в публічному превʼю.


DevUI: подивитися агенту в очі

Найнеприємніше в розробці агентів — невидимість. Агент відповів дурницю. Чому? Він викликав не той інструмент? Отримав не ті дані? Не зрозумів промпт? У консолі ви бачите тільки фінальний текст.

DevUI розвʼязує це буквально одним рядком:

from agent_framework.devui import serve

serve(entities=[agent], auto_open=True)

Відкривається браузер, у ньому — чат із вашим агентом. Ви пишете запит і бачите не тільки відповідь, а весь ланцюжок: які інструменти викликалися, з якими аргументами, що повернули, скільки часу зайняло, які трейси OpenTelemetry записалися.

Є й варіант без коду взагалі — просто вказати папку з агентами:

pip install agent-framework-devui --pre
devui ./agents --port 8080 --instrumentation

DevUI сам їх знайде і покаже списком. Прапорець --instrumentation вмикає збір трейсів — врахуйте, що в документації на Learn досі фігурує старіша назва --tracing, якої в самому пакеті вже немає. Для .NET DevUI теж зʼявився: пакет Microsoft.Agents.AI.DevUI, поки в preview.

Окремий бонус: під капотом там OpenAI-сумісний API. Тобто ваш агент одразу можна смикати будь-яким клієнтом, який уміє в OpenAI:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="<токен з логу запуску>")

response = client.responses.create(
    metadata={"entity_id": "support_agent"},
    input="Де моє замовлення 12345?",
)

Тут є пастка, на якій легко втратити пів години: авторизація за Bearer-токеном тепер увімкнена за замовчуванням, навіть на localhost. Токен генерується при старті й друкується в консоль. Якщо в прикладах ви бачите api_key="not-needed" — це застаріло, і запит поверне 401. Або підставляйте токен, або запускайте з --no-auth.

Це дуже зручно для того етапу, коли фронтенду ще немає, а показати замовнику щось треба вже завтра. Одне важливе застереження: DevUI — інструмент розробки, не для продакшену, і в README це написано прямим текстом.


AG-UI: спільна мова агента й інтерфейсу

Ось тут ховається найбільша економія часу, про яку зазвичай не думають на старті.

Агент — це не чат-бот, який видає абзац тексту. Агент працює довго, викликає інструменти, змінює свій стан, іноді питає дозволу. Все це користувач має бачити. І кожна команда до недавнього часу винаходила свій спосіб це показати: свій формат подій, свій стрімінг, свої милиці.

AG-UI — це стандарт на цю комунікацію. Він навмисне простий: фронтенд шле POST, бекенд стрімить назад типізовані JSON-події через SSE. Типів подій станом на серпень 2026 — двадцять сім: життєвий цикл запуску, шматки тексту, виклики інструментів, зміни стану, міркування моделі, довільні RAW і CUSTOM. Транспорт при цьому не прибитий цвяхами: SSE є референсним, але протокол однаково працює поверх WebSocket чи вебхуків.

У Agent Framework це підключається парою рядків:

using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAGUIServer();

var app = builder.Build();
app.MapAGUIServer("/", agent);
app.Run();

Тут теж варто звірятися з репозиторієм, а не тільки з Learn: у частині статей і навіть на деяких сторінках документації досі трапляється старіша назва MapAGUI без AddAGUIServer(). У поточних preview-збірках працює саме MapAGUIServer.

Або на Python — тут пакет уже вийшов зі стадії превʼю, тож --pre більше не потрібен:

pip install agent-framework-ag-ui

Все. Ваш агент тепер говорить стандартною мовою, і будь-який AG-UI-сумісний фронтенд його зрозуміє.

Що саме дає протокол «з коробки»:

  • Стрімінг чату з автоматичним викликом інструментів.
  • Показ роботи інструментів — користувач бачить, що агент зараз шукає в базі, а не просто «думає».
  • Human-in-the-loop — агент зупиняється і чекає підтвердження перед небезпечною дією.
  • Спільний стан — фронтенд і бекенд синхронізують один обʼєкт стану в обидва боки.
  • Генеративний UI — агент повертає не текст, а вказівку відрендерити конкретний компонент.

І головне: AG-UI підтримує не тільки Microsoft. У списку першої категорії підтримки — Microsoft Agent Framework, Google ADK, AWS Strands, LlamaIndex, Pydantic AI, Mastra, Agno, AG2; через партнерства — LangGraph і CrewAI; силами спільноти — Claude Agent SDK і Langroid. Тобто ви можете переписати бекенд агента з Python на .NET, а фронтенд навіть не помітить. Це рідкісна розкіш.

Спробувати без свого коду можна так:

npx create-ag-ui-app@latest

CopilotKit: фронтенд, який уже все вміє

AG-UI — це протокол. CopilotKit — готовий React-фронтенд, який його реалізує. Це ті самі люди, які протокол і придумали.

Одразу застереження, бо на ньому легко обпектися: у CopilotKit є два покоління API. Старі хуки — useCopilotAction, useCopilotReadable, useCoAgent — досі працюють і нікуди з пакета не поділися, але документація вже описує v2, а в коді вони позначені як legacy. Усі приклади нижче — на v2, який імпортується з підшляху /v2. Якщо гуглитимете і натрапите на старі назви — це не помилка автора, це попереднє покоління.

Мінімальний варіант — обгорнути застосунок провайдером і додати готовий чат:

import { CopilotKit, CopilotSidebar } from "@copilotkit/react-core/v2";
import "@copilotkit/react-core/v2/styles.css";

export default function App() {
  return (
    <CopilotKit runtimeUrl="/api/copilotkit">
      <YourApp />
      <CopilotSidebar labels={{ modalHeaderTitle: "Помічник" }} />
    </CopilotKit>
  );
}

Це вже робочий чат-асистент збоку екрана. Але цікаве починається далі.

Агент бачить те саме, що й користувач. Замість того щоб копіювати контекст у промпт руками, ви просто оголошуєте, що агенту видно:

import { useAgentContext } from "@copilotkit/react-core/v2";

useAgentContext({
  description: "Поточний кошик користувача",
  value: cartItems,
});

Агент може натискати кнопки у вашому інтерфейсі. Це фронтенд-інструменти — функції, які виконуються в браузері. Схема параметрів тепер описується через Zod, а не масивом обʼєктів:

import { useFrontendTool } from "@copilotkit/react-core/v2";
import { z } from "zod";

useFrontendTool({
  name: "addToCart",
  description: "Додати товар у кошик",
  parameters: z.object({
    productId: z.string().describe("ID товару"),
    quantity: z.number().describe("Кількість"),
  }),
  handler: async ({ productId, quantity }) => {
    addItem(productId, quantity);
  },
});

Тепер користувач пише «додай дві такі ж футболки» — і кошик оновлюється. Без API, без окремого ендпоінта.

Агент може малювати інтерфейс. Найефектніша частина — замість тексту повернути компонент:

import { useRenderTool } from "@copilotkit/react-core/v2";
import { z } from "zod";

useRenderTool({
  name: "showOrderStatus",
  parameters: z.object({ orderId: z.string() }),
  render: ({ status, parameters, result }) =>
    status === "complete"
      ? <OrderCard order={result} />
      : <OrderCardSkeleton id={parameters.orderId} />,
});

Замість абзацу «Ваше замовлення 12345 у дорозі, орієнтовна доставка завтра» користувач бачить нормальну картку з трекінгом і кнопкою — причому ще до того, як бекенд відповів, бо status дозволяє показати скелетон.

Одна незручність, про яку варто знати заздалегідь: у useRenderTool аргументи приходять у полі parameters, а в інлайновому render всередині useFrontendTool — у полі args. Це справді так в обох API, а не помилка в документації.

Спільний стан із бекенд-агентом. Якщо ваш агент довго працює над задачею і має власний стан — його видно в React:

import { useAgent } from "@copilotkit/react-core/v2";

const { agent, isReady } = useAgent({ agentId: "research-agent" });

// agent.state, agent.messages, agent.isRunning
agent.setState({ ...agent.state, topic: "AG-UI" });

Агент додав джерело — компонент перемалювався. Користувач змінив тему — агент про це знає.

Підключення AG-UI-бекенду. Ваш ендпоінт реєструється в рантаймі як HttpAgent — і після цього все перелічене вище працює автоматично:

// app/api/copilotkit/route.ts
import { HttpAgent } from "@ag-ui/client";
import { CopilotRuntime, copilotRuntimeNextJSAppRouterEndpoint } from "@copilotkit/runtime";

const runtime = new CopilotRuntime({
  agents: { default: new HttpAgent({ url: "http://localhost:8000/" }) },
});

export const POST = async (req) => {
  const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
    runtime,
    endpoint: "/api/copilotkit",
  });
  return handleRequest(req);
};

Ну і практичне: є готові компоненти CopilotChat, CopilotSidebar, CopilotPopup, а є headless-режим, коли вам віддають лише логіку, а весь дизайн ви робите свій. Є інтеграції зі Slack і Teams — той самий агент живе і в застосунку, і в корпоративному месенджері.


Як це складається разом

Уявімо реальну задачу: асистент для внутрішнього порталу компанії. Вміє шукати по базі знань, дивитися статуси задач, створювати заявки. Ось як виглядає шлях.

День перший. Пишете агента на Agent Framework. Три функції-інструменти, один промпт. Запускаєте serve(entities=[agent]) і в DevUI ганяєте його запитами: правильні інструменти? нормальні відповіді? Правите промпт, поки не почне поводитися пристойно. Фронтенду ще немає, і він не потрібен.

День другий. Додаєте app.MapAGUIServer("/", agent) — агент став HTTP-сервісом зі стрімінгом. Піднімаєте фронтенд на CopilotKit, вказуєте runtime URL. Отримуєте чат зі стрімінгом, показом інструментів і підтвердженнями. Написаного коду UI — рядків двадцять.

День третій. Заявку на доступ агент створювати вміє, але робити це без підтвердження страшно. Позначаєте інструмент як такий, що потребує апруву — AG-UI сам покаже користувачу діалог «підтвердити / відхилити». Далі додаєте useRenderTool, щоб замість тексту про заявку показувалася картка з кнопкою «відкрити в трекері».

День четвертий. Загортаєте все в Aspire: агент, фронтенд, Postgres для історії, Redis для кешу, окремий Python-сервіс для пошуку по базі знань. Одна команда — і вся система жива, з дашбордом, логами й наскрізними трейсами OpenTelemetry: видно, скільки коштував запит, який інструмент гальмує, де впало.

Чотири дні. Не тому, що хтось геніальний, а тому, що жоден із цих шарів не довелося писати самому.


Що варто памʼятати

Кілька тверезих зауважень, щоб стаття не виглядала рекламою.

Швидко зробити прототип ≠ швидко зробити продукт. Стек економить інфраструктурну роботу, але промпти, оцінка якості, обробка галюцинацій і граничні випадки — все одно ваші. Саме туди піде більшість часу, і це нормально.

Набір інструментів залежить від провайдера моделі. Function tools і локальний MCP працюють майже скрізь, а code interpreter чи file search — не завжди. Матрицю сумісності краще перевірити до того, як закласти щось в архітектуру, а не після.

DevUI — не продакшен. Це інструмент розробника, і в документації це написано прямо.

Частина речей досі в preview. Ядро Agent Framework і Python-пакет AG-UI уже GA, а от .NET-пакети хостингу AG-UI та DevUI, інтеграція Aspire з Foundry і функціональні воркфлоу — ні. Для внутрішніх інструментів це цілком ок, для критичних систем — тримайте в голові.

Документація місцями відстає від коду. Це найнеприємніше на практиці. Правило просте: якщо приклад із документації не працює — йдіть у репозиторій і дивіться README або код. Екосистема рухається швидше, ніж встигають оновлювати сторінки.

Але загальний напрямок дуже приємний. Розробка агентів перестала бути дослідницьким проєктом і стала звичайною інженерією: є оркестратор, є фреймворк, є протокол, є UI-бібліотека, є інструмент для дебагу. Приблизно як веб-розробка років пʼятнадцять тому перестала бути мистецтвом і стала ремеслом.

А найкраще в цьому те, що всі шари взаємозамінні. Не подобається CopilotKit — пишіть свій фронтенд на AG-UI. Не подобається Agent Framework — беріть LangGraph чи Pydantic AI, протокол той самий. Оце і є ознака зрілої екосистеми.

Sources: Aspire — AppHost, Aspire — Azure AI Foundry hosting, Aspire — Python integration, Announcing Aspire 13.2, What’s new in Aspire 13.4, Distributed multi-agent systems with Aspire and Microsoft Agent Framework, Microsoft Agent Framework Overview, DevUI README, AG-UI integration — getting started, AG-UI Protocol (GitHub), AG-UI event types, CopilotKit — migrate to v2, CopilotKit — useFrontendTool, CopilotKit — useRenderTool, CopilotKit — useAgent, CopilotKit — connect AG-UI agents