[控场AI]
· 7 分钟阅读· 3,908 字

把RecallOS搬进终端:本地AI文档助手改造实战

把RecallOS搬进终端:本地AI文档助手改造实战

把 Streamlit 版 RecallOS 改造为纯终端本地 AI 文档助手,替换交互层而保留逻辑层。

文章讨论如何把一个基于 Streamlit、Ollama 和 ChromaDB 的本地文档记忆与搜索助手 RecallOS 从浏览器界面改造为纯终端应用,以便在 VS Code 集成终端里直接使用,同时功能不减。改造的核心思路是替换交互层而非重写逻辑层,尽量复用 main.py、model.py 和 tools.py。终端界面可选 Textual(多面板 TUI)或 Rich + prompt_toolkit(轻量命令行)。文章还详述了文档分块与嵌入模型选择、ChromaDB 单集合加元数据过滤的检索方案、Ollama 配 Gemma 3 的 RAG 流程、以及聊天历史的本地存储与搜索,并给出分步实操顺序。

把浏览器标签页关掉——这是很多开发者在用久了 Streamlit 应用之后的共同冲动。RecallOS 是一个基于 Python 的本地 AI 文档记忆与搜索助手,依赖 Streamlit、Ollama 和 ChromaDB 三件套。它的功能已经很完整:导入文档、生成嵌入、语义检索、RAG 问答、保留聊天历史。但 Streamlit 的交互模式意味着每次使用都要开浏览器,对于习惯在 VS Code 里完成一切工作的人来说,这个切换成本并不低。

RecallOS 终端化改造的来源讨论

目标形态:终端内闭环

改造的核心诉求很明确:把 RecallOS 变成一个纯终端应用,直接跑在 VS Code 的集成终端里,不弹浏览器。功能上不能缩水——PDF、DOCX、TXT、Markdown 四类文档都要支持,文本抽取后继续用 Sentence Transformers 生成嵌入,ChromaDB 负责存储和语义搜索,Ollama 配 Gemma 3 (4B) 跑本地 RAG 问答,回答旁边要能看到引用的源文档和具体段落。聊天历史保留在本地,并且可以搜索历史对话。

这里有一个容易被忽略的约束:尽量复用现有的 main.py、model.py 和 tools.py。这意味着改造不是重写,而是替换交互层。

架构选择:Textual 还是 Rich + prompt_toolkit

Streamlit 之所以被绑在浏览器上,是因为它本身就是 Web 框架。要在终端里做等效的交互,有两条路。

一条是用 Textual 构建 TUI。Textual 提供组件化的终端界面,有布局、有滚动、可以响应键盘事件,适合需要多面板展示的应用——左边文档列表、中间问答、右边引用来源,这类布局在 Textual 里可以用 Grid 或 Dock 实现。

另一条是 Rich + prompt_toolkit 组合。Rich 负责渲染 Markdown 格式的回答和表格化的引用来源,prompt_toolkit 负责输入行的历史回溯和自动补全。这条路更轻,适合把重心放在命令行管道而不是界面本身。

如果 RecallOS 原来的 Streamlit 界面里有多个功能区(导入、检索、问答、历史),Textual 的迁移成本更低,因为可以一一映射。如果只是想保留问答主流程,Rich 方案代码量更少。

Streamlit 的 Web 绑定机制:理解为何必须换掉前端,需要知道 Streamlit 的运行模型。开发者写的 app.py 并不是普通脚本,而是一个由 Streamlit 运行时反复执行的脚本:每次用户点击按钮或输入文本,WebSocket 会通知服务端重跑整个脚本,界面随之刷新。所有跨交互的状态都必须放进 st.session_state,否则下一轮重跑就丢失。这种「重跑脚本 + 服务端渲染」的模型天然与浏览器绑定,终端里没有对应的 WebSocket 客户端与 DOM 渲染管线,所以无法在 TUI 中复用。这也解释了本文后面反复强调的一个重点:改造时要识别散落在 st.session_state 里的状态,把领域逻辑与其解耦。

文档处理层:复用 tools.py 的关键点

现有 tools.py 大概率已经包含了文档加载逻辑。改造时需要确认几件事。

首先是格式覆盖。PDF 的文本抽取在不同库里行为差异很大,PyMuPDF 对结构化 PDF 效果好但依赖较重,pdfplumber 在表格提取上更稳。DOCX 用 python-docx 是常规选择。TXT 和 Markdown 直接读取即可,但 Markdown 要注意是否保留标题层级作为分块依据。

其次是分块策略。Sentence Transformers 生成的嵌入维度固定,但文档需要先切成合适大小的片段再嵌入。分块太大,检索精度下降;太小,上下文丢失。常见做法是按语义边界切分,Markdown 按标题切,PDF 按段落切,再叠加一个 token 上限。

第三是嵌入模型的选择。Sentence Transformers 提供了从 MiniLM 到 MPNet 的一系列模型,本地跑要考虑内存和速度的平衡。

