1. 从零拆解AI投研系统到底在解决什么问题做投研的人都有一个共同的痛点信息过载。每天开盘前要看的公告、研报、新闻、财报电话会纪要、行业数据加起来少说几十万字。传统做法是靠人力去筛、去读、去总结一个分析师覆盖两三个行业就已经满负荷了。而AI投研系统要干的事情本质上就是把这套“信息采集—清洗—分析—输出”的流程用LLM和Agent架构重新做一遍让机器承担80%的重复劳动人只负责最后的判断和决策。我最初接触这个方向是在两年前当时市面上还没有成熟的“AI投研”产品大家更多是在用ChatGPT做单点的问答。但单点问答有个致命问题它没有记忆、没有上下文、没有数据源接入你问它“某公司三季度毛利率变化的原因”它要么胡编要么告诉你“我无法获取实时数据”。这就是为什么后来Agent架构和Multi-Agents协作会成为主流方案——因为投研本身就是一个多步骤、多角色、需要反复验证的复杂任务单靠一个Prompt根本搞不定。这篇文章适合三类人看一是想用AI提升投研效率的从业者二是正在设计AI投研系统的工程师三是对Agent架构和LLM应用感兴趣的技术人员。我会从系统设计思路、核心模块拆解、实操落地步骤、常见坑与排查四个维度展开尽量把每个决策背后的“为什么”讲清楚让你看完能直接上手搭一套自己的原型系统。提示本文讨论的AI投研系统仅针对公开市场信息的自动化处理与分析不涉及任何非公开信息或违规数据源。2. 系统整体设计为什么是Multi-Agents而不是单体LLM2.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必须是一个纯函数。给定相同的输入必须产生相同的输出在temperature0的前提下。这意味着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, modelgpt-4, temperature0.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机制实现简单可靠。存储方面原始数据存PostgreSQLAgent的输入输出日志存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等BB等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%。