실무 Multi-Agent 오케스트레이션 16장 · 멀티턴 대화와 세션 관리 3 / 7 ← 이전목차다음 → TechLead Cro

16장. 멀티턴 대화와 세션 관리

세션과 스레드 — 누구의, 어느 대화인가

한 줄 요약

이력을 보관하기로 했으면 어떤 단위로 나눠 보관할지 정해야 합니다. 대화 하나를 스레드(thread) 라고 부르고, 스레드마다 이력을 따로 둡니다. 8장에서 만든 "누가 로그인했는가"(신원 세션)와는 다른 개념입니다.


1. 이력이 섞이면 안 된다

상담 창구에는 동시에 여러 고객이 들어옵니다. 이력을 리스트 하나에 전부 쌓으면 고객 A의 "그거"가 고객 B의 주문을 가리키게 됩니다. 같은 고객이라도 어제의 상담과 오늘의 상담은 다른 대화일 수 있습니다.

그래서 이력은 대화 하나 단위로 격리합니다. 이 단위가 스레드이고, 스레드를 가리키는 이름표가 thread_id입니다.


2. 신원 세션과 대화 스레드

8장에서 CustomerSession을 만들었습니다. 이름에 "세션"이 들어 있어 헷갈리기 쉬우니 나란히 놓고 구분합니다.

신원 세션 (8장 CustomerSession) 대화 스레드 (이번 장 ChatSession)
답하는 질문 지금 상대가 누구인가 지금 어느 대화의 연속인가
정하는 것 볼 수 있는 데이터의 범위 (도구의 권한) 모델에게 보낼 이력 (문맥)
수명 로그인해 있는 동안 대화 하나가 이어지는 동안
코드에서 CustomerSession("C007") ChatSession(thread_id="web-C007-0001")

한 고객(신원 세션 하나)이 스레드를 여러 개 가질 수 있습니다. 반대로 스레드 하나가 여러 고객에 걸치는 일은 없어야 합니다.

코드 위쪽의 이 두 줄이 신원 쪽입니다.

session = CustomerSession("C007")
tools = make_tools(session)

make_tools(session)은 8장에서 본 대로 이 고객의 주문만 볼 수 있는 도구 묶음을 만듭니다. 이력이 아무리 길어져도 이 경계는 바뀌지 않습니다. 권한은 이력이 아니라 신원 세션이 정합니다.


3. 스레드 하나 = 객체 하나

우리 구현에서는 스레드 하나를 ChatSession 객체 하나로 나타냅니다.

class ChatSession:
    """세션(스레드) 하나의 대화 이력을 관리한다."""

    def __init__(self, thread_id: str, max_turns: int = 10):
        self.thread_id = thread_id
        self.history: list[types.Content] = []   # 대화 이력이 곧 '기억'
        self.max_turns = max_turns               # 보관할 최근 턴 수

history가 객체 안에 들어 있으므로, 객체를 두 개 만들면 이력도 두 개가 됩니다. 따로 격리하는 코드를 쓰지 않아도 객체가 다르면 대화가 섞이지 않습니다.

a = ChatSession(thread_id="ex-A")
b = ChatSession(thread_id="ex-B")   # a 의 대화를 전혀 모른다

이번 장의 thread_id는 이름표 역할만 합니다. 여러 사람이 동시에 접속하는 서비스라면 이 ID로 "이 대화의 이력"을 찾아 오게 됩니다.


4. 스레드가 끝나면 기억도 끝난다

history는 프로그램이 돌아가는 동안 메모리에만 있습니다. 프로그램을 끄거나 객체가 사라지면 이력도 함께 사라집니다.

상황 기억
같은 스레드에서 다음 문의 남아 있다
다른 스레드 모른다 (격리)
프로그램을 껐다 켠 뒤 사라졌다

지난주에 교환을 문의한 고객이 다시 찾아와 "저번에 문의한 건 어떻게 됐어요?"라고 하면, 지금의 구조로는 처음 보는 사람처럼 대할 수밖에 없습니다. 이 숙제는 17장에서 풉니다.


핵심 정리

  • 이력은 스레드(대화 하나) 단위로 격리하고, thread_id로 구분합니다.
  • 신원 세션은 "누구인가"(권한)를, 대화 스레드는 "어느 대화인가"(문맥)를 정합니다.
  • 권한의 경계는 이력이 아니라 신원 세션과 도구 코드에 있습니다.
  • 스레드 하나를 ChatSession 객체 하나로 나타냅니다. 객체가 다르면 이력이 섞이지 않습니다.
  • 이력은 메모리에만 있어, 스레드가 끝나면 사라집니다.
← 이전 절대화 이력 — 기억은 우리가 보관한다다음 절 →기억의 비용과 trim — 이력은 매번 다시 나간다
오명운 · macro@prag-ai.com