feat(auto-reply): 优化自动回复逻辑和知识库功能

- 将默认回复详细程度从"detailed"调整为"medium",前后端保持一致
- 新增话题切换检测逻辑,当用户主动要求换话题时提供引导回复
- 优化上下文处理机制,仅在指代型追问时注入历史对话,避免模型复读旧内容
- 改进知识库检索逻辑,区分自包含问题和指代型问题的上下文需求
- 完善知识库完整性指令,确保回复详细程度与知识展开程度一致
- 重构知识库重建逻辑,支持递归扫描子目录中的文件,修复索引为空的问题
- 增强素材匹配算法,引入强信号检测机制,避免仅凭模糊匹配误发素材
- 新增素材开场白AI生成功能,支持图片、视频、文档等类型智能描述
- 改进知识库重建通知,显示具体的文件数、分片数及失败统计信息
This commit is contained in:
2026-06-26 14:25:35 +08:00
parent 1517be2a25
commit 849090a627
12 changed files with 809 additions and 40 deletions

View File

@@ -1162,7 +1162,7 @@ function defaultConfig() {
audioApiKey: '',
timeoutSeconds: 20,
enableThinking: false,
replyDetail: 'detailed',
replyDetail: 'medium',
temperature: 0,
maxTokens: 700
},
@@ -2021,7 +2021,7 @@ function normalizeAIConfigBeforeSave() {
// 语音网关与 vision/embedding/rerank 一致audioBaseUrl 留空时不强写 DashScope
// 运行期由后端 audioRequestConfig 回退复用聊天网关。否则非 DashScope如万川会出现
// 「DashScope URL + 万川聊天 Key」的错配导致鉴权失败。用户填了独立语音网关则保留其值。
if (!['concise', 'medium', 'detailed'].includes(form.ai.replyDetail)) form.ai.replyDetail = 'detailed'
if (!['concise', 'medium', 'detailed'].includes(form.ai.replyDetail)) form.ai.replyDetail = 'medium'
if (looksLikeUrl(form.ai.audioApiKey)) {
form.ai.audioApiKey = ''
notify('语音 API Key 误填为 URL已清空并复用主 API Key', 'warn', 'ai')
@@ -2453,7 +2453,21 @@ async function rebuildKnowledge() {
try {
if (!(await saveConfig('knowledge', true))) return
const result = await RebuildKnowledgeIndex()
notify(result?.success ? '知识库索引已重建' : `重建失败: ${result?.message || ''}`, result?.success ? 'success' : 'error', 'knowledge')
if (result?.success) {
// 回显扫描到的文件数/分片数0 个文件多半是知识目录放错或文件在未支持的格式里,
// 此时给出醒目提示而不是笼统的“已重建”,避免“点了没反应”的误解。
const fileCount = Number(result?.data?.fileCount ?? 0)
const chunkCount = Number(result?.data?.chunkCount ?? 0)
const failedCount = (result?.data?.failedFiles || []).length
if (fileCount === 0) {
notify('知识库索引已重建,但未扫描到任何知识文件,请确认知识目录和文件格式是否正确。', 'error', 'knowledge')
} else {
const failedSuffix = failedCount > 0 ? `${failedCount} 个文件解析失败` : ''
notify(`知识库索引已重建:${fileCount} 个文件、${chunkCount} 个分片${failedSuffix}`, failedCount > 0 ? 'error' : 'success', 'knowledge')
}
} else {
notify(`重建失败: ${result?.message || ''}`, 'error', 'knowledge')
}
await loadStatus()
} catch (err) {
notify(`重建失败: ${err.message || err}`, 'error', 'knowledge')

View File

@@ -193,7 +193,7 @@ if (typeof window.go === 'undefined') {
visionModel: 'qwen3-vl-plus',
timeoutSeconds: 20,
enableThinking: false,
replyDetail: 'detailed',
replyDetail: 'medium',
temperature: 0,
maxTokens: 700
},