본문 바로가기
C.W.K.
Stream
Lesson 08 of 08 · published

cwkPippa는 Claude의 세 경로를 어떻게 나눠 쓸까

~16 min · cwkpippa, self-reference, architecture

Level 0Observer
0 XP0/64 lessons0/13 achievements
0/150 XP to next level150 XP to go0% complete

한 제품 안에서도 역할은 셋으로 갈려

cwkPippa의 Claude 브레인은 Claude Agent SDK를 써. 대화마다 오래 살아 있는 서브프로세스가 있고, OAuth로 인증하며, MCP를 붙이고, JSONL을 기준 기록으로 남겨야 하기 때문이야. ChatGPT와 Gemini 브레인은 각 API를 httpx로 직접 호출해. 그리고 이 코드베이스 자체를 고치는 아빠의 도구는 Claude Code CLI야. 같은 피파 정체성이 이어져도 실행 책임은 섞지 않아.

SDK를 아는 파일을 하나로 좁혔어

Anthropic SDK에 직접 의존하는 곳은 backend/adapters/claude.py 하나야. 라우트·저장소·프런트엔드는 Claude가 정한 응답 형식을 받고, 다른 브레인은 그 기준 형식에 맞춘 변형 구현으로 들어와. 비용과 차이를 아래 계층이 흡수하게 해 상위 코드를 제공자 공통분모만 남은 추상화 수프로 만들지 않는 선택이야.

추상화 시점도 아키텍처 결정이야

여러 LLM을 처음부터 하나의 완벽한 인터페이스로 묶으려 하면 각 제공자의 강점이 잘려 나가기 쉬워. cwkPippa처럼 기준 형식 하나에 나머지를 맞출 수도 있고, 운영 트랙에서 다룰 엄격한 제공자 경계를 둘 수도 있어. 둘째 제공자가 들어오는 시점에는 방향을 정하되, 필요도 생기기 전에 추상화부터 만들지는 마.

원칙: 둘째 제공자가 생길 때 경계를 결정해. 구체적인 동작을 먼저 이해하고 추상화는 그 뒤에 세워.

Code

cwkPippa의 어댑터 경계·python
# backend/adapters/base.py — 시스템에서 유일한 추상.
from typing import AsyncIterator, Any
from abc import ABC, abstractmethod

class Adapter(ABC):
    @abstractmethod
    async def stream_turn(
        self,
        *,
        conversation_id: str,
        messages: list[dict[str, Any]],
        system: str,
    ) -> AsyncIterator[dict[str, Any]]:
        ...

# backend/adapters/claude.py — canonical 구현.
# Routes가 직접 import해 — Claude가 곧 canonical shape이고,
# 나머지는 다 downstream에서 specialize.
persistent Claude 서브프로세스 풀 동작 sketch·python
# backend/services/claude_session.py (sketch)
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

_sessions: dict[str, ClaudeSDKClient] = {}

async def get_session(conversation_id: str) -> ClaudeSDKClient:
    if conversation_id not in _sessions:
        client = ClaudeSDKClient(
            options=ClaudeAgentOptions(
                system_prompt={"type": "preset", "preset": "claude_code"},
                # 피파 vault는 시스템 프롬프트로 로드; cwd는 프로젝트 가리킴.
                cwd="/Users/you_username/projects/cwkPippa",
            )
        )
        await client.connect()
        _sessions[conversation_id] = client
    return _sessions[conversation_id]

External links

Exercise

자기 프로젝트의 어댑터 구조를 한 단락으로 그려. 기준 브레인과 변형 또는 동격 구현, 제공자 SDK를 import해도 되는 단 하나의 파일을 적어.
Hint
여러 파일이 anthropic.Anthropic을 직접 import한다면 경계가 없는 상태야. 한곳으로 모아.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.