Chat Components
August 28, 2025 ยท View on GitHub
POML provides specialized components for creating structured AI conversations with proper role-based messaging.
Overview
Chat components (<ai>, <human>, <system>) are designed to create structured conversation flows that work seamlessly across different AI platforms and output formats.
System Component
The <system> component defines system-level instructions and context:
require 'poml'
markup = <<~POML
<poml>
<system>
You are a helpful assistant specializing in Ruby programming.
Provide clear, practical solutions with code examples.
Always explain your reasoning and suggest best practices.
</system>
</poml>
POML
result = Poml.process(markup: markup, format: 'openai_chat')
puts JSON.pretty_generate(result)
Output:
[
{
"role": "system",
"content": "You are a helpful assistant specializing in Ruby programming..."
}
]
Human Component
The <human> component represents user messages and queries:
markup = <<~POML
<poml>
<system>You are a code review assistant.</system>
<human>
Please review this Ruby method for potential improvements:
<code>
def calculate_total(items)
total = 0
items.each do |item|
total += item.price * item.quantity
end
total
end
</code>
</human>
</poml>
POML
result = Poml.process(markup: markup, format: 'openai_chat')
AI Component
The <ai> component represents assistant responses and can be used for few-shot examples:
markup = <<~POML
<poml>
<system>You are a Ruby expert providing code reviews.</system>
<human>How can I optimize this method?</human>
<ai>
Here's an optimized version using Ruby's built-in methods:
<code>
def calculate_total(items)
items.sum { |item| item.price * item.quantity }
end
</code>
This approach is more idiomatic and efficient.
</ai>
<human>Now please review this new code I've written:</human>
</poml>
POML
result = Poml.process(markup: markup, format: 'openai_chat')
Multi-Turn Conversations
Create complex conversation flows with multiple exchanges:
markup = <<~POML
<poml>
<system>
You are a technical interviewer conducting a Ruby programming interview.
Ask progressive questions to assess the candidate's knowledge.
</system>
<human>I'm ready for the Ruby interview questions.</human>
<ai>
Great! Let's start with a basic question:
What's the difference between a class method and an instance method in Ruby?
Can you provide examples of each?
</ai>
<human>
A class method is called on the class itself, while an instance method
is called on an instance of the class.
Class method: `User.find_by_email(email)`
Instance method: `user.save`
</human>
<ai>
Excellent! Now let's dive deeper. Can you explain how Ruby's method
lookup chain works? What happens when you call a method on an object?
</ai>
<human>{{candidate_response}}</human>
</poml>
POML
context = {
'candidate_response' => 'Please explain the method lookup process...'
}
result = Poml.process(markup: markup, context: context, format: 'openai_chat')
Chat Components with Formatting
Chat components support nested formatting and structure:
markup = <<~POML
<poml>
<system>You are a code documentation assistant.</system>
<human>
Please document this API endpoint:
<list>
<item><b>Method:</b> POST</item>
<item><b>Path:</b> /api/users</item>
<item><b>Purpose:</b> Create new user account</item>
</list>
</human>
<ai>
I'll create comprehensive documentation for this endpoint:
<h2>POST /api/users</h2>
<p><b>Description:</b> Creates a new user account in the system.</p>
<p><b>Request Body:</b></p>
<code>
{
"name": "string (required)",
"email": "string (required, unique)",
"password": "string (required, min 8 chars)"
}
</code>
<p><b>Response Codes:</b></p>
<list>
<item><code>201</code> - User created successfully</item>
<item><code>400</code> - Validation errors</item>
<item><code>409</code> - Email already exists</item>
</list>
</ai>
</poml>
POML
result = Poml.process(markup: markup, format: 'raw')
Template Variables in Chat
Use template variables within chat components:
markup = <<~POML
<poml>
<system>
You are a {{expertise_area}} expert helping with {{project_type}} projects.
Provide detailed, practical guidance based on industry best practices.
</system>
<human>
I'm working on a {{project_type}} and need help with {{specific_issue}}.
<p>Project Details:</p>
<list>
<item>Technology: {{technology_stack}}</item>
<item>Timeline: {{timeline}}</item>
<item>Team Size: {{team_size}}</item>
</list>
</human>
</poml>
POML
context = {
'expertise_area' => 'DevOps',
'project_type' => 'microservices deployment',
'specific_issue' => 'container orchestration',
'technology_stack' => 'Docker + Kubernetes',
'timeline' => '3 months',
'team_size' => '5 developers'
}
result = Poml.process(markup: markup, context: context, format: 'openai_chat')
Conditional Chat Content
Use conditionals to create dynamic conversation flows:
markup = <<~POML
<poml>
<system>You are a debugging assistant.</system>
<human>I'm having an issue with my {{language}} code.</human>
<ai>
I'd be happy to help you debug your {{language}} code!
<if condition="{{language}} == 'Ruby'">
<p>For Ruby issues, I'll need to see:</p>
<list>
<item>The Ruby version you're using</item>
<item>Your Gemfile (if applicable)</item>
<item>The specific error message</item>
<item>The problematic code snippet</item>
</list>
</if>
<if condition="{{language}} == 'Python'">
<p>For Python issues, please provide:</p>
<list>
<item>Python version and virtual environment info</item>
<item>requirements.txt or pip freeze output</item>
<item>Full traceback of the error</item>
<item>Minimal code to reproduce the issue</item>
</list>
</if>
<p>Please share these details and I'll help you solve the problem.</p>
</ai>
</poml>
POML
context = { 'language' => 'Ruby' }
result = Poml.process(markup: markup, context: context, format: 'raw')
Output Format Behavior
Chat components behave differently based on the output format:
OpenAI Chat Format
markup = <<~POML
<poml>
<system>You are a helpful assistant.</system>
<human>What is Ruby?</human>
</poml>
POML
result = Poml.process(markup: markup, format: 'openai_chat')
# Returns: [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}]
Raw Format
result = Poml.process(markup: markup, format: 'raw')
# Returns: Text with role boundaries like "===== system ====="
LangChain Format
result = Poml.process(markup: markup, format: 'langchain')
# Returns: LangChain-compatible message structure
Advanced Chat Patterns
Interview Flow
markup = <<~POML
<poml>
<system>
You are conducting a technical interview for a {{position}} role.
Ask progressive questions starting from basic concepts to advanced topics.
Provide feedback and follow-up questions based on responses.
</system>
<human>I'm ready to begin the {{position}} interview.</human>
<ai>
Welcome to the {{position}} interview! Let's start with some foundational questions.
<p><b>Question 1:</b> {{first_question}}</p>
<p>Take your time to explain your thought process.</p>
</ai>
<human>{{candidate_answer_1}}</human>
<ai>
<if condition="{{question_difficulty}} == 'basic'">
Good start! Now let's move to something more challenging.
</if>
<if condition="{{question_difficulty}} == 'advanced'">
Excellent answer! You clearly understand the concepts well.
</if>
<p><b>Follow-up:</b> {{follow_up_question}}</p>
</ai>
</poml>
POML
Debugging Session
markup = <<~POML
<poml>
<system>
You are a senior developer helping debug a complex issue.
Guide the user through systematic debugging steps.
</system>
<human>
I'm getting this error in production:
<code>{{error_message}}</code>
It happens intermittently and I can't reproduce it locally.
</human>
<ai>
Intermittent production-only errors can be tricky! Let's debug this systematically.
<p><b>First, let's gather information:</b></p>
<list>
<item>What's the frequency of this error?</item>
<item>Are there any patterns in timing or user actions?</item>
<item>What are the differences between your local and production environments?</item>
<item>Do you have logging around the error location?</item>
</list>
<p>Based on the error message, here are some initial hypotheses:</p>
<if condition="{{error_type}} == 'timeout'">
<list>
<item>Database connection pooling issues</item>
<item>External API timeouts</item>
<item>Load-related performance degradation</item>
</list>
</if>
<if condition="{{error_type}} == 'memory'">
<list>
<item>Memory leaks in long-running processes</item>
<item>Large dataset processing without pagination</item>
<item>Inefficient caching strategies</item>
</list>
</if>
</ai>
</poml>
POML
Code Review Conversation
markup = <<~POML
<poml>
<system>
You are a senior developer conducting a code review.
Provide constructive feedback focusing on maintainability, performance, and best practices.
</system>
<human>
Here's my implementation for the user authentication system:
<code>{{code_submission}}</code>
I'm particularly concerned about security and performance.
</human>
<ai>
Thanks for submitting this code! I'll review it focusing on security and performance as requested.
<p><b>Overall Assessment:</b> {{overall_assessment}}</p>
<p><b>Security Review:</b></p>
<list>
<for variable="security_issue" items="{{security_issues}}">
<item><b>{{security_issue.severity}}:</b> {{security_issue.description}}</item>
</for>
</list>
<p><b>Performance Considerations:</b></p>
<list>
<for variable="perf_issue" items="{{performance_issues}}">
<item>{{perf_issue.description}} - <i>{{perf_issue.solution}}</i></item>
</for>
</list>
<p><b>Recommended Changes:</b></p>
<code>{{suggested_improvements}}</code>
<p>Would you like me to explain any of these recommendations in more detail?</p>
</ai>
</poml>
POML
Best Practices
1. Clear Role Definition
# Good
<system>
You are a Ruby on Rails expert with 10+ years of experience.
Provide practical, production-ready solutions with security considerations.
</system>
# Better
<system>
You are a Senior Ruby on Rails Developer and Technical Lead specializing in:
- Performance optimization and scaling
- Security best practices and compliance
- Code architecture and maintainability
Always provide working code examples and explain trade-offs.
</system>
2. Structured Conversations
# Structure conversations logically
<system>Context and role definition</system>
<human>Initial request or question</human>
<ai>Example response (for few-shot learning)</ai>
<human>Actual user input</human>
3. Use Formatting for Clarity
<human>
<p>I need help with this problem:</p>
<p><b>Context:</b> {{context}}</p>
<p><b>Goal:</b> {{goal}}</p>
<p><b>Constraints:</b> {{constraints}}</p>
<p>Current code:</p>
<code>{{current_code}}</code>
</human>
4. Error Handling
def safe_chat_processing(markup, context = {})
begin
result = Poml.process(markup: markup, context: context, format: 'openai_chat')
# Validate chat structure
if result.is_a?(Array) && result.all? { |msg| msg.is_a?(Hash) && msg['role'] && msg['content'] }
{ success: true, messages: result }
else
{ success: false, error: 'Invalid chat structure' }
end
rescue => e
{ success: false, error: e.message }
end
end
Integration with AI Services
OpenAI API
require 'net/http'
require 'json'
def send_to_openai(poml_markup, context = {})
messages = Poml.process(
markup: poml_markup,
context: context,
format: 'openai_chat'
)
payload = {
model: 'gpt-4',
messages: messages,
max_tokens: 1000,
temperature: 0.7
}
# Send to OpenAI API...
end
Claude API
def send_to_claude(poml_markup, context = {})
# Convert to raw format for Claude
prompt = Poml.process(
markup: poml_markup,
context: context,
format: 'raw'
)
# Send to Claude API...
end
Next Steps
- Learn about Output Formats for different AI services
- Explore Schema Components for structured responses
- Check Integration Examples for real-world usage