从「会算」到「会想」:一个 AI 量化驾驶舱的知识库设计与实战

从「会算」到「会想」:一个 AI 量化驾驶舱的知识库设计与实战

本文是《RAG 知识库构建:让智能体越用越聪明》


0. 背景:为什么一个量化驾驶舱需要知识库

先说业务,再谈技术——这是面试官和读者最买账的切入点。

我们的产品是面向A 股散户的 AI 量化交易分析系统,核心模块是一个叫「智能驾驶舱」的 Dashboard。它的使命很朴素:用一块屏、10 秒,把 10+ 数据源(指数、涨跌停、北向资金、估值分位、板块轮动)压缩成一句"今天该进攻还是防守"的判读,再叠加风险预警。

但早期的驾驶舱有个致命特征:它是一个「无状态实时计算器」

  • 每次刷新,Agent 都从零开始分析实时行情;

  • 今天的分析和昨天的分析零传承

  • 投资人看完仍然"看不懂市场、管不住情绪、看不准因子、找不准关注点"。

换言之,它只是个"更好的东方财富",没有体现出 AI 的"智能"二字。

这就引出了知识库设计的根本动机:我们早已沉淀了投资纪律、历史决策、因子库,但它们在系统中"睡觉"。设计的全部努力,就是让驾驶舱从"看清行情"升级为"有记忆、守纪律、能自省"的随身投资教练


1. 家底盘点:现有 4 类知识载体

动手设计前,先摸清已有什么。项目里backend/app/knowledge/下其实已经搭好了知识底座:

(1) 向量库VectorStore(ChromaDB,6 个集合)— 知识底座。

COLLECTION_CONFIGS = { "market_analysis": "每日市场分析报告(DashboardAgent 输出)", "scan_decisions": "扫描决策记录(ScannerAgent 操作建议)", "daily_reports": "交易日报(ReporterAgent 输出)", "investment_rules": "投资规则与经验教训", "factor_history": "每日因子列表", "memory_docs": "ai-memory 结构化记忆文件(精确检索优先,语义兜底)", }

下面三类都是它的"语义包装"。

