当你在聊天框里输入「茅台现在能买吗」,你看到的是一句回答;系统内部发生的是一次「分诊 → 开检查单 → 看结果 → 补充检查 → 写诊断」的循环。这一章拆开这个循环,看看 Agent 如何决定先查什么、听谁的、什么时候停。
类比:带实习生的门诊
你(主诊医生)不会自己跑检验科。你告诉实习生:「先量体温、查血常规、再做个 B 超。」实习生把结果拿回来,你决定要不要加做 CT。Agent 的「工具调用」就是这个过程:模型负责决定开什么检查,运行时负责真的去执行,结果再回到病历里。循环直到信息足够,或预算用完。
一次问股的完整循环
解析股票代码/名称、对话历史、用户选择的策略。带 stock_code 的工具会被「股票范围守卫」约束,防止分析着 A 却查了 B。
角色、可用工具、输出语言、策略说明、历史摘要。策略不是硬编码,而是从 YAML 读入的能力包。
模型返回 tool_calls 就进入执行;没有工具调用,就把当前内容作为最终答案。默认最多 10 步。
多个互不依赖的工具可以并行(最多 5 个线程),例如同时取实时行情、日线和新闻。每个工具有独立超时。
工具结果以 role=tool 追加到消息列表,模型基于新证据继续思考。超时或越权的结果会被标记为不可重试,避免死循环。
模型给出结论后,风险否决、策略聚合、股票范围与预算护栏再检查一遍;最后流式输出并落库。
帮我看看贵州茅台,现在适合买吗?用多头趋势策略。
趋势仍是多头排列(MA5 > MA10 > MA20,MA20 向上),但现价距 MA5 乖离约 4.6%,接近 5% 的追高红线;上方压力位在 1,720 附近,资金流本周没有明显净流入。
结论:暂不追高,等待回踩 MA10 附近企稳,或放量突破压力位后再评估。 若已持仓,可将止损参考放在 MA20 下方。
工具箱:18 个原生工具 + 动态扩展
工具不是越多越好。每个工具都声明自己的策略:只读还是可能有副作用、需要什么权限、对哪些股票范围生效、默认超时多少。运行时据此做权限与预算控制。
| 类别 | 工具 | 能回答什么 |
|---|---|---|
| 数据 | get_realtime_quote、get_daily_history、get_chip_distribution、get_analysis_context、get_stock_info、get_portfolio_snapshot、get_capital_flow | 现在多少钱?过去怎么走?筹码在谁手里?我持有什么?资金流向? |
| 分析 | analyze_trend、calculate_ma、get_volume_analysis、analyze_pattern | 趋势状态、均线数值、量能、形态识别 |
| 搜索 | search_stock_news、search_comprehensive_intel | 最近发生了什么?有没有催化或风险? |
| 市场 | get_market_indices、get_sector_rankings | 大盘怎么样?哪些板块强? |
| 回测 | get_skill_backtest_summary、get_strategy_backtest_summary、get_stock_backtest_summary | 这个策略/这只股票历史上表现如何? |
| 宏观 | fxmacrodata_<op>(动态) | 汇率、宏观数据等扩展查询 |
工具结果会以结构化文本回到模型,而不是让模型直接访问数据库或网络。这既方便审计,也降低了「模型自己乱查」的风险。
多智能体:五个角色,一个决策
复杂问题不适合让一个 Agent 从头查到尾。多智能体模式把工作拆给专业角色,再由决策 Agent 汇总:
技术分析 Agent
均线、形态、量能,最多 6 步、8 个技术工具。
情报 Agent
新闻、公告、资金流、宏观,最多 4 步。
风险 Agent
风险旗标、风险等级、是否一票否决买入。
决策 Agent
零工具,只做综合:技术 40% + 情报 30% + 风险 30%。
持仓 Agent
结合你的持仓成本、集中度与风险暴露。
策略 Agent
按路由选中的 YAML 策略逐条检查,最多 4 步。
编排模式有 quick、standard、full、specialist:full 与 specialist 才会加入风险 Agent,specialist 还会额外插入策略 Agent。决策 Agent 的提示词里明确了权重,并规定「高风险旗标可以一票把信号封顶在 hold」。
多个策略的观点会被聚合:信号映射成 1–5 分,加权平均后落档;有效观点不足两条时输出 insufficient,而不是硬给方向。样本达到 30 条后,才启用历史表现权重。
策略路由:先分诊,再检查
策略路由决定「这次该用哪几份检查单」。优先级是:用户显式选择 > 手动模式 > 由技术观点推断的市场状态 > 默认集合。
| 推断状态 | 触发条件(简化) | 更可能选中的策略 |
|---|---|---|
trending_up | 多头排列,趋势分较高 | 多头趋势、均线金叉、放量突破、成长质量 |
trending_down | 空头排列,趋势分很低 | 底部放量、缩量回踩(作为反弹观察) |
sideways | 趋势分在中间区间 | 箱体震荡、缩量回踩 |
volatile | 量能明显放大或波动加剧 | 缠论、波浪、事件驱动、预期重估 |
sector_hot | 板块热点与情绪指标 | 热点题材、龙头、情绪周期 |
策略 Agent 的并发默认是 3,最多 4。它们各自独立读数据、独立给观点,最后由聚合器统一。这样既避免了一个 Agent 的偏见污染全部,也避免了 15 个策略同时跑导致成本爆炸。
记忆:谨慎地使用「经验」
Agent 的记忆默认关闭(AGENT_MEMORY_ENABLED=false)。开启后可提供三类信息:历史分析结论、置信度校准、策略历史胜率。设计上很克制:
- 置信度校准需要至少 30 个样本,并使用滚动窗口,避免用几条运气好的记录自我强化。
- 策略权重同样要样本达标才启用;样本不足时宁可不用历史,也不虚构胜率。
- 会话本身有 TTL(约 30 分钟),避免无限上下文导致成本与混乱。
这是一种「宁可少记,也不要记错」的取舍。金融场景里,错误的历史经验比没有经验更危险。
后端:谁能真正调用工具
Agent 能力依赖模型后端的工具调用(tool calling)。当前只有 LiteLLM 后端声明了 tools 能力;本地 CLI 后端(Codex、Claude Code、OpenCode)只适合文本生成。另有实验性的 codex_app_server 分支,它自己拥有循环,只通过只读工具接口暴露少量查询能力。
所以如果你把 AGENT_BACKEND 指向一个不支持工具的本地后端,问股会退化成「一次性文本问答」,而不是「自己查资料」。选择后端前,先确认它的能力声明。
护栏:让 Agent 不至于「自信地闯祸」
| 护栏 | 规则 | 目的 |
|---|---|---|
| 最大步数 | 默认 10 步 | 防止无限工具循环 |
| 时间预算 | 整体墙钟、单步最小 8 秒、单工具超时、编排 600 秒 | 不让一次问股拖垮服务 |
| 股票范围 | strict 模式下越界返回 stock_scope_violation | 防止答非所问、串股票 |
| 风险否决 | 高风险/否决 → 买入降为持有;可降 1–2 档 | 风险优先于收益叙事 |
| 超时缓存 | 超时结果标记为不可重试 | 避免对坏工具反复重试 |
| 预算跳过 | 编排层剩余预算不足时发 pipeline_budget_skipped | 部分完成好过整体崩溃 |
风险否决可以用 AGENT_RISK_OVERRIDE=false 关闭,但不建议在真实资金场景关闭。它不是「阻止你买」,而是「在系统已经识别到高风险时,不允许结论继续唱多」。
流式体验:让你看见它在想什么
长任务最怕「转圈十分钟」。Agent 通过流式事件把过程暴露出来:
前端通过 POST + 流式响应读取事件,可以随时取消;Web 端不需要轮询。事件契约写在 docs/agent-stream-events.md,外部集成也可以按这个协议接入。
多轮问股:从「一次回答」到「一次研究」
Web 的 /chat 页面、Bot 的 /ask、/chat、/research 都调用同一套执行器。多轮对话会保留上下文与股票范围,支持:
- 追问「那如果跌破 MA20 呢?」并沿用当前股票与策略;
- 切换策略或多选策略,观察观点差异;
- 把会话导出、发送到通知渠道,或转后台执行;
- 深度研究模式:更长的预算(默认约 3 万 token / 180 秒),做多轮检索与交叉验证。
Agent 不是「更聪明的日报」
定时日报适合「每天固定看一眼」,成本可控、结论稳定;Agent 适合「针对一个具体疑问深挖」。如果只是想要每日组合概览,用日报更便宜也更可复现。不要为了「AI 感」把简单任务复杂化。
关键配置一览
| 变量 | 默认 | 说明 |
|---|---|---|
AGENT_MODE | true | 用户意图 + kill switch;真正可用还需存在非 Hermes 的 Agent 路由 |
AGENT_BACKEND | auto | auto / litellm / codex_app_server |
AGENT_MAX_STEPS | 10 | 单次循环最大步数 |
AGENT_ORCHESTRATOR_TIMEOUT_S | 600 | 多智能体整体超时 |
AGENT_SKILL_CONCURRENCY | 3 | 策略 Agent 并发(上限 4) |
AGENT_RISK_OVERRIDE | true | 是否允许风险否决降级 |
AGENT_MEMORY_ENABLED | false | 是否启用历史记忆 |
AGENT_SKILL_ROUTING | auto | 策略路由模式 |
AGENT_SKILL_AUTOWEIGHT | true | 样本达标后是否启用表现权重 |
Agent 在第 3 步同时调用了「实时行情」和「新闻搜索」,这两个工具的超时时间不同。运行时最合理的做法是?