Oh My KB:一个 Agent 操作系统的设计

无重(姚继涛)· 2026-06-15

一个个人 AI Agent 系统,运行了 6 个月。管理 1093 篇文档、执行 11 个定时任务、接入 4 个外部数据源、维护三层记忆。这篇文章讲它的设计——不只是 prompt engineering,是 Agent 作为一个操作系统应该怎么架构。

一、系统全景

Oh My KB Agent OS
  │
  ├─ 决策层:路由 Agent(CLAUDE.md + 19 个 skill 入口)
  │    ├─ 管道型 (13):抓取 8 + 报告 3 + 记忆 2
  │    ├─ 工具型 (7) :行情 / 社区 / 部署 / 地图 / Logo / 搜索 / 热点
  │    └─ 路由器 (2) :财务子 Agent / 记忆子 Agent
  │
  ├─ 感知层:4 路数据源,各有 fallback
  │    ├─ 富途 OpenD(行情)      → 离线时回退 WebSearch
  │    ├─ TrendRadar Docker(热点)→ 离线时回退 WebSearch
  │    ├─ 雪球 Playwright(社区)  → 超时则跳过
  │    └─ WebSearch(宏观/研报)   → 最后的兜底层
  │
  ├─ 记忆层:三层递进,每周蒸馏
  │    ├─ L1 原始记录(JSONL / 飞书消息)
  │    ├─ L2 结构化摘要(会话 / 飞书 / 日报)
  │    └─ L3 语义记忆(用户档案 / 项目状态 / 行为纠正)
  │
  ├─ 运维层:11 个 cron + 健康检查 + 自我修复
  │    ├─ 投资 3 个:早盘 09:17 / 盘后 21:15 / 周回顾 周日
  │    ├─ 知识 3 个:编译 02:00 / 日报 22:30 / 健康检查 周一
  │    ├─ 记忆 4 个:飞书 21:45 / 会话 22:00 / 蒸馏 周日 / 审查 每月
  │    └─ 其他 1 个:GitHub 趋势 09:00
  │
  └─ 存储层
       ├─ raw/     (1093 篇原始素材,只读只追加)
       ├─ wiki/    (编译管道自动生成,LLM 维护)
       ├─ memory/  (结构化记忆,分 TTL 管理)
       └─ outputs/ (报告 / 分析 / 问答存档)

二、决策架构:Agent 怎么知道该做什么

用户说一句话,系统怎么路由到正确的技能?三层决策:

第一层:Skill 入口匹配

19 个 skill 各有 description 字段声明触发条件。Agent 看到用户输入,匹配触发词最高的那个:

用户:"https://x.com/xxx/status/123"
  → description "x.com/twitter.com URL" 匹配 → kb-fetch-x

用户:"帮我看看 BABA 的行情"
  → description "富途行情/看行情/持仓数据" 匹配 → kb-tools-futu

用户:"早盘分析"
  → description "早盘分析/盘后分析/投资分析" 匹配 → kb-finance
    → kb-finance 是路由器,启动 kb-finance-agent 子 Agent
      → 子 Agent 持有 kb-invest-report + kb-report-finance

第二层:管道内阶段导航

匹配到 skill 后,Agent 不是一次性加载所有文件——它按导航表分阶段加载:

SKILL.md 导航表:
| 阶段 | 读哪个文件 | 何时读 |
|------|-----------|--------|
| 全程清单 | checklist.md | 每次执行前 |
| 前置检查 | preflight.md | 脚本运行前 |
| 输出总结 | post-fetch.md | 脚本运行后,写总结前 |
| 总结参照 | example.md | 写总结时对照 |

Agent 的执行路径被文件依赖关系硬编码。它不能跳过"读 post-fetch.md"就去写总结——因为它不知道总结格式和硬约束。

第三层:工具选择

每个 skill 声明了 allowed-tools。抓取类用 Bash+Read+Write,分析类加 WebSearch,部署类只 Bash。Agent 不会被不需要的工具干扰。

三、记忆系统:Agent 怎么记住

这是整个系统最容易被忽视但最重要的部分。没有记忆,Agent 每次对话都是从零开始。

三层递进

L1 原始记录(自动生成,不可删除)
  ├─ Claude Code JSONL(每次对话自动记录)
  ├─ 飞书消息 JSON(lark-cli 每日拉取)
  └─ TrendRadar 热搜 DB(每 30 分钟抓取)

L2 结构化摘要(每日 cron 自动生成)
  ├─ 飞书日报 (21:45)  → 从 L1 飞书消息提取关键工作事项
  ├─ 会话摘要 (22:00)  → 从 L1 对话日志提取决策和待办
  └─ 知识库日报 (22:30) → 从原始素材汇总今日收录和编译

