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:
pythonfrom 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:
pythonfrom 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:
pythonfrom 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
| Manual | LangChain | LangGraph | |
|---|---|---|---|
| Setup | Simple | Medium | Complex |
| Control | Full | Less | Full (graph-based) |
| Memory types | DIY | Built-in | DIY + checkpoints |
| Summarization | DIY | Auto | DIY |
| Persistence | DIY | DIY | Built-in (checkpointer) |
| Best for | Simple chatbots | Standard chains | Complex 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)