(2) 投资规则库RuleStore(→investment_rules唯一已预置真实内容的知识库,7 条经典纪律:

DEFAULT_RULES = [ {"rule": "止损纪律:个股亏损达到止损线时必须执行减仓或止损", "category": "risk_management", "priority": 1}, {"rule": "趋势为王:大盘偏空时降低仓位,偏多时正常持仓", "category": "trend_following", "priority": 1}, {"rule": "量价配合:上涨放量看多,上涨缩量谨慎;下跌放量恐慌,下跌缩量企稳", "category": "technical", "priority": 2}, {"rule": "板块联动:持仓所属板块大涨时持有,板块转弱时减仓", "category": "sector", "priority": 2}, {"rule": "不追涨停:涨停板不追,等回调确认后介入", "category": "risk_management", "priority": 2}, {"rule": "MACD金叉参考:日线MACD金叉可作为加仓信号,死叉作为减仓信号", "category": "technical", "priority": 3}, {"rule": "北向资金参考:北向大幅净流出时整体谨慎,大幅流入时关注机会", "category": "macro", "priority": 3}, ]

(3) 因子库FactorStore(→factor_history— 影响股价的关键驱动因素(政策利好、量价背离、板块轮动)。结构 ready,内容靠 Agent 跑起来后写入。

(4) 决策日志DecisionLog(收编进local_storeSQLite)— 记录 ScannerAgent 每次操作建议,并支持回填结果验证reconcile_decisions),是"越用越聪明"的关键。

def log_decision(self, stock_code, action, reason, stock_name="", price=0, confidence=0, agent_name="ScannerAgent", date="") -> int: """记录一条决策,返回记录 ID。""" ... record = DecisionLogRecord(date=date, stock_code=stock_code, stock_name=stock_name, action=action, reason=reason, price_at_decision=price, confidence=confidence, agent_name=agent_name) db.add(record); db.commit(); db.refresh(record) return record.id

2. 知识库子系统架构

盘点完"有什么",要回答"怎么组织"。知识库不是一个单点,而是一个分层子系统

2.1 知识库子系统内部架构

知识库自己是一个"访问层 + 存储层"的两层结构:

┌──────────────────────────────────────────────────────────┐ │ 访问层(语义化接口) │ ├──────────┬───────────┬────────────┬───────────────────────┤ │ RuleStore│ FactorStore│ DecisionLog│ VectorStore │ ← 上层只关心"取规则/取因子/取决策/检索相似" ├──────────┴─────┬─────┴─────┬──────┴───────────┬───────────┤ │ ChromaDB │ │ SQLite │ ChromaDB │ ← 存储层(向量 + 关系型 混合) │ (向量·语义) │ │ (结构化·事实) │ (向量·语义) │ └────────────────┴───────────┴──────────────────┴───────────┘
  • 存储层:向量库(ChromaDB)负责"语义相似检索",关系库(SQLite)负责"结构化事实与聚合"。

  • 访问层:四个 Store 把底层存储细节屏蔽,对上层提供统一的语义接口。

注意:上图只是"知识库自己"的结构。它如何被使用——谁来读、谁来写、何时进 Agent——是下一节(§2.4)三方协作要回答的。

2.2 架构关键决策:向量 + 关系型「混合存储」

一个常被问到的问题:决策日志为什么不用 ChromaDB 存,而用 SQLite?

因为二者职责不同:

数据类型典型操作该用
投资规则 / 历史情境 / 因子语义相似检索、"找最像今天的"向量库(ChromaDB)
决策记录按 id 回填结果、按日期/结果聚合统计、算准确率关系库(SQLite)

向量库擅长"近似匹配",但极不擅长结构化聚合("近 30 天验证了多少、证伪了多少"这种 GROUP BY 它做不了,还得回查全部再在内存算)。所以我们坚持混合存储:语义检索用向量,事实聚合用 SQL。这也是DecisionLog最终从"独立 SQLite"收编进统一local_store的原因——结构化数据统一管理。

2.3 两个「记忆系统」的边界(容易混淆)

项目里其实有两套记忆,必须分清:

  1. 产品知识库backend/app/knowledge/)——运行时给 Agent 和终端用户用的领域知识(规则、因子、决策、市场分析)。

  2. 开发记忆体ai-memory/)——开发期给 AI 自身回忆用的工程记忆(文件即记忆 L1/L2/L3 + ChromaDBmemory_docs集合)。

二者通过VectorStorememory_docs集合桥接:ai-memory的 Markdown 被索引进产品 KB 的 ChromaDB,供语义兜底检索。但业务上它们是两条平行线——别把"AI 的开发笔记"当成"给散户看的投资知识"混为一谈。


2.4 Service、Agent 与知识库的三方协作

这是整个架构最关键的视角,也是后面"死库"问题的根源。先给一张端到端协作图:

┌──────────────────────────────────────────────┐ │ DashboardService(编排者) │ │ ① 取实时数据 ② 预取知识 ③ 组装 prompt │ │ ⑤ 解析输出 ⑥ 写回知识库 ⑦ 返回前端 │ └───┬───────────────┬───────────────┬──────────┘ │ │ │ ① 实时数据 │ ② 检索 / 写回 │ ③ 组装好的 prompt ▼ ▼ │ ┌──────────────┐ ┌──────────────┐ │ │ DataAggregator│ │ 知识库(4 Store)│ │ │ (Sina / CLS) │ │ ChromaDB+SQLite│ │ └──────────────┘ └──────┬───────┘ │ │ ④ 注入的知识只在 prompt 里 │ ▼ │ ┌──────────────────┐ │ │ DashboardAgent │ │ │ (tools=[] 直调) │ │ │ 纯推理单元 │ │ └────────┬─────────┘ │ ⑤ 结构化输出(JSON) └───────────────┘

(1) Service ↔ Agent:编排者 与 被调用的推理函数

DashboardAgenttools=[]直调模式——它不持工具、不持状态、不主动检索,本质是一个"给定 prompt → 产出结构化 JSON 分析"的纯推理函数。真正的主控是DashboardService:它负责数据获取(调DataAggregator)、知识预取、prompt 组装、调用 Agent、解析输出、持久化落库。

一句话:Service 是大脑(决定用什么知识、怎么问),Agent 是嘴巴(只负责按 prompt 作答)。

(2) Agent ↔ 知识库:零直接耦合,全靠 Service 中介

