"""
Pattern 128: Multi-Turn Dialogue Management
Description:
Manages coherent multi-turn conversations with context tracking, dialogue state,
and appropriate responses across multiple exchanges.
Components:
- Dialogue state tracking
- Context management
- Intent recognition
- Response generation
Use Cases:
- Conversational AI assistants
- Customer service chatbots
- Interactive tutoring systems
LangChain Implementation:
Uses LangChain memory, state management, and conversation chains.
"""
import os
from typing import List, Dict, Any, Optional
from dotenv import load_dotenv
from datetime import datetime
from enum import Enum
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from langchain_core.runnables import RunnablePassthrough
from langchain_core.pydantic_v1 import BaseModel, Field
load_dotenv()
class DialogueState(str, Enum):
"""Dialogue states"""
GREETING = "greeting"
INFO_GATHERING = "info_gathering"
CLARIFICATION = "clarification"
PROCESSING = "processing"
RESPONSE = "response"
CLOSING = "closing"
class UserIntent(BaseModel):
"""Detected user intent"""
intent: str = Field(description="Primary intent")
confidence: float = Field(description="Confidence score")
entities: Dict[str, Any] = Field(description="Extracted entities")
class DialogueContext(BaseModel):
"""Dialogue context"""
state: str = Field(description="Current dialogue state")
topic: Optional[str] = Field(description="Current topic")
user_goal: Optional[str] = Field(description="User's goal")
collected_info: Dict[str, Any] = Field(default_factory=dict)
class MultiTurnDialogueAgent:
"""Agent for managing multi-turn conversations"""
def __init__(self, model: str = "gpt-4o-mini", temperature: float = 0.7):
self.llm = ChatOpenAI(model=model, temperature=temperature)
self.conversation_history: List[Dict[str, str]] = []
self.context: DialogueContext = DialogueContext(
state=DialogueState.GREETING.value,
topic=None,
user_goal=None,
collected_info={}
)
# Intent detection prompt
self.intent_prompt = ChatPromptTemplate.from_messages([
("system", """Analyze the user's message and detect their intent.
Common intents: greeting, question, request_info, provide_info, complaint, thanks, goodbye
Return JSON:
{{
"intent": "intent_name",
"confidence": 0.9,
"entities": {{"key": "value"}}
}}"""),
("user", "{message}")
])
# Response generation with context
self.response_prompt = ChatPromptTemplate.from_messages([
("system", """You are a helpful conversational AI assistant.
Current conversation context:
- State: {state}
- Topic: {topic}
- User Goal: {user_goal}
- Collected Info: {collected_info}
Provide a natural, contextually appropriate response that:
1. Acknowledges the user's message
2. Maintains conversation flow
3. Helps achieve the user's goal
4. Asks follow-up questions if needed"""),
MessagesPlaceholder(variable_name="history"),
("user", "{message}")
])
self.intent_parser = JsonOutputParser()
self.response_parser = StrOutputParser()
def detect_intent(self, message: str) -> UserIntent:
"""Detect user intent from message"""
try:
chain = self.intent_prompt | self.llm | self.intent_parser
result = chain.invoke({"message": message})
return UserIntent(
intent=result["intent"],
confidence=result["confidence"],
entities=result.get("entities", {})
)
except Exception as e:
print(f"Intent detection error: {e}")
return UserIntent(intent="unknown", confidence=0.0, entities={})
def update_context(self, intent: UserIntent, message: str):
"""Update dialogue context based on intent"""
# Update state based on intent
if intent.intent == "greeting":
self.context.state = DialogueState.GREETING.value
elif intent.intent in ["question", "request_info"]:
self.context.state = DialogueState.INFO_GATHERING.value
elif intent.intent == "provide_info":
self.context.state = DialogueState.PROCESSING.value
# Store provided information
self.context.collected_info.update(intent.entities)
elif intent.intent == "goodbye":
self.context.state = DialogueState.CLOSING.value
# Extract topic if not set
if not self.context.topic and len(self.conversation_history) > 0:
# Simple topic extraction (could be enhanced)
for entity_key in intent.entities:
if entity_key not in ["time", "date", "number"]:
self.context.topic = intent.entities[entity_key]
break
def generate_response(self, message: str) -> str:
"""Generate contextually appropriate response"""
# Detect intent
intent = self.detect_intent(message)
print(f"\nšÆ Detected Intent: {intent.intent} (confidence: {intent.confidence:.2f})")
# Update context
self.update_context(intent, message)
print(f"š Dialogue State: {self.context.state}")
if self.context.topic:
print(f"š” Topic: {self.context.topic}")
# Prepare conversation history for prompt
history = []
for turn in self.conversation_history[-5:]: # Last 5 turns
if turn["role"] == "user":
history.append(HumanMessage(content=turn["content"]))
else:
history.append(AIMessage(content=turn["content"]))
# Generate response
chain = self.response_prompt | self.llm | self.response_parser
response = chain.invoke({
"message": message,
"state": self.context.state,
"topic": self.context.topic or "not set",
"user_goal": self.context.user_goal or "not determined",
"collected_info": str(self.context.collected_info),
"history": history
})
return response
def chat(self, user_message: str) -> str:
"""Process user message and return response"""
print(f"\n{'='*60}")
print(f"š¤ User: {user_message}")
# Add to history
self.conversation_history.append({
"role": "user",
"content": user_message,
"timestamp": datetime.now().isoformat()
})
# Generate response
response = self.generate_response(user_message)
# Add response to history
self.conversation_history.append({
"role": "assistant",
"content": response,
"timestamp": datetime.now().isoformat()
})
print(f"š¤ Assistant: {response}")
return response
def get_conversation_summary(self) -> str:
"""Generate summary of conversation"""
if not self.conversation_history:
return "No conversation yet."
summary_prompt = ChatPromptTemplate.from_messages([
("system", "Summarize the following conversation in 2-3 sentences."),
("user", "{conversation}")
])
conversation_text = "\n".join([
f"{turn['role']}: {turn['content']}"
for turn in self.conversation_history
])
chain = summary_prompt | self.llm | StrOutputParser()
summary = chain.invoke({"conversation": conversation_text})
return summary
def reset_conversation(self):
"""Reset conversation state"""
self.conversation_history = []
self.context = DialogueContext(
state=DialogueState.GREETING.value,
topic=None,
user_goal=None,
collected_info={}
)
print("\nš Conversation reset")
def demonstrate_multi_turn_dialogue():
"""Demonstrate multi-turn dialogue management"""
print("=" * 80)
print("Pattern 128: Multi-Turn Dialogue Management")
print("=" * 80)
agent = MultiTurnDialogueAgent()
# Example 1: Customer service conversation
print("\n" + "=" * 80)
print("EXAMPLE 1: Customer Service Conversation")
print("=" * 80)
conversation_1 = [
"Hi, I need help with my order",
"My order number is 12345",
"It was supposed to arrive yesterday but I haven't received it",
"Yes, my address is 123 Main Street",
"Thank you for your help!"
]
for message in conversation_1:
agent.chat(message)
print("\n" + "-" * 60)
print("š Conversation Summary:")
print(agent.get_conversation_summary())
# Example 2: Technical support
print("\n" + "=" * 80)
print("EXAMPLE 2: Technical Support Conversation")
print("=" * 80)
agent.reset_conversation()
conversation_2 = [
"Hello, my computer won't start",
"It's a laptop, about 2 years old",
"When I press the power button, nothing happens at all",
"No, there are no lights or sounds",
"Okay, I'll try that. Thanks!"
]
for message in conversation_2:
agent.chat(message)
print("\n" + "-" * 60)
print("š Conversation Summary:")
print(agent.get_conversation_summary())
# Example 3: Information gathering
print("\n" + "=" * 80)
print("EXAMPLE 3: Information Gathering Conversation")
print("=" * 80)
agent.reset_conversation()
conversation_3 = [
"I want to book a flight",
"From New York to London",
"Next week, preferably Tuesday",
"Economy class is fine",
"Great, please proceed with the booking"
]
for message in conversation_3:
agent.chat(message)
print("\n" + "-" * 60)
print("š Conversation Summary:")
print(agent.get_conversation_summary())
print("\n" + "-" * 60)
print("š Final Context State:")
print(f" State: {agent.context.state}")
print(f" Topic: {agent.context.topic}")
print(f" Collected Info: {agent.context.collected_info}")
print(f" Total Turns: {len(agent.conversation_history)}")
# Summary
print("\n" + "=" * 80)
print("SUMMARY")
print("=" * 80)
print("""
Multi-Turn Dialogue Management Pattern:
- Maintains context across conversation turns
- Tracks dialogue state and user intent
- Generates contextually appropriate responses
- Manages information collection
Key Features:
ā Intent detection
ā State tracking
ā Context maintenance
ā Natural conversation flow
ā Information extraction
Dialogue States:
⢠Greeting - Initial interaction
⢠Info Gathering - Collecting information
⢠Clarification - Resolving ambiguities
⢠Processing - Handling requests
⢠Response - Providing answers
⢠Closing - Ending conversation
Benefits:
ā Coherent multi-turn conversations
ā Context-aware responses
ā Better user experience
ā Goal-oriented dialogue
ā Efficient information gathering
""")
if __name__ == "__main__":
demonstrate_multi_turn_dialogue()
Agentic Design Pattern: Multi Turn Dialogue
Pattern 128: Multi Turn Dialogue – Line-by-Line Explanation
Overview
This document provides a detailed line-by-line explanation of the Multi Turn Dialogue pattern implementation.
Pattern Description
Pattern 128: Multi-Turn Dialogue Management
Description: Manages coherent multi-turn conversations with context tracking, dialogue state, and appropriate responses across multiple exchanges.
Components: – Dialogue state tracking – Context management – Intent recognition – Response generation
Use Cases: – Conversational AI assistants – Customer service chatbots – Interactive tutoring systems
LangChain Implementation: Uses LangChain memory, state management, and conversation chains.
File Statistics
- Total Lines: 357
- Classes: 4
- Functions: 1
- Constants: 0
Module Documentation
"""
Pattern 128: Multi-Turn Dialogue Management
Description:
Manages coherent multi-turn conversations with context tracking, dialogue state,
and appropriate responses across multiple exchanges.
Components:
- Dialogue state tracking
- Context management
- Intent recognition
- Response generation
Use Cases:
- Conversational AI assistants
- Customer service chatbots
- Interactive tutoring systems
LangChain Implementation:
Uses LangChain memory, state management, and conversation chains.
"""
Purpose: This module implements the Multi Turn Dialogue pattern, providing a structured approach to agent design and implementation.
Import Statements
Standard Library Imports
import datetime.datetime
import enum.Enum
import langchain_core.messages.AIMessage
import langchain_core.messages.HumanMessage
import langchain_core.messages.SystemMessage
import langchain_core.output_parsers.JsonOutputParser
import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import langchain_core.prompts.MessagesPlaceholder
import langchain_core.pydantic_v1.BaseModel
import langchain_core.pydantic_v1.Field
import langchain_core.runnables.RunnablePassthrough
import os
import typing.Any
import typing.Dict
import typing.List
import typing.Optional
Purpose: Core Python functionality:
– datetime.datetime: Date and time handling
– enum.Enum: Enumeration support
– langchain_core.messages.AIMessage: Regular expression operations
– langchain_core.messages.HumanMessage: Regular expression operations
– langchain_core.messages.SystemMessage: Regular expression operations
– langchain_core.output_parsers.JsonOutputParser: Regular expression operations
– langchain_core.output_parsers.StrOutputParser: Regular expression operations
– langchain_core.prompts.ChatPromptTemplate: Regular expression operations
– langchain_core.prompts.MessagesPlaceholder: Regular expression operations
– langchain_core.pydantic_v1.BaseModel: Regular expression operations
– langchain_core.pydantic_v1.Field: Regular expression operations
– langchain_core.runnables.RunnablePassthrough: Regular expression operations
– os: Environment variable access and system operations
– typing.Any: Type hints for better code documentation (List, Dict, Any, Optional)
– typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional)
– typing.List: Type hints for better code documentation (List, Dict, Any, Optional)
– typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)
LangChain Imports
from langchain_openai.ChatOpenAI
Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows
Other Imports
from dotenv.load_dotenv
Purpose: Additional dependencies for specialized functionality.
Classes
Class: DialogueState
Lines 39-46
Inherits from: str, Enum
Purpose:
Dialogue states
Class: UserIntent
Lines 49-53
Inherits from: BaseModel
Purpose:
Detected user intent
Class: DialogueContext
Lines 56-61
Inherits from: BaseModel
Purpose:
Dialogue context
Class: MultiTurnDialogueAgent
Lines 64-238
Purpose:
Agent for managing multi-turn conversations
Methods:
__init__(self, model, temperature)
Lines 67-110
Purpose: Initialize the class instance with required parameters.
Parameters:
– model: Language model instance
– temperature: Sampling temperature (0-1)
detect_intent(self, message)
Lines 112-125
Purpose:
Detect user intent from message
Parameters:
– message: Message
Returns: UserIntent
update_context(self, intent, message)
Lines 127-147
Purpose:
Update dialogue context based on intent
Parameters:
– intent: Intent
– message: Message
generate_response(self, message)
Lines 149-181
Purpose:
Generate contextually appropriate response
Parameters:
– message: Message
Returns: str
chat(self, user_message)
Lines 183-207
Purpose:
Process user message and return response
Parameters:
– user_message: User message
Returns: str
get_conversation_summary(self)
Lines 209-227
Purpose:
Generate summary of conversation
Parameters:
Returns: str
reset_conversation(self)
Lines 229-238
Purpose:
Reset conversation state
Parameters:
Functions
demonstrate_multi_turn_dialogue()
Lines 241-352
Purpose:
Demonstrate multi-turn dialogue management
Key Concepts Summary
Pattern Overview
The Multi Turn Dialogue pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.
Core Components
- Agent Class: Main implementation of the pattern logic
- Prompt Engineering: Carefully crafted prompts to guide LLM behavior
- Tool Integration: Optional tools for extended functionality
- Memory Management: State handling across interactions
- Output Parsing: Structured response processing
When to Use
ā Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability
ā Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)
Best Practices Demonstrated
1. Environment Configuration
- ā
Use
.envfiles for API keys - ā Never hardcode credentials
- ā Validate environment variables on startup
2. Error Handling
- ā Graceful degradation on failures
- ā Informative error messages
- ā Logging for debugging
3. Prompt Engineering
- ā Clear, specific instructions
- ā Structured output formats
- ā Few-shot examples when beneficial
4. Code Organization
- ā Separation of concerns (class-based design)
- ā Type hints for clarity
- ā Docstrings for documentation
5. Performance Optimization
- ā Appropriate temperature settings
- ā Token budget management
- ā Caching where applicable
LangChain Components Used
- ChatOpenAI: OpenAI model interface
- Chains: Sequential component composition
Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development
Execution Flow
1. Initialize agent with configuration
ā
2. Load environment and dependencies
ā
3. Prepare prompt with input data
ā
4. Invoke LLM through LangChain
ā
5. Parse and validate response
ā
6. Return formatted result
Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation
Performance Considerations
Computational Cost
- LLM Calls: Primary cost factor (based on tokens)
- Latency: Depends on model and input size
- Memory: Minimal for most patterns
Optimization Strategies
- Prompt Optimization: Minimize tokens while maintaining clarity
- Caching: Cache repeated queries/responses
- Model Selection: Use smaller models when appropriate
- Batch Processing: Group similar requests
- Streaming: For long responses, stream tokens
Cost Estimates (Approximate)
- GPT-3.5-turbo: ~$0.002 per request
- GPT-4: ~$0.03 per request
- GPT-4-turbo: ~$0.01 per request
Actual costs vary based on input/output token counts
Common Pitfalls to Avoid
1. Prompt Design Issues
ā Vague or ambiguous instructions
ā
Clear, specific, testable prompts
2. Error Handling
ā Ignoring API errors or rate limits
ā
Implement retry logic and graceful degradation
3. Token Management
ā Exceeding model token limits
ā
Truncate inputs, chunk processing
4. Security
ā Exposing API keys in code
ā
Use environment variables
5. Testing
ā Only testing happy paths
ā
Test edge cases, failures, malformed inputs
6. Cost Management
ā Unmonitored API usage
ā
Implement budgets, alerts, and monitoring
Further Improvements
Production Enhancements
- Monitoring: Add logging, metrics, tracing
- Validation: Input/output schema validation
- Rate Limiting: Implement request throttling
- Caching: Redis or in-memory cache for responses
- Async Support: Non-blocking operations for scalability
Feature Extensions
- Multi-Model Support: Switch between providers
- Fallback Models: Graceful degradation strategy
- Custom Tools: Domain-specific function calling
- Advanced Memory: Vector stores for long-term memory
- Evaluation: Automated testing and benchmarking
Code Quality
- Testing: Unit tests, integration tests
- Documentation: API docs, usage examples
- Type Safety: Stricter type hints
- Configuration: Externalized config files
Related Patterns
- Pattern 127
- Pattern 129
Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…
Summary
The Multi Turn Dialogue pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:
ā Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns
šÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability
š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/
File: 128_multi_turn_dialogue.py
Total Lines: 357
Pattern Category: AI Agent Design Pattern #128
Generated from actual implementation code
For educational and reference purposes