반응형
Phone Harness 사용법 — AI 에이전트가 내 폰을 직접 조작하는 도구

앱 안에서만 되는 일이 아직 많다. 당근 나눔 신청, 예약 앱 체크인, 은행 앱 인증처럼 API가 없거나 막혀 있는 일은 자동화 스크립트가 손을 못 댄다. Phone Harness는 이 지점을 정면으로 건드린다. 에이전트에게 실제 폰 화면을 보여주고, 손가락 대신 탭하고 입력하게 만든다.

이 글은 Phone Harness가 무엇인지, 아이폰·안드로이드·클라우드 폰 중 무엇을 골라야 하는지, 설치와 첫 실행에서 어디서 막히는지 정리한다.

30초 요약

궁금한 것답
무엇에이전트가 실제 폰 앱을 탭·입력·스크롤하게 해주는 오픈소스 Python CLI (GitHub)
라이선스MIT, Python, 2026-11-05 기준 GitHub 스타 4,449개
아이폰 경로맥의 iPhone Mirroring 창을 캡처 → Apple Vision OCR로 글자·좌표를 읽고 클릭을 보낸다
안드로이드 경로adb로 스크린샷·입력, 접근성 트리로 정확한 요소를 찾는다
설치pip install phone-harness (Python 3.10 이상), phone-harness skill로 에이전트에 스킬 등록
아이폰 필수 조건macOS 15 이상 + Apple silicon 또는 T2 맥, iOS 18 이상, 같은 Apple 계정
클라우드 요금안드로이드 분당 5¢(월 $20에 1,000분 포함), 클라우드 아이폰 월 $80
못 하는 것멀티터치, 카메라·Face ID, DRM 영상 캡처, adb 한글 직접 입력
제일 큰 위험모델이 쓴 Python이 내 맥에서 그대로 실행된다. 승인 게이트를 끄면 안 된다

목차

  1. Phone Harness란?
  2. 설치 전에 확인할 것 — 아이폰·안드로이드·클라우드
  3. 설치와 에이전트 연결 (Claude Code·Codex·OpenClaw)
  4. 아이폰·안드로이드 연결 — 두 경로의 차이
  5. 실제로 시키는 일 — 헬퍼 명령
  6. 클라우드 폰 요금과 쓰는 법
  7. 한계와 보안
  8. 내가 막혔던 곳
  9. 참고 자료

에이전트는 앱을 열고, 화면 글자에서 버튼 위치를 찾아 탭한 뒤 다시 화면을 읽는다. 사람이 폰을 쓰는 순서와 같다.


위 화면은 에이전트가 "설정 앱 열고 상위 10개 항목 읽기"를 수행하는 흐름을 도식으로 정리한 것이다. 사람이 하는 동작을 그대로 흉내 낸다는 점이 핵심이다.

Phone Harness란?

한 줄로 말하면 "폰을 다루는 손과 눈을 에이전트에게 붙여주는 도구"다. 탈옥도, Xcode 빌드도, 폰에 무언가를 설치하는 일도 없다. README는 이렇게 소개한다. "에이전트가 스크롤하고, 탭하고, 입력하고, 폰을 읽는다. 탈옥 없이, Xcode 없이, 폰에 설치되는 것도 없이." (GitHub README)

구조는 단순하다. Claude Code나 Codex 같은 CLI 에이전트가 내 컴퓨터에서 돌고, 그 에이전트가 phone-harness를 호출한다. Phone Harness는 폰 화면을 읽어 텍스트와 좌표를 돌려주고, 에이전트가 고른 좌표로 탭을 보낸다. 모델은 폰에 올라가지 않는다. 폰은 화면과 입력 장치 역할만 한다.

여기서 "하네스"라는 말이 낯설 수 있다. 원래 하네스는 모델을 둘러싸고 도구·권한·실행 환경을 붙여주는 껍데기다. 하네스(harness)란?에서 개념을 먼저 잡고 오면 이 글이 훨씬 빨리 읽힌다. Phone Harness는 그 껍데기에 "휴대폰"이라는 몸을 하나 더 단 셈이다.

지원 범위는 세 갈래다. 개인 아이폰은 맥의 iPhone Mirroring을 거친다. 개인 안드로이드는 adb로 붙는다. 폰이 없거나 여러 대가 필요하면 Phone Harness Cloud에서 빌려 쓴다. 세 경로의 요구사항이 완전히 다르므로, 설치보다 먼저 자기 폰이 어느 쪽인지 확인해야 한다.

설치 전에 확인할 것 — 아이폰·안드로이드·클라우드

연결필요한 것안 되는 경우
개인 아이폰macOS 15 이상, Apple silicon 또는 T2 맥, iOS 18 이상, iPhone Mirroring 페어링, 터미널에 손쉬운 사용·화면 기록 권한인텔 맥(2017년형 등), macOS 14 이하, EU 지역
개인 안드로이드macOS·Linux·Windows 아무거나, Android Platform Tools(adb), USB 디버깅 또는 무선 디버깅잠긴 폰은 직접 풀어야 함
클라우드 안드로이드Phone Harness Cloud 계정, 호스트에 adb분당 과금
클라우드 아이폰Cloud 계정만 (HTTPS로 제어)월 구독, 실기기 한정 수량

아이폰 조건이 특히 빡빡하다. Apple 문서는 iPhone Mirroring 요구사항을 이렇게 못 박는다. "Mac이 macOS Sequoia 15 이후이고 Apple silicon 또는 Apple T2 보안 칩이 탑재된 Mac일 것, iPhone이 iOS 18 이후이고 암호가 설정되어 있을 것, 두 기기가 같은 Apple 계정으로 2단계 인증을 사용할 것." (Apple — iPhone Mirroring) T2 칩이 없는 인텔 맥은 여기서 탈락한다. 내 맥이 정확히 그 경우였고, 자세한 건 8번 절에 적었다.

아이폰·안드로이드·클라우드 폰의 조건을 한 장으로 비교했다. 아이폰 경로의 요구사항이 가장 빡빡하다.

표에 담은 세 경로를 그림으로 비교하면 위와 같다. "폰을 이미 갖고 있는가"와 "아이폰인가" 두 질문으로 갈린다고 보면 된다.

설치와 에이전트 연결 (Claude Code·Codex·OpenClaw)

기본은 PyPI 설치다. 2026-11-05 기준 최신 버전은 0.3.3이고 Python 3.10 이상을 요구한다. (PyPI — phone-harness)

pip install phone-harness
phone-harness --doctor          # 연결 상태 점검
phone-harness config set telemetry false   # 익명 사용 통계 끄기 (선택)

소스를 고치고 싶으면 Git 체크아웃으로 설치한다.

git clone https://github.com/phone-harness/phone-harness ~/.phone-harness
cd ~/.phone-harness
pip install -e .

다음은 에이전트에 스킬을 등록하는 단계다. 여기서부터가 진짜다. CLI만 깔면 사람이 명령어를 외워야 하지만, 스킬을 등록하면 에이전트가 헬퍼 목록과 요령을 스스로 읽는다.

# Claude Code
mkdir -p ~/.claude/skills/phone-harness
phone-harness skill > ~/.claude/skills/phone-harness/SKILL.md

# Codex
mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills/phone-harness"
phone-harness skill > "${CODEX_HOME:-$HOME/.codex}/skills/phone-harness/SKILL.md"

OpenClaw를 쓴다면 플러그인으로 붙는 쪽이 편하다. 설치는 한 줄이다. (OpenClaw 통합 문서)

openclaw plugins install clawhub:phone-harness

조건은 OpenClaw 2026.10.9 이상과 게이트웨이가 도는 머신에 uv가 있는 것이다. 플러그인은 phone_exec 도구 하나를 노출한다. 모델이 짧은 Python 스크립트를 쓰면 승인 창에 스크립트 전문이 뜨고, 내가 허용해야 폰에서 실행된다. 스크립트 앞 500자가 넘으면 승인 창에 다 못 담기 때문에 아예 승인 요청이 오지 않는다. 그래서 모델이 스크립트를 잘게 쪼개서 보낸다.

MCP 클라이언트를 쓴다면 https://mcp.phone-harness.com/mcp를 등록하면 된다. 다만 MCP는 아직 클라우드 폰(안드로이드 에뮬레이터·클라우드 아이폰)만 지원한다. 내 방에 있는 실기기를 MCP로 직접 부르는 건 안 된다.

아이폰·안드로이드 연결 — 두 경로의 차이

아이폰: iPhone Mirroring이 전부다

아이폰 경로의 원리는 이렇다. 맥에서 iPhone Mirroring을 켜면 폰 화면이 맥 창으로 흘러나온다. Phone Harness는 그 창을 캡처해서 Apple Vision 프레임워크로 글자를 읽고, 읽은 글자의 좌표에 클릭과 키 입력을 보낸다. 폰 입장에서는 맥이 보낸 터치와 키보드 입력으로 보인다.

phone-harness --doctor ios

순서는 네 단계다.

  1. 맥에서 iPhone Mirroring을 열고 아이폰과 페어링한다.
  2. 시스템 설정 → 개인정보 보호 및 보안에서 터미널(또는 게이트웨이 앱)에 손쉬운 사용과 화면 기록을 허용한다.
  3. 화면 기록 권한을 준 뒤 터미널을 재시작한다. 이걸 빼먹으면 캡처가 계속 검게 나온다.
  4. 아이폰은 잠근 상태로 둔다. 잠금을 풀면 미러링이 끊긴다.

마지막 항목이 실사용에서 제일 걸린다. 내가 폰을 들고 잠금을 풀면 에이전트의 세션이 끊긴다. 반대로 말하면, 에이전트에게 폰을 맡기는 동안에는 폰을 건드리지 않는 습관이 필요하다. 문서도 잠금 해제가 미러링을 멈춘다고 명시한다.

안드로이드: adb와 접근성 트리

안드로이드 쪽은 요구사항이 훨씬 관대하다. 맥이든 리눅스든 윈도우든 상관없다. 대신 폰에서 개발자 옵션을 열어야 한다.

# 1) 폰: 설정 → 휴대전화 정보 → 빌드번호 7번 탭 → 개발자 옵션 → USB 디버깅 켜기
# 2) USB로 연결하고 폰 화면의 디버깅 허용 팝업 승인
phone-harness --doctor android

# 무선으로 붙일 때 (Android 11 이상)
phone-harness android pair 123456    # 폰에 뜬 6자리 코드

USB를 뺄 때는 무선 디버깅을 쓰면 된다. 같은 Wi-Fi에서 페어링 코드만 넣으면 선 없이 붙는다. 노트북을 들고 다니며 폰을 조작하는 상황이면 이쪽이 편하다.

아이폰과 갈리는 지점은 "무엇을 보고 판단하느냐"다. 아이폰은 OCR로 글자를 읽고 좌표를 추정한다. 안드로이드는 접근성 트리에서 요소의 정확한 텍스트·경계·리소스 ID를 받는다. 그래서 tap_ui()처럼 이름으로 요소를 집는 명령이 안드로이드에만 있다. 글자가 안 보이는 버튼도 리소스 ID로 찾을 수 있다는 뜻이다.

단, 접근성 트리를 노출하지 않는 화면도 있다. 그럴 때는 결국 스크린샷을 보고 다음 동작을 정해야 한다. OCR과 트리를 오가는 구조라고 이해하면 된다.

실제로 시키는 일 — 헬퍼 명령

CLI는 헬퍼를 미리 불러온 상태로 Python 코드를 받는다. 터미널에서 바로 실행해 볼 수 있다.

phone-harness <<'PY'
open_app("Notes")
tap_text("New Note")
type_text("hello from the harness")
print([o["text"] for o in ocr()][:10])
PY

에이전트에게는 이렇게 시키면 된다. "노트 앱을 열고 새 메모를 만들어 '내일 9시 회의'라고 적은 다음, 화면에 제대로 들어갔는지 확인해줘." 에이전트는 앱 열기 → 버튼 찾기 → 입력 → 화면 다시 읽기 순으로 스스로 판단한다. 각 동작 뒤에 화면을 다시 읽는 것이 이 도구의 기본 리듬이다.

헬퍼하는 일
ocr()화면 글자와 탭 좌표 읽기
screenshot()현재 화면 캡처
open_app()설치된 앱 실행
tap_text()보이는 텍스트로 컨트롤 누르기
tap() / long_press()좌표로 탭·길게 누르기
type_text()포커스된 입력란에 문자열 입력
swipe() / scroll()스와이프·스크롤
scroll_collect()긴 목록을 끝까지 훑어 모으기
wait_stable()화면 변화가 멈출 때까지 대기
tap_ui() / back()안드로이드 전용, 접근성 요소 선택·뒤로 가기

실무에서 쓸 만한 작업은 세 부류다. 첫째, 반복 입력이다. 매일 같은 앱에 같은 형식으로 기록하는 일. 둘째, 긴 목록 수집이다. scroll_collect()로 끝까지 내리며 텍스트를 모으면 손으로 캡처하는 것보다 빠르고 누락이 적다. 셋째, 앱 상태 확인이다. "이 화면에 오류 팝업 떴어?" 같은 질문은 스크린샷 한 장으로 끝난다.

클라우드 폰 요금과 쓰는 법

