跳到主要内容

WeKnora 架构全景:Go 与 Python 双引擎的企业级 RAG 框架

· 阅读需 9 分钟
一介布衣
全栈开发者

最近想找一个工程完成度足够高、又能拿来学 RAG 全链路的开源项目,翻了一圈最后停在腾讯开源的 WeKnora 上。它是 MIT 协议、当前版本 v0.8.2,把「文档理解 + 语义检索 + 自主推理」做成了一套可自托管的框架,代码结构比大多数 demo 级的 RAG 仓库认真得多。

我打算用一个系列把它拆开讲。这是第一篇,先建立整体认知:它分成哪几层、为什么主后端用 Go 而文档解析单独拎出一个 Python 服务、一条文档从上传到能被检索中间到底发生了什么。后面三篇分别深入分片机制、检索管线和 Agent 能力。

WeKnora 到底是个什么东西​

一句话概括:把散落的文档变成可查询、能推理、会持续演进的知识资产。它围绕三个核心能力组织:

  • RAG Quick Q&A:日常问答,走标准的检索增强生成管线,快而准。
  • ReAct Agent:自主编排知识检索、MCP 工具、租户技能目录、会话级持久化沙箱(Docker / E2B / Cube)、用户自己的浏览器(BrowserSkill)和网络搜索,处理复杂多步任务。
  • Wiki Mode:让 Agent 把原始文档蒸馏成一个自维护、互相链接的 Markdown 知识库,还带交互式知识图谱、手工编辑、修订历史和一键回滚。

除了这三条主线,它还塞进了跨会话长期记忆、树形文件夹视图、chunk 级编辑与修订历史、多数据源接入(飞书 / Confluence / GitLab / Notion / 语雀 / 钉钉文档 / RSS)、内置 MCP Server、多工作区 RBAC 等企业级特性。支持的文档格式有 PDF、Word、Excel、图片、EPUB、MHTML、XMind 等十余种,模型侧兼容 OpenAI、DeepSeek、Qwen、Zhipu、Hunyuan、Gemini、Ollama 等主流厂商。

功能清单很长,但对想学架构的人来说,真正值钱的是它把这些能力拆成了一条每个环节都可替换的流水线。

分层视角:一条文档的旅程​

WeKnora 的 README 里那句「Fully modular pipeline from document parsing, vectorization, and retrieval to LLM inference — every component is swappable」是理解它的钥匙。我把整个系统按数据流分成六层:

层职责关键代码位置
① 接入层多数据源同步、多格式上传internal/datasource/
② 解析层文档转 Markdown,扫描页走 OCR/VLMPython docreader/ + Go internal/infrastructure/docparser/
③ 分片层把长文切成检索单元Go internal/infrastructure/chunker/
④ 索引层向量化 + BM25 + 图谱抽取internal/application/service/knowledge_process.go
⑤ 检索层混合检索、重排、MMR、合并internal/application/service/chat_pipeline/
⑥ 推理层RAG 问答 / ReAct Agent / Wikiinternal/application/service/ + internal/agent/

横向还有一条平台层贯穿始终:8 种向量库、27 家模型厂商、多种对象存储、多工作区 RBAC、Langfuse 可观测、任务队列治理。这种「纵向数据流 + 横向可插拔基座」的组织方式,是它区别于玩具项目的地方。

flowchart LR
subgraph Ingest["① 接入层"]
DS["数据源/上传<br/>飞书·Confluence·GitLab·PDF·Word"]
end
subgraph Parse["② 解析层"]
DR["Python docreader<br/>(gRPC sidecar)"]
DP["Go docparser<br/>引擎路由"]
end
subgraph Chunk["③ 分片层"]
CK["Go chunker<br/>自适应三层分片"]
end
subgraph Index["④ 索引层"]
EM["Embedding"]
VS["向量库 + BM25"]
GR["图谱抽取"]
end
subgraph Retrieve["⑤ 检索层"]
PP["chat_pipeline<br/>12 阶段管线"]
end
subgraph Reason["⑥ 推理层"]
RAG["RAG Q&A"]
AG["ReAct Agent"]
WK["Wiki Mode"]
end
DS --> DP --> DR --> CK --> EM --> VS --> PP
CK --> GR --> PP
PP --> RAG & AG & WK

最特别的设计:Go 主后端 + Python 解析 sidecar​

第一次看 WeKnora 的目录,最容易困惑的是它同时有大量的 Go 代码(internal/、cmd/)和一个独立的 Python 项目(docreader/)。这不是历史包袱,而是一个刻意的双语言微服务设计。

分工是这样的:

  • Go app:主后端。对外提供 HTTP/REST API,承载分片、索引、检索、Agent 编排、多租户、任务队列这些工程密集、并发敏感的核心逻辑。它同时是文档解析的 gRPC 客户端。
  • Python docreader:文档解析 sidecar。它是一个 gRPC 服务端,默认监听 50051 端口,专门干一件事——把各种格式的文档(尤其是 PDF、Office、图片)解析成结构化文本。

两者通过 gRPC 通信,契约定义在 docreader/proto/docreader.proto:

service DocReader {
rpc Read (ReadFromFileRequest) returns (ReadResponse); // 一元调用
rpc ReadStream (ReadFromFileRequest) returns (stream ReadResponse); // 大 PDF 流式返回
rpc ListEngines (ListEnginesRequest) returns (ListEnginesResponse);
}

