목차
- A2A JS SDK란?
- A2A JS 설치 및 설정
- A2A JS 핵심 개념
- 첫 번째 A2A JS 에이전트 만들기
- A2A JS 서버 개발
- A2A JS 클라이언트 사용
- A2A JS 고급 기능
- A2A JS 모범 사례
- A2A JS 문제 해결
A2A JS SDK란?
A2A JS SDK는 Agent2Agent (A2A) 프로토콜을 준수하는 지능형 에이전트 애플리케이션을 구축하기 위해 JavaScript/TypeScript 개발자를 위해 특별히 설계된 강력한 라이브러리입니다. 이 A2A JS 프레임워크를 통해 개발자는 서로 통신하고 협업할 수 있는 지능형 에이전트 시스템을 쉽게 만들 수 있습니다.
A2A JS의 주요 장점
- 🚀 사용하기 쉬움: A2A JS는 개발자가 빠르게 시작할 수 있는 직관적인 API를 제공합니다
- 🔄 실시간 통신: 스트리밍 처리 및 Server-Sent Events (SSE) 지원
- 🛡️ 타입 안전성: TypeScript 기반으로 구축되어 완전한 타입 지원 제공
- 🌐 크로스 플랫폼: A2A JS는 Node.js와 브라우저 환경 모두에서 실행 가능
- 📡 표준 프로토콜: A2A 프로토콜 사양을 완전히 구현
A2A JS 설치 및 설정
A2A JS SDK 설치
npm을 사용하여 A2A JS SDK를 설치합니다:
npm install @a2a-js/sdk
또는 yarn을 사용합니다:
yarn add @a2a-js/sdk
A2A JS 설치 확인
A2A JS가 올바르게 설치되었는지 확인하기 위한 간단한 테스트 파일을 만듭니다:
import { A2AClient, AgentCard } from "@a2a-js/sdk";
console.log("A2A JS SDK가 성공적으로 설치되었습니다!");
A2A JS 핵심 개념
A2A JS를 사용하기 전에 다음 핵심 개념을 이해하는 것이 중요합니다:
1. 에이전트 카드
A2A JS의 각 에이전트는 에이전트의 기능과 인터페이스를 설명하는 에이전트 카드가 필요합니다:
import { AgentCard } from "@a2a-js/sdk";
const agentCard: AgentCard = {
name: '내 A2A JS 에이전트',
description: 'A2A JS SDK로 구축된 지능형 에이전트',
url: 'http://localhost:3000/',
provider: {
organization: 'A2A JS 개발자',
url: 'https://example.com'
},
version: '1.0.0',
capabilities: {
streaming: true,
pushNotifications: false,
stateTransitionHistory: true,
},
skills: [{
id: 'general_chat',
name: '일반 채팅',
description: 'A2A JS를 사용한 일반 대화',
tags: ['chat', 'a2a-js'],
examples: ['안녕하세요', '질문에 답변하는 것을 도와주세요']
}]
};
2. 에이전트 실행기
A2A JS의 핵심 실행 로직은 AgentExecutor를 통해 구현됩니다:
import { AgentExecutor, RequestContext, IExecutionEventBus } from "@a2a-js/sdk";
class MyA2AJSExecutor implements AgentExecutor {
async execute(
requestContext: RequestContext,
eventBus: IExecutionEventBus
): Promise<void> {
// A2A JS 에이전트 로직
console.log("A2A JS 에이전트가 요청을 처리 중입니다...");
}
async cancelTask(taskId: string, eventBus: IExecutionEventBus): Promise<void> {
console.log(`A2A JS 작업 취소 중: ${taskId}`);
}
}
첫 번째 A2A JS 에이전트 만들기
A2A JS SDK를 사용하여 완전한 에이전트 예제를 만들어 보겠습니다:
1단계: A2A JS 에이전트 카드 정의
import { AgentCard } from "@a2a-js/sdk";
const myAgentCard: AgentCard = {
name: 'Hello World A2A JS 에이전트',
description: 'A2A JS SDK를 배우기 위한 내 첫 번째 A2A JS 에이전트',
url: 'http://localhost:3000/',
provider: {
organization: 'A2A JS 튜토리얼',
url: 'https://example.com'
},
version: '1.0.0',
capabilities: {
streaming: true,
pushNotifications: false,
stateTransitionHistory: true,
},
defaultInputModes: ['text/plain'],
defaultOutputModes: ['text/plain'],
skills: [{
id: 'hello_world',
name: 'Hello World',
description: 'A2A JS 예제 스킬: 인사에 응답하기',
tags: ['hello', 'greeting', 'a2a-js'],
examples: [
'안녕하세요',
'반갑습니다',
'A2A JS에 대해 알려주세요'
],
inputModes: ['text/plain'],
outputModes: ['text/plain']
}],
supportsAuthenticatedExtendedCard: false,
};
2단계: A2A JS 실행기 구현
import {
AgentExecutor,
RequestContext,
IExecutionEventBus,
Task,
TaskState,
TaskStatusUpdateEvent
} from "@a2a-js/sdk";
import { v4 as uuidv4 } from "uuid";
class HelloWorldA2AJSExecutor implements AgentExecutor {
private cancelledTasks = new Set<string>();
async cancelTask(taskId: string, eventBus: IExecutionEventBus): Promise<void> {
this.cancelledTasks.add(taskId);
console.log(`A2A JS 실행기가 작업을 취소합니다: ${taskId}`);
}
async execute(
requestContext: RequestContext,
eventBus: IExecutionEventBus
): Promise<void> {
const userMessage = requestContext.userMessage;
const existingTask = requestContext.task;
const taskId = existingTask?.id || uuidv4();
const contextId = userMessage.contextId || existingTask?.contextId || uuidv4();
console.log(`A2A JS 에이전트가 메시지를 처리 중입니다: ${userMessage.parts[0]?.text}`);
// 새 작업 생성
if (!existingTask) {
const initialTask: Task = {
kind: 'task',
id: taskId,
contextId: contextId,
status: {
state: TaskState.Submitted,
timestamp: new Date().toISOString(),
},
history: [userMessage],
metadata: userMessage.metadata,
artifacts: [],
};
eventBus.publish(initialTask);
}
// 작업 상태 발행
const workingUpdate: TaskStatusUpdateEvent = {
kind: 'status-update',
taskId: taskId,
contextId: contextId,
status: {
state: TaskState.Working,
message: {
kind: 'message',
role: 'agent',
messageId: uuidv4(),
parts: [{ kind: 'text', text: 'A2A JS 에이전트가 생각 중입니다...' }],
taskId: taskId,
contextId: contextId,
},
timestamp: new Date().toISOString(),
},
final: false,
};
eventBus.publish(workingUpdate);
// 처리 시간 시뮬레이션
await new Promise(resolve => setTimeout(resolve, 1000));
// 취소 상태 확인
if (this.cancelledTasks.has(taskId)) {
const cancelledUpdate: TaskStatusUpdateEvent = {
kind: 'status-update',
taskId: taskId,
contextId: contextId,
status: {
state: TaskState.Canceled,
timestamp: new Date().toISOString(),
},
final: true,
};
eventBus.publish(cancelledUpdate);
return;
}
// 응답 생성
const userText = userMessage.parts[0]?.text || '';
let responseText = '';
if (userText.toLowerCase().includes('hello') || userText.toLowerCase().includes('hi')) {
responseText = `안녕하세요! A2A JS SDK에 오신 것을 환영합니다! 저는 A2A JS로 구축된 지능형 에이전트입니다.`;
} else if (userText.toLowerCase().includes('a2a js')) {
responseText = `A2A JS SDK는 지능형 에이전트 애플리케이션을 구축하기 위한 강력한 JavaScript 라이브러리입니다!`;
} else {
responseText = `저는 A2A JS 에이전트이며 귀하의 메시지를 받았습니다: "${userText}". A2A JS SDK를 사용해 주셔서 감사합니다!`;
}
// 최종 결과 발행
const finalUpdate: TaskStatusUpdateEvent = {
kind: 'status-update',
taskId: taskId,
contextId: contextId,
status: {
state: TaskState.Completed,
message: {
kind: 'message',
role: 'agent',
messageId: uuidv4(),
parts: [{ kind: 'text', text: responseText }],
taskId: taskId,
contextId: contextId,
},
timestamp: new Date().toISOString(),
},
final: true,
};
eventBus.publish(finalUpdate);
}
}
3단계: A2A JS 서버 시작
import express from 'express';
import {
A2AExpressApp,
DefaultRequestHandler,
InMemoryTaskStore
} from "@a2a-js/sdk";
const taskStore = new InMemoryTaskStore();
const agentExecutor = new HelloWorldA2AJSExecutor();
const requestHandler = new DefaultRequestHandler(
myAgentCard,
taskStore,
agentExecutor
);
const appBuilder = new A2AExpressApp(requestHandler);
const expressApp = appBuilder.setupRoutes(express(), '');
const PORT = process.env.PORT || 3000;
expressApp.listen(PORT, () => {
console.log(`A2A JS 에이전트 서버가 http://localhost:${PORT}에서 시작되었습니다`);
console.log(`A2A JS 에이전트 카드: http://localhost:${PORT}/.well-known/agent.json`);
console.log('A2A JS 서버를 중지하려면 Ctrl+C를 누르세요');
});
A2A JS 서버 개발
작업 저장소
A2A JS는 메모리 내 작업 저장소를 제공하며, 사용자 정의 저장소도 구현할 수 있습니다:
import { TaskStore, Task } from "@a2a-js/sdk";
class CustomA2AJSTaskStore implements TaskStore {
private tasks = new Map<string, Task>();
async getTask(taskId: string): Promise<Task | undefined> {
console.log(`A2A JS 작업 가져오기: ${taskId}`);
return this.tasks.get(taskId);
}
async setTask(task: Task): Promise<void> {
console.log(`A2A JS 작업 저장: ${task.id}`);
this.tasks.set(task.id, task);
}
async deleteTask(taskId: string): Promise<void> {
console.log(`A2A JS 작업 삭제: ${taskId}`);
this.tasks.delete(taskId);
}
}
미들웨어 지원
A2A JS는 Express.js를 기반으로 하며 모든 표준 미들웨어를 지원합니다:
import cors from 'cors';
import express from 'express';
const app = express();
// A2A JS 서버 미들웨어 구성
app.use(cors());
app.use(express.json());
// 사용자 정의 A2A JS 로깅 미들웨어
app.use((req, res, next) => {
console.log(`A2A JS 요청: ${req.method} ${req.path}`);
next();
});
A2A JS 클라이언트 사용
기본 클라이언트 작업
import { A2AClient, MessageSendParams } from "@a2a-js/sdk";
import { v4 as uuidv4 } from "uuid";
const client = new A2AClient("http://localhost:3000");
async function testA2AJSClient() {
console.log("A2A JS 클라이언트 테스트 중...");
const messageParams: MessageSendParams = {
message: {
messageId: uuidv4(),
role: "user",
parts: [{ kind: "text", text: "안녕하세요, A2A JS!" }],
kind: "message"
},
configuration: {
blocking: true,
acceptedOutputModes: ['text/plain']
}
};
try {
const response = await client.sendMessage(messageParams);
if (response.error) {
console.error("A2A JS 클라이언트 오류:", response.error);
return;
}
console.log("A2A JS 응답:", response.result);
} catch (error) {
console.error("A2A JS 통신 오류:", error);
}
}
testA2AJSClient();
A2A JS 스트리밍
A2A JS는 실시간 스트리밍 통신을 지원합니다:
import { A2AClient, TaskStatusUpdateEvent } from "@a2a-js/sdk";
async function streamA2AJSResponse() {
const client = new A2AClient("http://localhost:3000");
console.log("A2A JS 스트리밍 시작...");
const streamParams = {
message: {
messageId: uuidv4(),
role: "user",
parts: [{ kind: "text", text: "A2A JS를 사용한 스트리밍 대화" }],
kind: "message"
}
};
try {
const stream = client.sendMessageStream(streamParams);
for await (const event of stream) {
if (event.kind === 'task') {
console.log(`A2A JS 작업 생성됨: ${event.id}`);
} else if (event.kind === 'status-update') {
const statusEvent = event as TaskStatusUpdateEvent;
console.log(`A2A JS 상태 업데이트: ${statusEvent.status.state}`);
if (statusEvent.status.message?.parts[0]?.text) {
console.log(`A2A JS 메시지: ${statusEvent.status.message.parts[0].text}`);
}
if (statusEvent.final) {
console.log("A2A JS 스트리밍 완료");
break;
}
}
}
} catch (error) {
console.error("A2A JS 스트리밍 오류:", error);
}
}
A2A JS 고급 기능
아티팩트 처리
A2A JS는 아티팩트 생성 및 관리를 지원합니다:
import { TaskArtifactUpdateEvent } from "@a2a-js/sdk";
// AgentExecutor에서 아티팩트 발행
const artifactUpdate: TaskArtifactUpdateEvent = {
kind: 'artifact-update',
taskId: taskId,
contextId: contextId,
artifact: {
artifactId: "a2a-js-example",
name: "A2A JS 예제 파일",
parts: [{
text: `# A2A JS로 생성된 콘텐츠\n\n이것은 A2A JS SDK를 사용하여 생성된 예제 파일입니다.`
}],
},
append: false,
lastChunk: true,
};
eventBus.publish(artifactUpdate);
보안 구성
A2A JS 에이전트를 위한 보안 옵션 구성:
const secureAgentCard: AgentCard = {
name: '보안 A2A JS 에이전트',
description: '보안 A2A JS 에이전트',
// ... 기타 구성
securitySchemes: {
apiKey: {
type: 'apiKey',
name: 'X-API-Key',
in: 'header'
}
},
security: [{
apiKey: []
}]
};
A2A JS 모범 사례
1. 오류 처리
A2A JS 애플리케이션에서 포괄적인 오류 처리 구현:
class RobustA2AJSExecutor implements AgentExecutor {
async execute(requestContext: RequestContext, eventBus: IExecutionEventBus) {
try {
// A2A JS 실행 로직
await this.processRequest(requestContext, eventBus);
} catch (error) {
console.error("A2A JS 실행 오류:", error);
// 오류 상태 발행
const errorUpdate: TaskStatusUpdateEvent = {
kind: 'status-update',
taskId: requestContext.task?.id || uuidv4(),
contextId: requestContext.userMessage.contextId || uuidv4(),
status: {
state: TaskState.Failed,
message: {
kind: 'message',
role: 'agent',
messageId: uuidv4(),
parts: [{ kind: 'text', text: 'A2A JS 처리 중 오류가 발생했습니다. 나중에 다시 시도해 주세요.' }],
},
timestamp: new Date().toISOString(),
},
final: true,
};
eventBus.publish(errorUpdate);
}
}
}
2. 성능 최적화
A2A JS 애플리케이션 성능 최적화:
// 연결 풀링으로 A2A JS 클라이언트 최적화
const client = new A2AClient("http://localhost:3000", {
keepAlive: true,
timeout: 30000
});
// A2A JS 에이전트 응답 캐싱
class CachedA2AJSExecutor implements AgentExecutor {
private cache = new Map<string, string>();
async execute(requestContext: RequestContext, eventBus: IExecutionEventBus) {
const userText = requestContext.userMessage.parts[0]?.text || '';
const cacheKey = `a2a-js-${userText}`;
// A2A JS 캐시 확인
if (this.cache.has(cacheKey)) {
console.log("A2A JS 캐시된 응답 사용 중");
// 캐시된 응답 반환
}
// 새 요청 처리 및 결과 캐싱
}
}
3. 로깅
A2A JS 애플리케이션에 상세 로깅 추가:
import { createLogger, format, transports } from 'winston';
const a2aJSLogger = createLogger({
level: 'info',
format: format.combine(
format.timestamp(),
format.printf(({ timestamp, level, message }) => {
return `[A2A JS] ${timestamp} ${level}: ${message}`;
})
),
transports: [
new transports.Console(),
new transports.File({ filename: 'a2a-js.log' })
]
});
// A2A JS 코드에서 사용
a2aJSLogger.info('A2A JS 에이전트가 성공적으로 시작되었습니다');
a2aJSLogger.error('A2A JS 처리 오류', { error: errorDetails });
A2A JS 문제 해결
일반적인 문제 해결
1. A2A JS 연결 문제
// A2A JS 서버 연결 확인
async function checkA2AJSConnection() {
try {
const client = new A2AClient("http://localhost:3000");
const response = await fetch("http://localhost:3000/.well-known/agent.json");
if (response.ok) {
console.log("A2A JS 서버 연결 정상");
} else {
console.error("A2A JS 서버 응답 이상:", response.status);
}
} catch (error) {
console.error("A2A JS 연결 실패:", error);
}
}
다음 방법도 시도해 볼 수 있습니다:
2. A2A JS 타입 오류
A2A JS 타입을 올바르게 가져오는지 확인:
// 올바른 A2A JS 타입 가져오기
import {
AgentCard,
AgentExecutor,
A2AClient,
Task,
TaskState,
Message,
MessageSendParams
} from "@a2a-js/sdk";
3. A2A JS 성능 디버깅
// A2A JS 성능 모니터링
class PerformanceA2AJSExecutor implements AgentExecutor {
async execute(requestContext: RequestContext, eventBus: IExecutionEventBus) {
const startTime = Date.now();
console.log(`A2A JS 처리 시작: ${startTime}`);
try {
// A2A JS 로직
await this.processRequest(requestContext, eventBus);
} finally {
const endTime = Date.now();
console.log(`A2A JS 처리 완료, 소요 시간: ${endTime - startTime}ms`);
}
}
}
요약
A2A JS SDK는 지능형 에이전트 애플리케이션을 구축하기 위한 강력한 도구입니다. 이 튜토리얼을 통해 다음을 배웠습니다:
- A2A JS의 핵심 개념과 아키텍처
- A2A JS 에이전트 생성 및 구성 방법
- A2A JS 서버 및 클라이언트 개발
- A2A JS의 고급 기능과 모범 사례
- A2A JS 애플리케이션 문제 해결 방법
이제 자체 A2A JS 애플리케이션을 구축할 수 있습니다! A2A JS SDK는 강력하고 확장 가능한 지능형 에이전트 시스템을 구축하는 데 도움이 되는 풍부한 기능을 제공합니다.
더 많은 A2A JS 리소스와 예제는 다음을 방문하세요:
A2A JS 개발 여정을 시작하세요! 🚀