← 返回文章列表
June 25, 2026
5 分钟阅读

researcher:面向人类与 AI 智能体的可搜索量化研究档案库

researcher:面向人类与 AI 智能体的可搜索量化研究档案库
#researcher
#quant
#arxiv
#meilisearch
#mcp
#ai-agents
#research
#algotrading

量化研究无处不在,却又无处可寻。你需要的论文在 arXiv 上。参考实现在 GitHub 上。直觉藏在某人 2019 年写的一篇博客里。真正的入场/离场逻辑是 TradingView 上一段获得 400 个赞、却毫无文档的 Pine 脚本。四套语料、四个搜索框、四套约定,零交叉引用。当你试图判断一个想法是否值得花一周时间做回测时,这种碎片化才是真正的成本 —— 不是阅读本身,而是寻找

于是我们自己动手做了一个。researcher.marketmaker.cc 是一个面向量化交易研究的精选档案库与搜索引擎。它把通常散落在 arXiv、GitHub、量化博客和 TradingView 上的材料汇聚到一处,对全部内容建立全文索引,而且 —— 这是我们最看重的一点 —— 通过模型上下文协议(MCP)端点和一个公开的 REST API 把整个语料库开放给 AI 智能体。它是一个研究底座:人类可以用键盘浏览,智能体可以用工具调用查询,二者背后是完全相同的索引。

本文将带你了解里面有什么、它是怎么搭建的,以及为什么它在我们的 AI 智能体技术栈中处于现在这个位置。

语料库里有什么

四个数据孤岛 —— 论文、代码仓库、文章和图表脚本 —— 汇聚成单一索引

researcher 统一了四个主要数据集,每个都有自己的全文索引。下面的数字截至 2026-06-12,而且会变动 —— arXiv 流水线每天运行,索引从源头重建,所以数量会持续增长。

数据集 来源 文档数 你搜索的内容
论文 arXiv q-fin(1997–2026) 约 18,647 标题、摘要、作者(按类别过滤)
代码 GitHub 仓库 约 12,957 名称、描述、主题(按语言、星标数过滤)
文章 量化博客 约 4,633 标题、描述(按来源、日期过滤)
策略 TradingView Pine 脚本 约 15,180 标题、描述、标签(按类别过滤)

这四个可搜索索引加起来略超过 51,000 篇文档。论文索引是单个语料库中最大的,也是我们投入最多精力的:它是完整的 arXiv 量化金融数据洪流(q-fin.*),可追溯到 1997 年,而非人工挑选的子集。早期该站点只提供数百篇精选论文;当前的索引是完整的 q-fin 语料库,并在其之上合并了精选的来源出处信息,因此一篇同时被某个特定量化博客引用过的论文会携带相应的出处归属。

除了这四个搜索索引,面向人类的站点还叠加了更多内容:我们自己撰写的研究笔记和每日摘要、一个量化站点作者目录、一个索引相关 YouTube 频道的视频板块,以及一个基金目录。这四个索引是可搜索的主干;其余一切都是围绕它的精选内容。

单一真实来源

一个规范的数据集核心,并行地为搜索索引和应用视图供给数据 —— 单一真实来源

早期悄悄给我们带来麻烦、如今我们竭力防范的,是数量不一致。首页显示一个数字,搜索返回另一个,API 又是第三个。曾经有那么一刻,首页宣称有 719 篇论文,而搜索返回了超过 18,000 篇。对于一个研究工具而言,没有什么比一个连自己有多大都说不一致的语料库更能腐蚀信任了。

解决办法是让每一个界面都从同一个地方读取数据。对于论文语料库,Meilisearch 就是真实来源。应用打包里不存在论文的第二份副本;首页上的数字、/papers 页面上的数字、API 返回的数字,以及你实际搜索到的文档,全都是同一个索引。语料库本身由一个离线的摄取步骤构建:它取出精选论文集,与 arXiv 数据洪流求并集(按 arXiv id 去重,并合并来源出处数组),按最新优先排序,写出一个约 25 MB 的单一文件供索引器消费。该文件大约有 15,000–18,000 条记录,并且刻意打包进客户端 —— 这种规模的语料库根本不应该传送到浏览器里。

