Personalization used to mean rule engines and rigid templates. LLMs let you generate copy, recommendations, and onboarding flows that adapt to each user in real time, in their language and tone. This article shows how to add genuine personalization to a product using Model Database, without sacrificing control or predictability.
The pattern throughout: feed the model structured signals about the user, ask for a constrained output, and render it. The model personalizes; your code stays in charge.
What "personalization" actually means here
Useful personalization is grounded in real signals, not vibes. Typical inputs include the user's plan tier, recent activity, locale, and stated goals. You pass these as structured context and let the model adapt the message.
- Onboarding: tailor the first-run experience to the user's role.
- Lifecycle copy: write emails that reference what the user has actually done.
- Recommendations: explain why an item is suggested, in natural language.
Personalized onboarding copy
Give the model a user profile and a tight brief. Keep temperature moderate so output is fresh but on-brand.
from openai import OpenAI
client = OpenAI(
base_url="https://modeldatabase.com/v1",
api_key="mdb_live_...",
)
def welcome(profile):
resp = client.chat.completions.create(
model="openai/gpt-4o-mini",
messages=[
{"role": "system", "content":
"Write a 2-sentence welcome for a SaaS app. Friendly, "
"specific to the user's role and goal. No exclamation marks."},
{"role": "user", "content":
f"Role: {profile['role']}\nGoal: {profile['goal']}\n"
f"Plan: {profile['plan']}"},
],
temperature=0.5,
)
return resp.choices[0].message.content
Onboarding copy is high-volume and low-risk, so a fast, inexpensive model like openai/gpt-4o-mini is the right default.
Explaining recommendations
Your recommender system already ranks items with collaborative filtering or embeddings. The LLM's job is not to rank, it is to explain the ranking in human terms, which raises click-through and trust.
def explain_pick(user, item):
resp = client.chat.completions.create(
model="openai/gpt-4o-mini",
messages=[
{"role": "system", "content":
"In one sentence, explain why this item suits the user. "
"Use only the facts given. Never overpromise."},
{"role": "user", "content":
f"User likes: {user['interests']}\n"
f"Item: {item['name']} - {item['tags']}"},
],
temperature=0.4,
)
return resp.choices[0].message.content
Note the guardrail: the model explains using only the facts given. This keeps personalization honest and avoids invented claims.
Structured output for safe rendering
When personalization drives UI, ask for JSON so you can render it reliably and validate before display.
import json
def personalize_dashboard(profile):
resp = client.chat.completions.create(
model="anthropic/claude-sonnet-4-6",
messages=[
{"role": "system", "content":
"Return JSON: {\"headline\": str, \"cta\": str, "
"\"tips\": [str, str, str]}. Match the user's role."},
{"role": "user", "content": json.dumps(profile)},
],
response_format={"type": "json_object"},
temperature=0.5,
)
return json.loads(resp.choices[0].message.content)
Validate field lengths and reject anything unexpected before it reaches the page. The model proposes; your renderer disposes.
Localization comes for free
Because these models are multilingual, the same pipeline can produce copy in the user's language by adding their locale to the prompt. Models such as google/gemini-2.0-flash are a strong, fast option when you want broad language coverage at low cost.
Latency, caching, and cost
- Cache aggressively: personalization inputs change slowly. Cache generated copy keyed by the relevant profile fields and regenerate only when those change.
- Precompute: generate lifecycle emails in a batch job rather than at send time so the user never waits on a model call.
- Fall back: always keep a generic default ready. If a call fails or times out, render the default instead of blocking the page.
- Measure lift: A/B test personalized versus static copy. Track engagement, not just that the feature shipped.
Privacy first
Only send the model the signals it needs, and avoid passing raw PII into prompts. Personalization should feel helpful, not surveillant. Keep a clear boundary between the data you store and the minimal context you send per request.
Start building with a key and credit from your dashboard, and explore model options in the docs.