从源质Hokma到闪念库:用FastAPI和SQLite搭建本地知识服务
这次我们来看一个不太一样的主题“源质部分 2·Hokma-执我闪念探索无限”。如果你玩过《脑叶公司》或者《废墟图书馆》对这个名字应该不陌生——Hokma 来自卡巴拉生命树的第二源质 Chokhmah中文通常翻译成“智慧”。但这里的“智慧”并不是我们日常理解的“知识很多、很会算题”而是更接近“原初的灵感冲动”在混沌里突然抓到一个念头顺着它不断向外探索。这篇文章我会同时做两件事第一把 Hokma 的源质含义、角色设定和剧情脉络拆清楚第二把“执我闪念”这个很游戏化的概念翻译成一套可以在本地跑起来的“闪念采集与知识检索服务”。也就是说你用 Hokma 的精神内核搭一个属于自己的“灵感档案库”。适合的读者有三类一类是想看懂《脑叶公司》《废墟图书馆》世界观的剧情党一类是平时灵感很多、但记下来就再也不看的内容创作者还有一类是喜欢用 FastAPI、SQLite、向量检索这类工具给自己做效率工具的技术型玩家。如果你正好跨在“游戏设定”和“技术落地”中间这篇文章可以直接收藏。1. 源质与 Hokma先弄清这个符号在讲什么卡巴拉生命树里有十个源质Sephirot分别是王冠、智慧、理解、仁慈、严厉、美丽、胜利、荣耀、基础、王国。Hokma或写作 Chokhmah排在第二位对应“智慧”。在卡巴拉体系里这个源质代表的不是积攒出来的知识而是“第一道闪电”万物尚未成形时一种来自本能的、直接的理解冲动。这也是“执我闪念”四个字最核心的意象“执我”以自己内心真实的念头为起点而不是先看别人怎么想。“闪念”灵感往往只存在几秒钟不记下来就会消失。“探索无限”单个闪念价值有限但当你把大量闪念连接成网络就形成了一个可以不断扩展的知识系统。在 Project Moon 构建的世界观里十个源质对应脑叶公司设施里的十位 Sephirot。Hokma 在其中的身份不是一个天天讲大道理的智者而更像一个“档案管理员”他负责记录、整理、归档公司内部的信息与异常记录。公司很多被隐藏的过去都储存在他手里。这个设定非常有意思智慧源质在实际剧情里变成了“记忆的看守人”。所以理解 Hokma 有一个关键点他不是灵感的“生产者”而是灵感的“容器”。闪念出现时他负责接住它把它放好等未来某个时刻需要时再准确取出来。这就是为什么“执我闪念”和“知识管理”在精神上完全一致。如果你看《废墟图书馆》会发现 Hokma 依然延续了这个气质。他以司书身份登场围绕他的主题仍然是记忆、时间、秩序和智慧。他不是那种冲锋型角色更像站在幕后把线索一条条拼起来的人。这种角色在游戏叙事里往往承载着“真相知情者”的功能也解释了为什么很多剧情关键线索都与他有关。2. Hokma 的角色设定与剧情脉络在《脑叶公司》里Hokma 的外表是一个白发长须的老者形象看起来像是已经工作了很长时间的资深管理员。他掌管公司的记录与情报系统职责是确保所有数据、事件、异常记录都能被准确保存。和 Binah 类似他是最早陪创始人建立设施的一批 Sephirot因此对公司的真实计划了解得比后来者更多。从剧情脉络来看Hokma 有几个很关键的特征他信任记录多于信任口头承诺。凡是写过、归档过的内容在他那里才算是“发生过”。他对公司创始人的计划保持忠诚但态度并不乐观。他很清楚这个计划要付出多高的代价。他不是一个表情外露的人。越重要的情报他越会用平静的语气讲出来。在《废墟图书馆》中Hokma 再次登场以司书的身份继续和主角一行人产生交集。他的战斗机制、主题书目和对话都围绕“时间”与“记忆”展开。实际上他在整个世界观里承担的东西很清晰让过去不被遗忘让真相不会因为时间流逝而丢失。这里有一个值得单独拿出来说的设计细节Hokma 掌控“记录”而记录本身就是一种跨越时间的探索。短期的闪念经过整理、归档、关联之后会在未来重新浮现变成新的决策依据。游戏里的 Hokma 守着公司的记忆现实里我们也能用同样的逻辑守自己的灵感。如果只是停留在游戏解析这篇文章其实可以结束了。但“执我闪念”这句话太适合工程化了。所以接下来我会把 Hokma 的符号意义转成一套真正能用的本地工具。3. 从“闪念”到“无限”知识管理里的 Hokma 思维先抛一个观点很多人做知识管理失败不是因为工具不好而是因为他们没有区分“捕获”和“整理”。Hokma 给我们的启发是先无条件保存原始念头再定期归档、关联。原始念头对应“闪念笔记”归档关联对应“永久笔记”。这个过程在卡片盒笔记法里已经讲得很成熟。建议把灵感管线拆成四段捕获任何时间、任何地点只要有念头立即用最少的操作记下来。清洗每天或每周固定时间把零散闪念改写成语义完整的短句。连接给笔记加标签建立引用关系让单条笔记进入更大的知识网络。输出当你需要写文章、做方案、做视频脚本时从知识网络里提取素材。工具层面Obsidian、Logseq、思源笔记都支持双链和本地存储适合做“知识网络”。但如果你想要一个更可控、支持批量导入和接口调用的“闪念中台”完全可以自建一个轻量服务。下面我给出一套自建的迷你闪念采集服务用来演示“执我闪念”的完整闭环。注意这不是某个现成开源项目而是基于常见组件设计的示例工程你可以直接复制思路改成自己的版本。4. 把“Hokma闪念库”做成一个本地服务这套服务的设计目标很简单用 HTTP 接口写入闪念打标签再通过关键词或语义检索把相关闪念找回来。技术栈用 FastAPI SQLite代码量很小不需要 GPU 也能跑。4.1 环境准备与前置条件建议操作系统为 Windows 10/11、macOS 或 Linux。需要准备Python 3.10 或更高版本。pip 包管理工具。可选NVIDIA 显卡和 CUDA 环境用于向量检索的 GPU 推理加速纯 CPU 也能跑只是稍慢。磁盘空间不启用向量模型时整个服务占用几十 MB启用本地向量模型后需要额外预留 1GB 到 2GB 模型空间。安装依赖pip install fastapi uvicorn pydantic如果后续要启用语义检索再安装pip install sentence-transformers4.2 项目结构推荐按下面的目录组织hokma-flash/ ├── main.py ├── import_notes.py ├── data/ │ └── hokma_notes.db └── notes/ ├── 2025-01-01-灵感.md └── 2025-01-02-游戏设定.mddata/放 SQLite 数据库文件。notes/放 Markdown 格式的闪念原文。main.py是 FastAPI 服务入口。import_notes.py是批量导入脚本。4.3 服务端核心代码下面是main.py的完整实现包含初始化数据库、写入笔记、查询列表、关键词搜索四个接口。import json import sqlite3 from datetime import datetime from pathlib import Path from typing import List from fastapi import FastAPI, HTTPException from pydantic import BaseModel BASE_DIR Path(__file__).parent DATA_DIR BASE_DIR / data DB_PATH DATA_DIR / hokma_notes.db DATA_DIR.mkdir(exist_okTrue) app FastAPI(titleHokma Flash Note Service, version0.1.0) class NoteIn(BaseModel): content: str tags: List[str] [] source: str manual class NoteOut(NoteIn): id: int created_at: str def get_conn(): conn sqlite3.connect(DB_PATH) conn.row_factory sqlite3.Row return conn def init_db(): with get_conn() as conn: conn.execute( CREATE TABLE IF NOT EXISTS notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL, tags TEXT DEFAULT [], source TEXT DEFAULT manual, created_at TEXT NOT NULL ) ) app.on_event(startup) def on_startup(): init_db() app.post(/notes, response_modelNoteOut) def create_note(note: NoteIn): if not note.content.strip(): raise HTTPException(status_code400, detailcontent can not be empty) created_at datetime.now().isoformat(timespecseconds) with get_conn() as conn: cur conn.execute( INSERT INTO notes (content, tags, source, created_at) VALUES (?, ?, ?, ?), (note.content.strip(), json.dumps(note.tags), note.source, created_at), ) note_id cur.lastrowid return NoteOut( idnote_id, contentnote.content.strip(), tagsnote.tags, sourcenote.source, created_atcreated_at, ) app.get(/notes, response_modelList[NoteOut]) def list_notes(limit: int 50): with get_conn() as conn: rows conn.execute( SELECT * FROM notes ORDER BY id DESC LIMIT ?, (limit,) ).fetchall() return [ NoteOut( idrow[id], contentrow[content], tagsjson.loads(row[tags]), sourcerow[source], created_atrow[created_at], ) for row in rows ] app.get(/notes/{note_id}, response_modelNoteOut) def get_note(note_id: int): with get_conn() as conn: row conn.execute( SELECT * FROM notes WHERE id ?, (note_id,) ).fetchone() if row is None: raise HTTPException(status_code404, detailnote not found) return NoteOut( idrow[id], contentrow[content], tagsjson.loads(row[tags]), sourcerow[source], created_atrow[created_at], ) app.get(/search) def search_notes(q: str, limit: int 10): with get_conn() as conn: rows conn.execute( SELECT * FROM notes WHERE content LIKE ? ORDER BY id DESC LIMIT ? , (f%{q}%, limit), ).fetchall() return { query: q, hits: [ { id: row[id], content: row[content], tags: json.loads(row[tags]), source: row[source], created_at: row[created_at], } for row in rows ], }这里的关键点是不要把created_at交给前端生成服务端统一写入更可靠。标签用 JSON 字符串存 SQLite读取时再解析简单直接不需要为了一个小工具引入复杂 ORM。如果你想在本地不用 Python 直接测试可以在文件末尾加一个__main__入口if __name__ __main__: import uvicorn uvicorn.run(app, host127.0.0.1, port8000)4.4 启动服务在项目根目录执行python main.py启动后FastAPI 自带的交互式文档会在http://127.0.0.1:8000/docs打开。你可以在网页里直接调用/notes接口也可以用下面的 curl 命令验证。curl -X POST http://127.0.0.1:8000/notes \ -H Content-Type: application/json \ -d {content:Hokma是第二源质代表智慧与灵感,tags:[脑叶公司,源质],source:blog}如果返回内容带id和created_at说明写入成功。5. 接口 API 与批量任务这套服务虽然轻但已经具备了接入其他工具的基础只要对方能发 HTTP 请求就能把闪念写入或者查出来。5.1 API 接口一览接口方法作用主要参数/notesPOST写入一条闪念content、tags、source/notesGET查询最近笔记limit/notes/{id}GET查询单条笔记路径参数 id/searchGET关键词搜索q、limit5.2 Python 客户端示例import requests BASE_URL http://127.0.0.1:8000 # 写入一条闪念 resp requests.post( f{BASE_URL}/notes, json{ content: 闪念记录不要在灵感出现时立刻判断好坏。, tags: [方法论, 灵感], source: desktop, }, timeout10, ) print(resp.json()) # 搜索包含“灵感”的笔记 search_resp requests.get( f{BASE_URL}/search, params{q: 灵感, limit: 5}, timeout10, ) print(search_resp.json())如果你的项目已经有语音输入、微信转发、浏览器剪藏这些能力只需要把最终文本 POST 到/notes就能把零散闪念统一收口。5.3 批量导入 Markdown 目录已有的 Markdown 笔记可以直接批量导入。这里给出一个脚本import_notes.py读取notes/目录下所有.md文件把文件名当来源、正文当内容逐条调用本地接口写入。import requests from pathlib import Path BASE_URL http://127.0.0.1:8000 NOTES_DIR Path(__file__).parent / notes def import_all(): if not NOTES_DIR.exists(): print(f目录不存在: {NOTES_DIR}) return ok, fail 0, 0 for md_file in sorted(NOTES_DIR.glob(*.md)): content md_file.read_text(encodingutf-8).strip() if not content: continue resp requests.post( f{BASE_URL}/notes, json{ content: content, tags: [markdown-import], source: md_file.stem, }, timeout10, ) if resp.status_code 200: ok 1 else: fail 1 print(f导入失败: {md_file.name}, 状态码: {resp.status_code}) print(f批量导入完成成功 {ok} 条失败 {fail} 条。) if __name__ __main__: import_all()建议先放两三个测试文件跑通再批量导入全部笔记。批量脚本要能输出成功和失败数量这样后续扩展到几百条笔记时你能快速判断哪里出了问题。5.4 批量任务的失败重试设计如果笔记量很大或者导入过程中服务重启建议增加一个“失败重试”逻辑读取文件后先写入本地日志。请求失败时把文件路径记录到failed_notes.txt。全部跑完后再单独处理失败文件。同一文件不要无限重试保留失败清单比反复请求更安全。6. 资源占用与性能观察这个纯 SQLite 版本的闪念采集服务非常轻不加载模型时内存占用通常在几十 MB 到一两百 MB 之间启动速度几乎可以忽略CPU 占用在空闲时接近 0。哪怕是很老的笔记本也可以长时间挂着。不过一旦你想做语义检索事情就会复杂一些。6.1 启用本地向量检索后的资源变化语义检索需要把文本转成向量常见做法是用sentence-transformers加载本地 Embedding 模型。以BAAI/bge-small-zh-v1.5为例模型体积不大单条短文本编码速度很快但加载时需要几 GB 内存或几百 MB 显存具体取决于你的设备。显存占用观察方法nvidia-smi如果你用 GPU 跑向量编码会看到 Python 进程占用显存。如果显存不足可以强制使用 CPUfrom sentence_transformers import SentenceTransformer model SentenceTransformer(BAAI/bge-small-zh-v1.5, devicecpu)CPU 推理在小批量场景下完全可用只是大批量导入时速度会明显慢于 GPU。6.2 建议的部署方式为了不拖垮日常记录推荐把“写入”和“检索”做轻量隔离写入接口走纯 SQLite不用向量模型保证随时可写。检索接口可选打开向量模型或者单独启动一个检索服务。大批量离线导入时先批量生成向量再分批写入数据库避免占用过高。6.3 如何观察端口和进程启动服务后如果发现端口被占用可以用下面的命令检查lsof -i :8000Windows 下使用netstat -ano | findstr :8000找到占用进程后可以把它停掉或者把服务端口改成 8001。python main.py --port 80017. 常见问题与排查方法问题现象可能原因排查方式解决方案启动后页面打不开端口被占用或服务未启动查看终端日志执行lsof -i :8000换端口或重启服务依赖安装失败网络源不稳定或 Python 版本过低查看 pip 错误信息确认 Python 版本换国内镜像源升级 Python写入笔记返回 400content 为空字符串检查请求参数传入非空 content搜索中文失效SQLite LIKE 对中文大小写不敏感但通配符需要用%手动检查数据库内容在搜索词两边加%数据库文件不存在未执行初始化建表查看data/目录重启服务startup 事件会自动建表批量导入某些文件失败文件编码不是 UTF-8查看失败文件清单统一转成 UTF-8 再导入启用向量检索后内存过高Embedding 模型加载在进程内观察htop或任务管理器改用 CPU 推理或单独部署检索服务最常遇到的情况是“端口被占用”和“依赖安装失败”。前者换端口就行后者最好先把 pip 源切到国内镜像再重新安装。8. 合规与使用边界虽然这个示例服务只处理文本但在实际使用中要注意几个边界《脑叶公司》《废墟图书馆》的游戏剧本、角色原画、音频素材都有版权。写设定解析时尽量用自己的话概括剧情不要直接搬运大段原文或付费美术资源。如果你基于 Hokma 或其他角色做 AI 生成图、声音克隆、角色数字人必须先确认是否取得官方或版权方授权。二次创作要尊重原作者的社区规则。自建闪念库会记录你的真实想法涉及个人隐私和他人信息时建议加密存储或不要把服务暴露到公网。本地向量模型要使用合规开源的模型权重不要把未授权数据喂给在线 API除非你仔细阅读了数据使用条款。9. 最佳实践与使用建议第一先跑通最小闭环。不要一上来就搭 Obsidian、搭向量库、搭自动摘要先测试“POST 一条闪念再 SEARCH 到这条闪念”这个最小流程。能跑通后面所有功能都是加分项。第二给闪念设计统一的记录格式。我建议每条闪念至少包含三部分我看到了什么、我联想到什么、我下一步要做什么。这样整理时不会变成一句孤零零的碎片。第三批量导入一定要加日志。没有日志批量任务卡住时你根本不知道卡在第几个文件。第四不要把服务暴露到公网。FastAPI 默认跑在127.0.0.1只监听本机。如果确实需要远程访问至少加一个反向代理和身份验证。第五定期回顾比记录更重要。Hokma 的形象是“档案管理员”他的价值不是保存档案本身而是能在关键时刻调出正确的档案。建议每周花 20 分钟扫一遍新增闪念把相关的连起来。10. 总结与下一步这个主题最值得尝试的点是用 Hokma 的“记录者”视角重新审视自己的灵感管理方式。你不需要等灵感完整、清晰了再记录先“执我闪念”把每个瞬间的本能反应存档后面才有机会让它们连接成更大的知识网络。最先应该验证的功能就是启动main.py后用 curl POST 一条笔记再用/notes/1把它查出来。把这一步跑通你就拥有一个可编程的灵感底座。最容易踩的坑是过度设计。很多人一想到知识管理就立刻去搭“全家桶”结果变成了整理工具而不是记录工具。建议先用 SQLite FastAPI 这套轻方案跑两周觉得不够了再去接向量检索、自动摘要和可视化图谱。下一步可以扩展的方向有接入 Obsidian 的本地 Vault、增加语音转文字入口、给闪念加自动标签、做每周回顾面板。Hokma 的精神是让记忆有序而不是让记忆填满你所有时间。工具做得越简单你越愿意长期用这才是“执我闪念探索无限”真正落地的方式。