langgrpaph vs deepagent - 도입고민하기

sunn_ni·2026년 4월 10일

항상 프로덕트를 만들다보면.. 새로운게 나오고
새로운게 나오면 이걸 우리꺼에다 적용시켰을 때 뭐가 더 유리할지에 대해 고민하는 시간이 길어지는것같다.

예전에는 하나하나 검색하고 찾아보면서 판단했었는데..
지금은 일단 claude에게 물어보는중..

이미 예전에 했었던 고민이였지만 그당시에는 이렇게 점점 고도화가 되지 않았었기 때문에
deep-agent deploy가 나온 시점.. 함게 deep-agent도 다시 고민해보는 시간을 갖었다..

새로운게 계속 나오니까 나올때마다 이고민중이다 ㅠ 설계너무어려워..


create_react_agent vs Deep Agent — 실제 실행 메커니즘 차이

User: "강남역 지하철 도착 시간 알려줘"

LLM (1회 호출)
├─ System Prompt: "너는 도우미야"
├─ Tool descriptions: [a,b,c ..... ]  ← 20개 전부 프롬프트에
├─ User: "강남역 지하철 도착 시간"
└─ LLM 판단: tool_call → search(search="강남")
   └─ 결과 받아서 → LLM 최종 응답

이게 전부입니다. ReAct 루프는:

Think → Act(tool call) → Observe(결과) → Think → ... → 최종 답변

LLM 한 놈이 모든 걸 결정합니다. 도구 20개의 description을 전부 읽고, 어떤 도구를 쓸지 스스로 고릅니다.


Deep Agent 패턴 (Supervisor + Skill Agents)

User: "강남역 지하철 도착 시간 알려줘"

Supervisor (LLM 1회 호출) — 가벼운 라우터
├─ System Prompt: "아래 skill 중 적절한 것을 골라라"
├─ Skill 목록 (도구가 아니라 에이전트 이름):
│   ├─ "a" - search
│   ├─ "b" 
│   ├─ "c"
│   ├─ "d"— 
│   └─ "e" — 그냥 대화
├─ LLM 판단: → "search"
│
└─ Agent (별도 LLM 호출)
   ├─ System Prompt: "너는 한국 서비스 전문가야"
   ├─ Tool descriptions: [a] ← 1개만!
   ├─ Context: 원래 질문 + Supervisor가 전달한 맥락
   └─ LLM 판단: tool_call → search(search="강남")
      └─ 결과 받아서 → 최종 응답

대체 뭐가 다른 건데?

create_react_agentSupervisor + Skill
LLM 호출 수1회 (도구 사용 시 +1)2회 (분류 1회 + 실행 1회)
도구 선택LLM이 20개 중 직접 선택Supervisor가 분야 선택 → Skill Agent가 3개 중 선택
프롬프트 크기20개 도구 description 전부 (~2K 토큰)Supervisor: 5줄 목록 (~200 토큰), Skill: 3개 description (~300 토큰)
오선택 확률비슷한 도구 많으면 혼동단계적 축소 → 혼동 적음

본질적 차이는 "2단계 분류"입니다. 그 이상도 이하도 아닙니다.


"하네스(Harness)"란?

Deep Agents 블로그에서 말하는 harness는 거창한 게 아닙니다:

# 이게 하네스의 전부입니다
harness = {
    "supervisor": supervisor_agent,      # 라우팅 에이전트
    "skills": {
        "search": search_agent,          # Skill Agent 1
        "math": math_agent,              # Skill Agent 2
    },
    "memory": memory_store,              # 대화 기록/학습된 패턴
    "config": agents_md                  # AGENTS.md 설정 파일
}

# 실행
async def run(user_input):
    skill_name = await harness["supervisor"].invoke(user_input)  # 분류
    result = await harness["skills"][skill_name].invoke(user_input)  # 실행
    return result

하네스 = Supervisor + Skill Agents + Memory + Config를 묶어놓은 실행 컨테이너

LangChain 코드로 치면:

from langgraph.prebuilt import create_react_agent

# Skill Agent들 정의
search_agent = create_react_agent(
    model=llm,
    tools=[a, b, c]
)
math_agent = create_react_agent(
    model=llm,
    tools=[d, f]
)

# Supervisor = 그냥 또 다른 에이전트인데, "tools" 대신 "agents"를 호출
supervisor = create_react_agent(
    model=llm,
    tools=[
        Tool(name="search", func=search_agent.ainvoke, description="웹 검색"),
        Tool(name="math", func=math_agent.ainvoke, description="수학 계산"),
    ]
)

Supervisor의 "도구"가 다른 에이전트를 호출하는 함수인 겁니다.


솔직한 평가

현재 시스템에서 도구 20개 중 오선택이 자주 발생하나요?

  • 오선택 자주 발생 → Skill Router 도입 가치 있음
  • 잘 작동하고 있음 → LLM 호출 1회 추가 비용만 생기는 오버엔지니어링

도구가 50개, 100개로 늘어날 예정이라면 지금 구조화해두는 게 맞고, 현재 20개 선에서 잘 돌아가고 있다면 굳이 바꿀 필요 없습니다.


이렇게 보면.. 또 클로드 코드분석했을때의 tool사용하는 방법이랑 비슷한것같기도 한데..
아마 좀 더 기능을 붙이면 나중에는 deep-agent를 써야하지 않을 까 싶다..

제대로 알아보고 이해한게 맞는지 여러번 되묻고 찾아보기도했는데
혹시나 알게되는 다른내용이라던지.. 잘못이해한 내용있다면 언제든 피드백 환영입니다!

profile
방황중인 서버개발자

0개의 댓글