- BrainTools - https://www.braintools.ru -

AG-UI. Как написать AI ассистента для подбора подарков за 20 минут

Всем привет! Я Никита, Principal Engineer в стартапе AG2, мейнтейнер одноименного фреймворка для разработки AI агентов (AG2 [1]), автор фреймворка FastStream [2] и просто опенсорс и AI энтузиаст.

И, как любой разработчик, я иногда запускаю пет-проекты.

Один из таких проектов, который я запустил после новогодних праздников – это AI ассистент по подбору подарков (с интегрированным вишлистом) Дарий [3]

На его примере я хочу рассказать о протоколе AG-UI и на практике показать, как разработать ChatGPT-like агентное приложение за пару минут. Рассмотрим как бекенд (python), так и фронтенд (NextJS).

Важное уточнение: это реальный проект, с которым вы можете взаимодействовать. Это не разбор искусственных hello-world примеров.

После прочтения статьи у вас будет подробное руководство по разработке интерактивных chat-based приложений с элементами Generative UI.

Зачем я вообще сделал этот проект

Как многие программисты-социофобушки, я испытываю стресс [4] в период праздников. Мне тяжело подбирать подарки – боюсь ошибиться, подарить что-то не то, да и с фантазией все плохо. Но с другой стороны – я очень заботливый и хочу порадовать своих близких отличным подарков. И эта забота только усиливает стресс…

Решением для меня стал ChatGPT. На удивление он отлично генерирует идеи для подарков. На Новый Год я пошел по следующему пути:

  1. Подготовил небольшое “досье” на близких людей: что им нравится, не нравится, ссылки на их вишлисты (при наличии), социальные профили, описание наших отношений и контекст ближайших событий.

  2. Закинул эту простыню текста в GPT и попросил накидать идеи подарков – чтобы не совсем из вишлиста (я же хочу приятно удивить человека), но и “в тему”

  3. ChatGPT накинул интересные варианты, мы с ним еще поразгоняли и остановились на наборе, который меня устраивает

  4. Попросил GPT найти ссылки на конкретные позиции для покупки – он быстренько прошерстил интернет и я все заказал

Суммарно это заняло 10 минут на человека и избавило меня от большошо количества стресса [5] и демотивации выбором. Наоборот – подарки было интересно выбирать. GPT убрал весь стресс [6] из этого процесса.

Было настолько удобно, что я решил завернуть этот сценарий в сервис – Дарий [7].
Единственное отличие – чтобы не рассказывать о человеке каждый раз заново, в приложении можно вести свой профиль и вишлист.
Но сценарий, когда аккаунта пользователя нет на платформе, тоже заложен.

Если хотите полную историю “зачем” – у Дария есть свой манифест [8]

Как работает Дарий

В Дарии пользователь может заполнять свой профиль – немного информации о себе, что нравится и не нравится. А также вести вишлист – конкретный список вещей, которые можно подарить.

Даритель (или сам пользователь) может попросить Дария предложить идеи для подарков. Дарий изучит профиль пользователя, его вишлист, задаст пару уточняющих вопросов, прошерстит интернет – и предложит конкретные варианты.

Для удобства взаимодействия в проекте активно используется Generative UI (когда нейросеть сама рисует компоненты в UI) – Дарий предлагает варианты ответов табами, а также рисует свои предложения в виде карточек товара прямо в чате.

Выглядит все это следующим образом:

Технические требования к агенту

Итак, исходя из сценария, Дарий должен:

  • понимать, что за пользователь к нему обращается

  • распознавать упоминание профиля подопечного в чате

  • уметь доставать из БД информацию о профиле и его вишлисте

  • уметь искать в интернете (с учетом геолокации пользователя / подопечного)

  • предлагать пользователю стандартные варианты ответов табами в UI

  • рисовать карточки товаров в чате

В общем, дел на 20 минут. Зашли и вышли.

AG-UI Приложения

AG-UI [9] (Agent to UI) – это открытый протокол для реализации взаимодействия пользователя с агентным приложением.
Использование открытого протокола позволяет не реализовывать все взаимодействие самостоятельно, а воспользоваться готовыми решениями как для Frontend, так и для Backend части.

До реализации Дария я каждый раз писал что-то похожее на вебсокетах самостоятельно. Тот еще геморой. Поэтому для своего пет-проекта я решил попробовать
новую технологию – и не прогадал.

AG-UI строго регламентирует формат сообщений, которыми обмениваются серверная и клиентская часть агентного приложения, а также предлагает готовые реализации транспорта: HTTP-SSE и HTTP-Binary. Однако он совместим с любой реализацией интерфейса

