RAG2026-5일21차시 · 첫 번째 LangGraph 실습6 / 19← 이전목차다음 →MetaContents

21차시. 첫 번째 LangGraph 실습

3. 실습 ① — State와 더미 노드

출처: 원본 PDF 21차시_첫번째LangGraph실습.pdf 6~7쪽 · 쪽 그림 6쪽 7쪽

API 없이 돌아가는 완전한 그래프를 만들어봅니다.

📝 src/mini_graph.py — 1단계 State

Python
from typing import TypedDict, List, Annotated
from langgraph.graph import StateGraph, START, END
import operator

class MiniState(TypedDict):
    question: str
    documents: List[str]
    answer: str
    grade: str
    retries: int
    log: Annotated[List[str], operator.add]

def init(q: str) -> MiniState:
    return {"question": q, "documents": [], "answer": "",
            "grade": "", "retries": 0, "log": []}

📝 2단계 더미 노드

Python
def retrieve(state: MiniState):
    # 질문에 '없는'이 들어가면 검색 실패로 흉내
    q = state["question"]
    docs = [] if "없는" in q else ["조각A", "조각B", "조각C"]
    print(f"   → retrieve: {len(docs)}건")
    return {"documents": docs, "log": [f"검색 {len(docs)}건"]}

def generate(state: MiniState):
    n = len(state["documents"])
    # 재시도할수록 답변이 좋아지는 상황을 흉내
    quality = "좋은" if state["retries"] >= 1 else "부실한"
    print(f"   → generate: {quality} 답변")
    return {"answer": f"{n}건 근거로 만든 {quality} 답변",
            "log": [f"생성({quality})"]}

def verify(state: MiniState):
    ok = "좋은" in state["answer"]
    print(f"   → verify: {'통과' if ok else '재시도'}")
    return {"grade": "pass" if ok else "retry",
            "log": ["검증 " + ("통과" if ok else "실패")]}
def bump(state: MiniState):
    n = state["retries"] + 1
    print(f"   → bump: {n}회차")
    return {"retries": n, "log": [f"재시도 {n}"]}

def fallback(state: MiniState):
    print("   → fallback")
    return {"answer": "자료를 찾지 못했습니다.",
            "grade": "giveup", "log": ["fallback"]}

💡 더미 노드 설계 요령
원하는 상황을 마음대로 만들 수 있게 설계합니다.
· "없는"이 포함되면 → 검색 실패 재현
· retries가 0이면 → 검증 실패 재현
· retries가 1 이상이면 → 통과 재현
이렇게 하면 정상 경로 · 실패 경로 · 루프를
질문 하나만 바꿔서 전부 테스트할 수 있습니다.

실습 코드 · 21/mini_graph.py

실습 코드: 실습/src/21/mini_graph.py · 위의 원본 PDF 21차시 6~7쪽 「3️⃣ 실습 ① — State와 더미 노드」과 이어집니다.

Python
# ============================================================
# 21차시 | 첫 번째 LangGraph 실습
# 교안: 21차시_첫번째LangGraph실습.pptx
# 역할: 작은 RAG 그래프가 나눠 쓸 State 칸과 빈 노트를 만드는 함수만 둔다.
# 입력: init(question)
# 출력: 없음 (이 파일을 실행해도 print 하지 않는다)
#
#   State  = MiniState. 질문, 문서, 답변, 검증, 재시도, 로그.
#   Node   = 이 파일에는 없다. init 은 노드가 아니라 첫 노트 생성 함수.
#   reducer = log. Annotated[List[str], operator.add] 이면
#            노드가 ["한 줄"] 을 돌려줄 때 기존 리스트 뒤에 붙는다.
#            통째로 덮어쓰지 않는다.
#
# 흐름
#   (그래프 없음)
#   question → init → question 만 채우고 나머지 칸은 비운 딕셔너리
# ============================================================

# 이 코드는 LangGraph에서 사용할 상태(State)의 구조를 정의합니다.
# 질문, 검색 문서, 답변, 검증 결과, 재시도 횟수, 실행 로그를 관리합니다.

from typing import TypedDict, List, Annotated
import operator

# ------------------------------------------------------------
# 그래프가 공유할 상태 구조
# ------------------------------------------------------------

