요즘IT
위시켓
AIDP - AX
콘텐츠프로덕트 밸리
요즘 작가들컬렉션물어봐
놀이터
콘텐츠
프로덕트 밸리
요즘 작가들
컬렉션
물어봐
놀이터
새로 나온
인기
개발
AI
IT서비스
기획
디자인
비즈니스
프로덕트
커리어
트렌드
스타트업
서비스 전체보기
위시켓요즘ITAIDP - AX
고객 문의
02-6925-4867
10:00-18:00주말·공휴일 제외
yozm_help@wishket.com
요즘IT
요즘IT 소개작가 지원
기타 문의
콘텐츠 제안하기광고 상품 보기
요즘IT 슬랙봇크롬 확장 프로그램
이용약관
개인정보 처리방침
청소년보호정책
㈜위시켓
대표이사 : 박우범
서울특별시 강남구 테헤란로 211 3층 ㈜위시켓
사업자등록번호 : 209-81-57303
통신판매업신고 : 제2018-서울강남-02337 호
직업정보제공사업 신고번호 : J1200020180019
제호 : 요즘IT
발행인 : 박우범
편집인 : 노희선
청소년보호책임자 : 박우범
인터넷신문등록번호 : 서울,아54129
등록일 : 2022년 01월 23일
발행일 : 2021년 01월 10일
© 2013 Wishket Corp.
로그인
요즘IT 소개
콘텐츠 제안하기
광고 상품 보기
AI

클로드 코드 소스 유출에서 배우는 에이전트 구조

정현우
14분
2시간 전
265
에디터가 직접 고른 실무 인사이트 매주 목요일에 만나요.
newsletter_profile0명 뉴스레터 구독 중

쏟아지는 AI 정보 속에서 자칫 겉핥기식으로만 따라가게 되는 요즘, 오히려 더 중요해지는 것은 정의와 본질인 것 같습니다. 특히 에이전트 경쟁은 이제 더 이상 ‘누가 더 똑똑한 모델을 붙였는가’만으로 설명되지 않습니다.

 

지난 3월 31일, 앤트로픽의 AI 코딩 도구 클로드 코드에서 소스맵 파일이 함께 배포되는 사고가 있었는데요. 이로 인해 외부에 드러난 클로드 코드의 내부 구조는, 오히려 에이전트의 완성도와 디테일이 어디에서 갈리는지를 꽤 선명하게 보여줍니다. 오픈AI도 에이전트를 planning, tool calling, specialist ownership, state, guardrails, observability 관점에서 설명하고 있고, 앤트로픽 역시 Claude Agent SDK를 “same tools, agent loop, and context management that power Claude Code”라고 정의했죠.

 

결국 에이전트는 모델을 단순히 소비하거나 활용하는 데서 끝나는 개념이 아니라, 모델이 실제로 일을 수행하도록 만드는 실행 구조에 가깝습니다. 이번 글에서는 클로드 코드 소스 유출 사례를 통해, 에이전트 구조가 어떻게 설계되어 있는지 살펴보겠습니다.
 

미리 요점만 콕 집어보면?

  • 이제 완성도는 오케스트레이션, 역할 분리, 도구 계층, 상태 관리, 안전장치, 관측 가능성에서 갈립니다.
  • 결국 중요한 건 “어떤 모델을 썼나”보다 “그 모델이 어떤 루프와 상태 위에서 움직이나”입니다.
  • 그래서 Agent의 차이는 “얼마나 똑똑한가”보다 “어떻게 나누고, 잇고, 통제하느냐”에서 납니다.
 

에이전트란 무엇인가

에이전트(agent)란 말은 중세 라틴어 agens/agent-에서 왔습니다. 더 거슬러 올라가면 라틴어 agere에서 나옵니다. 뜻은 대체로 “움직이게 하다, 이끌다, 행하다, 수행하다”에 가깝습니다.

 

<출처: Merriam-Webster>

 

원래의 핵심은 “행동하는 존재”라기보다, 무언가를 일으키거나 대신 수행하는 것에 더 가깝습니다. 그래서 약간 비밀요원 같은 뉘앙스가 있었죠. AI 시대에 들어오면서 “환경을 보고 행동하는 주체”라는 기술적 의미가 중심이 됐습니다.

 