Sentence Transformers 与嵌入维度:Sentence Transformers 是基于 Transformer 的句向量模型库,把一段文本编码成固定维度的稠密向量,语义相近的文本在向量空间中距离更近。常用模型如 all-MiniLM-L6-v2 输出 384 维,all-mpnet-base-v2 输出 768 维。维度越高通常表达力越强,但内存占用和检索耗时也随之上升。关键约束是:嵌入模型一旦确定就不能中途更换,否则新写入的向量与旧向量维度不一致,ChromaDB 会直接报错,历史数据只能全部重建。因此在改造开始前就要敲定模型并写死配置,避免后续返工。

ChromaDB 与检索:语义搜索的实现细节

ChromaDB 作为向量库,在本地场景下是合理选择,因为它可以持久化到磁盘,不需要单独启动服务。改造时的一个关键问题是集合(collection)的组织方式——是所有文档放一个集合,还是按项目或目录分集合。

单集合实现简单,但文档量上去之后检索延迟会增加。按目录分集合更灵活,但需要在问答时决定查哪个集合。一个折中方案是单集合加元数据过滤,ChromaDB 支持在 query 时用 where 条件过滤。

检索结果要连同源文档和具体段落一起返回,这在 ChromaDB 里可以通过 metadata 存储原文片段和文件路径来实现。

向量检索与 top-k 的含义:ChromaDB 的语义搜索本质是最近邻检索。查询文本先被同一个嵌入模型编码成向量,然后与集合中所有向量计算距离(默认用余弦相似度),返回距离最小的 k 条。这个 k 就是 top-k,是 RAG 流程里最需要调参的变量:k 太小,召回的上下文不足以支撑回答;k 太大,无关片段混进 prompt 会稀释信号,还会撑爆模型的上下文窗口。ChromaDB 的 query 接口支持 n_results 指定 k,并可通过 where 字段做元数据过滤——这正是本文提到的「单集合 + 元数据过滤」方案的技术基础,让一个集合里既能按语义找,也能按 file_path 或 doc_type 缩小范围。

Ollama + Gemma 3 的 RAG 流程

Gemma 3 (4B) 在本地跑的可行性取决于硬件,4B 参数量在消费级显卡上可以接受,纯 CPU 推理则要接受一定的延迟。

RAG 流程本身不复杂:用户提问 → 嵌入查询 → ChromaDB 检索 top-k 片段 → 拼接 prompt → Ollama 生成答案。改造的关键是把这套流程从 Streamlit 的调用栈里剥离出来,让 model.py 里的生成函数不依赖任何 Streamlit 的 session state。

这一步往往是最容易出问题的地方,因为 Streamlit 应用常把状态散落在 st.session_state 里。改造时要识别出哪些状态是领域逻辑(检索结果、对话历史),哪些是界面状态(当前标签页、展开的折叠面板)。前者迁移,后者丢弃。

聊天历史:本地存储与可搜索

历史对话要存在本地并能搜索。最简单的方案是 SQLite,每轮问答存一条记录,字段包括时间戳、问题、回答、引用的文档片段 ID。搜索可以用 SQLite 的 FTS5 全文索引,也可以用嵌入做语义搜索。

如果想让历史搜索和文档检索共用同一套语义能力,可以把对话也嵌入后存入 ChromaDB 的另一个集合里,实现对话的语义回溯。这个方案更统一,但要注意区分文档集合和对话集合,避免检索时互相污染。

隐私边界:为什么本地化改造值得

整个改造的底层动机是隐私。Streamlit 本身不上传数据,但浏览器界面意味着开发者容易在多标签环境里混淆窗口,也可能在演示时不小心把本地文档内容暴露在屏幕共享里。纯终端应用把数据流转完全限制在本地进程内,Ollama 和 Sentence Transformers 都是本地推理,ChromaDB 落盘在本地路径。

这也是 RecallOS 这类工具的核心价值:在 AI 能力唾手可得的当下,把数据留在本地反而成了差异化。

改造的实操顺序

建议按这样的顺序推进。先冻结现有功能清单,逐项标注哪些属于交互层、哪些属于逻辑层。然后把 model.py 里对 Streamlit 的引用清理干净,这一步做完后整个模型层应该可以在纯 Python 环境里跑通。接着用 Textual 或 Rich 搭一个最小终端壳,把文档导入和问答主流程接上。最后补历史存储和搜索,以及引用来源的展示。

每完成一步都跑一遍原有测试或手动验证,避免在替换交互层的过程中把检索质量悄悄改坏。

完成之后,RecallOS 就从"打开浏览器才能用"变成了在 VS Code 终端里 python recallos.py 就能进入的本地 AI 文档助手——功能不减,隐私边界更清晰。

#RecallOS#终端AI文档助手#本地RAG#ChromaDB#Ollama#Sentence Transformers#Textual TUI#Streamlit改造
分享:

相关推荐