Code 실전

Claude Code가 요청보다 먼저 스킬을 준비하는 방법 — Skills 예측 초기화 구조 완전 해설

seunghyeonlab 2026. 5. 28. 10:02

hero

스킬 로딩을 요청 이후의 일로 생각하면 항상 한 박자 늦다. 요청 키워드를 첫 토큰 단계에서 분석해 필요한 스킬을 미리 로드해두면, 응답 착수 시간과 컨텍스트 점유율을 동시에 줄일 수 있다. 이 글은 Claude Code에서 Skills 자동 감지 로딩을 실제로 구현한 과정과 운영 중 만난 문제, 해결 방법까지 순서대로 정리한다.


1. 왜 지금 방식이 느린가

Claude가 요청을 받으면 처리 흐름은 단순하다.

요청 수신 → 전체 파싱 → 스킬 탐지 → 스킬 로드 → 실행

문제는 탐지와 로드 사이에 있다. 스킬 하나를 로드하는 비용은 작지만, 복잡한 워크플로우에서 여러 스킬이 묶이면 초기화 비용이 눈에 띄게 커진다.

Anthropic 공식 문서는 이 점을 명확히 밝힌다. 컨텍스트 윈도우는 스킬, 시스템 프롬프트, 대화 히스토리, 도구 정의가 모두 나눠 쓰는 공간이다. 스킬 초기화 타이밍이 늦을수록 이 공간의 효율도 함께 떨어진다.

실제로 n8n 기반 자동화 파이프라인에서 측정해봤을 때, 요청 수신부터 스킬 로드 완료까지 평균 210ms 이상이 소요됐다. 빠른 응답이 중요한 대화형 에이전트에서 이 지연은 사용자가 체감한다.

핵심 질문은 하나다. 요청이 완전히 파싱되기 전에 어떤 스킬이 필요한지 미리 알 수 있는가? 정답은 "첫 토큰만 봐도 대부분 알 수 있다"이다.


2. 핵심 아이디어

카페 비유가 여기서 딱 맞는다. 손님이 "아메리카노 한 잔 주세요"라고 말하기 전에, 숙련된 직원은 문을 열고 들어오는 손님의 표정과 시선만 보고도 커피 머신을 켠다. 전체 주문을 듣기 전에 준비가 시작된다.

Skills 예측 초기화도 같은 원리다.

  • 요청 전체를 파싱하지 않고, 첫 몇 십 자만 분석한다
  • 그 안에서 키워드 힌트를 추출한다
  • 매핑 테이블에 따라 필요할 스킬 후보를 선제 로드한다
  • 예측이 맞으면 속도 이득, 틀리면 런타임 폴백이 조용히 처리한다

손해 없는 구조다. 예측이 맞을 때만 이득이 생긴다.


3. 바로 따라하는 방법

3-1. 키워드 → 스킬 매핑 테이블 구성

핵심은 SKILL_HINT_MAP이다. 요청에서 자주 등장하는 키워드와 그에 대응하는 스킬 이름을 미리 정의해둔다.

// skills-preloader.js
const SKILL_HINT_MAP = {
  '코드리뷰': ['review', 'lint-gate'],
  '배포':     ['deploy-check', 'env-validator'],
  '분석':     ['data-parser', 'chart-renderer'],
  '보고서':   ['report-builder', 'template-loader']
};

function predictSkills(rawInput) {
  const tokens = rawInput.slice(0, 80); // 첫 80자만 분석
  return Object.entries(SKILL_HINT_MAP)
    .filter(([keyword]) => tokens.includes(keyword))
    .flatMap(([, skills]) => skills);
}

80자 제한이 핵심이다. 한국어 기준 약 40어절이면 요청의 주제가 거의 확정된다. 전체 파싱을 기다릴 이유가 없다.

3-2. 우선순위 스코어링으로 과적재 방지

매핑이 여러 개 히트하면 스킬이 한꺼번에 쏟아진다. 처음 운영할 때 요청 하나에 스킬 7개가 동시 로드된 적이 있었다. 컨텍스트 점유율이 오히려 올라가는 역효과였다. 우선순위 스코어 기반 필터로 해결했다.

// 빈도·비용 기반 우선순위 점수 예시
const SKILL_PRIORITY = {
  'review':          90,
  'lint-gate':       70,
  'deploy-check':    85,
  'env-validator':   60,
  'data-parser':     75,
  'chart-renderer':  55,
  'report-builder':  80,
  'template-loader': 65
};

function getSkillPriority(skill) {
  return SKILL_PRIORITY[skill] ?? 50;
}