Russell and Norvig의 AIMA(초판 95년), Artificial Intelligence: A Modern Approach는 agent를 “환경을 센서로 지각하고, 액추에이터로 그 환경에 작용하는 것”으로 정의합니다. 또한 에이전트 연구자인 Wooldridge와 Jennings는 1995년에 이미 “agent라는 개념이 AI와 주류 컴퓨터 과학에서 중요해졌다”고 쓰면서도, 동시에 보편적으로 합의된 하나의 정의는 없다고 말합니다.

 

에이전트가 처음부터 하나의 단일한 정의로 쓰였다기보단, agent, intelligent agent, software agent, softbot 같은 표현이 먼저 퍼진 뒤, 이를 나중에 ‘AI Agent’라는 이름 아래 묶어 부르게 된 흐름에 더 가깝습니다. 그리고 요즘은 이 개념을 정의하는 쪽이 자연스럽게 주류처럼 보이는 분위기도 있는 것 같습니다.

 

1) 빅테크의 에이전트 정의

그렇다면 빅테크에서는 에이전트를 어떻게 정의할까요? 우선 OpenAI는 Agent를 runtime loop, orchestration, handoffs, guardrails, results and state, observability까지 포함한 애플리케이션으로 설명합니다. Anthropic도 Claude Agent SDK를 Claude Code와 같은 tools, agent loop, context management를 프로그래밍할 수 있게 만든 형태로 소개합니다.

 

  • runtime loop는 “한 번 답하고 끝”이 아니라, 모델이 도구를 호출하고 그 결과를 다시 받아 다음 행동을 이어가는 반복 구조를 뜻합니다.
  • orchestration은 이 전체 흐름을 조율하는 layer입니다. 어떤 순서로 무엇을 하고, 어떤 agent를 부르고, 언제 멈출지를 정합니다.
  • handoffs는 작업을 다른 agent나 사람에게 넘기는 절차입니다.
  • guardrails는 위험한 행동을 막거나 제한하는 안전장치입니다.
  • state는 작업을 이어가기 위해 남겨두는 진행 상태와 맥락입니다.
  • results는 각 단계에서 나온 실제 산출물입니다.
  • observability는 이 시스템이 왜 그렇게 행동했는지 나중에 로그, 메트릭, 트레이스로 추적할 수 있게 해주는 장치입니다.
  • tools는 검색, 파일 읽기, 코드 수정, API 호출처럼 모델이 바깥 세계에 실제로 작동할 때 쓰는 기능입니다.
  • context management는 모델에게 어떤 정보를 보여주고, 어떤 정보를 숨기며, 무엇을 다음 단계로 넘길지를 다루는 방식입니다.

 

결국 중요한 건 “어떤 모델을 썼나”보다 “그 모델이 어떤 루프와 상태 위에서 움직이나”입니다.

 

<출처:작가,ChatGPT 생성>

 

2) 코드 리뷰 자동화를 만든다면

예를 들어, 모델 하나에 “PR 읽고 문제 찾고, 필요하면 수정까지 해”라고 던질 수는 있습니다. 데모는 그럴듯하게 나올 수 있습니다. 하지만 운영 단계로 들어가 몇 번 반복하면 원래 목표가 흐려집니다.

 

왜 그 파일을 위험하다고 봤는지, 왜 그 수정이 나왔는지, 누가 쓰기 권한을 가졌는지, 실패하면 어디서 멈춰야 하는지가 모두 섞이기 때문입니다. 그래서 보통은 아래와 같이 나눕니다.

 

manager -> diff 요약 -> review specialist -> 승인 후 수정 agent

 

여기서 중요한 건 “쪼갠다”는 사실 자체가 아니라, 각 단계의 [입력, 출력, 권한]이 좁고 분명하다는 점입니다.

 

  • manager가 orchestration 역할을 하고,
  • diff 요약 agent는 변경 의도와 리스크 파일 목록만 반환하며,
  • review specialist agent는 근거 라인과 치명도만 남기고,
  • 수정 agent는 승인 전까지 쓰기 권한을 갖지 못합니다.

 

