미들웨어
미들웨어 (Middleware)
기존 프로토콜, 인프로세스 에이전트, 커스텀 솔루션을 AG-UI로 연결하는 방법을 다루는 페이지예요. 미들웨어 구현은 기존 프로토콜과 애플리케이션을 AG-UI 이벤트로 번역(translate) 합니다.
출처: 문서
본문
소개 (Introduction)
미들웨어 구현을 사용하면 기존 프로토콜과 애플리케이션을 AG-UI 이벤트로 번역할 수 있어요. 이 접근 방식은 여러분의 기존 시스템과 AG-UI 사이에 브리지를 만들어, 현재 애플리케이션에 에이전트 기능을 추가하는 데 아주 적합합니다.
미들웨어 구현을 써야 할 때 (When to use a middleware implementation)
미들웨어는 유연한 선택지예요. 기존 프로토콜과 애플리케이션을 AG-UI 이벤트로 번역해 여러분의 기존 시스템과 AG-UI 사이에 브리지를 만들 수 있습니다.
미들웨어는 다음에 아주 좋습니다:
- 기존 프로토콜이나 API를 범용적으로 번역할 때
- 기존 시스템이나 프레임워크의 제약 안에서 작업할 때
- 에이전트 프레임워크나 시스템을 직접 통제할 수 없을 때
만들게 될 것 (What you'll build)
이 가이드에서는 다음을 수행하는 미들웨어 에이전트를 만듭니다:
AbstractAgent클래스 확장- OpenAI의 GPT-4o 모델에 연결
- OpenAI 응답을 AG-UI 이벤트로 번역
- 애플리케이션과 함께 인프로세스로 실행
이 접근 방식은 AG-UI 프로토콜의 모든 힘을 유지하면서 기존 코드베이스와 통합할 수 있는 최대한의 유연성을 제공합니다.
시작해 볼게요!
사전 요구 사항 (Prerequisites)
시작하기 전에 다음이 있는지 확인하세요:
- Node.js v16 이상
- OpenAI API 키
1. OpenAI API 키 제공
먼저 API 키를 설정합니다:
# Set your OpenAI API key
export OPENAI_API_KEY=your-api-key-here
2. 빌드 유틸리티 설치
다음 도구들을 설치하세요:
brew install protobuf
npm i nx
curl -fsSL https://get.pnpm.io/install.sh | sh -
1단계 – 통합 스캐폴드 (Step 1 – Scaffold your integration)
저장소를 클론하는 것부터 시작합니다
git clone [email protected]:ag-ui-protocol/ag-ui.git
cd ag-ui/
미들웨어 스타터 템플릿을 복사해 OpenAI 통합을 만듭니다:
cp -r integrations/middleware-starter integrations/openai
메타데이터 갱신 (Update metadata)
integrations/openai/package.json을 열고 필드를 새 폴더에 맞게 갱신합니다:
{
"name": "@ag-ui/openai",
"author": "Your Name <[email protected]>",
"version": "0.0.1",
... rest of package.json
}
다음으로 integrations/openai/src/index.ts 안의 클래스 이름을 갱신합니다:
// change the name to OpenAIAgent
export class OpenAIAgent extends AbstractAgent {}
마지막으로 apps/dojo/src/menu.ts에 추가해 여러분의 통합을 dojo에 소개합니다:
// ...
export const menuIntegrations: MenuIntegrationConfig[] = [
// ...
{
id: "openai",
name: "OpenAI",
features: ["agentic_chat"],
},
]
그리고 apps/dojo/src/agents.ts:
// ...
import { OpenAIAgent } from "@ag-ui/openai"
export const agentsIntegrations: AgentIntegrationConfig[] = [
// ...
{
id: "openai",
agents: async () => {
return {
agentic_chat: new OpenAIAgent(),
}
},
},
]
2단계 – dojo 의존성에 패키지 추가 (Step 2 – Add package to dojo dependencies)
apps/dojo/package.json을 열고 패키지 @ag-ui/openai를 추가합니다:
{
"name": "demo-viewer",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@ag-ui/agno": "workspace:*",
"@ag-ui/langgraph": "workspace:*",
"@ag-ui/mastra": "workspace:*",
"@ag-ui/middleware-starter": "workspace:*",
"@ag-ui/server-starter": "workspace:*",
"@ag-ui/server-starter-all-features": "workspace:*",
"@ag-ui/vercel-ai-sdk": "workspace:*",
"@ag-ui/openai": "workspace:*", <- Add this line
... rest of package.json
}
3단계 – dojo 시작 (Step 3 – Start the dojo)
이제 여러분의 작업이 동작하는 모습을 봅니다:
# Install dependencies
pnpm install
# Compile the project and run the dojo
pnpm dev
http://localhost:3000으로 가서 드롭다운에서 OpenAI를 선택하세요. 지금은 스텁 에이전트가 **Hello world!**라고 답하는 걸 볼 수 있어요.
그 스텁 에이전트가 하는 일은 다음과 같습니다:
// integrations/openai/src/index.ts
import {
AbstractAgent,
BaseEvent,
EventType,
RunAgentInput,
} from "@ag-ui/client"
import { Observable } from "rxjs"
export class OpenAIAgent extends AbstractAgent {
run(input: RunAgentInput): Observable<BaseEvent> {
const messageId = Date.now().toString()
return new Observable<BaseEvent>((observer) => {
observer.next({
type: EventType.RUN_STARTED,
threadId: input.threadId,
runId: input.runId,
} as any)
observer.next({
type: EventType.TEXT_MESSAGE_START,
messageId,
} as any)
observer.next({
type: EventType.TEXT_MESSAGE_CONTENT,
messageId,
delta: "Hello world!",
} as any)
observer.next({
type: EventType.TEXT_MESSAGE_END,
messageId,
} as any)
observer.next({
type: EventType.RUN_FINISHED,
threadId: input.threadId,
runId: input.runId,
} as any)
observer.complete()
})
}
}
4단계 – OpenAI를 AG-UI로 브리지 (Step 4 – Bridge OpenAI with AG-UI)
스텁을 OpenAI에서 완성 스트리밍하는 진짜 에이전트로 바꿔 봅시다.
OpenAI SDK 설치 (Install the OpenAI SDK)
먼저 OpenAI SDK가 필요합니다:
cd integrations/openai
pnpm install openai
AG-UI 되짚어보기 (AG-UI recap)
AG-UI 에이전트는 AbstractAgent를 확장하고 일련의 이벤트를 내보내서 다음을 알립니다:
- 수명주기 이벤트 (
RUN_STARTED,RUN_FINISHED,RUN_ERROR) - 콘텐츠 이벤트 (
TEXT_MESSAGE_*,TOOL_CALL_*, 등)
스트리밍 에이전트 구현 (Implement the streaming agent)
이제 스텁 에이전트를 진짜 OpenAI 통합으로 바꿉니다. 핵심 차이는 하드코딩된 "Hello world!" 메시지를 보내는 대신 OpenAI의 API에 연결하고 AG-UI 이벤트를 통해 응답을 스트리밍한다는 점입니다.
구현은 스텁과 같은 이벤트 흐름을 따르지만, 생성자에서 OpenAI 클라이언트 초기화를 추가하고 모의 응답을 실제 API 호출로 대체합니다. 또한 응답에 도구 호출이 있다면 처리해, 필요할 때 함수를 완전히 사용할 수 있는 에이전트로 만듭니다.
// integrations/openai/src/index.ts
import {
AbstractAgent,
RunAgentInput,
EventType,
BaseEvent,
} from "@ag-ui/client"
import { Observable } from "rxjs"
import { OpenAI } from "openai"
export class OpenAIAgent extends AbstractAgent {
private openai: OpenAI
constructor(openai?: OpenAI) {
super()
// Initialize OpenAI client - uses OPENAI_API_KEY from environment if not provided
this.openai = openai ?? new OpenAI()
}
run(input: RunAgentInput): Observable<BaseEvent> {
return new Observable<BaseEvent>((observer) => {
// Same as before - emit RUN_STARTED to begin
observer.next({
type: EventType.RUN_STARTED,
threadId: input.threadId,
runId: input.runId,
} as any)
// NEW: Instead of hardcoded response, call OpenAI's API
this.openai.chat.completions
.create({
model: "gpt-4o",
stream: true, // Enable streaming for real-time responses
// Convert AG-UI tools format to OpenAI's expected format
tools: input.tools.map((tool) => ({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.parameters,
},
})),
// Transform AG-UI messages to OpenAI's message format
messages: input.messages.map((message) => ({
role: message.role as any,
content: message.content ?? "",
// Include tool calls if this is an assistant message with tools
...(message.role === "assistant" && message.toolCalls
? {
tool_calls: message.toolCalls,
}
: {}),
// Include tool call ID if this is a tool result message
...(message.role === "tool"
? { tool_call_id: message.toolCallId }
: {}),
})),
})
.then(async (response) => {
const messageId = Date.now().toString()
// NEW: Stream each chunk from OpenAI's response
for await (const chunk of response) {
// Handle text content chunks
if (chunk.choices[0].delta.content) {
observer.next({
type: EventType.TEXT_MESSAGE_CHUNK, // Chunk events open and close messages automatically
messageId,
delta: chunk.choices[0].delta.content,
} as any)
}
// Handle tool call chunks (when the model wants to use a function)
else if (chunk.choices[0].delta.tool_calls) {
let toolCall = chunk.choices[0].delta.tool_calls[0]
observer.next({
type: EventType.TOOL_CALL_CHUNK,
toolCallId: toolCall.id,
toolCallName: toolCall.function?.name,
parentMessageId: messageId,
delta: toolCall.function?.arguments,
} as any)
}
}
// Same as before - emit RUN_FINISHED when complete
observer.next({
type: EventType.RUN_FINISHED,
threadId: input.threadId,
runId: input.runId,
} as any)
observer.complete()
})
// NEW: Handle errors from the API
.catch((error) => {
observer.next({
type: EventType.RUN_ERROR,
message: error.message,
} as any)
observer.error(error)
})
})
}
}
내부에서 무슨 일이 일어나는가? (What happens under the hood?)
여러분의 에이전트가 하는 일을 쪼개 보겠습니다:
- 설정 (Setup) – OpenAI 클라이언트를 만들고
RUN_STARTED를 내보냅니다 - 요청 (Request) – 사용자 메시지를
stream: true와 함께chat.completions로 보냅니다 - 스트리밍 (Streaming) – 각 청크를
TEXT_MESSAGE_CHUNK또는TOOL_CALL_CHUNK로 전달합니다 - 완료 (Finish) –
RUN_FINISHED(또는 문제가 있으면RUN_ERROR)를 내보내고 observable을 완료합니다
5단계 – 에이전트와 채팅 (Step 5 – Chat with your agent)
dojo 페이지를 새로고침하고 타이핑을 시작하세요. GPT-4o가 실시간으로 단어 단위로 답을 스트리밍하는 것을 볼 수 있어요.
AG-UI를 어떤 프로토콜로든 브리지 (Bridging AG-UI to any protocol)
방금 구현한 패턴 — 입력 번역, 스트리밍 청크 전달, AG-UI 이벤트 방출 — 은 사실상 모든 백엔드에 적용됩니다:
- REST 또는 GraphQL API
- WebSockets
- MQTT 같은 IoT 프로토콜
에이전트를 프런트엔드에 연결 (Connect your agent to a frontend)
CopilotKit 같은 도구는 AG-UI를 이미 이해하고 플러그앤플레이 React 컴포넌트를 제공합니다. 여러분의 에이전트 엔드포인트를 가리키면 완전한 기능의 채팅 UI가 즉시 나옵니다.
통합 공유 (Share your integration)
다른 사람이 재사용할 수 있는 커스텀 어댑터를 만들었나요? 커뮤니티 기여를 환영합니다!
- AG-UI 저장소를 포크하세요
integrations아래에 패키지를 추가하세요. 자세한 내용과 명명 규칙은 기여 (Contributing)를 참고하세요.- 사용 사례와 설계 결정을 설명하는 풀 리퀘스트를 여세요
질문이 있거나, 피드백이 필요하거나, 먼저 아이디어를 검증하고 싶다면 GitHub Discussions 게시판에서 스레드를 시작하세요: AG-UI GitHub Discussions 게시판.
여러분의 통합이 다음 릴리스에 실려 전체 AG-UI 생태계 성장에 도움을 줄 수 있어요.
결론 (Conclusion)
이제 OpenAI를 위한 완전한 기능의 AG-UI 어댑터와 그것을 테스트할 로컬 플레이그라운드가 생겼습니다. 여기서부터 여러분은:
- 도구 호출을 추가해 에이전트를 강화할 수 있어요
- 통합을 npm에 게시할 수 있어요
- AG-UI를 다른 어떤 모델이나 서비스로도 브리지할 수 있어요
즐겁게 빌드하세요!
더 알아보기 (Learn more)
- 애플리케이션 구축하기 —
create-ag-ui-appCLI로 빠르게 시작 - 디버깅 (Debugging) — AG-UI Dojo로 구현 검증
- 핵심 아키텍처 — AG-UI 구조 이해