feat: model-level system prompt with multi-language support - #6117
feat: model-level system prompt with multi-language support#6117Wu-jiyan wants to merge 1 commit into
Conversation
- Add system_prompt and system_prompt_mode fields to models table
- Support four modes: disabled, inject, override, append
- Apply model-level system prompt before channel-level in OpenAI/Claude/Gemini handlers
- Multi-language JSON format: {"en":"...","zh":"..."}, auto-matched to user language
- Frontend: System Prompt section in model edit drawer
- Frontend: System Prompt column in /models/metadata table
WalkthroughAdds persisted model-level system prompts with multilingual resolution and configurable injection modes. Prompts are initialized in request context, applied across OpenAI-compatible, Gemini, and Claude requests, and managed through the model administration UI. ChangesModel system prompt
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ModelConfiguration
participant ChannelSetup
participant RelayHandler
participant ProviderRequest
ModelConfiguration->>ChannelSetup: save and load model prompt settings
ChannelSetup->>RelayHandler: place prompt and mode in request context
RelayHandler->>ProviderRequest: apply model prompt before channel prompt
ProviderRequest-->>RelayHandler: continue provider-specific request flow
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
relay/helper/system_prompt.go (1)
4-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
common.UnmarshalJsonStrhererelay/helper/system_prompt.go:4,30importsencoding/jsonand parses a string withjson.Unmarshaldirectly; switch this tocommon.UnmarshalJsonStrso JSON handling stays consistent with the rest of the codebase.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@relay/helper/system_prompt.go` at line 4, Replace the direct encoding/json usage in the system prompt parsing flow with common.UnmarshalJsonStr, including updating the import and the call site near the existing JSON unmarshal logic. Preserve the current target and error-handling behavior while using the shared helper.Sources: Coding guidelines, Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@model/model_meta.go`:
- Around line 220-230: Update GetModelSystemPrompt to distinguish
gorm.ErrRecordNotFound from other database errors; retain the silent empty
fallback for missing records, but log unexpected query failures before returning
"", 0 using the project’s established logging mechanism.
In `@web/default/src/features/models/components/models-columns.tsx`:
- Around line 53-65: Update resolveSystemPromptText to match the backend
fallback order: prefer the “en” value, then “zh”, then the first object value,
and finally the original prompt. Keep the existing JSON parsing and plain-text
behavior unchanged.
---
Nitpick comments:
In `@relay/helper/system_prompt.go`:
- Line 4: Replace the direct encoding/json usage in the system prompt parsing
flow with common.UnmarshalJsonStr, including updating the import and the call
site near the existing JSON unmarshal logic. Preserve the current target and
error-handling behavior while using the shared helper.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7731406a-58c5-4984-9bba-939a0170e720
📒 Files selected for processing (11)
constant/context_key.gomiddleware/distributor.gomodel/model_meta.gorelay/claude_handler.gorelay/compatible_handler.gorelay/gemini_handler.gorelay/helper/system_prompt.goweb/default/src/features/models/components/drawers/model-mutate-drawer.tsxweb/default/src/features/models/components/models-columns.tsxweb/default/src/features/models/lib/model-form.tsweb/default/src/features/models/types.ts
|
|
||
| // GetModelSystemPrompt 根据模型名查找系统提示词配置 | ||
| // 返回 systemPrompt(可能为多语言JSON: {"en":"...", "zh":"..."})和 mode(0=禁用,1=注入,2=覆写,3=附加) | ||
| func GetModelSystemPrompt(modelName string) (systemPrompt string, mode int) { | ||
| var m Model | ||
| err := DB.Where("model_name = ? AND status = ?", modelName, 1).First(&m).Error | ||
| if err != nil || m.SystemPrompt == "" || m.SystemPromptMode == 0 { | ||
| return "", 0 | ||
| } | ||
| return m.SystemPrompt, m.SystemPromptMode | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Consider logging unexpected database errors in GetModelSystemPrompt.
The function returns "", 0 on any err != nil, which is a safe fallback. However, non-ErrRecordNotFound errors (e.g., connection failures) are silently swallowed with no log trail, making it difficult to diagnose why a model prompt isn't applying in production.
🛡️ Suggested improvement
func GetModelSystemPrompt(modelName string) (systemPrompt string, mode int) {
var m Model
err := DB.Where("model_name = ? AND status = ?", modelName, 1).First(&m).Error
- if err != nil || m.SystemPrompt == "" || m.SystemPromptMode == 0 {
+ if err != nil {
+ if !errors.Is(err, gorm.ErrRecordNotFound) {
+ logger.SysError("failed to query model system prompt for %s: %s", modelName, err.Error())
+ }
+ return "", 0
+ }
+ if m.SystemPrompt == "" || m.SystemPromptMode == 0 {
return "", 0
}
return m.SystemPrompt, m.SystemPromptMode
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // GetModelSystemPrompt 根据模型名查找系统提示词配置 | |
| // 返回 systemPrompt(可能为多语言JSON: {"en":"...", "zh":"..."})和 mode(0=禁用,1=注入,2=覆写,3=附加) | |
| func GetModelSystemPrompt(modelName string) (systemPrompt string, mode int) { | |
| var m Model | |
| err := DB.Where("model_name = ? AND status = ?", modelName, 1).First(&m).Error | |
| if err != nil || m.SystemPrompt == "" || m.SystemPromptMode == 0 { | |
| return "", 0 | |
| } | |
| return m.SystemPrompt, m.SystemPromptMode | |
| } | |
| // GetModelSystemPrompt 根据模型名查找系统提示词配置 | |
| // 返回 systemPrompt(可能为多语言JSON: {"en":"...", "zh":"..."})和 mode(0=禁用,1=注入,2=覆写,3=附加) | |
| func GetModelSystemPrompt(modelName string) (systemPrompt string, mode int) { | |
| var m Model | |
| err := DB.Where("model_name = ? AND status = ?", modelName, 1).First(&m).Error | |
| if err != nil { | |
| if !errors.Is(err, gorm.ErrRecordNotFound) { | |
| logger.SysError("failed to query model system prompt for %s: %s", modelName, err.Error()) | |
| } | |
| return "", 0 | |
| } | |
| if m.SystemPrompt == "" || m.SystemPromptMode == 0 { | |
| return "", 0 | |
| } | |
| return m.SystemPrompt, m.SystemPromptMode | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@model/model_meta.go` around lines 220 - 230, Update GetModelSystemPrompt to
distinguish gorm.ErrRecordNotFound from other database errors; retain the silent
empty fallback for missing records, but log unexpected query failures before
returning "", 0 using the project’s established logging mechanism.
| // 解析多语言系统提示词文本,优先中文 | ||
| function resolveSystemPromptText(prompt: string): string { | ||
| try { | ||
| const obj = JSON.parse(prompt) | ||
| if (typeof obj === 'object' && obj !== null) { | ||
| return obj['zh'] || obj['en'] || Object.values(obj)[0] || prompt | ||
| } | ||
| } catch { | ||
| // 不是 JSON,纯文本直接返回 | ||
| } | ||
| return prompt | ||
| } | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Align resolveSystemPromptText language fallback order with the backend.
The frontend resolver prioritizes zh → en → first, while the backend's resolveModelSystemPrompt (in relay/helper/system_prompt.go) falls back en → zh → first. For a prompt like {"en":"Hello","zh":"你好"}, the tooltip shows Chinese but a non-Chinese user receives English at request time. Aligning the fallback order to en → zh → first would make the tooltip preview more representative.
💚 Proposed fix
function resolveSystemPromptText(prompt: string): string {
try {
const obj = JSON.parse(prompt)
if (typeof obj === 'object' && obj !== null) {
- return obj['zh'] || obj['en'] || Object.values(obj)[0] || prompt
+ return obj['en'] || obj['zh'] || Object.values(obj)[0] || prompt
}
} catch {
// 不是 JSON,纯文本直接返回
}
return prompt
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // 解析多语言系统提示词文本,优先中文 | |
| function resolveSystemPromptText(prompt: string): string { | |
| try { | |
| const obj = JSON.parse(prompt) | |
| if (typeof obj === 'object' && obj !== null) { | |
| return obj['zh'] || obj['en'] || Object.values(obj)[0] || prompt | |
| } | |
| } catch { | |
| // 不是 JSON,纯文本直接返回 | |
| } | |
| return prompt | |
| } | |
| // 解析多语言系统提示词文本,优先中文 | |
| function resolveSystemPromptText(prompt: string): string { | |
| try { | |
| const obj = JSON.parse(prompt) | |
| if (typeof obj === 'object' && obj !== null) { | |
| return obj['en'] || obj['zh'] || Object.values(obj)[0] || prompt | |
| } | |
| } catch { | |
| // 不是 JSON,纯文本直接返回 | |
| } | |
| return prompt | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/default/src/features/models/components/models-columns.tsx` around lines
53 - 65, Update resolveSystemPromptText to match the backend fallback order:
prefer the “en” value, then “zh”, then the first object value, and finally the
original prompt. Keep the existing JSON parsing and plain-text behavior
unchanged.
功能说明
在模型管理页面为每个模型添加自定义系统提示词配置,支持多语言。
改动内容
后端
models表新增system_prompt(TEXT) 和system_prompt_mode(INT) 字段{"en":"...","zh":"..."},按用户语言自动匹配前端
/models/metadata新增 System Prompt 列,鼠标悬停查看内容处理优先级
请求 → 模型级 System Prompt → 渠道级 System Prompt → 发送上游
向后兼容
不配置时(mode=0)无任何影响,与原来完全一致。
Summary by CodeRabbit