Anthropic의 Claude Code subagent 문서도 각 subagent는 “자기 context window, 별도 system prompt, specific tool access, independent permissions를 가질 수 있다”고 설명합니다. 결국 잘 만든 Agent는 “여러 명이 협업하는 느낌”보다, 누가 무엇을 읽고 무엇을 쓸 수 있는지가 분명한 구조에 가깝습니다.

 

 

Claude Code 유출에서 배워야 할 것

1) Agent의 핵심은 엄청난 프롬프트보다 agent loop

공개된 분석들과 Anthropic 문서를 함께 보면, Claude Code의 본질은 결국 [입력 → 컨텍스트 결합 → 모델 호출 → tool_use 감지 → 툴 실행 → 결과 재주입 → 반복] 구조입니다. 그들만 가지고 있는 마법 같은 비밀이라기보다, 엉망인 코드라고 놀림받을지언정 예상보다 훨씬 명시적인 실행 루프에 가까웠습니다.

 

# Claude Code류 agent loop를 공식 문서 기준으로 재구성한 의사코드
# 핵심: 프롬프트 안에 다 우겨넣지 말고, 루프/권한/승인/중단 조건을 런타임으로 뺀다.

def run_agent(user_prompt, system_prompt, tools, state, policy):
    turn = 0
    max_turns = policy.max_turns
    max_failures = policy.max_failures
    failures = 0

    messages = []
    messages.append({"role": "system", "content": system_prompt})
    messages.extend(state.load_history())
    messages.append({"role": "user", "content": user_prompt})

    # 1) 프롬프트 제출 시점 전처리
    prompt_signals = inspect_user_prompt(user_prompt)  
    # 예: frustration, profanity, urgency, risky intent
    … # 생략

    
        runtime_context = build_runtime_context(
            messages=messages,
            memory=state.memory,
            task_state=state.task_state,
        )

        llm_response = model.generate(runtime_context, available_tools=tools)

            })
            state.save_history(messages + [llm_response.to_message()])

            requested_tools = llm_response.tool_calls

                decision = policy.check(call)


                    approved = human_review(call, state.snapshot())





    })

 

최대 반복 횟수, 실패 시 중단 조건, tool timeout, 재시도 횟수, human review 진입 조건은 런타임 레벨에서 따로 둬야 합니다. 그래야 시스템이 무너지지 않습니다. OpenAI도 workflow가 복잡해질수록 runtime loop, human review, guardrails를 별도 설계 대상으로 두라고 안내합니다.

 

유출된 실제 흐름은 아래와 같았습니다.

 

<출처: 작가>

 

  1. 모든 대화는 단 하나의 함수를 통과 - submitMessage()
  2. System Prompt 결합
  3. 내부적으로 최소 42개 도구 동적 배치
  4. context가 너무 커진다? -> 이전 메시지 자동 요약, 압축
  5. 프로젝트 -> 사용자 -> 글로벌 메모리 계층적 로딩

 

2) 잘 만든 Agent는 결국 “툴을 얼마나 잘 쓰느냐”에서 갈린다

구조 자체는 단순하지만, 그 단순한 루프 안에서 검색, 터미널, 파일 수정, 외부 시스템 연결을 얼마나 정확하게 실행하느냐가 완성도를 좌우합니다. Anthropic 공식 문서도 Claude Code를 파일 읽기, 명령 실행, MCP를 통한 외부 연동 중심의 agentic coding tool로 설명하고, OpenAI 역시 built-in tools, function calling, remote MCP servers를 통해 실제 기능을 확장하라고 안내합니다.

 

그래서 실전에서는 툴을 기능별로 나누는 것보다, 위험도별로 나누는 편이 더 유용하다고 합니다. read-only, external-read, write, exec, destructive처럼 등급을 나누고, 각 등급마다 승인 정책을 다르게 두는 방식입니다. “툴을 붙였다”보다 “어떤 툴을 어떤 조건에서 열었나”가 훨씬 중요합니다.

 

# 핵심만 남긴 툴 실행 정책 의사코드

def run_tool(tool_name, args, approved=False):
    risk = classify(tool_name)

    if risk == "read":
        return execute(tool_name, args)

    if risk in ["write", "exec"] and not approved:
        return "HUMAN_REVIEW_REQUIRED"

    if risk == "destructive":
        return "BLOCKED"



 