另外三个数据集(代码、文章、Pine 脚本)在服务端从各自的 JSON 文件读取,并从同样的文件建立索引,迁移到 “以 Meili 为来源” 是计划中的下一步。贯穿始终的规则是:在服务端读取数据,绝不把数兆字节的数据集 import 进客户端打包,并让索引和展示的数字来自同一个源头。这样,数据不同步在结构上就变得不可能了。

搜索:全文、容错、分面

全文、容错、分面搜索:一束查询光线进入索引,返回一个经过排序、带高亮的结果列表

搜索引擎是 Meilisearch,与应用运行在同一台服务器上并绑定到 localhost —— 它不对外公开。我们把它用作全文搜索引擎,而非向量存储。没有嵌入向量,没有语义相似度的魔法。对于 “帮我找出提到这个概念的论文和仓库” 这类需求,针对标题、摘要、描述、作者和标签的容错词法搜索快速、可预测,并且在调试上远比嵌入索引来得方便。每个索引都存储完整的原始文档外加一个新增的 _id,因此一次搜索就能返回完全填充好的记录,应用可以直接渲染 —— 无需为命中结果二次请求来补全数据。

几个在实践中很重要的细节:

  • 容错与相关性排序是 Meilisearch 免费附送的。搜索 momentm 仍能找到 momentum(动量)相关的论文;结果是经过排序的,而不仅仅是过滤。

  • 分面过滤。 论文按 arXiv categoryq-fin.PMq-fin.TR 等)过滤,仓库按 languagestars 过滤,文章按 sourcedate 过滤,Pine 脚本按 category 过滤。/papers 页面根据索引实时的分面分布来构建其类别下拉菜单,因此过滤选项始终反映语料库中实际存在的内容。

  • camelCase 拆分。 Meilisearch 在空白和标点处分词,但不在 camelCase 处分词。这意味着一个直接命名为 TradingAgents 的仓库会是单个词元,用自然查询 “trading agents” 无法触及。在索引时我们派生出一个 name_split 字段 —— TradingAgentsTradingAgents Trading Agentsai-hedge-fundai-hedge-fund ai hedge fund —— 并把它加入可搜索属性。原始词元被排在最前,使得精确名称匹配仍然排名最高,而派生字段从不返回给客户端。这是个小细节,却决定了你能不能找到那个旗舰仓库。

  • 浏览 = 最新优先。 空查询不是错误;它是浏览路径。在 /papers 上,空查询按 published 降序排列,因此该页面同时也是一个倒序时间排列的最新 q-fin 研究信息流。

  • 一个用于聚合的旁路索引。 有些数字 Meilisearch 在查询时无法低成本地计算 —— 所有仓库的总星标数、Python 文件总数、notebook 总数。与其在每次页面加载时扫描整个语料库,索引器在建立索引时一次性把这些总和写入一个小型的 researcher_meta 索引,每个数据集对应一篇文档。stats 端点直接读回它们。只在重新建索引时才变化的计数,也只在重新建索引时计算。

  • 一个真正可用的分页上限。 论文索引把 Meilisearch 的 maxTotalHits 提升到 50,000,并将 published 标记为可排序,因此你可以在约 1.8 万篇文档的语料库中深度翻页,并把整个语料按最新优先排序 —— 而不仅限于相关性命中的第一页。

索引器是幂等的:它在每个索引不存在时创建它,重新应用设置,并以 2,000 篇为一批、以 _id 为键 upsert 每篇文档(论文的 _id 由 arXiv id 派生,仓库和文章由 URL 的哈希派生)。因为整个索引都可以从源文件重建,所以无需管理备份 —— 回滚就是重新建一次索引。重新运行它在构造上就是安全的。

智能体可访问:MCP 与公开 API

自主 AI 智能体节点通过一个 MCP 与公开 API 界面接入一个中央研究语料库

下面这部分把 researcher 与我们所做的其他事情联系了起来。语料库不只是一个带搜索框的网站 —— 它是一个 AI 智能体可以调用的工具

MCP 端点

