做这个项目的起因其实特别直接——我一直在做智能体应用开发,去年陆续聊过不少垂直领域的落地需求后发现,A股投研分析是“大模型看着好用,落地处处碰壁”的典型场景。客户要的是这样一种效果:输入一句需求,比如“帮我找找受益于AI算力扩张、现金流稳健的A股标的”,系统能自动梳理产业链、拉财报、读公告、追踪新闻,最后产出一份带依据、可复核的分析结论。纯粹靠大模型硬答是做不到这个效果的,于是我最终把方案锁死在“RAG+智能体”的组合上,做成了一套端到端的A股智能选股分析智能体。这篇文章是这次开发全流程的复盘,内容包括架构取舍、知识库设计、检索调优、智能体工作流实现,以及一堆常规文档里不会写的踩坑记录。准备做RAG项目,或者想往垂直领域落智能体的朋友,可以直接参考里面的思路和坑位。
1. 为什么非要用RAG+智能体,而不是把大模型当“万事通”
1.1 我最初试纯大模型时踩的坑
第一期demo我偷懒,直接拿大模型做“股票问答”。结果一句话总结:看似什么都能聊,细看没有一句能直接信。最典型的是让模型帮我把某行业的龙头公司按营收排序,它会一本正经给出五六家公司,但其中有几家早就已经不再是行业头部队列,年份也说不清楚;让它解释某只票最近为什么异动,它给出的原因往往是训练数据里学到的历史相似行情,而非当下真实事件。这就是我反复强调的“知识冲突”问题:训练语料里的静态信息,和当下的市场动态天然存在时间差,模型自己根本意识不到。
更麻烦的是数据幻觉。股票分析最忌讳六位代码错一个、财报数字多一个零,但大模型在生成这类内容时,为了“回答得完整”,会主动把缺的信息补齐成看起来合理的数值。我做了一个小范围的抽样测试,让模型在不联网的情况下回答二十个涉及真实财务指标的问题,粗对率不到一半。这个数字直接让我把“纯LLM方案”划掉了。
1.2 RAG管知识,智能体管流程
既然单靠模型不行,第一反应是上RAG:把财报、公告、研报、新闻切块后向量化,检索召回相关内容再交给模型生成。RAG解决了“不知道”的问题,让模型能基于知识库内容回答,而不是凭空编。
但做着做着就会发现另一个缺口——股票分析不是一个“问一句答一句”的回合制游戏,而是一个多步骤的决策过程。“找AI算力概念里现金流稳健的公司”这句话,背后至少包含三件事:先判断什么是AI算力产业链、再筛选概念相关标的、还要逐个核查财务指标和近期公告。这需要系统动态决定“先做什么、再做什么、查哪些数据、用哪些工具”,也就是流程编排。
这就是我把智能体架构加进来的原因。简单说,RAG负责外挂记忆和事实供给,智能体负责任务拆解和工具调度。知识库是弹药库,智能体是指挥官,两者配合才能完成完整的分析动作。这个定位后来贯穿了整个项目设计。
2. 总体架构与数据链路设计
2.1 模块划分与信息流
整个系统的结构我拆成了四层,信息流是一条清晰的链路从数据源进,边处理边沉淀,最终在智能体层产出决策报告。采集层负责对接不同数据源,加工层负责清洗、切块、入库,服务层提供检索和重排能力,最上面是智能体执行层。
数据源 ├── 财报数据(EPS/ROE/现金流) ├── 公告与研报 ├── 行情与资金流数据 ├── 新闻资讯(按行业/个股打标) │ ▼ 采集清洗层 → 统一JSON格式,去除重复,时间戳对齐 │ ▼ 切块与向量化层 → 按业务类型分集合存储 + 本体关系映射 │ ▼ 检索服务层 → 多路召回(向量+BM25) → 重排 → 压缩 │ ▼ 智能体执行层 → 任务拆解 → 工具调用 → 生成与自检这个架构最大的特点是数据与决策解耦:知识库只负责“有什么”,智能体只负责“怎么用”。好处是后续替换模型、调整提示词、扩充数据源都不会牵一发动全身。我在项目中期至少大改过三轮智能体工作流,但这套模块边界始终没动,省下的返工时间非常可观。
2.2 数据采集管道设计:财报、公告、行情与新闻缺一不可
A股智能选股和通用问答的一个核心差异是:数据维度必须全。单有财报,做不了事件驱动;单有行情,做不了基本面判断。最终我只保留了四类数据源,每类的处理方式完全不同。
| 数据类别 | 核心字段 | 更新频率 | 入库方式 |
|---|---|---|---|
| 财报数据 | 营收、净利润、ROE、现金流、负债率 | 季度更新 | 全量清洗后增量入库 |
| 公告与研报 | 标题、公告类型、正文、发布机构 | 实时/每日 | 按公告ID去重,切块入库 |
| 行情与资金流 | 收盘价、涨跌幅、成交量、北向资金 | 每日收盘后 | 数值型存储,不做文本切块 |
| 行业新闻 | 标题、摘要、来源、涉及个股标签 | 小时级 | 事件抽取+标签化后入库 |
财报数据是结构化的数值型信息,不适合直接丢进向量库,我单独存成结构化记录,靠工具层取数;公告和新闻是非结构化文本,才是RAG知识库的主要对象。这个区分非常重要,很多人一上来把数值和文本混在同一个集合里,结果查出来的结果既没有精确财务指标,也没有完整上下文。
具体到入库管线,我有几个细节是反复调过的。一是公告去重必须用公告编号而不是标题,因为不同平台转载时标题可能微调,但公告编号是唯一的。二是新闻数据要解析正文后把涉及的公司名称统一替换成市场通用的简称或代码,否则会出现“苹果”和“Apple”之类概念词切割后的检索混乱。三是数据时间戳一定要保留到分钟级,这不只是入库要求,后期排序权重会用到。
2.3 知识库的“本体”设计:把A股业务概念变成可检索的约束
如果只是把一堆文档切一切丢进向量库,那就只是最基础的RAG,做不到行业级效果。我在这个项目里重点做了“本体”层面的设计,让知识库不只是散文档,而是一张有关系的业务网。
什么是本体?你可以把它理解为数据模型层面的概念约束。比如在A股分析场景里,我定义了这样几种实体:股票(Stock)、行业(Sector)、概念(Concept)、公司事件(CompanyEvent)、财务指标(FinancialMetric)。这些实体之间有明确的关系,比如“贵州茅台属于白酒行业”“AI芯片是AI算力概念下的子方向”“某公司发布股权激励计划属于公司事件”。把这些关系做成结构化约束后,检索过程就多了一层“路由能力”。
具体实现上,我用的是“向量库+关系边表”的混合体,关键动作是给每条知识打上本体类型标签。举个例子,某条新闻“某公司发布年度业绩预告,预计净利润同比增长40%”,入库时不仅做向量化,还会抽取出:涉及股票X、事件类型=业绩预告、指标=净利润增长。这样当用户问“近期哪些公司发布过业绩预喜公告”时,系统可以直接按结构化条件过滤检索结果,再结合语义相似度补充排名。纯向量检索这时候很难精确命中,因为“业绩预喜”和“净利润同比增长”不是同义词关系,但本体关系能把它关联起来。
这一块其实就是近来常说的Ontology RAG和GraphRAG思路的简化落地。我没有把知识图谱做得很重,因为完整图谱的构建和维护成本在A股这种动态场景里非常高昂,但抽取实体和关键关系来做约束与路由,性价比相当高,也是我后续项目中一直保留的设计。
3. 核心环节实现:索引、检索、重排与增强生成
3.1 文本切块与向量化:边界、粒度与召回质量
切块是RAG项目里最容易被低估的一环。很多人直接用固定长度硬切,切到一半把一段财报讨论和另一段毫无关联的新闻拼在一起,检索出来的结果自然又碎又乱。我在这个项目里花了两周专门调切块策略,最终形成了一套和业务类型绑定的规则。
| 内容类型 | 切块策略 | 块大小 | 重叠区间 |
|---|---|---|---|
| 公告正文 | 按章节标题切,每个章节独立成块 | 300~500字左右 | 50字 |
| 新闻事件 | 按段落切,保留标题+时间前缀 | 200~400字 | 20字 |
| 研报分析 | 按结论+逻辑段组织,优先保留对仗式观点 | 400~600字 | 100字 |
| 财报文本说明 | 保持整段完整,禁止跨章节拼接 | 整段一起入块 | 0 |
为什么公告要按章节切?因为A股公告有相对固定的格式,重要提示、交易概述、风险提示都是独立章节,混在一块会让模型分不清信息来源层级。新闻数据必须带标题和时间前缀,是因为单纯的正文切块会让模型丢失“这是什么时间谁说了什么”的核心语境。
向量化模型我对比过几款主流的Embedding模型,中文场景下BGE系列和基于同义句对比训练的模型表现比较稳定,金融语料上明显优于通用英文模型。最终选了BGE-M3的中文版本,它最大的优势是同时支持短句和长文检索,对公告这种长文本的召回效果更好。向量维度固定为1024,通过带语义权重的余弦相似度计算相关度。
有个实操提醒:向量化时不要对整篇财报做平均池化后塞进一个向量。财报信息密度极高,平均池化会把“净利润暴增”和“商誉减值”这种关键差异互相抵消成模糊的中间值。按小粒度切块后保留原文,比任何“精妙压缩”都可靠。
3.2 多路召回与重排:向量检索不是唯一解法
我在这批项目里反复实验得到一个结论:纯向量检索在A股场景下的召回质量不够稳定。主要原因是金融语言存在大量同义异构,比如“净利润增长”和“利润同比上升三成”语义相似但词面完全不同;反过来,“高增长”和“高估值”在语义空间里可能距离较近,但在分析语境里含义天差地别。向量检索只靠语义相似度打分,很容易召回到“听起来相关但实际无关”的内容。
所以我的检索层改成了多路召回+重排的结构。多路召回同时运行两条通道:向量通道负责语义相似,BM25关键词通道负责精确术语匹配。两个通道各召回前20条,合并去重后进入重排模型重新打分。重排器我用的是Reproducible的基于交叉编码器的中文Rerank模型,它比向量相似度更精细,因为它会给“查询-文档”对整体相关性打分,而不是只比对“查询向量-文档向量”的距离。
实验结果直接体现在指标上,加入重排后Hit率提升了近15个百分点。下面是某一轮测试的对比记录:
| 方案 | Top-3命中率 | Top-5命中率 | 平均首条相关度 |
|---|---|---|---|
| 仅向量检索 | 42% | 58% | 0.74 |
| 向量+BM25多路 | 51% | 66% | 0.79 |
| 多路+重排模型 | 63% | 78% | 0.86 |
还有一个细节:时间衰减权重。在新闻类文档的相关性得分上,我会叠乘一个时间衰减因子,越新的内容权重越高。这个设计在“近期利好/利空”类查询里收益特别大。有一次用户问“某公司最近有什么负面新闻”,如果不加时间权重,检索系统极可能把半年前的旧负面翻出来当最新事件,这是股票分析里不可接受的错误。
3.3 智能体决策工作流:从“一次性问答”到“多步分析任务”
有了知识库和检索能力,接下来就是把智能体用起来。我最开始把智能体做成“一个Agent走天下”,一个大模型收到问题后自行决定调什么工具。结果在复杂任务上经常出现工具漏调、逻辑跳跃的问题。后来换成了“主引擎+多个子Agent”的分层结构,稳定很多。
主Agent不直接处理具体工具,它只做两件事:理解任务意图和拆解执行路径。比如输入“找出XX概念下资产负债率低于40%的龙头公司”,主Agent会先把任务拆成三步:先定位概念相关公司、再逐家核实资产负债率指标、最后按市值和营收排序筛选龙头。每个子步骤交给对应的子Agent执行。
- 概念路由Agent:负责把行业/概念表述映射到知识库中的本体标签,处理“AI算力”和“算力基础设施”这种同义概念的归一。
- 财报分析Agent:调用结构化财务接口,只负责取数、算指标、做横向对比,不承担语义理解类任务。
- 公告事件Agent:检索公告库,提取事件类型、时间、涉及主体,输出结构化事件列表。
- 综合研判Agent:汇总前三个Agent的输出,结合RAG检索的新闻与研报内容,统一生成最终分析结论。
这种“一个主控+四个专职”的架构,好处是每个子Agent的提示词可以写得非常聚焦,判断准确率远高于一个全能提示词。我实测下来,单任务意图识别准确率从78%提升到92%左右,多步任务的完成率也明显提高。所谓Agentic RAG,本质就是让检索不再是“一次性查找”,而是嵌入到任务链路里被反复调用,并支持根据中间结果调整下一步检索方向。
3.4 提示词与输出约束:让模型学会“分清事实和判断”
模型生成环节其实是最容易被忽略的。很多人以为检索做好了,答案自然就准确了。实际上,就算检索结果完全正确,大模型生成时仍然可能发生两种情况:一是把不同来源的数字混着算,得出错误结论;二是把检索到的“预测性观点”直接叙述成“确定事实”。
我在提示词里强制加入了“证据边界”指令,把输出格式固化成了下面这种模板:
请基于提供的检索举证材料回答,不要使用记忆中的具体数值。 回答需遵守: 1. 每个结论后标注【来源序号】; 2. 明确区分【事实陈述】与【主观判断】; 3. 如果检索材料内的数据互相矛盾,需明确指出矛盾点,不可自行抹平; 4. 对未检索到的内容,说“当前知识库未覆盖”,不要补充推测数据。这个模板的实际价值远超我的预期。之前自动生成的分析报告里,经常出现“利润稳定增长”这种模糊表述,普通人看不出风险,但做投资的人一看就知道模型在“说废话”。加上证据边界的约束后,生成的结论在可复核性上提升了一个量级——每个关键判断都能追溯到原文。另外,我在生成前加入了一个“查询压缩”步骤,把用户的原始提问和之前轮次的上下文重新组织成一条自包含的检索query,避免多轮对话中指代问题导致的检索错误。
4. 实测效果、常见问题与复盘心得
4.1 评测指标与实验对比
项目上线前后我做了大量离线测试,除了基础的检索命中率,还重点评测了“最终答案的可执行性”。我在内部定义了一套五级评分标准,从高到低分别是:结论正确且数据可复核、结论正确但来源不够直接、结论泛化但方向正确、结论存在一处明显错误、幻觉输出。用这套标准评估了一个含一百多条真实分析需求的数据集,结果是达到前两级的比例稳定在67%左右。
为了说明架构的作用,我也做了个对照实验:同一批问题分别交给纯大模型、单轮RAG、RAG+智能体工作流三套方案。结果如下:
| 方案 | 得分前两级占比 | 幻觉输出占比 | 平均响应时间 |
|---|---|---|---|
| 纯大模型 | 18% | 44% | 3秒 |
| 单轮RAG | 45% | 12% | 5秒 |
| RAG+智能体工作流 | 67% | 4% | 12秒 |
响应时间变长是智能体多步调用的必然代价,但这个代价换来了任务完成度的显著提升,在实际使用场景中是可以接受的。后续我通过并行化检索和结果缓存,把这套流程的平均响应时间压缩到了8秒左右。
4.2 高频问题与排查技巧实录
开发过程中踩过的坑很多,我把几个最有代表性的列出来,这些常规文档里基本不会写。
问题一:检索到过时信息,但相关度排名很高。早期新闻检索不做时间衰减,用户问“最近一周某行业动态”,返回的却是一个月前的旧新闻。后来我在重排阶段给每条结果加上了按发布时间衰减的惩罚系数,并且对超过设定时限的新闻强制降低分数,问题基本解决。
问题二:财报分析时模型总把“增长率”算错。这不是检索问题,而是提示词没有明确数值计算规则。比如同比和环比经常混用。我后来在财报Agent的提示词里增加了一条:“所有计算必须先明确基准期,并输出计算公式后再给结果。”模型会在答案中写出“(本期值-上期值)/上期值”,从根源上减少了计算过程不透明造成的错误。
问题三:公告内容被切碎,导致事件全貌丢失。股权激励公告经常是二十页PDF,按章节切块后单块只覆盖“激励计划概述”或“授予对象名单”。模型只凭部分信息会误判成“大额股权激励”。解决办法是对公告类文档在按章节切块的同时,额外保留一份“全文摘要块”,生成时优先查看摘要块建立整体认知,再查看细粒度块引用细节。
问题四:智能体陷入死循环。有一次子Agent在调用财报接口时返回空数据,Agent不断重试同一个工具而不切换策略。我在工作流中加入了一条“失败熔断”规则:同一个工具调用失败超过两次,子Agent必须改变计划,要么换一个工具,要么向主Agent上报异常。这从根本上杜绝了无脑重试导致的超时问题。
4.3 复盘心得与可复用的设计建议
如果这个项目让我重新做一遍,我会在前期就优先做两件事:一是把评测集建得更完整,而不是等到开发中期才开始积累测试用例;二是尽早引入本体关系设计,它带来的收益远比想象中更大。对我来说,一套可复用的RAG知识库设计方法比一堆调参记录更值钱。这套方法后来已经被我复用到了金融以外的行业项目中。
另外必须说一点,A股智能选股这个方向,技术本身只是支撑,业务场景的风险意识更重要。系统必须明确区分“信息检索辅助”与“投资建议”,我的做法是在最终报告中每次都附带“风险提示”,并显著标明“本内容基于公开数据的客观整理,不构成投资建议”。省得用户把分析报告当操作指令,我以为这是底线思维,不搞容易出问题。
结束语
这个项目做下来,我最大的体会是:RAG和智能体从来不是互相替代的关系,而是解决不同层面问题的组合。RAG解决“模型不知道”的尴尬,智能体解决“只回答不行动”的局限。真正难的不是某一个环节的先进程度,而是数据、索引、检索、生成、工具调度这条链路能否在业务场景里闭合。如果这篇文章能帮你少踩几个坑,那我这套复盘的价值就已经到达了。后续我打算把“可复用RAG知识库设计模板”整理成一套更清晰的文档,到时候再拿出来继续分享。