feat: add search enhance mode switch

This commit is contained in:
kangfenmao 2025-03-19 16:59:43 +08:00
parent b89213b1ab
commit 11620828ad
14 changed files with 102 additions and 50 deletions

View File

@ -80,8 +80,8 @@ afterPack: scripts/after-pack.js
afterSign: scripts/notarize.js
releaseInfo:
releaseNotes: |
支持引文预览功能
界面显示优化
修复快捷弹窗无法对话问题
MCP修复豆包无法使用问题
MCP修复 Linux 上无法安装问题
知识库设置增加重排模型,提升知识库的准确性
自定义服务商增加兼容模式
增加 Github Copilot 服务商
PlantUML 预览支持放大和缩小
联网模式支持增强模式

View File

@ -1075,6 +1075,8 @@
"search_provider_placeholder": "Choose a search service provider.",
"search_result_default": "Default",
"search_with_time": "Search with dates included",
"enhance_mode": "Search enhance mode",
"enhance_mode_tooltip": "Use the default model to extract search keywords from the problem and search",
"tavily": {
"api_key": "Tavily API Key",
"api_key.placeholder": "Enter Tavily API Key",

View File

@ -1075,6 +1075,8 @@
"search_provider_placeholder": "検索サービスプロバイダーを選択する",
"search_result_default": "デフォルト",
"search_with_time": "日付を含む検索",
"enhance_mode": "検索強化モード",
"enhance_mode_tooltip": "デフォルトモデルを使用して問題から検索キーワードを抽出し、検索を実行します",
"tavily": {
"api_key": "Tavily API キー",
"api_key.placeholder": "Tavily API キーを入力してください",

View File

@ -1075,6 +1075,8 @@
"search_provider_placeholder": "Выберите поставщика поисковых услуг",
"search_result_default": "По умолчанию",
"search_with_time": "Поиск, содержащий дату",
"enhance_mode": "Режим улучшения поиска",
"enhance_mode_tooltip": "Используйте модель по умолчанию для извлечения ключевых слов из проблемы и поиска",
"tavily": {
"api_key": "Ключ API Tavily",
"api_key.placeholder": "Введите ключ API Tavily",

View File

@ -1075,6 +1075,8 @@
"search_provider_placeholder": "选择一个搜索服务商",
"search_result_default": "默认",
"search_with_time": "搜索包含日期",
"enhance_mode": "搜索增强模式",
"enhance_mode_tooltip": "使用默认模型提取关键词后搜索",
"tavily": {
"api_key": "Tavily API 密钥",
"api_key.placeholder": "请输入 Tavily API 密钥",

View File

@ -1075,6 +1075,8 @@
"search_provider_placeholder": "選擇一個搜尋服務商",
"search_result_default": "預設",
"search_with_time": "搜尋包含日期",
"enhance_mode": "搜索增強模式",
"enhance_mode_tooltip": "使用預設模型提取關鍵詞後搜索",
"tavily": {
"api_key": "Tavily API 金鑰",
"api_key.placeholder": "請輸入 Tavily API 金鑰",

View File

@ -80,6 +80,7 @@ const MCPSettings: FC = () => {
return (
<Paragraph
className="selectable"
ellipsis={{
rows: 1,
expandable: 'collapsible',

View File

@ -1,7 +1,8 @@
import { InfoCircleOutlined } from '@ant-design/icons'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useAppDispatch, useAppSelector } from '@renderer/store'
import { setMaxResult, setSearchWithTime } from '@renderer/store/websearch'
import { Slider, Switch } from 'antd'
import { setEnhanceMode, setMaxResult, setSearchWithTime } from '@renderer/store/websearch'
import { Slider, Switch, Tooltip } from 'antd'
import { t } from 'i18next'
import { FC } from 'react'
@ -10,21 +11,32 @@ import { SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle
const BasicSettings: FC = () => {
const { theme } = useTheme()
const searchWithTime = useAppSelector((state) => state.websearch.searchWithTime)
const enhanceMode = useAppSelector((state) => state.websearch.enhanceMode)
const maxResults = useAppSelector((state) => state.websearch.maxResults)
const dispatch = useAppDispatch()
return (
<>
<SettingGroup theme={theme}>
<SettingGroup theme={theme} style={{ paddingBottom: 8 }}>
<SettingTitle>{t('settings.general.title')}</SettingTitle>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.websearch.search_with_time')}</SettingRowTitle>
<Switch checked={searchWithTime} onChange={(checked) => dispatch(setSearchWithTime(checked))} />
</SettingRow>
<SettingDivider style={{ marginTop: 15, marginBottom: 5 }} />
<SettingRow style={{ marginBottom: -10 }}>
<SettingDivider style={{ marginTop: 15, marginBottom: 12 }} />
<SettingRow>
<SettingRowTitle>
{t('settings.websearch.enhance_mode')}
<Tooltip title={t('settings.websearch.enhance_mode_tooltip')} placement="right">
<InfoCircleOutlined style={{ marginLeft: 5, color: 'var(--color-icon)', cursor: 'pointer' }} />
</Tooltip>
</SettingRowTitle>
<Switch checked={enhanceMode} onChange={(checked) => dispatch(setEnhanceMode(checked))} />
</SettingRow>
<SettingDivider style={{ marginTop: 15, marginBottom: 12 }} />
<SettingRow>
<SettingRowTitle>{t('settings.websearch.search_max_result')}</SettingRowTitle>
<Slider
defaultValue={maxResults}

View File

@ -476,13 +476,18 @@ export default class AnthropicProvider extends BaseProvider {
content: messages.map((m) => m.content).join('\n')
}
const response = await this.sdk.messages.create({
const response = await this.sdk.messages.create(
{
messages: [userMessage] as Anthropic.Messages.MessageParam[],
model: model.id,
system: systemMessage.content,
stream: false,
max_tokens: 4096
})
},
{
timeout: 20 * 1000
}
)
const content = response.content[0].type === 'text' ? response.content[0].text : ''

View File

@ -518,7 +518,10 @@ export default class GeminiProvider extends BaseProvider {
temperature: assistant?.settings?.temperature
}
},
this.requestOptions
{
...this.requestOptions,
timeout: 20 * 1000
}
)
const chat = await geminiModel.startChat()

View File

@ -780,13 +780,18 @@ export default class OpenAIProvider extends BaseProvider {
content: messages.map((m) => m.content).join('\n')
}
// @ts-ignore key is not typed
const response = await this.sdk.chat.completions.create({
const response = await this.sdk.chat.completions.create(
{
model: model.id,
messages: [systemMessage, userMessage] as ChatCompletionMessageParam[],
stream: false,
keep_alive: this.keepAliveTime,
max_tokens: 1000
})
},
{
timeout: 20 * 1000
}
)
// 针对思考类模型的返回,总结仅截取</think>之后的内容
let content = response.choices[0].message?.content || ''

View File

@ -49,6 +49,7 @@ export async function fetchChatCompletion({
const lastMessage = findLast(messages, (m) => m.role === 'user')
const lastAnswer = findLast(messages, (m) => m.role === 'assistant')
const hasKnowledgeBase = !isEmpty(lastMessage?.knowledgeBaseIds)
if (lastMessage) {
if (hasKnowledgeBase) {
window.message.info({
@ -57,25 +58,28 @@ export async function fetchChatCompletion({
})
}
// 更新消息状态为搜索中
onResponse({ ...message, status: 'searching' })
try {
// 等待关键词生成完成
const searchSummaryAssistant = getDefaultAssistant()
searchSummaryAssistant.model = assistant.model || getDefaultModel()
searchSummaryAssistant.prompt = SEARCH_SUMMARY_PROMPT
// 如果启用搜索增强模式,则使用搜索增强模式
if (WebSearchService.isEnhanceModeEnabled()) {
const keywords = await fetchSearchSummary({
messages: lastAnswer ? [lastAnswer, lastMessage] : [lastMessage],
assistant: searchSummaryAssistant
})
if (keywords) {
query = keywords
}
} else {
query = lastMessage.content
}
// 更新消息状态为搜索中
onResponse({ ...message, status: 'searching' })
// 等待搜索完成
const webSearch = await WebSearchService.search(webSearchProvider, query)
@ -84,6 +88,7 @@ export async function fetchChatCompletion({
...message.metadata,
webSearch: webSearch
}
window.keyv.set(`web-search-${lastMessage?.id}`, webSearch)
} catch (error) {
console.error('Web search failed:', error)
@ -93,6 +98,7 @@ export async function fetchChatCompletion({
}
const allMCPTools = await window.api.mcp.listTools()
await AI.completions({
messages: filterUsefulMessages(messages),
assistant,

View File

@ -1,23 +1,10 @@
import store from '@renderer/store'
import { setDefaultProvider } from '@renderer/store/websearch'
import { setDefaultProvider, WebSearchState } from '@renderer/store/websearch'
import { WebSearchProvider, WebSearchResponse } from '@renderer/types'
import { hasObjectKey } from '@renderer/utils'
import WebSearchEngineProvider from '@renderer/webSearchProvider/WebSearchEngineProvider'
import dayjs from 'dayjs'
interface WebSearchState {
// 默认搜索提供商的ID
defaultProvider: string
// 所有可用的搜索提供商列表
providers: WebSearchProvider[]
// 是否在搜索查询中添加当前日期
searchWithTime: boolean
// 搜索结果的最大数量
maxResults: number
// 要排除的域名列表
excludeDomains: string[]
}
/**
*
*/
@ -55,6 +42,16 @@ class WebSearchService {
return false
}
/**
*
* @public
* @returns truefalse
*/
public isEnhanceModeEnabled(): boolean {
const { enhanceMode } = this.getWebSearchState()
return enhanceMode
}
/**
*
* @public

View File

@ -1,11 +1,19 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { WebSearchProvider } from '@renderer/types'
export interface WebSearchState {
// 默认搜索提供商的ID
defaultProvider: string
// 所有可用的搜索提供商列表
providers: WebSearchProvider[]
// 是否在搜索查询中添加当前日期
searchWithTime: boolean
// 搜索结果的最大数量
maxResults: number
// 要排除的域名列表
excludeDomains: string[]
// 是否启用搜索增强模式
enhanceMode: boolean
}
const initialState: WebSearchState = {
@ -29,7 +37,8 @@ const initialState: WebSearchState = {
],
searchWithTime: true,
maxResults: 5,
excludeDomains: []
excludeDomains: [],
enhanceMode: false
}
const websearchSlice = createSlice({
@ -59,6 +68,9 @@ const websearchSlice = createSlice({
},
setExcludeDomains: (state, action: PayloadAction<string[]>) => {
state.excludeDomains = action.payload
},
setEnhanceMode: (state, action: PayloadAction<boolean>) => {
state.enhanceMode = action.payload
}
}
})
@ -70,7 +82,8 @@ export const {
setDefaultProvider,
setSearchWithTime,
setExcludeDomains,
setMaxResult
setMaxResult,
setEnhanceMode
} = websearchSlice.actions
export default websearchSlice.reducer