ESSAY

PTC:Agent架构中最值得学但最被忽视的设计模式

Agent 架构设计 PTC 开源项目

“每次看到一个不相关领域的优秀项目,你都有一个选择:滑走,或者停下来拆解它的架构。“

核心观点 / 起源

最近在HN上看到一个叫LangAlpha1的项目被推到前面,标题是”Claude Code for Wall Street”。一个面向金融研究的AI Agent平台,功能包括DCF模型、财报分析、投资报告生成——全是金融领域的垂直场景。

如果你不做金融,很容易滑走。但我建议你停下来看看,不是因为它的领域知识,而是因为它内部藏着一个主流Agent框架都没解决好的问题——并且给出了一个优雅的答案。

这个答案叫Programmatic Tool Calling,简称PTC。它不是多Agent编排,不是记忆系统,不是中间件——这些LangGraph、CrewAI、OpenAI SDK都有。PTC是LangAlpha最有价值的架构创新,而且我在目前的主流框架里没看到同级别的实现。

细节展开

Agent上下文窗口的诅咒

先回想一个常见场景。

你写了一个Agent,给它配了一个数据查询工具。用户问”帮我分析过去一年每个月的销售趋势”,Agent调用数据库工具,返回了1000行记录。每行50 tokens,一共50k tokens——还没开始分析,上下文已经塞进去半本书。

然后Agent调用第二个工具做聚合,又返回50k tokens。等它终于开始写分析报告时,上下文里已经堆了150k tokens的各种原始数据,模型在噪音中找信号,中间结果和最终推理混在一起,Token成本越来越高,输出质量反而下降。

这不是金融特有的问题。任何涉及数据处理的Agent都面临这个诅咒:数据越多,上下文越胀,模型越笨。

传统的AI Agent工作流是这么走的:

Model → tool_A → Model → tool_B → Model → tool_C → Model

每一步,工具返回的原始数据都经过模型推理,塞回上下文窗口。到第5步的时候,上下文里的原始数据可能已经占了90%的Token,留给模型思考的空间不到10%。

LangChain Deep Agents的研究把这个问题总结为”三个上下文面”(Three Context Surfaces):

上下文面作用特性
Message history模型推理的直接对象昂贵,注意力受限
Filesystem持久化工件和长期工作记忆廉价,容量大
Interpreter state工作值(数组、对象、计数器)在eval间持久,不进模型

传统Tool Loop的问题在于:把所有数据都塞进Message history,把最昂贵的上下文面当存储用。

PTC做的事情很简单:把数据处理从Message history移到Filesystem和Interpreter state。


PTC的核心思想:把数据留在外面

一句话定义: Agent不在LLM上下文中处理原始数据,而是在沙箱里写代码执行数据处理,只把结果摘要返回给LLM。

两种模式的对比:

传统模式:  Model → tool_A → Model → tool_B → Model → tool_C → Model
PTC模式:   Model → code(tool_A, tool_B, tool_C) → Model

在PTC模式下,模型”一步到位”:它先生成一段Python代码,这段代码串起所有工具调用,在沙箱里依次执行。只有最终的print()结果回到LLM上下文——中间产生的所有数据,包括原始数据、中间变量、过滤结果、聚合统计,全部留在沙箱里。

这不是”让模型写代码”这么简单。这是对Agent-工具交互方式的范式转换

  1. 调用主体变了:不是LLM逐个”请求”工具,而是代码在沙箱内”操作”工具
  2. 数据流向变了:原始数据不经过LLM的上下文窗口,只进沙箱内存
  3. 上下文角色变了:上下文不再是数据仓库,而是推理工作台——只放它需要推理的信息

为什么比Tool Loop更可靠?这是一个反直觉但被实验验证的事实:让模型写代码处理数据,比让模型直接推理数据更可靠。

原因在于数字处理是LLM的弱项。你让模型”从1000条记录里找出异常值”,它可能会凭”感觉”挑几条,而非精确计算。但你让模型”写一段Python代码用3-sigma方法找出异常值”,代码在沙箱里执行的结果是确定的。

AWS Bedrock团队在2025-2026年的系统测试中发现:在非PTC模式下,8个主流模型中只有Claude能完成任务;而在PTC模式下,所有8个模型全部正确。PTC是一个模型无关的架构模式——它不依赖模型本身的推理能力,而是把推理负载从模型转移到代码。

过程 / 推演

LangAlpha的PTC实现:案例解剖

LangAlpha的PTC实现分为四个层次:

1. MCP → Python API 自动转换

这是整个PTC架构的起点。大多数Agent框架的做法是把MCP Server的工具schema丢给LLM,让LLM在推理过程中决定调哪个工具、传什么参数。LangAlpha走了完全不同的路:

当工作区初始化时,每个MCP Server被自动翻译成一个Python模块,放在沙箱的tools/目录下。翻译后的模块包含完整的类型签名、docstring和函数定义。LLM的系统提示里只写一句话:

你有一个 tools/fundamentals 模块,里面有 get_financial_statements() 函数,支持传入ticker和period参数。完整文档在沙箱的 tools/fundamentals.md

Agent需要用到时,写一句:

from tools.fundamentals import get_financial_statements
import pandas as pd

data = get_financial_statements("AAPL", period="5y")
result = data.groupby("year").eps.mean()
print(result)

这个”MCP→Python”自动转换层带来的Token节省是巨大的。工具schema不再占用上下文——一个MCP Server可能有几十个函数、每个函数有复杂的参数结构,这些全部留在沙箱的.py文件里,LLM只需要记住一行import语句。

2. 渐进式工具发现

传统做法是一次性加载所有工具的schema到上下文,即使Agent根本用不到。LangAlpha的实现是懒加载的:Agent在首次调用一个工具之前,才去读取它的markdown文档。这进一步降低了首轮对话的Token消耗,而且更符合真实工作模式——人类开发者也是用到什么库才查什么文档。

3. 沙箱执行引擎

LangAlpha使用Daytona沙箱(也可用本地Docker)作为代码执行环境。Daytona的核心能力是一个90ms启动的容器预热池:

container_pool = {
    'python': [Container1, Container2, ...],
}
sandbox = container_pool['python'].pop()

执行流程:

  1. Agent生成包含print()的Python代码
  2. 框架提取代码块,写入沙箱文件系统
  3. 沙箱内执行(默认配置:无网络、只读文件系统、非root用户、CPU/内存限制、30s超时)
  4. stdout/stderr捕获后返回给Agent
  5. 只有print()输出的摘要回到LLM上下文

如果执行超时或有语法错误,Agent会收到错误信息并自行修复代码重试。这个”自动修复”环节本身就是LLM擅长的——比让LLM直接从原始数据里推理可靠得多。

4. 配合工作区的持久化

PTC不是孤立运行的。LangAlpha把每次沙箱执行视为一次研究会话(session),中间产物自动写入工作区:

agent.md                  — 跨会话的研究记忆
work/<task_name>/         — 本次会话的工作区
  data/                   — 原始数据和中间结果
  charts/                 — 可视化输出
results/                  — 最终报告

这意味着Agent周一开始的研究,周二可以无缝续上。agent.md记录了目标、进展、关键发现、文件索引,下一次会话自动注入。

一点补充

PTC的效果数据

数据最有说服力。以下来自AWS Bedrock团队在2025-2026年的系统测试,涵盖8个模型、跨多个数据密集型任务。

模型PTC Token非PTC Token减少率
DeepSeek v3.219,543245,96792.1%
Kimi 2.510,875148,08592.7%
Claude Sonnet 4.612,739128,04390.1%
Claude Opus 4.613,043126,15289.7%
Qwen3-Coder-480B34,159305,11488.8%
Qwen3-Next-80B28,878233,33287.6%
MiniMax M2.111,787101,99088.4%
GLM 4.711,550115,82990.0%

平均Token减少率约90%。这个数字不是实验室里的极端值,而是跨多种任务类型的平均值。也就是说,你把输入Token的预算乘10,用PTC就能做到同等效果。

正确率方面:非PTC模式下8个模型中只有Claude能正确完成任务;PTC模式下所有8个模型全部正确。这意味着PTC抹平了模型之间的能力差距——一个弱模型加上PTC,可能在特定数据处理任务上超过一个强模型不加PTC。

成本方面:按每日1000次查询估算,非PTC约$15,600/月,PTC约$1,560/月,约10倍差距。

PTC的实现方案取舍

LangAlpha不是唯一的PTC实现,2025-2026年出现了多个方案:

方案沙箱方式启动速度隔离级别适用场景
LangAlphaDaytona/Docker~90ms容器级长期研究,需持久化工作区
AWS Bedrock PTCECS Docker + IPC~秒级容器级AWS生态,模型无关
Deep Agents InterpreterQuickJS~毫秒级语言级轻量JS计算
Anthropic官方托管沙箱托管托管Claude专用
open-ptc-agentDaytona~90ms容器级开源,可自托管

选择的核心取舍点有三个:

  • 隔离级别:Docker/容器级隔离提供完整进程隔离和网络限制;QuickJS轻量但不够安全
  • 持久化需求:超过一次会话的任务需要工作区持久化;独立会话用轻量方案即可
  • 运维成本:托管方案减少运维负担但绑定平台;自建方案灵活但需维护

PTC不适合的场景:简单单次查询(开销>收益)、Agent需要对中间结果做语义推理、沙箱启动成本高于数据处理本身。金标准:如果你的Agent调一个工具返回100k tokens,PTC就该上;如果只处理200 tokens,PTC是过度设计。

结语 / 反思

如果你已经被说服,下面是一条经过验证的落地路径,不需要一步到位。

Phase 0:手动验证(1天)——手动写Python脚本处理数据,只传摘要给LLM,感受Token节省量和输出质量的变化。

Phase 1:容器沙箱(1-2周)——引入Docker沙箱让Agent自动写代码执行。关键配置:无网络、只读文件系统、非root用户、内存/CPU限制、超时机制。

Phase 2:MCP→Python自动转换(1-2周)——用MCP SDK的list_tools()接口自动生成Python模块,或手写封装模块。

Phase 3:持久化工作区(持续优化)——如果Agent涉及跨会话研究,引入工作区文件系统(agent.md + work/ + results/)。

不是每个Agent都需要PTC。但如果你做处理数据的Agent,你应该试过PTC再决定不用它。

每次看到一个”不相关”领域的优秀项目,你都有一个选择:滑走,或者停下来拆解它的架构。LangAlpha被贴上”金融”的标签,这也许是一个损失——因为最值得学的PTC是模型无关、领域无关的设计模式。它解决的是每个Agent开发者都会遇到、但很多人没意识到可以解决的问题:不是所有数据都需要进上下文。

下次你写一个需要查数据再分析的Agent,问自己一个简单的问题:这些数据真的需要进LLM的上下文吗?

答案通常是不需要。


Footnotes

  1. LangAlpha 仓库:https://github.com/ginlix-ai/langalpha。PTC相关研究:AWS Bedrock PTC实现、LangChain Deep Agents、open-ptc-agent

输入关键词开始搜索