ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

腾讯WeKnora开源知识库本地部署实战:Docker Compose搭建RAG问答系统

腾讯WeKnora开源知识库本地部署实战:Docker Compose搭建RAG问答系统 1. 为什么我盯上了 WeKnora 这套开源知识库第一次看到 WeKnora 这个项目是在翻腾讯技术团队的开源仓库列表时。当时我正帮一个做企业内训的朋友找方案他们的需求很具体把几十份产品手册、FAQ 文档、历史工单记录整合起来让新员工能像聊天一样问问题而不是在文件夹里翻半天。市面上的 SaaS 知识库产品不少但数据要传到别人服务器上朋友那边合规过不了所以必须本地部署。WeKnora 正好卡在这个点上。它是腾讯微信团队开源的一套 AI 知识库问答系统核心能力是把文档灌进去自动切分、向量化、建索引然后通过对话界面回答问题。整个东西用 Docker Compose 编排一台普通配置的服务器就能跑起来。我实测下来从零到能问答大概花了两个小时其中大部分时间还是在等镜像下载。这篇文章我打算把整个部署过程、踩过的坑、参数怎么调、后面怎么扩展全部摊开讲一遍。适合两类人看一类是手上有文档资产、想搭内部问答系统但不想碰云服务的开发者另一类是刚接触 RAG检索增强生成这套东西想找个真实项目练手的技术爱好者。不需要你懂深度学习但基本的 Linux 命令和 Docker 概念得有不然下面有些操作会卡住。先说清楚 WeKnora 到底解决什么问题。传统的关键词搜索你搜退款流程它只能匹配到包含这四个字的文档段落换个说法钱怎么退回来就抓瞎了。WeKnora 走的是语义检索路线把你的问题转成向量去向量库里找语义最接近的文档片段再交给大模型组织成自然语言回答。这套流程就是现在常说的 RAG。它的价值在于你不需要重新训练模型只要把文档喂进去它就能基于你的私有资料回答问题而且答案有出处能点开看原文。2. 部署前的整体设计与选型考量2.1 这套系统由哪些部件拼起来WeKnora 不是单一服务它是一组容器协同工作。拆开看主要有这么几块前端界面提供对话窗口和文档管理页面你上传文档、提问都在这里操作。后端服务处理文档解析、切分、调用嵌入模型、检索、调用大模型生成回答是整个系统的大脑。向量数据库存文档切片的向量表示检索时从这里找相似内容。WeKnora 默认支持多种向量库社区里用得比较多的是腾讯云 VectorDB 的本地替代方案或者直接用内置的轻量级存储。关系型数据库存用户、会话、文档元数据这些结构化信息通常是 PostgreSQL 或 MySQL。嵌入模型服务把文本转成向量。可以用 API 调用远程模型也可以本地跑一个嵌入模型服务。大语言模型服务最终生成回答。同样可以接远程 API也可以本地部署。这六块通过 Docker Compose 的 network 连在一起互相通过服务名通信。理解这个结构很重要因为后面出问题的时候你得知道是哪个环节挂了。2.2 为什么选 Docker Compose 而不是别的有人会问为什么不直接装在一台机器上或者用 K8s。我的判断是这样的WeKnora 的定位是中小规模知识库文档量在几千到几万份这个量级单机 Docker Compose 完全扛得住。K8s 那套东西运维成本太高为了一个内部问答系统搭一套集群属于杀鸡用牛刀。直接裸装更不行Python 依赖、Node 依赖、数据库版本冲突能把人折腾疯。Docker Compose 的好处是所有依赖版本都锁在镜像里换台机器只要把 compose 文件和配置拷过去一条命令就能拉起一模一样的环境。这对需要在内网多台机器部署的场景特别友好。而且 WeKnora 官方提供的 compose 文件已经把服务依赖关系、网络、卷挂载都写好了你只需要改几个环境变量。不过有个前提你的机器得能拉取镜像。如果是完全隔离的内网环境需要提前在有网的机器上把镜像拉下来导出成 tar 包再拷进去加载。这个后面会讲具体操作。2.3 硬件和系统的最低要求我拿两台机器试过配置差别挺大这里给个参考配置项最低能跑推荐配置说明CPU4 核8 核以上文档解析和向量化吃 CPU内存8 GB16 GB 以上嵌入模型和大模型如果本地跑内存需求翻倍磁盘40 GB100 GB SSD镜像、向量数据、文档原文都占空间系统Ubuntu 20.04Ubuntu 22.04其他 Linux 发行版也行注意 Docker 版本Docker20.1024.0低版本 compose 语法可能不兼容Docker Composev2v2.20v1 已经停止维护别用了如果嵌入模型和大模型都走远程 API那 8 GB 内存的机器就能跑起来。但如果想完全本地化嵌入模型比如 BGE-M3 本地跑起来大概占 2-3 GB 内存大模型如果是 7B 量化版本至少再留 6-8 GB。所以本地全栈方案16 GB 是起步线。磁盘方面要注意Docker 的镜像层和卷会越积越多。我见过有人跑了三个月磁盘被日志和旧镜像撑爆的。建议单独挂一块数据盘给 Docker 用或者定期清理。3. 核心细节解析与实操要点3.1 镜像拉取与网络问题的处理国内拉 Docker Hub 的镜像速度是个绕不开的问题。WeKnora 的 compose 文件里引用的镜像来源比较多有 Docker Hub 的也有其他仓库的。我的做法是分两步先看 compose 文件里列了哪些镜像然后逐个确认能不能拉下来。具体操作先进入项目目录找到docker-compose.yml用这个命令把里面引用的镜像列出来grep -E image: docker-compose.yml | awk {print $2} | sort -u拿到镜像列表后可以配置镜像加速器。在/etc/docker/daemon.json里加上{ registry-mirrors: [ https://mirror.ccs.tencentyun.com, https://docker.mirrors.ustc.edu.cn ] }改完重启 Dockersudo systemctl daemon-reload sudo systemctl restart docker注意镜像加速器地址会变动用之前先确认当前可用的地址。如果加速器不生效就老老实实一个个拉或者找有网的机器导出镜像再传进来。导出镜像的命令是这样的docker save -o weknora-images.tar image1:tag image2:tag传到内网机器后加载docker load -i weknora-images.tar这一步看着笨但在隔离环境里是最稳的办法。我试过用代理但 compose 里有些服务不走代理配置反而更乱。3.2 环境变量的配置逻辑WeKnora 的配置集中在.env文件里。官方一般会给一个.env.example你需要复制成.env再改。这里面有几个关键变量必须搞清楚不然服务起不来或者起来了但功能不正常。数据库连接相关包括数据库地址、端口、用户名、密码、库名。这些在 compose 文件里通常有对应的服务定义你改.env里的值compose 启动时会注入到容器里。要注意的是如果数据库服务也是 compose 拉起来的那地址应该填服务名比如postgres或mysql而不是localhost。因为容器里的 localhost 指的是容器自己不是宿主机。向量库相关如果用的是内置向量存储一般不需要额外配置。如果接外部向量库需要填地址和认证信息。这里有个坑向量库的维度必须和嵌入模型输出的维度一致。比如 BGE-M3 输出的是 1024 维那向量库的集合创建时就得指定 1024 维填错了会报维度不匹配的错误。模型服务相关这里分嵌入模型和生成模型两块。如果走远程 API需要填 API 地址和密钥。如果本地部署需要填本地服务的地址。我建议第一次部署先用远程 API 把流程跑通确认系统能正常问答了再换成本地模型。这样出问题的时候能快速定位是系统本身的问题还是模型服务的问题。文件存储相关上传的文档存哪里解析后的中间文件存哪里。默认是存在容器内的卷里如果文档量大建议挂载到宿主机目录方便备份和迁移。配置完.env后不要急着docker compose up先用这个命令检查一下 compose 文件语法docker compose config它会把你配置的变量展开显示最终生效的完整配置。如果某个变量没填这里会显示为空一眼就能看出来。3.3 文档解析与切分策略文档灌进去之后WeKnora 会先解析再切分再向量化。这三步里切分策略对最终问答质量影响最大。解析这一步系统要处理 PDF、Word、Markdown、纯文本等格式。PDF 是最麻烦的尤其是扫描件需要 OCR。WeKnora 对文本型 PDF 支持比较好扫描件的话得先自己用 OCR 工具转一遍。我试过直接传扫描版 PDF解析出来是空的因为里面没有文字层。切分这一步系统会把长文档切成一段一段的。切得太碎上下文丢失回答不完整切得太大检索精度下降因为一个片段里混了太多主题。WeKnora 默认的切分是按固定长度加重叠比如每段 500 字相邻段重叠 50 字。这个参数在配置里可以调。我的经验是技术文档按 300-500 字切比较合适因为技术概念通常集中在一两段里。如果是叙事性的内容比如案例集可以切大一点800-1000 字保留完整情节。重叠部分的作用是防止一个完整意思被切断但重叠太多会导致检索结果重复一般设成片段长度的 10% 左右就行。还有一个细节切分的时候最好保留文档的标题层级。比如一个 Markdown 文档二级标题下的内容应该作为一个切分单元而不是机械地按字数切。WeKnora 对 Markdown 的支持比较好能识别标题结构。所以如果你的原始文档是 Word 或 PDF建议先转成 Markdown 再上传切分效果会好很多。3.4 嵌入模型的选择与本地部署嵌入模型决定了检索的准确度。WeKnora 默认可能用的是某个通用嵌入模型但你可以换。目前中文场景下BGE 系列是社区里反馈比较好的BGE-M3 支持多语言输出 1024 维向量对中英文混合的文档很友好。本地部署 BGE-M3最简单的办法是用一个专门的嵌入模型服务镜像。compose 文件里加一个服务embedding: image: your-embedding-service:latest ports: - 9997:9997 volumes: - ./models:/models environment: - MODEL_NAMEBAAI/bge-m3然后在 WeKnora 的配置里把嵌入模型地址指向http://embedding:9997。注意这里用的是服务名不是 localhost。提示嵌入模型服务启动后会加载模型到内存第一次启动比较慢要等模型加载完再调接口。可以用curl http://localhost:9997/health检查服务是否就绪。如果机器内存不够或者不想本地跑也可以用远程嵌入 API。但要注意远程 API 有调用频率限制和费用文档量大的时候成本不低。而且数据要传到外部合规上可能有问题。所以能本地跑就本地跑。3.5 大模型接入的几种方式生成回答的大模型接入方式更灵活。WeKnora 支持 OpenAI 兼容的接口这意味着只要你的模型服务提供这个接口就能接进来。几种常见方案远程 API配置最简单填个地址和密钥就行。缺点是数据出本地有费用。本地部署开源模型比如用 Ollama 跑一个 7B 或 13B 的模型提供 OpenAI 兼容接口。优点是数据不出本地缺点是生成速度取决于硬件。本地部署推理框架比如用 vLLM 或 TGI 部署性能比 Ollama 好但配置复杂一些。我建议先用远程 API 把系统跑通确认问答流程没问题再换本地模型。换的时候只需要改配置里的模型地址和模型名称其他不用动。本地模型的选择上7B 级别的模型在 16 GB 内存的机器上能跑但生成速度大概每秒几个字体验一般。如果追求速度可以用量化版本比如 4-bit 量化内存占用减半速度提升明显但回答质量会略有下降。这个取舍看你的场景内部知识库问答对回答质量要求没那么高的话量化版本够用了。4. 实操过程与核心环节实现4.1 从零开始的完整部署流程假设你拿到了一台干净的 Ubuntu 22.04 机器下面是我实测走通的完整流程。第一步装 Docker 和 Docker Compose。sudo apt update sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release echo $VERSION_CODENAME) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin装完后验证docker --version docker compose version两个命令都能输出版本号说明装好了。第二步获取 WeKnora 源码。git clone https://github.com/Tencent/WeKnora.git cd WeKnora如果 git 拉取慢可以用镜像源或者直接下载 zip 包。第三步配置环境变量。cp .env.example .env vim .env重点改这几项数据库密码、向量库配置、模型服务地址。第一次跑模型服务可以先填远程 API 的地址和密钥。第四步启动服务。docker compose up -d-d是后台运行。启动后看日志docker compose logs -f看到所有服务都输出 ready 或 listening 之类的字样说明启动成功。第五步验证。浏览器打开http://你的机器IP:端口默认端口看 compose 文件里的映射。能看到登录页或者对话界面就说明前端起来了。注册一个账号上传一份测试文档等它处理完问一个问题试试。4.2 文档上传与索引构建的现场记录我拿一份 50 页的产品手册 PDF 做测试。上传后系统显示处理中大概过了三分钟状态变成已完成。这期间后台在做解析、切分、向量化。处理完后我在对话框里问了一个手册里的具体问题比如XX 功能的配置步骤是什么。系统返回了答案并且下面附了引用来源点开能看到原文片段。这说明检索和生成链路是通的。但我也遇到了一个问题有些问题的回答不完整只答了一半。排查后发现是切分粒度的问题。手册里有些步骤跨了两页切分的时候被切断了检索只召回了前半部分。解决办法是调整切分参数增大重叠长度或者把相关章节合并成一个文档再上传。还有一个现象问一些手册里没有的问题系统会强行编一个答案。这是大模型的通病叫幻觉。WeKnora 的应对方式是在 prompt 里加约束让模型只根据检索到的内容回答检索不到就说不知道。但这个约束不是百分百生效所以关键场景下答案还是需要人工复核。4.3 参数调优的实际操作系统跑起来之后有几个参数值得调。检索返回条数默认可能是返回最相似的 3 条或 5 条片段。条数太少可能漏掉关键信息条数太多会引入无关内容干扰生成。我的经验是文档主题集中的话3 条够用文档主题分散的话调到 5-8 条。这个在配置里叫top_k之类的名字。相似度阈值低于这个阈值的检索结果会被丢弃。设得太高可能什么都检索不到设得太低会召回一堆不相关的内容。一般设在 0.5-0.7 之间具体看嵌入模型的特性。可以先用默认值跑一批问题看召回结果的质量再微调。生成温度控制大模型输出的随机性。知识库问答场景温度设低一点比如 0.1-0.3让回答更确定、更贴近原文。设太高的话模型会自由发挥容易偏离事实。调参的时候建议固定一批测试问题每次改完参数重新跑一遍对比回答质量。不要凭感觉调要有对照。4.4 数据备份与迁移的实操知识库跑起来之后数据就是资产了。备份分两块数据库和文件存储。数据库备份如果用 PostgreSQLdocker compose exec postgres pg_dump -U 用户名 库名 backup.sql文件存储备份找到 compose 文件里挂载的卷直接打包tar -czf files-backup.tar.gz /path/to/volume迁移的时候在新机器上先把服务停掉恢复数据库和文件再启动。注意数据库版本要一致不然恢复可能失败。提示备份最好做成定时任务用 cron 每天跑一次。备份文件存到另一台机器或者对象存储上别跟原数据放一块不然机器挂了全没了。5. 常见问题与排查技巧实录5.1 服务起不来的排查思路docker compose up之后如果某个服务一直重启先用这个命令看状态docker compose ps状态显示Restarting或Exit的就是有问题的。然后看它的日志docker compose logs 服务名常见的几类错误错误现象可能原因解决办法数据库连接被拒绝数据库还没启动完或密码不对等数据库就绪检查 .env 里的密码端口已被占用宿主机上已有服务占用端口改 compose 里的端口映射镜像拉取失败网络问题或镜像不存在配置加速器或手动导入镜像内存不足被 kill容器内存超限增加机器内存或限制容器内存卷挂载权限错误宿主机目录权限不对chmod 或 chown 调整权限我遇到过一次后端服务一直重启日志显示连不上向量库。查了半天发现是向量库服务启动比后端慢后端启动时连不上就退出了。解决办法是在 compose 里给后端加depends_on和健康检查等向量库就绪再启动后端。5.2 问答质量差的优化方向系统能跑但回答质量不行这是最常见的问题。排查方向按优先级排第一看检索结果。很多系统有调试模式能看到检索到了哪些片段。如果检索到的片段跟问题不相关那问题出在检索环节。可能是嵌入模型不适合你的文档语言或者切分粒度不对或者相似度阈值设得不好。第二看 prompt。如果检索结果是对的但生成的回答不对那是 prompt 的问题。可以调整 prompt 模板明确告诉模型只根据以下内容回答、如果内容中没有答案回答不知道。第三看模型能力。如果 prompt 没问题检索也没问题但回答还是不行那可能是模型本身能力不够。换一个更大的模型或者换一个在中文问答上表现更好的模型。第四看文档质量。如果原始文档本身结构混乱、错别字多、信息重复那再好的系统也救不了。这种情况得先整理文档把过时的、重复的内容清理掉再重新上传。5.3 性能瓶颈的定位与处理文档量大了之后可能会感觉变慢。慢在哪得定位。上传文档慢是解析和向量化慢。这两个都是 CPU 密集型操作。如果 CPU 核数少可以限制同时处理的文档数量排队处理。问答慢分两段检索慢和生成慢。检索慢通常是向量库的问题数据量大到一定程度需要建索引。生成慢是大模型的问题本地模型受限于硬件远程 API 受限于网络和对方限流。我实测下来一万份文档以内检索延迟在几百毫秒级别感知不明显。超过这个量级就得考虑向量库的索引优化了。WeKnora 支持的向量库一般都有索引配置建好索引后检索速度会快很多。5.4 几个容易忽略的细节时区问题容器默认可能是 UTC 时间日志时间跟本地对不上。在 compose 里加TZAsia/Shanghai环境变量可以解决。日志膨胀Docker 容器的日志默认不限制大小跑久了能把磁盘写满。在 daemon.json 里配置日志轮转{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }会话清理用户跟系统的对话记录会一直存着时间长了数据库会变大。可以配置定期清理或者只保留最近 N 天的记录。模型更新如果换了嵌入模型之前建的向量索引就失效了因为维度或语义空间变了。换模型后必须重新处理所有文档这个要有心理准备。6. 后续扩展的一些想法这套系统跑通之后能扩展的方向不少。比如接企业现有的账号体系用 OIDC 做单点登录这样员工不用单独注册账号。WeKnora 本身支持 OIDC 配置填几个参数就能接上。再比如把问答入口嵌到现有的办公工具里。WeKnora 提供 API可以自己写个前端调它的接口做成一个聊天窗口挂在内部系统里。这样用户不用专门打开知识库页面在平时用的工具里就能问。还有一个方向是加多轮对话能力。现在的问答基本是一问一答如果用户追问系统不一定能理解上下文。这个需要在会话管理上做文章把历史对话也作为上下文传给模型。WeKnora 的架构支持这个但需要改一些代码。文档更新也是个实际问题。产品手册会改版FAQ 会增加。目前的做法是删掉旧文档重新上传但这样会丢失历史记录。更好的做法是做增量更新只处理变化的文档。这个需要自己写脚本对比文档哈希值只重新处理变了的。我在实际使用中最大的体会是这套系统的效果三分靠系统七分靠文档。文档整理得好切分策略对问答质量就高。文档一团糟再好的模型也白搭。所以部署之前先花时间把文档理清楚比后面调参有用得多。
返回列表