L3 语义记忆(每周蒸馏,TTL 管理)
  ├─ user_profile.md   → 用户信息/偏好(TTL 90 天)
  ├─ mayfair-status.md → 项目进展/团队状态(TTL 14 天)
  ├─ feedback.md       → 行为纠正规则(永不过期)
  └─ recent.md         → 近期事件速记(10 天滑动窗口)

每周蒸馏:从原始到结构化

每周日 09:00,kb-memory-distill 执行。不是简单的"汇总本周内容"——是三路并行提取 + 冲突检测 + 验证门控:

Step 1: 启动 3 个子 Agent 并行读取近 10 天数据
  ├─ Agent A:读会话摘要 → 提取用户决策/偏好/待办
  ├─ Agent B:读飞书摘要 → 提取项目进展/人员动态/关键事件
  └─ Agent C:读聊天记录 → 提取隐性信息和背景线索

Step 2: 主 Agent 合并三路输出
  → 去重(同一事实多源提到 → 标记多源)
  → 冲突检测(A 说 X,B 说 Y → 标记 ⚠️ 待确认)
  → 分类写入(事实 / 纠正 / 决策 / 待跟进)

为什么三层而不是一层

如果每次对话都搜索全部原始数据,上下文爆炸。如果只存摘要没有原文,丢失细节。

三层让 Agent 按需下沉:日常对话读 L3(~2KB),需要细节时读 L2(~20KB),深度回溯时读 L1(完整记录)。不是存更多数据——是让 Agent 在正确的时间读到正确的粒度。

四、可靠性:怎么让 Agent 不退化

Agent 系统最大的敌人不是 bug——是退化。运行几周后,Agent 开始跳过步骤、忽略约束、输出质量下降。

根源:Agent 靠 prompt 驱动,prompt 里所有指令平权。关键约束("Cookie 过期必须检查")和普通信息("文件命名规则")混在一起。时间一长,Agent 会自主判断某些步骤"不需要"。

核心原则

不要试图让 Agent 更聪明。设计结构让 Agent 无法犯错。错误的机会不应该存在——不是 Agent 选择不走错路,是错路根本不存在。

四个机制实现这个原则:

机制 1:硬约束必须可度量

写总结前确认已读完全文,提取了关键证据。
| # | 检查项 | 方法 | 不过则 | | 1 | 全文已读 | Read 到文件末尾 | 重读 | | 2 | 有数据 | ≥1 个具体数字 | 补证据 | | 3 | 有判断 | 含 vault 关联或 🧠 标注 | 补关联 | → 三项及以上不通过 → 不输出,重读重写。

每条约束有:判定条件(怎么判断违规)、失败动作(违规做什么)、阈值(多少项触发)。Agent 无法模糊带过。

机制 2:文件存在性 = 零 token 信号

管道型 skill 有 checklist.mdpost-fetch.md。工具型 skill 没有。为什么不创建空的写上"本 skill 不需要"?

因为 Agent 需要读内容才知道不需要。文件缺席的话,Agent 在查找的那一刻就得到了答案——零 token 判断。命名前缀同理:kb-tools-futu 中的 tools- 直接告诉 Agent 不需要找 checklist 和 post-fetch。

机制 3:每个数据源有 fallback

数据源检查挂了的后果Fallback
富途 OpenDlsof -i :1111114 只标的价格没了WebSearch
TrendRadardocker ps --filter name=trendradar宏观热点没了WebSearch
雪球讨论脚本返回条数 > 0社区情绪没了跳过(非致命)
WebSearch始终在线兜底也挂仅用已有数据

管道不会因为一个数据源挂掉就静默失败。每个源有独立的健康检查和回退路径。

机制 4:健康检查 + 自我修复

每周一自动扫描知识库:

1. 摘要完整性:每篇摘要有三段(结论+证据+关联)?
2. 概念健康:来源 > 0?无失效 wikilink?更新 < 90 天?
3. 索引一致性:raw 文件数 vs All-Sources 条目数 = 0?
4. 断裂链接修复:标点标准化 → 前缀截断匹配 → 僵尸引用标记

发现断裂链接自动修复。不能自动修的(如"这个概念可能过时")生成报告通知用户。

五、数据融合:不是回答,是编织

普通 AI 回答"BABA 怎么样"——模型生成一段文字。我们的投资分析管线是同时拉四个数据源,交叉验证,结构化输出

Step 1: 数据采集(并行)
  ├─ futu API:14 只标的一秒拿完 → {code, price, change, volume}
  ├─ trendradar SQL:11 平台热搜,关键词筛选 12 个投资词
  ├─ xueqiu Playwright:6 只 ✅ 标的逐个拉讨论,提取情绪信号
  └─ WebSearch:补汇率/大宗/海外宏观