폰이 없거나, 여러 대를 동시에 돌리거나, 내 폰을 자동화에 쓰기 싫을 때 쓰는 경로다. (Phone Harness 요금)

플랜가격포함
Basic (클라우드 안드로이드)월 $0, 분당 5¢시작 크레딧 $5, 앱·로그인 유지, 라이브 뷰어, MCP 서버
Plus월 $201,000분 포함, 초과분 분당 4¢
Cloud iPhone월 $80 (연 결제 $64), eSIM 포함 $100실기기, 실번호, 분당 과금 없음
Scale문의전용 실기기 상시 점유, 다중 프로필, 프록시

과금 규칙에서 놓치기 쉬운 부분이 있다. 세션 시간에 프로비저닝 시간이 포함되고, 요금은 폰이 준비된 시점부터 시작된다. 세션을 끝내면 임시 폰과 앱 데이터가 삭제된다. 로그인을 유지하려면 "저장된 폰"으로 띄워야 한다는 뜻이다. (Cloud 개요)

phone-harness cloud login    # 최초 1회, 브라우저에서 승인
phone-harness cloud ls       # 계정의 폰과 진행 중인 세션 확인
phone-harness cloud start    # 기본 안드로이드, 15분
phone-harness cloud stop

클라우드 아이폰은 HTTPS로 제어하기 때문에 맥 OS 버전과 무관하다. 인텔 맥이라 iPhone Mirroring을 못 쓰는 경우에도 이 경로는 열린다. 월 $80이 비싸 보이지만, 중고 아이폰을 사서 상시 켜두는 비용과 전기·관리 공수를 생각하면 숫자가 달라진다.

한계와 보안

기능 목록보다 못 하는 일을 먼저 확인하는 편이 시간을 아낀다.

  • 멀티터치 제스처(핀치 줌 등), 카메라, Face ID 조작은 지원하지 않는다.
  • DRM이 걸린 영상은 캡처되지 않는다. 넷플릭스 화면을 읽히려는 시도는 처음부터 막힌다.
  • 아이폰의 백그라운드 제어는 macOS 비공개 API에 의존한다. 미러링 창이 다른 창에 가려지면 캡처가 흔들린다.
  • 잠긴 안드로이드는 직접 풀어야 한다. adb 텍스트 입력은 ASCII만 가능해서 한글은 그대로 타이핑되지 않는다.

마지막 항목은 한국 사용자에게 실제로 아프다. 한글 검색어를 앱에 넣어야 하는 작업이라면, 한글 입력은 클립보드 붙여넣기나 앱 자체의 최근 검색어를 쓰는 쪽으로 우회해야 한다. adb의 input text가 ASCII만 받는 것은 도구의 버그가 아니라 안드로이드 쪽 제약이다.

보안은 더 진지하게 봐야 한다. Phone Harness는 폰에 설치되는 앱이 아니라 내 컴퓨터에서 도는 프로그램이다. 에이전트가 쓴 Python이 내 계정 권한으로 실행되고, 그 코드가 실제 폰의 실제 앱을 건드린다. 결제·송금·삭제가 가능한 앱이 로그인된 폰이라면 위험도 그만큼 크다.

그래서 승인 게이트를 끄면 안 된다. OpenClaw 플러그인은 기본값이 "매 호출 승인"이고, 자동 실행(classifierAutoRun)은 꺼져 있다. 켜면 분류기가 "폰만 건드리는 코드"라고 판단한 스크립트를 묻지 않고 실행하는데, 문서 스스로 이 분류기가 휴리스틱이라 우회될 수 있다고 적는다. 그리고 샌드박스 세션에는 이 도구가 아예 주어지지 않는다. 플러그인이 게이트웨이 안에서 돌기 때문에, 샌드박스 밖인 내 맥에서 스크립트가 실행되기 때문이다.

내가 막혔던 곳

첫 번째 벽은 내 맥이었다. 아이폰 경로를 쓰려고 보니 요구사항이 macOS 15 이상에 Apple silicon 또는 T2였다. 내 장비에서 확인한 값은 이렇다.

$ sw_vers
ProductVersion:  13.7.8          # Ventura, macOS 15 미만

$ sysctl -n machdep.cpu.brand_string
Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz   # T2 칩 없음

$ ls -d "/System/Applications/iPhone Mirroring.app"
No such file or directory        # 미러링 앱 자체가 없음

세 줄이 동시에 걸린다. OS가 낮고, 칩이 T2가 아니고, 미러링 앱이 설치조차 되어 있지 않다. 이 조합에서는 iPhone Mirroring을 켜는 것부터가 불가능하니, Phone Harness 이전에 Apple 쪽에서 막힌 셈이다. 결론은 두 가지였다. 안드로이드 실기기로 가거나, 클라우드 아이폰을 쓰거나.

내 맥에서 직접 확인한 결과다. OS 버전, 칩, 미러링 앱 세 가지가 동시에 걸려 아이폰 경로는 시도조차 할 수 없었다.

위 화면은 실제로 내 맥에서 돌린 점검 결과를 그대로 옮긴 것이다. 세 개의 조건이 동시에 어긋나면 아이폰 경로는 시도조차 할 수 없다.

두 번째 벽은 Python 버전이었다. 이 맥의 기본 python3는 3.9.6인데 Phone Harness는 3.10 이상을 요구한다. uv도 없었다. 이때 시스템 파이썬을 건드리는 대신 uv를 새로 깔고 3.12를 따로 받는 쪽을 택했다. 시스템 파이썬에 직접 패키지를 넣으면 나중에 다른 스크립트가 깨진다. 이 맥에서 Python을 여러 버전으로 쓰는 방법은 Python 가상환경 venv 만들기에 정리해 두었다.

세 번째는 권한이었다. 손쉬운 사용과 화면 기록을 켜고도 캡처가 계속 검게 나왔다. 원인은 터미널을 재시작하지 않은 것이었다. 화면 기록 권한은 앱이 새로 뜰 때 반영된다. 권한을 준 뒤에는 터미널을 완전히 종료했다가 다시 열어야 한다.

네 번째는 승인 창이었다. 스크립트를 길게 쓰면 승인 요청이 아예 오지 않는다. 처음엔 버그인 줄 알았는데, 500자 제한 때문에 긴 스크립트는 승인 화면에 전문을 못 보여줘서 거부되는 구조였다. 지금은 "앱 열고 → 읽고 → 다음 판단"처럼 잘게 끊어서 시킨다. 폰 상태는 호출 사이에 유지되므로 쪼개도 결과는 이어진다. 에이전트를 다루는 기본기는 AI 에이전트란과 Claude Code 설치·사용법에 있다.

참고 자료

반응형
반응형
멀티모달 AI란 — 이미지 한 장이 토큰 1296개가 되는 이유

챗봇에 스크린샷을 붙여넣고 "이 오류 왜 나?"라고 물으면 답이 온다. 그런데 같은 이미지를 열 장 넣는 순간 요금이 확 뛰고, 아주 작은 글씨는 못 읽는다. 이미지가 텍스트와 똑같이 취급되는 것 같으면서도 숫자가 다르게 움직이는 이유가 있다.

이 글은 멀티모달 AI가 무엇인지, 이미지·영상이 어떤 단위로 토큰이 되는지, 그리고 그 계산이 실제 요금과 답변 품질을 어떻게 바꾸는지 정리한다.

30초 요약

궁금한 것답
정의텍스트뿐 아니라 이미지·오디오·영상을 입력으로 받아 처리하는 모델 (Google Cloud)
핵심 원리입력을 전부 토큰열로 바꿔 하나의 컨텍스트에 넣는다. 이미지는 패치·타일 단위로 토큰화된다
이미지 1장 비용1000×1000 한 장이 Claude 기준 1,296 토큰, GPT-6 Astra detail: high 기준 1,229 토큰
영상은 더 비싸다Gemini 기본 설정 기준 초당 약 300 토큰. 1분이면 18,000 토큰
잘 나오는 일OCR, 표·차트 읽기, UI 스크린샷 디버깅, 손글씨
잘 틀리는 일작은 글씨, 물체 개수 세기, 정확한 좌표, 사람 이름 맞히기
실무 결론파일 크기가 아니라 픽셀과 타일 수가 요금을 정한다. 보내기 전에 자르고 줄여라

목차

  1. 멀티모달 AI란? 한 문장 정의
  2. 텍스트 전용 모델과 무엇이 다른가
  3. 이미지는 어떻게 토큰이 되나 (모델별 계산식)
  4. 영상·오디오는 숫자가 한 자리 다르다
  5. 실제로 써보면 갈리는 지점
  6. 멀티모달 AI의 한계
  7. 내가 막혔던 곳
  8. 참고 자료

이미지는 28×28 픽셀 패치로 잘려 토큰이 된다. 파일 크기가 아니라 픽셀 수가 요금을 정한다.


멀티모달 AI란? 한 문장 정의

Google Cloud 문서는 멀티모달 모델을 "이미지, 영상, 텍스트 등 서로 다른 모달리티의 정보를 처리할 수 있는 머신러닝 모델"로 정의한다. 텍스트를 넣으면 텍스트만 나오는 모델과 달리, 입력과 출력의 종류가 서로 달라도 된다. (Google Cloud — Multimodal AI)

여기서 많이 헷갈리는 지점이 있다. 멀티모달은 모델을 여러 개 붙여놓은 구조가 아니다. 이미지 인코더가 뽑은 특징을 텍스트 토큰과 같은 공간에 넣고, 하나의 트랜스포머가 전부 같이 본다. 그래서 "이미지도 결국 토큰"이라는 말이 나온다. 토큰 개념이 낯설면 토큰(token)이란을 먼저 보면 좋다.

출력 쪽도 넓어졌다. 텍스트와 코드는 기본이고, 이미지 생성, 음성 합성, 영상 생성까지 같은 계열 모델이 처리한다. 다만 입력을 이해하는 능력과 출력을 생성하는 능력은 별개로 봐야 한다. 이미지를 잘 읽는 모델이 이미지를 잘 그리는 것은 아니다.

텍스트 전용 모델과 무엇이 다른가

같은 질문을 텍스트로 할 때와 이미지로 할 때, 모델이 하는 일이 다르다. 텍스트는 이미 토큰으로 잘려 있는 반면, 이미지는 전처리 단계를 한 번 더 거친다.

구분텍스트 입력이미지 입력
전처리토크나이저가 단어를 자른다리사이즈 → 패치·타일 분할
토큰 수 결정글자 수에 비례해상도와 타일 수에 비례
실패 양상문맥을 놓침작은 글씨 오독, 개수 오산
요금이 뛰는 순간대화가 길어질 때고해상도 이미지를 여러 장 넣을 때
잘하는 일요약, 코드, 추론OCR, 도표 해석, 화면 상태 판단

Anthropic 문서는 이미지를 텍스트보다 앞에 두라고 권한다. 긴 문서를 질문 앞에 두는 것과 같은 이유다. 이미지 뒤에 질문을 붙이는 순서가 인식률에 유리하다. (Anthropic — Vision)

이미지는 어떻게 토큰이 되나 (모델별 계산식)

세 회사 모두 "이미지를 작은 블록으로 나누고, 블록 수만큼 토큰을 센다"는 발상을 공유한다. 블록 크기와 상한이 다를 뿐이다.

제공사블록 단위토큰 계산상한
Anthropic28×28 px 패치⌈w/28⌉ × ⌈h/28⌉표준 1,568 / 고해상도 4,784 visual token
OpenAI32×32 px 패치패치 수 × 모델 배율(1.2)detail: high 기준 패치 예산 2,500
Google768×768 px 타일타일당 258 토큰요청당 이미지 3,600장

출처는 각각 Anthropic Vision, OpenAI Images and vision, Gemini 이미지 이해다.

Anthropic의 계산은 외우기 쉽다. 1000×1000 이미지는 ⌈1000/28⌉ = 36이라 36×36 = 1,296 토큰이다. 1920×1080은 표준 등급에서 1456×819로 줄어 1,560 토큰, 고해상도 등급(Claude 4.7 이후)에서는 원본 그대로 2,691 토큰이 된다. 4K 영상 프레임 한 장은 고해상도에서 4,784 토큰까지 올라간다.

OpenAI는 패치 수에 모델별 배율을 곱한다. GPT-6 Astra는 detail: high에서 최대 변 65,535 px, 패치 예산 2,500, 배율 1.2를 쓴다. 1024×1024는 1,024패치라 ⌈1024×1.2⌉ = 1,229 토큰, 2048×2048은 예산 때문에 1600×1600으로 줄어 3,000 토큰이다. 패치가 30,000개를 넘으면 리사이즈 없이 요청이 거부된다.

Google은 조금 다르게 센다. 양쪽 변이 384 px 이하면 258 토큰으로 끝나고, 그보다 크면 768×768 타일로 나눠 타일마다 258 토큰을 매긴다. 960×540 예시는 타일 6개라 1,548 토큰이 된다.

# 보내기 전에 대략적인 토큰을 미리 재는 용도 (Anthropic 기준)
import math

def claude_image_tokens(w, h, max_edge=1568):
    scale = min(1.0, max_edge / max(w, h))
    w, h = int(w * scale), int(h * scale)
    return math.ceil(w / 28) * math.ceil(h / 28)

