Chatbot Recipe¶
Build intelligent, context-aware chatbots with OpenDXA
Overview¶
This recipe demonstrates how to build sophisticated chatbots using OpenDXA. Learn to create conversational agents that maintain context, handle complex queries, and provide intelligent responses across various domains.
What You'll Build¶
A comprehensive chatbot system that can: - Understand context and maintain conversation history - Handle complex multi-turn conversations - Access external knowledge sources and APIs - Provide domain-specific expertise - Learn from interactions and improve over time
Quick Start¶
Basic Chatbot¶
# Configure chatbot resources
llm = create_llm_resource(provider="openai", model="gpt-4")
memory = create_memory_resource()
kb = create_kb_resource()
# Simple chatbot function
def simple_chatbot(user_message, conversation_id=None):
"""Basic chatbot with context awareness."""
# Get conversation history
if conversation_id:
history = memory.get_conversation(conversation_id)
else:
history = []
conversation_id = generate_conversation_id()
# Generate response with context
response = reason(f"""
You are a helpful assistant. Respond to the user's message considering the conversation history.
Conversation history:
{format_conversation_history(history)}
User message: {user_message}
Provide a helpful, relevant response.
""")
# Store interaction in memory
memory.store_interaction(conversation_id, {
"user_message": user_message,
"bot_response": response,
"timestamp": get_current_time()
})
log(f"Chatbot response for {conversation_id}: {response[:100]}...", level="INFO")
return {
"response": response,
"conversation_id": conversation_id,
"timestamp": get_current_time()
}
# Use the basic chatbot
response = simple_chatbot("Hello, can you help me with Python programming?")
print(f"Bot: {response['response']}")
# Continue conversation
follow_up = simple_chatbot(
"What are the best practices for error handling?",
response['conversation_id']
)
print(f"Bot: {follow_up['response']}")
Advanced Chatbot System¶
# Advanced chatbot with multiple capabilities
class IntelligentChatbot:
def __init__(self, config=None):
self.config = config or self.get_default_config()
self.llm = create_llm_resource(**self.config["llm"])
self.memory = create_memory_resource(**self.config["memory"])
self.kb = create_kb_resource(**self.config["knowledge_base"])
self.conversation_contexts = {}
self.user_profiles = {}
def get_default_config(self):
"""Get default chatbot configuration."""
return {
"llm": {
"provider": "openai",
"model": "gpt-4",
"temperature": 0.7,
"max_tokens": 1000
},
"memory": {
"max_history_length": 20,
"context_window": 10
},
"knowledge_base": {
"max_search_results": 5,
"relevance_threshold": 0.7
},
"personality": {
"tone": "helpful and professional",
"expertise_domains": ["general", "technology", "business"],
"response_style": "concise yet comprehensive"
}
}
def process_message(self, user_message, user_id, conversation_id=None):
"""Process user message with full context analysis."""
# Initialize or get conversation context
if conversation_id is None:
conversation_id = self.start_new_conversation(user_id)
context = self.get_conversation_context(conversation_id)
# Analyze user intent
intent_analysis = self.analyze_user_intent(user_message, context)
# Route to appropriate handler based on intent
if intent_analysis["type"] == "question":
response = self.handle_question(user_message, context, intent_analysis)
elif intent_analysis["type"] == "request":
response = self.handle_request(user_message, context, intent_analysis)
elif intent_analysis["type"] == "casual_conversation":
response = self.handle_casual_conversation(user_message, context)
else:
response = self.handle_general_query(user_message, context)
# Update conversation context
self.update_conversation_context(
conversation_id,
user_message,
response,
intent_analysis
)
return {
"response": response["text"],
"confidence": response["confidence"],
"intent": intent_analysis,
"conversation_id": conversation_id,
"suggestions": response.get("suggestions", [])
}
def analyze_user_intent(self, message, context):
"""Analyze user intent using conversation context."""
intent_analysis = reason(f"""
Analyze the user's intent based on their message and conversation context:
User message: {message}
Conversation context: {context}
Determine:
1. Intent type (question, request, casual_conversation, complaint, compliment, etc.)
2. Subject domain (technology, business, personal, etc.)
3. Urgency level (low, medium, high)
4. Required information type (factual, procedural, creative, etc.)
5. Expected response format (brief, detailed, step-by-step, etc.)
Return structured analysis.
""")
return intent_analysis
def handle_question(self, message, context, intent_analysis):
"""Handle question-type queries with knowledge base integration."""
# Search knowledge base for relevant information
kb_results = self.kb.search(
message,
limit=self.config["knowledge_base"]["max_search_results"]
)
# Filter results by relevance
relevant_results = [
result for result in kb_results
if result["relevance"] >= self.config["knowledge_base"]["relevance_threshold"]
]
# Generate response using knowledge and context
response = reason(f"""
Answer the user's question using available knowledge and conversation context:
Question: {message}
Context: {context}
Intent analysis: {intent_analysis}
Knowledge base results: {relevant_results}
Provide a comprehensive answer that:
1. Directly addresses the question
2. Uses relevant knowledge from the knowledge base
3. Considers the conversation context
4. Matches the expected response format
5. Includes confidence level
If the question cannot be fully answered, acknowledge limitations and suggest alternatives.
""")
return {
"text": response["answer"],
"confidence": response["confidence"],
"sources": relevant_results,
"suggestions": response.get("follow_up_questions", [])
}
def handle_request(self, message, context, intent_analysis):
"""Handle action requests and task-oriented queries."""
# Analyze what action is being requested
action_analysis = reason(f"""
Analyze the user's request to determine required actions:
Request: {message}
Context: {context}
Intent: {intent_analysis}
Determine:
1. Specific actions requested
2. Required parameters or information
3. Prerequisites or dependencies
4. Expected deliverables
5. Feasibility assessment
""")
# Execute appropriate actions
if action_analysis["feasible"]:
action_result = self.execute_requested_action(action_analysis)
response_text = reason(f"""
Provide a response about the completed action:
Original request: {message}
Action performed: {action_analysis["actions"]}
Result: {action_result}
Summarize what was done and provide any relevant next steps.
""")
else:
response_text = reason(f"""
Explain why the request cannot be fulfilled:
Request: {message}
Analysis: {action_analysis}
Provide explanation and suggest alternatives if possible.
""")
return {
"text": response_text,
"confidence": 0.9 if action_analysis["feasible"] else 0.7,
"action_performed": action_analysis["feasible"],
"suggestions": action_analysis.get("alternatives", [])
}
def handle_casual_conversation(self, message, context):
"""Handle casual, social conversation."""
response = reason(f"""
Engage in casual conversation with the user:
User message: {message}
Conversation context: {context}
Personality: {self.config["personality"]}
Respond in a way that is:
1. Friendly and engaging
2. Appropriate to the conversation tone
3. Consistent with the chatbot personality
4. Encouraging continued conversation
""")
return {
"text": response,
"confidence": 0.8,
"conversation_type": "casual"
}
def execute_requested_action(self, action_analysis):
"""Execute actions requested by the user."""
actions = action_analysis["actions"]
results = []
for action in actions:
if action["type"] == "search":
result = self.perform_search(action["parameters"])
elif action["type"] == "calculation":
result = self.perform_calculation(action["parameters"])
elif action["type"] == "analysis":
result = self.perform_analysis(action["parameters"])
elif action["type"] == "generation":
result = self.generate_content(action["parameters"])
else:
result = {"error": f"Unknown action type: {action['type']}"}
results.append(result)
return results
def get_conversation_context(self, conversation_id):
"""Get comprehensive conversation context."""
if conversation_id not in self.conversation_contexts:
return {"history": [], "topics": [], "user_preferences": {}}
context = self.conversation_contexts[conversation_id]
# Analyze context for patterns and insights
context_analysis = reason(f"""
Analyze this conversation context for insights:
{context}
Identify:
1. Main topics discussed
2. User preferences and interests
3. Communication style
4. Knowledge level in various domains
5. Current conversation thread
""")
return {
"history": context["history"][-self.config["memory"]["context_window"]:],
"topics": context_analysis.get("topics", []),
"user_preferences": context_analysis.get("preferences", {}),
"communication_style": context_analysis.get("style", {}),
"current_thread": context_analysis.get("current_thread", "")
}
def update_conversation_context(self, conversation_id, user_message, response, intent_analysis):
"""Update conversation context with new interaction."""
if conversation_id not in self.conversation_contexts:
self.conversation_contexts[conversation_id] = {
"history": [],
"start_time": get_current_time()
}
context = self.conversation_contexts[conversation_id]
# Add interaction to history
interaction = {
"user_message": user_message,
"bot_response": response["text"],
"intent": intent_analysis,
"timestamp": get_current_time()
}
context["history"].append(interaction)
# Maintain history length limit
max_length = self.config["memory"]["max_history_length"]
if len(context["history"]) > max_length:
context["history"] = context["history"][-max_length:]
# Store in persistent memory
self.memory.store_conversation_update(conversation_id, interaction)
def start_new_conversation(self, user_id):
"""Start a new conversation and return conversation ID."""
conversation_id = generate_conversation_id()
# Initialize conversation context
self.conversation_contexts[conversation_id] = {
"user_id": user_id,
"history": [],
"start_time": get_current_time()
}
# Get user profile if available
if user_id in self.user_profiles:
self.conversation_contexts[conversation_id]["user_profile"] = self.user_profiles[user_id]
log(f"Started new conversation {conversation_id} for user {user_id}", level="INFO")
return conversation_id
# Create chatbot instance
chatbot = IntelligentChatbot({
"personality": {
"tone": "friendly and knowledgeable",
"expertise_domains": ["technology", "programming", "business"],
"response_style": "detailed with examples"
}
})
📋 Implementation Steps¶
Step 1: Conversation Management¶
# Sophisticated conversation management
def implement_conversation_management():
"""Implement advanced conversation management features."""
class ConversationManager:
def __init__(self):
self.active_conversations = {}
self.conversation_summaries = {}
self.user_session_data = {}
def manage_conversation_flow(self, conversation_id, message_data):
"""Manage conversation flow and transitions."""
current_state = self.get_conversation_state(conversation_id)
# Analyze conversation flow
flow_analysis = reason(f"""
Analyze conversation flow and determine next steps:
Current state: {current_state}
New message: {message_data}
Consider:
1. Conversation continuity
2. Topic transitions
3. User engagement level
4. Completion status of current topics
5. Need for clarification or follow-up
""")
# Update conversation state
new_state = self.update_conversation_state(
conversation_id,
flow_analysis,
message_data
)
return new_state
def handle_conversation_interruption(self, conversation_id, interruption_type):
"""Handle conversation interruptions gracefully."""
if interruption_type == "topic_change":
return self.handle_topic_change(conversation_id)
elif interruption_type == "clarification_request":
return self.handle_clarification_request(conversation_id)
elif interruption_type == "session_timeout":
return self.handle_session_timeout(conversation_id)
else:
return self.handle_general_interruption(conversation_id, interruption_type)
def summarize_conversation(self, conversation_id):
"""Generate intelligent conversation summary."""
conversation_data = self.active_conversations[conversation_id]
summary = reason(f"""
Create a comprehensive conversation summary:
{conversation_data}
Include:
1. Main topics discussed
2. Key information exchanged
3. Decisions made or actions agreed upon
4. Outstanding questions or tasks
5. User satisfaction indicators
""")
self.conversation_summaries[conversation_id] = summary
return summary
def detect_conversation_patterns(self, user_id):
"""Detect patterns in user's conversation behavior."""
user_conversations = self.get_user_conversations(user_id)
patterns = reason(f"""
Analyze conversation patterns for this user:
{user_conversations}
Identify:
1. Preferred communication style
2. Common topics of interest
3. Question patterns and complexity
4. Response preferences
5. Engagement patterns
""")
return patterns
return ConversationManager()
Step 2: Domain-Specific Expertise¶
# Domain-specific chatbot capabilities
def add_domain_expertise(chatbot, domain_config):
"""Add domain-specific expertise to chatbot."""
def create_domain_expert(domain_name, expertise_config):
"""Create domain-specific expert module."""
return {
"name": domain_name,
"knowledge_base": load_domain_knowledge(expertise_config["knowledge_source"]),
"specialized_functions": load_domain_functions(expertise_config["functions"]),
"response_templates": load_response_templates(expertise_config["templates"]),
"validation_rules": expertise_config["validation_rules"]
}
def handle_domain_specific_query(query, domain, context):
"""Handle queries requiring domain expertise."""
domain_expert = chatbot.domain_experts[domain]
# Search domain knowledge
domain_knowledge = domain_expert["knowledge_base"].search(query)
# Apply domain-specific processing
if domain == "medical":
response = handle_medical_query(query, domain_knowledge, context)
elif domain == "legal":
response = handle_legal_query(query, domain_knowledge, context)
elif domain == "technical":
response = handle_technical_query(query, domain_knowledge, context)
elif domain == "financial":
response = handle_financial_query(query, domain_knowledge, context)
else:
response = handle_general_domain_query(query, domain_knowledge, context)
# Apply domain validation rules
validated_response = apply_domain_validation(response, domain_expert["validation_rules"])
return validated_response
def handle_medical_query(query, knowledge, context):
"""Handle medical domain queries with appropriate disclaimers."""
response = reason(f"""
Provide medical information response:
Query: {query}
Medical knowledge: {knowledge}
Context: {context}
Important: Include appropriate medical disclaimers and recommendations to consult healthcare professionals.
""")
# Add required disclaimers
response["disclaimers"] = [
"This information is for educational purposes only",
"Always consult with a qualified healthcare professional",
"This does not constitute medical advice"
]
return response
def handle_technical_query(query, knowledge, context):
"""Handle technical domain queries with examples and best practices."""
response = reason(f"""
Provide technical response with examples:
Query: {query}
Technical knowledge: {knowledge}
Context: {context}
Include:
1. Clear technical explanation
2. Code examples if applicable
3. Best practices
4. Common pitfalls to avoid
5. Related concepts
""")
return response
# Initialize domain experts
chatbot.domain_experts = {}
for domain_name, config in domain_config.items():
chatbot.domain_experts[domain_name] = create_domain_expert(domain_name, config)
# Attach domain handling methods
chatbot.handle_domain_query = handle_domain_specific_query
return chatbot
Step 3: Multi-Modal Capabilities¶
# Multi-modal chatbot capabilities
def add_multimodal_capabilities(chatbot):
"""Add support for images, files, and other media types."""
def process_image_message(image_data, text_message, context):
"""Process messages containing images."""
# Analyze image content
image_analysis = reason(f"""
Analyze this image in context of the user's message:
Image: {image_data}
User message: {text_message}
Conversation context: {context}
Describe what you see and how it relates to the user's query.
""")
# Generate response combining image and text
response = reason(f"""
Respond to the user considering both image and text:
Image analysis: {image_analysis}
Text message: {text_message}
Context: {context}
Provide helpful response that addresses both visual and textual elements.
""")
return {
"response": response,
"image_analysis": image_analysis,
"media_type": "image"
}
def process_file_upload(file_data, file_type, message, context):
"""Process uploaded files with content analysis."""
if file_type == "pdf":
content = extract_pdf_content(file_data)
elif file_type in ["doc", "docx"]:
content = extract_document_content(file_data)
elif file_type == "csv":
content = analyze_csv_data(file_data)
else:
content = {"error": f"Unsupported file type: {file_type}"}
if "error" not in content:
# Analyze file content
file_analysis = reason(f"""
Analyze this file content in context of user's message:
File content: {content}
User message: {message}
Context: {context}
Provide insights and answer any questions about the file.
""")
return {
"response": file_analysis,
"file_content": content,
"media_type": file_type
}
else:
return content
def handle_voice_message(voice_data, context):
"""Process voice messages with speech-to-text and sentiment analysis."""
# Convert speech to text
transcribed_text = transcribe_speech(voice_data)
# Analyze voice sentiment and tone
voice_analysis = reason(f"""
Analyze the voice message for sentiment and tone:
Transcribed text: {transcribed_text}
Voice characteristics: {analyze_voice_characteristics(voice_data)}
Determine emotional tone and adjust response accordingly.
""")
# Process as text message with voice context
response = chatbot.process_message(
transcribed_text,
context["user_id"],
context["conversation_id"]
)
# Adjust response based on voice tone
response["voice_context"] = voice_analysis
return response
# Attach multimodal handlers
chatbot.process_image = process_image_message
chatbot.process_file = process_file_upload
chatbot.process_voice = handle_voice_message
return chatbot
Step 4: Learning and Improvement¶
# Continuous learning and improvement
def implement_learning_system(chatbot):
"""Implement system for continuous learning and improvement."""
class ChatbotLearningSystem:
def __init__(self):
self.interaction_logs = []
self.feedback_data = []
self.performance_metrics = {}
self.learning_insights = {}
def log_interaction(self, interaction_data):
"""Log interaction for learning analysis."""
enhanced_interaction = {
**interaction_data,
"timestamp": get_current_time(),
"session_id": interaction_data.get("conversation_id"),
"response_quality": None # To be filled by feedback
}
self.interaction_logs.append(enhanced_interaction)
def process_user_feedback(self, conversation_id, feedback):
"""Process user feedback for learning."""
feedback_entry = {
"conversation_id": conversation_id,
"feedback": feedback,
"timestamp": get_current_time()
}
self.feedback_data.append(feedback_entry)
# Analyze feedback for improvement opportunities
improvement_analysis = reason(f"""
Analyze this user feedback for learning opportunities:
Feedback: {feedback}
Conversation context: {self.get_conversation_context(conversation_id)}
Identify:
1. Specific improvement areas
2. Response quality issues
3. Knowledge gaps
4. User preference insights
5. Suggested optimizations
""")
self.apply_learning_insights(improvement_analysis)
def analyze_performance_patterns(self, time_period="last_week"):
"""Analyze chatbot performance patterns."""
recent_interactions = self.filter_interactions_by_time(time_period)
pattern_analysis = reason(f"""
Analyze chatbot performance patterns:
Interactions: {recent_interactions}
Feedback data: {self.feedback_data}
Identify:
1. Common success patterns
2. Frequent failure modes
3. User satisfaction trends
4. Knowledge gap areas
5. Response time patterns
""")
self.performance_metrics[time_period] = pattern_analysis
return pattern_analysis
def generate_improvement_recommendations(self):
"""Generate specific improvement recommendations."""
all_insights = {
"interaction_patterns": self.learning_insights,
"feedback_analysis": self.feedback_data,
"performance_metrics": self.performance_metrics
}
recommendations = reason(f"""
Generate specific improvement recommendations:
Learning insights: {all_insights}
Provide:
1. Priority improvement areas
2. Specific implementation suggestions
3. Expected impact assessment
4. Resource requirements
5. Success metrics
""")
return recommendations
def apply_learning_insights(self, insights):
"""Apply learning insights to improve chatbot performance."""
for insight in insights["actionable_insights"]:
if insight["type"] == "knowledge_gap":
self.address_knowledge_gap(insight)
elif insight["type"] == "response_pattern":
self.improve_response_pattern(insight)
elif insight["type"] == "user_preference":
self.update_user_preferences(insight)
def address_knowledge_gap(self, gap_insight):
"""Address identified knowledge gaps."""
gap_topic = gap_insight["topic"]
# Search for additional knowledge sources
additional_knowledge = search_knowledge_sources(gap_topic)
# Update knowledge base
chatbot.kb.add_knowledge(gap_topic, additional_knowledge)
log(f"Added knowledge for topic: {gap_topic}", level="INFO")
def improve_response_pattern(self, pattern_insight):
"""Improve response patterns based on insights."""
pattern_type = pattern_insight["pattern_type"]
improvement = pattern_insight["improvement"]
# Update response generation logic
if pattern_type == "tone_adjustment":
chatbot.config["personality"]["tone"] = improvement["new_tone"]
elif pattern_type == "detail_level":
chatbot.config["response_style"] = improvement["new_style"]
log(f"Updated response pattern: {pattern_type}", level="INFO")
# Initialize learning system
learning_system = ChatbotLearningSystem()
# Attach to chatbot
chatbot.learning_system = learning_system
# Override process_message to include logging
original_process_message = chatbot.process_message
def enhanced_process_message(user_message, user_id, conversation_id=None):
result = original_process_message(user_message, user_id, conversation_id)
# Log interaction for learning
learning_system.log_interaction({
"user_message": user_message,
"bot_response": result["response"],
"user_id": user_id,
"conversation_id": result["conversation_id"],
"intent": result["intent"]
})
return result
chatbot.process_message = enhanced_process_message
return chatbot
Advanced Features¶
Contextual Memory System¶
# Advanced contextual memory
def implement_contextual_memory(chatbot):
"""Implement sophisticated contextual memory system."""
class ContextualMemory:
def __init__(self):
self.short_term_memory = {} # Current conversation
self.long_term_memory = {} # Cross-conversation patterns
self.semantic_memory = {} # Conceptual relationships
self.episodic_memory = {} # Specific interaction episodes
def store_contextual_information(self, context_data):
"""Store information in appropriate memory systems."""
# Analyze context importance and type
memory_analysis = reason(f"""
Analyze this context for memory storage:
{context_data}
Determine:
1. Memory type (short-term, long-term, semantic, episodic)
2. Importance level (low, medium, high)
3. Retention duration
4. Relationships to existing memories
""")
# Store in appropriate memory system
if memory_analysis["type"] == "short_term":
self.store_short_term(context_data, memory_analysis)
elif memory_analysis["type"] == "long_term":
self.store_long_term(context_data, memory_analysis)
elif memory_analysis["type"] == "semantic":
self.store_semantic(context_data, memory_analysis)
elif memory_analysis["type"] == "episodic":
self.store_episodic(context_data, memory_analysis)
def retrieve_relevant_context(self, query, conversation_id):
"""Retrieve relevant context for current query."""
# Search all memory systems
relevant_context = {
"short_term": self.search_short_term(query, conversation_id),
"long_term": self.search_long_term(query),
"semantic": self.search_semantic(query),
"episodic": self.search_episodic(query)
}
# Synthesize relevant information
synthesized_context = reason(f"""
Synthesize relevant context from memory systems:
{relevant_context}
For query: {query}
Provide consolidated, relevant context information.
""")
return synthesized_context
# Attach contextual memory to chatbot
chatbot.contextual_memory = ContextualMemory()
return chatbot
Real-time Analytics¶
# Real-time chatbot analytics
def implement_realtime_analytics(chatbot):
"""Implement real-time analytics and monitoring."""
def track_conversation_metrics(conversation_data):
"""Track detailed conversation metrics."""
metrics = {
"response_time": calculate_response_time(conversation_data),
"user_satisfaction": estimate_user_satisfaction(conversation_data),
"conversation_length": len(conversation_data["history"]),
"topic_diversity": calculate_topic_diversity(conversation_data),
"resolution_rate": calculate_resolution_rate(conversation_data)
}
return metrics
def generate_realtime_insights():
"""Generate real-time insights about chatbot performance."""
current_metrics = collect_current_metrics()
insights = reason(f"""
Analyze current chatbot performance metrics:
{current_metrics}
Provide:
1. Performance summary
2. User engagement patterns
3. Issue identification
4. Optimization opportunities
5. Anomaly detection
""")
return insights
chatbot.analytics = {
"track_metrics": track_conversation_metrics,
"get_insights": generate_realtime_insights
}
return chatbot
📊 Testing and Validation¶
Comprehensive Chatbot Testing¶
# Chatbot testing framework
def create_chatbot_testing_framework():
"""Create comprehensive testing framework for chatbots."""
def test_conversation_scenarios(test_scenarios):
"""Test chatbot with various conversation scenarios."""
test_results = []
for scenario in test_scenarios:
# Initialize test conversation
conversation_id = chatbot.start_new_conversation(scenario["user_id"])
scenario_results = []
# Execute conversation turns
for turn in scenario["conversation_turns"]:
response = chatbot.process_message(
turn["user_message"],
scenario["user_id"],
conversation_id
)
# Validate response
validation = validate_chatbot_response(
response,
turn["expected_criteria"]
)
scenario_results.append({
"turn": turn,
"response": response,
"validation": validation
})
test_results.append({
"scenario": scenario["name"],
"results": scenario_results,
"overall_success": all(r["validation"]["passed"] for r in scenario_results)
})
return test_results
def validate_chatbot_response(response, criteria):
"""Validate chatbot response against criteria."""
validation = reason(f"""
Validate chatbot response against criteria:
Response: {response}
Criteria: {criteria}
Check:
1. Relevance to user query
2. Accuracy of information
3. Appropriate tone and style
4. Completeness of answer
5. Adherence to safety guidelines
""")
return validation
return {
"test_scenarios": test_conversation_scenarios,
"validate_response": validate_chatbot_response
}
Next Steps¶
Enhancements¶
- Add voice synthesis for audio responses
- Implement personality customization
- Create chatbot analytics dashboard
- Add A/B testing for response variations
- Implement multilingual support
Integration Patterns¶
- Website widget integration
- Messaging platform connectors
- CRM system integration
- Knowledge base synchronization
- Customer service escalation
Ready to build your chatbot? Try the Quick Start example or explore more OpenDXA Recipes.