【第二弹】知识库架构分享,它在我的工作中已经无法替代!

Nolan Vale 2026-06-13 11:33 1

前段时间分享了 我的「CodeX / Claude Code + Hermes + 知识库」工作流,看到很多朋友比较感兴趣。


经过这么长时间的实践,确实发现使用这套工作流的效果不错!所以今天详细分享一下我的知识库怎么构建的,思路供大家参考哦 ~^-^


那么【第二弹】开始吧 ~


一、知识库架构图(AI总结我的知识库生成,去除了敏感信息):



一句话总结:


我的每个项目、服务、工具和运维流程都有自己的单页,AI 先读索引,再读对象页,不盲目全库搜索。注意:源码是最终事实源


二、怎么生成自己的知识库


知识库主体参考的开源项目:github.com/silverbulletmd/silverbullet

知识库日志和沉淀参考的开源项目:github.com/luotwo/llm-wiki


可以直接发给 AI,让它给你生成知识库!


三、怎么使用知识库


你需要给 AI 设置全局提示词(只说思路,具体可以让 AI 结合自己的项目生成):


我不希望 AI 每次上来就把所有资料全读一遍,那样慢、浪费上下文,也容易被无关信息干扰。


所以一些限制是必须的:



  1. AI每次只看目录,再看单页。遇到具体项目、服务等问题时,由知识库入口 → 目标单页 → 具体问题/配置页。

  2. 知识库信息足够准确才直接回答。拿不准就去读源码。。

  3. 知识库只放长期复用的事实。AI 发现长期事实变更(接口、部署方式、踩坑经验等等),才更新知识库,一直变化的、临时的规则请写到 AGENT.md / CLAUDE.md 放每个项目的根目录。

  4. 知识库日志只记有价值的。不要改个变量、修个小 bug 也往日志记录,没有意义。

  5. 知识库禁止放密钥、密码等一切敏感信息。必须要放也只可以放引用路径,所谓敏感信息就是能不能公开发到 Linux DO 的都算 ^-^


三、多环境如何使用同一个知识库


每台设备需要初始化一次路径,也只需要一次


知识库正文里不直接写死 /opt/xxx、D:/xxx 这种真实路径,而是写成变量,比如:


repo: ${QCODE_CONSOLE_REPO}

config: ${QCODE_CONSOLE_CONFIG_DIR}/console.env

logs: ${VAR_LOG}/xxx.log


不同机器各自维护一份本机映射:env/local-paths.yaml,这个文件是 gitignored,不提交。


Linux、mac、Windows 可以 clone 同一份知识库,但每台机器的 ${VAR} 指向自己的真实路径。


AI 第一次访问知识库会自动执行知识库路径初始化的脚本。




这里贴一下大家参考,也可以让 AI 自己写一个


#第一次在新机器上用,自动生成本机路径映射:
cd /opt/knowledge-base
python3 scripts/resolve-paths.py --list

#scripts/scripts/resolve-paths.py

#!/usr/bin/env python3
"""Resolve ${VAR} paths using the machine-local mapping.

Default behavior is lazy and agent-friendly: if env/local-paths.yaml does not
exist, this script creates it once by scanning common local paths.
"""
from __future__ import annotations

import argparse
import os
import re
import socket
import subprocess
import sys
from pathlib import Path

ROOT = Path(os.environ.get("KB_ROOT", "/opt/knowledge-base"))
LOCAL_MAPPING = ROOT / "env" / "local-paths.yaml"
VAR_RE = re.compile(r"\$\{([A-Z0-9_]+)\}")
# Documentation/template placeholders, not real host mappings.
IGNORE_VARS = {"VAR", "PROJECT_REPO", "PROJECT_CONFIG_FILE"}

def parse_mapping(path: Path) -> dict[str, str]:
data: dict[str, str] = {}
if not path.exists():
raise FileNotFoundError(f"local path mapping not found: {path}")
in_paths = False
for raw in path.read_text(encoding="utf-8").splitlines():
line = raw.rstrip()
if not line.strip() or line.lstrip().startswith("#"):
continue
if re.match(r"^paths\s*:\s*$", line):
in_paths = True
continue
if in_paths:
if not line.startswith((" ", "\t")):
in_paths = False
continue
m = re.match(r"\s*([A-Z0-9_]+)\s*:\s*(.*?)\s*$", line)
if m:
val = m.group(2).strip().strip('"\'')
data[m.group(1)] = os.path.expanduser(val)
return data