for size in [(1000, 1000), (1920, 1080), (3840, 2160)]:
    print(size, claude_image_tokens(*size))
# (1000, 1000) 1296 · (1920, 1080) 1560 · (3840, 2160) 1560

요금으로 바꾸면 차이가 더 분명해진다. Anthropic 문서의 예시를 그대로 인용하면, Claude Haiku 4.5(백만 입력 토큰당 $1, 표준 등급)에서 1000×1000 이미지 1,000장은 약 $1.30이다. Claude Opus 5.5(백만 토큰당 $4, 고해상도 등급)에서는 같은 이미지 1,000장이 약 $5.18, 4K 이미지 1,000장은 약 $19.14다. (같은 문서)

같은 그림도 해상도 설정에 따라 토큰이 두 배 넘게 벌어진다. 보내기 전에 크롭하는 이유다.

영상·오디오는 숫자가 한 자리 다르다

영상은 프레임을 초당 몇 장 뽑느냐로 비용이 결정된다. Gemini 문서 기준으로 기본값은 초당 1프레임이고, 프레임당 258 토큰(저해상도 설정은 66 토큰), 오디오는 초당 32 토큰이 붙는다.

설정초당 토큰1분 영상10분 영상
기본(저해상도 미디어)약 100약 6,000약 60,000
고해상도약 300약 18,000약 180,000
에이전트형 탐색내용에 따라 다름최대 88% 절감최대 88% 절감

출처는 Gemini 영상 이해다. 10분짜리 고해상도 영상 한 편이면 20만 토큰에 가까운 창을 쓴다. 컨텍스트 윈도우가 1M이어도 영상 몇 편이면 절반이 날아간다는 뜻이다. 창 크기 자체가 궁금하면 컨텍스트 윈도우란에서 자세히 다뤘다.

Gemini 4 Argon부터는 에이전트형 모드가 있어서, 모델이 영상 전체를 훑는 대신 필요한 구간만 골라 본다. 긴 영상에서 토큰을 88%까지 아낀다고 문서는 설명한다. 대신 첫 토큰이 나오는 시간은 느려진다.

실제로 써보면 갈리는 지점

내가 멀티모달을 실제로 쓰는 곳은 세 군데다. 첫째는 오류 화면이다. 터미널 스크린샷을 넣고 "이 에러 로그에서 진짜 원인만 뽑아줘"라고 하면, 텍스트로 옮겨 적는 것보다 빠르고 오타도 없다. 특히 스택트레이스처럼 줄이 긴 출력에서 차이가 크다.

둘째는 표와 차트다. 논문 PDF의 표를 이미지로 잘라 넣으면 열 정렬을 꽤 잘 맞춘다. 다만 단위를 생략한 열이나 각주는 자주 놓친다. 숫자를 인용할 때는 원문을 다시 확인하는 편이 안전하다.

셋째는 UI 상태 판단이다. "이 화면에서 다음에 눌러야 할 버튼이 뭐야" 같은 질문은 잘 맞힌다. 브라우저 자동화처럼 좌표가 필요한 작업은 다르다. Anthropic 문서는 좌표 출력이 근사치라고 명시하고, OpenAI 문서도 좌표가 중요한 작업은 detail: original을 쓰고 원본 좌표로 되돌려 매핑하라고 안내한다.

멀티모달 AI의 한계

가장 자주 부딪히는 벽은 해상도다. Anthropic은 200 px 이하로 작거나 회전된 이미지에서 오독이 생긴다고 적는다. 리사이즈가 걸리면 텍스트가 더 작아지므로, 글자가 중요한 이미지는 미리 자르거나 확대해서 넣어야 한다.

개수 세기도 믿을 일이 아니다. 문서는 물체가 많고 작을수록 개수 추정이 부정확해진다고 못 박는다. 표의 행 개수, 재고 수량, 사람 수처럼 정확한 숫자가 필요한 작업은 모델에게 세게 하면 안 된다.

사람 식별은 아예 거부된다. Anthropic 사용 정책상 이미지 속 사람의 이름을 맞히는 용도로 쓸 수 없다. 얼굴 인식 용도로 멀티모달을 검토하고 있다면 이 지점에서 설계가 달라진다.

내가 막혔던 곳

처음엔 파일 크기가 토큰을 정한다고 생각했다. 그래서 스크린샷을 JPEG로 세게 압축해서 넣었더니 요금은 그대로였고, 글씨만 뭉개져서 답이 나빠졌다. 토큰은 바이트가 아니라 픽셀과 타일로 결정된다. 지금은 압축보다 크롭을 먼저 한다. 필요한 영역만 잘라 넣으면 토큰도 줄고 인식률도 올라간다.

두 번째는 이미지 순서였다. 여러 장을 넣고 "첫 번째 사진"이라고 지칭했는데, 모델이 세는 순서와 내가 생각한 순서가 달랐다. 지금은 각 이미지 앞에 "화면 1:", "화면 2:" 같은 텍스트 라벨을 붙인다. 라벨 하나로 오독이 크게 줄었다.

세 번째는 PDF다. 페이지 30장짜리 문서를 통째로 넣었다가 요청 크기 제한에 걸렸다. Claude API는 이미지 한 장 10MB, 요청 전체 128MB가 한도라서, 토큰보다 바이트가 먼저 막는 경우가 있다. 지금은 페이지를 나눠 넣고 각 요청의 usage를 로그로 남긴다. 모델 계열 전체 그림이 필요하면 LLM이란 무엇인가를 같이 보면 좋다.

참고 자료

반응형
반응형
컨텍스트 윈도우란 — 1M 토큰이 1M처럼 안 쓰이는 이유

모델 스펙 표에서 "컨텍스트 윈도우 1M 토큰"이라는 숫자를 보고 책 한 권을 통째로 넣을 수 있다고 이해하는 경우가 많다. 실제로는 1M을 다 채우면 답의 정확도가 눈에 띄게 떨어지고, 요금도 배로 뛴다.

이 글은 컨텍스트 윈도우가 무엇이고, 무엇이 그 공간을 차지하며, 왜 큰 숫자를 그대로 믿으면 안 되는지를 정리한다.

30초 요약

궁금한 것답
정의모델이 한 번의 요청에서 참조할 수 있는 전체 텍스트. 입력과 출력이 같은 공간을 나눠 쓴다
다른 말로작업 기억(working memory), 토큰 예산
현재 최대치Claude 최신 모델 1M, GPT-6 Astra 1,050,000, Gemini 4 Argon 1,048,576
무엇이 포함되나시스템 프롬프트, 대화 전체, 툴 정의, 툴 결과, 이미지·문서, 사고 토큰, 생성 중인 답변
함정 1토큰이 늘수록 회수 정확도가 떨어진다(context rot)
함정 2한도를 넘으면 요청이 400으로 거절되거나 중간에 잘린다
실무 결론큰 창은 "한 번에 많이 넣는 용도"가 아니라 "필요한 것만 남기는 용도"

목차

  1. 컨텍스트 윈도우란? 한 문장 정의
  2. 무엇이 토큰을 먹는가
  3. 모델별 크기 비교 (2026년 11월 기준)
  4. 크다고 좋은 게 아닌 이유 — context rot
  5. 한도를 넘으면 실제로 무슨 일이 나나
  6. 내가 쓰는 컨텍스트 관리법
  7. 내가 막혔던 곳
  8. 참고 자료

1,048,576토큰을 다 채우면 회수 정확도가 떨어진다. 창의 크기와 실제 성능은 다른 문제다.


컨텍스트 윈도우란? 한 문장 정의

Anthropic 문서는 컨텍스트 윈도우를 "모델이 응답을 생성할 때 참조할 수 있는 모든 텍스트, 응답 자체를 포함한 것"으로 정의한다. 학습 데이터 전체와는 다른 개념이고, 문서 표현을 빌리면 모델의 작업 기억이다. (Anthropic — Context windows)

내가 쓰는 비유는 책상이다. 책장에 책이 아무리 많아도(학습 데이터), 지금 책상 위에 펼쳐둔 것만 보면서 일한다. 책상이 넓으면 자료를 많이 올려둘 수 있지만, 넓다고 해서 눈이 좋아지는 건 아니다.

단위는 토큰이다. 영어는 대략 단어 하나가 1~1.5토큰, 한국어는 같은 내용에 더 많은 토큰이 든다. 토큰 자체가 낯설면 토큰(token)이란을 먼저 보면 좋다.

무엇이 토큰을 먹는가

처음엔 "내가 쓴 질문 + 모델 답변"만 세면 된다고 생각했다. 실제 청구서와 usage 필드를 열어보면 항목이 훨씬 많다.

항목포함 여부비고
시스템 프롬프트포함매 요청마다 반복 과금
이전 대화 전체포함턴이 쌓일수록 선형으로 증가
툴 정의(스키마)포함툴이 많을수록 고정 비용
툴 실행 결과포함검색·파일 읽기 결과가 가장 크게 늘어난다
이미지·PDF포함요청당 이미지·PDF 최대 600장(200k 모델은 100장)
사고(thinking) 토큰포함출력으로 과금되고 창도 차지
생성 중인 답변포함출력 토큰도 같은 창을 쓴다

Anthropic 문서는 프롬프트 캐싱을 써도 캐시된 앞부분이 창에서 사라지지는 않는다고 못 박는다. 캐싱은 무엇을 지불하는지를 바꾸는 장치이지, 공간을 비워주는 장치가 아니다. (같은 문서)

실무에서 가장 많이 새는 곳은 툴 결과다. 파일 30개를 읽으면 그 내용이 전부 대화에 남는다. 다음 턴에도, 그다음 턴에도. 에이전트를 오래 돌릴수록 비용이 계단처럼 뛰는 이유가 여기 있다.

모델별 크기 비교 (2026년 11월 기준)

숫자는 공식 문서에서 직접 확인했다. 같은 회사 모델이라도 세대에 따라 두 배 이상 차이가 나니, 표를 볼 때 모델명까지 같이 봐야 한다.

모델컨텍스트 윈도우최대 출력특이사항
Claude 최신 모델(Fable 5.1·Mythos 5.1·Opus 5.5·Sonnet 5.5·Haiku 5.5 등)1M128k베타 헤더 없이 기본 1M
Claude Sonnet 4.5(지원 종료) 이전 세대200k모델별이미지·PDF 100장 제한
GPT-6 Astra1,050,000128k최대 입력 922,000, 272K 초과분은 2배 요금
Gemini 4 Argon1,048,57665,536(동기 1회)입력·출력 합산 한도, 스트리밍 아닌 HTTP 직접 호출은 32,768

출처는 각각 Anthropic Context windows, OpenAI GPT-6 Astra, Gemini 4 Argon다.

표를 읽을 때 걸리는 지점이 두 개 있다. GPT-6 Astra는 창이 1,050,000인데 최대 입력이 922,000이다. 나머지 128,000은 출력 몫으로 비워둔 것이다. Gemini 4 Argon은 입력과 출력을 합쳐 1,048,576이라, 입력을 꽉 채우면 답변할 공간이 남지 않는다.

질문과 답변만 세면 절반이 빠진다. 툴 결과와 사고 토큰까지 같은 창에 쌓인다.

크다고 좋은 게 아닌 이유 — context rot

Anthropic 엔지니어링 글에는 이 문장이 있다. 컨텍스트 창의 토큰 수가 늘어날수록, 모델이 그 안에서 정보를 정확히 회수하는 능력은 떨어진다. 이 현상을 context rot이라고 부른다. (Anthropic — Effective context engineering for AI agents)

원인으로 설명하는 건 트랜스포머의 구조다. n개 토큰이 서로를 참조하려면 n²개의 관계를 계산해야 한다. 창이 길어질수록 각 관계에 쓸 주의(attention)가 얇게 퍼진다. 사람의 작업 기억 용량이 유한한 것과 비슷하게, 모델에도 "주의 예산"이 있다는 표현을 쓴다.

논문 쪽 근거도 있다. RULER 벤치마크는 17개 장문맥 모델을 13개 과제로 평가했다. 바늘 찾기(needle-in-a-haystack) 시험에서는 거의 만점이던 모델들이, 과제가 복잡해지고 길이가 늘어나면 성적이 크게 떨어졌다. 32K 이상을 광고한 모델 중 절반만이 32K 길이에서 만족할 성적을 유지했다. (RULER, arXiv:2404.06654)

그래서 나는 스펙 숫자를 이렇게 읽는다. 1M은 "저장 가능 한도"이고, 실제로 잘 쓰는 구간은 그보다 훨씬 앞이다. 긴 문서를 넣을 때는 앞쪽에 핵심을 몰아넣고, 중간에 묻히는 구간을 만들지 않는 편이 낫다.

한도를 넘으면 실제로 무슨 일이 나나

증상은 두 갈래다. 입력만으로 이미 창을 넘으면 API가 400 invalid_request_error("prompt is too long")를 돌려준다. 이건 모든 모델에서 동일하다.

입력은 들어갔는데 생성 도중에 한도에 닿는 경우는 다르게 동작한다. Claude 4.5 이후 모델은 요청을 받아주고, 생성이 한도에 닿으면 stop_reason: "model_context_window_exceeded"로 멈춘다. 이전 모델은 아예 검증 오류를 낸다. (Anthropic — Context window overflow behavior)

