ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于RAG的A股智能选股Agent开发复盘:从知识库到决策链路

基于RAG的A股智能选股Agent开发复盘:从知识库到决策链路 最近把基于RAG的A股智能选股分析智能体从零到一完整走了一遍包括数据清洗、知识库构建、检索链路、Agent决策框架和最终的回测验证。这篇文章不是项目说明书而是把整个开发过程复盘一遍重点讲清楚每个环节为什么这么做、实际调试中会遇到什么问题。尤其是RAG部分很多教程只讲“装个LangChain、调个向量库、跑通demo”真到要做出一个能稳定输出的选股智能体时细节全在检索质量、上下文组装、工具调用的可靠性上。这个项目适合三类人看一是想用RAG做垂直领域知识库的开发者二是想给Agent接入真实数据和决策逻辑的朋友三是对A股量化投研方向感兴趣、但不想碰复杂数学模型的入门者。我不提代码层面怎么调API而是把设计思路和踩坑过程拆开讲。全程基于公开市场和公开数据智能体的所有输出都只是分析辅助不构成任何投资建议。1. 项目背景与需求拆解1.1 为什么选“A股智能选股”这个场景A股市场的公开信息量非常大财报、公告、研报、新闻、行业政策每天都产生大量文本数据。一个人的精力完全无法持续跟踪几千只股票更不要说在短时间内把某只股票的基本面、近期事件、行业位置和资金动向串起来形成判断。传统量化选股依赖结构化因子比如PE、PB、ROE、动量指标但结构化因子有个明显短板它抓不住公告措辞变化、研报里的投资逻辑、新闻事件背后对产业链的影响。这些问题恰恰是文本里承载的。RAG检索增强生成适合干这件事。它的核心思路是先把大量非结构化文本切分成片段、向量化、存入知识库用户提问时先检索出相关片段再把片段灌给大模型做回答。这样既能让大模型基于真实数据输出也能避免它凭空编造。把RAG和智能体结合等于在“读得懂文本”和“调用工具做计算”之间搭了一座桥。选股智能体不只是回答问题它能主动调用财务数据接口、行业板块接口、行情接口结合知识库里的研报和公告内容生成一份带数据支撑的分析结论。这个需求如果只用普通聊天机器人做最后输出一定是一碗“正确但空泛”的鸡汤。必须有RAG层提供事实依据必须有工具层提供可计算的指标才能让“智能选股”四个字落地。1.2 智能体能力拆解与边界确认动手前我把智能体的能力边界画清楚了。它不是一个自动交易机器人而是一个“分析型智能体”。主要提供四类能力基本面快速画像给定股票代码或名称输出主营业务、财务核心指标、最新业绩变化。事件驱动解析分析最新公告、研报中的关键信息解释事件对公司的潜在影响。横向对比分析把若干只股票从盈利能力、成长性、估值水平、行业地位等维度做对比。风险提示扫描从知识库和公告文本中提取质押、诉讼、减持、审计意见异常等风险信号。为什么要把边界定得这么具体因为Agent项目最怕的就是“什么都会”的错觉。范围一旦模糊用户问一句“帮我看看买哪个”大模型可能会基于幻觉直接给出建议这在金融场景里非常危险。我在系统Prompt里写死了“不构成投资建议”的兜底逻辑同时规定所有涉及数字的表达必须来自检索结果或工具返回值不允许模型自己推导具体数值。1.3 技术选型背后的取舍逻辑整体架构采用“数据层 知识库层 Agent调度层 模型层”的四层设计。数据层使用公开的A股数据源包括日线行情、财务摘要、公告全文、新闻资讯。行情和财务数据走结构化接口公告和新闻走文本采集通道。知识库层负责把文本数据切分、清洗、向量化并存储索引。我对比了FAISS、Milvus和Elasticsearch的向量能力最终选了Milvus。原因很简单项目后续不需要频繁更新全部索引Milvus支持增量写入而且它自带的HNSW索引在几十万条文本片段规模下查询延迟能控制在几十毫秒。如果数据量只有几万条FAISS完全够用没必要上重组件。Agent调度层我没有直接上LangChain完整框架而是用LangGraph自己编排状态流转。理由是选股这个场景需要确定性的分支逻辑比如先查工具、再查知识库、最后融合输出每一步的依赖关系很清晰。LangGraph能让我显式控制节点状态避免框架封装过深导致难以调试。模型层拆成两个角色。检索增强生成的主模型负责理解和输出一个轻量分类模型负责意图识别。这样主模型上下文更干净输出质量更稳定。这不是唯一方案但适合“要快速上线、又不想被框架绑定”的情况。如果你团队对LangChain非常熟用它也能做只是要做好定制的心理准备。2. 知识库构建RAG系统的基础工程2.1 数据采集与清洗决定检索上限RAG有一个被低估的关键点知识库的质量直接决定检索质量而检索质量直接决定模型输出质量。最开始我拿到的原始公告数据是混着PDF页眉、页脚、表格错位的文本直接切分向量化之后检索出来的片段经常是一堆半句话模型根本读不出有效信息。所以我在数据清洗上花的时间比预计多一倍。具体做了这几件事把PDF和其他格式的文档统一转成纯文本再用正则去除页眉页脚、重复行、表格错位符。针对财报和公告做结构化拆分。一份财报里有“财务摘要”“管理层讨论”“风险提示”多个段落直接机械切分会把完整逻辑切碎。我按一级标题和二级标题边界切块保证每个片段内有相对完整的语义。数据时效标记。每条文本入库时打上发布日期检索时按时间衰减加分避免三个月前的旧研报覆盖近期信息。去重。很多新闻源会转载同一篇内容我用SimHash做了近似去重把重复片段直接踢掉。这一步让知识库体积减少了约18%但检索精度提升很明显。清洗后的数据才是切分和向量化的输入。这个教训很朴素RAG系统里“垃圾进垃圾出”效应比传统模型更致命因为检索环节会把噪声放大。2.2 切分策略不是所有文本都用同一把尺子文本切分直接决定检索单元的粒度。最开始我用固定长度切分按256字符为一个chunk效果很差。因为公告里一个财务句子可能超过200字固定切分把“营业收入增长率”和“净利润增长率”这两组数据拆到两个片段检索时只命中一半模型的回答就变成单向维度出现明显偏颇。后来改成按结构边界切分主体逻辑是先按标题拆分出顶级段落。段落过长时再按句子边界二次切分每段保持256到512个token之间。设置相邻chunk之间40到80个token的重叠保证跨段信息的连续性。为什么设置重叠因为一句话的语义边界可能刚好落在切分点上重叠部分相当于留了一条“安全缓冲带”让检索能找回来一半的上下文。调参时可以从chunk_size512、overlap64起步再根据检索命中情况微调。数据量越大越建议保留结构化切分逻辑而不是盲目增加重叠比例。2.3 向量化、索引与混合检索向量模型用的是开源中文Embedding模型维度为1024。选型标准不是排行榜分数而是它对金融中文文本的语义理解能力。我跑了一个小测试集用“业绩预增”“股东减持”“资产重组”等典型短语做检索对比了三个模型效果差异比想象中大有的模型对新闻口语化表达更好有的模型对财报书面语更好选股场景必须优先照顾财报和公告文本。向量化之后我建的是“向量检索 关键词检索”的混合检索。原因很简单向量检索擅长语义相似但对“ROE大于20%”这类精确条件不敏感BM25关键词检索虽然不理解语义但能准确匹配“ST”“退市”“商誉减值”这种硬信号。两类结果用RRF融合算法合并排序重新排序后的Top结果才送入大模型。检索方式擅长场景弱项在选股场景中的用法向量检索语义相似、同义改写精确数字和代码匹配差检索“业绩下滑原因”这类泛化问法BM25关键词专业术语、代码、数字无法理解同义表达检索“商誉减值”“st”这类硬标签RRF融合综合两者优势需要调权重统一排序后送给重排模型顺序上先召回Top 50候选再用reranker模型压缩到Top 5。这一步非常值得做因为直接取向量检索的前几名经常会把同一份公告的好几个片段都排进来信息冗余严重。Reranker能把真正核心的片段提到最前面上下文里就能多塞几个不同来源的片段回答的信息密度立刻上来。2.4 防止RAG幻觉的三道保险RAG不是万能的它不应该成为放弃调优的借口。我上了三道保险检索内容必须带来源最终输出需要以“光标引号”形式引用来源片段不允许模型在没有检索结果的情况下直接陈述细节。检索不到相关内容时模型必须明确说“知识库中暂无相关信息”而不是编造一个答案。数值类问题强行引导到工具调用比如用户问“PE多少”Agent直接调结构化接口拿数据不依赖文本片段里可能过期的数值。这三道保险让系统的“胡说率”大幅下降。实际测试中主模型在纯RAG模式下偶尔还会把两篇公告内容混在一起加了“引用来源片段必须成句”的约束之后混种出错明显减少。关键不是要模型写论文而是让它形成一种“有据才说”的条件反射。3. 选股智能体核心逻辑与实操实现3.1 Agent状态机设计与工具注册Agent调度层的状态流我画了五个节点意图识别、参数抽取、工具调用、知识库检索、生成回答。节点之间是条件连线比如意图识别判定为“需要最新行情”就走行情工具节点判定为“需要基本面”就走财务接口和知识库双重通道。工具注册遵循“窄接口、单一职责”原则。每个工具只做一件事get_quote获取指定股票最新价格、涨跌幅、换手率。get_financials获取财务指标比如营收、净利润、ROE、毛利率。get_announcements从知识库检索最近公告返回结构化摘要。get_industry_compare对比股票所属行业主要竞争对手的估值和盈利能力。为什么工具入口要窄因为智能体的工具选择依赖大模型的意图判断工具说明越复杂模型越容易选错。每个工具的description我写得像操作手册输入参数范围、输出格式、典型召回场景。实际测试下来窄接口比一个“万能查询工具”的准确率高很多后者看起来省事实际是大模型最驾驭不了的东西。3.2 用RAG增强选股决策的完整链路完整的决策链路是这样的用户输入“帮我看看宁德时代和比亚迪的财报表现结合最近的行业消息做个对比”。意图识别节点Token分类模型识别出“对比”“财报”“行业消息”三个意图标签权重分数够了才往后续节点传。参数抽取节点从问题中抽出两只股票名称映射到股票代码。这里用了一个简单的映射表因为大模型直接抽代码容易抽成公司名本身。工具调用节点并行调用get_financials获取两家公司的核心财务指标拿到的是结构化JSON。知识库检索节点将“宁德时代 财报”“比亚迪 财报”“动力电池行业 政策 动态”拆成多个检索query分别走向量库召回相关公告和研报片段。生成回答节点把工具返回的报表数据加上检索到的文本片段塞进Prompt模板。模板规定先摆数据、再写分析、最后单列“外部信息来源”区块。这条链路的核心特征是“数据与文本分离”。数值走API逻辑和背景走RAG各司其职。对比纯大模型回答带数据支撑的输出准确性高很多对比纯SQL查询又能多出“行业政策方向”“管理层对业绩的解释”这类非结构化信息。3.3 Prompt工程系统指令里的隐性条件Prompt在这个项目里不是简单写个“你是专业人士”而是用来控制Agent行为边界的配置文件。我在System Prompt里写清了以下几点角色约束你是研究助理不是投资顾问禁止对具体买入卖出行为表态。信息优先级工具返回值优先于知识库检索内容知识库检索内容优先于模型自身知识。数值处理规则所有数字不四舍五入到“约”要求精确列出来源。输出结构必须使用“基本面概览”“业绩亮点”“风险信号”“综合分析”分段输出。反问规则用户给的股票信息不完整比如只说“新能源”没给代码则必须列出可能对象并询问确认。其中“信息优先级”这条最关键。大模型有个惯性碰到自己“熟悉”的上市公司容易直接把记忆里的数据写出来。如果工具返回的PE是30倍而模型记忆是20倍它很可能偷偷按记忆写。我用“必须给出原始数值来源编号”的方式强制它用工具结果效果立竿见影。3.4 从原型到回测量化效果而非手感智能体单次回答质量需要量化评估不能只看几个案例觉得“还行”。我搭了一套简单的离线评估管道准备70个问题覆盖基本面、事件、对比、风险四类请有金融背景的人给回答打分机器人每次运行后自动记录检索到的片段来源、工具调用次数、最终回答结构完整性。最重要的指标是“回答中数值与知识库来源一致的比例”。这个指标能直接暴露模型幻觉。评估维度通过标准实测结果数值一致性抽查20个指标回答与来源完全匹配占比≥90%第一版65%第二版92%工具调用正确率意图需要调用工具的问题中工具选择正确占比≥95%第一版82%第二版96%回答完整度四段式结构不缺失每段有实质内容占比≥85%第一版70%第二版90%风险信号覆盖率预设风险问题中智能体能主动识别并输出的占比≥70%第一版58%第二版76%回测则用历史公告和行情数据构造了一个简化场景让智能体在每个季度初基于当时可得的公告和财报生成一份“关注清单”再对比该季度后实际涨幅。这里必须注意存活者偏差和未来函数的问题我是严格按照公告发布日期截取数据绝不让模型使用当季结束后才出现的信息。结果虽然不能代表什么超额收益但能证明流程跑得通数据链路没有严重的时序错位。4. 开发过程中的典型问题与排查实录4.1 乱象一检索全命中回答全是废话第一版链接好之后遇到的最让人崩溃的问题是检索出来的片段确实都相关但大模型把这些片段堆在一起输出像在抄书没有观点、没有结构。后来发现是Prompt里缺少了“结构化提炼”的指令模型默认把检索内容当成要复述的文本。解决方案是把检索结果从“原文”变成“素材”。我在组装上下文时每个片段前面加了一个元信息标签比如“片段来源XX公司2024年中报发布时间2024-08-30情绪标签积极”。模型在生成时可以总结提炼并引用来源而不是整段照搬。这个改动让输出质量立刻提升一个档次也避免了模型同时引用多份公告时原文过长的问题。4.2 乱象二工具返回值互相矛盾智能体同时调用行情接口和财务接口后经常出现“PE为负但净利润为正”这种逻辑矛盾。排查后发现是不同工具的更新时点不一样行情有实时值财务可能是截止上一报告期的值。如果不对齐时间口径模型只会按照字面意思是两个数字都正确却看不出内部口径冲突。解决方法是给所有工具结果增加“数据日期”和“口径说明”字段并在Prompt中强调“若各数据源时间口径不一致应主动说明并优先采用最近数据日期”。这个逻辑开始只是防御性的后来发现它其实是最有价值的产品功能普通用户根本意识不到不同数据源之间有时间差Agent主动指出这一点反而是专业性的体现。4.3 乱象三大模型在“不知道”时硬答RAG系统里最难解决的问题不是检索不到而是检索到了噪音内容模型还误以为那是正确答案。我们遇到过一只基本面尚可的股票模型检索到了一条几个月前的“减持计划公告”直接把它写进风险提示导致整段分析倾向性很强好像公司要出事。为了让Agent规避这类误判我在知识库层加了“信息时效权重”距离当前时间越近权重越高在生成层加了一个“证据强度”标签如果某条风险信号只来自单一来源且时间跨度超过三个月模型必须标注“该信号时效性存疑”。这一条在实际使用中比任何Prompt话术都顶用因为它直接从系统层面压制了噪声信息的影响。4.4 性能优化与工程化经验本地部署这套系统时最吃性能的不是大模型而是Embedding和Reranker。大模型调用走云端API延迟可控本地Embedding如果并发高CPU直接被占满。后来我把Embedding模型加载成常驻服务批量处理知识库更新在线查询时走单独的轻量线程池每秒并发控制在20以内。Reranker的推理时间约40ms/条初期全量重排Top 50很慢优化成“先粗排Top 30再重排”整体延迟从2.3秒降到1.1秒。向量库方面Milvus的默认索引参数不一定适合中文金融文本。我调了nlist和nprobenlist代表聚类中心数nprobe代表查询时探访的聚类数量。四五十万条数据规模下nlist1024、nprobe16能兼顾召回和性能。参数调之前检索延迟有250ms调之后降到60ms。如果你用的是FAISS记得开启IDMap以避免删除重建索引的成本增量更新体验会好很多。5. 复盘心得这几个坑提前知道能省两周时间5.1 RAG部分最容易被低估的工作量数据清洗和切分策略的实际工作量占了整个RAG链路开发的60%。很多项目一开始追求Embedding模型和向量库的选型但真正影响效果的是你喂给它的数据长什么样。建议任何一个做垂直领域RAG的人先花一周时间把原始数据格式、切分策略、清洗规则定清楚再碰代码。5.2 Agent的可控性比聪明更重要在金融场景下智能体的“幻觉率”是安全指标。与其追求回答的全面和华丽不如在一开始就给System Prompt加满约束条件同时给每一个工具返回值加上完整的数据来源和时效信息。这会让模型看起来“笨”一些但用户拿到的是有依据、能追溯的分析而不是一堆漂亮但没有出处的话。5.3 评估体系一定要提前建没有评估体系的项目后续每次换模型、换Embedding、改Prompt都只能靠人工浏览案例来判断好坏效率极低。我在第二版时就引入了离线评估集并且把“数值一致率”作为核心指标。后续每次修改跑一遍评估集看指标变化比翻聊天记录直观太多。再分享一个我后来养成的习惯把所有失败案例单独存成一个“badcase池”每轮迭代后重跑badcase池观察修正情况和新增回归问题。这种做法比看一堆正面示例更能反映系统真实水平强烈推荐给所有在调RAG和Agent的朋友。
返回列表