mirror of
https://github.com/nocobase/nocobase.git
synced 2026-08-28 17:43:07 +08:00
feat(plugin-ai): support knowledge base retrieval strategies (#10362)
* feat(plugin-ai): support knowledge base retrieval strategies * fix(plugin-ai): report unavailable knowledge base access * fix(plugin-ai): refine knowledge base access notice * fix(plugin-ai): complete knowledge base feature contract * docs(ai): update RAG retrieval and permission guidance * docs(ai): sync RAG guidance across languages
This commit is contained in:
@@ -1,33 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "RAG 检索增强生成"
|
||||
description: "在 AI 员工设置中启用 RAG,配置 Knowledge Base Prompt、知识库选择、Top K、Score 阈值,AI 基于检索文档回复。"
|
||||
keywords: "RAG,检索增强,知识库检索,Top K,NocoBase"
|
||||
description: "在 AI 员工设置中启用 RAG,配置 Knowledge Base、Retrieval strategy、Top K 和 Score,并按用户角色控制知识库访问权限。"
|
||||
keywords: "RAG,检索增强,知识库检索,Retrieval strategy,知识库权限,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# RAG 检索
|
||||
|
||||
## 介绍
|
||||
|
||||
配置好知识库后,就可以在 AI 员工设置中启用 RAG 功能了。
|
||||
在 NocoBase 中,**RAG(检索增强生成)** 可以让 AI 员工先从知识库获取相关内容,再结合这些内容回答问题。
|
||||
|
||||
启用了 RAG 后,用户与 AI 员工对话时,AI 员工会使用 RAG 检索,用用户消息从知识库获取文档并基于检索到的文档回复。
|
||||
AI 员工实际可以使用哪些知识库,由 AI 员工的「Knowledge Base」配置和当前用户所属角色的知识库权限共同决定。只有同时处于这两个范围内的知识库,才会参与检索。
|
||||
|
||||
## 启用 RAG
|
||||
## 配置 AI 员工的知识库
|
||||
|
||||
进入 AI 员工插件配置页面,点击 `AI employees` 标签页,进入 AI 员工管理页。
|
||||
进入「AI employees」配置页,选择要启用 RAG 的 AI 员工,点击「Edit」。在编辑抽屉中切换到「Knowledge Base」标签页,然后打开「Enable」开关。
|
||||
|
||||

|
||||

|
||||
|
||||
选择要启用 RAG 的 AI 员工,点击 `Edit` 按钮,进入 AI 员工编辑页面。
|
||||
其中:
|
||||
|
||||
在`Knowledge base` 标签页中,打开`Enable`开关。
|
||||
- 「Knowledge Base」— 可选。留空时,会从当前用户角色有权访问的所有已启用知识库中检索;选择知识库后,只会从选中且有权访问的知识库中检索
|
||||
- 「Retrieval strategy」— 设置什么时候检索知识库,其中:
|
||||
- 「Retrieve on demand」— AI 员工判断当前问题需要知识库内容时才执行检索。新建 AI 员工默认使用该策略,通常来说也推荐使用该策略
|
||||
- 「Automatically retrieve for every question」— 在每个用户问题发送给 AI 员工前执行检索,适合每轮对话都依赖知识库内容的场景
|
||||
- 「Knowledge Base Prompt」— 设置如何把检索内容提供给 AI 员工。`{knowledgeBaseData}` 是固定占位符,不要删除或修改
|
||||
- 「Top K」— 每次检索最多返回的知识库内容数量,可设置为 1–100,默认为 3
|
||||
- 「Score」— 检索结果需要达到的最低相似度,可设置为 0–1,默认为 0.6。数值越高,进入结果的内容越相关,返回数量也可能越少
|
||||
|
||||
- 在 `Knowledge Base Prompt` 输入引用知识库的提示语,`{knowledgeBaseData}` 是固定的占位符,不要修改;
|
||||
- 在 `Knowledge Base` 选择配置好的知识库,参考:[知识库](./knowledge-base/);
|
||||
- 在 `Top K` 输入框中输入要检索的文档数量,默认为 3 个;
|
||||
- 在 `Score` 输入框检索时文档相关系阈值;
|
||||
配置完成后,点击「Submit」保存。
|
||||
|
||||
点击 `Submit` 按钮保存 AI 员工设置。
|
||||
## 配置知识库权限
|
||||
|
||||

|
||||
AI 员工选择了知识库,不代表所有用户都能访问这些知识库。还需要进入「Users & Permissions / Roles & Permissions」,选择用户所属的角色,然后打开「Permissions / Knowledge bases」。
|
||||
|
||||
在知识库列表中勾选「Available」,为该角色授予对应知识库的访问权限。如果希望以后新建的知识库自动对该角色开放,可以勾选「New knowledge bases are allowed by default」。
|
||||
|
||||

|
||||
|
||||
:::warning 注意
|
||||
|
||||
AI 员工检索的知识库范围,是「Knowledge Base」配置与当前用户角色权限的交集。未授权的知识库会被自动排除。
|
||||
|
||||
:::
|
||||
|
||||
## 没有知识库权限时
|
||||
|
||||
如果 AI 员工已经启用知识库,但配置范围与当前用户角色权限没有任何交集,AI 员工会先使用不依赖知识库的信息回答问题,然后在回答末尾醒目提示:本次回答没有使用知识库内容,因为当前用户没有知识库访问权限;如需使用,请联系管理员申请权限。
|
||||
|
||||

|
||||
|
||||
如果当前用户存在可访问的知识库,只是当前问题没有检索到相关内容,则不会显示无权限提示。
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [知识库](./knowledge-base/index.md) — 创建和维护用于 RAG 检索的知识库
|
||||
- [角色与权限](../../users-permissions/acl/permissions.md) — 配置角色的系统、菜单和数据访问权限
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "RAG – Retrieval-Augmented Generation"
|
||||
description: "Aktivieren Sie RAG für KI-Mitarbeiter, konfigurieren Sie Knowledge Base, Retrieval strategy, Top K und Score und steuern Sie den Zugriff auf Wissensdatenbanken über Benutzerrollen."
|
||||
keywords: "RAG,Retrieval-Augmented Generation,Wissensdatenbank-Abruf,Retrieval strategy,Wissensdatenbank-Berechtigungen,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# RAG-Abruf
|
||||
|
||||
## Einführung
|
||||
|
||||
Nachdem Sie die Wissensdatenbank konfiguriert haben, können Sie die RAG-Funktion in den Einstellungen des KI-Mitarbeiters aktivieren.
|
||||
In NocoBase ermöglicht **RAG (Retrieval-Augmented Generation)** einem KI-Mitarbeiter, vor der Beantwortung einer Frage relevante Inhalte aus Wissensdatenbanken abzurufen.
|
||||
|
||||
Wenn RAG aktiviert ist, nutzt der KI-Mitarbeiter beim Dialog mit einem Benutzer den RAG-Abruf. Er ruft Dokumente aus der Wissensdatenbank basierend auf der Nachricht des Benutzers ab und antwortet dann auf Grundlage dieser abgerufenen Dokumente.
|
||||
Welche Wissensdatenbanken ein KI-Mitarbeiter tatsächlich verwenden kann, ergibt sich sowohl aus seiner `Knowledge Base`-Konfiguration als auch aus den Wissensdatenbank-Berechtigungen der Rollen des aktuellen Benutzers. Nur Wissensdatenbanken, die in beiden Bereichen enthalten sind, werden durchsucht.
|
||||
|
||||
## RAG aktivieren
|
||||
## Wissensdatenbanken eines KI-Mitarbeiters konfigurieren
|
||||
|
||||
Navigieren Sie zur Konfigurationsseite des KI-Mitarbeiter-Plugins und klicken Sie auf den Tab `AI employees`, um zur Verwaltungsseite der KI-Mitarbeiter zu gelangen.
|
||||
Öffnen Sie die Konfigurationsseite `AI employees`, wählen Sie den KI-Mitarbeiter aus, für den Sie RAG aktivieren möchten, und klicken Sie auf `Edit`. Öffnen Sie im Bearbeitungsbereich den Tab `Knowledge Base` und aktivieren Sie `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Wählen Sie den KI-Mitarbeiter aus, für den Sie RAG aktivieren möchten, und klicken Sie auf die Schaltfläche `Edit`, um die Bearbeitungsseite des KI-Mitarbeiters aufzurufen.
|
||||
Folgende Einstellungen stehen zur Verfügung:
|
||||
|
||||
Im Tab `Knowledge base` schalten Sie den `Enable`-Schalter ein.
|
||||
- `Knowledge Base` — Optional. Wenn das Feld leer bleibt, durchsucht der KI-Mitarbeiter alle aktivierten Wissensdatenbanken, auf die die Rollen des aktuellen Benutzers zugreifen dürfen. Wenn Sie Wissensdatenbanken auswählen, werden nur die ausgewählten und für den Benutzer freigegebenen Wissensdatenbanken durchsucht
|
||||
- `Retrieval strategy` — Legt fest, wann der Abruf aus Wissensdatenbanken ausgeführt wird:
|
||||
- `Retrieve on demand` — Der KI-Mitarbeiter ruft Inhalte nur dann ab, wenn er feststellt, dass sie für die aktuelle Frage benötigt werden. Neue KI-Mitarbeiter verwenden diese Strategie standardmäßig; sie wird für die meisten Anwendungsfälle empfohlen
|
||||
- `Automatically retrieve for every question` — Der Abruf wird vor jeder Benutzerfrage ausgeführt, bevor diese an den KI-Mitarbeiter gesendet wird. Verwenden Sie diese Option, wenn jede Interaktion von Inhalten aus Wissensdatenbanken abhängt
|
||||
- `Knowledge Base Prompt` — Legt fest, wie die abgerufenen Inhalte an den KI-Mitarbeiter übergeben werden. `{knowledgeBaseData}` ist ein fester Platzhalter und darf nicht entfernt oder geändert werden
|
||||
- `Top K` — Die maximale Anzahl der bei jedem Abruf zurückgegebenen Ergebnisse. Der Wertebereich ist 1–100, der Standardwert ist 3
|
||||
- `Score` — Der minimale Ähnlichkeitswert, den ein Ergebnis erreichen muss. Der Wertebereich ist 0–1, der Standardwert ist 0,6. Ein höherer Wert liefert relevantere Inhalte, kann aber zu weniger Ergebnissen führen
|
||||
|
||||
- Geben Sie im Feld `Knowledge Base Prompt` den Prompt ein, der auf die Wissensdatenbank verweist. `{knowledgeBaseData}` ist ein fester Platzhalter und darf nicht geändert werden.
|
||||
- Wählen Sie unter `Knowledge Base` die konfigurierte Wissensdatenbank aus. Siehe: [Wissensdatenbank](./knowledge-base/).
|
||||
- Geben Sie im Eingabefeld `Top K` die Anzahl der abzurufenden Dokumente ein; der Standardwert ist 3.
|
||||
- Im Eingabefeld `Score` geben Sie den Schwellenwert für die Dokumentrelevanz beim Abruf ein.
|
||||
Klicken Sie auf `Submit`, um die Konfiguration zu speichern.
|
||||
|
||||
Klicken Sie auf die Schaltfläche `Submit`, um die Einstellungen des KI-Mitarbeiters zu speichern.
|
||||
## Berechtigungen für Wissensdatenbanken konfigurieren
|
||||
|
||||

|
||||
Die Auswahl von Wissensdatenbanken für einen KI-Mitarbeiter gewährt nicht automatisch allen Benutzern Zugriff. Öffnen Sie `Users & Permissions / Roles & Permissions`, wählen Sie die dem Benutzer zugewiesene Rolle aus und öffnen Sie anschließend `Permissions / Knowledge bases`.
|
||||
|
||||
Aktivieren Sie `Available` für jede Wissensdatenbank, auf die die Rolle zugreifen darf. Um dieser Rolle automatisch Zugriff auf künftig erstellte Wissensdatenbanken zu gewähren, aktivieren Sie `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Hinweis
|
||||
|
||||
Der für einen KI-Mitarbeiter verfügbare Wissensdatenbank-Bereich ist die Schnittmenge aus seiner `Knowledge Base`-Konfiguration und den Rollenberechtigungen des aktuellen Benutzers. Nicht autorisierte Wissensdatenbanken werden automatisch ausgeschlossen.
|
||||
|
||||
:::
|
||||
|
||||
## Wenn der Benutzer keinen Zugriff auf Wissensdatenbanken hat
|
||||
|
||||
Wenn Wissensdatenbanken für einen KI-Mitarbeiter aktiviert sind, der konfigurierte Bereich sich jedoch nicht mit den Rollenberechtigungen des aktuellen Benutzers überschneidet, antwortet der KI-Mitarbeiter zunächst mit Informationen, die nicht von einer Wissensdatenbank abhängen. Anschließend fügt er einen deutlich sichtbaren Hinweis hinzu, dass wegen fehlender Zugriffsrechte keine Inhalte aus Wissensdatenbanken verwendet wurden und der Benutzer sich bei Bedarf an einen Administrator wenden soll.
|
||||
|
||||

|
||||
|
||||
Wenn der Benutzer auf mindestens eine Wissensdatenbank zugreifen kann, für die aktuelle Frage jedoch keine relevanten Inhalte gefunden werden, wird der Hinweis auf fehlende Berechtigungen nicht angezeigt.
|
||||
|
||||
## Verwandte Links
|
||||
|
||||
- [Wissensdatenbank](./knowledge-base/index.md) — Wissensdatenbanken für den RAG-Abruf erstellen und verwalten
|
||||
- [Rollen und Berechtigungen](../../users-permissions/acl/permissions.md) — System-, Menü- und Datenzugriff für Rollen konfigurieren
|
||||
|
||||
@@ -1,29 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "RAG Retrieval-Augmented Generation"
|
||||
description: "Enable RAG for AI employees, configure the Knowledge Base, Retrieval strategy, Top K, and Score, and control knowledge-base access through user roles."
|
||||
keywords: "RAG,retrieval-augmented generation,knowledge-base retrieval,Retrieval strategy,knowledge-base permissions,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# RAG Retrieval
|
||||
|
||||
## Introduction
|
||||
|
||||
After configuring the knowledge base, you can enable the RAG feature in the AI employee settings.
|
||||
In NocoBase, **RAG (Retrieval-Augmented Generation)** enables an AI employee to retrieve relevant content from knowledge bases before answering a question.
|
||||
|
||||
With RAG enabled, when a user chats with an AI employee, the AI employee will use RAG retrieval to fetch documents from the knowledge base based on the user's message and reply based on the retrieved documents.
|
||||
The knowledge bases an AI employee can actually use are determined by both the employee's `Knowledge Base` configuration and the knowledge-base permissions of the current user's roles. Only knowledge bases included in both scopes are searched.
|
||||
|
||||
## Enable RAG
|
||||
## Configure an AI employee's knowledge bases
|
||||
|
||||
Go to the AI employee plugin configuration page, click the `AI employees` tab to enter the AI employee management page.
|
||||
Go to the `AI employees` configuration page, select the AI employee for which you want to enable RAG, and click `Edit`. In the edit drawer, open the `Knowledge Base` tab and turn on `Enable`.
|
||||
|
||||

|
||||
|
||||

|
||||
The available settings are:
|
||||
|
||||
- `Knowledge Base` — Optional. If left empty, the AI employee searches all enabled knowledge bases accessible to the current user's roles. If you select knowledge bases, it searches only the selected knowledge bases that the user is allowed to access
|
||||
- `Retrieval strategy` — Controls when knowledge-base retrieval runs:
|
||||
- `Retrieve on demand` — The AI employee retrieves knowledge-base content only when it determines that the current question requires it. New AI employees use this strategy by default, and it is the recommended option for most cases
|
||||
- `Automatically retrieve for every question` — Retrieval runs before every user question is sent to the AI employee. Use this when every turn depends on knowledge-base content
|
||||
- `Knowledge Base Prompt` — Defines how retrieved content is provided to the AI employee. `{knowledgeBaseData}` is a fixed placeholder; do not remove or modify it
|
||||
- `Top K` — The maximum number of knowledge-base results returned by each retrieval. The range is 1–100, and the default is 3
|
||||
- `Score` — The minimum similarity score required for a result. The range is 0–1, and the default is 0.6. A higher value returns more relevant content, but may produce fewer results
|
||||
|
||||
Select the AI employee for which you want to enable RAG, click the `Edit` button to enter the AI employee editing page.
|
||||
Click `Submit` to save the configuration.
|
||||
|
||||
In the `Knowledge base` tab, turn on the `Enable` switch.
|
||||
## Configure knowledge-base permissions
|
||||
|
||||
- In `Knowledge Base Prompt`, enter the prompt for referencing the knowledge base. `{knowledgeBaseData}` is a fixed placeholder and should not be modified.
|
||||
- In `Knowledge Base`, select the configured knowledge base. See: [Knowledge Base](./knowledge-base/).
|
||||
- In the `Top K` input box, enter the number of documents to retrieve, the default is 3.
|
||||
- In the `Score` input box, enter the document relevance threshold for retrieval.
|
||||
Selecting knowledge bases for an AI employee does not give every user access to them. Go to `Users & Permissions / Roles & Permissions`, select the role assigned to the user, and then open `Permissions / Knowledge bases`.
|
||||
|
||||
Click the `Submit` button to save the AI employee settings.
|
||||
Select `Available` for each knowledge base that the role should be allowed to access. To automatically grant this role access to knowledge bases created later, select `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||

|
||||
:::warning Note
|
||||
|
||||
The knowledge-base scope available to an AI employee is the intersection of its `Knowledge Base` configuration and the current user's role permissions. Unauthorized knowledge bases are automatically excluded.
|
||||
|
||||
:::
|
||||
|
||||
## When the user has no knowledge-base access
|
||||
|
||||
If knowledge bases are enabled for an AI employee but its configured scope has no overlap with the current user's role permissions, the AI employee first answers with information that does not depend on a knowledge base. It then appends a prominent notice explaining that no knowledge-base content was used because the user does not have access and advising the user to contact an administrator.
|
||||
|
||||

|
||||
|
||||
If the user can access at least one knowledge base but the current question returns no relevant content, the no-permission notice is not displayed.
|
||||
|
||||
## Related links
|
||||
|
||||
- [Knowledge Base](./knowledge-base/index.md) — Create and maintain knowledge bases used for RAG retrieval
|
||||
- [Roles and permissions](../../users-permissions/acl/permissions.md) — Configure system, menu, and data access for roles
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "Generación aumentada por recuperación (RAG)"
|
||||
description: "Active RAG para los empleados de IA, configure Knowledge Base, Retrieval strategy, Top K y Score, y controle el acceso a las bases de conocimientos mediante los roles de usuario."
|
||||
keywords: "RAG,generación aumentada por recuperación,recuperación de bases de conocimientos,Retrieval strategy,permisos de bases de conocimientos,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# Recuperación RAG
|
||||
|
||||
## Introducción
|
||||
|
||||
Una vez que haya configurado la base de conocimientos, podrá habilitar la función RAG en la configuración de los empleados de IA.
|
||||
En NocoBase, **RAG (generación aumentada por recuperación)** permite que un empleado de IA recupere contenido relevante de las bases de conocimientos antes de responder una pregunta.
|
||||
|
||||
Cuando RAG está habilitado, al conversar con un empleado de IA, este utilizará la recuperación RAG para obtener documentos de la base de conocimientos basándose en el mensaje del usuario y responderá utilizando los documentos recuperados.
|
||||
Las bases de conocimientos que el empleado de IA puede utilizar se determinan tanto por su configuración de `Knowledge Base` como por los permisos de las bases de conocimientos asociados a los roles del usuario actual. Solo se buscan las bases incluidas en ambos ámbitos.
|
||||
|
||||
## Habilitar RAG
|
||||
## Configurar las bases de conocimientos de un empleado de IA
|
||||
|
||||
Vaya a la página de configuración del plugin de empleados de IA, haga clic en la pestaña `AI employees` para acceder a la página de gestión de empleados de IA.
|
||||
Vaya a la página de configuración `AI employees`, seleccione el empleado de IA para el que desea activar RAG y haga clic en `Edit`. En el panel de edición, abra la pestaña `Knowledge Base` y active `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Seleccione el empleado de IA para el que desea habilitar RAG, haga clic en el botón `Edit` para acceder a la página de edición del empleado de IA.
|
||||
Las opciones disponibles son:
|
||||
|
||||
En la pestaña `Knowledge base`, active el interruptor `Enable`.
|
||||
- `Knowledge Base` — Es opcional. Si se deja vacío, el empleado de IA buscará en todas las bases de conocimientos activadas a las que puedan acceder los roles del usuario actual. Si selecciona bases de conocimientos, solo buscará en las seleccionadas para las que el usuario tenga permiso
|
||||
- `Retrieval strategy` — Controla cuándo se ejecuta la recuperación desde las bases de conocimientos:
|
||||
- `Retrieve on demand` — El empleado de IA recupera contenido únicamente cuando determina que la pregunta actual lo necesita. Los nuevos empleados de IA usan esta estrategia de forma predeterminada y es la opción recomendada en la mayoría de los casos
|
||||
- `Automatically retrieve for every question` — La recuperación se ejecuta antes de enviar cada pregunta del usuario al empleado de IA. Utilice esta opción cuando cada interacción dependa del contenido de las bases de conocimientos
|
||||
- `Knowledge Base Prompt` — Define cómo se proporciona el contenido recuperado al empleado de IA. `{knowledgeBaseData}` es un marcador de posición fijo; no lo elimine ni lo modifique
|
||||
- `Top K` — Es el número máximo de resultados que devuelve cada recuperación. El intervalo es de 1 a 100 y el valor predeterminado es 3
|
||||
- `Score` — Es la puntuación mínima de similitud que debe alcanzar un resultado. El intervalo es de 0 a 1 y el valor predeterminado es 0,6. Un valor más alto devuelve contenido más relevante, aunque puede reducir el número de resultados
|
||||
|
||||
- En `Knowledge Base Prompt`, introduzca el mensaje (prompt) para referenciar la base de conocimientos. `{knowledgeBaseData}` es un marcador de posición fijo y no debe modificarse.
|
||||
- En `Knowledge Base`, seleccione la base de conocimientos configurada. Consulte: [Base de conocimientos](./knowledge-base/).
|
||||
- En el campo `Top K`, introduzca el número de documentos a recuperar; el valor predeterminado es 3.
|
||||
- En el campo `Score`, introduzca el umbral de relevancia de los documentos para la recuperación.
|
||||
Haga clic en `Submit` para guardar la configuración.
|
||||
|
||||
Haga clic en el botón `Submit` para guardar la configuración del empleado de IA.
|
||||
## Configurar los permisos de las bases de conocimientos
|
||||
|
||||

|
||||
Seleccionar bases de conocimientos para un empleado de IA no concede acceso a todos los usuarios. Vaya a `Users & Permissions / Roles & Permissions`, seleccione el rol asignado al usuario y abra `Permissions / Knowledge bases`.
|
||||
|
||||
Seleccione `Available` para cada base de conocimientos a la que el rol deba tener acceso. Para conceder automáticamente a este rol acceso a las bases de conocimientos que se creen más adelante, seleccione `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Nota
|
||||
|
||||
El ámbito de bases de conocimientos disponible para un empleado de IA es la intersección entre su configuración de `Knowledge Base` y los permisos de los roles del usuario actual. Las bases de conocimientos no autorizadas se excluyen automáticamente.
|
||||
|
||||
:::
|
||||
|
||||
## Cuando el usuario no tiene acceso a ninguna base de conocimientos
|
||||
|
||||
Si las bases de conocimientos están activadas para un empleado de IA, pero su ámbito configurado no coincide con los permisos de los roles del usuario actual, el empleado de IA responde primero con información que no depende de una base de conocimientos. Después añade un aviso destacado que indica que no se utilizó contenido de las bases de conocimientos porque el usuario no tiene acceso y recomienda contactar con un administrador.
|
||||
|
||||

|
||||
|
||||
Si el usuario puede acceder al menos a una base de conocimientos, pero la pregunta actual no devuelve contenido relevante, no se muestra el aviso de falta de permisos.
|
||||
|
||||
## Enlaces relacionados
|
||||
|
||||
- [Base de conocimientos](./knowledge-base/index.md) — Crear y mantener las bases de conocimientos utilizadas para la recuperación RAG
|
||||
- [Roles y permisos](../../users-permissions/acl/permissions.md) — Configurar el acceso al sistema, los menús y los datos para cada rol
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "Génération augmentée par récupération (RAG)"
|
||||
description: "Activez le RAG pour les employés IA, configurez Knowledge Base, Retrieval strategy, Top K et Score, puis contrôlez l'accès aux bases de connaissances à l'aide des rôles utilisateur."
|
||||
keywords: "RAG,génération augmentée par récupération,récupération de base de connaissances,Retrieval strategy,autorisations de base de connaissances,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# Récupération RAG
|
||||
|
||||
## Introduction
|
||||
|
||||
Une fois votre base de connaissances configurée, vous pouvez activer la fonctionnalité RAG dans les paramètres de l'employé IA.
|
||||
Dans NocoBase, le **RAG (génération augmentée par récupération)** permet à un employé IA de récupérer du contenu pertinent dans les bases de connaissances avant de répondre à une question.
|
||||
|
||||
Lorsque le RAG est activé, lorsqu'un utilisateur discute avec un employé IA, ce dernier utilisera la récupération RAG pour récupérer des documents de la base de connaissances en fonction du message de l'utilisateur et y répondra en se basant sur les documents récupérés.
|
||||
Les bases de connaissances qu'un employé IA peut réellement utiliser dépendent à la fois de sa configuration `Knowledge Base` et des autorisations associées aux rôles de l'utilisateur actuel. Seules les bases incluses dans ces deux périmètres sont interrogées.
|
||||
|
||||
## Activer le RAG
|
||||
## Configurer les bases de connaissances d'un employé IA
|
||||
|
||||
Accédez à la page de configuration du plugin employé IA, puis cliquez sur l'onglet `AI employees` pour accéder à la page de gestion des employés IA.
|
||||
Accédez à la page de configuration `AI employees`, sélectionnez l'employé IA pour lequel vous souhaitez activer le RAG, puis cliquez sur `Edit`. Dans le panneau d'édition, ouvrez l'onglet `Knowledge Base` et activez `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Sélectionnez l'employé IA pour lequel vous souhaitez activer le RAG, puis cliquez sur le bouton `Edit` pour accéder à sa page d'édition.
|
||||
Les paramètres disponibles sont les suivants :
|
||||
|
||||
Dans l'onglet `Knowledge base`, activez l'interrupteur `Enable`.
|
||||
- `Knowledge Base` — Facultatif. Si ce champ reste vide, l'employé IA interroge toutes les bases de connaissances activées auxquelles les rôles de l'utilisateur actuel ont accès. Si vous sélectionnez des bases, seules celles qui sont sélectionnées et autorisées pour l'utilisateur sont interrogées
|
||||
- `Retrieval strategy` — Détermine quand la récupération depuis les bases de connaissances est exécutée :
|
||||
- `Retrieve on demand` — L'employé IA récupère du contenu uniquement lorsqu'il estime que la question actuelle en a besoin. Les nouveaux employés IA utilisent cette stratégie par défaut, et elle est recommandée dans la plupart des cas
|
||||
- `Automatically retrieve for every question` — La récupération est exécutée avant l'envoi de chaque question à l'employé IA. Utilisez cette option lorsque chaque interaction dépend du contenu des bases de connaissances
|
||||
- `Knowledge Base Prompt` — Définit comment le contenu récupéré est transmis à l'employé IA. `{knowledgeBaseData}` est un espace réservé fixe ; ne le supprimez pas et ne le modifiez pas
|
||||
- `Top K` — Nombre maximal de résultats renvoyés à chaque récupération. La plage est comprise entre 1 et 100, et la valeur par défaut est 3
|
||||
- `Score` — Score minimal de similarité requis pour un résultat. La plage est comprise entre 0 et 1, et la valeur par défaut est 0,6. Une valeur plus élevée produit du contenu plus pertinent, mais peut réduire le nombre de résultats
|
||||
|
||||
- Dans le champ `Knowledge Base Prompt`, saisissez l'invite pour référencer la base de connaissances. `{knowledgeBaseData}` est un espace réservé fixe et ne doit pas être modifié.
|
||||
- Dans le champ `Knowledge Base`, sélectionnez la base de connaissances configurée. Référencez : [Base de connaissances](./knowledge-base/).
|
||||
- Dans le champ `Top K`, saisissez le nombre de documents à récupérer. La valeur par défaut est de 3.
|
||||
- Dans le champ `Score`, saisissez le seuil de pertinence des documents pour la récupération.
|
||||
Cliquez sur `Submit` pour enregistrer la configuration.
|
||||
|
||||
Cliquez sur le bouton `Submit` pour enregistrer les paramètres de l'employé IA.
|
||||
## Configurer les autorisations des bases de connaissances
|
||||
|
||||

|
||||
Sélectionner des bases de connaissances pour un employé IA ne donne pas accès à tous les utilisateurs. Accédez à `Users & Permissions / Roles & Permissions`, sélectionnez le rôle attribué à l'utilisateur, puis ouvrez `Permissions / Knowledge bases`.
|
||||
|
||||
Sélectionnez `Available` pour chaque base de connaissances à laquelle le rôle doit pouvoir accéder. Pour accorder automatiquement à ce rôle l'accès aux bases créées ultérieurement, sélectionnez `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Remarque
|
||||
|
||||
Le périmètre des bases de connaissances disponible pour un employé IA correspond à l'intersection entre sa configuration `Knowledge Base` et les autorisations des rôles de l'utilisateur actuel. Les bases non autorisées sont automatiquement exclues.
|
||||
|
||||
:::
|
||||
|
||||
## Lorsque l'utilisateur n'a accès à aucune base de connaissances
|
||||
|
||||
Si les bases de connaissances sont activées pour un employé IA, mais que le périmètre configuré ne recoupe pas les autorisations des rôles de l'utilisateur actuel, l'employé IA répond d'abord à l'aide d'informations qui ne dépendent pas d'une base de connaissances. Il ajoute ensuite un avertissement bien visible indiquant qu'aucun contenu de base de connaissances n'a été utilisé faute d'autorisation et recommandant de contacter un administrateur.
|
||||
|
||||

|
||||
|
||||
Si l'utilisateur peut accéder à au moins une base de connaissances, mais que la question actuelle ne renvoie aucun contenu pertinent, l'avertissement relatif aux autorisations n'est pas affiché.
|
||||
|
||||
## Liens connexes
|
||||
|
||||
- [Base de connaissances](./knowledge-base/index.md) — Créer et gérer les bases de connaissances utilisées pour la récupération RAG
|
||||
- [Rôles et autorisations](../../users-permissions/acl/permissions.md) — Configurer l'accès au système, aux menus et aux données pour chaque rôle
|
||||
|
||||
@@ -1,33 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "RAG Retrieval Augmented Generation"
|
||||
description: "Pada pengaturan Karyawan AI aktifkan RAG, konfigurasi Knowledge Base Prompt, pemilihan Basis Pengetahuan, Top K, threshold Score, AI membalas berdasarkan dokumen retrieval."
|
||||
keywords: "RAG,Retrieval Augmented,Retrieval Basis Pengetahuan,Top K,NocoBase"
|
||||
title: "Retrieval-Augmented Generation (RAG)"
|
||||
description: "Aktifkan RAG untuk Karyawan AI, konfigurasi Knowledge Base, Retrieval strategy, Top K, dan Score, serta kelola akses basis pengetahuan melalui peran pengguna."
|
||||
keywords: "RAG,retrieval-augmented generation,pencarian basis pengetahuan,Retrieval strategy,izin basis pengetahuan,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# Retrieval RAG
|
||||
# Pencarian RAG
|
||||
|
||||
## Pengantar
|
||||
|
||||
Setelah mengonfigurasi Basis Pengetahuan, dapat mengaktifkan fungsi RAG di pengaturan Karyawan AI.
|
||||
Di NocoBase, **RAG (Retrieval-Augmented Generation)** memungkinkan Karyawan AI mengambil konten yang relevan dari basis pengetahuan sebelum menjawab pertanyaan.
|
||||
|
||||
Setelah RAG diaktifkan, saat Pengguna berdialog dengan Karyawan AI, Karyawan AI akan menggunakan retrieval RAG, menggunakan pesan Pengguna untuk mendapatkan dokumen dari Basis Pengetahuan dan membalas berdasarkan dokumen yang ditemukan.
|
||||
Basis pengetahuan yang dapat digunakan Karyawan AI ditentukan oleh konfigurasi `Knowledge Base` milik Karyawan AI dan izin basis pengetahuan dari peran pengguna saat ini. Hanya basis pengetahuan yang termasuk dalam kedua cakupan tersebut yang akan dicari.
|
||||
|
||||
## Mengaktifkan RAG
|
||||
## Mengonfigurasi basis pengetahuan Karyawan AI
|
||||
|
||||
Masuk ke halaman konfigurasi Plugin Karyawan AI, klik tab `AI employees`, masuk ke halaman manajemen Karyawan AI.
|
||||
Buka halaman konfigurasi `AI employees`, pilih Karyawan AI yang akan diaktifkan RAG, lalu klik `Edit`. Di panel pengeditan, buka tab `Knowledge Base` dan aktifkan `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Pilih Karyawan AI yang akan diaktifkan RAG, klik tombol `Edit`, masuk ke halaman edit Karyawan AI.
|
||||
Pengaturan yang tersedia adalah:
|
||||
|
||||
Pada tab `Knowledge base`, buka switch `Enable`.
|
||||
- `Knowledge Base` — Opsional. Jika dibiarkan kosong, Karyawan AI akan mencari di semua basis pengetahuan aktif yang dapat diakses oleh peran pengguna saat ini. Jika Anda memilih basis pengetahuan, pencarian hanya dilakukan pada basis yang dipilih dan dapat diakses oleh pengguna
|
||||
- `Retrieval strategy` — Menentukan kapan pencarian basis pengetahuan dijalankan:
|
||||
- `Retrieve on demand` — Karyawan AI mengambil konten hanya ketika menentukan bahwa pertanyaan saat ini memerlukannya. Karyawan AI baru menggunakan strategi ini secara default, dan strategi ini direkomendasikan untuk sebagian besar kasus
|
||||
- `Automatically retrieve for every question` — Pencarian dijalankan sebelum setiap pertanyaan pengguna dikirim ke Karyawan AI. Gunakan opsi ini jika setiap percakapan bergantung pada konten basis pengetahuan
|
||||
- `Knowledge Base Prompt` — Menentukan cara konten hasil pencarian diberikan kepada Karyawan AI. `{knowledgeBaseData}` adalah placeholder tetap; jangan hapus atau ubah
|
||||
- `Top K` — Jumlah maksimum hasil basis pengetahuan yang dikembalikan pada setiap pencarian. Rentangnya 1–100, dan nilai default-nya 3
|
||||
- `Score` — Skor kemiripan minimum yang harus dicapai sebuah hasil. Rentangnya 0–1, dan nilai default-nya 0,6. Nilai yang lebih tinggi memberikan konten yang lebih relevan, tetapi dapat mengurangi jumlah hasil
|
||||
|
||||
- Pada `Knowledge Base Prompt` masukkan prompt referensi Basis Pengetahuan, `{knowledgeBaseData}` adalah placeholder tetap, jangan dimodifikasi;
|
||||
- Pada `Knowledge Base` pilih Basis Pengetahuan yang sudah dikonfigurasi, rujuk: [Basis Pengetahuan](./knowledge-base/);
|
||||
- Pada kotak input `Top K` masukkan jumlah dokumen yang akan di-retrieve, default 3;
|
||||
- Pada kotak input `Score` threshold relevansi dokumen saat retrieval;
|
||||
Klik `Submit` untuk menyimpan konfigurasi.
|
||||
|
||||
Klik tombol `Submit` untuk menyimpan pengaturan Karyawan AI.
|
||||
## Mengonfigurasi izin basis pengetahuan
|
||||
|
||||

|
||||
Memilih basis pengetahuan untuk Karyawan AI tidak otomatis memberikan akses kepada semua pengguna. Buka `Users & Permissions / Roles & Permissions`, pilih peran yang diberikan kepada pengguna, lalu buka `Permissions / Knowledge bases`.
|
||||
|
||||
Pilih `Available` untuk setiap basis pengetahuan yang boleh diakses oleh peran tersebut. Untuk otomatis memberikan akses kepada peran ini atas basis pengetahuan yang dibuat di kemudian hari, pilih `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Catatan
|
||||
|
||||
Cakupan basis pengetahuan yang tersedia untuk Karyawan AI adalah irisan antara konfigurasi `Knowledge Base` dan izin peran pengguna saat ini. Basis pengetahuan yang tidak diizinkan akan otomatis dikecualikan.
|
||||
|
||||
:::
|
||||
|
||||
## Ketika pengguna tidak memiliki akses ke basis pengetahuan
|
||||
|
||||
Jika basis pengetahuan diaktifkan untuk Karyawan AI, tetapi cakupan yang dikonfigurasi tidak beririsan dengan izin peran pengguna saat ini, Karyawan AI terlebih dahulu menjawab dengan informasi yang tidak bergantung pada basis pengetahuan. Setelah itu, Karyawan AI menambahkan pemberitahuan yang jelas bahwa konten basis pengetahuan tidak digunakan karena pengguna tidak memiliki akses dan menyarankan pengguna menghubungi administrator.
|
||||
|
||||

|
||||
|
||||
Jika pengguna dapat mengakses setidaknya satu basis pengetahuan tetapi pertanyaan saat ini tidak menghasilkan konten yang relevan, pemberitahuan tidak memiliki izin tidak akan ditampilkan.
|
||||
|
||||
## Tautan terkait
|
||||
|
||||
- [Basis Pengetahuan](./knowledge-base/index.md) — Membuat dan memelihara basis pengetahuan yang digunakan untuk pencarian RAG
|
||||
- [Peran dan izin](../../users-permissions/acl/permissions.md) — Mengatur akses sistem, menu, dan data untuk setiap peran
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "RAG 検索拡張生成"
|
||||
description: "AI 従業員で RAG を有効にし、Knowledge Base、Retrieval strategy、Top K、Score を設定して、ユーザーロールに基づく知識ベースのアクセス権限を管理します。"
|
||||
keywords: "RAG,検索拡張生成,知識ベース検索,Retrieval strategy,知識ベース権限,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# RAG 検索
|
||||
|
||||
## はじめに
|
||||
|
||||
知識ベースを設定したら、AI従業員の設定でRAG機能を有効にできます。
|
||||
NocoBase の **RAG(検索拡張生成)** を使用すると、AI 従業員は質問に回答する前に、知識ベースから関連する内容を取得できます。
|
||||
|
||||
RAGを有効にすると、ユーザーがAI従業員と会話する際に、AI従業員はRAG検索を利用し、ユーザーのメッセージに基づいて知識ベースからドキュメントを取得し、取得したドキュメントに基づいて返信します。
|
||||
AI 従業員が実際に利用できる知識ベースは、AI 従業員の `Knowledge Base` 設定と、現在のユーザーが所属するロールの知識ベース権限の両方で決まります。両方の範囲に含まれる知識ベースだけが検索対象になります。
|
||||
|
||||
## RAGを有効にする
|
||||
## AI 従業員の知識ベースを設定する
|
||||
|
||||
AI従業員プラグインの設定ページに移動し、`AI employees` タブをクリックして、AI従業員管理ページに入ります。
|
||||
`AI employees` 設定ページを開き、RAG を有効にする AI 従業員を選択して `Edit` をクリックします。編集ドロワーで `Knowledge Base` タブを開き、`Enable` をオンにします。
|
||||
|
||||

|
||||

|
||||
|
||||
RAGを有効にしたいAI従業員を選択し、`Edit` ボタンをクリックして、AI従業員編集ページに入ります。
|
||||
各設定項目の内容は次のとおりです。
|
||||
|
||||
`Knowledge base` タブで、`Enable` スイッチをオンにします。
|
||||
- `Knowledge Base` — 任意項目です。空のままにすると、現在のユーザーのロールがアクセスできる、有効なすべての知識ベースから検索します。知識ベースを選択した場合は、選択済みかつアクセス権限のある知識ベースだけを検索します
|
||||
- `Retrieval strategy` — 知識ベースを検索するタイミングを設定します:
|
||||
- `Retrieve on demand` — 現在の質問に知識ベースの内容が必要だと AI 従業員が判断した場合だけ検索します。新しい AI 従業員ではこの方式がデフォルトであり、通常はこちらを推奨します
|
||||
- `Automatically retrieve for every question` — ユーザーの各質問を AI 従業員に送信する前に検索します。すべての対話で知識ベースの内容が必要な場合に使用します
|
||||
- `Knowledge Base Prompt` — 取得した内容を AI 従業員に渡す方法を設定します。`{knowledgeBaseData}` は固定のプレースホルダーなので、削除または変更しないでください
|
||||
- `Top K` — 1 回の検索で返す知識ベース結果の最大数です。1~100 の範囲で設定でき、デフォルトは 3 です
|
||||
- `Score` — 検索結果に必要な最小類似度です。0~1 の範囲で設定でき、デフォルトは 0.6 です。値を高くすると結果の関連性は高くなりますが、返される件数が少なくなる場合があります
|
||||
|
||||
- `Knowledge Base Prompt` に、知識ベースを参照するためのプロンプトを入力します。`{knowledgeBaseData}` は固定のプレースホルダーですので、変更しないでください。
|
||||
- `Knowledge Base` で、設定済みの知識ベースを選択します。参照:[知識ベース](./knowledge-base/)
|
||||
- `Top K` 入力ボックスに、検索するドキュメントの数を入力します。デフォルトは3です。
|
||||
- `Score` 入力ボックスに、検索時のドキュメント関連性しきい値を入力します。
|
||||
設定が完了したら、`Submit` をクリックして保存します。
|
||||
|
||||
`Submit` ボタンをクリックして、AI従業員の設定を保存します。
|
||||
## 知識ベースの権限を設定する
|
||||
|
||||

|
||||
AI 従業員で知識ベースを選択しても、すべてのユーザーにアクセス権限が付与されるわけではありません。`Users & Permissions / Roles & Permissions` を開いてユーザーが所属するロールを選択し、`Permissions / Knowledge bases` を開きます。
|
||||
|
||||
ロールにアクセスを許可する知識ベースの `Available` を選択します。今後作成される知識ベースへのアクセスも自動的に許可する場合は、`New knowledge bases are allowed by default` を選択します。
|
||||
|
||||

|
||||
|
||||
:::warning 注意
|
||||
|
||||
AI 従業員が検索できる知識ベースの範囲は、`Knowledge Base` 設定と現在のユーザーのロール権限の共通部分です。権限のない知識ベースは自動的に除外されます。
|
||||
|
||||
:::
|
||||
|
||||
## 知識ベースへのアクセス権限がない場合
|
||||
|
||||
AI 従業員で知識ベースが有効でも、設定された範囲と現在のユーザーのロール権限に共通する知識ベースがない場合、AI 従業員はまず知識ベースに依存しない情報で回答します。その後、知識ベースへのアクセス権限がないため知識ベースの内容を使用していないことと、必要な場合は管理者に権限を申請するよう促す目立つ通知を回答の末尾に表示します。
|
||||
|
||||

|
||||
|
||||
アクセス可能な知識ベースが 1 つ以上あり、現在の質問に関連する内容が見つからなかっただけの場合は、権限がないことを示す通知は表示されません。
|
||||
|
||||
## 関連リンク
|
||||
|
||||
- [知識ベース](./knowledge-base/index.md) — RAG 検索で使用する知識ベースの作成と管理
|
||||
- [ロールと権限](../../users-permissions/acl/permissions.md) — ロールのシステム、メニュー、データアクセス権限の設定
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "Geração aumentada por recuperação (RAG)"
|
||||
description: "Ative o RAG para funcionários de IA, configure Knowledge Base, Retrieval strategy, Top K e Score e controle o acesso às bases de conhecimento por meio dos papéis dos usuários."
|
||||
keywords: "RAG,geração aumentada por recuperação,recuperação de base de conhecimento,Retrieval strategy,permissões de base de conhecimento,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# Busca RAG
|
||||
|
||||
## Introdução
|
||||
|
||||
Depois de configurar a base de conhecimento, você pode habilitar o recurso RAG nas configurações do funcionário de IA.
|
||||
No NocoBase, o **RAG (geração aumentada por recuperação)** permite que um funcionário de IA recupere conteúdo relevante das bases de conhecimento antes de responder a uma pergunta.
|
||||
|
||||
Com o RAG habilitado, quando um usuário conversar com um funcionário de IA, o funcionário de IA usará a busca RAG para obter documentos da base de conhecimento com base na mensagem do usuário e responderá com base nos documentos recuperados.
|
||||
As bases de conhecimento que o funcionário de IA pode usar são determinadas tanto pela configuração de `Knowledge Base` do funcionário quanto pelas permissões de base de conhecimento dos papéis do usuário atual. Somente as bases incluídas nos dois escopos participam da busca.
|
||||
|
||||
## Habilitar RAG
|
||||
## Configurar as bases de conhecimento de um funcionário de IA
|
||||
|
||||
Acesse a página de configuração do **plugin** de funcionário de IA, clique na aba `AI employees` para entrar na página de gerenciamento de funcionários de IA.
|
||||
Acesse a página de configuração `AI employees`, selecione o funcionário de IA para o qual deseja ativar o RAG e clique em `Edit`. No painel de edição, abra a aba `Knowledge Base` e ative `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Selecione o funcionário de IA para o qual você deseja habilitar o RAG, clique no botão `Edit` para acessar a página de edição do funcionário de IA.
|
||||
As configurações disponíveis são:
|
||||
|
||||
Na aba `Knowledge base`, ative o interruptor `Enable`.
|
||||
- `Knowledge Base` — Opcional. Se ficar em branco, o funcionário de IA pesquisará em todas as bases de conhecimento ativadas que os papéis do usuário atual podem acessar. Se você selecionar bases de conhecimento, a pesquisa usará somente as bases selecionadas para as quais o usuário tem permissão
|
||||
- `Retrieval strategy` — Controla quando a recuperação da base de conhecimento é executada:
|
||||
- `Retrieve on demand` — O funcionário de IA recupera conteúdo apenas quando determina que a pergunta atual precisa dele. Novos funcionários de IA usam essa estratégia por padrão, e ela é recomendada para a maioria dos casos
|
||||
- `Automatically retrieve for every question` — A recuperação é executada antes de cada pergunta do usuário ser enviada ao funcionário de IA. Use esta opção quando toda interação depender do conteúdo da base de conhecimento
|
||||
- `Knowledge Base Prompt` — Define como o conteúdo recuperado é fornecido ao funcionário de IA. `{knowledgeBaseData}` é um placeholder fixo; não o remova nem modifique
|
||||
- `Top K` — O número máximo de resultados retornados em cada recuperação. O intervalo é de 1 a 100, e o padrão é 3
|
||||
- `Score` — A pontuação mínima de similaridade exigida para um resultado. O intervalo é de 0 a 1, e o padrão é 0,6. Um valor mais alto retorna conteúdo mais relevante, mas pode reduzir a quantidade de resultados
|
||||
|
||||
- Em `Knowledge Base Prompt`, insira o prompt para referenciar a base de conhecimento. `{knowledgeBaseData}` é um placeholder fixo e não deve ser modificado;
|
||||
- Em `Knowledge Base`, selecione a base de conhecimento configurada. Veja: [Base de Conhecimento](./knowledge-base/);
|
||||
- No campo `Top K`, insira o número de documentos a serem recuperados. O padrão é 3;
|
||||
- No campo `Score`, insira o limite de relevância do documento para a busca;
|
||||
Clique em `Submit` para salvar a configuração.
|
||||
|
||||
Clique no botão `Submit` para salvar as configurações do funcionário de IA.
|
||||
## Configurar as permissões das bases de conhecimento
|
||||
|
||||

|
||||
Selecionar bases de conhecimento para um funcionário de IA não concede acesso a todos os usuários. Acesse `Users & Permissions / Roles & Permissions`, selecione o papel atribuído ao usuário e abra `Permissions / Knowledge bases`.
|
||||
|
||||
Selecione `Available` para cada base de conhecimento que o papel deve poder acessar. Para conceder automaticamente a esse papel acesso às bases de conhecimento criadas no futuro, selecione `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Observação
|
||||
|
||||
O escopo de bases de conhecimento disponível para um funcionário de IA é a interseção entre sua configuração de `Knowledge Base` e as permissões dos papéis do usuário atual. Bases de conhecimento não autorizadas são excluídas automaticamente.
|
||||
|
||||
:::
|
||||
|
||||
## Quando o usuário não tem acesso a bases de conhecimento
|
||||
|
||||
Se as bases de conhecimento estiverem ativadas para um funcionário de IA, mas o escopo configurado não tiver sobreposição com as permissões dos papéis do usuário atual, o funcionário de IA responderá primeiro com informações que não dependem de uma base de conhecimento. Em seguida, adicionará um aviso destacado informando que nenhum conteúdo da base de conhecimento foi usado porque o usuário não tem acesso e recomendando que ele entre em contato com um administrador.
|
||||
|
||||

|
||||
|
||||
Se o usuário puder acessar pelo menos uma base de conhecimento, mas a pergunta atual não retornar conteúdo relevante, o aviso de falta de permissão não será exibido.
|
||||
|
||||
## Links relacionados
|
||||
|
||||
- [Base de conhecimento](./knowledge-base/index.md) — Criar e manter bases de conhecimento usadas pela recuperação RAG
|
||||
- [Papéis e permissões](../../users-permissions/acl/permissions.md) — Configurar o acesso ao sistema, aos menus e aos dados para cada papel
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
# Генерация с расширенными возможностями поиска
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "Генерация с дополнением извлечёнными данными (RAG)"
|
||||
description: "Включите RAG для ИИ-сотрудников, настройте Knowledge Base, Retrieval strategy, Top K и Score и управляйте доступом к базам знаний с помощью ролей пользователей."
|
||||
keywords: "RAG,генерация с дополнением извлечёнными данными,поиск по базе знаний,Retrieval strategy,права на базы знаний,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# RAG-поиск
|
||||
|
||||
## Введение
|
||||
|
||||
После настройки базы знаний вы можете включить функцию Генерации с расширенными возможностями поиска (RAG) в настройках ИИ-сотрудника.
|
||||
В NocoBase **RAG (генерация с дополнением извлечёнными данными)** позволяет ИИ-сотруднику получать релевантные материалы из баз знаний перед ответом на вопрос.
|
||||
|
||||
При включенной Генерации с расширенными возможностями поиска (RAG), когда пользователь общается с ИИ-сотрудником, ИИ-сотрудник будет использовать извлечение RAG, чтобы получать документы из базы знаний на основе сообщения пользователя, и отвечать на основе извлеченных документов.
|
||||
Базы знаний, которые ИИ-сотрудник может использовать, определяются одновременно его настройкой `Knowledge Base` и правами ролей текущего пользователя на базы знаний. Поиск выполняется только в базах, входящих в оба набора.
|
||||
|
||||
## Включить Генерацию с расширенными возможностями поиска (RAG)
|
||||
## Настройка баз знаний ИИ-сотрудника
|
||||
|
||||
Перейдите на страницу настроек плагина ИИ-сотрудника, нажмите вкладку `ИИ-сотрудники`, чтобы открыть страницу управления ИИ-сотрудниками.
|
||||
Откройте страницу настроек `AI employees`, выберите ИИ-сотрудника, для которого нужно включить RAG, и нажмите `Edit`. В панели редактирования откройте вкладку `Knowledge Base` и включите `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Выберите ИИ-сотрудника, для которого вы хотите включить Генерацию с расширенными возможностями поиска (RAG), нажмите кнопку `Редактировать`, чтобы перейти на страницу редактирования ИИ-сотрудника.
|
||||
Доступны следующие настройки:
|
||||
|
||||
На вкладке `База знаний` включите переключатель `Включить`.
|
||||
- `Knowledge Base` — Необязательное поле. Если оставить его пустым, ИИ-сотрудник будет искать во всех включённых базах знаний, доступных ролям текущего пользователя. Если выбрать базы знаний, поиск будет выполняться только в выбранных базах, к которым у пользователя есть доступ
|
||||
- `Retrieval strategy` — Определяет, когда выполняется поиск по базам знаний:
|
||||
- `Retrieve on demand` — ИИ-сотрудник извлекает материалы, только когда определяет, что они нужны для текущего вопроса. Эта стратегия используется по умолчанию для новых ИИ-сотрудников и рекомендуется для большинства случаев
|
||||
- `Automatically retrieve for every question` — Поиск выполняется перед отправкой каждого вопроса пользователя ИИ-сотруднику. Используйте эту стратегию, если каждое сообщение требует материалов из базы знаний
|
||||
- `Knowledge Base Prompt` — Определяет, как извлечённые материалы передаются ИИ-сотруднику. `{knowledgeBaseData}` — фиксированный плейсхолдер; не удаляйте и не изменяйте его
|
||||
- `Top K` — Максимальное количество результатов для каждого поиска. Допустимый диапазон — от 1 до 100, значение по умолчанию — 3
|
||||
- `Score` — Минимальная оценка сходства, необходимая для включения результата. Допустимый диапазон — от 0 до 1, значение по умолчанию — 0,6. Более высокое значение повышает релевантность материалов, но может уменьшить количество результатов
|
||||
|
||||
- В поле `Knowledge Base Prompt` введите подсказку для ссылки на базу знаний. `{knowledgeBaseData}` является фиксированным плейсхолдером и не должен изменяться.
|
||||
- В разделе `Knowledge Base` выберите настроенную базу знаний. См.: [База знаний](./knowledge-base/).
|
||||
- В поле `Top K` укажите количество документов для извлечения (по умолчанию — 3).
|
||||
- В поле `Score` введите пороговое значение релевантности документов для поиска.
|
||||
Нажмите `Submit`, чтобы сохранить настройки.
|
||||
|
||||
Нажмите кнопку `Отправить`, чтобы сохранить настройки ИИ-сотрудника.
|
||||
## Настройка прав на базы знаний
|
||||
|
||||

|
||||
Выбор баз знаний для ИИ-сотрудника не предоставляет к ним доступ всем пользователям. Откройте `Users & Permissions / Roles & Permissions`, выберите роль, назначенную пользователю, а затем откройте `Permissions / Knowledge bases`.
|
||||
|
||||
Выберите `Available` для каждой базы знаний, к которой роль должна иметь доступ. Чтобы автоматически предоставлять этой роли доступ к базам знаний, созданным в будущем, выберите `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Примечание
|
||||
|
||||
Доступный ИИ-сотруднику набор баз знаний представляет собой пересечение его настройки `Knowledge Base` и прав ролей текущего пользователя. Базы знаний без соответствующего разрешения автоматически исключаются.
|
||||
|
||||
:::
|
||||
|
||||
## Если у пользователя нет доступа к базам знаний
|
||||
|
||||
Если базы знаний включены для ИИ-сотрудника, но настроенный набор не пересекается с правами ролей текущего пользователя, ИИ-сотрудник сначала отвечает, используя информацию, не зависящую от базы знаний. Затем он добавляет заметное уведомление о том, что материалы из баз знаний не использовались из-за отсутствия доступа, и рекомендует обратиться к администратору.
|
||||
|
||||

|
||||
|
||||
Если пользователю доступна хотя бы одна база знаний, но для текущего вопроса не найдено релевантных материалов, уведомление об отсутствии прав не отображается.
|
||||
|
||||
## Связанные ссылки
|
||||
|
||||
- [База знаний](./knowledge-base/index.md) — Создание и сопровождение баз знаний для RAG-поиска
|
||||
- [Роли и права](../../users-permissions/acl/permissions.md) — Настройка доступа ролей к системе, меню и данным
|
||||
|
||||
@@ -1,33 +1,59 @@
|
||||
---
|
||||
pkg: "@nocobase/plugin-ai-knowledge-base"
|
||||
title: "RAG - Tăng cường truy xuất tạo sinh"
|
||||
description: "Kích hoạt RAG trong cài đặt Nhân viên AI, cấu hình Knowledge Base Prompt, chọn Knowledge Base, Top K, ngưỡng Score, AI phản hồi dựa trên tài liệu được truy xuất."
|
||||
keywords: "RAG,Tăng cường truy xuất,Truy xuất Knowledge Base,Top K,NocoBase"
|
||||
title: "Tạo sinh tăng cường truy xuất (RAG)"
|
||||
description: "Kích hoạt RAG cho Nhân viên AI, cấu hình Knowledge Base, Retrieval strategy, Top K và Score, đồng thời kiểm soát quyền truy cập cơ sở tri thức theo vai trò người dùng."
|
||||
keywords: "RAG,tạo sinh tăng cường truy xuất,truy xuất cơ sở tri thức,Retrieval strategy,quyền cơ sở tri thức,Top K,NocoBase"
|
||||
---
|
||||
|
||||
# Truy xuất RAG
|
||||
|
||||
## Giới thiệu
|
||||
|
||||
Sau khi cấu hình tốt Knowledge Base, bạn có thể kích hoạt tính năng RAG trong cài đặt Nhân viên AI.
|
||||
Trong NocoBase, **RAG (tạo sinh tăng cường truy xuất)** cho phép Nhân viên AI lấy nội dung liên quan từ cơ sở tri thức trước khi trả lời câu hỏi.
|
||||
|
||||
Sau khi kích hoạt RAG, khi người dùng trò chuyện với Nhân viên AI, Nhân viên AI sẽ sử dụng truy xuất RAG, dùng tin nhắn của người dùng để lấy tài liệu từ Knowledge Base và phản hồi dựa trên tài liệu được truy xuất.
|
||||
Các cơ sở tri thức mà Nhân viên AI thực sự có thể sử dụng được xác định bởi cả cấu hình `Knowledge Base` của Nhân viên AI và quyền truy cập cơ sở tri thức của các vai trò thuộc người dùng hiện tại. Chỉ các cơ sở tri thức nằm trong cả hai phạm vi mới được tìm kiếm.
|
||||
|
||||
## Kích hoạt RAG
|
||||
## Cấu hình cơ sở tri thức cho Nhân viên AI
|
||||
|
||||
Vào trang cấu hình Plugin Nhân viên AI, nhấp vào tab `AI employees` để vào trang quản lý Nhân viên AI.
|
||||
Mở trang cấu hình `AI employees`, chọn Nhân viên AI cần kích hoạt RAG rồi nhấp `Edit`. Trong bảng chỉnh sửa, mở tab `Knowledge Base` và bật `Enable`.
|
||||
|
||||

|
||||

|
||||
|
||||
Chọn Nhân viên AI cần kích hoạt RAG, nhấp nút `Edit` để vào trang chỉnh sửa Nhân viên AI.
|
||||
Các tùy chọn gồm có:
|
||||
|
||||
Trong tab `Knowledge base`, bật công tắc `Enable`.
|
||||
- `Knowledge Base` — Không bắt buộc. Nếu để trống, Nhân viên AI sẽ tìm kiếm trong tất cả cơ sở tri thức đã bật mà các vai trò của người dùng hiện tại có thể truy cập. Nếu chọn cơ sở tri thức, hệ thống chỉ tìm kiếm trong các cơ sở đã chọn mà người dùng có quyền truy cập
|
||||
- `Retrieval strategy` — Xác định thời điểm chạy truy xuất cơ sở tri thức:
|
||||
- `Retrieve on demand` — Nhân viên AI chỉ truy xuất nội dung khi xác định câu hỏi hiện tại cần đến nội dung đó. Nhân viên AI mới sử dụng chiến lược này theo mặc định và đây là lựa chọn được đề xuất cho hầu hết trường hợp
|
||||
- `Automatically retrieve for every question` — Truy xuất được chạy trước khi mỗi câu hỏi của người dùng được gửi đến Nhân viên AI. Sử dụng tùy chọn này khi mọi lượt trò chuyện đều phụ thuộc vào nội dung cơ sở tri thức
|
||||
- `Knowledge Base Prompt` — Xác định cách cung cấp nội dung truy xuất cho Nhân viên AI. `{knowledgeBaseData}` là placeholder cố định; không xóa hoặc sửa đổi
|
||||
- `Top K` — Số lượng kết quả cơ sở tri thức tối đa được trả về trong mỗi lần truy xuất. Phạm vi là 1–100 và giá trị mặc định là 3
|
||||
- `Score` — Điểm tương đồng tối thiểu mà một kết quả phải đạt. Phạm vi là 0–1 và giá trị mặc định là 0,6. Giá trị cao hơn trả về nội dung liên quan hơn nhưng có thể làm giảm số lượng kết quả
|
||||
|
||||
- Trong `Knowledge Base Prompt` nhập câu Prompt trích dẫn Knowledge Base, `{knowledgeBaseData}` là placeholder cố định, không sửa đổi;
|
||||
- Trong `Knowledge Base` chọn Knowledge Base đã cấu hình, tham khảo: [Knowledge Base](./knowledge-base/);
|
||||
- Trong ô nhập `Top K` nhập số lượng tài liệu cần truy xuất, mặc định là 3;
|
||||
- Trong ô nhập `Score` ngưỡng độ liên quan tài liệu khi truy xuất;
|
||||
Nhấp `Submit` để lưu cấu hình.
|
||||
|
||||
Nhấp nút `Submit` để lưu cài đặt Nhân viên AI.
|
||||
## Cấu hình quyền truy cập cơ sở tri thức
|
||||
|
||||

|
||||
Việc chọn cơ sở tri thức cho Nhân viên AI không tự động cấp quyền truy cập cho mọi người dùng. Mở `Users & Permissions / Roles & Permissions`, chọn vai trò được gán cho người dùng rồi mở `Permissions / Knowledge bases`.
|
||||
|
||||
Chọn `Available` cho từng cơ sở tri thức mà vai trò được phép truy cập. Để tự động cấp cho vai trò này quyền truy cập các cơ sở tri thức được tạo sau này, chọn `New knowledge bases are allowed by default`.
|
||||
|
||||

|
||||
|
||||
:::warning Lưu ý
|
||||
|
||||
Phạm vi cơ sở tri thức mà Nhân viên AI có thể sử dụng là phần giao giữa cấu hình `Knowledge Base` và quyền của các vai trò thuộc người dùng hiện tại. Các cơ sở tri thức không được cấp quyền sẽ tự động bị loại trừ.
|
||||
|
||||
:::
|
||||
|
||||
## Khi người dùng không có quyền truy cập cơ sở tri thức
|
||||
|
||||
Nếu Nhân viên AI đã bật cơ sở tri thức nhưng phạm vi được cấu hình không giao với quyền của các vai trò thuộc người dùng hiện tại, Nhân viên AI sẽ trả lời trước bằng thông tin không phụ thuộc vào cơ sở tri thức. Sau đó, Nhân viên AI thêm một thông báo nổi bật cho biết nội dung cơ sở tri thức không được sử dụng vì người dùng không có quyền truy cập và đề nghị liên hệ quản trị viên.
|
||||
|
||||

|
||||
|
||||
Nếu người dùng có thể truy cập ít nhất một cơ sở tri thức nhưng câu hỏi hiện tại không trả về nội dung liên quan, thông báo không có quyền sẽ không xuất hiện.
|
||||
|
||||
## Liên kết liên quan
|
||||
|
||||
- [Cơ sở tri thức](./knowledge-base/index.md) — Tạo và duy trì các cơ sở tri thức dùng cho truy xuất RAG
|
||||
- [Vai trò và quyền](../../users-permissions/acl/permissions.md) — Cấu hình quyền truy cập hệ thống, menu và dữ liệu cho từng vai trò
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import { defineTools } from '@nocobase/ai';
|
||||
import { z } from 'zod';
|
||||
import { getAIPlugin } from './sub-agents/shared';
|
||||
import { getCurrentRoleNames } from '../../server/ai-employees/ai-knowledge-base';
|
||||
// @ts-ignore
|
||||
import pkg from '../../../package.json';
|
||||
|
||||
@@ -61,6 +62,7 @@ export default defineTools({
|
||||
const content = await plugin.knowledgeBaseManager.retrievePrompt({
|
||||
username,
|
||||
query,
|
||||
roleNames: getCurrentRoleNames(ctx.state),
|
||||
});
|
||||
return {
|
||||
status: 'success',
|
||||
|
||||
@@ -12,12 +12,14 @@ import {
|
||||
EMPLOYEE_PROMPT_VARIABLE_NAMESPACES,
|
||||
buildEmployeeSubmitValues,
|
||||
createAIEmployee,
|
||||
createInitialEmployeeValues,
|
||||
deleteAIEmployee,
|
||||
isAIEmployeeUsernameConflictError,
|
||||
isKnowledgeBaseEnabled,
|
||||
listAIEmployees,
|
||||
listKnowledgeBases,
|
||||
moveAIEmployee,
|
||||
normalizeKnowledgeBaseSettingsForForm,
|
||||
normalizeSkillSettings,
|
||||
updateAIEmployee,
|
||||
updateAIEmployeeEnabled,
|
||||
@@ -29,6 +31,41 @@ describe('EmployeesPage request helpers', () => {
|
||||
expect(EMPLOYEE_PROMPT_VARIABLE_NAMESPACES).toEqual(['user', 'roleName', 'locale', 'now', 'timestamp']);
|
||||
});
|
||||
|
||||
it('defaults new employee knowledge-base retrieval to onDemand and displays legacy records as always', () => {
|
||||
const initialValues = createInitialEmployeeValues(((key: string) => key) as never);
|
||||
expect(initialValues.knowledgeBase?.retrievalStrategy).toBe('onDemand');
|
||||
expect(normalizeKnowledgeBaseSettingsForForm({ knowledgeBaseKeys: ['handbook'] }, 'always')).toEqual({
|
||||
knowledgeBaseKeys: ['handbook'],
|
||||
retrievalStrategy: 'always',
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps retrieval strategy and empty knowledge-base selection when submitting', () => {
|
||||
const values = buildEmployeeSubmitValues(
|
||||
{ username: 'atlas', nickname: 'Atlas' },
|
||||
{
|
||||
username: 'atlas',
|
||||
nickname: 'Atlas',
|
||||
knowledgeBase: {
|
||||
retrievalStrategy: 'onDemand',
|
||||
knowledgeBaseKeys: [],
|
||||
topK: 3,
|
||||
score: '0.6',
|
||||
},
|
||||
knowledgeBasePrompt: 'Use retrieved content.',
|
||||
},
|
||||
);
|
||||
expect(values).toMatchObject({
|
||||
knowledgeBase: {
|
||||
retrievalStrategy: 'onDemand',
|
||||
knowledgeBaseKeys: [],
|
||||
topK: 3,
|
||||
score: '0.6',
|
||||
},
|
||||
knowledgeBasePrompt: 'Use retrieved content.',
|
||||
});
|
||||
});
|
||||
|
||||
it('lists employees with the selected category filter', async () => {
|
||||
const list = vi.fn().mockResolvedValue({
|
||||
data: {
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { Form } from 'antd';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { KnowledgeBaseSettings } from '../pages/EmployeesPage';
|
||||
|
||||
vi.mock('../locale', () => ({
|
||||
useT: () => (key: string) => key,
|
||||
}));
|
||||
|
||||
const apiClient = {
|
||||
resource: () => ({
|
||||
list: vi.fn().mockResolvedValue({ data: { data: [{ key: 'handbook', name: 'Handbook' }] } }),
|
||||
}),
|
||||
};
|
||||
|
||||
describe('AI employee knowledge-base settings', () => {
|
||||
it('renders both retrieval strategies and the permission-aware empty-selection guidance', async () => {
|
||||
const onFinish = vi.fn();
|
||||
render(
|
||||
<Form
|
||||
initialValues={{
|
||||
enableKnowledgeBase: true,
|
||||
knowledgeBase: { retrievalStrategy: 'onDemand', knowledgeBaseKeys: [], topK: 3, score: '0.6' },
|
||||
knowledgeBasePrompt: 'Use retrieved content.',
|
||||
}}
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<KnowledgeBaseSettings apiClient={apiClient as never} />
|
||||
<button type="submit">Submit</button>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole('radio', { name: /Automatically retrieve for every question/ })).toBeTruthy();
|
||||
expect(screen.getByRole('radio', { name: /Retrieve on demand/ })).toBeChecked();
|
||||
expect(
|
||||
screen.getByText('Retrieve before every user question, then answer with the retrieved content.'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
screen.getByText('The AI employee retrieves knowledge-base content only when it determines that it is needed.'),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Actual retrieval is limited to knowledge bases accessible to the roles of the user using this AI employee. Inaccessible knowledge bases are excluded.',
|
||||
),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByText('Leave blank to retrieve from all knowledge bases')).toBeTruthy();
|
||||
expect(screen.getByText('Maximum number of knowledge-base entries returned for each retrieval.')).toBeTruthy();
|
||||
expect(
|
||||
screen.getByText('Minimum similarity score for knowledge-base content to be included in retrieval results.'),
|
||||
).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Submit' }));
|
||||
await waitFor(() =>
|
||||
expect(onFinish).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
knowledgeBase: expect.objectContaining({ knowledgeBaseKeys: [], retrievalStrategy: 'onDemand' }),
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -99,6 +99,7 @@ type SettingsAIEmployee = ChatAIEmployee & {
|
||||
topK?: number;
|
||||
score?: string | number;
|
||||
knowledgeBaseKeys?: string[];
|
||||
retrievalStrategy?: 'always' | 'onDemand';
|
||||
};
|
||||
missingKnowledgeBaseKeys?: string[];
|
||||
};
|
||||
@@ -286,7 +287,15 @@ export async function listKnowledgeBases(apiClient: APIClientLike): Promise<Know
|
||||
return Array.isArray(data) ? data.filter(isKnowledgeBaseOption) : [];
|
||||
}
|
||||
|
||||
const createInitialEmployeeValues = (t: ReturnType<typeof useT>): EmployeeFormValues => ({
|
||||
export const normalizeKnowledgeBaseSettingsForForm = (
|
||||
knowledgeBase: SettingsAIEmployee['knowledgeBase'] | undefined,
|
||||
defaultStrategy: 'always' | 'onDemand',
|
||||
): NonNullable<SettingsAIEmployee['knowledgeBase']> => ({
|
||||
...(knowledgeBase ?? {}),
|
||||
retrievalStrategy: knowledgeBase?.retrievalStrategy === 'onDemand' ? 'onDemand' : defaultStrategy,
|
||||
});
|
||||
|
||||
export const createInitialEmployeeValues = (t: ReturnType<typeof useT>): EmployeeFormValues => ({
|
||||
username: randomId(),
|
||||
enabled: true,
|
||||
enableKnowledgeBase: false,
|
||||
@@ -294,6 +303,7 @@ const createInitialEmployeeValues = (t: ReturnType<typeof useT>): EmployeeFormVa
|
||||
knowledgeBaseKeys: [],
|
||||
topK: 3,
|
||||
score: '0.6',
|
||||
retrievalStrategy: 'onDemand',
|
||||
},
|
||||
knowledgeBasePrompt: t('knowledge Base Prompt default'),
|
||||
avatar: defaultAvatar,
|
||||
@@ -510,6 +520,12 @@ export const buildEmployeeSubmitValues = (
|
||||
if (isRecord(allValues.modelSettings)) {
|
||||
submitValues.modelSettings = normalizeModelSettings(allValues.modelSettings);
|
||||
}
|
||||
if (allValues.knowledgeBase) {
|
||||
submitValues.knowledgeBase = allValues.knowledgeBase;
|
||||
}
|
||||
if (typeof allValues.knowledgeBasePrompt === 'string') {
|
||||
submitValues.knowledgeBasePrompt = allValues.knowledgeBasePrompt;
|
||||
}
|
||||
return submitValues;
|
||||
};
|
||||
|
||||
@@ -1035,7 +1051,7 @@ const ToolSettings: React.FC<{ builtIn?: boolean }> = observer(({ builtIn }) =>
|
||||
);
|
||||
});
|
||||
|
||||
const KnowledgeBaseSettings: React.FC<{ apiClient: APIClientLike }> = ({ apiClient }) => {
|
||||
export const KnowledgeBaseSettings: React.FC<{ apiClient: APIClientLike }> = ({ apiClient }) => {
|
||||
const t = useT();
|
||||
const form = Form.useFormInstance<EmployeeFormValues>();
|
||||
const enableKnowledgeBase = Form.useWatch('enableKnowledgeBase', form);
|
||||
@@ -1077,6 +1093,45 @@ const KnowledgeBaseSettings: React.FC<{ apiClient: APIClientLike }> = ({ apiClie
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={['knowledgeBase', 'knowledgeBaseKeys']}
|
||||
label={formLabel(t('Knowledge Base'))}
|
||||
extra={t(
|
||||
'Actual retrieval is limited to knowledge bases accessible to the roles of the user using this AI employee. Inaccessible knowledge bases are excluded.',
|
||||
)}
|
||||
preserve
|
||||
>
|
||||
<Select
|
||||
disabled={!enableKnowledgeBase}
|
||||
fieldNames={{ label: 'name', value: 'key' }}
|
||||
loading={loading}
|
||||
mode="multiple"
|
||||
placeholder={t('Leave blank to retrieve from all knowledge bases')}
|
||||
options={options}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name={['knowledgeBase', 'retrievalStrategy']} label={formLabel(t('Retrieval strategy'))} preserve>
|
||||
<Radio.Group disabled={!enableKnowledgeBase} aria-label={t('Retrieval strategy')}>
|
||||
<Space direction="vertical">
|
||||
<Radio value="onDemand">
|
||||
<Space direction="vertical" size={0}>
|
||||
<span>{t('Retrieve on demand')}</span>
|
||||
<Typography.Text type="secondary">
|
||||
{t('The AI employee retrieves knowledge-base content only when it determines that it is needed.')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</Radio>
|
||||
<Radio value="always">
|
||||
<Space direction="vertical" size={0}>
|
||||
<span>{t('Automatically retrieve for every question')}</span>
|
||||
<Typography.Text type="secondary">
|
||||
{t('Retrieve before every user question, then answer with the retrieved content.')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="knowledgeBasePrompt"
|
||||
label={formLabel(t('Knowledge Base Prompt'))}
|
||||
@@ -1086,23 +1141,21 @@ const KnowledgeBaseSettings: React.FC<{ apiClient: APIClientLike }> = ({ apiClie
|
||||
<Input.TextArea disabled={!enableKnowledgeBase} autoSize={{ minRows: 5 }} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={['knowledgeBase', 'knowledgeBaseKeys']}
|
||||
label={formLabel(t('Knowledge Base'))}
|
||||
rules={[{ required: !!enableKnowledgeBase }]}
|
||||
name={['knowledgeBase', 'topK']}
|
||||
label={formLabel(t('Top K'))}
|
||||
extra={t('Maximum number of knowledge-base entries returned for each retrieval.')}
|
||||
rules={[{ required: true }]}
|
||||
preserve
|
||||
>
|
||||
<Select
|
||||
disabled={!enableKnowledgeBase}
|
||||
fieldNames={{ label: 'name', value: 'key' }}
|
||||
loading={loading}
|
||||
mode="multiple"
|
||||
options={options}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name={['knowledgeBase', 'topK']} label={formLabel(t('Top K'))} rules={[{ required: true }]} preserve>
|
||||
<InputNumber disabled={!enableKnowledgeBase} min={1} max={100} />
|
||||
</Form.Item>
|
||||
<Form.Item name={['knowledgeBase', 'score']} label={formLabel(t('Score'))} rules={[{ required: true }]} preserve>
|
||||
<Form.Item
|
||||
name={['knowledgeBase', 'score']}
|
||||
label={formLabel(t('Score'))}
|
||||
extra={t('Minimum similarity score for knowledge-base content to be included in retrieval results.')}
|
||||
rules={[{ required: true }]}
|
||||
preserve
|
||||
>
|
||||
<InputNumber disabled={!enableKnowledgeBase} min={0} max={1} step={0.1} />
|
||||
</Form.Item>
|
||||
</>
|
||||
@@ -1471,6 +1524,7 @@ const AIEmployeeDrawerContent: React.FC<{
|
||||
initialValuesRef.current = editingRecord
|
||||
? {
|
||||
...editingRecord,
|
||||
knowledgeBase: normalizeKnowledgeBaseSettingsForForm(editingRecord.knowledgeBase, 'always'),
|
||||
_aboutMode: editingRecord.builtIn ? (editingRecord.about ? 'custom' : 'system') : undefined,
|
||||
}
|
||||
: createInitialEmployeeValues(t);
|
||||
|
||||
@@ -83,6 +83,7 @@ export default {
|
||||
* topK: number;
|
||||
* score: string;
|
||||
* knowledgeBaseKeys: string[];
|
||||
* retrievalStrategy: 'always' | 'onDemand';
|
||||
* }
|
||||
*/
|
||||
{
|
||||
@@ -135,6 +136,7 @@ export type AIEmployee = {
|
||||
topK: number;
|
||||
score: string;
|
||||
knowledgeBaseKeys: string[];
|
||||
retrievalStrategy?: 'always' | 'onDemand';
|
||||
};
|
||||
enableKnowledgeBase: boolean;
|
||||
enabled: boolean;
|
||||
|
||||
@@ -171,6 +171,15 @@
|
||||
"Knowledge Base Prompt": "Knowledge Base Prompt",
|
||||
"Knowledge Base Prompt placeholder": "Knowledge Base Prompt placeholder",
|
||||
"KnowledgeBase": "Knowledge Base",
|
||||
"Retrieval strategy": "Retrieval strategy",
|
||||
"Automatically retrieve for every question": "Automatically retrieve for every question",
|
||||
"Retrieve before every user question, then answer with the retrieved content.": "Retrieve before every user question, then answer with the retrieved content.",
|
||||
"Retrieve on demand": "Retrieve on demand",
|
||||
"The AI employee retrieves knowledge-base content only when it determines that it is needed.": "The AI employee retrieves knowledge-base content only when it determines that it is needed.",
|
||||
"Leave blank to retrieve from all knowledge bases": "Leave blank to retrieve from all knowledge bases",
|
||||
"Actual retrieval is limited to knowledge bases accessible to the roles of the user using this AI employee. Inaccessible knowledge bases are excluded.": "Actual retrieval is limited to knowledge bases accessible to the roles of the user using this AI employee. Inaccessible knowledge bases are excluded.",
|
||||
"Maximum number of knowledge-base entries returned for each retrieval.": "Maximum number of knowledge-base entries returned for each retrieval.",
|
||||
"Minimum similarity score for knowledge-base content to be included in retrieval results.": "Minimum similarity score for knowledge-base content to be included in retrieval results.",
|
||||
"LLM service": "LLM service",
|
||||
"LLM service \"{{name}}\" was not found": "LLM service \"{{name}}\" was not found",
|
||||
"LLM service not configured": "LLM service not configured",
|
||||
|
||||
@@ -172,6 +172,15 @@
|
||||
"Knowledge Base Prompt": "提示词(引用知识库)",
|
||||
"Knowledge Base Prompt placeholder": "",
|
||||
"KnowledgeBase": "知识库",
|
||||
"Retrieval strategy": "召回策略",
|
||||
"Automatically retrieve for every question": "每次提问自动召回",
|
||||
"Retrieve before every user question, then answer with the retrieved content.": "每次收到用户提问时,先检索知识库,再结合检索结果生成回答。",
|
||||
"Retrieve on demand": "按需召回",
|
||||
"The AI employee retrieves knowledge-base content only when it determines that it is needed.": "AI 员工会在判断有必要时调用知识库检索工具,再结合检索结果回答。",
|
||||
"Leave blank to retrieve from all knowledge bases": "未选择知识库时,将从所有可访问的知识库中召回相关内容",
|
||||
"Actual retrieval is limited to knowledge bases accessible to the roles of the user using this AI employee. Inaccessible knowledge bases are excluded.": "实际召回范围取决于使用该 AI 员工的用户角色权限;无权限的知识库不会参与召回。",
|
||||
"Maximum number of knowledge-base entries returned for each retrieval.": "设置每次召回返回的知识库内容条数上限。",
|
||||
"Minimum similarity score for knowledge-base content to be included in retrieval results.": "仅召回相似度分数不低于此阈值的知识库内容。",
|
||||
"LLM service": "LLM 服务",
|
||||
"LLM service \"{{name}}\" was not found": "未找到 LLM 服务 \"{{name}}\"",
|
||||
"LLM service not configured": "LLM 服务未配置",
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { AIEmployee } from '../ai-employees/ai-employee';
|
||||
|
||||
describe('AIEmployee knowledge-base tools', () => {
|
||||
it('does not expose the knowledge-base tool when tools are disabled', async () => {
|
||||
const employee = Object.create(AIEmployee.prototype) as AIEmployee;
|
||||
const getAIEmployeeTools = vi.fn();
|
||||
const getToolsMap = vi.fn();
|
||||
|
||||
Reflect.set(employee, 'areToolsEnabled', () => false);
|
||||
Reflect.set(employee, 'getAIEmployeeTools', getAIEmployeeTools);
|
||||
Reflect.set(employee, 'getToolsMap', getToolsMap);
|
||||
|
||||
await expect((employee as unknown as { getAgentTools: () => Promise<unknown> }).getAgentTools()).resolves.toEqual({
|
||||
tools: [],
|
||||
baseToolNames: new Set(),
|
||||
});
|
||||
expect(getAIEmployeeTools).not.toHaveBeenCalled();
|
||||
expect(getToolsMap).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not expose the knowledge-base tool when the current user has no accessible knowledge base', async () => {
|
||||
const employee = Object.create(AIEmployee.prototype) as AIEmployee;
|
||||
const hasAccessibleKnowledgeBase = vi.fn().mockResolvedValue(false);
|
||||
const getTools = vi.fn();
|
||||
|
||||
Reflect.set(employee, 'employee', {
|
||||
toJSON: () => ({ enableKnowledgeBase: true, knowledgeBase: { knowledgeBaseKeys: ['handbook'] } }),
|
||||
});
|
||||
Reflect.set(employee, 'ctx', { state: { currentUser: { roles: [{ name: 'member' }] } } });
|
||||
Reflect.set(employee, 'plugin', {
|
||||
knowledgeBaseManager: {
|
||||
isEnabledKnowledgeBase: vi.fn().mockResolvedValue(true),
|
||||
hasAccessibleKnowledgeBase,
|
||||
},
|
||||
});
|
||||
Reflect.set(employee, 'toolsManager', { getTools });
|
||||
|
||||
await expect(
|
||||
(employee as unknown as { getKnowledgeBaseRetrieveTool: () => Promise<unknown> }).getKnowledgeBaseRetrieveTool(),
|
||||
).resolves.toBeUndefined();
|
||||
expect(hasAccessibleKnowledgeBase).toHaveBeenCalledWith({
|
||||
employee: { enableKnowledgeBase: true, knowledgeBase: { knowledgeBaseKeys: ['handbook'] } },
|
||||
roleNames: ['member'],
|
||||
});
|
||||
expect(getTools).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+1
@@ -134,6 +134,7 @@ describe('AIEmployee skill tool binding', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
Reflect.set(employee, 'areToolsEnabled', () => true);
|
||||
const result = await (employee as any).getAgentTools();
|
||||
|
||||
expect(result.baseToolNames).toEqual(new Set(['getSkill']));
|
||||
|
||||
@@ -89,7 +89,11 @@ describe('aiEmployees.create', () => {
|
||||
|
||||
await create(ctx, vi.fn() as Next);
|
||||
|
||||
expect(values).toEqual({ username: 'sales-assistant_2', nickname: '销售助理 2' });
|
||||
expect(values).toEqual({
|
||||
username: 'sales-assistant_2',
|
||||
nickname: '销售助理 2',
|
||||
knowledgeBase: { retrievalStrategy: 'onDemand' },
|
||||
});
|
||||
expect(findOne).toHaveBeenCalledWith({ filter: { username: 'sales-assistant_2' } });
|
||||
expect(actionCreate).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
@@ -143,5 +143,11 @@ describe('AI plugin Swagger', () => {
|
||||
expect(schemas.AIEmployee.properties?.builtIn).toMatchObject({ type: 'boolean' });
|
||||
expect(schemas.AIEmployee.properties?.category).toMatchObject({ type: 'string' });
|
||||
expect(schemas.AIEmployee.properties?.deprecated).toMatchObject({ type: 'boolean' });
|
||||
expect(create.properties?.knowledgeBase?.properties?.retrievalStrategy).toEqual({
|
||||
type: 'string',
|
||||
enum: ['always', 'onDemand'],
|
||||
description:
|
||||
'Knowledge-base retrieval mode. Defaults to onDemand for new employees; omitted or invalid legacy values run as always.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import RetrievalStrategyMigration from '../migrations/20260501000000-ai-employee-knowledge-base-retrieval-strategy';
|
||||
|
||||
type EmployeeRecord = {
|
||||
get: (field: string) => unknown;
|
||||
update: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
|
||||
const createEmployee = (knowledgeBase: unknown): EmployeeRecord => ({
|
||||
get: (field) => (field === 'knowledgeBase' ? knowledgeBase : undefined),
|
||||
update: vi.fn(),
|
||||
});
|
||||
|
||||
describe('knowledge base retrieval strategy migration', () => {
|
||||
it('marks only missing or invalid legacy settings as always and preserves other JSON values', async () => {
|
||||
const missingStrategy = createEmployee({ knowledgeBaseKeys: ['handbook'], topK: 5, score: '0.7' });
|
||||
const explicitOnDemand = createEmployee({ knowledgeBaseKeys: ['sales'], retrievalStrategy: 'onDemand' });
|
||||
const invalidStrategy = createEmployee({ score: '0.8', retrievalStrategy: 'later' });
|
||||
const noSettings = createEmployee(undefined);
|
||||
const find = vi.fn().mockResolvedValue([missingStrategy, explicitOnDemand, invalidStrategy, noSettings]);
|
||||
const migration = new RetrievalStrategyMigration({
|
||||
db: { getRepository: () => ({ find }) },
|
||||
} as never);
|
||||
|
||||
await migration.up();
|
||||
|
||||
expect(missingStrategy.update).toHaveBeenCalledWith({
|
||||
knowledgeBase: { knowledgeBaseKeys: ['handbook'], topK: 5, score: '0.7', retrievalStrategy: 'always' },
|
||||
});
|
||||
expect(invalidStrategy.update).toHaveBeenCalledWith({
|
||||
knowledgeBase: { score: '0.8', retrievalStrategy: 'always' },
|
||||
});
|
||||
expect(noSettings.update).toHaveBeenCalledWith({ knowledgeBase: { retrievalStrategy: 'always' } });
|
||||
expect(explicitOnDemand.update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { AIEmployee } from '../../collections/ai-employees';
|
||||
import { KnowledgeBaseManager } from '../ai-employees/ai-knowledge-base';
|
||||
import {
|
||||
getCurrentRoleNames,
|
||||
getKnowledgeBaseBackgroundPrompt,
|
||||
KNOWLEDGE_BASE_NO_ACCESS_PROMPT,
|
||||
KNOWLEDGE_BASE_PRE_RETRIEVED_PROMPT,
|
||||
normalizeKnowledgeBaseRetrievalStrategy,
|
||||
withDefaultKnowledgeBaseRetrievalStrategy,
|
||||
} from '../ai-employees/ai-knowledge-base';
|
||||
|
||||
const createEmployee = (knowledgeBase: AIEmployee['knowledgeBase']): AIEmployee => ({
|
||||
username: 'atlas',
|
||||
enableKnowledgeBase: true,
|
||||
enabled: true,
|
||||
builtIn: false,
|
||||
knowledgeBase,
|
||||
});
|
||||
|
||||
describe('knowledge base retrieval settings', () => {
|
||||
it('normalizes missing and invalid legacy strategies to always', () => {
|
||||
expect(normalizeKnowledgeBaseRetrievalStrategy(undefined)).toBe('always');
|
||||
expect(normalizeKnowledgeBaseRetrievalStrategy('invalid')).toBe('always');
|
||||
expect(normalizeKnowledgeBaseRetrievalStrategy('onDemand')).toBe('onDemand');
|
||||
});
|
||||
|
||||
it('writes onDemand when a new employee has no valid strategy', () => {
|
||||
expect(withDefaultKnowledgeBaseRetrievalStrategy({ topK: 3 })).toEqual({
|
||||
topK: 3,
|
||||
retrievalStrategy: 'onDemand',
|
||||
});
|
||||
expect(withDefaultKnowledgeBaseRetrievalStrategy({ retrievalStrategy: 'always' })).toEqual({
|
||||
retrievalStrategy: 'always',
|
||||
});
|
||||
});
|
||||
|
||||
it('prefers the unique current user role names and preserves state fallbacks', () => {
|
||||
expect(
|
||||
getCurrentRoleNames({
|
||||
currentUser: { roles: [{ name: 'editor' }, { name: 'reviewer' }, { name: 'editor' }, { name: 1 }] },
|
||||
currentRoles: ['member'],
|
||||
currentRole: 'guest',
|
||||
}),
|
||||
).toEqual(['editor', 'reviewer']);
|
||||
expect(getCurrentRoleNames({ currentRoles: ['editor', 'reviewer', 'editor'], currentRole: 'member' })).toEqual([
|
||||
'editor',
|
||||
'reviewer',
|
||||
]);
|
||||
expect(getCurrentRoleNames({ currentRoles: [], currentRole: 'member' })).toEqual([]);
|
||||
expect(getCurrentRoleNames({ currentRole: 'member' })).toEqual(['member']);
|
||||
});
|
||||
|
||||
it('selects the knowledge-base background instruction for each retrieval state', () => {
|
||||
expect(getKnowledgeBaseBackgroundPrompt({ accessDenied: true, onDemand: true, preRetrieved: true })).toBe(
|
||||
KNOWLEDGE_BASE_NO_ACCESS_PROMPT,
|
||||
);
|
||||
expect(getKnowledgeBaseBackgroundPrompt({ accessDenied: false, onDemand: false, preRetrieved: true })).toBe(
|
||||
KNOWLEDGE_BASE_PRE_RETRIEVED_PROMPT,
|
||||
);
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain("First answer the user's question");
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain('Only after completing the answer');
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain("brief notice in the user's language");
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain('did not use knowledge-base content');
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain('visually prominent Markdown reminder');
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain('blockquote with a bold');
|
||||
expect(KNOWLEDGE_BASE_NO_ACCESS_PROMPT).toContain('contact an administrator');
|
||||
expect(KNOWLEDGE_BASE_PRE_RETRIEVED_PROMPT).toContain('<knowledgeBase>');
|
||||
expect(KNOWLEDGE_BASE_PRE_RETRIEVED_PROMPT).toContain('do not call the knowledge base retrieval tool again');
|
||||
});
|
||||
|
||||
it('detects when the current roles cannot access any configured knowledge base', async () => {
|
||||
const getAccessibleKnowledgeBaseKeys = vi.fn().mockResolvedValue([]);
|
||||
const manager = new KnowledgeBaseManager({
|
||||
features: { knowledgeBase: { getAccessibleKnowledgeBaseKeys } },
|
||||
} as never);
|
||||
const employee = createEmployee({ knowledgeBaseKeys: ['handbook'], topK: 3, score: '0.6' });
|
||||
|
||||
await expect(manager.hasAccessibleKnowledgeBase({ employee, roleNames: ['member'] })).resolves.toBe(false);
|
||||
expect(getAccessibleKnowledgeBaseKeys).toHaveBeenCalledWith({
|
||||
knowledgeBaseKeys: ['handbook'],
|
||||
roleNames: ['member'],
|
||||
});
|
||||
});
|
||||
|
||||
it('passes an empty selection and all request roles to the search feature', async () => {
|
||||
const search = vi.fn().mockResolvedValue([{ content: 'Internal policy', metadata: {} }]);
|
||||
const manager = new KnowledgeBaseManager({
|
||||
features: { knowledgeBase: { search } },
|
||||
} as never);
|
||||
|
||||
await expect(
|
||||
manager.retrievePrompt({
|
||||
employee: createEmployee({ knowledgeBaseKeys: [], topK: 3, score: '0.6' }),
|
||||
query: 'What is the internal policy?',
|
||||
roleNames: ['editor', 'reviewer'],
|
||||
}),
|
||||
).resolves.toBe('Human: Internal policy');
|
||||
|
||||
expect(search).toHaveBeenCalledWith({
|
||||
knowledgeBaseKeys: [],
|
||||
query: 'What is the internal policy?',
|
||||
topK: 3,
|
||||
score: '0.6',
|
||||
roleNames: ['editor', 'reviewer'],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -20,6 +20,11 @@ import { KnowledgeBaseGroup, DocumentSegmentedWithScore } from '../types';
|
||||
import { EEFeatures } from '../manager/ai-feature-manager';
|
||||
import { ChatPromptTemplate } from '@langchain/core/prompts';
|
||||
import type { AIEmployee as AIEmployeeType } from '../../collections/ai-employees';
|
||||
import {
|
||||
getCurrentRoleNames,
|
||||
getKnowledgeBaseBackgroundPrompt,
|
||||
normalizeKnowledgeBaseRetrievalStrategy,
|
||||
} from './ai-knowledge-base';
|
||||
import {
|
||||
conversationMiddleware,
|
||||
skillToolBindingMiddleware,
|
||||
@@ -168,6 +173,9 @@ export class AIEmployee {
|
||||
return this.chatSettings.enableTools !== false;
|
||||
}
|
||||
|
||||
private getAIEmployeeRecord(): AIEmployeeType {
|
||||
return this.employee.toJSON() as AIEmployeeType;
|
||||
}
|
||||
async getFormatMessages(userMessages: AIMessageInput[]) {
|
||||
const { provider } = await this.plugin.aiManager.getLLMService({
|
||||
...this.model,
|
||||
@@ -858,7 +866,18 @@ export class AIEmployee {
|
||||
if (this.systemPromptMode === 'raw') {
|
||||
return about;
|
||||
}
|
||||
|
||||
const employee = this.getAIEmployeeRecord();
|
||||
const knowledgeBaseManager = this.plugin.knowledgeBaseManager;
|
||||
const knowledgeBaseEnabled = await knowledgeBaseManager.isEnabledKnowledgeBase(employee);
|
||||
const roleNames = getCurrentRoleNames(this.ctx.state);
|
||||
const hasAccessibleKnowledgeBase = knowledgeBaseEnabled
|
||||
? await knowledgeBaseManager.hasAccessibleKnowledgeBase({ employee, roleNames })
|
||||
: false;
|
||||
const knowledgeBaseAccessDenied = knowledgeBaseEnabled && !hasAccessibleKnowledgeBase;
|
||||
const knowledgeBaseOnDemand =
|
||||
knowledgeBaseEnabled &&
|
||||
hasAccessibleKnowledgeBase &&
|
||||
normalizeKnowledgeBaseRetrievalStrategy(employee.knowledgeBase?.retrievalStrategy) === 'onDemand';
|
||||
const userConfig = await this.db.getRepository('usersAiEmployees').findOne({
|
||||
filter: {
|
||||
userId: this.ctx.auth?.user.id ?? 0,
|
||||
@@ -886,22 +905,24 @@ export class AIEmployee {
|
||||
}
|
||||
|
||||
let knowledgeBase: string | undefined;
|
||||
const { knowledgeBaseManager } = this.plugin;
|
||||
const employee: AIEmployeeType = this.employee.toJSON();
|
||||
if (
|
||||
(await knowledgeBaseManager.isEnabledKnowledgeBase(employee)) &&
|
||||
employee.knowledgeBasePrompt &&
|
||||
userMessages?.length
|
||||
) {
|
||||
if (knowledgeBaseEnabled && hasAccessibleKnowledgeBase && !knowledgeBaseOnDemand && userMessages?.length) {
|
||||
const lastUserMessage = userMessages.filter((x) => x.role === 'user').at(-1);
|
||||
if (lastUserMessage) {
|
||||
knowledgeBase = await knowledgeBaseManager.retrievePrompt({
|
||||
employee,
|
||||
query: lastUserMessage.content.content as string,
|
||||
roleNames,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const knowledgeBaseBackgroundPrompt = getKnowledgeBaseBackgroundPrompt({
|
||||
accessDenied: knowledgeBaseAccessDenied,
|
||||
onDemand: knowledgeBaseOnDemand,
|
||||
preRetrieved: Boolean(knowledgeBase),
|
||||
});
|
||||
if (knowledgeBaseBackgroundPrompt) {
|
||||
background = `${background}\n${knowledgeBaseBackgroundPrompt}`;
|
||||
}
|
||||
const availableSkills = await this.getAvailableSkills();
|
||||
const availableAIEmployees = await this.getAvailableAIEmployees();
|
||||
|
||||
@@ -1433,6 +1454,22 @@ If information is missing, clearly state it in the summary.</Important>`;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async getKnowledgeBaseRetrieveTool(): Promise<ToolsEntry | undefined> {
|
||||
const employee = this.getAIEmployeeRecord();
|
||||
const knowledgeBaseManager = this.plugin.knowledgeBaseManager;
|
||||
if (!(await knowledgeBaseManager.isEnabledKnowledgeBase(employee))) {
|
||||
return undefined;
|
||||
}
|
||||
const hasAccessibleKnowledgeBase = await knowledgeBaseManager.hasAccessibleKnowledgeBase({
|
||||
employee,
|
||||
roleNames: getCurrentRoleNames(this.ctx.state),
|
||||
});
|
||||
if (!hasAccessibleKnowledgeBase) {
|
||||
return undefined;
|
||||
}
|
||||
return await this.toolsManager.getTools(SYSTEM_TOOLS.KNOWLEDGE_BASE, { ctx: this.ctx });
|
||||
}
|
||||
|
||||
private async getAIEmployeeTools() {
|
||||
if (!this.areToolsEnabled()) {
|
||||
return [];
|
||||
@@ -1451,13 +1488,9 @@ If information is missing, clearly state it in the summary.</Important>`;
|
||||
const toolMap = await this.getToolsMap();
|
||||
const settingsTools = this.employee.skillSettings?.tools ?? [];
|
||||
const employeeTools = [...settingsTools, ...this.tools];
|
||||
if (await this.plugin.knowledgeBaseManager.isEnabledKnowledgeBase(this.employee.toJSON() as AIEmployeeType)) {
|
||||
const knowledgeBaseRetrieveTool = await this.toolsManager.getTools(SYSTEM_TOOLS.KNOWLEDGE_BASE, {
|
||||
ctx: this.ctx,
|
||||
});
|
||||
if (knowledgeBaseRetrieveTool) {
|
||||
employeeTools.push({ name: SYSTEM_TOOLS.KNOWLEDGE_BASE });
|
||||
}
|
||||
const knowledgeBaseRetrieveTool = await this.getKnowledgeBaseRetrieveTool();
|
||||
if (knowledgeBaseRetrieveTool) {
|
||||
employeeTools.push({ name: SYSTEM_TOOLS.KNOWLEDGE_BASE });
|
||||
}
|
||||
for (const toolSetting of employeeTools) {
|
||||
if (generalToolsNameSet.has(toolSetting.name)) {
|
||||
|
||||
@@ -13,7 +13,111 @@ import { EEFeatures } from '../manager/ai-feature-manager';
|
||||
import type PluginAIServer from '../plugin';
|
||||
import _ from 'lodash';
|
||||
|
||||
export type KnowledgeBaseRetrieveOptions = { username?: string; employee?: AIEmployee; query: string };
|
||||
export const KNOWLEDGE_BASE_RETRIEVAL_STRATEGIES = ['always', 'onDemand'] as const;
|
||||
|
||||
export type KnowledgeBaseRetrievalStrategy = (typeof KNOWLEDGE_BASE_RETRIEVAL_STRATEGIES)[number];
|
||||
|
||||
type RequestRoleState = {
|
||||
currentRole?: unknown;
|
||||
currentRoles?: unknown;
|
||||
currentUser?: unknown;
|
||||
};
|
||||
|
||||
type CurrentUserRole = {
|
||||
name?: unknown;
|
||||
};
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
|
||||
const getRoleNames = (roles: unknown): string[] =>
|
||||
Array.isArray(roles)
|
||||
? Array.from(
|
||||
new Set(
|
||||
roles
|
||||
.map((role) => (isRecord(role) ? (role as CurrentUserRole).name : role))
|
||||
.filter((role): role is string => typeof role === 'string' && role.length > 0),
|
||||
),
|
||||
)
|
||||
: [];
|
||||
|
||||
export const isKnowledgeBaseRetrievalStrategy = (value: unknown): value is KnowledgeBaseRetrievalStrategy =>
|
||||
typeof value === 'string' && KNOWLEDGE_BASE_RETRIEVAL_STRATEGIES.includes(value as KnowledgeBaseRetrievalStrategy);
|
||||
|
||||
export const normalizeKnowledgeBaseRetrievalStrategy = (value: unknown): KnowledgeBaseRetrievalStrategy =>
|
||||
isKnowledgeBaseRetrievalStrategy(value) ? value : 'always';
|
||||
|
||||
export const withDefaultKnowledgeBaseRetrievalStrategy = (knowledgeBase: unknown): Record<string, unknown> => {
|
||||
const settings = isRecord(knowledgeBase) ? { ...knowledgeBase } : {};
|
||||
if (!isKnowledgeBaseRetrievalStrategy(settings.retrievalStrategy)) {
|
||||
settings.retrievalStrategy = 'onDemand';
|
||||
}
|
||||
return settings;
|
||||
};
|
||||
|
||||
export const getCurrentRoleNames = (state: unknown): string[] => {
|
||||
const { currentRole, currentRoles, currentUser } = (isRecord(state) ? state : {}) as RequestRoleState;
|
||||
const currentUserRoleNames = getRoleNames(isRecord(currentUser) ? currentUser.roles : undefined);
|
||||
if (currentUserRoleNames.length) {
|
||||
return currentUserRoleNames;
|
||||
}
|
||||
if (Array.isArray(currentRoles)) {
|
||||
return getRoleNames(currentRoles);
|
||||
}
|
||||
return typeof currentRole === 'string' && currentRole.length > 0 ? [currentRole] : [];
|
||||
};
|
||||
|
||||
export const KNOWLEDGE_BASE_ON_DEMAND_PROMPT =
|
||||
'Use the knowledge base retrieval tool only when the request needs internal knowledge, uploaded documents, ' +
|
||||
'or knowledge-base facts. Do not call it for requests that clearly do not need those sources.';
|
||||
|
||||
export const KNOWLEDGE_BASE_PRE_RETRIEVED_PROMPT =
|
||||
'The <knowledgeBase> content was retrieved in advance for the current user request. ' +
|
||||
'Use it directly when it is sufficient to answer; do not call the knowledge base retrieval tool again ' +
|
||||
'unless additional or different knowledge-base information is genuinely needed.';
|
||||
|
||||
export const KNOWLEDGE_BASE_NO_ACCESS_PROMPT =
|
||||
"The current user does not have permission to access any knowledge base in this AI employee's configured scope. " +
|
||||
"First answer the user's question as helpfully as possible using only information available " +
|
||||
'without knowledge-base content; do not replace or interrupt the answer with a permission notice, ' +
|
||||
'and do not fabricate unavailable facts. ' +
|
||||
"Only after completing the answer, append a brief notice in the user's language stating " +
|
||||
'that this response did not use knowledge-base content because the current user does not have permission ' +
|
||||
'to access these knowledge bases. ' +
|
||||
'Format this notice as a visually prominent Markdown reminder, using a blockquote with a bold warning ' +
|
||||
'or reminder heading so that it is easy to notice. ' +
|
||||
'If knowledge-base access is needed, advise the user to contact an administrator. ' +
|
||||
'Do not claim to have searched or used knowledge-base content.';
|
||||
|
||||
export const getKnowledgeBaseBackgroundPrompt = ({
|
||||
accessDenied,
|
||||
onDemand,
|
||||
preRetrieved,
|
||||
}: {
|
||||
accessDenied: boolean;
|
||||
onDemand: boolean;
|
||||
preRetrieved: boolean;
|
||||
}): string | undefined => {
|
||||
if (accessDenied) {
|
||||
return KNOWLEDGE_BASE_NO_ACCESS_PROMPT;
|
||||
}
|
||||
if (onDemand) {
|
||||
return KNOWLEDGE_BASE_ON_DEMAND_PROMPT;
|
||||
}
|
||||
return preRetrieved ? KNOWLEDGE_BASE_PRE_RETRIEVED_PROMPT : undefined;
|
||||
};
|
||||
|
||||
export type KnowledgeBaseRetrieveOptions = {
|
||||
username?: string;
|
||||
employee?: AIEmployee;
|
||||
query: string;
|
||||
roleNames?: string[];
|
||||
};
|
||||
|
||||
export type KnowledgeBaseAccessOptions = {
|
||||
employee: AIEmployee;
|
||||
roleNames: string[];
|
||||
};
|
||||
|
||||
const normalizeMatchedQuestions = (value: unknown) => {
|
||||
if (!Array.isArray(value)) {
|
||||
@@ -33,18 +137,15 @@ const buildKnowledgeBaseContent = (content: string, metadata?: Record<string, un
|
||||
export class KnowledgeBaseManager {
|
||||
constructor(private readonly plugin: PluginAIServer) {}
|
||||
|
||||
async retrievePrompt({ username, employee, query }: KnowledgeBaseRetrieveOptions): Promise<string> {
|
||||
async retrievePrompt({ username, employee, query, roleNames }: KnowledgeBaseRetrieveOptions): Promise<string> {
|
||||
employee = employee ?? (username ? await this.getEmployee(username) : null);
|
||||
if (!employee) {
|
||||
return 'Specified knowledge base not existed';
|
||||
}
|
||||
const { knowledgeBaseKeys, topK, score } = employee.knowledgeBase ?? {};
|
||||
if (!knowledgeBaseKeys || _.isEmpty(knowledgeBaseKeys)) {
|
||||
return 'Specified knowledge base not existed';
|
||||
}
|
||||
const { knowledgeBaseKeys = [], topK, score } = employee.knowledgeBase ?? {};
|
||||
|
||||
const promptTemplate = ChatPromptTemplate.fromTemplate(employee.knowledgeBasePrompt ?? '{knowledgeBaseData}');
|
||||
const docs = await this.plugin.features.knowledgeBase.search({ knowledgeBaseKeys, query, topK, score });
|
||||
const docs = await this.plugin.features.knowledgeBase.search({ knowledgeBaseKeys, query, topK, score, roleNames });
|
||||
if (!docs?.length) {
|
||||
return 'No document match in knowledge base';
|
||||
}
|
||||
@@ -56,6 +157,15 @@ export class KnowledgeBaseManager {
|
||||
knowledgeBaseData,
|
||||
});
|
||||
}
|
||||
async hasAccessibleKnowledgeBase({ employee, roleNames }: KnowledgeBaseAccessOptions): Promise<boolean> {
|
||||
const knowledgeBaseKeys = employee.knowledgeBase?.knowledgeBaseKeys ?? [];
|
||||
const knowledgeBaseFeature = this.plugin.features.knowledgeBase;
|
||||
if (!knowledgeBaseFeature.getAccessibleKnowledgeBaseKeys) {
|
||||
return true;
|
||||
}
|
||||
const accessibleKeys = await knowledgeBaseFeature.getAccessibleKnowledgeBaseKeys({ knowledgeBaseKeys, roleNames });
|
||||
return accessibleKeys.length > 0;
|
||||
}
|
||||
|
||||
async isEnabledKnowledgeBase(username: string): Promise<boolean>;
|
||||
async isEnabledKnowledgeBase(employee: AIEmployee): Promise<boolean>;
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
|
||||
import { DocumentSegmentedWithScore, KnowledgeBase, KnowledgeBaseGroup, SearchOptions } from '../types';
|
||||
|
||||
export type KnowledgeBaseAccessOptions = Pick<SearchOptions, 'knowledgeBaseKeys' | 'roleNames'>;
|
||||
export interface KnowledgeBaseFeature {
|
||||
getKnowledgeBase(knowledgeBaseKeys: string[]): Promise<KnowledgeBase[]>;
|
||||
getKnowledgeBaseGroup(knowledgeBaseKeys: string[]): Promise<KnowledgeBaseGroup[]>;
|
||||
getAccessibleKnowledgeBaseKeys(options: KnowledgeBaseAccessOptions): Promise<string[]>;
|
||||
search(options: SearchOptions): Promise<DocumentSegmentedWithScore[]>;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export class AIPluginFeatureManagerImpl
|
||||
}
|
||||
|
||||
get knowledgeBase(): KnowledgeBaseFeature {
|
||||
if (!this.features.vectorStoreProvider) {
|
||||
if (!this.features.knowledgeBase) {
|
||||
throw this.featureNotSupportedError('knowledgeBase');
|
||||
}
|
||||
return this.features.knowledgeBase;
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { Migration } from '@nocobase/server';
|
||||
import { isKnowledgeBaseRetrievalStrategy } from '../ai-employees/ai-knowledge-base';
|
||||
|
||||
type KnowledgeBaseSettings = Record<string, unknown>;
|
||||
|
||||
const getKnowledgeBaseSettings = (value: unknown): KnowledgeBaseSettings =>
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value) ? { ...(value as KnowledgeBaseSettings) } : {};
|
||||
|
||||
export default class extends Migration {
|
||||
on = 'afterSync';
|
||||
appVersion = '<3.0.0';
|
||||
|
||||
async up() {
|
||||
const repository = this.db.getRepository('aiEmployees');
|
||||
const employees = await repository.find();
|
||||
|
||||
for (const employee of employees) {
|
||||
const knowledgeBase = getKnowledgeBaseSettings(employee.get('knowledgeBase'));
|
||||
if (isKnowledgeBaseRetrievalStrategy(knowledgeBase.retrievalStrategy)) {
|
||||
continue;
|
||||
}
|
||||
await employee.update({ knowledgeBase: { ...knowledgeBase, retrievalStrategy: 'always' } });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
import { KnowledgeBaseManager } from './ai-employees/ai-knowledge-base';
|
||||
import { LLMStreamCachedManager } from './manager/llm-stream-manager';
|
||||
import { appendAIFileAttachmentSource } from './attachments';
|
||||
|
||||
import { withDefaultKnowledgeBaseRetrievalStrategy } from './ai-employees/ai-knowledge-base';
|
||||
type MCPClientModel = Model<{ useUserContext?: boolean }>;
|
||||
type TransactionOptions = {
|
||||
transaction?: Transaction;
|
||||
@@ -119,8 +119,10 @@ export class PluginAIServer extends Plugin {
|
||||
this.app.on('afterUpgrade', async () => {
|
||||
await this.resetConversationThreadsWhenCheckpointsEmpty();
|
||||
});
|
||||
this.db.on('aiEmployees.beforeCreate', (employee: Model) => {
|
||||
employee.set('knowledgeBase', withDefaultKnowledgeBaseRetrievalStrategy(employee.get('knowledgeBase')));
|
||||
});
|
||||
}
|
||||
|
||||
private async resetConversationThreadsWhenCheckpointsEmpty() {
|
||||
const [checkpointCount, checkpointWriteCount, checkpointBlobCount, conversationsWithThreadCount] =
|
||||
await Promise.all([
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
isValidAIEmployeeUsername,
|
||||
normalizeAIEmployeeName,
|
||||
} from '../../common/ai-employee-validation';
|
||||
|
||||
import { withDefaultKnowledgeBaseRetrievalStrategy } from '../ai-employees/ai-knowledge-base';
|
||||
const isUniqueConstraintError = (error: unknown) =>
|
||||
error instanceof UniqueConstraintError ||
|
||||
(typeof error === 'object' && error !== null && 'name' in error && error.name === 'SequelizeUniqueConstraintError');
|
||||
@@ -65,8 +65,16 @@ const validateAndNormalizeProfileValues = (ctx: Context) => {
|
||||
}
|
||||
};
|
||||
|
||||
const setDefaultKnowledgeBaseRetrievalStrategy = (ctx: Context) => {
|
||||
const values = ctx.action.params.values;
|
||||
if (isRecord(values)) {
|
||||
values.knowledgeBase = withDefaultKnowledgeBaseRetrievalStrategy(values.knowledgeBase);
|
||||
}
|
||||
};
|
||||
|
||||
export const create = async (ctx: Context, next: Next) => {
|
||||
validateAndNormalizeProfileValues(ctx);
|
||||
setDefaultKnowledgeBaseRetrievalStrategy(ctx);
|
||||
const username = ctx.action.params.values?.username;
|
||||
|
||||
if (typeof username === 'string') {
|
||||
|
||||
@@ -52,4 +52,10 @@ export type DocumentSegmentedWithScore = DocumentSegmented & {
|
||||
score: number;
|
||||
};
|
||||
|
||||
export type SearchOptions = { knowledgeBaseKeys: string[]; query: string; topK?: number; score?: string };
|
||||
export type SearchOptions = {
|
||||
knowledgeBaseKeys?: string[];
|
||||
query: string;
|
||||
topK?: number;
|
||||
score?: string;
|
||||
roleNames?: string[];
|
||||
};
|
||||
|
||||
@@ -126,6 +126,12 @@ const knowledgeBaseSettings = {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
retrievalStrategy: {
|
||||
type: 'string',
|
||||
enum: ['always', 'onDemand'],
|
||||
description:
|
||||
'Knowledge-base retrieval mode. Defaults to onDemand for new employees; omitted or invalid legacy values run as always.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -7176,6 +7176,44 @@
|
||||
xml2js "^0.5.0"
|
||||
xmlbuilder "^15.1.1"
|
||||
|
||||
"@nocobase/utils@3.0.0-alpha.7":
|
||||
version "3.0.0-alpha.7"
|
||||
resolved "https://registry.npmmirror.com/@nocobase/utils/-/utils-3.0.0-alpha.7.tgz#6845be6838ed29c9a6b9916c0a106a16b20eaa8a"
|
||||
integrity sha512-o2EOkidCV7s3eiGqVQbK6h5j2EYTn12ex8+VWELisqvA2NZdFsUmvmBQSyWpoAdpYB8S0AlXZvaQHbbsEQrjCg==
|
||||
dependencies:
|
||||
"@budibase/handlebars-helpers" "0.14.0"
|
||||
"@hapi/topo" "^6.0.0"
|
||||
"@rc-component/mini-decimal" "^1.1.0"
|
||||
axios "^1.7.0"
|
||||
dayjs "^1.11.9"
|
||||
deepmerge "^4.2.2"
|
||||
flat-to-nested "^1.1.1"
|
||||
fs-extra "^11.1.1"
|
||||
graphlib "^2.1.8"
|
||||
handlebars "^4.7.8"
|
||||
ipaddr.js "^1.9.1"
|
||||
liquidjs "^10.23.0"
|
||||
multer "^2.1.1"
|
||||
object-path "^0.11.8"
|
||||
ses "^1.14.0"
|
||||
|
||||
"@node-saml/node-saml@^4.0.2":
|
||||
version "4.0.5"
|
||||
resolved "https://registry.npmmirror.com/@node-saml/node-saml/-/node-saml-4.0.5.tgz#039e387095b54639b06df62b1b4a6d8941c6d907"
|
||||
integrity sha512-J5DglElbY1tjOuaR1NPtjOXkXY5bpUhDoKVoeucYN98A3w4fwgjIOPqIGcb6cQsqFq2zZ6vTCeKn5C/hvefSaw==
|
||||
dependencies:
|
||||
"@types/debug" "^4.1.7"
|
||||
"@types/passport" "^1.0.11"
|
||||
"@types/xml-crypto" "^1.4.2"
|
||||
"@types/xml-encryption" "^1.2.1"
|
||||
"@types/xml2js" "^0.4.11"
|
||||
"@xmldom/xmldom" "^0.8.6"
|
||||
debug "^4.3.4"
|
||||
xml-crypto "^3.0.1"
|
||||
xml-encryption "^3.0.2"
|
||||
xml2js "^0.5.0"
|
||||
xmlbuilder "^15.1.1"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
|
||||
Reference in New Issue
Block a user