Claude 차트 생성 API 연동 방법: JSON 스키마 고정으로 안정적 구현
Claude 차트 생성 API 연동 방법의 핵심은 JSON 스키마를 미리 고정하고 응답 형식을 일관되게 유지하는 데 있습니다. 기존 대시보드에서 차트가 깨지거나 렌더링이 실패하는 문제도 대부분 응답 데이터 구조의 불일치에서 발생합니다.
이 글에서는 Claude API로 차트 데이터를 안정적으로 생성하고, 기존 프론트엔드에 통합하는 구현 방법을 정리합니다.
준비물
- Anthropic API 키 (Claude 4.5 Sonnet 이상 권장)
- 기존 차트 라이브러리 (Chart.js, D3.js, Recharts 등)
- Node.js 18+ 또는 Python 3.8+ 백엔드 환경
- JSON 스키마 검증 라이브러리 (Joi, Zod, Ajv 등)
1단계: 차트 데이터 JSON 스키마 설계 (Claude 차트 생성 API 연동 방법)
안정적인 Claude API 연동을 위해서는 먼저 차트 데이터의 표준 형식을 정의해야 합니다. 프론트엔드에서 예상하는 데이터 구조와 Claude가 생성하는 응답 구조를 일치시키는 게 핵심이죠.
다음은 범용적으로 사용할 수 있는 차트 데이터 스키마 예시입니다:
{
"chartType": "line" | "bar" | "pie" | "area",
"title": "차트 제목",
"data": {
"labels": ["Jan", "Feb", "Mar"],
"datasets": [
{
"label": "데이터셋명",
"data": [10, 20, 30],
"backgroundColor": "#3b82f6"
}
]
},
"options": {
"responsive": true,
"scales": {
"y": {
"beginAtZero": true
}
}
}
}
이 스키마는 Chart.js 형식을 기준으로 했지만, 다른 차트 라이브러리에 맞게 조정할 수 있습니다. 중요한 점은 chartType, data.labels, data.datasets 필드는 반드시 포함 해야 한다는 것입니다.
2단계: Claude 프롬프트 템플릿 작성
Claude에게 정확한 형식으로 차트 데이터를 생성하도록 지시하는 프롬프트가 필요합니다. 자유형 텍스트 응답보다 구조화된 JSON을 요청하는 편이 훨씬 안정적입니다.
const CHART_PROMPT_TEMPLATE = `
사용자 요청: {user_request}
위 요청을 바탕으로 차트 데이터를 생성해주세요.
반드시 아래 JSON 형식으로만 응답하세요:
{
"chartType": "line|bar|pie|area 중 하나",
"title": "차트 제목",
"data": {
"labels": ["라벨 배열"],
"datasets": [
{
"label": "데이터셋명",
"data": [숫자 배열],
"backgroundColor": "색상코드"
}
]
},
"options": {
"responsive": true,
"scales": {
"y": { "beginAtZero": true }
}
}
}
추가 설명이나 다른 텍스트 없이 JSON만 응답하세요.
`;
프롬프트 끝에 "JSON만 응답하세요" 라는 명시적 지시를 넣는 것이 중요합니다. 이렇게 하면 Claude가 부가 설명을 추가하지 않고 파싱 가능한 JSON만 반환할 가능성이 높아집니다.
주의: 프롬프트에서 예시 JSON 구조를 정확히 명시해야 합니다. "차트를 만들어줘"처럼 모호한 요청은 일관성 없는 응답을 만들기 쉽습니다.
3단계: API 호출 및 응답 검증 로직
Claude API에서 받은 응답을 바로 프론트엔드로 전달하지 말고, 중간에 검증 단계를 거치는 편이 안전합니다. 스키마에 맞지 않는 응답은 기본값으로 대체하거나 재요청하는 로직으로 처리하면 됩니다.
// Node.js + Zod 예시
import { z } from 'zod';
import Anthropic from '@anthropic-ai/sdk';
const ChartSchema = z.object({
chartType: z.enum(['line', 'bar', 'pie', 'area']),
title: z.string(),
data: z.object({
labels: z.array(z.string()),
datasets: z.array(z.object({
label: z.string(),
data: z.array(z.number()),
backgroundColor: z.string()
}))
}),
options: z.object({
responsive: z.boolean(),
scales: z.object({
y: z.object({
beginAtZero: z.boolean()
})
})
})
});
async function generateChart(userRequest) {
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
const prompt = CHART_PROMPT_TEMPLATE.replace('{user_request}', userRequest);
try {
const response = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 2026,
messages: [{ role: 'user', content: prompt }]
});
const jsonText = response.content[0].text;
const parsedData = JSON.parse(jsonText);
// 스키마 검증
const validatedChart = ChartSchema.parse(parsedData);
return validatedChart;
} catch (error) {
console.error('차트 생성 실패:', error);
return getDefaultChart(); // 기본 차트 반환
}
}
검증 로직에서 가장 중요한 부분은 에러 발생 시 기본값을 제공하는 것 입니다. API 응답이 실패하거나 형식이 맞지 않아도 프론트엔드가 깨지지 않게 보장해야 하거든요.
4단계: 프론트엔드 통합 및 렌더링
검증된 차트 데이터를 기존 대시보드에 통합할 때는 차트 라이브러리의 업데이트 메서드를 활용합니다. 새로운 차트를 생성하기보다 기존 차트 인스턴스를 업데이트하는 방식이 성능상 유리한 편입니다.
// React + Chart.js 예시
import { useRef, useCallback } from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
Title,
Tooltip,
Legend
);
function DashboardChart({ initialData }) {
const chartRef = useRef(null);
const updateChartWithAI = useCallback(async (prompt) => {
try {
const response = await fetch('/api/generate-chart', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt })
});
const chartData = await response.json();
if (chartRef.current) {
const chart = chartRef.current;
// 차트 타입이 바뀌면 새로 생성
if (chart.config.type !== chartData.chartType) {
chart.destroy();
createNewChart(chartData);
} else {
// 데이터만 업데이트
chart.data = chartData.data;
chart.options = { ...chart.options, ...chartData.options };
chart.update('active');
}
}
} catch (error) {
console.error('AI 차트 업데이트 실패:', error);
// 기본 차트 유지 또는 에러 메시지 표시
}
}, []);
return (
);
}
프론트엔드에서는 차트 타입 변경과 데이터 업데이트를 구분 해서 처리해야 합니다. 같은 타입은 업데이트하고, 타입이 바뀌면 새로 생성하는 방식이 효율적입니다.
5단계: 에러 처리 및 폴백 전략
실무에서는 Claude API 응답이 항상 완벽하지 않을 수 있습니다. 네트워크 오류, API 한계 초과, 잘못된 JSON 형식 등 다양한 실패 시나리오를 전제로 한 전략이 필요합니다.
function getDefaultChart() {
return {
chartType: 'bar',
title: '데이터 로드 중...',
data: {
labels: ['데이터 없음'],
datasets: [{
label: '기본값',
data: [0],
backgroundColor: '#e5e7eb'
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
};
}
// JSON 추출 유틸리티
function extractJSON(text) {
const jsonMatch = text.match(/\{[\s\S]*\}/);
return jsonMatch ? jsonMatch[0] : null;
}
// 부분 검증 및 보완
function sanitizeChartData(data) {
const defaults = getDefaultChart();
return {
chartType: ['line', 'bar', 'pie', 'area'].includes(data.chartType) ? data.chartType : defaults.chartType,
title: data.title || defaults.title,
data: {
labels: Array.isArray(data.data?.labels) ? data.data.labels : defaults.data.labels,
datasets: Array.isArray(data.data?.datasets) ? data.data.datasets : defaults.data.datasets
},
options: { ...defaults.options, ...data.options }
};
}
에러 처리에서 가장 중요한 원칙은 절대 빈 화면을 보여주지 않는 것 입니다. 완벽한 차트를 만들 수 없더라도 최소한의 시각적 피드백은 제공해야 합니다.
자주 묻는 질문
Q. Claude API 호출 시 응답 속도가 너무 느린데 어떻게 개선할 수 있나요?
max_tokens를 1000~1500 정도로 제한하고, 프롬프트에서 "간단한 차트"라고 명시하면 응답 시간을 단축하는 데 도움이 됩니다. 자주 요청되는 차트 패턴은 Redis 같은 캐시에 저장해 재사용하면 효과를 볼 수 있습니다.
Q. 차트 색상이 매번 달라지는데 일관성을 유지하려면?
프롬프트에 고정 색상 팔레트를 명시하거나, 백엔드에서 응답받은 후 색상만 별도로 치환하는 방법이 있습니다. 브랜드 컬러가 중요한 경우에는 후자가 더 안정적인 선택입니다.
Q. 복잡한 데이터를 Claude가 제대로 이해하지 못할 때는?
원본 데이터를 Claude에게 직접 전달하기보다는, 미리 전처리해서 핵심 정보만 요약해 보내는 편이 효과적입니다. 예를 들어 100개 데이터 포인트가 있다면 주요 10개만 추려 전달하고, 나머지는 백엔드에서 보간하는 방식을 사용할 수 있습니다.