3) “만능 한 명”이 아니라 “역할이 나뉜 팀형 구조”

멀티에이전트 스폰과 메시지 전달 구조, Anthropic 공식 문서는 subagent를 독립된 context window, 별도 system prompt, tool access, permissions를 가진 전문 역할로 정의합니다.

 

이는 곧 좋은 Agent가 거대한 단일 프롬프트보다 [리드 에이전트 + 전문 에이전트 구조]로 가고 있다는 신호입니다. 다만 여기서도 핵심은 “팀처럼 나눠라”가 아니라, “누가 최종 응답의 책임을 지는지”, “누가 도구를 직접 호출할 수 있는지”, “누가 읽기만 하고 누가 쓰기까지 가능한지”를 분명히 정하라는 뜻입니다.

 

예를 들어, retrieval specialist는 근거 ID만 넘기고, answering specialist는 그 근거 없이는 답을 못 하게 하며, mutation agent는 manager 승인 없이는 실행 자체가 안 되게 설계해야 합니다. 역할 분리는 예쁜 구조도가 아니라 책임 분리입니다.

 

# 역할 분리만 보여주는 가장 단순한 의사코드

def manager(question):
    evidence_ids = retrieval_agent(question)   # 읽기만 가능
    answer = answering_agent(question, evidence_ids)  # 근거 없으면 답변 금지

    if needs_change(answer):
        return mutation_agent(answer, approved=False)  # 승인 없으면 실행 금지

    return answer

def retrieval_agent(question):
    # Read-only tools만 허용
    return ["doc_12", "doc_48"


 

4) 진짜 경쟁력은 모델보다 컨텍스트 운영 능력

<출처: bits-bytes-nn.github>

 

[프롬프트 엔지니어링 → 컨텍스트 엔지니어링 → 하네스 엔지니어링 → 에이전틱 엔지니어링]의 흐름으로 진화하는 트렌드, 사실 각 단계의 진화라기보다 이 모든 것이 중요해진 게 더 맞는 것 같습니다.

 

CLAUDE.md, auto memory, subagent context 분리 같은 공식 기능을 보면, Claude Code는 단순히 답변을 잘하는 도구가 아니라 “무엇을 기억하고”, “무엇을 넘기고”, “무엇을 버릴지”를 구조적으로 다루는 방향으로 가고 있습니다. 컨텍스트는 많이 넣는다고 좋아지지 않습니다. 오히려 지속 규칙, 작업 상태, 근거 자료, 이번 턴 임시 정보를 분리해야 품질이 안정됩니다.

 

CLAUDE.md 같은 지속 규칙은 짧게 핵심만 두고, 작업 중간 산출물은 “session state”로만 들고 가며, specialist에게 넘길 때는 전체 대화가 아니라 요약된 작업 카드만 넘기는 편이 낫습니다. 결국 컨텍스트 운영은 기억력이 아니라 압축력의 문제입니다.

 

나아가 이 부분은 안드레 카파시(Andrej Karpathy)가 제안한 LLM 위키 개념이나, graphify를 적용하는 것도 매우 좋은 시도로 보입니다.

 

5) Claude Code는 사용자의 “짜증 신호”를 그냥 흘려보내지 않는다

<출처: 작가, ChatGPT 생성>

 

Claude Code는 단순히 질문만 받는 것이 아니라, 사용자의 프롬프트 안에서 욕설·분노·좌절 같은 신호를 별도로 읽어내는 계층을 갖고 있었습니다. 내 짜증 신호는 도대체 몇 개일까 너무 궁금해지는 대목입니다.

 

// 실제 코드는 아니고 유출된 코드 기반으로 재구성
const NEGATIVE_REGEX = /wtf|wth|ffs|omfg|...|so frustrating|this sucks|damn it/i

function processUserPrompt(prompt: string) {
  const isNegative = NEGATIVE_REGEX.test(prompt.toLowerCase())
  analytics.track("tengu_input_prompt", {
    is_negative: isNegative,
  })

  return prompt
}

 

userPromptKeywords 계열 로직과 관련한 보도에 따르면, profanity·frustration 신호를 정규식 기반으로 감지하는 흐름이 알려졌고, Scientific American도 이 감지를 “regex 기반 frustration detector”로 설명했습니다.

 

