실무 Multi-Agent 오케스트레이션 24장 · 서비스 통합과 실행 3 / 9 ← 이전목차다음 → TechLead Cro

24장. 서비스 통합과 실행

세션과 대화 이력 — 브라우저마다 대화가 따로 있다

한 줄 요약

서버 하나에 브라우저 여러 개가 붙습니다. 16장에서 배운 "이력이 곧 기억"을 그대로 쓰되, 누구의 이력인지 구분할 이름표가 필요합니다. 화면이 session_id 를 만들어 매 요청에 실어 보내고, 서버는 그 이름표별로 이력을 따로 보관합니다.


1. LLM은 기억하지 않고, 서버가 기억한다

16장의 원리를 다시 적습니다.

  • LLM은 이전 호출을 기억하지 않는다.
  • 그래서 앞선 대화 전체를 매번 다시 보낸다.
  • 그 이력을 보관하는 것은 우리 프로그램이다.

22장의 run_supervisor도 이 방식이었습니다. 이력을 받아서, 새 질문을 붙여 보내고, 갱신된 이력을 돌려주었습니다. 터미널에서는 변수 하나에 이력을 담으면 됐습니다. 서버에서는 대화가 여러 개입니다.


2. 이름표는 화면이 만든다

제공된 index.html에 이런 줄이 있습니다.

const sessionId = "web-" + Math.random().toString(36).slice(2, 10);

화면이 열릴 때 web-k3x9a2bf 같은 무작위 이름표를 하나 만듭니다. 그리고 문의를 보낼 때마다 함께 보냅니다.

body: JSON.stringify({ session_id: sessionId, message }),

이 이름표가 16장에서 말한 세션(session), 곧 "하나의 이어지는 대화"를 가리킵니다.

상황 session_id 대화
같은 화면에서 계속 묻는다 그대로 이어진다
화면을 새로고침한다 새로 만들어진다 새 대화가 된다
탭을 하나 더 연다 탭마다 다르다 서로 섞이지 않는다

3. 서버는 이름표별로 보관한다

main.py에서 이력을 다루는 줄은 셋입니다.

histories: dict[str, list] = {}          # session_id → messages

history = histories.get(req.session_id, [])            # 1) 꺼낸다 (없으면 빈 목록)
messages = list(history) + [{"role": "user", "content": req.message}]   # 2) 새 문의를 붙인다
...
histories[req.session_id] = new_messages               # 3) 갱신해 넣는다
단계 하는 일 16장에서는
꺼낸다 이 이름표의 이력을 찾는다. 처음이면 빈 목록 대화 객체의 이력 변수
붙인다 이력 뒤에 이번 문의를 더해 Supervisor에게 보낸다 같다
넣는다 답까지 포함된 이력으로 바꿔 둔다 같다

16장에서 변수 하나였던 것이 딕셔너리로 바뀌었을 뿐입니다. 탭 A의 "그거"는 A의 이력에서, 탭 B의 "그거"는 B의 이력에서 풀립니다. 실습문제 2에서 직접 확인합니다.


4. 두 가지 "세션"을 구분한다

이 프로젝트에는 세션이라는 말이 두 군데 나옵니다. 서로 다른 것입니다.

이름 무엇을 가리키나 어디에 있나 무엇을 정하나
CustomerSession 누가 로그인했는가 8장 haru_tools.py 누구의 주문을 볼 수 있는가 (권한)
session_id 어느 대화인가 화면이 만들어 보낸다 어느 이력을 이어 갈 것인가 (기억)

지금 서버에서는 CustomerSession이 C003 하나로 고정이고, session_id만 브라우저마다 다릅니다. 탭을 열 개 열면 같은 고객 C003의 서로 다른 대화 열 개가 됩니다.


5. 이력을 메모리에 둔다는 것

histories는 파이썬 딕셔너리, 곧 서버 프로그램의 메모리에 있습니다. 수업에서 내 컴퓨터로 돌리기에 알맞은 가장 단순한 보관 방법입니다. 이 선택에서 세 가지 성질이 따라옵니다.

성질 뜻 여러 사람이 쓰는 서비스로 갈 때
서버와 수명이 같다 서버를 다시 켜면 대화가 처음부터다. --reload로 코드를 고쳐 저장할 때도 같다 이력을 데이터베이스 같은 바깥 저장소에 둔다
대화만큼 길어진다 이력이 매 호출의 입력으로 나간다 17장의 요약 메모리를 붙인다
이름표는 화면이 만든다 session_id는 화면이 보낸 값을 그대로 쓴다 이름표를 로그인 정보와 묶는다

23장에서 InMemorySaver를 두고 한 이야기와 같습니다. 메모리에 둔 것은 프로그램과 함께 사라지고, 오래 남겨야 하는 것은 바깥 저장소로 옮깁니다.

이름표가 화면에서 오는데도 주문 데이터가 안전한 까닭도 봐 둡니다. 어떤 이름표로 대화하든 주문 데이터는 CustomerSession이 정한 고객 것만 나옵니다. 권한의 경계를 대화 이름표가 아니라 로그인 세션에 둔 8장의 설계가 여기서도 받쳐 줍니다.


핵심 정리

  • 대화의 기억은 서버가 이력을 보관해 만듭니다. 16장과 같은 원리입니다.
  • 화면이 무작위 session_id 를 만들어 매 요청에 실어 보냅니다. 새로고침하면 새 대화입니다.
  • 서버는 session_id별로 이력을 꺼내고, 붙이고, 다시 넣습니다.
  • CustomerSession(누가 로그인했나)과 session_id(어느 대화인가)는 다른 것입니다.
  • 이력은 메모리에 있어 서버를 끄면 사라집니다. 서비스로 가려면 바깥 저장소로 옮깁니다.
← 이전 절FastAPI — 파이썬 함수를 주소로 만든다다음 절 →SSE — 과정이 보이는 응답
오명운 · macro@prag-ai.com