본문으로 건너뛰기
페이지 목차
이 페이지에서 검색

멀티 에이전트

이 페이지에 묻기

멀티 에이전트 · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.

생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.

MULTI · AGENT

멀티 에이전트

생성 수정

도구 실행·검색·기억·그래프 흐름·전문 에이전트의 협업을 구성하고 권한·평가·사람의 확인으로 통제합니다.

26개 문서 · 3일차 · 19 / 26

18차시 · 그래프 기반 워크플로우

지도 위치 : 3일차 · README 4장의 ⑤ 협업 층(시작) | 이전: 17차시 장기 기억 관리 | 다음: 19차시 조건 분기와 라우팅 키워드 : State, Node, Edge, 그래프 실행

이 차시를 다 읽으면

  1. 선형 체인과 그래프를 분기 · 되돌아감 · 병렬 의 유무로 가를 수 있다.
  2. State · Node · Edge를 유와 종차로 정의하고, State와 Node를 축 ③ 속성 ↔ 기능 으로 구별할 수 있다.
  3. LangGraph StateGraph 코드에서 칸(노드) · 선(엣지) · 공유 값(State) 을 짚어 읽을 수 있다.
  4. 노드가 State 전체가 아니라 바뀐 부분만 돌려주는 이유와 리듀서의 역할을 말할 수 있다.
  5. 그래프가 "누가 흐름을 정하는가" 축에서 어느 자리에 있는지 (큰 흐름은 코드, 칸 안 판단은 모델) 설명할 수 있다.
  6. 오피스봇 흐름을 그래프로 다시 그리고, 그래프 그림으로 설계와 구현이 같은지 검수할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1선형 ↔ 그래프 ⭐체인 (A → B → C)그래프 (분기 · 되돌아감 · 병렬)흐름이 한 줄인가⑤ 하나 ↔ 여럿 (파생)
2속성 ↔ 기능 ⭐State — 노드들이 함께 보는 값Node — 그 값을 읽고 바꾸는 동작그래프의 무엇이 데이터이고 무엇이 동작인가③ 속성 ↔ 기능
3누가 흐름을 정하는가코드 — 엣지를 미리 그어 둠모델 — 매번 다음 행동을 고름그래프 전체 모양은 누가 정하나5.2 중심 축
4무상태 ↔ 상태노드 함수 자체는 기억이 없음State가 실행 내내 값을 들고 다님단계 사이에 무엇이 이어지나⑦ 무상태 ↔ 상태

이 차시가 답하는 질문은 "한 줄로 이어지지 않는 처리 흐름을 어떻게 설계하고 실행하나?" 입니다. 앞에서 배운 LangChain(11차시)의 체인은 단계를 한 줄로 이었습니다. 오피스봇은 이미 한 줄이 아닙니다 — 의도에 따라 갈라지고(4 · 7차시), 검색에 실패하면 다시 시도하고(15차시), 승인을 기다려야 합니다(8차시). 이 차시는 그 흐름을 그래프라는 하나의 그림 으로 다시 그립니다. 3일차 나머지(분기 · 분해 · 멀티에이전트 · 사람의 승인)는 모두 이 그림 위에 얹힙니다.


1. 선형에서 그래프로

1.1 정의

체인 — [처리 흐름]인데, [ 단계가 한 줄로만 이어져 앞 단계의 출력이 다음 단계의 입력이 된다 ]는 점에서 그래프와 구별된다. 앞에서 배운 LangChain(11차시)은 모델 · 도구 · 프롬프트를 부품으로 묶어 주는 프레임워크였고, 체인은 그 부품을 한 줄로 잇는 방식이었습니다.

그래프 — [처리 흐름의 표현]인데, [ 단계(노드)를 선(엣지)으로 잇되, 갈라지고 · 되돌아가고 · 동시에 갈 수 있다 ]는 점에서 한 줄로만 이어지는 체인과 구별된다.

