
Claude Code 도구 심층 분석 #1 — AskUserQuestion
요약
Claude Code의 핵심 도구인 'AskUserQuestion'의 설계 원리와 효용성을 분석합니다. 이 도구는 대화형 선택 패널을 통해 사용자 입력을 구조화함으로써 AI와 사용자 간의 정렬 문제를 해결합니다.
핵심 포인트
- AskUserQuestion은 대화형 선택 패널을 통해 구조화된 입력을 제공함
- 사용자의 인지 부하를 줄이고 답변 속도를 높임
- 자연어 파싱 없이 명확한 열거형(enum) 값을 AI에게 전달 가능
- 모호성을 줄이고 구체적인 대안 선택을 유도함
저는 Claude Code의 설계를 역공학(reverse-engineering)하는 데 시간을 보냈으며, 심지어 핵심 기능만 추린 Java 클론을 작성하여 jooj에 오픈 소스로 공개하기도 했습니다. 제가 계속해서 놀라움을 느끼는 한 가지는 Claude Code가 제공하는 모든 도구가 매우 정교하게 설계되었다는 점입니다. 그래서 저는 이 도구들을 하나씩 파헤쳐 보는 시리즈를 시작하려 합니다.
이 첫 번째 포스트는 가장 흔히 볼 수 있는 도구 중 하나이자, 그 설계가 과소평가되기 쉬운 AskUserQuestion에 관한 것입니다.
AskUserQuestion의 실체
AskUserQuestion는 Claude Code의 내장된 **구조화된 질문 도구 (structured question tool)**입니다. Claude가 단순히 일반 텍스트(plain-text) 질문을 내뱉고 사용자가 답변을 타이핑하기를 기다리는 대신, 이 도구는 질문을 **대화형 선택 패널 (interactive selection panel)**로 렌더링합니다. 즉, 사용자는 텍스트의 벽이 아니라 미리 정의된 옵션 세트(카드 형태)를 보게 됩니다.
이 도구가 해결하는 핵심 문제는 **AI와 사용자 간의 효율적인 정렬 (alignment)**입니다:
- 사용자 노력 감소 — 옵션을 클릭하는 것이 답변을 타이핑하는 것보다 빠릅니다.
- 구조화된 입력 (Structured input) — Claude는 자연어 파싱 (natural-language parsing)이 필요 없는 명확한 열거형 (enum) 값을 받습니다.
- 모호성 수렴 (Converges ambiguity) — 미리 설정된 옵션은 막연한 "당신이 결정하세요" 대신 구체적인 대안 중에서 선택하도록 강제합니다.
- 탈출구 (Escape hatch) — 시스템은 항상 암시적인 "기타 (Other)" 옵션을 추가하여 사용자가 선택의 틀에 갇히지 않도록 합니다.
구체적인 예시
트리거(triggers), 구현(implementation), 프롬프트(prompt) 세부 사항을 살펴보기 전에, 실제 시나리오를 통해 모든 것을 이해해 봅시다. "AskUserQuestion이 없는 삶"과 "있는 삶"을 비교해 보겠습니다.
시나리오: 사용자가 Claude에게 **"이 앱에 사용자 로그인을 추가하는 것을 도와줘."**라고 말합니다.
이 요청은 정보가 매우 부족합니다. 인증 방식(auth method)에 대한 결정도 없고, 자격 증명(credential)을 어디에 저장할지에 대한 결정도 없습니다. Claude는 단순히 추측할 수 없으며 (팀마다 관례가 있을 수 있음), 코드로부터 추론할 수도 없습니다 (전례가 없는 새로운 기능이기 때문입니다).
안티 패턴 (Anti-Pattern): AskUserQuestion이 없을 때 발생하는 일
Claude는 다음과 같이 일반 텍스트 프롬프트로 질문을 던질 수밖에 없습니다:
"어떤 인증 방식(auth method)을 원하시나요? JWT를 추천하지만, 세션 쿠키(session cookies)나 OAuth도 가능합니다. 또한, 자격 증명(credential)을 어디에 저장할까요 — httpOnly 쿠키 또는 localStorage 중 선택해 주세요."
사용자는 즉시 다음과 같은 여러 문제에 직면합니다:
- 높은 인지 부하 (High cognitive load) — 한 단락에 2개의 결정 사항과 5개의 옵션이 포함되어 있어, 사용자는 답변하기 전에 질문을 해석해야 합니다.
- 높은 답변 비용 (High answer cost) — 사용자는 답장을 직접 타이핑하거나 ("JWT + httpOnly"), 다시 돌아오기 전까지 "JWT vs session cookies"를 구글링하는 데 두 시간을 소비해야 합니다.
- Claude의 높은 파싱 비용 (High parsing cost for Claude) — "JWT로 하고, 쿠키 방식으로 가자"와 같은 답변은 Claude가 사용자가 실제로 어떤 옵션을 선택했는지 파악하도록 강제하며, 오해의 소지가 생길 수 있습니다.
- 텍스트 속에 묻히는 추천 (Recommendation drowns in text) — Claude가 "JWT를 추천합니다"라고 말하지만, 이것이 단락 속에 섞여 있어 놓치기 쉽습니다.
- 대안 부재 (No fallback) — 만약 사용자가 Claude가 나열하지 않은 옵션(예: 매직 이메일 링크)을 원한다면, 별도의 설명을 통해 흐름을 끊거나 세 가지 선택지 중 하나로 유도되는 것을 받아들여야 합니다.
핵심적인 고통 (The core pain): 자유 형식의 텍스트(free-text form)는 "협업적 정렬 (collaborative alignment)"을 비용이 많이 드는 자연어 왕복 과정으로 변질시킵니다.
해결책: AskUserQuestion이 이를 해결하는 방법
Claude는 두 개의 질문을 포함하는 단일 호출을 구성합니다. 사용자는 다음과 같이 두 개의 카드를 보게 됩니다:
질문 1 — 인증 방식 (Auth method)
질문 2 — 자격 증명 저장 (Credential storage)
각 카드 상단에는 짧은 칩 라벨("Auth method" / "Token storage")이 있고, 그 뒤로 3개 또는 2개의 옵션과 자동으로 추가된 "기타 (Other)"가 이어집니다. 두 번의 클릭만으로 Claude는 대략 다음과 같은 정보를 받게 됩니다:
- 질문 1 → 사용자가 JWT (Recommended) 선택
- 질문 2 → 사용자가 httpOnly cookie (Recommended) 선택
의사결정 시간이 분 단위에서 초 단위로 압축되었습니다. 이것이 AskUserQuestion의 핵심입니다. 단순히 "AI가 질문하게 만드는 것"이 아니라, "협업 과정에서의 모든 명확화(clarification) 비용을 낮추는 것"입니다.
병렬 비교: 각 페인 포인트(Pain Point)의 해결
| 안티 패턴(Anti-pattern)의 고통 | AskUserQuestion의 해결책 |
|---|---|
| 높은 인지 부하 (High cognitive load) | 2개의 독립적인 카드로 분리하여 한 번에 하나의 결정만 수행 |
| ... |
아래의 모든 설계 결정은 정확히 이 고통들 중 하나로 거슬러 올라갑니다. 이 매핑을 염두에 두세요. 도구 설명에 나오는 각 제약 사항이 이 표의 특정 행을 해결하고 있음을 알 수 있을 것입니다.
언제 실행해야 하는가 (When to Fire It)
도구 설명은 그 경계를 명확히 규정합니다: 오직 작업이 막혔을 때만, 그리고 그 결정이 진정으로 사용자의 몫일 때만 사용해야 합니다.
"예, 질문하세요" 상황 3가지:
- 요청으로부터 추론할 수 없는 경우 — 요구사항 자체가 모호함 (예: 인증 방식이 지정되지 않은 "로그인 추가" 요청)
- 코드로부터 추론할 수 없는 경우 — 모방할 기존 패턴이 없음
- 합리적인 기본값(Default)이 없는 경우 — 선택 사항이 취향, 비즈니스 규칙, 또는 AI가 독단적으로 결정해서는 안 되는 아키텍처적 갈림길을 포함하는 경우
"아니오, 질문하지 마세요" 상황 3가지:
- 답이 코드 안에 있는 경우 — 코드를 읽는 데 시간을 할애하고, 사용자를 방해하지 마세요.
- 명백히 합리적인 경로가 하나뿐인 경우 — 그냥 실행하고, 커밋 메시지(commit message)에서 설명하세요.
- 플랜 모드(plan mode)에서 "제 계획이 괜찮나요?"라고 묻는 경우 — 그것은 ExitPlanMode의 역할이며, 여기서 Ask를 사용하는 것은 중복입니다.
전형적인 안티 패턴: "이 계획이 좋아 보이나요?" 또는 "계속 진행해도 될까요?"와 같은 메타 질문(meta-questions)을 피하세요. 승인을 요청하기 위해 이미 ExitPlanMode가 존재하므로, 동일한 목적으로 Ask를 사용하는 것은 순전한 중복입니다.
스키마 설계 (Schema Design)
도구의 입력 스키마를 역공학(Reverse-engineering)해 보면, 핵심 구조는 다음과 같습니다:
Claude는 질문 리스트(1개에서 4개)를 전달합니다. 각 질문 객체는 네 부분으로 구성됩니다:
- question —
?로 끝나는 전체 질문 텍스트 - header — 카드 상단에 표시되는 매우 짧은 칩 레이블 (최대 12자)
- multiSelect — 불리언 (boolean); 여러 옵션을 선택할 수 있는지 여부 (기본값 false)
- options — 2개에서 4개의 옵션 리스트
각 옵션 객체는 세 가지 필드를 가집니다:
- label — 사용자가 보는 표시 텍스트 (1~5개 단어)
- description — 해당 옵션의 의미 또는 트레이드오프 (trade-off)에 대한 설명
- preview — 선택 사항; 옵션 간의 차이를 시각적 비교(목업, 코드 스니펫 등)가 필요할 때, 해당 옵션에 포커스가 맞춰지면 렌더링되는 콘텐츠
몇 가지 주요 설계 선택 사항:
- 호출당 1~4개의 질문 — 일괄 결정(예: 한 번의 호출로 "인증 방식 + 토큰 저장 방식" 결정)을 지원하면서도, Claude가 한꺼번에 10개의 질문을 던져 사용자를 몰아붙이는 것을 방지합니다.
- 질문당 2~4개의 옵션 — Claude가 미리 범주화하도록 강제하여, 긴 목록을 쏟아내는 대신 N개의 가능성을 클릭 가능한 소수의 선택지로 수렴시킵니다.
- "기타(Other)"는 암시적임 — UI에서 자동으로 추가되며, Claude가 직접 목록을 작성하지 않습니다. 이는 "Claude가 생각한 옵션 ≠ 전체 선택지" 상황이 사용자를 가두지 않도록 보장합니다.
- 추천 메커니즘 (Recommendation mechanism) — Claude에게 선호하는 사항이 있다면, 그것을 첫 번째로 배치하고 레이블에 "(Recommended)"를 추가합니다. 사용자는 이를 한눈에 알아챌 수 있습니다.
- 반환 값 형태 (Return value shape) — 질문 텍스트를 키(key)로 하여 선택된 레이블에 매핑됩니다. 별도의
annotations필드는 미리보기 기반 옵션에 대한 사용자의 노트를 담습니다.
preview 필드는 미묘하지만 강력한 기능 확장입니다. 옵션들이 시각적으로 다를 때(두 개의 UI 목업, 두 개의 코드 스타일), preview에 시각적 요소를 포함하면 옵션에 포커스가 갈 때 UI가 이를 실시간으로 렌더링할 수 있습니다. "어떤 API 형태" 또는 "어떤 레이아웃"과 같은 질문에 완벽하게 부합합니다.
EnterPlanMode / ExitPlanMode와의 역할 분담:
- 계획 모드(plan mode)에서: '어떤 접근 방식'인지 명확히 하기 위해 AskUserQuestion을 사용합니다(최종 확정 전).
- 계획 모드(plan mode)에서: '제 계획이 준비되었나요?'라고 묻기 위해 AskUserQuestion을 사용하지 않습니다(ExitPlanMode를 사용해야 합니다).
- 계획 모드 외에서: 사용자 판단이 필요한 모든 기술적 분기점(technical fork)에 대해 AskUserQuestion을 사용합니다.
세 가지 도구는 완전한 의사결정 파이프라인을 형성합니다: Ask가 명확히 하고 → EnterPlanMode가 확장하며 → ExitPlanMode가 확정합니다.
프롬프트 분석 (Prompt Breakdown)
도구 설명의 모든 문장은 행동 제약 조건(behavior constraint)을 인코딩합니다. 이를 분해해 보겠습니다.
제약 조건 1: 엄격한 적용 경계 (첫 문장)
이 도구는 요청, 코드 또는 합리적인 기본값으로 해결할 수 없는, 진정으로 사용자가 결정해야 하는 의사결정에 직면했을 때만 사용하십시오.
이는 Claude가 끼어들지 않도록(not interrupt) 훈련합니다. 불확실할 경우, 첫 번째 행동은 사용자에게 질문을 던지는 것이 아니라 코드를 확인하고 합리적인 기본값을 시도하는 것이어야 합니다.
제약 조건 2: '기타' 옵션의 투명성 확보 (Making the "Other" escape hatch transparent)
사용자는 항상
- 스키마를 단순하게 유지합니다;
recommended: true와 같은 불리언 (boolean) 필드를 사용하지 않습니다. - UI는 단순히 레이블 (label)을 렌더링하며, 별도의 예외 처리를 하지 않습니다.
- Claude의 추천 사항은 반드시 레이블에 표시되어야 합니다 — 메타데이터에 숨기는 것이 불가능하며, 사용자가 즉시 확인할 수 있습니다.
제약 조건 5: 플랜 모드 (plan mode)와의 시간적 순서 (Temporal ordering)
플랜 모드 참고 사항: 플랜 모드로 전환하려면
EnterPlanMode를 사용하십시오 (이 도구가 아닙니다). 플랜 모드에 진입한 후에는, 계획을 확정하기 전에 요구 사항을 명확히 하거나 접근 방식 사이에서 선택하기 위해 이 도구를 사용하십시오. "내 계획이 준비되었나요?", "진행해도 될까요?"라고 묻거나 질문에서 "계획"을 언급하며 이 도구를 사용하지 마십시오 — 사용자는 귀하가 승인을 위해ExitPlanMode를 호출할 때까지 계획을 볼 수 없습니다.
이 부분은 가장 교육적인 구절입니다 — 워크플로의 **시간적 순서 (temporal ordering)**를 고정합니다:
- 플랜 모드에서: 접근 방식의 분기점(예: "A인가요, B인가요?")을 명확히 하기 위해
Ask를 사용합니다. - 명확해지면: 전체 계획을 초안 작성하기 위해
EnterPlanMode를 사용합니다. - 마지막으로: 승인을 요청하기 위해
ExitPlanMode를 사용합니다 — "진행해도 될까요?"라고 물으며Ask로 되돌아가는 루프를 만들지 마십시오.
특히 마지막 절에 주목하십시오 — "사용자는 귀하가 승인을 위해 ExitPlanMode를 호출할 때까지 계획을 볼 수 없습니다" — 이것이 플랜 모드에서 "내 계획이 괜찮나요?"라고 물어서는 안 되는 실제 이유입니다. 이는 단순히 중복되는 문제가 아닙니다: ExitPlanMode가 실행될 때까지 사용자는 말 그대로 승인할 대상이 아무것도 없습니다.
세 가지 도구는 각각 뚜렷한 역할을 가집니다: Ask (명확화) / EnterPlanMode (확장) / ExitPlanMode (확정). 이 제약 조건은 Claude가 스스로의 승인 메커니즘 역할을 하기 위해 Ask로 되돌아가는 루프를 근본적으로 방지합니다.
제약 조건 6: header 칩 (chip)은 필수 사항입니다 (스키마 계층에서 강제됨)
칩/태그 형태로 표시되는 매우 짧은 레이블 (최대 12자). 예시: "인증 방식 (Auth method)", "라이브러리 (Library)", "접근 방식 (Approach)".
A UX 제약 사항입니다 — UI는 각 질문을 상단에 칩이 있는 카드로 렌더링합니다. 칩은 전체 질문 텍스트가 아닌 header를 사용합니다. 이는 Claude가 긴 질문(예: "로그인 흐름을 위해 어떤 인증 방식을 사용해야 할까요?")을 압축된 칩(예: "인증 방식")으로 응축하도록 강제합니다.
제약 사항 7: 질문은 반드시 물음표로 끝나야 함
명확하고 구체적이어야 하며, 물음표(?)로 끝나야 합니다.
사소해 보일 수 있지만, 이는 UI의 톤을 형성합니다. 질문 형태와 평서문 형태는 완전히 다른 심리적 반응을 유도합니다. 간접적으로, 이는 Claude가 콘텐츠를 위장된 명령이 아닌 진정한 질의 (genuine query) 형태로 표현하도록 강제합니다.
핵심 요약 (Takeaway)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