중요한 건 이 포인트가 의외로 굉장히 실무적이라는 점입니다. 감정 신호 감지는 거대한 추론보다 regex 같은 값싼 규칙 처리로 이루어지며, 이유도 단순합니다. 빠르고, 비용이 낮으며, 운영 지표로 쓰기 좋기 때문입니다. 최첨단(?) Agent 안에도 여전히 고전적인(?) 규칙 엔진이 섞여 있습니다.

 

그래서 무엇을 하느냐! 욕설을 감지했다고 해서 무조건 답변 톤을 바꾸는 것이 핵심은 아닙니다. 오히려 이 신호를 위험 작업 일시 중지, UI 단순화, 재질문 유도, human handoff 후보, 운영 지표 기록에 활용하는 편이 훨씬 낫습니다.

 

Anthropic 공식 문서도 UserPromptSubmit 같은 훅 이벤트에서 사용자 입력을 받을 수 있고, data usage 문서에는 Statsig와 Sentry를 통한 운영 메트릭 및 에러 로깅이 명시돼 있습니다. 다시 말해 “짜증 신호 감지”는 실행 전에 개입할 수 있는 운영 레버입니다. 이 기능을 시스템 프롬프트에 묻어두기보다, 프롬프트 제출 시점의 별도 전처리와 로깅 계층으로 분리하는 편이 실제 운영에 훨씬 유리합니다.

 

 

완성도 높은 Agent의 공통 구조

잘 만든 Agent는 대개 하나의 거대한 뇌보다, 오케스트레이터, 전문 역할, 툴 계층, 상태 관리, 가드레일, 관측 가능성으로 나뉜 구조입니다. 결국 이것이 “하네스(Harness) 엔지니어링”이라는 이름으로 불리게 되었다고 보입니다.

 

OpenAI는 orchestration, specialists, tools, approvals, state를 에이전트 설계의 중심에 놓고 있고, Anthropic은 subagent별 tool access와 independent permissions를 분리합니다.

 

MCP 역시 외부 데이터와 도구를 연결하는 표준 인터페이스로 정의되며, 사용자의 명시적 동의와 도구 실행 안전성이 중요해집니다. 이제 경쟁력은 자율성 그 자체보다, 무엇을 누구에게 맡기고 어떤 도구를 어떤 경계 안에서 연결하느냐에 더 가깝습니다.

 

실제로는 오케스트레이터가 “다음 행동 결정”, specialist가 “좁은 문제 해결”, tool layer가 “행동 실행”, guardrail이 “차단과 승인”, state가 “작업 이어 붙이기”, trace가 “사후 설명”을 맡는 식으로 기능을 분리해야 합니다. 각각의 책임이 겹치면 디버깅이 헬입니다.

 

예를 들어, 사내 문서 검색 Agent를 만든다면,

  • manager agent는 질문을 분류하고,
  • retrieval specialist는 파일과 검색만 담당하고,
  • answering specialist는 답변 생성만 담당하게 나누는 식입니다.

 

그런데 여기서 한 단계만 더 가야 합니다.

 

  • retrieval specialist는 원문 전체가 아니라 근거 snippet + 문서 ID + 신뢰도만 반환하게 하고,
  • answering specialist는 그 근거가 없으면 답변 대신 추가 탐색을 요청하게 해야 합니다.

 

외부 SaaS나 사내 시스템 연결은 MCP나 function calling으로 붙이되, 결재·삭제·배포 같은 작업은 반드시 approval step 뒤에서만 실행되게 막아두는 편이 안전합니다. trace/log에는 최소한 run_id, selected specialist, tool name, approval 여부, failure reason 정도는 남겨야 나중에 사고를 재현할 수 있습니다.

 

OpenAI도 tools와 remote MCP 서버를 통한 확장, server-owned orchestration, state, approvals, observability를 SDK 핵심 사용 방식으로 설명합니다. 구조를 잘 나누는 것보다, 재현 가능한 구조를 만드는 것이 더 중요합니다.

 

 

마치며

