跳到主要内容

🔄 知识库同步 (oikb)

让知识库与权威数据源保持自动同步。

oikb 是用于将内容同步到知识库中的官方配套工具。将其指向本地文件夹、GitHub 仓库、Confluence 空间、S3 存储桶或它支持的 44 种连接器中的任意一个,即可让知识库保持最新。

不同于一次性上传——上传后源数据一变化就立即过时——oikb 进行的是增量同步:它将知识库一次性接入到活跃的数据源,然后按计划、每次推送或按需持续保持数据新鲜。文档仓库、Wiki、存储桶,都能在无人值守的情况下保持同步。

它是一个独立的程序(命令行工具加上可选的长期运行的守护进程),不属于 Open WebUI 服务器的一部分,但它专为 Open WebUI 构建,并通过标准的 REST API 与之通信。

需要 Open WebUI 0.9.6+

oikb 调用增量同步端点(/sync/diff/sync/cleanup),这些端点在 v0.9.6 中加入。面对更早版本的服务器,没有可供调用的端点。这些端点的服务端行为记录在知识 → 同步本地目录中。


为什么使用知识库同步?

只传输变化的内容

每个文件都会计算哈希值(SHA-256),并与服务器上已有的内容进行对比,因此只会上传新增和修改的文件,已删除的会被移除。一个未发生变化的 10,000 文件仓库,重新同步只需几秒,因为没有文件被重新上传或重新嵌入。频繁运行几乎没有成本。

为大型文档库而设计

应用内的同步目录操作在浏览器中运行,因此在大型数据集(数千个文件或数 GB 的文档库)上会变慢且进度显示有限。oikb 以原生方式运行,带有进度条、并行上传和重试机制,因此可以可靠地同步数万级别的文件库。如果您的语料库很大,推荐使用此方式加载。

一个工具,所有数据源

将其指向本地文件夹、Git 仓库、Confluence 或 Notion 空间、S3 存储桶、Jira 项目、Slack 频道,以及另外 30 多种数据源。相同的命令和相同的增量引擎可处理所有这些场景。

自动保持新鲜

手动同步一次,或将其交给守护进程按间隔、Cron 或在有人推送时自动运行。一旦将知识库接入到活跃的数据源,它就不会再悄无声息地过时。

模型可以驱动它

守护进程同时充当 OpenAPI 工具服务器,因此模型可以在对话过程中触发重新同步并向用户反馈结果,而无需任何人触碰命令行。


主要功能

增量同步通过 SHA-256 差量比对,只上传新增和修改的文件;删除的文件会被移除,未变化的文件保持不动
🌐 44 种连接器本地文件夹、Git、云存储、Wiki、工单系统、聊天、CRM,以及一个网络爬虫
⏱️ 计划与 Webhook 同步按间隔、Cron 计划运行,或在有人推送的瞬间(通过守护进程)触发
👀 监听模式在本地文件夹每次保存时自动同步
🎯 选择性同步通过 include/exclude glob、大小上限进行过滤,并将一个数据源拆分到多个知识库
🤖 模型可触发守护进程是 OpenAPI 工具服务器,因此模型可以在聊天中启动和检查同步
🔑 使用您的权限以您的用户身份进行身份验证,绝不绕过知识库访问控制
📊 生产就绪Prometheus 指标、结构化 JSON 日志、同步历史记录和失败通知

安装

pip install oikb

需要 Python 3.11+Open WebUI 0.9.6+ 服务器。大多数连接器使用普通 HTTP,无需额外依赖。少数连接器需要相应的供应商 SDK,可作为可选扩展安装:

pip install oikb[s3]       # Amazon S3
pip install oikb[gcs]      # Google Cloud Storage
pip install oikb[azure]    # Azure Blob
pip install oikb[dropbox]  # Dropbox
pip install oikb[gdrive]   # Google Drive
pip install oikb[all]      # 一次性安装所有可选连接器

