我知道现在很多人的第一反应是:既然上下文窗口越来越大,那就把公司公告、研报、宏观数据、电话会议记录全部塞给模型,让模型“自己总结”。这个思路听着很省事,实际跑起来就是灾难——上下文越堆越长,输出延迟越来越高,你根本不知道模型到底看了什么、没看什么,更别说知道它为什么会做出某个投资判断。我这次做的投资项目,前前后后处理了大概百亿token级别的原始文本,如果真按“全文灌进上下文”的做法来,单次调用成本就能让人破产,而且结论质量反而会下降。
所以整个项目从第一天起就弃用了“全量灌入”的思路,改用一套更工程化的架构:先对百亿token做降维和结构化,再交给智能体按需检索、分层记忆、循环决策。这篇文章就把整套工作流程拆开讲,包括数据管道怎么做、决策引擎怎么路由、记忆系统怎么切分、回测和成本怎么控制,以及我踩过的各种坑。不管你是想做一个研究辅助类的智能体,还是做量化的数据底座,这套思路应该都能给你一些参考。
1. 先说结论:百亿token的体感来自“三层坍缩”,不是“上下文灌满”
百亿token是什么概念?按中文平均每千字约1300个token估算,就是接近七八千万字的原始文本。它可以是某个行业过去十年的政策文件、上千家上市公司的定期报告、几万条新闻公告,甚至是音频转录后的电话会议记录。直接把这些塞进一个对话框,等于让一个分析师在一夜之间看完一家图书馆,而且要求他边看边形成判断。这不现实。
1.1 为什么“把数据全塞进去”是死路
先算一笔账:假设你有100亿token的原始语料,哪怕只采样其中10%作为上下文,那也是10亿token。以当前主流大模型API的价格和上下文上限来看,一次调用几乎不可能完成,更别说你还需要多轮交互。即便真有模型能一次性吃下,模型的注意力机制在极长上下文中也会出现“中段遗忘”现象——大量token挤在一起,关键信号被稀释,模型给出的判断实际上是在盲人摸象。
在真实投资场景里,这个问题的危害更隐蔽。研报和公告里最关键的往往不是那一句结论,而是数字之间的勾稽关系、时间线上的异常变化。全文灌入会让模型把注意力平均分配给所有句子,结果就是它可能会记住一句边角新闻,却忘了资产负债表上的重大恶化信号。这类错误在演示Demo里很容易被忽略,但放在真实决策里就是实质风险。
1.2 三层坍缩:去重、仓库化、工作负载切割
我的方案是让原始文本经历三层坍缩:
第一层是“去重折叠”。同一事件会被不同媒体反复报道,同一个财务数据会在季报、年报、公告里多次出现。系统先用哈希指纹加语义相似度做一次粗过滤,再结合实体级去重,把重复文本压掉。实测下来,百亿token的语料去重后往往能减少30%到50%,而且这部分几乎不损失信息量。
第二层是“仓库化”。去重后的文本不是拿来直接检索用的,而是先拆分成段落级片段,然后做实体识别、关系抽取、时间戳标注,最后全部灌进一个带图结构的知识仓库。查询时先用向量检索召回候选节点,再用图遍历把关联关系捞出来,而不是把整段原文扔给模型。
第三层是“工作负载切割”。不是所有问题都需要看所有资料。系统先判断“用户这问题到底在问什么”,再决定去调财报库、新闻库、宏观数据库里的哪几个子集。比如问“这家公司现金流为何恶化”,路由层会优先命中现金流相关的指标节点、管理层讨论段落、以及近期的重大公告,而不是把这家公司过去十年的全部文本都调出来。
这三层做完,百亿token的体量在实际推理中被压缩成每次调用只接触几十万到几百万token,成本、延迟、可控性全都回到合理区间。下面我一个个模块展开讲。
2. 数据接入层:从财报堆到带时间戳的知识图谱
这一层是整条链路的地基。投资智能体的输出质量,上限基本上由数据接入层的质量决定。模型再强也弥补不了“原料缺了一角”的问题。我花了整个项目大约40%的时间在这一层,不是没有原因的。
2.1 非结构化文档的标准化流水线
原始数据形态千奇百怪:PDF格式的年报里既有文字段落又有财务报表表格,网页新闻经常带广告和页面噪声,电话会议转录稿可能是MP3转出来的,里面全是口语停顿和错误断句。我最终搭的流水线长这样:
- 第一步是格式识别,按文件类型分流到不同的解析器。PDF走表格抽取加段落切分,网页走正文抽取,音频先经过语音转写再按发言人分割。
- 第二步是统一schema化,所有解析出来的内容都被转成统一的文档对象,字段包括:来源ID、发布时间、文档类型、实体列表、章节标题、正文片段、关联表格。
- 第三步是分块,按段落和句子层级切分索引块。分块大小并不固定,我按投资场景做了约束:财报里一个科目下的连续说明尽量保持在一个块里,太长则按小标题切;新闻则按事件段落切,保证同一个事件的前因后果在相邻块中。
这里有个容易被忽视的环节:表格解析。PDF里的资产负债表转成Markdown表格后,经常出现表头错位、跨页断裂,直接用OCR和文本抽取结果特别稀疏。我最后的做法是,先用通用解析器把页面结构抽出来,再把每一行“科目名—数值—同比变动”绑定成三元组,存成结构化节点,而不是让模型自行去理解一张歪七扭八的表格。这个改动对后续回答“某项指标变化了多少”这类问题有决定性影响。
2.2 实体解析与三元组抽取,解决“同一家公司三种写法”
原始文本里,同一家公司可能被写成“中远海运”、“COSCO”或“中远海控”;同一个指标可能叫“毛利率”也叫“Gross Margin”。如果直接按字面去建索引,后续查询召回率会很可怜。我在这里做了一个实体链接模块:
- 先用实体识别从文本里标出公司、人物、行业、指标、政策条例。
- 再做指称消解,把“公司”“该集团”“其”等代词挂到前文最近的实体上。
- 最后通过别名映射表统一到一个规范ID上。这个映射表不是手写的,而是从历史数据中挖掘共现关系自动生成的,再定期人工抽检修正。
实体链接做完之后,系统会继续抽取关系三元组。例如“某公司”与“另一家子公司”存在“全资控股”关系,“某指标”与“某行业均值”存在“对比下限”关系。这些三元组全部带时间戳,存储在知识图谱中,决策阶段用来做关联查询会高效很多。
2.3 质量门与人工审核闭环
数据接入最后一步至关重要:设置质量门。每一批入库的数据都要过三个检查项:覆盖率是否达标,即关键公司最新报告是否已经入库;字段完整性是否合格,比如核心财务指标有没有缺漏;交叉验证是否通过,即同样的财务数据是否和另一来源对得上。
我们跑了一段时间后发现,即使自动化程度很高,也仍然会漏掉一些压了很久的公告。于是又在管道末尾留了一个人工审核队列。对于覆盖率不达标、或者交叉验证不一致的数据,它会自动生成一张差异清单,由研究员确认后决定是否重新抓取或人工修正。这个环节让我对系统给出的结论有了基本的信任基础。
3. 决策引擎:路由链加循环检索,而不是一条提示词走到底
很多人在写投资智能体的时候,习惯把所有能力塞进一个系统提示词里,然后靠一次调用输出结论。这么做在演示环境里效果不错,一旦遇到真实数据就会漏洞百出,因为真实问题往往混合了多重需求——既需要看财务数据、又需要比较行业趋势,还要结合市场事件判断。
3.1 三个子代理的分工协作
我把决策过程拆成了三个角色,它们在自己的职责范围内独立运行,结果统一交给最终判断器汇总:
- 信息检索代理负责“找证据”,判断问题需要哪类资料,去知识图谱和向量库里召回候选片段,并返回带来源和置信度标注的结果。
- 分析计算代理负责“算数和建模”,它只拿到检索代理给出的结构化字段,不会自己去看原始新闻。它负责计算同比、环比、复合增长率,生成简单的估值区间。
- 论证代理负责“权衡”,它把前两个代理的结果拿过来,形成支持面与风险面的辩论结构。这个结构最后交给汇总环节,输出带条件概率的结论,而不是二元式的“买”或“不买”。
三个代理之间不是完全自由对话,而是靠消息队列传递结构化数据。每个代理都有自己独立的槽位约束:比如分析计算代理只接受数值型输入,不允许它去看原始文本。这个约束看似简单,实际避免了模型把一篇文章里的修辞当证据的毛病。
3.2 工作流状态机
为了保证每一步都可追踪,我把整个流程做成状态机:收到问题后先进入“意图识别”状态,然后是“检索”状态、“分析”状态、“论证”状态,最后落在“结论生成”状态。每个状态都有超时限制、重试次数、以及跳转条件。
举个例子,如果检索代理返回的证据置信度普遍低于0.6,状态机会触发“二次检索”,它会自动换一套检索配方,从事件序列和时间范围两个维度重新召回一批数据。如果二次检索依然不理想,它会把“低置信度”作为一个明确标记传给论证代理,让论证代理着重讨论信息不足可能带来的误判风险。
使用状态机还有一个隐形好处:调试的时候,任何一次异常回答都能回放整条链路,看到底是从哪个状态开始跑偏的。这在纯对话式架构里几乎做不到。
3.3 参数路由的条件逻辑
不是所有问题都值得动用最强的模型,也不是所有问题都需要展开漫长的多代理协作。我在路由层加了一套条件逻辑:
- 简单事实类问题(“某公司上年营收是多少”)直接走单次轻量模型调用,只查一个指标节点。
- 中度分析类问题(“某公司毛利率近三个季度变化趋势”)走检索加计算的双代理协作。
- 复杂判断类问题(“该笔并购案对两家公司的长期价值影响如何”)才启动完整的三代理流程。
这个动态路由的实际效果是,每月总调用量里大约70%走的都是轻量链路,中量链路占20%,重量链路只占10%。而成本恰好相反,重量链路占了总预算的70%。这套配置让有限的预算几乎全部花在了真正需要深度推理的问题上。
4. 双层记忆:操作记忆管手感,档案记忆管长逻辑
智能体如果没有记忆,每次对话都像第一次见面。但如果把所有历史都塞进上下文,又回到了最开始的“上下文灾难”。我最后采用的方案是把记忆切成两层,分别负责不同的时间尺度。
4.1 操作记忆:短时缓存与增量更新
操作记忆保存的是最近一次决策周期内的状态,比如当前正在研究哪组股票、最近检索了哪些关键词、此前三轮对话里得出了哪些临时结论。这个记忆层直接参与上下文,但容量很小,通常只保留最近不超过200个关键信息位。
为了不让操作记忆被无关信息污染,我设计了一套增量更新机制:每当一轮交互结束,系统会把新的“关键节点变化”差量写入记忆池。比如用户问过“现金流”之后又问了“折旧方式”,系统不会把这两轮的所有对话都缓存下来,而是只记录“关注点:现金流+折旧方式”这个压缩后的意图向量。下一轮如果用户问“这两项对公司利润影响”,系统就能凭借意图向量快速定位到相关分析,而不是靠回忆聊天记录。
4.2 档案记忆:动态摘要加时间衰减
长期记忆并不直接参与上下文,而是以“压缩摘要”的形式存放。系统定期对每家公司生成层级摘要:最底层是市场事件的短摘要,中间层是季度财务表现的篇章摘要,最高层是投资逻辑的整体档案。每次新数据入库,摘要不是重新生成,而是走“增量融合”路径——旧摘要保留主干,新信息只更新与它冲突或延伸的部分。
时间衰减在档案记忆里也起了重要作用。一条三年前的新闻对当前决策的影响,显然不应该和一个月前的新闻等权。系统给每条记忆节点都挂了时间衰减权重,并且设置了强制过期时间。通常超过两年且没有被近期数据关联激活的节点,会被移到冷存储,不再参与常规检索。这样既控制了知识库体积,也减少了无意义的召回。
4.3 冲突消解与版本回滚
档案记忆最麻烦的问题是冲突:同一家公司,六个月前的管理层所描述的扩张战略,和本次财报里表达的收缩态度完全相反。如果系统只是简单地把新摘要覆盖旧摘要,就会丢掉历史拐点的上下文。
我的做法是给每条摘要带一个版本字段和置信度字段。新信息权重更高,但不会直接覆盖旧版本,而是生成一个新版本节点,并在两者之间记录“转折原因”:通常是某个事件(如行业政策变化、管理层变更、突发事件)导致逻辑发生切换。当决策引擎需要分析这家公司时,它会同时看到旧逻辑和新逻辑,并额外看到一个“逻辑切换时间点”。这个设计实测对捕捉基本面拐点特别有效,比单纯给模型灌入所有历史文本要清晰得多。
5. 回测与可视化:先让人看得懂,再让模型跑得对
投资分析类智能体和普通问答机器人还有一个本质区别:它必须在真实历史数据上验证自己的判断有没有效。否则模型很容易在个别案例上表现惊艳,换个时间段就完全翻车。
5.1 回测的重心在“决策痕迹”而不是收益率
很多回测框架一上来就看净值曲线,收益率高就认为策略好。但在智能体场景里,真正有价值的不是最终收益,而是“决策痕迹”——模型在每个时间点看了什么数据、得出什么结论、给出的置信度是多少。
我把每轮决策的记录设计成审计日志:包括时间戳、引用文档ID、计算用的指标值、模型输出的完整理由、以及当时的置信度。回测时,系统会把新时期的真实数据“切掉”,让智能体在旧时点上做预测,再和后来的真实结果对比。这里的关键是防止未来信息泄露,所以在回测数据切片时,必须严格保证任何输入都早于判断时间点。
5.2 可视化面板由三层瀑布组成
为了让自己和团队能快速看明白智能体的行为,我搭了一个三层可视化面板:
- 第一层是“证据瀑布”,展示某一决策引用了哪些文档、文档的时间分布,用瀑布图直观暴露是否过度依赖某一条新闻,或者有没有重要时间段的证据空白。
- 第二层是“置信度轨迹”,展示同一标的不同时期给出判断的置信度变化。置信度突然上升或骤降,往往对应某个重要事件,这能帮助我们快速定位模型关注的焦点。
- 第三层是“胜率统计”,按行业、按时间周期、按数据源类型分桶计算命中率。只看总体命中率很容易被平均掩盖,拆到分桶后你才能发现,模型可能对某些行业特别擅长、对另一些行业则是瞎猜。
5.3 评估指标要拆分子集看
我刚开始回测的时候只看整体准确率,发现数值一直不错,后来一拆开就发现问题了。模型对消费行业的判断准确率很高,但对周期行业的判断几乎等于抛硬币。原因不复杂:周期行业的拐点,依赖的是宏观高频数据和政策预判,而我在数据层构建的并不完善。
这里有一个很容易踩的坑:市场里大部分公开文本是“牛市叙事”或“多头逻辑”,空头逻辑的文本相对更少。如果评估集不平衡,模型学到的其实是一种偏向正面的表态方式,而不是真正的预测能力。我在评估时强制按多空标签做分层采样,并且刷掉了混杂性太高的样本,这样最后的指标才比较可信。
6. 成本、延迟与稳定性:把Token预算压回服务器能接受的范围
模型能力再强,也需要把成本放进可运行的范围。这个项目处理百亿token的原始数据,但真正在推理阶段花出去的token远没有那么夸张。核心就一句话:能离线算的不要在线算,能一次拿到的不要反复问。
6.1 预算拆解与缓存策略
我统计过整条系统一个典型的月运转情况:数据接入层离线跑批,每月只产生少量解析token费用;在线推理层大概消耗5000万到8000万token;真正耗token的是重量链路。按单价粗算,月度成本的大头就在那10%的复杂决策里。
缓存在这件事里作用巨大。同一个公司、同一个问题的答案如果三天内没有新数据入库,根本不需要重新跑一遍完整流程。系统把“问题+实体ID+数据版本”作为缓存键,命中之后直接返回上次的结论和证据列表。实测缓存命中率在中度分析类问题上能达到35%以上,直接把整月成本砍掉约两成。
6.2 并发编排与降级策略
百亿token的离线处理并不要求实时响应,正好可以利用异步并发拉满吞吐。我一开始用单线程跑批,一个月大概能处理几亿token的文档,后来改成多进程加队列之后,耗时直接缩短到原来的四分之一。
在线推理部分则要小心并发上限和限流。系统里有一个请求合并层:同一时间若有多个用户查询同一家公司的信息,合并层会将这些请求去重,只跑一次入仓分析,然后把结果广播给所有发起方。这个改动大幅降低了重复计算。
降级策略也很关键。大模型API偶尔会有超时或限流,我在请求层设置了多级降级:如果重量链路超时,先降级为中量链路;如果中量链路也超时,退到只返回检索结果,不返回深度论证。虽然回答深度变浅,但至少不会出现长时间无响应的情况。
6.3 输入精简与模型iciba的取舍
我还做了一轮针对输入内容本身的精简。分析计算代理依赖的是结构化字段,因此我会先经过一轮“数值提取”,把几十页财报转成十来个关键指标数组,再传给模型。新闻相关性判断则用轻量文本分类模型做粗筛,只有概率超过阈值的段落才会进入高风险上下文。
实测对比后发现,把同一个问题分别用“全量新闻摘要”和“精筛后核心段落”喂给模型,结论的差异并不明显,但token用量可以相差四到六倍。这个经验让我对“少即是多”有了非常直观的感受:模型不是看得越多就越准,它更怕注意力被无关信息分散。
7. 踩坑后的工具链沉淀与几条铁律
这类项目做到后面,真正留下来的不是某一次的漂亮结论,而是那套可复用的工具链和一堆从事故里学到的规则。
我提几个印象最深的坑。第一个是公告发布时间不一致:同一家公司会在交易平台、官网、媒体三个渠道发布公告,发布时间之间可能差出几小时甚至一天。如果按爬取时间当发布时间,定量分析常常会出现“未来信息泄露”。后来我做了多来源时间交叉校验,优先采用交易所正式公告时间,官网时间只当兜底。
第二个坑是财务重述:上市公司有时会追溯调整上一期的财务数据,同一份数据在不同下载日期里可能数值不同。如果不做版本管理,系统会在不同时间看到同一个指标的不同值,回测就会出现莫名奇妙的波动。我现在的做法是给所有财务指标都带“生效起始时间”和“记录版本”,任何分析在引用指标时都必须带上版本,才能保证整个链条的一致性。
第三个坑是过度推理:模型经常在证据不足时强行给出细腻的逻辑链条。用户看上去会觉得它很聪明,其实那些推论都是自洽的幻觉。为此我在输出层加了一个强制性兜底规则:当核心证据重合度低于阈值时,只允许给出“信息不足+建议补充哪些数据”的回答,禁止生成预测性结论。这个规则让系统的口气显得“笨”了很多,但整体可靠性明显上升。
第四个坑是召回倾向偏新:向量检索天然有近因效应,总是更倾向于召回和当前时刻接近的事件文本。结果就是回测时模型判断受“最新一条新闻”的影响远高于长期趋势。我后来在检索排序里加了时间分布均衡约束,确保召回结果既包含近期信息、也包含过去一到两年的关键片段,这才缓解了短视问题。
如果你也要做一个投资类的智能体,我最后的几条个人建议是:第一,把数据接入层的预算和耗时列为第一优先级,不要一上来就调模型提示词;第二,每一次判断都必须留痕迹,不然后期排查消耗的时间超过你的想象;第三,回测时多花时间做数据切片检查,宁可慢一点,也要盯住未来数据泄漏;第四,不要追求模型每次都给出肯定答案,学会让它承认“不知道”,这往往是系统真正成熟起来的分水岭。
这套架构目前在内部已经稳定跑了三个多月,从抓取、清洗、入库到检索、推理、回测,基本实现了全流程闭环。后续我准备在记忆层的衰减算法和检索的时间均衡策略上继续打磨,如果有什么新的进展或翻车经验,再回来写一篇实际案例分享。