그래서 Agent의 차이는 “얼마나 똑똑한가”보다 “어떻게 나누고, 잇고, 통제하느냐”에서 갈립니다. 누가 흐름을 잡을지, 어떤 specialist를 둘지, 어떤 도구를 어떤 권한으로 열지, 상태를 어디에 남길지, 어디서 사람 승인을 받을지를 먼저 정하는 일에 가깝습니다. OpenAI와 Anthropic의 공식 문서를 나란히 보면, 결국 오래 가는 Agent는 답변 품질 하나가 아니라 구조의 안정감에서 나온다는 점이 반복해서 강조됩니다. 더 현실적으로 말하면, 품질은 모델이 올려주지만 신뢰는 구조가 만듭니다. 신뢰의 판단 근거는 결국 “인간”인 거죠.

 

지금 당장 시작한다면, 거대한 만능 Agent 하나를 만들기보다 manager 1개 + specialist 2~3개 + tool layer + approval + trace/log 정도로 작게 나눠 설계해 보는 게 좋습니다. 각 specialist의 출력 스키마를 고정하고, tool 권한을 위험도별로 나누며, 루프 예산과 중단 조건을 두고, 사용자 짜증 신호 같은 운영 힌트도 전처리 계층에서 잡을 수 있게 Agent의 구조를 구성하는 방식으로 말이죠.

 

<출처:작가, ChatGPT 생성>

<출처>

  • https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf
  • https://code.claude.com/docs/en/overview
  • https://code.claude.com/docs/en/sub-agents
  • https://code.claude.com/docs/en/hooks
  • https://code.claude.com/docs/en/memory
  • https://code.claude.com/docs/en/data-usage
  • https://developers.openai.com/api/docs/guides/agents
  • https://developers.openai.com/api/docs/guides/tools

 

©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.

while
turn < max_turns:
turn +=
1
# 2) 모델 호출 전 컨텍스트 압축 / 결합
compact_if_needed=
True
,
# 3) 모델 호출
# 4) 답변 종료 조건
if
llm_response.
type
==
"final"
:
state.log_event(
"run_complete"
, {
"turn"
: turn,
"reason"
:
"final_answer"
,
return
llm_response.text
# 5) tool_use 요청 감지
if
llm_response.
type
==
"tool_use"
:
for
call
in
requested_tools:
# 5-1) 권한 정책 평가
# allow / ask / deny / escalate
if
decision ==
"deny"
:
…
# 생략
if
decision ==
"ask"
:
…
# 생략
if
not
approved:
…
# 생략
continue
# 5-2) timeout / retry / circuit breaker 포함한 실제 실행
try
:
…
# 생략
except
TimeoutError:
failures +=
1
…
# 생략
except
Exception
as
e:
failures +=
1
…
# 생략
# 6) 실패 누적 중단 조건
if
failures >= max_failures:
…
# 생략
return
"중단: 연속 실패가 임계치를 넘었습니다."
# 7) turn budget 소진
state.log_event(
"run_stopped"
, {
"reason"
:
"max_turns_exceeded"
,
"turn"
: turn,
return
"중단: 최대 반복 횟수를 초과했습니다."
return
execute(tool_name, args)
def
classify
(
tool_name
):
if
tool_name
in
[
"search_docs"
,
"read_file"
,
"grep_code"
]:
return
"read"
if
tool_name
in
[
"edit_file"
,
"create_draft"
]:
return
"write"
if
tool_name
in
[
"run_bash"
,
"run_python"
]:
return
"exec"
if
tool_name
in
[
"git_push"
,
"delete_file"
,
"deploy_prod"
]:
return
"destructive"
return
"blocked"
]
def
answering_agent
(
question, evidence_ids
):
if
not
evidence_ids:
return
"근거 부족: 추가 탐색 필요"
return
f"근거
{evidence_ids}
기준으로 답변 생성"
def
mutation_agent
(
payload, approved=
False
):
# Write / Edit / Exec는 승인 전 차단
if
not
approved:
return
"HUMAN_REVIEW_REQUIRED"
return
"변경 실행 완료"
  • https://platform.claude.com/docs/en/agent-sdk/overview
  • https://www.scientificamerican.com/article/anthropic-leak-reveals-claude-code-tracking-user-frustration-and-raises-new/
  • https://www.theregister.com/2026/03/31/anthropic_claude_code_source_code/
  • https://www.pcworld.com/article/3104748/claude-code-is-scanning-your-messages-for-curse-words.html