<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Financial Tech on Hypho - AI Agent 技术博客</title><link>https://blog.hypho.cn/tags/financial-tech/</link><description>Recent content in Financial Tech on Hypho - AI Agent 技术博客</description><image><title>Hypho - AI Agent 技术博客</title><url>https://blog.hypho.cn/papermod-cover.png</url><link>https://blog.hypho.cn/papermod-cover.png</link></image><generator>Hugo -- 0.148.2</generator><language>zh-cn</language><lastBuildDate>Wed, 15 Apr 2026 10:00:00 +0800</lastBuildDate><atom:link href="https://blog.hypho.cn/tags/financial-tech/index.xml" rel="self" type="application/rss+xml"/><item><title>LangAlpha：把 Claude Code 思维搬进金融投研，多智能体沙盒复利研究实战</title><link>https://blog.hypho.cn/posts/langalpha-multi-agent-finance-research/</link><pubDate>Wed, 15 Apr 2026 10:00:00 +0800</pubDate><guid>https://blog.hypho.cn/posts/langalpha-multi-agent-finance-research/</guid><description>LangAlpha 是将 AI Agent 思维系统性引入金融投研的开源框架，通过持久化工作空间、编程式工具调用（PTC）和 Agent Swarm 架构，让 AI 研究自然复利累积。本文深入解析其核心技术设计：LLM 写 Python 在云端沙盒执行、多层数据供给链、以及 23 个预置投研技能如何在多会话间持续构建认知资产。</description><content:encoded><![CDATA[<h2 id="真实案例引入一位分析师的日常工作困境">真实案例引入：一位分析师的日常工作困境</h2>
<p>张明（化名）是某私募的科技行业分析师。2025 年 Q4，他花了整整三周研究 NVIDIA 的数据中心业务护城河——从季报电话会记录、供应链文件、到 H100/H200 的产能分配逻辑，积累了大量笔记和 Excel 模型。</p>
<p>但问题来了：2026 年 2 月，DeepSeek-R2 发布后，客户开始问他&quot;这对 NVIDIA 影响多大&quot;。他打开笔记本，发现自己的分析框架已经支离破碎——三周前的笔记散落在不同文件，LLM 对话上下文早已丢失，要从头回忆当时的核心判断和假设前提。</p>
<p>他需要的是<strong>研究的复利</strong>：让 AI 在每次对话中记住之前的工作，持续累积洞察，而不是每次都从零开始。</p>
<p>这正是 LangAlpha 试图解决的核心问题——将 Claude Code/OpenManus 等代码 Agent 的&quot;持久上下文 + 增量构建&quot;模式，系统性引入金融投研场景。GitHub 已有 <strong>694 Stars</strong>，最新提交距今不到 24 小时，项目获得了 Gemini 3 Hackathon 奖项。</p>
<hr>
<h2 id="框架核心拆解">框架核心拆解</h2>
<h3 id="整体架构">整体架构</h3>
<p>LangAlpha 的后端基于 FastAPI，前端为 React 19 + Vite + Tailwind Web UI，消息推送采用 SSE（Server-Sent Events），状态持久化用 PostgreSQL 双池（应用数据 + LangGraph Checkpointer），Redis 承担事件缓冲和实时数据缓存。</p>
<pre tabindex="0"><code class="language-mermaid" data-lang="mermaid">%%{init: {&#39;theme&#39;: &#39;neutral&#39;}}%%
flowchart TB
    Web[&#34;Web UI&lt;br/&gt;React 19 · Vite · Tailwind&#34;] --&gt; API
    Web --&gt; WSP
    CLI[&#34;CLI / TUI&#34;] --&gt; API

    subgraph Server [&#34;FastAPI Backend&#34;]
        API[&#34;API Routers&lt;br/&gt;Threads · Workspaces · Market Data&#34;] --&gt; ChatHandler
        ChatHandler[&#34;Chat Handler&lt;br/&gt;LLM Resolution · Credit Check&#34;] --&gt; BTM
        BTM[&#34;Background Task Manager&lt;br/&gt;asyncio.shield · Workflow Lifecycle&#34;]
    end

    subgraph PostgreSQL [&#34;PostgreSQL — Dual Pool&#34;]
        AppPool[&#34;App Data&lt;br/&gt;Users · Workspaces · Threads&#34;] --&gt; BTM
        CheckPool[&#34;LangGraph Checkpointer&lt;br/&gt;Agent State · Checkpoints&#34;] --&gt; BTM
    end

    subgraph Redis [&#34;Redis&#34;]
        EventBuf[&#34;SSE Event Buffer&#34;] --&gt; BTM
        Steering[&#34;Steering Queue&lt;br/&gt;User Messages Mid-workflow&#34;] --&gt; BTM
        DataCache[&#34;API Cache&lt;br/&gt;Market Data&#34;] --&gt; API
    end

    BTM -. &#34;Sandbox API&#34; .-&gt; Daytona[&#34;Daytona&lt;br/&gt;Cloud Sandboxes&#34;]
    API -. &#34;REST&#34; .-&gt; FinAPIs[&#34;Financial APIs&lt;br/&gt;FMP · SEC EDGAR&#34;]
    WSP -. &#34;WebSocket&#34; .-&gt; GData[&#34;ginlix-data&lt;br/&gt;Polygon.io&#34;]
</code></pre><p>核心设计理念：<strong>工作空间（Workspace）是研究的容器，线程（Thread）是会话的单元，Agent.md 是跨会话的持久记忆</strong>。</p>
<h3 id="编程式工具调用ptctoken-消耗降低一个数量级">编程式工具调用（PTC）：Token 消耗降低一个数量级</h3>
<p>传统 Agent 调用金融数据的典型方式：用户问&quot;帮我查一下苹果最新的毛利率&quot;，Agent 调用 <code>get_financials(&quot;AAPL&quot;)</code>，API 返回 200 行原始财务数据，全部塞入 LLM context 窗口。Token 消耗惊人，而且原始数据里大量字段 Agent 根本不需要。</p>
<p>LangAlpha 的 PTC（Programmatic Tool Calling）彻底翻转了这个范式：<strong>Agent 自己写 Python 代码，在云端沙盒执行，只把最终结果返回给 LLM</strong>。</p>
<pre tabindex="0"><code class="language-mermaid" data-lang="mermaid">%%{init: {&#39;theme&#39;: &#39;neutral&#39;}}%%
flowchart LR
    LLM[&#34;LLM&lt;br/&gt;Writes Python&#34;] --&gt; EC[&#34;ExecuteCode Tool&#34;]
    EC --&gt; Run[&#34;Code Runner&#34;]

    subgraph Sandbox [&#34;Daytona Cloud Sandbox&#34;]
        Run --&gt; Wrappers[&#34;Generated Wrappers&lt;br/&gt;One module per MCP server&#34;]
        Wrappers --&gt; MCP[&#34;MCP Servers&lt;br/&gt;Subprocesses in sandbox&#34;]
    end

    MCP --&gt; APIs[&#34;Financial APIs&lt;br/&gt;FMP · Yahoo · Polygon&#34;]
    APIs --&gt; MCP
    Run --&gt; EC
    EC --&gt; LLM
</code></pre><p>举例：用户请求&quot;对比一下苹果、微软、谷歌过去 5 年的营业利润率，并画出趋势图&quot;。Agent 的思考链不是&quot;调用工具获取原始数据 → 塞入 context&quot;，而是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Agent 生成的 PTC 代码示例（LangAlpha 实际生成的代码结构）</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">yf_analysis</span> <span class="k">as</span> <span class="nn">yf</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tickers</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;AAPL&#34;</span><span class="p">,</span> <span class="s2">&#34;MSFT&#34;</span><span class="p">,</span> <span class="s2">&#34;GOOGL&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">years</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2019</span><span class="p">,</span> <span class="mi">2025</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">ticker</span> <span class="ow">in</span> <span class="n">tickers</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">bs</span> <span class="o">=</span> <span class="n">yf</span><span class="o">.</span><span class="n">get_balance_sheet</span><span class="p">(</span><span class="n">ticker</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">is_</span> <span class="o">=</span> <span class="n">yf</span><span class="o">.</span><span class="n">get_income_statement</span><span class="p">(</span><span class="n">ticker</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">operating_margins</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">year</span> <span class="ow">in</span> <span class="n">years</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">revenue</span> <span class="o">=</span> <span class="n">is_</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="s2">&#34;Total Revenue&#34;</span><span class="p">,</span> <span class="n">year</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">operating_income</span> <span class="o">=</span> <span class="n">is_</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="s2">&#34;Operating Income&#34;</span><span class="p">,</span> <span class="n">year</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">margin</span> <span class="o">=</span> <span class="n">operating_income</span> <span class="o">/</span> <span class="n">revenue</span>
</span></span><span class="line"><span class="cl">        <span class="n">operating_margins</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&#34;year&#34;</span><span class="p">:</span> <span class="n">year</span><span class="p">,</span> <span class="s2">&#34;margin&#34;</span><span class="p">:</span> <span class="n">margin</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">results</span><span class="p">[</span><span class="n">ticker</span><span class="p">]</span> <span class="o">=</span> <span class="n">operating_margins</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 生成图表</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">ticker</span><span class="p">,</span> <span class="n">data</span> <span class="ow">in</span> <span class="n">results</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">years</span> <span class="o">=</span> <span class="p">[</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;year&#34;</span><span class="p">]</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">data</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">margins</span> <span class="o">=</span> <span class="p">[</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;margin&#34;</span><span class="p">]</span> <span class="o">*</span> <span class="mi">100</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">data</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">years</span><span class="p">,</span> <span class="n">margins</span><span class="p">,</span> <span class="n">marker</span><span class="o">=</span><span class="s2">&#34;o&#34;</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="n">ticker</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">&#34;Operating Margin Trend (5Y)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s2">&#34;results/operating_margin_trend.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Chart saved to results/operating_margin_trend.png&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>整个多年度数据拉取、跨公司横向比对、图表渲染，全部在沙盒内完成，<strong>LLM 只收到最终图表路径和关键数字</strong>，而不是几千行原始 JSON。</p>
<h3 id="持久化工作空间让-ai-每次都从记忆出发">持久化工作空间：让 AI 每次都从记忆出发</h3>
<p>每个 Workspace 对应一个 Daytona 云端沙盒，带有固定目录结构：</p>
<pre tabindex="0"><code>/workspace/
├── work/              # 每次任务的临时工作区
│   └── &lt;task_name&gt;/
│       ├── data/      # 原始数据
│       ├── charts/   # 生成的图表
│       └── code/      # 执行的脚本
├── results/           # 最终交付物
├── data/              # 共享数据集
└── agent.md           # 跨会话持久记忆
</code></pre><p><code>agent.md</code> 是 LangAlpha 最关键的设计之一——Agent 在每次会话结束时自动将当前进度、关键发现、待跟进问题写入 <code>agent.md</code>，下次会话时 middleware 自动将其注入 LLM 上下文。这意味着：</p>
<ul>
<li>研究&quot;Q2 数据中心需求深度分析&quot;的 Workspace，第二周回来时 Agent <strong>已经知道</strong>之前的核心假设：H100 产能约束、中国区需求占比、Grace-Hopper 供应链风险</li>
<li>不需要用户手动总结历史上下文</li>
<li>研究自然累积，像一个永不遗忘的分析师助理</li>
</ul>
<h3 id="23-个预置投研技能">23 个预置投研技能</h3>
<p>LangAlpha 预装了 23 个金融研究技能（Skills），覆盖最常见的投研工作流，每个技能本质上是一个 <code>SKILL.md</code> 定义的工作流模板，可通过斜杠命令或自动意图检测激活：</p>
<table>
  <thead>
      <tr>
          <th>技能</th>
          <th>用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>dcf-model</code></td>
          <td>现金流折现模型构建</td>
      </tr>
      <tr>
          <td><code>comps-analysis</code></td>
          <td>可比公司法分析</td>
      </tr>
      <tr>
          <td><code>earnings-analysis</code></td>
          <td>财报深度解读</td>
      </tr>
      <tr>
          <td><code>morning-note</code></td>
          <td>晨会简报生成</td>
      </tr>
      <tr>
          <td><code>initiating-coverage</code></td>
          <td>首次覆盖报告模板</td>
      </tr>
      <tr>
          <td><code>thesis-tracker</code></td>
          <td>核心投资论点追踪</td>
      </tr>
      <tr>
          <td><code>sector-overview</code></td>
          <td>行业全景扫描</td>
      </tr>
      <tr>
          <td><code>check-deck</code></td>
          <td>投资 Deck 质量检查</td>
      </tr>
  </tbody>
</table>
<p>每个技能对应 MCP 服务器的特定工具子集，Agent 在激活技能时只暴露相关工具，避免过度工具化的上下文污染。</p>
<hr>
<h2 id="关键工程洞察">关键工程洞察</h2>
<h3 id="1-ptc-模式将-token-成本从-on数据量-降为-o结果">1. PTC 模式将 Token 成本从 O(n×数据量) 降为 O(结果)</h3>
<p>在传统 JSON Tool Calling 模式下，分析 AAPL/MSFT/GOOGL 三年季度数据，Token 消耗约为 <code>3 公司 × 4 季度 × 3 年 × 单季度数据量 ≈ 36× 单季度原始数据</code>。</p>
<p>PTC 模式：Agent 生成 ~20 行 Python 代码（&lt; 500 tokens），沙盒执行后返回一张图和 9 个数字（&lt; 200 tokens）。<strong>整体 Token 减少 95% 以上</strong>，且分析精度更高（代码逻辑可审计、可复用）。</p>
<p>这对需要<strong>大规模量化筛选</strong>（扫描整个 S&amp;P 500 财务数据找异常值）的场景尤为关键。</p>
<h3 id="2-数据供给链的三层降级设计是务实工程">2. 数据供给链的三层降级设计是务实工程</h3>
<p>LangAlpha 没有假设用户有彭博终端。它设计了数据 Provider 的三层降级链：</p>
<table>
  <thead>
      <tr>
          <th>层级</th>
          <th>数据源</th>
          <th>费用</th>
          <th>覆盖范围</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Tier 1</td>
          <td>ginlix-data（自建代理）</td>
          <td>需要 API Key</td>
          <td>实时 WebSocket、内盘数据、期权数据</td>
      </tr>
      <tr>
          <td>Tier 2</td>
          <td>FMP（Financial Modeling Prep）</td>
          <td>免费/付费</td>
          <td>高质量基本面、财务报表、宏观数据</td>
      </tr>
      <tr>
          <td>Tier 3</td>
          <td>Yahoo Finance（yfinance）</td>
          <td>免费</td>
          <td>价格历史、基本面、ESG、筛选器</td>
      </tr>
  </tbody>
</table>
<p><strong>系统自动降级</strong>：Tier 1 不可用 → Tier 2 → Tier 3。用户也可以用 <code>make config</code> 快速切换层级组合。</p>
<p>这对个人投资者和初创团队意义重大——<strong>零成本启动</strong>，随着研究规模升级到付费数据源，不需要换框架。</p>
<h3 id="3-flash--ptc-双模式设计是会话与深度分析的恰当分离">3. &ldquo;Flash + PTC&rdquo; 双模式设计是会话与深度分析的恰当分离</h3>
<p>LangAlpha 将 Agent 行为分为两个模式：</p>
<ul>
<li><strong>Flash 模式</strong>：快速会话——行情速查、即时问答、Workspace 管理、轻量级图表分析。延迟低，Token 消耗小，适合&quot;刚才 NVDA 涨了多少&quot;这类问题。</li>
<li><strong>PTC 模式</strong>：深度研究——多步骤财务建模、跨时期趋势分析、生成正式报告。启动沙盒有 ~2-5 秒冷启动开销，但分析质量远高于 Flash。</li>
</ul>
<p>这解决了 AI 投研工具的一个经典矛盾：用户既需要&quot;秒回&quot;的快速查询，也需要&quot;深度&quot;的多步骤分析，传统 RAG + 单 Agent 架构无法同时兼顾。</p>
<hr>
<h2 id="信源">信源</h2>
<ul>
<li>LangAlpha GitHub 仓库：https://github.com/ginlix-ai/langalpha</li>
<li>LangAlpha README（含架构图与技能列表）：https://github.com/ginlix-ai/langalpha#readme</li>
<li>LangAlpha API 文档：https://github.com/ginlix-ai/langalpha/tree/main/docs/api</li>
<li>Financial Modeling Prep（免费数据层）：https://site.financialmodelingprep.com/ （FMP 提供免费注册 API Key）</li>
<li>Daytona Sandboxes（云端代码执行）：https://www.daytona.io/</li>
<li>Agent Skills Spec（技能规范）：https://agentskills.io/specification</li>
</ul>
]]></content:encoded></item></channel></rss>