Agent从不直接访问知识库。知识库的两条通路都由 Service 代理:

  • 读取通路KB → Service(检索/预取) → prompt → Agent。Agent 看到的知识,是 Service "喂"进 prompt 的那一段上下文,它自己无从主动查询。

  • 写入通路Agent 输出 → Service(解析) → KB(store_agent_output)。Agent 产出的分析,由 Service 落库到market_analysis

所以对 Agent 而言,知识库只是"prompt 里的一段文本"——它既不知道知识来自哪个集合,也不知道背后有向量检索。这种"解耦"带来两个好处:Agent 可替换(换模型不影响知识逻辑)、知识逻辑可单测(检索在 Service 里,不依赖 LLM)。

(3) 为什么这正好是"死库"的根源

回头看 §3 的痛点就清楚了:项目早就有了写入通路(Service 把 Agent 结果store_agent_outputmarket_analysis),但始终缺了读取通路(Service 调用 Agent 前,从未先去 KB 检索并注入)。于是知识"只进不出"。我们这次设计的核心动作,就是在 ② 处补上"调用 Agent 前先检索知识并注入 prompt"——把断开的环闭合。


3. 核心问题:知识库成了「写而不读」的死库

盘点完家底,真正的痛点浮出水面——整条 Dashboard 链路没有任何一处"读取"知识库

DashboardAgent的 prompt 构造:

def _build_dashboard_prompt(sd: DataBundle) -> str: """将 DataBundle 格式化为 Agent 分析 prompt。""" parts = ["请基于以下实时市场数据,进行五步分析法宏观策略分析,输出JSON。\n"] # 指数 / 涨跌停 / 北向 / 板块 / CLS热点 / PE —— 只注入实时行情 ... return "\n".join(parts) if parts else "市场数据暂不可用,请降低置信度输出。"

prompt 里只有实时数据,没有一条规则、一段历史、一条决策。而分析完的结果却被写进了库:

# RAG 闭环:将 Agent 分析结果存入 market_analysis if agent_result.get("output"): store_agent_output(collection="market_analysis", content=agent_result["output"][:1500], metadata={"date": ..., "agent": "DashboardAgent", ...})

写进去了,但再没人读它。RuleStoreFactorStoreDecisionLog三者与 Dashboard 完全断开。

一句话痛点:知识库躺在 ChromaDB 里"睡觉",驾驶舱每次刷新从零算,今天的智慧和昨天零传承。


4. 设计目标与价值主张(投资者视角)

设计不是"多一个功能",而是把四个业务诉求一一落地:

投资者诉求知识库如何回应对应知识类型
认识市场:此刻是牛市中段还是熊市反弹?用「当前市场画像」检索历史上最像今天的日子,给出后续演变参照② 相似市场情境
把控情绪:恐慌割不割、狂热追不追?7 条投资纪律作硬约束注入,用规则替投资者踩刹车① 投资纪律规则
看准因子:什么在驱动行情?真利好还是噪音?沉淀每日因子 + 自省近期判断准不准,看清驱动逻辑③ 决策经验回流
找准关注点:今天盯北向、板块还是估值?前端「知识洞察」卡把注意力收敛到关键信号④ 前端知识洞察卡

一句话价值:把"个人的、临场的、易情绪化"的判断,升级为"有历史记忆、守纪律、能自省"的系统能力。


5. 总体架构:4 类知识的「注入 + 呈现」闭环

实时行情(sd) │ ├─① 投资纪律规则 ──► RuleStore.get_all_rules() ──┐ ├─② 相似市场情境 ──► market_regime 检索(向量) ├─► 拼入 DashboardAgent prompt ├─③ 决策经验回流 ──► DecisionLog.stats() + 近期成败 ──┘ │ └─④ 前端"知识洞察"卡 ◄── 新增 /api/dashboard/knowledge-context
  • ①②③ 是注入型知识:进入 LLM 推理上下文。

  • ④ 是呈现型知识:前端显式展示,不进 prompt,避免 token 浪费。

关键设计原则(与现有架构一致):知识检索在Service 层预取后注入 prompt不碰 Agent 的tools=[],尊重已有的"直调模式"决策。


6. 详细设计:四类知识逐一落地