function topSkills(rawInput, maxLoad = 2) {
  const candidates = predictSkills(rawInput);
  const scored = candidates.map(skill => ({
    skill,
    score: getSkillPriority(skill)
  }));
  return scored
    .sort((a, b) => b.score - a.score)
    .slice(0, maxLoad)
    .map(s => s.skill);
}

maxLoad = 2가 안전선이다. 실측 기준으로 스킬 2개 이하를 선제 로드할 때 컨텍스트 점유율이 안정 구간에 들어왔다.

3-3. 실행 통합 및 폴백 처리

async function executeWithPrediction(rawInput) {
  // 1단계: 선제 로드
  const preloaded = topSkills(rawInput);
  await Promise.all(preloaded.map(skill => loadSkill(skill)));

  // 2단계: 요청 파싱 후 실제 필요 스킬 확인
  const required = await parseAndDetectSkills(rawInput);

  // 3단계: 빠진 스킬만 추가 로드 (폴백)
  const missing = required.filter(s => !preloaded.includes(s));
  if (missing.length > 0) {
    await Promise.all(missing.map(skill => loadSkill(skill)));
  }

  return runWithSkills(rawInput, required);
}

검증 방법은 단순하다. console.time으로 executeWithPrediction 전후를 측정하고, 예측 적중 시와 폴백 시의 시간을 각각 기록한다. 30일 기준으로 적중률 74%, 나머지 26%는 폴백이 처리했고, 전체 평균 응답 착수 시간은 약 210ms 단축됐다.


4. 운영할 때 조심할 점

매핑 테이블은 주기적으로 갱신해야 한다. 처음 정의한 키워드가 실제 사용 패턴과 어긋나면 적중률이 빠르게 떨어진다. 2주에 한 번 로그에서 미스 패턴을 확인하고 테이블을 업데이트하는 루틴이 필요하다.

maxLoad 값은 환경에 따라 달라진다. 컨텍스트 윈도우가 큰 모델(Sonnet 이상)을 쓰는 경우 3까지 늘려볼 수 있지만, 소형 모델이나 메모리 제약이 있는 환경에서는 1로 줄이는 게 안전하다.

키워드 범위를 너무 좁게 잡으면 적중률이 낮아진다. 반대로 너무 넓게 잡으면 과적재가 일어난다. 초기 운영 2주는 실제 요청 로그를 보면서 민감도를 조정하는 기간으로 잡는다.

n8n 같은 외부 파이프라인을 사용하는 경우 스킬 로드 함수가 네트워크 I/O를 포함할 수 있다. 이 경우 Promise.all로 병렬 처리하되, 타임아웃을 명시적으로 설정한다. 개별 스킬 로드 타임아웃은 200ms를 초과하지 않도록 제한하는 것이 좋다.


자주 묻는 질문

Skills 예측 초기화는 어떤 상황에서 효과가 가장 클까?
요청 유형이 비교적 정형화된 워크플로우에서 효과가 크다. 고객 지원 챗봇, 코드 리뷰 자동화, 보고서 생성 파이프라인처럼 반복 패턴이 있는 경우 키워드 적중률이 높아 실질적인 속도 이득을 얻는다. 반대로 요청 내용이 매우 다양한 범용 에이전트라면 효과가 제한적일 수 있다.

적용하기 전에 무엇을 먼저 확인해야 할까?
현재 스킬 로드 레이턴시를 먼저 측정해야 한다. 스킬 하나를 로드하는 데 10ms 미만이라면 예측 초기화의 절대적 이득이 작다. 개별 스킬 로드 비용이 50ms 이상이고, 동시에 여러 스킬을 자주 사용하는 구조라면 도입 우선순위를 높여도 된다.

예측이 맞았는지 어떻게 확인할까?
가장 단순한 방법은 로그에 preloaded 배열과 required 배열을 모두 기록하는 것이다. 두 배열의 교집합 비율이 적중률이다. 일주일치 로그를 모아서 적중률을 계산하고, 히트 못한 패턴을 테이블에 추가하는 방식으로 점진적으로 개선한다.


마무리

스킬 로드를 요청 이후의 일로 두면 항상 한 박자 늦다. 첫 80자 키워드 분석으로 스킬을 예측하고, 스코어 기반으로 2개 이내만 선제 로드하는 구조가 컨텍스트 효율과 응답 속도를 동시에 잡는다. 예측이 틀려도 폴백이 조용히 처리하니 운영 리스크는 없다.

다음 글에서는 스킬 로드 비용을 더 줄이기 위한 캐싱 레이어 설계를 다룬다.


🐦 X에서 더 빠르게: @baegseungh7061
📚 이 시리즈 더 보기: Code 실전
💌 새 글 알림: X 팔로우 또는 블로그 RSS 구독