Add LLM system prompt override

Allow overriding the LLM system prompt via the `LLM_SYSTEM_PROMPT`
environment variable. This provides flexibility for customizing LLM
behavior without code changes. A default prompt is used if the
environment variable is unset or empty.
This commit is contained in:
2026-04-15 21:31:21 +02:00
parent 5608c8ba43
commit 70eed20909
4 changed files with 29 additions and 1 deletions
+3
View File
@@ -29,6 +29,9 @@ LLM_API_KEY=
LLM_MODEL=
LLM_TEMPERATURE=0
LLM_TIMEOUT_SECONDS=180
# Optional override of the consolidation system prompt. If unset or empty, a default is used.
# Single line — escape newlines with \n if your shell preserves them, or put the prompt on one logical line.
LLM_SYSTEM_PROMPT="Du bist ein medizinischer Assistent. Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden Text zusammen. Bereinigen und strukturieren, nichts hinzufügen, nichts interpretieren, keine Diagnose, keine Arztbrief-Struktur. Entferne Redundanzen. Spätere Aufnahmen haben Vorrang — Korrekturen, Nachträge und Widersprüche zugunsten der chronologisch letzten Aussage auflösen. Antworte auf Deutsch. Nur der zusammengefasste Text, keine Einleitung, kein Abschlusssatz."
# Session
SESSION_TIMEOUT_HOURS=8
+1 -1
View File
@@ -80,7 +80,7 @@ async fn process(
let document = match llm::chat_once(
client,
&settings,
prompt::SYSTEM_PROMPT,
&config.llm_system_prompt,
&user_content,
timeout,
)
+14
View File
@@ -53,6 +53,11 @@ pub struct Config {
pub llm_model: String,
pub llm_temperature: f32,
pub llm_timeout_seconds: u64,
/// System prompt sent to the analysis LLM. Defaults to
/// `crate::analyze::prompt::SYSTEM_PROMPT` if `LLM_SYSTEM_PROMPT` is unset
/// or empty. Runtime-configurable so admins can iterate and use the
/// "Neu analysieren" button to re-run cases.
pub llm_system_prompt: String,
pub session_timeout_hours: u32,
/// Whether to set the `Secure` flag on the session cookie. Default `true`.
/// Set `COOKIE_SECURE=false` only for plain-HTTP local development —
@@ -87,6 +92,14 @@ impl Config {
llm_model: optional_env("LLM_MODEL", ""),
llm_temperature: optional_env_parsed("LLM_TEMPERATURE", 0.0),
llm_timeout_seconds: optional_env_parsed("LLM_TIMEOUT_SECONDS", 180),
llm_system_prompt: {
let v = optional_env("LLM_SYSTEM_PROMPT", "");
if v.is_empty() {
crate::analyze::prompt::SYSTEM_PROMPT.to_string()
} else {
v
}
},
session_timeout_hours: optional_env_parsed("SESSION_TIMEOUT_HOURS", 8),
cookie_secure: optional_env_parsed("COOKIE_SECURE", true),
}
@@ -135,6 +148,7 @@ impl Config {
llm_model: String::new(),
llm_temperature: 0.0,
llm_timeout_seconds: 180,
llm_system_prompt: crate::analyze::prompt::SYSTEM_PROMPT.to_string(),
session_timeout_hours: 8,
cookie_secure: false,
}
+11
View File
@@ -48,6 +48,17 @@ async fn main() {
);
}
{
let custom = std::env::var("LLM_SYSTEM_PROMPT")
.map(|v| !v.is_empty())
.unwrap_or(false);
info!(
prompt_source = if custom { "env" } else { "default" },
prompt_chars = config.llm_system_prompt.chars().count(),
"system prompt loaded"
);
}
// Shared HTTP client for both downstream pipelines.
let http_client = reqwest::Client::builder()
.build()