LLM 엔지니어링14장 · Streamlit 화면과 Docker 컨테이너7 / 22← 이전목차다음 →MetaContents

14장. Streamlit 화면과 Docker 컨테이너

채팅 화면

메신저는 위로 지난 대화가 쌓이고 아래에 입력 칸이 있습니다. 새 말을 보내면 내 말풍선과 상대의 답 말풍선이 차례로 붙습니다. Streamlit 의 채팅 화면도 대화 기록(세션 상태)을 위에서부터 다시 그리고, 새 입력이 오면 모델에게 기록과 함께 보내 답을 붙입니다.

지난 대화를 다시 그리고, 새 질문을 받아, 대화 기록과 함께 모델에 보내고, 답을 그려 기록에 더하는 네 단계 흐름도

1번에서 세션 상태의 대화 기록을 말풍선으로 다시 그립니다. 2번에서 st.chat_input 으로 새 질문을 받습니다. 3번에서 시스템 지시와 최근 대화를 함께 모델에 보냅니다. 4번에서 답을 말풍선으로 그리고 기록에 더합니다. 여기서 메신저의 대화방이 세션 상태의 기록입니다. 다만 Streamlit 의 기록은 탭을 닫으면 사라지므로, 남겨야 하면 따로 저장합니다.

대화 기록의 꼴

대화 기록은 6장부터 쓴 채팅 API 의 메시지 목록과 같은 꼴로 둡니다. 그래야 그대로 모델에 보낼 수 있습니다.

칸값뜻
rolesystem모델의 역할과 규칙. 화면에는 그리지 않는다
roleuser사용자의 말
roleassistant모델의 답
content글말

최근 대화만 보내기

Python
history = []
for i in range(1, 8):                                     # 일곱 번 주고받은 대화
    history += [{"role": "user", "content": f"질문 {i}"}, {"role": "assistant", "content": f"답 {i}"}]

def to_send(system, history, keep_turns=3):
    """시스템 지시 + 최근 몇 번의 주고받음만 보낸다. 10차시의 컨텍스트 줄이기"""
    return [{"role": "system", "content": system}] + history[-keep_turns * 2:]

sent = to_send("당신은 사내 도우미입니다.", history)
print(len(history), "개 가운데", len(sent) - 1, "개를 보냄:", [m["content"] for m in sent])

코드에 나오는 함수

코드쉬운 뜻
history += [{...}, {...}]대화 기록 목록 끝에 사용자 말과 모델 답 두 개를 이어 붙인다
{"role": "user", "content": ...}메시지 하나의 꼴이다. role(역할)은 누가 말했는지, content(내용)는 말이다
keep_turns=3인자를 주지 않으면 3 을 쓴다. turn(차례)은 한 번 묻고 한 번 답한 것이다
history[-keep_turns * 2:]목록의 뒤에서 6개(3번 × 2개)만 잘라 낸다. 음수 번호는 뒤에서부터 센다
[m["content"] for m in sent]보낼 메시지마다 말만 뽑아 목록으로 만든다

이 코드가 뜻하는 것

회의에 늦게 온 동료에게 앞의 이야기를 다 들려주지 않고 "방금 나온 세 가지만" 알려 주는 것과 같습니다. 회의의 목적은 맨 앞에 꼭 말해 줍니다. 여기서 회의의 목적이 시스템 지시, 방금 나온 세 가지가 최근 세 번의 주고받음입니다.

줄하는 일쉽게 말하면
for i in range(1, 8):일곱 번 주고받은 대화를 만든다회의에서 이야기가 일곱 번 오갔다
def to_send(...)시스템 지시 하나에 최근 6개를 붙인다목적 한마디 + 최근 이야기 셋
sent = to_send(...)보낼 목록을 만든다늦은 동료에게 전할 말
print(len(history), ..., len(sent) - 1, ...)기록 수와 보낸 대화 수를 찍는다. 1 을 빼는 것은 시스템 지시를 세지 않으려는 것이다몇 개 가운데 몇 개를 전했나

결과는 14개 가운데 6개를 보냈고, 보낸 것은 시스템 지시와 질문 5부터 답 7까지입니다. 질문 1부터 답 4까지는 모델이 모르게 되므로, 아주 앞의 내용을 물으면 모델이 답하지 못할 수 있습니다.

주의할 점

  • 대화가 길어지면 모델에 보내는 글도 길어집니다. 최근 몇 번만 보내거나 요약합니다(10장).
  • 모델의 답이 늦으면 사용자는 화면이 멈췄다고 생각합니다. st.spinner 로 기다리는 중임을 보이거나, 답을 한 글자씩 흘려 보여 줍니다(st.write_stream).
← 이전 절14장 · 상태와 캐시다음 절 →14장 · 화면과 API 잇기