Implementace kontextu a historie zpráv v lokálním LLM chatu na Pythonu
Konzolový chat založený na LiteLLM a Ollama z předchozí části zpracovává dotazy nezávisle. Model nevidí předchozí repliky, což narušuje dialog: odkazy na minulé odpovědi jsou ignorovány. Řešením je ukládání historie zpráv v Python seznamu a její předávání s každým novým dotazem.
Tím se posloupnost volání mění v souvislou konverzaci. Model získává plný kontext: systémovou instrukci, předchozí páry uživatel/asistent a aktuální vstup.
Struktura zpráv pro kontext
Formát zpráv je standardní pro OpenAI kompatibilní API:
system: trvalá instrukce, přidává se zvlášťuser: dotaz uživateleassistant: odpověď modelu
Historie obsahuje pouze user/assistant. Při odeslání:
[
{"role": "system", "content": SYSTEM_PROMPT},
*conversation_history,
{"role": "user", "content": user_message}
]
Pořadí je klíčové: system nastavuje chování, historie poskytuje kontext, nový user je aktuální dotaz.
Aktualizovaný kód main.py
Úplný skript s historií a ořezáváním kontextu:
# -*- 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 = "Jsi užitečný asistent. Odpovídej stručně a k věci."
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"\nDoba generování: {duration:.2f} sek")
return response.choices[0].message.content
except Exception as e:
print(f"\nChyba při dotazu: {e}")
return None
def main() -> None:
print("Lokální AI asistent s pamětí spuštěn.")
print("Zadejte dotaz nebo 'konec' pro ukončení.\n")
conversation_history = []
while True:
user_input = input("Vy: ").strip()
if user_input.lower() in ("konec", "exit", "quit"):
print("Na shledanou!")
break
if not user_input:
print("Zadejte dotaz.")
continue
print("\nModel přemýšlí...")
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("\nOdpověď se nepodařilo získat. Zkontrolujte, zda je Ollama spuštěna.\n")
if __name__ == "__main__":
main()
Klíčové změny v logice
- conversation_history: seznam v main() ukládá páry zpráv
- send_request_to_llm: přijímá history, rozbalí přes
* - Ukládání párů: po odpovědi se přidají user a assistant
- trim_history: ořízne na MAX_HISTORY_MESSAGES (6 zpráv — 3 dialogy)
| Komponenta | Před aktualizací | Po aktualizaci |
|-----------|---------------|------------------|
| messages | system + user | system + history + user |
| Paměť | Chybí | Seznam v RAM |
| Velikost | Neomezená | Až 6 zpráv |
Ořezávání zabraňuje přetečení kontextu: staré zprávy zvyšují tokeny a zpomalují inference.
Testování kontextu
Dialog se závislými dotazy:
- Vy: Jmenuj tři frameworky pro webový vývoj v Pythonu
- AI: Django, Flask, FastAPI
- Vy: Řekni mi o druhém podrobněji
- AI: Flask — lehký microframework...
Model odkazuje na „druhý“ správně, protože vidí předchozí odpověď.
Omezení současné implementace
- Historie v RAM: ztrácí se po restartu
- Pevný limit: 6 zpráv (lze upravit)
- Žádná perzistence: pro produkci je potřeba Redis/Databáze
Pro Telegram bota nebo webovou aplikaci logika zůstává: history v uživatelské relaci.
Co je důležité
- Formát zpráv: system zvlášť, history pouze user/assistant
- Ořezávání historie: [-limit:] zachová poslední páry
- Rozdělení odpovědnosti: LLM dotazy v send_request_to_llm, stav v main()
- Časové limity: request_timeout=120 pro dlouhé kontexty
- Logování: doba generování pro ladění výkonu
— Editorial Team
Zatím žádné komentáře.