完整的扩展列表为 s3gcsazuredropboxr2gdrivegmailgsitesweboraclesharepoint-certall。此处未列出的连接器(GitHub、Confluence、Notion、Jira、Slack 以及大多数其他连接器)无需额外扩展。

生产环境可在 ghcr.io/open-webui/oikb 拉取 Docker 镜像。参见运行守护进程


快速开始

export OPEN_WEBUI_URL=http://localhost:3000
export OPEN_WEBUI_API_KEY=sk-your-api-key   # 设置 → 账户 → API 密钥

# 将本地文件夹同步到知识库
oikb sync ./docs --kb-id your-kb-id

# 或者同步 GitHub 仓库,无需本地克隆
oikb sync github:owner/repo --kb-id your-kb-id

# 预览将要发生的更改,不实际上传
oikb sync ./docs --kb-id your-kb-id --dry-run

--kb-id 是知识库的 ID,即工作区中其 URL 里的 UUID(.../knowledge/<kb-id>)。运行相同的命令两次,第二次运行不会有任何操作:只有内容发生变化的文件才会被处理。

同步过程示例

首次运行会上传所有内容;之后每次运行只传输变化的部分:

$ oikb sync github:acme/handbook --kb-id 8f3a2b1c-...
  1,204 files found
  Diff: +3, ~1, -2, 1198 unchanged
  Uploading ━━━━━━━━━━━━━━━━━━━━ 4/4 • 0:00:02
Sync complete: 3 added, 1 modified, 2 deleted, 1198 unchanged

Diff 一行是服务器对"实际变化"的回答:三个新增文件、一个修改文件、两个删除文件,以及 1,198 个保持原样的文件。

访问权限即您的权限

API 密钥以的用户身份进行身份验证。oikb 只能读写该用户已具有访问权限的知识库。它不是管理员后门,也不会绕过访问控制

保存凭据

避免每次命令都重复 URL 和密钥:

oikb config set url http://localhost:3000
oikb config set token sk-your-api-key
oikb config get                    # 显示已保存的内容(密钥会被掩码)