resp = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=8192,
    messages=[{"role": "user", "content": long_text}],
)
if resp.stop_reason == "model_context_window_exceeded":
    # 답이 중간에 끊긴 상태 — 이어붙이지 말고 입력을 줄여 재시도
    raise RuntimeError(f"context overflow: {resp.usage.input_tokens} tokens")

여기서 많이 하는 실수가 잘린 답변을 정상 답변으로 취급하는 것이다. 문장이 자연스럽게 끝나도 stop_reason이 end_turn이 아니면 완결된 답이 아니다. 비용을 아끼려고 max_tokens를 크게 잡아두면, 정작 창 한도에 먼저 부딪혀 잘리는 일이 생긴다.

내가 쓰는 컨텍스트 관리법

큰 창을 믿고 밀어 넣는 방식은 오래 못 간다. 지금 쓰는 방식은 네 가지다.

첫째, 툴 결과는 요약해서 넣는다. 파일을 읽고 그대로 대화에 남기지 않는다. 필요한 줄만 인용하고 나머지는 버린다. 같은 파일을 두 번 읽지 않도록 읽은 목록을 따로 적어둔다.

둘째, 대화가 길어지면 앞부분을 접는다. Anthropic은 서버 측 압축(compaction)을 제공하고, 직접 하려면 앞 턴을 요약해 시스템 프롬프트에 넣는 방식이 된다. 요약에는 결정 사항과 아직 안 끝난 일만 남긴다.

셋째, 출력 공간을 먼저 계산한다. 창이 200k면 200k를 입력에 쓰면 안 된다. 최대 출력 128k를 감안해 입력 예산을 잡는다.

넷째, 캐싱은 비용 절감용으로만 본다. 앞부분이 안 바뀌는 구조로 프롬프트를 짜면 캐시 적중률이 올라간다. 다만 창을 비워주지는 않으니, 캐시를 믿고 대화를 방치하면 안 된다.

관련 글: 프롬프트 작성법 — 좋은 예·나쁜 예 10쌍에서 무엇을 넣고 무엇을 뺄지 판단하는 기준을 다뤘다. RAG가 뭐야 (검색증강생성)는 창을 늘리는 대신 필요한 것만 검색해 넣는 접근이다.

내가 막혔던 곳

처음엔 컨텍스트 윈도우와 max_tokens를 같은 것으로 착각했다. max_tokens를 100k로 올려두면 긴 답이 나올 거라고 기대했는데, 실제로는 창 한도에서 먼저 잘렸다. 두 값은 별개이고, 출력은 언제나 창의 일부다.

두 번째는 한국어 토큰 수를 과소평가한 것이다. 같은 내용을 영어로 쓸 때와 한국어로 쓸 때 토큰 수가 꽤 벌어진다. 문서를 넣기 전에 토큰 카운팅 API로 재보는 습관을 들인 뒤로 "넣을 수 있겠지"로 시작하는 일이 없어졌다.

세 번째는 이미지다. PDF 200장을 한 요청에 넣었다가 요청 크기 제한에 걸렸다. 토큰보다 바이트 한도가 먼저 막는 경우가 있다. 지금은 문서를 나눠 넣고, 각 요청의 usage를 로그로 남긴다.

이 글의 숫자도 전부 공식 문서를 직접 열어 확인했다. 모델 이름이 바뀌면 창 크기도 같이 바뀌기 때문에, 블로그 글의 표보다 각 회사 문서를 우선하는 게 안전하다. 모델 계열 전체 그림이 필요하면 LLM이란 무엇인가를 같이 보면 좋다.

참고 자료

반응형
반응형
할루시네이션 뜻 — AI가 자신 있게 틀린 답을 말하는 이유

챗봇에게 논문 제목을 물었더니 저자와 연도까지 붙여서 답했다. 검색해보니 없는 논문이었다. 이런 답을 AI 업계에서는 할루시네이션(환각)이라고 부른다.

이 글은 그 말의 뜻, 왜 생기는지, 실제로 얼마나 틀리는지, 그리고 내가 쓰는 줄이는 방법까지 순서대로 정리한다.

30초 요약

궁금한 것답
뜻사실이 아닌 내용을 사실인 것처럼 자신 있게 만들어내는 현상
다른 이름환각, confabulation, bullshitting
원인 1다음 토큰의 확률을 맞히는 학습 방식 — 모르면 그럴듯한 쪽을 고른다
원인 2채점이 정답률만 봐서, 모르면 찍는 쪽이 점수가 높다
실제 오답률법률 리서치 AI도 17~33% (스탠퍼드, 2024)
줄이는 법"모른다"고 말할 권한 + 원문 인용 + 검색(RAG) + 사후 검증
주의RAG를 붙여도 0%가 되지 않는다

목차

  1. 할루시네이션이란? 한 문장 정의
  2. 왜 생기나 — 확률 맞히기와 채점 방식
  3. 실제로 얼마나 틀리나
  4. 환각이 잘 나는 유형
  5. 줄이는 법 — 프롬프트에서 할 수 있는 것
  6. 검색을 붙여도 사라지지 않는 이유
  7. 내가 막혔던 곳
  8. 참고 자료

할루시네이션은 지식이 없을 때 침묵하는 대신 형식만 맞는 답을 채우는 현상이다.


할루시네이션이란? 한 문장 정의

위키백과는 할루시네이션을 "AI가 생성한 응답이 사실로 제시되지만 거짓이거나 오해를 부르는 정보를 담은 것"으로 정의한다. 함께 쓰이는 말로 confabulation, bullshitting, mirage가 있다. (Wikipedia — Hallucination (artificial intelligence)))

재밌는 건 이 말이 원래 심리학 용어를 빌려온 것이다. 사람이 없는 소리를 듣는 현상과 비슷하게, 모델이 없는 사실을 "본 것처럼" 말한다는 뜻으로 붙였다. 2015년에는 안드레 카파시가 RNN 언어모델이 엉뚱한 인용 링크를 만든 사례를 블로그에서 hallucinated라고 불렀고, 2017년 구글 연구진이 기계번역 실패를 설명할 때 쓰면서 널리 퍼졌다. (같은 위키백과 문서)

그래서 나는 이렇게 이해한다. 모델이 지식이 없을 때 침묵하는 대신, 형식만 맞는 답을 채워 넣는 현상. 내용이 틀린 것보다 "틀린 티가 안 나는 것"이 문제의 핵심이다.

왜 생기나 — 확률 맞히기와 채점 방식

언어모델은 데이터베이스에서 답을 꺼내오는 프로그램이 아니다. 앞 문맥 다음에 올 토큰의 확률 분포를 계산하고, 그중 하나를 고른다. 학습 목표가 "다음에 올 단어 맞히기"이기 때문에, 지식이 희박한 지점에서도 모델은 가장 그럴듯한 형태를 낸다. (토큰(token)이란에서 이 단위를 먼저 보면 이해가 빠르다)

OpenAI는 2025년 9월 논문에서 원인을 하나 더 짚었다. 평가 방식이 추측을 장려한다는 것이다. 정답률만 채점하면, 모르는 문제에 "모르겠다"고 비우는 쪽은 0점이고 찍는 쪽은 기대값이 플러스다. 그래서 모델은 확신 없는 답을 자신 있게 내놓는 쪽으로 최적화된다. (OpenAI — Why language models hallucinate, arXiv:2509.04664)

이 주장을 뒷받침하는 표가 같은 글에 있다. SimpleQA 벤치마크에서 두 모델의 정답률은 비슷한데 오답률은 세 배 차이가 난다.

모델답하지 않음정답률오답률
gpt-5-thinking-mini52%22%26%
OpenAI o4-mini1%24%75%

정답률만 보면 아래 모델이 조금 앞선다. 실제 사용에서 체감하는 건 오답률이다. 모른다고 말하게 만드는 것만으로도 환각의 절반이 줄어든다는 뜻이다. (OpenAI, 같은 글의 GPT-5 시스템 카드 인용)

실제로 얼마나 틀리나

가장 유명한 벤치마크는 TruthfulQA다. 사람이 흔히 믿는 오해를 노린 817개 질문, 38개 카테고리로 이루어져 있다. 논문에 따르면 가장 좋은 모델도 진실 응답 비율이 58%였고, 사람은 94%였다. 더 큰 모델이 오히려 덜 진실했다는 결과도 함께 나온다. (TruthfulQA, arXiv:2109.07958)

"RAG를 쓰면 환각이 없다"는 마케팅도 검증된 적이 있다. 스탠퍼드 연구진이 Lexis+ AI, Westlaw AI-Assisted Research, Ask Practical Law AI를 사전 등록 방식으로 평가했더니, 세 도구 모두 17~33% 구간에서 환각을 냈다. 범용 챗봇보다는 낮았지만 "hallucination-free"라는 광고 문구와는 거리가 있었다. (Hallucination-Free? Assessing the Reliability of Leading AI Legal Research Tools, arXiv:2405.20362)

이 숫자들을 보고 나서 내 기준이 하나 생겼다. 환각은 유무의 문제가 아니라 비율의 문제다. "이 모델은 환각이 없다"는 말은 마케팅이고, "어떤 조건에서 몇 %인가"가 실무에서 쓸 수 있는 질문이다.

환각이 잘 나는 유형

경험상 잘 틀리는 자리가 정해져 있다. 이 목록만 기억해도 검수 시간이 꽤 줄어든다.

내가 자주 틀리는 다섯 자리와 그 자리에서 쓰는 검수 방법.

유형흔한 증상이유
인용·출처없는 논문, 없는 판례, 가짜 DOI형식은 배웠지만 실제 대응이 없다
최신 정보학습 시점 이후 사건을 아는 척한다컷오프 뒤 데이터가 없다
숫자·단위그럴듯한 자릿수의 통계정확한 값보다 빈도 높은 형태를 고른다
고유명사사람 이름, 제품명, 버전 번호조합이 무한해서 암기로 못 버틴다
부재 정보"문서에 없다"를 말하지 않고 채운다빈칸을 남기는 것이 학습 목표에 없다

특히 첫 번째가 위험하다. 링크와 서지정보는 생김새가 멀쩡해서 사람 눈으로는 걸러지지 않는다. 클릭해서 열어봐야 안다.

줄이는 법 — 프롬프트에서 할 수 있는 것

Anthropic 문서가 정리한 기본 전략은 세 가지다. 모른다고 말할 권한을 주기, 긴 문서에서는 원문 인용을 먼저 뽑기, 주장마다 출처를 달고 검증하기다. (Anthropic — Reduce hallucinations)

그중 첫 번째가 효과 대비 비용이 가장 싸다. 아래 문장을 시스템 프롬프트에 넣는 것만으로 답이 달라진다.

아래 <자료>만 근거로 답한다.
1) 답을 쓰기 전에 근거 문장을 원문 그대로 인용하고 번호를 붙인다.
2) 인용이 없는 문장은 답에서 삭제한다.
3) 자료에 없으면 "자료에 없음"이라고만 쓴다.
4) 확실하지 않으면 확률을 말하지 말고, 확인이 필요한 항목을 따로 나열한다.

세 번째 줄이 핵심이다. "모르면 모른다고 해"는 지시가 아니라 허가다. 모델은 대개 빈칸을 채우도록 압박받은 상태로 응답한다. 그 압박을 명시적으로 풀어줘야 한다.

네 번째 줄은 실무용이다. 확률을 말하게 하면 숫자가 또 하나의 환각이 된다. 대신 "확인 필요 항목"으로 분리하면 사람이 검수할 목록이 남는다.

관련 글: 프롬프트 작성법 — 좋은 예·나쁜 예 10쌍에서 근거를 고정하는 방식을 더 자세히 다뤘다.

검색을 붙여도 사라지지 않는 이유

RAG는 환각을 줄이는 데 확실히 도움이 된다. 다만 구조적으로 0이 되지 않는 이유가 있다. 검색이 틀린 문서를 가져오면 모델은 그 틀린 문서를 성실하게 요약한다. 문서는 맞는데 질문과 다른 부분을 인용하는 경우도 많다.

앞의 법률 도구 사례가 정확히 이 지점이다. RAG를 쓰는 상용 도구들이 17~33%에서 틀렸다. 검색 대상이 판례 데이터베이스처럼 정제돼 있어도 그렇다.

그래서 나는 RAG를 "정확도 장치"가 아니라 "근거를 대는 장치"로 본다. 답과 함께 원문 위치가 나오면 사람이 검증할 수 있다. 검증 가능성이 RAG의 진짜 값이다. (RAG가 뭐야 (검색증강생성))

내가 막혔던 곳

처음엔 temperature를 낮추면 해결되는 줄 알았다. 0으로 두고 돌렸는데도 없는 API 파라미터를 자신 있게 설명했다. temperature는 확률 분포의 뾰족함을 조절할 뿐, 없는 지식을 만들어내지는 않는다. 이걸 몰라서 한동안 엉뚱한 파라미터만 만졌다.

두 번째는 "모른다고 해"를 너무 세게 걸었을 때다. 아는 것까지 모른다고 답해서 쓸모가 없어졌다. 지금은 자료 범위를 명시하고, 그 범위 밖 질문에만 거절하도록 조건을 붙인다.