체인 (선형)그래프
모양A → B → CA → (B 또는 C) → D → A로 되돌아가기 가능
분기체인 바깥의 if 문으로 처리조건부 엣지 로 그림 안에 표시 (19차시)
반복표현하기 어려움되돌아가는 엣지로 표현
단계 사이에 넘기는 것앞 단계의 출력 하나State 전체 (모든 노드가 함께 봄)
맞는 경우단계가 고정된 단순 처리갈라지고 · 다시 시도하고 · 멈췄다 재개하는 처리

1.2 반례 — 그래프처럼 보이지만 아닌 것

대상왜 이 차시의 그래프가 아닌가
회의에서 그린 순서도그림일 뿐 실행되지 않음 . 이 차시의 그래프는 그림이 곧 실행 코드
지식 그래프사실 사이의 관계를 저장하는 데이터 구조 . 처리 흐름이 아님
if 문 몇 개가 든 함수갈라지긴 하지만 흐름이 코드 안에 숨어 있어 그림으로 볼 수 없음. 단순하면 이걸로 충분함

⚠️ 마지막 반례가 중요합니다. 단계가 셋이고 갈림길이 하나라면 if 문이 더 단순합니다. 그래프는 갈림길 · 되돌아감 · 멈춤이 늘어 흐름을 그림으로 보고 검수해야 할 때 값을 합니다. 문장 1(가장 단순한 것부터)이 여기에도 적용됩니다.

1.3 LangGraph

LangGraph — [에이전트 프레임워크]인데, [ 처리 흐름을 State를 가진 그래프로 정의하고 실행한다 ]는 점에서 부품 연결 중심의 LangChain과 구별된다. 같은 회사가 만들어 LangChain의 모델 · 도구를 노드 안에서 그대로 쓸 수 있습니다.

⚠️ LangGraph는 버전에 따라 함수 이름과 위치가 바뀝니다. 이 노트의 코드는 구조를 보이기 위한 예시이고, 실제로 쓸 때는 설치된 버전과 공식 문서를 확인 하세요.

💡 비유 (기억 보조용) — 체인은 컨베이어 벨트 , 그래프는 지하철 노선도 입니다. 노선도에는 갈아타는 역(분기), 순환선(되돌아감), 두 갈래로 동시에 가는 길(병렬)이 있습니다.


2. ⭐ State · Node · Edge — 축 ③

2.1 세 부품의 정의

State — [그래프의 구성 요소]인데, [ 실행 내내 모든 노드가 함께 읽고 쓰는 값의 묶음 ]이라는 점에서 동작인 노드와 구별된다.

Node — [그래프의 구성 요소]인데, [ State를 받아 일을 하고 바꿀 값을 돌려주는 함수 ]라는 점에서 값의 묶음인 State와 구별된다.

Edge — [그래프의 구성 요소]인데, [ 한 노드가 끝난 뒤 다음에 실행할 노드를 정하는 연결 ]이라는 점에서 일을 하는 노드와 구별된다.

부품축 ③에서오피스봇 예코드에서
State속성 (값)질문, 의도, 검색 결과, 답, 반복 횟수class State(TypedDict)
Node기능 (동작)의도 분류, 규정 검색, 답변 작성def classify(state) + add_node
Edge기능의 순서분류 → 검색 → 답변add_edge, add_conditional_edges

앞에서 배운 도구 호출(5 · 6차시)에서도 같은 축이 나왔습니다. 도구 정의와 결과 는 값(속성)이고 도구 실행 은 동작(기능)이었습니다. 그래프에서도 똑같이 값과 동작을 분리 합니다. 분리하면 State만 보고 "지금 어디까지 왔나"를 알 수 있습니다.

2.2 반례 — 헷갈리는 짝

헷갈리는 것바로잡기
"State = 대화 이력"❌ 대화 이력은 State의 한 필드 일 수 있을 뿐. State는 이 그래프가 필요로 하는 모든 값
"State = 장기 기억"❌ State는 한 번의 실행 안 의 값(메모리 쪽, 17차시 축 ①). 저장하려면 체크포인터(3.3)
"노드 = 에이전트"❌ 노드는 함수 하나. 그 안에서 LLM을 한 번 부를 수도, 에이전트 루프를 돌릴 수도, LLM 없이 규칙만 쓸 수도 있음

2.3 노드는 바뀐 부분만 돌려준다 — 리듀서