interface RunAgent {
    (input: RunAgentInput): Observable<BaseEvent>;
}
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 1 [10]

Т.е. нам просто нужен метод, который принимает на вход параметры “запуска агента”, а возвращает поток AG-UI событий.
На практике это позволяет вам не думать об общении с агентом как таковым, а просто писать БЛ вашего сценария в чате. Нюансы реализации
берут на себя разработчики конкретных библиотек.

В общем, отличия AG-UI и обычных решений на вебсокетах:

Обычно

С AG-UI

WebSocket логика [11]

Observable событий

Свой формат сообщений

Стандарт

UI и агент склеены

Развязаны

Backend – PydanticAI

Для реализации проекта я выбрал PydanticAI [12], а не свой фреймворк AG2, по одной простой причине – у них есть поддержка
AG-UI, а у нас – нет. Точнее не было :) Благо, я могу закидывать задачки в роадмап фреймворка. Так что после работы над Дарием я
затащил поддержку этого протокола в AG2 – изменения уже в main ветке, релиз будет на днях.

Чтож, для того, чтобы наш серверный агент стал доступен для AG-UI взаимодействия, нам нужно всего ничего:

  1. Пишем своего агента

from pydantic_ai import Agent

agent = Agent(
    tools=[...],
    instructions="Ты - Дарий - помощник по подбору подарков. Вот и помогай!"
)
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 2 [10]
  1. Заворачиваем его в AG-UI адаптер и SSE Endpoint HTTP фреймворка:

from ag_ui.core import RunAgentInput
from fastapi import APIRouter, Header
from fastapi.responses import StreamingResponse
from pydantic_ai.models import Model
from pydantic_ai.ui import SSE_CONTENT_TYPE
from pydantic_ai.ui.ag_ui import AGUIAdapter

from settings import model

router = APIRouter(prefix="/chat", tags=["chat"])

@router.post("/")
async def run_agent(
    run_input: RunAgentInput,
    accept: str = Header(SSE_CONTENT_TYPE),
) -> StreamingResponse:
    adapter = AGUIAdapter(
        agent=agent,  # наш PydanticAI агент
        run_input=run_input,
        accept=accept,
    )
    event_stream = adapter.run_stream(
        model=model  # в реальном проекте модель для подключения передается через DI
    )
    sse_event_stream = adapter.encode_stream(event_stream)
    return StreamingResponse(sse_event_stream, media_type=accept)
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 3 [10]

Этого уже достаточно, чтобы “чатиться” с нашим агентом. Инструменты докинем в него чуть позже.

Детали

Подход с использованием SSE стрима напрямую имеет существенное преимущество – HTTP логика строго отделена от логики самого агента.
Поэтому мы можем использовать стандартные решения для нашего HTTP приложения: например, авторизация у нас реализуется через стандартный fastapi.Depends

@router.post("/")
async def run_agent(
    # переиспользуем Depends из обычного приложения
    current_user: Annotated[User | None, Depends(get_user)],
    run_input: RunAgentInput,
    accept: str = Header(SSE_CONTENT_TYPE),
) -> StreamingResponse:
    ...
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 4 [10]

Передача модели при запуске, а не как параметер агента, также очень важна:

event_stream = adapter.run_stream(
    model=model
)
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 5 [10]

Используя такой подход мы можем легко реализовать следующий функционал:

  • запускать агента с моделью текущего пользователя (если мы даем возможность привязывать свои API ключи)

  • запускать разные модели для платных / бесплатных / анонимных пользователей

  • конфигурировать модель в рантайме без глобальных переменных

Frontend – CopilotKit

Для реализации самого чата в браузере возьмем фреймворк CopilotKit [13] – я считаю, он незаслуженно обделен вниманием [14] в ру комьюнити.
Этот фреймворк полностью реализует AG-UI протокол и позволяет вам использовать готовые React компоненты для чата.
На выбор есть следующие варианты [15]:

  • Сам чат отдельной страницей

  • Sidebar чат

  • Popup чат

  • Headless UI (для тех, кто хочет “совсем свое”)

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

В нашем случае возьмем обычную чат-страницу

// app/chat/page.tsx
"use client";

import { CopilotChat } from "@copilotkit/react-ui";
import { CopilotKit } from "@copilotkit/react-core";

