홈으로 돌아가기

Python Ollama LLM 채팅의 메시지 히스토리

이 기사는 Python에서 Ollama와 LiteLLM을 사용한 콘솔 LLM 채팅의 메시지 히스토리 구현을 설명합니다. 트리밍 포함 conversation_history 추가, 전체 메시지 구조. 컨텍스트 포함 코드와 대화 예제 제공.

로컬 LLM 채팅의 컨텍스트: 코드와 예제
Advertisement 728x90

로컬 LLM 채팅에 메시지 기록과 컨텍스트 구현하기: Python 활용

이전 파트의 LiteLLM과 Ollama 기반 콘솔 채팅은 요청을 독립적으로 처리합니다. 모델이 이전 메시지를 볼 수 없어 대화가 끊어지는데, 과거 응답에 대한 참조가 무시됩니다. 해결책은 Python 리스트에 메시지 기록을 저장하고 각 새 요청과 함께 전달하는 것입니다.

이를 통해 일련의 호출이 일관된 대화로 바뀝니다. 모델은 전체 컨텍스트를 받습니다: 시스템 지시, 과거 사용자/어시스턴트 쌍, 현재 입력.

컨텍스트를 위한 메시지 구조

메시지 형식은 OpenAI 호환 API에 표준입니다:

Google AdInline article slot
  • system: 지속적인 지시, 별도로 추가
  • user: 사용자의 질문
  • assistant: 모델의 응답

기록에는 사용자/어시스턴트 쌍만 포함됩니다. 전송 시:

[
    {"role": "system", "content": SYSTEM_PROMPT},
    *conversation_history,
    {"role": "user", "content": user_message}
]

순서가 중요합니다: 시스템은 동작을 설정하고, 기록은 컨텍스트를 제공하며, 새 사용자는 현재 질문입니다.

업데이트된 main.py 코드

기록과 컨텍스트 트리밍이 포함된 전체 스크립트:

Google AdInline article slot
# -*- coding: utf-8 -*-
import time
from typing import Optional
from litellm import completion

MODEL = "ollama_chat/qwen2.5:3b"
API_BASE = "http://localhost:11434"
SYSTEM_PROMPT = "You are a helpful assistant. Respond concisely and to the point."

MAX_HISTORY_MESSAGES = 6


def trim_history(history: list, limit: int) -> list:
    if len(history) <= limit:
        return history
    return history[-limit:]


def send_request_to_llm(user_message: str, history: list) -> Optional[str]:
    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        *history,
        {"role": "user", "content": user_message},
    ]
    try:
        start_time = time.time()
        response = completion(
            model=MODEL,
            messages=messages,
            api_base=API_BASE,
            request_timeout=120,
        )
        duration = time.time() - start_time
        print(f"\nGeneration time: {duration:.2f} sec")
        return response.choices[0].message.content
    except Exception as e:
        print(f"\nRequest error: {e}")
        return None


def main() -> None:
    print("Local AI assistant with memory started.")
    print("Enter a question or 'exit' to quit.\n")

    conversation_history = []

    while True:
        user_input = input("You: ").strip()

        if user_input.lower() in ("exit", "quit"):
            print("Goodbye!")
            break

        if not user_input:
            print("Please enter a question.")
            continue

        print("\nModel thinking...")
        answer = send_request_to_llm(user_input, conversation_history)

        if answer is not None:
            print(f"\nAI: {answer}\n")
            conversation_history.append({"role": "user",      "content": user_input})
            conversation_history.append({"role": "assistant", "content": answer})
            conversation_history = trim_history(conversation_history, MAX_HISTORY_MESSAGES)
        else:
            print("\nFailed to get a response. Check if Ollama is running.\n")


if __name__ == "__main__":
    main()

주요 논리 변경 사항

  • conversation_history: main()의 리스트가 메시지 쌍 저장
  • send_request_to_llm: 기록을 받아 *로 확장
  • 쌍 저장: 응답 후 사용자와 어시스턴트 추가
  • trim_history: MAX_HISTORY_MESSAGES(6개 항목 — 3개 대화)로 트리밍

| 구성 요소 | 업데이트 전 | 업데이트 후 |

|-----------|---------------|--------------|

| messages | system + user | system + history + user |

Google AdInline article slot

| 메모리 | 없음 | RAM의 리스트 |

| 크기 | 무제한 | 최대 6개 메시지 |

트리밍은 컨텍스트 오버플로를 방지합니다: 오래된 메시지는 토큰을 증가시키고 추론을 느리게 합니다.

컨텍스트 테스트

종속적 질문이 있는 대화:

  • 사용자: Python 웹 개발 프레임워크 세 가지 이름을 알려주세요
  • AI: Django, Flask, FastAPI
  • 사용자: 두 번째에 대해 더 자세히 알려주세요
  • AI: Flask는 가벼운 마이크로프레임워크입니다...

모델이 이전 응답을 보고 "두 번째"를 올바르게 참조합니다.

현재 구현의 한계

  • RAM의 기록: 재시작 시 손실
  • 고정 제한: 6개 메시지(구성 가능)
  • 지속성 없음: 프로덕션에는 Redis/DB 필요

텔레그램 봇이나 웹 앱의 경우 논리는 동일합니다: 사용자 세션의 기록.

중요한 점

  • 메시지 형식: 시스템은 별도, 기록은 사용자/어시스턴트만
  • 기록 트리밍: [-limit:]로 최근 쌍 보존
  • 책임 분리: LLM 요청은 send_request_to_llm, 상태는 main()
  • 타임아웃: 긴 컨텍스트를 위한 request_timeout=120
  • 로깅: 성능 디버깅을 위한 생성 시간

— Editorial Team

Advertisement 728x90

다음 읽기