class MiniState(TypedDict):
    # 사용자가 입력한 질문
    question: str

    # 검색된 문서 목록
    documents: List[str]

    # 생성된 답변
    answer: str

    # 답변 검증 결과
    # 예: "pass", "retry", "giveup"
    grade: str

    # 현재까지 재시도한 횟수
    retries: int

    # 그래프 실행 과정을 기록하는 로그
    # reducer: 여러 노드의 log 를 한 리스트 뒤에 이어 붙인다.
    log: Annotated[List[str], operator.add]

# ------------------------------------------------------------
# 그래프 실행에 사용할 초기 상태 만들기
# ------------------------------------------------------------

# 노드가 아님. invoke / stream 에 넣을 첫 State를 만든다.
#   읽기: 인자 question
#   쓰기: question, documents, answer, grade, retries, log (새 딕셔너리)
def init(question: str) -> MiniState:
    """
    사용자의 질문을 바탕으로 초기 상태를 만듭니다.

    그래프를 처음 실행할 때는 아직 검색 결과와 답변이 없습니다.
    따라서 documents, answer, grade, log는 빈 값으로 시작합니다.
    retries도 처음에는 0으로 설정합니다.
    """

    # 그래프 실행에 필요한 초기 상태를 반환합니다.
    return {
        "question": question,
        "documents": [],
        "answer": "",
        "grade": "",
        "retries": 0,
        "log": [],
    }

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/21
      python mini_graph.py
(실제 실행 출력)
(표준 출력 없음. State 와 init 만 정의한다.)

코드 해설

작은 RAG 그래프가 나눠 쓸 State 칸과 빈 노트를 만드는 함수만 둔다. 입력은 init(question)이고, 출력은 없음 (이 파일을 실행해도 print 하지 않는다)입니다.

주석에 적힌 흐름입니다.

출력
흐름
(그래프 없음)
question → init → question 만 채우고 나머지 칸은 비운 딕셔너리

코드 앞에서 고정해 두는 말입니다.

  • 21차시 | 첫 번째 LangGraph 실습
  • 교안: 21차시_첫번째LangGraph실습.pptx
  • State = MiniState. 질문, 문서, 답변, 검증, 재시도, 로그.
  • Node = 이 파일에는 없다. init 은 노드가 아니라 첫 노트 생성 함수.
  • reducer = log. Annotated[List[str], operator.add] 이면
  • 노드가 ["한 줄"] 을 돌려줄 때 기존 리스트 뒤에 붙는다.
  • 통째로 덮어쓰지 않는다.

함수와 클래스로 나누어 읽습니다.

  • MiniState: 이름 그대로 한 가지 일만 합니다. 본문 주석을 같이 읽습니다.
  • init: 노드가 아님. invoke / stream 에 넣을 첫 State를 만든다. 읽기: 인자 question 쓰기: question, documents, answer, grade, retries, log (새 딕셔너리)

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

실습 코드 · 21/mini_graph2.py

실습 코드: 실습/src/21/mini_graph2.py · 위의 원본 PDF 21차시 6~7쪽 「3️⃣ 실습 ① — State와 더미 노드」과 이어집니다.

Python
# ============================================================
# 21차시 | 첫 번째 LangGraph 실습
# 교안: 21차시_첫번째LangGraph실습.pptx
# 역할: 검색·생성·검증·재시도·안내를 가짜 데이터로 흉내 내는 노드 함수 모음.
#       이 파일은 노드를 엣지로 연결하지 않는다. 실행해도 출력은 없다.
# 입력: MiniState
# 출력: 각 함수가 고친 칸만 담은 딕셔너리
#
#   State  = MiniState. 노드들은 이 노트에서 자기 칸만 읽고 쓴다.
#   Node   = retrieve, generate, verify, bump, fallback.
#   reducer = log. return 하는 log 는 한 칸짜리 리스트라 뒤에 이어 붙는다.
#   Edge / compile / invoke = 다음 파일에서 연결한다.
#
# 함수만 있을 때의 데이터 흐름 (아직 자동 실행 아님)
#   question → retrieve → documents
#   documents, retries → generate → answer
#   answer → verify → grade
#   retries → bump → retries+1
#   (검색 실패 또는 포기) → fallback → answer, grade="giveup"
# ============================================================

# 이 코드는 LangGraph에서 사용할 상태와 더미 노드를 정의합니다.
# 실제 검색이나 LLM 호출 없이 검색, 생성, 검증, 재시도 과정을 흉내 냅니다.

from typing import TypedDict, List, Annotated
import operator

# ============================================================
# 그래프 상태 정의
# ============================================================

