Skip to content

[BUG]deepseek-stream.ts 中 SEARCH 控制标记无条件过滤问题 #142

@2256593769

Description

@2256593769

问题描述

使用非 search 模型(如 deepseek-chat)且未启用 web_search 时,若模型回答中的单词 search / Search / SEARCH 正好出现在某个 SSE 内容片段的开头,会被正则无条件剥离,导致回答内容丢失。该行为会影响到ClaudeCode的search功能。

复现步骤

  1. 使用 deepseek-chat 模型(禁用 web search)
  2. 发送消息:你能输出search这个单词吗
  3. 模型回复:当然可以,这个单词就是:("search" 被剥离)

根因

src/main/proxy/adapters/deepseek-stream.ts 在以下 5 个位置使用正则 /^(SEARCH|WEB_SEARCH|SEARCHING)\s*/i 过滤内容片段开头的控制标记,未加任何条件守卫

# 方法 行号(原) 触发条件
1 sendContent 243 每个内容片段
2 handleNonStream 389 片段类型 fragment
3 handleNonStream 403 response/fragments
4 handleNonStream 440 数组内嵌内容
5 handleNonStream 452 字符串内容

这些 SEARCH / WEB_SEARCH / SEARCHINGDeepSeek 启用联网搜索后 在响应中插入的状态标记。当不使用联网搜索时,这些标记从不出现,正则不应执行。
正则的 i 标志导致大小写不敏感匹配,因此自然语言中的 search Search SEARCH 如果恰好在一个内容片段开头,就会被误判为控制标记而剥离。

修复方案

在过滤前增加条件判断:仅在实际启用了联网搜索时才执行 SEARCH 标记过滤。

条件

this.webSearchEnabled || this.model.includes('search')
修改要点
sendContent 方法(第 243 行):
// Before:
const filteredForSearch = cleanedValue.replace(/^(SEARCH|WEB_SEARCH|SEARCHING)\s*/i, '')
// After:
const shouldFilterSearch = this.webSearchEnabled || this.model.includes('search')
const filteredForSearch = shouldFilterSearch
  ? cleanedValue.replace(/^(SEARCH|WEB_SEARCH|SEARCHING)\s*/i, '')
  : cleanedValue
handleNonStream 方法(第 358 行新增标志):
const isSearchModel = this.model.includes('search') || this.webSearchEnabled
handleNonStream 中其余 4 处过滤(第 389、403、440、452 行):
// Before:
cleanedFragment = cleanedFragment.replace(/^(SEARCH|WEB_SEARCH|SEARCHING)\s*/i, '')
// After:
if (isSearchModel) {
  cleanedFragment = cleanedFragment.replace(/^(SEARCH|WEB_SEARCH|SEARCHING)\s*/i, '')
}

修复提交:309c1d2

PR:#141

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions