
做企业研报的agent项目我前后踩了小半年坑从一开始单纯让大模型“读报告、写报告”到后来把检索、分析、多agent协作、记忆体系全部串起来才慢慢摸清楚这个方向真正应该怎么做。这篇文章把我实际开发过程中的架构取舍、代码实现、踩坑实录全部整理出来希望对同样在做agent落地的人有帮助。先说清楚一件事企业研报agent本质上不是“写一个会聊天的机器人”而是要把一个分析师团队的工作流拆解成可被大模型自动执行的任务链。它需要处理的是数据获取、研报阅读、财务指标提取、行业对比、风险识别、观点生成这一整套流程。如果只做一个“接上大模型API、把研报丢进去让它总结”的demo那种东西基本没有工程价值企业也不会买单。1. 先想清楚研报agent到底在解决什么问题1.1 研报场景跟通用agent的差别在哪里研报agent的核心难点不是“能理解自然语言”而是“对准确率的要求极其苛刻”。通用agent可以陪你闲聊说错了也无所谓研报不一样一个财务数据的错误、一个行业属性的误判会直接传导到投资建议层面没有人敢用一份数字有问题的报告做决策依据。这个场景决定了agent的架构选型它必须要有多源信息校验不能只依赖大模型的内部知识它必须有可追溯的分析链路每个结论都能回溯到具体的报告段落或数据源它还必须有严格的结构化输出能力最终产出的不是一段自由文本而是符合研报规范的框架化内容。我一开始犯的错误就是拿通用对话模板直接套研报场景结果模型自由发挥地很high生成的报告华丽但数据经不起推敲给业务方看一眼就被打回来了。1.2 企业研报agent的目标拆解在写任何代码之前先把目标拆成可见的交付物。我一般会把研报agent的能力拆成四层信息层自动解析PDF研报、定期抓取企业公告、接入财务数据库如Wind、Choice的开放接口把非结构化的研报文本转换成结构化数据。检索层对解析后的研报建立向量索引和全文索引保证agent能快速定位“某公司在某年的毛利率变化”这类具体问题。分析层执行财务指标计算、同行业横向对比、趋势分析、风险点扫描这层是agent真正体现“分析师能力”的地方。生成层基于分析结果按照目标券商或机构的研报模板生成结构化文档包括公司概况、行业分析、财务分析、估值与风险提示等章节。每一层的技术选型完全不同信息层偏工程化要处理PDF解析精度、表格还原等脏活检索层考验的是embedding模型和重排策略分析层依赖大模型的推理能力以及工具调用的稳定性生成层则考验提示词工程和对输出格式的约束能力。1.3 为什么选择agent而不是传统流程化程序这里有一个很现实的工程取舍如果所有的分析规则都是确定的用代码写死逻辑会比agent更稳。但研报分析恰恰有一大块是“半结构化”的不同行业的研究框架差异很大同样一个财务指标放在周期股和消费股里的解读逻辑完全不同。传统硬编码方案需要为每个行业维护一套独立规则维护成本极高。agent的价值在于它可以把“理解行业属性、选择分析框架、执行具体计算、生成解读”这个过程作为一个动态决策链来处理行业变了只要给它对应的上下文和工具集它就能自己适配。但这不意味着agent可以完全“自动驾驶”。我的实践结论是在研报这类高准确率要求的场景里agent适合做“分步决策”而非“端到端生成”。拆成小任务每步可验证、可回退、可人工介入才能保证最终质量。2. 从0到1搭一个能跑的通路2.1 数据接入研报PDF解析与表格还原研报agent的数据源通常分两类历史研报PDF和企业财务数据。历史研报PDF的解析是整个项目里最容易被低估的环节。市面上的研报PDF格式五花八门有扫描版的、有带复杂表格的、有双栏排版的直接拿通用的文本抽取工具硬上出来的内容经常是错乱的。我当时用的是“多层解析策略”先用PyMuPDF把PDF转成文本块同时保留块在页面上的位置坐标再用版面分析模型识别标题、正文、表格区域遇到表格区域就单独走表格还原管线用camelot或pdfplumber提取表格结构再转成DataFrame做后续计算。这样比单纯抽文本要多花一倍开发时间但数据质量对后续检索和计算的影响是决定性的。另一个容易踩坑的地方是单位换算。研报里的财务数据经常是“亿元”为单位的但有些图表数据用的又是“万元”。在做指标计算前必须统一单位并且把原始单位记录在元数据里。我见过不少团队在指标计算阶段出现几倍的偏差追根溯源都是单位问题。2.2 检索增强embedding选型与重排策略研报agent的检索环节和普通知识库问答有区别普通问答只需要“找到相似段落”研报场景还需要“找到数字、找到结论、找到上下文依据”。所以纯粹的向量检索是不够的我的做法是混合检索架构向量召回 关键词召回 业务标签过滤然后用重排模型做最终排序。embedding模型的选型上我对比过通用的中文embedding模型和针对金融语料微调的模型。实测下来金融领域微调模型在研报问答的召回效果上确实有明显优势尤其在处理财务术语的表述变体时。如果团队没有条件微调也可以先用通用模型但一定要在召回结果里叠加关键词匹配兜底否则一些精确的指标问题比如“2023年销售费用率”会召回出完全不相关的内容。重排层我用的方案是对召回结果让大模型做一次轻量级的相关性判断结合时间衰减因子越新的研报权重越高。这个方案比纯用bge-reranker或多轮重排模型更灵活因为加入时间先验后老报告里的一些过时结论不会被误带进来。2.3 生成环节提示词工程与结构化输出约束研报生成的提示词工程核心不是“让模型写得好”而是“让模型不乱写”。我用的提示词结构是角色设定 - 输入数据摘要 - 分析任务列表 - 输出格式约束 - 禁止事项。关于结构给定一个公司的各类数据指标列表要求模型输出公司概况、行业分析、财务分析、风险提示几个固定章节。关键点是数据摘要部分要把agent从检索层拿到的数据一并塞进去。模型生成时要明确要求它必须引用这些数据如果数据不足要明确输出“信息不足”而不是自己脑补一个数字。这里有个实用小技巧生成阶段不要用最高温度的模型配置温度尽量控制在0.2以下。研报内容需要的是稳定性和可复现性如果同一份数据每次生成的报告都不一样业务方没法做版本管理。输出格式约束方面我强烈建议用函数调用function calling或者结构化输出structured output机制而不是在提示词里依赖“请用JSON格式输出”。前者是模型原生能力失败率低后者看着简单实际经常出现JSON格式错误或字段缺失后期还得花精力做补全修复。2.4 工具调用让agent真的会“查数”研报agent如果要真正落地不能只靠大模型“知道什么”必须挂上工具集。我接得最频繁的工具类型有财务指标计算器传入营业收入、净利润、总资产等原始数据返回计算好的毛利率、净利率、ROE、资产负债率等指标及其同比变化。企业公告查询通过API连接企业公告库按关键词和时间范围拉取公告内容用于验证研报观点和发现最新动态。行业数据库查询接入行业宏观数据源行业景气度、上下游价格指数等为行业分析部分提供外部佐证。在工具调用层面一个极其重要的细节是工具的返回结果必须被完整记录到上下文中并且明确标注数据来源。我见过很多agent项目在工具调用后就丢了原始数据只把模型的理解结果传给下一步最后生成的报告没有任何可追溯性。工具调用的稳定性问题我放在后面“问题排查”部分细说。这里只强调一句话工具返回结果一定要做格式校验很多框架层面的报错都源于模型生成的参数与工具定义的JSON Schema不匹配。3. 记忆体系与多agent协作实战3.1 研报场景中的记忆分层设计研报agent与普通agent还有一个显著区别普通agent的对话是短期的聊完即忘研报agent必须在一次研究任务里维持对大量数据的“工作记忆”同时在不同任务之间保留可复用的“长期记忆”。我的设计分成三层短期记忆当前研究任务里的中间结果比如正在分析的这家公司的关键财务数据、刚检索到的报表段落。这层记忆用会话级的上下文存储实现注意控制token大小超过阈值就做摘要压缩。长期记忆跨任务沉淀下来的信息比如“这家公司所在的行业框架是什么”“过往我们分析这家公司时关注的几个核心风险点”。这层记忆保存在向量数据库里在每次任务开始时按公司和行业做召回作为分析背景注入。永久记忆对模型行为的规则约束比如“某客户的研报模板只接受指定章节结构”“某些金融专有名词必须使用标准表述”。这层记忆本质上是知识库和配置应该写死在系统逻辑里不应该让模型自由遗忘。这里我想重点提一个坑记忆召回不当会造成上下文污染。早期的做法是把所有历史分析结论都塞给模型“作为参考”结果模型经常被旧结论带偏在新数据出现变化时仍然沿用旧判断。后来我把记忆召回的优先级做了一个调整确定性数据最新财务数据优先于历史结论历史结论只能作为背景提示而不是决策依据。3.2 多agent拆分分析师、撰写者与审核者多agent协作是研报场景里发挥价值最明显的架构。我现在跑通的方案是三个角色并行分析师agent负责数据处理和指标分析。它接收原始财务数据、行业数据调用计算工具输出一份结构化的分析结论列表。这个agent的权限边界是“只分析不写最终观点”。撰写者agent负责把分析结论组织成研报章节。它接收分析师agent输出的结论按照客户模板要求进行润色和补全注意不能自己篡改数据。审核者agent负责校验最终报告。它把生成的报告重新拆解逐项比对数据引用、逻辑一致性、模板格式并把发现的问题返回给前两个agent修改。这个拆法的好处是每个agent的职责单一、上下文简洁、提示词可控性强。原先用一个“全能agent”跑全流程时推理链路经常在某个环节走偏而且一旦出错需要重跑全链路成本极高。拆成三个角色后每个环节的输入输出都是结构化数据可以单独调试、单独重跑。多agent之间通信我采用的是消息队列式的任务分发不依赖强对话而是把任务和结果作为JSON消息传递。这比让多个agent之间直接对话要稳定得多。agent对话一旦进入自由聊天模式上下文会迅速爆炸而且容易出现“跑题式协作”——一个agent夸夸其谈另一个agent跟着跑偏。3.3 编排框架怎么选商业框架与手写实现的取舍不少读者可能会问多agent编排是不是直接用LangChain或LangGraph之类的框架会更快这取决于是做POC还是做生产系统。我在POC阶段确实用过LangGraph做快速验证它的StateGraph思路非常适合定义状态机和任务流转内置的记忆模块和工具调用机制也能省不少代码。但进入生产阶段后我逐渐把核心链路替换成了自己的编排代码。原因主要有几个框架升级带来的破坏性变更太频繁生产环境不会允许每个版本都跟着改代码框架封装层级太深出问题时排查链路长很难定位是框架bug还是业务代码问题研报场景有大量的自定义逻辑模板解析、单位换算、指标校验这些逻辑放在业务层比放在框架层更好维护。我的建议是用框架学习架构思路但生产代码要自己掌控核心编排逻辑。框架可以保留在旁路用于快速试验新方案核心生产链路越薄越好自己写的那几十行状态机和调度逻辑比任何重型框架都靠谱。3.4 任务调度与状态管理多agent协作的工程难点之一是任务状态管理。我在自己写的编排层里维护了一个任务数据结构每一条任务记录包含任务ID、任务类型、输入数据引用、输出结果引用、状态pending/running/succeeded/failed、依赖任务列表、重试次数。这个结构让整个agent系统变得可观测、可重放。某一步失败时可以选择只重跑该步骤而不需要重跑完整流程。在实际运行中这一步挽救了我无数次调试时间——如果不是这个设计每次出问题都要全链路重跑token消耗会翻好几倍。运行时监控方面我把每个agent的输入输出、token消耗、工具调用记录全部写到日志里并加上trace_id串联。这一步看起来费功夫但等agent跑出问题再去翻日志时你会发现它是比你写提示词更重要的投资。4. 常见报错与排查实录4.1 agent execution terminated due to error这类框架错误的排查思路在agent开发中几乎每个人都会遇到那种泛化的报错信息“agent execution terminated due to error”是其中最常见的一种。这种报错的恶心之处在于它只告诉你执行终止了但不告诉你哪一步终止、为什么终止。我的排查习惯是分三步走。第一步查日志和trace确认最后成功的节点是哪一个出错节点的输入输出是什么。这一步能快速定位是检索层、工具调用层还是生成层出了问题。第二步查看工具调用的返回结果很多时候是工具返回格式不符合大模型的预期或者大模型生成的工具调用参数JSON里出现了非法值比如多余的逗号。第三步检查上下文长度如果上下文截断模型在处理后续任务时会莫名输出异常。这里补充一个我自己总结的稳定性措施在关键工具调用外面加一层参数校验和重试机制把参数传给工具之前先用代码校验一遍数据类型、枚举值、必填字段。这项措施能拦截掉大量垃圾输入。因为大模型返回的JSON参数偶尔会有小毛病如果直接透传给工具执行很容易触发框架层面的异常。4.2 上下文爆炸与token超限研报场景特别容易触发上下文爆炸因为检索召回的报告段落非常多加上财务数据表格、历史对话记录、工具返回结果分分钟撑爆上下文窗口。我采用的方案是“分段注入动态摘要”。首先是分段注入让agent在生成研报的不同章节时只注入该章节所需的数据和检索结果而不是把所有材料一次性倒进去。其次是动态摘要如果某一块数据太大比如某个公司的连续五年季度财务数据先让模型做一次数据压缩和要点提取把压缩后的摘要注入下一步。关于token成本也要提醒一句在agent开发阶段token消耗的实际增长速度远比想象中快。我曾经在一个测试周里跑了接近千次完整的研报生成流程烧掉的token费用对一个微小型团队来说已经是一笔不小的开支。所以一定要在系统里加token用量统计针对超长流程做分级策略——能先检索出重点再生成就不要贪心把全部上下文都带上。4.3 幻觉与数字错误最致命的质量问题研报agent最怕的就是幻觉和数字错误。模型生成的文字再流畅只要一个关键数据是错误的整个报告的信任就崩了。我在系统里强制加了两个校验环节。第一个是数字一致性校验生成完研报后写一个校验脚本扫描报告中的所有数字和输入数据表做比对发现不匹配直接标记错误。这套脚本我至今还没找到替代方案因为不管提示词怎么写禁止编造模型偶尔还是会把数字张冠李戴。第二个是“可引用性校验”模型输出的每个定性结论必须标注它所依据的数据来源编号如果没有引用来源审核agent会直接驳回。我特别认同一个观点在研报agent场景模型生成能力的提升永远替代不了“校验闭环”。做这个场景的开发至少要把两成精力用在构建数据校验和追溯体系上。4.4 框架配置类问题agent预设加载失败及其他环境坑还有一类问题发生在框架或开发环境层面。比如加载agent预设时出现的“无法加载agent预设client api: agentpresets/list failed”这类报错通常指向API链接配置或预设文件损坏。排查时需要确认API的认证信息是否过期、预设文件是否符合当前框架版本的格式规范。这类环境和配置问题看似琐碎却会消耗大量的开发时间。我的建议是在新环境里搭好项目后第一时间跑一个最小化的“精神支柱验证”用例——只跑一条最简单的消息链路排除环境因素后再开始开发复杂功能。别一上来就调试完整的研报流程否则你可能分不清是环境问题还是业务代码问题。5. 从POC到可以交付评估、观测与治理5.1 建立可量化的评估集研报agent能不能用不能靠感觉必须有评估集。我的做法是从历史研报里挑出二十份样本对每一份人工标注关键结论、关键数据、章节结构作为金标准。然后跑agent生成对应的内容逐项比对。评估维度包括数据准确率报告中的数字与金标准一致的占比、结论覆盖度金标准中的重要结论是否在报告中出现、结构完整度模板章节是否齐全、格式合规率是否符合客户的排版要求。这四个维度的加权得分可以作为每次迭代前后的对照基准。这一步给团队带来的最大价值不是“评分”而是“对齐”——业务方和开发团队终于可以在同一套标准下讨论agent的好坏而不是各说各话。5.2 可观测性建设trace、日志与告警agent系统的可观测性比传统的接口服务要求更高因为它的执行链路是动态的每次任务的调用图都可能不一样。我在部署时把每个节点检索、工具调用、生成、审核的耗时、token数、输入输出摘要都上报到统一日志平台并且配置了异常告警规则。告警规则不能太宽松也不能太敏感。我主要设了三类告警流程失败告警任务以错误状态终止、质量异常告警数字校验发现不匹配或审核agent驳回率超过阈值、成本异常告警单次任务的token消耗超出预算的1.5倍。别嫌这些建设麻烦。等到客户试用时提出“为什么某次生成的结果和上次差那么多”的问题时可观测性就是你唯一的武器。没有数据你连问题在哪儿都说不清。5.3 成本治理与分级策略研报agent的token成本一般会落在两个极端简单任务用大模型便宜得吓人复杂任务又能贵得让你肉疼。控制成本的方式是分级的。我按任务复杂度设计了三个档位轻量级任务比如回答某公司的单一问题用轻量模型的低档配置中型任务比如生成某公司的单节分析用标准模型重型任务比如全流程生成一份完整研报才启用最强的模型和最高的质量配置。再配合缓存机制——完全相同的检索问题和计算结果直接命中缓存不重复调用模型。这个成本分级的原理很简单大模型能力的边际成本是非线性的如果能用便宜模型解决的任务就不要让昂贵模型介入。实际运行下来成本至少降了三分之一而且没有明显感受到质量损失。5.4 安全边界与人工复核机制最后是研报agent的安全边界。金融场景的内容生成对合规要求很高我的处理方法是设置“人工复核闸门”agent生成的完整研报必须经过人工复核员确认后才能对外交付。系统在这一步保留所有中间数据、数据来源、分析链路的完整记录确保复核员可以一键核查任何一个数字的出处。这个机制看起来牺牲了一点“全自动化”的效率但它换来了业务方对系统的信任。在研报这种高风险场景里完全无人值守的自动化是很不现实的。Agent的价值是让人工复核从“逐字阅读全文”变成“针对性和重点核对异常项”——仍是人工在做决策但效率已经大幅提升。关于agent的可靠性和落地边界我的体感是不要追求一步到位的完全自动化把目标定在“人机协同的高效管线”上反而更容易让业务方接受也更容易在真实环境中稳定运行。最后补充一个小建议如果你想从零开始学agent开发不要一上来就去抄复杂的开源项目先手写一个单agent的最小闭环检索工具调用结构化输出把每一步的输入输出都吃透再往多agent、记忆体系做扩展。基础打牢了后面的路会顺很多。