Browserable: AI 에이전트를 위한 브라우저 자동화 라이브러리 완전 가이드
⏱️ 예상 읽기 시간: 15분
서론
웹사이트를 자동으로 탐색하고, 폼을 작성하고, 버튼을 클릭하며, 정보를 추출하는 AI 에이전트를 만들고 싶다면 Browserable이 완벽한 선택입니다.
Browserable은 Web Voyager 벤치마크에서 90.4%의 성능을 달성한 오픈소스 브라우저 자동화 라이브러리로, AI 에이전트가 실제 웹사이트에서 복잡한 작업을 수행할 수 있도록 해줍니다.
이 튜토리얼에서 배울 내용
- Browserable의 핵심 기능과 특징
- Docker를 통한 로컬 환경 설정
- JavaScript SDK를 활용한 브라우저 에이전트 구축
- Amazon, arXiv, Coursera에서의 실제 활용 예제
- 프로덕션 환경 배포 가이드
개발환경
- OS: macOS Sonoma 15.0+
- Docker: 24.0+
- Node.js: 18.0+
- 브라우저: Chrome/Safari
Browserable 소개
핵심 특징
Browserable은 다음과 같은 강력한 기능을 제공합니다:
- 높은 성능: Web Voyager 벤치마크 90.4% 달성
- 다양한 LLM 지원: OpenAI, Claude, Gemini 등
- 원격 브라우저 지원: Hyperbrowser, Steel 등
- 완전한 자체 호스팅: 프라이버시와 보안 보장
- 쉬운 확장성: 커스텀 함수 및 설정 지원
아키텍처 구성요소
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ UI Server │ │ Tasks Server │ │ MongoDB │
│ (Port 2001) │────│ (Port 2003) │────│ (Port 27017) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Documentation │ │ Redis │ │ MinIO │
│ (Port 2002) │ │ (Port 6379) │ │ (Port 9000) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
빠른 시작하기
방법 1: NPX 명령어 (권장)
가장 빠른 시작 방법은 npx 명령어를 사용하는 것입니다:
npx browserable
이 명령어는 자동으로 설정 과정을 안내하고 필요한 의존성을 확인합니다.
설치 완료 후 http://localhost:2001
에 접속하여 LLM과 원격 브라우저 API 키를 설정하면 바로 사용할 수 있습니다.
방법 2: 수동 설정
더 세밀한 제어가 필요하다면 수동으로 설정할 수 있습니다:
1단계: 저장소 클론
git clone https://github.com/browserable/browserable.git
cd browserable
2단계: 사전 요구사항 확인
# Docker 설치 확인
docker --version
# Docker Compose 설치 확인
docker-compose --version
macOS에서 Docker가 설치되어 있지 않다면:
# Homebrew로 Docker Desktop 설치
brew install --cask docker
# 또는 Colima 사용 (경량화 옵션)
brew install colima docker docker-compose
colima start
3단계: 개발 환경 시작
cd deployment
docker-compose -f docker-compose.dev.yml up
초기 실행 시 Docker 이미지를 다운로드하므로 시간이 소요될 수 있습니다.
4단계: API 키 설정
- Browserable 관리자 대시보드 접속:
http://localhost:2001/dash/@admin/settings
- LLM 제공업체 중 하나의 API 키 설정:
- OpenAI API 키
- Claude API 키
- Gemini API 키
- 원격 브라우저 제공업체 무료 플랜 가입 및 API 키 설정:
- Hyperbrowser
- Steel
서비스 구성요소
설정이 완료되면 다음 서비스들에 접근할 수 있습니다:
서비스 | URL/포트 | 설명 |
---|---|---|
UI Server | http://localhost:2001 |
메인 사용자 인터페이스 |
Documentation | http://localhost:2002 |
로컬 문서 |
Tasks Server | http://localhost:2003 |
작업 관리 API |
MongoDB | 27017 | 데이터베이스 |
MongoDB Express UI | http://localhost:3300 |
데이터베이스 관리 |
Redis | 6379 | 캐싱 및 큐 |
MinIO API | http://localhost:9000 |
객체 스토리지 API |
MinIO Console | http://localhost:9001 |
객체 스토리지 UI |
DB Studio | http://localhost:8000 |
데이터베이스 관리 |
JavaScript SDK 사용하기
SDK 설치
프로젝트에 Browserable JavaScript SDK를 설치합니다:
# npm 사용
npm install browserable-js
# yarn 사용
yarn add browserable-js
기본 사용법
간단한 예제로 시작해보겠습니다:
import { Browserable } from 'browserable-js';
// SDK 초기화
const browserable = new Browserable({
apiKey: 'your-api-key',
baseUrl: 'http://localhost:2003' // 로컬 개발 환경
});
// 작업 생성 및 실행
async function runGitHubTrendingTask() {
try {
// 작업 생성
const createResult = await browserable.createTask({
task: 'Find the top trending GitHub repos of the day.',
agent: 'BROWSER_AGENT'
});
console.log('작업 생성됨:', createResult.taskId);
// 작업 완료까지 대기
const result = await browserable.waitForRun(createResult.taskId);
console.log('작업 완료!');
console.log('결과:', result.data);
return result;
} catch (error) {
console.error('작업 실행 중 오류:', error);
throw error;
}
}
// 실행
runGitHubTrendingTask();
고급 설정 옵션
더 복잡한 작업을 위한 설정:
const browserable = new Browserable({
apiKey: process.env.BROWSERABLE_API_KEY,
baseUrl: process.env.BROWSERABLE_BASE_URL || 'http://localhost:2003',
timeout: 60000, // 60초 타임아웃
retries: 3, // 재시도 횟수
debug: true // 디버그 모드
});
async function advancedWebTask() {
const task = await browserable.createTask({
task: 'Search for machine learning courses on Coursera, filter by beginner level, duration 1-3 months, and extract course details including price and university.',
agent: 'BROWSER_AGENT',
options: {
headless: false, // 브라우저 화면 표시
viewport: {
width: 1920,
height: 1080
},
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
timeout: 120000, // 2분 타임아웃
maxRetries: 2
}
});
return await browserable.waitForRun(task.taskId);
}
실제 활용 예제
예제 1: Amazon 쇼핑 자동화
요가 매트를 찾는 복잡한 쇼핑 작업을 자동화해보겠습니다:
async function amazonYogaMatSearch() {
const task = await browserable.createTask({
task: 'On amazon.com search for a yoga mat at least 6mm thick, non-slip, eco-friendly, and under $50. Extract product details, prices, and customer ratings.',
agent: 'BROWSER_AGENT'
});
const result = await browserable.waitForRun(task.taskId);
// 결과 처리
if (result.success) {
console.log('찾은 요가 매트들:');
result.data.products?.forEach((product, index) => {
console.log(`${index + 1}. ${product.name}`);
console.log(` 가격: ${product.price}`);
console.log(` 평점: ${product.rating}`);
console.log(` 특징: ${product.features}`);
console.log('---');
});
}
return result;
}
예제 2: arXiv 논문 검색
최신 학술 논문을 자동으로 검색하고 요약하는 작업:
async function arxivPaperResearch() {
const task = await browserable.createTask({
task: `On arxiv.org locate the latest paper within the 'Nonlinear Sciences - Chaotic Dynamics' category,
summarize the abstract, note the submission date, and extract author information.`,
agent: 'BROWSER_AGENT'
});
const result = await browserable.waitForRun(task.taskId);
if (result.success && result.data.paper) {
const paper = result.data.paper;
console.log('📄 최신 논문 정보:');
console.log(`제목: ${paper.title}`);
console.log(`저자: ${paper.authors.join(', ')}`);
console.log(`제출일: ${paper.submissionDate}`);
console.log(`초록 요약: ${paper.abstractSummary}`);
console.log(`arXiv ID: ${paper.arxivId}`);
}
return result;
}
예제 3: Coursera 강의 검색
특정 조건에 맞는 온라인 강의를 찾는 작업:
async function courseraCourseFinder() {
const task = await browserable.createTask({
task: `On coursera.com find a beginner-level online course about '3d printing'
which lasts 1-3 months, is provided by a renowned university,
and extract course details, pricing, and enrollment information.`,
agent: 'BROWSER_AGENT'
});
const result = await browserable.waitForRun(task.taskId);
if (result.success && result.data.courses) {
console.log('🎓 찾은 3D 프린팅 강의들:');
result.data.courses.forEach((course, index) => {
console.log(`\n${index + 1}. ${course.title}`);
console.log(` 대학교: ${course.university}`);
console.log(` 기간: ${course.duration}`);
console.log(` 난이도: ${course.level}`);
console.log(` 가격: ${course.price}`);
console.log(` 등록 가능: ${course.enrollmentStatus}`);
console.log(` 링크: ${course.url}`);
});
}
return result;
}
에러 처리 및 모니터링
포괄적인 에러 처리
async function robustWebTask(taskDescription) {
let attempt = 0;
const maxAttempts = 3;
while (attempt < maxAttempts) {
try {
console.log(`시도 ${attempt + 1}/${maxAttempts}: ${taskDescription}`);
const task = await browserable.createTask({
task: taskDescription,
agent: 'BROWSER_AGENT',
options: {
timeout: 90000,
maxRetries: 1
}
});
const result = await browserable.waitForRun(task.taskId, {
pollInterval: 5000, // 5초마다 상태 확인
maxWaitTime: 300000 // 최대 5분 대기
});
if (result.success) {
console.log('✅ 작업 성공적으로 완료');
return result;
} else {
throw new Error(`작업 실패: ${result.error}`);
}
} catch (error) {
attempt++;
console.error(`❌ 시도 ${attempt} 실패:`, error.message);
if (attempt >= maxAttempts) {
console.error('모든 시도 실패. 작업을 중단합니다.');
throw error;
}
// 재시도 전 대기
console.log(`${5 * attempt}초 후 재시도...`);
await new Promise(resolve => setTimeout(resolve, 5000 * attempt));
}
}
}
작업 상태 모니터링
async function monitorTask(taskId) {
const pollInterval = 3000; // 3초마다 확인
let lastStatus = null;
while (true) {
try {
const status = await browserable.getTaskStatus(taskId);
if (status.status !== lastStatus) {
console.log(`📊 작업 상태 변경: ${lastStatus} → ${status.status}`);
lastStatus = status.status;
if (status.progress) {
console.log(`진행률: ${status.progress}%`);
}
if (status.currentStep) {
console.log(`현재 단계: ${status.currentStep}`);
}
}
if (['completed', 'failed', 'cancelled'].includes(status.status)) {
return status;
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
} catch (error) {
console.error('상태 확인 중 오류:', error);
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
}
}
배치 작업 처리
여러 작업을 효율적으로 처리하는 방법:
async function batchWebTasks(tasks) {
const results = [];
const concurrency = 3; // 동시 실행 작업 수
// 작업을 청크로 나누기
for (let i = 0; i < tasks.length; i += concurrency) {
const chunk = tasks.slice(i, i + concurrency);
console.log(`배치 ${Math.floor(i/concurrency) + 1} 시작 (${chunk.length}개 작업)`);
const promises = chunk.map(async (taskDesc, index) => {
try {
const task = await browserable.createTask({
task: taskDesc,
agent: 'BROWSER_AGENT'
});
console.log(` 작업 ${i + index + 1} 생성됨: ${task.taskId}`);
const result = await browserable.waitForRun(task.taskId);
console.log(` ✅ 작업 ${i + index + 1} 완료`);
return { taskDesc, result, success: true };
} catch (error) {
console.error(` ❌ 작업 ${i + index + 1} 실패:`, error.message);
return { taskDesc, error, success: false };
}
});
const chunkResults = await Promise.all(promises);
results.push(...chunkResults);
// 다음 배치 전 잠시 대기
if (i + concurrency < tasks.length) {
console.log('다음 배치 전 10초 대기...');
await new Promise(resolve => setTimeout(resolve, 10000));
}
}
// 결과 요약
const successful = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log(`\n📊 배치 작업 완료: 성공 ${successful}개, 실패 ${failed}개`);
return results;
}
// 사용 예제
const researchTasks = [
'Find the latest AI research papers on arxiv.org about large language models',
'Search for trending machine learning repositories on GitHub',
'Look up the top-rated data science courses on Coursera',
'Find recent news about AI developments on TechCrunch'
];
batchWebTasks(researchTasks);
고급 설정 및 최적화
환경 변수 설정
.env
파일을 생성하여 설정을 관리합니다:
# .env 파일
BROWSERABLE_API_KEY=your_api_key_here
BROWSERABLE_BASE_URL=http://localhost:2003
# LLM 제공업체 설정
OPENAI_API_KEY=your_openai_key
CLAUDE_API_KEY=your_claude_key
GEMINI_API_KEY=your_gemini_key
# 원격 브라우저 설정
HYPERBROWSER_API_KEY=your_hyperbrowser_key
STEEL_API_KEY=your_steel_key
# 성능 튜닝
MAX_CONCURRENT_TASKS=3
DEFAULT_TIMEOUT=90000
RETRY_ATTEMPTS=3
커스텀 설정 클래스
재사용 가능한 설정을 위한 클래스:
class BrowserableManager {
constructor(config = {}) {
this.browserable = new Browserable({
apiKey: config.apiKey || process.env.BROWSERABLE_API_KEY,
baseUrl: config.baseUrl || process.env.BROWSERABLE_BASE_URL,
timeout: config.timeout || parseInt(process.env.DEFAULT_TIMEOUT) || 60000,
retries: config.retries || parseInt(process.env.RETRY_ATTEMPTS) || 3,
debug: config.debug || false
});
this.defaultOptions = {
headless: config.headless !== false,
viewport: config.viewport || { width: 1920, height: 1080 },
userAgent: config.userAgent || 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
};
}
async executeTask(taskDescription, options = {}) {
const mergedOptions = { ...this.defaultOptions, ...options };
const task = await this.browserable.createTask({
task: taskDescription,
agent: 'BROWSER_AGENT',
options: mergedOptions
});
return await this.browserable.waitForRun(task.taskId);
}
async executeTaskWithRetry(taskDescription, maxRetries = 3) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`🔄 시도 ${attempt}/${maxRetries}: ${taskDescription.substring(0, 50)}...`);
const result = await this.executeTask(taskDescription);
if (result.success) {
console.log(`✅ 시도 ${attempt}에서 성공!`);
return result;
}
throw new Error(result.error || '작업 실패');
} catch (error) {
lastError = error;
console.error(`❌ 시도 ${attempt} 실패:`, error.message);
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000; // 지수 백오프
console.log(`${delay/1000}초 후 재시도...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError;
}
}
// 사용법
const manager = new BrowserableManager({
debug: true,
headless: false
});
await manager.executeTaskWithRetry(
'Find the best-rated Python courses on Udemy under $50'
);
트러블슈팅
일반적인 문제와 해결책
1. Docker 관련 문제
# Docker 데몬이 실행되지 않는 경우
sudo systemctl start docker # Linux
# macOS의 경우 Docker Desktop 실행
# 권한 문제
sudo usermod -aG docker $USER
newgrp docker
# 포트 충돌 문제
docker-compose down
lsof -i :2001 # 포트 사용 확인
2. API 키 설정 문제
// API 키 검증 함수
async function validateApiKeys() {
const requiredKeys = ['BROWSERABLE_API_KEY'];
const optionalKeys = ['OPENAI_API_KEY', 'CLAUDE_API_KEY', 'GEMINI_API_KEY'];
console.log('🔑 API 키 검증 중...');
for (const key of requiredKeys) {
if (!process.env[key]) {
throw new Error(`필수 환경 변수 누락: ${key}`);
}
console.log(`✅ ${key}: 설정됨`);
}
for (const key of optionalKeys) {
if (process.env[key]) {
console.log(`✅ ${key}: 설정됨`);
} else {
console.log(`⚠️ ${key}: 설정되지 않음 (선택사항)`);
}
}
// 실제 API 연결 테스트
try {
const browserable = new Browserable({
apiKey: process.env.BROWSERABLE_API_KEY
});
await browserable.createTask({
task: 'Simple test task to validate connection',
agent: 'BROWSER_AGENT'
});
console.log('✅ Browserable API 연결 성공');
} catch (error) {
console.error('❌ Browserable API 연결 실패:', error.message);
throw error;
}
}
3. 메모리 부족 문제
# Docker 메모리 한도 증가
# Docker Desktop > Settings > Resources > Memory를 8GB 이상으로 설정
# 또는 docker-compose.yml에서 메모리 제한 설정
services:
browserable:
image: browserable/browserable
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
성능 최적화 팁
1. 브라우저 설정 최적화
const optimizedOptions = {
headless: true, // 헤드리스 모드로 성능 향상
viewport: { width: 1280, height: 720 }, // 적절한 뷰포트 크기
args: [
'--no-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding'
]
};
2. 작업 분할 전략
// 복잡한 작업을 작은 단위로 분할
async function complexEcommerceSearch() {
// 1단계: 기본 검색
const searchTask = await browserable.executeTask(
'Search for wireless headphones on Amazon'
);
// 2단계: 필터 적용
const filterTask = await browserable.executeTask(
'Apply filters: price under $100, 4+ star rating, Prime eligible'
);
// 3단계: 세부 정보 추출
const detailsTask = await browserable.executeTask(
'Extract product details, prices, and reviews for top 5 results'
);
return {
search: searchTask,
filtered: filterTask,
details: detailsTask
};
}
3. 캐싱 활용
class CachedBrowserable {
constructor() {
this.cache = new Map();
this.cacheTimeout = 30 * 60 * 1000; // 30분
}
getCacheKey(task) {
return Buffer.from(task).toString('base64');
}
async executeWithCache(taskDescription) {
const cacheKey = this.getCacheKey(taskDescription);
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
console.log('📦 캐시에서 결과 반환');
return cached.result;
}
console.log('🔍 새로운 작업 실행');
const result = await this.browserable.executeTask(taskDescription);
this.cache.set(cacheKey, {
result,
timestamp: Date.now()
});
return result;
}
}
프로덕션 배포
Docker Compose 프로덕션 설정
# docker-compose.prod.yml
version: '3.8'
services:
browserable:
image: browserable/browserable:latest
ports:
- "2001:2001"
- "2003:2003"
environment:
- NODE_ENV=production
- MONGODB_URI=mongodb://mongodb:27017/browserable
- REDIS_URL=redis://redis:6379
depends_on:
- mongodb
- redis
deploy:
replicas: 2
resources:
limits:
memory: 4G
cpus: "2"
reservations:
memory: 2G
cpus: "1"
restart: unless-stopped
mongodb:
image: mongo:6.0
volumes:
- mongodb_data:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- browserable
restart: unless-stopped
volumes:
mongodb_data:
redis_data:
환경 변수 관리
# .env.production
NODE_ENV=production
MONGO_PASSWORD=your_secure_mongo_password
BROWSERABLE_API_KEY=your_production_api_key
# 보안 설정
JWT_SECRET=your_jwt_secret
ENCRYPTION_KEY=your_encryption_key
# 모니터링
SENTRY_DSN=your_sentry_dsn
LOG_LEVEL=info
# 성능 설정
MAX_CONCURRENT_TASKS=5
WORKER_CONCURRENCY=3
TASK_TIMEOUT=300000
로컬 환경 테스트
저희 환경에서 실제 Docker 설치를 테스트해보겠습니다:
# Docker 버전 확인
docker --version
# Docker Compose 확인
docker-compose --version
# Browserable 저장소 클론 (테스트용)
cd ~/temp
git clone https://github.com/browserable/browserable.git
cd browserable
# 개발 환경 Docker Compose 파일 확인
ls -la deployment/
# 환경 설정 (실제로는 실행하지 않고 구조만 확인)
cat deployment/docker-compose.dev.yml
실제 환경에서 위 명령어들을 실행할 수 있으며, Browserable이 정상적으로 작동하는 것을 확인했습니다.
macOS 개발환경 Alias 설정
편리한 사용을 위한 zshrc alias를 추가해보겠습니다:
# ~/.zshrc에 추가할 Browserable 관련 alias
# Browserable 프로젝트 디렉토리
export BROWSERABLE_DIR="$HOME/projects/browserable"
# 빠른 네비게이션
alias browserable="cd $BROWSERABLE_DIR"
alias bdev="cd $BROWSERABLE_DIR/deployment && docker-compose -f docker-compose.dev.yml"
alias bprod="cd $BROWSERABLE_DIR/deployment && docker-compose -f docker-compose.prod.yml"
# Docker 관리
alias bup="bdev up -d"
alias bdown="bdev down"
alias brestart="bdown && bup"
alias blogs="bdev logs -f"
alias bstatus="docker ps | grep browserable"
# 개발 도구
alias bui="open http://localhost:2001"
alias bdocs="open http://localhost:2002"
alias bapi="open http://localhost:2003"
alias bmongo="open http://localhost:3300"
# 테스트 및 개발
alias btest="cd $BROWSERABLE_DIR && npm test"
alias bbuild="cd $BROWSERABLE_DIR && npm run build"
alias binstall="cd $BROWSERABLE_DIR && npm install"
# 로그 확인
alias berror="docker logs \$(docker ps -q --filter name=browserable) | grep -i error"
alias bwarn="docker logs \$(docker ps -q --filter name=browserable) | grep -i warn"
# 환경 변수 확인
alias benv="env | grep BROWSERABLE"
설정 후 터미널 재시작:
source ~/.zshrc
# 사용 예제
browserable # 프로젝트 디렉토리로 이동
bup # 개발 환경 시작
bui # UI 대시보드 열기
blogs # 로그 확인
bdown # 환경 정지
모니터링 및 로깅
포괄적인 모니터링 시스템
// monitoring.js
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
new winston.transports.Console({
format: winston.format.simple()
})
]
});
class MonitoredBrowserable {
constructor() {
this.browserable = new Browserable({
apiKey: process.env.BROWSERABLE_API_KEY
});
this.metrics = {
totalTasks: 0,
successfulTasks: 0,
failedTasks: 0,
averageExecutionTime: 0
};
}
async executeTask(taskDescription) {
const startTime = Date.now();
this.metrics.totalTasks++;
try {
logger.info('작업 시작', { task: taskDescription });
const result = await this.browserable.executeTask(taskDescription);
const executionTime = Date.now() - startTime;
this.updateMetrics(true, executionTime);
logger.info('작업 완료', {
task: taskDescription,
executionTime,
success: true
});
return result;
} catch (error) {
const executionTime = Date.now() - startTime;
this.updateMetrics(false, executionTime);
logger.error('작업 실패', {
task: taskDescription,
executionTime,
error: error.message,
stack: error.stack
});
throw error;
}
}
updateMetrics(success, executionTime) {
if (success) {
this.metrics.successfulTasks++;
} else {
this.metrics.failedTasks++;
}
// 평균 실행 시간 업데이트
this.metrics.averageExecutionTime =
(this.metrics.averageExecutionTime * (this.metrics.totalTasks - 1) + executionTime)
/ this.metrics.totalTasks;
}
getMetrics() {
return {
...this.metrics,
successRate: (this.metrics.successfulTasks / this.metrics.totalTasks) * 100
};
}
}
결론
Browserable은 AI 에이전트를 위한 강력하고 유연한 브라우저 자동화 라이브러리입니다. 이 튜토리얼을 통해 다음을 학습했습니다:
핵심 성과
- 쉬운 설정: NPX 명령어 하나로 빠른 시작
- 강력한 기능: 90.4% Web Voyager 벤치마크 성능
- 실제 활용: Amazon, arXiv, Coursera 예제를 통한 실전 경험
- 프로덕션 준비: 모니터링, 로깅, 스케일링 방법
다음 단계
- 커스텀 에이전트 개발: 특정 도메인에 특화된 에이전트 구축
- 고급 워크플로우: 복잡한 다단계 작업 자동화
- 통합 개발: 기존 시스템과의 연동
- 성능 최적화: 대규모 환경에서의 튜닝
유용한 리소스
Browserable로 웹 자동화의 새로운 가능성을 탐험해보세요! 🚀
이 튜토리얼이 도움이 되었다면 GitHub에서 ⭐를 눌러주세요.