feat(openai): 极致优化 OAuth 链路并补齐性能守护
- 优化 /v1/responses 热路径,减少重复解析与不必要拷贝\n- 优化并发与 token 竞争路径并补齐运行指标\n- 补充 OpenAI/Ops 相关单元测试与回归用例\n- 新增灰度阈值守护与压测脚本,支撑发布验收
This commit is contained in:
@@ -1416,3 +1416,109 @@ func TestReplaceModelInResponseBody(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractOpenAISSEDataLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
line string
|
||||
wantData string
|
||||
wantOK bool
|
||||
}{
|
||||
{name: "标准格式", line: `data: {"type":"x"}`, wantData: `{"type":"x"}`, wantOK: true},
|
||||
{name: "无空格格式", line: `data:{"type":"x"}`, wantData: `{"type":"x"}`, wantOK: true},
|
||||
{name: "纯空数据", line: `data: `, wantData: ``, wantOK: true},
|
||||
{name: "非 data 行", line: `event: message`, wantData: ``, wantOK: false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, ok := extractOpenAISSEDataLine(tt.line)
|
||||
require.Equal(t, tt.wantOK, ok)
|
||||
require.Equal(t, tt.wantData, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSSEUsage_SelectiveParsing(t *testing.T) {
|
||||
svc := &OpenAIGatewayService{}
|
||||
usage := &OpenAIUsage{InputTokens: 9, OutputTokens: 8, CacheReadInputTokens: 7}
|
||||
|
||||
// 非 completed 事件,不应覆盖 usage
|
||||
svc.parseSSEUsage(`{"type":"response.in_progress","response":{"usage":{"input_tokens":1,"output_tokens":2}}}`, usage)
|
||||
require.Equal(t, 9, usage.InputTokens)
|
||||
require.Equal(t, 8, usage.OutputTokens)
|
||||
require.Equal(t, 7, usage.CacheReadInputTokens)
|
||||
|
||||
// completed 事件,应提取 usage
|
||||
svc.parseSSEUsage(`{"type":"response.completed","response":{"usage":{"input_tokens":3,"output_tokens":5,"input_tokens_details":{"cached_tokens":2}}}}`, usage)
|
||||
require.Equal(t, 3, usage.InputTokens)
|
||||
require.Equal(t, 5, usage.OutputTokens)
|
||||
require.Equal(t, 2, usage.CacheReadInputTokens)
|
||||
}
|
||||
|
||||
func TestExtractCodexFinalResponse_SampleReplay(t *testing.T) {
|
||||
body := strings.Join([]string{
|
||||
`event: message`,
|
||||
`data: {"type":"response.in_progress","response":{"id":"resp_1"}}`,
|
||||
`data: {"type":"response.completed","response":{"id":"resp_1","model":"gpt-4o","usage":{"input_tokens":11,"output_tokens":22,"input_tokens_details":{"cached_tokens":3}}}}`,
|
||||
`data: [DONE]`,
|
||||
}, "\n")
|
||||
|
||||
finalResp, ok := extractCodexFinalResponse(body)
|
||||
require.True(t, ok)
|
||||
require.Contains(t, string(finalResp), `"id":"resp_1"`)
|
||||
require.Contains(t, string(finalResp), `"input_tokens":11`)
|
||||
}
|
||||
|
||||
func TestHandleOAuthSSEToJSON_CompletedEventReturnsJSON(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
rec := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(rec)
|
||||
c.Request = httptest.NewRequest(http.MethodPost, "/", nil)
|
||||
|
||||
svc := &OpenAIGatewayService{cfg: &config.Config{}}
|
||||
resp := &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: http.Header{"Content-Type": []string{"text/event-stream"}},
|
||||
}
|
||||
body := []byte(strings.Join([]string{
|
||||
`data: {"type":"response.in_progress","response":{"id":"resp_2"}}`,
|
||||
`data: {"type":"response.completed","response":{"id":"resp_2","model":"gpt-4o","usage":{"input_tokens":7,"output_tokens":9,"input_tokens_details":{"cached_tokens":1}}}}`,
|
||||
`data: [DONE]`,
|
||||
}, "\n"))
|
||||
|
||||
usage, err := svc.handleOAuthSSEToJSON(resp, c, body, "gpt-4o", "gpt-4o")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, usage)
|
||||
require.Equal(t, 7, usage.InputTokens)
|
||||
require.Equal(t, 9, usage.OutputTokens)
|
||||
require.Equal(t, 1, usage.CacheReadInputTokens)
|
||||
// Header 可能由上游 Content-Type 透传;关键是 body 已转换为最终 JSON 响应。
|
||||
require.NotContains(t, rec.Body.String(), "event:")
|
||||
require.Contains(t, rec.Body.String(), `"id":"resp_2"`)
|
||||
require.NotContains(t, rec.Body.String(), "data:")
|
||||
}
|
||||
|
||||
func TestHandleOAuthSSEToJSON_NoFinalResponseKeepsSSEBody(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
rec := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(rec)
|
||||
c.Request = httptest.NewRequest(http.MethodPost, "/", nil)
|
||||
|
||||
svc := &OpenAIGatewayService{cfg: &config.Config{}}
|
||||
resp := &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: http.Header{"Content-Type": []string{"text/event-stream"}},
|
||||
}
|
||||
body := []byte(strings.Join([]string{
|
||||
`data: {"type":"response.in_progress","response":{"id":"resp_3"}}`,
|
||||
`data: [DONE]`,
|
||||
}, "\n"))
|
||||
|
||||
usage, err := svc.handleOAuthSSEToJSON(resp, c, body, "gpt-4o", "gpt-4o")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, usage)
|
||||
require.Equal(t, 0, usage.InputTokens)
|
||||
require.Contains(t, rec.Header().Get("Content-Type"), "text/event-stream")
|
||||
require.Contains(t, rec.Body.String(), `data: {"type":"response.in_progress"`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user