세 번째는 내 자동화에서 나온 실수다. 모델이 "공식 문서에 따르면"이라며 링크를 만들어 붙였고, 나는 그럴듯해서 그대로 초안에 넣었다. 나중에 링크 검사 스크립트를 돌려보니 절반이 404였다. 그 뒤로 숫자와 링크는 모델 말을 믿지 않고 직접 연다. 이 글의 수치도 전부 원문을 열어 확인했다.

참고 자료

반응형
반응형
LLM wiki 구축 — 100명 조직은 사람 수가 아니라 질문 경계로 나눈다

앞 글에서 LLM wiki와 RAG의 차이를 정리했다. 그 글을 읽고 바로 나온 질문이 "조직원이 100명이면 위키가 너무 커지지 않나"였다. 맞는 지적이다. 카파시가 말한 규모는 개인 지식베이스 기준이라, 100명 조직에 그대로 갖다 붙이면 인덱스가 컨텍스트를 넘는다.

이 글은 그다음 질문에 답한다. 사람 수로 상한을 둘지, 사업별로 나눌지, 팀별로 나눌지. 결론은 셋 다 아니다. 질문의 경계로 나눈다.

100명 조직의 LLM wiki는 공통 1개와 도메인 4~6개로 나눈다.


30초 요약

궁금한 것답
나누는 기준사람 수가 아니라 질문의 경계
기본 구조L0 공통 1개 + L1 도메인 4~6개 + L2 팀·프로젝트 원본
쪼개는 트리거인덱스 8,000토큰 초과, 질문 겹침 20% 미만, 권한 등급 차이
합치는 트리거교차 링크 20% 초과, 같은 개념 페이지 중복
100명 예시공통 + 도메인 4~5개, 큐레이터 도메인당 1명
주의인사·계약·고객 개인정보는 위키에 넣지 않는다

목차

  1. 100명이면 왜 커지는가
  2. 사람 수로 상한을 두면 안 되는 이유
  3. 사업별·팀별 분할이 어긋나는 지점
  4. 기준은 질문의 경계다 — 3층 연합 구조
  5. 쪼개고 합치는 트리거
  6. 100명 기준 현실 분할
  7. 운영 규칙 — 쓰기·승인·권한
  8. 내가 막혔던 곳

100명이면 왜 커지는가

카파시 원문이 말한 규모는 "약 100개 자료, 수백 페이지"다. Atlan 정리 글과 Decode the Future는 실용 상한을 대략 5만~10만 토큰으로 본다. 페이지 한 장이 300~500토큰이니 150~250페이지 정도다.

조직은 이 선을 쉽게 넘는다. 온보딩 문서, 회의록, 제품 스펙, 영업 자료, 장애 대응 기록이 각각 쌓인다. 100명이면 도메인 하나가 200~300페이지가 되는 건 시간문제다. 문제는 총량이 아니라 인덱스다. index.md에 페이지마다 한 줄씩 붙으면 300페이지에서 6,000~9,000토큰이 된다. 여기에 본문 몇 장을 더하면 컨텍스트가 금방 찬다.

사람 수로 상한을 두면 안 되는 이유

사람 수는 지식량과 상관이 없다. 100명이 같은 온보딩 질문을 하고 같은 규정을 찾으면 위키는 하나로 충분하다. 반대로 10명이 서로 다른 다섯 도메인을 다루면 위키는 다섯 개가 맞다.

사람 수가 실제로 영향을 주는 곳은 따로 있다.

  • 동시 편집 충돌: 같은 페이지를 여러 명이 동시에 고치면 병합 비용이 생긴다. 다만 이건 쓰기를 LLM 한 곳으로 모으면 대부분 사라진다.
  • 큐레이션 인력: 100명이면 도메인마다 승인자를 둬야 한다. 사람 수는 위키를 자르는 기준이 아니라 큐레이터를 배치하는 기준이다.
  • 질문의 다양성: 사람이 많을수록 질문 종류가 늘지만, 그 질문이 몇 개의 덩어리로 묶이는지가 실제 분할 단위다.

사람 수로 자르면 같은 내용이 여러 위키에 복제되고, 경계를 걸치는 질문은 어디서도 답이 안 나온다.

사업별·팀별 분할이 어긋나는 지점

사업별 분할은 사업 단위가 곧 질문 단위일 때만 맞다. 인사·재무·IT·총무 같은 공통 기능이 빠지면 각 사업 위키에 같은 규정 페이지가 생긴다. 나중에 규정이 바뀌면 다섯 곳을 고쳐야 한다.

팀별 분할은 대체로 너무 잘다. 팀 위키가 열 개를 넘으면 "이건 어느 팀 거지" 문제가 시작된다. 팀을 넘는 질문, 예를 들어 "신규 고객 온보딩이 영업에서 운영으로 넘어갈 때 뭐가 빠지나" 같은 질문은 어느 팀 위키에도 온전히 담기지 않는다.

팀은 위키를 나누는 단위가 아니라 원본을 넣는 단위로 쓰는 게 맞다. 팀별 raw/ 폴더를 두고, 승격할 것만 도메인 위키로 올린다.

기준은 질문의 경계다 — 3층 연합 구조

wiki-common/          L0 전사 공통 — 용어, 규정, 결정 로그, 온보딩
  index.md            메타 인덱스: 도메인 위키 목록 + 각 범위 한 줄
wiki-product/         L1 도메인 — 제품·기술
wiki-sales/           L1 도메인 — 영업·마케팅
wiki-ops/             L1 도메인 — 운영·CS
wiki-finance/         L1 도메인 — 재무·법무
raw-<team>/           L2 팀·프로젝트 원본 (공유 안 함)

핵심은 공통 위키의 index.md가 인덱스의 인덱스 역할을 한다는 점이다. 질문이 들어오면 LLM이 먼저 공통 인덱스를 읽고 어느 도메인 위키로 가야 하는지 판단한다. 도메인 위키는 자기 인덱스에서 페이지를 고른다. 이렇게 하면 전체 위키가 10만 토큰을 넘어도, 한 번에 읽는 양은 인덱스와 페이지 몇 장으로 유지된다.

L0 공통 위키는 100~150페이지 안으로 묶는다. 소유자는 1~2명. 여기에 조직 용어, 의사결정 로그, 온보딩, 부서 간 약속을 둔다. 모든 질문이 한 번은 거쳐 가는 층이라 작고 정확해야 한다.

쪼개고 합치는 트리거

쪼개는 트리거와 합치는 트리거. 숫자는 내가 쓰는 운영 기준이다.

방향트리거판단 방법
쪼개기인덱스가 8,000토큰 초과index.md를 세어 본다. 페이지 250~300장 선
쪼개기질문 겹침 20% 미만두 집단이 서로의 페이지를 거의 안 읽는다
쪼개기권한 등급 차이인사·계약·고객 개인정보가 섞여 있다
합치기교차 링크 20% 초과두 위키가 전체 링크의 5분의 1 이상을 서로에게 쓴다
합치기같은 개념 페이지 중복한쪽을 지우고 공통으로 승격한다
합치기소유자가 같다큐레이터가 한 명이면 위키도 하나가 낫다

8,000토큰은 내가 쓰는 기준이다. 모델 컨텍스트가 커지면 늘릴 수 있지만, 인덱스가 커질수록 LLM이 고르는 정확도는 떨어진다. 인덱스는 "읽는 목록"이지 "검색 결과"가 아니라는 점을 기억해야 한다.

100명 기준 현실 분할

위키범위페이지 목표큐레이터
공통용어, 규정, 결정 로그, 온보딩100~1501~2명
제품·기술스펙, 아키텍처, 장애 기록200~3001명
영업·마케팅제안서, 가격 정책, 캠페인150~2001명
운영·CS매뉴얼, 문의 유형, 에스컬레이션150~2001명
재무·법무계약, 정산, 컴플라이언스100~1501명

마크다운 폴더에 하이브리드 검색을 붙이는 qmd 저장소. 2026년 11월 3일 직접 캡처했다.

여기서 재무·법무는 특히 조심해야 한다. 위키는 파일 묶음이라 페이지 단위 권한을 쪼개기 어렵다. 계약 단가, 인사 평가, 고객 개인정보는 위키에 넣지 말고 RAG와 문서 권한으로 남긴다. 위키에는 "어떤 문서가 어디에 있고 누가 승인했는지"만 둔다.

큐레이터의 일은 글쓰기가 아니다. 인제스트 결과를 읽고, 승격할지 말지 정하고, 모순을 표시하고, 죽은 페이지를 지우는 일이다. 도메인당 주 2~3시간이면 돌아간다.

운영 규칙 — 쓰기·승인·권한

  • 쓰기는 LLM만. 사람은 raw/에 자료를 넣고 지시한다. 사람이 직접 페이지를 고치면 스키마와 링크가 깨진다.
  • 큐레이터는 승인자. 인제스트가 만든 페이지를 그대로 공개하지 않는다. 표본을 읽고 승인한다.
  • frontmatter를 강제한다. owner, last_reviewed, sources, status가 없으면 lint에서 걸리게 한다.
  • 주간 lint. 끊긴 링크, 고아 페이지, 90일 지난 페이지, 출처와 어긋난 문장을 점검한다.
  • 승격 규칙. 두 위키에서 세 번 이상 참조된 개념은 공통 위키로 올린다. 반대로 공통에 있는데 아무도 안 읽으면 내린다.
  • 검색 계층. 도메인 위키가 4개를 넘으면 통합 검색을 붙인다. qmd는 마크다운 폴더에 BM25와 벡터를 섞어 로컬에서 검색하는 도구다. 이걸 붙이는 순간 위키는 RAG와 결합한다. 그게 나쁜 게 아니라, 100명 규모에서는 자연스러운 다음 단계다.

인제스트 비용도 예산에 넣어야 한다. Decode the Future는 인제스트 한 번에 원본 토큰의 5~8배가 든다고 추정한다. 100명 조직이면 매일 전체를 다시 컴파일하지 말고, 도메인별로 주 1회 또는 자료가 들어올 때만 배치로 돌리는 편이 현실적이다.

내가 막혔던 곳

내 작업 폴더가 이 구조의 축소판이다. 공통 기억 파일 하나와 도메인별 폴더(강의, 자동차, 집안, 블로그), 그리고 그 위의 검색 인덱스가 있다. 처음엔 공통 파일 하나로 시작했다. 6개월쯤 지나니 공통 파일이 인덱스 역할을 못 할 만큼 길어졌다. 그래서 지금은 공통 파일에는 "어디에 무엇이 있다"만 남기고, 세부는 도메인 폴더로 내렸다.

두 번째로 막힌 건 검색이었다. 임베딩 인덱스가 조용히 죽어서 아무것도 못 찾은 날이 있었다. 그때 살아 있던 건 평문 마크다운과 SQLite FTS 색인이었다. 파일은 언제나 읽을 수 있으니 답은 할 수 있었다. 이 경험으로 두 가지를 배웠다. 위키는 검색이 죽어도 읽혀야 하고, 검색은 위키를 대체하지 않는다.

세 번째는 더 뼈아팠다. 위키가 커지는 것보다 소유자가 없는 것이 먼저 문제였다. 페이지는 늘어나는데 아무도 린트를 안 돌리면, 같은 내용이 세 곳에 다른 표현으로 남는다. 100명 조직이라면 크기보다 큐레이터 배치가 먼저다. 위키 하나에 이름 붙은 소유자가 없으면 그 위키는 이미 죽은 것이다.

앞 글에서 정리한 LLM wiki와 RAG의 차이는 LLM wiki란? RAG 차이에, RAG의 기본 원리는 RAG가 뭐야 (검색증강생성)에 있다. 컨텍스트 설계는 하네스란?과 이어진다.

참고 자료

반응형
반응형
LLM wiki란? RAG 차이 — 카파시 위키 방식, 잘 만든 RAG와 같이 쓰는 법

"RAG는 이제 끝났다"는 제목의 글을 요즘 자주 본다. 근거로 나오는 게 안드레이 카파시가 2026년 4월에 올린 llm-wiki 긴급 메모다. 그런데 원문을 읽어보면 "RAG를 버려라"가 아니라 "지식을 매번 다시 찾지 말고, 한 번 정리해서 쌓아두라"에 가깝다.

이 글은 LLM wiki가 정확히 무엇인지, RAG와 어디서 갈리는지, 그리고 잘 만든 RAG가 왜 여전히 필요한지를 정리한다. 결론부터 말하면 둘은 대체 관계가 아니다.

LLM wiki와 RAG는 지식을 언제 정리하느냐에서 갈린다.


30초 요약

궁금한 것답
LLM wiki원본을 LLM이 읽어 마크다운 위키로 미리 컴파일해 두는 방식. 카파시가 2026-04-03 공개
RAG질문이 올 때마다 문서 조각을 검색해서 프롬프트에 붙이는 방식
핵심 차이지식을 넣을 때 정리하느냐(컴파일), 물을 때 찾느냐(검색)
LLM wiki 한계대략 5만~10만 토큰. 그 위로는 인덱스가 컨텍스트를 넘는다
잘 만든 RAG여전히 좋다. 대용량·최신·권한 분리가 필요한 곳에서는 사실상 정답
실무 결론안정된 지식은 위키(L1), 크고 자주 바뀌는 지식은 RAG(L2)