export default function ChatPage() {
    return <div
        className="min-h-[calc(100vh-8rem)]
            px-4 sm:px-6 lg:px-8
            flex flex-col relative overflow-x-hidden"
    >
        {/* провайдер CopilotKit с указанием
        адреса и имени CopilotKit агента (не PydanticAI)*/}
        <CopilotKit
            runtimeUrl="/api/copilot"
            agent="dariy"
        >
            {/* сам CopilotKit чат 
            с кастомными компонентами для отрисовки */}
            <CopilotChat
                className="flex-1 flex flex-col relative h-full overflow-hidden w-full md:w-[70%] mx-auto"
                disableSystemMessage={true}
                labels={{
                    title: "Дарий",
                    initial: `👋 Привет! Я Дарий, ваш помощник по подбору подарков!
                            Расскажи мне о своем подопечном, и я помогу тебе подобрать лучший подарок.`,
                }}
                UserMessage={CustomUserMessage}
                AssistantMessage={CustomAssistantMessage}
                Input={CustomInput}
            >
            </CopilotChat>
        </CopilotKit>
    </div>
}
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 6 [10]

Обратите внимание, что CopilotKit подключается не к нашему PydanticAI агенту, а к своему адаптеру. Этот адаптер располагается на серверной части того же NextJS приложения и общается с UI компонентами в своем формате.

Он выглядит следующим образом:

// app/api/copilot/route.ts
import {
  CopilotRuntime,
  ExperimentalEmptyAdapter,
  copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
import { HttpAgent } from "@ag-ui/client";
import { NextRequest } from "next/server";
import { API_BASE_URL } from "@/lib/consts";

const serviceAdapter = new ExperimentalEmptyAdapter();

const pydanticAgent = new HttpAgent({
    // адрес нашего FastAPI эндпоинта
    url: `${API_BASE_URL}/chat/`,
});

export const POST = async (req: NextRequest) => {
  const runtime = new CopilotRuntime({
    agents: {
      // имя агента из CopilotKit
      dariy: pydanticAgent,
    },
  });

  const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
    runtime,
    serviceAdapter,
    // адрес, который мы указали в CopilotKit
    endpoint: "/api/copilot",
  });

  return handleRequest(req);
};
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 7 [10]

Все! Этого уже достаточно, чтобы получить полностью функциональный чат с вашим серверным агентом. Теперь мы можем приступать к разработке бизнес-логики.

Добавляем Backend Tools

Теперь нам нужно добавить агенту возможность изучать профиль пользователя и его вишлист.

Тут можно пойти двумя путями:

  • дать агенты read доступ напрямую в БД

  • дать агенту фиксированные методы для получения данных

Мы пойдем вторым путем. Фиксированная логика не позволит агенту случайно выдать информацию, к которой пользователь не имеет доступ. Да и в принципе не даст агенту сойти с ума от избытка информации.

Во всех фреймворках инструменты реализуются довольно просто. С Pydanitc AI у нас получится что-то такое:

from dataclasses import dataclass
from datetime import date

from pydantic_ai import RunContext, Tool

# наш класс для определения "зависимостей"
from .dependencies import Dependencies


@dataclass
class UserBio:
    name: str
    birthday: date | None
    bio: str | None
    interests: list[str]


async def get_user_profile(ctx: RunContext[Dependencies], user_id: str) -> UserBio:
    session = await ctx.deps.session_maker()
    user = await get_user(user_id, session)
    return UserBio(...)


@dataclass
class WishItem:
    wish_id: str

    title: str
    description: str | None
    price: float | None
    url: str | None
    categories: list[str]


async def get_user_wishes(ctx: RunContext[Dependencies], user_id: str) -> list[WishItem]:
    session = await ctx.deps.session_maker()
    wishes = await get_user_wishes(user_id, session)
    return [WishItem(...) for w in wishes]


agent = Agent[Dependencies, str](
    tools=[
        Tool[Dependencies](
            get_user_profile,
            name="get_user_profile",
            takes_ctx=True,
            description=(
                "Get user bio, birthday, interests and other information about the user. "
                "The user is identified by @`user_id` or @`user_slug`."
            ),
        ),
        Tool[Dependencies](
            get_user_wishes,
            name="get_user_wishes",
            takes_ctx=True,
            description=(
                "Get user's wishlist items including product details. "
                "The user is identified by @`user_id` or @`user_slug`."
            ),
        )
    ]
)
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 8 [10]

Dependency Injection в инструменты

В примере выше у нас есть класс Dependencies, который представляет собой те “зависимости”, которые мы хотим передать в наши инструменты.
Указать их можно при запуске агента:

