[{"content":"개요 Claude Code의 소스 구조를 27세션에 걸쳐 체계적으로 해부하는 시리즈의 첫 번째 글이다. 이 포스트에서는 사용자가 터미널에 \u0026ldquo;hello\u0026quot;를 입력했을 때, 응답이 화면에 출력되기까지 거치는 11개 TypeScript 파일의 전체 콜스택을 추적한다.\n분석 대상: 11개 핵심 파일 # 경로 줄 수 역할 1 entrypoints/cli.tsx 302 CLI 부트스트랩, 인자 파싱, 모드 라우팅 2 main.tsx 4,683 메인 REPL 컴포넌트, Commander 설정 3 commands.ts 754 커맨드 레지스트리 4 context.ts 189 시스템 프롬프트 조립, CLAUDE.md 주입 5 QueryEngine.ts 1,295 세션 관리, SDK 인터페이스 6 query.ts 1,729 핵심 턴 루프 — API + 도구 실행 7 services/api/client.ts 389 HTTP 클라이언트, 4개 프로바이더 라우팅 8 services/api/claude.ts 3,419 Messages API 래퍼, SSE 스트리밍, 재시도 9 services/tools/toolOrchestration.ts 188 동시성 파티셔닝 10 services/tools/StreamingToolExecutor.ts 530 스트리밍 중 도구 실행 11 services/tools/toolExecution.ts 1,745 도구 디스패치, 권한 검사 총 15,223줄을 추적한다.\n1. 진입과 부트스트랩: cli.tsx -\u0026gt; main.tsx cli.tsx는 302줄에 불과하지만, 놀라울 정도로 많은 패스트-패스(fast-path) 분기가 존재한다:\ncli.tsx:37 --version -\u0026gt; 즉시 출력, import 0개 cli.tsx:53 --dump-system -\u0026gt; 최소 import cli.tsx:100 --daemon-worker -\u0026gt; 워커 전용 경로 cli.tsx:112 remote-control -\u0026gt; 브릿지 모드 cli.tsx:185 ps/logs/attach -\u0026gt; 백그라운드 세션 cli.tsx:293 기본 경로 -\u0026gt; main.tsx 동적 import 설계 의도: --version 하나를 위해 main.tsx의 4,683줄을 로딩하지 않겠다는 것이다. CLI 도구의 체감 응답성에 직접 영향을 미치는 최적화다.\n기본 경로에서는 동적 import로 main.tsx를 로드한다:\n// cli.tsx:293-297 const { main: cliMain } = await import(\u0026#39;../main.js\u0026#39;); await cliMain(); main.tsx가 4,683줄인 이유는 다음을 모두 포함하기 때문이다:\n사이드 이펙트 import (1-209행): profileCheckpoint, startMdmRawRead, startKeychainPrefetch — 모듈 평가 시점에 병렬 서브프로세스를 시작하여 약 65ms의 macOS keychain 읽기를 숨긴다 Commander 설정 (585행~): CLI 인자 파싱, 10+개 모드별 분기 React/Ink REPL 렌더링: 터미널 UI 마운트 헤드리스 경로 (-p/--print): UI 없이 QueryEngine 직접 사용 2. 프롬프트 조립: context.ts의 dual-memoize context.ts는 189줄의 작은 파일이지만 시스템 프롬프트의 동적 부분을 전담한다. 두 개의 메모이즈된 함수가 핵심이다:\ngetSystemContext() (context.ts:116): git 상태(branch, status, 최근 커밋)를 수집 getUserContext() (context.ts:155): CLAUDE.md 파일들을 탐색/파싱 왜 분리했는가? Anthropic Messages API의 프롬프트 캐싱 전략과 직결된다. 시스템 프롬프트와 사용자 컨텍스트의 캐시 수명이 다르므로 cache_control을 서로 다르게 적용해야 한다. memoize로 감싸서 세션 내 한 번만 계산한다.\ncontext.ts:170-176에서 setCachedClaudeMdContent()를 호출하는 것은 순환 의존성을 끊기 위한 장치다 — yoloClassifier가 CLAUDE.md 내용을 필요로 하지만, 직접 import하면 permissions -\u0026gt; yoloClassifier -\u0026gt; claudemd -\u0026gt; permissions 순환이 발생한다.\n3. AsyncGenerator 체인: 아키텍처의 척추 Claude Code의 전체 데이터 플로우는 AsyncGenerator 체인으로 구성된다:\nQueryEngine.submitMessage()* -\u0026gt; query()* -\u0026gt; queryLoop()* -\u0026gt; queryModelWithStreaming()* 모든 핵심 함수가 async function*이다. 이는 단순한 구현 선택이 아니라 아키텍처적 결정이다:\nBackpressure: 소비자가 느리면 생산자도 대기 취소: AbortController와 결합하여 즉각적인 취소 가능 합성: yield*로 제너레이터 체인을 자연스럽게 연결 상태 관리: 루프 내 로컬 변수가 턴 간 상태를 자연스럽게 유지 QueryEngine.submitMessage() (QueryEngine.ts:209)의 시그니처를 보면:\nasync *submitMessage( prompt: string | ContentBlockParam[], options?: { uuid?: string; isMeta?: boolean }, ): AsyncGenerator\u0026lt;SDKMessage, void, unknown\u0026gt; SDK 모드에서 각 메시지는 yield로 스트리밍되며, Node.js의 backpressure가 자연스럽게 구현된다.\n4. 핵심 턴 루프: query.ts의 while(true) query.ts(1,729줄)의 queryLoop()가 실제 API+도구 루프다:\n// query.ts:307 while (true) { // 1. queryModelWithStreaming() 호출 -\u0026gt; SSE 스트림 // 2. 스트리밍 이벤트를 yield // 3. 도구 호출 감지 -\u0026gt; runTools()/StreamingToolExecutor // 4. 도구 결과를 메시지에 추가 // 5. stop_reason == \u0026#34;end_turn\u0026#34; -\u0026gt; break // stop_reason == \u0026#34;tool_use\u0026#34; -\u0026gt; continue } State 타입(query.ts:204)이 중요하다. messages, toolUseContext, autoCompactTracking, maxOutputTokensRecoveryCount 등 루프 상태를 명시적 레코드로 관리하여, continue 사이트에서 한 번에 갱신한다.\n5. API 통신: 4개 프로바이더와 캐싱 client.ts:88의 getAnthropicClient()는 4가지 프로바이더를 지원한다:\n프로바이더 SDK 동적 import 이유 Anthropic Direct Anthropic 기본, 즉시 로딩 AWS Bedrock AnthropicBedrock AWS SDK 수 MB Azure Foundry AnthropicFoundry Azure Identity 수 MB GCP Vertex AnthropicVertex Google Auth 수 MB claude.ts(3,419줄)의 핵심 함수 체인:\nqueryModelWithStreaming() (claude.ts:752) -\u0026gt; queryModel() -\u0026gt; withRetry() -\u0026gt; anthropic.beta.messages.stream() (SDK 호출) 캐싱 전략은 getCacheControl() (claude.ts:358)이 1시간 TTL 여부를 사용자 유형, 피처 플래그, 쿼리 소스에 따라 결정한다.\n6. 도구 오케스트레이션: 3-tier 동시성 flowchart TD TC[\"도구 호출 배열\u0026lt;br/\u0026gt;[ReadFile, ReadFile, Bash, ReadFile]\"] P[\"partitionToolCalls()\u0026lt;br/\u0026gt;toolOrchestration.ts:91\"] B1[\"Batch 1\u0026lt;br/\u0026gt;ReadFile + ReadFile\u0026lt;br/\u0026gt;isConcurrencySafe=true\"] B2[\"Batch 2\u0026lt;br/\u0026gt;Bash\u0026lt;br/\u0026gt;isConcurrencySafe=false\"] B3[\"Batch 3\u0026lt;br/\u0026gt;ReadFile\u0026lt;br/\u0026gt;isConcurrencySafe=true\"] PAR[\"Promise.all()\u0026lt;br/\u0026gt;최대 10개 동시\"] SEQ[\"순차 실행\"] PAR2[\"Promise.all()\"] TC --\u003e P P --\u003e B1 P --\u003e B2 P --\u003e B3 B1 --\u003e PAR B2 --\u003e SEQ B3 --\u003e PAR2 style B1 fill:#e8f5e9 style B2 fill:#ffebee style B3 fill:#e8f5e9StreamingToolExecutor(530줄)는 이 배치 파티셔닝을 스트리밍 컨텍스트로 확장한다. API 응답이 스트리밍되는 도중에 도구 호출을 감지하면 즉시 실행을 시작한다:\naddTool() (StreamingToolExecutor.ts:76) — 큐에 추가 processQueue() (StreamingToolExecutor.ts:140) — 동시성 확인 후 즉시 실행 getRemainingResults() (StreamingToolExecutor.ts:453) — 모든 도구 완료 대기 에러 전파 규칙: Bash 에러만 형제 도구를 취소한다 (siblingAbortController). Read/WebFetch 에러는 다른 도구에 영향을 주지 않는다. 이는 Bash 명령 간의 암묵적 의존성(mkdir 실패 -\u0026gt; 후속 명령 무의미)을 반영한 설계다.\n전체 데이터 플로우 sequenceDiagram participant User as 사용자 participant CLI as cli.tsx participant Main as main.tsx participant QE as QueryEngine participant Query as query.ts participant Claude as claude.ts participant API as Anthropic API participant Tools as toolOrchestration participant Exec as toolExecution User-\u003e\u003eCLI: \"hello\" 입력 CLI-\u003e\u003eMain: dynamic import Main-\u003e\u003eQE: new QueryEngine() QE-\u003e\u003eQuery: query() Query-\u003e\u003eClaude: queryModelWithStreaming() Claude-\u003e\u003eAPI: anthropic.beta.messages.stream() API--\u003e\u003eClaude: SSE 스트림 alt stop_reason == end_turn Claude--\u003e\u003eUser: 응답 출력 else stop_reason == tool_use Claude--\u003e\u003eQuery: tool_use blocks Query-\u003e\u003eTools: partitionToolCalls() Tools-\u003e\u003eExec: runToolUse() Exec-\u003e\u003eExec: canUseTool() + tool.call() Exec--\u003e\u003eQuery: 도구 결과 Note over Query: while(true) 다음 반복 endRust 갭 지도 미리보기 동일한 요청을 Rust 포트에서 추적한 결과, 31개 갭을 식별했다:\n우선순위 갭 수 핵심 예시 P0 (치명적) 2 동기 ApiClient, StreamingToolExecutor 부재 P1 (높음) 6 3-tier 동시성, 프롬프트 캐싱, Agent 도구 P2 (보통) 7 멀티 프로바이더, 노력 제어, 샌드박스 구현 완료 11 자동 압축, SSE 파서, OAuth, 설정 로딩 구현 완료율: 36% (11/31). 다음 포스트에서 이 갭들의 핵심인 대화 루프를 깊이 파고든다.\n인사이트 AsyncGenerator가 아키텍처의 척추다 — 단순한 구현 기법이 아니라 backpressure, 취소, 합성을 한 번에 해결하는 설계 결정이다. Rust에서는 Stream trait이 대응하지만 yield* 합성의 인체공학이 크게 다르다.\nmain.tsx 4,683줄은 기술 부채다 — Commander 설정, React 컴포넌트, 상태 관리가 한 파일에 혼재. 역사적 성장의 결과로, 모듈 분리의 기회가 된다.\n도구 동시성이 단순하지 않다 — \u0026ldquo;전부 병렬\u0026rdquo; 또는 \u0026ldquo;전부 직렬\u0026quot;이 아닌 3계층 모델(읽기 배치, 쓰기 순차, Bash 형제 취소)은 실전 에이전트 하네스의 핵심 설계 요소다.\n다음 포스트: #2 — 대화 루프의 심장, StreamingToolExecutor와 7개의 continue\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-harness-anatomy-1/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-harness-anatomy-1/","title":"Claude Code 하네스 해부학 #1 — 진입점에서 응답까지, 요청 하나의 여정"},{"content":"개요 시리즈 첫 번째 글에서 \u0026ldquo;hello\u0026rdquo; 한마디가 11개 파일을 관통하는 여정을 추적했다. 이번 포스트에서는 그 여정의 심장부인 query.ts 1,729줄의 while(true) 루프를 완전 해부한다. 7가지 continue 경로가 만드는 탄력적 실행 모델, StreamingToolExecutor의 4단계 상태 머신, 그리고 partitionToolCalls()의 3계층 동시성 모델을 분석한 뒤, Rust 프로토타입에서 이를 어떻게 재현했는지 대조한다.\n분석 대상: 10개 핵심 파일 # 경로 줄 수 역할 1 query/config.ts 46 이뮤터블 런타임 게이트 스냅샷 2 query/deps.ts 40 테스트 가능한 I/O 경계 (DI) 3 query/tokenBudget.ts 93 토큰 예산 관리, 자동 연속/중단 결정 4 query/stopHooks.ts 473 Stop/TaskCompleted/TeammateIdle 훅 5 query.ts 1,729 핵심 \u0026ndash; while(true) 턴 루프 6 QueryEngine.ts 1,295 세션 래퍼, SDK 인터페이스 7 toolOrchestration.ts 188 도구 파티셔닝 + 동시성 제어 8 StreamingToolExecutor.ts 530 SSE 중 도구 파이프라이닝 9 toolExecution.ts 1,745 도구 디스패치, 권한 검사 10 toolHooks.ts 650 Pre/PostToolUse 훅 파이프라인 총 6,789줄의 핵심 오케스트레이션 코드를 해부한다.\n1. queryLoop()의 7가지 continue 경로 query.ts의 queryLoop() 함수(query.ts:241)는 단순한 API 호출 루프가 아니다. 7가지 continue 사유를 가진 탄력적 실행기다. 각 경로는 고유한 장애 시나리오를 처리한다:\n사유 행 설명 collapse_drain_retry 1114 컨텍스트 축소 드레인 후 재시도 reactive_compact_retry 1162 반응형 압축 후 재시도 (413 복구) max_output_tokens_escalate 1219 8k -\u0026gt; 64k 토큰 에스컬레이션 max_output_tokens_recovery 1248 \u0026ldquo;이어서 작성하라\u0026rdquo; 넛지 메시지 주입 stop_hook_blocking 1303 Stop 훅이 블로킹 에러 반환 token_budget_continuation 1337 토큰 예산 미달로 계속 next_turn 1725 도구 실행 완료 후 다음 턴 State 타입이 핵심이다 (query.ts:204-217). 루프 상태를 10개 필드의 레코드로 관리한다. 왜 개별 변수가 아닌 레코드인가? continue 사이트가 7곳이며, 각각 state = { ... }으로 한 번에 갱신한다. 9개 변수를 개별 할당하면 하나를 빠뜨리는 실수가 발생하기 쉽다. 레코드 갱신은 타입 시스템이 누락을 잡아준다.\n루프 한 반복의 전체 흐름 1. 전처리 (365-447): snip 압축, 마이크로 컴팩트, 컨텍스트 축소 2. 자동 압축 (454-543): 성공 시 메시지 교체 후 continue 3. 블로킹 한도 검사 (628-648): 토큰 임계값 초과 시 즉시 종료 4. API 스트리밍 (654-863): SSE 이벤트를 for await로 소비 5. 도구 없는 종료 경로 (1062-1357): 413 복구, max_output 복구, stop 훅 6. 도구 있는 계속 경로 (1360-1728): 나머지 도구 실행 -\u0026gt; next_turn 2. StreamingToolExecutor의 4단계 상태 머신 StreamingToolExecutor.ts(530줄)는 Claude Code에서 가장 정교한 동시성 패턴이다. 핵심 아이디어: API 응답이 아직 스트리밍되는 동안 이미 완성된 도구 호출의 실행을 시작한다.\n모델이 [ReadFile(\u0026quot;a.ts\u0026quot;), ReadFile(\u0026quot;b.ts\u0026quot;), Bash(\u0026quot;make test\u0026quot;)]를 한 번에 호출하는 경우, 파이프라이닝 없이는 세 도구 블록이 모두 도착한 후에야 실행이 시작된다. 파이프라이닝에서는 ReadFile(\u0026quot;a.ts\u0026quot;) 블록이 완성되는 즉시 파일 읽기가 시작된다.\nstateDiagram-v2 [*] --\u003e queued: addTool() queued --\u003e executing: processQueue()\u0026lt;br/\u0026gt;canExecuteTool() == true queued --\u003e completed: 사전 취소\u0026lt;br/\u0026gt;getAbortReason() != null executing --\u003e completed: 도구 실행 완료\u0026lt;br/\u0026gt;또는 sibling abort completed --\u003e yielded: getCompletedResults()\u0026lt;br/\u0026gt;순서대로 yield yielded --\u003e [*] note right of queued processQueue()는 addTool() + 이전 도구 완료 시 자동 트리거 end note note right of completed Bash 에러 시 siblingAbortController.abort() 형제 도구만 취소 end note동시성 결정 로직 (canExecuteTool, line 129) 실행 가능 조건: - 현재 실행 중인 도구가 없음 (executingTools.length === 0) - 또는: 이 도구가 concurrencySafe이고 실행 중인 모든 도구도 concurrencySafe read-only 도구끼리는 병렬 실행이 가능하지만, write 도구가 하나라도 있으면 그 도구가 끝날 때까지 다음 도구는 대기한다.\nsiblingAbortController \u0026ndash; 계층적 취소 siblingAbortController(line 46-61)는 toolUseContext.abortController의 자식이다. Bash 도구가 에러를 발생시키면 siblingAbortController.abort('sibling_error')를 호출하여 형제 도구만 취소한다. 부모 컨트롤러는 영향을 받지 않으므로 전체 쿼리는 계속 실행된다.\n왜 Bash 에러만 형제를 취소하는가? mkdir -p dir \u0026amp;\u0026amp; cd dir \u0026amp;\u0026amp; make에서 mkdir이 실패하면 후속 명령은 무의미하다. ReadFile이나 WebFetch 실패는 독립적이므로 다른 도구에 영향을 주지 않아야 한다.\n3. partitionToolCalls \u0026ndash; 3계층 동시성 모델 toolOrchestration.ts(188줄)는 도구 실행의 동시성 모델 전체를 정의한다.\nflowchart TD TC[\"도구 호출 배열\u0026lt;br/\u0026gt;[ReadFile, ReadFile, Bash, ReadFile]\"] P[\"partitionToolCalls()\u0026lt;br/\u0026gt;toolOrchestration.ts:91\"] B1[\"Batch 1\u0026lt;br/\u0026gt;ReadFile + ReadFile\u0026lt;br/\u0026gt;isConcurrencySafe=true\"] B2[\"Batch 2\u0026lt;br/\u0026gt;Bash\u0026lt;br/\u0026gt;isConcurrencySafe=false\"] B3[\"Batch 3\u0026lt;br/\u0026gt;ReadFile\u0026lt;br/\u0026gt;isConcurrencySafe=true\"] PAR[\"Promise.all()\u0026lt;br/\u0026gt;최대 10개 동시\"] SEQ[\"순차 실행\"] PAR2[\"Promise.all()\"] TC --\u003e P P --\u003e B1 P --\u003e B2 P --\u003e B3 B1 --\u003e PAR B2 --\u003e SEQ B3 --\u003e PAR2 style B1 fill:#e8f5e9 style B2 fill:#ffebee style B3 fill:#e8f5e9규칙은 단순하다: 연속된 isConcurrencySafe 도구는 하나의 배치로 묶고, 그렇지 않은 도구는 각각 독립 배치가 된다. 이 결정은 도구 정의 자체에서 나온다 \u0026ndash; tool.isConcurrencySafe(parsedInput) 호출로 결정된다. 같은 도구라도 입력에 따라 동시성 안전성이 달라질 수 있다.\n컨텍스트 수정자와 경쟁 조건 왜 배치 완료 후 순서대로 적용하는가? 병렬 실행 중 컨텍스트 수정자를 즉시 적용하면 경쟁 조건이 발생한다. A가 먼저 완료되어 컨텍스트를 수정하면, 아직 실행 중인 B는 수정 전 컨텍스트로 시작했지만 수정 후 컨텍스트를 보게 된다. 배치 완료 후 원래 도구 순서대로 적용하면 결정론적 결과를 보장한다 (toolOrchestration.ts:54-62).\n4. 도구 실행 파이프라인과 훅 toolExecution.ts(1,745줄)의 runToolUse()(line 337)가 개별 도구 호출의 전체 생명주기를 관리한다:\nrunToolUse() 진입점 1. findToolByName() -- deprecated 별칭으로 재시도 (345-356) 2. abort 체크 -- 이미 취소되었으면 CANCEL_MESSAGE (415) 3. streamedCheckPermissionsAndCallTool() -- 권한 + 실행 + 훅 (455) -\u0026gt; checkPermissionsAndCallTool(): a. Zod 스키마로 입력 유효성 검사 (615) b. tool.validateInput() 커스텀 검증 (683) c. 투기적 분류기 (Bash 전용, 740) d. runPreToolUseHooks() (800) e. resolveHookPermissionDecision() (921) f. tool.call() 실제 실행 (1207) g. runPostToolUseHooks() 결과 변환 resolveHookPermissionDecision의 핵심 불변식 resolveHookPermissionDecision()(toolHooks.ts:332)에서 훅의 allow가 settings.json의 deny/ask 규칙을 바이패스하지 않는다 (toolHooks.ts:373). 훅이 allow해도 checkRuleBasedPermissions()를 통과해야 한다. 이것은 \u0026ldquo;훅은 자동화 도우미이지 보안 우회가 아니다\u0026quot;라는 설계 원칙을 반영한다.\n훅 결과가 allow일 때: -\u0026gt; checkRuleBasedPermissions() 호출 -\u0026gt; null이면 통과 (규칙 없음) -\u0026gt; deny이면 규칙이 훅을 오버라이드 -\u0026gt; ask이면 사용자 프롬프트 필요 5. Rust 대조 \u0026ndash; 152줄 vs 1,729줄 Rust의 ConversationRuntime::run_turn()은 152줄의 단일 loop {} (conversation.rs:183-272)로 구성된다. TS의 7가지 continue 경로 중 Rust에 존재하는 것은 next_turn(도구 실행 완료 후 다음 턴) 딱 하나뿐이다.\nTS continue 사유 Rust 상태 이유 collapse_drain_retry 미구현 컨텍스트 축소 없음 reactive_compact_retry 미구현 413 복구 없음 max_output_tokens_escalate 미구현 8k-\u0026gt;64k 에스컬레이션 없음 max_output_tokens_recovery 미구현 멀티턴 넛지 없음 stop_hook_blocking 미구현 Stop 훅 없음 token_budget_continuation 미구현 토큰 예산 시스템 없음 next_turn 구현됨 도구 결과 후 API 재호출 가장 치명적인 갭: 동기적 API 소비 Rust의 ApiClient 트레이트 시그니처가 모든 것을 말해준다:\nfn stream(\u0026amp;mut self, request: ApiRequest) -\u0026gt; Result\u0026lt;Vec\u0026lt;AssistantEvent\u0026gt;, RuntimeError\u0026gt;; 반환 타입이 Vec\u0026lt;AssistantEvent\u0026gt;다. 스트리밍이 아니다. SSE 이벤트를 모두 수집한 후 벡터로 반환한다. 이로 인해 모델이 5개 ReadFile을 호출할 때, TS는 첫 번째 ReadFile이 스트리밍 중에 실행 완료될 수 있지만, Rust는 5개 모두 스트리밍이 끝난 후에야 순차 실행을 시작한다. 레이턴시 차이가 도구 수에 비례하여 증가한다.\n6. Rust 프로토타입 \u0026ndash; 갭 브릿지 S04 프로토타입에서 P0 갭 3개를 브릿지하는 오케스트레이션 레이어를 구현했다:\nflowchart LR subgraph TS[\"TS 스트리밍 파이프라인\"] direction TB ts1[\"SSE 이벤트 스트림\"] ts2[\"StreamingToolExecutor\u0026lt;br/\u0026gt;4-state machine\"] ts3[\"getCompletedResults()\u0026lt;br/\u0026gt;yield 순서 보장\"] ts1 --\u003e ts2 --\u003e ts3 end subgraph Rust[\"Rust 프로토타입\"] direction TB rs1[\"EventStream\u0026lt;br/\u0026gt;tokio async\"] rs2[\"StreamingPipeline\u0026lt;br/\u0026gt;tokio::spawn + mpsc\"] rs3[\"MessageEnd 후\u0026lt;br/\u0026gt;채널 수집 + 정렬\"] rs1 --\u003e rs2 --\u003e rs3 end subgraph Bridge[\"핵심 매핑\"] direction TB b1[\"yield -\u003e tx.send()\"] b2[\"yield* -\u003e 채널 전달\"] b3[\"for await -\u003e while let recv()\"] end TS ~~~ Bridge ~~~ Rust style TS fill:#e1f5fe style Rust fill:#fff3e0 style Bridge fill:#f3e5f5프로토타입의 3가지 구현 1. 비동기 스트리밍: ApiClient 트레이트를 비동기 스트림으로 확장. MessageStream::next_event()가 이미 비동기이므로 소비 측만 변경하면 된다.\n2. 도구 파이프라이닝: ToolUseEnd 이벤트 수신 시 누적된 입력으로 ToolCall을 조립하고 tokio::spawn으로 즉시 백그라운드 실행을 시작한다. mpsc::unbounded_channel로 완료 순서로 수집하고 나중에 원래 순서로 정렬한다.\n3. 3-tier 동시성: ToolCategory enum(ReadOnly/Write/BashLike)에 따라 파티셔닝. ReadOnly 배치는 Semaphore(10) + tokio::spawn으로 최대 10개 병렬. BashLike는 순차 실행 + 에러 시 나머지 중단.\n프로토타입 커버리지 TS 기능 프로토타입 상태 partitionToolCalls() 3-tier partition_into_runs() + ToolCategory 구현 runToolsConcurrently() max 10 Semaphore(10) + tokio::spawn 구현 siblingAbortController BashLike에서 break 단순화 StreamingToolExecutor.addTool() ToolUseEnd 시 tokio::spawn 구현 PreToolUse hook deny/allow HookDecision::Allow/Deny 구현 PostToolUse output transform HookResult::transformed_output 구현 4-state machine (queued-\u0026gt;yielded) spawned/completed 2-state 미완성 413 복구 / max_output 에스컬레이션 \u0026ndash; 미구현 preventContinuation \u0026ndash; 미구현 정지 조건 비교 조건 TS Rust 도구 없음 (end_turn) handleStopHooks() 실행 후 종료 즉시 break 토큰 예산 초과 checkTokenBudget() 3가지 결정 없음 max_output_tokens 에스컬레이션 + 멀티턴 복구 없음 413 prompt-too-long 컨텍스트 축소 + 반응형 압축 에러 전파 maxTurns maxTurns 파라미터 (query.ts:1696) max_iterations 수확 체감 3회 이상 + 500토큰 미만 증가 없음 tokenBudget.ts(93줄)의 checkTokenBudget()은 프롬프트 크기가 아닌 응답 연속 여부를 제어한다. COMPLETION_THRESHOLD = 0.9(전체 버짓의 90% 미만이면 계속), DIMINISHING_THRESHOLD = 500(연속 3회 이상 매번 500토큰 미만 생성 시 수확 체감으로 중단). nudgeMessage가 명시적으로 \u0026ldquo;do not summarize\u0026quot;를 지시한다.\n설계 결정의 핵심 \u0026ndash; 왜 AsyncGenerator인가 전체 파이프라인이 async function* 체인이다:\nQueryEngine.submitMessage()* -\u0026gt; query()* -\u0026gt; queryLoop()* -\u0026gt; deps.callModel()* runTools()* -\u0026gt; runToolUse()* -\u0026gt; handleStopHooks()* -\u0026gt; executeStopHooks()* 이 선택의 핵심 이점: 제어 흐름의 반전 없이 복잡한 상태 기계를 구현할 수 있다. 7가지 continue 경로에서 state = { ... }로 상태를 명시적으로 구성하고 continue하면 된다. 콜백 기반이었다면 상태 관리가 분산되어 7가지 복구 경로의 정합성을 보장하기 어려웠을 것이다.\nRust에서는 yield 키워드가 안정화되지 않았으므로, tokio::sync::mpsc 채널로 대체한다. yield -\u0026gt; tx.send(), yield* -\u0026gt; 채널 전달, for await...of -\u0026gt; while let Some(v) = rx.recv().\n인사이트 query.ts의 7가지 continue는 \u0026ldquo;에러 처리\u0026quot;가 아니라 \u0026ldquo;탄력성 엔진\u0026quot;이다 \u0026ndash; 413 에러에서 컨텍스트를 축소하고, max_output에서 토큰을 에스컬레이션하며, stop 훅 블로킹에서 에러를 모델에 피드백한다. 이 복구 파이프라인이 장시간 자율 작업의 안정성을 보장한다. Rust에서 이를 재현하려면 단순한 loop {} 이상의 상태 관리가 필요하다.\nStreamingToolExecutor는 성능 최적화가 아니라 UX 결정이다 \u0026ndash; 도구 5개를 직렬로 실행하면 사용자가 체감하는 대기 시간이 직렬 합산이 된다. 파이프라이닝은 벤치마크 수치가 아니라 \u0026ldquo;응답을 기다리는\u0026rdquo; 시간을 줄이는 사용자 경험 요소다. Rust 프로토타입에서 tokio::spawn + mpsc 채널로 이를 20줄 이내에 구현할 수 있었다.\n정적 파티셔닝 + 런타임 동시성의 이중 구조가 안전성과 성능을 양립시킨다 \u0026ndash; partitionToolCalls()가 컴파일 타임에 배치를 나누고, canExecuteTool()이 런타임에 실행 가능 여부를 판단한다. 이 이중 구조 덕분에 비스트리밍 경로(runTools)와 스트리밍 경로(StreamingToolExecutor)가 동일한 동시성 의미론을 공유한다.\n다음 포스트: #3 \u0026ndash; 42개 도구의 설계 철학, BashTool부터 AgentTool까지\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-harness-anatomy-2/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-harness-anatomy-2/","title":"Claude Code 하네스 해부학 #2 — 대화 루프의 심장, StreamingToolExecutor와 7개의 continue"},{"content":"개요 Claude Code에는 42개의 도구가 존재한다. 이 포스트에서는 Tool.ts의 30+ 멤버 인터페이스가 구현하는 \u0026ldquo;도구가 자신을 알고 있다\u0026rdquo; 패턴을 해부하고, 42개 도구를 8개 패밀리로 분류한다. 그 중 가장 복잡한 BashTool(12,411줄)의 6계층 보안 체인, AgentTool(6,782줄)의 4가지 스폰 모드, FileEditTool의 문자열 매칭 전략, MCPTool의 빈 껍데기 프록시 패턴, Task 상태 머신을 심층 분석한다.\n1. Tool 인터페이스 \u0026ndash; \u0026ldquo;도구가 자신을 알고 있다\u0026rdquo; Tool.ts(792줄)는 도구 시스템의 계약서다. 모든 도구가 구현하는 Tool 타입(Tool.ts:362-695)은 30개 이상의 멤버로 구성되며 네 영역으로 나뉜다:\n영역 핵심 멤버 역할 실행 계약 call(), inputSchema, validateInput(), checkPermissions() 도구의 핵심 로직 메타데이터 name, aliases, searchHint, shouldDefer, maxResultSizeChars 검색과 표시 동시성/안전성 isConcurrencySafe(), isReadOnly(), isDestructive(), interruptBehavior() 오케스트레이션 결정 UI 렌더링 renderToolUseMessage() 등 10개+ 터미널 표시 왜 이렇게 많은 멤버가 한 인터페이스에? 오케스트레이터(toolExecution.ts)가 도구를 호출할 때 외부 매핑 테이블 없이 도구 객체 자체에서 모든 메타데이터를 읽을 수 있다. 새 도구 추가가 한 디렉토리 안에서 완결되는 플러그인 아키텍처의 근간이다.\nToolUseContext \u0026ndash; 42개 필드의 실행 환경 ToolUseContext(Tool.ts:158-300)는 도구 실행 시 주입되는 환경 컨텍스트다. 142줄에 걸쳐 42개 필드가 정의되어 있다:\nabortController: 3-tier 동시성 모델의 취소 전파 getAppState()/setAppState(): 전역 상태 접근 (권한, todo, 팀) readFileState: LRU 캐시 기반 변경 감지 contentReplacementState: 대용량 결과를 디스크에 저장하고 요약만 반환 도구는 격리된 함수가 아니라 하네스의 전체 상태에 접근해야 한다. FileReadTool은 캐시로 변경 여부를 판단하고, AgentTool은 서브에이전트 상태를 등록하며, BashTool은 형제 프로세스를 중단한다.\nbuildTool()의 fail-closed 기본값 buildTool()(Tool.ts:783)은 ToolDef를 받아 기본값을 채운 완전한 Tool을 반환한다. 기본값은 fail-closed 원칙(Tool.ts:757-768):\nisConcurrencySafe -\u0026gt; false (안전하지 않다고 가정) isReadOnly -\u0026gt; false (쓰기한다고 가정) 새 도구를 만들 때 동시성/읽기전용을 명시적으로 선언하지 않으면 가장 보수적인 경로(순차 실행, 쓰기 권한 요구)를 탄다. 실수로 안전하지 않은 도구를 병렬 실행하는 버그를 구조적으로 방지한다.\n2. 42개 도구의 8개 패밀리 flowchart LR subgraph safe[\"isConcurrencySafe: true (10개)\"] direction TB R1[\"FileReadTool\"] R2[\"GlobTool / GrepTool\"] R3[\"WebFetchTool / WebSearchTool\"] R4[\"ToolSearchTool / SleepTool\"] R5[\"TaskGetTool / TaskListTool\"] R6[\"LSPTool\"] end subgraph unsafe[\"isConcurrencySafe: false (32개)\"] direction TB W1[\"BashTool 12,411줄\"] W2[\"FileEditTool / FileWriteTool\"] W3[\"AgentTool 6,782줄\"] W4[\"MCPTool / SkillTool\"] W5[\"Task 5개 / Todo\"] W6[\"Config / PlanMode / Worktree\"] end subgraph orch[\"오케스트레이터\"] O[\"partitionToolCalls()\u0026lt;br/\u0026gt;toolOrchestration.ts\"] end O --\u003e|\"병렬 배치\"| safe O --\u003e|\"순차 실행\"| unsafe style safe fill:#e8f5e9 style unsafe fill:#ffebee 패밀리 도구 수 대표 도구 핵심 특징 파일시스템 5 FileReadTool (1,602줄) PDF/이미지/노트북 지원, 토큰 제한 실행 3 BashTool (12,411줄) 6계층 보안, 명령 의미론 에이전트/팀 4 AgentTool (6,782줄) 4가지 스폰, 재귀적 하네스 태스크 관리 7 TaskUpdateTool (484줄) 상태 머신, 검증 넛지 MCP/LSP 5 MCPTool (1,086줄) 빈 껍데기 프록시 웹/외부 2 WebFetchTool (1,131줄) 병렬 안전 상태/설정 5 ConfigTool (809줄) 세션 상태 변경 인프라/유틸 11 SkillTool (1,477줄) 커맨드-도구 브리지 42개 중 10개(24%)만 병렬 실행 가능하지만, 이 10개가 가장 빈번하게 호출되는 도구(Read, Glob, Grep, Web)이므로 실제 체감 병렬성은 비율보다 높다.\n3. BashTool \u0026ndash; 6계층 보안 체인 BashTool은 단순한 셸 실행기가 아니다. 임의 코드 실행이라는 본질적 위험 때문에 12,411줄의 절반 이상이 보안 레이어다.\nflowchart TB A[\"모델: Bash 호출\"] --\u003e B{\"validateInput\"} B --\u003e|\"sleep 패턴 차단\"| B1[\"에러 반환\"] B --\u003e|\"통과\"| C{\"6계층 보안 체인\"} subgraph chain[\"보안 체인\"] C1[\"1. bashSecurity.ts\u0026lt;br/\u0026gt;2,592줄 -- 명령 구조 분석\"] C2[\"2. bashPermissions.ts\u0026lt;br/\u0026gt;2,621줄 -- 규칙 매칭\"] C3[\"3. readOnlyValidation.ts\u0026lt;br/\u0026gt;1,990줄 -- 읽기전용 판단\"] C4[\"4. pathValidation.ts\u0026lt;br/\u0026gt;1,303줄 -- 경로 기반 보안\"] C5[\"5. sedValidation.ts\u0026lt;br/\u0026gt;684줄 -- sed 전용 보안\"] C6[\"6. shouldUseSandbox.ts\u0026lt;br/\u0026gt;153줄 -- 샌드박스 결정\"] C1 --\u003e C2 --\u003e C3 --\u003e C4 --\u003e C5 --\u003e C6 end C --\u003e chain chain --\u003e D{\"allow / ask / deny\"} D --\u003e|\"allow\"| E[\"runShellCommand()\"] D --\u003e|\"ask\"| F[\"사용자 승인 요청\"] D --\u003e|\"deny\"| G[\"거부\"] E --\u003e H[\"결과 처리\u0026lt;br/\u0026gt;interpretCommandResult()\u0026lt;br/\u0026gt;trackGitOperations()\"] style chain fill:#fff3e0각 레이어가 다른 위협을 담당한다:\nbashSecurity.ts (2,592줄): 명령 치환($(), `), Zsh 모듈 기반 공격 차단. 핵심: unquoted 컨텍스트의 메타문자만 위험으로 분류 bashPermissions.ts (2,621줄): 규칙 기반 allow/deny/ask. stripAllLeadingEnvVars() + stripSafeWrappers()로 래퍼 제거 후 실제 명령 추출 readOnlyValidation.ts (1,990줄): 읽기전용이면 isConcurrencySafe: true \u0026ndash; 병렬 실행 허용 pathValidation.ts (1,303줄): 명령별 경로 추출 규칙으로 경로 안전성 판단 sedValidation.ts (684줄): sed의 w, e 플래그는 파일 쓰기/임의 실행 가능 \u0026ndash; 별도 차단 shouldUseSandbox.ts (153줄): 최종 격리 결정 명령 의미론 (commandSemantics.ts): grep과 diff는 exit code 1이 에러가 아닌 정상 결과다. COMMAND_SEMANTICS Map으로 명령별 해석 규칙을 정의한다.\nRust 포팅 시사점: 이 6계층을 통째로 재현하거나, 아예 sandbox-only로 단순화해야 한다. 중간 단계 생략은 보안 구멍을 만든다.\n4. AgentTool \u0026ndash; 4가지 스폰 모드 AgentTool은 \u0026ldquo;도구\u0026quot;라기보다 에이전트 오케스트레이터다. 핵심: runAgent()는 하네스의 query() 루프를 재귀 호출한다. 자식 에이전트는 부모와 동일한 도구/API/보안 체크를 받는다.\n모드 트리거 컨텍스트 공유 백그라운드 동기 기본 없음 (프롬프트만) X 비동기 run_in_background: true 없음 O 포크 subagent_type 생략 부모 전체 컨텍스트 O 원격 isolation: \u0026quot;remote\u0026quot; 없음 O 포크 서브에이전트 \u0026ndash; byte-identical 프리픽스 포크는 부모의 전체 대화 컨텍스트를 상속한다. 프롬프트 캐시 공유를 위해 모든 포크 자식이 byte-identical API 요청 프리픽스를 생성하도록 설계한다:\n도구 사용 결과를 플레이스홀더로 대체 FORK_BOILERPLATE_TAG로 재귀 포크 방지 모델 동일 유지 (model: 'inherit') \u0026ndash; 다른 모델은 캐시 불일치 메모리 시스템 (agentMemory.ts) 에이전트별 지속 메모리를 3가지 스코프로 관리:\nuser: ~/.claude/agent-memory/\u0026lt;type\u0026gt;/ \u0026ndash; 사용자 전역 project: .claude/agent-memory/\u0026lt;type\u0026gt;/ \u0026ndash; 프로젝트 공유 (VCS) local: .claude/agent-memory-local/\u0026lt;type\u0026gt;/ \u0026ndash; 로컬 전용 5. FileEditTool \u0026ndash; 부분 대체 패턴 FileEditTool(1,812줄)은 전체 파일 쓰기가 아닌 old_string -\u0026gt; new_string 패치를 수행한다. 모델이 전체 파일을 출력할 필요가 없어 토큰을 절약하고, diff 기반 리뷰를 가능하게 한다.\n매칭 전략:\n정확한 문자열 매칭: fileContent.includes(searchString) 따옴표 정규화: curly quote -\u0026gt; straight quote 변환 후 재시도, preserveQuoteStyle()로 원본 스타일 보존 고유성 검증: old_string이 파일에서 유일하지 않으면 실패 (또는 replace_all) 동시성 보호: readFileState Map에 파일별 마지막 읽기 타임스탬프를 저장. 편집 시 디스크 수정 시간과 비교하여 외부 변경을 감지한다. 이것이 \u0026ldquo;Read 후 Edit\u0026rdquo; 규칙이 프롬프트에서 강제되는 이유다.\n6. MCPTool \u0026ndash; 빈 껍데기 프록시 MCPTool(1,086줄)은 하나의 도구 정의가 수백 개의 외부 도구를 대표한다. 빌드 시점에는 빈 껍데기이고, 런타임에 mcpClient.ts가 서버별로 복제 + 오버라이드한다:\n// MCPTool.ts:27-51 -- 핵심 메서드가 \u0026#34;Overridden in mcpClient.ts\u0026#34; 주석 name: \u0026#39;mcp\u0026#39;, // 런타임에 \u0026#39;mcp__serverName__toolName\u0026#39;으로 교체 async call() { return { data: \u0026#39;\u0026#39; } }, // 런타임에 실제 MCP 호출로 교체 UI 축소 분류(classifyForCollapse.ts, 604줄)는 139개 SEARCH_TOOLS, 280개+ READ_TOOLS 이름으로 MCP 도구의 읽기/검색 여부를 판단한다. 알 수 없는 도구는 축소하지 않는다(보수적).\n7. Task 상태 머신 \u0026ndash; 에이전트 IPC TaskUpdateTool(406줄)의 상태 흐름: pending -\u0026gt; in_progress -\u0026gt; completed 또는 deleted.\n핵심 행동:\n소유자 자동 설정: in_progress 변경 시 현재 에이전트 이름 자동 할당 검증 넛지: 3개+ 태스크 완료 후 검증 단계가 없으면 verification agent 스폰 권고 메시지 라우팅 (SendMessageTool 917줄): 이름, * 브로드캐스트, uds:path Unix 도메인 소켓, bridge:session 원격 피어, 에이전트 ID 재개 Task/SendMessage는 단순한 유틸리티가 아니라 멀티에이전트 시스템의 프로세스 간 통신(IPC) 기초다.\nTS vs Rust 비교 측면 TS (42개 도구) Rust (10개 도구) 도구 정의 Tool 인터페이스 + buildTool() ToolSpec 구조체 + mvp_tool_specs() 입력 스키마 Zod v4 + lazySchema() serde_json::json!() JSON Schema 직접 동시성 선언 isConcurrencySafe(parsedInput) 없음 \u0026ndash; 순차 실행 권한 검사 checkPermissions() -\u0026gt; PermissionResult PermissionMode enum UI 렌더링 10+ render 메서드 (React/Ink) 없음 MCP 통합 MCPTool + inputJSONSchema 이중 경로 없음 크기 비교 ~48,000줄 (도구 코드만) ~1,300줄 (lib.rs 단일) 핵심 격차: Rust 포트는 실행 계약(call 등가물)만 구현하고, 동시성 선언, 권한 파이프라인, UI 렌더링, 지연 로딩 최적화는 모두 없다.\n인사이트 보안은 단일 체크포인트가 아니라 체인이다 \u0026ndash; BashTool의 6계층은 각 레이어가 다른 위협을 담당한다. bashSecurity는 명령 구조, bashPermissions는 규칙 매칭, pathValidation은 경로 안전성. 이 체인의 어느 한 곳이라도 빠지면 공격 표면이 열린다. fail-closed 원칙과 결합하여 \u0026ldquo;모르면 차단\u0026quot;이라는 보수적 전략이 전체 시스템을 관통한다.\n에이전트는 재귀적 하네스 인스턴스다 \u0026ndash; AgentTool의 runAgent()가 하네스의 query() 루프를 재귀 호출한다는 것은, \u0026ldquo;에이전트\u0026quot;가 별개의 시스템이 아니라 **같은 하네스의 다른 구성(configuration)**이라는 아키텍처 결정이다. 도구 풀만 교체하고 동일한 보안/훅/오케스트레이션을 재사용한다.\n42개 도구 중 10개만 concurrency-safe이지만 체감 병렬성은 높다 \u0026ndash; 전체의 24%에 불과한 10개 도구(Read, Glob, Grep, Web, LSP)가 가장 빈번하게 호출된다. 이 비대칭이 3-tier 동시성 모델의 실용적 가치를 보여준다. buildTool()의 fail-closed 기본값(isConcurrencySafe: false)이 안전 경계를 형성하여, 새 도구 개발자가 동시성을 잘못 선언하는 실수를 구조적으로 방지한다.\n다음 포스트: #4 \u0026ndash; 런타임 훅 26+이벤트와 CLAUDE.md 6단계 디스커버리\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-harness-anatomy-3/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-harness-anatomy-3/","title":"Claude Code 하네스 해부학 #3 — 42개 도구의 설계 철학, BashTool부터 AgentTool까지"},{"content":"개요 Claude Code에서 \u0026ldquo;hook\u0026quot;이라는 단어는 두 가지 완전히 다른 시스템을 가리킨다. 런타임 훅(toolHooks.ts + utils/hooks.ts)은 도구 실행 전후에 셸 스크립트를 실행하는 보안/확장 파이프라인이고, React 훅(hooks/*.ts 85개+)은 터미널 UI의 상태 관리 코드다. 이 구분을 놓치면 Rust 재구현 범위를 85배 오판하게 된다. 이번 포스트에서는 런타임 훅의 PreToolUse/PostToolUse 파이프라인과 resolveHookPermissionDecision()의 보안 불변식, 85개 React 훅의 9개 카테고리 분류, 그리고 CLAUDE.md 6단계 디스커버리와 토큰 버짓 관리를 분석한다.\n1. 런타임 훅 vs React 훅 \u0026ndash; 핵심 구분 차원 런타임 훅 (toolHooks.ts + utils/hooks.ts) React 훅 (hooks/*.ts) 실행 주체 child_process.spawn() React 렌더 사이클 구성 방법 settings.json hooks 필드, 셸 커맨드 소스코드 import 실행 시점 도구 사용 전/후, 세션 시작 등 26+ 이벤트 컴포넌트 마운트/업데이트 사용자 정의 가능 \u0026ndash; 사용자가 셸 스크립트 등록 불가능 \u0026ndash; 내부 코드 결과 형태 JSON stdout (allow/deny/ask/rewrite) React state 변경 Rust 재구현 필수 \u0026ndash; 도구 실행 파이프라인의 핵심 불필요 \u0026ndash; TUI 전용 2. PreToolUse 파이프라인 \u0026ndash; 7가지 yield 변형 runPreToolUseHooks()(toolHooks.ts:435-650)는 AsyncGenerator로 설계되어 있다. 도구 실행 전에 호출되며 다음 yield 타입들을 방출한다:\nmessage: 진행 상황 메시지 (훅 시작/에러/취소) hookPermissionResult: allow/deny/ask 결정 hookUpdatedInput: 입력 재작성 (권한 결정 없이 입력만 변경) preventContinuation: 실행 중단 플래그 stopReason: 중단 사유 문자열 additionalContext: 모델에 전달할 추가 컨텍스트 stop: 즉시 중단 왜 AsyncGenerator인가? 훅은 여러 개가 순차 실행되고, 각 훅의 결과가 다음 처리에 영향을 미친다. Promise 체이닝은 최종 결과만 반환하고, 이벤트 이미터는 타입 안전성이 없다. AsyncGenerator는 호출자가 각 결과를 소비하면서 중간에 중단할 수 있는 유일한 패턴이다.\nflowchart TD subgraph \"PreToolUse 파이프라인\" A[\"toolExecution.ts\u0026lt;br/\u0026gt;도구 호출 시작\"] B[\"runPreToolUseHooks()\u0026lt;br/\u0026gt;toolHooks.ts:435\"] C[\"getMatchingHooks()\u0026lt;br/\u0026gt;utils/hooks.ts:1603\"] D[\"settings.json hooks\u0026lt;br/\u0026gt;이벤트+패턴 매칭\"] E[\"spawn() 셸 커맨드\u0026lt;br/\u0026gt;stdin: JSON, stdout: 결과\"] F[\"HookResult 파싱\u0026lt;br/\u0026gt;allow / deny / ask / rewrite\"] end subgraph \"권한 해석\" G[\"resolveHookPermission\u0026lt;br/\u0026gt;Decision()\u0026lt;br/\u0026gt;toolHooks.ts:332\"] H{\"훅 결과?\"} I[\"allow: checkRule\u0026lt;br/\u0026gt;BasedPermissions()\u0026lt;br/\u0026gt;규칙이 훅을 오버라이드\"] J[\"deny: 즉시 거부\"] K[\"ask: canUseTool()\u0026lt;br/\u0026gt;사용자 프롬프트\"] end subgraph \"도구 실행\" L[\"tool.call()\"] end subgraph \"PostToolUse\" M[\"runPostToolUseHooks()\u0026lt;br/\u0026gt;결과 변환 / 차단\"] end A --\u003e B --\u003e C --\u003e D --\u003e E --\u003e F --\u003e G --\u003e H H --\u003e|\"allow\"| I H --\u003e|\"deny\"| J H --\u003e|\"ask\"| K I --\u003e|\"규칙 통과\"| L L --\u003e MresolveHookPermissionDecision \u0026ndash; allow != bypass resolveHookPermissionDecision()(toolHooks.ts:332-433)의 핵심 불변식: 훅의 allow가 settings.json의 deny/ask 규칙을 바이패스하지 않는다 (toolHooks.ts:325-327).\n처리 로직 3단계:\n1단계 \u0026ndash; allow 처리 (toolHooks.ts:347-406):\nhookResult.behavior === \u0026#39;allow\u0026#39;: -\u0026gt; checkRuleBasedPermissions() 호출 -\u0026gt; null -\u0026gt; 규칙 없음, 훅 허용 통과 -\u0026gt; deny -\u0026gt; 규칙이 훅을 오버라이드 (보안 우선!) -\u0026gt; ask -\u0026gt; 사용자 프롬프트 필요 왜 allow가 bypass하지 않는가? 이것은 의도적 보안 결정이다. 외부 셸 스크립트가 {\u0026quot;decision\u0026quot;:\u0026quot;allow\u0026quot;}를 반환한다고 해서 settings.json의 deny 규칙을 무시하면, 악의적 훅이 보안 정책을 우회할 수 있다. 규칙은 항상 훅보다 우선한다.\n2단계 \u0026ndash; deny (toolHooks.ts:408-411): 즉시 거부, 추가 검사 없음.\n3단계 \u0026ndash; ask/없음 (toolHooks.ts:413-432): canUseTool() 호출로 사용자 프롬프트.\n26개 이상의 이벤트 유형 getMatchingHooks()(utils/hooks.ts:1603-1682)이 훅 매칭을 담당한다:\n도구 이벤트: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied 세션 이벤트: SessionStart, SessionEnd, Setup 에이전트 이벤트: SubagentStart, SubagentStop, TeammateIdle 작업 이벤트: TaskCreated, TaskCompleted 시스템 이벤트: Notification, ConfigChange, FileChanged, InstructionsLoaded 컴팩트 이벤트: PreCompact, PostCompact 입력 이벤트: UserPromptSubmit, Elicitation, ElicitationResult 중단 이벤트: Stop, StopFailure 매칭된 훅들은 순차 실행되며, 하나가 deny하면 이후 훅은 실행되지 않는다.\n3. 85개 React 훅 \u0026ndash; 9개 카테고리 분류 mindmap root((\"TS 훅 시스템\")) 런타임 훅 toolHooks.ts 651줄 PreToolUse PostToolUse PostToolUseFailure utils/hooks.ts ~5000줄 26+ 이벤트 유형 셸 스폰 비동기 프로토콜 React 훅 85+ 권한 3개 useCanUseTool PermissionContext UI 입력 11개 useTextInput useVimInput useTypeahead UI 디스플레이 11개 useVirtualScroll useDiffData 상태/설정 12개 useSettings useSessionBackgrounding 통합/원격 12개 useRemoteSession useReplBridge 기능 20개 useVoice useSwarm useTasks 알림 16개 notifs/ 디렉토리 도구/키바인딩 5개 useMergedTools 추가 5+개 fileSuggestions useManagePlugins 카테고리 개수 Rust 재구현 대표 훅 권한 3 부분 (브릿지) useCanUseTool (203줄) UI 입력 11 불필요 useTextInput (529줄), useVimInput (316줄) UI 디스플레이 11 불필요 useVirtualScroll (721줄) 상태/설정 12 불필요 useSessionBackgrounding (158줄) 통합/원격 12 불필요 useRemoteSession (605줄) 기능/알림 20 불필요 useVoice (1,144줄) 알림/배너 16 불필요 notifs/ 디렉토리 도구/키바인딩 5 불필요 useMergedTools (44줄) 추가 5+ 불필요 fileSuggestions (811줄) 핵심: Rust가 재구현해야 하는 것은 toolHooks.ts(651줄) + utils/hooks.ts(~5,000줄)의 런타임 파이프라인뿐이다. 85개 React 훅 15,000줄+은 범위 밖이다.\n4. CLAUDE.md 6단계 디스커버리 claudemd.ts(1,479줄)의 getMemoryFiles()(L790-1074)는 6단계 계층으로 CLAUDE.md를 로드한다:\n단계 소스 경로 예시 우선순위 1. Managed 조직 정책 /etc/claude-code/CLAUDE.md 최저 2. User 개인 습관 ~/.claude/CLAUDE.md, ~/.claude/rules/*.md 3. Project 프로젝트 규칙 cwd에서 루트까지 CLAUDE.md, .claude/rules/*.md 4. Local 로컬 오버라이드 CLAUDE.local.md (gitignore) 5. AutoMem 자동 메모리 MEMORY.md 엔트리포인트 6. TeamMem 팀 메모리 조직 간 동기화 최고 왜 이 순서인가? 파일 주석(L9)이 명시한다: \u0026ldquo;Files are loaded in reverse order of priority.\u0026rdquo; LLM은 프롬프트 후반부에 더 주의를 기울이므로, 가장 구체적인 지시(Local \u0026gt; Project \u0026gt; User \u0026gt; Managed)가 마지막에 위치한다. 이것은 CSS specificity가 아니라 LLM 주의 편향을 활용한 설계다.\n디렉토리 상향 탐색과 중복 방지 originalCwd에서 파일시스템 루트까지 올라간 뒤 dirs.reverse()로 루트부터 아래로 처리한다 (L851-857). 모노레포에서 상위 CLAUDE.md가 먼저 로드되고 하위 프로젝트의 CLAUDE.md가 그 위에 오는 효과를 만든다.\n워크트리 중복 방지 (L868-884): git 워크트리가 메인 레포 내부에 중첩되면 동일 CLAUDE.md가 두 번 로드되는 것을 isNestedWorktree 검사로 방지한다.\n@include 지시자 (L451-535): 마크다운 토큰을 렉싱하여 코드 블록 내부의 @path는 무시하고, 텍스트 노드의 @path만 재귀적으로 해석한다. 최대 깊이 5.\n5. 시스템/사용자 컨텍스트 분리 \u0026ndash; dual-memoize 캐시 context.ts(189줄)는 시스템 프롬프트를 두 개의 독립적인 컨텍스트로 분리한다:\ngetSystemContext() (L116): git 상태, 캐시 브레이커 getUserContext() (L155): CLAUDE.md 머지 문자열, 현재 날짜 왜 둘로 나누었는가? Anthropic API의 프롬프트 캐싱 전략 때문이다. git 상태(세션 고정)와 CLAUDE.md(파일 변경 시에만 무효화)의 캐시 수명이 다르므로, cache_control을 서로 다르게 적용해야 한다. 두 함수 모두 memoize로 감싸져 세션 내 한 번만 실행된다.\n3가지 캐시 무효화 경로 setSystemPromptInjection() (context.ts:29): 양쪽 캐시 모두 클리어 clearMemoryFileCaches() (claudemd.ts:1119): 메모리 파일만 클리어 resetGetMemoryFilesCache() (claudemd.ts:1124): 메모리 파일 클리어 + InstructionsLoaded 훅 발화 이 분리는 워크트리 전환(리로드 불필요)과 실제 리로드(compaction 후)를 구분하기 위함이다.\n6. 토큰 버짓 \u0026ndash; 응답 연속 결정 tokenBudget.ts(93줄)의 checkTokenBudget()은 프롬프트 크기가 아닌 응답 연속 여부를 제어한다:\nCOMPLETION_THRESHOLD = 0.9 -- 90% 미만이면 계속 DIMINISHING_THRESHOLD = 500 -- 3회+ 연속, 매번 500토큰 미만 -\u0026gt; 수확 체감 if (!isDiminishing \u0026amp;\u0026amp; turnTokens \u0026lt; budget * 0.9) -\u0026gt; continue if (isDiminishing || continuationCount \u0026gt; 0) -\u0026gt; stop with event else -\u0026gt; stop without event 왜 0.9인가? 모델이 버짓 근처에서 요약을 시작하는 경향이 있다. 90%에서 멈추면 \u0026ldquo;마무리 요약\u0026quot;을 하지 않고 작업을 계속하게 만든다. nudgeMessage가 명시적으로 \u0026ldquo;do not summarize\u0026quot;를 지시한다.\n수확 체감 감지는 모델이 반복적 패턴에 빠지는 것을 방지한다. 서브에이전트는 즉시 stop (L51) \u0026ndash; 자체 버짓을 갖지 않는다.\nRust 대조 관점 TS Rust 훅 이벤트 유형 26개+ PreToolUse, PostToolUse 2개 훅 실행 비동기 AsyncGenerator 동기 Command::output() 훅 결과 7가지 yield 변형 + JSON Allow/Deny/Warn 3가지 (exit code) 입력 수정 hookUpdatedInput 불가능 allow != bypass 보장됨 미구현 (보안 취약) CLAUDE.md 6단계 디스커버리 4후보 per dir @include 재귀적, 깊이 5 미지원 토큰 버짓 checkTokenBudget() 3가지 결정 없음 프롬프트 캐시 memoize + 3가지 무효화 매번 빌드 인사이트 \u0026ldquo;hook\u0026quot;의 이중 의미가 아키텍처의 가장 큰 혼동원이다 \u0026ndash; 85개 React 훅은 Rust 재구현 범위에 포함되지 않는다. 런타임 훅(~5,600줄)만이 포팅 대상이다. 그러나 이 런타임 엔진은 26개 이벤트 유형, 비동기 프로토콜({\u0026quot;async\u0026quot;:true} 백그라운드 전환), 프롬프트 요청(stdin/stdout 양방향)까지 포함하는 복잡한 시스템이다. \u0026ldquo;훅\u0026quot;이라는 단어의 범위를 정확히 파악하는 것이 범위 산정의 출발점이다.\nCLAUDE.md의 \u0026ldquo;마지막이 더 강하다\u0026rdquo; 패턴은 LLM 주의 편향의 의도적 활용이다 \u0026ndash; 6단계 계층 로딩(Managed -\u0026gt; User -\u0026gt; Project -\u0026gt; Local -\u0026gt; AutoMem -\u0026gt; TeamMem)에서 가장 구체적인 지시가 프롬프트 끝에 위치하여 가장 강한 영향력을 갖는다. 이것은 아키텍처적 깔끔함이 아니라 API 프롬프트 캐싱 적중률 최적화 + LLM 행동 특성의 교차점에서 나온 설계다.\nresolveHookPermissionDecision()의 \u0026ldquo;allow != bypass\u0026rdquo; 불변식은 보안의 핵심이다 \u0026ndash; 현재 Rust hooks.rs는 exit code만으로 allow/deny를 판단한다. JSON 결과 파싱과 checkRuleBasedPermissions 후속 검사를 구현하지 않으면, 악의적 훅이 deny 규칙을 우회할 수 있는 보안 취약점이 생긴다. 편의 자동화와 보안 정책의 경계를 명확히 하는 것이 훅 시스템의 근본 과제다.\n다음 포스트: #5 \u0026ndash; MCP 서비스와 플러그인 스킬 확장 생태계\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-harness-anatomy-4/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-harness-anatomy-4/","title":"Claude Code 하네스 해부학 #4 — 런타임 훅 26+이벤트와 CLAUDE.md 6단계 디스커버리"},{"content":"개요 Claude Code는 42개의 내장 도구 외에 MCP(Model Context Protocol)를 통해 외부 도구를 무제한으로 확장할 수 있다. 이 포스트에서는 client.ts(3,348줄)의 연결 관리 아키텍처, auth.ts(2,465줄)의 OAuth 인증 체계, 4계층 보안 모델, 설정 중복 제거를 분석한다. 이어서 플러그인과 스킬의 구조적 차이, 5계층 스킬 디스커버리 엔진, mcpSkillBuilders.ts의 순환 참조 해결 패턴까지 해부한다.\n1. MCP 클라이언트 \u0026ndash; 연결 관리가 프로토콜보다 어렵다 메모이제이션 기반 커넥션 풀 connectToServer는 lodash.memoize로 래핑되어 있다. 캐시 키는 name + JSON(config). MCP 서버는 stateful(stdio 프로세스, WebSocket 연결)이므로 매 도구 호출마다 새 연결을 만들면 성능이 치명적으로 나빠진다.\nonclose 핸들러가 캐시를 무효화 -\u0026gt; 다음 호출이 자동으로 재연결 fetchToolsForClient, fetchResourcesForClient도 각각 LRU 캐시(20개) 도구 프록시 패턴 MCP 도구는 네이티브 Tool 인터페이스로 변환된다:\nname: mcp__\u0026lt;normalized_server\u0026gt;__\u0026lt;normalized_tool\u0026gt; 형식 call(): ensureConnectedClient -\u0026gt; callMCPToolWithUrlElicitationRetry -\u0026gt; callMCPTool checkPermissions(): 항상 passthrough \u0026ndash; MCP 도구는 별도 권한 시스템 annotations: readOnlyHint, destructiveHint 등 MCP 어노테이션 매핑 URL Elicitation Retry: OAuth 기반 MCP 서버는 도구 호출 중간에 인증을 요구할 수 있다(에러 코드 -32042). retry 루프가 사용자에게 URL을 보여주고 인증 완료 후 재시도한다.\n연결 상태 머신과 3-strike 터미널 에러 stateDiagram-v2 [*] --\u003e Pending: 설정 로드됨 Pending --\u003e Connected: connectToServer 성공 Pending --\u003e Failed: 연결 타임아웃 Pending --\u003e NeedsAuth: 401 UnauthorizedError Pending --\u003e Disabled: isMcpServerDisabled() Connected --\u003e Connected: 도구 호출 성공 Connected --\u003e Failed: 터미널 에러 3회 연속 Connected --\u003e NeedsAuth: 401 during callMCPTool Connected --\u003e Pending: onclose 캐시 무효화 NeedsAuth --\u003e Pending: 인증 완료 NeedsAuth --\u003e NeedsAuth: 15분 TTL 캐시 Failed --\u003e Pending: reconnectMcpServer() Disabled --\u003e Pending: toggleMcpServer() note right of Connected memoize 캐시에 존재 fetchTools/Resources도 캐시 end note3-strike 규칙: 터미널 에러가 3회 연속 발생하면 Failed 상태로 강제 전환. 이는 죽은 서버에 계속 재시도하는 것을 방지한다.\n15분 needs-auth 캐시: 401을 받은 서버를 매번 재시도하면 30개 이상의 커넥터가 동시에 네트워크 요청을 만든다. TTL 캐시로 불필요한 재시도를 방지한다.\n2. OAuth \u0026ndash; 2,465줄의 현실 auth.ts가 2,465줄인 이유는 현실의 OAuth 서버들이 RFC를 일관성 있게 구현하지 않기 때문이다:\n구성 요소 설명 RFC 9728 + 8414 디스커버리 서버가 별도 호스트에서 AS 운영 가능 -\u0026gt; PRM으로 AS URL 탐색 PKCE 공개 클라이언트 \u0026ndash; code_verifier/code_challenge 필수 XAA (Cross-App Access) IdP의 id_token으로 MCP 서버 AS에서 access_token 교환 비표준 에러 정규화 Slack은 HTTP 200에 {\u0026quot;error\u0026quot;:\u0026quot;invalid_grant\u0026quot;} 반환 Keychain 저장 macOS Keychain 연동 (getSecureStorage()) Rust 포팅 시사점: OAuth는 SDK 의존이 아니라 복잡한 비동기 상태 머신이다. 디스커버리(2단계) -\u0026gt; PKCE -\u0026gt; 콜백 서버 -\u0026gt; 토큰 저장 -\u0026gt; 갱신 -\u0026gt; 폐기 -\u0026gt; XAA. 이 전체를 이식하는 것은 비현실적이므로, stdio MCP + API 키 인증으로 시작하는 것이 현실적이다.\n3. 4계층 보안 모델 MCP 보안은 단일 게이트가 아니라 트러스트 레벨의 합성이다:\nflowchart TD subgraph L1[\"1. Enterprise\"] E1[\"managed-mcp.json\u0026lt;br/\u0026gt;존재하면 다른 모든 소스 차단\"] E2[\"denylist / allowlist\u0026lt;br/\u0026gt;이름, 명령어, URL 패턴\"] end subgraph L2[\"2. Project\"] P1[\".mcp.json 로드\"] P2[\"pending -\u003e 사용자 승인 -\u003e approved\"] end subgraph L3[\"3. Server\"] S1[\"OAuth 서버별 독립 토큰\"] S2[\"Keychain 저장\"] end subgraph L4[\"4. Channel\"] C1[\"GrowthBook allowlist\u0026lt;br/\u0026gt;tengu_harbor_ledger\"] C2[\"구조화된 이벤트\u0026lt;br/\u0026gt;일반 텍스트 매칭 아님\"] end L1 --\u003e L2 --\u003e L3 --\u003e L4 style L1 fill:#ffcdd2 style L2 fill:#fff9c4 style L3 fill:#c8e6c9 style L4 fill:#e1f5fe각 레이어가 독립적으로 동작하며, Enterprise가 최우선이다. .mcp.json이 프로젝트에 있어도 enterprise denylist에 걸리면 차단된다.\n설정 소스와 중복 제거 (config.ts 1,578줄) 설정 소스 우선순위 (높은 것이 이긴다):\nEnterprise managed (managed-mcp.json) Local (사용자별 프로젝트 설정) User (글로벌 ~/.claude.json) Project (.mcp.json) Plugin (동적) claude.ai connectors (최저) 왜 중복 제거가 필요한가? 같은 MCP 서버가 .mcp.json과 claude.ai 커넥터 모두에 존재할 수 있다. getMcpServerSignature가 stdio:[command|args] 또는 url:\u0026lt;base\u0026gt; 시그니처를 만들어, CCR 프록시 URL도 원본 벤더 URL로 언래핑한 뒤 비교한다.\n환경 변수 확장: ${VAR} 및 ${VAR:-default} 문법 지원. 누락 변수는 에러 대신 경고로 보고하여 부분적 연결 실패를 방지한다.\n4. 플러그인 vs 스킬 \u0026ndash; 구조적 차이 차원 스킬 플러그인 본질 프롬프트 확장 (SKILL.md = 텍스트) 시스템 확장 (스킬 + 훅 + MCP) 설치 파일 하나 배치 마켓플레이스 git 클론 런타임 코드 없음 (순수 텍스트) 있음 (MCP 서버, 훅 스크립트) 토글 암묵적 (파일 존재 여부) 명시적 (/plugin UI) ID 체계 파일 경로 {name}@builtin 또는 {name}@marketplace 스킬은 \u0026ldquo;파일 = 확장\u0026quot;이라는 원칙의 구현이다. SKILL.md 하나가 설치/빌드 없이 즉시 확장으로 작동한다.\n플러그인 서비스의 관심사 분리 파일 역할 부작용 pluginOperations.ts 순수 라이브러리 함수 없음 pluginCliCommands.ts CLI 래퍼 process.exit, console 출력 PluginInstallationManager.ts 백그라운드 조정기 AppState 업데이트 pluginOperations의 순수 함수는 CLI와 대화형 UI 양쪽에서 재사용된다.\n마켓플레이스 조정: diffMarketplaces()로 선언된 마켓플레이스와 실재 설치를 비교. 신규 설치면 자동 새로고침, 기존 업데이트면 needsRefresh 플래그만 설정. 신규는 \u0026ldquo;플러그인 못 찾음\u0026rdquo; 오류 방지가 필요하지만, 업데이트는 사용자가 적용 시점을 선택해야 한다.\n5. 5계층 스킬 디스커버리 엔진 loadSkillsDir.ts(1,086줄)의 로딩 소스 우선순위:\nflowchart TD subgraph Discovery[\"스킬 디스커버리\"] A[\"1. policySettings\u0026lt;br/\u0026gt;managed-settings.json\"] B[\"2. userSettings\u0026lt;br/\u0026gt;~/.claude/skills/\"] C[\"3. projectSettings\u0026lt;br/\u0026gt;.claude/skills/\u0026lt;br/\u0026gt;프로젝트 루트~홈까지\"] D[\"4. --add-dir\u0026lt;br/\u0026gt;추가 디렉토리\"] E[\"5. 레거시\u0026lt;br/\u0026gt;/commands/ 디렉토리\"] end subgraph Dedup[\"중복 제거\"] F[\"realpath() 심링크 해소\"] G[\"파일 ID 기반 first-wins\"] end subgraph Parse[\"프론트매터 파싱\"] H[\"description, when_to_use\"] I[\"allowed-tools\"] J[\"model, context, hooks\"] K[\"paths, shell\"] end A --\u003e B --\u003e C --\u003e D --\u003e E E --\u003e F --\u003e G G --\u003e H \u0026 I \u0026 J \u0026 K style Discovery fill:#e1f5fe style Parse fill:#fff3e0프론트매터 시스템 SKILL.md의 YAML 프론트매터에서 15개+ 필드를 추출한다:\ndescription, when_to_use: 모델이 스킬 선택에 사용 allowed-tools: 스킬 실행 시 허용 도구 목록 model: 특정 모델 강제 지정 context: fork: 별도 컨텍스트에서 실행 hooks: 스킬 전용 훅 설정 paths: 경로 기반 활성화 필터 shell: 인라인 셸 명령 실행 번들 스킬의 지연 디스크 추출 CLI 바이너리에 컴파일되는 17개 번들 스킬(skills/bundled/)은 files 필드가 있으면 첫 호출 시 디스크에 추출한다:\nO_NOFOLLOW | O_EXCL 플래그로 심링크 공격 차단 0o600 퍼미션으로 접근 제한 resolveSkillFilePath()가 .. 경로를 거부하여 디렉토리 탈출 방지 왜 디스크에 추출하는가? 모델이 Read/Grep 도구로 참조 파일을 읽을 수 있게 하기 위해서다. 메모리에만 두면 모델이 접근할 수 없다.\nmcpSkillBuilders \u0026ndash; 44줄짜리 순환 참조 해결 mcpSkillBuilders.ts(44줄)는 작지만 아키텍처적으로 중요하다.\n문제: mcpSkills.ts가 loadSkillsDir.ts의 함수를 필요로 하지만, 직접 임포트하면 순환 참조가 발생한다 (client.ts -\u0026gt; mcpSkills.ts -\u0026gt; loadSkillsDir.ts -\u0026gt; ... -\u0026gt; client.ts).\n해법: write-once 레지스트리. loadSkillsDir.ts가 모듈 초기화 시 함수를 등록하고, mcpSkills.ts가 필요할 때 가져간다. 동적 임포트는 Bun 번들러에서 실패하고, 리터럴 동적 임포트는 dependency-cruiser 순환 검사를 트리거하기 때문에 이 방식이 유일한 해결책이다.\n의존성 그래프의 리프 모듈이 타입만 임포트하고, 런타임 등록은 시작 시 한 번만 수행한다.\nRust 대조 영역 TS (완성) Rust (현재) 이름 정규화 normalization.ts mcp.rs \u0026ndash; 동일 로직 서버 시그니처 getMcpServerSignature mcp_server_signature \u0026ndash; CCR 프록시 언래핑 포함 stdio JSON-RPC SDK 의존 mcp_stdio.rs \u0026ndash; 직접 구현 (initialize, tools/list, tools/call) OAuth 2,465줄 완전 구현 없음 \u0026ndash; 타입만 정의 연결 관리 memoize + onclose 재연결 없음 스킬 로딩 5계층 + 프론트매터 15필드 2 디렉토리, SKILL.md만 번들 스킬 17개 내장 없음 플러그인 빌트인 + 마켓플레이스 없음 보안 4계층 (Enterprise-\u0026gt;Channel) 없음 핵심 격차: Rust는 부트스트랩(설정 -\u0026gt; 트랜스포트)과 stdio JSON-RPC까지 구현했다. mcp_stdio.rs의 SDK 없는 JSON-RPC 구현은 의미 있는 진전이다. 그러나 OAuth, 연결 생명주기, 채널 보안, 스킬 디스커버리 전체가 부재한다.\n인사이트 MCP는 \u0026ldquo;프로토콜\u0026quot;이 아니라 \u0026ldquo;통합 프레임워크\u0026quot;다 \u0026ndash; 3,348줄의 client.ts가 말해주는 것은, 어려운 부분이 JSON-RPC가 아니라 연결 생명주기 관리라는 점이다. 메모이제이션, 자동 재연결, 세션 만료 감지, 401 retry, 3-strike 터미널 에러, needs-auth 캐시. 외부 프로세스(stdio)와 원격 서비스(HTTP/SSE)는 예측 불가능하게 죽고, OAuth 토큰은 만료되고, 네트워크는 끊긴다. \u0026ldquo;한번 연결하면 끝\u0026quot;이 아닌 현실을 반영하는 코드다.\n스킬은 \u0026ldquo;파일 = 확장\u0026quot;이라는 원칙의 구현이다 \u0026ndash; SKILL.md 하나가 설치/빌드 없이 즉시 확장으로 작동한다. 이 단순성이 프론트매터를 통한 점진적 복잡성 추가(모델 지정, 훅, 경로 필터)와 결합되어 초보자와 파워 유저를 모두 수용한다. 플러그인은 스킬의 상위 조직 단위로, \u0026ldquo;스킬 + 훅 + MCP 서버\u0026quot;를 묶는 패키지다.\nmcpSkillBuilders.ts는 44줄짜리 아키텍처 교훈이다 \u0026ndash; Bun 번들러의 동적 임포트 제약과 dependency-cruiser의 순환 검사를 동시에 만족시키는 유일한 해법이 \u0026ldquo;write-once 레지스트리\u0026quot;였다. 의존성 그래프의 리프 모듈이 타입만 임포트하고 런타임 등록은 시작 시 한 번만 수행하는 패턴은, 복잡한 모듈 시스템에서 순환 참조를 해결하는 범용적인 접근법으로 기억할 가치가 있다.\n다음 포스트: #6 \u0026ndash; Claude Code를 넘어서, 7크레이트 독자 하네스 구축 회고\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-harness-anatomy-5/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-harness-anatomy-5/","title":"Claude Code 하네스 해부학 #5 — MCP 서비스와 플러그인 스킬 확장 생태계"},{"content":"개요 Claude Code의 TypeScript 소스를 27세션에 걸쳐 체계적으로 해부한 여정의 마지막 포스트다. Phase 1에서 10만줄+ TS 코드의 아키텍처를 이해하고, Phase 2에서 핵심 패턴을 Rust로 재구현한 뒤, Phase 3에서 발견한 8가지 한계점을 극복하는 독자 에이전트 하네스를 설계-구축했다. 이 포스트에서는 한계점 분석, 5가지 설계 원칙, 7크레이트 아키텍처, 61개 테스트, 그리고 전체 여정의 회고를 정리한다.\n1. Claude Code 아키텍처의 8가지 한계점 27세션의 분석에서 발견한 강점과 한계를 구분했다. 강점(AsyncGenerator 파이프라인, 3-tier 동시성, 훅 확장성, CLAUDE.md 디스커버리, MCP 지원, 자기 완결적 도구 인터페이스, 7가지 에러 복구)은 설계의 우수한 면이다. 그러나 다음 8가지 한계가 독자 하네스의 동기가 되었다:\n# 한계점 근거 세션 영향 1 React/Ink 의존 \u0026ndash; 무거운 TUI S08 headless 모드에서 불필요한 의존 2 단일 프로바이더 (실질 Anthropic 전용) S01 OpenAI, 로컬 모델 사용 불가 3 main.tsx 4,683줄 모놀리스 S01 CLI/REPL/세션이 단일 파일에 혼재 4 동기적 도구 실행 (Rust 포트) S03 스트리밍 파이프라이닝 불가 5 TS 생태계에 묶인 플러그인 S13 언어 중립적 확장 불가 6 85개 React 훅의 UI/런타임 혼재 S08 \u0026ldquo;hook\u0026rdquo; 용어의 이중 의미 7 프롬프트 캐싱의 암묵적 의존 S10 3가지 캐시 무효화 경로가 암묵적 8 MCP OAuth 2,465줄의 복잡성 S12 RFC 비일관성이 근본 원인 2. 5가지 설계 원칙 한계점을 극복하기 위해 5가지 핵심 원칙을 정립했다:\n원칙 1 \u0026ndash; 멀티 프로바이더: Anthropic, OpenAI, 로컬 모델(Ollama)을 단일 추상화로 지원.\n#[async_trait] pub trait Provider: Send + Sync { async fn stream(\u0026amp;self, request: ProviderRequest) -\u0026gt; Result\u0026lt;EventStream, ProviderError\u0026gt;; fn available_models(\u0026amp;self) -\u0026gt; \u0026amp;[ModelInfo]; fn name(\u0026amp;self) -\u0026gt; \u0026amp;str; } ProviderRequest는 프로바이더 중립적 구조체로, 각 구현체가 자신의 API 형식으로 변환한다.\n원칙 2 \u0026ndash; 네이티브 비동기: tokio 기반 완전 비동기. yield -\u0026gt; tx.send(), yield* -\u0026gt; 채널 전달로 AsyncGenerator 패턴을 대체.\n원칙 3 \u0026ndash; 모듈 분리: 대화 엔진, 도구, 훅, 프롬프트를 각각 독립 크레이트로 분리. main.tsx 모놀리스를 반복하지 않는다.\n원칙 4 \u0026ndash; 언어 중립 확장: SKILL.md 호환 + MCP 서버를 플러그인 단위로 활용.\n원칙 5 \u0026ndash; MCP 통합 활용: 도구뿐 아니라 리소스, 프롬프트, 샘플링까지 전체 스펙 활용.\n3. 7크레이트 아키텍처 graph TD CLI[\"harness-cli\u0026lt;br/\u0026gt;REPL 바이너리\"] --\u003e CORE[\"harness-core\u0026lt;br/\u0026gt;대화 엔진 + 턴 루프\"] CORE --\u003e PROV[\"harness-provider\u0026lt;br/\u0026gt;LLM 프로바이더 추상화\"] CORE --\u003e TOOLS[\"harness-tools\u0026lt;br/\u0026gt;도구 레지스트리 + 내장 도구\"] CORE --\u003e HOOKS[\"harness-hooks\u0026lt;br/\u0026gt;훅 파이프라인\"] CORE --\u003e PROMPT[\"harness-prompt\u0026lt;br/\u0026gt;CLAUDE.md 디스커버리\"] CORE --\u003e MCP[\"harness-mcp\u0026lt;br/\u0026gt;MCP 클라이언트\"] MCP --\u003e TOOLS style CLI fill:#b3e5fc style CORE fill:#fff9c4 style PROV fill:#c8e6c9 style TOOLS fill:#c8e6c9 style HOOKS fill:#c8e6c9 style PROMPT fill:#c8e6c9 style MCP fill:#e1bee7핵심 설계: harness-core만 다른 크레이트를 의존한다. 나머지는 서로 독립적이다(harness-mcp -\u0026gt; harness-tools 제외). 이 구조 덕분에:\n각 크레이트를 독립적으로 cargo test 가능 프로바이더 추가 시 harness-core 수정 불필요 MCP 도구가 내장 도구와 동일한 Tool 트레이트 구현 크레이트 핵심 책임 테스트 수 harness-provider LLM API 호출, SSE 파싱, 재시도 11 harness-tools 도구 레지스트리, 3-tier 동시성 12 harness-hooks 셸 훅 실행, deny short-circuit, rewrite 체인 9 harness-prompt 6단계 CLAUDE.md, SHA-256 중복 제거 9 harness-core 대화 엔진, StreamingToolExecutor 6 harness-mcp JSON-RPC, stdio 트랜스포트 14 harness-cli REPL 바이너리 \u0026ndash; Provider 트레이트 \u0026ndash; 멀티 프로바이더 기존 Rust 포트의 ApiClient 트레이트는 Anthropic 전용이었다(ApiRequest에 Anthropic 필드). Provider 트레이트는 프로바이더 중립적 ProviderRequest를 받아 각 구현체가 자신의 API 형식으로 변환한다. Box\u0026lt;dyn Provider\u0026gt;로 런타임에 폴백 체인 구현 가능.\nConversationEngine \u0026ndash; 턴 루프 pub struct ConversationEngine { session: Session, provider: Box\u0026lt;dyn Provider\u0026gt;, tool_executor: StreamingToolExecutor, hook_pipeline: HookPipeline, prompt_builder: PromptBuilder, budget: TokenBudget, } 기존 Rust 포트의 ConversationRuntime\u0026lt;C, T\u0026gt; 제네릭 패턴 대신 트레이트 객체를 사용한다. 런타임에 프로바이더를 교체할 수 있어야 하고(모델 폴백), 제네릭은 컴파일 타임에 타입이 고정되므로 유연성이 부족하다.\n스트리밍 도구 실행 (파이프라이닝) 기존 Rust 포트의 가장 큰 제약인 \u0026ldquo;모든 SSE 이벤트를 수집 후 도구 실행\u0026quot;을 해결했다:\nEventStream에서 ContentBlockStop(ToolUse) 이벤트 도착 시 즉시 전달 is_concurrency_safe() 검사 후 tokio::spawn으로 병렬 처리 API가 아직 스트리밍 중인 동안 도구 실행 병행 4. Phase 2 회고 \u0026ndash; 기존 포트 확장 Phase 3의 독자 하네스 이전에, Phase 2에서 기존 rust/ 프로토타입을 확장했다:\n스프린트 성과 핵심 패턴 S14-S15 오케스트레이션 모듈 + 3-tier 동시성 tokio::JoinSet 기반 병렬 실행 S16-S17 도구 확장 (19 -\u0026gt; 26개) Task, PlanMode, AskUser 추가 S18-S19 훅 실행 파이프라인 stdin JSON, deny short-circuit S20-S21 스킬 디스커버리 .claude/skills/ 스캔, 프롬프트 주입 Phase 2의 코드 대부분은 Phase 3에서 재작성되었다. 그러나 프로토타입 과정에서 발견한 질문들(\u0026ldquo;왜 AsyncGenerator인가?\u0026rdquo;, \u0026ldquo;왜 도구가 UI를 몰라야 하는가?\u0026quot;)이 최종 설계를 결정했다.\n5. 61개 테스트와 MockProvider 패턴 모든 크레이트가 독립적으로 테스트 가능하다. MockProvider를 통해 실제 API 호출 없이 대화 엔진의 전체 턴 루프를 검증한다:\nharness-provider: 11 테스트 (SSE 파싱, 재시도, 스트림) harness-tools: 12 테스트 (레지스트리, 동시성, 실행) harness-hooks: 9 테스트 (deny 단락, rewrite 체인, 타임아웃) harness-prompt: 9 테스트 (6단계 디스커버리, 해시 중복제거) harness-core: 6 테스트 (턴 루프, 도구 호출, 최대 반복) harness-mcp: 14 테스트 (JSON-RPC, 초기화, 도구 목록) 6. Phase 1-2 교훈이 설계에 반영된 방식 flowchart LR subgraph Phase1[\"Phase 1 -- 이해\"] direction TB P1A[\"S02: AsyncGenerator 체인\"] P1B[\"S05: 42개 도구 분류\"] P1C[\"S08: 런타임 vs React 훅\"] P1D[\"S10: 6단계 CLAUDE.md\"] P1E[\"S12: MCP 연결 관리\"] P1F[\"S13: 스킬 = 프롬프트\"] end subgraph Phase3[\"Phase 3 -- 독자 하네스\"] direction TB P3A[\"EventStream + mpsc 채널\"] P3B[\"Tool 트레이트 + 3-tier\"] P3C[\"HookPipeline (런타임만)\"] P3D[\"PromptAssembler 분리\"] P3E[\"harness-mcp stdio\"] P3F[\"SKILL.md 호환\"] end P1A --\u003e|\"yield -\u003e tx.send()\"| P3A P1B --\u003e|\"fail-closed 기본값\"| P3B P1C --\u003e|\"범위 축소\"| P3C P1D --\u003e|\"캐시 분할\"| P3D P1E --\u003e|\"SDK 없이 구현\"| P3E P1F --\u003e|\"텍스트 주입\"| P3F style Phase1 fill:#e1f5fe style Phase3 fill:#fff3e0 교훈 출처 설계 반영 StreamingToolExecutor 4단계 상태 기계 S03 harness-core에 async 구현 QueryDeps 콜백 DI의 타입 안전성 한계 S03 트레이트 객체 DI 6층 Bash 보안 체인 S06 check_permissions() + 훅 분리 에이전트 = 하네스 재귀 인스턴스 S06 ConversationEngine 재사용 ApiClient 동기 트레이트가 파이프라이닝 차단 S03 Provider async 트레이트 Deny 단락 + Rewrite 체이닝 S09 HookPipeline 동일 패턴 SHA-256 콘텐츠 해시가 경로 해시보다 우수 S11 harness-prompt 콘텐츠 해시 7. 학습한 아키텍처 패턴 TOP 10 27세션에서 추출한 핵심 아키텍처 패턴:\nAsyncGenerator/Stream 파이프라인: 스트리밍 LLM 응답의 핵심 추상화 3-tier 도구 동시성: ReadOnly/Write/Dangerous 분류로 안전성과 성능 균형 ToolSpec + ToolResult 이원화: 메타데이터(LLM 전달용)와 실행 결과 분리 훅 체인 실행: deny short-circuit, rewrite 체인, 독립 post-hook 변환 6단계 프롬프트 디스커버리: managed -\u0026gt; user -\u0026gt; project -\u0026gt; local 오버라이드 MCP 어댑터 패턴: 외부 프로토콜 도구를 내부 Tool 트레이트로 통일 Provider 추상화: 동일 인터페이스로 Anthropic/OpenAI 교체 가능 SSE 점진적 파싱: 네트워크 청크를 이벤트 프레임으로 조립 MockProvider 테스트: 사전 정의 이벤트 시퀀스로 엔진 동작 검증 스킬 = 프롬프트: 복잡한 플러그인 시스템 대신 텍스트 주입으로 충분 8. 전체 여정 회고 Phase 세션 핵심 산출물 Phase 1 \u0026ndash; 이해 S00-S13 14개 분석 문서, Rust 프로토타입 Phase 2 \u0026ndash; 재구현 S14-S21 오케스트레이션, 26 도구, 훅, 스킬 Phase 3 \u0026ndash; 독자 하네스 S22-S27 7크레이트 워크스페이스, 61+ 테스트 Claude Code는 프롬프트 엔지니어링 런타임이다. 핵심 루프가 메시지를 조립하고, 도구 시스템이 세상과의 상호작용 능력을 부여하고, 권한 시스템이 경계를 설정한다. CLAUDE.md가 컨텍스트를 주입하고, MCP가 외부를 통합하며, 훅과 에이전트가 자동화/위임을 가능케 하고, 플러그인/스킬이 사용자 확장 플랫폼으로 전환한다.\n향후 방향 진정한 스트리밍: SSE 바이트 스트림을 청크 단위로 처리 권한 시스템: 도구별 사용자 승인 워크플로우 MCP SSE 전송: stdio 외에 HTTP SSE 지원 토큰 예산 통합: 컨텍스트 윈도우 예산 자동 관리 멀티턴 에이전트 모드: 자율 반복 + 중단점 시스템 인사이트 좋은 추상화는 경계에서 나온다 \u0026ndash; Provider 트레이트, Tool 트레이트, HookRunner 트레이트. 모든 핵심 추상화는 모듈 간 경계를 정의하는 트레이트다. 기존 Rust 포트의 ConversationRuntime\u0026lt;C, T\u0026gt; 제네릭은 컴파일 타임 보장이 강하지만, 런타임에 프로바이더를 교체하거나 MCP 도구를 동적 등록하는 시나리오에서 한계가 있었다. Box\u0026lt;dyn Provider\u0026gt; + Box\u0026lt;dyn Tool\u0026gt; 트레이트 객체가 약간의 vtable 비용으로 런타임 유연성을 확보한다. LLM API 지연시간(수백 ms~수 s) 대비 vtable 비용은 측정 불가능한 수준이다.\n프로토타입의 가치는 코드가 아니라 질문이다 \u0026ndash; Phase 1-2의 프로토타입 코드 대부분은 Phase 3에서 재작성되었다. 그러나 \u0026ldquo;왜 AsyncGenerator인가?\u0026rdquo;, \u0026ldquo;왜 도구가 UI를 몰라야 하는가?\u0026rdquo;, \u0026ldquo;왜 allow가 bypass하지 않는가?\u0026rdquo; 같은 질문들이 최종 설계를 결정했다. 10만줄 코드를 읽는 행위 자체가 답이 아니라, 읽으면서 발견하는 **설계 의도(왜)**가 진정한 산출물이다.\nTS 코드의 복잡성은 대부분 방어선이다 \u0026ndash; 권한 계층, 프론트매터 파싱, 중복 제거, symlink 방지. 이것들은 기능이 아니라 방어선이다. Rust는 타입 시스템과 소유권 모델로 일부를 컴파일타임에 보장할 수 있지만, 파일시스템 보안과 사용자 설정 우선순위 같은 런타임 정책은 명시적으로 구현해야 한다. 27세션은 이 방어선의 지도를 그리는 과정이었고, 그 지도가 독자 하네스의 설계를 안내했다.\n시리즈 완결. 전체 분석 문서는 claw-code 리포지토리에서 확인할 수 있다.\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-harness-anatomy-6/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-harness-anatomy-6/","title":"Claude Code 하네스 해부학 #6 — Claude Code를 넘어서, 7크레이트 독자 하네스 구축 회고"},{"content":"개요 Anthropic의 Claude가 단순한 챗봇을 넘어 하나의 생태계로 진화하고 있다. Chat은 웹과 데스크톱에서 대화하는 기본 인터페이스, Cowork는 파일 시스템과 브라우저를 직접 제어하는 데스크톱 에이전트, Code는 터미널에서 코드베이스 전체를 다루는 개발자용 CLI 도구다. 이 글에서는 세 제품의 차이점, 각각의 핵심 사용 사례, 그리고 Claude Code를 쓸 때 토큰 비용이 기하급수적으로 늘어나는 구조와 이를 줄이는 실전 팁을 정리한다.\nChat, Cowork, Code — 세 제품의 스펙트럼 Claude의 세 제품은 \u0026ldquo;접근성 vs 제어력\u0026quot;이라는 스펙트럼 위에 놓여 있다.\ngraph LR A[\"Chat \u0026lt;br/\u0026gt; 웹 + 데스크톱 \u0026lt;br/\u0026gt; 대화 중심\"] --\u003e B[\"Cowork \u0026lt;br/\u0026gt; 데스크톱 전용 \u0026lt;br/\u0026gt; 파일 + 브라우저 + 앱\"] B --\u003e C[\"Code \u0026lt;br/\u0026gt; 터미널 CLI \u0026lt;br/\u0026gt; 코드베이스 + 시스템 전체\"] style A fill:#e8f4f8,stroke:#2196F3 style B fill:#fff3e0,stroke:#FF9800 style C fill:#fce4ec,stroke:#E91E63Chat — 대화의 기본기 플랫폼: 웹(claude.ai) + 데스크톱 앱 핵심 기능: Projects(GPTs와 유사), Google Docs 연동, 커넥터, 웹 검색, Research 모드 적합한 사용자: 누구나 — 글쓰기, 요약, 질의응답, 리서치 Claude Chat의 강점은 긴 문서 처리와 글쓰기 품질이다. ChatGPT가 창의적 대화에, Gemini가 멀티모달과 Google Workspace 연동에 강하다면, Claude는 대량의 텍스트를 정확하게 다루는 데 특화되어 있다.\nCowork — 비개발자를 위한 에이전트 Cowork는 한 마디로 **\u0026ldquo;비개발자를 위한 Claude Code\u0026rdquo;**다. Windows/Mac 데스크톱 앱에서만 사용 가능하며, Claude Code보다 설치와 사용이 훨씬 간단하다.\n5가지 핵심 기능:\n기능 설명 예시 파일 관리 로컬 파일 분석/생성 영수증 사진 → Excel 정리 브라우저 제어 AI가 Chrome을 직접 클릭 웹사이트 자동 탐색/입력 외부 앱 커넥터 Gmail, Calendar, Notion, Slack 연동 Slack 채널 분석, 이메일 자동화 Skills 반복 워크플로우를 묶어 재사용 뉴스레터 자동 생성 Plugins 커넥터 + Skills 조합 LinkedIn 포스팅 자동화 Code — 개발자의 터미널 동반자 Claude Code는 터미널에서 실행되는 CLI 도구로, 코드베이스 전체에 접근할 수 있다.\nCowork와의 핵심 차이:\ngraph TB subgraph Cowork[\"Cowork 영역\"] F1[\"파일 분석/생성\"] F2[\"브라우저 자동화\"] F3[\"앱 커넥터\"] F4[\"Skills/Plugins\"] end subgraph Code[\"Code 영역\"] C1[\"코드베이스 전체 접근\"] C2[\"서브 에이전트 실행\"] C3[\"Git 통합\"] C4[\"MCP 서버 연동\"] C5[\"터미널 명령어 실행\"] end Cowork --\u003e|\"고급 기능이 필요하면\"| Code style Cowork fill:#fff3e0,stroke:#FF9800 style Code fill:#fce4ec,stroke:#E91E63 Cowork: 일상 업무 자동화 — 파일 분석, 브라우저 제어, 앱 연동 Code: 소프트웨어 개발 — 커스텀 코드 작성, 고급 자동화, 시스템 레벨 제어 추천 경로: Cowork부터 시작해서, 고급 기능이 필요해지면 Code로 넘어가면 된다.\n가격 구조 플랜 월 가격 주요 제한 Free $0 기본 대화만 Pro $20 Chat + Cowork + Code 사용 가능 Max $100/$200 대량 사용, 높은 토큰 한도 데스크톱 앱 사용을 권장한다. 웹에서는 Cowork/Code 기능이 제한된다.\nClaude Code 토큰 최적화 — 비용이 녹아내리는 구조 이해하기 Claude Code를 무심코 쓰면 토큰 비용이 기하급수적으로 증가한다. 핵심 원리를 이해해야 한다.\n왜 비용이 기하급수적으로 느는가 Claude Code는 매 메시지마다 전체 대화 내용을 다시 읽는다. 대화가 길어질수록 한 번의 메시지에 소모되는 토큰이 누적된다.\ngraph TD M1[\"1번째 메시지 \u0026lt;br/\u0026gt; ~7.5K tokens\"] --\u003e M10[\"10번째 메시지 \u0026lt;br/\u0026gt; ~25K tokens\"] M10 --\u003e M20[\"20번째 메시지 \u0026lt;br/\u0026gt; ~100K tokens\"] M20 --\u003e M30[\"30번째 메시지 \u0026lt;br/\u0026gt; ~232K tokens\"] M30 -.- NOTE[\"30번째 메시지는 \u0026lt;br/\u0026gt; 1번째의 31배 비용\"] style M1 fill:#c8e6c9,stroke:#4CAF50 style M10 fill:#fff9c4,stroke:#FFC107 style M20 fill:#ffe0b2,stroke:#FF9800 style M30 fill:#ffcdd2,stroke:#F44336 style NOTE fill:#f5f5f5,stroke:#9E9E9E초급자를 위한 핵심 팁 (52개 중 19개) 원본 영상에서 소개된 52개 팁 중 초급편 19개의 핵심을 요약한다.\n대화 관리\n/clear를 습관화하라 — 작업 하나 끝나면 바로 초기화. 토큰 누적을 원점으로 돌린다. 프롬프트 범위를 좁혀라 — \u0026ldquo;이 파일 고쳐줘\u0026quot;가 아니라 \u0026ldquo;readme 10번째 줄 수정해줘\u0026rdquo; 간단한 명령은 묶어라 — 쉬운 작업 여러 개를 한 메시지에 배치 필요한 부분만 붙여넣어라 — 파일 전체가 아니라 관련 코드 스니펫만 자리를 비우지 마라 — 무한 루프 위험. 실행 중에는 모니터링 모델 선택 6. 기본 모델을 Sonnet으로 설정 — Opus는 비용이 높다 7. 작업에 맞는 모델을 선택하라:\nHaiku: 단순 질문, 파일 이름 변경 등 Sonnet: 일반 개발 작업 (기본값으로 적합) Opus: 아키텍처 설계, 깊은 디버깅 등 고난도 작업 기타 설정과 습관\n불필요한 파일을 컨텍스트에 포함하지 않기 .claudeignore로 큰 파일/디렉토리 제외 작업 단위를 작게 유지 결과 확인 후 불필요한 대화는 정리 관련 도구 Quick Links 도구 설명 Whispree macOS 메뉴바 STT 앱. Apple Silicon 전용, 완전 로컬. Whisper + LLM 후처리로 한영 코드스위칭 최적화. 타이핑 대신 음성으로 프롬프트 입력 (3~5배 빠름) OpenClaude Claude Code 스타일의 오픈소스 코딩 에이전트 CLI. OpenAI, Gemini, DeepSeek, Ollama 등 200+ 모델 지원. VS Code 확장도 있음 WorkMux 터미널에서 여러 AI 에이전트를 병렬 실행하는 도구 참고 영상 클로드 코드보다 \u0026lsquo;코워크\u0026rsquo;가 초보자에게 훨씬 쉽고 강력합니다 클로드 채팅/코워크/코드 차이, 한 번에 이해하기 이렇게 안하면 클로드 코드 토큰이 녹아내립니다 - 1부 초급편 마무리 Claude 생태계는 \u0026ldquo;누구나 쓸 수 있는 Chat → 업무 자동화의 Cowork → 개발자의 Code\u0026quot;로 이어지는 명확한 스펙트럼을 갖고 있다. 자신의 기술 수준과 필요에 맞는 도구부터 시작하되, Claude Code를 쓴다면 토큰 구조를 반드시 이해하고 /clear 습관부터 들이자. 대화 30번째 메시지가 첫 메시지의 31배 비용이라는 사실을 알면, 최적화는 선택이 아니라 필수다.\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-claude-chat-cowork-code/cover-ko.jpg","permalink":"/ko/posts/claude-chat-cowork-code/","title":"Claude 생태계 완전 정리 — Chat, Cowork, Code의 차이와 토큰 절약 전략"},{"content":"개요 hybrid-image-search FastAPI 서비스에 OpenTelemetry 기반 분산 추적을 붙였다. 목표는 단순했다 — 이미지 검색 요청이 들어왔을 때 벡터 검색부터 Gemini API 호출까지 어디서 시간이 소요되는지 한눈에 보는 것. 그런데 패키지 설치부터 Grafana에서 트레이스가 실제로 보이기까지 12번의 수정이 필요했다. 이 글에서는 전체 아키텍처, 실제 코드, 그리고 삽질 과정을 정리한다.\n아키텍처 옵저버빌리티 파이프라인은 세 계층으로 구성된다. FastAPI 앱이 OpenTelemetry로 트레이스를 생성하고, 같은 EC2 인스턴스의 Grafana Alloy가 수집/배치 처리하며, Grafana Cloud Tempo에 저장된 트레이스를 UI에서 조회한다.\nflowchart LR A[\"FastAPI App \u0026lt;br/\u0026gt; OpenTelemetry SDK\"] --\u003e|OTLP HTTP :4318| B[\"Grafana Alloy \u0026lt;br/\u0026gt; on EC2\"] B --\u003e|OTLP HTTP| C[\"Grafana Cloud \u0026lt;br/\u0026gt; Tempo\"] C --\u003e D[\"Grafana UI \u0026lt;br/\u0026gt; Trace Explorer\"]핵심 설계 포인트는 gRPC가 아닌 OTLP HTTP (포트 4318)를 사용한 것이다. 이 선택이 왜 중요했는지는 디버깅 섹션에서 다룬다.\n1단계: 텔레메트리 모듈 설정의 핵심은 import 시점에 OpenTelemetry를 초기화하는 telemetry.py 모듈이다:\n# backend/src/telemetry.py import logging, os from contextlib import contextmanager import psutil from opentelemetry import trace from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor _endpoint = os.environ.get( \u0026#34;OTEL_EXPORTER_OTLP_ENDPOINT\u0026#34;, \u0026#34;http://localhost:4318\u0026#34; ) _environment = os.environ.get(\u0026#34;DEPLOYMENT_ENV\u0026#34;, \u0026#34;dev\u0026#34;) _resource = Resource.create({ \u0026#34;service.name\u0026#34;: \u0026#34;hybrid-image-search\u0026#34;, \u0026#34;deployment.environment\u0026#34;: _environment, }) _provider = TracerProvider(resource=_resource) _exporter = OTLPSpanExporter(endpoint=f\u0026#34;{_endpoint}/v1/traces\u0026#34;) _provider.add_span_processor(SimpleSpanProcessor(_exporter)) trace.set_tracer_provider(_provider) tracer = trace.get_tracer(\u0026#34;hybrid-image-search\u0026#34;) 세 가지 포인트:\nTracerProvider를 모듈 레벨에서 설정한다. 함수 안에서 하면 안 된다. FastAPIInstrumentor가 import 시점에 tracer provider 참조를 캐시하기 때문에, lifespan 함수에서 나중에 설정하면 이미 no-op provider를 잡고 있다.\nSimpleSpanProcessor를 사용한다. BatchSpanProcessor는 백그라운드 스레드에서 배치 전송하므로 성능은 좋지만, uv run으로 실행할 때 프로세스가 flush 전에 종료될 수 있다. SimpleSpanProcessor는 동기 전송이라 유실이 없다.\nOTLP HTTP exporter를 사용한다. gRPC는 grpcio 의존성이 필요하고 이 환경에서 안정성 문제가 있었다. HTTP exporter는 requests 기반이라 그냥 동작한다.\n2단계: traced_span 헬퍼 자동 계측 외에, 각 스팬별 리소스 사용량 — Gemini API 호출의 메모리 할당량, 벡터 검색의 CPU 시간 — 도 보고 싶었다:\n_process = psutil.Process(os.getpid()) @contextmanager def traced_span(name, **attrs): \u0026#34;\u0026#34;\u0026#34;CPU/메모리 측정이 포함된 스팬 생성.\u0026#34;\u0026#34;\u0026#34; mem_before = _process.memory_info().rss cpu_before = _process.cpu_times() with tracer.start_as_current_span(name) as span: for k, v in attrs.items(): span.set_attribute(k, v) yield span mem_after = _process.memory_info().rss cpu_after = _process.cpu_times() span.set_attribute(\u0026#34;process.memory_mb\u0026#34;, round(mem_after / 1024 / 1024, 1)) span.set_attribute(\u0026#34;process.memory_delta_kb\u0026#34;, round((mem_after - mem_before) / 1024, 1)) span.set_attribute(\u0026#34;process.cpu_user_ms\u0026#34;, round((cpu_after.user - cpu_before.user) * 1000, 1)) span.set_attribute(\u0026#34;process.cpu_system_ms\u0026#34;, round((cpu_after.system - cpu_before.system) * 1000, 1)) generation 라우트에서의 사용 예:\nwith traced_span(\u0026#34;generation.gemini_api\u0026#34;, model=model_name): response = await model.generate_content_async(prompt) with traced_span(\u0026#34;generation.prompt_build\u0026#34;, ref_count=len(references)): prompt = build_prompt(query, references) Grafana Tempo에서 이들은 FastAPI 루트 스팬의 하위 스팬으로 표시되며, 스팬 상세 패널에서 메모리/CPU 속성을 확인할 수 있다.\n3단계: FastAPI 연결 애플리케이션 연결은 두 곳에서 이루어진다:\n# main.py — 모듈 레벨 (app 생성 후) from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor FastAPIInstrumentor.instrument_app(app) # main.py — lifespan 함수 from telemetry import init_telemetry @asynccontextmanager async def lifespan(app): try: init_telemetry(db_engine=db_engine) except Exception as e: logger.warning(\u0026#34;Telemetry init failed: %s\u0026#34;, e) yield init_telemetry는 SQLAlchemy 계측 같은 선택적 기능을 처리한다. 핵심은 FastAPIInstrumentor를 모듈 레벨에 두는 것이다. lifespan 안에서 계측하면 잘못된 tracer provider를 캡처할 수 있다.\n텔레메트리 초기화의 try/except는 의도적이다 — 관측성 때문에 앱이 죽으면 안 된다. Alloy가 내려가 있거나 엔드포인트 설정이 잘못되어도 서비스는 정상 동작해야 한다.\n4단계: EC2의 Grafana Alloy Grafana Alloy는 로컬 컬렉터 역할을 한다. FastAPI 앱으로부터 OTLP 트레이스를 받아 배치 처리 후 Grafana Cloud로 전달한다:\notelcol.receiver.otlp \u0026#34;default\u0026#34; { grpc { endpoint = \u0026#34;127.0.0.1:4317\u0026#34; } http { endpoint = \u0026#34;127.0.0.1:4318\u0026#34; } output { traces = [otelcol.processor.batch.default.input] } } otelcol.processor.batch \u0026#34;default\u0026#34; { timeout = \u0026#34;5s\u0026#34; output { traces = [otelcol.exporter.otlphttp.grafana_cloud.input] } } otelcol.exporter.otlphttp \u0026#34;grafana_cloud\u0026#34; { client { endpoint = env(\u0026#34;GRAFANA_OTLP_ENDPOINT\u0026#34;) auth = otelcol.auth.basic.grafana_cloud.handler } } otelcol.auth.basic \u0026#34;grafana_cloud\u0026#34; { username = env(\u0026#34;GRAFANA_INSTANCE_ID\u0026#34;) password = env(\u0026#34;GRAFANA_API_TOKEN\u0026#34;) } Alloy는 127.0.0.1에만 바인딩되어 외부 노출이 없다. 인증 정보는 환경 변수로 주입하며, EC2의 systemd unit 파일에서 설정한다.\n5초 배치 타임아웃은 적절한 균형점이다 — 실시간에 가까운 가시성을 제공하면서도 요청당 여러 스팬을 묶을 수 있다.\n디버깅 여정 패키지 설치부터 Grafana에서 트레이스가 보이기까지 약 12번의 수정이 필요했다. 주요 이슈와 해결 과정은 다음과 같다:\n단계 문제 해결 1 트레이스가 전혀 안 보임 TracerProvider를 lifespan에서 설정했는데, FastAPIInstrumentor가 이미 no-op provider를 캐시한 상태. 모듈 레벨로 이동. 2 프로세스 종료 시 트레이스 유실 BatchSpanProcessor의 백그라운드 스레드가 uv run 종료 전에 flush 못 함. SimpleSpanProcessor로 전환. 3 gRPC 연결 실패 EC2에서 grpcio의 간헐적 문제. OTLP HTTP exporter로 전환. 4 Alloy 다운 시 앱 크래시 init_telemetry 주위에 에러 핸들링 없었음. lifespan에 try/except 추가. 5 FastAPI 스팬에 커스텀 속성 누락 tracer provider 설정 전에 FastAPIInstrumentor 호출. provider를 import 시점에, instrumentor를 app 생성 후 모듈 레벨에서 호출하도록 수정. 가장 미묘한 버그는 1번이었다. OpenTelemetry의 글로벌 tracer provider는 싱글턴이다 — FastAPIInstrumentor가 한 번 읽으면 그 참조를 캐시한다. 그 시점에 글로벌 provider가 아직 no-op 기본값이면, 나중에 진짜 provider를 설정해도 자동 계측된 스팬은 전부 허공으로 사라진다.\nGrafana에서 보이는 것 모든 설정이 완료되면, Grafana Tempo에서 service.name = hybrid-image-search로 필터링하면 전체 요청 워터폴을 볼 수 있다:\nflowchart TD A[\"GET /search\"] --\u003e B[\"search.vector_query\"] A --\u003e C[\"search.rerank\"] A --\u003e D[\"generation.injection\"] D --\u003e E[\"generation.prompt_build\"] E --\u003e F[\"generation.gemini_api\"]각 스팬에는 다음 정보가 포함된다:\nDuration — 소요 시간 process.memory_mb — 스팬 종료 시점의 RSS process.memory_delta_kb — 스팬 실행 중 할당된 메모리 process.cpu_user_ms / process.cpu_system_ms — 소비된 CPU 시간 예를 들어 generation.gemini_api 스팬은 평균 1.2초에 ~8MB를 할당하고, search.vector_query는 200ms에 메모리 영향이 거의 없다는 것을 바로 확인할 수 있다.\n배운 점 TracerProvider는 import 시점에 설정하라. import나 모듈 레벨에서 실행되는 instrumentor는 그 시점의 provider를 캡처한다. 늦은 초기화는 조용한 no-op을 의미한다.\n개발 환경과 단기 프로세스에서는 SimpleSpanProcessor를 쓰라. BatchSpanProcessor가 프로덕션 처리량에는 유리하지만, 클린 셧다운에 의존한다. 프로세스가 갑자기 종료되면 스팬이 유실된다.\nOTLP HTTP가 gRPC보다 이식성이 좋다. 의존성이 적고, 디버깅이 쉽고 (curl로 엔드포인트 테스트 가능), protobuf 컴파일 문제도 없다.\nAlloy를 로컬 컬렉터로 두는 것이 클라우드 직접 전송보다 낫다. 앱과 Grafana Cloud 인증을 분리하고, 배치 처리와 재시도를 처리하며, 앱은 localhost:4318만 알면 된다.\n텔레메트리 초기화에 에러 핸들링을 넣어라. 관측성은 graceful하게 열화되어야 한다. 컬렉터 설정 오류가 애플리케이션을 죽여서는 안 된다.\npsutil을 활용한 커스텀 리소스 메트릭은 비용 대비 가치가 높다. 스팬당 memory_info()와 cpu_times() 호출의 오버헤드는 무시할 수준이지만, 타이밍 데이터와 함께 메모리/CPU 정보가 있으면 성능 디버깅이 훨씬 풍부해진다.\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-grafana-otel-fastapi/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-grafana-otel-fastapi/","title":"FastAPI 애플리케이션에 Grafana Cloud 옵저버빌리티 구축하기"},{"content":"개요 Google의 Veo 모델 시리즈가 실험적인 영상 생성 도구에서 본격적인 프로덕션 도구로 빠르게 진화하고 있다. 2025년 10월 출시된 Veo 3.1은 향상된 리얼리즘, 네이티브 오디오 생성, 세밀한 편집 기능을 Vertex AI와 Flow App을 통해 제공한다. 동시에 AI 생성 영상의 배경 제거와 합성을 위한 실용적인 도구 생태계도 성장 중이다. VideoBGRemover 같은 서비스와 n8n 워크플로우 템플릿이 자동화된 영상 파이프라인을 크리에이터와 개발자 모두에게 열어주고 있다.\nVeo의 진화: 1.0에서 3.1까지 Google은 Veo를 놀라운 속도로 발전시켜 왔다. 매 버전마다 점진적 개선이 아닌 의미 있는 도약이 있었다.\nflowchart LR A[\"Veo 1.0 \u0026lt;br/\u0026gt; 기본 영상 생성\"] --\u003e B[\"Veo 2.0 \u0026lt;br/\u0026gt; 품질 + 일관성\"] B --\u003e C[\"Veo 3.0 \u0026lt;br/\u0026gt; 네이티브 오디오 \u0026lt;br/\u0026gt; 멀티모달 입력\"] C --\u003e D[\"Veo 3.1 \u0026lt;br/\u0026gt; 편집 컨트롤 \u0026lt;br/\u0026gt; 장면 확장 \u0026lt;br/\u0026gt; 긴 클립\"]Veo 3.1의 주요 변화 리얼리즘과 물리 시뮬레이션 향상 \u0026mdash; 조명, 그림자, 오브젝트 상호작용이 눈에 띄게 자연스러워짐 장면 일관성 \u0026mdash; 긴 시퀀스에서도 캐릭터와 환경이 일관되게 유지 더 긴 클립 \u0026mdash; 기존 한계를 넘어선 확장 생성 장면 확장(Scene Expansion) \u0026mdash; 기존 영상을 AI가 자연스럽게 연장 편집 컨트롤 \u0026mdash; 오브젝트 제거, 조명 조절, 그림자 조작을 파이프라인 내에서 직접 처리 오디오 개선 \u0026mdash; 영상 콘텐츠와 동기화되는 네이티브 오디오 생성 고도화 Flow App 통합 \u0026mdash; \u0026ldquo;Ingredients to Video\u0026rdquo;, \u0026ldquo;Frames to Video\u0026rdquo; 모드로 다양한 크리에이티브 워크플로우 지원 Veo 3.1은 Standard(고품질, 느림)와 Fast(빠른 처리) 두 가지 변형으로 제공된다. 모두 720p, 1080p를 지원하며 Vertex AI API를 통해 접근 가능하다.\nVertex AI에서의 오브젝트 제거 Veo 3.1의 실용적인 기능 중 하나가 Vertex AI Studio에서 제공하는 마스크 기반 오브젝트 제거다. 워크플로우는 간단하다:\n단계 작업 내용 소요 시간 준비 영상 업로드, 제거할 오브젝트 식별 2\u0026ndash;5분 마스킹 프레임별 또는 트래킹으로 마스크 그리기 3\u0026ndash;8분 생성 AI가 마스크 영역을 맥락에 맞는 배경으로 채움 1\u0026ndash;3분 검수 결과 확인, 아티팩트 발생 시 반복 회당 3\u0026ndash;6분 깔끔한 결과를 위한 팁:\n오브젝트보다 약간 넓게 마스킹해서 경계 아티팩트 방지 제거 후 배경이 어떻게 보여야 하는지 명시적으로 프롬프트에 기술 Google Flow 에디터에서 Add/Remove 도구가 점진적으로 배포 중 배경 제거 도구 생태계 Veo가 생성과 기본 편집을 담당한다면, 전용 배경 제거 도구는 영상이나 이미지에서 피사체를 알파 투명도와 함께 추출하는 특정 영역을 커버한다.\n클라우드 서비스 VideoBGRemover는 영상 특화 클라우드 서비스다:\n초당 과금 (기본 $4.80/분, 대량 시 $2.50/분까지) MP4, MOV, WEBM, GIF 포맷 지원 알파 채널 출력 포함 9가지 내보내기 포맷 일반적인 클립 5분 이내 처리 프로그래밍 방식 연동을 위한 API withoutBG는 오픈소스 배경 제거 API와 고품질 클라우드 처리를 위한 Pro 티어를 제공한다.\n오픈소스 옵션 오픈소스 생태계는 특히 Meta의 SAM(Segment Anything Model) 기반 도구가 풍부하다:\nSAM-remove-background \u0026mdash; SAM을 직접 활용한 오브젝트 추출 및 배경 제거 remback \u0026mdash; 배경 제거 특화 SAM 파인튜닝 carvekit \u0026mdash; 여러 세그멘테이션 모델을 래핑한 자동화 배경 제거 프레임워크 remove-bg (WebGPU) \u0026mdash; WebGPU로 브라우저에서 직접 배경 제거, 서버 비용 제로 WebGPU 접근이 특히 흥미롭다. 추론을 클라이언트 GPU로 옮기면 API 비용이 없고 데이터가 사용자 기기를 떠나지 않는다. 프라이버시 민감 사용 사례나 대량 처리에서 클라우드 API보다 실용적일 수 있다.\nRGBA 출력(RGB 컬러 채널 + Alpha 투명도 채널)이 합성을 가능하게 하는 핵심이다. 깔끔하게 분리된 피사체를 원하는 배경 위에 레이어링할 수 있다.\nn8n 워크플로우 템플릿: 영상 자동화 가장 흥미로운 부분은 videobgremover/videobgremover-n8n-templates 리포지토리다. 완전한 자동화 파이프라인을 n8n 워크플로우로 패키징해 제공한다:\nflowchart TD subgraph T1[\"템플릿 01: 영상 합성\"] A1[\"영상 업로드\"] --\u003e B1[\"VideoBGRemover API \u0026lt;br/\u0026gt; 배경 제거\"] B1 --\u003e C1[\"새 배경에 합성\"] C1 --\u003e D1[\"Google Drive \u0026lt;br/\u0026gt; 내보내기\"] end subgraph T2[\"템플릿 02: AI UGC 광고 생성기\"] A2[\"화면 녹화\"] --\u003e B2[\"Gemini 분석\"] B2 --\u003e C2[\"Sora 2 \u0026lt;br/\u0026gt; AI 배우 생성\"] C2 --\u003e D2[\"VideoBGRemover \u0026lt;br/\u0026gt; 합성\"] D2 --\u003e E2[\"최종 UGC 광고\"] end subgraph T3[\"기타 템플릿\"] F3[\"03: 이미지 합성\"] G3[\"04: AI 배경 생성\"] H3[\"05: Lottie 오버레이\"] endUGC 광고 파이프라인 (템플릿 02) 템플릿 02가 특히 주목할 만하다. 여러 AI 서비스를 하나의 자동화 플로우로 연결한다:\n입력: 제품이나 앱의 화면 녹화 Gemini: 녹화 영상을 분석해 제품이 하는 일을 파악 Sora 2: 제품을 소개하는 리얼한 AI 배우 영상 생성 VideoBGRemover: AI 배우의 배경을 제거하고 화면 녹화 위에 합성 출력: 바로 게시할 수 있는 UGC 스타일 광고 n8n 같은 오케스트레이션 도구가 개별 AI 기능을 엔드투엔드 프로덕션 워크플로우로 만드는 구체적인 사례다.\nVeo vs. 경쟁 모델 Veo 3.1의 주요 경쟁자는 OpenAI의 Sora와 기타 영상 생성 모델이다. 핵심 차별점은 Google의 통합 깊이다. Veo는 Vertex AI 안에 위치하기 때문에 다른 Google Cloud 서비스와 바로 연결되고, Flow App이 시각적 편집 레이어를 제공하며, API를 통해 커스텀 파이프라인(위의 n8n 워크플로우 포함)에 내장할 수 있다.\nSora가 크리에이티브 생성 품질에 집중하는 반면, Veo는 편집, 제거, 합성 기능이 내장된 보다 완전한 영상 프로덕션 툴킷으로 포지셔닝하고 있다.\n참고 링크 Veo 3.1 소개 \u0026mdash; 기능 정리 및 다른 영상 AI 모델과의 비교 Veo 오브젝트 제거 가이드 \u0026mdash; Vertex AI Studio에서의 마스킹 및 프롬프트 워크플로우 VideoBGRemover \u0026mdash; API 제공하는 영상 배경 제거 서비스 withoutBG \u0026mdash; 오픈소스 배경 제거 + Pro API 티어 n8n 워크플로우 템플릿 \u0026mdash; 영상 합성 파이프라인 자동화 템플릿 2026 배경 제거 도구 비교 \u0026mdash; 클라우드 및 로컬 옵션 비교 rembg vs Cloud API \u0026mdash; 배경 제거 방식 선택 가이드 carvekit과 rembg 비교 \u0026mdash; Python 배경 제거 라이브러리 비교 RGBA 설명 \u0026mdash; RGB vs RGBA, 알파 투명도 기초 설명 정리 영상 AI 분야가 \u0026ldquo;클립 하나 생성\u0026quot;에서 \u0026ldquo;영상 프로덕션\u0026quot;으로 전환되고 있다. Veo 3.1은 편집 컨트롤과 장면 조작 기능으로 이 흐름을 대표한다. 하지만 진짜 이야기는 도구 레이어에 있을 수 있다. Gemini + Sora + 배경 제거를 연결해 자동화된 광고 파이프라인을 만드는 n8n 템플릿이 이 분야의 방향을 보여준다. 개별 AI 모델이 더 큰 프로덕션 시스템의 컴포넌트가 되고 있으며, 실질적인 가치는 오케스트레이션 레이어에서 복리로 쌓인다.\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-veo-video-ai/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-veo-video-ai/","title":"Google Veo 3.1과 영상 AI 배경 제거 생태계"},{"content":"개요 이전 글: Hybrid Image Search 개발기 #8에서 톤/앵글 S3 마이그레이션과 EC2 배포 수정, hex 컬러 추출을 다뤘다. 이번에는 한 발짝 물러서서 관측 가능성(observability)에 집중했다.\nFastAPI 서버에 OpenTelemetry를 도입해 검색 파이프라인과 이미지 생성 파이프라인의 각 단계를 스팬으로 추적하고, EC2에 Grafana Alloy를 설치해 트레이스를 Grafana Cloud로 전송하는 구성을 완성했다. 이틀에 걸친 작업이었는데, 1일차의 깔끔한 구현과 2일차의 현실적인 디버깅이 극명하게 대비되었다.\n아키텍처 — 트레이스 수집 경로 아래 다이어그램은 트레이스가 앱에서 Grafana Cloud까지 전달되는 경로를 보여준다.\nflowchart LR A[\"FastAPI 앱 \u0026lt;br/\u0026gt; (OTel SDK)\"] --\u003e|OTLP HTTP| B[\"Grafana Alloy \u0026lt;br/\u0026gt; (localhost:4318)\"] B --\u003e|OTLP HTTP| C[\"Grafana Cloud \u0026lt;br/\u0026gt; Tempo\"] C --\u003e D[\"Grafana UI \u0026lt;br/\u0026gt; 트레이스 조회\"] A --\u003e|스팬 생성| E[\"traced_span \u0026lt;br/\u0026gt; CPU/메모리 메트릭\"] E --\u003e A핵심 구성요소는 세 가지다. 앱 내부의 OTel SDK가 스팬을 생성하고, EC2 로컬의 Grafana Alloy가 OTLP 수신 후 배치 처리하며, Grafana Cloud Tempo가 최종 저장 및 조회를 담당한다.\n1일차 — 깔끔한 초기 구현 첫날은 순조로웠다. OpenTelemetry 패키지를 추가하고, 텔레메트리 모듈을 만들고, 앱 라이프사이클에 연결하고, 두 파이프라인에 스팬을 삽입했다.\n텔레메트리 모듈 구조 # telemetry.py — Provider를 임포트 시점에 설정 _resource = Resource.create({ \u0026#34;service.name\u0026#34;: \u0026#34;hybrid-image-search\u0026#34;, \u0026#34;deployment.environment\u0026#34;: _environment, }) _provider = TracerProvider(resource=_resource) _exporter = OTLPSpanExporter(endpoint=f\u0026#34;{_endpoint}/v1/traces\u0026#34;) _provider.add_span_processor(SimpleSpanProcessor(_exporter)) trace.set_tracer_provider(_provider) tracer = trace.get_tracer(\u0026#34;hybrid-image-search\u0026#34;) TracerProvider를 모듈 수준에서 설정하는 이유는, uvicorn이 ASGI 앱을 바인딩하기 전에 provider가 준비되어야 FastAPIInstrumentor가 올바른 provider를 참조하기 때문이다.\n파이프라인 스팬 삽입 검색 파이프라인에는 임베딩 생성, 벡터 검색, 재랭킹 등 단계별로 스팬을 삽입했다. 생성 파이프라인에는 레퍼런스 주입(generation.injection), 프롬프트 빌드(generation.prompt_build), Gemini API 호출(generation.gemini_api) 스팬을 추가했다.\nDB 인덱스도 함께 추가했다. 검색과 생성 쿼리 성능이 트레이스에서 병목으로 보이기 전에 미리 정리한 것이다.\n2일차 — 현실과의 충돌 EC2에 Grafana Alloy를 설치하고 Grafana Cloud 연동을 설정한 후, 트레이스가 전혀 나타나지 않았다. 여기서부터 연속 6개의 fix 커밋이 이어졌다.\n문제 1: TracerProvider 초기화 시점 uvicorn이 앱을 로드하는 시점에 TracerProvider가 아직 설정되지 않아 FastAPIInstrumentor가 기본(no-op) provider를 참조했다. 해결: 모듈 임포트 시점에 provider를 설정하도록 변경.\n문제 2: BatchSpanProcessor의 비동기 플러시 uv run으로 실행하면 프로세스가 빠르게 종료되면서 BatchSpanProcessor의 백그라운드 스레드가 스팬을 내보내기 전에 죽었다. 해결: SimpleSpanProcessor로 교체해 스팬 생성 즉시 동기적으로 전송.\n문제 3: gRPC exporter 침묵 gRPC exporter가 연결 실패를 로그 없이 삼키고 있었다. 해결: OTLP HTTP exporter로 전환. HTTP는 디버깅이 용이하고 Alloy의 기본 HTTP 엔드포인트(4318)와 바로 호환된다.\n문제 4: 텔레메트리 초기화 크래시 OTel 초기화 중 예외가 발생하면 앱 전체가 죽었다. 해결: try/except로 감싸서 텔레메트리 실패가 앱 가동을 막지 않도록 변경.\n문제 5: FastAPIInstrumentor provider 누락 FastAPIInstrumentor().instrument()가 글로벌 provider를 자동으로 찾지 못하는 경우가 있었다. 해결: tracer_provider를 명시적으로 전달.\n문제 6: 모듈 임포트 순서 main.py에서 app = FastAPI()와 instrumentation 호출의 순서 문제. 해결: FastAPIInstrumentor를 모듈 수준에서 app 생성 직후에 호출.\nGrafana Alloy 구성 EC2에 배포한 Alloy 설정은 간결하다.\notelcol.receiver.otlp \u0026#34;default\u0026#34; { grpc { endpoint = \u0026#34;127.0.0.1:4317\u0026#34; } http { endpoint = \u0026#34;127.0.0.1:4318\u0026#34; } output { traces = [otelcol.processor.batch.default.input] } } otelcol.processor.batch \u0026#34;default\u0026#34; { timeout = \u0026#34;5s\u0026#34; output { traces = [otelcol.exporter.otlphttp.grafana_cloud.input] } } otelcol.exporter.otlphttp \u0026#34;grafana_cloud\u0026#34; { client { endpoint = env(\u0026#34;GRAFANA_OTLP_ENDPOINT\u0026#34;) auth = otelcol.auth.basic.grafana_cloud.handler } } otelcol.auth.basic \u0026#34;grafana_cloud\u0026#34; { username = env(\u0026#34;GRAFANA_INSTANCE_ID\u0026#34;) password = env(\u0026#34;GRAFANA_API_TOKEN\u0026#34;) } 앱은 localhost:4318로 OTLP HTTP를 보내고, Alloy가 5초 배치로 묶어 Grafana Cloud Tempo로 전송한다. 인증 정보는 환경 변수로 관리한다.\ntraced_span — CPU/메모리 메트릭 자동 수집 마지막으로 traced_span 컨텍스트 매니저를 만들어, 스팬 전후의 CPU 시간과 메모리 사용량을 자동으로 측정해 스팬 속성에 기록하도록 했다.\n@contextmanager def traced_span(name, **attrs): \u0026#34;\u0026#34;\u0026#34;CPU/메모리 측정이 포함된 스팬 생성.\u0026#34;\u0026#34;\u0026#34; mem_before = _process.memory_info().rss cpu_before = _process.cpu_times() with tracer.start_as_current_span(name) as span: for k, v in attrs.items(): span.set_attribute(k, v) yield span mem_after = _process.memory_info().rss cpu_after = _process.cpu_times() span.set_attribute(\u0026#34;process.memory_mb\u0026#34;, round(mem_after / 1024 / 1024, 1)) span.set_attribute(\u0026#34;process.memory_delta_kb\u0026#34;, round((mem_after - mem_before) / 1024, 1)) span.set_attribute(\u0026#34;process.cpu_user_ms\u0026#34;, round((cpu_after.user - cpu_before.user) * 1000, 1)) span.set_attribute(\u0026#34;process.cpu_system_ms\u0026#34;, round((cpu_after.system - cpu_before.system) * 1000, 1)) psutil.Process로 현재 프로세스의 RSS 메모리와 CPU user/system 시간을 스팬 시작/종료 시점에 측정한다. 이를 통해 Grafana에서 각 파이프라인 단계가 소비하는 리소스를 개별적으로 확인할 수 있다. 검색 파이프라인과 생성 파이프라인 모두 traced_span으로 교체 완료했다.\n커밋 로그 메시지 변경 파일 feat: add no-text directive for injected refs and remove color palettes prompt.py, App.tsx, GeneratedImageDetail.tsx deps: add OpenTelemetry packages for observability requirements.txt feat: add telemetry module with OpenTelemetry init and tracer telemetry.py feat: wire OpenTelemetry init into app lifespan main.py feat: add OpenTelemetry spans to search pipeline stages search.py feat: add OpenTelemetry spans to generation pipeline generation.py add indices DB migration infra: add Grafana Alloy config and EC2 setup guide infra/alloy/config.alloy deps: move OpenTelemetry packages to pyproject.toml pyproject.toml fix: set OTel TracerProvider at import time telemetry.py fix: use SimpleSpanProcessor for reliable export under uv run telemetry.py fix: switch to OTLP HTTP exporter for reliable trace delivery telemetry.py fix: add error handling for telemetry init telemetry.py fix: pass tracer_provider explicitly to FastAPIInstrumentor main.py fix: move FastAPI instrumentation to module level in main.py main.py feat: add traced_span helper with CPU/memory resource metrics telemetry.py feat: use traced_span for CPU/memory metrics in search and generation pipelines search.py, generation.py 인사이트 OTel 초기화는 반드시 임포트 시점에 완료하라. uvicorn 같은 ASGI 서버는 앱 모듈을 임포트한 직후 라우터와 미들웨어를 바인딩한다. FastAPIInstrumentor가 이 시점에 유효한 TracerProvider를 찾지 못하면 no-op tracer를 캐시해 버리고, 이후 아무리 provider를 설정해도 계측이 동작하지 않는다. 모듈 최상단에서 provider를 설정하는 패턴이 이 문제를 근본적으로 방지한다.\nBatchSpanProcessor는 장수(long-lived) 프로세스 전용이다. uv run이나 테스트처럼 프로세스가 빠르게 종료되는 환경에서는 백그라운드 플러시 스레드가 작동할 틈이 없다. SimpleSpanProcessor는 성능 대비 안정성 트레이드오프가 명확하지만, 개발/소규모 프로덕션에서는 합리적인 선택이다.\ngRPC보다 HTTP를 먼저 시도하라. OTLP gRPC exporter는 연결 실패를 조용히 처리해 디버깅을 어렵게 만든다. HTTP exporter는 상태 코드와 에러 메시지를 명확히 반환하므로, 새 인프라를 연결할 때 HTTP로 먼저 동작을 확인한 뒤 필요시 gRPC로 전환하는 것이 효율적이다.\n","date":"2026-04-06T00:00:00+09:00","image":"/images/posts/2026-04-06-hybrid-search-dev9/cover-ko.jpg","permalink":"/ko/posts/2026-04-06-hybrid-search-dev9/","title":"Hybrid Image Search 개발기 #9 — OpenTelemetry 분산 추적, Grafana Cloud 연동, traced_span 헬퍼"},{"content":"개요 2026년 4월 1일, Claude Code Max 20 플랜($200/월)을 사용하던 한 개발자가 평범한 코딩 세션에서 70분 만에 사용량 100%를 소진하는 경험을 했다. JSONL 로그 분석 결과 cache read 비율이 평균 36.1%(최저 21.1%)에 불과했다 — 정상이라면 90% 이상이어야 한다.\n이것이 ArkNill/claude-code-cache-analysis 레포지토리가 탄생한 배경이다. 개인 디버깅에서 시작해 커뮤니티 기반 체계적 분석으로 발전한 이 프로젝트는, 프록시(cc-relay)를 통한 실측 데이터로 5개 레이어에 걸친 7가지 버그를 확인했다.\n배경: 70분 만에 소진된 플랜 v2.1.89 standalone 바이너리에서 캐시 read 비율이 급락했다. 즉각적인 workaround로 v2.1.68(npm)로 다운그레이드하자 cache read가 97.6% 평균(119 entries)으로 즉시 회복 — 회귀가 v2.1.89에서 발생했음이 확인됐다.\n이후 ANTHROPIC_BASE_URL 환경 변수를 이용한 투명 모니터링 프록시(cc-relay)를 구성해 요청별 데이터를 수집하기 시작했다. 91개 이상의 관련 GitHub 이슈에서 같은 현상을 보고한 다른 사용자들과 함께, 퍼즐 조각들을 하나의 구조화된 분석으로 통합했다.\n7가지 확인된 버그 (v2.1.91 기준) flowchart TD A[\"Claude Code 요청\"] --\u003e B{\"버전 확인\"} B --\u003e|\"v2.1.89 standalone\"| C[\"B1: Sentinel \u0026lt;br/\u0026gt; 캐시 prefix 손상 \u0026lt;br/\u0026gt; → 4-17% cache read\"] B --\u003e|\"--resume 사용\"| D[\"B2: Resume \u0026lt;br/\u0026gt; 전체 컨텍스트 재전송 \u0026lt;br/\u0026gt; → 20x 비용\"] B --\u003e|\"v2.1.91\"| E[\"캐시 정상 95-99%\"] E --\u003e F{\"추가 버그 확인\"} F --\u003e G[\"B3: False RL \u0026lt;br/\u0026gt; 가짜 Rate Limit 에러\"] F --\u003e H[\"B4: Microcompact \u0026lt;br/\u0026gt; tool 결과 조용히 삭제\"] F --\u003e I[\"B5: Budget Cap \u0026lt;br/\u0026gt; 200K 집계 제한 \u0026lt;br/\u0026gt; → 1-41자로 잘림\"] F --\u003e J[\"B8: Log Inflation \u0026lt;br/\u0026gt; JSONL 중복 항목 \u0026lt;br/\u0026gt; → 2.87x 부풀림\"] 버그 동작 영향 v2.1.91 상태 B1 Sentinel Standalone 바이너리가 캐시 prefix 손상 4-17% cache read (v2.1.89) 수정됨 B2 Resume --resume이 전체 컨텍스트를 캐시 없이 재전송 재시작당 20x 비용 수정됨 B3 False RL 클라이언트가 가짜 에러로 API 호출 차단 즉각적인 \u0026ldquo;Rate limit reached\u0026rdquo;, API 호출 0건 미수정 B4 Microcompact 세션 중간에 tool 결과가 조용히 삭제 컨텍스트 품질 저하 미수정 B5 Budget Cap tool 결과 200K 집계 제한 이전 결과가 1-41자로 잘림 미수정 (MCP만 우회 가능) B8 Log Inflation Extended thinking이 JSONL 항목 중복 2.87x 로컬 토큰 부풀림 미수정 Server 피크 시간 제한 강화 + 1M 빌링 버그 실효 쿼터 감소 의도적 설계 핵심 버그 상세 분석 B1: Sentinel 버그 (수정됨) Standalone 바이너리는 단일 ELF 64비트 실행 파일(~228MB, 내장 Bun 런타임)로 배포된다. 이 바이너리에는 cch=00000으로 캐시 prefix를 교체하는 Sentinel 메커니즘이 포함되어 있었고, 이것이 캐시 prefix를 손상시켰다.\nnpm 패키지(cli.js, ~13MB, Node.js 실행)에는 이 로직이 없어 버그에 면역이었다.\nv2.1.91에서 stripAnsi가 Bun.stripANSI를 통해 라우팅되도록 변경되면서 Sentinel 격차가 닫혔다. 현재 npm과 standalone은 동일하게 84.7% cold-start cache read를 달성한다.\nB2: Resume 버그 (수정됨) --resume 플래그 사용 시 전체 컨텍스트가 캐시 없이 billable input으로 재전송됐다. 재시작당 최대 20x 비용이 발생하는 심각한 버그였다. v2.1.91에서 transcript chain break fix가 적용됐지만, --resume 및 --continue 사용 자체를 피하는 것을 권장한다.\nB3: False Rate Limiting (미수정) 클라이언트 측에서 실제 API 호출 없이 \u0026ldquo;Rate limit reached\u0026rdquo; 에러를 생성한다. 151개 항목 / 65개 세션에서 측정됐다. API를 전혀 호출하지 않으면서 마치 서버 제한에 걸린 것처럼 동작한다.\nB4 \u0026amp; B5: Microcompact와 Budget Cap (미수정) 세션 중간에 tool 결과가 조용히 삭제되는 현상(327건 감지)과, 200K 집계 제한으로 이전 파일 읽기 결과가 1-41자로 잘리는 현상이 함께 작동한다. 약 15-20회 tool 사용 후 이전 컨텍스트가 사실상 사라진다고 볼 수 있다.\nCache TTL (버그 아님) 13시간 이상 유휴 상태 후 재개 시 350K 토큰 캐시가 완전 재구성된다. 캐시 write 비용은 $3.75/M, read는 $0.30/M — 12.5x 차이다. 5-26분의 짧은 유휴는 96%+ 캐시를 유지한다. 이것은 버그가 아닌 설계(5분 TTL)지만 알아두어야 할 사항이다.\nnpm vs Standalone: v2.1.90 벤치마크 지표 npm Standalone 승자 전체 cache read % 86.4% 86.2% 동률 안정 세션 95-99.8% 95-99.7% 동률 Sub-agent cold start 79-87% 47-67% npm Sub-agent warmed (5+ req) 87-94% 94-99% 동률 전체 테스트 사용량 Max 20의 7% Max 20의 5% 동률 v2.1.91에서는 sub-agent cold start 격차도 닫혀 양쪽 모두 동일하게 84.7%를 달성한다.\nAnthropic의 공식 입장 Lydia Hallie(Anthropic)는 4월 2일 X(트위터)에 다음과 같이 게시했다:\n\u0026ldquo;피크 시간 제한이 더 엄격해졌고 1M 컨텍스트 세션이 더 커졌습니다. 몇 가지 버그를 수정했지만, 과금 초과는 없었습니다.\u0026rdquo;\n권장 사항으로는 Sonnet을 기본으로 사용, effort level 낮추기, 재개 대신 새 세션 시작, CLAUDE_CODE_AUTO_COMPACT_WINDOW=200000 설정 등을 제시했다.\n분석팀의 측정 데이터는 캐시 버그 수정에는 동의하지만, Anthropic이 언급하지 않은 5개의 추가 메커니즘을 식별했다.\n지금 당장 할 수 있는 것 v2.1.91로 업데이트 — 최악의 캐시 회귀가 수정됨 npm과 standalone 모두 v2.1.91에서 동일 — 어느 쪽이든 괜찮음 --resume과 --continue 사용 금지 — 전체 컨텍스트가 billable input으로 재전송됨 주기적으로 새 세션 시작 — 200K tool 결과 한도(B5) 때문에 15-20회 tool 사용 후 이전 파일 읽기가 조용히 잘림 /dream과 /insights 피하기 — 조용히 사용량을 소진하는 백그라운드 API 호출 // ~/.claude/settings.json — 자동 업데이트 비활성화 { \u0026#34;env\u0026#34;: { \u0026#34;DISABLE_AUTOUPDATER\u0026#34;: \u0026#34;1\u0026#34; } } 마치며 이 분석은 개인적인 디버깅에서 시작해 커뮤니티 기반의 체계적 조사로 발전한 좋은 사례다. ANTHROPIC_BASE_URL을 이용한 투명 프록시라는 단순한 도구로, 91개 이상의 GitHub 이슈가 공유하는 현상의 근본 원인을 측정 데이터로 뒷받침했다.\n캐시 버그(B1, B2)는 v2.1.91에서 수정됐지만, 나머지 5개 버그는 여전히 활성 상태다. Max 플랜 사용자라면 위의 실용적 대응법을 적용하고, 새로운 버전 출시 시 DISABLE_AUTOUPDATER로 검증된 버전을 유지하는 전략이 유효하다.\n원본 레포: ArkNill/claude-code-cache-analysis\n","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-claude-code-cache-analysis/cover.jpg","permalink":"/ko/posts/2026-04-03-claude-code-cache-analysis/","title":"Claude Code 캐시 버그 실측 분석: 7가지 버그와 그 영향"},{"content":"개요 Claude Code가 공식 플러그인 마켓플레이스 시스템을 출시했다. 단순한 확장 기능 설치를 넘어 팀 단위 배포, 버전 관리, 권한 제어까지 아우르는 본격적인 생태계다. 이 글에서는 플러그인을 직접 만들고 마켓플레이스로 배포하는 전체 흐름을 기술적으로 분석한다.\n마켓플레이스 아키텍처 전체 흐름 플러그인 마켓플레이스 시스템은 크게 세 계층으로 구성된다: 마켓플레이스 카탈로그, 플러그인 소스, 로컬 캐시. 아래 다이어그램은 전체 흐름을 보여준다.\nflowchart TD A[\"Developer \u0026lt;br/\u0026gt; 플러그인 제작\"] --\u003e B[\"plugin.json \u0026lt;br/\u0026gt; 매니페스트 정의\"] B --\u003e C[\"marketplace.json \u0026lt;br/\u0026gt; 카탈로그 등록\"] C --\u003e D{\"배포 방식\"} D --\u003e E[\"GitHub \u0026lt;br/\u0026gt; owner/repo\"] D --\u003e F[\"GitLab \u0026lt;br/\u0026gt; git URL\"] D --\u003e G[\"npm \u0026lt;br/\u0026gt; 패키지\"] D --\u003e H[\"상대 경로 \u0026lt;br/\u0026gt; ./plugins/...\"] E --\u003e I[\"사용자\"] F --\u003e I G --\u003e I H --\u003e I I --\u003e J[\"\u0026lt;br/\u0026gt;/plugin marketplace add\u0026lt;br/\u0026gt;마켓플레이스 등록\"] J --\u003e K[\"\u0026lt;br/\u0026gt;/plugin install\u0026lt;br/\u0026gt;플러그인 설치\"] K --\u003e L[\"~/.claude/plugins/cache \u0026lt;br/\u0026gt; 로컬 캐시\"] L --\u003e M[\"Claude Code \u0026lt;br/\u0026gt; 플러그인 활성화\"]플러그인 제작: 구조와 매니페스트 플러그인 디렉토리 구조 플러그인은 .claude-plugin/plugin.json 매니페스트를 중심으로 구성된다. 핵심 규칙은 하나다: commands/, agents/, skills/, hooks/는 반드시 플러그인 루트에 위치해야 하며, .claude-plugin/ 안에 넣으면 안 된다.\nmy-plugin/ ├── .claude-plugin/ │ └── plugin.json ← 매니페스트만 여기에 ├── skills/ │ └── code-review/ │ └── SKILL.md ├── commands/ ├── agents/ ├── hooks/ │ └── hooks.json ├── .mcp.json ├── .lsp.json ├── bin/ ← Bash PATH에 추가될 실행파일 └── settings.json ← 플러그인 기본 설정 plugin.json 매니페스트 { \u0026#34;name\u0026#34;: \u0026#34;quality-review-plugin\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Adds a /quality-review skill for quick code reviews\u0026#34;, \u0026#34;version\u0026#34;: \u0026#34;1.0.0\u0026#34;, \u0026#34;author\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;Your Name\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;you@example.com\u0026#34; }, \u0026#34;homepage\u0026#34;: \u0026#34;https://github.com/you/quality-review-plugin\u0026#34;, \u0026#34;license\u0026#34;: \u0026#34;MIT\u0026#34; } name 필드는 스킬 네임스페이스가 된다. quality-review-plugin으로 등록된 플러그인의 hello 스킬은 /quality-review-plugin:hello로 호출된다. 이 네임스페이싱이 여러 플러그인 간 이름 충돌을 막는다.\nSkills 추가 스킬은 skills/ 디렉토리 아래 폴더명이 스킬명이 되는 구조다. SKILL.md의 frontmatter에 description을 적으면 Claude가 자동으로 상황에 맞게 호출한다.\n--- name: code-review description: Reviews code for best practices and potential issues. Use when reviewing code, checking PRs, or analyzing code quality. --- When reviewing code, check for: 1. Code organization and structure 2. Error handling 3. Security concerns 4. Test coverage $ARGUMENTS 플레이스홀더를 사용하면 사용자 입력을 동적으로 받을 수 있다: /my-plugin:hello Alex.\nLSP 서버 연동 공식 마켓플레이스에는 이미 주요 언어(TypeScript, Python, Rust, Go 등) LSP 플러그인이 제공된다. 지원되지 않는 언어라면 .lsp.json으로 직접 구성할 수 있다.\n{ \u0026#34;go\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;gopls\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;serve\u0026#34;], \u0026#34;extensionToLanguage\u0026#34;: { \u0026#34;.go\u0026#34;: \u0026#34;go\u0026#34; } } } LSP 플러그인이 설치되면 Claude는 파일 수정 후 자동으로 타입 오류, 누락된 import, 구문 오류를 감지한다.\n기본 설정 배포 settings.json으로 플러그인 활성화 시 기본 설정을 배포할 수 있다. 현재는 agent 키만 지원된다.\n{ \u0026#34;agent\u0026#34;: \u0026#34;security-reviewer\u0026#34; } 마켓플레이스 파일 스키마 marketplace.json 필수 필드 .claude-plugin/marketplace.json이 마켓플레이스의 핵심이다.\n{ \u0026#34;name\u0026#34;: \u0026#34;company-tools\u0026#34;, \u0026#34;owner\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;DevTools Team\u0026#34;, \u0026#34;email\u0026#34;: \u0026#34;devtools@example.com\u0026#34; }, \u0026#34;metadata\u0026#34;: { \u0026#34;description\u0026#34;: \u0026#34;Internal developer tools marketplace\u0026#34;, \u0026#34;version\u0026#34;: \u0026#34;1.0.0\u0026#34;, \u0026#34;pluginRoot\u0026#34;: \u0026#34;./plugins\u0026#34; }, \u0026#34;plugins\u0026#34;: [ { \u0026#34;name\u0026#34;: \u0026#34;code-formatter\u0026#34;, \u0026#34;source\u0026#34;: \u0026#34;./plugins/formatter\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Automatic code formatting on save\u0026#34;, \u0026#34;version\u0026#34;: \u0026#34;2.1.0\u0026#34; }, { \u0026#34;name\u0026#34;: \u0026#34;deployment-tools\u0026#34;, \u0026#34;source\u0026#34;: { \u0026#34;source\u0026#34;: \u0026#34;github\u0026#34;, \u0026#34;repo\u0026#34;: \u0026#34;company/deploy-plugin\u0026#34; }, \u0026#34;description\u0026#34;: \u0026#34;Deployment automation tools\u0026#34; } ] } 예약된 이름: claude-code-marketplace, anthropic-marketplace, agent-skills 등 Anthropic 공식 마켓플레이스 이름은 사용 불가.\n플러그인 소스 타입 비교 소스 타입 형식 특징 상대 경로 \u0026quot;./plugins/my-plugin\u0026quot; Git 배포 시에만 동작, URL 배포 불가 GitHub {\u0026quot;source\u0026quot;: \u0026quot;github\u0026quot;, \u0026quot;repo\u0026quot;: \u0026quot;owner/repo\u0026quot;} ref, sha 핀닝 지원 Git URL {\u0026quot;source\u0026quot;: \u0026quot;url\u0026quot;, \u0026quot;url\u0026quot;: \u0026quot;https://...\u0026quot;} GitLab, Bitbucket, 자체 호스팅 지원 Git 서브디렉토리 {\u0026quot;source\u0026quot;: \u0026quot;git-subdir\u0026quot;, \u0026quot;url\u0026quot;: \u0026quot;...\u0026quot;, \u0026quot;path\u0026quot;: \u0026quot;tools/plugin\u0026quot;} 모노레포용 sparse clone npm {\u0026quot;source\u0026quot;: \u0026quot;npm\u0026quot;, \u0026quot;package\u0026quot;: \u0026quot;my-plugin\u0026quot;} npm registry 활용 중요 구분: 마켓플레이스 소스(카탈로그 위치)와 플러그인 소스(개별 플러그인 위치)는 별개다. 마켓플레이스 소스는 ref만 지원하고, 플러그인 소스는 ref와 sha 모두 지원한다.\nStrict 모드 { \u0026#34;name\u0026#34;: \u0026#34;my-plugin\u0026#34;, \u0026#34;source\u0026#34;: \u0026#34;./plugins/my-plugin\u0026#34;, \u0026#34;strict\u0026#34;: true } strict: true(기본값)면 plugin.json이 컴포넌트 정의의 권위 소스가 된다. 마켓플레이스에서 오버라이드하려면 strict: false로 설정.\n마켓플레이스 배포 전략 GitHub 배포 (권장) # 마켓플레이스 추가 /plugin marketplace add anthropics/claude-code # 특정 브랜치나 태그 지정 /plugin marketplace add https://gitlab.com/company/plugins.git#v1.0.0 팀 자동 설정 .claude/settings.json에 마켓플레이스를 등록하면 팀원들이 레포지토리를 신뢰할 때 자동으로 마켓플레이스가 추가된다.\n{ \u0026#34;extraKnownMarketplaces\u0026#34;: [ { \u0026#34;name\u0026#34;: \u0026#34;company-tools\u0026#34;, \u0026#34;source\u0026#34;: \u0026#34;github\u0026#34;, \u0026#34;repo\u0026#34;: \u0026#34;myorg/claude-plugins\u0026#34; } ] } 컨테이너 환경 사전 설치 CI/CD나 컨테이너 환경에서는 forcedPlugins로 특정 플러그인을 강제 설치할 수 있다. Managed settings를 통해 팀 전체에 배포 가능.\n버전 관리와 릴리즈 채널 { \u0026#34;name\u0026#34;: \u0026#34;my-plugin\u0026#34;, \u0026#34;source\u0026#34;: { \u0026#34;source\u0026#34;: \u0026#34;github\u0026#34;, \u0026#34;repo\u0026#34;: \u0026#34;owner/plugin-repo\u0026#34;, \u0026#34;ref\u0026#34;: \u0026#34;v2.0.0\u0026#34;, \u0026#34;sha\u0026#34;: \u0026#34;a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0\u0026#34; } } sha로 정확한 커밋을 핀닝해 재현 가능한 배포를 보장할 수 있다.\nCLI로 마켓플레이스 관리 명령 설명 /plugin marketplace add \u0026lt;source\u0026gt; 마켓플레이스 등록 /plugin marketplace list 등록된 마켓플레이스 목록 /plugin marketplace update \u0026lt;name\u0026gt; 마켓플레이스 업데이트 /plugin marketplace remove \u0026lt;name\u0026gt; 마켓플레이스 제거 /plugin install \u0026lt;name\u0026gt;@\u0026lt;marketplace\u0026gt; 플러그인 설치 /plugin disable \u0026lt;name\u0026gt;@\u0026lt;marketplace\u0026gt; 플러그인 비활성화 /plugin uninstall \u0026lt;name\u0026gt;@\u0026lt;marketplace\u0026gt; 플러그인 제거 /reload-plugins 재시작 없이 플러그인 리로드 스코프 옵션으로 설치 범위를 지정할 수 있다:\nUser scope: 모든 프로젝트에 적용 Project scope: 해당 레포 협업자 공유 (.claude/settings.json) Local scope: 현재 레포에서 본인만 적용 권한 시스템 연동 계층적 권한 구조 Claude Code의 권한은 deny → ask → allow 순서로 평가된다. 첫 번째 매칭 규칙이 우선된다.\n{ \u0026#34;permissions\u0026#34;: { \u0026#34;allow\u0026#34;: [ \u0026#34;Bash(npm run *)\u0026#34;, \u0026#34;Bash(git commit *)\u0026#34; ], \u0026#34;deny\u0026#34;: [ \u0026#34;Bash(git push *)\u0026#34; ] } } 권한 모드 모드 설명 default 첫 사용 시 승인 요청 acceptEdits 파일 수정 자동 허용 plan 분석만 가능, 수정 불가 auto 배경 안전 검사 후 자동 승인 (연구 프리뷰) dontAsk 사전 승인된 툴만 허용 bypassPermissions 권한 프롬프트 전체 우회 (격리 환경 전용) 도구별 권한 규칙 { \u0026#34;permissions\u0026#34;: { \u0026#34;allow\u0026#34;: [ \u0026#34;WebFetch(domain:github.com)\u0026#34;, \u0026#34;mcp__puppeteer__puppeteer_navigate\u0026#34;, \u0026#34;Agent(Explore)\u0026#34; ], \u0026#34;deny\u0026#34;: [ \u0026#34;Agent(Plan)\u0026#34;, \u0026#34;Read(~/.ssh/**)\u0026#34; ] } } 권한 확장: Hooks PreToolUse 훅으로 런타임에 동적 권한 평가가 가능하다. 훅이 exit code 2를 반환하면 allow 규칙이 있어도 툴 호출이 차단된다.\n{ \u0026#34;hooks\u0026#34;: { \u0026#34;PreToolUse\u0026#34;: [ { \u0026#34;matcher\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;hooks\u0026#34;: [{ \u0026#34;type\u0026#34;: \u0026#34;command\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;validate-command.sh\u0026#34; }] } ] } } 공식 마켓플레이스 플러그인 현황 Anthropic 공식 마켓플레이스(claude-plugins-official)는 Claude Code 시작 시 자동으로 추가된다.\n코드 인텔리전스: clangd-lsp, gopls-lsp, pyright-lsp, rust-analyzer-lsp, typescript-lsp 등 11개 언어 지원\n외부 연동: GitHub, GitLab, Jira/Confluence, Figma, Vercel, Firebase, Slack, Sentry 등\n개발 워크플로: commit-commands, pr-review-toolkit, agent-sdk-dev, plugin-dev\n출력 스타일: explanatory-output-style, learning-output-style\nQuick Links (빠른 링크) 플러그인 마켓플레이스 생성 및 배포 플러그인 제작 가이드 플러그인 검색 및 설치 권한 설정 공식 플러그인 제출 (Claude.ai) 공식 플러그인 제출 (Console) Insights (인사이트) 플러그인 vs 독립 설정: .claude/ 디렉토리의 독립 설정은 프로젝트별, 개인용으로 적합하다. 팀 공유나 여러 프로젝트 재사용이 필요하면 플러그인으로 패키징하는 것이 맞다. 스킬 이름이 /hello에서 /my-plugin:hello로 네임스페이스가 붙는 것이 유일한 트레이드오프.\n마켓플레이스 소스와 플러그인 소스는 별개: 마켓플레이스 카탈로그가 있는 레포와 실제 플러그인이 있는 레포는 다를 수 있다. 이 분리 덕분에 하나의 카탈로그에서 여러 레포의 플러그인을 관리할 수 있다.\n상대 경로의 함정: ./plugins/my-plugin 같은 상대 경로는 Git 기반 배포에서만 동작한다. URL로 marketplace.json을 직접 배포하면 상대 경로가 해석되지 않는다. URL 배포 시에는 GitHub, npm, git URL 소스를 사용해야 한다.\nsha 핀닝으로 재현성 확보: ref(브랜치/태그)만 사용하면 브랜치 업데이트 시 예상치 못한 변경이 들어올 수 있다. 프로덕션 환경에서는 sha로 정확한 커밋을 고정하는 것이 안전하다.\n권한과 샌드박싱은 보완 관계: 권한 규칙은 Claude가 어떤 툴을 사용할 수 있는지 제어하고, 샌드박싱은 OS 레벨에서 Bash 명령의 파일시스템/네트워크 접근을 제한한다. Read(./.env) deny 규칙은 Read 툴을 막지만 cat .env는 막지 못한다. 진정한 격리가 필요하면 샌드박싱을 함께 활성화해야 한다.\n","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-claude-code-plugin-marketplace/cover.jpg","permalink":"/ko/posts/2026-04-03-claude-code-plugin-marketplace/","title":"Claude Code 플러그인 마켓플레이스 완전 분석"},{"content":"개요 이전 글: Hybrid Image Search 개발기 #7에서 LLM 기반 톤/앵글 카테고리 자동 주입을 구현했다. 이번 스프린트에서는 그 구현을 실제 배포 환경에서 안정적으로 작동하게 다듬는 데 집중했다.\n크게 세 축으로 작업이 진행됐다. 첫째, 로컬 파일시스템에 남아있던 카테고리 이미지 읽기 로직을 완전히 S3로 전환했다. 둘째, EC2 프로덕션 인스턴스에서 torch의 CUDA 의존성이 충돌하는 문제를 CPU-only 인덱스 핀으로 해결했다. 셋째, 톤 레퍼런스 이미지에서 지배색 hex 코드를 추출해 DB에 저장하고, 프롬프트 상세 UI에 컬러 스와치로 렌더링했다.\n톤/앵글 카테고리 이미지 — S3 읽기로 전환 이전 구현에서 injection.py의 _list_category_images()는 로컬 data/tone_angle_image_ref/{category}/ 폴더를 os.listdir()으로 읽고 있었다. EC2 인스턴스에는 이 폴더가 없으므로 항상 빈 리스트가 반환되어 주입이 무력화되는 버그가 있었다.\n수정 방향은 명확했다. S3Storage 인스턴스를 select_auto_injection()에 전달하고, 카테고리 폴더 목록을 s3.list_objects(prefix) 호출로 교체하는 것이다.\n# 변경 전: 로컬 폴더를 직접 읽음 def _list_category_images(category: str) -\u0026gt; list[str]: folder = TONE_ANGLE_IMAGE_DIR / category return [f.name for f in folder.iterdir() if ...] # 변경 후: S3에서 prefix 기반으로 조회 def _list_category_images(category: str, s3: S3Storage) -\u0026gt; list[str]: prefix = f\u0026#34;refs/tone_angle_image_ref/{category}/\u0026#34; keys = s3.list_objects(prefix) return [basename(k) for k in keys if k.lower().endswith(IMAGE_EXTS)] 동시에 S3 키 캐시(build_ref_key_cache) 구조도 수정해, data/tone_angle_image_ref/a(natural,film) 같은 중첩 경로가 refs/tone_angle_image_ref/a(natural,film)/{filename} 형식으로 올바르게 캐싱되도록 했다.\n# storage.py — Path.relative_to(\u0026#34;data\u0026#34;)로 서브디렉토리 구조 보존 ref_subdir = str(p.relative_to(\u0026#34;data\u0026#34;)) self._ref_key_cache[f.name] = f\u0026#34;refs/{ref_subdir}/{f.name}\u0026#34; EC2 배포 — torch CPU-only 핀 프로덕션 EC2 인스턴스에서 서버 기동 시 libcudnn.so.9 파일을 찾지 못해 임베딩 모델 로드에 실패하는 문제가 발생했다. sentence-transformers가 torch를 의존성으로 끌어오는데, uv가 CUDA 지원 torch를 설치하면서 실제로는 없는 CUDA 라이브러리를 참조하게 된 것이다.\n개발 환경에서는 nvidia-cudnn-cu12와 nvidia-cudnn-cu13이 모두 설치되어 있어 우연히 동작했지만, 프로덕션에는 cu13만 있어 충돌이 발생했다.\n해결책은 개별 cudnn 패키지를 추적하는 대신, pyproject.toml의 S3 인덱스 설정에서 CPU-only torch를 명시적으로 핀하는 것이었다.\n# pyproject.toml — CPU-only torch 인덱스 추가 [[tool.uv.index]] name = \u0026#34;pytorch-cpu\u0026#34; url = \u0026#34;https://download.pytorch.org/whl/cpu\u0026#34; explicit = true [tool.uv.sources] torch = [{ index = \u0026#34;pytorch-cpu\u0026#34; }] 이렇게 하면 uv sync 시 항상 CPU-only 빌드가 설치되어, EC2 인스턴스의 CUDA 환경 유무와 무관하게 안정적으로 동작한다.\nHex 컬러 추출 — 지배색 분석 \u0026amp; DB 저장 톤 레퍼런스 이미지가 어떤 색감을 대표하는지 시각적으로 확인할 수 있도록, 이미지에서 지배색 hex 코드를 추출해 generation_logs 테이블에 함께 저장하는 기능을 추가했다.\n아래 다이어그램은 데이터 흐름을 보여준다.\nflowchart TD A[\"이미지 생성 요청\"] --\u003e B[\"LLM 카테고리 분류\"] B --\u003e C[\"S3에서 카테고리 이미지 목록 조회\"] C --\u003e D[\"랜덤 이미지 선택 \u0026lt;br/\u0026gt; (tone + angle)\"] D --\u003e E[\"지배색 hex 추출 \u0026lt;br/\u0026gt; (PIL + K-Means)\"] E --\u003e F[\"generation_logs에 \u0026lt;br/\u0026gt; hex_colors 저장\"] F --\u003e G[\"Gemini API 이미지 생성\"] G --\u003e H[\"프론트엔드에 hex_colors 포함 응답\"] H --\u003e I[\"구조화된 프롬프트 UI \u0026lt;br/\u0026gt; 컬러 스와치 렌더링\"]지배색 추출은 scikit-learn의 KMeans를 사용해 이미지를 N개의 클러스터로 나누고, 각 클러스터의 중심색을 hex 형식으로 변환한다.\n# hex_color_extractor.py (개념) from PIL import Image from sklearn.cluster import KMeans import numpy as np def extract_dominant_hex_colors(image_bytes: bytes, n_colors: int = 5) -\u0026gt; list[str]: img = Image.open(io.BytesIO(image_bytes)).convert(\u0026#34;RGB\u0026#34;) img = img.resize((100, 100)) # 속도를 위해 축소 pixels = np.array(img).reshape(-1, 3) km = KMeans(n_clusters=n_colors, n_init=3) km.fit(pixels) centers = km.cluster_centers_.astype(int) return [f\u0026#34;#{r:02x}{g:02x}{b:02x}\u0026#34; for r, g, b in centers] 추출된 hex 값은 generation_logs.hex_colors(JSON 컬럼)에 저장되고, API 응답의 InjectedReference.hex_colors 필드를 통해 프론트엔드로 전달된다.\n구조화된 프롬프트 UI — hex 스와치 포함 기존에 이미지 상세 모달의 \u0026ldquo;작업 프롬프트\u0026rdquo; 섹션은 getFullPrompt()가 반환하는 원시 텍스트(마크다운 스타일 ###, === 구분자, 날것의 JSON hex 배열)를 whitespace-pre-wrap으로 그대로 뿌리고 있었다. 가독성이 매우 낮았다.\n이번에 renderStructuredPrompt() 함수를 추가해, 같은 데이터를 구조화된 형태로 렌더링하도록 교체했다.\n### 헤딩 → 앰버/스카이 컬러 섹션 헤더 === 구분자 → \u0026lt;hr\u0026gt; 엘리먼트 - 이미지 N: 줄 → 배지 + 설명 형식의 리스트 아이템 hex_colors 배열 → 컬러 원형 + 모노 hex 코드 pill 배지 복사 기능은 기존 fullPrompt raw 텍스트를 그대로 사용하므로 영향 없다.\n노-텍스트 디렉티브 \u0026amp; 컬러 팔레트 제거 주입된 레퍼런스 이미지의 프롬프트에 \u0026ldquo;이미지의 텍스트나 워터마크를 생성에 반영하지 말 것\u0026quot;을 명시하는 no-text 디렉티브를 추가했다. 또한 이미지 카드 오버레이와 상세 모달에서 컬러 팔레트 점 표시(dot 시각화)를 제거했다. 구조화된 프롬프트 섹션의 hex 스와치가 그 역할을 충분히 대체하기 때문이다.\n커밋 로그 메시지 변경 파일 fix: list tone/angle category images from S3 instead of local filesystem injection.py, storage.py, generation.py fix: pin torch to CPU-only index to prevent broken CUDA deps on EC2 pyproject.toml fix: fix the injection prompt prompt.py, injection.py docs: update README to reflect recent changes README.md feat: extract dominant hex colors from tone reference images injection.py, schemas.py, api.ts, DB migration feat: structured prompt display with hex color swatches in image detail GeneratedImageDetail.tsx feat: add no-text directive for injected refs and remove color palettes prompt.py, App.tsx, GeneratedImageDetail.tsx get rid of the test folder test/ 삭제 인사이트 로컬 개발 환경과 프로덕션 환경의 차이를 코드로 명시하라. S3 마이그레이션 이후에도 파일 목록 조회 코드가 로컬 경로를 참조하고 있었다. 이런 류의 버그는 개발 환경에서는 조용히 통과되다가 배포 직후에야 드러난다. 추상화 경계(여기서는 S3Storage)를 일관되게 사용하는 것이 방어책이다.\nCUDA 의존성은 명시적으로 핀해야 한다. torch는 환경에 따라 CPU/CUDA 빌드가 혼재될 수 있다. EC2처럼 GPU가 없는 인스턴스에서 CUDA 빌드가 설치되면 임포트 시점에 실패한다. pyproject.toml의 [[tool.uv.index]]로 CPU-only를 명시적으로 강제하면 이 클래스의 문제 전체를 예방할 수 있다.\nUI 렌더링과 데이터 직렬화는 분리해야 한다. 복사 기능이 필요한 raw 텍스트와, 화면에 보여줄 구조화된 렌더링을 동일한 데이터 소스에서 각각 파생시키는 패턴이 깔끔하다. getFullPrompt()는 그대로 유지하고 renderStructuredPrompt()를 별도로 추가한 방식이 이 원칙을 잘 따른다.\n","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-hybrid-search-dev8/cover.jpg","permalink":"/ko/posts/2026-04-03-hybrid-search-dev8/","title":"Hybrid Image Search 개발기 #8 — 톤/앵글 S3 마이그레이션, EC2 배포 수정, Hex 컬러 추출"},{"content":"개요 k-skill은 NomaDamas가 만든 한국인 특화 Claude Code 스킬 컬렉션이다. GitHub 스타 1,371개(포크 113개)를 받은 이 프로젝트는 SRT/KTX 기차 예매, KBO 야구 경기 결과, 카카오톡 메시지 전송, HWP 문서 처리, 미세먼지 조회 같은 한국 일상 업무를 AI 에이전트에게 위임할 수 있도록 설계되었다.\nClaude Code, Codex, OpenCode, OpenClaw/ClawHub 등 다양한 코딩 에이전트를 지원하며, 추가 클라이언트 API 레이어 없이 k-skill-proxy 같은 프록시 서버로 HTTP 요청만 넣으면 작동한다.\n스킬 구조와 통합 아키텍처 k-skill이 Claude Code와 어떻게 연동되는지 전체 흐름을 도식화하면 다음과 같다.\nflowchart TD User[\"사용자\"] --\u003e CC[\"Claude Code \u0026lt;br/\u0026gt; (AI 에이전트)\"] CC --\u003e Skills[\"k-skill 컬렉션\"] Skills --\u003e Auth[\"인증 필요 스킬\"] Skills --\u003e NoAuth[\"인증 불필요 스킬\"] Skills --\u003e Proxy[\"프록시 경유 스킬\"] Auth --\u003e SRT[\"SRT 예매\"] Auth --\u003e KTX[\"KTX 예매\"] Auth --\u003e Toss[\"토스증권 조회\"] NoAuth --\u003e KBO[\"KBO 경기 결과\"] NoAuth --\u003e Lotto[\"로또 당첨 확인\"] NoAuth --\u003e HWP[\"HWP 문서 처리\"] NoAuth --\u003e Zip[\"우편번호 검색\"] NoAuth --\u003e KakaoTalk[\"카카오톡 Mac CLI\"] NoAuth --\u003e Delivery[\"택배 배송조회\"] Proxy --\u003e Subway[\"서울 지하철 도착정보\"] Proxy --\u003e Dust[\"미세먼지 조회\"] Proxy --\u003e Coupang[\"쿠팡 상품 검색\"] Proxy --\u003e Law[\"한국 법령 검색\"] Proxy --\u003e ProxySrv[\"k-skill-proxy \u0026lt;br/\u0026gt; (self-host)\"]포함된 스킬 전체 목록 k-skill은 현재 총 18가지 기능을 제공한다.\n교통 스킬 설명 인증 SRT 예매 열차 조회, 예약, 확인, 취소 필요 KTX 예매 Dynapath anti-bot 대응 helper 포함 필요 서울 지하철 도착정보 실시간 도착 예정 열차 확인 (k-skill-proxy 경유) 프록시 URL 생활 정보 스킬 설명 인증 미세먼지 조회 현재 위치 또는 지역 기준 PM10/PM2.5 확인 불필요 우편번호 검색 주소 키워드로 공식 우체국 우편번호 조회 불필요 택배 배송조회 CJ대한통운·우체국 공식 표면 조회 불필요 근처 블루리본 맛집 블루리본 서베이 기준 맛집 검색 불필요 근처 술집 조회 카카오맵 기반 영업 상태·메뉴·전화번호 포함 불필요 다이소 상품 조회 특정 매장 상품 재고 확인 불필요 중고차 가격 조회 SK렌터카 타고BUY 기준 인수가/월 렌트료 불필요 스포츠 / 엔터테인먼트 스킬 설명 인증 KBO 경기 결과 날짜별 경기 일정·결과·팀별 필터링 불필요 K리그 경기 결과 K리그1/2 결과·순위 확인 불필요 로또 당첨 확인 최신 회차 및 번호 대조 불필요 업무 / 문서 스킬 설명 인증 HWP 문서 처리 .hwp → JSON/Markdown/HTML 변환, 이미지 추출 불필요 한국 법령 검색 법령·판례·유권해석 조회 로컬만 필요 카카오톡 Mac CLI macOS에서 메시지 읽기·검색·전송 불필요 쇼핑 / 금융 스킬 설명 인증 쿠팡 상품 검색 coupang-mcp 경유로 로켓배송·특가 조회 불필요 토스증권 조회 tossctl 기반 계좌·포트폴리오·시세 조회 필요 카카오톡 Mac CLI 상세 — kakaocli 카카오톡 스킬은 k-skill 중에서도 흥미로운 축에 속한다. macOS 전용 CLI 도구 kakaocli를 사용해 Claude Code가 카카오톡 대화를 직접 읽고 메시지를 보낼 수 있다.\n설치 brew install silver-flight-group/tap/kakaocli 터미널 앱에 Full Disk Access와 Accessibility 권한이 반드시 필요하다. 없으면 읽기 명령도 실패한다.\nKakaoTalk for Mac이 없다면 mas로 설치 가능하다.\nbrew install mas mas account mas install 869223134 주요 명령어 # 권한 및 DB 접근 확인 kakaocli status kakaocli auth # 대화 목록 읽기 kakaocli chats --limit 10 --json # 특정 채팅방 최근 메시지 kakaocli messages --chat \u0026#34;지수\u0026#34; --since 1d --json # 키워드 검색 kakaocli search \u0026#34;회의\u0026#34; --json # 나와의 채팅으로 테스트 전송 kakaocli send --me _ \u0026#34;테스트 메시지\u0026#34; # dry-run 으로 실제 전송 없이 확인 kakaocli send --dry-run \u0026#34;팀 공지방\u0026#34; \u0026#34;오늘 3시에 만나요\u0026#34; 보안 설계가 눈에 띈다. 다른 사람에게 보내는 메시지는 --dry-run으로 먼저 확인하고, 사용자 승인 후에만 전송한다. AI 에이전트가 무단으로 메시지를 발송하지 않도록 명시적 안전장치가 내장되어 있다.\n설치 방법 기본 흐름은 세 단계다.\ndocs/install.md를 따라 전체 스킬 설치 k-skill-setup 스킬로 credential 확보 및 환경변수 확인 각 기능 문서에서 입력값·예시·제한사항 확인 인증이 필요한 스킬(SRT, KTX, 토스증권)은 별도 credential resolution order를 따르며, docs/security-and-secrets.md에 저장 원칙과 금지 패턴이 명시되어 있다. 환경변수 이름도 표준화되어 있어 충돌 위험이 낮다.\nNode.js와 Python 패키지가 혼재하므로 전역 설치를 기본으로 한다. k-skill-proxy는 서울 지하철, 미세먼지 같이 공공 API 직접 호출이 필요한 스킬을 위한 self-host 가능한 프록시 서버다.\n의의 k-skill의 가장 큰 의의는 한국 인터넷 생태계의 단편화를 AI 에이전트로 극복하려는 시도라는 점이다.\n한국에는 글로벌 서비스 대신 자체 플랫폼(카카오톡, KBO, Korail, 정부24 등)이 깊게 뿌리내려 있다. 해외 AI 도구들은 이런 한국 특화 서비스를 지원하지 않는다. k-skill은 바로 이 공백을 메운다.\nJavaScript와 Python으로 구성된 멀티 런타임 구조, npm Changesets 기반 버전 관리, GitHub Actions CI/CD까지 갖춘 프로덕션급 오픈소스 프로젝트로서, 한국 개발자 커뮤니티의 실용적인 오픈소스 문화를 잘 보여준다.\nClaude Code를 쓰는 한국 개발자라면 한 번쯤 설치해 둘 만하다.\nGitHub: NomaDamas/k-skill Stars: 1,371 | Forks: 113 주요 언어: JavaScript, Python ","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-k-skill-korean-claude-code/cover.jpg","permalink":"/ko/posts/2026-04-03-k-skill-korean-claude-code/","title":"k-skill: 한국인을 위한 Claude Code 스킬 모음집"},{"content":"개요 이전 글: Log-Blog 개발기 #5\n#5에서 Firecrawl deep docs 통합과 이중 언어 블로그 배포 파이프라인을 구현했다면, 이번 #6은 그 여파를 정리하는 회차다. 블로그 구조가 content/ko/posts/와 content/en/posts/로 바뀐 뒤, 새 사용자도 처음부터 이 구조를 설정할 수 있도록 setup 스킬을 확장했다. 동시에 실제 운영 중에 마주친 AI 채팅 CDP 연결 경쟁 조건을 수정하고, Perplexity 노이즈 URL 필터를 추가했다. 플러그인은 글로벌 설치 방식에서 marketplace 기반 설치로 마이그레이션했고, 버전은 0.2.0을 거쳐 0.2.1로 올렸다.\ngraph TD A[\"log-blog #6 변경사항\"] --\u003e B[\"이중 언어 셋업 스킬\"] A --\u003e C[\"CDP 신뢰성 개선\"] A --\u003e D[\"플러그인 마켓플레이스 마이그레이션\"] A --\u003e E[\"README 문서화\"] B --\u003e B1[\"Phase 3A: 다국어 Hugo \u0026lt;br/\u0026gt; languages: 블록 생성\"] B --\u003e B2[\"Phase 3B: 기존 블로그 \u0026lt;br/\u0026gt; 누락 languages: 감지\"] B --\u003e B3[\"publisher --language 라우팅\"] B --\u003e B4[\"post_advisor: 중복 제거\"] C --\u003e C1[\"CDP 네비게이션 재시도 \u0026lt;br/\u0026gt; (race condition 수정)\"] C --\u003e C2[\"Perplexity /search/new \u0026lt;br/\u0026gt; 노이즈 필터\"] C --\u003e C3[\"에러 메시지 개선\"] D --\u003e D1[\"0.2.0: 이중 언어 기능\"] D --\u003e D2[\"0.2.1: CDP 수정\"] 이중 언어 Hugo 셋업 스킬 확장 배경 #5에서 블로그 레포를 content/ko/posts/와 content/en/posts/로 나누고 12개 포스트를 이중 언어로 배포했다. 그런데 막상 /logblog:setup으로 새 블로그를 만들면 이 구조를 전혀 생성하지 못했다. setup 스킬은 단일 언어 content/posts/ 구조만 알고 있었기 때문이다. 새 사용자가 플러그인을 설치해도 이중 언어 워크플로를 바로 시작할 수 없는 상황이었다.\n구현 — Phase 3A: 신규 블로그 이중 언어 설정 setup 스킬 질문 흐름을 개편했다. 이제 Hugo 사이트 생성 단계에서 세 가지를 묻는다:\n블로그 이름 기본 언어 (en/ko, 기본값: en) 다국어 지원 여부 — Yes면 언어 목록을 입력 (예: en,ko) 다국어를 선택하면 hugo.yaml에 Hugo 공식 languages: 블록이 추가된다:\nlanguages: en: languageName: English weight: 1 contentDir: content/en menu: main: [] social: [] ko: languageName: 한국어 weight: 2 contentDir: content/ko menu: main: [] social: [] 동시에 각 언어별 content 디렉토리와 초기 포스트를 생성한다. 영어는 content/en/posts/hello-world.md, 한국어는 content/ko/posts/hello-world.md로, 파일명이 같으면 Hugo가 자동으로 번역본으로 인식한다.\n구현 — Phase 3B: 기존 블로그 마이그레이션 감지 단순 생성보다 까다로운 케이스는 이미 다국어 디렉토리 구조는 있는데 Hugo config에 languages: 블록이 없는 경우다. 이 경우 Hugo가 언어별 디렉토리를 무시하고 언어 전환기도 동작하지 않는다.\nsetup 스킬 Step 2.5가 이를 감지한다:\nls -d \u0026#34;{path}/content/ko/posts\u0026#34; \u0026#34;{path}/content/en/posts\u0026#34; 2\u0026gt;/dev/null grep -c \u0026#34;^languages:\u0026#34; \u0026#34;{path}/hugo.yaml\u0026#34; 2\u0026gt;/dev/null 디렉토리는 있는데 languages: 블록이 없으면 경고 후 추가 여부를 묻는다. 사용자가 동의하면 기존 설정을 보존하면서 languages: 섹션만 삽입한다.\npublisher와 post_advisor 연동 setup 스킬 변경과 함께 publisher.py에도 --language 파라미터를 추가했다. 이 파라미터가 전달되면 config.yaml의 language_content_dirs 매핑에서 해당 언어의 content 경로를 찾아 라우팅한다:\ncontent_dir = config.blog.content_path_for(language) post_advisor.py도 수정했다. 기존에는 content_dir 하나만 스캔했는데, 이제는 language_content_dirs의 모든 경로를 스캔하되 동일 파일명의 중복을 제거한다. 이중 언어 블로그에서 scan 명령이 한쪽 언어 포스트만 보는 문제가 해결됐다.\nAI 채팅 CDP 신뢰성 개선 문제: CDP 네비게이션 경쟁 조건 uv run log-blog chrome-cdp로 Chrome을 CDP 모드로 실행하면, 이미 탭이 열려 있는 상태에서 Playwright가 새 페이지를 만들고 URL로 이동할 때 \u0026ldquo;navigation interrupted\u0026rdquo; 오류가 간헐적으로 발생했다. Chrome 탭 간 이벤트 충돌이 원인이다.\n수정 전 코드는 단순히 한 번 시도하고 실패하면 None을 반환했다:\nawait page.goto(url, wait_until=\u0026#34;domcontentloaded\u0026#34;, timeout=timeout_ms) 해결: 재시도 로직 _NAV_RETRIES = 2 상수를 추가하고, \u0026quot;interrupted\u0026quot; 문자열이 에러 메시지에 포함된 경우에만 재시도한다. 재시도 사이에는 500ms 대기로 탭 이벤트가 안정되길 기다린다:\n_NAV_RETRIES = 2 # retry count for CDP navigation race conditions for attempt in range(_NAV_RETRIES + 1): try: await page.goto(url, wait_until=\u0026#34;domcontentloaded\u0026#34;, timeout=timeout_ms) last_err = None break except Exception as nav_err: last_err = nav_err if attempt \u0026lt; _NAV_RETRIES and \u0026#34;interrupted\u0026#34; in str(nav_err).lower(): logger.debug(\u0026#34;CDP navigation interrupted (attempt %d), retrying\u0026#34;, attempt + 1) await page.wait_for_timeout(500) else: raise \u0026ldquo;interrupted\u0026quot;가 아닌 다른 오류(타임아웃, 네트워크 에러 등)는 즉시 raise해서 불필요한 재시도를 방지한다.\nPerplexity 노이즈 필터 Perplexity 방문 기록에 실제 대화 URL(perplexity.ai/search/...) 외에 새 검색 페이지(perplexity.ai/search/new)가 섞여 들어왔다. 이 URL은 콘텐츠가 없는 랜딩 페이지인데, 기존 분류기가 이를 ai_chat_perplexity로 잘못 분류해 쓸모없는 CDP fetch를 시도했다.\n_AI_NOISE_PATTERNS 리스트에 한 줄을 추가해 필터링했다:\nre.compile(r\u0026#34;perplexity\\.ai/search/new(?:[?#]|$)\u0026#34;), # \u0026#34;new search\u0026#34; landing page 에러 메시지 개선 CDP fetch 실패 시 로그가 단순히 \u0026quot;AI chat fetch failed for URL: error\u0026quot; 였다. 원인을 알기 어렵다. 이제는 실행 가능한 조치를 포함한 메시지를 출력한다:\nlogger.warning( \u0026#34;AI chat fetch failed for %s (%s): %s. \u0026#34; \u0026#34;Ensure Chrome is running with: uv run log-blog chrome-cdp\u0026#34;, url, service, e, ) 플러그인 마켓플레이스 마이그레이션 배경: 글로벌 설치의 한계 이전에는 플러그인을 ~/.claude/plugins/logblog/에 직접 설치하는 방식이었다. 이 방식의 문제는 업데이트 감지가 플러그인 내 plugin.json의 version 문자열 비교에 의존한다는 점이다. 버전을 올리지 않으면 새 기능이 배포돼도 /plugin이 \u0026ldquo;최신 버전\u0026rdquo; 으로 판단해 업데이트를 건너뛴다.\n#5에서 Firecrawl, 이중 언어 지원 등 15개 커밋을 쌓았지만 version은 \u0026quot;0.1.0\u0026quot; 그대로였다. 이를 발견한 후 marketplace 기반 설치로 전환했다:\n설치 위치: ~/.claude/plugins/marketplaces/logblog/ 업데이트: marketplace의 버전 체계를 통해 관리 버전 체계: 0.2.0과 0.2.1 0.2.0 — Firecrawl deep docs 통합, 이중 언어 블로그 지원, setup 스킬 다국어 확장, publisher --language 라우팅 등 새 기능 묶음이라 minor 버전 업으로 결정했다.\n0.2.1 — CDP 신뢰성 수정과 Perplexity 노이즈 필터. 새 기능이 아니라 버그 수정이므로 patch 버전 업.\nmarketplace.json의 플러그인 항목도 최신 버전 정보를 반영하도록 업데이트했다.\nREADME 문서화 이번 세션에서 README가 크게 업데이트됐다. 추가된 주요 섹션:\n이중 언어 워크플로: 한국어 포스트 작성 → 영어 번역 → 각 content/{lang}/posts/에 배포하는 전체 흐름 Firecrawl 통합: --deep 플래그로 문서 사이트 전체 크롤링하는 방법 Dev Log 모드: 세션 데이터에서 dev log 포스트를 생성하는 스킬 사용법 AI 채팅 fetching: chrome-cdp 명령으로 Chrome을 CDP 모드로 실행하는 법, 각 서비스별 auth_profile 설정 커밋 로그 메시지 변경 docs: update README with bilingual workflow, Firecrawl, dev logs, and AI chat features +31 -7 chore: bump plugin version to 0.2.0 +1 -1 feat: add multi-language Hugo setup to setup skill and publisher +226 -26 chore: bump plugin version to 0.2.1 +1 -1 fix: improve AI chat CDP reliability and Perplexity noise filter +30 -3 인사이트 이번 회차는 \u0026ldquo;기능을 만들었더니 인프라가 따라오지 못하는\u0026rdquo; 전형적인 패턴이었다. #5에서 이중 언어 블로그를 구현하고 수동으로 레포를 재구성했는데, setup 스킬이 이를 지원하지 못해 새 사용자가 같은 결과를 얻을 수 없었다. 기능과 셋업 경험을 동기화하는 작업이 항상 뒤를 따라야 한다는 점을 다시 확인했다.\nCDP 연결 경쟁 조건은 재현이 어려운 종류의 버그다. Chrome의 탭 이벤트 타이밍에 의존하기 때문에 매번 나타나지 않는다. \u0026ldquo;interrupted\u0026rdquo; 문자열로만 재시도를 트리거하는 좁은 조건이 오히려 올바른 선택이었다 — 타임아웃 같은 다른 오류까지 재시도하면 느린 네트워크에서 지연이 두 배로 늘어난다.\n플러그인 버전 관리는 단순해 보이지만 배포 신뢰성의 핵심이다. 버전 문자열을 올리지 않으면 사용자가 업데이트를 받지 못한다. marketplace 기반 관리로 전환하면서 이 프로세스가 더 명시적이 됐다.\nlog-blog 자체가 log-blog로 기록되는 메타적 상황을 즐기고 있다. 포스트를 쓰다 발견한 불편함이 다음 커밋의 동기가 되고, 그 커밋이 다음 포스트의 내용이 된다.\n","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-log-blog-dev6/cover.jpg","permalink":"/ko/posts/2026-04-03-log-blog-dev6/","title":"Log-Blog 개발기 #6 — 이중 언어 셋업, CDP 신뢰성, 마켓플레이스 마이그레이션"},{"content":"개요 Android에서 음악을 들으며 다른 앱을 쓸 때 미디어 컨트롤에 접근하려면 알림 바를 내리거나 앱을 전환해야 한다. MediaFloat는 이 문제를 단 하나의 방법으로 해결한다: 이전/재생·일시정지/다음 버튼을 항상 화면 위에 떠 있는 작은 오버레이 바로 표시하는 것이다.\nKotlin + Jetpack Compose로 작성된 오픈소스 앱으로, Android 10 이상을 지원하며 Apache License 2.0으로 배포된다. GitHub 저장소: Leuconoe/MediaFloat\n핵심 아키텍처 MediaFloat의 구조는 세 가지 Android 시스템 기능의 조합으로 이루어진다.\nflowchart TD A[\"사용자 미디어 앱\u0026lt;br/\u0026gt;(YouTube, Spotify 등)\"] --\u003e|\"미디어 세션 발행\"| B[\"NotificationListenerService\u0026lt;br/\u0026gt;(미디어 세션 감지)\"] B --\u003e|\"재생 상태 / 트랜스포트 액션\"| C[\"ForegroundService\u0026lt;br/\u0026gt;(오버레이 런타임)\"] C --\u003e|\"WindowManager 오버레이\"| D[\"Compose UI\u0026lt;br/\u0026gt;(플로팅 컨트롤 바)\"] D --\u003e|\"이전 / 재생 / 다음\"| B E[\"사용자 설정\u0026lt;br/\u0026gt;(Main / Settings / Advanced)\"] --\u003e|\"위치, 크기, 테마\"| C세 가지 핵심 권한과 역할 권한 / 접근 역할 SYSTEM_ALERT_WINDOW 다른 앱 위에 오버레이 윈도우를 띄움 FOREGROUND_SERVICE + FOREGROUND_SERVICE_SPECIAL_USE 오버레이 런타임을 지속적으로 유지 POST_NOTIFICATIONS Foreground service 알림 표시 (Android 13+) Notification listener access 활성 미디어 세션 상태와 트랜스포트 액션 읽기 Android Overlay 구현 방식 SYSTEM_ALERT_WINDOW 권한은 Android에서 \u0026ldquo;다른 앱 위에 표시\u0026rdquo; 권한으로 불린다. 이 권한을 얻으면 WindowManager.addView()를 통해 시스템 레이어에 뷰를 삽입할 수 있다.\nMediaFloat는 여기에 Jetpack Compose를 결합한다. 전통적인 XML 레이아웃 대신 Compose의 AndroidView 또는 ComposeView를 WindowManager에 붙이는 방식으로 플로팅 UI를 렌더링한다.\nForeground Service의 역할 Android는 백그라운드에서 UI를 표시하는 컴포넌트를 엄격하게 제한한다. 오버레이가 앱이 백그라운드에 있을 때도 유지되려면 반드시 Foreground Service 안에서 실행되어야 한다.\nForeground Service는 사용자에게 보이는 알림을 반드시 표시해야 한다 Android 13+에서는 POST_NOTIFICATIONS 권한이 추가로 필요하다 FOREGROUND_SERVICE_SPECIAL_USE 타입은 overlay처럼 특수 용도의 서비스에 요구된다 NotificationListenerService로 미디어 세션 감지 미디어 앱들은 재생 상태를 MediaSession API를 통해 시스템에 등록한다. MediaFloat는 NotificationListenerService를 통해 이 세션을 감지하고, MediaController로 트랜스포트 액션(이전/재생·일시정지/다음)을 전송한다.\n이 경로 덕분에 Spotify, YouTube, 팟캐스트 앱 등 어떤 미디어 앱이든 동일한 인터페이스로 제어할 수 있다.\n앱 구조: 단일 모듈, 다섯 가지 Surface MediaFloat는 의도적으로 단일 모듈(single-module) 구조를 선택했다. 복잡성을 낮추고 런타임 동작과 복구 경로를 명확하게 유지하기 위함이다.\n다섯 가지 앱 화면 flowchart LR Main[\"Main\u0026lt;br/\u0026gt;오버레이 시작/중지\u0026lt;br/\u0026gt;준비 상태 확인\"] Settings[\"Settings\u0026lt;br/\u0026gt;버튼 가시성, 크기\u0026lt;br/\u0026gt;불투명도, 동작\"] Advanced[\"Advanced\u0026lt;br/\u0026gt;언어, 테마\u0026lt;br/\u0026gt;사이드바, 영속 모드\"] Support[\"Support\u0026lt;br/\u0026gt;설정 안내\u0026lt;br/\u0026gt;버전, 라이선스\"] Debug[\"Debug\u0026lt;br/\u0026gt;런타임 진단\u0026lt;br/\u0026gt;트랜스포트 명령\"] Main --- Settings Settings --- Advanced Advanced --- Support Support --- DebugDebug 화면이 특히 흥미롭다. 런타임 준비 상태, 미디어 세션 상태 점검, 트랜스포트 명령 직접 전송, 최근 이벤트 로그 확인 기능을 제공한다. 개발자 도구를 앱 안에 통합한 사례다.\n자동화 연동: Exported Action MediaFloat는 외부 자동화 도구와 연동할 수 있는 exported intent action을 제공한다:\nsw2.io.mediafloat.action.SHOW_OVERLAY Android의 ShortcutManager를 통해 런처 단축키도 두 가지 노출한다:\nLaunch widget — 오버레이 시작 Stop widget — 오버레이 중지 Tasker, MacroDroid, Android Shortcuts 같은 루틴 도구에서 이 action을 직접 호출할 수 있다.\n다국어 지원 v0.2.1은 AppCompat app-language API를 사용해 Android 13 이상과 그 이하 버전 모두에서 언어 전환을 지원한다. 지원 언어: System default, English, Korean, Chinese, Japanese, Spanish, French.\n한국어가 기본 지원 언어 목록에 포함된 것이 인상적이다. 언어 선택은 Advanced 화면에서 가능하고, 현재 언어는 Support 화면에 반영된다.\n현재 버전의 의도적 제약 v0.2.1은 다음 기능을 의도적으로 포함하지 않는다:\n자유로운 크기 조절 (사이즈 프리셋만 지원) 여러 컨트롤 패밀리 (수평 단일 레이아웃만 지원) 버튼 조합 자유 선택 (이전/재생·일시정지/다음 레이아웃에 한정) README에서 \u0026ldquo;intentionally constrained\u0026quot;라고 명시한 것은, 기능 추가보다 안정성과 이해 가능성을 우선한 설계 철학을 보여준다.\n최근 커밋을 보면 v0.3.0 릴리스 준비와 thumbnail 지원, 사이드바 스페이싱 정규화 작업이 진행 중이다.\n기술 스택 요약 항목 내용 언어 Kotlin UI Jetpack Compose + Material 3 대상 플랫폼 Android 10+ 빌드 시스템 Gradle 라이선스 Apache License 2.0 주요 Android API SYSTEM_ALERT_WINDOW, ForegroundService, NotificationListenerService, MediaController 마치며 MediaFloat는 Android overlay 개발의 좋은 학습 사례다. SYSTEM_ALERT_WINDOW + Foreground Service + NotificationListenerService 세 가지 시스템 기능을 조합하는 패턴은, 플로팅 UI를 구현하는 Android 앱에서 공통적으로 사용된다.\nJetpack Compose를 WindowManager overlay에 적용하는 구체적인 구현, 자동화 도구와 연동하는 exported action 패턴, 그리고 Debug 화면을 앱 내에 통합하는 방식이 주목할 만하다.\n저장소에서 직접 빌드해 볼 수 있으며, 릴리스 서명 설정도 문서화되어 있다.\n","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-mediafloat-android/cover.jpg","permalink":"/ko/posts/2026-04-03-mediafloat-android/","title":"MediaFloat: Android 플로팅 미디어 컨트롤의 구조 분석"},{"content":"이전 글: PopCon 개발기 #1\n개요 오늘은 PopCon의 \u0026ldquo;겉모습\u0026quot;과 \u0026ldquo;안정성\u0026quot;을 모두 다듬은 세션이었다. 오전에는 Gemini가 생성한 이미지를 로고와 파비콘으로 변환하고, GitHub에 공개할 수 있는 수준의 README를 작성했다. 오후에는 Docker에서 API 키 오류가 터졌고, 파이프라인 전체를 점검하며 재시도 로직과 이모지별 에러 핸들링까지 구현했다.\n1. 로고 \u0026amp; 파비콘 — Gemini 이미지를 브랜드 에셋으로 첫 번째 작업은 Gemini가 생성한 2880×1440 이미지를 PopCon 브랜드 에셋으로 만드는 것이었다. 이미지를 중앙 기준 1:1 정사각형으로 크롭한 뒤, 여러 크기로 변환했다.\n파일 크기 용도 logo.png 512×512 헤더 로고 favicon.ico 16/32/48 멀티 사이즈 브라우저 탭 아이콘 favicon-16x16.png 16×16 소형 파비콘 favicon-32x32.png 32×32 표준 파비콘 apple-touch-icon.png 180×180 iOS 홈 화면 icon-192.png / icon-512.png 192×192 / 512×512 PWA 아이콘 Docker에서 파비콘이 안 보이는 문제 파비콘을 교체했는데 브라우저에 반영이 안 됐다. 원인이 두 가지였다.\nNext.js App Router 우선순위: app/favicon.ico가 public/favicon.ico보다 우선한다. 이미 기본 파비콘이 app/ 디렉토리에 있었고, 이 파일을 교체해야 했다. Docker 이미지 캐시: COPY . .로 빌드 시점에 파일을 굽기 때문에, 파일을 수정해도 컨테이너를 재빌드하지 않으면 반영되지 않는다. docker compose build frontend \u0026amp;\u0026amp; docker compose up -d frontend 재빌드 후 curl -I localhost:3000/favicon.ico로 HTTP 200을 확인하고 마무리했다.\n2. 전체 제품 README 작성 다음은 GitHub에 공개할 README를 제품 개요 수준으로 작성하는 작업이었다.\n처음에는 영어·한국어를 하나의 파일에 넣었는데, \u0026ldquo;두 언어가 구분이 안 된다\u0026quot;는 피드백이 나왔다. 결과적으로 파일을 분리했다.\nREADME.md — 영어, 상단에 English | [한국어](README.ko.md) 토글 README.ko.md — 한국어, 상단에 [English](README.md) | 한국어 토글 README 내용이 코드와 달랐던 부분들 첫 커밋 후 실제 코드를 확인하니 README와 다른 점이 여러 곳 있었다.\n항목 README 작성 내용 실제 코드 이미지 생성 모델 Google Imagen Gemini Flash Image VEO 모드 듀얼 프레임 I2V 시작 프레임 + 모션 프롬프트만 (API 미지원) 최소 영상 길이 \u0026ldquo;4초 이내\u0026rdquo; 4초 고정 (API 최소값), 후처리에서 트리밍 전처리 단계 없음 크롭 → 정사각 패딩 → 512×512 리사이즈 작업 저장소 없음 Redis (24시간 TTL) 누락 엔드포인트 없음 /api/job/{job_id}/emoji/{filename} 두 README 파일 모두 업데이트 후 푸시했다.\n3. Docker 디버깅 — API 키와 씨름한 오후 오후 세션은 Docker 로그부터 시작했다. 서비스가 전혀 동작하지 않았는데, 원인은 .env 파일의 API 키 값 뒤에 venv가 붙어 있었던 것이다.\nPOPCON_GOOGLE_API_KEY=AIzaSy...-mAcuv venv 아마 터미널에서 복사할 때 venv 활성화 명령어가 함께 딸려온 것으로 추정된다. .env에서 venv를 제거하고 재시작했지만, 이번엔 키 자체가 만료된 것으로 확인됐다. Google AI Studio에서 새 키를 발급받아 해결했다.\n이 과정에서 파이프라인을 실제로 돌려보면서 여러 품질 문제를 발견했다.\n발견한 문제들과 수정 flowchart TD A[\"파이프라인 실행\"] --\u003e B[\"출력 검토\"] B --\u003e C[\"문제 발견\"] C --\u003e D[\"구름 효과 \u0026lt;br/\u0026gt; 배경 노이즈\"] C --\u003e E[\"중복 캐릭터 \u0026lt;br/\u0026gt; 스프라이트 시트\"] C --\u003e F[\"체커보드 배경 \u0026lt;br/\u0026gt; NB2 가짜 투명\"] C --\u003e G[\"VEO 엣지 라인 \u0026lt;br/\u0026gt; 좌우 경계선\"] D --\u003e H[\"rembg 완전 제거 \u0026lt;br/\u0026gt; 밝기 기반 크롭으로 대체\"] E --\u003e I[\"프롬프트에 \u0026lt;br/\u0026gt; 단일 캐릭터 강제\"] F --\u003e J[\"#FFFFFF 명시 \u0026lt;br/\u0026gt; NOT checkerboard 프롬프트\"] G --\u003e K[\"ffmpeg 2% 엣지 크롭\"]가장 큰 결정은 rembg 라이브러리를 완전히 제거한 것이다. 배경 제거를 시도할수록 문제가 생겼다 — isnet-general-use 모델이 구름 같은 아티팩트를 남겼고, u2net으로 바꿔도 마찬가지였다. 결국 VEO가 흰 배경으로 영상을 생성하도록 프롬프트를 강화하고, 밝기 기반 크롭으로 콘텐츠 영역만 추출하는 방향으로 전환했다.\n# processor.py — 밝기 기반 콘텐츠 감지 brightness = arr.astype(float).mean(axis=2) content_mask = (brightness \u0026gt; 10) \u0026amp; (brightness \u0026lt; 245) pyproject.toml에서 rembg[cpu]\u0026gt;=2.0.0을 제거하고 numpy\u0026gt;=1.26.0으로 교체하면서 Docker 이미지도 가벼워졌다.\nLINE 규격 파일 명명 수정 LINE Creators Market 가이드라인을 확인하니 파일명이 001.png~040.png 형식이어야 했다. 기존 코드는 액션 이름으로 저장하고 있었다.\n# packager.py for i, emoji_path in enumerate(emoji_paths): line_name = f\u0026#34;{i + 1:03d}.png\u0026#34; zf.write(emoji_path, line_name) 4. 재시도 로직 \u0026amp; API 스로틀링 마지막 커밋은 안정성 강화였다. 풀 세트(24개)를 생성하다 보면 VEO나 Gemini API가 간헐적으로 503이나 429를 반환했다. 하나가 실패하면 전체 작업이 멈추는 구조를 개선했다.\n이모지별 독립적인 에러 처리 기존 구조는 하나의 이모지가 예외를 던지면 전체 run_emoji_generation 태스크가 실패했다. 이를 각 이모지별로 try/except를 적용해서 실패한 것만 \u0026quot;error\u0026quot; 상태로 기록하고 나머지는 계속 진행하도록 변경했다.\n# worker.py — 이모지별 에러 핸들링 failed_indices = set() for i, action in enumerate(actions): try: # ... 포즈 생성, 애니메이션, 후처리 except Exception as e: logger.error(f\u0026#34;Emoji {i} ({action.name}) failed: {e}\u0026#34;) failed_indices.add(i) status.results[i].status = \u0026#34;error\u0026#34; save_job(status) 작업 완료 상태도 세분화했다. \u0026quot;done\u0026quot; 외에 \u0026quot;done_with_errors\u0026quot; 상태를 추가해서 일부 실패해도 ZIP을 다운로드할 수 있도록 했다.\nAPI 재시도 로직 Gemini Image와 VEO 모두 지수 백오프 재시도를 추가했다.\n# pose_generator.py — 재시도 로직 async def _generate_image(self, prompt, reference_image_path=None, max_retries=3): for attempt in range(max_retries): try: response = await asyncio.to_thread( self.client.models.generate_content, ... ) return ... except (ServerError, ClientError) as e: if attempt == max_retries - 1: raise wait = 2 ** attempt # 1s, 2s, 4s logger.warning(f\u0026#34;Attempt {attempt+1} failed, retrying in {wait}s: {e}\u0026#34;) await asyncio.sleep(wait) 타입 시스템 동기화 모델 상태 타입을 백엔드와 프론트엔드 모두 업데이트했다.\n계층 변경 backend/models.py EmojiStatus에 \u0026quot;error\u0026quot; 추가, JobStatusType에 \u0026quot;done_with_errors\u0026quot; 추가 frontend/lib/api.ts 동일한 상태 타입 동기화 frontend/components/ProgressTracker.tsx \u0026quot;error\u0026quot; 상태 빨간 카드 UI 추가 frontend/components/EmojiPreview.tsx \u0026quot;done_with_errors\u0026quot; 일 때도 ZIP 다운로드 버튼 표시 정리 오늘 작업한 커밋 4개의 흐름을 요약하면 이렇다.\n순서 내용 1 로고/파비콘 생성, 브랜딩 에셋, 전체 제품 README 2 README 영어/한국어 분리, 언어 토글 3 README를 실제 파이프라인 동작에 맞게 업데이트 4 재시도 로직, 이모지별 에러 처리, API 스로틀링 Docker 디버깅을 하다 보니 파이프라인 품질 문제들도 많이 잡았다. 특히 rembg 제거 결정은 \u0026ldquo;뭔가를 빼는 게 더 나은 경우\u0026quot;의 전형적인 사례였다 — 복잡성도 줄고, Docker 이미지도 가벼워지고, 결과물도 오히려 더 깔끔해졌다.\n다음 세션에서는 실제 LINE Creators Market 제출을 목표로 최종 품질 검증을 할 예정이다.\n","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-popcon-dev2/cover.jpg","permalink":"/ko/posts/2026-04-03-popcon-dev2/","title":"PopCon 개발기 #2 — 브랜딩, README, Docker 디버깅, 그리고 재시도 로직"},{"content":"개요 Pylette는 이미지에서 대표 색상 팔레트를 추출해주는 Python 라이브러리다. K-Means 클러스터링과 Median Cut 두 가지 알고리즘을 지원하며, CLI와 Python API 양쪽으로 사용할 수 있다. 164 stars, 16 forks의 소규모 오픈소스 프로젝트지만 설계가 깔끔하고 실용적이다. 이번 글에서는 color.py 소스 코드를 중심으로 라이브러리 아키텍처와 Color 클래스 구현을 분석한다.\n색상 추출 파이프라인 Pylette의 내부 처리 흐름은 크게 세 단계로 나뉜다: 이미지 로딩, 알고리즘 적용, Color 객체 생성.\nflowchart TD A[\"이미지 입력 \u0026lt;br/\u0026gt; (파일, URL, 디렉토리)\"] --\u003e B[\"Pillow로 로딩 \u0026lt;br/\u0026gt; Alpha 마스킹 처리\"] B --\u003e C{\"추출 알고리즘\"} C --\u003e|\"KMeans\"| D[\"K-Means 클러스터링 \u0026lt;br/\u0026gt; scikit-learn\"] C --\u003e|\"MedianCut\"| E[\"Median Cut \u0026lt;br/\u0026gt; 색공간 분할\"] D --\u003e F[\"클러스터 중심 → Color 객체\"] E --\u003e F F --\u003e G[\"Palette 구성 \u0026lt;br/\u0026gt; 빈도 정규화\"] G --\u003e H{\"출력 형태\"} H --\u003e|\"CLI\"| I[\"Rich 테이블 출력\"] H --\u003e|\"Python API\"| J[\"Palette 객체 반환\"] H --\u003e|\"--export-json\"| K[\"JSON 파일 저장\"]Color 클래스 구현 분석 Pylette/src/color.py는 전체 라이브러리의 핵심 데이터 구조다. 106줄의 간결한 코드로 색상의 표현과 변환을 모두 담당한다.\n초기화와 RGBA 처리 class Color(object): def __init__(self, rgba: tuple[int, ...], frequency: float): assert len(rgba) == 4, \u0026#34;RGBA values must be a tuple of length 4\u0026#34; *rgb, alpha = rgba self.rgb = cast(tuple[int, int, int], rgb) self.rgba = rgba self.a = alpha self.freq: float = frequency self.weight = alpha / 255.0 주목할 점이 두 가지 있다. 첫째, *rgb, alpha = rgba 패턴으로 RGBA를 한 번에 언패킹한다. Python의 starred assignment를 활용한 깔끔한 코드다. 둘째, self.weight = alpha / 255.0로 알파값을 0~1 범위로 정규화한다. 투명한 픽셀을 alpha_mask_threshold로 필터링하는 로직에 이 값이 쓰인다.\n색공간 변환 프로퍼티 @property def hsv(self) -\u0026gt; tuple[float, float, float]: return colorsys.rgb_to_hsv( r=self.rgb[0] / 255, g=self.rgb[1] / 255, b=self.rgb[2] / 255 ) @property def hls(self) -\u0026gt; tuple[float, float, float]: return colorsys.rgb_to_hls( r=self.rgb[0] / 255, g=self.rgb[1] / 255, b=self.rgb[2] / 255 ) HSV와 HLS 변환은 Python 표준 라이브러리 colorsys를 활용한다. @property로 선언되어 있어 color.hsv, color.hls처럼 속성처럼 접근할 수 있다. 내부적으로는 RGB 값을 0~1 범위로 정규화한 뒤 변환한다.\n루미넌스(휘도) 계산 luminance_weights = np.array([0.2126, 0.7152, 0.0722]) @property def luminance(self) -\u0026gt; float: return np.dot(luminance_weights, self.rgb) 휘도 계산에 [0.2126, 0.7152, 0.0722] 가중치를 사용한다. 이는 ITU-R BT.709 표준에 정의된 sRGB 휘도 계수다. 인간의 눈은 녹색(0.7152)에 가장 민감하고, 파란색(0.0722)에 가장 둔감하다는 사실을 반영한다. sort-by luminance 옵션이 이 값으로 색상을 정렬한다.\n비교 연산자와 정렬 def __lt__(self, other: \u0026#34;Color\u0026#34;) -\u0026gt; bool: return self.freq \u0026lt; other.freq __lt__만 구현하고 나머지 비교 연산자는 생략했다. Python의 sorted()와 list.sort()는 __lt__만 있어도 동작하기 때문이다. functools.total_ordering을 쓰지 않은 것도 같은 이유다. 빈도 기반 정렬이 기본이고, CLI에서 --sort-by luminance를 선택하면 luminance 프로퍼티로 재정렬한다.\n색공간 통합 접근자 def get_colors( self, colorspace: ColorSpace = ColorSpace.RGB ) -\u0026gt; tuple[int, ...] | tuple[float, ...]: colors = { ColorSpace.RGB: self.rgb, ColorSpace.HSV: self.hsv, ColorSpace.HLS: self.hls } return colors[colorspace] 딕셔너리 디스패치 패턴이다. if/elif 체인 대신 딕셔너리로 색공간 선택을 처리한다. ColorSpace는 별도의 types.py에 정의된 enum이며, 타입 힌트가 tuple[int, ...] | tuple[float, ...]인 이유는 RGB가 정수, HSV/HLS가 부동소수점을 반환하기 때문이다.\n추출 알고리즘 비교 Pylette가 지원하는 두 알고리즘의 특성을 비교하면 다음과 같다.\n항목 K-Means Median Cut 방식 클러스터 중심 탐색 색공간 재귀 분할 결과 통계적 대표색 균형 잡힌 색상 분포 속도 반복 수렴 필요 결정론적, 빠름 기본값 예 아니오 적합한 용도 복잡한 그라데이션 단순한 블록 이미지 K-Means는 반복 수렴이 필요하지만 이미지의 실제 색상 분포를 더 잘 반영한다. Median Cut은 결정론적이라 같은 이미지에 항상 같은 결과를 낸다.\n사용 예시 CLI 사용 # 기본 추출 (5색, K-Means, RGB) pylette image.jpg # 8색, HSV 색공간, JSON 내보내기 pylette photo.png --n 8 --colorspace hsv --export-json --output colors.json # Median Cut 알고리즘, 투명 이미지 처리 pylette logo.png --mode MedianCut --alpha-mask-threshold 128 # 병렬 처리로 여러 이미지 배치 처리 pylette images/*.png --n 6 --num-threads 4 출력 예시:\n✓ Extracted 5 colors from sunset.jpg ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓ ┃ Hex ┃ RGB ┃ Frequency┃ ┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩ │ #FF6B35 │ (255, 107, 53) │ 28.5% │ │ #F7931E │ (247, 147, 30) │ 23.2% │ │ #FFD23F │ (255, 210, 63) │ 18.7% │ │ #06FFA5 │ (6, 255, 165) │ 15.4% │ │ #4ECDC4 │ (78, 205, 196) │ 14.2% │ └──────────┴─────────────────┴──────────┘ Python API 사용 from Pylette import extract_colors palette = extract_colors(image=\u0026#39;image.jpg\u0026#39;, palette_size=8) for color in palette.colors: print(f\u0026#34;RGB: {color.rgb}\u0026#34;) print(f\u0026#34;Hex: {color.hex}\u0026#34;) print(f\u0026#34;HSV: {color.hsv}\u0026#34;) print(f\u0026#34;Luminance: {color.luminance:.2f}\u0026#34;) print(f\u0026#34;Frequency: {color.freq:.2%}\u0026#34;) # JSON으로 내보내기 palette.to_json(filename=\u0026#39;palette.json\u0026#39;, colorspace=\u0026#39;hsv\u0026#39;) 배치 처리 from Pylette import batch_extract_colors results = batch_extract_colors( images=[\u0026#39;image1.jpg\u0026#39;, \u0026#39;image2.png\u0026#39;, \u0026#39;image3.jpg\u0026#39;], palette_size=8, max_workers=4, mode=\u0026#39;KMeans\u0026#39; ) for result in results: if result.success and result.palette: print(f\u0026#34;✓ {result.source}: {len(result.palette.colors)} colors\u0026#34;) result.palette.export(f\u0026#34;{result.source}_palette\u0026#34;) Python 이미지 처리 생태계에서의 위치 Pylette는 Pillow(이미지 로딩), NumPy(행렬 연산), scikit-learn(K-Means)을 조합해 색상 추출이라는 좁은 문제에 집중한다. 비슷한 도구들과 비교하면:\ncolorgram.py: 가장 유사한 경쟁 라이브러리. Pylette보다 API가 단순하지만 색공간 변환 지원이 없다. sklearn.cluster.KMeans 직접 사용: 유연하지만 이미지 처리 파이프라인을 직접 구성해야 한다. PIL.Image.quantize: Median Cut 기반이지만 팔레트 메타데이터(빈도, 색공간 변환)가 없다. Pylette의 강점은 CLI와 Python API의 이중 인터페이스, 투명 이미지 지원, 색공간 변환 내장, JSON 내보내기다. 약점은 GPU 가속이 없고 대용량 이미지에서 속도가 느릴 수 있다는 점이다.\n설계에서 배울 점 Color 클래스 구현에서 몇 가지 파이써닉한 패턴이 눈에 띈다:\n@property 지연 계산: HSV, HLS, hex, luminance 모두 프로퍼티로 선언해 필요할 때만 계산한다. 캐싱은 없지만 Color 객체가 immutable하게 사용되므로 문제가 없다.\n딕셔너리 디스패치: get_colors()의 딕셔너리 패턴은 새로운 색공간 추가 시 elif 체인을 수정하지 않아도 된다.\n표준 라이브러리 우선: 색공간 변환에 colorsys를 사용해 외부 의존성을 줄인다.\n타입 힌트 일관성: 반환 타입이 tuple[int, ...] | tuple[float, ...]로 명확히 표현되어 있다.\n마무리 Pylette는 \u0026ldquo;이미지에서 대표 색상을 뽑는다\u0026quot;는 단순한 문제를 잘 정의된 인터페이스로 해결한다. Color 클래스는 106줄이지만 RGB, HSV, HLS, hex, luminance, 빈도까지 모두 다루는 완결된 데이터 구조다. 디자인 시스템 구축, 이미지 분류, 시각화 도구 제작 같은 실제 작업에서 바로 쓸 수 있는 실용적인 라이브러리다.\nGitHub: qTipTip/Pylette 문서: qtiptip.github.io/Pylette PyPI: pip install Pylette ","date":"2026-04-03T00:00:00+09:00","image":"/images/posts/2026-04-03-pylette-color-extraction/cover.jpg","permalink":"/ko/posts/2026-04-03-pylette-color-extraction/","title":"Pylette: 이미지에서 색상 팔레트를 추출하는 Python 라이브러리 분석"},{"content":"개요 AI 이미지 생성 분야가 빠르게 진화하고 있다. 단순한 text-to-image를 넘어서 레이어 분해, 실시간 편집, 동영상 생성, 멀티모달 서빙까지 스택 전체가 재편되는 중이다. 이 글에서는 최근 주목할 만한 네 가지 프로젝트를 분석한다.\nQwen-Image-Layered — 이미지를 RGBA 레이어로 분해해 편집 가능성을 내재화 Nano Banana 2 — Gemini 3.1 Flash 기반, Pro급 품질을 Flash 속도로 제공 Veo 3.1 — 사운드 포함 동영상 생성, 참고 이미지 기반 스타일 가이드 vLLM-Omni — 텍스트/이미지/오디오/비디오를 하나의 서빙 프레임워크로 통합 이 기술들이 PopCon 프로젝트에서 어떻게 결합되는지는 PopCon 개발기 #1에서 다룬다.\nAI 이미지 파이프라인 아키텍처 현재 AI 이미지 생성 에코시스템을 하나의 파이프라인으로 정리하면 다음과 같다.\ngraph LR A[\"텍스트 프롬프트\"] --\u003e B[\"이미지 생성 모델\u0026lt;br/\u0026gt;Qwen-Image / Gemini\"] B --\u003e C[\"정적 이미지\"] C --\u003e D[\"레이어 분해\u0026lt;br/\u0026gt;Qwen-Image-Layered\"] D --\u003e E[\"RGBA 레이어별 편집\"] C --\u003e F[\"동영상 생성\u0026lt;br/\u0026gt;Veo 3.1\"] F --\u003e G[\"사운드 포함 동영상\"] B --\u003e H[\"서빙 인프라\u0026lt;br/\u0026gt;vLLM-Omni\"] H --\u003e I[\"API Endpoint\u0026lt;br/\u0026gt;OpenAI 호환\"] E --\u003e J[\"최종 에셋\u0026lt;br/\u0026gt;PopCon 이모지\"] G --\u003e J핵심은 생성 -\u0026gt; 분해/편집 -\u0026gt; 서빙이라는 3단계 구조가 명확해지고 있다는 점이다. 각 단계의 도구를 살펴보자.\nQwen-Image-Layered — 레이어 분해로 편집 가능성 내재화 항목 내용 GitHub QwenLM/Qwen-Image-Layered Stars 1,741 언어 Python 라이선스 Apache 2.0 논문 arXiv:2512.15603 핵심 아이디어 기존 이미지 편집은 마스크 기반 inpainting이 주류였다. Qwen-Image-Layered는 발상을 전환해서, 이미지를 처음부터 여러 RGBA 레이어로 분해한다. Photoshop의 레이어 개념을 AI가 자동으로 수행하는 셈이다.\n아키텍처 분석 기반 모델: Qwen2.5-VL 위에 fine-tuning한 diffusion 모델 파이프라인: QwenImageLayeredPipeline (HuggingFace diffusers 통합) 출력 형식: RGBA PNG 레이어 + PSD/PPTX 내보내기 지원 추론 설정: num_inference_steps=50, true_cfg_scale=4.0, 해상도 640 권장 from diffusers import QwenImageLayeredPipeline import torch pipeline = QwenImageLayeredPipeline.from_pretrained(\u0026#34;Qwen/Qwen-Image-Layered\u0026#34;) pipeline = pipeline.to(\u0026#34;cuda\u0026#34;, torch.bfloat16) inputs = { \u0026#34;image\u0026#34;: image, \u0026#34;layers\u0026#34;: 4, # 분해할 레이어 수 (가변) \u0026#34;resolution\u0026#34;: 640, \u0026#34;cfg_normalize\u0026#34;: True, } output = pipeline(**inputs) 설계 패턴에서 주목할 점 가변 레이어 수: 3개든 8개든 원하는 만큼 분해 가능하다. 재귀적 분해도 지원해서, 한 레이어를 다시 분해하는 \u0026ldquo;무한 분해\u0026quot;가 가능하다. 편집 파이프라인 분리: 분해 후 개별 레이어는 Qwen-Image-Edit로 편집하고, combine_layers.py로 다시 합성한다. 관심사 분리가 깔끔하다. PSD 내보내기: psd-tools 라이브러리를 활용해서 디자이너 워크플로우와 바로 연결된다. PopCon 활용 포인트 애니메이션 이모지를 만들 때, 캐릭터/배경/소품을 레이어로 분해하면 각 요소를 독립적으로 애니메이션할 수 있다. 예를 들어 캐릭터만 움직이고 배경은 고정하는 식이다.\nQwen-Image 생태계 — 20B MMDiT 파운데이션 모델 Qwen-Image-Layered를 이해하려면 상위 프로젝트인 Qwen-Image도 봐야 한다.\n항목 내용 GitHub QwenLM/Qwen-Image Stars 7,694 모델 크기 20B MMDiT 최신 버전 Qwen-Image-2.0 (2026.02) Qwen-Image는 텍스트 렌더링(특히 중국어)과 정밀 이미지 편집에 강점을 가진 파운데이션 모델이다. 2026년 2월에 발표된 Qwen-Image-2.0은 다음을 개선했다:\n전문 타이포그래피 렌더링 — PPT, 포스터, 만화 등 인포그래픽 직접 생성 네이티브 2K 해상도 — 사람, 자연, 건축물의 세밀한 디테일 이해+생성 통합 — 이미지 생성과 편집을 하나의 모드로 통합 경량화 아키텍처 — 더 작은 모델 크기, 더 빠른 추론 속도 AI Arena 10,000회 이상 블라인드 테스트에서 오픈소스 이미지 모델 1위를 기록했다.\nNano Banana 2 — Gemini Flash 속도의 이미지 생성 Google의 공식 발표 2026년 2월 Google이 공개한 Nano Banana 2(정식명 Gemini 3.1 Flash Image)는 Nano Banana Pro의 품질을 Flash 속도로 제공하는 모델이다.\n주요 특징:\n고급 세계 지식: Gemini의 실시간 웹 검색 정보를 활용한 정확한 렌더링 정밀 텍스트 렌더링 및 번역: 마케팅 목업, 인포그래픽에 정확한 텍스트 생성 주체 일관성: 최대 5개 캐릭터, 14개 오브젝트의 일관성 유지 프로덕션 스펙: 512px ~ 4K, 다양한 aspect ratio 지원 SynthID + C2PA: AI 생성 이미지 출처 추적 기술 내장 nano-banana-2-skill CLI 분석 항목 내용 GitHub kingbootoshi/nano-banana-2-skill Stars 299 언어 TypeScript (Bun 런타임) 라이선스 MIT 이 프로젝트는 Nano Banana 2를 CLI로 감싼 도구인데, 설계가 꽤 영리하다.\n아키텍처 특징 멀티 모델 지원: --model flash (기본), --model pro 등 모델 전환이 쉽다 Green Screen 파이프라인: -t 플래그 하나로 투명 배경 에셋 생성 AI가 green screen 위에 생성 -\u0026gt; FFmpeg colorkey + despill -\u0026gt; ImageMagick trim 코너 픽셀에서 키 색상을 자동 감지 (AI가 정확한 #00FF00 대신 #05F904 같은 근사값을 쓰기 때문) 비용 추적: 모든 생성을 ~/.nano-banana/costs.json에 기록 Claude Code Skill: Claude Code 플러그인으로도 동작해서, \u0026ldquo;generate an image of\u0026hellip;\u0026rdquo; 같은 자연어 명령으로 이미지를 생성할 수 있다 비용 구조 해상도 Flash 비용 Pro 비용 512x512 ~$0.045 N/A 1K ~$0.067 ~$0.134 2K ~$0.101 ~$0.201 4K ~$0.151 ~$0.302 4K 이미지 한 장에 $0.15면 매우 저렴하다. 대량 에셋 생성에 현실적인 가격이다.\nPopCon 활용 포인트 PopCon 이모지 에셋을 대량 생성할 때 Nano Banana 2의 -t (투명 배경) 모드가 바로 쓸 수 있다. 캐릭터 에셋을 green screen으로 생성하고, FFmpeg 파이프라인으로 배경을 자동 제거하는 흐름이다.\nVeo 3.1 — 사운드 포함 AI 동영상 생성 Google의 Veo 3.1은 텍스트 프롬프트에서 사운드가 포함된 동영상을 생성하는 모델이다.\n주요 기능 네이티브 오디오 생성: 별도의 TTS/사운드 모델 없이 동영상에 사운드가 포함된다 참고 이미지 기반 스타일 가이드: 여러 이미지를 업로드해서 캐릭터/장면의 스타일을 지정할 수 있다 세로 동영상 지원: 세로 이미지를 업로드하면 소셜 미디어용 세로 동영상을 생성한다 8초 분량: 현재 최대 8초 동영상 생성 가격 티어 모델 요금제 특징 Veo 3.1 Fast AI Pro 고화질 + 속도 최적화 Veo 3.1 AI Ultra 최고 수준 동영상 품질 PopCon 활용 포인트 정적 이모지에서 한 발 나아가, Veo 3.1로 이모지에 짧은 애니메이션과 사운드 이펙트를 추가할 수 있다. \u0026ldquo;웃는 캐릭터가 손을 흔드는 2초 애니메이션 + 효과음\u0026rdquo; 같은 시나리오에 적합하다.\nvLLM-Omni — 멀티모달 서빙 프레임워크 항목 내용 GitHub vllm-project/vllm-omni Stars 4,094 언어 Python 최신 릴리스 v0.18.0 (2026.03) 논문 arXiv:2602.02204 왜 중요한가 위에서 살펴본 모델들(Qwen-Image, Qwen-Image-Layered 등)이 모두 좋지만, 프로덕션에서 서빙하는 것은 별개의 문제다. vLLM-Omni는 이 gap을 메운다.\n아키텍처 핵심 기존 vLLM은 텍스트 기반 autoregressive 생성만 지원했다. vLLM-Omni는 세 가지를 확장한다:\nOmni-modality: 텍스트, 이미지, 비디오, 오디오 데이터 처리 Non-autoregressive 아키텍처: Diffusion Transformers (DiT) 등 병렬 생성 모델 지원 이종 출력: 텍스트 생성에서 멀티모달 출력까지 성능 최적화 KV 캐시 관리: vLLM의 효율적인 KV 캐시를 그대로 활용 파이프라인 스테이지 오버래핑: 높은 throughput OmniConnector 기반 완전 분리: 스테이지 간 동적 리소스 할당 분산 추론: Tensor, pipeline, data, expert parallelism 모두 지원 지원 모델 (2026.03 기준) v0.18.0에서 지원하는 주요 모델:\nQwen3-Omni / Qwen3-TTS: 텍스트+이미지+오디오 통합 Qwen-Image / Qwen-Image-Edit / Qwen-Image-Layered: 이미지 생성/편집/분해 Bagel, MiMo-Audio, GLM-Image: 기타 멀티모달 모델 Diffusion (DiT) 스택: 이미지/비디오 생성 Day-0 지원 패턴 vLLM-Omni의 주목할 점은 새 모델 출시와 동시에 서빙 지원을 제공하는 \u0026ldquo;Day-0 support\u0026rdquo; 패턴이다. Qwen-Image-2512 출시일에 바로 vLLM-Omni 지원이 나왔고, Qwen-Image-Layered도 마찬가지였다. 이는 모델 개발팀과 서빙 인프라팀 간의 긴밀한 협력을 보여준다.\nPopCon 활용 포인트 PopCon 서비스에서 이모지 생성 API를 구축할 때, vLLM-Omni를 서빙 레이어로 사용하면 Qwen-Image로 이미지를 생성하고, Qwen-Image-Layered로 분해하는 전체 파이프라인을 하나의 OpenAI 호환 API 뒤에 숨길 수 있다.\n빠른 링크 Qwen-Image-Layered GitHub — 이미지 레이어 분해 모델 Qwen-Image GitHub — 20B 이미지 파운데이션 모델 Qwen-Image-Layered 논문 nano-banana-2-skill GitHub — Gemini 기반 이미지 생성 CLI Nano Banana 2 공식 블로그 — Google 공식 발표 Veo 3.1 소개 페이지 — 사운드 포함 동영상 생성 vLLM-Omni GitHub — 멀티모달 서빙 프레임워크 vLLM-Omni 논문 인사이트 에코시스템이 수직 통합되고 있다. Qwen 팀은 파운데이션 모델(Qwen-Image) -\u0026gt; 특화 모델(Layered, Edit) -\u0026gt; 서빙(vLLM-Omni Day-0 지원)까지 전체 스택을 커버한다. Google은 Nano Banana 2로 생성, Veo 3.1로 동영상, SynthID/C2PA로 출처 추적까지 묶었다. 개별 모델의 성능보다 파이프라인 전체의 완성도가 경쟁력을 좌우하는 단계에 들어섰다.\n편집 가능성(Editability)이 새로운 차별점이다. 단순히 \u0026ldquo;좋은 이미지를 생성하는 것\u0026quot;에서 \u0026ldquo;생성된 이미지를 얼마나 쉽게 수정할 수 있는가\u0026quot;로 경쟁 축이 이동하고 있다. Qwen-Image-Layered의 레이어 분해는 이 방향의 대표적인 사례다. 레이어 단위로 분리하면 recolor, resize, repositon 같은 기본 조작이 물리적으로 다른 콘텐츠에 영향을 주지 않는다.\n서빙 인프라가 병목이다. 아무리 좋은 모델이 있어도 프로덕션에서 서빙할 수 없으면 의미가 없다. vLLM-Omni가 autoregressive 전용이던 vLLM을 Diffusion Transformer까지 확장한 것은 이 병목을 해소하려는 시도다. 특히 long sequence parallelism, cache acceleration 같은 최적화가 이미지 생성 모델의 서빙 비용을 현실적인 수준으로 낮추고 있다.\n도구 체인이 개발자 경험을 결정한다. nano-banana-2-skill 같은 CLI 래퍼가 299 star를 받은 이유가 있다. nano-banana \u0026quot;robot mascot\u0026quot; -t -o mascot 한 줄로 투명 배경 에셋이 나오는 경험은, API 문서를 읽고 코드를 작성하는 것과 차원이 다르다. Claude Code skill로도 동작하니 AI 코딩 어시스턴트에서 바로 이미지를 생성할 수 있다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-ai-image-gen-ecosystem/cover.jpg","permalink":"/ko/posts/2026-04-02-ai-image-gen-ecosystem/","title":"AI 이미지 생성 에코시스템 분석 — Qwen-Image-Layered, Nano Banana 2, Veo 3.1, vLLM-Omni"},{"content":"개요 2026년 3월 31일, Anthropic의 AI 코딩 에이전트 Claude Code의 전체 소스코드가 NPM 패키지에 포함된 소스맵(.map) 파일을 통해 공개 유출되었다. 약 1,900개의 TypeScript 파일, 512,000줄 이상의 코드가 노출되었으며, 미공개 기능인 Buddy 가차 시스템, Kairos 상시 어시스턴트, Undercover Mode 등 Anthropic이 발표하지 않은 내부 로드맵까지 드러났다. 이 사건은 모델 가중치 유출이 아님에도 불구하고, 에이전트 시대의 핵심 경쟁력인 하네스 설계가 통째로 노출되었다는 점에서 업계에 큰 파장을 일으키고 있다.\n사건 경위 — 소스맵이 뭐길래 Claude Code는 Anthropic이 NPM 레지스트리를 통해 배포하는 공식 CLI 도구다. JavaScript/TypeScript 프로젝트를 배포할 때 빌드 도구가 코드를 압축(minify)하는 것이 일반적이며, .map 파일(소스맵)은 이 압축된 코드와 원본 소스코드를 매핑해주는 디버깅용 파일이다. 프로덕션 배포물에는 절대 포함시키지 않아야 하는 파일이다.\n문제는 빌드 설정 오류로 이 소스맵 파일이 공개 NPM 패키지에 그대로 포함된 것이다. 소스맵은 Anthropic의 R2 스토리지 버킷에 저장된 원본 TypeScript 소스코드를 직접 가리키고 있었고, 해당 버킷 역시 공개 접근이 가능한 상태였다. 보안 연구자 Chai Found Show가 이를 최초 발견하여 X(트위터)에 공유했고, 해당 포스트는 310만 뷰를 넘겼다. 수 시간 내에 전체 소스코드가 GitHub에 아카이브되어 100개 이상의 스타와 1,900개의 포크를 기록했다.\nAnthropic은 신속하게 소스맵을 제거한 업데이트를 배포하고 이전 버전을 NPM에서 철회했지만, GitHub 아카이브는 이미 영구적으로 퍼진 뒤였다. 더 충격적인 것은 이것이 처음이 아니라는 점이다. 2025년에도 v2.8과 v4.228 버전에서 동일한 소스맵 유출이 있었고, 유출 5일 전인 3월 26일에는 CMS 설정 오류로 미발표 모델 Mythos와 초안 블로그 포스트가 노출되는 별도 사고도 있었다. 5일 안에 두 건의 설정 오류 사고가 발생한 것이다.\nflowchart LR A[\"TypeScript 원본 소스\"] --\u003e B[\"빌드 \u0026amp; 번들링\"] B --\u003e C[\".map 소스맵 생성\"] B --\u003e D[\"minified JS 번들\"] C --\u003e E[\"R2 스토리지 버킷\u0026lt;br/\u0026gt;(공개 접근 가능)\"] D --\u003e F[\"NPM 패키지 배포\"] C --\u003e|\".npmignore 누락\"| F F --\u003e G[\"보안 연구자 발견\"] G --\u003e H[\"GitHub 아카이브\u0026lt;br/\u0026gt;(1,900+ forks)\"]유출된 코드의 규모와 구조 유출된 코드베이스는 약 1,900개의 TypeScript 파일, 512,000줄 이상의 코드로 구성되어 있다. Bun 런타임 기반이며, React와 Ink를 사용한 터미널 UI를 갖추고 있다. 기술 스택을 살펴보면 Zod v4를 사용한 스키마 검증, MCP(Model Context Protocol) 클라이언트 매니저, OpenTelemetry 기반의 관찰 가능성(observability) 시스템, GrowthBook을 통한 feature flag 관리 등이 확인된다.\n아키텍처 측면에서 가장 주목할 부분은 40개 이상의 permission-gated 도구가 내장되어 있다는 점이다. AI 호출 및 스트리밍을 담당하는 모듈만 46,000줄에 달하며, 멀티 에이전트 오케스트레이션 시스템(Coordinator Mode)이 완벽하게 구현되어 있다. 하나의 Claude 인스턴스가 여러 워커 에이전트를 스폰하고 병렬로 관리할 수 있으며, 워커 간 통신은 XML 메시지와 공유 스크래치패드 디렉토리를 통해 이루어진다.\n엔트리 포인트는 main.tsx이며, bootstrap 레이어, conversation engine, 서비스 레이어(API), 오케스트레이션 레이어, 도구 레이어(40+ tools), 유틸리티 레이어(plugins, permissions)로 구성된다. 세션은 .claude 디렉토리의 JSONL 파일로 persist되고, 큰 결과물은 tool result 파일로 분리되어 메모리에 보관된다. 순환 의존성(circular dependency)이 다수 존재하며, 일부 Rust 네이티브 모듈(fuzzy search, Napi 모듈 등)도 포함되어 있다는 분석이 나왔다.\n미공개 기능들 — Buddy, Kairos, Ultra Plan 유출된 코드에서 가장 화제가 된 것은 Anthropic이 공개하지 않은 기능들이다. 이들은 환경 변수와 feature flag 뒤에 숨겨져 있어 일반 사용자에게는 활성화되지 않는 상태였다.\nBuddy 시스템은 다마고치 스타일의 AI 반려동물 기능이다. 18종의 종족(오리, 드래곤, 아홀로틀, 카피바라, 버섯, 유령 등)이 있으며, Common부터 1% 확률의 Legendary까지 희귀도 티어가 존재한다. 모자, 색이 다른 변종(shiny) 등의 코스메틱과 함께 debugging, patience, chaos, wisdom, snark 다섯 가지 성격 스탯이 있다. 첫 실행 시 Claude가 고유한 이름과 성격(\u0026ldquo;soul description\u0026rdquo;)을 생성하도록 설계되어 있었다. 코드에는 4월 1~7일 티저 기간, 5월 정식 출시(Anthropic 직원 우선) 일정까지 포함되어 있었다.\nKairos는 always-on 상시 어시스턴트 모드다. 사용자 입력을 기다리지 않고 항상 실행되며, 매일의 관찰 내용과 조치를 기록하는 append-only 로그(\u0026ldquo;tick\u0026rdquo;)를 유지한다. 15초의 차단 예산(blocking budget)이 있어 사용자 워크플로우를 15초 이상 방해하는 작업은 자동 연기된다. 정기 알림을 받아 능동적 조치를 취할지 침묵할지 결정하는 로직도 포함되어 있다.\nUltra Plan은 복잡한 계획 작업을 Opus 4.6이 실행되는 원격 클라우드 컨테이너로 오프로드하여 최대 30분간 deep planning을 수행하는 모드다. tengu-ultraplan 모델 설정을 통해 CC(Cloud Container) 세션을 시작하고, 3초마다 폴링하며 상태를 표시한다.\n**Dream 시스템(Auto-Dream)**은 백그라운드 메모리 통합 엔진이다. 포크된 서브에이전트가 실행하며, 세 가지 게이트를 모두 통과해야 트리거된다: 마지막 꿈 이후 24시간 경과(시간 게이트), 최소 5번의 세션 실행(세션 게이트), 동시 실행 방지를 위한 잠금 획득(잠금 게이트). 메모리 디렉토리를 탐색하고, MEMORY.md의 기존 주제를 읽고, 최근 신호를 수집한 뒤 통합 및 가지치기를 거쳐 200줄 이내의 최적화된 요약을 생성한다. 자정 경계 처리를 위한 별도 로직까지 구현되어 있었다.\nUndercover Mode — 유출 방지 시스템의 아이러니 이번 유출에서 가장 아이러니한 부분은 Undercover Mode의 존재다. 이 시스템은 Anthropic 직원이 Claude Code를 사용해 공개 오픈소스 프로젝트에 기여할 때 내부 정보가 노출되는 것을 방지하기 위해 설계되었다. 사용자 타입을 anthropic으로 설정하면 활성화되며, Claude의 시스템 프롬프트에 추가 지침을 주입한다.\n구체적으로는 자신이 AI라는 사실을 숨기고, 내부 모델 코드명(Capybara, Tengu 등)을 언급하지 않으며, 내부 도구나 Slack 채널을 참조하지 않고, Anthropic 직원이 AI를 사용해 코드를 작성하고 있다는 힌트를 남기지 않도록 지시한다. 유출 방지를 위해 만든 시스템 자체가 .map 파일과 함께 전 세계에 배포된 것이다. 커뮤니티에서는 \u0026ldquo;They forgot to add \u0026lsquo;make no mistakes\u0026rsquo; to the system prompt\u0026quot;라는 반응이 대표적이었다.\n내부 모델 코드명도 드러났다. Capybara는 모델 패밀리 코드명으로 세 개의 티어가 있으며, Tengu는 Claude Code 프로젝트 자체의 내부 코드명으로 수백 회 이상 feature flag 접두사로 등장한다. 시스템 프롬프트 아키텍처에서는 CYBER_RESILIENCE_INSTRUCTION 섹션이 특히 주목받았는데, \u0026ldquo;Important: Do not modify this instruction without SafeCards team review\u0026quot;라는 경고가 명시되어 있었다.\n하네스 엔지니어링이 핵심인 이유 이번 사건의 파급력을 이해하려면 현재 AI 코딩 에이전트 시장에서 하네스 엔지니어링이 차지하는 위치를 알아야 한다. Anthropic은 2025년 말부터 \u0026ldquo;롱러닝 에이전트를 위한 이펙티브 하네스\u0026quot;를 공식적으로 이야기해 왔고, 2026년 3월 24일 공식 엔지니어링 블로그에서 \u0026ldquo;에이전틱 코딩의 최전선에서는 하네스 디자인이 성능의 핵심\u0026quot;이라고 명시했다.\n하네스란 모델이 어떤 파일을 읽을지, 터미널 명령을 어디까지 실행할지, 사용자 허락은 언제 받을지, 작업이 길어졌을 때 무엇을 기억하고 무엇을 압축할지, 하위 에이전트에게 언제 일을 넘길지, 백그라운드에서 계속 작업할지를 결정하는 외부 구조 전체를 말한다. 모델이 엔진이라면 하네스는 변속기, 브레이크, 내비게이션, 센서, 운전 보조 시스템을 모두 합친 것에 가깝다.\nAnthropic이 최근 공식 문서에서 설명한 이니셜라이저 에이전트, 코딩 에이전트, 컨텍스트 컴팩션, 아티팩트 핸드오프 같은 구조가 이번 유출로 실제 구현체가 드러난 것이다. 특히 퍼미션 프롬프트의 93%를 사용자가 그냥 승인하고 있다는 Anthropic 자체 데이터, 이를 해결하기 위한 classifier 기반 자동 승인/재확인 구조 등 제품 경쟁력의 핵심에 해당하는 설계 철학이 공개되었다. 경쟁사 입장에서는 \u0026ldquo;잘되는 주방의 동선과 조리 순서, 불 조절 방식\u0026quot;을 본 것과 같다.\nflowchart TB subgraph Harness[\"하네스 (유출된 영역)\"] direction TB P[\"Permission System\u0026lt;br/\u0026gt;40+ gated tools\"] --\u003e O[\"Orchestration\u0026lt;br/\u0026gt;Coordinator Mode\"] O --\u003e SA[\"Sub-Agent 관리\u0026lt;br/\u0026gt;병렬 워커 스폰\"] O --\u003e BG[\"Background Agent\u0026lt;br/\u0026gt;Task 시스템\"] SA --\u003e MEM[\"Memory 시스템\u0026lt;br/\u0026gt;Dream / MEMORY.md\"] BG --\u003e MEM MEM --\u003e CC[\"Context Compaction\u0026lt;br/\u0026gt;JSONL 세션 persist\"] end subgraph Model[\"모델 (유출되지 않음)\"] MW[\"Model Weights\u0026lt;br/\u0026gt;Claude Opus / Sonnet\"] TD[\"Training Data\"] end subgraph User[\"사용자 환경\"] CLI[\"Claude Code CLI\u0026lt;br/\u0026gt;Bun + React Ink\"] IDE[\"IDE Bridge\u0026lt;br/\u0026gt;LSP 통합\"] end User --\u003e Harness Harness --\u003e Model커뮤니티 반응과 의혹 커뮤니티 반응은 크게 세 갈래로 나뉘었다. 첫 번째는 \u0026ldquo;별일 아니다\u0026quot;는 입장으로, 모델 가중치가 유출된 것이 아니므로 Claude의 핵심 경쟁력은 여전히 안전하다는 시각이다. Hacker News에서도 \u0026ldquo;underlying model이 Claude를 가치 있게 만드는 것이지 클라이언트 코드가 아니다\u0026quot;라는 의견이 있었다.\n두 번째는 \u0026ldquo;심각한 신뢰 문제\u0026quot;라는 입장이다. 파일 시스템과 터미널 접근 권한을 맡기는 도구를 만드는 회사가 자사 소프트웨어를 두 번이나 제대로 보호하지 못했다는 점이 문제의 핵심이라는 것이다. AI 안전성을 최우선으로 내세우는 회사가 릴리스 위생, 패키징 검수, 소스맵 제거 같은 기본적인 소프트웨어 공급망 통제에서 실수를 반복한 아이러니가 지적되었다.\n세 번째는 한국 유튜버를 중심으로 나온 \u0026ldquo;의도적 유출 의혹\u0026quot;이다. CI/CD 파이프라인의 여러 단계를 모두 뚫고 소스맵이 포함되었다는 것이 상식적으로 납득이 어렵다는 논리다. .npmignore에 원래 소스맵 제외 설정이 있었는데 이것이 빠졌다는 것은 누군가 의도적으로 제거한 것 아니냐는 의문, OpenAI Codex가 오픈소스로 공개된 시점과의 타이밍, 4월 1일 만우절과의 근접성 등이 근거로 제시되었다. 다만 이는 추측에 불과하며, Anthropic은 CI 파이프라인의 배포 실수라고 공식 확인했다.\n보안 시사점 — 공급망 보안의 기본기 이번 사건에서 기술적으로 가장 중요한 교훈은 소프트웨어 공급망 보안(supply-chain security)의 기본기다. 소스맵 파일의 프로덕션 번들 포함 여부를 CI/CD 파이프라인에서 자동 검증하는 것은 체크리스트 한 줄이면 가능한 일이다. .npmignore 또는 package.json의 files 필드를 통한 화이트리스트 방식이 더 안전하며, 번들 산출물의 크기/내용을 릴리스 전에 자동 스캔하는 프로세스가 있었다면 두 번의 유출 모두 방지할 수 있었다.\n사용자 데이터 유출은 아니었다. API 키, 개인 정보, 대화 이력 등은 포함되지 않았으며, 유출된 것은 CLI 클라이언트 코드 자체다. 그러나 공격자 관점에서는 내부 아키텍처 지식이 프롬프트 인젝션 공격, 권한 체크 우회, 가드레일 회피 등의 공격 효율을 높여줄 수 있다. permission 시스템의 로직, 도구 호출 순서, 백그라운드 작업과 로컬 브리지의 연결 지점 등이 이제 공개 지식이 되었기 때문이다.\n엔터프라이즈 고객 입장에서는 당장 데이터가 유출되지 않았더라도 배포 및 검수 프로세스의 성숙도를 재평가할 수밖에 없다. 안전성을 핵심 브랜드로 내세운 회사가 기본적인 빌드 설정에서 반복 사고를 낸 것은 신뢰 비용을 수반한다.\nOpenClaude — 유출 코드의 재탄생 유출 사태가 가져온 가장 극적인 후속 전개는 OpenClaude의 등장이다. 유출된 Claude Code 소스코드를 기반으로 만들어진 오픈소스 포크로, GPT-4o, Gemini, DeepSeek, Ollama 등 200개 이상의 모델을 Claude Code의 UI와 워크플로우 그대로 사용할 수 있도록 OpenAI 호환 provider shim을 추가한 프로젝트다.\n무엇이 그대로이고 무엇이 바뀌었나 OpenClaude가 유지하는 것은 Claude Code의 하네스 전체다. bash, file read/write/edit, grep, glob, agents, tasks, MCP, 슬래시 커맨드, 스트리밍 출력, 멀티스텝 추론 — Claude Code에서 쓰던 터미널 우선 워크플로우가 그대로 동작한다. 바뀐 것은 백엔드 모델뿐이다. 환경 변수 세 줄로 즉시 전환된다.\nexport CLAUDE_CODE_USE_OPENAI=1 export OPENAI_API_KEY=sk-your-key-here export OPENAI_MODEL=gpt-4o OPENAI_BASE_URL만 바꾸면 OpenRouter(Gemini), DeepSeek, Groq, Mistral, LM Studio, Ollama(로컬 모델) 등 어떤 OpenAI 호환 제공자든 연결할 수 있다. Codex 백엔드도 지원하는데, codexplan(GPT-5.4, 고추론)과 codexspark(GPT-5.3 Codex Spark, 빠른 루프) 두 가지 모드를 제공한다.\n설치와 프로필 시스템 npm install -g @gitlawb/openclaude /provider 슬래시 커맨드로 guided setup을 진행하면 선호 제공자와 모델을 .openclaude-profile.json에 저장한다. 이후에는 프로필만으로 최적 제공자/모델로 바로 실행된다. Ollama를 사용하는 경우 로컬 인스턴스를 자동 감지한다.\n커뮤니티 반응 — 기회 vs. 저작권 2026년 4월 기준 GitHub에서 8,176개의 스타와 3,131개의 포크를 기록하며 폭발적인 관심을 받고 있다. \u0026ldquo;Claude Code의 UX는 그대로 쓰면서 모델 비용이나 API 선택의 자유를 갖고 싶은 개발자들에게 즉각적인 답이 된다\u0026quot;는 평가다.\n그러나 GeekNews 커뮤니티 반응은 냉담하다. \u0026ldquo;훔친 걸 훔쳐서 훔치고\u0026rdquo;, \u0026ldquo;해적판 게임 돌아다니는 것과 다른 게 없다\u0026rdquo;, \u0026ldquo;저작권이 뭔지 모르나봐요\u0026rdquo; 같은 비판이 주를 이룬다. Claude는 Anthropic의 등록 상표이기 때문에 프로젝트 이름 자체도 법적 문제가 될 수 있다는 지적도 있다(Clawdbot이 OpenClaw로 이름을 바꾼 사례가 언급됐다). OpenClaude 저장소 자체도 \u0026ldquo;OpenClaude is an independent community project and is not affiliated with, endorsed by, or sponsored by Anthropic\u0026quot;이라고 면책 조항을 명시하고 있다.\n법적 긴장과 기술적 완성도 유출된 소스 기반이라는 점에서 Anthropic과의 법적 분쟁 가능성이 상존한다. Anthropic은 Claude Code 소스코드에 대한 저작권을 보유하고 있으며, 유출된 코드를 그대로 포크해 배포하는 것은 저작권 침해에 해당할 수 있다. MIT 라이선스를 표방하고 있지만, 그 라이선스를 적용할 권한이 Gitlawb에게 있는지가 핵심 쟁점이다.\n기술적 완성도는 별개로 높다는 평가를 받는다. VS Code 익스텐션, Firecrawl 연동, Android 설치 가이드, LM Studio 제공자 지원(PR #227) 등 이미 활발한 커뮤니티 기여가 이루어지고 있다. 유출 사태 이후 불과 며칠 만에 이 정도 규모의 생태계가 형성되었다는 사실 자체가, Claude Code 하네스 아키텍처가 얼마나 재사용 가능성이 높은 설계를 갖추고 있었는지를 역설적으로 증명한다.\n빠른 링크 Claude Code LEAKS is INSANE! - Julian Goldie SEO — 유출 경위와 미공개 기능(Buddy, Kairos, Undercover Mode) 종합 분석 Claude Code LEAKED - What It Really Means — 코드베이스 구조, 아키텍처, 개선 가능 포인트 기술 분석 클로드 코드 소스코드 유출 사태. 도대체 왜 그러시는 건데요? — 의도적 유출 의혹, 가차 시스템/Dream 시스템 상세 분석 (한국어) AI 모델 유출보다 더 치명적인 이유 - 클로드 코드 유출, 하네스가 일부 유출 — 하네스 엔지니어링 관점의 사건 해석 (한국어) Claude Code CLI 유출된 소스코드 파헤치기 - bkamp — 커뮤니티 소스코드 분석 글 OpenClaude GitHub 저장소 — 유출 코드 기반 멀티모델 코딩 에이전트 CLI (8,176 stars) GeekNews: Claude Code 소스 유출로 탄생한 OpenClaude — GPT-4o, Gemini, Ollama 등 200개 모델을 Claude Code UI로 인사이트 이번 Claude Code 소스코드 유출 사태는 AI 시대의 경쟁력이 어디에 있는지를 극명하게 보여준 사건이다. 모델 가중치가 아닌 하네스 아키텍처가 유출되었다는 점에서, 에이전트 시대의 핵심 IP가 더 이상 모델 파라미터에만 있지 않다는 현실이 드러났다. 40개 이상의 permission-gated 도구, 멀티 에이전트 오케스트레이션, Dream 시스템을 통한 메모리 통합, 15초 차단 예산의 Kairos 상시 어시스턴트 등 Claude Code의 내부 복잡도는 대부분의 예상을 훨씬 뛰어넘었다. 동시에 .npmignore 한 줄, CI 파이프라인의 산출물 검증 한 단계만 있었으면 방지할 수 있었다는 점에서 기본기의 중요성도 재확인되었다.\nOpenClaude의 등장은 이 사태의 여파가 단순한 정보 노출을 넘어섰음을 보여준다. 유출된 하네스 코드가 며칠 만에 다른 모델들을 위한 풀스택 코딩 에이전트로 재탄생한 것은, 아이러니하게도 Claude Code 설계의 품질을 증명하는 증거다. Anthropic이 \u0026ldquo;안전성의 회사\u0026quot;를 표방하면서 소프트웨어 공급망의 가장 기초적인 부분에서 반복 사고를 낸 것은 기술적 아이러니를 넘어 엔터프라이즈 신뢰의 문제로 확장될 수 있다. 개발자로서 이번 사건에서 배울 점은, 아무리 정교한 보안 시스템(Undercover Mode)을 만들어도 빌드 파이프라인의 한 줄 설정이 모든 것을 무력화할 수 있다는 것이다. 결국 소프트웨어 보안은 가장 화려한 기능이 아니라 가장 지루한 체크리스트에서 결정된다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-claude-code-leak/cover.jpg","permalink":"/ko/posts/2026-04-02-claude-code-leak/","title":"Claude Code 소스코드 유출 사태 — NPM 소스맵 실수로 드러난 에이전트 아키텍처의 민낯"},{"content":"개요 이전 글: #3 — 플러그인 트리거 수정과 마켓플레이스 추천 시스템\n이번 #4에서는 17개 커밋에 걸쳐 마켓플레이스 설치 인프라를 안정화하고 v0.3.0을 릴리스했다. marketplace.json 도입으로 claude plugin add 설치 경로를 확보하고, README를 영어/한국어로 분리했으며, 플러그인 트리거 전면 검토를 통해 CLAUDE_PLUGIN_ROOT 통일, preset 체크, 설치 검증까지 완료했다. 마켓플레이스 추천도 사전 검증 기반으로 재설계했다.\nmarketplace.json — 플러그인 설치의 시작점 문제 Claude Code 마켓플레이스에서 플러그인을 설치하려면 .claude-plugin/marketplace.json이 필요하다. 이 파일이 없으면 claude plugin add 명령으로 설치할 수 없어, 사용자가 수동으로 클론해야 했다.\n해결 marketplace.json을 추가하고, source 경로를 ./ 상대 경로로 수정해 마켓플레이스 설치를 가능하게 했다. 이것이 v0.3.0의 출발점이다.\ngraph LR A[\"사용자\"] --\u003e|\"claude plugin add\"| B[\"Marketplace\"] B --\u003e|\"marketplace.json 참조\"| C[\"plugin.json\"] C --\u003e D[\"skills / hooks 설치\"] D --\u003e E[\"HarnessKit 활성화\"] README 이중화 — 영어와 한국어 분리 마켓플레이스에 올라가면 영어 사용자도 README를 읽게 된다. 하나의 README에 두 언어를 섞으면 양쪽 모두 불편하다. README.md를 영어 전용으로 다시 작성하고, README.ko.md를 새로 추가해 한국어 버전을 분리했다.\n플러그인 트리거 전면 검토와 수정 스펙 기반 접근 단순히 버그를 고치는 것이 아니라, 먼저 스펙 문서를 작성해 5개 트리거링 문제를 분류했다. CRITICAL, MAJOR, MINOR로 우선순위를 나누고, 스펙 리뷰를 거쳐 수정 계획을 확정한 뒤 구현에 들어갔다.\ngraph TD A[\"스펙 작성 \u0026lt;br/\u0026gt; 5개 문제 식별\"] --\u003e B[\"스펙 리뷰 \u0026lt;br/\u0026gt; CRITICAL/MAJOR 수정\"] B --\u003e C[\"구현 계획 수립\"] C --\u003e D[\"CLAUDE_PLUGIN_ROOT \u0026lt;br/\u0026gt; 통일\"] C --\u003e E[\"preset 체크 \u0026lt;br/\u0026gt; 추가\"] C --\u003e F[\"status 스킬에 \u0026lt;br/\u0026gt; 설치 검증 추가\"] D --\u003e G[\"hooks / skills \u0026lt;br/\u0026gt; 전체 마이그레이션\"] E --\u003e G F --\u003e G G --\u003e H[\"v0.3.0 릴리스\"]CLAUDE_PLUGIN_ROOT 통일 claude plugin path, 하드코딩된 절대 경로, 상대 경로가 혼재하던 것을 CLAUDE_PLUGIN_ROOT 환경 변수 하나로 통일했다. guardrails.sh, pre-commit-test.sh 등 hooks와 init, setup 스킬 모두 동일한 패턴으로 마이그레이션했다.\n# 통일된 패턴: 환경 변수 + dirname fallback PLUGIN_DIR=\u0026#34;${CLAUDE_PLUGIN_ROOT:-$(cd \u0026#34;$(dirname \u0026#34;$0\u0026#34;)/..\u0026#34; \u0026amp;\u0026amp; pwd)}\u0026#34; preset 체크 추가 post-edit-lint.sh와 post-edit-typecheck.sh가 preset 설정 전에도 실행되면서 오류가 발생했다. preset 파일 존재 여부를 먼저 확인하고, 없으면 조기 종료하도록 수정했다.\n설치 검증 기능 /harnesskit:status 스킬에 플러그인 설치 상태를 검증하는 기능을 추가했다. 스킬 파일 존재 여부, hooks 실행 권한, 설정 파일 무결성을 한눈에 확인할 수 있다.\n마켓플레이스 검증 추천 시스템 실시간 마켓플레이스 검색에 의존하던 추천을 사전 검증된 marketplace-recommendations.json으로 교체했다.\nupdate-recommendations.sh 스크립트가 마켓플레이스를 크롤링해 목록을 갱신한다 /harnesskit:init이 이 목록에서 프로젝트에 맞는 플러그인을 추천한다 /harnesskit:insights도 같은 목록을 참조해 일관된 추천을 보장한다 3단계 슬라이딩 윈도우 도구 시퀀스 session-end.sh의 도구 사용 패턴 분석을 업그레이드했다. 단순 카운트 대신 3단계 슬라이딩 윈도우로 도구 시퀀스를 추적하고, tool:summary 형식으로 기록한다. 반복 패턴을 감지해 자동화 제안의 정밀도를 높였다.\nv0.3.0 릴리스 모든 수정이 반영된 후 plugin.json의 버전을 0.3.0으로 올렸다. 마켓플레이스 플러그인 캐시가 버전 변경을 감지해 갱신하므로, 설치된 사용자에게도 변경 사항이 전파된다.\n커밋 로그 메시지 변경 feat: add marketplace.json for plugin installation marketplace fix: use ./ relative path in marketplace.json source marketplace docs: split README into English and Korean versions docs docs: add Korean README docs docs: add spec for plugin trigger review — 5 fixes docs docs: address spec review — fix CRITICAL and MAJOR issues docs docs: add implementation plan for plugin trigger fixes docs fix: add preset check to post-edit hooks + CLAUDE_PLUGIN_ROOT fallback hooks refactor: unify PLUGIN_DIR to CLAUDE_PLUGIN_ROOT with fallback hooks refactor: migrate skills from \u0026lsquo;claude plugin path\u0026rsquo; to CLAUDE_PLUGIN_ROOT skills feat: add verified marketplace-recommendations.json templates feat: add update-recommendations.sh for marketplace crawling scripts feat: rewrite init marketplace discovery with verified recs skills feat: add recommendations.json reference to insights skills feat: upgrade tool sequence to 3-step sliding window hooks feat: add plugin installation verification to status skills chore: bump version to 0.3.0 for plugin cache refresh plugin 인사이트 마켓플레이스에 올린다는 것은 \u0026ldquo;내 환경에서 동작하는 도구\u0026quot;를 \u0026ldquo;누구의 환경에서든 동작하는 제품\u0026quot;으로 전환하는 일이다. marketplace.json 하나 추가하는 것은 간단하지만, 그 뒤로 경로 참조 통일, 환경 변수 fallback, preset 미설정 대응, 설치 상태 검증까지 연쇄적으로 필요해진다. 스펙 문서를 먼저 작성하고 리뷰한 후 구현에 들어간 것이 효과적이었다 — 5개 문제를 한 번에 파악하고 우선순위를 정한 덕분에 흩어진 수정 대신 체계적인 마이그레이션을 할 수 있었다. \u0026ldquo;코드를 고치기 전에 문서를 고쳐라\u0026quot;는 원칙이 다시 한번 유효했다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-harnesskit-dev4/cover.jpg","permalink":"/ko/posts/2026-04-02-harnesskit-dev4/","title":"HarnessKit 개발기 #4 — 마켓플레이스 안정화와 v0.3.0 릴리스"},{"content":"개요 이전 글: #6 — S3 이미지 스토리지 마이그레이션과 브랜딩\n이번 #7에서는 7개 커밋에 걸쳐 세 가지 핵심 작업을 진행했다. 첫째, 기존 검색 점수 기반 톤/앵글 이미지 주입 로직을 Gemini Flash LLM 카테고리 분류 방식으로 전면 교체했다. 둘째, S3 마이그레이션 이후 깨진 다운로드 버튼을 백엔드 프록시로 수정했다. 셋째, 사용자가 톤/앵글 반영 비율을 조정하여 이미지를 재생성할 수 있는 기능을 추가했다. 부수적으로 레포에서 대용량 이미지 데이터를 제거하고 pyproject.toml로 패키지 관리를 마이그레이션했다.\ngraph TD A[\"사용자 프롬프트\"] --\u003e B[\"Gemini Flash\u0026lt;br/\u0026gt;카테고리 분류\"] B --\u003e C{\"4개 카테고리 중 1개 선택\"} C --\u003e D[\"a: 내추럴/필름\"] C --\u003e E[\"b: 비비드/컬러풀\"] C --\u003e F[\"c: 시네마틱/콘트라스트\"] C --\u003e G[\"d: 뷰티\"] D --\u003e H[\"랜덤 이미지 2장 선택\u0026lt;br/\u0026gt;톤 + 앵글\"] E --\u003e H F --\u003e H G --\u003e H B --\u003e I[\"톤/앵글 비율 결정\u0026lt;br/\u0026gt;25 / 50 / 75 / 100%\"] H --\u003e J[\"프롬프트에 비율 반영\u0026lt;br/\u0026gt;이때 톤을 N%만 참고\"] I --\u003e J J --\u003e K[\"Gemini 이미지 생성\"] K --\u003e L{\"사용자 비율 조정?\"} L --\u003e|\"예\"| M[\"injection_override\u0026lt;br/\u0026gt;같은 이미지, 다른 비율\"] M --\u003e J L --\u003e|\"아니오\"| N[\"완료\"] LLM 카테고리 분류로 톤/앵글 주입 전면 교체 배경 기존 톤/앵글 자동 주입 시스템은 하이브리드 검색 파이프라인을 사용해 후보 이미지를 찾고, images.json의 tone_score/angle_score로 점수를 매겨 상위 20%에서 선택하는 방식이었다. 이 방식은 두 가지 문제가 있었다:\n톤/앵글 이미지가 기존 검색용 이미지 풀과 혼재되어 있어 부적절한 이미지가 선택될 수 있었다 프롬프트의 분위기와 무관하게 검색 점수만으로 선택하다 보니 일관성이 떨어졌다 새로운 방식에서는 전용 톤/앵글 레퍼런스 이미지 299장을 4개 카테고리로 분류하여 별도 관리하고, LLM이 프롬프트를 분석해 카테고리와 반영 비율을 결정하도록 했다.\n카테고리 설명 이미지 수 a(natural,film) 자연스럽고 필름 느낌, 따뜻한 색감 129장 b(vivid,colorful) 선명하고 화려한, 높은 채도 39장 c(cinematic,contrast) 영화적 무드, 강한 명암 대비 80장 d(beauty) 뷰티/인물 스타일, 부드러운 조명 51장 구현 injection.py 전면 재작성:\n기존의 검색+점수 로직(_search_candidates_for_injection, _select_best_category_ref)을 모두 제거하고, Gemini Flash를 활용한 경량 분류 호출로 교체했다. LLM에게 프롬프트를 분석시키면 카테고리 하나와 톤/앵글 비율(25/50/75/100%)을 JSON으로 반환한다.\nCLASSIFICATION_PROMPT = \u0026#34;\u0026#34;\u0026#34;\\ 당신은 이미지 생성 프롬프트를 분석하여 가장 적합한 톤/앵글 카테고리를 선택하고, 톤과 앵글의 반영 비율을 결정하는 전문가입니다. ## 반영 비율 가이드 - 25%: 프롬프트가 이미 매우 구체적인 스타일/톤을 명시 → 최소한만 참고 - 50%: 어느 정도 스타일 방향은 있지만 보강 필요 - 75%: 주제 중심이고 스타일 지정이 약해서 많이 참고 필요 - 100%: 스타일 관련 언급이 전혀 없어 전적으로 참고 ## 응답 형식 (JSON만 출력) {{\u0026#34;category\u0026#34;: \u0026#34;...\u0026#34;, \u0026#34;tone_ratio\u0026#34;: N, \u0026#34;angle_ratio\u0026#34;: N}} \u0026#34;\u0026#34;\u0026#34; 분류 결과에 따라 해당 카테고리 폴더에서 톤용, 앵글용 이미지를 각각 랜덤 선택한다. 같은 카테고리에서 선택하되 서로 다른 이미지를 사용한다.\n스키마 변경:\nInjectedReference에서 score: float을 제거하고 category: str + ratio: int를 추가했다. InjectionInfo에도 category 필드를 추가하여 프론트엔드에서 어떤 카테고리로 분류됐는지 표시할 수 있게 했다.\nclass InjectedReference(BaseModel): filename: str category: str = \u0026#34;\u0026#34; ratio: int = 100 프롬프트 구성 변경:\n비율 정보를 직접 프롬프트에 반영하도록 build_generation_prompt()를 업데이트했다:\n톤/색감 레퍼런스. 무조건 이 이미지의 색감, 톤, 무드만 참고하세요. 이때 톤을 {N}%만 참고하여 반영하세요. 이 이미지의 구도, 피사체, 형태, 배경 등 색감 외 요소는 절대로 반영하지 마세요. S3 통합:\n299장의 톤/앵글 레퍼런스 이미지를 S3에 업로드하고, ref_dirs에 4개 카테고리 서브디렉토리를 등록하여 기존 image_ref_1~4와 동일한 방식으로 서빙되도록 했다. S3 키 구조는 refs/tone_angle_image_ref/{category}/{filename}으로, 로컬 디렉토리 구조를 그대로 반영한다.\n문제 해결 처음 S3에 업로드할 때 키 구조가 refs/a(natural,film)/...으로 플랫하게 들어가 기존 image_ref_1~4 이미지와 같은 레벨에 혼재됐다. 사용자 피드백에 따라 refs/tone_angle_image_ref/a(natural,film)/...으로 상위 폴더를 추가하여 레포 구조와 일치시키고, build_ref_key_cache에서 Path.relative_to(\u0026quot;data\u0026quot;)를 사용해 중첩 디렉토리도 올바르게 캐싱하도록 수정했다.\n# 기존: p.name만 사용 → \u0026#34;a(natural,film)\u0026#34; # 수정: data/ 기준 상대경로 → \u0026#34;tone_angle_image_ref/a(natural,film)\u0026#34; try: ref_subdir = str(p.relative_to(\u0026#34;data\u0026#34;)) except ValueError: ref_subdir = p.name S3 이미지 다운로드 버튼 수정 배경 #6에서 S3로 이미지 스토리지를 마이그레이션한 후, 다운로드 버튼이 작동하지 않는 문제가 발견됐다. 버튼을 누르면 이미지가 새 탭에서 열리거나 화면에 확대되기만 할 뿐, 파일로 저장되지 않았다.\n원인 분석 HTML \u0026lt;a download\u0026gt; 속성은 same-origin URL에서만 동작한다. S3 마이그레이션 전에는 /images/filename으로 같은 도메인에서 서빙되어 문제가 없었지만, 마이그레이션 후에는 https://\u0026lt;bucket\u0026gt;.s3.\u0026lt;region\u0026gt;.amazonaws.com/... 형태의 cross-origin URL로 바뀌면서 브라우저가 download 속성을 무시하게 됐다.\n추가로, 새로 생성된 이미지는 data URI(data:image/png;base64,...)를 사용하므로 fetch()가 정상 동작했지만, 히스토리 이미지는 presigned S3 URL이라 CORS 정책에 의해 fetch()도 차단됐다.\n구현 2단계로 수정했다:\n1단계 \u0026ndash; 프론트엔드 downloadImage 헬퍼 추가:\n\u0026lt;a href download\u0026gt; 태그를 \u0026lt;button\u0026gt;으로 교체하고, JavaScript로 blob을 fetch하여 프로그래매틱 다운로드를 트리거하도록 변경했다.\nexport const downloadImage = async (filename: string): Promise\u0026lt;void\u0026gt; =\u0026gt; { const downloadUrl = `/images/${encodeURIComponent(filename)}/download`; const response = await fetch(downloadUrl, { credentials: \u0026#39;include\u0026#39; }); if (!response.ok) throw new Error(`Download failed: ${response.status}`); const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); const a = document.createElement(\u0026#39;a\u0026#39;); a.href = blobUrl; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(blobUrl); }; 2단계 \u0026ndash; 백엔드 다운로드 프록시 엔드포인트:\nGET /images/{filename}/download 엔드포인트를 추가하여 S3에서 이미지 바이트를 직접 스트리밍하고 Content-Disposition: attachment 헤더를 붙여 반환한다. 기존 /images/{filename}은 302 리다이렉트 방식이라 CORS 문제를 해결할 수 없었기 때문에, 별도 프록시가 필요했다.\n소유권 검증(check_file_ownership)과 Content-Disposition 헤더 인젝션 방어(따옴표 제거)도 포함했다.\n사용자 비율 조정 재생성 배경 LLM이 결정한 톤/앵글 반영 비율이 사용자의 의도와 다를 수 있다. 예를 들어 LLM이 톤 75%로 판단했지만, 사용자는 25%로 낮추고 싶을 수 있다. 첫 번째 생성은 AI가 판단하되, 생성된 이미지를 클릭해 상세 화면에서 비율을 변경하여 재생성할 수 있어야 한다.\n구현 InjectionOverride 스키마 추가:\n백엔드에 InjectionOverride 모델을 추가하고, GenerateImageRequest에 injection_override 옵셔널 필드를 추가했다. 이 필드가 있으면 LLM 분류를 건너뛰고 사용자가 지정한 비율과 같은 이미지 파일로 바로 생성한다.\nclass InjectionOverride(BaseModel): tone_filename: str angle_filename: str category: str tone_ratio: int = Field(ge=25, le=100) angle_ratio: int = Field(ge=25, le=100) 프론트엔드 비율 조정 UI:\nGeneratedImageDetail 컴포넌트에 톤/앵글 비율 뱃지를 클릭하면 25 -\u0026gt; 50 -\u0026gt; 75 -\u0026gt; 100 -\u0026gt; 25로 순환하는 인터랙션을 추가했다. 원래 비율과 달라지면 \u0026ldquo;비율 변경 재생성\u0026rdquo; 버튼이 나타나고, 클릭 시 injection_override를 포함한 생성 요청을 보낸다.\nconst RATIO_STEPS = [25, 50, 75, 100] as const; const nextRatio = (current: number) =\u0026gt; { const idx = RATIO_STEPS.indexOf(current as typeof RATIO_STEPS[number]); return RATIO_STEPS[(idx + 1) % RATIO_STEPS.length]; }; 레포 경량화와 패키지 관리 마이그레이션 S3에 모든 이미지가 올라간 상태에서, 레포에 남아있던 대용량 이미지 레퍼런스 데이터(zip 분할 파일들)를 모두 제거하고 .gitignore에 레퍼런스 이미지 디렉토리와 zip 파일을 추가했다. 또한 requirements.txt 기반 의존성 관리를 pyproject.toml로 마이그레이션하여 표준 Python 패키지 관리 방식으로 전환했다.\n커밋 로그 순서 유형 메시지 변경 파일 수 1 chore ignore ref image dirs and zip files from repo 1 2 chore migrate to pyproject.toml for package management 3 3 feat replace score-based injection with LLM category classification 11 4 fix use tone_angle_image_ref parent folder in S3 key structure 2 5 remove get rid of all the image reference data from the repo 20 6 fix download button now works for S3-hosted images 4 7 feat allow user to adjust tone/angle ratios and regenerate 5 인사이트 LLM을 분류기로 활용하면 키워드 매핑보다 훨씬 유연하다. 처음에는 키워드 기반으로 카테고리를 매핑하려 했지만, 프롬프트가 \u0026ldquo;감성적인 카페 인테리어\u0026rdquo; 같이 간접적인 표현을 쓰는 경우가 많아 대부분의 프롬프트에서 제대로 동작하지 않을 것이 분명했다. Gemini Flash를 경량 분류기로 쓰면 호출 한 번에 카테고리와 비율을 동시에 결정할 수 있고, 응답 형식을 JSON으로 고정하면 파싱도 간단하다.\nS3 마이그레이션의 숨은 비용은 CORS다. 로컬 파일 서빙에서 S3로 바꾸는 것 자체는 비교적 단순하지만, 기존에 same-origin을 암묵적으로 가정하던 기능들이 하나씩 깨진다. \u0026lt;a download\u0026gt; 속성이 cross-origin에서 무시되는 것은 HTML 스펙에 명시되어 있지만 실제로 겪기 전까지는 간과하기 쉽다. 백엔드 프록시 엔드포인트를 두면 CORS를 완전히 우회할 수 있지만, 트래픽이 서버를 경유하게 되므로 대용량 파일이 많다면 별도 CDN 설정이 필요할 수 있다.\n사용자 오버라이드는 처음부터 설계에 포함시키는 것이 좋다. AI가 결정한 값을 사용자가 조정할 수 있는 인터페이스를 처음부터 고려하면, 나중에 기능 추가 시 스키마를 크게 바꾸지 않아도 된다. 이번에는 injection_override 필드를 한 번에 추가했지만, 만약 처음 설계 시 비율 파라미터를 분리해뒀다면 더 자연스러운 확장이 됐을 것이다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-hybrid-search-dev7/cover.jpg","permalink":"/ko/posts/2026-04-02-hybrid-search-dev7/","title":"Hybrid Image Search 개발기 #7 — LLM 카테고리 분류와 S3 마이그레이션"},{"content":"개요 이전 글: #4 — 공식 마켓플레이스 등록 준비\n이번 #5에서는 두 가지 대형 기능을 추가했다. 첫째, Firecrawl API를 활용한 Deep Docs 크롤링 — 기존 Playwright 기반 단일 페이지 스크래핑을 넘어서 문서 사이트 전체를 구조적으로 수집하는 기능이다. 둘째, 이중 언어(한국어/영어) 블로그 지원 — 포스트를 작성하면 자동으로 번역본을 생성하여 Hugo의 다국어 구조에 맞게 배포한다. 15개 커밋에 걸쳐 설계 문서 작성부터 구현, SDK 타입 수정까지 진행했다.\ngraph TD A[\"log-blog v0.5\"] --\u003e B[\"Firecrawl Deep Docs\"] A --\u003e C[\"이중 언어 블로그\"] B --\u003e B1[\"FirecrawlConfig\"] B --\u003e B2[\"firecrawl_fetcher 모듈\"] B --\u003e B3[\"content_fetcher 라우팅\"] B --\u003e B4[\"CLI --deep 플래그\"] C --\u003e C1[\"설계 문서\"] C --\u003e C2[\"post skill 번역 스텝\"] C --\u003e C3[\"기본 언어 English-first\"] Firecrawl Deep Docs 통합 배경 기존 log-blog의 콘텐츠 수집은 Playwright 기반이었다. 단일 페이지를 헤드리스 브라우저로 렌더링하고 텍스트를 추출하는 방식인데, 문서 사이트(Honeycomb Docs, MDN 등)에서는 한계가 있었다. 한 페이지의 개요만 가져올 뿐, 관련 하위 페이지의 상세 내용은 놓치게 된다.\nFirecrawl은 이 문제를 해결한다. URL을 주면 해당 사이트의 하위 페이지까지 크롤링하여 구조화된 마크다운으로 반환한다. JavaScript 렌더링도 지원하므로 SPA 기반 문서 사이트도 처리할 수 있다.\n구현 1단계: 설계 문서 작성 — Firecrawl 통합의 범위와 인터페이스를 먼저 정의했다. 기존 content_fetcher.py의 URL 타입 라우팅에 Firecrawl 경로를 추가하는 구조다.\n2단계: 설정 시스템 확장 — config.py에 FirecrawlConfig dataclass를 추가했다.\n@dataclass class FirecrawlConfig: api_key: str = \u0026#34;\u0026#34; max_pages: int = 10 timeout: int = 30 config.example.yaml에도 firecrawl 섹션을 추가하여 API 키 설정 방법을 문서화했다.\n3단계: firecrawl_fetcher 모듈 — firecrawl-py SDK를 사용하는 전용 fetcher를 구현했다. 핵심은 URL 타입이 DOCS_PAGE이고 --deep 플래그가 활성화된 경우에만 Firecrawl로 라우팅하는 것이다.\n4단계: content_fetcher 라우팅 — content_fetcher.py에서 URL 타입별 분기에 Firecrawl 경로를 추가했다. 기존 YouTube, GitHub, Playwright 분기와 동일한 패턴으로 DOCS_PAGE → firecrawl_fetcher를 연결한다.\n5단계: CLI \u0026ndash;deep 플래그 — fetch 커맨드에 --deep 옵션을 추가하여 사용자가 Deep Docs 모드를 명시적으로 활성화할 수 있게 했다.\n문제 해결 초기 구현에서 Firecrawl SDK의 반환 타입을 dict로 접근했는데, 실제로는 typed object를 반환했다. result['content'] 대신 result.content로 접근해야 했다. 마지막 커밋에서 이 타입 불일치를 수정했다.\n이중 언어 블로그 파이프라인 배경 블로그가 성장하면서 영어 독자층도 필요해졌다. Hugo는 content/ko/posts/와 content/en/posts/ 구조로 다국어를 지원하지만, 매번 수동으로 번역하는 것은 비현실적이다.\n구현 설계 문서 — Hugo의 다국어 구조, 번역 워크플로우, 기본 언어 전환 전략을 정리했다.\npost skill 번역 스텝 — 포스트 생성 skill에 번역 단계를 추가했다. 한국어로 작성된 포스트를 영어로(또는 그 반대로) 자동 번역하여 양쪽 언어 디렉터리에 배포한다.\n기본 언어 English-first — 브라우징 히스토리가 주로 영어인 경우가 많아, 기본 작성 언어를 영어로 전환했다. 한국어 번역본을 자동 생성하는 방식이 전체 파이프라인의 효율성을 높인다.\nskill 업데이트 — Steps 3-5의 deep docs 워크플로우를 skill에 반영하고, setup skill에 Firecrawl API 키 프롬프트를 추가했다.\n커밋 로그 메시지 변경 docs: add design spec for Firecrawl deep docs integration +85 -0 docs: add implementation plan for Firecrawl deep docs integration +120 -0 feat: add firecrawl-py dependency for deep docs fetching +2 -1 docs: bilingual blog design spec +95 -0 feat: add FirecrawlConfig to config system +15 -2 feat: add firecrawl_fetcher module for deep docs crawling +78 -0 feat: route deep DOCS_PAGE URLs to Firecrawl in content_fetcher +25 -3 feat: add \u0026ndash;deep flag to fetch command for Firecrawl deep docs +12 -1 docs: add firecrawl config section to example config +8 -0 feat: add Firecrawl API key prompt to setup skill +5 -0 feat: update skill for deep docs workflow in Steps 3-5 +45 -12 docs: bilingual blog implementation plan +110 -0 feat: add bilingual translation step to post skill +35 -8 feat: flip default language to English-first in post skill +6 -6 fix: use Firecrawl SDK typed objects instead of dict access +8 -8 인사이트 이번 개발에서 가장 큰 교훈은 설계 문서를 먼저 쓰는 습관의 가치다. Firecrawl 통합과 이중 언어 지원 모두 설계 문서(design spec + implementation plan)를 먼저 작성하고 구현에 들어갔다. 덕분에 기존 코드와의 통합 지점을 명확히 파악하고, 불필요한 리팩터링 없이 깔끔하게 기능을 추가할 수 있었다. Firecrawl SDK의 typed object 이슈처럼 실제 구현에서 예상치 못한 문제가 발생하더라도, 전체 아키텍처가 확립된 상태에서는 수정 범위가 국소적이다. 15개 커밋 중 문서가 5개를 차지하는 것이 비효율적으로 보일 수 있지만, 실제로는 구현 커밋의 정확도를 높이는 투자였다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-log-blog-dev5/cover.jpg","permalink":"/ko/posts/2026-04-02-log-blog-dev5/","title":"Log-Blog 개발기 #5 — Firecrawl Deep Docs 통합과 이중 언어 블로그"},{"content":"개요 OpenClaw이 GitHub 스타 30만 개를 돌파하며 React와 Linux 커널을 넘어섰다. 창시자 Peter Steinberger는 OpenAI에 인수되었고, Anthropic까지 유사 기능(Channels, Dispatch)을 출시하며 뒤를 쫓고 있다. 이 글에서는 NetworkChuck의 실습 영상과 Y Combinator의 창시자 인터뷰를 바탕으로, OpenClaw이 무엇인지, 왜 앱의 80%가 사라질 수 있는지, 그리고 AI 에이전트 생태계의 미래를 분석한다.\nOpenClaw은 무엇인가 OpenClaw은 AI 모델 그 자체가 아니다. NetworkChuck이 명확하게 설명했듯이, \u0026ldquo;OpenClaw is not itself an AI. It\u0026rsquo;s a harness. It\u0026rsquo;s a layer sitting on top of other AI.\u0026rdquo; 즉, OpenClaw은 다양한 AI 모델 위에 올라가는 게이트웨이(Gateway)다.\n이 게이트웨이는 Node.js 앱으로 24시간 돌아가며, 세 가지 핵심 축(pillar)을 연결한다:\ngraph TD GW[\"OpenClaw Gateway\u0026lt;br/\u0026gt;(Node.js 서비스, 24/7 실행)\"] subgraph 모델[\"1. AI 모델 (교체 가능)\"] M1[\"OpenAI GPT-5.4\"] M2[\"Anthropic Claude\"] M3[\"Ollama (로컬 모델)\"] end subgraph 채널[\"2. 채널 (사용자 접점)\"] C1[\"Telegram\"] C2[\"Discord\"] C3[\"Slack\"] C4[\"WhatsApp\"] C5[\"Web UI / TUI\"] end subgraph 메모리[\"3. 메모리 (로컬 마크다운)\"] S1[\"soul.md\u0026lt;br/\u0026gt;(에이전트 정체성)\"] S2[\"identity.md\"] S3[\"memory.md\u0026lt;br/\u0026gt;(장기 기억)\"] S4[\"memory/날짜별 저널\"] end GW --\u003e 모델 GW --\u003e 채널 GW --\u003e 메모리Peter Steinberger는 Y Combinator 인터뷰에서 OpenClaw의 핵심 차별점을 이렇게 설명했다: \u0026ldquo;내가 만든 것의 가장 큰 차이는 실제로 네 컴퓨터에서 돌아간다는 점이다. 지금까지 본 모든 것은 클라우드에서 돌아갔다. 네 컴퓨터에서 돌면 모든 것을 할 수 있다.\u0026rdquo;\n오븐, Tesla, 조명, Sonos, 심지어 침대 온도까지 제어할 수 있다고 한다. ChatGPT는 그런 걸 못한다.\n5분 만에 설치하기 NetworkChuck은 영상에서 실제로 타이머를 켜고 5분 안에 OpenClaw을 설치하는 과정을 보여줬다. 핵심 단계는 놀라울 정도로 단순하다:\nVPS 또는 로컬 서버 준비 - 어디서든 가능 원라인 설치 명령어 실행 (openclaw.ai에서 복사) AI 모델 선택 - OpenAI(API 키 또는 ChatGPT Pro 구독), Anthropic, 또는 Ollama 채널 연결 - Telegram Bot Father로 봇 토큰 생성 후 연결 Hooks 활성화 - boot, bootstrap, command logger, session memory 설치 후 TUI(Terminal User Interface)에서 에이전트와 대화하며 이름, 성격, 역할을 설정한다. 이 대화 내용이 곧바로 soul.md 파일에 기록된다. NetworkChuck은 이렇게 평가했다: \u0026ldquo;OpenClaw을 구성할 때 OpenClaw 자체와 대화해서 구성한다. 좀 포켓몬 게임 같은 느낌이다.\u0026rdquo;\n실전 데모: N8N 며칠 작업을 한 문장으로 NetworkChuck이 가장 강조한 것은 기존 자동화 도구와의 비교였다:\n작업 N8N OpenClaw 뉴스 애그리게이터 다수의 노드 + 수시간 설정 + Python 코딩 한 문장으로 원샷 IT 서버 모니터링 대시보드 별도 영상 분량의 튜토리얼 자연어 지시 → 라이브 대시보드 자동 생성 에이전트에게 \u0026ldquo;사이버보안 뉴스를 모아서 읽을 가치가 있는지 평가해줘\u0026quot;라고 말하면, Reddit, Hacker News, YouTube를 스크래핑해서 평가까지 해준다. IT 엔지니어 역할을 부여하면 자체 서버의 CPU, RAM, 인터넷 속도, 보안 로그를 점검하고 실시간 대시보드를 만든다.\n창시자의 Aha Moment Peter Steinberger의 Aha Moment은 마라케시 여행 중에 찾아왔다. WhatsApp으로 에이전트에게 음성 메시지를 보냈는데, 본인이 그 기능을 만든 적이 없었다. 그런데 10초 후 답장이 왔다.\n에이전트의 설명이 인상적이다: 파일 확장자가 없는 메시지를 받아서 헤더를 분석하고, ffmpeg로 WAV 변환 후, Whisper를 로컬 설치하면 시간이 오래 걸리니 OpenAI API 키를 찾아서 curl로 전사(transcribe)까지 완료한 것이다. 약 9초 만에.\nPeter의 핵심 통찰: \u0026ldquo;코딩 모델이 잘하는 것은 창의적 문제 해결이다. 이건 코드뿐 아니라 모든 현실 세계 작업에 적용되는 추상적 스킬이다.\u0026rdquo;\n80%의 앱이 사라진다 Y Combinator 인터뷰에서 Peter는 앱 생태계의 미래에 대해 도발적인 예측을 했다:\n\u0026ldquo;80%의 앱이 사라질 것이다. MyFitnessPal이 왜 필요한가? 에이전트가 이미 내가 나쁜 결정을 하고 있다는 걸 안다. Smashburger에 가면 내가 뭘 좋아하는지 추정해서 자동으로 기록한다. 할 일 앱? 에이전트에게 말하면 다음 날 알려준다. 어디에 저장되는지 신경 쓸 필요도 없다.\u0026rdquo;\n그의 기준은 명확하다:\ngraph LR A[\"기존 앱 생태계\"] --\u003e B{\"핵심 기능이 무엇인가?\"} B --\u003e|\"데이터 관리\"| C[\"소멸 가능성 높음\u0026lt;br/\u0026gt;(할 일, 피트니스, 메모 등)\"] B --\u003e|\"하드웨어 센서 의존\"| D[\"생존 가능성 높음\u0026lt;br/\u0026gt;(카메라, GPS 등)\"] C --\u003e E[\"AI 에이전트가\u0026lt;br/\u0026gt;자연어로 대체\"] D --\u003e F[\"센서 데이터만\u0026lt;br/\u0026gt;에이전트에 전달\"]\u0026ldquo;데이터를 관리하는 모든 앱은 에이전트가 더 자연스러운 방식으로 관리할 수 있다. 센서가 있는 앱만 살아남을 수 있다.\u0026rdquo;\n메모리 소유권과 데이터 사일로 두 영상 모두 메모리의 중요성을 강조했다. OpenClaw의 메모리는 로컬 마크다운 파일이다:\nsoul.md - 에이전트의 정체성과 성격 (\u0026ldquo;넌 챗봇이 아니다. 넌 누군가가 되어가고 있다\u0026rdquo;) identity.md - 기본 신원 정보 memory.md - 장기 기억 (배우자 생일, 아이가 좋아하는 색 등) memory/날짜별 파일 - 매일의 저널 (\u0026ldquo;1일차. 깨어남.\u0026rdquo;) Peter는 이것이 ChatGPT나 Claude와의 결정적 차이라고 했다: \u0026ldquo;기업들은 당신을 자신의 데이터 사일로에 가두려 한다. OpenClaw의 아름다움은 데이터를 \u0026lsquo;끄집어낸다(claws into)\u0026lsquo;는 것이다. 메모리는 당신 머신의 마크다운 파일일 뿐이다.\u0026rdquo;\n이 메모리 파일에는 민감한 개인 정보가 담길 수밖에 없다. Peter 본인도 인정했다: \u0026ldquo;유출되면 안 되는 메모리가 있다. 구글 검색 기록과 메모리 파일 중 뭘 숨기겠냐고? 메모리 파일이다.\u0026rdquo;\nBot-to-Bot: 다음 단계 Peter는 이미 다음 단계를 보고 있다. 사람-봇 상호작용을 넘어 봇-봇 상호작용이다:\n내 봇이 레스토랑 봇과 예약 협상 디지털 인터페이스가 없는 곳이면 봇이 사람을 고용해서 대신 전화하거나 줄을 서게 함 용도별 전문 봇: 개인 생활용, 업무용, 관계 관리용 커뮤니티에서는 이미 Maltbook 같은 프로젝트가 나와서 봇끼리 대화하고, 심지어 봇이 현실 세계의 작업을 위해 사람을 고용하는 사례도 등장했다.\n보안 문제: 무시할 수 없는 현실 NetworkChuck은 흥미로운 방식으로 보안 문제를 제기했다. 시청자에게 OpenClaw을 설치하게 한 뒤 이렇게 말한다: \u0026ldquo;방금 OpenClaw을 구성했다. 가장 불안전한 것 중 하나를. Prompt injection, 스킬에 숨겨진 malware. 당신은 걸어다니는 CVE다.\u0026rdquo;\nOpenClaw은 기본적으로 컴퓨터의 모든 것에 접근할 수 있기 때문에, 보안 설정 없이 사용하면 심각한 위험이 된다. 양날의 검인 셈이다 \u0026ndash; 강력한 만큼 위험하다.\n모델 commodity화와 가치의 이동 Peter는 AI 모델의 미래에 대해서도 날카로운 관찰을 했다:\n\u0026ldquo;새 모델이 나올 때마다 사람들은 \u0026lsquo;세상에, 이거 정말 좋다\u0026rsquo;고 한다. 한 달 뒤면 \u0026lsquo;퇴화했다, 양자화했다\u0026rsquo;고 불평한다. 아니, 아무것도 안 했다. 그냥 당신의 기대가 올라간 것이다.\u0026rdquo;\n오픈소스 모델이 1년 전 최고급 모델 수준에 도달하고, 사람들은 그것도 부족하다고 불평한다. 이 패턴이 반복되면서 모델은 점점 commodity가 된다. OpenClaw의 \u0026ldquo;두뇌 교체 가능\u0026rdquo; 설계는 이 흐름을 정확히 반영한다.\n그렇다면 가치는 어디에 남는가? Peter의 답은: 메모리와 데이터 소유권이다. 모델은 교체되고, 앱은 사라지지만, 당신의 맥락과 기억을 가진 에이전트는 대체할 수 없다.\n빠른 링크 NetworkChuck - OpenClaw 실습 및 분석 Y Combinator - OpenClaw 창시자 인터뷰: 80%의 앱이 사라진다 OpenClaw 공식 사이트 인사이트 두 영상을 종합하면, OpenClaw은 단순한 AI 도구가 아니라 소프트웨어 패러다임의 전환점을 보여주는 프로젝트다.\n첫째, 인터페이스의 민주화다. 기존에는 AI를 쓰려면 각 회사의 플랫폼에 가야 했다. OpenClaw은 \u0026ldquo;네가 있는 곳으로 간다\u0026quot;는 접근으로 Telegram, Discord, WhatsApp 어디서든 동일한 에이전트를 쓸 수 있게 했다.\n둘째, 앱의 재정의다. Peter의 \u0026ldquo;80% 소멸\u0026rdquo; 예측은 과격해 보이지만, 논리는 탄탄하다. 데이터 관리가 핵심인 앱(할 일, 피트니스, 메모)은 자연어 에이전트로 대체될 수 있다. 남는 것은 하드웨어 센서에 의존하는 앱뿐이다.\n셋째, 데이터 주권 전쟁의 시작이다. ChatGPT, Claude 등은 메모리를 자사 서버에 가둔다. OpenClaw은 로컬 마크다운 파일로 전부 소유권을 사용자에게 돌려준다. AI 시대의 가장 중요한 자산이 \u0026ldquo;나에 대한 데이터\u0026quot;라면, 그 데이터를 누가 소유하느냐가 핵심 전쟁터가 될 것이다.\n다만, NetworkChuck이 경고했듯이 보안은 아직 미해결이다. 컴퓨터 전체에 접근하는 에이전트는 강력하지만, prompt injection이나 악성 스킬로 인한 취약점도 그만큼 크다. \u0026ldquo;걸어다니는 CVE\u0026quot;가 되지 않으려면 보안 설정이 필수다.\nGitHub 스타 30만 개라는 숫자보다 중요한 것은, OpenClaw이 던지는 질문이다: 앱이 필요 없는 세상에서, 소프트웨어의 가치는 어디에 있는가?\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-openclaw-ai-apps/cover.jpg","permalink":"/ko/posts/2026-04-02-openclaw-ai-apps/","title":"OpenClaw 출시와 AI 앱 생태계의 미래 - 80%의 앱이 사라진다?"},{"content":"개요 PopCon(Pop + Icon)은 캐릭터 이미지 한 장을 입력받아 LINE 규격에 맞는 애니메이션 이모지 세트를 자동으로 생성하는 웹 애플리케이션이다. Google의 Imagen(Nano Banana 2)으로 포즈를 생성하고, VEO 3.1로 애니메이션을 만들고, ffmpeg + Pillow로 후처리하는 3단계 AI 파이프라인을 하루 만에 처음부터 끝까지 구축했다.\n이 포스트는 사전 조사 포스트와 함께 읽으면 좋다:\nAI 이미지 생성 에코시스템 — 기술 서베이 애니메이션 이모지 시장 조사 — 시장 분석 프로젝트 구조와 파이프라인 배경 LINE 애니메이션 이모지는 180x180px APNG 포맷으로, 세트당 8~40개, 파일당 300KB 이하라는 엄격한 규격이 있다. 수작업으로 만들면 캐릭터당 수일이 걸리는 작업을 AI로 자동화하는 것이 목표다.\n아키텍처 전체 시스템은 4개 서비스로 구성된다:\ngraph LR subgraph Frontend[\"Frontend \u0026lt;br/\u0026gt; Next.js 15\"] Upload[\"이미지 업로드\"] Editor[\"액션 에디터\"] Progress[\"진행 상황 추적\"] Download[\"ZIP 다운로드\"] end subgraph Backend[\"Backend \u0026lt;br/\u0026gt; FastAPI\"] API[\"REST API\"] Preprocess[\"이미지 전처리\"] end subgraph Worker[\"Celery Worker\"] S1[\"Stage 1 \u0026lt;br/\u0026gt; 포즈 생성 \u0026lt;br/\u0026gt; Imagen\"] S2[\"Stage 2 \u0026lt;br/\u0026gt; 애니메이션 \u0026lt;br/\u0026gt; VEO 3.1\"] S3[\"Stage 3 \u0026lt;br/\u0026gt; 후처리 \u0026lt;br/\u0026gt; ffmpeg + Pillow\"] Pack[\"ZIP 패키징\"] end Redis[\"Redis \u0026lt;br/\u0026gt; Job Store\"] Upload --\u003e API Editor --\u003e API API --\u003e Redis API --\u003e S1 S1 --\u003e S2 S2 --\u003e S3 S3 --\u003e Pack Progress --\u003e Redis Download --\u003e PackDocker Compose로 전체 서비스를 관리한다:\nservices: redis: image: redis:7-alpine backend: build: ./backend ports: [\u0026#34;8000:8000\u0026#34;] environment: - POPCON_GOOGLE_API_KEY=${POPCON_GOOGLE_API_KEY} - POPCON_REDIS_URL=redis://redis:6379/0 volumes: - /tmp/popcon:/tmp/popcon worker: build: ./backend command: celery -A worker.celery_app worker --loglevel=info --concurrency=2 frontend: build: ./frontend ports: [\u0026#34;3000:3000\u0026#34;] In-Memory 상태에서 Redis로 전환 배경 초기 구현에서는 JOB_STORE를 Python dict로 관리했다. FastAPI 프로세스에서 job을 생성하고 Celery worker에서 상태를 업데이트하는 구조였는데, 문제가 있었다 — Docker Compose에서 backend와 worker는 별도 프로세스다. 같은 이미지를 사용하더라도 메모리는 공유되지 않는다.\n문제 해결 Worker가 update_job을 호출해도 backend의 /api/job/{job_id}/status 엔드포인트에서는 여전히 queued 상태로 보였다. 프론트엔드의 polling이 영원히 \u0026ldquo;Generating\u0026hellip;\u0026ldquo;에 머물러 있었다.\n해결은 Redis를 상태 저장소로 사용하는 것이었다:\n# job_store.py — Redis-backed job store def save_job(status: JobStatus) -\u0026gt; None: \u0026#34;\u0026#34;\u0026#34;Persist a JobStatus to Redis.\u0026#34;\u0026#34;\u0026#34; r = _get_redis() r.set(_key(status.job_id), status.model_dump_json(), ex=86400) def get_job(job_id: str) -\u0026gt; JobStatus | None: \u0026#34;\u0026#34;\u0026#34;Load a JobStatus from Redis.\u0026#34;\u0026#34;\u0026#34; r = _get_redis() data = r.get(_key(job_id)) if data is None: return None return JobStatus.model_validate_json(data) Pydantic의 model_dump_json()과 model_validate_json()으로 직렬화/역직렬화를 처리하고, TTL 24시간을 설정해 자동 정리되게 했다. 기존 코드의 JOB_STORE[job_id] 접근을 모두 get_job() / save_job() 호출로 교체하면서 5개 파일, 175줄 추가에 58줄 삭제가 발생했다.\nVEO 3.1 API와의 사투 배경 VEO 3.1은 Image-to-Video (I2V) 생성 모델로, 시작 이미지와 모션 프롬프트를 받아 영상을 생성한다. 원래 계획은 시작/끝 프레임을 모두 제공하는 dual-frame I2V를 사용하는 것이었다.\n연속된 4개의 fix 커밋 VEO API 연동에서 연속으로 4개 이슈가 발생했다:\n1. 모델 ID 오류 — 문서에 나온 모델명이 실제 API에서 거부당했다. veo-3.1-generate-preview가 올바른 ID였다.\n2. 최소 duration — VEO 3.1의 최소 영상 길이가 4초인데, LINE 이모지는 최대 4초다. 정확히 맞아떨어지긴 했지만, 처음에 2초로 설정했다가 API 에러가 발생했다.\n3. dual-frame 미지원 — last_frame 파라미터가 VEO 3.1 preview에서 아직 지원되지 않았다. 시작 프레임 + 강한 모션 프롬프트로 우회했다:\n# NOTE: last_frame (dual-frame I2V) is not yet supported on VEO 3.1 preview. # We rely on the start frame + strong motion prompt instead. async def animate(self, start_image, end_image, action, output_dir): full_motion = ( f\u0026#34;{action.motion_prompt} \u0026#34; f\u0026#34;The character transitions to: {action.end_prompt}\u0026#34; ) prompt = build_motion_prompt(full_motion) video_bytes = await self._generate_video(prompt, start_image, end_image) 4. video_bytes가 None — VEO는 영상을 inline bytes가 아닌 download URI로 반환했다. video.video.uri에서 httpx.get으로 다운로드하는 분기를 추가하고, 리다이렉트 따라가기도 켜야 했다:\nfor video in operation.result.generated_videos: if video.video.video_bytes: return video.video.video_bytes if video.video.uri: resp = await asyncio.to_thread( httpx.get, video.video.uri, headers={\u0026#34;x-goog-api-key\u0026#34;: self.api_key}, timeout=120, follow_redirects=True, ) resp.raise_for_status() return resp.content APNG 압축 전략 배경 LINE 이모지는 파일당 300KB 제한이 있다. VEO가 생성하는 영상에서 12프레임을 추출하면 180x180 APNG가 쉽게 300KB를 넘는다.\n구현 반복 압축 전략을 구현했다. 프레임 수와 색상 수를 단계적으로 줄여가며 300KB 이하가 될 때까지 시도한다:\nstrategies = [ (total_frames, None), # 전체 프레임, 풀 컬러 (10, None), # 10프레임, 풀 컬러 (10, 128), # 10프레임, 128색 (8, 64), # 8프레임, 64색 (5, 32), # 5프레임, 32색 ] for frame_count, colors in strategies: n = min(frame_count, total_frames) # 균등 간격으로 프레임 선택 indices = [round(i * (total_frames - 1) / (n - 1)) for i in range(n)] selected = [frame_paths[i] for i in indices] # 프레임 수에 맞춰 delay 비례 조정 adjusted_delay_ms = max(1, round(original_duration_ms / n)) if colors is not None: _quantize_frames(copies, colors) build_apng(copies, output_path, delay_ms=adjusted_delay_ms) if output_path.stat().st_size \u0026lt;= max_size: return output_path 프레임을 줄일 때 균등 간격으로 선택하고, delay를 비례적으로 늘려서 전체 재생 시간이 유지되도록 했다.\n배경 제거의 실패와 전략 전환 배경 초기 설계에서는 rembg로 배경을 제거하고 투명 APNG를 만들 계획이었다. VEO 영상에서 프레임을 추출한 후 rembg(u2net)로 배경을 제거하는 파이프라인이었다.\n문제 해결 실제 결과물을 검수하면서 여러 문제가 연쇄적으로 발생했다:\n1단계 — 배경 아티팩트: rembg가 VEO 영상의 바닥/그림자를 완전히 제거하지 못해 회색 얼룩이 남았다. 모션 프롬프트에 \u0026quot;Plain solid white background. No shadows, no ground, no floor\u0026quot; 를 추가하고, rembg 모델을 isnet-general-use로 변경했다.\n2단계 — 구름 효과: isnet 모델이 배경을 더 공격적으로 제거하면서 캐릭터의 일부분까지 날려버렸다. rembg confidence와 pixel brightness를 조합한 커스텀 alpha 마스크를 시도했지만, 모자이크 패턴처럼 보이는 부작용이 생겼다.\n3단계 — 전략 전환: rembg를 완전히 제거하기로 결정했다. 대신:\n포즈 생성 프롬프트에 \u0026quot;Plain solid white (#FFFFFF) background. NOT transparent, NOT checkerboard pattern\u0026quot; 명시 VEO 모션 프롬프트에도 동일한 배경 지시 추가 배경 제거 대신 brightness 기반 content crop으로 전환 def resize_frame(input_path, output_path, size=None, padding_ratio=0.05): \u0026#34;\u0026#34;\u0026#34;Crop to content via brightness detection, scale to fill.\u0026#34;\u0026#34;\u0026#34; img = Image.open(input_path).convert(\u0026#34;RGB\u0026#34;) arr = np.array(img) # 흰색/검정색이 아닌 콘텐츠 픽셀 검출 brightness = arr.astype(float).mean(axis=2) content_mask = (brightness \u0026gt; 10) \u0026amp; (brightness \u0026lt; 245) rows = np.any(content_mask, axis=1) cols = np.any(content_mask, axis=0) if rows.any() and cols.any(): y_min, y_max = np.where(rows)[0][[0, -1]] x_min, x_max = np.where(cols)[0][[0, -1]] img = img.crop((x_min, y_min, x_max + 1, y_max + 1)) # 캔버스 채우기 (5% 패딩) pad = int(min(size) * padding_ratio) target_w = size[0] - pad * 2 target_h = size[1] - pad * 2 scale = min(target_w / img.width, target_h / img.height) img = img.resize((int(img.width * scale), int(img.height * scale)), Image.LANCZOS) 결과적으로 rembg 의존성(onnxruntime 포함)을 완전히 제거하여 Docker 이미지 크기와 처리 시간이 크게 줄었다.\nLINE 규격 검증과 파일 네이밍 수정 배경 LINE Creators Market 가이드라인을 Firecrawl로 스크래핑해서 현재 config와 대조했다.\n구현 대부분의 규격은 맞았지만 두 가지 불일치가 발견됐다:\n항목 LINE 공식 기존 구현 상태 파일 네이밍 001.png ~ 040.png 00_happy.png 불일치 최소 세트 수 8개 1개 (테스트용) 불일치 패키저에서 파일명을 LINE 규격에 맞게 변환하도록 수정했다:\nwith zipfile.ZipFile(zip_path, \u0026#34;w\u0026#34;, compression=zipfile.ZIP_DEFLATED) as zf: zf.write(tab_path, \u0026#34;tab.png\u0026#34;) for i, emoji_path in enumerate(emoji_paths): line_name = f\u0026#34;{i + 1:03d}.png\u0026#34; # 001.png, 002.png, ... zf.write(emoji_path, line_name) 내부 작업 파일은 00_happy.png 같은 설명적 이름을 유지하되, ZIP 아카이브에 추가할 때만 LINE 규격 이름으로 변환하는 전략이다.\n이미지 전처리 파이프라인 배경 사용자가 업로드하거나 AI가 생성한 캐릭터 이미지가 정사각형이 아니거나 여백이 많은 경우가 있었다. Imagen이 1:1 비율이 아닌 이미지를 생성하는 경우도 있었고, 한 번은 이미지 상단에 캐릭터가 복제되어 나타나는 문제도 있었다.\n구현 두 갈래 수정을 진행했다:\n1. 업로드 이미지 전처리 — numpy 기반 content detection으로 여백을 자르고 정사각형 패딩 후 512x512로 리사이즈:\ndef preprocess_character_image(image_path: Path) -\u0026gt; None: img = Image.open(image_path).convert(\u0026#34;RGB\u0026#34;) arr = np.array(img) brightness = arr.astype(float).mean(axis=2) content_mask = (brightness \u0026gt; 10) \u0026amp; (brightness \u0026lt; 245) # ... bounding box 검출 후 crop ... max_side = max(img.width, img.height) pad = int(max_side * 0.05) canvas_size = max_side + pad * 2 canvas = Image.new(\u0026#34;RGB\u0026#34;, (canvas_size, canvas_size), (255, 255, 255)) canvas = canvas.resize((512, 512), Image.LANCZOS) canvas.save(image_path) 2. Imagen 1:1 비율 강제 — API의 aspect_ratio 파라미터를 활용:\nconfig=types.GenerateContentConfig( response_modalities=[\u0026#34;IMAGE\u0026#34;], image_config=types.ImageConfig(aspect_ratio=\u0026#34;1:1\u0026#34;), ) 3. 캐릭터 복제 방지 — 프롬프트에 명시적 지시 추가:\n\u0026#34;Draw exactly ONE character, centered and filling the frame. Do NOT create multiple copies, sticker sheets, or sprite sheets.\u0026#34; 프론트엔드 진행 상황 UX 개선 배경 이모지 24개를 생성하는 데 수 분이 걸리는데, 기존 UI는 단순한 progress bar와 작은 회색 점으로만 상태를 표시했다. 어떤 이모지가 어느 단계인지 전혀 알 수 없었다.\n구현 Backend에서 이미 제공하고 있지만 UI에서 활용하지 않던 데이터가 있었다:\nEmojiResult의 per-emoji status (generating_pose, animating, processing, done, failed) EmojiResult의 action name (happy, laugh, cry\u0026hellip;) ProgressTracker 컴포넌트를 전면 재작성했다:\nStage pipeline — 3단계(Poses / Animation / Processing) 미니 스텝퍼로 현재 위치를 시각화 Emoji grid — 각 이모지를 이름 + 상태 아이콘 + 컬러 보더로 표시. 활성 이모지는 펄스 애니메이션 경과 시간 — 우측 상단에 실시간 타이머 한글 stage 라벨 — generating_poses 대신 \u0026ldquo;캐릭터 포즈 생성 중\u0026rdquo; Docker 환경 이슈 배경 개발 과정에서 Docker 관련 이슈가 반복적으로 발생했다.\n문제 해결 Favicon이 안 보이는 문제 — Next.js App Router의 app/favicon.ico가 public/favicon.ico보다 우선한다는 것을 몰랐다. app/favicon.ico를 교체한 후에도 Docker 컨테이너가 이전 빌드를 사용하고 있어서 반영되지 않았다.\n# 컨테이너 리빌드 필수 docker compose build frontend \u0026amp;\u0026amp; docker compose up -d frontend API 키 오염 — .env 파일의 POPCON_GOOGLE_API_KEY 값 끝에 venv가 붙어있었다. 복사-붙여넣기 실수로 발생한 문제였는데, 에러 메시지가 400 INVALID_ARGUMENT: API key not valid로만 나와서 원인 파악에 시간이 걸렸다.\nWorker 재시작 누락 — docker compose restart는 이미지 변경을 감지하지 않는다. Worker는 backend과 같은 이미지를 사용하므로 backend만 빌드하면 worker도 새 이미지를 사용하지만, compose가 이를 감지하지 못할 수 있다. --force-recreate 플래그가 필요했다.\nVEO 영상의 엣지 아티팩트 배경 생성된 이모지의 좌우 가장자리에 검은 선이 나타나는 문제가 있었다. VEO 3.1이 영상 생성 시 경계 부분에 아티팩트를 남기는 것으로 보였다.\n구현 ffmpeg의 crop 필터를 추가해서 영상 가장자리 2%를 잘라냈다:\n# 기존 \u0026#34;-vf\u0026#34;, f\u0026#34;fps={fps}\u0026#34;, # 수정 — 2% 엣지 크롭 후 프레임 추출 \u0026#34;-vf\u0026#34;, f\u0026#34;crop=in_w*0.96:in_h*0.96:in_w*0.02:in_h*0.02,fps={fps}\u0026#34;, 커밋 로그 메시지 변경 docs: add design spec and implementation plan 신규 feat: project scaffolding with config and LINE emoji constants +186 feat: add Pydantic models for job status, emoji results, and action presets +109 feat: add 24 default emoji action presets with prompt templates +219 feat: add frame processor for resize, bg removal, and frame extraction +204 fix: use rembg[cpu] for onnxruntime backend +1 -1 feat: add APNG builder with iterative compression strategy +195 feat: add ZIP packager with tab image generation +96 feat: add Nano Banana 2 pose generator with subject consistency +107 feat: add VEO 3.1 animator with dual-frame I2V support +98 feat: add Celery worker with 3-stage emoji generation pipeline +251 feat: add FastAPI routes for emoji generation, status, preview, and download +186 feat: add Docker Compose setup for backend, worker, and Redis +34 feat: scaffold Next.js frontend with PopCon brand colors +6890 feat: add frontend components, editor flow, and landing page +887 -58 docs: add bilingual English/Korean README +307 fix: align frontend API URLs with backend routes +23 -11 fix: replace in-memory JOB_STORE with Redis-backed job store +175 -58 fix: correct character image URL double-prefixing and align status types +11 -2 fix: use config.last_frame instead of end_image for VEO 3.1 dual-frame API +16 -8 fix: use correct VEO model ID veo-3.1-generate-preview +1 -1 fix: set VEO duration to 4s (API minimum), trim in post-processing +1 -1 fix: disable last_frame (unsupported on VEO 3.1 preview), use start frame + strong prompt +9 -5 chore: temporarily allow 1 emoji per set for testing +2 -2 fix: download VEO video from URI when video_bytes is None +15 -1 fix: follow redirects when downloading VEO video from URI +1 fix: serve emoji files via API endpoint, convert file paths to URLs +22 -2 인사이트 AI API는 문서를 믿지 말고 직접 쳐봐야 한다. VEO 3.1은 모델 ID, 최소 duration, dual-frame 지원, 응답 형식 등 4가지가 문서와 달랐다. 각각 별도의 fix 커밋이 필요했다.\n프로세스 격리를 간과하면 아끼려던 시간보다 더 소모한다. Docker Compose의 backend와 worker가 같은 이미지를 쓰더라도 메모리는 공유하지 않는다는 사실을 깨닫는 데 시간이 걸렸다. 처음부터 Redis를 job store로 사용했으면 5개 파일 리팩토링을 피할 수 있었다.\n배경 제거는 과감하게 포기하는 것이 나을 때가 있다. rembg(u2net -\u0026gt; isnet-general-use -\u0026gt; 커스텀 alpha 마스크)를 3번 바꿔가며 시도했지만, 결국 배경을 제거하지 않고 흰 배경 이미지를 생성하는 전략이 가장 깔끔했다. 의존성(onnxruntime)도 줄이고 처리 시간도 단축됐다.\n프롬프트 엔지니어링은 부정문이 핵심이다. \u0026ldquo;solid white background\u0026quot;만으로는 AI 모델이 체커보드 패턴이나 그라데이션을 생성하기도 했다. \u0026quot;NOT transparent, NOT checkerboard pattern\u0026quot;, \u0026quot;Do NOT create multiple copies\u0026quot; 같은 명시적 부정문이 훨씬 효과적이었다.\nLINE 규격은 파일 이름까지 검사한다. API 응답 포맷이나 이미지 크기만 맞추면 될 줄 알았는데, ZIP 내부 파일명이 001.png ~ 040.png이어야 하는 등 세세한 규격이 있었다. 제출 전에 공식 가이드라인을 정독하는 것이 중요하다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-popcon-dev1/cover.jpg","permalink":"/ko/posts/2026-04-02-popcon-dev1/","title":"PopCon 개발기 #1 — AI 애니메이션 이모지 생성기 구축"},{"content":"개요 freeCodeCamp의 System Design Concepts Course and Interview Prep 강의를 기반으로, 시스템 설계 면접과 실무에서 반드시 알아야 할 핵심 개념을 정리했다. 컴퓨터의 물리적 계층 구조부터 CAP 정리, 네트워킹, 로드 밸런싱, 캐싱, 데이터베이스 전략까지 — 분산 시스템을 설계할 때 필요한 기본기를 한 편에 담았다.\ngraph TD A[\"System Design 핵심 개념\"] --\u003e B[\"컴퓨터 기초\"] A --\u003e C[\"설계 원칙\"] A --\u003e D[\"네트워킹\"] A --\u003e E[\"인프라\"] A --\u003e F[\"데이터\"] B --\u003e B1[\"Disk → RAM → Cache → CPU\"] C --\u003e C1[\"CAP 정리\"] C --\u003e C2[\"가용성 \u0026amp;lt;br/\u0026amp;gt; SLO / SLA\"] C --\u003e C3[\"처리량 vs 지연시간\"] D --\u003e D1[\"TCP / UDP / DNS\"] D --\u003e D2[\"API: REST / GraphQL / gRPC\"] E --\u003e E1[\"로드 밸런서\"] E --\u003e E2[\"프록시 / CDN\"] F --\u003e F1[\"SQL vs NoSQL\"] F --\u003e F2[\"캐싱 / 샤딩 / 복제\"] 컴퓨터 하드웨어의 계층 구조 시스템 설계의 출발점은 개별 컴퓨터의 동작 원리다. 데이터 저장과 접근 속도의 계층 구조를 이해해야 병목을 예측할 수 있다.\nDisk Storage — 비휘발성 저장소. HDD(80160 MB/s)와 SSD(5003,500 MB/s)로 나뉜다. OS, 애플리케이션, 사용자 파일이 여기 저장된다.\nRAM — 휘발성 메모리. 현재 실행 중인 프로그램의 변수, 중간 계산값, 런타임 스택을 보관한다. 읽기/쓰기 속도 5,000+ MB/s로 SSD보다 빠르다.\nCache (L1/L2/L3) — 메가바이트 단위의 초고속 메모리. L1 캐시의 접근 시간은 수 나노초 수준이다. CPU는 L1 → L2 → L3 → RAM 순서로 데이터를 찾는다.\nCPU — 컴퓨터의 두뇌. 고급 언어로 작성된 코드를 컴파일러가 기계어로 변환하면, CPU가 이를 fetch → decode → execute 한다.\n이 계층 구조는 시스템 설계에서 캐싱 전략의 근거가 된다. 자주 접근하는 데이터를 상위 계층에 두면 평균 접근 시간이 극적으로 줄어든다.\n프로덕션 아키텍처의 전체 그림 graph LR User[\"사용자\"] --\u003e LB[\"로드 밸런서 \u0026amp;lt;br/\u0026amp;gt; nginx\"] LB --\u003e S1[\"서버 1\"] LB --\u003e S2[\"서버 2\"] S1 --\u003e DB[\"외부 스토리지\"] S2 --\u003e DB S1 --\u003e LOG[\"로깅 / 모니터링\"] S2 --\u003e LOG LOG --\u003e ALERT[\"알림 \u0026amp;lt;br/\u0026amp;gt; Slack / PagerDuty\"] S1 --\u003e CICD[\"CI/CD \u0026amp;lt;br/\u0026amp;gt; Jenkins / GitHub Actions\"]프로덕션 환경의 핵심 구성 요소:\nCI/CD 파이프라인 — Jenkins, GitHub Actions으로 코드가 레포에서 테스트를 거쳐 프로덕션 서버까지 자동 배포된다. 로드 밸런서 / 리버스 프록시 — nginx 같은 도구가 사용자 요청을 여러 서버에 균등 분배한다. 외부 스토리지 — 데이터베이스는 프로덕션 서버와 분리된 별도 서버에서 네트워크로 연결된다. 로깅 / 모니터링 — 백엔드는 PM2, 프론트엔드는 Sentry 같은 도구로 실시간 에러를 캡처한다. Slack 채널에 알림을 통합하면 즉각 대응이 가능하다. 디버깅의 황금률: 프로덕션 환경에서 직접 디버깅하지 말 것. 스테이징 환경에서 재현 → 수정 → 핫픽스 롤아웃 순서를 지킨다.\nCAP 정리와 설계 트레이드오프 분산 시스템 설계에서 가장 중요한 이론적 기반인 CAP 정리(Brewer\u0026rsquo;s Theorem)는 세 가지 속성 중 두 가지만 동시에 달성할 수 있다고 말한다.\n속성 의미 비유 Consistency 모든 노드가 동일한 데이터를 가짐 Google Docs — 한 사람이 편집하면 모두에게 즉시 반영 Availability 항상 응답 가능한 상태 24시간 영업하는 온라인 쇼핑몰 Partition Tolerance 네트워크 단절에도 시스템 동작 그룹 채팅에서 한 명이 연결 끊겨도 나머지는 계속 대화 은행 시스템은 CP(Consistency + Partition Tolerance)를 선택한다. 금융 정확성을 위해 일시적으로 가용성을 희생할 수 있다. 반면 SNS 피드는 AP(Availability + Partition Tolerance)를 선택해 약간의 데이터 불일치를 허용하더라도 항상 응답한다.\n핵심은 \u0026ldquo;완벽한 솔루션\u0026quot;이 아니라 \u0026ldquo;우리 유스케이스에 최적인 솔루션\u0026quot;을 찾는 것이다.\n가용성과 SLO/SLA 가용성(Availability)은 시스템의 운영 성능과 신뢰성의 척도다. \u0026ldquo;Five 9\u0026rsquo;s\u0026rdquo; (99.999%)를 목표로 하면 연간 다운타임이 약 5분에 불과하다.\n가용성 연간 허용 다운타임 99.9% 약 8.76시간 99.99% 약 52분 99.999% 약 5.26분 SLO (Service Level Objective) — 내부 성능 목표. \u0026ldquo;웹 서비스의 99.9% 요청이 300ms 이내에 응답해야 한다.\u0026rdquo;\nSLA (Service Level Agreement) — 고객과의 공식 계약. SLA 위반 시 환불이나 보상을 제공해야 한다.\n복원력(Resilience) 구축 전략:\nRedundancy — 백업 시스템을 항상 대기시킨다 Fault Tolerance — 예상치 못한 장애나 공격에 대비한다 Graceful Degradation — 일부 기능이 불가해도 핵심 기능은 유지한다 처리량 vs 지연시간 메트릭 단위 의미 Server Throughput RPS (Requests/sec) 서버가 초당 처리하는 요청 수 Database Throughput QPS (Queries/sec) DB가 초당 처리하는 쿼리 수 Data Throughput Bytes/sec 네트워크 또는 시스템의 데이터 전송 속도 Latency ms 단일 요청의 응답 시간 처리량과 지연시간은 트레이드오프 관계다. 배치 처리(batch)로 처리량을 늘리면 개별 요청의 지연시간이 증가할 수 있다. 시스템 설계에서는 유스케이스에 맞는 균형점을 찾아야 한다.\n네트워킹 기초 — IP, TCP, UDP, DNS IP 주소와 패킷 모든 네트워크 통신의 기본은 IP 주소다. IPv4는 32비트(약 40억 개)로 부족해지면서 IPv6(128비트)로 전환 중이다. 데이터 패킷의 IP 헤더에 송수신자 주소가 담기며, 애플리케이션 레이어에서 HTTP 같은 프로토콜로 데이터를 해석한다.\nTCP vs UDP TCP (Transmission Control Protocol) — 연결 지향, 순서 보장, 재전송 지원. 웹 브라우징, 파일 전송, 이메일에 적합. Three-way handshake(SYN → SYN-ACK → ACK)로 연결을 설정한다.\nUDP (User Datagram Protocol) — 비연결, 순서 비보장, 빠름. 실시간 스트리밍, 게임, VoIP에 적합. 약간의 패킷 손실을 허용하는 대신 속도를 얻는다.\nDNS (Domain Name System) 사람이 읽을 수 있는 도메인(google.com)을 IP 주소로 변환하는 인터넷의 전화번호부. 브라우저 캐시 → OS 캐시 → 재귀 리졸버 → 루트 서버 → TLD 서버 → 권한 서버 순서로 해석한다.\nAPI 설계 — REST, GraphQL, gRPC REST (Representational State Transfer) 가장 보편적인 API 스타일. HTTP 메서드(GET, POST, PUT, DELETE)와 URL 경로로 리소스를 조작한다. 무상태(stateless) 원칙으로 각 요청이 독립적이다.\nGraphQL 클라이언트가 필요한 데이터만 정확히 요청할 수 있다. Over-fetching과 Under-fetching 문제를 해결하지만, 서버 구현이 복잡해지고 캐싱이 어렵다.\ngRPC (Google Remote Procedure Call) Protocol Buffers를 사용하는 바이너리 프로토콜. HTTP/2 기반으로 양방향 스트리밍을 지원한다. 마이크로서비스 간 통신에서 REST보다 높은 성능을 보인다.\n특성 REST GraphQL gRPC 데이터 포맷 JSON JSON Protobuf (바이너리) 프로토콜 HTTP/1.1 HTTP HTTP/2 유스케이스 공개 API 복잡한 쿼리 서비스 간 통신 스트리밍 제한적 Subscription 양방향 로드 밸런싱과 프록시 로드 밸런싱 전략 여러 서버에 트래픽을 분배하여 단일 서버의 과부하를 방지한다.\nRound Robin — 순차적으로 요청을 분배. 가장 단순하다. Least Connections — 현재 연결 수가 가장 적은 서버에 분배. IP Hash — 클라이언트 IP를 해싱하여 항상 같은 서버로 라우팅. 세션 유지에 유용하다. Weighted — 서버 성능에 따라 가중치를 부여. Forward Proxy vs Reverse Proxy Forward Proxy — 클라이언트 측에서 동작. 사용자의 IP를 숨기고, 콘텐츠 필터링이나 캐싱에 사용한다. (예: VPN)\nReverse Proxy — 서버 측에서 동작. 실제 서버의 IP를 숨기고, 로드 밸런싱, SSL 종료, 캐싱을 담당한다. (예: nginx, HAProxy)\n캐싱 전략 graph TD Client[\"클라이언트\"] --\u003e CDN[\"CDN 캐시\"] CDN --\u003e LB[\"로드 밸런서\"] LB --\u003e APP[\"애플리케이션 \u0026amp;lt;br/\u0026amp;gt; 인메모리 캐시\"] APP --\u003e REDIS[\"Redis / Memcached\"] REDIS --\u003e DB[\"데이터베이스\"]캐싱은 시스템의 모든 계층에서 적용될 수 있다:\n브라우저 캐시 — 정적 자산(CSS, JS, 이미지)을 클라이언트에 저장 CDN — 지리적으로 분산된 서버에 콘텐츠를 캐싱하여 지연시간을 줄임 애플리케이션 캐시 — Redis, Memcached로 빈번한 DB 쿼리 결과를 메모리에 보관 DB 쿼리 캐시 — 동일 쿼리 결과를 DB 레벨에서 캐싱 캐시 무효화(Cache Invalidation) 전략이 핵심이다:\nWrite-Through — 쓰기 시 캐시와 DB를 동시에 업데이트. 일관성 높지만 쓰기 지연. Write-Back — 캐시만 먼저 업데이트, DB는 나중에 배치로. 빠르지만 데이터 손실 위험. Write-Around — DB에만 쓰고 캐시는 읽기 시 갱신. 자주 안 읽는 데이터에 적합. 데이터베이스 — SQL vs NoSQL, 샤딩, 복제 SQL vs NoSQL 특성 SQL (PostgreSQL, MySQL) NoSQL (MongoDB, Cassandra) 스키마 고정 스키마, 테이블 기반 유연한 스키마, 문서/KV/그래프 확장 수직 확장(Scale Up) 수평 확장(Scale Out) 트랜잭션 ACID 보장 BASE (최종 일관성) 적합 유스케이스 관계형 데이터, 복잡한 조인 대용량 비정형 데이터, 빠른 쓰기 샤딩 (Sharding) 데이터를 여러 DB 인스턴스에 분할 저장하는 수평 분할 전략이다. 샤딩 키 선택이 핵심 — 불균등한 분배(hot spot)가 발생하면 특정 샤드에 부하가 집중된다.\n복제 (Replication) 데이터를 여러 노드에 복사하여 읽기 성능과 내결함성을 높인다.\nLeader-Follower — 리더가 쓰기를 담당하고 팔로워가 읽기를 처리 Leader-Leader — 모든 노드가 읽기/쓰기 가능하지만 충돌 해결이 복잡 빠른 링크 System Design Concepts Course and Interview Prep — freeCodeCamp 전체 강의 인사이트 시스템 설계의 본질은 \u0026ldquo;트레이드오프\u0026quot;다. CAP 정리에서 두 가지만 선택할 수 있듯, 모든 설계 결정은 무엇을 얻고 무엇을 포기할지의 문제다. 처리량을 높이면 지연시간이 늘고, 일관성을 강화하면 가용성이 떨어진다. 좋은 시스템 설계자는 정답을 암기하는 것이 아니라 유스케이스에 맞는 최적의 타협점을 찾는 능력을 갖춘다. 이 강의가 다루는 범위는 넓지만, 각 개념이 독립적이지 않고 서로 맞물려 있다는 점이 가장 큰 교훈이다. CDN은 캐싱의 확장이고, 샤딩은 CAP 정리의 실전 적용이며, 로드 밸런싱은 가용성과 확장성의 교차점이다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-system-design-concepts/cover.jpg","permalink":"/ko/posts/2026-04-02-system-design-concepts/","title":"System Design 핵심 개념 총정리 — 면접 준비부터 실전 아키텍처까지"},{"content":"개요 이전 글: Trading Agent 개발기 #7에서는 에이전트 설정 UI와 시그널 카드 개선을 다뤘다. 이번 #8에서는 단일 min_rr_score 게이트를 5개 팩터 합성 스코어(Composite Score) 시스템으로 교체하고, 종목 리서치 페이지 신규 구축, 매도 검증 로직, 그리고 프로젝트 리브랜딩까지 41개 커밋에 걸친 대규모 개선을 정리한다.\n1. 종목 리서치 페이지 (Stock Info) 문제 시그널이 발생해도 해당 종목의 기본적 분석, 기술적 지표, 수급 동향 등을 한눈에 볼 수 있는 페이지가 없었다. 매번 외부 증권사 HTS를 열어야 했고, 이는 의사결정 지연의 원인이 됐다.\n구현 백엔드에 /api/research 라우터를 추가하고 5개 엔드포인트(기본 정보, 재무, 기술적 지표, 수급, 뉴스/공시)를 구성했다. 프론트엔드는 9개 섹션 컴포넌트로 분리했다.\n// frontend/src/components/stockinfo/ 구조 DiscoverySidebar.tsx // 종목 검색 사이드바 ResearchHeader.tsx // 종목 기본 정보 헤더 PriceChartSection.tsx // 캔들스틱 차트 + 기술적 지표 FundamentalsSection.tsx // 재무제표 핵심 지표 ValuationSection.tsx // 밸류에이션 비교 InvestorFlowSection.tsx // 외국인/기관 수급 PeerSection.tsx // 동종업계 비교 InsiderSection.tsx // 내부자 거래 SignalHistorySection.tsx // 과거 시그널 이력 차트는 기존 라인 차트에서 캔들스틱 + 거래량 + 이동평균선(MA) + 볼린저 밴드(BB) 오버레이로 업그레이드했으며, 기술적 지표는 RSI, MACD, 볼린저 밴드, 거래량 추세를 각각 미니 차트가 포함된 2x2 그리드 카드로 표시한다.\n2. 시그널 파이프라인 개선 — 선형 신뢰도와 매도 검증 Sigmoid에서 Linear 매핑으로 기존 sigmoid 기반 compute_confidence는 R/R 스코어가 0.5~1.5 구간에서 거의 동일한 신뢰도를 출력하는 \u0026ldquo;사각지대\u0026quot;가 있었다. 이를 선형 매핑으로 교체하고 min_rr_score 임계값을 0.3으로 낮춰 더 넓은 범위의 시그널을 포착하도록 했다.\n매도(SELL) 검증 로직 보유하지 않은 종목에 대해 SELL 시그널이 발생하는 문제를 발견했다. 두 단계의 하드 게이트를 추가했다.\nRisk Manager: 미보유 종목 SELL 거부 + 최소 보유 기간(min hold time) 검증 Market Scanner: 미보유 종목의 SELL을 HOLD로 강제 전환 전문가 패널 프롬프트에도 SELL/HOLD 방향 규칙을 명시적으로 추가하여, Chief Analyst가 보유 현황을 인지한 상태에서 의견을 내도록 개선했다.\n3. 다중 팩터 합성 스코어 시스템 이번 시리즈의 핵심 변경이다. 단일 R/R 스코어에 의존하던 시그널 필터링을 5개 독립 팩터의 가중합으로 전면 교체했다.\nflowchart LR subgraph 5-Factors[\"5개 서브 스코어\"] A[\"R/R Ratio\u0026lt;br/\u0026gt;(리스크 대비 수익)\"] B[\"Expert Consensus\u0026lt;br/\u0026gt;(전문가 합의도)\"] C[\"Fundamental\u0026lt;br/\u0026gt;(PER, ROE 등)\"] D[\"Technical Momentum\u0026lt;br/\u0026gt;(RSI, MACD, 거래량)\"] E[\"Institutional Flow\u0026lt;br/\u0026gt;(외국인/기관 수급)\"] end subgraph Weights[\"가중치 정규화\"] W[\"normalize_weights()\"] end subgraph Quality[\"데이터 품질\"] Q[\"confidence_grades\u0026lt;br/\u0026gt;A=1.0 B=0.85 C=0.6 D=0.3\"] end A --\u003e W B --\u003e W C --\u003e W D --\u003e W E --\u003e W W --\u003e|\"weighted sum\"| R[\"raw score\"] R --\u003e|\"x quality\"| F[\"Composite Score\u0026lt;br/\u0026gt;(0~100)\"] Q --\u003e F서브 스코어 설계 각 팩터는 0~1 범위로 정규화되며, 데이터가 없으면 기본값 0.5(중립)를 반환한다.\n# backend/app/models/composite_score.py def score_fundamental( per: float | None = None, roe: float | None = None, debt_ratio: float | None = None, operating_margin: float | None = None, ) -\u0026gt; float: \u0026#34;\u0026#34;\u0026#34;각 지표를 독립적으로 0~1로 정규화하고 평균을 반환한다. 누락된 지표는 계산에서 제외.\u0026#34;\u0026#34;\u0026#34; components: list[float] = [] if per is not None and per \u0026gt; 0: components.append(min(max(1.0 - per / 40.0, 0.0), 1.0)) if roe is not None: components.append(min(max(roe / 30.0, 0.0), 1.0)) # ... debt_ratio, operating_margin 동일 패턴 return sum(components) / len(components) if components else 0.5 기관/외국인 수급 스코어는 sigmoid 정규화를 사용한다. 순매수 합계를 기준금액(기본 10억원)으로 나눠 -1~1 범위로 매핑한다.\ndef score_institutional_flow( foreign_net: float = 0, institution_net: float = 0, scale: float = 1_000_000_000, # 10억원 ) -\u0026gt; float: combined = foreign_net + institution_net return 1.0 / (1.0 + math.exp(-combined / scale)) 가중치 정규화와 합산 사용자가 설정한 가중치는 합이 1.0이 되도록 자동 정규화된다. 최종 점수는 가중합에 데이터 품질 멀티플라이어를 곱한 뒤 0~100 스케일로 변환한다.\ndef compute_composite_score( rr_score: float, calibration_ceiling: float = 2.0, expert_analyses: list[dict] | None = None, dart_financials: dict | None = None, technicals: dict | None = None, investor_trend: dict | None = None, confidence_grades: dict[str, str] | None = None, weights: dict[str, float] | None = None, ) -\u0026gt; float: w = normalize_weights(weights) if weights else dict(DEFAULT_WEIGHTS) # ... 5개 서브 스코어 계산 ... raw = ( w[\u0026#34;rr_ratio\u0026#34;] * rr_sub + w[\u0026#34;expert_consensus\u0026#34;] * expert_sub + w[\u0026#34;fundamental\u0026#34;] * fundamental_sub + w[\u0026#34;technical\u0026#34;] * technical_sub + w[\u0026#34;institutional\u0026#34;] * institutional_sub ) quality = compute_data_quality_multiplier(confidence_grades or {}) return min(max(raw * quality * 100, 0.0), 100.0) 데이터 품질 멀티플라이어 전문가별로 데이터 신뢰도 등급(A/B/C/D)을 부여하고, 등급 평균을 멀티플라이어로 적용한다. 데이터 품질이 낮으면 합성 스코어가 자동으로 할인된다.\n등급 멀티플라이어 A 1.00 B 0.85 C 0.60 D 0.30 4. UI 슬라이더와 DB 마이그레이션 가중치 조절 UI Settings 페이지에 5개 팩터별 가중치 슬라이더를 추가했다. 사용자가 슬라이더를 움직이면 실시간으로 정규화된 비율이 표시된다. 기존 min_rr_score 슬라이더는 min_composite_score로 교체되었고, 기본 임계값은 15%로 설정했다.\n전체 스택 마이그레이션 min_rr_score에서 min_composite_score로의 변경은 다음 레이어를 모두 수정해야 했다.\n레이어 파일 변경 내용 스코어링 모듈 composite_score.py 5개 서브 스코어 + 합산 함수 신규 스캐너 market_scanner.py compute_confidence 제거, composite score 연결 리스크 매니저 risk_manager.py 게이트 기준 변경 API 라우터 agents.py 가중치 필드 추가, 필드명 변경 프론트엔드 타입 types.ts 가중치 필드 5개 추가 설정 UI SettingsView.tsx 슬라이더 5개 추가 DB trading.db 컬럼 rename + 가중치 기본값 insert 5. 기타 개선사항 Alpha Pulse 리브랜딩 프로젝트명을 \u0026ldquo;KIS Trading\u0026quot;에서 Alpha Pulse로 변경했다. 파비콘, 매니페스트, 헤더바, 앱 타이틀 등 전체 브랜딩 에셋을 교체했다.\n인프라 수정 APScheduler cron 요일 변환: 표준 cron(0=Sun)과 APScheduler(0=Mon) 간 요일 인덱스 차이를 변환하여 스케줄 태스크가 정확한 요일에 실행되도록 수정 uvicorn WebSocket: websockets 패키지의 DeprecationWarning을 해결하기 위해 wsproto로 구현체 변경 스케줄 정렬: 스케줄 태스크 목록을 cron 시간(시:분) 기준 오름차순으로 정렬 전문가 패널 강화 각 전문가에게 투자자 수급 동향, DART 공시 요약, 전문 분야별 신뢰도 등급을 추가로 제공하여 분석 품질을 향상시켰다.\n커밋 로그 날짜 설명 카테고리 03-24 스케줄 태스크 cron 시간순 정렬 UI 03-25 에이전트 설정 구성 가능화 + 시그널 카드 UI 개선 feat 03-25 CLAUDE.md 멀티 에이전트 시스템 문서 업데이트 docs 03-30 uvicorn WebSocket을 wsproto로 전환 fix 03-30 APScheduler cron 요일 변환 수정 fix 03-30 Stock Info 페이지 설계 문서 + 구현 계획 docs 03-31 technical_service 모듈 추가 (재사용 가능 지표 계산) feat 03-31 research 타입 + API 함수 추가 feat 03-31 /api/research 라우터 (5개 엔드포인트) feat 03-31 stockinfo 섹션 컴포넌트 9개 + DiscoverySidebar feat 03-31 InsiderSection, SignalHistorySection 컴포넌트 feat 03-31 ResearchPanel, StockInfoView, CSS 완성 feat 03-31 StockInfoView를 앱 내비게이션에 연결 feat 03-31 lint 에러 해결 및 stockinfo 컴포넌트 완성 fix 03-31 verbatimModuleSyntax 호환 import type 수정 fix 03-31 검색 결과 반환 + 종목 전환 시 stale state 방지 fix 03-31 시그널 파이프라인 수정 설계 문서 docs 03-31 캔들스틱 차트 + 거래량, MA, BB 오버레이 feat 03-31 기술적 지표 미니 차트 카드 분리 feat 03-31 compute_confidence 선형 매핑 함수 추가 feat 03-31 sigmoid를 linear confidence로 교체, min_rr_score 0.3 feat 03-31 기술적 지표 카드 2x2 그리드 레이아웃 feat 03-31 SELL 검증 — 미보유 종목 거부 + 최소 보유 기간 feat 03-31 미보유 종목 SELL을 HOLD로 강제 전환 feat 03-31 Chief Analyst 프롬프트에 SELL/HOLD 방향 규칙 추가 feat 03-31 전문가 데이터 강화 — 수급, DART, 신뢰도 등급 feat 03-31 가격/거래량 차트 영역 간격 조정 fix 03-31 calibration ceiling 슬라이더, min hold time 입력 feat 03-31 RSI 게이지 CSS 누락분 반영 fix 03-31 다중 팩터 합성 스코어 설계 문서 (Approach C) docs 03-31 다중 팩터 합성 스코어 구현 계획 docs 03-31 KIS Trading에서 Alpha Pulse로 리브랜딩 feat 04-01 5개 서브 스코어 함수 + 데이터 품질 멀티플라이어 feat 04-01 compute_composite_score + 가중치 정규화 feat 04-01 합성 스코어를 파이프라인에 연결, compute_confidence 제거 feat 04-01 min_rr_score 게이트를 min_composite_score로 변경 (15%) feat 04-01 API 라우터에 가중치 필드 추가 feat 04-01 프론트엔드 타입에 가중치 필드 추가 feat 04-01 가중치 슬라이더 UI, min_composite_score 교체 feat 04-01 DB 마이그레이션 — 컬럼 rename + 가중치 기본값 feat 인사이트 단일 지표의 한계: min_rr_score 하나로 매매 신호를 필터링하면, R/R이 높지만 기본적 분석이 취약한 종목이나, 수급이 좋지만 기술적 지표가 부정적인 종목을 구분할 수 없다. 다중 팩터 시스템으로 전환하면서 각 차원을 독립적으로 평가하고 가중합으로 결합할 수 있게 됐다. 사용자가 슬라이더로 가중치를 조절할 수 있어 투자 성향(기본적 분석 중심 vs 모멘텀 중심)에 맞는 튜닝이 가능하다.\n데이터 품질을 점수에 반영하는 것의 가치: 모든 팩터의 데이터가 동일한 품질은 아니다. DART 공시가 오래된 종목, 거래량이 적어 기술적 지표가 불안정한 종목 등에서는 높은 합성 스코어가 나오더라도 실제 신뢰도는 낮다. 데이터 품질 멀티플라이어를 도입하여 \u0026ldquo;좋은 데이터로 계산된 70점\u0026quot;과 \u0026ldquo;나쁜 데이터로 계산된 70점\u0026quot;을 구분할 수 있게 한 것이 이번 설계의 핵심이었다.\n전체 스택을 관통하는 필드명 변경의 비용: min_rr_score 하나를 min_composite_score로 바꾸는 데 DB, 백엔드 모델, API 라우터, 프론트엔드 타입, UI 컴포넌트까지 7개 레이어를 수정해야 했다. 초기 설계 시 범용적인 네이밍을 사용했다면 이 비용을 줄일 수 있었을 것이다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-trading-agent-dev8/cover.jpg","permalink":"/ko/posts/2026-04-02-trading-agent-dev8/","title":"Trading Agent 개발기 #8 — 다중 팩터 가중치 시스템과 합성 스코어 마이그레이션"},{"content":"개요 오늘은 세 가지 흥미로운 주제를 다룹니다. 먼저 Google이 발표한 TurboQuant 연구로, 동일 하드웨어에서 로컬 LLM의 컨텍스트 윈도우를 6배까지 늘릴 수 있는 KV Cache 양자화 기술입니다. 다음으로 한국의 AI 캐릭터 대화 플랫폼 **플릿(Plit)**을 살펴보고, 마지막으로 Claude Code + Nano Banana 2 조합으로 3D 애니메이션이 포함된 프리미엄 웹사이트를 빠르게 제작하는 워크플로우를 분석합니다.\nTurboQuant — 로컬 AI의 게임 체인저 KV Cache 문제란? 로컬에서 LLM을 실행할 때 가장 큰 병목은 KV Cache(Key-Value Cache)입니다. KV Cache는 대화 히스토리를 저장하는 메모리 영역으로, 채팅이 길어질수록 GPU/NPU RAM을 점점 더 많이 소비합니다. 모델 자체도 메모리를 차지하기 때문에, 소비자급 하드웨어(832GB RAM)에서는 컨텍스트 윈도우가 8K16K 토큰으로 제한되는 것이 현실입니다.\nAnythingLLM의 창립자 Timothy Carabatsos는 이 문제의 실질적 영향을 이렇게 설명합니다:\n8K 컨텍스트 윈도우로는 YouTube 팟캐스트 하나도 요약할 수 없습니다. 16K로는 겨우 가능하지만 시스템의 다른 작업이 멈출 수 있죠. 32K가 되면 이런 작업이 trivial해집니다.\nTurboQuant의 핵심 Google의 TurboQuant 연구는 KV Cache를 양자화하여 동일 메모리 공간에 약 6배 더 많은 토큰을 저장할 수 있게 합니다. 벤치마크에서는 F16(기존 방식) 대비 메모리 사용량이 약 4배 감소하는 것으로 확인되었습니다.\nflowchart LR A[\"기존 로컬 LLM\u0026lt;br/\u0026gt;8K 컨텍스트\"] --\u003e|\"TurboQuant\u0026lt;br/\u0026gt;KV Cache 양자화\"| B[\"개선된 로컬 LLM\u0026lt;br/\u0026gt;32K~48K 컨텍스트\"] B --\u003e C[\"팟캐스트 요약\"] B --\u003e D[\"문서 분석\"] B --\u003e E[\"복잡한 에이전트 워크플로우\"] F[\"RAM 사용량\u0026lt;br/\u0026gt;F16 기준\"] --\u003e|\"~4x 감소\"| G[\"RAM 사용량\u0026lt;br/\u0026gt;TurboQuant 적용\"]실질적 의미 현재 llama.cpp에 TurboQuant를 병합하려는 작업이 진행 중입니다. llama.cpp는 로컬 모델 실행의 사실상 표준이므로, 이 통합이 완료되면 대부분의 로컬 AI 도구에 즉각 반영될 것입니다.\n특히 DDR5 메모리 가격이 최근 급등하고 있는 상황에서, 기존 하드웨어의 활용도를 극대화하는 TurboQuant의 가치는 더욱 두드러집니다. 7B 모델 기준으로:\n항목 기존 TurboQuant 적용 후 컨텍스트 윈도우 8K 토큰 32K+ 토큰 KV Cache 메모리 100% ~25% 팟캐스트 요약 불가능 가능 복잡한 워크플로우 제한적 실용적 클라우드 모델이 여전히 100만 토큰급 작업에서 우위를 가지겠지만, 일상적인 AI 작업의 상당 부분이 로컬에서 실행 가능해지는 전환점이 될 수 있습니다.\n플릿(Plit) — AI 캐릭터 대화 플랫폼 서비스 개요 **플릿(Plit)**은 한국의 스타트업 파이어스(Pius)가 개발한 AI 캐릭터 대화 플랫폼입니다. 현재 베타 테스트 중이며, 세 가지 핵심 기능을 제공합니다:\n캐릭터 챗 — AI 캐릭터와 1:1 대화 토크룸 — 테마별 자유 대화 공간 스토리 — 분기형 인터랙티브 스토리 Character.ai나 Janitor AI 같은 해외 서비스와 유사한 포지셔닝이지만, 한국어에 최적화된 서비스라는 점이 차별점입니다. \u0026ldquo;나만의 AI 캐릭터와 대화를 시작해보세요\u0026quot;라는 슬로건 아래, 인기 캐릭터와 새로운 캐릭터를 탐색할 수 있는 구조로 되어 있습니다.\nAI 캐릭터 대화 시장의 흐름 AI 캐릭터 대화 플랫폼은 전 세계적으로 빠르게 성장하는 영역입니다. Character.ai의 폭발적 성장 이후 다양한 경쟁 서비스가 등장하고 있으며, 플릿은 한국 시장을 타겟으로 한 진입으로 볼 수 있습니다. 분기형 스토리 기능은 단순 채팅을 넘어 인터랙티브 콘텐츠로의 확장을 시도한다는 점에서 주목할 만합니다.\nClaude Code + Nano Banana 2 — 프리미엄 웹사이트 원샷 제작 워크플로우 전체 흐름 AI 자동화 사업을 운영하는 Jack Roberts가 소개한 이 워크플로우는, 코딩 경험이 없어도 모바일 반응형, SEO 최적화, 3D 애니메이션이 포함된 프리미엄 웹사이트를 만들 수 있다는 것이 핵심입니다.\nflowchart TD S1[\"Step 1: 브랜드 추출\u0026lt;br/\u0026gt;Firecrawl로 기존 사이트 스크래핑\"] --\u003e S2[\"Step 2: 이미지 생성\u0026lt;br/\u0026gt;Nano Banana 2로 3D 에셋 생성\"] S2 --\u003e S3[\"Step 3: 비디오 전환\u0026lt;br/\u0026gt;시작/끝 프레임으로 애니메이션 생성\"] S3 --\u003e S4[\"Step 4: 웹사이트 빌드\u0026lt;br/\u0026gt;Claude Code + 스킬로 HTML 생성\"] S4 --\u003e S5[\"Step 5: 배포\u0026lt;br/\u0026gt;도메인 연결 및 호스팅\"] T1[\"Firecrawl API\"] -.-\u003e S1 T2[\"Nano Banana 2\u0026lt;br/\u0026gt;(16x9, 2K+)\"] -.-\u003e S2 T3[\"Kling 3.0\u0026lt;br/\u0026gt;(영상 생성)\"] -.-\u003e S3 T4[\"Claude Code\u0026lt;br/\u0026gt;+ 3D Website Skill\"] -.-\u003e S45단계 프로세스 상세 Step 1 — 브랜드 추출: Firecrawl의 branding 스크래핑 기능으로 대상 웹사이트의 색상, 로고, 브랜드 에셋을 자동 추출합니다. API를 통해 대규모 자동화도 가능합니다.\nStep 2 — 3D 에셋 생성: Nano Banana 2에서 16x9 비율, 최소 2K 해상도로 이미지를 생성합니다. 핵심 팁은 깨끗한 흰색 배경을 지정하는 것과, 4회 이상 iteration을 돌려 최적의 결과물을 선택하는 것입니다. 1K 해상도는 품질이 부족하므로 반드시 2K 이상을 사용해야 합니다.\nStep 3 — 스크롤 애니메이션 비디오: 조립된 상태(시작 프레임)와 분해된 상태(끝 프레임) 두 이미지를 Kling 3.0 같은 영상 생성 도구에 넣어 전환 영상을 만듭니다. 이전에는 수백 개 프레임을 수동으로 만들어야 했지만, 이제 두 장의 이미지만 있으면 됩니다.\nStep 4 — Claude Code로 웹사이트 빌드: Claude Code의 스킬 시스템(/skillcreator)을 활용하여 3D Website Builder와 Asset Generation 스킬을 설치하고, 생성된 에셋을 통합한 HTML 웹사이트를 자동 생성합니다. shift 단축키로 \u0026ldquo;edit automatically\u0026rdquo; 모드를 활성화하면 더 빠르게 진행됩니다.\nStep 5 — 참조 기반 개선: 기존 웹사이트의 HTML 구조를 참조(reference)로 제공하여, 레이아웃과 디자인을 더욱 정교하게 다듬을 수 있습니다.\n핵심 인사이트 이 워크플로우에서 가장 주목할 점은 도구 체인의 조합입니다. 개별 도구(Firecrawl, Nano Banana, Claude Code)는 각각 특정 역할을 수행하지만, 스킬 시스템으로 연결하면 하나의 자동화 파이프라인이 됩니다. Jack Roberts는 이 방식으로 수천 달러 규모의 웹사이트를 실제로 판매해 왔다고 언급합니다.\n빠른 링크 주제 링크 TurboQuant 설명 영상 (AnythingLLM) YouTube 플릿(Plit) 공식 사이트 plit.io Claude Code + Nano Banana 2 웹사이트 제작 YouTube AnythingLLM 공식 사이트 anythingllm.com Firecrawl 개발자 도구 firecrawl.dev 인사이트 로컬 AI의 실용성이 급속도로 올라가고 있습니다. TurboQuant는 단순한 학술 연구가 아니라, llama.cpp 통합을 통해 소비자급 하드웨어에서의 AI 활용 범위를 실질적으로 넓힐 기술입니다. 8K에서 32K로의 컨텍스트 확장은 \u0026ldquo;대화 몇 번 하면 끝\u0026quot;이던 로컬 모델이 \u0026ldquo;문서 분석과 에이전트 워크플로우가 가능한 도구\u0026quot;로 전환되는 것을 의미합니다.\nAI 캐릭터 대화 시장은 지역화가 핵심입니다. 플릿이 베타 단계에서 한국어 특화로 시작한 것은 전략적 선택입니다. Character.ai의 영어 중심 서비스가 한국어 뉘앙스를 완벽히 처리하지 못하는 틈새를 공략하는 것이죠.\n웹사이트 제작의 패러다임이 바뀌고 있습니다. Nano Banana 2 워크플로우가 보여주는 것은 \u0026ldquo;코딩 → 디자인 → 배포\u0026quot;의 전통적 흐름이 \u0026ldquo;브랜드 추출 → 에셋 생성 → AI 빌드\u0026quot;로 대체될 수 있다는 것입니다. 특히 Claude Code의 스킬 시스템은 반복적인 웹사이트 제작을 대규모로 자동화할 수 있는 가능성을 열어줍니다. 프리랜서나 에이전시에게는 생산성의 질적 변화가 될 수 있습니다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-turboquant-plit/cover.jpg","permalink":"/ko/posts/2026-04-02-turboquant-plit/","title":"TurboQuant, 플릿, Nano Banana 2 — 로컬 AI 양자화부터 AI 웹사이트 제작까지"},{"content":"개요 애니메이션 이모지와 스티커는 모바일 메신저 생태계에서 핵심 수익원이자 사용자 표현 수단이다. 카카오톡 이모티콘 시장은 연간 수천억 원 규모이며, LINE Creators Market은 전 세계 크리에이터가 참여하는 개방형 플랫폼이다. 이 글에서는 플랫폼별 기술 규격, 기존 제작 도구, 오픈소스 대안, 그리고 이미지 보정 기술까지 조사하여 PopCon 프로젝트가 어떤 틈새를 공략할 수 있는지 분석한다.\nPopCon이 이 시장에서 어떻게 구현되었는지는 PopCon 개발기 #1에서 다룬다.\n시장 현황 카카오톡 이모티콘 카카오톡 이모티콘 스토어는 국내 최대의 디지털 스티커 마켓이다. 주요 특징은 다음과 같다:\n심사 기반 등록: 크리에이터가 제출하면 카카오 측 심사를 거쳐 출시 움직이는 이모티콘(움티): 24프레임 기반 애니메이션, APNG 또는 GIF 포맷 수익 배분: 크리에이터 35% (플랫폼 수수료가 높은 편) 경쟁 심화: 월 수천 개의 신규 이모티콘 세트가 제출되며, 승인률은 낮음 LINE Creators Market LINE은 글로벌 크리에이터에게 개방된 마켓을 운영한다. 애니메이션 스티커와 이모티콘 두 가지 카테고리가 있으며, 각각 규격이 다르다.\n애니메이션 스티커 규격:\n항목 규격 이미지 크기 최대 320 x 270px (한 변 최소 270px) 프레임 수 5~20프레임 (APNG) 재생 시간 최대 4초 반복 횟수 1~4회 파일 크기 개당 1MB 이하, ZIP 전체 60MB 이하 파일 형식 APNG (.png 확장자) 세트 구성 8종, 16종, 24종 중 택1 배경 투명 필수 색 공간 RGB 이모티콘 규격:\n항목 규격 이미지 크기 180 x 180px 세트 구성 8~40개 (일반), 문자 이모티콘 포함 시 최대 305개 파일 크기 개당 1MB 이하, ZIP 20MB 미만 해상도 최소 72dpi, RGB 디자인 권장 굵고 짙은 테두리, 심플한 형태 LINE의 심사 가이드라인에서 특히 주목할 점은 이모티콘이 단독 전송 시 스티커처럼 크게 표시된다는 점이다. 따라서 작은 크기에서도 식별 가능하면서 큰 크기에서도 보기 좋은 디자인이 필요하다.\n기존 제작 도구 분석 이모레비 (Emorevi) 이모레비는 AI 기반 애니메이션 이모티콘 제작 SaaS다.\n핵심 기능:\nAI Generation: 단일 이미지에서 애니메이션 자동 생성 Smart Interpolation: 프레임 간 자연스러운 보간 알고리즘 Platform Optimized: 카카오톡, LINE, Discord 등 플랫폼별 프리셋 다중 포맷 지원: MP4, GIF, APNG, WebP 내보내기 Style Transfer: 애니메이션 스타일 커스터마이징 Real-time Preview: 편집 중 실시간 미리보기 가격 정책:\n플랜 가격 티켓 수 티켓 단가 Basic $9.99 1,000 $0.01 Standard $29.99 3,600 (+600 보너스) $0.008 Premium $99.99 14,000 (+4,000 보너스) $0.007 이모레비는 \u0026ldquo;이미지 한 장에서 애니메이션까지\u0026quot;라는 워크플로우를 제공하지만, 티켓 기반 과금 모델이라 대량 제작 시 비용이 누적된다. 또한 생성 결과물의 품질 제어가 제한적이다.\n오픈소스 솔루션 Partymoji Partymoji는 TypeScript + Rust로 만든 웹 기반 애니메이션 GIF 생성기다.\n스택: TypeScript (219K LoC), Rust (GIF 인코더), 웹 브라우저에서 실행 기능: 이미지에 파티 효과(무지개, 회전, 반짝임 등)를 적용하여 애니메이션 GIF 생성 라이브 데모: https://mikeyburkman.github.io/partymoji/ 특징: IndexedDB 기반 프로젝트 저장, Bezier 커브로 애니메이션 제어 한계: 이모티콘/스티커 플랫폼 규격에 맞춘 출력 기능 없음, 효과 중심(원본 캐릭터 애니메이션 아님) gif_emoji gif_emoji는 Python(Pillow)으로 만든 미니멀 도구로, 이미지를 회전하는 GIF로 변환한다.\n출력: 32x32 GIF, 36프레임 (10도씩 회전) 용도: Slack 커스텀 이모지 (60KB 제한 준수) 코드량: Python 1,655줄 — 매우 간결 한계: 회전 애니메이션만 지원, 크기/프레임 수 하드코딩 두 프로젝트 모두 \u0026ldquo;이미지에 효과를 입히는\u0026rdquo; 접근 방식이다. 캐릭터 자체를 움직이게 하는 것(표정 변화, 손 흔들기 등)과는 근본적으로 다르다.\n이미지 보정 기술 애니메이션 이모지 제작 파이프라인에서 입력 이미지의 품질은 결과물에 직접적인 영향을 미친다. 두 가지 관련 기술을 살펴본다.\nWAIR — Wide-angle Image Rectification WAIR는 광각/어안 렌즈 왜곡을 보정하는 딥러닝 모델이다.\n아키텍처: ResNet50 기반, ImageNet pretrained 왜곡 모델: FOV, Division Model, Equidistant 세 가지 지원 성능: ADE20k 데이터셋 기준 PSNR 26.43 / SSIM 0.85 (FOV 모델) 실용성: 256x256 입력으로 추정한 왜곡 파라미터 k를 1024x1024 원본에 적용 가능 (워핑 5.3ms) 이모지 관련성: 사용자가 스마트폰 광각 카메라로 촬영한 사진을 이모지 소스로 쓸 때 왜곡 보정에 활용 가능 Deep-OAD — Image Orientation Angle Detection Deep-OAD는 이미지의 회전 각도를 감지하고 자동으로 바로잡는 모델이다.\nV2 업데이트: ViT(Vision Transformer) 적용으로 SOTA 달성 정확도: 0~359도 범위에서 test MAE 6.5도 학습 데이터: MS COCO 대부분의 이미지로 학습 활용: 사용자 업로드 이미지의 방향을 자동 감지하여 전처리 단계에서 보정 이 두 기술은 \u0026ldquo;사용자가 제공하는 원본 이미지를 자동으로 정규화\u0026quot;하는 전처리 파이프라인에 통합할 수 있다.\n도구 비교 graph LR subgraph 상용[\"상용 서비스\"] A[\"이모레비\u0026lt;br/\u0026gt;AI 애니메이션 생성\u0026lt;br/\u0026gt;티켓 과금\"] end subgraph 오픈소스[\"오픈소스 도구\"] B[\"Partymoji\u0026lt;br/\u0026gt;효과 기반 GIF\u0026lt;br/\u0026gt;TypeScript + Rust\"] C[\"gif_emoji\u0026lt;br/\u0026gt;회전 GIF\u0026lt;br/\u0026gt;Python\"] end subgraph 보정[\"이미지 보정\"] D[\"WAIR\u0026lt;br/\u0026gt;광각 왜곡 보정\u0026lt;br/\u0026gt;ResNet50\"] E[\"Deep-OAD\u0026lt;br/\u0026gt;방향 감지\u0026lt;br/\u0026gt;ViT\"] end subgraph 목표[\"PopCon\"] F[\"캐릭터 애니메이션\u0026lt;br/\u0026gt;플랫폼 규격 준수\u0026lt;br/\u0026gt;로컬 실행\"] end A --\u003e|\"영감\"| F B --\u003e|\"GIF 인코딩 참고\"| F C --\u003e|\"Pillow 파이프라인\"| F D --\u003e|\"전처리\"| F E --\u003e|\"전처리\"| FPopCon과의 차별점 기존 도구들의 한계를 정리하면 PopCon이 차지할 포지션이 보인다:\n측면 기존 도구 PopCon 애니메이션 방식 효과 적용(회전, 파티) 또는 AI 블랙박스 캐릭터 리깅 기반 의도된 움직임 플랫폼 규격 범용 GIF 출력 LINE/카카오 규격 프리셋 내장 비용 SaaS 과금 (이모레비) 로컬 실행, 무료 제어 수준 제한적 파라미터 프레임 단위 세밀한 제어 이미지 전처리 없음 왜곡 보정 + 방향 감지 파이프라인 통합 가능 출력 포맷 주로 GIF APNG, GIF, WebP 멀티 포맷 핵심 차별점은 세 가지로 요약된다:\n규격 준수 자동화 — LINE 애니메이션 스티커의 320x270px, 5~20프레임, 4초 제한 등을 프리셋으로 제공하여 제출 시행착오를 줄인다 캐릭터 중심 애니메이션 — 효과를 \u0026ldquo;입히는\u0026rdquo; 것이 아니라 캐릭터가 \u0026ldquo;움직이는\u0026rdquo; 애니메이션을 생성한다 전처리 파이프라인 — WAIR, Deep-OAD 같은 보정 모델을 통합하여 다양한 품질의 입력 이미지를 정규화한다 빠른 링크 이모레비 — AI 애니메이션 이모티콘 제작 LINE Creators Market 애니메이션 스티커 가이드라인 LINE Creators Market 이모티콘 가이드라인 Partymoji — 웹 기반 애니메이션 GIF 생성기 gif_emoji — Python 회전 GIF 생성기 WAIR — 광각 이미지 왜곡 보정 Deep-OAD — 이미지 방향 자동 감지 인사이트 시장 진입 장벽은 \u0026ldquo;심사\u0026quot;에 있다 — 기술적으로 애니메이션을 만드는 것보다, 카카오/LINE 심사를 통과하는 품질을 일관되게 내는 것이 더 어렵다. 자동화 도구가 규격을 정확히 지키는 것이 첫 번째 과제다. 오픈소스 공백이 크다 — partymoji나 gif_emoji는 \u0026ldquo;장난감\u0026rdquo; 수준이다. 플랫폼 규격을 준수하면서 캐릭터 애니메이션을 생성하는 오픈소스 도구는 사실상 없다. 이모레비의 한계가 기회 — SaaS 모델은 대량 제작에 비용이 쌓이고, AI 생성 결과물의 세밀한 제어가 어렵다. 로컬에서 실행되면서 프레임 단위 제어가 가능한 도구에 수요가 있다. 전처리 자동화가 UX를 결정한다 — 사용자가 올린 사진이 기울어져 있거나 광각 왜곡이 있으면, 아무리 좋은 애니메이션 엔진이 있어도 결과물이 어색하다. WAIR + Deep-OAD 같은 모델의 전처리 통합이 체감 품질을 크게 높일 수 있다. APNG가 핵심 포맷이다 — LINE과 카카오 모두 APNG를 공식 지원한다. GIF보다 색상 표현이 풍부하고(알파 채널 지원), 파일 크기 효율도 좋다. PopCon의 기본 출력 포맷은 APNG여야 한다. ","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-emoji-market-research/cover.jpg","permalink":"/ko/posts/2026-04-02-emoji-market-research/","title":"애니메이션 이모지 시장 조사 — 플랫폼 규격부터 오픈소스 도구까지"},{"content":"개요 이전 포스트들에서 하네스의 기본 개념(가드레일/모니터링/피드백 루프 3요소), 장기 실행 에이전트의 체크포인트와 상태 관리, 그리고 플러그인 생태계를 다뤘다. 이번 포스트에서는 기존에 다루지 않은 두 가지 관점을 정리한다. 첫째, 실베개발자의 YouTube 영상에서 제시하는 프롬프트 → 컨텍스트 → 하네스 → 에이전틱 4축 프레임워크와 \u0026ldquo;프롬프트는 부탁, 하네스는 물리적 차단\u0026quot;이라는 핵심 철학. 둘째, Anthropic의 하네스 디자인 문서를 분석한 TILNOTE 아티클에서 나온 플래너-생성기-평가자 3인조 아키텍처와 스프린트 계약 패턴. 관련 포스트: Long-Running Agents와 하네스 엔지니어링, HarnessKit 개발기 #3\ngraph TD A[\"AI 활용 4축 프레임워크\"] --\u003e B[\"1. 프롬프트 엔지니어링\u0026lt;br/\u0026gt;말을 잘 거는 기술\"] A --\u003e C[\"2. 컨텍스트 엔지니어링\u0026lt;br/\u0026gt;필요한 정보를 제공하는 기술\"] A --\u003e D[\"3. 하네스 엔지니어링\u0026lt;br/\u0026gt;규칙과 울타리를 만드는 기술\"] A --\u003e E[\"4. 에이전틱 엔지니어링\u0026lt;br/\u0026gt;자율 워크플로우를 설계하는 기술\"] B -.-\u003e|\"천장 존재\"| C C -.-\u003e|\"정보만으론 부족\"| D D -.-\u003e|\"상호보완\"| E style D fill:#ff6b6b,stroke:#c92a2a,color:#fff 4축 프레임워크 — 프롬프트부터 에이전틱까지 프롬프트 엔지니어링은 끝났습니다: 이제 \u0026lsquo;하네스\u0026rsquo;의 시대입니다 영상에서 실베개발자는 AI 활용 방법론을 네 가지 축으로 정리한다. 이 축들은 순서대로 졸업하는 것이 아니라 전부 동시에 필요한 상호보완적 관계다.\n프롬프트의 천장 프롬프트 엔지니어링은 AI에게 \u0026ldquo;말을 잘 거는 기술\u0026quot;이다. \u0026ldquo;계산기 만들어줘\u0026rdquo; 대신 \u0026ldquo;공학용 계산기, 사인/코사인 지원, GUI 포함\u0026quot;으로 구체화하면 결과가 달라진다. 하지만 천장이 있다. 아무리 정교한 프롬프트를 써도 프로젝트 기술 스택, 코드 구조, DB 스키마를 모르면 좋은 코드가 나올 수 없다.\n컨텍스트만으로 부족한 이유 컨텍스트 엔지니어링은 프로젝트 구조, 기존 코드, API 문서, 디자인 규칙을 함께 제공한다. Anthropic의 정의: \u0026ldquo;AI가 일할 때 필요한 정보를 적절하게 골라서 제공하는 기술.\u0026rdquo; 핵심은 많이 주는 것이 아니라 지금 필요한 것만 정확하게 주는 것이다.\n그런데 컨텍스트를 아무리 잘 설계해도 해결 안 되는 문제가 있다. AI가 정보를 다 알고 있는데 엉뚱한 짓을 하는 경우다. 결제 시스템을 맡겼더니 DB 스키마를 마음대로 바꾸거나, 신용카드 번호를 로그에 찍어 버리는 상황. 이것은 정보의 문제가 아니라 규칙과 울타리의 문제다.\n하네스 vs 에이전틱 — 마구 vs 말 훈련 이전 포스트에서 하네스의 기본 개념은 다뤘지만, 에이전틱 엔지니어링과의 관계는 명확히 정리하지 않았다. 영상의 정리가 깔끔하다:\n관점 에이전틱 엔지니어링 하네스 엔지니어링 비유 말을 훈련시키는 기술 마구를 만드는 기술 초점 AI가 어떻게 생각하는가 AI가 무엇을 할 수 있고 없는가 실패 대응 프롬프트 변경, 추론 루프 조정 규칙/테스트 자동 추가 인간 역할 위임자, 감독자 설계자, 경계 설정자 핵심은 한 줄: 아무리 잘 훈련된 말이라도 마구 없이는 밭을 갈 수 없다.\n구조적 반복 불가능성 — 하네스의 핵심 철학 이전 포스트에서 가드레일과 피드백 루프를 다뤘지만, 영상이 제시하는 가장 중요한 문장은 별도로 정리할 가치가 있다:\n에이전트가 규칙을 어겼을 때 \u0026ldquo;더 잘해봐\u0026quot;라고 프롬프트를 고치는 것이 아니다. 그 실패가 구조적으로 반복 불가능하도록 하네스를 고치는 것이다.\n부탁 vs 물리적 차단 AI 에이전트가 프론트엔드 코드에서 DB를 직접 호출했다고 하자.\n프롬프트 접근: \u0026ldquo;DB를 직접 호출하지 마\u0026quot;를 프롬프트에 추가 → 다음번에 또 실수한다. 프롬프트는 부탁이지 강제가 아니기 때문이다. 하네스 접근: 아키텍처 테스트를 추가해서 프론트엔드 폴더에서 DB를 임포트하는 순간 빌드가 실패하도록 만든다. 구조적으로 불가능해진다. 이 구분이 중요한 이유는 기존 포스트에서 \u0026ldquo;가드레일\u0026quot;을 다룰 때 개념적 수준에 머물렀기 때문이다. \u0026ldquo;프롬프트는 부탁, 도구적 경계는 물리적 차단\u0026quot;이라는 프레이밍은 실무에서 어떤 수준의 제약을 걸어야 하는지를 판단하는 기준이 된다.\n하네스의 4기둥 — 기존 3요소를 넘어서 이전 포스트에서 가드레일/모니터링/피드백 루프 3요소를 다뤘다. 영상에서는 마틴 파울러가 체계화한 4기둥 구조를 소개하는데, 기존 3요소와 겹치는 부분이 있지만 새로운 두 가지가 눈에 띈다.\n새로운 기둥 1: 도구 경계 (Tool Boundaries) AI 에이전트가 어떤 도구를 쓸 수 있고 어디까지 접근할 수 있는지를 물리적으로 제한한다:\n파일 시스템: src/ 폴더는 읽기/쓰기, config/ 폴더는 읽기만 가능 API: 내부 API 호출은 가능, 외부 서비스 호출은 불가 데이터베이스: SELECT는 가능, DROP TABLE은 절대 불가 터미널: 화이트리스트된 명령만 실행 가능 이전 포스트의 \u0026ldquo;가드레일\u0026quot;은 \u0026ldquo;하면 안 되는 것을 정의\u0026quot;하는 수준이었다면, 도구 경계는 접근 자체를 시스템적으로 차단하는 물리적 계층이다.\n새로운 기둥 2: 가비지 컬렉션 (코드 품질 자동 정리) 마틴 파울러가 명명한 이 개념은 기존 포스트에서 다루지 않았다. AI가 기존 코드를 참고해서 새 코드를 짜는데, 기존 코드에 나쁜 패턴이 있으면 그대로 따라한다. 나쁜 패턴이 눈덩이처럼 불어나는 것을 막기 위한 자동 청소 시스템이다:\n코딩 규칙 위반 자동 감지 중복 코드 발견 및 리팩토링 PR 자동 생성 데드 코드 자동 제거 아키텍처 안티패턴 주기적 체크 핵심: 에이전트가 실수할 때마다 그 실수가 새로운 규칙이 된다. 린터 규칙 추가, 테스트 추가, 제약 추가 — 하네스가 점점 더 정교해지는 진화적 특성이다.\n플래너-생성기-평가자 아키텍처 여기서부터는 Anthropic의 하네스 디자인: 플래너-생성기-평가자 아키텍처 아티클의 내용이다. 이전 포스트에서 다루지 않은 완전히 새로운 아키텍처 패턴이다.\ngraph LR subgraph 오케스트레이션 P[\"플래너\u0026lt;br/\u0026gt;스펙 확장 + 설계\"] end subgraph 실행 G[\"생성기\u0026lt;br/\u0026gt;코드 작성\"] end subgraph 검증 E[\"평가자\u0026lt;br/\u0026gt;QA + 채점\"] end P --\u003e|\"제품 스펙\"| G G --\u003e|\"구현 결과\"| E E --\u003e|\"피드백 + 점수\"| G E --\u003e|\"통과\"| R[\"완료\"] E --\u003e|\"미달\"| G T[\"Playwright\u0026lt;br/\u0026gt;브라우저 자동화\"] --\u003e E style P fill:#4dabf7,stroke:#1c7ed6,color:#fff style G fill:#69db7c,stroke:#2f9e44,color:#fff style E fill:#ff6b6b,stroke:#c92a2a,color:#fff왜 단일 에이전트가 무너지는가 장시간 작업에서 두 가지 붕괴 원인이 있다:\n컨텍스트 불안: 컨텍스트 창이 차면서 앞서 한 결정이 뒤엉기고, 모델이 한계가 다가온다고 \u0026ldquo;느끼면\u0026rdquo; 일을 서둘러 마무리하려는 경향을 보인다 자기평가의 관대함: 에이전트에게 자기 결과를 평가하라고 하면, 실제 품질이 결함이 있어도 \u0026ldquo;괜찮다\u0026quot;고 결론내리기 쉽다 이전 포스트에서 다룬 체크포인트/상태 관리는 첫 번째 문제의 해결책이었다. 두 번째 문제의 해결책이 바로 역할 분리 — GAN에서 빌린 생성기-평가자 루프다.\nGAN의 직관을 엔지니어링으로 GAN(Generative Adversarial Network)에서 생성자와 판별자가 경쟁하며 품질을 올리듯:\n생성기: 결과물을 만든다 평가자: 기준에 따라 채점하고 비평한다 생성기: 피드백을 받아 다음 버전을 만든다 \u0026ldquo;막연한 개선\u0026quot;이 아니라 **\u0026ldquo;특정 기준을 만족시키는 개선\u0026rdquo;**이 반복된다. 평가자가 독립적일수록 \u0026lsquo;봐주기\u0026rsquo;가 줄어든다. 다만 평가자도 LLM이므로 기본 성향은 관대하다 — 퓨샷 예시와 점수 분해로 채점 습관을 교정해야 한다.\n플래너의 역할 3인조에서 플래너는 1~4문장짜리 요청을 \u0026ldquo;충분히 큰\u0026rdquo; 제품 스펙으로 확장한다. 핵심 원칙:\n너무 이른 구현 세부사항을 넣지 않는다 — 틀린 결정이 아래로 전염된다 제품 맥락과 큰 설계를 중심으로 쓰되, 구현은 여지를 남긴다 AI 기능을 제품에 섞을 기회를 적극적으로 찾게 만든다 스프린트 계약 — 완료 정의의 계약화 이전 포스트에서 체크포인트를 다뤘지만, \u0026ldquo;뭘 만들면 완료인지\u0026quot;를 어떻게 정의하는가는 다루지 않았다. Anthropic의 하네스에서 이 간극을 메우는 장치가 스프린트 계약이다.\n계약 프로세스 각 스프린트 시작 전에 생성기와 평가자가 협상한다:\n생성기가 제안: 구현 계획과 검증 방법을 제시 평가자가 점검: 스펙에 부합하는지, 테스트 가능한지 확인 합의 후 실행: 합의된 뒤에만 코드 작성 시작 이 패턴의 핵심은 에이전트 간 의사소통을 파일 기반 산출물로 고정하는 것이다. 한쪽이 파일 작성, 다른 쪽이 읽고 수정/추가. 컨텍스트가 흔들려도 작업 상태가 명시적으로 남아 장기 실행에 유리하다.\n비용 대비 품질 방식 시간 결과 단일 에이전트 20분 겉보기엔 그럴듯하지만 핵심 기능이 깨짐 플래너-생성기-평가자 하네스 6시간 더 많은 기능, 실제 동작하는 수준 차이를 만든 결정적 요소: 평가자의 실제 조작 기반 QA와 계약 기반 완료 정의.\n평가자는 스크린샷이 아니라 직접 조작 평가자가 정지 이미지 한 장만 보고 판단하면 상호작용, 레이아웃, 상태 변화에서 드러나는 품질을 놓친다. Anthropic의 해법:\n평가자에게 Playwright 같은 브라우저 자동화 도구를 붙인다 평가자가 스스로 클릭하고, 이동하고, 화면을 관찰한다 기준별 점수와 상세 비평을 작성한다 주관적 디자인 품질도 채점 가능하게 만든다. 4개 축:\n전체적 디자인 완성도 — 일관된 무드/정체성 독창성 — 템플릿/기본 컴포넌트 느낌 탈피 공예적 완성 — 타이포, 간격, 대비 같은 기본기 기능성 — 사용성 모델은 기능성과 기본기는 무난히 달성하는 경향이 있으므로, 실제로 부족한 완성도와 독창성에 더 큰 가중치를 걸어야 안전지대에서 벗어난다.\n모델이 좋아지면 하네스를 덜어내라 이전 포스트에서 다루지 않은 중요한 통찰: 하네스의 각 구성 요소는 \u0026ldquo;모델이 혼자 못 하는 것\u0026quot;에 대한 가정이다. 모델이 발전하면 그 가정이 틀어진다.\n스프린트 제거 사례 더 강해진 모델에서는:\n스프린트 분해 없이도 2시간 넘게 일관된 빌드가 가능해짐 스프린트 구조를 제거하고, 평가도 \u0026ldquo;마지막에 한 번\u0026quot;으로 축소 불필요한 장치가 비용만 늘리는 결과를 방지 다만 평가자가 완전히 불필요해지는 것은 아니다. 과제가 모델의 신뢰 경계 밖에 걸릴 때 — 예를 들어 핵심 상호작용이 자꾸 스텁으로 남는 경우 — 평가자는 여전히 값비싼 보험이다.\n실천 원칙: 새 모델이 나올 때마다 하네스를 스트레스 테스트하고, 짐이 된 부분을 떼어내는 재설계를 수행한다.\n빠른 링크 프롬프트 엔지니어링은 끝났습니다: 이제 \u0026lsquo;하네스\u0026rsquo;의 시대입니다 (YouTube) — 실베개발자, 4축 프레임워크와 하네스 4기둥 구조 Anthropic의 하네스 디자인: 플래너-생성기-평가자 아키텍처 (TILNOTE) — Anthropic 하네스 디자인 문서 분석 Harness design for long-running application development (Anthropic) — 원문 참고 Long-Running Agents와 하네스 엔지니어링 — 이전 포스트: 체크포인트, 상태 관리, 3요소 HarnessKit 개발기 #3 — 이전 포스트: 플러그인 트리거, 마켓플레이스 인사이트 이전 포스트들이 하네스의 \u0026ldquo;무엇을\u0026rdquo;(가드레일, 모니터링, 피드백 루프)에 집중했다면, 이번 두 소스는 **\u0026ldquo;왜\u0026quot;와 \u0026ldquo;어떻게\u0026rdquo;**를 보완한다.\n\u0026ldquo;왜\u0026rdquo; 측면에서, 4축 프레임워크는 하네스가 프롬프트나 컨텍스트와 어떤 관계에 있는지를 명확히 한다. 프롬프트는 부탁이고 하네스는 물리적 차단이라는 구분은, 실무에서 \u0026ldquo;이 규칙을 CLAUDE.md에 쓸 것인가, 린터 규칙으로 강제할 것인가\u0026quot;를 판단하는 기준이 된다.\n\u0026ldquo;어떻게\u0026rdquo; 측면에서, 플래너-생성기-평가자 아키텍처는 하네스의 구체적 구현 패턴을 제시한다. 특히 스프린트 계약으로 완료 정의를 계약화하고, 평가자에게 Playwright를 붙여 실제 조작 기반 QA를 수행하는 패턴은 바로 적용 가능한 수준이다. 그리고 \u0026ldquo;모델이 좋아지면 하네스를 덜어내라\u0026quot;는 통찰은 하네스를 영구 불변의 인프라가 아니라 모델 능력에 대한 가정의 집합으로 바라보게 한다. HarnessKit 개발에서도 새 모델 출시 때마다 각 스킬의 필요성을 재검증하는 프로세스가 필요하겠다.\n","date":"2026-04-02T00:00:00+09:00","image":"/images/posts/2026-04-02-harness-beyond-prompt-engineering/cover.jpg","permalink":"/ko/posts/2026-04-02-harness-beyond-prompt-engineering/","title":"프롬프트를 고치지 마세요, 하네스를 고치세요 — 4축 프레임워크와 생성기-평가자 아키텍처"},{"content":"2026년 3월 마지막 주, 오픈소스 생태계에 연쇄 공급망 공격이 터졌습니다. 주간 1억 다운로드의 axios가 npm에서 감염되고, 월간 9,700만 다운로드의 LiteLLM이 PyPI에서 뚫렸으며, Claude Code의 소스 코드가 npm .map 파일을 통해 유출되었습니다. 이 글에서는 각 사건의 기술적 세부사항과 공통 패턴, 그리고 실무 대응법을 정리합니다.\n1. axios 공급망 공격 (2026-03-31) 공격 경위 axios 리드 메인테이너 jasonsaayman의 npm 계정이 탈취되었습니다. 공격자는 계정 이메일을 ProtonMail 주소(ifstap@proton.me)로 변경한 뒤, 장기 유효 npm 토큰을 이용해 GitHub Actions CI/CD를 완전히 우회하고 npm CLI로 직접 퍼블리시했습니다.\n두 릴리스 브랜치(1.x, 0.x)가 39분 이내에 동시 감염되었습니다:\n감염 버전 안전 버전 axios@1.14.1 axios@1.14.0 axios@0.30.4 axios@0.30.3 악성 의존성 plain-crypto-js@4.2.1은 공격 18시간 전에 npm 계정 nrwise(nrwise@proton.me)로 미리 스테이징되어 있었습니다. 3개 OS용 페이로드가 사전 빌드된 치밀한 공격이었습니다.\n악성 동작 감염된 axios 버전은 plain-crypto-js@4.2.1이라는 가짜 의존성을 주입합니다. 이 패키지는 axios 소스 어디에서도 import되지 않으며, 유일한 목적은 postinstall 스크립트를 통해 크로스플랫폼 RAT(원격 접근 트로이목마)를 배포하는 것입니다.\n플랫폼별 페이로드 OS 동작 흔적 파일 macOS AppleScript로 C2 서버에서 트로이목마 다운로드 /Library/Caches/com.apple.act.mond Windows ProgramData에 실행 파일 드롭 %PROGRAMDATA%\\wt.exe Linux Python 스크립트 실행 /tmp/ld.py 자기 은폐 메커니즘 실행 후 악성코드가 스스로를 삭제하고, package.json을 미리 준비해둔 깨끗한 버전(package.md)으로 교체하여 포렌식 탐지를 회피합니다. 감염 후 node_modules를 열어봐도 정상적으로 보이도록 설계되어 있었습니다.\n공격 흐름 다이어그램 flowchart TD A[\"npm 계정 탈취\u0026lt;br/\u0026gt;jasonsaayman\"] --\u003e B[\"이메일 변경\u0026lt;br/\u0026gt;ifstap@proton.me\"] B --\u003e C[\"장기 유효 npm 토큰으로\u0026lt;br/\u0026gt;CI/CD 우회\"] C --\u003e D[\"plain-crypto-js@4.2.1\u0026lt;br/\u0026gt;18시간 전 스테이징\"] C --\u003e E[\"axios@1.14.1 퍼블리시\"] C --\u003e F[\"axios@0.30.4 퍼블리시\"] E --\u003e G[\"npm install 실행\"] F --\u003e G G --\u003e H[\"postinstall 스크립트 실행\"] H --\u003e I[\"플랫폼 감지\"] I --\u003e J[\"macOS: AppleScript RAT\"] I --\u003e K[\"Windows: wt.exe 드롭\"] I --\u003e L[\"Linux: ld.py 실행\"] J --\u003e M[\"C2 통신\u0026lt;br/\u0026gt;sfrclak.com:8000\"] K --\u003e M L --\u003e M M --\u003e N[\"package.md로 교체\u0026lt;br/\u0026gt;자기 은폐\"] style A fill:#ff6b6b,color:#fff style M fill:#ff6b6b,color:#fff style N fill:#ffa94d,color:#fff침해 지표 (IOC) 항목 값 C2 도메인 sfrclak.com C2 IP 142.11.206.73 C2 포트 8000 악성 npm 계정 nrwise (nrwise@proton.me) 악성 패키지 plain-crypto-js@4.2.1 탈취된 계정 이메일 ifstap@proton.me 추가 감염 패키지 동일 악성코드를 배포하는 추가 패키지도 확인되었습니다:\n@shadanai/openclaw (버전 2026.3.28-2, 2026.3.28-3, 2026.3.31-1, 2026.3.31-2) @qqbrowser/openclaw-qbot@0.0.130 (변조된 axios@1.14.1을 node_modules에 포함) 사건 대응 경과 GitHub issue axios/axios#10604에서 실시간으로 상황이 공유되었습니다. 다른 협력자 DigitalBrainJS는 jasonsaayman의 권한이 더 높아 직접 대응이 불가능한 상황이었으며, npm 관리팀에 전체 토큰 폐기를 요청한 뒤에야 상황이 수습되었습니다.\n2. LiteLLM 공급망 공격 (2026-03-24) 배경: TeamPCP 연쇄 공격 이 사건은 TeamPCP 해킹 그룹이 벌인 연쇄 공급망 공격 캠페인의 일부였습니다. 시작점은 보안 스캐너 Trivy였습니다.\n날짜 대상 2026-02-28 Trivy 저장소 초기 침투 2026-03-19 Trivy GitHub Actions 태그 76개 변조 2026-03-20 npm 패키지 28개 이상 탈취 2026-03-21 Checkmarx KICS GitHub Action 침해 2026-03-24 LiteLLM PyPI 패키지 침해 LiteLLM은 CI/CD 보안 스캔에 Trivy를 버전 고정 없이 사용하고 있었고, 변조된 Trivy가 실행되면서 PyPI 배포 토큰이 공격자에게 넘어갔습니다.\n공격 방식 공격자는 탈취한 PyPI 토큰으로 litellm v1.82.7(10:39 UTC)과 v1.82.8(10:52 UTC)을 직접 업로드했습니다.\n핵심 공격 벡터는 .pth 파일이었습니다. Python의 .pth 파일은 site-packages에 위치하면 Python 인터프리터 시작 시 자동 실행되는 특성이 있어, import litellm 없이도 해당 환경에서 Python을 실행하기만 하면 악성 코드가 동작합니다.\n# litellm_init.pth (34,628 bytes) - 한 줄짜리 코드 import os, subprocess, sys; subprocess.Popen([sys.executable, \u0026#34;-c\u0026#34;, \u0026#34;import base64; exec(base64.b64decode(\u0026#39;...\u0026#39;))\u0026#34;]) 디코딩된 페이로드는 332줄짜리 인증 정보 수집 스크립트로, 다음을 수집했습니다:\nSSH 키 (RSA, Ed25519, ECDSA, DSA 등 전 유형) AWS/GCP/Azure 클라우드 인증 정보 (인스턴스 메타데이터 포함) 쿠버네티스 서비스 계정 토큰 및 시크릿 PostgreSQL, MySQL, Redis, MongoDB 설정 파일 비트코인, 이더리움, 솔라나 등 암호화폐 지갑 .bash_history, .zsh_history 등 셸 히스토리 수집된 데이터는 AES-256-CBC + RSA-4096으로 이중 암호화되어 https://models.litellm.cloud/로 전송되었습니다. 이 도메인은 공격 하루 전에 등록된 사칭 도메인이었습니다.\n피해 규모 월간 다운로드: ~9,700만 건 (하루 ~340만 건) PyPI 노출 시간: 약 3시간 클라우드 환경 존재율: ~36% (Wiz Research 분석) 영향받은 하류 프로젝트: DSPy(스탠퍼드), CrewAI, Google ADK, browser-use 등 발각 경위 공교롭게도 공격자의 버그로 발각되었습니다. .pth 파일이 Python 시작 시마다 자식 프로세스를 생성하고, 그 자식이 다시 .pth를 실행하는 포크 폭탄 구조가 되어 메모리가 급격히 고갈되었습니다. FutureSearch.ai의 Callum McMahon이 이 이상 현상을 발견하고 이슈를 등록했으나, 공격자는 봇넷 73개를 동원해 102초간 스팸 댓글 88개를 쏟아부어 이슈를 묻으려 시도했습니다.\nAndrej Karpathy는 이 사건을 **\u0026ldquo;software horror\u0026rdquo;**라고 평했습니다.\nLiteLLM 감염 확인 방법 # 설치된 버전 확인 — 1.82.7 또는 1.82.8이면 감염 pip show litellm | grep Version # .pth 파일 존재 여부 find / -name \u0026#34;litellm_init.pth\u0026#34; 2\u0026gt;/dev/null # 백도어 확인 ls ~/.config/sysmon/sysmon.py 2\u0026gt;/dev/null ls ~/.config/systemd/user/sysmon.service 2\u0026gt;/dev/null # Kubernetes 환경 kubectl get pods -n kube-system | grep node-setup 3. Claude Code 소스 유출 같은 시기에 npm 보안과 관련된 또 다른 사건이 보고되었습니다. Anthropic의 Claude Code CLI 소스 코드가 npm 레지스트리에 포함된 .map 파일(소스맵)을 통해 전체 복원 가능한 형태로 유출되었습니다.\n이 사건은 악의적 공격은 아니었지만, npm 패키지 배포 시 .map 파일이 포함되면 난독화/번들링된 코드의 원본 소스가 그대로 노출될 수 있다는 점을 보여주는 사례입니다. .npmignore나 files 필드 설정의 중요성을 다시 한번 상기시켜 줍니다.\n4. 공통 교훈과 대응 세 사건의 공통 패턴 세 사건 모두 패키지 레지스트리(npm/PyPI)에 대한 신뢰를 악용한 공격입니다:\n패턴 axios LiteLLM Claude Code 공격 경로 npm 계정 탈취 PyPI 토큰 탈취 (via Trivy) 소스맵 미제거 레지스트리 npm PyPI npm CI/CD 우회 직접 퍼블리시 직접 퍼블리시 N/A 악성 동작 postinstall RAT .pth 자동실행 소스 노출 은폐 시도 package.md 교체 봇넷 스팸 없음 즉시 대응 체크리스트 npm (axios) 대응 # 1. 감염 버전 확인 npm ls axios # 2. 안전 버전으로 고정 npm install axios@1.14.0 # 3. lockfile 커밋 git add package-lock.json \u0026amp;\u0026amp; git commit -m \u0026#34;fix: pin axios to safe version\u0026#34; # 4. 보안 감사 npm audit # 5. IOC 네트워크 확인 # sfrclak.com 또는 142.11.206.73으로의 아웃바운드 연결 확인 PyPI (LiteLLM) 대응 # 1. 안전 버전으로 고정 pip install \u0026#34;litellm\u0026lt;=1.82.6\u0026#34; # 2. 감염 시 시크릿 전체 로테이션 # SSH 키, AWS/GCP/Azure 인증 정보, DB 비밀번호, API 키 전부 교체 장기 방어 조치 버전 핀 고정: ^이나 ~ 대신 정확한 버전 사용. lockfile은 반드시 커밋. postinstall 스크립트 차단: CI/CD에서 npm install --ignore-scripts 적용 고려. MFA 필수화: npm/PyPI 메인테이너 계정에 TOTP 기반 2FA 활성화. 토큰 수명 관리: 장기 유효 토큰 대신 OIDC 기반 단기 토큰 사용. 정기적으로 로테이션. CI/CD 도구 버전 고정: LiteLLM이 Trivy를 버전 고정 없이 쓴 것이 화근. 보안 스캐너도 예외 아님. 소스맵 제거: 프로덕션 npm 패키지에 .map 파일 포함 여부 확인. 의존성 모니터링: Socket, Snyk, npm audit 등으로 공급망 지속 감시. 인사이트 일주일 사이에 npm과 PyPI에서 동시다발적으로 터진 이 사건들은 몇 가지 불편한 진실을 드러냅니다.\n첫째, 메인테이너가 단일 실패점(SPOF)이다. axios의 경우 한 명의 계정이 뚫리자 두 릴리스 브랜치가 39분 만에 감염되었고, 다른 협력자는 권한이 부족해 아무것도 할 수 없었습니다. npm/PyPI의 OIDC 기반 퍼블리시가 아직 널리 채택되지 않은 현실에서, 장기 유효 토큰은 시한폭탄입니다.\n둘째, 보안 도구도 공격 벡터가 된다. LiteLLM 사건에서 보안 스캐너 Trivy가 오히려 공격의 진입점이 되었습니다. CI/CD 파이프라인에서 apt-get install -y trivy처럼 버전 고정 없이 도구를 설치하는 패턴은, 편의성을 위해 보안을 포기하는 것과 같습니다.\n셋째, 공격자는 점점 정교해지고 있다. axios 공격에서 18시간 전 페이로드 스테이징과 자기 은폐 메커니즘, LiteLLM 공격에서 봇넷을 동원한 이슈 은폐 시도와 AI 에이전트를 활용한 취약점 스캐닝까지 — 공급망 공격이 산업화되고 있습니다.\n결론적으로, npm install이나 pip install 한 줄이 실행되는 순간 우리는 수천 명의 메인테이너를 신뢰하는 것입니다. lockfile 커밋, 버전 핀 고정, --ignore-scripts, 토큰 로테이션 같은 기본적인 위생 조치가 그 어느 때보다 중요해졌습니다.\n","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-npm-supply-chain-attacks/cover.jpg","permalink":"/ko/posts/2026-04-01-npm-supply-chain-attacks/","title":"2026년 npm 공급망 공격 총정리 — axios, LiteLLM, 그리고 교훈"},{"content":"2024~2025년까지 AI 에이전트를 만들려면 프레임워크 선택부터 RAG 파이프라인, 상태 관리까지 직접 구축해야 했다. 하지만 2026년 현재, Claude Agent SDK와 Codex SDK 같은 \u0026ldquo;batteries-included\u0026rdquo; SDK가 등장하면서 에이전트 구축의 출발점 자체가 바뀌고 있다. 이번 포스트에서는 에이전트 아키텍처의 Old vs New 패러다임 전환과 RAG의 역할 변화를 분석한다. 관련 포스트: Excalidraw 다이어그램 스킬, NotebookLM 실전 활용법\n1. Old vs New: 에이전트 구축 패러다임의 전환 기존 방식 (2024~2025) 전통적인 에이전트 구축 흐름은 다음과 같았다:\n프레임워크 선택 — LangChain, LangGraph, Pydantic AI, N8N 등에서 하나를 고른다 도구 정의 — 파일 시스템 접근, 이메일 조회 등 에이전트 capability를 직접 구현한다 RAG 구성 — chunking, embedding, retrieval 전략을 설계하고 벡터 DB에 연결한다 에이전트 루프 구축 — 상태 관리, 대화 기록 저장, 메모리 시스템까지 직접 배선한다 이 방식의 핵심 문제는 glue code가 너무 많다는 것이다. DB 테이블 설계, 세션 관리, ingestion pipeline 등 에이전트의 \u0026ldquo;지능\u0026quot;과 무관한 인프라 코드가 전체 코드베이스의 상당 부분을 차지했다.\n새로운 방식: SDK-First Claude Agent SDK나 Codex SDK를 기반으로 구축하면 상황이 완전히 달라진다:\n대화 기록 관리가 SDK에 내장되어 있어 별도 DB 불필요 파일 검색 도구(Grep, Read 등)가 이미 포함되어 있어 소규모 지식 베이스에 RAG가 불필요 Skills와 MCP 서버로 도구를 재사용 가능한 형태로 추가 Sub-agent, Hooks, 권한 설정까지 단일 TypeScript/Python 파일에서 선언적으로 구성 실제로 Claude Agent SDK를 사용하면 이전보다 더 많은 기능을 더 적은 코드로 구현할 수 있다. Second Brain 시스템처럼 메모리 구축, 일일 리플렉션, 통합 관리까지 하나의 SDK 위에서 동작한다.\n아키텍처 비교 flowchart LR subgraph OLD[\"기존 방식 (Framework)\"] direction TB A1[\"프레임워크 선택\u0026lt;br/\u0026gt;LangChain / Pydantic AI\"] --\u003e A2[\"도구 직접 정의\u0026lt;br/\u0026gt;Tool functions\"] A2 --\u003e A3[\"RAG 파이프라인\u0026lt;br/\u0026gt;Chunking + Embedding + VectorDB\"] A3 --\u003e A4[\"에이전트 루프\u0026lt;br/\u0026gt;State / Memory / DB\"] end subgraph NEW[\"새로운 방식 (SDK-First)\"] direction TB B1[\"Claude Agent SDK\u0026lt;br/\u0026gt;Codex SDK\"] --\u003e B2[\"Skills + MCP 서버\u0026lt;br/\u0026gt;재사용 가능한 도구\"] B2 --\u003e B3[\"파일 검색 내장\u0026lt;br/\u0026gt;Grep / Read / Glob\"] B3 --\u003e B4[\"Sub-agents + Hooks\u0026lt;br/\u0026gt;선언적 구성\"] end OLD -- \"전환\" --\u003e NEW언제 프레임워크가 여전히 필요한가? SDK-First가 만능은 아니다. 다음 세 가지 한계가 명확하다:\n기준 SDK (Claude Agent SDK 등) 프레임워크 (Pydantic AI 등) 속도 추론 오버헤드로 느림 (10초+) Sub-second 응답 가능 비용 토큰 소모 큼, 다수 사용자 시 API 비용 폭증 직접 제어로 비용 최적화 제어권 대화 기록/관찰성 제한적 모든 것을 직접 관리 판단 기준은 두 가지다:\n누가 쓰는가? — 본인만 쓰면 SDK, 다수가 프로덕션에서 쓰면 프레임워크 속도/규모 요구사항은? — 지연 허용이면 SDK, 빠른 응답이 필수면 프레임워크 실무적으로는 SDK로 프로토타이핑 후 검증된 워크플로를 프레임워크로 이식하는 패턴이 가장 현실적이다. Skills와 MCP 서버는 양쪽 모두에서 재사용 가능하므로 전환 비용이 낮다.\nRAG는 죽었는가? 결론부터 말하면 아니다 — 하지만 역할이 바뀌었다.\n소규모 코드/문서: 파일 검색(Grep)이 semantic search를 능가한다는 것이 증명됨 (LlamaIndex 연구) 대규모 지식 베이스: 여전히 벡터 DB 기반 RAG가 필요 — 수천 개 문서를 Grep으로 탐색하는 건 비현실적 Skills가 RAG를 대체하는 영역: 코드 컨텍스트 작업에서 skill.md가 chunking + embedding을 대체. 에이전트가 필요할 때 스킬을 로드하면 충분 핵심은 \u0026ldquo;RAG냐 아니냐\u0026quot;가 아니라, 지식의 규모와 접근 패턴에 맞는 검색 전략을 선택하는 것이다.\n인사이트 에이전트 구축의 본질이 변하고 있다. \u0026ldquo;어떤 프레임워크를 쓸까?\u0026ldquo;에서 \u0026ldquo;에이전트에게 어떤 Skills를 줄까?\u0026ldquo;로 질문이 이동했다. SDK가 인프라를 추상화하면서, 개발자의 시간은 glue code가 아니라 에이전트의 능력 설계에 집중된다.\n선언적 도구 구성의 승리 — Skills, MCP 서버 모두 \u0026ldquo;이것을 할 수 있다\u0026quot;를 선언하는 방식이다. 절차적으로 에이전트 루프를 짜는 시대에서 벗어나고 있다. SDK로 프로토타이핑, 프레임워크로 프로덕션 — 이 패턴이 가장 현실적이다. Skills와 MCP는 양쪽에서 재사용 가능하므로 전환 비용이 낮다. RAG는 사라지는 게 아니라 민주화되고 있다 — 개발자는 파일 검색과 Skills로 RAG를 대체하고, 비개발자는 NotebookLM으로 코드 없이 동일한 효과를 얻는다. 이 주제의 실전 적용은 별도 포스트에서 다룬다:\nExcalidraw 다이어그램 스킬 — 코딩 에이전트의 시각적 논증 NotebookLM 실전 활용법 12가지 참고 영상:\nEverything You Thought About Building AI Agents is Wrong — Cole Medin ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-ai-agent-paradigm/cover.jpg","permalink":"/ko/posts/2026-04-01-ai-agent-paradigm/","title":"AI 에이전트 구축의 새로운 패러다임 — 프레임워크에서 SDK-First로"},{"content":"Claude Code는 그 자체로 강력하지만, MCP 서버를 연결하면 브라우저 제어, 웹 크롤링, 최신 문서 참조, 데이터베이스 조작까지 가능해진다. 이 포스트에서는 실무에서 바로 쓸 수 있는 MCP 서버 네 가지를 설치 방법과 실전 프롬프트 포함하여 정리한다. AI 사용성연구소의 영상 \u0026ldquo;클로드 코드 고수들은 이미 쓰고 있는 MCP 4가지 | EP.02\u0026ldquo;를 참고했다.\nMCP란 무엇인가 — 스마트폰 비유 MCP(Model Context Protocol)를 이해하는 가장 쉬운 방법은 스마트폰 비유다.\n스마트폰을 처음 샀을 때를 떠올려 보자. 하드웨어 자체는 훌륭하지만, 앱을 설치하기 전에는 전화와 문자 정도밖에 할 수 없다. 카카오톡도 없고, 네이버 지도도 없고, 유튜브도 없다. 앱을 설치하는 순간 비로소 스마트폰이 진짜 \u0026ldquo;스마트\u0026quot;해진다.\nClaude Code도 똑같다.\n비유 실제 스마트폰 Claude Code 앱스토어에서 앱 설치 MCP 서버 연결 USB-C 케이블 (표준 규격) MCP (표준 프로토콜) 앱이 알아서 알림을 보냄 Claude가 맥락에 맞게 MCP를 자동 선택 MCP는 Claude Code에 외부 도구를 연결해 주는 표준 규격이다. USB-C 케이블처럼 하나의 프로토콜로 수백 가지 도구를 연결할 수 있다.\n작동 원리 flowchart LR A[\"사용자\u0026lt;br/\u0026gt;프롬프트 입력\"] --\u003e B[\"Claude Code\u0026lt;br/\u0026gt;맥락 판단\"] B --\u003e C[\"MCP 서버\u0026lt;br/\u0026gt;자동 선택\"] C --\u003e D[\"외부 도구\u0026lt;br/\u0026gt;실행\"] D --\u003e E[\"결과 정리\u0026lt;br/\u0026gt;사용자에게 반환\"]핵심은 사용자가 MCP를 직접 호출할 필요가 없다는 점이다. 카카오톡을 설치해 두면 메시지가 올 때 자동으로 알림이 오듯, MCP를 설치해 두면 Claude가 \u0026ldquo;이건 브라우저를 열어야 하는 일이구나\u0026rdquo; 하고 알아서 Playwright를 쓴다.\n단, 특정 MCP를 강제 발동시키고 싶으면 프롬프트에 명시하는 것이 더 확실하다.\nMCP 설치 후 반드시 재시작 MCP를 설치한 뒤에는 Claude Code를 껐다 켜야 한다. /exit 후 다시 claude를 실행하면 된다.\n1. Playwright MCP — 브라우저를 직접 제어하는 손과 발 어떤 MCP인가 Playwright MCP는 Claude가 직접 브라우저를 열고 클릭하고 입력하는 것을 가능하게 한다. 웹사이트 접속, 버튼 클릭, 폼 입력, 스크린샷 촬영까지 — 평소 우리가 브라우저에서 하는 모든 것을 Claude가 대신 해준다.\n설치 Claude Code 안에서 자연어로 설치할 수 있다:\n플레이라이트 MCP 설치해 줘 또는 터미널에서 직접:\nclaude mcp add playwright -- npx @anthropic-ai/mcp-playwright 활용 시나리오 QA 테스트: 내가 만든 웹사이트를 Claude가 직접 브라우저에서 열어 테스트 데이터 수집: 네이버 지도에서 맛집 검색 후 구글 시트에 정리 API 키 발급 대행: Firecrawl 같은 서비스의 웹사이트를 열어 API 키 발급까지 보조 시각적 검증: 스크린샷을 찍어 레이아웃이 맞는지 스스로 판단 실전 프롬프트 플레이라이트 MCP를 써서 네이버 지도에서 \u0026#34;강남역 맛집\u0026#34;을 검색하고, 평점이 좋은 곳 10개를 구글 시트에 정리해 줘. 항목: 가게명, 평점, 리뷰 수, 주소 내가 만든 웹사이트 http://localhost:3000 을 Playwright로 열어서 모든 페이지의 링크가 정상 작동하는지 QA 테스트해 줘. 깨진 링크가 있으면 목록으로 정리해 줘. Playwright는 한 페이지씩 직접 탐색하므로, 대량 크롤링보다는 정밀한 상호작용에 적합하다.\n2. Firecrawl MCP — 대규모 웹 크롤링의 끝판왕 어떤 MCP인가 Playwright가 한 페이지씩 직접 클릭하며 탐색한다면, Firecrawl은 웹사이트 전체를 한 번에 크롤링한다. 긁어온 내용을 Markdown이나 JSON 같은 정리된 형태로 변환해 주며, AI 기반 분석까지 내장되어 있다.\n설치 Firecrawl은 API 키가 필요하다. 무료 티어로 약 2,000회 크롤링이 가능하다.\n# API 키 발급: https://firecrawl.dev 에서 가입 후 발급 claude mcp add firecrawl -- npx firecrawl-mcp --api-key YOUR_API_KEY 또는 Claude Code 안에서:\n파이어크롤 MCP를 설치해 줘 API 키 발급이 어려우면 Playwright MCP에게 대행을 맡길 수도 있다:\n플레이라이트를 써서 firecrawl.dev에 접속해서 API 키 발급받는 방법 알려 줘. 네가 직접 진행해 줘. Playwright vs Firecrawl 항목 Playwright Firecrawl 방식 한 페이지씩 직접 제어 사이트 전체 일괄 크롤링 속도 느림 (상호작용 포함) 빠름 (대량 처리 최적화) 출력 스크린샷, DOM 접근 Markdown, JSON, CSV 적합한 작업 QA 테스트, 폼 입력 데이터 수집, 경쟁사 분석 비용 무료 무료 티어 (2,000회) 실전 프롬프트 파이어크롤 MCP를 써서 toss.tech 블로그에서 최신 아티클 10개를 수집해 줘. 수집 항목: 제목, 작성자, 카테고리, 요약, URL 최신 순서로 정렬해서 CSV 파일로 만들어 줘. 무신사 랭킹 페이지(https://www.musinsa.com/ranking)에서 1위부터 50위까지 크롤링해 줘. 수집 항목: 순위, 브랜드명, 상품명, 할인율, 판매 가격, 상품 URL 엑셀 파일로 정리하고 이미지 URL도 포함해 줘. Firecrawl에 대한 더 깊은 분석은 별도 포스트 Firecrawl — AI 시대의 웹 스크래핑 끝판왕에서 다룬다.\n3. Context7 MCP — 최신 공식 문서를 실시간 참조 어떤 MCP인가 AI에게 코드를 부탁하면 가끔 \u0026ldquo;그런 함수 없는데?\u0026ldquo;라는 상황이 발생한다. AI의 학습 데이터에는 유통 기한이 있기 때문이다. 예를 들어 Next.js가 15로 업데이트되었는데 Claude가 13 버전 문법으로 코드를 짜고 있는 상황.\nContext7 MCP는 이 문제를 근본적으로 해결한다. 프롬프트를 입력하면 해당 라이브러리의 현재 최신 공식 문서를 실시간으로 가져와서 Claude에게 보여 준다. 학습 데이터가 아니라 실제 공식 문서를 보고 코드를 짜게 만드는 것이다.\n설치 무료이며 API 키가 필요 없다.\nclaude mcp add context7 -- npx @context7/mcp 또는:\n컨텍스트7 MCP 설치해 줘 실전 프롬프트 Next.js의 App Router를 사용해서 블로그 목록 페이지의 서버 컴포넌트를 만들어 줘. use context7 Prisma ORM으로 PostgreSQL 연결하는 코드 작성해 줘. 최신 문서 기준으로 use context7 Tailwind CSS v4의 새로운 설정 방식으로 다크 모드 구현해 줘. use context7 CLAUDE.md에 \u0026ldquo;컨텍스트7 MCP를 써서 최신 문서를 참조해라\u0026quot;고 지시를 넣어 두면, 매번 프롬프트에 명시하지 않아도 자동으로 최신 문서를 참조하게 할 수 있다.\n4. Supabase MCP — 데이터베이스를 자연어로 제어 어떤 MCP인가 Supabase MCP는 Claude가 데이터베이스를 직접 조작할 수 있게 해준다. 테이블 생성, 데이터 삽입, 쿼리 실행, 스키마 변경까지 — SQL을 몰라도 자연어로 데이터베이스를 다룰 수 있다.\n설치 Supabase 프로젝트의 연결 정보가 필요하다.\nclaude mcp add supabase -- npx @supabase/mcp-server \\ --supabase-url https://YOUR_PROJECT.supabase.co \\ --supabase-key YOUR_SERVICE_ROLE_KEY 또는:\n수파베이스 MCP 설치해 줘. 내 프로젝트 URL은 https://xxx.supabase.co 이고 서비스 롤 키는 eyJ... 야. 활용 시나리오 테이블 설계: \u0026ldquo;회원, 주문, 상품 테이블을 만들어 줘. 관계 설정까지.\u0026rdquo; 데이터 마이그레이션: CSV 데이터를 Supabase 테이블에 일괄 삽입 RLS 정책 설정: Row Level Security를 자연어로 설정 크롤링 → DB 저장: Firecrawl로 수집한 데이터를 바로 DB에 저장 실전 프롬프트 Supabase에 블로그 시스템용 테이블을 만들어 줘. - posts: id, title, content, author_id, created_at, published - comments: id, post_id, user_id, body, created_at - users: id, email, display_name, avatar_url 외래 키 관계까지 설정하고, RLS 정책도 추가해 줘. 크롤링해서 만든 products.csv를 Supabase의 products 테이블에 일괄 삽입해 줘. 중복 상품명은 건너뛰고 새로운 것만 추가해. MCP 조합의 진짜 위력 MCP의 진정한 가치는 여러 개를 조합할 때 나타난다. Claude Code에 MCP를 여러 개 연결해 두면, Claude가 상황에 맞게 자동으로 적절한 MCP를 선택한다.\nflowchart TD A[\"사용자 요청\u0026lt;br/\u0026gt;경쟁사 강의 분석해 줘\"] --\u003e B[\"Claude Code\u0026lt;br/\u0026gt;작업 분해\"] B --\u003e C[\"Firecrawl MCP\u0026lt;br/\u0026gt;5개 플랫폼 크롤링\"] B --\u003e D[\"Context7 MCP\u0026lt;br/\u0026gt;분석 프레임워크 참조\"] C --\u003e E[\"수집 데이터\u0026lt;br/\u0026gt;통합 정리\"] D --\u003e E E --\u003e F[\"Supabase MCP\u0026lt;br/\u0026gt;DB 저장\"] E --\u003e G[\"분석 보고서\u0026lt;br/\u0026gt;엑셀 출력\"]조합 예시: 경쟁사 강의 분석 1단계 — 데이터 수집 (Firecrawl): 아래 교육 플랫폼에서 \u0026#34;클로드 코드\u0026#34; 관련 강의를 크롤링해 줘. - 인프런, 패스트캠퍼스, 클래스101, 콜로소, 러닝스푼즈 수집 항목: 강의명, 강사명, 가격, 수강생 수, 리뷰 수, 평점, URL 2단계 — 분석: 수집한 데이터를 기반으로 단계별 분석을 진행해 줘. - 강점/약점 비교 - 가격대별 포지셔닝 - 시장에 비어 있는 포지션 분석 최종 출력은 엑셀 파일로. 추천 MCP 설정 요약 flowchart LR subgraph FREE[\"무료\"] P[\"Playwright\u0026lt;br/\u0026gt;브라우저 제어\"] C7[\"Context7\u0026lt;br/\u0026gt;최신 문서 참조\"] end subgraph FREEMIUM[\"무료 티어\"] FC[\"Firecrawl\u0026lt;br/\u0026gt;웹 크롤링\"] SB[\"Supabase\u0026lt;br/\u0026gt;DB 제어\"] end P --\u003e |\"QA, 폼 입력\"| USE[\"실무 활용\"] C7 --\u003e |\"최신 API 코딩\"| USE FC --\u003e |\"대량 데이터 수집\"| USE SB --\u003e |\"데이터 저장/조회\"| USE MCP 용도 비용 API 키 Playwright 브라우저 제어, QA 무료 불필요 Firecrawl 웹 크롤링, 데이터 수집 무료 2,000회 필요 Context7 최신 공식 문서 참조 무료 불필요 Supabase 데이터베이스 조작 무료 티어 필요 인사이트 MCP는 Claude Code의 \u0026ldquo;앱 생태계\u0026quot;다. 스마트폰이 앱 없이는 전화기에 불과하듯, Claude Code도 MCP 없이는 텍스트 생성기에 불과하다. MCP를 연결하는 순간 Claude는 브라우저를 제어하고, 웹을 크롤링하고, 최신 문서를 읽고, 데이터베이스를 조작하는 진짜 에이전트가 된다.\n특히 인상적인 점은 진입 장벽의 낮음이다. \u0026ldquo;플레이라이트 MCP 설치해 줘\u0026quot;라는 한 문장이면 설치가 끝나고, 설치 후에는 명시적으로 호출하지 않아도 Claude가 맥락에 맞게 자동으로 적절한 MCP를 선택한다. 비개발자도 자연어만으로 브라우저 자동화, 웹 크롤링, 데이터베이스 조작이 가능해지는 것이다.\n한 가지 실전 팁: MCP를 강제 발동시키고 싶으면 프롬프트에 MCP 이름을 명시하는 것이 확실하다. \u0026ldquo;플레이라이트를 써서\u0026rdquo;, \u0026ldquo;파이어크롤로\u0026rdquo;, \u0026ldquo;use context7\u0026quot;처럼 직접 지정하면 의도한 도구가 발동될 확률이 높아진다.\n앞으로 Notion MCP, Figma MCP, Linear MCP 등 더 많은 MCP가 생태계에 추가될수록, Claude Code는 단순한 코딩 도구를 넘어 범용 업무 자동화 플랫폼으로 진화할 것이다.\n","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-claude-code-mcp-4/cover.jpg","permalink":"/ko/posts/2026-04-01-claude-code-mcp-4/","title":"Claude Code MCP 서버 필수 4종 가이드 — Playwright부터 Firecrawl까지"},{"content":"개요 Claude Code 실전 가이드 시리즈의 네 번째 글입니다. 이전 글에서는 컨텍스트 관리와 워크플로우(1편), 최신 기능 정복(2편), 500시간 사용자의 27가지 팁(3편)을 다뤘습니다.\n이번 편에서는 두 가지 핵심 주제를 다룹니다. 첫째, Anthropic이 공식 출시한 Claude Code auto-fix 기능으로 PR 생성부터 CI 실패 해결, 리뷰 코멘트 반영까지 자동화하는 방법. 둘째, Cole Medin이 공개한 Self-Healing AI Coding Workflow로 코딩 에이전트가 자기 작업을 시각적으로 검증하고 스스로 버그를 수정하는 프로세스입니다.\n전체 워크플로우 개요 아래 다이어그램은 auto-fix와 Self-Healing 워크플로우가 개발 사이클에서 어떻게 연결되는지 보여줍니다.\nflowchart TD A[\"개발자가 코드 작성\"] --\u003e B[\"PR 생성\"] B --\u003e C{\"CI 통과?\"} C -- Yes --\u003e D[\"리뷰어 코멘트\"] C -- No --\u003e E[\"auto-fix가 \u0026lt;br/\u0026gt; CI 로그 분석 \u0026lt;br/\u0026gt; 자동 수정\"] E --\u003e C D --\u003e F[\"auto-fix가 \u0026lt;br/\u0026gt; 코멘트 반영 \u0026lt;br/\u0026gt; 코드 수정\"] F --\u003e C B --\u003e G[\"Self-Healing \u0026lt;br/\u0026gt; 워크플로우 실행\"] G --\u003e H[\"3개 서브 에이전트 \u0026lt;br/\u0026gt; 병렬 리서치\"] H --\u003e I[\"E2E 테스트 \u0026lt;br/\u0026gt; + 시각적 검증\"] I --\u003e J{\"블로커 발견?\"} J -- Yes --\u003e K[\"자동 수정 \u0026lt;br/\u0026gt; + 재테스트\"] K --\u003e I J -- No --\u003e L[\"검증 리포트 생성\"]1. Claude Code auto-fix: 원격 자동 수정의 시대 PR 자동 추적과 CI 실패 해결 Claude Code auto-fix는 웹이나 모바일 환경에서 Pull Request를 자동으로 추적하고, CI 실패를 감지해 스스로 해결하는 기능입니다. 핵심은 모든 작업이 원격으로 진행된다는 점입니다. 개발자가 PR을 올리고 자리를 비워도, 돌아오면 CI가 통과된 상태의 PR을 확인할 수 있습니다.\n작동 방식은 다음과 같습니다. auto-fix는 GitHub Actions 로그를 가져와 실패 원인을 정확히 진단합니다. 빌드 오류인지 lint 에러인지, 코드의 문제인지 인프라의 문제인지를 구분합니다. PHP 메모리 부족 같은 흔한 인프라 오류에 대해서는 해결 템플릿도 갖추고 있어 불필요한 코드 수정을 방지합니다.\n세 가지 사용 방법 auto-fix를 활용하는 구체적인 방법은 세 가지입니다:\n웹 버전: Claude Code 웹에서 생성한 PR의 CI 메뉴에서 auto-fix를 선택 모바일: AI 에이전트에게 직접 auto-fix를 지시 (모바일용 빠른 실행 버튼도 추가 예정) PR 링크 붙여넣기: 모니터링하고 싶은 PR 링크를 복사해서 에이전트에게 auto-fix 요청 사용을 시작하려면 Claude GitHub App을 설치해야 하며, 자동 수정 기능을 쓰려면 저장소 설정에서 이를 활성화해야 합니다.\n보안 시스템 자율적으로 코드를 수정하는 기능인 만큼 보안이 중요합니다. auto-fix는 Claude Sonnet 4.6 기반의 **독립적인 안전 분류기(safety classifier)**를 사용합니다. 이 분류기의 특징은 AI의 내부 추론 과정을 보지 않고 요청만 검사한다는 점입니다. 즉, 프롬프트 인젝션으로 내부 로직을 우회하더라도 실제 실행되는 액션 자체를 별도로 검증합니다. 권한을 넘어서는 작업이나 민감한 데이터 유출은 원천적으로 차단됩니다.\n# .github/settings.yml 예시 — auto-fix 활성화 claude_code: auto_fix: enabled: true on_ci_failure: true # CI 실패 시 자동 수정 on_review_comment: true # 리뷰 코멘트 반영 allowed_branches: - \u0026#34;feature/*\u0026#34; - \u0026#34;fix/*\u0026#34; 2. Self-Healing 워크플로우: 에이전트가 스스로 검증하는 시대 Cole Medin의 접근법 Cole Medin이 \u0026ldquo;This One Command Makes Coding Agents Find All Their Mistakes\u0026quot;에서 공개한 Self-Healing 워크플로우는 핵심 문제를 정확히 짚습니다: 코딩 에이전트는 코드를 빠르게 생성하지만, 자기 작업을 검증하는 데는 형편없습니다. 개발자가 프레임워크를 제공하지 않으면 검증을 대충 넘기거나 아예 건너뛰기 때문입니다.\n이 워크플로우는 Claude Code의 skill(커맨드) 형태로 패키징되어 있으며, /e2e-test 명령 하나로 6단계 프로세스가 시작됩니다. 프론트엔드가 있는 거의 모든 코드베이스에서 즉시 사용할 수 있습니다.\n6단계 검증 프로세스 Phase 0 - 사전 점검: Vercel Agent Browser CLI 설치 여부, OS 환경(Windows면 WSL 필요) 등을 확인합니다.\nPhase 1 - 리서치: 3개의 서브 에이전트가 병렬로 실행됩니다:\n코드베이스 구조 파악 + 사용자 여정(user journey) 식별 데이터베이스 스키마 분석 코드 리뷰 (로직 에러 탐색) Phase 2 - 테스트 계획: 리서치 결과를 바탕으로 task list를 정의합니다. 각 task가 하나의 사용자 여정입니다.\nPhase 3 - E2E 테스트 루프: 각 사용자 여정을 순서대로 실행하며, Agent Browser CLI로 페이지를 탐색하고 DB 쿼리로 백엔드 상태를 검증합니다.\n# Vercel Agent Browser CLI 사용 예시 npx @anthropic-ai/agent-browser snapshot # 현재 페이지 상태 캡처 npx @anthropic-ai/agent-browser click \u0026#34;Sign In\u0026#34; npx @anthropic-ai/agent-browser screenshot ./screenshots/login.png Phase 4 - 자가 수정: 블로커 이슈만 자동 수정하고 재테스트합니다. 중요한 설계 철학은 모든 이슈를 고치지 않는다는 것입니다. 큰 블로커만 수정해서 테스트를 계속 진행할 수 있게 하고, 나머지는 리포트에 남겨서 개발자가 판단합니다.\nPhase 5 - 리포트: 구조화된 형식으로 결과를 출력합니다 \u0026ndash; 수정한 사항, 남은 이슈, 전체 테스트 경로. 스크린샷과 함께 리뷰하면 에이전트가 실제로 어떤 경로를 테스트했는지 빠르게 확인할 수 있습니다.\n시각적 검증의 힘 이 워크플로우에서 가장 인상적인 부분은 스크린샷 기반 시각적 검증입니다. 에이전트가 각 단계마다 스크린샷을 촬영하고, AI의 이미지 분석 능력으로 UI가 정상인지 확인합니다. 이는 단순히 \u0026ldquo;에러가 없으면 통과\u0026rdquo; 수준을 넘어, 실제 사용자가 보는 화면이 의도대로 렌더링되는지까지 검증하는 것입니다.\n또한 반응형 검증도 포함되어 있어 모바일, 태블릿, 데스크톱 뷰포트에서 페이지가 정상적으로 보이는지 가볍게 확인합니다. 전통적인 E2E 테스트 프레임워크(Cypress, Playwright)로는 구현하기 어려운 \u0026ldquo;눈으로 보고 판단하는\u0026rdquo; 검증을 AI가 대신하는 셈입니다.\n실전 활용 팁 이 워크플로우는 두 가지 방식으로 사용할 수 있습니다:\n독립 실행: 임의의 시점에 전체 E2E 테스트를 돌리고 싶을 때 기능 구현 파이프라인에 통합: 에이전트가 기능을 구현한 직후 자동으로 regression testing 실행 컨텍스트 윈도우가 커지므로, 테스트 완료 후 리포트를 새 세션에 넘겨서 후속 작업을 하는 것이 권장됩니다.\n인사이트 auto-fix와 Self-Healing은 같은 방향을 가리킵니다. 코드 생성 속도가 검증 속도를 압도하는 시대에서, 검증 자체를 자동화하는 것이 핵심 과제입니다. auto-fix는 CI/리뷰라는 기존 인프라에 AI를 얹은 방식이고, Self-Healing은 브라우저 자동화로 사용자 관점의 검증까지 확장한 방식입니다.\n실무에서 두 접근을 함께 쓰면 강력합니다. Self-Healing 워크플로우로 로컬에서 사전 검증을 마치고, PR을 올린 뒤에는 auto-fix가 CI 실패와 리뷰 코멘트를 자동 처리합니다. 개발자는 최종 리포트와 스크린샷만 확인하면 됩니다.\n다만 한 가지 주의할 점이 있습니다. AI가 생성한 코드의 책임은 여전히 개발자에게 있습니다. Cole Medin도 강조했듯이, 이 워크플로우는 \u0026ldquo;vibe coding\u0026quot;을 지향하는 것이 아니라 검증의 부담을 덜어주는 것입니다. 자동 수정이 만능이 아니므로 최종 판단은 사람이 해야 합니다.\n빠른 링크 주제 링크 Claude Code auto-fix 한국어 영상 Nova AI Daily - auto-fix 출시 Self-Healing 워크플로우 영상 Cole Medin - Find All Mistakes Claude Code 공식 문서 docs.anthropic.com Vercel Agent Browser CLI npmjs.com/@anthropic-ai/agent-browser 시리즈 1편 - 컨텍스트 관리 Claude Code 실전 가이드 1 시리즈 2편 - 신기능 정복 Claude Code 실전 가이드 2 시리즈 3편 - 27가지 팁 Claude Code 실전 가이드 3 ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-claude-code-autofix/cover.jpg","permalink":"/ko/posts/2026-04-01-claude-code-autofix/","title":"Claude Code 실전 가이드 4 — auto-fix와 Self-Healing 워크플로우"},{"content":"개요 Claude Code 실전 가이드 시리즈의 다섯 번째 글입니다. 이전 글에서는 컨텍스트 관리(#1, 03/19), 최근 신기능(#2, 03/24), 500시간 사용자의 27가지 팁(#3, 03/30), auto-fix와 Self-Healing 워크플로우(#4, 04/01)를 다뤘습니다.\n이번 포스트에서는 AI LABS 채널의 12 Hidden Settings To Enable In Your Claude Code Setup 영상을 기반으로, settings.json과 환경 변수에 숨겨진 12가지 설정을 하나씩 파헤칩니다. 대부분의 사용자가 모르고 지나가는 설정이지만, 이것들을 켜면 Claude Code의 성능과 사용 경험이 확연히 달라집니다.\n전체 설정 구조 아래 다이어그램은 이번 포스트에서 다루는 12가지 설정이 Claude Code의 어떤 영역에 속하는지 보여줍니다.\ngraph LR A[\"settings.json\"] --\u003e B[\"대화 보관 \u0026lt;br/\u0026gt; cleanup_period_days\"] A --\u003e C[\"출력 한도 \u0026lt;br/\u0026gt; max_read_tokens\"] A --\u003e D[\"자동 compact \u0026lt;br/\u0026gt; auto_compact_%\"] A --\u003e E[\"알림 \u0026lt;br/\u0026gt; notifications\"] A --\u003e F[\"모델 라우팅 \u0026lt;br/\u0026gt; thinking budget\"] A --\u003e G[\"권한 모드 \u0026lt;br/\u0026gt; permissions\"] H[\".claude/ 폴더\"] --\u003e I[\"path-specific rules\"] H --\u003e J[\"custom slash commands\"] H --\u003e K[\"MCP 서버 설정\"] L[\"환경 변수\"] --\u003e M[\"CLAUDE_CODE_MAX \u0026lt;br/\u0026gt; _BASH_OUTPUT\"] N[\"hooks 시스템\"] --\u003e O[\"pre/post hooks \u0026lt;br/\u0026gt; exit codes\"] P[\"오픈소스 도구\"] --\u003e Q[\"Claude CTX \u0026lt;br/\u0026gt; Claude Tuner\"] 1. cleanup_period_days \u0026ndash; 대화 보관 기간 /insights 명령이나 --resume 플래그를 사용할 때, 기본적으로 최근 30일의 대화만 표시됩니다. Claude Code가 그 이전 데이터를 시스템에서 삭제하기 때문입니다.\nOpus 4.6의 1M 토큰 컨텍스트 윈도우를 활용해 더 긴 기간의 인사이트 분석을 하고 싶다면, 이 설정을 바꿔야 합니다.\n설정 위치: ~/.claude/settings.json\n{ \u0026#34;cleanup_period_days\u0026#34;: 365 } 값 동작 365 1년치 대화 보관 90 3개월 보관 (권장 중간값) 0 대화를 전혀 보관하지 않음 \u0026ndash; insights/resume 불가 주의: 값을 너무 크게 설정하면 ~/.claude/ 폴더 용량이 상당히 커질 수 있습니다. 디스크 여유 공간을 확인하세요.\n2. Path-Specific Rules \u0026ndash; 경로별 규칙 프로젝트의 .claude/ 폴더 안에 경로 패턴에 따라 로드되는 규칙 파일을 만들 수 있습니다. 에이전트가 특정 파일을 읽거나 수정할 때, 해당 경로 패턴과 매칭되는 규칙만 컨텍스트에 로드됩니다.\n왜 필요한가? 많은 사람들이 CLAUDE.md 하나에 모든 지시사항을 몰아넣습니다. 프로젝트가 커지면 이 파일 자체가 너무 방대해져서, Claude가 어떤 지시를 따라야 할지 혼란을 겪습니다. 프론트엔드 작업 중인데 백엔드 규칙까지 로드할 필요는 없습니다.\n설정 예시 .claude/rules/ 디렉토리에 파일별 규칙을 분리합니다:\n.claude/ rules/ react-components.md # src/components/** 패턴에 매칭 api-routes.md # src/api/** 패턴에 매칭 database.md # prisma/** 또는 drizzle/** 패턴에 매칭 각 규칙 파일은 해당 경로의 파일을 작업할 때만 컨텍스트에 주입됩니다. 이렇게 하면:\n관심사 분리 (Separation of Concerns)가 자연스럽게 이루어지고 에이전트가 현재 작업에 집중할 수 있으며 컨텍스트 윈도우를 효율적으로 사용합니다 3. 출력 토큰 한도와 대형 파일 읽기 Bash 출력 한도 Claude Code가 bash 명령 결과를 읽을 때, 기본 한도는 30,000자입니다. 테스트 스위트, 빌드 로그, 데이터베이스 마이그레이션처럼 대량의 출력을 생성하는 명령은 잘려나갑니다.\n{ \u0026#34;max_output_chars\u0026#34;: 150000 } 1M 토큰 컨텍스트 윈도우가 있는 지금, 30K 제한은 200K 시절의 유산입니다. 150K 정도로 올리면 전체 출력을 읽을 수 있습니다.\n파일 읽기 토큰 한도 기본적으로 Claude는 파일을 읽을 때 25K 토큰만 읽습니다. 더 큰 파일은 100K 이상으로 설정할 수 있습니다:\n{ \u0026#34;max_read_file_tokens\u0026#34;: 100000 } 2,000줄 제한 우회 여기서 중요한 함정이 있습니다. 토큰 한도를 아무리 올려도, Claude는 한 번에 최대 2,000줄만 읽고 나머지가 있다는 사실조차 모릅니다. Anthropic이 이 제한을 변경할 수 있는 설정을 제공하지 않습니다.\n우회 방법: CLAUDE.md에 다음 지시를 추가합니다:\n## 대형 파일 읽기 규칙 파일을 읽을 때 먼저 줄 수를 확인하세요. 2,000줄을 초과하는 파일은 offset과 limit 파라미터를 사용해 전체를 읽으세요. 추가로, Read 도구가 실행될 때마다 트리거되는 hook을 설정하여 파일 줄 수를 체크하고, 2,000줄 초과 시 분할 읽기를 강제할 수도 있습니다.\n4. CLAUDE_CODE_MAX_BASH_OUTPUT \u0026ndash; Bash 출력 전용 한도 환경 변수 CLAUDE_CODE_MAX_BASH_OUTPUT을 설정하면 bash 명령 출력의 최대 문자 수를 별도로 제어할 수 있습니다.\n# ~/.zshrc 또는 ~/.bashrc에 추가 export CLAUDE_CODE_MAX_BASH_OUTPUT=150000 이 환경 변수는 settings.json의 설정과 함께 작동하며, 특히 CI/CD 파이프라인이나 대형 로그를 다룰 때 유용합니다. 기본값 30K는 테스트 결과의 앞부분만 보여주고 실제 에러가 있는 뒷부분을 잘라버리는 경우가 많습니다.\n// settings.json에서도 동일하게 설정 가능 { \u0026#34;env\u0026#34;: { \u0026#34;CLAUDE_CODE_MAX_BASH_OUTPUT\u0026#34;: \u0026#34;150000\u0026#34; } } 5. 자동 Compact와 컨텍스트 관리 Claude Code는 컨텍스트 윈도우가 **95%**에 도달하면 자동으로 compact를 실행합니다. 하지만 1M 토큰 윈도우에서도 70% 이후부터 출력 품질이 저하되기 시작합니다.\n최적 설정 { \u0026#34;auto_compact_percentage_override\u0026#34;: 75 } 75%에서 자동 compact를 트리거하면, 에이전트가 항상 충분한 여유 컨텍스트를 확보한 상태에서 작업합니다. 95%까지 기다리면 이미 품질이 떨어진 상태에서 compact가 일어나므로, 그 사이 구간에서 생성된 코드 품질이 보장되지 않습니다.\n팁: 특별히 전체 1M 컨텍스트가 필요한 대형 코드베이스 분석 작업이 아니라면, 70-80% 범위를 권장합니다.\n6. 알림 설정 Claude Code가 장시간 작업을 수행할 때, 완료 알림을 놓치기 쉽습니다. settings.json에서 알림 동작을 제어할 수 있습니다.\n{ \u0026#34;notifications\u0026#34;: { \u0026#34;enabled\u0026#34;: true, \u0026#34;sound\u0026#34;: true, \u0026#34;on_complete\u0026#34;: true } } Telemetry와 프라이버시 Claude Code는 기본적으로 Statsig(사용 패턴/지연 시간)과 Sentry(에러 로깅)에 데이터를 전송합니다. 옵트아웃하려면:\n{ \u0026#34;disable_telemetry\u0026#34;: true, \u0026#34;disable_error_reporting\u0026#34;: true, \u0026#34;disable_feedback_display\u0026#34;: true } 주의: CLI 플래그 --disable-non-essential-traffic도 비슷해 보이지만, 이건 자동 업데이트까지 차단합니다. 위 세 가지 설정을 개별로 사용하는 것이 더 안전합니다.\n7. 모델 라우팅과 Thinking Budget effort 파라미터 sub-agent를 실행할 때 --effort 플래그로 thinking 수준을 조절할 수 있습니다. 모든 작업에 최대 thinking이 필요한 것은 아닙니다.\n# 가벼운 작업에는 낮은 effort claude --agent formatter --effort low # 복잡한 아키텍처 결정에는 높은 effort claude --agent architect --effort high Sub-agent 고급 설정 sub-agent는 단순히 모델과 MCP 도구만 설정할 수 있는 것이 아닙니다:\n{ \u0026#34;agents\u0026#34;: { \u0026#34;formatter\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;claude-sonnet-4-20250514\u0026#34;, \u0026#34;effort\u0026#34;: \u0026#34;low\u0026#34;, \u0026#34;background\u0026#34;: true, \u0026#34;skills\u0026#34;: [\u0026#34;lint-fix\u0026#34;], \u0026#34;hooks\u0026#34;: { \u0026#34;post_tool_use\u0026#34;: \u0026#34;./hooks/format-check.sh\u0026#34; } }, \u0026#34;architect\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;claude-opus-4-20250514\u0026#34;, \u0026#34;effort\u0026#34;: \u0026#34;high\u0026#34;, \u0026#34;isolation\u0026#34;: true, \u0026#34;permitted_agent_names\u0026#34;: [\u0026#34;formatter\u0026#34;, \u0026#34;tester\u0026#34;] } } } 옵션 설명 skill sub-agent에 특정 skill 상속 effort thinking 토큰 사용량 조절 background 백그라운드 실행 여부 isolation 별도 worktree에서 격리 실행 permitted_agent_names 생성 가능한 하위 에이전트 제한 Agent Teams (실험적 기능) Sub-agent와 달리, Agent Teams에서는 팀 멤버끼리 서로 통신할 수 있습니다. 팀 리더가 작업을 조율하고, 각 멤버는 독립된 Claude 세션으로 동작하면서도 정보를 공유합니다.\n8. 권한 모드와 Auto-Accept Claude Code의 권한 시스템은 파일 수정, bash 실행 등의 작업마다 사용자 승인을 요구합니다. 신뢰할 수 있는 프로젝트에서는 이를 자동화할 수 있습니다.\n{ \u0026#34;permissions\u0026#34;: { \u0026#34;allow\u0026#34;: [ \u0026#34;Read\u0026#34;, \u0026#34;Glob\u0026#34;, \u0026#34;Grep\u0026#34;, \u0026#34;Bash(git *)\u0026#34;, \u0026#34;Bash(npm test)\u0026#34;, \u0026#34;Bash(npx prettier *)\u0026#34; ], \u0026#34;deny\u0026#34;: [ \u0026#34;Bash(rm -rf *)\u0026#34;, \u0026#34;Bash(git push --force *)\u0026#34; ] } } 프로필별 권한 관리 \u0026ndash; Claude CTX 여러 프로젝트에서 다른 권한 설정이 필요하다면, 오픈소스 도구 Claude CTX가 유용합니다:\n# 설치 (macOS) brew install claude-ctx # 현재 프로필 확인 claude ctx -c # 프로필 전환 claude ctx work # 업무용 설정으로 전환 claude ctx personal # 개인 프로젝트 설정으로 전환 Claude CTX는 ~/.claude/profiles/ 폴더에 프로필별 settings.json과 CLAUDE.md를 관리합니다. 전환 시 현재 상태를 자동 백업하므로 설정이 섞일 걱정이 없습니다.\n9. MCP 서버 설정 MCP(Model Context Protocol) 서버를 settings.json에서 직접 설정할 수 있습니다. sub-agent별로 다른 MCP 도구를 할당하는 것도 가능합니다.\n{ \u0026#34;mcpServers\u0026#34;: { \u0026#34;filesystem\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;npx\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;-y\u0026#34;, \u0026#34;@modelcontextprotocol/server-filesystem\u0026#34;, \u0026#34;/path/to/project\u0026#34;] }, \u0026#34;github\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;npx\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;-y\u0026#34;, \u0026#34;@modelcontextprotocol/server-github\u0026#34;], \u0026#34;env\u0026#34;: { \u0026#34;GITHUB_PERSONAL_ACCESS_TOKEN\u0026#34;: \u0026#34;${GITHUB_TOKEN}\u0026#34; } }, \u0026#34;postgres\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;npx\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;-y\u0026#34;, \u0026#34;@modelcontextprotocol/server-postgres\u0026#34;], \u0026#34;env\u0026#34;: { \u0026#34;DATABASE_URL\u0026#34;: \u0026#34;${DATABASE_URL}\u0026#34; } } } } 프로젝트 레벨(.claude/settings.json)과 글로벌 레벨(~/.claude/settings.json) 모두에서 설정할 수 있으며, 프로젝트 레벨이 우선합니다.\n10. Custom Slash Commands .claude/commands/ 디렉토리에 마크다운 파일을 만들면 커스텀 슬래시 명령을 정의할 수 있습니다.\n.claude/ commands/ review.md → /review로 호출 deploy.md → /deploy로 호출 e2e-test.md → /e2e-test로 호출 예시: /review 명령 # Code Review 현재 staged된 변경사항을 리뷰합니다: 1. `git diff --cached`로 변경사항 확인 2. 보안 취약점 체크 3. 성능 이슈 확인 4. 코드 스타일 검토 5. 리뷰 결과를 구조화된 형태로 출력 이 파일은 별도의 등록 과정 없이, 디렉토리에 넣기만 하면 Claude Code가 자동으로 인식합니다. skill과 달리 단순한 프롬프트 템플릿으로 동작하며, 반복적인 워크플로우를 명령 하나로 축약할 때 유용합니다.\n11. Pre/Post Hooks와 Exit Codes Hooks는 Claude Code의 도구 실행 전후에 커스텀 스크립트를 실행합니다. 핵심은 exit code에 따라 동작이 달라진다는 점입니다.\nExit Code 체계 Exit Code 동작 용도 0 성공, 컨텍스트에 삽입 안 됨 정상 완료 확인 2 블로킹 \u0026ndash; 에러 메시지가 Claude에 피드백됨 금지된 명령 차단 그 외 비블로킹, verbose 모드에서만 표시 경고성 메시지 실전 예시: 패키지 매니저 강제 Claude가 학습 데이터의 패턴 때문에 pip을 사용하려 할 때, uv를 강제하는 hook:\n{ \u0026#34;hooks\u0026#34;: { \u0026#34;pre_tool_use\u0026#34;: [ { \u0026#34;tool\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;./hooks/enforce-uv.sh\u0026#34; } ] } } #!/bin/bash # hooks/enforce-uv.sh if echo \u0026#34;$CLAUDE_TOOL_INPUT\u0026#34; | grep -q \u0026#34;pip install\u0026#34;; then echo \u0026#34;ERROR: pip 대신 uv를 사용하세요. \u0026#39;uv pip install\u0026#39; 또는 \u0026#39;uv add\u0026#39;를 사용해주세요.\u0026#34; exit 2 # 블로킹 -- Claude가 이 메시지를 읽고 명령을 수정함 fi exit 0 대형 파일 읽기 강제 hook { \u0026#34;hooks\u0026#34;: { \u0026#34;pre_tool_use\u0026#34;: [ { \u0026#34;tool\u0026#34;: \u0026#34;Read\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;./hooks/check-file-lines.sh\u0026#34; } ] } } 이 hook은 Read 도구가 실행될 때마다 파일 줄 수를 체크하고, 2,000줄 초과 시 exit code 2로 분할 읽기를 강제합니다.\n12. 오픈소스 대안 도구 Claude CTX \u0026ndash; 프로필 매니저 앞서 권한 모드에서 언급했듯이, 여러 설정 프로필을 관리합니다:\n~/.claude/ profiles/ work/ settings.json CLAUDE.md personal/ settings.json CLAUDE.md client-a/ settings.json CLAUDE.md backups/ 2026-04-01T10:00:00/ Attribution 커스터마이징 Claude가 GitHub 커밋에 자동으로 co-author를 추가하는 것이 불편하다면:\n{ \u0026#34;attribution\u0026#34;: { \u0026#34;commit\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;pr\u0026#34;: \u0026#34;\u0026#34; } } 빈 문자열로 설정하면 co-author 태그가 추가되지 않습니다. 커스텀 문자열을 넣으면 원하는 이름으로 표시됩니다.\n기타 유용한 팁 Prompt Stashing: Ctrl+S로 현재 프롬프트를 임시 저장하고, 다른 작업을 먼저 수행한 후 자동으로 복원 Sub-agent 직접 실행: claude --agent \u0026lt;name\u0026gt; 플래그로 특정 sub-agent를 직접 호출하여 로딩 오버헤드 제거 나의 settings.json 종합 설정 위 내용을 종합한 실전 settings.json 예시입니다:\n{ \u0026#34;cleanup_period_days\u0026#34;: 90, \u0026#34;max_read_file_tokens\u0026#34;: 100000, \u0026#34;auto_compact_percentage_override\u0026#34;: 75, \u0026#34;notifications\u0026#34;: { \u0026#34;enabled\u0026#34;: true, \u0026#34;on_complete\u0026#34;: true }, \u0026#34;permissions\u0026#34;: { \u0026#34;allow\u0026#34;: [ \u0026#34;Read\u0026#34;, \u0026#34;Glob\u0026#34;, \u0026#34;Grep\u0026#34;, \u0026#34;Bash(git *)\u0026#34;, \u0026#34;Bash(uv *)\u0026#34;, \u0026#34;Bash(npm test)\u0026#34; ], \u0026#34;deny\u0026#34;: [ \u0026#34;Bash(rm -rf *)\u0026#34;, \u0026#34;Bash(git push --force *)\u0026#34; ] }, \u0026#34;attribution\u0026#34;: { \u0026#34;commit\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;pr\u0026#34;: \u0026#34;\u0026#34; }, \u0026#34;disable_telemetry\u0026#34;: true, \u0026#34;disable_error_reporting\u0026#34;: true, \u0026#34;hooks\u0026#34;: { \u0026#34;pre_tool_use\u0026#34;: [ { \u0026#34;tool\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;./hooks/enforce-uv.sh\u0026#34; } ] } } 인사이트 설정의 계층 구조를 이해하라: ~/.claude/settings.json(글로벌) -\u0026gt; .claude/settings.json(프로젝트) -\u0026gt; 환경 변수 순으로 우선순위가 높아집니다. 프로젝트별 특성에 맞게 설정을 분리하면 충돌이 줄어듭니다.\n30K 기본 한도는 과거의 유산: 200K 컨텍스트 시절의 보수적 기본값이 아직 적용되어 있습니다. 1M 토큰 시대에는 출력 한도와 파일 읽기 한도를 적극적으로 올려야 Claude의 잠재력을 제대로 활용할 수 있습니다.\nAuto-compact 75%는 품질 보험: 95% 기본값은 \u0026ldquo;가능한 한 많이 기억하겠다\u0026quot;는 전략이지만, 70% 이후 품질 저하를 감안하면 75%가 실용적인 균형점입니다.\nExit code 2가 hooks의 핵심: 단순한 전처리/후처리가 아니라, Claude의 행동을 능동적으로 교정하는 메커니즘입니다. 팀 전체의 코딩 표준을 hook으로 강제하면 AI가 생성하는 코드의 일관성이 크게 향상됩니다.\nPath-specific rules는 미래 투자: 프로젝트 초기에는 과잉 설계처럼 보이지만, 코드베이스가 성장하면서 CLAUDE.md 하나로 모든 걸 관리하는 것이 병목이 됩니다. 일찍 분리해두면 나중에 큰 효과를 봅니다.\n참고 자료 12 Hidden Settings To Enable In Your Claude Code Setup \u0026ndash; AI LABS Claude Code 공식 문서 Claude CTX GitHub ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-claude-code-settings/cover.jpg","permalink":"/ko/posts/claude-code-hidden-settings/","title":"Claude Code 실전 가이드 5 — 숨겨진 12가지 설정 최적화"},{"content":"개요 Claude Code 사용자가 빠르게 늘고 있지만, 학습 리소스는 영어 공식 문서에 집중되어 있어 한국어 사용자에게 진입 장벽이 존재한다. 최근 들어 WikiDocs 커뮤니티 가이드, 위니북스의 바이브코딩 에센셜 같은 한국어 리소스가 등장하면서 상황이 달라지고 있다.\n이 글에서는 현재 사용 가능한 Claude Code 학습 리소스 4가지를 비교 분석하고, 수준별 추천 학습 경로를 정리한다. 이미 Claude Code 실전 가이드 시리즈 #1~#5와 Claude Code 자동화 삼총사 — 스킬, 스케줄, 디스패치 포스트를 읽은 분들이라면, 이 로드맵으로 빈 곳을 채울 수 있다.\n1. 공식 문서 — code.claude.com/docs 가장 먼저 확인해야 할 곳은 Anthropic 공식 문서다. Overview에서 Claude Code가 무엇인지 파악하고, Quickstart로 첫 번째 실습을 진행한 뒤, Reference 문서에서 세부 기능을 확인하는 흐름이다.\n주요 구성 개요(Overview): Claude Code의 정의, 할 수 있는 것, 환경별 설치 가이드 빠른 시작(Quickstart): 코드베이스 탐색에서 수정 커밋까지 첫 실제 작업 핵심 개념: 작동 방식, Context Window, 권한 모드 워크플로우 및 모범 사례: CLAUDE.md 설정, 일반적인 패턴 플랫폼 및 통합: VS Code, JetBrains, Slack, GitHub Actions 등 한국어 버전 공식 문서에 /docs/ko/ 경로로 한국어 버전이 존재한다. 번역 품질이 준수하며, 원문과 거의 동시에 업데이트된다. 영어가 부담스러운 경우 한국어 문서로 시작해도 충분하다.\n장단점 장점 단점 항상 최신 상태 유지 실전 예제가 부족 Anthropic이 직접 관리 — 가장 정확 기능 나열 위주, \u0026ldquo;왜\u0026rdquo; 쓰는지 설명 부족 한국어 버전 존재 초보자에게 정보량이 과다 무료 커뮤니티 토론/Q\u0026amp;A 없음 추천 시점: 새 기능이 나왔을 때 가장 먼저 확인하는 레퍼런스. 처음 배울 때보다 이미 쓰고 있는 사용자가 \u0026ldquo;이 기능 정확히 어떻게 동작하지?\u0026ldquo;를 확인할 때 최적이다.\n2. Anthropic Skilljar — Claude Code in Action Claude Code in Action은 Anthropic이 Skilljar 플랫폼에서 제공하는 무료 온라인 코스다. \u0026ldquo;What is a coding assistant?\u0026ldquo;라는 근본적인 질문에서 시작해 실제 데모까지 단계적으로 진행한다.\n코스 특징 무료: 계정만 만들면 모든 콘텐츠 이용 가능 체계적 구성: 개념 → 데모 → 실습 순서로 진행 공식 교육: Anthropic이 직접 제작한 커리큘럼 진도 추적: Skilljar LMS가 학습 진행률을 관리 장단점 장점 단점 무료, 공식 교육 자료 영어로만 제공 체계적 커리큘럼 기본 수준에 머무름 인터랙티브 학습 경험 고급 사용법 (Skills, MCP) 미포함 수료증 발급 가능 업데이트 주기가 문서보다 느림 추천 시점: Claude Code를 처음 접하는 사람이 \u0026ldquo;이게 뭔지, 왜 쓰는지\u0026quot;를 이해하는 첫 단계. 영어에 거부감이 없다면 공식 문서보다 이 코스를 먼저 수강하는 것을 추천한다.\n3. WikiDocs 클로드 코드 가이드 WikiDocs 클로드 코드 가이드는 한국어 커뮤니티에서 만든 실전 중심 가이드다. Skills 개발, MCP 서버 연동 등 공식 문서에서 다루지 않는 실무 챕터가 포함되어 있어 중급 이상 사용자에게 특히 유용하다.\n주요 내용 Claude Code 설치 및 기본 설정 Skills 개발: 커스텀 스킬 작성, 테스트, 배포 MCP 서버 연동: 외부 도구와의 통합 프로젝트별 CLAUDE.md 작성 전략 실전 트러블슈팅 사례 함께 보면 좋은 입문서 WikiDocs에는 클로드 코드 입문서도 있다. 완전한 초보자라면 입문서(19202)를 먼저 보고, 본 가이드(19104)로 넘어가는 것이 좋다.\n장단점 장점 단점 한국어 — 언어 장벽 없음 커뮤니티 작성이라 정확도 편차 실무/실전 중심 업데이트가 공식 문서보다 느릴 수 있음 Skills, MCP 등 고급 주제 포함 체계적 구성이 공식 코스보다 느슨함 무료, 누구나 접근 가능 집필자에 따라 문체/깊이 차이 추천 시점: 기본 사용법을 익힌 후 Skills나 MCP 연동 같은 고급 주제를 한국어로 학습하고 싶을 때. 실전 가이드 시리즈를 읽은 분들이 다음 단계로 가기에 적합하다.\n4. 바이브코딩 에센셜 with Claude Code (위니북스) 위니북스(WeniVooks)에서 제공하는 비개발자 대상 Claude Code 가이드다. \u0026ldquo;바이브코딩\u0026quot;이라는 이름답게, 코딩 경험이 없는 사람도 Claude Code로 무언가를 만들어보는 것을 목표로 한다.\n챕터 구성 챕터 내용 대상 0장 위니브 서비스 소개 전체 1~2장 Claude Code 설치, 기본 사용법 입문자 3~4장 실전 프로젝트 (웹사이트, 자동화) 초급~중급 5장 고급 활용 (확장, 커스터마이징) 중급 장단점 장점 단점 한국어, 비개발자 친화적 일부 콘텐츠 유료일 수 있음 기본 → 실전 → 고급 단계적 구성 개발자에게는 내용이 얕을 수 있음 프로젝트 기반 학습 고급 주제 (MCP, Skills) 제한적 위니브 커뮤니티 지원 업데이트 주기 불확실 추천 시점: 개발 경험이 없지만 Claude Code로 무언가를 만들어보고 싶은 사람. PM, 디자이너, 기획자 등 비개발 직군에서 AI 코딩 도구를 입문할 때 최적이다.\n리소스 종합 비교 구분 공식 문서 Skilljar WikiDocs 위니북스 언어 영어 + 한국어 영어 한국어 한국어 비용 무료 무료 무료 무료/일부 유료 대상 전 수준 입문자 중급~고급 비개발자~초급 강점 정확성, 최신성 체계적 교육 실전, 고급 주제 비개발자 친화 약점 실전 예제 부족 기본 수준 정확도 편차 깊이 제한 Skills 다룸 O (Reference) X O (실전) 제한적 MCP 다룸 O (Reference) X O (실전) 제한적 형식 웹 문서 온라인 코스 위키 이북 추천 학습 경로 수준별로 어떤 순서로 학습하면 효과적인지 정리했다.\nflowchart TD START[\"Claude Code\u0026lt;br/\u0026gt;학습 시작\"] START --\u003e Q{\"개발 경험이\u0026lt;br/\u0026gt;있나요?\"} Q -- \"없음\" --\u003e BEGINNER[\"입문자 경로\"] Q -- \"있음\" --\u003e Q2{\"Claude Code\u0026lt;br/\u0026gt;써본 적 있나요?\"} Q2 -- \"없음\" --\u003e INTERMEDIATE[\"중급자 경로\"] Q2 -- \"있음\" --\u003e ADVANCED[\"고급자 경로\"] BEGINNER --\u003e B1[\"1. Skilljar 코스 수강\"] B1 --\u003e B2[\"2. 공식 문서 한국어판\"] B2 --\u003e B3[\"3. 위니북스 바이브코딩\"] B3 --\u003e B4[\"4. WikiDocs 입문서\"] INTERMEDIATE --\u003e M1[\"1. 공식 문서 Quickstart\"] M1 --\u003e M2[\"2. WikiDocs 가이드\"] M2 --\u003e M3[\"3. 실전 가이드 시리즈\"] M3 --\u003e M4[\"4. 자동화 삼총사\"] ADVANCED --\u003e A1[\"1. WikiDocs Skills 챕터\"] A1 --\u003e A2[\"2. MCP 서버 연동\"] A2 --\u003e A3[\"3. 커스텀 에이전트 구축\"] A3 --\u003e A4[\"4. 공식 문서 Agent SDK\"] style START fill:#6366f1,color:#fff style BEGINNER fill:#22c55e,color:#fff style INTERMEDIATE fill:#f59e0b,color:#fff style ADVANCED fill:#ef4444,color:#fff입문자 (비개발자/코딩 초보) Skilljar — \u0026ldquo;코딩 어시스턴트란 무엇인가\u0026quot;부터 이해 공식 문서 한국어판 — 설치 및 기본 개념 확인 위니북스 바이브코딩 — 프로젝트 기반으로 실제 만들어보기 WikiDocs 입문서 — 추가 실습과 커뮤니티 Q\u0026amp;A 중급자 (개발 경험 있음, Claude Code 첫 사용) 공식 문서 Quickstart — 빠르게 설치하고 첫 작업 수행 WikiDocs 가이드 — 실전 활용법과 CLAUDE.md 전략 실전 가이드 시리즈 — 컨텍스트 관리, 워크플로우 패턴 자동화 삼총사 — Skills, 스케줄, 디스패치 활용 고급자 (Claude Code 사용 중, 확장 원함) WikiDocs Skills 챕터 — 커스텀 스킬 개발 실습 MCP 서버 연동 — 외부 도구 통합 커스텀 에이전트 구축 — Agent SDK 활용 공식 문서 Reference — 세부 API 확인 인사이트 Claude Code 학습 생태계를 살펴보면서 몇 가지 흥미로운 점을 발견했다.\n한국어 리소스가 빠르게 성장하고 있다. 불과 몇 달 전만 해도 영어 공식 문서가 유일한 선택지였지만, 지금은 WikiDocs 가이드, 위니북스, 그리고 공식 문서의 한국어 번역까지 선택지가 다양해졌다. 이는 한국에서 Claude Code 채택이 빠르게 진행되고 있음을 보여준다.\n\u0026ldquo;공식 문서 = 최고\u0026rdquo; 공식이 성립하지 않는다. 공식 문서는 정확하고 최신이지만, \u0026ldquo;이걸 왜 써야 하는지\u0026rdquo;, \u0026ldquo;실전에서 어떻게 조합하는지\u0026quot;를 알려주지 않는다. WikiDocs처럼 커뮤니티가 만든 가이드가 이 빈자리를 채운다. 이상적인 학습은 공식 문서와 커뮤니티 가이드를 병행하는 것이다.\n비개발자 시장이 열리고 있다. 위니북스의 \u0026ldquo;바이브코딩 에센셜\u0026quot;은 개발자가 아닌 사람들을 정면으로 겨냥한다. Claude Code가 단순한 개발 도구를 넘어 \u0026ldquo;누구나 코딩할 수 있게 해주는 도구\u0026quot;로 포지셔닝되고 있다는 신호다. PM이 직접 프로토타입을 만들고, 마케터가 데이터 분석 스크립트를 작성하는 시대가 오고 있다.\n학습 자료의 생명주기를 고려하라. AI 도구는 빠르게 변한다. 오늘 정확한 가이드가 한 달 뒤에는 구식이 될 수 있다. 공식 문서는 항상 최신을 유지하지만, 커뮤니티 가이드나 이북은 그렇지 않을 수 있다. 학습할 때 항상 \u0026ldquo;이 내용이 현재 버전에도 적용되는가?\u0026ldquo;를 스스로 검증하는 습관이 필요하다.\n관련 포스트:\nClaude Code 실전 가이드 시리즈 — 컨텍스트 관리부터 워크플로우까지 Claude Code 자동화 삼총사 — 스킬, 스케줄, 디스패치 — Skills와 자동화 심화 ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-claude-code-learning-roadmap/cover.jpg","permalink":"/ko/posts/2026-04-01-claude-code-learning-roadmap/","title":"Claude Code 학습 로드맵 — 공식 문서부터 한국어 가이드까지"},{"content":"코딩 에이전트는 텍스트에 강하지만 시각적 표현에는 약하다. Claude Code의 Skills 시스템은 이 한계를 체계적으로 극복하는 프레임워크다. Excalidraw 다이어그램 스킬을 사례로, Skills의 구조부터 \u0026ldquo;visual argumentation\u0026rdquo; 철학까지 깊이 파고든다.\nClaude Code Skills 시스템 개요 Skills란 무엇인가 Skills는 재사용 가능한 프롬프트 + 리소스 패키지다. 코딩 에이전트에게 특정 작업을 수행하는 방법을 가르치는 \u0026ldquo;지침서\u0026quot;를 디렉토리 하나로 묶은 것이다.\n핵심은 skill.md 파일이다. 이 마크다운 파일이 에이전트의 행동을 정의한다 — 무엇을 입력으로 받고, 어떤 단계를 거치며, 어떤 품질 기준으로 결과물을 검증할지가 모두 여기에 담긴다.\n.claude/skills/ ├── excalidraw-diagram/ │ ├── skill.md # 핵심 지침서 │ ├── reference/ # 참조 리소스 │ │ ├── color-palette.json │ │ └── element-templates/ │ └── render.py # 보조 스크립트 ├── code-review/ │ └── skill.md └── documentation/ └── skill.md Skills는 slash command(예: /diagram)로 호출된다. Claude Code가 프롬프트 의도를 파악하면 자동으로 해당 skill.md를 로드하고, 거기 정의된 워크플로를 따른다.\nSkills vs MCP vs CLAUDE.md — 언제 뭘 쓰는가 이 세 가지는 모두 에이전트의 행동을 확장하지만, 용도가 다르다.\n구분 용도 범위 예시 CLAUDE.md 프로젝트 전체에 적용되는 규칙 항상 로드됨 코딩 컨벤션, 빌드 명령어 Skills 특정 작업의 체계적 워크플로 필요할 때만 로드 다이어그램 생성, 코드 리뷰 MCP 외부 서비스 연동 (API 호출) 도구 수준 Slack 메시지 전송, DB 쿼리 CLAUDE.md는 \u0026ldquo;이 프로젝트에서는 항상 이렇게 해라\u0026quot;이고, Skills는 \u0026ldquo;이 작업을 할 때는 이 절차를 따라라\u0026quot;이며, MCP는 \u0026ldquo;이 외부 시스템과 이렇게 통신해라\u0026quot;다.\nSkills의 장점은 명확하다:\n컨텍스트 효율성 — 필요할 때만 로드되므로 토큰을 낭비하지 않는다 재사용성 — 한 번 만들면 어떤 프로젝트에서든 사용 가능 공유 가능 — GitHub repo로 배포하면 누구나 clone해서 쓸 수 있다 Excalidraw 다이어그램 스킬 상세 분석 문제 정의: LLM의 시각적 한계 코딩 에이전트에게 \u0026ldquo;아키텍처 다이어그램을 그려줘\u0026quot;라고 요청하면 어떤 일이 벌어지는가?\n스킬 없이 생성하면 결과물은 판에 박힌 박스와 화살표의 나열이다. 색상 선택은 무작위에 가깝고, 레이아웃에 정보 계층(hierarchy)이 없으며, 어떤 다이어그램이든 거의 동일한 모양이 나온다. LLM은 텍스트 토큰을 생성하는 데 최적화되어 있지, 시각적 의사결정(색상 조합, 공간 배치, 시선 흐름)에는 체계적 지침이 필요하다.\nExcalidraw 스킬은 이 문제를 해결한다. \u0026ldquo;어떤 색을 쓸지\u0026rdquo;, \u0026ldquo;어떤 레이아웃 패턴을 적용할지\u0026rdquo;, \u0026ldquo;결과물을 어떻게 검증할지\u0026quot;를 모두 체계화하여 skill.md에 담았다.\n디렉토리 구조 .claude/skills/excalidraw-diagram/ ├── skill.md # 워크플로 전체 정의 ├── reference/ │ ├── color-palette.json # 브랜드 컬러 시스템 │ └── element-templates/ # 재사용 가능한 도형 템플릿 └── render.py # PNG 렌더링 스크립트 (검증용) 각 파일의 역할:\nskill.md — 에이전트가 다이어그램을 생성하는 전체 과정을 지시. 입력 분석부터 검증 루프까지 포함 color-palette.json — 일관된 색상 체계. 주요색, 보조색, 배경색 등을 hex 코드로 정의 element-templates/ — 자주 쓰이는 시각 패턴(flow diagram, architecture map 등)의 JSON 스니펫 render.py — Excalidraw JSON을 PNG로 변환. 에이전트가 자체 검증에 사용 skill.md 핵심 내용 분석 skill.md의 핵심 워크플로를 단계별로 살펴보자.\n1단계: 입력 소스 처리 스킬은 다양한 입력을 처리할 수 있도록 설계되었다:\n## Input Processing - **Code file** → 아키텍처, 데이터 플로우, 클래스 관계 추출 - **PDF document** → 핵심 개념과 관계 구조 파악 - **YouTube transcript** → 설명 흐름을 시각적 구조로 변환 - **Raw text/notes** → 개념 간 관계 매핑 코드 파일이라면 함수 호출 그래프나 모듈 의존성을, YouTube 스크립트라면 설명의 논리적 흐름을 시각화한다.\n2단계: 깊이 평가 (Depth Assessment) 이 단계가 존재하는 이유는 실용적이다. Claude Code에는 32K 토큰 출력 제한이 있다. 복잡한 다이어그램의 Excalidraw JSON은 이 한도를 쉽게 초과한다.\n## Depth Assessment IF simple diagram (single concept, few elements): → Build entire JSON in one pass IF complex diagram (multiple sections, many relationships): → Build section by section, merging incrementally 단순한 다이어그램은 한 번에 생성하고, 복잡한 것은 섹션별로 나누어 생성한 후 병합한다.\n3단계: 패턴 매핑 에이전트가 \u0026ldquo;박스와 화살표만 반복\u0026quot;하는 것을 방지하는 핵심 단계다:\n## Pattern Mapping 입력의 성격에 따라 시각 패턴을 선택: - System architecture → 계층형 레이어 다이어그램 - Data flow → 방향성 있는 파이프라인 - Decision process → 분기형 트리 - Comparison → 병렬 배치 + 대비 색상 - Timeline → 수평/수직 시간축 여기에 \u0026ldquo;박스의 반복을 피하라\u0026rdquo;, \u0026ldquo;Multi-zoom architecture를 활용하라\u0026rdquo; 같은 디자인 원칙도 포함된다.\n4단계: JSON 생성 Excalidraw의 네이티브 포맷은 JSON이다. skill.md는 JSON 생성 시 따라야 할 규칙을 명시한다:\n{ \u0026#34;type\u0026#34;: \u0026#34;excalidraw\u0026#34;, \u0026#34;version\u0026#34;: 2, \u0026#34;elements\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;rectangle\u0026#34;, \u0026#34;x\u0026#34;: 100, \u0026#34;y\u0026#34;: 200, \u0026#34;width\u0026#34;: 240, \u0026#34;height\u0026#34;: 80, \u0026#34;backgroundColor\u0026#34;: \u0026#34;#a5d8ff\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#1971c2\u0026#34;, \u0026#34;roundness\u0026#34;: { \u0026#34;type\u0026#34;: 3 }, \u0026#34;boundElements\u0026#34;: [], \u0026#34;label\u0026#34;: { \u0026#34;text\u0026#34;: \u0026#34;Content Fetcher\u0026#34; } } ] } 컬러 팔레트에서 색상을 가져오고, 요소 간 간격과 정렬 규칙을 따르며, 화살표 연결의 시작점/끝점을 정확히 계산해야 한다.\n5단계: 검증 루프 (Self-Validation) 이 스킬의 가장 강력한 부분이다:\n## Validation Loop (2-4 iterations) 1. render.py로 JSON → PNG 렌더링 2. 생성된 PNG 스크린샷을 직접 확인 3. 다음 기준으로 평가: - 시각적 흐름이 자연스러운가? - 정보 계층이 명확한가? - 화살표 연결이 정확한가? - 색상 대비가 충분한가? - 텍스트가 잘려나가지 않았는가? 4. 문제 발견 시 JSON을 직접 수정 (재생성 아님) 5. 2-4회 반복 에이전트가 자기 작업물을 \u0026ldquo;눈으로 확인\u0026quot;하고 수정하는 것이다. render.py가 PNG를 생성하면, Claude Code의 멀티모달 능력으로 이미지를 분석하고 개선점을 찾는다. 중요한 점은 매번 처음부터 다시 만드는 게 아니라 기존 JSON을 직접 편집한다는 것이다.\n전체 워크플로 시각화 flowchart TD A[\"아이디어 입력\u0026lt;br/\u0026gt;코드 / PDF / 스크립트\"] --\u003e B[\"깊이 평가\u0026lt;br/\u0026gt;단순 vs 복잡\"] B --\u003e|단순| C[\"한 번에 JSON 생성\"] B --\u003e|복잡| D[\"섹션별 분할 생성\u0026lt;br/\u0026gt;32K 토큰 제한 대응\"] D --\u003e E[\"섹션 병합\"] C --\u003e F[\"패턴 매핑\u0026lt;br/\u0026gt;레이아웃 + 색상 결정\"] E --\u003e F F --\u003e G[\"Excalidraw JSON 생성\"] G --\u003e H[\"render.py\u0026lt;br/\u0026gt;PNG 렌더링\"] H --\u003e I{\"시각적 검증\u0026lt;br/\u0026gt;흐름 / 계층 / 정렬\"} I --\u003e|문제 발견| J[\"JSON 직접 수정\"] J --\u003e H I --\u003e|통과| K[\"최종 결과물 전달\u0026lt;br/\u0026gt;excalidraw.com 또는\u0026lt;br/\u0026gt;Obsidian에서 렌더링\"] style A fill:#4dabf7,stroke:#1971c2,color:#fff style F fill:#69db7c,stroke:#2f9e44,color:#fff style I fill:#ffa94d,stroke:#e8590c,color:#fff style K fill:#b197fc,stroke:#7048e8,color:#fffVisual Argumentation 철학 Excalidraw 스킬의 핵심 철학은 \u0026ldquo;visual argumentation\u0026rdquo; — 시각적 논증이다. 단순히 예쁜 그림을 만드는 것이 아니라, 다이어그램의 구조 자체가 논점을 전달해야 한다.\n두 가지 핵심 질문 skill.md는 에이전트에게 매 단계마다 두 가지를 자문하도록 지시한다:\n\u0026ldquo;시각적 구조가 개념의 동작을 반영하는가?\u0026rdquo; (Does the visual structure mirror the concept\u0026rsquo;s behavior?) \u0026ldquo;누군가 이 다이어그램에서 구체적인 것을 배울 수 있는가?\u0026rdquo; (Could someone learn something concrete from this diagram?) 첫 번째 질문은 구조적 정합성에 관한 것이다. 예를 들어 파이프라인을 설명하는데 순환형 레이아웃을 쓰면 개념과 시각이 어긋난다. 데이터가 A에서 B로 흐르면, 다이어그램도 왼쪽에서 오른쪽으로(또는 위에서 아래로) 흘러야 한다.\n두 번째 질문은 교육적 가치에 관한 것이다. 다이어그램이 단순히 문서의 장식이 아니라, 독자가 실제로 개념을 이해하는 데 도움이 되어야 한다.\n텍스트 제거 테스트 가장 인상적인 검증 기법이다:\n다이어그램에서 모든 설명 텍스트를 제거했을 때, 구조와 레이아웃만으로 논점이 전달되어야 한다.\n박스 안의 텍스트를 다 지워도 화살표의 방향, 요소의 크기 차이, 색상의 구분, 공간적 배치만으로 \u0026ldquo;무엇이 중요하고 무엇이 부차적인지\u0026rdquo;, \u0026ldquo;데이터가 어디서 어디로 흘러가는지\u0026quot;가 드러나야 한다는 것이다.\n이것이 \u0026ldquo;visual argumentation\u0026quot;의 핵심이다. 텍스트는 부연일 뿐, 시각적 구조 자체가 주장을 담아야 한다.\n적용 예시 시각화 대상 구조가 반영해야 할 것 나쁜 예 마이크로서비스 아키텍처 서비스 간 독립성, 통신 경로 모든 서비스를 동일 크기 박스로 일렬 배치 데이터 파이프라인 단방향 흐름, 변환 단계의 순서 양방향 화살표, 무작위 배치 의사결정 트리 분기의 조건, 경로별 결과 차이 모든 분기를 동일하게 표현 계층형 시스템 상위/하위 관계, 의존성 방향 평면적 나열 실전 데모 워크플로 실제로 이 스킬을 사용하는 과정을 단계별로 따라가 보자.\nStep 1: 프롬프트 입력 Claude Code에서 다음과 같이 요청한다:\n이 파일의 아키텍처를 다이어그램으로 만들어줘 /path/to/content_fetcher.py 또는 더 구체적으로:\n이 YouTube 스크립트를 기반으로 데이터 파이프라인 다이어그램을 만들어줘. 핵심 개념 간의 관계에 집중해줘. Step 2: skill.md 로드 Claude Code는 프롬프트 의도를 파악하고 .claude/skills/excalidraw-diagram/skill.md를 자동으로 로드한다. 이 시점에서 에이전트의 행동이 완전히 바뀐다 — skill.md에 정의된 워크플로를 단계별로 따르기 시작한다.\nStep 3: JSON 생성 및 검증 에이전트가 입력을 분석하고, 깊이를 평가하고, 패턴을 선택하여 Excalidraw JSON을 생성한다. 그 다음 render.py를 실행하여 PNG를 만들고, 자체적으로 검증한다.\n# 에이전트가 내부적으로 실행하는 과정 python render.py output.excalidraw --output preview.png # → PNG 생성 후 이미지 분석 # → \u0026#34;화살표 간격이 좁다\u0026#34; → JSON 수정 # → 재렌더링 → 재검증 # → 2-4회 반복 Step 4: 결과물 렌더링 최종 JSON 파일을 두 가지 방법으로 열 수 있다:\nexcalidraw.com — 브라우저에서 바로 열기. 무료. \u0026ldquo;Open\u0026rdquo; → 로컬 .excalidraw 파일 선택 Obsidian Excalidraw 플러그인 — 노트 시스템과 통합. .excalidraw 파일을 Vault에 넣으면 바로 렌더링 Step 5: 반복 수정 첫 결과물은 완벽하지 않다. 이건 의도된 것이다. LLM이 하나의 다이어그램을 만들 때 내려야 하는 미시적 결정의 수를 생각해 보라:\n모든 요소의 x, y 좌표 모든 색상 선택 모든 화살표의 시작점과 끝점 텍스트 크기와 배치 요소 간 간격 이 모든 결정이 동시에 완벽할 수는 없다. 하지만 시작점이 80% 완성도라면 나머지 20%는 2-3번의 지시로 도달할 수 있다:\n- 화살표가 너무 짧아, 간격을 넓혀줘 - 색상 대비를 더 높여줘, 배경과 텍스트가 구분이 안 돼 - \u0026#34;Data Layer\u0026#34; 섹션을 더 크게 만들어서 중요도를 강조해줘 핵심은 처음부터 직접 그리는 것 대비 시간을 극적으로 절약한다는 것이다. 매주 수십 개의 다이어그램을 만드는 워크플로에서 이 차이는 수 시간에 달한다.\n나만의 Skills 만들기 가이드 Excalidraw 스킬의 구조를 이해했다면, 자신만의 스킬을 만들 수 있다.\nskill.md 작성 팁 # My Custom Skill ## Purpose 이 스킬이 해결하는 문제를 한 문장으로 정의 ## Inputs - 어떤 종류의 입력을 받는가 - 입력의 형식과 제약 조건 ## Workflow 1. 분석 단계 — 입력을 어떻게 해석하는가 2. 생성 단계 — 무엇을 어떤 순서로 만드는가 3. 검증 단계 — 결과물을 어떻게 확인하는가 ## Quality Criteria - 구체적이고 측정 가능한 품질 기준 - \u0026#34;좋은 결과물\u0026#34;의 정의 ## Anti-patterns - 에이전트가 빠지기 쉬운 함정 - \u0026#34;이렇게 하지 마라\u0026#34;의 구체적 예시 핵심 원칙은 구체성이다. \u0026ldquo;좋은 다이어그램을 만들어라\u0026quot;가 아니라 \u0026ldquo;정보 계층이 3단계 이하이면 단일 패스로 생성하고, 색상은 color-palette.json에서 가져오며, 텍스트 제거 테스트를 통과해야 한다\u0026quot;처럼 써야 한다.\nreference 디렉토리 활용법 skill.md만으로 부족한 정보를 reference 디렉토리에 담는다:\nreference/ ├── color-palette.json # 색상 코드 정의 ├── element-templates/ # 재사용 가능한 패턴 ├── examples/ # 좋은 결과물 예시 └── anti-patterns/ # 나쁜 결과물 예시 특히 예시가 강력하다. \u0026ldquo;이런 결과물을 만들어라\u0026quot;보다 실제 JSON이나 마크다운 예시를 보여주는 것이 에이전트를 정확하게 유도한다.\n검증 루프 설계 원칙 Excalidraw 스킬에서 가장 배울 점은 자체 검증 루프다. 모든 스킬에 이 패턴을 적용할 수 있다:\n결과물을 외부에서 실행/렌더링한다 — JSON이면 파싱, 코드면 실행, 이미지면 렌더링 실행 결과를 에이전트가 직접 확인한다 — 에러 메시지를 읽거나, 스크린샷을 분석 문제를 발견하면 기존 결과물을 수정한다 — 처음부터 재생성하지 않음 반복 횟수를 제한한다 — 무한 루프 방지. 2-4회가 적절 실전 스킬 아이디어 스킬 이름 용도 검증 방법 Code Review PR diff를 구조적으로 분석 체크리스트 항목별 근거 확인 Documentation 코드에서 API 문서 생성 생성된 예제 코드 실행 Test Generator 함수 시그니처에서 테스트 생성 생성된 테스트 실행 Commit Message diff에서 의미 있는 커밋 메시지 conventional commits 규격 검증 Architecture Audit 코드베이스 의존성 분석 순환 의존성 탐지 스크립트 실행 인사이트 Skills 시스템의 본질은 \u0026ldquo;에이전트의 약점을 구조로 보완하는 것\u0026quot;이다. LLM은 범용 능력이 높지만 특정 도메인에서는 체계적 지침 없이 일관된 품질을 내지 못한다. Skills는 그 체계를 패키지로 만들어 재사용 가능하게 한다.\nExcalidraw 스킬에서 가장 주목할 점은 검증 루프다. \u0026ldquo;만들고 끝\u0026quot;이 아니라 \u0026ldquo;만들고 → 확인하고 → 고치고\u0026quot;를 자동화한 것이다. 이 패턴은 다이어그램에만 적용되는 것이 아니다. 코드 생성, 문서 작성, 데이터 분석 등 거의 모든 에이전트 작업에 적용할 수 있다. 에이전트가 자기 작업물을 검증할 수 있는 외부 피드백 루프를 설계하는 것이 스킬 제작의 핵심이다.\n\u0026ldquo;Visual argumentation\u0026quot;이라는 개념도 다이어그램을 넘어선다. 구조 자체가 메시지를 담아야 한다는 원칙은 코드 아키텍처, 문서 구조, API 설계에도 그대로 적용된다. 코드의 디렉토리 구조만 봐도 프로젝트의 관심사 분리가 보여야 하듯, 다이어그램의 레이아웃만 봐도 시스템의 핵심 흐름이 보여야 한다.\n마지막으로, Skills를 만드는 행위 자체가 자신의 전문 지식을 코드화하는 과정이다. \u0026ldquo;나는 다이어그램을 이렇게 만든다\u0026quot;는 암묵지를 명시적 워크플로로 변환하면, 그 지식이 에이전트를 통해 확장 가능(scalable)해진다. 이것이 agentic engineering의 핵심 가치다 — 전문가의 판단을 자동화하는 것이 아니라, 전문가의 프로세스를 자동화하는 것.\n출처: Build BEAUTIFUL Diagrams with Claude Code (Full Workflow) — Cole Medin\n","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-excalidraw-skill/cover.jpg","permalink":"/ko/posts/2026-04-01-excalidraw-skill/","title":"Excalidraw 다이어그램 스킬 — 코딩 에이전트에게 시각적 논증 능력을 부여하는 법"},{"content":"개요 AI 코딩 에이전트 시대에 웹 스크래핑은 단순한 데이터 수집을 넘어 경쟁 분석, 리드 발굴, 시장 조사의 핵심 인프라가 되었다. 하지만 Claude Code의 내장 web fetch만으로는 JavaScript 렌더링 사이트나 anti-bot 보호가 적용된 페이지를 제대로 처리할 수 없다. Firecrawl은 이 문제를 정면으로 해결하는 도구다. 웹 데이터를 LLM이 바로 소화할 수 있는 마크다운과 구조화된 JSON으로 변환해 주며, Claude Code와 MCP 서버로 매끄럽게 연동된다.\nClaude Code의 web fetch, 어디가 부족한가 Claude Code에 내장된 web fetch는 기본적으로 HTML을 직접 가져오는 방식이다. 이 접근법에는 세 가지 명확한 한계가 있다.\nJavaScript 렌더링 실패 — SPA(Single Page Application)나 동적 콘텐츠를 가진 사이트에서 빈 껍데기만 가져온다. SimilarWeb 같은 경쟁 분석 도구에서 통계 데이터를 가져오려 하면 JavaScript로 렌더링되는 수치를 전혀 읽지 못한다. Anti-bot 차단 — Yellow Pages, Booking.com 등 봇 탐지 시스템이 있는 사이트에서 403 에러가 연속으로 발생한다. 실제 테스트에서 Yellow Pages 플러머 검색 시 web fetch는 반복적인 403 에러로 아무 데이터도 가져오지 못했다. 속도와 토큰 비효율 — Amazon 상품 4개 페이지를 스크래핑할 때, web fetch는 5분 30초가 걸린 반면 Firecrawl은 45초 만에 동일한 작업을 완료했다. raw HTML 13,000줄을 LLM에 던지는 것은 토큰 낭비다. Firecrawl이란 Firecrawl은 웹 데이터를 LLM 친화적인 형식으로 변환해 주는 웹 스크래핑 플랫폼이다. 핵심 특징은 다음과 같다.\n마크다운 변환: 웹페이지를 깔끔한 마크다운으로 추출 스키마 지원: 원하는 필드만 정의하면 구조화된 JSON으로 반환 Anti-bot 우회: 자체 Fire Engine으로 봇 탐지 시스템 통과 토큰 효율성: 로컬 파일 시스템 저장 + 필요한 데이터만 추출하여 토큰 사용 최소화 오픈소스: 셀프호스팅 가능 (단, anti-bot 우회와 agent 기능은 유료 전용) Firecrawl vs 전통적 스크래핑 비교 flowchart LR subgraph Traditional[\"기존 방식\u0026lt;br/\u0026gt;Playwright / Puppeteer\"] A[\"브라우저 설치\u0026lt;br/\u0026gt;환경 설정\"] --\u003e B[\"셀렉터 작성\u0026lt;br/\u0026gt;DOM 파싱\"] B --\u003e C[\"Anti-bot\u0026lt;br/\u0026gt;대응 코드\"] C --\u003e D[\"raw HTML\u0026lt;br/\u0026gt;13,000+ lines\"] D --\u003e E[\"후처리\u0026lt;br/\u0026gt;데이터 정제\"] end subgraph Firecrawl[\"Firecrawl 방식\"] F[\"CLI 또는\u0026lt;br/\u0026gt;MCP 호출\"] --\u003e G[\"스키마 정의\u0026lt;br/\u0026gt;JSON schema\"] G --\u003e H[\"자동 Anti-bot\u0026lt;br/\u0026gt;Fire Engine\"] H --\u003e I[\"LLM-ready\u0026lt;br/\u0026gt;Markdown or JSON\"] end style Traditional fill:#ffcccc,stroke:#cc0000 style Firecrawl fill:#ccffcc,stroke:#00cc00 항목 Playwright / Puppeteer Firecrawl 설치 복잡도 브라우저 바이너리 + 드라이버 설정 npx firecrawl 한 줄 Anti-bot 직접 구현 필요 Fire Engine 내장 JS 렌더링 지원 (headless 브라우저) 지원 (관리형 샌드박스) 출력 형식 raw HTML / DOM 객체 Markdown / 구조화 JSON LLM 연동 별도 파이프라인 필요 MCP 서버로 직접 연결 토큰 효율 낮음 (전체 HTML) 높음 (스키마 기반 추출) 대규모 크롤링 직접 구현 crawl / map 명령으로 내장 5가지 핵심 명령어 Firecrawl CLI는 다섯 가지 주요 명령어를 제공한다.\n1. scrape — 단일 페이지 추출 가장 기본적인 명령. URL 하나를 지정하면 해당 페이지의 콘텐츠를 마크다운으로 가져온다.\nnpx firecrawl scrape https://www.amazon.com/dp/B0CZJR9KCZ 2. search — 웹 검색 + 스크래핑 URL을 모를 때 사용한다. 키워드로 검색한 뒤 결과 페이지를 자동으로 스크래핑한다.\nnpx firecrawl search \u0026#34;2026 best noise cancelling headphones review\u0026#34; 3. browse — 클라우드 브라우저 상호작용 클라우드 브라우저 세션을 열어 클릭, 폼 입력, 스냅샷 촬영 등을 수행한다. Playwright의 Firecrawl 버전이라고 보면 된다.\nnpx firecrawl browse https://example.com --action \u0026#34;click login button\u0026#34; 4. crawl — 사이트 전체 크롤링 시작 URL에서 출발해 링크를 따라가며 사이트 전체를 체계적으로 스크래핑한다.\nnpx firecrawl crawl https://docs.example.com --limit 100 5. map — 도메인 URL 탐색 도메인 내 모든 URL을 발견하여 사이트맵을 생성한다. crawl 전에 구조를 파악할 때 유용하다.\nnpx firecrawl map https://example.com Claude Code와 MCP 서버 연동 Firecrawl을 Claude Code에서 사용하는 가장 강력한 방법은 MCP(Model Context Protocol) 서버로 연동하는 것이다. 설정 방법은 간단하다.\n설치 # Firecrawl CLI 설치 npx firecrawl setup # Claude Code에서 MCP 서버 추가 claude mcp add firecrawl -- npx -y firecrawl-mcp 사용 예시 MCP로 연동하면 자연어로 바로 사용할 수 있다.\n# Claude Code에서 자연어로 요청 \u0026#34;이 Amazon 상품 페이지 5개에서 제품명, 가격, 평점, 리뷰 수를 표로 정리해줘\u0026#34; # Claude Code가 자동으로 Firecrawl scrape 스킬을 선택하여 실행 스키마 기반 추출 예시 원하는 데이터 필드를 JSON 스키마로 정의하면 정확히 그 필드만 추출한다.\n{ \u0026#34;type\u0026#34;: \u0026#34;object\u0026#34;, \u0026#34;properties\u0026#34;: { \u0026#34;product_name\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;string\u0026#34; }, \u0026#34;price\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;string\u0026#34; }, \u0026#34;rating\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;number\u0026#34; }, \u0026#34;review_count\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;integer\u0026#34; }, \u0026#34;seller\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;string\u0026#34; } }, \u0026#34;required\u0026#34;: [\u0026#34;product_name\u0026#34;, \u0026#34;price\u0026#34;, \u0026#34;rating\u0026#34;] } 이 스키마를 적용하면 Amazon 상품 페이지에서 13,000줄의 HTML 대신 깔끔한 JSON 5줄을 받게 된다.\n{ \u0026#34;product_name\u0026#34;: \u0026#34;Sony WH-1000XM5 Wireless Headphones\u0026#34;, \u0026#34;price\u0026#34;: \u0026#34;$278.00\u0026#34;, \u0026#34;rating\u0026#34;: 4.5, \u0026#34;review_count\u0026#34;: 12847, \u0026#34;seller\u0026#34;: \u0026#34;Amazon.com\u0026#34; } 실전 데모: Amazon 상품 스크래핑 실제 테스트 결과를 비교해 보자.\n테스트 조건: Amazon 상품 페이지 4개에서 제품 정보 추출\n항목 Claude Code (web fetch) Claude Code + Firecrawl 소요 시간 ~5분 30초 ~45초 성공률 부분 성공 (HTML 파싱 불안정) 100% 토큰 사용 높음 (raw HTML 전체) 낮음 (스키마 필드만) 출력 형식 비정형 텍스트 구조화된 JSON SimilarWeb 테스트 (JavaScript 렌더링 사이트):\nweb fetch: 4분 30초 후 타임아웃, 빈 껍데기만 수집 Firecrawl: 42초, 트래픽 지표/국가별 분류/소셜 미디어 비중까지 완벽 수집 Yellow Pages 테스트 (anti-bot 보호):\nweb fetch: 연속 403 에러, 데이터 0건 Firecrawl: 53초, 16건의 업체 정보 수집 완료 요금제 플랜 크레딧 가격 비고 Free 500 무료 1회성, 체험용 Hobby 3,000/월 $16/월 개인 프로젝트 Standard 100,000/월 $83/월 스타트업 Growth 500,000/월 $333/월 대규모 운영 오픈소스 셀프호스팅도 가능하지만, 다음 기능은 유료 전용이다:\nFire Engine (anti-bot 우회) Agent 모드 Browser Interact Docker 환경 세팅 필요 실전 활용 시나리오 경쟁사 분석 SimilarWeb에서 경쟁사 트래픽 데이터를 주기적으로 수집하여 대시보드 구성. web fetch로는 JavaScript 렌더링 때문에 불가능하지만 Firecrawl은 42초면 끝난다.\n리드 발굴 (Lead Enrichment) 기업 웹사이트를 crawl하여 의사결정자 정보, 기술 스택, 채용 공고 등을 구조화된 데이터로 추출. 50개 기업 사이트를 한 번에 처리 가능.\n시장 조사 Amazon, 쿠팡 등 이커머스 플랫폼에서 경쟁 제품의 가격/평점/리뷰를 스키마 기반으로 수집. 정기적으로 실행하면 가격 변동 추이 파악 가능.\n콘텐츠 수집 기술 블로그, 문서 사이트를 crawl하여 RAG(Retrieval-Augmented Generation) 파이프라인의 지식 베이스 구축.\n인사이트 Firecrawl을 살펴보면서 느낀 점은, 웹 스크래핑의 패러다임이 \u0026ldquo;브라우저를 직접 조작하는 것\u0026quot;에서 \u0026ldquo;원하는 데이터의 스키마를 선언하는 것\u0026quot;으로 전환되고 있다는 것이다.\nPlaywright나 Puppeteer로 셀렉터를 작성하고, anti-bot을 우회하고, HTML을 파싱하는 과정은 결국 **\u0026ldquo;원하는 데이터를 얻기 위한 수단\u0026rdquo;**이었다. Firecrawl은 이 수단을 추상화하고, 개발자가 **\u0026ldquo;무엇을 원하는지\u0026rdquo;**만 선언하면 나머지를 알아서 처리한다. 이것은 SQL이 파일 시스템 직접 접근을 대체한 것과 비슷한 방향성이다.\n다만 무료 크레딧이 500회로 제한되어 있고, 핵심 차별점인 anti-bot 우회가 유료 전용이라는 점은 고려해야 한다. 셀프호스팅 오픈소스 버전은 anti-bot이 빠지므로, 결국 Firecrawl의 진짜 가치는 Fire Engine이라는 독점 기술에 있다. 이 부분이 장기적으로 어떤 가격 구조로 발전할지 지켜볼 필요가 있다.\n그래도 MCP 서버 연동으로 Claude Code 안에서 자연어로 웹 스크래핑을 지시할 수 있다는 점은 개발 워크플로우를 확실히 바꿔놓을 잠재력이 있다. 특히 대규모 데이터 수집이 필요한 프로젝트에서는 투자 대비 시간 절약 효과가 명확하다.\n참고 영상\nClaude Code + Firecrawl = UNLIMITED Web Scraping — Chase AI 퍼페티어는 이제 그만! AI 웹 스크래핑 끝판왕 Firecrawl CLI 등장 — Nova AI Daily ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-firecrawl-web-scraping/cover.jpg","permalink":"/ko/posts/2026-04-01-firecrawl-web-scraping/","title":"Firecrawl — AI 시대의 웹 스크래핑 끝판왕"},{"content":"개요 이전 포스트에서 Observability vs Monitoring 비교 분석과 Honeycomb과 Observability 입문 — 오픈소스 대안 비교를 다뤘다. 이번에는 한 단계 더 나아가 Honeycomb이 MCP(Model Context Protocol) Server를 GA로 출시하면서, observability 데이터를 AI 도구에 직접 연결하는 새로운 워크플로우를 살펴본다. Canvas(인앱 AI)와 IDE 연동까지 포함하면, \u0026ldquo;데이터 확인 -\u0026gt; 원인 분석 -\u0026gt; 코드 수정\u0026quot;이 하나의 흐름으로 이어진다.\nHoneycomb MCP Server GA - AI와 Observability의 연결 Honeycomb의 MCP Server가 GA(General Availability)로 출시되었다. Austin Parker(Honeycomb MCP 프로덕트 리드)가 소개한 핵심 컨셉은 간단하다: observability 데이터를 AI 도구가 있는 곳으로 가져온다.\nMCP(Model Context Protocol)는 AI 에이전트가 외부 도구와 통신하는 표준 프로토콜이다. Honeycomb MCP Server를 설정하면 Claude Desktop, Cursor, VS Code Copilot, Claude Code 등 다양한 AI 환경에서 production 데이터에 직접 접근할 수 있다.\nMCP Server가 제공하는 주요 기능:\n환경 정보 조회: 서비스 맵, dataset, environment 상세 정보 쿼리 실행: 자연어로 Honeycomb 쿼리를 생성하고 실행 SLO 모니터링: SLO 상태 확인 및 보드(Board) 조회 트레이스 탐색: trace ID로 상세 trace waterfall 확인 OpenTelemetry 가이드: 최신 계측(instrumentation) 정보 제공 Canvas: 인앱 AI 어시스턴트 Canvas는 Honeycomb 내부에 탑재된 AI 어시스턴트다. 대화 인터페이스로 observability 데이터를 탐색한다.\n작동 방식 Canvas를 열고 자연어로 질문한다: \u0026ldquo;How is our app responding?\u0026rdquo; Canvas가 적절한 environment와 service를 파악한다 필요한 쿼리를 자동으로 생성하고 실행한다 결과 그래프가 대화 옆에 나란히 표시된다 AI가 데이터의 스토리를 서술한다 \u0026ndash; 예: \u0026ldquo;latency가 증가하고 있다\u0026rdquo; Honeycomb이 2016년 설립 당시부터 고수한 원칙이 여기서 빛을 발한다: 어떤 attribute에 대해서든, 어떤 쿼리든 빠르게 실행할 수 있어야 한다. AI는 분당 수십 개의 쿼리를 연속으로 던질 수 있고, Honeycomb의 빠른 쿼리 엔진이 이를 뒷받침한다.\nAI 결과 검증의 중요성 Canvas가 제공하는 모든 그래프는 클릭 가능하다. 쿼리가 정확한지 직접 확인할 수 있고, trace waterfall로 드릴다운하여 원본 데이터를 검토할 수 있다. AI의 결론을 맹목적으로 신뢰하지 않고 근거를 검증하는 것이 핵심이다.\nIDE 연동: VS Code/Cursor + Copilot Honeycomb MCP의 진정한 강점은 IDE 안에서 production 데이터와 코드를 동시에 볼 수 있다는 점이다.\n커스텀 Slash Commands MCP Server를 설정하면 IDE에서 Honeycomb 전용 slash command를 사용할 수 있다:\n/otel-analysis: 코드의 OpenTelemetry 계측 상태를 분석한다. AI가 학습 시점의 오래된 정보가 아니라, MCP를 통해 최신 정보를 참조한다. /otel-instrumentation: 계측 가이드를 제공한다. 어떤 span을 추가해야 하는지, 어떤 attribute가 유용한지 안내한다. 이 slash command들의 핵심 가치는 정보의 최신성이다. AI 에이전트가 학습한 OpenTelemetry 지식은 시간이 지나면 outdated 된다. MCP는 항상 최신 문서와 best practice를 참조할 수 있는 경로를 제공한다.\nDemo: 새 팀원 온보딩 시나리오 MCP Server GA 발표 데모에서 인상적이었던 것은 온보딩 시나리오다.\nClaude Desktop에 Honeycomb MCP를 연결한 뒤, \u0026ldquo;첫 출근한 신입 개발자가 시스템을 파악할 수 있도록 interactive artifact를 만들어 달라\u0026quot;고 요청했다. 결과물:\nDataflow Architecture: 시스템 간 데이터 흐름을 시각화한 인터랙티브 다이어그램 Critical SLOs: 핵심 SLO 목록과 현재 상태 주요 Board 링크: 모니터링 대시보드로 바로 이동 Trace/Query 바로가기: 클릭 한 번으로 실제 trace나 쿼리로 점프 이 모든 것이 MCP의 get_environment_details, get_service_map, get_slos, get_boards, run_query 같은 도구를 조합해서 자동으로 생성된다. 수동으로 wiki를 작성하고 스크린샷을 첨부하는 것과는 차원이 다르다.\nReal Debugging Flow: Canvas에서 코드 수정까지 가장 실용적인 시나리오는 end-to-end 디버깅 흐름이다. 데모에서 보여준 실제 플로우를 정리하면:\nflowchart LR A[\"Canvas에서 질문\u0026lt;br/\u0026gt;How is our app responding?\"] --\u003e B[\"쿼리 자동 실행\u0026lt;br/\u0026gt;latency 이상 발견\"] B --\u003e C[\"Trace 드릴다운\u0026lt;br/\u0026gt;checkout 서비스 지연\"] C --\u003e D[\"Root Cause 특정\u0026lt;br/\u0026gt;get_discounts N+1 쿼리\"] D --\u003e E[\"IDE에서 MCP 연동\u0026lt;br/\u0026gt;코드 위치 자동 탐색\"] E --\u003e F[\"수정 제안\u0026lt;br/\u0026gt;batch query로 변환\"]단계별 상세 1단계 \u0026ndash; Canvas에서 이상 감지\nCanvas에 \u0026ldquo;How is our app responding?\u0026ldquo;이라고 질문하면, 여러 서비스의 latency와 error rate를 자동으로 쿼리한다. 이 과정에서 checkout 서비스의 P99 latency가 비정상적으로 높은 것을 발견한다.\n2단계 \u0026ndash; Trace 드릴다운\nCanvas가 느린 trace ID를 찾아 trace waterfall을 로드한다. Checkout 부분을 확대하면 get_discounts 함수에서 대부분의 시간이 소비되고 있음을 확인한다.\n3단계 \u0026ndash; IDE로 전환\n여기서 Canvas의 한계가 나온다. 코드를 직접 수정하려면 IDE로 넘어가야 한다. VS Code + Copilot에 Honeycomb MCP를 설정한 상태에서, \u0026ldquo;Honeycomb에서 checkout latency 문제를 확인하고 코드에서 원인을 찾아라\u0026quot;고 요청한다.\n4단계 \u0026ndash; MCP가 쿼리 실행\nIDE의 AI 에이전트가 MCP를 통해 Honeycomb에 쿼리를 실행한다. 동일한 latency 패턴을 확인하고, trace 데이터에서 get_discounts의 N+1 쿼리 패턴을 식별한다.\n5단계 \u0026ndash; 코드 탐색 및 수정 제안\n에이전트가 코드베이스에서 get_discounts 함수를 찾고, 반복문 안에서 개별 DB 쿼리를 실행하는 패턴을 발견한다. Batch query로 변환하는 구체적인 수정안을 제시한다.\nMCP의 효율적 통신 방식 Honeycomb MCP는 AI 에이전트와의 통신에서 토큰 효율성을 극대화하도록 설계되었다.\n일반적으로 API 응답은 JSON 형태로 돌아오지만, Honeycomb MCP는 상황에 따라 다양한 포맷을 조합한다:\n포맷 용도 Text 서술형 설명, 컨텍스트 전달 CSV 표 형태 쿼리 결과 (행/열 데이터) JSON 구조화된 메타데이터 ASCII Art trace waterfall, 간단한 시각화 이 혼합 포맷 전략의 목적은 명확하다. LLM이 소비하는 토큰을 최소화하면서 필요한 정보를 최대한 전달하는 것이다. 그래프 이미지를 통째로 보내는 대신 CSV 데이터를 보내면 토큰이 훨씬 적게 들고, AI가 수치를 정확히 파악할 수 있다.\nCanvas(인앱)에서는 그래프가 자동으로 렌더링되지만, MCP를 통한 IDE 연동에서는 그래프 대신 쿼리 링크를 제공한다. 필요하면 해당 링크를 클릭해서 Honeycomb UI에서 직접 확인하면 된다.\nOpenTelemetry Instrumentation Guidance MCP가 단순히 \u0026ldquo;데이터를 읽는\u0026rdquo; 도구를 넘어서는 지점이 여기다. Honeycomb은 OpenTelemetry 전문 지식을 MCP를 통해 AI 에이전트에게 제공한다.\n실질적으로 이것이 의미하는 바:\n코드에 어떤 span을 추가해야 하는지 AI가 제안할 때, Honeycomb의 최신 best practice를 참조한다 otel-instrumentation slash command를 통해, 사용 중인 언어/프레임워크에 맞는 계측 가이드를 받을 수 있다 AI 모델의 학습 데이터가 아니라 실시간으로 업데이트되는 가이드를 기반으로 조언한다 이는 OpenTelemetry의 빠른 버전 변화를 고려하면 매우 실용적이다. SDK 버전에 따라 API가 달라지는 상황에서 outdated된 정보로 계측하면 오히려 문제를 만든다.\n인사이트 Observability의 소비 방식이 바뀌고 있다. 기존에는 대시보드를 열고, 그래프를 보고, 의심되는 trace를 수동으로 찾았다. Honeycomb Canvas와 MCP는 이 과정을 \u0026ldquo;질문하면 답이 오는\u0026rdquo; 형태로 바꾼다.\nIDE 연동이 game changer다. Production 데이터와 코드가 같은 화면에 있으면 context switching이 사라진다. 데모에서 보여준 N+1 쿼리 디버깅처럼, trace에서 발견한 문제를 바로 코드에서 수정할 수 있다. 이건 Honeycomb 웹 UI만으로는 불가능했던 워크플로우다.\nMCP의 토큰 효율성 설계가 인상적이다. Text + CSV + JSON + ASCII art를 조합해서 최소 토큰으로 최대 정보를 전달하는 접근은, 다른 MCP 서버 구현에도 참고할 만한 패턴이다. AI 시대에 API 설계는 \u0026ldquo;사람이 읽기 편한 것\u0026quot;뿐 아니라 \u0026ldquo;AI가 효율적으로 소비할 수 있는 것\u0026quot;도 고려해야 한다.\n새 팀원 온보딩 시나리오가 현실적이다. 시스템 아키텍처, SLO 현황, 주요 대시보드를 한 번의 프롬프트로 파악할 수 있다면, 온보딩에 걸리는 시간이 극적으로 줄어든다. 이것은 observability 도구가 \u0026ldquo;장애 대응 전용\u0026quot;에서 \u0026ldquo;일상적 개발 도구\u0026quot;로 확장되는 사례다.\n참고 자료\nIntroducing Honeycomb Intelligence MCP Server - Now GA! \u0026ndash; Honeycomb 공식 GA 발표 AI for Observability: Honeycomb Canvas \u0026amp; MCP \u0026ndash; Canvas + MCP 디버깅 데모 ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-honeycomb-mcp/cover.jpg","permalink":"/ko/posts/2026-04-01-honeycomb-mcp/","title":"Honeycomb MCP로 Observability 자동화하기"},{"content":"이전 글에서 Observability와 Monitoring의 차이, Honeycomb과 Grafana의 접근 방식을 비교했다. 이번에는 Honeycomb 공식 문서를 깊이 파고들어 observability의 핵심 개념을 정리하고, 셀프호스팅 가능한 오픈소스 대안들을 실무 관점에서 비교해 본다.\n이전 글: Observability vs Monitoring — Honeycomb vs Grafana\nObservability 핵심 개념 Honeycomb 문서에서 가장 강조하는 정의는 이것이다:\nObservability is about being able to ask arbitrary questions about your environment without having to know ahead of time what you wanted to ask.\nMonitoring은 이미 알고 있는 문제에 대한 threshold를 설정하고 alert을 받는 것이다. 반면 observability는 예상하지 못한 질문을 던질 수 있어야 한다. 마이크로서비스 환경에서 장애의 원인은 무한히 조합될 수 있기 때문에, 미리 정의한 dashboard만으로는 새로운 유형의 문제를 진단할 수 없다.\nObservability를 개선하려면 두 가지가 필요하다:\n풍부한 런타임 컨텍스트를 포함한 텔레메트리 데이터 수집 그 데이터를 반복적으로 쿼리하여 인사이트를 발견하는 능력 Structured Events vs Metrics vs Logs Honeycomb의 데이터 모델 핵심은 structured event다. Event, metric, log 각각의 차이를 이해하는 것이 observability 입문의 출발점이다.\nStructured Event Event는 하나의 작업 단위(unit of work)를 완전하게 설명하는 JSON 객체다. HTTP 요청을 받아 처리하고 응답을 돌려주는 전체 과정이 하나의 event가 된다.\n{ \u0026#34;service.name\u0026#34;: \u0026#34;retriever\u0026#34;, \u0026#34;duration_ms\u0026#34;: 0.011668, \u0026#34;dataset_id\u0026#34;: \u0026#34;46829\u0026#34;, \u0026#34;global.env\u0026#34;: \u0026#34;production\u0026#34;, \u0026#34;global.instance_type\u0026#34;: \u0026#34;m6gd.2xlarge\u0026#34;, \u0026#34;global.memory_inuse\u0026#34;: 671497992, \u0026#34;trace.trace_id\u0026#34;: \u0026#34;845a4de7-...\u0026#34;, \u0026#34;trace.span_id\u0026#34;: \u0026#34;84c82b34...\u0026#34; } 핵심은 모든 필드가 쿼리 가능하다는 것이다. duration_ms로 느린 요청을 찾고, instance_type별로 그룹핑하고, memory_inuse와의 상관관계를 한 번에 탐색할 수 있다.\nPre-aggregated Metrics의 한계 Metrics 방식은 데이터를 미리 집계해서 보낸다:\n{ \u0026#34;time\u0026#34;: \u0026#34;4:03 pm\u0026#34;, \u0026#34;total_hits\u0026#34;: 500, \u0026#34;avg_duration\u0026#34;: 113, \u0026#34;p95_duration\u0026#34;: 236 } 만약 \u0026ldquo;storage engine cache hit 여부에 따른 latency 차이\u0026quot;를 보고 싶다면? avg_duration_cache_hit_true, p95_duration_cache_hit_true 같은 조합을 미리 만들어야 한다. 이것이 차원의 저주(curse of dimensionality) — 차원이 늘어날수록 필요한 metric 수가 기하급수적으로 증가한다.\nUnstructured Logs의 한계 로그는 사람이 읽기엔 편하지만 쿼리하기 어렵다. \u0026ldquo;어떤 서비스가 시작하는 데 가장 오래 걸리나?\u0026ldquo;를 알려면 여러 줄의 timestamp를 파싱하고 빼야 한다. Structured event는 duration_ms 필드 하나로 즉시 답할 수 있다.\ngraph TD A[\"Telemetry Data\"] --\u003e B[\"Structured Events\"] A --\u003e C[\"Metrics\"] A --\u003e D[\"Logs\"] B --\u003e B1[\"모든 필드 쿼리 가능 \u0026lt;br/\u0026gt; High Cardinality 지원\"] C --\u003e C1[\"미리 집계 필요 \u0026lt;br/\u0026gt; 차원의 저주\"] D --\u003e D1[\"파싱 필요 \u0026lt;br/\u0026gt; 구조화 어려움\"] B1 --\u003e E[\"Observability 달성\"] C1 --\u003e F[\"Monitoring 수준\"] D1 --\u003e F style B fill:#f5a623,color:#000 style E fill:#7ed321,color:#000 style F fill:#d0021b,color:#fffDistributed Tracing Tracing은 분산 시스템의 여러 서비스에서 발생하는 계측(instrumentation)을 하나로 연결하여 크로스 서비스 장애를 파악할 수 있게 해준다. 프록시, 앱, 데이터베이스만 있어도 이미 분산 시스템이다.\nTrace의 동작 원리 Trace는 시스템 내 완전한 작업 단위의 이야기를 담는다. 사용자가 페이지를 로드하면 요청이 edge proxy, frontend, auth, rate limiter, backend, DB를 거치게 된다. 이 이야기의 각 부분을 span이 담당한다.\nSpan은 코드의 특정 위치에서 수행되는 하나의 작업 단위를 나타내며, 다음 정보를 포함한다:\nserviceName — 해당 span이 속한 서비스 name — span의 역할 (함수명, 메서드명) timestamp와 duration — 시작 시점과 소요 시간 traceID — 이 span이 속한 trace 식별자 parentID — 이 span을 호출한 부모 span graph LR A[\"Client 요청\"] --\u003e B[\"Edge Proxy \u0026lt;br/\u0026gt; span 1\"] B --\u003e C[\"Frontend \u0026lt;br/\u0026gt; span 2\"] C --\u003e D[\"Auth Service \u0026lt;br/\u0026gt; span 3\"] C --\u003e E[\"Rate Limiter \u0026lt;br/\u0026gt; span 4\"] C --\u003e F[\"Backend API \u0026lt;br/\u0026gt; span 5\"] F --\u003e G[\"Database \u0026lt;br/\u0026gt; span 6\"] style A fill:#e8e8e8,color:#000 style B fill:#4a90d9,color:#fff style F fill:#f5a623,color:#000 style G fill:#7ed321,color:#000같은 traceID를 공유하는 모든 span이 모여 하나의 요청이 전체 시스템을 어떻게 흘렀는지 완전한 그림을 만든다. Span의 duration을 분석하면 정확히 어떤 서비스가 병목인지 파악할 수 있다 — 전통적인 로그나 메트릭만으로는 불가능한 일이다.\nHigh Cardinality의 중요성 Cardinality란 특정 필드가 가질 수 있는 고유 값의 수를 말한다. user_id, trace_id, request_id 같은 필드는 수백만 개의 고유 값을 가진다 — 이것이 high cardinality다.\n전통적인 metrics 도구(Prometheus, Graphite 등)는 high cardinality를 잘 처리하지 못한다. Label 조합이 폭발적으로 증가하면 성능이 급격히 저하된다. 하지만 observability에서는 \u0026ldquo;이 특정 사용자에게 왜 느린가?\u0026ldquo;처럼 개별 값을 추적해야 하는 질문이 핵심이다.\nHoneycomb은 columnar storage 기반으로 high cardinality 데이터를 효율적으로 처리한다. BubbleUp 기능은 이상치(outlier)를 자동으로 감지하고, 어떤 필드 조합이 문제와 상관있는지 찾아준다.\nCore Analysis Loop Honeycomb이 제안하는 디버깅 방법론은 Core Analysis Loop다:\n관찰(Observe): 시스템의 전체 상태를 시각화한다 가설 수립(Hypothesize): 이상 패턴을 발견하면 원인에 대한 가설을 세운다 검증(Validate): 데이터를 GROUP BY, WHERE로 쪼개어 가설을 검증하거나 기각한다 반복(Iterate): 새로운 질문으로 돌아가 반복한다 이것은 \u0026ldquo;dashboard를 보고 alert를 기다리는\u0026rdquo; monitoring 방식과 근본적으로 다르다. Query Builder에서 SELECT, WHERE, GROUP BY, ORDER BY, LIMIT, HAVING 절을 조합하여 자유롭게 데이터를 탐색한다.\nHoneycomb Intelligence — AI 기반 분석 Honeycomb Intelligence는 엔지니어가 더 빠르게 조사할 수 있도록 돕는 AI 기능 모음이다. 주요 기능은 다음과 같다:\nCanvas — 자연어로 시스템에 대한 질문을 할 수 있는 대화형 조사 도구. 쿼리, 시각화, 설명을 자동으로 생성하여 대화형 디버깅 경험을 제공한다 Query Assistant — 자연어 설명으로 Honeycomb 쿼리를 자동 생성한다. \u0026ldquo;show me the slowest endpoints grouped by service\u0026rdquo; 같은 입력이 실행 가능한 쿼리가 된다 Hosted MCP Service — Honeycomb이 Model Context Protocol (MCP) 서버를 제공하여 AI 에이전트와 도구(Claude, Cursor 등)가 Honeycomb 데이터를 직접 쿼리할 수 있다 Honeycomb의 AI 원칙은 어떤 기능이 AI를 사용하는지 투명하게 공개하고, 고객 데이터를 모델 학습에 사용하지 않으며, AI 기능을 선택적으로 사용할 수 있도록 보장한다. 서드파티 AI 제공업체(OpenAI, Anthropic)에 전송되는 데이터는 학습 금지 조항이 포함된 데이터 처리 계약 하에 처리된다.\nOpenTelemetry로 데이터 전송 Honeycomb은 OpenTelemetry를 네이티브로 지원한다. 처음 계측을 시작한다면 OpenTelemetry로 시작하는 것을 권장한다.\n주요 연동 포인트 OTLP 프로토콜: gRPC, HTTP/protobuf, HTTP/JSON을 통한 OTLP 데이터 수신 지원 직접 전송: 간단한 구성에서는 별도 collector 없이 Honeycomb 엔드포인트로 직접 전송 가능 Collector 지원: OpenTelemetry Collector로 레거시 포맷(OpenTracing, Zipkin, Jaeger)을 OTLP로 변환 최소 설정은 환경 변수 두 개면 충분하다:\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\u0026#34;https://api.honeycomb.io:443\u0026#34; export OTEL_EXPORTER_OTLP_HEADERS=\u0026#34;x-honeycomb-team=YOUR_API_KEY\u0026#34; Go, Python, Java, .NET, Node.js, Ruby 등 다양한 언어의 OpenTelemetry SDK가 제공되며, 각 SDK는 주요 프레임워크에 대한 자동 계측을 지원한다. 최소한의 코드 변경으로 trace와 metric을 수집할 수 있다.\n레거시 시스템에서의 마이그레이션 이미 Jaeger, Zipkin, OpenTracing으로 계측된 시스템이 있다면, OpenTelemetry Collector가 브릿지 역할을 한다 — 레거시 포맷 데이터를 받아 OTLP로 변환하여 Honeycomb에 전송한다. 전체 재계측 없이 점진적 마이그레이션이 가능하다.\neBPF와 Observability eBPF(extended Berkeley Packet Filter) 는 Linux 커널을 수정하지 않고 확장 기능을 실행할 수 있는 기술이다. Observability 관점에서 중요한 이유는 코드 변경 없이 텔레메트리를 수집할 수 있기 때문이다.\n동작 원리 JIT Compiler: eBPF 프로그램은 커널 내 JIT 컴파일러로 실행되어 고성능을 보장한다 Hook Points: system call, 함수 진입/종료, kernel tracepoint, network event 등 미리 정의된 hook에 연결된다 Kprobes / Uprobes: 미리 정의된 hook이 없으면 커널 프로브(Kprobes)나 유저 프로브(Uprobes)를 생성하여 거의 모든 지점에 eBPF 프로그램을 부착할 수 있다 Observability에서의 활용 자동 계측(automatic instrumentation) 도구가 없는 언어(C++, Rust 등)에서 eBPF는 특히 유용하다. 애플리케이션 외부에서 커널 프로브를 통해 네트워크 활동, CPU/메모리 사용률, 네트워크 인터페이스 메트릭 등을 수집할 수 있다.\nOpenTelemetry는 현재 Go 언어용 eBPF 기반 자동 계측 도구를 개발 중이며, HTTP client/server, gRPC, gorilla/mux 라우터 등을 지원한다. C++과 Rust 지원도 계획되어 있다.\n오픈소스 대안 비교 Honeycomb은 강력하지만 SaaS 종속성과 비용이 부담될 수 있다. 셀프호스팅 가능한 오픈소스 대안을 살펴보자.\nJaeger 개발사: Uber 백엔드: Cassandra / Elasticsearch 특징: 스팬(span) 단위 호출 시간/지연 분석이 핵심 강점. Zipkin과 호환되며, OpenTelemetry 네이티브 지원 배포: Kubernetes Helm 차트, Jaeger Operator로 쉬운 배포 UI: 16686 포트에서 서비스별 duration 쿼리, 트레이스 타임라인 시각화 # All-in-one 실행 (개발/테스트용) ./jaeger-all-in-one --memory-max-table-size=100000 # EKS 배포 kubectl create namespace observability kubectl apply -f jaeger-operator.yaml Zipkin 개발사: Twitter 백엔드: Elasticsearch / MySQL 특징: 가볍고 심플한 트레이싱 서버. Spring Cloud Sleuth와 네이티브 연동 배포: Docker 한 줄로 실행 가능 docker run -d -p 9411:9411 openzipkin/zipkin 서비스 호출 그래프와 의존성(dependency) 다이어그램을 자동 생성하며, 장애 분석에 유용하다. 다만 OpenTelemetry 지원은 브릿지 방식이라 네이티브에 비해 설정이 더 필요하다.\nSigNoz 특징: OpenTelemetry 네이티브 오픈소스 APM. Honeycomb 스타일의 쿼리와 대시보드를 셀프호스팅으로 제공 백엔드: ClickHouse (고성능 columnar DB) 장점: 로그, 메트릭, 트레이스를 하나의 플랫폼에서 통합. Honeycomb의 가장 가까운 오픈소스 대안 배포: AWS ECS CloudFormation 템플릿, Kubernetes 풀스택 배포 지원 SigNoz는 OTLP(OpenTelemetry Protocol)을 직접 수신하므로 별도 변환 없이 OpenTelemetry Collector에서 데이터를 보낼 수 있다.\nPinpoint 개발사: Naver 백엔드: HBase 특징: 대규모 Java 애플리케이션 트레이싱에 최적화. 바이트코드 계측으로 코드 변경 없이 에이전트 적용 강점: Scatter/Timeline 차트로 호출 흐름과 시간을 상세 분석. 한국 대기업 환경에서 검증된 안정성 # 에이전트 적용 (JVM 옵션) java -javaagent:pinpoint-agent.jar \\ -Dpinpoint.agentId=myapp-01 \\ -Dpinpoint.applicationName=my-service \\ -jar my-application.jar 비교 테이블 도구 백엔드 OTel 지원 K8s 배포 핵심 강점 Honeycomb SaaS (AWS) 네이티브 N/A (SaaS) High cardinality 쿼리, BubbleUp, AI 분석 Jaeger ES / Cassandra 네이티브 Helm / Operator 고트래픽 스팬 트레이싱 Zipkin ES / MySQL 브릿지 기본 Deployment 간단 배포, Spring 연동 SigNoz ClickHouse 네이티브 풀스택 올인원 관찰성 (로그+메트릭+트레이스) Pinpoint HBase 부분 지원 지원 대규모 Java APM, 바이트코드 계측 Honeycomb 가격 (2026 기준) 플랜 월 비용 이벤트 한도 보관 기간 대상 Free 무료 20M/월 60일 소규모 팀, 테스트 Pro $100~ 1.5B/월 60일 성장 팀, SLO 필요 Enterprise 맞춤 무제한 확장 대규모, Private Cloud 연간 계약 시 15~20% 할인이 적용된다. Free 플랜의 20M 이벤트는 소규모 서비스 검증에 충분하다.\n인사이트 Observability의 본질은 도구가 아니라 사고방식의 전환이다. \u0026ldquo;어떤 dashboard를 만들까?\u0026ldquo;가 아니라 \u0026ldquo;어떤 질문이든 던질 수 있는가?\u0026ldquo;가 핵심이다. Honeycomb은 이 철학을 structured event와 high cardinality 쿼리로 구현했다.\nHoneycomb Intelligence의 등장은 업계의 방향을 보여준다 — 자연어로 쿼리를 생성하고 Canvas를 통한 조사 가이드를 제공하는 AI 기반 디버깅. MCP 연동은 AI 에이전트가 프로덕션 텔레메트리를 직접 쿼리할 수 있게 하여 효과적인 observability의 진입 장벽을 더욱 낮춘다.\n실무에서의 선택 기준을 정리하면:\n빠른 시작: Honeycomb Free 플랜 (20M 이벤트/월)으로 observability 경험을 먼저 쌓고 셀프호스팅 올인원: SigNoz가 Honeycomb에 가장 가까운 오픈소스 대안. ClickHouse 백엔드의 쿼리 성능이 좋고 OTel 네이티브 Java 중심 레거시: Pinpoint가 바이트코드 계측으로 코드 변경 없이 적용 가능 이미 Kubernetes에 익숙하다면: Jaeger + OpenTelemetry Collector 조합이 생태계가 가장 넓음 마이그레이션 경로: OpenTelemetry Collector가 레거시 계측(Jaeger/Zipkin 포맷)을 모든 현대 백엔드로 브릿지하여 점진적 도입이 가능 eBPF는 아직 초기 단계지만, 코드 변경 없는 계측이라는 점에서 Go, C++, Rust 생태계에서 점점 중요해질 기술이다. OpenTelemetry의 eBPF 기반 자동 계측이 성숙하면 observability 도입 비용이 크게 낮아질 것이다.\n참고 자료 Honeycomb Docs: Introduction to Observability Honeycomb Docs: Events, Metrics, and Logs Honeycomb Docs: Distributed Tracing Honeycomb Docs: eBPF Honeycomb Docs: Build a Query Honeycomb Docs: Send Data with OpenTelemetry Honeycomb Docs: Honeycomb Intelligence Jaeger - Distributed Tracing Zipkin SigNoz - Open Source APM Pinpoint - Application Performance Management ","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-honeycomb-observability/cover.jpg","permalink":"/ko/posts/2026-04-01-honeycomb-observability/","title":"Honeycomb과 Observability 입문 — 오픈소스 대안 비교"},{"content":"Google NotebookLM은 \u0026ldquo;코드 없는 RAG\u0026quot;라는 개념을 현실로 만든 도구입니다. 자신의 문서, 영상, URL을 소스로 올리면 그 데이터만을 기반으로 답변하는 커스텀 AI 비서를 만들 수 있습니다. 이 글에서는 오빠두엑셀 채널의 실전 튜토리얼 영상을 바탕으로, 1년 이상 사용 경험에서 나온 12가지 활용법과 데이터 준비 노하우를 상세히 정리합니다.\nNotebookLM이란 무엇인가 \u0026ldquo;코드 없는 RAG\u0026rdquo; — 자신의 데이터로 만드는 커스텀 AI RAG(Retrieval-Augmented Generation)는 외부 데이터를 검색해서 LLM의 답변에 근거를 부여하는 기술입니다. 전통적으로 RAG를 구현하려면 문서를 chunking하고, embedding 벡터를 생성하고, 벡터 DB에 저장한 뒤 retrieval 파이프라인을 구축해야 합니다. NotebookLM은 이 모든 과정을 UI 하나로 해결합니다. 사용자는 소스를 업로드하기만 하면 되고, Google이 내부적으로 RAG 파이프라인을 처리합니다.\n핵심은 **\u0026ldquo;내 데이터만을 기반으로 답변한다\u0026rdquo;**는 점입니다. ChatGPT나 Gemini에게 질문하면 학습 데이터 전체에서 답변을 생성하지만, NotebookLM은 사용자가 업로드한 소스 범위 안에서만 답변합니다. 이것이 바로 hallucination 문제를 구조적으로 해결하는 방식입니다.\nChatGPT의 Hallucination 문제와 소스 기반 답변 유명한 \u0026ldquo;세종대왕 맥북 사건\u0026quot;이 좋은 예시입니다. ChatGPT에게 \u0026ldquo;세종대왕이 맥북을 던진 이유\u0026quot;를 물으면, 실제로는 존재하지 않는 사건임에도 그럴듯한 답변을 생성합니다. 이것이 hallucination입니다. LLM이 학습 데이터에서 패턴을 조합해 사실이 아닌 내용을 자신있게 출력하는 현상이죠.\nNotebookLM은 이 문제를 원천적으로 차단합니다. 소스에 없는 내용은 \u0026ldquo;해당 정보가 소스에 없습니다\u0026quot;라고 답변하며, 모든 답변에 소스 인용 번호가 붙어 있어 출처를 바로 확인할 수 있습니다. 업무 보고서나 논문 리뷰처럼 정확성이 중요한 작업에서 이 차이는 결정적입니다.\n프롬프트 엔지니어링에서 데이터 엔지니어링으로 기존 AI 활용의 핵심은 \u0026ldquo;어떻게 질문할 것인가\u0026rdquo;, 즉 프롬프트 엔지니어링이었습니다. NotebookLM에서는 패러다임이 바뀝니다. **\u0026ldquo;어떤 데이터를 넣을 것인가\u0026rdquo;**가 답변 품질을 결정합니다. 좋은 프롬프트보다 좋은 소스가 더 중요한 세상입니다. 이것을 데이터 엔지니어링이라 부를 수 있으며, NotebookLM 활용의 핵심 역량이 됩니다.\nflowchart LR subgraph 기존방식[\"기존 AI 활용\"] direction TB A[\"범용 LLM \u0026lt;br/\u0026gt; ChatGPT, Gemini\"] B[\"프롬프트 엔지니어링 \u0026lt;br/\u0026gt; 질문을 잘 해야 함\"] C[\"Hallucination 위험 \u0026lt;br/\u0026gt; 출처 불분명\"] A --\u003e B --\u003e C end subgraph 새방식[\"NotebookLM 방식\"] direction TB D[\"소스 업로드 \u0026lt;br/\u0026gt; PDF, URL, 영상 등\"] E[\"데이터 엔지니어링 \u0026lt;br/\u0026gt; 좋은 소스 선별\"] F[\"소스 기반 답변 \u0026lt;br/\u0026gt; 인용 번호 포함\"] D --\u003e E --\u003e F end 기존방식 -- \"패러다임 전환\" --\u003e 새방식데이터 준비가 핵심 소스 종류 NotebookLM이 지원하는 소스 유형은 다양합니다:\n텍스트 문서: Google Docs, 복사-붙여넣기 텍스트 PDF 파일: 논문, 보고서, 계약서 등 URL: 웹페이지, 블로그 글 영상: YouTube 동영상 (자막 기반 분석) 이미지: 스크린샷, 도표 (OCR 기반) 오디오: 녹음 파일, 팟캐스트 특히 YouTube 영상을 소스로 넣으면 자막을 자동으로 추출해서 분석합니다. 1시간짜리 강의 영상도 URL 하나로 소스화할 수 있어, 영상 학습의 효율이 극적으로 올라갑니다.\nDeep Research로 소스 자동 수집 NotebookLM에는 Deep Research 기능이 내장되어 있습니다. 특정 주제에 대해 웹을 검색하고, 관련 소스를 자동으로 수집해서 노트북에 추가합니다. 두 가지 모드가 있습니다:\n빠른 검색: 키워드 기반으로 빠르게 관련 소스를 찾아줍니다. 간단한 조사에 적합합니다. 딥 리서치 모드: 여러 소스를 교차 분석하며 심층적으로 조사합니다. \u0026ldquo;2026년 반도체 산업 전망\u0026quot;처럼 복잡한 주제를 조사할 때 유용합니다. 수집된 소스는 노트북에 자동으로 추가되므로, 일일이 URL을 찾아서 넣는 수고를 덜 수 있습니다. 다만 자동 수집된 소스의 신뢰성은 반드시 교차 검증해야 합니다.\n소스 한도와 관리 무료 플랜: 노트북당 최대 50개 소스 Pro 플랜: 노트북당 최대 300개 소스 대부분의 업무 용도에서 50개면 충분합니다. 핵심은 소스의 양이 아니라 질입니다. 관련 없는 소스가 많으면 오히려 답변 품질이 떨어집니다.\n데이터 정제 프로세스 (1년+ 사용 경험 기반) 영상의 발표자는 1년 이상 NotebookLM을 사용하면서 체득한 데이터 정제 프로세스를 공유합니다:\n주제 명확화: 노트북 하나에 하나의 주제만 담기. \u0026ldquo;AI 전반\u0026quot;이 아니라 \u0026ldquo;2026년 생성형 AI 시장 전망\u0026quot;처럼 구체적으로. 소스 큐레이션: 신뢰할 수 있는 소스만 선별. 블로그 글보다 논문, 공식 보고서, 1차 자료 우선. 중복 제거: 같은 내용을 다루는 소스가 여러 개이면 가장 포괄적인 것 하나만 남기기. 노트 활용: 소스를 넣은 뒤 핵심 내용을 노트로 정리해두면, 이후 질문의 맥락이 더 풍부해집니다. 12가지 실전 활용법 1. 맞춤형 AI 비서 (업무 매뉴얼 기반) 회사의 업무 매뉴얼, 사내 규정, 표준 운영 절차(SOP)를 소스로 올리면, 해당 조직 전용 AI 비서가 됩니다. 신입 사원이 \u0026ldquo;출장비 정산 절차가 어떻게 되나요?\u0026ldquo;라고 물으면, 사내 규정 문서를 기반으로 정확한 절차를 안내합니다.\n기존에는 이런 질문에 답하려면 선배에게 묻거나 인트라넷을 뒤져야 했습니다. NotebookLM으로 매뉴얼을 올려두면, 24시간 즉시 답변이 가능한 사내 도우미가 만들어집니다. 특히 반복적으로 동일한 질문을 받는 팀(HR, IT 헬프데스크)에서 효과가 큽니다.\n실전 팁으로, 매뉴얼 외에 과거 FAQ나 자주 묻는 질문 모음도 함께 소스로 넣으면, 매뉴얼에 명시되지 않은 엣지 케이스까지 커버할 수 있습니다.\n2. Deep Research 보고서 \u0026ldquo;2026년 한국 경제 산업 전망\u0026quot;처럼 복잡한 주제의 보고서를 작성할 때, Deep Research 기능으로 관련 소스를 자동 수집한 뒤 분석을 요청할 수 있습니다. 한국은행 보고서, 산업연구원 자료, 주요 증권사 리포트를 소스로 넣고 \u0026ldquo;핵심 리스크 요인 3가지를 비교 분석해줘\u0026quot;라고 요청하면, 각 소스의 관점을 인용과 함께 정리해줍니다.\n보고서 작성 시간이 수일에서 수 시간으로 단축됩니다. 중요한 것은 NotebookLM이 보고서를 \u0026ldquo;대신 써주는\u0026rdquo; 것이 아니라, 분석의 뼈대를 잡아준다는 점입니다. 최종 판단과 문맥은 여전히 사람의 몫입니다.\n3. 소스 신뢰성 교차 검증 하나의 주장에 대해 3~5개 소스를 넣고 \u0026ldquo;이 주장에 대한 각 소스의 입장을 비교해줘\u0026quot;라고 요청하면, 동의/반대/조건부 동의 등으로 분류해서 정리해줍니다. 예를 들어 \u0026ldquo;AI가 일자리를 줄일 것인가\u0026quot;라는 주제에 대해 맥킨지 보고서, OECD 리포트, 학술 논문을 넣으면 각각의 관점 차이를 한눈에 파악할 수 있습니다.\n팩트 체크나 리서치 초기 단계에서 특히 유용합니다. 모든 소스가 동일한 결론을 내리는지, 아니면 상충하는 부분이 있는지 빠르게 파악할 수 있어, 분석의 깊이가 달라집니다.\n4. 회의록/녹음 분석 회의 녹음 파일이나 자동 생성된 회의록을 소스로 올리면, 단순 요약을 넘어서 액션 아이템 추출, 결정 사항 정리, 미해결 이슈 목록까지 뽑아줍니다. \u0026ldquo;이번 회의에서 김 팀장이 맡기로 한 업무를 정리해줘\u0026quot;처럼 구체적인 질문도 가능합니다.\n주간 회의가 많은 팀에서는 매주 회의록을 누적해서 넣어두면, \u0026ldquo;지난 한 달간 결정된 사항 중 아직 완료되지 않은 것\u0026quot;을 추적하는 용도로도 쓸 수 있습니다. 회의 기록이 쌓일수록 노트북의 가치가 올라가는 구조입니다.\n5. 논문 리뷰 및 비교 분석 관련 논문 여러 편을 소스로 올리고 \u0026ldquo;각 논문의 연구 방법론과 결론을 비교해줘\u0026quot;라고 요청하면, 체계적인 비교표를 생성합니다. 대학원생이나 연구자에게 literature review 시간을 대폭 줄여줍니다.\n특히 유용한 기능은 인용 추적입니다. \u0026ldquo;논문 A의 핵심 주장을 뒷받침하는 근거가 다른 소스에서도 확인되나?\u0026ldquo;라고 물으면, 교차 검증 결과를 소스 번호와 함께 보여줍니다. 논문 하나를 읽는 것보다 여러 논문의 맥락 속에서 읽는 것이 이해도를 높여줍니다.\n6. 학습 가이드/퀴즈 자동 생성 교재나 강의 자료를 소스로 올리고 \u0026ldquo;이 내용을 기반으로 20문항 퀴즈를 만들어줘\u0026quot;라고 요청하면, 객관식/주관식/OX 문제를 자동 생성합니다. 각 문제에는 정답과 해설이 포함되며, 해설은 소스의 어느 부분에서 나왔는지 인용으로 표시됩니다.\n시험 준비뿐 아니라 팀 교육 자료 제작에도 활용됩니다. 신규 입사자 온보딩 자료를 소스로 넣고 이해도 확인 퀴즈를 만들면, 교육 담당자의 업무 부담을 크게 줄일 수 있습니다. 학습 가이드 기능은 \u0026ldquo;이 자료의 핵심 개념 10가지를 뽑아서 각각 한 문단으로 설명해줘\u0026quot;처럼 요약형으로도 활용 가능합니다.\n7. 오디오 오버뷰 (팟캐스트 형식 변환) NotebookLM의 시그니처 기능 중 하나입니다. 소스를 업로드하면 두 명의 AI 호스트가 팟캐스트 형식으로 대화하며 내용을 설명하는 오디오를 생성합니다. 복잡한 보고서도 출퇴근길에 귀로 들을 수 있는 콘텐츠로 변환됩니다.\n영어뿐 아니라 한국어로도 생성이 가능하며, 대화체로 풀어주기 때문에 딱딱한 보고서보다 이해하기 쉽습니다. 팀 전체가 읽어야 하는 긴 문서가 있을 때, 오디오 오버뷰를 생성해서 공유하면 실제 읽는 비율이 올라갑니다.\n8. 계약서/법률 문서 분석 계약서를 소스로 올리고 \u0026ldquo;갑에게 불리한 조항을 찾아줘\u0026rdquo;, \u0026ldquo;위약금 관련 조항을 정리해줘\u0026quot;라고 요청할 수 있습니다. NotebookLM은 소스 내에서만 답변하므로, 존재하지 않는 조항을 만들어내지 않습니다.\n비법률 전문가가 계약서를 검토할 때 1차 필터로 활용하기 좋습니다. 물론 최종 법률 검토는 전문가에게 맡겨야 하지만, \u0026ldquo;어디를 집중적으로 봐야 하는지\u0026rdquo; 파악하는 데 걸리는 시간을 절약합니다. 여러 계약서를 동시에 올려서 조건 비교도 가능합니다.\n9. 경쟁사 분석 매트릭스 경쟁사 IR 자료, 뉴스 기사, 산업 보고서를 소스로 넣고 \u0026ldquo;경쟁사 A, B, C의 매출, 주력 제품, 시장 점유율을 비교 매트릭스로 정리해줘\u0026quot;라고 요청하면 구조화된 비교표를 생성합니다.\n사업 기획이나 전략 회의 준비에 유용합니다. 특히 해외 경쟁사 자료를 영문 그대로 넣어도 한국어로 분석 결과를 받을 수 있어, 영문 보고서를 일일이 번역하지 않아도 됩니다. 분기마다 소스를 업데이트하면 경쟁 환경 변화를 추적하는 대시보드 역할도 합니다.\n10. 이력서/자기소개서 작성 채용 공고와 자신의 경력 기술서를 함께 소스로 올리면, \u0026ldquo;이 공고에 맞는 자기소개서 초안을 작성해줘\u0026quot;라고 요청할 수 있습니다. 소스 기반이므로 존재하지 않는 경력을 만들어내지 않고, 실제 경험을 공고의 요구사항에 맞게 재구성합니다.\n여러 채용 공고를 동시에 올려서 \u0026ldquo;A 회사와 B 회사 공고에서 공통으로 요구하는 역량\u0026quot;을 분석하는 것도 가능합니다. 커리어 전환을 준비할 때, 기존 경력과 새 분야의 접점을 찾는 데도 도움이 됩니다.\n11. 블로그/콘텐츠 기획 콘텐츠 제작자에게 NotebookLM은 리서치 어시스턴트 역할을 합니다. 참고할 자료, 경쟁 콘텐츠, 키워드 리서치 결과를 소스로 넣고 \u0026ldquo;이 주제로 블로그 글의 목차를 잡아줘\u0026quot;라고 요청하면, 소스에 기반한 구조화된 아웃라인을 받을 수 있습니다.\n핵심은 \u0026ldquo;내가 넣은 자료의 범위 안에서\u0026rdquo; 기획이 나온다는 점입니다. ChatGPT로 콘텐츠 기획을 하면 일반적인 내용이 나오지만, NotebookLM은 사용자가 수집한 특정 자료들을 기반으로 차별화된 관점을 제안합니다. SEO 분석 자료와 함께 넣으면 검색 의도에 맞는 콘텐츠 구조를 잡을 수도 있습니다.\n12. 프로젝트 문서화 프로젝트의 기획서, 회의록, 기술 문서, 이메일 스레드를 모아서 소스로 올리면, 프로젝트 전체 맥락을 이해하는 AI가 만들어집니다. \u0026ldquo;이 프로젝트의 주요 마일스톤과 현재 진행 상황을 정리해줘\u0026quot;라고 요청하면, 흩어져 있던 정보를 통합해서 보여줍니다.\n팀원 교체 시 인수인계 문서 생성, 프로젝트 회고 자료 정리, 스테이크홀더 보고용 요약 등 다양한 형태의 산출물을 만들 수 있습니다. 개발 팀에서는 PRD, 기술 스펙, API 문서를 넣어서 프로젝트 컨텍스트를 한 곳에 모아두는 용도로도 활용합니다.\n무료 vs Pro 비교 무료로도 충분한 이유 NotebookLM의 무료 플랜은 놀랍도록 관대합니다. 핵심 기능인 소스 기반 질의응답, 오디오 오버뷰, 노트 생성이 모두 무료로 제공됩니다. 소스 50개 한도도 하나의 프로젝트나 주제를 다루기에 충분한 양입니다. 개인 사용자나 소규모 팀이라면 무료 플랜만으로 위 12가지 활용법을 모두 실행할 수 있습니다.\nPro에서 추가되는 기능 Google One AI Premium 또는 Workspace 요금제에 포함되는 Pro 기능:\n항목 무료 Pro 노트북당 소스 수 50개 300개 오디오 오버뷰 기본 커스텀 지시 가능 Deep Research 제한적 확장 사용 응답 품질 Gemini 기본 Gemini 고급 모델 팀 공유 제한적 팀 협업 기능 실전 시나리오: 2026년 경제 산업 전망 보고서 만들기 영상에서 시연된 예시 흐름입니다:\nDeep Research로 \u0026ldquo;2026년 한국 경제 전망\u0026rdquo; 관련 소스 자동 수집 수집된 소스 중 신뢰도 높은 것만 선별 (한국은행, KDI, 주요 증권사) \u0026ldquo;핵심 경제 지표별 전망을 비교 분석해줘\u0026rdquo; 질의 산업별(반도체, 자동차, 바이오) 세부 분석 요청 오디오 오버뷰로 팟캐스트 형식 요약 생성 최종 보고서 초안 작성 요청 이 전체 과정이 2~3시간 안에 완료됩니다. 동일한 작업을 수동으로 하면 2~3일은 걸릴 분량입니다.\n개발자 관점에서의 NotebookLM RAG와의 비교: Chunking/Embedding 없이 동일 효과 개발자 입장에서 NotebookLM의 가치를 정확히 이해하려면, 직접 RAG 파이프라인을 구축해본 경험이 있으면 좋습니다. 일반적인 RAG 구현에는 다음 단계가 필요합니다:\n문서 로드 및 전처리 텍스트 chunking (overlap 포함) Embedding 모델로 벡터 변환 벡터 DB (Pinecone, Chroma 등) 저장 쿼리 시 similarity search 검색된 chunk + 원본 질문 → LLM 프롬프트 조합 답변 생성 및 후처리 NotebookLM은 이 7단계를 소스 업로드 → 질문 2단계로 압축합니다. 개발자가 chunking 전략을 고민할 필요도, embedding 모델을 선택할 필요도, 벡터 DB를 운영할 필요도 없습니다. Google이 내부적으로 최적화된 파이프라인을 돌려주기 때문입니다.\n비개발자에게 RAG를 민주화한 도구 NotebookLM의 진짜 혁신은 기술적 탁월함이 아니라 접근성입니다. 마케터, 기획자, 연구자 등 코드를 모르는 사람도 자신의 데이터로 RAG 수준의 AI를 만들 수 있게 되었습니다. 이전에는 \u0026ldquo;우리 회사 문서를 학습한 AI 챗봇\u0026quot;을 만들려면 개발팀에 요청해야 했지만, 이제 누구나 5분 안에 만들 수 있습니다.\n이것은 스프레드시트가 데이터 분석을 민주화한 것과 같은 맥락입니다. 전문 도구가 필요했던 작업을 누구나 할 수 있게 만드는 것, 그것이 NotebookLM이 AI 생태계에서 차지하는 위치입니다.\n프로젝트 문서 관리 도구로서의 가능성 개발 팀에서 NotebookLM을 프로젝트 문서 허브로 활용하는 시나리오도 흥미롭습니다. PRD, 기술 스펙, API 문서, 아키텍처 결정 기록(ADR)을 소스로 올려두면, 새로 합류한 팀원이 \u0026ldquo;이 프로젝트에서 Redis를 선택한 이유가 뭐야?\u0026ldquo;라고 물었을 때 관련 ADR을 인용하며 답변해줍니다.\n다만 한계도 있습니다. NotebookLM은 코드 자체를 소스로 넣기에는 적합하지 않고, 실시간 동기화도 되지 않습니다. 문서 기반 프로젝트 컨텍스트 관리 도구로서의 가능성은 크지만, Codebase 분석 도구(Cursor, Claude Code 등)와는 역할이 다릅니다.\n인사이트 NotebookLM을 사용하면서 느끼는 가장 큰 전환은 AI와의 상호작용 모델 자체가 바뀐다는 점입니다. 범용 AI에게 \u0026ldquo;잘 질문하는 법\u0026quot;을 연구하던 시대에서, **\u0026ldquo;좋은 데이터를 큐레이션하는 법\u0026rdquo;**이 핵심 역량이 되는 시대로 이동하고 있습니다.\n이 변화에는 중요한 함의가 있습니다. 프롬프트 엔지니어링은 진입 장벽이 높습니다. 좋은 프롬프트를 쓰려면 LLM의 작동 방식을 어느 정도 이해해야 하기 때문입니다. 반면 데이터 큐레이션은 도메인 전문가의 기존 역량과 직결됩니다. 회계사는 어떤 재무 문서가 중요한지 알고, 연구자는 어떤 논문이 핵심인지 압니다. NotebookLM은 이 도메인 지식을 AI 활용 역량으로 직접 전환해줍니다.\n개발자 관점에서 한 가지 더 주목할 점은, NotebookLM이 보여주는 것이 RAG의 최종 형태가 아니라 시작점이라는 것입니다. 현재는 소스를 수동으로 올려야 하지만, 향후 실시간 데이터 소스 연동, API 기반 자동 업데이트, 팀 단위 지식 그래프 구축 등으로 발전할 가능성이 큽니다. Google이 Gemini 생태계의 핵심 접점으로 NotebookLM을 포지셔닝하고 있다는 점에서, 이 도구의 진화를 계속 추적할 가치가 있습니다.\n출처: 직장인이라면 지금 당장 써야 할 무료 AI | 노트북LM 실전 활용법 12가지 (최신 가이드) — 오빠두엑셀\n","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-notebooklm-guide/cover.jpg","permalink":"/ko/posts/2026-04-01-notebooklm-guide/","title":"NotebookLM 실전 활용법 12가지 — 직장인을 위한 무료 AI 비서 완전 가이드"},{"content":"Stripe가 매주 1,300개 이상의 PR을 AI 코딩 에이전트로 작성하고 있다는 사실이 공개되었다. 사람은 코드를 한 줄도 작성하지 않고 리뷰만 담당한다. 동시에, Anthropic의 연구에서 영감을 받은 적대적 개발(Adversarial Development) 기법이 코딩 에이전트의 신뢰성을 극적으로 끌어올리고 있다. 이 글에서는 Stripe Minions의 내부 구조와 적대적 개발 아키텍처를 분석하고, 직접 구축하는 방법까지 다룬다.\nStripe Minions — 주당 1,300+ PR의 비밀 왜 Stripe인가 Stripe는 코딩 에이전트를 운영하기에 가장 까다로운 환경 중 하나다.\nRuby 백엔드 — LLM에게 익숙하지 않은 uncommon stack 방대한 자체 라이브러리 — 오픈소스가 아닌 homegrown 코드베이스 연간 $1T 이상의 결제 처리량 — 코드 한 줄의 오류가 치명적 이런 환경에서 AI가 작성한 PR이 매주 1,300개 이상 머지되고 있다는 것은, 워크플로우의 신뢰성이 그만큼 높다는 의미다. Stripe의 3,400명 이상 엔지니어가 주당 8,000개 PR을 올리는 것 중 일부지만, 그 비중은 빠르게 성장 중이다.\nStructured Workflow의 핵심 원리 Stripe Minions의 핵심은 에이전트가 시스템을 제어하는 것이 아니라, 시스템이 에이전트를 제어한다는 점이다.\n일반적인 AI 코딩 워크플로우에서는 에이전트가 계획, 구현, 검증을 모두 담당한다. 문제는 에이전트가 우리가 원하는 검증을 반드시 수행한다는 보장이 없다는 것이다. Stripe는 이를 해결하기 위해 deterministic node와 agent node를 조합한 blueprint 기반 워크플로우를 만들었다.\n\u0026ldquo;In our experience, writing code to deterministically accomplish small decisions we can anticipate — like we always want to lint changes at the end of a run — is far more reliable than asking an agent to do it.\u0026rdquo;\nflowchart TD A[\"Slack / CLI\u0026lt;br/\u0026gt;Entry Point\"] --\u003e B[\"Context Curation\u0026lt;br/\u0026gt;(Deterministic)\"] B --\u003e B1[\"Tool Shed에서\u0026lt;br/\u0026gt;MCP 도구 선별\"] B --\u003e B2[\"문서 검색 \u0026amp;\u0026lt;br/\u0026gt;컨텍스트 조합\"] B1 --\u003e C[\"Agent: 구현\u0026lt;br/\u0026gt;(Isolated Dev Box)\"] B2 --\u003e C C --\u003e D[\"Linting \u0026amp; Type Check\u0026lt;br/\u0026gt;(Deterministic)\"] D --\u003e|실패| E[\"Agent: 수정\"] E --\u003e D D --\u003e|통과| F[\"테스트 실행\u0026lt;br/\u0026gt;(Deterministic)\"] F --\u003e|실패, 최대 2회| G[\"Agent: 테스트 수정\"] G --\u003e F F --\u003e|통과| H[\"Human Review\u0026lt;br/\u0026gt;PR 제출\"] F --\u003e|2회 초과 실패| I[\"Engineer에게\u0026lt;br/\u0026gt;Escalation\"] style A fill:#4a90d9,color:#fff style B fill:#50c878,color:#fff style B1 fill:#50c878,color:#fff style B2 fill:#50c878,color:#fff style C fill:#f5a623,color:#fff style D fill:#50c878,color:#fff style E fill:#f5a623,color:#fff style F fill:#50c878,color:#fff style G fill:#f5a623,color:#fff style H fill:#4a90d9,color:#fff style I fill:#d94a4a,color:#fff녹색 = Deterministic Node, 주황 = Agent Node로, 에이전트는 워크플로우의 일부에서만 동작한다.\nContext Curation — 500개 MCP 도구에서 필요한 것만 Stripe는 내부 시스템과 SaaS 플랫폼을 연결하는 Tool Shed라는 단일 MCP 서버를 운영한다. 약 500개의 MCP 도구가 등록되어 있지만, 에이전트에게 전부 주면 오히려 혼란을 일으킨다.\n워크플로우의 첫 번째 deterministic node에서 요청을 분석한 뒤:\n관련 문서와 티켓을 검색해서 컨텍스트를 조합 필요한 MCP 도구의 subset만 선별하여 에이전트에게 전달 이 과정이 에이전트가 아닌 코드로 처리된다는 점이 핵심이다.\nIsolated Dev Box — Cattle, Not Pets 모든 Minion 실행은 격리된 AWS EC2 인스턴스에서 이루어진다. Stripe 코드베이스, lint 캐시 등이 미리 로드되어 빠르게 시작되며, 실행이 끝나면 바로 폐기된다.\nWork tree나 로컬 컨테이너 방식 대비 권한 관리와 확장성이 우수 한 엔지니어가 동시에 여러 Minion을 병렬 실행 가능 3백만 개 이상의 테스트 중 관련 subset만 선별하여 실행 테스트 실패 시 에이전트가 최대 2회 수정을 시도하고, 그래도 실패하면 사람에게 에스컬레이션한다. 무한 루프 방지가 설계에 내장되어 있다.\n다른 기업들의 움직임 Stripe만이 아니다. 주요 테크 기업들이 비슷한 structured workflow engine을 구축하고 있다.\n기업 도구 특징 Shopify Roast 오픈소스로 공개, structured AI workflow engine Airbnb 내부 도구 테스트 마이그레이션에 특화 AWS 내부 도구 블로그 포스트를 통해 일부 공개 공통점은 모두 에이전트에게 전체를 맡기지 않고, 결정론적 단계와 에이전트 단계를 명확히 분리한다는 것이다.\n적대적 개발(Adversarial Development) — 에이전트가 논쟁할 때 Sycophancy 문제 — 더 강해질수록 더 나빠진다 AI의 가장 큰 문제 중 하나는 **sycophancy(아첨)**다. LLM은 사용자의 의견에 동의하고, 자기 자신의 결과물도 과대평가하는 경향이 있다. 문제는 모델이 강력해질수록 이 현상이 더 심해진다는 점이다.\n코딩 에이전트에서 이것은 치명적이다:\n에이전트가 자신이 작성한 코드를 스스로 평가하면 → \u0026ldquo;학생이 자기 숙제를 채점하는 것\u0026rdquo; 몇 가지 사소한 문제만 지적하며 리뷰가 합격한 것처럼 보이게 함 진짜 심각한 문제는 은폐됨 해결책: 별도의 Sparring Partner GAN(Generative Adversarial Network)에서 영감을 받은 접근법이다. GAN에서 Generator가 이미지를 만들고 Discriminator가 진위를 판별하듯이, 코딩 에이전트도 **구현자(Implementer)**와 **평가자(Evaluator)**를 분리한다.\n핵심은 평가자가 완전히 별도의 컨텍스트 세션을 가진다는 것이다. 구현 과정에서 축적된 bias가 없기 때문에 진짜 객관적인 평가가 가능하다.\nflowchart TD UP[\"User Prompt\"] --\u003e PL[\"Planner Agent\u0026lt;br/\u0026gt;프롬프트 → 상세 스펙 생성\"] PL --\u003e NEG[\"Contract Negotiation\u0026lt;br/\u0026gt;Sprint 분할 \u0026amp; 평가 기준 합의\"] NEG --\u003e SP[\"Sprint Cycle 시작\"] subgraph SPRINT [\"Sprint N\"] direction TB GEN[\"Implementer Agent\u0026lt;br/\u0026gt;코드 구현\"] EVAL[\"Evaluator Agent\u0026lt;br/\u0026gt;독립 컨텍스트에서 평가\"] GEN --\u003e EVAL EVAL --\u003e|\"점수 \u0026lt; threshold\u0026lt;br/\u0026gt;(최대 3회 재시도)\"| GEN end SP --\u003e SPRINT EVAL --\u003e|\"모든 기준 통과\"| NEXT[\"다음 Sprint 또는 완료\"] NEXT --\u003e|\"남은 Sprint 있음\"| SP style UP fill:#4a90d9,color:#fff style PL fill:#9b59b6,color:#fff style NEG fill:#50c878,color:#fff style GEN fill:#f5a623,color:#fff style EVAL fill:#d94a4a,color:#fff style NEXT fill:#4a90d9,color:#fff아키텍처 상세 1단계: Planner Agent\n사용자의 간단한 프롬프트를 받아 상세한 Product Specification으로 확장 기술 스택, 기능 요구사항, 구조까지 정의 2단계: Contract Negotiation\nImplementer와 Evaluator가 사전에 합의 스펙을 여러 Sprint로 분할 각 Sprint별 평가 기준(criteria)과 threshold(1~10점) 설정 \u0026ldquo;적대적이지만 공정한\u0026rdquo; 규칙을 먼저 정함 3단계: Sprint Cycle\nImplementer: 합의된 Sprint의 기능을 구현 Evaluator: 독립된 컨텍스트에서 각 criteria를 1~10점으로 채점 Threshold 미달 시 Implementer에게 피드백과 함께 재시도 요청 (최대 3회) 모든 criteria 통과 시 다음 Sprint로 진행 Cross-Model 평가도 가능 흥미로운 점은 Implementer와 Evaluator에 서로 다른 모델을 사용할 수 있다는 것이다.\nClaude가 구현 → Codex가 평가 Codex가 구현 → Claude가 평가 서로 다른 모델의 bias가 다르기 때문에, cross-evaluation은 단일 모델의 sycophancy 문제를 더 효과적으로 해소할 수 있다. 이 접근법은 Anthropic의 multi-agent evaluation 연구에서 직접적으로 영감을 받은 것이다.\n직접 Structured Workflow 구축하기 Stripe 규모가 아니더라도 핵심 원리는 동일하게 적용할 수 있다.\n설계 원칙 예측 가능한 작업은 deterministic하게 — linting, type checking, 테스트 실행은 코드로 강제 에이전트는 창의적 작업에만 — 구현, 버그 수정 등 판단이 필요한 부분 재시도 횟수 제한 — 무한 루프 방지를 위해 최대 재시도 횟수를 설정하고 초과 시 에스컬레이션 컨텍스트를 사전에 큐레이션 — 에이전트에게 모든 도구를 주지 말고, 작업에 필요한 subset만 전달 격리된 실행 환경 — 프로덕션 코드에 영향을 주지 않는 sandbox에서 실행 적대적 개발 도입 시 고려사항 장점 비용 단일 에이전트 대비 훨씬 높은 신뢰성 토큰 사용량 증가 (2~3배) Sycophancy 문제 해소 실행 시간 증가 더 저렴한 모델로도 좋은 결과 가능 초기 harness 구축 비용 사람의 리뷰 부담 감소 Contract negotiation 오버헤드 핵심은 신뢰성과 비용의 트레이드오프다. Stripe처럼 높은 안정성이 필요한 환경에서는 이 오버헤드가 충분히 정당화된다. PoC나 프로토타입 수준에서도 적대적 개발을 적용하면 단일 에이전트 대비 완성도가 크게 올라간다.\n인사이트 \u0026ldquo;System controls the agent\u0026rdquo; 패러다임 전환 — 에이전트에게 전부 맡기는 시대는 끝나가고 있다. Stripe, Shopify, Airbnb, AWS 모두 에이전트를 워크플로우의 일부로 삽입하는 방식을 채택했다. 에이전트의 자유도를 줄이는 것이 오히려 신뢰성을 높이는 역설이다.\nSycophancy는 기술적으로 해결해야 할 문제 — 더 강한 모델이 나와도 sycophancy가 줄어들지 않는다면, 아키텍처 수준에서 해결해야 한다. 적대적 개발은 단순한 트릭이 아니라, GAN에서 검증된 원리를 코딩 에이전트에 적용한 것이다.\nContext curation이 곧 경쟁력 — Stripe의 500개 MCP 도구 중 필요한 것만 선별하는 과정, 3백만 테스트 중 관련 subset만 실행하는 과정 — 이 \u0026ldquo;선별\u0026quot;의 정확도가 워크플로우 전체의 성능을 결정한다.\nCross-model evaluation의 가능성 — Claude + Codex처럼 서로 다른 모델을 조합하면 단일 모델의 blind spot을 보완할 수 있다. 앞으로 모델 선택은 \u0026ldquo;어떤 모델이 최고인가\u0026quot;가 아니라 \u0026ldquo;어떤 조합이 최적인가\u0026quot;의 문제가 될 것이다.\n참고 영상: Stripe\u0026rsquo;s Coding Agents Ship 1,300 PRs EVERY Week / Coding Agent Reliability EXPLODES When They Argue — Cole Medin\n","date":"2026-04-01T00:00:00+09:00","image":"/images/posts/2026-04-01-stripe-coding-agents/cover.jpg","permalink":"/ko/posts/2026-04-01-stripe-coding-agents/","title":"Stripe 1,300 PR/주의 비밀 — 코딩 에이전트 실전 운영과 적대적 개발"},{"content":"개요 YouTube 영상 27 Claude Code Tips That Make You 10x Faster를 분석했다. 500시간 이상 Claude Code를 사용한 경험에서 나온 27가지 팁을 초급/중급/고급으로 재분류하고, 실전 적용 관점에서 정리한다. 이전 시리즈와 이어진다:\nClaude Code 실전 가이드 1 — 컨텍스트 관리부터 워크플로우까지 Claude Code 실전 가이드 2 — 최근 2개월 신기능 graph TD A[\"Claude Code 3계층 구조\"] --\u003e B[\"CLAUDE.md\u0026lt;br/\u0026gt;행동 규칙\u0026lt;br/\u0026gt;매 메시지마다 자동 로드\"] A --\u003e C[\"Skills/Workflows\u0026lt;br/\u0026gt;반복 태스크 자동화\u0026lt;br/\u0026gt;온디맨드 호출\"] A --\u003e D[\"Reference Files\u0026lt;br/\u0026gt;재사용 템플릿\u0026lt;br/\u0026gt;모든 스킬에서 참조\"] B --\u003e E[\"방향 챌린지\"] B --\u003e F[\"품질 게이트\"] B --\u003e G[\"테스트 먼저\"] B --\u003e H[\"컨텍스트 절약\"] C --\u003e I[\"이메일 답장\"] C --\u003e J[\"LinkedIn 포스트\"] C --\u003e K[\"제안서 작성\"] I --\u003e D J --\u003e D K --\u003e D 초급: 시작하기 환경 설정 VS Code 또는 Antigravity에 통합 — Claude Code를 단독으로 쓰는 것보다 IDE에 통합하면 코드 에디터와 AI 대화가 같은 화면에 있어 컨텍스트 전환 비용이 줄어든다. 플러그인 마켓에서 설치 한 번이면 된다.\n자동 저장 설정 — 이건 정말 중요하다. VS Code의 autosave를 켜지 않으면 Claude가 수정한 파일이 저장되지 않아 시간을 낭비하게 된다. Config에서 autosave 검색 후 체크.\n딕테이션 활용 — Mac에서 Fn 키 두 번으로 음성 입력 가능. 타이핑보다 빠르게 프롬프트를 입력할 수 있다.\n방향 설정 Claude Code를 처음 쓸 때 가장 어려운 건 \u0026ldquo;뭘 물어봐야 하는지 모르는 것\u0026quot;이다. 영상에서 제안하는 접근:\n\u0026ldquo;I\u0026rsquo;m building a website from scratch. What questions should I be asking you?\u0026rdquo;\n이렇게 하면 Claude가 \u0026ldquo;웹사이트의 목적은?\u0026rdquo;, \u0026ldquo;성공 기준은?\u0026rdquo;, \u0026ldquo;타겟 사용자는?\u0026rdquo; 같은 질문을 역으로 던져주고, 이 대화 체인을 따라가면 자연스럽게 요구사항이 정리된다.\n중급: 생산성 극대화 멀티탭 병렬 작업 영상 제작자가 \u0026ldquo;너무 늦게 발견해서 부끄럽다\u0026quot;고 한 팁이다. 여러 탭을 열어 동시에 다른 태스크를 실행할 수 있다. 스플릿 스크린으로 두 프로젝트를 나란히 놓고 병렬 작업이 가능하다. 수평으로도 분할할 수 있어 다수의 대화를 동시에 모니터링할 수 있다.\n주의점: 20분 후 돌아왔더니 권한 승인을 기다리며 멈춰 있는 상황을 방지하려면, bypass permissions 모드를 활성화해야 한다. 설정에서 bypass permissions 검색 후 토글.\nCLAUDE.md — 두 개의 필수 파일 모든 프로젝트에 반드시 있어야 할 파일:\nCLAUDE.md — Claude가 어떻게 행동해야 하는지. \u0026ldquo;직원을 고용하고 교육하는 것\u0026quot;과 같다 project_specs — 무엇을 만들고 있는지. \u0026ldquo;직원에게 회사가 뭘 하는지 알려주는 것\u0026quot;과 같다 둘 다 살아있는 문서(living document)로, 프로젝트가 진화하면서 함께 업데이트되어야 한다.\nCLAUDE.md에 넣어야 할 5가지 규칙 규칙 목적 Challenge my direction yes-man 방지, 최선의 결과 도출 Quality gate 품질 점수를 솔직하게 (3/10 → 9/10 개선 방법) Test before delivery 깨진 결과물을 사람이 디버깅하지 않도록 Context awareness 컨텍스트 윈도우 절약, 불필요한 토큰 사용 방지 Upgrade suggestion 매 응답마다 개선 제안, 사각지대 발견 응답 구조화 복잡한 프로젝트에서 Claude의 응답이 구조화되지 않으면 압도적이다. 영상에서 제안하는 5단계 응답 형식:\n무엇을 했는지 — 작업 요약 나한테 필요한 것 — 내가 해야 할 액션 왜 중요한지 — 15세에게 설명하듯 다음 단계 — 진행 방향 에러와 컨텍스트 — 발생한 문제와 이해에 필요한 정보 메시지 큐잉 이전 메시지가 끝나기를 기다리지 않아도 된다. 여러 메시지를 연속으로 보내면 큐에 쌓여서 순서대로 처리된다.\n고급: 시스템 설계 3계층 아키텍처 영상에서 제안하는 Claude Code 프로젝트의 3계층:\nCLAUDE.md — 행동 규칙. 매 메시지마다 자동으로 읽힘 Skills/Workflows — 반복 태스크 자동화. 온디맨드로 호출 (/skill-name) Reference Files — 재사용 템플릿. 모든 스킬에서 참조 예: 이메일 답장, LinkedIn 포스트, 제안서 작성 세 스킬이 모두 \u0026ldquo;나의 어조(tone)\u0026rdquo; 레퍼런스 파일을 참조하면, 어조를 한 번 수정하면 세 스킬 모두에 반영된다. 한 번 설정하고 영원히 재사용하며 계속 개선하는 구조다.\n서브에이전트 활용 5페이지 웹사이트를 순차적으로 만들면 느리다. 서브에이전트를 사용하면 각 페이지를 병렬로 생성한다:\n홈페이지 → 서브에이전트 1 About 페이지 → 서브에이전트 2 Contact 페이지 → 서브에이전트 3 각 에이전트가 하나에 특화되어 컨텍스트가 분리되므로, 더 빠르고 더 좋은 결과를 낸다.\n디자인 팁 Dribbble 클론 — Dribbble에서 영감을 얻고, 스크린샷을 Claude Code에 첨부하면 픽셀 단위로 복제 가능. URL을 첨부해도 사이트를 분석하고 복제한다.\nSpline 3D — 무료 3D 그래픽을 웹사이트에 추가. 커서를 따라다니는 큐브, 공 등의 인터랙티브 요소로 $10,000짜리 사이트처럼 보이게 만든다.\n기타 고급 팁 Escape + Rewind — 작업이 잘못된 방향으로 갈 때 Escape로 중단, Rewind 버튼으로 이전 단계로 복원 Compacting — 컨텍스트 83% 이상 사용 시 수동으로 compact하고, 잊으면 안 되는 핵심 정보를 리마인더로 추가 Memory — 프로젝트 간 지속되는 비밀 메모리 파일. /memory로 관리. 이름, 선호도 등을 기억 Insights — insights 입력으로 전체 사용 통계와 피드백 리포트 확인 Plugins — /plugin으로 프리빌트 솔루션 다운로드 (예: frontend-design) 빠른 링크 무료 CLAUDE.md 템플릿 — 영상 설명에 링크 Dribbble — 디자인 영감 Spline — 무료 3D 그래픽 인사이트 27가지 팁을 관통하는 핵심은 \u0026ldquo;Claude Code는 도구가 아니라 시스템\u0026quot;이라는 관점이다. CLAUDE.md로 행동을 정의하고, Skills로 워크플로우를 자동화하고, Reference Files로 일관성을 유지하는 3계층 구조는 단순한 팁 모음을 넘어 설계 패턴이다. 이전 실전 가이드 1, 2와 합치면 컨텍스트 관리(#1) → 신기능 활용(#2) → 시스템 설계(#3)로 자연스럽게 이어지는 시리즈가 된다. 특히 서브에이전트와 3계층 아키텍처는 현재 HarnessKit과 log-blog 프로젝트에서 이미 활용하고 있는 패턴이기도 하다.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-claude-code-27-tips/cover.jpg","permalink":"/ko/posts/2026-03-30-claude-code-27-tips/","title":"Claude Code 실전 가이드 3 — 500시간 사용자의 27가지 팁"},{"content":"개요 Claude Code의 자동화 기능을 다루는 세 편의 YouTube 영상을 분석했다. 스킬 시스템의 제작~배포, n8n 대체론과 스케줄링 3가지 방식, 그리고 Dispatch를 통한 원격 제어까지 — 이 세 축이 Claude Code를 코딩 도구에서 워크플로우 자동화 플랫폼으로 확장시키고 있다. 관련 포스트: Claude Computer Use, HarnessKit 개발기\ngraph TD A[\"Claude Code 자동화\"] --\u003e B[\"스킬 시스템\"] A --\u003e C[\"스케줄링\"] A --\u003e D[\"디스패치\"] B --\u003e E[\"제작\u0026lt;br/\u0026gt;slash command 정의\"] B --\u003e F[\"배포\u0026lt;br/\u0026gt;마켓플레이스\"] C --\u003e G[\"Cron 기반\u0026lt;br/\u0026gt;반복 실행\"] C --\u003e H[\"이벤트 트리거\u0026lt;br/\u0026gt;Hooks\"] C --\u003e I[\"원격 에이전트\u0026lt;br/\u0026gt;Remote Triggers\"] D --\u003e J[\"모바일 → PC\u0026lt;br/\u0026gt;원격 세션 제어\"] 스킬 시스템 — 반복을 캡슐화 자동화 대세 클로드 스킬! 제작부터 배포까지 영상에서는 스킬의 전체 라이프사이클을 다룬다.\n스킬이란 스킬은 반복적인 워크플로우를 markdown 파일로 캡슐화한 것이다. 슬래시 커맨드(/skill-name)로 호출하면 Claude가 정의된 절차를 따라 작업을 수행한다. CLAUDE.md가 \u0026ldquo;항상 적용되는 규칙\u0026quot;이라면, 스킬은 \u0026ldquo;필요할 때만 호출하는 전문 작업자\u0026quot;다.\n제작 과정 스킬 파일은 frontmatter + 프롬프트 구조다:\n--- name: email-reply description: 수신 이메일에 대한 답장 초안 작성 --- 1. 이메일 내용을 분석하라 2. reference/tone.md의 어조를 참조하라 3. 핵심 포인트별로 답변을 구성하라 4. 공손하지만 명확한 어조로 작성하라 한 번 만들면 무한 재사용이 가능하고, 100번째 실행이 첫 번째보다 좋아지도록 계속 개선할 수 있다. 매번 새 채팅에서 컨텍스트를 처음부터 설명하는 것과 비교하면 엄청난 효율 차이다.\n마켓플레이스 배포 스킬은 개인용을 넘어 마켓플레이스에 배포할 수 있다. 현재 HarnessKit과 log-blog도 이 경로로 마켓플레이스에 등록되어 있다. 플러그인 형태로 패키징하면 다른 사용자도 설치 후 바로 사용 가능하다.\n스케줄링 — n8n이 사라지는 이유 n8n 써야 할 이유가 점점 사라집니다 영상에서는 Claude Code의 스케줄링 기능 3가지를 소개하며 n8n 같은 자동화 도구와 비교한다.\n방법 1: Cron 기반 반복 실행 /schedule 또는 /loop 커맨드로 cron 표현식 기반의 반복 실행을 설정할 수 있다. 예를 들어 \u0026ldquo;매 30분마다 서버 로그를 확인하고 에러를 분류하라\u0026quot;를 cron으로 등록하면 Claude가 주기적으로 작업을 수행한다.\n방법 2: 이벤트 트리거 (Hooks) 특정 이벤트가 발생했을 때 자동으로 스킬이나 작업을 실행한다. 파일 변경, git commit, 도구 호출 등을 트리거로 사용할 수 있다. settings.json에서 hook을 정의하면 된다.\n방법 3: 원격 에이전트 (Remote Triggers) 서버에서 실행되는 Claude Code 세션을 원격으로 트리거한다. API 호출이나 웹훅으로 작업을 시작할 수 있어, CI/CD 파이프라인이나 외부 서비스와의 연동이 가능하다.\nn8n과의 비교 구분 n8n Claude Code 스케줄링 설정 GUI 노드 에디터 자연어 + cron 로직 노드 간 연결 AI가 판단 유연성 사전 정의된 노드 자유 형식 에러 처리 조건 분기 AI 자체 판단 비용 self-host 무료 API 비용 완전한 대체라기보다, 개발자 워크플로우 자동화 영역에서 겹치는 부분이 상당하다. n8n은 정형화된 통합에 강하고, Claude Code는 비정형 판단이 필요한 자동화에 강하다.\n디스패치 — 모바일에서 PC 원격 제어 폰 하나로 PC 원격 제어하는 클로드 역대급 신기능 영상에서는 Claude Dispatch를 소개한다.\nDispatch는 모바일 기기에서 PC의 Claude Code 세션을 원격으로 트리거하고 결과를 확인할 수 있는 기능이다. 출퇴근 중이나 외출 중에도 개발 환경의 에이전트에게 작업을 지시하고 모니터링할 수 있다.\n이전에 다뤘던 Claude Computer Use와 결합하면, 물리적으로 PC 앞에 없어도 Claude가 마우스와 키보드를 제어하며 작업을 수행하는 완전 자동화가 가능해진다.\n세 기능의 시너지 스킬 (무엇을) + 스케줄 (언제) + 디스패치 (어디서든) = 완전 자동화 워크플로우 실제 예시:\n스킬: \u0026ldquo;서버 로그 분석 후 에러 보고서 생성\u0026rdquo; 정의 스케줄: 매 1시간마다 cron 실행 디스패치: 에러 발견 시 모바일로 알림, 추가 지시 가능 현재 trading-agent 프로젝트에서 이 패턴을 활용 중이다 — ScheduleManager로 cron을 편집하고, MCP를 통해 에이전트에게 분석 작업을 위임하는 구조다.\n인사이트 세 편의 영상을 관통하는 키워드는 \u0026ldquo;탈중앙화된 자동화\u0026quot;다. n8n이나 Zapier 같은 중앙 집중형 자동화 플랫폼이 정형화된 트리거-액션 파이프라인을 제공한다면, Claude Code의 자동화는 AI가 판단을 내리는 비정형 자동화를 지원한다. 스킬로 작업을 정의하고, 스케줄로 타이밍을 관리하고, 디스패치로 장소 제약을 없앤다. 이 세 축이 합쳐지면 \u0026ldquo;사람이 없어도 돌아가는 개발 환경\u0026quot;에 한 발 더 가까워진다.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-claude-code-automation/cover.jpg","permalink":"/ko/posts/2026-03-30-claude-code-automation/","title":"Claude Code 자동화 삼총사 — 스킬, 스케줄, 디스패치"},{"content":"개요 이전 글: #5 — Inpaint UX 개선, Dev 서버 배포, 안정성 강화\n이번 #6에서는 31개 커밋에 걸쳐 세 가지 핵심 작업을 진행했다. 첫째, 로컬 파일 시스템 기반 이미지 저장을 AWS S3로 전면 마이그레이션했다. 둘째, \u0026ldquo;Diffs Image Agent\u0026quot;로 브랜딩을 적용하고 파비콘을 교체했다. 셋째, UI 안정성과 사용성을 개선하는 다수의 수정을 적용했다.\ngraph LR A[\"기존: 로컬 파일시스템\u0026lt;br/\u0026gt;EC2 디스크 직접 저장\"] --\u003e B[\"신규: AWS S3\u0026lt;br/\u0026gt;diffs-studio-hybrid-search-images\"] B --\u003e C[\"업로드 이미지\u0026lt;br/\u0026gt;uploads/\"] B --\u003e D[\"생성 이미지\u0026lt;br/\u0026gt;generated/\"] B --\u003e E[\"썸네일\u0026lt;br/\u0026gt;thumbnails/\"] F[\"Terraform\u0026lt;br/\u0026gt;IaC\"] --\u003e G[\"S3 버킷\"] F --\u003e H[\"IAM Role\u0026lt;br/\u0026gt;Instance Profile\"] F --\u003e I[\"버킷 정책\u0026lt;br/\u0026gt;CIDR notation\"] S3 이미지 스토리지 마이그레이션 배경 기존에는 EC2 인스턴스의 로컬 디스크에 이미지를 직접 저장하고 있었다. 이 구조는 스토리지 용량 한계, 인스턴스 교체 시 데이터 유실 위험, 로컬과 서버 간 환경 불일치 등의 문제가 있었다. S3로 마이그레이션하면 스토리지 걱정 없이 이미지를 관리할 수 있고, 로컬 개발과 프로덕션 환경에서 동일한 스토리지 레이어를 사용할 수 있다.\n구현 마이그레이션은 설계 문서 작성부터 시작하여 체계적으로 진행했다. 먼저 S3 마이그레이션 설계 스펙과 구현 계획을 문서화한 후, 인프라부터 애플리케이션까지 순차적으로 작업했다.\n인프라 레이어 (Terraform):\ndiffs-studio-hybrid-search-images S3 버킷 생성 IAM Role과 Instance Profile 설정으로 EC2에서 버킷 접근 버킷 정책에 EIP CIDR notation 적용 백엔드 레이어:\nS3 config와 boto3 의존성 추가 S3 스토리지 래퍼 모듈 구현 — 앱 lifespan에서 초기화 로컬 파일 URL/경로 헬퍼를 S3 기반으로 전면 교체 /images/ 경로를 S3로 리다이렉트, 업로드도 S3로 전환 생성 이미지와 썸네일을 S3에 직접 저장 레퍼런스 이미지, 인페인트/편집용 소스 이미지 모두 S3에서 로드 썸네일 백필 스크립트를 S3 기반으로 재작성 presigned URL 활용:\n탭 visibility 변경 시 presigned URL을 자동 갱신하는 기능 추가 — S3 presigned URL의 만료 시간 이슈를 우아하게 해결 문제 해결 Terraform 버킷 정책에서 EIP의 CIDR notation 이슈가 있었다. 단일 IP를 /32로 지정해야 하는데 누락되어 정책이 제대로 적용되지 않았다. 코드 리뷰에서 발견하여 CIDR notation, ref key cache, ContentType, Gemini API 관련 이슈들을 일괄 수정했다.\nDiffs 브랜딩 적용 로그인 및 헤더 로그인 페이지와 헤더에 Diffs 로고를 적용하여 기존 무미건조한 기본 UI에서 브랜드 아이덴티티를 부여했다.\n브라우저 타이틀과 파비콘 브라우저 탭 타이틀을 \u0026ldquo;Diffs Image Agent\u0026quot;로 변경하고, 기존 generic 파비콘을 \u0026ldquo;D.\u0026rdquo; 아이콘으로 교체했다. 파비콘은 favicon.io를 사용해 PNG에서 ICO로 변환했다.\nUI 안정성 및 사용성 개선 여러 세션에 걸쳐 다양한 UI 이슈를 수정했다:\n카드 액션 버튼: 밝은 이미지 위에서 버튼이 보이지 않는 문제 — 배경을 어둡게 조정 무한 스크롤: 빈 상태에서 무한 스크롤 로딩이 페이지 바운스를 일으키는 버그 수정 레퍼런스 이미지 순서: 사용자가 올린 레퍼런스가 시스템 주입 이미지보다 앞에 오도록 정렬 업로드 이미지 표시: 검색 팝업과 수직 브라우즈 그리드에서 업로드 이미지를 카드로 표시 타입 라벨: \u0026lsquo;베이스 재생성\u0026rsquo;으로 라벨을 변경하여 버튼과의 혼동 방지 베이스 이미지 인디케이터: 보라색에서 회색으로 중립적 색상 전환 IMAGE_SAFETY 에러: 프론트엔드에 구체적인 사유를 표시하도록 개선 (기존 generic 500 에러) 카드/디테일 UI: 중립적이고 미니멀한 스타일로 통일 DB 마이그레이션과 사용자 데이터 EC2 서버에서 Alembic 마이그레이션 동기화 작업을 진행했다. 서버 풀링 전에 마이그레이션 버전을 확인하고, 로컬과 서버 간 마이그레이션 버전을 동기화했다. 또한 기존에 user_id 없이 생성된 이미지들을 특정 사용자에게 재할당하는 작업도 수행했다.\nGemini 라벨링 파이프라인 이미지 레퍼런스에 대한 라벨링 작업을 진행했다. Gemini API를 사용한 라벨링 파이프라인의 상태를 확인하고, 30분 간격으로 진행률을 모니터링했다. 새 이미지 라벨을 추가하는 작업도 포함되었다.\n커밋 로그 메시지 변경 fix: terraform bucket policy CIDR notation for EIPs infra add new image label data chore: add APP_ENVIRONMENT to ecosystem config and .env config fix: address code review issues — CIDR, ref key cache, ContentType, Gemini multi feat: refresh presigned image URLs on tab visibility change frontend feat: rewrite thumbnail backfill script to use S3 backend feat: add S3 image source support to labeling pipeline backend feat: load source images from S3 for inpaint/edit backend feat: load reference images from S3 for generation backend feat: write generated images and thumbnails to S3 backend feat: redirect /images/ to S3, upload to S3 backend feat: replace local file URL/path helpers with S3-based versions backend feat: initialize S3 storage in app lifespan, remove local dir constants backend feat: add S3 storage wrapper module backend feat: add S3 config and boto3 dependency backend infra: add S3 bucket, IAM role, and instance profile for image storage infra docs: add S3 image migration implementation plan docs docs: add S3 image migration design spec docs feat: replace generic favicon with branded Diffs \u0026ldquo;D.\u0026rdquo; icon frontend feat: update browser tab title to \u0026ldquo;Diffs Image Agent\u0026rdquo; frontend fix: darken card action button backgrounds for visibility frontend fix: prevent infinite scroll loading on empty state frontend refactor: reorder reference images so user refs come before system-injected backend feat: rebrand login page and header with Diffs logo frontend fix: hide info button and scroll arrows on uploaded image cards frontend feat: show uploaded images as cards in search popup + vertical browse grid frontend fix: rename type label to \u0026lsquo;베이스 재생성\u0026rsquo; frontend refactor: neutralize base image indicator colors from purple to gray frontend fix: surface IMAGE_SAFETY reason to frontend instead of generic 500 full-stack refactor: unify card and detail UI to neutral, minimal style frontend 인사이트 이번 개발 사이클의 핵심은 S3 마이그레이션이다. 설계 문서 → Terraform 인프라 → 백엔드 래퍼 → API 엔드포인트 → 프론트엔드 URL 갱신까지 전 레이어를 체계적으로 전환한 점이 잘 진행되었다. presigned URL 만료 문제를 탭 visibility 이벤트로 해결한 것은 사용자 경험 관점에서 깔끔한 접근이었다. 브랜딩 작업은 단순해 보이지만, 파비콘과 타이틀 하나만 바꿔도 앱의 완성도 인상이 크게 달라진다. 31개 커밋 중 절반 이상이 S3 관련인 것을 보면, 스토리지 레이어 교체가 생각보다 많은 접점을 가지고 있음을 실감했다.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-hybrid-search-dev6/cover.jpg","permalink":"/ko/posts/2026-03-30-hybrid-search-dev6/","title":"Hybrid Image Search 개발기 #6 — S3 이미지 스토리지 마이그레이션과 브랜딩"},{"content":"개요 YouTube 영상 LiteParse - The Local Document Parser를 분석했다. LiteParse 자체도 흥미로운 도구이지만, 더 중요한 것은 RAG 프레임워크의 선두 주자였던 LlamaIndex가 **\u0026ldquo;프레임워크 시대는 끝났다\u0026rdquo;**고 선언하며 단일 도구로 방향을 전환한 배경이다. 관련 포스트: Context7 deep dive\ngraph TD A[\"LlamaIndex 진화\"] --\u003e B[\"2022.11\u0026lt;br/\u0026gt;RAG 프레임워크 탄생\u0026lt;br/\u0026gt;Jerry Liu\"] B --\u003e C[\"2023-2024\u0026lt;br/\u0026gt;프레임워크 전성기\u0026lt;br/\u0026gt;인덱싱+검색+생성 통합\"] C --\u003e D[\"문제 발생\u0026lt;br/\u0026gt;추상화 과잉\u0026lt;br/\u0026gt;문서 지연\u0026lt;br/\u0026gt;디버깅 불가\"] D --\u003e E[\"2025\u0026lt;br/\u0026gt;전략 전환 선언\u0026lt;br/\u0026gt;프레임워크 → 도구\"] E --\u003e F[\"LiteParse\u0026lt;br/\u0026gt;문서 파싱 하나에 집중\u0026lt;br/\u0026gt;로컬 실행\"] LlamaIndex의 역사와 전환 배경 RAG 프레임워크의 선구자 Jerry Liu가 2022년 11월에 만든 LlamaIndex는 최초의 본격적인 RAG 프레임워크였다. 문서 인덱싱, 벡터 검색, 답변 생성을 하나의 프레임워크 안에서 추상화하여, RAG 파이프라인을 빠르게 구축할 수 있게 했다. 당시 RAG가 LLM 활용의 핵심 패턴으로 떠오르면서 LlamaIndex는 이 분야의 대표 프레임워크가 되었다.\n프레임워크 시대의 근본적 문제 영상에서 지적하는 프레임워크 시대의 문제들:\n추상화 레이어의 빠른 변화 — AI 모델과 기술이 매달 바뀌는데, 프레임워크의 추상화는 이 속도를 따라가지 못한다. 문서는 항상 뒤처지고, 6개월 전 튜토리얼이 이미 동작하지 않는다.\n디버깅의 어려움 — 프레임워크 내부에 숨겨진 복잡성 때문에, 무언가 잘못되었을 때 원인을 찾기 어렵다. \u0026ldquo;인덱스 → 검색 → 생성\u0026rdquo; 파이프라인 중 어디서 문제가 생겼는지 추상화 뒤에 가려져 있다.\n추상화가 오히려 제약 — AI 모델 자체가 빠르게 발전하면서, 프레임워크가 정해놓은 방식이 최선이 아닌 경우가 늘어난다. 프레임워크를 우회하는 코드가 늘어나면 프레임워크의 존재 의미가 희석된다.\nLlamaIndex 팀 스스로가 이 문제를 인정하고 방향을 전환했다는 점이 핵심이다. 자신들이 만든 프레임워크 시대의 한계를 자신들이 선언한 것이다.\nLiteParse — 하나의 문제를 잘 해결하는 도구 해결하는 문제 코딩 에이전트는 Python 수천 줄을 거뜬히 쓰지만, PDF나 문서를 주면 유용한 맥락이 사라진다:\n테이블이 평탄화됨 — 행/열 구조 정보가 손실되어 데이터 의미가 왜곡 차트가 사라짐 — 시각적 데이터가 완전히 무시 숫자가 환각함 — OCR 오류로 잘못된 수치가 전달 PyPDF 등의 우회 방법이 불안정 — janky workaround로 기본 텍스트만 추출 기존에는 이런 문제를 해결하려면 별도 OCR 모델을 붙이거나, 여러 라이브러리를 조합하는 복잡한 파이프라인을 구축해야 했다.\nLiteParse의 접근 LiteParse는 로컬에서 실행되는 문서 파서로, 단 하나의 일을 한다 — PDF, DOCX 등의 문서에서 테이블 구조, 차트, 코드 블록을 정확하게 추출하는 것.\n핵심 특성:\n로컬 실행 — 외부 API 의존 없음, 프라이버시 보장 구조 보존 — 테이블의 행/열, 차트의 데이터 포인트를 유지 단일 목적 — RAG 파이프라인의 일부가 아닌, 독립 도구 아무 파이프라인에 연결 가능 — LlamaIndex에 종속되지 않음 프레임워크 vs 도구 — 패러다임 비교 구분 프레임워크 (LlamaIndex RAG) 도구 (LiteParse) 범위 전체 RAG 파이프라인 문서 파싱만 추상화 높음 (인덱스, 검색, 생성) 낮음 (입력 → 파싱 결과) 유연성 프레임워크 방식에 종속 아무 파이프라인에 연결 가능 디버깅 추상화 뒤에 숨겨짐 입출력이 명확 유지보수 빈번한 breaking changes 안정적 인터페이스 학습 곡선 프레임워크 전체 이해 필요 해당 기능만 이해 AI 개발 생태계의 구조적 변화 LlamaIndex의 전환은 고립된 사건이 아니다. AI 개발 생태계 전반에서 같은 패턴이 반복되고 있다:\nContext7 — LLM에게 최신 문서를 주입하는 \u0026ldquo;하나의 일\u0026quot;에 특화된 MCP 도구로 성공 (Context7 deep dive) MCP (Model Context Protocol) — 프레임워크가 아닌, 도구 간 표준화된 프로토콜 Claude Code 마켓플레이스 — 특정 기능에 특화된 플러그인들의 생태계 (마켓플레이스 비교) 2022-2024년은 \u0026ldquo;모든 것을 감싸는 프레임워크\u0026quot;의 시대였다면, 2025년부터는 \u0026ldquo;하나를 잘 하는 도구\u0026quot;의 시대가 되고 있다. 현재 HarnessKit과 log-blog도 이 방향 — 프레임워크가 아닌, 특정 문제를 잘 해결하는 플러그인으로 설계했다.\n인사이트 LlamaIndex의 전환이 의미 있는 이유는, 프레임워크의 한계를 외부 비평가가 아닌 프레임워크의 선구자 자신이 인정했다는 점이다. 이는 AI 개발 도구의 방향성에 대한 강한 신호다. 에이전트 시대에는 에이전트 자체가 오케스트레이션을 담당하기 때문에, 개발자가 필요한 것은 \u0026ldquo;모든 것을 엮어주는 프레임워크\u0026quot;가 아니라 \u0026ldquo;에이전트가 호출할 수 있는 좋은 도구\u0026quot;다. LiteParse가 문서 파싱을, Context7이 문서 주입을, MCP가 도구 프로토콜을 각각 담당하듯, 잘 만든 단일 도구들의 조합이 프레임워크를 대체하고 있다.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-ai-dev-tools/cover.jpg","permalink":"/ko/posts/2026-03-30-ai-dev-tools/","title":"LiteParse와 프레임워크 시대의 종말 — LlamaIndex의 전략적 전환"},{"content":"개요 AI 에이전트의 아키텍처와 품질 관리를 다루는 두 편의 YouTube 영상을 분석했다. 첫 번째는 Anthropic이 발표한 장기 실행 에이전트 블루프린트로, 몇 시간에서 며칠에 걸친 복잡한 태스크를 자율적으로 수행하는 설계 가이드다. 두 번째는 하네스 엔지니어링 실천으로, 에이전트의 품질을 체계적으로 관리하는 방법론이다. 관련 포스트: 서브에이전트 시대의 도래, HarnessKit 개발기 #3\ngraph TD A[\"Long-Running Agent\"] --\u003e B[\"태스크 분해\"] B --\u003e C[\"서브태스크 1\"] B --\u003e D[\"서브태스크 2\"] B --\u003e E[\"서브태스크 N\"] C --\u003e F{\"체크포인트\"} D --\u003e F E --\u003e F F --\u003e|\"성공\"| G[\"다음 단계\"] F --\u003e|\"실패\"| H[\"복구 전략\"] H --\u003e I[\"재시도\"] H --\u003e J[\"대체 경로\"] H --\u003e K[\"사람 에스컬레이션\"] L[\"하네스 엔지니어링\"] --\u003e M[\"가드레일\"] L --\u003e N[\"모니터링\"] L --\u003e O[\"피드백 루프\"] Anthropic의 Long-Running Agent 블루프린트 Anthropic Just Dropped the New Blueprint for Long-Running AI Agents 영상에서는 Anthropic이 공개한 장기 실행 에이전트 설계 가이드를 심층 분석한다.\n단발성 vs 장기 실행 기존 AI 에이전트 대부분은 단발성(one-shot)이다 — 질문을 받고, 답하고, 끝. 하지만 실제 업무는 \u0026ldquo;이 코드베이스를 리팩토링해줘\u0026rdquo;, \u0026ldquo;이 데이터 파이프라인을 구축해줘\u0026rdquo; 같은 몇 시간에서 며칠이 걸리는 복합 태스크다.\n장기 실행 에이전트는 이런 태스크를 자율적으로 수행하되, 중간에 실패하거나 방향을 잃었을 때 스스로 복구할 수 있어야 한다. Anthropic의 블루프린트는 이를 위한 설계 원칙을 제시한다.\n핵심 설계 원칙 1. 태스크 분해 (Task Decomposition)\n복잡한 태스크를 독립적인 서브태스크로 분해한다. 각 서브태스크는:\n명확한 입력과 출력 독립적으로 실행 및 검증 가능 실패 시 다른 서브태스크에 영향 최소화 2. 체크포인트와 상태 관리\n장기 실행에서 가장 위험한 것은 중간 결과의 유실이다. 각 서브태스크 완료 시 체크포인트를 저장하여:\n실패 시 마지막 체크포인트부터 재개 컨텍스트 윈도우 압축 시 핵심 상태 보존 사람 리뷰 포인트 제공 3. 실패 복구 전략\n세 단계 복구:\n재시도 — 일시적 오류(API 타임아웃 등)에 대해 자동 재시도 대체 경로 — 같은 목표를 다른 방법으로 달성 (Deterministic Fallback과 유사) 사람 에스컬레이션 — 에이전트가 자체적으로 해결할 수 없을 때 사람에게 판단 위임 4. 진행 보고와 투명성\n장기 실행 중 사용자가 \u0026ldquo;지금 뭘 하고 있는지\u0026rdquo; 알 수 있어야 한다. 주기적인 진행 보고, 현재 단계 표시, 예상 완료 시간 등을 제공한다.\n실제 적용 사례 현재 Claude Code 자체가 이 블루프린트의 구현체다. 대규모 리팩토링이나 기능 구현 시:\n태스크를 서브태스크로 분해 (Plan 모드) 각 파일 수정마다 체크포인트 (git commit) 실패 시 rewind로 이전 상태 복원 진행 상황을 사용자에게 보고 하네스 엔지니어링 — 에이전트 품질 관리 하네스 엔지니어링 따라하기 영상에서는 AI 에이전트의 품질을 체계적으로 관리하는 하네스 엔지니어링 방법론을 실무 관점에서 설명한다.\n하네스란 무엇인가 하네스(harness)는 원래 \u0026ldquo;마구\u0026quot;를 뜻한다. 말의 힘을 제어하고 방향을 잡아주는 장치처럼, AI 에이전트의 출력을 제어하고 품질을 보장하는 시스템이다. 에이전트가 강력할수록 하네스도 견고해야 한다.\n하네스의 3요소 1. 가드레일 (Guard Rails)\n에이전트가 하면 안 되는 것을 정의한다:\n파일 삭제 금지 영역 자동 커밋 조건 외부 API 호출 제한 비용 한도 2. 모니터링\n에이전트의 행동을 실시간으로 추적한다:\n도구 호출 패턴 에러 발생률 토큰 사용량 작업 완료율 3. 피드백 루프\n에이전트의 결과를 평가하고 개선한다:\n자동 테스트 결과 수집 사용자 피드백 반영 실패 패턴 학습 설정 자동 조정 매니지먼트 관점 영상은 기술적 구현뿐 아니라 매니지먼트 관점도 다룬다. 에이전트 팀을 관리하는 것은 인간 팀을 관리하는 것과 유사한 면이 있다:\n명확한 역할과 책임 정의 주기적인 성과 리뷰 (eval) 문제 발생 시 에스컬레이션 경로 지속적 교육 (프롬프트 개선) 두 접근법의 교차점 Long-Running Agent 블루프린트와 하네스 엔지니어링은 같은 문제를 다른 각도에서 본다:\n관점 Long-Running Agent 하네스 엔지니어링 초점 에이전트 내부 설계 에이전트 외부 제어 목표 자율적 태스크 완수 품질 보장 실패 대응 자체 복구 전략 가드레일 + 에스컬레이션 개선 방식 체크포인트 기반 피드백 루프 기반 둘을 합치면: 에이전트는 내부적으로 체크포인트와 복구 전략을 갖추고, 외부에서 하네스가 가드레일과 모니터링으로 품질을 보장하는 이중 안전 구조가 된다.\n현재 HarnessKit 프로젝트가 정확히 이 교차점에 있다 — Claude Code 에이전트의 외부 하네스를 플러그인 형태로 구현하여, 가드레일과 모니터링을 자동화하고 있다.\n인사이트 AI 에이전트가 단발성에서 장기 실행으로 진화하면서, \u0026ldquo;똑똑한 에이전트\u0026quot;보다 \u0026ldquo;신뢰할 수 있는 에이전트\u0026quot;가 더 중요해지고 있다. Anthropic의 블루프린트는 내부 설계로, 하네스 엔지니어링은 외부 제어로 이 신뢰성을 구축한다. 두 접근법이 결합된 이중 안전 구조가 프로덕션 에이전트의 표준이 될 것으로 보인다. 이 관점은 AI 앱 프로덕션 설계 패턴 포스트의 Deterministic Fallback, HITL과도 맥이 닿는다 — 결국 \u0026ldquo;실패를 전제한 설계\u0026quot;가 핵심이다.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-long-running-agents/cover.jpg","permalink":"/ko/posts/2026-03-30-long-running-agents/","title":"Long-Running AI Agents와 하네스 엔지니어링 실천"},{"content":"개요 YouTube 영상 별 11만개 받은 AI 플러그인, 코드 한 줄이면 끝을 분석했다. 이 11만 스타 플러그인의 정체는 Superpowers — 이전에 Superpowers 완벽 가이드에서 깊이 다뤘던 Claude Code 플러그인이다. 당시 69k 스타였던 것이 5개월 만에 11만을 돌파했다. 이번 포스트에서는 한국어 유튜버의 실무 관점 분석과 비판 포인트를 중심으로 정리한다. 관련 포스트: Superpowers 완벽 가이드, HarnessKit 개발기 #3\ngraph TD A[\"Superpowers 4단계 프로세스\"] --\u003e B[\"1. 브레인스토밍\u0026lt;br/\u0026gt;코드 전에 대화부터\"] B --\u003e C[\"2. 계획 수립\u0026lt;br/\u0026gt;설계도 먼저\"] C --\u003e D[\"3. TDD\u0026lt;br/\u0026gt;기준 먼저, 코드 나중\"] D --\u003e E[\"4. 서브에이전트 병렬\u0026lt;br/\u0026gt;팀으로 나눠서 실행\"] F[\"팀장 AI\u0026lt;br/\u0026gt;Opus 모델\"] --\u003e G[\"팀원 AI 1\u0026lt;br/\u0026gt;Haiku 모델\"] F --\u003e H[\"팀원 AI 2\u0026lt;br/\u0026gt;Haiku 모델\"] F --\u003e I[\"팀원 AI 3\u0026lt;br/\u0026gt;Haiku 모델\"] G --\u003e J[\"독립 작업 공간\u0026lt;br/\u0026gt;Git Worktree\"] H --\u003e J I --\u003e J Superpowers란 무엇인가 AI 코딩 도구(Claude Code, Cursor, Codex 등)에게 \u0026ldquo;앱 하나 만들어줘\u0026quot;라고 하면, 바로 코드를 짜기 시작한다. 영상의 비유가 적절하다:\n인테리어 업자한테 \u0026ldquo;카페 느낌으로 해주세요\u0026rdquo; 했더니, 몇 인석인지, 예산은 얼마인지 물어보지도 않고 바로 벽을 부수기 시작하는 것과 같다.\nSuperpowers는 이 문제를 해결한다. AI에게 **작업 순서를 강제하는 매뉴얼(스킬 파일)**을 주입하여, 대화 → 계획 → 테스트 → 구현 순서를 지키게 만든다. 5개월 만에 GitHub 11만 스타를 달성했고, 제작자 Jesse Vincent는 오랫동안 오픈소스를 만들어온 개발자다.\n설치는 간단하다:\n# Claude Code 사용자 /plugin install superpowers # Cursor 사용자 /plugin superpowers 핵심 1: 브레인스토밍 — 코드 전에 대화부터 일반적인 AI 코딩 도구에게 \u0026ldquo;로그인 기능 만들어줘\u0026quot;라고 하면 바로 코드를 생성한다. Superpowers가 설치되어 있으면 AI가 먼저 질문한다:\n어떤 방식으로 로그인하게 할 건가요? 이메일? 소셜 로그인? 비밀번호 찾기도 필요해요? 세션 관리는 어떻게? 두세 가지 방법을 제안하면서 장단점을 알려주고, 사용자가 \u0026ldquo;이걸로 가자\u0026rdquo; 승인을 해야 그때서야 만들기 시작한다. 벽부터 부수던 업자가 도면부터 보여주는 업자로 바뀌는 것이다.\n스킬 파일에는 AI가 이 단계를 건너뛸 수 없도록 명시되어 있다:\n\u0026ldquo;이건 선택이 아닙니다. 반드시 따르세요.\u0026rdquo;\nAI가 \u0026ldquo;이건 너무 간단해서 안 해도 되지 않나\u0026quot;라고 빠져나가려 할 때를 대비한 대응 매뉴얼까지 포함되어 있다.\n핵심 2: TDD — 기준 먼저, 코드 나중 영상의 비유: 된장찌개를 만들 때 보통은 레시피대로 만들고 마지막에 맛을 본다. TDD는 맛을 먼저 정해놓고 시작하는 것이다. \u0026ldquo;짠맛이 이 정도, 고춧가루는 이만큼\u0026rdquo; — 이 기준을 먼저 만들고 그 기준에 맞춰 요리한다.\nSuperpowers에서 이것은 \u0026ldquo;철칙\u0026quot;으로 적혀 있다:\n\u0026ldquo;기준 없이 만들기 시작하는 거 금지. 기준 없이 먼저 만들었으면 지우고 다시 해.\u0026rdquo;\n기능이 어떻게 동작해야 하는지의 기준(테스트)을 먼저 만들고, 그 기준을 통과하는 코드를 작성한다. \u0026ldquo;나중에 이거 왜 안 돼요?\u0026ldquo;라고 할 일이 없다.\n핵심 3: 서브에이전트 팀 — AI도 분업한다 가장 인상적인 설계 포인트다. 하나의 AI가 혼자 다 하는 것이 아니라, 팀을 나눠서 일한다.\n모델 분리 전략 역할 모델 이유 팀장 (계획 수립) Opus (고급) 깊이 생각해야 하는 전체 설계 팀원 (코드 작성) Haiku (경량) 계획이 나왔으니 빠르게 실행 건축에서 설계는 경력 30년 건축가가 하고, 벽돌쌓기는 숙련 기술자가 하는 것과 같다.\n컨텍스트 분리 각 팀원 AI는 자기 작업에만 집중한다. 코드를 읽는 AI, 코드를 짜는 AI, 검토하는 AI가 분리되어 있다. 사람도 회의 3개를 동시에 하면 머리가 터지듯, AI도 이것저것 다 시키면 실수가 늘어난다.\n독립 작업 공간 (Git Worktree) 여러 AI가 같은 프로젝트를 동시에 건드리면 충돌이 생긴다. Superpowers는 프로젝트의 복사본을 각 AI에게 따로 제공한다 (Git Worktree 활용). AI 1은 로그인 기능을, AI 2는 결제 기능을 각자의 작업 공간에서 만들고, 다 끝나면 합친다.\nSuperpowers의 한계 영상에서도 솔직하게 짚는 비판 포인트:\n정식 벤치마크가 없다 — 효과를 수치로 증명하는 비교 실험 데이터가 부족 브레인스토밍 질문의 깊이 — 어떤 질문을 할지의 설계가 아직 부족 QA 파트의 한계 — E2E(End-to-End) 테스트까지 가야 진짜 동작을 검증하는데, 현재 QA 단계가 충분하지 않음 HarnessKit과의 비교 Superpowers와 HarnessKit은 같은 문제를 다른 관점에서 해결한다:\n구분 Superpowers HarnessKit 접근 워크플로우 강제 (스킬) 가드레일 + 모니터링 (하네스) 초점 AI의 작업 순서 AI의 출력 품질 방식 프로세스 주입 환경 제어 설치 plugin install 한 줄 마켓플레이스 설치 둘은 경쟁이 아니라 보완 관계다. Superpowers로 작업 순서를 잡고, HarnessKit으로 품질을 관리하면 이중 안전 구조가 된다.\n인사이트 Superpowers가 5개월 만에 11만 스타를 받은 이유는 기술의 혁신이 아니다. \u0026ldquo;AI에게 프로세스를 심어주면 결과가 달라진다\u0026quot;는 단순한 원리를 시스템으로 구현한 것이다. 영상의 핵심 메시지가 정확하다 — AI 자체가 똑똑해지는 것보다, AI를 어떻게 쓰느냐가 더 중요하다. 같은 Claude Code를 써도 Superpowers 유무에 따라 결과가 완전히 달라진다. 이는 코딩뿐 아니라 모든 AI 활용에 적용되는 원칙이다. 현재 우리가 만드는 HarnessKit도 같은 철학의 산물이다 — AI의 능력이 아니라 AI의 작업 환경을 설계하는 것.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-ai-plugin-ecosystem/cover.jpg","permalink":"/ko/posts/2026-03-30-ai-plugin-ecosystem/","title":"Superpowers 후속 — 69k에서 11만 스타로, 그리고 아직 남은 한계"},{"content":"개요 이전 글: #6\n이번 #7에서는 34개 커밋에 걸쳐 트레이딩 에이전트의 분석 역량을 대폭 확장했다. DCF 밸류에이션과 민감도 히트맵, 포트폴리오 리스크 분석(VaR, 베타, 섹터 집중도), 시그널 파이프라인에 6번째 전문가(뉴스/매크로 애널리스트) 추가, DART 공시 연동, 그리고 투자 메모 내보내기 기능을 구현했다.\ngraph TD A[\"Signal Pipeline\"] --\u003e B[\"기술적 분석\"] A --\u003e C[\"펀더멘털 분석\"] A --\u003e D[\"센티먼트 분석\"] A --\u003e E[\"수급 분석\"] A --\u003e F[\"밸류에이션\"] A --\u003e G[\"뉴스/매크로 분석\u0026lt;br/\u0026gt;6번째 전문가 NEW\"] G --\u003e H[\"Google News RSS\"] G --\u003e I[\"DART 공시\"] G --\u003e J[\"내부자 거래\"] F --\u003e K[\"DCF 민감도\u0026lt;br/\u0026gt;히트맵\"] F --\u003e L[\"동종업계 비교\u0026lt;br/\u0026gt;DART 기반\"] A --\u003e M[\"포트폴리오 리스크\"] M --\u003e N[\"VaR\"] M --\u003e O[\"Beta\"] M --\u003e P[\"상관관계 행렬\"] DCF 밸류에이션과 민감도 분석 배경 기존 시그널 파이프라인에는 정량적 밸류에이션 모델이 없었다. 종목의 적정 가치를 추정하려면 DCF(Discounted Cash Flow) 모델이 필수적이고, 단일 값이 아닌 다양한 시나리오에서의 민감도를 보여줘야 투자 판단에 유용하다.\n구현 DCF 밸류에이션 서비스를 구현하고, 할인율(WACC)과 성장률 조합에 따른 민감도 히트맵 테이블을 ValuationView에 추가했다. 프론트엔드에서는 히트맵 형태로 시각화하여 어떤 가정 하에서 현재가가 저평가/고평가인지 직관적으로 파악할 수 있다.\n또한 동종업계 비교(peer comparison) 기능도 추가했다. DART에서 같은 섹터의 기업 밸류에이션 데이터를 가져와 상대적 위치를 비교할 수 있도록 했다.\n단위 테스트도 추가하여 DCF 밸류에이션과 포트폴리오 리스크 서비스의 핵심 로직을 검증했다.\n포트폴리오 리스크 분석 VaR, 베타, 섹터 집중도 포트폴리오 레벨의 리스크 분석 기능을 구현했다:\nVaR (Value at Risk): 일정 신뢰구간에서의 최대 예상 손실 Beta: 실제 포트폴리오 데이터 기반 베타 계산 섹터 집중도: 특정 섹터에 과도하게 집중되어 있는지 분석 상관관계 행렬 히트맵: 보유 종목 간 상관관계를 시각화 KOSPI200 구성 종목의 섹터 데이터를 NAVER Finance에서 수집하여 섹터 분류에 활용했다.\n시그널 파이프라인 확장 6번째 전문가: 뉴스/매크로 애널리스트 기존 5명의 전문가(기술적, 펀더멘털, 센티먼트, 수급, 밸류에이션)에 뉴스/매크로 애널리스트를 추가했다. 이 전문가는 거시경제 뉴스와 종목별 이벤트를 분석하여 시그널에 반영한다.\nGoogle News RSS 연동 — 뉴스 수집의 안정성을 높이기 위해 Google News RSS를 fallback으로 추가했다. 기존 뉴스 소스가 불안정할 때 자동으로 전환된다.\nDART 공시 연동 촉매 캘린더(Catalyst Calendar): DART 공시 일정을 타임라인 UI로 표시하여 향후 중요 이벤트를 한눈에 파악 내부자 거래: DART 내부자 거래 데이터를 시그널 파이프라인에 통합 외국인/기관 투자자 동향: 수급 분석에 외국인·기관 매매 동향 데이터 추가 DB 스키마 확장 8개 신규 테이블과 ANALYST 역할, 메타데이터 초기화를 추가했다. 새 기능들에 필요한 데이터 모델을 한 번에 정의했다.\n시그널 히스토리와 비교 시그널 히스토리 스냅샷과 타임라인 비교 기능을 추가했다. 과거 시그널과 현재를 비교하여 시간에 따른 변화 추이를 추적할 수 있다. 이는 시그널의 일관성과 예측력을 사후 평가하는 데 활용된다.\n프론트엔드 UI 개선 SignalCard 확장: 전문가 의견 확장 표시, risk_notes 표시, compact/expanded 뷰 토글 SignalDetailModal: 관련 주문 내역을 드릴다운으로 확인 ReportViewer: 거래 PnL 컬럼과 rr_score 색상 코딩 추가 ScheduleManager: cron 편집과 즉시 실행(run-now) 버튼, 에이전트 이름과 친숙한 태스크 라벨 표시 DashboardView: report.generated 이벤트 핸들링, 성능 엔드포인트 기간 선택 투자 메모 내보내기 시그널 데이터를 기반으로 한 투자 메모를 HTML과 DOCX 형식으로 내보내는 기능을 추가했다. python-docx를 사용하여 Word 문서 형식의 투자 메모를 생성할 수 있다.\n서버 안정성 MCP(Model Context Protocol) 연결 안정성을 개선했다:\n비동기 MCP 컨텍스트 메서드에 await 누락 수정 연결 실패 시 자동 재연결 로직 추가 서버 로그를 주기적으로 모니터링하며 websockets 라이브러리의 deprecated API 경고와 기타 런타임 에러를 분류하고 코드베이스 이슈만 선별 수정했다.\n설정 확장 initial_capital과 min_rr_score를 설정과 risk-config API에 추가 기존 디자인 시스템과 일관된 스타일로 새 컴포넌트 정렬 Vite ESM 해석 오류 수정 (import type 사용) lint 에러(unused vars) 정리 커밋 로그 메시지 변경 feat: show agent name and friendly task labels in ScheduleManager frontend style: align new components with existing design system frontend fix: use import type for ScheduledTask to fix Vite ESM resolution frontend feat: add Google News RSS fallback for news collection stability backend feat: add compact/expanded view toggle to SignalCard frontend feat: add DOCX investment memo export with python-docx backend feat: add real portfolio beta calculation and correlation matrix heatmap backend + frontend feat: add DCF sensitivity heatmap table to ValuationView frontend test: add unit tests for DCF valuation and portfolio risk services test feat: populate kospi200_components sector data from NAVER Finance backend fix: await async MCP context methods and add auto-reconnect on failure backend fix: replace explicit any types with proper interfaces in SignalCard frontend feat: add investment memo HTML export from signal data backend feat: add VaR, beta, sector concentration risk analysis backend feat: add DCF valuation with sensitivity table backend feat: add signal history snapshots and timeline comparison full-stack feat: add peer comparison with sector-based DART valuation backend feat: add news/macro analyst as 6th expert in signal pipeline backend feat: add catalyst calendar with DART disclosures and timeline UI full-stack feat: add DART insider trading data to signal pipeline backend feat: add foreign/institutional investor trend to signal pipeline backend feat: add 8 new DB tables, ANALYST role, and metadata init backend fix: resolve lint errors (unused vars) in DashboardView and SignalCard frontend feat: add report.generated event handling in DashboardView frontend feat: add initial_capital and min_rr_score to settings and risk-config API full-stack feat: add ScheduleManager with cron editing and run-now button frontend feat: add trade PnL column and rr_score color coding to ReportViewer frontend feat: add SignalDetailModal with related orders drilldown frontend feat: add expert opinion expansion and risk_notes display to SignalCard frontend feat: use correct performance endpoint with period selector and metrics frontend 인사이트 34개 커밋은 이번 시리즈에서 가장 많은 양이다. 트레이딩 에이전트가 단순한 시그널 생성 도구에서 포트폴리오 리스크 관리, 밸류에이션 분석, 공시 모니터링까지 아우르는 종합 분석 플랫폼으로 진화하고 있다. 특히 6번째 전문가(뉴스/매크로)의 추가와 DART 연동은 한국 주식시장에 특화된 데이터 소스를 적극 활용한다는 점에서 의미가 크다. DCF 민감도 히트맵과 포트폴리오 상관관계 행렬은 시각적으로 복잡한 데이터를 직관적으로 전달하는 좋은 사례다. 서버 안정성 측면에서 MCP 자동 재연결과 주기적 로그 모니터링 패턴이 정착된 것도 프로덕션 수준 향상에 기여하고 있다.\n","date":"2026-03-30T00:00:00+09:00","image":"/images/posts/2026-03-30-trading-agent-dev7/cover.jpg","permalink":"/ko/posts/2026-03-30-trading-agent-dev7/","title":"Trading Agent 개발기 #7 — DCF 밸류에이션, 포트폴리오 리스크 분석, 6번째 전문가 추가"},{"content":"개요 TILNOTE의 글 \u0026ldquo;AI 앱에서 진짜 중요한 것\u0026quot;을 분석했다. 핵심 메시지는 명확하다 — 진짜 문제는 모델이 잘 말하는 순간이 아니라, 애매하게 틀릴 때 시스템이 어떻게 행동하느냐에 있다. Deterministic Fallback, HITL, Evaluation Stack 세 가지 패턴을 프로덕션 관점에서 정리한다. 관련 포스트: 바이브 코딩 보안 점검 가이드\ngraph TD A[\"사용자 입력\"] --\u003e B{\"모델 응답 + 검증\"} B --\u003e|\"통과\"| C[\"정상 경로\u0026lt;br/\u0026gt;모델 답변 제공\"] B --\u003e|\"근거 부족\"| D[\"제한 경로\u0026lt;br/\u0026gt;확인된 범위만 답변\"] B --\u003e|\"실패\"| E[\"대체 경로\u0026lt;br/\u0026gt;검색/템플릿 제공\"] B --\u003e|\"위험\"| F[\"중단 경로\u0026lt;br/\u0026gt;사람 검토로 전환\"] G[\"HITL 제어\"] --\u003e B G --\u003e D G --\u003e F H[\"Evaluation Stack\"] --\u003e I[\"Offline eval\"] H --\u003e J[\"Pre-production backtest\"] H --\u003e K[\"Online eval\"] H --\u003e L[\"Human review\"] 왜 이 세 가지인가 글은 구체적인 사례로 시작한다. 고객지원 AI가 환불 정책을 안내하는 상황:\n사용자: \u0026ldquo;지난달 결제 건 환불 가능한가요? 카드 취소로 처리해 주세요.\u0026rdquo; 모델: \u0026ldquo;네, 최근 30일 이내 결제 건은 자동 환불 가능합니다. 바로 진행할게요.\u0026rdquo;\n문제는 실제 정책에 \u0026ldquo;디지털 상품 사용 이력이 있으면 환불 불가\u0026rdquo; 조항이 있고, 자동 환불은 상담사 승인 대상이라는 점이다. 사고의 본질은 \u0026ldquo;모델이 틀렸다\u0026quot;가 아니라 **\u0026ldquo;시스템이 틀렸을 때 멈추도록 설계되지 않았다\u0026rdquo;**에 있다.\nNIST AI 600-1도 생성형 AI는 별도의 위험 관리, 측정, 운영 통제가 필요하다고 정리하고, Anthropic과 OpenAI 모두 성공 기준 정의와 평가 설계를 우선하라고 안내한다.\n1. Deterministic Fallback — 모르면 안전한 길로 많은 개발자가 temperature를 낮추고 프롬프트를 다듬으면 안정적일 거라 기대한다. 어느 정도는 맞지만, 그건 출력 흔들림을 줄이는 것이지 시스템을 결정적으로 만드는 것이 아니다.\n실무에서 필요한 건 모델이 실패했을 때 미리 정한 경로로 강등되는 구조다:\n단계 경로 동작 1 정상 모델 답변 + 검증 통과 2 제한 근거가 확인된 범위만 답변 3 대체 검색 결과, 정책 문서, 템플릿만 제공 4 중단 사람 검토로 전환 핵심은 실패를 모델의 감각에 맡기지 않고, 코드로 정의된 상태 전이로 바꾸는 것이다.\n고객지원 봇의 안전한 흐름:\nFAQ/정책 문서 검색 먼저 근거 충분할 때만 답변 근거 약하면 상담 연결 환불 같은 액션은 자동 실행 금지 코드 생성 도구도 마찬가지다. 위험한 구조는 \u0026ldquo;코드 직접 반영\u0026quot;이고, 현실적 구조는 \u0026ldquo;패치 제안 → 테스트 → 리뷰 → 사람이 머지\u0026quot;다. Anthropic의 Tool Use 문서가 이 구조를 잘 설명한다 — 모델이 도구를 직접 실행하지 않고, 호출을 제안하면 앱이 실행을 담당한다.\n2. HITL — 사람은 승인 버튼이 아니라 제어 장치 HITL(Human-in-the-Loop)을 \u0026ldquo;마지막에 사람 한 번 본다\u0026quot;로 이해하면 불완전하다. 실무에서 중요한 HITL은 사람이 시스템 흐름을 멈추고, 수정하고, 다시 이어가게 하는 제어 장치다.\n글에서 강조하는 구분:\n수동적 HITL 능동적 HITL 최종 승인만 담당 흐름 중간에 개입 결과 확인 원인 수정 배치 리뷰 실시간 제어 능동적 HITL은 에이전트 워크플로우에서 특히 중요하다. 에이전트가 10단계 작업 중 3단계에서 잘못된 방향으로 가고 있을 때, 10단계가 끝나고 승인하는 것이 아니라 3단계에서 멈추고 방향을 수정할 수 있어야 한다.\n3. Evaluation Stack — 평가는 회귀 방지 장치 OpenAI의 eval 가이드는 \u0026ldquo;생성형 AI는 본질적으로 variability가 있기 때문에, 기존 소프트웨어 테스트만으로는 충분하지 않다\u0026quot;고 설명한다.\n4단계 평가 체계:\nOffline eval: 고정 데이터셋에서 모델 성능 측정. 가장 빠르고 저렴 Pre-production backtest: 실제 트래픽 로그로 새 버전을 시뮬레이션 Online eval: A/B 테스트, 카나리 배포. 실제 사용자에게 점진적 노출 Human review: 사람이 직접 출력을 검토. 가장 비싸지만 가장 신뢰 핵심은 평가가 리더보드(벤치마크 경쟁)가 아니라 회귀 방지 장치라는 관점이다. 새 프롬프트나 모델 변경이 기존에 잘 되던 것을 망가뜨리지 않는지 확인하는 것이 목적이다.\n오늘 바로 적용할 수 있는 순서 글에서 제안하는 실무 적용 순서:\n출력 구조화 — 자유 텍스트가 아닌 JSON 등 구조화된 형태로 위험한 액션 한 단계 낮추기 — 직접 실행 → 제안으로 fallback 조건을 코드로 정의 — confidence 기반 분기 실패 사례 모아 eval 세트 만들기 — 작은 것부터 사람 검토 로그 보존 — 향후 eval 데이터로 활용 흔한 실수 \u0026ldquo;프롬프트를 잘 짜면 된다\u0026rdquo; → 프롬프트는 출력 흔들림 감소, 시스템 안전성과는 별개 \u0026ldquo;guardrail만 달면 된다\u0026rdquo; → 입력 필터링은 일부일 뿐, 출력 경로 설계가 핵심 \u0026ldquo;사람이 마지막에 확인하면 된다\u0026rdquo; → 수동적 HITL은 규모에서 실패 \u0026ldquo;벤치마크가 좋으면 프로덕션도 좋다\u0026rdquo; → eval은 회귀 방지지, 성능 보증이 아님 인사이트 이 글이 가치 있는 이유는 \u0026ldquo;모델을 더 똑똑하게 만드는 기술\u0026quot;이 아니라 \u0026ldquo;모델이 흔들려도 제품이 같이 흔들리지 않게 만드는 설계\u0026quot;에 집중한다는 점이다. NIST, Anthropic, OpenAI의 공식 가이드를 근거로 삼으면서도 실무 적용 순서를 구체적으로 제시한다. 현재 진행 중인 trading-agent와 hybrid-search 프로젝트 모두에서, 특히 자동 매매나 이미지 생성 같은 \u0026ldquo;되돌리기 어려운 액션\u0026quot;에 대해 Deterministic Fallback 패턴을 적용할 수 있다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-ai-app-production-patterns/cover.jpg","permalink":"/ko/posts/2026-03-25-ai-app-production-patterns/","title":"AI 앱 프로덕션 설계 — Deterministic Fallback, HITL, Evaluation Stack"},{"content":"개요 바이브 코딩으로 앱을 만들 때 가장 큰 문제 중 하나는 디자인의 일관성이다. AI가 생성한 UI는 기능적으로 작동하지만, 색상, 간격, 타이포그래피가 화면마다 제각각인 경우가 많다. 피튜브의 주간 라이브에서 소개된 Claude Code \u0026amp; 피그마로 일관된 디자인 하는 방법 Figma 커뮤니티 파일과 Figmapedia 리소스를 분석하고, 실전 워크플로우를 정리한다.\n문제: 바이브 코딩에서의 디자인 파편화 Claude Code로 UI를 생성하면 각 프롬프트마다 독립적으로 스타일이 결정된다. 컴포넌트 A는 #3B82F6 파란색, 컴포넌트 B는 #2563EB 파란색 — 미묘하게 다른 색상이 누적되면 전체적으로 정돈되지 않은 느낌을 준다.\ngraph TD A[\"프롬프트 1 \u0026lt;br/\u0026gt; 버튼 컴포넌트\"] --\u003e B[\"색상: #3B82F6 \u0026lt;br/\u0026gt; 패딩: 8px 16px\"] C[\"프롬프트 2 \u0026lt;br/\u0026gt; 카드 컴포넌트\"] --\u003e D[\"색상: #2563EB \u0026lt;br/\u0026gt; 패딩: 12px 24px\"] E[\"프롬프트 3 \u0026lt;br/\u0026gt; 네비게이션\"] --\u003e F[\"색상: #1D4ED8 \u0026lt;br/\u0026gt; 패딩: 10px 20px\"] B --\u003e G[\"디자인 파편화\"] D --\u003e G F --\u003e G 해결책: Figma 디자인 토큰 → Claude Code 컨텍스트 1단계: Figma에서 디자인 시스템 정의 Figma 커뮤니티 파일에서 제안하는 방식은 디자인 토큰을 체계적으로 정의하는 것이다:\nColor Tokens: Primary, Secondary, Neutral, Semantic (Success/Warning/Error) Spacing Scale: 4px 단위 (4, 8, 12, 16, 24, 32, 48, 64) Typography Scale: Heading 1~6, Body, Caption, Label Border Radius: 4px, 8px, 12px, 16px, Full Shadow Scale: sm, md, lg, xl 2단계: CLAUDE.md에 디자인 규칙 명시 # Design System ## Colors - Primary: #3B82F6 (Blue 500) - Primary Hover: #2563EB (Blue 600) - Background: #FFFFFF - Surface: #F8FAFC (Slate 50) - Text Primary: #0F172A (Slate 900) ## Spacing - Base unit: 4px - Component padding: 8px 16px (sm), 12px 24px (md), 16px 32px (lg) ## Typography - Font: Inter - Heading: 600 weight, 1.25 line-height - Body: 400 weight, 1.5 line-height 이 규칙을 CLAUDE.md에 포함하면, Claude Code가 모든 UI 생성 시 동일한 디자인 토큰을 참조한다.\n3단계: 컴포넌트 단위 프롬프팅 graph LR A[\"Figma \u0026lt;br/\u0026gt; 디자인 토큰\"] --\u003e B[\"CLAUDE.md \u0026lt;br/\u0026gt; 디자인 규칙\"] B --\u003e C[\"Claude Code \u0026lt;br/\u0026gt; UI 생성\"] C --\u003e D[\"일관된 \u0026lt;br/\u0026gt; 컴포넌트\"] D --\u003e E[\"Figma \u0026lt;br/\u0026gt; 검증\"] E --\u003e|\"불일치 발견\"| B Figmapedia — 디자인 용어를 정확하게 Figmapedia는 디자인 용어사전 \u0026amp; 리소스 플랫폼이다. \u0026ldquo;AI로 검색해도 잘 나오지 않는 실무 디자인 정보\u0026quot;를 정리해놓은 사이트로, Claude Code에 디자인 관련 프롬프트를 작성할 때 정확한 용어를 사용하는 데 도움이 된다.\n주요 카테고리:\n피그마 용어 \u0026amp; 정보: Figma 고유 기능과 용어 설명 프롬프트 피디아: AI 코딩에 활용할 수 있는 디자인 프롬프트 모음 버튼 컴포넌트 내부/외부 여백: 실무에서 자주 혼동되는 패딩/마진 규칙 Claude Code에 \u0026ldquo;버튼의 내부 여백을 줄여줘\u0026quot;라고 프롬프팅할 때, padding과 margin의 차이를 정확하게 인지하고 있어야 원하는 결과를 얻을 수 있다. Figmapedia가 이런 간극을 메워준다.\n실전 팁: Claude Code + Figma 워크플로우 디자인 스크린샷 기반 프롬프팅 Figma에서 디자인을 완성한 뒤, 스크린샷을 Claude Code에 전달하면 시각적 참조를 기반으로 코드를 생성한다:\n이 Figma 디자인을 React 컴포넌트로 구현해줘. 디자인 토큰은 CLAUDE.md의 Design System 섹션을 따라줘. Tailwind CSS 토큰 매핑 Figma 디자인 토큰을 Tailwind의 tailwind.config.js로 변환하면, Claude Code가 생성하는 코드에서 자동으로 일관된 스타일이 적용된다.\n검증 루프 Claude Code로 컴포넌트 생성 브라우저에서 렌더링 확인 Figma 원본과 시각적 비교 차이가 있으면 피드백 → 재생성 인사이트 바이브 코딩의 \u0026ldquo;디자인 품질 문제\u0026quot;는 기술적 한계가 아니라 컨텍스트 부족의 문제다. Claude Code에 명확한 디자인 토큰과 규칙을 제공하면, 일관된 UI를 생성할 수 있다. Figma 디자인 시스템 → CLAUDE.md 규칙 → Claude Code 생성이라는 파이프라인을 구축하면, 디자이너 없이도 프로덕션 수준의 UI 일관성을 유지할 수 있다. Figmapedia 같은 리소스는 개발자가 디자인 영역의 정확한 어휘를 익히는 데 유용하며, 이는 AI에게 더 정확한 지시를 내리는 것으로 직결된다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-claude-code-figma/cover.jpg","permalink":"/ko/posts/2026-03-25-claude-code-figma/","title":"Claude Code와 Figma로 일관된 디자인 구현하기 — 피그마 커뮤니티 리소스 분석"},{"content":"개요 Anthropic이 Claude에게 컴퓨터의 마우스, 키보드, 화면을 직접 제어하는 기능을 정식 출시했다. Claude Code Desktop 및 Cowork과 연동되어 실제 GUI를 조작할 수 있고, Dispatch와 결합하면 자리를 비운 상태에서도 원격으로 Claude가 작업을 수행한다. macOS에 먼저 출시되었으며, Windows는 수 주 내 지원 예정이다.\nComputer Use란 무엇인가 기존 Claude Code는 터미널 안에서 CLI 명령어를 실행하는 방식으로 동작했다. Computer Use는 이 범위를 GUI 전체로 확장한다. Claude가 화면을 스크린샷으로 인식하고, 마우스 클릭, 키보드 입력, 드래그 등의 액션을 실행할 수 있다.\ngraph LR A[\"Claude AI\"] --\u003e B[\"Screen Capture \u0026lt;br/\u0026gt; 화면 인식\"] B --\u003e C[\"Action Planning \u0026lt;br/\u0026gt; 행동 계획\"] C --\u003e D[\"Mouse / Keyboard \u0026lt;br/\u0026gt; 입력 실행\"] D --\u003e E[\"Result Capture \u0026lt;br/\u0026gt; 결과 확인\"] E --\u003e B핵심 제약: Computer Use는 아직 초기 단계다. Claude는 사람보다 훨씬 느리고 신중하게 동작한다. 이는 의도된 설계로, 안전성을 우선시하기 때문이다.\nClaude Code Desktop \u0026amp; Cowork 연동 Claude Code Desktop에서 Computer Use를 활성화하면, 코딩 작업 중 IDE나 브라우저를 직접 조작할 수 있다. 예를 들어:\n레거시 앱 자동화: API가 없는 GUI 전용 앱의 반복 작업 자동화 네이티브 앱 디버깅: Xcode, Android Studio 등에서 직접 빌드/테스트 실행 브라우저 테스트: 실제 브라우저에서 UI 인터랙션 테스트 Cowork 모드에서는 Claude가 사용자와 동시에 같은 화면에서 작업하며, 사용자가 실시간으로 Claude의 동작을 관찰하고 개입할 수 있다.\nDispatch — 원격 비동기 작업 Computer Use의 진정한 잠재력은 Dispatch와 결합할 때 나타난다.\ngraph TD A[\"사용자\"] --\u003e|\"작업 지시\"| B[\"Dispatch\"] B --\u003e|\"태스크 큐잉\"| C[\"Claude Agent\"] C --\u003e|\"Computer Use\"| D[\"macOS Desktop\"] D --\u003e|\"결과 보고\"| B B --\u003e|\"알림\"| A자리를 비운 상태에서도 Claude가 컴퓨터를 조작하도록 지시할 수 있다. 예를 들어 \u0026ldquo;이 스프레드시트의 데이터를 정리해서 이메일로 보내줘\u0026rdquo; 같은 복합 작업을 비동기로 처리한다.\n기존 Claude Code Remote Control과의 관계 이전에 Claude Code에는 이미 원격 제어 기능(Remote Control)이 있었다. Computer Use와의 차이를 정리하면:\n기능 Remote Control Computer Use 범위 터미널 CLI 명령어 GUI 전체 (마우스/키보드) 대상 파일 시스템, 셸 모든 데스크톱 앱 속도 즉시 실행 느리고 신중함 안전성 샌드박스 내 화면 전체 접근 활용 코딩, 빌드, 테스트 레거시 자동화, GUI 테스트 두 기능은 보완 관계다. CLI로 처리 가능한 작업은 Remote Control이 효율적이고, GUI가 필수적인 작업에만 Computer Use를 사용하는 것이 권장된다.\n실전 활용 시나리오 레거시 앱 자동화 API가 없는 엔터프라이즈 소프트웨어(ERP, CRM 등)의 반복 작업을 자동화할 수 있다. 데이터 입력, 보고서 생성, 승인 프로세스 등 매일 수행하는 GUI 작업을 Claude에게 위임한다.\n크로스 앱 워크플로우 여러 앱을 오가며 수행하는 복합 작업을 단일 명령으로 실행한다. 예를 들어 Figma에서 디자인을 캡처 → VS Code에서 코드 수정 → 브라우저에서 결과 확인하는 전체 흐름을 자동화한다.\nQA 테스트 실제 UI에서의 사용자 경험을 테스트한다. Playwright나 Selenium 같은 자동화 도구와 달리, Computer Use는 시각적으로 화면을 인식하므로 CSS 셀렉터 변경에 영향받지 않는 강건한 테스트가 가능하다.\n현재 한계 속도: 사람보다 훨씬 느림 — 각 단계에서 스크린샷을 분석하고 계획을 세우므로 대기 시간 발생 정확도: 복잡한 UI에서 잘못된 요소를 클릭할 가능성 플랫폼: macOS 우선 출시, Windows는 아직 미지원 보안: 화면 전체에 접근하므로, 민감한 정보가 표시된 상태에서의 사용 주의 필요 인사이트 Claude Computer Use는 AI 에이전트가 \u0026ldquo;코드 생성기\u0026quot;에서 \u0026ldquo;디지털 작업자\u0026quot;로 진화하는 중요한 전환점이다. CLI 환경에 갇혀 있던 AI가 GUI 전체를 다룰 수 있게 되면서, 자동화 가능한 작업의 범위가 극적으로 넓어졌다. 아직 초기 단계라 속도와 정확도에 한계가 있지만, Dispatch와의 결합으로 비동기 원격 작업이 가능해진 점은 개발자 워크플로우에 실질적인 변화를 가져올 수 있다. 특히 레거시 시스템 자동화와 크로스 앱 워크플로우에서 Claude Code의 Remote Control과 Computer Use를 조합하면, 거의 모든 컴퓨터 작업을 AI에게 위임할 수 있는 시대가 가까워지고 있다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-claude-computer-use/cover.jpg","permalink":"/ko/posts/2026-03-25-claude-computer-use/","title":"Claude Computer Use — 마우스와 키보드를 직접 제어하는 AI의 등장"},{"content":"개요 이미지-텍스트 임베딩 모델의 핵심인 CLIP 계열 생태계를 집중 리서치했다. OpenAI의 오리지널 CLIP부터 Meta의 MetaCLIP2(NeurIPS 2025 Spotlight), Apple의 MobileCLIP2(TMLR 2025 Featured), 커뮤니티 기반 OpenCLIP, Google의 SigLIP까지 — 현재 hybrid-image-search 프로젝트의 임베딩 모델 선정을 위한 비교 분석이다. 관련 시리즈: Hybrid Image Search 개발기 #5\ngraph TD A[\"OpenAI CLIP\u0026lt;br/\u0026gt;2021, 33k stars\u0026lt;br/\u0026gt;WIT 4억 쌍\"] --\u003e B[\"OpenCLIP\u0026lt;br/\u0026gt;커뮤니티 재현\u0026lt;br/\u0026gt;13.6k stars\"] A --\u003e C[\"MetaCLIP\u0026lt;br/\u0026gt;Meta FAIR\u0026lt;br/\u0026gt;데이터 큐레이션 공개\"] A --\u003e D[\"SigLIP\u0026lt;br/\u0026gt;Google\u0026lt;br/\u0026gt;Sigmoid Loss\"] A --\u003e E[\"MobileCLIP\u0026lt;br/\u0026gt;Apple\u0026lt;br/\u0026gt;Multi-Modal Reinforced\"] C --\u003e F[\"MetaCLIP2\u0026lt;br/\u0026gt;NeurIPS 2025 Spotlight\u0026lt;br/\u0026gt;Worldwide 다국어\"] E --\u003e G[\"MobileCLIP2\u0026lt;br/\u0026gt;TMLR 2025 Featured\u0026lt;br/\u0026gt;iPhone 최적화\"] B --\u003e H[\"통합 허브\u0026lt;br/\u0026gt;300+ 사전학습 모델\"] D --\u003e H F --\u003e H G --\u003e H OpenAI CLIP — 모든 것의 시작 openai/CLIP(33k stars)은 2021년 발표된 Contrastive Language-Image Pre-Training 모델이다. 이미지와 텍스트를 같은 임베딩 공간에 매핑하는 접근법을 대중화했고, 이후 모든 CLIP 변형의 기반이 되었다.\n핵심 아이디어는 놀랍도록 단순하다 — 4억 개의 (이미지, 텍스트) 쌍에서 contrastive learning으로 학습하면, ImageNet의 128만 라벨링 이미지 없이도 zero-shot으로 이미지를 분류할 수 있다. 기본 사용법도 직관적이다:\nimport clip model, preprocess = clip.load(\u0026#34;ViT-B/32\u0026#34;, device=device) image_features = model.encode_image(image) text_features = model.encode_text(text) logits_per_image, logits_per_text = model(image, text) probs = logits_per_image.softmax(dim=-1).cpu().numpy() # prints: [[0.9927937 0.00421068 0.00299572]] encode_image()와 encode_text()로 각각 벡터를 뽑고, 코사인 유사도를 계산하면 끝이다. API는 clip.available_models()로 사용 가능한 모델 목록을 확인하고, clip.load(name)으로 모델과 전처리 함수를 로드하는 구조다.\n한계: 학습 데이터 WIT(WebImageText)는 비공개이고, 최대 모델은 ViT-L/14까지다. 이 두 가지 한계가 후속 연구들의 동기가 되었다.\nOpenCLIP — 사실상의 CLIP 허브 mlfoundations/open_clip(13.6k stars)은 CLIP의 오픈소스 재구현이자, 현재 CLIP 생태계의 사실상 허브다. LAION-2B, DataComp-1B 같은 공개 대규모 데이터셋에서 학습한 300개 이상의 사전학습 모델을 제공한다.\n성능 비교가 핵심이다:\n모델 학습 데이터 해상도 학습 샘플 수 ImageNet zero-shot ViT-B-16 DataComp-1B 224px 13B 73.5% ViT-L-14 DataComp-1B 224px 13B 79.2% ViT-H-14 LAION-2B 224px 32B 78.0% ViT-bigG-14 LAION-2B 224px 34B 80.1% ViT-L-14 (OpenAI 원본) WIT 224px 13B 75.5% OpenCLIP ViT-L-14가 같은 아키텍처의 OpenAI 원본 대비 3.7%p 높은 정확도를 달성했다. 학습 데이터가 같은 모델 아키텍처에서 이 정도 차이를 만든다는 것은 데이터 큐레이션의 중요성을 명확히 보여준다.\nMetaCLIP, SigLIP, MobileCLIP 등 주요 변형 모델이 모두 OpenCLIP을 통해 로드 가능하다. open_clip.create_model_and_transforms()로 통합 인터페이스를 제공하기 때문에, 모델 비교 실험에서 코드 변경 없이 모델만 교체할 수 있다.\nMetaCLIP2 — 다국어 확장과 NeurIPS 2025 Spotlight facebookresearch/metaclip(1.8k stars)은 Meta FAIR의 프로젝트로, CLIP의 데이터 큐레이션 과정 자체를 재현 가능하게 만든 것이 핵심 기여다. 최신 MetaCLIP2(\u0026ldquo;worldwide\u0026rdquo;)는 NeurIPS 2025 Spotlight으로 선정되었다.\nMetaCLIP2의 가장 중요한 발견은 **영어와 비영어 데이터가 서로를 상호 강화(mutually benefit)**한다는 것이다. 기존 multilingual CLIP들은 다국어를 추가하면 영어 성능이 떨어지는 \u0026ldquo;다국어의 저주(curse of multilinguality)\u0026ldquo;가 있었다. MetaCLIP2는 데이터 큐레이션 파이프라인 자체를 다국어로 설계하여 이 문제를 해결했다.\n학술적 성과도 인상적이다:\nICLR 2024 Spotlight (MetaCLIP 1.0) CVPR 2024, EMNLP 2024 (Altogether 합성 캡션) NeurIPS 2025 Spotlight (MetaCLIP2 Worldwide) distillation 모델과 학습/평가 코드가 모두 공개되어 있고, HuggingFace 컬렉션과 OpenCLIP에서 바로 사용 가능하다. 한국어 이미지 검색을 다루는 hybrid-search 프로젝트 관점에서, 다국어 CLIP의 성능이 영어 전용 모델을 넘어선다는 점은 모델 선택에 직접적인 영향을 준다.\nMobileCLIP2 — 모바일 디바이스의 최전선 apple/ml-mobileclip(1.5k stars)은 Apple의 Multi-Modal Reinforced Training 기반 경량 CLIP 모델이다. MobileCLIP2는 TMLR 2025 Featured Certification을 받았다.\n벤치마크 결과가 강력하다:\nMobileCLIP2-S4는 SigLIP-SO400M/14과 동등한 정확도를 2배 적은 파라미터로 달성하고, DFN ViT-L/14 대비 2.5배 낮은 레이턴시(iPhone 12 Pro Max 기준)를 보인다.\n특히 다른 CLIP 변형들과 차별화되는 점은 **iOS 앱 데모(ios_app/)**를 포함한다는 것이다. Swift 코드로 실시간 zero-shot 이미지 분류를 모바일에서 직접 실행할 수 있다. 학습 코드는 OpenCLIP 기반이며, DFNDR과 DataCompDR 데이터셋을 사용한다.\nMobileCLIP의 핵심 기술인 Multi-Modal Reinforced Training은 대형 teacher 모델의 지식을 경량 student 모델로 증류(distillation)하되, 이미지와 텍스트 양쪽에서 동시에 reinforcement를 적용하는 방식이다. 대규모 데이터 생성 코드는 별도 레포(ml-mobileclip-dr)로 공개되어 있다.\nSigLIP과 HuggingFace 임베딩 모델 생태계 Google의 SigLIP(Sigmoid Loss for Language-Image Pre-Training)은 CLIP의 softmax contrastive loss를 sigmoid loss로 대체한 변형이다. google/siglip-so400m-patch14-384가 대표 모델로, HuggingFace에서 10개 모델 컬렉션으로 제공된다.\nSigLIP의 장점은 배치 크기에 덜 민감하다는 것이다. 원본 CLIP은 큰 배치에서 더 좋은 성능을 보이는데, sigmoid loss는 각 쌍을 독립적으로 처리하여 배치 크기 의존도를 줄인다.\nHuggingFace 모델 허브 탐색 HuggingFace의 세 가지 허브를 함께 탐색했다:\nImage Feature Extraction Models — CLIP 계열 모델들이 트렌딩 상위를 차지. pipeline_tag=image-feature-extraction으로 필터링하면 현재 활발한 모델들을 확인 가능 Zero-Shot Image Classification Models — 라벨 없이 이미지를 분류하는 모델들. CLIP 기반이 대다수 MTEB Leaderboard — Massive Text Embedding Benchmark. 텍스트 임베딩 성능을 38개 데이터셋에서 종합 평가. 이미지 임베딩과 직접 비교할 수는 없지만, 멀티모달 모델의 텍스트 쪽 성능을 가늠하는 데 참고 모델 선정 기준 정리 리서치 결과를 hybrid-search 프로젝트 관점에서 정리하면:\n기준 최적 모델 이유 정확도 우선 OpenCLIP ViT-bigG-14 ImageNet 80.1% 다국어 (한국어) MetaCLIP2 다국어 성능 SoTA 모바일 배포 MobileCLIP2-S4 SigLIP 동급, 2배 경량 범용 + 생태계 OpenCLIP ViT-L-14 79.2%, 가장 넓은 지원 빠른 링크 HuggingFace Image Feature Extraction Models HuggingFace Zero-Shot Classification Models MTEB Leaderboard 인사이트 2021년 CLIP 발표 이후 4년간 생태계가 놀라울 정도로 성숙했다. OpenCLIP이 통합 허브 역할을 하면서 Meta, Apple, Google의 연구가 하나의 인터페이스로 수렴하고 있다. 모델 선택은 더 이상 \u0026ldquo;어떤 CLIP을 쓸까\u0026quot;가 아니라 \u0026ldquo;어떤 축을 최적화할까\u0026quot;의 문제가 되었다 — 정확도, 다국어, 모바일, 학습 가능성 각각에서 최적 모델이 다르다. MetaCLIP2의 다국어 상호 강화 발견은 한국어 이미지 검색에 직접 적용 가능한 인사이트이고, MobileCLIP2의 모바일 최적화는 향후 앱 배포 시 검토할 가치가 있다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-clip-ecosystem/cover.jpg","permalink":"/ko/posts/2026-03-25-clip-ecosystem/","title":"CLIP 모델 생태계 — OpenAI에서 MetaCLIP2, MobileCLIP2까지"},{"content":"개요 Hacker News에서 434포인트, 108개 댓글을 기록한 프로젝트를 분석했다. Gemini Embedding 2가 비디오를 직접 768차원 벡터에 임베딩할 수 있게 되면서, 기존의 전사(transcription) → 텍스트 임베딩 파이프라인이 불필요해졌다. 이 기술로 구현된 sub-second 비디오 검색 CLI와, HN 커뮤니티에서 벌어진 감시 사회(panopticon) 논쟁을 함께 다룬다. 이전 포스트 CLIP 모델 생태계와 이어지는 임베딩 시리즈다.\ngraph LR subgraph 기존[\"기존 파이프라인\"] A[\"비디오\"] --\u003e B[\"프레임 추출\"] B --\u003e C[\"캡셔닝/전사\"] C --\u003e D[\"텍스트 임베딩\"] end subgraph 신규[\"Gemini Embedding 2\"] E[\"비디오\"] --\u003e F[\"직접 768-dim 벡터\"] end F --\u003e G[\"ChromaDB\"] G --\u003e H[\"자연어 쿼리\u0026lt;br/\u0026gt;sub-second 검색\"] 비디오 직접 임베딩이란 기존 비디오 검색의 한계는 명확했다. 비디오에서 의미를 추출하려면 프레임을 캡셔닝하거나 오디오를 전사한 뒤 텍스트를 임베딩해야 했다. 이 과정에서 시각적 맥락이 손실되고, 파이프라인 복잡도가 증가하며, \u0026ldquo;green car cutting me off\u0026rdquo; 같은 시각적 쿼리에는 전사 기반으로는 답할 수 없었다.\nGemini Embedding 2는 이 중간 단계를 완전히 제거한다. 30초 비디오 클립을 텍스트 쿼리와 직접 비교 가능한 768차원 벡터로 변환한다. 전사도, 프레임 캡셔닝도, 중간 텍스트도 없다. 비디오와 텍스트가 같은 벡터 공간에 네이티브로 투영된다.\n구현: CLI 비디오 검색 도구 프로젝트 제작자 sohamrj가 구현한 CLI 도구의 아키텍처:\n인덱싱: 긴 영상을 청크로 분할 → Gemini Embedding 2로 각 청크 임베딩 → ChromaDB에 저장 검색: 자연어 쿼리를 같은 모델로 임베딩 → ChromaDB에서 벡터 유사도 검색 출력: 매칭된 클립을 자동 트리밍하여 반환 비용: 영상 1시간당 약 $2.50. still-frame 감지로 유휴 구간을 건너뛰기 때문에 보안 카메라나 Tesla 센트리 모드 영상은 훨씬 저렴하다.\nCLIP 기반 이미지 임베딩이 정적 이미지에 대해 해준 것을 Gemini가 동적 비디오에 대해 실현한 셈이다. CLIP 모델 생태계 포스트에서 다룬 이미지-텍스트 임베딩의 자연스러운 확장이다.\nHN 커뮤니티 토론: 감시 사회 논쟁 108개 댓글 중 기술 구현보다 사회적 함의에 대한 논의가 더 뜨거웠다.\n핵심 우려: Panopticon macNchz의 최상위 댓글이 핵심을 찔렀다:\n\u0026ldquo;우리는 카메라로 가득 찬 세계에 살고 있지만, 아무도 모든 영상을 실제로 볼 수 없다는 사실 덕분에 어느 정도의 반익명성을 유지하고 있다. 하지만 이 기술은 그 전제를 바꾼다.\u0026rdquo;\n카메라 소유자, 제조사, 정부가 자연어 파라미터로 특정 인물이나 활동에 대한 알림을 설정할 수 있게 되면 — 범죄 감지, 반려견 미수거 신고 같은 그럴듯한 사례로 시작해 — 결국 규제 없는 panopticon으로 이어질 수 있다는 우려다.\n이미 현실: Fusus 플랫폼 citruscomputing은 실제 시의회 미팅에서 목격한 사례를 공유했다. ALPR(자동 번호판 인식) 카메라 계약을 논의하는 자리에서, 카메라 벤더의 Fusus 플랫폼을 알게 되었다고 한다. 이 플랫폼은:\n다양한 카메라 시스템을 통합하는 대시보드 자연어로 비디오 피드를 쿼리하는 기능 민간 배포 카메라와의 연동 계획 시 예산으로 50대 ALPR만 배치했지만, 이웃의 카메라가 경찰의 AI 시스템에 직접 피딩되는 미래는 시간문제라는 지적이다.\n기술적 논의 기술 측면에서는:\n비용 효율성: $2.50/hr는 대규모 감시에는 아직 비싸지만, 가격 하락 추세를 고려하면 시간문제 정확도: 텍스트 기반 검색 대비 시각적 쿼리의 정확도 향상이 핵심 가치 ChromaDB vs 대안: 벡터 DB 선택에 대한 논의도 활발 임베딩 기술 비교 구분 CLIP (이미지) Gemini Embedding 2 (비디오) 입력 정적 이미지 동적 비디오 (30초 청크) 차원 512~1024 (모델별) 768 중간 단계 없음 (직접 임베딩) 없음 (직접 임베딩) 비용 무료 (로컬 실행) ~$2.50/hr (API) 오픈소스 OpenCLIP 등 다수 비공개 (API only) 인사이트 비디오 직접 임베딩은 텍스트 중간 단계를 제거한다는 점에서 기술적으로 깔끔한 진보다. 하지만 HN 토론이 보여주듯, 이 기술의 사회적 함의는 기술적 우아함을 훨씬 넘어선다. 모든 영상을 인덱싱하고 자연어로 검색할 수 있는 세상은 \u0026ldquo;할 수 있는가\u0026quot;의 문제가 아니라 \u0026ldquo;해야 하는가\u0026quot;의 문제다. Fusus 같은 플랫폼이 이미 경찰에 배포되고 있다는 사실은, 규제 논의가 기술 발전 속도를 따라가지 못하고 있음을 보여준다. hybrid-image-search 프로젝트에서도 비디오 검색 확장을 고려할 때 이러한 윤리적 지점을 함께 검토해야 할 것이다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-gemini-video-embedding/cover.jpg","permalink":"/ko/posts/2026-03-25-gemini-video-embedding/","title":"Gemini 비디오 임베딩 — 멀티모달 검색의 새 패러다임"},{"content":"개요 Get Shit Done(GSD)은 Claude Code, Gemini CLI, OpenCode, Codex, Copilot, Antigravity 등 주요 AI 코딩 도구에서 동작하는 메타 프롬프팅 시스템이다. GitHub 스타 40,799개를 기록하며, \u0026ldquo;context rot — 컨텍스트 윈도우가 채워질수록 발생하는 품질 저하\u0026quot;를 정면으로 해결한다. Amazon, Google, Shopify, Webflow 엔지니어들이 실전에서 사용한다고 알려져 있다.\nContext Rot이란 AI 코딩 에이전트와 긴 대화를 나눌수록 코드 품질이 떨어지는 현상이다. 컨텍스트 윈도우가 이전 대화로 채워지면서, 초반에는 정확했던 AI가 점점 같은 실수를 반복하고, 일관성 없는 코드를 생성한다.\ngraph TD A[\"세션 시작 \u0026lt;br/\u0026gt; 높은 품질\"] --\u003e B[\"컨텍스트 누적\"] B --\u003e C[\"Context Rot \u0026lt;br/\u0026gt; 품질 저하\"] C --\u003e D[\"GSD 개입 \u0026lt;br/\u0026gt; 스펙 기반 리셋\"] D --\u003e E[\"품질 복구\"] E --\u003e|\"다음 단계\"| BGSD의 핵심 주장은 이 문제가 LLM의 한계가 아니라 컨텍스트 엔지니어링의 부재라는 것이다.\nGSD의 핵심 메커니즘 스펙 기반 개발 GSD의 워크플로우는 세 단계로 구성된다:\n/gsd:new-project — 프로젝트 초기화\n목표, 제약 조건, 기술 선호도를 질문 정보가 충분해지면 \u0026ldquo;Ultra Spec\u0026rdquo; 생성 (스펙 문서) 페이즈별 구현 계획 자동 생성 /gsd:begin — 구현 시작\n스펙을 기반으로 단계별 작업 실행 각 단계 완료 시 체크포인트 생성 Context rot 발생 시 스펙에서 컨텍스트 복구 /gsd:continue — 중단 후 재개\n이전 상태를 스펙에서 읽어 복원 새 세션에서도 일관성 유지 기존 코드베이스 지원 /gsd:map-codebase 명령어로 기존 프로젝트를 분석한다. 병렬 에이전트가 스택, 아키텍처, 컨벤션, 관심사를 파악하고, 이후 /gsd:new-project에서 이 분석 결과를 활용한다.\ngraph LR A[\"기존 코드베이스\"] --\u003e|\"/gsd:map-codebase\"| B[\"병렬 분석 에이전트\"] B --\u003e C[\"스택 분석\"] B --\u003e D[\"아키텍처 분석\"] B --\u003e E[\"컨벤션 분석\"] C --\u003e F[\"Ultra Spec\"] D --\u003e F E --\u003e F F --\u003e|\"/gsd:begin\"| G[\"일관된 구현\"] 멀티 런타임 지원 GSD의 독특한 점은 특정 AI 코딩 도구에 종속되지 않는다는 것이다:\n런타임 설치 명령어 형식 Claude Code ~/.claude/ /gsd:help Gemini CLI ~/.gemini/ /gsd:help OpenCode ~/.config/opencode/ /gsd-help Codex ~/.codex/ (skills) $gsd-help Copilot ~/.github/ /gsd:help Antigravity ~/.gemini/antigravity/ /gsd:help 설치는 npx get-shit-done-cc@latest 한 줄로 완료되며, 인터랙티브 프롬프트에서 런타임과 설치 위치를 선택한다.\n유사 도구와의 비교 GSD의 창시자 TÂCHES는 BMAD, Speckit, Taskmaster 등 기존 스펙 기반 도구를 직접 사용해본 뒤 불만을 느끼고 GSD를 만들었다고 밝힌다.\n특성 GSD BMAD/Speckit 철학 최소 워크플로우 엔터프라이즈 프로세스 복잡도 3개 핵심 명령어 스프린트, 스토리 포인트, 회고 대상 솔로 개발자/소규모 팀 팀/조직 Context rot 스펙 기반 자동 복구 명시적 해결책 없음 GSD의 슬로건인 \u0026ldquo;The complexity is in the system, not in your workflow\u0026quot;가 이 차이를 요약한다. 사용자에게 보이는 워크플로우는 단순하지만, 내부적으로 XML 프롬프트 포매팅, 서브에이전트 오케스트레이션, 상태 관리가 동작한다.\n인사이트 GSD는 바이브 코딩의 근본적인 문제 — context rot — 에 대한 실용적인 해결책이다. 단순히 \u0026ldquo;좋은 프롬프트를 쓰세요\u0026quot;가 아니라, 스펙 문서라는 영구 저장소를 두고 컨텍스트를 주기적으로 리셋하는 구조적 접근이다. 40K 스타라는 수치는 이 문제가 얼마나 보편적인지 보여준다. Claude Code의 CLAUDE.md, Plan 모드, Memory 시스템도 같은 문제를 다루지만, GSD는 이를 하나의 통합 워크플로우로 묶었다는 점에서 차별화된다. 런타임 불가지론적 설계 덕분에 Claude Code를 쓰다가 Gemini CLI로 전환해도 같은 스펙을 공유할 수 있다는 점도 실전에서 유용하다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-get-shit-done/cover.jpg","permalink":"/ko/posts/2026-03-25-get-shit-done/","title":"Get Shit Done — Context Rot 문제를 해결하는 메타 프롬프팅 시스템"},{"content":"개요 Google AI Studio가 프롬프트만으로 배포 가능한 풀스택 앱을 만드는 \u0026ldquo;바이브 코딩\u0026rdquo; 경험을 대폭 강화했다. 핵심은 Antigravity 코딩 에이전트와 Firebase 통합이다. 실시간 멀티플레이, DB, 인증, 외부 API 연동, 시크릿 관리, 세션 저장까지 한 흐름에서 처리한다. TILNOTE 정리를 기반으로 핵심 기능과 활용 전략을 분석한다.\nAntigravity 에이전트: 더 긴 기억, 더 큰 수정 Antigravity는 Google AI Studio에 내장된 코딩 에이전트다. 기존 AI Studio의 코드 생성과 달리, 프로젝트 구조와 대화 맥락을 더 깊게 유지한다.\ngraph TD A[\"프롬프트\"] --\u003e B[\"Antigravity Agent\"] B --\u003e C[\"프로젝트 구조 이해\"] B --\u003e D[\"대화 맥락 유지\"] C --\u003e E[\"멀티 파일 수정\"] D --\u003e E E --\u003e F[\"빌드 / 미리보기\"] F --\u003e|\"추가 지시\"| B\u0026ldquo;이 기능 추가해줘\u0026rdquo; 같은 짧은 지시로도 여러 파일에 걸친 수정과 연쇄 작업을 정확히 수행한다. 코드를 \u0026ldquo;조각조각 수선\u0026quot;하는 것이 아니라, 앱 전체를 이해하는 편집자로서 반복 개선 속도를 높인다.\nFirebase 내장 통합 앱이 데이터를 저장하거나 사용자 계정이 필요해지는 순간을 에이전트가 먼저 감지한다. 사용자가 승인하면 Firebase를 연결해 백엔드를 구성한다.\n제공 서비스 서비스 용도 Cloud Firestore 데이터 저장 (NoSQL) Firebase Authentication 로그인 (Google OAuth 등) Realtime Database 실시간 동기화 핵심은 개발자가 Firebase 콘솔에서 수동으로 프로젝트를 생성하고 SDK를 연결하는 과정을 에이전트가 자동으로 처리한다는 점이다.\n실시간 멀티플레이와 협업 이번 업데이트의 야심작은 동시 접속과 실시간 동기화가 필요한 앱을 만들 수 있게 한 것이다.\ngraph LR A[\"사용자 A\"] --\u003e B[\"Firebase \u0026lt;br/\u0026gt; Realtime DB\"] C[\"사용자 B\"] --\u003e B D[\"사용자 C\"] --\u003e B B --\u003e E[\"실시간 동기화\"] E --\u003e A E --\u003e C E --\u003e D공식 예시로 제시된 앱들:\n실시간 멀티플레이 레이저 태그 3D 파티클 기반 협업 공간 물리 기반 3D 게임 (클로 머신) Google Maps 연동 유틸리티 레시피 생성 및 가족/친구 협업 앱 공통점은 화면(UI)만 그럴듯한 것이 아니라, 동기화·데이터·연동·인증 중 최소 하나 이상이 들어간 \u0026ldquo;진짜 앱\u0026rdquo; 형태라는 점이다.\n외부 서비스 연동과 Secrets Manager 지도, 결제, 외부 DB 같은 실제 서비스와 연결하려면 API 키가 필수다. Antigravity는 키가 필요한 시점을 감지하고, Settings 탭의 Secrets Manager에 안전하게 보관하도록 안내한다.\n코드에 API 키를 하드코딩하는 실수를 구조적으로 방지하며, 운영 환경에 가까운 형태로 연동을 진행할 수 있다.\n프레임워크 지원 React, Angular에 더해 Next.js가 기본 지원되었다. Settings 패널에서 프레임워크를 선택하는 흐름으로, 라우팅/서버 렌더링/풀스택 패턴을 활용하는 앱으로 자연스럽게 확장할 수 있다.\n프레임워크 선택 기준:\nReact: 빠른 UI 실험, 클라이언트 중심 앱 Angular: 대규모 엔터프라이즈 앱, 구조화된 프로젝트 Next.js: SEO, 서버 기능, 풀스택 패턴이 중요한 앱 Claude Code와의 비교 특성 Google AI Studio + Antigravity Claude Code 환경 웹 브라우저 터미널 CLI 백엔드 통합 Firebase 자동 연결 수동 설정 배포 Firebase Hosting 원클릭 수동 또는 스크립트 멀티플레이 Realtime DB 내장 직접 구현 필요 코드 접근 웹 에디터 내 전체 파일 시스템 유연성 프레임워크 제한적 모든 스택 가능 심화 작업 프로토타입 수준 프로덕션 수준 활용 전략 이 업데이트를 효과적으로 활용하려면:\n운영 조건을 프롬프트에 포함: \u0026ldquo;사용자 여러 명이 동시에 쓰고, 로그인 후 내 데이터가 저장되며, 외부 서비스와 연결된다\u0026rdquo; Firebase 통합을 일찍 승인: 구조를 먼저 잡으면 시행착오 감소 Secrets Manager 기본 사용: API 키 하드코딩 방지 프레임워크 선택: SEO/서버 기능 → Next.js, 빠른 실험 → React 인사이트 Google AI Studio의 이번 업데이트는 \u0026ldquo;프롬프트 → 프로덕션\u0026quot;의 간극을 좁히는 방향으로 진화하고 있다. Firebase 통합으로 백엔드 설정의 마찰을 제거하고, Antigravity 에이전트의 긴 컨텍스트 유지로 반복 개선 속도를 높였다. Claude Code가 전문 개발자를 위한 도구라면, AI Studio는 \u0026ldquo;앱 아이디어가 있지만 인프라 설정이 장벽인\u0026rdquo; 사용자를 위한 도구로 포지셔닝된다. 두 도구를 조합하면 — AI Studio로 빠르게 프로토타입을 만들고, Claude Code로 프로덕션 수준으로 정제하는 — 효과적인 개발 파이프라인이 가능하다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-google-ai-studio-antigravity/cover.jpg","permalink":"/ko/posts/2026-03-25-google-ai-studio-antigravity/","title":"Google AI Studio 풀스택 바이브 코딩 — Antigravity 에이전트와 Firebase 통합"},{"content":"개요 이전 글: #2 — Marketplace-First 전환과 v2a/v2b 설계 및 구현\n이번 #3에서는 12개 커밋에 걸쳐 두 가지 핵심 작업을 진행했다. 첫째, 플러그인이 올바르게 트리거되는지 전체 검토하고 5개 수정 사항을 적용했다. 둘째, 마켓플레이스 플러그인 추천 시스템을 검증 기반으로 재설계하고, 도구 시퀀스를 3단계 슬라이딩 윈도우로 업그레이드했다.\n플러그인 트리거 전체 검토 문제 진단 plugin.json의 스킬 정의, hooks 실행 경로, 스킬 파일 내부 로직을 종합 검토한 결과, 5개의 트리거링 문제를 발견했다.\ngraph TD A[\"트리거 검토\"] --\u003e B[\"CRITICAL \u0026lt;br/\u0026gt; 경로 참조 오류\"] A --\u003e C[\"MAJOR \u0026lt;br/\u0026gt; 환경 변수 불일치\"] A --\u003e D[\"MINOR \u0026lt;br/\u0026gt; 기능 누락\"] B --\u003e E[\"CLAUDE_PLUGIN_ROOT \u0026lt;br/\u0026gt; 통일\"] C --\u003e F[\"preset 체크 \u0026lt;br/\u0026gt; 추가\"] D --\u003e G[\"status에 \u0026lt;br/\u0026gt; 설치 검증 추가\"]핵심 수정 1: CLAUDE_PLUGIN_ROOT 통일 스킬과 hooks에서 플러그인 디렉토리를 참조하는 방식이 제각각이었다. claude plugin path 명령어, 하드코딩된 경로, 상대 경로 등이 혼재했다. 이를 CLAUDE_PLUGIN_ROOT 환경 변수로 통일하고, dirname 기반 fallback을 추가했다.\n# Before: 다양한 참조 방식 혼재 PLUGIN_DIR=\u0026#34;$(claude plugin path harnesskit)\u0026#34; PLUGIN_DIR=\u0026#34;/Users/lsr/.claude/plugins/cache/harnesskit/...\u0026#34; # After: 통일된 참조 PLUGIN_DIR=\u0026#34;${CLAUDE_PLUGIN_ROOT:-$(cd \u0026#34;$(dirname \u0026#34;$0\u0026#34;)/..\u0026#34; \u0026amp;\u0026amp; pwd)}\u0026#34; 핵심 수정 2: post-edit hooks에 preset 체크 추가 post-edit-lint.sh와 post-edit-typecheck.sh가 preset 설정 전에도 실행되어 오류가 발생했다. preset 존재 여부를 체크하고, 미설정 시 건너뛰도록 수정했다.\n마켓플레이스 검증 추천 시스템 기존 문제 /harnesskit:init에서 마켓플레이스 플러그인을 추천할 때, 실시간 검색에 의존해 불안정하고 결과가 일관되지 않았다.\n해결: 사전 검증된 추천 목록 marketplace-recommendations.json 파일에 검증된 플러그인 목록을 유지하고, update-recommendations.sh 스크립트로 주기적으로 크롤링/갱신하도록 변경했다.\ngraph LR A[\"update-recommendations.sh\"] --\u003e|\"크롤링\"| B[\"Marketplace\"] B --\u003e C[\"검증 / 필터링\"] C --\u003e D[\"marketplace-recommendations.json\"] D --\u003e|\"/harnesskit:init\"| E[\"사용자에게 추천\"]/harnesskit:insights에서도 recommendations.json을 참조해 개선 제안을 할 때 검증된 플러그인만 추천하도록 연동했다.\n3단계 슬라이딩 윈도우 도구 시퀀스 도구 사용 패턴 분석의 정밀도를 높이기 위해 기존 단순 카운트 방식에서 3단계 슬라이딩 윈도우로 업그레이드했다. tool:summary 형식으로 도구 사용 시퀀스를 기록하고, 패턴을 감지해 개선을 제안한다.\n플러그인 설치 검증 /harnesskit:status 스킬에 플러그인 설치 상태를 검증하는 기능을 추가했다. 스킬 파일 존재 여부, hooks 실행 권한, 설정 파일 무결성을 한눈에 확인할 수 있다.\n커밋 로그 메시지 변경 feat: add plugin installation verification to status skills feat: upgrade tool sequence to 3-step sliding window skills feat: add recommendations.json reference to insights skills feat: rewrite init marketplace discovery with verified recs skills feat: add update-recommendations.sh for marketplace crawling scripts feat: add verified marketplace-recommendations.json templates refactor: migrate skills from \u0026lsquo;claude plugin path\u0026rsquo; to CLAUDE_PLUGIN_ROOT skills refactor: unify PLUGIN_DIR to CLAUDE_PLUGIN_ROOT with fallback hooks fix: add preset check to post-edit hooks + CLAUDE_PLUGIN_ROOT fallback hooks docs: add implementation plan for plugin trigger fixes docs docs: address spec review — fix CRITICAL and MAJOR issues docs docs: add spec for plugin trigger review — 5 fixes docs 인사이트 플러그인 개발에서 \u0026ldquo;동작하는 것\u0026quot;과 \u0026ldquo;올바르게 트리거되는 것\u0026quot;은 다른 문제다. 로컬 개발 환경에서는 경로가 고정되어 있어 문제가 없지만, 다른 사용자의 환경에서는 플러그인 캐시 경로, 환경 변수, preset 상태가 모두 다르다. CLAUDE_PLUGIN_ROOT 하나로 통일한 것은 작은 변경이지만, 플러그인의 이식성을 근본적으로 개선했다. 마켓플레이스 추천을 실시간 검색에서 사전 검증 목록으로 전환한 것도 같은 맥락이다 — 불확실성을 줄이고 일관된 경험을 보장하는 방향이다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-harnesskit-dev3/cover.jpg","permalink":"/ko/posts/2026-03-25-harnesskit-dev3/","title":"HarnessKit 개발기 #3 — 플러그인 트리거 수정과 마켓플레이스 추천 시스템"},{"content":"개요 이전 글: #4 — 라우터 분리, Terraform Dev 서버, Inpaint 에디터\n이번 #5에서는 13개 커밋에 걸쳐 세 가지 작업 스트림을 진행했다. 첫째, Inpaint 에디터의 UX를 개선하고 메인 페이지에서 바로 접근 가능하게 만들었다. 둘째, EC2 Dev 서버에 Google OAuth를 연동하고 이미지 로딩 문제를 해결했다. 셋째, 이미지 생성의 중복 방지와 모달 닫기 등 전반적인 안정성을 강화했다.\nInpaint 에디터 UX 개선 카드 호버에서 Inpaint 진입 기존에는 이미지 상세 페이지에서만 Inpaint를 사용할 수 있었다. 이번에 메인 페이지 카드에 호버 시 \u0026ldquo;Edit\u0026rdquo; 버튼을 추가하고, 클릭하면 바로 Inpaint 에디터가 열리도록 개선했다.\ngraph LR A[\"메인 페이지 \u0026lt;br/\u0026gt; 카드 호버\"] --\u003e|\"Edit 버튼\"| B[\"Inpaint 에디터\"] C[\"상세 페이지\"] --\u003e|\"Edit 버튼\"| B B --\u003e D[\"스켈레톤 로딩\"] D --\u003e E[\"생성된 이미지\"]스켈레톤 로딩 카드 Inpaint 생성 중 메인 페이지에 스켈레톤 로딩 카드를 표시해, 생성 진행 상황을 시각적으로 확인할 수 있게 했다.\nUndo 히스토리 수정 Inpaint 에디터에서 stroke 시작 전에 saveHistory()를 호출하도록 수정했다. 기존에는 stroke 완료 후에 저장해서, undo 시 이전 상태가 아닌 현재 상태가 복원되는 버그가 있었다.\nEC2 Dev 서버 배포 Google OAuth 연동 Dev 서버에 처음 접속했을 때 로그인이 안 되는 문제가 있었다. 원인은 두 가지:\nVITE_GOOGLE_CLIENT_ID 미설정 — Vite의 환경 변수는 빌드 타임에 인라인되므로, EC2에서 빌드 시 .env에 설정되어 있어야 한다 GCP OAuth 승인된 출처 미등록 — EC2의 URL(http://ec2-xxx.compute.amazonaws.com:5173)을 GCP 콘솔의 승인된 JavaScript 출처에 추가해야 한다 이미지 표시 문제 서버에서 검색과 리랭킹은 정상 동작하지만 이미지가 404로 표시되는 문제가 있었다. 원인은 README의 \u0026ldquo;데이터 준비\u0026rdquo; 단계를 건너뛴 것 — 이미지 파일이 split zip으로 저장되어 있어 압축 해제가 필요했다.\n추가로 fix: add recursive image search for nested directory structures — 디렉토리 구조가 중첩된 경우에도 이미지를 찾을 수 있도록 수정했다.\n생성 안정성 강화 중복 생성 방지 Enter 키를 빠르게 연타하면 이미지가 2개 생성되는 버그를 수정했다. handleGenerate 진입 시 generatingCount \u0026gt; 0이면 즉시 리턴하는 가드를 추가했다. 이후 더 근본적인 해결을 위해 lock 대신 500ms debounce로 전환했다.\nESC 키로 모달 닫기 모든 modal/popup 컴포넌트에 ESC 키 이벤트를 추가했다.\n톤/앵글 참조 프롬프트 강화 자동 주입 시스템에서 톤/앵글이 의도치 않게 생성 결과에 영향을 주는 문제를 수정했다. 참조 프롬프트를 강화해 톤/앵글이 순수한 메타데이터로만 사용되도록 했다.\naspect_ratio 유효성 검증 Gemini edit API에 전달하기 전에 aspect_ratio 값을 검증하고, 재생성(regeneration)과 inpaint 간에 aspect_ratio와 resolution이 보존되도록 수정했다.\n클립보드 폴백 상세 페이지의 프롬프트 복사 버튼이 일부 환경에서 동작하지 않는 문제를 수정했다. navigator.clipboard.writeText()이 실패할 경우 execCommand('copy') 폴백을 추가했다.\nML 모델 백그라운드 로딩 서버 시작 시 ML 모델 로딩이 완료될 때까지 로그인 페이지가 응답하지 않는 문제를 수정했다. 모델 로딩을 백그라운드 태스크로 전환해 서버 시작 즉시 로그인이 가능하도록 개선했다.\n커밋 로그 메시지 변경 fix: add clipboard fallback for prompt copy button FE fix: strengthen tone/angle reference prompt BE fix: validate aspect_ratio before Gemini edit API BE fix: preserve aspect_ratio and resolution across regen/inpaint BE+FE feat: show skeleton loading cards during inpaint generation FE feat: add inpaint edit button to card hover FE fix: replace generation lock with 500ms debounce FE fix: load ML models in background so login works during startup BE feat: add ESC key to close all modal/popup components FE fix: prevent duplicate image generation on rapid Enter FE fix: add recursive image search for nested directories BE add allowed host BE fix: save undo history before stroke begins in InpaintEditor FE 인사이트 이번 스프린트는 \u0026ldquo;만든 기능을 실제 환경에서 안정적으로 동작하게 만드는\u0026rdquo; 작업이 중심이었다. Inpaint 에디터를 로컬에서 만들고 EC2에 배포하니 예상치 못한 문제(OAuth, 이미지 경로, 환경 변수)가 줄줄이 나왔다. 특히 Vite의 빌드 타임 환경 변수(import.meta.env.*)는 서버 배포 시 반드시 빌드 전에 설정되어야 한다는 점을 다시 확인했다. 중복 생성 방지를 lock에서 debounce로 전환한 것은 UX 관점에서 더 자연스러운 해결이었다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-hybrid-search-dev5/cover.jpg","permalink":"/ko/posts/2026-03-25-hybrid-search-dev5/","title":"Hybrid Image Search 개발기 #5 — Inpaint UX 개선, Dev 서버 배포, 안정성 강화"},{"content":"개요 LLM 기반 주식 트레이딩 에이전트가 2025~2026년 사이 폭발적으로 성장하고 있다. 단순 감성 분석을 넘어, 멀티 에이전트 아키텍처로 트레이딩 펌 전체를 시뮬레이션하거나, 강화학습(RL)과 결합해 실시간 리스크 관리까지 수행하는 단계에 이르렀다. 이 글에서는 주요 오픈소스 프레임워크 4종과 학술 논문 3편을 분석하고, 실제 트레이딩 에이전트를 개발하는 관점에서 어떤 인사이트를 얻을 수 있는지 정리한다.\nTradingAgents — 트레이딩 펌을 LLM으로 시뮬레이션하다 TradingAgents는 UCLA와 MIT 연구팀이 개발한 멀티 에이전트 트레이딩 프레임워크다. GitHub 스타 40,795개를 기록하며, LLM 트레이딩 분야에서 가장 큰 커뮤니티를 보유하고 있다.\n아키텍처: 트레이딩 펌의 조직 구조를 그대로 재현 TradingAgents의 핵심 아이디어는 실제 트레이딩 회사의 역할 분담을 LLM 에이전트로 구현하는 것이다.\ngraph TD A[\"Market Data\"] --\u003e B[\"Analyst Team\"] B --\u003e C[\"Fundamental Analyst\"] B --\u003e D[\"Sentiment Analyst\"] B --\u003e E[\"Technical Analyst\"] C --\u003e F[\"Researcher Team\"] D --\u003e F E --\u003e F F --\u003e G[\"Bull Researcher\"] F --\u003e H[\"Bear Researcher\"] G --\u003e I[\"Debate \u0026lt;br/\u0026gt; Protocol\"] H --\u003e I I --\u003e J[\"Trader Agents\"] J --\u003e K[\"Risk Management Team\"] K --\u003e L[\"Final Decision\"] Analyst Team: 펀더멘탈, 감성, 기술 분석을 각각 전담하는 에이전트 Researcher Team: Bull/Bear 관점에서 시장 상황을 평가하고 토론 Trader Agents: 다양한 위험 선호도를 가진 트레이더 에이전트 Risk Management Team: 포지션 노출을 감시하고 최종 의사결정 실험 결과 백테스팅에서 기존 기준 모델 대비 누적 수익률, 샤프 비율, 최대 낙폭 모두에서 유의미한 개선을 보였다. 특히 Bull/Bear 토론 프로토콜이 단일 의견 에이전트 대비 더 균형 잡힌 판단을 이끌어낸다는 점이 주목할 만하다.\n기술 스택 Python 기반 229K 라인 규모로, v0.2.2까지 진화했다. 최근 커밋에서는 5단계 등급 체계 표준화, 포트폴리오 매니저 리팩토링, 거래소 수식 티커 보존 등의 개선이 이루어졌다.\nPrimoAgent — 멀티 에이전트 주식 분석 PrimoAgent는 멀티 에이전트 아키텍처를 주식 분석에 적용한 프레임워크다. TradingAgents가 트레이딩 실행까지 포괄하는 반면, PrimoAgent는 분석 파이프라인에 집중한다.\n각 에이전트가 서로 다른 분석 영역(재무제표, 뉴스 감성, 기술적 지표)을 담당하고, 최종 분석 보고서를 통합 생성하는 구조다. 소규모 팀이나 개인 투자자가 기관 수준의 리서치 프로세스를 자동화하려는 용도에 적합하다.\nAlpacaTradingAgent — LLM 금융 트레이딩 에이전트 AlpacaTradingAgent는 Alpaca Markets API와 LLM을 결합한 자동 트레이딩 시스템이다. 실제 주식 매매를 수행할 수 있다는 점에서 백테스팅에 머무는 학술 프레임워크와 차별화된다.\nAlpaca의 페이퍼 트레이딩 API를 통해 실제 시장 데이터로 위험 없이 전략을 검증한 뒤, 실전 매매로 전환할 수 있는 파이프라인을 제공한다.\nstock-analysis-agent — 한국 주식 리서치 자동화 stock-analysis-agent는 Claude Code를 활용해 한국 및 미국 주식에 대한 기관급 리서치를 자동화하는 오픈소스 프로젝트다. 한국 시장 특유의 데이터 소스(DART 전자공시, 네이버 금융 등)를 지원한다는 점이 핵심이다.\n기존 분석 글에서 다룬 바와 같이, 이 프로젝트는 한국 주식 시장의 데이터 접근성 문제를 LLM + MCP 아키텍처로 해결하려는 시도다.\nStockBench — LLM 에이전트는 실제로 수익을 낼 수 있는가? 칭화대학교 연구팀이 발표한 StockBench는 \u0026ldquo;LLM 에이전트가 실제 시장에서 수익성 있게 거래할 수 있는가?\u0026ldquo;라는 질문에 정면으로 답하는 벤치마크다.\n벤치마크 설계 StockBench는 실제 시장 데이터를 사용한 백트레이딩 환경을 구축하고, 표준화된 에이전트 워크플로우를 정의한다.\ngraph LR A[\"시장 데이터 수집\"] --\u003e B[\"LLM 분석\"] B --\u003e C[\"매매 결정\"] C --\u003e D[\"주문 실행\"] D --\u003e E[\"포트폴리오 평가\"] E --\u003e F[\"성과 측정\"] F --\u003e|\"다음 거래일\"| A주요 발견 투자 대상 규모의 영향: 종목 수가 많아질수록 LLM 에이전트의 성과가 저하되는 경향 워크플로우 오류 분석: 매매 결정 과정에서 발생하는 오류 유형 분류 데이터 소스 기여도: 어떤 데이터 소스가 수익률에 가장 큰 영향을 미치는지 ablation study 이 벤치마크는 LLM 트레이딩 에이전트의 실전 적용 가능성을 냉정하게 평가한다는 점에서 중요하다. \u0026ldquo;LLM이 주식으로 돈을 벌 수 있다\u0026quot;는 주장에 대한 과학적 검증 도구로 기능한다.\nLLM + 강화학습: 최신 논문 3편 분석 AI for Life 블로그에서 정리한 2025년 주요 LLM+RL 트레이딩 논문 3편을 분석한다.\n1. FinRL-DeepSeek: LLM 기반 리스크 인식 RL 하이브리드 트레이딩 에이전트로, 딥 RL에 LLM의 뉴스 분석 신호를 결합한다. CVaR-Proximal Policy Optimization(CPPO) 알고리즘을 확장해 매일 LLM이 생성한 투자 추천과 리스크 평가 점수를 RL 에이전트에 주입한다.\n핵심은 단순 감성 분석을 넘어, DeepSeek V3, Qwen-2.5, Llama 3.3 등 LLM을 프롬프팅해 뉴스에서 미묘한 리스크/수익 인사이트를 추출하는 것이다. Nasdaq-100 지수에 대한 1999~2023년 백테스트에서 리스크 관리 성능이 크게 향상되었다.\n2. FLAG-Trader: LLM과 Gradient RL의 융합 LLM의 언어 이해 능력과 RL의 연속 의사결정 능력을 gradient 수준에서 통합하는 접근법이다. LLM이 시장 텍스트 데이터를 처리하고, RL 에이전트가 이를 기반으로 매매를 학습한다.\n3. Stock-Evol-Instruct: LLM 가이드 RL 트레이딩 LLM이 생성한 진화적 명령어(evolutionary instructions)로 RL 에이전트의 학습을 가이드하는 방식이다. 전통적 RL의 보상 설계 어려움을 LLM의 자연어 피드백으로 우회한다.\ngraph TD A[\"3대 LLM+RL 접근법\"] --\u003e B[\"FinRL-DeepSeek\"] A --\u003e C[\"FLAG-Trader\"] A --\u003e D[\"Stock-Evol-Instruct\"] B --\u003e E[\"LLM 신호 → RL 입력 \u0026lt;br/\u0026gt; 리스크 인식 CPPO\"] C --\u003e F[\"Gradient 수준 통합 \u0026lt;br/\u0026gt; 언어+의사결정 융합\"] D --\u003e G[\"LLM 명령어 → RL 가이드 \u0026lt;br/\u0026gt; 진화적 학습\"] 자체 프로젝트와의 연결 현재 개발 중인 trading-agent 프로젝트와 비교하면:\n특성 TradingAgents 자체 trading-agent 시장 미국 주식 한국 주식 (KIS API) 에이전트 수 10+ (분석+트레이딩+리스크) 6 (뉴스/매크로 포함) 데이터 소스 Yahoo Finance, Reddit DART, 네이버, KIS 실행 백테스팅 중심 실매매 지원 (MCP) UI CLI React 대시보드 TradingAgents의 Bull/Bear 토론 프로토콜과 StockBench의 벤치마킹 방법론은 자체 프로젝트에도 적용할 가치가 있다. 특히 리스크 관리 팀 에이전트 패턴과 DCF/PER 기반 밸류에이션 비교는 현재 구현 중인 기능과 직접 연결된다.\n인사이트 LLM 트레이딩 에이전트 생태계의 현재 상황은 \u0026ldquo;멀티 에이전트 = 트레이딩 펌 시뮬레이션\u0026quot;이라는 공식이 표준으로 자리잡고 있음을 보여준다. 단일 LLM이 모든 분석과 결정을 내리는 시대는 끝났고, 역할별 전문화된 에이전트가 토론하고 합의하는 구조가 일관되게 더 나은 성과를 보인다.\n학술 연구 쪽에서는 LLM+RL 하이브리드가 주류가 되고 있다. LLM의 텍스트 이해와 RL의 시퀀셜 결정을 결합하면, 순수 LLM이나 순수 RL보다 리스크 조정 수익률이 높아진다는 실증이 쌓이고 있다.\nStockBench 같은 벤치마크의 등장은 이 분야가 \u0026ldquo;데모 수준\u0026quot;에서 \u0026ldquo;과학적 검증 가능한 수준\u0026quot;으로 성숙하고 있다는 신호다. 자체 트레이딩 에이전트 개발에서도 TradingAgents의 조직 구조 패턴, StockBench의 평가 프레임워크, FinRL-DeepSeek의 리스크 관리 방법론을 참고하여 한국 시장에 맞게 적용할 수 있을 것이다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-llm-trading-agents-ecosystem/cover.jpg","permalink":"/ko/posts/2026-03-25-llm-trading-agents-ecosystem/","title":"LLM 트레이딩 에이전트 생태계 총정리 — TradingAgents, StockBench, FinRL-DeepSeek"},{"content":"개요 이전 글: #3 — 스킬에서 플러그인으로의 전환\n이번 #4에서는 2개 커밋으로 log-blog 플러그인을 Claude Code 공식 마켓플레이스에 등록하기 위한 준비 작업을 진행했다. README를 공식 플러그인 형식에 맞춰 재작성하고, LICENSE 파일 추가 및 개인 정보 제거 작업을 완료했다.\n공식 마켓플레이스 등록 요건 Claude Code 공식 마켓플레이스(anthropics/claude-plugins-official)에 플러그인을 등록하려면 몇 가지 요건을 충족해야 한다.\ngraph TD A[\"플러그인 개발 완료\"] --\u003e B[\"README 형식 통일\"] B --\u003e C[\"LICENSE 파일 추가\"] C --\u003e D[\"개인 정보 제거\"] D --\u003e E[\"marketplace.json 작성\"] E --\u003e F[\"PR 제출\"]README 재작성 기존 README는 개발 노트 성격이 강했다. 공식 플러그인 README 형식에 맞춰 다음 구조로 재작성했다:\nOverview: 플러그인이 무엇을 하는지 한 문장 설명 Skills: 사용 가능한 스킬 목록과 설명 Installation: 설치 방법 CLI Usage: CLI 명령어 가이드 Requirements: 필수 의존성 Troubleshooting: 자주 발생하는 문제 해결 LICENSE 파일 추가 MIT 라이선스를 추가했다. 마켓플레이스 등록 시 라이선스가 명시되어 있어야 한다.\n개인 정보 제거 plugin.json의 author 필드와 기타 설정에서 개인 이메일 등의 정보를 정리했다. 공개 배포 시 불필요한 개인 정보가 노출되지 않도록 했다.\n커밋 로그 메시지 변경 docs: rewrite README to match official Claude Code plugin format docs fix: add LICENSE file, unify author, remove personal info for marketplace review config 인사이트 플러그인 개발의 마지막 마일은 코드가 아니라 패키징이다. 기능이 완벽해도 README가 불친절하거나 라이선스가 없으면 마켓플레이스 심사를 통과할 수 없다. 이번 작업은 규모는 작지만, .claude/skills/ 디렉토리의 로컬 스킬에서 시작해 공식 마켓플레이스에 등록 가능한 플러그인으로 진화하는 여정의 마지막 단계다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-log-blog-dev4/cover.jpg","permalink":"/ko/posts/2026-03-25-log-blog-dev4/","title":"Log-Blog 개발기 #4 — 공식 마켓플레이스 등록 준비"},{"content":"개요 이전 글: #5 — Backend 안정화와 데이터 파이프라인 개선\n이번 #6에서는 35개 커밋에 걸쳐 세 가지 큰 작업 스트림을 진행했다. 첫째, 6번째 전문가(뉴스/매크로 분석가)를 시그널 파이프라인에 추가하고 DART 기반 분석을 대폭 강화했다. 둘째, DCF 밸류에이션, 포트폴리오 리스크, 시그널 히스토리 등 심화 분석 기능을 구현했다. 셋째, 프론트엔드에 ScheduleManager, SignalDetailModal, 투자 메모 내보내기 등 대규모 UI 확장을 진행했다.\n시그널 파이프라인 확장 뉴스/매크로 분석가 — 6번째 전문가 기존 5인 전문가 체제(기술, 펀더멘탈, 감성, 수급, 리스크)에 뉴스/매크로 분석가를 추가했다. Google News RSS를 fallback으로 활용해 뉴스 수집의 안정성을 높였다.\ngraph TD A[\"시그널 파이프라인\"] --\u003e B[\"기술 분석가\"] A --\u003e C[\"펀더멘탈 분석가\"] A --\u003e D[\"감성 분석가\"] A --\u003e E[\"수급 분석가\"] A --\u003e F[\"리스크 분석가\"] A --\u003e G[\"뉴스/매크로 분석가\"] G --\u003e H[\"Google News RSS\"] G --\u003e I[\"DART 공시\"] B --\u003e J[\"종합 시그널\"] C --\u003e J D --\u003e J E --\u003e J F --\u003e J G --\u003e JDART 데이터 대폭 강화 DART 전자공시 시스템에서 가져오는 데이터를 크게 확장했다:\n내부자 거래 데이터 (feat: add DART insider trading data) — 임원 매수/매도 동향 외국인/기관 투자자 동향 (feat: add foreign/institutional investor trend) — 수급 흐름 분석 촉매 캘린더 (feat: add catalyst calendar with DART disclosures) — 실적 발표, 공시 일정을 타임라인 UI로 시각화 피어 비교 (feat: add peer comparison with sector-based DART valuation) — 동종 업계 밸류에이션 비교 8개 신규 DB 테이블 새로운 분석 기능을 지원하기 위해 8개 테이블과 ANALYST 역할, 메타데이터 초기화를 한 번에 추가했다.\n심화 분석 기능 DCF 밸류에이션 현금흐름할인법(DCF) 밸류에이션 모듈을 구현했다. 민감도 테이블과 히트맵을 포함해 WACC/성장률 변화에 따른 적정 주가 범위를 시각화한다.\n# DCF sensitivity heatmap 핵심 로직 for wacc in wacc_range: for growth in growth_range: intrinsic_value = calculate_dcf(fcf, wacc, growth, terminal_growth) heatmap[wacc][growth] = intrinsic_value 포트폴리오 리스크 분석 실제 포트폴리오 데이터를 기반으로 VaR(Value at Risk), 베타, 섹터 집중도를 계산한다. 상관관계 매트릭스 히트맵으로 포지션 간 상관성을 시각화한다.\nVaR 계산: Historical simulation 방식으로 95%/99% 신뢰구간의 최대 손실 추정 베타: KOSPI200 대비 포트폴리오 베타 계산 섹터 집중도: NAVER Finance에서 KOSPI200 종목별 섹터 데이터를 수집해 섹터 분포 분석 시그널 히스토리 스냅샷 시그널을 시점별로 저장하고, 과거 시그널과 비교할 수 있는 타임라인 기능을 추가했다.\n프론트엔드 대규모 확장 ScheduleManager 크론 편집과 즉시 실행(run-now) 버튼을 포함하는 스케줄 관리 컴포넌트를 구현했다. 에이전트 이름과 친근한 태스크 레이블 표시, 크론 시간(시:분) 기준 정렬 기능을 포함한다.\nSignalDetailModal 시그널을 클릭하면 관련 주문 내역까지 드릴다운할 수 있는 상세 모달을 추가했다. 전문가 의견 확장, risk_notes 표시, compact/expanded 뷰 토글도 함께 구현했다.\n투자 메모 내보내기 시그널 데이터를 기반으로 HTML 및 DOCX 형식의 투자 메모를 생성하는 기능을 추가했다. python-docx를 사용해 Word 문서 형식으로 내보낼 수 있다.\n기타 UI 개선 컴포넌트 변경 OrderHistory fill_price, order_type, 시그널 링크 표시 PositionsTable market_value 컬럼 추가 ReportViewer 거래 PnL 컬럼, rr_score 색상 코딩 DashboardView report.generated 이벤트 핸들링 Settings initial_capital, min_rr_score 설정 MCP 미들웨어 수정 Session 1에서 ctx.set_state()와 ctx.get_state()가 async 메서드인데 await 없이 호출되던 문제를 발견하고 수정했다. 서버 로그에 반복적으로 나타나던 \u0026ldquo;MCP tool call failed\u0026rdquo; 에러의 원인이었다.\n# Before ctx.set_state(factory.CONTEXT_STARTED_AT, started_dt.strftime(\u0026#34;%Y-%m-%d %H:%M:%S\u0026#34;)) # After await ctx.set_state(factory.CONTEXT_STARTED_AT, started_dt.strftime(\u0026#34;%Y-%m-%d %H:%M:%S\u0026#34;)) auto-reconnect 로직도 추가해 MCP 연결 실패 시 자동 복구되도록 개선했다.\n단위 테스트 DCF 밸류에이션과 포트폴리오 리스크 서비스에 대한 단위 테스트를 추가했다.\n커밋 로그 메시지 변경 feat: sort schedule tasks by cron time ascending UI feat: show agent name and friendly task labels in ScheduleManager UI style: align new components with existing design system UI fix: use import type for ScheduledTask (Vite ESM) FE feat: add Google News RSS fallback for news stability BE feat: add compact/expanded view toggle to SignalCard UI feat: add DOCX investment memo export BE feat: add real portfolio beta and correlation heatmap BE feat: add DCF sensitivity heatmap table UI test: add unit tests for DCF and portfolio risk TEST feat: populate kospi200 sector data from NAVER BE fix: await async MCP context methods + auto-reconnect BE fix: replace explicit any types FE feat: add investment memo HTML export BE feat: add VaR, beta, sector concentration risk BE feat: add DCF valuation with sensitivity table BE feat: add signal history snapshots and timeline BE+FE feat: add peer comparison with DART valuation BE feat: add news/macro analyst as 6th expert BE feat: add catalyst calendar with DART disclosures BE+FE feat: add DART insider trading data BE feat: add foreign/institutional investor trend BE feat: add 8 new DB tables, ANALYST role, metadata init BE fix: resolve lint errors in DashboardView/SignalCard FE feat: add report.generated event handling FE feat: add initial_capital and min_rr_score to settings BE+FE feat: add ScheduleManager with cron editing FE feat: add trade PnL column and rr_score color coding FE feat: add SignalDetailModal with orders drilldown FE feat: add expert opinion expansion and risk_notes FE feat: use correct performance endpoint with selector FE feat: add market_value to PositionsTable FE feat: show fill_price, order_type, signal link FE feat: add missing type fields FE feat: add missing API service functions FE 인사이트 이번 스프린트는 trading-agent의 분석 깊이와 프론트엔드 완성도를 동시에 끌어올린 대규모 확장이었다. 6번째 전문가 추가로 시그널 파이프라인이 더 균형 잡힌 의사결정을 내릴 수 있게 되었고, DCF/VaR/베타 같은 기관급 분석 도구가 추가되면서 단순 시그널 생성을 넘어 종합 투자 분석 플랫폼으로 진화하고 있다. DART 데이터 활용 범위가 내부자 거래, 수급 동향, 공시 캘린더까지 확장되면서, 한국 주식 시장 특화 트레이딩 에이전트로서의 차별점이 더욱 뚜렷해졌다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-trading-agent-dev6/cover.jpg","permalink":"/ko/posts/2026-03-25-trading-agent-dev6/","title":"Trading Agent 개발기 #6 — 분석 고도화와 프론트엔드 대규모 확장"},{"content":"개요 바이브 코딩으로 웹사이트를 만드는 것은 쉬워졌지만, 보안은 여전히 사람의 몫이다. 기술루트 알렉의 영상 AI가 짠 코드, 그대로 배포하면 털립니다에서 다룬 내용을 기반으로, AI 생성 코드의 보안 취약점을 체계적으로 점검하는 방법과 자동 스캐닝 도구를 정리한다.\n보안의 4개 레이어 웹 애플리케이션 보안은 크게 4개 구간으로 나뉜다.\ngraph TD A[\"네트워크 보안\"] --\u003e B[\"HTTPS 적용 \u0026lt;br/\u0026gt; 데이터 스누핑 방지\"] C[\"서버 보안\"] --\u003e D[\"OS 보안 패치 \u0026lt;br/\u0026gt; 보안 솔루션 설치\"] E[\"DB 보안\"] --\u003e F[\"비밀번호 해싱 \u0026lt;br/\u0026gt; 개인정보 암호화\"] G[\"애플리케이션 보안\"] --\u003e H[\"OWASP Top 10 \u0026lt;br/\u0026gt; 코드 레벨 취약점\"]바이브 코딩으로 간단한 웹페이지(HTML/CSS/JS)만 올렸다면 네트워크/서버/DB 보안은 상대적으로 단순하다. 하지만 애플리케이션 보안 — 코드 안에 숨어있는 취약점 — 은 반드시 점검해야 한다.\nOWASP Top 10 — 반드시 알아야 할 웹 보안 위협 OWASP(Open Worldwide Application Security Project)는 매년 웹 애플리케이션의 주요 보안 위협을 발표한다.\n1. 접근 제어 실패 (Broken Access Control) 권한이 없는 사용자가 다른 사용자의 데이터나 기능에 접근 가능한 상태. API 호출 시 권한 검증이 누락되면 발생한다.\n2. 암호화 실패 (Cryptographic Failures) 비밀번호를 평문으로 저장하거나, 약한 해싱 알고리즘을 사용하는 경우.\n3. 인젝션 (Injection) SQL 쿼리, OS 명령어, LDAP 쿼리에 악성 코드를 삽입해 실행시키는 공격. AI가 생성한 코드에서 가장 흔하게 발견되는 취약점 중 하나다.\n4. 보안이 고려되지 않은 설계 (Insecure Design) 기능 구현에만 집중하고 보안 아키텍처를 무시한 설계.\n5. 보안 설정 오류 (Security Misconfiguration) 기본 비밀번호 미변경, 불필요한 기능 활성화, 에러 메시지를 통한 정보 노출.\n6. 취약한 컴포넌트 (Vulnerable Components) 알려진 취약점이 있는 라이브러리나 패키지를 사용하는 경우.\n7. 인증 실패 (Authentication Failures) 세션 관리 미흡, 약한 비밀번호 정책, 무차별 대입 공격 미방어.\n8. 소프트웨어 무결성 오류 (Software Integrity Failures) CI/CD 파이프라인에서 코드나 의존성의 무결성을 검증하지 않는 경우.\n9. 로깅 및 모니터링 실패 (Logging \u0026amp; Monitoring Failures) 공격 시도를 탐지하지 못하는 상태.\n10. SSRF (Server-Side Request Forgery) 서버가 공격자가 지정한 URL로 요청을 보내도록 유도하는 공격.\nAI가 자주 만드는 보안 실수 바이브 코딩에서 특히 주의해야 할 패턴:\ngraph LR A[\"AI 생성 코드\"] --\u003e B[\"SQL 인젝션 \u0026lt;br/\u0026gt; f-string 쿼리\"] A --\u003e C[\"XSS \u0026lt;br/\u0026gt; innerHTML 사용\"] A --\u003e D[\"하드코딩된 \u0026lt;br/\u0026gt; API 키/비밀번호\"] A --\u003e E[\"CORS * \u0026lt;br/\u0026gt; 전체 허용\"] A --\u003e F[\"평문 \u0026lt;br/\u0026gt; 비밀번호 저장\"] SQL 인젝션: f\u0026quot;SELECT * FROM users WHERE id = {user_id}\u0026quot; — 파라미터 바인딩 미사용 XSS: element.innerHTML = userInput — 사용자 입력을 직접 HTML로 삽입 비밀 정보 하드코딩: API_KEY = \u0026quot;sk-abc123...\u0026quot; — 환경 변수 미사용 CORS 전체 허용: Access-Control-Allow-Origin: * — 모든 도메인 허용 평문 저장: 비밀번호를 해싱 없이 DB에 직접 저장 자동 보안 스캐닝 도구 영상에서 소개된 방식처럼, URL을 입력하면 자동으로 보안 점검을 수행하는 도구를 활용할 수 있다.\n정적 분석 (SAST) 코드 자체를 분석해 취약점을 찾는다:\nSemgrep: 패턴 매칭 기반 보안 스캐너 Bandit: Python 전용 보안 분석기 ESLint Security Plugin: JavaScript 보안 규칙 동적 분석 (DAST) 실행 중인 애플리케이션을 스캔한다:\nOWASP ZAP: 무료 웹 애플리케이션 보안 스캐너 Nikto: 웹 서버 취약점 스캐너 의존성 취약점 검사 사용 중인 라이브러리의 알려진 취약점을 확인한다:\nnpm audit / pip audit / safety check Snyk: SCA(Software Composition Analysis) 도구 Claude Code에서 보안 점검 통합하기 Claude Code로 코드를 작성할 때 보안을 강화하는 방법:\nCLAUDE.md에 보안 규칙 명시: \u0026ldquo;SQL 쿼리는 반드시 파라미터 바인딩 사용\u0026rdquo;, \u0026ldquo;사용자 입력은 항상 sanitize\u0026rdquo; 코드 리뷰 시 보안 관점 추가: /review 시 OWASP Top 10 기준으로 검토 요청 배포 전 자동 스캔: CI/CD 파이프라인에 Semgrep이나 Bandit 통합 환경 변수 분리: .env 파일을 .gitignore에 포함하고, 비밀 정보는 환경 변수로만 접근 인사이트 바이브 코딩의 편리함에 빠져 보안을 간과하기 쉽다. AI가 생성한 코드는 기능적으로 정확하더라도, OWASP Top 10 취약점을 내포하고 있을 수 있다. 특히 SQL 인젝션, XSS, 비밀 정보 하드코딩은 AI가 가장 자주 만드는 보안 실수다. 배포 전에 Semgrep이나 OWASP ZAP 같은 자동 스캐닝 도구로 한 번만 점검해도 대부분의 기본적인 취약점을 잡을 수 있다. 보안은 코드 작성 후의 추가 단계가 아니라, 프롬프트 시점부터 고려해야 하는 기본 요소다.\n","date":"2026-03-25T00:00:00+09:00","image":"/images/posts/2026-03-25-ai-code-security/cover.jpg","permalink":"/ko/posts/2026-03-25-ai-code-security/","title":"바이브 코딩 보안 점검 가이드 — OWASP Top 10과 AI 자동 스캐닝"},{"content":"개요 AI가 크리에이티브 콘텐츠 제작의 핵심 도구로 자리잡고 있다. 두 가지 사례가 이 흐름의 양면을 선명하게 보여준다. 하나는 한국 VFX 기업 자이언트스텝이 AI와 VFX를 결합해 만든 파일럿 영상 SPACE GREEN, 다른 하나는 2025년 4월 세상을 떠난 배우 발 킬머(Val Kilmer)를 generative AI로 스크린에 되살린 영화 As Deep as the Grave다. 전자는 \u0026ldquo;AI 콘텐츠를 어떻게 팔 것인가\u0026quot;라는 비즈니스 질문을, 후자는 \u0026ldquo;사후 AI 출연은 헌사인가 착취인가\u0026quot;라는 윤리적 질문을 던진다.\n자이언트스텝 SPACE GREEN — 하이브리드 접근법 자이언트스텝이란 자이언트스텝(Giantstep)은 2008년 설립된 한국의 VFX 전문 기업이다. SM 엔터테인먼트의 버추얼 아티스트 NAEVIS, 삼성, 넷플릭스, 디즈니 등과 협업해 왔다. 순수 AI 스타트업이 아니라 수년간 축적된 VFX 역량 위에 AI를 올린 회사라는 점이 중요하다.\nSPACE GREEN 프로젝트 SPACE GREEN은 자이언트스텝의 R\u0026amp;D 파일럿 영상이다. 핵심은 AI 단독이 아닌 하이브리드 접근법이다.\n제작 인력: 경력 1~3년차 주니어 아티스트 4명 + 디렉터 1명 제작 기간: 단 10일 방법론: AI가 러프 드래프트를 생성하면, VFX 팀이 디테일을 보강하고, 최종 DI(Digital Intermediate) 단계에서 마무리 flowchart LR A[\"AI 생성\u0026lt;br/\u0026gt;Rough Draft\"] --\u003e B[\"VFX 보강\u0026lt;br/\u0026gt;Detail Work\"] B --\u003e C[\"DI 마무리\u0026lt;br/\u0026gt;Color + Polish\"] C --\u003e D[\"최종 콘텐츠\u0026lt;br/\u0026gt;SPACE GREEN\"] style A fill:#4a9eff,color:#fff style B fill:#ff6b6b,color:#fff style C fill:#ffa94d,color:#fff style D fill:#51cf66,color:#fff이 파이프라인의 본질을 한 문장으로 요약하면 이렇다: AI가 1에서 9까지 가져가고, 아티스트가 마지막 1마일을 완성한다.\n디테일 밸리(Detail Valley) AI가 생성한 영상은 언뜻 그럴듯해 보이지만 확대하면 디테일이 무너진다. 이 구간을 디테일 밸리라고 부른다. 자이언트스텝이 파는 것은 AI 영상 그 자체가 아니라, AI와 VFX 전문성을 결합해 이 디테일 밸리를 건너는 퀄리티 갭이다.\n참고로 두바이 국제 AI 영화제(Dubai International AI Film Festival) 대상 수상작 One More Pumpkin은 제작비 0원, 제작 기간 5일이었다. AI만으로도 상을 탈 수 있다. 그렇다면 질문은 이렇게 바뀐다:\nAI 콘텐츠의 경쟁력은 잘 만드는 것에 있는가? 아니면 잘 파는 것에 있는가?\n자이언트스텝의 답은 명확하다 — 둘 다 필요하지만, 시장에서 차별화는 \u0026lsquo;잘 만드는 것\u0026rsquo;에서 나온다. 0원짜리 AI 영상은 누구나 만든다. 클라이언트가 비용을 지불하는 건 그 너머의 퀄리티다.\n발 킬머의 유작 — 기술이 예술이 되는 순간 배경 발 킬머(Val Kilmer)는 탑건(Top Gun)의 아이스맨(Iceman)으로 잘 알려진 배우다. 2015년 후두암으로 목소리를 잃었고, 2025년 4월 65세의 나이로 세상을 떠났다.\n영화 As Deep as the Grave의 코어테 브뤼인스(Koerte Bruyns) 감독은 2020년 킬머를 캐스팅했지만, 병세 악화로 촬영이 불가능해졌다. 감독은 킬머의 젊은 시절부터 말년까지의 사진과 영상으로 학습한 generative AI를 활용해 그를 스크린에 되살렸다.\n핵심 결정: 손상된 실제 목소리 2022년 탑건: 매버릭(Top Gun: Maverick)에서는 AI로 복원한 목소리를 사용했다. 하지만 이 영화에서는 정반대의 선택을 했다 — 킬머의 손상된 실제 목소리를 그대로 사용했다.\n영화 속 캐릭터도 병을 앓고 있다. 캐릭터의 고통과 배우의 실제 고통이 겹치면서, 기술적 한계가 오히려 서사적 진정성이 되었다.\n이 지점에서 기술은 예술이 된다.\n윤리적 프레임워크 사후 AI 출연은 민감한 문제다. 이 프로젝트는 다음 기준을 충족했다:\n본인 의사: 킬머 본인이 생전에 출연 의향을 표명했다 유가족 동의: 자녀들이 프로젝트를 지지했다 업계 기준 준수: SAG-AFTRA 가이드라인을 따랐다 정당한 보상: 유산 관리 측에 정당한 보수를 지급했다 감독이 밝힌 철학은 한 마디로 요약된다:\n\u0026ldquo;교체가 아닌 함께.\u0026rdquo;\nAI 크리에이티브의 가치 논쟁 두 사례를 나란히 놓으면 AI 크리에이티브 콘텐츠의 가치를 둘러싼 핵심 축이 드러난다.\n비교 항목 SPACE GREEN As Deep as the Grave AI 역할 초안 생성 (1→9) 배우 재현 (얼굴 + 몸) 인간 역할 디테일 보강 + DI 연출 판단 + 목소리 선택 핵심 가치 퀄리티 갭 = 상업적 차별화 서사적 진정성 = 예술적 가치 논쟁 지점 잘 만드는 것 vs 잘 파는 것 헌사(tribute) vs 착취(exploitation) 윤리 이슈 상대적으로 낮음 사후 초상권, 동의, 보상 할리우드에서는 사후 AI 출연을 둘러싼 논쟁이 계속되고 있다. \u0026ldquo;Posthumous AI: tribute or exploitation?\u0026rdquo; 이 질문에 대한 답은 아직 합의되지 않았지만, As Deep as the Grave는 하나의 프레임워크를 제시했다 — 본인 의사, 유가족 동의, 업계 기준, 정당한 보상이라는 네 가지 조건이다.\n인사이트 1. AI는 도구이지 결과물이 아니다. 자이언트스텝의 사례가 보여주듯, AI 생성물 자체는 commodity화되고 있다. 경쟁력은 AI 위에 무엇을 얹느냐에서 갈린다.\n2. 하이브리드 파이프라인이 현실적 답이다. 순수 AI 영상은 디테일 밸리에 빠진다. 주니어 4명 + 디렉터 1명이 10일 만에 완성한 SPACE GREEN은, 소규모 팀이 AI를 레버리지 삼아 대형 스튜디오급 결과물을 낼 수 있음을 증명한다.\n3. 윤리적 프레임워크가 기술보다 먼저다. 발 킬머 프로젝트가 논란이 아닌 감동이 된 건 기술력 때문이 아니라 네 가지 윤리 조건을 충족했기 때문이다. AI가 고인의 초상을 다루는 영역으로 확장될수록, SAG-AFTRA 같은 가이드라인의 중요성은 커진다.\n4. \u0026ldquo;교체가 아닌 함께\u0026quot;는 모든 AI 크리에이티브의 원칙이 되어야 한다. 자이언트스텝도, 코어테 브뤼인스 감독도 AI를 인간의 대체재가 아닌 협업 도구로 위치시켰다. 이 관점이 AI 크리에이티브의 지속가능성을 결정한다.\n출처: 프롬 AI Cinema Briefing (YouTube)\n","date":"2026-03-24T00:00:00+09:00","image":"/images/posts/2026-03-24-ai-creative-content/cover.jpg","permalink":"/ko/posts/2026-03-24-ai-creative-content/","title":"AI 크리에이티브의 두 얼굴 — 자이언트스텝의 하이브리드 VFX와 발 킬머의 유작"},{"content":"개요 이전 글: Claude Code 실전 가이드 — 컨텍스트 관리부터 워크플로우까지에서는 CLAUDE.md, Lazy Loading, TDD 워크플로우, 서브에이전트 등 Claude Code의 핵심 사용 전략을 정리했다. 불과 5일 만에 후속편을 쓰게 된 이유는 단순하다 — Claude Code가 최근 2개월간 쏟아낸 신기능의 양이 그만큼 압도적이기 때문이다. Cole Medin의 You\u0026rsquo;re Hardly Using What Claude Code Has to Offer, it\u0026rsquo;s Insane 영상을 바탕으로, 이전 글에서 다루지 않은 9가지 핵심 신기능을 정리한다.\ngraph TD subgraph PREV[\"이전 글에서 다룬 것\"] A[\"CLAUDE.md / MEMORY.md\"] B[\"Lazy Loading\"] C[\"Plan 모드\"] D[\"TDD 워크플로우\"] E[\"서브에이전트 16개\"] F[\"Hooks\"] end subgraph NEW[\"이번 글에서 다루는 것\"] G[\"1M 컨텍스트 윈도우\"] H[\"Git Worktrees 네이티브\"] I[\"/simplify, /batch\"] J[\"Remote Control\"] K[\"Auto-memory\"] L[\"/btw, /loop, /voice\"] M[\"Effort Levels\"] N[\"Scheduled Tasks\"] end PREV -.-\u003e|\"기반 위에\"| NEW style PREV fill:#e8eaf6 style NEW fill:#e8f5e91M 컨텍스트 윈도우 — 그러나 250K가 실질적 한계 Sonnet과 Opus 모두 1M(백만) 토큰 컨텍스트 윈도우가 GA(General Availability)되었다. 약 750,000 단어를 단기 기억에 담을 수 있다는 뜻이다. 이론적으로는 전체 코드베이스를 한 번에 읽힐 수 있다.\n그러나 실전에서의 한계는 분명하다. Cole Medin의 반복적인 테스트에 따르면, 250K~300K 토큰을 넘어가면 환각(hallucination)이 급격히 증가한다. /context 명령으로 현재 토큰 사용량을 수시로 확인하고, 250K에 가까워지면 memory compaction을 하거나 handoff prompt를 작성해서 새 세션으로 넘어가는 것이 좋다.\n이전 글에서 \u0026ldquo;Context is milk — 시간이 지나면 상한다\u0026quot;고 했는데, 1M 윈도우가 열려도 이 원칙은 변하지 않는다. 신선한 200K가 부풀어진 500K보다 낫다.\nGit Worktrees 네이티브 지원 이전 글에서 git worktree 명령어를 수동으로 실행하는 방법을 소개했다. 이제는 Claude Code가 워크트리를 네이티브로 지원한다.\n# 이전: 수동으로 worktree 생성 후 각각에서 claude 실행 git worktree add ../project-feature-a feature-a cd ../project-feature-a \u0026amp;\u0026amp; claude # 현재: Claude Code 내에서 직접 생성 # .claude/worktrees/ 폴더에 자동 관리 핵심 변화는 .claude/worktrees/ 폴더에서 워크트리가 자동으로 관리된다는 것이다. 별도의 git 명령 없이 Claude Code 안에서 바로 워크트리를 만들고, 각각에서 독립적인 작업을 진행할 수 있다. 실제 개발에서는 항상 여러 feature branch와 PR을 동시에 다루므로, 이 기능은 병렬 작업의 진입 장벽을 크게 낮춘다.\n/simplify — 과잉 엔지니어링 방지 LLM이 코드를 생성할 때 가장 흔한 문제 중 하나가 과잉 엔지니어링이다. 불필요한 추상화, 과도한 에러 핸들링, 쓸데없는 유틸리티 함수가 끼어든다. Anthropic이 내부에서 쓰다가 공개한 빌트인 커맨드가 바로 /simplify다.\n구현을 완료한 직후 /simplify를 실행하면, Claude가 코드를 리뷰하면서 불필요한 복잡성을 제거한다. 수동으로 \u0026ldquo;이거 너무 복잡한데 단순화해줘\u0026quot;라고 매번 타이핑하던 것을 한 명령으로 자동화한 셈이다.\n/batch — 대규모 리팩토링의 병렬 처리 /batch는 대규모 변경 사항을 병렬로 처리하는 커맨드다. 내부적으로 작업을 분할하고 여러 서브에이전트에게 분배한다.\n/batch replace all console.log calls with structured logger from utils/logger 이 한 줄로 Claude가:\n코드베이스를 스캔해서 모든 console.log를 찾고 작업을 서브에이전트들에게 분배하고 각 에이전트가 병렬로 변환을 수행하고 결과를 취합해서 PR을 생성한다 대규모 마이그레이션, 린팅 규칙 변경, API 버전 업그레이드 등 \u0026ldquo;단순하지만 파일이 많은\u0026rdquo; 리팩토링에 최적이다.\nRemote Control — 폰에서 데스크탑 제어 가장 인상적인 신기능 중 하나다. Claude Code 세션에서 /remote-control을 실행하면 클라우드 세션이 생성되고, Claude 모바일 앱에서 그 세션에 접속할 수 있다.\nsequenceDiagram participant Phone as Claude App (Phone) participant Cloud as Cloud Session participant Desktop as Claude Code (Desktop) Desktop-\u003e\u003eCloud: /remote-control 실행 Cloud--\u003e\u003ePhone: 세션 동기화 Phone-\u003e\u003eCloud: 메시지 전송 Cloud-\u003e\u003eDesktop: 실시간 반영 Desktop--\u003e\u003eCloud: 실행 결과 Cloud--\u003e\u003ePhone: 결과 표시폰에서 보내는 메시지가 데스크탑의 Claude Code 세션에 실시간으로 반영된다. 이동 중에도 빌드 상태를 확인하거나, 간단한 수정 지시를 내릴 수 있다. 데스크탑 앞에 앉아 있지 않아도 개발을 계속할 수 있는 것이다.\nAuto-memory — Claude가 스스로 기억하는 시스템 이전 글에서 CLAUDE.md(팀 공유 규칙)와 MEMORY.md(개인 학습)를 분리하는 전략을 다뤘다. Auto-memory는 여기서 한 단계 더 나아간다 — Claude가 세션을 넘나들며 스스로 기억을 축적한다.\n구분 CLAUDE.md Auto-memory 관리 방식 사용자가 수동 작성 Claude가 자동 축적 저장 위치 프로젝트 루트 ~/.claude/memory/ 내용 팀 규칙, 컨벤션 실수 패턴, 프로젝트 인사이트 결정론성 높음 (우리가 통제) 낮음 (Claude가 판단) 비활성화 N/A 가능 기본적으로 활성화되어 있으며, 비활성화할 수도 있다. Cole Medin의 조언:\n최대한의 통제를 원한다면 → CLAUDE.md만 사용 Claude에게 자율성을 주고 싶다면 → CLAUDE.md + Auto-memory 병행 실전에서는 둘을 병행하는 것을 추천한다. Auto-memory가 축적한 내용을 주기적으로 확인하고, 유용한 것은 CLAUDE.md로 승격시키면 된다.\n/btw — 컨텍스트를 오염시키지 않는 질문 작업 중에 \u0026ldquo;이 라이브러리의 이 함수가 뭐하는 거지?\u0026rdquo; 같은 빠른 질문이 떠올랐을 때, 메인 세션에서 물어보면 컨텍스트가 불필요하게 커진다. /btw는 사이드카 대화를 열어서 메인 컨텍스트를 건드리지 않고 질문할 수 있게 해준다.\n/btw CRUD가 뭐의 약자야? → (답변 확인) → Escape로 닫기 → 메인 세션은 그대로 유지 주의: /btw 모드에서는 Claude가 도구를 사용할 수 없다. 코드베이스 탐색이 필요한 질문은 서브에이전트를 쓰고, 단순 지식 질문만 /btw로 처리하라.\n/loop — 반복 작업 예약 특정 프롬프트를 일정 간격으로 반복 실행하는 커맨드다.\n# 5분마다 배포 상태 확인 /loop 5m check if the deployment finished and give me a status update # 30분마다 테스트 실행 /loop 30m run all tests and alert if any are failing CI/CD 파이프라인 모니터링, 주기적 테스트 실행, 외부 웹사이트 폴링 등에 유용하다. 다른 Claude Code 인스턴스에서 작업하면서 /loop으로 품질 게이트를 돌리는 패턴이 특히 강력하다.\n/voice — 네이티브 음성 입력 /voice로 음성 입력을 활성화할 수 있다. 특히 Plan 모드에서 브레인덤프를 할 때 타이핑보다 훨씬 빠르다.\nCole Medin은 Aqua Voice, WhisperFlow, Whispering(오픈소스) 같은 외부 도구가 아직 네이티브보다 약간 더 정확하다고 평가했지만, 별도 도구를 설치하지 않고 바로 쓸 수 있다는 점에서 진입 장벽이 낮다.\nEffort Levels — 토큰 사용량 조절 모델의 추론 깊이를 조절할 수 있다. /effort 또는 세션 시작 시 좌우 화살표로 변경 가능하다.\n레벨 적합한 작업 토큰 사용량 Low 간단한 수정, 포맷팅 최소 Medium (기본) 일반 코딩, 버그 수정 보통 High 복잡한 문제 해결 높음 Max (Opus 전용) 극도로 어려운 디버깅 최대 5시간 또는 주간 토큰 한도에 걸리지 않으려면, 간단한 작업에서 Low를 적극 활용하고 정말 어려운 문제에만 High/Max를 쓰는 것이 좋다.\nScheduled Tasks \u0026amp; Cron Jobs /loop이 세션 내 반복이라면, Scheduled Tasks는 세션 바깥에서 작동한다.\n일회성 리마인더: \u0026ldquo;3시에 릴리스 브랜치 push 알려줘\u0026rdquo; Cron Jobs: 반복적으로 실행할 작업을 예약. 매일 아침 코드 품질 리포트를 생성하거나, 매시간 특정 API의 상태를 체크하는 등의 자동화가 가능하다. 인사이트 이전 글에서 \u0026ldquo;Claude Code는 도구가 아니라 시스템이다\u0026quot;라고 했다. 이번 신기능들은 그 시스템의 범위를 시간과 공간 모두에서 확장한다.\n공간의 확장: Remote Control로 데스크탑 밖으로, Git Worktrees로 단일 브랜치 밖으로, /batch로 단일 파일 밖으로 작업 범위가 넓어졌다.\n시간의 확장: Auto-memory로 세션을 넘어선 학습이, /loop과 Scheduled Tasks로 사용자가 자리를 비운 시간에도 작업이 이어진다.\n인지 부하의 감소: /simplify가 과잉 엔지니어링을, /btw가 컨텍스트 오염을, Effort Levels가 토큰 낭비를 줄여준다.\n5일 전 글에서 다룬 CLAUDE.md, Plan 모드, TDD, 서브에이전트가 기초 체력이라면, 이번 글의 기능들은 장비 업그레이드다. 기초 체력 없이 장비만 좋아선 안 되지만, 기초가 탄탄한 상태에서 이 도구들을 활용하면 생산성이 확실히 한 단계 올라간다.\n출처: You\u0026rsquo;re Hardly Using What Claude Code Has to Offer, it\u0026rsquo;s Insane — Cole Medin\n","date":"2026-03-24T00:00:00+09:00","image":"/images/posts/2026-03-24-claude-code-new-features/cover.jpg","permalink":"/ko/posts/2026-03-24-claude-code-new-features/","title":"Claude Code 실전 가이드 2 — 최근 2개월 신기능 완전 정복"},{"content":"개요 이전 글: #3 — 검색 파이프라인 고도화와 생성 이미지 비교 모드\n이번 #4에서는 23개 커밋에 걸쳐 세 가지 큰 작업 스트림을 진행했다.\nmain.py 라우터 분리 — 비대해진 단일 파일을 5개 route 모듈로 쪼개는 리팩토링 Terraform Dev 서버 구축 — AWS EC2 + Lambda Scheduler로 비용 효율적인 개발 환경 구성 Inpaint 에디터 구현 — Figma 디자인부터 Canvas 기반 마스크 에디터, API, DB migration까지 main.py 라우터 분리 왜 분리했나 코드 리뷰 중 main.py가 앱 초기화, 글로벌 상태, 라우트 핸들러를 전부 담고 있어서 변경 충돌이 잦고 탐색이 어려운 문제가 있었다. 특히 generation, search, images 관련 엔드포인트가 하나의 파일에 섞여 있으니 새 기능(Inpaint 등)을 추가할 때마다 diff가 커졌다.\n어떻게 분리했나 FastAPI의 APIRouter를 활용해서 5개 모듈로 순차적으로 추출했다.\nbackend/src/routes/ ├── meta.py # health, API info, frontend serving ├── images.py # GET /images, upload, selection logging ├── search.py # POST /search, hybrid/simple ├── history.py # GET /api/history/generations ├── generation.py # POST /api/generate-image ├── edit.py # POST /api/edit-image (나중에 추가) └── auth.py # Google OAuth (기존) 각 route 모듈은 글로벌 상태(images_data, hybrid_pipeline 등)에 접근할 때 from backend.src import main as app_module을 함수 본문 안에서 import하는 패턴을 유지했다. 순환 참조를 피하면서도 별도 DI 컨테이너 없이 간결하게 처리하는 방식이다.\n분리 후 main.py는 약 140줄로 줄었고, 앱 생성 + lifespan + CORS + 라우터 등록만 남게 되었다.\n리팩토링 원칙 한 번에 하나의 모듈만 추출: meta → images → search → history → generation 순서로, 매번 커밋 후 동작 확인 기존 URL 경로 변경 없음: prefix 설정으로 API 계약 유지 import 패턴 통일: 모든 route 모듈이 동일한 방식으로 글로벌 상태에 접근 Terraform Dev 서버 구축 배경 로컬 개발 환경에서는 ML 모델 로딩과 이미지 처리가 느리고, 팀원 간 환경 차이도 있었다. AWS에 dev 서버를 하나 올리되, 사용하지 않는 시간에는 자동으로 꺼서 비용을 절약하고 싶었다.\n아키텍처 결정 VPC를 새로 만들 것인지, 기존 prod VPC를 공유할 것인지 논의했다. 결론은 Option B: VPC 공유, Security Group 분리. 소규모 프로젝트에서 VPC를 이중으로 관리하는 것은 오버헤드가 크고, Security Group 레벨에서 충분히 격리할 수 있다고 판단했다.\ngraph TB subgraph VPC[\"VPC 10.0.0.0/16\"] subgraph SG_PROD[\"Prod Security Group\"] EC2_PROD[\"EC2 Prod\u0026lt;br/\u0026gt;t3.medium\"] end subgraph SG_DEV[\"Dev Security Group\"] EC2_DEV[\"EC2 Dev\u0026lt;br/\u0026gt;t3.medium\"] end end EIP_PROD[\"Elastic IP Prod\"] --\u003e EC2_PROD EIP_DEV[\"Elastic IP Dev\"] --\u003e EC2_DEV subgraph SCHEDULER[\"Lambda Scheduler\"] EB_START[\"EventBridge\u0026lt;br/\u0026gt;cron 10:00 KST\"] --\u003e|start| LAMBDA[\"Lambda\u0026lt;br/\u0026gt;ec2_scheduler\"] EB_STOP[\"EventBridge\u0026lt;br/\u0026gt;cron 22:00 KST\"] --\u003e|stop| LAMBDA end LAMBDA --\u003e|\"StartInstances\u0026lt;br/\u0026gt;StopInstances\"| EC2_DEV주요 리소스 리소스 용도 aws_security_group.dev_sg SSH(22), HTTP(80), Backend(8000), Vite(5173) 허용 aws_instance.dev_server Ubuntu 24.04 LTS, t3.medium, gp3 40GB aws_eip.dev_eip 고정 IP (서버 재시작해도 유지) aws_key_pair.dev_key dev 전용 SSH 키페어 aws_lambda_function EC2 start/stop 실행 aws_scheduler_schedule (start) 매일 10:00 KST 시작 aws_scheduler_schedule (stop) 매일 22:00 KST 중지 Lambda Scheduler 구조 EventBridge Scheduler가 Lambda를 호출할 때 action과 instance_id를 JSON payload로 전달한다. Lambda는 단순히 boto3로 start_instances 또는 stop_instances를 호출하는 역할만 한다.\nIAM 권한은 최소 권한 원칙을 적용했다. Lambda Role은 해당 인스턴스에 대해서만 ec2:StartInstances, ec2:StopInstances, ec2:DescribeInstances를 허용하고, EventBridge Scheduler Role은 해당 Lambda 함수만 invoke할 수 있도록 제한했다.\n하루 12시간(10:00~22:00) 운영이므로, 24시간 대비 약 50% 비용 절감 효과가 있다.\nInpaint 에디터 구현 설계 과정 Figma에서 InpaintFullPage 디자인을 확인한 뒤, design spec과 implementation plan을 먼저 작성했다. 전체 흐름은 다음과 같다.\nsequenceDiagram participant User participant Editor as InpaintEditor (React) participant API as FastAPI participant Gemini as Gemini Imagen 3 User-\u003e\u003eEditor: 생성된 이미지에서 Edit 클릭 Editor-\u003e\u003eEditor: Canvas에 마스크 그리기 User-\u003e\u003eEditor: prompt 입력 + Generate Editor-\u003e\u003eAPI: mask_file + source_filename + prompt API-\u003e\u003eGemini: source image + mask + prompt Gemini--\u003e\u003eAPI: edited image API--\u003e\u003eEditor: EditImageResponse Editor--\u003e\u003eUser: 결과 표시Backend 변경사항 DB Migration: generation_logs 테이블에 is_inpaint Boolean 컬럼 추가. 기존 생성 이력과 inpaint 생성을 구분하기 위해서다.\nSchemas: EditImageRequest와 EditImageResponse를 새로 정의했다. Request는 source_filename, prompt, swap_filename, parent_generation_id, image_count를 받고, mask는 multipart File로 별도 전송한다.\nJSON 데이터와 파일을 함께 전송해야 하므로, JSON payload를 Form 필드의 문자열로 받아서 파싱하는 방식을 택했다. FastAPI에서 File과 Body(JSON)를 동시에 사용할 수 없는 제약 때문이다.\nService: generate_edit_image 헬퍼를 추가해서, 기존 generate_single_image와 구조를 맞추되 Gemini API 호출 시 source image + mask image + (optional) swap image를 contents에 포함하도록 했다.\nFrontend: InpaintEditor 컴포넌트 Canvas 기반 마스크 에디팅 컴포넌트를 구현했다. 주요 기능:\n원본 이미지 위에 Canvas overlay로 브러시 마스크 그리기 브러시 크기 조절 Undo/Clear 지원 마스크 영역을 흰색 PNG로 export해서 API에 전송 App.tsx의 상태로 editingImage를 추가하고, 생성된 이미지의 Edit 버튼 클릭 시 InpaintEditor가 표시되도록 연결했다.\n커밋 로그 # 커밋 메시지 변경 요약 1 refactor: extract routes/meta.py with APIRouter meta 라우트 분리 2 refactor: extract routes/images.py with APIRouter images 라우트 분리 3 refactor: extract routes/search.py with APIRouter search 라우트 분리 4 refactor: extract routes/history.py with APIRouter history 라우트 분리 5 refactor: extract routes/generation.py with APIRouter generation 라우트 분리 6 docs: add dev server Terraform design spec Terraform 설계 스펙 문서 7 docs: add dev server Terraform implementation plan Terraform 구현 계획 문서 8 chore: add SSH key pair public keys 공개키 파일 추가 9 feat: manage SSH key pairs via Terraform aws_key_pair SSH 키페어 Terraform 관리 10 feat: add dev security group dev 전용 Security Group 11 feat: add dev EC2 instance and Elastic IP dev EC2 t3.medium + EIP 12 feat: add dev Lambda scheduler with IAM role and policy Lambda + IAM 권한 13 feat: add dev EventBridge scheduler (10:00-22:00 KST) EventBridge cron 스케줄 14 docs: add inpaint \u0026amp; swap feature design spec 기능 설계 스펙 문서 15 docs: add inpaint \u0026amp; swap implementation plan 구현 계획 문서 16 feat: add is_inpaint column to generation_logs Alembic migration 17 feat: add EditImageRequest/Response schemas Pydantic schema 추가 18 feat: add generate_edit_image service helper Gemini API 서비스 헬퍼 19 feat: add POST /api/edit-image endpoint edit.py 라우트 모듈 20 feat: add editImage API function and is_inpaint types frontend api.ts 21 feat: add InpaintEditor component Canvas 마스크 에디터 22 feat: integrate InpaintEditor with edit button and app state App.tsx 통합 23 fix: correct image_count field name and add Form annotation 필드명 수정 인사이트 리팩토링은 기능 추가 전에 하는 게 맞다. main.py 라우터 분리를 먼저 했기 때문에 Inpaint 에디터의 edit.py를 추가할 때 기존 코드를 건드릴 필요 없이 새 모듈만 등록하면 됐다. 분리하지 않았다면 main.py에 150줄이 더 추가되었을 것이다.\nTerraform은 prod/dev를 같은 파일에서 관리해도 된다. 별도 workspace나 디렉토리 분리 없이 하나의 main.tf에 prod/dev 리소스를 모두 선언했다. 프로젝트 규모가 작을 때는 이 방식이 전체 인프라를 한눈에 파악하기 좋다.\nFile + JSON 동시 전송은 FastAPI에서 까다롭다. File과 Body를 동시에 사용할 수 없어서 JSON payload를 Form 문자열로 받아 파싱하는 우회 방식을 썼다. multipart form data의 본질적인 제약이다.\nLambda Scheduler는 소규모 dev 서버에 최적이다. AWS Instance Scheduler 같은 무거운 솔루션 대신 Lambda + EventBridge 조합으로 구현하면 추가 비용이 거의 0에 가깝고, Terraform으로 관리하기도 쉽다.\n","date":"2026-03-24T00:00:00+09:00","image":"/images/posts/2026-03-24-hybrid-search-dev4/cover.jpg","permalink":"/ko/posts/2026-03-24-hybrid-search-dev4/","title":"Hybrid Image Search 개발기 #4 — 라우터 분리, Terraform Dev 서버, Inpaint 에디터"},{"content":"개요 이전 글: #2 — Unified Skill Flow와 \u0026ndash;since-last-run 추적\n이번 글에서는 두 가지 큰 흐름을 다룬다. 첫째, YouTube oEmbed 메타데이터와 시리즈 연속성 감지 같은 기능 개선. 둘째, .claude/skills/ 디렉토리에 놓던 단독 스킬을 Claude Code 플러그인 구조로 전환한 작업이다. 9개 커밋, 총 7개 세션에 걸친 작업 기록이다.\nYouTube oEmbed 메타데이터 개선 기존에는 YouTube 링크를 블로그 포스트에 포함할 때 제목 정도만 가져왔다. 이번에 두 가지를 개선했다.\noEmbed API 활용. YouTube의 oEmbed endpoint를 호출해서 썸네일, 작성자, 영상 제목 등 메타데이터를 자동으로 수집한다. Hugo shortcode에서 이 정보를 활용할 수 있게 했다.\ntranscript-api v1.x 마이그레이션. youtube-transcript-api 라이브러리가 v1.x로 메이저 업데이트되면서 API가 바뀌었다. 기존의 YouTubeTranscriptApi.get_transcript() 호출 방식에서 새로운 인터페이스로 전환했다. 이 작업은 단순한 의존성 업데이트지만, transcript 기반 요약 기능이 블로그 포스트 생성에 핵심이므로 빠르게 대응할 필요가 있었다.\n시리즈 연속성 감지 Log-Blog의 핵심 기능 중 하나는 시리즈물 관리다. 같은 프로젝트에 대해 #1, #2, #3을 이어서 쓸 때, 이전 글 이후의 커밋만 골라내야 한다.\n기존에는 날짜 기반으로 커밋을 필터링했다. 문제는 날짜가 부정확하다는 것이다. 포스트 발행일과 마지막 작업일이 다를 수 있고, 타임존 이슈도 있다.\n해결책은 간단했다. Hugo frontmatter에 last_commit 필드를 추가하고, sessions 명령에서 이 SHA를 읽어 해당 커밋 이후의 변경사항만 수집하는 것이다. 날짜 파싱의 모호함이 사라지고, 정확히 이전 포스트가 커버한 지점부터 이어갈 수 있게 되었다.\n플러그인 전환 이번 개발 사이클에서 가장 큰 작업이다. 7번째 세션에서 약 7시간을 투자했다.\n왜 플러그인인가 .claude/skills/ 디렉토리에 스킬 파일을 직접 넣는 방식은 동작하지만, 배포와 업데이트에 한계가 있다. 사용자가 수동으로 파일을 복사해야 하고, 버전 관리도 안 된다. Claude Code의 플러그인 시스템을 사용하면 설치와 업데이트를 자동화할 수 있다.\n구조 설계 graph TD A[\"기존 구조\u0026lt;br/\u0026gt;.claude/skills/log-blog.md\"] --\u003e B{\"전환\"} B --\u003e C[\"plugin.json\u0026lt;br/\u0026gt;플러그인 매니페스트\"] C --\u003e D[\"/logblog:post\u0026lt;br/\u0026gt;포스트 생성 스킬\"] C --\u003e E[\"/logblog:setup\u0026lt;br/\u0026gt;초기 설정 스킬\"] C --\u003e F[\"marketplace.json\u0026lt;br/\u0026gt;배포 메타데이터\"] style A fill:#f9f,stroke:#333 style C fill:#bbf,stroke:#333 style D fill:#bfb,stroke:#333 style E fill:#bfb,stroke:#333 style F fill:#fbf,stroke:#333plugin.json 매니페스트 플러그인의 진입점이다. author 필드는 처음에 문자열로 넣었다가 스키마 검증에서 실패했다. 객체 형태({ \u0026quot;name\u0026quot;: \u0026quot;...\u0026quot;, \u0026quot;url\u0026quot;: \u0026quot;...\u0026quot; })여야 한다는 걸 에러 메시지를 보고 알았다. 사소하지만 이런 게 한 커밋을 잡아먹는다.\n스킬 마이그레이션 기존 /log-blog 스킬을 /logblog:post로 이름을 바꿨다. 콜론(:) 구분자는 Claude Code 플러그인의 네임스페이스 컨벤션이다. 플러그인 이름이 접두사가 되고, 콜론 뒤가 개별 스킬 이름이 된다. 스킬의 내부 로직은 그대로 유지하되, 경로 참조와 호출 방식만 플러그인 구조에 맞게 조정했다.\n/logblog:setup 스킬 새로 추가한 스킬이다. 블로그를 처음 세팅하는 사용자를 위해 end-to-end 설정을 자동화한다.\nHugo 프로젝트 구조 확인 설정 파일 생성 필요한 디렉토리 구조 생성 Git 연동 확인 5번째 세션에서 /logblog:post를 호출했는데 스킬을 찾지 못하는 문제가 있었다. 플러그인 설치 전이라 당연한 결과였지만, 이 경험이 setup 스킬의 필요성을 확인시켜 줬다.\n마켓플레이스 배포 marketplace.json은 Claude Code 플러그인 레지스트리에 등록하기 위한 메타데이터 파일이다. 플러그인 이름, 설명, 버전, 저장소 URL, 지원하는 스킬 목록 등을 포함한다. 아직 공식 마켓플레이스가 활성화되지 않은 상태이므로, 현재는 GitHub 저장소 URL을 통한 직접 설치 방식을 사용한다. 마켓플레이스가 열리면 바로 등록할 수 있도록 준비해 둔 셈이다.\n커밋 로그 # 커밋 메시지 비고 1 feat: add YouTube oEmbed metadata and migrate to transcript-api v1.x 기능 개선 2 feat: detect series updates via last_commit SHA in sessions command 시리즈 연속성 3 docs: add logblog plugin design spec 설계 문서 4 docs: add logblog plugin implementation plan 구현 계획 5 feat: add logblog Claude Code plugin manifest plugin.json 6 feat: migrate /log-blog skill to /logblog:post in plugin structure 스킬 이전 7 feat: add /logblog:setup skill for end-to-end blog setup setup 스킬 8 fix: plugin.json author field must be object, not string 스키마 수정 9 feat: add marketplace.json for plugin distribution 마켓플레이스 인사이트 문서 먼저, 코드 나중. 7번째 세션에서 설계 문서와 구현 계획을 먼저 작성하고 코드를 짰다. 412분이라는 긴 세션이었지만, 방향이 흔들리지 않았다. 플러그인 구조라는 새로운 영역에서는 특히 이 순서가 중요했다.\n스키마는 추측하지 말고 검증하라. plugin.json의 author 필드 타입을 틀린 게 대표적이다. 새로운 포맷을 다룰 때는 예제나 스키마 정의를 먼저 확인해야 한다.\n실패한 호출이 기능을 만든다. 5번째 세션에서 스킬 호출이 실패한 경험이 /logblog:setup 스킬을 만드는 동기가 되었다. 사용자가 겪을 첫 경험을 직접 겪어보는 것, 이것이 가장 정확한 요구사항 수집이다.\n네이밍은 생태계를 따른다. /log-blog에서 /logblog:post로의 변경은 단순 이름 변경이 아니다. 플러그인 생태계의 네임스페이스 컨벤션을 따르는 것이다. 독자적 네이밍보다 생태계 관습을 따르는 편이 장기적으로 유리하다.\n","date":"2026-03-24T00:00:00+09:00","image":"/images/posts/2026-03-24-log-blog-dev3/cover.jpg","permalink":"/ko/posts/2026-03-24-log-blog-dev3/","title":"Log-Blog 개발기 #3 — 스킬에서 플러그인으로의 전환"},{"content":"개요 oh-my-openagent(이전 이름: oh-my-opencode)는 특정 LLM에 종속되지 않는 모델 불가지론(model-agnostic) 에이전트 오케스트레이터다. GitHub 스타 42,810개를 기록하며, TypeScript 기반 6M+ 라인 규모의 프로젝트로 성장했다.\n이전에 소개한 oh-my-claudecode(OMC)가 Claude Code 전용 확장이었다면, oh-my-openagent는 근본적으로 다른 접근을 취한다. Claude, GPT, Kimi, GLM, Gemini, Minimax 등 어떤 모델이든 하나의 인터페이스로 통합하는 것이 목표다.\n핵심 철학 — 벤더 종속의 거부 oh-my-openagent의 철학은 한 문장으로 요약된다:\n\u0026ldquo;Anthropic wants you locked in. Claude Code\u0026rsquo;s a nice prison, but it\u0026rsquo;s still a prison.\u0026rdquo;\nClaude Code는 훌륭한 도구다. 하지만 Anthropic 생태계 안에 사용자를 가두는 구조이기도 하다. 실제로 Anthropic은 이 프로젝트(당시 OpenCode) 때문에 API 접근을 차단한 전력이 있다. 이는 역설적으로 oh-my-openagent의 존재 이유를 증명해 주었다 — 단일 벤더에 의존하면 언제든 문이 닫힐 수 있다.\n이 프로젝트는 SUL-1.0 라이선스를 채택했다. 그리고 Sisyphus Labs에서 상용화 버전을 구축 중이다.\n구독 비용 비교 모델 불가지론 접근의 실질적 장점은 비용 최적화에서도 드러난다:\n서비스 월 비용 비고 ChatGPT $20 GPT-4o 기반 Kimi Code $0.99 가성비 최강 GLM $10 중간 가격대 Claude Pro $20 Claude Code 포함 하나의 도구로 이 모든 모델을 오가며 작업할 수 있다는 것이 핵심이다.\n아키텍처 oh-my-openagent의 킬러 피처는 ultrawork 커맨드다. 한 줄 명령으로 에이전트가 코드 분석, 수정, 테스트, 린팅까지 전체 워크플로우를 자동 수행한다.\ngraph TB USER[\"사용자\"] --\u003e|ultrawork 명령| ORCH[\"Agent Orchestrator\"] ORCH --\u003e ROUTER[\"Model Router\"] ROUTER --\u003e CLAUDE[\"Claude API\"] ROUTER --\u003e GPT[\"GPT API\"] ROUTER --\u003e KIMI[\"Kimi API\"] ROUTER --\u003e GLM[\"GLM API\"] ROUTER --\u003e GEMINI[\"Gemini API\"] ROUTER --\u003e MINIMAX[\"Minimax API\"] ORCH --\u003e TOOLS[\"Tool Layer\"] TOOLS --\u003e FS[\"파일 시스템\"] TOOLS --\u003e TERM[\"터미널 실행\"] TOOLS --\u003e LINT[\"린팅 / 테스트\"] ORCH --\u003e COMPAT[\"호환 레이어\"] COMPAT --\u003e CC[\"Claude Code\"] COMPAT --\u003e AMP[\"AmpCode\"] COMPAT --\u003e CURSOR[\"Cursor\"] style ORCH fill:#e1f5fe style ROUTER fill:#fff3e0 style COMPAT fill:#f3e5f5주요 구성 요소 Agent Orchestrator — 작업을 분석하고 최적의 모델과 도구 조합을 결정한다 Model Router — 작업 특성에 따라 Claude, GPT, Kimi 등 적절한 모델로 라우팅한다 Tool Layer — 파일 시스템 접근, 터미널 실행, 린팅/테스트 등 실제 작업을 수행한다 호환 레이어 — Claude Code, AmpCode, Cursor 등 기존 도구와의 통합을 지원한다 최근 커밋에서는 background-agent의 stale timeout 처리가 개선되었는데, 이는 장시간 실행되는 에이전트 작업의 안정성을 높이기 위한 것이다.\nOMC와의 비교 oh-my-claudecode(OMC)와 oh-my-openagent는 이름이 비슷하지만 철학과 범위가 완전히 다르다.\ngraph LR subgraph OMC[\"oh-my-claudecode (OMC)\"] direction TB OMC_STAR[\"GitHub Stars: 10,400\"] OMC_AUTHOR[\"by Yeachan-Heo\"] OMC_MODEL[\"Claude 전용\"] OMC_GOAL[\"Claude Code 경험 극대화\"] end subgraph OOA[\"oh-my-openagent\"] direction TB OOA_STAR[\"GitHub Stars: 42,810\"] OOA_AUTHOR[\"by code-yeongyu\"] OOA_MODEL[\"6+ 모델 지원\"] OOA_GOAL[\"모델 불가지론 오케스트레이션\"] end OMC -.-\u003e|\"Claude 생태계 내 최적화\"| CLAUDE_ONLY[\"단일 모델 심화\"] OOA -.-\u003e|\"벤더 독립 전략\"| MULTI_MODEL[\"다중 모델 통합\"] style OMC fill:#e8eaf6 style OOA fill:#e8f5e9 style CLAUDE_ONLY fill:#c5cae9 style MULTI_MODEL fill:#c8e6c9 항목 oh-my-claudecode (OMC) oh-my-openagent GitHub Stars 10,400 42,810 지원 모델 Claude 전용 Claude, GPT, Kimi, GLM, Gemini, Minimax 철학 Claude Code를 더 좋게 특정 모델에 종속되지 않겠다 킬러 피처 Claude 특화 프롬프트/워크플로우 ultrawork 통합 커맨드 언어 TypeScript TypeScript 접근 방식 단일 모델 심화 (depth) 다중 모델 통합 (breadth) 라이선스 MIT SUL-1.0 상용화 커뮤니티 주도 Sisyphus Labs 상용화 진행 OMC는 Claude가 최고의 모델이라는 전제 하에 Claude Code 경험을 극대화한다. oh-my-openagent는 어떤 모델이 최고인지는 작업마다 다르다는 전제 하에 모델 선택권을 사용자에게 돌려준다. 두 프로젝트는 경쟁이 아니라 서로 다른 질문에 대한 답이다.\n커뮤니티 반응 42,810개의 스타가 말해주듯, 커뮤니티의 반응은 폭발적이다. 몇 가지 실제 리뷰를 보자:\n\u0026ldquo;Cursor 구독을 취소했다\u0026rdquo; — 별도의 IDE 구독 없이 oh-my-openagent 하나로 충분하다는 의견 \u0026ldquo;하루 만에 ESLint 경고 8,000개를 처리했다\u0026rdquo; — ultrawork 커맨드의 자동화 능력을 보여주는 사례 \u0026ldquo;45,000줄짜리 Tauri 앱을 하룻밤 만에 SaaS로 전환했다\u0026rdquo; — 대규모 리팩터링에서의 생산성 이런 리뷰들의 공통점은 자동화 범위의 넓이다. 단순한 코드 완성이 아니라, 프로젝트 전체를 아우르는 작업을 한 번의 명령으로 수행할 수 있다는 점이 기존 도구와의 차별점이다.\n인사이트 — AI 코딩 생태계의 분기점 oh-my-openagent의 부상은 AI 코딩 도구 생태계에서 중요한 신호를 보내고 있다.\n1. 벤더 종속에 대한 피로감 Anthropic이 OpenCode를 차단한 사건은 개발자 커뮤니티에 경종을 울렸다. 아무리 좋은 도구라도 플랫폼 사업자의 한마디에 접근이 끊길 수 있다. oh-my-openagent의 42K+ 스타는 이 불안감에 대한 시장의 응답이다.\n2. \u0026ldquo;최고의 모델\u0026quot;은 없다 GPT가 잘하는 작업, Claude가 잘하는 작업, Kimi가 가성비 좋은 작업이 각각 다르다. 모델 불가지론 접근은 이 현실을 인정하고, 작업 특성에 따라 최적의 모델을 선택할 수 있게 해 준다.\n3. CLI 에이전트의 수렴 진화 Claude Code, Cursor, AmpCode 등 다양한 도구가 결국 비슷한 형태(터미널 기반 에이전트 + 도구 사용)로 수렴하고 있다. oh-my-openagent는 이 수렴을 한 발 앞서 읽고, 모든 도구를 하나의 인터페이스로 통합하는 메타 레이어를 구축했다.\n4. OMC와 oh-my-openagent, 양립 가능한 미래 단일 모델 심화(OMC)와 다중 모델 통합(oh-my-openagent)은 상호 배타적이지 않다. Claude가 주력 모델인 개발자는 OMC로 Claude 경험을 최적화하면서, oh-my-openagent로 다른 모델을 보조적으로 활용할 수 있다. 생태계가 성숙할수록 이런 레이어드 접근이 표준이 될 가능성이 높다.\nAI 코딩 도구의 경쟁이 \u0026ldquo;어떤 모델이 좋은가\u0026quot;에서 \u0026ldquo;어떻게 모델을 조합하는가\u0026quot;로 이동하고 있다. oh-my-openagent는 그 전환점에 서 있는 프로젝트다.\n","date":"2026-03-24T00:00:00+09:00","image":"/images/posts/2026-03-24-oh-my-opencode/cover.jpg","permalink":"/ko/posts/2026-03-24-oh-my-opencode/","title":"oh-my-opencode — 모델 불가지론 에이전트 오케스트레이터"},{"content":"개요 2024년 9월, 인프런 온라인 밋업에서 스포티파이 현직 데이터 엔지니어가 자신의 커리어 전환과 실무 경험을 공유했다. 네이버에서 4.5년간 Spring 백엔드 개발을 하다가 Scala + Spark 경험을 기반으로 스포티파이 데이터 엔지니어로 전환한 이야기였다. 약 1년이 지난 지금, 스포티파이 엔지니어링 블로그에는 하루 1.4조 데이터 포인트를 처리하는 플랫폼, AI 모델 증류 파이프라인, 멀티 에이전트 광고 시스템까지 — 데이터 엔지니어링의 범위가 극적으로 확장된 흔적이 남아있다. 밋업에서 들은 현장의 목소리와 공식 블로그의 기술 상세를 교차하면, 데이터 엔지니어라는 역할이 어디로 향하고 있는지 더 선명하게 보인다.\n밋업 핵심 내용 도메인 전환의 현실 발표자는 백엔드 엔지니어에서 데이터 엔지니어로 전환하면서 겪은 인식의 변화를 솔직하게 전했다. 데이터 엔지니어링이라고 하면 Spark 파이프라인을 떠올리기 쉽지만, 실제 업무의 상당 부분은 SQL 기반 프로덕트 개발, 데이터 모델링, 대시보드 설계에 집중된다.\n\u0026ldquo;데이터 생성자와 사용자를 이어주는 연결고리\u0026rdquo;\n이것이 발표자가 정의한 데이터 엔지니어의 본질이었다.\nEngineering vs Science 밋업에서 강조된 구분:\n구분 Data Engineering Data Science 핵심 활동 자동화, 최적화 가설 검증 주요 산출물 파이프라인, 데이터 모델 분석 리포트, 메트릭 설계 도구 SQL, Scala, dbt Python, Jupyter, 통계 모델 조직 구조 Platform Org: 백엔드 인프라, 대규모 수집 시스템, Schema Evolution, Data Warehouse Business Org: 도메인별 데이터 수집, 데이터 모델링, 품질 모니터링 Data Scientist: 분석, 메트릭 설계, 대시보드 현직자가 강조한 것들 SQL 유창함이 핵심이다 — 복잡한 프레임워크보다 SQL을 정확하게 쓰는 능력이 실무에서 더 중요하다 Nitpicking이 중요하다 — 데이터 품질은 사소한 불일치를 끈질기게 파고드는 데서 나온다 누구나 데이터에 접근한다 — BigQuery와 Jupyter를 통해 엔지니어가 아닌 사람도 직접 데이터를 탐색한다 AI가 검증과 이해를 대체하지 못한다 — 자동화가 아무리 발전해도 데이터를 이해하고 검증하는 역량은 사람의 몫이다 2026년 스포티파이 데이터 플랫폼 2024년 4월 스포티파이 엔지니어링 블로그에 공개된 플랫폼 규모는 밋업에서 언급된 수치를 구체화한다.\n규모 하루 1.4조(trillion) 데이터 포인트 처리 1,800개 이상의 이벤트 타입 수집 38,000개 이상의 활성 스케줄 파이프라인 운영 100명 이상의 엔지니어가 데이터 플랫폼 전담 밋업에서 언급된 하루 약 1,200억 건의 사용자 인터랙션 로그는 이 1.4조의 부분집합이다 플랫폼 아키텍처 graph TB subgraph Collection[\"Data Collection\"] A[\"클라이언트 이벤트\u0026lt;br/\u0026gt;1,800+ 타입\"] --\u003e B[\"Pub/Sub\"] B --\u003e C[\"Dataflow\u0026lt;br/\u0026gt;실시간 수집\"] end subgraph Processing[\"Data Processing\"] C --\u003e D[\"Apache Beam\u0026lt;br/\u0026gt;Scio (Scala)\"] D --\u003e E[\"BigQuery\u0026lt;br/\u0026gt;Data Warehouse\"] D --\u003e F[\"GCS\u0026lt;br/\u0026gt;Object Storage\"] end subgraph Management[\"Data Management\"] E --\u003e G[\"dbt\u0026lt;br/\u0026gt;데이터 모델링\"] G --\u003e H[\"Flyte / Styx\u0026lt;br/\u0026gt;오케스트레이션\"] H --\u003e I[\"38,000+\u0026lt;br/\u0026gt;스케줄 파이프라인\"] end subgraph Consumers[\"데이터 소비자\"] E --\u003e J[\"Jupyter\u0026lt;br/\u0026gt;탐색적 분석\"] E --\u003e K[\"대시보드\u0026lt;br/\u0026gt;비즈니스 메트릭\"] E --\u003e L[\"ML 파이프라인\u0026lt;br/\u0026gt;추천 / 개인화\"] end style Collection fill:#1DB954,color:#fff style Processing fill:#191414,color:#fff style Management fill:#535353,color:#fff style Consumers fill:#1DB954,color:#fff밋업에서 발표자가 설명한 Platform Org / Business Org 구분이 블로그에서는 Data Collection / Data Processing / Data Management 세 영역으로 구체화되어 있다. 공식적으로 나눈 세 영역은 다음과 같다:\nData Collection: 클라이언트 이벤트 수집, Schema Evolution, 실시간 스트리밍 Data Processing: 배치 및 스트리밍 파이프라인, 대규모 변환 Data Management: 메타데이터 관리, 데이터 카탈로그, 품질 모니터링 Wrapped 2025의 데이터 파이프라인 2026년 3월에 공개된 Wrapped 2025 기술 포스트는 데이터 엔지니어링과 AI가 만나는 지점을 보여준다.\n규모와 제약 3.5억 사용자에게 14억 개의 개인화 리포트 생성 개인별 청취 데이터를 기반으로 LLM이 자연어 요약을 생성 AI 모델 증류 파이프라인 Wrapped 팀은 흥미로운 접근을 취했다. Frontier 모델의 출력을 학습 데이터로 사용해 더 작고 빠른 모델을 fine-tuning하는 Model Distillation 방식이다.\ngraph LR A[\"Frontier Model\u0026lt;br/\u0026gt;고품질 출력 생성\"] --\u003e B[\"DPO 학습 데이터\u0026lt;br/\u0026gt;선호도 쌍 구성\"] B --\u003e C[\"Fine-tuned 소형 모델\u0026lt;br/\u0026gt;증류 완료\"] C --\u003e D[\"14억 리포트 생성\u0026lt;br/\u0026gt;3.5억 사용자\"] E[\"LLM-as-Judge\"] --\u003e |\"정확도, 안전성\u0026lt;br/\u0026gt;톤, 포맷 평가\"| C style A fill:#1DB954,color:#fff style C fill:#191414,color:#fff style D fill:#1DB954,color:#fff style E fill:#535353,color:#fff핵심 설계 결정들:\nDPO(Direct Preference Optimization): Frontier 모델의 좋은 출력과 나쁜 출력을 쌍으로 구성해 선호도 학습 LLM-as-Judge 평가: 정확도(accuracy), 안전성(safety), 톤(tone), 포맷(formatting) 네 축으로 품질 검증 Column-oriented Storage 설계: 3.5억 사용자의 동시 접근에서 Race Condition을 방지하기 위한 저장소 설계 \u0026ldquo;At this scale, the LLM call is the easy part.\u0026rdquo;\n이 한 문장이 데이터 엔지니어링의 본질을 관통한다. LLM API를 호출하는 것은 쉽다. 14억 건을 안정적으로, 정확하게, 안전하게 생성하고 전달하는 파이프라인 — 그것이 진짜 엔지니어링이다.\n멀티 에이전트 광고 아키텍처 2026년 2월에 공개된 멀티 에이전트 광고 시스템은 데이터 엔지니어링이 AI 에이전트 인프라로 확장되는 최전선을 보여준다.\n문제 광고 캠페인 기획에는 타겟 오디언스 설정, 예산 배분, 스케줄링, 미디어 포맷 선택 등 복잡한 의사결정이 필요하다. 기존에는 15~30분이 걸리던 수동 작업이다.\n해결: 6개의 전문 에이전트 graph TB User[\"광고주 요청\"] --\u003e Router[\"Router Agent\u0026lt;br/\u0026gt;요청 분류 및 라우팅\"] Router --\u003e Goal[\"GoalResolver\u0026lt;br/\u0026gt;캠페인 목표 해석\"] Router --\u003e Audience[\"AudienceResolver\u0026lt;br/\u0026gt;타겟 오디언스 설정\"] Router --\u003e Budget[\"Budget Agent\u0026lt;br/\u0026gt;예산 최적화\"] Router --\u003e Schedule[\"Schedule Agent\u0026lt;br/\u0026gt;일정 계획\"] Router --\u003e Media[\"MediaPlanner\u0026lt;br/\u0026gt;미디어 포맷 선택\"] Goal --\u003e Result[\"통합 캠페인 계획\u0026lt;br/\u0026gt;5-10초 내 완료\"] Audience --\u003e Result Budget --\u003e Result Schedule --\u003e Result Media --\u003e Result History[\"수천 건의\u0026lt;br/\u0026gt;과거 캠페인 데이터\"] -.-\u003e Router style Router fill:#1DB954,color:#fff style Result fill:#191414,color:#fff style History fill:#535353,color:#fff기술 스택 구성 요소 기술 Agent Framework Google ADK 0.2.0 LLM Vertex AI (Gemini 2.5 Pro) 통신 gRPC 학습 데이터 수천 건의 과거 캠페인 1530분 → 510초. 데이터 엔지니어링 관점에서 주목할 점은 에이전트 자체보다 그 뒤의 데이터 파이프라인이다. 수천 건의 과거 캠페인 데이터를 정제하고, 에이전트가 참조할 수 있는 형태로 구조화하고, 실시간으로 서빙하는 것 — 이것이 데이터 엔지니어의 영역이다.\n데이터 엔지니어 스킬트리 2026 밋업에서 언급된 기술 스택과 2026년 채용 공고를 교차하면, 현재 스포티파이 데이터 엔지니어에게 요구되는 역량이 선명해진다.\n2024년 밋업 vs 2026년 채용 비교 영역 2024 밋업 언급 2026 채용 요구 언어 SQL, Scala, Python SQL, Python, Scala (순서 변화 주목) 처리 엔진 Spark Spark, Apache Beam, Scio, Flink 클라우드 GCP, BigQuery, GCS GCP, BigQuery, Dataflow, GCS 오케스트레이션 언급 없음 Flyte, Styx AI/ML 간접 언급 LLM 파이프라인, Model Distillation 에이전트 없음 Multi-Agent 인프라 1년 사이에 Apache Beam / Scio / Flink가 Spark와 나란히 필수로 올라왔고, LLM 파이프라인과 에이전트 인프라가 데이터 엔지니어 영역에 진입했다.\n인사이트: 1년간의 변화 밋업의 예언이 맞았다 발표자가 강조한 \u0026ldquo;AI가 검증과 이해를 대체하지 못한다\u0026quot;는 메시지는 Wrapped 2025의 사례에서 정확히 입증되었다. LLM-as-Judge를 도입했지만, 그 평가 기준(정확도, 안전성, 톤, 포맷)을 설계하고 파이프라인에 통합하는 것은 결국 엔지니어의 몫이었다.\n데이터 엔지니어의 범위 확장 2024년 밋업에서 데이터 엔지니어는 \u0026ldquo;데이터 생성자와 사용자를 이어주는 연결고리\u0026quot;였다. 2026년에는 그 사용자에 AI 에이전트가 추가되었다. 에이전트에게 데이터를 서빙하고, 에이전트의 출력을 검증하고, 에이전트 시스템의 데이터 파이프라인을 구축하는 것이 새로운 업무 영역이 되었다.\n변하지 않는 것 규모가 1,200억에서 1.4조로 10배 이상 커졌고, AI 에이전트와 LLM 파이프라인이 등장했지만, 발표자가 강조한 세 가지는 여전히 유효하다:\nSQL 유창함 — BigQuery가 여전히 중심이고, dbt가 데이터 모델링의 표준이다 Nitpicking — 14억 건의 Wrapped 리포트에서 하나의 오류도 허용되지 않는다 연결고리로서의 정체성 — 생성자와 사용자 사이, 이제는 생성자와 에이전트 사이까지 밋업에서 들은 현직자의 목소리와 1년 후의 공식 기술 블로그를 겹쳐보면, 데이터 엔지니어링은 단순히 파이프라인을 만드는 일에서 AI 시대의 데이터 인프라를 설계하는 일로 진화하고 있다. 그리고 그 중심에는 여전히 — 데이터를 정확하게 이해하고, 끈질기게 검증하는 사람이 있다.\n","date":"2026-03-24T00:00:00+09:00","image":"/images/posts/2026-03-24-spotify-data-engineering/cover.jpg","permalink":"/ko/posts/2026-03-24-spotify-data-engineering/","title":"스포티파이 데이터 엔지니어링 — 현직자 밋업 리뷰와 2026년 플랫폼 진화"},{"content":"개요 2007년에 탄생한 tmux는 19년간 서버 관리와 개발 환경의 핵심 도구로 자리잡았다. 최근 Claude Code의 Agent Team 기능이 tmux 위에서 병렬 에이전트를 생성하면서 다시 주목받고 있다. 한편, Manaflow AI가 만든 cmux는 \u0026ldquo;AI 에이전트를 위한 터미널\u0026quot;이라는 콘셉트로 등장했다. Ghostty의 렌더링 엔진(libghostty)을 기반으로 한 네이티브 macOS 앱이다.\n이 글에서는 두 도구의 아키텍처, 핵심 개념, AI 에이전트 지원 방식을 비교하고, 실전에서 어떻게 조합하면 좋은지 정리한다.\n아키텍처 비교 두 도구는 근본적으로 다른 설계 철학을 갖고 있다.\ngraph LR subgraph tmux[\"tmux (Server-Client)\"] S[\"tmux server\"] --\u003e C1[\"Client 1\"] S --\u003e C2[\"Client 2\"] S --\u003e C3[\"Client 3\"] S --\u003e SE1[\"Session 1\"] S --\u003e SE2[\"Session 2\"] SE1 --\u003e W1[\"Window 1\"] SE1 --\u003e W2[\"Window 2\"] W1 --\u003e P1[\"Pane 1\"] W1 --\u003e P2[\"Pane 2\"] end subgraph cmux[\"cmux (Native macOS App)\"] APP[\"cmux.app \u0026lt;br/\u0026gt; Swift + AppKit\"] --\u003e WS1[\"Workspace 1 \u0026lt;br/\u0026gt; git branch, PR, ports\"] APP --\u003e WS2[\"Workspace 2\"] WS1 --\u003e SF1[\"Surface 1\"] WS1 --\u003e SF2[\"Surface 2\"] SF1 --\u003e PA1[\"Pane A\"] SF1 --\u003e PA2[\"Pane B\"] end 항목 tmux cmux 유형 Terminal multiplexer AI agent terminal 아키텍처 Server-client Native macOS app OS 지원 Cross-platform (Linux, macOS, BSD, Solaris) macOS 14.0+ only UI TUI (텍스트 기반) GUI (네이티브 AppKit) 렌더링 자체 TUI Ghostty 엔진 (libghostty) 라이선스 ISC AGPL tmux는 서버 프로세스가 모든 세션을 관리하고, 클라이언트가 접속해서 보는 구조다. 터미널을 닫아도 서버가 살아있으면 세션이 유지된다. cmux는 macOS 네이티브 앱으로, 사이드바에 워크스페이스별 git branch, PR 상태, 열린 포트, 알림 등 메타데이터를 시각적으로 표시한다.\n핵심 개념 매핑 두 도구의 계층 구조는 대응 관계가 명확하다.\ntmux cmux 설명 Session Workspace 최상위 작업 단위 Window Surface Session/Workspace 안의 탭 Pane Pane 화면 분할 영역 조작 방식의 차이 tmux는 prefix key 방식이다. Ctrl+b를 먼저 누르고 명령 키를 입력한다. 학습 곡선이 가파르지만 키보드만으로 모든 조작이 가능하다.\ncmux는 macOS 네이티브 단축키를 사용한다. prefix 없이 바로 동작한다.\n동작 tmux cmux 새 세션/워크스페이스 tmux new -s name Cmd+N 수평 분할 Ctrl+b % Cmd+D 수직 분할 Ctrl+b \u0026quot; Cmd+Shift+D 새 윈도우/서피스 Ctrl+b c Cmd+T 세션 목록 Ctrl+b s 사이드바에 항상 표시 AI 에이전트 지원 이 부분이 두 도구의 가장 큰 차이점이다.\nflowchart TB subgraph tmux_flow[\"tmux + AI Agent\"] A1[\"Claude Code \u0026lt;br/\u0026gt; Agent Team\"] --\u003e|\"tmux new-session\"| A2[\"tmux session\"] A2 --\u003e|\"tmux send-keys\"| A3[\"Agent Pane 1\"] A2 --\u003e|\"tmux send-keys\"| A4[\"Agent Pane 2\"] A2 --\u003e|\"tmux send-keys\"| A5[\"Agent Pane 3\"] A3 --\u003e|\"tmux capture-pane\"| A6[\"결과 수집\"] A4 --\u003e|\"tmux capture-pane\"| A6 A5 --\u003e|\"tmux capture-pane\"| A6 end subgraph cmux_flow[\"cmux + AI Agent\"] B1[\"AI Agent\"] --\u003e|\"cmux new-workspace\"| B2[\"Workspace\"] B2 --\u003e|\"cmux split\"| B3[\"Pane A\"] B2 --\u003e|\"cmux split\"| B4[\"Pane B\"] B3 --\u003e|\"cmux send\"| B5[\"명령 실행\"] B4 --\u003e|\"cmux read-screen\"| B6[\"다른 Pane 읽기 \u0026lt;br/\u0026gt; (inter-agent 통신)\"] B2 --\u003e|\"알림 시스템\"| B7[\"macOS 알림 \u0026lt;br/\u0026gt; + 파란 링 표시 \u0026lt;br/\u0026gt; + unread 뱃지\"] endtmux의 AI 에이전트 활용 tmux는 원래 AI를 위해 설계된 도구가 아니다. 하지만 프로그래밍 가능한 API를 통해 AI 도구들이 활용하고 있다.\nClaude Code: Agent Team 기능에서 tmux 세션을 생성해 병렬 에이전트를 구동 Codex, Gemini CLI: 비슷한 방식으로 tmux를 활용 tmux send-keys로 명령 전송, tmux capture-pane으로 출력 수집 cmux의 네이티브 AI 지원 cmux는 처음부터 AI 에이전트를 위해 설계되었다.\n알림 시스템: 입력 대기 중인 pane에 파란 링 표시, 워크스페이스 탭에 unread 뱃지, macOS 데스크톱 알림까지 지원. Cmd+Shift+U로 가장 최근 알림으로 점프. read-screen: 한 pane이 다른 pane의 내용을 읽을 수 있다. 에이전트 간 통신의 핵심 기능이다. send: 다른 pane에 프로그래밍 방식으로 명령을 전송한다. 환경 변수: CMUX_WORKSPACE_ID, CMUX_SURFACE_ID, CMUX_SOCKET_PATH — 에이전트가 자신의 컨텍스트를 자동으로 인식한다. 내장 브라우저: 터미널 안에서 웹 페이지를 열 수 있다. CLI 자동화 비교 # tmux — 프로그래밍 방식 제어 tmux new-session -d -s work tmux split-window -h tmux send-keys -t work:0.1 \u0026#34;npm run dev\u0026#34; Enter tmux capture-pane -t work:0.0 -p # cmux — AI 에이전트 전용 CLI cmux new-workspace cmux split --direction right cmux send --pane-id $CMUX_PANE_ID \u0026#34;npm run dev\u0026#34; cmux read-screen --pane-id $TARGET_PANE_ID \u0026ldquo;Primitive, Not Solution\u0026rdquo; 철학 cmux의 핵심 설계 철학은 **\u0026ldquo;Primitive, Not Solution\u0026rdquo;**이다. 완성된 워크플로우를 제공하는 대신, read-screen, send, 알림 같은 저수준 빌딩 블록을 제공한다. AI 에이전트가 이 요소들을 조합해서 자신만의 워크플로우를 구성하도록 맡긴다.\n이 접근 방식은 다양한 AI 도구와의 호환성을 높이고, 에이전트의 자율성을 극대화한다.\n경쟁 도구 현황 AI 에이전트 터미널 분야는 빠르게 성장하고 있다.\n도구 특징 cmux 네이티브 macOS, Ghostty 기반, read-screen Claude Squad GitHub 기반 에이전트 오케스트레이션 Pane AI 에이전트용 터미널 Amux AI 중심 멀티플렉서 Calyx 신생 경쟁자 실전 권장 조합: tmux + cmux 결론적으로, tmux와 cmux는 대체 관계가 아니라 보완 관계다.\ntmux: 세션 영속성(서버 기반), 크로스 플랫폼 지원, 원격 서버 작업 cmux: GUI 시각화, AI 에이전트 알림, inter-agent 통신 (read-screen) 로컬 macOS 환경에서 AI 에이전트를 활용한 개발을 할 때는 cmux를 메인으로 사용하되, 원격 서버 작업이나 세션 영속성이 필요한 경우 tmux를 함께 사용하는 것이 현재로서는 가장 효과적인 조합이다.\n설치 # tmux brew install tmux # cmux brew tap manaflow-ai/cmux \u0026amp;\u0026amp; brew install --cask cmux 빠른 링크 tmux GitHub — 43,430 stars, C 기반 오픈소스 cmux 공식 사이트 — Manaflow AI cmux: 코딩 에이전트를 위한 터미널 — Dale Seo — 실전 가이드 tmux vs cmux 비교 — goddaehee — 설치부터 경쟁 도구까지 TMUX 마스터클래스 — YouTube 인사이트 tmux는 19년 동안 검증된 안정성과 크로스 플랫폼 지원이 강점이다. 원격 서버, CI/CD, 세션 영속성이 필요한 모든 시나리오에서 여전히 최고의 선택이다. cmux는 AI 에이전트 시대에 맞게 설계된 도구로, 알림 시스템과 read-screen 기능이 멀티 에이전트 워크플로우에 최적화되어 있다. 두 도구는 대체 관계가 아니라 보완 관계다. tmux가 \u0026ldquo;세션이 죽지 않는 인프라\u0026quot;라면, cmux는 \u0026ldquo;에이전트가 서로 대화하는 인터페이스\u0026quot;다. AI 코딩 도구가 tmux 위에서 에이전트를 스폰하고, cmux가 그 에이전트들의 상태를 시각적으로 관리하는 조합이 현재로서는 가장 강력한 터미널 환경이다.\n","date":"2026-03-23T00:00:00+09:00","image":"/images/posts/2026-03-23-tmux-cmux/cover.jpg","permalink":"/ko/posts/2026-03-23-tmux-cmux/","title":"tmux vs cmux — 전통의 터미널 멀티플렉서와 AI 에이전트 시대의 터미널"},{"content":"개요 2007년 Nicolas Marriott이 만든 tmux는 19년이 지난 지금도 터미널 환경의 핵심 인프라로 자리잡고 있다. 최근 Claude Code의 Agent Team 기능이 tmux 위에서 병렬 에이전트를 스폰하면서, AI 코딩 에이전트 시대에 다시 한번 강력한 주목을 받고 있다. Codex, Gemini CLI, OpenCode 등 터미널 기반 코딩 에이전트들도 tmux의 프로그래밍 가능한 API를 적극 활용한다.\n이 글에서는 tmux의 아키텍처부터 세션/윈도우/패인 관리, 커스터마이징, 플러그인 생태계, 그리고 AI 에이전트와의 연동까지 한 편으로 완전 정복한다. tmux vs cmux 비교는 별도 포스트에서 다루고 있으므로, 이 글에서는 tmux 자체에 대한 딥다이브에 집중한다.\n터미널 에뮬레이터 vs 터미널 멀티플렉서 tmux를 이해하려면 먼저 터미널 에뮬레이터와 터미널 멀티플렉서의 근본적 차이를 알아야 한다.\ngraph TB subgraph emulator[\"터미널 에뮬레이터\"] direction TB E[\"터미널 앱 \u0026lt;br/\u0026gt; iTerm2, Ghostty, \u0026lt;br/\u0026gt; Warp, Kitty, Alacritty\"] E --\u003e|\"직접 연결\"| SH1[\"Shell 1\"] E --\u003e|\"직접 연결\"| SH2[\"Shell 2\"] E --\u003e|\"앱 종료 시\"| X[\"Shell도 함께 종료\"] end subgraph multiplexer[\"터미널 멀티플렉서\"] direction TB T[\"터미널 앱\"] --\u003e|\"접속\"| TC[\"tmux Client\"] TC --\u003e|\"연결\"| TS[\"tmux Server\"] TS --\u003e|\"관리\"| S1[\"Shell 1\"] TS --\u003e|\"관리\"| S2[\"Shell 2\"] T2[\"앱 종료\"] -.-\u003e|\"서버는 살아있음\"| TS end터미널 에뮬레이터는 화면을 그려주는 앱이다. iTerm2, Ghostty, Warp, Kitty, Alacritty 등이 여기에 해당한다. 쉘에 직접 연결되므로, 앱을 닫으면 실행 중이던 프로세스와 세션이 모두 사라진다.\n터미널 멀티플렉서는 세션을 관리하는 서버다. tmux와 screen이 대표적이다. 터미널 에뮬레이터 위에서 동작하며, 서버-클라이언트 구조 덕분에 터미널 앱을 닫아도 세션이 유지된다.\n터미널 에뮬레이터는 \u0026ldquo;화면을 그려주는 앱\u0026quot;이고, 터미널 멀티플렉서는 \u0026ldquo;세션을 관리하는 서버\u0026quot;다. 멀티플렉서를 쓰면 탭 관리, 화면 분할, 세션 관리를 터미널 에뮬레이터가 아니라 멀티플렉서가 전부 담당하게 된다.\n이 구조적 차이 때문에 tmux를 사용할 때 터미널 에뮬레이터에서 가장 중요한 기준은 얼마나 가볍고 빠른지다. 탭 관리나 화면 분할 같은 기능은 tmux가 다 해주므로, 터미널 앱 자체는 빠른 렌더링에 집중하면 된다.\ntmux 아키텍처 tmux는 서버-클라이언트 모델로 동작한다. 이 구조가 tmux의 모든 강점 \u0026ndash; 세션 영속성, 다중 클라이언트 접속, 프로그래밍 가능한 제어 \u0026ndash; 의 근간이다.\n서버-클라이언트 모델 ┌─────────────────────────────────────────────────┐ │ tmux server │ │ (백그라운드 프로세스, 모든 세션을 관리) │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Session 0│ │ Session 1│ │ Session 2│ │ │ │ frontend │ │ backend │ │ devops │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └─────────────┬──────────┬──────────┬─────────────┘ │ │ │ ┌──────┘ ┌─────┘ ┌────┘ ▼ ▼ ▼ Client A Client B Client C (iTerm2) (Ghostty) (SSH) tmux server: tmux 명령을 처음 실행하면 백그라운드에 서버 프로세스가 시작된다. 이 서버가 모든 세션, 윈도우, 패인을 관리한다. tmux client: 사용자가 보는 화면이다. 서버에 접속해서 특정 세션의 내용을 표시한다. 소켓 통신: 클라이언트와 서버는 Unix 소켓(/tmp/tmux-{uid}/default)으로 통신한다. 세션 영속성 이 구조의 핵심 이점은 세션 영속성이다.\nGhostty에서 tmux를 실행하고 Claude Code와 개발 서버를 띄워 놓는다 Ghostty를 완전히 종료한다 Ghostty를 다시 열고 tmux attach를 입력한다 Claude Code와 개발 서버가 그대로 살아있다 터미널 에뮬레이터는 사라졌지만, tmux 서버가 백그라운드에서 모든 프로세스를 계속 관리하고 있었기 때문이다. SSH 접속이 끊겨도, 노트북 덮개를 닫았다 열어도, tmux 세션은 유지된다.\n설치 및 초기 설정 설치 # macOS brew install tmux # Ubuntu/Debian sudo apt install tmux # Fedora sudo dnf install tmux # 버전 확인 tmux -V 첫 실행 # 새 세션 시작 (이름 자동 부여: 0, 1, 2...) tmux # 이름을 지정해서 세션 시작 tmux new-session -s work # 축약형 tmux new -s work 기본 설정 파일 tmux 설정은 ~/.tmux.conf에 작성한다. 최소한의 필수 설정부터 시작하자.\n# ~/.tmux.conf — 최소 필수 설정 # 스크롤백 히스토리 확장 (기본 2,000줄 → 50,000줄) set -g history-limit 50000 # 마우스 지원 활성화 set -g mouse on # 윈도우/패인 인덱스를 1부터 시작 (0은 키보드 왼쪽 끝이라 불편) set -g base-index 1 setw -g pane-base-index 1 설정 파일 수정 후 적용하는 방법:\n# tmux 내부에서 설정 리로드 tmux source-file ~/.tmux.conf # 또는 prefix + : 로 명령 모드 진입 후 source-file ~/.tmux.conf 핵심 개념: Session, Window, Pane tmux는 3계층 구조로 이루어져 있다.\ngraph TD SERVER[\"tmux server\"] --\u003e S1[\"Session: frontend\"] SERVER --\u003e S2[\"Session: backend\"] S1 --\u003e W1[\"Window 0: editor\"] S1 --\u003e W2[\"Window 1: terminal\"] S1 --\u003e W3[\"Window 2: logs\"] S2 --\u003e W4[\"Window 0: api\"] S2 --\u003e W5[\"Window 1: db\"] W1 --\u003e P1[\"Pane 0 \u0026lt;br/\u0026gt; vim\"] W1 --\u003e P2[\"Pane 1 \u0026lt;br/\u0026gt; file tree\"] W2 --\u003e P3[\"Pane 0 \u0026lt;br/\u0026gt; zsh\"] W3 --\u003e P4[\"Pane 0 \u0026lt;br/\u0026gt; tail -f app.log\"] W3 --\u003e P5[\"Pane 1 \u0026lt;br/\u0026gt; tail -f error.log\"] W4 --\u003e P6[\"Pane 0 \u0026lt;br/\u0026gt; npm run dev\"] W4 --\u003e P7[\"Pane 1 \u0026lt;br/\u0026gt; claude\"] W5 --\u003e P8[\"Pane 0 \u0026lt;br/\u0026gt; psql\"] 계층 설명 비유 Session 최상위 작업 단위. 독립된 프로젝트나 작업 맥락 데스크톱의 가상 데스크톱 Window 세션 안의 탭. 하나의 전체 화면 브라우저의 탭 Pane 윈도우 안의 분할 영역. 각각 독립된 쉘 IDE의 분할 패널 하나의 세션 안에 여러 윈도우를 만들 수 있고, 하나의 윈도우 안에 여러 패인을 분할할 수 있다. tmux 하단 상태 바에서 현재 세션 이름과 윈도우 목록을 확인할 수 있다.\nPrefix Key 시스템 tmux의 모든 단축키는 prefix key를 먼저 누른 뒤 명령 키를 입력하는 방식이다. 기본 prefix는 Ctrl+b다.\n컨트롤 B라는 예약어가 좀 불편하다. 키보드에서 컨트롤 B를 입력하는 게 좀 불편하기 때문에 컨트롤 스페이스로 키 매핑을 해 두고 사용하고 있다.\n즉, Ctrl+b 를 누르고 손을 떼고, 그 다음에 명령 키를 누르면 된다. 동시에 누르는 것이 아니다.\n완전 단축키 레퍼런스 세션 관련 단축키 동작 Prefix + d 현재 세션에서 detach (나가기) Prefix + s 세션 목록 보기 Prefix + $ 현재 세션 이름 변경 Prefix + ( 이전 세션으로 전환 Prefix + ) 다음 세션으로 전환 Prefix + : new 새 세션 생성 (tmux 내부에서) 윈도우 관련 단축키 동작 Prefix + c 새 윈도우 생성 Prefix + w 윈도우 목록 보기 (세션 포함, 트리 뷰) Prefix + , 현재 윈도우 이름 변경 Prefix + n 다음 윈도우로 이동 Prefix + p 이전 윈도우로 이동 Prefix + 0~9 해당 번호의 윈도우로 직접 이동 Prefix + \u0026amp; 현재 윈도우 닫기 (확인 메시지 있음) Prefix + l 마지막으로 사용한 윈도우로 전환 패인 관련 단축키 동작 Prefix + % 수평 분할 (좌우로 나누기) Prefix + \u0026quot; 수직 분할 (상하로 나누기) Prefix + 방향키 해당 방향의 패인으로 이동 Prefix + o 다음 패인으로 순환 이동 Prefix + z 현재 패인 줌 토글 (전체 화면 ↔ 원래 크기) Prefix + x 현재 패인 닫기 (확인 메시지 있음) Prefix + q 패인 번호 표시 (번호 입력으로 이동) Prefix + { 현재 패인을 이전 위치로 swap Prefix + } 현재 패인을 다음 위치로 swap Prefix + Space 패인 레이아웃 순환 변경 Prefix + ! 현재 패인을 새 윈도우로 분리 기타 단축키 동작 Prefix + : 명령 모드 진입 Prefix + ? 모든 키 바인딩 목록 보기 Prefix + t 시계 표시 Prefix + [ 복사 모드 진입 (스크롤 가능) 세션 관리 세션 생성 # 터미널에서 새 세션 생성 tmux new -s frontend tmux new -s backend tmux new -s devops # 세션 생성 + 첫 윈도우 이름 지정 tmux new -s work -n editor # 세션 생성하되 attach하지 않기 (백그라운드) tmux new -d -s background-job tmux 윈도우 내부에서 새 세션을 생성하려면:\nPrefix + : → new -s session-name 세션 목록 확인 # 터미널에서 tmux ls tmux list-sessions # tmux 내부에서 Prefix + s # 세션 목록 (방향키로 선택) Prefix + w # 윈도우까지 펼쳐진 전체 목록 Prefix + w가 Prefix + s보다 더 실용적이다. 세션뿐 아니라 그 안의 윈도우까지 트리 형태로 보여주기 때문이다. 목록에서 좌측 인덱스 번호를 직접 입력하면 해당 항목으로 즉시 이동할 수 있다.\n세션 전환 (Attach/Detach) # 세션에서 나가기 (세션은 살아있음) Prefix + d # 특정 세션에 다시 접속 tmux attach -t frontend tmux a -t frontend # 축약형 tmux a # 마지막 세션에 접속 # 세션이 하나뿐이면 tmux a 세션 이름 변경 및 종료 # tmux 내부에서 현재 세션 이름 변경 Prefix + $ # 터미널에서 세션 종료 tmux kill-session -t old-session # 모든 세션 종료 tmux kill-server 윈도우 관리 윈도우는 세션 안의 \u0026ldquo;탭\u0026quot;에 해당한다. 하단 상태 바에 윈도우 목록이 표시된다.\n윈도우 생성 및 전환 # 새 윈도우 생성 Prefix + c # 윈도우 간 이동 Prefix + n # 다음 윈도우 Prefix + p # 이전 윈도우 Prefix + 0 # 0번 윈도우로 직접 이동 Prefix + 1 # 1번 윈도우로 직접 이동 Prefix + l # 마지막으로 사용한 윈도우로 토글 # 윈도우 이름 변경 Prefix + , 윈도우 검색 및 이동 # 윈도우 찾기 (이름으로 검색) Prefix + f # 윈도우를 다른 세션으로 이동 Prefix + : → move-window -t target-session # 윈도우 순서 변경 Prefix + : → swap-window -t 0 패인 관리 패인은 윈도우 안의 분할 영역이다. 각 패인은 독립된 쉘을 실행한다.\n패인 분할 # 수평 분할 (좌우) Prefix + % # 수직 분할 (상하) Prefix + \u0026#34; 패인 이동 # 방향키로 이동 Prefix + ↑↓←→ # 순환 이동 Prefix + o # 패인 번호로 이동 Prefix + q → 번호 입력 패인 크기 조절 # 방향키로 미세 조절 (prefix + 방향키를 반복) Prefix + Ctrl+↑ # 위로 1칸 확장 Prefix + Ctrl+↓ # 아래로 1칸 확장 Prefix + Ctrl+← # 왼쪽으로 1칸 확장 Prefix + Ctrl+→ # 오른쪽으로 1칸 확장 # 마우스로 드래그 (mouse on 설정 시) # 패인 경계선을 마우스로 잡아 끌기 # 균등 분할 레이아웃 순환 Prefix + Space 패인 줌 (전체 화면 토글) # 현재 패인을 윈도우 전체 크기로 확대/축소 Prefix + z 특정 패인의 출력을 자세히 봐야 할 때 유용하다. 다시 Prefix + z를 누르면 원래 분할 상태로 돌아온다.\n패인 스왑 및 레이아웃 # 패인 위치 교환 Prefix + { # 이전 패인과 교환 Prefix + } # 다음 패인과 교환 # 현재 패인을 새 윈도우로 분리 Prefix + ! # 프리셋 레이아웃 순환 (even-horizontal, even-vertical, main-horizontal, main-vertical, tiled) Prefix + Space 커스터마이징 (.tmux.conf) 권장 설정 파일 # ~/.tmux.conf — 실전 설정 # ────────────────────────────────────── # 기본 설정 # ────────────────────────────────────── # Prefix 키 변경: Ctrl+b → Ctrl+Space set -g prefix C-Space unbind C-b bind C-Space send-prefix # 스크롤백 히스토리 (기본 2,000 → 50,000) set -g history-limit 50000 # 마우스 지원 set -g mouse on # 윈도우/패인 번호를 1부터 set -g base-index 1 setw -g pane-base-index 1 # 윈도우 닫으면 번호 재정렬 set -g renumber-windows on # ESC 지연 제거 (Vim/Neovim 사용자 필수) set -sg escape-time 0 # 256 색상 지원 set -g default-terminal \u0026#34;tmux-256color\u0026#34; set -ga terminal-overrides \u0026#34;,xterm-256color:Tc\u0026#34; # ────────────────────────────────────── # 패인 분할 키 변경 (직관적으로) # ────────────────────────────────────── # | 로 수평 분할, - 로 수직 분할 bind | split-window -h -c \u0026#34;#{pane_current_path}\u0026#34; bind - split-window -v -c \u0026#34;#{pane_current_path}\u0026#34; # 새 윈도우도 현재 경로에서 열기 bind c new-window -c \u0026#34;#{pane_current_path}\u0026#34; # ────────────────────────────────────── # Vi 스타일 패인 이동 # ────────────────────────────────────── bind h select-pane -L bind j select-pane -D bind k select-pane -U bind l select-pane -R # Alt + hjkl로 패인 이동 (prefix 없이) bind -n M-h select-pane -L bind -n M-j select-pane -D bind -n M-k select-pane -U bind -n M-l select-pane -R # ────────────────────────────────────── # 패인 크기 조절 # ────────────────────────────────────── bind -r H resize-pane -L 5 bind -r J resize-pane -D 5 bind -r K resize-pane -U 5 bind -r L resize-pane -R 5 # ────────────────────────────────────── # 복사 모드 (Vi 스타일) # ────────────────────────────────────── setw -g mode-keys vi bind -T copy-mode-vi v send-keys -X begin-selection bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel \u0026#34;pbcopy\u0026#34; # ────────────────────────────────────── # 상태 바 커스터마이징 # ────────────────────────────────────── set -g status-style \u0026#34;bg=#1e1e2e,fg=#cdd6f4\u0026#34; set -g status-left \u0026#34;#[fg=#89b4fa,bold] #S \u0026#34; set -g status-right \u0026#34;#[fg=#a6adc8] %Y-%m-%d %H:%M \u0026#34; set -g status-left-length 30 # 활성 윈도우 강조 setw -g window-status-current-style \u0026#34;fg=#89b4fa,bold\u0026#34; # ────────────────────────────────────── # 설정 리로드 단축키 # ────────────────────────────────────── bind r source-file ~/.tmux.conf \\; display-message \u0026#34;Config reloaded!\u0026#34; 주요 커스터마이징 포인트 Prefix 키 변경: 기본 Ctrl+b는 Vim의 Page Up과 충돌하고 손가락 위치상 불편하다. Ctrl+Space나 Ctrl+a(screen 호환)로 바꾸는 개발자가 많다.\nhistory-limit: 기본 2,000줄은 개발 서버 로그를 보기에 턱없이 부족하다. 50,000줄 이상으로 설정하는 것을 권장한다.\nmouse on: 마우스로 패인 클릭 전환, 경계선 드래그 리사이즈, 스크롤이 가능해진다. tmux 입문자에게 필수 설정이다.\npane_current_path: 패인을 분할하거나 새 윈도우를 열 때 현재 작업 디렉토리를 유지한다. 이 설정 없이는 매번 홈 디렉토리에서 시작해서 cd를 반복해야 한다.\n플러그인 생태계 (TPM) TPM (Tmux Plugin Manager) 설치 git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm ~/.tmux.conf에 추가:\n# 플러그인 목록 set -g @plugin \u0026#39;tmux-plugins/tpm\u0026#39; set -g @plugin \u0026#39;tmux-plugins/tmux-sensible\u0026#39; set -g @plugin \u0026#39;tmux-plugins/tmux-resurrect\u0026#39; set -g @plugin \u0026#39;tmux-plugins/tmux-continuum\u0026#39; set -g @plugin \u0026#39;tmux-plugins/tmux-yank\u0026#39; set -g @plugin \u0026#39;catppuccin/tmux\u0026#39; # TPM 초기화 (설정 파일 맨 아래에 위치해야 함) run \u0026#39;~/.tmux/plugins/tpm/tpm\u0026#39; 플러그인 설치: Prefix + I (대문자 I)\n추천 플러그인 플러그인 설명 tmux-sensible 범용적인 기본 설정 모음 (history-limit, escape-time 등) tmux-resurrect 세션 상태 저장/복원. 재부팅 후에도 세션 복구 가능 tmux-continuum resurrect를 자동으로 주기적 저장. tmux 시작 시 자동 복원 tmux-yank 시스템 클립보드 연동 복사 tmux-open 복사 모드에서 URL을 브라우저로 열기 catppuccin/tmux Catppuccin 테마 (상태 바 미화) tmux-fzf fzf를 활용한 세션/윈도우/패인 검색 tmux-resurrect + tmux-continuum 이 조합은 tmux의 세션 영속성을 한 단계 더 강화한다. tmux 서버 자체가 종료되거나 시스템이 재부팅되어도 세션 구조를 복원할 수 있다.\n# tmux-resurrect 설정 set -g @resurrect-capture-pane-contents \u0026#39;on\u0026#39; set -g @resurrect-strategy-nvim \u0026#39;session\u0026#39; # tmux-continuum 설정 set -g @continuum-restore \u0026#39;on\u0026#39; # tmux 시작 시 자동 복원 set -g @continuum-save-interval \u0026#39;15\u0026#39; # 15분마다 자동 저장 추천 터미널 에뮬레이터 tmux는 어떤 터미널 에뮬레이터에서든 동작하지만, tmux를 사용할 때는 터미널 앱의 기본 성능이 중요하다. 탭 관리, 화면 분할 등은 tmux가 담당하므로 터미널 앱은 빠른 렌더링에 집중하면 된다.\nGhostty 현재 tmux와 조합하기에 가장 추천하는 터미널 에뮬레이터는 Ghostty다.\nGPU 가속 렌더링: 대량의 출력도 빠르게 처리 낮은 리소스 사용: CPU와 메모리 점유율이 매우 낮음 네이티브 UI: macOS에서 네이티브 앱처럼 동작 검증된 렌더링 엔진: cmux(Sixworks)도 Ghostty의 libghostty 기반 Ghostty 설치:\nbrew install --cask ghostty 기타 터미널 에뮬레이터와의 호환 터미널 tmux 호환성 특징 Ghostty 우수 GPU 가속, 경량 iTerm2 우수 tmux integration 모드 지원 Alacritty 우수 GPU 가속, 설정 파일 기반 Kitty 우수 GPU 가속, 자체 분할 기능 WezTerm 우수 Lua 스크립팅 Warp 보통 AI 기능 내장, 자체 분할 선호 AI 코딩 에이전트와 tmux 왜 AI 에이전트가 tmux를 사용하는가 tmux가 AI 에이전트 시대에 다시 주목받는 핵심 이유는 프로그래밍 가능한 터미널 제어다. tmux의 CLI 명령으로 세션 생성, 명령 전송, 출력 수집을 자동화할 수 있기 때문이다.\nClaude Code의 Agent Team은 여러 에이전트를 병렬로 생성할 때 tmux를 활용한다. 각 에이전트를 별도 패인에서 실행하고, send-keys로 명령을 보내고, capture-pane으로 결과를 수집한다.\n핵심 API: send-keys와 capture-pane # 1. 백그라운드 세션 생성 tmux new-session -d -s agents # 2. 여러 패인으로 분할 tmux split-window -h -t agents tmux split-window -v -t agents:0.1 # 3. 각 패인에 명령 전송 tmux send-keys -t agents:0.0 \u0026#34;cd ~/project \u0026amp;\u0026amp; claude \u0026#39;Fix the login bug\u0026#39;\u0026#34; Enter tmux send-keys -t agents:0.1 \u0026#34;cd ~/project \u0026amp;\u0026amp; claude \u0026#39;Write unit tests\u0026#39;\u0026#34; Enter tmux send-keys -t agents:0.2 \u0026#34;cd ~/project \u0026amp;\u0026amp; npm run dev\u0026#34; Enter # 4. 특정 패인의 출력 수집 tmux capture-pane -t agents:0.0 -p # stdout에 출력 tmux capture-pane -t agents:0.0 -p -S -100 # 마지막 100줄 tmux capture-pane -t agents:0.0 -b temp # 버퍼에 저장 타겟 지정 문법 tmux의 타겟 지정 문법은 session:window.pane 형식이다.\nagents:0.0 → \u0026#34;agents\u0026#34; 세션의 0번 윈도우의 0번 패인 agents:0.1 → \u0026#34;agents\u0026#34; 세션의 0번 윈도우의 1번 패인 work:editor.0 → \u0026#34;work\u0026#34; 세션의 \u0026#34;editor\u0026#34; 윈도우의 0번 패인 실전 AI 에이전트 워크플로우 스크립트 #!/bin/bash # ai-workspace.sh — AI 에이전트 병렬 작업 환경 구성 PROJECT_DIR=\u0026#34;$1\u0026#34; SESSION=\u0026#34;ai-work\u0026#34; # 기존 세션이 있으면 종료 tmux kill-session -t \u0026#34;$SESSION\u0026#34; 2\u0026gt;/dev/null # 메인 세션 생성 tmux new-session -d -s \u0026#34;$SESSION\u0026#34; -c \u0026#34;$PROJECT_DIR\u0026#34; -n \u0026#34;agents\u0026#34; # 패인 분할: 3개의 에이전트 영역 tmux split-window -h -t \u0026#34;$SESSION:agents\u0026#34; -c \u0026#34;$PROJECT_DIR\u0026#34; tmux split-window -v -t \u0026#34;$SESSION:agents.1\u0026#34; -c \u0026#34;$PROJECT_DIR\u0026#34; # 모니터링 윈도우 생성 tmux new-window -t \u0026#34;$SESSION\u0026#34; -n \u0026#34;monitor\u0026#34; -c \u0026#34;$PROJECT_DIR\u0026#34; tmux split-window -v -t \u0026#34;$SESSION:monitor\u0026#34; -c \u0026#34;$PROJECT_DIR\u0026#34; # 모니터링 윈도우에 개발 서버 + 로그 tmux send-keys -t \u0026#34;$SESSION:monitor.0\u0026#34; \u0026#34;npm run dev\u0026#34; Enter tmux send-keys -t \u0026#34;$SESSION:monitor.1\u0026#34; \u0026#34;tail -f logs/app.log\u0026#34; Enter # agents 윈도우로 돌아가기 tmux select-window -t \u0026#34;$SESSION:agents\u0026#34; # 접속 tmux attach -t \u0026#34;$SESSION\u0026#34; 에이전트 출력 모니터링 스크립트 #!/bin/bash # monitor-agents.sh — 모든 패인의 출력을 주기적으로 수집 SESSION=\u0026#34;ai-work\u0026#34; OUTPUT_DIR=\u0026#34;/tmp/agent-outputs\u0026#34; mkdir -p \u0026#34;$OUTPUT_DIR\u0026#34; while true; do # 모든 패인의 최근 출력 수집 for pane in $(tmux list-panes -t \u0026#34;$SESSION\u0026#34; -F \u0026#39;#{pane_id}\u0026#39;); do tmux capture-pane -t \u0026#34;$pane\u0026#34; -p -S -50 \u0026gt; \u0026#34;$OUTPUT_DIR/${pane}.txt\u0026#34; done # 특정 키워드 감지 (에러, 완료 등) if grep -q \u0026#34;Error\\|FAIL\\|Complete\\|Done\u0026#34; \u0026#34;$OUTPUT_DIR\u0026#34;/*.txt 2\u0026gt;/dev/null; then echo \u0026#34;[$(date)] Agent activity detected\u0026#34; fi sleep 10 done Claude Code Agent Team과 tmux Claude Code의 Agent Team은 내부적으로 다음과 같은 흐름으로 tmux를 활용한다:\ntmux new-session -d로 백그라운드 세션 생성 tmux split-window로 에이전트 수만큼 패인 생성 tmux send-keys로 각 에이전트에 태스크 전송 tmux capture-pane으로 각 에이전트의 출력 수집 결과를 종합하여 최종 응답 생성 이 모든 것이 tmux의 프로그래밍 가능한 API 덕분에 가능하다. tmux가 없었다면 AI 에이전트가 여러 터미널을 프로그래밍 방식으로 제어하는 것이 훨씬 어려웠을 것이다.\n실전 팁 Copy Mode (스크롤 및 복사) tmux에서 스크롤하거나 텍스트를 복사하려면 Copy Mode에 진입해야 한다.\n# Copy Mode 진입 Prefix + [ # Copy Mode에서의 이동 (vi 모드 설정 시) h/j/k/l # 방향 이동 Ctrl+u/d # 페이지 업/다운 g/G # 처음/끝으로 이동 /search-term # 텍스트 검색 n/N # 다음/이전 검색 결과 # 텍스트 선택 및 복사 (vi 모드) Space # 선택 시작 Enter # 선택한 텍스트 복사 + Copy Mode 종료 q # Copy Mode 종료 (복사 없이) # 복사한 텍스트 붙여넣기 Prefix + ] 마우스 모드(set -g mouse on)를 활성화하면 마우스 스크롤로도 Copy Mode에 자동 진입한다.\n패인 동기화 (Synchronize Panes) 여러 서버에 동일한 명령을 동시에 보내야 할 때 유용하다.\n# 동기화 활성화: 현재 윈도우의 모든 패인에 동일한 입력 전송 Prefix + : → setw synchronize-panes on # 동기화 비활성화 Prefix + : → setw synchronize-panes off # .tmux.conf에 토글 단축키 추가 bind S setw synchronize-panes \\; display-message \u0026#34;Sync #{?synchronize-panes,ON,OFF}\u0026#34; 프리셋 레이아웃 # 레이아웃 순환 Prefix + Space # 특정 레이아웃 직접 지정 Prefix + : → select-layout even-horizontal # 수평 균등 분할 Prefix + : → select-layout even-vertical # 수직 균등 분할 Prefix + : → select-layout main-horizontal # 상단 메인 + 하단 분할 Prefix + : → select-layout main-vertical # 좌측 메인 + 우측 분할 Prefix + : → select-layout tiled # 타일 형태 tmux 명령 모드 Prefix + :로 진입하는 명령 모드에서는 모든 tmux 명령을 직접 입력할 수 있다.\n# 자주 쓰는 명령 모드 명령 new -s session-name # 새 세션 move-window -t other-session # 윈도우를 다른 세션으로 이동 swap-pane -U # 패인 위치 위로 이동 swap-pane -D # 패인 위치 아래로 이동 resize-pane -D 10 # 아래로 10칸 확장 resize-pane -R 20 # 오른쪽으로 20칸 확장 Vi 방향키 습관 들이기 키보드에서 손이 밑으로 왔다 갔다 하지 않아도 되는 자세로 최대한 몸을 움직이지 않고 모든 작업을 하기 위해, 방향키 대신 Vi 방향키 HJKL을 익혀 두는 것을 권장한다. 로컬뿐 아니라 원격 서버에서 SSH로 작업할 때도 Vi 방향키와 단축어를 굉장히 많이 활용하게 된다.\nH = ← (왼쪽) J = ↓ (아래) K = ↑ (위) L = → (오른쪽) 빠른 링크 tmux GitHub \u0026ndash; C 기반 오픈소스, ISC 라이선스 tmux Wiki \u0026ndash; 공식 문서 TPM (Tmux Plugin Manager) \u0026ndash; 플러그인 매니저 tmux-resurrect \u0026ndash; 세션 저장/복원 Ghostty \u0026ndash; GPU 가속 터미널 에뮬레이터 TMUX 마스터클래스 \u0026ndash; YouTube \u0026ndash; 이 글의 주요 참고 영상 tmux 기본 사용법 \u0026ndash; hyde1004 \u0026ndash; 한국어 tmux 가이드 인사이트 tmux는 19년간 검증된 안정성과 크로스 플랫폼 지원이라는 압도적 강점을 가진 터미널 인프라다. 서버-클라이언트 아키텍처 덕분에 세션 영속성이 보장되고, 프로그래밍 가능한 CLI API 덕분에 AI 코딩 에이전트 시대에 다시 핵심 도구로 부상했다.\n학습 곡선이 가파르다는 인식이 있지만, 실제로 핵심 단축키는 10개 남짓이다. Prefix + c(새 윈도우), Prefix + %/\u0026quot; (분할), Prefix + 방향키(이동), Prefix + d(detach), Prefix + w(윈도우 목록) 정도만 익히면 일상적인 작업은 충분하다. 여기에 .tmux.conf 커스터마이징으로 Vi 방향키와 직관적인 분할 키를 추가하면 생산성이 한 단계 올라간다.\nAI 에이전트와의 조합에서 tmux의 진가가 드러난다. send-keys와 capture-pane이라는 두 가지 명령만으로 \u0026ldquo;명령 전송 → 출력 수집\u0026rdquo; 사이클이 완성되고, 이것이 Claude Code Agent Team의 병렬 에이전트 아키텍처의 기반이 된다. tmux가 \u0026ldquo;세션이 죽지 않는 인프라\u0026quot;라면, AI 에이전트는 그 인프라 위에서 자율적으로 작업하는 워커다. 2026년 현재, tmux를 모르고 터미널 기반 AI 코딩 도구를 활용하는 것은 기초 체력 없이 마라톤에 나서는 것과 같다.\n","date":"2026-03-23T00:00:00+09:00","image":"/images/posts/2026-03-23-tmux-masterclass/cover.jpg","permalink":"/ko/posts/2026-03-23-tmux-masterclass/","title":"tmux 마스터클래스 — 터미널 멀티플렉서의 모든 것과 AI 에이전트 활용법"},{"content":"개요 하니스 시리즈 글:\nHarness(하니스) — Claude Code를 범용 AI에서 전담 직원으로 — 개념과 핵심 구조 Harness Engineering #2 — Antigravity로 하니스 실전 구축하기 — Google Antigravity 실전 이 글 — 커뮤니티 하니스 플러그인 비교 분석 HarnessKit 개발기 #1 — Zero-Based Vibe Coder를 위한 Adaptive Harness Plugin — 분석 결과를 바탕으로 직접 만든 플러그인 이 글은 HarnessKit을 설계하기 전 사전 조사로 작성되었다. 기존 하니스 플러그인들의 장단점을 분석하고, 어떤 부분을 수용하고 어떤 부분을 개선할지 판단하기 위해 GitHub에서 가장 활발한 두 구현체를 비교했다 — Chachamaru127의 claude-code-harness(281★)와 panayiotism의 claude-harness(73★). 같은 문제를 풀지만 접근 방식이 완전히 다르다.\n설계 철학 비교 flowchart LR subgraph CCH[\"claude-code-harness\"] A1[\"TypeScript Core\"] --\u003e B1[\"Guardrail Engine\"] B1 --\u003e C1[\"5-Verb Skills\"] C1 --\u003e D1[\"Multi-Platform\"] end subgraph CH[\"claude-harness\"] A2[\"Shell Scripts\"] --\u003e B2[\"Memory Architecture\"] B2 --\u003e C2[\"/flow 단일 명령\"] C2 --\u003e D2[\"GitHub MCP 통합\"] end CCH -.-\u003e|\"같은 목표\"| CH두 플러그인 모두 Anthropic의 \u0026ldquo;Effective harnesses for long-running agents\u0026rdquo; 아티클에서 출발한다. 하지만 구현 전략이 갈린다.\nclaude-code-harness는 런타임 안전성에 집중한다. TypeScript로 작성된 가드레일 엔진이 매 도구 호출을 감시하고, deny/warn 규칙으로 위험한 명령을 차단한다. \u0026ldquo;매번 같은 형태로 무너지지 않고 진행\u0026quot;하는 것이 핵심 가치다.\nclaude-harness는 컨텍스트 연속성에 집중한다. 5-layer 메모리 아키텍처로 세션 간 맥락을 보존하고, /flow 단일 명령으로 계획부터 머지까지 전 과정을 자동화한다. \u0026ldquo;한 번 시작하면 끝까지 자동으로 흘러가게\u0026rdquo; 하는 것이 핵심 가치다.\n아키텍처 상세 claude-code-harness — TypeScript 가드레일 엔진 flowchart TD A[\"사용자 명령\"] --\u003e B[\"PreToolUse Hook\"] B --\u003e C{\"Guardrail Engine\u0026lt;br/\u0026gt;(TypeScript)\"} C --\u003e|DENY| D[\"차단 + 경고\"] C --\u003e|WARN| E[\"경고 + 진행\"] C --\u003e|PASS| F[\"실행\"] F --\u003e G[\"PostToolUse Hook\"] G --\u003e H{\"tampering 감지\"} H --\u003e|감지| I[\"롤백\"] H --\u003e|정상| J[\"계속\"] 구성 요소 설명 core/guardrails/ pre-tool, post-tool, permission, tampering 감지 core/engine/lifecycle.js 세션 라이프사이클 관리 core/state/ 상태 스키마, 마이그레이션, 저장소 skills-v3/ 5-verb 스킬 (plan, work, review, validate, release) agents-v3/ reviewer, scaffolder, worker, team-composition 5-Verb 시스템이 이 플러그인의 뼈대다:\nPlan — 요구사항을 Plans.md로 구조화 Work — 구현 (--parallel 지원, Breezing 모드) Review — 코드 리뷰 공정 Validate — 재실행 가능한 검증 (evidence pack 생성) Release — 머지 + 릴리스 특이한 점은 멀티 플랫폼 지원이다. Claude Code 외에도 Cursor, Codex, OpenCode 설정 파일이 포함되어 있다. 이는 특정 AI 코딩 도구에 종속되지 않겠다는 의지를 보여준다.\n가드레일 엔진은 TypeScript로 컴파일된 바이너리가 매 도구 호출 시 stdin으로 JSON을 받아 패턴 매칭한다. Shell 스크립트의 grep 기반 매칭과 달리 구조화된 AST 수준의 검사가 가능하다. tampering.js는 가드레일 설정 자체를 우회하려는 시도까지 감지한다.\nclaude-harness — Shell 기반 메모리 아키텍처 flowchart TD A[\"/flow 명령\"] --\u003e B[\"Context 컴파일\"] B --\u003e C[\"4-Layer 메모리 로드\"] C --\u003e D[\"GitHub Issue 생성\"] D --\u003e E[\"Branch 생성\"] E --\u003e F[\"TDD 구현\"] F --\u003e G[\"Checkpoint\"] G --\u003e H[\"PR 생성\"] H --\u003e I[\"Auto-Merge\"] subgraph Memory[\"메모리 계층\"] M1[\"Layer 1: Project Rules\"] M2[\"Layer 2: Feature State\"] M3[\"Layer 3: Session Context\"] M4[\"Layer 4: Learned Patterns\"] end C --\u003e Memory 구성 요소 설명 hooks/ 8개 hook (session-start, pre-tool-use, stop, pre-compact 등) skills/ 6개 skill (setup, start, flow, checkpoint, merge, prd-breakdown) schemas/ JSON Schema로 상태 검증 (active-features, memory-entries, loop-state 등) setup.sh 원타임 초기화 /flow 단일 명령이 이 플러그인의 핵심이다. 컨텍스트 컴파일 → GitHub Issue → Branch → TDD 구현 → Checkpoint → PR → Merge까지 하나의 명령으로 처리한다. 옵션으로 세부 제어가 가능하다:\n/flow \u0026#34;Add dark mode\u0026#34; # 풀 라이프사이클 /flow --no-merge \u0026#34;Add feature\u0026#34; # 머지 전 중단 /flow --autonomous # 전체 feature 배치 처리 /flow --team # ATDD (Agent Teams) /flow --quick # 계획 생략 (단순 작업) 메모리 아키텍처가 차별점이다. 4개 계층(Project Rules → Feature State → Session Context → Learned Patterns)으로 컨텍스트를 구조화하고, 세션 시작 시 자동으로 컴파일한다. pre-compact hook은 컨텍스트 압축 전에 중요 정보를 저장하여 장시간 세션에서도 맥락이 유실되지 않도록 한다.\n모든 hook이 순수 Shell 스크립트다. Node.js나 Python 런타임 없이 bash + jq만으로 동작한다. 설치가 단순하고 의존성이 없다는 장점이 있지만, 복잡한 패턴 매칭에는 한계가 있다.\n비교표 기준 claude-code-harness claude-harness 언어 TypeScript (core) + Shell (hooks) + Markdown (skills) Shell + Markdown Stars 281 73 버전 v3.10.6 v10.2.0 핵심 모델 5-Verb (Plan→Work→Review→Validate→Release) /flow 단일 명령 (end-to-end) 가드레일 TypeScript 엔진 (deny/warn/pass + tampering 감지) Shell 기반 pre-tool-use hook 메모리 상태 스키마 + 마이그레이션 4-Layer 아키텍처 (Project→Feature→Session→Learned) GitHub 연동 간접 (gh CLI) GitHub MCP 통합 TDD 스킬에서 권장 /flow에서 강제 (RED→GREEN→REFACTOR) 멀티 플랫폼 Claude Code, Cursor, Codex, OpenCode Claude Code 전용 Agents reviewer, scaffolder, worker, team-composition Agent Teams (ATDD 모드) PRD 지원 Plans.md 기반 /prd-breakdown → GitHub Issues 자동 생성 자율 실행 /harness-work all (배치) /flow --autonomous (feature 루프) 런타임 의존성 Node.js (TypeScript core) 없음 (bash + jq) 어떤 플러그인이 맞는가 flowchart TD A[\"하니스 플러그인 선택\"] --\u003e B{\"런타임 안전성이\u0026lt;br/\u0026gt;최우선인가?\"} B --\u003e|\"예\"| C[\"claude-code-harness\"] B --\u003e|\"아니오\"| D{\"세션 간 컨텍스트\u0026lt;br/\u0026gt;연속성이 중요한가?\"} D --\u003e|\"예\"| E[\"claude-harness\"] D --\u003e|\"아니오\"| F{\"멀티 플랫폼이\u0026lt;br/\u0026gt;필요한가?\"} F --\u003e|\"예\"| C F --\u003e|\"아니오\"| G{\"최소 의존성을\u0026lt;br/\u0026gt;선호하는가?\"} G --\u003e|\"예\"| E G --\u003e|\"아니오\"| Cclaude-code-harness를 선택해야 할 때:\n위험한 명령 차단이 중요한 팀 환경 Cursor, Codex 등 여러 AI 코딩 도구를 병행 검증(validation) 결과를 증거로 남겨야 할 때 단계별 세분화된 워크플로우가 필요할 때 claude-harness를 선택해야 할 때:\n\u0026ldquo;한 명령으로 끝까지\u0026rdquo; 자동화를 원할 때 장시간 세션에서 맥락 유실이 문제일 때 Node.js 의존성 없이 가볍게 시작하고 싶을 때 GitHub Issues/PR과의 긴밀한 통합이 필요할 때 Anthropic Superpowers와의 관계 두 플러그인 모두 obra/superpowers(71,993★)를 의식하고 있다. claude-code-harness의 벤치마크 문서는 세 플러그인을 직접 비교하면서 각각의 강점을 정리한다:\n워크플로우의 폭을 넓히고 싶다면 Superpowers. 요건 → 설계 → 태스크의 규율을 강화하고 싶다면 cc-sdd. 계획 · 구현 · 리뷰 · 검증을 무너지지 않는 표준 플로우로 바꾸고 싶다면 Claude Harness.\n실제로 Superpowers는 하니스보다는 워크플로우 프레임워크에 가깝다. brainstorming → writing-plans → executing-plans → code-review까지의 흐름을 제공하지만, 런타임 가드레일이나 메모리 아키텍처 같은 인프라 수준의 기능은 전면에 내세우지 않는다. 세 플러그인은 경쟁 관계가 아니라 레이어가 다르다.\n인사이트 TypeScript vs Shell — 트레이드오프가 명확하다. TypeScript 가드레일 엔진은 구조화된 검사와 tampering 감지가 가능하지만 Node.js 의존성을 요구한다. Shell hook은 의존성 제로이지만 패턴 매칭의 정교함에 한계가 있다. 프로젝트의 보안 요구 수준이 선택 기준이 된다. \u0026ldquo;5-Verb\u0026quot;와 \u0026ldquo;/flow\u0026quot;는 같은 문제의 다른 해법이다. 단계를 명시적으로 분리하면 각 단계를 독립적으로 제어할 수 있지만 마찰이 생긴다. 단일 명령으로 통합하면 마찰은 줄지만 세밀한 개입이 어렵다. 팀 규모가 클수록 전자, 개인 개발자는 후자가 유리하다. 메모리 계층화는 하니스의 다음 전장이다. panayiotism의 4-layer 메모리 아키텍처는 세션 간 맥락 보존이라는 근본 문제를 정면으로 다룬다. Chachamaru127도 state/migration 모듈을 갖고 있지만 메모리보다는 가드레일에 무게를 둔다. 장기적으로는 메모리 아키텍처가 하니스 품질을 결정하는 핵심 요소가 될 것이다. 하니스 생태계는 분화 중이다. 범용 워크플로우(Superpowers), 런타임 안전성(claude-code-harness), 컨텍스트 연속성(claude-harness), 적응형 프리셋(HarnessKit) — 각각 다른 축을 공략한다. 이는 하니스가 단일 솔루션이 아니라 도구 체인으로 진화하고 있음을 의미한다. ","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-harness-plugins/cover.jpg","permalink":"/ko/posts/2026-03-20-harness-plugins/","title":"Claude Code Harness 플러그인 비교 — claude-code-harness vs claude-harness"},{"content":"개요 Claude Code가 플러그인 시스템을 도입한 이후, 생태계가 빠르게 확장되고 있다. 공식 마켓플레이스 하나로 시작했지만 지금은 커뮤니티 디렉토리, 한국어 전용 마켓플레이스까지 선택지가 다양해졌다. 이 글에서는 주요 마켓플레이스 네 곳을 비교하고, 목적에 맞는 선택 기준을 정리한다.\n생태계 구조 Claude Code 플러그인 생태계는 크게 세 계층으로 나뉜다.\ngraph TD A[\"Claude Code CLI\"] --\u003e B[\"Built-in Official Marketplace \u0026lt;br/\u0026gt; claude-plugins-official\"] A --\u003e C[\"Third-party Marketplaces \u0026lt;br/\u0026gt; GitHub repo 기반\"] B --\u003e D[\"Code Intelligence \u0026lt;br/\u0026gt; LSP 11개 언어\"] B --\u003e E[\"External Integrations \u0026lt;br/\u0026gt; GitHub, Slack, Jira 등\"] B --\u003e F[\"Development Workflows \u0026lt;br/\u0026gt; commit, PR review\"] B --\u003e G[\"Output Styles\"] C --\u003e H[\"claudemarketplaces.com \u0026lt;br/\u0026gt; 커뮤니티 디렉토리 (2,919개)\"] C --\u003e I[\"modu-ai/cc-plugins \u0026lt;br/\u0026gt; 한국어 마켓플레이스\"] C --\u003e J[\"skillsmp.com \u0026lt;br/\u0026gt; Agent Skills\"] H --\u003e K[\"GitHub Repos \u0026lt;br/\u0026gt; 개별 마켓플레이스\"] I --\u003e L[\"보안 특화 플러그인 \u0026lt;br/\u0026gt; Auth0, MFA, Compliance\"] style A fill:#6366f1,color:#fff style B fill:#059669,color:#fff style C fill:#d97706,color:#fff1. 공식 마켓플레이스 — claude-plugins-official Anthropic이 직접 운영하는 기본 마켓플레이스다. Claude Code를 설치하면 자동으로 사용 가능하다.\n주요 카테고리 카테고리 내용 예시 Code Intelligence LSP 기반 언어 지원 (11개 언어) TypeScript, Python, Rust, Go 등 External Integrations 외부 서비스 연동 GitHub, GitLab, Jira, Slack, Figma Development Workflows 개발 프로세스 자동화 commit-commands, pr-review-toolkit Output Styles 출력 형식 커스터마이징 — 설치 방법 # 플러그인 설치 /plugin install plugin-name@claude-plugins-official # 설치된 플러그인 확인 /plugin list 장점: Anthropic이 제공하므로 안정성과 호환성이 보장된다. 별도 마켓플레이스 등록 없이 바로 사용할 수 있다.\n단점: 플러그인 수가 제한적이고, 커뮤니티의 다양한 요구를 모두 반영하기 어렵다.\n2. claudemarketplaces.com — 커뮤니티 디렉토리 @mertduzgun이 운영하는 독립 프로젝트로, Anthropic과는 공식적인 관계가 없다. 현재 2,919개 마켓플레이스를 색인하고 있어 규모 면에서 가장 크다.\n인기 마켓플레이스 (Stars 기준) 마켓플레이스 Stars 플러그인 수 특징 f/prompts.chat 144.8k — 프롬프트 중심 anthropics/claude-code 65.1k 13 공식 레포 obra/superpowers 46.9k — 확장 기능 upstash/context7 45k — 컨텍스트 관리 affaan-m/everything-claude-code 41.3k — 종합 리소스 ComposioHQ/awesome-claude-skills 32k 107 스킬 모음 wshobson/agents 28k 73 에이전트 특화 eyaltoledano/claude-task-master 25.3k — 태스크 관리 카테고리 분류 3D-Development, Agents, Authentication, Automation, Backend, Claude, Code-Quality 등 세분화된 카테고리로 정리되어 있다. Sponsored listing(ideabrowser.com, supastarter 등)도 포함되어 있으므로, 스폰서 표시 여부를 확인하는 습관이 필요하다.\n장점: 압도적인 규모, 카테고리 검색, Stars 기반 인기도 확인 가능.\n단점: 품질 검증이 없고, Anthropic 비공식이므로 보안 판단은 사용자 몫이다.\n3. skillsmp.com (SkillsMP) Agent Skills 전문 마켓플레이스로, 한국어 지원(skillsmp.com/ko)을 제공한다. 다만 현재 접근 시 HTTP 403 오류가 발생하는 상태로, 안정성에 대한 확인이 필요하다.\n장점: 한국어 UI 지원, Agent Skills 특화.\n단점: 접근 불안정(403 에러), 콘텐츠 확인 불가.\n4. modu-ai/cc-plugins — 한국어 커뮤니티 \u0026ldquo;모두의AI 공식 Claude Code Plugin Marketplace\u0026quot;를 표방하는 한국어 최적화 마켓플레이스다.\n특징 Stars: 56 (성장 초기) 라이선스: GPL-3.0 (Copyleft) 기술 스택: MoAI-ADK (AI Development Kit), DDD 방법론 기반 주력 분야: Auth0 보안, MFA, 토큰 보안, 컴플라이언스 설치 # 마켓플레이스 등록 /plugin marketplace add modu-ai/cc-plugins # 등록 후 플러그인 설치 /plugin install plugin-name@modu-ai-cc-plugins 장점: 한국어 문서, 보안 특화 플러그인, 국내 커뮤니티 연결.\n단점: 아직 초기 단계로 플러그인 수가 적고, GPL-3.0 라이선스의 제약을 이해해야 한다.\n마켓플레이스 종합 비교 항목 공식 (Anthropic) claudemarketplaces.com skillsmp.com modu-ai/cc-plugins 규모 소 대 (2,919) 미확인 소 운영 주체 Anthropic 커뮤니티 (개인) 미확인 한국 커뮤니티 품질 검증 O X 미확인 부분적 한국어 지원 X X O O 보안 신뢰도 높음 낮음 (직접 확인 필요) 미확인 중간 설치 편의성 내장 별도 등록 필요 — 별도 등록 필요 자동 업데이트 O (설정 가능) 마켓플레이스별 상이 — — 주력 분야 범용 범용 Agent Skills 보안 플러그인 시스템 아키텍처 Claude Code의 마켓플레이스 시스템은 GitHub repo를 기반으로 동작한다.\ngraph LR subgraph \"마켓플레이스 구조\" A[\"marketplace.json\"] --\u003e B[\"sources \u0026lt;br/\u0026gt; 플러그인 메타데이터\"] A --\u003e C[\"scopes \u0026lt;br/\u0026gt; 권한 범위 정의\"] B --\u003e D[\"GitHub Repos\"] B --\u003e E[\"Git URLs\"] B --\u003e F[\"npm Packages\"] B --\u003e G[\"Local Paths\"] end subgraph \"설치 경로\" H[\"사용자\"] --\u003e I[\"/plugin marketplace add\"] I --\u003e A H --\u003e J[\"/plugin install\"] J --\u003e K[\"플러그인 다운로드 \u0026lt;br/\u0026gt; + 활성화\"] end style A fill:#6366f1,color:#fff style H fill:#059669,color:#fff지원하는 플러그인 소스 유형 소스 유형 예시 용도 GitHub repo owner/repo 가장 일반적 Git URL https://github.com/... 직접 URL 지정 Local path 로컬 디렉토리 경로 로컬 개발/테스트 npm package @scope/package Node.js 생태계 팀 마켓플레이스 설정 팀에서 공유 마켓플레이스를 사용하려면 .claude/settings.json에 설정한다.\n{ \u0026#34;extraKnownMarketplaces\u0026#34;: [ \u0026#34;your-org/internal-plugins\u0026#34; ] } 선택 기준 — 어떤 마켓플레이스를 쓸까 상황별 추천 \u0026ldquo;처음 시작한다\u0026rdquo; — 공식 마켓플레이스부터. 별도 설정 없이 바로 사용 가능하고, LSP 플러그인으로 코드 인텔리전스를 먼저 강화하는 것이 좋다.\n\u0026ldquo;다양한 플러그인이 필요하다\u0026rdquo; — claudemarketplaces.com에서 검색한 뒤, Stars와 최근 업데이트 날짜를 확인하고 개별 마켓플레이스를 등록한다. ComposioHQ/awesome-claude-skills(107개)나 wshobson/agents(73개)가 실용적이다.\n\u0026ldquo;한국어 환경에서 쓴다\u0026rdquo; — modu-ai/cc-plugins를 등록한다. 한국어 문서와 국내 커뮤니티 지원이 있다.\n\u0026ldquo;보안이 중요하다\u0026rdquo; — 공식 마켓플레이스를 기본으로 사용하고, 서드파티는 소스 코드를 직접 검토한 후에만 설치한다.\n보안 고려사항 플러그인 생태계에서 보안은 가장 중요한 문제다.\nAnthropic은 서드파티 플러그인을 검증하지 않는다. 공식 문서에도 \u0026ldquo;user must trust plugins\u0026quot;라고 명시되어 있다.\n설치 전 확인 사항:\nGitHub repo의 Stars, Issues, 최근 커밋 활동 라이선스 (GPL-3.0 같은 Copyleft 라이선스는 상업 프로젝트에 영향) 플러그인이 요구하는 권한(scopes) 범위 소스 코드에서 외부 API 호출이나 데이터 전송 여부 자동 업데이트 설정: 신뢰하는 마켓플레이스만 자동 업데이트를 켜고, 나머지는 수동으로 관리한다.\nSponsored listing 주의: claudemarketplaces.com의 스폰서 리스팅은 품질 보증이 아니다. 광고임을 인지해야 한다.\n빠른 링크 Claude Code 공식 플러그인 문서 claudemarketplaces.com skillsmp.com modu-ai/cc-plugins 마켓플레이스 생성 가이드 인사이트 Claude Code 플러그인 생태계는 아직 초기 성장 단계다. 2,919개 마켓플레이스가 색인될 만큼 빠른 성장이 이루어지고 있고, 공식 마켓플레이스의 체계적인 카테고리 분류와 한국어 커뮤니티의 자체 마켓플레이스 운영은 긍정적 신호다. 그러나 품질 검증 체계 부재, 플러그인 간 호환성 표준 미정립, GitHub Stars에만 의존하는 신뢰 모델은 개선이 필요하다. VS Code 확장 생태계가 성숙하기까지 수년이 걸렸던 것처럼, Claude Code도 시간이 필요하다. 지금은 공식 마켓플레이스를 중심으로 사용하면서, 커뮤니티 마켓플레이스는 선별적으로 활용하는 전략이 합리적이다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-claude-code-marketplaces/cover.jpg","permalink":"/ko/posts/2026-03-20-claude-code-marketplaces/","title":"Claude Code 플러그인 마켓플레이스 비교 — 어디서 찾고 어떻게 고를까"},{"content":"개요 AI 코딩 어시스턴트를 사용하다 보면 한 번쯤은 겪는 일이 있다. Cursor나 Claude Code가 자신 있게 작성해준 코드가 실제로는 존재하지 않는 API를 호출하고 있거나, 2년 전에 deprecated된 패턴을 사용하고 있는 것이다. LLM의 학습 데이터에는 시간적 한계가 있고, 라이브러리는 끊임없이 업데이트된다. Context7은 이 간극을 메우기 위해 최신 버전의 문서를 LLM 프롬프트에 직접 주입하는 플랫폼이다. GitHub 스타 약 49,800개를 기록하며 빠르게 성장 중인 이 도구를 깊이 분석해본다.\nLLM 환각 문제: 왜 발생하는가 LLM이 코드를 생성할 때 발생하는 환각(hallucination)은 단순한 \u0026ldquo;실수\u0026quot;가 아니라 구조적 문제다.\nflowchart LR A[\"LLM 학습 데이터\u0026lt;br/\u0026gt;(~2025년 초 기준)\"] --\u003e B[\"코드 생성 요청\u0026lt;br/\u0026gt;Next.js 15 middleware\"] B --\u003e C{\"학습 데이터에\u0026lt;br/\u0026gt;해당 버전 존재?\"} C -- \"Yes\" --\u003e D[\"정확한 코드 생성\"] C -- \"No\" --\u003e E[\"이전 버전 패턴으로\u0026lt;br/\u0026gt;자신있게 생성\"] E --\u003e F[\"deprecated API 사용\u0026lt;br/\u0026gt;존재하지 않는 함수 호출\u0026lt;br/\u0026gt;잘못된 파라미터 전달\"]대표적인 사례들:\n상황 증상 Next.js App Router 관련 코드 요청 Pages Router 패턴을 혼합하여 생성 Supabase 최신 Auth API 사용 supabase.auth.api (deprecated) 호출 Tailwind CSS v4 설정 v3 config 포맷으로 생성 Cloudflare Workers 새 API 존재하지 않는 메서드 조합 문제의 핵심은, LLM이 \u0026ldquo;모른다\u0026quot;고 말하지 않는다는 점이다. 학습 데이터에 유사한 패턴이 있으면 그것을 기반으로 그럴듯한 코드를 생성하고, 개발자는 런타임 에러가 발생할 때까지 이를 알아차리지 못한다.\nContext7의 해결 방식 Context7의 접근법은 단순하면서도 효과적이다: LLM이 코드를 생성하기 전에, 해당 라이브러리의 최신 공식 문서를 프롬프트 컨텍스트에 삽입한다.\nflowchart TB subgraph User[\"사용자 환경\"] A[\"AI 코딩 에디터\u0026lt;br/\u0026gt;Cursor / Claude Code / OpenCode\"] end subgraph Context7[\"Context7 플랫폼\"] B[\"MCP Server\u0026lt;br/\u0026gt;(오픈소스)\"] C[\"API Backend\u0026lt;br/\u0026gt;(Upstash 프로프라이어터리)\"] D[\"Crawling Engine\u0026lt;br/\u0026gt;문서 수집 및 파싱\"] E[\"Documentation DB\u0026lt;br/\u0026gt;버전별 인덱싱\"] end subgraph Sources[\"문서 소스\"] F[\"공식 문서 사이트\"] G[\"GitHub README\"] H[\"API Reference\"] end A -- \"use context7\" --\u003e B B -- \"resolve-library-id\u0026lt;br/\u0026gt;query-docs\" --\u003e C C --\u003e E D --\u003e E Sources --\u003e D C -- \"최신 문서 조각\" --\u003e B B -- \"컨텍스트 주입\" --\u003e A동작 흐름 사용자가 프롬프트에 use context7을 추가 Context7 MCP 서버가 라이브러리를 식별 (resolve-library-id) 해당 라이브러리의 최신 문서에서 관련 섹션을 검색 (query-docs) 검색된 문서 조각을 LLM 컨텍스트에 삽입 LLM이 최신 문서를 기반으로 코드 생성 이 과정이 중요한 이유는, 단순히 \u0026ldquo;최신 문서를 읽어라\u0026quot;가 아니라 쿼리와 관련된 문서 섹션만 선별적으로 추출한다는 점이다. 전체 문서를 컨텍스트에 넣으면 토큰 낭비이자 오히려 성능 저하를 일으킬 수 있다.\nCLI vs MCP: 두 가지 사용 모드 Context7은 두 가지 방식으로 사용할 수 있다.\n1. CLI + Skills 모드 (MCP 불필요) # 설치 및 설정 npx ctx7 setup # OAuth 인증 → API 키 생성 → skill 설치 # 라이브러리 검색 ctx7 library nextjs middleware # 특정 라이브러리의 문서 조회 ctx7 docs /vercel/next.js \u0026#34;middleware authentication JWT\u0026#34; CLI 모드는 MCP를 지원하지 않는 환경이나, 단순히 터미널에서 빠르게 문서를 확인하고 싶을 때 유용하다.\n2. MCP 모드 (네이티브 통합) MCP(Model Context Protocol)를 지원하는 클라이언트에서는 Context7이 자동으로 동작한다.\n제공되는 MCP Tool:\nTool 용도 입력 출력 resolve-library-id 라이브러리 이름을 Context7 ID로 변환 \u0026quot;nextjs\u0026quot; /vercel/next.js query-docs 라이브러리 ID로 관련 문서 검색 library ID + query 문서 조각 MCP 모드의 핵심 장점: 사용자가 use context7만 프롬프트에 추가하면, 나머지는 LLM이 자동으로 tool call을 수행한다.\n모드 비교 기준 CLI 모드 MCP 모드 설정 복잡도 낮음 (npx 한 줄) MCP 서버 등록 필요 자동화 수준 수동 완전 자동 MCP 지원 필요 불필요 필수 적합한 상황 빠른 문서 확인, MCP 미지원 환경 일상적인 AI 코딩 워크플로우 Library ID 시스템과 버전 타겟팅 Context7의 Library ID는 GitHub 스타일의 경로를 사용한다:\n/supabase/supabase /vercel/next.js /mongodb/docs /langchain-ai/langchainjs 이 ID 체계가 흥미로운 이유는, 단순히 패키지 이름이 아니라 문서의 출처를 명시적으로 식별한다는 점이다. react라고만 검색하면 여러 결과가 나올 수 있지만, /facebook/react는 하나의 정확한 소스를 가리킨다.\n버전 타겟팅 프롬프트에 버전을 명시하면 Context7이 자동으로 해당 버전의 문서를 매칭한다:\nCreate a Next.js 15 middleware that validates JWT. use context7 위 프롬프트에서 \u0026ldquo;Next.js 15\u0026quot;를 감지하여 v15 문서에서 middleware 관련 섹션을 가져온다.\nClaude Code에서의 실전 사용 설정 npx ctx7 setup 실전 프롬프트 패턴 기본 사용:\nSupabase Edge Function에서 Row Level Security를 우회하는 서비스 역할 키 사용법을 알려줘. use context7 버전 지정:\nTailwind CSS v4에서 custom theme을 설정하는 방법. use context7 Context7이 없을 때 vs 있을 때 // ❌ Context7 없이 — LLM이 오래된 패턴 생성 가능 import { createMiddlewareClient } from \u0026#39;@supabase/auth-helpers-nextjs\u0026#39; // auth-helpers-nextjs는 deprecated, @supabase/ssr로 대체됨 // ✅ Context7 사용 — 최신 공식 문서 기반 import { createServerClient } from \u0026#39;@supabase/ssr\u0026#39; import { NextResponse, type NextRequest } from \u0026#39;next/server\u0026#39; export async function middleware(request: NextRequest) { let supabaseResponse = NextResponse.next({ request }) const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll() { return request.cookies.getAll() }, setAll(cookiesToSet) { cookiesToSet.forEach(({ name, value }) =\u0026gt; request.cookies.set(name, value)) supabaseResponse = NextResponse.next({ request }) cookiesToSet.forEach(({ name, value, options }) =\u0026gt; supabaseResponse.cookies.set(name, value, options)) }, }, } ) await supabase.auth.getUser() return supabaseResponse } Upstash 커넥션과 비즈니스 모델 Context7은 Upstash가 만든 프로젝트다. Upstash는 서버리스 Redis, Kafka, QStash 등을 제공하는 인프라 회사로, 최근 AI/LLM 도구 생태계로 확장하고 있다.\n오픈소스 경계 컴포넌트 공개 여부 MCP Server 소스 오픈소스 (GitHub) CLI 도구 오픈소스 API Backend 비공개 (Upstash 프로프라이어터리) Crawling/Parsing Engine 비공개 Documentation DB 비공개 MCP 서버와 CLI를 오픈소스로 공개하여 커뮤니티 신뢰와 채택을 얻되, 핵심 가치인 문서 크롤링/파싱/인덱싱 엔진은 독점함으로써 비즈니스 모트를 형성한다.\n수익 모델: 기본 사용은 무료(rate limit 있음)이고, context7.com/dashboard에서 API 키를 발급받으면 더 높은 rate limit를 사용할 수 있다.\n대안과의 비교 방식 정확도 자동화 구축 비용 의존성 수동 문서 복사 높음 없음 없음 없음 자체 RAG 높음 높음 매우 높음 자체 인프라 Context7 높음 높음 거의 없음 Upstash 웹 검색 통합 중간 중간 낮음 검색 API Context7의 가장 큰 장점은 설정 비용 대비 효과다. npx ctx7 setup 한 줄로 수십 개 라이브러리의 최신 문서에 접근할 수 있다.\n비판적 분석 강점 극도로 낮은 진입 장벽: npx ctx7 setup 한 줄이면 끝 버전 인식: 프롬프트에 버전을 명시하면 자동 매칭 광범위한 클라이언트 지원: Cursor, Claude Code, OpenCode 등 30개 이상의 클라이언트와 통합 커뮤니티 모멘텀: 약 49,800 스타는 문서 DB의 품질과 커버리지를 지속적으로 개선할 동력 한계와 리스크 단일 장애점(SPOF): 백엔드 API가 Upstash에 완전히 의존. 서비스 장애 시 대안이 없다 문서 커버리지의 불확실성: 어떤 라이브러리가 DB에 있는지, 얼마나 최신인지 투명하게 공개되지 않는다 프롬프트 토큰 소비: 문서 조각이 컨텍스트에 주입되므로 토큰을 소비한다 \u0026ldquo;use context7\u0026rdquo; 키워드 의존: 프롬프트에 키워드를 붙여야 동작하는 것은 사용자가 판단해야 한다는 뜻이다 벤더 락인 경로: 무료 사용 → rate limit 도달 → 유료 전환의 전형적인 프리미엄 모델 빠른 링크 Context7 GitHub Context7 웹사이트 API 키 발급 Claude Code 플러그인 마켓플레이스 인사이트 Context7은 기술적으로 복잡한 도구가 아니다. \u0026ldquo;최신 문서를 LLM 컨텍스트에 넣어준다\u0026quot;는 아이디어 자체는 누구나 떠올릴 수 있다. 하지만 수천 개 라이브러리의 문서를 지속적으로 크롤링하고, 버전별로 인덱싱하며, 관련 섹션만 정확히 추출하는 인프라를 실제로 구축하고 무료로 제공하는 것은 완전히 다른 문제다. Context7의 진짜 가치는 코드가 아니라 이 데이터 파이프라인에 있다. MCP 생태계의 관점에서 보면, Context7은 MCP가 \u0026ldquo;왜\u0026rdquo; 필요한지를 가장 설득력 있게 보여주는 사례 중 하나다. 다만 장기적으로는 이런 기능이 AI 코딩 도구 자체에 내장될 가능성이 높다. Cursor나 Claude Code가 자체적으로 문서 인덱싱을 제공하기 시작하면, Context7의 독립적인 가치는 줄어들 수 있다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-context7/cover.jpg","permalink":"/ko/posts/2026-03-20-context7/","title":"Context7 — LLM에게 최신 문서를 주입하는 플랫폼 deep dive"},{"content":"개요 Y Combinator CEO Garry Tan이 자신의 Claude Code 개발 환경을 오픈소스로 공개했다. gstack은 Claude Code를 15개의 전문 스킬과 6개의 파워 툴로 구성된 가상 엔지니어링 팀으로 변환하는 스킬 프레임워크로, 공개 첫날 GitHub 스타 10,000개를 돌파하며 현재 27,000개 이상을 기록하고 있다. 60일간 600,000줄 이상의 프로덕션 코드를 작성했다는 Garry Tan의 주장과 함께, 하루 10,000~20,000줄의 사용 가능한 코드를 생산할 수 있다는 점이 개발자 커뮤니티의 폭발적인 관심을 끌었다.\n스프린트 아키텍처 gstack의 핵심은 소프트웨어 개발의 전체 라이프사이클을 7단계 스프린트 프로세스로 구조화한 것이다. 단순히 코드를 생성하는 것이 아니라, 실제 엔지니어링 팀이 수행하는 사고 → 계획 → 구현 → 리뷰 → 테스트 → 배포 → 회고의 순환을 Claude Code 안에서 재현한다.\nflowchart LR A[\"Think \u0026lt;br/\u0026gt; 문제 분석\"] --\u003e B[\"Plan \u0026lt;br/\u0026gt; 설계 및 리뷰\"] B --\u003e C[\"Build \u0026lt;br/\u0026gt; 구현\"] C --\u003e D[\"Review \u0026lt;br/\u0026gt; 코드 리뷰\"] D --\u003e E[\"Test \u0026lt;br/\u0026gt; QA 검증\"] E --\u003e F[\"Ship \u0026lt;br/\u0026gt; 배포\"] F --\u003e G[\"Reflect \u0026lt;br/\u0026gt; 회고\"] G --\u003e|\"다음 스프린트\"| A style A fill:#e1f5fe style B fill:#f3e5f5 style C fill:#e8f5e9 style D fill:#fff3e0 style E fill:#fce4ec style F fill:#e0f2f1 style G fill:#f5f5f5이 프로세스에서 주목할 점은 10~15개의 스프린트를 병렬로 실행할 수 있다는 것이다. Claude Code의 멀티 태스크 기능을 활용해 여러 기능을 동시에 개발하되, 각 스프린트가 독립적인 리뷰와 테스트 단계를 거치도록 설계되어 있다.\n15개 스킬의 역할 분석 gstack은 엔지니어링 팀의 각 역할을 독립된 스킬로 매핑한다. 각 스킬은 / 커맨드로 호출되며, 컨텍스트에 따라 자동으로 로딩되기도 한다.\nCEO \u0026amp; 경영진 역할 스킬 커맨드 역할 CEO Review /plan-ceo-review 비즈니스 관점에서 계획 검토, 우선순위 조정 Design Review /plan-design-review UX/UI 관점의 설계 리뷰 Eng Review /plan-eng-review 기술적 타당성, 아키텍처 리뷰 Office Hours /office-hours 자유로운 질의응답, 방향성 논의 CEO Review는 Garry Tan이 \u0026ldquo;Boulder Ocean\u0026rdquo; 철학이라고 부르는 접근 방식을 따른다. 핵심은 CEO가 세부 구현에 간섭하지 않되, 전략적 방향과 우선순위에 대해서는 명확한 피드백을 제공하는 것이다. 실제로 이 리뷰에서 나오는 대부분의 권고사항은 기본적으로 수용(accept)되도록 설계되어 있어, Claude가 스스로 판단하여 빠르게 진행할 수 있다.\n엔지니어링 역할 스킬 커맨드 역할 Code Review /review PR 수준의 코드 리뷰 수행 QA /qa 자동화 테스트 및 품질 검증 Ship /ship 배포 프로세스 관리 Investigate /investigate 버그 추적, 로그 분석 Careful /careful 신중한 모드로 전환, 위험한 변경 감지 운영 및 문서화 역할 스킬 커맨드 역할 Document Release /document-release 릴리즈 노트 자동 생성 Retro /retro 스프린트 회고, 개선점 도출 Browse /browse 웹 검색 및 참조 자료 수집 Codex /codex 코드베이스 지식 관리 파워 툴 (안전 장치) 툴 커맨드 기능 Freeze /freeze 특정 파일/디렉토리 변경 금지 Guard /guard 변경 감시 및 경고 Unfreeze /unfreeze freeze 해제 /freeze와 /guard는 특히 중요한 안전 장치다. 병렬 스프린트를 실행할 때 여러 Claude 인스턴스가 동일한 파일을 동시에 수정하는 충돌을 방지한다. 예를 들어 핵심 설정 파일이나 데이터베이스 스키마를 freeze하면, 해당 스프린트에서는 그 파일을 건드리지 않는다.\n설치 및 사용법 설치는 간단하다. Claude Code의 스킬 디렉토리에 클론하고 셋업 스크립트를 실행하면 된다:\ngit clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack cd ~/.claude/skills/gstack ./setup 설치 후 Claude Code에서 바로 사용할 수 있다:\n\u0026gt; /plan-ceo-review \u0026gt; 포모도로 타이머 앱을 만들고 싶어. React + TypeScript로. [CEO Review 스킬 활성화] - 목표 명확성: ✅ - 시장 차별점: 권고 - 기존 타이머 대비 차별화 포인트 정의 필요 - 기술 스택 적합성: ✅ React + TS는 이 규모에 적합 - MVP 범위: 타이머 기본 기능 + 세션 기록으로 한정 권고 수용하시겠습니까? [Y/n] CEO 리뷰가 끝나면 자연스럽게 다음 단계로 넘어간다:\n\u0026gt; /plan-eng-review [Eng Review 스킬 활성화] - 컴포넌트 구조 제안 (ASCII 플로우차트 생성) - 상태 관리: useReducer 권고 - 테스트 전략: Vitest + React Testing Library gstack의 특징 중 하나는 ASCII 플로우차트를 자동 생성하여 계획 단계에서 아키텍처를 시각화한다는 점이다. Mermaid가 아닌 ASCII 아트를 사용하는 이유는 Claude Code의 터미널 환경에서 바로 확인할 수 있기 때문이다.\n기존 도구와의 비교 Claude Code 생태계에는 gstack 외에도 여러 확장 도구가 존재한다. 대표적으로 harness와 oh-my-claudecode가 있다.\nflowchart TD subgraph gstack G1[\"역할 기반 스킬 15개\"] G2[\"스프린트 프로세스\"] G3[\"CEO/Design/Eng 리뷰\"] G4[\"Freeze/Guard 안전 장치\"] end subgraph harness[\"harness\"] H1[\"워크플로우 자동화\"] H2[\"커스텀 파이프라인\"] H3[\"도구 체이닝\"] end subgraph omc[\"oh-my-claudecode\"] O1[\"프롬프트 템플릿\"] O2[\"컨텍스트 관리\"] O3[\"설정 프리셋\"] end style gstack fill:#e8f5e9 style harness fill:#e1f5fe style omc fill:#fff3e0 특성 gstack harness oh-my-claudecode 핵심 철학 가상 팀 시뮬레이션 워크플로우 자동화 프롬프트 최적화 스킬 수 15 + 6 파워 툴 커스텀 정의 템플릿 기반 리뷰 프로세스 CEO/Design/Eng 3단 리뷰 없음 없음 병렬 실행 10-15 스프린트 파이프라인 기반 미지원 안전 장치 freeze/guard/unfreeze 없음 없음 설치 방식 git clone + setup npm/pip dotfiles gstack의 가장 큰 차별점은 프로세스 지향적이라는 것이다. 다른 도구들이 \u0026ldquo;Claude Code를 더 잘 쓰는 법\u0026quot;에 집중한다면, gstack은 \u0026ldquo;소프트웨어 팀이 일하는 방식 자체를 Claude Code 안에 이식\u0026quot;하려 한다. CEO 리뷰라는 개념 자체가 다른 도구에는 없는 고유한 레이어다.\nGarry Tan의 배경이 말해주는 것 Garry Tan은 단순한 CEO가 아니다. Palantir의 초기 엔지니어로 Palantir 로고를 직접 디자인했고, 이후 YC의 파트너를 거쳐 CEO가 되었다. 이 배경이 gstack의 설계에 그대로 반영된다:\nPalantir 경험 → 데이터 중심의 의사결정, 구조화된 리뷰 프로세스 YC 경험 → 빠른 MVP, 스프린트 기반 개발, \u0026ldquo;Ship fast\u0026rdquo; 문화 디자인 감각 → Design Review 스킬의 존재, UX를 코드 리뷰와 동등하게 취급 하루 10,000~20,000줄이라는 숫자는 과장처럼 들릴 수 있지만, 병렬 스프린트와 Claude Code의 코드 생성 능력을 고려하면 물리적으로 불가능한 수치는 아니다. 다만 \u0026ldquo;사용 가능한(usable)\u0026rdquo; 코드의 기준이 무엇인지는 논의가 필요하다.\n비판적 분석 강점 구조화된 개발 프로세스: 무작정 \u0026ldquo;코드 짜줘\u0026quot;가 아닌, 계획 → 리뷰 → 구현의 단계를 강제하여 코드 품질을 높인다 안전 장치: /freeze와 /guard로 병렬 작업 시 충돌을 예방하는 것은 실무적으로 매우 유용하다 낮은 진입 장벽: git clone 한 번으로 설치가 끝나며, MIT 라이선스로 자유롭게 사용 가능하다 컨텍스트 자동 로딩: 상황에 맞는 스킬이 자동으로 활성화되어 매번 수동으로 호출할 필요가 없다 약점 및 우려 Claude Code 종속: Anthropic의 Claude Code에만 작동한다. Cursor, Windsurf 등 다른 AI 코딩 도구에서는 사용할 수 없다 \u0026ldquo;마법의 탄환\u0026rdquo; 착각: 27,000 스타의 상당 부분은 Garry Tan의 네임 밸류에서 온 것이다. 동일한 도구를 무명의 개발자가 공개했다면 이 정도 관심을 받았을지 의문이다 LOC 지표의 한계: 줄 수(LOC)는 생산성의 좋은 지표가 아니다. 600,000줄이 모두 의미 있는 코드인지, 보일러플레이트와 생성된 코드가 포함된 수치인지 명확하지 않다 팀 시뮬레이션의 한계: CEO Review, Design Review 등이 실제 인간 리뷰어의 깊이를 대체할 수 있는지는 검증이 필요하다. LLM의 리뷰는 패턴 매칭에 가깝고, 도메인 특화된 비즈니스 판단을 내리기는 어렵다 TypeScript + Go Template 혼합: 스킬 정의가 여러 언어로 분산되어 있어, 커스터마이징 시 진입 장벽이 있다 빠른 링크 GitHub 저장소: garrytan/gstack Claude Code 공식 문서 Y Combinator YouTube: 하루만에 만개의 깃허브 스타를 받은 gstack 인사이트 gstack이 보여주는 가장 흥미로운 패턴은 AI 코딩 도구의 진화 방향이다. 초기에는 \u0026ldquo;코드를 더 빨리 생성하는 것\u0026quot;이 목표였지만, gstack은 \u0026ldquo;소프트웨어 개발 프로세스 전체를 AI 안에 캡슐화하는 것\u0026quot;으로 목표를 확장했다. 이는 단순한 코드 생성 도구에서 개발 방법론 프레임워크로의 전환을 의미한다.\n특히 /freeze와 /guard 같은 안전 장치의 존재는, 병렬 AI 에이전트 실행이 실무에서 실제 문제를 일으킨다는 것을 방증한다. 여러 Claude 인스턴스가 동시에 같은 코드베이스를 수정할 때의 충돌 관리는 앞으로 AI 코딩 도구 생태계 전체가 풀어야 할 과제다.\n다만 gstack의 인기가 도구 자체의 우수성보다 Garry Tan이라는 브랜드에 더 많이 기인한 측면은 분명히 있다. 중요한 것은 이 프레임워크가 실제 프로덕션 환경에서 검증되었는지, 그리고 Garry Tan 본인 외의 개발자들도 동일한 생산성 향상을 경험하는지다. 27,000개의 스타가 27,000명의 활성 사용자를 의미하지는 않는다. Vibe coding의 시대에 도구 선택은 신중해야 하며, 스타 수보다는 자신의 워크플로우에 실질적으로 도움이 되는지를 기준으로 판단해야 한다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-gstack/cover.jpg","permalink":"/ko/posts/2026-03-20-gstack/","title":"gstack — YC CEO Garry Tan이 만든 Claude Code 가상 엔지니어링 팀"},{"content":"개요 HarnessKit은 zero-based vibe coder를 위한 Claude Code Plugin이다. Anthropic의 \u0026ldquo;Effective harnesses for long-running agents\u0026rdquo; 아티클과 기존 harness engineering 구현체들(autonomous-coding, claude-harness 등)을 분석한 뒤, 장점을 수용하고 단점을 개선하는 방향으로 설계했다. 핵심 사이클은 감지 -\u0026gt; 설정 -\u0026gt; 관찰 -\u0026gt; 개선이며, 총 19시간에 걸쳐 설계 스펙부터 v0.1.0 구현까지 완료했다.\n설계: Harness Engineering이란 배경 Vibe coding에서 AI agent는 세션이 끝나면 모든 맥락을 잃는다. feature_list.json에 passes: false를 기록하고, progress 파일로 핸드오프하고, failures.json으로 실패를 학습하는 인프라를 세션 바깥에 구축해야 agent가 일관성을 유지한다. 이것이 harness engineering의 핵심이다.\n기존 구현체들의 문제는 명확했다:\nrepo 속성을 수동으로 파악해야 한다 경험 수준에 관계없이 동일한 가드레일을 적용한다 한번 설정하면 개선 루프가 없다 설계 원칙: Marketplace First, Customize Later 초기 설계에서는 skill seed 템플릿을 플러그인 내부에 두고 /skill-builder로 생성하는 방식이었다. 하지만 논의 과정에서 **\u0026ldquo;바퀴를 재발명하지 말자\u0026rdquo;**는 원칙이 확립되었다:\n\u0026ldquo;이미 나온 강력한 plugin이 있다면 그대로 차용하겠다\u0026rdquo;\n이에 따라 skills/agents 템플릿을 모두 제거하고, marketplace에서 검증된 plugin을 먼저 탐색/설치한 뒤, 사용 패턴을 분석하여 부족한 영역만 /skill-builder로 커스터마이즈하는 구조로 전환했다.\nflowchart TD A[\"/harnesskit:setup\"] --\u003e B[\"Repo 감지\u0026lt;br/\u0026gt;detect-repo.sh\"] B --\u003e C[\"프리셋 선택\u0026lt;br/\u0026gt;beginner / intermediate / advanced\"] C --\u003e D[\"인프라 생성\u0026lt;br/\u0026gt;CLAUDE.md, feature_list,\u0026lt;br/\u0026gt;progress, failures\"] C --\u003e E[\"Marketplace 탐색\u0026lt;br/\u0026gt;skills, agents, review\"] E --\u003e F[\"Plugin 설치 추천\"] D --\u003e G[\"Hooks 등록\u0026lt;br/\u0026gt;session-start, guardrails,\u0026lt;br/\u0026gt;session-end\"] G --\u003e H[\"세션 시작\"] H --\u003e I[\"작업 중\u0026lt;br/\u0026gt;가드레일 + dev hooks\"] I --\u003e J[\"세션 종료\u0026lt;br/\u0026gt;로그 저장 + 패턴 감지\"] J --\u003e|\"반복 패턴 감지\"| K[\"/harnesskit:insights\u0026lt;br/\u0026gt;심층 분석 + diff 제안\"] K --\u003e L[\"/harnesskit:apply\u0026lt;br/\u0026gt;승인 후 적용\"] L --\u003e H구현: 4개 Plan 하루 완성 Plan 1: Plugin Skeleton + Repo Detection Plugin 매니페스트(plugin.json)와 repo 자동 감지 스크립트가 핵심이다. detect-repo.sh는 파일 존재 패턴만으로 language, framework, package manager, test framework, linter를 판별한다. 토큰 소비 0.\n# detect-repo.sh 핵심 로직 (발췌) TOOL=$(echo \u0026#34;$INPUT\u0026#34; | jq -r \u0026#39;.tool_name\u0026#39; 2\u0026gt;/dev/null || echo \u0026#34;\u0026#34;) [ \u0026#34;$TOOL\u0026#34; != \u0026#34;Bash\u0026#34; ] \u0026amp;\u0026amp; exit 0 CMD=$(echo \u0026#34;$INPUT\u0026#34; | jq -r \u0026#39;.tool_input.command // \u0026#34;\u0026#34;\u0026#39; 2\u0026gt;/dev/null || echo \u0026#34;\u0026#34;) 프리셋은 3단계로 나뉜다:\n프리셋 가드레일 브리핑 넛지 임계값 beginner 강 (대부분 BLOCK) 상세 (full) 2세션 intermediate 균형 (core BLOCK, 일부 WARN) 요약 (concise) 3세션 advanced 최소 (대부분 WARN/PASS) 한 줄 (minimal) 5세션 Plan 2: File Generation + Toolkit init.md skill이 모든 harness 인프라 파일을 생성한다. CLAUDE.md는 base.md + framework 템플릿 + preset 필터로 조합된다. .claudeignore는 감지된 프레임워크에 맞는 제외 패턴을 적용한다.\nDev hooks도 여기서 등록된다:\npost-edit-lint.sh \u0026ndash; PostToolUse: 파일 수정 후 자동 lint post-edit-typecheck.sh \u0026ndash; PostToolUse: .ts/.tsx 수정 후 tsc 실행 pre-commit-test.sh \u0026ndash; PreToolUse: git commit 전 테스트 (beginner만) Plan 3: Hooks System (TDD) 가장 까다로웠던 부분. 세 개의 core hook을 TDD로 구현했다.\nguardrails.sh (PreToolUse): stdin으로 JSON을 받아 패턴 매칭:\n{\u0026#34;tool_name\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;tool_input\u0026#34;: {\u0026#34;command\u0026#34;: \u0026#34;git push --force origin main\u0026#34;}} 프리셋별 룰 매트릭스:\n패턴 Beginner Intermediate Advanced sudo BLOCK BLOCK BLOCK rm -rf / BLOCK BLOCK BLOCK .env 쓰기 BLOCK BLOCK WARN git push --force BLOCK BLOCK WARN git reset --hard BLOCK WARN PASS it.skip, test.skip WARN PASS PASS session-start.sh (SessionStart): progress, features, failures를 읽어 프리셋에 맞는 브리핑을 출력한다.\nsession-end.sh (Stop): current-session.jsonl scratch 파일을 읽어 세션 로그를 생성하고 failures.json을 업데이트한다.\nPlan 4: Insights + Apply /harnesskit:insights는 축적된 세션 데이터를 5가지 차원에서 분석한다:\n에러 패턴 (반복 에러, root cause) Feature 진행도 (완료율, 병목) 가드레일 활동 (BLOCK/WARN 빈도) Toolkit 사용 현황 (어떤 plugin이 쓰이는가) 프리셋 적합도 (승급/강등 조건) 거절된 제안은 insights-history.json에 기록되어 동일 category + target 조합을 10세션간 억제한다.\n문제 해결 session-end.sh grep 파이프 실패 grep이 매칭 결과가 없으면 exit code 1을 반환하는데, grep ... | jq -s ... 파이프에서 이 문제가 발생했다. || echo \u0026quot;[]\u0026quot; fallback이 부분 출력([]\\n[])을 만들어 jq --argjson이 깨졌다.\n해결: grep 결과를 변수에 먼저 담고(|| true), 비어있지 않을 때만 jq로 파이핑.\n사용자 프로젝트에 직접적 영향이 없다는 피드백 초기 스펙은 .harnesskit/ 내부 파일만 생성했다. 사용자 입장에서는 \u0026ldquo;harness를 설치했는데 코딩할 때 차이를 못 느끼겠다\u0026quot;는 문제가 있었다.\n\u0026ldquo;초기 repo에는 직접 설치하는 형태를 기대했는데 여태 이야기한 것으로는 그런 직접적 반영이 안되는 느낌이야\u0026rdquo;\n해결: Section 9 전체를 추가하여 Harness Toolkit Generation을 정의. Marketplace plugin 탐색/설치, dev hooks 구성, dev commands 등록, agent 추천까지 포함시켰다. 이후 \u0026ldquo;Marketplace First, Customize Later\u0026quot;로 한번 더 리팩터링.\nInsights 자동 실행 vs 수동 트리거 사용자는 처음에 hooks가 자동으로 /insights를 실행하는 형태를 기대했다.\n\u0026ldquo;처음엔 hooks로 /insights를 실행하고 제안하는 형태를 가정했는데 혹시 다른 형태인가요?\u0026rdquo;\n해결: Hybrid 방식으로 합의. Shell hooks는 토큰 0으로 반복 패턴만 감지하고 넛지를 출력. 실제 /insights는 사용자가 수동으로 트리거하면 Claude가 심층 분석. 진단(내장 insights)과 처방(HarnessKit insights)을 분리.\n커밋 로그 메시지 변경 docs: add HarnessKit design spec and harness engineering research guide 설계 스펙 초안 docs: resolve spec review issues (10/10 fixed, approved) 스펙 리뷰 10건 반영 docs: add Harness Toolkit generation, file impact matrix, v2 roadmap Section 9 추가 + v2 로드맵 docs: integrate /skill-builder for skill generation and improvement skill-builder 연동 docs: add \u0026lsquo;Curate Don\u0026rsquo;t Reinvent\u0026rsquo; principle across all toolkit areas 외부 위임 원칙 docs: add 4 implementation plans for HarnessKit v0.1.0 Plan 1-4 작성 feat: initialize plugin skeleton with manifest and directory structure plugin.json + 디렉토리 구조 feat: add beginner/intermediate/advanced preset definitions 3단계 프리셋 JSON feat: add repo detection script with test suite detect-repo.sh + 11개 테스트 feat: add /harnesskit:setup skill with detection, preset selection, and reset mode setup skill feat: add orchestrator agent for multi-step flow coordination orchestrator agent test: add integration test for setup flow components setup flow 19개 테스트 feat: add CLAUDE.md templates (base + nextjs + fastapi + react-vite + django + generic) 6개 CLAUDE.md 템플릿 feat: add .claudeignore and feature_list starter templates .claudeignore + starter.json feat: add skill seed templates for /skill-builder generation 8개 seed 템플릿 feat: add agent templates (planner, reviewer, researcher, debugger) 4개 agent 템플릿 feat: add dev hooks (auto-lint, auto-typecheck, pre-commit-test) PostToolUse/PreToolUse dev hooks feat: add dev command skills (test, lint, typecheck, dev) and update manifest 4개 dev command skills feat: add init skill \u0026ndash; orchestrates all harness + toolkit generation init.md test: add template validation tests for init 34개 템플릿 검증 테스트 test: add fixtures for hooks testing mock JSON/JSONL fixtures feat: add guardrails hook with preset-aware blocking rules guardrails.sh + 7개 테스트 feat: add session-start hook with preset-aware briefing session-start.sh + 3개 테스트 feat: add session-end hook with log saving, failure tracking, and nudge detection session-end.sh + 5개 테스트 test: add hooks integration test \u0026ndash; full session lifecycle 6개 통합 테스트 feat: add /harnesskit:status skill \u0026ndash; quick dashboard status.md feat: add /harnesskit:insights skill \u0026ndash; analysis, report, and proposal generation insights.md feat: add /harnesskit:apply skill \u0026ndash; proposal review and application apply.md feat: register all skills in plugin manifest plugin.json 최종 업데이트 인사이트 Subagent-Driven Development의 위력: 4개 Plan을 subagent에게 task 단위로 위임하고, spec compliance review + code quality review 2단계 검증을 거쳤다. 하루 만에 85개 테스트가 통과하는 v0.1.0을 완성할 수 있었던 핵심 요인이다.\n\u0026ldquo;Marketplace First\u0026rdquo; 원칙의 진화: 처음에는 seed 템플릿을 직접 작성하고 /skill-builder로 커스터마이즈하는 설계였다. 하지만 \u0026ldquo;이미 좋은 plugin이 있는데 왜 만드나?\u0026ldquo;라는 사용자 피드백으로 전환했다. skill/agent 템플릿을 모두 제거하고 marketplace 우선 탐색으로 바꾼 것은 상당한 코드 삭제를 수반했지만, 유지보수 부담을 크게 줄였다.\nShell Hook의 0-token 설계: guardrails, session-start, session-end 모두 순수 bash + jq로 구현하여 Claude API 호출 없이 동작한다. 세션당 토큰 소비를 최소화하면서도 위험 행동 차단, 브리핑, 로그 수집을 자동화할 수 있었다.\nv2를 위한 데이터 파이프라인 확보: v1의 진짜 가치는 기능 자체보다 데이터 축적 구조다. session-logs, failures.json, insights-history.json이 쌓이면 v2에서 agent 자동 생성, skill 자동 생성, 프리셋 자동 조정이 가능해진다. v1은 v2의 토대다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-harnesskit-dev1/cover.jpg","permalink":"/ko/posts/2026-03-20-harnesskit-dev1/","title":"HarnessKit 개발기 #1 — Zero-Based Vibe Coder를 위한 Adaptive Harness Plugin 설계와 구현"},{"content":"개요 이전 글: #1 — Zero-Based Vibe Coder를 위한 Adaptive Harness Plugin 설계와 구현\nv1이 85개 테스트를 통과하며 완성된 직후, 근본적인 질문이 떠올랐다 — \u0026ldquo;기존 마켓플레이스 플러그인이 있는데 굳이 커스텀 템플릿을 만들어야 하나?\u0026rdquo; 이 질문이 26시간 마라톤 세션의 방향을 결정했다.\ngraph TD A[v1 완성] --\u003e|패러다임 전환| B[Marketplace-First] B --\u003e C[v2a 설계] B --\u003e D[v2b 설계] C --\u003e E[Intelligent Harness Evolution] D --\u003e F[Extended Features] E --\u003e G[세션 데이터 수집 강화] E --\u003e H[딥 패턴 분석] E --\u003e I[자동 생성 제안] F --\u003e J[PRD to Issues] F --\u003e K[Worktree Isolation] F --\u003e L[Bible Template] G --\u003e M[v0.2.0 출시] H --\u003e M I --\u003e M J --\u003e M K --\u003e M L --\u003e M Marketplace-First 패러다임 전환 배경 v1에는 12개 이상의 커스텀 스킬/에이전트 템플릿이 있었다 — nextjs, python-fastapi, common, generic 등 8개 스킬 템플릿과 planner, reviewer, researcher, debugger 4개 에이전트 템플릿. 이 템플릿들은 유지보수 부담이 컸고, Claude Code 플러그인 마켓플레이스에 이미 검증된 플러그인들이 존재했다.\n구현 핵심 커밋 하나가 이 전환을 말해준다: 모든 커스텀 스킬/에이전트 템플릿 삭제. 대신 HarnessKit은 마켓플레이스 플러그인을 큐레이션하고, insights 데이터가 정당화할 때만 /skill-builder를 통해 커스텀 스킬을 생성하는 방식으로 전환했다.\n\u0026ldquo;Curate, Don\u0026rsquo;t Reinvent\u0026rdquo; — 바퀴를 다시 발명하지 말고, 검증된 것을 큐레이션하자\ninit, apply, insights 스킬 모두 이 원칙에 맞게 재작성되었다.\nv2a: Intelligent Harness Evolution 배경 v1의 관찰 시스템은 기본적인 세션 로그 수집에 그쳤다. v2a는 수집된 데이터에서 패턴을 분석하고 자동으로 개선안을 제안하는 지능형 진화 시스템을 목표로 했다.\n브레인스토밍 과정에서 3가지 핵심 결정이 내려졌다:\n점진적 복잡도 — insights 데이터를 보고 언제 진화할지 판단 diff 기반 제안 — 변경사항을 diff로 제안하고, 사용자가 승인 후 적용 최소한의 커맨드 — \u0026ldquo;많은 커맨드가 좋은 사용성을 의미하지 않는다\u0026rdquo; 구현 v2a 스펙은 5가지 핵심 기능을 정의했다:\n세션 데이터 수집 강화 — tool call sequence, 시간 분포, 플러그인 사용 패턴 딥 패턴 분석 — time-sink 감지, 반복 행동 식별, coverage gap 분석 자동 생성 제안 — 사용 패턴 기반으로 agent, skill, hook 자동 생성 제안 리뷰 내재화 파이프라인 — 마켓플레이스 플러그인 → 데이터가 정당화하면 커스텀 대체 A/B 테스트 통합 — /skill-builder와 연동한 스킬 품질 비교 # v2a 세션 종료 시 데이터 추출 예시 (base.md 로깅 프로토콜) # tool call sequence, time distribution, plugin usage를 자동 기록 구현은 subagent-driven development로 진행되어 7개 태스크로 분할 실행했다.\nv2b: Extended Harness Features PRD to GitHub Issues (/harnesskit:prd) PRD 문서를 받아 GitHub 이슈로 분해하고 feature_list.json에 동기화하는 스킬이다. vibe coder가 요구사항을 체계적으로 관리할 수 있게 돕는다.\nWorktree Isolation (/harnesskit:worktree) 하네스 인식 git worktree 관리 스킬이다. 병렬 개발을 위한 격리 환경을 제공하되, 기존 Claude Code의 worktree 기능을 활용하여 처음부터 만들지 않았다 — marketplace-first 원칙의 연장선이다.\nBible Template — 설계 진화의 흥미로운 사례 Bible은 하네스 엔지니어링 원칙을 담은 큐레이션된 템플릿이다. 처음에는 사용자가 자유롭게 확장 가능하도록 설계했으나, 세션 중 중요한 우려가 제기되었다:\n\u0026ldquo;사용자가 자유롭게 추가하면 일관성 없는 가이드라인으로 플러그인 품질이 떨어지지 않을까?\u0026rdquo;\n이 피드백으로 Bible은 플러그인 관리자만 업데이트할 수 있는 상수(constant) 큐레이션 템플릿으로 재설계되었다. 품질 저하 방지를 위한 의도적 제약이다.\n플러그인 포맷 구조 변경 Claude Code 공식 플러그인 포맷으로의 전환이 2라운드에 걸쳐 진행되었다:\n1차: harnesskit/ 중첩 디렉토리 → skills/SKILL.md 플랫 구조 2차: skills/setup.md → skills/setup/SKILL.md 디렉토리 기반 구조 (공식 컨벤션) 26개 이상의 파일이 영향을 받은 대규모 리팩토링이었다.\n제품화 마지막 단계는 HarnessKit을 실제 배포 가능한 제품으로 만드는 것이었다:\nProduction-grade README와 MIT 라이선스 Privacy Policy: \u0026ldquo;No external data collection\u0026rdquo; — 모든 데이터가 .harnesskit/에 로컬 저장 버전 0.2.0으로 범프, 모든 v2b 스킬 등록 모노레포 감지 강화: detect-repo.sh가 backend/frontend 하위 디렉토리 스캔 커밋 로그 메시지 변경 refactor: marketplace-first approach — remove skill/agent templates 대규모 삭제 + 재작성 docs: add HarnessKit v2a design spec v2a 설계 문서 docs: add v2a implementation plan 구현 계획 feat(v2a): add tool usage and plugin logging protocol base.md 로깅 test(v2a): add session data fixtures 테스트 픽스처 feat(v2a): add tool call sequence, time distribution extraction 데이터 추출 feat(v2a): add v2a config schema initialization 설정 스키마 feat(v2a): add v1→v2a migration path 마이그레이션 feat(v2a): add review internalization, custom toolkit to status 상태 대시보드 feat(v2a): add agent/hook/review proposals to apply 적용 실행 경로 feat(v2a): add time-sink, repeated actions, coverage gap analysis 딥 분석 docs: add HarnessKit v2b design spec v2b 설계 문서 docs: redesign bible as constant curated template Bible 재설계 feat(v2b): add curated bible template Bible 구현 feat(v2b): add /harnesskit:prd skill PRD 스킬 feat(v2b): add /harnesskit:worktree skill Worktree 스킬 feat(v2b): add A/B eval comparison to apply 스킬 비교 평가 feat(v2b): register prd + worktree skills, bump to 0.2.0 버전 범프 docs: add production README, LICENSE, .gitignore 제품화 refactor: restructure to official Claude Code plugin format 1차 구조 변경 docs: add privacy policy 개인정보 보호 refactor: restructure skills/agents to official plugin format 2차 구조 변경 feat: enhance detect-repo.sh for monorepos 모노레포 감지 인사이트 26시간 마라톤 세션에서 가장 인상적이었던 것은 \u0026ldquo;Curate, Don\u0026rsquo;t Reinvent\u0026rdquo; 원칙의 채택이다. v1에서 공들여 만든 12개 이상의 템플릿을 과감하게 삭제하고 마켓플레이스 우선 접근으로 전환한 것은 기술적으로도, 철학적으로도 큰 전환이었다. Bible 템플릿의 설계 변경도 흥미로운 사례다 — \u0026ldquo;사용자에게 자유를 주자\u0026quot;에서 \u0026ldquo;품질을 위해 의도적으로 제약하자\u0026quot;로의 전환은 플러그인 생태계의 성숙도와 관련된 중요한 교훈이다. v2a/v2b의 핵심은 결국 데이터 기반 판단 — insights가 정당화할 때만 커스텀 스킬을 생성하고, 그 전까지는 검증된 마켓플레이스 플러그인을 사용하는 것이다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-harnesskit-dev2/cover.jpg","permalink":"/ko/posts/2026-03-20-harnesskit-dev2/","title":"HarnessKit 개발기 #2 — Marketplace-First 전환과 v2a/v2b 설계 및 구현"},{"content":"개요 이전 글: #2\n\u0026ldquo;동작하게 만들기\u0026quot;에서 \u0026ldquo;제대로 만들기\u0026quot;로의 전환이 이번 세션의 주제다. Gemini API를 비동기로 전환하고 동시 생성을 지원한 뒤, 성능 최적화 과정에서 드러난 구조적 부채를 해결하기 위해 1,516줄의 main.py를 11-task, 4-phase 계획으로 체계적으로 분해했다.\ngraph TD A[성능 최적화] --\u003e B[비동기 병렬화] A --\u003e C[동시 생성 지원] B --\u003e D[구조적 부채 노출] C --\u003e D D --\u003e E[코드 리뷰] E --\u003e F[11-task 4-phase 분해 계획] F --\u003e G[Phase 1: generation 모듈] F --\u003e H[Phase 2: app_utils] F --\u003e I[Phase 3: routes 분리] F --\u003e J[Phase 4: main.py 정리] G --\u003e K[\"main.py 1516줄 → ~900줄\"] H --\u003e K I --\u003e K 비동기 병렬화 배경 기존 이미지 생성 파이프라인은 async def 안에서 동기 client.models.generate_content()를 호출하고 있었다 — 이벤트 루프 전체를 블로킹하는 구조였다. google-genai SDK v1.62.0에 이미 비동기 API client.aio.models.generate_content()가 존재했으나 사용하지 않고 있었다.\n구현: 2단계 병렬화 # 1단계: 배치 내 병렬화 — 개별 이미지 동시 생성 async def _generate_single_image(...): async with semaphore: # Semaphore(4) — API rate limit 준수 return await client.aio.models.generate_content(...) results = await asyncio.gather( *[_generate_single_image(item) for item in batch] ) # 2단계: 배치 간 병렬화 — primary + comparison 동시 실행 primary, comparison = await asyncio.gather( generate_batch(primary_items), generate_batch(comparison_items) ) 4장 이미지 + comparison 모드 기준, 기존에 8번 순차 호출하던 것이 Semaphore(4) 제한 내에서 병렬 실행되어 체감 속도가 크게 개선되었다.\n프론트엔드: 동시 생성 지원 비동기 전환 후에도 UI가 생성 중 버튼을 잠그고 있었다. generating: boolean을 generatingCount: number로 교체하여 여러 생성 요청을 동시에 실행할 수 있게 했다.\n// Before: boolean lock — 한 번에 하나만 const [generating, setGenerating] = useState(false); // After: counter — 동시 생성 허용 const [generatingCount, setGeneratingCount] = useState(0); // 버튼은 프롬프트가 비어있을 때만 disable // 스피너: \u0026#34;2건 이미지 생성 중...\u0026#34; 생성 품질 개선 프롬프트 구조화 Gemini에 보내는 프롬프트에 구조화된 섹션 헤더(### 핵심 생성 주제 ###, 구분선 등)를 추가하여 지시사항을 명확하게 전달하도록 개선했다. 디테일 뷰에 full prompt preview를 추가하여 실제로 어떤 프롬프트가 전송되었는지 확인 가능해졌다.\n참조 이미지 랜덤화 기존에는 tone/angle 참조 이미지로 항상 가장 높은 점수의 이미지 하나만 선택했다 — 같은 쿼리에 항상 같은 결과가 나오는 결정론적 구조였다.\ngraph LR A[참조 이미지 후보] --\u003e B[유사도 점수 계산] B --\u003e C[\"상위 20% 필터링 (최소 1장)\"] C --\u003e D[random.choice] D --\u003e E[프롬프트에 포함]random.choice로 상위 20% 풀에서 랜덤 선택하도록 변경했다. search-based와 fallback 경로 모두, tone과 angle 참조 모두에 적용된다. 작은 변경이지만 생성 결과의 다양성이 크게 향상되었다.\n구조적 리팩토링: main.py 분해 코드 리뷰 결과 비동기 코드 추가 후 요청한 코드 리뷰에서 main.py의 문제가 명확해졌다:\n1,516줄에 7가지 책임: app bootstrap, auth, image serving, search, generation injection, Gemini service, generation orchestration APIRouter 미사용 — 모든 라우트가 @app.get/@app.post로 직접 등록 전역 가변 상태 — images_data, hybrid_pipeline 등이 모듈 레벨 변수 145줄짜리 _generate_single_image 함수 분해 계획 11개 태스크, 4단계 분해 계획을 수립:\nPhase 추출 대상 결과 1 generation/injection.py, prompt.py, service.py 생성 핵심 로직 분리 2 app_utils.py 공유 유틸리티 3 routes/auth.py, meta.py, images.py, search.py, history.py, generation.py APIRouter 기반 라우트 분리 4 main.py 최종 정리 ~100줄 목표 실행과 기술적 결정 Subagent-driven development로 실행 — 각 태스크를 별도 서브에이전트에 위임하고 2단계 리뷰(스펙 준수 + 코드 품질)를 거쳤다.\n리팩토링 중 내린 핵심 결정들:\n전역 변수 → 명시적 파라미터: images_data, hybrid_pipeline 등을 읽는 함수는 명시적 파라미터를 받도록 변경 순환 import 방지: 라우트 모듈은 main.py의 전역 변수를 함수 본문 내에서만 접근 (모듈 스코프에서 접근하지 않음) _gemini_semaphore: generation/service.py로 이동, main.py에서 삭제 발견된 기존 버그: get_image_file_legacy에 auth dependency 누락 — 동작 보존 리팩토링이므로 기록만 하고 수정하지 않음 결과 세션 종료 시점에 Phase 1 완료, Phase 2 완료, Phase 3 진행 중 (routes/auth.py, routes/meta.py 추출 완료). main.py가 1,516줄에서 약 900줄로 감소했고, 나머지 라우트 추출이 남아있다.\n커밋 로그 메시지 변경 feat: allow concurrent image generations by removing button lock boolean → counter, 동시 생성 UI feat: add structured prompt headers and full prompt preview 프롬프트 품질 + 디버깅 feat: randomize tone/angle ref selection from top 20% candidates 생성 다양성 확보 refactor: extract generation/injection.py from main.py Phase 1 — 인젝션 분리 refactor: extract generation/prompt.py from main.py Phase 1 — 프롬프트 분리 refactor: extract generation/service.py from main.py Phase 1 — Gemini 서비스 분리 refactor: extract app_utils.py with shared utilities Phase 2 — 유틸리티 분리 refactor: extract routes/auth.py with APIRouter Phase 3 — 인증 라우트 분리 인사이트 이번 세션은 성능 최적화가 구조적 리팩토링을 촉발하는 전형적인 패턴을 보여준다. 비동기 병렬화를 추가하면서 main.py의 복잡도가 임계점을 넘었고, 코드 리뷰가 체계적 분해의 계기가 되었다. 리팩토링에서 가장 중요했던 원칙은 동작 보존 — 기존 버그도 의도적으로 유지하면서 구조만 변경하는 것이다. 참조 이미지 랜덤화는 한 줄 변경에 가까운 작은 수정이지만, 생성 AI 파이프라인에서 \u0026ldquo;결정론적 최적\u0026quot;보다 \u0026ldquo;확률적 다양성\u0026quot;이 사용자 경험에 더 크게 기여한다는 점을 보여주는 좋은 사례다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-hybrid-search-dev3/cover.jpg","permalink":"/ko/posts/2026-03-20-hybrid-search-dev3/","title":"Hybrid Image Search 개발기 #3 — 비동기 병렬화, 프롬프트 품질 개선, 구조적 리팩토링"},{"content":"개요 이전 글: #1 — Sessions 명령어와 개발일지 자동화\nlog-blog 스킬을 실행하면서 근본적인 문제를 발견했다 — 브라우저 히스토리만 추출되고, Claude Code 세션과 커밋 기반 개발일지가 초기 리스트에 포함되지 않았다. 이 문제를 해결하기 위해 두 흐름을 통합하고, --since-last-run 플래그로 시간 범위를 자동 관리하도록 개선했다.\ngraph TD A[\"문제 발견: 세션/커밋 누락\"] --\u003e B[설계 스펙 작성] B --\u003e C[리뷰 피드백 반영] C --\u003e D[구현 계획 수립] D --\u003e E[run_state 모듈] D --\u003e F[\"extract --since-last-run\"] D --\u003e G[\"sessions --since-last-run\"] D --\u003e H[SKILL.md 통합] E --\u003e I[통합 완료] F --\u003e I G --\u003e I H --\u003e I I --\u003e J[\"fix: JSON 경로에서 save_last_run\"] 문제 발견 log-blog 스킬을 실행하면 Step 1에서 extract --json으로 브라우저 히스토리만 추출했다. Claude Code 세션과 git 커밋 기반 개발일지는 별도로 요청해야만 리스트업되었다.\n사용자의 피드백이 직접적이었다:\n\u0026ldquo;커밋을 내가 안했을 리가 없는데 혹시 오류아냐?\u0026rdquo; \u0026ldquo;세션과 커밋 기반으로는 왜 포스트를 만들지 않나요?\u0026rdquo;\n매일 두 작업(브라우저 히스토리 + 개발일지)을 실행할 것이므로, 초기부터 양쪽 모두 리스트업하는 통합 흐름이 필요했다.\n설계: Unified Skill Flow 핵심 결정 브레인스토밍에서 3가지 접근을 검토한 후, 시간은 늘어나더라도 매번 양쪽 모두 실행하는 방식을 선택했다:\nStep 1에서 extract와 sessions --list를 동시에 실행 Step 3에서 브라우저 기반 항목과 dev log 후보를 함께 제시 사용자 승인 후 브라우저 항목은 fetch로, dev log은 sessions --project로 진행 \u0026ndash;since-last-run 추적 --hours 24 기본값의 문제: 이틀에 한 번 실행하면 하루치가 누락되고, 하루에 두 번 실행하면 중복된다.\n해결책: last-run 타임스탬프 기반 시간 범위 자동 계산\ngraph LR A[실행 시작] --\u003e B{last-run 파일 존재?} B --\u003e|Yes| C[\"hours = (now - last_run).hours\"] B --\u003e|No| D[\"hours = 24 (기본값)\"] C --\u003e E[extract/sessions 실행] D --\u003e E E --\u003e F[last-run 타임스탬프 저장] 구현 run_state 모듈 run_state.py를 추가하여 last-run 타임스탬프를 관리한다:\n# 마지막 실행 시각 로드/저장 def load_last_run() -\u0026gt; Optional[datetime]: ... def save_last_run(timestamp: datetime) -\u0026gt; None: ... def hours_since_last_run() -\u0026gt; Optional[float]: ... 타임스탬프는 프로젝트 루트의 .log-blog-last-run 파일에 ISO 8601 형식으로 저장된다.\nextract/sessions에 \u0026ndash;since-last-run 플래그 추가 extract와 sessions 명령어 모두에 --since-last-run 플래그를 추가했다. 이 플래그가 설정되면:\nhours_since_last_run()으로 마지막 실행 이후 경과 시간 계산 해당 시간을 --hours 값으로 사용 last-run 파일이 없으면 기본 24시간으로 폴백 실행 완료 후 save_last_run() 호출 SKILL.md 통합 스킬 문서를 수정하여 Step 1에서 양쪽 명령어를 동시에 실행하도록 통합했다:\n# Step 1: 동시 실행 uv run log-blog extract --json --since-last-run uv run log-blog sessions --list --since-last-run Step 3의 사용자 확인 화면에도 dev log 후보가 자동으로 포함되도록 스킬 문서를 개선했다.\n버그 수정: JSON 출력 경로에서 save_last_run 마지막 커밋은 --json 플래그 사용 시 save_last_run이 호출되지 않는 버그를 수정했다. JSON 출력 경로에서도 실행 완료 후 타임스탬프가 저장되도록 했다.\n커밋 로그 메시지 변경 docs: add unified skill flow and session data bug fix design spec 설계 스펙 docs: address spec review feedback 리뷰 피드백 반영 docs: add last-run tracking feature to unified skill flow spec last-run 추적 스펙 추가 docs: add implementation plan 구현 계획 feat: add run_state module for last-run timestamp tracking run_state 모듈 feat: add \u0026ndash;since-last-run flag to extract command extract 플래그 feat: add \u0026ndash;since-last-run flag to sessions command sessions 플래그 feat: unify browser history and dev log flows in SKILL.md 스킬 통합 fix: save_last_run in JSON output path of extract command JSON 경로 버그 수정 인사이트 이번 개선의 트리거는 \u0026ldquo;사용자가 직접 도구를 사용하면서 느낀 불편함\u0026quot;이었다. 개발자가 자신의 도구를 직접 사용하는 dogfooding의 가치를 다시 확인했다. --since-last-run 플래그는 기술적으로 단순하지만 (타임스탬프 저장/로드), 사용자 경험에 미치는 영향은 크다 — \u0026ldquo;몇 시간을 지정할까?\u0026rdquo; 라는 판단을 완전히 제거해준다. 설계 → 리뷰 → 구현의 3단계 워크플로우가 9개 커밋에 걸쳐 체계적으로 진행된 점도 log-blog 프로젝트의 성숙도를 보여준다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-log-blog-dev2/cover.jpg","permalink":"/ko/posts/2026-03-20-log-blog-dev2/","title":"Log-Blog 개발기 #2 — Unified Skill Flow와 --since-last-run 추적"},{"content":"개요 AI 코딩 에이전트가 코드를 생성하는 시대는 이미 왔다. 하지만 한 가지 근본적인 질문이 남는다 — 에이전트 자체는 어떻게 개선되는가? 현재 대부분의 AI 코딩 도구는 매 세션마다 백지 상태에서 시작한다. 이전 작업에서 무엇을 배웠든 다음 세션에는 반영되지 않는다.\nMEGA Code는 이 문제를 정면으로 공략한다. 세션 로그에서 Skills(재사용 가능한 노하우)과 Strategies(의사결정 가이드)를 자동 추출하여, AI 코딩 에이전트가 경험을 축적하고 스스로 진화하는 인프라를 구축하겠다는 야심 찬 프로젝트다. 벤치마크에 따르면 토큰 사용량을 1/5로 줄이면서도 구조적 품질을 3배 향상시켰다고 한다.\n이 포스트에서는 MEGA Code의 핵심 개념, 3-Layer 아키텍처, 벤치마크 주장에 대한 분석, 그리고 다른 메타러닝 접근법과의 비교까지 깊이 파고들어 본다.\n핵심 개념: Skills vs Strategies MEGA Code의 자기진화 메커니즘은 두 가지 핵심 개념 위에 세워져 있다. 얼핏 비슷해 보이지만, 역할과 추출 방식이 근본적으로 다르다.\nSkills — 재사용 가능한 노하우 Skill은 특정 작업을 수행하는 구체적인 절차적 지식이다. \u0026ldquo;어떻게(How) 하는가\u0026quot;에 대한 답이다.\n예시:\nReact 컴포넌트 테스트 작성: Jest + React Testing Library로 컴포넌트를 마운트하고, user event를 시뮬레이션하고, assertion을 작성하는 일련의 패턴 API 에러 핸들링 표준화: try-catch 블록의 구조, 에러 타입별 분기, 사용자에게 노출할 메시지 포맷 DB 마이그레이션 스크립트 생성: 스키마 변경을 감지하고, rollback 가능한 마이그레이션 파일을 생성하는 절차 Skill은 diff에서 추출된다. 에이전트가 코드를 수정한 이력(before → after)을 분석하여 \u0026ldquo;이 패턴은 반복적으로 적용할 수 있는 노하우다\u0026quot;라고 판단되면 Skill로 등록된다.\nStrategies — 의사결정 가이드 Strategy는 상황에 따른 판단 기준이다. \u0026ldquo;무엇을(What) 선택하는가\u0026quot;에 대한 답이다.\n예시:\n상태 관리 도구 선택: 컴포넌트 수가 10개 미만이면 React Context, 글로벌 상태가 복잡하면 Zustand, 서버 상태가 주요하면 TanStack Query 테스트 전략 결정: 유틸 함수는 unit test, API 통합은 integration test, 핵심 유저 플로우는 E2E test 리팩토링 우선순위: 변경 빈도가 높은 파일부터, 의존성이 적은 모듈부터 Strategy는 반복적인 편집 패턴에서 추출된다. 에이전트가 비슷한 상황에서 일관된 선택을 반복하면, 그 선택 기준이 Strategy로 추상화된다.\ngraph LR A[\"세션 로그\"] --\u003e B[\"Diff 분석\"] A --\u003e C[\"패턴 감지\"] B --\u003e D[\"Skills \u0026lt;br/\u0026gt; (절차적 노하우)\"] C --\u003e E[\"Strategies \u0026lt;br/\u0026gt; (의사결정 가이드)\"] D --\u003e F[\"Skill Registry\"] E --\u003e G[\"Strategy Registry\"] F --\u003e H[\"다음 세션에 \u0026lt;br/\u0026gt; 자동 적용\"] G --\u003e HDiff-to-Skill 파이프라인 MEGA Code의 핵심 엔진은 세션 로그의 diff를 Skill로 변환하는 파이프라인이다. 단순히 코드 변경 이력을 저장하는 것이 아니라, 추상화된 재사용 가능한 지식으로 승격시키는 과정이다.\n파이프라인 동작 방식 Diff 수집: 에이전트가 코드를 수정할 때마다 before/after diff가 기록된다 패턴 클러스터링: 유사한 diff들을 그룹핑한다. 예를 들어 \u0026ldquo;API 호출 후 에러 핸들링 추가\u0026rdquo; 패턴이 3번 이상 반복되면 하나의 클러스터로 묶인다 추상화: 구체적인 변수명, 함수명을 제거하고 패턴의 본질만 남긴다. fetchUser → fetchEntity, UserError → EntityError처럼 일반화한다 Skill 생성: 추상화된 패턴에 이름, 설명, 적용 조건, 코드 템플릿을 부여하여 Skill로 등록한다 검증: 생성된 Skill이 새로운 세션에서 실제로 유용한지 피드백 루프를 통해 검증한다 이 과정에서 흥미로운 점은 양적 임계치가 존재한다는 것이다. 한 번 나타난 패턴은 무시되고, 반복적으로 등장하는 패턴만 Skill로 승격된다. 이는 노이즈를 줄이고 실제로 재사용 가능한 지식만 축적하는 효과가 있다.\nStrategy 추출 메커니즘 Strategy 추출은 더 상위 수준에서 이루어진다. Diff 자체가 아니라 에이전트의 선택 패턴을 분석한다.\n예를 들어, 에이전트가 상태 관리 코드를 작성할 때:\n세션 A: 작은 앱 → Context API 선택 세션 B: 복잡한 앱 → Zustand 선택 세션 C: 서버 상태 중심 → TanStack Query 선택 이런 선택 이력이 쌓이면, \u0026ldquo;앱의 복잡도와 상태 특성에 따라 상태 관리 도구를 다르게 선택하라\u0026quot;는 Strategy가 자동 생성된다.\n3-Layer 아키텍처 MEGA Code는 점진적으로 복잡도를 높여가는 3단계 아키텍처를 제시한다.\ngraph TB subgraph L1[\"Layer 1 — 현재\"] A1[\"Auto Skills Generation\"] --\u003e A2[\"Auto Strategies Generation\"] A2 --\u003e A3[\"Eureka VS Code Extension\"] end subgraph L2[\"Layer 2 — 계획 중\"] B1[\"Wisdom Graph\"] --\u003e B2[\"Atomic-level \u0026lt;br/\u0026gt; Skill Decomposition\"] B2 --\u003e B3[\"Cross-project \u0026lt;br/\u0026gt; Knowledge Transfer\"] end subgraph L3[\"Layer 3 — 계획 중\"] C1[\"Offline Optimization\"] --\u003e C2[\"Compound Intelligence\"] C2 --\u003e C3[\"Multi-agent \u0026lt;br/\u0026gt; Collaboration\"] end L1 --\u003e L2 L2 --\u003e L3 style L1 fill:#2d5016,stroke:#4a8c28,color:#fff style L2 fill:#1a3a5c,stroke:#2980b9,color:#fff style L3 fill:#5c1a3a,stroke:#b92980,color:#fffLayer 1: Auto Skills \u0026amp; Strategies + Eureka (현재) 현재 가용한 단계다. 세션 로그에서 Skills과 Strategies를 자동 추출하고, VS Code extension인 Eureka를 통해 개발자에게 제공한다.\nEureka Extension의 역할:\n추출된 Skills/Strategies를 VS Code 내에서 직접 조회 가능 현재 작업 컨텍스트에 맞는 Skill을 자동 추천 개발자가 수동으로 Skill을 편집하거나 새로 등록할 수 있는 인터페이스 제공 프로젝트별 Skills/Strategies를 분리 관리 Eureka는 단순한 코드 스니펫 관리 도구가 아니다. 컨텍스트 인식 기반 추천이 핵심이다. 현재 열려 있는 파일, 커서 위치, 최근 편집 이력을 분석하여 관련된 Skill을 능동적으로 제안한다.\nLayer 2: Wisdom Graph (계획 중) Skill과 Strategy를 **원자 수준(atomic level)**으로 분해하겠다는 구상이다. 하나의 복합 Skill을 더 작은 단위로 쪼개고, 이들 사이의 관계를 그래프로 모델링한다.\n왜 원자 모듈화가 중요한가?\n현재 Layer 1의 Skills은 상대적으로 거친(coarse-grained) 단위다. \u0026ldquo;React 컴포넌트 테스트 작성\u0026quot;이라는 Skill은 내부적으로 여러 세부 단계를 포함한다. 문제는 이 중 일부만 필요한 상황에서도 전체 Skill이 적용되어 불필요한 토큰을 소비한다는 것이다.\nWisdom Graph는 이를 해결한다:\n컴포넌트 마운트 → 이벤트 시뮬레이션 → assertion 작성 각각이 독립된 atomic Skill 필요한 부분만 선택적으로 조합 프로젝트 간 지식 전이(cross-project knowledge transfer)가 가능해짐 이는 마치 Unix 철학의 \u0026ldquo;한 가지 일을 잘하는 작은 프로그램들을 조합한다\u0026quot;와 유사하다.\nLayer 3: Offline Optimization + Compound Intelligence (계획 중) 가장 야심 찬 단계다. 에이전트가 실시간 세션이 아닌 오프라인 상태에서 기존 Skill/Strategy를 최적화하고, 여러 에이전트의 경험을 통합하는 Compound Intelligence를 구현한다.\n이 단계가 실현되면:\n에이전트 A가 프론트엔드에서 배운 노하우를 에이전트 B의 백엔드 작업에 적용 밤 사이에 축적된 Skill들을 자동으로 정리, 병합, 최적화 다수의 에이전트가 협업하는 Multi-agent 시나리오에서 지식 공유 벤치마크 분석 MEGA Code 팀이 공개한 벤치마크 수치는 인상적이다:\n지표 Baseline MEGA Code 개선율 토큰 사용량 897K 169K 81% 감소 (약 1/5) 구조적 품질 1x 3x 3배 향상 토큰 사용량 1/5 감소 이 수치가 의미하는 바는 크다. 토큰 사용량 감소는 곧:\n비용 절감: LLM API 호출 비용이 1/5로 감소 속도 향상: 처리할 토큰이 줄어들면 응답 속도도 빨라짐 컨텍스트 윈도우 효율화: 제한된 컨텍스트 윈도우를 더 유용한 정보에 할당 가능 토큰 감소의 메커니즘은 명확하다. Skills가 축적되면 에이전트는 매번 \u0026ldquo;처음부터 생각\u0026quot;할 필요 없이 검증된 패턴을 바로 적용한다. 이는 Few-shot prompting과 유사하지만, 프롬프트 자체를 줄이는 것이 아니라 불필요한 탐색과 시행착오를 제거하는 방식이다.\n구조적 품질 3배 향상 \u0026ldquo;구조적 품질\u0026quot;의 정확한 측정 기준이 공개되지 않은 점은 주의가 필요하다. 가능한 측정 방식으로는:\n코드 구조의 일관성 (naming convention, 파일 구조 등) 아키텍처 패턴 준수율 테스트 커버리지 코드 리뷰 통과율 벤치마크 조건 (어떤 프로젝트, 어떤 태스크, 비교 대상 모델 등)의 세부사항이 추가로 공개되면 더 정확한 평가가 가능할 것이다.\n다른 메타러닝 접근법과의 비교 MEGA Code만이 \u0026ldquo;AI 에이전트의 자기 개선\u0026quot;에 도전하는 것은 아니다. 유사한 방향의 프로젝트들과 비교해 보자.\nHarnessKit의 Observe-Improve Loop HarnessKit은 에이전트의 행동을 관찰(observe)하고, 결과를 기반으로 프로세스를 개선(improve)하는 루프를 구축한다.\n공통점: 세션 이력을 분석하여 에이전트를 개선한다 차이점: HarnessKit은 프로세스 레벨의 개선에 집중하고, MEGA Code는 지식(Skills/Strategies) 레벨의 개선에 집중한다. HarnessKit이 \u0026ldquo;어떤 순서로 작업하면 효율적인가\u0026quot;를 최적화한다면, MEGA Code는 \u0026ldquo;어떤 코드 패턴을 적용하면 좋은가\u0026quot;를 최적화한다. Superpowers의 Memory 시스템 Superpowers는 에이전트에게 장기 기억(long-term memory)을 부여한다.\n공통점: 세션 간 지식 유지 차이점: Superpowers의 memory는 상대적으로 raw한 형태의 기억 저장에 가깝고, MEGA Code의 Skills/Strategies는 구조화되고 추상화된 지식이다. Memory가 \u0026ldquo;일기장\u0026quot;이라면, Skills은 \u0026ldquo;교과서\u0026quot;에 가깝다. Claude의 Memory/CLAUDE.md Anthropic의 Claude Code도 CLAUDE.md와 memory 시스템을 통해 프로젝트 컨텍스트를 유지한다.\n공통점: 세션 간 지식 전달 차이점: Claude의 memory는 사용자가 명시적으로 관리하고 CLAUDE.md에 기록하는 반면, MEGA Code는 자동 추출을 목표로 한다. 자동화 수준에서 MEGA Code가 더 야심 찬 접근이지만, 자동 추출의 정확도와 노이즈 관리가 핵심 과제가 된다. 접근법 지식 형태 추출 방식 추상화 수준 MEGA Code Skills + Strategies 자동 (diff 분석) 높음 HarnessKit Process 패턴 반자동 (observe loop) 중간 Superpowers Raw memory 자동 (세션 기록) 낮음 Claude Memory 구조화된 노트 수동 + 반자동 중간 비판적 분석 강점 명확한 문제 정의: \u0026ldquo;에이전트가 경험에서 배우지 못한다\u0026quot;는 문제를 정확히 짚었다 Skills/Strategies 구분: 절차적 지식과 의사결정 지식을 분리한 프레임워크가 깔끔하다 점진적 아키텍처: 3-Layer 접근으로 현재 가용한 가치와 미래 비전을 분리했다 인상적인 벤치마크: 토큰 1/5 감소는 실질적 비용 절감으로 직결된다 약점과 열린 질문 Skill 품질 관리: 자동 추출된 Skill이 실제로 유용한지 어떻게 검증하는가? 잘못된 패턴이 Skill로 등록되면 오히려 코드 품질이 하락할 수 있다 프로젝트 종속성: 프로젝트 A에서 추출한 Skill이 프로젝트 B에서도 유효한가? 도메인별 컨벤션이 다른 환경에서 cross-project transfer의 한계는? Skill 충돌: 두 Skill이 상충하는 패턴을 권장하면 어떻게 처리하는가? 벤치마크 투명성: 구조적 품질 3배 향상의 측정 기준과 실험 조건이 충분히 공개되지 않았다 Layer 2/3의 실현 가능성: Wisdom Graph와 Compound Intelligence는 아직 구상 단계다. Layer 1의 성과가 곧 Layer 2/3의 성공을 보장하지는 않는다 Lock-in 리스크: Skills/Strategies가 MEGA Code 플랫폼에 종속되면, 다른 도구로의 전환이 어려워질 수 있다 기대와 우려 가장 기대되는 부분은 Wisdom Graph다. 현재 AI 코딩 도구들의 가장 큰 문제 중 하나인 \u0026ldquo;맥락 없는 코드 생성\u0026quot;을 해결할 잠재력이 있다. 하지만 원자 수준의 Skill 분해가 실제로 가능한지, 그리고 그 분해된 조각들을 의미 있게 재조합할 수 있는지는 여전히 증명되지 않았다.\n빠른 링크 MEGA Code 공식 사이트 — 제품 소개 및 접근 신청 Eureka VS Code Extension — VS Code Marketplace에서 검색 MEGA Code 벤치마크 리포트 — 토큰 감소 및 품질 향상 데이터 인사이트 \u0026ldquo;경험에서 배우는 에이전트\u0026quot;는 AI 코딩의 다음 전선이다. 코드 생성 능력은 이미 범용화되고 있다. 차별화는 \u0026ldquo;더 잘 생성하는가\u0026quot;가 아니라 \u0026ldquo;사용할수록 더 나아지는가\u0026quot;에서 나올 것이다.\nSkills vs Strategies 구분은 인간 전문가의 지식 구조를 반영한다. 숙련된 개발자는 \u0026ldquo;어떻게 구현하는가\u0026rdquo;(절차적 지식)와 \u0026ldquo;무엇을 선택하는가\u0026rdquo;(전략적 판단)를 별도로 축적한다. MEGA Code가 이 구조를 자동화하려는 시도는 이론적으로 건전하다.\n토큰 효율성은 비용 문제를 넘어 품질 문제다. 컨텍스트 윈도우가 제한된 상황에서, 불필요한 토큰을 줄이면 정말 중요한 정보에 더 많은 공간을 할당할 수 있다. 이는 단순한 비용 절감이 아니라 에이전트의 \u0026ldquo;주의력\u0026rdquo; 개선이다.\n자동 추출의 정확도가 핵심 병목이 될 것이다. 잘못된 Skill이 등록되면 에이전트가 잘못된 패턴을 반복 적용한다. \u0026ldquo;쓰레기가 들어가면 쓰레기가 나온다(GIGO)\u0026ldquo;의 메타 버전이 발생할 수 있다. Skill의 품질 관리 메커니즘이 MEGA Code의 성패를 가를 것이다.\n경쟁은 \u0026ldquo;누가 먼저 자기진화 루프를 완성하는가\u0026quot;로 수렴하고 있다. MEGA Code, HarnessKit, Superpowers 모두 같은 방향을 가리키고 있다. 최종 승자는 가장 빠른 팀이 아니라, 가장 신뢰할 수 있는 자기진화 루프를 구축한 팀이 될 가능성이 높다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-mega-code/cover.jpg","permalink":"/ko/posts/2026-03-20-mega-code/","title":"MEGA Code — 세션 로그에서 스스로 진화하는 AI 코딩 인프라"},{"content":"개요 oh-my-claudecode(OMC)는 Claude Code 위에서 동작하는 Teams-first 멀티 에이전트 오케스트레이션 프레임워크다. GitHub 스타 10,400개 이상, v4.9.0까지 빠르게 진화하면서 \u0026ldquo;Zero config, Zero learning curve\u0026quot;를 표방한다. 핵심 아이디어는 단순하다 — Claude Code의 마스터 에이전트를 교체하는 것이 아니라, 스킬 주입(skill injection) 방식으로 27개 전문 에이전트와 28개 스킬을 레이어링한다. 이 글에서는 OMC의 아키텍처, Team Mode 파이프라인, 오케스트레이션 모드 비교, 그리고 언제 써야 하는지까지 깊이 파고든다.\n스킬 합성 아키텍처 — 레이어링 모델 OMC가 다른 Claude Code 확장과 근본적으로 다른 점은 **모드 전환(mode switching)**이 아닌 **레이어 합성(layer composition)**이라는 것이다.\n전통적인 접근은 \u0026ldquo;플래닝 모드로 전환 → 실행 모드로 전환\u0026quot;처럼 컨텍스트를 끊고 모드를 바꾼다. OMC는 Claude Code의 스킬 시스템을 활용해 행동을 겹쳐 쌓는다.\n스킬 합성의 공식은 다음과 같다:\n[Execution Skill] + [0-N Enhancement Skills] + [Optional Guarantee] 구체적으로:\nExecution Skill: 실제 작업을 수행하는 핵심 스킬 (예: team-exec, autopilot) Enhancement Skills: 부가 행동을 주입하는 스킬 (예: critic, researcher) Optional Guarantee: 품질 보증 레이어 (예: team-verify, team-fix) 이 방식의 최대 장점은 컨텍스트가 끊기지 않는다는 것이다. 플래닝에서 실행으로 넘어갈 때 이전 대화의 맥락이 그대로 유지된다. Claude Code의 마스터 에이전트가 살아 있는 상태에서 스킬이 행동을 주입하기 때문이다.\ngraph TB Master[\"Claude Code\u0026lt;br/\u0026gt;Master Agent\"] subgraph Skills[\"스킬 레이어 합성\"] direction TB Exec[\"Execution Skill\u0026lt;br/\u0026gt;team-exec / autopilot\"] Enhance[\"Enhancement Skills\u0026lt;br/\u0026gt;critic + researcher + ...\"] Guard[\"Guarantee Layer\u0026lt;br/\u0026gt;team-verify / team-fix\"] end subgraph Agents[\"27개 전문 에이전트\"] direction LR A1[\"architect\"] A2[\"researcher\"] A3[\"designer\"] A4[\"writer\"] A5[\"critic\"] A6[\"planner\"] A7[\"qa-tester\"] A8[\"...\"] end Master --\u003e Skills Exec --\u003e Agents Enhance --\u003e Agents Guard --\u003e|\"실패 시 루프\"| Exec style Master fill:#4A90D9,color:#fff style Skills fill:#f5f5f5 style Agents fill:#f0f8ffTeam Mode 파이프라인 v4.1.7부터 canonical이 된 Team Mode는 OMC의 핵심 오케스트레이션 모드다. 5단계 스테이지드 파이프라인으로 구성된다.\ngraph LR Plan[\"team-plan\u0026lt;br/\u0026gt;요구사항 분석\"] PRD[\"team-prd\u0026lt;br/\u0026gt;설계 문서 작성\"] Exec[\"team-exec\u0026lt;br/\u0026gt;병렬 구현\"] Verify[\"team-verify\u0026lt;br/\u0026gt;품질 검증\"] Fix[\"team-fix\u0026lt;br/\u0026gt;이슈 수정\"] Plan --\u003e PRD --\u003e Exec --\u003e Verify Verify --\u003e|\"통과\"| Done[\"완료\"] Verify --\u003e|\"실패\"| Fix Fix --\u003e|\"루프\"| Verify style Plan fill:#E8F5E9 style PRD fill:#E3F2FD style Exec fill:#FFF3E0 style Verify fill:#F3E5F5 style Fix fill:#FFEBEE style Done fill:#C8E6C9각 단계를 자세히 보면:\n1. team-plan — 요구사항 분석 사용자의 요청을 받아 architect와 planner 에이전트가 협력한다. 작업 범위를 정의하고, 필요한 파일과 모듈을 식별하며, 의존성 그래프를 만든다.\n2. team-prd — 설계 문서 작성 plan 결과를 바탕으로 writer와 designer 에이전트가 PRD(Product Requirements Document)를 생성한다. 이 문서는 이후 단계의 컨텍스트로 주입된다.\n3. team-exec — 병렬 구현 PRD에 따라 여러 에이전트가 병렬로 구현을 수행한다. 여기서 tmux CLI 워커가 활용될 수 있다. 각 워커는 독립적인 Claude Code(또는 Codex, Gemini) 프로세스로 split-pane에서 실행된다.\n4. team-verify — 품질 검증 qa-tester와 critic 에이전트가 구현 결과를 검증한다. 테스트 실행, 코드 리뷰, 요구사항 충족 여부를 확인한다.\n5. team-fix — 수정 루프 검증에서 발견된 이슈를 수정한다. 수정 후 다시 team-verify로 돌아가는 루프 구조다. 이 루프가 OMC의 품질 보증 메커니즘의 핵심이다.\n오케스트레이션 모드 비교 OMC는 Team Mode 외에도 여러 오케스트레이션 모드를 제공한다. 각 모드는 다른 상황에 최적화되어 있다.\n모드 Magic Keyword 특징 적합한 상황 Team Mode team 5단계 파이프라인, 병렬 실행 멀티 파일/멀티 역할 대규모 작업 omc team (CLI) — CLI에서 직접 Team Mode 실행 CI/CD 통합, 스크립트 자동화 ccg — Codex + Gemini + Claude 삼중 모델 어드바이저 설계 의사결정, 아키텍처 리뷰 Autopilot autopilot, ap 자율 실행, 최소 개입 반복 작업, 잘 정의된 태스크 Ultrawork ulw 고강도 집중 모드 복잡한 단일 파일 리팩토링 Ralph ralph, ralplan 계획 중심, 신중한 실행 기획 단계, 리스크가 높은 변경 ccg — Tri-Model Advisor 특히 흥미로운 것은 /ccg 스킬이다. Claude Code 안에서 Codex와 Gemini의 의견을 함께 받아 Claude가 종합하는 구조다. 모델 간 관점 차이를 활용해 더 나은 의사결정을 유도한다.\ndeep-interview — 코딩 전 소크라테스식 질문 코딩을 시작하기 전에 사용자에게 반복적인 질문을 던져 요구사항을 명확히 한다. \u0026ldquo;무엇을 만들 것인가\u0026quot;보다 \u0026ldquo;왜 만드는가\u0026rdquo;, \u0026ldquo;어떤 제약이 있는가\u0026quot;를 먼저 파악한다.\ntmux CLI 워커와 멀티 모델 지원 v4.4.0에서 도입된 tmux CLI Workers는 OMC의 병렬 실행 능력을 극적으로 확장했다.\ngraph TB OMC[\"OMC Orchestrator\"] subgraph tmux[\"tmux Session\"] direction LR P1[\"Pane 1\u0026lt;br/\u0026gt;Claude Code\"] P2[\"Pane 2\u0026lt;br/\u0026gt;Codex CLI\"] P3[\"Pane 3\u0026lt;br/\u0026gt;Gemini CLI\"] P4[\"Pane 4\u0026lt;br/\u0026gt;Claude Code\"] end OMC --\u003e|\"task 분배\"| P1 OMC --\u003e|\"task 분배\"| P2 OMC --\u003e|\"task 분배\"| P3 OMC --\u003e|\"task 분배\"| P4 P1 --\u003e|\"결과\"| OMC P2 --\u003e|\"결과\"| OMC P3 --\u003e|\"결과\"| OMC P4 --\u003e|\"결과\"| OMC style OMC fill:#4A90D9,color:#fff style tmux fill:#f5f5f5핵심 특징:\n실제 프로세스 스폰: 각 pane에서 독립적인 claude, codex, gemini CLI 프로세스가 실행된다 멀티 모델 라우팅: 작업 특성에 따라 적절한 모델로 라우팅한다. Smart model routing으로 토큰 비용 30-50% 절감을 주장한다 시각적 모니터링: tmux split-pane으로 각 워커의 진행 상황을 실시간으로 볼 수 있다 HUD Statusline: 현재 활성 에이전트, 진행 단계, 토큰 사용량을 한눈에 보여준다 Magic Keyword 시스템 OMC의 사용 경험에서 가장 눈에 띄는 것은 magic keyword 시스템이다. 복잡한 명령어 대신 자연어 키워드로 오케스트레이션 모드를 활성화한다.\nKeyword 동작 ralph Ralph 모드 활성화 — 신중한 계획 우선 ralplan Ralph의 플래닝 단계만 실행 ulw Ultrawork 모드 — 고강도 집중 plan 플래닝 스킬 활성화 autopilot / ap Autopilot 모드 — 자율 실행 이 키워드들은 Claude Code의 프롬프트에서 자연어로 사용할 수 있다:\n\u0026#34;ralph, 이 프로젝트의 인증 시스템을 리팩토링해줘\u0026#34; \u0026#34;ap 모든 테스트 파일에 타입 어노테이션 추가해\u0026#34; 3-Tier 메모리 시스템 장시간 세션에서 컨텍스트 유실은 AI 코딩 도구의 고질적 문제다. OMC는 3단계 메모리 시스템으로 이를 해결한다.\n계층 용도 특징 Priority Memory 최우선 컨텍스트 항상 프롬프트에 주입, 프로젝트 규칙/제약 Working Memory 현재 작업 컨텍스트 세션 중 자동 업데이트, 진행 상태 추적 Manual Notes 사용자 지정 메모 수동 관리, 장기 보존 Priority Memory는 CLAUDE.md와 유사한 역할을 하지만, OMC가 자동으로 관리하며 에이전트 간에 공유된다. Working Memory는 Team Mode의 각 단계에서 자동으로 업데이트되어, 다음 단계의 에이전트가 이전 단계의 결정 사항을 알 수 있게 한다.\n설치와 빠른 시작 설치는 Claude Code의 플러그인 시스템을 통해 이루어진다:\n# 1. 플러그인 추가 /plugin marketplace add https://github.com/Yeachan-Heo/oh-my-claudecode # 2. 설치 /plugin install oh-my-claudecode # 3. 초기 설정 /omc-setup 설치 후 바로 사용할 수 있다. \u0026ldquo;Zero configuration\u0026quot;을 표방하는 만큼, /omc-setup 이후 추가 설정 없이 magic keyword로 바로 시작 가능하다.\nnpm 패키지명은 oh-my-claude-sisyphus이며, TypeScript(6.9M)와 JavaScript(5.2M)로 작성되어 있다.\n트레이드오프 — OMC vs 순수 Claude Code OMC가 만능은 아니다. 레이어를 쌓는 만큼 비용이 따른다.\nOMC를 써야 하는 경우 멀티 파일/멀티 역할 작업: 프론트엔드 + 백엔드 + 테스트를 동시에 변경해야 할 때 장시간 세션: 컨텍스트 유실이 문제가 되는 2시간 이상의 작업 계획이 중요한 작업: 아키텍처 변경, 대규모 리팩토링처럼 먼저 생각하고 실행해야 하는 경우 팀 워크플로우 시뮬레이션: 혼자 작업하지만 architect → developer → reviewer 흐름이 필요할 때 순수 Claude Code가 나은 경우 단순한 작업: 함수 하나 수정, 버그 하나 수정 같은 작업에 Team Mode 파이프라인은 과도하다 토큰 비용이 민감한 경우: 5단계 파이프라인은 순수 Claude Code 대비 상당한 추가 토큰을 소비한다 투명성이 중요한 경우: 오케스트레이션 레이어가 추가될수록 \u0026ldquo;왜 이런 결정을 했는지\u0026rdquo; 추적이 어려워진다 빠른 반복이 필요한 경우: plan → prd → exec → verify → fix 루프는 시간이 걸린다 핵심 트레이드오프 요약 항목 OMC 순수 Claude Code 토큰 비용 높음 (멀티 에이전트) 낮음 작업 시간 길지만 품질 높음 빠르지만 단순 투명성 오케스트레이션 레이어로 낮음 높음 컨텍스트 유지 3-Tier 메모리로 우수 기본 수준 멀티 파일 작업 병렬 실행으로 강력 순차 처리 가드레일 자동 verify/fix 루프 수동 확인 비판적 분석 OMC는 인상적인 프로젝트지만, 몇 가지 점에서 냉정하게 볼 필요가 있다.\n코드베이스 규모에 대한 의문. TypeScript 6.9M + JavaScript 5.2M은 \u0026ldquo;Zero config\u0026rdquo; 도구치고는 거대하다. 스킬 정의와 에이전트 프롬프트가 대부분이겠지만, 이 규모의 코드베이스는 유지보수 부담이 크다.\n\u0026ldquo;27개 에이전트\u0026quot;의 실체. 27개 전문 에이전트가 실제로 얼마나 차별화된 행동을 하는지는 프롬프트 엔지니어링의 질에 달려 있다. architect와 planner의 경계, critic과 qa-tester의 차이가 실질적인지 검증이 필요하다.\nSmart model routing의 30-50% 절감 주장. 이 수치의 벤치마크 조건이 명시되어 있지 않다. 단순 작업에서 작은 모델로 라우팅하면 절감되겠지만, 복잡한 작업에서의 재시도 비용은 포함되었는지 불분명하다.\nGuardrail 민감도. team-verify → team-fix 루프가 과도하게 민감하면 불필요한 수정 사이클이 반복될 수 있다. 이는 토큰 낭비로 직결된다.\n그럼에도 불구하고, OMC가 제시하는 스킬 합성이라는 패러다임 자체는 가치가 있다. 모드 전환 대신 레이어링으로 컨텍스트를 보존하면서 행동을 확장하는 접근은, AI 코딩 도구의 다음 단계로서 설득력이 있다. 특히 Team Mode의 plan → prd → exec → verify → fix 파이프라인은 소프트웨어 엔지니어링의 실제 워크플로우를 잘 반영하고 있다.\n빠른 링크 oh-my-claudecode GitHub ROBOCO 소개 글 npm: oh-my-claude-sisyphus 인사이트 OMC가 제시하는 스킬 합성이라는 패러다임 자체는 가치가 있다. 모드 전환 대신 레이어링으로 컨텍스트를 보존하면서 행동을 확장하는 접근은, AI 코딩 도구의 다음 단계로서 설득력이 있다. 특히 Team Mode의 plan → prd → exec → verify → fix 파이프라인은 소프트웨어 엔지니어링의 실제 워크플로우를 잘 반영하고 있다. 다만 이러한 복잡한 오케스트레이션이 실제로 순수 Claude Code 대비 어느 정도의 품질 향상을 가져오는지에 대한 정량적 벤치마크가 부족하다. \u0026ldquo;느낌\u0026quot;이 아닌 \u0026ldquo;수치\u0026quot;로 증명해야 할 시점이다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-oh-my-claudecode/cover.jpg","permalink":"/ko/posts/2026-03-20-oh-my-claudecode/","title":"oh-my-claudecode (OMC) — Claude Code를 위한 Teams-first 멀티 에이전트 오케스트레이션"},{"content":"개요 이번 개발 로그에서는 trading-agent의 backend 안정화 작업을 중점적으로 다룬다. DART 재무 데이터 클라이언트의 연도 fallback과 PBR 계산 로직 추가, market scanner 파이프라인에서 current_price가 누락되던 버그 수정, FastMCP 미들웨어의 async/sync 혼용 문제 해결, 그리고 프론트엔드에서는 SignalPanel에 날짜별 그룹핑과 DAG 워크플로우 시각화 개선을 진행했다.\n이전 글: #4\nDART 클라이언트 개선 배경 DART(전자공시시스템) API에서 재무 데이터를 가져올 때 두 가지 문제가 있었다:\n연도 데이터 누락: 최신 연도의 재무제표가 아직 공시되지 않은 경우, API가 빈 응답을 반환했다. 이전 연도로 fallback하는 로직이 없어서 분석 에이전트가 재무 데이터 없이 판단해야 했다. PBR 미계산: PER은 API에서 직접 제공하지만 PBR(주가순자산비율)은 제공하지 않았다. 시가총액과 순자산 데이터가 있음에도 PBR을 계산하지 않고 있었다. 업종별 필드 차이: 금융업과 일반 기업의 재무제표 항목명이 달라서 특정 업종에서 파싱 에러가 발생했다. 구현 backend/app/services/dart_client.py에서 다음을 개선했다:\n연도 Fallback 로직:\n# 최신 연도부터 시도하여 데이터가 있는 연도를 찾음 for year in range(current_year, current_year - 3, -1): result = await self._fetch_financial_data(corp_code, year) if result and result.get(\u0026#34;list\u0026#34;): break PBR 자동 계산:\n# 순자산(자본총계)과 시가총액으로 PBR 계산 if total_equity and total_equity \u0026gt; 0: pbr = market_cap / total_equity 업종별 필드 매핑:\n금융업(은행, 보험, 증권)은 영업이익 대신 영업수익을 사용하고, 매출액 대신 이자수익 등의 항목을 참조하도록 분기 처리했다.\nMarket Scanner 파이프라인 수정 배경 Market scanner가 종목을 스캔한 뒤, 각 전문가 에이전트(기술적 분석, 펀더멘털 분석 등)에게 전달할 때 current_price 필드가 누락되는 문제가 있었다. Scanner가 가격 데이터를 가져오지만 하위 expert 호출 시 해당 값을 전달하지 않았다.\n구현 flowchart LR A[\"Market Scanner\"] --\u003e|\"종목 리스트 +\u0026lt;br/\u0026gt;current_price\"| B[\"Expert Agents\"] B --\u003e|\"분석 결과\"| C[\"Chief Analyst\"] C --\u003e|\"최종 시그널\"| D[\"Signal Queue\"]backend/app/agents/market_scanner.py에서 expert 호출 시 current_price를 명시적으로 전달하도록 수정했다:\n# Before: expert에 price 정보 누락 expert_result = await expert.analyze(stock_code, stock_name) # After: current_price를 pipeline 전체에 전달 expert_result = await expert.analyze(stock_code, stock_name, current_price=price) 또한 market_scanner_experts.py에서 chief analyst의 토론(debate) 로직을 단순화했다. 기존에는 모든 expert 의견을 순차적으로 토론시켰는데, 불필요한 라운드를 줄여 응답 시간을 개선했다.\nFastMCP 미들웨어 async/sync 버그 수정 문제 MCP 서버의 미들웨어에서 context.state에 접근하는 메서드가 동기(sync) 함수임에도 await로 호출하고 있었다:\n# Bug: sync 함수에 await 사용 state = await ctx.get_state(\u0026#34;trading_mode\u0026#34;) # TypeError! FastMCP의 context state 메서드는 동기 함수인데, 이를 await하면 coroutine이 아닌 값에 대해 TypeError가 발생하거나, 일부 Python 버전에서는 조용히 무시되어 None을 반환했다.\n해결 open-trading-api/MCP/Kis Trading MCP/module/middleware.py와 tools/base.py에서 await를 제거:\n# Fix: sync 메서드는 await 없이 직접 호출 state = ctx.get_state(\u0026#34;trading_mode\u0026#34;) Scheduled Tasks 활성화 backend/app/models/database.py에서 스케줄러 관련 설정을 업데이트했다:\n기존에 비활성화되어 있던 scheduled task들을 활성화 Cron 타이밍을 한국 장 운영 시간에 맞게 조정 (장 시작 전 스캔, 장 중 모니터링, 장 마감 후 리포트) 프론트엔드 개선 SignalPanel 날짜별 그룹핑 frontend/src/components/dashboard/SignalPanel.tsx에 날짜별 collapsible 섹션을 추가했다. 기존에는 모든 시그널이 시간순으로 나열되어 특정 날짜의 시그널을 찾기 어려웠다.\nflowchart TD A[\"SignalPanel\"] --\u003e B{\"날짜별 그룹핑\"} B --\u003e C[\"2026-03-19\u0026lt;br/\u0026gt;5개 시그널\"] B --\u003e D[\"2026-03-18\u0026lt;br/\u0026gt;3개 시그널\"] B --\u003e E[\"2026-03-17\u0026lt;br/\u0026gt;8개 시그널\"] C --\u003e F[\"Collapsible\u0026lt;br/\u0026gt;펼치기/접기\"]일별 차트 데이터 확장 backend/app/services/market_service.py에서 일별 차트 데이터 조회 기간을 30일에서 90일로 확장했다. 기술적 분석에서 이동평균선(60일, 90일) 계산에 충분한 데이터가 필요했기 때문이다.\nDAG 워크플로우 스타일링 frontend/src/components/AgentWorkflow.css와 AgentWorkflow.tsx에서 에이전트 파이프라인 DAG 시각화의 레이아웃과 expert chip 스타일링을 개선했다. 노드 간 간격, 커넥터 라벨 위치, 전체 컨테이너 정렬을 조정하여 가독성을 높였다.\n커밋 로그 메시지 변경 feat: improve DART client with year fallback, PBR calculation, and industry-variant fields dart_client.py fix: pass current_price through scanner pipeline and simplify chief debate market_scanner.py, market_scanner_experts.py fix: remove await from sync FastMCP context state methods middleware.py, tools/base.py feat: enable scheduled tasks and adjust cron timings database.py feat: extend daily chart data from 30 to 90 days market_service.py feat: add date-grouped collapsible sections to SignalPanel SignalPanel.tsx, App.css style: improve DAG workflow layout and expert chip styling AgentWorkflow.css, index.css 인사이트 async/sync 혼용은 조용한 버그를 만든다. Python에서 sync 함수를 await하면 일부 런타임에서 에러 대신 None을 반환하는 경우가 있다. FastMCP처럼 sync/async가 혼재하는 라이브러리를 쓸 때는 각 메서드의 시그니처를 반드시 확인해야 한다. 파이프라인에서 데이터 전달 누락은 흔한 실수다. Scanner가 가격을 가져오고도 expert에 전달하지 않은 건 각 단계가 독립적으로 테스트되었기 때문이다. End-to-end 테스트의 필요성을 다시 한번 느꼈다. 재무 데이터 API는 업종별 차이를 고려해야 한다. 금융업의 재무제표 구조는 일반 기업과 근본적으로 다르다. DART API를 래핑할 때 이런 변이를 미리 매핑해두지 않으면 런타임에서 KeyError가 터진다. 차트 데이터 기간과 분석 지표는 함께 설계해야 한다. 90일 이동평균을 계산하려면 최소 90일치 데이터가 필요한데, 30일만 가져오고 있었다. 기술적 분석 지표를 추가할 때 데이터 소스의 범위도 같이 점검해야 한다. ","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-trading-agent-dev5/cover.jpg","permalink":"/ko/posts/2026-03-20-trading-agent-dev5/","title":"Trading Agent 개발기 #5 — Backend 안정화와 데이터 파이프라인 개선"},{"content":"개요 AI 코딩 도구의 패러다임이 바뀌고 있다. 하나의 거대한 LLM이 모든 작업을 처리하던 시대에서, 여러 개의 경량 서브에이전트가 병렬로 리서치하고 메인 에이전트가 통합하는 아키텍처로 전환되고 있다. OpenAI가 GPT 5.4 mini/nano를 \u0026ldquo;서브에이전트용으로 명시적 설계\u0026quot;했다고 발표한 것은 이 흐름이 단순한 트렌드가 아니라 산업 표준이 되었음을 의미한다. Cole Medin의 The Subagent Era Is Officially Here 영상을 바탕으로, 서브에이전트 아키텍처의 핵심 개념과 실전 활용 전략을 깊이 있게 정리한다.\n왜 서브에이전트인가 — Context Rot 문제 Context Rot이란 LLM은 context window에 많은 정보를 넣을수록 성능이 떨어진다. 이를 context rot이라 부른다. 200K 토큰 context window를 가진 모델이라 해도, 실제로 200K 토큰을 채우면 초반에 넣은 정보를 \u0026ldquo;잊거나\u0026rdquo; 중요도를 잘못 판단하는 현상이 발생한다.\n이 문제는 AI 코딩 도구에서 특히 치명적이다:\n대규모 코드베이스 분석: 수십 개의 파일을 context에 넣으면, 정작 핵심 파일의 내용을 놓친다 멀티스텝 디버깅: 프론트엔드 코드, 백엔드 코드, 에러 로그를 동시에 분석할 때 정보가 섞인다 웹 리서치 + 코드 수정: 검색 결과와 코드를 함께 처리하면 두 작업 모두 품질이 떨어진다 서브에이전트가 해결하는 방식 서브에이전트 아키텍처는 이 문제를 근본적으로 해결한다. 각 서브에이전트는 독립된 context window를 가지므로, 자신이 맡은 작업에만 집중할 수 있다. 메인 에이전트는 각 서브에이전트의 결과 요약만 받으므로 context가 깔끔하게 유지된다.\ngraph TD User[\"사용자 요청\"] --\u003e Main[\"메인 에이전트 \u0026lt;br/\u0026gt; (오케스트레이터)\"] Main --\u003e SA1[\"서브에이전트 1 \u0026lt;br/\u0026gt; 웹 리서치\"] Main --\u003e SA2[\"서브에이전트 2 \u0026lt;br/\u0026gt; 프론트엔드 분석\"] Main --\u003e SA3[\"서브에이전트 3 \u0026lt;br/\u0026gt; 백엔드 분석\"] SA1 --\u003e R1[\"요약된 리서치 결과\"] SA2 --\u003e R2[\"요약된 코드 분석\"] SA3 --\u003e R3[\"요약된 API 분석\"] R1 --\u003e Main R2 --\u003e Main R3 --\u003e Main Main --\u003e Result[\"통합된 해결책\"] style Main fill:#4A90D9,stroke:#333,color:#fff style SA1 fill:#7B68EE,stroke:#333,color:#fff style SA2 fill:#7B68EE,stroke:#333,color:#fff style SA3 fill:#7B68EE,stroke:#333,color:#fff핵심은 context 격리다. 각 서브에이전트가 10K 토큰씩 사용하더라도, 메인 에이전트에는 각각 1K 토큰 정도의 요약만 전달된다. 메인 에이전트의 context는 3K 토큰만 추가되는 셈이다.\n서브에이전트 전용 모델 비교 OpenAI가 GPT 5.4 nano를 \u0026ldquo;서브에이전트용\u0026quot;으로 명시한 것은 업계 최초다. Google도 Gemini 3.1 Flash Light를 \u0026ldquo;intelligence at scale\u0026rdquo; 콘셉트로 출시하며 같은 방향으로 움직이고 있다.\n주요 모델 스펙 비교 모델 처리 속도 입력 비용 (1M 토큰) 출력 비용 (1M 토큰) 주요 용도 Claude Haiku 4.5 53 tok/s $1.00 $5.00 범용 서브에이전트 GPT 5.4 nano 188 tok/s $0.20 $1.00 전용 서브에이전트 GPT 5.4 mini ~120 tok/s $0.40 $2.00 중간 복잡도 작업 Gemini 3.1 Flash Light ~150 tok/s $0.15 $0.60 대규모 병렬 처리 GPT 5.4 nano의 수치가 눈에 띈다:\n비용: Claude Haiku 4.5 대비 1/5 수준 — 서브에이전트를 5개 돌려도 같은 비용 처리량: 3.5배 빠른 throughput — 병렬 서브에이전트의 대기 시간이 크게 줄어든다 설계 철학: \u0026ldquo;충분히 똑똑하되, 빠르고 저렴하게\u0026rdquo; — 서브에이전트에 최적화된 트레이드오프 왜 전용 모델이 필요한가 서브에이전트는 메인 에이전트와 성격이 다르다:\n메인 에이전트: 복잡한 추론, 계획 수립, 코드 생성 — 정확도가 최우선 서브에이전트: 정보 수집, 코드 읽기, 패턴 탐색 — 속도와 비용이 최우선 GPT-4o나 Claude Sonnet 같은 대형 모델을 서브에이전트로 쓰면 비용이 급격히 증가한다. 3개의 서브에이전트를 5번 호출하면 15회의 LLM 호출이 발생하는데, 대형 모델로는 비현실적인 비용이 된다. nano급 모델이 서브에이전트 아키텍처를 경제적으로 실현 가능하게 만든 셈이다.\n실전 아키텍처 — 서브에이전트는 어떻게 동작하는가 Claude Code의 Agent Tool 방식 Claude Code는 서브에이전트 아키텍처의 first mover다. Agent Tool을 통해 서브에이전트를 생성하며, 각 서브에이전트는 독립된 context에서 파일 읽기, 검색, 분석 작업을 수행한다.\nsequenceDiagram participant U as 사용자 participant M as 메인 에이전트 participant T as tmux 세션 participant S1 as 서브에이전트 1 participant S2 as 서브에이전트 2 participant S3 as 서브에이전트 3 U-\u003e\u003eM: 버그 수정 요청 M-\u003e\u003eM: 작업 분해 M-\u003e\u003eT: 서브에이전트 스폰 T-\u003e\u003eS1: 웹 리서치 위임 T-\u003e\u003eS2: 프론트엔드 코드 분석 T-\u003e\u003eS3: 백엔드 코드 분석 S1--\u003e\u003eM: 관련 문서 요약 S2--\u003e\u003eM: UI 컴포넌트 분석 결과 S3--\u003e\u003eM: API 엔드포인트 분석 결과 M-\u003e\u003eM: 결과 통합 및 수정 계획 M-\u003e\u003eU: 코드 수정 제안특히 Claude Code의 Agent Team 기능은 tmux를 활용해 여러 서브에이전트를 동시에 터미널 세션으로 스폰한다. 이 방식 덕분에 tmux에 대한 개발자들의 관심이 다시 높아지는 현상까지 나타났다.\nOpenAI Codex의 접근 방식 OpenAI Codex는 다른 방식을 취한다. 샌드박스 환경에서 에이전트를 실행하며, GPT 5.4 nano를 서브에이전트로 활용해 비용을 최소화한다. Claude Code가 로컬 터미널 기반이라면, Codex는 클라우드 샌드박스 기반이라는 차이가 있다.\n두 접근의 핵심적인 차이:\n특성 Claude Code Agent Tool OpenAI Codex 실행 환경 로컬 터미널 (tmux) 클라우드 샌드박스 서브에이전트 모델 Claude Haiku 4.5 GPT 5.4 nano 병렬화 방식 tmux 세션 분할 컨테이너 기반 파일 접근 로컬 파일시스템 직접 접근 샌드박스 내 복사본 비용 구조 API 호출 비용만 컴퓨팅 + API 비용 현재 서브에이전트를 지원하는 AI 코딩 도구들 서브에이전트는 더 이상 실험적 기능이 아니다. 주요 AI 코딩 도구들이 모두 채택했다:\nClaude Code — Agent Tool (first mover, 가장 성숙한 구현) OpenAI Codex — GPT 5.4 nano 기반 서브에이전트 Gemini CLI — 실험적 서브에이전트 지원 GitHub Copilot — 에이전트 모드에서 서브태스크 분할 Cursor — Background Agent를 통한 병렬 처리 Open Code — 오픈소스 구현체 Best Practices — 서브에이전트 활용의 정석 Cole Medin이 영상에서 강조한 실전 팁은 매우 구체적이다.\n서브에이전트를 써야 할 때: 리서치 서브에이전트의 최적 활용처는 리서치다:\n코드 분석: \u0026ldquo;이 모듈의 의존성 구조를 파악해줘\u0026rdquo; 웹 검색: \u0026ldquo;이 에러 메시지의 해결 방법을 찾아줘\u0026rdquo; 문서 탐색: \u0026ldquo;이 라이브러리의 마이그레이션 가이드를 정리해줘\u0026rdquo; 패턴 탐색: \u0026ldquo;이 프로젝트에서 비슷한 구현이 있는지 찾아줘\u0026rdquo; 실전 예시: 3개의 병렬 리서치 서브에이전트 Cole Medin이 소개한 실제 버그 수정 사례를 보자:\n[버그] 사용자 프로필 업데이트 시 이미지가 저장되지 않는 문제 메인 에이전트의 작업 분해: ├── 서브에이전트 1: 웹 리서치 │ → \u0026#34;multer file upload not saving express.js\u0026#34; 검색 │ → Stack Overflow, GitHub Issues에서 해결책 수집 │ → 결과: multer storage 설정 누락 가능성 높음 │ ├── 서브에이전트 2: 프론트엔드 분석 │ → ProfileEdit.tsx의 form submission 로직 분석 │ → FormData 구성 방식 확인 │ → 결과: Content-Type 헤더가 multipart로 설정되지 않음 │ └── 서브에이전트 3: 백엔드 분석 → upload.route.ts의 multer 미들웨어 설정 확인 → 파일 저장 경로 및 권한 확인 → 결과: destination 경로는 정상, 미들웨어 순서 문제 발견 메인 에이전트 통합: → 프론트엔드 Content-Type 수정 + 백엔드 미들웨어 순서 조정 세 서브에이전트가 동시에 각자의 영역을 조사했기 때문에, 순차적으로 진행했을 때보다 시간이 1/3로 줄었다. 그리고 각 서브에이전트는 자기 영역의 코드만 context에 넣었기 때문에, context rot 없이 정확한 분석이 가능했다.\n서브에이전트를 쓰면 안 될 때: 구현 Cole Medin이 강하게 경고한 안티패턴이 있다. 구현 작업을 서브에이전트에 분할하지 마라.\n왜 안 되는가:\n[안티패턴] 프론트엔드/백엔드/DB를 서브에이전트로 분할 서브에이전트 A: React 컴포넌트 작성 서브에이전트 B: Express API 작성 서브에이전트 C: DB 스키마 작성 문제: - A가 만든 API 호출 형식 ≠ B가 만든 API 응답 형식 - B가 기대하는 DB 스키마 ≠ C가 만든 스키마 - 타입 불일치, 필드명 불일치, 인터페이스 불일치 → 통합 시 대규모 수정 필요 → 서브에이전트 안 쓴 것만 못함 구현은 본질적으로 컴포넌트 간 통신 계약이 중요하다. 서브에이전트들은 서로의 context를 공유하지 않으므로, 인터페이스 합의가 불가능하다. 리서치는 각자 독립적으로 수행해도 결과를 합칠 수 있지만, 코드 구현은 그렇지 않다.\n올바른 패턴:\n리서치 → 서브에이전트 (병렬) 구현 → 메인 에이전트 (순차, 통합된 context에서) 서브에이전트 아키텍처의 한계와 주의점 1. 오케스트레이션 오버헤드 서브에이전트를 관리하는 메인 에이전트도 비용이 든다. 작업 분해, 서브에이전트 프롬프트 작성, 결과 통합 — 이 모든 과정이 메인 에이전트의 context를 소비한다. 단순한 작업에 서브에이전트를 쓰면 오히려 비효율적이다.\n기준: 파일 2-3개만 읽으면 해결되는 문제에는 서브에이전트가 필요 없다. 5개 이상의 파일을 cross-reference해야 하거나, 웹 검색이 필요한 경우에 서브에이전트가 빛을 발한다.\n2. 결과 품질의 편차 서브에이전트가 nano급 경량 모델을 사용하면, 복잡한 추론이 필요한 리서치에서는 품질이 떨어질 수 있다. \u0026ldquo;이 코드의 버그를 찾아줘\u0026quot;가 아니라 \u0026ldquo;이 파일의 구조를 정리해줘\u0026rdquo; 수준의 작업이 서브에이전트에 적합하다.\n3. 보안 고려사항 서브에이전트가 외부 웹 검색을 수행하는 경우, prompt injection 공격에 노출될 수 있다. 검색 결과에 포함된 악의적 지시가 서브에이전트를 통해 메인 에이전트에 전달될 위험이 있다.\n앞으로의 전망 서브에이전트 아키텍처는 단순히 \u0026ldquo;빠르게 검색하는 도구\u0026quot;를 넘어, AI 코딩의 근본적인 패턴을 바꾸고 있다:\n모델 전문화 가속: 범용 모델 하나가 아닌, 역할별 최적화 모델의 조합이 표준이 된다 비용 구조 변화: 큰 모델 1회 호출보다, 작은 모델 N회 호출이 더 경제적이고 정확한 결과를 낸다 개발자 워크플로우 변화: tmux, 터미널 멀티플렉서 같은 \u0026ldquo;구식\u0026rdquo; 도구가 AI 에이전트 인프라로 재조명된다 OpenAI, Google, Anthropic이 모두 서브에이전트용 경량 모델을 출시하고 있다는 것은 명확한 시그널이다. 서브에이전트 시대는 이미 도래했다.\n빠른 링크 Cole Medin — The Subagent Era Is Officially Here OpenAI GPT 5.4 모델 카드 Claude Code 공식 문서 인사이트 서브에이전트 아키텍처의 진정한 의미는 \u0026ldquo;더 빠른 코딩\u0026quot;이 아니라 정보 처리 방식의 근본적 변화에 있다. 하나의 만능 LLM에 모든 것을 맡기던 방식에서, 역할별로 최적화된 경량 모델들이 협업하는 구조로 전환되고 있다. 이는 소프트웨어 엔지니어링에서 마이크로서비스가 모놀리스를 대체한 흐름과 놀라울 정도로 유사하다. OpenAI가 모델 출시 헤드라인에 \u0026ldquo;서브에이전트용\u0026quot;을 명시한 것은 이 패러다임이 실험이 아닌 산업 표준임을 선언한 것이다. 개발자로서 주목해야 할 것은 모델 자체가 아니라, 이 아키텍처를 자신의 워크플로우에 어떻게 녹이느냐다.\n","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-subagent-era/cover.jpg","permalink":"/ko/posts/2026-03-20-subagent-era/","title":"서브에이전트 시대의 도래 — GPT 5.4 nano와 Context Rot 해결 전략"},{"content":"개요 이전 글에서 Google OAuth 로그인 벽을 구현한 데 이어, 이번에는 자동 주입(tone/angle) 시스템의 시각적 피드백, 사용자별 데이터 격리, 그리고 이미지 생성 병렬화를 구현했다. PRD v3에서 정의한 비교 생성(톤+앵글 vs 톤만) 결과를 사용자가 직관적으로 확인할 수 있도록 UI를 대폭 개선했다.\n이전 글: #1 — 하이브리드 이미지 검색 개발기 — Google OAuth 로그인 월 구현\n자동 주입 레퍼런스 시각화 배경 PRD v3의 핵심 기능 중 하나는 시스템이 자동으로 톤/앵글 레퍼런스를 주입하는 것이다. 그런데 실제로 어떤 이미지가 톤/앵글로 적용되었는지 사용자에게 전혀 보이지 않는 상태였다. 생성된 이미지를 보면서 \u0026ldquo;왜 이 색감이 나왔지?\u0026ldquo;라는 의문이 생겨도 확인할 방법이 없었다.\n구현 백엔드부터 프론트엔드까지 풀스택으로 injection 정보 파이프라인을 구성했다.\nflowchart LR A[\"GenerationLog DB\"] --\u003e|injected_tone_filename| B[\"service.py\"] B --\u003e|InjectionInfo| C[\"main.py API\"] C --\u003e|JSON response| D[\"api.ts\"] D --\u003e|injection_info| E[\"App.tsx\"] E --\u003e F[\"배지 표시\"] E --\u003e G[\"상세 카드\"]백엔드 — schemas.py에 InjectionInfo 모델을 추가하고, service.py에서 DB의 injected_tone_filename, injected_angle_filename 필드를 읽어 구조화된 응답으로 변환했다:\ndef _build_injection_info_from_row(row: dict) -\u0026gt; InjectionInfo | None: tone_fn = row.get(\u0026#34;injected_tone_filename\u0026#34;) angle_fn = row.get(\u0026#34;injected_angle_filename\u0026#34;) reason = row.get(\u0026#34;injection_reason\u0026#34;) if not tone_fn and not angle_fn: return None return InjectionInfo( tone=InjectedReference(filename=tone_fn, score=0.0) if tone_fn else None, angle=InjectedReference(filename=angle_fn, score=0.0) if angle_fn else None, reason=reason, ) 프론트엔드 — 두 가지 시각 요소를 추가했다:\n썸네일 배지: 이미지 카드 좌상단에 톤, 앵글 태그를 amber/blue 컬러로 표시 상세 모달 카드: GeneratedImageDetail.tsx에서 실제 주입된 레퍼런스 이미지를 썸네일로 보여주고, 주입 사유(reason)를 텍스트로 표시 디버깅 — 주입 레퍼런스가 표시되지 않는 문제 처음 구현 후 실제 생성을 해봤는데, 톤/앵글 표시가 전혀 나오지 않았다. 스크린샷을 찍어 확인해보니 injection_info가 null로 오고 있었다. 원인은 _build_injection_info_from_row에서 DB 컬럼명과 실제 row 키가 불일치한 것이었다. row dict에서 올바른 필드를 매핑하도록 수정하여 해결했다.\n추가로, 레퍼런스 이미지 선택 로직에서 ImageCategories 구조체가 제대로 로드되지 않는 문제도 발견했다. images.json 로딩 시 categories 필드를 파싱하도록 수정:\ncategories = ImageCategories(**img[\u0026#34;categories\u0026#34;]) if \u0026#34;categories\u0026#34; in img else ImageCategories() doc = ImageDocument( id=img[\u0026#34;id\u0026#34;], filename=img[\u0026#34;filename\u0026#34;], labels=labels, categories=categories, ) 비교 이미지 hover 오버레이 톤+앵글 적용 버전과 톤만 적용 버전을 비교하기 위해, 이미지 카드에 hover 시 비교 이미지를 오버레이로 보여주는 기능을 구현했다. 처음에는 별도 카드로 표시하는 방안도 검토했지만, 사용성을 고려해 같은 카드 위에 hover 효과로 전환하는 방식을 채택했다.\n구현 과정에서 hover 시 톤 텍스트 위치가 이동하는 문제가 있었다. CSS position: absolute로 고정하여 해결했고, 텍스트 크기도 가독성을 위해 키웠다.\n검색 결과 가로 스크롤 전환 배경 \u0026ldquo;참조찾기\u0026rdquo; 버튼으로 열리는 검색 결과 팝업이 grid grid-cols-6 기반의 세로 그리드였다. 이미지가 많아지면 스크롤이 길어지고 한눈에 비교하기 어려웠다.\n구현 팝업 내 3개 그리드(구성요소별, 통합결과, 전체보기)를 모두 단일 가로 행 + 좌우 화살표 방식으로 교체했다.\nScrollableRow 컴포넌트를 새로 만들어 재사용:\nconst ScrollableRow: React.FC\u0026lt;{ children: React.ReactNode }\u0026gt; = ({ children }) =\u0026gt; { const scrollRef = useRef\u0026lt;HTMLDivElement\u0026gt;(null); const [canScrollLeft, setCanScrollLeft] = useState(false); const [canScrollRight, setCanScrollRight] = useState(true); const scroll = (direction: \u0026#39;left\u0026#39; | \u0026#39;right\u0026#39;) =\u0026gt; { const el = scrollRef.current; if (!el) return; const scrollAmount = 540; // ~3 cards el.scrollBy({ left: direction === \u0026#39;left\u0026#39; ? -scrollAmount : scrollAmount, behavior: \u0026#39;smooth\u0026#39; }); }; return ( \u0026lt;div className=\u0026#34;relative group/scroll\u0026#34;\u0026gt; {canScrollLeft \u0026amp;\u0026amp; ( \u0026lt;button onClick={() =\u0026gt; scroll(\u0026#39;left\u0026#39;)} className=\u0026#34;absolute left-0 top-0 bottom-0 z-10 w-10 ...\u0026#34;\u0026gt; \u0026lt;ChevronLeft size={20} /\u0026gt; \u0026lt;/button\u0026gt; )} \u0026lt;div ref={scrollRef} onScroll={updateScrollState} className=\u0026#34;flex gap-2.5 overflow-x-auto custom-scrollbar-hidden\u0026#34;\u0026gt; {children} \u0026lt;/div\u0026gt; {canScrollRight \u0026amp;\u0026amp; ( \u0026lt;button onClick={() =\u0026gt; scroll(\u0026#39;right\u0026#39;)} className=\u0026#34;...\u0026#34;\u0026gt; \u0026lt;ChevronRight size={20} /\u0026gt; \u0026lt;/button\u0026gt; )} \u0026lt;/div\u0026gt; ); }; 기존 grid grid-cols-6 gap-2.5를 모두 \u0026lt;ScrollableRow\u0026gt;로 교체하고, 각 이미지 카드를 flex-shrink-0 w-[200px]로 고정 너비를 설정했다. 처음에는 160px이었으나 가로 레이아웃에서 좀 더 큰 카드가 적합하여 200px로 조정했다.\n사용자별 데이터 격리 배경 멀티유저 환경에서 생성 기록이 user_id 필터 없이 전체 조회되고 있었다. 다른 사용자의 생성 이미지가 히스토리에 노출될 수 있는 보안 문제가 있었다.\n구현 단순한 표시 제한이 아닌, 백엔드 레벨에서의 완전한 격리를 구현했다:\nflowchart TD A[\"GET /api/history/generations\"] --\u003e B{\"user_id 필터\"} B --\u003e C[\"본인 생성 기록만 반환\"] D[\"GET /images/filename\"] --\u003e E{\"check_file_ownership\"} E --\u003e|본인 파일| F[\"이미지 반환\"] E --\u003e|공유 레퍼런스| F E --\u003e|타인 생성 파일| G[\"403 Forbidden\"] get_generation_history(user_id=...) — 쿼리에 user_id 필터 추가 check_file_ownership(filename, user_id) — 생성/업로드 파일의 소유권 확인. 레퍼런스 이미지(image_ref_* 디렉토리)는 공유 자산이므로 허용, gen_*/upload_* 파일은 소유자만 접근 가능 /images/{filename} 엔드포인트 — 인증 의존성 추가 및 소유권 검증 async def check_file_ownership(filename: str, user_id: int) -\u0026gt; bool: \u0026#34;\u0026#34;\u0026#34;Check if a generated or uploaded file belongs to the given user. Returns True if the file is not found in any table (legacy/orphan data). \u0026#34;\u0026#34;\u0026#34; 비동기 병렬 생성 배경 PRD 2.4에서 비교 생성(톤+앵글 vs 톤만)을 Promise.all로 병렬 실행하도록 명시했지만, 실제 백엔드는 순차 호출(await 연속)로 구현되어 있었다. 4장 생성 기준으로 대기 시간이 두 배였다.\n구현 asyncio.gather와 asyncio.Semaphore를 활용하여 Gemini API 호출을 병렬화했다:\nimport asyncio # Limit concurrent Gemini API calls _gemini_semaphore = asyncio.Semaphore(4) 기존에 for 루프로 순차 생성하던 _generate_batch 함수를 리팩토링하여, 비교 모드일 때 두 배치를 asyncio.gather로 동시 실행하도록 변경했다. Semaphore로 동시 호출 수를 제한하여 API rate limit을 방지했다.\nDB 관리 편의 — make db-clean 개발 중 데이터를 자주 초기화해야 했는데, 매번 sqlite3 명령어를 수동으로 입력하는 것이 번거로웠다. Makefile에 db-clean 타겟을 추가:\ndb-clean: @sqlite3 data/logs.db \u0026#34;DELETE FROM search_logs; DELETE FROM image_selections; DELETE FROM generation_logs; DELETE FROM manual_uploads;\u0026#34; @echo \u0026#34;Cleared: search_logs, image_selections, generation_logs, manual_uploads\u0026#34; 스키마와 alembic_version, images, users 테이블은 보존하고 로그 데이터만 정리한다.\n커밋 로그 메시지 변경 perf: parallelize image generation with async Gemini API backend/src/main.py data: update images.json with refreshed labels and metadata data/images.json feat: comparison hover overlay, injection badges, and scrollable search results App.tsx, GeneratedImageDetail.tsx, SearchResultsPopup.tsx feat: add comparison images and injection info to generation history API schemas.py, api.ts chore: add db-clean Makefile target for clearing log tables Makefile chore: remove stale docs and skill file, update gitignore .gitignore 외 4파일 fix: isolate user data — filter history by user_id and enforce image ownership database/__init__.py, service.py, main.py docs: update README with auto-injection system README.md 외 2파일 인사이트 시각적 피드백은 디버깅 도구이기도 하다 — 톤/앵글 주입 정보를 UI에 표시하는 과정에서 실제 주입 로직의 버그(카테고리 미로딩, 필드명 불일치)를 여럿 발견했다. \u0026ldquo;보이게 만들면 버그도 보인다.\u0026rdquo; 데이터 격리는 처음부터 — 멀티유저 기능을 나중에 추가하면 기존 쿼리를 전부 뒤져야 한다. user_id 필터는 테이블 설계 단계부터 넣어두는 것이 맞다. Semaphore로 API 병렬화 제어 — asyncio.gather만으로는 rate limit에 걸릴 수 있다. Semaphore(4) 같은 동시성 제한을 함께 사용해야 안정적이다. 가로 스크롤 UX — 이미지 검색 결과는 세로 그리드보다 가로 스크롤이 직관적이다. 특히 카테고리별 결과를 한 줄씩 보여주면 비교가 쉬워진다. hover 시 나타나는 화살표 버튼은 스크롤바를 숨기면서도 조작성을 유지하는 좋은 패턴이다. ","date":"2026-03-20T00:00:00+09:00","image":"/images/posts/2026-03-20-hybrid-search-dev2/cover.jpg","permalink":"/ko/posts/2026-03-20-hybrid-search-dev2/","title":"하이브리드 이미지 검색 개발기 #2 — 자동 주입 시각화, 사용자 격리, 비동기 병렬 생성"},{"content":"개요 Claude Code를 설치하고 기본 사용법을 익힌 뒤에도, \u0026ldquo;왜 나는 남들만큼 효과를 못 보지?\u0026ldquo;라는 의문이 드는 경우가 많다. 대화가 길어지면 Claude가 점점 멍청해지고, 같은 실수를 반복하고, 코드를 수정하다가 다른 곳이 망가진다. 이런 문제의 대부분은 컨텍스트 관리와 워크플로우의 문제다.\n이 글에서는 두 편의 영상을 기반으로 실전에서 바로 적용할 수 있는 전략과 패턴을 정리한다. 첫 번째는 메타 엔지니어가 정리한 컨텍스트 관리와 실전 워크플로우 20분 총정리로, Second Brain 구축부터 WAT 프레임워크까지 다룬다. 두 번째는 Anthropic 해커톤 우승자 Afan Mustafa의 Claude Code 10가지 꿀팁으로, GitHub 스타 7만 이상을 달성한 10개월간의 실전 노하우를 초급-중급-고급 단계로 풀어낸다.\n두 영상의 핵심 메시지는 같다. Claude Code의 성능은 얼마나 좋은 컨텍스트를 주느냐에 달려 있고, 그 컨텍스트를 체계적으로 관리하는 시스템이 곧 생산성이다.\n컨텍스트 관리의 핵심 원칙 Second Brain — 지식을 구조화하라 Claude Code와 작업하면서 발견한 패턴, 해결책, 의사결정 이유를 로컬 markdown 파일에 기록해두는 전략이다. 메타 엔지니어는 프로젝트 의사 결정 기록 문서를 만들어 목차별로 개발 중 마주한 패턴, 해결책, 의사 결정 이유를 정리해두었다. 다음에 비슷한 작업을 할 때 Claude에게 이 파일만 읽히면 된다.\n이전에는 이 문서를 수동으로 관리했지만, 현재는 /memory 명령으로 자동화되었다. Claude가 작업하면서 자동으로 학습한 내용 — 빌드 명령, 디버깅 인사이트, 코드 패턴 — 을 MEMORY.md에 저장하고, 매 세션 시작 시 자동으로 로드한다. \u0026ldquo;기억해줘\u0026quot;라고 말하면 저장되고, /memory로 확인하거나 편집할 수 있다.\n파일 역할 범위 관리 방식 CLAUDE.md 팀 공유 규칙, 코딩 컨벤션, 아키텍처 결정 프로젝트 전체 수동 MEMORY.md 개인 선호, 반복 실수 패턴, 학습 내용 개인 자동 (/memory) TODO.md 세션 간 작업 연속성 유지 세션 단위 수동 + AI 협업 핵심은 CLAUDE.md에 모든 것을 넣지 않는 것이다. 개인 메모리는 MEMORY.md로, 팀 공유 지식은 CLAUDE.md로 분리하는 것을 추천한다.\nLazy Loading — 필요할 때만 로드하라 사람들이 하는 흔한 실수가 API 스펙, DB 스키마, 코딩 컨벤션, 아키텍처 문서를 전부 CLAUDE.md 하나에 몰아넣는 것이다. 문제는 CLAUDE.md가 매 세션마다 자동으로 로드된다는 점이다. API 엔드포인트 50개, DB 테이블 스키마 30개가 들어 있다면 매번 수천 토큰이 날아간다. 정작 작업에 필요한 건 그중 5%도 안 된다.\n나쁜 예 — CLAUDE.md에 API 엔드포인트 50개를 모두 포함:\n# CLAUDE.md ## API Endpoints POST /api/users ... GET /api/users/:id ... (50개 엔드포인트 전부 나열) 좋은 예 — CLAUDE.md에는 참조만 두고, 상세는 별도 파일로 분리:\n# CLAUDE.md ## 참조 문서 - API 스펙: docs/api-spec.md - DB 스키마: docs/db-schema.md - 아키텍처: docs/architecture.md 이 전략을 사용하면 Lazy Loading이 된다. \u0026ldquo;DB 스키마 업데이트 해줘\u0026quot;라고 하면 Claude가 CLAUDE.md에서 docs/db-schema.md 파일만 읽고 작업을 수행한다. 다른 API 스펙이나 프론트엔드 아키텍처 문서는 로드하지 않는다. Afan Mustafa는 이를 Progressive Disclosure라고 표현했다 — 회사에서 신입에게 업무 매뉴얼을 통째로 주는 것보다 목차만 주고 필요할 때 찾아보라고 하는 것이 낫다.\n루트 CLAUDE.md가 커지는 것이 걱정된다면 폴더별 CLAUDE.md를 따로 만들면 된다:\nproject/ ├── CLAUDE.md # 전체 규칙 (간결하게) ├── apps/api/ │ └── CLAUDE.md # API 서버 전용 규칙 ├── web/ │ └── CLAUDE.md # 프론트엔드 전용 규칙 ├── supabase/ │ └── CLAUDE.md # DB 관련 규칙 └── docs/ └── architecture.md # Mermaid 다이어그램 포함 특정 폴더에서 작업할 때 해당 폴더의 CLAUDE.md만 자동으로 로드된다. 루트 CLAUDE.md의 비대화를 막으면서 컨텍스트 오염도 방지할 수 있다.\n아키텍처를 Mermaid 다이어그램으로 정리하라 매번 시스템 구조를 말로 설명하는 대신 Mermaid 다이어그램으로 아키텍처를 정리하면 Claude가 훨씬 빠르게 이해하고 컨텍스트도 효율적으로 저장된다.\ngraph TD A[\"API Gateway\"] --\u003e B[\"인증 서비스\"] A --\u003e C[\"주문 서비스\"] A --\u003e D[\"결제 서비스\"] A --\u003e E[\"재고 서비스\"]이런 다이어그램을 docs/architecture.md 같은 별도 파일에 기능별로 정리해두고 CLAUDE.md에서 참조하면, Lazy Loading과 결합하여 Claude가 필요한 아키텍처만 읽고 기능을 짤 수 있다. 자연어로 설명하는 것보다 토큰 효율이 훨씬 높다.\n세션 위생 — 하나의 세션, 하나의 기능 컨텍스트 윈도우는 200K 토큰이 한계다. 많아 보이지만 실제로 쓰다 보면 생각보다 금방 찬다. Afan Mustafa는 이를 **\u0026ldquo;Context is milk\u0026rdquo;**라고 표현했다 — 시간이 지나면 상한다. 대화가 길어질수록 앞에서 나눈 내용이 흐릿해진다.\n핵심 원칙:\n한 세션 = 한 기능. \u0026ldquo;결제 시스템 전체 만들어줘\u0026quot;가 아니라 \u0026ldquo;Stripe webhook handler 구현해줘\u0026rdquo; 단위로 쪼개야 한다. 로그인 기능 구현이 끝났다면 /clear로 초기화하거나 아예 새 세션을 시작하고 다음 기능으로 넘어간다 **적절한 시점에 /compact**를 실행한다. 자동 압축에만 맡기면 중요한 맥락이 날아갈 수 있다. 큰 기능 하나를 완성했을 때, 또는 작업 방향이 바뀔 때 한 번씩 실행하면 중요한 맥락은 살리면서 불필요한 내용만 정리해준다 /statusline으로 현재 토큰 사용량을 상시 모니터링한다. 자동차 운전할 때 연료 게이지가 없으면 불안한 것처럼, 눈에 보여야 관리가 된다 **핵심 원칙은 \u0026ldquo;신선한 컨텍스트가 부풀어진 컨텍스트보다 낫다\u0026rdquo;**이다. 이전 대화에 집착하지 말고, 매 작업마다 깨끗한 세션으로 시작하는 것이 오히려 더 좋은 결과를 만든다.\nMCP 다이어트 — 사용하지 않는 도구는 끄라 MCP를 여러 개 연결하면 도구 설명만으로 토큰을 크게 소비한다. Afan Mustafa의 실제 설정을 보면 MCP를 14개나 설치해두었지만 동시에 켜놓는 건 5~6개뿐이다. 나머지는 필요할 때만 켠다.\n시스템 프롬프트가 약 2만 토큰까지 차지할 수 있는데, 안 쓰는 MCP를 꺼두면 9,000 토큰으로 반 이상 줄일 수 있다. 너무 많이 켜두면 Claude가 쓸 수 있는 컨텍스트 공간이 200K에서 7만 토큰까지 줄어들 수 있다.\n두 영상 모두 같은 조언을 한다:\n/mcp로 현재 활성화된 MCP를 확인한다 지금 작업에 안 쓰는 MCP는 비활성화한다 특히 Notion, Linear 같은 MCP는 도구 설명이 매우 커서 토큰을 크게 잡아먹는다 자주 쓰는 기능만 골라서 커스텀 MCP를 만들어 쓴다. 필요한 엔드포인트만 래핑하면 토큰 절약은 물론 응답 품질도 올라간다 flowchart TD A[\"컨텍스트 관리 전략\"] --\u003e B[\"Second Brain\u0026lt;br/\u0026gt;CLAUDE.md + MEMORY.md\"] A --\u003e C[\"Lazy Loading\u0026lt;br/\u0026gt;폴더별 CLAUDE.md\"] A --\u003e D[\"세션 위생\u0026lt;br/\u0026gt;1 session = 1 feature\"] A --\u003e E[\"MCP Diet\u0026lt;br/\u0026gt;미사용 MCP 비활성화\"] A --\u003e F[\"Mermaid 아키텍처\u0026lt;br/\u0026gt;토큰 효율적 구조 문서화\"] A --\u003e G[\"스크립트 오프로드\u0026lt;br/\u0026gt;무거운 작업 분리\"] B --\u003e B1[\"팀 규칙은 CLAUDE.md\u0026lt;br/\u0026gt;개인 학습은 MEMORY.md\"] C --\u003e C1[\"규칙만 상위에\u0026lt;br/\u0026gt;상세는 별도 파일 참조\"] D --\u003e D1[\"/clear로 초기화\u0026lt;br/\u0026gt;/statusline으로 모니터링\"] E --\u003e E1[\"14개 설치, 5-6개만 활성\u0026lt;br/\u0026gt;2만→9천 토큰 절약\"]무거운 작업은 스크립트로 오프로드하라 무거운 데이터 처리를 대화 안에서 시키면 컨텍스트가 오염된다. 10만 행짜리 CSV를 파싱해야 하는 DB 마이그레이션을 예로 들면, Claude가 그 10만 행을 읽어야 하고, 모두 컨텍스트에 저장해야 하고, 처리해야 한다. 이 과정에서 컨텍스트가 오염되고 품질이 떨어진다.\n대신 이렇게 한다:\nClaude에게 CSV를 파싱하는 DB 마이그레이션 스크립트를 작성해 달라고 한다 Claude에게 그 스크립트를 실행하게 한다 스크립트가 처리한 결과(JSON 등)만 Claude가 받아서 다음 작업을 진행한다 Claude는 10만 행의 CSV를 직접 읽을 필요가 없다. 스크립트가 처리한 결과값만 받으면 된다. 무거운 데이터는 스크립트로, 결과 요약만 Claude가 받으면 컨텍스트가 깨끗하게 유지된다.\n실전 워크플로우 패턴 Plan 모드 — 먼저 설계하고, 그 다음 구현하라 두 영상 모두 Plan 모드를 먼저 실행하라고 강조한다. Afan은 \u0026ldquo;건축할 때 설계도 없이 벽돌부터 쌓지 않는 것처럼\u0026quot;이라고 비유했다. 플랜 없이 바로 실행하면 Claude가 엉뚱한 방향으로 코드를 대량 수정해버리는 참사가 발생할 수 있다. 컨텍스트도 낭비되고, 사용량(usage)도 낭비된다.\n구체적인 실전 워크플로우:\nPlan 모드에서 Claude에게 작업을 설명한다 Claude가 계획을 제시한다 — 어떤 파일을 수정해야 하고, 어떤 접근을 해야 하는지 계획을 리뷰하고 피드백을 준다. 계획이 틀렸다면 수정 방향을 알려주고, 다른 옵션을 원한다면 대안을 요청한다 만족스러운 계획이 나오면 Accept 모드로 전환하여 실행한다 완료되면 /clear 후 다음 단계로 넘어간다 핵심은 플랜을 짜는 세션과 구현하는 세션을 분리하는 것이다.\nThinking 프로세스를 반드시 읽어라 Claude가 사고하는 과정(thinking)을 무시하면 안 된다. Claude가 \u0026ldquo;이 함수는 X를 하는 것 같으니까 이걸 하겠다\u0026quot;라며 가정을 세우는 순간이 있는데, 그 가정이 틀릴 때가 있다. 그 순간에 Escape로 바로 중단시키고 가정을 수정해줘야 한다. 잘못된 가정 위에 쌓인 코드는 전부 쓸모없다. 초반에 잡는 것이 핵심이다.\nCross-AI 비평 메타 엔지니어가 유용하게 쓰는 팁이다. Claude의 플랜을 ChatGPT나 Gemini에게 보여주고 비평을 받는다.\n\u0026ldquo;이 대화를 분석해서 Claude가 놓치고 있는 거나 잘못된 접근이 있으면 지적해줘\u0026rdquo;\n각 AI 모델이 정말 다른 시선으로 문제를 정의하고 다른 솔루션을 제시하는 것을 볼 수 있다. 여기서 한 단계 더 나아가면, 이 과정 자체를 커스텀 스킬로 자동화할 수 있다. 예를 들어 with-multiple-ai라는 스킬을 만들면 한 AI 모델의 플랜을 다른 AI에게 전달하고, 피드백을 취합해서 요약을 보여주는 워크플로우를 자동화할 수 있다.\nTDD 기반 스마트 코딩 AI가 만든 코드를 사람이 꼼꼼히 보기 어렵기 때문에, 작은 단위의 TDD 루프가 필수적이다.\nflowchart LR A[\"작은 변경\"] --\u003e B[\"테스트 작성\"] B --\u003e C[\"테스트 실행\"] C --\u003e D{\"통과?\"} D -- Yes --\u003e E[\"커밋\"] D -- No --\u003e F[\"수정\"] F --\u003e C E --\u003e G[\"다음 변경\"] G --\u003e A 변경 단위를 작게 유지한다 매 변경 후 테스트를 작성하고 실행한다 통과하면 바로 커밋한다. 문제가 생겨도 마지막 커밋으로 돌아가면 되니까 디버깅이 훨씬 쉬워진다 에러가 발생하면 로그를 해석하지 말고 통째로 붙여넣는다 — 사람이 해석해서 정보를 빠뜨리거나 잘못된 정보를 줄 수 있다. Claude는 스택트레이스 분석에 매우 뛰어나므로 원본 그대로 주는 것이 가장 좋다 TODO.md로 작업 연속성 유지 AI는 오늘 할 일, 내일 할 일, 모레 할 일을 우리처럼 다 알고 있지 않다. TODO.md를 프로젝트 시작부터 끝까지 하나의 파일에서 관리하면서 AI와 공유하는 것이 핵심이다.\n실전 워크플로우:\n오늘 할 일을 정리한다 — 결제 구현, 랜딩 페이지 다듬기, 구독 시스템, 버그 1번·2번 수정 TODO.md에 체크리스트로 작성한다 Claude에게 \u0026ldquo;TODO.md 파일부터 시작해줘\u0026quot;라고 지시한다 Agent Teams 기능으로 여러 태스크를 병렬 처리한다 세션 종료 시 \u0026ldquo;TODO.md에 업데이트해줘\u0026quot;라고 말하면 진행 상황이 자동으로 반영된다 이렇게 하면 여러 세션에 걸쳐서 작업의 연속성을 유지할 수 있다.\nWAT Framework NetworkChuck가 제안한 WAT(Workflow-Agent-Tools) 프레임워크는 Claude Code 프로젝트 관리의 구조를 잡는 틀이다. 메타 엔지니어도 실제로 써보고 나쁘지 않았다고 한다.\nW (Workflow) — 작업의 흐름과 단계를 plain English로 명확하게 정의한다. 코드를 쓰기 전에 이 작업이 어떤 단계로 이루어져야 하는지를 글로 적는다 A (Agent) — 각 단계를 수행할 에이전트를 배치한다. Self-healing 메커니즘이 핵심이다 — 에러가 나면 스스로 로그를 읽고, 원인을 파악하고, 코드를 수정하고, 다시 실행한다. 에이전트들로 역할을 분리해서 병렬 처리하면 10분 걸릴 작업을 3~4분에 끝낼 수 있다 T (Tools) — 거대한 스크립트 하나보다 작은 단위의 스크립트 여러 개가 훨씬 낫다. deploy-all.sh 대신 원잡(one-job) 단위로 쪼개야 한다. Claude가 스크립트 실행 중 실패했을 때 작은 스크립트 하나를 디버깅하는 것이 훨씬 효율적이다 구체적 예시 — 블로그에 댓글 기능 추가하기:\nW (Workflow): 1. comments 테이블 스키마 설계 및 마이그레이션 2. API 엔드포인트 구현 3. 프론트엔드 UI 구현 4. 각 단계마다 테스트 작성 및 통과 확인 A (Agent): - Claude가 코디네이터로서 에이전트들에게 작업 분배 - API 구현하는 동안 다른 서브에이전트가 테스트를 미리 설계 - 에러 발생 시 self-healing으로 자동 복구 T (Tools): - scripts/migrate.sh → DB 마이그레이션 실행 - MCP GitHub → PR 자동 생성 - Hooks → 커밋마다 테스트 자동 실행 이 프레임워크의 핵심은 AI의 추론과 코드 실행을 분리하는 것이다. Claude에게 생각하게 하고, 실행은 별도 도구나 스크립트에 맡기면 복잡한 워크플로우도 안정적으로 관리할 수 있다.\n모델 선택 전략 모든 작업에 Opus를 쓸 필요는 없다. Afan Mustafa는 식당 비유를 들었다 — 간단한 식사에 코스 요리를 시키진 않는 것처럼.\n모델 적합한 작업 비유 Haiku 파일 찾기, 간단한 수정, 포맷 변경 간단한 식사 Sonnet 여러 파일 동시 수정, 일반 코딩, 버그 수정 일반 식사 Opus 전체 구조 설계, 복잡한 버그, 멀티파일 리팩토링 코스 요리 레퍼런스 코드를 같이 주는 것도 중요하다. Claude에게 뭔가 만들어달라고 할 때 비슷한 오픈소스 코드를 같이 보여주면 결과물의 품질이 확연히 달라진다. 미술 시간에 빈 종이에 그리라는 것과 참고 작품을 보고 그리라는 건 완전히 다르다.\n고급 활용: 서브에이전트와 자동화 서브에이전트 — 전문화된 16개의 에이전트 Afan Mustafa의 시스템에는 16개의 전문 서브에이전트가 있다. 오케스트라 지휘자가 직접 모든 악기를 연주하지 않듯이, 각 에이전트에게 할 일을 하나씩만 주고 결과물을 다음 에이전트에게 넘기는 방식이다.\nflowchart TD M[\"메인 에이전트\u0026lt;br/\u0026gt;오케스트라 지휘자\"] --\u003e P[\"Planner\u0026lt;br/\u0026gt;작업 계획 수립\"] M --\u003e D[\"Designer\u0026lt;br/\u0026gt;UI/UX 설계\"] M --\u003e R[\"Reviewer\u0026lt;br/\u0026gt;코드 리뷰\"] M --\u003e T[\"Tester\u0026lt;br/\u0026gt;테스트 작성\"] M --\u003e O[\"기타 전문 에이전트\u0026lt;br/\u0026gt;총 16개\"] P --\u003e |\"계획 전달\"| D D --\u003e |\"설계 전달\"| T R --\u003e |\"피드백 반영\"| M서브에이전트를 활용하면 각 역할의 컨텍스트를 독립적으로 유지할 수 있고, 메인 에이전트가 오케스트레이션만 담당하므로 복잡한 프로젝트도 체계적으로 진행할 수 있다.\nGit Worktrees — 병렬 작업의 핵심 보통은 하나의 작업이 끝나야 다음을 시작하지만, git worktree를 사용하면 같은 프로젝트에서 여러 작업 폴더를 동시에 만들 수 있다. 사무실에서 책상 하나로 일하던 것을 책상 5개 놓고 동시에 진행하는 것과 같다.\n# worktree 생성 git worktree add ../project-feature-a feature-a git worktree add ../project-feature-b feature-b # 각 worktree에서 독립적인 Claude Code 세션 실행 cd ../project-feature-a \u0026amp;\u0026amp; claude cd ../project-feature-b \u0026amp;\u0026amp; claude 각 폴더에서 Claude를 따로 실행하면 에이전트 5개가 동시에 다른 기능을 개발한다. 서로 충돌하지 않는 기능이라면 동시에 개발을 진행하고, 완료 후 main에 머지하는 방식이다.\nHooks — 자동 학습 시스템 Claude Code의 Hook 기능은 알람 시계와 같다. 특정 시점에 자동으로 실행되는 명령어를 설정할 수 있다.\nHook 타이밍 활용 예시 session_start 새 대화 시작 시 지난 기록 자동 불러오기, TODO.md 로드 pre_compact 컨텍스트 압축 전 중요 내용을 MEMORY.md에 먼저 저장 stop 대화 종료 시 이번 세션에서 배운 것을 자동 기록 이 세 개를 조합하면 Claude가 대화가 끝나도 배운 것을 기억하는 시스템이 된다. 매번 수동으로 컨텍스트를 설정하는 수고를 줄이고, Claude가 프로젝트에 대해 점점 더 많이 \u0026ldquo;기억\u0026quot;하게 된다.\n보안 주의사항 Afan Mustafa가 강조한 주의사항도 빠뜨릴 수 없다:\nMCP를 너무 많이 켜지 마라 — 컨텍스트 공간이 크게 줄어든다 자동 압축만 믿지 마라 — 중요한 맥락이 날아갈 수 있다 보안에 신경 써라 — Claude가 외부 데이터를 읽을 때 악의적인 명령이 숨어 있을 수 있다. 이를 Prompt Injection이라 하며, Afan의 가이드에는 이를 자동으로 감지하는 보안 도구도 포함되어 있다 빠른 링크 메타 엔지니어의 클로드코드 완벽 가이드 — 실전편 — 컨텍스트 관리, TDD 워크플로우, WAT 프레임워크, Cross-AI 비평 Claude Code 10가지 꿀팁 — Anthropic 해커톤 우승자 — Progressive Disclosure, 시스템 프롬프트 다이어트, 서브에이전트, Git Worktrees, Hooks 인사이트 두 영상을 관통하는 인사이트는 **\u0026ldquo;Claude Code는 도구가 아니라 시스템이다\u0026rdquo;**라는 점이다. 단순히 프롬프트를 잘 쓰는 것을 넘어, 지식 관리(CLAUDE.md, MEMORY.md), 세션 설계(Plan-Implement 분리, /clear), 도구 최적화(MCP Diet), 자동화(Hooks, 서브에이전트)까지 아우르는 개발 시스템을 구축해야 한다.\n특히 인상적인 것은 두 영상의 출발점이 다른데도 결론이 수렴한다는 점이다. 메타 엔지니어는 대규모 팀 환경에서, Afan Mustafa는 개인 해커톤 프로젝트에서 출발했지만, 둘 다 컨텍스트 효율성과 작업 단위의 분리를 최우선으로 꼽는다. 이는 Claude Code의 컨텍스트 윈도우라는 물리적 제약이 만들어낸 자연스러운 수렴이다.\n실천 우선순위를 정한다면: 먼저 CLAUDE.md를 정리하고 폴더별로 분리하라. 그 다음 Plan 모드를 습관화하라. 그리고 TODO.md로 세션 간 연속성을 확보하라. 마지막으로 서브에이전트와 Hooks로 자동화를 확장하라. 한 번에 모두 적용하려 하지 말고, 한 단계씩 워크플로우에 녹여가는 것이 핵심이다.\n","date":"2026-03-19T00:00:00+09:00","image":"/images/posts/2026-03-19-claude-code-practical-guide/cover.jpg","permalink":"/ko/posts/2026-03-19-claude-code-practical-guide/","title":"Claude Code 실전 가이드 — 컨텍스트 관리부터 워크플로우까지"},{"content":"개요 Anthropic이 Claude Code Skills의 대규모 업데이트를 발표했다. 가장 눈에 띄는 변화는 빌트인 벤치마킹 시스템의 도입이다. 스킬이 실제로 결과물의 품질을 높이는지 A/B 테스트 방식으로 수치화할 수 있게 되었고, Skill Creator V2가 테스트 케이스 생성부터 반복 개선까지 전 과정을 자동화한다. 새로운 프론트매터 옵션들도 추가되어 스킬의 실행 방식을 세밀하게 제어할 수 있다.\n스킬의 두 가지 분류: Capability Uplift vs Inquiry Preference Anthropic은 공식적으로 스킬을 두 가지 범주로 나누었다.\nCapability Uplift Skills 모델이 기본적으로 할 수 없는 일을 가능하게 만드는 스킬이다. 특정 API 호출 패턴이나 외부 도구 연동 등이 여기에 해당한다. 이 유형의 스킬은 모델이 발전하면 불필요해질 수 있다. 모델 자체가 해당 능력을 흡수하면 스킬 없이도 동일한 결과를 낼 수 있기 때문이다.\nInquiry Preference Skills 사용자의 특정 워크플로우나 선호도를 강제하는 스킬이다. 예를 들어 \u0026ldquo;응답을 항상 한국어로 작성하라\u0026rdquo;, \u0026ldquo;PR 리뷰 시 반드시 보안 체크리스트를 따르라\u0026rdquo; 같은 규칙들이다. 이 유형은 모델이 아무리 발전해도 사용자 고유의 요구사항이므로 deprecated될 일이 없다.\nflowchart TD A[\"Claude Code Skill\"] --\u003e B[\"Capability Uplift\"] A --\u003e C[\"Inquiry Preference\"] B --\u003e D[\"모델이 못하는 기능 활성화\"] D --\u003e E[\"모델 발전 시 deprecated 가능\"] C --\u003e F[\"사용자 워크플로우 강제\"] F --\u003e G[\"deprecated 없음 — 사용자 고유 요구\"] style B fill:#f9a825,stroke:#f57f17,color:#000 style C fill:#42a5f5,stroke:#1565c0,color:#000 style E fill:#ef5350,stroke:#c62828,color:#fff style G fill:#66bb6a,stroke:#2e7d32,color:#000이 분류가 중요한 이유는 바로 다음에 설명할 벤치마킹 시스템 때문이다. Capability Uplift 스킬은 벤치마크 결과에 따라 퇴역 여부를 판단할 수 있다.\n벤치마킹 시스템: 스킬의 가치를 수치로 증명하다 V2의 핵심 기능이다. 스킬이 실제로 결과물의 품질을 높이는지 정량적으로 측정할 수 있는 빌트인 평가 시스템이 추가되었다.\n작동 방식 flowchart LR subgraph 평가[\"A/B 테스트 실행\"] direction TB A1[\"스킬 적용 O\"] --\u003e R1[\"결과 A\"] A2[\"스킬 적용 X\"] --\u003e R2[\"결과 B\"] end subgraph 판정[\"점수 비교\"] direction TB R1 --\u003e SC[\"평가 기준별 채점\"] R2 --\u003e SC SC --\u003e V{\"점수 차이?\"} V --\u003e|\"유의미한 차이\"| KEEP[\"스킬 유지\"] V --\u003e|\"비슷한 점수\"| DROP[\"스킬 불필요 — 모델이 이미 흡수\"] end 평가 --\u003e 판정 style KEEP fill:#66bb6a,stroke:#2e7d32,color:#000 style DROP fill:#ef5350,stroke:#c62828,color:#fffMulti-agent 지원으로 A/B 테스트를 동시에 실행할 수 있다. 스킬이 적용된 에이전트와 적용되지 않은 에이전트가 동일한 태스크를 수행하고, 결과를 평가 기준에 따라 비교한다.\n자동 생성되는 평가 기준 예시 Skill Creator가 소셜 미디어 포스트 생성 스킬을 만들 때 자동으로 생성한 7가지 평가 기준 사례:\n# 평가 기준 설명 1 Platform coverage 지정된 플랫폼별 포스트가 모두 생성되었는가 2 Language match 요청한 언어로 작성되었는가 3 X character limit X(트위터) 글자 수 제한을 준수하는가 4 Hashtags 적절한 해시태그가 포함되었는가 5 Factual content 원본 내용과 사실적으로 일치하는가 6 Tone differentiation 플랫폼별 톤이 적절히 차별화되었는가 7 Tone compliance 지정된 톤 가이드라인을 따르는가 스킬 적용 여부에 따라 이 기준들의 점수가 유의미하게 차이나면 해당 스킬은 가치가 있는 것이고, 점수가 비슷하면 모델이 이미 해당 능력을 갖추고 있으므로 스킬이 불필요하다는 뜻이다.\n스킬 크리에이터 V2: 만들고 평가하고 개선하는 자동화 루프 Skill Creator Skill이 V2로 업그레이드되면서 단순 생성을 넘어 전체 라이프사이클을 자동화한다.\n설치 및 사용 /plugin 명령 실행 \u0026ldquo;skill creator skill\u0026rdquo; 검색 후 설치 원하는 스킬을 자연어로 설명 자동으로 스킬 생성 → 테스트 케이스 생성 → 벤치마크 실행 → 결과 확인 자동화 루프 flowchart TD START[\"사용자: 원하는 스킬 설명\"] --\u003e CREATE[\"Skill Creator가 스킬 생성\"] CREATE --\u003e EVAL[\"테스트 케이스 자동 생성\"] EVAL --\u003e BENCH[\"벤치마크 실행 \u0026lt;br/\u0026gt; with skill vs without skill\"] BENCH --\u003e REVIEW{\"사용자 만족?\"} REVIEW --\u003e|\"아니오\"| IMPROVE[\"피드백 기반 개선\"] IMPROVE --\u003e EVAL REVIEW --\u003e|\"예\"| DONE[\"스킬 완성\"] style START fill:#42a5f5,stroke:#1565c0,color:#000 style DONE fill:#66bb6a,stroke:#2e7d32,color:#000 style BENCH fill:#f9a825,stroke:#f57f17,color:#000기존 스킬의 개선도 가능하다. 이미 만들어진 스킬을 Skill Creator에 넘기면 현재 성능을 벤치마크한 뒤 개선점을 찾아 반복적으로 최적화한다.\nProgressive disclosure guidance가 내장되어 있어, 스킬 작성 경험이 적은 사용자도 단계적으로 안내받으며 스킬을 완성할 수 있다.\nImplicit Triggering 개선 이전 버전에서는 implicit trigger(슬래시 명령 없이 자동 실행)가 잘 작동하지 않는 문제가 있었다. V2에서는 Skill Creator가 description 최적화를 함께 수행하면서 implicit triggering의 정확도가 크게 향상되었다. 스킬의 설명문이 모델이 언제 이 스킬을 호출해야 하는지 더 명확하게 전달하도록 자동으로 다듬어진다.\n새로운 프론트매터 옵션들 V2에서 추가된 프론트매터 옵션으로 스킬의 동작을 세밀하게 제어할 수 있다.\n옵션 설명 user_invocable: false 모델만 트리거 가능, 사용자가 직접 호출 불가 user_enable: false 사용자가 slash command로 사용 불가 allow_tools 스킬이 사용할 수 있는 도구를 제한 model 스킬을 실행할 모델 지정 context: fork Sub-agent에서 스킬 실행 agents Sub-agent 정의 (context: fork 필요) hooks 스킬별 hooks를 YAML 형식으로 정의 특히 context: fork와 agents 조합이 흥미롭다. 스킬 실행을 별도의 sub-agent에 위임하여 메인 컨텍스트를 오염시키지 않고 독립적으로 작업을 수행할 수 있다. 벤치마킹의 multi-agent A/B 테스트도 이 구조 위에서 동작한다.\nuser_invocable: false는 사용자에게 노출하지 않으면서 모델이 내부적으로 판단하여 호출하는 \u0026ldquo;백그라운드 스킬\u0026quot;을 만들 때 유용하다.\n빠른 링크 Claude Skills V2 업데이트 영상 Claude Code 공식 문서 Anthropic 공식 사이트 인사이트 이번 V2 업데이트의 핵심은 스킬의 실효성을 객관적으로 측정할 수 있게 된 것이다.\n지금까지 스킬은 \u0026ldquo;만들면 좋아질 것이다\u0026quot;라는 가정 위에서 운영되었다. 하지만 빌트인 벤치마킹의 도입으로 스킬이 실제로 결과물의 품질을 높이는지, 아니면 모델이 이미 충분히 잘하는 영역에 불필요한 프롬프트를 추가하는 것인지 수치로 판단할 수 있게 되었다.\nCapability Uplift vs Inquiry Preference 분류도 실용적이다. 모든 스킬을 동일하게 취급하지 않고, 모델 발전에 따라 자연스럽게 퇴역시킬 스킬과 영구적으로 유지할 스킬을 구분하는 프레임워크를 제공한다.\nSkill Creator V2가 생성-평가-개선 루프를 자동화한 것도 진입 장벽을 크게 낮춘다. 스킬 작성 자체가 프롬프트 엔지니어링의 영역이었는데, 이제는 \u0026ldquo;무엇을 원하는지\u0026quot;만 말하면 최적화된 스킬이 벤치마크 검증까지 마친 상태로 완성된다. 스킬 생태계가 양적으로도 질적으로도 빠르게 성장할 것으로 보인다.\n","date":"2026-03-19T00:00:00+09:00","image":"/images/posts/2026-03-19-claude-skills-v2/cover.jpg","permalink":"/ko/posts/2026-03-19-claude-skills-v2/","title":"Claude Skills V2 — 벤치마킹과 자동 평가로 진화한 스킬 시스템"},{"content":"개요 이전 글: Harness(하니스) — Claude Code를 범용 AI에서 전담 직원으로에서 하니스 엔지니어링의 개념과 Claude Code에서의 Skills, Agents, Commands 핵심 구성 요소를 다뤘다. 이번 글에서는 Google이 무료로 제공하는 AI 개발 도구 Antigravity를 통해 하니스를 실전에서 어떻게 구축하고 활용하는지 살펴본다. Rules 계층 구조, Skills의 토큰 효율성, MCP 연동, 그리고 바이브 코딩으로 결제 기능이 포함된 SaaS까지 만드는 과정을 정리했다.\nAntigravity: 하니스의 실전 무대 Antigravity는 Google이 제공하는 무료 AI 개발 도구다. Cursor($20/월), GitHub Copilot($10/월), Replit($25/월) 같은 유료 도구의 대안으로 주목받고 있다.\n핵심 구조는 Agent Manager가 Editor와 Browser를 관리하는 형태다. 단순 코드 자동완성이 아니라 에이전트 중심 개발 방식을 채택했다. 에이전트가 계획을 세우고, 파일을 생성하고, 코드를 작성하고, 에러가 발생하면 스스로 수정까지 한다.\n특히 인상적인 점은 멀티 모델 지원이다. Gemini 3 Pro/Flash는 물론, Claude Sonnet 4.6/Opus 4.6, GPT OS까지 선택할 수 있다. Google 도구에서 Anthropic과 OpenAI 모델을 쓸 수 있다는 건 하니스 관점에서 중요하다. 동일한 Rules와 Skills 체계 아래에서 모델만 바꿔가며 최적의 조합을 찾을 수 있기 때문이다.\nflowchart LR subgraph Antigravity AM[\"Agent Manager\"] ED[\"Editor\"] BR[\"Browser Subagent\"] end subgraph Models G3P[\"Gemini 3 Pro\"] G3F[\"Gemini 3 Flash\"] CS[\"Claude Sonnet 4.6\"] CO[\"Claude Opus 4.6\"] GPT[\"GPT OS\"] end subgraph Harness[\"하니스 구성\"] R[\"Rules \u0026lt;br/\u0026gt; Global + Workspace + Inline\"] S[\"Skills \u0026lt;br/\u0026gt; Progressive Disclosure\"] M[\"MCP \u0026lt;br/\u0026gt; 35+ Services\"] end AM --\u003e ED AM --\u003e BR Models --\u003e AM Harness --\u003e AM하니스 구성 요소 실전 적용 하니스 엔지니어링의 핵심은 AI가 작업을 시작하기 전에 제어 구조와 작업 환경을 설계하는 것이다. 말의 하니스(마구)처럼 힘을 묶는 게 아니라 올바른 방향으로 이끄는 것이고, Test Harness처럼 실행 환경을 감싸서 제어하는 것이다.\nAntigravity에서 에이전트가 활성화되는 흐름은 다음과 같다.\nflowchart TD A[\"Global Rules 로드\"] --\u003e B[\"Workspace Rules 로드\"] B --\u003e C[\"Skills 로드 \u0026lt;br/\u0026gt; YAML frontmatter만\"] C --\u003e D[\"MCP 연결\"] D --\u003e E[\"Agent 작업 시작\"] style A fill:#4a9eff,color:#fff style B fill:#4a9eff,color:#fff style C fill:#f5a623,color:#fff style D fill:#7b61ff,color:#fff style E fill:#4caf50,color:#fffRules: 3계층 규칙 체계 Antigravity의 Rules는 세 가지 계층으로 나뉜다.\n계층 위치 용도 Global Rules .gemini/gemini.md 모든 프로젝트에 공통 적용되는 규칙 Workspace Rules .agents/rules/ 또는 .agent/rules/ 프로젝트별 규칙 Inline Rules 에이전트 채팅 내 직접 입력 즉각적인 리마인더 Global Rules는 Gemini CLI와 경로를 공유한다(.gemini/). 즉 Antigravity에서 설정한 규칙이 Gemini CLI에서도 동일하게 적용된다. 사용 쿼터는 별도로 관리되지만, 하니스 설정은 하나로 통일되는 셈이다.\nActivation Mode: 규칙의 발동 조건 Rules에는 네 가지 활성화 모드가 있다.\nAlways-on — 항상 적용 Model Decision — 모델이 필요하다고 판단하면 적용 GLB (File Pattern Matching) — 파일 확장자 패턴에 따라 적용 Manual — 직접 멘션해야 적용 GLB 패턴이 특히 실용적이다. 예를 들어 *.py 파일을 다룰 때 자동으로 \u0026ldquo;UV 가상환경을 사용하라\u0026quot;는 규칙을 적용할 수 있다. 파일 타입에 따라 다른 컨벤션을 강제할 수 있으니, 한 프로젝트에서 Python과 TypeScript를 동시에 다루는 경우에 유용하다.\n스킬과 MCP: 토큰 효율의 차이 Progressive Disclosure: 스킬의 핵심 설계 Antigravity의 Skills는 Progressive Disclosure 방식으로 동작한다. 처음에는 YAML frontmatter(description)만 로드한다. 에이전트가 해당 스킬이 필요하다고 판단했을 때 비로소 전체 내용을 읽는다.\n이 설계가 MCP와의 결정적 차이를 만든다. Context7 같은 MCP는 연결 시점에 대량의 컨텍스트를 한꺼번에 로드한다. 반면 Skills는 필요한 시점에 필요한 만큼만 컨텍스트를 소비한다. 토큰 예산이 제한된 환경에서 이 차이는 크다.\nflowchart LR subgraph Skills[\"Skills 방식\"] S1[\"YAML 설명만 로드 \u0026lt;br/\u0026gt; 수 토큰\"] --\u003e S2{\"필요한 \u0026lt;br/\u0026gt; 스킬?\"} S2 --\u003e|Yes| S3[\"전체 내용 로드 \u0026lt;br/\u0026gt; 필요한 것만\"] S2 --\u003e|No| S4[\"스킵 \u0026lt;br/\u0026gt; 토큰 절약\"] end subgraph MCP[\"MCP 방식\"] M1[\"연결 시 전체 로드 \u0026lt;br/\u0026gt; 대량 토큰\"] --\u003e M2[\"항상 컨텍스트에 \u0026lt;br/\u0026gt; 포함\"] end style S1 fill:#4caf50,color:#fff style S3 fill:#4caf50,color:#fff style S4 fill:#4caf50,color:#fff style M1 fill:#f44336,color:#fff style M2 fill:#f44336,color:#fffSkill Creator와 공식 스킬 설치 Antigravity에는 Skill Creator가 내장되어 있다. 스킬을 직접 만들고 반복적으로 개선할 수 있다. Anthropic의 공식 스킬을 GitHub에서 가져와 설치하는 것도 가능하다.\n스킬을 글로벌로 적용하려면 .gemini/skills/ 폴더에 드래그하면 된다. Git을 사용하지 않는 경우에는 ZIP으로 다운로드해서 배치할 수 있다.\nMCP: 외부 서비스 연동 MCP(Model Context Protocol)는 35개 이상의 외부 서비스를 에이전트에 연결한다. 데이터베이스, API, GitHub 등을 에이전트가 직접 조작할 수 있게 해준다. 에이전트 워크플로우를 구성하면 데이터 수집부터 리포트 생성, 대시보드 구축까지 자동화할 수 있다.\nSkills와 MCP를 적절히 조합하는 것이 하니스 설계의 핵심이다. 자주 쓰는 패턴은 Skills로, 외부 서비스 연동은 MCP로 분리하면 토큰 효율과 기능성을 동시에 확보할 수 있다.\n바이브 코딩으로 SaaS까지 바이브 코딩이란 바이브 코딩(Vibe Coding)은 Andrej Karpathy가 2025년 2월에 제안한 개념이다. 코드를 한 줄씩 작성하는 대신, AI에게 원하는 결과를 설명하고 AI가 코드를 생성하는 방식이다. 개발자는 방향을 잡고 결과를 검증하는 역할에 집중한다.\nAntigravity에서의 바이브 코딩은 에이전트가 계획 → 파일 생성 → 코드 작성 → 에러 자체 수정까지 전 과정을 수행한다. Browser Subagent가 Chrome을 직접 제어해서 UI 테스트와 디버깅까지 자동화한다.\n4가지 프로젝트로 보는 난이도 곡선 영상에서 소개된 4개 프로젝트는 단순한 것에서 복잡한 것으로 자연스럽게 난이도가 올라간다.\n프로젝트 난이도 핵심 요소 LinkInBio 입문 정적 페이지, 기본 레이아웃 Reading Tracker App 초급 CRUD, 데이터 저장 AI SNS Post Generator 중급 AI API 연동, 콘텐츠 생성 AI Background Removal SaaS 고급 결제(TossPayments), 관리자 대시보드, MRR 추적 마지막 SaaS 프로젝트가 인상적이다. TossPayments 결제 연동, 관리자 대시보드, MRR(Monthly Recurring Revenue) 트래킹까지 포함된 실제 서비스 수준의 결과물을 바이브 코딩으로 만들어낸다.\n디버깅 프레임워크 바이브 코딩에서도 에러는 발생한다. 영상에서 제시한 디버깅 프레임워크는 간결하다.\n에러 메시지 읽기 — 무엇이 실패했는지 파악 재현하기 — 동일 조건에서 에러 확인 컨텍스트와 함께 AI에 전달 — 에러 로그, 관련 코드, 재현 조건을 묶어서 전달 결국 디버깅도 하니스의 일부다. 에러 컨텍스트를 잘 구조화해서 전달하는 것 자체가 AI를 올바른 방향으로 이끄는 제어 구조이기 때문이다.\n빠른 링크 Harness Engineering 안티그래비티에 앤트로픽 클로드 스킬 적용하기 — Antigravity 하니스 구조, Rules/Skills/MCP 실전 적용 코딩 없이 SaaS와 결제 기능 만들어주는 Antigravity — 바이브 코딩, 4개 프로젝트 예제, TossPayments 연동 이전 글: Harness(하니스) — Claude Code를 범용 AI에서 전담 직원으로 — 하니스 엔지니어링 개념과 핵심 구성 요소 인사이트 이전 글에서 하니스를 \u0026ldquo;AI를 범용에서 전담으로 바꾸는 제어 구조\u0026quot;로 정의했다. Antigravity를 살펴보면서 이 개념이 도구를 넘어 패턴으로 수렴하고 있다는 걸 느낀다.\nClaude Code의 CLAUDE.md와 Antigravity의 .gemini/gemini.md는 이름만 다를 뿐 역할이 같다. Skills의 Progressive Disclosure도 Claude Code의 스킬 시스템과 동일한 설계 철학을 공유한다. 도구는 다르지만 하니스 구성 요소 — Rules, Skills, MCP — 는 거의 1:1로 대응된다.\n주목할 점은 토큰 효율이다. MCP가 편리하지만 연결 시점에 대량의 컨텍스트를 소비한다. Skills의 Progressive Disclosure는 이 문제를 우아하게 해결한다. 하니스를 설계할 때 \u0026ldquo;무엇을 컨텍스트에 넣을까\u0026quot;보다 \u0026ldquo;언제 컨텍스트에 넣을까\u0026quot;를 먼저 고민해야 하는 이유다.\n바이브 코딩으로 SaaS까지 만들 수 있다는 건, 이제 개발의 병목이 코딩 능력이 아니라 하니스 설계 능력으로 이동하고 있다는 신호다. 어떤 Rules를 세울지, 어떤 Skills를 준비할지, 에러 컨텍스트를 어떻게 구조화할지 — 이것이 결과물의 품질을 결정한다.\n","date":"2026-03-19T00:00:00+09:00","image":"/images/posts/2026-03-19-harness-antigravity/cover.jpg","permalink":"/ko/posts/2026-03-19-harness-antigravity/","title":"Harness Engineering #2 — Antigravity로 하니스 실전 구축하기"},{"content":"개요 인프라 장애는 책으로만 공부해서는 절대 감을 잡을 수 없다. 실제 로그를 읽고, 설정 파일의 어느 줄이 문제인지 짚어내는 경험이 반복되어야 비로소 트러블슈팅 근육이 생긴다. Infratice는 그 경험을 웹에서 바로 제공하는 Problem-based learning 플랫폼이다. Kubernetes, Linux, Network, CI/CD, Monitoring 등 실무에서 실제로 마주치는 장애 시나리오를 정적 로그와 설정 파일 형태로 제공하고, 사용자가 직접 원인을 분석해 풀이 노트를 작성하면 AI 검토용 프롬프트까지 자동으로 생성해준다.\nGitHub 저장소 kiku99/Infratice는 TypeScript로 작성되었으며 25개의 스타를 받고 있다. Next.js App Router 위에 올라간 정적 콘텐츠 기반 아키텍처가 인상적인데, 모든 문제 데이터는 Markdown 파일로 관리되어 기여하기도 쉽다. 배포는 Cloudflare Pages를 사용해 전 세계 어디서나 빠르게 접근할 수 있다.\n문제 풀이 흐름 Infratice의 학습 흐름은 단순하면서도 실무와 유사한 구조를 갖는다. 문제를 고르고, 주어진 로그와 설정 파일을 읽으며 원인을 추론하고, 풀이 노트를 직접 작성한다. 작성이 끝나면 AI 검토용 프롬프트가 생성되어 ChatGPT나 Claude 같은 도구로 피드백을 받을 수 있고, 마지막으로 모범 답안을 확인해 자신의 분석과 비교해볼 수 있다.\nflowchart TD A[\"문제 선택\u0026lt;br/\u0026gt;(카테고리별 탐색)\"] B[\"로그 / 설정 파일 분석\"] C[\"풀이 노트 작성\"] D[\"AI 검토 프롬프트 생성\"] E[\"모범 답안 확인\"] F[\"다음 문제 도전\"] A --\u003e B B --\u003e C C --\u003e D D --\u003e E E --\u003e F F --\u003e A style A fill:#3b82f6,color:#fff style D fill:#8b5cf6,color:#fff style E fill:#10b981,color:#fff이 흐름에서 핵심은 AI 검토 프롬프트 생성 단계다. 단순히 정답을 보여주는 대신, 사용자의 풀이를 바탕으로 AI가 피드백할 수 있는 프롬프트를 자동으로 조합해준다. 덕분에 틀린 부분을 스스로 발견하고 교정하는 능동적 학습이 가능하다. 모범 답안은 그 이후에 제공되므로, 풀이 과정 자체에 집중하게 된다.\n카테고리와 예제 문제 현재 제공되는 문제 카테고리는 다섯 가지다: Linux, Kubernetes, Network, CI/CD, Monitoring. 각 문제는 content/problems/{category}/{NNN}-{description}.md 형식의 Markdown 파일로 저장되어 있어, 누구나 PR을 통해 새 시나리오를 추가할 수 있다.\n대표적인 예제 문제 두 가지를 살펴보면:\nKubernetes — ImagePullBackOff: Pod 이벤트 로그와 kubectl describe 출력을 읽고, 이미지 태그 오타인지 레지스트리 인증 문제인지 구분하는 시나리오. 실무에서 아주 흔하게 마주치는 장애 유형이다. CI/CD — GitHub Actions 빌드 실패: workflow.yml 설정과 Actions 로그를 분석해 환경 변수 누락, 캐시 충돌, runner 버전 불일치 등 다양한 원인을 탐색하는 문제. 두 문제 모두 실제 운영 환경에서 발생하는 패턴을 그대로 재현하고 있어, 처음 접하는 사람이라면 \u0026ldquo;이런 상황을 어디서 봤는데\u0026hellip;\u0026rdquo; 하는 데자뷰가 느껴질 것이다.\n기술 스택 및 아키텍처 Infratice는 Next.js App Router를 기반으로 하며, 문제 콘텐츠는 Markdown 파일로 관리된다. 코드 하이라이팅에는 Shiki를 사용해 로그와 설정 파일의 가독성을 높인다. 스타일링은 Tailwind CSS v4, 배포는 Cloudflare Pages를 사용한다.\nflowchart LR subgraph content [\"Content Layer\"] MD[\"Markdown Files\u0026lt;br/\u0026gt;(problems/)\"] end subgraph app [\"Next.js App Router\"] FS[\"File System\u0026lt;br/\u0026gt;Reader\"] SHIKI[\"Shiki\u0026lt;br/\u0026gt;Code Highlight\"] PROMPT[\"AI Prompt\u0026lt;br/\u0026gt;Generator\"] end subgraph deploy [\"Deploy\"] CF[\"Cloudflare Pages\"] end MD --\u003e FS FS --\u003e SHIKI FS --\u003e PROMPT SHIKI --\u003e CF PROMPT --\u003e CF style content fill:#1e293b,color:#94a3b8 style app fill:#1e3a5f,color:#93c5fd style deploy fill:#1a2e1a,color:#86efac콘텐츠를 Markdown으로 분리한 선택이 돋보인다. Next.js 앱은 빌드 시 Markdown 파일을 읽어 정적 페이지를 생성하므로, 서버 없이 Cloudflare Pages의 엣지 네트워크에서 모든 것이 처리된다. 새로운 문제를 추가하려면 Markdown 파일 하나만 작성해 PR을 올리면 된다 — 데이터베이스도, API도 필요 없다.\nShiki는 서버 사이드에서 토큰화가 완료되어 클라이언트 자바스크립트 없이도 정확한 문법 강조가 가능하다. 로그 파일이나 YAML 설정 같은 구조적 텍스트를 읽기 좋게 렌더링하는 데 적합한 선택이다.\n함께 살펴볼 것들 이번에 눈에 띈 다른 저장소들도 간단히 소개한다.\nyoungwoocho02/unity-cli (57 stars, C#/Go) — Unity Editor를 CLI로 제어하는 단일 Go 바이너리 도구. MCP 없이 단독으로 사용할 수 있어 빌드 자동화나 CI 파이프라인에 바로 연결할 수 있다. softaworks/agent-toolkit — AI 코딩 에이전트를 위한 큐레이티드 스킬 컬렉션. Claude Code나 Cursor 같은 도구에서 재사용 가능한 스킬을 체계적으로 정리한 저장소다. alibaba/page-agent — 자연어로 웹 인터페이스를 제어하는 JavaScript in-page GUI 에이전트. 브라우저 안에서 직접 동작하며, 복잡한 UI 자동화를 자연어 명령으로 처리할 수 있다. 마치며 Infratice는 \u0026ldquo;로그를 읽는 능력\u0026quot;을 직접 훈련할 수 있는 보기 드문 플랫폼이다. 이론과 실습의 간극을 좁히려는 시도가 기술적으로도 깔끔하게 구현되어 있다. Markdown 기반 콘텐츠 관리 덕분에 커뮤니티 기여도 열려 있으니, 본인이 겪었던 실무 장애 시나리오를 문제로 만들어 기여해보는 것도 좋은 방법이다.\n인프라 트러블슈팅에 익숙해지고 싶다면 infratice.co.kr에서 직접 문제를 풀어보길 권한다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-infratice-devops/cover.jpg","permalink":"/ko/posts/2026-03-17-infratice-devops/","title":"Infratice — 실무 인프라 장애를 로그로 풀어보는 DevOps 트러블슈팅 플랫폼"},{"content":"개요 log-blog는 Chrome 브라우징 히스토리를 Hugo 블로그 포스트로 변환하는 Python CLI 도구다. 오늘은 두 가지 큰 축으로 작업했다. 첫째, AI 채팅 URL 분류와 Gemini share link 추출 기능을 개선했고, 둘째, Claude Code CLI 세션 데이터를 파싱해서 개발 로그 블로그 포스트를 자동 생성하는 sessions 커맨드를 새로 만들었다. 총 4개의 세션에 걸쳐 약 5시간 동안 13개의 커밋이 생성됐다.\nAI 채팅 추출 개선 — AI_LANDING 노이즈 필터 배경 Chrome 히스토리에서 AI 서비스 URL을 추출할 때, 실제 대화 페이지와 단순 랜딩/로그인 페이지가 섞여 나오는 문제가 있었다. 두 개의 Chrome 프로필에서 3,575개의 URL 중 96개가 AI 서비스 URL이었는데, 대부분이 claude.ai/oauth/*, chatgpt.com/ (랜딩), gemini.google.com/app (ID 없음) 같은 노이즈였다.\n진단 결과:\nClaude: claude.ai/code/* (Claude Code 세션) URL이 대부분이고, claude.ai/chat/{uuid} 패턴은 0개 ChatGPT: 대화 URL 1개, 나머지는 랜딩 페이지 Gemini: gemini.google.com/app/{id} 대화는 매칭되지만 gemini.google.com/share/{id} (공유 링크)가 누락 Perplexity: 히스토리에 URL 자체가 없음 구현 UrlType enum에 AI_LANDING을 추가하고, 대화 패턴 매칭 이전에 노이즈 필터를 실행하는 구조로 변경했다.\nclass UrlType(str, Enum): # ... 기존 타입 ... AI_LANDING = \u0026#34;ai_landing\u0026#34; # 노이즈: 랜딩/OAuth/설정 페이지 노이즈 패턴 예시:\n_AI_NOISE_PATTERNS = [ re.compile(r\u0026#34;claude\\.ai/(?:oauth|chrome|code(?:/(?:onboarding|family))?)?(?:[?#]|$)\u0026#34;), re.compile(r\u0026#34;chatgpt\\.com/?(?:[?#]|$)\u0026#34;), re.compile(r\u0026#34;gemini\\.google\\.com/(?:app)?(?:/download)?(?:[?#]|$)\u0026#34;), # ... ] content_fetcher.py에서는 AI_LANDING URL을 fetch 시도 없이 즉시 스킵하도록 early-return을 추가했다. 이렇게 하면 Playwright 슬롯을 로그인 벽에 낭비하지 않는다.\nextract --json 출력에 url_type 필드를 포함시켜서, 스킬의 Step 2 분류가 Claude의 추측이 아닌 동일한 regex 엔진을 사용하도록 개선했다.\n결과: 34개의 AI 채팅 대화가 정상 분류되고, 32개의 노이즈 URL이 필터링됐다.\nGemini Share Link 지원 gemini.google.com/share/{id} 패턴을 Gemini 분류 regex에 추가하고, ai_chat_fetcher.py에 _extract_gemini_share() 전용 추출기를 구현했다. 공유 링크는 인증 없이 접근 가능하므로 CDP 연결 없이 일반 Playwright로 처리한다.\nYouTube Fetcher 수정 — API 브레이킹 체인지 대응 배경 블로그 포스트 작성 중 YouTube 트랜스크립트 fetch가 실패했다:\nAttributeError: type object \u0026#39;YouTubeTranscriptApi\u0026#39; has no attribute \u0026#39;list_transcripts\u0026#39; 원인은 youtube-transcript-api 라이브러리가 v1.x로 업데이트되면서 클래스 메서드에서 인스턴스 메서드로 변경된 것이다.\nv0.x (기존) v1.x (신규) YouTubeTranscriptApi.list_transcripts(video_id) YouTubeTranscriptApi().list(video_id) YouTubeTranscriptApi.get_transcript(video_id) YouTubeTranscriptApi().fetch(video_id) 구현 youtube_fetcher.py를 전면 리라이트했다:\ndef _get_transcript(video_id: str): from youtube_transcript_api import YouTubeTranscriptApi api = YouTubeTranscriptApi() try: return api.fetch(video_id, languages=[\u0026#34;ko\u0026#34;, \u0026#34;en\u0026#34;]) except Exception: pass try: transcript_list = api.list(video_id) for transcript in transcript_list: try: return transcript.fetch() except Exception: continue except Exception: pass return None 추가로 YouTube oEmbed API를 활용해 트랜스크립트 없이도 비디오 메타데이터(제목, 채널명, 썸네일)를 가져올 수 있게 했다. API 키 없이 urllib.request만으로 동작하는 zero-dependency 방식이다:\n_OEMBED_URL = \u0026#34;https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}\u0026amp;format=json\u0026#34; 3단계 fallback 체계:\n트랜스크립트 + oEmbed 메타데이터 (최상) oEmbed 메타데이터만 (트랜스크립트 불가 시) Playwright 스크래핑 (모든 것 실패 시) Sessions 커맨드 — Claude Code 세션에서 개발 로그 추출 배경 매일 20~40개의 Claude Code CLI 세션을 여러 프로젝트(GitHub + Bitbucket)에 걸쳐 사용하고 있다. 이 세션들에는 디버깅 과정, 아키텍처 결정, 코드 변경 등 풍부한 개발 내러티브가 담겨 있는데, 이를 블로그 포스트로 활용할 방법이 없었다. Chrome 히스토리 기반 파이프라인은 \u0026ldquo;무엇을 봤는가\u0026quot;는 알려주지만 \u0026ldquo;무엇을 만들었는가\u0026quot;는 알려주지 못한다.\n데이터 흐름 flowchart TD A[\"~/.claude/projects/\u0026lt;br/\u0026gt;*.jsonl 세션 파일\"] --\u003e B[\"session_parser.py\u0026lt;br/\u0026gt;JSONL 파싱 + 필터링\"] C[\"git log\u0026lt;br/\u0026gt;프로젝트별 커밋\"] --\u003e B B --\u003e D[\"sessions CLI 커맨드\u0026lt;br/\u0026gt;--project --json\"] D --\u003e E[\"구조화된 JSON 출력\"] E --\u003e F[\"Claude Code Skill\u0026lt;br/\u0026gt;Dev Log Mode\"] F --\u003e G[\"Hugo 블로그 포스트\u0026lt;br/\u0026gt;narrative dev log\"] G --\u003e H[\"log-blog publish\"]프로젝트 자동 발견 Claude Code는 세션 파일을 ~/.claude/projects/ 하위에 프로젝트 경로를 인코딩한 디렉토리명으로 저장한다:\n-Users-lsr-Documents-github-trading-agent/ ├── f08f2420-0442-475f-a1f8-3691da54eb9d.jsonl ├── 30de43c5-8bc2-48d0-86df-c1a6a3f7f6ee.jsonl └── ... 문제는 디렉토리 이름 자체에 하이픈이 포함될 수 있다는 점이다. 예를 들어 hybrid-image-search-demo라는 레포의 경로에서 어디까지가 경로 구분자이고 어디부터가 디렉토리 이름인지 알 수 없다.\nGreedy filesystem matching 알고리즘으로 해결했다:\ndef _reverse_map_path(dirname: str) -\u0026gt; Path | None: # Worktree 접미사 제거 if _WORKTREE_SEPARATOR in dirname: dirname = dirname.split(_WORKTREE_SEPARATOR)[0] raw = \u0026#34;/\u0026#34; + dirname[1:] # 선행 \u0026#39;-\u0026#39;를 \u0026#39;/\u0026#39;로 segments = raw.split(\u0026#34;-\u0026#34;) result_parts: list[str] = [] i = 0 while i \u0026lt; len(segments): matched = False for j in range(len(segments), i, -1): candidate = \u0026#34;-\u0026#34;.join(segments[i:j]) test_path = \u0026#34;/\u0026#34;.join(result_parts + [candidate]) if os.path.exists(test_path): result_parts.append(candidate) i = j matched = True break if not matched: result_parts.append(segments[i]) i += 1 path = Path(\u0026#34;/\u0026#34;.join(result_parts)) return path if path.exists() else None 가장 긴 매칭을 우선 시도하므로, /Users/lsr/Documents/bitbucket/hybrid-image-search-demo처럼 하이픈이 포함된 디렉토리도 정확히 역매핑된다.\nJSONL 파싱 — 스마트 필터링 Claude Code의 JSONL 파일에는 user, assistant, system, progress 등 다양한 타입의 메시지가 있다. 모든 것을 포함하면 노이즈가 너무 많고, 핵심만 추출해야 한다.\n메시지 타입 포함 여부 추출 대상 사용자 텍스트 O 전체 텍스트 (내러티브 뼈대) 어시스턴트 텍스트 O 최대 1,500자 (결정/설명) Edit/Write 도구 호출 O 파일 경로 + diff 내용 Bash 에러 O 커맨드 + stderr Bash 성공 요약만 커맨드만 기록 WebFetch/WebSearch 요약만 URL/쿼리만 기록 Agent 서브태스크 요약만 위임 설명 + 결과 요약 Read/Grep/Glob X 탐색 노이즈 thinking 블록 X 내부 추론, 노이즈 세션별 최대 100개 항목, 2분 미만 또는 3개 미만 메시지의 세션은 기본 제외(--include-short로 포함 가능)한다.\nCLI 사용법 # 프로젝트 목록 조회 uv run log-blog sessions --list # 특정 프로젝트의 상세 세션 데이터 (JSON) uv run log-blog sessions --project log-blog --all --json # 전체 데이터 (짧은 세션 포함) uv run log-blog sessions --all --include-short --json 출력 JSON은 sessions, git_commits, files_changed 세 가지 핵심 데이터를 포함하며, Claude Code 스킬의 \u0026ldquo;Dev Log Mode\u0026quot;에서 이를 읽어 내러티브 개발 로그 포스트를 작성한다.\n스킬 업데이트 — Dev Log Mode 추가 SKILL.md에 \u0026ldquo;Dev Log Mode\u0026rdquo; 섹션을 추가했다. 사용자가 \u0026ldquo;오늘 뭐 했는지 정리해줘\u0026rdquo;, \u0026ldquo;dev log 작성해줘\u0026rdquo; 등을 요청하면 Chrome 히스토리 대신 세션 데이터 기반 플로우를 탄다.\n기존 워크플로우와의 차이:\n항목 Chrome 히스토리 모드 Dev Log 모드 데이터 소스 Chrome SQLite DB Claude Code JSONL + git log 콘텐츠 성격 \u0026ldquo;무엇을 봤는가\u0026rdquo; \u0026ldquo;무엇을 만들었는가\u0026rdquo; 포스트 스타일 주제별 기술 분석 문제 → 해결 내러티브 Fetch 필요 URL별 Playwright/API 불필요 (세션 데이터에 포함) 커밋 로그 메시지 변경 파일 docs: add design spec for AI chat extraction improvement specs docs: fix stale references in AI chat extraction spec specs docs: add implementation plan for AI chat extraction improvement plans chore: add pytest dev dependency pyproject.toml, uv.lock feat: add AI_LANDING noise filter and Gemini share link support url_classifier.py, tests feat: add url_type to extract \u0026ndash;json and filter AI_LANDING noise cli.py, tests feat: skip AI_LANDING URLs in content fetcher content_fetcher.py feat: add Gemini share link content extraction ai_chat_fetcher.py docs: update skill to use url_type from extract output SKILL.md docs: add session-to-devlog feature design spec specs docs: update session-devlog spec with review fixes specs docs: add session-devlog implementation plan plans feat: add sessions command for Claude Code dev log extraction cli.py, config.py, session_parser.py 인사이트 하루 동안 두 가지 방향의 작업이 하나의 목표로 수렴했다. AI 채팅 URL 분류 개선은 \u0026ldquo;외부에서 본 것\u0026quot;을 더 정확히 캡처하는 일이고, sessions 커맨드는 \u0026ldquo;내부에서 한 것\u0026quot;을 캡처하는 일이다. 둘이 합쳐져서 log-blog가 \u0026ldquo;브라우징 로그 도구\u0026quot;에서 \u0026ldquo;개발 활동 전체를 기록하는 도구\u0026quot;로 진화하는 기반이 됐다.\nGreedy filesystem matching 알고리즘은 단순하지만 효과적이다. 하이픈이 포함된 디렉토리명을 역매핑하는 문제는 정규식만으로는 해결할 수 없고, 실제 파일시스템을 탐색하는 것이 가장 확실한 방법이었다. Claude Code의 프로젝트 디렉토리 인코딩이 손실적(lossy)이라는 점을 받아들이고, 런타임에 검증하는 접근이 핵심이다.\nyoutube-transcript-api v1.x 브레이킹 체인지는 라이브러리 의존성 관리의 중요성을 다시 한번 상기시켜 줬다. oEmbed API를 fallback으로 추가한 것은 \u0026ldquo;트랜스크립트가 없어도 메타데이터라도 가져오자\u0026quot;는 graceful degradation 원칙의 적용이다. 결과적으로 3단계 fallback 체계(트랜스크립트 + oEmbed, oEmbed만, Playwright)가 완성됐고, 각 단계에서 가능한 최대한의 정보를 확보한다.\nspec-design-plan-implement 워크플로우(brainstorm → writing-plans → subagent-driven-development)의 효과가 체감된다. AI 채팅 개선은 설계부터 구현까지 7개 태스크를 서브에이전트가 병렬로 처리했고, 스펙 리뷰 루프가 3번 반복되면서 AI_CHAT_CLAUDE_CODE 같은 불필요한 타입이 제거되는 등 설계 품질이 실제로 향상됐다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-log-blog-sessions/cover.jpg","permalink":"/ko/posts/2026-03-17-log-blog-sessions/","title":"log-blog 개발기 — Claude Code 세션에서 개발 로그 자동 추출하기"},{"content":"MEGA Code는 Claude Code 세션을 학습 자료로 변환하는 VS Code 확장이다. 23개 언어를 지원하지만 번역 커버리지가 들쭉날쭉한 상태였다 — 한국어 약 90%, 나머지 대부분 20~30%. 매번 수동으로 빠진 키를 찾고 번역하는 과정이 반복되다 보니 자동화가 절실했다.\n이번 개발 세션에서는 i18n 워크플로를 자동화하는 두 가지 Claude Code 커맨드(/i18n-audit, /i18n-fill)를 설계하고 구현했다. 그 과정에서 발견한 Node.js 오버레이 레이스 컨디션과 ChatService PATH 불일치 버그도 함께 수정했다.\ni18n 자동화 커맨드 설계 문제 인식 기존 i18n 작업 세션의 가장 큰 문제점은 세 가지였다:\nClaude가 파일을 읽지 않고 내용을 가정하는 패턴 누락된 키를 빠뜨리는 불완전한 감사 파일 편집 실패의 반복 이 마찰을 해결하기 위해 Two-Phase 접근법을 채택했다 — 먼저 감사(audit)로 현황을 파악하고, 그 다음 채움(fill)으로 번역을 삽입하는 구조다.\n/i18n-audit — 읽기 전용 번역 감사 .claude/commands/i18n-audit.md에 작성된 이 커맨드는 en.ts를 기준으로 22개 언어 파일의 누락 키를 스캔한다. 핵심 규칙은 단순하다 — 반드시 파일을 읽은 뒤 분석할 것.\n출력 형식은 markdown 테이블이다:\n| Language | File | Total | Present | Missing | Coverage | |----------|---------|-------|---------|---------|----------| | Korean | ko.ts | N | ... | ... | ...% | | Japanese | ja.ts | N | ... | ... | ...% | 키 수는 런타임에 en.ts에서 동적으로 카운트한다. 282개라고 하드코딩하면 기능 추가 때마다 깨지기 때문이다.\n/i18n-fill — AI 번역 자동 채움 감사 결과를 바탕으로 실제 번역을 삽입하는 커맨드다. 선택적으로 언어를 지정할 수 있다:\n/i18n-fill # 22개 전체 /i18n-fill ko ja # 한국어, 일본어만 번역 시 지켜야 할 guardrail이 명확하게 프롬프트에 포함되어 있다:\n{param} 인터폴레이션 플레이스홀더 보존 HTML 태그의 속성(href, class 등)은 그대로, 보이는 텍스트만 번역 기존 번역의 톤과 존댓말 수준 맞추기 id.ts처럼 export 이름이 특수한 경우(id_) 그대로 유지 flowchart TD A[\"사용자가 /i18n-audit 실행\"] --\u003e B[\"en.ts 읽기\u0026lt;br/\u0026gt;전체 키 추출\"] B --\u003e C[\"22개 언어 파일 순차 스캔\"] C --\u003e D{\"누락 키 발견?\"} D -- Yes --\u003e E[\"커버리지 테이블\u0026lt;br/\u0026gt;+ 누락 키 목록 출력\"] D -- No --\u003e F[\"100% 커버리지 보고\"] E --\u003e G[\"사용자가 /i18n-fill 실행\"] G --\u003e H[\"대상 언어 파일 읽기\"] H --\u003e I[\"누락 키의 영어 값을\u0026lt;br/\u0026gt;대상 언어로 AI 번역\"] I --\u003e J[\"번역된 키-값 삽입\u0026lt;br/\u0026gt;섹션 위치 유지\"] J --\u003e K[\"npm run compile\u0026lt;br/\u0026gt;타입 체크\"] K --\u003e L[\"결과 요약 테이블 출력\"]설계 과정에서의 주요 결정 스펙 리뷰에서 5가지 중요한 피드백이 나왔다:\n인도네시아어 export 이름 문제 — id.ts는 id가 아닌 id_로 export한다. JavaScript 예약어 충돌 때문이다. 하드코딩된 키 수 — \u0026ldquo;282개\u0026quot;를 런타임 카운트로 변경 키 삽입 위치 — 파일 끝에 몰아넣지 않고 en.ts의 섹션 구조에 맞춰 삽입 HTML 태그 보존 — 번역 대상은 태그 내부의 텍스트만 extra key 처리 — en.ts에 없지만 언어 파일에 있는 키는 절대 삭제하지 않음 버그 수정: Node.js 오버레이 레이스 컨디션 증상 Node.js가 설치되어 있지 않은데도 \u0026ldquo;Node.js missing\u0026rdquo; 경고 배너가 보이지 않는 현상. 사용자 입장에서는 모든 것이 정상인 것처럼 보인다.\n원인 분석 오버레이 상태 전달 구조를 추적한 결과, push-only 설계의 빈틈 4개를 발견했다:\nGap 1: 초기 로드 레이스 컨디션 — node-overlay HTML이 class=\u0026quot;hidden\u0026quot;으로 시작하지만 updateNodeUI()는 node:statusUpdate 메시지가 도착해야만 실행된다. 메시지가 리스너 등록 전에 도착하면 영원히 hidden 상태로 남는다.\nGap 2: onDidChangeVisibility가 node 상태를 무시 — 패널을 숨겼다 다시 열 때 sendAuthStatus()만 재전송하고 node 상태는 복구 경로가 없다.\nGap 3: sendNodeStatus가 visibility를 체크하지 않음 — 패널이 숨겨진 상태에서 보낸 메시지가 소실된다.\n수정 내용 auth 시스템이 이미 사용하고 있던 Push + Pull + Pending 트리플 안전 패턴을 node 상태에도 적용했다:\n// dashboard-provider.ts — 새로 추가된 필드 private pendingNodeUpdate = false; private lastNodeAvailable: boolean | null = null; // sendNodeStatus — visibility 체크 추가 public sendNodeStatus(available: boolean): void { this.lastNodeAvailable = available; if (!this.view) return; if (!this.view.visible) { this.pendingNodeUpdate = true; return; } this.view.webview.postMessage({ type: \u0026#39;node:statusUpdate\u0026#39;, data: { available }, }); } Webview 측에서는 DOMContentLoaded와 agent zone 전환 시 node:requestStatus를 요청하도록 추가했다:\n// card-scripts-init.ts — DOMContentLoaded에 추가 vscode.postMessage({ type: \u0026#39;node:requestStatus\u0026#39; }); vscode.postMessage({ type: \u0026#39;auth:requestStatus\u0026#39; }); // card-scripts-tabs.ts — zone 전환 시 추가 if (zone === \u0026#39;agent\u0026#39;) { vscode.postMessage({ type: \u0026#39;node:requestStatus\u0026#39; }); vscode.postMessage({ type: \u0026#39;auth:requestStatus\u0026#39; }); } 수정 파일 3개: dashboard-provider.ts, card-scripts-init.ts, card-scripts-tabs.ts.\n버그 수정: ChatService PATH 불일치 증상 Claude CLI가 터미널에서 정상 작동하는데도 Q\u0026amp;A 패널에서 \u0026ldquo;Error: Claude CLI not found\u0026quot;가 표시되는 현상.\n원인 ClaudeCliChecker.isAvailable()과 ChatService.runClaude()가 서로 다른 PATH를 사용하고 있었다:\n// ClaudeCliChecker — 확장 PATH 사용 (OK) const env = { ...process.env, PATH: buildExtendedPath() }; execFile(\u0026#39;claude\u0026#39;, [\u0026#39;--version\u0026#39;], { timeout: 5000, env }, ...); // ChatService — 기본 PATH 사용 (BUG) const proc = spawn(\u0026#39;claude\u0026#39;, args, { timeout: DEFAULT_CHAT_TIMEOUT_MS, stdio: [\u0026#39;pipe\u0026#39;, \u0026#39;pipe\u0026#39;, \u0026#39;pipe\u0026#39;], // env 없음! VS Code 기본 PATH만 사용 }); ClaudeCliChecker는 /opt/homebrew/bin 등을 포함한 확장 PATH로 claude를 찾아 \u0026ldquo;사용 가능\u0026quot;이라고 판정하지만, 실제로 ChatService가 spawn할 때는 그 경로가 없어서 ENOENT가 발생했다.\n수정 buildExtendedPath()를 공유 유틸리티로 추출하고 세 곳에서 동일하게 사용하도록 통합했다:\n// src/dependency/extended-path.ts (새 파일) export function buildExtendedPath(): string { const home = os.homedir(); const extra: string[] = []; if (process.platform !== \u0026#39;win32\u0026#39;) { extra.push( \u0026#39;/usr/local/bin\u0026#39;, \u0026#39;/opt/homebrew/bin\u0026#39;, path.join(home, \u0026#39;.local/bin\u0026#39;), path.join(home, \u0026#39;.claude/bin\u0026#39;), path.join(home, \u0026#39;.nvm/versions/node\u0026#39;), path.join(home, \u0026#39;.local/share/fnm\u0026#39;), path.join(home, \u0026#39;.volta/bin\u0026#39;), path.join(home, \u0026#39;.nodenv/shims\u0026#39;), \u0026#39;/usr/bin\u0026#39;, ); } const current = process.env.PATH || \u0026#39;\u0026#39;; return [...extra, current].join(path.delimiter); } 기존에 node-checker.ts와 claude-cli-checker.ts가 각각 자체 buildExtendedPath()를 갖고 있었는데, 이미 드리프트가 발생해 node-checker는 7개 경로, cli-checker는 4개 경로만 포함하고 있었다. 통합으로 잠재 버그까지 함께 해결했다.\n수정 파일 4개: extended-path.ts(신규), claude-cli-checker.ts, node-checker.ts, chat-service.ts.\n기타 작업 /explain-code 스킬 설계 — 바이브 코더(코드 구조를 모르는 사용자)를 위한 코드 투어 스킬. /mend-logic이나 /mend-ui를 사용하기 전에 코드 구조를 이해할 수 있도록 \u0026ldquo;Bird\u0026rsquo;s Eye → Room by Room → Glossary\u0026rdquo; 3단계로 설명한다. 문서 구조 정리 — developer README를 docs/로 이동, walkthrough 문서 제거 버전 0.1.1 릴리스 — README에 \u0026ldquo;Reliability Improvements\u0026rdquo; 섹션 추가 커밋 로그 메시지 변경 파일 fix(webview): add pull-based recovery for Node.js overlay status dashboard-provider.ts, card-scripts-init.ts, card-scripts-tabs.ts fix(chat): unify PATH resolution so ChatService finds Claude CLI chat-service.ts, claude-cli-checker.ts, extended-path.ts, node-checker.ts docs: restructure \u0026ndash; move developer README to docs/ README-for-developers.md 외 다수 chore: bump version to 0.1.1 package.json, package-lock.json docs: add bug reports, specs, and implementation plans 6개 문서 파일 docs: add i18n commands design spec i18n-commands-design.md docs: address spec review feedback for i18n commands i18n-commands-design.md docs: add i18n commands implementation plan i18n-commands-plan.md feat: add /i18n-audit command for translation key auditing i18n-audit.md feat: add /i18n-fill command for AI-powered translation gap filling i18n-fill.md chore: allow .claude/commands/ to be tracked in git .gitignore 인사이트 Push-only 메시징은 반드시 깨진다 VS Code webview와 extension host 사이의 메시지 전달은 비동기다. push-only 방식은 타이밍에 따라 메시지가 유실될 수 있다. auth 시스템은 이미 Pull + Pending 패턴을 갖추고 있었지만, 같은 프로젝트 내에서 node 상태는 빠져 있었다. 한 시스템에서 해결한 패턴은 동일한 제약을 가진 다른 시스템에도 적용해야 한다.\nPATH 불일치는 \u0026ldquo;체크는 통과하지만 실행은 실패\u0026quot;를 만든다 의존성 체크와 실제 사용이 서로 다른 환경(PATH)에서 동작하면, 체크 결과가 무의미해진다. 특히 VS Code extension host의 PATH는 시스템 셸과 다를 수 있다는 점을 항상 염두에 둬야 한다. buildExtendedPath()를 공유 유틸리티로 추출한 것은 단순한 DRY가 아니라 정합성 보장이다.\ni18n 자동화에서 가장 중요한 규칙: \u0026ldquo;반드시 읽고 나서 분석하라\u0026rdquo; Claude가 파일 내용을 가정하고 분석하는 것이 i18n 세션에서 가장 큰 마찰이었다. /i18n-audit와 /i18n-fill 프롬프트 모두 첫 번째 규칙으로 \u0026ldquo;ALWAYS read a file before editing it\u0026quot;을 명시하고 있다. AI 도구의 프롬프트 설계에서 가장 흔한 실패 모드를 첫 번째 규칙으로 막는 것이 효과적이다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-megaupskill-i18n/cover.jpg","permalink":"/ko/posts/2026-03-17-megaupskill-i18n/","title":"MegaUpskill 개발기 — i18n 자동 감사와 번역 채움 커맨드 구현"},{"content":"개요 이미지의 스타일을 다른 이미지에 입히는 기술은 2015년 Gatys et al.의 논문 이후 놀라운 속도로 발전해왔다. 초기에는 VGG19 네트워크를 이용한 느린 최적화 방식이 전부였지만, 이제는 Stable Diffusion 기반의 실시간 스타일 트랜스퍼를 거쳐 포즈 기반 가상 인간 비디오 생성까지 가능한 시대가 됐다. 이번 글에서는 각 시대를 대표하는 세 가지 오픈소스 프로젝트를 살펴보며, 기술이 어떤 방향으로 진화했는지 정리해본다.\n세 프로젝트는 접근 방식이 완전히 다르다. nazianafis/Neural-Style-Transfer는 고전적인 최적화 기반 방식으로 원리를 이해하기 좋고, philz1337x/style-transfer는 Stable Diffusion 생태계를 활용해 훨씬 빠르고 정교한 결과를 낸다. 마지막으로 텐센트 뮤직의 TMElyralab/MusePose는 스타일 트랜스퍼의 개념을 확장해, 포즈 정보를 기반으로 정지 이미지를 춤추는 비디오로 변환한다.\n세 가지 접근법의 스펙트럼 아래 다이어그램은 세 기술이 어떤 축으로 구분되는지를 보여준다.\nflowchart LR A[\"고전 NST\u0026lt;br/\u0026gt;VGG19 + L-BFGS\u0026lt;br/\u0026gt;(최적화 기반)\"] B[\"현대 스타일 트랜스퍼\u0026lt;br/\u0026gt;SD + ControlNet\u0026lt;br/\u0026gt;+ IP-Adapter\"] C[\"포즈 기반 비디오\u0026lt;br/\u0026gt;Diffusion + Pose Align\u0026lt;br/\u0026gt;(영상 생성)\"] A --\u003e|\"속도·품질 향상\"| B B --\u003e|\"시간 차원 확장\"| C style A fill:#f0e6ff,stroke:#9b59b6 style B fill:#e6f0ff,stroke:#2980b9 style C fill:#e6fff0,stroke:#27ae60 고전 NST: 단일 이미지 한 쌍에 대해 수백 번 역전파를 반복하는 최적화 프로세스. 원리가 명확하고 구현이 단순하지만 속도가 느리다. 현대 스타일 트랜스퍼: Stable Diffusion의 latent space를 활용해 구조 보존(ControlNet Canny)과 스타일 주입(IP-Adapter)을 분리 처리한다. 속도와 품질이 크게 향상됐다. 포즈 기반 비디오 생성: 스타일이라는 개념을 포즈와 동작으로 확장한다. 레퍼런스 이미지의 외형을 유지하면서, 타겟 댄스 영상의 움직임을 그대로 입힌다. 1. nazianafis/Neural-Style-Transfer — 원리를 이해하는 출발점 고전 Gatys 방식의 구현 nazianafis/Neural-Style-Transfer(59 stars)는 2015년 Gatys et al.의 논문 \u0026ldquo;A Neural Algorithm of Artistic Style\u0026quot;을 PyTorch + VGG19로 구현한 교육용 프로젝트다. 코드가 간결하고 각 손실 함수의 역할이 코드에서 명확히 드러나기 때문에, Neural Style Transfer의 원리를 처음 공부하는 사람에게 이상적인 레퍼런스다.\n핵심 아이디어는 하나의 콘텐츠 이미지와 하나의 스타일 이미지를 입력으로 받아, 세 가지 손실 함수를 최소화하는 방향으로 출력 이미지를 직접 최적화하는 것이다. 신경망의 가중치는 고정하고, 픽셀 값 자체를 업데이트한다는 점이 일반적인 학습과 다르다.\n손실 함수 구조 세 가지 손실이 합산되어 최적화를 이끈다.\nContent Loss: conv4_2 레이어의 feature map 간 L2 거리. 구조와 레이아웃을 보존한다. Style Loss: conv1_1부터 conv5_1까지 다섯 레이어의 Gram matrix 간 차이. Gram matrix는 feature map 간의 채널 상관관계를 포착해 텍스처와 스타일을 표현한다. Total Variation Loss: 인접 픽셀 간 차이의 합. 노이즈를 억제하고 결과를 부드럽게 만든다. # Gram matrix 계산 예시 def gram_matrix(feature_map): b, c, h, w = feature_map.size() features = feature_map.view(b * c, h * w) gram = torch.mm(features, features.t()) return gram.div(b * c * h * w) # 전체 손실 total_loss = alpha * content_loss + beta * style_loss + gamma * tv_loss 최적화 알고리즘으로는 L-BFGS를 사용하는데, 이는 2차 미분 근사를 활용하는 준뉴턴 방법으로 Adam보다 빠르게 수렴한다. 단점은 이미지 해상도가 높아질수록 메모리 사용량이 급격히 늘고, 이미지 한 쌍당 수백 번의 forward/backward pass가 필요하다는 것이다. 실용적인 용도보다는 Gram matrix가 어떻게 스타일을 인코딩하는지, VGG 레이어 깊이에 따라 포착되는 정보가 어떻게 달라지는지를 실험하기 좋다.\n2. philz1337x/style-transfer — Stable Diffusion 기반의 실용적 스타일 트랜스퍼 ControlNet + IP-Adapter 조합 philz1337x/style-transfer(55 stars)는 고전 NST의 속도 문제를 Stable Diffusion 생태계로 해결한 프로젝트다. 핵심 아이디어는 두 가지 컴포넌트를 조합하는 것이다. ControlNet Canny로 콘텐츠 이미지의 엣지 구조를 보존하고, IP-Adapter로 스타일 이미지의 시각적 특성을 diffusion 과정에 주입한다.\nControlNet Canny: 콘텐츠 이미지에서 Canny edge map을 추출해 denoising 과정의 가이드 신호로 사용한다. 이를 통해 원본 이미지의 윤곽과 구조가 결과물에 유지된다. IP-Adapter (Image Prompt Adapter): 스타일 이미지를 CLIP image encoder로 인코딩한 뒤, cross-attention을 통해 UNet에 주입한다. 텍스트 프롬프트 없이도 이미지 자체가 스타일 가이드 역할을 한다. 두 컴포넌트를 함께 쓰면 \u0026ldquo;구조는 콘텐츠 이미지에서, 색감과 텍스처는 스타일 이미지에서\u0026quot;라는 명확한 역할 분리가 가능해진다. 고전 NST에서 가중치를 조정해가며 균형을 맞추던 작업이 훨씬 직관적으로 바뀐다.\n배포 방식 두 가지 방법으로 실행할 수 있다.\nCog (Replicate) 방식: Docker 기반 패키징 도구 cog를 이용해 Replicate 플랫폼에 배포하거나 로컬에서 컨테이너로 실행한다.\n# 로컬 실행 cog predict -i image=@content.jpg -i style_image=@style.jpg # Replicate API curl -X POST https://api.replicate.com/v1/predictions \\ -H \u0026#34;Authorization: Token $REPLICATE_API_TOKEN\u0026#34; \\ -d \u0026#39;{\u0026#34;version\u0026#34;: \u0026#34;...\u0026#34;, \u0026#34;input\u0026#34;: {\u0026#34;image\u0026#34;: \u0026#34;...\u0026#34;, \u0026#34;style_image\u0026#34;: \u0026#34;...\u0026#34;}}\u0026#39; A1111 WebUI 방식: AUTOMATIC1111의 Stable Diffusion Web UI에 ControlNet 익스텐션과 IP-Adapter를 설치하면 GUI에서 동일한 파이프라인을 사용할 수 있다. 개발자가 ClarityAI.cc에서 유료 버전도 운영하고 있으며, 이쪽은 업스케일링과 같은 추가 기능이 포함되어 있다.\n고전 NST와 비교하면 결과물의 품질이 높고 속도도 빠르다. 특히 포토리얼리스틱한 스타일보다 예술적 스타일(수채화, 유화 등)을 적용할 때 두드러진 차이를 보인다. 모델 자체가 이미 방대한 이미지-텍스트 쌍으로 학습되어 있어, 텍스처와 색감의 표현력이 VGG19 기반 Gram matrix보다 훨씬 풍부하다.\n3. TMElyralab/MusePose — 포즈 기반 가상 인간 비디오 생성 AnimateAnyone의 실용적 구현 TMElyralab/MusePose(2,659 stars)는 텐센트 뮤직 엔터테인먼트의 Lyra Lab이 개발한 포즈 기반 이미지-투-비디오 프레임워크다. Alibaba의 AnimateAnyone 논문 아이디어를 실용적으로 구현한 Moore-AnimateAnyone을 최적화한 버전으로, Muse 시리즈(MuseV, MuseTalk, MusePose) 중 포즈 애니메이션을 담당한다.\n핵심 목표는 단 하나의 레퍼런스 인물 이미지와 댄스 비디오만으로, 그 인물이 해당 댄스를 추는 것처럼 보이는 비디오를 생성하는 것이다. 배경, 의상, 얼굴 특성은 레퍼런스 이미지에서 유지하고, 동작과 포즈는 가이드 비디오에서 가져온다.\nMusePose 파이프라인 flowchart TD A[\"레퍼런스 이미지\u0026lt;br/\u0026gt;(인물 1장)\"] B[\"가이드 댄스 비디오\u0026lt;br/\u0026gt;(DWPose 추출)\"] C[\"pose_align 알고리즘\u0026lt;br/\u0026gt;(스케일·위치 정렬)\"] D[\"ReferenceNet\u0026lt;br/\u0026gt;(SD Image Variations)\"] E[\"Denoising UNet\u0026lt;br/\u0026gt;(Temporal Attention)\"] F[\"VAE Decoder\"] G[\"생성된 비디오\"] A --\u003e D A --\u003e C B --\u003e C C --\u003e|\"정렬된 포즈 시퀀스\"| E D --\u003e|\"외형 특성\"| E E --\u003e F F --\u003e G style A fill:#fff3e0,stroke:#e67e22 style B fill:#fff3e0,stroke:#e67e22 style G fill:#e8f5e9,stroke:#27ae60pose_align — 핵심 기여 MusePose의 가장 중요한 기술적 기여는 pose_align 알고리즘이다. 레퍼런스 이미지의 인물과 가이드 비디오의 인물은 키, 체형, 카메라 거리가 다를 수 있다. 그대로 사용하면 포즈가 어색하게 맞지 않는 문제가 생긴다.\npose_align은 두 인물의 DWPose 키포인트를 기반으로 스케일, 위치, 비율을 자동으로 정렬한다. 이 전처리 단계를 거쳐야 생성 품질이 유지된다.\n# pose_align 실행 예시 python pose_align.py \\ --imgfn_refer reference_person.jpg \\ --vidfn_guide dance_video.mp4 \\ --outfn_align aligned_pose.mp4 모델 구조 ReferenceNet: Stable Diffusion Image Variations 기반. 레퍼런스 이미지의 외형 특성(의상, 얼굴 등)을 인코딩해 UNet에 공급한다. Denoising UNet: Temporal Attention 레이어가 추가된 UNet으로, 프레임 간 시간적 일관성을 유지한다. DWPose: 각 프레임에서 인체 키포인트를 추출하는 포즈 추정 모델. OpenPose보다 정확도가 높다. VAE: latent space에서 pixel space로 복원한다. 2025년 3월에 학습 코드가 공개되어 커스텀 데이터셋으로 파인튜닝도 가능해졌고, ComfyUI 워크플로우도 지원한다. 가상 패션 피팅, K-pop 아이돌 댄스 생성 등 엔터테인먼트 분야에서 활발히 활용되고 있다.\n세 프로젝트 비교 항목 Neural-Style-Transfer style-transfer MusePose 기반 기술 VGG19 + L-BFGS SD + ControlNet + IP-Adapter Diffusion + DWPose 출력 형식 이미지 이미지 비디오 속도 느림 (분 단위) 빠름 (초 단위) 느림 (영상 길이 비례) 학습 필요 없음 없음 (프리트레인 사용) 없음 (프리트레인 사용) 용도 교육·실험 실용적 스타일 적용 가상 인간·댄스 영상 GPU 요구 낮음 중간 높음 고전 NST는 GPU 없이도 CPU로 돌릴 수 있고, 중간 과정을 시각화하며 원리를 실험하기 좋다. 실제 사용 목적이라면 style-transfer가 품질 대비 진입 장벽이 낮다. MusePose는 결과가 가장 인상적이지만 그만큼 인프라 요구사항도 높다.\n마치며 세 프로젝트를 같이 보면 AI 이미지 생성 기술의 진화 경로가 선명하게 보인다. 처음에는 단순히 \u0026ldquo;한 이미지의 스타일을 다른 이미지에 입히는 것\u0026quot;에서 출발했지만, 이제는 시간 차원까지 확장되어 인물의 동작과 포즈를 자유롭게 제어할 수 있게 됐다. 공통점은 모두 딥러닝 모델이 이미 학습한 시각적 표현을 활용한다는 것이다. 고전 NST는 분류 모델(VGG19)의 feature를, 현대 방법들은 생성 모델(Stable Diffusion)의 latent space를 이용한다.\nMusePose 같은 프로젝트가 오픈소스로 공개되고 학습 코드까지 제공되면서, 가상 인간 기술의 진입 장벽은 계속 낮아지고 있다. 앞으로는 단순한 댄스 생성을 넘어 실시간 아바타 제어, 개인화된 가상 인플루언서 생성 등으로 적용 범위가 넓어질 것으로 보인다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-neural-style-transfer/cover.jpg","permalink":"/ko/posts/2026-03-17-neural-style-transfer/","title":"Neural Style Transfer에서 가상 인간까지 — AI 이미지 생성의 세 가지 접근법"},{"content":"개요 Replit이 시리즈 D에서 90억 달러 가치 평가를 받으며 4억 달러를 확보한 직후 Agent 4를 출시했다. Agent 2(2025년 2월) → Agent 3(2025년 9월) → Agent 4로 이어지는 진화에서, 이번 버전의 핵심 전환은 \u0026ldquo;코딩 에이전트\u0026quot;에서 **\u0026ldquo;크리에이티브 협업 플랫폼\u0026rdquo;**으로의 패러다임 변화다. 웹앱, 모바일앱, 랜딩 페이지, 프레젠테이션, 데이터 시각화, 심지어 애니메이션 비디오까지 — 코드를 넘어 지식 노동 전반을 다루는 방향으로 확장됐다.\nAgent 3에서 무엇이 달라졌나 Agent 3는 장시간 자율 운영에 초점을 맞췄다 — 스스로 테스트하고, 버그를 고치고, 몇 시간이든 독립적으로 돌아가는 에이전트. Agent 4는 방향을 틀었다. 순수한 자율성 대신 **\u0026ldquo;크리에이티브 제어\u0026rdquo;**를 강조한다. 에이전트가 조율과 반복 작업을 처리하되, 창의적 판단은 사람이 내리는 구조다.\n이 전환은 2026년의 지배적 트렌드 — \u0026ldquo;코딩 에이전트 → 지식 노동 에이전트\u0026rdquo; — 와 정확히 맞물린다. OpenAI의 Cowork, Notion의 Custom Agents와 같은 맥락에서 Replit도 순수 코드 생성을 넘어선 것이다.\n4가지 핵심 기둥 flowchart TD subgraph pillar1 [\"Design Freely\"] A1[\"무한 캔버스\u0026lt;br/\u0026gt;(Infinite Canvas)\"] A2[\"UI 변형 동시 생성\u0026lt;br/\u0026gt;(각각 별도 에이전트)\"] A3[\"디자인 ↔ 코드\u0026lt;br/\u0026gt;실시간 동기화\"] end subgraph pillar2 [\"Move Faster\"] B1[\"병렬 에이전트 실행\u0026lt;br/\u0026gt;(auth, DB, backend, frontend 동시)\"] B2[\"자동 태스크 분할\u0026lt;br/\u0026gt;+ 충돌 해결 서브에이전트\"] end subgraph pillar3 [\"Ship Anything\"] C1[\"웹앱 · 모바일앱\"] C2[\"프레젠테이션 · 비디오\"] C3[\"Linear · Notion · Excel 연동\"] end subgraph pillar4 [\"Build Together\"] D1[\"칸반 스타일 워크플로우\"] D2[\"동시 요청 + 지능형 시퀀싱\"] D3[\"백그라운드 실행\u0026lt;br/\u0026gt;+ 승인 게이트\"] end pillar1 --\u003e pillar2 pillar2 --\u003e pillar3 pillar3 --\u003e pillar41. Design Freely — 무한 캔버스 빌드 환경 안에 디자인 캔버스가 통합됐다. 무한 캔버스에서 자유롭게 디자인을 탐색하면서 여러 UI 변형을 동시에 생성할 수 있는데, 각 변형은 별도의 에이전트가 처리한다. 가장 인상적인 부분은 디자인과 코드가 실시간으로 동기화된다는 점이다 — 별도의 디자인-투-개발 핸드오프가 없다.\n2. Move Faster — 병렬 에이전트 Agent 4의 기술적 핵심이다. 인증, 데이터베이스, 백엔드, 프론트엔드 같은 프로젝트 구성 요소를 여러 에이전트가 동시에 처리한다. 태스크를 자동으로 작은 단위로 분할하고, 충돌이 발생하면 전용 서브에이전트가 해결한다. 순차 처리 대신 병렬 처리로 전환한 것이 \u0026ldquo;프로덕션 수준 소프트웨어 10배 빠르게\u0026quot;라는 Replit의 주장의 기반이다.\n단, 병렬 에이전트는 현재 Pro/Enterprise 티어 전용이며 Core 사용자에게는 일시적으로 제공된다.\n3. Ship Anything — 코드를 넘어서 하나의 통합 프로젝트에서 웹앱, 모바일앱, 랜딩 페이지, 프레젠테이션, 데이터 시각화, 애니메이션 비디오를 모두 만들 수 있다. Linear, Notion, Excel, Stripe 같은 외부 서비스와의 연동도 지원한다.\nReplit CEO Amjad Masad는 Agent 4가 \u0026ldquo;애플리케이션 하나를 만드는 것이 아니라 회사 전체를 만들고 유지할 수 있다\u0026quot;고 했다 — 피치 덱, 애니메이션 로고, 결제 연동까지 한 플랫폼에서 처리하겠다는 비전이다.\n4. Build Together — 칸반 워크플로우 기존의 순차적 채팅 스레드를 태스크 기반 칸반 워크플로우로 대체했다. 여러 팀원이 동시에 요청을 제출하면 에이전트가 지능형 시퀀싱으로 처리한다. 백그라운드에서 실행되다가 병합 전에 승인 게이트를 거치는 구조다.\nAgent 3 vs Agent 4 비교 항목 Agent 3 (2025.09) Agent 4 (2026.03) 핵심 철학 장시간 자율 운영 크리에이티브 협업 디자인 별도 도구 필요 무한 캔버스 내장 에이전트 실행 순차 (단일) 병렬 (다중) 작업 범위 코드 중심 앱 + 슬라이드 + 비디오 팀 워크플로우 채팅 스레드 칸반 + 승인 게이트 외부 연동 제한적 Linear, Notion, Stripe 등 가격 유료 플랜 Core 이상 (병렬은 Pro+) 빠른 링크 Replit 공식 블로그 — Introducing Agent 4 — 공식 출시 발표 Agent 4 제품 페이지 — 기능 소개 및 시작하기 AINews — Replit Agent 4: The Knowledge Work Agent — Latent Space 분석 인사이트 Agent 4에서 가장 주목할 전환은 \u0026ldquo;자율성의 후퇴\u0026quot;다. Agent 3가 \u0026ldquo;에이전트가 알아서 다 해준다\u0026quot;를 밀었다면, Agent 4는 \u0026ldquo;에이전트가 반복 작업을 처리하되 창의적 결정은 사람이 한다\u0026quot;로 방향을 틀었다. 이것은 현재 AI 코딩 도구 시장 전체에서 나타나는 패턴이다 — 완전 자율보다는 인간-AI 협업의 접점을 어디에 둘 것인가가 핵심 과제로 부상하고 있다.\n병렬 에이전트 아키텍처도 흥미롭다. 인증, DB, 백엔드, 프론트엔드를 동시에 처리하면서 충돌을 서브에이전트가 해결한다는 설계는, TradingAgents의 멀티에이전트 토론 구조와 마찬가지로 \u0026ldquo;여러 에이전트의 협업이 단일 에이전트보다 낫다\u0026quot;는 2026년의 핵심 가설을 공유한다. 다만 \u0026ldquo;10배 빠르다\u0026quot;는 주장은 실제 사용에서 검증이 필요하다 — 병렬 에이전트 간 충돌 해결 비용이 순차 처리 대비 얼마나 되는지가 관건이다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-replit-agent4/cover.jpg","permalink":"/ko/posts/2026-03-17-replit-agent4/","title":"Replit Agent 4 — 코딩 에이전트에서 크리에이티브 협업 플랫폼으로"},{"content":"개요 이전 글: 주식 트레이딩 에이전트 개발기 #2 — Expert Agent Team과 KOSPI200 데이터 삽질기\n#2에서 직접 Expert Agent Team 아키텍처를 구축하면서 느낀 것이 있다 — 멀티에이전트 토론 구조가 단일 LLM보다 훨씬 풍부한 분석을 만들어낸다는 점. 그런데 이 아이디어를 본격적으로 프레임워크화한 프로젝트가 있었다. TradingAgents는 2026년 3월 기준 32,395개 스타를 기록하고 있는 멀티에이전트 트레이딩 프레임워크로, 실제 트레이딩 펌의 조직 구조를 LLM 에이전트로 모사한다.\nTradingAgents 아키텍처 4단계 파이프라인 TradingAgents의 파이프라인은 실제 증권사 리서치팀의 의사결정 흐름을 따른다. arXiv 논문 2412.20138로 학술적 근거를 갖추고 있으며, 별도로 Trading-R1 기술 보고서도 공개됐다.\nflowchart TD subgraph analysts [\"1단계: Analyst Team\"] A1[\"Fundamentals Analyst\u0026lt;br/\u0026gt;재무제표·밸류에이션\"] A2[\"Sentiment Analyst\u0026lt;br/\u0026gt;시장 심리·소셜\"] A3[\"News Analyst\u0026lt;br/\u0026gt;뉴스·공시 분석\"] A4[\"Technical Analyst\u0026lt;br/\u0026gt;차트·지표\"] end subgraph researchers [\"2단계: Researcher Team\"] B1[\"Bullish Researcher\u0026lt;br/\u0026gt;매수 논거\"] B2[\"Bearish Researcher\u0026lt;br/\u0026gt;매도 논거\"] end A1 \u0026 A2 \u0026 A3 \u0026 A4 --\u003e B1 A1 \u0026 A2 \u0026 A3 \u0026 A4 --\u003e B2 B1 \u0026 B2 --\u003e C[\"3단계: Trader Agent\u0026lt;br/\u0026gt;포지션 결정\"] C --\u003e D[\"4단계: Risk Management\u0026lt;br/\u0026gt;+ Portfolio Manager\"] D --\u003e E[\"최종 매매 결정\"]Analyst Team은 4명의 전문 분석가로 구성된다. Fundamentals Analyst는 재무제표와 밸류에이션을, Sentiment Analyst는 시장 심리와 소셜 데이터를, News Analyst는 뉴스와 공시를, Technical Analyst는 차트 패턴과 기술적 지표를 담당한다. 각 에이전트는 독립적으로 보고서를 작성한다.\nResearcher Team은 Bullish와 Bearish 두 명의 연구원이 분석가 보고서를 바탕으로 매수·매도 논거를 구성하고 토론한다. 이 단계가 TradingAgents의 핵심 차별점이다 — 단순히 정보를 모으는 게 아니라, 상반된 시각을 의도적으로 충돌시킨다. #2에서 직접 구현한 Expert Team과 비교하면, TradingAgents는 토론 라운드를 여러 번 반복하며 합의에 도달하는 구조가 추가되었다.\nTrader Agent는 분석가·연구원 보고서를 종합해 실제 포지션 결정을 내린다. 마지막으로 Risk Management와 Portfolio Manager가 최종 승인 단계를 담당한다.\n우리 시스템과의 비교 #2에서 구축한 Expert Agent Team은 4명의 전문가 + Chief Analyst 구조였다. TradingAgents와 비교하면:\n항목 우리 시스템 (#2) TradingAgents 분석 에이전트 4명 (동일) 4명 (동일) 토론 구조 Chief Analyst 종합 Bullish vs Bearish 토론 리스크 관리 없음 Risk Management + Portfolio Manager 데이터 소스 KIS API + NAVER Finance Alpha Vantage + 뉴스 API LLM Claude API GPT-5.4, Gemini 3.1, Claude 4.6 등 한국 시장 KOSPI200 직접 지원 미지원 핵심 차이는 Bullish vs Bearish 토론 구조와 리스크 관리 레이어다. 우리 시스템은 Chief Analyst가 의견을 종합하지만, TradingAgents는 상반된 입장을 명시적으로 충돌시킨 뒤 Trader가 판단한다. 이 구조가 더 풍부한 분석을 만들어낼 수 있지만, API 호출 비용도 그만큼 증가한다.\n빠른 시작 git clone https://github.com/TauricResearch/TradingAgents.git cd TradingAgents pip install -r requirements.txt from tradingagents.graph.trading_graph import TradingAgentsGraph from tradingagents.default_config import DEFAULT_CONFIG ta = TradingAgentsGraph(debug=True, config=DEFAULT_CONFIG) _, decision = ta.propagate(\u0026#34;NVDA\u0026#34;, \u0026#34;2024-05-10\u0026#34;) print(decision) propagate() 호출 하나로 전체 파이프라인이 실행된다. 티커 심볼과 날짜만 넘기면 Analyst Team 전체가 병렬로 보고서를 작성하고, Researcher Team의 토론을 거쳐 Trader의 최종 결정이 반환된다.\nLLM 프로바이더 교체 v0.2.1에서 GPT-5.4, Gemini 3.1, Claude 4.6, Grok 4.x, Ollama를 모두 지원한다. 설정 파일에서 교체 가능:\nconfig = DEFAULT_CONFIG.copy() config[\u0026#34;llm_provider\u0026#34;] = \u0026#34;anthropic\u0026#34; config[\u0026#34;deep_think_llm\u0026#34;] = \u0026#34;claude-sonnet-4-6\u0026#34; config[\u0026#34;quick_think_llm\u0026#34;] = \u0026#34;claude-haiku-4-6\u0026#34; 특정 모델에 lock-in되지 않는다는 점이 실무 도입에서 중요한 장점이다. 우리 시스템은 Claude API에 묶여 있었는데, TradingAgents의 프로바이더 추상화 레이어를 참고할 만하다.\n실전 배포 전 고려사항 논문과 기술 보고서에서 제시하는 백테스트 결과는 인상적이다. 그러나 실전 배포 전에 몇 가지 고려사항이 있다.\nAPI 비용: 에이전트 간 토론 라운드가 많아질수록 API 비용이 급격히 증가한다. 분석 1회에 수십 번의 LLM 호출이 발생할 수 있다.\n환각 리스크: LLM은 환각(hallucination)을 일으킨다 — 특히 구체적인 수치나 날짜를 다룰 때. 사실 검증 레이어가 없으면 잘못된 정보가 투자 결정에 반영될 수 있다. 이 점에서 stock-analysis-agent의 \u0026ldquo;Blank beats wrong\u0026rdquo; 원칙이 좋은 참고가 된다.\n주문 집행 미포함: 오픈소스 프레임워크이므로 실제 주문 집행(order execution) 레이어는 별도로 구현해야 한다. 우리 시스템처럼 KIS API 연동이 필요하다.\n한국 시장 미지원: KOSPI200이나 DART 공시를 다루려면 추가 개발이 필요하다. 이 부분은 우리 시스템의 강점이다.\n다음 단계 TradingAgents의 Bullish vs Bearish 토론 구조와 리스크 관리 레이어는 우리 시스템에 도입할 가치가 있다. 특히:\nChief Analyst → 토론 구조로 전환: 단순 종합 대신 상반된 입장의 명시적 충돌 Risk Management 레이어 추가: 포트폴리오 전체 맥락에서의 리스크 체크 LLM 프로바이더 추상화: Claude 외 다른 모델도 실험할 수 있는 구조 TradingAgents 프레임워크를 직접 fork해서 KIS API와 DART 데이터를 연동하는 것도 하나의 방향이다. 기본 아키텍처는 이미 검증됐으니, 한국 시장 특화 레이어만 올리면 된다.\n빠른 링크 TauricResearch/TradingAgents — 멀티에이전트 트레이딩 프레임워크 (32K stars) arXiv 논문 2412.20138 — 학술적 근거 stock-analysis-agent 포스트 — Claude Code 기반 실전 분석 도구 (이전 포스트) #2 Expert Agent Team — 시리즈 이전 글 인사이트 TradingAgents를 살펴보면서 느낀 것은, 멀티에이전트 토론 구조의 핵심 가치가 \u0026ldquo;더 많은 정보\u0026quot;가 아니라 **\u0026ldquo;반대 의견의 구조화\u0026rdquo;**라는 점이다. Bullish와 Bearish가 동일한 데이터를 놓고 정반대의 해석을 제시하면, 투자자는 양쪽 논거를 모두 본 상태에서 판단할 수 있다. 이것은 확증 편향(confirmation bias)에 빠지기 쉬운 단일 LLM 분석의 근본적 한계를 구조적으로 극복하는 방법이다.\n32,000개 스타는 이 아이디어에 대한 커뮤니티의 공감을 보여준다. LLM 기반 금융 분석은 이미 \u0026ldquo;가능한가\u0026quot;의 단계를 넘어 \u0026ldquo;어떻게 신뢰할 수 있게 만들 것인가\u0026quot;의 단계로 진입했다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-trading-agents/cover.jpg","permalink":"/ko/posts/2026-03-17-trading-agents/","title":"주식 트레이딩 에이전트 개발기 #3 — TradingAgents: 3만 스타 멀티에이전트 트레이딩 펌 시뮬레이터"},{"content":"개요 이전 글: #3 — TradingAgents 분석에서 오픈소스 TradingAgents 레포를 분석했다. 그 과정에서 우리 에이전트에 빠진 것들이 눈에 들어왔다 — 재무제표 기반 펀더멘털 분석, 투자 신호 품질 검증, 시나리오 기반 R/R(Risk/Reward) 스코어링, 그리고 리치 리포트 출력. 이번 글에서는 이 네 가지 갭을 모두 메우는 과정을 기록한다.\n3개 세션, 총 20시간 넘게 작업했다. 37개 커밋, 25개 파일 신규 생성, 65개 파일 변경. 설계 → 스펙 리뷰 → 구현 플랜 → Subagent 기반 TDD 실행 → 머지 → 프론트엔드 디버깅 → 대시보드 리액티비티 개선까지 한 사이클을 돌았다.\n1. 갭 분석 — 우리에게 없는 것 kipeum86/stock-analysis-agent 레포와 비교하면서 정리한 기능 갭 테이블:\n기능 stock-analysis-agent 우리 trading-agent 펀더멘털 데이터 (DART API) PER, EPS, 매출 등 기술적 분석만 데이터 신뢰도 등급 A/B/C/D 검증 없음 시나리오 프레임워크 Bull/Base/Bear + 확률 없음 R/R 스코어 공식 정량적 계산 없음 비평가(Critic) 에이전트 7-item 품질 루브릭 없음 리치 HTML 리포트 KPI 타일, 차트 플레인 텍스트 반면 우리 쪽 강점은 — 실시간 주문 실행, 리스크 관리(손절/익절), 이벤트 기반 멀티 에이전트 오케스트레이션, WebSocket 푸시. 읽기 전용 리서치 툴 vs 실행 가능한 트레이딩 시스템이라는 근본적 차이가 있다.\n목표는 명확했다: A) DART 펀더멘털 연동 → B) 신호 품질 검증 (비평가 + R/R) → C) 리치 대시보드. Vertical Slice 접근법으로 한 종목이 전체 파이프라인을 관통하는 것부터 만들기로 했다.\n2. DART 재무제표 연동 DartClient 설계 금감원 전자공시시스템(DART) OpenAPI를 래핑하는 DartClient 서비스를 만들었다. 핵심 설계 결정들:\nDART_API_KEY는 선택적 — 없으면 enabled=False로 모든 필드를 grade D 처리. 이러면 confidence hard gate에서 즉시 reject되어 Claude API 비용 낭비 없이 신호가 차단된다. Corp code 캐싱 — DART는 종목코드가 아닌 8자리 고유번호를 쓴다. corpCode.xml 엔드포인트에서 전체 매핑을 받아 SQLite dart_corp_codes 테이블에 캐싱. 하루에 한 번만 갱신. 일일 재무 캐시 — 같은 종목 재무데이터를 하루 안에 중복 호출하지 않도록 dart_cache 테이블 도입. class DartClient: def __init__(self): self.enabled = bool(settings.dart_api_key) self.base_url = \u0026#34;https://opendart.fss.or.kr/api\u0026#34; async def fetch(self, stock_code: str) -\u0026gt; dict: if not self.enabled: return {\u0026#34;financials\u0026#34;: None, \u0026#34;confidence_grades\u0026#34;: { \u0026#34;dart_revenue\u0026#34;: \u0026#34;D\u0026#34;, \u0026#34;dart_operating_profit\u0026#34;: \u0026#34;D\u0026#34;, \u0026#34;dart_per\u0026#34;: \u0026#34;D\u0026#34;, \u0026#34;dart_eps\u0026#34;: \u0026#34;D\u0026#34;, }} corp_code = await self._resolve_corp_code(stock_code) # fnlttSinglAcntAll 엔드포인트로 최근 4분기 재무제표 조회 ... Confidence Grading 모든 데이터 소스에 신뢰도 등급을 매긴다:\nclass DataConfidence(Enum): A = \u0026#34;A\u0026#34; # 공시 원본, 산술 검증 완료 B = \u0026#34;B\u0026#34; # 2개 이상 소스, 5% 이내 오차 C = \u0026#34;C\u0026#34; # 단일 소스, 미검증 D = \u0026#34;D\u0026#34; # 데이터 없음 — hard gate 트리거 Hard gate: current_price, volume, dart_revenue, dart_operating_profit, dart_per 중 하나라도 grade D면 신호 생성 자체를 중단한다. \u0026ldquo;모르는 건 추측하지 않는다\u0026quot;가 원칙이다.\n3. 신호 파이프라인 — 5인 전문가 → 비평가 → R/R 게이트 기존 4인 전문가 패널(기술적, 거시경제, 심리, 리스크)에 기본적분석가를 5번째로 추가했다. DART 데이터를 주 입력으로 받아 매출 성장 추세, 영업이익률, PER/PBR 밸류에이션, 부채비율을 분석한다.\nflowchart TD A[\"KOSPI200 스크리닝\"] --\u003e B[\"차트 + 기술적 지표\"] B --\u003e C[\"DART 재무데이터 조회\"] C --\u003e D{\"Confidence\u0026lt;br/\u0026gt;Hard Gate\"} D --\u003e|\"grade D 존재\"| E[\"신호 거부\u0026lt;br/\u0026gt;(Claude 호출 없음)\"] D --\u003e|\"통과\"| F[\"5인 전문가 패널\u0026lt;br/\u0026gt;(병렬 Claude 호출)\"] F --\u003e G[\"Chief Analyst 토론\u0026lt;br/\u0026gt;Bull/Base/Bear 시나리오\"] G --\u003e H[\"R/R 스코어 계산\"] H --\u003e I[\"SignalCriticAgent\u0026lt;br/\u0026gt;5-item 루브릭\"] I --\u003e|\"통과\"| J[\"signal.generated 이벤트\"] I --\u003e|\"실패\"| K[\"1회 수정 시도\"] K --\u003e|\"재통과\"| J K --\u003e|\"재실패\"| L[\"signal.rejected\"] J --\u003e M{\"RiskManager\u0026lt;br/\u0026gt;R/R ≥ 2.0?\"} M --\u003e|\"Yes\"| N[\"자동 승인 → 주문\"] M --\u003e|\"No\"| O[\"수동 승인 대기\"]R/R 스코어링 기존 confidence: float 필드를 시나리오 기반 구조로 교체했다:\nclass Scenario(BaseModel): label: str # \u0026#34;강세\u0026#34; / \u0026#34;기본\u0026#34; / \u0026#34;약세\u0026#34; price_target: float upside_pct: float # 현재가 대비 % probability: float # 0.0–1.0, 3개 합 = 1.0 class SignalAnalysis(BaseModel): bull: Scenario base: Scenario bear: Scenario rr_score: float # (bull.upside × bull.prob + base.upside × base.prob) # / |bear.upside × bear.prob| variant_view: str # 시장 컨센서스가 놓치고 있는 포인트 def compute_rr_score(bull, base, bear) -\u0026gt; float: upside = bull.upside_pct * bull.probability + base.upside_pct * base.probability downside = abs(bear.upside_pct * bear.probability) return upside / downside if downside \u0026gt; 0 else 0.0 RiskManager의 자동 승인 게이트에 min_rr_score 조건을 추가했다. R/R ≥ 2.0이고 critic_result == \u0026quot;pass\u0026quot;일 때만 자동 승인이 가능하다.\nSignalCriticAgent 신호 생성 직후, 이벤트 발행 전에 비평가가 5개 항목을 검사한다:\n# 검사 항목 통과 조건 1 시나리오 완전성 3개 시나리오 존재, 확률 합 1.0 ±0.01 2 데이터 신뢰도 핵심 필드에 grade D 없음 3 R/R 산술 검증 계산된 R/R과 선언된 R/R이 5% 이내 4 전문가 이견 반영 최소 1인의 비주류 의견이 토론에 포함 5 Variant view 구체성 일반적 리스크 문장이 아닌 구체적 데이터 포인트 참조 항목 1-3은 프로그래밍적으로 검사(Claude 호출 없음), 4-5만 Claude 루브릭 검사를 수행한다. 실패 시 Chief에게 피드백을 주입해 1회 수정 기회를 준다. 2차 실패 시 signal.rejected로 드롭.\nChief 토론 업데이트 5인 체제에 맞춰 consensus 기준도 변경:\nbullish_count \u0026gt;= 4 → \u0026quot;우세\u0026quot; (≥80%) bullish_count == 3 → \u0026quot;과반수\u0026quot; (60%) bullish_count \u0026lt;= 2 → \u0026quot;분열\u0026quot; 4. DB 스키마 확장 signals 테이블에 7개 컬럼을 추가하고, agent_events 테이블을 새로 만들었다:\n-- 기존 DB에 ALTER TABLE로 마이그레이션 (column already exists면 무시) ALTER TABLE signals ADD COLUMN scenarios_json TEXT; ALTER TABLE signals ADD COLUMN variant_view TEXT; ALTER TABLE signals ADD COLUMN rr_score REAL; ALTER TABLE signals ADD COLUMN expert_stances_json TEXT; ALTER TABLE signals ADD COLUMN dart_fundamentals_json TEXT; ALTER TABLE signals ADD COLUMN confidence_grades_json TEXT; ALTER TABLE signals ADD COLUMN critic_result TEXT; -- 에이전트 이벤트 영속화 CREATE TABLE IF NOT EXISTS agent_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, event_type TEXT NOT NULL, agent_name TEXT, data_json TEXT, timestamp DATETIME DEFAULT (datetime(\u0026#39;now\u0026#39;)) ); risk_config 테이블에는 min_rr_score (기본값 2.0)과 require_critic_pass (기본값 true) 행을 시드했다.\n5. 대시보드 리액티비티와 ReportViewer WebSocket 기반 실시간 갱신 기존 대시보드는 마운트 시 한 번만 데이터를 가져왔다. WebSocket 이벤트가 들어와도 UI가 반응하지 않았다. 이를 개선했다:\nflowchart LR BE[\"Backend\u0026lt;br/\u0026gt;EventBus\"] --\u003e|\"WebSocket\"| WS[\"WS Connection\"] WS --\u003e DF[\"DashboardView\"] DF --\u003e|\"refreshTrigger+1\"| SP[\"SignalPanel\"] DF --\u003e|\"refreshTrigger+1\"| OH[\"OrderHistory\"] DF --\u003e|\"refreshTrigger+1\"| PC[\"PerformanceChart\"] WS --\u003e AF[\"AlertFeed\u0026lt;br/\u0026gt;(실시간 이벤트)\"] WS --\u003e RB[\"RiskAlertBanner\u0026lt;br/\u0026gt;(손절/익절 알림)\"] WS --\u003e AP[\"AgentPanel\u0026lt;br/\u0026gt;(최근 로그)\"] BE --\u003e|\"DB 영속화\"| DB[\"agent_events\u0026lt;br/\u0026gt;테이블\"] DB --\u003e|\"마운트 시 조회\"| AF핵심 변경: DashboardView에서 WS 메시지 수신 시 refreshTrigger state를 증가시키고, 각 패널 컴포넌트가 이 prop 변경을 감지해 데이터를 다시 fetch한다. RiskAlertBanner는 signal.stop_loss와 signal.take_profit 이벤트를 감지해 상단에 경고 배너를 표시한다.\nAgent Events 영속화 기존에는 에이전트 이벤트가 메모리에만 있어서 서버 재시작 시 사라졌다. event_bus.py에서 이벤트 발행 시 fire-and-forget으로 DB에 저장하고, AlertFeed 마운트 시 DB에서 최근 이벤트를 불러온 뒤 WS 실시간 이벤트와 병합한다.\nReportViewer 기존 ReportList를 완전히 교체하는 새 컴포넌트를 만들었다:\nKPI 타일 행: 총 수익률, 승률, 평균 R/R, 총 거래 수 거래 테이블: 종목별 매수/매도 내역과 수익률 신호 그리드: 시나리오 카드와 전문가 스탠스 Narrative 섹션: 마크다운 리포트 본문 백엔드에서는 report_generator.py가 summary_json을 구조화된 형태로 생성하고, reports.py 라우터의 _enrich_report()가 JSON 컬럼을 파싱해 프론트엔드에 전달한다.\n6. 삽질 기록 import type을 빠뜨리면 React가 백지가 된다 머지 후 대시보드가 완전히 하얗게 됐다. 에러 바운더리가 없어서 아무 단서도 없었다. Playwright로 브라우저 콘솔을 확인해서야 원인을 찾았다:\nUncaught SyntaxError: The requested module does not provide an export named \u0026#39;Scenario\u0026#39; TypeScript의 interface는 컴파일 타임에 지워진다. 그런데 세 컴포넌트가 모두 import { Scenario } from '../../types'로 런타임 import를 하고 있었다. 수정은 간단했다:\n// Before — runtime import of a type-only construct import { Scenario } from \u0026#39;../../types\u0026#39;; // After — properly erased at compile time import type { Scenario } from \u0026#39;../../types\u0026#39;; 세 파일(SignalCard.tsx, ScenarioChart.tsx, FundamentalsKPI.tsx) 모두 같은 패턴. Error boundary가 없는 상태에서 한 컴포넌트의 crash가 전체 페이지를 날려버리는 건 mermaid에서 한 다이어그램 오류가 전체를 숨기는 것과 같은 패턴이다.\n9시간 전? — UTC 타임스탬프 파싱 문제 대시보드의 모든 시간이 \u0026ldquo;9시간 전\u0026quot;으로 표시됐다. SQLite datetime('now')는 UTC 문자열을 Z 접미사 없이 \u0026quot;2026-03-17 01:55:01\u0026quot; 형태로 저장한다. JavaScript new Date()는 이걸 로컬 타임존으로 해석해서 KST(UTC+9) 환경에서 9시간 차이가 발생했다.\n// frontend/src/utils/time.ts — 모든 컴포넌트에서 공유하는 UTC 파서 export function parseUTC(timestamp: string): Date { const ts = timestamp.endsWith(\u0026#39;Z\u0026#39;) || timestamp.includes(\u0026#39;+\u0026#39;) ? timestamp : timestamp + \u0026#39;Z\u0026#39;; return new Date(ts); } AgentPanel, AlertFeed, OrderHistory, PerformanceChart, ReportViewer, RiskAlertBanner 6개 컴포넌트에서 new Date(timestamp)를 parseUTC(timestamp)로 일괄 교체했다.\n7. 커밋 로그 3세션에 걸친 37개 커밋 요약:\n단계 커밋 수 내용 설계 3 스펙 문서 작성, 리뷰 반영, 구현 플랜 Phase A: DART 4 DataConfidence enum, Scenario/SignalAnalysis 모델, DB 스키마, DartClient Phase B: 품질 4 Chief 토론 업데이트, SignalCriticAgent, DART+hard gate 연결, critic 루프 연결 Phase C: UI 4 R/R 게이트, signals API 확장, React 컴포넌트 3종, import type 수정 머지 1 feature branch → main (1,493줄 삽입, 25파일) 대시보드 7 설계 스펙, 구현 플랜, WS 리프레시, RiskAlertBanner, 이벤트 영속화, AgentPanel 로그 리포트 6 ReportSummary 타입, getReport API, summary_json 계산, ReportViewer, CSS, ReportList 삭제 수정 4 confidence_grades_json 파싱, Reports 탭 네비게이션, AgentPanel 레이아웃, UTC 파싱 기타 4 .gitignore, 플랜 문서, 기타 8. 인사이트 Vertical Slice가 통합 문제를 일찍 드러낸다 DART → 전문가 → Chief → Critic → R/R 게이트 → UI를 한 종목으로 먼저 관통시키니, import type 문제라든가 confidence_grades_json 누락 같은 통합 이슈가 머지 직후 바로 드러났다. 레이어별로 완성했다면 나중에 훨씬 큰 디버깅 비용이 들었을 것이다.\n비평가 에이전트의 프로그래밍적 검사가 LLM 비용을 절약한다 5개 루브릭 중 3개(시나리오 완전성, 데이터 신뢰도, R/R 산술)는 Claude 호출 없이 순수 코드로 검증한다. 나머지 2개만 LLM이 판단한다. \u0026ldquo;LLM에게 산술을 시키지 마라\u0026quot;는 원칙 — 계산은 코드가, 판단은 LLM이.\n시간 다루기는 항상 함정이다 SQLite의 datetime('now')가 Z 없이 UTC를 저장하는 건 문서화된 동작이지만, 프론트엔드에서 new Date()로 파싱할 때 로컬로 해석되는 건 매번 빠지는 함정이다. parseUTC() 유틸리티를 한 번 만들어두고 모든 컴포넌트에서 일관되게 사용하는 게 정답이었다.\n다음 할 일 Error boundary 추가 — 컴포넌트 하나의 crash가 전체 페이지를 죽이지 않도록 DART API rate limiting — 현재 단순 daily cache만 있는데, 다중 종목 동시 스캔 시 호출 제한 대응 필요 실제 마켓 스캐너 실행 후 critic rejection 비율 확인 — 루브릭이 너무 엄격하면 유용한 신호까지 차단할 수 있다 ","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-trading-agent-dev4/cover.jpg","permalink":"/ko/posts/2026-03-17-trading-agent-dev4/","title":"주식 트레이딩 에이전트 개발기 #4 — DART 연동, 신호 비평가, 실시간 대시보드"},{"content":"개요 하이브리드 이미지 검색 데모 앱에 Google OAuth 로그인을 추가했다. 기존에는 인증이 전혀 없어서 모든 API 엔드포인트가 완전히 열려 있었는데, 특히 Gemini API를 호출하는 이미지 생성 기능이 비용을 발생시키기 때문에 인증 없이 방치할 수 없었다. 이번 작업에서는 설계 문서 작성부터 스펙 리뷰, 구현 계획, 실제 코딩, 보안 리뷰까지 전 과정을 Claude Code의 superpowers 플러그인 워크플로우로 진행했다. 총 17개의 커밋으로 완전한 로그인 월(login wall)을 구현했다.\n인증 아키텍처 로그인 방식으로 Lightweight Custom Auth를 선택했다. FastAPI-Users 같은 라이브러리는 비밀번호 리셋, 이메일 인증 등 불필요한 기능이 15개 이상 딸려 오고, Authlib + Session Middleware는 서버 사이드 리다이렉트 방식이라 SPA 구조와 맞지 않았다. 직접 구현하면 코드 전체를 이해하고 디버깅할 수 있다는 장점이 있다.\n핵심 스택:\nBackend: google-auth (Google ID 토큰 검증) + python-jose (JWT 생성/검증) Frontend: @react-oauth/google (Google Sign-In 팝업 버튼) 세션: HttpOnly 쿠키에 JWT 저장 (localStorage 방식보다 XSS에 안전) 인증 플로우 sequenceDiagram participant U as User participant F as React Frontend participant G as Google OAuth participant B as FastAPI Backend participant DB as SQLite U-\u003e\u003eF: 앱 접속 F-\u003e\u003eB: GET /api/auth/me B--\u003e\u003eF: 401 Unauthorized F-\u003e\u003eU: LoginPage 표시 U-\u003e\u003eF: Google Sign-In 클릭 F-\u003e\u003eG: OAuth 팝업 G--\u003e\u003eF: ID Token 반환 F-\u003e\u003eB: POST /api/auth/google\u0026lt;br/\u0026gt;{id_token} B-\u003e\u003eG: verify_oauth2_token() G--\u003e\u003eB: Claims (sub, email, name, picture) B-\u003e\u003eDB: get_or_create_user() DB--\u003e\u003eB: User 객체 B-\u003e\u003eB: create_jwt(user_id) B--\u003e\u003eF: Set-Cookie: access_token=JWT\u0026lt;br/\u0026gt;(HttpOnly, SameSite=Lax) B--\u003e\u003eF: LoginResponse {user} F-\u003e\u003eU: 메인 앱 전환 Note over F,B: 이후 모든 요청 F-\u003e\u003eB: API 요청\u0026lt;br/\u0026gt;(쿠키 자동 첨부) B-\u003e\u003eB: get_current_user()\u0026lt;br/\u0026gt;JWT 검증 B--\u003e\u003eF: Protected 데이터데이터베이스 변경 User 모델 추가 기존에 SearchLog, ImageSelection, GenerationLog, ManualUpload 4개 테이블이 있었고, 모두 사용자 개념 없이 익명으로 기록되고 있었다. 새로 User 테이블을 만들고, 기존 4개 테이블에 user_id FK 컬럼을 추가했다.\nclass User(Base): __tablename__ = \u0026#34;users\u0026#34; id = Column(Integer, primary_key=True, autoincrement=True) google_id = Column(String, unique=True, nullable=False, index=True) email = Column(String, unique=True, nullable=False) name = Column(String, nullable=False) picture_url = Column(String, nullable=True) generation_count = Column(Integer, default=0, nullable=False) last_active_at = Column(DateTime, nullable=True) created_at = Column(DateTime, nullable=False, server_default=func.now()) 기존 데이터는 건드리지 않기로 했다. FK 컬럼은 nullable=True로 선언해서 기존 행은 user_id=NULL로 남기고, 새로운 행만 인증 미들웨어에서 user_id를 채운다. Alembic 마이그레이션 1개로 테이블 생성과 FK 추가를 처리했다.\nBackend 구현 auth.py — 인증 모듈 모든 인증 로직을 backend/src/auth.py 하나에 모았다. 세 가지 핵심 함수가 있다.\n1. Google 토큰 검증 — verify_google_token()\nasync def verify_google_token(token: str) -\u0026gt; dict: try: # verify_oauth2_token은 동기 함수이고 Google 공개키를 네트워크로 가져올 수 있음 idinfo = await asyncio.to_thread( id_token.verify_oauth2_token, token, google_requests.Request(), GOOGLE_CLIENT_ID ) if idinfo[\u0026#34;iss\u0026#34;] not in (\u0026#34;accounts.google.com\u0026#34;, \u0026#34;https://accounts.google.com\u0026#34;): raise ValueError(\u0026#34;Invalid issuer\u0026#34;) return idinfo except ValueError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=f\u0026#34;Invalid Google token: {e}\u0026#34;, ) 보안 리뷰에서 asyncio.to_thread()로 감싸는 수정이 들어갔다. verify_oauth2_token()은 동기 함수인데 Google의 공개키를 네트워크에서 가져오는 I/O가 발생할 수 있어서, 그냥 호출하면 이벤트 루프를 블로킹한다.\n2. JWT 쿠키 관리 — create_jwt() / set_auth_cookie()\nJWT에는 user_id와 exp만 담는다. 쿠키 설정에서 중요한 부분:\nHttpOnly — JavaScript에서 토큰을 읽을 수 없어 XSS 방지 SameSite=Lax — CSRF 보호 (추가 CSRF 토큰 불필요) Secure — 프로덕션(HTTPS)에서만 활성화, 로컬 개발은 비활성화 3. FastAPI Dependency — get_current_user()\nasync def get_current_user(access_token: str = Cookie(None)): if not access_token: raise HTTPException(status_code=401, detail=\u0026#34;Not authenticated\u0026#34;) try: payload = jwt.decode(access_token, JWT_SECRET, algorithms=[\u0026#34;HS256\u0026#34;]) user_id = payload.get(\u0026#34;user_id\u0026#34;) except JWTError: raise HTTPException(status_code=401, detail=\u0026#34;Invalid token\u0026#34;) user = await get_user_by_id(user_id) if not user: raise HTTPException(status_code=401, detail=\u0026#34;User not found\u0026#34;) # last_active_at 업데이트 (분당 1회 throttling) now = datetime.now(timezone.utc) if not user.last_active_at or (now - user.last_active_at).seconds \u0026gt; 60: await update_last_active(user.id) return user last_active_at 업데이트를 매 요청마다 하면 SQLite에 쓰기 부하가 걸리므로, 분당 1회로 throttling한다. 또한 /api/auth/me용으로 401 대신 None을 반환하는 get_optional_user() 변형도 만들었다.\n엔드포인트 보호 기존 10개 데이터 접근 엔드포인트 전부에 user = Depends(get_current_user)를 추가했다. 이미지 생성 엔드포인트에서는 추가로 increment_generation_count(user.id)를 호출한다. 모든 로그 함수(log_search, log_image_selection 등)에 user_id 파라미터를 추가하고, 서비스 레이어에서 해당 컬럼에 저장한다.\n# 보호 대상 (get_current_user 필수) POST /search, /search/simple, /search/hybrid, GET /search POST /api/generate-image, /api/log-selection, /api/upload-reference-image GET /api/history/generations, /api/images, /api/images/{image_id} # 비보호 (인증 불필요) GET /, /health, /api/info, /images/{filename} POST /api/auth/google, /api/auth/logout GET /api/auth/me Frontend 로그인 플로우 LoginPage 컴포넌트 @react-oauth/google의 \u0026lt;GoogleLogin\u0026gt; 컴포넌트로 팝업 방식의 로그인을 구현했다. 리다이렉트 방식이 아니라 팝업에서 Google 계정을 선택하면 바로 ID 토큰이 콜백으로 돌아온다.\n// LoginPage.tsx import { GoogleLogin, GoogleOAuthProvider } from \u0026#39;@react-oauth/google\u0026#39;; function LoginPage({ onLogin }: { onLogin: (user: UserProfile) =\u0026gt; void }) { const handleSuccess = async (credentialResponse) =\u0026gt; { const response = await loginWithGoogle(credentialResponse.credential); onLogin(response.user); }; return ( \u0026lt;GoogleOAuthProvider clientId={import.meta.env.VITE_GOOGLE_CLIENT_ID}\u0026gt; \u0026lt;div className=\u0026#34;login-container\u0026#34;\u0026gt; \u0026lt;h1\u0026gt;Hybrid Image Search\u0026lt;/h1\u0026gt; \u0026lt;GoogleLogin onSuccess={handleSuccess} onError={() =\u0026gt; setError(\u0026#39;Login failed\u0026#39;)} /\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/GoogleOAuthProvider\u0026gt; ); } App.tsx 변경 앱 진입점에서 인증 상태를 관리한다:\n마운트 시 — GET /api/auth/me 호출. 성공하면 기존 세션 복구, 401이면 로그인 페이지 표시 조건부 렌더링 — authLoading → 스피너, !user → \u0026lt;LoginPage\u0026gt;, else → 기존 UI 로그아웃 — 우측 상단 버튼, POST /api/auth/logout 호출 후 상태 초기화 데이터 로딩 가드 — useEffect에서 if (!user) return;으로 로그인 전 API 호출 방지 // App.tsx (핵심 로직) useEffect(() =\u0026gt; { if (!user) return; const loadHistory = async () =\u0026gt; { const items = await fetchGenerationHistory(20, 0); setGeneratedImages(mapHistoryItems(items)); }; loadHistory(); }, [user]); api.ts — Axios 설정 // withCredentials: true — 브라우저가 쿠키를 자동으로 요청에 첨부 const api = axios.create({ baseURL: API_BASE, withCredentials: true, }); // 401 인터셉터 — 토큰 만료 시 자동으로 로그인 페이지로 전환 api.interceptors.response.use( (response) =\u0026gt; response, (error) =\u0026gt; { if (error.response?.status === 401) { window.dispatchEvent(new Event(\u0026#39;auth:logout\u0026#39;)); } return Promise.reject(error); } ); 보안 리뷰 구현 후 /ship 커맨드로 보안 리뷰를 실행했다. 발견된 주요 사항과 수정 내용:\n항목 문제 수정 Google 토큰 검증 동기 함수가 이벤트 루프 블로킹 asyncio.to_thread()로 감싸기 JWT 시크릿 미설정 시크릿 없이 서버 시작 시 모든 인증 실패 configure_auth()에서 logger.warning 출력 create_jwt() 가드 JWT_SECRET=None일 때 서명 시도 RuntimeError 발생시키도록 가드 추가 프론트엔드 스타일 하드코딩된 inline style Tailwind CSS 클래스로 전환 히스토리 로딩 로그인 전 API 호출 시도 user 의존성 가드 추가 시크릿 관리도 설계 시 고려했다. GOOGLE_OAUTH_CLIENT_ID와 JWT_SECRET은 yaml 설정 파일이 아닌 os.getenv()로 로드한다. yaml은 버전 관리 대상이므로 시크릿을 넣으면 안 된다. 토큰 만료 시간 같은 비밀이 아닌 설정만 config.py의 AuthConfig에 담는다.\n개발 도구: /ship 커맨드와 PostToolUse 훅 이번 작업에서는 프로젝트 전용 개발 도구도 함께 세팅했다.\nPostToolUse 훅 — 파일 수정할 때마다 자동으로 타입 체크:\n.ts/.tsx 파일 수정 → tsc --noEmit 자동 실행 backend/*.py 파일 수정 → pyright 자동 실행 /ship 커맨드 — 커밋 전 6단계 검증 파이프라인:\n변경 파일 식별 타입 검증 (tsc + pyright) API contract 동기화 확인 (schemas.py ↔ api.ts) 코드 단순화 리뷰 보안 리뷰 자동 커밋 한 가지 재미있는 삽질이 있었는데, PostToolUse 훅에서 $CLAUDE_FILE_PATH 환경변수를 사용했더니 동작하지 않았다. 알고 보니 훅은 stdin JSON으로 입력을 받는 구조였다:\nINPUT=$(cat) FILEPATH=$(echo \u0026#34;$INPUT\u0026#34; | jq -r \u0026#39;.tool_input.file_path // empty\u0026#39;) 커밋 로그 메시지 주요 파일 docs: Google 로그인 설계 스펙 2026-03-17-google-login-design.md docs: 스펙 리뷰 피드백 반영 동일 docs: 엔드포인트 경로 및 설명 일관성 수정 동일 docs: 구현 계획서 작성 2026-03-17-google-login.md feat: User 모델 + user_id FK 추가 models.py, Alembic 마이그레이션 feat: google-auth, python-jose 의존성 requirements.txt feat: @react-oauth/google 의존성 package.json feat: 인증 Pydantic 스키마 schemas.py feat: 사용자 CRUD 및 활동 추적 service.py feat: auth 모듈 (토큰 검증 + JWT 쿠키) auth.py feat: AuthConfig 추가 config.py, default.yaml feat: LoginPage 컴포넌트 LoginPage.tsx feat: auth API 함수, 401 인터셉터 api.ts feat: 인증 상태, 로그인/로그아웃 플로우 App.tsx feat: auth 엔드포인트 + 전체 라우트 보호 main.py, service.py fix: 보안 가드, async 토큰 검증, UI auth.py, App.tsx feat: Google OAuth 로그인 월 완성 최종 병합 인사이트 HttpOnly 쿠키 vs localStorage — SPA에서 JWT를 localStorage에 넣는 튜토리얼이 많지만, XSS 한 방이면 토큰이 털린다. HttpOnly 쿠키는 JavaScript가 아예 접근할 수 없어서, 특히 Gemini API처럼 과금이 되는 서비스를 보호할 때는 이쪽이 맞다. 구현 복잡도 차이는 CORS에 allow_credentials=True 추가하는 정도밖에 없다.\n설계 먼저, 코드는 나중에 — 이번에 설계 스펙 → 리뷰 → 구현 계획 → 리뷰 → 코딩 순서로 진행했다. 시간이 더 걸리는 것 같지만, 스펙 리뷰에서 get_optional_user() 패턴 누락, 시크릿 로딩 전략 미비, 엔드포인트 목록 불일치 등을 코딩 전에 잡았다. 코드 리뷰에서 잡는 것보다 수정 비용이 훨씬 적다.\nasyncio.to_thread() 패턴 — FastAPI에서 동기 라이브러리를 쓸 때 흔히 빠지는 함정이다. google.oauth2.id_token.verify_oauth2_token()은 내부에서 HTTP 요청을 보내는데, await 없이 호출하면 이벤트 루프가 멈춘다. asyncio.to_thread()로 스레드 풀에 위임하는 패턴을 기억해두자.\nClaude Code /ship 워크플로우 — 타입 체크 → API contract 동기화 → 코드 리뷰 → 보안 리뷰 → 자동 커밋을 한 번에 돌리니, 커밋 품질이 확실히 올라간다. 특히 schemas.py와 api.ts가 동시에 바뀌었는지 자동으로 확인해주는 부분이 유용했다. 프로젝트별로 커스텀 훅과 커맨드를 만들 수 있다는 점이 Claude Code의 강점이다.\n","date":"2026-03-17T00:00:00+09:00","image":"/images/posts/2026-03-17-hybrid-search-auth/cover.jpg","permalink":"/ko/posts/2026-03-17-hybrid-search-auth/","title":"하이브리드 이미지 검색 개발기 — Google OAuth 로그인 월 구현"},{"content":"개요 한국 AI 커뮤니티의 대표 팟캐스트 AI Frontier에서 최근 공개한 3편의 에피소드를 정리한다. EP 90은 알파고 10주년 회고, EP 88은 RL 중심의 기술 혁신 트렌드, EP 86은 실전 에이전트 코딩 워크플로우를 다룬다. 세 편을 관통하는 키워드는 \u0026ldquo;검증 가능성\u0026quot;이다.\n탐색 맵 graph TD A[\"AI Frontier 팟캐스트\"] --\u003e B[\"EP 90: 알파고 10주년 \u0026lt;br/\u0026gt; AI 10년 회고\"] A --\u003e C[\"EP 88: 비결은 없다 \u0026lt;br/\u0026gt; RL의 시대\"] A --\u003e D[\"EP 86: Agentic Workflow \u0026lt;br/\u0026gt; 실전 에이전트 코딩\"] B --\u003e E[\"ImageNet → Transformer → LLM\"] C --\u003e F[\"RL 스케일링 \u0026lt;br/\u0026gt; 환경 병목 \u0026lt;br/\u0026gt; 검증 가능성\"] D --\u003e G[\"Backend.AI:GO \u0026lt;br/\u0026gt; 40일, 130억 토큰 \u0026lt;br/\u0026gt; 100만 줄 코드\"] EP 90: 알파고 이후, 10년 게스트: HyperAccel 이진원 CTO (추론 전용 AI 반도체 스타트업)\n2026년 3월 14일(파이 데이)에 녹화된 이 에피소드는 알파고 대국 10주년을 계기로 딥러닝 10년사를 회고한다. 노정석, 최승준 호스트와 이진원 CTO가 함께했다.\n핵심 타임라인:\nImageNet과 NPU 개발기: 이진원 CTO가 삼성전자에서 딥러닝 NPU를 개발하던 시절의 이야기 프레임워크 변천: Theano → Caffe → TensorFlow → PyTorch로 이어진 딥러닝 프레임워크의 진화 GAN에서 Transformer로: GAN의 유행과 생성 AI의 시작, 그리고 Attention 메커니즘의 등장 BERT vs GPT: 인코더(BERT)와 디코더(GPT)의 갈림길, GPT가 LLM으로 이어진 경로 한국 파운데이션 모델: HyperCLOVA와 Stability AI 커뮤니티의 역할 Andrej Karpathy의 Autoresearch와 \u0026ldquo;검증 가능한 신호의 반복\u0026quot;이 키워드로 등장하며, Noam Brown이 알파고 10주년 포스팅에서 강조한 37수의 의미를 재조명한다.\nEP 88: 비결은 없다 게스트: 성현 (AI 연구자)\n제목 그대로 — AI 기술에 단일한 \u0026ldquo;비밀 레시피\u0026quot;는 없다는 것이 핵심 메시지다.\n주요 논점:\nGLM 5 리포트와 RL: Yao Shunyu의 \u0026ldquo;The Second Half\u0026rdquo; 논문이 제시한 RL 중심 패러다임. \u0026ldquo;비결은 없지만, 지금 가장 유력한 방향은 RL\u0026quot;이라는 결론 기본기의 시대: 화려한 아키텍처 혁신보다 데이터 품질과 제품 감각이 중요해진 국면 Fog of Progress: 미래 예측이 어려운 구조적 이유. 모델의 성능 곡선이 비선형이라 \u0026ldquo;올해 안에 될 것 같다\u0026quot;는 감각이 자주 틀림 환경 스케일링: 에이전트 RL의 최대 병목은 모델이 아닌 \u0026ldquo;환경\u0026quot;의 확장. 시뮬레이션과 검증 가능한 환경을 얼마나 풍부하게 만드느냐가 핵심 컨텍스트 관리: Sparse Attention과 멀티 에이전트 접근으로 컨텍스트 길이 한계를 우회하는 전략 하네스와 모델의 융합: 제품과 모델의 경계가 흐려지는 현상. 좋은 하네스가 모델 성능을 끌어올림 EP 86: 진짜 내 일을 위한 Agentic Workflow 게스트: 신정규 대표 (Lablup, Backend.AI)\n가장 실전적인 에피소드다. Backend.AI:GO라는 제품을 40일 만에, 130억 토큰을 사용해, 100만 줄의 코드로 완성한 이야기를 중심으로 에이전트 코딩의 교훈을 풀어낸다.\ngraph LR A[\"Backend.AI:GO \u0026lt;br/\u0026gt; 40일 개발\"] --\u003e B[\"130억 토큰 소비\"] B --\u003e C[\"100만 줄 코드\"] C --\u003e D[\"클라우드 모델 연결 \u0026lt;br/\u0026gt; 분산 라우팅\"]핵심 인사이트:\n토큰 경쟁력과 고속 inference: 에이전트 코딩에서 inference 속도가 개발 생산성에 직결 바이오 토큰: AI 시대에 \u0026ldquo;인간의 인지 부하\u0026quot;라는 개념. 사람이 처리할 수 있는 정보의 양에도 한계가 있다 소프트웨어 과잉 시대: \u0026ldquo;인스턴트 앱\u0026quot;의 등장 — 코드의 가치가 0으로 수렴하는가? Claude Code의 진짜 경쟁력은 harness다: 모델 자체보다 모델을 감싸는 하네스(도구, 컨텍스트 관리, 워크플로우)가 차별화 요소 결과물이 아닌 생성 장치를 만든다: 자동화의 핵심은 개별 결과가 아닌 결과를 만드는 시스템 AI에게 존댓말을 쓰는 이유: (실제로 성능에 영향을 주는지는 불분명하지만) 프롬프트의 톤이 결과에 영향을 줄 수 있다는 경험적 관찰 Claude Code vs Codex의 철학 차이를 \u0026ldquo;사이버 포뮬러\u0026rdquo; 비유로 설명하는 부분이 인상적이다.\n빠른 링크 AI Frontier EP 90 — 알파고 이후, 10년 AI Frontier EP 88 — 비결은 없다 AI Frontier EP 86 — 진짜 내 일을 위한 Agentic Workflow 인사이트 세 에피소드를 관통하는 키워드는 **\u0026ldquo;검증 가능성(verifiability)\u0026rdquo;**이다. EP 90에서 Karpathy가 강조한 \u0026ldquo;검증 가능한 신호의 반복\u0026rdquo;, EP 88에서 RL 스케일링의 병목으로 지목된 \u0026ldquo;검증 가능한 환경\u0026rdquo;, EP 86에서 신정규 대표가 말한 \u0026ldquo;결과물이 아닌 생성 장치\u0026rdquo; — 모두 같은 문제의 다른 단면이다. AI 모델이 강력해질수록 \u0026ldquo;이 결과가 맞는지 어떻게 아느냐\u0026quot;는 질문의 무게가 커진다. 기본기(데이터, 하네스, 환경)에 집중하라는 EP 88의 \u0026ldquo;비결은 없다\u0026quot;라는 결론이 가장 정직한 답일 것이다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-ai-frontier-podcast/cover.jpg","permalink":"/ko/posts/2026-03-16-ai-frontier-podcast/","title":"AI Frontier 팟캐스트 3편 요약 — 알파고 10년, RL의 시대, Agentic Workflow"},{"content":"개요 사무실에서 Claude Code로 리팩토링을 진행하다가 자리를 비워야 한다. 터미널을 닫으면 세션이 끊긴다. 이전에는 SSH 터널이나 서드파티 도구(happy, hapi 등)를 사용해야 했지만, 이제 Claude Code에 공식 Remote Control 기능이 추가되었다. claude remote-control 한 줄이면 스마트폰, 태블릿, 다른 컴퓨터에서 동일한 세션을 이어받을 수 있다.\n동작 원리 graph TD A[\"로컬 머신 \u0026lt;br/\u0026gt; claude remote-control\"] --\u003e|\"HTTPS 아웃바운드만\"| B[\"Anthropic API \u0026lt;br/\u0026gt; 메시지 라우팅\"] B --\u003e C[\"claude.ai/code \u0026lt;br/\u0026gt; 브라우저\"] B --\u003e D[\"Claude 모바일 앱 \u0026lt;br/\u0026gt; iOS/Android\"] B --\u003e E[\"다른 컴퓨터 \u0026lt;br/\u0026gt; 브라우저\"] C --\u003e|\"실시간 동기화\"| A D --\u003e|\"실시간 동기화\"| A E --\u003e|\"실시간 동기화\"| A핵심은 세션이 항상 로컬 머신에서 실행된다는 점이다. 코드가 클라우드로 올라가지 않으며, 파일시스템, MCP 서버, 프로젝트 설정이 그대로 유지된다. 로컬 Claude Code 프로세스가 HTTPS 아웃바운드 요청만 보내고, 인바운드 포트는 열지 않는다. Anthropic API가 중간에서 메시지를 라우팅하는 구조다.\n네트워크가 끊기거나 노트북이 잠들어도, 머신이 다시 온라인이 되면 자동 재연결된다. 다만 10분 이상 네트워크가 끊기면 세션이 타임아웃된다.\n사용법 기본: 서버 모드 claude remote-control 터미널에 세션 URL과 QR 코드가 표시된다. 스페이스바로 QR 코드를 토글할 수 있어 폰으로 바로 스캔 가능하다.\n주요 플래그 플래그 설명 --name \u0026quot;My Project\u0026quot; claude.ai/code 세션 목록에 표시될 이름 --spawn same-dir 동시 세션이 같은 디렉토리 공유 (기본값) --spawn worktree 각 세션이 독립 git worktree 사용 --capacity \u0026lt;N\u0026gt; 동시 세션 최대 수 (기본 32) --sandbox 파일시스템/네트워크 격리 활성화 기존 세션에서 활성화 이미 진행 중인 대화형 세션에서 /remote-control 명령으로 활성화할 수도 있다. 또는 /config에서 \u0026ldquo;Enable Remote Control for all sessions\u0026quot;를 켜면 모든 세션에 자동 적용된다.\n연결 방법 (3가지) URL 직접 입력: 터미널에 표시된 세션 URL을 브라우저에 입력 QR 코드 스캔: 스페이스바로 QR 코드 표시 → 폰 카메라로 스캔 세션 목록: claude.ai/code 또는 Claude 앱에서 세션 이름으로 찾기 (초록 점이 온라인 표시) Claude Code on the Web과의 차이 graph LR subgraph RC[\"Remote Control\"] A1[\"로컬 머신에서 실행\"] --\u003e B1[\"내 파일시스템 접근\"] A1 --\u003e C1[\"내 MCP 서버 사용\"] A1 --\u003e D1[\"내 프로젝트 설정 유지\"] end subgraph Web[\"Claude Code on the Web\"] A2[\"Anthropic 클라우드에서 실행\"] --\u003e B2[\"클라우드 VM 환경\"] A2 --\u003e C2[\"로컬 설정 없이 사용\"] A2 --\u003e D2[\"레포 클론 없이 작업\"] end 구분 Remote Control Claude Code on the Web 실행 위치 내 로컬 머신 Anthropic 클라우드 파일시스템 내 로컬 파일 클라우드 VM MCP 서버 사용 가능 불가 로컬 설정 필요 필요 (프로젝트 클론 필수) 불필요 적합한 상황 진행 중인 작업 이어하기 새 작업 빠르게 시작 Remote Control은 \u0026ldquo;내 환경에서 계속\u0026rdquo;, **Web은 \u0026ldquo;어디서든 새로 시작\u0026rdquo;**이다.\n서드파티 대안과 비교 GeekNews 댓글에서 언급된 서드파티 프로젝트들:\nslopus/happy, tiann/hapi — 비슷한 목적의 오픈소스 SSH 터널을 통한 원격 터미널 접속 공식 Remote Control의 장점은 별도 서버 설정이 필요 없고, Anthropic API를 통한 TLS 보안이 기본 적용된다는 것이다. 단점으로는 댓글에서 지적된 것처럼 \u0026ldquo;미리 세션을 만들어둬야 한다\u0026quot;는 점이 오픈소스 대안보다 불편할 수 있다.\n제약사항 플랜: Pro, Max, Team, Enterprise (Team/Enterprise는 관리자가 Claude Code를 먼저 활성화해야 함) API 키 미지원: claude.ai 로그인 인증만 지원 터미널 종속: claude 프로세스를 닫으면 세션 종료 단일 원격 연결: 서버 모드 외에는 세션당 1개의 원격 연결만 허용 버전: Claude Code v2.1.51 이상 필요 (claude --version으로 확인) 인사이트 Remote Control의 진짜 가치는 \u0026ldquo;원격 접속\u0026quot;이 아니라 **\u0026ldquo;컨텍스트 보존\u0026rdquo;**에 있다. Claude Code 세션에는 대화 히스토리, 읽은 파일들의 컨텍스트, MCP 서버 연결 상태가 쌓여 있다. 이것을 잃지 않고 디바이스만 바꿀 수 있다는 것이 핵심이다. GeekNews의 \u0026ldquo;이제 유튜브에서 \u0026lsquo;바깥에서 바이브코딩하기\u0026rsquo; 콘텐츠들이 많이 올라오겠네요\u0026quot;라는 댓글이 이 기능의 사용 패턴을 잘 예측한다. cmux의 알림 시스템과 결합하면 — cmux로 여러 에이전트를 모니터링하다가, 자리를 비울 때 Remote Control로 모바일에서 이어받는 — 완전한 멀티디바이스 에이전트 코딩 워크플로우가 가능해진다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-claude-code-remote-control/cover.jpg","permalink":"/ko/posts/2026-03-16-claude-code-remote-control/","title":"Claude Code Remote Control — 자리를 비워도 코딩 세션이 끊기지 않는다"},{"content":"개요 Anthropic이 Claude for Chrome 확장 프로그램을 출시했다. 별도 탭이나 앱을 열지 않고 브라우저 안에서 바로 Claude를 호출할 수 있게 되었다. 동시에 3월 13일부터 27일까지 오프피크 시간대 사용량을 2배로 늘리는 프로모션도 시작했다.\nClaude for Chrome 확장 graph LR A[\"웹 브라우징 중\"] --\u003e B[\"Claude 확장 호출\"] B --\u003e C[\"현재 페이지 컨텍스트 전달\"] C --\u003e D[\"Claude 응답\"] D --\u003e E[\"브라우저 내 인라인 표시\"]Claude for Chrome은 Chrome 웹 스토어에서 설치할 수 있다. 핵심 기능:\n브라우저 내 직접 호출: 현재 보고 있는 웹페이지의 컨텍스트를 Claude에게 바로 전달 Claude Code 연동: Claude Code와 함께 사용 가능 — 코드 리뷰, 문서 요약 등 백그라운드 작업: 작업을 백그라운드에서 실행하고 완료 시 알림 스케줄 워크플로우: 예약된 작업 자동 실행 이 확장의 전략적 의미는 Claude의 접근성 확대에 있다. 기존에는 claude.ai 사이트, 데스크톱 앱, 또는 API를 통해서만 접근 가능했다면, 이제 브라우저 어디서든 단축키 하나로 호출할 수 있다. ChatGPT, Gemini, Perplexity 등 경쟁 서비스가 이미 브라우저 확장을 제공하고 있는 상황에서 Anthropic도 합류한 것이다.\n3월 사용량 2배 프로모션 구분 내용 기간 2026.03.13 ~ 2026.03.27 대상 Free, Pro, Max, Team 플랜 (Enterprise 제외) 조건 오프피크 시간대 (ET 오전 8시오후 2시 / PT 오전 5시11시 외의 시간) 적용 자동 (별도 신청 불필요) 주간 한도 보너스 사용량은 주간 사용 한도에 포함되지 않음 graph TD A[\"평일 하루\"] --\u003e B{\"시간대 확인\"} B --\u003e|\"ET 8AM-2PM \u0026lt;br/\u0026gt; (피크)\"| C[\"기존 사용량\"] B --\u003e|\"그 외 시간 \u0026lt;br/\u0026gt; (오프피크)\"| D[\"2x 사용량\"] D --\u003e E[\"주간 한도 미포함\"]한국 시간 기준으로 오프피크: ET 오전 8시오후 2시는 KST 오후 10시새벽 4시에 해당한다. 즉 한국에서 낮 시간에 사용하면 대부분 오프피크에 해당하여 2배 혜택을 받을 수 있다.\n적용 범위는 Claude 웹/데스크톱/모바일, Cowork, Claude Code, Claude for Excel, Claude for PowerPoint까지 포함된다.\nClaude 플랫폼 확장 전략 graph TD A[\"Claude 플랫폼\"] --\u003e B[\"claude.ai \u0026lt;br/\u0026gt; 웹/데스크톱/모바일\"] A --\u003e C[\"Claude Code \u0026lt;br/\u0026gt; 터미널/VS Code/JetBrains\"] A --\u003e D[\"Claude for Chrome \u0026lt;br/\u0026gt; 브라우저 확장\"] A --\u003e E[\"Claude for Office \u0026lt;br/\u0026gt; Excel/PowerPoint\"] A --\u003e F[\"Claude for Slack\"] A --\u003e G[\"Cowork \u0026lt;br/\u0026gt; 자율 에이전트\"]Anthropic은 Claude를 단일 챗봇이 아닌 모든 작업 환경에 편재하는 AI 레이어로 확장하고 있다. 터미널(Claude Code), 브라우저(Chrome), 오피스(Excel/PowerPoint), 협업 도구(Slack), 자율 에이전트(Cowork) — 개발자가 일하는 거의 모든 표면에 Claude가 존재하게 되었다.\n인사이트 Chrome 확장의 출시와 사용량 프로모션의 동시 진행은 명확한 전략이다 — 접근성을 높이고(확장), 시도 비용을 낮추고(프로모션), 습관을 만든다. 한국 사용자에게 특히 유리한 점은 시차 덕분에 업무 시간 대부분이 오프피크에 해당한다는 것이다. 3월 27일까지 Claude Code와 웹 모두 2배 사용량을 활용할 수 있으니, 새 기능이나 대규모 리팩토링을 시도하기에 좋은 시점이다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-claude-for-chrome/cover.jpg","permalink":"/ko/posts/2026-03-16-claude-for-chrome/","title":"Claude for Chrome — 브라우저에 AI를 심는 Anthropic의 새 전략"},{"content":"개요 Anthropic이 Claude에 대화 속에서 바로 인터랙티브 차트, 다이어그램, 시각화를 생성하는 베타 기능을 추가했다. 지난 가을 \u0026ldquo;Imagine with Claude\u0026rdquo; 프리뷰와 기존 Artifacts 기능을 결합한 것으로, 사이드 패널이 아닌 채팅 본문에 직접 임베드되는 \u0026ldquo;임시 시각화\u0026rdquo; 방식이 핵심이다.\n핵심 변화: 코드 없이, 대화 흐름 안에서 graph TD A[\"사용자 요청\"] --\u003e B{\"Claude 판단\"} B --\u003e|\"텍스트가 나을 때\"| C[\"기존 텍스트 응답\"] B --\u003e|\"시각화가 나을 때\"| D[\"인터랙티브 차트 생성\"] D --\u003e E[\"채팅 본문에 임베드\"] E --\u003e F[\"사용자 인터랙션 \u0026lt;br/\u0026gt; 클릭, 값 변경\"] F --\u003e G[\"대화로 수정 요청\"] G --\u003e D이번 기능의 핵심은 두 가지다. 첫째, 사용자가 \u0026ldquo;다이어그램으로 그려줘\u0026rdquo;, \u0026ldquo;시간에 따라 어떻게 변해?\u0026ldquo;처럼 요청하면 즉시 생성되고, Claude가 알아서 \u0026ldquo;그림이 더 빠르겠다\u0026quot;고 판단해 자동 생성하기도 한다. 둘째, 결과물이 영구 문서가 아닌 임시 도구라는 점이다.\n복리 그래프를 만들어 놓고 \u0026ldquo;기간을 20년으로 늘려줘\u0026rdquo;, \u0026ldquo;월 적립으로 바꿔줘\u0026quot;처럼 대화로 계속 다듬는 워크플로우가 가능하다. 클릭 가능한 주기율표, 인터랙티브 결정 트리 등 탐색형 시각화가 특히 강점이다.\nArtifacts와의 차이 graph LR A[\"Artifacts\"] --\u003e B[\"사이드 패널 \u0026lt;br/\u0026gt; 영구 저장 \u0026lt;br/\u0026gt; 공유/다운로드\"] C[\"인챗 비주얼\"] --\u003e D[\"채팅 본문 임베드 \u0026lt;br/\u0026gt; 임시 도구 \u0026lt;br/\u0026gt; 대화로 즉시 수정\"] 구분 Artifacts 인챗 인터랙티브 비주얼 위치 사이드 패널 답변 본문 수명 영구 (저장/공유) 임시 (대화 흐름 따라 변화) 목적 결과물 전달 설명 보조 수정 별도 편집 대화로 즉시 반영 다만 커뮤니티 반응을 보면, 환경에 따라 인라인이 아닌 아티팩트(오른쪽 패널)로 표시되거나 앱 버전별 지원이 들쭉날쭉하다는 경험담이 있다. iOS/iPadOS에서 시각화 지원이 늦다는 보고와 사용량 제한에 빨리 걸렸다는 사례도 공유됐다.\n실전 활용 시나리오 학습: 클릭 가능한 주기율표, 결정 트리 같은 탐색형 자료로 \u0026ldquo;읽는 공부\u0026quot;에서 \u0026ldquo;만져보는 공부\u0026quot;로 전환. 수학·과학 분야에서 변수 하나를 바꿨을 때 그래프가 어떻게 변하는지 보는 순간 이해가 빨라진다.\n업무 미팅: \u0026ldquo;우리 서비스 퍼널을 단계별로 그려줘\u0026rdquo;, \u0026ldquo;가설 A/B 비교를 차트로 보여줘\u0026quot;처럼 말로 만든 임시 대시보드를 띄워놓고 질문이 나올 때마다 바로 수정하는 방식이 가능하다.\n데이터 분석: 포트폴리오 분석을 시각화로 자동 생성해 \u0026ldquo;사람이 일주일 걸릴 결과\u0026quot;를 수분 만에 얻었다는 반응도 있다.\n주의할 점: 화려함 ≠ 정확성 The New Stack의 테스트에서 도식은 그럴듯했지만 항공 패턴 다이어그램의 일부 라벨 위치가 틀린 사례가 발견됐다. 시각화는 \u0026ldquo;이해를 돕는 UI\u0026quot;이지 \u0026ldquo;정답 인증 배지\u0026quot;가 아니다.\n실용적인 사용법은 간단하다:\n**\u0026ldquo;표/차트로 보여줘\u0026rdquo;**로 시작 **\u0026ldquo;이 그래프의 전제와 계산식을 같이 적어줘\u0026rdquo;**로 검증 장치 추가 **\u0026ldquo;변수 하나만 바꿔서 비교해줘\u0026rdquo;**로 탐색 반복 이 기능은 모든 요금제(Free, Pro, Max, Team)에서 사용 가능하다.\n인사이트 Claude의 인챗 인터랙티브 차트는 AI가 답을 \u0026ldquo;말로\u0026rdquo; 전달하던 단계에서 사용자가 답을 \u0026ldquo;눌러서 확인\u0026quot;하는 단계로의 전환 신호다. 텍스트 기반 대화에 시각적 탐색을 결합하는 이 방향은, ChatGPT의 Canvas나 Gemini의 멀티모달 출력과 함께 AI 인터페이스의 진화를 보여준다. 다만 베타인 만큼 렌더링 위치나 속도, 플랫폼 지원은 흔들릴 수 있고, 가장 중요한 것은 화려한 시각화에 현혹되지 않고 원데이터와 전제 조건을 함께 요구하는 습관을 유지하는 것이다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-claude-interactive-visuals/cover.jpg","permalink":"/ko/posts/2026-03-16-claude-interactive-visuals/","title":"Claude 인챗 인터랙티브 비주얼 — 대화가 대시보드가 되는 순간"},{"content":"개요 AI 코딩 에이전트를 3~4개씩 동시에 돌리다 보면, 터미널 창이 폭발한다. iTerm2 탭이 15개, tmux 세션이 8개 — 어떤 에이전트가 입력을 기다리는지 찾느라 시간을 소모한다. cmux는 이 문제를 정면으로 해결하기 위해 설계된 macOS 네이티브 터미널이다.\nSwift + AppKit으로 구축되었고, Ghostty의 libghostty를 렌더링 엔진으로 사용한다. AGPL 라이선스로 완전히 무료다. 워크스페이스 사이드바에 git 브랜치, PR 상태, 열린 포트, 알림 텍스트를 실시간으로 표시하고, read-screen으로 패인 간 통신을 지원하며, 내장 브라우저는 풀 자동화 API를 제공한다. 전통적인 터미널 멀티플렉서와의 비교가 아니라 — AI 에이전트를 위한 새로운 카테고리의 도구다.\ntmux와의 비교는 별도 포스트에서 다룬다.\n아키텍처: Ghostty 위의 새로운 레이어 cmux는 Ghostty의 포크가 아니다. libghostty를 라이브러리로 사용하는 별도의 앱이다 — WebKit을 사용하는 앱들이 Safari의 포크가 아닌 것과 같은 관계다. Mitchell Hashimoto(Ghostty + HashiCorp 창시자) 본인이 \u0026ldquo;또 하나의 libghostty 기반 프로젝트\u0026quot;라며 긍정적으로 언급했다.\ngraph TD A[\"cmux.app \u0026lt;br/\u0026gt; Swift + AppKit\"] --\u003e B[\"libghostty \u0026lt;br/\u0026gt; GPU 가속 터미널 렌더링\"] A --\u003e C[\"수직 탭 사이드바 \u0026lt;br/\u0026gt; git branch, PR, ports\"] A --\u003e D[\"알림 시스템 \u0026lt;br/\u0026gt; OSC 9/99/777 + macOS 알림\"] A --\u003e E[\"내장 브라우저 \u0026lt;br/\u0026gt; 풀 자동화 API\"] A --\u003e F[\"소켓 API \u0026lt;br/\u0026gt; CLI 자동화 + read-screen\"] A --\u003e G[\"세션 복원 \u0026lt;br/\u0026gt; 레이아웃 + 메타데이터\"] F --\u003e H[\"UNIX 도메인 소켓 \u0026lt;br/\u0026gt; CMUX_SOCKET_PATH\"] H --\u003e I[\"cmux CLI \u0026lt;br/\u0026gt; identify, send, read-screen, \u0026lt;br/\u0026gt; split, browser, notify\"]GPU 가속 렌더링은 Ghostty에서 그대로 가져오므로 속도는 동일하다. cmux는 그 위에 워크스페이스 관리, 알림, 브라우저 통합, CLI 자동화 레이어를 올린 것이다. 통신은 UNIX 도메인 소켓을 통해 이루어지며, 각 패인에 CMUX_SOCKET_PATH 환경 변수가 자동으로 주입된다.\n기존 Ghostty 사용자라면 별도로 Ghostty를 설치할 필요가 없다. cmux가 libghostty를 자체 번들하고 있다. 동시에, Ghostty와 cmux를 함께 설치해도 충돌이 없다.\n설치 및 초기 설정 Homebrew 설치 brew tap manaflow-ai/cmux \u0026amp;\u0026amp; brew install --cask cmux 또는 공식 사이트에서 DMG를 직접 다운로드할 수 있다.\nCLI 심링크 설정 cmux CLI를 터미널 어디서든 사용하려면 심링크를 설정한다.\nsudo ln -sf /Applications/cmux.app/Contents/MacOS/cmux-cli /usr/local/bin/cmux 이 설정 없이도 GUI는 정상 동작하지만, cmux send, cmux read-screen 같은 CLI 자동화 기능을 사용하려면 필수다.\nGhostty 설정 호환 cmux는 기존 Ghostty 설정 파일을 그대로 읽는다.\n~/.config/ghostty/config 폰트, 테마, 색상 설정이 자동으로 적용된다. Ghostty를 사용하던 환경이라면 별도 설정 없이 동일한 터미널 환경을 얻을 수 있다. Ghostty를 사용하지 않았더라도 cmux의 기본 설정으로 바로 시작할 수 있다.\nCLI 설치 확인 # CLI가 정상 설치되었는지 확인 cmux identify --json # 환경 변수 확인 env | grep CMUX cmux identify는 현재 워크스페이스, 서피스, 패인의 ID를 출력한다. cmux 터미널 안에서 실행해야 정상 동작한다.\n트러블슈팅 증상 원인 해결 cmux: command not found CLI 심링크 미설정 sudo ln -sf 명령 실행 소켓 연결 오류 cmux 앱이 실행 중이 아님 cmux.app을 먼저 실행 Ghostty 설정 충돌 호환되지 않는 설정 키 cmux 전용 설정으로 분리 폰트가 다르게 보임 Ghostty config 경로 불일치 ~/.config/ghostty/config 확인 핵심 개념: 계층 구조 cmux의 계층 구조는 건물 비유로 이해하면 쉽다.\ngraph TD W[\"Window \u0026lt;br/\u0026gt; macOS 윈도우 = 건물\"] --\u003e WS1[\"Workspace 1 \u0026lt;br/\u0026gt; = 층 \u0026lt;br/\u0026gt; git branch, PR, ports\"] W --\u003e WS2[\"Workspace 2 \u0026lt;br/\u0026gt; = 층\"] WS1 --\u003e S1[\"Surface 1 \u0026lt;br/\u0026gt; = 책상 (탭)\"] WS1 --\u003e S2[\"Surface 2 \u0026lt;br/\u0026gt; = 책상 (탭)\"] S1 --\u003e P1[\"Pane A \u0026lt;br/\u0026gt; = 방 (분할 영역)\"] S1 --\u003e P2[\"Pane B \u0026lt;br/\u0026gt; = 방 (분할 영역)\"] S1 --\u003e P3[\"Browser Pane \u0026lt;br/\u0026gt; = 방 (브라우저)\"] S2 --\u003e P4[\"Pane C\"] S2 --\u003e P5[\"Pane D\"] 계층 비유 설명 Window 건물 macOS 윈도우. 보통 하나만 사용 Workspace 층 독립적인 작업 컨텍스트. 사이드바 탭으로 표시. git branch, PR 상태, 포트, 알림 메타데이터 포함 Surface 책상 워크스페이스 안의 탭. 여러 패인을 포함 Pane 방 실제 터미널 또는 브라우저가 실행되는 분할 영역 tmux의 Session \u0026gt; Window \u0026gt; Pane과 대응되지만, cmux는 각 워크스페이스에 메타데이터를 연결한다는 점이 결정적 차이다. 사이드바를 한 번 보는 것만으로 각 프로젝트의 git 브랜치, 관련 PR 번호, 현재 열려 있는 포트, 최근 알림 내용을 한눈에 파악할 수 있다.\n환경 변수 cmux는 각 패인에 자동으로 환경 변수를 주입한다.\n변수 용도 CMUX_WORKSPACE_ID 현재 패인이 속한 워크스페이스 ID CMUX_SURFACE_ID 현재 패인이 속한 서피스 ID CMUX_SOCKET_PATH cmux 소켓 경로 — CLI 통신에 사용 에이전트가 CMUX_WORKSPACE_ID를 읽으면 자신이 어떤 프로젝트에서 실행 중인지 자동으로 인식할 수 있다. 별도로 프로젝트 경로를 파라미터로 전달할 필요가 없다.\n워크스페이스 관리 워크스페이스는 cmux의 최상위 작업 단위다. 사이드바에 수직 탭으로 표시되며, 각 탭에는 다음 메타데이터가 실시간으로 갱신된다.\nGit 브랜치명: 현재 체크아웃된 브랜치 PR 상태/번호: 해당 브랜치와 연관된 Pull Request 작업 디렉토리: 현재 경로 열린 포트: localhost:3000, localhost:8080 등 최근 알림 텍스트: 마지막 알림 내용 미리보기 Firefox의 수직 탭을 터미널에 적용한 것과 유사한 UX다. 한 번에 5~6개 프로젝트를 오가는 상황에서 탭 제목만으로 컨텍스트를 파악할 수 있다.\n워크스페이스 단축키 동작 단축키 새 워크스페이스 ⌘N 워크스페이스 전환 ⌘1 ~ ⌘8 이름 변경 ⌘⇧R 닫기 ⌘⇧W CLI로 워크스페이스 관리 # 새 워크스페이스 생성 cmux new-workspace --name \u0026#34;my-project\u0026#34; # 워크스페이스 목록 조회 cmux list-workspaces # 현재 워크스페이스 정보 확인 cmux identify --json cmux identify --json의 출력 예시:\n{ \u0026#34;workspace_id\u0026#34;: \u0026#34;ws-abc123\u0026#34;, \u0026#34;surface_id\u0026#34;: \u0026#34;sf-def456\u0026#34;, \u0026#34;pane_id\u0026#34;: \u0026#34;pn-ghi789\u0026#34; } 이 ID들은 cmux send, cmux read-screen 등에서 대상 패인을 지정할 때 사용한다.\n서피스와 패인 서피스 (Surface) 서피스는 워크스페이스 안의 탭이다. 하나의 워크스페이스에 여러 서피스를 두고, 각 서피스에서 서로 다른 작업 맥락을 유지할 수 있다.\n동작 단축키 새 서피스 ⌘T 다음 서피스 ⌘⇧] 이전 서피스 ⌘⇧[ 서피스 닫기 ⌘W 패인 (Pane) 패인은 서피스를 수평/수직으로 분할한 영역이다. 각 패인에서 독립적인 터미널 세션 또는 브라우저가 실행된다.\n동작 단축키 오른쪽 분할 ⌘D 아래쪽 분할 ⌘⇧D 패인 이동 (왼쪽) ⌥⌘← 패인 이동 (오른쪽) ⌥⌘→ 패인 이동 (위) ⌥⌘↑ 패인 이동 (아래) ⌥⌘↓ 핵심 차이: prefix 키가 없다. tmux는 Ctrl+b를 먼저 누르고 명령 키를 입력해야 하지만, cmux는 macOS 네이티브 단축키를 그대로 사용한다. ⌘D로 바로 분할, ⌥⌘→로 바로 이동. iTerm2나 VS Code 터미널에 익숙한 사용자라면 학습 곡선이 거의 없다.\nCLI로 패인 관리 # 오른쪽으로 분할 cmux split --direction right # 아래쪽으로 분할 cmux split --direction down # 특정 패인에 명령 전송 cmux send --pane-id \u0026lt;target-pane-id\u0026gt; \u0026#34;npm run dev\u0026#34; 알림 시스템 cmux의 알림 시스템은 다층 구조다. AI 에이전트를 동시에 여러 개 돌릴 때, \u0026ldquo;어떤 에이전트가 입력을 기다리고 있는가\u0026quot;라는 질문에 대한 답을 즉시 제공하도록 설계되었다.\n4단계 알림 패인 알림 링 (파란 링): 입력을 대기 중인 패인 주변에 파란색 링이 표시된다. 현재 보고 있는 서피스에서 어느 패인이 주의를 필요로 하는지 즉시 알 수 있다.\n사이드바 unread 뱃지: 다른 워크스페이스에서 알림이 발생하면 사이드바 탭에 읽지 않은 알림 수가 표시된다. 현재 작업 중인 워크스페이스를 벗어나지 않고도 다른 프로젝트의 상태를 확인할 수 있다.\n앱 내 알림 패널: ⌘I로 알림 패널을 열면 모든 알림을 시간순으로 확인할 수 있다. 어떤 워크스페이스, 어떤 패인에서 발생한 알림인지 컨텍스트가 함께 표시된다.\nmacOS 데스크톱 알림: cmux를 포커스하고 있지 않을 때도 macOS 알림 센터에 알림이 뜬다. 브라우저에서 다른 작업을 하다가도 에이전트가 입력을 기다리면 알 수 있다.\n알림 단축키 동작 단축키 알림 패널 열기 ⌘I 가장 최근 unread로 점프 ⌘⇧U ⌘⇧U는 특히 유용하다. 5개 워크스페이스에서 에이전트를 돌리고 있을 때, 이 단축키 하나로 가장 최근에 입력을 요청한 에이전트의 패인으로 즉시 이동한다.\n표준 이스케이프 시퀀스 지원 cmux의 알림은 표준 터미널 이스케이프 시퀀스(OSC 9, OSC 99, OSC 777)를 사용한다. 별도의 플러그인이나 설정 없이, 이 시퀀스를 출력하는 모든 도구가 자동으로 cmux 알림을 트리거한다.\nCLI로 알림 전송 # 커스텀 알림 보내기 cmux notify --title \u0026#34;Build done\u0026#34; --body \u0026#34;Success\u0026#34; # CI/CD 스크립트에서 활용 npm run build \u0026amp;\u0026amp; cmux notify --title \u0026#34;Build\u0026#34; --body \u0026#34;Build succeeded\u0026#34; \\ || cmux notify --title \u0026#34;Build\u0026#34; --body \u0026#34;Build FAILED\u0026#34; # 장시간 작업 완료 알림 python train_model.py \u0026amp;\u0026amp; cmux notify --title \u0026#34;Training\u0026#34; --body \u0026#34;Model training complete\u0026#34; 이 기능은 Claude Code hooks와도 결합할 수 있다. 에이전트가 특정 작업을 완료하면 자동으로 알림을 보내도록 설정하는 것이다.\nread-screen과 send: 에이전트 간 통신 이 두 기능이 cmux를 단순한 터미널 앱에서 에이전트 통신 플랫폼으로 만드는 핵심 차별점이다.\nread-screen 한 패인에서 다른 패인의 터미널 출력을 읽을 수 있다.\n# 대상 패인의 현재 화면 내용 읽기 cmux read-screen --pane-id \u0026lt;target-pane-id\u0026gt; 이 명령은 지정된 패인에 현재 표시된 텍스트 내용을 반환한다. 에이전트 A가 에이전트 B의 출력을 읽고, 그 결과에 따라 다음 행동을 결정할 수 있다.\n실전 활용 시나리오 # 에이전트 A: 다른 패인의 테스트 결과 확인 TEST_OUTPUT=$(cmux read-screen --pane-id $TEST_PANE_ID) if echo \u0026#34;$TEST_OUTPUT\u0026#34; | grep -q \u0026#34;FAIL\u0026#34;; then echo \u0026#34;테스트 실패 감지 — 수정 시작\u0026#34; fi # 에이전트 B: 빌드 서버 상태 모니터링 BUILD_STATUS=$(cmux read-screen --pane-id $BUILD_PANE_ID) if echo \u0026#34;$BUILD_STATUS\u0026#34; | grep -q \u0026#34;compiled successfully\u0026#34;; then cmux notify --title \u0026#34;Build\u0026#34; --body \u0026#34;빌드 성공\u0026#34; fi tmux의 capture-pane과 유사하지만, cmux의 read-screen은 에이전트 간 통신이라는 명확한 의도를 가지고 설계되었다. 환경 변수로 패인 ID가 자동 주입되므로, 에이전트가 자기 자신의 ID와 이웃 패인의 ID를 프로그래밍 방식으로 파악할 수 있다.\nsend 다른 패인에 명령을 프로그래밍 방식으로 전송한다.\n# 특정 패인에 명령 전송 cmux send --pane-id \u0026lt;target-pane-id\u0026gt; \u0026#34;npm run test\u0026#34; # 현재 서피스에 명령 전송 cmux send --surface-id \u0026lt;target-surface-id\u0026gt; \u0026#34;cd ~/projects/my-app\u0026#34; # 여러 패인에 순차적으로 명령 전송 cmux send --pane-id $PANE_1 \u0026#34;git pull\u0026#34; cmux send --pane-id $PANE_2 \u0026#34;npm install\u0026#34; cmux send --pane-id $PANE_3 \u0026#34;docker compose up -d\u0026#34; read-screen + send 조합 두 기능을 조합하면, 에이전트가 다른 에이전트의 상태를 읽고 그에 따라 명령을 보내는 자율적 워크플로우가 가능하다.\n# 에이전트 A: 빌드 패인 상태 확인 후 다음 단계 진행 while true; do STATUS=$(cmux read-screen --pane-id $BUILD_PANE) if echo \u0026#34;$STATUS\u0026#34; | grep -q \u0026#34;ready on\u0026#34;; then cmux send --pane-id $TEST_PANE \u0026#34;npm run e2e\u0026#34; cmux notify --title \u0026#34;Pipeline\u0026#34; --body \u0026#34;E2E 테스트 시작\u0026#34; break fi sleep 2 done 내장 브라우저 cmux는 터미널과 같은 창에서 브라우저 패인을 열 수 있다. PR 페이지를 옆에 띄워놓고 Claude Code가 코드를 수정하거나, localhost 개발 서버의 결과를 바로 확인하는 워크플로우다.\n기본 사용법 # 독립 브라우저 창 열기 cmux browser open http://localhost:3000 # 현재 서피스에 브라우저 분할 패인으로 열기 cmux browser open-split http://localhost:3000 # 현재 브라우저 패인의 URL 이동 cmux browser navigate https://github.com/my/repo/pull/42 # 뒤로/앞으로 이동 cmux browser back cmux browser forward # 새로고침 cmux browser reload # 현재 URL 확인 cmux browser url open-split이 핵심이다. 터미널 분할의 한쪽에 브라우저가 들어가므로, 화면을 벗어나지 않고 코드와 결과를 동시에 볼 수 있다.\n브라우저 자동화 상세 cmux 내장 브라우저는 단순 뷰어가 아니다. Playwright 수준의 풀 자동화 API를 제공한다.\n대기 (Wait) 페이지 로딩, 요소 렌더링, URL 변경 등을 기다릴 수 있다.\n# CSS 셀렉터로 요소 대기 cmux browser wait --selector \u0026#34;.login-form\u0026#34; # 텍스트 출현 대기 cmux browser wait --text \u0026#34;Dashboard loaded\u0026#34; # URL 변경 대기 cmux browser wait --url-contains \u0026#34;/dashboard\u0026#34; # 페이지 로드 상태 대기 cmux browser wait --load-state networkidle # JavaScript 함수 결과 대기 cmux browser wait --function \u0026#34;document.readyState === \u0026#39;complete\u0026#39;\u0026#34; DOM 조작 # 클릭 cmux browser click --selector \u0026#34;#submit-button\u0026#34; # 더블 클릭 cmux browser dblclick --selector \u0026#34;.editable-cell\u0026#34; # 호버 cmux browser hover --selector \u0026#34;.dropdown-trigger\u0026#34; # 포커스 cmux browser focus --selector \u0026#34;#email-input\u0026#34; # 체크박스 토글 cmux browser check --selector \u0026#34;#agree-terms\u0026#34; # 텍스트 입력 (keystroke 방식) cmux browser type --selector \u0026#34;#search\u0026#34; --text \u0026#34;query\u0026#34; # 텍스트 채우기 (값 직접 설정) cmux browser fill --selector \u0026#34;#email\u0026#34; --text \u0026#34;user@example.com\u0026#34; # 키 입력 cmux browser press --key \u0026#34;Enter\u0026#34; # 셀렉트 박스 옵션 선택 cmux browser select --selector \u0026#34;#country\u0026#34; --value \u0026#34;KR\u0026#34; # 스크롤 cmux browser scroll --selector \u0026#34;.content\u0026#34; --direction down 정보 추출 (Inspection) # 페이지 스냅샷 (접근성 트리 기반) cmux browser snapshot # 스크린샷 캡처 cmux browser screenshot --output /tmp/page.png # 텍스트 추출 cmux browser get text --selector \u0026#34;.result-count\u0026#34; # HTML 추출 cmux browser get html --selector \u0026#34;.article-body\u0026#34; # 입력 필드 값 추출 cmux browser get value --selector \u0026#34;#price-input\u0026#34; # 속성 값 추출 cmux browser get attr --selector \u0026#34;img.logo\u0026#34; --attr \u0026#34;src\u0026#34; # 요소 개수 확인 cmux browser get count --selector \u0026#34;.list-item\u0026#34; # 요소 상태 확인 cmux browser is visible --selector \u0026#34;.modal\u0026#34; cmux browser is enabled --selector \u0026#34;#submit\u0026#34; cmux browser is checked --selector \u0026#34;#newsletter\u0026#34; # 요소 찾기 cmux browser find role --role \u0026#34;button\u0026#34; cmux browser find text --text \u0026#34;Submit\u0026#34; cmux browser find label --label \u0026#34;Email address\u0026#34; # 페이지 제목/URL 가져오기 cmux browser get title cmux browser get url JavaScript 실행 # JavaScript 코드 실행 cmux browser eval \u0026#34;document.querySelectorAll(\u0026#39;.item\u0026#39;).length\u0026#34; # 초기화 스크립트 추가 (페이지 로드 전 실행) cmux browser addinitscript \u0026#34;window.__TEST_MODE = true\u0026#34; # 외부 스크립트 추가 cmux browser addscript --url \u0026#34;https://cdn.example.com/helper.js\u0026#34; # 커스텀 스타일 추가 cmux browser addstyle \u0026#34;body { background: #f0f0f0; }\u0026#34; 상태 관리 # 쿠키 확인 cmux browser cookies # 로컬 스토리지 확인 cmux browser storage # 브라우저 세션 상태 저장 (쿠키, 스토리지 포함) cmux browser state --save /tmp/browser-state.json # 저장된 상태 복원 cmux browser state --load /tmp/browser-state.json 상태 저장/복원은 인증 세션을 유지할 때 유용하다. 한 번 로그인한 후 상태를 저장해 두면, 자동화 스크립트에서 로그인 과정을 반복하지 않아도 된다.\n탭 관리 # 열린 탭 목록 cmux browser tab list # 특정 탭으로 전환 cmux browser tab switch --index 2 자동화 패턴 예시 실전에서 자주 사용하는 브라우저 자동화 패턴이다.\n패턴 1: 네비게이션 후 대기, 정보 추출 cmux browser navigate https://github.com/my/repo/pull/42 cmux browser wait --selector \u0026#34;.merge-message\u0026#34; PR_STATUS=$(cmux browser get text --selector \u0026#34;.State\u0026#34;) echo \u0026#34;PR 상태: $PR_STATUS\u0026#34; 패턴 2: 폼 작성 후 검증 cmux browser fill --selector \u0026#34;#title\u0026#34; --text \u0026#34;Fix: resolve memory leak\u0026#34; cmux browser fill --selector \u0026#34;#body\u0026#34; --text \u0026#34;Closes #123\u0026#34; cmux browser click --selector \u0026#34;#create-pr\u0026#34; cmux browser wait --text \u0026#34;Pull request created\u0026#34; 패턴 3: 실패 시 디버그 아티팩트 캡처 cmux browser click --selector \u0026#34;#deploy-button\u0026#34; cmux browser wait --text \u0026#34;Deployed\u0026#34; || { cmux browser screenshot --output /tmp/deploy-failure.png cmux browser snapshot \u0026gt; /tmp/deploy-failure-dom.txt cmux notify --title \u0026#34;Deploy\u0026#34; --body \u0026#34;배포 실패 — 스크린샷 저장됨\u0026#34; } CLI 자동화 전체 명령 레퍼런스 cmux CLI는 cmux 앱의 모든 기능을 프로그래밍 방식으로 제어할 수 있게 한다.\n워크스페이스 관리 명령 설명 cmux new-workspace --name \u0026quot;name\u0026quot; 새 워크스페이스 생성 cmux list-workspaces 워크스페이스 목록 조회 cmux identify 현재 패인의 워크스페이스/서피스/패인 ID 출력 cmux identify --json JSON 형식으로 ID 출력 패인 및 분할 명령 설명 cmux split --direction right 오른쪽으로 분할 cmux split --direction down 아래쪽으로 분할 통신 명령 설명 cmux send \u0026quot;command\u0026quot; 현재 패인에 명령 전송 cmux send --pane-id ID \u0026quot;command\u0026quot; 특정 패인에 명령 전송 cmux send --surface-id ID \u0026quot;command\u0026quot; 특정 서피스에 명령 전송 cmux read-screen 현재 패인의 화면 읽기 cmux read-screen --pane-id ID 특정 패인의 화면 읽기 알림 명령 설명 cmux notify --title \u0026quot;T\u0026quot; --body \u0026quot;B\u0026quot; 알림 전송 브라우저 명령 설명 cmux browser open URL 브라우저 열기 cmux browser open-split URL 분할 패인으로 브라우저 열기 cmux browser navigate URL URL 이동 cmux browser snapshot 페이지 스냅샷 cmux browser screenshot 스크린샷 cmux browser click --selector S 요소 클릭 cmux browser wait --selector S 요소 대기 cmux browser eval \u0026quot;JS\u0026quot; JavaScript 실행 환경 변수 모든 cmux 패인에는 다음 환경 변수가 자동 주입된다.\nCMUX_WORKSPACE_ID=ws-abc123 CMUX_SURFACE_ID=sf-def456 CMUX_SOCKET_PATH=/tmp/cmux-socket-xyz 스크립트에서 이 변수들을 활용하면 하드코딩 없이 현재 컨텍스트를 자동으로 인식할 수 있다.\n멀티 에이전트 워크플로우 cmux의 진가는 여러 AI 에이전트를 동시에 관리할 때 나타난다. 아래는 실전 멀티 에이전트 셋업 스크립트다.\n프로젝트 셋업 자동화 #!/bin/bash # cmux 멀티 에이전트 워크플로우 셋업 스크립트 # 1. 프로젝트 워크스페이스 생성 cmux new-workspace --name \u0026#34;my-project\u0026#34; # 2. 메인 에이전트 패인에서 프로젝트 디렉토리로 이동 cmux send \u0026#34;cd ~/projects/my-app\u0026#34; # 3. 오른쪽에 두 번째 에이전트용 패인 분할 cmux split --direction right # 4. 두 번째 패인에서 개발 서버 실행 cmux send --surface-id right \u0026#34;npm run dev\u0026#34; # 5. 브라우저 분할로 localhost 결과 확인 cmux browser open-split http://localhost:3000 Claude Code 멀티 에이전트 패턴 # 워크스페이스 1: 백엔드 에이전트 cmux new-workspace --name \u0026#34;backend\u0026#34; cmux send \u0026#34;cd ~/projects/api \u0026amp;\u0026amp; claude\u0026#34; # 워크스페이스 2: 프론트엔드 에이전트 cmux new-workspace --name \u0026#34;frontend\u0026#34; cmux send \u0026#34;cd ~/projects/web \u0026amp;\u0026amp; claude\u0026#34; # 워크스페이스 3: 테스트 에이전트 cmux new-workspace --name \u0026#34;testing\u0026#34; cmux send \u0026#34;cd ~/projects/api \u0026amp;\u0026amp; claude\u0026#34; # 이제 사이드바에서 3개 워크스페이스를 한눈에 볼 수 있다. # 각 워크스페이스의 git 브랜치, PR 상태, 알림이 표시된다. # ⌘⇧U로 입력을 기다리는 에이전트로 즉시 점프한다. 에이전트 간 협업 워크플로우 # 패인 A: Claude Code가 코드 수정 중 # 패인 B: 테스트 러너 # 패인 B의 스크립트 — 패인 A의 완료를 감지하고 테스트 실행 AGENT_PANE=$1 # 패인 A의 ID while true; do SCREEN=$(cmux read-screen --pane-id $AGENT_PANE) # Claude Code가 작업 완료하면 프롬프트가 다시 나타남 if echo \u0026#34;$SCREEN\u0026#34; | grep -q \u0026#34;claude\u0026gt;\u0026#34;; then cmux notify --title \u0026#34;Agent\u0026#34; --body \u0026#34;코드 수정 완료 — 테스트 시작\u0026#34; npm run test break fi sleep 5 done 세션 복원 cmux는 앱을 종료했다가 다시 열면 이전 상태를 복원한다.\n복원되는 항목 워크스페이스 레이아웃 (분할 구조, 패인 배치) 워크스페이스 메타데이터 (이름, git 브랜치 등) 각 패인의 작업 디렉토리 브라우저 패인의 URL 복원되지 않는 항목 실행 중인 프로세스: Claude Code 세션, npm run dev 같은 라이브 프로세스는 복원되지 않는다. 이것은 tmux와의 핵심 차이점이다 — tmux는 서버가 살아있는 한 세션이 유지되지만, cmux는 프로세스를 다시 시작해야 한다. tmux 세션: cmux 안에서 tmux를 실행했다면, tmux 세션 자체는 tmux 서버에서 관리하므로 별도로 유지된다. 프로세스 영속성이 중요한 경우, cmux 안에서 tmux를 함께 사용하는 것이 현실적인 대안이다.\n\u0026ldquo;Primitive, Not Solution\u0026rdquo; 철학 cmux의 핵심 설계 철학은 **\u0026ldquo;Primitive, Not Solution\u0026rdquo;**이다.\nSolution 접근: \u0026ldquo;Claude Code 3개를 동시에 돌리는 UI를 만들어 준다\u0026rdquo; Primitive 접근: \u0026ldquo;read-screen, send, 알림, 브라우저 API라는 블록을 제공하니, 원하는 워크플로우를 직접 조립해라\u0026rdquo; 이 철학은 여러 장점을 가진다.\n도구 독립성: Claude Code뿐 아니라 Cursor, Windsurf, Codex, Gemini CLI 등 어떤 AI 에이전트와도 결합할 수 있다. 워크플로우 유연성: 미리 정해진 워크플로우에 갇히지 않는다. 팀마다 프로젝트마다 다른 방식으로 조합할 수 있다. 미래 호환성: 새로운 AI 도구가 나와도 기존 primitive들을 그대로 활용할 수 있다. 반면 단점도 있다. 초기 설정이 다소 복잡하고, 최적의 워크플로우를 찾기까지 시행착오가 필요하다. 이 점은 Claude Squad처럼 \u0026ldquo;완성된 솔루션\u0026quot;을 제공하는 도구와 비교했을 때 진입 장벽이 된다.\n경쟁 도구 현황 AI 에이전트 터미널 분야는 2025년 하반기부터 급격히 성장하고 있다.\n도구 접근 방식 특징 cmux Primitive 제공 네이티브 macOS, Ghostty 기반, read-screen, 브라우저 자동화 Claude Squad 에이전트 오케스트레이션 GitHub 기반, 에이전트 생명주기 관리에 초점 Pane AI 에이전트용 터미널 에이전트 상태 시각화 Amux AI 중심 멀티플렉서 tmux 대체를 목표 Calyx 신생 경쟁자 cmux와 다른 접근 방식, 빠르게 성장 중 커뮤니티 반응 Google DeepMind Research Director Edward Grefenstette, Dagster 창시자 Nick Schrock, HashiCorp 창시자 Mitchell Hashimoto 등이 긍정적 피드백을 남겼다. 일본 개발자 커뮤니티에서도 \u0026ldquo;Warp → Ghostty → cmux\u0026quot;로 이동했다는 반응이 나오고 있다.\nHacker News에서는 기능에 대한 관심과 함께 안정성에 대한 우려도 제기되었다. 업데이트 주기가 빠르고, macOS 전용이라는 점이 논점이 되었다.\n실제 사용 후기에서 가장 많이 언급되는 워크플로우:\n\u0026ldquo;수직 탭 하나에 WIP 작업 하나. 안에서 Claude Code 한쪽, 브라우저에 PR과 리소스 한쪽. 작업 전환이 자연스럽다.\u0026rdquo;\n제한사항 cmux를 도입하기 전에 알아야 할 제한사항이다.\nmacOS 전용 macOS 14.0+ 에서만 동작한다. Linux나 Windows 지원 계획은 현재 없다. 다만, AI 코딩 에이전트를 로컬에서 돌리는 워크플로우가 주로 macOS 환경에서 이루어지는 현실을 감안하면, 당장의 치명적 제약은 아니다.\n프로세스 영속성 없음 앱을 종료하면 실행 중인 프로세스가 사라진다. 레이아웃과 메타데이터는 복원되지만, Claude Code 세션이나 개발 서버는 다시 시작해야 한다. 이것이 tmux 대비 가장 큰 구조적 약점이다.\n빠른 업데이트 주기 활발한 개발이 진행 중이므로 API와 기능이 빈번하게 변경될 수 있다. 자동화 스크립트를 작성할 때 버전 의존성을 고려해야 한다.\n안정성 HN에서 안정성 우려가 제기된 바 있다. 프로덕션 워크플로우의 핵심 도구로 사용하기 전에 충분한 테스트가 필요하다.\nFAQ 질문 답변 cmux는 유료인가? 아니다. AGPL 라이선스로 완전 무료다 Ghostty를 따로 설치해야 하나? 아니다. libghostty가 번들되어 있다 tmux와 함께 쓸 수 있나? 된다. cmux 안에서 tmux를 실행할 수 있다 SSH 접속에 사용할 수 있나? cmux 패인에서 SSH를 실행할 수 있지만, cmux 자체는 원격 서버에 설치할 수 없다 빠른 링크 cmux 공식 사이트 — 문서, 다운로드, 튜토리얼 cmux 공식 문서 — 개념 — 핵심 개념 정리 cmux 공식 문서 — 시작하기 — 설치부터 기본 사용법 cmux GitHub — 소스 코드 및 이슈 트래커 cmux Homebrew — brew install --cask cmux AI 코딩 에이전트 전용 터미널 cmux 소개 (daleseo.com) — 상세 사용 가이드 cmux 분석 (goddaehee) — 설치부터 경쟁 도구까지 AI 코딩 에이전트 전용 터미널 cmux 소개 영상 — 개발동생 채널 tmux vs cmux 비교 분석 — tmux와의 상세 비교 인사이트 cmux의 포지션은 명확하다 — 터미널 렌더링은 해결된 문제로 취급하고(libghostty), 그 위의 에이전트 UX 레이어에 집중한다. GPU 가속 렌더링이라는 어려운 문제를 Ghostty 라이브러리에 위임하고, cmux는 워크스페이스 메타데이터, 다층 알림, inter-agent 통신, 브라우저 자동화에 역량을 쏟는다.\n특히 read-screen + send 조합은 에이전트 간 \u0026ldquo;대화\u0026quot;를 가능하게 한다는 점에서 주목할 만하다. 에이전트 A가 에이전트 B의 출력을 읽고 반응하는 것은 단순 멀티플렉싱을 넘어선, 에이전트 오케스트레이션의 기초 인프라다.\n브라우저 자동화 API의 깊이도 인상적이다. navigate → wait → inspect, fill → click → verify, 실패 시 스크린샷 캡처까지 — Playwright 수준의 자동화를 터미널 CLI 한 줄로 실행할 수 있다. 에이전트가 웹 UI를 직접 조작하고 검증하는 워크플로우가 별도 도구 없이 cmux 안에서 완결된다.\n\u0026ldquo;Primitive, Not Solution\u0026rdquo; 철학은 양날의 검이다. 어떤 에이전트와도 결합할 수 있는 범용성을 얻지만, 초기 설정의 복잡함이라는 비용을 치른다. Calyx 같은 경쟁자가 더 opinionated한 솔루션으로 빠르게 치고 올라오고 있다는 점도 주시해야 한다.\n아직 macOS 전용이고 프로세스 영속성이 없다는 구조적 제약이 있지만, AI 에이전트 중심 개발 환경이 macOS 위에서 주로 이루어지는 현실, 그리고 커뮤니티의 빠른 성장세를 감안하면 cmux는 이 분야에서 가장 완성도 높은 도구로 자리잡고 있다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-cmux-terminal/cover.jpg","permalink":"/ko/posts/2026-03-16-cmux-terminal/","title":"cmux — AI 에이전트 시대를 위해 설계된 macOS 네이티브 터미널"},{"content":"개요 소규모 팀에서 마케팅 콘텐츠를 만들 때 가장 큰 병목은 \u0026ldquo;브랜드 톤을 일관되게 유지하면서 빠르게 여러 채널용 에셋을 뽑아내는 것\u0026quot;이다. Pomelli는 Google Labs에서 공개한 AI 마케팅 도구로, 웹사이트 URL 하나만 입력하면 브랜드 DNA를 자동 추출하고 캠페인 크리에이티브를 생성한다.\n3단계 워크플로우 graph TD A[\"1. 웹사이트 URL 입력\"] --\u003e B[\"Pomelli가 사이트 분석 \u0026lt;br/\u0026gt; 문구, 시각 요소, 컬러\"] B --\u003e C[\"Business DNA 생성 \u0026lt;br/\u0026gt; 톤, 폰트, 이미지 스타일\"] C --\u003e D[\"2. 캠페인 아이디어 제안\"] D --\u003e E[\"사용자가 선택 또는 \u0026lt;br/\u0026gt; 직접 프롬프트 입력\"] E --\u003e F[\"3. 채널별 크리에이티브 생성\"] F --\u003e G[\"인앱 편집 \u0026lt;br/\u0026gt; 문구/이미지 수정\"] G --\u003e H[\"다운로드 \u0026lt;br/\u0026gt; → 실제 채널 게시\"]Step 1: Business DNA 웹사이트 URL을 입력하면 Pomelli가 사이트의 문구와 시각 요소를 분석해 브랜드 프로필(Business DNA)을 만든다. 여기에는 브랜드 톤(문장 분위기), 폰트 느낌, 이미지 스타일, 컬러 팔레트가 포함된다.\n중요한 점은 Pomelli가 **\u0026ldquo;내가 원하는 브랜드\u0026quot;가 아닌 \u0026ldquo;웹에 드러난 브랜드\u0026rdquo;**를 따라간다는 것이다. 사이트가 오래됐거나 페이지마다 톤이 다르면, 그 혼란까지 학습한다. 시작 전에 대표 페이지를 정리해두는 것이 좋다.\nStep 2: 캠페인 아이디어 Business DNA가 만들어지면 브랜드에 맞는 캠페인 주제를 제안한다. 직접 프롬프트를 입력할 수도 있다. 프롬프트는 **\u0026ldquo;대상 고객 + 제안 가치 + 행동\u0026rdquo;**처럼 짧고 명확하게 적는 것이 효과적이다. 예: \u0026ldquo;처음 방문 고객에게 10% 할인, 예약 링크 클릭 유도\u0026rdquo;\nStep 3: 크리에이티브 생성 \u0026amp; 편집 소셜, 웹, 광고 등 채널별 에셋을 생성하고, 인앱에서 문구와 이미지를 수정한 뒤 다운로드한다. 자동 게시까지는 하지 않고 초안 생성 → 사람의 최종 결정 워크플로우다.\n활용 시나리오 시나리오 예시 Pomelli의 역할 시즌 캠페인 봄 한정 메뉴 출시 카페 브랜드 톤으로 Instagram 피드 이미지 + 캡션 변주 신제품 런칭 \u0026ldquo;무설탕, 7일 체험\u0026rdquo; 런칭 공지 → 후기 요청 → 재방문 유도 게시물 세트 예약/상담 유도 미용실, 피트니스 헤드라인 + CTA 문구를 여러 톤으로 → A/B 테스트 초안 채용 브랜딩 팀 가치/일하는 방식 브랜드 톤 유지한 채용 크리에이티브 재활성화 휴면 고객 재유입 할인 코드 + 복귀 메시지를 다양한 각도로 생성 특히 반복 변주를 빠르게 해주는 것이 강점이다. 같은 캠페인 주제로 톤(캐주얼/프리미엄)을 바꿔가며 여러 버전을 뽑아볼 수 있다.\n주의사항 Business DNA가 현재 브랜드와 맞는지 먼저 확인 (웹사이트가 오래됐다면 결과도 오래된 톤) 제품명, 가격, 할인 조건 등 사실 정보는 반드시 사람이 재검증 건강, 금융, 교육 분야는 과장 광고 여부와 표기 의무 확인 필수 Google Labs의 공개 베타 — 품질이 들쭉날쭉할 수 있고, 제공 지역과 언어가 제한될 수 있음 \u0026ldquo;Pomodoro 타이머\u0026quot;와 이름이 비슷하지만, 시간관리 도구가 아닌 마케팅 도구 인사이트 Pomelli가 해결하는 핵심 문제는 **\u0026ldquo;매번 프롬프트로 브랜드 가이드를 설명하지 않아도 되는 것\u0026rdquo;**이다. 일반 AI 도구에 \u0026ldquo;우리 브랜드 톤은 캐주얼하면서도 전문적이고\u0026hellip;\u0026ldquo;라고 매번 설명하는 대신, 웹사이트에서 자동 추출한 프로필을 기반으로 일관된 결과를 낸다. 이 접근은 Claude의 CLAUDE.md나 Cursor의 .cursorrules와 동일한 패턴이다 — 컨텍스트를 매번 전달하는 대신 한 번 설정하고 재사용하는 것. Google이 SMB 마케팅 도구에 이 패턴을 적용한 것이 흥미롭다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-google-pomelli/cover.jpg","permalink":"/ko/posts/2026-03-16-google-pomelli/","title":"Google Pomelli — 웹사이트 URL 하나로 온브랜드 마케팅 콘텐츠를 만드는 AI 도구"},{"content":"개요 Claude Code를 본격적으로 사용하면 세션이 수십 개씩 쌓인다. api-refactor, debug-pipeline, write-tests — 각각 다른 tmux 세션에서 돌아가는데, 어떤 에이전트가 입력을 기다리고 있고 어떤 에이전트가 작업 중인지 한눈에 파악하기 어렵다. recon은 이 문제를 해결하는 tmux 네이티브 대시보드다.\n아키텍처: tmux 위의 TUI graph TD A[\"tmux 서버\"] --\u003e B[\"세션: api-refactor \u0026lt;br/\u0026gt; Claude Code\"] A --\u003e C[\"세션: debug-pipeline \u0026lt;br/\u0026gt; Claude Code\"] A --\u003e D[\"세션: write-tests \u0026lt;br/\u0026gt; Claude Code\"] B --\u003e E[\"recon TUI\"] C --\u003e E D --\u003e E E --\u003e F[\"tmux list-panes \u0026lt;br/\u0026gt; PID, 세션 이름\"] E --\u003e G[\"~/.claude/sessions/ \u0026lt;br/\u0026gt; PID.json\"] E --\u003e H[\"tmux capture-pane \u0026lt;br/\u0026gt; 상태 바 텍스트\"]recon은 Rust로 작성되었으며(98K줄), 각 Claude Code 인스턴스가 자체 tmux 세션에서 실행되는 구조를 전제로 한다. 상태 감지는 tmux 패인 하단의 상태 바 텍스트를 읽는 방식으로 동작한다:\n상태 바 텍스트 상태 의미 esc to interrupt Working 응답 스트리밍 또는 도구 실행 중 Esc to cancel Input 권한 승인 대기 — 사용자 개입 필요 기타 Idle 다음 프롬프트 대기 (0 tokens) New 아직 인터랙션 없음 세션 매칭은 ~/.claude/sessions/{PID}.json 파일을 사용한다. ps 파싱이나 CWD 기반 휴리스틱이 아닌 Claude Code가 직접 쓰는 파일을 읽으므로 정확하다.\n두 가지 뷰 Table View (기본) ┌─ recon — Claude Code Sessions ─────────────────────────────────────┐ │ # Session Git(Branch) Status Model Context │ │ 1 api-refactor feat/auth ● Input Opus 4.6 45k/1M │ │ 2 debug-pipeline main ● Work Sonnet 4.6 12k/200k │ │ 3 write-tests feat/auth ● Work Haiku 4.5 8k/200k │ │ 4 code-review pr-452 ● Idle Sonnet 4.6 90k/200k │ └────────────────────────────────────────────────────────────────────┘ Git 레포 이름과 브랜치, 모델명, 컨텍스트 사용량(45k/1M 형식)이 한눈에 보인다. Input 상태의 행은 하이라이트되어 즉시 주목할 수 있다.\nTamagotchi View 각 에이전트가 픽셀 아트 캐릭터로 표현된다. Working은 발이 달린 초록색 블롭, Input은 화난 오렌지색 블롭(깜빡임), Idle은 Zzz가 뜨는 파란 블롭, New는 알 형태다. 에이전트들은 작업 디렉토리별 \u0026ldquo;방\u0026quot;에 그룹화되며, 2×2 그리드로 페이지네이션된다.\n사이드 모니터에 띄워놓고 한눈에 어떤 에이전트가 일하고, 자고, 주의를 필요로 하는지 파악하는 용도로 설계되었다.\n주요 기능 라이브 상태: 2초마다 폴링, 증분 JSONL 파싱 Git 인식: 세션별 레포 이름과 브랜치 표시 컨텍스트 추적: 토큰 사용량을 used/available 형식으로 표시 (예: 45k/1M) 모델 표시: Claude 모델명과 effort level 표시 Resume picker: recon resume로 과거 세션 스캔, Enter로 재개 JSON 모드: recon --json으로 스크립팅 및 자동화 recon next: 다음 Input 상태 에이전트로 바로 점프 tmux 통합 # ~/.tmux.conf에 추가 bind g display-popup -E -w 80% -h 60% \u0026#34;recon\u0026#34; # prefix + g → 대시보드 bind n display-popup -E -w 80% -h 60% \u0026#34;recon new\u0026#34; # prefix + n → 새 세션 bind r display-popup -E -w 80% -h 60% \u0026#34;recon resume\u0026#34; # prefix + r → 재개 선택 bind i run-shell \u0026#34;recon next\u0026#34; # prefix + i → Input 에이전트로 점프 팝업 오버레이로 열리므로 현재 작업을 중단하지 않고 세션을 전환할 수 있다.\n설치 cargo install --path . tmux와 Claude Code가 설치되어 있어야 한다. 흥미로운 점은 recon 자체의 커밋 이력에 Co-Authored-By: Claude Opus 4.6이 포함되어 있다는 것이다 — Claude Code로 Claude Code 관리 도구를 만드는 메타적 구조다.\n인사이트 recon은 AI 코딩 에이전트의 \u0026ldquo;세션 관리\u0026rdquo; 문제를 tmux라는 검증된 인프라 위에서 해결한다. agentsview(웹 대시보드)나 agf(Fzf 기반 검색)와 달리, tmux 네이티브라는 점이 차별화 포인트다. 터미널을 떠나지 않고 모든 에이전트를 관리할 수 있으며, 다마고치 뷰는 기능적으로도 재미있지만 \u0026ldquo;에이전트의 상태를 직관적으로 인지\u0026quot;한다는 점에서 UI/UX적으로도 의미 있는 시도다. Claude Code를 동시에 3개 이상 돌리는 워크플로우에서 특히 유용할 것이다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-recon-claude-code-tmux/cover.jpg","permalink":"/ko/posts/2026-03-16-recon-claude-code-tmux/","title":"recon — Claude Code 에이전트를 다마고치처럼 관리하는 tmux 대시보드"},{"content":"개요 \u0026ldquo;NVDA 분석해줘\u0026rdquo; 한 마디에 시나리오 분석(Bull/Base/Bear), 확률 가중 R/R Score, 8분기 재무제표, 인터랙티브 HTML 대시보드가 나온다. stock-analysis-agent는 Claude Code 위에서 동작하는 기관급 주식 리서치 자동화 도구다. 미국 주식은 SEC 파일링, 한국 주식은 금감원 DART OpenAPI에서 직접 데이터를 가져온다.\n핵심 원칙: Blank beats Wrong graph TD A[\"티커 입력 \u0026lt;br/\u0026gt; NVDA / 005930\"] --\u003e B[\"데이터 수집\"] B --\u003e C{\"출처 검증\"} C --\u003e|\"Grade A: SEC/DART 직접\"| D[\"숫자 표시 + 출처 태그\"] C --\u003e|\"Grade B: 2+ 소스 교차\"| D C --\u003e|\"Grade C: 단일 소스\"| E[\"주의 표시\"] C --\u003e|\"검증 불가\"| F[\"— (공란 처리)\"] D --\u003e G[\"분석 보고서 생성\"] E --\u003e G F --\u003e G이 에이전트의 핵심 철학은 **\u0026ldquo;검증할 수 없는 숫자는 공란으로 표시한다\u0026rdquo;**는 것이다. AI가 그럴듯한 숫자를 만들어내는 hallucination 문제를 정면으로 해결한다. 모든 숫자에 [Filing], [Portal], [Calc] 같은 출처 태그가 붙고, Grade A(공시 원본)부터 Grade D(검증 불가 → 공란)까지 4단계 신뢰도 시스템을 적용한다.\n4가지 출력 모드 모드 이름 형식 용도 A At-a-glance HTML 판정 카드 + 180일 이벤트 타임라인 — 스크리닝용 B Benchmark HTML 2~5 종목 나란히 비교 매트릭스 C Chart (기본) HTML 인터랙티브 대시보드 — 시나리오, KPI, 차트 포함 D Document DOCX 3,000+단어 투자 메모 — Goldman Sachs 리서치 노트 스타일 Mode C의 대시보드에는 시나리오 카드(Bull/Base/Bear), R/R Score 배지, KPI 타일(P/E, EV/EBITDA, FCF Yield 등), Variant View(시장이 틀린 지점), Precision Risk(인과 체인 분석), Chart.js 차트, 8분기 손익계산서가 모두 포함된다.\n듀얼 데이터 파이프라인 graph LR subgraph US[\"미국 주식\"] A1[\"Financial Datasets API\"] --\u003e B1[\"SEC 10-K, 10-Q \u0026lt;br/\u0026gt; Grade A\"] A2[\"Yahoo Finance \u0026lt;br/\u0026gt; TipRanks 등\"] --\u003e B2[\"시세, 컨센서스 \u0026lt;br/\u0026gt; Grade B\"] end subgraph KR[\"한국 주식\"] C1[\"DART OpenAPI\"] --\u003e D1[\"연결 재무제표 \u0026lt;br/\u0026gt; Grade A\"] C2[\"네이버금융\"] --\u003e D2[\"현재가, PER \u0026lt;br/\u0026gt; Grade B\"] end B1 --\u003e E[\"Claude Code \u0026lt;br/\u0026gt; 분석 엔진\"] B2 --\u003e E D1 --\u003e E D2 --\u003e E E --\u003e F[\"HTML / DOCX \u0026lt;br/\u0026gt; 보고서\"]미국: Financial Datasets API(MCP)가 연결되면 SEC 파일링에서 직접 Grade A 데이터를 추출한다. MCP 없이도 Yahoo Finance, SEC EDGAR, TipRanks 등에서 웹 스크래핑으로 동작하지만 최대 Grade B까지만 가능하다.\n한국: DART OpenAPI로 금융감독원 공시를 직접 연동한다. fnlttSinglAcntAll 엔드포인트에서 연결 재무제표(IS/BS/CF)를, 네이버금융에서 현재가·PER·외국인지분율을 가져온다. DART API 키는 무료다.\nR/R Score — 리스크/리워드를 하나의 숫자로 R/R Score = (Bull_return% × Bull_prob + Base_return% × Base_prob) ───────────────────────────────────────────────────── |Bear_return% × Bear_prob| 시나리오별 목표가와 확률을 가중 평균해 단일 점수로 산출한다. 2.0 이상이면 Attractive, 1.0~2.0이면 Neutral, 1.0 미만이면 Unfavorable로 판정한다.\nVariant View — \u0026ldquo;시장이 틀린 지점\u0026rdquo; 가장 흥미로운 섹션이다. 일반적인 AI 분석이 \u0026ldquo;장단점 나열\u0026quot;에 그치는 것과 달리, stock-analysis-agent는 시장의 컨센서스가 구체적으로 어디서 틀렸는지를 회사 고유의 증거를 기반으로 제시한다. Q1~Q3 형식으로 3가지 포인트를 추출하며, 각각 \u0026ldquo;왜 시장이 이것을 놓치고 있는가\u0026quot;를 설명한다.\n사용법 # 단일 종목 분석 NVDA 분석해줘 005930 심층 분석 # 동종 비교 삼성전자 vs SK하이닉스 비교 NVDA vs AMD vs INTC # 포트폴리오/워치리스트 워치리스트 스캔해줘 카탈리스트 캘린더 보여줘 Claude Code에서 직접 대화하듯 명령하면 된다. 커밋 이력을 보면 Co-Authored-By: Claude Opus 4.6이 포함되어 있어, 이 에이전트 자체도 Claude Code로 개발되었음을 알 수 있다.\n인사이트 stock-analysis-agent가 보여주는 가장 중요한 패턴은 **\u0026ldquo;AI hallucination 문제를 시스템 설계로 해결한다\u0026rdquo;**는 접근이다. 모든 숫자에 출처를 강제하고, 검증할 수 없으면 공란으로 남기는 규칙은 단순하지만 강력하다. 또한 한미 시장을 동시에 지원하면서 각각의 공시 시스템(SEC/DART)에 직접 연동하는 듀얼 파이프라인은, 한국 개발자에게 특히 실용적인 레퍼런스가 된다. 다만 stars 3개의 초기 프로젝트인 만큼, 프로덕션 사용보다는 구조와 프롬프트 설계를 학습하는 용도로 접근하는 것이 현실적이다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-stock-analysis-agent/cover.jpg","permalink":"/ko/posts/2026-03-16-stock-analysis-agent/","title":"stock-analysis-agent — Claude Code로 기관급 주식 리서치를 자동화하는 오픈소스"},{"content":"개요 \u0026ldquo;Vibe Coding\u0026quot;이라는 용어가 Andrej Karpathy의 트윗에서 시작되어 하나의 개발 패러다임으로 자리 잡고 있다. YouTube에 공개된 Vibe Coding Fundamentals In 33 minutes는 이 패러다임의 기본기를 체계적으로 정리한 영상이다. 코드를 한 줄도 직접 쓰지 않으면서 AI에게 자연어로 지시해 소프트웨어를 만드는 방식의 핵심 원칙을 다룬다.\n바이브 코딩이란 graph TD A[\"전통적 코딩\"] --\u003e B[\"개발자가 코드 작성 \u0026lt;br/\u0026gt; AI가 보조\"] C[\"바이브 코딩\"] --\u003e D[\"개발자가 의도 전달 \u0026lt;br/\u0026gt; AI가 코드 작성\"] D --\u003e E[\"개발자가 결과 검증\"] E --\u003e|\"수정 필요\"| D E --\u003e|\"완료\"| F[\"배포\"]Karpathy가 처음 제안한 개념은 단순하다 — \u0026ldquo;코드를 보기는 하지만 읽지는 않는다. 에러가 나면 에러 메시지를 그대로 AI에게 붙여넣는다. 대부분의 경우 동작한다.\u0026rdquo; 이것이 바이브 코딩의 원형이다.\n하지만 이 원형은 프로토타이핑에는 효과적이되, 프로덕션 코드에는 위험하다. Vibe Coding Fundamentals는 이 갭을 메우기 위한 체계적 접근법을 제시한다.\n핵심 원칙 1. 명확한 컨텍스트 전달 AI에게 \u0026ldquo;채팅 앱 만들어줘\u0026quot;가 아닌, 기술 스택, 디렉토리 구조, 코딩 컨벤션, 비즈니스 요구사항을 구조화된 문서로 전달하는 것이 출발점이다. Claude Code의 CLAUDE.md, Cursor의 .cursorrules 같은 파일이 이 역할을 한다.\n2. 작은 단위로 반복 한 번에 전체 기능을 요청하지 않고, 작은 단위로 나누어 요청 → 검증 → 다음 요청 사이클을 반복한다. 한 프롬프트에 한 가지 변경만 요청하는 것이 핵심이다.\n3. 검증 가능한 결과물 \u0026ldquo;잘 되는 것 같다\u0026quot;가 아닌, 테스트 코드나 실행 결과로 검증한다. TDD(Test-Driven Development)와 바이브 코딩의 결합이 여기서 나온다 — 테스트를 먼저 쓰게 하고, 그 테스트를 통과하는 코드를 AI에게 작성하게 한다.\n4. 결과물이 아닌 생성 장치 일회성 코드 생성이 아닌, 재현 가능한 워크플로우를 만든다. 프롬프트 자체를 버전 관리하고, 성공한 패턴을 스킬이나 규칙 파일로 저장한다.\n바이브 코딩의 스펙트럼 graph LR A[\"순수 바이브 \u0026lt;br/\u0026gt; 프로토타이핑\"] --\u003e B[\"구조화된 바이브 \u0026lt;br/\u0026gt; 규칙 + 검증\"] B --\u003e C[\"에이전트 코딩 \u0026lt;br/\u0026gt; 자율 실행 + 하네스\"] C --\u003e D[\"팀 코딩 \u0026lt;br/\u0026gt; 멀티 에이전트 협업\"]바이브 코딩은 단일한 방법론이 아니라 스펙트럼이다:\n레벨 특징 적합한 상황 순수 바이브 자연어만으로 코드 생성, 검증 최소화 프로토타이핑, 일회성 스크립트 구조화된 바이브 CLAUDE.md 등 규칙 파일 + TDD 사이드 프로젝트, MVP 에이전트 코딩 하네스 + 자율 실행 루프 프로덕션 기능 개발 팀 코딩 멀티 에이전트 + 코드 리뷰 대규모 프로젝트 빠른 링크 Vibe Coding Fundamentals In 33 minutes — YouTube 원본 인사이트 바이브 코딩의 \u0026ldquo;바이브\u0026quot;라는 표현이 주는 가벼운 인상과 달리, 실제로 이 패러다임이 작동하려면 상당한 엔지니어링 규율이 필요하다. 명확한 컨텍스트 전달, 작은 단위의 반복, 검증 가능한 결과물 — 이것들은 사실 전통적 소프트웨어 엔지니어링의 기본기와 다르지 않다. 차이는 \u0026ldquo;누가 코드를 쓰느냐\u0026quot;가 바뀌었을 뿐, \u0026ldquo;어떻게 좋은 소프트웨어를 만드느냐\u0026quot;의 원칙은 그대로라는 것이다. AI Frontier EP 86에서 신정규 대표가 말한 \u0026ldquo;결과물이 아닌 생성 장치를 만든다\u0026quot;는 조언과 정확히 겹친다.\n","date":"2026-03-16T00:00:00+09:00","image":"/images/posts/2026-03-16-vibe-coding-fundamentals/cover.jpg","permalink":"/ko/posts/2026-03-16-vibe-coding-fundamentals/","title":"Vibe Coding Fundamentals — 33분 만에 배우는 바이브 코딩의 기본기"},{"content":"개요 Claude Code로 복잡한 리팩토링을 진행하다가 문득 궁금한 게 생긴다. \u0026ldquo;이 함수가 deprecated된 이유가 뭐였지?\u0026rdquo; 이걸 메인 프롬프트에 입력하면 대화 히스토리가 더러워지고, 에이전트가 맥락을 잃을 수도 있다. /btw는 이 문제를 해결하는 사이드 질문 기능이다.\n/btw의 동작 원리 graph TD A[\"메인 대화 진행 중\"] --\u003e B[\"/btw 질문 입력\"] B --\u003e C[\"전체 대화 맥락 읽기 \u0026lt;br/\u0026gt; 읽었던 코드, 합의한 결정 포함\"] C --\u003e D[\"일회성 오버레이로 답변\"] D --\u003e E[\"Space/Enter/Escape로 닫기\"] E --\u003e F[\"메인 대화 히스토리 \u0026lt;br/\u0026gt; 변화 없음\"] style D fill:#2196F3,color:#fff style F fill:#4CAF50,color:#fff핵심 특징:\n맥락 접근: 현재 대화의 전체 맥락을 그대로 볼 수 있다. 이미 읽었던 코드, 앞에서 합의한 결정, 방금까지의 논의 내용을 기반으로 답한다. 히스토리 비오염: 질문과 답변은 일회성 오버레이로 처리되고, 메인 대화 기록에는 남지 않는다. 비간섭 실행: Claude가 메인 답변을 생성 중인 상황에서도 /btw를 실행할 수 있다. 메인 응답을 중단시키지 않는다. /btw vs 서브에이전트: 용도 분리 특성 /btw 서브에이전트 맥락 전체 대화 맥락 접근 ✓ 새 세션, 맥락 없음 도구 사용 불가 ✗ 가능 ✓ 대화 형태 단발성 (1회 응답) 멀티턴 가능 히스토리 남지 않음 결과만 반환 비용 프롬프트 캐시 재사용 (저비용) 새 세션 비용 정리하면:\n\u0026ldquo;이미 알고 있을 법한 것\u0026quot;을 확인 → /btw \u0026ldquo;새로 조사/탐색이 필요한 것\u0026quot;을 수행 → 서브에이전트 제약사항 도구 접근 불가 /btw는 파일 읽기, 명령 실행, 웹 검색 등 일체의 도구를 사용할 수 없다. 현재 대화 맥락에 이미 들어 있는 정보만으로 답한다. 이 제약은 의도적이다 — 도구 호출이 끼어들면 사이드 질문이 메인 작업에 영향을 줄 수 있기 때문이다.\n단발성 대화 후속 질문으로 이어지는 핑퐁 대화가 필요하면 /btw가 아니라 일반 프롬프트를 사용해야 한다. /btw는 말 그대로 \u0026ldquo;by the way(참고로)\u0026rdquo; — 한 번 물어보고 넘어가는 용도다.\n비용 관점 /btw는 부모 대화의 프롬프트 캐시를 재사용하도록 설계되어 있다. 새로운 컨텍스트를 구성하지 않으니 추가 비용이 최소화된다. Claude Code의 토큰 비용이 신경 쓰이는 상황에서, 빠른 확인성 질문은 /btw가 경제적이다.\n실전 활용 패턴 # 리팩토링 중 빠른 확인 /btw 이 파일에서 아까 deprecated라고 했던 메서드가 정확히 어떤 거였지? # 코드 리뷰 중 컨벤션 확인 /btw 우리 프로젝트에서 에러 핸들링 패턴이 try-catch였나 Result 타입이었나? # 설계 논의 중 이전 결정 참조 /btw 아까 데이터베이스 선택할 때 PostgreSQL로 가기로 한 이유가 뭐였지? 인사이트 /btw는 작은 기능처럼 보이지만, Claude Code의 대화 모델에서 중요한 빈 공간을 채운다. 메인 대화를 오염시키지 않으면서 맥락을 활용하는 방법이 없었다. 이는 개발자가 실제로 작업할 때의 사고 패턴 — \u0026ldquo;잠깐, 이거 뭐였더라?\u0026rdquo; — 을 반영한 설계다. 도구 접근 제한과 단발성이라는 제약도, 사이드 질문이 메인 워크플로우를 방해하지 않도록 하는 의도적인 가드레일이다.\n","date":"2026-03-13T00:00:00+09:00","image":"/images/posts/2026-03-13-claude-code-btw/cover.jpg","permalink":"/ko/posts/2026-03-13-claude-code-btw/","title":"Claude Code /btw — 작업 흐름을 끊지 않는 사이드 질문 기능"},{"content":"개요 Google 검색 트래픽이 2028년까지 50% 감소할 것이라는 Gartner 예측, AI 추천 트래픽의 전년 대비 527% 성장, AI 트래픽의 오가닉 대비 4.4배 높은 전환율 — 이 숫자들이 말하는 건 분명하다. SEO의 무게중심이 **GEO(Generative Engine Optimization)**로 이동하고 있다. geo-seo-claude는 이 전환을 Claude Code 스킬 하나로 대응하는 도구다.\nGEO란 무엇인가 GEO는 ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews 같은 AI 검색 엔진에 최적화하는 것을 말한다. 전통 SEO가 \u0026ldquo;검색 결과 페이지에서 링크를 클릭하게 만드는 것\u0026quot;이었다면, GEO는 \u0026ldquo;AI가 내 콘텐츠를 인용하게 만드는 것\u0026quot;이다.\ngraph LR A[\"전통 SEO\"] --\u003e B[\"검색 결과 순위 \u0026lt;br/\u0026gt; 백링크 중심\"] C[\"GEO\"] --\u003e D[\"AI 인용 가능성 \u0026lt;br/\u0026gt; 브랜드 멘션 중심\"] B --\u003e E[\"사용자가 링크 클릭\"] D --\u003e F[\"AI가 콘텐츠 인용\"] style C fill:#4CAF50,color:#fff핵심 지표의 변화:\n지표 값 GEO 서비스 시장 $850M+ (2031년 $7.3B 전망) 백링크 vs 브랜드 멘션 (AI 가시성) 브랜드 멘션이 3배 더 강한 상관관계 ChatGPT와 Google AIO 동시 인용 도메인 11% 뿐 GEO에 투자 중인 마케터 23% 뿐 아키텍처: 5개 병렬 서브에이전트 geo-seo-claude의 설계가 흥미로운 건 Claude Code의 스킬 + 서브에이전트 패턴을 교과서적으로 보여주기 때문이다.\ngraph TD U[\"/geo audit URL\"] --\u003e D[\"Discovery \u0026lt;br/\u0026gt; 홈페이지 fetch + 비즈니스 타입 감지\"] D --\u003e S1[\"AI Visibility \u0026lt;br/\u0026gt; 인용성 + 크롤러 + llms.txt + 브랜드\"] D --\u003e S2[\"Platform Analysis \u0026lt;br/\u0026gt; ChatGPT/Perplexity/AIO 대응\"] D --\u003e S3[\"Technical SEO \u0026lt;br/\u0026gt; Core Web Vitals + SSR + 보안\"] D --\u003e S4[\"Content Quality \u0026lt;br/\u0026gt; E-E-A-T + 가독성 + 최신성\"] D --\u003e S5[\"Schema Markup \u0026lt;br/\u0026gt; 감지 + 검증 + 생성\"] S1 --\u003e R[\"Synthesis \u0026lt;br/\u0026gt; GEO Score 0-100 산출\"] S2 --\u003e R S3 --\u003e R S4 --\u003e R S5 --\u003e R R --\u003e O[\"우선순위별 액션 플랜\"]/geo audit 명령 하나로 5개 서브에이전트가 동시에 돌아간다:\nAI Visibility — 인용성 점수, 크롤러 접근, llms.txt, 브랜드 멘션 Platform Analysis — ChatGPT, Perplexity, Google AIO별 최적화 Technical SEO — Core Web Vitals, SSR, 보안, 모바일 Content Quality — E-E-A-T, 가독성, 콘텐츠 최신성 Schema Markup — 감지, 검증, JSON-LD 생성 주요 기능 AI 인용성(Citability) 점수 AI가 인용하기 좋은 텍스트 블록의 조건을 수치화한다. 최적 인용 패시지는 134-167 단어, 자기 완결적이고, 팩트 밀도가 높으며, 질문에 직접 답하는 형태다.\nAI 크롤러 분석 robots.txt에서 GPTBot, ClaudeBot, PerplexityBot 등 14개 이상의 AI 크롤러 접근 상태를 점검하고, 허용/차단 권장사항을 제공한다.\n브랜드 멘션 스캔 백링크보다 AI 가시성에 3배 더 강한 상관관계를 보이는 브랜드 멘션을 YouTube, Reddit, Wikipedia, LinkedIn 등 7개 이상 플랫폼에서 스캔한다.\nllms.txt 생성 AI 크롤러가 사이트 구조를 이해할 수 있도록 하는 신규 표준인 llms.txt 파일을 분석하거나 생성한다.\n점수 산출 방법론 카테고리 가중치 AI 인용성 \u0026amp; 가시성 25% 브랜드 권위 시그널 20% 콘텐츠 품질 \u0026amp; E-E-A-T 20% 기술적 기반 15% 구조화 데이터 10% 플랫폼 최적화 10% 설치와 사용 # 원커맨드 설치 curl -fsSL https://raw.githubusercontent.com/zubair-trabzada/geo-seo-claude/main/install.sh | bash # Claude Code에서 사용 /geo audit https://example.com # 전체 감사 /geo quick https://example.com # 60초 스냅샷 /geo citability https://example.com # 인용성 점수 /geo report-pdf # PDF 리포트 생성 Python 3.8+, Claude Code CLI, Git이 필요하고, Playwright는 선택 사항이다.\n비즈니스 관점 도구 자체는 MIT 라이선스 무료다. 흥미로운 건 이 도구를 기반으로 한 GEO 에이전시 비즈니스 모델을 함께 제시한다는 점이다. GEO 에이전시의 월 과금 범위는 $2K~$12K. 도구가 감사를 수행하고, 커뮤니티에서 영업 방법을 가르치는 구조다. 스타 2,264개에 포크 369개 — Claude Code 스킬 중 상당한 규모다.\n인사이트 geo-seo-claude가 보여주는 건 두 가지다. 첫째, Claude Code 스킬이 단순한 프롬프트 래퍼를 넘어 11개 서브스킬 + 5개 병렬 서브에이전트 + Python 유틸리티로 구성된 본격적인 소프트웨어 제품이 될 수 있다는 것. 둘째, AI 검색이 전통 검색을 대체하면서 SEO → GEO 전환이 실질적인 비즈니스 기회가 되고 있다는 것. \u0026ldquo;AI search is eating traditional search\u0026rdquo; — 이 도구의 슬로건이 현실이 되는 속도가 빠르다.\n","date":"2026-03-13T00:00:00+09:00","image":"/images/posts/2026-03-13-geo-seo-claude/cover.jpg","permalink":"/ko/posts/2026-03-13-geo-seo-claude/","title":"geo-seo-claude — AI 검색 시대의 SEO를 Claude Code로 자동화하는 GEO 스킬"},{"content":"개요 GPT-5.4는 장문 유지, 멀티스텝 에이전트, 근거 기반 종합에 강하다. 하지만 이 장점은 자동으로 나오지 않는다. OpenAI의 공식 프롬프트 가이드가 제시하는 핵심 메시지는 명확하다 — \u0026ldquo;더 생각하게 만들기\u0026quot;보다 \u0026ldquo;덜 흔들리게 만들기\u0026quot;가 먼저다.\n네 가지 핵심 장치 graph TD A[\"GPT-5.4 프롬프트 최적화\"] --\u003e B[\"1. 출력 계약 \u0026lt;br/\u0026gt; 형식 고정\"] A --\u003e C[\"2. 도구 규칙 \u0026lt;br/\u0026gt; 지속성/의존성/병렬화\"] A --\u003e D[\"3. 완전성 계약 \u0026lt;br/\u0026gt; 전부 처리 or blocked 표시\"] A --\u003e E[\"4. 검증 루프 \u0026lt;br/\u0026gt; 요구/근거/형식/허가\"] B --\u003e F[\"reasoning_effort 조정은 \u0026lt;br/\u0026gt; 이 네 가지 이후에\"] C --\u003e F D --\u003e F E --\u003e F style F fill:#FF9800,color:#fff추론 노력(reasoning_effort)을 올리는 건 마지막 미세조정 노브다. 대부분의 경우 위 네 가지 프롬프트 장치가 비용 대비 효과가 더 크다.\n1. 출력 계약(Output Contract) GPT-5.4가 \u0026ldquo;도움이 되려고\u0026rdquo; 중간 설명을 덧붙이며 형식을 깨는 걸 방지한다.\n\u0026lt;output_contract\u0026gt; - Return exactly the sections requested, in the requested order. - If a format is required (JSON, Markdown, SQL, XML), output only that format. \u0026lt;/output_contract\u0026gt; 견적서처럼 작동한다. \u0026ldquo;결과물은 이 양식으로 납품\u0026quot;이라고 쓰면 과잉 친절이 줄고 파싱 실패도 감소한다.\n2. 도구 지속성 규칙(Tool Persistence) 에이전트 실패의 가장 흔한 패턴: \u0026ldquo;정답이 뻔해 보여서\u0026rdquo; 선행 조회를 건너뛰는 것. 이를 막는 세 가지 원칙:\n원칙 설명 강제 사용 정확도/근거/완성도를 올리면 도구를 써야 하고, 빈 결과면 다른 전략으로 재시도 의존성 체크 행동 전에 \u0026ldquo;선행 조회가 필요한지\u0026rdquo; 점검. \u0026ldquo;최종 상태가 obvious\u0026quot;여도 건너뛰기 금지 병렬/순차 분리 독립 조회는 병렬로 속도, 의존 단계는 순차로 정확성 확보 핵심: 도구 사용을 \u0026ldquo;선택\u0026quot;이 아니라 **\u0026ldquo;필요조건\u0026rdquo;**으로 만든다.\n3. 완전성 계약(Completeness Contract) 긴 배치 작업에서 모델이 \u0026ldquo;대충 끝낸 것처럼\u0026rdquo; 마무리하는 문제를 해결한다.\n요청 항목 전부를 처리했거나, 못 했으면 [blocked]로 표시 검색이 비었을 때 즉시 \u0026ldquo;없다\u0026quot;고 결론내리지 않고, 최소 1-2번 대체 전략 시도 다른 쿼리, 넓은 필터, 선행 조회, 다른 소스 이 두 규칙이 \u0026ldquo;긴 작업을 끝까지 가져가는 체력\u0026quot;을 프롬프트로 보강한다.\n4. 검증 루프(Verification Loop) 완료 직전에 네 갈래 검증:\ngraph LR A[\"완료 직전\"] --\u003e B[\"요구사항 \u0026lt;br/\u0026gt; 전부 다 했나?\"] A --\u003e C[\"근거 \u0026lt;br/\u0026gt; 주장에 출처가 있나?\"] A --\u003e D[\"형식 \u0026lt;br/\u0026gt; 스키마를 지켰나?\"] A --\u003e E[\"외부 영향 \u0026lt;br/\u0026gt; 비가역이면 허락 받았나?\"]추가 게이팅 규칙: \u0026ldquo;필요한 정보가 없으면 추측하지 말고, 가능하면 조회 도구를 쓰고, 불가하면 최소 질문만\u0026rdquo;.\n대화 중 요구 변경 대응 사용자는 중간에 방향을 자주 꺾는다. 이때의 기본 정책:\n되돌릴 수 있고 저위험 → 묻지 말고 진행 외부 영향/비가역/민감정보 → 허락 요청 지시 우선순위: 최신 사용자 지시가 기존 스타일 규칙을 덮되, 안전/정직/프라이버시는 예외 없이 유지 리서치 품질 고정 AI 리서치에서 가장 위험한 건 \u0026ldquo;어디까지가 근거이고 어디부터가 상상인지\u0026rdquo; 경계가 흐려지는 것.\n\u0026ldquo;이번 워크플로에서 실제로 가져온 소스만 인용\u0026rdquo; 규칙 URL/ID/인용구 지어내기 금지 인용을 문서 끝에 몰지 말고 해당 주장 바로 옆에 배치 리서치 3단계 강제: 질문 쪼개기 → 각 질문 검색 + 2차 단서 → 모순 조정 후 인용 포함 결과 작성 reasoning_effort 튜닝 작업 유형 권장 수준 빠른 실행/추출/분류/짧은 변환 none ~ low 장문 종합/다문서 검토/전략 글쓰기 medium 이상 xhigh 평가(evals)에서 확실히 이득이 보일 때만 마이그레이션 순서: 모델만 먼저 바꾸고 → 추론 노력 고정 → 평가 → 프롬프트 블록 추가 → 추론 노브 한 단계씩 조정.\n인사이트 이 가이드의 교훈은 GPT-5.4에 국한되지 않는다. Claude, Gemini 등 모든 LLM 에이전트에 적용되는 보편적 패턴이다. \u0026ldquo;규칙을 주면 규칙을 오래 기억하고 지키는\u0026rdquo; 모델의 특성을 활용하는 것 — 출력 계약, 도구 강제, 완전성 계약, 검증 루프. 이 네 가지를 먼저 고정하고, 그래도 부족할 때만 추론 노력을 올리는 순서가 비용과 품질을 동시에 잡는 길이다. 결국 프롬프트 엔지니어링은 \u0026ldquo;AI에게 더 생각하라고 하는 것\u0026quot;이 아니라 \u0026ldquo;AI가 흔들릴 여지를 줄이는 것\u0026quot;이다.\n","date":"2026-03-13T00:00:00+09:00","image":"/images/posts/2026-03-13-gpt54-prompt-guide/cover.jpg","permalink":"/ko/posts/2026-03-13-gpt54-prompt-guide/","title":"GPT-5.4 프롬프트 가이드 핵심 정리 — 성능보다 계약이 먼저다"},{"content":"개요 웹페이지에 AI 에이전트를 붙이려면 보통 Playwright 같은 헤드리스 브라우저나 Chrome 확장 프로그램이 필요하다. 알리바바가 공개한 page-agent는 이 전제를 뒤집는다 — \u0026lt;script src=\u0026quot;page-agent.js\u0026quot;\u0026gt;\u0026lt;/script\u0026gt; 한 줄이면 웹사이트가 AI 네이티브 앱으로 변한다.\n핵심 아키텍처: In-Page 실행 모델 page-agent의 가장 큰 차별점은 in-page 실행 모델이다. 기존 브라우저 자동화 도구들과의 차이를 보면:\ngraph TD A[\"기존 접근법\"] --\u003e B[\"Playwright/Puppeteer \u0026lt;br/\u0026gt; 헤드리스 브라우저 제어\"] A --\u003e C[\"Chrome Extension \u0026lt;br/\u0026gt; 별도 권한 요청\"] A --\u003e D[\"멀티모달 LLM \u0026lt;br/\u0026gt; 스크린샷 + OCR\"] E[\"page-agent\"] --\u003e F[\"DOM 직접 접근 \u0026lt;br/\u0026gt; 텍스트 기반 조작\"] F --\u003e G[\"권한 요청 없음\"] F --\u003e H[\"스크린샷/OCR 불필요\"] F --\u003e I[\"웹페이지 내부 실행\"] style E fill:#4CAF50,color:#fff모든 처리가 웹페이지 내부에서 수행된다. 별도 권한 요청 없이 DOM 요소를 직접 제어하고, 스크린샷이나 OCR, 멀티모달 LLM이 필요 없다. 텍스트 기반 DOM 조작이 핵심이라 속도도 빠르다.\n사용 방법 코드에 직접 삽입 \u0026lt;script src=\u0026#34;page-agent.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 북마클릿으로 아무 사이트에 적용 코드에 넣지 않아도 북마클릿(bookmarklet)을 이용하면 아무 웹사이트에나 즉시 적용할 수 있다. 기본 북마클릿은 알리바바 서버를 거치지만, 원하는 LLM 엔드포인트로 변경 가능하다:\njavascript:(function(){ import(\u0026#39;https://cdn.jsdelivr.net/npm/page-agent@1.5.5/+esm\u0026#39;) .then(module =\u0026gt; { window.agent = new module.PageAgent({ model: \u0026#39;gpt-5.4\u0026#39;, baseURL: \u0026#39;\u0026lt;your-api-url\u0026gt;\u0026#39;, apiKey: \u0026#39;\u0026lt;your-api-key\u0026gt;\u0026#39; }); if(window.agent.panel) window.agent.panel.show(); }) .catch(e =\u0026gt; console.error(e)); })(); 지원 모델 OpenAI, Claude, DeepSeek, Qwen 등 다양한 모델을 지원하며, Ollama를 통한 완전 오프라인 구동도 가능하다 (API 키 기반 통합).\n활용 사례 사례 설명 SaaS AI Copilot 백엔드 수정 없이 제품 내 AI Copilot 구현 스마트 폼 자동화 다단계 클릭 과정을 한 문장으로 단축 (ERP/CRM/관리자 도구) 접근성 강화 음성 명령과 스크린리더를 통한 웹 접근성 향상 관리자 도구 워크플로우 CRUD만 만들고 순차적 지시로 워크플로우 자동 구성 GeekNews 커뮤니티에서는 특히 관리자 도구에 대한 반응이 뜨거웠다. \u0026ldquo;대충 CRUD만 만들고, 이거하고 저거하라고 순차적으로 시키면 워크플로우 만들어지는\u0026rdquo; 패턴이다. 실제로 토스증권에서 SOXL 30일 전 주가를 조회하는 데모에서 Playwright보다 훨씬 빠른 속도를 보였다는 후기도 있다.\nChrome 확장 — 멀티 페이지 지원 단일 페이지 북마클릿 방식을 넘어, Chrome 확장을 설치하면 멀티 페이지를 연결한 태스크도 지원한다. 브라우저 레벨 제어와 외부 연동까지 가능해져, 단순 DOM 조작을 넘어선 복잡한 자동화 시나리오를 처리할 수 있다.\n보안 고려사항 커뮤니티에서 지적된 핵심 우려는 보안이다. API 키가 클라이언트 사이드에 노출되는 구조이므로:\n프로덕션 환경에서는 프록시 서버를 통한 API 키 관리 필수 내부 관리자 도구나 개발 환경에서의 활용이 가장 안전 기본 북마클릿의 알리바바 서버 경유가 우려되면 자체 LLM 엔드포인트 지정 MIT 라이선스로 공개되어 있어 포크 후 커스터마이징이 자유롭다.\n인사이트 page-agent가 제시하는 \u0026ldquo;in-page 실행 모델\u0026quot;은 브라우저 자동화의 패러다임 전환이다. 기존에는 외부에서 브라우저를 제어했다면, 이제는 페이지 안에서 AI가 직접 DOM을 읽고 조작한다. 스크린샷 → OCR → 좌표 클릭의 무거운 파이프라인 대신, 텍스트 기반으로 DOM을 이해하니 속도와 정확도 모두 유리하다. 특히 SaaS 제품에 백엔드 변경 없이 AI Copilot을 삽입하는 시나리오는, 레거시 시스템 현대화의 새로운 경로가 될 수 있다.\n","date":"2026-03-13T00:00:00+09:00","image":"/images/posts/2026-03-13-page-agent/cover.jpg","permalink":"/ko/posts/2026-03-13-page-agent/","title":"page-agent — 코드 1줄로 웹페이지를 AI 네이티브 앱으로 바꾸는 알리바바의 오픈소스"},{"content":"개요 AI 코딩 에이전트를 본격적으로 사용하다 보면 세션이 수십 개씩 쌓인다. 어떤 프로젝트에서 어떤 작업을 했는지, 어디서 중단했는지 기억하기 어렵다. 이 문제를 해결하기 위해 등장한 두 도구 — agentsview와 agf — 를 비교 분석한다.\ngraph LR A[\"AI 에이전트 세션 데이터\"] --\u003e B[\"agentsview\"] A --\u003e C[\"agf\"] B --\u003e D[\"웹/데스크톱 UI \u0026lt;br/\u0026gt; 대시보드 + 검색 + 분석\"] C --\u003e E[\"TUI \u0026lt;br/\u0026gt; 빠른 검색 + 즉시 재개\"]agentsview — 세션 분석 대시보드 agentsview는 AI 에이전트 코딩 세션을 브라우징, 검색, 분석하는 로컬 퍼스트 데스크톱/웹 애플리케이션이다. Go 백엔드 + Svelte 프론트엔드 + Tauri 데스크톱 앱으로 구성되어 있다.\n지원 에이전트 Claude Code, Codex, OpenCode를 포함해 11개 이상의 AI 코딩 에이전트를 지원한다. 각 에이전트의 세션 로그를 파싱하여 통합된 뷰를 제공한다.\n주요 특징 대시보드: 프로젝트별, 에이전트별 사용량 통계와 시각화 전문 검색: 세션 내용을 텍스트 검색하여 \u0026ldquo;그때 뭘 했더라?\u0026rdquo; 질문에 답할 수 있음 로컬 퍼스트: 모든 데이터가 로컬에 저장되어 프라이버시 보장 데스크톱 앱: macOS/Windows 인스톨러 제공, 자동 업데이트 지원 설치 # CLI curl -fsSL https://agentsview.io/install.sh | bash # 데스크톱 앱 # GitHub Releases에서 다운로드 기술 스택 구성 기술 백엔드 Go 1.25+ 프론트엔드 Svelte + TypeScript 데스크톱 Tauri (Rust) Stars 453 agf — 터미널 세션 파인더 agf는 한국 개발자 subinium이 만든 TUI 기반 에이전트 세션 관리 도구다. Rust로 작성되어 빠르고, 설치가 간단하다.\n해결하려는 문제 에이전트 사용자들의 전형적인 경험을 이렇게 설명한다:\n어떤 프로젝트에서 작업하고 있었는지 기억나지 않음 잘못된 디렉토리로 cd 세션 ID를 기억하려고 시도 포기하고 새 세션 시작 주요 특징 통합 뷰: Claude Code, Codex, OpenCode, pi, Kiro, Cursor CLI, Gemini 지원 퍼지 검색: 프로젝트 이름으로 즉시 검색 원키 재개: 선택한 세션을 Enter 한 번으로 재개 Resume Mode Picker: Tab으로 재개 모드 선택 (v0.5.5) Worktree 스캔: 병렬화된 worktree 스캔으로 삭제된 프로젝트도 추적 설치 brew install subinium/tap/agf agf setup # 이후 셸 재시작하고 agf 입력 Quick Resume agf resume project-name # 퍼지 매칭으로 바로 재개 두 도구 비교 graph TD subgraph agentsview A1[\"Go + Svelte + Tauri\"] A2[\"웹 대시보드\"] A3[\"분석 + 통계\"] A4[\"11개 에이전트 지원\"] end subgraph agf B1[\"Rust TUI\"] B2[\"터미널 네이티브\"] B3[\"빠른 검색 + 재개\"] B4[\"7개 에이전트 지원\"] end A1 --\u003e A2 --\u003e A3 B1 --\u003e B2 --\u003e B3 기준 agentsview agf 인터페이스 웹/데스크톱 GUI TUI (터미널) 주요 용도 세션 분석 + 검색 빠른 세션 재개 언어 Go + Svelte Rust 설치 curl or 데스크톱 앱 Homebrew Stars 453 99 지원 에이전트 11개+ 7개 인사이트 AI 코딩 에이전트의 세션 관리 도구가 등장했다는 것 자체가 이 생태계의 성숙도를 보여준다. 에디터 플러그인처럼, 에이전트도 이제 \u0026ldquo;사용하는 것\u0026rdquo; 자체보다 \u0026ldquo;잘 관리하는 것\u0026quot;이 생산성의 핵심이 되고 있다.\nagentsview는 \u0026ldquo;이번 주에 AI와 뭘 했지?\u0026ldquo;라는 회고적 질문에 강하고, agf는 \u0026ldquo;방금 하던 거 이어서\u0026quot;라는 즉시적 니즈에 강하다. 두 도구 모두 로컬 퍼스트라는 점이 인상적이다 — AI 세션 데이터가 클라우드로 빠져나갈 걱정 없이 사용할 수 있다. 결국 두 도구는 경쟁이 아니라 보완 관계에 있다.\n","date":"2026-03-11T00:00:00+09:00","image":"/images/posts/2026-03-11-ai-agent-session-managers/cover.jpg","permalink":"/ko/posts/2026-03-11-ai-agent-session-managers/","title":"AI 코딩 에이전트 세션 관리의 진화 — agentsview와 agf 비교"},{"content":"개요 AI 코딩 에이전트를 \u0026ldquo;그냥 쓰는\u0026rdquo; 시대에서 \u0026ldquo;구조화해서 쓰는\u0026rdquo; 시대로 넘어가고 있다. OpenAI Codex와 Claude Code 위에 얹어서 에이전트의 행동을 제어하고, 팀 워크플로우를 구성하고, 개발 방법론을 강제하는 확장 프레임워크 3종을 비교한다.\ngraph TD A[\"AI 코딩 에이전트 \u0026lt;br/\u0026gt; (Codex, Claude Code)\"] --\u003e B[\"bkit-codex \u0026lt;br/\u0026gt; PDCA 방법론\"] A --\u003e C[\"oh-my-codex \u0026lt;br/\u0026gt; 멀티 에이전트 오케스트레이션\"] A --\u003e D[\"Superpowers \u0026lt;br/\u0026gt; 스킬 프레임워크\"] B --\u003e E[\"계획 → 실행 → 검증 → 개선\"] C --\u003e F[\"hooks + teams + HUDs\"] D --\u003e G[\"brainstorm → plan → TDD → review\"]bkit-codex — PDCA + Context Engineering bkit-codex는 OpenAI Codex CLI 확장으로, PDCA(Plan-Do-Check-Act) 방법론과 Context Engineering 아키텍처를 통해 AI 네이티브 개발 워크플로우를 제공한다.\nContext Engineering이란 AI에게 전달되는 컨텍스트 토큰을 체계적으로 큐레이션하는 방법론이다. 단순히 프롬프트를 잘 쓰는 것을 넘어, 어떤 정보를 어떤 순서로 AI에게 제공할지를 구조화한다.\n핵심 구성 PDCA 사이클: Plan(계획서 작성) → Do(코드 생성) → Check(테스트/검증) → Act(개선/배포) Skills: 재사용 가능한 에이전트 행동 모듈 Pipeline: 여러 스킬을 체이닝하여 복잡한 워크플로우 구성 MCP 통합: Model Context Protocol을 통한 도구 연동 기술 스택 JavaScript 기반, Apache 2.0 라이센스, 10 Stars\noh-my-codex (OMX) — 멀티 에이전트 오케스트레이션 oh-my-codex는 OpenAI Codex CLI 위에 멀티 에이전트 오케스트레이션 레이어를 추가한다. 1,744 Stars로 이 분야에서 가장 활발한 커뮤니티를 보유하고 있다.\n핵심 기능 Agent Teams: 여러 에이전트가 역할을 분담하여 협업 (리더/워커 구조) Hooks: 에이전트 실행 전/후에 커스텀 로직 삽입 HUDs (Head-Up Displays): 에이전트 상태를 실시간 모니터링 Harness: 에이전트 실행 환경을 표준화하고 패키징 OpenClaw 통합: 알림 게이트웨이를 통한 에이전트 상태 알림 아키텍처 graph LR A[\"사용자 명령\"] --\u003e B[\"OMX 오케스트레이터\"] B --\u003e C[\"Team Leader\"] C --\u003e D[\"Worker Agent 1\"] C --\u003e E[\"Worker Agent 2\"] C --\u003e F[\"Worker Agent N\"] D --\u003e G[\"Codex CLI\"] E --\u003e G F --\u003e G B --\u003e H[\"Hooks \u0026lt;br/\u0026gt; pre/post 실행\"] B --\u003e I[\"HUD \u0026lt;br/\u0026gt; 실시간 모니터링\"]기술 스택 TypeScript 기반, MIT 라이센스, 1,744 Stars, v0.8.12\nSuperpowers — 스킬 기반 개발 방법론 Superpowers는 76,619 Stars라는 압도적인 인기를 자랑하는 에이전트 스킬 프레임워크다. 단순한 도구가 아니라 완전한 소프트웨어 개발 방법론을 제공한다.\n철학 코딩 에이전트가 \u0026ldquo;코드부터 쓰지 않는다\u0026quot;는 원칙에서 출발한다. 대신:\nBrainstorming: 무엇을 만들려는지 사용자에게 질문 Spec Review: 스펙을 소화 가능한 단위로 쪼개어 검토 Implementation Plan: \u0026ldquo;열정적이지만 경험 부족한 주니어 엔지니어\u0026quot;도 따를 수 있는 구현 계획 Subagent-Driven Development: 서브에이전트가 각 태스크를 수행, 메인 에이전트가 검수 TDD + YAGNI + DRY: 테스트 주도 개발과 간결함을 강제 주요 스킬 brainstorming — 기능 구현 전 요구사항 탐색 writing-plans — 구현 계획 수립 test-driven-development — Red/Green TDD 강제 systematic-debugging — 체계적 디버깅 워크플로우 dispatching-parallel-agents — 독립 태스크 병렬 처리 verification-before-completion — 완료 전 검증 강제 기술 스택 Shell + JavaScript, v5.0.0, 76,619 Stars\n3종 비교 기준 bkit-codex oh-my-codex Superpowers 대상 에이전트 Codex CLI Codex CLI Claude Code + 범용 핵심 가치 PDCA 방법론 멀티 에이전트 협업 개발 방법론 강제 Stars 10 1,744 76,619 언어 JavaScript TypeScript Shell 팀 기능 Pipeline Agent Teams Subagent 모니터링 리포트 HUD 실시간 검증 체크리스트 빠른 링크 Claude Code 제대로 쓰고 싶다면 — bkit으로 AI 코딩 완전 정복 — 58분 분량의 bkit 활용 실습 영상 인사이트 세 프레임워크의 공통점은 \u0026ldquo;AI에게 구조를 부여한다\u0026quot;는 것이다. 이것이 2026년 AI 코딩의 핵심 트렌드다.\nbkit-codex는 제조업의 PDCA를 소프트웨어에 접목한 실험적 시도, oh-my-codex는 Codex를 팀으로 확장하려는 실용적 접근, Superpowers는 76K Stars가 증명하듯 가장 검증된 방법론이다.\n특히 Superpowers의 \u0026ldquo;코딩 에이전트가 코드부터 쓰지 않게 만든다\u0026quot;는 철학은 인상적이다. 인간 개발자에게도 좋은 교훈 — 설계 없이 코딩에 뛰어드는 것은 AI든 사람이든 비효율적이라는 것.\nAI가 코드를 \u0026ldquo;짜는\u0026rdquo; 능력은 이미 충분하다. 이제 필요한 것은 AI가 코드를 \u0026ldquo;잘 짜게\u0026rdquo; 만드는 프레임워크이며, 이 세 프로젝트가 그 방향을 선도하고 있다.\n","date":"2026-03-11T00:00:00+09:00","image":"/images/posts/2026-03-11-ai-agent-frameworks/cover.jpg","permalink":"/ko/posts/2026-03-11-ai-agent-frameworks/","title":"AI 코딩 에이전트 확장 프레임워크 3종 비교 — bkit-codex, oh-my-codex, Superpowers"},{"content":"개요 Claude Opus 4.6의 품질 향상으로 업무에 Claude를 더 많이 사용하게 되면서, \u0026ldquo;내가 이 플랜을 제대로 활용하고 있나?\u0026rdquo;, \u0026ldquo;리밋까지 얼마나 남았지?\u0026ldquo;라는 질문이 자연스럽게 생긴다. ClaudeTuner는 이 문제를 해결하는 크롬 확장 + 웹 대시보드다.\ngraph TD A[\"크롬 확장 프로그램\"] --\u003e|사용량 수집| B[\"ClaudeTuner 서버\"] B --\u003e C[\"웹 대시보드\"] C --\u003e D[\"5시간/7일 사용률 게이지\"] C --\u003e E[\"리셋 카운트다운\"] C --\u003e F[\"사용량 예측\"] C --\u003e G[\"리밋 방지 알림 \u0026lt;br/\u0026gt; 80%, 95% 도달 시\"]주요 기능 개인 사용량 모니터링 크롬 확장을 설치하고 Claude에서 로그인하면 사용량이 자동 수집된다. Claude Code 사용량도 합산 추적된다.\n5시간/7일 사용률 게이지바: 현재 사용 상태를 한눈에 확인 리셋 카운트다운: 다음 리셋까지 남은 시간 표시 사용량 예측: 현재 속도 기준으로 리셋 시점의 예상 사용률 계산 리밋 방지 알림: 80%, 95% 도달 시 브라우저 알림으로 속도 조절 유도 시간대별 사용 패턴: 언제 가장 많이 사용하는지 분석 B2B 비용 최적화 Claude Team 플랜을 사용하는 조직을 위한 관리 기능도 제공한다. 팀원별 사용량을 추적하고, 실제 사용 패턴에 맞는 최적 플랜을 추천한다.\n데이터 수집 방식 크롬 확장이 Claude 웹사이트에서 사용량 데이터를 주기적으로 읽어온다. 최초 로그인 이후에는 자동 수집되므로 별도 작업이 필요 없다.\n인사이트 AI 도구의 사용량 관리가 하나의 독립된 소프트웨어 카테고리가 되고 있다는 점이 흥미롭다. 구독 비용 대비 실제 사용량을 데이터로 보여주는 도구의 등장은, AI 도구가 이제 \u0026ldquo;써보는 것\u0026quot;에서 \u0026ldquo;관리하는 것\u0026quot;으로 전환되고 있음을 의미한다. 팀 관리 기능까지 제공하는 것은 기업에서 AI 도구 비용 최적화가 현실적 이슈가 되었다는 반증이기도 하다.\n","date":"2026-03-11T00:00:00+09:00","image":"/images/posts/2026-03-11-claudetuner/cover.jpg","permalink":"/ko/posts/2026-03-11-claudetuner/","title":"ClaudeTuner — Claude 사용량 실시간 추적과 플랜 최적화 도구"},{"content":"개요 Google DeepMind가 2026년 3월 10일 Gemini Embedding 2를 공개했다. 텍스트, 이미지, 비디오, 오디오, 문서를 단일 임베딩 공간에 매핑하는 최초의 네이티브 멀티모달 임베딩 모델이다.\ngraph TD A[\"Gemini Embedding 2\"] --\u003e B[\"텍스트\"] A --\u003e C[\"이미지\"] A --\u003e D[\"비디오\"] A --\u003e E[\"오디오\"] A --\u003e F[\"문서\"] B --\u003e G[\"단일 임베딩 공간 \u0026lt;br/\u0026gt; (동일 벡터 차원)\"] C --\u003e G D --\u003e G E --\u003e G F --\u003e G G --\u003e H[\"멀티모달 검색\"] G --\u003e I[\"크로스모달 분류\"]새로운 모달리티와 유연한 차원 기존 임베딩 모델들은 텍스트만 처리하거나, 멀티모달이더라도 별도의 인코더를 사용했다. Gemini Embedding 2는 네이티브하게 여러 모달리티를 하나의 벡터 공간으로 매핑한다.\n이는 \u0026ldquo;고양이 사진\u0026quot;으로 검색하면 고양이가 등장하는 비디오 클립, 고양이 소리가 담긴 오디오, \u0026ldquo;고양이\u0026quot;라는 텍스트가 포함된 문서를 모두 찾을 수 있다는 뜻이다.\nSOTA 성능 Google은 Gemini Embedding 2가 여러 벤치마크에서 최고 수준(state-of-the-art)의 성능을 달성했다고 발표했다. 텍스트-텍스트 검색뿐 아니라 크로스모달 검색에서도 강력한 성능을 보여준다.\n활용 시나리오 멀티모달 RAG 기존 RAG(Retrieval-Augmented Generation) 파이프라인은 텍스트 문서만 검색 대상으로 삼았다. Gemini Embedding 2를 사용하면 이미지, 비디오, 오디오까지 검색 대상에 포함할 수 있어, 진정한 멀티모달 RAG가 가능해진다.\n미디어 라이브러리 검색 대규모 미디어 아카이브에서 텍스트 쿼리로 이미지/비디오를 검색하거나, 이미지로 유사한 비디오를 찾는 등의 크로스모달 검색이 가능하다.\n콘텐츠 분류 다양한 형태의 콘텐츠를 하나의 분류 체계로 정리할 수 있다. 텍스트 레이블과 이미지/오디오 콘텐츠를 같은 공간에서 비교하므로 별도의 분류 모델이 필요 없다.\n인사이트 멀티모달 임베딩은 검색과 RAG의 게임 체인저가 될 수 있다. 지금까지 \u0026ldquo;이미지 검색\u0026quot;과 \u0026ldquo;텍스트 검색\u0026quot;은 완전히 별개의 파이프라인이었는데, 단일 임베딩 공간이 이 경계를 허문다. 특히 RAG 파이프라인에서 PDF 내 이미지, 프레젠테이션 슬라이드, 화이트보드 사진 등을 텍스트와 동일하게 검색할 수 있게 되면, 기업 지식 관리 시스템의 커버리지가 크게 확장될 것이다. Public preview로 출시되었으므로 바로 테스트해볼 수 있다.\n","date":"2026-03-11T00:00:00+09:00","image":"/images/posts/2026-03-11-gemini-embedding-2/cover.jpg","permalink":"/ko/posts/2026-03-11-gemini-embedding-2/","title":"Gemini Embedding 2 — Google의 최초 네이티브 멀티모달 임베딩 모델"},{"content":"개요 EC2 인스턴스의 디스크 용량이 부족해질 때, df와 du 명령만으로는 어떤 디렉토리가 용량을 많이 차지하는지 파악하기 어렵다. ncdu는 ncurses 기반 TUI로 디스크 사용량을 시각적으로 분석해주는 도구다.\ngraph TD A[\"디스크 용량 부족\"] --\u003e B[\"df: 전체 사용량 확인\"] B --\u003e C[\"du: 디렉토리별 용량\"] C --\u003e D[\"ncdu: 인터랙티브 TUI \u0026lt;br/\u0026gt; 그래프 + 네비게이션 + 삭제\"] style D fill:#4CAF50,color:#fff설치 # Ubuntu/Debian sudo apt-get install ncdu # CentOS/RHEL yum install -y ncdu # macOS brew install ncdu 기본 사용법 # 현재 디렉토리 분석 ncdu # 특정 경로 분석 ncdu /var/log # 전체 디스크 분석 ncdu / 실행하면 스캔 후 그래픽 막대와 함께 디렉토리/파일의 트리 구조가 표시된다. 어디에서 용량을 많이 사용하는지 직관적으로 파악할 수 있다.\n주요 조작 키 동작 방향키 디렉토리 탐색 Enter 하위 디렉토리 진입 i 선택 항목 상세 정보 d 선택 항목 삭제 (확인 필요) ? / Shift+? 도움말 q 종료 df, du와의 차이 도구 장점 단점 df 파티션별 전체 사용량 즉시 확인 어떤 디렉토리가 문제인지 모름 du 디렉토리별 용량 계산 출력이 길고 정렬이 번거로움 ncdu 인터랙티브 TUI, 즉시 정렬, 삭제 가능 별도 설치 필요 인사이트 서버 디스크 관리에서 ncdu는 htop이 프로세스 관리에 하는 것과 같은 역할을 한다 — 기본 명령어(df, du)로 할 수 있는 일이지만, TUI로 인터랙티브하게 탐색할 수 있다는 것만으로 효율이 크게 달라진다. 특히 EC2처럼 디스크 용량이 제한된 환경에서 갑자기 디스크가 가득 찼을 때, ncdu 하나면 원인 파악부터 정리까지 터미널을 벗어나지 않고 처리할 수 있다.\n","date":"2026-03-11T00:00:00+09:00","image":"/images/posts/2026-03-11-ncdu/cover.jpg","permalink":"/ko/posts/2026-03-11-ncdu/","title":"ncdu — 리눅스 디스크 사용량을 한눈에 파악하는 TUI 도구"},{"content":"개요 \u0026ldquo;집 PC에서 하던 OpenCode 작업을 밖에서 그대로 이어서 하고 싶다.\u0026rdquo; SSH는 번거롭고 모바일로는 더 답답한 상황에서, opencode serve/web이 해결책이 될 수 있다.\ngraph LR A[\"작업 머신 \u0026lt;br/\u0026gt; opencode serve/web\"] --\u003e|API + 웹 UI| B[\"Tailscale VPN\"] B --\u003e C[\"모바일 브라우저 \u0026lt;br/\u0026gt; 같은 세션 접속\"] A --\u003e D[\"레포 접근\"] A --\u003e E[\"도구 실행\"] A --\u003e F[\"모델 호출\"]핵심 개념: \u0026ldquo;TUI가 본체가 아니라, 서버가 본체\u0026rdquo; opencode의 아키텍처에서 중요한 관점 전환이 있다. TUI(터미널 UI)는 단순히 서버에 접속하는 클라이언트일 뿐, 실제 작업의 \u0026ldquo;본체\u0026quot;는 서버(백엔드)다. 이 관점을 이해하면 원격 개발이 자연스러워진다.\nopencode web 급할 때 가장 편한 방법이다. API 서버와 웹 UI를 함께 올려주기 때문에, 별도 앱이나 SSH 없이도 폰 브라우저만 열면 \u0026ldquo;방금 하던 그 화면\u0026quot;으로 들어갈 수 있다.\n무거운 작업(레포 접근, 도구 실행, 모델 호출)은 서버 머신이 처리하고, 모바일 기기는 입력과 화면만 담당한다.\nopencode serve opencode serve는 \u0026ldquo;화면 없는 백엔드\u0026quot;를 띄우는 명령이다. 웹 UI 없이 API 서버만 실행되므로, 커스텀 클라이언트를 연결하거나 자동화 파이프라인에서 사용할 수 있다.\n보안: Tailscale + 비밀번호 포트를 직접 열지 않고 Tailscale VPN을 통해 접속하는 것이 권장된다. Tailscale 네트워크 내에서만 접근 가능하므로 외부 노출 위험이 없다.\n인사이트 AI 코딩 도구의 \u0026ldquo;서버-클라이언트 분리\u0026rdquo; 패턴이 점점 일반화되고 있다. GitHub Codespaces, code-server, 그리고 이제 opencode까지 — \u0026ldquo;무거운 연산은 서버, 인터랙션은 클라이언트\u0026quot;라는 아키텍처가 AI 코딩에서도 자연스럽게 자리잡고 있다. 특히 모바일에서 AI 에이전트에게 간단한 지시를 내릴 수 있다는 점은, 개발 워크플로우의 시간적 제약을 크게 줄여줄 수 있다.\n","date":"2026-03-11T00:00:00+09:00","image":"/images/posts/2026-03-11-opencode-remote/cover.jpg","permalink":"/ko/posts/2026-03-11-opencode-remote/","title":"opencode serve/web — 폰으로 개발PC 원격 제어하기"},{"content":"개요 Claude Code는 Anthropic이 만든 에이전트 코딩 도구다. 단순히 코드 자동완성을 제공하는 수준이 아니라, 코드베이스 전체를 읽고, 파일을 편집하고, 터미널 명령을 직접 실행하며, 개발 도구와 깊게 통합되는 방식으로 동작한다. 2026년 초 기준으로 Claude Code는 Terminal, VS Code, Desktop app, Web, JetBrains, Chrome extension(beta)에 이르기까지 개발자가 일하는 거의 모든 환경을 지원하고 있다.\n최근 유튜브 채널 @codefactory_official이 올린 쇼트 영상(\u0026ldquo;클로드 코드 최신 업데이트 Statusline\u0026rdquo;)이 246개의 좋아요를 받으며 주목받았다. 제목의 핵심 키워드인 Statusline — 터미널 하단에 표시되는 상태표시줄 — 이 추가되면서 터미널 UI가 한층 더 스마트해졌다는 것이 영상의 요지다. 이 글에서는 Statusline 업데이트를 시작으로, Claude Code가 구축하고 있는 멀티 환경 AI 코딩 생태계 전체를 정리한다.\nStatusline — 터미널이 더 스마트해졌다 Statusline은 Claude Code가 터미널 인터페이스에 추가한 상태표시줄 UI 컴포넌트다. 기존에는 Claude Code를 터미널에서 실행할 때 어떤 작업이 진행 중인지, 현재 컨텍스트가 얼마나 소비되었는지 등을 한눈에 확인하기 어려웠다. Statusline이 추가되면서 터미널 하단에 현재 작업 상태, 사용 중인 모델 정보, 컨텍스트 사용량 등이 실시간으로 표시된다.\n이 변화는 단순한 UX 개선 이상의 의미를 갖는다. 터미널 기반 개발 워크플로우를 선호하는 개발자들에게 Claude Code는 이제 IDE 수준의 시각적 피드백을 터미널 안에서 제공한다. tmux나 zellij 같은 멀티플렉서와 함께 사용할 때도 Statusline이 제 역할을 하며, 여러 세션을 동시에 관리할 때 각 세션의 상태를 명확하게 구분할 수 있게 되었다. \u0026ldquo;터미널이 이뻐졌다\u0026hellip;?\u0026ldquo;는 영상 설명 문구가 가볍게 들릴 수 있지만, 실제로 이는 Claude Code가 터미널을 1등 시민(first-class citizen)으로 대우하겠다는 방향성을 명확히 보여준다.\nStatusline의 도입은 Claude Code가 단순한 CLI 도구를 넘어 완성도 높은 터미널 개발 환경으로 진화하고 있음을 보여준다. 기존 AI 코딩 도구들이 주로 GUI IDE 플러그인 형태로 제공되었던 것과 달리, Claude Code는 터미널을 중심에 두고 다른 환경들을 확장으로 지원한다는 독특한 포지셔닝을 갖고 있다. 이 방향성은 서버 접속, CI/CD 파이프라인, Docker 컨테이너 내부 등 GUI가 없는 환경에서 AI 코딩 어시스턴트를 활용해야 하는 수요를 정확히 겨냥한 것이다.\nClaude Code가 지원하는 모든 환경 graph TD CC[Claude Code 코어] CC --\u003e T[TerminalCLI / Statusline] CC --\u003e VS[VS Code익스텐션] CC --\u003e DA[Desktop AppmacOS / Windows] CC --\u003e WB[Web Browserclaude.ai] CC --\u003e JB[JetBrainsIntelliJ 계열] CC --\u003e CR[Chrome Extensionbeta] CC --\u003e RC[Remote Control모바일 / 원격 기기] CC --\u003e GA[GitHub ActionsCI/CD 통합] CC --\u003e GL[GitLab CI/CD파이프라인 통합] CC --\u003e SL[Slack팀 협업 통합] CC --\u003e SDK[Agent SDK커스텀 에이전트] CC --\u003e MCP[MCP도구 연결 프로토콜] style CC fill:#4a90d9,color:#fff style RC fill:#f5a623,color:#fff style SDK fill:#7ed321,color:#fff style MCP fill:#9b59b6,color:#fffClaude Code가 지원하는 환경은 크게 두 축으로 나눌 수 있다. 첫째는 개발자가 직접 인터랙션하는 인터페이스 계층으로, Terminal(CLI), VS Code 익스텐션, Desktop App, Web(claude.ai), JetBrains 계열 IDE, Chrome Extension(beta)이 여기에 해당한다. 둘째는 자동화 및 통합 계층으로, GitHub Actions, GitLab CI/CD, Slack 통합, Remote Control, Agent SDK가 포함된다.\nVS Code 익스텐션은 에디터 내에서 Claude Code를 직접 호출할 수 있게 해준다. 파일을 열어놓은 상태에서 \u0026ldquo;이 함수를 리팩터링해줘\u0026rdquo;, \u0026ldquo;이 모듈에 대한 테스트를 작성해줘\u0026rdquo; 같은 자연어 명령을 내리면 Claude Code가 현재 열려 있는 파일의 컨텍스트를 파악하고 편집을 수행한다. JetBrains 지원은 IntelliJ IDEA, PyCharm, GoLand, WebStorm 등 JetBrains 계열 IDE 전체를 커버하며, Java/Kotlin/Python 등 JetBrains 생태계를 주로 사용하는 백엔드 개발자들도 Claude Code를 자신의 IDE 안에서 사용할 수 있다.\nChrome Extension은 현재 beta 상태이지만 흥미로운 가능성을 열어준다. 브라우저에서 코드가 표시된 웹페이지(GitHub, GitLab, 문서 사이트 등)를 보면서 바로 Claude Code와 상호작용할 수 있다. 이는 PR 리뷰나 오픈소스 코드 탐색 시 특히 유용하다. 설치 방법은 macOS/Linux 기준으로 curl -fsSL https://claude.ai/install.sh | bash 한 줄로 가능하며, Windows에서는 PowerShell 스크립트를 통해 설치한다.\nRemote Control과 비동기 코딩의 미래 Remote Control은 Claude Code의 기능 중 가장 혁신적인 것 중 하나다. 로컬 개발 세션을 실행해 두고 휴대폰이나 다른 기기에서 그 세션을 계속 이어갈 수 있다. 예를 들어, 사무실에서 복잡한 리팩터링 작업을 Claude Code에 맡겨두고 퇴근한 뒤 스마트폰에서 진행 상황을 확인하고 다음 지시를 내릴 수 있다. 이는 AI 코딩의 패러다임을 동기식(synchronous) 인터랙션에서 비동기식(asynchronous) 협업으로 전환시키는 핵심 기능이다.\nRemote Control의 기술적 기반은 Claude Code의 세션 영속성(session persistence)에 있다. 로컬 머신에서 실행 중인 Claude Code 인스턴스는 세션 상태를 서버에 동기화하며, 권한을 부여받은 다른 기기는 이 세션에 연결하여 지시를 전달하거나 결과를 확인할 수 있다. 이 구조 덕분에 장시간 실행되는 작업(대규모 코드베이스 마이그레이션, 전체 테스트 스위트 실행 등)을 맡겨두고 필요할 때만 개입하는 방식이 가능해진다.\nGitHub Actions 및 GitLab CI/CD 통합은 Remote Control의 자동화 확장판이라 볼 수 있다. PR이 열리면 Claude Code가 자동으로 코드를 리뷰하고, 테스트가 실패하면 원인을 분석하고 수정안을 제안한다. 이는 CI/CD 파이프라인을 단순한 빌드/테스트 자동화를 넘어 AI 지원 코드 품질 게이트로 격상시킨다. Slack 통합을 통해서는 팀 채널에서 Claude Code에게 작업을 할당하고 결과 리포트를 받을 수 있어, 개발팀의 비동기 협업 워크플로우에 자연스럽게 녹아든다.\n에이전트 생태계 확장 — MCP, Skills, Hooks MCP(Model Context Protocol)는 Claude Code가 외부 도구와 연결되는 표준 프로토콜이다. 데이터베이스, API, 파일 시스템, 다른 AI 서비스 등 어떤 도구든 MCP 서버로 구현하면 Claude Code가 자연어 명령으로 해당 도구를 사용할 수 있게 된다. Anthropic은 MCP를 오픈 스펙으로 공개했으며, 이미 다수의 서드파티 MCP 서버가 생태계를 구성하고 있다. 이 저장소(log-blog)도 Claude Code skill로 Claude AI를 지능 계층으로 활용하는 구조를 채택하고 있다.\nSkills와 Hooks는 Claude Code의 커스터마이징 레이어다. Skills는 Claude Code가 특정 도메인이나 프로젝트에 특화된 행동을 학습하게 하는 방법으로, SKILL.md 파일에 도메인 지식과 작업 패턴을 정의하면 Claude Code가 이를 참조하여 더 정확한 결과를 낸다. Hooks는 특정 이벤트(파일 저장, 명령 실행 전후 등)에 커스텀 스크립트를 연결하는 메커니즘으로, 프로젝트별 규칙 강제나 자동화 파이프라인 구축에 활용된다.\nAgent SDK는 Claude Code의 가장 확장성 높은 기능이다. 개발자가 직접 커스텀 에이전트를 구축할 수 있게 해주며, 여러 에이전트가 팀을 이루어 복잡한 작업을 분업하는 \u0026ldquo;에이전트 팀\u0026rdquo; 실행도 지원한다. 예를 들어, 하나의 에이전트가 요구사항을 분석하고, 다른 에이전트가 코드를 작성하며, 세 번째 에이전트가 테스트를 실행하고 검증하는 파이프라인을 구성할 수 있다. 이는 단일 AI 어시스턴트의 한계를 넘어 실질적인 멀티 에이전트 소프트웨어 개발의 가능성을 열어준다.\n경쟁 시장도 빠르게 움직이고 있다. Amazon은 최근 Kiro IDE(app.kiro.dev)를 출시했다. AWS Cognito 기반 인증을 사용하는 Kiro는 Amazon의 AI 코딩 생태계를 중심으로 개발자를 끌어들이려는 전략적 움직임이다. GitHub Copilot, Cursor, Windsurf에 이어 Kiro까지 가세하면서 AI 코딩 도구 시장의 경쟁은 더욱 치열해지고 있다. Claude Code가 이 경쟁에서 차별화하는 요소는 에이전트 수준의 자율성, 멀티 환경 지원의 폭, 그리고 MCP를 통한 개방적 확장성이다.\n빠른 링크 Claude Code 공식 문서 (한국어) — 설치부터 Agent SDK까지 전체 가이드 Claude Code 설치 스크립트 — curl -fsSL https://claude.ai/install.sh | bash로 즉시 설치 Anthropic Academy — Claude Code in Action — 공식 실습 코스 YouTube: 클로드 코드 최신 업데이트 Statusline — @codefactory_official 쇼트 영상 Kiro IDE — Amazon의 새 AI IDE, 경쟁 제품 인사이트 Claude Code의 Statusline 업데이트는 사소한 UI 개선처럼 보이지만, Anthropic이 터미널을 AI 코딩의 핵심 인터페이스로 진지하게 투자하고 있다는 신호다. Terminal, VS Code, JetBrains, Web, Chrome Extension까지 아우르는 멀티 환경 지원은 개발자가 어떤 도구를 쓰든 Claude Code를 선택할 수 있게 하려는 전략이며, 특정 IDE 생태계에 lock-in하지 않겠다는 메시지이기도 하다. Remote Control과 GitHub Actions/GitLab 통합이 의미하는 바는 더 깊다 — AI 코딩이 \u0026ldquo;내가 앞에 앉아서 대화하는 도구\u0026quot;에서 \u0026ldquo;백그라운드에서 일하고 결과를 보고하는 에이전트\u0026quot;로 전환되고 있다. MCP의 오픈 스펙 공개와 Agent SDK의 제공은 Claude Code를 단독 도구가 아닌 플랫폼으로 만들려는 시도이며, 이는 경쟁사 대비 중요한 해자(moat)가 될 수 있다. Amazon Kiro, GitHub Copilot Workspace, Cursor 등 경쟁 제품들도 빠르게 에이전트 기능을 강화하고 있어, 2026년은 AI 코딩 도구가 진정한 자율 에이전트로 도약하는 원년이 될 것으로 보인다. 이 경쟁에서 승자는 단순한 코드 생성 품질이 아니라, 개발자의 전체 워크플로우에 얼마나 자연스럽게 녹아드는가로 결정될 가능성이 높다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-claude-code-statusline-2026/cover.jpg","permalink":"/ko/posts/2026-03-06-claude-code-statusline-2026/","title":"Claude Code 2026 — Statusline 업데이트와 멀티 환경 AI 코딩 생태계"},{"content":"개요 프레젠테이션 자료 하나를 만들기 위해 쏟는 시간을 생각해보면, 보통 자료 수집에 몇 시간, 내용 정리에 몇 시간, 슬라이드 디자인에 또 몇 시간이 들어간다. 이 과정을 AI로 자동화한다는 아이디어는 이전에도 있었지만, 실제로 고퀄리티 결과물을 만들어내는 실전 워크플로우는 드물었다. Google의 두 AI 도구 — NotebookLM과 Gemini — 를 조합하면 이 문제가 달라진다.\n유튜브에 올라온 영상(\u0026ldquo;제미나이 + 노트북LM으로 고퀄리티 PPT 진짜 쉽게 만드는 미친 조합법\u0026rdquo;, 14분 20초)이 큰 반향을 얻은 이유가 여기 있다. 단순히 \u0026ldquo;AI에게 PPT 만들어줘\u0026quot;라고 요청하는 수준이 아니라, 각 도구의 강점을 분업해 시너지를 극대화하는 체계적인 방법론을 제시했기 때문이다. NotebookLM이 리서치와 합성을 담당하고, Gemini가 콘텐츠 생성과 포매팅을 담당하는 이 조합은 \u0026ldquo;미친 조합법\u0026quot;이라는 표현이 과장이 아닐 만큼 효율적이다.\nNotebookLM이란 무엇인가 NotebookLM은 Google이 제공하는 AI 기반 리서치 도구로 무료로 사용할 수 있다. 일반 LLM과 결정적으로 다른 점은 사용자가 제공한 소스 문서만을 기반으로 답변한다는 것이다. PDF, Google Docs, Google Slides, YouTube 동영상 링크, 웹페이지 URL, 일반 텍스트 파일 등 다양한 형식의 자료를 노트북에 추가하면, NotebookLM은 이 자료들을 분석해 질문에 답하고, 요약을 생성하고, 인사이트를 도출한다. 출처가 명확하게 표시되기 때문에 AI가 할루시네이션(환각)으로 없는 내용을 만들어내는 위험이 크게 줄어든다.\nNotebookLM의 기능 중 특히 주목할 만한 것은 Audio Overview다. 노트북에 추가한 자료를 바탕으로 AI가 팟캐스트 형식의 오디오 해설을 자동 생성해준다. 두 명의 AI 호스트가 마치 라디오 방송처럼 자연스럽게 대화하며 핵심 내용을 설명하는 방식이다. PPT 제작과 직접 연관되지는 않지만, 자료를 빠르게 파악하는 용도로 탁월하다. 이 외에도 마인드맵, 스터디 가이드, 브리핑 문서, FAQ 형식으로 자료를 재구성하는 기능을 제공하며, 이 결과물들이 PPT 제작의 입력 재료로 활용된다.\nNotebookLM의 또 다른 강점은 여러 소스를 동시에 교차 분석하는 능력이다. 예를 들어 논문 3편, 유튜브 강의 2개, 관련 뉴스 기사 5개를 한 노트북에 넣고 \u0026ldquo;이 자료들을 종합했을 때 핵심 논지는 무엇인가?\u0026ldquo;라고 물으면, NotebookLM은 각 소스의 관련 부분을 인용하면서 통합된 분석을 제공한다. 이 기능이 PPT 리서치 단계에서 수 시간의 작업을 수십 분으로 단축시키는 핵심 역할을 한다. 특히 발표 주제가 복잡하거나 다양한 관점을 포함해야 할 때 효과가 극대화된다.\nGemini의 역할 Gemini는 Google의 멀티모달 대형 언어 모델로, gemini.google.com/app에서 무료로 사용할 수 있다. GPT-4나 Claude와 경쟁하는 포지션의 모델로, 텍스트 생성, 요약, 코드 작성, 이미지 분석 등을 지원한다. Gemini 2.0부터는 멀티모달 기능이 강화되어 이미지를 입력으로 받아 설명하거나, 차트에서 데이터를 추출하는 등의 작업도 가능하다.\nPPT 제작 워크플로우에서 Gemini는 NotebookLM이 정리한 리서치 결과를 입력으로 받아 실제 슬라이드 콘텐츠를 생성하는 역할을 한다. \u0026ldquo;다음 내용을 10장의 슬라이드로 구성해줘. 각 슬라이드에는 제목, 핵심 포인트 3개, 발표자 노트를 포함해줘\u0026quot;와 같은 구체적인 프롬프트를 사용하면 바로 편집 가능한 슬라이드 구조가 출력된다. Google Slides와의 통합이 자연스러운 것도 장점이다. Gemini에서 생성한 내용을 Google Docs에 붙여넣고, Google Slides로 변환하거나 Gemini in Slides 기능을 직접 활용하는 방식으로 연결된다.\nGemini의 강점 중 하나는 구체적인 포매팅 지시를 잘 따른다는 것이다. 예를 들어 \u0026ldquo;각 섹션을 인트로 → 문제 제기 → 해결책 → 사례 → 요약 구조로 짜줘\u0026rdquo;, \u0026ldquo;비전문가 청중을 위해 전문 용어는 쉬운 말로 풀어줘\u0026rdquo; 같은 세부 지시를 주면 그에 맞는 출력이 나온다. NotebookLM이 \u0026ldquo;무엇을 말할 것인가\u0026quot;를 결정했다면, Gemini는 \u0026ldquo;어떻게 말할 것인가\u0026quot;를 결정한다고 볼 수 있다.\n실전 PPT 제작 워크플로우 flowchart LR A[자료 수집 \u0026lt;br/\u0026gt; PDF, 유튜브, 웹페이지] --\u003e B[NotebookLM에 \u0026lt;br/\u0026gt; 소스 추가] B --\u003e C[NotebookLM 분석 \u0026lt;br/\u0026gt; 요약 / 마인드맵 / FAQ] C --\u003e D[핵심 인사이트 \u0026lt;br/\u0026gt; 텍스트로 추출] D --\u003e E[Gemini에 입력 \u0026lt;br/\u0026gt; 슬라이드 구조 생성] E --\u003e F[Gemini 출력 \u0026lt;br/\u0026gt; 슬라이드별 제목 + 내용] F --\u003e G[Google Slides \u0026lt;br/\u0026gt; PowerPoint 붙여넣기] G --\u003e H[디자인 편집 \u0026lt;br/\u0026gt; 이미지 추가 / 정렬] H --\u003e I[완성된 고퀄리티 PPT] style A fill:#4285f4,color:#fff style B fill:#34a853,color:#fff style C fill:#34a853,color:#fff style E fill:#4285f4,color:#fff style F fill:#4285f4,color:#fff style I fill:#ea4335,color:#fff실제 워크플로우는 크게 세 단계로 나눌 수 있다. 1단계: 자료 수집 및 NotebookLM 분석. 발표 주제와 관련된 자료를 최대한 다양하게 수집한다. 학술 논문, 관련 유튜브 강연, 업계 리포트, 경쟁사 분석 자료 등을 NotebookLM 노트북 하나에 모두 추가한다. 자료 추가가 완료되면 NotebookLM에 \u0026ldquo;이 자료들을 발표 목적으로 구조화해줘. 주요 섹션을 제안하고 각 섹션의 핵심 포인트를 정리해줘\u0026quot;라고 요청한다. 이 과정에서 마인드맵과 스터디 가이드 생성 기능을 활용하면 자료 전체의 구조를 빠르게 파악할 수 있다.\n2단계: Gemini로 슬라이드 구조 생성. NotebookLM에서 나온 요약과 핵심 인사이트를 복사해 Gemini에 붙여넣는다. 이때 프롬프트를 구체적으로 작성하는 것이 중요하다. 청중 특성(전문가/비전문가), 발표 시간(10분/30분/1시간), 슬라이드 수, 원하는 구조(문제-해결 형식, 스토리텔링 형식 등)를 명시한다. Gemini가 출력하는 슬라이드 구조는 각 슬라이드의 제목, 불릿 포인트, 발표자 노트까지 포함하며, 이것이 PPT의 뼈대가 된다.\n3단계: 편집 및 디자인. Gemini 출력 결과를 Google Slides나 PowerPoint에 붙여넣고 디자인 편집을 진행한다. 이 단계에서 Gemini 2.0의 이미지 분석 기능이 유용하다. 삽입할 그래프나 데이터 이미지를 Gemini에 첨부하면 이미지를 분석해 해석 텍스트를 생성해주고, 발표 맥락에 맞게 설명을 조정할 수 있다. 최종 편집은 사람이 담당하지만, 이 시점에서 편집자는 \u0026ldquo;내용을 만드는 작업\u0026rdquo; 대신 \u0026ldquo;기존 내용을 다듬고 시각화하는 작업\u0026quot;에만 집중할 수 있어 훨씬 효율적이다.\n두 도구를 조합하면 달라지는 것 단일 도구만 사용할 때의 한계가 명확하다. Gemini만 사용하면 자료 기반 없이 모델의 학습 데이터에 의존하게 되어 최신 정보나 특정 맥락에 맞는 내용을 보장하기 어렵다. 할루시네이션 위험도 있다. 반대로 NotebookLM만 사용하면 자료 분석은 뛰어나지만 슬라이드 포매팅이나 발표용 언어로의 변환은 직접 해야 한다. 두 도구를 조합했을 때 비로소 \u0026ldquo;자료의 신뢰성 + 생성의 유연성\u0026quot;이 함께 실현된다.\n조합의 시너지는 특히 \u0026ldquo;이미 알고 있는 것을 체계화해야 하는 발표\u0026quot;보다 \u0026ldquo;새로운 분야를 빠르게 파악해야 하는 발표\u0026quot;에서 극대화된다. 예를 들어 갑자기 낯선 기술 주제로 발표 요청을 받았을 때, 관련 자료 10개를 NotebookLM에 넣고 30분 안에 자료 구조를 파악한 뒤 Gemini로 슬라이드를 생성하면 2시간 내에 발표 준비를 마칠 수 있다. 기존에는 동일한 작업에 하루 이상이 걸리는 경우가 많았다.\n이 조합이 가진 또 다른 가치는 반복 사용 가능성이다. NotebookLM 노트북은 저장되므로 같은 주제에 대해 다양한 각도의 발표 자료를 반복적으로 생성할 수 있다. \u0026ldquo;같은 주제를 임원 대상으로 5분 요약 발표 버전으로 만들어줘\u0026quot;라고 Gemini에 요청하면 이미 정리된 리서치를 바탕으로 새로운 버전이 즉시 생성된다. 주제 전문성이 쌓일수록 노트북의 자료가 축적되고, 이후 발표 제작 속도는 더욱 빨라진다. 이는 단순한 도구 사용을 넘어 개인 지식 베이스 구축으로 이어지는 선순환이다.\n빠른 링크 Google NotebookLM — 무료 AI 리서치 도구, 문서 분석 및 Audio Overview 생성 Google Gemini — Google 멀티모달 LLM, 무료 사용 가능 YouTube: 제미나이 + 노트북LM PPT 조합법 — 14분 20초 실전 튜토리얼 Google Slides — Gemini 출력 결과를 편집하는 최종 도구 NotebookLM 공식 가이드 — 소스 추가 방법 및 기능 설명 인사이트 Gemini + NotebookLM 조합이 주목받는 이유는 두 도구가 AI 생산성의 서로 다른 문제를 각각 해결하기 때문이다. NotebookLM은 \u0026ldquo;AI가 없는 내용을 만들어내는 할루시네이션 문제\u0026quot;를 소스 기반 답변으로 근본적으로 제한하고, Gemini는 \u0026ldquo;정리된 내용을 발표 가능한 형태로 빠르게 변환하는 포매팅 문제\u0026quot;를 해결한다. 이 분업 구조는 AI 도구를 단순히 하나씩 사용하는 것보다 훨씬 신뢰할 수 있는 결과물을 만들어낸다. 앞으로 PPT 자동화 워크플로우가 발전하면 NotebookLM의 분석 결과를 직접 Gemini in Slides로 전달하는 더 긴밀한 통합이 실현될 가능성이 높다. 이 조합이 보여주는 더 큰 시사점은 \u0026ldquo;AI 도구를 잘 쓰는 사람\u0026quot;의 기준이 바뀌고 있다는 것이다 — 프롬프트 엔지니어링 능력도 중요하지만, 여러 AI 도구를 적재적소에 연결하는 워크플로우 설계 능력이 새로운 핵심 역량이 되고 있다. 발표 자료 제작에서 시간 비용이 극적으로 줄어든다는 것은 지식 노동의 생산성 향상 측면에서 중요한 의미를 갖는다 — 전문가가 내용 생성보다 내용 검토와 전략적 판단에 더 많은 시간을 쓸 수 있게 되기 때문이다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-gemini-notebooklm-ppt/cover.jpg","permalink":"/ko/posts/2026-03-06-gemini-notebooklm-ppt/","title":"Gemini + NotebookLM 조합으로 고퀄리티 PPT 만들기 — 자료수집부터 편집까지"},{"content":"개요 Google Antigravity는 Gemini AI를 핵심 엔진으로 탑재한 구글의 AI IDE로, OpenAI Codex, Anthropic Claude Cowork와 함께 AI 주도 개발 환경 시장을 3분하는 신규 플레이어다. 단순한 코드 자동완성을 넘어 자연어 명령만으로 전체 프로젝트를 구성하는 바이브 코딩(vibe coding) 패러다임을 지향하며, Google NotebookLM과 연동해 전문화된 서브에이전트 아키텍처까지 구축할 수 있다는 점이 경쟁 도구와의 핵심 차별점이다.\nAntigravity 기본 설정과 UI 구조 Antigravity를 처음 실행하면 Cursor나 VS Code와 유사한 웹 기반 IDE 레이아웃이 나타나지만, 인터페이스의 주도권이 코드 에디터가 아닌 AI 채팅 패널에 있다는 점에서 근본적으로 다르다. 좌측 사이드바에는 파일 트리와 프로젝트 네비게이터가 위치하고, 중앙 영역은 코드 편집기가 차지하지만, 우측의 Gemini 채팅 패널이 실질적인 작업의 시작점 역할을 한다. UI 버튼 하나하나가 특정 Gemini 기능에 매핑되어 있어, 툴바를 읽는 것 자체가 이 도구의 설계 철학을 이해하는 경로다.\n기본 설정 단계에서 가장 중요한 작업은 Google 계정 연동과 프로젝트 초기화다. 계정 연동 후 새 프로젝트를 생성하면 Gemini가 프로젝트 컨텍스트를 자동으로 파악하고, 이후 모든 채팅 요청은 해당 컨텍스트를 기반으로 처리된다. 특히 MCP(Model Context Protocol) 연결 설정 옵션이 기본 세팅 화면에 노출되어 있다는 점이 주목할 만하다 — 구글이 MCP를 외부 도구 연동의 표준 인터페이스로 공식 채택했다는 신호로 읽힌다.\n바이브 코딩 관점에서 Antigravity의 진입 장벽은 다른 AI IDE보다 낮은 편이다. \u0026ldquo;React로 할 일 관리 앱 만들어줘\u0026quot;라고 입력하면 Gemini가 파일 구조를 제안하고, 승인하면 곧바로 코드를 생성하며, 결과물은 내장 미리보기 창에서 즉시 확인할 수 있다. 이 흐름은 Claude Cowork나 Codex와 표면적으로 유사하지만, Google Cloud 인프라와의 직접 통합(Cloud Run 배포, Firebase 연동 등)이 원클릭 수준으로 지원된다는 점에서 구글 생태계 내 개발자에게는 명확한 이점이 존재한다.\nAI IDE 3파전 비교 — Antigravity vs Codex vs Claude Cowork 세 도구는 모두 자연어 기반 코드 생성을 표방하지만, 설계 철학과 실제 사용 경험은 뚜렷하게 갈린다. OpenAI Codex는 터미널 친화적인 CLI 에이전트에 가깝고, Anthropic Claude Cowork는 긴 컨텍스트 처리와 정교한 코드 리뷰에 강점을 보이며, Google Antigravity는 시각적 UI와 Google 서비스 에코시스템 통합을 전면에 내세운다. 어느 도구가 우월하다기보다는, 개발자의 작업 스타일과 사용하는 클라우드 환경에 따라 선택지가 달라지는 구조다.\n코드 품질 측면에서 세 도구의 차이는 복잡한 로직을 다룰 때 두드러진다. Claude Cowork는 긴 컨텍스트 윈도우 덕분에 대형 코드베이스 전체를 참조하는 리팩터링에서 두각을 나타내고, Codex는 테스트 작성과 자동화 스크립트 생성에서 일관된 성능을 보인다. Antigravity는 UI 컴포넌트 생성과 Google Cloud 관련 보일러플레이트 코드에서 가장 빠른 결과물을 제공하지만, 도메인 특화 로직이 복잡해질수록 다른 두 도구에 비해 수정 사이클이 늘어나는 경향이 관찰된다.\ngraph TD Dev[개발자 — 자연어 요청] Dev --\u003e AG[Google Antigravity] Dev --\u003e Codex[OpenAI Codex] Dev --\u003e CW[Claude Cowork] AG --\u003e AG_Engine[Gemini 2.0 Flash] Codex --\u003e OAI_Engine[GPT-4o / o3] CW --\u003e CW_Engine[Claude 3.7 Sonnet] AG_Engine --\u003e AG_Feat[Google Cloud 통합 \u0026lt;br/\u0026gt; MCP 지원 \u0026lt;br/\u0026gt; NotebookLM 연동] OAI_Engine --\u003e Codex_Feat[CLI 에이전트 \u0026lt;br/\u0026gt; 터미널 중심 \u0026lt;br/\u0026gt; 파일시스템 접근] CW_Engine --\u003e CW_Feat[긴 컨텍스트 처리 \u0026lt;br/\u0026gt; 코드 리뷰 특화 \u0026lt;br/\u0026gt; MCP 지원] AG_Feat --\u003e Deploy_AG[Firebase / Cloud Run] Codex_Feat --\u003e Deploy_OAI[범용 환경] CW_Feat --\u003e Deploy_CW[범용 환경] style AG fill:#4285F4,color:#fff style Codex fill:#10a37f,color:#fff style CW fill:#cc785c,color:#fffMCP 지원 여부는 세 도구 비교에서 점점 더 중요한 축이 되고 있다. Claude Cowork는 MCP의 원조 지지자였고, Antigravity도 이를 빠르게 채택했으며, Codex 역시 유사한 외부 도구 연동 메커니즘을 갖추어 가고 있다. 이는 AI IDE 경쟁의 다음 전선이 모델 품질 벤치마크보다 에코시스템 연동 깊이로 이동하고 있음을 시사한다 — 어떤 외부 데이터 소스와 서비스를 얼마나 자연스럽게 연결할 수 있는가가 실질적인 생산성 차이를 결정하는 시대가 오고 있다.\nNotebookLM 연동 서브에이전트 구축 Google NotebookLM은 원래 문서 분석과 지식 관리 도구로 알려져 있지만, Antigravity와 연동하면 도메인 특화 지식을 가진 서브에이전트로 변신한다. 연동 방법은 두 가지 경로가 있다. 첫 번째는 NotebookLM의 공유 링크를 Antigravity의 MCP 설정에 등록하는 방식으로, NotebookLM이 보유한 문서 지식을 Antigravity의 채팅 컨텍스트로 직접 주입할 수 있다. 두 번째는 NotebookLM의 API 엔드포인트를 커스텀 MCP 서버로 래핑하는 방식으로, 더 정교한 쿼리 제어가 가능하지만 초기 설정 비용이 상대적으로 높다.\n서브에이전트 아키텍처의 실용적 가치는 명확하다. 예를 들어 레거시 시스템의 내부 문서 수백 페이지를 NotebookLM에 업로드하고, 이를 Antigravity에 연결하면 \u0026ldquo;이 레거시 API를 호출하는 새 Python 클라이언트 작성해줘\u0026quot;라는 요청에 Antigravity가 NotebookLM에서 관련 스펙을 검색해 근거 있는 코드를 생성한다. 일반적으로 AI IDE가 환각(hallucination)에 빠지기 쉬운 내부 도메인 지식 영역에서 정확도를 크게 높일 수 있다는 점이 핵심 가치다.\n서브에이전트 구축 과정에서 핵심 개념은 역할 분담이다. Antigravity는 코드 생성과 실행을 담당하는 오케스트레이터 역할을 하고, NotebookLM은 도메인 지식을 제공하는 리트리버 역할을 한다. 이 패턴은 RAG(Retrieval-Augmented Generation) 아키텍처와 본질적으로 동일하지만, 개발자가 별도의 벡터 데이터베이스를 구축하거나 임베딩 파이프라인을 관리할 필요 없이 GUI 수준의 설정만으로 동일한 효과를 얻을 수 있다는 점이 혁신적이다.\n실제 데모에서 확인된 한계도 있다. NotebookLM과 Antigravity 간의 컨텍스트 전달 지연이 체감될 만큼 존재하며, NotebookLM의 응답이 길어질수록 Antigravity의 코드 생성 품질이 다소 저하되는 경향이 보고된다. 또한 현재는 NotebookLM의 특정 노트북에 대한 접근 권한 관리가 세밀하지 않아, 팀 환경에서 사용할 때는 정보 보안 측면에서 추가적인 고려가 필요하다. 그럼에도 불구하고 이 연동 패턴이 보여주는 가능성 — 도메인 지식 베이스를 AI IDE에 플러그인하는 방식 — 은 향후 엔터프라이즈 AI 개발 환경의 핵심 아키텍처가 될 가능성이 높다.\n빠른 링크 구글 안티그래비티 기본 설정 및 사용방법, 코덱스 앱, 클로드 코워크와 비교 — 오늘코드todaycode 채널, 29분 43초. UI 버튼별 기능 소개와 3파전 비교 실습 안티그래비티 + 노트북 LM으로 만드는 서브 에이전트 — 투쏠 AI 에이전트 채널, 14분 20초. NotebookLM 연동 두 가지 방법과 에이전트 구축 실전 인사이트 Google Antigravity의 등장이 의미하는 바는 단순히 경쟁자가 하나 더 늘었다는 것 이상이다. Google이 Gemini를 단독 제품이 아닌 IDE라는 개발자 도구 내에 통합한 것은, AI 모델 경쟁의 주 전장이 API 성능 벤치마크에서 개발자 워크플로우 통합으로 이동했음을 명확히 보여준다. NotebookLM 서브에이전트 연동은 특히 흥미로운데, 이는 AI IDE가 단일 모델의 한계를 여러 전문화된 에이전트로 보완하는 방향으로 진화하고 있음을 시사한다. MCP가 이 에코시스템을 연결하는 표준 프로토콜로 자리잡아 가는 흐름도 뚜렷하다 — Anthropic이 제안하고, Google이 채택하고, OpenAI도 호환 방향으로 움직이는 수렴이 일어나고 있다. 바이브 코딩이라는 개념 자체도 점점 현실화되고 있지만, 현 시점에서는 설계 단계의 빠른 프로토타이핑과 보일러플레이트 생성에서 가장 실용적이며, 복잡한 비즈니스 로직 구현에서는 여전히 개발자의 판단과 검증이 필수다. AI IDE 3파전의 진짜 승자는 특정 모델이 아니라, 개발자의 기존 스택과 가장 자연스럽게 통합되는 도구가 될 가능성이 높다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-google-antigravity-ide-analysis/cover.jpg","permalink":"/ko/posts/2026-03-06-google-antigravity-ide-analysis/","title":"Google Antigravity IDE 완전 분석 — AI IDE 전쟁의 새 플레이어"},{"content":"개요 Google Code Wiki는 codewiki.google에서 공개된 구글의 새로운 AI 문서화 도구로, Gemini가 코드베이스를 분석해 인터랙티브한 지식 베이스를 자동으로 생성하고 PR 병합 시마다 관련 문서를 실시간으로 갱신한다. \u0026ldquo;Stop documenting. Start understanding.\u0026ldquo;이라는 슬로건이 압축하듯, 이 도구는 문서화를 개발자가 직접 작성하는 부담에서 AI가 자동으로 유지하는 인프라로 전환하려는 시도다.\nCode Wiki란 무엇인가 Code Wiki는 표면적으로는 자동 문서화 도구처럼 보이지만, 그 본질은 코드베이스를 살아있는 지식 그래프로 변환하는 에이전트 시스템이다. 기존의 문서화 도구들 — Confluence, Notion, GitBook — 은 개발자가 내용을 직접 작성하고, 코드가 변경되어도 문서는 자동으로 따라가지 않는다는 구조적 한계를 가진다. 코드와 문서 사이의 이 \u0026ldquo;드리프트(drift)\u0026ldquo;는 대형 코드베이스에서 만성적인 문제다. Code Wiki는 Gemini AI 에이전트가 코드를 직접 읽고 문서를 생성하기 때문에, 코드가 진실의 원천(source of truth)이 되고 문서는 그 파생물이 된다.\n도구의 핵심 포지셔닝은 \u0026ldquo;agentic era를 위한 새로운 개발 관점(A new perspective on development for the agentic era)\u0026ldquo;이라는 문구에 담겨 있다. 에이전트 시대란 AI가 단순히 도구를 보조하는 것이 아니라 스스로 판단하고 행동하는 시대를 뜻하는데, Code Wiki는 문서화라는 영역에서 그 에이전트적 역할을 맡겠다고 선언하는 것이다. Gemini-generated documentation이 항상 최신 상태(always up-to-date)를 유지한다는 약속은, 인간이 문서를 유지보수해야 하는 의무에서 해방될 수 있다는 가능성을 제시한다.\n현재 Code Wiki는 초대 기반(invite only)으로 운영되며, 일부 주목할 만한 오픈소스 저장소들을 피처드 리포(featured repos)로 공개 데모하고 있다. 프라이빗 리포지토리 지원은 \u0026ldquo;Coming Soon\u0026rdquo; 상태다. 이 단계적 공개 전략은 AI 생성 문서의 품질을 공개 검증하면서 인프라를 확장하려는 신중한 접근으로 읽힌다.\n핵심 기능 분석 Code Wiki의 첫 번째 핵심 기능은 섹션별 심층 탐색(Understand your code section by section)이다. 단순히 전체 코드베이스의 개요를 생성하는 것이 아니라, 특정 섹션을 선택해 해당 섹션이 어떻게 동작하는지 드릴다운할 수 있다. 이는 신규 팀원이 대형 프로젝트에 온보딩할 때, 또는 오랜만에 돌아온 개발자가 특정 서비스의 동작을 파악할 때 기존 방식 — 코드를 직접 읽거나 동료에게 물어보거나 — 을 대체할 수 있는 기능이다. Gemini가 생성한 설명이 얼마나 정확하고 유용한지가 관건이지만, 이 인터랙티브한 탐색 경험 자체는 문서화의 새로운 UX를 제안한다.\n자동 업데이트 메커니즘은 Code Wiki에서 기술적으로 가장 흥미로운 부분이다. PR이 병합될 때마다 Gemini 에이전트가 변경된 코드를 분석하고 관련 문서를 자동으로 갱신한다. 이 파이프라인이 제대로 동작하려면 diff 분석, 연관 문서 식별, 기존 문서와의 정합성 유지라는 세 가지 어려운 문제를 동시에 풀어야 한다. 특히 리팩터링처럼 코드 구조 자체가 크게 바뀌는 경우, AI가 이전 문서의 어느 부분을 수정하고 어느 부분을 폐기해야 하는지 판단하는 것은 상당한 추론 능력을 요구한다.\n코드와 문서 사이의 양방향 링크(Linked back to your code) 기능은 실용적 가치가 높다. 아키텍처 개요를 읽다가 특정 서비스에 대한 설명을 클릭하면 해당 서비스의 소스 파일로 이동하고, 함수 설명에서 그 함수의 정의 위치로 바로 점프할 수 있다. 이는 문서와 코드가 별도의 사일로(silo)에 존재하던 기존 방식에서 벗어나, 문서가 코드의 네비게이션 레이어로 기능하는 새로운 패턴을 제시한다. JetBrains의 코드 내비게이션이나 GitHub의 코드 검색이 코드 레벨에서 이 경험을 제공했다면, Code Wiki는 자연어 설명 레벨에서 같은 경험을 시도한다.\n다이어그램 자동 생성 기능도 주목할 만하다. 복잡한 시스템을 머릿속에서 조각을 맞추는 대신, 코드가 명확하고 직관적인 시각적 다이어그램으로 변환된다는 약속이다. 대형 마이크로서비스 아키텍처에서 서비스 간 의존성을 파악하거나, 복잡한 데이터 흐름을 이해하는 데 이 다이어그램이 실제로 얼마나 정확한지는 더 많은 실사용 사례가 필요하다. 다만 AI가 코드에서 직접 추출한 다이어그램이라면, 사람이 수동으로 그린 다이어그램보다 최신 상태를 더 잘 반영할 가능성이 높다.\ngraph TD Repo[GitHub 저장소] PR[PR 병합] Agent[Gemini AI 에이전트] DocGen[문서 자동 생성 \u0026lt;br/\u0026gt; 섹션별 설명 \u0026lt;br/\u0026gt; 다이어그램] Wiki[Code Wiki \u0026lt;br/\u0026gt; 인터랙티브 지식 베이스] Chat[자연어 질의 \u0026lt;br/\u0026gt; 코드베이스 채팅] CodeLink[코드 직접 링크 \u0026lt;br/\u0026gt; 정의로 점프] Repo --\u003e|초기 분석| Agent PR --\u003e|변경사항 트리거| Agent Agent --\u003e|자동 생성 및 갱신| DocGen DocGen --\u003e Wiki Wiki --\u003e Chat Wiki --\u003e CodeLink CodeLink --\u003e Repo style Agent fill:#4285F4,color:#fff style Wiki fill:#34A853,color:#fff코드베이스와의 자연어 채팅(Talk to your codebase) 기능은 \u0026ldquo;24/7 온콜 엔지니어\u0026rdquo; 경험을 제공한다는 설명이 붙어 있다. 이는 단순한 문서 검색이 아니라, 코드베이스를 이해하는 AI와 실시간으로 대화하는 경험을 의미한다. \u0026ldquo;이 API 엔드포인트는 어떤 인증 방식을 사용하나요?\u0026rdquo;, \u0026ldquo;결제 서비스와 주문 서비스 사이에 어떤 이벤트가 오가나요?\u0026rdquo; 같은 질문에 즉시 답변을 받을 수 있다면, 신규 팀원의 온보딩 시간과 시니어 개발자의 컨텍스트 공유 부담을 동시에 줄일 수 있다.\n에이전트 시대의 문서화 패러다임 변화 전통적인 문서화 철학은 \u0026ldquo;코드가 변경되면 문서도 업데이트해야 한다\u0026quot;는 규범에 기반한다. 그러나 현실에서 이 규범은 대부분 지켜지지 않는다. 개발 속도가 빠를수록, 팀 규모가 클수록, 그리고 문서화에 직접적인 비즈니스 가치를 느끼기 어려울수록 문서는 뒤처진다. Code Wiki의 접근법은 이 인간적 한계를 규범이 아닌 자동화로 해결하려는 시도다. 문서화 의무를 개발자에게 부과하는 대신, 코드 변경이라는 이벤트를 자동화 파이프라인의 트리거로 만드는 것이다.\n이 패러다임 전환이 가져오는 더 깊은 함의는 개발자의 역할 변화다. 지금까지 시니어 개발자의 중요한 기여 중 하나는 암묵지(tacit knowledge) — 코드에 명시되지 않은 설계 결정, 역사적 맥락, 트레이드오프 — 를 문서로 남기거나 후배에게 전달하는 것이었다. AI가 코드에서 명시적 지식을 자동으로 추출할 수 있게 되면, 개발자의 가치 있는 지식 기여는 점점 더 이 암묵지 영역으로 이동할 것이다. 그리고 아이러니하게도, AI가 이 암묵지까지 포착하려면 개발자가 커밋 메시지, PR 설명, 코드 주석에 더 풍부한 컨텍스트를 남겨야 한다 — AI 도구가 더 좋아질수록 개발자가 남겨야 하는 구조화된 정보의 질도 높아지는 역설이 생긴다.\nCode Wiki가 장기적으로 의미 있는 도구가 되려면 AI 생성 문서에 대한 신뢰 문제를 해결해야 한다. 개발자가 문서를 직접 작성할 때는 그 문서에 책임 소재가 명확하지만, AI가 생성한 문서가 틀렸을 때 누가 책임지는가, 그리고 개발자가 AI 문서를 얼마나 신뢰하고 행동할 것인가는 기술적 문제가 아닌 문화적 문제다. 특히 미션 크리티컬한 시스템에서 AI 문서를 기반으로 유지보수 결정을 내리는 것은, 문서의 정확도에 대한 높은 신뢰가 전제되어야 한다.\n또한 Code Wiki는 현재 공개 오픈소스 리포지토리에서만 동작하며 프라이빗 리포 지원은 준비 중이다. 엔터프라이즈 환경에서 채택되려면 코드 보안, 데이터 주권, 온프레미스 배포 옵션 같은 거버넌스 요건을 충족해야 한다. Google이 이미 Google Cloud의 기업 고객들을 보유하고 있다는 점은 이 문제에서 유리한 출발점이 될 수 있지만, 코드베이스를 외부 AI 서비스에 노출하는 데 대한 기업의 보수적 태도를 극복하는 것은 별개의 도전이다.\n빠른 링크 [Product Review] Google의 Code Wiki, 코드베이스 설명서 — LOADING_ 채널, 9분 12초. codewiki.google 실사용 리뷰 Code Wiki 공식 사이트 — 피처드 리포 데모 및 초대 신청 인사이트 Code Wiki는 단순한 문서화 도구가 아니라, AI 에이전트가 소프트웨어 개발 생명주기의 일부를 자율적으로 담당하기 시작하는 전환점의 상징이다. PR 병합이라는 개발자의 행동이 AI 에이전트의 작업을 자동 트리거하고, 그 결과가 팀 전체에 즉시 공유되는 흐름은 에이전트와 인간이 협업하는 방식의 초기 모델을 보여준다. Google이 Antigravity(코드 작성)와 Code Wiki(코드 문서화)를 동시에 출시하고 있다는 점은 의도적인 전략처럼 보인다 — AI가 코드를 쓰고, AI가 그 코드를 설명하는 완전한 루프를 만들려는 시도다. NotebookLM이 지식 저장소 역할을 하고, Antigravity가 코드를 생성하며, Code Wiki가 결과를 문서화한다면, 이 세 도구의 통합은 구글이 그리는 AI 개발 환경의 큰 그림일 수 있다. 개발자에게 실질적인 함의는, 좋은 커밋 메시지와 잘 구조화된 PR 설명이 단순한 팀 협업 예절을 넘어 AI 문서화 품질을 결정하는 핵심 입력값이 된다는 것이다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-google-code-wiki/cover.jpg","permalink":"/ko/posts/2026-03-06-google-code-wiki/","title":"Google Code Wiki — AI가 코드베이스 문서를 대신 써주는 시대"},{"content":"개요 새 직원이 첫 출근을 했다. 실력은 뛰어나지만 팀의 코딩 컨벤션을 모르고, 어떤 프레임워크를 쓰는지도 모르고, PR 리뷰 기준도 모른다. 그래서 온보딩 문서를 준비하고, 코드 스타일 가이드를 알려주고, 자주 쓰는 패턴을 설명한다. 시간이 걸리지만 한 번 제대로 가르쳐 두면 그 이후로는 맥락 없이도 올바른 방향으로 일한다.\nClaude Code를 쓸 때 매번 같은 설명을 반복하는 것은 이 온보딩이 매일 리셋되는 것과 같다. Harness는 이 문제를 해결하는 프레임워크다. 프로젝트의 코딩 방식, 선호하는 라이브러리, 팀의 규칙을 한 번 정의해 두면 Claude Code가 세션마다 그 맥락을 그대로 이어받는다. 설치는 한 번이지만 절약은 장기적으로 누적된다.\n하니스란 무엇인가 Harness는 Claude Code에 지속적인 컨텍스트를 제공하는 구성 시스템이다. CLAUDE.md가 단일 마크다운 파일로 프로젝트 전반의 지시사항을 담는 방식이라면, Harness는 더 구조화된 방식으로 AI의 행동을 정의한다. 핵심 구성 요소는 Skills(스킬), Agents(에이전트), Commands(커맨드) 세 가지다.\nHarness가 없을 때 Claude Code는 범용 AI다. FastAPI를 쓸 수도, Django를 쓸 수도 있고, 의존성을 추가하는 방식도, 에러 처리 패턴도 프로젝트마다 다를 수 있다. Harness를 설치하면 Claude Code는 이 프로젝트에서는 FastAPI를 쓰고, Pydantic v2로 스키마를 정의하고, 에러 응답은 특정 형식을 따른다는 사실을 처음부터 알고 시작한다. 이 차이는 단순히 편의의 문제가 아니라 AI 출력 품질과 일관성에 직접적으로 영향을 미친다.\nHarness를 새 직원 비유로 설명하면 이해가 빠르다. 실력 있는 신입 직원도 팀 컨텍스트 없이는 엉뚱한 방향으로 일할 수 있다. 매번 팀 리더가 맥락을 설명해야 한다면 그 비용은 개인의 생산성이 아닌 팀 전체에서 반복적으로 지불된다. Harness는 이 반복 비용을 초기 설치 한 번으로 대체한다.\n하니스의 3가지 핵심 개념 스킬 — 전문 지식 문서 스킬은 Claude Code에게 특정 영역의 패턴을 가르치는 마크다운 문서다. \u0026ldquo;FastAPI 백엔드를 이 프로젝트에서 어떻게 구조화하는가\u0026rdquo;, \u0026ldquo;Next.js 컴포넌트를 어떤 규칙으로 만드는가\u0026rdquo;, \u0026ldquo;Mermaid 다이어그램을 어떻게 표현하는가\u0026rdquo; 같은 전문 지식을 담는다. 스킬 파일은 Claude Code의 행동을 범용에서 전문화로 전환하는 핵심 메커니즘이다.\n아래는 FastAPI 백엔드 스킬 파일이 어떤 형태를 가질 수 있는지 보여주는 예시다.\n# FastAPI Backend Skill ## 프로젝트 구조 - 라우터는 `app/routers/` 에 도메인별로 분리 - 스키마는 Pydantic v2 (`app/schemas/`) - 의존성 주입은 `app/dependencies.py` ## 응답 형식 성공 응답: { \u0026#34;success\u0026#34;: true, \u0026#34;data\u0026#34;: { ... } } 에러 응답: { \u0026#34;success\u0026#34;: false, \u0026#34;error\u0026#34;: { \u0026#34;code\u0026#34;: \u0026#34;...\u0026#34;, \u0026#34;message\u0026#34;: \u0026#34;...\u0026#34; } } ## 코딩 규칙 - async/await 필수 — 동기 엔드포인트 금지 - 모든 엔드포인트에 response_model 명시 - HTTPException 대신 커스텀 AppException 사용 이처럼 스킬 파일은 Claude Code가 코드를 생성할 때 참조하는 팀의 결정들을 문서화한다. 스킬은 단순한 스타일 가이드가 아니라 AI의 의사결정 기준이 된다. 팀의 규칙이 바뀌면 스킬 파일을 업데이트하면 되고, 그 이후로 Claude Code의 출력도 자동으로 갱신된다.\n스킬의 진가는 범위가 넓어질수록 드러난다. FastAPI 스킬, Next.js 스킬, 데이터베이스 마이그레이션 스킬, PDF 생성 스킬, Mermaid 다이어그램 스킬을 각각 정의해 두면, Claude Code는 그 스택 전반에 걸쳐 일관된 방식으로 코드를 작성한다. 모든 지식을 매번 프롬프트에 포함시킬 필요 없이 Harness가 필요한 스킬을 자동으로 불러온다.\n에이전트 — 목적 특화 AI 인스턴스 에이전트는 특정 역할에 맞게 사전 구성된 Claude Code 인스턴스다. 플래너(Planner), 플랜 리뷰어(Plan Reviewer), 웹 리서치 스페셜리스트처럼 역할별로 다른 에이전트를 정의할 수 있다. 각 에이전트는 자신이 해야 할 일, 어떤 스킬을 참조해야 하는지, 어떤 도구를 사용할 수 있는지를 미리 설정해 둔다.\n플래너 에이전트는 새 기능 구현 전에 세부 실행 계획을 작성하는 역할을 담당한다. 플랜 리뷰어 에이전트는 플래너가 만든 계획의 빈틈을 찾아 피드백을 제공한다. 웹 리서치 스페셜리스트는 최신 라이브러리 정보나 기술 문서를 검색하는 역할을 맡는다. 이처럼 에이전트를 역할로 분리하면 단일 범용 AI가 모든 것을 처리하려는 것보다 훨씬 예측 가능하고 신뢰할 수 있는 결과를 얻을 수 있다.\n커맨드 — 슬래시 하나로 워크플로우 실행 커맨드는 반복적으로 수행하는 작업 흐름을 슬래시 명령어 하나로 실행할 수 있게 만드는 매크로다. /review-pr, /generate-schema, /write-tests 같은 커맨드를 정의해 두면, 복잡한 프롬프트를 매번 작성할 필요 없이 커맨드 하나로 전체 워크플로우를 트리거한다. 이 log-blog 프로젝트에서 쓰는 Claude Code 스킬도 같은 원리로 동작한다.\n실전 스킬 목록 — FastAPI부터 Mermaid까지 Harness 생태계에서 실제로 활용되는 스킬들은 프로젝트의 기술 스택을 따라 구성된다. FastAPI 백엔드 스킬은 라우터 구조, 스키마 패턴, 에러 처리 방식을 정의하고, Next.js 프론트엔드 스킬은 컴포넌트 명명 규칙, 상태 관리 방식, API 호출 패턴을 정의한다.\nMermaid 다이어그램 스킬은 Claude Code가 다이어그램을 생성할 때 자주 발생하는 문법 오류를 방지하는 규칙을 담는다. 예를 들어, Mermaid v11에서는 \\n이 노드 라벨의 줄바꿈으로 동작하지 않으며 Hugo Stack 테마에서는 \u0026lt;br/\u0026gt; 대신 \u0026amp;lt;br/\u0026amp;gt;를 써야 한다는 규칙을 스킬에 명시해 두면, Claude Code가 다이어그램을 만들 때마다 이 규칙을 자동으로 따른다.\n# Mermaid Diagram Skill ## Hugo Stack 테마 규칙 - 노드 라벨 줄바꿈: `\u0026amp;lt;br/\u0026amp;gt;` 사용 (NOT `\\n`, NOT `\u0026lt;br/\u0026gt;`) - 슬래시 포함 라벨은 반드시 따옴표로 감쌀 것: `[\u0026#39;label/text\u0026#39;]` - 이중 따옴표 금지 — Hugo 파싱 충돌 가능성 - 한 다이어그램의 오류가 페이지 전체 다이어그램을 숨김 처리하므로 문법 검증 철저히 ## 허용 다이어그램 타입 flowchart TD, graph TD, sequenceDiagram, classDiagram PDF 및 PPTX 문서 도구 스킬, 웹 디자인 리뷰 스킬도 각각의 도메인에서 Claude Code가 일관된 방식으로 산출물을 만들도록 가이드한다. 스킬의 수가 많아질수록 Claude Code는 프로젝트 전반에 걸쳐 더 일관되고 예측 가능한 결과를 낸다.\n에이전트 팀 구성 Harness의 에이전트 설계에서 흥미로운 점은 단일 AI가 모든 역할을 수행하는 것이 아니라, 역할별로 최적화된 에이전트들이 협력하는 팀 구조를 만든다는 것이다. 개발 팀이 개발자, 리뷰어, 리서처로 역할을 나누는 것처럼 AI 에이전트도 같은 방식으로 구성한다.\n플래너 에이전트는 구현에 들어가기 전에 세부 계획을 먼저 수립한다. 어떤 파일을 수정해야 하는지, 어떤 순서로 작업해야 하는지, 잠재적 위험 요소는 무엇인지를 정리한다. 플랜 리뷰어 에이전트는 이 계획을 독립적으로 검토해서 빠뜨린 엣지 케이스나 잘못된 가정을 찾아낸다. 이 두 에이전트의 협력은 단일 에이전트가 계획과 실행을 동시에 담당할 때 발생하는 자기 확증 편향을 줄인다.\ngraph TD U[사용자 요청] --\u003e H[Harness] H --\u003e SK[Skills] H --\u003e AG[Agents] H --\u003e CM[Commands] SK --\u003e S1[FastAPI 스킬] SK --\u003e S2[Next.js 스킬] SK --\u003e S3[Mermaid 스킬] SK --\u003e S4[커스텀 스킬...] AG --\u003e A1[플래너] AG --\u003e A2[플랜 리뷰어] AG --\u003e A3[웹 리서치 스페셜리스트] CM --\u003e C1[\"/review-pr\"] CM --\u003e C2[\"/generate-schema\"] CM --\u003e C3[\"/write-tests\"] S1 --\u003e CC[Claude Code] S2 --\u003e CC S3 --\u003e CC A1 --\u003e CC A2 --\u003e CC C1 --\u003e CC C2 --\u003e CC CC --\u003e PM[프로젝트 메모리] CC --\u003e OUT[\"출력 — 일관된 코드 / 문서\"] PM --\u003e CC style H fill:#1a3a5c,color:#fff style CC fill:#2d5a27,color:#fff style OUT fill:#5c3a1a,color:#fff웹 리서치 스페셜리스트 에이전트는 최신 API 문서, 라이브러리 변경사항, 기술적 레퍼런스를 찾는 역할에 특화된다. 범용 Claude Code에게 \u0026ldquo;최신 Pydantic v2 문서를 참고해서\u0026quot;라고 매번 지시하는 대신, 리서치 에이전트가 자율적으로 필요한 정보를 수집하고 정리해서 실제 구현 에이전트에 전달한다. 이 분업 구조는 각 에이전트가 자신의 역할에 집중하면서 전체 워크플로우의 품질을 높인다.\n범용 AI vs 전담 전문가 Harness가 제기하는 질문은 AI 도구 사용 방식에 대한 더 근본적인 관점을 담고 있다. 범용 AI는 무엇이든 할 수 있지만 특정 맥락에서는 최적이 아닐 수 있다. 전담 전문가는 범위가 좁지만 그 범위 안에서는 훨씬 예측 가능하고 신뢰할 수 있는 결과를 낸다.\n소프트웨어 개발 팀에서 모든 역할을 한 사람이 담당하는 것보다 전문화된 역할 분담이 전체 생산성을 높이는 것처럼, AI 에이전트도 마찬가지 원리가 적용된다. Harness는 Claude Code라는 강력한 범용 AI에 프로젝트별 전문성을 덧입혀 전담 직원으로 만드는 프레임워크다.\n개발자가 AI를 길들이는 데 6개월이 걸렸다는 경험담은 이 과정이 단순하지 않음을 보여준다. 어떤 스킬을 정의할지, 에이전트를 어떻게 분리할지, 커맨드를 어떤 수준으로 추상화할지는 프로젝트와 팀의 특성에 따라 달라진다. 하지만 한 번 제대로 구성해 두면 그 이후의 세션마다 반복적으로 쌓이는 절약이 초기 투자를 빠르게 회수한다.\n빠른 링크 하니스 완전 공개 — Claude Code AI를 내 전담 직원으로 만드는 법 — 메이커 에반 채널, 설치부터 스킬/에이전트/커맨드 실습까지 (5분 13초, 7,800 views) 개발자가 AI 길들이는 데 6개월 걸린 이유 — 메이커 에반 이전 영상, 시행착오 전부 공개 (11만 views) 인사이트 Harness는 기술적으로 새로운 발명이 아니다. 마크다운 파일과 구성 시스템의 조합으로 이루어진다. 하지만 이 단순한 조합이 Claude Code 사용 경험을 질적으로 바꾸는 이유는 AI와 일하는 방식에 대한 관점의 전환에서 비롯된다. 매 세션마다 처음부터 설명하는 방식에서, 한 번 설정하고 영구히 기억하게 만드는 방식으로의 전환이다. 스킬, 에이전트, 커맨드의 삼분 구조는 각각 지식의 문서화, 역할의 전문화, 워크플로우의 자동화라는 서로 다른 문제를 해결한다. 팀 컨텍스트를 AI에 전달하는 가장 좋은 방법은 가장 명시적인 방법이다. Harness의 스킬 파일은 팀의 암묵적 지식을 명시적 문서로 강제 전환하는 효과도 있다. 이 과정에서 팀원들이 당연하게 여기던 규칙들이 처음으로 문서화되는 부수적 효과도 생긴다. 에이전트를 역할로 분리하는 설계는 단일 AI가 자기 자신의 계획을 검토하는 자기 확증 편향을 줄이는 데 실질적 효과가 있다. 초기 설치에 투자하는 시간을 장기 절약의 관점에서 계산하면 ROI는 대부분의 개발 도구 투자보다 빠르게 나타난다. 특히 같은 기술 스택을 반복적으로 다루는 팀이나 개인 개발자일수록 Harness의 가치는 더 빠르게 체감된다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-claude-code-harness/cover.jpg","permalink":"/ko/posts/2026-03-06-claude-code-harness/","title":"Harness(하니스) — Claude Code를 범용 AI에서 전담 직원으로"},{"content":"개요 Claude Code에게 작업을 시키면 \u0026ldquo;성공적으로 완료했습니다\u0026quot;라는 메시지가 뜬다. 하지만 실제로 테스트를 돌려보면 에러가 터진다. 이 불일치는 AI 코딩 도구가 가진 구조적 한계에서 비롯된다. AI는 자신이 작업을 완료했다고 판단하는 순간 멈추지만, 그 판단이 틀릴 수 있다는 사실을 스스로 검증하지 않는다.\nRalph Loop는 이 문제를 정면으로 해결하는 패턴이다. 핵심 아이디어는 단순하다. AI가 \u0026ldquo;완료\u0026quot;라고 말해도 자동으로 다시 시작해서 스스로 검증하게 만든다. 끝없이 반복하는 루프 안에 AI 에이전트를 가두면, 에이전트는 실패를 감지하고 수정하기를 반복하다가 진짜로 통과할 때까지 멈추지 않는다. 이 아이디어는 2025-2026년에 걸쳐 AI 개발 커뮤니티에서 가장 주목받는 자동화 패턴 중 하나로 부상했다.\nRalph Loop의 탄생 배경 Ralph Loop라는 이름은 미국 애니메이션 심슨 가족의 등장인물 Ralph Wiggum에서 왔다. Ralph는 특별히 똑똑하지는 않지만 절대 포기하지 않는 캐릭터다. Geoffrey Huntley가 이 비유에서 영감을 받아 가장 단순한 형태의 에이전트 루프 패턴을 제안했고, 그 원본 구현은 단 한 줄의 bash 명령어다.\nwhile :; do cat PROMPT.md | agent; done 이게 전부다. PROMPT.md에 작업 지시를 적어두면, 이 루프는 에이전트가 종료될 때마다 즉시 새 에이전트를 띄워 같은 프롬프트로 다시 시작한다. 컨텍스트 창이 가득 차도, 에이전트가 중간에 멈춰도, 오류가 발생해도 루프는 계속 돌아간다. 새 에이전트는 파일시스템과 git 히스토리를 읽어 이전 에이전트가 어디까지 했는지 파악하고 이어서 작업한다.\n이 패턴이 주목받게 된 결정적 계기는 Y Combinator 해커톤 사례다. 참가자들이 GCP 인스턴스에 Ralph Loop를 돌려놓고 잠자리에 들었더니, 아침에 확인해보니 6개 레포지토리에 걸쳐 1,100개의 커밋이 쌓여 있었다. Browser Use 라이브러리를 Python에서 TypeScript로 거의 완전히 포팅하는 작업이 하룻밤 사이에 완료된 것이다. 총 비용은 800달러였는데, 이는 시간당 10.50달러짜리 개발자를 고용한 것과 같은 단가다. 이 사례는 Ralph Loop의 현실적 효용을 증명하면서 커뮤니티 전체에 퍼져나갔다.\n파생 프로젝트들도 빠르게 등장했다. snarktank/ralph 레포지토리는 9,200개 이상의 GitHub 스타를 받았고, oh-my-opencode 프로젝트는 /ralph-loop 명령어를 내장 기능으로 포함했다. 원래는 실험적 해킹에 가까웠던 이 패턴이 점차 표준화된 도구로 자리를 잡아가는 과정이 빠르게 진행됐다.\n왜 효과적인가 — 컨텍스트 vs 파일시스템 전통적인 AI 코딩 도구의 문제는 진행 상황을 컨텍스트 창 안에만 저장한다는 점이다. LLM의 컨텍스트 창은 유한하고, 한 번 가득 차면 이전 내용이 잊힌다. 장시간 작업에서는 에이전트가 앞서 무엇을 했는지 기억하지 못하거나, 컨텍스트 한계에 도달해 강제로 종료되는 문제가 발생한다.\nRalph Loop의 핵심 통찰은 상태를 컨텍스트가 아니라 외부 파일시스템과 git에 저장한다는 것이다. 에이전트가 코드를 작성하면 파일에 저장된다. 에이전트가 git commit을 하면 히스토리가 남는다. 컨텍스트가 가득 차서 에이전트가 종료되더라도 루프는 새 에이전트를 띄운다. 새 에이전트는 파일시스템을 읽고 git log를 확인해서 이전 에이전트가 어디까지 진행했는지 파악하고 작업을 이어간다.\nflowchart TD P[PROMPT.md] --\u003e A[에이전트 실행] A --\u003e T{작업 수행} T --\u003e W[파일 쓰기 + git commit] W --\u003e C{컨텍스트 한계?} C --\u003e|아니오| V{검증 통과?} C --\u003e|예 — 에이전트 종료| R[새 에이전트 시작] R --\u003e FS[파일시스템 / git 상태 읽기] FS --\u003e T V --\u003e|실패| F[오류 분석 + 수정] F --\u003e T V --\u003e|통과| E[완료] style P fill:#2d2d2d,color:#fff style E fill:#1a5c2e,color:#fff style R fill:#5c3317,color:#fff이 아키텍처가 중요한 이유는 에이전트 루프의 지속성을 컨텍스트 창의 한계에서 완전히 분리했다는 점이다. 컨텍스트는 언제든 리셋될 수 있지만, 파일시스템과 git은 영속적이다. 새 에이전트는 항상 \u0026ldquo;fresh\u0026quot;한 상태로 시작하면서도 이전 작업의 결과물을 온전히 이어받는다. 이 패턴은 특히 대규모 리팩토링, 라이브러리 포팅, 레거시 코드 마이그레이션처럼 맥락이 긴 작업에서 강력하게 작동한다.\n프로덕션 수준으로 진화한 패턴들 단순한 bash 루프에서 출발한 Ralph Loop는 프로덕션 환경에서 요구되는 복잡도를 반영하며 여러 방향으로 진화했다. Peter Steinberger가 공개한 OpenClaw 프로젝트(152,000개 이상의 GitHub 스타)는 에이전트 루프를 실제 서비스 수준으로 끌어올린 사례다. OpenClaw는 WhatsApp, Slack, Discord, iMessage, Telegram 등 12개 이상의 채널을 연결하고, \u0026ldquo;soul document\u0026quot;라는 개념으로 에이전트의 성격과 행동 원칙을 정의 문서로 관리한다. Gateway 기반 세션 라우팅과 사용량 모니터링까지 갖추고 있으며, 총 커밋 수가 8,700개를 넘는다.\nNanobot 프로젝트는 에이전트 루프의 핵심을 330줄로 증류해서 보여준다. 복잡한 인프라 없이 루프의 본질만 남긴 이 코드는 Ralph Loop의 기계적 구조를 가장 명확하게 드러낸다.\nwhile iteration \u0026lt; self.max_iterations: iteration += 1 response = await self.provider.chat( messages=messages, tools=self.tools.get_definitions() ) if response.has_tool_calls: for tool_call in response.tool_calls: result = await self.tools.execute( tool_call.name, tool_call.arguments) messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result) else: final_content = response.content break 이 코드의 구조를 보면 Ralph Loop가 얼마나 오래된 컴퓨터 과학 개념에 기반하는지 명확해진다. while문, 도구 호출 응답 처리, 메시지 히스토리 누적, 탈출 조건. 새로운 것은 없다. 달라진 점은 루프 안에서 LLM이 \u0026ldquo;다음에 무엇을 할지\u0026quot;를 결정한다는 것, 그리고 탈출 조건인 \u0026ldquo;완료\u0026quot;를 어떻게 정의하느냐다. max_iterations는 무한 루프를 막는 안전장치로, 그 한계에 도달하면 루프를 강제 종료하는 대신 MaxReachedAgent를 호출해 지금까지의 작업을 요약하고 다음 방향을 안내한다.\n채널톡 FrontALF가 구현한 실전 설계 채널톡의 AI 상담 시스템 FrontALF는 Ralph Loop 패턴을 실제 B2B 서비스에 적용한 사례로, 두 가지 루프를 목적에 따라 분리해 설계했다. 이 설계는 단순한 반복 루프를 넘어 에이전트 루프를 상황에 맞게 전문화하는 아키텍처 관점을 보여준다.\n첫 번째는 Stateless Agent Loop다. 고객 Q\u0026amp;A, RAG 검색, 빠른 응답이 필요한 상황에서 사용한다. 각 턴은 독립적으로 실행되고 상태를 외부에 저장하지 않는다.\nfor i := 0; i \u0026lt; maxTurns; i++ { response := llm.Request(currentHistory) currentHistory = append(currentHistory, response.Events...) if !checkShouldContinue(response.Events) { break } } RAG Handler 내부에서 검색 결과의 충분성을 판단해 필요하면 재검색하는 미니 루프가 내포되어 있다. 바깥 루프는 단순하지만 안쪽에서 필요에 따라 자율적으로 보완하는 구조다.\n두 번째는 Stateful Task Loop다. 환불 처리처럼 여러 단계를 거치는 워크플로우, 외부 시스템 승인을 기다려야 하는 작업에 사용한다.\ntype TaskSession struct { CurrentNodeID string TaskMemory map[string]any // 노드 간 공유 상태 NodeTrace []string // 실행 경로 추적 } TaskMemory가 노드 간 공유 상태를 담당하고, NodeTrace가 실행 경로를 기록해 디버깅과 재실행을 지원한다. 특정 노드에서 실패하면 그 노드부터 재실행할 수 있고, 외부 승인을 기다리는 동안 세션을 일시 정지했다가 재개하는 것도 가능하다. 두 루프의 분리는 요구사항이 다를 때 억지로 단일 패턴에 맞추려 하지 않는 실용적 판단이다.\n빠른 링크 클로드 코드 랄프 루프 — 잠자는 동안 AI가 코딩하게 만드는 법 — 오늘노트 채널, Ralph Loop 개념 소개와 실습 (8분 16초) 클로드가 알아서 테스트하고 수정하게 만드는 방법 | Ralph Loop — 딩코딩코 채널, 직접 실습 위주 튜토리얼 (6분 29초, 32,000 views) Ralph Loop, OpenClaw - 새로운건 없었다 — 채널톡 엔지니어 몽의 심층 분석, FrontALF 실전 설계 포함 인사이트 Ralph Loop가 흥미로운 이유는 기술적 혁신이 아니라 관점의 전환 때문이다. while문, 상태 머신, 재시도 패턴, graceful shutdown — 이 모든 것은 수십 년 전부터 존재했다. 달라진 것은 루프 안의 의사결정자가 규칙 기반 로직에서 LLM으로 바뀌었다는 것, 그리고 \u0026ldquo;완료\u0026quot;의 정의가 미리 프로그래밍된 조건이 아니라 AI가 판단하는 맥락적 기준이 되었다는 것이다. Y Combinator 사례의 800달러, 시간당 10.50달러라는 수치는 이 패턴이 이미 현실적인 경제적 단위로 작동하고 있음을 보여준다. 채널톡의 두 루프 분리 — Stateless와 Stateful — 는 에이전트 루프를 도입할 때 요구사항의 차이를 무시하고 단일 패턴을 강요하지 말라는 실용적 교훈을 남긴다. OpenClaw의 soul document 개념, 즉 에이전트의 성격과 행동 원칙을 명시적 문서로 정의하는 접근은 단순한 루프 반복을 넘어 에이전트를 어떻게 제어하고 신뢰할 수 있게 만드는지에 대한 더 깊은 설계 문제를 제기한다. Ralph Loop를 실제로 프로덕션에 도입하려면 max_iterations 같은 안전장치와 비용 모니터링이 반드시 필요하다. 루프가 의도한 대로 수렴하지 않으면 비용이 선형이 아닌 속도로 늘어날 수 있기 때문이다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-ralph-loop-ai-automation/cover.jpg","permalink":"/ko/posts/2026-03-06-ralph-loop-ai-automation/","title":"Ralph Loop — AI가 스스로 테스트하고 고치는 무한 루프 패턴"},{"content":"개요 code-server는 VS Code를 브라우저에서 실행할 수 있게 해주는 오픈소스 프로젝트다 (GitHub 76,491 stars, TypeScript 주요 언어). 서버에 code-server를 설치하고 브라우저로 접속하면 완전한 VS Code 개발 환경을 어디서든 사용할 수 있다는 것이 핵심 가치다. 그런데 바로 이 \u0026ldquo;브라우저에서 실행\u0026quot;이라는 특성이 OAuth 기반 인증을 사용하는 VSCode 익스텐션들에게 치명적인 문제를 일으킨다.\n문제의 핵심은 URI 스킴이다. 로컬 VS Code는 vscode:// 스킴을 통해 OAuth 리다이렉트를 처리한다. OS 레벨에서 vscode://로 시작하는 URL을 VS Code 프로세스로 라우팅하는 핸들러가 등록되어 있기 때문이다. 그러나 code-server 환경에서는 VS Code가 브라우저 탭으로 실행된다. 브라우저는 code-oss:// 스킴을 알지 못하고, OS 레벨 핸들러도 없다. 결과적으로 OAuth 인증 완료 후 리다이렉트 단계에서 인증 플로우가 완전히 중단된다. 이 글에서는 이 문제의 기술적 구조를 분석하고 올바른 해결책을 정리한다.\n문제의 본질 — vscode:// vs code-oss:// URI 스킴 로컬 VS Code에서 OAuth를 사용하는 익스텐션은 보통 다음과 같은 흐름으로 인증을 처리한다. 익스텐션이 OAuth 제공자의 인증 URL을 브라우저로 열고, 사용자가 로그인 및 권한 승인을 완료하면 제공자가 미리 등록된 redirect_uri로 리다이렉트한다. 이때 redirect_uri는 vscode://extension-name/auth-callback 형태이고, OS가 이 스킴을 인식해 VS Code 프로세스를 깨워 해당 URI를 전달한다. 익스텐션은 이 URI에서 authorization code를 추출해 액세스 토큰을 교환한다.\ncode-server 환경에서는 VS Code 자체의 URI 스킴이 code-oss://로 바뀐다. 이는 code-server가 사용하는 VS Code 포크(fork)인 Code-OSS의 기본 스킴이다. 문제는 이 스킴이 브라우저나 OS에 전혀 등록되어 있지 않다는 것이다. code-oss://augment.vscode-augment/auth/... 같은 URL로 리다이렉트가 발생하면 브라우저는 다음과 같은 에러를 표시한다.\nFailed to launch \u0026#39;code-oss://{extension_name}?{params}\u0026#39; because the scheme does not have a registered handler code-server Issue #6584에서 Augment Code 익스텐션 사용자 @tianze0926이 정확히 이 증상을 보고했다. 인증 완료 후 code-oss://augment.vscode-augment/auth/... URI가 자동으로 열리지 않아 수동으로 복사해야 하는 상황이었다. 이 이슈는 code-server 고유의 문제가 아니라 브라우저 기반 VS Code 환경 전반의 구조적 한계에서 비롯된 것이다.\n브라우저 환경에서 OAuth가 실패하는 이유 graph LR subgraph local[로컬 VS Code] L1[익스텐션이OAuth URL 열기] --\u003e L2[브라우저에서OAuth 승인] L2 --\u003e L3[redirect_uri:vscode://ext/cb] L3 --\u003e L4[OS가 vscode://핸들러 호출] L4 --\u003e L5[익스텐션이토큰 수신 SUCCESS] end subgraph cs[code-server 브라우저] C1[익스텐션이OAuth URL 열기] --\u003e C2[새 탭에서OAuth 승인] C2 --\u003e C3[redirect_uri:code-oss://ext/cb] C3 --\u003e C4[브라우저: 핸들러없음 FAIL] C4 --\u003e C5[인증 중단토큰 없음] end style L5 fill:#27ae60,color:#fff style C4 fill:#e74c3c,color:#fff style C5 fill:#e74c3c,color:#fff로컬 VS Code와 code-server의 OAuth 플로우 차이를 도식화하면 위와 같다. 로컬 환경에서는 OS 레벨 URI 스킴 핸들러가 중간에서 브릿지 역할을 해준다. macOS는 Info.plist에 등록된 URL scheme으로, Windows는 레지스트리를 통해, Linux는 XDG 설정을 통해 vscode:// URL을 VS Code 프로세스로 전달한다. 이것이 가능한 이유는 VS Code 설치 시 OS에 해당 스킴 핸들러를 등록하기 때문이다.\n반면 code-server는 브라우저 탭으로 실행된다. 브라우저 내에서 새로운 탭이나 팝업으로 OAuth 인증을 진행하고, 인증이 완료되면 OAuth 제공자는 등록된 redirect_uri로 리다이렉트를 시도한다. 그런데 code-oss:// 스킴은 브라우저의 커스텀 프로토콜 핸들러 목록에 없다. 브라우저는 이 URL을 어떻게 처리해야 할지 모르고 에러를 반환한다. code-server maintainer @code-asher의 분석처럼, 이 문제를 해결하려면 VS Code 자체를 수정하거나, 익스텐션이 다른 인증 방식을 택해야 한다.\npolling 방식은 이 문제에 대한 초기 해결책으로 자주 언급되었다. OAuth 리다이렉트 대신 익스텐션이 자체 서버 엔드포인트를 열고, 클라이언트 측에서 주기적으로 해당 엔드포인트를 폴링해 토큰이 전달되었는지 확인하는 방식이다. 이는 redirect_uri를 https://extension-server.com/callback 형태의 일반 HTTPS URL로 바꿀 수 있어 브라우저 스킴 문제를 우회한다. 그러나 별도 서버 인프라가 필요하고, 토큰이 중간 서버를 거친다는 보안 우려가 있어 완전한 해결책은 아니다.\nregisterUriHandler — 올바른 해결책 VSCode Extension API의 vscode.window.registerUriHandler는 이 문제의 공식적인 해결책이다. 익스텐션이 vscode://publisher.extension-name/path 형태의 URI에 대한 핸들러를 직접 등록할 수 있게 해주는 API다. code-server 환경에서 이 API를 사용하면, code-server 서버 측이 외부에서 들어오는 해당 URI 요청을 가로채 익스텐션 핸들러로 라우팅해준다.\n동작 원리는 다음과 같다. code-server는 웹 서버 형태로 실행되므로, OAuth redirect_uri를 https://your-code-server.com/vscode-extension/callback 같은 일반 HTTPS URL로 설정할 수 있다. 인증이 완료되면 이 HTTPS 엔드포인트가 호출되고, code-server는 이를 내부적으로 vscode:// URI 이벤트로 변환해 익스텐션 핸들러에 전달한다. 즉, 브라우저의 커스텀 스킴 문제를 HTTP/HTTPS 레이어에서 우회하는 것이다.\n// 올바른 방법 — registerUriHandler 사용 import * as vscode from \u0026#39;vscode\u0026#39;; export function activate(context: vscode.ExtensionContext) { // vscode://publisher.my-extension/auth-callback URI 핸들러 등록 const uriHandler = vscode.window.registerUriHandler({ handleUri(uri: vscode.Uri): void { if (uri.path === \u0026#39;/auth-callback\u0026#39;) { const params = new URLSearchParams(uri.query); const code = params.get(\u0026#39;code\u0026#39;); const state = params.get(\u0026#39;state\u0026#39;); if (code \u0026amp;\u0026amp; state) { // authorization code로 토큰 교환 exchangeCodeForToken(code, state); } } } }); context.subscriptions.push(uriHandler); } // OAuth 시작 시 redirect_uri 설정 function startOAuthFlow() { // code-server 환경에서는 HTTPS로 변환되어 라우팅됨 const redirectUri = vscode.env.uriScheme + \u0026#39;://publisher.my-extension/auth-callback\u0026#39;; const authUrl = buildOAuthUrl({ redirect_uri: redirectUri }); vscode.env.openExternal(vscode.Uri.parse(authUrl)); } // 잘못된 방법 — 하드코딩된 code-oss:// 스킴 function startOAuthFlowBroken() { // code-server 브라우저 환경에서는 이 URL을 열 수 없음 const redirectUri = \u0026#39;code-oss://extension-name/auth-callback\u0026#39;; const authUrl = buildOAuthUrl({ redirect_uri: redirectUri }); vscode.env.openExternal(vscode.Uri.parse(authUrl)); // 브라우저: \u0026#34;the scheme does not have a registered handler\u0026#34; 에러 } vscode.env.uriScheme을 사용하는 것이 핵심이다. 이 값은 로컬 VS Code에서는 vscode, code-server에서는 code-oss 또는 환경에 따른 적절한 값을 반환한다. 하드코딩 없이 동적으로 현재 환경의 스킴을 감지해 redirect_uri를 구성할 수 있다. GitLens가 이 패턴을 성공적으로 구현했으며, code-server maintainer가 GitLens 소스코드를 참조 구현으로 언급했다. 커뮤니티 확인 결과 GitLens는 code-server 환경에서도 OAuth 인증이 정상 동작한다.\n팝업 창 API 요청 (VSCode #142080) VSCode 이슈 #142080은 OAuth2 인증을 팝업 창으로 처리하는 Extension API 추가를 요청한다. 현재는 새 탭(new tab)으로만 OAuth 창을 열 수 있는데, 팝업 창을 사용하면 인증 완료 후 스크립트로 창을 자동으로 닫을 수 있어 사용자 경험이 훨씬 개선된다.\nVSCode 팀의 @TylerLeonhardt는 vscode.dev에서 GitHub Authentication 익스텐션이 팝업 처리를 받는 것은 하드코딩된 URI 화이트리스트를 통해서라고 설명했다. 즉, 일반 익스텐션이 사용할 수 있는 공식 API가 아닌 특별 처리다. Electron 담당자 @deepak1556은 데스크톱 환경에서는 OS 플랫폼 핸들러(XDGOpen, OpenURL, ShellExecuteW)에 위임하는 방식이라 범용 팝업 API 구현이 복잡하다고 밝혔다. 웹 임베딩 환경에서는 구현 가능성이 있다는 의견도 나왔다.\n이 이슈는 현재 OPEN 상태이며 커뮤니티 업보트 대기 중(20 upvotes 필요)이다. GitHub Authentication 익스텐션만 특별 팝업 처리를 받는 현 상황은 커뮤니티의 불만 사항 중 하나다. 일반 익스텐션도 동일한 사용자 경험을 제공할 수 있는 공식 API가 제공되어야 한다는 것이 이슈의 핵심 요구사항이다.\nwindow.close()의 브라우저 제약 OAuth 팝업 창을 사용하려면 window.close()로 인증 완료 후 창을 닫아야 한다. 그런데 브라우저에는 window.close()에 대한 중요한 제약이 있다. MDN 스펙에 따르면 스크립트로 창을 닫을 수 있는 것은 스크립트로 열린 창(via window.open())과 링크/폼으로 열렸지만 사용자 수정 동작 없이 열린 창에 한정된다.\n사용자가 Ctrl+Click이나 마우스 중간 버튼으로 직접 새 탭을 연 경우는 스크립트로 닫을 수 없다. Chrome은 이 경우 콘솔에 다음 메시지를 출력한다.\nScripts may not close windows that were not opened by script. OAuth 팝업 패턴이 올바르게 동작하려면 반드시 window.open()으로 팝업 창을 열어야 한다. 인증 완료 페이지에서 window.opener를 통해 부모 창에 메시지를 전달하고 (window.opener.postMessage()), 그 후 window.close()를 호출하는 방식이다. 이 패턴은 OAuth 팝업 구현의 표준적인 접근법이다.\n// OAuth 시작 측 (익스텐션/앱) const popup = window.open(authUrl, \u0026#39;oauth-popup\u0026#39;, \u0026#39;width=600,height=700\u0026#39;); window.addEventListener(\u0026#39;message\u0026#39;, (event) =\u0026gt; { if (event.source === popup \u0026amp;\u0026amp; event.data.type === \u0026#39;oauth-success\u0026#39;) { const { code, state } = event.data; // 토큰 교환 진행 exchangeCodeForToken(code, state); } }); // OAuth 콜백 페이지 (redirect_uri) // 인증 완료 후 부모 창에 코드 전달하고 팝업 닫기 window.opener.postMessage({ type: \u0026#39;oauth-success\u0026#39;, code: new URLSearchParams(location.search).get(\u0026#39;code\u0026#39;), state: new URLSearchParams(location.search).get(\u0026#39;state\u0026#39;) }, \u0026#39;*\u0026#39;); window.close(); // window.open()으로 열렸으므로 닫기 가능 WSL1에서의 디버거 Detach 이슈 VSCode 이슈 #1650(vscode-js-debug)은 언뜻 OAuth 문제처럼 보이지만 실제로는 다른 원인이었다. Chrome 디버그 세션이 OAuth 리다이렉트(크로스 도메인 탐색) 시 연결이 끊어진다는 보고였다. vscode-js-debug maintainer @connor4312는 \u0026ldquo;일단 연결되면 연결이 유지되어야 하며 알려진 이슈가 없다\u0026quot;고 응답했다.\n실제 원인을 조사한 결과 WSL1의 네트워크 격리가 문제였다. WSL1은 Linux 커널 없이 Windows 커널 위에서 Linux 시스템 콜을 번역하는 방식으로 동작하는데, 이 구조 때문에 네트워크 인터페이스가 제대로 공유되지 않는 케이스가 있다. Chrome DevTools Protocol 연결이 WSL1의 네트워크 레이어를 거치면서 OAuth 리다이렉트 시 끊어지는 것이었다. 해결책은 VSCode를 WSL1이 아닌 Windows에서 직접 실행하거나, WSL2로 마이그레이션하는 것이다. WSL2는 실제 Linux 커널을 사용해 네트워크 격리 문제가 없다.\n이 이슈는 code-oss 스킴 문제와 별개로 \u0026ldquo;브라우저/원격 환경에서 VSCode 익스텐션 개발이 로컬 환경과 다른 맥락에서 동작한다\u0026quot;는 더 넓은 패턴의 사례다. WSL, Docker, code-server, vscode.dev 등 다양한 환경에서 익스텐션이 사용되는 현실에서 익스텐션 개발자는 각 환경의 차이를 깊이 이해해야 한다.\n빠른 링크 code-server GitHub — 76,491 stars, TypeScript 오픈소스 프로젝트 code-server Issue #6584 — code-oss:// 스킴 OAuth 실패 이슈 (CLOSED) VSCode Issue #142080 — OAuth2 팝업 창 Extension API 요청 (OPEN) VSCode API: registerUriHandler — 공식 API 문서 MDN: window.close() — 브라우저 창 닫기 제약 설명 GitLens Extension — registerUriHandler 참조 구현 인사이트 code-server의 OAuth 문제는 \u0026ldquo;브라우저에서 실행되는 VS Code\u0026quot;라는 개념이 얼마나 복잡한 호환성 도전을 수반하는지 잘 보여준다. 로컬 환경에서 당연하게 동작하는 OS 레벨 URI 스킴 핸들러가 브라우저 샌드박스 안에서는 존재하지 않으며, 이 간극을 메우는 것은 code-server 팀이 단독으로 해결할 수 없는 VS Code 코어 레벨의 문제다. registerUriHandler API가 해결책으로 존재하지만, 모든 익스텐션 개발자가 이 API를 알고 올바르게 사용하는 것은 아니다 — Augment Code 같은 상용 제품조차 이 문제에 부딪혔다. GitLens가 성공적인 참조 구현을 제공했다는 점은 오픈소스 커뮤니티의 지식 공유 가치를 다시 한번 증명한다. vscode.env.uriScheme을 사용해 환경을 동적으로 감지하는 패턴은 로컬/원격/브라우저 환경을 모두 지원해야 하는 모든 VSCode 익스텐션 개발자가 반드시 숙지해야 하는 기법이다. 팝업 창 API(#142080)가 정식 API로 표준화된다면 OAuth UX가 크게 개선되겠지만, GitHub Auth만 특별 대우받는 현 상황이 개선될지는 불투명하다. WSL1 디버거 이슈는 별도의 교훈을 준다 — 네트워킹 문제는 코드 버그가 아닌 실행 환경의 구조적 차이에서 비롯될 수 있으므로, 환경 진단이 디버깅의 첫 단계가 되어야 한다.\n","date":"2026-03-06T00:00:00+09:00","image":"/images/posts/2026-03-06-vscode-code-server-oauth/cover.jpg","permalink":"/ko/posts/2026-03-06-vscode-code-server-oauth/","title":"VSCode + code-server OAuth 인증 이슈 — code-oss:// 스킴 문제의 원인과 해결책"},{"content":"개요 Google이 VS Code를 포크하여 만든 Agentic IDE, Antigravity가 등장했다. Cursor, Windsurf에 이어 AI IDE 시장의 세 번째 주자로 떠오르고 있는 Antigravity를 YouTube 데모, 실사용 블로그, Reddit 커뮤니티 반응, 그리고 URL scheme 호환성 이슈까지 종합적으로 분석한다.\ngraph TD A[VS Code 원본] --\u003e B[Cursor] A --\u003e C[Windsurf] A --\u003e D[Antigravity] B --\u003e E['커서탭' 자동완성 특화] C --\u003e F[Codeium 기반 AI Flow] D --\u003e G[Agent 컨트롤 패널 + 대형 컨텍스트] style D fill:#4285f4,color:#fffAntigravity 첫인상 — Agent 컨트롤 패널 YouTube 데모 영상에서 확인할 수 있는 Antigravity의 핵심 차별점은 \u0026ldquo;IDE가 아니라 Agent 컨트롤 패널에 가깝다\u0026quot;는 점이다.\n중국어권 개발자 Jimmy Song의 실사용 리뷰에 따르면:\n인터페이스 구조: Agent 관리 뷰 + 에디터 뷰로 분리되어, AgentHQ + VS Code를 합친 느낌 Agent 실행 속도: 코드 수정 한 번에 완료되는 비율이 일반 챗봇형 보조보다 높음 컨텍스트 윈도우: 에디터와 컨텍스트 영역이 모두 넓어 긴 diff/로그 분석에 유리 확장 마켓: 기본값이 OpenVSX Gallery라서 VS Code 공식 Marketplace와 불일치 VS Code처럼 쓰기 — 마이그레이션 가이드 Jimmy Song이 공유한 실전 마이그레이션 단계는 VS Code 유저가 Antigravity로 넘어갈 때 바로 적용 가능하다.\n1단계: 확장 마켓 교체 Settings → Antigravity Settings → Editor에서 두 URL을 VS Code 공식으로 변경:\nMarketplace Item URL: https://marketplace.visualstudio.com/items Marketplace Gallery URL: https://marketplace.visualstudio.com/_apis/public/gallery 이 한 줄로 VS Code의 전체 확장 생태계에 접근할 수 있게 된다.\n2단계: 외부 확장 설치 AMP: 무료 모드 지원, 문서 작성/스크립트 실행에 강점. 다만 Antigravity에서는 API 키 로그인만 가능 (OAuth 미지원) CodeX: 직접 VSIX 다운로드 불가 → VS Code에서 먼저 설치 후 .vsix 파일로 익스포트 → Antigravity에 Install from VSIX 3단계: TUN 모드 프록시 이슈 해결 VPN이나 TUN 모드를 사용하는 경우, Antigravity의 Chrome DevTools Protocol 디버깅이 깨진다. Settings → HTTP: No Proxy에 localhost, 127.0.0.1 추가로 해결.\n커뮤니티 반응 — Reddit의 솔직한 평가 Reddit r/ChatGPTCoding에서의 Antigravity 리뷰 제목 자체가 분위기를 말해준다: \u0026ldquo;I tried Google\u0026rsquo;s new Antigravity IDE so you don\u0026rsquo;t have to\u0026rdquo;\n커뮤니티에서 지적하는 핵심 문제:\n안정성: \u0026ldquo;Agent terminated due to error\u0026rdquo; 에러가 빈번. 수동 재시도 필요 모델 생태계: OpenAI, Anthropic, xAI 등 외부 모델 네이티브 통합 부재 커스터마이징: Copilot Chat처럼 커스텀 prompt/agent 불가, rules 설정만 가능 가격: 무료 모델 미지원 (월 $20+ 예상), GitHub Copilot Free tier와 대비 URL Scheme 전쟁 — vscode:// vs cursor:// vs antigravity:// AI IDE가 VS Code를 포크할 때 발생하는 흥미로운 문제가 있다. OS 수준에서 vscode:// URL scheme이 어떤 에디터로 라우팅되느냐 하는 충돌이다.\nCursor 포럼의 논의에 따르면:\n\u0026ldquo;VS Code는 vscode:// URI scheme을 등록하여 파일 열기, 특정 액션 트리거 등에 사용한다. Cursor도 같은 방식의 고유 scheme이 있는가?\u0026rdquo;\n실전 해결책으로 duti라는 macOS 도구를 활용한 URL scheme 리매핑이 공유되었다:\n# Cursor의 번들 ID 확인 osascript -e \u0026#39;id of application \u0026#34;Cursor\u0026#34;\u0026#39; # vscode:// → Cursor로 리매핑 duti -s com.todesktop.230313mzl4w4u92 vscode # 테스트 open \u0026#34;vscode://file/somefile.text:123\u0026#34; 이 문제는 Antigravity 등장으로 더 복잡해진다. 세 IDE가 모두 vscode://를 claim할 수 있기 때문이다. VS Code API의 UriHandler 인터페이스를 통한 커스텀 URI 처리가 확장 개발자에게는 필수 고려사항이 되었다.\ngraph LR A['vscode:// URL 클릭'] --\u003e B{OS URL 라우터} B --\u003e|기본| C[VS Code] B --\u003e|duti 리매핑| D[Cursor] B --\u003e|?| E[Antigravity] F[확장 개발자] --\u003e|UriHandler 구현| G[scheme 충돌 대응]빠른 링크 Google Antigravity YouTube Demo — 9분짜리 핸즈온 데모 영상 Antigravity를 VS Code처럼 쓰기 (Jimmy Song) — 마이그레이션 실전 가이드 (중문) duti를 이용한 URL scheme 리매핑 — macOS 전용 해결책 Cursor Forum: URL scheme 논의 — 커뮤니티 토론 VS Code UriHandler API — 확장 개발자용 레퍼런스 인사이트 AI IDE 전쟁은 이제 \u0026ldquo;AI가 코드를 얼마나 잘 쓰나\u0026quot;를 넘어 플랫폼 락인 싸움으로 진화하고 있다. VS Code 포크라는 전략은 기존 확장 생태계를 빌려올 수 있다는 장점이 있지만, URL scheme 충돌, 인증 호환성, 마켓플레이스 정책 등 예상치 못한 마찰이 발생한다.\nAntigravity의 Agent 컨트롤 패널 접근법은 \u0026ldquo;코드 에디터에 AI를 붙인다\u0026quot;가 아니라 \u0026ldquo;AI 에이전트 환경에 에디터를 붙인다\u0026quot;는 역발상이다. 이 철학적 차이가 장기적으로 승부를 가를 수 있다. 다만 현재의 안정성 문제와 모델 생태계 제한은 프로덕션 환경에서의 채택을 어렵게 만든다.\nduti를 활용한 URL scheme 리매핑은 당장 실전에서 쓸 수 있는 팁이며, 확장 개발자라면 UriHandler를 통한 multi-IDE 호환성을 반드시 고려해야 할 시점이다.\n","date":"2026-03-05T00:00:00+09:00","image":"/images/posts/2026-03-05-google-antigravity-ide/cover.jpg","permalink":"/ko/posts/2026-03-05-google-antigravity-ide/","title":"Google Antigravity IDE 완전 분석 — AI IDE 전쟁의 새 판도"},{"content":"개요 KIS OpenAPI 기반 AI 트레이딩 시스템에 Expert Agent Team 아키텍처를 도입한 하루의 기록이다. 4명의 전문가 AI + Chief Analyst 토론 시뮬레이션, 순수 Python 기술 지표 계산기, 그리고 KOSPI200 데이터 소스를 3번이나 갈아치운 삽질기를 정리한다.\ngraph TD A[KOSPI200 구성종목] --\u003e B[거래량/등락률 TOP50 교차] B --\u003e C[5~25개 후보 추출] C --\u003e D[일봉 차트 수집] D --\u003e E[기술 지표 계산] E --\u003e F[4명 Expert 병렬 분석] F --\u003e G[Chief Analyst 토론] G --\u003e H[매매 신호 생성] style F fill:#e8d44d,color:#333 style G fill:#e74c3c,color:#fffExpert Agent Team 아키텍처 기존 MarketScanner는 단일 Claude 호출로 종목을 분석했다. 이를 4명의 전문가가 각자 관점에서 분석하고, Chief Analyst가 의견을 종합하는 토론 구조로 교체했다.\n4명의 전문가 전문가 분석 관점 기술적 분석가 MA 정배열/역배열, RSI 구간, MACD 크로스, 볼린저 밴드 모멘텀 트레이더 거래량 급등 배율, Stochastic K/D, 단기 돌파 패턴 리스크 평가자 ATR 기반 위험도, RSI 과매수, 포트폴리오 집중도 포트폴리오 전략가 현금 비중, 섹터 분산, 기회비용 핵심은 asyncio.gather로 4명을 병렬 호출하는 것이다:\nasync def run_expert_panel(data_package: dict) -\u0026gt; list[dict]: experts = [ (\u0026#34;기술적 분석가\u0026#34;, \u0026#34;MA 정배열/역배열, RSI, MACD ...\u0026#34;), (\u0026#34;모멘텀 트레이더\u0026#34;, \u0026#34;거래량 급등, Stochastic K/D ...\u0026#34;), (\u0026#34;리스크 평가자\u0026#34;, \u0026#34;ATR 기반 위험도, RSI 과매수 ...\u0026#34;), (\u0026#34;포트폴리오 전략가\u0026#34;, \u0026#34;현금 비중, 섹터 집중도 ...\u0026#34;), ] tasks = [_call_expert(persona, focus, data_package) for persona, focus in experts] return await asyncio.gather(*tasks, return_exceptions=True) Chief Analyst 토론 시뮬레이션 4명의 의견이 모이면, Chief Analyst가 bullish/bearish 비율을 보고 최종 판단을 내린다. 단순 다수결이 아니라 반대 의견의 근거까지 평가하도록 프롬프트를 설계했다:\n# bullish 3 vs bearish 1이라도 bearish의 근거가 강하면 hold 가능 prompt = f\u0026#34;\u0026#34;\u0026#34; 전문가 의견 요약: {analyses_text} 만장일치가 아닌 경우, 소수 의견의 우려사항을 특히 주의 깊게 검토하세요. \u0026#34;\u0026#34;\u0026#34; 순수 Python 기술 지표 계산기 외부 라이브러리(TA-Lib, pandas-ta) 의존을 제거하기 위해 RSI, MACD, Stochastic, Bollinger Bands, ATR을 직접 구현했다.\ndef calculate_rsi(closes: list[float], period: int = 14) -\u0026gt; float | None: gains, losses = [], [] for i in range(1, len(closes)): diff = closes[i] - closes[i - 1] gains.append(max(diff, 0)) losses.append(max(-diff, 0)) avg_gain = sum(gains[:period]) / period avg_loss = sum(losses[:period]) / period # Wilder\u0026#39;s smoothing — SMA가 아닌 지수 평활법 for i in range(period, len(gains)): avg_gain = (avg_gain * (period - 1) + gains[i]) / period avg_loss = (avg_loss * (period - 1) + losses[i]) / period rs = avg_gain / avg_loss if avg_loss != 0 else float(\u0026#39;inf\u0026#39;) return round(100 - (100 / (1 + rs)), 2) Wilder\u0026rsquo;s Smoothing을 사용한 이유는 일반 SMA 대비 최근 값에 더 민감하게 반응하여 트레이딩 신호의 적시성이 높아지기 때문이다.\nKOSPI200 데이터 소스 삽질기 하루 동안 데이터 소스를 세 번 교체했다. 각 단계의 실패 원인과 해결 과정을 정리한다.\ngraph LR A[KIS APIinquire_index_components] --\u003e|실패| B[KIS APImarket_cap] B --\u003e|30개 제한| C[pykrx] C --\u003e|세션 쿠키 LOGOUT| D[NAVER Finance스크래핑] style A fill:#ff6b6b,color:#fff style B fill:#ff9f43,color:#fff style C fill:#ff6b6b,color:#fff style D fill:#2ecc71,color:#fff1차: KIS API inquire_index_components ❌ domestic_stock.json에 미등록 → API 호출 자체가 불가 KIS OpenAPI의 inquire_index_components는 문서에는 있지만 실제 SDK에 등록되지 않은 유령 API였다.\n2차: KIS API market_cap (fid_input_iscd=2001) ⚠️ 호출은 성공하지만 최대 30개만 반환 KOSPI200 필터(2001)를 걸어도 상위 30개 시가총액 종목만 내려온다. 200개 전체가 필요한 스크리닝에는 부족했다.\n3차: pykrx KRX 공식 데이터를 Python으로 가져올 수 있는 인기 라이브러리. 하지만:\n❌ KRX 엔드포인트가 세션 쿠키 없이 LOGOUT을 반환 pykrx의 내부 HTTP 세션이 KRX 서버의 인증 쿠키를 제대로 관리하지 못하는 경우가 있어, 서버가 LOGOUT이라는 텍스트 응답만 반환했다.\n최종 해결: NAVER Finance 스크래핑 결국 가장 안정적인 소스는 NAVER Finance였다:\ndef _fetch_kospi200_via_naver() -\u0026gt; dict[str, str]: session = requests.Session() session.headers[\u0026#34;User-Agent\u0026#34;] = \u0026#34;Mozilla/5.0\u0026#34; session.get(\u0026#34;https://finance.naver.com/\u0026#34;) # 세션 쿠키 획득 codes: dict[str, str] = {} for page in range(1, 25): # 24페이지 순회 resp = session.get( \u0026#34;https://finance.naver.com/sise/entryJongmok.naver\u0026#34;, params={\u0026#34;indCode\u0026#34;: \u0026#34;KPI200\u0026#34;, \u0026#34;page\u0026#34;: str(page)}, ) pairs = re.findall( r\u0026#34;item/main\\.naver\\?code=(\\d{6})[^\u0026gt;]*\u0026gt;([^\u0026lt;]+)\u0026#34;, resp.text, ) if not pairs: break for code, name in pairs: codes[code] = name.strip() return codes # 199개 정확히 반환 핵심 포인트:\nsession.get(\u0026quot;https://finance.naver.com/\u0026quot;)으로 세션 쿠키를 먼저 획득해야 함 entryJongmok.naver의 indCode=KPI200이 KOSPI200 필터 24페이지를 순회하면 199개 전체 구성종목을 정확히 가져옴 결과는 SQLite에 upsert하여 당일 캐시, 다음날 자동 갱신 마켓 스캐너 파이프라인 최종 완성된 파이프라인은 4단계로 동작한다:\nStage 작업 결과 1 KOSPI200 × (거래량 TOP50 + 등락률 TOP50) 교차 ~5개 후보 2 후보 종목 일봉 차트 수집 + 기술 지표 계산 enriched data 3 4명 Expert 병렬 Claude 분석 각자 bullish/bearish/neutral 4 Chief Analyst 토론 → 최종 신호 생성 BUY/SELL/HOLD 하루 커밋 10개, 2,689줄 추가로 전체 아키텍처를 단일 Claude 호출에서 Expert Team 토론 시스템으로 전환했다.\n빠른 링크 sharebook-kr/pykrx — KRX 주식 정보 스크래핑 라이브러리 (세션 이슈로 채택하지 않음) NAVER Finance KOSPI200 — 최종 채택한 데이터 소스 인사이트 이번 작업에서 가장 큰 교훈은 금융 데이터 API의 신뢰성은 문서가 아니라 실행으로만 검증 가능하다는 점이다. KIS API는 문서에 있지만 SDK에 없는 API가 있었고, pykrx는 세션 관리 버그로 인해 프로덕션에서 사용하기 어려웠다.\nExpert Agent Team 패턴은 주식 분석뿐 아니라 의사결정이 필요한 모든 AI 시스템에 적용 가능하다. 핵심은 단순 다수결이 아니라 소수 의견의 근거까지 평가하는 Chief Analyst의 토론 프롬프트 설계다. bullish 3 vs bearish 1이라도 bearish의 근거가 ATR 기반 변동성 경고라면, Chief가 hold 판단을 내릴 수 있다.\n순수 Python 기술 지표 구현은 TA-Lib 설치 이슈(C 라이브러리 의존)를 완전히 제거하면서도 Wilder\u0026rsquo;s Smoothing 같은 정확한 알고리즘을 유지할 수 있음을 보여준다. 배포 환경의 제약이 있는 프로젝트에서 유용한 접근법이다.\n","date":"2026-03-05T00:00:00+09:00","image":"/images/posts/2026-03-05-trading-agent-expert-team/cover.jpg","permalink":"/ko/posts/2026-03-05-trading-agent-expert-team/","title":"주식 트레이딩 에이전트 개발기 #2 — Expert Agent Team과 KOSPI200 데이터 삽질기"},{"content":"개요 Claude Code를 처음 쓰면 그냥 채팅하듯 명령을 던진다. 그런데 조금만 써보면 느끼게 된다 — \u0026ldquo;이건 뭔가 더 있는 것 같은데.\u0026rdquo; 실제로 Claude Code는 단순한 AI 채팅창이 아니라, Skills, Subagents, Commands 세 가지 핵심 레이어로 이루어진 에이전트 프레임워크다. 이 세 개념을 모르면 Claude Code를 절반의 성능으로만 쓰는 셈이다.\ngraph TD U[사용자 요청] --\u003e C[\"Commands \u0026lt;br/\u0026gt;슬래시 명령 진입점\"] C --\u003e S[\"Skills \u0026lt;br/\u0026gt;재사용 가능한 워크플로우\"] S --\u003e A[\"Subagents \u0026lt;br/\u0026gt;독립 실행 에이전트\"] A --\u003e R[결과 반환] S --\u003e RSkills — AI에게 \u0026lsquo;업무 매뉴얼\u0026rsquo;을 건네는 방법 Skills란 무엇인가 Skills는 Claude Code에 주입하는 재사용 가능한 워크플로우 정의서다. 마크다운(.md) 파일 하나가 곧 하나의 Skill이다. Claude가 특정 상황에서 어떻게 행동해야 하는지, 어떤 순서로 작업을 처리해야 하는지를 자연어로 기술한다.\n일반적인 프롬프트와의 차이가 중요하다. 프롬프트는 매번 새로 입력해야 하지만, Skill은 한 번 설치하면 조건이 맞을 때 자동으로 트리거된다. \u0026ldquo;기능 추가해줘\u0026quot;라고 했을 때 AI가 알아서 브레인스토밍 → 계획 수립 → 구현 → 리뷰 순서를 밟는 것, 이게 Skill이 작동하는 방식이다.\ngraph LR Normal[\"일반 프롬프트 \u0026lt;br/\u0026gt;매번 새로 작성\"] --\u003e|반복 작업| Waste[\"맥락 손실 \u0026lt;br/\u0026gt;비일관성\"] Skill[\"Skill 파일 \u0026lt;br/\u0026gt;한 번 정의\"] --\u003e|자동 트리거| Consistent[\"일관된 워크플로우 \u0026lt;br/\u0026gt;재사용 가능\"]Skill 파일 구조 .claude/ └── skills/ └── my-skill/ └── SKILL.md SKILL.md 안에는 이 Skill이 언제 발동해야 하는지(description), 그리고 어떤 절차로 실행해야 하는지(instructions)를 담는다. 예시:\n--- name: code-review description: PR 코드 리뷰 요청 시 자동 실행 --- ## 리뷰 절차 1. 변경된 파일 목록 확인 2. 보안 취약점 체크 3. 성능 이슈 분석 4. 개선 제안 작성 Skills 마켓플레이스 개인이 Skills를 직접 만들 수도 있지만, 이미 잘 만들어진 Skills 생태계가 존재한다. 대표적인 것이 obra/superpowers (⭐69k)다. Claude Code에 설치하면 브레인스토밍, 계획 수립, TDD 구현, 코드 리뷰까지의 전체 엔지니어링 워크플로우가 자동화된다.\n# Claude Code에서 마켓플레이스 추가 및 설치 /plugin marketplace add obra/superpowers-marketplace /plugin install superpowers@superpowers-marketplace Subagents — AI가 AI를 부리는 구조 Subagent의 핵심 아이디어 Subagent는 메인 Claude Code 세션이 별도의 Claude 인스턴스를 생성해 특정 작업을 위임하는 구조다. 마치 선임 개발자가 \u0026ldquo;이 모듈은 네가 담당해\u0026quot;라며 팀원에게 작업을 나눠주는 것과 같다.\n단순히 작업을 분리하는 것 이상의 의미가 있다. Subagent는 완전히 독립된 컨텍스트 윈도우를 갖는다. 메인 세션의 누적된 맥락, 이전 실패, 엉킨 히스토리로부터 자유롭다. 덕분에 \u0026lsquo;환각(hallucination)\u0026rsquo; 가능성이 현저히 줄어든다.\ngraph TD Main[\"메인 에이전트 \u0026lt;br/\u0026gt;전체 조율\"] --\u003e|암호화 모듈 작성| Sub1[\"Subagent 1 \u0026lt;br/\u0026gt;깨끗한 컨텍스트\"] Main --\u003e|유효성 검사 로직| Sub2[\"Subagent 2 \u0026lt;br/\u0026gt;깨끗한 컨텍스트\"] Main --\u003e|테스트 작성| Sub3[\"Subagent 3 \u0026lt;br/\u0026gt;깨끗한 컨텍스트\"] Sub1 --\u003e|결과만 반환| Main Sub2 --\u003e|결과만 반환| Main Sub3 --\u003e|결과만 반환| MainSubagent 만드는 법 Claude Code의 Task 도구를 사용하면 Subagent를 생성할 수 있다. Skill 파일 내부에서 다음과 같이 명시한다:\n## Subagent 실행 각 모듈을 독립된 Subagent에게 할당: - 인증 모듈: Task 도구로 별도 에이전트 실행 - DB 레이어: Task 도구로 별도 에이전트 실행 각 Subagent는 결과만 메인에 보고한다. 추천 Subagent 활용 패턴 패턴 설명 효과 병렬 모듈 구현 독립적인 파일/모듈을 동시에 개발 개발 속도 2~3배 향상 리뷰 전문화 보안·성능·스타일을 각각 다른 에이전트가 담당 편향 없는 철저한 리뷰 컨텍스트 초기화 복잡한 버그를 깨끗한 눈으로 재탐색 확증 편향 극복 장시간 작업 격리 메인 세션 오염 없이 실험적 작업 수행 안전한 탐색 Subagent vs Agent Teams 차이: Subagent는 결과만 반환하는 일방향 구조다. Agent Teams (실험적 기능)는 팀원끼리 직접 대화하는 양방향 협업 구조다. 복잡도와 비용도 Agent Teams가 훨씬 높다.\nCommands — 슬래시 명령어로 진입점 만들기 Commands란 Commands는 사용자가 직접 /명령어 형식으로 호출할 수 있는 슬래시 명령어다. 내부적으로 특정 Skill을 실행하거나, 복잡한 프롬프트를 단일 명령어로 캡슐화한다.\n.claude/ └── commands/ └── review.md # /review 명령어 정의 └── deploy.md # /deploy 명령어 정의 Command 파일 구조 # /review — PR 코드 리뷰 실행 ## 실행 내용 1. 현재 브랜치의 변경사항 분석 2. 보안·성능·스타일 순서로 리뷰 3. 개선 제안을 마크다운으로 정리 $ARGUMENTS 변수로 추가 옵션을 받을 수 있음 기본 제공 Commands vs 커스텀 Commands Claude Code는 기본적으로 /help, /clear, /compact 같은 Commands를 제공한다. 이외에 .claude/commands/ 디렉토리에 직접 만든 .md 파일이 커스텀 Command가 된다. Superpowers 같은 플러그인을 설치하면 /brainstorm, /write-plan, /execute-plan 같은 Commands가 추가된다.\ngraph LR User[\"/review 입력\"] --\u003e Cmd[\"Commands 레이어 \u0026lt;br/\u0026gt;명령어 파싱\"] Cmd --\u003e Skill[\"Skills 레이어 \u0026lt;br/\u0026gt;워크플로우 실행\"] Skill --\u003e Sub[\"Subagents 생성 \u0026lt;br/\u0026gt;병렬 실행\"] Sub --\u003e Out[결과 통합]세 개념의 관계 정리 graph TD Commands[\"Commands \u0026lt;br/\u0026gt;'진입점' \u0026lt;br/\u0026gt;사용자가 호출\"] Skills[\"Skills \u0026lt;br/\u0026gt;'워크플로우' \u0026lt;br/\u0026gt;AI가 따르는 절차서\"] Subagents[\"Subagents \u0026lt;br/\u0026gt;'실행자' \u0026lt;br/\u0026gt;독립 인스턴스\"] Commands --\u003e|Skills를 트리거| Skills Skills --\u003e|Subagents를 생성| Subagents Skills --\u003e|직접 실행도 가능| Result[결과] Subagents --\u003e|결과 반환| Result세 레이어는 이렇게 연결된다:\nCommands: 사용자의 요청을 받는 창구. /review를 입력하면 Commands 레이어가 어떤 Skill을 실행할지 결정한다. Skills: AI가 따르는 업무 매뉴얼. 어떤 순서로, 어떤 원칙으로 작업할지를 정의한다. Subagents: 실제 실행 단위. Skills가 복잡한 작업을 위임할 때 생성되는 독립 에이전트들이다. 빠른 링크 obra/superpowers GitHub — ⭐69k, Claude Code 최강 Skills 모음 Claude Code 공식 Skills 문서 — Skills 파일 형식 레퍼런스 코딩알려주는누나: Claude Code 3대 개념 영상 — 25분 실전 튜토리얼 인사이트 Skills, Subagents, Commands는 단순한 기능 목록이 아니라 Claude Code를 도구에서 시스템으로 격상시키는 아키텍처다. 매번 \u0026ldquo;이렇게 해줘\u0026quot;라고 프롬프트를 쓰는 것과, 한 번 Skill을 정의해 두고 자동으로 실행되게 하는 것은 개발 생산성에서 차원이 다른 결과를 만든다. 특히 Subagent의 \u0026lsquo;깨끗한 컨텍스트\u0026rsquo; 개념은 AI 환각 문제를 구조적으로 해결하는 우아한 접근이다. 작업마다 새로운 관점으로 시작하는 에이전트는 이전 실패에 갇히지 않는다. Commands는 이 복잡한 체계에 단순한 진입점을 만들어주는 UX 레이어다 — 복잡한 파이프라인을 /deploy 한 단어로 실행할 수 있다는 것 자체가 이 시스템의 완성도를 보여준다.\n","date":"2026-03-04T00:00:00+09:00","image":"/images/posts/2026-03-04-claude-code-skills-subagents-commands/cover.jpg","permalink":"/ko/posts/2026-03-04-claude-code-skills-subagents-commands/","title":"Claude Code 3대 핵심 개념 — Skills, Subagents, Commands 완전 정복"},{"content":"개요 2026년 2월 26일, Google이 이미지 생성 모델 역사를 다시 썼다. Nano Banana 2 (gemini-3.1-flash-image-preview) — Pro 수준의 지능과 Flash의 속도를 동시에 갖춘 새로운 스탠다드다. Nano Banana가 바이럴 센세이션을 일으켰고, Nano Banana Pro가 스튜디오급 품질을 제공했다면, Nano Banana 2는 그 둘의 정수를 합쳐 모든 사용자에게 개방했다.\ngraph LR NB1[\"Nano Banana \u0026lt;br/\u0026gt;2025 8월 \u0026lt;br/\u0026gt;'바이럴 센세이션'\"] --\u003e NBP[\"Nano Banana Pro \u0026lt;br/\u0026gt;2025 11월 \u0026lt;br/\u0026gt;'스튜디오 품질'\"] NBP --\u003e NB2[\"Nano Banana 2 \u0026lt;br/\u0026gt;2026 2월 26일 \u0026lt;br/\u0026gt;'Pro 품질 + Flash 속도'\"] NB1 --\u003e NB2 style NB2 fill:#4285F4,color:#fffNano Banana 2가 바꾼 것들 Pro 기능의 대중화 기존에 Nano Banana Pro 전용이었던 기능들이 Nano Banana 2에서 전체 사용자에게 개방됐다:\n실제 세계 지식 기반 생성 — Gemini의 실시간 웹 검색을 활용해 특정 인물, 장소, 제품을 정확하게 렌더링한다. 인포그래픽, 다이어그램, 데이터 시각화 생성이 더 정교해졌다.\n정밀 텍스트 렌더링 — 이미지 안에 선명하고 정확한 텍스트를 생성한다. 마케팅 목업, 그리팅 카드, 다국어 번역 및 현지화까지 지원한다.\n새로운 핵심 기능 피사체 일관성 유지 — 단일 워크플로우에서 최대 5명의 캐릭터와 14개 오브젝트의 외형을 일관되게 유지한다. 스토리보드나 연속 이미지 시리즈 제작이 가능해졌다.\n정확한 명령 이행 — 복잡한 프롬프트의 구체적인 뉘앙스까지 캡처한다. \u0026ldquo;원하는 이미지를 얻었다\u0026quot;는 경험이 이전보다 훨씬 일관적이다.\n프로덕션 레디 스펙 — 512px부터 4K까지, 4:1/1:4/8:1/1:8 등 극단적 비율을 포함한 다양한 종횡비 지원. 세로형 소셜 포스트부터 와이드스크린 배경까지 커버한다.\ngraph TD NB2[Nano Banana 2] --\u003e WK[\"실세계 지식 \u0026lt;br/\u0026gt;웹 검색 연동\"] NB2 --\u003e TR[\"텍스트 렌더링 \u0026lt;br/\u0026gt;다국어 지원\"] NB2 --\u003e SC[\"피사체 일관성 \u0026lt;br/\u0026gt;최대 5인 + 14객체\"] NB2 --\u003e IF[정밀 명령 이행] NB2 --\u003e PS[\"프로덕션 스펙 \u0026lt;br/\u0026gt;512px~4K\"] NB2 --\u003e VF[\"비주얼 피델리티 \u0026lt;br/\u0026gt;생동감 있는 조명·텍스처\"]API 접근법 3가지 전제 조건: 유료 API 키 필수 이것이 많은 개발자가 처음에 막히는 지점이다. 이미지 생성은 무료 티어에서 불가능하다. 다음 오류가 발생하면 유료 키가 없는 것이다:\nQuota exceeded for metric: generativelanguage.googleapis.com/ generate_content_free_tier_input_token_count, limit: 0 Method 1: Google AI Studio (코드 없이 테스트) AI Studio 접속 모델 드롭다운에서 gemini-3.1-flash-image-preview 선택 프롬프트 입력 후 Run 프로덕션 코드 작성 전 프롬프트 실험에 최적이다.\nMethod 2: Gemini API 직접 호출 Python:\nimport google.generativeai as genai import base64 genai.configure(api_key=\u0026#34;YOUR_PAID_API_KEY\u0026#34;) model = genai.GenerativeModel(\u0026#34;gemini-3.1-flash-image-preview\u0026#34;) response = model.generate_content( \u0026#34;A photorealistic golden retriever puppy in a sunlit meadow, \u0026#34; \u0026#34;soft bokeh background, warm afternoon light\u0026#34;, generation_config=genai.GenerationConfig( response_modalities=[\u0026#34;image\u0026#34;, \u0026#34;text\u0026#34;], ), ) for part in response.parts: if part.inline_data: image_data = base64.b64decode(part.inline_data.data) with open(\u0026#34;output.png\u0026#34;, \u0026#34;wb\u0026#34;) as f: f.write(image_data) Node.js:\nconst { GoogleGenerativeAI } = require(\u0026#34;@google/generative-ai\u0026#34;); const fs = require(\u0026#34;fs\u0026#34;); const genAI = new GoogleGenerativeAI(\u0026#34;YOUR_PAID_API_KEY\u0026#34;); async function generateImage() { const model = genAI.getGenerativeModel({ model: \u0026#34;gemini-3.1-flash-image-preview\u0026#34;, }); const result = await model.generateContent({ contents: [{ role: \u0026#34;user\u0026#34;, parts: [{ text: \u0026#34;a photorealistic cat\u0026#34; }] }], generationConfig: { responseModalities: [\u0026#34;image\u0026#34;, \u0026#34;text\u0026#34;] }, }); const imageData = result.response.candidates[0].content.parts[0].inlineData; fs.writeFileSync(\u0026#34;output.png\u0026#34;, Buffer.from(imageData.data, \u0026#34;base64\u0026#34;)); } generateImage(); Method 3: OpenAI 호환 게이트웨이 기존 OpenAI SDK를 사용하는 프로젝트라면 게이트웨이를 통해 최소한의 코드 변경으로 접근할 수 있다:\nfrom openai import OpenAI client = OpenAI( api_key=\u0026#34;YOUR_GATEWAY_KEY\u0026#34;, base_url=\u0026#34;https://gateway.example.com/v1\u0026#34;, ) response = client.images.generate( model=\u0026#34;gemini-3.1-flash-image-preview\u0026#34;, prompt=\u0026#34;A minimalist workspace with a MacBook and plant\u0026#34;, n=1, ) 가격 구조 해상도 Google 공식 서드파티 게이트웨이 2K 이미지 $0.101/장 ~$0.081/장 (약 20% 저렴) 4K 이미지 $0.150/장 ~$0.120/장 프로덕션 볼륨이 크다면 게이트웨이 옵션이 비용 절감에 유효하다.\nNano Banana 2 vs Nano Banana Pro 항목 Nano Banana 2 Nano Banana Pro 모델 ID gemini-3.1-flash-image-preview gemini-3-pro-image-preview 속도 Flash (빠름) Pro (느림) 화질 고품질 (Pro에 근접) 최고 품질 적합한 용도 빠른 반복, 대량 생성 최고 충실도가 필요한 전문 작업 Gemini 앱 기본값 ✅ (현재 기본) 3점 메뉴로 전환 가능 출시 플랫폼 Nano Banana 2는 Google 전체 에코시스템에 동시 출시됐다:\nGemini 앱: Fast, Thinking, Pro 모드 전체에서 기본 모델 Google 검색: AI Mode, Lens, 모바일/데스크톱 브라우저 (141개국) AI Studio + Gemini API: 미리보기로 제공 Google Cloud (Vertex AI): 미리보기 Flow: 기본 이미지 생성 모델 (크레딧 소모 없음) Google Ads: 캠페인 생성 시 제안 기능에 탑재 프롬프트 엔지니어링 팁 구체적으로 쓰기 — \u0026ldquo;강아지\u0026rdquo; 보다 \u0026ldquo;황금빛 털의 리트리버 강아지, 햇빛이 비치는 초원, 부드러운 보케 배경\u0026quot;이 훨씬 낫다.\n스타일 키워드 활용 — photorealistic, cinematic lighting, studio quality, minimalist, watercolor 등을 조합하면 원하는 미적 방향으로 유도할 수 있다.\n생각 수준 설정 — 복잡한 구성에는 Thinking: High 또는 Thinking: Dynamic을 지정하면 더 정교한 결과를 얻을 수 있다.\n멀티턴 편집 — 단일 요청으로 완벽한 결과를 기대하지 말자. \u0026ldquo;배경을 더 어둡게 해줘\u0026rdquo;, \u0026ldquo;캐릭터의 옷 색을 파란색으로 바꿔줘\u0026rdquo; 같은 반복적 수정이 최종 품질을 높인다.\n출처 표시 기술: SynthID + C2PA AI 생성 이미지임을 명확히 표시하는 두 가지 기술이 적용됐다:\nSynthID: 이미지에 눈에 보이지 않는 워터마크를 삽입. AI 생성 여부를 기계적으로 검증 가능. C2PA Content Credentials: 이미지 생성 정보를 메타데이터로 포함. 출처 추적 가능. 생성형 AI 시대의 미디어 신뢰성 문제에 대한 Google의 기술적 답변이다.\n빠른 링크 Nano Banana 2 공식 발표 (blog.google) — 기능 상세 및 프롬프트 예시 Nano Banana 2 API 튜토리얼 (evolink.ai) — Python/Node.js 코드 예제 및 가격 가이드 Google AI Studio — 코드 없이 바로 테스트 Gemini API 가격 페이지 — 최신 이미지 생성 요금 인사이트 Nano Banana 2의 등장이 의미하는 바는 단순히 \u0026ldquo;더 좋은 이미지 생성\u0026quot;이 아니다. Pro 수준의 기능을 Flash 속도와 합치면서 이미지 생성의 경제성이 근본적으로 달라졌다. 스튜디오급 품질을 위해 느린 Pro 모델을 써야 했던 트레이드오프가 사라진다. 특히 피사체 일관성(최대 5인 캐릭터 + 14 오브젝트)과 실세계 지식 연동은 마케팅, 컨텐츠 제작, 게임 에셋 파이프라인의 프로덕션 워크플로우를 직접적으로 타겟한다. 실시간 웹 검색 기반의 이미지 생성은 \u0026ldquo;지식과 시각의 통합\u0026quot;이라는 방향성을 보여준다 — AI가 단순히 패턴을 생성하는 것이 아니라 세계를 이해하고 시각화하는 방향으로 진화하고 있다. SynthID와 C2PA를 통한 출처 표시 기술을 기본 탑재한 것도 주목할 점이다. 생성형 AI에 대한 신뢰성 논쟁이 커지는 상황에서 \u0026ldquo;우리가 만든 것임을 증명할 수 있는\u0026rdquo; 기술을 처음부터 심어두는 접근은, 앞으로 이 기술이 얼마나 진지하게 프로덕션 환경에서 쓰일 것인지를 보여주는 신호다.\n","date":"2026-03-04T00:00:00+09:00","image":"/images/posts/2026-03-04-nano-banana-2/cover.jpg","permalink":"/ko/posts/2026-03-04-nano-banana-2/","title":"Nano Banana 2 완전 분석 — Pro급 품질을 Flash 속도로, Google 최신 이미지 생성 모델"},{"content":"개요 Claude Code는 강력하다. 그런데 이상하게 결과물이 찜찜하다. \u0026ldquo;일단 돌아가기는 하는데…\u0026rdquo; 싶은 코드. 테스트는 없고, 구조는 엉성하고, 어제 쓴 코드를 오늘 AI가 기억 못 한다. Superpowers는 이 문제를 구조적으로 해결하는 Skills 프레임워크다. GitHub 스타 ⭐69k, Claude Code에서 설치 가능한 플러그인 중 압도적 1위다.\n단순한 프롬프트 모음집이 아니다. \u0026ldquo;먼저 생각하고, 설계하고, 테스트하고, 구현하는\u0026rdquo; 엔지니어링 규율을 AI에게 강제 주입하는 시스템이다.\ngraph TD Request[\"사용자 요청 \u0026lt;br/\u0026gt;'이거 만들어줘'\"] --\u003e Brain[\"brainstorming \u0026lt;br/\u0026gt;요구사항 명확화\"] Brain --\u003e Plan[\"writing-plans \u0026lt;br/\u0026gt;구현 계획 수립\"] Plan --\u003e Exec[\"subagent-driven-development \u0026lt;br/\u0026gt;병렬 구현\"] Exec --\u003e Review[\"requesting-code-review \u0026lt;br/\u0026gt;품질 검증\"] Review --\u003e Done[완성된 코드베이스] style Brain fill:#4A90D9,color:#fff style Plan fill:#4A90D9,color:#fff style Exec fill:#4A90D9,color:#fff style Review fill:#4A90D9,color:#fffSuperpowers란 Superpowers는 Jesse Vincent(@obra)가 만든 오픈소스 Skills 프레임워크다. Claude Code, Cursor, Codex, OpenCode 모두 지원한다.\n핵심 아이디어는 단순하다: AI가 코딩 요청을 받았을 때 즉시 코드를 쓰지 못하게 한다. 대신 브레인스토밍 → 계획 수립 → TDD 구현 → 리뷰 순서를 강제한다. 급할수록 돌아가라는 소프트웨어 공학의 오래된 진리를 AI에게 가르치는 것이다.\n설치 방법 # Claude Code에서 마켓플레이스 등록 /plugin marketplace add obra/superpowers-marketplace # 플러그인 설치 /plugin install superpowers@superpowers-marketplace 설치 후 새 세션을 시작하면 즉시 동작한다. /sup을 입력해 brainstorm, write-plan, execute-plan 등이 나오면 설치 성공이다.\n7가지 핵심 Skill 분석 Superpowers는 소프트웨어 개발 라이프사이클 전체를 커버하는 7개 핵심 Skills로 구성된다.\ngraph LR S1[brainstorming] --\u003e S2[writing-plans] S2 --\u003e S3[using-git-worktrees] S3 --\u003e S4[subagent-driven-development] S4 --\u003e S5[requesting-code-review] S5 --\u003e S6[receiving-code-review] S6 --\u003e S7[finishing-a-development-branch]1. brainstorming — 코딩 전에 \u0026lsquo;멈추는\u0026rsquo; 기술 요청을 받으면 AI가 즉시 코드를 쓰지 않고 역질문을 던진다. \u0026ldquo;사용 시나리오는?\u0026rdquo;, \u0026ldquo;배포 환경은?\u0026rdquo;, \u0026ldquo;성능 요구사항은?\u0026rdquo; 마치 베테랑 아키텍트가 주니어 개발자의 코딩을 잠시 멈추는 것처럼.\n이 과정 끝에 AI는 요구사항 문서를 생성한다. 사용자가 승인하면 다음 단계로 넘어간다.\n심리학적 배경: Superpowers 제작자는 심리학 전공자다. \u0026ldquo;목표를 먼저 선언하면 행동이 바뀐다\u0026quot;는 인지심리학 원리를 AI 워크플로우에 적용한 것이다.\n2. writing-plans — 주니어도 따를 수 있는 계획서 브레인스토밍이 끝나면 구현 계획을 수립한다. 이 계획서의 기준이 독특하다: \u0026ldquo;판단력 없고, 맥락 없고, 테스트를 싫어하는 열정적인 주니어 개발자도 따를 수 있을 만큼 명확하게.\u0026rdquo;\n계획서는 원자 단위 태스크로 분해된다. 각 태스크는 독립적으로 실행 가능하고, 완료 여부를 명확히 판단할 수 있다.\n├── Task 1: validators/ 모듈 구조 생성 (파일만) ├── Task 2: 이메일 형식 검증 로직 + 테스트 작성 ├── Task 3: DNS MX 레코드 검증 로직 + 테스트 작성 └── Task 4: 미들웨어 레이어 통합 3. using-git-worktrees — 독립된 작업 공간 확보 각 개발 태스크를 Git Worktree(메인 브랜치를 건드리지 않는 독립된 파일시스템 복사본)에서 실행한다. 실험이 실패해도 메인 코드베이스는 안전하다.\n# Superpowers가 자동으로 실행하는 worktree 생성 git worktree add .claude/worktrees/feature-auth feature/auth 4. subagent-driven-development — AI 팀으로 병렬 개발 계획서의 각 태스크를 독립된 Subagent에게 할당한다. 각 Subagent는:\n깨끗한 컨텍스트에서 시작 (이전 실패 기억 없음) 단 하나의 태스크만 집중 완료 후 결과만 메인에 보고 graph TD Lead[\"메인 에이전트 \u0026lt;br/\u0026gt;PM 역할\"] --\u003e|Task 1| S1[\"Subagent 1 \u0026lt;br/\u0026gt;이메일 검증 로직\"] Lead --\u003e|Task 2| S2[\"Subagent 2 \u0026lt;br/\u0026gt;DNS 검증 로직\"] Lead --\u003e|Task 3| S3[\"Subagent 3 \u0026lt;br/\u0026gt;미들웨어 통합\"] S1 --\u003e|결과 + 테스트| Lead S2 --\u003e|결과 + 테스트| Lead S3 --\u003e|결과 + 테스트| Lead Lead --\u003e Merge[통합 및 검증] \u0026ldquo;이 구조를 생각한 사람은 천재인 것 같다.\u0026rdquo; — velog 실전 체험기\n5. requesting-code-review / 6. receiving-code-review — 완성 전 검증 구현이 끝나면 자동으로 코드 리뷰를 요청한다. 리뷰 결과를 받았을 때 AI가 무조건 동의하지 않도록 receiving-code-review Skill이 제동을 건다. 기술적으로 타당한지 검증한 뒤에만 반영한다.\n7. finishing-a-development-branch — 안전한 머지 개발 완료 후 머지 전략을 제시한다. PR 생성, 브랜치 정리, 릴리즈 노트 등 마무리 단계를 체계적으로 안내한다.\n실전 데모: 이메일 검증 서비스 만들기 다음 프롬프트를 Superpowers가 설치된 Claude Code에 입력했을 때의 실제 흐름이다.\nPython으로 엔터프라이즈급 이메일 검증 서비스를 만들어줘. RFC 표준 (sub-addressing 포함), IDN, DNS MX 레코드 체크 지원. Step 1: brainstorm 자동 발동\nAI가 코드 대신 질문을 던진다:\n\u0026ldquo;단일 이메일 검증인가요, 배치 처리인가요?\u0026rdquo; \u0026ldquo;DNS 검증 레벨은? (기본/심화)\u0026rdquo; \u0026ldquo;캐싱 전략이 필요한가요?\u0026rdquo; Step 2: 프로젝트 구조 제안\nemail_validator/ ├── validators/ # 검증 로직 ├── middleware/ # 속도 제한 ├── cache/ # 결과 캐싱 └── tests/ # 선-실패 테스트 Step 3: TDD로 구현\n먼저 실패하는 테스트를 작성하고, 그걸 통과하도록 코드를 짠다. AI가 흔히 생산하는 \u0026ldquo;돌아가지만 테스트 없는 스파게티 코드\u0026quot;의 근본 원인을 차단한다.\nSuperpowers가 강제하는 엔지니어링 원칙 원칙 의미 Superpowers의 구현 TDD 테스트 먼저, 구현 나중 subagent-driven-development Skill에 명시 YAGNI You Aren\u0026rsquo;t Gonna Need It — 지금 필요한 것만 writing-plans에서 범위 제한 DRY Don\u0026rsquo;t Repeat Yourself 코드 리뷰 단계에서 중복 감지 깨끗한 컨텍스트 이전 실패에 오염되지 않은 새 시작 Subagent 구조로 보장 mega-code와의 비교 비슷한 시기에 등장한 wisdomgraph/mega-code (⭐15)도 주목할 만하다. Superpowers가 \u0026ldquo;엔지니어링 워크플로우 강제\u0026quot;에 집중한다면, mega-code는 \u0026ldquo;세션 간 지식 축적\u0026quot;에 집중한다.\ngraph LR SP[\"Superpowers \u0026lt;br/\u0026gt;워크플로우 규율\"] --\u003e|설치| Claude[Claude Code] MC[\"mega-code \u0026lt;br/\u0026gt;지식 진화\"] --\u003e|설치| Claude SP -.-\u003e|보완| MC MC -.-\u003e|보완| SP Superpowers: 매 세션의 개발 품질을 높임. Skills가 자동 트리거. mega-code: 세션 간 실수를 기억해 점진적으로 개선. BYOK(자체 API 키) 방식. 둘을 함께 쓰면 개발 품질과 세션 간 학습을 동시에 챙길 수 있다.\n빠른 링크 obra/superpowers GitHub — ⭐69k, 소스코드 및 설치 문서 Claude Code × Superpowers 체험기 (velog) — 실전 이메일 검증 서비스 데모 하리아빠 Superpowers 완벽 가이드 (YouTube) — 7가지 Skill 실전 데모 30분 wisdomgraph/mega-code GitHub — 자기 진화 AI 코딩 인프라 인사이트 Superpowers가 보여주는 핵심 통찰은 \u0026ldquo;AI의 문제는 능력 부족이 아니라 규율 부족\u0026ldquo;이라는 것이다. Claude Code는 이미 충분히 똑똑하다. 문제는 \u0026ldquo;이거 만들어줘\u0026quot;라는 지시를 받으면 즉시 코드를 뱉어내는 본능이다. 베테랑 개발자가 요구사항을 받으면 먼저 질문하고, 설계하고, 테스트 시나리오를 구상하듯이, AI도 그렇게 행동하도록 강제하는 것이 Superpowers의 본질이다. 특히 subagent-driven-development 패턴에서 각 Subagent가 깨끗한 컨텍스트를 갖는다는 설계는 AI 환각(hallucination) 문제를 구조적으로 해결한다. 긴 대화에서 이전 실패가 다음 응답을 오염시키는 문제를 Subagent 격리로 차단하는 것이다. 69k 스타가 보여주듯, 이 접근법은 이미 수많은 개발자에게 검증되었다.\n","date":"2026-03-04T00:00:00+09:00","image":"/images/posts/2026-03-04-claude-code-superpowers/cover.jpg","permalink":"/ko/posts/2026-03-04-claude-code-superpowers/","title":"Superpowers 완벽 가이드 — Claude Code에 '엔지니어링 규율'을 주입하는 법"},{"content":"개요 Claude Code의 Agent Teams는 여러 Claude Code 인스턴스를 하나의 팀으로 묶어 병렬 작업을 수행하는 실험적 기능이다. 기존 Subagent가 단일 세션 내에서 결과만 돌려보내는 구조였다면, Agent Teams는 팀원끼리 직접 메시지를 주고받고, 공유 태스크 리스트를 통해 자율적으로 작업을 조율한다. 오늘은 Agent Teams의 아키텍처, Subagent와의 차이점, 그리고 실전 활용 패턴을 정리한다.\ngraph TD Lead[Team Lead] --\u003e|생성| T1[Teammate 1] Lead --\u003e|생성| T2[Teammate 2] Lead --\u003e|생성| T3[Teammate 3] T1 --- T2 T2 --- T3 T1 --- T3 T1 --\u003e TL[Shared Task List] T2 --\u003e TL T3 --\u003e TL T1 --\u003e MB[Mailbox] T2 --\u003e MB T3 --\u003e MBAgent Teams vs Subagent — 핵심 차이점 Agent Teams와 Subagent는 둘 다 작업을 병렬화하지만, 동작 방식이 근본적으로 다르다.\nSubagent는 메인 세션 내부에서 실행되는 경량 헬퍼다. 작업을 수행한 뒤 결과를 메인 에이전트에 보고하는 것이 전부다. Subagent끼리는 서로 대화할 수 없고, 작업 중간에 발견한 내용을 공유할 수도 없다. 메인 에이전트가 모든 중개 역할을 한다.\nAgent Teams는 완전히 독립된 Claude Code 인스턴스들로 구성된다. 각 팀원은 자신만의 컨텍스트 윈도우를 가지며, 공유 태스크 리스트를 통해 작업을 자율적으로 선택(claim)한다. 핵심은 팀원 간 직접 커뮤니케이션이 가능하다는 것이다. 특정 팀원에게 메시지를 보낼 수도 있고, 전체 팀에 브로드캐스트할 수도 있다.\n항목 Subagent Agent Teams 컨텍스트 독립 컨텍스트, 결과만 반환 독립 컨텍스트, 완전 자율 커뮤니케이션 메인 에이전트에만 보고 팀원 간 직접 메시징 조율 방식 메인 에이전트가 전부 관리 공유 태스크 리스트 + 자율 조율 적합한 작업 결과만 필요한 단순 작업 토론과 협업이 필요한 복잡한 작업 토큰 비용 낮음 (요약된 결과만 반환) 높음 (각 팀원이 별도 인스턴스) graph LR MA[Main Agent] --\u003e|지시| SA1[Subagent 1] MA --\u003e|지시| SA2[Subagent 2] SA1 --\u003e|결과| MA SA2 --\u003e|결과| MAAgent Teams 모델에서는 이 구조가 달라진다:\ngraph LR TL[Team Lead] --\u003e|조율| AT1[Teammate 1] TL --\u003e|조율| AT2[Teammate 2] AT1 --- AT2 AT1 --\u003e TaskList[Task List] AT2 --\u003e TaskList팀 설정과 활성화 Agent Teams는 기본적으로 비활성화되어 있다. settings.json에서 환경변수를 설정하면 활성화된다:\n{ \u0026#34;env\u0026#34;: { \u0026#34;CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS\u0026#34;: \u0026#34;1\u0026#34; } } 활성화 후에는 자연어로 팀 구성을 요청하면 된다:\nCLI 도구의 UX, 기술 아키텍처, 반론을 각각 담당하는 3명의 팀원으로 에이전트 팀을 구성해줘. 디스플레이 모드 In-process: 메인 터미널에서 모든 팀원이 실행. Shift+Down으로 팀원 전환. 별도 설정 불필요. Split panes: tmux 또는 iTerm2에서 각 팀원이 독립된 패널. 모든 작업 상태를 동시에 확인 가능. settings.json에서 모드를 설정한다:\n{ \u0026#34;teammateMode\u0026#34;: \u0026#34;tmux\u0026#34; } 실전 활용 패턴 1. 병렬 코드 리뷰 단일 리뷰어는 한 번에 한 가지 유형의 이슈에 집중하기 마련이다. 리뷰 관점을 독립된 도메인으로 분리하면 보안, 성능, 테스트 커버리지를 동시에 철저히 검토할 수 있다:\nPR #142를 리뷰할 에이전트 팀을 만들어줘. 3명의 리뷰어: - 보안 취약점 전문 - 성능 영향 분석 - 테스트 커버리지 검증 각자 리뷰 후 결과를 보고하도록. 2. 경쟁 가설 디버깅 원인이 불분명한 버그에서 단일 에이전트는 하나의 설명을 찾으면 멈추는 경향이 있다. Agent Teams로 서로 다른 가설을 동시에 탐구하고 상호 반박하게 하면, 살아남는 이론이 실제 원인일 가능성이 훨씬 높다:\n앱이 한 번의 메시지 후 종료되는 문제 조사. 5명의 팀원을 생성해서 각각 다른 가설을 탐구하되, 과학적 토론처럼 서로의 이론을 반박하도록 해줘. 3. 크로스레이어 기능 개발 프론트엔드, 백엔드, 테스트가 동시에 변경되어야 하는 작업에서 각 레이어를 별도 팀원이 담당한다. 파일 충돌을 방지하기 위해 각 팀원이 담당하는 파일 세트를 명확히 분리하는 것이 중요하다.\nWorktree와의 결합 Agent Teams의 팀원들은 기본적으로 같은 파일시스템을 공유한다. 서로 다른 파일을 편집하면 문제없지만, 같은 파일을 동시에 수정하면 충돌이 발생할 수 있다. 이때 Git Worktree를 결합하면 각 팀원이 독립된 파일시스템 복사본에서 작업하게 된다:\ngraph TD A[Teammate A] --\u003e|편집| FS[공유 파일시스템] B[Teammate B] --\u003e|편집| FS FS --\u003e CONFLICT[파일 충돌] C[Teammate A] --\u003e|편집| WT1[Worktree A] D[Teammate B] --\u003e|편집| WT2[Worktree B] WT1 --\u003e|병합| MAIN[Main Branch] WT2 --\u003e|병합| MAIN에이전트 정의에서 isolation: worktree를 설정하면 팀원마다 별도의 worktree가 생성된다.\n비용과 운영 팁 Agent Teams는 팀원 수에 비례하여 토큰을 소비한다. 3명의 팀원이면 단일 세션 대비 약 3~4배의 토큰을 사용한다. Plan mode에서 실행하면 약 7배까지 증가할 수 있다.\n비용을 관리하면서 효과를 극대화하는 전략:\n팀원에게 Sonnet 모델 사용: 비용과 성능의 균형. Opus는 리드에게만 할당. 3~5명으로 시작: 대부분의 워크플로우에서 최적. 팀원당 5~6개 태스크가 적정. 완료 후 즉시 정리: 유휴 팀원도 토큰을 소비. Clean up the team 명령으로 정리. Spawn 프롬프트에 충분한 컨텍스트 제공: 팀원은 리드의 대화 히스토리를 상속하지 않으므로, 작업에 필요한 맥락을 프롬프트에 포함해야 한다. 빠른 링크 Claude Code Agent Teams 공식 문서 — 설정, 명령어, 제한사항 상세 Claude Code Agent Teams Complete Guide (claudefa.st) — 2026년 최신 가이드 Worktree + Agent Teams 병행 가이드 — 파일시스템 격리 전략 인사이트 Agent Teams는 단순한 병렬 실행이 아니라, 에이전트 간 소통과 자율 조율이라는 새로운 차원을 추가한 기능이다. Subagent가 \u0026ldquo;일꾼에게 지시하고 결과를 받는\u0026rdquo; 위계적 모델이라면, Agent Teams는 \u0026ldquo;동료들이 함께 문제를 토론하고 해결하는\u0026rdquo; 협업 모델에 가깝다. 특히 경쟁 가설 디버깅 패턴은 단일 에이전트의 확증 편향(confirmation bias)을 극복하는 효과적인 전략이다. 아직 실험 단계이고 세션 재개가 안 되는 등 제약이 있지만, 복잡한 코드베이스에서 병렬 탐색이 필요한 작업에는 상당한 가치를 제공한다. Worktree와 결합하면 파일 충돌 없이 완전한 병렬 개발이 가능하므로, 대규모 리팩토링이나 멀티레이어 기능 구현에서 특히 유용하다.\n","date":"2026-03-03T00:00:00+09:00","image":"/images/posts/2026-03-03-claude-code-agent-teams/cover.jpg","permalink":"/ko/posts/2026-03-03-claude-code-agent-teams/","title":"Claude Code Agent Teams — 멀티 에이전트 협업의 새로운 패러다임"},{"content":"개요 Claude Code는 개발자당 평균 하루 $6, 월 $100200 정도의 토큰 비용이 발생한다. 그런데 사용 방식에 따라 이 비용은 크게 달라진다. 컨텍스트 관리, 모델 선택, CLAUDE.md 최적화, 그리고 Usage \u0026amp; Cost API를 활용한 모니터링까지 — 체계적인 전략으로 토큰 소비를 5080% 줄일 수 있다. 이 글에서는 Claude Code의 비용 구조를 이해하고, 실전에서 바로 적용할 수 있는 최적화 기법들을 정리한다.\ngraph TD A[토큰 비용 절감] --\u003e B[컨텍스트 관리] A --\u003e C[모델 선택] A --\u003e D[CLAUDE.md 최적화] A --\u003e E[모니터링] B --\u003e B1[clear 명령] B --\u003e B2[compact 명령] B --\u003e B3[Auto-compaction] C --\u003e C1[Sonnet] C --\u003e C2[Opus] C --\u003e C3[Haiku] D --\u003e D1[500줄 이하 유지] D --\u003e D2[Skills로 분리] E --\u003e E1[cost 명령] E --\u003e E2[Usage API] E --\u003e E3[Cost API]비용이 발생하는 구조 이해하기 Claude Code의 토큰 비용은 컨텍스트 크기에 비례한다. Claude가 처리하는 컨텍스트가 클수록 메시지당 비용이 올라간다. 대화가 길어질수록, 참조하는 파일이 많을수록, MCP 서버가 많을수록 컨텍스트가 커진다.\nClaude Code는 자동으로 두 가지 최적화를 수행한다:\nPrompt Caching: 시스템 프롬프트 같은 반복 콘텐츠의 비용을 자동 절감 Auto-compaction: 컨텍스트 한도에 접근하면 대화 히스토리를 자동 요약 그러나 이것만으로는 부족하다. 사용자가 적극적으로 관리해야 진짜 절약이 된다.\n전략 1: 컨텍스트를 적극적으로 관리하기 가장 큰 토큰 낭비는 불필요한 컨텍스트 축적에서 온다.\n/clear — 작업 전환 시 필수 관련 없는 작업으로 넘어갈 때는 반드시 /clear로 컨텍스트를 초기화한다. 이전 대화의 오래된 컨텍스트는 이후 모든 메시지에서 토큰을 낭비한다.\n/rename auth-refactoring # 현재 세션에 이름 붙이기 /clear # 컨텍스트 초기화 # 새 작업 시작 나중에 해당 세션이 필요하면 /resume으로 돌아갈 수 있다.\n/compact — 10~15회 대화마다 대화가 길어지면 /compact로 히스토리를 압축한다. 옵션으로 보존할 내용을 지정할 수 있다:\n/compact Focus on code samples and API usage CLAUDE.md에서 compaction 동작을 커스터마이징하는 것도 가능하다:\n# Compact instructions When you are using compact, please focus on test output and code changes /cost — 실시간 비용 모니터링 현재 세션의 토큰 사용량을 /cost로 확인한다. 상태줄에 지속적으로 표시하려면 statusline 설정을 변경한다.\n전략 2: 모델을 적재적소에 배치하기 모든 작업에 Opus를 쓸 필요가 없다.\n모델 적합한 작업 비용 Opus 복잡한 아키텍처 결정, 다단계 추론 높음 Sonnet 일반 코딩 작업 (대부분의 경우) 중간 Haiku 파일 탐색, 테스트 실행, 단순 질문 낮음 (~80% 저렴) 세션 중간에 /model로 전환하고, /config에서 기본값을 설정한다. Subagent에는 model: haiku를 지정해서 단순 작업에 비용을 아낀다.\ngraph LR Task[작업 종류] --\u003e|복잡한 설계| Opus[Opus 4.6] Task --\u003e|일반 코딩| Sonnet[Sonnet 4.6] Task --\u003e|탐색| Haiku[Haiku] Opus --\u003e|전환| Sonnet Sonnet --\u003e|전환| HaikuExtended Thinking 조정 확장 사고(Extended Thinking)는 기본 31,999 토큰 예산으로 활성화되어 있다. 사고 토큰은 출력 토큰으로 과금되므로, 단순한 작업에서는 불필요한 비용이다:\n/model에서 Opus 4.6의 노력 수준(effort level)을 낮추기 /config에서 사고 기능 비활성화 MAX_THINKING_TOKENS=8000으로 예산 낮추기 전략 3: CLAUDE.md를 날씬하게 유지하기 CLAUDE.md는 세션 시작 시 전체가 컨텍스트에 로드된다. PR 리뷰 절차, 데이터베이스 마이그레이션 가이드 같은 특정 워크플로우 지침이 들어있으면, 관련 없는 작업을 할 때도 그 토큰이 매 턴마다 과금된다.\nSkills로 분리하기 CLAUDE.md에서 전문 지침을 Skills로 분리하면 호출될 때만 로드된다:\nCLAUDE.md (필수 사항만, ~500줄 이하) ├── 프로젝트 아키텍처 요약 ├── 핵심 코딩 컨벤션 └── 자주 쓰는 명령어 .claude/skills/ (필요할 때만 로드) ├── pr-review/ # PR 리뷰 절차 ├── db-migration/ # DB 마이그레이션 가이드 └── deploy/ # 배포 프로세스 MCP 서버 오버헤드 줄이기 각 MCP 서버는 유휴 상태에서도 도구 정의를 컨텍스트에 추가한다. /context로 현재 컨텍스트 점유 상황을 확인하고:\n사용하지 않는 MCP 서버는 /mcp에서 비활성화 gh, aws 같은 CLI 도구를 MCP 서버 대신 선호 (컨텍스트 오버헤드 없음) 도구 검색 임계값을 ENABLE_TOOL_SEARCH=auto:5로 낮추기 전략 4: 작업 패턴 최적화 Plan Mode 활용 Shift+Tab으로 Plan Mode에 진입하면 Claude가 코드베이스를 탐색하고 접근 방식을 제안한다. 초기 방향이 틀렸을 때 비용이 큰 재작업을 방지할 수 있다.\n조기 방향 수정 Claude가 잘못된 방향으로 가면 Escape로 즉시 중단. /rewind 또는 Escape 두 번으로 이전 체크포인트로 복원한다.\nSubagent에 무거운 작업 위임 테스트 실행, 문서 가져오기, 로그 파일 처리 같은 대량 출력 작업은 Subagent에 위임한다. 상세 출력은 Subagent 컨텍스트에 남고, 요약만 메인 대화로 돌아온다.\n전략 5: Usage \u0026amp; Cost API로 조직 비용 관리 개인 사용을 넘어 팀 전체의 비용을 추적하려면 Anthropic의 Admin API를 활용한다.\nUsage API — 토큰 소비량 추적 모델별 일일 토큰 사용량을 조회하는 예시:\ncurl \u0026#34;https://api.anthropic.com/v1/organizations/usage_report/messages?\\ starting_at=2026-03-01T00:00:00Z\u0026amp;\\ ending_at=2026-03-03T00:00:00Z\u0026amp;\\ group_by[]=model\u0026amp;\\ bucket_width=1d\u0026#34; \\ --header \u0026#34;anthropic-version: 2023-06-01\u0026#34; \\ --header \u0026#34;x-api-key: $ADMIN_API_KEY\u0026#34; 주요 기능:\n1분/1시간/1일 단위로 시계열 집계 모델, 워크스페이스, API 키, 서비스 티어별 필터링 Uncached input, cached input, cache creation, output 토큰 추적 Data residency(추론 지역) 및 Fast Mode 추적 Cost API — USD 비용 추적 워크스페이스별 비용을 조회한다:\ncurl \u0026#34;https://api.anthropic.com/v1/organizations/cost_report?\\ starting_at=2026-03-01T00:00:00Z\u0026amp;\\ ending_at=2026-03-03T00:00:00Z\u0026amp;\\ group_by[]=workspace_id\u0026amp;\\ group_by[]=description\u0026#34; \\ --header \u0026#34;anthropic-version: 2023-06-01\u0026#34; \\ --header \u0026#34;x-api-key: $ADMIN_API_KEY\u0026#34; graph TD AdminKey[Admin API Key] --\u003e UsageAPI[Usage API] AdminKey --\u003e CostAPI[Cost API] UsageAPI --\u003e Dashboard[모니터링 대시보드] CostAPI --\u003e Dashboard Dashboard --\u003e Alert[비용 알림 설정] Dashboard --\u003e Report[팀별 비용 리포트] Dashboard --\u003e Optimize[캐시 효율 분석]파트너 솔루션 직접 대시보드를 구축하지 않아도 Datadog, Grafana Cloud, CloudZero 같은 플랫폼이 기성 통합을 제공한다. Claude Code 사용자별 비용 분석이 필요하면 Claude Code Analytics API가 별도로 존재한다.\n빠른 링크 Claude Code 비용 관리 공식 문서 — 한국어 공식 가이드 Usage and Cost API 문서 — Admin API 상세 Claude Code Token Optimization (GitHub) — 커뮤니티 최적화 팁 모음 인사이트 Claude Code 토큰 최적화의 핵심은 \u0026ldquo;컨텍스트를 작게 유지하는 것\u0026quot;이라는 단순한 원칙으로 수렴된다. /clear로 작업 단위를 분리하고, CLAUDE.md를 Skills로 분산시키며, 모델을 작업 복잡도에 맞게 선택하는 — 이 세 가지만 실천해도 대부분의 비용 낭비를 막을 수 있다. 팀 레벨에서는 Usage \u0026amp; Cost API가 토큰 소비 패턴을 가시화해주므로, 캐싱 효율을 측정하고 예산 초과 알림을 설정하는 데 활용할 수 있다. 특히 2026년 2월에 추가된 Data Residency와 Fast Mode 추적 기능은 엔터프라이즈 환경에서 규정 준수와 성능 모니터링에 유용하다. 결국 좋은 습관(작업 전환 시 clear, 10~15회 대화마다 compact, 모호한 프롬프트 대신 구체적인 지시)이 어떤 설정보다 효과적인 비용 절감 도구다.\n","date":"2026-03-03T00:00:00+09:00","image":"/images/posts/2026-03-03-claude-code-token-optimization/cover.jpg","permalink":"/ko/posts/2026-03-03-claude-code-token-optimization/","title":"Claude Code 토큰 절약 가이드 — 비용을 80% 줄이는 실전 전략"},{"content":"개요 SonarSource에서 실험 중인 Kintsugi는 CLI 에이전트 사용자를 위한 Agentic Development Environment(ADE)다. IDE를 대체하는 것이 아니라 Claude Code 같은 CLI 에이전트를 시각적으로 보완하는 새로운 접근이다.\ngraph LR A[CLI AgentClaude Code] --\u003e|코드 생성| B[Kintsugi ADE] B --\u003e C{Sonar 가드레일} C --\u003e|통과| D[리뷰 승인] C --\u003e|이슈 발견| E[변경 요청] E --\u003e AKintsugi란 무엇인가 Kintsugi는 기존 IDE와 완전히 다른 개념의 개발 환경이다. 스스로를 **Agentic Development Environment(ADE)**라고 정의하며, 코드를 직접 작성하는 대신 AI 에이전트가 생성한 코드를 오케스트레이션하고 리뷰하는 데 초점을 맞춘다. 현재는 Claude Code만 지원하며, Gemini CLI와 Codex 지원도 계획 중이다.\n핵심 기능은 크게 세 가지다:\n멀티스레드 개발 — 여러 AI 세션을 병렬로 관리하면서 각 태스크의 상태를 시각적 큐로 추적할 수 있다. CLI에서 claude 명령어를 여러 터미널에 띄워 놓고 컨텍스트를 잃어버리는 문제를 해결한다. 플랜 리뷰와 변경 요청 — 에이전트가 제안한 구현 계획을 시각적으로 확인하고, 코드를 쓰기 전에 방향을 수정할 수 있다. Sonar 기반 가드레일 — SonarQube/SonarCloud의 정적 분석 엔진을 통합하여, AI가 생성한 코드의 보안 취약점과 품질 이슈를 매 단계마다 자동 검사한다. 프라이버시와 시스템 요구사항 프라이버시 측면도 인상적이다. Kintsugi는 로컬 데스크톱 앱으로, 소스 코드를 Sonar 서버로 전송하지 않는다. 익명 사용 데이터만 수집하며 설정에서 옵트아웃 가능하다.\n시스템 요구사항:\nmacOS 전용 (현재) Claude Code 2.0.57+ Git, Node.js, Java 17+ 아직 초기 단계라 초대 기반으로 접근을 열고 있으며, SonarCloud 계정과 연동하여 사용할 수 있다.\nCursor/Windsurf와의 차이 graph TD subgraph IDE 대체 접근 A[Cursor] --\u003e A1[에디터 내장 AI] B[Windsurf] --\u003e B1[에디터 내장 AI] end subgraph CLI 보완 접근 C[Kintsugi] --\u003e C1[CLI 에이전트 유지] C1 --\u003e C2[시각적 관리 레이어] C2 --\u003e C3[Sonar 품질 게이트] endCursor나 Windsurf가 에디터 자체에 AI를 내장하여 IDE를 대체하려는 반면, Kintsugi는 CLI 에이전트의 파워를 그대로 유지하면서 시각적 관리 레이어만 얹는다. \u0026ldquo;AI가 코드를 짜고, 사람은 리뷰한다\u0026quot;는 워크플로우에 SonarQube의 정적 분석 가드레일까지 자동으로 적용된다는 점이 차별점이다.\n인사이트 Kintsugi가 던지는 메시지는 명확하다 — AI가 생성한 코드도 품질과 보안을 보장해야 한다. CLI 에이전트의 생산성은 유지하면서 \u0026ldquo;리뷰 없이 머지되는 AI 코드\u0026quot;라는 리스크를 구조적으로 차단하려는 시도다. 개발자의 역할이 \u0026ldquo;코드 작성자\u0026quot;에서 \u0026ldquo;AI 오케스트레이터\u0026quot;로 이동하는 흐름에서, 그 오케스트레이션을 위한 전용 도구가 등장한 셈이다.\n","date":"2026-02-27T00:00:00+09:00","image":"/images/posts/2026-02-27-kintsugi-ade/cover.jpg","permalink":"/ko/posts/2026-02-27-kintsugi-ade/","title":"Kintsugi — SonarSource가 만든 Claude Code 전용 ADE"},{"content":"개요 한국투자증권의 KIS Developers 포털은 국내 증권사 중 가장 적극적으로 Open API를 제공하는 플랫폼이다. REST/WebSocket API는 물론, MCP(Model Context Protocol)를 통해 LLM에서 직접 트레이딩 API를 호출할 수 있는 인프라까지 갖추고 있다.\ngraph TD A[KIS Open API] --\u003e B[REST API] A --\u003e C[WebSocket API] A --\u003e D[AI 도구] B --\u003e B1[주문/계좌] B --\u003e B2[시세 조회] B --\u003e B3[종목 분석] C --\u003e C1[실시간 체결] C --\u003e C2[실시간 호가] D --\u003e D1[코딩도우미 MCP] D --\u003e D2[트레이딩 MCP] D --\u003e D3[GPTs 어시스턴트]API 구조 KIS Open API는 REST와 WebSocket 두 가지 방식으로 제공된다. 국내주식만 해도 주문/계좌, 기본시세, ELW, 업종/기타, 종목정보, 시세분석, 순위분석, 실시간시세로 세분화되어 있다. 해외주식, 선물옵션, 채권까지 포함하면 수백 개의 엔드포인트가 존재한다.\n인증은 OAuth 방식으로, appkey와 appsecret을 발급받아 접근토큰을 생성한다. WebSocket은 별도의 접속키를 발급받아 실시간 데이터를 수신한다. GitHub에 Python 샘플코드(REST, WebSocket)가 공개되어 있어 빠르게 프로토타이핑할 수 있다.\nMCP 연동 — LLM에서 직접 트레이딩 가장 눈에 띄는 것은 AI 도구 섹션이다. KIS Developers는 MCP를 공식 지원하며 두 가지를 제공한다:\n코딩도우미 MCP — API 사용법, 샘플코드 생성, 오류 해결을 LLM 대화로 처리 트레이딩 MCP — ChatGPT나 Claude에서 직접 주문, 시세 조회 등 트레이딩 기능 호출 24시간 GPTs 기반 1:1 지원 어시스턴트도 운영 중이다. 국내 증권사가 MCP를 공식 지원하는 사례는 아직 드물어, API 기반 자동매매를 구축하려는 개발자에게는 상당히 매력적인 환경이다.\n보안 유의사항 최근 KIS에서 올린 보안 관련 공지 두 가지가 있다:\nappkey/appsecret 노출 주의 — 발급받은 보안코드와 접근토큰을 외부에 공유하거나 웹에 게시하지 말 것. 이상 징후 발견 시 즉시 서비스(보안코드) 해지. WebSocket 무한 연결 차단 — 연결→즉시종료를 반복하거나, 구독 등록/해제를 무한 반복하는 비정상 패턴이 감지되면 IP 및 앱키가 일시 차단된다. 정상 패턴: 연결 → 종목 구독 → 데이터 수신 → 구독 해제 → 연결 종료\ngraph LR A[연결] --\u003e B[종목 구독] B --\u003e C[데이터 수신] C --\u003e D[구독 해제] D --\u003e E[연결 종료] style A fill:#4CAF50,color:#fff style E fill:#4CAF50,color:#fff인사이트 KIS Developers가 MCP를 공식 지원한다는 것은 금융 API와 LLM의 결합이 실험 단계를 넘어 프로덕션 레벨로 진입하고 있다는 신호다. API 문서 읽고 코드 짜는 과정 자체를 AI에게 위임할 수 있고, 나아가 트레이딩 의사결정까지 LLM 파이프라인에 통합할 수 있는 구조가 갖춰지고 있다. 다만 보안코드 관리와 비정상 호출 패턴에 대한 주의는 필수적이다 — 자동화할수록 예외 처리의 중요성은 오히려 커진다.\n","date":"2026-02-27T00:00:00+09:00","image":"/images/posts/2026-02-27-kis-open-api-mcp/cover.jpg","permalink":"/ko/posts/2026-02-27-kis-open-api-mcp/","title":"KIS Developers — 한국투자증권 Open API와 MCP 트레이딩"},{"content":"개요 VS Code Extension을 Marketplace에 배포하려면 @vscode/vsce 패키지를 사용한다. Azure DevOps PAT 발급부터 Publisher 생성, 패키징, 배포까지의 전체 워크플로우를 정리한다.\ngraph LR A[Extension 개발] --\u003e B[vsce 설치] B --\u003e C[Azure DevOps PAT 발급] C --\u003e D[Publisher 생성] D --\u003e E[vsce login] E --\u003e F{배포 방식} F --\u003e|직접| G[vsce publish] F --\u003e|패키지| H[vsce package → .vsix]1단계: vsce 설치 vsce는 VS Code Extension의 패키징과 배포를 담당하는 CLI 도구다.\nnpm install -g @vscode/vsce 주요 커맨드 세 가지:\nvsce login — 퍼블리셔 계정으로 로그인 vsce publish — Marketplace에 직접 배포 vsce package — .vsix 정적 파일로 패키징 2단계: Azure DevOps PAT 발급 VS Code Marketplace는 Azure DevOps를 통해 인증한다.\nAzure DevOps에 가입/로그인 Personal Access Token(PAT) 생성 중요: VS Code Marketplace에 대한 Manage 권한을 반드시 부여 발급된 토큰은 다시 조회할 수 없으므로 안전하게 보관 3단계: Publisher 생성 및 로그인 VS Code Marketplace에서 Publish extensions → Create publisher Publisher 이름 설정 후 생성 CLI에서 로그인: vsce login \u0026lt;publisherName\u0026gt; # PAT 입력 프롬프트가 나타남 4단계: package.json 필수 필드 { \u0026#34;name\u0026#34;: \u0026#34;my-extension\u0026#34;, \u0026#34;displayName\u0026#34;: \u0026#34;My Extension\u0026#34;, \u0026#34;publisher\u0026#34;: \u0026#34;my-publisher\u0026#34;, \u0026#34;version\u0026#34;: \u0026#34;0.0.1\u0026#34;, \u0026#34;engines\u0026#34;: { \u0026#34;vscode\u0026#34;: \u0026#34;^1.84.0\u0026#34; } } 위 필드 중 하나라도 누락되면 배포가 실패한다.\n5단계: 배포 # Marketplace에 직접 배포 vsce publish # 또는 .vsix 파일로 패키징 후 수동 배포 vsce package vsce package로 생성된 .vsix 파일은 Marketplace 웹에서 수동 업로드하거나, code --install-extension my-extension.vsix로 로컬 설치할 수 있다.\n인사이트 Azure DevOps와 VS Code Marketplace가 별개 시스템이라 첫 설정 시 혼란스러울 수 있다. 핵심은 PAT 발급(Azure DevOps) → Publisher 생성(Marketplace) → 로그인(vsce CLI) → 배포 순서다. 한번 세팅해두면 이후에는 vsce publish만으로 원클릭 배포가 가능하고, CI/CD 파이프라인에 통합하여 태그 푸시 시 자동 배포도 구성할 수 있다.\n","date":"2026-02-27T00:00:00+09:00","image":"/images/posts/2026-02-27-vsce-extension-deploy/cover.jpg","permalink":"/ko/posts/2026-02-27-vsce-extension-deploy/","title":"VS Code Extension 배포 — vsce 워크플로우 정리"},{"content":"개요 AI 서비스의 dev 환경 인프라를 관리했다. ECS 서비스 업데이트, EC2 인스턴스 확인, ElastiCache(Valkey) 모니터링, IAM 액세스 키 생성, 그리고 AWS CLI 자격 증명 설정까지 일련의 DevOps 작업을 수행했다.\nECS 서비스 관리 dev 환경 ECS 클러스터에서 AI 서비스의 태스크 상태 확인, 헬스 체크, 서비스 업데이트를 진행했다. ECS 콘솔에서 확인한 항목들:\nService tasks: 실행 중인 태스크의 컨테이너 상태와 로그 Health and metrics: 서비스 헬스 체크 결과와 CPU/메모리 메트릭 Service update: 태스크 정의 업데이트 후 롤링 배포 graph TD A[\"ECS Clusterdev-cluster\"] --\u003e B[\"Serviceai-service\"] B --\u003e C[\"Task Definition\"] B --\u003e D[\"Running Tasks\"] B --\u003e E[\"Health Check\"] D --\u003e F[\"Container: app\"] F --\u003e G[\"EC2 Instance\"] F --\u003e H[\"ElastiCache / Valkey\"]ECS Express Mode도 확인했는데, 이는 간단한 서비스를 빠르게 배포할 수 있는 모드다.\nEC2 인스턴스와 ElastiCache dev 환경에서 운영 중인 EC2 인스턴스들의 상태를 확인했다. ElastiCache에서는 Valkey(Redis 호환 인메모리 데이터스토어) 클러스터를 모니터링했다. Valkey는 Redis의 오픈소스 포크로, AWS가 공식 지원하는 인메모리 캐시 엔진이다.\nIAM 액세스 키 생성과 CLI 설정 개발용 IAM 사용자의 보안 자격 증명 탭에서 새 액세스 키를 생성했다. 이후 AWS CLI 설정 문서를 참조해 aws configure로 로컬 환경을 설정했다.\nAWS CLI의 자격 증명 우선순위:\ngraph TD A[\"1. 커맨드라인 옵션--profile, --region\"] --\u003e B[\"2. 환경 변수AWS_ACCESS_KEY_ID 등\"] B --\u003e C[\"3. CLI 자격 증명 파일~/.aws/credentials\"] C --\u003e D[\"4. CLI 구성 파일~/.aws/config\"] D --\u003e E[\"5. 컨테이너 자격 증명ECS 태스크 역할\"] E --\u003e F[\"6. EC2 인스턴스 프로파일IAM 역할\"]aws configure 실행 시 네 가지를 입력한다:\nAWS Access Key ID AWS Secret Access Key Default region name (예: ap-northeast-2) Default output format (json, yaml, text, table) 설정 결과는 ~/.aws/credentials(자격 증명)와 ~/.aws/config(리전, 출력 형식)에 각각 저장된다. 프로필을 여러 개 설정하려면 aws configure --profile 프로필명을 사용한다.\n인사이트 오늘의 AWS 작업은 일상적인 DevOps 루틴이지만, 몇 가지 포인트가 있다. ECS 서비스 업데이트는 콘솔에서 직접 했지만, 반복적인 작업이라면 CI/CD 파이프라인이나 Terraform으로 자동화하는 것이 맞다. IAM 액세스 키 생성 후 CLI 설정까지의 흐름은 새로운 개발 환경 세팅 시 항상 거치는 과정인데, 자격 증명 우선순위를 정확히 이해하고 있어야 환경변수와 파일 설정이 충돌할 때 디버깅이 쉬워진다. Valkey(Redis 포크)를 ElastiCache에서 관리형으로 사용하는 것은 라이선스 변경 이후의 실용적인 선택이다.\n","date":"2026-02-26T00:00:00+09:00","image":"/images/posts/2026-02-26-aws-ecs-cli-setup/cover.jpg","permalink":"/ko/posts/2026-02-26-aws-ecs-cli-setup/","title":"AWS ECS 서비스 운영과 CLI 자격 증명 설정"},{"content":"개요 Claude Code는 LLM이 도구를 \u0026ldquo;선택\u0026quot;해서 실행하는 구조다. 하지만 특정 작업은 선택이 아니라 항상 실행되어야 할 때가 있다 — 파일 저장 후 포맷팅, 명령어 로깅, 프로덕션 파일 수정 차단 같은 것들. Claude Code 훅은 이런 요구를 충족하는 라이프사이클 셸 명령 시스템이다.\n훅 이벤트 종류 Claude Code는 워크플로우의 다양한 지점에서 실행되는 10가지 훅 이벤트를 제공한다:\ngraph LR A[\"세션 시작\"] --\u003e|SessionStart| B[\"사용자 입력\"] B --\u003e|UserPromptSubmit| C[\"Claude 처리\"] C --\u003e|PreToolUse| D[\"도구 실행\"] D --\u003e|PostToolUse| E[\"결과 반환\"] C --\u003e|PermissionRequest| F[\"권한 확인\"] E --\u003e G[\"응답 완료\"] G --\u003e|Stop| H[\"세션 종료\"] H --\u003e|SessionEnd| I[\"종료\"] C --\u003e|Notification| J[\"알림\"] C --\u003e|PreCompact| K[\"컴팩트\"] D --\u003e|SubagentStop| L[\"서브에이전트 완료\"] 이벤트 시점 제어 PreToolUse 도구 호출 전 차단 가능 PostToolUse 도구 호출 후 피드백 제공 PermissionRequest 권한 대화상자 허용/거부 UserPromptSubmit 프롬프트 제출 시 전처리 Notification 알림 발생 시 커스텀 알림 Stop 응답 완료 시 후처리 SubagentStop 서브에이전트 완료 후처리 PreCompact 컴팩트 실행 전 전처리 SessionStart 세션 시작/재개 초기화 SessionEnd 세션 종료 정리 실전 예제: Bash 명령어 로깅 가장 기본적인 훅 — 모든 셸 명령을 파일에 기록한다. PreToolUse 이벤트에 Bash 매처를 걸고, jq로 도구 입력을 파싱한다:\n{ \u0026#34;hooks\u0026#34;: { \u0026#34;PreToolUse\u0026#34;: [ { \u0026#34;matcher\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;hooks\u0026#34;: [ { \u0026#34;command\u0026#34;: \u0026#34;jq -r \u0026#39;\\\u0026#34;\\\\(.tool_input.command) - \\\\(.tool_input.description // \\\u0026#34;No description\\\u0026#34;)\\\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.claude/bash-command-log.txt\u0026#34; } ] } ] } } 설정은 /hooks 슬래시 명령으로 접근하며, User settings(전역) 또는 Project settings(프로젝트별)로 저장 범위를 선택할 수 있다.\n활용 패턴 자동 포맷팅: PostToolUse에서 파일 확장자별로 포맷터를 실행한다. .ts 파일이면 prettier, .go 파일이면 gofmt, .py 파일이면 black을 자동 적용하면 Claude가 생성하는 코드가 항상 프로젝트 스타일을 따른다.\n파일 보호: PreToolUse에서 특정 경로 패턴(예: production/, .env)에 대한 수정을 차단한다. LLM이 실수로 프로덕션 설정을 건드리는 것을 원천적으로 방지할 수 있다.\n커스텀 알림: Notification 이벤트에 시스템 알림, Slack 웹훅, 소리 재생 등을 연결한다. Claude가 입력을 기다리거나 작업이 완료되었을 때 원하는 방식으로 알림을 받을 수 있다.\n코드 품질 피드백: PostToolUse에서 lint 결과를 Claude에게 돌려주면, Claude가 자동으로 수정 사항을 반영한다. 프롬프트 지시사항이 아닌 코드 레벨의 강제다.\n보안 고려사항 훅은 현재 환경의 자격 증명으로 에이전트 루프 중 자동 실행된다. 이것은 강력한 기능이지만 동시에 위험하다 — 악의적인 훅 코드가 환경변수를 읽어 외부로 전송하거나, 파일을 삭제하거나, 임의의 명령을 실행할 수 있다. 반드시 훅 구현을 등록 전에 검토하고, 프로젝트 레벨 훅은 .claude/settings.json의 변경사항을 코드 리뷰에 포함시켜야 한다.\n인사이트 훅의 핵심 가치는 \u0026ldquo;제안을 코드로 변환\u0026quot;하는 것이다. 프롬프트에 \u0026ldquo;항상 prettier를 실행해줘\u0026quot;라고 써도 LLM은 가끔 잊는다. 하지만 훅으로 등록하면 100% 실행된다. 이것은 LLM 기반 개발 도구의 근본적인 한계 — 비결정론적 행동 — 를 결정론적 셸 명령으로 보완하는 패턴이다. PreToolUse로 차단, PostToolUse로 후처리, Stop으로 마무리라는 세 가지 포인트만 잘 활용하면 Claude Code의 동작을 프로젝트 요구사항에 정확히 맞출 수 있다.\n","date":"2026-02-26T00:00:00+09:00","image":"/images/posts/2026-02-26-claude-code-hooks/cover.jpg","permalink":"/ko/posts/2026-02-26-claude-code-hooks/","title":"Claude Code Hooks — 에이전트 동작의 결정론적 제어"},{"content":"개요 이전 포스트에서 Gemini 3의 모델 라인업, 가격, Thought Signatures, thinking_level/media_resolution 파라미터, 이미지 생성(Nano Banana Pro), Flash Preview 버그까지 다뤘다. 오늘은 Gemini 3 Developer Guide에서 아직 정리하지 않은 Function Calling strict validation, Structured Outputs with tools, Code Execution with images, Multimodal function responses, OpenAI 호환 API 기능을 살펴본다.\n이전 포스트: Gemini 3 이미지 생성 API + Mermaid.js, Gemini 3 Flash Preview 무한 루프 버그\nGemini 3.1 Pro Preview 발표 Gemini 3.1 Pro가 프리뷰로 공개되었다. 3 Pro 대비 성능, 행동, 지능 개선이 이루어졌으며, 모델 ID는 gemini-3.1-pro-preview다. 가격과 컨텍스트 윈도우(1M/64k)는 3 Pro와 동일하다. Google AI Studio에서 무료로 시도할 수 있다.\nFunction Calling — Strict Validation Gemini 3에서 Function Calling에 strict validation이 도입되었다. 이전 모델에서는 도구 호출 시 스키마를 느슨하게 검증했지만, 이제 이미지 생성/편집과 Function Calling 모드에서는 Thought Signatures를 포함한 엄격한 검증이 적용된다.\n두 가지 호출 패턴을 지원한다:\ngraph TD A[\"Function Calling\"] --\u003e B[\"Sequential멀티스텝\"] A --\u003e C[\"Parallel동시 실행\"] B --\u003e B1[\"1. 모델이 tool_call 반환\"] B1 --\u003e B2[\"2. 클라이언트가 실행\"] B2 --\u003e B3[\"3. 결과를 모델에 피드백\"] B3 --\u003e B4[\"4. 모델이 다음 tool_call 또는 최종 응답\"] C --\u003e C1[\"1. 모델이 여러 tool_call 동시 반환\"] C1 --\u003e C2[\"2. 클라이언트가 병렬 실행\"] C2 --\u003e C3[\"3. 모든 결과를 모델에 피드백\"] C3 --\u003e C4[\"4. 모델이 최종 응답\"]Sequential (멀티스텝): 모델이 한 번에 하나의 도구를 호출하고, 결과를 받은 뒤 다음 도구를 호출한다. 이전 도구의 결과에 따라 다음 행동이 달라지는 에이전트 워크플로우에 적합하다.\nParallel: 모델이 독립적인 여러 도구 호출을 한 번에 반환한다. 클라이언트가 병렬로 실행하고 결과를 모아서 피드백하면 모델이 종합 응답을 생성한다. 지연 시간을 크게 줄일 수 있다.\n주의사항: 텍스트/스트리밍과 인컨텍스트 추론(In-Context Reasoning)에서는 strict validation이 적용되지 않는다. 즉, 이미지 생성 모드에서는 Thought Signature 없이 도구를 호출하면 400 에러가 발생하지만, 일반 텍스트 모드에서는 기존처럼 동작한다.\nStructured Outputs with Tools Function Calling과 Structured Output을 결합할 수 있다. 도구 정의 시 응답 스키마를 지정하면, 모델이 도구 호출 결과를 구조화된 JSON으로 반환하도록 강제할 수 있다. 이전에는 모델이 자유 형식으로 응답했는데, 이제 프로덕션 파이프라인에서 파싱 에러 없이 안정적으로 처리할 수 있다.\nCode Execution with Images Gemini 3의 코드 실행 기능이 이미지 출력을 지원한다. 모델이 Python 코드를 실행하고, matplotlib 같은 라이브러리로 생성한 차트나 그래프를 이미지로 반환할 수 있다. 데이터 분석 → 시각화 → 설명이라는 파이프라인을 단일 API 호출로 처리할 수 있다는 점이 핵심이다.\ngraph LR A[\"프롬프트:'이 데이터로 차트 그려줘'\"] --\u003e B[\"Gemini 3\"] B --\u003e C[\"Python 코드 생성\"] C --\u003e D[\"코드 실행(matplotlib)\"] D --\u003e E[\"차트 이미지 반환\"] E --\u003e F[\"이미지 + 설명 텍스트\"]Multimodal Function Responses 도구 호출의 결과로 텍스트뿐 아니라 이미지, 오디오 등 멀티모달 데이터를 반환할 수 있다. 예를 들어 \u0026ldquo;이 주소의 위성 사진을 가져와\u0026quot;라는 도구 호출 결과로 실제 이미지를 반환하면, 모델이 이미지를 분석해서 종합 응답을 생성한다. 에이전트가 외부 API에서 가져온 비텍스트 데이터를 모델의 멀티모달 이해 능력과 결합할 수 있는 것이다.\nOpenAI 호환 API Gemini 3는 OpenAI 호환 엔드포인트를 제공한다. 기존에 OpenAI API를 사용하는 코드베이스에서 모델명과 API 키만 바꾸면 Gemini 3를 사용할 수 있다. 마이그레이션 비용을 최소화하는 전략적 선택이다.\nGemini 2.5에서 마이그레이션 기존 Gemini 2.5 사용자가 3으로 넘어갈 때 주의할 점:\n모델 ID 변경 (gemini-2.5-* → gemini-3-*-preview) Thought Signatures가 새로 도입됨 — Function Calling에서 strict validation 적용 temperature 기본값 1.0에 최적화 — 낮은 temperature 코드가 있다면 반드시 제거 thinking_level과 thinking_budget 동시 사용 불가 (400 에러) 인사이트 Gemini 3의 새 기능을 보면 Google이 \u0026ldquo;에이전트 파이프라인의 신뢰성\u0026quot;에 집중하고 있음을 알 수 있다. Function Calling의 strict validation, Structured Outputs, Parallel 호출 패턴은 모두 프로덕션 에이전트에서 발생하는 파싱 에러와 지연 문제를 해결하는 기능이다. Code Execution with images와 Multimodal function responses는 텍스트 중심이던 도구 호출을 멀티모달로 확장한다. OpenAI 호환 API는 경쟁 모델 간 전환 비용을 낮추는 전략인데, 이는 Claude의 OpenAI 호환 모드와도 비슷한 방향이다. 모델 간 API 호환성이 높아질수록 개발자는 벤더 종속 없이 성능과 비용 기준으로 모델을 선택할 수 있게 된다.\n","date":"2026-02-26T00:00:00+09:00","image":"/images/posts/2026-02-26-gemini-3-function-calling/cover.jpg","permalink":"/ko/posts/2026-02-26-gemini-3-function-calling/","title":"Gemini 3 — Function Calling, Structured Outputs, Code Execution 새 기능 정리"},{"content":"개요 자연어로 주식 시세를 조회하고 모의투자 주문까지 넣을 수 있는 웹앱, trading-agent를 개발 중이다. 한국투자증권(KIS) OpenAPI를 MCP(Model Context Protocol)로 감싸고, Claude API가 도구 호출을 결정하는 구조다. 오늘은 이 프로젝트의 아키텍처와 PR #1에서 추가한 CLAUDE.md의 역할을 정리한다.\n아키텍처 전체 시스템은 세 개의 서비스로 구성된다. React 프론트엔드(Vite, :5173), FastAPI 백엔드(:8000), 그리고 KIS Trading MCP Server(SSE, :3000)다.\nReact (Vite, :5173) \u0026lt;--\u0026gt; FastAPI (:8000) \u0026lt;--\u0026gt; Claude API | MCP Client (fastmcp) | KIS Trading MCP Server (SSE, :3000) | KIS OpenAPI (paper trading) 사용자가 \u0026ldquo;삼성전자 현재가 알려줘\u0026quot;라고 입력하면 다음 플로우로 처리된다:\nsequenceDiagram participant User as 사용자 participant React as React UI participant API as FastAPI participant Claude as Claude API participant MCP as MCP Server participant KIS as KIS OpenAPI User-\u003e\u003eReact: \"삼성전자 현재가 알려줘\" React-\u003e\u003eAPI: POST /chat API-\u003e\u003eClaude: 메시지 + MCP 도구 정의 Claude-\u003e\u003eAPI: tool_use: get_stock_price API-\u003e\u003eMCP: fastmcp 도구 호출 MCP-\u003e\u003eKIS: REST API 요청 KIS--\u003e\u003eMCP: 주가 데이터 MCP--\u003e\u003eAPI: 도구 결과 API-\u003e\u003eClaude: 도구 결과 피드백 Claude--\u003e\u003eAPI: \"삼성전자 현재가는...\" API--\u003e\u003eReact: SSE 스트리밍 React--\u003e\u003eUser: 응답 표시핵심은 FastAPI가 Claude API를 호출할 때 MCP 도구 정의를 함께 전달한다는 것이다. Claude가 사용자 의도를 파악해 적절한 도구 호출을 결정하면, FastAPI가 MCP Client(fastmcp)를 통해 실행하고 결과를 다시 Claude에게 피드백한다. 최종 응답은 SSE로 React UI에 스트리밍된다.\n기술 스택과 설정 필수 요구사항은 Python 3.12+(uv), Node.js 22+, Anthropic API 키, KIS 모의투자 인증 정보다. 기본 모델은 claude-sonnet-4-5-20250929을 사용하며, make install \u0026amp;\u0026amp; make start로 세 서비스를 동시에 기동한다.\n주요 환경변수 구성:\n변수 설명 ANTHROPIC_API_KEY Anthropic API 키 MCP_SERVER_URL MCP 서버 SSE 엔드포인트 (기본: http://localhost:3000/sse) CLAUDE_MODEL 사용할 Claude 모델 KIS_PAPER_APP_KEY KIS 모의투자 앱 키 KIS_PAPER_APP_SECRET KIS 모의투자 앱 시크릿 KIS_PAPER_STOCK 모의투자 계좌번호 (8자리) make 타겟으로 install, start, 개별 서비스 시작 등이 제공되어 개발 편의성을 높였다.\nCLAUDE.md — Claude Code를 위한 프로젝트 가이드 PR #1에서 CLAUDE.md를 추가했다. 이 파일은 Claude Code가 프로젝트에 진입할 때 가장 먼저 읽는 컨텍스트 문서다. 빌드 명령어, 아키텍처 개요, 개발 컨벤션을 정리해두면 Claude Code가 코드 수정 시 일관성을 유지할 수 있다.\ngraph TD A[\"Claude Code 세션 시작\"] --\u003e B[\"CLAUDE.md 읽기\"] B --\u003e C[\"프로젝트 구조 파악\"] C --\u003e D[\"빌드/테스트 명령어 확인\"] D --\u003e E[\"개발 컨벤션 준수하며 코딩\"] B --\u003e F[\"아키텍처 이해\"] F --\u003e G[\"MCP 도구 구조 파악\"] G --\u003e ECLAUDE.md를 두는 것은 단순한 문서화가 아니라, AI 에이전트와의 협업 인터페이스를 설계하는 것이다. 프로젝트별로 빌드 명령어가 다르고, 테스트 컨벤션이 다르고, 코드 스타일이 다른데, 이걸 매번 대화로 설명하는 대신 파일 하나로 정의해두면 Claude Code의 첫 번째 행동부터 정확해진다.\n인사이트 이 프로젝트에서 MCP의 가치가 명확히 드러난다. KIS OpenAPI는 REST 기반이지만, MCP Server로 감싸면 Claude가 자연어 의도에서 바로 도구 호출로 넘어갈 수 있다. 중요한 건 FastAPI가 MCP Client와 Claude API 사이의 오케스트레이터 역할을 한다는 점이다 — Claude가 \u0026ldquo;어떤 도구를 호출할지\u0026rdquo; 결정하고, FastAPI가 \u0026ldquo;실제로 실행\u0026quot;하는 분리가 깔끔하다. 모의투자(paper trading)로 시작해서 실제 API 전환도 환경변수 하나로 가능한 구조이며, make start로 전체 스택을 한 번에 올릴 수 있는 DX도 중요한 설계 포인트다.\n","date":"2026-02-26T00:00:00+09:00","image":"/images/posts/2026-02-26-kis-trading-agent-mcp/cover.jpg","permalink":"/ko/posts/2026-02-26-kis-trading-agent-mcp/","title":"KIS Trading Agent — MCP 기반 LLM 주식 트레이딩 아키텍처"},{"content":"개요 VS Code 확장 생태계가 전환기를 맞고 있다. 한쪽에서는 Microsoft의 공식 Webview UI Toolkit이 deprecated되어 아카이브되었고, 다른 한쪽에서는 AI 코딩 어시스턴트가 필수 확장 카테고리로 자리 잡았다. 오늘은 이 두 흐름을 살펴본다.\nWebview UI Toolkit의 종료 Issue #561에서 hawkticehurst가 종료를 발표했다. 2.1k 스타, 157 포크의 프로젝트가 2025년 1월 6일 아카이브되었다.\n종료 원인은 핵심 의존성 FAST Foundation의 deprecation이다. 2024년 5월 FAST 프로젝트가 재편(re-alignment)을 발표하면서 여러 코어 패키지가 deprecated 목록에 올랐고, Webview UI Toolkit의 기반 기술이 사라진 것이다. 유일한 해결책은 FAST Element(저수준 웹 컴포넌트 라이브러리)로 완전 재작성이었지만 리소스가 배정되지 않았다.\ngraph TD A[\"FAST Foundationdeprecated (2024.05)\"] --\u003e B[\"Webview UI Toolkit기반 기술 상실\"] B --\u003e C{\"재작성?\"} C --\u003e|\"리소스 미배정\"| D[\"2025.01 아카이브\"] C --\u003e|\"대안\"| E[\"FAST Element로완전 재작성 필요\"] D --\u003e F[\"기존 사용자 대안\"] F --\u003e G[\"VS Code CSS 변수직접 활용\"] F --\u003e H[\"Svelte/React 기반자체 컴포넌트\"] F --\u003e I[\"@vscode/codicons아이콘만 사용\"]이 라이브러리가 제공했던 가치는 세 가지였다:\nVS Code 디자인 언어를 따르는 UI 컴포넌트(버튼, 드롭다운, 데이터 그리드 등) 에디터 테마 자동 지원 (다크/라이트 모드 자동 전환) 웹 컴포넌트 기반이라 React, Vue, Svelte 등 프레임워크에 구애받지 않음 이제 이 역할을 대체할 공식 도구가 없다. VS Code의 CSS 변수(--vscode-button-background, --vscode-input-border 등)를 직접 사용하거나, @vscode/codicons로 아이콘만 가져오고 나머지는 자체 구현해야 한다.\n2026년 추천 확장 — AI가 별도 카테고리가 되다 Builder.io의 Best VS Code Extensions for 2026 리뷰에서 눈에 띄는 변화는 AI 확장이 독립 카테고리로 분리되었다는 점이다. 2025년이 AI 에이전트의 해였고, 2026년에는 대부분의 개발자가 이미 Cursor나 Claude Code 같은 AI IDE를 사용한다는 전제로 글이 작성되었다.\n추천된 AI 확장 세 가지:\nFusion: 비주얼 편집 + AI 코드 수정을 실제 repo에서 PR로 생성 Claude Code: 컨텍스트 인식 기반 IDE 내 코딩, 509만+ 설치 Sourcegraph Cody: 코드 그래프 기반 크로스 리포 컨텍스트 그 외 주요 추천:\nThunder Client: REST 클라이언트 (Postman 대체) Error Lens: 인라인 에러/경고 표시 Pretty TypeScript Errors: TS 진단 메시지 가독성 향상 TODO Tree: TODO/FIXME 한 곳에 수집 Git Graph: 커밋 히스토리 시각화 CSS Peek: 마크업/JSX에서 스타일 정의로 바로 점프 Import Cost: 임포트 번들 사이즈 표시 확장 선택 기준으로 제시된 체크리스트도 실용적이다: 누가 만들었는지(verified publisher, 오픈소스), 최근 업데이트 여부, 성능 영향과 권한 요구사항 확인. 무거운 확장은 특정 워크스페이스에서만 설치하고, node_modules 같은 폴더를 제외하는 팁도 포함되어 있다.\nClaude Code for VS Code VS Code Marketplace에서 Claude Code는 509만 설치를 기록 중이다. Pro, Max, Team, Enterprise 구독 또는 종량제로 사용 가능하며, 터미널 기반 확장과 IDE 통합 두 가지 모드를 모두 지원한다. 별도 Homebrew로 데스크톱 앱을 설치할 수도 있다(brew install --cask claude-code).\ngraph TD A[\"Claude Code\"] --\u003e B[\"VS Code 확장509만+ 설치\"] A --\u003e C[\"터미널 CLI\"] A --\u003e D[\"데스크톱 앱Homebrew\"] B --\u003e E[\"IDE 내 코딩\"] C --\u003e F[\"터미널 워크플로우\"] D --\u003e G[\"독립 실행\"] E \u0026 F \u0026 G --\u003e H[\"동일한 Claude 모델Pro/Max/Team/Enterprise\"]인사이트 VS Code 확장 생태계의 두 가지 흐름이 교차하고 있다. Webview UI Toolkit 같은 기존 인프라가 의존성 체인 붕괴(FAST Foundation → Toolkit)로 종료되는 반면, AI 코딩 어시스턴트는 \u0026ldquo;없으면 안 되는\u0026rdquo; 필수 카테고리로 성장했다. 웹뷰 기반 확장을 개발한다면 이제 자체 UI 컴포넌트를 구축하거나 경량 프레임워크를 선택해야 하는데, 역설적으로 이때 Claude Code 같은 AI 도구가 보일러플레이트 생성을 도와줄 수 있다. 확장 생태계의 빈자리를 AI가 채우는 구도인 셈이다.\n","date":"2026-02-26T00:00:00+09:00","image":"/images/posts/2026-02-26-vscode-ecosystem-2026/cover.jpg","permalink":"/ko/posts/2026-02-26-vscode-ecosystem-2026/","title":"VS Code 확장 생태계 2026: Webview UI Toolkit 종료부터 AI 확장까지"},{"content":"개요 juehang/vscode-mcp-server는 VS Code의 내장 편집 기능(파일 조작, 심볼 검색, 진단 등)을 MCP 프로토콜로 노출하는 확장이다. Claude Desktop이나 다른 MCP 클라이언트가 VS Code에서 직접 코딩할 수 있게 해준다. Serena에서 영감을 받았지만, VS Code의 네이티브 API를 활용한다는 점이 차별화된다.\n아키텍처 확장은 Streamable HTTP API(http://localhost:3000/mcp)를 제공하며, SSE가 아닌 새로운 MCP 전송 방식을 사용한다. Claude Desktop에서는 npx mcp-remote@next로 연결한다:\n{ \u0026#34;mcpServers\u0026#34;: { \u0026#34;vscode-mcp-server\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;npx\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;mcp-remote@next\u0026#34;, \u0026#34;http://localhost:3000/mcp\u0026#34;] } } } graph LR A[\"Claude DesktopMCP Client\"] --\u003e|\"Streamable HTTP\"| B[\"vscode-mcp-server:3000/mcp\"] B --\u003e C[\"VS Code API\"] C --\u003e D[\"워크스페이스 파일\"] C --\u003e E[\"Language Server\"] C --\u003e F[\"터미널\"]MCP 도구 목록 다섯 카테고리, 총 7개 이상의 도구를 제공한다:\nFile Tools — 파일 시스템 조작\nlist_files_code: 디렉토리 파일 목록 조회 read_file_code: 파일 내용 읽기 create_file_code: 파일 생성 (overwrite 옵션) Edit Tools — 코드 수정\nreplace_lines_code: 특정 라인 범위 교체. 원본 내용과 정확히 일치해야 동작 Diagnostics Tools — 코드 진단\nget_diagnostics_code: Language Server의 진단 결과(에러, 경고) 반환 Symbol Tools — 코드 탐색\nsearch_symbols_code: 워크스페이스 전체에서 함수/클래스 검색 get_document_symbols_code: 파일 내 심볼 아웃라인 Shell Tools — 터미널 명령 실행\nClaude Code와의 차이점 Claude Code도 파일 읽기/쓰기를 지원하지만, vscode-mcp-server는 VS Code 고유 기능을 노출한다는 점이 다르다. Language Server 기반의 심볼 검색, 문서 아웃라인, 코드 진단은 Claude Code의 grep/ripgrep 기반 검색보다 의미론적으로 정확하다. 두 도구를 조합하면 Claude Code의 강력한 파일 조작 + VS Code의 의미론적 코드 이해를 함께 활용할 수 있다.\n권장 워크플로우는 프로젝트 README에서 제시하는 것처럼:\nlist_files_code로 프로젝트 구조 파악 search_symbols_code로 수정 대상 함수/클래스 찾기 read_file_code로 현재 내용 확인 소규모 수정은 replace_lines_code, 대규모 변경은 create_file_code with overwrite 매번 수정 후 get_diagnostics_code로 에러 확인 보안 주의사항 Shell Tools가 포함되어 있어 셸 명령 실행이 가능하다. MCP 인증 스펙이 아직 확정되지 않아 인증이 구현되지 않은 상태이므로, 포트가 외부에 노출되지 않도록 주의해야 한다. 신뢰할 수 있는 MCP 클라이언트만 연결하는 것이 권장된다.\n인사이트 이 확장은 MCP 생태계가 \u0026ldquo;도구 표준화\u0026quot;를 넘어 \u0026ldquo;환경 통합\u0026quot;으로 진화하고 있음을 보여준다. 기존에는 LLM이 파일을 직접 읽고 쓰는 방식이었지만, vscode-mcp-server를 통하면 Language Server의 타입 체크, 심볼 인덱싱, 진단 기능까지 활용할 수 있다. 특히 get_diagnostics_code를 매번 수정 후 호출하는 패턴은 \u0026ldquo;코드를 쓰고 → 컴파일러에게 물어보고 → 수정하는\u0026rdquo; 인간 개발자의 워크플로우를 LLM에게도 적용하는 것이다. MCP 인증 스펙이 확정되면 더 안전하게 활용할 수 있을 것이다.\n","date":"2026-02-26T00:00:00+09:00","image":"/images/posts/2026-02-26-vscode-mcp-server/cover.jpg","permalink":"/ko/posts/2026-02-26-vscode-mcp-server/","title":"vscode-mcp-server — VS Code 편집 기능을 LLM에 노출하는 MCP 서버"},{"content":"개요 gemini-3-flash-preview를 프로덕션에서 사용 중이라면 지금 당장 방어 코드를 추가해야 할 버그가 보고됐다. 동시 요청 100개 이상을 보낼 때 3~5%의 확률로 모델이 무한 추론 루프에 빠져 maxOutputTokens를 전부 소진하고, 내부 추론 과정을 최종 응답으로 반환하는 두 가지 장애가 동시에 발생한다. 이전 포스트에서 Gemini 3의 Thought Signatures와 thinking_level 파라미터를 정리했는데, 이 버그는 정확히 그 Thinking 메커니즘의 stop condition 오류다.\n이전 포스트 참고: Gemini 3 이미지 생성 API, Thought Signatures, thinking_level, media_resolution 파라미터 → 2026-02-20 포스트\n버그 상세: 무슨 일이 벌어지는가 트리거 조건 비트 연산, 수학적 검증, 논리 퍼즐 등 단계적 증명이 필요한 문제에서 발생한다. 예시 프롬프트: \u0026ldquo;Bitwise Toggle algorithm\u0026rdquo; 같은 유형.\n모델이 정답을 바로 도출하지 않고 특정 정수값에 대해 검증을 시작하면 수렴하지 않는다:\nn = 67108863 검증... 맞음 n = 67108864 검증... 맞음 n = 134217727 검증... 맞음 n = 134217728 검증... (계속) 2배씩 증가하는 값을 순차적으로 검증하는 루프가 끝없이 이어지다 토큰 한도에 걸린다.\nAPI 응답의 두 가지 동시 실패 { \u0026#34;response\u0026#34;: { \u0026#34;usageMetadata\u0026#34;: { \u0026#34;totalTokenCount\u0026#34;: 16233, \u0026#34;thoughtsTokenCount\u0026#34;: 15356, // ← 전체 토큰의 94.6%가 내부 추론에 소진됨 \u0026#34;candidatesTokenCount\u0026#34;: 640 }, \u0026#34;candidates\u0026#34;: [{ \u0026#34;content\u0026#34;: { \u0026#34;parts\u0026#34;: [ { \u0026#34;text\u0026#34;: \u0026#34;**Algorithm for Bitwise Toggle**\\n\\nOkay, here\u0026#39;s my line of thinking...\u0026#34;, \u0026#34;thought\u0026#34;: true // ← 정상적인 내부 추론 (숨겨져야 함) }, { // ⚠️ BUG: 내부 추론 루프인데 thought: true 플래그가 없음 \u0026#34;text\u0026#34;: \u0026#34;Wait, let\u0026#39;s check n = 67108863... Correct. Wait, let\u0026#39;s check n = 67108864...\u0026#34;, \u0026#34;thoughtSignature\u0026#34;: \u0026#34;.....\u0026#34; // thought: true 빠짐 → 파서가 최종 응답으로 처리 } ] }, \u0026#34;finishReason\u0026#34;: \u0026#34;MAX_TOKENS\u0026#34; // ← 정상 종료가 아닌 토큰 강제 종료 }] } } 실패 1 — 토큰 소진: 16,233 토큰 중 15,356개(94.6%)가 thoughtsTokenCount에 잡힌다. 실제 응답에 사용 가능한 토큰은 640개뿐이고, 제대로 된 답은 생성되지 않는다.\n실패 2 — 내부 로직 노출: finishReason: MAX_TOKENS로 강제 종료될 때 현재 버퍼의 내용이 flush된다. 문제는 이 루프 텍스트 파트에 \u0026quot;thought\u0026quot;: true 플래그가 없다는 것이다. SDK 파서가 이걸 최종 사용자 응답으로 처리해 반환한다.\nflowchart TD A[프롬프트 입력] --\u003e B{모델 추론 시작} B --\u003e|정상 케이스 95-97%| C[일반화 공식 도출] C --\u003e D[최종 답변 생성] D --\u003e E[thought: true 파트 + 답변 파트 반환] B --\u003e|버그 케이스 3-5%| F[특정 정수값 검증 시작] F --\u003e G[\"n=67108863 검증... n=67108864 검증...\"] G --\u003e|토큰 한도 초과| H[MAX_TOKENS finishReason] H --\u003e I[\"버퍼 flush: 루프 텍스트 반환 \u0026lt;br/\u0026gt;⚠️ thought: true 플래그 없음\"] I --\u003e J[\"클라이언트: 쓸모없는 추론 텍스트를 최종 답으로 인식\"]영향 범위 모델: gemini-3-flash-preview (확인됨) 재현률: 100개 이상 동시 요청 시 3~5% 토큰 설정: maxOutputTokens 16k, 32k 모두 동일하게 발생 실행 모드: Batch mode와 일반 API 호출 모두 영향 현재 가능한 방어 코드 공식 수정 전까지 클라이언트 측에서 방어할 수 있는 방법:\n1. finishReason 체크 response = model.generate_content(prompt) for candidate in response.candidates: if candidate.finish_reason == \u0026#34;MAX_TOKENS\u0026#34;: # 유효하지 않은 응답 — 재시도 또는 에러 처리 raise ValueError(\u0026#34;Response was truncated due to token limit\u0026#34;) 2. thoughtsTokenCount 비율 체크 usage = response.usage_metadata thoughts_ratio = usage.thoughts_token_count / usage.total_token_count if thoughts_ratio \u0026gt; 0.9: # 추론에 토큰의 90% 이상 사용 → 무한 루프 가능성 logger.warning(f\u0026#34;Possible reasoning loop detected: {thoughts_ratio:.1%} tokens in thoughts\u0026#34;) raise ValueError(\u0026#34;Model entered a reasoning loop\u0026#34;) 3. thought 플래그 검사 for part in response.candidates[0].content.parts: # thought: true가 없고 thoughtSignature가 있는 파트는 의심 if hasattr(part, \u0026#39;thought_signature\u0026#39;) and not getattr(part, \u0026#39;thought\u0026#39;, False): logger.error(\u0026#34;Leaked reasoning detected in response parts\u0026#34;) # 이 파트를 응답에서 제거하거나 전체를 재시도 4. thinking_level 조정 이전 포스트에서 정리한 thinking_level 파라미터를 \u0026quot;low\u0026quot; 또는 \u0026quot;medium\u0026quot;으로 내리면 발생 빈도를 줄일 수 있다. 단, 추론 품질도 같이 낮아진다:\ngeneration_config = { \u0026#34;thinking_config\u0026#34;: { \u0026#34;thinking_budget\u0026#34;: 4096, # thinking_level 대신 토큰 예산 직접 제한 } } 왜 Flash Preview인가? Gemini 3 Flash는 속도와 비용 효율을 위해 추론 과정을 경량화했다. Pro 모델에 비해 수렴 조건(stop condition)의 안전망이 약한 것으로 보인다. 비트 연산이나 수학적 증명처럼 \u0026ldquo;모든 케이스를 검증해야 안심\u0026quot;하는 문제 유형에서 취약점이 드러난다.\n실용적 권고: 프로덕션에서 gemini-3-flash-preview를 쓴다면:\n로직/수학 문제는 가능하면 gemini-3-pro-preview로 라우팅 Flash를 쓸 때는 finishReason + thoughtsTokenCount 방어 코드 필수 대량 배치 처리 시 응답 검증 레이어 추가 빠른 링크 Google AI Developers Forum — 버그 리포트 원문 Gemini 3 Developer Guide — thinking_level 파라미터 인사이트 이 버그는 \u0026ldquo;추론 능력이 강해질수록 새로운 종류의 장애가 생긴다\u0026quot;는 것을 보여준다. Gemini 3 이전의 모델은 그냥 틀린 답을 내놨지만, Thinking 모델은 \u0026ldquo;정답을 찾아야 한다\u0026quot;는 드라이브가 강해서 수렴하지 않으면 무한 루프에 빠진다. 추론 모델을 프로덕션에 도입할 때는 maxOutputTokens를 낮추는 것보다 응답 유효성 검증 레이어를 별도로 두는 게 더 안전하다. finishReason: MAX_TOKENS인 응답은 항상 의심하자.\n","date":"2026-02-25T00:00:00+09:00","image":"/images/posts/2026-02-25-gemini-3-flash-infinite-loop-bug/cover.jpg","permalink":"/ko/posts/2026-02-25-gemini-3-flash-infinite-loop-bug/","title":"Gemini 3 Flash Preview 버그: 무한 추론 루프와 내부 로직 노출"},{"content":"개요 DevOps 엔지니어 포지션을 탐색하면서 한국 APM 시장 리더인 와탭랩스(WhaTap Labs) 채용 공고를 보게 됐고, 자연스럽게 Observability 툴 생태계를 깊이 파보게 됐다. Honeycomb vs Grafana 비교를 보면 단순한 \u0026ldquo;어느 툴이 더 좋냐\u0026quot;를 넘어서 모니터링(Monitoring)과 관측 가능성(Observability)이라는 두 가지 패러다임의 차이가 드러난다. 오늘은 그 차이를 데이터 모델, 쿼리 방식, SLO 설계 측면에서 정리한다.\ngraph TD subgraph \"전통적 모니터링 (Grafana)\" A[애플리케이션] --\u003e|metrics| B[Prometheus/InfluxDB] A --\u003e|logs| C[Loki/Elasticsearch] A --\u003e|traces| D[Tempo/Jaeger] B --\u003e E[Grafana 대시보드] C --\u003e E D --\u003e E E --\u003e|분리된 뷰| F[개발자] end subgraph \"Observability (Honeycomb)\" G[애플리케이션] --\u003e|wide events| H[Honeycomb 단일 저장소] H --\u003e|통합 쿼리 빌더| I[개발자] end패러다임의 차이: 데이터 모델이 전부다 모니터링 (Grafana 방식) 전통적 모니터링은 미리 정의된 질문에 답하기 위해 설계됐다. 알고 싶은 지표를 미리 정해서 시계열 데이터로 집계한다.\nMetrics: CPU 사용률, 응답시간 P99, 에러율 — 숫자로 집계된 시계열 Logs: 개별 이벤트 텍스트 — Loki나 Elasticsearch에 별도 저장 Traces: 분산 요청 추적 — Tempo나 Jaeger에 별도 저장 각 신호(signal)가 다른 저장소에 분리되어 있다. \u0026ldquo;에러가 났는데 어느 사용자에서 발생했고 어느 서버였는지\u0026quot;를 파악하려면 세 개의 탭을 오가며 시간 범위를 맞춰 수동으로 연관 분석을 해야 한다.\nGrafana의 강점은 가시화 유연성이다. 어떤 데이터 소스든 연결해서 대시보드를 만들 수 있다. 이미 Prometheus, MySQL, CloudWatch 등을 쓰고 있다면 Grafana는 통합 뷰어 역할을 한다.\nObservability (Honeycomb 방식) Observability의 핵심 개념은 Wide Events다. 요청 하나가 처리될 때 관련된 모든 컨텍스트를 하나의 이벤트로 기록한다:\n{ \u0026#34;timestamp\u0026#34;: \u0026#34;2026-02-25T10:30:00Z\u0026#34;, \u0026#34;service\u0026#34;: \u0026#34;payment-api\u0026#34;, \u0026#34;user_id\u0026#34;: \u0026#34;u_12345\u0026#34;, \u0026#34;tenant_id\u0026#34;: \u0026#34;enterprise_co\u0026#34;, \u0026#34;request_path\u0026#34;: \u0026#34;/api/charge\u0026#34;, \u0026#34;duration_ms\u0026#34;: 2340, \u0026#34;db_query_count\u0026#34;: 12, \u0026#34;cache_hit\u0026#34;: false, \u0026#34;region\u0026#34;: \u0026#34;ap-northeast-2\u0026#34;, \u0026#34;k8s_pod\u0026#34;: \u0026#34;payment-6c8b7d9-xk2p4\u0026#34;, \u0026#34;feature_flag\u0026#34;: \u0026#34;new_checkout_flow\u0026#34;, \u0026#34;error\u0026#34;: null } 이 이벤트 하나에 메트릭(duration_ms), 로그 컨텍스트(error), 트레이스 컨텍스트(k8s_pod, region)가 모두 담겨 있다. Honeycomb은 이걸 단일 저장소에서 단일 쿼리 빌더로 분석한다.\n핵심 기능 비교 graph LR subgraph \"고카디널리티(High Cardinality) 처리\" A[\"Grafana \u0026lt;br/\u0026gt;필드당 column 생성 필요 \u0026lt;br/\u0026gt;또는 비용 증가\"] B[\"Honeycomb \u0026lt;br/\u0026gt;모든 필드 무제한 쿼리 가능 \u0026lt;br/\u0026gt;(비용 변화 없음)\"] end subgraph \"SLO 설계\" C[\"Grafana \u0026lt;br/\u0026gt;메트릭 기반 SLO \u0026lt;br/\u0026gt;컨텍스트 유실\"] D[\"Honeycomb \u0026lt;br/\u0026gt;이벤트 기반 SLO \u0026lt;br/\u0026gt;왜 위반됐는지 즉시 드릴다운\"] end subgraph \"쿼리 복잡도\" E[\"Grafana \u0026lt;br/\u0026gt;PromQL + LogQL 각각\"] F[\"Honeycomb \u0026lt;br/\u0026gt;통합 Query Builder\"] endHigh Cardinality 문제 카디널리티(Cardinality)는 특정 필드가 가질 수 있는 고유값의 수다. user_id는 수백만 개의 값을 가질 수 있는 고카디널리티 필드다.\nGrafana (Prometheus): 각 고유값마다 시계열 하나가 생성된다. user_id 기준으로 집계하면 수백만 개의 시계열이 생겨 저장소가 폭발한다. 이를 피하려면 미리 집계하거나 인덱싱 전략을 세워야 한다. \u0026ldquo;특정 사용자의 느린 요청 패턴\u0026quot;을 사후에 분석하기 어렵다.\nHoneycomb: Wide Events에 user_id를 그냥 넣으면 된다. 이벤트 기반 저장이라 카디널리티 제약이 없다. 문제가 발생한 후에도 user_id = \u0026quot;u_12345\u0026quot;로 필터링해서 해당 사용자의 모든 이벤트를 즉시 조회할 수 있다.\nSLO 비교 SLO(Service Level Objective)를 잘못 설계하면 알람은 울리는데 무엇을 고쳐야 하는지 모르는 상황이 발생한다.\n기준 Grafana Honeycomb 데이터 소스 집계된 메트릭 원시 이벤트 위반 컨텍스트 없음 (숫자만) 위반된 이벤트 바로 드릴다운 알람 정확도 False positive 가능 이벤트 기반이라 높은 정밀도 \u0026ldquo;왜 위반됐나?\u0026rdquo; 수동으로 로그/트레이스 교차 분석 같은 UI에서 즉시 분석 예: P99 응답시간 SLO 위반 시\nGrafana: 알람 → 메트릭 대시보드 → Loki에서 로그 검색 → Tempo에서 트레이스 분석 (3개 탭) Honeycomb: 알람 → SLO 위반 이벤트 목록 → feature_flag = \u0026quot;new_checkout_flow\u0026quot; 패턴 발견 (1개 UI) 가격 모델 항목 Grafana Cloud Honeycomb 기본 단위 바이트 + 시계열 수 + 사용자 수 이벤트 수 고카디널리티 추가 비용 포함 쿼리 비용 일정량 초과시 추가 포함 예측 가능성 낮음 (다변수) 높음 (이벤트 단위) Grafana가 더 저렴한 경우: 이미 Prometheus를 쓰고 있고, 메트릭 수가 적고, 추가 분석이 필요 없을 때.\nHoneycomb이 더 저렴한 경우: 고카디널리티 분석이 필요하거나, 여러 신호(metrics/logs/traces) 통합에 엔지니어링 비용이 드는 경우.\n언제 무엇을 선택할까? graph TD A[관측 전략 선택] --\u003e B{현재 인프라 상황?} B --\u003e|이미 Prometheus 사용 중| C[Grafana 계속 활용] B --\u003e|새로 시작 또는 전환 검토| D{팀 규모와 요구사항?} D --\u003e|인프라 지표 중심, 소규모| E[Grafana + Prometheus] D --\u003e|분산 시스템, 사용자별 디버깅 필요| F[Honeycomb] D --\u003e|대규모 엔터프라이즈| G[Datadog / New Relic] C --\u003e H{고카디널리티 분석 필요?} H --\u003e|No| I[Grafana 충분] H --\u003e|Yes| J[Honeycomb 또는 Grafana + Tempo 조합]Grafana가 적합한 경우:\n이미 Prometheus/Loki 스택을 운영 중 인프라 메트릭 대시보드가 주된 용도 비용 민감도가 높고 트래픽이 예측 가능 오픈소스 셀프호스팅 요건 Honeycomb이 적합한 경우:\n마이크로서비스/분산 시스템에서 \u0026ldquo;어느 요청이 왜 느린지\u0026rdquo; 빠르게 파악해야 할 때 고카디널리티 속성(user_id, tenant_id, feature_flag)으로 분석하는 케이스가 많을 때 SRE 팀이 DORA 메트릭 / SLO 관리에 집중하는 조직 한국 시장 맥락: 와탭랩스와 APM 오늘 채용 공고를 보면서 흥미로운 점을 발견했다 — WhaTap Labs는 한국 자체 개발 APM(Application Performance Monitoring) 도구를 제공하는 회사다. Honeycomb/Datadog 같은 글로벌 툴의 한국형 대안으로 포지셔닝하며 에이전트 기반 자동 계측, 한국어 지원, 온프레미스 배포 옵션을 강점으로 한다.\nDevOps/Observability 엔지니어를 채용 중인 한국 회사들(코인원, 야놀자 등)이 Grafana + 내부 도구 조합을 쓰는 경우가 많은데, Honeycomb 같은 \u0026ldquo;개발자 중심 observability\u0026rdquo; 패러다임으로의 전환이 글로벌에서는 가속화되고 있다. 이 공간의 전문성이 커리어 관점에서도 흥미롭다.\n빠른 링크 Honeycomb vs Grafana — Honeycomb 공식 비교 Gartner Peer Insights — Grafana vs Honeycomb WhaTap Labs DevOps 채용 인사이트 모니터링과 Observability의 차이는 \u0026ldquo;질문을 미리 알고 있느냐 아니냐\u0026quot;에 있다. 전통적 모니터링은 미리 정의한 지표가 임계값을 넘으면 알린다 — 알고 있는 장애에 강하다. Observability는 \u0026ldquo;왜 이 사용자의 요청이 느린가\u0026quot;처럼 사전에 정의하지 않은 질문을 사후에 탐색할 수 있게 한다. 시스템이 복잡해질수록, 그리고 알 수 없는 미지의 장애가 많아질수록 Observability 패러다임의 가치가 커진다. Grafana를 이미 쓰고 있다면 Loki + Tempo + Grafana를 조합해 Observability를 흉내낼 수 있지만, 데이터가 분리된 이상 쿼리 UX의 한계는 피할 수 없다.\n","date":"2026-02-25T00:00:00+09:00","image":"/images/posts/2026-02-25-observability-honeycomb-vs-grafana/cover.jpg","permalink":"/ko/posts/2026-02-25-observability-honeycomb-vs-grafana/","title":"Observability vs Monitoring: Honeycomb vs Grafana 비교 분석"},{"content":"개요 EC2에서 FastAPI 백엔드와 Vite 프론트엔드를 동시에 운영해야 할 때, nohup python ... \u0026amp; 같은 방법은 프로세스가 죽어도 모르고, 재부팅하면 날아가고, 로그 관리도 어렵다. PM2(Process Manager 2)는 Node.js 생태계에서 나왔지만 어떤 언어로 만든 프로세스도 관리할 수 있는 프로덕션 프로세스 매니저다. 오늘은 PM2 기본 명령어부터, Python(uvicorn) + Node.js(Vite)를 ecosystem.config.js 하나로 관리하는 실전 패턴, 그리고 dotenv 문제 해결까지 정리한다.\ngraph TD A[pm2 start ecosystem.config.js] --\u003e B[PM2 Daemon] B --\u003e C[\"backend 프로세스 \u0026lt;br/\u0026gt;uv run uvicorn :8000\"] B --\u003e D[\"frontend 프로세스 \u0026lt;br/\u0026gt;npm run dev :5173\"] C --\u003e|크래시| E[자동 재시작 autorestart] D --\u003e|크래시| E E --\u003e B F[pm2 save] --\u003e G[\"~/.pm2/dump.pm2 \u0026lt;br/\u0026gt;프로세스 목록 저장\"] H[pm2 startup] --\u003e I[\"시스템 서비스 등록 \u0026lt;br/\u0026gt;재부팅 후 자동 복구\"] G --\u003e IPM2 기본 명령어 치트시트 # 설치 (전역) npm install pm2 -g # 단일 프로세스 시작 pm2 start app.js pm2 start server.py --interpreter python3 # Python # 프로세스 목록 조회 pm2 list # 상세 정보 pm2 show \u0026lt;name\u0026gt; # 로그 실시간 확인 pm2 logs # 전체 pm2 logs backend # 특정 프로세스만 pm2 logs --lines 200 # 최근 200줄 # 재시작 / 정지 / 삭제 pm2 restart \u0026lt;name\u0026gt; pm2 stop \u0026lt;name\u0026gt; pm2 delete \u0026lt;name\u0026gt; # 목록에서 완전 제거 # 리소스 모니터 (CPU/메모리 실시간) pm2 monit # 현재 프로세스 목록 저장 → 재부팅 시 복구 pm2 save pm2 stop과 pm2 delete의 차이: stop은 목록에 남아있고 delete는 목록 자체에서 제거한다. 다시 쓸 프로세스라면 stop, 완전히 치우려면 delete.\necosystem.config.js — 여러 프로세스를 하나로 pm2 start app.js --name backend --watch --max-memory-restart 1G ... 처럼 플래그가 늘어나면 관리가 힘들다. ecosystem.config.js로 모든 설정을 코드로 관리하자.\n# 자동 생성 (예시 파일 만들어줌) pm2 ecosystem 생성된 파일을 프로젝트에 맞게 수정한다:\nmodule.exports = { apps: [ { name: \u0026#39;my-api\u0026#39;, script: \u0026#39;server.js\u0026#39;, instances: 1, autorestart: true, // 크래시 시 자동 재시작 watch: false, // 파일 변경 감지 재시작 (dev 환경에서만 true) max_memory_restart: \u0026#39;1G\u0026#39;, env: { // 기본 환경 변수 NODE_ENV: \u0026#39;development\u0026#39;, PORT: 3000 }, env_production: { // --env production 시 적용 NODE_ENV: \u0026#39;production\u0026#39;, PORT: 8080 } } ] }; 환경별로 다른 변수를 쓰려면 env_\u0026lt;이름\u0026gt; 키를 추가하고 시작 시 --env 플래그로 선택한다:\npm2 start ecosystem.config.js # env 적용 pm2 start ecosystem.config.js --env production # env_production 적용 dotenv(.env)와 PM2의 충돌 문제 PM2를 쓸 때 가장 흔히 겪는 문제: 로컬에서 node server.js로 실행하면 잘 되는데 PM2로 돌리면 환경 변수가 없다고 에러가 난다.\n원인은 단순하다. dotenv는 프로세스가 시작될 때 .env 파일을 읽어 process.env에 주입한다. 그런데 PM2는 독립적인 데몬(백그라운드 서비스)으로 동작하기 때문에 현재 쉘의 환경 변수가 자동으로 상속되지 않는다.\n해결책 두 가지:\n방법 1 — ecosystem.config.js에 직접 선언 (권장)\nenv: { NODE_ENV: \u0026#39;production\u0026#39;, DATABASE_URL: \u0026#39;postgresql://...\u0026#39;, API_KEY: \u0026#39;your-key-here\u0026#39; } 단점: ecosystem.config.js가 git에 올라가면 시크릿이 노출된다. .gitignore에 추가하거나, 시크릿만 별도 파일로 분리해서 require('./secrets')로 불러오는 방식을 쓴다.\n방법 2 — 애플리케이션 코드에서 dotenv 직접 로드\nPython이라면 python-dotenv가 앱 실행 시 직접 .env를 읽으므로 PM2 환경과 무관하게 작동한다:\n# main.py from dotenv import load_dotenv load_dotenv() # 이 코드가 있으면 PM2 하에서도 .env 로드됨 Node.js도 마찬가지:\nrequire(\u0026#39;dotenv\u0026#39;).config(); // 코드 첫 줄에 있으면 PM2 무관하게 작동 Non-Node.js 프로세스 실행 — interpreter: \u0026ldquo;none\u0026rdquo; PM2는 기본적으로 .js 파일을 Node.js로 실행하려 한다. Python, Go, 쉘 스크립트 등 다른 런타임의 프로세스를 실행하려면 두 가지 방법이 있다:\n방법 1 — interpreter 명시\n{ name: \u0026#39;flask-api\u0026#39;, script: \u0026#39;app.py\u0026#39;, interpreter: \u0026#39;python3\u0026#39; } 방법 2 — interpreter: \u0026ldquo;none\u0026rdquo; + script에 실행파일 직접 지정 (권장)\n{ name: \u0026#39;backend\u0026#39;, script: \u0026#39;uvicorn\u0026#39;, // 또는 절대경로: \u0026#39;/usr/local/bin/uvicorn\u0026#39; args: \u0026#39;main:app --host 0.0.0.0 --port 8000\u0026#39;, interpreter: \u0026#39;none\u0026#39; // Node.js 래핑 없이 바이너리 직접 실행 } interpreter: \u0026quot;none\u0026quot;이 더 유연하다. uv, gunicorn, go, 쉘 스크립트 등 어떤 실행파일이든 script에 넣고 args로 인자를 넘길 수 있다.\n실전: Hybrid Image Search Demo 설정 실제로 운영 중인 프로젝트(hybrid-image-search-demo)의 ecosystem.config.js다. FastAPI 백엔드(Python + uv)와 Vite 프론트엔드(Node.js)를 함께 관리한다:\nmodule.exports = { apps: [ { name: \u0026#34;backend\u0026#34;, cwd: \u0026#34;./\u0026#34;, // 리포 루트에서 실행 — Python 모듈 경로 해결에 중요 script: \u0026#34;uv\u0026#34;, // uv (Python 패키지 매니저)를 직접 실행 args: \u0026#34;run python -m uvicorn backend.src.main:app --host 0.0.0.0 --port 8000\u0026#34;, interpreter: \u0026#34;none\u0026#34;, // uv는 Node.js가 아니므로 반드시 설정 env: { NODE_ENV: \u0026#34;production\u0026#34;, // GOOGLE_API_KEY, OPENAI_API_KEY는 .env에서 python-dotenv가 로드 } }, { name: \u0026#34;frontend\u0026#34;, cwd: \u0026#34;./frontend\u0026#34;, // npm 명령은 package.json이 있는 폴더에서 실행 script: \u0026#34;npm\u0026#34;, args: \u0026#34;run dev -- --host\u0026#34;, // \u0026#39;--host\u0026#39;는 Vite가 0.0.0.0 바인딩하도록 (외부 접근 허용) interpreter: \u0026#34;none\u0026#34;, } ] }; 이 설정의 핵심 포인트:\ncwd: \u0026quot;./\u0026quot; — 백엔드는 리포 루트에서 실행해야 backend.src.main처럼 점 표기 모듈 경로가 작동한다. cwd를 생략하거나 ./backend로 설정하면 ModuleNotFoundError가 난다.\nargs: \u0026quot;run dev -- --host\u0026quot; — npm 스크립트에 추가 인자를 넘길 때 --로 구분한다. --host는 npm이 아닌 Vite에 전달된다.\n시크릿은 .env + python-dotenv — GOOGLE_API_KEY와 OPENAI_API_KEY는 ecosystem 파일에 없다. FastAPI 앱이 시작될 때 .env 파일을 직접 읽어 처리한다.\ngraph LR subgraph \"PM2 Daemon\" A[\"backend \u0026lt;br/\u0026gt;uv run python -m uvicorn \u0026lt;br/\u0026gt;:8000\"] B[\"frontend \u0026lt;br/\u0026gt;npm run dev --host \u0026lt;br/\u0026gt;:5173\"] end C[\".env \u0026lt;br/\u0026gt;GOOGLE_API_KEY \u0026lt;br/\u0026gt;OPENAI_API_KEY\"] --\u003e|python-dotenv 로드| A D[\"ecosystem.config.js \u0026lt;br/\u0026gt;NODE_ENV=production\"] --\u003e|PM2 주입| A E[Nginx 또는 직접 접근] --\u003e A E --\u003e B서버 재부팅 후 자동 복구 PM2 프로세스 목록은 서버를 재시작하면 사라진다. 두 단계로 영구 등록한다:\n# 1단계: 현재 실행 중인 프로세스 목록 저장 pm2 save # → ~/.pm2/dump.pm2 파일에 기록됨 # 2단계: 시스템 서비스에 PM2 등록 (재부팅 시 자동 시작) pm2 startup # 이 명령을 실행하면 시스템에 맞는 명령어를 출력해준다: # [PM2] To setup the Startup Script, copy/paste the following command: # sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu # 출력된 sudo 명령을 그대로 실행 sudo env PATH=$PATH:/usr/bin ... pm2 startup은 시스템 init 방식(systemd, SysV 등)을 자동 감지한다. AWS EC2 Ubuntu 기준으로는 systemd 서비스 파일을 생성한다.\n주의: 폴더 경로 고정 문제 PM2는 한 번 등록된 서비스명(예: main)에 스크립트 경로를 고정해서 기억한다. /home/project1/server.js로 시작한 main 서비스는 이후 /home/project2/에서 같은 이름으로 시작해도 여전히 /home/project1/server.js를 실행한다.\n# 현재 연결된 경로 확인 pm2 show main # script path 항목 확인 # 해결: 기존 서비스 완전 삭제 후 재등록 pm2 delete main cd /home/project2/ pm2 start server.js --name main ecosystem.config.js를 쓰면 이 문제가 자연스럽게 해결된다 — cwd와 script를 명시적으로 선언하기 때문이다.\n빠른 참고 — 자주 쓰는 패턴 # ecosystem으로 시작/재시작/정지 pm2 start ecosystem.config.js pm2 restart ecosystem.config.js pm2 stop ecosystem.config.js # 특정 앱만 pm2 restart backend pm2 logs frontend --lines 100 # 상태 한눈에 보기 pm2 list # 전체 클린 재시작 pm2 delete all \u0026amp;\u0026amp; pm2 start ecosystem.config.js \u0026amp;\u0026amp; pm2 save 빠른 링크 PM2 공식 문서 — ecosystem.config.js PM2 ecosystem.config.js 환경 변수 설정 (한국어) PM2 백그라운드 실행/중지/재시작 (한국어) 인사이트 PM2를 처음 쓸 때 가장 헷갈리는 지점은 \u0026ldquo;Node.js 도구인데 왜 Python에서도 쓰나?\u0026ldquo;다. interpreter: \u0026quot;none\u0026quot;으로 설정하면 PM2는 단순히 프로세스 감시자가 된다 — 언어와 무관하게 어떤 프로세스든 크래시를 감지하고 재시작한다. 실제로 이 프로젝트처럼 Python 백엔드와 Node.js 프론트엔드를 동시에 운영할 때, PM2 하나로 두 프로세스의 로그를 pm2 logs로 통합 확인할 수 있다는 것이 운영 편의성에서 큰 차이를 만든다. .env와 PM2의 충돌은 \u0026ldquo;프로세스 실행 컨텍스트\u0026quot;의 차이에서 오는데, 이를 이해하면 비슷한 문제(Docker 컨테이너에서 환경 변수가 안 보일 때 등)도 같은 원리로 해결할 수 있다.\n","date":"2026-02-25T00:00:00+09:00","image":"/images/posts/2026-02-25-pm2-process-manager-ecosystem/cover.jpg","permalink":"/ko/posts/2026-02-25-pm2-process-manager-ecosystem/","title":"PM2로 Python + Node.js 멀티 서비스 운영하기 — ecosystem.config.js 완전 가이드"},{"content":"개요 VS Code 확장에서 외부 OAuth 서비스(GitHub, Auth0 등)로 로그인하려면 브라우저를 열고 콜백을 받아야 한다. 일반 웹앱은 http://localhost:3000/callback 같은 로컬 서버가 콜백 URI지만, VS Code 확장은 로컬 포트 없이 vscode://publisher.extension-name 프로토콜로 직접 콜백을 받을 수 있다. 오늘은 registerUriHandler와 AuthenticationProvider API를 조합해 OAuth 흐름을 구현하는 방법, code-server(브라우저 기반 VS Code)에서의 프로토콜 제약, 그리고 Remote Tunnels의 OAuth 메커니즘을 살펴본다.\ngraph TD A[Extension 시작] --\u003e B[registerUriHandler 등록] A --\u003e C[registerAuthenticationProvider 등록] B --\u003e D[UriEventHandler] C --\u003e E[Auth0AuthenticationProvider] D --\u003e|handleUri 이벤트| E E --\u003e|createSession 호출 시| F[브라우저 열기 - Auth0 로그인 페이지] F --\u003e|OAuth 콜백| G[\"vscode://publisher.ext-name#access_token=...\"] G --\u003e|OS가 VS Code에 전달| B B --\u003e|URI 파싱| H[토큰 추출] H --\u003e I[context.secrets 저장] I --\u003e J[AuthenticationSession 반환]registerUriHandler — 외부 콜백의 진입점 vscode.window.registerUriHandler()는 OS 수준의 URI 핸들러를 등록해서 외부에서 vscode:// 링크를 열면 확장이 해당 URI를 받도록 한다. VS Code가 여러 창이 열려 있으면 최상위 창이 처리한다.\n구현은 단순하다. UriHandler 인터페이스를 구현하고 EventEmitter로 이벤트를 전파한다:\nclass UriEventHandler extends EventEmitter\u0026lt;Uri\u0026gt; implements UriHandler { public handleUri(uri: Uri) { this.fire(uri); // 구독자들에게 URI 전달 } } // extension.ts의 activate() 안에서: const uriHandler = new UriEventHandler(); context.subscriptions.push( vscode.window.registerUriHandler(uriHandler) ); 이 핸들러에 URI가 들어오는 URL 형식은:\nvscode://\u0026lt;publisher\u0026gt;.\u0026lt;extension-name\u0026gt;[/path][?query=value][#fragment=value] 예: vscode://mycompany.my-ext?code=abc123 또는 vscode://mycompany.my-ext#access_token=xyz\n중요한 구분이 있다. Auth0는 OAuth implicit flow에서 토큰을 URI fragment(#) 에 담아 보내고, Azure AD는 query string(?) 에 담는다. 코드에서 어느 쪽을 파싱하는지 OAuth 제공자에 따라 달라진다.\nAuthenticationProvider 인터페이스 VS Code 1.54부터 authentication.registerAuthenticationProvider()로 커스텀 인증 프로바이더를 등록할 수 있다. 이렇게 하면 VS Code의 Account 메뉴에 표시되고, 다른 확장이 vscode.authentication.getSession()으로 세션을 요청할 수 있다.\n구현해야 할 인터페이스:\nexport class Auth0AuthenticationProvider implements AuthenticationProvider, Disposable { private _sessionChangeEmitter = new EventEmitter\u0026lt;...\u0026gt;(); // VS Code가 세션 변경을 구독하는 이벤트 get onDidChangeSessions() { return this._sessionChangeEmitter.event; } // 저장된 세션 반환 (secrets store에서 읽기) async getSessions(scopes?: string[]): Promise\u0026lt;readonly AuthenticationSession[]\u0026gt; { const stored = await this.context.secrets.get(SESSIONS_KEY); return stored ? JSON.parse(stored) : []; } // 로그인 → 토큰 획득 → 세션 생성 async createSession(scopes: string[]): Promise\u0026lt;AuthenticationSession\u0026gt; { const token = await this.login(scopes); const userinfo = await this.getUserInfo(token); const session: AuthenticationSession = { id: uuid(), accessToken: token, account: { label: userinfo.name, id: userinfo.email }, scopes: [] }; await this.context.secrets.store(SESSIONS_KEY, JSON.stringify([session])); this._sessionChangeEmitter.fire({ added: [session], removed: [], changed: [] }); return session; } // 로그아웃 async removeSession(sessionId: string): Promise\u0026lt;void\u0026gt; { const sessions = JSON.parse(await this.context.secrets.get(SESSIONS_KEY) || \u0026#39;[]\u0026#39;); const idx = sessions.findIndex((s: AuthenticationSession) =\u0026gt; s.id === sessionId); const [removed] = sessions.splice(idx, 1); await this.context.secrets.store(SESSIONS_KEY, JSON.stringify(sessions)); this._sessionChangeEmitter.fire({ added: [], removed: [removed], changed: [] }); } } context.secrets는 VS Code의 내장 시크릿 스토어(macOS Keychain, Windows Credential Manager, Linux libsecret)에 암호화 저장한다. 토큰을 평문으로 globalState에 저장하면 안 되는 이유가 이것이다.\nOAuth 로그인 플로우 상세 createSession에서 호출하는 login() 메서드가 실제 OAuth 흐름의 핵심이다:\nprivate async login(scopes: string[]) { return await window.withProgress({ location: ProgressLocation.Notification, ... }, async () =\u0026gt; { const stateId = uuid(); // CSRF 방지용 state 파라미터 this._pendingStates.push(stateId); // OAuth 인가 URL 구성 const params = new URLSearchParams({ response_type: \u0026#39;token\u0026#39;, client_id: CLIENT_ID, redirect_uri: `vscode://${PUBLISHER}.${EXT_NAME}`, state: stateId, scope: scopes.join(\u0026#39; \u0026#39;) }); await env.openExternal(Uri.parse(`https://auth0.com/authorize?${params}`)); // URI 핸들러가 콜백을 받을 때까지 대기 (60초 타임아웃) return await Promise.race([ promiseFromEvent(this._uriHandler.event, this.handleUri(scopes)).promise, new Promise((_, reject) =\u0026gt; setTimeout(() =\u0026gt; reject(\u0026#39;Timeout\u0026#39;), 60000)) ]); }); } private handleUri = (scopes) =\u0026gt; async (uri, resolve, reject) =\u0026gt; { const fragment = new URLSearchParams(uri.fragment); // Auth0는 fragment const token = fragment.get(\u0026#39;access_token\u0026#39;); const state = fragment.get(\u0026#39;state\u0026#39;); if (!this._pendingStates.includes(state)) { reject(new Error(\u0026#39;Invalid state\u0026#39;)); // CSRF 방어 return; } resolve(token); }; Promise.race()를 쓰는 이유가 흥미롭다 — 정상 흐름(URI 콜백), 타임아웃(60초), 사용자 취소(Cancellation token) 세 가지 중 가장 먼저 도착하는 걸 처리한다.\n사용 측 코드 등록된 프로바이더를 다른 확장이나 같은 확장 내에서 사용할 때:\n// 세션이 있으면 가져오고, 없으면 로그인 요청 (createIfNone: true) const session = await vscode.authentication.getSession(\u0026#39;auth0\u0026#39;, [\u0026#39;openid\u0026#39;, \u0026#39;profile\u0026#39;], { createIfNone: true }); if (session) { vscode.window.showInformationMessage(`환영합니다, ${session.account.label}!`); // session.accessToken으로 API 호출 } code-server에서의 프로토콜 제약 여기서 중요한 현실 제약이 있다. code-server는 브라우저에서 VS Code를 실행하는 오픈소스 프로젝트(★76k)인데, vscode:// 프로토콜이 브라우저에서는 작동하지 않는다.\n브라우저 보안 정책상 navigator.registerProtocolHandler()로 등록 가능한 스킴이 제한되어 있고, vscode://는 허용 목록에 없다. code-server 메인테이너 답변:\n\u0026ldquo;I do not think browsers allow handling vscode:// anyway, at best we could do web+vscode:// or web+code-server://.\u0026rdquo;\n제안된 우회책:\nhttps://code-server-url/protocol-handler?uri=vscode://my-plugin/path code-server 자체가 /protocol-handler 라우트를 처리해서 연결된 클라이언트 확장에 URI를 전달하는 방식이다. 이 방법은 알림/확인 팝업이 없어서 UX가 더 깔끔하다는 장점도 있다.\nPWA(Progressive Web App)로 설치된 경우엔 manifest.json의 protocol_handlers로 부분 해결도 가능하다 (https:// 스킴 필수).\ngraph LR subgraph \"Desktop VS Code\" A[\"vscode://ext/callback\"] --\u003e|OS 프로토콜 핸들러| B[VS Code 프로세스] B --\u003e C[handleUri 호출] end subgraph \"code-server (브라우저)\" D[\"vscode://ext/callback\"] --\u003e|❌ 브라우저 차단| E[실패] F[\"https://code-server/protocol-handler?uri=...\"] --\u003e|✅ HTTP 경유 우회| G[code-server 서버] G --\u003e H[WebSocket으로 확장에 전달] endRemote Tunnels의 OAuth 메커니즘 VS Code Remote Tunnels는 SSH 없이 원격 머신에 접속하는 기능이다. 내부적으로 GitHub OAuth를 사용해 터널 서비스를 인증한다:\ncode tunnel 명령 실행 → VS Code Server가 원격 머신에 설치됨 Microsoft Azure 기반 dev tunnels 서비스에 연결 vscode.dev/tunnel/\u0026lt;machine_name\u0026gt; URL 생성 클라이언트가 이 URL 접속 시 github.com/login/oauth/authorize... 리다이렉트 터널 보안은 AES-256-CTR로 E2E 암호화되며, VS Code는 리슨 포트를 열지 않고 아웃바운드 연결만 한다. 방화벽 설정이 필요 없는 이유다.\n실용 가이드: 어떤 방식을 선택할까? 상황 권장 방식 Desktop VS Code + 외부 OAuth registerUriHandler + AuthenticationProvider code-server + OAuth /protocol-handler 라우트 우회 또는 localhost 서버 사내 Remote 환경 접근 Remote Tunnels (GitHub 계정만 있으면 됨) 여러 GitHub 계정 관리 GitShift 확장 (mikeeeyy04.gitshift) 프로덕션 AuthenticationProvider를 만든다면 두 가지를 추가해야 한다:\nRefresh token만 저장하고 Access token은 매번 갱신 (보안) Refresh token 만료 감지 → 자동 세션 제거 → 재로그인 유도 빠른 링크 Elio Struyf — Authentication Provider 만들기 Elio Struyf — 외부에서 VS Code 확장으로 콜백 VS Code API — UriHandler 레퍼런스 VS Code — Remote Tunnels 공식 문서 coder/code-server — registerUriHandler 이슈 논의 RFC 6750 — OAuth 2.0 Bearer Token 인사이트 VS Code 확장의 OAuth 구현을 파고들면서 \u0026ldquo;플랫폼 경계\u0026quot;가 얼마나 중요한지 다시 실감했다. vscode:// 프로토콜은 네이티브 데스크탑에서는 완벽히 작동하지만, 브라우저라는 경계를 넘는 순간 OS 수준의 프로토콜 핸들링이 막힌다. code-server가 제안한 /protocol-handler 우회책은 문제를 HTTP 레이어로 내려서 브라우저 제약을 피하는 영리한 접근이다. 한편 Remote Tunnels가 동일한 OAuth 문제를 vscode.dev 도메인 하나로 우아하게 해결하는 방식을 보면, 플랫폼 설계자가 미리 OAuth 리다이렉트를 중앙화한 덕분임을 알 수 있다. AuthenticationProvider API가 확장 개발자에게 노출하는 context.secrets 스토어는 단순해 보이지만, 플랫폼마다 다른 Keychain/Credential Manager를 추상화해준다는 점에서 잘 설계된 인터페이스다.\n","date":"2026-02-25T00:00:00+09:00","image":"/images/posts/2026-02-25-vscode-extension-uri-handler-oauth/cover.jpg","permalink":"/ko/posts/2026-02-25-vscode-extension-uri-handler-oauth/","title":"VS Code 확장 개발: URI Handler로 OAuth 인증 구현하기"},{"content":"개요 데이터베이스 스키마는 프로젝트와 함께 계속 변한다. 테이블을 추가하고, 컬럼을 수정하고, 인덱스를 생성하는 이 과정을 수동으로 관리하면 \u0026ldquo;이 DB에 어떤 변경을 했더라?\u0026rdquo; 같은 질문에 답할 수 없게 된다. Alembic은 SQLAlchemy 기반의 마이그레이션 도구로, 스키마 변경을 코드처럼 버전 관리하고 안전하게 적용/롤백할 수 있게 해준다.\ngraph LR A[모델 변경] --\u003e B[alembic revision] B --\u003e C[마이그레이션 스크립트 생성] C --\u003e D[alembic upgrade] D --\u003e E[DB 스키마 적용] E --\u003e F{문제 발생?} F --\u003e|Yes| G[alembic downgrade] F --\u003e|No| H[완료] G --\u003e A마이그레이션 환경 구조 Alembic을 초기화하면 다음과 같은 디렉토리 구조가 생성된다:\nyourproject/ alembic.ini # 메인 설정 파일 (DB URL, 로깅 등) pyproject.toml # Python 프로젝트 설정 alembic/ env.py # 마이그레이션 실행 환경 (DB 연결, 트랜잭션 관리) README script.py.mako # 마이그레이션 스크립트 생성 템플릿 versions/ # 실제 마이그레이션 스크립트들 3512b954651e_add_account.py 2b1ae634e5cd_add_order_id.py 3adcc9a56557_rename_username_field.py 핵심 파일별 역할 alembic.ini: DB URL, 로깅, 스크립트 경로 등 전체 설정. %(here)s 토큰으로 설정 파일 위치 기준 상대 경로를 지정할 수 있다.\nenv.py: 마이그레이션의 \u0026ldquo;두뇌\u0026rdquo;. SQLAlchemy 엔진 생성, DB 연결, 트랜잭션 관리, 모델 임포트 등을 제어한다. 다중 DB나 커스텀 인자가 필요하면 이 파일을 수정한다.\nscript.py.mako: Mako 템플릿으로, 새 마이그레이션 파일의 뼈대를 정의한다. upgrade()와 downgrade() 함수 구조를 커스텀할 수 있다.\nversions/: 실제 마이그레이션 스크립트가 저장되는 디렉토리. 파일 이름에 정수 시퀀스 대신 부분 GUID를 사용하여 브랜치 간 병합이 가능하다.\n기본 워크플로우 1단계: 환경 초기화 cd /path/to/yourproject alembic init alembic 4가지 템플릿 중 선택 가능:\n템플릿 용도 generic 단일 DB 기본 설정 pyproject pyproject.toml 기반 설정 (v1.16+) async 비동기 DB 드라이버 (asyncpg 등) multidb 다중 DB 환경 2단계: DB 연결 설정 alembic.ini에서 데이터베이스 URL을 설정한다:\nsqlalchemy.url = postgresql://user:pass@localhost/dbname 주의: URL에 % 기호가 포함된 경우 (URL 인코딩된 비밀번호 등) %%로 이스케이프해야 한다. 예: p%40ss → p%%40ss\n3단계: 마이그레이션 스크립트 생성 alembic revision -m \u0026#34;add account table\u0026#34; 이 명령은 versions/ 디렉토리에 새 마이그레이션 파일을 생성한다:\n\u0026#34;\u0026#34;\u0026#34;add account table Revision ID: 3512b954651e Revises: 2b1ae634e5cd Create Date: 2026-02-24 12:00:00.000000 \u0026#34;\u0026#34;\u0026#34; def upgrade(): # 여기에 스키마 변경 코드 작성 pass def downgrade(): # 여기에 롤백 코드 작성 pass 4단계: 마이그레이션 적용 alembic upgrade head # 최신 버전으로 업그레이드 alembic upgrade +2 # 현재 위치에서 2단계 앞으로 5단계: 롤백 alembic downgrade -1 # 1단계 롤백 alembic downgrade base # 모든 마이그레이션 롤백 6단계: 상태 확인 alembic current # 현재 DB가 어느 버전인지 확인 alembic history # 전체 마이그레이션 히스토리 alembic history -r1a:3b # 특정 범위의 히스토리만 조회 알아두면 유용한 기능 부분 Revision ID 명령어에서 Revision ID 전체를 입력할 필요 없이, 고유성이 보장되는 만큼만 입력하면 된다:\nalembic upgrade ae1027a6acf # 전체 ID alembic upgrade ae1 # 이것만으로 충분 (고유하다면) Post-write Hooks 마이그레이션 파일 생성 후 자동으로 코드 포매터를 실행할 수 있다:\n[post_write_hooks] hooks = ruff ruff.type = module ruff.module = ruff ruff.options = check --fix REVISION_SCRIPT_FILENAME black, ruff 등을 연결하면 생성된 마이그레이션 스크립트가 자동으로 포매팅된다.\npyproject.toml 지원 Alembic 1.16부터 pyproject.toml에서 직접 설정을 관리할 수 있다:\nalembic init --template pyproject ./alembic 이 경우 소스 코드 관련 설정은 pyproject.toml에, DB 연결 등 환경별 설정은 alembic.ini에 분리된다.\n빠른 링크 Alembic Tutorial — 공식 튜토리얼 Alembic Cookbook — 실전 레시피 SQLAlchemy — Alembic의 기반 ORM 인사이트 Alembic의 핵심 가치는 \u0026ldquo;DB 스키마 변경을 코드처럼 관리한다\u0026quot;는 것이다. git log로 코드 변경 이력을 추적하듯, alembic history로 스키마 변경 이력을 추적할 수 있다. 특히 팀 개발에서는 \u0026ldquo;이 테이블 언제 추가했지?\u0026rdquo;, \u0026ldquo;이 컬럼 누가 바꿨지?\u0026ldquo;라는 질문에 마이그레이션 스크립트가 답이 된다. 프로젝트 초기부터 Alembic을 도입하면 나중에 스키마 변경이 쌓일 때 큰 빚을 지지 않게 된다. 정수 시퀀스 대신 GUID 기반 버전 관리를 채택한 설계도 주목할 만한데, 이를 통해 여러 브랜치에서 동시에 마이그레이션을 생성해도 병합이 가능하다.\n","date":"2026-02-24T00:00:00+09:00","image":"/images/posts/2026-02-24-alembic-database-migration/cover.jpg","permalink":"/ko/posts/2026-02-24-alembic-database-migration/","title":"Alembic — SQLAlchemy 데이터베이스 마이그레이션 가이드"},{"content":"개요 VS Code 확장(Extension)을 개발할 때 단순히 로컬에서 동작하는 것만으로는 부족하다. Remote Development, GitHub Codespaces 환경에서도 정상 동작해야 하며, 확장이 다루는 시크릿(토큰, API 키)의 보안도 고려해야 한다. 오늘은 VS Code 확장의 원격 개발 아키텍처, 핵심 API, 시크릿 보안 리스크, 그리고 Azure 연동 패턴을 정리한다.\ngraph TD A[VS Code Extension 개발] --\u003e B[Remote Architecture] A --\u003e C[Core API] A --\u003e D[Secret Security] A --\u003e E[Azure Integration] B --\u003e F[UI Extension - 로컬 실행] B --\u003e G[Workspace Extension - 원격 실행] D --\u003e H[SecretStorage API] D --\u003e I[Keytar / Keychain]VS Code Remote Extension 아키텍처 UI Extension vs Workspace Extension VS Code는 원격 개발 시 확장을 두 가지 종류로 구분한다:\n종류 실행 위치 역할 예시 UI Extension 로컬 머신 VS Code UI 기여 (테마, 키맵, 스니펫) Color Theme, Vim keybinding Workspace Extension 원격 머신 파일 접근, 도구 실행, 언어 서버 Python, ESLint, GitLens VS Code는 package.json의 내용을 분석하여 확장을 자동으로 올바른 위치에 설치한다. 자동 감지가 실패할 경우 extensionKind 속성을 명시적으로 지정할 수 있다:\n{ \u0026#34;extensionKind\u0026#34;: [\u0026#34;workspace\u0026#34;] } Developer: Show Running Extensions 명령을 사용하면 각 확장이 실제로 어디서 실행 중인지 확인할 수 있다.\n원격 환경에서의 주요 이슈 1. 시크릿 저장\n원격 환경에서는 로컬 Keychain에 접근할 수 없다. VS Code의 SecretStorage API를 사용하면 로컬/원격 여부에 관계없이 안전하게 시크릿을 관리할 수 있다.\n2. Webview 리소스 경로\nWebview에서 로컬 리소스를 참조할 때 반드시 asWebviewUri()를 사용해야 한다. 원격 환경에서는 파일 경로가 달라지기 때문에, 직접 경로를 하드코딩하면 리소스 로드에 실패한다.\n3. localhost 포워딩\n원격 머신의 localhost 포트에 접근하려면 VS Code의 포트 포워딩 기능을 활용해야 한다. Webview에서 localhost를 사용해야 할 경우:\nOption 1: asExternalUri로 URI를 변환 Option 2: portMapping 옵션으로 포트 매핑 설정 4. 확장 간 통신\n원격과 로컬에서 실행되는 확장끼리는 직접 API를 호출할 수 없다. 대신 VS Code의 commands API를 통해 통신해야 한다:\n{ \u0026#34;api\u0026#34;: \u0026#34;none\u0026#34; } 이 설정을 package.json에 추가하면 API export를 비활성화하고, 명령 기반 통신으로 전환할 수 있다.\n디버깅 환경 원격 확장을 테스트할 수 있는 네 가지 환경이 제공된다:\nGitHub Codespaces — 클라우드 기반 개발 환경 Dev Containers — 커스텀 Docker 컨테이너 SSH — 원격 서버 연결 WSL — Windows Subsystem for Linux 미공개 확장을 테스트하려면 vsce package로 VSIX 파일을 생성한 후 수동 설치할 수 있다.\nVS Code API 핵심 네임스페이스 VS Code API Reference는 확장 개발에 사용할 수 있는 전체 API를 제공한다. 주요 네임스페이스를 정리한다:\n네임스페이스 역할 vscode.authentication 인증 세션 관리 vscode.commands 명령 등록 및 실행 vscode.window 에디터, 터미널, 알림 UI vscode.workspace 파일 시스템, 설정, 워크스페이스 관리 vscode.languages 언어 기능 (자동완성, 진단, 심볼) vscode.debug 디버거 연동 vscode.env 환경 정보 (clipboard, URI 열기) vscode.chat AI/Chat 기능 통합 확장 개발에서 자주 쓰이는 패턴 CancellationToken: 장시간 실행되는 작업에는 항상 CancellationToken을 받아 취소 가능하게 만들어야 한다.\nDisposable: 리소스 해제를 위해 Disposable 인터페이스를 구현하고, context.subscriptions.push()로 등록한다.\nEventEmitter: 커스텀 이벤트를 발행하려면 EventEmitter\u0026lt;T\u0026gt;를 사용한다.\nVS Code 시크릿 보안 — 숨겨진 리스크 Cycode의 보안 분석에 따르면, VS Code 확장의 시크릿 관리에는 주의가 필요한 보안 리스크가 있다.\n시크릿 저장 메커니즘 VS Code는 OS별 Keychain/Keyring을 통해 시크릿을 저장한다:\nmacOS: Keychain Windows: Credential Manager Linux: libsecret (GNOME Keyring 등) 확장은 context.secrets (SecretStorage API)를 통해 이 저장소에 접근할 수 있다.\n보안 리스크 1. Electron 프로세스를 통한 추출\nVS Code는 Electron 기반이므로, 특정 플래그를 사용하면 시크릿에 접근할 수 있는 경로가 존재한다:\nELECTRON_RUN_AS_NODE=1 \u0026#34;${electronPath}\u0026#34; \\ --ms-enable-electron-run-as-node \u0026#34;${vscodeDecryptScriptPath}\u0026#34; ${machineId} 2. 악성 확장을 통한 노출\n설치된 확장은 SecretStorage API에 접근할 수 있으므로, 검증되지 않은 확장 설치 시 저장된 토큰이 노출될 위험이 있다.\n보안 모범 사례 항상 SecretStorage API 사용 — 환경 변수나 설정 파일에 시크릿을 저장하지 말 것 확장 권한 최소화 — 필요한 scope만 요청 검증된 확장만 설치 — Marketplace에서 게시자 인증 확인 정기적 토큰 교체 — 장기간 사용하는 토큰은 주기적으로 갱신 Azure Resources 확장 — 인증 연동 패턴 Azure Resources 확장은 VS Code 내에서 Azure 리소스를 관리하는 확장이다. 확장 개발 시 인증 패턴의 좋은 참고가 된다.\n인증 흐름 Azure Resources 뷰에서 \u0026ldquo;Sign in to Azure\u0026hellip;\u0026rdquo; 클릭 VS Code 내장 Microsoft 인증 프로바이더 사용 MFA(다단계 인증)가 필요한 테넌트는 Accounts \u0026amp; Tenants 뷰에서 별도 인증 여러 Azure 계정을 동시에 사용 가능 주요 설정 azureResourceGroups.selectedSubscriptions — 표시할 구독 필터링 Microsoft-sovereign-cloud.environment — 소버린 클라우드(정부용 Azure 등) 접속 시 자동 설정 이 패턴은 자체 확장에서 외부 서비스 인증을 구현할 때 참고할 수 있는 좋은 레퍼런스다.\n빠른 링크 VS Code Remote Extensions 가이드 — 원격 개발 확장 완전 가이드 VS Code API Reference — 전체 API 레퍼런스 Cycode: VS Code 시크릿 보안 — 시크릿 추출 리스크 분석 Azure Resources Extension — Azure 연동 가이드 인사이트 VS Code 확장 개발은 단순히 \u0026ldquo;로컬에서 동작하는 플러그인\u0026quot;을 만드는 것이 아니다. Remote Development와 Codespaces가 표준이 된 지금, 확장은 **\u0026ldquo;어디서 실행되든 동작하는 분산 컴포넌트\u0026rdquo;**로 설계해야 한다. UI Extension과 Workspace Extension의 구분을 이해하는 것이 첫걸음이고, 시크릿 관리는 처음부터 SecretStorage API를 사용하는 것이 정답이다. 보안은 나중에 추가하는 것이 아니라 설계 단계에서 내장해야 하며, Cycode의 분석처럼 Electron 기반 앱에서의 시크릿 추출 경로를 인지하고 있어야 한다.\n","date":"2026-02-24T00:00:00+09:00","image":"/images/posts/2026-02-24-vscode-extension-auth-security/cover.jpg","permalink":"/ko/posts/2026-02-24-vscode-extension-auth-security/","title":"VS Code 확장 개발 — Remote Extension 아키텍처부터 시크릿 보안까지"},{"content":"개요 소프트웨어 아키텍처 선택은 프로젝트의 성패를 좌우하는 핵심 결정이다. 모놀리식 아키텍처(MA)와 마이크로서비스 아키텍처(MSA)는 각각의 장단점이 뚜렷하며, \u0026ldquo;어느 쪽이 더 좋다\u0026quot;가 아니라 **\u0026ldquo;지금 상황에 무엇이 맞는가\u0026rdquo;**가 올바른 질문이다.\ngraph TD A[아키텍처 결정] --\u003e B{프로젝트 규모?} B --\u003e|소규모/MVP| C[모놀리식 아키텍처] B --\u003e|대규모/복잡| D[마이크로서비스 아키텍처] C --\u003e E[단일 코드 베이스 + 단일 DB] D --\u003e F[독립 서비스 + 서비스별 DB] C --\u003e G[빠른 초기 개발] D --\u003e H[유연한 확장과 배포]모놀리식 아키텍처 (Monolithic Architecture) 모놀리식 아키텍처는 모든 비즈니스 로직이 하나의 통합된 코드 베이스에 존재하는 전통적인 구조다. 단일 애플리케이션 안에 인증, 결제, 알림 등 모든 기능이 포함되어 있다.\ngraph LR subgraph \"단일 애플리케이션\" A[인증] --- B[상품] B --- C[결제] C --- D[알림] end subgraph \"인프라\" E[(단일 DB)] end A --\u003e E B --\u003e E C --\u003e E D --\u003e E장점 장점 설명 빠른 개발 코드베이스가 단순하고 통합이 쉬워 초기 개발 속도가 빠르다 간단한 유지보수 단일 코드 베이스에서 변경 사항 적용이 쉽다 낮은 인프라 비용 단일 애플리케이션으로 운영하므로 인프라 복잡성이 낮다 쉬운 디버깅 모든 코드가 한 곳에 있어 문제 추적이 용이하다 네트워크 지연 없음 서비스 간 통신이 함수 호출이므로 네트워크 오버헤드가 없다 기술 스택 통일 팀 전체가 같은 기술을 사용하므로 온보딩이 쉽다 단점 단점 설명 부분 확장 불가 특정 기능만 확장할 수 없고 전체를 확장해야 한다 전체 재배포 필요 작은 변경도 전체 앱을 다시 배포해야 한다 기술 스택 제한 새로운 기술 도입이 어렵다 복잡성 증가 프로젝트 성장 시 코드베이스가 방대해진다 팀 간 충돌 같은 코드에서 작업하므로 병합 충돌이 빈번하다 적합한 경우: 소규모 프로젝트, 빠른 MVP 개발, 복잡한 비즈니스 로직이 불필요할 때, 변경이 적은 시스템\n모놀리식 아키텍처의 장점은 주로 소규모 프로젝트에서 부각되며, 프로젝트 규모가 커질수록 이 장점들이 오히려 단점으로 전환된다.\n마이크로서비스 아키텍처 (Microservices Architecture) 마이크로서비스 아키텍처는 애플리케이션을 여러 작고 독립적인 서비스로 분리하는 구조다. 각 서비스는 특정 비즈니스 기능을 담당하고, API를 통해 통신한다. 대규모 개발팀의 조직 구조에 맞게 설계된 아키텍처다.\ngraph TD subgraph \"API Gateway\" GW[Gateway] end subgraph \"독립 서비스들\" S1[인증 서비스Node.js] S2[상품 서비스Python] S3[결제 서비스Go] S4[알림 서비스Java] end subgraph \"서비스별 DB\" D1[(Auth DB)] D2[(Product DB)] D3[(Payment DB)] D4[(Notification DB)] end GW --\u003e S1 GW --\u003e S2 GW --\u003e S3 GW --\u003e S4 S1 --\u003e D1 S2 --\u003e D2 S3 --\u003e D3 S4 --\u003e D4장점 독립적 배포: 각 서비스를 개별적으로 개발, 테스트, 배포 가능 기술 다양성: 서비스별로 최적의 기술 스택 선택 가능 선택적 확장: 수요가 높은 서비스만 독립적으로 스케일링 — 예를 들어 뉴스 서비스 사용자가 1명이고 웹툰 서비스 사용자가 1억 명일 때 웹툰 서비스만 확장 가능 장애 격리: 한 서비스의 장애가 전체 시스템에 영향을 미치지 않음 쉬운 유지보수: 특정 서비스 변경이 다른 서비스에 미치는 영향이 적음 단점 운영 복잡성: 서비스 디스커버리, 로깅, 분산 추적 관리 필요 데이터 일관성: 분산 트랜잭션 처리가 어려움 테스트 어려움: 통합 테스트와 E2E 테스트의 복잡도 증가 시스템 전반 복잡성: 전체 시스템을 이해하는 데 추가적인 노력 필요 전환 비용: 기존 모놀리식에서 MSA로의 전환에 상당한 비용과 시간 소요 네트워크 지연: 서비스 간 통신으로 인한 지연 발생 적합한 경우: 대규모 및 복잡한 시스템, 독립적인 개발 팀 존재, 유연한 확장 필요\n핵심 비교 정리 항목 모놀리식 마이크로서비스 구조 단일 코드 베이스, 기능 간 강한 의존 독립 서비스 + API 통신, 분산 시스템 배포 전체 재배포 서비스별 독립 배포 기술 스택 전체 통일 서비스별 자유 선택 확장 전체 확장만 가능 서비스별 선택적 확장 지연 시간 없음 (내부 함수 호출) 네트워크 통신 지연 존재 디버깅 단일 코드에서 추적 용이 분산 추적 도구 필요 팀 구조 소규모 팀에 적합 독립 팀 조직에 적합 빠른 링크 모놀리식 vs MSA 비교 (Korean) — 장단점 상세 정리 Martin Fowler: Microservices — MSA 개념 정의의 원조 인사이트 아키텍처 선택에서 가장 흔한 실수는 \u0026ldquo;MSA가 최신이니까 무조건 MSA\u0026quot;라는 생각이다. 소규모 프로젝트에서 MSA를 적용하면 서비스 간 통신, 분산 트랜잭션, 로깅 등 불필요한 복잡성만 늘어난다. 반대로, 사용자가 급증하는 대규모 시스템에서 모놀리식을 고수하면 특정 기능만 확장할 수 없어 전체 인프라를 키워야 하는 비효율이 발생한다. 핵심은 **\u0026ldquo;지금 우리 팀의 규모와 프로젝트의 복잡도에 맞는 선택\u0026rdquo;**이며, 많은 성공적인 프로젝트가 모놀리식으로 시작해서 필요 시점에 MSA로 전환하는 점진적 접근을 택한다.\n","date":"2026-02-24T00:00:00+09:00","image":"/images/posts/2026-02-24-monolithic-vs-microservices/cover.jpg","permalink":"/ko/posts/2026-02-24-monolithic-vs-microservices/","title":"모놀리식 vs 마이크로서비스 — 아키텍처 선택의 기준"},{"content":"개요 오늘은 두 가지 주제를 집중적으로 탐구했다. 첫째, gemini-3-pro-image-preview 모델로 이미지 생성 API를 직접 구축하면서 생긴 궁금증들 — 해상도 비용 구조, Thought Signatures, 신규 파라미터 등을 Gemini 3 공식 문서로 정리했다. 둘째, 아키텍처 문서화 도구로 Mermaid.js를 탐색하며 주요 다이어그램 타입별 문법을 정리했다.\nGemini 3 모델 패밀리와 가격 Gemini 3는 현재 프리뷰 상태이지만 실제로 쓸 수 있는 수준이다. 모델별 스펙은 다음과 같다.\n모델 ID 컨텍스트 (In/Out) 가격 (입력/출력) gemini-3.1-pro-preview 1M / 64k $2 / $12 (200k 이하) gemini-3-pro-preview 1M / 64k $2 / $12 (200k 이하) gemini-3-flash-preview 1M / 64k $0.50 / $3 gemini-3-pro-image-preview 65k / 32k $2 (텍스트 입력) / $0.134 (이미지 출력)** 이미지 모델의 경우 출력 이미지 1장당 $0.134가 기준이지만, 해상도에 따라 달라진다. 1K가 기본이고 4K로 갈수록 비용이 증가한다. 정확한 해상도별 비용은 별도 pricing 페이지를 참조해야 한다.\nNano Banana Pro — Gemini 3 이미지 생성의 핵심 Google이 공식적으로 \u0026ldquo;Nano Banana\u0026quot;라는 코드명을 쓰는 게 독특한데, 이 이름은 Gemini의 네이티브 이미지 생성 기능 전체를 가리킨다. 두 가지 모델이 있다:\nNano Banana: gemini-2.5-flash-image — 속도·효율 중심, 대량 처리에 적합 Nano Banana Pro: gemini-3-pro-image-preview — 프로 에셋 생산용, Thinking 기반 고품질 Gemini 3 Pro Image가 기존 Imagen과 다른 점은 추론(Thinking) 과정이 이미지 생성에 통합된다는 것이다. 복잡한 프롬프트를 받으면 모델이 내부적으로 \u0026ldquo;thought images\u0026quot;를 최대 2장 생성해 구도와 로직을 검증한 뒤 최종 이미지를 출력한다. 이 중간 이미지는 과금되지 않는다.\n주요 신기능 1. 최대 14개 레퍼런스 이미지\ngemini-3-pro-image-preview는 레퍼런스 이미지를 최대 14개까지 받을 수 있다:\n오브젝트 고해상도 이미지: 최대 6개 인물 캐릭터 일관성 유지: 최대 5개 이를 활용하면 특정 제품이나 캐릭터의 일관성을 유지하면서 다양한 씬을 생성할 수 있다.\n2. 해상도 제어 — 1K / 2K / 4K\n기본은 1K 출력이며, generation_config에서 image_size를 지정해 올릴 수 있다. 주의할 점은 반드시 대문자 K를 써야 한다는 것 — 1k로 쓰면 에러가 난다.\ngeneration_config = { \u0026#34;image_size\u0026#34;: \u0026#34;2K\u0026#34; # \u0026#34;1K\u0026#34;, \u0026#34;2K\u0026#34;, \u0026#34;4K\u0026#34; 가능. 소문자 불가! } 3. Google Search Grounding\ngoogle_search 툴을 연결하면 실시간 정보 기반 이미지를 생성할 수 있다. 날씨 예보 차트, 주가 그래프, 최근 뉴스 기반 인포그래픽 등이 가능하다. 단, 이미지 기반 검색 결과는 생성 모델에 전달되지 않으며 응답에서도 제외된다.\nHybrid Image Search API — FastAPI로 감싸기 오늘 localhost:8000에서 실행 중인 Hybrid Image Search API의 Swagger UI를 통해 직접 테스트했다. gemini-3-pro-image-preview를 백엔드로 쓰는 FastAPI 서버로, /api/generate_image 엔드포인트가 핵심이다. 이미지 프롬프트를 받아 Gemini API를 호출하고 결과를 반환하는 구조다.\ngraph LR Client --\u003e|POST /api/generate_image| FastAPI FastAPI --\u003e|generateContent| Gemini3ProImage[gemini-3-pro-image-preview] Gemini3ProImage --\u003e|image + thought_signature| FastAPI FastAPI --\u003e|base64 image| ClientSwagger UI로 엔드포인트를 직접 실행해보면 응답 스키마에서 thought_signature 필드를 확인할 수 있는데, 멀티턴 편집 세션을 유지하려면 이 값을 다음 요청에 포함시켜야 한다.\nThought Signatures — 멀티턴 편집의 핵심 메커니즘 이미지 생성 API를 처음 쓸 때 가장 헷갈리는 부분이 Thought Signatures다. 이게 뭔지 이해하면 멀티턴(대화형) 이미지 편집이 왜 그렇게 동작하는지 명확해진다.\nThought Signature는 모델의 내부 추론 과정을 암호화한 문자열이다. 모델이 이미지를 생성하면 응답에 thought_signature 필드가 포함되는데, 다음 요청을 보낼 때 이 값을 그대로 돌려줘야 한다. 그래야 모델이 이전 이미지의 구도·로직을 기억하면서 편집할 수 있다.\n이미지 생성 요청 → 응답에 thought_signature 포함 → \u0026#34;배경을 석양으로 바꿔줘\u0026#34; 요청 시 thought_signature 같이 전송 → 모델이 구도 컨텍스트를 유지하며 편집 이미지 생성/편집에서는 strict validation이 적용된다 — signature를 빼먹으면 400 에러가 발생한다. 공식 Python/Node/Java SDK를 쓰고 chat history를 그대로 넘기면 자동 처리되니, SDK 없이 raw REST를 쓸 때만 직접 관리해야 한다.\nGemini 2.5에서 마이그레이션 시 주의사항 기존 Gemini 2.5 conversation trace를 그대로 쓰거나 커스텀 function call을 주입할 경우 유효한 signature가 없다. 이때는 dummy 값으로 우회할 수 있다:\n\u0026#34;thoughtSignature\u0026#34;: \u0026#34;context_engineering_is_the_way to_go\u0026#34; Gemini 3의 새 API 파라미터들 thinking_level — 모델 추론 깊이 제어\n레벨 설명 minimal Flash만 지원. thinking 최소화, 지연 최소 low 간단한 지시 따르기, 고처리량 앱에 적합 medium 균형잡힌 추론 high 기본값. 추론 최대화, 응답이 느릴 수 있음 thinking_level과 구형 thinking_budget 파라미터를 동시에 쓰면 400 에러가 발생한다.\nmedia_resolution — 멀티모달 비전 처리 정밀도 제어\n이미지 분석은 media_resolution_high (1120 토큰/이미지), PDF는 media_resolution_medium (560 토큰)이 권장값이다. 비용과 품질의 트레이드오프를 명시적으로 제어할 수 있게 됐다.\nTemperature 주의사항: Gemini 3는 기본값 1.0에 최적화되어 있다. 기존 코드에서 결정론적 출력을 위해 낮은 temperature를 설정했다면 반드시 제거해야 한다. 낮은 temperature에서 루프나 성능 저하가 발생할 수 있다.\nLLM 토큰 \u0026amp; 비용 계산 도구 이미지 생성 비용을 예측할 때 텍스트 토큰뿐 아니라 이미지 출력 비용을 함께 고려해야 한다. 유용한 도구들:\ntoken-calculator.net — GPT, Claude, Gemini 등 주요 LLM 토큰 수 계산 및 비용 추정. 2026년 기준 최신 모델까지 반영됨. OpenAI Tokenizer — OpenAI 공식 토크나이저. 텍스트가 실제로 어떤 토큰으로 분할되는지 시각화. Gemini 3 Pro Image의 경우 이미지 1장 출력이 $0.134이고 해상도에 따라 추가 과금된다. 고해상도 이미지를 대량 생성하는 프로덕션 환경이라면 Batch API를 활용하면 더 높은 rate limit을 대신 최대 24시간 지연을 허용하는 방식으로 비용을 관리할 수 있다.\nMermaid.js — 텍스트로 다이어그램 그리기 Mermaid.js는 Markdown처럼 텍스트로 다이어그램을 정의하는 JavaScript 라이브러리다. GitHub, GitLab, Notion, 그리고 이 블로그처럼 Hugo에서도 코드 블록 하나로 SVG 다이어그램을 렌더링할 수 있다. 별도 드로잉 도구 없이 코드베이스에 아키텍처 문서를 함께 관리할 수 있다는 점이 핵심 장점이다.\n사용법은 간단하다. ```mermaid 코드 블록 안에 다이어그램 정의를 쓰면 된다.\nFlowchart — 가장 범용적인 다이어그램 흐름도, 의사결정 트리, 시스템 아키텍처 등에 쓰인다. 첫 줄에 방향을 선언한다.\ngraph TD %% Top → Down graph LR %% Left → Right graph BT %% Bottom → Top graph RL %% Right → Left 노드 모양\nA[사각형] B(둥근 모서리) C([스타디움]) D[[서브루틴]] E[(실린더 / DB)] F((원형)) G{마름모 / 결정} H{{육각형}} I[/평행사변형/] J[\\역평행사변형\\] 연결선 종류\nA --\u0026gt; B %% 화살표 A --- B %% 선만 A -.- B %% 점선 A ==\u0026gt; B %% 굵은 화살표 A --\u0026gt;|레이블| B %% 레이블 있는 화살표 A --o B %% 원 끝 A --x B %% X 끝 서브그래프 (영역 묶기)\ngraph LR subgraph Backend API --\u0026gt; DB end subgraph Frontend UI --\u0026gt; API end 실제 예시 — Gemini 이미지 생성 흐름:\ngraph TD A[사용자 프롬프트] --\u003e B{해상도 선택} B --\u003e|1K| C[image_size: 1K] B --\u003e|2K| D[image_size: 2K] B --\u003e|4K| E[image_size: 4K] C \u0026 D \u0026 E --\u003e F[gemini-3-pro-image-preview] F --\u003e G[Thinking: thought images x2 생성] G --\u003e H[최종 이미지 출력] H --\u003e I[thought_signature 반환] I --\u003e|멀티턴 편집 시 재사용| FSequence Diagram — 서비스 간 통신 흐름 API 호출 시퀀스, 인증 플로우, 마이크로서비스 간 메시지 흐름을 표현할 때 쓴다.\n기본 문법\nsequenceDiagram participant A as 클라이언트 participant B as 서버 participant C as DB A-\u0026gt;\u0026gt;B: 요청 (실선 화살표) B--\u0026gt;\u0026gt;A: 응답 (점선 화살표) A-)B: 비동기 (열린 화살표) 화살표 타입 10가지\n문법 의미 -\u0026gt; 실선, 화살촉 없음 --\u0026gt; 점선, 화살촉 없음 -\u0026gt;\u0026gt; 실선, 화살촉 있음 --\u0026gt;\u0026gt; 점선, 화살촉 있음 \u0026lt;\u0026lt;-\u0026gt;\u0026gt; 실선, 양방향 화살촉 -x 실선, X 끝 (비동기) -) 실선, 열린 화살촉 (비동기) 활성화 박스 (Activation)\nsequenceDiagram A-\u0026gt;\u0026gt;+B: 요청 시작 B--\u0026gt;\u0026gt;-A: 응답 (B의 활성 구간 표시) 루프, 조건, 병렬\nloop 재시도 3회 A-\u0026gt;\u0026gt;B: 요청 end alt 성공 B--\u0026gt;\u0026gt;A: 200 OK else 실패 B--\u0026gt;\u0026gt;A: 500 Error end par 병렬 처리 A-\u0026gt;\u0026gt;B: 작업 1 and A-\u0026gt;\u0026gt;C: 작업 2 end Note와 배경 강조\nNote right of A: 여기서 토큰 검증 Note over A,B: 두 참여자에 걸친 노트 rect rgb(200, 220, 255) A-\u0026gt;\u0026gt;B: 강조 영역 end Class Diagram — OOP 설계 문서화 클래스 구조, 상속 관계, 인터페이스를 표현한다.\n클래스 정의와 멤버\nclassDiagram class Animal { +String name -int age #String species +speak() String +move()* void %% abstract +clone()$ Animal %% static } 멤버 가시성: + public, - private, # protected, ~ package 분류자: * abstract, $ static\n제네릭 타입\nclass Stack~T~ { +push(item: T) +pop() T +peek() T } 관계 타입\n문법 관계 설명 A \u0026lt;|-- B 상속 (Inheritance) B는 A를 상속 A *-- B 합성 (Composition) B는 A의 일부 A o-- B 집합 (Aggregation) B는 A에 포함 A --\u0026gt; B 연관 (Association) A가 B를 사용 A ..\u0026gt; B 의존 (Dependency) A가 B에 의존 A ..|\u0026gt; B 실현 (Realization) A가 B 인터페이스 구현 카디널리티\nclassDiagram Customer \u0026#34;1\u0026#34; --\u0026gt; \u0026#34;0..*\u0026#34; Order : places Order \u0026#34;1\u0026#34; *-- \u0026#34;1..*\u0026#34; OrderItem : contains ER Diagram — 데이터베이스 스키마 엔티티-관계 다이어그램으로 DB 설계를 문서화한다.\n기본 문법\nerDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE-ITEM : contains CUSTOMER { string name PK string email UK int age } ORDER { int id PK date created_at int customer_id FK } 관계 카디널리티 기호\n왼쪽 오른쪽 의미 |o o| 0 또는 1 || || 정확히 1 }o o{ 0 이상 }| |{ 1 이상 식별 관계(실선 --)와 비식별 관계(점선 ..)로 구분한다.\n주요 활용 팁 %% 는 모든 다이어그램 타입에서 주석 direction TB/LR 으로 대부분의 다이어그램 방향 변경 가능 노드 ID에는 공백 불가 — 레이블은 [텍스트]로 분리 복잡한 다이어그램은 Mermaid Live Editor에서 실시간 미리보기 가능 빠른 링크 Gemini API — Nano Banana Image Generation — 공식 이미지 생성 가이드 (프롬프팅 전략, 코드 예제 포함) Gemini 3 Developer Guide — Gemini 3 전체 API 가이드 (pricing, 파라미터, 마이그레이션) Token Calculator — LLM 토큰 수 및 비용 계산기 OpenAI Tokenizer — 토크나이저 시각화 도구 Mermaid.js — 공식 문서 (Flowchart, Sequence, Class, ER 등 다이어그램 타입별 문법 레퍼런스) Mermaid Live Editor — 브라우저에서 실시간 미리보기 인사이트 오늘 탐색한 두 주제는 사실 한 가지 공통점을 가진다 — 텍스트로 복잡한 것을 표현하기. Gemini 3 Pro Image는 텍스트 프롬프트로 이미지를 생성하되, Thought Signatures라는 메커니즘으로 편집 세션의 컨텍스트를 텍스트로 직렬화해 보존한다. Mermaid.js는 아키텍처나 데이터 흐름 같은 시각적 개념을 텍스트 문법으로 표현해 코드와 함께 버전 관리할 수 있게 한다. 특히 FastAPI 서버에 Gemini 이미지 생성을 래핑하면서 아키텍처가 복잡해지는 시점에 Mermaid의 Flowchart와 Sequence Diagram은 팀 커뮤니케이션 비용을 줄이는 실용적인 선택이다. 다이어그램 타입별로 용도가 뚜렷이 나뉘므로 — 흐름도는 Flowchart, API 통신은 Sequence, 데이터 모델은 ER — 상황에 맞게 골라 쓰는 것이 핵심이다.\n","date":"2026-02-20T00:00:00+09:00","image":"/images/posts/2026-02-20-tech-log/cover.jpg","permalink":"/ko/posts/2026-02-20-tech-log/","title":"Gemini 3 이미지 생성 API + Mermaid.js 다이어그램 문법 정리"},{"content":"개요 AI 코딩 도구가 점점 강력해지고 있지만, 프로젝트 맥락을 체계적으로 관리하고 주입하는 것은 여전히 어렵다. Cole Medin의 Archon은 이 문제를 MCP 서버 패턴으로 해결하려는 도구다.\nArchon이란? Archon은 AI 코딩 어시스턴트를 위한 커맨드 센터다. GitHub 스타 13,700개 이상을 기록 중인 이 프로젝트는 Claude Code, Cursor, Windsurf 같은 AI 코딩 도구에 커스텀 지식 베이스와 태스크 관리 기능을 MCP(Model Context Protocol) 서버로 제공한다.\n사용자에게는 지식과 태스크를 관리하는 깔끔한 웹 인터페이스이고, AI 코딩 어시스턴트에게는 같은 지식과 태스크에 접근할 수 있는 MCP 서버다.\n아키텍처 graph LR A[UI :3737] --\u003e B[Server :8181] B --\u003e C[MCP Server :8051] C --\u003e D[Claude Code / Cursor / Windsurf] B --\u003e E[Supabase DB]세 개의 마이크로서비스로 구성된다:\nServer (Python): 핵심 API와 비즈니스 로직. 웹 크롤링, PDF 업로드, RAG(Retrieval-Augmented Generation) 검색을 처리 MCP Server: AI 코딩 어시스턴트가 연결하는 프로토콜 인터페이스 UI (TypeScript): 지식 베이스 관리, 프로젝트/태스크 관리를 위한 웹 인터페이스 Docker Compose로 원커맨드 셋업이 가능하고, Supabase를 백엔드 DB로 사용한다.\n주요 기능 문서 관리: 웹사이트 크롤링, PDF/문서 업로드로 지식 베이스 구축 스마트 검색: 고급 RAG 전략으로 관련 문서를 검색 태스크 관리: 지식 베이스와 통합된 프로젝트/태스크 관리 실시간 업데이트: 콘텐츠 추가 시 즉시 AI 어시스턴트에 반영 기술 스택 영역 기술 Backend Python (2.3M+ LOC) Frontend TypeScript (1.8M+ LOC) Database Supabase (PostgreSQL + PLpgSQL) Infra Docker, Make LLM OpenAI, Gemini, Ollama, OpenRouter 최근 OpenRouter 임베딩 지원이 추가되어 벤더 종속 없이 자유롭게 모델을 선택할 수 있다.\n셋업 git clone -b stable https://github.com/coleam00/archon.git cd archon cp .env.example .env # .env에 Supabase 자격 증명 추가 docker compose up --build -d 셋업 후 http://localhost:3737에서 온보딩 플로우를 따라 API 키를 설정하면 바로 사용할 수 있다.\n참고 자료 The OFFICIAL Archon Guide (23분) — 설치부터 실제 워크플로우까지 GitHub Discussions — 커뮤니티 Archon Kanban Board — 개발 현황 인사이트 Archon이 보여주는 MCP 서버 패턴은 AI 코딩 도구의 미래 방향을 보여준다. 단순히 코드를 생성하는 것을 넘어, 프로젝트 맥락과 지식을 체계적으로 관리하고 AI에 주입하는 것이 핵심이다. \u0026ldquo;Context Engineering\u0026quot;이라는 개념이 점점 중요해지고 있으며, Archon은 이를 실용적으로 구현한 좋은 사례다.\n","date":"2026-02-19T00:00:00+09:00","image":"/images/posts/2026-02-19-archon-ai-coding-command-center/cover.jpg","permalink":"/ko/posts/2026-02-19-archon-ai-coding-command-center/","title":"Archon — AI 코딩 어시스턴트의 지휘본부"},{"content":"개요 Hugo 블로그 테마를 본격적으로 비교하고, GitHub Pages로 블로그를 구축하는 과정을 정리했다. PaperMod와 Stack을 중심으로 8개 이상의 테마를 살펴보며, Hugo + GitHub Pages 조합의 셋업 워크플로우를 파악했다.\nHugo 테마 비교 themes.gohugo.io에서 다양한 테마를 탐색하고 비교했다.\nPaperMod — 가장 인기 있는 선택 hugo-PaperMod | 스타 13,100+ | 포크 3,300+\nHugo 생태계에서 가장 인기 있는 테마다. \u0026ldquo;Fast, Clean, Responsive\u0026quot;를 표방하며, webpack이나 Node.js 의존성 없이 순수 Hugo 기능만으로 동작한다.\n핵심 특징:\nRegular / Home-Info / Profile 세 가지 모드 Fuse.js 기반 클라이언트 사이드 검색 다국어 지원 + SEO 최적화 라이트/다크 테마 자동 전환 코드 블록 복사 버튼, 목차 자동 생성 Breadcrumb 내비게이션 최근 주목할 변경:\nllms.txt 파일 지원 추가 — LLM이 블로그 콘텐츠를 효율적으로 인덱싱할 수 있게 해주는 업계 표준 테마 결정 로직을 head.html로 리팩토링하여 스크립트 실행 속도 개선 라이브 데모 | 설치 가이드\nStack — 카드 스타일 블로거 테마 hugo-theme-stack | 스타 6,200+ | 포크 1,900+\n카드 스타일 레이아웃이 특징인 블로거 전용 테마. 시각적으로 풍부한 블로그를 원하는 경우 좋은 선택이다.\n최근 주목할 변경:\nMarkdown Alert 지원 (GitHub 스타일 \u0026gt; [!NOTE], \u0026gt; [!WARNING] 등) Generic taxonomy widget 리팩토링으로 확장성 향상 커스텀 canonical URL 설정 기능 추가 i18n 지원 확대 라이브 데모 | 문서\n테마 비교 요약 테마 스타 특징 적합한 용도 PaperMod 13.1K 미니멀, 빠름, SEO 최적화 기술 블로그, 포트폴리오 Stack 6.2K 카드 UI, 풍부한 시각 일반 블로그, 사진 블로그 Coder - 극도로 미니멀 개발자 포트폴리오 Book - 문서 사이드바 기술 문서 사이트 Docsy - Google 후원, 대규모 기업 기술 문서 Terminal - 레트로 터미널 스타일 개성 있는 개발 블로그 Blox-Tailwind - Tailwind CSS 기반 현대적 디자인 블로그 Compose - 깔끔한 다목적 범용 블로그 Hugo + GitHub Pages 구축 가이드 Integerous의 가이드를 참고하여 구축 워크플로우를 정리했다.\nStatic Site Generator 선택 배경 Jekyll — Ruby 기반, 가장 인기, 한글 레퍼런스 많음, 빌드 느림 Hexo — Node.js 기반, 중국어 자료 많음, 메인 개발 부진 Hugo — Go 기반, 빌드 가장 빠름, 문서화 잘됨, 한글 레퍼런스 적음 Hugo는 런타임 의존성 없이 빌드 시간이 가장 빠르고, 문서화가 잘 되어 있어 선택했다.\n구축 흐름 graph TD A[hugo new site blog] --\u003e B[테마 submodule 추가] B --\u003e C[config.toml 설정] C --\u003e D[hugo new post/글.md] D --\u003e E[hugo server로 로컬 확인] E --\u003e F[hugo 빌드 → public 생성] F --\u003e G[public → username.github.io push] G --\u003e H[소스 → blog repo push]핵심 포인트 1. 저장소 2개 준비\nblog — Hugo 소스 파일 관리 username.github.io — 빌드된 정적 사이트 배포 2. 테마는 반드시 submodule로\n# clone보다 submodule이 권장됨 git submodule add https://github.com/테마/레포.git themes/테마이름 업데이트된 테마를 쉽게 가져올 수 있고, 환경이 바뀌어도 테마를 잃지 않는다. 테마 레포를 먼저 Fork한 후 submodule로 추가하는 것이 가장 좋은 방법이다.\n3. deploy.sh로 배포 자동화 빌드 → public 커밋/푸시 → 소스 커밋/푸시를 쉘 스크립트 하나로 처리.\n4. Utterances 댓글 시스템 GitHub Issues API를 활용한 댓글 시스템. 별도 서버 없이 GitHub 계정으로 댓글을 달 수 있다.\n빠른 링크 Hugo Themes Gallery PaperMod Wiki Stack Documentation Homebrew — macOS 패키지 매니저 (brew install hugo로 설치) VS Code Homebrew Cask 인사이트 Hugo 테마 선택에서 가장 중요한 건 \u0026ldquo;지금 당장 예쁜가\u0026quot;보다 **\u0026ldquo;커뮤니티가 활발한가, 꾸준히 업데이트되는가\u0026rdquo;**다. PaperMod의 llms.txt 지원 추가처럼, 활발한 프로젝트는 시대 변화에 맞춰 계속 진화한다. 테마를 submodule로 관리하는 패턴은 Hugo에 국한되지 않고, 외부 의존성을 프로젝트에 안전하게 통합하는 보편적인 방법이다.\n","date":"2026-02-19T00:00:00+09:00","image":"/images/posts/2026-02-19-hugo-theme-comparison-blog-setup/cover.jpg","permalink":"/ko/posts/2026-02-19-hugo-theme-comparison-blog-setup/","title":"Hugo 블로그 테마 비교 분석 \u0026 GitHub Pages 구축 가이드"},{"content":"개요 매일 브라우저에서 수많은 기술 문서와 GitHub 레포를 탐색하지만, 그 과정은 기록되지 않고 사라진다. log-blog는 Chrome 브라우저 히스토리를 읽어서 Hugo 호환 블로그 포스트로 자동 변환하는 Python CLI 도구다.\nlog-blog란? ice-ice-bear/log-blog는 \u0026ldquo;탐색 → 정리 → 공유\u0026quot;의 사이클을 자동화하는 도구다. Chrome의 SQLite 히스토리 DB에서 데이터를 추출하고, Playwright로 각 URL의 콘텐츠를 수집한 후, Hugo 호환 마크다운으로 변환하여 블로그 레포에 커밋한다.\n파이프라인 구조 graph TD A[Chrome History SQLite DB] --\u003e|extract| B[URL + Title + Timestamp JSON] B --\u003e|AI classify| C[Tech vs Non-tech 분류] C --\u003e|fetch| D[Enriched Content] D --\u003e|AI write| E[Hugo Markdown Post] E --\u003e|publish| F[Git Commit → GitHub Pages]1단계: Extract — 히스토리 추출 log-blog extract --json --hours 24 Chrome의 SQLite 히스토리 DB에서 최근 N시간의 방문 기록을 추출한다. URL, 제목, 방문 횟수, 마지막 방문 시간을 JSON으로 출력한다.\n2단계: Classify — AI 분류 Claude Code의 skill 시스템과 결합하여, AI가 URL을 tech/non-tech으로 분류하고 YouTube, GitHub, Docs/Web으로 그룹핑한다.\n3단계: Fetch — 콘텐츠 수집 log-blog fetch --json \u0026#34;URL1\u0026#34; \u0026#34;URL2\u0026#34; \u0026#34;URL3\u0026#34; URL 타입에 따라 다른 전략으로 콘텐츠를 수집한다:\nURL 타입 수집 내용 YouTube 전체 자막 텍스트 (한국어 우선) GitHub 레포 설명, 스타, 언어, README, 최근 커밋 GitHub PR 제목, 상태, 본문, diff 통계, 댓글 GitHub 이슈 제목, 상태, 라벨, 본문, 댓글 웹 페이지 전체 텍스트, 헤딩 구조, 코드 블록 4단계: Write \u0026amp; Publish — 포스트 생성 및 배포 AI가 수집된 콘텐츠를 바탕으로 기술 블로그 포스트를 작성하고, publish 명령으로 블로그 레포에 커밋한다.\nlog-blog publish post.md # 로컬 커밋 log-blog publish post.md --push # 커밋 + 푸시 기술 스택 src/log_blog/ cli.py # CLI 진입점 (extract, fetch, publish) config.py # YAML 설정 로더 history_reader.py # Chrome SQLite 히스토리 리더 content_fetcher.py # Playwright 기반 콘텐츠 추출기 post_generator.py # Hugo 마크다운 포스트 생성기 publisher.py # Git commit/push Python 3.12+ — 메인 언어 Playwright — 브라우저 자동화로 동적 페이지 콘텐츠 수집 SQLite — Chrome 히스토리 DB 직접 읽기 Claude Code Skill — AI 분류/요약/작성 자동화 설정 chrome: profiles: [\u0026#34;Default\u0026#34;] history_db_base: \u0026#34;~/Library/Application Support/Google/Chrome\u0026#34; time_range_hours: 24 blog: repo_path: \u0026#34;~/Documents/github/ice-ice-bear.github.io\u0026#34; content_dir: \u0026#34;content/posts\u0026#34; language: \u0026#34;auto\u0026#34; playwright: headless: true timeout_ms: 15000 max_concurrent: 5 빠른 링크 mindai/mega-code PR #26 — add_behavioral_validation (Upskill) mindai/megaupskill — MegaUpskill 프로젝트 인사이트 log-blog의 핵심 가치는 **\u0026ldquo;탐색 자체를 콘텐츠로 만든다\u0026rdquo;**는 것이다. 매일 브라우저에서 일어나는 기술 탐색은 이미 학습 과정이지만, 기록하지 않으면 사라진다. 이 도구는 그 과정을 자동으로 포착하고 구조화한다. 바로 지금 이 글이 그 파이프라인으로 만들어졌다 — Chrome 히스토리 추출 → AI 분류 → 콘텐츠 수집 → AI 작성 → 블로그 배포.\n","date":"2026-02-19T00:00:00+09:00","image":"/images/posts/2026-02-19-log-blog-browser-history-automation/cover.jpg","permalink":"/ko/posts/2026-02-19-log-blog-browser-history-automation/","title":"log-blog — 브라우저 히스토리를 블로그 포스트로 자동 변환하기"},{"content":"개요 오늘은 Hugo 블로그 테마를 본격적으로 탐색하며 블로그 리뉴얼을 구상했고, 바이브코딩 에센셜 책으로 Claude Code 활용법을 학습했다. AI 코딩 워크플로우를 강화하는 Archon이라는 새로운 도구도 발견했으며, Python의 비동기 SQLite 라이브러리인 aiosqlite도 살펴보았다.\n주요 하이라이트 Hugo 테마 대탐험 — 블로그 리뉴얼을 위한 10개 테마 비교 블로그 리뉴얼을 위해 Hugo 테마 갤러리에서 다양한 테마를 집중 탐색했다. 총 10개의 테마를 직접 데모 사이트까지 방문하며 비교한 결과를 정리한다.\n블로그용 테마:\nPaperMod (★13,116) — 가장 인기 있는 Hugo 테마. 빠르고 깔끔하며 반응형. Regular, Home-Info, Profile 3가지 모드를 지원하고, 다크/라이트 테마 자동 전환, SEO 최적화, Fuse.js 기반 검색 등 기능이 풍부하다. webpack이나 Node.js 같은 외부 의존성 없이 테마 수정이 가능하다는 점이 매력적이다. Stack (★6,261) — 카드 스타일의 블로거 친화적 테마. 시각적으로 세련된 레이아웃이 특징이며, 한/영/중 다국어 문서를 제공한다. GPL-3.0 라이선스. Coder (★3,031) — 심플하고 깔끔한 개인 블로그 테마. 다크모드 지원. MIT 라이선스. Terminal (★2,680) — 레트로 터미널 스타일. 개발자 감성을 좋아하는 사람에게 추천. 문서/포트폴리오용 테마:\nBlox Tailwind (★10,025) — 50개 이상의 컬러 테마와 위젯 포함. 회사 사이트, 포트폴리오, 블로그 등 다용도. Book (★3,953) — 책처럼 깔끔한 문서화 테마. Docsy (★2,903) — 기술 문서 사이트 전용 테마. Apache 2.0 라이선스. Compose, Bootstrap — 각각 깔끔한 문서형, 부트스트랩 기반 테마. 참고로, Hugo로 github.io 블로그 만들기에서는 Jekyll, Hexo, Hugo 세 가지 정적 사이트 생성기를 비교하며 Hugo를 선택한 이유(Go 기반의 빠른 빌드 속도, 외부 의존성 없음)와 GitHub Pages 배포 과정, Utterances 댓글 위젯 설정, 테마를 submodule로 관리하는 팁까지 상세히 정리되어 있다.\nArchon — AI 코딩 어시스턴트의 지식 관리 허브 Archon은 AI 코딩 어시스턴트를 위한 지식 및 작업 관리 플랫폼이다. MCP(Model Context Protocol) 서버로 동작하여 Claude Code, Cursor, Windsurf 등 다양한 AI 코딩 도구에 연결할 수 있다.\n핵심 기능:\n지식 관리: 웹사이트 크롤링, PDF/문서 업로드, 코드 예제 자동 추출, 벡터 검색 기반 RAG 프로젝트/태스크 관리: 계층적 프로젝트 구조, AI 지원 태스크 생성 마이크로서비스 아키텍처: Frontend(React+Vite, 3737포트), API Server(FastAPI, 8181포트), MCP Server(8051포트), Agents(PydanticAI, 8052포트) Docker Compose로 간단히 띄울 수 있으며, Supabase(PostgreSQL + PGVector)를 데이터베이스로 사용한다. OpenAI, Ollama, Google Gemini 등 다양한 LLM을 지원하며, 하이브리드 검색과 결과 리랭킹 등 고급 RAG 전략을 제공한다.\nCole Medin의 YouTube 가이드에서 실제 AI 코딩 워크플로우 예시를 확인할 수 있다.\n바이브코딩 에센셜 with Claude Code 위니북스의 바이브코딩 에센셜 Chapter 02의 섹션 7~10을 학습했다. Claude Code를 활용한 실전 개발 패턴과 워크플로우를 다루는 내용으로, AI 코딩 도구를 효과적으로 활용하기 위한 실전 가이드를 제공한다.\nPython aiosqlite — SQLite 비동기 프로그래밍 aiosqlite 사용법 정리 글을 통해 Python에서 SQLite를 비동기로 다루는 방법을 살펴보았다. 기본 sqlite3 모듈은 비동기를 지원하지 않기 때문에, aiosqlite 라이브러리를 사용하면 asyncio 이벤트 루프에서 다른 코루틴을 차단하지 않고 DB 작업을 수행할 수 있다. 사용법은 sqlite3와 거의 동일하되 async with와 await만 붙여주면 된다.\nimport aiosqlite import asyncio async def main(): async with aiosqlite.connect(\u0026#39;example.db\u0026#39;) as con: cur = await con.cursor() await cur.execute(\u0026#39;SELECT * FROM stocks WHERE symbol=:symbol\u0026#39;, {\u0026#39;symbol\u0026#39;: \u0026#39;RHAT\u0026#39;}) data = await cur.fetchall() print(data) asyncio.run(main()) 빠른 링크 Homebrew + VS Code Homebrew 설치 — macOS 개발 환경 세팅 AWS EC2 (ap-northeast-2) — 프론트엔드 서비스 배포 및 인스턴스 관리 AI/개발 유튜버 탐색: Cole Medin, Corbin Brown, Rok Benko, Fabio Bergmann 인사이트 오늘의 브라우징에서 뚜렷한 두 가지 흐름이 보인다. 첫째, 블로그 인프라 리뉴얼 — Hugo 테마 10개를 비교 탐색하고, GitHub Pages 배포 방법을 다시 정리한 것은 블로그를 더 체계적으로 운영하려는 의지를 보여준다. PaperMod와 Stack이 가장 많은 시간을 투자한 후보였다. 둘째, AI 코딩 워크플로우 고도화 — Archon, 바이브코딩 에센셜, 그리고 여러 AI 개발 유튜버를 탐색한 것은 AI 도구를 단순 사용 수준을 넘어 체계적인 지식 관리와 통합된 워크플로우로 발전시키려는 방향을 시사한다. Archon의 MCP 서버 기반 접근은 특히 여러 AI 코딩 도구를 동시에 활용하는 환경에서 유용할 수 있다.\n","date":"2026-02-19T00:00:00+09:00","image":"/images/posts/2026-02-19-tech-log/cover.jpg","permalink":"/ko/posts/2026-02-19-tech-log/","title":"Tech Log: 2026-02-19"},{"content":"인공 신경망 핵심 포인트:\n인공 신경망(Artificial Neural Networks)은 생물학적 뉴런에서 영감을 받아 만든 머신러닝 알고리즘입니다. 하지만 실제 뇌를 모델링한 것은 아닙니다. 신경망은 이미지, 음성, 텍스트 처리와 같은 복잡한 문제에서 뛰어난 성능을 발휘하며, 종종 딥러닝(Deep Learning)이라고 불립니다. 코드 설명:\n# 인공 신경망에서의 랜덤성을 제어하여 재현 가능한 결과를 얻도록 설정합니다. import tensorflow as tf tf.keras.utils.set_random_seed(42) tf.config.experimental.enable_op_determinism() 이 코드는 텐서플로에서 재현 가능한 결과를 얻기 위해 난수 시드를 설정합니다. 이는 실험을 반복할 때마다 같은 결과를 얻을 수 있게 도와줍니다.\n추가 학습:\n신경망의 기본 구조 (입력층, 은닉층, 출력층)와 뉴런 간의 연결 방식에 대해 학습합니다. 활성화 함수(Activation Function)와 그 중요성에 대해 깊이 이해합니다. 예: ReLU, Sigmoid, Softmax 등. 패션 MNIST 핵심 포인트:\n패션 MNIST는 10가지 패션 제품 카테고리에 속한 28x28 크기의 흑백 이미지로 구성된 데이터셋입니다. 이 데이터셋은 기존 MNIST 손글씨 데이터셋보다 실제 문제를 더 잘 반영합니다. 코드 설명:\nfrom tensorflow import keras (train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() print(train_input.shape, train_target.shape) print(test_input.shape, test_target.shape) 이 코드는 패션 MNIST 데이터를 로드하고, 학습용 및 테스트용 데이터의 형태를 출력합니다.\nimport matplotlib.pyplot as plt # 패션 MNIST의 처음 10개 이미지를 시각화합니다. fig, axs = plt.subplots(1, 10, figsize=(10,10)) for i in range(10): axs[i].imshow(train_input[i], cmap=\u0026#39;gray_r\u0026#39;) axs[i].axis(\u0026#39;off\u0026#39;) plt.show() 이 코드는 데이터셋의 이미지를 시각화하여 각 클래스의 예시를 제공합니다.\n추가 학습:\nFashion MNIST 데이터셋의 각 클래스가 어떤 패션 아이템인지 이해합니다. 데이터 전처리 과정(예: 이미지 정규화, 데이터 증강)에 대해 학습합니다. 로지스틱 회귀로 패션 아이템 분류하기 핵심 포인트:\n로지스틱 회귀(Logistic Regression)는 이진 분류를 위한 선형 모델입니다. 다중 클래스 분류를 위해 소프트맥스(Softmax) 함수를 사용하여 확장할 수 있습니다. 코드 설명:\ntrain_scaled = train_input / 255.0 train_scaled = train_scaled.reshape(-1, 28*28) print(train_scaled.shape) 이 코드는 이미지를 1차원 벡터로 변환하고, 픽셀 값을 0과 1 사이로 정규화합니다.\nfrom sklearn.model_selection import cross_validate from sklearn.linear_model import SGDClassifier sc = SGDClassifier(loss=\u0026#39;log_loss\u0026#39;, max_iter=5, random_state=42) scores = cross_validate(sc, train_scaled, train_target, n_jobs=-1) print(np.mean(scores[\u0026#39;test_score\u0026#39;])) 로지스틱 회귀 모델을 사용하여 패션 아이템을 분류합니다. 교차 검증을 통해 모델의 성능을 평가합니다.\n추가 학습:\n로지스틱 회귀의 수학적 배경과 소프트맥스 함수의 역할에 대해 학습합니다. 교차 검증(Cross-Validation)과 그 중요성에 대해 이해합니다. 인공신경망 핵심 포인트:\n인공 신경망은 로지스틱 회귀보다 복잡한 모델로, 은닉층을 추가하여 비선형 문제를 해결할 수 있습니다. 텐서플로와 케라스는 신경망을 효율적으로 구축하고 훈련하기 위한 강력한 도구입니다. 코드 설명:\nimport tensorflow as tf from tensorflow import keras from sklearn.model_selection import train_test_split # 학습용 데이터를 훈련 및 검증 세트로 나눕니다. train_scaled, val_scaled, train_target, val_target = train_test_split( train_scaled, train_target, test_size=0.2, random_state=42) print(train_scaled.shape, train_target.shape) print(val_scaled.shape, val_target.shape) 이 코드는 데이터를 훈련 세트와 검증 세트로 분할하여 모델의 성능을 검증합니다.\n추가 학습:\n케라스의 Sequential 모델 구조와 각 층의 역할에 대해 학습합니다. 딥러닝에서 과적합(Overfitting) 문제와 이를 해결하기 위한 방법(예: 드롭아웃, 정규화)들을 이해합니다. 인공신경망 모델 만들기 핵심 포인트:\n케라스의 Dense 층은 기본적인 밀집층으로, 모든 뉴런이 완전히 연결된 상태를 의미합니다. 출력층에서 소프트맥스 함수를 사용하여 클래스별 확률을 출력합니다. 코드 설명:\ndense = keras.layers.Dense(10, activation=\u0026#39;softmax\u0026#39;, input_shape=(784,)) model = keras.Sequential(dense) model.compile(loss=\u0026#39;sparse_categorical_crossentropy\u0026#39;, metrics=\u0026#39;accuracy\u0026#39;) print(train_target[:10]) 이 코드는 간단한 신경망 모델을 정의하고 컴파일합니다. 입력은 784개의 픽셀(28x28 이미지), 출력은 10개의 클래스 확률입니다.\n추가 학습:\n손실 함수와 최적화 알고리즘(예: Adam, SGD)의 역할에 대해 학습합니다. 모델 컴파일 과정에서 사용되는 각 매개변수의 의미를 이해합니다. 인공 신경망으로 패션 아이템 분류하기 핵심 포인트:\n모델 훈련은 데이터를 통해 모델의 가중치를 업데이트하는 과정이며, 평가 단계에서는 새로운 데이터에 대한 모델의 성능을 확인합니다. 코드 설명:\nmodel.fit(train_scaled, train_target, epochs=5) model.evaluate(val_scaled, val_target) 이 코드는 모델을 훈련시키고 검증 세트를 통해 모델의 성능을 평가합니다.\n추가 학습:\n에포크(Epoch)와 배치 크기(Batch Size)의 의미와 그 설정 방법에 대해 학습합니다. 모델 성능을 평가하는 다양한 지표(예: 정확도, 손실 값)를 이해하고, 이들을 개선하기 위한 방법들을 탐색합니다. ","date":"2024-08-18T00:00:00+09:00","image":"/images/posts/2024-08-18-혼공머신7-1/cover.jpg","permalink":"/ko/posts/2024-08-18-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A07-1/","title":"[혼공머신]7-1"},{"content":"심층 신경망 (Deep Neural Networks) 심층 신경망은 두 개 이상의 층을 포함한 신경망으로, 이러한 구조는 입력 데이터의 복잡한 패턴을 학습할 수 있게 해줍니다. 각 층은 주로 여러 뉴런으로 구성되며, 각 뉴런은 이전 층의 모든 뉴런과 연결되어 있을 수 있습니다.\n1. 심층 신경망 만들기 케라스(Keras)를 사용하여 심층 신경망을 만드는 방법은 간단합니다. 기본적으로 Sequential 모델을 사용하여 여러 층을 쉽게 추가할 수 있습니다. 각 층은 특정한 역할과 파라미터를 가지고 있으며, 예를 들어 Dense 층은 완전 연결 층을 의미합니다.\n층을 추가하는 다른 방법 층을 추가하는 또 다른 방법으로는 함수형 API를 사용하는 것입니다. 이 방법은 보다 복잡한 모델 아키텍처를 구성할 때 유용하며, 층 간의 다양한 연결을 가능하게 합니다. 예를 들어, 입력 데이터를 여러 층에 동시에 연결하거나 층의 출력을 다시 입력으로 사용할 수 있습니다.\n초기 설정 import tensorflow as tf # 실행마다 동일한 결과를 얻기 위해 랜덤 시드를 설정합니다. tf.keras.utils.set_random_seed(42) # 텐서플로 연산을 결정적으로 만듭니다. tf.config.experimental.enable_op_determinism() 데이터 로드 및 전처리 from tensorflow import keras from sklearn.model_selection import train_test_split # Fashion MNIST 데이터셋을 로드합니다. (train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() # 픽셀 값을 0과 1 사이로 정규화합니다. train_scaled = train_input / 255.0 # 입력 데이터를 1D 배열로 변환합니다. train_scaled = train_scaled.reshape(-1, 28*28) # 데이터를 훈련 세트와 검증 세트로 분할합니다. train_scaled, val_scaled, train_target, val_target = train_test_split( train_scaled, train_target, test_size=0.2, random_state=42) 신경망 층 설정 및 모델 구성 dense1 = keras.layers.Dense(100, activation=\u0026#39;sigmoid\u0026#39;, input_shape=(784,)) dense2 = keras.layers.Dense(10, activation=\u0026#39;softmax\u0026#39;) # Sequential 모델을 사용하여 층을 구성합니다. model = keras.Sequential([dense1, dense2]) # 모델 구조를 출력합니다. model.summary() 2. 렐루 함수 (ReLU Function) 렐루(ReLU) 함수는 신경망의 은닉층에서 가장 널리 사용되는 활성화 함수 중 하나입니다. 이 함수는 입력이 0보다 클 경우 입력을 그대로 출력하고, 0 이하일 경우 0을 출력합니다. 이 특성 때문에 렐루 함수는 비선형성을 추가하면서도 계산이 매우 간단하고, 기울기 소실 문제를 효과적으로 줄여줍니다.\nmodel = keras.Sequential() # 이미지 데이터를 평탄화하는 층을 추가합니다. model.add(keras.layers.Flatten(input_shape=(28, 28))) # ReLU 활성화 함수를 사용하는 은닉층을 추가합니다. model.add(keras.layers.Dense(100, activation=\u0026#39;relu\u0026#39;)) # 소프트맥스 활성화 함수를 사용하는 출력 층을 추가합니다. model.add(keras.layers.Dense(10, activation=\u0026#39;softmax\u0026#39;)) # 모델 구조를 출력합니다. model.summary() 3. 옵티마이저 (Optimizer) 신경망의 학습에서 중요한 부분은 옵티마이저의 선택입니다. 옵티마이저는 네트워크의 가중치를 업데이트하는 방법을 결정하며, 여러 종류가 있습니다:\nSGD (Stochastic Gradient Descent): 가장 기본적인 형태의 경사 하강법. Nesterov Accelerated Gradient: 모멘텀을 기반으로 하며, 더 빠른 수렴을 도모합니다. RMSprop: 그레이디언트의 제곱근을 사용하여 학습률을 조절합니다. Adam: 모멘텀과 RMSprop의 장점을 결합한 방법으로, 일반적으로 가장 효과적인 성능을 보입니다. SGD 옵티마이저 sgd = keras.optimizers.SGD(learning_rate=0.1) # SGD 옵티마이저를 사용하여 모델을 컴파일합니다. model.compile(optimizer=sgd, loss=\u0026#39;sparse_categorical_crossentropy\u0026#39;, metrics=\u0026#39;accuracy\u0026#39;) Adagrad 옵티마이저 adagrad = keras.optimizers.Adagrad() # Adagrad 옵티마이저를 사용하여 모델을 컴파일합니다. model.compile(optimizer=adagrad, loss=\u0026#39;sparse_categorical_crossentropy\u0026#39;, metrics=\u0026#39;accuracy\u0026#39;) RMSprop 옵티마이저 rmsprop = keras.optimizers.RMSprop() # RMSprop 옵티마이저를 사용하여 모델을 컴파일합니다. model.compile(optimizer=rmsprop, loss=\u0026#39;sparse_categorical_crossentropy\u0026#39;, metrics=\u0026#39;accuracy\u0026#39;) Adam 옵티마이저 # Adam 옵티마이저를 사용하여 모델을 컴파일합니다. model.compile(optimizer=\u0026#39;adam\u0026#39;, loss=\u0026#39;sparse_categorical_crossentropy\u0026#39;, metrics=\u0026#39;accuracy\u0026#39;) # 훈련 데이터로 모델을 학습합니다. model.fit(train_scaled, train_target, epochs=5) # 검증 데이터로 모델 성능을 평가합니다. model.evaluate(val_scaled, val_target) ","date":"2024-08-18T00:00:00+09:00","image":"/images/posts/2024-08-18-혼공머신7-2/cover.jpg","permalink":"/ko/posts/2024-08-18-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A07-2/","title":"[혼공머신]7-2"},{"content":"1. 손실 곡선 손실 곡선은 모델의 학습 과정에서 손실(loss) 값이 어떻게 변화하는지 보여주는 그래프입니다. 이 그래프를 통해 모델이 학습을 잘 하고 있는지, 과적합 또는 과소적합 문제가 발생하고 있는지 파악할 수 있습니다. 파일에서는 훈련 손실과 검증 손실을 시각화하는 코드가 포함되어 있으며, 이는 matplotlib 라이브러리를 사용해 그래프로 나타냈습니다.\nimport matplotlib.pyplot as plt # 훈련 과정의 손실 및 검증 손실을 그래프로 표시 plt.plot(history.history[\u0026#39;loss\u0026#39;], label=\u0026#39;Training Loss\u0026#39;) plt.plot(history.history[\u0026#39;val_loss\u0026#39;], label=\u0026#39;Validation Loss\u0026#39;) plt.title(\u0026#39;Training and Validation Loss\u0026#39;) plt.xlabel(\u0026#39;Epochs\u0026#39;) plt.ylabel(\u0026#39;Loss\u0026#39;) plt.legend() plt.show() 설명: 위 코드는 matplotlib 라이브러리를 사용하여 훈련 손실과 검증 손실을 에포크별로 시각화합니다. history 객체에는 각 에포크마다 계산된 손실과 다른 메트릭스들이 저장되어 있으며, 이를 그래프로 그리면 모델의 학습 과정을 쉽게 파악할 수 있습니다. 2. 검증 손실 검증 손실은 모델이 새로운 데이터에 얼마나 잘 맞는지를 평가하기 위해 사용되는 지표입니다. 훈련 데이터와 별도로 준비된 검증 데이터셋에서 계산된 손실 값으로, 모델의 일반화 능력을 확인할 수 있습니다. 파일에는 검증 데이터셋을 사용하여 모델을 평가하는 과정이 코드로 구현되어 있습니다.\n# 검증 데이터셋을 사용하여 모델의 손실과 정확도 평가 val_loss, val_accuracy = model.evaluate(val_scaled, val_target) print(f\u0026#39;Validation Loss: {val_loss}\u0026#39;) print(f\u0026#39;Validation Accuracy: {val_accuracy}\u0026#39;) 설명: 이 코드는 검증 데이터셋을 모델에 입력하여 손실과 정확도를 평가합니다. evaluate 함수는 모델의 성능을 확인하기 위해 사용되며, 검증 손실(val_loss)과 정확도(val_accuracy)를 반환합니다. 3. 드롭아웃 드롭아웃은 과적합을 방지하기 위한 기법으로, 훈련 과정에서 뉴런의 일부를 임의로 활성화하지 않는 방식으로 작동합니다. 이는 모델이 특정 뉴런에 과도하게 의존하는 것을 방지하고, 다양한 뉴런의 조합을 통해 학습할 수 있도록 돕습니다. 파일에는 드롭아웃 적용 예시가 코드로 포함되어 있으며, 텐서플로와 케라스를 통해 쉽게 구현할 수 있습니다.\nfrom tensorflow.keras.layers import Dropout # 드롭아웃 층 추가 예시 model.add(Dropout(0.5)) # 50%의 뉴런을 무작위로 꺼둠 설명: 드롭아웃 층은 모델에 과적합을 방지하기 위해 추가됩니다. 여기서 0.5는 50%의 비율로 뉴런의 출력을 임의로 0으로 설정한다는 의미입니다. 이 기법은 모델이 특정 뉴런이나 뉴런의 조합에 과도하게 의존하는 것을 방지하여 일반화 능력을 향상시킵니다. 4. 모델 저장과 복원 모델을 저장하고 불러오는 기능은 학습된 모델을 재사용하거나 배포하는 데 필수적입니다. model.save() 함수를 사용해 전체 모델을 저장할 수 있으며, load_model() 함수로 저장된 모델을 다시 불러올 수 있습니다. 이 과정을 통해 모델의\n# 모델 저장 model.save(\u0026#39;model.h5\u0026#39;) # HDF5 포맷으로 모델 전체를 저장 # 저장된 모델 로드 from tensorflow.keras.models import load_model loaded_model = load_model(\u0026#39;model.h5\u0026#39;) 설명: model.save 메소드를 사용하여 학습된 모델을 파일로 저장합니다. 여기서 \u0026lsquo;model.h5\u0026rsquo;는 파일 이름이며, 저장 포맷은 HDF5입니다. load_model 함수는 저장된 모델 파일을 로드하여 사용할 수 있도록 합니다. 5. 콜백 케라스에서는 콜백(callbacks)을 사용하여 모델을 훈련하는 도중에 특정 작업을 수행할 수 있습니다. 예를 들어 ModelCheckpoint 콜백은 특정 조건에 맞춰 모델을 자동으로 저장하고, EarlyStopping 콜백은 훈련을 조기에 종료할 수 있도록 도와줍니다. 이를 통해 효율적이고 효과적인 모델 훈련이 가능해집니다.\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping # 모델 체크포인트 콜백 설정 checkpoint = ModelCheckpoint( \u0026#39;best_model.h5\u0026#39;, # 모델 파일 경로 save_best_only=True, # 가장 좋은 모델만 저장 monitor=\u0026#39;val_loss\u0026#39;, # 검증 손실을 기준으로 verbose=1 ) # 조기 종료 콜백 설정 early_stopping = EarlyStopping( monitor=\u0026#39;val_loss\u0026#39;, # 검증 손실을 기준으로 patience=10, # 10 에포크 동안 개선이 없다면 종료 verbose=1, restore_best_weights=True # 가장 좋은 모델의 가중치를 복원 ) # 콜백을 사용하여 모델 훈련 history = model.fit( train_scaled, train_target, validation_data=(val_scaled, val_target), epochs=100, callbacks=[checkpoint, early_stopping] ) 설명: ModelCheckpoint 콜백은 학습 중 가장 좋은 모델을 자동으로 저장하도록 설정됩니다. EarlyStopping은 모델의 성능이 더 이상 개선되지 않을 때 학습을 조기에 종료시킵니다. 이러한 콜백들은 효율적인 모델 훈련을 도와주며, 과적합의 위험을 줄이는 데 유용합니다. ","date":"2024-08-18T00:00:00+09:00","image":"/images/posts/2024-08-18-혼공머신7-3/cover.jpg","permalink":"/ko/posts/2024-08-18-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A07-3/","title":"[혼공머신]7-3"},{"content":"혼공학습단 12기 회고록 스터디 기간: 2023년 7월 1일 ~ 8월 18일 스터디 교재: 혼자 공부하는 머신러닝+딥러닝 (hanbit.co.kr) 스터디 내용: # 진도 기본 숙제(필수) 추가 숙제(선택) 1주차 Chapter 01 ~ 02 코랩 실습 화면 캡처하기 Ch.02(02-1) 확인 문제 풀고, 풀이 과정 정리하기 2주차 Chapter 03 Ch.03(03-1) 2번 문제 출력 그래프 인증하기 모델 파라미터에 대해 설명하기 3주차 Chapter 04 Ch.04(04-1) 2번 문제 풀고, 풀이 과정 설명하기 Ch.04(04-2) 과대적합/과소적합 손코딩 코랩 화면 캡처하기 4주차 Chapter 05 교차 검증을 그림으로 설명하기 Ch.05(05-3) 앙상블 모델 손코딩 코랩 화면 인증하기 5주차 Chapter 06 k-평균 알고리즘 작동 방식 설명하기 Ch.06(06-3) 확인 문제 풀고, 풀이 과정 정리하기 6주차 Chapter 07 Ch.07(07-1) 확인 문제 풀고, 풀이 과정 정리하기 Ch.07(07-2) 확인 문제 풀고, 풀이 과정 정리하기 스터디 후기: 스터디의 장점: 저자와의 직접 소통: 스터디 참여자들은 저자가 함께 있는 디스코드 방에 초대되어 직접 질문할 수 있었습니다. 또한, 유튜브나 인프런을 통해 제공되는 저자의 무료 강의를 참고할 수 있어 학습에 큰 도움이 되었습니다.\n온라인 스터디의 지원: 온라인으로 진행되다 보니 자칫하면 뒤처질 수 있었지만, 운영자님의 정성 어린 피드백과 격려 덕분에 중도에 포기하지 않고 끝까지 참여할 수 있었습니다. 또한, 중간중간 제공된 간식 등 작은 보상들이 학습 동기를 유지하는 데 큰 역할을 했습니다.\n본인에게 아쉬운 점: 페이스북 사용의 어려움: 개인적으로 페이스북을 거의 사용하지 않아서 새로 게시 글을 올리는 과정이 헷갈렸습니다. 하지만 운영자님께서 이 부분까지도 세심하게 확인해 주셔서 큰 도움이 되었습니다.\n계정 정책 변화로 인한 문제: 중간에 페이스북의 계정 정책이 바뀌면서 게시글을 올리지 못하는 해프닝이 발생했습니다. 그러나 이후 새로운 업로드 방식이 도입되어 오히려 더 만족스럽게 사용할 수 있었습니다.\n기한 준수의 어려움: 스터디 초반에는 과제를 기한에 맞춰 제출했지만, 뒤로 갈수록 기한 막바지에 제출하는 경우가 많아졌습니다. 이 점은 복습을 통해 보강해야겠다고 다짐했습니다. 또한 책을 아직 끝까지 완독 못했는데 스터디 기간 떠나서 좀 더 학습해볼 생각입니다.\n이번 혼공학습단 12기 스터디는 머신러닝과 딥러닝에 대해 체계적으로 공부할 수 있는 좋은 기회였습니다. 저자와의 소통, 운영자님의 꼼꼼한 피드백, 그리고 적절한 보상 시스템 덕분에 학습에 대한 동기 부여가 지속될 수 있었습니다. 비록 개인적으로 아쉬운 점도 있었지만, 이를 통해 배운 점이 많았고 앞으로의 학습에도 큰 도움이 될 것 같습니다.\n","date":"2024-08-18T00:00:00+09:00","image":"/images/posts/2024-08-18-혼공학습단12기_후기/cover.jpg","permalink":"/ko/posts/2024-08-18-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A0%ED%98%BC%EA%B3%B5%ED%95%99%EC%8A%B5%EB%8B%A812%EA%B8%B0_%ED%9B%84%EA%B8%B0/","title":"[혼공머신]혼공학습단 12기 회고록"},{"content":"확률 및 통계 핵심개념 정리 확률 및 확률분포 확률(Probability) 확률(Probability): 특정 사건이 일어날 가능성을 0에서 1 사이의 값으로 나타내며, 사건이 발생할 확률이 높을수록 1에 가까워집니다. $$ 0 \\leq P(A) \\leq 1 $$ 여기서 $ P(A) $는 사건 $ A $가 발생할 확률을 나타냅니다.\n표본공간(Sample Space, $ S $): 모든 가능한 결과의 집합입니다. 예를 들어, 주사위를 던졌을 때의 표본공간은 ${1, 2, 3, 4, 5, 6}$입니다.\n사건(Event): 표본공간의 부분집합으로, 특정한 결과나 결과들의 집합을 나타냅니다. 예를 들어, 짝수가 나오는 사건은 ${2, 4, 6}$입니다.\n확률변수와 확률분포 확률변수(Random Variable): 결과를 수치적으로 나타내는 함수입니다. 주사위를 던졌을 때 나오는 수를 $ X $로 표현할 수 있습니다.\n확률분포(Probability Distribution): 확률변수가 취할 수 있는 모든 가능한 값에 대한 확률을 나타내는 함수입니다.\n이산형 확률분포(Discrete Probability Distribution): 확률변수가 특정한 이산값을 가질 확률을 나타냅니다. 예를 들어, 동전을 던졌을 때 앞면이 나올 확률은 $\\frac{1}{2}$입니다.\n연속형 확률분포(Continuous Probability Distribution): 확률변수가 특정 구간 내의 실수값을 가질 확률을 나타내며, 확률밀도함수(PDF)를 통해 설명됩니다.\n$$ P(a \\leq X \\leq b) = \\int_{a}^{b} f(x) , dx $$\n여기서 $ f(x) $는 확률밀도함수입니다.\n우도와 최대우도추정법 우도(Likelihood) 우도(Likelihood): 주어진 데이터가 특정 확률 분포로부터 발생했을 가능성을 나타내는 척도로, 관측된 데이터에 대한 확률을 계산하는 데 사용됩니다.\n주어진 데이터 $ x_1, x_2, \\ldots, x_n $의 확률 분포 $ f(x|\\theta) $가 주어졌을 때, 우도는 다음과 같이 정의됩니다.\n$$ L(\\theta|x_1, x_2, \\ldots, x_n) = \\prod_{i=1}^{n} f(x_i|\\theta) $$\n최대우도추정법(Maximum Likelihood Estimation) 최대우도추정법(Maximum Likelihood Estimation, MLE): 주어진 데이터가 관측될 확률을 최대화하는 분포의 모수를 추정하는 방법입니다.\n우도를 최대화하는 모수 $\\theta$를 찾는 방법으로, 수학적으로는 다음과 같은 식을 최대화합니다.\n$$ \\hat{\\theta} = \\arg\\max_{\\theta} L(\\theta|x_1, x_2, \\ldots, x_n) $$\n중심극한정리와 큰수의 법칙 중심극한정리(Central Limit Theorem) 중심극한정리: 표본의 크기가 충분히 크다면, 표본 평균의 분포는 모집단의 분포 형태와 관계없이 정규분포에 가까워진다는 이론입니다. 이는 많은 표본의 평균이 모평균에 접근한다는 것을 의미합니다.\n수식: 표본 크기가 $ n $인 표본의 평균 $ \\bar{X} $는 모집단의 평균 $\\mu$와 분산 $\\sigma^2/n$를 갖는 정규분포에 수렴합니다. $$ \\bar{X} \\sim N\\left(\\mu, \\frac{\\sigma^2}{n}\\right) $$\n큰수의 법칙(Law of Large Numbers) 큰수의 법칙: 표본 크기가 커짐에 따라 표본 평균은 모집단 평균에 수렴합니다. 즉, 표본의 수가 많을수록 표본 평균은 모집단의 실제 평균에 가까워집니다.\n$$ \\lim_{n \\to \\infty} \\bar{X}_n = \\mu $$ 여기서 $\\bar{X}_n$은 표본 평균, $\\mu$는 모집단 평균입니다.\n평균, 분산, 표준편차 평균(Mean) 평균(Mean): 데이터의 산술적 중심값으로, 모든 관측값의 합을 관측값의 수로 나눈 값입니다.\n$$ \\bar{x} = \\frac{1}{n} \\sum_{i=1}^{n} x_i $$ 여기서 $ x_i $는 각 데이터 포인트, $ n $은 데이터의 총 개수입니다.\n분산(Variance) 분산(Variance): 각 데이터 포인트가 평균에서 얼마나 떨어져 있는지를 나타내는 척도로, 산포도의 크기를 측정합니다.\n$$ \\sigma^2 = \\frac{1}{n} \\sum_{i=1}^{n} (x_i - \\bar{x})^2 $$ 표본의 분산은 다음과 같이 정의됩니다.\n$$ s^2 = \\frac{1}{n-1} \\sum_{i=1}^{n} (x_i - \\bar{x})^2 $$\n표준편차(Standard Deviation) 표준편차(Standard Deviation): 분산의 제곱근으로, 데이터의 변동성을 원래 단위로 나타내는 척도입니다.\n$$ \\sigma = \\sqrt{\\sigma^2} $$ 표본 표준편차는 다음과 같이 정의됩니다.\n$$ s = \\sqrt{s^2} $$\n정규분포와 표준화 정규분포(Normal Distribution) 정규분포: 데이터가 평균을 중심으로 대칭적으로 분포하는 확률분포로, 가장 흔히 사용되는 통계적 분포입니다. 확률 밀도 함수는 다음과 같습니다.\n$$ f(x|\\mu, \\sigma^2) = \\frac{1}{\\sqrt{2\\pi\\sigma^2}} e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}} $$\n$\\mu$는 평균, $\\sigma^2$는 분산입니다. 정규분포의 그래프는 종 모양을 띄며, 중앙의 평균을 중심으로 좌우 대칭입니다.\n표준화(Standardization) 표준화: 데이터에서 평균을 빼고 표준편차로 나눈 값을 사용하여 데이터를 표준정규분포로 변환하는 과정입니다. $$ Z = \\frac{X - \\mu}{\\sigma} $$ 여기서 $ Z $는 표준화된 변수, $ X $는 원래 데이터, $\\mu$는 평균, $\\sigma$는 표준편차입니다.\n표준정규분포는 평균이 0이고, 표준편차가 1인 정규분포입니다.\n가설 검정 가설 검정의 개념 가설 검정: 통계적 방법을 사용하여 표본 데이터로부터 모집단에 대한 가설을 검증하는 절차입니다. 귀무가설과 대립가설 귀무가설(Null Hypothesis, $ H_0 $): 연구나 실험에서 기본적으로 채택되는 가설로, 변화가 없음을 가정합니다. 예를 들어, \u0026ldquo;동전의 앞면이 나올 확률은 50%이다.\u0026rdquo;\n대립가설(Alternative Hypothesis, $ H_1 $): 귀무가설과 반대되는 가설로, 연구자가 증명하고자 하는 가설입니다. 예를 들어, \u0026ldquo;동전의 앞면이 나올 확률은 50%가 아니다.\u0026rdquo;\n검정 통계량과 유의 수준 검정 통계량(Test Statistic): 귀무가설이 참일 때 표본에서 관찰된 데이터를 요약한 값으로, 이를 통해 가설을 검정합니다. 유의 수준(Significance Level, $\\alpha$): 귀무가설이 참일 때, 그것을 기각할 확률로 일반적으로 0.05가 사용됩니다. p-값(p-value): 검정 통계량이 관측된 값보다 극단적인 값을 가질 확률로, $ p $-값이 $\\alpha$보다 작으면 귀무가설을 기각합니다. 회귀 분석 (Regression Analysis) 회귀 분석의 개념 회귀 분석: 두 변수 간의 관계를 분석하여 예측 모델을 만드는 통계 기법입니다. 단순 선형회귀(Simple Linear Regression) 단순 선형회귀: 독립 변수와 종속 변수 사이의 선형 관계를 분석하는 방법으로, 하나의 독립 변수를 사용하여 결과를 예측합니다.\n회귀식: $$ y=ax+by = ax + by=ax+b $$\n여기서 $ a $는 기울기(회귀계수), $ b $는 절편이며, $ y $는 예측된 종속 변수 값입니다.\n목표: 관측된 데이터와 회귀 직선 사이의 차이가 최소가 되도록 회귀계수를 추정하는 것입니다. 최소 제곱법(Ordinary Least Squares, OLS) 최소 제곱법(OLS): 회귀 분석에서 잔차(실제 관측값과 예측값의 차이)를 최소화하여 회귀계수를 추정하는 방법입니다.\n잔차(Residual): 회귀모형의 예측값과 실제 관측값 간의 차이입니다. 잔차 제곱의 합을 최소화: 잔차의 제곱합이 최소가 되는 기울기와 절편을 찾아냅니다. $$ \\text{Sum of Squared Residuals} = \\sum_{i=1}^{n} (y_i - \\hat{y}_i)^2 $$\n여기서 $ y_i $는 실제 값, $\\hat{y}_i$는 예측된 값입니다.\n","date":"2024-08-13T00:00:00+09:00","image":"/images/posts/2024-08-13-Pre-Onboarding1/cover.jpg","permalink":"/ko/posts/2024-08-13-pre-onboarding1.%ED%99%95%EB%A5%A0_%EB%B0%8F_%ED%86%B5%EA%B3%84_%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90_%EC%A0%95%EB%A6%AC/","title":"[원티드_프리온보딩]1.확률 및 통계 핵심개념 정리"},{"content":"선형대수 핵심개념 정리 행렬 (Matrix) 행렬(Matrix): 수 또는 다항식을 직사각형 배열로 나타낸 것으로, 행과 열로 구성됩니다. 행렬은 데이터의 변환, 시스템의 표현, 기하학적 변환 등을 나타내는 데 사용됩니다.\n예시: 실수 1, 9, -13, 20, 5, -16을 2행 3열의 직사각형 형태로 배열한 행렬. $$ A = \\begin{bmatrix} 1 \u0026amp; 9 \u0026amp; -13 \\ 20 \u0026amp; 5 \u0026amp; -16 \\end{bmatrix} $$\n행렬은 다양한 연산이 가능하며, 예를 들어 두 행렬 ( A )와 ( B )의 곱셈은 다음과 같이 정의됩니다. $$ C = AB = \\begin{bmatrix} a_{11} \u0026amp; a_{12} \\ a_{21} \u0026amp; a_{22} \\end{bmatrix} \\begin{bmatrix} b_{11} \u0026amp; b_{12} \\ b_{21} \u0026amp; b_{22} \\end{bmatrix} = \\begin{bmatrix} a_{11}b_{11} + a_{12}b_{21} \u0026amp; a_{11}b_{12} + a_{12}b_{22} \\ a_{21}b_{11} + a_{22}b_{21} \u0026amp; a_{21}b_{12} + a_{22}b_{22} \\end{bmatrix} $$\n벡터 (Vector) 벡터(Vector): 크기와 방향을 함께 가지는 물리량으로, 수학적으로는 좌표 공간의 점을 나타냅니다. 벡터는 덧셈, 뺄셈, 내적, 외적 등의 연산이 가능합니다.\n벡터의 예시: $$ \\mathbf{v} = \\begin{bmatrix} 3 \\ 4 \\end{bmatrix} $$\n벡터의 내적(Dot Product): 두 벡터 $ \\mathbf{u} = \\begin{bmatrix} u_1 \\ u_2 \\end{bmatrix} $와 $ \\mathbf{v} = \\begin{bmatrix} v_1 \\ v_2 \\end{bmatrix} $의 내적은 다음과 같이 계산됩니다. $$ \\mathbf{u} \\cdot \\mathbf{v} = u_1v_1 + u_2v_2 $$\n생성(Span)과 기저(Basis) 생성(Span): 주어진 벡터 집합의 선형 결합으로 얻을 수 있는 모든 벡터들의 집합입니다.\n예를 들어, 벡터 $ \\mathbf{a} $와 $ \\mathbf{b} $가 주어졌을 때, 이 벡터들의 span은 모든 선형 결합 $ c_1\\mathbf{a} + c_2\\mathbf{b} $으로 표현됩니다. 기저(Basis): 벡터 공간에서 모든 벡터를 유일하게 표현할 수 있는 최소한의 벡터 집합으로, 서로 선형 독립인 벡터들로 구성됩니다.\n선형 독립 (Linearly Independent) 선형 독립(Linearly Independent): 벡터 집합에서 임의의 벡터를 다른 벡터의 선형 결합으로 표현할 수 없는 경우를 의미합니다. 즉, 벡터들이 서로 독립적으로 존재합니다.\n벡터 $ \\mathbf{v}_1, \\mathbf{v}_2, \\mathbf{v}_3 $가 선형 독립이라면 다음 식이 성립합니다: $$ c_1\\mathbf{v}_1 + c_2\\mathbf{v}_2 + c_3\\mathbf{v}_3 = \\mathbf{0} \\implies c_1 = c_2 = c_3 = 0 $$\n행렬식 (Determinant) 및 고유값과 고유벡터 행렬식(Determinant): 정방행렬의 스칼라 값으로, 행렬의 가역성을 판별하는 데 사용됩니다. 행렬식이 0이 아니면 행렬은 가역이며, $ \\det(A) $로 표현됩니다.\n예를 들어, 2x2 행렬의 행렬식은 다음과 같이 계산됩니다: $$ \\det(A) = \\begin{vmatrix} a \u0026amp; b \\ c \u0026amp; d \\end{vmatrix} = ad - bc $$\n고유값(Eigenvalue)과 고유벡터(Eigenvector): 행렬의 선형 변환에서 벡터가 같은 방향으로 유지되면서 크기만 변할 때 그 벡터를 고유벡터, 변하는 크기를 고유값이라고 합니다.\n고유값 방정식: $ A\\mathbf{v} = \\lambda\\mathbf{v} $, 여기서 $ \\lambda $는 고유값이고 $ \\mathbf{v} $는 고유벡터입니다. 계수 (Rank) 계수(Rank): 행렬의 선형적으로 독립인 행 또는 열의 최대 개수로, $ \\text{Rank}(A) $로 표현됩니다. 계수는 연립방정식의 해의 존재성과 유일성을 판단하는 데 사용됩니다. 차원의 저주 (The Curse of Dimensionality) 차원의 저주: 데이터의 차원이 증가함에 따라 데이터가 희소(Sparse)해지고, 모델의 성능이 저하되는 현상입니다. 차원이 커지면 데이터 포인트 간의 거리 차이가 극단적으로 커지면서 데이터 분석과 머신러닝 모델의 성능에 악영향을 미칠 수 있습니다. 차원 축소 (Dimensional Reduction) 차원 축소: 고차원 데이터를 저차원 데이터로 변환하여 데이터의 중요 정보를 보존하면서 데이터의 복잡성을 줄이는 기법입니다.\nFeature Selection (특성 선택): 통계적 방법을 사용해 중요한 특징을 선택하는 방법으로, 상관분석, 전/후진선택 등이 있습니다.\nFeature Extraction (특성 추출): 기존 특징을 사용하여 새로운 유용한 특징을 생성하는 방법으로, PCA, LDA 등이 있습니다.\nPCA와 LDA PCA(Principal Component Analysis, 주성분 분석): 변수 간 상관관계를 이용해 주성분을 추출하여 차원을 축소하는 기법으로, 가장 큰 분산을 가지는 축을 기반으로 차원을 축소합니다.\n데이터의 분산을 최대화하는 새로운 축을 정의하여 차원을 축소합니다.\n예시: 2차원 데이터를 1차원으로 투영\nLDA(Linear Discriminant Analysis, 선형판별분석): 클래스 간 분산을 최대화하고 클래스 내 분산을 최소화하는 고유값과 고유벡터를 찾아 선형 변환하는 방법입니다.\nLDA는 데이터의 분리 가능성을 최대화하는 새로운 축을 찾습니다.\n예시: 2차원 데이터에서 클래스 간 분리를 최대화하는 방향으로 투영\n","date":"2024-08-13T00:00:00+09:00","image":"/images/posts/2024-08-13-Pre-Onboarding2/cover.jpg","permalink":"/ko/posts/2024-08-13-pre-onboarding2.%EC%84%A0%ED%98%95%EB%8C%80%EC%88%98_%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90_%EC%A0%95%EB%A6%AC/","title":"[원티드_프리온보딩]2.선형대수 핵심개념 정리"},{"content":"컴퓨터공학 핵심개념 정리 객체지향 프로그래밍 (Object-Oriented Programming, OOP) 객체지향 프로그래밍(OOP): 프로그램을 객체라는 단위로 구성하여 소프트웨어를 설계하는 방법론입니다. 객체는 데이터와 그 데이터를 처리하는 함수를 하나의 단위로 묶은 것입니다.\n주요 개념: 클래스(Class): 객체를 생성하기 위한 청사진으로, 속성과 메서드를 정의합니다. 객체(Object): 클래스의 인스턴스로, 실제로 메모리에 할당된 구조입니다. 상속(Inheritance): 기존 클래스를 확장하여 새로운 클래스를 생성하는 기능으로, 코드 재사용성을 높입니다. 다형성(Polymorphism): 동일한 인터페이스나 메서드를 통해 다른 동작을 수행할 수 있는 기능입니다. 캡슐화(Encapsulation): 객체의 속성과 메서드를 하나로 묶고, 외부에서 접근을 제한하여 데이터 보호를 강화합니다. 관계형 데이터베이스 (RDBMS)와 SQL 관계형 데이터베이스(RDBMS): 데이터를 테이블 형식으로 저장하며, 데이터 간의 관계를 설정하여 효율적으로 관리합니다. 각 테이블은 고유한 키를 가지고 있으며, 이를 통해 다른 테이블과의 관계를 정의합니다.\nSQL (Structured Query Language): 데이터베이스 관리 및 조작을 위한 표준화된 언어로, 데이터를 삽입, 삭제, 수정, 조회하는 다양한 명령어를 제공합니다.\n기본 SQL 명령어: SELECT: 데이터 조회 INSERT: 데이터 삽입 UPDATE: 데이터 수정 DELETE: 데이터 삭제 REST API REST(Representational State Transfer): 웹 상에서 클라이언트와 서버 간의 자원을 교환하기 위한 아키텍처 스타일로, HTTP 프로토콜을 기반으로 합니다.\nHTTP 메서드:\nGET: 데이터 조회 POST: 데이터 생성 PUT: 데이터 수정 DELETE: 데이터 삭제 특징:\n무상태성(Stateless): 각 요청은 독립적이며, 서버는 클라이언트의 상태를 저장하지 않습니다. 자원(Resource): URL을 통해 자원을 식별하며, 메서드를 통해 자원에 대한 작업을 수행합니다. 기본 자료구조 배열(Array): 동일한 데이터 타입의 요소들을 연속적으로 저장하는 자료구조입니다. 링크드 리스트(Linked List): 노드가 포인터로 연결된 형태로, 요소들이 비연속적으로 저장되는 자료구조입니다. 스택(Stack): LIFO(Last In First Out) 방식으로 작동하는 자료구조로, 가장 최근에 추가된 요소가 먼저 제거됩니다. 큐(Queue): FIFO(First In First Out) 방식으로 작동하는 자료구조로, 가장 먼저 추가된 요소가 먼저 제거됩니다. 해시 테이블(Hash Table): 키-값 쌍을 저장하며, 해시 함수를 통해 데이터에 빠르게 접근할 수 있습니다. 트리(Tree): 계층적인 구조로 데이터를 저장하는 자료구조로, 각 노드가 자식 노드를 가질 수 있습니다. 그래프(Graph): 정점과 간선으로 이루어진 구조로, 정점 간의 관계를 표현합니다. 기본 알고리즘 정렬 알고리즘: 데이터를 특정 순서로 정렬하는 알고리즘으로, 버블 정렬, 퀵 정렬, 합병 정렬 등이 있습니다. 탐색 알고리즘: 데이터 내에서 특정 값을 찾는 알고리즘으로, 이진 탐색, 깊이 우선 탐색(DFS), 너비 우선 탐색(BFS) 등이 있습니다. 동적 프로그래밍(Dynamic Programming): 문제를 하위 문제로 분할하여 해결한 결과를 저장하고 재사용하는 기법으로, 피보나치 수열, 최적 경로 문제 등에 사용됩니다. GitHub GitHub: 소프트웨어 개발 및 협업을 위한 플랫폼으로, Git 버전 관리 시스템을 기반으로 합니다.\n주요 기능:\n리포지토리(Repository): 프로젝트 파일과 변경 내역을 저장하는 공간 커밋(Commit): 파일의 변경 내역을 기록하는 단위 브랜치(Branch): 독립적인 작업 흐름을 나타내는 포인터 풀 리퀘스트(Pull Request): 변경 사항을 병합 요청하는 기능 기본 명령어:\ngit clone: 원격 리포지토리를 로컬로 복사 git init: 새로운 로컬 리포지토리 생성 git add: 변경된 파일을 스테이징 영역에 추가 git commit: 스테이징 영역의 변경 사항을 커밋 git pull: 원격 리포지토리의 변경 사항을 로컬로 가져옴 git push: 로컬 리포지토리의 변경 사항을 원격에 업로드 컴퓨터 구조 CPU (Central Processing Unit): 컴퓨터의 중앙 처리 장치로, 명령어 해석 및 연산을 수행합니다. 구성 요소로는 산술논리장치(ALU), 제어장치(CU), 레지스터 등이 있습니다.\n메모리 계층 구조:\n캐시(Cache): CPU에 가장 가까운 메모리로, 데이터 접근 속도를 향상시키기 위해 사용됩니다. 주 메모리(Main Memory): 실행 중인 프로그램과 데이터를 저장하는 RAM입니다. 보조 기억 장치: 하드디스크(HDD)나 SSD와 같은 장기 저장 장치입니다. 파이프라이닝(Pipelining): 명령어를 여러 단계로 나누어 병렬로 처리하여 CPU의 효율을 높이는 기술입니다.\n슈퍼스칼라 아키텍처: 여러 명령어를 동시에 실행할 수 있도록 설계된 CPU 구조입니다.\n캐시 메모리: 데이터를 빠르게 접근하기 위해 사용하는 작은 크기의 고속 메모리입니다.\n가상 메모리(Virtual Memory): 물리 메모리의 크기를 초과하는 데이터를 저장할 수 있도록 하는 메모리 관리 기법입니다.\n인터럽트(Interrupt): 특정 이벤트가 발생했을 때 CPU의 실행 흐름을 변경하는 메커니즘입니다.\nDMA (Direct Memory Access): CPU의 개입 없이 메모리와 장치 간 데이터를 전송하는 방법입니다.\n웹 서버 웹 서버(Web Server): 클라이언트(주로 웹 브라우저)로부터 HTTP 요청을 받아들여, 요청된 자원을 제공하거나 서버 측에서 처리한 결과를 응답으로 보내는 소프트웨어입니다.\nHTTP (Hypertext Transfer Protocol): 웹 서버와 클라이언트 간에 데이터를 주고받기 위한 프로토콜입니다.\n가상 호스팅(Virtual Hosting): 하나의 물리적 서버에서 여러 개의 웹사이트를 호스팅할 수 있는 기능으로, 도메인 기반과 IP 기반으로 나눌 수 있습니다.\n리버스 프록시(Reverse Proxy): 클라이언트를 대신하여 서버의 리소스를 요청하는 프록시 서버입니다.\n로드 밸런싱(Load Balancing): 여러 서버에 트래픽을 분산시켜 시스템의 효율성을 높이는 기술입니다.\nHTTPS: HTTP에 SSL/TLS를 추가하여 보안을 강화한 프로토콜입니다.\n캐싱(Caching): 데이터 접근 속도를 높이기 위해 데이터를 임시 저장하는 기법입니다.\n클라우드 서비스 클라우드 컴퓨팅(Cloud Computing): 인터넷을 통해 IT 자원(서버, 스토리지, 데이터베이스, 네트워크, 소프트웨어 등)을 제공하고 관리하는 서비스입니다.\nIaaS (Infrastructure as a Service): 서버, 스토리지, 네트워크 등 기본적인 컴퓨팅 자원을 가상화하여 제공하는 서비스입니다. (예: AWS EC2, Google Compute Engine)\nPaaS (Platform as a Service): 애플리케이션 개발에 필요한 플랫폼을 제공하는 서비스로, 인프라 관리를 하지 않고 개발에 집중할 수 있습니다. (예: AWS Elastic Beanstalk, Google App Engine)\nSaaS (Software as a Service): 소프트웨어를 서비스 형태로 제공하는 방식으로, 사용자는 웹 브라우저를 통해 소프트웨어를 사용합니다. (예: Google Workspace, Microsoft Office 365)\n가상화(Virtualization): 물리적 하드웨어를 여러 가상 인스턴스로 분할하여 독립적으로 운영하는 기술입니다. (예: VMware, Hyper\n","date":"2024-08-13T00:00:00+09:00","image":"/images/posts/2024-08-13-Pre-Onboarding3/cover.jpg","permalink":"/ko/posts/2024-08-13-pre-onboarding3.%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B3%B5%ED%95%99_%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90_%EC%A0%95%EB%A6%AC/","title":"[원티드_프리온보딩]3.컴퓨터공학 핵심개념 정리"},{"content":"머신러닝 핵심개념 정리 데이터 전처리 (Data Preprocessing) 데이터 전처리는 머신러닝 프로젝트의 기초 단계로, 데이터를 분석 가능하고 의미 있게 만드는 과정입니다. 데이터 전처리는 전체 데이터 과학 프로세스의 80%를 차지할 정도로 중요합니다. Anthony Goldbloom에 따르면, 데이터 과학자들은 대부분의 시간을 데이터 클리닝과 전처리에 사용하며, 이는 머신러닝 모델의 성능에 직접적인 영향을 미칩니다.\n데이터의 특성과 문제점 특성/문제점 정의 발생 원인 해결 방법 잡음 (Noise) 랜덤 에러나 측정된 변수의 변형된 값 센서의 작동 실패, 데이터 전송 문제 회귀 분석, 클러스터링을 통한 노이즈 제거 결측값 (Missing Value) 데이터 수집 과정에서 누락된 값 데이터 입력 누락, 데이터 수집 오류 평균값, 중앙값 대체 또는 행/열 삭제 이상값 (Outlier) 데이터의 정상적인 범위를 벗어난 값 입력 오류, 측정 오류, 실험 조건의 불일치 시각화를 통한 탐지, 통계적 방법을 통한 처리 불일관성 다양한 출처에서 수집된 데이터의 형식 및 단위 차이 데이터 형식 및 단위의 차이 형식과 단위를 일관되게 맞추기 데이터 전처리 기술 데이터 전처리 기술을 사용하여 위의 특성과 문제점을 해결합니다. 이러한 기술은 데이터의 품질을 높이고 머신러닝 모델의 성능을 개선하는 데 필수적입니다.\n전처리 기술 설명 데이터 유형 변환 데이터를 분석에 적합한 형식으로 일관되게 변환 평활화 (Smoothing) 데이터의 잡음을 제거하여 시각화를 용이하게 함 정규화 (Normalization) 데이터를 일정한 범위로 스케일링하여 모델의 성능 향상 표준화 (Standardization) 데이터의 평균을 0, 표준편차를 1로 조정하여 정규분포로 변환 데이터 여과 (Filtering) 중복성과 오류를 제거하여 데이터 품질 향상 데이터 정제 (Cleansing) 잘못된 데이터를 수정하거나 제거 이 표들은 데이터의 특성과 문제점을 명확하게 파악하고, 데이터 전처리 기술을 활용하여 이를 해결하는 데 도움을 줍니다. 데이터 전처리는 머신러닝 모델의 성능을 좌우하는 중요한 단계이며, 이를 통해 보다 정확하고 신뢰성 있는 모델을 구축할 수 있습니다.\n데이터 전처리 기술의 예시 결측값 처리 예시\n자동 채우기: 결측값을 평균, 중앙값, 최빈값으로 대체하여 데이터의 완성도를 높입니다. 전문가 수작업: 도메인 전문가가 데이터를 수작업으로 수정하는 방법도 있습니다. 잡음 처리 예시\n구간화 (Binning): 데이터를 여러 구간으로 나누고 각 구간의 대표값으로 대체하여 잡음을 제거합니다. 회귀값 적용: 데이터의 추세를 가장 잘 나타내는 회귀 함수를 적용하여 잡음을 줄입니다. 이상치 처리 예시\n단순 삭제: 이상치가 명백한 입력 오류일 경우 해당 값을 삭제합니다. 통계값 대체: 이상치를 다른 통계값으로 대체하여 데이터의 왜곡을 방지합니다. 머신러닝 알고리즘 머신러닝 알고리즘은 크게 지도학습, 비지도학습, 강화학습으로 분류됩니다.\n지도학습 (Supervised Learning) 정의: 입력 데이터와 해당 데이터의 정답(레이블)을 함께 사용하여 학습하는 방법입니다. 예시 알고리즘: 선형 회귀 (Linear Regression): 연속적인 값을 예측하는 데 사용됩니다. 예를 들어, 주택 가격 예측. 로지스틱 회귀 (Logistic Regression): 이진 분류 문제에 사용됩니다. 예를 들어, 이메일 스팸 필터링. 의사결정나무 (Decision Tree): 데이터의 특징을 기반으로 분류 규칙을 생성하여 데이터를 분류하는 알고리즘입니다. 설명력이 뛰어나지만 과적합 문제가 발생할 수 있습니다. 비지도학습 (Unsupervised Learning) 정의: 레이블이 없는 데이터로부터 패턴을 찾는 학습 방법입니다. 예시 알고리즘: K-평균 클러스터링 (K-Means Clustering): 데이터 포인트를 K개의 군집으로 나눕니다. 주성분 분석 (PCA): 데이터의 차원을 축소하여 정보 손실을 최소화하면서 시각화나 처리 속도를 높입니다. 강화학습 (Reinforcement Learning) 정의: 에이전트가 환경과 상호작용하며 보상을 통해 학습하는 방법입니다. 예시: 게임 AI, 로봇 제어 등에서 사용됩니다. 머신러닝 모델 평가 지표 모델 평가지표를 이해하기 위해서는 혼동 행렬(confusion matrix)을 사용하여 각각의 지표를 계산할 수 있습니다. 혼동 행렬은 모델이 분류한 결과를 실제 라벨과 비교하여 참과 거짓을 구분하는 데 사용됩니다.\n혼동 행렬 (Confusion Matrix) 실제\\예측 예측 Positive 예측 Negative 실제 Positive a (True Positive, TP) c (False Negative, FN) 실제 Negative b (False Positive, FP) d (True Negative, TN) True Positive (TP): 실제 Positive이고, Positive로 예측한 경우 False Negative (FN): 실제 Positive인데, Negative로 예측한 경우 False Positive (FP): 실제 Negative인데, Positive로 예측한 경우 True Negative (TN): 실제 Negative이고, Negative로 예측한 경우 평가지표 계산식 정확도 (Accuracy): 전체 데이터 중에서 올바르게 예측한 데이터의 비율 $$ \\text{Accuracy} = \\frac{a + d}{a + b + c + d} $$\n정밀도 (Precision): 성으로 예측한 것 중 실제 양성인 데이터의 비율 $$ \\text{Precision} = \\frac{a}{a + b} $$\n재현율 (Recall, Sensitivity): 실제 양성인 데이터 중 양성으로 예측한 비율 $$ \\text{Recall} = \\frac{a}{a + c} $$\n특이도 (Specificity): $$ \\text{Specificity} = \\frac{d}{b + d} $$\nF1-score: $$ \\text{F1-score} = 2 \\times \\frac{\\text{Precision} \\times \\text{Recall}}{\\text{Precision} + \\text{Recall}} $$\n예시 데이터와 계산 표 다음은 혼동 행렬을 기반으로 각 지표를 계산하는 예시입니다.\n예시 데이터 True Positive (TP) = 50 False Negative (FN) = 10 False Positive (FP) = 5 True Negative (TN) = 35 계산 표 지표 계산식 값 정확도 $\\frac{a + d}{a + b + c + d}$ $\\frac{50 + 35}{50 + 10 + 5 + 35} = \\frac{85}{100} = 0.85$ 정밀도 $\\frac{a}{a + b}$ $\\frac{50}{50 + 5} = \\frac{50}{55} \\approx 0.91$ 재현율 $\\frac{a}{a + c}$ $\\frac{50}{50 + 10} = \\frac{50}{60} \\approx 0.83$ 특이도 $\\frac{d}{b + d}$ $\\frac{35}{5 + 35} = \\frac{35}{40} = 0.875$ F1-score $2 \\times \\frac{\\text{Precision} \\times \\text{Recall}}{\\text{Precision} + \\text{Recall}}$ $2 \\times \\frac{0.91 \\times 0.83}{0.91 + 0.83} \\approx 0.87$ 이 표를 통해 각 지표가 혼동 행렬의 요소를 어떻게 사용하는지, 그리고 각각의 계산 과정이 어떻게 진행되는지 명확히 이해할 수 있습니다. 이를 통해 모델의 성능을 평가하고 개선 방향을 도출할 수 있습니다.\n","date":"2024-08-13T00:00:00+09:00","image":"/images/posts/2024-08-13-Pre-Onboarding4/cover.jpg","permalink":"/ko/posts/2024-08-13-pre-onboarding4.%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D_%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90_%EC%A0%95%EB%A6%AC/","title":"[원티드_프리온보딩]4.머신러닝 핵심개념 정리"},{"content":"딥러닝 핵심 개념 정리 딥러닝은 인공신경망을 기반으로 하여 대량의 데이터를 처리하고 학습하는 기계 학습의 한 분야입니다. 여러 계층(layer)으로 구성된 신경망을 통해 복잡한 패턴을 학습할 수 있습니다. 아래는 딥러닝의 핵심 개념을 표와 수식, 그래프를 사용하여 자세히 정리한 것입니다.\n딥러닝의 기본 개념 인공신경망 (Artificial Neural Network) 인공신경망은 뇌의 신경망을 본떠 만든 구조로, 입력 계층, 은닉 계층, 출력 계층으로 구성됩니다. 각 계층은 뉴런(노드)으로 이루어져 있으며, 뉴런 간에는 가중치(weight)가 연결되어 있습니다.\n퍼셉트론 (Perceptron)\n구성 요소: 입력, 가중치, 활성화 함수 수식: $$ \\text{Output} = f\\left(\\sum_{i=1}^{n} w_i \\cdot x_i + b\\right) $$ 여기서 $ w_i $는 가중치, $x_i$는 입력값, $b$는 편향(bias), $f$는 활성화 함수입니다. 다층 퍼셉트론 (Multi-Layer Perceptron, MLP)\n여러 개의 퍼셉트론이 층(layer)으로 연결되어 있는 구조. 입력층, 은닉층(hidden layer), 출력층으로 구성. 활성화 함수 (Activation Function) 활성화 함수는 신경망의 각 뉴런에서 입력 신호를 받아 출력 신호로 변환하는 역할을 하며, 신경망이 학습할 수 있는 비선형성을 제공합니다. 아래는 주요 활성화 함수의 특징과 사용 사례를 정리한 표입니다.\n활성화 함수의 특징 활성화 함수 수식 특징 및 사용 사례 Sigmoid $ \\sigma(x) = \\frac{1}{1 + e^{-x}} $ - 특징: 출력값을 0과 1 사이로 압축하는 S자 형태의 곡선입니다. 연속적인 실수 값을 확률값으로 변환할 때 주로 사용됩니다.\n- 사용 사례: 이진 분류 문제에서 출력 뉴런의 활성화 함수로 자주 사용됩니다.\n- 단점: 입력 값의 절대값이 큰 경우 기울기가 매우 작아져서, 학습이 느려지는 vanishing gradient 문제를 발생시킬 수 있습니다. Tanh $ \\tanh(x) = \\frac{e^x - e^{-x}}{e^x + e^{-x}} $ - 특징: Sigmoid와 유사하지만 출력값이 -1과 1 사이로 압축됩니다. 데이터의 중앙값을 0으로 맞추는 데 유리합니다.\n- 사용 사례: LSTM 및 RNN과 같은 순환 신경망에서 내부 상태를 업데이트할 때 자주 사용됩니다.\n- 장점: Sigmoid보다 중심이 0에 가까워 학습 효율이 높은 편입니다. ReLU (Rectified Linear Unit) $ f(x) = \\max(0, x) $ - 특징: 입력이 양수면 그대로 출력하고, 음수면 0을 출력합니다. 신경망에 비선형성을 부여하면서 계산이 매우 간단합니다.\n- 사용 사례: CNN 및 MLP에서 은닉층의 활성화 함수로 널리 사용됩니다.\n- 장점: Sigmoid와 Tanh에 비해 vanishing gradient 문제가 덜 발생하며, 학습이 빠릅니다.\n- 단점: 입력이 음수인 경우 기울기가 0이 되어 학습이 멈추는 dying ReLU 문제가 발생할 수 있습니다. Leaky ReLU $ f(x) = \\max(0.01x, x) $ - 특징: ReLU의 변형으로, 음수 입력에 대해 아주 작은 기울기를 부여합니다.\n- 사용 사례: ReLU의 dying 문제를 해결하기 위해 사용됩니다.\n- 장점: 모든 입력 값에 대해 기울기가 존재하므로, ReLU보다 안정적인 학습이 가능합니다. Softmax $ \\sigma(\\mathbf{z})i = \\frac{e^{z_i}}{\\sum{j=1}^{K} e^{z_j}} $ - 특징: 여러 클래스에 대한 확률 분포를 출력하도록 설계되었습니다. 입력 벡터의 각 요소를 확률로 변환합니다.\n- 사용 사례: 다중 클래스 분류 문제의 출력층에 사용됩니다.\n- 장점: 출력값의 합이 1이 되어 확률 분포를 표현할 수 있습니다. 각 활성화 함수는 특정 상황에서 유용하게 사용되며, 문제의 특성에 따라 적절한 함수를 선택하는 것이 중요합니다. 활성화 함수를 선택할 때는 학습의 안정성, 계산의 효율성, 문제의 특성을 고려해야 합니다.\n손실 함수 (Loss Function) 손실 함수는 모델의 예측과 실제 값 간의 차이를 측정하여 학습 방향을 결정하는 중요한 역할을 합니다.\nMean Squared Error (MSE)\n정의: 회귀 문제에서 주로 사용되는 손실 함수. 수식: $$ \\text{MSE} = \\frac{1}{n} \\sum_{i=1}^{n} (y_i - \\hat{y}_i)^2 $$ 여기서 $y_i$는 실제 값, $\\hat{y}_i$는 예측 값입니다. Cross Entropy Loss\n정의: 분류 문제에서 사용되는 손실 함수. 수식: $$ \\text{Cross Entropy} = -\\sum_{i=1}^{n} y_i \\log(\\hat{y}_i) $$ 역전파 (Backpropagation) 역전파는 신경망의 가중치를 업데이트하는 알고리즘으로, 손실 함수의 기울기를 계산하여 가중치를 조정합니다.\n개념: 출력에서 입력 방향으로 손실의 그래디언트를 전파하여 각 가중치를 업데이트. 수식: 가중치 업데이트 공식 $$ w = w - \\eta \\cdot \\frac{\\partial \\text{Loss}}{\\partial w} $$ 여기서 $ \\eta $는 학습률(learning rate)입니다. 딥러닝의 최적화 알고리즘 최적화 알고리즘은 역전파 과정에서 가중치를 효율적으로 업데이트하기 위한 방법을 제공합니다.\n알고리즘 특징 SGD (Stochastic Gradient Descent) 각 샘플에 대해 가중치를 업데이트하여 학습을 빠르게 진행하지만, 노이즈가 많을 수 있습니다. Momentum 이전 단계의 기울기를 고려하여 업데이트, 진동 감소 및 수렴 속도 증가 Adam 학습률을 개별적으로 조정하여 빠르고 안정적인 수렴을 유도합니다. 배치 학습과 미니배치 학습 배치 학습과 미니배치 학습은 데이터를 나누어 처리하는 방식으로, 모델의 학습 효율성을 높입니다.\n배치 학습 (Batch Learning): 전체 데이터셋을 한 번에 처리하여 가중치를 업데이트합니다. 미니배치 학습 (Mini-batch Learning): 데이터셋을 작은 배치로 나누어 각 배치마다 가중치를 업데이트합니다. 예시: 데이터셋 크기 = 1000, 배치 크기 = 100일 때, 10번의 업데이트 수행. 딥러닝 모델 평가 지표 딥러닝 모델의 성능을 평가하기 위해 다양한 지표를 사용합니다.\n정확도 (Accuracy)\n정의: 전체 예측 중에서 정확히 맞춘 비율. 계산식: $$ \\text{Accuracy} = \\frac{\\text{TP} + \\text{TN}}{\\text{TP} + \\text{FP} + \\text{FN} + \\text{TN}} $$ 정밀도 (Precision)\n정의: 양성으로 예측한 것 중 실제 양성의 비율. 계산식: $$ \\text{Precision} = \\frac{\\text{TP}}{\\text{TP} + \\text{FP}} $$ 재현율 (Recall)\n정의: 실제 양성 중에서 양성으로 예측한 비율. 계산식: $$ \\text{Recall} = \\frac{\\text{TP}}{\\text{TP} + \\text{FN}} $$ F1-score\n정의: 정밀도와 재현율의 조화 평균. 계산식: $$ \\text{F1-score} = 2 \\times \\frac{\\text{Precision} \\times \\text{Recall}}{\\text{Precision} + \\text{Recall}} $$ 딥러닝은 복잡한 데이터 구조를 학습하고 추론하는 강력한 도구이며, 이러한 개념과 기술을 이해함으로써 더욱 효과적으로 적용할 수 있습니다. 딥러닝 모델을 구축하고 평가하는 과정에서 이러한 핵심 개념을 잘 활용하는 것이 중요합니다.\n","date":"2024-08-13T00:00:00+09:00","image":"/images/posts/2024-08-13-Pre-Onboarding5/cover.jpg","permalink":"/ko/posts/2024-08-13-pre-onboarding5.%EB%94%A5%EB%9F%AC%EB%8B%9D_%ED%95%B5%EC%8B%AC%EA%B0%9C%EB%85%90_%EC%A0%95%EB%A6%AC/","title":"[원티드_프리온보딩]5.딥러닝 핵심개념 정리"},{"content":"군집 알고리즘 1. 타깃을 모르는 비지도 학습 비지도 학습은 주어진 데이터에 대해 명시적인 타깃 레이블이 없는 상태에서 유용한 정보를 추출하는 머신러닝 기법입니다. 데이터의 구조나 패턴을 자동으로 인식하여 유사한 데이터물은 하나의 그룹(클러스터)으로 묶는 것이 일반적인 접근 방식입니다. 이러한 접근은 데이터의 숨겨진 특성이나 구조를 이해하는데 도움을 줍니다.\n2. 과일 사진 데이터 준비하기 과일 사진 데이터를 사용하여 군집화를 실습하는 경우, 데이터 준비 과정은 다음과 같습니다:\n데이터 수집: 다양한 종류의 과일 사진을 수집합니다. 이때, 각 과일의 이미지는 다양한 각도와 배경에서 촬영되어야 합니다. 이미지 전처리: 이미지 크기 조정, 색상 정규화, 필요한 경우 배경 제거 등의 전처리 작업을 수행합니다. 이는 알고리즘의 성능에 크게 영향을 미칠 수 있습니다. 데이터 세트 구성: 전처리된 이미지를 데이터 세트로 구성하여 알고리즘에 입력할 준비를 합니다. # 과일 데이터셋 다운로드 !wget https://bit.ly/fruits_300_data -O fruits_300.npy # 데이터셋 로드 fruits = np.load(\u0026#39;fruits_300.npy\u0026#39;) import matplotlib.pyplot as plt # 첫 번째 과일 이미지를 흑백으로 시각화 plt.imshow(fruits[0], cmap=\u0026#39;gray\u0026#39;) plt.show() 3. 픽셀값 분석하기 과일 사진의 픽셀 값을 분석하는 과정은 다음과 같습니다:\n픽셀 데이터 추출: 각 이미지에서 RGB 픽셀 값을 추출합니다. 픽셀 데이터의 특성 파악: 과일의 색상, 질감 등 이미지의 특성을 파악하기 위해 픽셀 값의 분포를 분석합니다. 차원 축소: 고차원의 픽셀 데이터를 처리 가능한 형태로 차원을 축소합니다. PCA(주성분 분석) 같은 기법을 사용할 수 있습니다. # 사과 이미지만 선택하여 픽셀값의 평균 계산 apple = fruits[0:100].reshape(-1, 100*100) # 픽셀 평균값의 히스토그램 표시 plt.hist(np.mean(apple, axis=1), alpha=0.8) plt.legend([\u0026#39;apple\u0026#39;]) plt.show() 4. 평균값과 가까운 사진 고르기 군집화를 통해 비슷한 특성을 가진 과일 사진을 그룹화 한 후, 각 클러스터의 중심(평균 픽셀값)에 가장 가까운 사진을 선택하는 방법은 다음과 같습니다:\n클러스터 평균 계산: 각 클러스터의 평균 픽셀 값을 계산합니다. 대표 이미지 선택: 평균값과 가장 유사한 픽셀 값을 가진 이미지를 각 클러스터의 대표 이미지로 선택합니다. # 사과 이미지의 평균값 계산 apple_mean = np.mean(apple, axis=0).reshape(100, 100) # 각 이미지와 평균 이미지의 차이 계산 abs_diff = np.abs(fruits - apple_mean) # 차이의 평균값 계산 abs_mean = np.mean(abs_diff, axis=(1,2)) # 평균값과 가장 가까운 이미지의 인덱스 정렬 apple_index = np.argsort(abs_mean)[:100] # 가장 유사한 이미지 시각화 plt.imshow(fruits[apple_index[0]], cmap=\u0026#39;gray_r\u0026#39;) plt.show() ","date":"2024-08-11T00:00:00+09:00","image":"/images/posts/2024-08-11-혼공머신6-1/cover.jpg","permalink":"/ko/posts/2024-08-11-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A06-1/","title":"[혼공머신]6-1"},{"content":"k-평균 (K-Means) k-평균 알고리즘은 비지도 학습에서 매우 흔히 사용되는 클러스터링 방법입니다. 이 알고리즘의 주 목적은 데이터를 k개의 클러스터로 그룹화하는 것이며, 각 클러스터는 서로 비슷한 특성을 가진 데이터 포인트들로 구성됩니다. 알고리즘의 기본적인 단계는 다음과 같습니다:\n초기화: 먼저 클러스터의 수 ( k )를 정하고, 데이터 포인트들 중에서 무작위로 ( k )개의 포인트를 클러스터의 중심(센트로이드)으로 선택합니다. 할당: 각 데이터 포인트를 가장 가까운 센트로이드에 할당하여 클러스터를 형성합니다. 업데이트: 각 클러스터의 평균 위치로 센트로이드를 업데이트합니다. 이 할당과 업데이트 과정을 센트로이드의 변화가 없거나, 사용자가 설정한 최대 반복 횟수에 도달할 때까지 반복합니다. 이 알고리즘은 특히 대용량 데이터 세트에 효과적이며, 다양한 응용 분야에서 클러스터링을 위해 널리 사용됩니다.\n1. KMeans 클래스 scikit-learn 라이브러리의 KMeans 클래스는 Python에서 k-평균 알고리즘을 구현할 때 사용됩니다. 이 클래스의 주요 매개변수는 다음과 같습니다:\nn_clusters: 클러스터의 개수 ( k )를 정합니다. 기본값은 8입니다. n_init: 초기 센트로이드 설정 후 알고리즘을 반복 실행하는 횟수입니다. 최적의 결과를 얻기 위해 여러 번 실행 후 최소 이너셔를 가진 결과를 선택합니다. 사이킷런 1.4에서는 이 값이 \u0026lsquo;auto\u0026rsquo;로 설정될 예정이며, 이는 알고리즘의 실행을 자동으로 조정합니다. max_iter: 한 번의 실행에서 최적의 센트로이드를 찾기 위해 반복할 수 있는 최대 횟수입니다. 기본값은 200입니다. # 데이터 로드 및 전처리 !wget https://bit.ly/fruits_300_data -O fruits_300.npy import numpy as np fruits = np.load(\u0026#39;fruits_300.npy\u0026#39;) fruits_2d = fruits.reshape(-1, 100*100) # KMeans 클러스터링 수행 from sklearn.cluster import KMeans km = KMeans(n_clusters=3, random_state=42) km.fit(fruits_2d) 2. 클러스터 중심 클러스터 중심, 또는 센트로이드는 해당 클러스터에 속한 모든 샘플의 특성 평균값으로 정의됩니다. 클러스터링 과정에서 이 센트로이드는 각 클러스터의 \u0026ldquo;중심점\u0026quot;으로 작용하며, 새로운 데이터 포인트를 클러스터링 할 때 참조점으로 사용됩니다. 센트로이드는 클러스터의 대표적인 특성을 나타내므로, 각 클러스터의 특징을 이해하는 데 중요한 역할을 합니다.\n# 클러스터 레이블 출력 및 개수 확인 print(km.labels_) print(np.unique(km.labels_, return_counts=True)) # 클러스터링 결과 시각화] import matplotlib.pyplot as plt def draw_fruits(arr, ratio=1): # 코드는 배열의 이미지를 그리는 함수를 정의 draw_fruits(fruits[km.labels_==0]) draw_fruits(fruits[km.labels_==1]) draw_fruits(fruits[km.labels_==2]) draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3) 3. 최적의 k 찾기 클러스터의 수 ( k )를 결정하는 것은 k-평균 알고리즘에서 중요한 결정 중 하나입니다. 너무 많은 클러스터는 과적합을, 너무 적은 클러스터는 과소적합을 초래할 수 있습니다. 최적의 ( k )를 찾기 위한 하나의 방법은 엘보우 방법입니다. 이 방법에서는 다양한 ( k )값에 대해 이너셔를 계산하고, 이너셔가 급격히 감소하는 지점을 찾습니다. 이 \u0026ldquo;꺾이는 지점\u0026quot;은 클러스터 수가 적절한 수준에 도달했음을 나타내며, 여기서 추가적인 클러스터가 큰 이득을 주지 않는다는 신호로 해석됩니다.\n이와 같은 분석을 통해 데이터를 효과적으로 이해하고, 구조화하는 데 도움을 줄 수 있습니다.\n# 새로운 샘플에 대한 변환 및 예측 print(km.transform(fruits_2d[100:101])) print(km.predict(fruits_2d[100:101])) draw_fruits(fruits[100:101]) # 최적의 클러스터 수를 찾기 위한 엘보우 방법 inertia = [] for k in range(2, 7): km = KMeans(n_clusters=k, n_init=\u0026#39;auto\u0026#39;, random_state=42) km.fit(fruits_2d) inertia.append(km.inertia_) plt.plot(range(2, 7), inertia) plt.xlabel(\u0026#39;k\u0026#39;) plt.ylabel(\u0026#39;inertia\u0026#39;) plt.show() ","date":"2024-08-11T00:00:00+09:00","image":"/images/posts/2024-08-11-혼공머신6-2/cover.jpg","permalink":"/ko/posts/2024-08-11-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A06-2/","title":"[혼공머신]6-2"},{"content":"주성분 분석 1. 차원과 차원 축소 차원의 개념 차원이란 데이터에서 각 특성(Feature)의 수를 의미합니다. 예를 들어, 사람의 키, 몸무게, 나이라는 3가지 특성을 가진 데이터는 3차원 데이터입니다. 차원 축소의 필요성 차원의 저주: 차원이 증가할수록, 각 차원에 걸쳐 데이터를 충분히 표현하기 위해 필요한 데이터 양이 기하급수적으로 증가합니다. 이로 인해 모델의 성능이 저하될 수 있습니다. 계산 효율성 및 시각화: 높은 차원의 데이터를 처리하는 것은 계산상의 비효율을 초래하며, 3차원 이상의 데이터는 직관적으로 이해하고 시각화하기 어렵습니다. 2. 주성분 분석 소개 PCA의 원리 주성분 분석은 데이터의 분산을 최대화하는 축을 찾아 데이터를 새로운 축에 투영함으로써 차원을 축소합니다. 이 때 새로운 축들은 서로 직교합니다. 주성분(Principal Components) 데이터의 분산이 최대인 방향을 찾아 그 방향으로 데이터를 투영한 것이 주성분입니다. 첫 번째 주성분은 데이터의 분산을 가장 많이 설명하고, 두 번째 주성분은 첫 번째 주성분에 직각이면서 다음으로 큰 분산을 설명하는 방향입니다. # 필요한 라이브러리를 불러옵니다. from sklearn.decomposition import PCA from sklearn.datasets import load_iris import matplotlib.pyplot as plt # Iris 데이터셋을 로드합니다. data = load_iris() X = data.data # PCA 모델을 생성하고 학습합니다. 이 때, 2개의 주성분만을 유지하도록 설정합니다. pca = PCA(n_components=2) X_pca = pca.fit_transform(X) # 변환된 데이터의 분포를 시각화합니다. plt.figure(figsize=(8, 6)) plt.scatter(X_pca[:, 0], X_pca[:, 1], c=data.target, cmap=\u0026#39;viridis\u0026#39;) plt.xlabel(\u0026#39;First principal component\u0026#39;) plt.ylabel(\u0026#39;Second principal component\u0026#39;) plt.title(\u0026#39;PCA result of Iris Dataset\u0026#39;) plt.colorbar() plt.show() 3. PCA 클래스 (scikit-learn) 주요 매개변수 n_components: 축소할 차원의 수를 지정합니다. 기본적으로는 None으로 설정되며, 이 경우 더 적은 수의 주성분으로 설정됩니다. random_state: 결과의 일관성을 위한 난수 시드를 설정합니다. 주요 속성 components_: 추출된 주성분의 방향 벡터입니다. explained_variance_: 각 주성분에 의해 설명된 분산의 양입니다. explained_variance_ratio_: 전체 분산에 대한 각 주성분의 분산 비율입니다. # PCA 객체의 주요 속성을 출력합니다. print(\u0026#34;Components (Principal axes):\u0026#34;, pca.components_) print(\u0026#34;Explained variance:\u0026#34;, pca.explained_variance_) print(\u0026#34;Explained variance ratio:\u0026#34;, pca.explained_variance_ratio_) 4. 원본 데이터 재구성 PCA 변환 후, inverse_transform() 메서드를 사용하여 축소된 차원에서 원본 차원으로 데이터를 복원할 수 있습니다. 이 과정에서 일부 정보 손실이 발생하지만, 주요 특성은 유지됩니다. # 차원 축소된 데이터를 원래의 차원으로 복원합니다. X_inverse = pca.inverse_transform(X_pca) # 원본 데이터와 복원된 데이터의 비교를 위해 시각화합니다. plt.figure(figsize=(8, 6)) plt.scatter(X[:, 0], X[:, 1], alpha=0.2, label=\u0026#39;Original\u0026#39;) plt.scatter(X_inverse[:, 0], X_inverse[:, 1], alpha=0.8, label=\u0026#39;Recovered\u0026#39;) plt.legend() plt.title(\u0026#39;Comparison of Original and Recovered Data\u0026#39;) plt.show() 5. 설명된 분산 설명된 분산은 PCA에서 각 주성분이 데이터 전체 분산에서 얼마나 많은 부분을 차지하는지를 나타내는 지표입니다. 높은 설명된 분산 비율은 주성분이 데이터의 중요한 정보를 많이 포함하고 있음을 의미합니다. 6. 다른 알고리즘과 함께 사용하기 PCA는 다른 기계학습 알고리즘 전에 데이터를 전처리하는 단계로 사용될 수 있습니다. 차원이 축소된 데이터는 학습 속도를 향상시키고, 과적합을 방지하는 효과가 있습니다. 예를 들어, 고차원 데이터에 대해 SVM, 로지스틱 회귀 등을 적용하기 전에 PCA로 차원을 축소하는 것이 일반적입니다. from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split # PCA를 적용한 데이터로 로지스틱 회귀 모델을 학습합니다. X_train, X_test, y_train, y_test = train_test_split(X_pca, data.target, test_size=0.2, random_state=42) model = LogisticRegression() model.fit(X_train, y_train) # 모델의 정확도를 평가합니다. print(\u0026#34;Test accuracy:\u0026#34;, model.score(X_test, y_test)) ","date":"2024-08-11T00:00:00+09:00","image":"/images/posts/2024-08-11-혼공머신6-3/cover.jpg","permalink":"/ko/posts/2024-08-11-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A06-3/","title":"[혼공머신]6-3"},{"content":"결정 트리의 정확도를 높이기 위한 방법 1. 가지치기 (Pruning) 가지치기는 트리의 불필요한 가지를 제거하여 과대적합을 방지하는 방법입니다.\n사전 가지치기 (Pre-pruning): max_depth: 트리의 최대 깊이를 제한합니다. min_samples_split: 노드를 분할하기 위한 최소 샘플 수를 지정합니다. min_samples_leaf: 리프 노드가 가져야 하는 최소 샘플 수를 지정합니다. max_leaf_nodes: 리프 노드의 최대 개수를 제한합니다. model = DecisionTreeClassifier(max_depth=5, min_samples_split=10, min_samples_leaf=5, random_state=42) model.fit(X_train, y_train) 사후 가지치기 (Post-pruning): 사후 가지치기는 트리가 생성된 후 가지를 잘라내는 방법입니다. scikit-learn에서 직접 제공하지는 않지만, 트리를 생성한 후 수동으로 가지를 잘라낼 수 있습니다. 2. 앙상블 방법 (Ensemble Methods) 여러 개의 결정 트리를 사용하여 예측을 개선하는 방법입니다.\n랜덤 포레스트 (Random Forest): 여러 결정 트리를 학습시키고, 그 결과를 앙상블하여 최종 예측을 도출합니다. from sklearn.ensemble import RandomForestClassifier model = RandomForestClassifier(n_estimators=100, random_state=42) model.fit(X_train, y_train) 배깅 (Bagging): 데이터의 서브셋을 생성하여 각 서브셋에 대해 결정 트리를 학습시킵니다. 그 결과를 평균화하거나 다수결로 예측합니다. from sklearn.ensemble import BaggingClassifier model = BaggingClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=100, random_state=42) model.fit(X_train, y_train) 부스팅 (Boosting): 이전 트리의 오차를 보정하는 방식으로 순차적으로 트리를 학습시킵니다. 대표적으로 AdaBoost와 Gradient Boosting이 있습니다. from sklearn.ensemble import AdaBoostClassifier model = AdaBoostClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=100, random_state=42) model.fit(X_train, y_train) 3. 특성 공학 (Feature Engineering) 데이터의 특성을 개선하여 모델의 성능을 높이는 방법입니다.\n특성 선택 (Feature Selection):\n중요한 특성만을 선택하여 모델을 단순화하고 성능을 향상시킵니다. 특성 생성 (Feature Generation):\n기존 특성에서 새로운 특성을 생성하여 모델의 성능을 개선합니다. 4. 하이퍼파라미터 튜닝 (Hyperparameter Tuning) 모델의 하이퍼파라미터를 최적화하여 성능을 향상시키는 방법입니다.\n그리드 서치 (Grid Search): 여러 하이퍼파라미터 조합을 시도하여 최적의 조합을 찾습니다. from sklearn.model_selection import GridSearchCV param_grid = { \u0026#39;max_depth\u0026#39;: [3, 5, 7], \u0026#39;min_samples_split\u0026#39;: [2, 5, 10], \u0026#39;min_samples_leaf\u0026#39;: [1, 2, 5] } grid_search = GridSearchCV(DecisionTreeClassifier(), param_grid, cv=5) grid_search.fit(X_train, y_train) 랜덤 서치 (Random Search): 무작위로 하이퍼파라미터 조합을 시도하여 최적의 조합을 찾습니다. from sklearn.model_selection import RandomizedSearchCV param_distributions = { \u0026#39;max_depth\u0026#39;: [3, 5, 7, None], \u0026#39;min_samples_split\u0026#39;: [2, 5, 10], \u0026#39;min_samples_leaf\u0026#39;: [1, 2, 5], \u0026#39;max_features\u0026#39;: [\u0026#39;auto\u0026#39;, \u0026#39;sqrt\u0026#39;, \u0026#39;log2\u0026#39;] } random_search = RandomizedSearchCV(DecisionTreeClassifier(), param_distributions, n_iter=100, cv=5, random_state=42) random_search.fit(X_train, y_train) 5. 데이터 전처리 (Data Preprocessing) 데이터 정규화 (Normalization): 데이터의 스케일을 조정하여 모델의 성능을 개선할 수 있습니다. 결측치 처리 (Handling Missing Values): 결측치를 적절히 처리하여 모델의 정확성을 높일 수 있습니다. 이 방법들을 조합하여 사용하면 결정 트리의 정확도를 높이고 성능을 개선할 수 있습니다.\n","date":"2024-07-28T00:00:00+09:00","image":"/images/posts/2024-07-28-혼공머신5-1-1/cover.jpg","permalink":"/ko/posts/2024-07-28-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A05-1-1/","title":"[혼공머신]5-1"},{"content":"결정 트리 (Decision Tree) 결정 트리는 예/아니오에 대한 질문을 통해 데이터를 분류하거나 예측하는 데 사용되는 알고리즘입니다. 이해하기 쉽고, 예측 과정도 투명하게 드러나기 때문에 매우 유용한 도구입니다.\n핵심 포인트 불순도 (Impurity): 결정 트리는 데이터를 나눌 때, 각 분할이 얼마나 순수한지를 평가합니다. 사이킷런은 지니 불순도와 엔트로피 불순도를 제공합니다. 불순도는 노드의 순수도를 나타내는 척도로, 낮을수록 더 순수합니다. 정보 이득 (Information Gain): 정보 이득은 부모 노드와 자식 노드의 불순도 차이로 정의됩니다. 결정 트리는 정보 이득이 최대화되도록 학습합니다. 과대적합 (Overfitting): 결정 트리는 트리가 너무 깊어지면 훈련 데이터에 과대적합될 수 있습니다. 이를 방지하기 위해 가지치기 (Pruning)을 사용합니다. 사이킷런은 여러 가지 가지치기 매개변수를 제공합니다. 특성 중요도 (Feature Importance): 결정 트리는 각 특성이 분할에 기여한 정도를 계산할 수 있습니다. 이는 모델의 해석성을 높여주는 중요한 장점입니다. 결정 트리 알고리즘 이해하기 결정 트리 알고리즘은 데이터 분류와 회귀 문제를 해결하는 데 사용됩니다. 예/아니오와 같은 질문을 반복하여 데이터를 분할하며, 최종적으로 목표 변수의 예측을 돕습니다. 아래는 결정 트리의 시각화와 이를 읽는 방법에 대한 설명입니다.\n결정 트리 시각화 트리 시각화 해독 방법 노드 (Node):\n각 사각형은 하나의 노드를 나타냅니다. 노드는 데이터를 특정 특성에 따라 분할합니다. 루트 노드 (Root Node):\n트리의 최상단에 위치한 노드입니다. 전체 데이터를 가장 잘 분할하는 기준을 나타냅니다. 내부 노드 (Internal Node):\n루트 노드 아래에 위치한 노드들입니다. 데이터를 계속 분할하여 보다 구체적인 질문을 만듭니다. 리프 노드 (Leaf Node):\n더 이상 분할되지 않는 최종 노드입니다. 각 리프 노드는 최종 예측을 나타냅니다. 노드 구성 요소:\n특성 (Feature): 노드가 데이터를 분할하는 기준이 되는 특성입니다. 임계값 (Threshold): 분할 기준이 되는 값입니다. gini: 지니 불순도로, 0에 가까울수록 순수한 노드를 나타냅니다. samples: 노드에 있는 샘플의 수입니다. value: 각 클래스에 속한 샘플의 수입니다. class: 예측 클래스입니다. 결정 트리 시각화 예제 코드 설명 데이터 생성 및 전처리 from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split # 데이터 생성 X, y = make_classification(n_samples=100, n_features=4, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) make_classification(): 분류 문제를 위한 가상 데이터를 생성합니다. train_test_split(): 데이터를 훈련 세트와 테스트 세트로 나눕니다. 결정 트리 모델 학습 from sklearn.tree import DecisionTreeClassifier # 모델 학습 model = DecisionTreeClassifier(criterion=\u0026#39;gini\u0026#39;, max_depth=3, random_state=42) model.fit(X_train, y_train) DecisionTreeClassifier(): 결정 트리 분류기를 생성합니다. criterion='gini': 지니 불순도를 사용하여 노드를 분할합니다. max_depth=3: 트리의 최대 깊이를 3으로 제한하여 과대적합을 방지합니다. random_state=42: 결과 재현성을 위해 랜덤 시드를 설정합니다. fit(): 모델을 학습 데이터에 맞춰 학습시킵니다. 결정 트리 시각화 from sklearn.tree import plot_tree import matplotlib.pyplot as plt # 트리 시각화 plt.figure(figsize=(20,10)) plot_tree(model, filled=True, feature_names=[f\u0026#39;Feature {i}\u0026#39; for i in range(1, 5)]) plt.show() plot_tree(): 결정 트리 모델을 시각화합니다. filled=True: 각 노드를 색으로 채워 타깃값을 시각적으로 구분합니다. feature_names=[f'Feature {i}' for i in range(1, 5)]: 특성의 이름을 그래프에 표시합니다. plt.show(): 시각화된 트리를 화면에 출력합니다. 이 시각화는 결정 트리 모델이 어떻게 데이터를 분류하고 있는지를 직관적으로 보여줍니다. 각 노드에서 데이터를 분할하는 기준과 그에 따른 결과를 이해할 수 있습니다.\n","date":"2024-07-28T00:00:00+09:00","image":"/images/posts/2024-07-28-혼공머신5-1-2/cover.jpg","permalink":"/ko/posts/2024-07-28-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A05-1-2/","title":"[혼공머신]5-1-2"},{"content":"하이퍼파라미터를 튜닝하는 방법 그리드 서치와 랜덤 서치 외에도 하이퍼파라미터를 튜닝하는 방법은 여러 가지가 있습니다. 대표적으로는 베이지안 최적화, 하이퍼밴드(Hyperband), 그리고 진화 알고리즘(Evolutionary Algorithms) 등이 있습니다. 각각의 방법을 예시 코드와 함께 구체적으로 설명하겠습니다.\n1. 베이지안 최적화 (Bayesian Optimization) 베이지안 최적화는 함수의 최대값이나 최소값을 찾는 데 사용되는 방법으로, 하이퍼파라미터 튜닝에 자주 사용됩니다. 이를 위해 scikit-optimize 라이브러리의 BayesSearchCV를 사용할 수 있습니다.\nfrom skopt import BayesSearchCV from sklearn.datasets import load_iris from sklearn.svm import SVC # 데이터 준비 iris = load_iris() X, y = iris.data, iris.target # SVM 모델 정의 svc = SVC() # 하이퍼파라미터 범위 설정 param_space = { \u0026#39;C\u0026#39;: (1e-6, 1e+6, \u0026#39;log-uniform\u0026#39;), \u0026#39;gamma\u0026#39;: (1e-6, 1e+1, \u0026#39;log-uniform\u0026#39;), \u0026#39;degree\u0026#39;: (1, 8), \u0026#39;kernel\u0026#39;: [\u0026#39;linear\u0026#39;, \u0026#39;poly\u0026#39;, \u0026#39;rbf\u0026#39;] } # 베이지안 최적화 수행 opt = BayesSearchCV(estimator=svc, search_spaces=param_space, n_iter=32, cv=3, n_jobs=-1, random_state=42) opt.fit(X, y) # 최적의 하이퍼파라미터와 성능 출력 print(\u0026#34;Best parameters:\u0026#34;, opt.best_params_) print(\u0026#34;Best cross-validation score:\u0026#34;, opt.best_score_) 2. 하이퍼밴드 (Hyperband) 하이퍼밴드는 자원의 효율적인 할당을 통해 하이퍼파라미터 최적화를 수행하는 방법입니다. scikit-optimize 라이브러리의 SuccessiveHalvingSearchCV를 사용하여 구현할 수 있습니다.\nfrom sklearn.experimental import enable_halving_search_cv # noqa from sklearn.model_selection import HalvingGridSearchCV from sklearn.ensemble import RandomForestClassifier # 데이터 준비 X, y = load_iris(return_X_y=True) # 랜덤 포레스트 모델 정의 rfc = RandomForestClassifier() # 하이퍼파라미터 범위 설정 param_grid = { \u0026#39;max_depth\u0026#39;: [3, 5, 10, 20], \u0026#39;min_samples_split\u0026#39;: [2, 5, 10], \u0026#39;min_samples_leaf\u0026#39;: [1, 2, 4], \u0026#39;n_estimators\u0026#39;: [10, 50, 100] } # 하이퍼밴드 수행 hb_search = HalvingGridSearchCV(estimator=rfc, param_grid=param_grid, factor=2, random_state=42) hb_search.fit(X, y) # 최적의 하이퍼파라미터와 성능 출력 print(\u0026#34;Best parameters:\u0026#34;, hb_search.best_params_) print(\u0026#34;Best cross-validation score:\u0026#34;, hb_search.best_score_) 3. 진화 알고리즘 (Evolutionary Algorithms) 진화 알고리즘은 유전 알고리즘 등을 사용해 하이퍼파라미터를 최적화하는 방법입니다. DEAP 라이브러리를 사용하여 구현할 수 있습니다.\nimport numpy as np from deap import base, creator, tools, algorithms from sklearn.model_selection import cross_val_score from sklearn.svm import SVC # 데이터 준비 X, y = load_iris(return_X_y=True) # SVM 모델 정의 def evaluate(individual): C, gamma = individual clf = SVC(C=C, gamma=gamma) return cross_val_score(clf, X, y, cv=3).mean(), # 하이퍼파라미터 범위 설정 toolbox = base.Toolbox() toolbox.register(\u0026#34;attr_float\u0026#34;, np.random.uniform, 1e-6, 1e+6) toolbox.register(\u0026#34;individual\u0026#34;, tools.initCycle, creator.Individual, (toolbox.attr_float, toolbox.attr_float), n=1) toolbox.register(\u0026#34;population\u0026#34;, tools.initRepeat, list, toolbox.individual) # 진화 알고리즘 설정 toolbox.register(\u0026#34;mate\u0026#34;, tools.cxBlend, alpha=0.5) toolbox.register(\u0026#34;mutate\u0026#34;, tools.mutGaussian, mu=0, sigma=1, indpb=0.2) toolbox.register(\u0026#34;select\u0026#34;, tools.selTournament, tournsize=3) toolbox.register(\u0026#34;evaluate\u0026#34;, evaluate) # 진화 알고리즘 수행 population = toolbox.population(n=50) ngen = 10 cxpb = 0.5 mutpb = 0.2 algorithms.eaSimple(population, toolbox, cxpb, mutpb, ngen, verbose=True) # 최적의 하이퍼파라미터와 성능 출력 best_individual = tools.selBest(population, k=1)[0] print(\u0026#34;Best individual:\u0026#34;, best_individual) print(\u0026#34;Best cross-validation score:\u0026#34;, evaluate(best_individual)) 요약 베이지안 최적화: 하이퍼파라미터 공간을 효율적으로 탐색. 하이퍼밴드: 자원 효율성을 높여 탐색. 진화 알고리즘: 유전 알고리즘을 사용해 탐색. 이들 방법은 각기 다른 특성을 가지며, 문제의 특성과 자원 제약에 따라 적절한 방법을 선택해 사용할 수 있습니다.\n","date":"2024-07-28T00:00:00+09:00","image":"/images/posts/2024-07-28-혼공머신5-2-2/cover.jpg","permalink":"/ko/posts/2024-07-28-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A05-2-2/","title":"[혼공머신]5-2-2 -추가학습(하이퍼파라미터 튜닝)"},{"content":"XGBoost와 LightGBM XGBoost와 LightGBM은 그레이디언트 부스팅의 구현체로, 빠르고 효율적인 알고리즘을 제공합니다. 이들은 특히 대규모 데이터셋에 대해 뛰어난 성능을 발휘합니다.\nXGBoost XGBoost는 Extreme Gradient Boosting의 약자로, 효율적이고 확장 가능한 그레이디언트 부스팅 알고리즘입니다. 주요 특징은 다음과 같습니다:\nRegularization: 과적합을 방지하기 위한 정규화 기법을 포함합니다. Parallel Processing: 병렬 처리를 통해 학습 속도를 향상시킵니다. Tree Pruning: 최적의 트리 크기를 찾기 위해 사후 가지치기를 사용합니다. Sparsity Awareness: 희소 데이터(예: 결측값)에 대한 최적화를 포함합니다. Cross Validation: 내부적으로 교차 검증을 통해 모델의 성능을 평가할 수 있습니다. XGBoost 예제 코드 from xgboost import XGBClassifier from sklearn.model_selection import train_test_split, cross_validate import pandas as pd # 데이터 로드 및 전처리 wine = pd.read_csv(\u0026#39;https://bit.ly/wine_csv_data\u0026#39;) data = wine[[\u0026#39;alcohol\u0026#39;, \u0026#39;sugar\u0026#39;, \u0026#39;pH\u0026#39;]].to_numpy() target = wine[\u0026#39;class\u0026#39;].to_numpy() train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42) # XGBoost 모델 학습 xgb = XGBClassifier(tree_method=\u0026#39;hist\u0026#39;, random_state=42) scores = cross_validate(xgb, train_input, train_target, return_train_score=True, n_jobs=-1) print(np.mean(scores[\u0026#39;train_score\u0026#39;]), np.mean(scores[\u0026#39;test_score\u0026#39;])) xgb.fit(train_input, train_target) print(xgb.score(test_input, test_target)) LightGBM LightGBM은 Microsoft에서 개발한 그레이디언트 부스팅 프레임워크로, 다음과 같은 특징이 있습니다:\nLeaf-wise Growth: 기존의 레벨-wise 방식과 달리, 잎사귀 수준에서 가장 손실이 큰 잎사귀를 먼저 분할합니다. 이로 인해 훈련 속도가 빠르고, 더 나은 성능을 보일 수 있습니다. Histogram-based: 연속형 특성을 히스토그램으로 변환하여 효율성을 높입니다. Sparse Optimization: 희소 데이터에 대한 최적화 기법을 포함합니다. Categorical Features: 범주형 변수를 자동으로 처리합니다. LightGBM 예제 코드 from lightgbm import LGBMClassifier from sklearn.model_selection import train_test_split, cross_validate import pandas as pd # 데이터 로드 및 전처리 wine = pd.read_csv(\u0026#39;https://bit.ly/wine_csv_data\u0026#39;) data = wine[[\u0026#39;alcohol\u0026#39;, \u0026#39;sugar\u0026#39;, \u0026#39;pH\u0026#39;]].to_numpy() target = wine[\u0026#39;class\u0026#39;].to_numpy() train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42) # LightGBM 모델 학습 lgb = LGBMClassifier(random_state=42) scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-1) print(np.mean(scores[\u0026#39;train_score\u0026#39;]), np.mean(scores[\u0026#39;test_score\u0026#39;])) lgb.fit(train_input, train_target) print(lgb.score(test_input, test_target)) 요약 랜덤 포레스트: 여러 결정 트리를 생성하고, 각 트리의 예측을 결합하여 최종 예측을 만듭니다. 엑스트라 트리: 랜덤 포레스트와 유사하지만, 노드 분할 시 더 많은 무작위성을 도입하여 과적합을 줄입니다. 그레이디언트 부스팅: 각 트리가 이전 트리의 오류를 보완하도록 순차적으로 트리를 추가합니다. 히스토그램 기반 그레이디언트 부스팅: 그레이디언트 부스팅의 개선 버전으로, 히스토그램을 사용하여 학습 속도를 높입니다. XGBoost: 고효율의 그레이디언트 부스팅 구현체로, 병렬 처리와 정규화 등의 기능을 포함합니다. LightGBM: 빠르고 확장 가능한 그레이디언트 부스팅 프레임워크로, 잎사귀 수준의 성장과 히스토그램 기반의 최적화를 사용합니다. 각 알고리즘의 장단점을 이해하고 적절히 활용하면 머신러닝 모델의 성능을 극대화할 수 있습니다.\n","date":"2024-07-28T00:00:00+09:00","image":"/images/posts/2024-07-28-혼공머신5-3-1/cover.jpg","permalink":"/ko/posts/2024-07-28-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A05-3-1/","title":"[혼공머신]5-3"},{"content":"기타 앙상블학습 앙상블 학습에는 다양한 방법들이 있으며, 여기서는 그 중 일부를 소개하겠습니다. 대표적인 앙상블 방법으로 배깅(Bagging), 부스팅(Boosting), 스태킹(Stacking), 그리고 배깅의 일종인 랜덤 서브스페이스(Random Subspace)를 설명하고, 예시 코드를 제공합니다.\n배깅 (Bagging) 배깅은 같은 모델을 여러 개 학습시키고, 데이터의 부분 집합을 사용하여 각각의 모델을 학습시킨 후, 예측 시 이들의 평균 또는 투표 결과를 사용하는 방법입니다. 랜덤 포레스트가 대표적인 배깅 기법입니다.\n배깅 예제 코드 from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split, cross_validate import pandas as pd # 데이터 로드 및 전처리 wine = pd.read_csv(\u0026#39;https://bit.ly/wine_csv_data\u0026#39;) data = wine[[\u0026#39;alcohol\u0026#39;, \u0026#39;sugar\u0026#39;, \u0026#39;pH\u0026#39;]].to_numpy() target = wine[\u0026#39;class\u0026#39;].to_numpy() train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42) # 배깅 모델 학습 bagging = BaggingClassifier(DecisionTreeClassifier(), n_estimators=100, random_state=42) scores = cross_validate(bagging, train_input, train_target, return_train_score=True, n_jobs=-1) print(np.mean(scores[\u0026#39;train_score\u0026#39;]), np.mean(scores[\u0026#39;test_score\u0026#39;])) bagging.fit(train_input, train_target) print(bagging.score(test_input, test_target)) 부스팅 (Boosting) 부스팅은 약한 학습기(Weak Learner)를 순차적으로 학습시키고, 이전 모델의 오류를 수정해 나가는 방식입니다. 그레이디언트 부스팅, XGBoost, LightGBM 등이 여기에 속합니다.\n부스팅 예제 코드 그레이디언트 부스팅은 앞서 다룬 예시를 참조하십시오.\n스태킹 (Stacking) 스태킹은 여러 모델을 학습시키고, 이들의 예측 결과를 새로운 모델의 입력으로 사용하여 최종 예측을 수행하는 방법입니다. 다양한 모델의 조합을 통해 성능을 향상시킬 수 있습니다.\n스태킹 예제 코드 from sklearn.ensemble import StackingClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split, cross_validate import pandas as pd # 데이터 로드 및 전처리 wine = pd.read_csv(\u0026#39;https://bit.ly/wine_csv_data\u0026#39;) data = wine[[\u0026#39;alcohol\u0026#39;, \u0026#39;sugar\u0026#39;, \u0026#39;pH\u0026#39;]].to_numpy() target = wine[\u0026#39;class\u0026#39;].to_numpy() train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42) # 기본 모델 정의 estimators = [ (\u0026#39;dt\u0026#39;, DecisionTreeClassifier(random_state=42)), (\u0026#39;svc\u0026#39;, SVC(random_state=42)) ] # 스태킹 모델 학습 stacking = StackingClassifier(estimators=estimators, final_estimator=LogisticRegression()) scores = cross_validate(stacking, train_input, train_target, return_train_score=True, n_jobs=-1) print(np.mean(scores[\u0026#39;train_score\u0026#39;]), np.mean(scores[\u0026#39;test_score\u0026#39;])) stacking.fit(train_input, train_target) print(stacking.score(test_input, test_target)) 랜덤 서브스페이스 (Random Subspace) 랜덤 서브스페이스는 배깅의 변형으로, 각 모델을 학습할 때마다 특성 공간의 무작위 부분 집합을 사용합니다. 이를 통해 모델의 다양성을 높입니다.\n랜덤 서브스페이스 예제 코드 from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split, cross_validate import pandas as pd # 데이터 로드 및 전처리 wine = pd.read_csv(\u0026#39;https://bit.ly/wine_csv_data\u0026#39;) data = wine[[\u0026#39;alcohol\u0026#39;, \u0026#39;sugar\u0026#39;, \u0026#39;pH\u0026#39;]].to_numpy() target = wine[\u0026#39;class\u0026#39;].to_numpy() train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42) # 랜덤 서브스페이스 모델 학습 random_subspace = BaggingClassifier(DecisionTreeClassifier(), n_estimators=100, max_features=2, random_state=42) scores = cross_validate(random_subspace, train_input, train_target, return_train_score=True, n_jobs=-1) print(np.mean(scores[\u0026#39;train_score\u0026#39;]), np.mean(scores[\u0026#39;test_score\u0026#39;])) random_subspace.fit(train_input, train_target) print(random_subspace.score(test_input, test_target)) 이와 같이 다양한 앙상블 기법을 활용하면 머신러닝 모델의 성능을 크게 향상시킬 수 있습니다. 각 기법의 특징과 사용 사례를 이해하고, 문제에 맞는 방법을 선택하여 적용하는 것이 중요합니다.\n","date":"2024-07-28T00:00:00+09:00","image":"/images/posts/2024-07-28-혼공머신5-3-2/cover.jpg","permalink":"/ko/posts/2024-07-28-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A05-3-2/","title":"[혼공머신]5-3-2 -추가학습(기타 앙상블학습)"},{"content":"교차검증과 그리드 서치 1. 검증 세트 검증 세트는 하이퍼파라미터 튜닝을 위해 훈련 세트에서 분리한 데이터 세트입니다. 모델의 성능을 평가할 때, 테스트 세트를 사용하지 않도록 합니다.\nimport pandas as pd # 데이터 불러오기 및 전처리 wine = pd.read_csv(\u0026#39;https://bit.ly/wine_csv_data\u0026#39;) data = wine[[\u0026#39;alcohol\u0026#39;, \u0026#39;sugar\u0026#39;, \u0026#39;pH\u0026#39;]].to_numpy() target = wine[\u0026#39;class\u0026#39;].to_numpy() # 훈련 세트와 테스트 세트로 분리 from sklearn.model_selection import train_test_split train_input, test_input, train_target, test_target = train_test_split( data, target, test_size=0.2, random_state=42) # 훈련 세트에서 다시 검증 세트로 분리 sub_input, val_input, sub_target, val_target = train_test_split( train_input, train_target, test_size=0.2, random_state=42) print(sub_input.shape, val_input.shape) 위 코드에서 데이터를 불러와 훈련 세트와 테스트 세트로 나눈 후, 다시 훈련 세트를 서브 세트와 검증 세트로 분리합니다.\n2. 교차 검증 교차 검증은 훈련 세트를 여러 폴드로 나누어, 각 폴드를 번갈아 가며 검증 세트로 사용하고 나머지 폴드를 훈련 세트로 사용하는 방법입니다.\n교차검증 방법\n데이터를 K개의 폴드로 나눕니다.\n각 폴드를 번갈아 가며 검증 세트로 사용하고 나머지 폴드를 훈련 세트로 사용하여 모델을 훈련하고 평가합니다.\n모든 폴드에 대해 검증 점수를 얻고, 이를 평균하여 최종 성능을 평가합니다.\n아래는 5-폴드 교차 검증의 예시 그림입니다.\nFold 1: 첫 번째 폴드를 검증 세트로 사용하고, 나머지 폴드를 훈련 세트로 사용합니다.\nFold 2: 두 번째 폴드를 검증 세트로 사용하고, 나머지 폴드를 훈련 세트로 사용합니다.\nFold 3: 세 번째 폴드를 검증 세트로 사용하고, 나머지 폴드를 훈련 세트로 사용합니다.\nFold 4: 네 번째 폴드를 검증 세트로 사용하고, 나머지 폴드를 훈련 세트로 사용합니다.\nFold 5: 다섯 번째 폴드를 검증 세트로 사용하고, 나머지 폴드를 훈련 세트로 사용합니다.\n교차 검증을 통한 모델 평가 과정\n데이터 분할: 전체 데이터를 K개의 폴드로 나눕니다. 모델 훈련 및 검증: 각 폴드에 대해 모델을 훈련하고 검증합니다. 훈련 세트는 (K-1)개의 폴드로 구성되고, 검증 세트는 1개의 폴드로 구성됩니다. 평균 검증 점수 계산: 각 폴드에서 얻은 검증 점수를 평균하여 최종 성능을 평가합니다. from sklearn.tree import DecisionTreeClassifier # 기본 의사결정나무 모델 훈련 및 평가 dt = DecisionTreeClassifier(random_state=42) dt.fit(sub_input, sub_target) print(dt.score(sub_input, sub_target)) print(dt.score(val_input, val_target)) # 교차 검증 from sklearn.model_selection import cross_validate scores = cross_validate(dt, train_input, train_target) print(scores) import numpy as np print(np.mean(scores[\u0026#39;test_score\u0026#39;])) 이 코드는 기본 의사결정나무 모델을 훈련하고 검증 세트를 사용해 성능을 평가합니다. 이어서 cross_validate 함수를 사용해 교차 검증을 수행하고, 각 폴드의 성능을 출력합니다.\nfrom sklearn.model_selection import StratifiedKFold # StratifiedKFold를 사용한 교차 검증 scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold()) print(np.mean(scores[\u0026#39;test_score\u0026#39;])) # 10-폴드 교차 검증 splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42) scores = cross_validate(dt, train_input, train_target, cv=splitter) print(np.mean(scores[\u0026#39;test_score\u0026#39;])) 여기서는 StratifiedKFold를 사용해 계층적 폴드를 생성하고 교차 검증을 수행합니다. 10-폴드 교차 검증을 통해 모델의 성능을 평가합니다.\n3. 하이퍼파라미터 튜닝 하이퍼파라미터 튜닝은 모델의 성능을 최적화하기 위해 필요한 단계입니다. 이를 위해 그리드 서치와 랜덤 서치를 사용합니다.\n그리드 서치 from sklearn.model_selection import GridSearchCV # 그리드 서치를 위한 하이퍼파라미터 설정 params = {\u0026#39;min_impurity_decrease\u0026#39;: [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]} # 그리드 서치 수행 gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1) gs.fit(train_input, train_target) # 최적의 모델 및 하이퍼파라미터 dt = gs.best_estimator_ print(dt.score(train_input, train_target)) print(gs.best_params_) print(gs.cv_results_[\u0026#39;mean_test_score\u0026#39;]) best_index = np.argmax(gs.cv_results_[\u0026#39;mean_test_score\u0026#39;]) print(gs.cv_results_[\u0026#39;params\u0026#39;][best_index]) 이 코드는 GridSearchCV를 사용해 다양한 하이퍼파라미터 조합을 평가하고, 최적의 하이퍼파라미터를 찾습니다.\n# 확장된 하이퍼파라미터 그리드 설정 params = {\u0026#39;min_impurity_decrease\u0026#39;: np.arange(0.0001, 0.001, 0.0001), \u0026#39;max_depth\u0026#39;: range(5, 20, 1), \u0026#39;min_samples_split\u0026#39;: range(2, 100, 10) } gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1) gs.fit(train_input, train_target) print(gs.best_params_) print(np.max(gs.cv_results_[\u0026#39;mean_test_score\u0026#39;])) 이 코드는 더 넓은 범위의 하이퍼파라미터를 탐색하여 최적의 조합을 찾습니다.\n랜덤 서치 from scipy.stats import uniform, randint # 랜덤 서치를 위한 하이퍼파라미터 분포 설정 params = {\u0026#39;min_impurity_decrease\u0026#39;: uniform(0.0001, 0.001), \u0026#39;max_depth\u0026#39;: randint(20, 50), \u0026#39;min_samples_split\u0026#39;: randint(2, 25), \u0026#39;min_samples_leaf\u0026#39;: randint(1, 25) } from sklearn.model_selection import RandomizedSearchCV # 랜덤 서치 수행 gs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42), params, n_iter=100, n_jobs=-1, random_state=42) gs.fit(train_input, train_target) print(gs.best_params_) print(np.max(gs.cv_results_[\u0026#39;mean_test_score\u0026#39;])) dt = gs.best_estimator_ print(dt.score(test_input, test_target)) 여기서는 RandomizedSearchCV를 사용해 랜덤한 하이퍼파라미터 조합을 평가하고 최적의 모델을 찾습니다.\n문제 해결 과정 - 최적의 모델을 위한 하이퍼파라미터 튜닝 위의 과정을 통해 최적의 모델을 찾기 위한 하이퍼파라미터 튜닝 과정을 정리할 수 있습니다.\n데이터 준비: 데이터를 훈련 세트와 테스트 세트로 나눕니다. 모델 선택: 사용할 모델을 선택합니다. (예: 의사결정나무) 교차 검증 설정: 교차 검증을 위한 폴드 수를 설정합니다. 하이퍼파라미터 탐색: 그리드 서치 또는 랜덤 서치를 사용하여 최적의 하이퍼파라미터를 찾습니다. 최종 모델 훈련: 찾은 최적의 하이퍼파라미터로 전체 훈련 세트를 사용해 최종 모델을 훈련합니다. 모델 평가: 테스트 세트를 사용해 최종 모델의 성능을 평가합니다. 이와 같은 과정을 통해 모델의 예측 성능을 최대화할 수 있습니다.\n","date":"2024-07-28T00:00:00+09:00","image":"/images/posts/2024-07-28-혼공머신5-2-1/cover.jpg","permalink":"/ko/posts/2024-07-28-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A05-2-1/","title":"혼공머신5-2-1"},{"content":"로지스틱 회귀 로지스틱 회귀는 선형 회귀와 달리 분류 문제에 사용되는 지도 학습 알고리즘입니다. 주요한 특징은 선형 방정식을 사용하여 데이터 포인트를 분류하는데, 이 과정에서 시그모이드 함수나 소프트맥스 함수를 사용해 클래스 확률을 출력합니다.\n핵심 개념 로지스틱 회귀 (Logistic Regression)\n선형 회귀와 달리, 로지스틱 회귀는 이진 분류 문제에 사용됩니다. 출력값은 시그모이드 함수에 의해 0과 1 사이의 확률 값으로 변환됩니다. 시그모이드 함수 (Sigmoid Function)\n$ \\sigma(x) = \\frac{1}{1 + e^{-x}} $ 선형 방정식의 출력을 0과 1 사이의 값으로 압축합니다. 주로 이진 분류에서 사용됩니다. 소프트맥스 함수 (Softmax Function)\n다중 분류 문제에서 사용됩니다. 여러 선형 방정식의 출력을 정규화하여 확률 분포를 만듭니다. 각 클래스의 확률 합이 1이 되도록 조정합니다. 주요 패키지 및 함수 (scikit-learn) LogisticRegression\n로지스틱 회귀를 위한 클래스입니다. solver 매개변수로 최적화 알고리즘을 선택할 수 있습니다. 예: 'lbfgs', 'sag', 'saga'. penalty 매개변수로 규제 방법을 선택합니다. 예: 'l2' (릿지), 'l1' (라쏘). C 매개변수로 규제 강도를 제어합니다. 기본값은 1.0입니다. predict_proba()\n예측 확률을 반환합니다. 이진 분류의 경우 음성 클래스와 양성 클래스의 확률을 반환합니다. 다중 분류의 경우 모든 클래스에 대한 확률을 반환합니다. decision_function()\n모델이 학습한 선형 방정식의 출력을 반환합니다. 이진 분류의 경우 양성 클래스의 점수를 반환합니다. 다중 분류의 경우 각 클래스에 대한 선형 방정식의 결과를 반환합니다. 예제 코드 설명 노트북에 포함된 주요 코드 블록들을 설명하면 다음과 같습니다.\n데이터 전처리 및 모델 훈련\nfrom sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression import numpy as np # 데이터셋을 훈련 세트와 테스트 세트로 분할 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 데이터 스케일링 scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # 로지스틱 회귀 모델 훈련 lr = LogisticRegression() lr.fit(X_train_scaled, y_train) 예측 및 확률 계산\n# 테스트 데이터에 대한 예측 확률 계산 proba = lr.predict_proba(X_test_scaled[:5]) print(np.round(proba, decimals=3)) # 결정 함수 값 계산 decision = lr.decision_function(X_test_scaled[:5]) print(np.round(decision, decimals=2)) 소프트맥스 함수 적용\nfrom scipy.special import softmax # 결정 함수 값을 소프트맥스 함수로 확률 변환 proba = softmax(decision, axis=1) print(np.round(proba, decimals=3)) 추가 정보 오버피팅과 언더피팅: 모델의 일반화 성능을 평가하고 조절하는 방법. 정규화 기법: L1, L2 정규화를 사용하여 모델의 복잡도를 제어하는 방법. 최적화 알고리즘: Gradient Descent, Stochastic Gradient Descent 등 다양한 최적화 방법의 원리와 적용법. ","date":"2024-07-21T00:00:00+09:00","image":"/images/posts/2024-07-21-혼공머신4-1-1/cover.jpg","permalink":"/ko/posts/2024-07-21-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A04-1-1/","title":"[혼공머신]4-1"},{"content":"정규화 기법 (Regularization Techniques) 정규화는 머신러닝 모델의 과적합(overfitting)을 방지하고 일반화 성능을 향상시키기 위해 사용되는 기법입니다. 특히 로지스틱 회귀와 같은 선형 모델에서 중요한 역할을 합니다. 정규화는 모델의 복잡도를 줄여, 학습 데이터에 너무 치우치지 않도록 하는 데 도움을 줍니다. 주로 사용되는 정규화 기법에는 L1 정규화와 L2 정규화가 있습니다.\n1. L1 정규화 (Lasso Regularization) L1 정규화는 가중치 벡터의 절대값 합을 패널티로 추가하는 방식입니다.\n수식: $$ \\text{Loss function} = \\text{original loss} + \\lambda \\sum_{j=1}^{p} |w_j| $$ 여기서 $ \\lambda $는 정규화 강도를 제어하는 하이퍼파라미터이고,$ w_j $는 모델의 가중치입니다.\n특징:\nL1 정규화는 일부 가중치를 정확히 0으로 만듭니다. 이는 변수 선택(feature selection) 효과를 가지며, 모델을 더 해석 가능하게 만듭니다. 희소 모델(sparse model)을 생성하는 데 유리합니다. 2. L2 정규화 (Ridge Regularization) L2 정규화는 가중치 벡터의 제곱 합을 패널티로 추가하는 방식입니다.\n수식: $$ \\text{Loss function} = \\text{original loss} + \\lambda \\sum_{j=1}^{p} w_j^2 $$ 특징:\n모든 가중치를 작게 만들어, 모델이 극단적인 가중치 값을 가지지 않도록 합니다. L2 정규화는 가중치를 0에 가깝게 만들지만 정확히 0으로 만들지는 않습니다. 3. Elastic Net Regularization Elastic Net은 L1 정규화와 L2 정규화를 결합한 방식입니다. 두 패널티를 모두 사용하는 모델입니다.\n수식: $$ \\text{Loss function} = \\text{original loss} + \\lambda_1 \\sum_{j=1}^{p} |w_j| + \\lambda_2 \\sum_{j=1}^{p} w_j^2 $$ 특징:\nL1과 L2 정규화의 장점을 모두 취합니다. 변수 선택과 함께 모든 변수의 가중치를 적절히 줄여줍니다. 실습 예제 다음은 L1, L2, 그리고 Elastic Net 정규화를 적용한 로지스틱 회귀 모델의 예제입니다.\nfrom sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.datasets import load_iris # 데이터셋 로드 및 분할 iris = load_iris() X, y = iris.data, iris.target X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 데이터 스케일링 scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # L1 정규화 적용 (라쏘 방식) lr_l1 = LogisticRegression(penalty=\u0026#39;l1\u0026#39;, solver=\u0026#39;saga\u0026#39;, C=1.0, max_iter=10000) lr_l1.fit(X_train_scaled, y_train) print(\u0026#34;L1 정규화 모델의 정확도:\u0026#34;, lr_l1.score(X_test_scaled, y_test)) # L2 정규화 적용 (릿지 방식) lr_l2 = LogisticRegression(penalty=\u0026#39;l2\u0026#39;, solver=\u0026#39;lbfgs\u0026#39;, C=1.0, max_iter=10000) lr_l2.fit(X_train_scaled, y_train) print(\u0026#34;L2 정규화 모델의 정확도:\u0026#34;, lr_l2.score(X_test_scaled, y_test)) # Elastic Net 정규화 적용 lr_en = LogisticRegression(penalty=\u0026#39;elasticnet\u0026#39;, solver=\u0026#39;saga\u0026#39;, l1_ratio=0.5, C=1.0, max_iter=10000) lr_en.fit(X_train_scaled, y_train) print(\u0026#34;Elastic Net 정규화 모델의 정확도:\u0026#34;, lr_en.score(X_test_scaled, y_test)) 이 코드는 Iris 데이터셋을 사용하여 L1, L2, Elastic Net 정규화를 각각 적용한 로지스틱 회귀 모델을 훈련시키고, 테스트 세트에 대한 모델의 정확도를 출력합니다.\n","date":"2024-07-21T00:00:00+09:00","image":"/images/posts/2024-07-21-혼공머신4-1-2/cover.jpg","permalink":"/ko/posts/2024-07-21-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A04-1-2/","title":"[혼공머신]4-1 -추가학습(정규화 기법)"},{"content":"확률적 경사 하강법(SGD, Stochastic Gradient Descent) 확률적 경사 하강법(SGD)은 기계 학습에서 널리 사용되는 최적화 알고리즘입니다. 이 알고리즘은 대규모 데이터 셋에서도 빠르고 효율적으로 동작합니다. 아래는 확률적 경사 하강법에 대한 핵심 포인트와 상세한 설명입니다.\n핵심 포인트 확률적 경사 하강법: 훈련 세트에서 샘플 하나씩 꺼내 손실 함수의 경사를 따라 최적의 모델을 찾는 알고리즘. 미니배치 경사 하강법: 여러 개의 샘플을 동시에 사용하는 방법. 배치 경사 하강법: 전체 샘플을 한 번에 사용하는 방법. 손실 함수: SGD가 최적화할 대상. 이진 분류에는 로지스틱 회귀, 다중 분류에는 크로스엔트로피 손실 함수, 회귀 문제에는 평균 제곱 오차 손실 함수를 사용. 에포크: 전체 샘플을 모두 사용하는 한 번의 반복. 수십에서 수백 번의 에포크를 반복. 주요 패키지와 함수 scikit-learn\nSGDClassifier : 확률적 경사 하강법을 사용한 분류 모델.\nloss 매개변수: 최적화할 손실 함수를 지정 (기본값은 \u0026lsquo;hinge\u0026rsquo; 손실 함수). penalty 매개변수: 규제의 종류를 지정 (기본값은 L2 규제를 위한 \u0026rsquo;l2\u0026rsquo;). alpha 매개변수: 규제 강도 (기본값은 0.0001). max_iter 매개변수: 에포크 횟수 지정 (기본값은 1000). tol 매개변수: 반복을 멈출 조건 (기본값은 0.001). SGDRegressor : 확률적 경사 하강법을 사용한 회귀 모델.\nloss 매개변수: 손실 함수를 지정 (기본값은 \u0026lsquo;squared_loss\u0026rsquo;). 1. 라이브러리 임포트 및 데이터 준비 먼저, 필요한 라이브러리를 임포트하고 데이터를 준비합니다.\nfrom sklearn.linear_model import SGDClassifier, SGDRegressor from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split # 예시 데이터 준비 X, y = load_some_data() # 적절한 데이터 로드 함수 사용 SGDClassifier, SGDRegressor: 확률적 경사 하강법을 사용한 분류 및 회귀 모델을 생성하는 클래스. StandardScaler: 데이터 표준화를 위한 클래스. train_test_split: 데이터를 훈련 세트와 테스트 세트로 분할하기 위한 함수. load_some_data(): 실제로는 사용자가 로드하는 데이터셋을 가져오는 함수입니다. 2. 데이터 분할 데이터를 훈련 세트와 테스트 세트로 분할합니다.\ntrain_data, test_data, train_target, test_target = train_test_split(X, y, test_size=0.2, random_state=42) train_test_split: 데이터를 무작위로 섞어서 훈련 세트와 테스트 세트로 나눕니다. test_size=0.2: 데이터의 20%를 테스트 세트로 사용합니다. random_state=42: 결과 재현성을 위해 난수 시드를 설정합니다. 3. 데이터 스케일링 훈련 세트와 테스트 세트를 표준화합니다.\nscaler = StandardScaler() train_scaled = scaler.fit_transform(train_data) test_scaled = scaler.transform(test_data) StandardScaler(): 각 특징의 평균을 0, 분산을 1로 맞추어 표준화합니다. fit_transform(train_data): 훈련 데이터의 평균과 분산을 계산하여 변환합니다. transform(test_data): 훈련 데이터의 평균과 분산을 사용하여 테스트 데이터를 변환합니다. 4. SGDClassifier 사용 예제 로지스틱 회귀를 사용한 확률적 경사 하강법 분류 모델을 학습시키고 평가합니다.\nclf = SGDClassifier(loss=\u0026#39;log\u0026#39;, max_iter=1000, tol=0.001, random_state=42) clf.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, clf.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, clf.score(test_scaled, test_target)) SGDClassifier(loss='log', max_iter=1000, tol=0.001, random_state=42): SGDClassifier 객체를 생성합니다. loss='log': 로지스틱 회귀 손실 함수를 사용합니다. max_iter=1000: 최대 1000번의 에포크 동안 학습합니다. tol=0.001: 손실 함수가 이 값 이하로 감소하면 학습을 중지합니다. random_state=42: 결과 재현성을 위해 난수 시드를 설정합니다. fit(train_scaled, train_target): 훈련 데이터를 사용하여 모델을 학습시킵니다. score(train_scaled, train_target): 훈련 세트에 대한 모델의 성능을 평가합니다. score(test_scaled, test_target): 테스트 세트에 대한 모델의 성능을 평가합니다. 5. SGDRegressor 사용 예제 제곱 오차를 사용한 확률적 경사 하강법 회귀 모델을 학습시키고 평가합니다.\nreg = SGDRegressor(loss=\u0026#39;squared_loss\u0026#39;, max_iter=1000, tol=0.001, random_state=42) reg.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, reg.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, reg.score(test_scaled, test_target)) SGDRegressor(loss='squared_loss', max_iter=1000, tol=0.001, random_state=42): SGDRegressor 객체를 생성합니다. loss='squared_loss': 평균 제곱 오차 손실 함수를 사용합니다. max_iter=1000: 최대 1000번의 에포크 동안 학습합니다. tol=0.001: 손실 함수가 이 값 이하로 감소하면 학습을 중지합니다. random_state=42: 결과 재현성을 위해 난수 시드를 설정합니다. fit(train_scaled, train_target): 훈련 데이터를 사용하여 모델을 학습시킵니다. score(train_scaled, train_target): 훈련 세트에 대한 모델의 성능을 평가합니다. score(test_scaled, test_target): 테스트 세트에 대한 모델의 성능을 평가합니다. ","date":"2024-07-21T00:00:00+09:00","image":"/images/posts/2024-07-21-혼공머신4-2-1/cover.jpg","permalink":"/ko/posts/2024-07-21-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A04-2-1/","title":"[혼공머신]4-2"},{"content":"기타 손실함수 1. Hinge Loss (힌지 손실 함수) 특징: 주로 서포트 벡터 머신(SVM)에서 사용됩니다. 분류 문제에 적합하며, 데이터 포인트가 결정 경계를 넘어갈 때 손실을 가중합니다. 이진 분류 문제에서 많이 사용됩니다. 예시: from sklearn.linear_model import SGDClassifier clf = SGDClassifier(loss=\u0026#39;hinge\u0026#39;, max_iter=1000, tol=0.001, random_state=42) clf.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, clf.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, clf.score(test_scaled, test_target)) 2. Squared Hinge Loss (제곱 힌지 손실 함수) 특징: 힌지 손실의 변형으로, 제곱된 값을 사용하여 오류가 클 때 더 큰 패널티를 줍니다. 더 큰 마진을 제공하여 분류기의 일반화 능력을 향상시킵니다. 예시: clf = SGDClassifier(loss=\u0026#39;squared_hinge\u0026#39;, max_iter=1000, tol=0.001, random_state=42) clf.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, clf.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, clf.score(test_scaled, test_target)) 3. Huber Loss (후버 손실 함수) 특징: 회귀 문제에서 사용됩니다. 작은 오류에 대해서는 제곱 오차로 처리하고, 큰 오류에 대해서는 절대 오차로 처리하여 이상치에 강건한 성능을 보입니다. 예시: from sklearn.linear_model import SGDRegressor reg = SGDRegressor(loss=\u0026#39;huber\u0026#39;, max_iter=1000, tol=0.001, random_state=42) reg.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, reg.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, reg.score(test_scaled, test_target)) 4. Log Loss (로그 손실 함수 또는 로지스틱 손실 함수) 특징: 로지스틱 회귀에서 사용됩니다. 이진 분류 문제에 적합하며, 예측 확률과 실제 클래스 간의 차이를 측정합니다. 예시: clf = SGDClassifier(loss=\u0026#39;log\u0026#39;, max_iter=1000, tol=0.001, random_state=42) clf.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, clf.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, clf.score(test_scaled, test_target)) 5. Epsilon-Insensitive Loss (엡실론 민감 손실 함수) 특징: 서포트 벡터 회귀(SVR)에서 사용됩니다. 예측 값과 실제 값이 일정 범위(엡실론) 내에 있을 때 손실을 무시합니다. 회귀 문제에서 특정 오차 범위 내의 값을 무시하고, 이상치에 민감하지 않은 모델을 만듭니다. 예시: reg = SGDRegressor(loss=\u0026#39;epsilon_insensitive\u0026#39;, max_iter=1000, tol=0.001, random_state=42) reg.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, reg.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, reg.score(test_scaled, test_target)) 6. Squared Loss (제곱 오차 손실 함수) 특징: 회귀 문제에서 가장 일반적으로 사용됩니다. 예측 값과 실제 값의 차이를 제곱하여 손실을 계산합니다. 이상치에 민감할 수 있습니다. 예시: reg = SGDRegressor(loss=\u0026#39;squared_loss\u0026#39;, max_iter=1000, tol=0.001, random_state=42) reg.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, reg.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, reg.score(test_scaled, test_target)) 7. Perceptron Loss (퍼셉트론 손실 함수) 특징: 퍼셉트론 학습에서 사용됩니다. 분류 문제에 적합하며, 예측이 틀렸을 때만 손실을 계산합니다. 예시: clf = SGDClassifier(loss=\u0026#39;perceptron\u0026#39;, max_iter=1000, tol=0.001, random_state=42) clf.fit(train_scaled, train_target) print(\u0026#34;훈련 세트 점수:\u0026#34;, clf.score(train_scaled, train_target)) print(\u0026#34;테스트 세트 점수:\u0026#34;, clf.score(test_scaled, test_target)) 결론 이와 같이 다양한 손실 함수는 각기 다른 문제와 목표에 맞춰 최적의 성능을 발휘할 수 있도록 설계되었습니다. 각 손실 함수의 특성을 이해하고 적절히 선택하는 것이 모델 성능 향상의 핵심입니다.\n","date":"2024-07-21T00:00:00+09:00","image":"/images/posts/2024-07-21-혼공머신4-2-2/cover.jpg","permalink":"/ko/posts/2024-07-21-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A04-2-2/","title":"[혼공머신]4-2 -추가학습(기타 손실함수)"},{"content":"[혼공머신]3-1 1. 회귀 문제란? 회귀는 임의의 수치를 예측하는 문제로, 타깃값도 임의의 수치가 됩니다.\n2. k-최근접 이웃 회귀 k-최근접 이웃 회귀는 k-최근접 이웃 알고리즘을 사용해 회귀 문제를 풉니다. 가장 가까운 이웃 샘플을 찾아 이 샘플들의 타깃값을 평균하여 예측으로 삼습니다.\n3. 결정계수 (R²) 결정계수는 회귀 문제의 성능을 측정하는 대표적인 도구입니다. 1에 가까울수록 좋은 모델이며, 0에 가까울수록 성능이 나쁜 모델입니다.\n4. 과대적합과 과소적합 과대적합: 모델의 훈련 세트 성능이 테스트 세트 성능보다 훨씬 높을 때 발생합니다. 모델이 훈련 세트에 너무 집착하여 데이터의 거시적인 패턴을 감지하지 못하는 경우입니다. 과소적합: 훈련 세트와 테스트 세트 성능이 모두 낮거나 테스트 세트 성능이 더 높을 때 발생합니다. 더 복잡한 모델을 사용해 훈련 세트에 잘 맞는 모델을 만들어야 합니다. 5. 핵심 패키지와 함수 scikit-learn KNeighborsRegressor: k-최근접 이웃 회귀 모델을 만드는 사이킷런 클래스입니다. n_neighbors 매개변수로 이웃의 개수를 지정합니다. mean_absolute_error(): 회귀 모델의 평균 절댓값 오차를 계산합니다. 첫 번째 매개변수는 타깃, 두 번째 매개변수는 예측값을 전달합니다. mean_squared_error(): 평균 제곱 오차를 계산합니다. numpy reshape(): 배열의 크기를 바꾸는 메서드입니다. 바꾸고자 하는 배열의 크기를 매개변수로 전달합니다. 6. 예제 코드 다음은 k-최근접 이웃 회귀를 사용한 간단한 예제입니다.\nimport numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import mean_absolute_error # 데이터 준비 # 퍼치 물고기의 길이 데이터 perch_length = np.array( [8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0, 21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7, 23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5, 27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0, 39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5, 44.0] ) # 퍼치 물고기의 무게 데이터 perch_weight = np.array( [5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0, 115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0, 150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0, 218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0, 556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0, 850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0, 1000.0] ) # 데이터 시각화 # 길이와 무게 데이터를 산점도로 표시 plt.scatter(perch_length, perch_weight) plt.xlabel(\u0026#39;length\u0026#39;) # x축 라벨 plt.ylabel(\u0026#39;weight\u0026#39;) # y축 라벨 plt.show() # 데이터 분할 # train_test_split 함수를 사용하여 데이터를 훈련 세트와 테스트 세트로 분리 train_input, test_input, train_target, test_target = train_test_split( perch_length, perch_weight, random_state=42 ) # 데이터 변환 # 1차원 배열을 2차원 배열로 변환 train_input = train_input.reshape(-1, 1) test_input = test_input.reshape(-1, 1) # k-최근접 이웃 회귀 모델 생성 및 훈련 # 기본 이웃 수(k=5)를 사용하여 모델 생성 knr = KNeighborsRegressor() knr.fit(train_input, train_target) # 모델 평가 # 테스트 세트에 대한 예측 생성 test_prediction = knr.predict(test_input) # 평균 절댓값 오차 계산 mae = mean_absolute_error(test_target, test_prediction) print(f\u0026#39;Mean Absolute Error: {mae}\u0026#39;) # 결정계수 계산 # 훈련 세트와 테스트 세트에 대한 결정계수(R²) 계산 train_score = knr.score(train_input, train_target) test_score = knr.score(test_input, test_target) print(f\u0026#39;Train R^2: {train_score}\u0026#39;) print(f\u0026#39;Test R^2: {test_score}\u0026#39;) 코드 설명 데이터 준비 퍼치 물고기의 길이와 무게 데이터를 각각 perch_length와 perch_weight 배열로 준비합니다.\n데이터 시각화 길이와 무게 데이터를 산점도로 표시하여 데이터의 분포를 시각적으로 확인합니다.\n데이터 분할 train_test_split 함수를 사용하여 데이터를 훈련 세트와 테스트 세트로 분리합니다. random_state를 설정하여 실행할 때마다 동일하게 데이터를 분할할 수 있도록 합니다.\n데이터 변환 1차원 배열을 2차원 배열로 변환합니다. 이는 scikit-learn의 회귀 모델이 2차원 배열을 입력으로 받기 때문입니다. reshape(-1, 1)을 사용하여 배열을 변환합니다.\nk-최근접 이웃 회귀 모델 생성 및 훈련 기본 이웃 수(k=5)를 사용하여 KNeighborsRegressor 모델을 생성하고, fit 메서드를 사용하여 모델을 훈련합니다.\n모델 평가 테스트 세트에 대한 예측을 생성하고, mean_absolute_error 함수를 사용하여 평균 절댓값 오차(MAE)를 계산합니다. 또한, 훈련 세트와 테스트 세트에 대한 결정계수(R²)를 계산하여 모델의 성능을 평가합니다.\n요약 이 예제에서는 k-최근접 이웃 회귀를 사용하여 물고기의 길이와 무게 데이터를 기반으로 모델을 학습시키고 평가했습니다. 주요 개념과 사이킷런의 핵심 함수를 활용하여 회귀 문제를 해결하는 방법을 배웠습니다.\n","date":"2024-07-13T00:00:00+09:00","image":"/images/posts/2024-07-13-혼공머신3-1-1/cover.jpg","permalink":"/ko/posts/2024-07-13-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A03-1-1/","title":"[혼공머신]3-1"},{"content":"[혼공머신]3-1 -추가학습(k-최근접 이웃 모델의 원리와 활용) k-최근접 이웃 모델의 수학적 원리 k-최근접 이웃(K-Nearest Neighbors, KNN) 모델은 비모수적 방법으로, 데이터 포인트가 주어졌을 때 가장 가까운 ( k )개의 이웃을 기반으로 새로운 데이터를 예측하는 방법입니다. 이 알고리즘은 다음과 같은 단계를 따릅니다:\n거리 측정: 새로운 데이터 포인트와 기존 데이터 포인트 간의 거리를 계산합니다. 일반적으로 유클리드 거리(Euclidean distance)를 사용합니다. 유클리드 거리 ( d )는 다음과 같이 계산됩니다: $$ d(\\mathbf{x}i, \\mathbf{x}j) = \\sqrt{\\sum{l=1}^{n} (x{il} - x_{jl})^2} $$ 여기서 $\\mathbf{x}_i $와 $ \\mathbf{x}_j $는 각각 ( n )차원의 벡터를 나타냅니다.\n이웃 선택: 계산된 거리들을 기준으로 가장 가까운 ( k )개의 데이터 포인트(이웃)를 선택합니다.\n예측:\n분류(Classification): 이웃들의 클래스 레이블 중 다수결을 통해 새로운 데이터 포인트의 클래스를 결정합니다. 예를 들어, ( k )개의 이웃 중 가장 많은 클래스가 예측 클래스가 됩니다. 회귀(Regression): 이웃들의 타깃값의 평균을 구하여 새로운 데이터 포인트의 값을 예측합니다. 예를 들어, ( k )개의 이웃의 타깃값의 산술 평균이 예측값이 됩니다. 분류와 회귀를 모두 해결할 수 있는 이유 k-최근접 이웃 모델은 본질적으로 비모수적(non-parametric)이며, 데이터의 구조를 미리 가정하지 않습니다. 이는 이 모델이 다양한 문제 유형에 유연하게 적용될 수 있는 이유입니다.\n1. 분류 문제 다수결 원칙: 분류 문제에서는 새로운 데이터 포인트의 클래스가 가장 가까운 ( k )개의 이웃 중에서 가장 빈번한 클래스로 결정됩니다. 이는 다수결 원칙에 기반한 간단한 투표 방식입니다. 이 방식은 데이터 포인트들이 특정 클래스에 속할 확률을 반영합니다. 예시: 고양이와 개를 구분하는 문제에서 새로운 이미지가 들어왔을 때, 가장 가까운 ( k )개의 이미지가 고양이인지 개인지 투표하여 새로운 이미지의 클래스를 결정합니다. 2. 회귀 문제 평균 계산: 회귀 문제에서는 새로운 데이터 포인트의 값이 가장 가까운 ( k )개의 이웃의 값의 평균으로 결정됩니다. 이는 근처 데이터 포인트들의 값을 기반으로 새로운 값을 예측하는 것입니다. 예시: 집의 크기와 가격 데이터를 기반으로 새로운 집의 가격을 예측할 때, 가장 가까운 ( k )개의 집들의 가격의 평균을 구하여 새로운 집의 가격을 예측합니다. 수학적 예시 분류 예시 주어진 데이터 포인트 ((3, 3))에 대한 클래스를 예측한다고 가정합니다. 이웃의 개수 ( k = 3 )로 설정합니다. 기존 데이터 포인트와의 거리를 계산하여 가장 가까운 3개의 이웃을 찾습니다.\n포인트 클래스 거리 (유클리드) (1, 2) A 2.236 (4, 2) B 1.414 (2, 3) A 1.000 (5, 3) B 2.000 (3, 4) A 1.000 가장 가까운 3개의 이웃은 (4, 2), (2, 3), (3, 4)이며, 클래스는 B, A, A입니다. 따라서 예측 클래스는 다수결 원칙에 따라 A가 됩니다.\n회귀 예시 주어진 데이터 포인트 ((3, 3))에 대한 값을 예측한다고 가정합니다. 이웃의 개수 ( k = 3 )로 설정합니다. 기존 데이터 포인트와의 거리를 계산하여 가장 가까운 3개의 이웃을 찾습니다.\n포인트 값 거리 (유클리드) (1, 2) 10 2.236 (4, 2) 20 1.414 (2, 3) 15 1.000 (5, 3) 25 2.000 (3, 4) 30 1.000 가장 가까운 3개의 이웃은 (4, 2), (2, 3), (3, 4)이며, 값은 20, 15, 30입니다. 따라서 예측값은 ((20 + 15 + 30) / 3 = 21.67)이 됩니다.\n요약 k-최근접 이웃 모델은 비모수적 접근법을 통해 분류와 회귀 문제를 모두 해결할 수 있습니다. 분류에서는 다수결 원칙을 통해 클래스를 예측하고, 회귀에서는 평균 계산을 통해 값을 예측합니다. 이는 이 모델이 데이터의 분포나 가정에 의존하지 않고, 단순히 거리 기반의 이웃 관계를 통해 예측을 수행하기 때문에 가능합니다.\n","date":"2024-07-13T00:00:00+09:00","image":"/images/posts/2024-07-13-혼공머신3-1-2/cover.jpg","permalink":"/ko/posts/2024-07-13-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A03-1-2/","title":"[혼공머신]3-1 -추가학습(k-최근접 이웃 모델의 원리와 활용)"},{"content":"[혼공머신]3-1 -추가학습(분류와 회귀문제에 모두 사용할 수 있는 머신러닝 모델) 1. 결정 트리 (Decision Trees) 결정 트리는 데이터의 특성과 타깃 변수 간의 관계를 모델링하기 위해 트리 구조를 사용하는 알고리즘입니다.\n분류(Decision Tree Classifier): 각 노드에서 특정 특성의 값에 따라 데이터를 분할하여 최종적으로 클래스 레이블을 예측합니다. 회귀(Decision Tree Regressor): 각 노드에서 특정 특성의 값에 따라 데이터를 분할하여 최종적으로 타깃 값의 평균을 예측합니다. 예제 코드 from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor # 분류 clf = DecisionTreeClassifier() clf.fit(train_input, train_target) clf_pred = clf.predict(test_input) # 회귀 reg = DecisionTreeRegressor() reg.fit(train_input, train_target) reg_pred = reg.predict(test_input) 2. 랜덤 포레스트 (Random Forest) 랜덤 포레스트는 다수의 결정 트리를 사용하여 예측을 수행하는 앙상블 기법입니다.\n분류(Random Forest Classifier): 여러 결정 트리를 생성하고 각 트리의 예측 결과를 투표하여 최종 클래스를 결정합니다. 회귀(Random Forest Regressor): 여러 결정 트리를 생성하고 각 트리의 예측 값을 평균하여 최종 값을 결정합니다. 예제 코드 from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor # 분류 clf = RandomForestClassifier() clf.fit(train_input, train_target) clf_pred = clf.predict(test_input) # 회귀 reg = RandomForestRegressor() reg.fit(train_input, train_target) reg_pred = reg.predict(test_input) 3. 서포트 벡터 머신 (Support Vector Machines, SVM) SVM은 데이터 포인트를 고차원 공간으로 매핑하여 분류 또는 회귀를 수행하는 강력한 기법입니다.\n분류(Support Vector Classifier, SVC): 데이터 포인트를 고차원 공간으로 매핑하고, 클래스 간의 최대 마진을 분리하는 초평면을 찾습니다. 회귀(Support Vector Regressor, SVR): 데이터 포인트를 고차원 공간으로 매핑하고, 결정 경계 내의 포인트를 예측하는 회귀 모델을 생성합니다. 예제 코드 from sklearn.svm import SVC, SVR # 분류 clf = SVC() clf.fit(train_input, train_target) clf_pred = clf.predict(test_input) # 회귀 reg = SVR() reg.fit(train_input, train_target) reg_pred = reg.predict(test_input) 4. 인공 신경망 (Artificial Neural Networks, ANN) 신경망은 여러 계층을 통해 데이터의 특징을 학습하고 예측을 수행하는 모델입니다.\n분류(Neural Network Classifier): 다층 퍼셉트론(MLP) 구조를 사용하여 클래스 레이블을 예측합니다. 회귀(Neural Network Regressor): 다층 퍼셉트론(MLP) 구조를 사용하여 연속적인 값을 예측합니다. 예제 코드 from sklearn.neural_network import MLPClassifier, MLPRegressor # 분류 clf = MLPClassifier() clf.fit(train_input, train_target) clf_pred = clf.predict(test_input) # 회귀 reg = MLPRegressor() reg.fit(train_input, train_target) reg_pred = reg.predict(test_input) 요약 위에 언급한 모델들은 모두 분류와 회귀 두 가지 문제를 해결할 수 있는 강력한 도구입니다. 이들은 데이터의 특성과 목표에 따라 유연하게 사용할 수 있으며, scikit-learn 라이브러리를 통해 쉽게 구현할 수 있습니다. 모델 선택은 데이터의 특성과 문제의 요구 사항에 따라 달라질 수 있으므로, 여러 모델을 시도해보고 최적의 성능을 제공하는 모델을 선택하는 것이 좋습니다.\n","date":"2024-07-13T00:00:00+09:00","image":"/images/posts/2024-07-13-혼공머신3-1-3/cover.jpg","permalink":"/ko/posts/2024-07-13-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A03-1-3/","title":"[혼공머신]3-1 -추가학습(분류와 회귀문제에 모두 사용할 수 있는 머신러닝 모델)"},{"content":"[혼공머신]3-2 머신러닝에서의 선형 회귀와 다항 회귀 머신러닝에서 회귀는 종속 변수(타깃)와 하나 이상의 독립 변수(특성) 사이의 관계를 모델링하는 기본적인 기술입니다. 목표는 이 관계를 나타내는 최적의 선 또는 곡선을 찾는 것입니다. 이 교육 자료에서는 선형 회귀와 다항 회귀의 주요 개념과 이를 Python의 scikit-learn 라이브러리를 사용하여 구현하는 방법에 대해 다룹니다.\n선형 회귀 선형 회귀는 특성과 타깃 사이의 선형 관계를 찾는 것을 목표로 합니다. 이 관계는 다음과 같은 선형 방정식으로 표현됩니다: $$ y = \\beta_0 + \\beta_1 x_1 + \\beta_2 x_2 + \\cdots + \\beta_n $$ 여기서:\n$ y $는 타깃 변수입니다. $ x_1, x_2, \\ldots, x_n$는 특성 변수입니다. $ \\beta_0 $는 절편입니다. $ \\beta_1, \\beta_2, \\ldots, \\beta_n $는 특성의 계수(가중치)입니다. 주요 포인트: **계수(가중치)**는 각 특성이 타깃에 미치는 영향을 나타냅니다. 절편은 모든 특성이 0일 때의 타깃 값입니다. 다항 회귀 다항 회귀는 선형 회귀의 확장으로, 특성과 타깃 사이의 관계를 $n$차 다항식으로 모델링합니다. 이는 비선형 관계를 포착할 수 있습니다.\n$d$차 다항식 방정식은 다음과 같습니다: $$ y=\\beta_0 + \\beta_1 x + \\beta_2 x^2 + \\cdots + \\beta_d $$ 비록 모델이 특성에 대해 비선형이지만, 여전히 계수에 대해서는 선형이므로 선형 회귀 기법을 사용하여 해결할 수 있습니다.\n주요 포인트: 다항식의 차수는 모델의 유연성을 결정합니다. 비선형 관계는 다항 회귀를 사용하여 포착할 수 있습니다. 주요 패키지와 함수 Scikit-learn Scikit-learn은 데이터 마이닝 및 데이터 분석을 위한 파이썬의 인기 있는 머신러닝 라이브러리입니다. 회귀 모델을 포함한 사용하기 쉬운 도구를 제공합니다.\nLinearRegression Scikit-learn의 LinearRegression 클래스는 선형 회귀를 수행하는 데 사용됩니다.\n주요 매개변수:\nfit_intercept: 모델에 대한 절편을 계산할지 여부입니다. False로 설정하면 모델에서 절편을 사용하지 않습니다. 기본값은 True입니다. 주요 속성:\ncoef_: 특성에 대한 계수 배열입니다. intercept_: 절편 값입니다. 머신러닝 실습 교육자료 1. 데이터 준비 먼저, 사용할 데이터를 준비합니다. 여기서는 물고기의 길이와 무게를 포함한 데이터를 사용합니다.\nimport numpy as np perch_length = np.array([ 8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0, 21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7, 23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5, 27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0, 39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5, 44.0 ]) perch_weight = np.array([ 5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0, 115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0, 150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0, 218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0, 556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0, 850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0, 1000.0 ]) 2. 데이터 분할 훈련 데이터와 테스트 데이터를 나눕니다. 이를 통해 모델의 성능을 평가할 수 있습니다.\nfrom sklearn.model_selection import train_test_split # 훈련 세트와 테스트 세트로 나눕니다 train_input, test_input, train_target, test_target = train_test_split( perch_length, perch_weight, random_state=42) # 훈련 세트와 테스트 세트를 2차원 배열로 바꿉니다 train_input = train_input.reshape(-1, 1) test_input = test_input.reshape(-1, 1) 3. 선형 회귀 모델 사이킷런의 LinearRegression 클래스를 사용하여 선형 회귀 모델을 학습합니다.\nfrom sklearn.linear_model import LinearRegression lr = LinearRegression() # 선형 회귀 모델 훈련 lr.fit(train_input, train_target) # 50cm 농어에 대한 예측 print(lr.predict([[50]])) # 회귀 계수와 절편 출력 print(lr.coef_, lr.intercept_) 4. 모델 평가 훈련 데이터와 테스트 데이터에 대한 모델의 성능을 평가합니다.\nprint(lr.score(train_input, train_target)) print(lr.score(test_input, test_target)) 5. 다항 회귀 모델 다항 회귀 모델을 학습하여 비선형 데이터를 모델링합니다.\ntrain_poly = np.column_stack((train_input ** 2, train_input)) test_poly = np.column_stack((test_input ** 2, test_input)) lr = LinearRegression() lr.fit(train_poly, train_target) # 50cm 농어에 대한 예측 print(lr.predict([[50**2, 50]])) # 다항 회귀 계수와 절편 출력 print(lr.coef_, lr.intercept_) # 모델 평가 print(lr.score(train_poly, train_target)) print(lr.score(test_poly, test_target)) 6. 시각화 데이터와 모델을 시각화하여 결과를 확인합니다.\nimport matplotlib.pyplot as plt # 훈련 세트의 산점도를 그립니다 plt.scatter(train_input, train_target) # 15에서 50까지 1차 방정식 그래프를 그립니다 plt.plot([15, 50], [15*lr.coef_[1]+lr.intercept_, 50*lr.coef_[1]+lr.intercept_]) # 50cm 농어 데이터 plt.scatter(50, lr.predict([[50**2, 50]]), marker=\u0026#39;^\u0026#39;) plt.xlabel(\u0026#39;length\u0026#39;) plt.ylabel(\u0026#39;weight\u0026#39;) plt.show() # 구간별 직선을 그리기 위해 15에서 49까지 정수 배열을 만듭니다 point = np.arange(15, 50) # 훈련 세트의 산점도를 그립니다 plt.scatter(train_input, train_target) # 15에서 49까지 2차 방정식 그래프를 그립니다 plt.plot(point, lr.coef_[0]*point**2 + lr.coef_[1]*point + lr.intercept_) # 50cm 농어 데이터 plt.scatter(50, lr.predict([[50**2, 50]]), marker=\u0026#39;^\u0026#39;) plt.xlabel(\u0026#39;length\u0026#39;) plt.ylabel(\u0026#39;weight\u0026#39;) plt.show() 강의 요약 선형 회귀는 특성과 타깃 사이의 관계를 선형 방정식으로 나타냅니다. 다항 회귀는 다항식을 사용하여 비선형 관계를 모델링할 수 있습니다. LinearRegression 클래스는 선형 회귀 모델을 쉽게 구현할 수 있게 도와줍니다. 학습된 모델의 성능은 훈련 데이터와 테스트 데이터를 통해 평가할 수 있습니다. 모델의 시각화를 통해 데이터를 더 직관적으로 이해할 수 있습니다. ","date":"2024-07-13T00:00:00+09:00","image":"/images/posts/2024-07-13-혼공머신3-2/cover.jpg","permalink":"/ko/posts/2024-07-13-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A03-2/","title":"[혼공머신]3-2 머신러닝에서의 선형 회귀와 다항 회귀"},{"content":"[혼공머신]3-3 -추가학습(L1 규제와 L2 규제) L1 규제와 L2 규제는 머신러닝 모델, 특히 선형 회귀 모델에서 과대적합을 방지하고 모델의 일반화 성능을 향상시키기 위해 사용하는 두 가지 주요 규제 방법입니다.\nL1 규제 (L1 Regularization, Lasso Regression) 정의: L1 규제는 비용 함수에 계수의 절대값 합을 추가합니다. $$ \\text{L1 규제 비용 함수} = \\text{기본 비용 함수} + \\lambda \\sum_{i=1}^{n} |\\beta_i| $$ 여기서 $ \\lambda $는 규제 강도를 조절하는 하이퍼파라미터이고, $ \\beta_i $는 모델의 계수입니다.\n특징:\n계수 희소화: L1 규제는 일부 계수를 0으로 만들 수 있습니다. 즉, 특정 특성의 영향을 완전히 제거합니다. 특성 선택: L1 규제를 통해 자동으로 불필요한 특성을 선택하지 않게 됩니다. 이는 모델을 더 간결하고 해석 가능하게 만듭니다. 모델 복잡도 감소: 계수의 절대값 합을 최소화함으로써 모델의 복잡도를 줄이고, 과대적합을 방지합니다. 적용 예: Lasso 회귀는 L1 규제를 적용한 회귀 모델입니다.\nL2 규제 (L2 Regularization, Ridge Regression) 정의: L2 규제는 비용 함수에 계수의 제곱합을 추가합니다. $$ \\text{L2 규제 비용 함수} = \\text{기본 비용 함수} + \\lambda \\sum_{i=1}^{n} \\beta_i^2 $$ 여기서 $ \\lambda $는 규제 강도를 조절하는 하이퍼파라미터이고, $ \\beta_i $는 모델의 계수입니다.\n특징:\n계수 감소: L2 규제는 계수를 작게 만들지만, 완전히 0으로 만들지는 않습니다. 모든 특성의 영향을 유지합니다. 과대적합 방지: 계수의 제곱합을 최소화함으로써 모델의 복잡도를 줄이고, 과대적합을 방지합니다. 모델 안정화: 모든 특성을 유지하면서 과대적합을 방지하기 때문에 모델이 좀 더 안정적입니다. 적용 예: Ridge 회귀는 L2 규제를 적용한 회귀 모델입니다.\n시각적 비교 다음 그림은 L1 규제와 L2 규제의 차이를 시각적으로 설명합니다.\nL1 규제 (Lasso)\n절대값 합을 최소화하므로, 계수가 0이 되는 경우가 발생합니다. 결과적으로, 일부 특성은 모델에서 완전히 제거됩니다. L2 규제 (Ridge)\n제곱합을 최소화하므로, 계수가 작아지지만 0이 되지는 않습니다. 모든 특성이 모델에 포함되어 기여하게 됩니다. 시각적 비교 예시 이 그림은 L1 규제와 L2 규제가 계수에 어떻게 영향을 미치는지를 보여줍니다. L1 규제에서는 다이아몬드 모양의 등고선을 형성하여 계수가 0이 될 가능성이 높음을 나타내고, L2 규제에서는 원형 등고선을 형성하여 모든 계수가 작아지지만 0이 되지 않는 특성을 나타냅니다.\n","date":"2024-07-13T00:00:00+09:00","image":"/images/posts/2024-07-13-혼공머신3-3-2/cover.jpg","permalink":"/ko/posts/2024-07-13-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A03-3-2/","title":"[혼공머신]3-3 -추가학습(L1 규제와 L2 규제)"},{"content":"[혼공머신]3-3 다중회귀 다중 회귀는 여러 개의 특성을 사용하는 회귀 모델입니다. 단순 회귀가 하나의 특성만을 사용하는 반면, 다중 회귀는 여러 개의 특성을 동시에 고려하여 종속 변수에 대한 예측을 수행합니다. 이는 예측의 정확도를 높일 수 있으며, 다양한 실제 문제에서 유용하게 사용됩니다.\n데이터 준비 데이터를 준비하는 과정은 머신러닝 모델의 성능에 큰 영향을 미칩니다. 여기서는 pandas 라이브러리를 사용하여 CSV 파일을 로드하고, 필요한 전처리 과정을 수행합니다.\nimport pandas as pd # CSV 파일 로드 data = pd.read_csv(\u0026#39;data.csv\u0026#39;, sep=\u0026#39;,\u0026#39;, header=0, skiprows=0, nrows=100) print(data.head()) 위 코드에서는 pandas의 read_csv 함수를 사용하여 데이터를 로드합니다. sep, header, skiprows, nrows 등의 매개변수를 통해 CSV 파일의 형식에 맞게 데이터를 읽을 수 있습니다.\n사이킷런의 변환기 사이킷런의 PolynomialFeatures 변환기를 사용하여 특성 공학을 수행할 수 있습니다. 이를 통해 주어진 특성들을 조합하여 새로운 특성들을 생성할 수 있습니다.\nfrom sklearn.preprocessing import PolynomialFeatures # 특성 공학 poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=True) X_poly = poly.fit_transform(X) print(X_poly) 여기서 PolynomialFeatures를 사용하여 기존 특성의 2차 항을 포함한 새로운 특성을 생성합니다. degree, interaction_only, include_bias 매개변수를 통해 세부 설정이 가능합니다.\n다중회귀 모델 훈련하기 다중회귀 모델을 훈련하는 과정은 간단합니다. scikit-learn의 LinearRegression 클래스를 사용하여 모델을 훈련합니다.\nfrom sklearn.linear_model import LinearRegression # 모델 훈련 model = LinearRegression() model.fit(X_poly, y) # 예측 y_pred = model.predict(X_poly) 위 코드에서는 LinearRegression 객체를 생성하고 fit 메서드를 사용하여 모델을 훈련합니다. 훈련된 모델을 사용하여 예측을 수행합니다.\n규제 규제는 모델의 복잡도를 조절하여 과대적합을 방지하는 방법입니다. 대표적인 규제 기법으로 릿지 회귀와 라쏘 회귀가 있습니다.\n릿지 회귀 릿지 회귀는 선형 회귀 모델의 계수를 작게 만들어 과대적합을 완화하는 방법입니다. scikit-learn의 Ridge 클래스를 사용하여 릿지 회귀 모델을 훈련할 수 있습니다.\nfrom sklearn.linear_model import Ridge # 릿지 회귀 모델 훈련 ridge = Ridge(alpha=1.0, solver=\u0026#39;auto\u0026#39;, random_state=42) ridge.fit(X_poly, y) # 예측 y_pred_ridge = ridge.predict(X_poly) alpha 매개변수를 통해 규제 강도를 조절할 수 있으며, solver와 random_state를 통해 최적화 방법과 난수 시드값을 설정할 수 있습니다.\n라쏘 회귀 라쏘 회귀는 일부 계수를 0으로 만들어 특성 선택의 효과도 제공합니다. scikit-learn의 Lasso 클래스를 사용하여 라쏘 회귀 모델을 훈련할 수 있습니다.\nfrom sklearn.linear_model import Lasso # 라쏘 회귀 모델 훈련 lasso = Lasso(alpha=1.0, max_iter=1000, random_state=42) lasso.fit(X_poly, y) ## 예측 y_pred_lasso = lasso.predict(X_poly) alpha와 random_state 매개변수는 릿지와 동일하며, max_iter를 통해 알고리즘의 반복 횟수를 지정할 수 있습니다.\n","date":"2024-07-13T00:00:00+09:00","image":"/images/posts/2024-07-13-혼공머신3-3-1/cover.jpg","permalink":"/ko/posts/2024-07-13-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A03-3-1/","title":"[혼공머신]3-3 다중회귀"},{"content":"[혼공머신]1-3 머신러닝의 기본 개념 특성 특성은 데이터를 표현하는 하나의 성질입니다. 예를 들어, 생선 데이터를 길이와 무게 특성으로 나타낼 수 있습니다.\n훈련 머신러닝 알고리즘이 데이터에서 규칙을 찾는 과정을 훈련이라고 합니다. 사이킷런에서는 fit() 메서드를 사용합니다.\nk-최근접 이웃 알고리즘 k-최근접 이웃 알고리즘은 가장 간단한 머신러닝 알고리즘 중 하나로, 특정 규칙을 찾기보다는 전체 데이터를 메모리에 저장해 둡니다.\n모델 머신러닝 프로그램에서 알고리즘이 구현된 객체를 모델이라고 부릅니다. 종종 알고리즘 자체를 모델이라고 부르기도 합니다.\n정확도 정확도는 정확한 답을 몇 개 맞혔는지를 백분율로 나타낸 값입니다. 사이킷런에서는 0~1 사이의 값으로 출력됩니다.\n$$ \\text{정확도} = \\frac{\\text{정확히 맞힌 개수}}{\\text{전체 데이터 개수}} $$\n핵심 패키지와 함수 Matplotlib scatter(): 산점도를 그리는 함수입니다. x축 값과 y축 값을 리스트 또는 넘파이 배열로 전달합니다. c 매개변수로 색깔을 지정할 수 있습니다. Scikit-learn KNeighborsClassifier(): k-최근접 이웃 분류 모델을 만드는 클래스입니다.\nn_neighbors: 이웃의 개수를 지정합니다. 기본값은 5입니다. p: 거리를 재는 방법을 지정합니다. 1일 경우 맨해튼 거리, 2일 경우 유클리디안 거리를 사용합니다. 기본값은 2입니다. n_jobs: 사용할 CPU 코어를 지정합니다. -1로 설정하면 모든 CPU 코어를 사용합니다. fit(): 모델을 훈련할 때 사용하는 메서드입니다. 처음 두 매개변수로 훈련에 사용할 특성과 정답 데이터를 전달합니다.\npredict(): 훈련된 모델을 사용하여 예측할 때 사용하는 메서드입니다. 특성 데이터 하나만 매개변수로 받습니다.\nscore(): 훈련된 모델의 성능을 측정합니다. 처음 두 매개변수로 특성과 정답 데이터를 전달합니다. 이 메서드는 predict() 메서드로 예측을 수행한 후, 분류 모델일 경우 정답과 비교하여 올바르게 예측한 개수의 비율을 반환합니다.\n코드 예제 데이터 준비 import matplotlib.pyplot as plt import numpy as np from sklearn.neighbors import KNeighborsClassifier # 데이터 준비 fish_length = [25.4, 26.3, 26.5, 29.0, 29.0, 30.0, 31.2, 31.1, 31.1, 30.4, 30.4, 30.9, 32.0, 32.7, 33.5, 34.0, 34.0, 34.5, 35.0, 35.0] fish_weight = [242.0, 290.0, 340.0, 363.0, 430.0, 450.0, 500.0, 390.0, 490.0, 450.0, 500.0, 475.0, 500.0, 500.0, 500.0, 600.0, 600.0, 700.0, 700.0, 610.0] # numpy 배열로 변환 fish_data = np.column_stack((fish_length, fish_weight)) fish_target = np.ones(20) # 산점도 그리기 plt.scatter(fish_length, fish_weight) plt.xlabel(\u0026#39;length\u0026#39;) plt.ylabel(\u0026#39;weight\u0026#39;) plt.show() 모델 훈련 # KNeighborsClassifier 객체 생성 kn = KNeighborsClassifier(n_neighbors=5) # 모델 훈련 kn.fit(fish_data, fish_target) # 새로운 데이터 예측 new_data = [[30, 600]] print(kn.predict(new_data)) 모델 성능 평가 # 모델의 정확도 평가 score = kn.score(fish_data, fish_target) print(f\u0026#34;모델의 정확도: {score}\u0026#34;) 확인 문제 # 최근접 이웃 개수 변화에 따른 모델 성능 평가 for n in range(5, 50): kn.n_neighbors = n score = kn.score(fish_data, fish_target) if score \u0026lt; 1: print(n, score) break ","date":"2024-07-07T00:00:00+09:00","image":"/images/posts/2024-07-07-혼공머신1-3/cover.jpg","permalink":"/ko/posts/2024-07-07-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A01-3/","title":"[혼공머신]1-3"},{"content":"[혼공머신]2-1 1. 지도 학습과 비지도 학습 지도 학습 (Supervised Learning) 정의: 입력 데이터와 해당 타깃(라벨) 데이터를 사용하여 모델을 훈련한 후, 새로운 입력 데이터에 대한 예측을 수행합니다. 예시: K-최근접 이웃 알고리즘 (K-Nearest Neighbors) 입력 데이터와 그에 따른 레이블(타깃)을 사용하여 새로운 데이터의 레이블을 예측합니다. from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=3) knn.fit(train_input, train_target) prediction = knn.predict(test_input) score = knn.score(test_input, test_target) 비지도 학습 (Unsupervised Learning) 정의: 타깃 데이터가 없으며, 예측보다는 데이터의 구조나 패턴을 찾는 데 중점을 둡니다. 예시: 클러스터링 알고리즘 (K-Means Clustering) 데이터를 몇 개의 그룹으로 묶는 작업을 수행합니다. from sklearn.cluster import KMeans kmeans = KMeans(n_clusters=3) kmeans.fit(data) labels = kmeans.labels_ 2. 데이터 분할 훈련 세트 (Training Set) 정의: 모델을 훈련하는 데 사용하는 데이터입니다. 일반적으로 전체 데이터의 70-80%를 차지합니다. 중요성: 훈련 세트가 클수록 모델이 더 잘 학습할 수 있습니다. 코드 예시: from sklearn.model_selection import train_test_split train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2) 테스트 세트 (Test Set) 정의: 모델을 평가하는 데 사용하는 데이터입니다. 전체 데이터의 20-30%를 차지합니다. 중요성: 모델의 일반화 성능을 평가하는 데 사용됩니다. 코드 예시: from sklearn.model_selection import train_test_split train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2) 3. 핵심 패키지와 함수 NumPy seed()\n정의: 난수 생성을 위한 초깃값을 지정하여 동일한 난수를 재현할 수 있게 합니다. 사용 예: import numpy as np np.random.seed(42) arange()\n정의: 일정한 간격의 숫자 배열을 생성합니다. 사용 예: import numpy as np array = np.arange(0, 10, 1) shuffle()\n정의: 주어진 배열을 랜덤하게 섞습니다. 사용 예: import numpy as np array = np.arange(10) np.random.shuffle(array) 4. 실습 코드 예시 데이터 분할 및 모델 훈련 import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split # 데이터 생성 data = np.array([[1, 2], [2, 3], [3, 4], [5, 6], [8, 9], [9, 10]]) target = np.array([0, 0, 0, 1, 1, 1]) # 데이터 분할 train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2) # 모델 훈련 knn = KNeighborsClassifier(n_neighbors=3) knn.fit(train_input, train_target) # 예측 및 평가 prediction = knn.predict(test_input) score = knn.score(test_input, test_target) print(\u0026#34;Prediction:\u0026#34;, prediction) print(\u0026#34;Accuracy:\u0026#34;, score) ","date":"2024-07-07T00:00:00+09:00","image":"/images/posts/2024-07-07-혼공머신2-1-1/cover.jpg","permalink":"/ko/posts/2024-07-07-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A02-1-1/","title":"[혼공머신]2-1"},{"content":"[혼공머신]2-1 -추가학습(데이터 분할 방법) 데이터 분할의 종류와 기준 데이터 분할은 모델의 성능을 평가하고, 과적합을 방지하기 위해 필수적인 단계입니다. 데이터 분할의 주요 종류와 각 방법의 기준은 다음과 같습니다.\n1. 홀드아웃 방법 (Holdout Method) 정의: 데이터를 훈련 세트와 테스트 세트로 한 번만 나누는 방법입니다. 분할 기준: 훈련 세트: 전체 데이터의 70-80%를 차지합니다. 테스트 세트: 전체 데이터의 20-30%를 차지합니다. 장점: 간단하고 빠릅니다. 단점: 데이터의 특정 부분이 훈련 세트나 테스트 세트에 치우칠 수 있습니다. 코드 예시: from sklearn.model_selection import train_test_split train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42) 2. 교차 검증 (Cross-Validation) 정의: 데이터를 여러 번 분할하여 각각 다른 훈련 세트와 테스트 세트를 사용하는 방법입니다. 분할 기준: K-폴드 교차 검증: 데이터를 K개의 폴드로 나누고, 각 폴드를 한 번씩 테스트 세트로 사용합니다. 스트래티파이드 K-폴드 교차 검증: 분류 문제에서 각 클래스 비율이 동일하게 유지되도록 데이터를 나눕니다. 장점: 데이터의 모든 부분이 훈련 및 테스트에 사용되어 더 안정적인 평가를 제공합니다. 단점: 계산 비용이 많이 들 수 있습니다. 코드 예시: from sklearn.model_selection import cross_val_score, KFold, StratifiedKFold # K-폴드 교차 검증 kf = KFold(n_splits=5, shuffle=True, random_state=42) scores = cross_val_score(model, data, target, cv=kf) # 스트래티파이드 K-폴드 교차 검증 skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) stratified_scores = cross_val_score(model, data, target, cv=skf) 3. 시간 기반 분할 (Time-Based Split) 정의: 시간 순서가 중요한 시계열 데이터에서 사용되는 방법입니다. 과거 데이터를 훈련 세트로, 미래 데이터를 테스트 세트로 사용합니다. 분할 기준: 훈련 세트: 과거 데이터 테스트 세트: 미래 데이터 장점: 시계열 데이터의 특성을 반영하여 적합한 모델 평가가 가능합니다. 단점: 데이터가 충분하지 않으면 어려울 수 있습니다. 코드 예시: # 예시로 시계열 데이터를 80:20으로 분할 train_size = int(len(data) * 0.8) train, test = data[:train_size], data[train_size:] 4. 부트스트래핑 (Bootstrapping) 정의: 데이터에서 중복을 허용하여 여러 번 샘플링을 수행하는 방법입니다. 훈련 세트와 테스트 세트를 여러 번 재샘플링하여 모델을 평가합니다. 분할 기준: 훈련 세트: 원본 데이터에서 샘플링된 데이터 테스트 세트: 샘플링에서 제외된 데이터 장점: 데이터의 여러 샘플에 대해 모델의 성능을 평가할 수 있습니다. 단점: 원본 데이터가 충분히 크지 않으면 샘플링 편향이 발생할 수 있습니다. 코드 예시: from sklearn.utils import resample # 부트스트래핑 예시 n_iterations = 1000 n_size = int(len(data) * 0.8) for i in range(n_iterations): train = resample(data, n_samples=n_size) test = [x for x in data if x not in train] model.fit(train) score = model.score(test) 데이터 분할 시 고려 사항 데이터 균형: 분류 문제에서 각 클래스의 비율이 훈련 세트와 테스트 세트에서 동일하게 유지되도록 합니다. 무작위성: 데이터 분할 시 랜덤성을 도입하여 특정 패턴이 훈련 세트나 테스트 세트에 치우치지 않도록 합니다. 데이터 크기: 데이터가 충분히 클수록 더 작은 테스트 세트로도 모델의 일반화 성능을 평가할 수 있습니다. 시간 순서: 시계열 데이터의 경우, 시간 순서를 고려하여 데이터를 분할해야 합니다. 이러한 다양한 분할 방법과 기준을 이해하고 상황에 맞게 적절히 사용하는 것이 중요합니다. 이를 통해 모델의 성능을 더 정확하게 평가하고, 과적합을 방지할 수 있습니다.\n","date":"2024-07-07T00:00:00+09:00","image":"/images/posts/2024-07-07-혼공머신2-1-3/cover.jpg","permalink":"/ko/posts/2024-07-07-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A02-1-3/","title":"[혼공머신]2-1 -추가학습(데이터분할 방법)"},{"content":"[혼공머신]2-1 -추가학습(지도학습 및 비지도학습) 지도 학습 (Supervised Learning) 알고리즘 1 선형 회귀 (Linear Regression) 특징:\n입력 변수와 출력 변수 간의 선형 관계를 모델링 회귀 계수를 사용하여 예측 간단하고 빠르며 해석이 용이함 용도:\n연속형 변수 예측 (예: 집값 예측, 매출 예측) 예시코드:\nimport numpy as np from sklearnlinear_model import LinearRegression # 예제 데이터 X = nparray([[1], [2], [3], [4], [5]]) y = nparray([1, 4, 9, 16, 25]) # 모델 훈련 model = LinearRegression() modelfit(X, y) # 예측 predictions = modelpredict(nparray([[6], [7]])) print(predictions) 2 로지스틱 회귀 (Logistic Regression) 특징:\n이진 분류 문제에 사용 시그모이드 함수로 출력값을 0과 1 사이로 변환 결과를 확률로 해석할 수 있음 용도:\n분류 문제 (예: 스팸 메일 분류, 질병 진단) 예시코드:\nimport numpy as np from sklearnlinear_model import LogisticRegression # 예제 데이터 X = nparray([[0], [1], [2], [3], [4], [5]]) y = nparray([0, 0, 0, 1, 1, 1]) # 모델 훈련 model = LogisticRegression() modelfit(X, y) # 예측 predictions = modelpredict(nparray([[15], [35]])) print(predictions) 3 k-최근접 이웃 (k-Nearest Neighbors, k-NN) 특징:\n데이터 포인트 간의 거리를 기반으로 분류 및 회귀 수행 단순하지만 계산 비용이 높음 비선형 문제에 효과적 용도:\n분류 및 회귀 (예: 이미지 분류, 추천 시스템) 예시코드:\nimport numpy as np from sklearnneighbors import KNeighborsClassifier # 예제 데이터 X = nparray([[0], [1], [2], [3], [4], [5]]) y = nparray([0, 0, 0, 1, 1, 1]) # 모델 훈련 model = KNeighborsClassifier(n_neighbors=3) modelfit(X, y) # 예측 predictions = modelpredict(nparray([[15], [35]])) print(predictions) 4 서포트 벡터 머신 (Support Vector Machine, SVM) 특징:\n최대 마진 분리 초평면을 사용하여 분류 커널 트릭을 통해 비선형 문제 해결 고차원 데이터에 효과적 용도:\n분류 문제 (예: 텍스트 분류, 이미지 인식) 예시코드:\nimport numpy as np from sklearn.svm import SVC # 예제 데이터 X = np.array([[0], [1], [2], [3], [4], [5]]) y = np.array([0, 0, 0, 1, 1, 1]) # 모델 훈련 model = SVC(kernel=\u0026#39;linear\u0026#39;) model.fit(X, y) # 예측 predictions = model.predict(np.array([[1.5], [3.5]])) print(predictions) 5 결정 트리 (Decision Tree) 특징:\n트리 구조를 사용하여 결정 규칙을 모델링 해석이 용이하고 시각화가 가능 과적합 가능성이 높음 용도:\n분류 및 회귀 (예: 고객 세분화, 리스크 분석) 예시코드:\nimport numpy as np from sklearn.tree import DecisionTreeClassifier # 예제 데이터 X = np.array([[0], [1], [2], [3], [4], [5]]) y = np.array([0, 0, 0, 1, 1, 1]) # 모델 훈련 model = DecisionTreeClassifier() model.fit(X, y) # 예측 predictions = model.predict(np.array([[1.5], [3.5]])) print(predictions) 비지도 학습 (Unsupervised Learning) 알고리즘 1 k-평균 클러스터링 (k-Means Clustering) 특징:\n데이터 포인트를 k개의 클러스터로 분할 각 클러스터의 중심을 기준으로 군집화 간단하고 빠르지만 초기값에 민감 용도:\n데이터 군집화 (예: 고객 분류, 이미지 세그먼트) 예시코드:\nimport numpy as np from sklearn.cluster import KMeans # 예제 데이터 X = np.array([[1, 2], [1, 4], [1, 0], [10, 2], [10, 4], [10, 0]]) # 모델 훈련 model = KMeans(n_clusters=2, random_state=0) model.fit(X) # 클러스터 할당 labels = model.predict(X) print(labels) 2 주성분 분석 (Principal Component Analysis, PCA) 특징:\n고차원 데이터를 저차원으로 변환 데이터의 분산을 최대화하는 새로운 축을 찾음 차원 축소 및 데이터 시각화에 유용 용도:\n차원 축소 (예: 이미지 압축, 노이즈 제거) 예시코드:\nimport numpy as np from sklearn.decomposition import PCA # 예제 데이터 X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) # 모델 훈련 pca = PCA(n_components=2) X_reduced = pca.fit_transform(X) print(X_reduced) 3 아이소맵 (Isomap) 특징:\n비선형 차원 축소 기법 지오데식 거리(비선형 거리)를 사용하여 차원 축소 고차원 데이터의 비선형 구조를 보존 용도:\n차원 축소 (예: 얼굴 인식, 문서 시각화) 예시코드:\nimport numpy as np from sklearn.manifold import Isomap # 예제 데이터 X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) # 모델 훈련 isomap = Isomap(n_neighbors=2, n_components=2) X_reduced = isomap.fit_transform(X) print(X_reduced) 4 DBSCAN (Density-Based Spatial Clustering of Applications with Noise) 특징:\n밀도 기반 클러스터링 알고리즘 임의의 모양을 가진 클러스터를 탐지 노이즈 데이터 포인트를 잘 처리 용도:\n데이터 군집화 (예: 지리 공간 데이터 분석, 이상 감지) 예시코드:\nimport numpy as np from sklearn.cluster import DBSCAN # 예제 데이터 X = np.array([[1, 2], [2, 2], [2, 3], [8, 7], [8, 8], [25, 80]]) # 모델 훈련 dbscan = DBSCAN(eps=3, min_samples=2) labels = dbscan.fit_predict(X) print(labels) 비교 요약 지도 학습:\n입력과 타깃 데이터 사용 예측 모델을 학습하여 새로운 데이터에 대한 예측 수행 대표적인 알고리즘: 선형 회귀, 로지스틱 회귀, k-NN, SVM, 결정 트리 비지도 학습:\n타깃 데이터 없이 입력 데이터만 사용 데이터의 패턴이나 구조를 탐지 대표적인 알고리즘: k-평균 클러스터링, PCA, 아이소맵, DBSCAN ","date":"2024-07-07T00:00:00+09:00","image":"/images/posts/2024-07-07-혼공머신2-1-2/cover.jpg","permalink":"/ko/posts/2024-07-07-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A02-1-2/","title":"[혼공머신]2-1 -추가학습(지도학습 및 비지도학습)"},{"content":"[혼공머신]2-2 데이터 전처리 및 핵심 패키지와 함수 데이터 전처리 데이터 전처리는 머신러닝 모델에 훈련 데이터를 주입하기 전에 가공하는 단계를 말합니다. 데이터 전처리에는 결측값 처리, 데이터 정규화, 이상치 제거 등이 포함됩니다. 때로는 데이터 전처리에 많은 시간이 소모되기도 합니다.\n표준점수: 표준점수는 훈련 세트의 스케일을 바꾸는 대표적인 방법 중 하나입니다. 표준점수를 얻으려면 특성의 평균을 빼고 표준편차로 나눕니다. 이 때 반드시 훈련 세트의 평균과 표준편차로 테스트 세트를 변환해야 합니다. 핵심 개념 브로드캐스팅: 크기가 다른 넘파이 배열에서 자동으로 사칙 연산을 모든 행이나 열로 확장하여 수행하는 기능입니다. 핵심 패키지와 함수 scikit-learn train_test_split( )\n훈련 데이터를 훈련 세트와 테스트 세트로 나누는 함수입니다. 여러 개의 배열을 전달할 수 있으며, 테스트 세트로 나눌 비율은 test_size 매개변수에서 지정할 수 있습니다. 기본값은 0.25 (25%)입니다. shuffle 매개변수로 훈련 세트와 테스트 세트로 나누기 전에 무작위로 섞을지 여부를 결정할 수 있으며 기본값은 True입니다. stratify 매개변수에 클래스 레이블이 담긴 배열(일반적으로 타깃 데이터)을 전달하면 클래스 비율에 맞게 훈련 세트와 테스트 세트를 나눌 수 있습니다. kneighbors( )\nk-최근접 이웃 객체의 메서드로, 입력한 데이터에 가장 가까운 이웃을 찾아 거리와 이웃 샘플의 인덱스를 반환합니다. 이웃의 개수는 KNeighborsClassifier 클래스의 객체를 생성할 때 지정한 개수를 사용하며, n_neighbors 매개변수에서 다르게 지정할 수도 있습니다. return_distance 매개변수를 False로 지정하면 이웃 샘플의 인덱스만 반환하고 거리는 반환하지 않습니다. 기본값은 True입니다. 데이터 전처리 예시 코드 import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier # 데이터 생성 X, y = np.random.rand(100, 2), np.random.randint(0, 2, 100) # 훈련 세트와 테스트 세트로 분리 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, shuffle=True, stratify=y) # 데이터 스케일링 scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # k-최근접 이웃 모델 훈련 knn = KNeighborsClassifier(n_neighbors=3) knn.fit(X_train_scaled, y_train) # 새로운 데이터 포인트 예측 new_data = np.array([[0.5, 0.5]]) new_data_scaled = scaler.transform(new_data) distances, indexes = knn.kneighbors(new_data_scaled) # 시각화 plt.scatter(X_train_scaled[:, 0], X_train_scaled[:, 1], label=\u0026#39;Training Data\u0026#39;) plt.scatter(new_data_scaled[0, 0], new_data_scaled[0, 1], label=\u0026#39;New Data\u0026#39;, marker=\u0026#39;^\u0026#39;) plt.scatter(X_train_scaled[indexes, 0], X_train_scaled[indexes, 1], label=\u0026#39;Neighbors\u0026#39;, marker=\u0026#39;D\u0026#39;) plt.xlabel(\u0026#39;Feature 1\u0026#39;) plt.ylabel(\u0026#39;Feature 2\u0026#39;) plt.legend() plt.show() 요약 데이터 전처리는 머신러닝 모델의 성능을 높이는 중요한 단계입니다. 표준점수와 브로드캐스팅 같은 개념을 이해하면 데이터 전처리를 더 효율적으로 수행할 수 있습니다. scikit-learn 패키지의 train_test_split과 kneighbors 함수는 데이터 분할과 모델 학습에 유용합니다. 이 자료를 통해 데이터 전처리의 중요성과 scikit-learn을 활용한 데이터 전처리 방법을 이해할 수 있을 것입니다.\n","date":"2024-07-07T00:00:00+09:00","image":"/images/posts/2024-07-07-혼공머신2-2-1/cover.jpg","permalink":"/ko/posts/2024-07-07-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A02-2-1/","title":"[혼공머신]2-2"},{"content":"[혼공머신]2-2 -추가학습(데이터 전처리) 데이터 전처리 기술 표준점수 외에도 여러 가지 데이터 전처리 기술이 있습니다. 주요한 몇 가지를 소개하고 예시 코드를 함께 설명하겠습니다.\n1. Min-Max 스케일링 Min-Max 스케일링은 데이터를 최소값과 최대값을 사용하여 0과 1 사이의 값으로 변환하는 방법입니다.\nfrom sklearn.preprocessing import MinMaxScaler # 데이터 생성 X, y = np.random.rand(100, 2), np.random.randint(0, 2, 100) # Min-Max 스케일링 scaler = MinMaxScaler() X_scaled = scaler.fit_transform(X) print(\u0026#34;Original Data:\u0026#34;, X[:5]) print(\u0026#34;Scaled Data:\u0026#34;, X_scaled[:5]) 2. 로버스트 스케일링 로버스트 스케일링은 중간값과 사분위수를 사용하여 스케일링합니다. 이는 이상치에 덜 민감하게 작용합니다.\nfrom sklearn.preprocessing import RobustScaler # 로버스트 스케일링 scaler = RobustScaler() X_robust_scaled = scaler.fit_transform(X) print(\u0026#34;Original Data:\u0026#34;, X[:5]) print(\u0026#34;Robust Scaled Data:\u0026#34;, X_robust_scaled[:5]) 3. 정규화 (Normalization) 정규화는 각 샘플의 길이를 1로 만들어줍니다. 이는 주로 텍스트 데이터나 유클리드 거리를 사용하는 알고리즘에서 사용됩니다.\nfrom sklearn.preprocessing import Normalizer # 정규화 normalizer = Normalizer() X_normalized = normalizer.fit_transform(X) print(\u0026#34;Original Data:\u0026#34;, X[:5]) print(\u0026#34;Normalized Data:\u0026#34;, X_normalized[:5]) 4. 원-핫 인코딩 (One-Hot Encoding) 카테고리형 데이터를 이진 벡터로 변환하는 방법입니다.\nfrom sklearn.preprocessing import OneHotEncoder # 카테고리 데이터 생성 categories = np.array([\u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;, \u0026#39;cherry\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;apple\u0026#39;, \u0026#39;banana\u0026#39;]) categories = categories.reshape(-1, 1) # 원-핫 인코딩 encoder = OneHotEncoder() categories_encoded = encoder.fit_transform(categories).toarray() print(\u0026#34;Original Categories:\u0026#34;, categories.ravel()) print(\u0026#34;One-Hot Encoded Data:\u0026#34;, categories_encoded) 예시 코드: 여러 전처리 기술 적용 다양한 전처리 기술을 적용한 종합 예시입니다.\nimport numpy as np from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler, Normalizer, OneHotEncoder from sklearn.model_selection import train_test_split import matplotlib.pyplot as plt # 데이터 생성 X, y = np.random.rand(100, 2), np.random.randint(0, 2, 100) categories = np.random.choice([\u0026#39;cat\u0026#39;, \u0026#39;dog\u0026#39;, \u0026#39;mouse\u0026#39;], size=100).reshape(-1, 1) # 훈련 세트와 테스트 세트로 분리 X_train, X_test, y_train, y_test, categories_train, categories_test = train_test_split(X, y, categories, test_size=0.25, stratify=y) # Min-Max 스케일링 min_max_scaler = MinMaxScaler() X_train_min_max_scaled = min_max_scaler.fit_transform(X_train) X_test_min_max_scaled = min_max_scaler.transform(X_test) # 표준점수 스케일링 standard_scaler = StandardScaler() X_train_standard_scaled = standard_scaler.fit_transform(X_train) X_test_standard_scaled = standard_scaler.transform(X_test) # 로버스트 스케일링 robust_scaler = RobustScaler() X_train_robust_scaled = robust_scaler.fit_transform(X_train) X_test_robust_scaled = robust_scaler.transform(X_test) # 정규화 normalizer = Normalizer() X_train_normalized = normalizer.fit_transform(X_train) X_test_normalized = normalizer.transform(X_test) # 원-핫 인코딩 one_hot_encoder = OneHotEncoder() categories_train_encoded = one_hot_encoder.fit_transform(categories_train).toarray() categories_test_encoded = one_hot_encoder.transform(categories_test).toarray() # 시각화 plt.figure(figsize=(15, 10)) plt.subplot(2, 3, 1) plt.scatter(X_train[:, 0], X_train[:, 1], label=\u0026#39;Original Data\u0026#39;) plt.title(\u0026#39;Original Data\u0026#39;) plt.subplot(2, 3, 2) plt.scatter(X_train_min_max_scaled[:, 0], X_train_min_max_scaled[:, 1], label=\u0026#39;Min-Max Scaled\u0026#39;, color=\u0026#39;g\u0026#39;) plt.title(\u0026#39;Min-Max Scaled Data\u0026#39;) plt.subplot(2, 3, 3) plt.scatter(X_train_standard_scaled[:, 0], X_train_standard_scaled[:, 1], label=\u0026#39;Standard Scaled\u0026#39;, color=\u0026#39;r\u0026#39;) plt.title(\u0026#39;Standard Scaled Data\u0026#39;) plt.subplot(2, 3, 4) plt.scatter(X_train_robust_scaled[:, 0], X_train_robust_scaled[:, 1], label=\u0026#39;Robust Scaled\u0026#39;, color=\u0026#39;m\u0026#39;) plt.title(\u0026#39;Robust Scaled Data\u0026#39;) plt.subplot(2, 3, 5) plt.scatter(X_train_normalized[:, 0], X_train_normalized[:, 1], label=\u0026#39;Normalized\u0026#39;, color=\u0026#39;c\u0026#39;) plt.title(\u0026#39;Normalized Data\u0026#39;) plt.tight_layout() plt.show() print(\u0026#34;Original Categories:\u0026#34;, categories_train.ravel()[:5]) print(\u0026#34;One-Hot Encoded Categories:\\n\u0026#34;, categories_train_encoded[:5]) 요약 Min-Max 스케일링: 데이터를 0과 1 사이로 변환. 로버스트 스케일링: 중간값과 사분위수를 사용하여 스케일링. 정규화: 각 샘플의 길이를 1로 만들어줌. 원-핫 인코딩: 카테고리형 데이터를 이진 벡터로 변환. 이 예제 코드를 통해 다양한 전처리 기술을 학습하고 적용하는 방법을 익힐 수 있습니다. 이를 통해 머신러닝 모델의 성능을 더욱 향상시킬 수 있습니다.\n","date":"2024-07-07T00:00:00+09:00","image":"/images/posts/2024-07-07-혼공머신2-2-2/cover.jpg","permalink":"/ko/posts/2024-07-07-%ED%98%BC%EA%B3%B5%EB%A8%B8%EC%8B%A02-2-2/","title":"[혼공머신]2-2 -추가학습(데이터 전처리)"},{"content":"오늘 처음 블로그를 만들었어요 앞으로 열심히 해보겠습니다\n프로필 이미지 이미지 세부 목차1 이미지 입니다. ","date":"2024-06-11T00:00:00+09:00","image":"/images/posts/2024-06-11-first/cover.jpg","permalink":"/ko/posts/2024-06-11-first/","title":"첫 포스팅 입니다. 설레네요"}]