목차

  1. LLM wiki란? — 카파시가 공개한 3층 구조
  2. RAG와의 차이는 '언제 정리하느냐'다
  3. LLM wiki가 이기는 경우
  4. 잘 만든 RAG는 여전히 좋다
  5. 규모와 조건으로 고르는 표
  6. 직접 만들어 보기 — 폴더 3개와 schema 하나
  7. 내가 막혔던 곳
  8. 실무 결론 — 위키는 L1, RAG는 L2

LLM wiki란? — 카파시가 공개한 3층 구조

원문 gist는 "LLM으로 개인 지식베이스를 만드는 패턴"이라는 한 줄로 시작한다. 문서를 올리고 질문할 때마다 조각을 찾는 대신, 새 자료가 들어올 때 LLM이 읽고 기존 위키 페이지를 고쳐 쓰는 구조다.

층은 세 개다.

층내용누가 쓰나
raw/PDF, 논문, 기사, 스크린샷 같은 원본사람이 모은다. LLM은 읽기만
wiki/개념·인물·비교·연표 페이지. 서로 링크로 연결LLM이 전부 쓰고 고친다
schemaCLAUDE.md 같은 편집 규칙. 이름 규칙, 모순 처리, 인제스트 절차사람과 LLM이 같이 다듬는다

동작은 세 가지다. 인제스트는 새 자료를 읽고 관련 페이지 10~15개를 한 번에 갱신한다. 쿼리는 index.md를 먼저 읽고 필요한 페이지만 골라 답한다. 린트는 페이지 사이 모순, 끊긴 링크, 고아 페이지를 주기적으로 점검한다.

카파시가 강조한 건 유지보수의 주체다. 위키가 무너지는 이유는 읽기가 귀찮아서가 아니라 상호참조·요약 갱신·모순 표시 같은 잡일이 쌓여서다. 그 잡일을 LLM이 대신하면 위키가 관리되는 상태로 유지된다. 원문 표현대로 "Obsidian이 IDE, LLM이 프로그래머, 위키가 코드베이스"다.

RAG와의 차이는 '언제 정리하느냐'다

RAG는 질문이 들어온 순간 관련 청크를 찾아 프롬프트를 조립한다. 같은 문서를 다섯 개 읽어야 하는 질문이면, 그 다섯 조각을 매번 새로 찾아 붙인다. Atlan의 비교 글은 이 차이를 컴파일 시점 대 질의 시점이라고 정리한다.

왼쪽이 미리 컴파일하는 LLM wiki, 오른쪽이 질문할 때 검색하는 RAG다.

구분LLM wikiRAG
지식 상태누적된다. 넣을수록 두꺼워짐매 질문마다 처음부터 검색
검색 신뢰도컨텍스트에 다 들어가면 사실상 100%청킹·임베딩·top-k 품질에 의존
규모 상한대략 5만~10만 토큰수백만 문서
인프라마크다운 파일과 에이전트뿐벡터DB, 임베딩 파이프라인, 검색 API
질문당 비용고정적 (인덱스+몇 페이지)가변적 (검색된 조각만)
여러 문서 종합미리 연결돼 있어 강함검색 재현율에 따라 흔들림
유지보수LLM이 잡일 처리재색인, 청크 튜닝, 임베딩 드리프트
종속성사실상 없음 (평문 파일)벡터DB·임베딩 모델에 묶임

표만 보면 위키가 이기는 것 같지만, 규모 상한이 전부를 바꾼다. 인덱스가 컨텍스트를 넘는 순간 위키는 "읽을 수 있는 목록"이 아니라 그냥 파일 더미가 된다. 그때부터는 검색 계층이 반드시 필요하다.

LLM wiki가 이기는 경우

카파시가 말한 규모는 "약 100개 자료, 수백 페이지"다. 이 범위에서는 위키가 단순하고, 빠르고, 디버깅하기 쉽다.

  • 주제가 좁고 안정적일 때. 사내 규정, 강의 노트, 한 분야 논문, 책 한 권처럼 경계가 분명한 지식.
  • 여러 문서를 합쳐야 하는 질문이 많을 때. "A 문서와 B 문서가 충돌하는 부분은?" 같은 질문은 조각 검색보다 미리 표시해 둔 모순 페이지가 훨씬 정확하다.
  • 지식이 쌓여야 할 때. 같은 질문을 세 번 하면 세 번 다 처음부터 찾는 RAG와 달리, 위키는 답변 자체를 새 페이지로 남길 수 있다.
  • 인프라를 만들기 싫을 때. 마크다운 폴더와 git이면 끝난다. 검색이 필요해지면 qmd 같은 로컬 검색을 나중에 붙이면 된다.

비용 구조도 알아둘 만하다. 인제스트 한 번에 원본 토큰의 대략 5~8배가 든다는 추정이 Decode the Future 정리 글에 나온다. 10페이지 PDF 하나가 위키 12개 파일을 건드릴 수 있으니, 넣을 때는 비싸고 물을 때는 싸다.

잘 만든 RAG는 여전히 좋다

여기가 이 글에서 제일 중요한 부분이다. "LLM wiki가 RAG를 이긴다"는 말은 잘 만든 RAG 앞에서는 성립하지 않는다.

RAG가 이기는 조건은 명확하다.

  • 문서가 컨텍스트보다 클 때. 수만~수백만 건이면 위키 인덱스는 애초에 안 들어간다.
  • 지식이 자주 바뀔 때. 가격, 재고, 티켓, 오늘의 공지. 인제스트를 매시간 돌리는 것보다 검색이 싸다.
  • 사용자별 권한이 다를 때. 위키는 파일 하나에 다 들어 있어 권한을 쪼개기 어렵다. RAG는 검색 단계에서 문서를 걸러낼 수 있다.
  • 출처를 한 줄 단위로 대야 할 때. 규정·계약·감사 대응은 "이 문장이 어느 문서 몇 쪽"까지 필요하다. RAG의 청크 인용이 유리하다.
  • 롱테일 질문이 많을 때. 무엇을 물을지 모르는 상태에서는 미리 정리해 둘 수도 없다.

그리고 "잘 만든" RAG는 생각보다 많은 걸 한다. 구조를 존중하는 청킹, BM25와 벡터를 섞는 하이브리드 검색, 리랭커, 질문 재작성, 평가 세트, 인용 강제. 이런 게 갖춰진 RAG는 순진한 위키보다 정확하다. 반대로 청크를 500자로 균등하게 자르고 top-3만 붙이는 RAG라면, 위키가 이기는 게 당연하다.

비교는 늘 잘 만든 쪽과 못 만든 쪽 사이에서 벌어진다. 도구 이름 사이에서 벌어지지 않는다.

규모와 조건으로 고르는 표

카파시가 공개한 llm-wiki 원문 gist. 2026년 11월 3일 직접 캡처했다.

상황추천이유
개인 노트, 강의 준비, 한 주제 연구LLM wiki10만 토큰 이하, 종합 질문이 많음
팀 위키, 회의록, 프로젝트 문서위키 + 가벼운 검색사람이 큐레이션, LLM이 정리
사내 규정·계약 검색RAG (+권한)문서량, 감사, 접근 제어
고객지원, 최신 공지RAG갱신 주기가 짧음
위 둘이 섞인 실무하이브리드안정 지식은 위키, 나머지는 RAG

직접 만들어 보기 — 폴더 3개와 schema 하나

카파시 원문은 "복사해서 네 에이전트에 붙여넣으라"고 되어 있다. 최소 구성은 이 정도다.

mkdir -p my-wiki/{raw,wiki}
touch my-wiki/wiki/index.md
touch my-wiki/wiki/log.md
touch my-wiki/CLAUDE.md

CLAUDE.md에는 편집 규칙을 적는다. 핵심은 세 가지다.

## 규칙
- 하나의 개념 = wiki/ 아래 파일 하나
- 모든 페이지는 제목 → 두 문장 요약 → 태그 → 본문 순서
- 관련 페이지는 [[페이지-이름]] 으로 연결
- 자료가 충돌하면 덮어쓰지 말고 양쪽을 인용해 표시

## 인제스트 절차
1. raw/ 새 자료를 끝까지 읽는다
2. 개념·인물·주장을 뽑는다
3. 해당 위키 페이지를 만들거나 고친다
4. 상호참조와 index.md를 갱신한다
5. log.md에 날짜와 함께 한 줄 남긴다

## 린트 체크
- index.md에 없는 페이지가 있는가
- 끊긴 [[링크]]가 있는가
- 같은 개념을 다루는 페이지가 두 개인가
- 출처와 어긋난 문장이 있는가

자료를 넣을 때는 이렇게 말하면 된다.

raw/2026-규정집.pdf를 읽고 CLAUDE.md 스키마대로 인제스트해줘.
관련 페이지를 새로 만들거나 갱신하고, 충돌하는 내용은 표시해줘.
마지막에 index.md와 log.md도 업데이트해.

여기서 끝내면 반쪽이다. 일주일에 한 번은 린트를 돌려야 한다. 위키는 방치하면 조용히 썩는다. 이건 RAG의 재색인과 같은 일이다.

내가 막혔던 곳

내 작업 폴더에도 성격이 다른 두 지식층이 같이 있다. 하나는 MEMORY.md와 날짜별 노트, 다른 하나는 그걸 임베딩으로 검색하는 인덱스다. 앞은 위키, 뒤는 RAG다.

문제는 임베딩 인덱스가 조용히 죽을 때였다. 어느 날 검색이 "index metadata is missing"만 뱉고 아무것도 못 찾았다. 벡터 검색이 안 되면 RAG 기준으로는 지식이 0이 된다. 그때 살아 있던 건 평문 마크다운 파일과 SQLite FTS 색인이었다. 파일은 언제나 읽을 수 있으니, 검색이 죽어도 답은 할 수 있었다.

그래서 지금은 검색이 실패하면 FTS로 내려가고, 답을 하기 전에 원문 파일을 다시 확인한다. 위키가 원본에 대한 포인터 역할을 하고, RAG는 찾는 속도를 담당하는 식이다. 어느 한쪽만 믿었으면 그날 답을 못 했다.

두 번째로 막힌 건 드리프트다. 날짜별 노트는 계속 쌓이는데 MEMORY.md는 자동으로 갱신되지 않는다. 몇 주 지나면 같은 내용이 세 곳에 다른 표현으로 적혀 있다. 이건 검색 문제가 아니라 큐레이션 문제다. 카파시가 린트를 따로 둔 이유를 그때 이해했다.

실무 결론 — 위키는 L1, RAG는 L2

둘 중 하나를 고르는 질문이 아니다. 어디에 무엇을 둘지의 문제다.

지식 종류두는 곳
용어, 원칙, 결정 기록, 자주 쓰는 절차위키 (항상 컨텍스트에)
대용량 문서, 최신 데이터, 권한별 자료RAG (필요할 때 검색)
위키에서 자주 나오는 질문의 답위키 페이지로 승격
위키에서 다 못 담는 세부 원문원본 링크로 연결

잘 만든 RAG는 좋다. 다만 RAG만 있으면 같은 질문에 매번 처음부터 답하고, 그 답이 어디에도 쌓이지 않는다. 위키만 있으면 규모가 커지는 순간 멈춘다. 위키를 L1 캐시, RAG를 L2 저장소로 두는 쪽이 실무에서 오래 간다.

RAG의 기본 원리와 실패 원인은 RAG가 뭐야 (검색증강생성)에 따로 정리해 뒀다. 에이전트가 어떤 도구와 권한을 갖느냐는 AI 에이전트란?에서, 컨텍스트를 어떻게 설계하느냐는 하네스란?에서 이어진다. 위키를 코드베이스처럼 다루고 싶다면 Claude Code 설치·사용법부터 보면 된다.

참고 자료

반응형
반응형
k-skill 사용법 — Skills.sh로 KTX·로또·홈택스까지 AI에게 시키는 법

깃허브에서 k-skill 저장소가 별 8천 개를 넘겼다. 코딩 에이전트에게 "KTX 시간표 찾아줘", "로또 당첨번호 알려줘", "홈택스에서 원천징수 내역 뽑아줘"를 시킬 수 있게 만든 한국 서비스 스킬 모음집이다.

그 스킬들을 검색하고 한 줄로 설치하는 곳이 Skills.sh다. 이 글은 Skills.sh가 뭔지, k-skill을 실제로 어떻게 설치하는지, 설치하면 내 컴퓨터 어디에 무엇이 생기는지를 순서대로 정리한다.

30초 요약

궁금한 것답
Skills.sh에이전트 스킬을 모아둔 공개 디렉터리 + 설치 CLI. Vercel Labs가 만들었다
설치 명령npx skills add <owner>/<repo>
k-skill한국 서비스 146개를 에이전트에 연결하는 스킬 모음집 (skills.sh 기준)
한 줄 설치npx --yes skills add NomaDamas/k-skill --all -g
설치 위치-g를 붙이면 홈(~/.claude/skills), 빼면 현재 프로젝트의 .claude/skills
지원 에이전트Claude Code, Codex, Cursor, OpenCode 등 89개 (skills.sh 표기)
주의스킬은 에이전트 전체 권한으로 실행된다. 설치 전에 SKILL.md를 읽어야 한다

