mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-06-04 13:30:32 +08:00
feat: Add agent readiness checks and detailed configuration messages
- Implemented a function to retrieve reasons for agent unavailability, enhancing user feedback on configuration issues. - Updated the agent status message to include specific missing configurations, improving clarity for users. - Enhanced localization support for new messages related to agent configuration requirements in English, Russian, and Chinese. - Added navigation options for users to quickly access model configuration settings when the agent is not ready.
This commit is contained in:
@@ -591,6 +591,25 @@ const handleGoToAgentSettings = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 Agent 不就绪的原因
|
||||
const getAgentNotReadyReasons = (): string[] => {
|
||||
const reasons: string[] = []
|
||||
const config = settingsStore.agentConfig || { allowedTools: [] }
|
||||
const models = settingsStore.conversationModels || { summaryModelId: '', rerankModelId: '' }
|
||||
|
||||
if (!config.allowedTools || config.allowedTools.length === 0) {
|
||||
reasons.push(t('input.agentMissingAllowedTools'))
|
||||
}
|
||||
if (!models.summaryModelId || models.summaryModelId.trim() === '') {
|
||||
reasons.push(t('input.agentMissingSummaryModel'))
|
||||
}
|
||||
if (!models.rerankModelId || models.rerankModelId.trim() === '') {
|
||||
reasons.push(t('input.agentMissingRerankModel'))
|
||||
}
|
||||
|
||||
return reasons
|
||||
}
|
||||
|
||||
const toggleAgentMode = () => {
|
||||
// 如果要启用 Agent,先检查是否就绪
|
||||
// 注意:isAgentReady 是从 store 中计算的,需要确保 store 中的配置是最新的
|
||||
@@ -598,16 +617,19 @@ const toggleAgentMode = () => {
|
||||
// 尝试启用 Agent,先检查是否就绪
|
||||
const agentReady = settingsStore.isAgentReady
|
||||
if (!agentReady) {
|
||||
const reasons = getAgentNotReadyReasons()
|
||||
const reasonsText = reasons.join('、')
|
||||
|
||||
// 创建带跳转链接的自定义消息
|
||||
const messageContent = h('div', { style: 'display: flex; align-items: center; gap: 8px; flex-wrap: wrap;' }, [
|
||||
h('span', { style: 'flex: 1; min-width: 0;' }, t('input.messages.agentNotReadyDetail')),
|
||||
const messageContent = h('div', { style: 'display: flex; flex-direction: column; gap: 8px; max-width: 320px;' }, [
|
||||
h('span', { style: 'color: #333; line-height: 1.5;' }, t('input.messages.agentNotReadyDetail', { reasons: reasonsText })),
|
||||
h('a', {
|
||||
href: '#',
|
||||
onClick: (e: Event) => {
|
||||
e.preventDefault();
|
||||
handleGoToAgentSettings();
|
||||
},
|
||||
style: 'color: #07C05F; text-decoration: none; font-weight: 500; cursor: pointer; white-space: nowrap; flex-shrink: 0;',
|
||||
style: 'color: #07C05F; text-decoration: none; font-weight: 500; cursor: pointer; align-self: flex-start;',
|
||||
onMouseenter: (e: Event) => {
|
||||
(e.target as HTMLElement).style.textDecoration = 'underline';
|
||||
},
|
||||
|
||||
@@ -642,7 +642,10 @@ export default {
|
||||
normalModeDesc: 'Knowledge base RAG Q&A',
|
||||
agentModeDesc: 'ReAct reasoning framework with multi-step thinking',
|
||||
agentNotReadyTooltip: 'Agent is not ready. Please finish configuration first.',
|
||||
agentNotReadyDetail: 'Agent is not ready. Please complete the agent configuration in settings (thinking model, rerank model, and allowed tools).',
|
||||
agentNotReadyDetail: 'Agent is not ready. Please configure the following: {reasons}',
|
||||
agentMissingAllowedTools: 'Allowed tools',
|
||||
agentMissingSummaryModel: 'Chat Model (Summary Model)',
|
||||
agentMissingRerankModel: 'Rerank Model',
|
||||
goToSettings: 'Go to settings →',
|
||||
webSearch: {
|
||||
toggleOn: 'Enable Web Search',
|
||||
@@ -666,7 +669,10 @@ export default {
|
||||
agentSwitchedOff: 'Switched to Normal Mode',
|
||||
agentEnabled: 'Agent Mode enabled',
|
||||
agentDisabled: 'Agent Mode disabled',
|
||||
agentNotReadyDetail: 'Agent is not ready. Please complete the agent configuration in settings (thinking model, rerank model, and allowed tools).',
|
||||
agentNotReadyDetail: 'Agent is not ready. Please configure the following: {reasons}',
|
||||
agentMissingAllowedTools: 'Allowed tools',
|
||||
agentMissingSummaryModel: 'Chat Model (Summary Model)',
|
||||
agentMissingRerankModel: 'Rerank Model',
|
||||
webSearchNotConfigured: 'Web search engine is not configured. Please configure a provider and credentials in settings.',
|
||||
webSearchEnabled: 'Web search enabled',
|
||||
webSearchDisabled: 'Web search disabled',
|
||||
@@ -1311,7 +1317,8 @@ export default {
|
||||
missingThinkingModel: 'Thinking model',
|
||||
missingRerankModel: 'Rerank model',
|
||||
missingAllowedTools: 'Allowed tools',
|
||||
pleaseConfigure: 'Please configure {items}'
|
||||
pleaseConfigure: 'Please configure {items}',
|
||||
goConfigureModels: 'Configure models →'
|
||||
},
|
||||
maxIterations: {
|
||||
label: 'Max Iterations',
|
||||
|
||||
@@ -785,7 +785,7 @@ export default {
|
||||
uninitializedBanner: 'Некоторые базы знаний не инициализированы. Сначала настройте модели в разделе настроек, чтобы добавлять документы.',
|
||||
empty: {
|
||||
title: 'Базы знаний отсутствуют',
|
||||
description: 'Нажмите «Создать базу знаний» в правом верхнем углу, чтобы добавить первую базу.'
|
||||
description: 'Нажмите «Создать базу знаний» в левом быстром действии, чтобы добавить первую базу.'
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: 'Подтверждение удаления',
|
||||
@@ -1177,7 +1177,8 @@ export default {
|
||||
missingThinkingModel: 'модель мышления',
|
||||
missingRerankModel: 'модель ранжирования',
|
||||
missingAllowedTools: 'разрешённые инструменты',
|
||||
pleaseConfigure: 'Пожалуйста, настройте: {items}'
|
||||
pleaseConfigure: 'Пожалуйста, настройте: {items}',
|
||||
goConfigureModels: 'Перейти к настройке моделей →'
|
||||
},
|
||||
maxIterations: {
|
||||
label: 'Макс. число итераций',
|
||||
@@ -1512,7 +1513,10 @@ export default {
|
||||
normalModeDesc: 'RAG-вопросы и ответы по базе знаний',
|
||||
agentModeDesc: 'Шаблон рассуждений ReAct, многошаговое мышление',
|
||||
agentNotReadyTooltip: 'Agent не готов. Пожалуйста, завершите настройку.',
|
||||
agentNotReadyDetail: 'Agent не готов. Сначала завершите настройку агента в параметрах (модель мышления, модель rerank и разрешённые инструменты).',
|
||||
agentNotReadyDetail: 'Agent не готов. Пожалуйста, настройте следующее: {reasons}',
|
||||
agentMissingAllowedTools: 'Разрешённые инструменты',
|
||||
agentMissingSummaryModel: 'Модель беседы (Summary Model)',
|
||||
agentMissingRerankModel: 'Модель переранжирования (Rerank Model)',
|
||||
goToSettings: 'Перейти к настройкам →',
|
||||
webSearch: {
|
||||
toggleOn: 'Включить веб-поиск',
|
||||
@@ -1536,7 +1540,10 @@ export default {
|
||||
agentSwitchedOff: 'Переключено в обычный режим',
|
||||
agentEnabled: 'Agent режим включён',
|
||||
agentDisabled: 'Agent режим отключён',
|
||||
agentNotReadyDetail: 'Agent не готов. Сначала завершите настройку агента в параметрах (модель мышления, модель rerank и разрешённые инструменты).',
|
||||
agentNotReadyDetail: 'Agent не готов. Пожалуйста, настройте следующее: {reasons}',
|
||||
agentMissingAllowedTools: 'Разрешённые инструменты',
|
||||
agentMissingSummaryModel: 'Модель беседы (Summary Model)',
|
||||
agentMissingRerankModel: 'Модель переранжирования (Rerank Model)',
|
||||
webSearchNotConfigured: 'Веб-поиск не настроен. Сначала выберите провайдера и настройте ключи в разделе настроек.',
|
||||
webSearchEnabled: 'Веб-поиск включён',
|
||||
webSearchDisabled: 'Веб-поиск выключен',
|
||||
|
||||
@@ -1010,7 +1010,7 @@ export default {
|
||||
"部分知识库尚未初始化,需要先在设置中配置模型信息才能添加知识文档",
|
||||
empty: {
|
||||
title: "暂无知识库",
|
||||
description: "点击右上角“新建知识库”按钮创建第一个知识库",
|
||||
description: "点击左侧快捷操作“新建知识库”按钮创建第一个知识库",
|
||||
},
|
||||
delete: {
|
||||
confirmTitle: "删除确认",
|
||||
@@ -1162,7 +1162,7 @@ export default {
|
||||
title: "模型配置",
|
||||
description: "为知识库选择合适的 AI 模型",
|
||||
llmLabel: "LLM 大语言模型",
|
||||
llmDesc: "用于总结和摘要的大语言模型(可选)",
|
||||
llmDesc: "用于总结和摘要的大语言模型",
|
||||
llmPlaceholder: "请选择 LLM 模型(可选)",
|
||||
embeddingLabel: "Embedding 嵌入模型",
|
||||
embeddingDesc: "用于文本向量化的嵌入模型",
|
||||
@@ -1267,7 +1267,10 @@ export default {
|
||||
agentModeDesc: "ReAct 推理框架,多步思考",
|
||||
agentNotReadyTooltip: "Agent 未就绪,请先在设置中完成配置",
|
||||
agentNotReadyDetail:
|
||||
"Agent 未就绪,请先在设置中完成 Agent 配置(思考模型、Rerank 模型和允许的工具)",
|
||||
"Agent 未就绪,需要配置以下内容:{reasons}",
|
||||
agentMissingAllowedTools: "允许的工具",
|
||||
agentMissingSummaryModel: "对话模型(Summary Model)",
|
||||
agentMissingRerankModel: "重排模型(Rerank Model)",
|
||||
goToSettings: "前往设置 →",
|
||||
webSearch: {
|
||||
toggleOn: "开启网络搜索",
|
||||
@@ -1292,7 +1295,7 @@ export default {
|
||||
agentEnabled: "Agent 模式已启用",
|
||||
agentDisabled: "Agent 模式已禁用",
|
||||
agentNotReadyDetail:
|
||||
"Agent 未就绪,请先在设置中完成 Agent 配置(思考模型、Rerank 模型和允许的工具)",
|
||||
"Agent 未就绪,需要配置以下内容:{reasons}",
|
||||
webSearchNotConfigured:
|
||||
"未配置网络搜索引擎,请先在设置中完成搜索引擎选择与接口配置。",
|
||||
webSearchEnabled: "网络搜索已开启",
|
||||
@@ -1313,9 +1316,12 @@ export default {
|
||||
notReady: "未就绪",
|
||||
hint: "配置完成后,Agent 状态将自动变为“可用”,此时可在对话界面开启 Agent 模式",
|
||||
missingThinkingModel: "思考模型",
|
||||
missingSummaryModel: "对话模型(Summary Model)",
|
||||
missingRerankModel: "Rerank 模型",
|
||||
missingAllowedTools: "允许的工具",
|
||||
pleaseConfigure: "请配置{items}",
|
||||
goToConfig: "前往配置对话模型",
|
||||
goConfigureModels: "前往配置模型 →",
|
||||
},
|
||||
maxIterations: {
|
||||
label: "最大迭代次数",
|
||||
|
||||
@@ -65,7 +65,7 @@ const defaultSettings: Settings = {
|
||||
agentConfig: {
|
||||
maxIterations: 5,
|
||||
temperature: 0.7,
|
||||
allowedTools: ["knowledge_search", "multi_kb_search", "list_knowledge_bases"],
|
||||
allowedTools: [], // 默认为空,需要通过 API 从后端加载
|
||||
system_prompt_web_enabled: "",
|
||||
system_prompt_web_disabled: "",
|
||||
use_custom_system_prompt: false
|
||||
@@ -99,12 +99,15 @@ export const useSettingsStore = defineStore("settings", {
|
||||
isAgentEnabled: (state) => state.settings.isAgentEnabled || false,
|
||||
|
||||
// Agent 是否就绪(配置完整)
|
||||
// 需要满足:1) 配置了允许的工具 2) 设置了对话模型 3) 设置了重排模型
|
||||
isAgentReady: (state) => {
|
||||
const config = state.settings.agentConfig || defaultSettings.agentConfig
|
||||
const models = state.settings.conversationModels || defaultSettings.conversationModels
|
||||
return config.allowedTools.length > 0 &&
|
||||
models.summaryModelId !== '' &&
|
||||
models.rerankModelId !== ''
|
||||
return Boolean(
|
||||
config.allowedTools && config.allowedTools.length > 0 &&
|
||||
models.summaryModelId && models.summaryModelId.trim() !== '' &&
|
||||
models.rerankModelId && models.rerankModelId.trim() !== ''
|
||||
)
|
||||
},
|
||||
|
||||
// 获取 Agent 配置
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
</div>
|
||||
<span v-if="!isAgentReady" class="status-hint">
|
||||
{{ agentStatusMessage }}
|
||||
<t-link v-if="needsModelConfig" @click="handleGoToModelSettings" theme="primary">
|
||||
{{ $t('agentSettings.status.goConfigureModels') }}
|
||||
</t-link>
|
||||
</span>
|
||||
<p v-if="!isAgentReady" class="status-tip">
|
||||
<t-icon name="info-circle" class="tip-icon" />
|
||||
@@ -302,7 +305,7 @@
|
||||
</t-tabs>
|
||||
</div>
|
||||
|
||||
<div v-else-if="activeSection === 'models'" class="section-block">
|
||||
<div v-else-if="activeSection === 'models'" class="section-block" data-conversation-section="models">
|
||||
<div class="section-header">
|
||||
<h2>{{ $t('conversationSettings.menus.models') }}</h2>
|
||||
<p class="section-description">{{ $t('conversationSettings.models.description') }}</p>
|
||||
@@ -808,7 +811,13 @@ const saveConversationConfig = async (partial: Partial<ConversationConfig>, toas
|
||||
|
||||
// 计算 Agent 是否就绪
|
||||
const isAgentReady = computed(() => {
|
||||
return localAllowedTools.value.length > 0
|
||||
return (
|
||||
localAllowedTools.value.length > 0 &&
|
||||
localSummaryModelId.value &&
|
||||
localSummaryModelId.value.trim() !== '' &&
|
||||
localConversationRerankModelId.value &&
|
||||
localConversationRerankModelId.value.trim() !== ''
|
||||
)
|
||||
})
|
||||
|
||||
const buildAgentConfigPayload = (overrides: Partial<AgentConfig> = {}): AgentConfig => ({
|
||||
@@ -823,6 +832,14 @@ const buildAgentConfigPayload = (overrides: Partial<AgentConfig> = {}): AgentCon
|
||||
...overrides,
|
||||
})
|
||||
|
||||
// 是否缺少模型配置
|
||||
const needsModelConfig = computed(() => {
|
||||
return (
|
||||
(!localSummaryModelId.value || localSummaryModelId.value.trim() === '') ||
|
||||
(!localConversationRerankModelId.value || localConversationRerankModelId.value.trim() === '')
|
||||
)
|
||||
})
|
||||
|
||||
// Agent 状态提示消息
|
||||
const agentStatusMessage = computed(() => {
|
||||
const missing: string[] = []
|
||||
@@ -831,6 +848,14 @@ const agentStatusMessage = computed(() => {
|
||||
missing.push(t('agentSettings.status.missingAllowedTools'))
|
||||
}
|
||||
|
||||
if (!localSummaryModelId.value || localSummaryModelId.value.trim() === '') {
|
||||
missing.push(t('agentSettings.status.missingSummaryModel'))
|
||||
}
|
||||
|
||||
if (!localConversationRerankModelId.value || localConversationRerankModelId.value.trim() === '') {
|
||||
missing.push(t('agentSettings.status.missingRerankModel'))
|
||||
}
|
||||
|
||||
if (missing.length === 0) {
|
||||
return ''
|
||||
}
|
||||
@@ -838,6 +863,25 @@ const agentStatusMessage = computed(() => {
|
||||
return t('agentSettings.status.pleaseConfigure', { items: missing.join('、') })
|
||||
})
|
||||
|
||||
// 跳转到模型配置
|
||||
const handleGoToModelSettings = () => {
|
||||
router.push('/platform/settings')
|
||||
|
||||
setTimeout(() => {
|
||||
const event = new CustomEvent('settings-nav', {
|
||||
detail: { section: 'agent', subsection: 'models' }
|
||||
})
|
||||
window.dispatchEvent(event)
|
||||
|
||||
setTimeout(() => {
|
||||
const sectionEl = document.querySelector('[data-conversation-section="models"]')
|
||||
if (sectionEl) {
|
||||
sectionEl.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}, 150)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 模型列表状态
|
||||
const chatModels = ref<ModelConfig[]>([])
|
||||
const rerankModels = ref<ModelConfig[]>([])
|
||||
|
||||
@@ -4,4 +4,5 @@ const (
|
||||
DefaultAgentTemperature = 0.7
|
||||
DefaultAgentMaxIterations = 20
|
||||
DefaultAgentReflectionEnabled = false
|
||||
DefaultUseCustomSystemPrompt = false
|
||||
)
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Tencent/WeKnora/internal/agent"
|
||||
"github.com/Tencent/WeKnora/internal/agent/tools"
|
||||
chatpipline "github.com/Tencent/WeKnora/internal/application/service/chat_pipline"
|
||||
llmcontext "github.com/Tencent/WeKnora/internal/application/service/llmcontext"
|
||||
"github.com/Tencent/WeKnora/internal/config"
|
||||
@@ -858,15 +860,22 @@ func (s *sessionService) AgentQA(ctx context.Context, session *types.Session, qu
|
||||
tenantInfo := ctx.Value(types.TenantInfoContextKey).(*types.Tenant)
|
||||
|
||||
// Check if agent is enabled at session level
|
||||
if session.AgentConfig == nil || !session.AgentConfig.AgentModeEnabled {
|
||||
logger.Warnf(ctx, "Agent not enabled for session: %s", sessionID)
|
||||
return errors.New("agent not enabled for this session")
|
||||
if session.AgentConfig == nil {
|
||||
logger.Warnf(ctx, "Agent config not found for session: %s", sessionID)
|
||||
return errors.New("agent config not found for session")
|
||||
}
|
||||
|
||||
// Check if tenant has agent configuration
|
||||
if tenantInfo.AgentConfig == nil {
|
||||
logger.Warnf(ctx, "Tenant %d has no agent configuration", tenantInfo.ID)
|
||||
return errors.New("tenant has no agent configuration")
|
||||
tenantInfo.AgentConfig = &types.AgentConfig{
|
||||
MaxIterations: agent.DefaultAgentMaxIterations,
|
||||
ReflectionEnabled: agent.DefaultAgentReflectionEnabled,
|
||||
AllowedTools: tools.DefaultAllowedTools(),
|
||||
Temperature: agent.DefaultAgentTemperature,
|
||||
SystemPromptWebEnabled: agent.ProgressiveRAGSystemPromptWithWeb,
|
||||
SystemPromptWebDisabled: agent.ProgressiveRAGSystemPromptWithoutWeb,
|
||||
UseCustomSystemPrompt: agent.DefaultUseCustomSystemPrompt,
|
||||
}
|
||||
}
|
||||
|
||||
// Create runtime AgentConfig by merging session and tenant configs
|
||||
|
||||
Reference in New Issue
Block a user