프롬프트 체이닝으로 AI 워크플로우 안정성 개선하기

문제 상황

요구사항 문서에서 API 스펙을 추출하고, 타입 정의와 테스트 코드까지 생성하는 워크플로우를 구축했다. 처음엔 하나의 긴 프롬프트로 모든 작업을 처리했는데, 가끔 중간 단계를 건너뛰거나 형식이 어긋나는 문제가 발생했다.

프롬프트 체이닝 적용

작업을 3단계로 분리했다.

// 1단계: 요구사항 → 구조화된 스펙
const spec = await llm.generate({
  prompt: `다음 요구사항에서 API 엔드포인트, 메서드, 파라미터를 JSON으로 추출:\n${requirements}`,
  schema: apiSpecSchema
});

// 2단계: 스펙 → TypeScript 타입
const types = await llm.generate({
  prompt: `다음 API 스펙을 TypeScript 인터페이스로 변환:\n${JSON.stringify(spec)}`,
  context: { existingTypes }
});

// 3단계: 타입 → 테스트 코드
const tests = await llm.generate({
  prompt: `다음 타입에 대한 Vitest 테스트 작성:\n${types}`,
  examples: testExamples
});

중간 검증 추가

각 단계 사이에 검증 로직을 넣었다.

function validateSpec(spec) {
  if (!spec.endpoints || spec.endpoints.length === 0) {
    throw new Error('엔드포인트가 추출되지 않음');
  }
  
  for (const endpoint of spec.endpoints) {
    if (!endpoint.path || !endpoint.method) {
      throw new Error(`유효하지 않은 엔드포인트: ${JSON.stringify(endpoint)}`);
    }
  }
  
  return true;
}

결과

  • 성공률: 73% → 94%
  • 평균 재시도 횟수: 2.1회 → 0.3회
  • 처리 시간은 15% 증가했지만 안정성 개선으로 충분히 상쇄됨

배운 점

복잡한 작업일수록 프롬프트를 작은 단위로 쪼개는 것이 효과적이었다. 각 단계의 출력을 명확하게 정의하고, 다음 단계의 입력으로 사용하는 구조가 예측 가능성을 높였다. LLM의 context window가 충분히 크더라도, 인지 부하를 줄이는 것이 더 중요하다는 걸 확인했다.