class MiniState(TypedDict):
    # 사용자가 입력한 질문
    question: str

    # 검색된 문서 목록
    documents: List[str]

    # 생성된 답변
    answer: str

    # 검증 결과
    # pass: 통과, retry: 재시도, giveup: 포기
    grade: str

    # 재시도 횟수
    retries: int

    # 노드 실행 기록
    # reducer: 각 노드가 돌려준 log 를 한 리스트에 이어 붙인다.
    log: Annotated[List[str], operator.add]

# ============================================================
# 초기 상태 생성 함수
# ============================================================

# 노드가 아님. 첫 공유 노트를 만든다.
#   읽기: 인자 question
#   채우는 칸: question, documents, answer, grade, retries, log
def init(question: str) -> MiniState:
    """
    그래프 실행에 사용할 초기 상태를 만듭니다.

    처음에는 검색 결과와 답변이 없으므로
    관련 항목을 빈 값으로 설정합니다.
    """

    # 그래프 실행에 사용할 초기 상태를 반환합니다.
    return {
        "question": question,
        "documents": [],
        "answer": "",
        "grade": "",
        "retries": 0,
        "log": [],
    }

# ============================================================
# Retriever Node
# ============================================================

# 노드 retrieve
#   읽기: question
#   쓰기: documents, log
def retrieve(state: MiniState) -> dict:
    """
    질문을 바탕으로 검색 결과를 만듭니다.

    질문에 '없는'이라는 단어가 포함되면
    검색 실패 상황을 흉내 냅니다.
    """

    # 현재 질문을 가져옵니다.
    question = state["question"]

    # 검색 결과를 저장할 리스트를 만듭니다.
    documents = []

    # 질문에 '없는'이 포함되어 있는지 확인합니다.
    if "없는" in question:
        # 검색 실패 상황을 만듭니다.
        documents = []
    else:
        # 검색 성공 상황을 만듭니다.
        documents = ["조각A", "조각B", "조각C"]

    # 검색된 문서 개수를 출력합니다.
    print(f"   → retrieve: {len(documents)}건")

    # 변경된 값만 반환합니다.
    return {
        "documents": documents,
        "log": [f"검색 {len(documents)}건"],
    }

# ============================================================
# Generator Node
# ============================================================

# 노드 generate
#   읽기: documents, retries
#   쓰기: answer, log
def generate(state: MiniState) -> dict:
    """
    검색된 문서를 바탕으로 가짜 답변을 생성합니다.

    첫 번째 답변은 부실하게 만들고,
    재시도 후에는 좋은 답변을 만듭니다.
    """

    # 검색된 문서의 개수를 확인합니다.
    document_count = len(state["documents"])

    # 현재 재시도 횟수를 확인합니다.
    retry_count = state["retries"]

    # 답변 품질을 저장할 변수입니다.
    quality = ""

    # 재시도 횟수에 따라 답변 품질을 결정합니다.
    if retry_count >= 1:
        # 재시도 후에는 좋은 답변을 만듭니다.
        quality = "좋은"
    else:
        # 첫 번째 답변은 부실한 답변으로 처리합니다.
        quality = "부실한"

    # 생성된 답변의 품질을 출력합니다.
    print(f"   → generate: {quality} 답변")

    # 가짜 답변을 생성합니다.
    answer = f"{document_count}건 근거로 만든 {quality} 답변"

    # 변경된 값만 반환합니다.
    return {
        "answer": answer,
        "log": [f"생성({quality})"],
    }

# ============================================================
# Verifier Node
# ============================================================

# 노드 verify
#   읽기: answer
#   쓰기: grade, log
def verify(state: MiniState) -> dict:
    """
    생성된 답변을 검증합니다.

    답변에 '좋은'이라는 단어가 있으면 통과시키고,
    없으면 재시도 대상으로 처리합니다.
    """

    # 현재 답변을 가져옵니다.
    answer = state["answer"]

    # 검증 결과를 저장할 변수를 만듭니다.
    grade = ""
    message = ""

    # 답변에 '좋은'이라는 단어가 포함되어 있는지 확인합니다.
    if "좋은" in answer:
        # 좋은 답변이면 통과시킵니다.
        grade = "pass"
        message = "통과"
    else:
        # 부실한 답변이면 재시도 대상으로 처리합니다.
        grade = "retry"
        message = "실패"

    # 검증 결과를 출력합니다.
    if grade == "pass":
        print("   → verify: 통과")
    else:
        print("   → verify: 재시도")

    # 검증 결과와 로그를 반환합니다.
    return {
        "grade": grade,
        "log": [f"검증 {message}"],
    }

