LangChain 챗봇7장 · 웹 UI 연동과 배포5 / 22← 이전목차다음 →MetaContents

7장. 웹 UI 연동과 배포

st.session_state 로 기억하기

식당에서 손님이 자리에 앉으면 직원이 테이블에 주문표를 하나 꽂아 둡니다. 주문서를 몇 번 새로 쓰든, 테이블의 주문표에 적힌 것은 그대로 남아 있습니다. 옆 테이블에는 옆 테이블의 주문표가 따로 있습니다. st.session_state 가 이 주문표입니다. 스크립트가 처음부터 다시 돌아도 지워지지 않고, 손님(브라우저 탭)마다 따로 있습니다.

다시 돌 때마다 처음 값으로 돌아가는 보통 변수와 다시 돌아도 남는 session_state 를 나란히 놓은 비교 그림

왼쪽 파랑 상자는 보통 변수입니다. 다시 돌 때마다 count = 0 부터 시작합니다. 오른쪽 보라 상자는 st.session_state 입니다. 처음 열었을 때 한 번만 0 을 적어 두고, 그 뒤로는 적힌 값에 더해 갑니다. 여기서 테이블의 주문표가 st.session_state, 테이블마다 따로인 것이 손님(세션)마다 따로인 것입니다. 비유와 다른 점은, 주문표는 손님이 자리를 떠도 영수증으로 남지만 st.session_state 는 손님이 브라우저 탭을 닫거나 새로 고치면 사라진다는 것입니다. 오래 남겨야 하는 기록은 4장 실습 3처럼 파일이나 데이터베이스에 저장합니다.

session_state 다루기

하는 일쓰는 모양뜻
처음 한 번만 만들기if "messages" not in st.session_state:메모장에 이 이름이 없을 때(처음 열었을 때)만
값 적기st.session_state.messages = []점(.)으로 적는다. st.session_state["messages"] 도 같다
값 읽기·고치기st.session_state.count += 1보통 변수처럼 쓴다
이름이 있는지"count" in st.session_stateTrue / False
지우기del st.session_state.count그 이름을 메모장에서 뺀다

짧은 예시

앞 절의 앱에서 보통 변수 대신 메모장에 숫자를 적습니다. 단추를 세 번 누르고, 같은 앱을 새로 열어 새 손님이 되어 봅니다.

Python
from streamlit.testing.v1 import AppTest

APP = """
import streamlit as st

# 메모장에 count 가 없을 때(처음 열었을 때)만 0 을 적는다
if "count" not in st.session_state:
    st.session_state.count = 0
if st.button("장바구니에 담기"):
    st.session_state.count += 1
st.write(f"장바구니: {st.session_state.count}개")
"""

at = AppTest.from_string(APP).run()
for _ in range(3):
    at.button[0].click().run()
print("세 번 누른 뒤:", at.markdown[0].value, "/ 메모장의 count:", at.session_state["count"])

# 같은 앱을 새로 열면 새 손님(새 세션)이다
other = AppTest.from_string(APP).run()
print("새 손님의 화면:", other.markdown[0].value)
출력
세 번 누른 뒤: 장바구니: 3개 / 메모장의 count: 3
새 손님의 화면: 장바구니: 0개

세 번 누르자 3 이 되었습니다. 스크립트는 네 번 돌았지만 count = 0 은 처음 한 번만 실행되었기 때문입니다. at.session_state["count"] 로 앱 밖에서 메모장을 들여다볼 수도 있습니다. 새로 연 other 는 다른 손님이라 메모장이 비어 있고 0 개에서 시작합니다.

코드가 의미하는 것

이 코드는 테이블에 주문표를 꽂아 두고 장바구니 수를 적어 가는 일과, 옆 테이블에 새 손님을 앉히는 일을 흉내 낸 것입니다. 주문표 꽂기, 적어 가기, 새 손님 앉히기의 세 동작입니다.

코드하는 일챗봇에서 뜻하는 것
if "count" not in st.session_state:메모장에 이름이 없을 때만 안쪽을 돈다손님이 처음 앉았을 때 주문표를 한 번만 꽂는 일입니다. 챗봇에서는 빈 대화 기록 목록을 여기서 만듭니다
st.session_state.count += 1메모장의 값을 1 올린다다시 실행을 건너 값이 쌓입니다. 대화 기록에 말을 덧붙이는 일도 같은 방식입니다
at.session_state["count"]앱 밖에서 메모장을 들여다본다시험 코드가 화면 글뿐 아니라 기록 자체를 확인할 수 있습니다
other = AppTest.from_string(APP).run()같은 앱을 새로 연다새 브라우저 탭으로 들어온 다른 손님입니다. 메모장이 따로 생깁니다

결과에서 읽을 것은 두 가지입니다.

  • 세 번 누르자 3 이 되었습니다. 화면의 "장바구니: 3개" 와 메모장의 count 3 이 같습니다. 0 을 적는 줄은 처음 한 번만 돌았습니다.
  • 새 손님은 0 개에서 시작합니다. other 의 화면은 "장바구니: 0개" 입니다. 웹 챗봇에서 손님마다 대화가 섞이지 않는 까닭이 이것입니다.

주의할 점

  • if "…" not in st.session_state: 를 빼고 st.session_state.count = 0 만 적으면 다시 돌 때마다 0 으로 덮어써서 보통 변수와 같아집니다.
  • 4장에서는 손님마다 기록을 나누려고 세션 id 와 store 사전을 직접 만들었습니다. Streamlit 에서는 브라우저 탭마다 st.session_state 가 따로 있으므로, 대화 기록을 여기에 두기만 해도 손님마다 나뉩니다.
  • 메모장은 서버의 메모리에 있습니다. 손님이 많고 대화가 길면 메모리를 많이 쓰므로, 4장의 Window 처럼 최근 기록만 남기는 것을 생각합니다.
← 이전 절7장 · 위에서 아래로 다시 도는 실행 모델다음 절 →7장 · 채팅 화면: chat_message 와 chat_input