A2A Protocol

A2A JS SDK 완전 가이드: 빠른 시작 가이드

MILO
Share
A2A JS SDK 완전 가이드: 빠른 시작 가이드

목차

  1. A2A JS SDK란?
  2. A2A JS 설치 및 설정
  3. A2A JS 핵심 개념
  4. 첫 번째 A2A JS 에이전트 만들기
  5. A2A JS 서버 개발
  6. A2A JS 클라이언트 사용
  7. A2A JS 고급 기능
  8. A2A JS 모범 사례
  9. A2A JS 문제 해결

A2A JS SDK란?

A2A JS SDKAgent2Agent (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 개발 여정을 시작하세요! 🚀