Step 2: 标准化 → Step 3: 四维评分(技术面+基本面+情绪面+事件驱动)
  → Step 4: 风险闸(BLOCK/WARN/PASS)→ Step 5: 五板块输出 → Step 6: Critic

每个标的不是得到一个 AI 生成的模糊评价——是得到一个结构化的评分,有来源可追溯:价格来自 OpenD 实时数据(不是训练数据),情绪来自雪球真实讨论(3 分钟内的帖子),宏观来自 11 个平台的热搜交叉验证(crawl_count 越高越可信)。

六、技能工程:怎么组织 19 个技能

三条规则搞定分类

1. Agent 需要"读结果→做判断→写总结"?→ 管道型
   文件:checklist + preflight + post-fetch + examples

2. Agent 跑完脚本就结束?→ 工具型
   文件:preflight 就够了(不要 checklist/post-fetch)

3. 技能需要启动子 Agent?→ 路由器
   文件:只 10 行,声明路由目标和子 Agent 路径

目录即状态机

管道型:                    工具型:
  SKILL.md    (入口+导航)      SKILL.md    (入口+导航)
  checklist.md (门控)          codemap.md
  codemap.md                   procedures/
  procedures/                    preflight.md (唯一的 process)
    preflight.md               references/
    post-fetch.md              scripts/
  references/
  examples/
  scripts/

SKILL.md 模板(直接抄)

---
name: kb-fetch-xxx
description: "触发条件"
allowed-tools: Bash Read Write
context: default
---

# 标题
一句话描述。

## 快速执行
```bash
grep -r "source: URL" "dir/" --include="*.md" -l  # 重复检测
python3 scripts/fetcher.py "URL"                   # 执行
```

## 执行导航
> 先读 `checklist.md` 了解全程,再按阶段读对应文件。

| 阶段 | 读哪个文件 | 何时读 |
|------|-----------|--------|
| 全程清单 | `checklist.md` | 每次执行前 |
| 前置检查 | `procedures/preflight.md` | 脚本运行前 |
| 输出总结 | `procedures/post-fetch.md` | 脚本运行后 |
| 总结参照 | `examples/example.md` | 写总结时 |

重构数据

技能类型重构前重构后
kb-fetch-wx管道15537
kb-fetch-web管道18137
kb-report-daily管道19235
kb-memory-distill管道22847
kb-tools-github工具20037
kb-tools-logo工具19627

平均 182→36 行(-80%)。不是行数重要——是每个阶段 Agent 上下文从"20% 相关"变成"接近 100% 相关"。

七、持续学习:Trace2Skill

即使有门控和硬约束,Agent 仍然会犯错。关键是从错误中学到东西,且不因偶发错误过度修正。

每周蒸馏结束后:

A. 收集 patterns.md 最近 10 天 Critic 记录(FAIL + PASS 都要)

B. 每条 FAIL 独立找根因
   → 偶发个例 → 丢弃
   → 系统性模式 → 输出优化提案

C. 层次归并
   → ≥3 条不同的 FAIL 指向同一个根因 → 保留
   → 1-2 次个例 → 丢弃为噪声

D. 验证门控(不可跳过)
   → 模拟应用新规则到上周全部 Critic 记录
   → a) 是否召回至少 1 条漏掉的 FAIL?
   → b) 是否误伤任何 PASS?
   → 两项通过 → 自动升级到 skill 的 Critic 标准
   → 任一不通过 → 丢弃或软化

旧版"≥3 次就升级"。问题:同一条 bug 在 3 次蒸馏里重复标记 → 假阳性 → 规则膨胀。新版要求 ≥3 条 不同的 FAIL + 验证门。一字之差,精度完全不同。

八、踩过的坑

  1. Cron prompt 不能含路径。 改流程要改两个地方(cron + skill),迟早冲突。正确做法:cron 只写触发词,所有逻辑在 skill 文件里。
  2. 文档说的不一定存在。 futu skill 写"venv 已安装",实际目录从没被创建。preflight 检查会暴露这种不一致。
  3. 外部依赖会静默失效。 Colima 重启后 Docker 容器不自动恢复,TrendRadar 挂了两周没人发现。
  4. 标记需要维护。 雪球讨论标记过时——中芯标了 ✅ 但没社区,MSFT 没标但讨论活跃。
  5. 周末不要跑投资 cron。 港股美股都不开盘,空转没意义。盘后从每天改成仅工作日。

总结

设计一个 AI Agent 系统,不是写一份很长的 prompt。是设计五层架构:决策层负责路由和技能选择,感知层负责多源数据融合和 fallback,记忆层负责信息粒度和时效管理,运维层负责定时任务和健康检查,存储层负责只读只追加的不可变数据。

技能不过是决策层的一个子模块。

当前系统:19 个 skill,11 个 cron,4 个数据源,3 层记忆,2 个子 Agent。运行 6 个月。所有设计决策有对应代码可验证。