researcher 在 /api/mcp 上通过 Streamable HTTP 暴露了一个模型上下文协议服务器。任何兼容 MCP 的智能体 —— Claude、我们自己技术栈中的自定义智能体、任何会说这个协议的东西 —— 都可以连接并对实时语料库调用只读工具。共有 13 个工具,按数据集分组,遵循一致的 search / get / list 形态:

分组 工具
论文 search_papersget_paperlist_papers
代码 search_reposget_repolist_repos
文章 search_articlesget_articlelist_articles_by_site
策略 search_pineget_pine_scriptlist_pine
知识 knowledge_query(优雅的占位实现,预留给未来的图谱层)

工具的 schema 是为智能体而写,而非为人类。以 search_papers 为例,它把自己描述为针对标题、摘要和作者的容错、按相关性排序的搜索,带一个可选的 category 过滤器(例如 q-fin.PM)和一个结果数量上限 —— 并告诉智能体在缩小范围之后调用 get_paper 来获取完整摘要。search 返回紧凑的、片段大小的命中结果,让智能体能够低成本地扫描许多结果;一旦选定某一篇,get 就返回完整记录。这种两步式形态让智能体的上下文窗口不至于淹没在它并不需要的摘要里。

具体来说,一个在调查(比如说)最优执行的智能体,可以运行 search_papers("optimal execution", category: "q-fin.TR") 来得到一份按相关性排序的标题与片段短名单,运行 search_repos("optimal execution", language: "Python") 来找到按相关性排序、可按星标数过滤的实现,再运行 search_pine("VWAP") 来看看同一个想法如何以一段已发布的 TradingView 策略呈现出来 —— 针对三个语料库的三次工具调用,而它们在一小时前还是三个不同的网站。然后一次 get_paper 就为那篇看起来有希望的论文取回完整摘要。智能体始终不离开协议,而且每个结果都是真实、已填充的记录,而非它还得回头再取一遍的搜索结果占位条目。

公开 REST API

对于非 MCP 的使用者,/api/v1/ 下有一套并行的 REST 接口:papersreposarticlespine,以及一个 stats 聚合接口。它讲纯 JSON,带 qcategorylimitoffset 参数,在返回每一页的同时给出真实的总数和分面分布,并且启用了 CORS。GET /api/v1/papers?q=optimal+execution&category=q-fin.TR 在任何地方都是一行就能搞定。同一个端点也驱动着站点自己的 /papers 页面 —— 浏览器只是又一个 API 客户端。

诚实地失败

一个会撒谎的搜索后端比一个宕机的更糟糕。对于 Meilisearch 不可达时会发生什么,我们采取了有意为之的立场。数据层在失败时抛出异常,而不是悄悄返回空结果 —— 由调用方决定如何处理。对于那些仍保留内存副本的数据集,工具会回退到对该副本进行普通的 .filter(),因此站点保持可用。对于论文 —— Meilisearch 就是真实来源、且没有第二份副本 —— 工具和 API 返回明确的错误(API 响应 503),而不是提供陈旧或不完整的数据。每次搜索调用都有一个很短的超时,因此一个卡死的索引不会拖垮某个工具。原则是:大声地降级,绝不悄悄递回错误答案。

数据是怎么进来的

摄取流水线:外部来源经过抽取与归一化阶段,流入一个统一索引

语料库由一套抓取器流水线供给,它们全都针对免费、公开的来源运行。

  • 论文来自 arXiv Atom API。一个采集器把完整的 q-fin 语料库拉取成 JSONL,一个构建步骤把它与精选集求并集(按 arXiv id 去重,合并来源出处),结果交给索引器。该采集器还有一个 “扩充这些特定 id” 的模式,用于从外部阅读清单进行种子初始化。
  • 代码是对量化相关 GitHub 仓库的一次爬取,连同对过滤至关重要的元数据一起捕获 —— 星标数、fork 数、主要语言、主题,以及 Python 文件数和 notebook 数。
  • 文章抓取自量化博客和聚合站点,其中较好的会在本地镜像一份,以便它们在链接失效后仍能存续。首页会标注我们保存了哪些文章的本地副本。
  • 策略是带元数据的 TradingView Pine 脚本 —— 作者、类别、标签、点赞数,以及该条目是否包含代码、图表或分析。
  • 视频索引相关的 YouTube 频道,使得讲座和讲解视频能与文字材料并列被发现。

生产环境中的重新建索引通过一条 SSH 隧道连到绑定在 localhost 的 Meilisearch 上运行,因为该引擎从不对互联网公开。整个循环 —— 采集、构建、部署、建索引 —— 都被设计成可幂等地重新运行,而这正是每日定时任务所做的事。

访问与托管

对一项托管服务的安全、经过认证的访问:一座发光的服务器集群前方有一道认证门

researcher 作为一个小型 Docker Compose 栈运行在我们的 Server 1 上:一个位于 Traefik 之后的 Next.js 容器,以及一个绑定到 localhost 的 Meilisearch 容器。Next.js 应用在服务端读取其数据集,并通过内部网络与 Meilisearch 通信。

访问通过我们的共享身份服务 auth.marketmaker.cc 来把关。令牌是 RS256 的 JWT,对照认证服务的 JWKS 进行校验 —— 每一次授权决策都会校验签名(带有严格的签发者和算法检查,在密钥端点不可达时按失败关闭处理),而未经校验的解码路径只用于纯装饰性的 UI,比如在导航栏里显示你的邮箱。认证服务签发按服务划分的角色;在 researcher 上,admin 角色为内部管理区把关(我们在那里运行并监控抓取器),而公开首页完全不需要任何令牌。这套认证架构与我们其他内部工具前置的是同一套,因此一次登录就能贯通整个生态系统。

它在 Marketmaker 技术栈中的位置

研究档案库在 Marketmaker 技术栈中的位置:一个为 AI 智能体和人类研究者供给数据的中央底座

researcher 是基础设施,而非终点。重点不在于这个网站 —— 而在于我们现在拥有了一个人与智能体共享的、对整个领域可查询的视图。

对作为人类的我们来说,这正是这个博客很多内容的来源。当我们评测像 VectorBT 这样的工具,或者剖析像 TradingAgentsFincept Terminal 这样的框架时,起点往往是在 researcher 上的一次搜索:这建立在哪些论文之上、还有哪些仓库解决同一个问题、谁写过它。档案库是漏斗;博客文章是从中沉淀出来的东西。

对我们的 AI 智能体来说,它的意义更具结构性。一个可通过 MCP 访问的研究底座,意味着一个在做策略工作的智能体不必去实时抓取 arXiv、不必同时应付四个不同的 API、也不必去猜外面有什么 —— 它对一个已经统一、去重并建好索引的语料库调用 search_paperssearch_repossearch_pine。这与我们的命令与操作(cmdop)以及智能体工具化的方向一致:给智能体提供类型化的、只读的、有良好文档的工具,让它们作用于真实数据,在后端不可用时大声失败,并让同一套共享后端从完全相同的索引同时服务人类 UI 和机器接口。人类浏览,智能体查询 —— 但他们看的是同一个档案库,而这正是整个理念所在。

结语

researcher 起初是为了解决一个小而恼人的问题 —— 量化研究散落在四个彼此不通气的地方 —— 后来变成了我们每天都依赖的东西。横跨论文、代码、文章和策略的大约 51,000 篇文档,全都在一个全文搜索引擎之后,既能被一个拿着浏览器的人访问,也能被一个带着 MCP 客户端的智能体访问。它刻意地不花哨:用全文搜索,而非嵌入向量;用单一真实来源,而非巧妙的缓存;用会抛出诚实错误的工具,而非那些掩盖故障的工具。

如果你正在为交易研究构建智能体,这个经验可以推广到我们这个特定语料库之外:你能给智能体的最高杠杆之物,不是一个更大的模型,而是一个对它所需数据干净、统一、可查询的视图 —— 并通过人类所信任的同一套索引暴露出来。这就是 researcher。

免责声明:本文提供的信息仅用于教育和参考目的,不构成财务、投资或交易建议。加密货币交易涉及重大损失风险。

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

紧跟市场步伐

订阅我们的时事通讯,获取独家 AI 交易见解、市场分析和平台更新。

我们尊重您的隐私。您可以随时退订。