1. WeKnora 到底是什么:先从标题里的三个关键词说起
标题里写着「RAG + Agent + Wiki 三合一」,这个定位很值得拆开看。市面上叫得上名的开源知识库项目不少,比如 RAGFlow、Dify、MaxKB,但用 Go 写、又把 Agent 和 Wiki 直接揉进内核的,WeKnora 是其中一个辨识度很高的选手。它出自腾讯,服务端核心全部用 Go 实现,这意味着从内存占用、并发处理到编译产物,它都带着典型的 Go 工程气质——单个二进制跑起来不依赖一堆运行时,部署压力比 Python 系项目小一个量级。
WeKnora 解决的核心问题,其实是企业知识管理里那个老生常谈的断头路:文档归文档、对话归对话、知识库归知识库。传统做法是拿 RAG 框架做问答,再把问答记录同步到 Wiki,顺便在另一个系统里挂几个 Agent 流程,三个系统之间数据口径不一致,维护成本极高。WeKnora 把这三种能力收敛到一个进程里,以本体 RAG(Ontology RAG)为骨架,把实体、概念、文档之间的关联关系做成可查询的知识图谱,再把 Agent 当作执行层去触发检索、摘要和问答动作。对于正在做企业级 AI 落地、又不希望往基础设施里堆五六个开源组件的团队来说,它是值得花半天时间跑一遍实物再判断要不要进生产环境的项目。
这篇就把三合一的架构设计、Go 选型的理由、本地部署的完整路径、以及我实测过程中踩过的坑一并写出来。涉及 WeKnora 部署、配置和常见报错定位的部分,都是有明确操作对象的内容,不是泛泛谈架构。
2. 整体设计与思路拆解:为什么是 Go、为什么把 RAG 做成本体驱动的
2.1 核心技术点视角:Weka 与知识图谱的边界
先说本体 RAG 这个名字。普通 RAG 做法是 "query -> embedding -> topK 向量 -> 拼 prompt",本质上是在向量空间里做模糊匹配,它不关心两段文本之间的语义关系到底属于同义替换、上下位还是因果。WeKnora 引入本体层之后,文档里的实体会被抽出来,实体与实体之间的关系也会被建索引。检索时先去图谱里定位候选实体,再用这些实体的关联文档做答案召回,这种检索方式在「多跳问题」上的表现明显优于纯向量召回。
一个典型场景:员工问"A 产品线的故障率跟 B 团队的交付节奏有没有关系",纯向量检索会把两个独立文档分别召回,但本体 RAG 会先在图谱里找到「产品线 A -> 关联团队 B -> 关联指标故障率」这条路径,再精准召回路径上的文档片段。对于企业知识库这种数据天然带关系的场景,这种设计确实更贴合真实业务。代价是离线阶段多了一步本体抽取的耗时,但推理阶段并没有显著变慢,这是值得做的取舍。
2.2 为什么选 Go:从部署成本到并发模型
用 Go 写 AI 应用框架,在 2025 年的开源生态里已经不是新鲜事。Go 的优势集中在三个层面:第一,编译产物是单一原生二进制,配合 Docker 镜像可以做到 100MB 以内,启动时间秒级;第二,Goroutine 在知识库高频检索、多文档并发解析、多路 Agent 调用并发执行时,资源开销比 Java 线程小得多,且内存可预见性好,不会像 Python 那样动不动涨到几个 GB;第三,Go 的静态类型在 Wiki、权限、文档状态管理这类业务逻辑层减少了隐性 bug,大型项目维护起来更省心。
WeKnora 在这种选型下得到了一个非常实在的好处:整体资源占用明显低于同量级的 Python 项目。同规格机器上跑 RAGFlow 需要 8GB 内存起步是正常,WeKnora 在本地做小规模知识库测试时可以压低到 2GB 不到。对于想要私有化部署在低成本服务器上的中小团队,这个差距直接决定了项目能不能落地。
2.3 三合一设计:RAG、Agent、Wiki 如何共享同一套数据
三合一最容易做成一锅粥,WeKnora 的做法是分层共享。底层是统一的存储层,文档、向量、图谱、Wiki 页面、对话历史全在同一个数据库体系里;中间层是服务层,RAG 模块负责索引和检索,Agent 模块负责流程编排和工具调用,Wiki 模块负责知识的结构化沉淀;最上层是 API 层,对外暴露 REST 接口。
关键细节在于 Wiki 和 RAG 的联动:Wiki 里的每一次修订,会触发对应文档的重新切分和向量更新,也就是说知识库不是一次性快照,而是跟随 Wiki 持续演进的活体数据。Agent 调用的工具集里也内置了 Wiki 查询能力,Agent 的每次回答结果可以反向写入 Wiki 页面。这套联动逻辑在别的项目里往往要自己写胶水代码,而 WeKnora 内建了,省去不少集成成本。
3. 核心功能拆解:RAG 模块的完整工作流
3.1 加载、切分、向量化:从原始文件到高密度索引
先从数据导入说起。WeKnora 支持的文件格式覆盖常见企业场景:PDF、DOCX、Markdown、TXT、HTML,以及带链接抓取规则的网页。进入它内部后,一套标准 RAG 管线立即启动:
- 文件解析:按文档类型分发到不同解析器,PDF 走文本提取,带扫描件时会走 OCR(需要额外配置本地 OCR 服务);
- 文本切分:默认块大小和重叠参数可按知识库粒度覆盖配置;
- 向量化:接入指定 Embedding 模型,把每个切片转成向量并写入向量库;
- 双层索引写入:同时写入倒排索引(用于 BM25 稀疏检索)和向量索引(用于稠密检索);
- 本体抽取:在后台异步进行实体识别、关系构建,形成图谱数据。
我实测时发现切分参数对最终效果影响最大。默认按 Token 切分出的块在代码类文档上很吃亏,经常把一个函数定义和它的调用注释拆进两个块里。建议针对纯文本类和代码类分别建知识库,代码类目录把块大小下调到 300 到 400 Token、重叠控制在 50 左右,纯文档类用 500 Token 加 80 重叠,命中率会明显改善。
3.2 检索与重排:混合检索 + 权重调优
检索阶段 WeKnora 默认执行混合检索:向量召回 + BM25 关键词召回,再用 RRF(倒数排名融合)合并排序。这个方案的实用价值在于:向量对同义词友好,关键词对生僻词、型号、编号友好,两者取交集后再排序,比单走一路稳得多。
不过混合检索默认权重不一定适配你的数据分布。如果你的文档以规范、制度、流程为主,专业术语频繁出现但变化不大,建议把关键词召回权重调高一些。如果文档是偏描述性的技术文章、FAQ,向量贡献更关键。在配置里调整两个召回通道的 topK 数值即可,不需要改代码。
重排环节可选接入一个 BGE-Reranker 之类的模型,效果提升明显,但推理耗时增加也明显。建议先不加重排跑一阵子,确认准确率不够再考虑。从资源角度说,本地 8GB 显存或 16GB 内存机器不建议开重排,很吃资源。
3.3 本体 RAG 在 WeKnora 中的落地方式
提到本体 RAG 就得多说两句落地细节。WeKnora 的图谱不在你导入文档那一刻立即构建,而是由一种「知识抽取任务」的形式在后台异步执行。系统会从库里选定一批文档,调用配置好的 LLM,把文档中涉及的组织、项目、指标、系统、负责人这类实体,以及它们之间的关系,用一套 JSON Schema 抽出来,存入图谱库。
这套设计的代价是知识抽取的准确性高度依赖模型能力。我用通义千问跑出来的本体,比用本地小模型跑出来的好用很多。如果你部署时打算用 Ollama 的 7B / 14B 模型,建议关掉本体抽取功能,或者手动指定一个推理能力更强的模型来完成抽取和最终生成。否则图谱里全是错漏关系,检索反而被带偏。
注意:本体抽取不是实时动作,新文档导入后要等异步任务跑完,知识库里的图谱才会更新。想加速可以把抽取任务并发数调大,但会占用更多 CPU 和内存。
4. 实操过程:本地部署 WeKnora 并跑通第一个知识库问答
4.1 前置准备与 Windows / macOS / Linux 环境要求
我分别在 Windows 11 和 Linux 服务器上各跑了一轮,给两个典型场景的配置参考。WeKnora 依赖 macOS 或 Linux 环境相对更好跑,Windows 11 需要 Docker Desktop,关于 Windows 下安装的细节后面单讲(常见问题部分)。
最省心的方式是走 Docker Compose。推荐规格是一台至少 4C16G 的机器。本地测试如果只导少量文档,可以降到 4C8G,但要密切关注是否出现 OOM。
本机部署前需要准备:
- Docker 与 Docker Compose(Windows 上注意将 Docker Desktop 的 WSL 2 后端开启)
- 一个 Embedding 模型接口(OpenAI 兼容格式即可)
- 一个 LLM 接口(OpenAI 兼容 / 各类厂商接入均可)
- 可选:BGE-Reranker 地址
- 可选:If 用本地模型,装好 Ollama 并拉取模型
4.2 Docker Compose 部署步骤
安装命令以 Linux 服务器为例。先克隆仓库:
git clone https://github.com/tencent/weknora.git cd weknora cp docker-compose.yml docker-compose.local.yml修改 docker-compose.local.yml 里的资源限制。默认配置是按生产环境给的,本地跑建议调低:
services: server: mem_limit: 2g cpus: 2 worker: mem_limit: 2g cpus: 2 postgres: mem_limit: 1g然后一键拉起:
docker compose -f docker-compose.local.yml up -d首次启动会拉几个镜像,包括 Go 编译产物和服务端镜像,国内网络情况请做好镜像加速配置,不然拉取时间会非常痛苦。启动后访问 http://localhost:8080 可以看到 Web 控制台。默认账号密码在环境变量里配置,我建议立刻改成强密码。
4.3 配置接入自定义模型
进入控制台后,第一件事是配置模型供应商。WeKnora 走的是 OpenAI 兼容接口,如果你本机有 Ollama,直接填本地地址:
OLLAMA_BASE_URL=http://host.docker.internal:11434 OLLAMA_MODEL=llama3.1:8b如果在容器内访问宿主机 Ollama,注意要使用 host.docker.internal 而不是 localhost。
Embedding 模型建议选择本地小模型:
EMBEDDING_MODEL=bge-m3 EMBEDDING_BASE_URL=http://host.docker.internal:11434保存后先建一个知识库。建库时可以选「标准模式」和「本体模式」。如果你的业务场景是 FAQ、制度手册这种结构松散的文档集合,选标准模式节省算力。如果涉及跨文档关联查询,选本体模式,但要确保你配置的 LLM 足够强。
4.4 导入第一批知识库文档
知识库里把项目文档传进去。传完后观察切分任务状态,切片完成后立刻可以做一轮检索测试,看看默认配置下效果如何。我传了一套约 20 篇产品文档后,标准模式下大概 5 分钟完成所有索引。知识抽取任务则多跑了近 15 分钟才结束。
Docs 上传后的「解析失败」不要急着找模型问题,最常见的原因是源文件名中带有特殊字符或非法编码。具体排查见下一节。
5. 常见问题与排查技巧实录:我踩过的那些坑
5.1 文档解析失败原因定位
最近网上经常有人提到 WeKnora 解析失败,我在本地也碰到过,核心原因大类有下面几种:
- 文件名编码问题:Windows 上传的中文名文件若文件名含全角括号或尾部空格,解析器可能无法正确写入存储。解决方式是上传前规范化文件名,只保留字母数字、下划线、横线;
- PDF 扫描件缺 OCR:文本型 PDF 能正常解析,图片型 PDF 必须要 OCR 组件参与。本地默认环境没有 OCR 引擎时报错信息并不明显,建议直接看 worker 日志;
- 特殊表格结构:复杂合并单元格的 DOCX 转文本后信息丢失,但不是失败,只是切分异常,体现在检索不中段落,很隐蔽。
- 文件大小超限:默认单个文件 10MB / 50MB 的限制可调,超过后任务会被丢弃且控制台不一定有明确提示。
排查思路:先看 worker 容器日志,搜索 "failed" 或者任务 ID,看是解析器报错还是后续管线报错,然后按上面分类去对号入座。
5.2 Agent 并发扛不住:问题不在 WeKnora 而在模型接口
很多人关注「AI Agent 怎么扛并发」。在原版部署中,Agent 执行环节非常容易成为瓶颈,因为 Agent 编排逻辑是串行的:先想计划,再调检索工具,再生成文本,每一跳都要等模型接口返回,而且单轮回答经常会有两三次的模型调用。
我在压测环境里试过把并发用户数抬到 20,结果发现 WeKnora 进程本身很稳,Goroutine 调度没有出现明显阻塞。真正的瓶颈在 LLM 接口的 TPS 限制上。本地跑 Ollama 时单卡同时推理任务一多就排队,远程 API 则直接触发限流。
所以如果你要给团队用,与其调优 WeKnora 服务端,不如先解决模型推理并发:本地部署用 vLLM 这类加吞吐的方案,远程 API 则要多配几个 key 做负载均衡。这个结论同样适用于 Dify、RAGFlow 等一票 RAG 项目——扛并发的是模型服务,不是编排框架。
5.3 Windows 11 安装部署中的特殊坑
Windows 11 Docker Desktop 跑 WeKnora 有别的坑。首先是 Docker Desktop 的 WSL 后端内存分配问题,默认给 WSL 的内存可能只有 4GB,跑 WeKnora 全家桶非常紧张。建议在.wslconfig里限制并加大内存,至少给 6GB 以上。
第二个坑是端口占用。Windows 上 8080 常常被其他程序占用,启动后页面打不开,检查一下把 compose 文件里的左侧端口号换成 18080 之类的空闲端口再映射。第三个坑是文件路径大小写不敏感带来的挂载问题,Windows 挂载目录给容器内写中文文件名时也可能出乱码,建议尽量在 Linux 或 macOS 环境下部署,Windows 下做简单体验即可。
5.4 WeKnora 和 Obsidian / Dify / RAGFlow 怎么选
问这两者关系的人不少,其实这压根不是同一层的东西。Obsidian 是本地 Markdown 笔记工具,WeKnora 是服务端知识管理框架,两者可以选择「联动」而不是「二选一」:笔记内容通过 Git 同步或手工导入 WeKnora 做成可对话知识库。我在本地试过用 Obsidian 作为语料编辑端,WeKnora 作为服务端问答引擎,效果意外顺滑,本地 Markdown 文件直接批量复制进数据目录即可入库。
和 Dify、RAGFlow 的对比可以列个表:
| 项目 | 语言栈 | 本体 RAG | Wiki 协同 | Agent 工作流 | 轻量化部署 |
|---|---|---|---|---|---|
| WeKnora | Go | 内置 | 内置 | 内置 | 较强 |
| Dify | Python/TS | 需插件 | 弱 | 强 | 中 |
| RAGFlow | Python | 部分支持 | 弱 | 弱 | 较差 |
| MaxKB | Python | 无 | 无 | 无 | 强 |
Dify 更偏 Agent 流程的可视化编排,适合业务人员快速搭前端流程;WeKnora 更偏知识库底座的完整性,它的强项是企业内部知识的结构化管理和跨文档关联检索,而不是做复杂的低代码 Agent 编辑器。如果你既要 Agent 编排又要知识管理,WeKnora 的总体集成度会高一些,但如果你习惯 Dify 的界面和插件生态,迁移学习成本需要考虑进去。
5.5 参数调优心得:检索质量上不去时先调这几处
实测下来,影响最明显的三处参数在config.yaml:
retrieval.top_k:默认可能只有几,加大到 20 到 30 可以显著提升召回率,然后再靠重排或相关性过滤挤压精准度;chunk_size:默认值在长文档上容易出现信息截断,建议看文档类型动态调整;llm.temperature:知识库问答建议 0.1 到 0.3 之间,用太高容易出现幻觉。
还有一点不太容易察觉:Embedding 模型名称填错了不一定立即报错,而是索引写入成功但查询时维度不匹配,报错之后再去查已经很费时间。建议在配置完 Embedding 后先建一个空知识库,跑一条测试查询确认无报错,再批量导数据。
6. 最后再分享一点个人的实践体会
把 WeKnora 完整跑通之后,我最大的感受是「Go 写 AI 基础设施」这条路线确实有它的合理性。我见过太多 Python 知识库项目,功能没跑起来先被环境依赖折磨,而 WeKnora 从 clone 到跑通第一个问答,花的时间不到 Dify 那种全家桶体系的一半。这背后其实是企业级软件的一个朴素真理:能快速部署、稳定运行、资源可控,往往比功能列表华丽更重要。
如果团队已经在用 Wiki 类的知识库工具,WeKnora 里内置 Wiki 协同的存在感会越来越强。你可以用它的页面编辑功能维护一套内部技术规范,Agent 问答直接引用这套规范作答,员工收到的回答天然带引用来源。相比传统"问答系统 + 文档站"双轨制,这种模式下的知识沉淀是连续的,每一次对话、每一次修订都会回流到索引里。对做内部知识管理的人来说,这个方向值得持续关注。
如果你正在评估下一代的团队知识库方案,别只盯着一堆 Python 生态。花一个下午,用 Docker 把 WeKnora 拉起来,传一批真实文档进去跑跑检索,再用你自己的问题集对比一下 Dify 和 RAGFlow 的效果。工具可以慢慢磨合,但架构方向选对了,后面优化起来才不会束手束脚。