멀티턴(Multi-turn)이란?

wldbs._.·2025년 8월 11일

RAG

목록 보기
17/22
post-thumbnail

LangChain으로 이전 대화 내용을 기억하는 4가지 구현 방법 | 멀티턴 챗봇
Google Colab

RAG를 구현할 때, 사용자와 LLM 간의 대화가 지속적으로 이루어지기 위해서는 "멀티턴"이 필요하다.
이에 대해서 알아보자.


💡 멀티턴이란?

전체 대화의 맥락을 읽고 대화를 주고 받는 것을 멀티턴(Multi-turn)이라 한다.

↔ 이와 다르게 바로 직전의 질문에만 답하는 것은 싱글턴(single-turn)이라 한다.

chat = ChatOpenAI(model="gpt-4o")

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful assistant. Answer all questions to the best of your ability. YOU MUST ANSWER IN KOREAN.",
        ),
        ("placeholder", "{messages}"),
    ]
)

멀티턴을 구현한다는 것은 기본적인 답변 기능에 이전 대화 기록 저장 기능이 추가되는 것이다.

  • 능숙한 답변을 하기 위한 모델에서, 이전 대화를 함께 넘겨줌으로써 대화 맥락을 이해하는 모델이 구성된 것이다.
chain = prompt | chat

위에서 만든 채팅모델(chat)과 프롬프트(prompt)를 버티컬바(|)로 연결해주어, 각 단계가 이전 단계의 결과를 이어받아 처리하도록 한다.

  • 여기서는 (1) 프롬프트를 통해 이전 대화기록이 반영된, 모델에 입력될 메시지가 완성되었다면 → (2) 그것을 채팅모델에 넘겨주는 구성이다.

🎆 Langchain - memory

How to add memory to chatbots | 🦜️🔗 LangChain

A key feature of chatbots is their ability to use content of previous conversation turns as context.

This state management can take several forms, including:

  • Simply stuffing previous messages into a chat model prompt.
  • The above, but trimming old messages to reduce the amount of distracting information the model has to deal with.
  • More complex modifications like synthesizing summaries for long running conversations.

🔊 We can see that by passing the previous conversation into a chain, it can use it as context to answer questions.
This is the basic concept underpinning chatbot memory - the rest of the guide will demonstrate convenient techniques for passing or reformatting messages.

# we want to trim the number of messages passed to the chain to only the 2 most recent ones. 
# count each message as 1 "token" (token_counter=len) and keep only the last two messages
trimmer = trim_messages(strategy="last", max_tokens=2, token_counter=len)

LLMs and chat models have limited context windows, and even if you're not directly hitting limits, you may want to limit the amount of distraction the model has to deal with. One solution is trim the historic messages before passing them to the model.


LLM과의 다단계 대화 (multi-turn conversation) 를 구현하려면 문맥 유지 (context preservation)대화 이력 관리가 핵심이다!
멀티턴은 단순히 질문을 여러 번 던지는 것이 아니라, 과거의 질문과 답변을 기억하고 반영해서 대화를 이어가는 걸 의미한다.


💡 멀티턴 대화의 원리

🎆 1. LLM은 스테이트리스(stateless)

  • LLM 자체는 기본적으로 이전 대화 내용을 기억하지 못한다.
  • 따라서 매 요청 시마다 지금까지의 모든 대화 이력(history) 을 함께 넣어줘야 한다.
  • LLM은 이 이력을 기반으로 다음 응답을 생성한다.

🎆 2. 역할(role) 기반의 메시지 리스트

OpenAI API, LangChain 등에서는 아래처럼 role을 사용한 대화 이력 리스트를 유지함:

[
    {"role": "system", "content": "당신은 친절한 AI 비서입니다."},
    {"role": "user", "content": "오늘 날씨 어때?"},
    {"role": "assistant", "content": "서울은 맑고 28도입니다."},
    {"role": "user", "content": "그럼 반팔 입어도 될까?"}
]

→ LLM은 이 전체 문맥을 보고 마지막 질문에 답변을 생성함


💡 멀티턴 대화 구현 방법 (Python 기준)

✅ Step 1: 대화 이력을 저장할 리스트 만들기

messages = [
    {"role": "system", "content": "당신은 친절한 AI 비서입니다."}
]