6.1 投资纪律规则(Knowledge ①,硬约束)

  • 来源RuleStoreinvestment_rules,已预置 7 条(止损/趋势/量价/板块/不追涨停/MACD/北向)。

  • 检索策略:全量注入(规则少,约 7–30 条)。进阶:按当前 regime 过滤 category(偏空时优先risk_management)。

  • 注入位置:直接进DASHBOARD_SYSTEM_PROMPT的"必须遵守以下投资纪律"段,作为硬性约束

效果:分析天然遵守纪律,而非每次靠 LLM 随机发挥。即使检索到的历史案例建议"进攻",只要与"偏空减仓"纪律冲突,纪律压住参考。

6.2 相似市场情境(Knowledge ②,核心价值 · 软参考)

这是让驾驶舱"有记忆"的灵魂。用当前市场画像检索历史上最像今天的日子,把"当时之后 3–5 天的演变"喂给 Agent。

市场画像(Market Regime Signature)——可向量化的每日特征:

字段来源
上证/深证/创业板 涨跌幅sd.indices
涨跌家数比breadth_ratiosd.advancing/(advancing+declining)
涨停/跌停比sd.limit_up/limit_down
北向净流入(归一化)sd.north_amount
领涨板块sd.sectors[:3]
上证 PE 分位sd.sh_pe["pct"]

存储集合:新增market_regime,每条文档带outcome 标签

