1. 从零拆解:AI投研系统到底在解决什么问题
做投研的人都有一个共同的痛点:信息过载。每天开盘前要看的公告、研报、新闻、财报电话会纪要、行业数据,加起来少说几十万字。传统做法是靠人力去筛、去读、去总结,一个分析师覆盖两三个行业就已经满负荷了。而AI投研系统要干的事情,本质上就是把这套“信息采集—清洗—分析—输出”的流程用LLM和Agent架构重新做一遍,让机器承担80%的重复劳动,人只负责最后的判断和决策。
我最初接触这个方向是在两年前,当时市面上还没有成熟的“AI投研”产品,大家更多是在用ChatGPT做单点的问答。但单点问答有个致命问题:它没有记忆、没有上下文、没有数据源接入,你问它“某公司三季度毛利率变化的原因”,它要么胡编,要么告诉你“我无法获取实时数据”。这就是为什么后来Agent架构和Multi-Agents协作会成为主流方案——因为投研本身就是一个多步骤、多角色、需要反复验证的复杂任务,单靠一个Prompt根本搞不定。
这篇文章适合三类人看:一是想用AI提升投研效率的从业者,二是正在设计AI投研系统的工程师,三是对Agent架构和LLM应用感兴趣的技术人员。我会从系统设计思路、核心模块拆解、实操落地步骤、常见坑与排查四个维度展开,尽量把每个决策背后的“为什么”讲清楚,让你看完能直接上手搭一套自己的原型系统。
提示:本文讨论的AI投研系统仅针对公开市场信息的自动化处理与分析,不涉及任何非公开信息或违规数据源。
2. 系统整体设计:为什么是Multi-Agents而不是单体LLM
2.1 单体LLM的局限性在哪里
很多人第一反应是:我直接写一个超长的Prompt,把研报模板、分析框架、数据格式全塞进去,让GPT-4或者Claude一次性输出不就行了?我试过,结论是:短期演示可以,长期生产不行。
原因有三个。第一,上下文窗口限制。一份完整的投研报告需要参考的数据源可能包括:最近四个季度的财报、近三年的年报、最近30天的新闻、行业对比数据、管理层历史表态等。这些内容全部塞进一个Prompt,轻松超过100K token,即使模型支持,成本和延迟也会爆炸。第二,任务耦合导致错误累积。数据提取、财务计算、逻辑推理、文字生成,这四类任务的Prompt策略完全不同。混在一起写,模型很容易在某个环节跑偏,而且你很难定位是哪个环节出了问题。第三,无法并行和复用。投研中有大量可以并行的子任务,比如同时分析五家可比公司,单体LLM只能串行处理,效率极低。
2.2 Multi-Agents架构的核心优势
Multi-Agents的思路是把一个复杂的投研任务拆成多个独立的子任务,每个子任务由一个专门的Agent负责,Agent之间通过结构化的消息传递协作。这样做的好处非常明显:
- 职责单一,Prompt更精准。每个Agent只需要关注自己那一亩三分地,Prompt可以写得非常具体,输出格式也更容易控制。
- 可并行,效率高。数据采集Agent可以同时从多个源拉取数据,分析Agent可以并行处理多家公司。
- 可替换,易迭代。如果发现某个环节效果不好,只需要替换对应的Agent,不影响其他模块。
- 可追溯,好排查。每个Agent的输入输出都有日志,出问题时能快速定位。
我目前用的架构是“Orchestrator + 专业Agent”的模式。Orchestrator负责接收用户指令、拆解任务、调度Agent、汇总结果;专业Agent包括数据采集Agent、财务分析Agent、新闻情绪Agent、可比公司Agent、报告生成Agent等。这个架构不是拍脑袋定的,而是根据投研工作的实际流程反推出来的。
2.3 架构选型的关键考量
在选择具体框架时,我对比过几种方案。LangChain的Agent模块功能全但抽象层太厚,调试困难;AutoGen的多Agent对话机制很灵活,但生产环境下的稳定性需要额外加固;CrewAI的角色定义很直观,适合快速原型。最终我选择的是自研轻量级调度层 + 标准化的Agent接口,原因是我需要完全控制Agent之间的消息格式和错误处理逻辑,用现成框架反而束手束脚。
核心设计原则就一条:每个Agent必须是一个纯函数。给定相同的输入,必须产生相同的输出(在temperature=0的前提下)。这意味着Agent内部不能有隐藏状态,所有依赖都必须通过输入显式传入。这样做的好处是测试极其方便,你可以对每个Agent单独写单元测试,用固定输入验证输出是否符合预期。
3. 核心模块拆解:每个Agent到底怎么设计
3.1 数据采集Agent:投研系统的地基
数据采集Agent是整个系统的入口,它的质量直接决定了后续所有分析的上限。我见过太多项目在数据采集上偷懒,结果分析Agent再强也出不来好结果——垃圾进,垃圾出。
数据采集Agent需要处理三类数据源:结构化数据(财报数据、行情数据)、半结构化数据(公告、研报PDF)、非结构化数据(新闻、社交媒体、电话会录音转文字)。对于结构化数据,直接用API拉取即可,关键是做好字段映射和异常值处理。对于半结构化数据,需要用PDF解析工具提取文本,再用LLM做信息抽取。对于非结构化数据,重点是去重和相关性过滤。
这里有一个非常关键的细节:数据采集Agent必须输出标准化的JSON格式,而不是自然语言。比如财报数据,输出应该是:
{ "company": "某公司", "period": "2024Q3", "revenue": 1234567890, "gross_profit": 567890123, "gross_margin": 0.46, "yoy_growth": 0.12, "source": "财报PDF第12页", "confidence": 0.95 }为什么要这么设计?因为下游的分析Agent需要做精确计算,自然语言描述的数字它没法直接用。而且带上source和confidence字段,后续可以做溯源和置信度过滤。
注意:数据采集Agent的Prompt里一定要明确要求“如果某个字段无法从原文中提取,返回null而不是猜测”。我踩过这个坑,早期版本模型会“好心”地根据上下文推断数字,结果导致分析结论完全错误。
3.2 财务分析Agent:从数字到洞察
财务分析Agent接收数据采集Agent的输出,负责计算财务指标、识别异常变化、生成初步分析结论。这个Agent的核心挑战是:如何让LLM做准确的数学计算。
我的做法是:所有计算逻辑用代码实现,LLM只负责解释结果。具体来说,Agent内部先调用一个Python函数库完成比率计算、同比环比、趋势分析等,然后把计算结果和原始数据一起喂给LLM,让LLM用自然语言解释“为什么毛利率下降了”“应收账款周转天数上升意味着什么”。
这样做的好处是计算绝对准确,同时LLM的解释能力又得到了充分发挥。Prompt的设计大概是这样的:
你是一位资深财务分析师。以下是某公司2024Q3的财务数据计算结果: - 毛利率:46%,同比下降3个百分点 - 应收账款周转天数:67天,同比增加12天 - 经营性现金流/净利润:0.8,去年同期为1.2 请基于以上数据,分析该公司可能面临的经营问题,并给出你的判断依据。 要求:每个结论必须引用具体数据,不要泛泛而谈。实测下来,这种“代码计算+LLM解释”的模式,比让LLM直接算数字的准确率高出一个数量级。
3.3 新闻情绪Agent:捕捉市场预期差
投研的核心是找预期差,而预期差往往藏在新闻和社交媒体的情绪变化里。新闻情绪Agent的任务是:给定一家公司,抓取最近N天的相关新闻,判断每条新闻的情绪倾向(正面/负面/中性),并汇总出整体情绪趋势。
这个Agent的设计难点在于情绪判断的粒度和一致性。早期我直接用LLM打标签,发现同一个新闻在不同时间跑出来的结果不一致,原因是Prompt不够具体。后来我改成Few-shot + 评分制:给LLM提供5个标注好的示例,要求它输出-2到+2的整数评分,并给出理由。这样一致性大幅提升。
另外,新闻情绪Agent还需要做去重和事件聚类。同一件事可能被十家媒体转载,如果不去重,情绪汇总会被重复信息带偏。我的做法是用Embedding做语义相似度计算,相似度超过0.85的新闻合并为一条,只保留最早的那条。
3.4 可比公司Agent:横向对比的自动化
投研报告中必不可少的一部分是可比公司分析。传统做法是分析师手动拉几家公司的数据做表格,费时费力。可比公司Agent的目标是自动化这个过程。
这个Agent的输入是目标公司名称和行业分类,输出是一张可比公司对比表,包含估值指标(PE、PB、PS)、成长指标(营收增速、利润增速)、盈利指标(ROE、毛利率)等。实现上,它需要先根据行业分类找到可比公司列表,然后并行调用数据采集Agent获取每家公司的数据,最后汇总成表。
这里有个坑:可比公司的选择不能完全交给LLM。LLM可能会选出业务差异很大的公司。我的做法是先用行业分类代码做初筛,再用LLM做二次筛选,Prompt里明确要求“选择主营业务相似度超过70%的公司”。
3.5 报告生成Agent:从碎片到成文
报告生成Agent是最后一道工序,它接收前面所有Agent的输出,按照预设的报告模板生成最终文档。这个Agent的Prompt设计最关键的一点是:必须严格遵循模板结构,不能自由发挥。
我的报告模板包括:核心结论、财务分析、新闻情绪、可比公司对比、风险提示五个部分。报告生成Agent的Prompt里会明确每个部分的字数要求、必须包含的数据点、以及禁止出现的内容(比如“可能”“或许”这类模糊表述)。
实操心得:报告生成Agent的temperature一定要设低,我一般用0.3。温度太高会导致每次生成的报告风格不一致,用户体验很差。
4. 实操落地:从零搭建一套可运行的原型
4.1 环境准备与依赖安装
先说一下我的技术栈选择:Python 3.11 + FastAPI做服务层 + Redis做消息队列 + PostgreSQL做数据存储 + 任意主流LLM API。选择Python是因为生态最成熟,FastAPI是因为异步性能好,Redis是因为Agent之间的消息传递需要低延迟。
依赖安装清单如下:
pip install fastapi uvicorn redis psycopg2-binary pip install langchain openai tiktoken pip install pandas numpy scipy pip install pdfplumber python-docx pip install sentence-transformers如果你不想用LangChain,完全可以自己写调度逻辑,核心就是几个HTTP请求和JSON解析,没必要引入太重的框架。
4.2 Agent基类的设计与实现
所有Agent都继承同一个基类,基类负责处理LLM调用、重试、日志、错误处理等通用逻辑。这样每个具体Agent只需要实现build_prompt和parse_output两个方法。
class BaseAgent: def __init__(self, name, model="gpt-4", temperature=0.0): self.name = name self.model = model self.temperature = temperature self.max_retries = 3 def build_prompt(self, input_data): raise NotImplementedError def parse_output(self, raw_output): raise NotImplementedError def run(self, input_data): prompt = self.build_prompt(input_data) for attempt in range(self.max_retries): try: raw = call_llm(prompt, self.model, self.temperature) result = self.parse_output(raw) log_success(self.name, input_data, result) return result except Exception as e: log_error(self.name, attempt, str(e)) if attempt == self.max_retries - 1: raise time.sleep(2 ** attempt)这个基类看起来简单,但重试机制和日志记录是生产环境必不可少的。我早期版本没有重试,结果LLM API偶尔超时就直接导致整个流程失败,体验极差。
4.3 Orchestrator的调度逻辑
Orchestrator的核心是一个状态机。它接收用户请求后,按顺序执行以下步骤:
- 解析用户意图,确定目标公司和分析维度
- 调用数据采集Agent获取基础数据
- 并行调用财务分析Agent、新闻情绪Agent、可比公司Agent
- 等待所有并行任务完成,汇总结果
- 调用报告生成Agent生成最终报告
- 返回结果并记录全链路日志
并行调用用asyncio.gather实现,代码大概长这样:
async def analyze_company(company_name): data = await data_agent.run(company_name) tasks = [ financial_agent.run(data), news_agent.run(company_name), comparable_agent.run(company_name) ] financial_result, news_result, comparable_result = await asyncio.gather(*tasks) report = await report_agent.run({ "financial": financial_result, "news": news_result, "comparable": comparable_result }) return report这里有个细节:并行任务中任何一个失败,不应该导致整个流程失败。我的做法是给每个任务加超时和降级逻辑,比如新闻情绪Agent超时了,就在报告中标注“新闻情绪数据暂不可用”,而不是直接报错。
4.4 Prompt模板的管理与版本控制
Prompt是AI投研系统的核心资产,必须像代码一样管理。我的做法是把所有Prompt存在独立的YAML文件里,用Git做版本控制,每次修改都记录变更原因和效果对比。
financial_analysis: version: "2.3" system: | 你是一位拥有15年经验的资深财务分析师... user: | 以下是{company}的财务数据: {financial_data} 请分析以下维度: 1. 盈利能力变化及原因 2. 营运效率变化及原因 3. 现金流健康度 4. 主要风险点 constraints: max_tokens: 2000 temperature: 0.2这样做的好处是:当某个Agent效果下降时,可以快速回滚到上一个版本的Prompt,而不是在一堆代码里翻找。
4.5 数据存储与缓存策略
投研系统的数据有很强的时效性,但也不是每次都要重新拉取。我的缓存策略是:财报数据缓存24小时,新闻数据缓存1小时,行情数据缓存5分钟。用Redis的TTL机制实现,简单可靠。
存储方面,原始数据存PostgreSQL,Agent的输入输出日志存MongoDB(因为格式不固定),最终报告存对象存储。这样分层存储的好处是各取所需,查询效率高。
5. 常见问题与排查技巧实录
5.1 LLM输出格式不稳定的排查思路
这是最常见的问题。你明明在Prompt里要求输出JSON,但模型就是会加一些“好的,以下是分析结果”之类的前缀。我的解决方案分三步:
第一步,用JSON mode。主流LLM API都支持强制JSON输出,开启后模型不会输出多余内容。第二步,在Prompt里给示例。不要只说“输出JSON”,而是给一个完整的JSON示例,模型模仿能力很强。第三步,加解析容错。用正则提取第一个{到最后一个}之间的内容,再尝试解析,这样即使有少量多余文字也能处理。
如果三步都做了还是不稳定,那大概率是Prompt太复杂了。拆成两个Agent,一个负责分析,一个负责格式化。
5.2 Agent之间消息传递的常见错误
Multi-Agents系统最容易出问题的地方就是Agent之间的接口。我遇到过几种典型情况:
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| 下游Agent收到空数据 | 上游Agent返回了null但未做检查 | 在Orchestrator层加schema校验 |
| 数据格式不匹配 | 上游改了输出格式但下游没同步 | 用Pydantic定义严格的数据模型 |
| 循环等待 | Agent A等B,B等A | 调度层加超时和依赖检测 |
| 数据量过大导致超token | 上游返回了完整原始数据 | 上游只返回摘要,原始数据存引用 |
实操心得:我强烈建议用Pydantic定义所有Agent的输入输出模型,这样在开发阶段就能发现大部分接口问题,而不是等到运行时才报错。
5.3 成本控制的实战经验
AI投研系统的成本主要来自LLM API调用。一个完整的分析流程,如果全部用GPT-4,成本可能在2-5美元。如果每天分析50家公司,一个月就是3000-7500美元,不是小数目。
我的降本策略有四个:第一,分级用模型。数据提取用便宜的小模型,逻辑推理用大模型。第二,缓存复用。相同公司的相同分析维度,24小时内不重复调用。第三,Prompt压缩。去掉冗余的示例和说明,把token数压到最低。第四,批量处理。把多个小请求合并成一个大请求,减少API调用次数。
实测下来,这四招能把成本降低60%-70%,而分析质量几乎没有下降。
5.4 如何评估AI投研系统的输出质量
这是个很难的问题,因为投研分析没有标准答案。我的做法是建立三层评估体系:
第一层是事实准确性。检查报告中引用的数据是否与原始数据源一致,这个可以用代码自动校验。第二层是逻辑一致性。检查结论和论据之间是否有逻辑跳跃,这个需要人工抽查。第三层是实用性。让实际做投研的同事盲评,看AI生成的报告和人工写的报告有多大差距。
我目前系统的水平是:事实准确性99%以上,逻辑一致性85%左右,实用性大概能达到初级分析师70%的水平。距离替代人类还远,但作为辅助工具已经能显著提升效率了。
5.5 系统扩展性的考量
当你要覆盖的行业从1个扩展到10个,公司从10家扩展到100家时,系统会面临新的挑战。我的经验是:提前做好抽象,但不要过度设计。
具体来说,行业特定的分析逻辑应该做成可插拔的模块,而不是硬编码在Agent里。比如消费行业关注同店增长,科技行业关注研发投入,金融行业关注不良率。这些差异可以通过配置文件来管理,而不是改代码。
另外,当Agent数量增多时,调度层的复杂度会指数上升。我的建议是引入工作流引擎(比如Prefect或Airflow)来管理Agent之间的依赖关系,而不是自己手写调度逻辑。
6. 我踩过的坑与最后的建议
做AI投研系统这两年,最大的教训是:不要试图让LLM做它不擅长的事。LLM擅长的是语言理解、信息抽取、文本生成,不擅长的是精确计算、实时数据获取、确定性逻辑判断。把这两类任务分开,用代码做计算,用LLM做解释,系统稳定性会好很多。
第二个教训是:Prompt工程不是一劳永逸的。模型在更新,数据在变化,业务需求在演进,Prompt必须持续迭代。我现在的做法是每周review一次各Agent的输出质量,发现下降就立即调整Prompt。
第三个教训是:人机协作比全自动更现实。我最初的目标是做一个全自动的投研系统,后来发现完全不现实。现在的定位是“AI做初稿,人做终审”,这样既发挥了AI的效率优势,又保留了人的判断力。
如果你正准备开始做类似的项目,我的建议是从一个垂直场景切入,比如只做财报分析,或者只做新闻情绪监控。把一个场景做深做透,比做一个大而全但每个环节都半吊子的系统有价值得多。等这个场景跑通了,再逐步扩展其他模块。
最后分享一个实用技巧:在Agent的Prompt里加一句“如果你不确定,请明确说‘不确定’而不是猜测”。这句话能显著降低幻觉率,尤其是在数据不完整的情况下。我实测下来,加了这句话之后,事实性错误减少了大约40%。