# ============================================================
# Retry Counter Node
# ============================================================

# 노드 bump
#   읽기: retries
#   쓰기: retries, log
def bump(state: MiniState) -> dict:
    """
    재시도 횟수를 1 증가시킵니다.
    """

    # 현재 재시도 횟수에 1을 더합니다.
    retry_count = state["retries"] + 1

    # 증가한 재시도 횟수를 출력합니다.
    print(f"   → bump: {retry_count}회차")

    # 변경된 값만 반환합니다.
    return {
        "retries": retry_count,
        "log": [f"재시도 {retry_count}"],
    }

# ============================================================
# Fallback Node
# ============================================================

# 노드 fallback
#   읽기: 없음 (state 는 받지만 칸을 읽지 않음)
#   쓰기: answer, grade, log
def fallback(state: MiniState) -> dict:
    """
    검색에 실패했거나 더 이상 처리할 수 없을 때
    사용자에게 안내 답변을 반환합니다.
    """

    # Fallback 노드가 실행되었음을 출력합니다.
    print("   → fallback")

    # 안내 답변과 포기 상태를 반환합니다.
    return {
        "answer": "자료를 찾지 못했습니다.",
        "grade": "giveup",
        "log": ["fallback"],
    }

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/21
      python mini_graph2.py
(실제 실행 출력)
(표준 출력 없음. 노드 함수만 정의하고 호출하지 않는다.)

코드 해설

검색·생성·검증·재시도·안내를 가짜 데이터로 흉내 내는 노드 함수 모음. 입력은 MiniState이고, 출력은 각 함수가 고친 칸만 담은 딕셔너리입니다.

코드 앞에서 고정해 두는 말입니다.

  • 21차시 | 첫 번째 LangGraph 실습
  • 교안: 21차시_첫번째LangGraph실습.pptx
  • 이 파일은 노드를 엣지로 연결하지 않는다. 실행해도 출력은 없다.
  • State = MiniState. 노드들은 이 노트에서 자기 칸만 읽고 쓴다.
  • Node = retrieve, generate, verify, bump, fallback.
  • reducer = log. return 하는 log 는 한 칸짜리 리스트라 뒤에 이어 붙는다.
  • Edge / compile / invoke = 다음 파일에서 연결한다.
  • 함수만 있을 때의 데이터 흐름 (아직 자동 실행 아님)

함수와 클래스로 나누어 읽습니다.

  • MiniState: 이름 그대로 한 가지 일만 합니다. 본문 주석을 같이 읽습니다.
  • init: 노드가 아님. 첫 공유 노트를 만든다. 읽기: 인자 question 채우는 칸: question, documents, answer, grade, retries, log
  • retrieve: 노드 retrieve 읽기: question 쓰기: documents, log
  • generate: 노드 generate 읽기: documents, retries 쓰기: answer, log
  • verify: 노드 verify 읽기: answer 쓰기: grade, log
  • bump: 노드 bump 읽기: retries 쓰기: retries, log
  • fallback: 노드 fallback 읽기: 없음 (state 는 받지만 칸을 읽지 않음) 쓰기: answer, grade, log

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

실습 코드 · 21/mini_graph_nodetest.py

실습 코드: 실습/src/21/mini_graph_nodetest.py · 위의 원본 PDF 21차시 6~7쪽 「3️⃣ 실습 ① — State와 더미 노드」과 이어집니다.

Python
# ============================================================
# 21차시 | 첫 번째 LangGraph 실습
# 교안: 21차시_첫번째LangGraph실습.pptx
# 역할: 그래프에 연결하기 전에 노드 함수를 하나씩 직접 호출해 입출력을 본다.
# 입력: init("환불 규정은?") 로 만든 State. 중간에는 documents, answer 를 손으로 넣는다.
# 출력: 각 함수의 return 딕셔너리
#
#   State  = MiniState. 테스트에서는 그래프가 아니라 지역 변수 state 를 고친다.
#   Node   = retrieve, generate, verify, bump. fallback 은 정의만 하고 이 테스트에서 호출하지 않는다.
#   reducer = log 규칙만 정의해 둔다. 함수를 직접 부르면 이어 붙이지 않고 return 값 그대로 보인다.
#   Edge / compile / invoke = 없다.
#
# 테스트가 손으로 밟는 순서
#   init → retrieve → (documents 를 2건으로 바꿈) → generate → (answer 를 부실로 바꿈) → verify → bump
# ============================================================