保存到 ~/.config/oikb/config.yaml(可通过 OIKB_CONFIG_DIR 覆盖目录)。解析顺序,按优先级从高到低:

  1. CLI 参数(--url--token
  2. 环境变量(OPEN_WEBUI_URLOPEN_WEBUI_API_KEY
  3. 配置文件

增量同步的工作原理

  1. oikb 扫描数据源,为每个文件计算 SHA-256 校验和。
  2. 它将该清单(路径、文件名和校验和,包含文件内容)发送到 Open WebUI 的 /sync/diff,后者返回新增修改删除的精确清单,以及需要创建或移除的目录。此调用是只读的,不会更改知识库。
  3. oikb 删除过时的文件(以及变为空的目录),创建缺失的目录,然后仅上传新增修改的文件,每个文件都标记了其哈希值,以便服务器跳过重新计算哈希。

由于差量比对基于内容哈希,未发生变化的仓库几乎可以瞬时重新同步:没有文件被重新上传、重新提取或重新嵌入,因此频繁运行没有成本。只有真正的变化才会产生工作。

上传过程中的瞬态服务器错误(HTTP 5xx)会以指数退避策略重试最多三次。上传默认按顺序进行;通过 --concurrency N(或在每个条目中设置 concurrency:)可使 N 个文件并行上传,适用于大型同步。

相同的服务端行为以及暴露给您自定义脚本的同样两个端点,记录在知识 → 同步本地目录知识 → API 访问中。oikb 是实现完整循环并在其上添加了计划任务、Webhook 和 44 种连接器的官方维护客户端。


数据源与连接器

数据源是本地路径或 scheme:target 字符串。oikb 将 scheme 解析为对应的连接器,拉取文件并同步到知识库。凭据永远不会被写入数据源字符串或 .oikb.yaml;每个连接器都从环境变量中读取凭据,因此机密信息不会出现在您的配置中(配合 ${VAR} 插值 可让配置文件能够提交到版本控制)。

下表中,[方括号] 标记数据源字符串中的可选部分。

分组连接器数据源字符串凭据(环境变量)
本地本地目录./path(任意文件系统路径)
代码GitHubgithub:owner/repoGITHUB_TOKEN(私有仓库)
GitLabgitlab:owner/repoGITLAB_TOKENGITLAB_URL(自建实例)
Bitbucketbitbucket:owner/repoBITBUCKET_USERBITBUCKET_APP_PASSWORD
云存储Amazon S3s3://bucket/prefix标准 AWS 凭据链(boto3)
Google Cloud Storagegs://bucket/prefixGOOGLE_APPLICATION_CREDENTIALS
Azure Blobaz://container/prefixAZURE_STORAGE_CONNECTION_STRING
Cloudflare R2r2://bucket/prefixR2_ACCOUNT_IDR2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEY
Oracle Cloudoci://bucket/prefixOCI_NAMESPACE + OCI SDK 配置
Dropboxdropbox:/pathDROPBOX_TOKEN
Google Drivegdrive:folder_idGOOGLE_APPLICATION_CREDENTIALS
SharePointsharepoint:site[/library]SHAREPOINT_TENANT_IDSHAREPOINT_CLIENT_IDSHAREPOINT_CLIENT_SECRET SHAREPOINT_CERTIFICATE_PATH
Egnyteegnyte:/pathEGNYTE_DOMAINEGNYTE_TOKEN
Wiki 与知识库Confluenceconfluence:SPACECONFLUENCE_URLCONFLUENCE_USERCONFLUENCE_TOKEN
Notionnotion:root_idNOTION_TOKEN
BookStackbookstack:BOOKSTACK_URLBOOKSTACK_TOKEN_IDBOOKSTACK_TOKEN_SECRET
Discoursediscourse:[category]DISCOURSE_URLDISCOURSE_API_KEYDISCOURSE_API_USERNAME
GitBookgitbook:space_idGITBOOK_TOKEN
Guruguru:[collection]GURU_USERGURU_TOKEN
Outlineoutline:[collection]OUTLINE_URLOUTLINE_TOKEN
Slabslab:[org]SLAB_ORGSLAB_TOKEN
Document360document360:project_idDOCUMENT360_TOKEN
DokuWikidokuwiki:[namespace]DOKUWIKI_URLDOKUWIKI_USERDOKUWIKI_PASSWORD
Google Sitesgsites:site_idGOOGLE_SITES_TOKEN
工单系统Jirajira:PROJECTJIRA_URLJIRA_USERJIRA_TOKEN
Linearlinear:team_keyLINEAR_TOKEN
Zendeskzendesk:[subdomain]ZENDESK_SUBDOMAINZENDESK_USERZENDESK_TOKEN
Freshdeskfreshdesk:[domain]FRESHDESK_DOMAINFRESHDESK_TOKEN
Asanaasana:project_idASANA_TOKEN
ClickUpclickup:space_idCLICKUP_TOKEN
Airtableairtable:base_id[/table]AIRTABLE_TOKEN
ServiceNowservicenow:[table]SERVICENOW_INSTANCESERVICENOW_USERSERVICENOW_PASSWORD
ProductBoardproductboard:PRODUCTBOARD_TOKEN
即时通讯Slackslack:channel_idSLACK_TOKEN
Discorddiscord:channel_idDISCORD_TOKEN
Microsoft Teamsteams:team_id/channel_idTEAMS_TENANT_IDTEAMS_CLIENT_IDTEAMS_CLIENT_SECRET
Gmailgmail:user@example.comGOOGLE_APPLICATION_CREDENTIALS
Zulipzulip:[stream]ZULIP_URLZULIP_EMAILZULIP_KEY
会议Gonggong:GONG_ACCESS_KEYGONG_ACCESS_KEY_SECRET
Firefliesfireflies:FIREFLIES_TOKEN
销售与 CRMSalesforcesalesforce:SALESFORCE_URLSALESFORCE_TOKEN
HubSpothubspot:HUBSPOT_TOKEN
论坛XenForoxenforo:[forum_id]XENFORO_URLXENFORO_KEY
Web网站 / sitemapweb:https://example.com

一些值得了解的连接器注意事项:

  • GitHub 通过 Trees API 读取数据,因此无需本地克隆。添加 --branch--path(或在配置中 branch: / path:)来指定分支或子目录。
  • 聊天连接器(Slack、Discord、Teams)按天拆分历史记录,因此同步是真正的增量:过去的日子是不可变的,其校验和永远不会变化,永远不会被重新上传。
  • JiraServiceNow 接受数据源字符串中的额外选项(查询、字段、输出格式、结果限制),例如 servicenow:incident?query=...&limit=500。每个连接器的完整选项请参见 oikb 仓库

过滤同步内容

使用 include/exclude glob 和大小限制来缩小数据源范围。这些配置位于 .oikb.yaml 中的 filter: 下:

sources:
  - name: docs
    source: github:owner/repo
    kb-id: your-kb-id
    filter:
      include: ["docs/**/*.md", "*.txt"]   # 仅同步这些
      exclude: ["drafts/**", "**/*.tmp"]   # 排除这些(在 include 之后应用)
      max-size: 50mb                        # 跳过超过此大小的文件

max-size 接受 bkbmbgb。超限文件会在差量比对前被警告并跳过,因此不会被上传。它也可以作为 CLI 参数使用:oikb sync ./docs --kb-id abc --max-file-size 50mb

要将同一数据源的不同部分路由到不同的知识库,请使用具有不同 filter.includekb-id 的单独条目:

sources:
  - name: user-docs
    source: github:owner/repo
    kb-id: abc123
    filter: { include: ["docs/**"] }
  - name: api-reference
    source: github:owner/repo
    kb-id: def456
    filter: { include: ["api/**"] }

跳过的文件与 .oikbignore

同步本地目录时,oikb 始终跳过隐藏条目(任何以 . 开头的项)以及内置列表:.git.svn.hg.DS_StoreThumbs.db__pycache__.pytest_cachenode_modules.oikb.env

对于项目特定的排除项,请在同步根目录中放置 .oikbignore 文件。它使用 gitignore 风格的 glob(末尾的 / 仅匹配目录,开头的 / 锚定到根目录)。暂不支持 ! 取反语法。


监听模式

对于正在主动编辑的本地文件夹,watch 会在文件变化的瞬间重新同步:

oikb watch ./docs --kb-id your-kb-id

它使用文件系统事件(而非轮询),去抖时间为 1 秒(可通过 --debounce 调整),并持续运行直到您使用 Ctrl+C 停止。适合实时笔记文件夹;对于远程或无人值守的场景,请改用守护进程


CI 中的一次性同步

Docker 镜像作为一次性命令运行,可作为开箱即用的 GitHub Actions 步骤,在每次合并时将文档推送到知识库:

- name: Sync docs to Open WebUI
  uses: docker://ghcr.io/open-webui/oikb:latest
  with:
    args: sync /github/workspace/docs --kb-id ${{ secrets.KB_ID }}
  env:
    OPEN_WEBUI_URL: ${{ secrets.OPEN_WEBUI_URL }}
    OPEN_WEBUI_API_KEY: ${{ secrets.OPEN_WEBUI_API_KEY }}

CLI 参考

命令功能
oikb sync <source>从数据源增量同步到知识库(--kb-id)。省略 <source> 可同步 .oikb.yaml 中的所有条目。
oikb sync --dry-run预览新增/修改/删除的内容,不实际上传。
oikb sync --concurrency N并行上传 N 个文件(默认 1,顺序执行)。
oikb sync --max-file-size 50mb跳过超过指定大小的文件。
oikb sync --name <alias>.oikb.yaml 模式下,仅同步匹配的条目。
oikb diff <source> --kb-id ID预览更改(sync --dry-run 的别名)。
oikb watch <dir> --kb-id ID本地目录变化时自动同步(--debounce)。
oikb init生成 .oikb.yaml 的交互式向导。
oikb validate检查 .oikb.yaml 语法。添加 --deep 还会 ping Open WebUI、验证 API 密钥并确认每个知识库存在。
oikb daemon运行带 HTTP API 的计划任务守护进程
oikb ls --kb-id ID列出知识库中的文件。
oikb status --kb-id ID显示知识库的名称、文件数和总大小。
oikb history查看同步历史(--json--errors--kb-id--clear --days N)。
oikb reset --kb-id ID删除知识库中的所有文件(--keep-directories 保留目录结构)。会提示确认。
oikb config set url|token <value>保存 Open WebUI URL 或 API 密钥。oikb config get 显示它们。

在任何命令上添加 -q / --quiet 可抑制非错误输出(脚本中很有用),添加 -v / --verbose 可获得每个文件的详细信息。

oikb reset 会删除知识库中的所有内容

reset 会删除目标知识库中的每个文件,而不仅仅是 oikb 上传的文件。它是唯一具有破坏性的命令。确认提示的存在是有原因的。


使用场景

始终保持最新的产品文档

将您的文档仓库(github:acme/docs)接入到知识库,并在 CI 中每次合并时同步,或通过 Webhook 触发。支持代理和客户查询的文档永远不会比最新一次提交晚一步。

大型个人或家庭文档库

数千个混合文档(PDF、Markdown、扫描件、记录)集中在一个组织良好的文件夹中。将 oikb 指向文档库顶部,它会同步整个目录树,包括所有子目录,到一个统一的知识库,让家庭成员无需知道哪个子文件夹包含答案即可提问。应用内同步在如此大的规模下会吃力;oikb 正是为这种规模而生。

来自 Wiki 的公司手册

将 Confluence 空间或 Notion 工作区镜像到知识库,按早晨的 cron 执行。一个"询问 HR"模型根据当前手册回答问题,Wiki 中的编辑会在第二天显示出来,无需任何人重新上传。

来自工单的支持知识

将已解决的 Zendesk 或 Jira 工单同步到知识库,使分类模型可以基于您自己的历史(而非通用训练数据)找出类似问题之前是如何处理的。

代码感知助手

通过过滤器将一个仓库拆分到两个知识库:docs/** 下的散文进入"Docs"知识库,src/** 下的源代码进入"Code"知识库。根据需要将适合的知识库附加到模型,两者都从单个配置保持同步。


限制

需要 Open WebUI 0.9.6+

增量同步端点在 v0.9.6 中加入。面对更早版本的服务器,oikb 没有可调用的端点。

守护进程以单一进程运行

调度和每个知识库的锁位于单个进程中,因此守护进程应以单一副本运行。要支持更多数据源,请向单个守护进程添加条目,而非运行多个副本。

索引仍在服务端进行

oikb 上传很快,但 Open WebUI 异步提取和嵌入每个新文件。刚刚同步的文件已在知识库中,但可能需要片刻才可被查询。


故障排除

Connection refused401 Unauthorized:URL 或密钥错误或未设置。通过 oikb config get 检查,或运行 echo $OPEN_WEBUI_URLecho $OPEN_WEBUI_API_KEY。密钥必须是有效的 Open WebUI API 密钥(设置 → 账户)。

No source specified and no .oikb.yaml found:您在没有数据源的情况下运行了 oikb sync,且当前目录下没有 .oikb.yaml。请提供数据源(oikb sync ./docs --kb-id ...)或使用 oikb init 创建配置。

大型同步缓慢:添加 --concurrency 4 进行并行上传,设置 filter.max-size 跳过大型二进制文件,并使用 filter.exclude 排除模型不需要的内容。

守护进程无法启动 / 知识库似乎缺失:运行 oikb validate --deep。它会验证服务器是否可访问、API 密钥是否有效,以及配置中的每个 kb-id 是否实际存在。

我的知识库 ID 在哪里? 在工作区中打开知识库;UUID 是 URL 的最后一段路径,.../knowledge/<kb-id>


另请参阅

本内容仅供参考,不构成任何保证、担保或合同承诺。Open WebUI 按“现状”提供。请参阅您的许可协议 以了解适用条款。