Prompt Templates
ChimerAI Prompt Templates let you store, manage, and apply system prompts from the database — without changing code. Admins create templates in the dashboard; the chat route loads them automatically at runtime.
Installation
chimerai add prompt-management
Scaffolds:
app/dashboard/prompts/page.tsx— CRUD UI (create, edit, delete, set default)app/api/prompts/route.ts— GET / POSTapp/api/prompts/[id]/route.ts— GET / PUT / DELETEapp/api/prompts/[id]/set-default— POST (marks one prompt as default per category)components/chat/prompt-selector.tsx— dropdown for the chat UIPromptTemplatemodel added to Prisma schema
Database Model
model PromptTemplate {
id String @id @default(cuid())
name String
category String // "system" | "rag" | "widget" | "user"
description String?
content String @db.Text
isDefault Boolean @default(false)
isActive Boolean @default(true)
language String @default("en")
tags String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Categories
| Category | Zweck | Automatisch aktiv |
|---|---|---|
system | Chat-Verhalten, Persona, Tonalität | ✅ ja — Default-Prompt wird immer geladen |
rag | Kontext-Framing für Dokumentantworten | ❌ nein — manuelle Integration (siehe unten) |
widget | System-Prompt für eingebettetes Chat-Widget | ❌ nein — optional per promptId |
user | Vorgeschlagene User-Prompts / Starter-Fragen | ❌ nein — rein informativ / UI |
Wie Prompts im Chat verwendet werden
Automatisch — Default-Prompt
Die Stream-Route (/api/v1/chat/stream) lädt bei jedem Request automatisch den aktiven Default-Prompt der Kategorie system:
Request ohne promptId
→ Stream-Route sucht: category='system', isDefault=true, isActive=true
→ Findet einen → wird als System-Message vor alle anderen Messages prepended
→ Kein Default gefunden → kein System-Prompt (normales Verhalten)
Das bedeutet: du erstellst einen Prompt in /dashboard/prompts, setzt ihn als Default — ab sofort gilt er für alle Chat-Konversationen, ohne Code-Änderung.
Explizit — per promptId
Der Client kann eine promptId im Request-Body mitschicken um einen bestimmten Prompt zu erzwingen:
// useChat hook — sendMessage
await fetch('/api/v1/chat/stream', {
method: 'POST',
body: JSON.stringify({
messages,
model,
promptId: 'clxyz123...', // lädt diesen Prompt statt dem Default
}),
});
Die Stream-Route priorisiert promptId über den Default:
if (promptId) {
// lädt genau diesen Prompt
} else {
// lädt Default (category='system', isDefault=true)
}
PromptSelector-Komponente
chimerai add prompt-management liefert einen fertigen Dropdown mit dem der User im Chat selbst einen Prompt wählen kann:
import { PromptSelector } from '@/components/chat/prompt-selector';
// Im Chat-Header oder Sidebar:
const [promptId, setPromptId] = useState<string | null>(null);
<PromptSelector
value={promptId}
onChange={setPromptId}
category="system" // filtert auf System-Prompts
placeholder="No system prompt"
/>
Die gewählte promptId dann beim Senden mitgeben:
sendMessage(userInput, { promptId });
Prompts im RAG
Die Kategorie rag ist für Dokument-Kontext-Templates gedacht ("Beantworte die Frage nur anhand der folgenden Dokumente: ..."). Die RAG-Route lädt sie nicht automatisch — das erfordert eine manuelle Anpassung:
// app/api/v1/rag/query/route.ts — eigene Erweiterung
const ragTemplate = await prisma.promptTemplate.findFirst({
where: { category: 'rag', isDefault: true, isActive: true },
});
const systemPrompt = ragTemplate
? ragTemplate.content
: 'Answer based on the provided context only.';
// systemPrompt dann als System-Message in den LLM-Call einbauen
Ein typisches RAG-Template:
Du bist ein hilfreicher Assistent. Beantworte die folgende Frage ausschließlich
auf Basis der bereitgestellten Dokumente. Wenn die Antwort nicht in den
Dokumenten enthalten ist, antworte mit "Diese Information liegt mir nicht vor."
Dokumente:
{{context}}
Frage: {{question}}
{{context}}und{{question}}sind Platzhalter — die RAG-Route muss sie vor dem LLM-Aufruf ersetzen.
API Endpoints
| Method | Path | Beschreibung |
|---|---|---|
GET | /api/prompts | Alle aktiven Templates |
GET | /api/prompts?category=system | Gefiltert nach Kategorie |
POST | /api/prompts | Neues Template erstellen |
GET | /api/prompts/:id | Einzelnes Template |
PUT | /api/prompts/:id | Template aktualisieren |
DELETE | /api/prompts/:id | Template löschen |
POST | /api/prompts/:id/set-default | Als Default markieren |
Access Control
Prompt-Verwaltung hinter Admin-Rolle absichern:
// app/dashboard/prompts/page.tsx
const session = await getServerSession(authOptions);
if (session?.user?.role !== 'admin') redirect('/');
Typische Workflows
System-Prompt für alle Chats setzen:
/dashboard/prompts→ Neuer Prompt → Kategorie:system- "Als Default setzen" klicken
- Fertig — gilt ab sofort für alle neuen Konversationen
Verschiedene Prompts pro Use-Case (z.B. Support vs. Coding):
- Mehrere
system-Prompts erstellen (nur einer kann Default sein) PromptSelectorin die Chat-UI einbauen- User wählt den passenden Prompt pro Konversation
Mehrsprachige Apps:
- Gleicher Prompt-Name, unterschiedliche
language-Werte (de,en,fr) - In der Stream-Route auf
Accept-LanguageHeader filtern:const lang = request.headers.get('accept-language')?.slice(0, 2) ?? 'en'; const tmpl = await prisma.promptTemplate.findFirst({ where: { category: 'system', isDefault: true, isActive: true, language: lang }, });