从限制出发,而不是从技术出发
做径舟之前,我认真用过 ima 和 NotebookLM。它们都很好用,但都有一个共同的前提:你得接受它们的形态——源文件数量有上限,必须联网,数据要上传到别人的服务器。我想做的东西很简单:学生把几份课件 PDF 拖进去,用自己的话提问,系统跨文档找出相关段落,给出带来源的回答。在自己的电脑上跑,教室里没网也能用。
目标一旦具体到这份上,技术选型反而容易了:所有"强大但重"的方案都可以划掉。
看懂别人的架构,然后扔掉它们的依赖列表
调研阶段我读了两个开源知识库项目。SurfSense 用 Next.js + PostgreSQL + pgvector + Celery + Redis,挂了 27 个外部数据连接器;open-notebook 用 FastAPI + Next.js + SurrealDB。都是好工程,但都是企业级形态——为一个"上传几份课件"的场景,引入五六个服务进程,就像为了泡一碗面先盖一间厨房。
我把它们的 RAG 流程图看懂了:分块、嵌入、检索、拼上下文、生成。然后把依赖列表扔掉,从零搭最小可行栈。
三个关键取舍
向量存储:NumPy 内存矩阵,不要数据库。 ChromaDB 功能完善,但要多一个进程和持久化层。我的目标场景单次上传不超过 10 份 PDF,语义块总量很小——NumPy 一次矩阵点积就是全部检索计算,毫秒级返回。而且向量先做 L2 归一化,点积就直接等于余弦相似度,连额外的距离函数都省了。零依赖,零配置。初版连持久化都不做,进程关掉一切归零;后来才把索引落盘,重启不必重传——但那是后话了。
嵌入模型:本地小模型,不要云端 Embedding。 云端 Embedding API 意味着每次索引都要联网、按量计费,还有数据出境的问题。我选了智源开源的 bge-small-zh-v1.5:100MB,纯 CPU 推理,中文语义相似度评测表现很好。首次启动通过国内镜像下载,之后完全离线。代价是嵌入计算吃 CPU——5MB 的 PDF 最初索引要 12 秒,用线程池加批处理压到了 3 秒。这是整个项目里最有"手搓"手感的一段优化。
分块与生成:段落优先,云端大模型只做最后一步。 先按自然段落切,再按 2048 字符窗口合并,相邻块保留 512 字符重叠,避免一个概念被从中间截断。提问编码成向量后取 Top-8 段落,按"文档名 + 片段编号"拼进提示词,要求模型仅基于文档回答并标注来源,DeepSeek 流式输出,前端打字机呈现。
轻量不是简陋
回头看,这条链路的每一笔都是"把复杂度花在该花的地方":检索留在本地,因为那是隐私和低门槛所在;生成放在云端,因为那是大模型不可替代的能力所在。径舟后来能在一周内搭出初版、拿到两个班级去给真实的同学用,靠的不是技术堆料,而是从一开始就没给自己背上多余的重量。
工具如此,做事也一样。