diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 2e39ca5b1..8bf7724d4 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -205,6 +205,7 @@ export default defineConfig({ { text: "组件:事件监听器", link: "/zh/plugin/dev/components/event-listener" }, { text: "组件:命令", link: "/zh/plugin/dev/components/command" }, { text: "组件:工具", link: "/zh/plugin/dev/components/tool" }, + { text: "组件:知识检索器", link: "/zh/plugin/dev/components/knowledge-retriever" }, ], }, { @@ -477,6 +478,7 @@ export default defineConfig({ { text: "Component: Event Listener", link: "/en/plugin/dev/components/event-listener" }, { text: "Component: Command", link: "/en/plugin/dev/components/command" }, { text: "Component: Tool", link: "/en/plugin/dev/components/tool" }, + { text: "Component: Knowledge Retriever", link: "/en/plugin/dev/components/knowledge-retriever" }, ], }, { diff --git a/docs/assets/image/zh/plugin/dev/components/knowledge_retriever_config.png b/docs/assets/image/zh/plugin/dev/components/knowledge_retriever_config.png new file mode 100644 index 000000000..672537ec3 Binary files /dev/null and b/docs/assets/image/zh/plugin/dev/components/knowledge_retriever_config.png differ diff --git a/docs/assets/image/zh/plugin/dev/components/knowledge_retriever_use.png b/docs/assets/image/zh/plugin/dev/components/knowledge_retriever_use.png new file mode 100644 index 000000000..623d4bcb5 Binary files /dev/null and b/docs/assets/image/zh/plugin/dev/components/knowledge_retriever_use.png differ diff --git a/docs/en/plugin/dev/components/add.md b/docs/en/plugin/dev/components/add.md index c534aaef6..327c03371 100644 --- a/docs/en/plugin/dev/components/add.md +++ b/docs/en/plugin/dev/components/add.md @@ -5,6 +5,7 @@ Plugins consist of one or more components that provide different functionalities - Event Listeners (EventListener): Listen to events during pipeline execution and modify context or pipelines. - Commands (Command): Triggered by user command messages starting with `!` (or other configured prefixes). - Tools (Tool): Called by LLMs during execution of LangBot's built-in Local Agent. +- Knowledge Retrievers (KnowledgeRetriever): Provide external knowledge base retrieval capabilities for LangBot, supporting integration with various RAG systems. ## Adding Components @@ -68,4 +69,5 @@ For detailed usage of each component, please refer to: - [EventListener](./event-listener.md) - [Command](./command.md) -- [Tool](./tool.md) \ No newline at end of file +- [Tool](./tool.md) +- [KnowledgeRetriever](./knowledge-retriever.md) \ No newline at end of file diff --git a/docs/en/plugin/dev/components/knowledge-retriever.md b/docs/en/plugin/dev/components/knowledge-retriever.md new file mode 100644 index 000000000..5a5bc74b1 --- /dev/null +++ b/docs/en/plugin/dev/components/knowledge-retriever.md @@ -0,0 +1,264 @@ +# Component: Knowledge Retriever + +The Knowledge Retriever component allows plugins to provide external knowledge base retrieval capabilities for LangBot. When users create an external knowledge base in LangBot, they can choose a knowledge retriever provided by a plugin to retrieve knowledge. + + + +## Adding a Knowledge Retriever Component + +A single plugin can add any number of knowledge retrievers. Execute the command `lbp comp KnowledgeRetriever` in the plugin directory and follow the prompts to enter the knowledge retriever configuration. + +```bash +➜ FastGPTRetriever > lbp comp KnowledgeRetriever +Generating component KnowledgeRetriever... +KnowledgeRetriever name: fastgpt +KnowledgeRetriever description: Retrieve knowledge from FastGPT knowledge bases +Component KnowledgeRetriever generated successfully. +``` + +This will generate `fastgpt.yaml` and `fastgpt.py` files in the `components/knowledge_retriever/` directory. The `.yaml` file defines the basic information and configuration parameters of the knowledge retriever, and the `.py` file is the handler for this retriever: + +```bash +➜ FastGPTRetriever > tree +... +├── components +│ ├── __init__.py +│ └── knowledge_retriever +│ ├── __init__.py +│ ├── fastgpt.py +│ └── fastgpt.yaml +... +``` + +## Manifest File: Knowledge Retriever + +```yaml +apiVersion: v1 # Do not modify +kind: KnowledgeRetriever # Do not modify +metadata: + name: fastgpt # Knowledge retriever name, used to identify this retriever + label: + en_US: FastGPT Knowledge Base # Retriever display name, shown in LangBot's UI, supports multiple languages + zh_Hans: FastGPT 知识库 + ja_JP: FastGPT ナレッジベース + description: + en_US: 'Retrieve knowledge from FastGPT knowledge bases' # Retriever description, shown in LangBot's UI, supports multiple languages. Optional + zh_Hans: '从 FastGPT 知识库中检索知识' + ja_JP: 'FastGPT ナレッジベースから知識を取得' + icon: assets/icon.svg # Retriever icon, displayed on the external knowledge base configuration page +spec: + config: # Retriever configuration parameters, users need to fill in these parameters when creating an external knowledge base + - name: api_base_url # Parameter name + type: string # Parameter type: string, number, boolean, select + label: + en_US: API Base URL + zh_Hans: API 基础地址 + ja_JP: API ベース URL + description: + en_US: 'Base URL for FastGPT API' + zh_Hans: 'FastGPT API 基础地址' + ja_JP: 'FastGPT API ベース URL' + default: 'http://localhost:3000' # Default parameter value + required: true # Whether required + - name: api_key + type: string + label: + en_US: FastGPT API Key + zh_Hans: FastGPT API Key + ja_JP: FastGPT API キー + description: + en_US: 'API key from your FastGPT instance' + zh_Hans: '从您的 FastGPT 实例获取的 API Key' + ja_JP: 'FastGPT インスタンスから取得した API Key' + default: '' + required: true + - name: search_mode # Example of select type parameter + type: select + label: + en_US: Search Mode + zh_Hans: 搜索模式 + ja_JP: 検索モード + description: + en_US: 'The search method to use' + zh_Hans: '使用的搜索方法' + ja_JP: '使用する検索方法' + default: 'embedding' + options: # Select type parameters need to define an option list + - name: 'embedding' + label: + en_US: 'Embedding Search' + zh_Hans: '向量搜索' + ja_JP: '埋め込み検索' + - name: 'fullTextRecall' + label: + en_US: 'Full-Text Recall' + zh_Hans: '全文检索' + ja_JP: '全文検索' + - name: using_rerank # Example of boolean type parameter + type: boolean + label: + en_US: Use Re-ranking + zh_Hans: 使用重排序 + ja_JP: リランキングを使用 + description: + en_US: 'Whether to use re-ranking' + zh_Hans: '是否使用重排序' + ja_JP: 'リランキングを使用するかどうか' + default: false + required: false +execution: + python: + path: fastgpt.py # Retriever handler, do not modify + attr: FastGPT # Class name of the retriever handler, consistent with the class name in fastgpt.py +``` + +For configuration item format reference, see: [Plugin Manifest Configuration Format](/en/plugin/dev/basic-info) + +## Plugin Handler + +The following code will be generated by default (components/knowledge_retriever/.py). You need to implement the knowledge retrieval logic in the `retrieve` method of the `FastGPT` class. Complete code can be found in [langbot-plugin-demo](https://github.com/langbot-app/langbot-plugin-demo). + +```python +# Auto generated by LangBot Plugin SDK. +# Please refer to https://docs.langbot.app/en/plugin/dev/tutor.html for more details. +... + +class FastGPT(KnowledgeRetriever): + + async def retrieve(self, context: RetrievalContext) -> list[RetrievalResultEntry]: + """Retrieve knowledge from FastGPT knowledge base""" + + # 1. Get configuration parameters + api_base_url = self.config.get('api_base_url', 'http://localhost:3000') + api_key = self.config.get('api_key') + dataset_id = self.config.get('dataset_id') + search_mode = self.config.get('search_mode', 'embedding') + using_rerank = self.config.get('using_rerank', False) + + # 2. Parameter validation + if not api_key or not dataset_id: + logger.error("Missing required configuration: api_key or dataset_id") + return [] + + # 3. Build API request + url = f"{api_base_url.rstrip('/')}/api/core/dataset/searchTest" + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json" + } + payload = { + "datasetId": dataset_id, + "text": context.query, # Get query text from RetrievalContext + "searchMode": search_mode, + "usingReRank": using_rerank, + } + + try: + # 4. Call external API + async with httpx.AsyncClient() as client: + response = await client.post(url, json=payload, headers=headers, timeout=30.0) + response.raise_for_status() + result = response.json() + + # 5. Parse response and convert to RetrievalResultEntry + results = [] + for record in result.get('data', []): + # Combine main data and auxiliary data as content + content_text = '\n'.join([ + record.get('q', ''), + record.get('a', '') + ]).strip() + + # Create retrieval result entry + entry = RetrievalResultEntry( + id=record.get('id', ''), + content=[ContentElement.from_text(content_text)], + metadata={ + 'dataset_id': record.get('datasetId', ''), + 'source_name': record.get('sourceName', ''), + 'score': record.get('score', 0.0), + }, + # Convert similarity score to distance (higher score = smaller distance) + distance=1.0 - float(record.get('score', 0.0)), + ) + results.append(entry) + + logger.info(f"Retrieved {len(results)} chunks from FastGPT dataset {dataset_id}") + return results + + except httpx.HTTPStatusError as e: + logger.error(f"HTTP error from FastGPT API: {e.response.status_code} - {e.response.text}") + return [] + except httpx.RequestError as e: + logger.error(f"Request error when calling FastGPT API: {str(e)}") + return [] + except Exception as e: + traceback.print_exc() + logger.error(f"Unexpected error during retrieval: {str(e)}") + return [] +``` + +### Retrieval Context + +`RetrievalContext` contains context information for this retrieval: + +```python +class RetrievalContext(pydantic.BaseModel): + """Knowledge retrieval context""" + + query: str + """Query text, the user's retrieval question""" +``` + +### Retrieval Results + +Retrieval results need to be converted to a list of `RetrievalResultEntry` objects, each representing a retrieved knowledge chunk: + +```python +class RetrievalResultEntry(pydantic.BaseModel): + """Single retrieval result entry""" + + id: str + """Result ID, uniquely identifies this entry""" + + content: list[ContentElement] + """Result content, create text content using ContentElement.from_text()""" + + metadata: dict[str, Any] + """Result metadata, can contain any key-value pairs, such as source, score, etc.""" + + distance: float + """Distance score, indicates relevance to the query (smaller is more relevant) + Usually calculated as 1.0 - similarity_score""" +``` + +### Getting Configuration Parameters + +Get user-configured parameter values using `self.config.get(parameter_name, default_value)`: + +```python +# Get string parameter +api_base_url = self.config.get('api_base_url', 'http://localhost:3000') + +# Get number parameters +limit = self.config.get('limit', 5000) +similarity = self.config.get('similarity', 0.0) + +# Get boolean parameter +using_rerank = self.config.get('using_rerank', False) + +# Get select parameter +search_mode = self.config.get('search_mode', 'embedding') +``` + +## Testing the Retriever + +After creation, execute the command `lbp run` in the plugin directory to start debugging. Then in LangBot: + +1. Go to the "Knowledge Base" page +2. Add an external knowledge base +3. Select the knowledge retriever provided by your plugin and fill in the configuration + + + +After saving, you can select this knowledge base in the LangBot pipeline. diff --git a/docs/en/plugin/plugin-intro.md b/docs/en/plugin/plugin-intro.md index e2a782c6c..af6ea5ec9 100644 --- a/docs/en/plugin/plugin-intro.md +++ b/docs/en/plugin/plugin-intro.md @@ -13,6 +13,7 @@ Plugins can provide the following components based on their specific functionali - Event Handlers: Listen to events during pipeline execution and modify context or pipelines. - Commands: Triggered by user command messages starting with `!` (or other configured prefixes). - Tools: Called by LLMs during execution of LangBot's built-in Local Agent. +- Knowledge Retrievers: Used to retrieve relevant knowledge from external knowledge bases. More component types will be supported for plugin implementation in the future. diff --git a/docs/zh/plugin/dev/components/add.md b/docs/zh/plugin/dev/components/add.md index 594cf3f23..eef807db9 100644 --- a/docs/zh/plugin/dev/components/add.md +++ b/docs/zh/plugin/dev/components/add.md @@ -5,6 +5,7 @@ - 事件监听器(EventListener):监听流水线执行期间的事件,对上下文或流水线进行修改。 - 命令(Command):由用户通过`!`(或其他已设置的前缀)开头的命令消息触发。 - 工具(Tool):供 LangBot 内置的 Local Agent 在执行期间由 LLM 调用。 +- 知识检索器(KnowledgeRetriever):为 LangBot 提供外部知识库检索能力,支持接入各类 RAG 系统。 ## 添加组件 @@ -69,4 +70,5 @@ components: - [EventListener](./event-listener.md) - [Command](./command.md) -- [Tool](./tool.md) \ No newline at end of file +- [Tool](./tool.md) +- [KnowledgeRetriever](./knowledge-retriever.md) \ No newline at end of file diff --git a/docs/zh/plugin/dev/components/knowledge-retriever.md b/docs/zh/plugin/dev/components/knowledge-retriever.md new file mode 100644 index 000000000..560a6fee6 --- /dev/null +++ b/docs/zh/plugin/dev/components/knowledge-retriever.md @@ -0,0 +1,265 @@ +# 组件:知识检索器 + +知识检索器(Knowledge Retriever)组件允许插件为 LangBot 提供外部知识库检索能力。当用户在 LangBot 中创建外部知识库时,可以选择由插件提供的知识检索器来检索知识。 + + + +## 添加知识检索器组件 + +单个插件中能添加任意数量的知识检索器,请在插件目录执行命令`lbp comp KnowledgeRetriever`,并根据提示输入知识检索器的配置。 + +```bash +➜ FastGPTRetriever > lbp comp KnowledgeRetriever +Generating component KnowledgeRetriever... +KnowledgeRetriever name: fastgpt +KnowledgeRetriever description: Retrieve knowledge from FastGPT knowledge bases +Component KnowledgeRetriever generated successfully. +组件 KnowledgeRetriever 生成成功。 +``` + +现在即会在`components/knowledge_retriever/`目录下生成`fastgpt.yaml`和`fastgpt.py`文件,`.yaml`定义了知识检索器的基础信息和配置参数,`.py`是该知识检索器的处理程序: + +```bash +➜ FastGPTRetriever > tree +... +├── components +│ ├── __init__.py +│ └── knowledge_retriever +│ ├── __init__.py +│ ├── fastgpt.py +│ └── fastgpt.yaml +... +``` + +## 清单文件:知识检索器 + +```yaml +apiVersion: v1 # 请勿修改 +kind: KnowledgeRetriever # 请勿修改 +metadata: + name: fastgpt # 知识检索器名称,用于标识该检索器 + label: + en_US: FastGPT Knowledge Base # 检索器显示名称,用于显示在 LangBot 的 UI 上,支持多语言 + zh_Hans: FastGPT 知识库 + ja_JP: FastGPT ナレッジベース + description: + en_US: 'Retrieve knowledge from FastGPT knowledge bases' # 检索器描述,用于显示在 LangBot 的 UI 上,支持多语言。可选 + zh_Hans: '从 FastGPT 知识库中检索知识' + ja_JP: 'FastGPT ナレッジベースから知識を取得' + icon: assets/icon.svg # 检索器图标,会被展示在外部知识库配置页面 +spec: + config: # 检索器配置参数,用户在创建外部知识库时需要填写这些参数 + - name: api_base_url # 参数名称 + type: string # 参数类型:string, number, boolean, select + label: + en_US: API Base URL + zh_Hans: API 基础地址 + ja_JP: API ベース URL + description: + en_US: 'Base URL for FastGPT API' + zh_Hans: 'FastGPT API 基础地址' + ja_JP: 'FastGPT API ベース URL' + default: 'http://localhost:3000' # 参数默认值 + required: true # 是否必填 + - name: api_key + type: string + label: + en_US: FastGPT API Key + zh_Hans: FastGPT API Key + ja_JP: FastGPT API キー + description: + en_US: 'API key from your FastGPT instance' + zh_Hans: '从您的 FastGPT 实例获取的 API Key' + ja_JP: 'FastGPT インスタンスから取得した API Key' + default: '' + required: true + - name: search_mode # select 类型参数示例 + type: select + label: + en_US: Search Mode + zh_Hans: 搜索模式 + ja_JP: 検索モード + description: + en_US: 'The search method to use' + zh_Hans: '使用的搜索方法' + ja_JP: '使用する検索方法' + default: 'embedding' + options: # select 类型参数需要定义选项列表 + - name: 'embedding' + label: + en_US: 'Embedding Search' + zh_Hans: '向量搜索' + ja_JP: '埋め込み検索' + - name: 'fullTextRecall' + label: + en_US: 'Full-Text Recall' + zh_Hans: '全文检索' + ja_JP: '全文検索' + - name: using_rerank # boolean 类型参数示例 + type: boolean + label: + en_US: Use Re-ranking + zh_Hans: 使用重排序 + ja_JP: リランキングを使用 + description: + en_US: 'Whether to use re-ranking' + zh_Hans: '是否使用重排序' + ja_JP: 'リランキングを使用するかどうか' + default: false + required: false +execution: + python: + path: fastgpt.py # 检索器处理程序,请勿修改 + attr: FastGPT # 检索器处理程序的类名,与 fastgpt.py 中的类名一致 +``` + +配置项格式可参考:[插件清单配置项格式](/zh/plugin/dev/basic-info) + +## 插件处理 + +默认会生成如下代码(components/knowledge_retriever/<检索器名称>.py),您需要在`FastGPT`类的`retrieve`方法中实现知识检索逻辑。完整代码可在[langbot-plugin-demo](https://github.com/langbot-app/langbot-plugin-demo)中找到。 + +```python +# Auto generated by LangBot Plugin SDK. +# Please refer to https://docs.langbot.app/en/plugin/dev/tutor.html for more details. +... + +class FastGPT(KnowledgeRetriever): + + async def retrieve(self, context: RetrievalContext) -> list[RetrievalResultEntry]: + """Retrieve knowledge from FastGPT knowledge base""" + + # 1. 获取配置参数 + api_base_url = self.config.get('api_base_url', 'http://localhost:3000') + api_key = self.config.get('api_key') + dataset_id = self.config.get('dataset_id') + search_mode = self.config.get('search_mode', 'embedding') + using_rerank = self.config.get('using_rerank', False) + + # 2. 参数验证 + if not api_key or not dataset_id: + logger.error("Missing required configuration: api_key or dataset_id") + return [] + + # 3. 构建 API 请求 + url = f"{api_base_url.rstrip('/')}/api/core/dataset/searchTest" + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json" + } + payload = { + "datasetId": dataset_id, + "text": context.query, # 从 RetrievalContext 获取查询文本 + "searchMode": search_mode, + "usingReRank": using_rerank, + } + + try: + # 4. 调用外部 API + async with httpx.AsyncClient() as client: + response = await client.post(url, json=payload, headers=headers, timeout=30.0) + response.raise_for_status() + result = response.json() + + # 5. 解析响应并转换为 RetrievalResultEntry + results = [] + for record in result.get('data', []): + # 合并主要数据和辅助数据作为内容 + content_text = '\n'.join([ + record.get('q', ''), + record.get('a', '') + ]).strip() + + # 创建检索结果条目 + entry = RetrievalResultEntry( + id=record.get('id', ''), + content=[ContentElement.from_text(content_text)], + metadata={ + 'dataset_id': record.get('datasetId', ''), + 'source_name': record.get('sourceName', ''), + 'score': record.get('score', 0.0), + }, + # 将相似度分数转换为距离(分数越高,距离越小) + distance=1.0 - float(record.get('score', 0.0)), + ) + results.append(entry) + + logger.info(f"Retrieved {len(results)} chunks from FastGPT dataset {dataset_id}") + return results + + except httpx.HTTPStatusError as e: + logger.error(f"HTTP error from FastGPT API: {e.response.status_code} - {e.response.text}") + return [] + except httpx.RequestError as e: + logger.error(f"Request error when calling FastGPT API: {str(e)}") + return [] + except Exception as e: + traceback.print_exc() + logger.error(f"Unexpected error during retrieval: {str(e)}") + return [] +``` + +### 检索上下文 + +`RetrievalContext` 包含本次检索的上下文信息: + +```python +class RetrievalContext(pydantic.BaseModel): + """知识检索上下文""" + + query: str + """查询文本,用户的检索问题""" +``` + +### 检索结果 + +检索结果需要转换为 `RetrievalResultEntry` 对象列表,每个对象代表一个检索到的知识块: + +```python +class RetrievalResultEntry(pydantic.BaseModel): + """单个检索结果条目""" + + id: str + """结果 ID,唯一标识此条目""" + + content: list[ContentElement] + """结果内容,使用 ContentElement.from_text() 创建文本内容""" + + metadata: dict[str, Any] + """结果元数据,可以包含任意键值对,如来源、分数等""" + + distance: float + """距离分数,表示与查询的相关度(越小越相关) + 通常通过 1.0 - similarity_score 计算""" +``` + +### 获取配置参数 + +通过 `self.config.get(参数名, 默认值)` 获取用户配置的参数值: + +```python +# 获取字符串参数 +api_base_url = self.config.get('api_base_url', 'http://localhost:3000') + +# 获取数字参数 +limit = self.config.get('limit', 5000) +similarity = self.config.get('similarity', 0.0) + +# 获取布尔参数 +using_rerank = self.config.get('using_rerank', False) + +# 获取 select 参数 +search_mode = self.config.get('search_mode', 'embedding') +``` + +## 测试检索器 + +创建完成后,在插件目录执行命令 `lbp run`,启动调试。然后在 LangBot 中: + +1. 进入"知识库"页面 +2. 添加外部知识库 +3. 选择您的插件提供的知识检索器并填写配置 + + + +保存后即可在 LangBot 流水线中选用该知识库。 \ No newline at end of file diff --git a/docs/zh/plugin/plugin-intro.md b/docs/zh/plugin/plugin-intro.md index f4f8de7e8..6c59b864b 100644 --- a/docs/zh/plugin/plugin-intro.md +++ b/docs/zh/plugin/plugin-intro.md @@ -13,6 +13,7 @@ LangBot 内部由多种组件组成,如大模型工具、命令、消息平台 - 事件处理器:监听流水线执行期间的事件,对上下文或流水线进行修改。 - 命令:由用户通过`!`(或其他已设置的前缀)开头的命令消息触发。 - 工具:供 LangBot 内置的 Local Agent 在执行期间由 LLM 调用。 +- 知识检索器:用于从外部知识库中检索相关知识。 后续还将支持更多组件的插件化。