knowhub-code-review-feedback.md 6.5 KB

KnowHub 代码审查反馈

目的是帮助改进,不是批评。


1. 数据库设计:用 PostgreSQL 但不用关系型特性

现象:所有实体间关系都存为 JSONB 数组(capabilities: ["CAP-001", "CAP-002"]),同一关系在两张表各存一份,由应用层维护双向一致性。

问题

  • 这是文档数据库(MongoDB)的做法,放弃了 PostgreSQL 最核心的能力:引用完整性和 JOIN
  • 删一个 Capability,Tool 表里的 JSONB 数组还挂着已删除的 ID,变成悬空引用,数据库不会报错
  • 想查"CAP-001 关联了哪些 Tool",要遍历 Tool 表所有行做 @> 匹配
  • 两边各存一份的结果是:一边更新了另一边忘了 → 数据不一致,而且这种不一致很难发现

应该怎么做:多对多关系用关联表(junction table),关系只存一份,用外键约束和 ON DELETE CASCADE。这是关系型数据库的基本功。

已解决:迁移到新库 knowhub,所有关系改为关联表(8 张 junction table)。详见 schema.mdschema-migration-plan.md


2. 字段命名不统一

现象

  • Requirement 指向 Capability 的字段叫 atomics
  • Knowledge 指向 Capability 的字段叫 support_capability(单数)
  • Capability 指向 Knowledge 的字段叫 source_knowledge
  • Tool 按知识类型拆成三个字段:tool_knowledge / case_knowledge / process_knowledge
  • Capability.implements 的 key 用 tool name 而非 tool id

问题

  • 看到 atomics 不知道它指向哪张表,必须查文档
  • 单复数混用(support_capability vs capabilities
  • Tool 的三个 knowledge 字段是冗余的——Knowledge 自己有 types 字段区分类型,不需要 Tool 侧按类型拆存
  • implements 的 key 用 name 而非 id,和所有其他关联字段(都用 id)不一致

原则:字段名应该自解释指向什么。如果需要一个额外的"关联到"列来解释每个字段指向哪张表,说明命名有问题。

已解决:统一为 {entity}_ids 命名(capability_ids, tool_ids, knowledge_ids),Tool 的三个 knowledge 字段合并为一个 knowledge_ids。详见 schema.md


3. 文档与代码严重脱节

现象

  • knowhub/README.md 描述的是 SQLite + LIKE 搜索的老架构,实际代码是 PostgreSQL + pgvector
  • knowhub/docs/knowledge-management.md 写着"Milvus Lite 单一存储架构",实际没有 Milvus
  • README 写"Server 无 LLM 调用、无 embedding、无向量数据库",实际全都有

问题:新人看文档会被误导,基于错误理解做设计决策。文档不如没有——错误的文档比没有文档更有害。

应该怎么做

  • 文档是代码的快照,代码变了文档必须同步更新
  • 如果没时间更新文档,至少在文档顶部标注"⚠️ 可能过时,以代码为准"
  • 设计方案和代码快照用不同文件名区分(我们现在用 *-plan.md 后缀标识未实现的方案)

4. 代码组织:一次性脚本和核心代码混在一起

现象knowhub_db/ 目录下 28 个 .py 文件,其中 5 个是核心 store,16 个是已跑完的一次性迁移脚本,7 个是调试脚本。

问题:打开目录看到 28 个文件,完全不知道哪些是重要的、哪些是垃圾。新人会花时间去读 fix_embedding_migration.py 试图理解系统,结果那只是修了一个一次性的 bug。

应该怎么做

  • 核心代码和一次性脚本物理分开(migrations/scripts/
  • 或者跑完的迁移脚本直接删掉(git 历史里还有)

已整理:核心 5 个 store 留根目录,迁移脚本移到 migrations/,调试脚本移到 scripts/


5. Prompt 撰写:像写系统文档而非行为指令

现象:Librarian Agent 的 prompt 中包含大量实现细节和无关信息:

  • "你是 Knowledge Manager,作为后台服务运行,通过 IM 消息与调研 Agent 协作"
  • "你是事件驱动的:收到消息时立即处理并回复"
  • 大段描述"调研 Agent 如何发送调研结果"

问题

  • LLM 不需要知道自己通过什么协议被调用、运行在什么架构上、调用方是谁
  • 这些信息只消耗 token,不改善行为
  • "Knowledge Manager"、"Librarian Agent" 这类标签不激活任何有用的行为模式
  • 数据库 schema 介绍和操作策略混在一起,LLM 需要行动时去翻 schema 定义

应该怎么做

  • 角色定位描述具体能力("擅长从碎片信息中识别关联、去重"),不给标签
  • 去掉所有实现细节(协议、框架、调用方)
  • Schema(世界是什么样的)和策略(遇到 X 做 Y)分层写
  • 给判断标准而非流程步骤

规范已建立agent/docs/prompt-guidelines.md


6. 知识库的"知识图谱"定位不准确

现象:文档和 prompt 中多处使用"知识图谱"一词。

问题:知识图谱(Knowledge Graph)通常指实体-关系-实体的三元组结构,通过图数据库存储和图遍历查询。KnowHub 是关系型数据库 + 向量检索,实体间通过 ID 列表关联。这不是图结构。

在 prompt 中用"知识图谱"会误导 LLM 去做图推理相关的行为(比如试图做多跳遍历),实际系统不支持。

应该怎么做:使用准确的术语。KnowHub 是"分层分类索引"或直接叫"知识库"。


7. 上传流程中的概念混淆

现象:Librarian Agent prompt 中描述实体关系为"需求 → 拆解为能力 → 由工具实现 → 产生知识"的单向链。

问题

  • 能力(Capability)是不可分割的原子能力,来自对工具的分析(可能参考需求),不是仅根据需求就能"拆解"出来的
  • 知识(Knowledge)来自其他 Agent 的调研和汇报,不是 Librarian 自己创造的
  • 单向链的描述暗示了错误的因果关系和创建流程

应该怎么做:各实体独立描述来源和用途,不要用暗示因果关系的箭头链。


做得好的地方

值得肯定:

  • 上传编排的去重规则写得很好:先查后写、新建 Capability 的三个条件(有工具+有用例+具体可操作),这是实战中总结出的判断标准
  • tree_matcher 工具的设计不错,将需求匹配到内容分类树,多维度(实质/形式/意图)搜索
  • upload 的 buffer + batch 机制是合理的:先缓存、批量合并、再由 Agent 处理,避免频繁小请求
  • KnowledgeProcessor 的去重流水线(向量召回→LLM 关系判断→双向写关系)设计完整