블로그 목록
ai

Claude Vision으로 이미지 읽히기 — 스크린샷·차트·영수증을 텍스트로 뽑기

사용자가 올린 영수증 사진에서 금액과 항목을 뽑아내야 하는 일이 있었다. OCR 라이브러리를 붙일까 하다가, 어차피 뒤에서 정리 작업을 또 해야 하니 그냥 Claude에 이미지째로 던져보기로 했다. 결과가 생각보다 깔끔해서 그 뒤로 스크린샷 분석이나 차트 읽기에도 계속 쓰고 있다.

핵심은 image 블록

텍스트만 보내던 messages.createimage 타입 콘텐츠 블록을 하나 끼워 넣으면 끝이다. 이미지는 base64로 인코딩해서 넣거나, 접근 가능한 URL을 그대로 줄 수도 있다.

써보기

로컬 파일을 base64로 읽어 넣는 경우다.

import Anthropic from '@anthropic-ai/sdk';
import { readFileSync } from 'fs';

const client = new Anthropic();

const imageData = readFileSync('./receipt.jpg').toString('base64');

const msg = await client.messages.create({
  model: 'claude-opus-4-8',
  max_tokens: 1024,
  messages: [
    {
      role: 'user',
      content: [
        {
          type: 'image',
          source: {
            type: 'base64',
            media_type: 'image/jpeg',
            data: imageData,
          },
        },
        {
          type: 'text',
          text: '이 영수증에서 각 항목명과 금액, 총액을 JSON으로 뽑아줘.',
        },
      ],
    },
  ],
});

console.log(msg.content[0].type === 'text' && msg.content[0].text);

media_type은 실제 파일 형식과 맞춰야 한다. PNG면 image/png, WebP면 image/webp. 여기를 대충 넣으면 인식이 안 되니 주의.

실제로 쓰면서 알게 된 것

  • 이미지를 먼저, 질문을 나중에. 콘텐츠 배열에서 image 블록을 앞에 두고 텍스트 지시를 뒤에 붙이면 답변 품질이 더 안정적이었다. 여러 장을 비교시킬 땐 각 이미지 앞에 "이미지 1:" 같은 라벨 텍스트를 끼워두면 헷갈리지 않는다.
  • 해상도를 무작정 키우지 말자. 긴 변 기준 약 1568px가 넘어가면 내부에서 리사이즈된다. 그보다 큰 원본을 보내봐야 토큰만 더 먹고 이득이 없다. 미리 줄여서 보내는 게 비용에 낫다.
  • 구조화가 필요하면 스키마를 못박아라. "JSON으로"라고만 하면 가끔 설명을 덧붙인다. 원하는 필드를 예시까지 딱 정해주거나 structured outputs를 같이 쓰면 파싱이 편해진다.

정리

이미지 분석에 별도 OCR 파이프라인을 깔 필요 없이, image 블록 하나면 스크린샷·차트·영수증을 바로 텍스트나 JSON으로 뽑을 수 있다. media_type 정확히 맞추기, 이미지 먼저·질문 나중, 해상도는 1568px 안쪽으로 — 이 세 가지만 챙기면 대부분의 문서 읽기 작업은 무난하게 끝난다.