document: "市场画像: 上证+1.2%, 涨跌比62%, 涨停80/跌停20, 北向+45亿, 领涨AI/半导体..." metadata: { date: "2026-07-29", signature: {sh_chg, breadth_ratio, limit_up_ratio, north_norm, pe_pct, top_sector}, outcome_3d: null, # T+3 后回填:上证 3 日累计涨跌幅 outcome_label: null # "验证偏多" / "证伪" / null }

写入与回填流水线

时机动作
每日首次/market刷新后DashboardService构建当日market_regime文档(upsert by date)
夜间定时任务(T+3)用温层指数 K 线算 T+3 收益率,按 date 更新outcome_3d/outcome_label

检索算法:用当前 sd 构建今日画像文本 → 同一 EF embedding →query(top_k=3~5, 仅返回已带 outcome 的历史日)

最小数据护栏(重要):若历史带 outcome 的文档 < 20 条,优雅跳过注入。小样本检索无统计意义,反而污染分析。早期靠护栏过渡,样本足了自动生效。

6.3 决策经验回流(Knowledge ③,自省)

  • 来源DecisionLog.stats()返回{verified, falsified, pending, accuracy}query_recent(limit, outcome)取近期验证/证伪样本。

  • 注入内容:"近期决策准确率 X%;对[北向/小盘]类判断偏[准/不准],请相应调整该类信号权重"。

  • 效果:Agent 知道自己的近期偏差,动态调节信号权重——自省闭环,呼应已落地的reconcile_decisions

6.4 前端「知识洞察」卡(Knowledge ④,呈现)

新增KnowledgeInsight.vue+ 端点/api/dashboard/knowledge-context,三块展示:

  1. 📏遵守的纪律(规则条数 + 关键几条)

  2. 🪞历史相似情境(3 例,绿/红标 outcome)

  3. 🎯决策准确率(近 30 天,与AccuracyPanel同源)


7. 技术选型:为什么是这套组合

技术选型不是追新,而是贴合"单机、中文、A 股、结构化+语义混合"这四个约束。

维度选型为什么选它否决的替代
向量库ChromaDB(嵌入式)单机部署免服务器;内置 onnxruntime default embedding免下载;集合模型简单Milvus / Qdrant(集群级,过重)
EmbeddingBGE-small-zh-v1.5(中文优化),降级 ChromaDB defaultA 股文本以中文为主,通用英文模型召回差;本地缓存模型可切换纯英文 embedding(中文语义坍塌)
结构化存储SQLite(local_store)决策需按 id 回填 + 聚合统计,SQL 擅长全塞进 ChromaDB(聚合灾难)
检索实现直接query调用,非 LangChain RAG chain保持显式、可单测、检索逻辑可控黑箱 RAG 框架(难调试、难评审)
注入实现Service 层字符串模板拼接不引入框架,prompt 结构可评审、可 diff自动拼接链(不可控)

几个选型背后的权衡

  1. 为什么不直接上 pgvector / Milvus?温层数据(宏观时序、K 线)后续规划入 PG,但知识库先用轻量 ChromaDB——知识检索是低频、小数据量场景,没必要为一棵树引入一片森林。

  2. 为什么 embedding 要中文模型?投资规则、因子描述、市场分析全是中文。我们用 BGE-small-zh 并在本地缓存,没下载到时自动降级 ChromaDB 默认 embedding——可用性优先,质量次之,可平滑升级

  3. 为什么不用 RAG 框架?框架的"自动检索-拼接"会把检索逻辑变黑箱。我们宁可手写query+ 模板拼接,换取每一行注入都可测试、可评审


8. 知识库与提示词的关系(RAG 的两半)

这是整个设计里最容易被忽视、却最决定成败的一点。

8.1 一句话关系

知识库决定"往 prompt 里塞什么",提示词工程决定"怎么塞、塞在哪个位置、怎么让模型用起来"。二者合起来才是完整的 RAG。

很多 RAG 项目只优化检索(向量、chunk、rerank),却忽略:检索到的内容放错位置,等于没检索

8.2 知识类型 → prompt 位置的映射

这张表是整个 KB↔Prompt 设计的核心:

知识类型注入位置为什么是这个位置
① 硬规则System Prompt(常驻)要对所有对话生效、不被长上下文"挤出注意力";是不可违背的"人设/纪律"
② 软情境User Context(动态)随市场状态变化、可灵活增删;放进 user 才能"今天像 2024-09,明天像 2025-03"
③ 自省经验User Context 的"反思段"属于对当前分析的补充约束,动态生成
④ 前端卡不进 prompt纯呈现,进 prompt 纯浪费 token

我们的"硬约束 / 软参考分离"本质就是一条提示词工程决策:硬规则进 system(压舱石、永不被覆盖),软情境进 user(风向标、灵活可变)。这一分法同时解决了"知识放哪"和"冲突时谁优先"两个问题。

8.3 张力:注入多少才合适

  • 塞太多:token 浪费 + 注意力稀释——上下文越长,模型越容易忽略中段内容(lost-in-the-middle)。

  • 塞太少:知识库形同虚设,回到"无状态计算器"。

我们的平衡策略:① 全量(量小、必填);② 仅 top-k=3~5 且带 outcome;③ 仅近期 2–3 条;④ 直接剥离到前端不进 prompt。分层 + 最小护栏 + 呈现分离,正是为这个张力服务的。

8.4 与提示词课程的呼应

本项目另有提示词工程课程(prompt/SYSTEM_PROMPT_DESIGN.mdprompt/COURSEWARE.md)。知识库可以理解为提示词工程的"外挂记忆":system prompt 定义"你是谁、守什么纪律",知识库在运行时动态补充"此刻该参考哪段历史"。二者正交、互补,缺一不可。


9. 工程落地关键点(踩坑与权衡)

9.1 为什么是「Service 层注入」而非「Agent 挂 tools」

DashboardAgenttools=[]直调模式。两个选择:

方案优点缺点
给 Agent 挂tools(RAG 工具)灵活,Agent 自主决定查不查不可控、难单测、检索逻辑随对话漂移
Service 层预取后注入 prompt低侵入、好单测、检索可复用、不破坏直调架构需 Service 自己编排检索逻辑

我们选后者:知识检索是确定性编排,不该交给 LLM 自由发挥。这也让"注入什么知识"成为可测试、可评审的工程决策,而非 LLM 的黑箱行为。

9.2 embedding 一致性护栏

检索与写入必须共用同一个embedding_function(BGE-small-zh 或 ChromaDB 内置 default)。否则"写进去和查出来不在同一向量空间",相似度全失效——这是 RAG 隐性 bug,排查极难。

9.3 最小数据护栏

RAG 上线初期样本极少,硬检索等于"用 3 个样本下结论"。护栏(N=20 跳过)是工程上最务实的处理,也让系统"诚实地说我不知道"。


10. 工程鲁棒性:当知识库「说谎」或「自相矛盾」

知识库不是信仰,而是带置信度、可溯源、能被市场证伪的参考系

10.1 知识之间矛盾(如:历史说"进攻",纪律说"减仓")

  1. 优先级仲裁:硬规则(人工审核、可信度高)> 软情境(检索、带相似度置信度)。冲突时规则压参考,并让 LLM显式输出裁决依据("我注意到历史 X 与纪律 Y 冲突,按纪律取舍")。

  2. 置信度加权聚合:top-k 检索先做一致性投票,相似度低于阈值的直接丢弃;若 k 条多数指向相反,宁可降级为"无强信号"也不强行给结论。

  3. 强制引用溯源:prompt 要求"每条结论必须标注来自哪条知识 / 哪个 date",把黑箱变可复核。

10.2 知识本身不准确(过时、噪声、证伪样本)

  1. 衰减机制outcome_label=证伪的样本在后续检索中降权,验证过的加权——错误记忆被市场自我修正。

  2. 事实 vs 解读分层:关键数字(涨跌停、北向)永远以实时 API 为准,知识库只做"解读"不做"事实源",从根上避免数值错误污染决策。

  3. 闭环自净:用reconcile_decisions把预测与真实结果回填,错误自动暴露、准确率面板量化——一套"持续校准"机制。

  4. 护栏兜底:样本不足不检索;写入/检索 embedding 一致;chunk 策略固定。

收尾话术:所有优化都围绕一条——降低错误记忆进入决策的概率


11. 实战效果与验证(Done 定义)

  • /market返回的分析里,能观察到 Agent 引用了投资纪律(①)
  • 历史样本 ≥ 20 时,prompt 注入"相似历史情境"段;样本不足时优雅跳过(② 护栏)
  • KnowledgeInsight卡展示纪律/相似情境/准确率三块(④)
  • 决策经验段出现在 prompt(③)
  • 前端vue-tsc零错误;后端导入冒烟通过
  • 全程不破坏"直调模式 / Service 层注入"架构约定

如何评估知识库真的有用?不靠"感觉更聪明",而靠两个可量化信号:①AccuracyPanel决策准确率随回填样本累积是否趋势上升(自省闭环生效);② 相似情境注入后,Agent 输出是否出现"当前类似 X 日,彼时后续 Y"这类可验证的参照表述(记忆生效)。没有度量,知识库只是心理安慰。


12. 总结与可迁移经验

一句话收获:知识库的价值不在"存了多少",而在"有没有被用对地方、用对方式、用对位置"。

可迁移的五条经验:

  1. 先盘家底,再谈设计:我们不是从零造知识库,而是发现"已有知识在睡觉",设计的核心是"唤醒"而非"新建"。

  2. 混合存储:语义检索用向量,结构化事实与聚合用 SQL——别让向量库做它不擅长的事。

  3. 硬约束 / 软参考分离:规则是纪律(压舱石,进 system),检索是参考(风向标,进 user),二者必须分优先级与位置。

  4. 知识库 = 提示词的外挂记忆:RAG 效果 = 检索质量 × prompt 编排质量,两者缺一不可。

  5. 知识库必须可证伪:带 outcome 标签、带置信度、能回填、能衰减——只有能被市场打分的记忆,才配叫"智能"。

这套方法论不止适用于量化驾驶舱:任何"AI + 领域知识"的产品(客服、法务、医疗问诊),都能套用「盘点既有知识 → 分层(硬规则/软案例/自省经验)→ 混合存储 → Service 层确定性注入 → 与提示词协同 → 鲁棒性与证伪闭环」这条主线。


附:面试如何讲这个项目(速记版)

  • 业务背景:A 股散户驾驶舱,早期是"无状态计算器",知识库"写而不读"。

  • 架构:向量(ChromaDB)+关系(SQLite)混合;访问层四个 Store;Service 层确定性注入。

  • 技术选型:ChromaDB 嵌入式 + BGE 中文 embedding;SQLite 管决策;不引 RAG 框架。

  • 设计亮点:① 硬约束/软参考分离(system vs user)② Service 层注入不碰 tools ③ 最小数据护栏 ④ outcome 标签闭环。

  • KB↔Prompt:知识库定"塞什么",提示词定"怎么塞/塞哪";RAG 两半缺一不可。

  • 矛盾处理:优先级仲裁(规则>检索)+ 置信度加权 + 强制溯源。

  • 不准确处理:衰减机制 + 事实/解读分层 + 回填自净 + embedding 一致性。

(设计稿权威版本见ai-memory/iterations/iter-012-cockpit-kb/design.md,本文为其可发布实战版。)