@dataclass
class Dependencies:
    session_maker: async_sessionmaker
    user_id: str | None = None


@router.post("/")
async def run_agent(
    session_maker: Annotated[async_sessionmaker, Depends(get_session_maker)],
    current_user: Annotated[User | None, Depends(get_user)],
    run_input: RunAgentInput,
    accept: str = Header(SSE_CONTENT_TYPE),
) -> StreamingResponse:
    adapter = AGUIAdapter(
        agent=agent,
        run_input=run_input,
        accept=accept,
    )

    # формируем зависимости
    request_deps = Dependencies(
        session_maker=session_maker,
        user_id=current_user.id,
    )

    event_stream = adapter.run_stream(
        deps=request_deps,  # передаем зависимости в запрос к агенту
        model=model
    )
    sse_event_stream = adapter.encode_stream(event_stream)
    return StreamingResponse(sse_event_stream, media_type=accept)
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 9 [10]

Уведомление пользователя о запуске инструментов

Теперь наш агент может принимать решения более взвешено. Однако работать он стал тоже значительно дольше. Чтобы пользователь не скучал и понимал, что происходит прямо сейчас, давайте отрисовывать вызовы инструментов прямо в UI.

AG-UI подразумевает отправку событий о запуске и завершении инструментов агентом. Мы можем использовать эту информацию для отображения компонентов в бразуере.

Для этого в CopilotKit есть хук useRenderToolCall – он позволяет захватить запуск инструментов на бекенде и отрисовать их как React компоненты в чате.

С его помощью удобно делать progressive трекеры или отрисовывать результаты работы инструментов красивыми карточками

"use client";

import { CopilotChat } from "@copilotkit/react-ui";
import { CopilotKit } from "@copilotkit/react-core";

function Chat() {
    useRenderToolCall({
        name: "get_user_bio",  // название бекенд инструмента
        render: ({ status }) => {  // React компонент
            if (status !== "complete") {
                return (
                    <div className="flex items-center gap-2 text-gray-500 dark:text-gray-400 text-sm py-2">
                        <div className="w-4 h-4 border-2 border-primary-500 border-t-transparent rounded-full animate-spin" />
                        Изучаю профиль пользователя...
                    </div>
                );
            }
            return <></>;
        },
    });

    useRenderToolCall({
        name: "get_user_wishes",  // название бекенд инструмента
        render: ({ status }) => {  // React компонент
            if (status !== "complete") {
                return (
                    <div className="flex items-center gap-2 text-gray-500 dark:text-gray-400 text-sm py-2">
                        <div className="w-4 h-4 border-2 border-primary-500 border-t-transparent rounded-full animate-spin" />
                        Изучаю желания пользователя...
                    </div>
                );
            }
            return <></>;
        },
    });

    return <CopilotChat
        className="flex-1 flex flex-col relative h-full overflow-hidden w-full md:w-[70%] mx-auto"
        disableSystemMessage={true}
        labels={{
            title: "Дарий",
            initial: `👋 Привет! Я Дарий, ваш помощник по подбору подарков!
                    Расскажи мне о своем подопечном, и я помогу тебе подобрать лучший подарок.`,
        }}
    >
    </CopilotChat>
}

export default function ChatPage() {
    return <div
        className="min-h-[calc(100vh-8rem)]
            px-4 sm:px-6 lg:px-8
            flex flex-col relative overflow-x-hidden"
    >
        {/* провайдер CopilotKit */}
        <CopilotKit runtimeUrl="/api/copilot" agent="dariy">
            <Chat/>
        </CopilotKit>
    </div>
}
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 10 [10]

Теперь при вызове инструментов агентом на сервере, пользователь увидит соответствующие сообщения в чате. Но мы этим не ограничены – вы вольны отображать компоненты любой сложности, если этого требуют сценарий.

Обратите внимени, что все CopilotKit хуки должен находится внутри CopilotKit провайдера.

Инструмент для поиска в интернете

По такому же принципу добавим инструмент для поиска в интернете (и его UI отображение). Благо, во все
фреймворки по умолчанию включен DuckDuckGo-поисковый инструмент

Единственный нюанс – нам нужно задавать регион и локацию основывясь на локации текущего пользователя

import functools

import anyio.to_thread
from ddgs.ddgs import DDGS
from pydantic_ai import RunContext, Tool
from pydantic_ai.common_tools.duckduckgo import DuckDuckGoResult, duckduckgo_ta

from .dependencies import Dependencies