def ensure_mapping(path: Path = LOCAL_MAPPING) -> bool:
"""Create local mapping once if missing. Returns True if created."""
if path.exists():
return False
bootstrap = ROOT / "scripts" / "kb-host-bootstrap.py"
if not bootstrap.exists():
raise FileNotFoundError(f"bootstrap script not found: {bootstrap}")
subprocess.run([sys.executable, str(bootstrap), "--write", "--output", str(path)], check=True)
return True

def mapping_path() -> Path:
return LOCAL_MAPPING

def host_name() -> str:
return os.environ.get("KB_HOST") or socket.gethostname()

def resolve(text: str, mapping: dict[str, str]) -> str:
def repl(m: re.Match[str]) -> str:
name = m.group(1)
if name not in mapping:
raise KeyError(name)
return mapping[name]
return VAR_RE.sub(repl, text)

def scan_vars() -> dict[str, set[str]]:
found: dict[str, set[str]] = {}
for path in ROOT.rglob("*.md"):
if ".git" in path.parts:
continue
rel = str(path.relative_to(ROOT))
for var in VAR_RE.findall(path.read_text(encoding="utf-8", errors="replace")):
if var in IGNORE_VARS:
continue
found.setdefault(var, set()).add(rel)
return found

def main() -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("value", nargs="?", help="string/path containing ${VAR} references")
ap.add_argument("--list", action="store_true", help="list local path mapping")
ap.add_argument("--check", action="store_true", help="check all ${VAR} references in markdown files are mapped")
ap.add_argument("--mapping", default=str(LOCAL_MAPPING), help="mapping file path; default env/local-paths.yaml")
ap.add_argument("--no-create", action="store_true", help="do not auto-create the local mapping if missing")
args = ap.parse_args()

mp = Path(args.mapping)
if not mp.is_absolute():
mp = ROOT / mp

created = False
try:
if not args.no_create:
created = ensure_mapping(mp)
mapping = parse_mapping(mp)
except FileNotFoundError as e:
print(f"ERROR: {e}", file=sys.stderr)
print("Hint: run `python3 scripts/kb-host-bootstrap.py --write` once, or omit --no-create.", file=sys.stderr)
return 2
except subprocess.CalledProcessError as e:
print(f"ERROR: failed to create local mapping: {e}", file=sys.stderr)
return 2

if created:
print(f"created local mapping: {mp}", file=sys.stderr)

if args.list:
print(f"host: {host_name()}")
print(f"mapping: {mp}")
for k in sorted(mapping):
print(f"{k}={mapping[k]}")

if args.check:
refs = scan_vars()
missing = sorted(v for v in refs if v not in mapping)
if missing:
print("Missing path mappings:")
for var in missing:
print(f"- {var}: {', '.join(sorted(refs[var]))}")
return 1
print(f"OK: all {len(refs)} referenced path variables are mapped in {mp}")

if args.value is not None:
try:
print(resolve(args.value, mapping))
except KeyError as e:
print(f"ERROR: unmapped variable: {e.args[0]}", file=sys.stderr)
return 1

if not (args.list or args.check or args.value is not None):
ap.print_help()
return 0

if __name__ == "__main__":
raise SystemExit(main())

本人迫不得已,要在Windows/Mac/Linux上工作,才想的这个办法,否则维护太困难!!


四、使用前的痛点和优缺点总结


痛点:

欸?我这个服务架构怎么实现的,端口号是多少?部署在docker吗,挂载到哪个目录了?


欸?我这个服务绑定的哪个域名?


欸?我这个服务里用到的第三方服务密钥配置在哪里了?


欸?之前看到一篇很好的文章 / 一个很优秀的项目,想不起来了!





使用知识库之后


优点:


项目职责和配置清晰明了。


运维历史可追溯。


个人知识沉淀了,走到哪里都能复用。




缺点:


Token 稍微多花费了一些,这个还在持续优化中,怎么让 AI 更有效率,更少检索来实现更好的效果。已经从每次读 1 万到 2 千左右了。


PS: 在一个上下文(Session)中,这些额外Token占用会带到每一轮对话中,看你是否能够承受!




只要用心维护知识库,你的知识永远会为你服务。

最新回复 (2)
  • 海盗船长 06-13 11:40
    1

    感谢大佬分享,前排火速收藏学习,最近看了前几天java老哥RAG知识库架构,再来学习一下这个,看看有啥不同。

  • xinxinzi 06-15 00:56
    2

    真的很不错啊佬,项目感觉很轻量,而且拜读了上一篇文章,感觉写的都很不错,目前打算尝试一下结合ccg工作流来使用,打赏佬88ldc ^-^

* 帖子来源Linux.do
返回