# 이 코드는 LangGraph에서 사용할 상태와 더미 노드를 정의합니다.
# 실제 RAG나 LLM 없이 검색, 생성, 검증, 재시도 과정을 흉내 냅니다.

from typing import TypedDict, List, Annotated
import operator

# ============================================================
# 그래프 상태 정의
# ============================================================

class MiniState(TypedDict):
    # 사용자의 질문
    question: str

    # 검색된 문서 목록
    documents: List[str]

    # 생성된 답변
    answer: str

    # 검증 결과
    # pass: 통과, retry: 재시도, giveup: 포기
    grade: str

    # 재시도 횟수
    retries: int

    # 노드 실행 로그
    # reducer: 그래프에 넣으면 log 를 뒤에 이어 붙인다. 이 파일은 직접 호출만 한다.
    log: Annotated[List[str], operator.add]

# ============================================================
# 초기 상태 생성
# ============================================================

# 노드가 아님. 첫 State를 만든다.
#   읽기: 인자 question
#   채우는 칸: question, documents, answer, grade, retries, log
def init(question: str) -> MiniState:
    """
    그래프 실행에 사용할 초기 상태를 만듭니다.
    """

    # 초기 상태를 반환합니다.
    return {
        "question": question,
        "documents": [],
        "answer": "",
        "grade": "",
        "retries": 0,
        "log": [],
    }

# ============================================================
# Retriever Node
# ============================================================

# 노드 retrieve
#   읽기: question
#   쓰기: documents, log
def retrieve(state: MiniState) -> dict:
    """
    질문을 바탕으로 검색 결과를 만듭니다.

    질문에 '없는'이 포함되면 검색 실패로 처리합니다.
    """

    # 질문을 가져옵니다.
    question = state["question"]

    # 검색 결과를 저장할 리스트입니다.
    documents = []

    # 검색 실패 상황인지 확인합니다.
    if "없는" in question:
        # 검색 결과가 없는 상태를 만듭니다.
        documents = []
    else:
        # 검색 성공 상황을 만듭니다.
        documents = ["조각A", "조각B", "조각C"]

    # 검색 결과 개수를 출력합니다.
    print(f"   → retrieve: {len(documents)}건")

    # 변경된 값만 반환합니다.
    return {
        "documents": documents,
        "log": [f"검색 {len(documents)}건"],
    }

# ============================================================
# Generator Node
# ============================================================

# 노드 generate
#   읽기: documents, retries
#   쓰기: answer, log
def generate(state: MiniState) -> dict:
    """
    검색된 문서를 바탕으로 가짜 답변을 생성합니다.

    첫 번째 답변은 부실하게 만들고,
    재시도 후에는 좋은 답변을 만듭니다.
    """

    # 검색된 문서의 개수를 확인합니다.
    document_count = len(state["documents"])

    # 재시도 횟수를 확인합니다.
    retry_count = state["retries"]

    # 답변 품질을 결정합니다.
    if retry_count >= 1:
        quality = "좋은"
    else:
        quality = "부실한"

    # 가짜 답변을 만듭니다.
    answer = f"{document_count}건 근거로 만든 {quality} 답변"

    # 생성 결과를 출력합니다.
    print(f"   → generate: {quality} 답변")

    # 변경된 값만 반환합니다.
    return {
        "answer": answer,
        "log": [f"생성({quality})"],
    }

# ============================================================
# Verifier Node
# ============================================================

# 노드 verify
#   읽기: answer
#   쓰기: grade, log
def verify(state: MiniState) -> dict:
    """
    생성된 답변을 검증합니다.

    답변에 '좋은'이 포함되면 통과시키고,
    그렇지 않으면 재시도 대상으로 처리합니다.
    """

    # 현재 답변을 가져옵니다.
    answer = state["answer"]

    # 답변 품질을 확인합니다.
    if "좋은" in answer:
        print("   → verify: 통과")

        return {
            "grade": "pass",
            "log": ["검증 통과"],
        }

    # 좋은 답변이 아니면 재시도합니다.
    print("   → verify: 재시도")

    return {
        "grade": "retry",
        "log": ["검증 실패"],
    }

# ============================================================
# Retry Counter Node
# ============================================================

