feat(tenant): make monitoring parse & compliance judge models configurable

Replace the hardcoded doubao-lite model used for monitoring answer
parsing and compliance LLM judging with configurable values, resolved
from config with env overrides and a legacy default fallback.

- Add llm.monitoring_answer_parse_model and compliance.llm_judge_model
  to config struct, env overrides, and all config files
- Thread the resolved model through MonitoringCallbackService via a
  ConfigProvider and into parseMonitoringAnswerWithLLM
- Pass compliance.llm_judge_model into the review-job LLM request

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 17:04:01 +08:00
parent fb142e4ca7
commit c8dceb43d7
13 changed files with 103 additions and 17 deletions
+19 -11
View File
@@ -328,22 +328,24 @@ type LogConfig struct {
}
type LLMConfig struct {
Provider string `mapstructure:"provider"`
APIKey string `mapstructure:"api_key"`
BaseURL string `mapstructure:"base_url"`
Model string `mapstructure:"model"`
KnowledgeURLModel string `mapstructure:"knowledge_url_model"`
Timeout time.Duration `mapstructure:"timeout"`
MaxOutputTokens int64 `mapstructure:"max_output_tokens"`
Temperature float64 `mapstructure:"temperature"`
TopP float64 `mapstructure:"top_p"`
ReasoningEffort string `mapstructure:"reasoning_effort"`
WebSearchLimit int32 `mapstructure:"web_search_limit"`
Provider string `mapstructure:"provider"`
APIKey string `mapstructure:"api_key"`
BaseURL string `mapstructure:"base_url"`
Model string `mapstructure:"model"`
KnowledgeURLModel string `mapstructure:"knowledge_url_model"`
MonitoringAnswerParseModel string `mapstructure:"monitoring_answer_parse_model"`
Timeout time.Duration `mapstructure:"timeout"`
MaxOutputTokens int64 `mapstructure:"max_output_tokens"`
Temperature float64 `mapstructure:"temperature"`
TopP float64 `mapstructure:"top_p"`
ReasoningEffort string `mapstructure:"reasoning_effort"`
WebSearchLimit int32 `mapstructure:"web_search_limit"`
}
type ComplianceConfig struct {
Enabled bool `mapstructure:"enabled"`
LLMJudgeEnabled bool `mapstructure:"llm_judge_enabled"`
LLMJudgeModel string `mapstructure:"llm_judge_model"`
SnapshotReloadInterval time.Duration `mapstructure:"snapshot_reload_interval"`
PublishGateTimeout time.Duration `mapstructure:"publish_gate_timeout"`
ReviewWorkerConcurrency int `mapstructure:"review_worker_concurrency"`
@@ -987,12 +989,18 @@ func applyEnvOverrides(cfg *Config) {
if model, ok := lookupNonEmptyEnv("LLM_KNOWLEDGE_URL_MODEL"); ok {
cfg.LLM.KnowledgeURLModel = model
}
if model, ok := lookupNonEmptyEnv("LLM_MONITORING_ANSWER_PARSE_MODEL"); ok {
cfg.LLM.MonitoringAnswerParseModel = model
}
if enabled, ok := lookupBoolEnv("COMPLIANCE_ENABLED"); ok {
cfg.Compliance.Enabled = enabled
}
if enabled, ok := lookupBoolEnv("COMPLIANCE_LLM_ENABLED"); ok {
cfg.Compliance.LLMJudgeEnabled = enabled
}
if model, ok := lookupNonEmptyEnv("COMPLIANCE_LLM_JUDGE_MODEL"); ok {
cfg.Compliance.LLMJudgeModel = model
}
if d, ok := lookupDurationEnv("COMPLIANCE_SNAPSHOT_RELOAD_INTERVAL"); ok {
cfg.Compliance.SnapshotReloadInterval = d
}
@@ -27,6 +27,30 @@ llm:
}
}
func TestLoadAppliesSpecializedLLMModelEnvOverrides(t *testing.T) {
t.Setenv("LLM_MONITORING_ANSWER_PARSE_MODEL", "env-monitoring-parse")
t.Setenv("COMPLIANCE_LLM_JUDGE_MODEL", "env-compliance-judge")
configPath := writeTestConfig(t, `
llm:
monitoring_answer_parse_model: "config-monitoring-parse"
compliance:
llm_judge_model: "config-compliance-judge"
`)
cfg, err := Load(configPath)
if err != nil {
t.Fatalf("Load() error = %v", err)
}
if cfg.LLM.MonitoringAnswerParseModel != "env-monitoring-parse" {
t.Fatalf("expected env monitoring parse model, got %q", cfg.LLM.MonitoringAnswerParseModel)
}
if cfg.Compliance.LLMJudgeModel != "env-compliance-judge" {
t.Fatalf("expected env compliance judge model, got %q", cfg.Compliance.LLMJudgeModel)
}
}
func TestDatabaseConfigDSNEscapesCredentials(t *testing.T) {
cfg := DatabaseConfig{
Host: "db.internal",