import operator
from typing import Annotated, TypedDict

class State(TypedDict):
    question: str
    intent: str
    answer: str
    sources: Annotated[list[str], operator.add]   # 리듀서: 덮어쓰지 말고 이어 붙여라

def classify(state: State) -> dict:
    return {"intent": "규정질문"}                    # 바뀐 필드만

def search_policy(state: State) -> dict:
    return {"sources": ["취업규칙 제23조"]}          # 기존 sources 뒤에 붙음

🔍 읽는 포인트

  • return {"intent": ...} — 노드는 State 전체를 다시 쓰지 않고 바꿀 필드만 돌려줍니다. 나머지 필드는 그대로 남습니다. 그래서 노드끼리 서로의 값을 실수로 지우지 않습니다.
  • Annotated[list[str], operator.add] — 리듀서 (합치는 규칙)입니다. 리듀서가 없으면 새 값이 옛 값을 덮어쓰고 , 있으면 정한 규칙대로 합칩니다. 여러 노드가 출처를 하나씩 보태는 경우에 씁니다.
  • ⚠️ 리듀서 없는 리스트 필드에 두 노드가 동시에 값을 쓰면 하나가 사라지거나 오류가 납니다. 병렬 실행(20차시)에서 자주 만나는 실수입니다.

3. StateGraph — 정의 · 컴파일 · 실행

3.1 그래프 정의

from langgraph.graph import StateGraph, START, END

g = StateGraph(State)                     # 이 State를 들고 다니는 그래프
g.add_node("classify", classify)          # 칸: 이름 + 함수
g.add_node("search_policy", search_policy)
g.add_node("answer", write_answer)

g.add_edge(START, "classify")             # 선: 시작 → 분류
g.add_edge("classify", "search_policy")
g.add_edge("search_policy", "answer")
g.add_edge("answer", END)                 # 선: 답변 → 끝

🔍 읽는 포인트

  • add_node("이름", 함수) — 무엇을 하는 칸 인가. 이름은 그림과 실행 추적에 그대로 찍힙니다.
  • add_edge(A, B) — A가 끝나면 B로 . START · END는 입구와 출구입니다.
  • 이 예는 아직 한 줄입니다. 갈림길(add_conditional_edges)은 19차시에서 붙입니다.

3.2 컴파일과 실행

그래프 실행 — [프로그램 실행]인데, [ State를 입구에 넣고 엣지를 따라 노드를 차례로 돌리며 State를 갱신하다가 END에 닿으면 마지막 State를 돌려준다 ]는 점에서 함수를 한 번 부르는 일반 호출과 구별된다.

app = g.compile()                                   # 정의 → 실행 가능한 객체
result = app.invoke({"question": "육아휴직 며칠까지 돼요?", "sources": []})
print(result["answer"], result["sources"])

for update in app.stream({"question": "..."}, stream_mode="updates"):
    print(update)                                   # 노드 하나 끝날 때마다 바뀐 값

🔍 읽는 포인트

  • compile() — 정의를 검사하고 실행 가능한 형태로 만듭니다. 없는 노드를 가리키는 엣지나 입구(START)가 없는 그래프처럼 구조가 틀리면 여기서 오류 가 납니다. 실행 전에 걸러지는 것이 그래프의 장점입니다.
  • invoke(...) — 끝까지 돌리고 마지막 State 를 돌려줍니다.
  • stream(..., stream_mode="updates") — 노드마다 무엇이 바뀌었는지 차례로 보여 줍니다. 디버깅과 화면의 "검색 중..." 표시(24차시)에 씁니다. stream_mode 값은 버전에 따라 다를 수 있으니 문서를 확인하세요.

3.3 체크포인터 — 미리 보기

compile()에 체크포인터 를 넘기면 노드가 끝날 때마다 State를 저장소에 남깁니다. 실행이 중간에 멈춰도 저장된 State에서 다시 시작할 수 있습니다. 축 ⑦에서 State를 메모리(이번 실행)에서 디스크(저장소) 쪽으로 옮기는 장치입니다.

