How to Create Temperature and Parameter Presets
Optimize model parameters for different tasks: creative, analytical, and factual.
Jay Banlasan
The AI Systems Guy
Most people use the same AI parameters for every task. Temperature 0.7, max tokens 1000, done. That is leaving real quality on the table. The parameters that make a creative brainstorm session excellent will make a data extraction task unreliable. The settings that produce tight, factual summaries will make creative writing feel robotic. I use parameter presets matched to task types, and the quality difference is immediately obvious.
Temperature is the most important lever but not the only one. Top-p, frequency penalty, and presence penalty each affect output in measurable ways. Understanding what each does lets you dial in exactly the right behavior for each use case.
What You Need Before Starting
- Python 3.9+
- OpenAI API key
- A clear understanding of what tasks your system handles
- 5-10 sample inputs per task type for testing your presets
Step 1: Understand What Each Parameter Does
Before writing code, understand the controls:
"""
TEMPERATURE (0.0 - 2.0):
- 0.0: Fully deterministic. Same input = same output every time.
- 0.1-0.3: Highly consistent. Small variations. Best for: extraction, classification, factual Q&A.
- 0.5-0.7: Balanced. Good variation without chaos. Best for: summaries, explanations, general writing.
- 0.8-1.2: Creative and varied. Different outputs per run. Best for: brainstorming, creative writing, ideas.
- 1.3+: Increasingly random. Often degrades quality. Use only for specific creative tasks.
TOP_P (0.0 - 1.0) - nucleus sampling:
- Controls vocabulary diversity independently of temperature.
- 0.1: Only top 10% probability tokens. Very conservative.
- 0.9: Standard. Most common default.
- 1.0: Full vocabulary available.
- Lower top_p + low temperature = extremely predictable outputs.
FREQUENCY_PENALTY (-2.0 - 2.0):
- Positive values penalize tokens that have already appeared based on frequency.
- 0.5-1.0: Reduces word repetition in long outputs. Good for reports and documents.
- 0.0: No penalty. Normal behavior.
PRESENCE_PENALTY (-2.0 - 2.0):
- Positive values penalize any token that has appeared at all (regardless of count).
- 0.5-1.0: Encourages topic diversity. Good for brainstorming multiple angles.
- 0.0: No penalty. Normal behavior.
MAX_TOKENS:
- Hard limit on output length.
- Set to what you actually need plus 20% buffer.
- Too low = truncated outputs. Too high = wasted costs.
"""
Step 2: Define Your Task Presets
from dataclasses import dataclass
from typing import Optional
@dataclass
class ParameterPreset:
name: str
temperature: float
max_tokens: int
top_p: float = 1.0
frequency_penalty: float = 0.0
presence_penalty: float = 0.0
description: str = ""
PRESETS = {
# Factual, deterministic tasks
"extraction": ParameterPreset(
name="extraction",
temperature=0.0,
max_tokens=1000,
top_p=0.9,
description="Data extraction, classification, structured output. Zero variance."
),
"factual_qa": ParameterPreset(
name="factual_qa",
temperature=0.1,
max_tokens=500,
top_p=0.9,
description="FAQ answers, documentation Q&A. Consistent with slight variation."
),
"summarization": ParameterPreset(
name="summarization",
temperature=0.2,
max_tokens=800,
top_p=0.95,
frequency_penalty=0.3,
description="Document summaries. Low variance, reduced repetition."
),
# Balanced tasks
"support_response": ParameterPreset(
name="support_response",
temperature=0.4,
max_tokens=400,
top_p=0.9,
frequency_penalty=0.1,
description="Customer support. Natural but consistent. Not robotic."
),
"content_writing": ParameterPreset(
name="content_writing",
temperature=0.6,
max_tokens=1500,
top_p=0.95,
frequency_penalty=0.4,
presence_penalty=0.2,
description="Blog posts, articles, emails. Natural writing, varied vocabulary."
),
# Creative tasks
"brainstorming": ParameterPreset(
name="brainstorming",
temperature=0.9,
max_tokens=2000,
top_p=1.0,
presence_penalty=0.6,
description="Idea generation, angles, concepts. Maximum variety per run."
),
"ad_copy": ParameterPreset(
name="ad_copy",
temperature=0.8,
max_tokens=600,
top_p=1.0,
presence_penalty=0.5,
frequency_penalty=0.3,
description="Ad hooks, headlines, creative copy. Varied, energetic."
),
"code_generation": ParameterPreset(
name="code_generation",
temperature=0.1,
max_tokens=2000,
top_p=0.95,
description="Code writing. Low temperature for logical consistency."
),
}
Step 3: Build a Preset-Aware Completion Function
import openai
client = openai.OpenAI(api_key="YOUR_API_KEY")
def complete(
messages: list,
task_type: str = "factual_qa",
model: str = "gpt-4o-mini",
preset_overrides: dict = None
) -> dict:
preset = PRESETS.get(task_type, PRESETS["factual_qa"])
params = {
"temperature": preset.temperature,
"max_tokens": preset.max_tokens,
"top_p": preset.top_p,
"frequency_penalty": preset.frequency_penalty,
"presence_penalty": preset.presence_penalty,
}
if preset_overrides:
params.update(preset_overrides)
response = client.chat.completions.create(
model=model,
messages=messages,
**params
)
return {
"content": response.choices[0].message.content,
"preset_used": task_type,
"params": params,
"tokens_used": response.usage.total_tokens
}
# Usage
result = complete(
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Extract all dates from this document: The contract starts March 1, 2024 and expires December 31, 2025. Payment due January 15, 2024."}
],
task_type="extraction"
)
print(result["content"])
Step 4: Build a Preset Comparison Tool
Test your presets against the same input to see the difference.
def compare_presets(
messages: list,
preset_names: list[str],
model: str = "gpt-4o-mini"
) -> dict:
results = {}
for preset_name in preset_names:
print(f"Running preset: {preset_name}...")
result = complete(messages, task_type=preset_name, model=model)
results[preset_name] = {
"output": result["content"],
"tokens": result["tokens_used"],
"params": result["params"]
}
return results
# Compare extraction vs brainstorming on the same task
test_messages = [
{"role": "system", "content": "Generate 5 marketing angles for a productivity app that saves teams 2 hours per day."},
{"role": "user", "content": "Give me 5 distinct angles."}
]
comparison = compare_presets(test_messages, ["brainstorming", "content_writing", "factual_qa"])
for preset, result in comparison.items():
print(f"\n=== {preset.upper()} ===")
print(result["output"][:300])
Step 5: Auto-Detect Task Type from Content
Automatically select the right preset based on the input and system prompt.
TASK_CLASSIFIER_PROMPT = """Classify this AI task into one of these categories:
extraction, factual_qa, summarization, support_response, content_writing, brainstorming, ad_copy, code_generation
Return ONLY the category name. One word."""
def auto_detect_task_type(messages: list) -> str:
# Build a description of the task from the messages
task_description = ""
for msg in messages:
if msg["role"] in {"system", "user"}:
task_description += f"{msg['role'].upper()}: {msg['content'][:200]}\n"
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": TASK_CLASSIFIER_PROMPT},
{"role": "user", "content": task_description}
],
temperature=0,
max_tokens=10
)
detected = response.choices[0].message.content.strip().lower()
return detected if detected in PRESETS else "factual_qa"
def smart_complete(messages: list, model: str = "gpt-4o-mini") -> dict:
task_type = auto_detect_task_type(messages)
result = complete(messages, task_type=task_type, model=model)
result["auto_detected_task"] = task_type
return result
Step 6: Save Custom Presets for Your Use Case
import json
from pathlib import Path
CUSTOM_PRESETS_PATH = Path("./custom_presets.json")
def save_custom_preset(name: str, preset: ParameterPreset):
existing = {}
if CUSTOM_PRESETS_PATH.exists():
existing = json.loads(CUSTOM_PRESETS_PATH.read_text())
existing[name] = {
"temperature": preset.temperature,
"max_tokens": preset.max_tokens,
"top_p": preset.top_p,
"frequency_penalty": preset.frequency_penalty,
"presence_penalty": preset.presence_penalty,
"description": preset.description
}
CUSTOM_PRESETS_PATH.write_text(json.dumps(existing, indent=2))
print(f"Preset '{name}' saved.")
def load_custom_presets():
if not CUSTOM_PRESETS_PATH.exists():
return
data = json.loads(CUSTOM_PRESETS_PATH.read_text())
for name, config in data.items():
PRESETS[name] = ParameterPreset(name=name, **config)
load_custom_presets()
# Save a domain-specific preset
save_custom_preset("legal_review", ParameterPreset(
name="legal_review",
temperature=0.0,
max_tokens=2000,
top_p=0.9,
description="Contract review, legal analysis. Zero variance required."
))
What to Build Next
- Build a parameter tuning script that runs your test set at 5 different temperature values and scores outputs to find the empirical optimum for your specific task
- Add cost tracking by preset so you know which task types are consuming the most tokens and whether larger max_tokens settings are actually being used
- Create per-user parameter profiles so power users in your product can adjust creativity level with a simple slider that maps to your preset library
Related Reading
- How to Write System Prompts That Control AI Behavior - parameters and prompts work together; the best prompt at temperature 0.0 may not be the best at 0.8
- How to Build AI Guardrails for Safe Outputs - higher temperature settings need stronger guardrails to catch more varied outputs
- How to Use AI for Automated Data Extraction - always use the extraction preset for structured data tasks; never trust extraction at temperature above 0.1
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment