三名投资人员。450家公司进入他们的观察名单。每次季度委员会会议之前,都要有人花两到三天阅读PDF,准备一份定性简报。这就是我们为解决这个问题而构建的东西,以及要把这件事做对需要付出什么。
TLDR
Emerald Wealth Partners 是一个私人家族办公室。它的实际投资组合刻意保持小规模,大约20到25个持仓。但它背后的观察名单却刻意做宽:450家上市公司,作为未来候选、竞争基准和行业背景被跟踪。三名投资人员(一名主管和两名助理)承担全部研究。
FactSet 覆盖财务数据。其他一切,管理层对定价权、资本纪律、竞争地位或AI投资的表述,仍然要靠人工阅读申报文件。
问题在于时间。每次季度投资委员会会议之前,都要有人花两到三天阅读PDF,准备一份定性摘要。对于一个新的持仓,深入研究意味着一名助理要花好几天处理一家公司最近四份年报,加上最近的财报电话会议记录(大约1,200页)。
我们在他们的整个研究语料库之上构建了一个私有AI搜索工具:覆盖400家公司的2,200份年报和财报电话会议记录。其余50个观察名单上的名字被排除在外,因为他们在语料库构建时还没有四年的SEC申报历史。语料库覆盖每家公司最近四份年度申报文件(10-K和20-F),外加从提交给SEC的8-K附件中取得的会议记录。
用平实的英文提问。得到一条简短、带引用的答案。看到它来自的确切段落。点击跳转到原始的SEC申报文件或会议记录。一切都在他们的基础设施上运行。他们的查询永远不会离开自己的环境。
10 min
投资委员会研究准备
之前每个会议周期要花2到3天手动阅读。
3×
每季度评估的新持仓
团队现在每季度评估12到15个新名字,之前是4到5个。
0%
上线以来引用零错误
每个答案都链接到原始申报文件或会议记录中的确切段落。
50+
60天时每周查询数
跨公司比较和历史语气分析是最常见的类型。
让这个项目立项的时刻
Emerald 的季度投资委员会会议围绕一份定性简报展开:管理层语气在整个投资组合中如何变化,风险因素措辞发生了什么变化,公司在上一份年报中承诺要做的事是否出现在最近的财报电话会议里。准备这份简报每个季度要花两到三天。
在某一次会议之前,主管想要一个简单的答案。过去两年里,15家零售和消费品公司在谈论关税和成本上升时是否保持一致,还是措辞已经悄悄发生了变化?回答这个问题意味着要阅读这15家公司大约60份季度申报文件,然后再与每场财报电话会议上的发言逐一核对。
助理花了三天。委员会会议在第二天举行。主管带着不完整的笔记走了进去。
之后,她说了她这一年来一直在说的话:“一定有更好的办法来做这件事。“这一次,她请我们去评估这个项目。
他们之前试过的东西
其中一名助理自己搭了一个原型:OpenAI的API、每次会话上传几份PDF,以及一个简单的聊天界面。它适用于单一公司、单一申报文件的问题。它无法在上下文中容纳超过一两份文档,这排除了任何跨公司或跨年度的问题。而且有时答案引用的段落,对照原始申报文件检查后,并不是模型声称的意思。
她称之为”看似合理的幻觉”。错误的答案听起来完全正确。它比没有答案更糟,因为你不知道需要去核实。
有两份投资备忘录发出去了,用模型部分捏造的引用总结了某家公司管理层关于定价权的表述。被引用的段落是存在的。被引用的具体句子并不存在。这不是什么大事,因为两份备忘录都是供内部讨论用的。
他们来找我们时,要求很简单:要么答案附带一个可以点击核实的来源,要么就没有答案。
FactSet、Bloomberg AI 和通用 AI 搜索工具都不够
他们的 FactSet 订阅能精确处理定量数据。当他们需要收入、利润率、负债率或一致预期时,FactSet 是正确的工具。FactSet 的标准研究工作台做不到的是回答”这个管理团队在过去五份年报中如何描述其资本配置方法,这种措辞是否发生了变化?“这个问题需要阅读。FactSet 近年来增加了AI功能,但这些功能运行在 FactSet 自己的数据范围内,而不是一个限定在他们真正跟踪的400家公司之上的、经过整理的私有语料库。
通用 AI 搜索工具(Perplexity、各种研究平台内置的AI功能)引用新闻文章和分析师评论。对于基于原始来源的基础研究,新闻文章里的转述不是引用。你要的是 10-K 里的那句话,而不是别人对它的概括。
助理的原型有正确的直觉:私有、本地、直接基于原始来源工作。但它一次只能工作一个会话。它无法容纳一个包含2,200份文档的永久资料库。它无法回答跨公司问题,因为它在同一时间只能看到一两份文档。而且它编造内容的频率高到无法使用。
他们需要的是这样一个东西:把整个语料库永久留在内存里,同时按含义和精确词语搜索,当证据不足以支撑一个自信的回答时拒绝作答。最后一个行为(说”无数据”而不是猜测)被证明是最难正确构建的部分。
还有一个他们很早就提出、我们认真对待的数据问题。Emerald 研究的内容是一个投资办公室能接触到的最敏感的信号。让这些数据经过第三方供应商的系统,会带来他们不愿承担的风险。这个工具运行在他们的基础设施上,使用他们的API密钥。一条关于 Nvidia 在最近三场财报电话会议上对产能说了什么的查询,永远不会碰到一台不属于他们的服务器。
七周的构建
从启动到团队能把工具放到真实委员会备忘录面前,用了七周。每一周都买到了一些具体的东西,跳过其中任何一周都会留下一个没人真正敢信任的工具。
-
调研 + 语料库范围界定
确定哪400家公司对观察名单真正重要,让工具从第一天起就在正确的范围内回答问题
-
摄取流水线:申报文件 + 会议记录
把2,200份年报和财报电话会议记录汇入一个可搜索的语料库,每周自动更新,无需任何工程介入
-
更聪明的搜索 + 公司匹配
确保关于一家公司的问题不会返回另一家公司答案的引擎
-
评估套件(从13个到83个有据可查的案例)
在投资团队的任何人看到它之前,持续测试工具给出的答案是正确而非只是听起来合理
-
检索调优 + 同一个bug的三个版本
弥合了"返回一个答案"和"每次都返回正确答案"之间的差距,包括会把引文错配到错误公司的bug
-
忠实度检查层 + 来源查看器
每个答案都链接到它来源的确切句子,确保没有任何东西能进入委员会备忘录而不被一键核实
-
CI门禁 + 交付
永久锁定了准确率门槛,培训了团队,交付了一个能自我保持更新的工具
构建工具: OpenAI 负责搜索引擎,Supabase 负责存储和搜索语料库,SEC EDGAR 的公共数据源负责拉取申报文件,另有一个定制流水线让一切保持有条理、可搜索。查询界面是一个轻量的内部Web应用。按团队目前的查询量,基础设施和API成本大约每月150到250美元。
如何把 2,200 份文件变成一个可搜索的语料库
前两周纯粹是搭建。在2,200份文件全部拉取、切分成可搜索的片段并存储之前,其他什么都不能建。
流水线直接从 SEC EDGAR 拉取每份申报文件,去掉格式,把文档分成两层。约220词的小段落是搜索真正扫描以找到正确答案的内容。约650词的更大窗口是工具读回来撰写答案的内容。220词的片段很少拥有足够的上下文来单独成立。工具需要更完整的段落来解释它发现了什么。
财报电话会议记录需要不同的方法。许多公司在电话会议结束后不久,把会议记录作为例行报告的附件提交给SEC。流水线像拉取其他申报文件一样把它们拉下来,但拿到后对它们的处理不同:它让每个分析师的问题与其回答保持配对,而不是把对话拆散。
语料库还包括观察名单上的外国公司,比如 ASML、TSMC 和 SAP,它们提交的报告类型与美国公司不同。流水线两者都能处理。其中一些外国申报文件结果只是空白的封面页,没有实际内容。它们会被记录并自动跳过,不会影响其他部分。
第2周结束:400家公司,2,200份年报和会议记录,大约160,000个可搜索片段。
流水线从那时起还会自己运行,按周计划执行。当新的申报文件出现在SEC网站上时,它会拉取并添加到已有内容中,不重复任何东西,也不用从头重建。每次周运行都会生成一份报告,显示更新了什么、跳过了什么。全程不需要工程师守着。
第一版,以及它为何悄悄失败
第一版搜索很简陋。一个问题进来,工具找到听起来最接近的12个段落,那就是答案。不检查问题到底说的是哪家公司。在基于含义的搜索之外没有关键词匹配。当语料库没有相关内容时,也没有办法说”我不知道”。
它在直白的问题上表现不错。“Nvidia 如何讨论AI供应链风险?“返回的是Nvidia的段落。其他一切都失败了。
一个关于投入成本压力的问题,可能因为措辞恰好相似,就从同一份申报文件中返回三个完全无关主题的段落。像”哪些公司在最近的财报电话会议上提到了定价纪律?“这样宽泛的问题,把同一家公司返回了六次,因为没有任何机制推动工具从多家公司取材。一个关于根本不在语料库里的公司的问题,仍然得到了一个听起来很有把握的答案。
我们做了测量。大约三分之二的情况下,正确段落甚至不是第一个结果。此后的每个修复都针对这些具体失败之一。
股票代码错误:三次出现
最有启发性的失败以三种不同的伪装出现了三次。
第一版通过检查公司名称的任何部分是否出现在问题中来匹配公司。单字母股票代码立刻让它崩溃。AT&T 的代码是 “T”。“discussed” 这个词里包含字母 T。每个关于AI战略的问题都被路由到了 AT&T,也路由到了 Disney,因为 Disney 的代码 DIS 正好嵌在 “discussed” 这个词里。修复方法:只匹配完整单词,绝不匹配埋在别的单词里的字母。
然后同一个问题以新形式回来了,这次是普通词语被塞进公司法定名称。“Companies” 是 “Lowe’s Companies, Inc.” 的一部分。像”哪些公司提到了定价纪律?“这样的问题会把结果过滤到只剩 Lowe’s。“Electric” 是 General Electric 名称的一部分。“Technology” 出现在语料库好几家公司的完整法定名称中。修复方法:任何出现在多家公司名称里的词都会从匹配列表中被剔除,只留下真正能识别单一公司的词。
第三,缩写。有人在问题里输入”AI”,无法匹配那些完整写出”artificial intelligence”的申报文件。分析师搜索AI投资,会在不知情的情况下漏掉一半结果。修复方法:工具现在会在搜索前展开常见缩写。
这些问题没有一个能靠读代码发现。三个都是因为测试套件在每次搜索后不断追问一个简单问题才被发现的:实际返回了哪些公司,这是不是正确的名单?
40 秒搜索幽灵
大约有一个星期,搜索需要40秒。我们建好了搜索索引,确认它能工作,然后眼睁睁看着每个问题慢慢爬。
原因藏在数据库搜索配置里的一个设置。它静默地把每次搜索上限设为40个结果,不管实际请求了多少。需要80个结果才能从多家公司取到答案的宽泛问题只拿到40个,没有任何被截断的警告。结果看起来就是很单薄,排序看起来也不对。而且,每次大问题搜索都在后台做额外的不必要工作,这才是它变慢的原因。
改一个设置就修好了。但能找到那个设置,只是因为测试套件已经在问正确的问题:为什么宽泛搜索总是返回同一家公司的结果?
先测量,再调参
在碰任何搜索设置之前,我们先建了一个带标注的测试套件。一开始是13个手写案例:必须返回特定公司的问题,必须浮现特定主题的问题,以及必须什么都不返回的问题:不在语料库里的公司、任何申报文件中都不存在的主题。
从那里,套件通过从真实语料库中提取真实主题、围绕六个类别生成测试问题来成长:单一公司、并排比较、历史趋势、别名匹配、过滤搜索,以及刻意无法回答的问题,用来检查工具会说”无数据”而不是猜测。每个生成的测试问题在加入套件之前都要对运行中的工具跑一遍。如果工具用当前语料库真的无法回答,这个问题就不会入选。测试文件里没有任何东西期望语料库给不出的答案。
套件增长到83个有据可查的案例。构建它的过程中发现的问题比代码审查还多。
一个反复出现的教训:测试问题需要与语料库一起成长。“哪些公司提到了AI投资?“是在只有少数几家公司被索引时写的。面对完整的400家,一个好的答案会浮现20家或更多不同的公司。原来的测试写的是期望一个固定的短名单,错的是测试,不是工具。任何这样的测试现在检查的是公司数量下限而不是精确名单,这样它就能随着语料库增长继续有意义。
29 次调参尝试,一次真正的改进
当测试套件大到足以信任时,我们尝试调参:基于含义的匹配相对于关键词匹配该给多少权重,宽泛问题该拉取多少个结果,以及工具在信任一个匹配足以作答之前该多严格。29种不同的组合,每次只改一个变量,对同一组案例测试。
起始设置已经接近正确。唯一真正的改进:宽泛问题拉取更少的结果(40个而不是80个),让正确段落更稳定地排得更靠前,准确率没有下降。更小的池子意味着真正回答问题的段落不会被更弱的匹配淹没。
反直觉的部分:把每个类别里最好的设置单独组合起来,效果反而更差。最好的关键词与含义平衡单独就弄坏了一个比较类问题。最好的池子大小单独没有碰那个问题。放在一起,两者都造成伤害。我们保留的每一项改动,上线前都重新对完整套件跑了一遍。
确保答案不偏离证据
检查每一条引用确实指向一个真实、检索到的段落,是第一道保护。必要,但单独不够。一个答案可以引用真实段落,却仍然声称这些段落没有说的内容。
所以第二个AI模型检查第一个模型的工作。每次回答后,它会对照引用的段落重新阅读答案,标出任何超出证据实际陈述范围的句子。这个检查的第一轮就抓到了引用检查漏掉的两个问题。
一个关于 Apple、Cisco 和 IBM 的答案里有一句话听起来合理,但不在任何被引用的段落里。那是模型做出的小推断,不是任何申报文件说的。一个比较类答案从 Tesla 和 Rivian 都检索了段落,却生成了一段只讨论 Rivian 的答案,悄悄丢掉了比较的一半。
两个修复:工具现在明确告诉模型哪些引用是有效的,让它停止编造指向虚无的引用编号。而且当模型写出的内容没有通过准确率检查时,备用答案现在显示5个原始段落而不是3个,这样即使是在备用答案里,比较的两边也都会出现。
这两个修复把准确率检查的通过率从10个里8个提到了干净的10个里10个。
三件出问题的事
评估测错了东西
三周后,我们运行套件,得到一个看起来健康的通过率。然后我们查看了”通过”对于一个案例类别到底意味着什么。
有几个问题的固定公司名单预期,是在语料库只有少数几家公司时写的。面对400家公司,“哪些管理团队在最近的财报电话会议上提到了供应链压力?“的好答案会浮现30或40家不同的公司。我们写的三家公司测试是错的,错不在工具。我们在把正确答案标成失败,然后得到一个因为错误原因而看起来健康的通过率。
修那些测试花了半天。两周后,又加入了一些外国公司,同样的事情再次发生。测试问题需要持续维护。写一次就忘记是行不通的。
语料库更新后公司识别出错
往语料库新增28家公司的第二天,工具开始漏掉其中一些公司的结果。不常发生。但频率高到需要重视。
其中两家新公司的名称里有本应从匹配中排除的词语,就是上面股票代码错误里”出现在多家公司名称中”的那条规则。但那条排除名单是开始时手工建立的,之后新增公司时再没检查过。它已经过期了。
修复方法:现在每次新增一家公司,系统都会自动把它与现有匹配名单核对,在公司上线前标出任何冲突,并写出一份清晰的摘要说明它会被匹配到什么。任何人都可以在不读代码的情况下检查这份摘要。这个检查现在每次更新都会运行,不只是第一次。
开发过程中”无数据”边界发生了偏移
工具对无法真正回答的问题内置了一条规则。如果找到的证据太薄弱,不足以支撑真正的答案,它就说”未找到数据”,而不是照样猜测。这是第一天起就有的核心要求。团队已经被听起来很有把握但实际错误的答案坑过一次了。
但在语料库还在建设的过程中,有些公司当时只索引了两三份申报文件。关于这些公司的问题有时会因为技术细节越过”证据充足”的门槛,产生技术上站得住脚、但薄弱到没用的答案。助理无法分辨一个薄弱的答案意味着工具真有毛病,还是只是那家公司的申报文件还没加载全。
我们加了一个覆盖度标记:当被查询的公司索引文档少于五份时,答案会附带一条说明,提示覆盖有限。“系统无法回答这个问题”和”语料库还不够”是两种不同的情况,对应不同的处理:第二种有解决路径。
60 天后的结果
Emerald 的团队从上线后的第一周就开始使用这个工具。定性反馈始终一致:工具消除了瓶颈,没有消除思考。查找 Nvidia 在过去四场财报电话会议中就产能投资说了什么,需要10分钟,并返回带来源链接的确切段落。这对投资论点意味着什么,仍然是助理的工作,需要多久就多久。
10 min
投资委员会准备
过去需要2到3天的研究简报,现在在会议当天早上就能准备好。
12–15
每季度评估的新持仓
之前是4到5个。同一个三人团队。
50+
每周查询数
主要是跨公司比较和历史语气分析:手动阅读完全无法回答的问题。
0
上线以来引用零错误
每个 [1] 都已对照原始来源验证。忠实度检查对每个答案都运行。
更大的变化不是单次查询的速度。而是团队愿意去问什么问题了。像”这个管理团队过去五年如何描述其资本配置理念,措辞是变得更具体还是更模糊?“这样的问题,过去是一周的工作量,所以没人会跑。现在只需要15分钟,所以他们跑了。
这里定制有意义,平台没有
对于文档集很小、研究需求偶发的团队,通用AI工具(甚至一个维护良好的 NotebookLM 工作区)很可能就足够了。这个项目对 Emerald 有意义,有三个具体原因。
第一,语料库太大、变化太频繁,任何只能一次会话工作的工具都跟不上。交付时是2,200份文档,而且随着新的年报和会议记录提交,每周都在增长。每次会话都重新上传文档,是跟不上的。
第二,引用完整性没有商量余地。投资决策(哪怕是内部的)取决于能否核实每一条主张的来源。忠实度检查和指向原始申报文件的深度链接不是锦上添花。它们就是产品本身。
第三,数据敏感性。一个投资办公室的研究活动(他们在研究什么、在试探哪些公司、在就管理层可信度或资本纪律问哪些问题)是专有信号。让这些数据经过第三方AI平台处理,会带来他们不愿接受的风险敞口。每条查询都留在他们的环境里。
观察名单很小(少于150家公司),研究偶发且只针对单一申报文件
你的数据供应商 + 手动EDGAR就足够了。不需要定制构建。
中等观察名单,每季度做跨公司研究,能容忍一些引用局限
评估托管式AI搜索工具或NotebookLM。这个阶段定制可能过度。
大型持久语料库,跨时间段的定性研究,要求引用完整,数据必须留在内部
定制构建。这需要的是不同的地基,而不是同一个工具的更大版本。
我们会怎么做不同
我们会在第1周就开始测试套件,而不是第4周。股票代码错误本该在第一周就被抓到,而不是三周后。40秒变慢的问题本该从第一天就显而易见,因为”为什么宽泛的问题总是返回同一家公司的结果?“正是测试套件生来要问的问题,而不是你后来偶然撞上的东西。我们把测试套件当成开发工具来建,直到它沿途抓到的东西才真正发现它的价值。我们本该在需要它之前就知道它是干什么的。
我们还会在第1周更激进地处理语料库构成。Emerald 对哪些公司重要有清晰的想法,但对工具的实际覆盖范围没有任何书面定义。有些公司在观察名单上理由明确。有些是因为没人能还原的历史原因被纳入的。把一个公司重新跑一遍流水线只会更新它,而不是创建重复项,所以公司名单越早锁定,名称匹配就越早稳定,测试问题也就越早保持有效。
第三,我们会在第4周而不是第7周,把只读版本放到一名助理面前。我们自己的测试能抓到逻辑bug。真实的研究问题能抓到其他一切:我们没考虑到的公司名称、被切分得别扭的财报电话会议记录、按助理实际说话方式而非我们想象的方式提出的问题。一个人跑一周真实问题教给我们的,比我们自己再写20个问题还要多。
第一天就开始评估套件,在调任何参数之前敲定语料库,并且尽早把真实用户放到可用版本面前。一旦你知道自己在测什么,构建就会变得更容易。在此之前的一切都是受过教育的猜测。
来聊聊吧
执行这套方案的团队在第一个冲刺中就能看到成果。
预约一次轻松的30分钟通话。带上您心中的任何疑问,我们帮您理清思路,无论您是否最终与我们合作。
- 友好交流,不是销售电话
- 无需准备,无需承诺,没有压力
- 带着您的问题来,带着答案走