async def duckduckgo_search(
    ctx: RunContext[Dependencies],
    query: str,
    max_results: int | None = 10,
) -> list[DuckDuckGoResult]:
    # попробуем получить локацию пользователя из IP запроса
    # и поместим ее в зависимости сессии
    region = ctx.deps.location or "ru-ru"

    search = functools.partial(
        DDGS().text,
        region=region,
        max_results=max_results,
    )
    try:
        results = await anyio.to_thread.run_sync(search, query)
    except Exception:
        return [DuckDuckGoResult(title="Web search failed", href="", body="")]

    return duckduckgo_ta.validate_python(results)


search_tool = Tool[Dependencies](
    duckduckgo_search,
    name="duckduckgo_search",
    takes_ctx=True,
    description="Searches DuckDuckGo for the given query and returns the results.",
)
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 11 [10]

Generative UI

Теперь перейдем в браузер и сделаем его немного веселее.

Практически все фичи CopilotKit основаны на простой идее – FrontendTools.
Т.е. клиент передает с запросом к агенту список инструментов, которые доступны в браузере.
LLM не видит разницы между такими инструментами и обычными серверными. Агент же, когда видит вызов FrontendTool моделью, отправляет соответствующее AG-UI событие, а CopilotKit запускает нужный инструмент в браузере пользователя.

Таким образом можно:

  • отрисовывать UI компоненты (Generative UI)

  • запрашивать пользовательский ввод (HITL)

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

  • делать любые вещи, которые допускает JS и ваша фантазия

Предлагаем ответы табами

Например, для отрисовки вариантов ответов табами, мы используем HITL хук

useHumanInTheLoop({
    // Описание инструмента для LLM
    name: "suggest_next_steps",
    description: `Suggest next steps to the user`,
    // JSON Schema для описания параметров инструмента
    parameters: [
        {
            name: "suggestion_answers",
            type: "string[]",
            description: `Array of suggestion titles to display to the user as answer options`,
            required: true,
        },
        {
            name: "question",
            type: "string",
            description: "Question to the user to clarify the situation",
            required: true,
        },
    ],
    // Обычный React компонент для рендеринга
    render: ({ args, respond }) => {
        const { suggestion_answers, question } = args as {
            suggestion_answers: string[],
            question: string
        };

        return {respond && <div className="flex flex-wrap gap-2">
            {suggestion_answers.map((suggestion) =>
                <SuggestionButton
                    key={suggestion}
                    suggestion={{ title: suggestion, message: suggestion }}
                    onSuggestionClick={(message: string) => {
                        respond(message);
                    }}/>
            )}
        </div>}
    },
});
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 12 [10]

Теперь агент может задавать пользователю вопросы и предлагать варианты ответов табами.

Табы с подсказками

Табы с подсказками

Пришлось немного поприседать, чтобы сделать захват пользовательского ввода легитимным ответом на вызов инструмента наравне с нажатием на таб. Но эта проблема имеет множество решений.

Рисуем карточки товара

Для отрисовки карточек предлагаемого подарка добавим еще один FrontendTool

useFrontendTool({
    // Описание инструмента для LLM
    name: "display_gift_ideas",
    description: "Use this tool to show recommended gifts",
    // JSON Schema для описания параметров инструмента
    parameters: [
        {
            name: "ideas",
            type: "object[]",
            description: "Array of recommended gifts",
            required: true,
            properties: [
                { name: "title", type: "string", description: "Gift title", required: true },
                { name: "description", type: "string", description: "Why this gift is a good choice", required: true },
                { name: "url", type: "string", description: "URL to the product page", required: true, },
                {
                    name: "price",
                    type: "object",
                    description: "Price with amount and currency",
                    required: false,
                    properties: [
                        { name: "amount", type: "number", description: "Price amount", required: true },
                        { name: "currency", type: "string", description: "Price currency", required: true },
                    ],
                },
            ],
        },
    ],
    // отвечаем модели на вызов
    handler: async ({ ideas }) => {
        return { displayed: Array.isArray(ideas) ? ideas.length : 0 };
    },
    // рендерим React компонент
    render: ({ status, args }) => {
        if (!args || status == "inProgress" || status === "executing") {
            return <></>;
        }

        const ideas = (args.ideas || []).map((idea) => ({
            title: idea.title,
            description: idea?.description || idea?.why,
            url: idea?.url || idea?.link,
            price: idea.price,
        }));

        return <WishCards wishes={ideas} />;
    },
});
AG-UI. Как написать AI ассистента для подбора подарков за 20 минут - 14 [10]

