1. 从零拆解一个投资决策智能体的核心架构
1.1 这个系统到底在解决什么问题
先把场景说清楚。所谓“百亿token手搓的投资agent”,本质上是一套用大语言模型驱动、面向二级市场投研场景的自动化决策辅助系统。它要处理的核心矛盾是:一个投研团队每天要面对海量非结构化信息——财报、公告、研报、新闻、社交媒体情绪、宏观数据——而人的阅读带宽是有限的。传统做法是靠人海战术堆分析师,但覆盖度和响应速度始终有天花板。
这套系统想做的事,是把“信息采集→信息理解→逻辑推理→观点生成→风险校验”这条链路尽可能自动化。注意,我说的是“辅助”而不是“替代”,因为投资决策里最值钱的部分是判断力和仓位管理,这部分目前机器还接不住。但信息处理这一层,机器确实能做得比人快几个数量级。
为什么强调“百亿token”这个量级?因为一个真正能用的投研agent,不是问一句答一句的聊天机器人。它需要持续摄入大量文本,建立跨时间、跨标的的关联记忆,还要在每次决策时把相关上下文全部拉出来做推理。token消耗量级直接决定了系统的记忆深度和推理广度。百亿token意味着它处理过的语料规模已经远超任何单个人类分析师的阅读量。
适合谁来参考这套东西?我认为有三类人:一是想了解LLM在垂直金融场景怎么落地的工程师;二是想用AI工具提升投研效率的从业者;三是对agent架构设计感兴趣的产品经理。哪怕你不做投资,这套“感知-记忆-推理-行动”的架构思路放到任何信息密集型行业都能迁移。
1.2 整体架构的分层设计
我先把这套系统的骨架拆开给你看。它不是一个单体模型,而是多个模块协同工作的流水线。从上到下大致分四层:
第一层是数据接入层。负责把各种来源的原始数据拉进来——结构化数据(行情、财务指标)走API,非结构化数据(公告、新闻、研报)走爬取和订阅。这一层的关键不是“能拉到数据”,而是“拉到之后怎么标准化”。不同来源的财报格式千差万别,有的用PDF有的用HTML,表格结构还不一样。我的做法是先做一层统一的文档解析,把PDF、HTML、纯文本全部转成带结构标记的中间格式,再往下游送。
第二层是记忆与检索层。这是整个系统最核心的基础设施。百亿token的语料不可能全部塞进上下文窗口,所以必须做向量化存储+分层检索。具体来说,把每段文本切成合适粒度的chunk,用embedding模型转成向量存进向量数据库。检索时不是简单做相似度匹配,而是结合时间衰减、来源权重、标的关联度做多路召回。举个例子,你问“某公司最近的经营状况”,系统不能只召回语义最相似的段落,还要把最近三个月的公告、最近一周的新闻、以及同行业可比公司的数据一起拉出来。
第三层是推理与决策层。这是agent真正“动脑子”的地方。它接收检索层送来的上下文,按照预设的推理框架做分析。这里有个关键设计:不是让模型自由发挥,而是用结构化提示词约束推理路径。比如分析一家公司,强制走“行业景气度→公司竞争地位→财务健康度→估值合理性→风险因素”这条链。每一步都有明确的输出格式要求,避免模型跑偏。
第四层是输出与校验层。模型生成的观点不能直接推给用户,必须过一道校验。校验包括事实一致性检查(生成的内容是否和检索到的原文矛盾)、逻辑自洽性检查(前后结论是否打架)、以及合规性过滤。这一层还负责把最终结果格式化成人类可读的报告或结构化数据。
1.3 为什么选择这种架构而不是端到端微调
有人可能会问:为什么不直接拿一个大模型做端到端微调,输入问题直接输出答案?我试过,效果不好。原因有三个:
第一,金融数据的时效性太强。微调是把知识固化在权重里,但财报每季度更新、新闻每天在变,你不可能天天重新训练模型。用检索增强生成(RAG)的方式,知识存在外部数据库里,更新数据只需要更新库,不用动模型。
第二,可解释性要求高。投资决策必须能追溯依据。端到端模型给你一个“买入”结论,你问它为什么,它可能编一个听起来合理但实际不存在的理由。而分层架构下,每个结论都能对应到具体的检索片段和推理步骤,方便人工复核。
第三,成本可控。微调大模型的算力成本极高,而且每次迭代都要重新来过。分层架构下,你可以只优化检索策略或提示词模板,不用动底层模型,迭代速度快得多。
注意:分层架构的代价是工程复杂度上升。你需要维护数据管道、向量库、检索服务、推理服务等多个组件,任何一个环节出问题都会影响最终输出。所以这套方案更适合有一定工程能力的团队,个人开发者想快速验证想法的话,可以先从简化版做起。
2. 记忆系统的工程实现细节
2.1 文档解析与分块策略
记忆系统的第一步是把原始文档变成可检索的片段。这一步看着简单,实际上坑最多。我踩过的坑包括:PDF里的表格解析出来全是乱码、HTML里的正文和导航栏混在一起、同一份财报在不同来源的格式不一致导致重复入库。
我的解决方案是多解析器级联+人工规则兜底。具体流程是:先用通用解析库做第一遍提取,如果提取结果的文本密度低于阈值(说明可能解析失败),自动切换到备用解析器。对于表格,单独走表格识别流程,把表格转成Markdown格式再入库,这样检索时能保留行列关系。
分块策略上,我没有用固定长度的滑动窗口,而是按语义边界切分。具体做法是:先按段落切,如果段落超过一定长度(比如800字),再按句子边界切。每个chunk保留前后各一段的上下文作为“重叠区”,避免检索时丢失跨段落的逻辑关系。chunk的大小控制在300-600字之间,这个粒度在检索精度和上下文完整性之间比较平衡。
还有一个细节:每个chunk都要打上元数据标签,包括来源类型(公告/新闻/研报)、时间戳、关联标的、置信度权重。这些标签在检索时用来做过滤和排序。比如你查某公司的最新动态,系统会优先召回时间戳近的、来源权威的chunk。
2.2 向量化模型的选择与调优
embedding模型的选择直接决定检索质量。我对比过几种方案:通用文本embedding模型、金融领域微调过的embedding模型、以及直接用大模型做embedding。
通用模型的问题是对金融术语不敏感。比如“毛利率下滑”和“盈利能力承压”在通用模型里可能相似度不高,但在投研语境下它们说的是同一件事。金融领域微调过的模型在这方面表现好很多,但获取成本较高。
我最终采用的方案是:用通用模型做基础embedding,再加一层轻量级的领域适配。具体做法是收集一批金融领域的同义表述对,用对比学习的方式微调一个小的适配层,加在通用模型后面。这样既保留了通用模型的泛化能力,又提升了领域内的语义匹配精度。
另一个关键是多向量表示。同一段文本,我用不同的提示词模板生成多个embedding,分别侧重“事实描述”、“观点判断”、“数据指标”等不同维度。检索时根据查询意图选择对应的向量空间。比如你问“某公司营收多少”,走数据指标向量;你问“市场对某公司怎么看”,走观点判断向量。
2.3 分层检索与重排序
检索不是一步到位的。我的做法是三路召回+重排序:
第一路是向量相似度召回,从向量库里找语义最接近的top-K片段。第二路是关键词召回,用BM25等传统方法找包含特定术语的片段,弥补向量检索对精确匹配不敏感的缺陷。第三路是图谱召回,沿着标的关联关系(上下游、竞争对手、同概念板块)扩展检索范围。
三路召回的结果合并后,送进一个重排序模型做精排。重排序模型是一个交叉编码器,它同时看查询和候选片段,输出一个相关性分数。这一步比单纯的向量相似度准得多,但计算量大,所以只对召回后的少量候选做。
实操心得:重排序模型的推理延迟是整套系统里比较高的环节。如果对响应速度有要求,可以只对top-N做重排序,N控制在20以内。另外,重排序模型可以离线预计算一部分,比如对高频查询的候选集提前算好分数缓存起来。
2.4 记忆的更新与遗忘机制
一个容易被忽略的问题是:记忆不是越多越好。过时的信息会干扰推理。比如一家公司三年前的战略和现在的战略可能完全相反,如果检索时把旧信息也拉出来,模型可能会得出矛盾结论。
我的做法是引入时间衰减因子。每个chunk在检索评分时乘以一个基于时间差的衰减系数,时间越久权重越低。但衰减不是一刀切的——财报数据的半衰期长一些(比如一年),新闻的半衰期短一些(比如一周)。这个半衰期参数需要根据实际场景调。
另外还有主动遗忘机制。当系统检测到某个信息被后续信息明确推翻时(比如公司发布了更正公告),旧信息的权重会被手动调低或标记为失效。这个机制目前还需要人工介入,完全自动化做容易误伤。
3. 推理引擎的提示词工程与决策链路
3.1 结构化推理框架的设计
推理引擎的核心不是模型本身,而是怎么组织提示词让模型按正确的方式思考。我试过让模型自由分析,结果它经常跳步——直接从“营收增长”跳到“建议买入”,中间缺少竞争分析和估值判断。后来我设计了一套强制性的推理框架,每一步都有明确的输入输出要求。
以分析一家公司为例,推理链路分五步:
第一步:行业定位。输入是行业数据和公司业务描述,输出是公司在产业链中的位置、主要竞争对手、行业景气度判断。这一步的目的是建立分析坐标系,避免后面就公司论公司。
第二步:竞争力评估。输入是公司的财务数据、市场份额、技术壁垒等信息,输出是护城河的宽度和可持续性判断。这里我会要求模型引用具体的财务指标来支撑结论,不能空泛地说“竞争力强”。
第三步:财务健康度扫描。输入是三张报表的关键科目,输出是盈利能力、偿债能力、运营效率、现金流质量四个维度的评分和异常项提示。这一步有大量的计算,我会让模型先做计算再下结论,避免它凭感觉编数字。
第四步:估值判断。输入是当前估值指标和历史估值区间、可比公司估值,输出是估值处于什么分位、是否合理。这里会强制模型给出估值方法和关键假设,方便人工复核。
第五步:风险清单。输入是前面四步的所有输出,输出是可能推翻前面结论的风险因素,按概率和影响程度排序。这一步是防止模型过度自信的关键。
每一步的输出都会作为下一步的输入,形成一条完整的推理链。最终报告里会保留每一步的中间结论,方便追溯。
3.2 提示词模板的迭代与版本管理
提示词不是写一次就完事的。我维护了一个提示词版本库,每次修改都记录改了什么、为什么改、改之前和改之后的效果对比。这个习惯看起来繁琐,但当你发现某个版本的效果突然变差时,能快速定位到是哪次修改引入的问题。
提示词迭代的主要方向有三个:
一是减少幻觉。早期版本里模型经常编造不存在的财务数据。后来我在提示词里加了硬性约束:“所有数字必须来自提供的上下文,如果上下文里没有,明确说‘数据缺失’,禁止推测。”这个约束加上之后,编数字的情况大幅减少。
二是提升推理深度。早期版本的分析比较浅,停留在“营收增长所以公司不错”的层面。后来我加入了“追问机制”——要求模型对每个结论都问一句“为什么”和“还有什么可能”,逼它做更深层的思考。
三是统一输出格式。不同查询的输出格式不一致会导致下游处理困难。我在提示词里定义了严格的输出模板,包括章节标题、表格格式、评分标准等,确保每次输出都是结构化的。
3.3 多模型协同与投票机制
单一模型容易有偏见。我的做法是用多个模型并行推理,然后做投票或加权融合。具体来说,同一个查询同时发给三个不同的大模型,每个模型独立生成分析结论。然后有一个聚合模块,对比三个结论的异同。
如果三个结论高度一致,直接采纳。如果分歧较大,聚合模块会分析分歧点在哪里,是数据解读不同还是推理逻辑不同,然后把分歧点标注出来供人工判断。这种机制能有效降低单一模型的系统性偏差。
代价是推理成本翻了三倍。所以实际使用中,我会根据查询的重要性分级——重要的深度分析走多模型投票,日常的快速查询走单模型。
注意:多模型投票的前提是模型之间要有足够的差异性。如果三个模型都是同一家公司的不同版本,投票意义不大。我选的是不同技术路线的模型,确保它们的错误模式不相关。
3.4 推理过程的中间态记录与回放
这套系统有一个我觉得很值的设计:完整记录每次推理的中间态。包括检索到了哪些片段、每个片段的评分是多少、模型每一步的输入输出是什么、最终结论是怎么聚合出来的。
这个记录有两个用途。一是调试:当输出有问题时,可以回放整个推理过程,定位是检索环节漏了关键信息,还是推理环节逻辑跑偏。二是审计:投资决策需要留痕,完整的推理记录可以作为决策依据的存档。
记录格式我用的是结构化的JSON,每个步骤一个对象,包含时间戳、步骤类型、输入摘要、输出摘要、耗时等字段。这些记录存在独立的日志库里,不占用主数据库的空间。
4. 实战中的典型问题与排查手册
4.1 检索质量问题的排查思路
检索是整套系统的地基,检索出问题后面全错。我遇到过的检索问题主要有三类:
第一类是召回不足。明明库里有相关信息,但检索没拉出来。原因通常是embedding模型对某些表述不敏感,或者chunk切分把关键信息切断了。排查方法是:拿一个已知答案的查询,手动检查库里相关片段的位置,看检索评分是多少。如果评分很低,说明embedding需要调优;如果片段根本没被切出来,说明分块策略有问题。
第二类是召回过多噪声。检索拉出来一堆不相关的片段,干扰模型判断。这通常是相似度阈值设得太低,或者元数据过滤没做好。解决办法是提高重排序的权重,让精排模型把噪声压下去。另外可以在检索时加更严格的元数据过滤,比如限定时间范围或来源类型。
第三类是时效性问题。检索到的信息太旧,和当前情况不符。这需要检查时间衰减因子的参数是否合理,以及数据更新管道是否正常工作。
下面这张表是我整理的检索问题速查表:
| 现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| 召回不足 | embedding不敏感 | 手动检查已知答案片段的评分 | 微调embedding或增加关键词召回 |
| 召回不足 | chunk切分不当 | 检查关键信息是否被切断 | 调整分块粒度或增加重叠区 |
| 噪声过多 | 相似度阈值过低 | 统计召回片段的平均相关度 | 提高阈值或加强重排序 |
| 噪声过多 | 元数据过滤缺失 | 检查召回片段的来源和时间分布 | 增加元数据过滤条件 |
| 时效性差 | 衰减因子不合理 | 对比新旧信息的检索评分 | 调整半衰期参数 |
| 时效性差 | 数据管道延迟 | 检查最新数据的入库时间 | 修复数据更新流程 |
4.2 模型幻觉的识别与抑制
幻觉是LLM落地金融场景最大的风险。模型会编造财务数据、虚构新闻事件、甚至捏造不存在的公司关系。我总结了三种识别幻觉的方法:
一是交叉验证。模型生成的每个事实性陈述,都回到检索库里查证。如果检索库里找不到支撑,标记为“待核实”。这个步骤可以自动化,用另一个模型做事实检查。
二是数字一致性检查。财务数据是最容易出幻觉的地方。我会把模型输出里的所有数字提取出来,和检索到的原始数据做比对。不一致的标红提示。
三是逻辑链检查。如果模型的结论和推理过程不匹配(比如推理说“营收下滑”但结论说“业绩向好”),说明中间有逻辑断裂,需要人工复核。
抑制幻觉的根本方法还是约束模型的输出空间。我在提示词里明确要求:“只使用提供的上下文信息,不确定的内容标注‘不确定’,禁止编造。”同时降低模型的temperature参数,减少随机性。
4.3 性能瓶颈的定位与优化
这套系统在规模上来之后,性能瓶颈会出现在几个地方:
向量检索的延迟。当向量库达到千万级别时,单次检索可能超过一秒。优化方向包括:使用近似最近邻算法(如HNSW)替代精确检索、对向量做降维、增加缓存层。
重排序的计算量。交叉编码器的推理是O(n)复杂度的,候选集越大越慢。优化方法是先用轻量级模型做粗筛,只对top候选做精排。
大模型推理的吞吐。如果并发查询多,模型推理会成为瓶颈。解决办法包括:使用推理加速框架、对高频查询做结果缓存、以及把非实时任务放到离线队列里跑。
数据管道的积压。当新数据大量涌入时,解析和入库可能跟不上。需要做背压控制,或者增加解析节点的并行度。
实操心得:性能优化不要一上来就做,先用监控工具定位真正的瓶颈在哪里。我见过有人花大力气优化向量检索,结果发现瓶颈其实在数据解析环节。先测量,再优化。
4.4 成本控制的实战经验
百亿token的量级意味着成本不是小数目。我在成本控制上主要做了这几件事:
分级处理。不是所有查询都需要走完整链路。简单的事实查询走轻量级模型+缓存,只有复杂的分析请求才走完整的多模型投票流程。
缓存策略。高频查询的结果缓存起来,下次同样或相似的查询直接返回缓存。缓存的失效策略要设计好,避免返回过时信息。
批处理。非实时任务(如每日报告生成)攒成一批一起处理,比单条处理效率高得多。
模型选择。不是所有环节都需要用最大的模型。检索、分类、格式化这些任务用小模型就够了,只有核心推理环节用大模型。
下面这张表是我实际运行下来的成本分布,供参考:
| 环节 | 成本占比 | 优化空间 |
|---|---|---|
| 向量检索 | 15% | 中,主要是计算资源 |
| 重排序 | 10% | 中,可缓存 |
| 大模型推理 | 55% | 大,模型选择和缓存是关键 |
| 数据解析入库 | 12% | 小,主要是工程优化 |
| 日志与监控 | 8% | 小 |
5. 系统扩展与场景迁移的思考
5.1 从单一市场到多市场扩展
最初这套系统只覆盖一个市场,后来要扩展到多个市场时,发现不是简单加数据源就行。不同市场的披露规则、财务准则、交易机制都不一样。比如有的市场财报是季度披露,有的是半年度;有的用自然语言描述为主,有的表格数据更多。
我的做法是抽象出一层“市场适配器”。每个市场实现自己的数据解析逻辑、财务科目映射、以及特定的推理规则。核心的检索和推理引擎保持不变,只通过适配器接口对接不同市场的数据。这样扩展新市场的成本主要在于写适配器,不用动核心代码。
5.2 从投研辅助到其他信息密集型场景
这套架构的核心是“大规模信息摄入+结构化推理+可追溯输出”,这个模式不限于投资场景。我后来把这套思路迁移到了几个其他场景:
合规审查场景。输入是大量的法规文件和内部制度,输出是某项业务是否合规的判断和依据。架构基本不变,只是把财务分析框架换成了合规检查清单。
技术情报场景。输入是论文、专利、技术博客,输出是技术趋势判断和竞争格局分析。检索层需要针对技术术语做优化,推理层需要加入技术成熟度评估框架。
舆情监控场景。输入是社交媒体和新闻,输出是舆情态势和风险预警。这个场景对时效性要求更高,需要调整时间衰减参数和流式处理能力。
迁移的关键是把领域相关的部分抽象成可配置的模块。检索策略、推理框架、输出模板都可以做成配置项,换场景时只改配置不改代码。
5.3 人机协作的边界设计
这套系统运行一段时间后,我越来越清楚哪些事该机器做、哪些事必须人来做。
机器擅长的:大规模信息扫描、跨文档关联、数据计算、格式化输出、7x24小时不间断运行。
人擅长的:非共识判断、对管理层质地的感知、极端情况下的决策、以及承担决策责任。
所以系统的定位是把分析师从信息处理中解放出来,让他们把时间花在真正需要人类判断的地方。系统输出的报告不是最终结论,而是“经过整理的决策素材”。分析师可以快速浏览系统整理好的要点,然后用自己的判断力做最终决策。
这个边界设计很重要。如果系统试图替代人的判断,一方面技术上做不到,另一方面责任也无法界定。明确边界之后,系统的价值反而更清晰——它不抢分析师的饭碗,它让分析师的工作更有价值。
5.4 持续迭代的机制建设
最后说说怎么让这套系统持续变好。我的做法是建立反馈闭环:
每次系统输出报告后,分析师可以标注哪些部分有用、哪些部分有误、哪些部分缺失。这些标注数据定期汇总,用来优化检索策略和提示词模板。同时,系统会记录分析师的修改动作——比如分析师把某个结论从“中性”改成了“谨慎”,这个修改会被记录下来,作为后续优化的信号。
另外,我会定期做回测验证。把系统在历史时点上的输出和实际发生的情况做对比,看系统的判断准确率如何。这个回测不是为了证明系统多准,而是为了发现系统在哪些类型的判断上容易出错,然后针对性改进。
这套机制运行下来,系统的输出质量是逐步提升的。但我也要诚实地说,提升不是线性的,有时候改了某个地方反而引入了新问题。所以迭代要有耐心,每次只改一个变量,改完观察一段时间再决定下一步。
我个人在实际操作中的体会是,做这类系统最忌讳的是追求一步到位。先跑通最小闭环,哪怕检索粗糙一点、推理浅一点,只要端到端能跑通,就能开始积累反馈。有了反馈,迭代才有方向。反过来,如果一开始就追求完美架构,很可能在工程细节里陷太久,迟迟看不到实际效果,最后不了了之。先让它跑起来,再让它跑得好。