拆解开源交易 Agent Vibe-Trading:工具、技能与风控三层

2026-08-05

本文基于 Vibe-Trading 仓库 commit 3a752d5(2026-08-04)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/HKUDS/Vibe-Trading 最新代码与文档为准。

把 HKUDS 开源的 Vibe-Trading 和 opencode、Hermes Agent 摆在一起,最先分叉的地方不是模型、不是提示词,而是工具清单指向哪里。 通用向的编码 Agent,工具作用对象基本还是你本机的文件与命令行,opencode 是其中最典型的一个;Vibe-Trading 的 agent/src/tools/ 下有 72 个文件,其中读写文件和跑命令的只是零星几个,剩下大半指向外部数据源、领域计算,以及一道给券商下单用的闸门。工具清单一变,技能怎么组织、安全边界画在哪里,跟着全都变了。这篇就顺着这三层往下拆。

一、三个仓库摆在同一张桌子上,先看它们各自在动什么

先说清楚这篇和站内几篇的分工,免得你重复读:三个开源 Agent 项目的三体对比 讲的是通用 Agent 项目之间的选型;Hermes Agent 四方对比opencode 五方对比 各自站在那一个项目的视角往外看;本篇不排座次,只做一件事——拿「通用编码 Agent」和「垂直领域 Agent」这条线切开,看工具层、技能层、风控层各自长成什么样,并且每条差异都回到三个仓库的真实文件里取证。

三个仓库的自我定位差得很明显。opencode 的 README 开门见山写的是「开源 AI 编码 Agent」,内置两个可以用 Tab 键切换的 agent:build 是默认的全权限开发 agent,plan 是只读 agent,默认拒绝文件编辑、跑 bash 命令前先要许可;另有一个 general 子 agent 用 @general 唤起做复杂检索与多步任务。Hermes Agent 的 README 把自己定位成「自我改进的 AI Agent」,重点铺在学习闭环、跨平台网关(Telegram、Discord、Slack、WhatsApp、Signal、CLI 共用一个 gateway 进程)和七种终端后端(local、Docker、SSH、Singularity、Modal、Daytona、Vercel Sandbox)上。

Vibe-Trading 的 README 则把自己写成「一个把金融问题变成可运行分析的开源研究工作台」,并且在 Disclaimer 里明确写了它不是投资建议、不持有资金、不运营任何撮合场所。这句定位不是免责套话,它直接决定了仓库的形状:全仓 2030 个受版本控制文件里,agent/ 占 1805 个,frontend/ 只有 155 个;agent/src/ 下有 23 个模块目录,其中体量最大的几个——skills/factors/tools/——全部是领域资产而不是 Agent 内核。Agent 内核本身在 agent/src/agent/ 下,只有 loop.pycontext.pyskills.pytools.pytrace.py 等十来个文件。

组成部分它负责什么对应仓库位置你什么时候会碰到它
Agent 内核ReAct 主循环、系统提示词组装、技能装载、执行轨迹落盘agent/src/agent/loop.py / context.py / skills.py / trace.py想改 Agent 行为、查一次运行到底调了哪些工具时
工具层72 个工具文件,含行情、公告、财报、期权、因子、文件读写、bashagent/src/tools/想加一个自有数据源工具,或想知道某个能力从哪来
技能层88 个技能目录、共 404 个文件,每个目录都有一份 SKILL.mdagent/src/skills/load_skill(name) 拉方法论,或想写自己的技能
因子库五个因子子库,其中四个带 LICENSE.md 声明上游来源agent/src/factors/zoo/qlib158 / alpha101 / gtja191 / academic / fundamentalvibe-trading alpha 系列命令、排查因子来源与许可时
回测引擎与加载器分市场引擎 + 数据源加载器 + 组合优化器agent/backtest/engines/agent/backtest/loaders/agent/backtest/optimizers/回测行为对不上、想接自己的历史行情源时
多智能体编制30 份预设团队 yaml,写死角色、提示词、可用工具与技能agent/src/swarm/presets/run_swarm,或想照着改一套自己的团队
券商连接与下单闸门12 家券商连接器子目录 + 授权书、闸门、熔断、审计agent/src/trading/connectors/agent/src/live/一旦你想让它碰真账户,这一层是必须先读完的
会话渠道16 个具体渠道实现文件,另有 base / manager / registry 等公共文件agent/src/channels/想把研究会话接到飞书、Telegram、企业微信这类入口时

上面这些目录数与文件数是我在仓库里用 lsgit ls-files 直接数出来的,你 clone 下来能当场复现。README 与 agent/SKILL.md 里还有项目自述的一批总数(引擎数、alpha 数、数据源数),那些是项目自己的说法,本文引用时会写清出处。