Теперь агент будет предлагать не просто текстовое описание подарка, но и рендерить интерактивную карточку прямо в чате

Карточки подарков

Карточки подарков

Проблемы AG-UI

  1. Больше всего меня напрягает сильно размазанный промпт между разными частями системы. Тебе нужно составить качественное описание Backend инструментов, Frontend инструментов, их параметров – но это не помогает. Для нормальной работы агента нужно еще и в системном промпте повторить все это + рассказать, в каком порядке и в каких случаях вызывать эти инструменты. Хотели разделить агента и UI, но система все равно получается достаточно связной.

  2. Пока нет поддержки Thinking. Т.е. сами Thinking Events уже в драфте, а даже внедрены в ряде бекенд фреймворков, но пока нет поддержки в CopilotKit. Ждемс…

  3. Пока это однонаправленный канал общения. События стримятся от агента к пользователю, но не наоборот. Хотелось бы иметь возможность отправлять события от пользователя к агенту в процессе его функционирования. Но это пока задача, которую никто не знает как решать.

Итоги

Еще пару лет назад такие интерфейсы выглядели как “магия”. Сейчас это уже обычная инженерная задача. Использование AG-UI как транспорта позволяет сфокусироваться на сценариях и бизнес-логике агента, а не на бесконечном склеивании стримов, форматов сообщений и UI-состояний.

На примере Дария я собрал агентное приложение, которое:

  • работает с пользовательскими данными без прямого доступа LLM к БД

  • использует инструменты как основной механизм принятия решений

  • умеет искать в интернете с учетом контекста пользователя

  • отображает процесс работы агента и результаты через Generative UI

И все это занимает минимум кода, который описывает, в основном, бизнес-логику происходящего, а не низкоуровневые детали.

Часть кода в примерах была опущена, сокращена или упрощена ради читабельности, но сама композиция инструментов и взаимодействий полностью рабочая. Основная сложность здесь не в инфраструктуре, а в сценариях и промптинге: нужно объяснить агенту, какие инструменты ему доступны, в каком порядке их вызывать и как обрабатывать нестандартные кейсы. Именно это и есть основная точка оптимизации.

Если вы сейчас проектируете агентное приложение или собираетесь это делать, мой совет простой: не пишите транспорт руками. Используйте готовые протоколы и тратьте время на то, что действительно отличает ваш продукт.

Напомню, что Дарий [3] – это настоящий функционирующий и развивающийся проект, который вы можете опробовать сами.

Единственное, я еще не проводил полное тестирование агента через garak [16] и не выстраивал защиту от промпт-инъекций. Поэтому агента можно забавно “сломать”

А поддержку AG-UI в AG2 [17] мы выпустим уже в конце этой недели, так что я смогу переписать Дария на свой родной инструментарий :)

Если вам интересно читать про такие активности, вы можете подписаться на

Где я рассказываю об опенсорсе, AI, продуктивности и всему, что мне интересно.

Увидимся!

Автор: Propan671

Источник [19]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/25249

URLs in this post:

[1] AG2: https://github.com/ag2ai/ag2

[2] FastStream: https://github.com/ag2ai/faststream

[3] Дарий: https://xn--80ahne7a.com?utm_source=habr.com

[4] стресс: http://www.braintools.ru/article/9548

[5] стресса: http://www.braintools.ru/article/9041

[6] стресс: http://www.braintools.ru/article/6151

[7] Дарий: https://xn--80ahne7a.com/chat?utm_source=habr.com

[8] манифест: https://xn--80ahne7a.com/blog/dariy-philosophy?utm_source=habr.com

[9] AG-UI: https://docs.ag-ui.com/introduction

[10] Image: https://sourcecraft.dev/

[11] логика: http://www.braintools.ru/article/7640

[12] PydanticAI: https://ai.pydantic.dev/

[13] CopilotKit: https://docs.copilotkit.ai/

[14] вниманием: http://www.braintools.ru/article/7595

[15] следующие варианты: https://docs.copilotkit.ai/pydantic-ai/agentic-chat-ui

[16] garak: https://github.com/NVIDIA/garak

[17] AG-UI в AG2: https://docs.ag2.ai/latest/docs/user-guide/ag-ui/

[18] мой Telegram канал: https://t.me/fastnewsdev

[19] Источник: https://habr.com/ru/articles/992866/?utm_source=habrahabr&utm_medium=rss&utm_campaign=992866

www.BrainTools.ru

Rambler's Top100