Go 侧通过环境变量 DOCREADER_ADDR(默认 docreader:50051)找到它,DOCREADER_TRANSPORT 默认 grpc(也可切 http)。生产环境里,这两个服务由 docker-compose 编排成两个独立容器。

为什么不干脆全用 Go?​

这是我看代码时最想搞清楚的问题。答案藏在文档解析这件事的特殊性里:

  1. Python 的文档解析生态无可替代。PDF 版面分析、OCR、公式识别、表格结构还原这些领域,最好用的库(PyMuPDF、各类 OCR/VLM 管线)几乎都在 Python 生态里。用 Go 重写等于跟整个生态作对。
  2. 进程隔离带来稳定性。文档解析是出了名的容易崩——畸形 PDF、超大文件、解析库 segfault。把它关进独立进程,崩了也只影响一个解析任务,不会拖垮承载所有 API 和检索的主后端。
  3. 资源特征不同。解析是 CPU/内存密集、突发性的;主后端是 IO 密集、需要高并发低延迟。分开部署后可以独立扩缩容——解析队列堆积时只加 docreader 实例即可。

Go 负责「稳、快、并发」,Python 负责「解析能力强」,gRPC 是它们之间清晰的边界。这是一个非常典型的 polyglot 微服务权衡:用一点跨进程通信的复杂度,换来两边各自用最合适的语言。

关于「双引擎」的一个常见误解​

需要澄清的是,这里的通信是单向的:永远是 Go 主动调用 Python,Python 不会反向调 Go。docreader 是一个纯粹的、无状态的解析服务。

另外,两个容器不一定要在同一台机器上。跨物理机部署时,它们靠的是普通的 TCP/IP 网络(gRPC over HTTP/2),而不是 Docker 本身的什么魔法——docker-compose 只是把它们放在同一个网络里让服务名可以互相解析。真要跨机,把 DOCREADER_ADDR 指到远端 IP 即可。安全上要注意:默认配置下这条 gRPC 链路是不带 TLS 的,跨公网部署需要额外开启(v0.6.0 起支持 docreader gRPC TLS + Token)。

八种解析引擎:一个路由问题​

docreader 并不是唯一的解析路径。Go 侧的 internal/infrastructure/docparser/engines.go 定义了一个引擎路由,把不同文件类型分发给最合适的解析器:

引擎实现适用
builtinPython docreader 解析套件主力,能逐页分类,把扫描页路由到 OCR/VLM
simpleGo 原生md / txt / csv / json / 图片等简单格式
anydocGo 进程内Office 文档转换(不含 PDF)
mineru / mineru_cloud远程 APIMinerU 高精度解析
paddleocr_vl / paddleocr_vl_cloud远程 APIPaddleOCR-VL
weknoracloud远程 APIWeKnora 云托管解析

有个细节很能说明设计考量:PDF 被排除在 anydoc 之外。源码注释解释,因为 builtin 引擎能对 PDF 逐页分类,把扫描页单独路由到 OCR 或 VLM,而 anydoc 做不到这种页级智能。而且注释里明确写着「docreader itself never runs OCR」——真正的 OCR 决策在 Go 侧完成,docreader 只负责按指令解析。

可插拔的基座​

纵向流水线之外,横向基座的可替换性是 WeKnora 的另一个卖点:

  • 向量库:PostgreSQL(pgvector) / Elasticsearch / OpenSearch / Milvus / Weaviate / Qdrant / Apache Doris / 腾讯向量库,通过统一的 RetrieveEngine 接口抽象(internal/types/interfaces/retriever.go)。
  • 模型:Chat / Embedding / Rerank / VLM / ASR 五类,27 家内置厂商,声明式 YAML 配置,支持按知识库选模型、按模型配 thinking-mode 和 embedding 维度。
  • 对象存储:本地 / MinIO / AWS S3 / 火山 TOS / 阿里 OSS / 金山 KS3 / 华为 OBS,支持一个工作区挂多个存储实例、按知识库绑定。

这些替换都通过接口 + 注册表模式完成,加一个新向量库不需要动检索管线的代码。这种「面向接口 + 注册表」的组织方式贯穿整个 internal/,是它能同时支持这么多后端而不失控的根本原因。

小结​

WeKnora 给人的第一印象是功能多,但真正值得学的是它用分层和接口把复杂度关进了笼子:

  • 纵向按数据流分六层,每层职责单一;
  • 横向用接口 + 注册表让向量库、模型、存储都可插拔;
  • 最重的文档解析单独拆成 Python sidecar,用 gRPC 划出清晰边界,兼顾生态能力和主后端稳定性。

这一篇建立的是地图。接下来三篇会分别钻进地图里最硬核的三个区域:自适应分片机制(RAG 质量的地基)、12 阶段检索管线(召回与重排的编排)、以及 ReAct Agent 与三大能力(问答之上的自主推理)。

系列导航:

  • (一)架构全景:Go 与 Python 双引擎 ← 本文
  • (二)自适应分片机制:三层策略与父子分块
  • (三)RAG 检索管线:12 阶段 Pipeline 剖析
  • (四)ReAct Agent 与三大能力
  • (五·番外)向量库可插拔抽象