二、工具层:工具清单指向哪里,Agent 就长成什么形状

通用向 Agent 的工具面相对收敛。opencode 的 README 里,能力差异是靠 agent 档位表达的——build 全权限、plan 只读,工具的作用对象自始至终是你这个代码仓库。Hermes Agent 把工具面往外推了一层:README 的文档索引里那一行写的是「40+ 工具、toolset 体系、终端后端」,它扩的是「在哪台机器上执行」这个维度,七种终端后端让同一批工具能落在本地、容器、SSH 远端或 serverless 沙箱里。

Vibe-Trading 扩的是另一个维度。agent/src/tools/ 那 72 个文件里,read_file_tool.pywrite_file_tool.pyedit_file_tool.pybash_tool.py 这类通用工具确实在,但只占一小撮;更多的是 market_data_tool.pysec_filings_tool.pyfinancial_statements_tool.pyoptions_chain_tool.pydragon_tiger_tool.pynorthbound_tool.pymargin_trading_tool.pyblock_trades_tool.pylockup_expiry_tool.pyshareholder_count_tool.py 这种一个文件对应一类外部数据的工具。仓库 agent/SKILL.md 里把 MCP 侧的工具数描述为 55 个,并逐行列了每个工具是否需要 API key。

这个差别对你意味着什么?通用编码 Agent 的工具返回值基本是「你自己仓库里的文本」,错了你能一眼看出来;而这类领域工具的返回值是外部世界的数据,错了你未必看得出来。所以 Vibe-Trading 在工具层旁边额外挂了一批「管数据可信度」的工具:financial_rigor_tool.pyreport_audit_tool.pygoal_tool.pyhypothesis_tool.py,以及 agent/src/goal/ 这个独立模块。agent/SKILL.md 的工具表里,start_research_goal 被描述为「创建一个可审计的研究目标」,配套还有 add_goal_evidenceupdate_research_goal_status——也就是说,它把「结论必须挂在证据上」做成了工具协议,而不是靠提示词嘱咐模型别乱说。这条思路的落点是:返回值本身要携带可核验的结构,而不是让模型自由发挥。

另一处能看出取向的是加载器。README 的「Custom Data Source」一节写得很具体:你新增一个历史行情加载器,要在 agent/backtest/loaders/ 下写一个满足 DataLoaderProtocol 的类、打上 @register、把模块名加进 registry.py_loader_modules、再把名字加进 agent/backtest/runner.py_VALID_SOURCES。同一节还画了一条硬边界:实时逐笔与盘口深度不在加载器职责内,加载器只做时点历史 K 线,实时数据走券商连接器。这种「哪层能拿什么数据」的显式切分,在通用编码 Agent 里是不存在的,因为它们没有这个问题。

三、技能层:预置的领域方法论,和从经验里长出来的技能

三个项目都有「技能」,但技能是从哪来的完全不同,这一点比名字重要得多。

Hermes Agent 的 README 把技能写进了「闭环学习」那一格:复杂任务之后自主创建技能、使用过程中自我改进、兼容 agentskills.io 开放标准。技能在它这里是经验的沉淀物,是运行时产物。

Vibe-Trading 的技能是随包分发的领域教科书。agent/src/skills/ 下 88 个目录、404 个文件,目录名一眼就能看出是方法论而不是操作记录:factor-researchoptions-payoffliquidation-heatmapchanlunsmcichimokuedgar-sec-filingshk-connect-flowashare-pre-st-filtertrade-journalshadow-account。每个目录里都有一份 SKILL.md,带 name / description / category 三个 frontmatter 字段;88 份 SKILL.md 之外还多出三百多个文件,是少数技能自带的脚本与参考资料——比如 chanlun 目录下另有一批中文参考文档,ashare-pre-st-filter 目录下有 scripts/ 里的抓取脚本。以 agent/src/skills/factor-research/SKILL.md 为例,正文结构是「Purpose → 适用场景 → Workflow → 工具参数表 → 输出文件」,Workflow 那一段直接写死了调用顺序:先算因子值输出 CSV(行是日期、列是标的代码),再算前向收益 CSV,再调 factor_analysis 工具,最后解读结果;并且用加粗强调因子 CSV 和收益 CSV 的行列必须严格对齐,收益必须是因子观测日之后的前向收益,以避免前视偏差。