# 노드 bump
#   읽기: retries
#   쓰기: retries, log
def bump(state: MiniState) -> dict:
    """
    재시도 횟수를 1 증가시킵니다.
    """

    # 재시도 횟수를 1 증가시킵니다.
    retry_count = state["retries"] + 1

    # 재시도 횟수를 출력합니다.
    print(f"   → bump: {retry_count}회차")

    # 변경된 값만 반환합니다.
    return {
        "retries": retry_count,
        "log": [f"재시도 {retry_count}"],
    }

# ============================================================
# Fallback Node
# ============================================================

# 노드 fallback
#   읽기: 없음
#   쓰기: answer, grade, log
def fallback(state: MiniState) -> dict:
    """
    검색에 실패했을 때 안내 답변을 반환합니다.
    """

    # Fallback 실행을 출력합니다.
    print("   → fallback")

    # 안내 답변과 포기 상태를 반환합니다.
    return {
        "answer": "자료를 찾지 못했습니다.",
        "grade": "giveup",
        "log": ["fallback"],
    }

# ============================================================
# 노드 단독 테스트
# ============================================================

if __name__ == "__main__":

    print("■ 노드 단독 테스트")

    # 초기 상태를 만듭니다.
    state = init("환불 규정은?")

    # Retriever 노드를 테스트합니다.
    retrieve_result = retrieve(state)
    print("1) retrieve:", retrieve_result)

    # 검색 결과를 임의로 설정합니다.
    state["documents"] = ["조각A", "조각B"]

    # Generator 노드를 테스트합니다.
    generate_result = generate(state)
    print("2) generate:", generate_result)

    # 부실한 답변을 임의로 설정합니다.
    state["answer"] = "부실한 답변"

    # Verifier 노드를 테스트합니다.
    verify_result = verify(state)
    print("3) verify:  ", verify_result)

    # Bump 노드를 테스트합니다.
    bump_result = bump(state)
    print("4) bump:    ", bump_result)

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/21
      python mini_graph_nodetest.py
(실제 실행 출력)
■ 노드 단독 테스트
   → retrieve: 3건
1) retrieve: {'documents': ['조각A', '조각B', '조각C'], 'log': ['검색 3건']}
   → generate: 부실한 답변
2) generate: {'answer': '2건 근거로 만든 부실한 답변', 'log': ['생성(부실한)']}
   → verify: 재시도
3) verify:   {'grade': 'retry', 'log': ['검증 실패']}
   → bump: 1회차
4) bump:     {'retries': 1, 'log': ['재시도 1']}

코드 해설

그래프에 연결하기 전에 노드 함수를 하나씩 직접 호출해 입출력을 본다. 입력은 init("환불 규정은?") 로 만든 State. 중간에는 documents, answer 를 손으로 넣는다.이고, 출력은 각 함수의 return 딕셔너리입니다.

코드 앞에서 고정해 두는 말입니다.

  • 21차시 | 첫 번째 LangGraph 실습
  • 교안: 21차시_첫번째LangGraph실습.pptx
  • State = MiniState. 테스트에서는 그래프가 아니라 지역 변수 state 를 고친다.
  • Node = retrieve, generate, verify, bump. fallback 은 정의만 하고 이 테스트에서 호출하지 않는다.
  • reducer = log 규칙만 정의해 둔다. 함수를 직접 부르면 이어 붙이지 않고 return 값 그대로 보인다.
  • Edge / compile / invoke = 없다.
  • 테스트가 손으로 밟는 순서
  • init → retrieve → (documents 를 2건으로 바꿈) → generate → (answer 를 부실로 바꿈) → verify → bump

함수와 클래스로 나누어 읽습니다.

  • MiniState: 이름 그대로 한 가지 일만 합니다. 본문 주석을 같이 읽습니다.
  • init: 노드가 아님. 첫 State를 만든다. 읽기: 인자 question 채우는 칸: question, documents, answer, grade, retries, log
  • retrieve: 노드 retrieve 읽기: question 쓰기: documents, log
  • generate: 노드 generate 읽기: documents, retries 쓰기: answer, log
  • verify: 노드 verify 읽기: answer 쓰기: grade, log
  • bump: 노드 bump 읽기: retries 쓰기: retries, log
  • fallback: 노드 fallback 읽기: 없음 쓰기: answer, grade, log

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

← 이전 절21차시 · 2. 그래프 만드는 4단계다음 절 →21차시 · 4. 실습 ② — 노드 단독 테스트