feat: 支持工作流知识库多库检索

This commit is contained in:
2026-09-04 17:40:55 +08:00
parent 386cebf342
commit 9722bea701
56 changed files with 5539 additions and 154 deletions

View File

@@ -0,0 +1,186 @@
import type { Parameter, SelectItem } from '#types';
export function normalizeKnowledgeIds(data: Record<string, any>): string[] {
if (Array.isArray(data.knowledgeIds)) {
const seen = new Set<string>();
return data.knowledgeIds.flatMap((id: unknown) => {
if (id === null || id === undefined) return [];
const value = String(id).trim();
if (!value || seen.has(value)) return [];
seen.add(value);
return [value];
});
}
return data.knowledgeId === null || data.knowledgeId === undefined || String(data.knowledgeId).trim() === ''
? []
: [String(data.knowledgeId).trim()];
}
export function toggleKnowledgeId(
selectedIds: Array<number | string>,
value: number | string,
): string[] {
const key = String(value);
return selectedIds.some((id) => String(id) === key)
? selectedIds.filter((id) => String(id) !== key).map(String)
: [...selectedIds.map(String), key];
}
export function applyEmbeddingCompatibility(
items: SelectItem[],
selectedIds: Array<number | string>,
): SelectItem[] {
const selectedKeys = new Set(selectedIds.map(String));
const normalizedItems = items.map((item) => ({ ...item, value: String(item.value) }));
for (const selectedId of selectedIds.map(String)) {
if (!normalizedItems.some((item) => String(item.value) === selectedId)) {
normalizedItems.push({
value: selectedId,
label: `已失效知识库(${selectedId}`,
selectable: true,
disabledReason: '知识库不存在或已无权限,仅可移除',
});
}
}
const firstSelected = normalizedItems.find(
(item) => String(item.value) === String(selectedIds[0]),
);
if (!firstSelected) return normalizedItems;
const vectorState = (item: SelectItem): 'available' | 'unavailable' | 'unknown' => {
if (item.vectorStoreEnabled === false) return 'unavailable';
if (
item.vectorStoreEnabled === true
&& item.embeddingModelId !== null
&& item.embeddingModelId !== undefined
&& item.embeddingDimension !== null
&& item.embeddingDimension !== undefined
) {
return 'available';
}
return 'unknown';
};
const firstState = vectorState(firstSelected);
const isCompatible = (item: SelectItem) => firstState === 'available'
&& vectorState(item) === 'available'
&& firstSelected.embeddingModelId === item.embeddingModelId
&& firstSelected.embeddingDimension === item.embeddingDimension;
return normalizedItems.map((item) => {
if (selectedKeys.has(String(item.value))) {
if (item.disabledReason) return item;
const itemState = vectorState(item);
if (itemState === 'unavailable') {
return {
...item,
selectable: true,
disabledReason: '未启用向量检索,仅可移除',
};
}
if (
firstState === 'available'
&& itemState === 'available'
&& !isCompatible(item)
) {
return {
...item,
selectable: true,
disabledReason: '与首个知识库的 Embedding 配置不一致,仅可移除',
};
}
return { ...item, selectable: true, disabledReason: undefined };
}
const itemState = vectorState(item);
if (firstSelected.disabledReason || firstState === 'unavailable') {
return {
...item,
selectable: false,
disabledReason: '请先移除未启用向量检索的知识库',
};
}
if (itemState === 'unavailable') {
return {
...item,
selectable: false,
disabledReason: '未启用向量检索',
};
}
if (firstState === 'unknown' || itemState === 'unknown') {
return { ...item, selectable: true, disabledReason: undefined };
}
return isCompatible(item)
? { ...item, selectable: true, disabledReason: undefined }
: {
...item,
selectable: false,
disabledReason: '与首个知识库的 Embedding 模型或向量维度不一致',
};
});
}
export function buildKnowledgeSelectItems(
items: SelectItem[],
selectedIds: Array<number | string>,
reloadItem?: SelectItem,
): SelectItem[] {
const compatibleItems = applyEmbeddingCompatibility(items, selectedIds);
return reloadItem
? [
...compatibleItems,
{ ...reloadItem, selectable: true, disabledReason: undefined },
]
: compatibleItems;
}
const locked = (parameter: Parameter): Parameter => ({
...parameter,
nameDisabled: true,
dataTypeDisabled: true,
deleteDisabled: true,
});
const expectedOutputDefs: Parameter[] = [
locked({
id: 'knowledge_documents',
name: 'documents',
dataType: 'Array',
addChildDisabled: true,
children: [
locked({ id: 'knowledge_documents_title', name: 'title', dataType: 'String' }),
locked({ id: 'knowledge_documents_content', name: 'content', dataType: 'String' }),
locked({ id: 'knowledge_documents_document_id', name: 'documentId', dataType: 'Number' }),
locked({ id: 'knowledge_documents_knowledge_id', name: 'knowledgeId', dataType: 'Number' }),
],
}),
];
function mergeParameter(current: Parameter | undefined, expected: Parameter): Parameter {
if (!current) {
return {
...expected,
children: expected.children?.map((child) => ({ ...child })),
};
}
const result = { ...current, ...expected, id: current.id || expected.id };
if (expected.children) {
const currentChildren = current.children || [];
result.children = expected.children.map((child) =>
mergeParameter(
currentChildren.find((item) => item.name === child.name),
child,
),
);
}
return result;
}
export function ensureKnowledgeOutputDefs(outputDefs?: Parameter[]): Parameter[] {
const current = outputDefs || [];
return expectedOutputDefs.map((expected) =>
mergeParameter(
current.find((item) => item.name === expected.name),
expected,
),
);
}