第二章:需求分析与架构设计——核心功能模块拆解
好,咱们进入正题。上一章我们把知识库的「为什么」讲清楚了,这一章聊聊「怎么做」。
说实话,我见过不少团队,一上来就撸代码,结果做到一半发现数据源接不进来,或者检索慢得像蜗牛。嗯,这就是典型的「架构没想清楚就动手」。我个人习惯,先花两天时间把需求掰开揉碎,再画图,最后选技术栈。磨刀不误砍柴工嘛。
2.1 核心功能模块拆解
一个金融知识库,说白了就干五件事:采、洗、存、搜、答。我把它拆成五个模块,每个模块都有明确的边界。
核心五模块一览:
- 数据采集:从外部源(研报、公告、新闻)拉取原始数据
- 数据清洗:去噪、格式化、实体识别、去重
- 数据存储:结构化数据 + 非结构化数据 + 向量索引
- 智能检索:关键词 + 语义 + 混合检索
- 问答引擎:基于大模型的上下文理解与生成
你可能会问:为什么要把「问答」单独拎出来?我在项目中遇到过,很多人把检索和问答混在一起,结果用户问「茅台2023年营收多少」,系统返回了一堆研报片段,还得用户自己翻。这体验太差了。问答引擎应该直接给出答案,并附上引用来源。
2.2 数据采集模块
数据采集是地基。地基没打好,后面全是白费。
金融数据源五花八门:PDF研报、HTML网页、API接口、甚至扫描件。我建议按数据源类型分策略:
- 结构化数据(财报、行情):走API定时拉取,用ETL工具(比如Airbyte)
- 半结构化数据(HTML新闻):用Scrapy或Playwright爬取,注意反爬
- 非结构化数据(PDF研报):用PyMuPDF或OCR(Tesseract)提取文本
避坑指南:我曾经天真地以为所有PDF都能直接提取文本。结果遇到扫描件,全是图片。后来老老实实加了OCR流水线。记住:永远假设数据源是脏的。
2.3 数据清洗模块
清洗这一步,我见过太多人轻视了。金融数据里全是坑:
- 「贵州茅台」和「贵州茅台酒股份有限公司」是不是同一个实体?
- 「2023年12月31日」和「2023-12-31」要不要统一?
- 研报里那些表格,怎么提取成结构化数据?
我的做法是三步走:
- 格式标准化:日期、金额、百分比统一格式
- 实体对齐:用预训练的金融NER模型(比如FinBERT)识别公司名、人名、产品名
- 去重:基于MinHash或SimHash做近似去重,避免同一篇研报被重复收录
注意:金融数据去重不能只看文本相似度。两篇研报可能内容相似但观点相反,都得保留。我一般用「标题+发布时间+来源」做指纹,再辅以语义相似度做二次判断。
2.4 数据存储模块
存储是重头戏。金融知识库需要同时支持三种查询:
- 精确查询:查某只股票的历史PE
- 模糊查询:搜「新能源车 研报」
- 语义查询:问「最近哪些公司发布了超预期财报?」
所以我用了混合存储架构:
| 数据类型 | 存储引擎 | 用途 |
|---|---|---|
| 结构化数据 | PostgreSQL | 财报、行情、元数据 |
| 非结构化文本 | Elasticsearch | 全文检索、关键词匹配 |
| 向量嵌入 | Milvus / Qdrant | 语义相似度检索 |
| 原始文件 | MinIO (S3兼容) | PDF、图片等原始文件存储 |
你想想看,如果只用ES做全文检索,用户问「2024年白酒行业毛利率趋势」,ES只能匹配关键词,但理解不了「趋势」这个语义。所以必须上向量检索。
2.5 系统架构图
下面这张图是我画的核心架构。别嫌丑,逻辑清楚最重要。
这张图我画了三遍才满意。第一版太复杂,把每个模块的内部细节都画出来了,结果没人看得懂。后来我简化成四层:采集→清洗→存储→检索问答。每一层只标核心组件,够用了。
2.6 技术选型对比
选技术栈这事儿,没有银弹。我列个对比表,你根据自己团队的情况选:
| 模块 | 推荐方案 | 备选方案 | 我的建议 |
|---|---|---|---|
| 数据采集 | Airbyte + Scrapy | Apache Nifi / 自研 | 小团队用Airbyte,开箱即用 |
| 数据清洗 | Python (Pandas + SpaCy) | Spark NLP / 自研规则 | 数据量<10G用Pandas足够 |
| 结构化存储 | PostgreSQL | MySQL / TiDB | PG的JSON和向量扩展很香 |
| 全文检索 | Elasticsearch 8.x | Meilisearch / Typesense | ES生态最成熟,但重资源 |
| 向量检索 | Milvus | Qdrant / Weaviate | Milvus性能好,但运维复杂 |
| LLM推理 | vLLM + Qwen2.5 | Ollama / 文心API | 本地部署用vLLM,省钱 |
| 编排调度 | Airflow / Prefect | Dagster / 自研Cron | Prefect的Python原生体验更好 |
个人经验:别一上来就上Kubernetes。我见过一个5人团队,花了两周搭K8s集群,结果业务代码一行没写。前期用Docker Compose + 单机部署,等日均请求量超过1万再说。
2.7 避坑指南汇总
最后,我把这些年踩过的坑总结一下:
- 数据源变更:金融网站改版是常事。爬虫要加监控,发现异常立刻告警。我曾经因为没监控,数据断供了三天才发现。
- PDF解析精度:别信100%准确率。表格、公式、页眉页脚都会干扰。我一般保留原始PDF,清洗后的文本只做索引用。
- 向量维度选择:不是越大越好。768维的text-embedding-3-small够用了,1536维的模型推理慢一倍,效果提升不到5%。
- 检索召回率:纯向量检索容易漏掉精确匹配。我建议用「ES关键词检索 + 向量检索」的混合模式,权重按场景动态调整。
嗯,架构设计这块就聊到这儿。记住一句话:架构是演进来的,不是设计出来的。先跑通最小闭环,再逐步优化。下一章我们开始动手搭建开发环境,把代码跑起来。
公众号:蓝海资料掘金营,微信deep3321