这就是垂直技能和通用技能最实际的差别:它写的不只是「怎么用工具」,还有「这个领域里做错了会静默出错的地方在哪」。前视偏差不会让程序报错,只会让结果好看,所以只能靠方法论文档和工程校验一起兜住。仓库里对应的工程兜底也能查到:agent/SKILL.md 描述因子库带 __alpha_meta__ 元数据,并由 AST 纯度门加一个 300 行数据规模的前视哨兵测试守着;AGENT_CONTRIBUTOR_GUIDE.md 则给出了改因子库时该跑的测试命令,指名 agent/tests/factors/test_alpha_purity.pyagent/tests/factors/test_lookahead.py

顺带说清楚因子库的来源,这是很多人会写错的地方:仓库根目录的 NOTICE 声明得很明白,qlib158 是 Microsoft Qlib 的 Alpha158 特征定义,走 Apache 2.0 并注明了 pinned commit;alpha101 来自 Kakushadze (2015) 的 arXiv:1601.00991;gtja191 来自国泰君安 2014 年的研究报告;academic 一组来自公开学术文献。NOTICE 明确写了源论文与报告的正文、表格、图不在本仓库内复制,只把数学公式作为事实性内容重新实现;qlib158alpha101gtja191academic 四个子目录下另有各自的 LICENSE.mdfundamental 目录没有单独的许可证文件)。以 qlib158/LICENSE.md 为例,它把上游仓库地址、Apache 2.0、pinned commit 与 pinned path 逐项列了出来,并说明每个 .py 的文件头都会重复同一条出处标注。所以别把它笼统说成「项目自研的因子库」,那是不准确的。至于能不能商用,本文不提供法律意见,以许可证原文为准。还要说明一句:历史表现不代表未来,本文只讨论工程实现,不评价任何因子或策略的好坏。

技能怎么切分粒度、怎么写才不至于变成模型看不懂的长文,可以对照 技能机制三体对比 一起看。

四、风控层:多出来的那道不可回滚的闸门

这是三者分野最大的一层,也是垂直 Agent 真正的工程重量所在。

通用编码 Agent 的安全边界画在「改坏了能不能回滚」上。opencode 的做法是给你一个只读的 plan agent,默认拒绝文件编辑、跑 bash 前先问;Hermes Agent 的 README 文档索引里,Security 那一行写的是命令审批、DM 配对、容器隔离。这两套边界的共同前提是:最坏情况是本地文件或本地环境被弄乱,而这是可恢复的。

一旦 Agent 能连券商,这个前提就没了。下错的单不可撤销。Vibe-Trading 为此在 agent/src/live/ 下单独建了一整层:mandate/(授权书的 model / store / commit)、order_guard.pysdk_order_gate.pyhalt.pydaily_count.pyaudit.pyenforcement.pyclassification.py,外加 runtime/ 下的 flatten.pyreconcile.pyscheduler.py

agent/src/live/order_guard.py 的模块文档字符串把闸门顺序写得很清楚,每一步都是 fail-closed:先 load_mandate,没有有效授权书或 schema 版本不认识就 DENY;再查授权是否过期,过期就 DENY 并走重新授权;再查 halt_flag_set,熔断开关一旦触发直接 DENY 且不发出任何远程调用;再 extract_order_intent,解析不出订单意图就 DENY;然后走只读路径读持仓与余额;最后 check_mandate 给出 ALLOW / DENY / PAUSE_FOR_REAUTH 三种结果。同一段注释还写了两个容易被忽略的细节:每日成交计数只在「确认放行且券商侧返回非错误」时才递增(转发失败根本没下单,不该消耗额度),并按 UTC 日期滚动;以及这个工具的 repeatable = False,因为一笔实盘单绝不能被静默重发。

README 在券商连接器那一节还写了两条结构性约束:下单类工具不进 MCP 面(只在 agent 与 CLI 可用),研究与回测路径在结构上被禁止触达任何实盘端点;纸面账户与实盘账户的区分是每家券商各自的运行时判别(账户 ID 格式、主机分离、demo 标志或交易环境),不是一个模型能翻转的配置开关;某家券商如果拿不出这种判别手段,就被限定在只读加纸面。README 的连接器表里,Trading 212 一行写的是完全只读,place_order / cancel_order 连纸面也硬拒绝。

AGENT_CONTRIBUTOR_GUIDE.md 把这条纪律延伸到了协作层面:它把券商连接器、授权书、下单闸门、熔断和审计账本列为「即使改动看起来很小也属于安全关键」的面,要求涉及下单安全的改动去跑 agent/tests/test_sdk_order_gate.pytest_mandate_enforcement.pytest_killswitch_blocks_orders.pytest_readonly_default.py,并明确写着:不要把实盘交易、支付、钱包、券商写操作当作日常 PR 验证的一部分。这份文件本身就是给 AI 协作者看的,值得单独读一遍——它是少见的把「Agent 参与开发时的高风险操作清单」写进仓库的做法。

