feat: add compatibility setting to strip reference markers from model output and update stream handlers accordingly

This commit is contained in:
CJACK
2026-04-05 00:50:30 +08:00
parent a6836455dc
commit c9201174f6
62 changed files with 7831 additions and 1105 deletions

View File

@@ -28,7 +28,8 @@
"o3": "deepseek-reasoner"
},
"compat": {
"wide_input_strict_output": true
"wide_input_strict_output": true,
"strip_reference_markers": true
},
"toolcall": {
"mode": "feature_match",

View File

@@ -1,8 +1,10 @@
# DeepSeek SSE 流格式字段分析(2026-04-03
# DeepSeek SSE 流格式字段分析(永久默认样本
> 日期2026-04-03UTC
> 日期2026-04-05UTC
>
> 样本:`tests/raw_stream_samples/guangzhou-weather-reasoner-search-20260403/upstream.stream.sse`
> 默认样本:
> - `tests/raw_stream_samples/guangzhou-weather-reasoner-search-20260404/upstream.stream.sse`
> - `tests/raw_stream_samples/content-filter-trigger-20260405-jwt3/upstream.stream.sse`
>
> 模型:`deepseek-reasoner-search`(搜索 + 思考)
@@ -69,13 +71,28 @@ data: <json or text>
1. 跳过所有 `response/fragments/-?\d+/status`
2. 继续保留 `response/status=FINISHED` 作为真正结束判定。
3. 通过独立仿真工具持续回放全部样本,作为回归门禁:
3. 通过独立仿真工具持续回放 manifest 声明的 canonical 默认样本,作为回归门禁:
```bash
./tests/scripts/run-raw-stream-sim.sh
```
## 6. 后续扩展建议
## 6. `CONTENT_FILTER` 终态样本
`content-filter-trigger-20260405-jwt3` 样本中,末尾会出现一组明确的风控终态字段:
- `response.status = CONTENT_FILTER`
- `response.quasi_status = CONTENT_FILTER`
- `response.fragments` 里包含 `TEMPLATE_RESPONSE` 拒答文案
- 后续仍会有 `event: finish`
这说明:
1. 风控不是“没有结束信号”,而是“正常流式输出后在尾部切换到风控终态”。
2. 适配层不能把 `TEMPLATE_RESPONSE` 当普通正文输出。
3. 回放工具需要把这种终态保留下来,用于后续回归和字段分析。
## 7. 后续扩展建议
- 增加不同模型(`deepseek-chat-search` / 非 search / 非 thinking样本。
- 增加异常样本限流、中断、content_filter、空结果

View File

@@ -233,7 +233,7 @@ go run ./cmd/ds2api-tests --no-preflight
```
说明:
- 该工具重放 `tests/raw_stream_samples` 下全部样本,按上游 SSE 顺序做 1:1 仿真解析。
- 该工具默认重放 `tests/raw_stream_samples/manifest.json` 声明的 canonical 样本,按上游 SSE 顺序做 1:1 仿真解析。
- 默认校验不出现 `FINISHED` 文本泄露,并要求存在结束信号。
- 结果会写入 `artifacts/raw-stream-sim/*.json`,可供其他测试脚本或排障流程复用。

View File

@@ -22,6 +22,7 @@ type DeepSeekCaller interface {
type ConfigReader interface {
ClaudeMapping() map[string]string
CompatStripReferenceMarkers() bool
}
type OpenAIChatRunner interface {

View File

@@ -7,6 +7,7 @@ type mockClaudeConfig struct {
}
func (m mockClaudeConfig) ClaudeMapping() map[string]string { return m.m }
func (mockClaudeConfig) CompatStripReferenceMarkers() bool { return true }
func TestNormalizeClaudeRequestUsesConfigInterfaceMapping(t *testing.T) {
req := map[string]any{

View File

@@ -149,6 +149,7 @@ func (h *Handler) handleClaudeStreamRealtime(w http.ResponseWriter, r *http.Requ
messages,
thinkingEnabled,
searchEnabled,
h.compatStripReferenceMarkers(),
toolNames,
)
streamRuntime.sendMessageStart()

View File

@@ -21,6 +21,13 @@ type Handler struct {
OpenAI OpenAIChatRunner
}
func (h *Handler) compatStripReferenceMarkers() bool {
if h == nil || h.Store == nil {
return true
}
return h.Store.CompatStripReferenceMarkers()
}
var (
claudeStreamPingInterval = time.Duration(deepseek.KeepAliveTimeout) * time.Second
claudeStreamIdleTimeout = time.Duration(deepseek.StreamIdleTimeout) * time.Second

View File

@@ -0,0 +1,13 @@
package claude
import textclean "ds2api/internal/textclean"
func cleanVisibleOutput(text string, stripReferenceMarkers bool) string {
if text == "" {
return text
}
if stripReferenceMarkers {
text = textclean.StripReferenceMarkers(text)
}
return text
}

View File

@@ -16,6 +16,8 @@ func (s claudeProxyStoreStub) ClaudeMapping() map[string]string {
return s.mapping
}
func (claudeProxyStoreStub) CompatStripReferenceMarkers() bool { return true }
type openAIProxyStub struct {
status int
body string

View File

@@ -19,13 +19,14 @@ type claudeStreamRuntime struct {
toolNames []string
messages []any
thinkingEnabled bool
searchEnabled bool
bufferToolContent bool
thinkingEnabled bool
searchEnabled bool
bufferToolContent bool
stripReferenceMarkers bool
messageID string
thinking strings.Builder
text strings.Builder
messageID string
thinking strings.Builder
text strings.Builder
outputTokens int
nextBlockIndex int
@@ -45,21 +46,23 @@ func newClaudeStreamRuntime(
messages []any,
thinkingEnabled bool,
searchEnabled bool,
stripReferenceMarkers bool,
toolNames []string,
) *claudeStreamRuntime {
return &claudeStreamRuntime{
w: w,
rc: rc,
canFlush: canFlush,
model: model,
messages: messages,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
bufferToolContent: len(toolNames) > 0,
toolNames: toolNames,
messageID: fmt.Sprintf("msg_%d", time.Now().UnixNano()),
thinkingBlockIndex: -1,
textBlockIndex: -1,
w: w,
rc: rc,
canFlush: canFlush,
model: model,
messages: messages,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
bufferToolContent: len(toolNames) > 0,
stripReferenceMarkers: stripReferenceMarkers,
toolNames: toolNames,
messageID: fmt.Sprintf("msg_%d", time.Now().UnixNano()),
thinkingBlockIndex: -1,
textBlockIndex: -1,
}
}
@@ -80,10 +83,11 @@ func (s *claudeStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
contentSeen := false
for _, p := range parsed.Parts {
if p.Text == "" {
cleanedText := cleanVisibleOutput(p.Text, s.stripReferenceMarkers)
if cleanedText == "" {
continue
}
if p.Type != "thinking" && s.searchEnabled && sse.IsCitation(p.Text) {
if p.Type != "thinking" && s.searchEnabled && sse.IsCitation(cleanedText) {
continue
}
contentSeen = true
@@ -92,7 +96,7 @@ func (s *claudeStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
if !s.thinkingEnabled {
continue
}
s.thinking.WriteString(p.Text)
s.thinking.WriteString(cleanedText)
s.closeTextBlock()
if !s.thinkingBlockOpen {
s.thinkingBlockIndex = s.nextBlockIndex
@@ -112,13 +116,13 @@ func (s *claudeStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
"index": s.thinkingBlockIndex,
"delta": map[string]any{
"type": "thinking_delta",
"thinking": p.Text,
"thinking": cleanedText,
},
})
continue
}
s.text.WriteString(p.Text)
s.text.WriteString(cleanedText)
if s.bufferToolContent {
if hasUnclosedCodeFence(s.text.String()) {
continue
@@ -144,7 +148,7 @@ func (s *claudeStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
"index": s.textBlockIndex,
"delta": map[string]any{
"type": "text_delta",
"text": p.Text,
"text": cleanedText,
},
})
}

View File

@@ -43,7 +43,7 @@ func (s *claudeStreamRuntime) finalize(stopReason string) {
s.closeTextBlock()
finalThinking := s.thinking.String()
finalText := s.text.String()
finalText := cleanVisibleOutput(s.text.String(), s.stripReferenceMarkers)
if s.bufferToolContent {
detected := util.ParseStandaloneToolCalls(finalText, s.toolNames)
@@ -64,7 +64,7 @@ func (s *claudeStreamRuntime) finalize(stopReason string) {
"input": map[string]any{},
},
})
inputBytes, _ := json.Marshal(tc.Input)
s.send("content_block_delta", map[string]any{
"type": "content_block_delta",

View File

@@ -28,6 +28,8 @@ func (streamStatusClaudeStoreStub) ClaudeMapping() map[string]string {
}
}
func (streamStatusClaudeStoreStub) CompatStripReferenceMarkers() bool { return true }
func captureClaudeStatusMiddleware(statuses *[]int) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@@ -22,6 +22,7 @@ type DeepSeekCaller interface {
type ConfigReader interface {
ModelAliases() map[string]string
CompatStripReferenceMarkers() bool
}
type OpenAIChatRunner interface {

View File

@@ -140,7 +140,15 @@ func (h *Handler) handleNonStreamGenerateContent(w http.ResponseWriter, resp *ht
}
result := sse.CollectStream(resp, thinkingEnabled, true)
writeJSON(w, http.StatusOK, buildGeminiGenerateContentResponse(model, finalPrompt, result.Thinking, result.Text, toolNames, result.OutputTokens))
stripReferenceMarkers := h.compatStripReferenceMarkers()
writeJSON(w, http.StatusOK, buildGeminiGenerateContentResponse(
model,
finalPrompt,
cleanVisibleOutput(result.Thinking, stripReferenceMarkers),
cleanVisibleOutput(result.Text, stripReferenceMarkers),
toolNames,
result.OutputTokens,
))
}
func buildGeminiGenerateContentResponse(model, finalPrompt, finalThinking, finalText string, toolNames []string, outputTokens int) map[string]any {
@@ -179,7 +187,7 @@ func buildGeminiUsage(finalPrompt, finalThinking, finalText string, outputTokens
func buildGeminiPartsFromFinal(finalText, finalThinking string, toolNames []string) []map[string]any {
detected := util.ParseToolCalls(finalText, toolNames)
if len(detected) == 0 && strings.TrimSpace(finalThinking) != "" {
if len(detected) == 0 && finalThinking != "" {
detected = util.ParseToolCalls(finalThinking, toolNames)
}
if len(detected) > 0 {
@@ -196,7 +204,7 @@ func buildGeminiPartsFromFinal(finalText, finalThinking string, toolNames []stri
}
text := finalText
if strings.TrimSpace(text) == "" {
if text == "" {
text = finalThinking
}
return []map[string]any{{"text": text}}

View File

@@ -17,6 +17,13 @@ type Handler struct {
OpenAI OpenAIChatRunner
}
func (h *Handler) compatStripReferenceMarkers() bool {
if h == nil || h.Store == nil {
return true
}
return h.Store.CompatStripReferenceMarkers()
}
func RegisterRoutes(r chi.Router, h *Handler) {
r.Post("/v1beta/models/{model}:generateContent", h.GenerateContent)
r.Post("/v1beta/models/{model}:streamGenerateContent", h.StreamGenerateContent)

View File

@@ -27,7 +27,7 @@ func (h *Handler) handleStreamGenerateContent(w http.ResponseWriter, r *http.Req
rc := http.NewResponseController(w)
_, canFlush := w.(http.Flusher)
runtime := newGeminiStreamRuntime(w, rc, canFlush, model, finalPrompt, thinkingEnabled, searchEnabled, toolNames)
runtime := newGeminiStreamRuntime(w, rc, canFlush, model, finalPrompt, thinkingEnabled, searchEnabled, h.compatStripReferenceMarkers(), toolNames)
initialType := "text"
if thinkingEnabled {
@@ -57,13 +57,14 @@ type geminiStreamRuntime struct {
model string
finalPrompt string
thinkingEnabled bool
searchEnabled bool
bufferContent bool
toolNames []string
thinkingEnabled bool
searchEnabled bool
bufferContent bool
stripReferenceMarkers bool
toolNames []string
thinking strings.Builder
text strings.Builder
thinking strings.Builder
text strings.Builder
outputTokens int
}
@@ -75,18 +76,20 @@ func newGeminiStreamRuntime(
finalPrompt string,
thinkingEnabled bool,
searchEnabled bool,
stripReferenceMarkers bool,
toolNames []string,
) *geminiStreamRuntime {
return &geminiStreamRuntime{
w: w,
rc: rc,
canFlush: canFlush,
model: model,
finalPrompt: finalPrompt,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
bufferContent: len(toolNames) > 0,
toolNames: toolNames,
w: w,
rc: rc,
canFlush: canFlush,
model: model,
finalPrompt: finalPrompt,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
bufferContent: len(toolNames) > 0,
stripReferenceMarkers: stripReferenceMarkers,
toolNames: toolNames,
}
}
@@ -113,20 +116,21 @@ func (s *geminiStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
contentSeen := false
for _, p := range parsed.Parts {
if p.Text == "" {
cleanedText := cleanVisibleOutput(p.Text, s.stripReferenceMarkers)
if cleanedText == "" {
continue
}
if p.Type != "thinking" && s.searchEnabled && sse.IsCitation(p.Text) {
if p.Type != "thinking" && s.searchEnabled && sse.IsCitation(cleanedText) {
continue
}
contentSeen = true
if p.Type == "thinking" {
if s.thinkingEnabled {
s.thinking.WriteString(p.Text)
s.thinking.WriteString(cleanedText)
}
continue
}
s.text.WriteString(p.Text)
s.text.WriteString(cleanedText)
if s.bufferContent {
continue
}
@@ -136,7 +140,7 @@ func (s *geminiStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
"index": 0,
"content": map[string]any{
"role": "model",
"parts": []map[string]any{{"text": p.Text}},
"parts": []map[string]any{{"text": cleanedText}},
},
},
},
@@ -148,7 +152,7 @@ func (s *geminiStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Parse
func (s *geminiStreamRuntime) finalize() {
finalThinking := s.thinking.String()
finalText := s.text.String()
finalText := cleanVisibleOutput(s.text.String(), s.stripReferenceMarkers)
if s.bufferContent {
parts := buildGeminiPartsFromFinal(finalText, finalThinking, s.toolNames)

View File

@@ -17,7 +17,8 @@ import (
type testGeminiConfig struct{}
func (testGeminiConfig) ModelAliases() map[string]string { return nil }
func (testGeminiConfig) ModelAliases() map[string]string { return nil }
func (testGeminiConfig) CompatStripReferenceMarkers() bool { return true }
type testGeminiAuth struct {
a *auth.RequestAuth
@@ -62,8 +63,8 @@ func (m testGeminiDS) CallCompletion(_ context.Context, _ *auth.RequestAuth, _ m
}
type geminiOpenAIErrorStub struct {
status int
body string
status int
body string
headers map[string]string
}
@@ -247,7 +248,7 @@ func TestStreamGenerateContentEmitsSSE(t *testing.T) {
func TestGenerateContentOpenAIProxyErrorUsesGeminiEnvelope(t *testing.T) {
h := &Handler{
Store: testGeminiConfig{},
Store: testGeminiConfig{},
OpenAI: geminiOpenAIErrorStub{
status: http.StatusUnauthorized,
body: `{"error":{"message":"invalid api key"}}`,

View File

@@ -0,0 +1,13 @@
package gemini
import textclean "ds2api/internal/textclean"
func cleanVisibleOutput(text string, stripReferenceMarkers bool) string {
if text == "" {
return text
}
if stripReferenceMarkers {
text = textclean.StripReferenceMarkers(text)
}
return text
}

View File

@@ -22,8 +22,9 @@ type chatStreamRuntime struct {
finalPrompt string
toolNames []string
thinkingEnabled bool
searchEnabled bool
thinkingEnabled bool
searchEnabled bool
stripReferenceMarkers bool
firstChunkSent bool
bufferToolContent bool
@@ -49,25 +50,27 @@ func newChatStreamRuntime(
finalPrompt string,
thinkingEnabled bool,
searchEnabled bool,
stripReferenceMarkers bool,
toolNames []string,
bufferToolContent bool,
emitEarlyToolDeltas bool,
) *chatStreamRuntime {
return &chatStreamRuntime{
w: w,
rc: rc,
canFlush: canFlush,
completionID: completionID,
created: created,
model: model,
finalPrompt: finalPrompt,
toolNames: toolNames,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
bufferToolContent: bufferToolContent,
emitEarlyToolDeltas: emitEarlyToolDeltas,
streamToolCallIDs: map[int]string{},
streamToolNames: map[int]string{},
w: w,
rc: rc,
canFlush: canFlush,
completionID: completionID,
created: created,
model: model,
finalPrompt: finalPrompt,
toolNames: toolNames,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
stripReferenceMarkers: stripReferenceMarkers,
bufferToolContent: bufferToolContent,
emitEarlyToolDeltas: emitEarlyToolDeltas,
streamToolCallIDs: map[int]string{},
streamToolNames: map[int]string{},
}
}
@@ -98,7 +101,7 @@ func (s *chatStreamRuntime) sendDone() {
func (s *chatStreamRuntime) finalize(finishReason string) {
finalThinking := s.thinking.String()
finalText := sanitizeLeakedOutput(s.text.String())
finalText := cleanVisibleOutput(s.text.String(), s.stripReferenceMarkers)
detected := util.ParseStandaloneToolCallsDetailed(finalText, s.toolNames)
if len(detected.Calls) > 0 && !s.toolCallsDoneEmitted {
finishReason = "tool_calls"
@@ -142,7 +145,7 @@ func (s *chatStreamRuntime) finalize(finishReason string) {
if evt.Content == "" {
continue
}
cleaned := sanitizeLeakedOutput(evt.Content)
cleaned := cleanVisibleOutput(evt.Content, s.stripReferenceMarkers)
if cleaned == "" {
continue
}
@@ -203,10 +206,11 @@ func (s *chatStreamRuntime) onParsed(parsed sse.LineResult) streamengine.ParsedD
newChoices := make([]map[string]any, 0, len(parsed.Parts))
contentSeen := false
for _, p := range parsed.Parts {
if s.searchEnabled && sse.IsCitation(p.Text) {
cleanedText := cleanVisibleOutput(p.Text, s.stripReferenceMarkers)
if s.searchEnabled && sse.IsCitation(cleanedText) {
continue
}
if p.Text == "" {
if cleanedText == "" {
continue
}
contentSeen = true
@@ -217,15 +221,15 @@ func (s *chatStreamRuntime) onParsed(parsed sse.LineResult) streamengine.ParsedD
}
if p.Type == "thinking" {
if s.thinkingEnabled {
s.thinking.WriteString(p.Text)
delta["reasoning_content"] = p.Text
s.thinking.WriteString(cleanedText)
delta["reasoning_content"] = cleanedText
}
} else {
s.text.WriteString(p.Text)
s.text.WriteString(cleanedText)
if !s.bufferToolContent {
delta["content"] = p.Text
delta["content"] = cleanedText
} else {
events := processToolSieveChunk(&s.toolSieve, p.Text, s.toolNames)
events := processToolSieveChunk(&s.toolSieve, cleanedText, s.toolNames)
for _, evt := range events {
if len(evt.ToolCallDeltas) > 0 {
if !s.emitEarlyToolDeltas {
@@ -264,7 +268,7 @@ func (s *chatStreamRuntime) onParsed(parsed sse.LineResult) streamengine.ParsedD
continue
}
if evt.Content != "" {
cleaned := sanitizeLeakedOutput(evt.Content)
cleaned := cleanVisibleOutput(evt.Content, s.stripReferenceMarkers)
if cleaned == "" {
continue
}

View File

@@ -25,6 +25,7 @@ type DeepSeekCaller interface {
type ConfigReader interface {
ModelAliases() map[string]string
CompatWideInputStrictOutput() bool
CompatStripReferenceMarkers() bool
ToolcallMode() string
ToolcallEarlyEmitConfidence() string
ResponsesStoreTTLSeconds() int

View File

@@ -15,6 +15,7 @@ func (m mockOpenAIConfig) ModelAliases() map[string]string { return m.aliases }
func (m mockOpenAIConfig) CompatWideInputStrictOutput() bool {
return m.wideInput
}
func (m mockOpenAIConfig) CompatStripReferenceMarkers() bool { return true }
func (m mockOpenAIConfig) ToolcallMode() string { return m.toolMode }
func (m mockOpenAIConfig) ToolcallEarlyEmitConfidence() string { return m.earlyEmit }
func (m mockOpenAIConfig) ResponsesStoreTTLSeconds() int { return m.responsesTTL }

View File

@@ -104,9 +104,10 @@ func (h *Handler) handleNonStream(w http.ResponseWriter, ctx context.Context, re
_ = ctx
result := sse.CollectStream(resp, thinkingEnabled, true)
finalThinking := result.Thinking
finalText := sanitizeLeakedOutput(result.Text)
if writeUpstreamEmptyOutputError(w, result) {
stripReferenceMarkers := h.compatStripReferenceMarkers()
finalThinking := cleanVisibleOutput(result.Thinking, stripReferenceMarkers)
finalText := cleanVisibleOutput(result.Text, stripReferenceMarkers)
if writeUpstreamEmptyOutputError(w, finalThinking, finalText, result.ContentFilter) {
return
}
respBody := openaifmt.BuildChatCompletion(completionID, model, finalPrompt, finalThinking, finalText, toolNames)
@@ -141,6 +142,7 @@ func (h *Handler) handleStream(w http.ResponseWriter, r *http.Request, resp *htt
created := time.Now().Unix()
bufferToolContent := len(toolNames) > 0
emitEarlyToolDeltas := h.toolcallFeatureMatchEnabled() && h.toolcallEarlyEmitHighConfidence()
stripReferenceMarkers := h.compatStripReferenceMarkers()
initialType := "text"
if thinkingEnabled {
initialType = "thinking"
@@ -156,6 +158,7 @@ func (h *Handler) handleStream(w http.ResponseWriter, r *http.Request, resp *htt
finalPrompt,
thinkingEnabled,
searchEnabled,
stripReferenceMarkers,
toolNames,
bufferToolContent,
emitEarlyToolDeltas,

View File

@@ -28,6 +28,13 @@ type Handler struct {
responses *responseStore
}
func (h *Handler) compatStripReferenceMarkers() bool {
if h == nil || h.Store == nil {
return true
}
return h.Store.CompatStripReferenceMarkers()
}
type streamLease struct {
Auth *auth.RequestAuth
ExpiresAt time.Time

View File

@@ -0,0 +1,13 @@
package openai
import textclean "ds2api/internal/textclean"
func cleanVisibleOutput(text string, stripReferenceMarkers bool) string {
if text == "" {
return text
}
if stripReferenceMarkers {
text = textclean.StripReferenceMarkers(text)
}
return sanitizeLeakedOutput(text)
}

View File

@@ -113,8 +113,10 @@ func (h *Handler) handleResponsesNonStream(w http.ResponseWriter, resp *http.Res
return
}
result := sse.CollectStream(resp, thinkingEnabled, true)
sanitizedText := sanitizeLeakedOutput(result.Text)
if writeUpstreamEmptyOutputError(w, result) {
stripReferenceMarkers := h.compatStripReferenceMarkers()
sanitizedThinking := cleanVisibleOutput(result.Thinking, stripReferenceMarkers)
sanitizedText := cleanVisibleOutput(result.Text, stripReferenceMarkers)
if writeUpstreamEmptyOutputError(w, sanitizedThinking, sanitizedText, result.ContentFilter) {
return
}
textParsed := util.ParseStandaloneToolCallsDetailed(sanitizedText, toolNames)
@@ -126,7 +128,7 @@ func (h *Handler) handleResponsesNonStream(w http.ResponseWriter, resp *http.Res
return
}
responseObj := openaifmt.BuildResponseObject(responseID, model, finalPrompt, result.Thinking, sanitizedText, toolNames)
responseObj := openaifmt.BuildResponseObject(responseID, model, finalPrompt, sanitizedThinking, sanitizedText, toolNames)
if result.OutputTokens > 0 {
if usage, ok := responseObj["usage"].(map[string]any); ok {
usage["output_tokens"] = result.OutputTokens
@@ -159,6 +161,7 @@ func (h *Handler) handleResponsesStream(w http.ResponseWriter, r *http.Request,
}
bufferToolContent := len(toolNames) > 0
emitEarlyToolDeltas := h.toolcallFeatureMatchEnabled() && h.toolcallEarlyEmitHighConfidence()
stripReferenceMarkers := h.compatStripReferenceMarkers()
streamRuntime := newResponsesStreamRuntime(
w,
@@ -169,6 +172,7 @@ func (h *Handler) handleResponsesStream(w http.ResponseWriter, r *http.Request,
finalPrompt,
thinkingEnabled,
searchEnabled,
stripReferenceMarkers,
toolNames,
bufferToolContent,
emitEarlyToolDeltas,

View File

@@ -23,8 +23,9 @@ type responsesStreamRuntime struct {
traceID string
toolChoice util.ToolChoicePolicy
thinkingEnabled bool
searchEnabled bool
thinkingEnabled bool
searchEnabled bool
stripReferenceMarkers bool
bufferToolContent bool
emitEarlyToolDeltas bool
@@ -63,6 +64,7 @@ func newResponsesStreamRuntime(
finalPrompt string,
thinkingEnabled bool,
searchEnabled bool,
stripReferenceMarkers bool,
toolNames []string,
bufferToolContent bool,
emitEarlyToolDeltas bool,
@@ -71,34 +73,35 @@ func newResponsesStreamRuntime(
persistResponse func(obj map[string]any),
) *responsesStreamRuntime {
return &responsesStreamRuntime{
w: w,
rc: rc,
canFlush: canFlush,
responseID: responseID,
model: model,
finalPrompt: finalPrompt,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
toolNames: toolNames,
bufferToolContent: bufferToolContent,
emitEarlyToolDeltas: emitEarlyToolDeltas,
streamToolCallIDs: map[int]string{},
functionItemIDs: map[int]string{},
functionOutputIDs: map[int]int{},
functionArgs: map[int]string{},
functionDone: map[int]bool{},
functionAdded: map[int]bool{},
functionNames: map[int]string{},
messageOutputID: -1,
toolChoice: toolChoice,
traceID: traceID,
persistResponse: persistResponse,
w: w,
rc: rc,
canFlush: canFlush,
responseID: responseID,
model: model,
finalPrompt: finalPrompt,
thinkingEnabled: thinkingEnabled,
searchEnabled: searchEnabled,
stripReferenceMarkers: stripReferenceMarkers,
toolNames: toolNames,
bufferToolContent: bufferToolContent,
emitEarlyToolDeltas: emitEarlyToolDeltas,
streamToolCallIDs: map[int]string{},
functionItemIDs: map[int]string{},
functionOutputIDs: map[int]int{},
functionArgs: map[int]string{},
functionDone: map[int]bool{},
functionAdded: map[int]bool{},
functionNames: map[int]string{},
messageOutputID: -1,
toolChoice: toolChoice,
traceID: traceID,
persistResponse: persistResponse,
}
}
func (s *responsesStreamRuntime) finalize() {
finalThinking := s.thinking.String()
finalText := sanitizeLeakedOutput(s.text.String())
finalText := cleanVisibleOutput(s.text.String(), s.stripReferenceMarkers)
if s.bufferToolContent {
s.processToolStreamEvents(flushToolSieve(&s.sieve, s.toolNames), true)
@@ -190,10 +193,11 @@ func (s *responsesStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Pa
contentSeen := false
for _, p := range parsed.Parts {
if p.Text == "" {
cleanedText := cleanVisibleOutput(p.Text, s.stripReferenceMarkers)
if cleanedText == "" {
continue
}
if p.Type != "thinking" && s.searchEnabled && sse.IsCitation(p.Text) {
if p.Type != "thinking" && s.searchEnabled && sse.IsCitation(cleanedText) {
continue
}
contentSeen = true
@@ -201,15 +205,11 @@ func (s *responsesStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Pa
if !s.thinkingEnabled {
continue
}
s.thinking.WriteString(p.Text)
s.sendEvent("response.reasoning.delta", openaifmt.BuildResponsesReasoningDeltaPayload(s.responseID, p.Text))
s.thinking.WriteString(cleanedText)
s.sendEvent("response.reasoning.delta", openaifmt.BuildResponsesReasoningDeltaPayload(s.responseID, cleanedText))
continue
}
cleanedText := sanitizeLeakedOutput(p.Text)
if cleanedText == "" {
continue
}
s.text.WriteString(cleanedText)
if !s.bufferToolContent {
s.emitTextDelta(cleanedText)

View File

@@ -69,7 +69,7 @@ func (s *responsesStreamRuntime) ensureMessageContentPartAdded() {
}
func (s *responsesStreamRuntime) emitTextDelta(content string) {
if strings.TrimSpace(content) == "" {
if content == "" {
return
}
s.ensureMessageContentPartAdded()

View File

@@ -83,13 +83,13 @@ func (s *responsesStreamRuntime) buildCompletedResponseObject(finalThinking, fin
})
} else if len(calls) == 0 {
content := make([]map[string]any, 0, 2)
if strings.TrimSpace(finalThinking) != "" {
if finalThinking != "" {
content = append(content, map[string]any{
"type": "reasoning",
"text": finalThinking,
})
}
if strings.TrimSpace(finalText) != "" {
if finalText != "" {
content = append(content, map[string]any{
"type": "output_text",
"text": finalText,
@@ -136,10 +136,10 @@ func (s *responsesStreamRuntime) buildCompletedResponseObject(finalThinking, fin
}
outputText := s.visibleText.String()
if strings.TrimSpace(outputText) == "" && len(calls) == 0 {
if strings.TrimSpace(finalText) != "" {
if outputText == "" && len(calls) == 0 {
if finalText != "" {
outputText = finalText
} else if strings.TrimSpace(finalThinking) != "" {
} else if finalThinking != "" {
outputText = finalThinking
}
}

View File

@@ -48,7 +48,7 @@ func (s *toolStreamSieveState) resetIncrementalToolState() {
}
func (s *toolStreamSieveState) noteText(content string) {
if strings.TrimSpace(content) == "" {
if content == "" {
return
}
s.recentTextTail = appendTail(s.recentTextTail, content, toolSieveContextTailLimit)

View File

@@ -1,17 +1,12 @@
package openai
import (
"net/http"
"strings"
import "net/http"
"ds2api/internal/sse"
)
func writeUpstreamEmptyOutputError(w http.ResponseWriter, result sse.CollectResult) bool {
if strings.TrimSpace(result.Thinking) != "" || strings.TrimSpace(sanitizeLeakedOutput(result.Text)) != "" {
func writeUpstreamEmptyOutputError(w http.ResponseWriter, thinking, text string, contentFilter bool) bool {
if thinking != "" || text != "" {
return false
}
if result.ContentFilter {
if contentFilter {
writeOpenAIErrorWithCode(w, http.StatusBadRequest, "Upstream content filtered the response and returned no output.", "content_filter")
return true
}

View File

@@ -99,10 +99,13 @@ func (h *Handler) handleVercelStreamPrepare(w http.ResponseWriter, r *http.Reque
"final_prompt": stdReq.FinalPrompt,
"thinking_enabled": stdReq.Thinking,
"search_enabled": stdReq.Search,
"tool_names": stdReq.ToolNames,
"deepseek_token": a.DeepSeekToken,
"pow_header": powHeader,
"payload": payload,
"compat": map[string]any{
"strip_reference_markers": h.compatStripReferenceMarkers(),
},
"tool_names": stdReq.ToolNames,
"deepseek_token": a.DeepSeekToken,
"pow_header": powHeader,
"payload": payload,
})
}

View File

@@ -32,6 +32,7 @@ type ConfigStore interface {
RuntimeAccountMaxQueue(defaultSize int) int
RuntimeGlobalMaxInflight(defaultSize int) int
RuntimeTokenRefreshIntervalHours() int
CompatStripReferenceMarkers() bool
AutoDeleteSessions() bool
}

View File

@@ -21,10 +21,11 @@ func boolFrom(v any) bool {
}
}
func parseSettingsUpdateRequest(req map[string]any) (*config.AdminConfig, *config.RuntimeConfig, *config.ResponsesConfig, *config.EmbeddingsConfig, *config.AutoDeleteConfig, map[string]string, map[string]string, error) {
func parseSettingsUpdateRequest(req map[string]any) (*config.AdminConfig, *config.RuntimeConfig, *config.CompatConfig, *config.ResponsesConfig, *config.EmbeddingsConfig, *config.AutoDeleteConfig, map[string]string, map[string]string, error) {
var (
adminCfg *config.AdminConfig
runtimeCfg *config.RuntimeConfig
compatCfg *config.CompatConfig
respCfg *config.ResponsesConfig
embCfg *config.EmbeddingsConfig
autoDeleteCfg *config.AutoDeleteConfig
@@ -37,7 +38,7 @@ func parseSettingsUpdateRequest(req map[string]any) (*config.AdminConfig, *confi
if v, exists := raw["jwt_expire_hours"]; exists {
n := intFrom(v)
if n < 1 || n > 720 {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("admin.jwt_expire_hours must be between 1 and 720")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("admin.jwt_expire_hours must be between 1 and 720")
}
cfg.JWTExpireHours = n
}
@@ -49,43 +50,56 @@ func parseSettingsUpdateRequest(req map[string]any) (*config.AdminConfig, *confi
if v, exists := raw["account_max_inflight"]; exists {
n := intFrom(v)
if n < 1 || n > 256 {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.account_max_inflight must be between 1 and 256")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.account_max_inflight must be between 1 and 256")
}
cfg.AccountMaxInflight = n
}
if v, exists := raw["account_max_queue"]; exists {
n := intFrom(v)
if n < 1 || n > 200000 {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.account_max_queue must be between 1 and 200000")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.account_max_queue must be between 1 and 200000")
}
cfg.AccountMaxQueue = n
}
if v, exists := raw["global_max_inflight"]; exists {
n := intFrom(v)
if n < 1 || n > 200000 {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.global_max_inflight must be between 1 and 200000")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.global_max_inflight must be between 1 and 200000")
}
cfg.GlobalMaxInflight = n
}
if v, exists := raw["token_refresh_interval_hours"]; exists {
n := intFrom(v)
if n < 1 || n > 720 {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.token_refresh_interval_hours must be between 1 and 720")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.token_refresh_interval_hours must be between 1 and 720")
}
cfg.TokenRefreshIntervalHours = n
}
if cfg.AccountMaxInflight > 0 && cfg.GlobalMaxInflight > 0 && cfg.GlobalMaxInflight < cfg.AccountMaxInflight {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.global_max_inflight must be >= runtime.account_max_inflight")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("runtime.global_max_inflight must be >= runtime.account_max_inflight")
}
runtimeCfg = cfg
}
if raw, ok := req["compat"].(map[string]any); ok {
cfg := &config.CompatConfig{}
if v, exists := raw["wide_input_strict_output"]; exists {
b := boolFrom(v)
cfg.WideInputStrictOutput = &b
}
if v, exists := raw["strip_reference_markers"]; exists {
b := boolFrom(v)
cfg.StripReferenceMarkers = &b
}
compatCfg = cfg
}
if raw, ok := req["responses"].(map[string]any); ok {
cfg := &config.ResponsesConfig{}
if v, exists := raw["store_ttl_seconds"]; exists {
n := intFrom(v)
if n < 30 || n > 86400 {
return nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("responses.store_ttl_seconds must be between 30 and 86400")
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("responses.store_ttl_seconds must be between 30 and 86400")
}
cfg.StoreTTLSeconds = n
}
@@ -133,5 +147,5 @@ func parseSettingsUpdateRequest(req map[string]any) (*config.AdminConfig, *confi
autoDeleteCfg = cfg
}
return adminCfg, runtimeCfg, respCfg, embCfg, autoDeleteCfg, claudeMap, aliasMap, nil
return adminCfg, runtimeCfg, compatCfg, respCfg, embCfg, autoDeleteCfg, claudeMap, aliasMap, nil
}

View File

@@ -26,6 +26,7 @@ func (h *Handler) getSettings(w http.ResponseWriter, _ *http.Request) {
"global_max_inflight": h.Store.RuntimeGlobalMaxInflight(recommended),
"token_refresh_interval_hours": h.Store.RuntimeTokenRefreshIntervalHours(),
},
"compat": snap.Compat,
"responses": snap.Responses,
"embeddings": snap.Embeddings,
"auto_delete": snap.AutoDelete,

View File

@@ -17,7 +17,7 @@ func (h *Handler) updateSettings(w http.ResponseWriter, r *http.Request) {
return
}
adminCfg, runtimeCfg, responsesCfg, embeddingsCfg, autoDeleteCfg, claudeMap, aliasMap, err := parseSettingsUpdateRequest(req)
adminCfg, runtimeCfg, compatCfg, responsesCfg, embeddingsCfg, autoDeleteCfg, claudeMap, aliasMap, err := parseSettingsUpdateRequest(req)
if err != nil {
writeJSON(w, http.StatusBadRequest, map[string]any{"detail": err.Error()})
return
@@ -49,6 +49,14 @@ func (h *Handler) updateSettings(w http.ResponseWriter, r *http.Request) {
c.Runtime.TokenRefreshIntervalHours = runtimeCfg.TokenRefreshIntervalHours
}
}
if compatCfg != nil {
if compatCfg.WideInputStrictOutput != nil {
c.Compat.WideInputStrictOutput = compatCfg.WideInputStrictOutput
}
if compatCfg.StripReferenceMarkers != nil {
c.Compat.StripReferenceMarkers = compatCfg.StripReferenceMarkers
}
}
if responsesCfg != nil && responsesCfg.StoreTTLSeconds > 0 {
c.Responses.StoreTTLSeconds = responsesCfg.StoreTTLSeconds
}

View File

@@ -35,7 +35,7 @@ func (c Config) MarshalJSON() ([]byte, error) {
if c.Runtime.AccountMaxInflight > 0 || c.Runtime.AccountMaxQueue > 0 || c.Runtime.GlobalMaxInflight > 0 || c.Runtime.TokenRefreshIntervalHours > 0 {
m["runtime"] = c.Runtime
}
if c.Compat.WideInputStrictOutput != nil {
if c.Compat.WideInputStrictOutput != nil || c.Compat.StripReferenceMarkers != nil {
m["compat"] = c.Compat
}
if c.Responses.StoreTTLSeconds > 0 {
@@ -137,6 +137,7 @@ func (c Config) Clone() Config {
Runtime: c.Runtime,
Compat: CompatConfig{
WideInputStrictOutput: cloneBoolPtr(c.Compat.WideInputStrictOutput),
StripReferenceMarkers: cloneBoolPtr(c.Compat.StripReferenceMarkers),
},
Responses: c.Responses,
Embeddings: c.Embeddings,

View File

@@ -52,6 +52,7 @@ func (c *Config) DropInvalidAccounts() {
type CompatConfig struct {
WideInputStrictOutput *bool `json:"wide_input_strict_output,omitempty"`
StripReferenceMarkers *bool `json:"strip_reference_markers,omitempty"`
}
type AdminConfig struct {

View File

@@ -97,6 +97,8 @@ func TestLowerFunction(t *testing.T) {
// ─── Config.MarshalJSON / UnmarshalJSON roundtrip ────────────────────
func TestConfigJSONRoundtrip(t *testing.T) {
trueVal := true
falseVal := false
cfg := Config{
Keys: []string{"key1", "key2"},
Accounts: []Account{{Email: "user@example.com", Password: "pass", Token: "tok"}},
@@ -107,6 +109,10 @@ func TestConfigJSONRoundtrip(t *testing.T) {
Runtime: RuntimeConfig{
TokenRefreshIntervalHours: 12,
},
Compat: CompatConfig{
WideInputStrictOutput: &trueVal,
StripReferenceMarkers: &falseVal,
},
VercelSyncHash: "hash123",
VercelSyncTime: 1234567890,
AdditionalFields: map[string]any{
@@ -136,6 +142,12 @@ func TestConfigJSONRoundtrip(t *testing.T) {
if decoded.Runtime.TokenRefreshIntervalHours != 12 {
t.Fatalf("unexpected runtime refresh interval: %#v", decoded.Runtime.TokenRefreshIntervalHours)
}
if decoded.Compat.WideInputStrictOutput == nil || !*decoded.Compat.WideInputStrictOutput {
t.Fatalf("unexpected compat wide_input_strict_output: %#v", decoded.Compat.WideInputStrictOutput)
}
if decoded.Compat.StripReferenceMarkers == nil || *decoded.Compat.StripReferenceMarkers {
t.Fatalf("unexpected compat strip_reference_markers: %#v", decoded.Compat.StripReferenceMarkers)
}
if decoded.VercelSyncHash != "hash123" {
t.Fatalf("unexpected vercel sync hash: %q", decoded.VercelSyncHash)
}
@@ -162,12 +174,16 @@ func TestConfigUnmarshalJSONPreservesUnknownFields(t *testing.T) {
// ─── Config.Clone ────────────────────────────────────────────────────
func TestConfigCloneIsDeepCopy(t *testing.T) {
falseVal := false
cfg := Config{
Keys: []string{"key1"},
Accounts: []Account{{Email: "user@test.com", Token: "token"}},
ClaudeMapping: map[string]string{
"fast": "deepseek-chat",
},
Compat: CompatConfig{
StripReferenceMarkers: &falseVal,
},
AdditionalFields: map[string]any{"custom": "value"},
}
@@ -177,6 +193,9 @@ func TestConfigCloneIsDeepCopy(t *testing.T) {
cfg.Keys[0] = "modified"
cfg.Accounts[0].Email = "modified@test.com"
cfg.ClaudeMapping["fast"] = "modified-model"
if cfg.Compat.StripReferenceMarkers != nil {
*cfg.Compat.StripReferenceMarkers = true
}
// Cloned should not be affected
if cloned.Keys[0] != "key1" {
@@ -188,6 +207,9 @@ func TestConfigCloneIsDeepCopy(t *testing.T) {
if cloned.ClaudeMapping["fast"] != "deepseek-chat" {
t.Fatalf("clone claude mapping was affected: %#v", cloned.ClaudeMapping)
}
if cloned.Compat.StripReferenceMarkers == nil || *cloned.Compat.StripReferenceMarkers {
t.Fatalf("clone compat was affected: %#v", cloned.Compat.StripReferenceMarkers)
}
}
func TestConfigCloneNilMaps(t *testing.T) {
@@ -359,6 +381,39 @@ func TestStoreCompatWideInputStrictOutputCanDisable(t *testing.T) {
}
}
func TestStoreCompatStripReferenceMarkersDefaultTrue(t *testing.T) {
t.Setenv("DS2API_CONFIG_JSON", `{"keys":["k1"],"accounts":[]}`)
store := LoadStore()
if !store.CompatStripReferenceMarkers() {
t.Fatal("expected default strip_reference_markers=true when unset")
}
}
func TestStoreCompatStripReferenceMarkersCanDisable(t *testing.T) {
t.Setenv("DS2API_CONFIG_JSON", `{"keys":["k1"],"accounts":[],"compat":{"strip_reference_markers":false}}`)
store := LoadStore()
if store.CompatStripReferenceMarkers() {
t.Fatal("expected strip_reference_markers=false when explicitly configured")
}
snap := store.Snapshot()
data, err := snap.MarshalJSON()
if err != nil {
t.Fatalf("marshal failed: %v", err)
}
var out map[string]any
if err := json.Unmarshal(data, &out); err != nil {
t.Fatalf("decode failed: %v", err)
}
rawCompat, ok := out["compat"].(map[string]any)
if !ok {
t.Fatalf("expected compat in marshaled output, got %#v", out)
}
if rawCompat["strip_reference_markers"] != false {
t.Fatalf("expected explicit false in compat, got %#v", rawCompat)
}
}
func TestStoreIsEnvBacked(t *testing.T) {
t.Setenv("DS2API_CONFIG_JSON", `{"keys":["k1"],"accounts":[]}`)
store := LoadStore()

View File

@@ -42,6 +42,15 @@ func (s *Store) CompatWideInputStrictOutput() bool {
return *s.cfg.Compat.WideInputStrictOutput
}
func (s *Store) CompatStripReferenceMarkers() bool {
s.mu.RLock()
defer s.mu.RUnlock()
if s.cfg.Compat.StripReferenceMarkers == nil {
return true
}
return *s.cfg.Compat.StripReferenceMarkers
}
func (s *Store) ToolcallMode() string {
return "feature_match"
}

View File

@@ -7,6 +7,7 @@ const {
parseChunkForContent,
extractContentRecursive,
shouldSkipPath,
stripReferenceMarkers,
} = require('./sse_parse');
const {
resolveToolcallPolicy,
@@ -100,6 +101,7 @@ module.exports.__test = {
parseChunkForContent,
extractContentRecursive,
shouldSkipPath,
stripReferenceMarkers,
asString,
resolveToolcallPolicy,
formatIncrementalToolCallDeltas,

View File

@@ -5,7 +5,7 @@ const {
SKIP_EXACT_PATHS,
} = require('../shared/deepseek-constants');
function parseChunkForContent(chunk, thinkingEnabled, currentType) {
function parseChunkForContent(chunk, thinkingEnabled, currentType, stripReferenceMarkers = true) {
if (!chunk || typeof chunk !== 'object' || !Object.prototype.hasOwnProperty.call(chunk, 'v')) {
return { parts: [], finished: false, newType: currentType };
}
@@ -26,7 +26,7 @@ function parseChunkForContent(chunk, thinkingEnabled, currentType) {
continue;
}
const fragType = asString(frag.type).toUpperCase();
const content = asString(frag.content);
const content = asContentString(frag.content, stripReferenceMarkers);
if (!content) {
continue;
}
@@ -76,14 +76,15 @@ function parseChunkForContent(chunk, thinkingEnabled, currentType) {
if (val === 'FINISHED' && (!pathValue || pathValue === 'status')) {
return { parts: [], finished: true, newType };
}
if (val) {
parts.push({ text: val, type: partType });
const content = asContentString(val, stripReferenceMarkers);
if (content) {
parts.push({ text: content, type: partType });
}
return { parts, finished: false, newType };
}
if (Array.isArray(val)) {
const extracted = extractContentRecursive(val, partType);
const extracted = extractContentRecursive(val, partType, stripReferenceMarkers);
if (extracted.finished) {
return { parts: [], finished: true, newType };
}
@@ -98,7 +99,7 @@ function parseChunkForContent(chunk, thinkingEnabled, currentType) {
if (!frag || typeof frag !== 'object') {
continue;
}
const content = asString(frag.content);
const content = asContentString(frag.content, stripReferenceMarkers);
if (!content) {
continue;
}
@@ -118,7 +119,7 @@ function parseChunkForContent(chunk, thinkingEnabled, currentType) {
return { parts, finished: false, newType };
}
function extractContentRecursive(items, defaultType) {
function extractContentRecursive(items, defaultType, stripReferenceMarkers = true) {
const parts = [];
for (const it of items) {
if (!it || typeof it !== 'object') {
@@ -135,7 +136,7 @@ function extractContentRecursive(items, defaultType) {
if (shouldSkipPath(itemPath)) {
continue;
}
const content = asString(it.content);
const content = asContentString(it.content, stripReferenceMarkers);
if (content) {
const typeName = asString(it.type).toUpperCase();
if (typeName === 'THINK' || typeName === 'THINKING') {
@@ -157,7 +158,10 @@ function extractContentRecursive(items, defaultType) {
if (typeof itemV === 'string') {
if (itemV && itemV !== 'FINISHED') {
parts.push({ text: itemV, type: partType });
const content = asContentString(itemV, stripReferenceMarkers);
if (content) {
parts.push({ text: content, type: partType });
}
}
continue;
}
@@ -168,14 +172,17 @@ function extractContentRecursive(items, defaultType) {
for (const inner of itemV) {
if (typeof inner === 'string') {
if (inner) {
parts.push({ text: inner, type: partType });
const content = asContentString(inner, stripReferenceMarkers);
if (content) {
parts.push({ text: content, type: partType });
}
}
continue;
}
if (!inner || typeof inner !== 'object') {
continue;
}
const ct = asString(inner.content);
const ct = asContentString(inner.content, stripReferenceMarkers);
if (!ct) {
continue;
}
@@ -218,6 +225,40 @@ function isCitation(text) {
return asString(text).trim().startsWith('[citation:');
}
function asContentString(v, stripReferenceMarkers = true) {
if (typeof v === 'string') {
return stripReferenceMarkers ? stripReferenceMarkersText(v) : v;
}
if (Array.isArray(v)) {
let out = '';
for (const item of v) {
out += asContentString(item, stripReferenceMarkers);
}
return out;
}
if (v && typeof v === 'object') {
if (Object.prototype.hasOwnProperty.call(v, 'content')) {
return asContentString(v.content, stripReferenceMarkers);
}
if (Object.prototype.hasOwnProperty.call(v, 'v')) {
return asContentString(v.v, stripReferenceMarkers);
}
return '';
}
if (v == null) {
return '';
}
const text = String(v);
return stripReferenceMarkers ? stripReferenceMarkersText(text) : text;
}
function stripReferenceMarkersText(text) {
if (!text) {
return text;
}
return text.replace(/\[reference:\s*\d+\]/gi, '');
}
function asString(v) {
if (typeof v === 'string') {
return v.trim();
@@ -237,4 +278,5 @@ module.exports = {
shouldSkipPath,
isFragmentStatusPath,
isCitation,
stripReferenceMarkers: stripReferenceMarkersText,
};

View File

@@ -15,6 +15,7 @@ const {
resolveToolcallPolicy,
formatIncrementalToolCallDeltas,
filterIncrementalToolCallDeltasByAllowed,
boolDefaultTrue,
} = require('./toolcall_policy');
const { createChatCompletionEmitter } = require('./stream_emitter');
const {
@@ -47,6 +48,7 @@ async function handleVercelStream(req, res, rawBody, payload) {
const toolPolicy = resolveToolcallPolicy(prep.body, payload.tools);
const toolNames = toolPolicy.toolNames;
const emitEarlyToolDeltas = toolPolicy.emitEarlyToolDeltas;
const stripReferenceMarkers = boolDefaultTrue(prep.body.compat && prep.body.compat.strip_reference_markers);
if (!model || !leaseID || !deepseekToken || !powHeader || !completionPayload) {
writeOpenAIError(res, 500, 'invalid vercel prepare response');
@@ -219,7 +221,7 @@ async function handleVercelStream(req, res, rawBody, payload) {
await finish('content_filter');
return;
}
const parsed = parseChunkForContent(chunk, thinkingEnabled, currentType);
const parsed = parseChunkForContent(chunk, thinkingEnabled, currentType, stripReferenceMarkers);
currentType = parsed.newType;
if (parsed.finished) {
await finish('stop');

View File

@@ -0,0 +1,12 @@
package textclean
import "regexp"
var referenceMarkerPattern = regexp.MustCompile(`(?i)\[reference:\s*\d+\]`)
func StripReferenceMarkers(text string) string {
if text == "" {
return text
}
return referenceMarkerPattern.ReplaceAllString(text, "")
}

View File

@@ -222,6 +222,29 @@ test('parseChunkForContent supports wrapped response.fragments object shape', ()
assert.equal(parsed.parts.map((p) => p.text).join(''), 'AB');
});
test('parseChunkForContent preserves space-only content tokens', () => {
const chunk = {
p: 'response/content',
v: ' ',
};
const parsed = parseChunkForContent(chunk, false, 'text');
assert.equal(parsed.finished, false);
assert.deepEqual(parsed.parts, [{ text: ' ', type: 'text' }]);
});
test('parseChunkForContent strips reference markers from fragment content', () => {
const chunk = {
p: 'response/fragments',
o: 'APPEND',
v: [
{ type: 'RESPONSE', content: '广州天气 [reference:12] 多云' },
],
};
const parsed = parseChunkForContent(chunk, false, 'text');
assert.equal(parsed.finished, false);
assert.deepEqual(parsed.parts, [{ text: '广州天气 多云', type: 'text' }]);
});
test('shouldSkipPath skips dynamic response/fragments/*/status paths only', () => {
assert.equal(shouldSkipPath('response/fragments/-16/status'), true);
assert.equal(shouldSkipPath('response/fragments/8/status'), true);

View File

@@ -2,6 +2,15 @@
该目录用于存放**上游真实 SSE 原始流**样本,供本地仿真测试和解析适配使用。
## 默认永久样本
仓库当前只保留两份永久默认样本:
- `guangzhou-weather-reasoner-search-20260404`:包含 `reference:N` 引用标记的天气搜索流,用于验证引用清理与正文输出。
- `content-filter-trigger-20260405-jwt3`:真实命中的 `CONTENT_FILTER` 风控流,用于验证终态处理与拒答格式。
默认回放工具会优先读取 [`manifest.json`](./manifest.json) 中的 `default_samples`,以稳定固定回放集。
## 目录规范
每个样本一个子目录:
@@ -19,10 +28,12 @@
./tests/scripts/run-raw-stream-sim.sh
```
该工具会自动遍历本目录全部样本,按真实流顺序重放并验证:
该工具默认按 `manifest.json` 中声明的永久样本重放并验证:
- 不会把上游 `status=FINISHED` 片段当正文输出(防泄露)。
- 能正确检测 `response/status=FINISHED` 流结束信号。
- 生成可归档 JSON 报告(`artifacts/raw-stream-sim/`)。
如果 `manifest.json` 不存在,则回退为遍历目录中的全部样本。
> 注意:样本可能包含搜索结果正文与引用信息,请勿放入敏感账号/密钥。

View File

@@ -0,0 +1,22 @@
{
"sample_id": "content-filter-trigger-20260405-jwt3",
"captured_at_utc": "2026-04-04T16:28:52Z",
"request": {
"model": "deepseek-reasoner-search",
"stream": true,
"messages": [
{
"role": "user",
"content": "我是历史老师,请帮我找一些一些历史书上没写的,文革期间的,但是真实记载发生的事情,尤其是派系之间的斗争,要体现历史人物的复杂性而不是单一评价立场"
}
]
},
"capture": {
"label": "deepseek_completion",
"url": "https://chat.deepseek.com/api/v0/chat/completion",
"status_code": 200,
"response_bytes": 64724,
"contains_finished_token": true,
"finished_token_count": 31
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,55 +0,0 @@
# 样本分析(广州天气 / deepseek-reasoner-search
- 样本来源:`/admin/dev/captures` 上游原始 SSE 抓包
- 采集时间UTC2026-04-03 01:28:50
- 原始字节数41043
- `FINISHED` 字符串出现次数24
- JSON `data:` chunk 数420
## 事件分布
- `ready`: 1
- `update_session`: 2
- `finish`: 1
## 高频路径Top 12
- `response/fragments/-1/content`: 13
- `response/fragments/-1`: 9
- `response`: 5
- `response/has_pending_fragment`: 4
- `response/fragments/-1/elapsed_secs`: 3
- `response/fragments/-5/status`: 2
- `response/fragments/-6/status`: 2
- `response/fragments/-3/status`: 2
- `response/fragments/-1/status`: 2
- `response/fragments/-4/status`: 2
- `response/fragments/-2/status`: 2
- `response/fragments/-5/results`: 1
## 关键泄露来源
以下状态路径会高频出现 `v=FINISHED`,如果解析器按普通文本透传,就会出现 `FINISHEDFINISHED...` 泄露:
- `response/fragments/-5/status`: 2
- `response/fragments/-6/status`: 2
- `response/fragments/-3/status`: 2
- `response/fragments/-1/status`: 2
- `response/fragments/-4/status`: 2
- `response/fragments/-2/status`: 2
- `response/fragments/-14/status`: 1
- `response/fragments/-12/status`: 1
- `response/fragments/-10/status`: 1
- `response/fragments/-9/status`: 1
- `response/fragments/-8/status`: 1
- `response/fragments/-7/status`: 1
- `response/fragments/-11/status`: 1
- `response/fragments/-16/status`: 1
- `response/fragments/-13/status`: 1
- `response/fragments/-15/status`: 1
## 适配建议
1. 跳过 `response/fragments/<index>/status`(所有 index而非仅 `-1/-2/-3`)。
2. 保留 `response/status=FINISHED` 用于结束流判定,不应当输出正文。
3. 在样本仿真测试中对全部样本执行“不得输出 `FINISHED`”断言。

View File

@@ -1,25 +0,0 @@
{
"sample_id": "guangzhou-weather-reasoner-search-20260403",
"captured_at_utc": "2026-04-03T01:28:50Z",
"request": {
"model": "deepseek-reasoner-search",
"stream": true,
"messages": [
{
"role": "user",
"content": "广州天气"
}
],
"thinking_enabled": true,
"search_enabled": true
},
"capture": {
"label": "deepseek_completion",
"url": "https://chat.deepseek.com/api/v0/chat/completion",
"status_code": 200,
"response_bytes": 41043,
"contains_finished_token": true,
"finished_token_count": 24
},
"notes": "Captured from upstream DeepSeek SSE via /admin/dev/captures with packet capture enabled. Account ID removed."
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"detail":"invalid credentials"}

View File

@@ -0,0 +1,24 @@
{
"sample_id": "guangzhou-weather-reasoner-search-20260404",
"captured_at_utc": "2026-04-04T16:01:27Z",
"request": {
"model": "deepseek-reasoner-search",
"stream": true,
"messages": [
{
"role": "user",
"content": "广州天气"
}
]
},
"capture": {
"label": "deepseek_completion",
"url": "https://chat.deepseek.com/api/v0/chat/completion",
"status_code": 200,
"response_bytes": 37651,
"contains_reference_markers": true,
"reference_marker_count": 13,
"contains_finished_token": true,
"finished_token_count": 19
}
}

View File

@@ -0,0 +1,790 @@
data: {"choices":[{"delta":{"reasoning_content":"用户","role":"assistant"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"想"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"了解"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"广州"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"的"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"情况"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"今天是"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"202"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"6"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"年"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"我需要"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"提供"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"广州"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"当前的"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"以及"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"未来的"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气预报"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"为了"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"全面"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"获取"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"信息"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"我需要"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"同时"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"进行"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"多项"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"搜索"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"涵盖"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"不同"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"时间"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"范围和"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"可能的"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"信息来源"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
: keep-alive
data: {"choices":[{"delta":{"reasoning_content":"搜索"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"结果显示"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"了一些"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"相关的"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"页面"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"为了"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"全面"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"获取"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"信息"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"我需要"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"同时"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"打开"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"这些"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"页面"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"这些"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"搜索结果"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"提供了"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"广州"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"的"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"当前"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"和"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"未来"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"预报"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"我将"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"整合"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"这些"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"信息"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"来"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"回答"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"用户"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"的问题"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"回答"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"中"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"会"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"引用"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"多个"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"来源"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"包括"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"nm"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
: keep-alive
data: {"choices":[{"delta":{"reasoning_content":"c"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":".cn"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"、"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"weather"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":".com"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":".cn"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"、"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"yz"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"q"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"xj"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":".com"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"、"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"t"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"ian"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"qi"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":".com"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"、"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"e"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"ast"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"day"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":".com"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"等"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"回答"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"将"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"涵盖"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"当前"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"、"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"未来"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"几天"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"预报"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"、"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"预警"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"信息"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"以及"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"相关"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"提示"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"reasoning_content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"广州"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"今天"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"不稳定"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"区"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"有"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"暴雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"和"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"强"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"对流"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"预警"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:0]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:1]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"未来"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"一周"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"以"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"阴"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"为主"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"特别是"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"明"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"后"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"两天"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"5"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"-"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"6"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"势"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"较大"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"今日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"中"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"到大"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"转"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多云"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"20"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"26"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃,"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"微风"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"相对"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"湿度"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"约"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"88"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"%-"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"96"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"%"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:2]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:3]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:4]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:5]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"明天"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"5"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"大到"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"暴雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"转"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雷"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"阵"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"20"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"25"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:6]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:7]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:8]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:9]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"后天"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"6"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"中"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"转"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多云"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"23"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"30"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:10]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:11]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:12]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"周二"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"7"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雷"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"阵"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"转"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多云"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"24"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
: keep-alive
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"29"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:13]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:14]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:15]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"周三"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"8"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多云"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"24"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"30"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:16]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:17]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:18]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"周四"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"9"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多云"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"23"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"31"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:19]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:20]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:21]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"*"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"周五"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"4"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"月"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"10"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"日"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"多云"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"24"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" ~"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"31"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"℃"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:22]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:23]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:24]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。\n\n"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"⚠"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":" **"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"特别"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"提醒"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"**"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"未来"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"三天"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"天气"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"非常"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"不稳定"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"出门"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"一定要注意"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"防范"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"强"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"降雨"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"和"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"雷电"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"大风"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":""},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"注意"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"安全"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:25]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:26]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:27]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"[reference:28]"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{"content":"。"},"index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk"}
data: {"choices":[{"delta":{},"finish_reason":"stop","index":0}],"created":1775318365,"id":"d9f968ed-f385-4bc5-a996-690bccd5e461","model":"deepseek-reasoner-search","object":"chat.completion.chunk","usage":{"completion_tokens":280,"completion_tokens_details":{"reasoning_tokens":173},"prompt_tokens":6,"total_tokens":286}}
data: [DONE]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
{
"version": 1,
"default_samples": [
"guangzhou-weather-reasoner-search-20260404",
"content-filter-trigger-20260405-jwt3"
],
"notes": "Canonical raw stream samples used by the default replay simulator."
}

View File

@@ -13,6 +13,7 @@ function parseArgs(argv) {
samplesRoot: 'tests/raw_stream_samples',
reportPath: '',
failOnLeak: true,
failOnReferenceLeak: true,
failOnMissingFinish: true,
};
for (let i = 2; i < argv.length; i += 1) {
@@ -23,6 +24,8 @@ function parseArgs(argv) {
out.reportPath = argv[++i];
} else if (a === '--no-fail-on-leak') {
out.failOnLeak = false;
} else if (a === '--no-fail-on-reference-leak') {
out.failOnReferenceLeak = false;
} else if (a === '--no-fail-on-missing-finish') {
out.failOnMissingFinish = false;
}
@@ -30,15 +33,55 @@ function parseArgs(argv) {
return out;
}
function findSampleDirs(root) {
if (!fs.existsSync(root)) {
return [];
function loadManifest(root) {
const manifestPath = path.join(root, 'manifest.json');
if (!fs.existsSync(manifestPath)) {
return null;
}
return fs.readdirSync(root)
try {
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
const defaultSamples = Array.isArray(manifest.default_samples)
? manifest.default_samples.map((v) => String(v).trim()).filter(Boolean)
: [];
if (defaultSamples.length === 0) {
return null;
}
return { manifestPath, defaultSamples };
} catch (err) {
throw new Error(`[sim] failed to parse ${manifestPath}: ${err.message}`);
}
}
function resolveSampleDirs(root) {
if (!fs.existsSync(root)) {
return { dirs: [], manifestPath: '' };
}
const manifest = loadManifest(root);
if (manifest) {
const dirs = [];
const missing = [];
for (const sampleID of manifest.defaultSamples) {
const dir = path.join(root, sampleID);
const ssePath = path.join(dir, 'upstream.stream.sse');
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory() || !fs.existsSync(ssePath)) {
missing.push(sampleID);
continue;
}
dirs.push(dir);
}
if (missing.length > 0) {
throw new Error(`[sim] manifest sample(s) missing: ${missing.join(', ')}`);
}
return { dirs, manifestPath: manifest.manifestPath };
}
const dirs = fs.readdirSync(root)
.map((name) => path.join(root, name))
.filter((p) => fs.statSync(p).isDirectory())
.filter((p) => fs.existsSync(path.join(p, 'upstream.stream.sse')))
.sort();
return { dirs, manifestPath: '' };
}
function parseSSE(raw) {
@@ -101,13 +144,15 @@ function replaySample(raw) {
parsedChunks,
sawFinish,
leakedFinishedText: outputText.includes('FINISHED'),
leakedReferenceMarkers: /\[reference:/i.test(outputText),
referenceLeakCount: (outputText.match(/\[reference:/gi) || []).length,
outputChars: outputText.length,
};
}
function main() {
const opts = parseArgs(process.argv);
const dirs = findSampleDirs(opts.samplesRoot);
const { dirs, manifestPath } = resolveSampleDirs(opts.samplesRoot);
if (dirs.length === 0) {
console.error(`[sim] no samples found: ${opts.samplesRoot}`);
process.exit(1);
@@ -116,11 +161,16 @@ function main() {
const report = {
generated_at: new Date().toISOString(),
samples_root: opts.samplesRoot,
manifest_path: manifestPath,
total: dirs.length,
failed: 0,
samples: [],
};
if (manifestPath) {
console.log(`[sim] using manifest ${manifestPath} samples=${dirs.length}`);
}
for (const dir of dirs) {
const sampleID = path.basename(dir);
const raw = fs.readFileSync(path.join(dir, 'upstream.stream.sse'), 'utf8');
@@ -132,6 +182,9 @@ function main() {
if (opts.failOnLeak && r.leakedFinishedText) {
errors.push('FINISHED leaked into output text');
}
if (opts.failOnReferenceLeak && r.leakedReferenceMarkers) {
errors.push('reference markers leaked into output text');
}
if (errors.length > 0) {
report.failed += 1;
}
@@ -144,8 +197,9 @@ function main() {
for (const s of report.samples) {
const status = s.ok ? 'OK' : 'FAIL';
const leakNote = s.leakedReferenceMarkers ? ` refLeaks=${s.referenceLeakCount}` : '';
const note = s.errors.length > 0 ? ` errors=${s.errors.join(';')}` : '';
console.log(`[sim] ${status} ${s.sample_id} events=${s.events} parsed=${s.parsedChunks} chars=${s.outputChars}${note}`);
console.log(`[sim] ${status} ${s.sample_id} events=${s.events} parsed=${s.parsedChunks} chars=${s.outputChars}${leakNote}${note}`);
}
if (report.failed > 0) {

View File

@@ -0,0 +1,34 @@
import { ShieldAlert } from 'lucide-react'
export default function CompatibilitySection({ t, form, setForm }) {
return (
<div className="bg-card border border-border rounded-xl p-5 space-y-4">
<div className="flex items-center gap-2">
<ShieldAlert className="w-4 h-4 text-muted-foreground" />
<h3 className="font-semibold">{t('settings.compatibilityTitle')}</h3>
</div>
<p className="text-sm text-muted-foreground">{t('settings.compatibilityDesc')}</p>
<div className="flex items-center justify-between gap-4">
<label className="text-sm font-medium">{t('settings.stripReferenceMarkers')}</label>
<button
type="button"
role="switch"
aria-checked={form.compat?.strip_reference_markers ?? true}
onClick={() => setForm((prev) => ({
...prev,
compat: { ...prev.compat, strip_reference_markers: !Boolean(prev.compat?.strip_reference_markers ?? true) },
}))}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
form.compat?.strip_reference_markers ?? true ? 'bg-primary' : 'bg-muted'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
form.compat?.strip_reference_markers ?? true ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
</div>
)
}

View File

@@ -5,6 +5,7 @@ import { useSettingsForm } from './useSettingsForm'
import SecuritySection from './SecuritySection'
import RuntimeSection from './RuntimeSection'
import BehaviorSection from './BehaviorSection'
import CompatibilitySection from './CompatibilitySection'
import AutoDeleteSection from './AutoDeleteSection'
import ModelSection from './ModelSection'
import BackupSection from './BackupSection'
@@ -94,6 +95,8 @@ export default function SettingsContainer({ onRefresh, onMessage, authFetch, onF
<BehaviorSection t={t} form={form} setForm={setForm} />
<CompatibilitySection t={t} form={form} setForm={setForm} />
<AutoDeleteSection t={t} form={form} setForm={setForm} />
<ModelSection t={t} form={form} setForm={setForm} />

View File

@@ -13,6 +13,7 @@ const MAX_AUTO_FETCH_FAILURES = 3
const DEFAULT_FORM = {
admin: { jwt_expire_hours: 24 },
runtime: { account_max_inflight: 2, account_max_queue: 10, global_max_inflight: 10, token_refresh_interval_hours: 6 },
compat: { strip_reference_markers: true },
responses: { store_ttl_seconds: 900 },
embeddings: { provider: '' },
auto_delete: { sessions: false },
@@ -46,6 +47,9 @@ function fromServerForm(data) {
global_max_inflight: Number(data.runtime?.global_max_inflight || 10),
token_refresh_interval_hours: Number(data.runtime?.token_refresh_interval_hours || 6),
},
compat: {
strip_reference_markers: data.compat?.strip_reference_markers ?? true,
},
responses: {
store_ttl_seconds: Number(data.responses?.store_ttl_seconds || 900),
},
@@ -69,6 +73,9 @@ function toServerPayload(form) {
global_max_inflight: Number(form.runtime.global_max_inflight),
token_refresh_interval_hours: Number(form.runtime.token_refresh_interval_hours),
},
compat: {
strip_reference_markers: Boolean(form.compat?.strip_reference_markers ?? true),
},
responses: { store_ttl_seconds: Number(form.responses.store_ttl_seconds) },
embeddings: { provider: String(form.embeddings.provider || '').trim() },
auto_delete: { sessions: Boolean(form.auto_delete?.sessions) },

View File

@@ -236,6 +236,9 @@
"behaviorTitle": "Behavior",
"responsesTTL": "Responses store TTL (seconds)",
"embeddingsProvider": "Embeddings provider",
"compatibilityTitle": "Compatibility",
"compatibilityDesc": "Compatibility controls that keep stream output closer to the wire format or safer for the web UI.",
"stripReferenceMarkers": "Strip [reference:N] markers",
"modelTitle": "Model mapping",
"claudeMapping": "Claude mapping (JSON)",
"modelAliases": "Model aliases (JSON)",

View File

@@ -236,6 +236,9 @@
"behaviorTitle": "行为设置",
"responsesTTL": "Responses 缓存 TTL",
"embeddingsProvider": "Embeddings Provider",
"compatibilityTitle": "兼容性设置",
"compatibilityDesc": "用于控制输出格式兼容性,避免把模型原始流里的标记直接暴露到前端。",
"stripReferenceMarkers": "移除 [reference:N] 标记",
"modelTitle": "模型映射",
"claudeMapping": "Claude 映射JSON",
"modelAliases": "模型别名JSON",