Einem LangChain-Chatbot mit Messages einen Gesprächsverlauf geben
Bauen Sie einen einfachen Chatbot, indem Sie frühere Nachrichten per MessagesPlaceholder an das Modell zurückgeben, und sehen Sie, warum Verlauf nicht dasselbe ist wie eingebautes Modellgedächtnis.
Bisher stand jeder Modellaufruf für sich. Frage stellen, Antwort bekommen, und der nächste Aufruf beginnt bei null. Damit etwas entsteht, das sich wie ein echter Chatbot verhält, muss man sich zuerst darum kümmern.
Hier sind zwei Aufrufe direkt hintereinander:
model.invoke("What is Python?")
model.invoke("What is it used for?")
Der zweite hat keine Ahnung, dass es um Python ging. Das Modell sieht nur, was in den Nachrichten steht, die Sie ihm schicken, also muss der vorherige Austausch mitgeschickt werden.
Die Grundidee
Ein Gespräch ist eine Liste von Beiträgen. Der erste:
Human → What is Python?
AI → Python is a programming language.
Und die Nachfrage:
Human → What is it used for?
AI → Python is used for web development, AI, automation...
Damit das Modell die zweite Frage versteht, schicken Sie die früheren Beiträge in der richtigen Reihenfolge mit:
SystemMessage
HumanMessage
AIMessage
HumanMessage
Deshalb ist AIMessage so wichtig. Auf diesem Weg gelangen die früheren Antworten des Modells zurück in den Prompt.
Zuerst ein Gespräch von Hand
Es lohnt sich, das erst manuell zu machen, bevor man Hilfsmittel hinzufügt. Das Beispiel unten nutzt Ollama, läuft also gegen ein lokales Modell und braucht kein API-Kontingent.
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
model = ChatOllama(model="llama3.2")
prompt = ChatPromptTemplate.from_messages([
(
"system",
"You are a helpful teacher."
),
MessagesPlaceholder(variable_name="history"),
(
"human",
"{question}"
)
])
chain = prompt | model
history = []
def chat(question):
response = chain.invoke({
"history": history,
"question": question
})
history.append(HumanMessage(content=question))
history.append(AIMessage(content=response.content))
return response.content
print(chat("What is Python?"))
print(chat("What is it used for?"))
print(chat("Can you give me three examples?"))
Sehen Sie sich diese Zeile genau an:
messages.append(response)
Sie legt die Antwort des Modells zurück ins Gespräch. Danach enthält die Liste die Systemnachricht, die erste Frage, die erste Antwort und die Nachfrage:
SystemMessage
HumanMessage("What is Python?")
AIMessage("Python is...")
HumanMessage("What is it used for?")
Bei diesem Aufruf sieht das Modell also den ganzen Verlauf:
model.invoke(messages)
Warum das funktioniert
Stellen Sie sich vor, Sie würden nur das hier senden:
HumanMessage(content="What is it used for?")
Nichts sagt dem Modell, worauf sich "it" bezieht. Mit dem angehängten Verlauf liest es stattdessen Folgendes:
Human: What is Python?
AI: Python is a programming language.
Human: What is it used for?
Jetzt kann es das Pronomen auflösen:
"it" = Python
Verlauf ist schlicht Kontext, den man dem Modell übergibt.
LangChain gibt dem Modell kein Gedächtnis
Dieser Punkt wird leicht übersehen. LangChain zu verwenden bringt ein Modell nicht dazu, sich an irgendetwas zu erinnern. Das Modell erhält in der Regel nur die Nachrichten, die Sie für diese eine Interaktion übergeben. Grob gesagt:
Your application
↓
Conversation history
↓
Messages
↓
Model
Der Gesprächszustand gehört Ihrer Anwendung. Behalten Sie das im Kopf, denn es wird sehr wichtig, sobald Sie bei State-Management und LangGraph ankommen.
Ein Prompt-Template hinzufügen
Der Verlauf lässt sich gut mit den Prompt-Templates aus früheren Lektionen kombinieren. Beginnen Sie mit den Imports:
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
Dann definieren Sie den Prompt:
prompt = ChatPromptTemplate.from_messages([
(
"system",
"You are a helpful Python teacher."
),
MessagesPlaceholder(variable_name="history"),
(
"human",
"{question}"
)
])
Die entscheidende Zeile ist diese:
MessagesPlaceholder(variable_name="history")
Lesen Sie sie als "hier die früheren Nachrichten einfügen".
Die Chain bauen
Leiten Sie den Prompt per Pipe in das Modell:
chain = prompt | model
Beginnen Sie mit einer leeren Verlaufsliste:
history = []
Machen Sie den ersten Aufruf und geben Sie die Antwort aus:
response = chain.invoke({
"history": history,
"question": "What is Python?"
})print(response.content)
Speichern Sie dann beide Seiten des Austauschs, zuerst die Nachricht des Nutzers
history.append(
HumanMessage(content="What is Python?")
)
und dann die Antwort des Modells:
history.append(response)
Stellen Sie nun die Nachfrage:
response = chain.invoke({
"history": history,
"question": "What is it used for?"
})
print(response.content)
Was das Modell tatsächlich erhält, sieht ungefähr so aus, beginnend mit der Systemanweisung:
System:
You are a helpful Python teacher.
gefolgt vom bisherigen Gespräch:
Human:
What is Python?AI:
Python is a programming language.Human:
What is it used for?
Als Chatbot verpacken
All das passt in eine einzige Funktion:
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
model = ChatOllama(model="llama3.2")
prompt = ChatPromptTemplate.from_messages([
(
"system",
"You are a helpful teacher."
),
MessagesPlaceholder(variable_name="history"),
(
"human",
"{question}"
)
])
chain = prompt | model
history = []
def chat(question):
response = chain.invoke({
"history": history,
"question": question
})
history.append(HumanMessage(content=question))
history.append(AIMessage(content=response.content))
return response.content
print(chat("What is Python?"))
print(chat("What is it used for?"))
print(chat("Can you give me three examples?"))
Damit haben Sie eine minimalistische Konversations-App.
Ein Detail zur Reihenfolge
Die Nachricht des Nutzers kommt nach dem Modellaufruf in den Verlauf, nicht davor:
response = chain.invoke(...)
history.append(HumanMessage(content=question))
history.append(AIMessage(content=response.content))
Der Grund: Der Prompt nimmt die aktuelle Frage bereits als eigene Eingabe entgegen:
"question": question
also würde sie doppelt auftauchen, wenn man sie zusätzlich zu history hinzufügt. Man kann es auch andersherum machen, alles in den Verlauf legen und dem Modell nur den Verlauf übergeben. Beide Designs funktionieren. Achten Sie nur darauf, dass die aktuelle Nachricht nicht zweimal erscheint.
Verlauf versus Gedächtnis
Ältere LangChain-Tutorials reden viel von „Gedächtnis“ ("memory."). Gehen Sie nicht davon aus, dass beides immer dasselbe ist:
history = memory
Auf der hier behandelten Ebene bedeutet Verlauf einfach die Nachrichten aus früheren Beiträgen:
History = messages from previous turns
Leistungsfähigerer Umgang mit Zustand kommt später, wenn eine Anwendung den Gesprächszustand über mehrere Schritte hinweg speichert und aktualisiert. Merken Sie sich vorerst diesen Ablauf:
Conversation history
↓
Previous messages
↓
Model gets context
Die resultierende Architektur
Der gebaute Chatbot funktioniert so: Die Anwendung speichert den Verlauf, speist ihn in den Prompt ein, und das Modell antwortet auf dieser Grundlage.
Warum das in echten Apps zählt
Dieselbe Idee steckt hinter vielen Produkten:
Customer support chatbot
AI tutor
Personal assistant
HR assistant
Coding assistant
Sales assistant
Nehmen wir einen einfachen Austausch, in dem sich der Nutzer vorstellt:
User: My name is Wasim.
Fragt die nächste Frage nach seinem Namen, kann das Modell korrekt antworten, weil die früheren Beiträge als Kontext mitgegeben wurden:
AI: Nice to meet you, Wasim.User: What is my name?AI: Your name is Wasim.
Ihr mentales Modell bis hierhin
Sie haben diese Bausteine abgedeckt, vom nackten Modellaufruf bis zur Chain mit Verlauf:
1. Model
↓
invoke()2. Messages
↓
System / Human / AI
3. Prompt Templates
↓
{variables}
4. Structured Output
↓
predictable data
5. Chains
↓
prompt | model | parser
6. Conversation History
↓
previous messages → context
Wie es weitergeht
Das nächste Thema sind Tools und Tool Calling. Dort beginnt ein LLM, Dinge außerhalb des Modells selbst zu tun, auf diesem Weg:
User
↓
LLM
↓
"I need a calculation"
↓
Python tool
↓
Result
↓
LLM
↓
Final answer
Das ist die Grundlage, um Agenten zu verstehen.