当前 AI Agent 框架热衷于构建复杂的循环链:规划器 → 执行器 → 反思器 → 再规划。我选择了反过来:工具是无状态纯函数,LLM 自己决定调用顺序。不是因为循环链不酷,而是因为它把决策权放错了地方。
两种架构,一个根本分歧
在 上一篇 里,我解释了为什么没有用多智能体架构。那篇文章的结论是"用单 Agent + 状态机"。但这只回答了"几个 Agent"的问题,没有回答一个更重要的问题:Agent 的决策边界在哪里?
目前主流的 Agent 框架(LangGraph、CrewAI、AutoGen)都在做同一件事:构建一条越来越复杂的决策管道。规划器决定做什么,执行器去做,反思器评估结果,然后回到规划器。管道本身是"聪明"的——它知道何时循环、何时退出、何时回溯。
我做了一个相反的选择:管道是"笨"的,工具是"聪明"的。
具体来说:QuantGPT 的 MCP server 暴露了 10 个独立工具(run_backtest、score_factor、diagnose_factor、run_anti_overfit 等),每个工具是无状态纯函数——接收参数,返回完整结果,不记录调用历史,不知道上一次调用了什么。
“管道"在哪?不存在。LLM Agent(Claude)直接看到所有工具的描述,自己决定下一步调用什么。没有 planner、没有router、没有 reflection loop——这些全部由 LLM 自身的推理能力承担。
这不是偷懒。这是架构选择。
“聪明管道"的隐含假设
当你构建一个 Planner → Executor → Reflector 循环链时,你隐含地做了一个假设:你比 LLM 更知道决策应该怎么流转。
这个假设在 2023 年是合理的。GPT-3.5 的推理能力有限,确实需要外部脚手架来引导它——告诉它"先规划再执行”、“执行完要反思”、“反思后要判断是否重试”。框架的价值在于弥补模型能力的不足。
但到了 2025 年,这个假设越来越可疑。
Claude、GPT-4o、DeepSeek-V3 已经具备了强大的工具选择和多步推理能力。当你给它 10 个工具和一个目标,它完全有能力自己规划调用顺序。它甚至能根据中间结果动态调整策略——这恰恰是循环链无法做到的,因为循环链的分支逻辑是你预先编码的。
聪明管道的问题不是"它不工作”,而是"它固化了一个特定的决策流程,而这个流程很可能不是最优的"。
举一个具体例子。在我的因子研究场景中,标准的 Agent 循环链会这样设计:
生成因子 → 回测 → 评分 → 分数够高?
├── 是 → 反过拟合检验 → 通过? → 提交
└── 否 → 突变 → 回到生成
这看起来很合理。但实际研究中会出现循环链无法处理的情况:
- Agent 发现某个因子评分一般,但诊断结果显示只是窗口参数偏小,直接调参就行,不需要走完整的突变-重生成流程
- Agent 发现两个独立因子各自 Sharpe 1.3,想直接尝试交叉组合,但循环链里没有这个分支
- Agent 在跑反过拟合时发现 IC 在某个子样本上突然衰减,想临时回去跑一个诊断看是不是行业暴露问题
这些都是研究者的即兴判断,不是可以预编码的分支。循环链的每一个 if-else 都需要开发者预见到这个场景。预见不到的就走不通。
MCP 工具设计的三条原则
既然不用循环链,工具本身的设计就变得至关重要。我遵循了三条原则:
1. 无状态:每个工具调用独立完备
@mcp.tool()
async def run_backtest(expression: str, universe: str = "hs300", ...):
# 不读取任何全局状态
# 不依赖"上一次调用的结果"
# 返回完整的回测报告(指标 + 诊断 + 评分)
...
工具不知道自己是被"第一次"调用还是"迭代第 15 次"调用。它不关心上下文。这意味着 Agent 可以以任意顺序、任意频率调用任何工具,不会出现"状态不一致"的问题。
对比循环链:如果 Executor 依赖 Planner 设置的全局变量,那 Agent 必须严格按照 Planner → Executor 的顺序调用。打破顺序就打破一致性。
2. 完整返回:结果自包含,不需要后续查询
每个工具的返回值包含所有相关信息,Agent 不需要再调用另一个工具来"补充"结果。
run_backtest 返回的不只是 Sharpe 和 Returns——它同时返回分组收益、换手率、最大回撤、行业暴露、因子载荷。Agent 看到完整图景后自己判断下一步做什么。
这和 Unix 哲学的"小而专"相反。小而专适合人类组合管道(cat | grep | sort),但 LLM 不擅长组合十次调用来拼凑一个完整结果——它擅长从一个完整结果中提取关键信息。工具设计要适配调用者的认知模式,不是设计者的审美偏好。
3. 语义命名:工具名就是意图描述
run_backtest — 我想知道这个因子的表现
score_factor — 我想知道这个因子的综合评分
diagnose_factor — 我想知道这个因子为什么表现不好
run_anti_overfit — 我想知道这个因子是不是过拟合了
run_rolling_validation — 我想知道这个因子在不同时间段的稳定性
LLM 根据自然语言描述选择工具。工具名越接近意图描述,LLM 的选择准确率越高。我不需要 router 来分发请求——语义匹配就是最好的路由。
“但你需要一个 planner 来…”
反对意见通常是这样的:“没有 planner,Agent 怎么知道先做什么?”
答案是:它本来就知道。
给 Claude 一个目标"挖掘一个 Fitness > 1.0 的因子"和 10 个工具描述,它会自发地:
- 先检查可用算子(
list_operators) - 设计一个因子表达式
- 验证语法(
validate_expression) - 回测(
run_backtest) - 评分(
score_factor) - 如果分数低,诊断问题(
diagnose_factor) - 根据诊断修改表达式,回到第 3 步
- 如果分数高,检测过拟合(
run_anti_overfit) - 通过后提交
没有人教它这个流程。它从工具的语义描述中自行推导出来的。
更重要的是,它会根据中间结果偏离这个流程。如果诊断发现不是表达式问题而是股票池问题,它会切换股票池重跑,而不是继续在同一个池子里迭代。如果反过拟合检测发现 IC 衰减集中在 2022 年下半年,它会推测是市场结构变化导致的,主动缩短窗口重测。
这种灵活性是你无法在循环链中预编码的。 你能写 if-else 处理 10 种情况,但第 11 种需要改代码。LLM 能处理任意多种情况,只要工具的能力覆盖到。
这不是"无架构"
有人会说:“你只是把架构决策推给了 LLM,这不是好的工程实践。”
不对。架构依然存在,只是位置不同。
循环链架构的约束在管道层——管道定义了哪些步骤可以走、走到哪分叉、何时循环。Agent 的自由度被管道框住。
我的架构的约束在工具层——工具定义了 Agent 能做什么、每个操作返回什么信息、操作之间没有隐式依赖。Agent 的自由度被能力集框住。
类比操作系统:循环链是宏内核,所有决策逻辑编译在一起;MCP 工具集是微内核,只暴露系统调用,调度逻辑在用户态(LLM)。
两种架构都有约束。区别在于:管道约束是流程约束(你必须按这个顺序走),工具约束是能力约束(你只能用这些操作)。
流程约束容易过时——研究范式变了就得改管道。能力约束更稳定——只要操作的语义不变,Agent 可以自由组合出新流程。
实际效果
这个架构在 QuantGPT 上跑了几个月,产出了 3 个正式提交 WorldQuant BRAIN 的因子(最佳 Fitness 1.26、Sharpe 1.77),全部 IS 检测通过。
几个具体的观察:
Agent 发明了我没预想过的研究路径。 例如它发现 ts_av_diff 和 rank(debt/enterprise_value) 各自表现一般,但主动尝试加法组合后 Fitness 从 0.7 跃升到 1.26。没有任何代码告诉它"试试组合"——它从 score_factor 的结果中自行推理出两个信号互补。
调试从"追踪管道状态"变成"看 Agent 日志"。 Agent 的每次工具调用和返回结果都是独立的 JSON,按时间线排列就是完整的研究记录。不需要理解管道的内部状态机。
工具更新不影响 Agent 行为。 我后来加了 wq_brain_batch_submit 工具,Agent 自动发现并开始使用,不需要改任何"管道逻辑"——因为没有管道逻辑可改。
什么时候这个方案是错的
诚实说,有场景不该用这个方案:
- 模型能力不足时。 如果你的 LLM 是 GPT-3.5 级别,它确实需要外部脚手架来引导决策。Skill 编排隐含依赖一个足够聪明的调用者。
- 确定性流程时。 如果你的流程完全没有分支判断(ETL pipeline、数据清洗),直接写代码比让 LLM 决定更可靠、更便宜。
- 高吞吐量时。 每秒处理几千个请求的场景,LLM 推理的延迟和成本不可接受。硬编码管道更合适。
但这些例外恰好说明了判断标准:当任务需要灵活判断、中间步骤不可预见、且你有一个足够聪明的调用者时,Skill 编排优于 Agent 循环链。
一句话总结
不要用代码固化 LLM 已经具备的决策能力。给它好工具,让它自己决定怎么用。
2023 年我们需要框架来弥补模型的不足。2025 年我们需要退后一步,把预编码的决策逻辑还给模型。
聪明管道 + 笨工具是上一个时代的产物。笨管道 + 聪明工具才是 LLM-native 的架构。