Concept #138Mediumextended-ai-concepts

How is conversation history managed without and with LangChain framework?

#gen-ai#agents#langchain

Answer

Conversation History Without and With LangChain

Both approaches maintain conversation context across turns. The difference is abstraction level and feature richness.

Without LangChain (Manual)

Full control, minimal dependencies:

python
from anthropic import Anthropic

client = Anthropic()

# Manual conversation history management
class ChatSession:
    def __init__(self, system_prompt: str = "You are a helpful assistant."):
        self.system = system_prompt
        self.history: list[dict] = []

    def send(self, user_message: str) -> str:
        # Append user message
        self.history.append({"role": "user", "content": user_message})

        # Call API with full history
        response = client.messages.create(
            model="claude-opus-4-6",
            max_tokens=1024,
            system=self.system,
            messages=self.history
        )

        assistant_message = response.content[0].text

        # Append assistant response to history
        self.history.append({"role": "assistant", "content": assistant_message})

        return assistant_message

    def clear(self):
        self.history = []

    def token_estimate(self) -> int:
        return sum(len(m["content"].split()) for m in self.history) * 1.3

# Usage
chat = ChatSession("You are a Python tutor.")
print(chat.send("What is a decorator?"))
print(chat.send("Can you show me an example?"))
print(chat.send("How is that different from a class?"))
# Each call automatically includes full history

With LangChain

Higher-level abstraction with automatic memory management:

python
from langchain_anthropic import ChatAnthropic
from langchain.memory import ConversationSummaryBufferMemory
from langchain.chains import ConversationChain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

llm = ChatAnthropic(model="claude-opus-4-6", max_tokens=1024)

# LangChain handles history automatically + summarizes when needed
memory = ConversationSummaryBufferMemory(
    llm=llm,
    max_token_limit=2000,
    return_messages=True
)

chain = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=False
)

# LangChain manages history injection automatically
response1 = chain.predict(input="What is a decorator in Python?")
response2 = chain.predict(input="Show me an example")
response3 = chain.predict(input="How about a real-world use case?")

# Inspect stored memory
print(memory.chat_memory.messages)

With LangGraph (Most Powerful)

State-based conversation management:

python
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langchain_anthropic import ChatAnthropic
from typing import TypedDict, Annotated
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages

llm = ChatAnthropic(model="claude-opus-4-6")

class State(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]

def chat_node(state: State) -> State:
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

# Build graph with checkpointing (persistent memory)
graph = StateGraph(State)
graph.add_node("chat", chat_node)
graph.add_edge("chat", END)
graph.set_entry_point("chat")

# MemorySaver persists state across invocations
checkpointer = MemorySaver()
app = graph.compile(checkpointer=checkpointer)

# Same thread_id = same conversation history automatically
config = {"configurable": {"thread_id": "user_123"}}

result1 = app.invoke({"messages": [("user", "What is RAG?")]}, config=config)
result2 = app.invoke({"messages": [("user", "Give me a code example")]}, config=config)
# history is automatically maintained across invocations via checkpointer

Comparison

ManualLangChainLangGraph
SetupSimpleMediumComplex
ControlFullLessFull (graph-based)
Memory typesDIYBuilt-inDIY + checkpoints
SummarizationDIYAutoDIY
PersistenceDIYDIYBuilt-in (checkpointer)
Best forSimple chatbotsStandard chainsComplex agents

Token Management Tip

Always monitor token usage to avoid context overflow:

python
# Check before sending
def safe_chat(session: ChatSession, message: str, max_tokens: int = 150000) -> str:
    estimated = session.token_estimate()
    if estimated > max_tokens * 0.8:
        # Summarize or trim history
        session.summarize_old_messages()
    return session.send(message)