设计决策
Knowlery 背后承重的设计决策,以及产生它们的推理。架构页说各部分是什么; 本页说它们为什么长成这个形状。
确定性优先于提示词
最早的版本靠提示词指挥 agent 检索知识——"先查 X,再 grep Y"的瀑布。模型 心情好的时候它能工作。0.6 的重写把检索搬进了代码:一个质量可测量的确定性 引擎,被 agent 调用,而不是由 agent 表演。
沉淀下来的分界规则:agent 行使判断;代码保证机制。 编译知识(/cook) 是判断——它保持为技能。找候选、检测陈旧、检查健康、打包知识包——这些是 机制,每一项都带着测试搬进了代码。当某个行为重要时,问题从来不是"怎么把 提示词写得更好",而是"这能不能变成一个函数"。
弃答是一等公民的回答
一个总能返回点什么的检索系统,会训练它的调用者不信任它。引擎的置信门禁 存在的意义,就是让 no-confident-match 成为真实、常见的判定——top 候选 必须过特异性加权的词覆盖或 source-graph 证据,而不是仅仅分数最高。
这向外传播为一种产品立场:CLI 在弃答时 exit 0(它是结果,不是错误),MCP 工具描述指示 agent 转述而非重试,eval harness 在守住 recall 下限的同时把 不可答问题的准确率保持在 100%——拒绝悄悄用一个换另一个。
发现即数据;只有坏掉的调用才是错误
每个报告面都区分报告里有坏消息和操作失败了。不健康的 health、很长的 stale 清单、弃答的 query——都是携带发现的成功结果。错误留给没能做到 所请求之事的调用:未知的 KB 名、格式错误的输入、sync 的降级守卫(它的目的 就是它拒绝执行的那次写入)。
这条线对 agent 最重要:把坏消息当失败的 agent 会重试,而重试一个真实答案 的 agent,最终会幻觉出一个听起来更好的。
安全论证必须是结构性的
凡是 Knowlery 做出安全承诺的地方,首选的设计是让违规不可能而不是被检查:
capture没有路径参数——文件名由时间戳 + slug 构造,穿越根本无法表达。 写入用wx标志,覆盖在系统调用层面就不会发生。inbox 经lstat验证是 真实目录,symlink 的 inbox 无法改写写入去向。- 远程访问旗标决定哪些工具被注册——未允许的写工具不出现在
tools/list里,而不是"存在但拒绝"。不存在可能写错的权限检查。 init_kb在每次检查前 canonicalize(parent realpath + candidate join)、 最多创建一层目录、拒绝非空目标——爆炸半径由构造保证。- 知识包批准记录内容哈希,编辑已批准页面会自动使批准失效。
模式是:当 review 发现某个边界只是被过滤时,修法是重新设计它,让坏状态 没有表示。
评审门禁,没有批量旁路
任何内容未经评审不得离开 vault:导出要求逐项 approve/flag 决定,且刻意 没有 approve-all 开关。当 agent 居间时,行为准则(写在技能本身里)要求 完整逐字呈现清单、只执行用户明说的决定。公开发布再加一道门:对每个风险项 二次确认,因为公开发布是永久的。
同样的哲学守着相反的方向——MCP 写工具执行用户的话、绝不 agent 主动—— 而编译知识层在所有传输层上都只能通过 /cook 的评审管线写入。
无缓存,无索引
每次查询、陈旧报告、健康检查都是实时扫描。这是先测量后选择的:vault 规模 的语料毫秒级扫完,缓存买不到任何东西,却要付出失效协议、一类陈旧 bug 和 跨壳一致性问题(三个壳会共享过期状态)。这个决定带来了意外的红利:MCP 的 无状态和重启安全白拿了,kb add 也不需要重建索引这一步。
一个核心,壳即传输层
每个特性先落进平台无关的核心;壳只做 I/O 适配。这是被强制的,不是愿景—— 纯度测试会让任何以值导入 Obsidian 的核心模块失败,smoke 测试证明构建出的 CLI 产物用纯 node 跑完整个生命周期。
这个纪律在复利:CLI(0.7)逼出了 VaultFs 倒置;MCP 服务器(1.0)原样复用 了倒置后的核心;HTTP 传输层(1.0)原样复用了 MCP 处理器。每个新壳都比上一 个便宜,而未来的托管平台被设计为"第二个宿主,而不是一次重设计"。
版本是契约
- manifest 记录最后 sync 工作区的版本;旧壳拒绝 sync,而不是降级新壳写过的 内容。
- 知识包更新要求版本递增,且拒绝覆盖(按哈希检测的)本地修改,除非
--force。 - 发布是幂等的——重发已存在的版本绿色跳过,而不是覆盖。
- 1.0 起,工作区格式、CLI 旗标/JSON 形状、MCP 工具契约在 semver 下冻结; 冻结后的重命名需要显式决定,不是一次重构。
凭证从来不归 Knowlery
Knowlery 只验证,不管理。私有知识包访问委托给用户的 gh 登录。npm 发布用 OIDC trusted publishing 而不是长命 token。MCP 远程 token 由运维者生成、从 环境变量或文件读取(绝不走 argv)、常数时间比较、不存任何地方。每一处都 选择了"接入既有的凭证所有权"而不是"自己持有秘密"。
测量的质量,冻结的下限
eval harness 是检索变更敢发布的原因:黄金问题集配期望页面、每次运行计算 recall@10 和 MRR、CI 基线让任何回退直接失败。当行为有意改变时,下限在同一 个 PR 里重新冻结——质量变动是显式的,绝无顺手为之。同样的思路治理弃答门禁 (不可答集的准确率是基线的一部分),以及 1.0 的契约冻结(测试里的 schema 断言就是接口的下限)。
规格驱动开发(SDD)
每个特性的发布路径:spec PR → 维护者评审(常常多轮,发现的问题修在 spec 里)→ 实现 → 维护者真实场景验收 → 状态翻转。spec 存于 specs/<version>/, 读起来就是项目的决策日志——包括那些改变了设计的评审发现(无状态生命周期 契约、symlinked-inbox 拒绝、canonical-candidate 算法都来自评审轮)。安全 性质在实现开始之前就以测试的形式写进 spec。