feat(ai-statistics): add system field support for Claude /v1/messages API (#3511)

This commit is contained in:
澄潭
2026-02-15 14:16:19 +08:00
committed by GitHub
parent 8e7292c42e
commit 28df33c596

View File

@@ -105,6 +105,7 @@ const (
BuiltinAnswerKey = "answer" BuiltinAnswerKey = "answer"
BuiltinToolCallsKey = "tool_calls" BuiltinToolCallsKey = "tool_calls"
BuiltinReasoningKey = "reasoning" BuiltinReasoningKey = "reasoning"
BuiltinSystemKey = "system"
BuiltinReasoningTokens = "reasoning_tokens" BuiltinReasoningTokens = "reasoning_tokens"
BuiltinCachedTokens = "cached_tokens" BuiltinCachedTokens = "cached_tokens"
BuiltinInputTokenDetails = "input_token_details" BuiltinInputTokenDetails = "input_token_details"
@@ -115,6 +116,9 @@ const (
QuestionPathOpenAI = "messages.@reverse.0.content" QuestionPathOpenAI = "messages.@reverse.0.content"
QuestionPathClaude = "messages.@reverse.0.content" // Claude uses same format QuestionPathClaude = "messages.@reverse.0.content" // Claude uses same format
// System prompt paths (from request body)
SystemPathClaude = "system" // Claude /v1/messages has system as a top-level field
// Answer paths (from response body - non-streaming) // Answer paths (from response body - non-streaming)
AnswerPathOpenAINonStreaming = "choices.0.message.content" AnswerPathOpenAINonStreaming = "choices.0.message.content"
AnswerPathClaudeNonStreaming = "content.0.text" AnswerPathClaudeNonStreaming = "content.0.text"
@@ -150,6 +154,10 @@ func getDefaultAttributes() []Attribute {
Key: BuiltinQuestionKey, Key: BuiltinQuestionKey,
ApplyToLog: true, ApplyToLog: true,
}, },
{
Key: BuiltinSystemKey,
ApplyToLog: true,
},
{ {
Key: BuiltinAnswerKey, Key: BuiltinAnswerKey,
ApplyToLog: true, ApplyToLog: true,
@@ -871,7 +879,7 @@ func setAttributeBySource(ctx wrapper.HttpContext, config AIStatisticsConfig, so
// isBuiltinAttribute checks if the given key is a built-in attribute // isBuiltinAttribute checks if the given key is a built-in attribute
func isBuiltinAttribute(key string) bool { func isBuiltinAttribute(key string) bool {
return key == BuiltinQuestionKey || key == BuiltinAnswerKey || key == BuiltinToolCallsKey || key == BuiltinReasoningKey || return key == BuiltinQuestionKey || key == BuiltinAnswerKey || key == BuiltinToolCallsKey || key == BuiltinReasoningKey || key == BuiltinSystemKey ||
key == BuiltinReasoningTokens || key == BuiltinCachedTokens || key == BuiltinReasoningTokens || key == BuiltinCachedTokens ||
key == BuiltinInputTokenDetails || key == BuiltinOutputTokenDetails key == BuiltinInputTokenDetails || key == BuiltinOutputTokenDetails
} }
@@ -880,7 +888,7 @@ func isBuiltinAttribute(key string) bool {
// Returns nil if the key is not a built-in attribute // Returns nil if the key is not a built-in attribute
func getBuiltinAttributeDefaultSources(key string) []string { func getBuiltinAttributeDefaultSources(key string) []string {
switch key { switch key {
case BuiltinQuestionKey: case BuiltinQuestionKey, BuiltinSystemKey:
return []string{RequestBody} return []string{RequestBody}
case BuiltinAnswerKey, BuiltinToolCallsKey, BuiltinReasoningKey: case BuiltinAnswerKey, BuiltinToolCallsKey, BuiltinReasoningKey:
return []string{ResponseStreamingBody, ResponseBody} return []string{ResponseStreamingBody, ResponseBody}
@@ -918,6 +926,13 @@ func getBuiltinAttributeFallback(ctx wrapper.HttpContext, config AIStatisticsCon
return value return value
} }
} }
case BuiltinSystemKey:
if source == RequestBody {
// Try Claude /v1/messages format (system is a top-level field)
if value := gjson.GetBytes(body, SystemPathClaude).Value(); value != nil && value != "" {
return value
}
}
case BuiltinAnswerKey: case BuiltinAnswerKey:
if source == ResponseStreamingBody { if source == ResponseStreamingBody {
// Try OpenAI format first // Try OpenAI format first
@@ -1069,6 +1084,9 @@ func debugLogAiLog(ctx wrapper.HttpContext) {
if question := ctx.GetUserAttribute("question"); question != nil { if question := ctx.GetUserAttribute("question"); question != nil {
userAttrs["question"] = question userAttrs["question"] = question
} }
if system := ctx.GetUserAttribute("system"); system != nil {
userAttrs["system"] = system
}
if answer := ctx.GetUserAttribute("answer"); answer != nil { if answer := ctx.GetUserAttribute("answer"); answer != nil {
userAttrs["answer"] = answer userAttrs["answer"] = answer
} }