Role Prompting: Persona and Expertise Framing
Use role prompting to prime models for specific expertise domains, communication styles, and reasoning patterns. Design effective personas for different deployment contexts.
How Role Prompting Works
Assigning a role to a model activates related knowledge, communication patterns, and reasoning styles from pretraining. The model has learned how domain experts write and think by training on domain-specific text. Role prompting retrieves that learned distribution.
"Answer this question:" β General-purpose distribution
"As a clinical pharmacist, answer:" β Medical/pharmaceutical distribution
"As a skeptical clinical pharmacist reviewing a colleague's suggestion:" β Critical evaluation modeRole prompting doesn't give the model capabilities it doesn't have β it surfaces expertise already in the weights.
Basic Role Framing
from openai import OpenAI
client = OpenAI()
def ask_with_role(role: str, question: str, additional_context: str = "") -> str:
system = f"You are {role}."
if additional_context:
system += f" {additional_context}"
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": question},
],
temperature=0,
)
return response.choices[0].message.content
question = "What is the recommended INR target for a patient with a mechanical heart valve?"
# Three different role framings β observe how the response style changes
print("=== General ===")
print(ask_with_role("a helpful medical assistant", question))
print("\n=== Clinical Pharmacist ===")
print(ask_with_role("a board-certified clinical pharmacist", question,
"Provide precise, clinically actionable information for healthcare providers."))
print("\n=== Skeptical Reviewer ===")
print(ask_with_role("a critical pharmacist reviewing clinical practice guidelines", question,
"Highlight evidence quality, clinical nuance, and situations where guidelines may not apply."))Expertise Level in the Role
The expertise level described in the role affects how much background knowledge is assumed:
roles_by_expertise = {
"patient": "You are explaining this to a patient with no medical background. Use plain language, define all medical terms, and focus on practical implications.",
"medical_student": "You are a clinical pharmacology professor explaining this to a third-year medical student. Assume knowledge of basic biochemistry but not clinical application.",
"resident": "You are a senior attending physician briefing an internal medicine resident. Use clinical terminology and focus on decision-making, not basic science.",
"specialist": "You are a clinical pharmacologist consulting with a cardiologist colleague. Peer-level communication; skip basic explanations.",
}
# The same question returns very different answers based on audience
question = "Why do we use warfarin instead of heparin for long-term anticoagulation?"
for role_name, role_prompt in roles_by_expertise.items():
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": role_prompt},
{"role": "user", "content": question},
],
temperature=0,
)
print(f"=== {role_name.upper()} ===")
print(response.choices[0].message.content[:300])
print()Multi-Perspective Role Prompting
Get multiple viewpoints by running the same question through different expert roles:
def multi_perspective_analysis(
topic: str,
perspectives: list[dict],
) -> dict:
"""Analyze a topic from multiple expert perspectives."""
results = {}
for perspective in perspectives:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"You are {perspective['role']}. {perspective.get('instructions', '')}"},
{"role": "user", "content": f"Analyze the following from your professional perspective:\n\n{topic}"},
],
temperature=0.1,
)
results[perspective["name"]] = response.choices[0].message.content
return results
# Analyze a drug from multiple clinical perspectives
analysis = multi_perspective_analysis(
topic="Patient case: 72-year-old with new atrial fibrillation. Considering anticoagulation with warfarin vs a DOAC.",
perspectives=[
{
"name": "cardiologist",
"role": "a cardiologist focused on stroke prevention and rhythm management",
"instructions": "Focus on stroke risk (CHAβDSβ-VASc), rhythm management, and cardiovascular considerations.",
},
{
"name": "clinical_pharmacist",
"role": "a clinical pharmacist specializing in anticoagulation management",
"instructions": "Focus on drug interactions, monitoring requirements, adherence, and safety profiles.",
},
{
"name": "geriatrician",
"role": "a geriatrician focused on frailty, fall risk, and polypharmacy in elderly patients",
"instructions": "Focus on fall risk, cognitive function, renal function, and quality of life in elderly patients.",
},
{
"name": "patient_advocate",
"role": "a patient advocate focused on patient preferences and quality of life",
"instructions": "Focus on patient burden (monitoring requirements, dietary restrictions), cost, and lifestyle impact.",
},
],
)
for perspective, analysis_text in analysis.items():
print(f"\n{'='*40}")
print(f" {perspective.upper()} PERSPECTIVE")
print('='*40)
print(analysis_text)Adversarial Role: Devil's Advocate
Use an adversarial role to stress-test reasoning:
def devils_advocate_review(proposal: str) -> str:
"""Review a clinical or technical proposal from an adversarial perspective."""
system = """You are a rigorous devil's advocate reviewing clinical proposals.
Your job is NOT to find reasons why this is a good idea β it's to identify:
1. Logical weaknesses in the argument
2. Evidence that contradicts the proposal
3. Scenarios where this approach would fail
4. Assumptions being made that may not hold
5. Alternative explanations for the supporting evidence
Be specific and cite realistic counterexamples. Do not soften your critique β the goal is to stress-test the proposal before implementation."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": f"Critically evaluate this proposal:\n\n{proposal}"},
],
temperature=0.3,
)
return response.choices[0].message.content
proposal = """
We should switch all atrial fibrillation patients from warfarin to apixaban
because DOACs have better safety profiles and don't require INR monitoring,
reducing burden on the anticoagulation clinic.
"""
critique = devils_advocate_review(proposal)
print(critique)Role Consistency Across Turns
In multi-turn conversations, maintain the role consistently:
class RoleConsistentChat:
def __init__(self, role: str, role_instructions: str = ""):
self.messages = [
{"role": "system", "content": f"You are {role}. {role_instructions} Maintain this perspective consistently throughout the conversation."}
]
def chat(self, user_message: str) -> str:
self.messages.append({"role": "user", "content": user_message})
response = client.chat.completions.create(
model="gpt-4o",
messages=self.messages,
temperature=0.1,
)
assistant_message = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": assistant_message})
return assistant_message
# Usage
pharmacist = RoleConsistentChat(
role="a hospital clinical pharmacist during a ward round",
role_instructions="You provide concise, immediately actionable drug information. Reference your institution's formulary when relevant."
)
print(pharmacist.chat("We're considering starting digoxin for this patient with heart failure. Their creatinine is 1.8."))
print(pharmacist.chat("What dose would you recommend?"))
print(pharmacist.chat("And what should we monitor?"))Role Prompting Limitations
Roles don't create new knowledge: A role assigned to a model that wasn't trained on pharmacology won't produce better pharmacology. The role unlocks pretraining knowledge, not capability beyond it.
Roles can be overridden: A carefully designed adversarial persona can "jailbreak" the role. In production systems, roles should work alongside system constraints, not instead of them.
Inconsistency across sessions: The model doesn't "remember" a role between API calls β the system prompt must be present in every request.
Calibration drift: A very authoritative role ("world's leading expert") can make the model more confident and less appropriately uncertain. Pair expert roles with explicit uncertainty instructions: "When you are not certain, say so even if it feels inconsistent with your role."
Role Prompting for Code and Technical Tasks
Role prompting works for non-clinical domains too:
technical_roles = {
"code_reviewer": """You are a senior software engineer reviewing code for correctness, maintainability, and performance. Be direct. Identify issues in order of severity. Suggest specific improvements, not general advice.""",
"security_auditor": """You are a security engineer reviewing code for vulnerabilities. Focus on OWASP top 10, injection attacks, authentication flaws, and data exposure. Provide CVE references where relevant.""",
"optimization_expert": """You are a performance engineer. Identify the biggest bottlenecks first. Measure before optimizing. Prefer proven algorithmic improvements over micro-optimizations.""",
}
code_to_review = """
def get_user(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
return db.execute(query)
"""
for role_name, role_prompt in technical_roles.items():
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": role_prompt},
{"role": "user", "content": f"Review this code:\n```python\n{code_to_review}\n```"},
],
temperature=0,
)
print(f"\n=== {role_name.upper()} ===")
print(response.choices[0].message.content)Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.