feat: 重构知识库系统,移除Hermes集成,增强RAG和同步功能

主要变更:
- 移除Hermes智能体及相关回调服务
- 新增知识库RAG、同步、调度、规范化和索引任务服务
- 重构orchestrator服务,增强运行时聊天功能
- 更新前端聊天、政策制度、设置等页面样式和逻辑
- 更新expense_claims和document_intelligence服务
- 删除llm_wiki相关服务和测试文件
- 更新docker-compose配置和启动脚本
This commit is contained in:
caoxiaozhu
2026-05-17 08:38:41 +00:00
parent 212c935308
commit 68f663f2f4
308 changed files with 83729 additions and 13588 deletions

View File

@@ -39,8 +39,8 @@ const SECTION_DEFINITIONS = [
id: 'llm',
label: '大语言模型',
title: '模型接入配置',
desc: '主模型、备份模型与多模态模型',
longDesc: '集中维护主模型、备份模型、VLM 模型和 Embedding 模型的接入参数,供 AI 助手和识别链路调用。',
desc: '主模型、备份模型与检索模型',
longDesc: '集中维护主模型、备份模型、Embedding 模型和 Reranker 模型的接入参数,供 AI 助手和检索链路调用。',
actionLabel: '保存模型配置'
},
{
@@ -82,7 +82,7 @@ const PROVIDER_OPTIONS = [
CUSTOM_OPENAI_PROVIDER
]
const PROVIDER_ENDPOINTS = {
const PROVIDER_ENDPOINTS = {
MiniMax: 'https://api.minimaxi.com/v1',
GLM: 'https://open.bigmodel.cn/api/paas/v4/',
Kimi: 'https://api.moonshot.ai/v1',
@@ -90,8 +90,13 @@ const PROVIDER_ENDPOINTS = {
Codex: 'https://api.openai.com/v1',
Claude: 'https://api.anthropic.com/v1/',
Gemini: 'https://generativelanguage.googleapis.com/v1beta/openai/',
[CUSTOM_OPENAI_PROVIDER]: ''
}
[CUSTOM_OPENAI_PROVIDER]: ''
}
const RERANKER_PROVIDER_ENDPOINTS = {
Ali: 'https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank',
[CUSTOM_OPENAI_PROVIDER]: ''
}
const LEGACY_PROVIDER_MAP = {
'OpenAI Compatible': 'Codex',
@@ -117,23 +122,23 @@ const MODEL_TEST_CONFIGS = {
apiKeyKey: 'backupApiKey',
capability: 'chat'
},
vlm: {
label: 'VLM 模型',
providerKey: 'vlmProvider',
modelKey: 'vlmModel',
endpointKey: 'vlmEndpoint',
apiKeyKey: 'vlmApiKey',
capability: 'chat'
},
embedding: {
label: 'Embedding 模型',
providerKey: 'embeddingProvider',
modelKey: 'embeddingModel',
endpointKey: 'embeddingEndpoint',
apiKeyKey: 'embeddingApiKey',
capability: 'embedding'
}
}
embedding: {
label: 'Embedding 模型',
providerKey: 'embeddingProvider',
modelKey: 'embeddingModel',
endpointKey: 'embeddingEndpoint',
apiKeyKey: 'embeddingApiKey',
capability: 'embedding'
},
reranker: {
label: 'Reranker 模型',
providerKey: 'rerankerProvider',
modelKey: 'rerankerModel',
endpointKey: 'rerankerEndpoint',
apiKeyKey: 'rerankerApiKey',
capability: 'reranker'
}
}
const MODEL_API_KEY_CONFIGS = Object.values(MODEL_TEST_CONFIGS)
const SESSION_RETENTION_OPTIONS = Array.from({ length: 10 }, (_item, index) => ({
@@ -159,9 +164,13 @@ function normalizeProviderValue(value, fallback = 'Codex') {
return fallback
}
function getProviderEndpoint(provider) {
return PROVIDER_ENDPOINTS[provider] ?? ''
}
function getProviderEndpoint(provider) {
return PROVIDER_ENDPOINTS[provider] ?? ''
}
function getRerankerEndpoint(provider) {
return RERANKER_PROVIDER_ENDPOINTS[provider] ?? getProviderEndpoint(provider)
}
function buildDefaultState(companyProfile, currentUser) {
const companyName = normalizeValue(companyProfile?.name) || 'X-Financial'
@@ -201,21 +210,21 @@ function buildDefaultState(companyProfile, currentUser) {
mainEndpoint: getProviderEndpoint('Codex'),
mainApiKey: '',
mainApiKeyConfigured: false,
backupProvider: 'GLM',
backupModel: 'glm-5.1',
backupEndpoint: getProviderEndpoint('GLM'),
backupApiKey: '',
backupApiKeyConfigured: false,
vlmProvider: 'Gemini',
vlmModel: 'gemini-2.5-flash',
vlmEndpoint: getProviderEndpoint('Gemini'),
vlmApiKey: '',
vlmApiKeyConfigured: false,
embeddingProvider: 'GLM',
embeddingModel: 'Embedding-3',
backupProvider: 'GLM',
backupModel: 'glm-5.1',
backupEndpoint: getProviderEndpoint('GLM'),
backupApiKey: '',
backupApiKeyConfigured: false,
embeddingProvider: 'GLM',
embeddingModel: 'Embedding-3',
embeddingEndpoint: getProviderEndpoint('GLM'),
embeddingApiKey: '',
embeddingApiKeyConfigured: false
embeddingApiKeyConfigured: false,
rerankerProvider: 'Ali',
rerankerModel: 'gte-rerank-v2',
rerankerEndpoint: getRerankerEndpoint('Ali'),
rerankerApiKey: '',
rerankerApiKeyConfigured: false
},
renderForm: {
enabled: false,
@@ -268,15 +277,18 @@ function readStoredSettings() {
}
function mergeState(baseState, overrideState) {
const mergedLlmForm = { ...baseState.llmForm, ...(overrideState?.llmForm || {}) }
mergedLlmForm.mainProvider = normalizeProviderValue(mergedLlmForm.mainProvider, baseState.llmForm.mainProvider)
mergedLlmForm.backupProvider = normalizeProviderValue(mergedLlmForm.backupProvider, baseState.llmForm.backupProvider)
mergedLlmForm.vlmProvider = normalizeProviderValue(mergedLlmForm.vlmProvider, baseState.llmForm.vlmProvider)
mergedLlmForm.embeddingProvider = normalizeProviderValue(
mergedLlmForm.embeddingProvider,
baseState.llmForm.embeddingProvider
)
const mergedLlmForm = { ...baseState.llmForm, ...(overrideState?.llmForm || {}) }
mergedLlmForm.mainProvider = normalizeProviderValue(mergedLlmForm.mainProvider, baseState.llmForm.mainProvider)
mergedLlmForm.backupProvider = normalizeProviderValue(mergedLlmForm.backupProvider, baseState.llmForm.backupProvider)
mergedLlmForm.embeddingProvider = normalizeProviderValue(
mergedLlmForm.embeddingProvider,
baseState.llmForm.embeddingProvider
)
mergedLlmForm.rerankerProvider = normalizeProviderValue(
mergedLlmForm.rerankerProvider,
baseState.llmForm.rerankerProvider
)
return {
companyForm: { ...baseState.companyForm, ...(overrideState?.companyForm || {}) },
@@ -302,8 +314,8 @@ function sanitizeForStorage(state) {
...state.llmForm,
mainApiKey: '',
backupApiKey: '',
vlmApiKey: '',
embeddingApiKey: ''
embeddingApiKey: '',
rerankerApiKey: ''
},
renderForm: {
...state.renderForm,
@@ -402,11 +414,15 @@ function computeSectionStatus(state) {
llm: Boolean(
isModelConfigReady(state.llmForm.mainProvider, state.llmForm.mainModel, state.llmForm.mainEndpoint) &&
isModelConfigReady(state.llmForm.backupProvider, state.llmForm.backupModel, state.llmForm.backupEndpoint) &&
isModelConfigReady(state.llmForm.vlmProvider, state.llmForm.vlmModel, state.llmForm.vlmEndpoint) &&
isModelConfigReady(
state.llmForm.embeddingProvider,
state.llmForm.embeddingModel,
state.llmForm.embeddingEndpoint
) &&
isModelConfigReady(
state.llmForm.rerankerProvider,
state.llmForm.rerankerModel,
state.llmForm.rerankerEndpoint
)
),
rendering: Boolean(
@@ -440,11 +456,11 @@ export default {
const sessionRetentionPickerOpen = ref(false)
const sessionRetentionPickerRef = ref(null)
const modelTestState = ref({
main: { status: 'idle', message: '' },
backup: { status: 'idle', message: '' },
vlm: { status: 'idle', message: '' },
embedding: { status: 'idle', message: '' }
})
main: { status: 'idle', message: '' },
backup: { status: 'idle', message: '' },
embedding: { status: 'idle', message: '' },
reranker: { status: 'idle', message: '' }
})
const sections = SECTION_DEFINITIONS
const logLevels = LOG_LEVELS
@@ -484,8 +500,8 @@ export default {
if (preserveModelApiKeys) {
nextState.llmForm.mainApiKey = currentState.llmForm.mainApiKey
nextState.llmForm.backupApiKey = currentState.llmForm.backupApiKey
nextState.llmForm.vlmApiKey = currentState.llmForm.vlmApiKey
nextState.llmForm.embeddingApiKey = currentState.llmForm.embeddingApiKey
nextState.llmForm.rerankerApiKey = currentState.llmForm.rerankerApiKey
}
if (preserveAdminPasswords) {
@@ -582,7 +598,8 @@ export default {
const provider = normalizeProviderValue(llmForm[config.providerKey], CUSTOM_OPENAI_PROVIDER)
llmForm[config.providerKey] = provider
llmForm[config.endpointKey] = getProviderEndpoint(provider)
llmForm[config.endpointKey] =
slot === 'reranker' ? getRerankerEndpoint(provider) : getProviderEndpoint(provider)
}
function getModelTestState(testKey) {
@@ -735,12 +752,12 @@ export default {
async function saveLlmSection() {
const llmForm = pageState.value.llmForm
const modelConfigs = [
['主模型', llmForm.mainProvider, llmForm.mainModel, llmForm.mainEndpoint],
['备份模型', llmForm.backupProvider, llmForm.backupModel, llmForm.backupEndpoint],
['VLM 模型', llmForm.vlmProvider, llmForm.vlmModel, llmForm.vlmEndpoint],
['Embedding 模型', llmForm.embeddingProvider, llmForm.embeddingModel, llmForm.embeddingEndpoint]
]
const modelConfigs = [
['主模型', llmForm.mainProvider, llmForm.mainModel, llmForm.mainEndpoint],
['备份模型', llmForm.backupProvider, llmForm.backupModel, llmForm.backupEndpoint],
['Embedding 模型', llmForm.embeddingProvider, llmForm.embeddingModel, llmForm.embeddingEndpoint],
['Reranker 模型', llmForm.rerankerProvider, llmForm.rerankerModel, llmForm.rerankerEndpoint]
]
for (const [label, provider, model, endpoint] of modelConfigs) {
if (!isModelConfigReady(provider, model, endpoint)) {