至于凭据本身,README 里有一个可选的 TAP 模式,把 Alpaca 的密钥从 Agent 进程里整个挪走,由代理在服务端注入,写操作阻塞在人工审批上,读操作自动放行;它连已知缺陷都写了出来——如果人在超时边界上批准,闸门可能报错而订单其实已经到达券商,此时每日成交计数会少算一笔,建议超时报错后先查未成交订单再重试。这种把边界条件写进 README 的态度,比宣称「绝对安全」有用得多。权限最小化的通用原则可以对照 最小权限设计 那篇。

需要如实说明代价:只要你走到连券商这一步,凭据的暴露面就真实存在——本地 .env~/.vibe-trading/ 目录、OAuth 缓存都是可被读取的位置,AGENT_CONTRIBUTOR_GUIDE.md 也专门要求不要把这些东西提交进仓库。下错的单不可撤销,闸门只能拦住越界的单,拦不住一笔在授权范围内但你本来不想下的单。程序化交易还有合规义务,各司法辖区要求不同。能不能这么用、能用到什么程度,以你所在司法辖区的监管要求与券商协议为准。

五、边界与代价:这套设计放弃了什么

垂直做深,代价是很具体的。

放弃了通用性。同样是 Agent 框架,opencode 和 Hermes Agent 你拿去做任何事都行;Vibe-Trading 的 88 个技能、五个因子库、分市场回测引擎、12 家券商连接器,换个领域全部归零。你不能指望复用它来做别的行业的研究 Agent,能复用的只有骨架思路。

放弃了轻量。agent/src/factors/ 一个目录就有 482 个文件,agent/src/skills/ 有 404 个,这些都要随包分发。仓库 agent/SKILL.md 里描述的多数工具在 HK/US/加密市场上零 API key 可用,但 A 股数据的稳定性依赖多源回退,多智能体团队 run_swarm 需要 LLM key,get_macro_series 需要 FRED_API_KEYiwencai_search 需要 IWENCAI_KEY——这些都在那张工具表里逐行标注了。

有几件事它明确不管。README 写明它不持有资金、不运营撮合场所、不构成投资建议;加载器层明确不做实时逐笔与盘口深度;README 的 MCP 客户端一节列了 v1 限制——外部 MCP 工具只能串行执行、不进并行只读路径,只暴露 tools 不暴露 resources 与 prompts,swarm worker 注册表在 v1 里排除 MCP 工具,配置不支持热重载,改完要重启进程。README 还把券商交易能力标注为实验性、未经真实券商账户验证。

还有一层容易被忽略的代价:agent/src/swarm/presets/ 那 30 份 yaml 是把角色和提示词写死在配置里的。翻开 investment_committee.yaml 能看到,每个角色都由一段很长的 system_prompt 定义,正文里用 {target}{market} 这类占位符留出运行时参数,并用一个「Required outputs」小节把该角色必须产出哪几个板块逐条写死;同一个 agent 还配了 toolsskillsmax_iterationstimeout_secondsmax_retries 等字段——可用工具、可加载技能、迭代上限、超时与重试次数全在配置里,不由模型临场决定。这里必须框定清楚:以上是在描述这个 yaml 文件长什么样,不是本文对读者的任何建议;本文不复述其提示词内容,也不给出、不暗示任何标的、点位、仓位或买卖倾向。工程上真正该盯的是另一件事——把输出结构写死在预设里,好处是产出可解析、可归档、多次运行之间可比对,坏处是这类预设一旦被误读成「照着做就行」,风险就从工程层滑到了使用者身上。配置能约束的只是格式,约束不了内容对不对。

六、上手与避坑清单

下面每条都写清楚为什么会踩,以及怎么避。

先分清包名和命令名。 会踩是因为 PyPI 包叫 vibe-trading-ai,装完之后可用的命令却是 vibe-trading(交互式 CLI)、vibe-trading serve(FastAPI 服务)、vibe-trading-mcp(MCP 服务端),照着命令名去 pip install 会找不到包。agent/SKILL.md 里专门用一张表把这三者列了出来,配置 MCP 时 command 填的是 vibe-trading-mcp

别把 MCP 插件模式和 MCP 客户端模式搞混。 会踩是因为 README 里两节标题长得很像。前者是把 Vibe-Trading 的工具暴露给你的 Agent,后者是让 Vibe-Trading 自己的 Agent 去调你的外部 MCP 服务端,配置文件是 ~/.vibe-trading/agent.jsonagent/SKILL.md 里专门加了一段 Note 强调这两者方向相反。