목차

  1. Skills.sh란? — 스킬을 찾고 설치하는 곳
  2. Skills.sh와 MCP는 무엇이 다른가
  3. k-skill이란? — 한국 서비스 146개
  4. 설치 — npx 한 줄
  5. 설치하면 어디에 무엇이 생기나
  6. 어떤 스킬부터 쓸까 — 추천 4개
  7. 내가 막혔던 곳
  8. 안전하게 쓰는 법
  9. 참고 자료

Skills.sh란? — 스킬을 찾고 설치하는 곳

에이전트 스킬은 SKILL.md 파일 하나로 이루어진다. 앞부분(frontmatter)에 name, description을 적고, 본문에 "이런 상황이면 이 순서로 하라"는 절차를 쓴다. 에이전트는 대화 중에 관련 스킬이 필요해지면 그때 본문을 읽는다.

이 형식은 Agent Skills 오픈 표준으로 정리됐고, Claude Code는 이 표준을 그대로 따른다. 예전 .claude/commands/에 넣던 커스텀 명령도 스킬로 통합됐다. /deploy 같은 명령을 스킬로 만들면 지원 파일을 같이 둘 수 있고, 내가 부르지 않아도 상황에 맞으면 에이전트가 알아서 꺼내 쓴다.

Skills.sh는 그 스킬들을 모아 검색·설치하게 해주는 디렉터리다. 사이트에서 스킬을 찾고, 설치는 npx skills CLI로 한다. CLI는 vercel-labs/skills에 MIT 라이선스로 공개돼 있고, 사이트에는 2026년 11월 2일 기준 89개 에이전트가 지원 목록에 올라 있다.

명령하는 일
npx skills find [검색어]스킬 검색 (대화형)
npx skills add owner/repo저장소의 스킬 설치
npx skills use owner/repo@스킬설치 없이 프롬프트로만 사용
npx skills list설치된 스킬 목록
npx skills check / update업데이트 확인·적용
npx skills remove삭제
npx skills init 내스킬내 스킬 템플릿 만들기

Skills.sh 첫 화면 — 스킬 검색, 추천 목록, 설치 명령이 한 화면에 있다

이 구조의 장점은 토큰이다. CLAUDE.md는 세션이 시작될 때 통째로 읽히지만, 스킬 본문은 쓸 때만 읽힌다. 그래서 "배포 절차 30줄" 같은 내용은 CLAUDE.md에 두는 것보다 스킬로 빼는 편이 낫다. 이 차이는 하네스(harness)란?에서 다룬 컨텍스트 설계와 같은 맥락이다.

Skills.sh와 MCP는 무엇이 다른가

둘 다 "에이전트에게 능력을 붙인다"고 설명되지만 층이 다르다. 자주 헷갈리는 부분이라 표로 정리한다.

구분스킬 (SKILL.md)MCP
본질절차·판단 기준을 적은 문서도구·데이터를 노출하는 서버 프로토콜
준비물파일 하나실행 중인 서버(로컬 또는 원격)
예시"한글 문서는 이 순서로 변환한다""파일 시스템에서 읽고 쓴다"
강점가볍고, 읽을 때만 토큰을 쓴다실제 실행·인증·상태를 다룬다
약점실행 능력은 에이전트 도구에 의존서버 관리·권한 설정이 필요

k-skill은 이 둘을 섞어 쓴다. 스킬 문서가 절차를 알려주고, 실제 데이터는 공개 API나 프록시 서버에 HTTP 요청을 넣어 가져온다. 별도 MCP 서버를 띄우지 않아도 되는 구성이다.

k-skill이란? — 한국 서비스 146개

NomaDamas/k-skill은 "한국인을 위한 스킬 모음집"이다. 소개 문구가 정확하다. 언젠가 무조건 쓸 때가 온다.

2026년 11월 2일 기준으로 skills.sh의 k-skill 페이지에는 스킬 146개, 누적 설치 96.8만 회가 찍혀 있고, 깃허브 별은 8.2k다. 저장소 README는 133개라고 적고 있으니, 스킬이 계속 추가되는 중이라고 보면 된다.

영역대표 스킬하는 일
이동·교통railway-timetable코레일 공식 KTX 시간표 조회
이동·교통seoul-subway-arrival서울 지하철 실시간 도착 정보
이동·교통express-bus-booking고속버스 배차·좌석 조회와 예매 보조
부동산real-estate-search아파트·오피스텔 실거래가·전월세
법률·공공korean-law-search법령·판례 검색, 신구조문대비표 생성
사업·세무nts-business-registration사업자등록 상태·진위 확인
금융k-dart, korean-stock-search전자공시·주가 조회
쇼핑coupang-product-search, danawa-price-search상품 검색·최저가 비교
생활delivery-tracking, lotto-results택배 조회, 로또 당첨번호
문서hwp, rhwp-editHWP/HWPX 읽기·변환·편집

설치 순위 상위는 hwp(10.1K), k-skill-setup(10.0K), korean-spell-check(9.6K), korean-law-search(9.6K), daiso-product-search(9.5K) 순이다. 한국에서 문서·행정 업무에 얼마나 수요가 큰지 그대로 드러난다.

skills.sh의 k-skill 페이지 — 스킬 146개, 누적 설치 96.8만 회(2026-11-02 확인)

한 가지 분명히 해둘 것. KTX 스킬은 조회 전용이다. 로그인, 예약, 결제, 취소는 하지 않는다. README에 명시돼 있다. 자동결제까지 기대하고 설치하면 안 된다.

설치 — npx 한 줄

Node.js와 npx만 있으면 된다. 터미널에서 이렇게 실행한다.

# 전체 스킬 설치 (모든 에이전트, 전역)
npx --yes skills add NomaDamas/k-skill --all -g

# 특정 스킬만 설치
npx --yes skills add NomaDamas/k-skill --skill railway-timetable -g

# 설치된 스킬과 CLI를 한 번에 최신으로
npx -y @nomadamas/k-skill@0 update

# 어떤 스킬이 있는지 먼저 보기 (설치 안 함)
npx --yes skills add NomaDamas/k-skill --list

-g는 전역 설치다. 이게 있고 없고가 생각보다 크게 갈린다.

실행 위치-g 없음-g 있음
설치 경로./.claude/skills/~/.claude/skills/
보이는 범위그 프로젝트에서만모든 프로젝트
락 파일./skills-lock.json홈 디렉터리 기준
추천팀 프로젝트에 스킬을 고정할 때개인 노트북에서 두루 쓸 때

Claude Code는 스킬을 자동으로 인식한다. 설치 후 /hwp처럼 슬래시로 직접 부를 수도 있고, "이 한글 문서 읽어줘"라고 하면 관련 스킬을 스스로 꺼내기도 한다. Claude Code 자체가 처음이라면 Claude Code 설치·사용법을 먼저 보는 편이 빠르다.

설치하면 어디에 무엇이 생기나

빈 폴더에서 hwp 하나만 설치해 봤다. 명령은 이랬다.

mkdir /tmp/kskilltest && cd /tmp/kskilltest
npx --yes skills add NomaDamas/k-skill --skill hwp -a claude-code -y

설치가 끝나면 CLI가 보안 평가표를 보여준다. Gen, Socket, Snyk 세 곳의 자동 검사 결과다.

◇  Security Risk Assessments
│       Gen               Socket            Snyk
│  hwp  Safe              0 alerts          Low Risk
◇  Installed 1 skill
│  K Skill
│  ✓ hwp (copied)
│    → ./.claude/skills/hwp

폴더에는 파일 세 개가 생긴다.

/tmp/kskilltest/
├── skills-lock.json          # 설치한 스킬과 해시 고정
└── .claude/skills/hwp/
    ├── SKILL.md              # 에이전트가 읽는 진입점
    ├── instruction.md        # 실제 절차 본문
    └── skill.json            # 메타데이터

SKILL.md를 열어보면 길이가 1,594바이트밖에 안 된다. 내용은 이렇다.

---
name: hwp
description: Use kordoc for agent-native HWP/HWPX document parsing, JSON extraction, ...
license: MIT
metadata:
  category: documents
  locale: ko-KR
---

<!-- k-skill:cli-stub — generated by scripts/generate-skill-stubs.js -->

## Get the full instructions (required first step)

Run this and follow its output as the primary instructions for this skill:

npx -y @nomadamas/k-skill@0 instruct hwp

여기가 중요하다. 설치된 SKILL.md는 안내문이고, 진짜 절차는 실행할 때 instruct 명령으로 받아온다. 그래서 첫 실행에는 네트워크가 필요하고, 스킬 본문을 고쳐도 원본이 바뀌면 다시 받아와야 한다.

skills-lock.json에는 설치한 스킬의 출처와 해시가 남는다. 나중에 다른 컴퓨터에서 npx skills experimental_install로 같은 구성을 복원할 수 있다.

어떤 스킬부터 쓸까 — 추천 4개

146개를 다 깔면 컨텍스트만 늘어난다. 실제로 자주 쓸 것부터 네 개만 고르면 이렇다.

스킬고른 이유
hwp강의 자료·청구서·공문이 아직 한글 파일이다. 읽기만 돼도 반나절이 줄어든다
korean-spell-check블로그 초안을 붙여넣고 교정하는 왕복이 사라진다. 실패해도 손해가 없다
delivery-tracking송장번호 복사·붙여넣기보다 "택배 어디쯤이야"가 빠르다
real-estate-search이사·투자 판단에 쓰는 숫자라 출처가 공개 데이터여야 한다. 이 스킬은 실거래가를 직접 조회한다

고르는 기준은 두 가지다. 실패했을 때 손해가 작은가, 그리고 하루에 두 번 이상 반복하는 일인가. 반대로 결제·예약·신청처럼 되돌릴 수 없는 작업은 스킬에게 맡기기 전에 한 번 더 확인하는 게 좋다.

내가 막혔던 곳

1. 사이트가 비어 보인다.

curl https://skills.sh로 확인했더니 ASCII 로고와 한 줄 소개만 나왔다. 나머지는 자바스크립트로 그려지기 때문이다. 스킬 목록은 사이트 HTML이 아니라 npx skills find나 저장소 README에서 보는 게 정확하다.

깃허브 NomaDamas/k-skill 저장소 — 카테고리별 스킬표와 설치 명령

2. -g를 빼고 설치해서 안 보였다.

처음엔 프로젝트 폴더에서 그냥 npx --yes skills add NomaDamas/k-skill --all을 돌렸다. 설치는 성공했는데 다른 폴더에서 연 세션에서는 스킬이 하나도 안 보였다. -g가 없으면 현재 프로젝트에만 깔린다. 개인 노트북에서 두루 쓰려면 -g를 붙여야 한다.

3. Node 버전이 걸린다.

skills CLI 저장소는 Node.js 22.20 이상을 요구한다. k-skill README는 18 이상이라고 적혀 있어서 문서만 보고 낮은 버전으로 맞추면 CLI에서 막힌다. 둘 중 높은 쪽인 22 이상으로 맞추는 게 안전하다.

4. 보안 평가표가 통과 도장이 아니다.

설치 로그에 Safe, 0 alerts, Low Risk가 뜨니 검사에 합격한 줄 알았다. 이건 자동 스캔 결과를 보여주는 참고 지표다. CLI도 마지막 줄에 "스킬은 에이전트 전체 권한으로 실행되니 쓰기 전에 검토하라"고 적어둔다.

안전하게 쓰는 법

스킬은 코드가 아니라 문서지만, 그 문서를 읽는 주체가 내 파일과 터미널을 다룰 수 있는 에이전트다. 그래서 설치 전 확인이 필요하다.

  • 설치 전에 SKILL.md와 instruction.md를 읽는다. 어떤 명령을 실행하고 어디로 요청을 보내는지 확인한다.
  • 프록시를 거치는 스킬은 k-skill-proxy 개인정보 처리방침을 본다. 공공데이터 API 키를 대신 넣어주는 구조라, 어떤 값이 오가는지 알아야 한다.
  • 사용 통계를 끄려면 KSKILL_ANALYTICS_DISABLED=1, skills CLI 쪽은 DISABLE_TELEMETRY=1 또는 DO_NOT_TRACK=1을 설정한다.
  • 사내망에서는 스킬이 외부로 요청을 보낼 수 있다는 점을 먼저 확인한다. 화이트리스트에 없는 도메인이면 설치하지 않는 편이 낫다.
  • 공개 웹 화면을 긁어오는 스킬은 사이트 개편에 약하다. 갑자기 실패하면 스킬 업데이트를 먼저 확인한다.

이런 권한 구조는 AI 에이전트란?에서 정리한 "도구·권한" 문제와 같다. 에이전트가 강해질수록 스킬 하나를 설치하는 일이 곧 권한을 주는 일이 된다.

참고 자료

반응형
반응형
AI 에이전트란? — 챗봇과 다른 점을 4단계 루프로 정리

"AI 에이전트"라는 말이 2026년 들어 회사 소개서마다 붙었다. 그런데 막상 물어보면 답이 제각각이다. 어떤 사람은 챗봇을 부르고, 어떤 사람은 자동화 스크립트를 부르고, 어떤 사람은 클로드 코드를 부른다.

