主题
06 — v0.1.1 Hotfix + P1 起步
Status: ✅ v0.1.1 hotfix shipped 2026-05-07 · ⏳ P1.0 backend pending Scope: 用户报告的
get_price拿不到最新价 bug 的修复方案 + 顺势启动 P1.0 backend 的决策与边界
修 stale price 的最短路径 + 把多租户决策从 P2 拉到 v0.1.1 起步落地
目标 (Goal)
修复用户在 stock-research_Agent profile 报告的 get_price 在交易时段返回隔夜收盘价的问题,并以这个 hotfix 为契机:
- 把 cite 信封拓展为前向兼容多源(
served_by字段) - 跑通 install-skill.sh 把更新推到运行中的 profile
- 起步 P1.0 backend 时复用本次的路由逻辑
待研究 / 已确认的源
- ✅ akshare
stock_individual_spot_xq(雪球单 code 端点):~1.4s/查询,单 HTTP 调用 - ❌ akshare
stock_zh_a_spot_em(东方财富全市场):~75s/查询(58 页分页全市场扫描),不可用于实时单查 - ✅ Tushare
trade_cal(exchange=SSE):判断当日是否交易日,缓存当日结果即可 - ⏳ pytdx3 / Yahoo / 跨源比对:P1.2 范围
關鍵決策點 (Open Questions)
Q1. 修复策略 — 自动路由 / 显式 flag / 仅文档
- A) 自动路由:盘中调 akshare 实时,盘后/周末调 Tushare daily(agent 不用知道市场时段)
- B) 加
--realtimeflag:保持 tushare daily 默认,让 agent 显式选实时 - C) 仅文档说明 T+1 语义,不改代码
→ 已决 A(自动路由) —— 引用 §D1-D5 Background Track plan。理由:agent prompt 越简单越稳定;路由失败时 fallback 到 Tushare 仍然返回有效值。已落地 core/core/data/schemas.py:get_price。
Q2. cite 信封怎么表达"哪个源出的数"
- A) 复用
cite.source字段("tushare" / "akshare") - B) 加
served_by字段(更明确,跨源比对更友好) - C) 同时写
cite.source+cite.adapter
→ 已决 B(加 served_by):cite.source 历史含义是"这条数据的原始来源"(schema 里也是 tushare 字符串),served_by 表达"本次查询路由到了哪个 adapter",两者将来可能不一致(缓存场景:served_by="cache", source="tushare")。已落地 core/core/citation.py:ToolCite。
Q3. v0.1.1 完成后是直接起 P1.0 还是先做 P1.2 多源?
- A) 直接 P1.0 backend skeleton(按 Phase 1 plan Tasks 1-4 + 8)
- B) 先 P1.2 多源(pytdx3 + Yahoo),再起 backend
→ 已决 A(先 P1.0) —— 见 v3 plan §8 Week 2。理由:backend 是 Direct → Service 模式迁移的载体,越早把这条路跑通越能验证多租户假设;多源数据 P1.2 可以挂在 backend 后面增量做。
Q4. 是否同步替换 stock-research_Agent profile 的 AGENTS.md/SOUL.md?
- A) 是,本次 hotfix 一并替换(A 股专用版)
- B) 否,留到 P1.1 provisioner 模板化时统一处理
→ 已决 A(一并替换):模板源就放在仓库 profile/template-stock-research-pro/,用本周末时间替换运行中的 profile,同时也是 P1.1 provisioner 用模板时的现成原料。
修复实现 (v0.1.1,已 shipped)
Code 改动
| 文件 | 操作 |
|---|---|
core/core/data/akshare.py | 新建:get_spot_price(code) 走 Xueqiu 单 code 端点;_to_xueqiu_symbol("600519.SH") → "SH600519" |
core/core/data/_market.py | 新建:is_market_open(now, token) + is_trading_day(date_str, token);缓存当日结果;Tushare 失败降级为 weekday-only |
core/core/data/schemas.py:get_price | 加路由:trade_date is None && is_market_open() → akshare;否则 → tushare daily;akshare 失败 fallback 到 daily |
core/core/citation.py:ToolCite | 加 `served_by: str |
core/pyproject.toml | 加 akshare>=1.13,<2;版本 0.1.0 → 0.1.1 |
skill/stock-research/SKILL.md | 加 §"价格新鲜度语义"段落,说明 metric 与 served_by 的语义 |
测试
- 16 个新单测:
test_data_market.py(市场时段、trade_cal 缓存、Tushare 降级)+test_data_akshare.py(envelope shape、suffix 翻译、NaN/None 处理、upstream exception 包装) - 路由分支测试:
test_data_schemas.py加盘中→akshare、akshare 失败 fallback、市场关闭→tushare 三个场景 - 集成测试:
test_skill_scripts.py加served_by断言 + akshare 路由 e2e
E2E 验证(盘后路径)
bash
$ ~/.hermes/profiles/stock-research-agent/skills/research/stock-research/scripts/fetch_price.py 600519
{
"value": 1371.05,
"metric": "close",
"code": "600519.SH",
"as_of": "2026-05-07",
"cite": {"served_by": "tushare", "source": "tushare", "table": "daily", ...}
}akshare 路径直接调用(绕过市场时段判断):~1.4s 返回 served_by: "akshare"、metric: "current_price"。
P1.0 启动边界(Week 2)
起步范围
按 Phase 1 plan Tasks 1-4 + 8:
- FastAPI app skeleton + Settings (Pydantic) + Bearer auth 中间件(SHA256 hash)
- DuckDB cache 层(24h TTL,schema
daily_cache(code, trade_date, close, fetched_at)) - Endpoints:
/healthz、/price、/fundamentals - admin CLI
scripts/issue-token.py - Vultr 部署(systemd + Caddy)
不在 Week 2 范围
- P1.1 支付 / onboarding(W3)
- P1.2 pytdx3 / Yahoo / 跨源比对(W4)
- P1.3 web search(W5)
- P2 任何 initiative
与 v0.1.1 的复用
P1.0 /price endpoint 内部直接调 core/core/data/schemas.get_price,自动继承 v0.1.1 的 akshare/Tushare 路由。Backend 添加的只是:
- 缓存(DuckDB cache 层在 schemas.get_price 之上)
- 鉴权(Bearer 中间件)
- HTTP 协议层
→ Direct/Service 双模式 user 看到一样的 cite 信封。
與其他層的關係
- L3 Tools(v0.1.0):本次只改
schemas.get_price,不动tushare.call抽象 - L4 Skills(v0.1.0):fetch_price.py CLI 不变;只更新 SKILL.md 让 agent 知道怎么解读
metric与served_by - 未来 cross-source 比对(P1.2):
served_by是 single 字段;P1.2 多源同时返回时改成served_by: ["tushare", "pytdx3"],这是 forward-compatible 演进路径
下一步 (Next Steps)
已完成(v0.1.1 shipped 2026-05-07):
- ✅ akshare adapter + market clock + 路由
- ✅ cite
served_by加字段 - ✅ 测试 60/60 绿
- ✅ install-skill.sh dev 模式部署到 stock-research_Agent profile
- ✅ E2E 验证盘后路径
待办(Week 1 D5 收尾):
- 替换 stock-research_Agent profile 的 AGENTS.md/SOUL.md(A 股专用)
- 同步进
profile/template-stock-research-pro/ - tag v0.1.1 + push(触发 release workflow)
- 部署文档站到 Cloudflare Pages
待办(Week 2 起,P1.0):
详见 plans/2026-05-07-v0.1.1-hotfix.md §"Phase 2: P1.0 backend"。
进一步阅读
plans/2026-05-07-v0.1.1-hotfix.md:本次 hotfix 的逐 Task 实施记录- Phase 1 spec:P1.0 完整设计
- 01 — 数据层:Tushare/akshare 选型和数据决策
- 00 — 多租户架构:P1.0 backend 怎么收敛 Tier 1 secrets
- 架构 — 数据流转:v0.1.1 路由在用户请求路径上的位置