内容
# okforge
一款本地优先的LLM知识库引擎。将它指向您的文档;它会构建一个相互关联的wiki — 每个文档的摘要、跨文档的概念和实体页面、提取的图像,以及返回源的实际页面引用。Wiki是纯Markdown格式,带有YAML frontmatter,可在Obsidian或任何编辑器中阅读,并可通过CLI、聊天REPL、任何MCP客户端或配套的[okforge-webui](https://github.com/okforge/okforge-webui)网页应用查询。
## 为什么
大多数检索设置都将大量原始数据交给LLM,然后希望它能正确处理。而okforge则在运行时前将您的来源编译成精选的页面 — 已经综合了多个文档中的信息的概念和实体,每个声明都可以追溯到原始来源的`(第N页)`引用。对于上下文有限的模型(包括在您自己的硬件上运行的小型模型)来说,这尤为重要:它们不必为每个查询从头开始重建答案,而且它们所说的答案也可以根据特定的页面进行验证,而不仅仅是听起来合理。
输出遵循[开放知识格式(OKF)](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) — 类型化的frontmatter、相对链接、可预测的目录布局 — 因此知识库(KB)生成的wiki是可移植的,不仅仅局限于okforge本身。
## 安装
```bash
pip install git+https://github.com/okforge/okforge@main
```
## 快速入门
```bash
mkdir my-kb && cd my-kb
okforge init # 初始化raw/、wiki/、.okforge/目录 (--json用于脚本)
okforge add paper.md # 导入(预先转换非md/pdf输入)
okforge query "论文的结论是什么?"
okforge chat # 交互式REPL
okforge list --json # 机器可读状态(也支持status、okf-lint)
okforge describe "关于该项目的简要描述。" # 精炼描述
```
查询代理首先读取精选的页面,然后使用内置的`grep_wiki`词法搜索(定位后读取)进行详细查找,而不是重新嵌入所有内容。`okf-lint`检查wiki包的OKF一致性。
配置存储在`.okforge/config.yaml`(模型、语言、实体类型等)和`~/.config/okforge/global.yaml`(KB注册表、默认KB)中。LLM端点按照litellm样式配置 — 任何OpenAI兼容的服务器都可以使用,包括本地的llama.cpp实例。托管提供商通过相同的模型字符串工作,例如,使用`okforge init --model openrouter/qwen/qwen3.6-27b`和`LLM_API_KEY=sk-or-...`在KB的`.env`中运行整个管道,而无需其他更改。
对于具有思考能力的模型(特别是Qwen3系列),单独放置它们会花费一个隐藏的推理过程在**每个**管道调用上,而每个服务堆栈都不同意“不要推理”。在KB的`config.yaml`中添加端点理解的方言 — 对于llama.cpp/vLLM:
```yaml
llm_extra_body:
chat_template_kwargs:
enable_thinking: false
```
对于OpenRouter:
```yaml
llm_extra_body:
reasoning:
enabled: false
```
错误的(被忽略的)方言会静默失败 — wiki仍然会构建,您只需为每个调用支付推理令牌成本和延迟。在OpenRouter上使用`qwen3.6-27b`进行测量:一个微不足道的补全操作从199个令牌减少到2个令牌。
### 导入扫描和非文本文档
`okforge add`直接接受Markdown、纯文本和PDF。其他格式 — docx、pptx、扫描页面、照片目录 — 需要先转换为Markdown。特别是对于扫描页面,[**okforge-vision-ocr**](https://github.com/okforge/okforge-vision-ocr)(`pip install okforge-vision-ocr`)正是为此而设计的:每个页面调用一个视觉LLM,生成干净的Markdown转录和提取的照片/图片,以及一个`<doc>.pages.json`页面数组,`okforge add`直接读取以获得编译摘要中的实际(第N页)引用 — 无需额外的线路。
高于/等于`pageindex_threshold`页面的PDF(默认为20)会以相同的方式拒绝 — okforge不会自动分割长文档,因此请先像处理其他大型来源一样将其分割成较小的页面范围。
```bash
okforge-vision-ocr scanned.pdf raw/book.md # OCR + 照片提取
okforge add raw/book.md # 导入,附带页面引用
```
它适用于任何OpenAI兼容的视觉语言模型(针对本地托管的Qwen3.6-27B-MTP进行调优,但不限于此)。
### MCP服务器
`okforge mcp`在运行的KB上启动MCP服务器 — 与其他命令相同的解析度(cwd walk-up,或 `--kb-dir`)。工具:`query`、`grep_wiki`、`read_wiki_page`、`status`和`read_topic`(当KB启用`topic_tree`时)。只读 — 导入仍然是故意的CLI操作。
两种传输方式,可通过 `--transport` 选择:
```bash
# stdio(默认)— 客户端自行启动此进程
claude mcp add --transport stdio okforge -- okforge --kb-dir /path/to/kb mcp
# 流式HTTP — 此进程监听套接字供客户端连接
okforge --kb-dir /path/to/kb mcp --transport http --port 8000
claude mcp add --transport http okforge http://127.0.0.1:8000/mcp
```
与任何支持stdio或流式HTTP的MCP客户端配合使用。
**两种传输方式均无身份验证。** stdio默认情况下是安全的(它只是此进程自己的管道,没有人在网络上监听)。`--transport http`默认绑定到`127.0.0.1`,出于同样的原因 — 如果您更改 `--host` 或将其放在反向代理后面,请仅在您已经信任端到端(SSH隧道、VPN、身份验证代理)的网络上执行 — 切勿直接公开端口。任何可以访问它的人都可以完全读取KB,包括 `query`(代表您运行配置的LLM),无需登录步骤。
**直接测试http传输**(例如,使用 `curl`,无需真正的MCP客户端)意味着您需要自己实现流式HTTP会话握手 — 真正的客户端(`claude mcp add --transport http ...`)会自动为您完成所有这些操作:
- `Accept` 必须同时包含 `application/json` 和 `text/event-stream` — 单独的任意一个都会得到 `406 Not Acceptable`。
- 首先调用 `initialize` 并捕获 `Mcp-Session-Id` 响应头;将其作为后续每个请求的头发送。没有它就不会有会话。
- 响应是SSE(`event: message` / `data: {...}`)— 删除 `data: ` 前缀,将其余部分解析为JSON。
- `query` 的参数键是 `question`,而不是 `query`。
### 主题树(实验性,每个KB可选)
对于超出扁平概念列表的知识库:设置 `.okforge/config.yaml` 中的 `topic_tree: true`,然后运行 `okforge reindex`。现有概念聚类到命名目录 `concepts/<topic>/`,每个目录都有一个 `_topic.md` 汇总节点;后续导入按树结构归属新概念,查询获得一个 `read_topic` 导航工具,用于从上到下浏览,而不是扫描扁平列表。
## Wiki布局
```
wiki/
index.md # 文档 + 概念索引
summaries/<doc>.md # 每文档摘要(有页面引用时)
concepts/<name>.md # 跨文档概念页面
entities/<name>.md # 命名人员/地点/组织/作品
sources/<doc>.md # 导入的源文本
sources/<doc>.json # 每页文本 + 图片(当页面感知时)
sources/images/<doc>/ # 提取的图片
log.md # 追加式导入日志
```
## 路线图
一个网页UI已经作为单独的配套应用存在:[okforge-webui](https://github.com/okforge/okforge-webui) 通过浏览器驱动整个扫描到wiki的流程 — PDF邮箱、OCR试点、分割导入作业,附带实时进度、wiki浏览和查询,以及静态网站发布 — 基于相同的每个KB一个目录的布局,本README描述(它通过扫描`kbs/`根目录来发现KB,因此CLI创建的KB放在那里就会出现)。
计划中但尚未构建:
- **多个LLM端点** — 目前,一个KB配置指向一个litellm样式的端点;计划支持注册多个(不同主机,不同模型),并在调用时选择,而不是锁定整个KB使用一个。
- **并行处理** — 目前,导入和查询都是完全串行的(一次一个`add`,一次一个生成调用);计划对页面级工作和多文档导入进行并发处理,限定在每个端点的槽预算内,以便吞吐量随实际可用硬件扩展。
## 开发
```bash
uv run --extra dev python -m pytest tests/ # 测试套件
uv run --extra dev ruff check okforge tests # 检查
uv run --extra dev ruff format okforge tests # 格式化
```
## 起源
okforge最初是[VectifyAI/OpenKB](https://github.com/VectifyAI/OpenKB)的硬分叉,本着Karpathy的LLM-wiki理念,并在之后故意偏离 — 默认本地,仅有自己的文档转换边界,以及OKF一致性作为首要目标,而不是附带格式。
## 许可证
Apache-2.0。部分内容源自上游OpenKB项目(版权归原作者所有);okforge特定更改在[okforge/okforge](https://github.com/okforge/okforge)上维护。