이 글은 그 셋을 구분하는 기준 하나만 남긴다. 누가 다음 행동을 정하는가. 이 기준으로 보면 에이전트가 무엇이고, 어디에 쓰고, 어디에 쓰면 안 되는지가 같이 정리된다.

한 줄 정의: 에이전트는 다음에 뭘 할지 스스로 정하고, 도구로 실행하고, 결과를 보고 다시 판단하는 프로그램이다.

30초 요약

궁금한 것답
무엇목표를 받고 스스로 단계를 정해 도구를 호출하는 LLM 기반 프로그램
챗봇과 차이챗봇은 답을 뱉고 끝, 에이전트는 행동한 뒤 결과를 다시 읽는다
핵심 부품모델 · 도구 · 루프 · 상태(기억) · 권한
판단 기준다음 단계를 코드가 정하면 워크플로, 모델이 정하면 에이전트
연결 표준MCP(Model Context Protocol) — 도구 붙이는 규격
만드는 법직접 API 루프를 짜거나 Agent SDK·Agents SDK를 쓴다
주의느리고 비싸다. 단순 작업엔 오히려 손해

목차

  1. AI 에이전트란? 한 문장 정의
  2. 챗봇·워크플로·에이전트 차이
  3. 에이전트의 4단계 루프
  4. 도구 설계가 성능을 가른다
  5. MCP와 에이전트 SDK — 연결은 표준으로
  6. 파이썬으로 30줄 에이전트 만들기
  7. 내가 막혔던 곳: 멈추지 않는 루프와 권한
  8. 참고 자료

AI 에이전트란? 한 문장 정의

Anthropic은 에이전트를 "LLM이 자기 프로세스와 도구 사용을 스스로 지시하며, 일을 어떻게 해낼지에 대한 통제권을 유지하는 시스템"으로 정의한다. 같은 문서에서 "에이전트는 보통 환경 피드백을 받아가며 도구를 쓰는 LLM 루프에 불과하다"고도 못 박는다. (Anthropic, Building effective agents)

Claude Agent SDK 문서의 표현은 더 짧다. "에이전트는 스스로 단계를 계획하고, 파일을 읽거나 명령을 실행하거나 코드를 고치는 도구를 호출해 작업을 끝내는 애플리케이션"이다. (Agent SDK overview)

두 정의에서 공통으로 나오는 건 계획과 도구 호출이다. 그래서 나는 에이전트를 이렇게 부른다. "스스로 순서를 정하는 도구 사용자." 모델 성능보다 이 순서 정하기가 되는지가 에이전트의 본질이다.

챗봇·워크플로·에이전트 차이

여기서 많이 헷갈린다. 셋 다 LLM을 쓰지만 다음 행동을 정하는 주체가 다르다.

구분다음 단계를 정하는 것예실패했을 때
챗봇없음 (한 번 묻고 한 번 답)고객센터 FAQ 봇답이 틀리면 끝
워크플로미리 짠 코드 경로문서 요약 → 번역 → 검수 파이프라인정해진 분기로만 복구
에이전트모델의 판단"테스트 통과시켜" → 코드 읽고 고치고 재실행스스로 다른 방법을 시도

Anthropic은 이 구분을 특히 강조한다. 워크플로는 LLM과 도구를 미리 정해진 코드 경로로 엮은 시스템이고, 에이전트는 그 경로를 모델이 동적으로 정하는 시스템이다. 둘을 합쳐 agentic system이라고 부른다. (같은 문서)

워크플로 쪽에는 이미 패턴 이름이 붙어 있다. 프롬프트 체이닝, 라우팅, 병렬화, 오케스트레이터-워커, 평가자-최적화자다. 다섯 가지 모두 코드가 흐름을 잡고, 모델은 각 단계에서만 똑똑하게 굴면 된다. 예측 가능성이 필요한 업무는 대개 여기서 끝난다.

내 경험으로도 그렇다. 반복되는 정형 업무는 워크플로가 더 싸고 디버깅이 쉽다. 에이전트가 진짜 값을 하는 건 다음에 뭘 해야 할지 내가 미리 못 쓰는 작업이다. 파일 몇 개를 고쳐야 하는지, 어느 문서를 더 찾아봐야 하는지 모르는 그런 일.

관련 글: 하네스(harness)란? — 에이전트를 감싸는 실행 틀 이야기. 에이전트와 하네스는 층이 다르다.

에이전트의 4단계 루프

에이전트 내부는 화려하지 않다. 대부분 이 네 단계를 돈다.

[목표] "테스트 깨진 거 고쳐줘"
   ↓
① 관찰  : 파일 목록, 에러 로그, 테스트 출력 읽기
   ↓
② 판단  : "test_user.py의 import가 문제다" → 다음 도구 선택
   ↓
③ 행동  : edit_file(...) / run_tests(...) 실행
   ↓
④ 피드백: 결과를 다시 읽고 ②로 돌아감 (끝났으면 종료)

Anthropic이 말한 "환경 피드백을 받아가며 도구를 쓰는 루프"가 정확히 이 모양이다. 여기서 중요한 건 ④번이다. 결과를 실제 환경에서 받아오지 못하는 시스템은 에이전트가 아니라 그냥 긴 프롬프트다.

각 단계에서 실제로 필요한 것도 다르다.

단계필요한 것없으면
① 관찰파일·셸·브라우저 같은 읽기 도구추측으로 코드를 고친다
② 판단계획을 세우는 모델 + 명확한 도구 설명엉뚱한 도구를 부른다
③ 행동실행 권한과 샌드박스사고가 그대로 실행된다
④ 피드백종료 조건, 최대 반복 수영원히 돈다

에이전트가 "똑똑해 보이는" 이유는 ②가 아니라 ①과 ④에 있다. 좋은 모델에 형편없는 도구를 물리면 ①에서 이미 실패한다.

도구 설계가 성능을 가른다

Anthropic 문서에서 반복해서 나오는 조언이 이것이다. 도구 설명을 사람이 읽기 좋게 쓰고, 인터페이스를 좁고 명확하게 만들어라. 모델이 헷갈릴 만한 도구를 두 개 주면, 모델은 둘 다 잘못 쓴다.

내가 도구를 만들 때 지키는 기준은 세 줄이다.

  • 이름만 보고 무슨 일을 하는지 알 수 있어야 한다. do_stuff는 도구가 아니다.
  • 인자는 필수만 남긴다. 선택지가 많을수록 모델이 틀린다.
  • 실패는 예외로 던지지 말고 문자열로 돌려준다. 모델이 읽고 고칠 수 있어야 한다.

마지막 항목이 특히 중요하다. 도구가 조용히 실패하거나 스택트레이스만 뱉으면, 모델은 실패한 걸 모른 채 같은 요청을 반복한다. 실패 사유를 문장으로 돌려주면 다음 턴에서 스스로 경로를 바꾼다.

관련 글: Claude API 사용법 (Python) — 도구 호출(tool use) 루프를 직접 짜는 기본형은 여기 있다.

MCP와 에이전트 SDK — 연결은 표준으로

도구를 붙이는 방식은 2024년 이후로 꽤 정리됐다. Anthropic이 공개한 MCP(Model Context Protocol) 는 AI 애플리케이션과 외부 시스템을 잇는 오픈 표준이다. 공식 문서는 이걸 "AI 애플리케이션용 USB-C 포트"에 비유한다. 한 번 서버를 만들면 클로드, ChatGPT, VS Code, Cursor 같은 클라이언트에서 같은 방식으로 붙는다. (MCP 소개)

스펙은 계속 개정된다. 지금 문서 사이트가 안내하는 리비전은 2026-07-28이다. 도구를 직접 붙일 때 프로토콜 버전을 함께 확인하는 이유가 여기 있다.

SDK 쪽도 선택지가 늘었다. 에이전트를 만들 때 실제로 고르는 갈래는 이렇다.

방식누가 루프를 돌리나특징
직접 API 호출내 코드통제 최대, 코드량 최대
Claude Agent SDK내 프로세스클로드 코드의 도구·권한·세션을 라이브러리로
Claude Managed AgentsAnthropic 호스팅세션·하네스·샌드박스 분리, 인프라 직접 안 굴림
OpenAI Agents SDK내 코드에이전트·핸드오프·가드레일, 트레이싱 내장

OpenAI 쪽은 원시 요소를 작게 유지하는 게 설계 철학이다. 에이전트에 지시문과 도구를 주고, 필요하면 다른 에이전트로 핸드오프하고, 입출력은 가드레일로 검사한다. 설치도 pip install openai-agents 한 줄이다. (OpenAI Agents SDK)

어느 쪽을 고르든 순서는 같다. 먼저 직접 API로 루프를 한 번 짜본다. SDK는 그 루프를 대신 돌려주는 도구지, 루프를 이해해주는 도구가 아니다.

파이썬으로 30줄 에이전트 만들기

개념은 코드로 보는 게 빠르다. 도구 두 개(파일 읽기, 파일 쓰기)만 가진 최소 에이전트다. 모델 호출 부분은 어떤 SDK로 바꿔도 구조가 같다.

import json, subprocess

def read_file(path: str) -> str:
    with open(path, encoding="utf-8") as f:
        return f.read()

def run_tests() -> str:
    p = subprocess.run(["pytest", "-q"], capture_output=True, text=True)
    return (p.stdout + p.stderr)[-2000:]  # 실패 로그는 잘라서 넘긴다

TOOLS = {"read_file": read_file, "run_tests": run_tests}

def agent(goal: str, llm, max_steps: int = 12):
    history = [{"role": "user", "content": goal}]
    for step in range(max_steps):                 # ④ 종료 조건: 최대 반복
        msg = llm(history, tools=TOOLS)           # ② 판단
        history.append(msg)

        if not msg.tool_calls:                    # 도구 호출이 없으면 끝
            return msg.content

        for call in msg.tool_calls:               # ③ 행동
            try:
                result = TOOLS[call.name](**call.args)
            except Exception as e:                # 실패도 문장으로 돌려준다
                result = f"ERROR: {e}"
            print(f"[{step}] {call.name} -> {result[:60]}")
            history.append({"role": "tool", "name": call.name,
                            "content": str(result)})  # ① 관찰
    return "중단: 최대 단계 초과"

여기서 눈여겨볼 줄은 max_steps와 except다. 이 두 줄이 없으면 에이전트는 끝나지 않거나 조용히 죽는다. 실제 서비스라면 여기에 토큰 예산, 도구별 허용 목록, 사람 승인 게이트가 더 붙는다.

내가 막혔던 곳: 멈추지 않는 루프와 권한

처음 에이전트를 붙였을 때 가장 오래 헤맨 건 모델이 아니라 종료 조건이었다. 테스트가 계속 실패하는 상황에서 에이전트는 같은 파일을 조금씩 고치며 계속 재실행했다. 로그를 보니 40번이 넘게 돌고 있었다. 그때 배운 건 "실패하면 3번까지만" 같은 규칙을 코드에 박아야 한다는 것이다. 모델에게 "그만두세요"라고 프롬프트로 부탁하는 건 종료 조건이 아니다.

두 번째로 막힌 곳은 권한이었다. 셸 도구를 그냥 열어줬더니, 에이전트가 테스트 정리 스크립트를 실행하면서 내가 만든 임시 파일까지 지웠다. 다행히 지워도 되는 파일이었지만 그 뒤로는 rm이 들어간 명령은 무조건 승인 대기로 돌린다. Anthropic도 도구마다 권한 게이트를 두고, 삭제·배포·결제 같은 행동은 사람이 확인하는 구조를 권한다.

세 번째는 비용이다. 에이전트는 한 번의 답에 여러 번 모델을 부른다. 같은 작업을 챗봇으로 하면 1회, 에이전트로 하면 5~10회 호출이 나간다. 그래서 나는 "이 작업, 굳이 에이전트여야 하나" 를 먼저 묻는다. Anthropic이 "가장 단순한 해법부터 찾고, 필요할 때만 복잡도를 올려라"라고 쓴 이유를 몸으로 이해했다. (같은 글, 언제 에이전트를 쓸까)

관련 글: RAG가 뭐야 (검색증강생성) — 검색을 붙이는 순간 에이전트의 관찰 능력이 달라진다. agent-desktop 사용법 — 화면을 직접 조작하는 에이전트 쪽 사례.

에이전트를 쓰면 안 되는 경우

정리 삼아 반대쪽도 적어둔다. 아래에 해당하면 워크플로나 단일 호출로 충분하다.

상황이유대안
입력 종류가 몇 개로 고정분기만 잘 짜면 된다라우팅 워크플로
틀리면 안 되는 계산·정산확률적 판단이 위험코드로 계산, 모델은 설명만
응답 지연이 중요한 대화루프가 곧 지연단일 호출 + 검색
권한이 넓은 내부 시스템사고 반경이 크다읽기 전용 도구 + 승인 게이트

에이전트는 "알아서 해줘"를 가능하게 만드는 대신, 예측 불가능성과 비용을 같이 산다. 그 거래가 남는 장사인지가 도입 판단의 전부다.

참고 자료

반응형

+ Recent posts