mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 02:20:10 +08:00
feat: optimize knowledge recognize (#5707)
Co-authored-by: 自由的世界人 <3196812536@qq.com>
This commit is contained in:
parent
b6520cdc9a
commit
97130cfb1e
@ -9,7 +9,6 @@
|
|||||||
"add.prompt": "Prompt",
|
"add.prompt": "Prompt",
|
||||||
"add.prompt.placeholder": "Enter prompt",
|
"add.prompt.placeholder": "Enter prompt",
|
||||||
"add.title": "Create Agent",
|
"add.title": "Create Agent",
|
||||||
"import.title": "Import from External",
|
|
||||||
"import": {
|
"import": {
|
||||||
"title": "Import from External",
|
"title": "Import from External",
|
||||||
"type": {
|
"type": {
|
||||||
@ -78,7 +77,11 @@
|
|||||||
"settings.reasoning_effort.low": "Think less",
|
"settings.reasoning_effort.low": "Think less",
|
||||||
"settings.reasoning_effort.medium": "Think normally",
|
"settings.reasoning_effort.medium": "Think normally",
|
||||||
"settings.reasoning_effort.default": "Default",
|
"settings.reasoning_effort.default": "Default",
|
||||||
"settings.more": "Assistant Settings"
|
"settings.more": "Assistant Settings",
|
||||||
|
"settings.knowledge_base.recognition.tip": "The assistant will use the large model's intent recognition capability to determine whether to use the knowledge base for answering. This feature will depend on the model's capabilities",
|
||||||
|
"settings.knowledge_base.recognition": "Use Knowledge Base",
|
||||||
|
"settings.knowledge_base.recognition.off": "Force Search",
|
||||||
|
"settings.knowledge_base.recognition.on": "Intent Recognition"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"error": "API key automatically obtained failed, please get it manually",
|
"error": "API key automatically obtained failed, please get it manually",
|
||||||
@ -1540,8 +1543,7 @@
|
|||||||
"privacy": {
|
"privacy": {
|
||||||
"title": "Privacy Settings",
|
"title": "Privacy Settings",
|
||||||
"enable_privacy_mode": "Anonymous reporting of errors and statistics"
|
"enable_privacy_mode": "Anonymous reporting of errors and statistics"
|
||||||
},
|
}
|
||||||
"defaultAgent": "Built-in"
|
|
||||||
},
|
},
|
||||||
"translate": {
|
"translate": {
|
||||||
"any.language": "Any language",
|
"any.language": "Any language",
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
"add.prompt": "プロンプト",
|
"add.prompt": "プロンプト",
|
||||||
"add.prompt.placeholder": "プロンプトを入力",
|
"add.prompt.placeholder": "プロンプトを入力",
|
||||||
"add.title": "エージェントを作成",
|
"add.title": "エージェントを作成",
|
||||||
"import.title": "外部からインポート",
|
|
||||||
"import": {
|
"import": {
|
||||||
"title": "外部からインポート",
|
"title": "外部からインポート",
|
||||||
"type": {
|
"type": {
|
||||||
@ -78,7 +77,11 @@
|
|||||||
"settings.reasoning_effort.low": "少しの思考",
|
"settings.reasoning_effort.low": "少しの思考",
|
||||||
"settings.reasoning_effort.medium": "普通の思考",
|
"settings.reasoning_effort.medium": "普通の思考",
|
||||||
"settings.reasoning_effort.default": "デフォルト",
|
"settings.reasoning_effort.default": "デフォルト",
|
||||||
"settings.more": "アシスタント設定"
|
"settings.more": "アシスタント設定",
|
||||||
|
"settings.knowledge_base.recognition.tip": "アシスタントは大規模言語モデルの意図認識能力を使用して、ナレッジベースを参照する必要があるかどうかを判断します。この機能はモデルの能力に依存します",
|
||||||
|
"settings.knowledge_base.recognition": "ナレッジベースの呼び出し",
|
||||||
|
"settings.knowledge_base.recognition.off": "強制検索",
|
||||||
|
"settings.knowledge_base.recognition.on": "意図認識"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"error": "APIキーの自動取得に失敗しました。手動で取得してください",
|
"error": "APIキーの自動取得に失敗しました。手動で取得してください",
|
||||||
@ -1540,7 +1543,6 @@
|
|||||||
"title": "プライバシー設定",
|
"title": "プライバシー設定",
|
||||||
"enable_privacy_mode": "匿名エラーレポートとデータ統計の送信"
|
"enable_privacy_mode": "匿名エラーレポートとデータ統計の送信"
|
||||||
},
|
},
|
||||||
"defaultAgent": "内蔵",
|
|
||||||
"input.show_translate_confirm": "翻訳確認ダイアログを表示"
|
"input.show_translate_confirm": "翻訳確認ダイアログを表示"
|
||||||
},
|
},
|
||||||
"translate": {
|
"translate": {
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
"add.prompt": "Промпт",
|
"add.prompt": "Промпт",
|
||||||
"add.prompt.placeholder": "Введите промпт",
|
"add.prompt.placeholder": "Введите промпт",
|
||||||
"add.title": "Создать агента",
|
"add.title": "Создать агента",
|
||||||
"import.title": "Импорт из внешнего источника",
|
|
||||||
"delete.popup.content": "Вы уверены, что хотите удалить этого агента?",
|
"delete.popup.content": "Вы уверены, что хотите удалить этого агента?",
|
||||||
"edit.message.add.title": "Добавить",
|
"edit.message.add.title": "Добавить",
|
||||||
"edit.message.assistant.placeholder": "Введите сообщение ассистента",
|
"edit.message.assistant.placeholder": "Введите сообщение ассистента",
|
||||||
@ -78,7 +77,11 @@
|
|||||||
"settings.reasoning_effort.medium": "Среднее",
|
"settings.reasoning_effort.medium": "Среднее",
|
||||||
"settings.reasoning_effort.default": "По умолчанию",
|
"settings.reasoning_effort.default": "По умолчанию",
|
||||||
"settings.more": "Настройки ассистента",
|
"settings.more": "Настройки ассистента",
|
||||||
"settings.reasoning_effort": "Настройки размышлений"
|
"settings.reasoning_effort": "Настройки размышлений",
|
||||||
|
"settings.knowledge_base.recognition.tip": "Ассистент будет использовать возможности большой модели для распознавания намерений, чтобы определить, нужно ли обращаться к базе знаний для ответа. Эта функция будет зависеть от возможностей модели",
|
||||||
|
"settings.knowledge_base.recognition": "Использование базы знаний",
|
||||||
|
"settings.knowledge_base.recognition.off": "Принудительный поиск",
|
||||||
|
"settings.knowledge_base.recognition.on": "Распознавание намерений"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"error": "Автоматический получение ключа API не удалось, пожалуйста, получите ключ вручную",
|
"error": "Автоматический получение ключа API не удалось, пожалуйста, получите ключ вручную",
|
||||||
@ -1540,7 +1543,6 @@
|
|||||||
"title": "Настройки конфиденциальности",
|
"title": "Настройки конфиденциальности",
|
||||||
"enable_privacy_mode": "Анонимная отчетность об ошибках и статистике"
|
"enable_privacy_mode": "Анонимная отчетность об ошибках и статистике"
|
||||||
},
|
},
|
||||||
"defaultAgent": "Встроенный",
|
|
||||||
"input.show_translate_confirm": "Показать диалоговое окно подтверждения перевода"
|
"input.show_translate_confirm": "Показать диалоговое окно подтверждения перевода"
|
||||||
},
|
},
|
||||||
"translate": {
|
"translate": {
|
||||||
|
|||||||
@ -68,6 +68,10 @@
|
|||||||
"settings.mcp.description": "默认启用的 MCP 服务器",
|
"settings.mcp.description": "默认启用的 MCP 服务器",
|
||||||
"settings.default_model": "默认模型",
|
"settings.default_model": "默认模型",
|
||||||
"settings.knowledge_base": "知识库设置",
|
"settings.knowledge_base": "知识库设置",
|
||||||
|
"settings.knowledge_base.recognition.tip": "智能体将调用大模型的意图识别能力,判断是否需要调用知识库进行回答,该功能将依赖模型的能力",
|
||||||
|
"settings.knowledge_base.recognition": "调用知识库",
|
||||||
|
"settings.knowledge_base.recognition.off": "强制检索",
|
||||||
|
"settings.knowledge_base.recognition.on": "意图识别",
|
||||||
"settings.model": "模型设置",
|
"settings.model": "模型设置",
|
||||||
"settings.preset_messages": "预设消息",
|
"settings.preset_messages": "预设消息",
|
||||||
"settings.prompt": "提示词设置",
|
"settings.prompt": "提示词设置",
|
||||||
|
|||||||
@ -77,7 +77,11 @@
|
|||||||
"settings.reasoning_effort.low": "稍微思考",
|
"settings.reasoning_effort.low": "稍微思考",
|
||||||
"settings.reasoning_effort.medium": "正常思考",
|
"settings.reasoning_effort.medium": "正常思考",
|
||||||
"settings.reasoning_effort.default": "預設",
|
"settings.reasoning_effort.default": "預設",
|
||||||
"settings.more": "助手設定"
|
"settings.more": "助手設定",
|
||||||
|
"settings.knowledge_base.recognition.tip": "智慧代理人將調用大語言模型的意圖識別能力,判斷是否需要調用知識庫進行回答,該功能將依賴模型的能力",
|
||||||
|
"settings.knowledge_base.recognition": "調用知識庫",
|
||||||
|
"settings.knowledge_base.recognition.off": "強制檢索",
|
||||||
|
"settings.knowledge_base.recognition.on": "意圖識別"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"error": "自動取得金鑰失敗,請手動取得",
|
"error": "自動取得金鑰失敗,請手動取得",
|
||||||
|
|||||||
@ -2,7 +2,8 @@ import { CheckOutlined } from '@ant-design/icons'
|
|||||||
import { Box } from '@renderer/components/Layout'
|
import { Box } from '@renderer/components/Layout'
|
||||||
import { useAppSelector } from '@renderer/store'
|
import { useAppSelector } from '@renderer/store'
|
||||||
import { Assistant, AssistantSettings } from '@renderer/types'
|
import { Assistant, AssistantSettings } from '@renderer/types'
|
||||||
import { Select, SelectProps } from 'antd'
|
import { Row, Segmented, Select, SelectProps, Tooltip } from 'antd'
|
||||||
|
import { CircleHelp } from 'lucide-react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -46,6 +47,34 @@ const AssistantKnowledgeBaseSettings: React.FC<Props> = ({ assistant, updateAssi
|
|||||||
.includes(input.toLowerCase())
|
.includes(input.toLowerCase())
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Row align="middle" style={{ marginTop: 10 }}>
|
||||||
|
<Label>{t('assistants.settings.knowledge_base.recognition')}</Label>
|
||||||
|
</Row>
|
||||||
|
<Row align="middle" style={{ marginTop: 10 }}>
|
||||||
|
<Segmented
|
||||||
|
value={assistant.knowledgeRecognition ?? 'off'}
|
||||||
|
options={[
|
||||||
|
{ label: t('assistants.settings.knowledge_base.recognition.off'), value: 'off' },
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
|
||||||
|
{t('assistants.settings.knowledge_base.recognition.on')}
|
||||||
|
<Tooltip title={t('assistants.settings.knowledge_base.recognition.tip')}>
|
||||||
|
<QuestionIcon size={15} />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
value: 'on'
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
onChange={(value) =>
|
||||||
|
updateAssistant({
|
||||||
|
...assistant,
|
||||||
|
knowledgeRecognition: value as 'off' | 'on'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -57,5 +86,13 @@ const Container = styled.div`
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
`
|
`
|
||||||
|
const Label = styled.p`
|
||||||
|
margin-right: 5px;
|
||||||
|
font-weight: 500;
|
||||||
|
`
|
||||||
|
|
||||||
|
const QuestionIcon = styled(CircleHelp)`
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
`
|
||||||
export default AssistantKnowledgeBaseSettings
|
export default AssistantKnowledgeBaseSettings
|
||||||
|
|||||||
@ -46,22 +46,32 @@ async function fetchExternalTool(
|
|||||||
// 可能会有重复?
|
// 可能会有重复?
|
||||||
const knowledgeBaseIds = getKnowledgeBaseIds(lastUserMessage)
|
const knowledgeBaseIds = getKnowledgeBaseIds(lastUserMessage)
|
||||||
const hasKnowledgeBase = !isEmpty(knowledgeBaseIds)
|
const hasKnowledgeBase = !isEmpty(knowledgeBaseIds)
|
||||||
|
const knowledgeRecognition = assistant.knowledgeRecognition || 'on'
|
||||||
const webSearchProvider = WebSearchService.getWebSearchProvider(assistant.webSearchProviderId)
|
const webSearchProvider = WebSearchService.getWebSearchProvider(assistant.webSearchProviderId)
|
||||||
|
|
||||||
|
const shouldWebSearch = !!assistant.webSearchProviderId && webSearchProvider !== null
|
||||||
|
const shouldKnowledgeSearch = hasKnowledgeBase
|
||||||
|
|
||||||
|
// 在工具链开始时发送进度通知
|
||||||
|
const willUseTools = shouldWebSearch || shouldKnowledgeSearch
|
||||||
|
if (willUseTools) {
|
||||||
|
onChunkReceived({ type: ChunkType.EXTERNEL_TOOL_IN_PROGRESS })
|
||||||
|
}
|
||||||
|
|
||||||
// --- Keyword/Question Extraction Function ---
|
// --- Keyword/Question Extraction Function ---
|
||||||
const extract = async (): Promise<ExtractResults | undefined> => {
|
const extract = async (): Promise<ExtractResults | undefined> => {
|
||||||
if (!lastUserMessage) return undefined
|
if (!lastUserMessage) return undefined
|
||||||
// 如果都不需要搜索,则直接返回,不意图识别
|
|
||||||
if (!shouldWebSearch && !hasKnowledgeBase) return undefined
|
|
||||||
|
|
||||||
// Notify UI that extraction/searching is starting
|
// 根据配置决定是否需要提取
|
||||||
onChunkReceived({ type: ChunkType.EXTERNEL_TOOL_IN_PROGRESS })
|
const needWebExtract = shouldWebSearch
|
||||||
|
const needKnowledgeExtract = hasKnowledgeBase && knowledgeRecognition === 'on'
|
||||||
|
|
||||||
let prompt = ''
|
if (!needWebExtract && !needKnowledgeExtract) return undefined
|
||||||
|
|
||||||
if (shouldWebSearch && !hasKnowledgeBase) {
|
let prompt: string
|
||||||
|
if (needWebExtract && !needKnowledgeExtract) {
|
||||||
prompt = SEARCH_SUMMARY_PROMPT_WEB_ONLY
|
prompt = SEARCH_SUMMARY_PROMPT_WEB_ONLY
|
||||||
} else if (!shouldWebSearch && hasKnowledgeBase) {
|
} else if (!needWebExtract && needKnowledgeExtract) {
|
||||||
prompt = SEARCH_SUMMARY_PROMPT_KNOWLEDGE_ONLY
|
prompt = SEARCH_SUMMARY_PROMPT_KNOWLEDGE_ONLY
|
||||||
} else {
|
} else {
|
||||||
prompt = SEARCH_SUMMARY_PROMPT
|
prompt = SEARCH_SUMMARY_PROMPT
|
||||||
@ -71,29 +81,20 @@ async function fetchExternalTool(
|
|||||||
summaryAssistant.model = assistant.model || getDefaultModel()
|
summaryAssistant.model = assistant.model || getDefaultModel()
|
||||||
summaryAssistant.prompt = prompt
|
summaryAssistant.prompt = prompt
|
||||||
|
|
||||||
const getFallbackResult = (): ExtractResults => {
|
|
||||||
const fallbackContent = getMainTextContent(lastUserMessage)
|
|
||||||
return {
|
|
||||||
websearch: shouldWebSearch
|
|
||||||
? {
|
|
||||||
question: [fallbackContent || 'search']
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
knowledge: hasKnowledgeBase
|
|
||||||
? {
|
|
||||||
question: [fallbackContent || 'search']
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
} as ExtractResults
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const keywords = await fetchSearchSummary({
|
const keywords = await fetchSearchSummary({
|
||||||
messages: lastAnswer ? [lastAnswer, lastUserMessage] : [lastUserMessage],
|
messages: lastAnswer ? [lastAnswer, lastUserMessage] : [lastUserMessage],
|
||||||
assistant: summaryAssistant
|
assistant: summaryAssistant
|
||||||
})
|
})
|
||||||
|
|
||||||
return keywords ? extractInfoFromXML(keywords) : getFallbackResult()
|
if (!keywords) return getFallbackResult()
|
||||||
|
|
||||||
|
const extracted = extractInfoFromXML(keywords)
|
||||||
|
// 根据需求过滤结果
|
||||||
|
return {
|
||||||
|
websearch: needWebExtract ? extracted?.websearch : undefined,
|
||||||
|
knowledge: needKnowledgeExtract ? extracted?.knowledge : undefined
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error('extract error', e)
|
console.error('extract error', e)
|
||||||
if (isAbortError(e)) throw e
|
if (isAbortError(e)) throw e
|
||||||
@ -101,16 +102,29 @@ async function fetchExternalTool(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getFallbackResult = (): ExtractResults => {
|
||||||
|
const fallbackContent = getMainTextContent(lastUserMessage)
|
||||||
|
return {
|
||||||
|
websearch: shouldWebSearch ? { question: [fallbackContent || 'search'] } : undefined,
|
||||||
|
knowledge: shouldKnowledgeSearch
|
||||||
|
? {
|
||||||
|
question: [fallbackContent || 'search'],
|
||||||
|
rewrite: fallbackContent
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Web Search Function ---
|
// --- Web Search Function ---
|
||||||
const searchTheWeb = async (): Promise<WebSearchResponse | undefined> => {
|
const searchTheWeb = async (extractResults: ExtractResults | undefined): Promise<WebSearchResponse | undefined> => {
|
||||||
|
if (!shouldWebSearch) return
|
||||||
|
|
||||||
// Add check for extractResults existence early
|
// Add check for extractResults existence early
|
||||||
if (!extractResults?.websearch) {
|
if (!extractResults?.websearch) {
|
||||||
console.warn('searchTheWeb called without valid extractResults.websearch')
|
console.warn('searchTheWeb called without valid extractResults.websearch')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldWebSearch) return
|
|
||||||
|
|
||||||
// Add check for assistant.model before using it
|
// Add check for assistant.model before using it
|
||||||
if (!assistant.model) {
|
if (!assistant.model) {
|
||||||
console.warn('searchTheWeb called without assistant.model')
|
console.warn('searchTheWeb called without assistant.model')
|
||||||
@ -138,93 +152,121 @@ async function fetchExternalTool(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Knowledge Base Search Function ---
|
// --- Knowledge Base Search Function ---
|
||||||
const searchKnowledgeBase = async (): Promise<KnowledgeReference[] | undefined> => {
|
const searchKnowledgeBase = async (
|
||||||
// Add check for extractResults existence early
|
extractResults: ExtractResults | undefined
|
||||||
if (!extractResults?.knowledge) {
|
): Promise<KnowledgeReference[] | undefined> => {
|
||||||
console.warn('searchKnowledgeBase called without valid extractResults.knowledge')
|
if (!hasKnowledgeBase) return
|
||||||
return
|
|
||||||
|
// 知识库搜索条件
|
||||||
|
let searchCriteria: { question: string[]; rewrite: string }
|
||||||
|
if (knowledgeRecognition === 'off') {
|
||||||
|
const directContent = getMainTextContent(lastUserMessage)
|
||||||
|
searchCriteria = { question: [directContent || 'search'], rewrite: directContent }
|
||||||
|
} else {
|
||||||
|
// auto mode
|
||||||
|
if (!extractResults?.knowledge) {
|
||||||
|
console.warn('searchKnowledgeBase: No valid search criteria in auto mode')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
searchCriteria = extractResults.knowledge
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldSearch = hasKnowledgeBase && extractResults.knowledge.question[0] !== 'not_needed'
|
if (searchCriteria.question[0] === 'not_needed') return
|
||||||
|
|
||||||
if (!shouldSearch) return
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const tempExtractResults: ExtractResults = {
|
||||||
|
websearch: undefined,
|
||||||
|
knowledge: searchCriteria
|
||||||
|
}
|
||||||
// Attempt to get knowledgeBaseIds from the main text block
|
// Attempt to get knowledgeBaseIds from the main text block
|
||||||
// NOTE: This assumes knowledgeBaseIds are ONLY on the main text block
|
// NOTE: This assumes knowledgeBaseIds are ONLY on the main text block
|
||||||
// NOTE: processKnowledgeSearch needs to handle undefined ids gracefully
|
// NOTE: processKnowledgeSearch needs to handle undefined ids gracefully
|
||||||
// const mainTextBlock = mainTextBlocks
|
// const mainTextBlock = mainTextBlocks
|
||||||
// ?.map((blockId) => store.getState().messageBlocks.entities[blockId])
|
// ?.map((blockId) => store.getState().messageBlocks.entities[blockId])
|
||||||
// .find((block) => block?.type === MessageBlockType.MAIN_TEXT) as MainTextMessageBlock | undefined
|
// .find((block) => block?.type === MessageBlockType.MAIN_TEXT) as MainTextMessageBlock | undefined
|
||||||
return await processKnowledgeSearch(extractResults, knowledgeBaseIds)
|
return await processKnowledgeSearch(tempExtractResults, knowledgeBaseIds)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Knowledge base search failed:', error)
|
console.error('Knowledge base search failed:', error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldWebSearch = !!assistant.webSearchProviderId
|
|
||||||
|
|
||||||
// --- Execute Extraction and Searches ---
|
// --- Execute Extraction and Searches ---
|
||||||
const extractResults = await extract()
|
let extractResults: ExtractResults | undefined
|
||||||
// Run searches potentially in parallel
|
|
||||||
|
|
||||||
let webSearchResponseFromSearch: WebSearchResponse | undefined
|
try {
|
||||||
let knowledgeReferencesFromSearch: KnowledgeReference[] | undefined
|
// 根据配置决定是否需要提取
|
||||||
const isWebSearchValid = extractResults?.websearch && assistant.model
|
if (shouldWebSearch || hasKnowledgeBase) {
|
||||||
const isKnowledgeSearchValid = extractResults?.knowledge
|
extractResults = await extract()
|
||||||
const isAllValidSearch = lastUserMessage && (isKnowledgeSearchValid || isWebSearchValid)
|
console.log('Extraction results:', extractResults)
|
||||||
|
}
|
||||||
|
|
||||||
if (isAllValidSearch) {
|
let webSearchResponseFromSearch: WebSearchResponse | undefined
|
||||||
// TODO: 应该在这写search开始
|
let knowledgeReferencesFromSearch: KnowledgeReference[] | undefined
|
||||||
if (isKnowledgeSearchValid && isWebSearchValid) {
|
|
||||||
|
// 并行执行搜索
|
||||||
|
if (shouldWebSearch || shouldKnowledgeSearch) {
|
||||||
;[webSearchResponseFromSearch, knowledgeReferencesFromSearch] = await Promise.all([
|
;[webSearchResponseFromSearch, knowledgeReferencesFromSearch] = await Promise.all([
|
||||||
searchTheWeb(),
|
searchTheWeb(extractResults),
|
||||||
searchKnowledgeBase()
|
searchKnowledgeBase(extractResults)
|
||||||
])
|
])
|
||||||
} else if (isKnowledgeSearchValid) {
|
|
||||||
knowledgeReferencesFromSearch = await searchKnowledgeBase()
|
|
||||||
} else if (isWebSearchValid) {
|
|
||||||
webSearchResponseFromSearch = await searchTheWeb()
|
|
||||||
}
|
}
|
||||||
// Search判断很准确了,可以在这写search结束
|
|
||||||
onChunkReceived({
|
// 存储搜索结果
|
||||||
type: ChunkType.EXTERNEL_TOOL_COMPLETE,
|
if (lastUserMessage) {
|
||||||
external_tool: {
|
if (webSearchResponseFromSearch) {
|
||||||
webSearch: webSearchResponseFromSearch,
|
window.keyv.set(`web-search-${lastUserMessage.id}`, webSearchResponseFromSearch)
|
||||||
knowledge: knowledgeReferencesFromSearch
|
}
|
||||||
|
if (knowledgeReferencesFromSearch) {
|
||||||
|
window.keyv.set(`knowledge-search-${lastUserMessage.id}`, knowledgeReferencesFromSearch)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Prepare for AI Completion ---
|
|
||||||
// Store results temporarily (e.g., using window.keyv like before)
|
|
||||||
if (lastUserMessage) {
|
|
||||||
if (webSearchResponseFromSearch) {
|
|
||||||
window.keyv.set(`web-search-${lastUserMessage.id}`, webSearchResponseFromSearch)
|
|
||||||
}
|
}
|
||||||
if (knowledgeReferencesFromSearch) {
|
|
||||||
window.keyv.set(`knowledge-search-${lastUserMessage.id}`, knowledgeReferencesFromSearch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get MCP tools (Fix duplicate declaration)
|
// 发送工具执行完成通知
|
||||||
let mcpTools: MCPTool[] = [] // Initialize as empty array
|
if (willUseTools) {
|
||||||
const enabledMCPs = lastUserMessage?.enabledMCPs
|
onChunkReceived({
|
||||||
if (enabledMCPs && enabledMCPs.length > 0) {
|
type: ChunkType.EXTERNEL_TOOL_COMPLETE,
|
||||||
try {
|
external_tool: {
|
||||||
const toolPromises = enabledMCPs.map(async (mcpServer) => {
|
webSearch: webSearchResponseFromSearch,
|
||||||
const tools = await window.api.mcp.listTools(mcpServer)
|
knowledge: knowledgeReferencesFromSearch
|
||||||
return tools.filter((tool: any) => !mcpServer.disabledTools?.includes(tool.name))
|
}
|
||||||
})
|
})
|
||||||
const results = await Promise.all(toolPromises)
|
|
||||||
mcpTools = results.flat() // Flatten the array of arrays
|
|
||||||
} catch (toolError) {
|
|
||||||
console.error('Error fetching MCP tools:', toolError)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return { mcpTools }
|
// Get MCP tools (Fix duplicate declaration)
|
||||||
|
let mcpTools: MCPTool[] = [] // Initialize as empty array
|
||||||
|
const enabledMCPs = lastUserMessage?.enabledMCPs
|
||||||
|
if (enabledMCPs && enabledMCPs.length > 0) {
|
||||||
|
try {
|
||||||
|
const toolPromises = enabledMCPs.map(async (mcpServer) => {
|
||||||
|
const tools = await window.api.mcp.listTools(mcpServer)
|
||||||
|
return tools.filter((tool: any) => !mcpServer.disabledTools?.includes(tool.name))
|
||||||
|
})
|
||||||
|
const results = await Promise.all(toolPromises)
|
||||||
|
mcpTools = results.flat() // Flatten the array of arrays
|
||||||
|
} catch (toolError) {
|
||||||
|
console.error('Error fetching MCP tools:', toolError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { mcpTools }
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Tool execution failed:', error)
|
||||||
|
if (isAbortError(error)) throw error
|
||||||
|
|
||||||
|
// 发送错误状态
|
||||||
|
if (willUseTools) {
|
||||||
|
onChunkReceived({
|
||||||
|
type: ChunkType.EXTERNEL_TOOL_COMPLETE,
|
||||||
|
external_tool: {
|
||||||
|
webSearch: undefined,
|
||||||
|
knowledge: undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { mcpTools: [] }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchChatCompletion({
|
export async function fetchChatCompletion({
|
||||||
|
|||||||
@ -23,6 +23,7 @@ export type Assistant = {
|
|||||||
webSearchProviderId?: WebSearchProvider['id']
|
webSearchProviderId?: WebSearchProvider['id']
|
||||||
enableGenerateImage?: boolean
|
enableGenerateImage?: boolean
|
||||||
mcpServers?: MCPServer[]
|
mcpServers?: MCPServer[]
|
||||||
|
knowledgeRecognition?: 'off' | 'on'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AssistantMessage = {
|
export type AssistantMessage = {
|
||||||
|
|||||||
@ -28,6 +28,6 @@ export const extractInfoFromXML = (text: string): ExtractResults => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const extractResults: ExtractResults = parser.parse(text)
|
const extractResults: ExtractResults = parser.parse(text)
|
||||||
console.log('Extracted results:', extractResults)
|
// console.log('Extracted results:', extractResults)
|
||||||
return extractResults
|
return extractResults
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user