URL 型 MCP 服务端必须显式写 type 会踩是因为很多框架会按 URL 后缀猜传输方式。README 明确写了它不再猜,SSE 与 streamable HTTP 之间必须由你指定,ssestreamableHttp 二选一;stdio 才可以省略。配错的表现通常是连不上而不是报错报得清楚。

别指望通过 API 注入 MCP 服务端定义。 会踩是因为你在 POST /sessionssession.config 里塞了 mcpServers 却毫无反应。agent/SKILL.md 写得很直白:这个键默认会被静默剥离,因为它能定义子进程的 command/args/env,属于运维方信任面;要开启得由服务端运维显式设置 ALLOW_SESSION_MCP_SERVERS=1。同一节还写了,磁盘上的全局运维配置无论该开关如何都会被尊重。README 里那一节只讲了怎么传,没重复这条安全前提,只看 README 会踩空。

改配置后记得重启进程。 会踩是因为你以为改完 agent.json 就生效了。README 的 v1 限制里写明不支持热重载。

数据目录和凭据搜索顺序要先弄清。 会踩是因为你把 key 写在了一个它不读的位置。README 里提到会话、运行记录、swarm 运行、上传件都放在 ~/.vibe-trading 下(可用 VIBE_TRADING_HOME 重定位),并写了 provider 加载器的 .env 搜索顺序是 ~/.vibe-trading/.envagent/.env → 当前工作目录的 .env。搞错顺序的典型症状是「明明配了 key 却说没配」。

部署到回环地址之外,一定要开 API_AUTH_KEY 会踩是因为本地调试时不需要它,一上服务器就忘了。AGENT_CONTRIBUTOR_GUIDE.md 把这条列在安全规则里:API 或 Web 部署超出 loopback 必须使用 API_AUTH_KEY

碰实盘之前,先把 agent/src/live/order_guard.py 的模块注释从头读到尾。 会踩是因为闸门的语义细节(fail-closed 顺序、计数何时递增、不可重试)只写在代码注释里,README 只给了结论。这一层出错的代价和前面所有层都不是一个量级。

自己加数据源要改三处,少一处就不生效。 会踩是因为只写了加载器类却忘了注册。README 的步骤是:写满足 DataLoaderProtocol 的类并加 @register、把模块名加进 registry.py_loader_modules、把名字加进 runner.py_VALID_SOURCES,想让 source="auto" 也能选中它还要挂进 FALLBACK_CHAINS

跑测试要挑窄命令并说明没跑什么。 会踩是因为全量套件很贵,你可能直接跳过验证。AGENT_CONTRIBUTOR_GUIDE.md 给了分类的目标测试命令(一般 Python 改动、实盘与订单安全改动、因子库改动、前端改动各一组),并要求当全量套件太贵时使用最窄的匹配命令,同时说明哪些没有跑。

收束:接下来该读哪个文件

如果你只想借鉴这套工程思路,读三个文件就够了:agent/src/skills/ 下任意一份 SKILL.md,看领域方法论怎么写成 Agent 能用的形态;agent/src/swarm/presets/investment_committee.yaml,看多角色编制怎么落成配置;agent/src/live/order_guard.py 的模块注释,看不可回滚的操作该怎么加闸门。

如果你打算真的跑起来,给自己一份自检清单:我分清 vibe-trading-aivibe-trading-mcp 了吗?我知道自己配的 key 落在了哪个 .env 吗?我的部署是不是暴露在 loopback 之外、开了 API_AUTH_KEY 吗?我读懂了 order_guard.py 那六步 fail-closed 顺序吗?我清楚因子库各自的上游来源与许可,不会把它当成项目自研的东西对外转述吗?

最后重复一遍本文的立场:以上全部是对一个开源仓库工程实现的描述。历史表现不代表未来,本文不构成任何投资建议,也不对任何标的、策略或参数给出倾向。凡涉及能不能连券商、能不能做程序化交易这类判断,一律以你所在司法辖区的监管要求与券商协议为准。

本篇属于一个把开源个人交易 Agent 项目 Vibe-Trading逐层拆开讲的系列,整体地图见 Vibe-Trading 是什么:HKUDS 这个开源交易 Agent 项目的工程全景与边界;沿着这条线往下,还可以看 开源项目 Vibe-Trading 的定时研究:把每天自动跑一遍做成带存储的可执行对象开源项目 Vibe-Trading 仓库结构导读:改一处功能从哪进去

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。