✅ Step 2: 사용자 입력 → 대화 이력에 추가

user_input = "오늘 점심 뭐 먹을까?"
messages.append({"role": "user", "content": user_input})

✅ Step 3: OpenAI API 호출 → 응답 추가

from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY")

response = client.chat.completions.create(
    model="gpt-4",
    messages=messages
)
assistant_reply = response.choices[0].message.content
messages.append({"role": "assistant", "content": assistant_reply})

이후 대화에서도 위의 messages 리스트를 계속 업데이트하면서 API를 호출하면 멀티턴이 완성된다!


💡 고려할 점

항목설명
🔁 메시지 길이 제한GPT-4의 토큰 제한(예: 128k context) 안에 모든 대화 이력을 유지해야 함
🧹 이력 정리오래된 대화는 삭제하거나 요약해서 문맥 압축
🧠 기억 기능중요한 정보(예: 유저 이름, 선호도 등)를 따로 저장해서 context에 추가 가능
🤖 LangChain 사용 시ConversationBufferMemory, ConversationSummaryMemory 등으로 상태 관리 자동화 가능

💡 정리: 멀티턴 대화는 어떻게 구현되는가?

구성 요소역할
messages 리스트모든 대화 이력 저장 (user, assistant role 포함)
매 요청 시 context 포함LLM은 과거 대화를 기반으로 다음 응답 생성
토큰 제한 관리오래된 메시지를 정리하거나 요약 필요
고급 구현LangChain, LangGraph 등으로 memory 자동화 가능

사용자와 LLM의 대화가 한 턴씩 이루어질 때마다, 그 내용은 다음처럼 리스트에 계속 추가되고, 그 전체를 LLM에게 다시 보내야 멀티턴 대화가 성립된다!

🧱 구조 요약

🔁 예: 대화가 3턴 이루어졌을 때

messages = [
    {"role": "system", "content": "당신은 친절한 AI 비서입니다."},  # 시스템 프롬프트 (선택적)

    {"role": "user", "content": "안녕?"},                     # 1턴
    {"role": "assistant", "content": "안녕하세요! 무엇을 도와드릴까요?"},

    {"role": "user", "content": "오늘 날씨 어때?"},            # 2턴
    {"role": "assistant", "content": "서울은 맑고 28도입니다."},

    {"role": "user", "content": "그럼 반팔 입어도 될까?"}       # 3턴
]

이걸 OpenAI API에 보내면, LLM은 지금까지의 흐름을 이해한 상태로 "반팔 입어도 될까?" 에 대한 답변을 생성함.

response = client.chat.completions.create(
    model="gpt-4",
    messages=messages
)

💡 왜 이렇게 하냐면...

  • LLM은 기본적으로 "기억 상실증" 😅
    → 이전 턴을 따로 저장하거나 기억하지 않기 때문에,
    문맥을 유지하려면 사람이 직접 모든 이력을 매번 넘겨줘야 한다!

🔄 대화 예시 (실시간 흐름으로 설명)

messages = [
    {"role": "system", "content": "당신은 친절한 AI 비서입니다."}
]

# User 질문 1
user_input = "안녕"
messages.append({"role": "user", "content": user_input})

# → GPT 응답
assistant_reply = "안녕하세요! 무엇을 도와드릴까요?"
messages.append({"role": "assistant", "content": assistant_reply})

# User 질문 2
user_input = "날씨 어때?"
messages.append({"role": "user", "content": user_input})

# → GPT 응답
assistant_reply = "서울은 맑고 28도입니다."
messages.append({"role": "assistant", "content": assistant_reply})

# → messages 전체가 다음 질문에도 계속 쓰임

📌 정리

항목설명
✔️ 리스트에 추가되는 항목{"role": "user", "content": "..."} / {"role": "assistant", "content": "..."}
✔️ 다음 요청 시 사용되는 메시지전체 messages (이전 대화 포함)
✔️ 대화 문맥 유지 방식이전 대화 기록을 계속 누적해서 LLM에 전달
⚠️ 주의할 점토큰 한계가 있으므로 너무 긴 대화는 정리/요약 필요
profile
공부 기록용 24.08.05~ #LLM #RAG

0개의 댓글