앞으로 다시 만납니다 — 23차시에서 체크포인터가 핵심이 됩니다. 장비 신청을 사람이 승인할 때까지 그래프를 멈추고 , 몇 시간 뒤 승인이 오면 그 자리에서 재개 하려면 멈춘 State가 저장되어 있어야 합니다.


4. 누가 흐름을 정하는가 — 그래프의 자리

README 5.2의 중심 축 위에 지금까지 만든 것을 놓으면 이렇습니다.

1일차 워크플로우9차시 에이전트 루프18차시 그래프
다음 단계를 정하는 것코드 (if 문)모델 (매 반복 판단)큰 흐름은 엣지(코드), 칸 안의 판단은 모델
예측 가능성높음낮음큰 흐름은 높음
실패 위치 찾기쉬움추적을 읽어야 함어느 노드에서 인지 바로 보임
비용낮음반복 수만큼노드 수만큼 (예측 가능)

⭐ 그래프는 축의 왼쪽과 오른쪽을 섞는 방법 입니다. 앞에서 배운 에이전트 루프(9차시)에서는 모델이 "도구를 부를지, 끝낼지"를 매번 정했습니다. 그래프에서는 "분류 → 검색 → 답변"이라는 큰 순서를 코드가 그림으로 고정 하고, 각 칸 안에서 "이 질문의 의도는?", "이 근거로 어떻게 답할까?" 같은 판단만 모델에게 맡깁니다.

칸 안에 넣을 수 있는 것축의 자리
규칙 함수 (LLM 없음)왼쪽 끝
LLM 한 번 호출 (분류 · 요약)왼쪽에 가까움
에이전트 루프 (도구를 고르며 반복)오른쪽 — 칸 하나가 통째로 에이전트

앞으로 다시 만납니다 — 22차시의 관리 에이전트(Supervisor)는 그래프 안에서 모델이 다음 노드를 고르게 합니다. 같은 그래프라도 엣지를 누가 고르느냐에 따라 축의 오른쪽으로 옮겨 갑니다.


5. 오피스봇 흐름을 그래프로 다시 그리기

5.1 그림

1 · 2일차에 만든 부품을 노드로 놓으면 이렇습니다. 실선은 이 차시의 고정 엣지, 점선은 19차시 이후에 붙일 엣지입니다.

            START
              │
        [load_profile]          ← 17차시 장기 기억 주입
              │
          [classify]            ← 4차시 의도 분류기
         ┊    ┊     ┊
   [hr_tools] [search_policy] [it_tools]   ← 6차시 도구 · 13~15차시 검색
         ┊    │     ┊
          [answer]              ← 14차시 근거 기반 답변
              │
        [save_memory]           ← 17차시 기억 쓰기
              │
             END
노드읽는 State쓰는 State
load_profileuser_idprofile
classifyquestion, profileintent, confidence
search_policyquestionsources (리듀서로 누적)
answerquestion, sources, profileanswer
save_memory전체 대화(DB에 저장, State는 그대로)

💡 이 표를 먼저 쓰고 코드를 맡기세요. "누가 무엇을 읽고 쓰는가" 가 정해지면 노드끼리의 충돌(같은 필드를 두 노드가 덮어쓰기)을 미리 볼 수 있습니다.

5.2 그래프 그림으로 검수하기

print(app.get_graph().draw_mermaid())     # Mermaid 형식의 그림 문자열

🔍 읽는 포인트

  • 컴파일된 그래프에서 실제 구조 를 그림으로 뽑습니다. 출력은 Mermaid라는 그림 문법 글이고, Mermaid를 지원하는 편집기나 웹 미리보기에 붙이면 그림이 됩니다. 함수 이름은 버전에 따라 다를 수 있으니 문서를 확인하세요.
  • ⭐ 내가 그린 설계 그림(5.1)과 나란히 놓고 비교 합니다. 코드를 읽지 않고도 "빠진 노드", "엉뚱한 곳으로 가는 선", "END에 닿지 않는 길"을 찾을 수 있습니다. AI가 만든 그래프를 검수하는 가장 싼 방법입니다.

6. 실습 — 맡기고 검수하기

지시

오피스봇의 규정 질문 흐름을 LangGraph StateGraph로 다시 구성해줘.
참고 공식 문서: LangGraph 공식 문서의 StateGraph, State 리듀서, compile/invoke/stream, 그래프 시각화 항목.
  설치된 langgraph 버전을 먼저 출력하고, 그 버전 문서 기준으로 작성할 것.
구조: START → load_profile → classify → search_policy → answer → save_memory → END (분기는 아직 만들지 말 것)
제약:
- State 필드: user_id, question, profile, intent, confidence, sources(리듀서로 누적), answer
- 각 노드는 바뀐 필드만 dict로 반환. 노드마다 [읽는 필드 | 쓰는 필드] 표를 함께 보고할 것.
- 기존 분류기 · 검색 · 답변 함수는 고치지 말고 노드로 감싸기만 할 것.
테스트: 평가셋의 규정 질문 10개를 invoke로 돌리고, 그중 1개는 stream(stream_mode="updates") 출력 원문을 붙일 것.
보고 형식: [질문 | intent | sources | 답 요약 | 기존 구현과 답이 같은가] 표 + draw_mermaid() 출력 원문.
추측하지 말고 실행 출력 원문을 붙여.

받을 증거

  • langgraph 버전 출력 과 참고한 문서 주소
  • 노드별 읽는 필드 / 쓰는 필드 표
  • draw_mermaid() 출력 원문, stream 출력 원문, 10개 질문 결과표

내가 직접 확인할 것

볼 것이걸로 아는 것
Mermaid 그림과 내 설계 그림(5.1)이 같은 모양 인가설계대로 구현됐는가 (5.2)
stream 출력에서 노드가 설계한 순서대로 찍히는가엣지가 맞게 이어졌는가 (3.2)
sources가 덮어써지지 않고 누적 되는가리듀서가 걸렸는가 (2.3)
기존 구현과 답이 같은 비율그래프로 옮기며 동작이 바뀌지 않았는가 (회귀 확인, 11차시)
노드 표에서 두 노드가 같은 필드를 쓰는가충돌 위험

부록 A. 스스로 확인하기

#질문답이 있는 곳
1체인과 그래프를 가르는 세 가지(분기 · 되돌아감 · 병렬)는?1.1
2if 문으로 충분한데 그래프를 쓰면 안 되는 경우는?1.2
3State · Node · Edge를 유와 종차로 정의하면?2.1
4State가 장기 기억이 아닌 이유는?2.2
5노드가 바뀐 부분만 돌려주는 이유와 리듀서의 역할은?2.3
6compile()에서 오류가 나는 것이 왜 장점인가?3.2
7그래프가 "누가 흐름을 정하는가" 축에서 어디에 있나?4
8코드를 읽지 않고 그래프 구현을 검수하는 방법은?5.2

부록 B. 자주 하는 실수

실수바로잡기
"그래프가 체인보다 발전된 것"❌ 단순한 흐름은 체인이나 if 문이 낫습니다. 갈림길 · 되돌아감이 늘 때 씁니다
노드가 State 전체를 새로 만들어 돌려줌⚠️ 다른 노드가 쓴 값을 지울 수 있습니다. 바뀐 필드만 돌려주세요
리스트 필드에 리듀서 없이 여러 노드가 씀❌ 덮어써집니다. Annotated[..., operator.add] 같은 리듀서를 거세요
"노드 하나 = 에이전트 하나"❌ 노드는 함수입니다. 규칙 · LLM 한 번 · 에이전트 루프 무엇이든 담길 수 있습니다
AI가 쓴 LangGraph 코드를 버전 확인 없이 실행⚠️ 이름이 자주 바뀝니다. 버전 출력과 문서 주소를 받으세요
그래프 그림을 안 뽑고 코드만 검수⭕ draw_mermaid()로 설계 그림과 비교하는 것이 가장 쌉니다

부록 C. NotebookLM 복습 프롬프트

이 18차시 노트만 근거로 비전공자용 5문제를 내줘.
"체인과 그래프의 경계", "State와 Node를 축 ③으로 구별하기", "리듀서", "큰 흐름은 코드, 칸 안 판단은 모델"은 반드시 포함해줘.
내가 답한 뒤에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.