Files
auv/AGENTS.md
T
Sakurasan e24b1a360b feat: 优化每日分析提示词模板并修复分段生成链路
提示词:
- SYSTEM_PROMPT 重写为可执行原则(事实优先/时间锚定/判断挂数字/禁用套话)+输出格式契约
- DAILY_ANALYSIS_PROMPT 重排注意力:取数指令置顶(要求同轮并行调用 4 个核心工具)、
  写作规约 8 条、环比快照居中、前日报告全文置底并改为「今日数据优先+核对昨日展望」
- 新增单位口径、符号规范(+/- 是前端红涨绿跌着色依据)、不荐股等硬规约
- 移除已废弃的「今日定调」摘要规则(与分段指令、前端渲染互相冲突)
- 八章重构:板块资金流独立为「四、资金与筹码」,重复的「关注方向+下个交易日建议」
  合并为「七、明日展望」

生成链路:
- 修复分段生成未回灌前文,后段看不到前段导致重复铺数据、数字口径打架
- 新增 REQUIRED_TOOLS 校验:核心工具不全时补一轮并在 user 消息点名缺失项
- 修复 _extract_summary 被 # 标题行占掉,改为剥离标题与 Markdown 标记后截断

AGENTS.md 同步八章结构与 prompt 工程约定
2026-09-12 15:57:14 +08:00

13 KiB
Executable File
Raw Blame History

A股走势追踪应用 - 技术上下文

Dependencies

  • recharts - K线图表库(已内置)
  • lucide-react - 图标库(已内置)
  • sonner - Toast通知组件(已内置)

Architecture

路由结构

  • / - 首页:搜索股票、创建集合、管理股票
  • /stock/$code - 股票详情页:K线图、实时行情、涨幅显示
  • /share/$code - 分享页面:通过短链查看公开的股票集合

数据库表

  • stock_collections - 股票集合(名称、描述、user_id、last_accessed_at)
  • collection_stocks - 集合中的股票记录(股票代码、名称、添加时间、添加价格)
  • share_links - 分享短链(短链码、关联集合ID)

用户管理

  • 每个匿名用户生成永久 userid 存储到 localStorage
  • 集合通过 user_id 隔离,RLS 策略基于 user_id 控制访问
  • 3个月未访问的集合自动删除(通过 Edge Function 定时清理)

数据源

  • Edge Function stock-quote 代理腾讯财经API获取A股实时行情
  • Edge Function stock-history 双数据源获取历史K线:主源腾讯 fqkline(前复权),腾讯返回数据少于2条时降级新浪 getKLineData(北交所920开头新股腾讯常只返回1条,新浪能返回完整90天)
  • Edge Function stock-search 代理腾讯智能搜索API(smartbox.gtimg.cn)支持名称/代码/拼音模糊搜索
  • Edge Function stock-fund-flow 获取近30日资金流向数据,主数据源为东方财富妙想MX API(mkapi2.dfcfs.com,每日150次调用限制,需配置 MX_APIKEY 环境变量),回退方案为东方财富 push2his.eastmoney.com
    • MX API 数据特性:返回数据按日期降序(最新在前),Edge Function 内必须 sort 为正序后再计算累计值;只返回主力净流入和成交额,不提供散户/中单/小单数据
    • 日期格式标准化:MX API 返回日期格式可能不统一(2026/07/04、07-04),Edge Function 内统一为 YYYY-MM-DD 以匹配 K 线数据
    • 数值解析:MX API rawTable 字段可能是字符串(如 "1.432亿元"),需用 parseAmount 函数解析
    • JWT 鉴权:stock-fund-flow 必须部署为 -j false(匿名可访问),否则前端调用被拒绝
    • 回退方案东方财富API字段(索引0-18):日期,主力净流入,超大单流入/流出,大单流入/流出,中单流入/流出,小单流入/流出,主力净流入%,超大单流入/流出%,大单流入/流出%,中单流入/流出%,小单流入/流出%
    • 腾讯K线API字段:[日期, 开, 收, 高, 低, 成交量, 成交额](第7个字段是成交额)
    • ❌ 东方财富K线API(kline/get)不稳定,可能返回 data:null,已弃用改用腾讯
  • 前端通过 /sb-api/functions/v1/stock-quote?code={6位代码} 调用实时行情
  • 前端通过 /sb-api/functions/v1/stock-history?code={6位代码}&days={天数} 调用历史数据
  • 前端通过 /sb-api/functions/v1/stock-search?keyword={关键词} 调用搜索(腾讯返回UTF-8+\u转义,类型字段GP-A/GP-A-KCB/GP-A-BJB区分主板/科创板/北交所)
  • 前端通过 /sb-api/functions/v1/stock-fund-flow?code={6位代码}&name={股票名称}&days={天数} 调用资金流向数据(name 参数用于MX API查询)
  • 市场标识:688/60开头为SH(上海主板/科创板),920/8/4开头为BJ(北交所),其他为SZ(深圳主板/创业板)

What Didn't Work

  • ❌ 新浪财经API直接在前端调用 → 跨域限制 → 改用Edge Function代理
  • ❌ 腾讯财经历史API直接在前端调用 → 跨域限制 → 改用Edge Function代理
  • ❌ 百度股市通API → 返回格式不稳定 → 改用腾讯+新浪双数据源
  • ❌ Python mootdx库 → 沙箱环境无法安装C++依赖 → 放弃Python方案

Patterns / Constraints

  • RLS策略设置为匿名可读写,支持分享链接公开访问
  • 股票代码格式:6位数字(如600519)
  • 分享短链生成:随机8位字母数字组合
  • 集合卡片股票列表格式:名称/代码(左)+ 添加价/涨跌%/最新价(右三列)
  • 添加股票时 added_price 保存为当日实时价格;若无历史数据则显示当前价和 0.00%
  • 分享链接区域点击自动复制到剪贴板,通过 Sonner Toaster 显示提示;复制失败时降级为 textarea 方案或提示手动复制
  • 生成分享链接时复用已有短链,避免每次生成新链接
  • 全页面适配移动端:响应式字体、间距、布局断点(sm/md/lg)
  • K线图历史数据获取失败时直接报错,禁止使用模拟数据降级(避免"刷新数据变化"问题)
  • K线天数逻辑:日K一次拉取近365天(供拖动回看),默认视口只展示最近90个自然日(3个月),向左拖动查看更早数据;分钟K一次拉取320根,铺满展示
  • K线图基于 TradingView Lightweight Charts v5 实现(蜡烛/折线 + MA/MACD/RSI 副图);拖动/缩放查看数据,切换指标或显示方式保留当前视口(仅在数据集变化时重置)
  • K线图时间格式自定义:时间轴刻度 年→YYYY、月→YYYY-MM、日→MM-DD,十字光标→YYYY-MM-DD(tickMarkFormatter + localization.timeFormatter);格式化必须用 UTC 取值(getUTCFullYear 等),因为时间戳按"北京时间墙钟视作 UTC"存储,用本地时区方法会错位一天
  • 板块标记:688开头=科创(红)、300/301开头=创业(紫)、920/8/4开头=北交(橙),主板不显示标签;标记位置:搜索候选、详情页标题、集合卡片股票列表、分享页股票卡片标题
  • 详情页右上角外部跳转按钮:①"东方财富" https://wap.eastmoney.com/quote/stock/{market}.{code}.html?appfenxiang=1,market映射 688→6/60→1/其他→0;②"金十数据" https://search.jin10.com/?keyword={股票名称URL编码}(按名称搜索金十资讯)
  • 详情页资金流向模块:展示近30日资金流向分析,包含:
    • 资金流向概览:主力总净流入、大单流入资金(≈主买资金)、日均主力流入、主力流入/流出天数统计
    • 主力资金流向:柱状图展示每日主力净额
    • 累计主力资金趋势:折线图展示累计主力资金的走势变化
  • 每日行情明细表:独立于资金流向模块,默认显示7日数据,支持切换7日/21日;表格列包含日期、涨幅、主力净流入、成交额,颜色遵循A股惯例(红涨绿跌)
  • 每日行情明细表数据截取:使用 chartData.slice(-dailyTableDays).reverse() 获取最近N个交易日的倒序数据(最新日期在前)
  • 每日行情明细表资金流向匹配:K线 dateObj 转 YYYY-MM-DD 时必须用本地时区(getFullYear/getMonth/getDate),禁止用 toISOString().split('T')[0](UTC 偏移会导致中国时区日期错位一天,资金流向数据匹配失败);匹配字段为 mainForceNet(主力净额=超大单+大单净流入)和 turnover(成交额)
  • 成交额备用计算:当资金流向API获取失败时,使用 chartData 的 volume × close 近似计算成交额(单位:元)
  • 资金流向数据获取失败时,前端通过 fundFlowError 状态显示错误信息,便于排查问题
  • ❌ 东方财富 API(push2his.eastmoney.com)在 Edge Function 环境被拒绝访问(peer closed connection),主力净流入数据无法获取,显示为 "-"
  • ✅ 替代方案:使用腾讯实时行情API的外盘(索引7)和内盘(索引8)数据计算净主动买入额 = (外盘 - 内盘) × 当前价 × 100(单位:元)

每日 AI 分析(backend FastAPI,15:10 自动触发)

  • 报告结构约定:正文以 # {trade_date} A股收盘分析报告 开头后直接进入第一章,无"今日定调"摘要(已移除:prompt 不生成、前端无高亮框);summary 为去掉标题行与 Markdown 标记后的正文前200字,供管理列表展示

  • 八章固定顺序:一、市场总览|二、题材热点分析|三、核心股追踪|四、资金与筹码|五、重要消息面|六、海外市场与国内期货|七、明日展望|八、风险提示;分段归属:part1=一+二、part2=三+四、part3=五~八(原"四、关注方向/五、下个交易日建议"内容重复,已合并为"七、明日展望",板块资金流从第二章挪出独立成第四章)

  • prompt 工程约定(改模板必读):①取数指令放 prompt 最前(要求同一轮并行调用 4 个核心工具,代码用 REQUIRED_TOOLS 校验,缺则补一轮并在 user 消息里点名缺哪些);②环比快照紧随其后、前日报告全文放最后(避免长文本把取数指令挤出注意力区);③凡写数字的规则必须同时写"找不到就写 —(今日无数据)",否则模型会用常识补全;④涨跌幅/环比/净额一律带 + 或 -,这是前端 colorizeText 红涨绿跌的着色依据;⑤模板用 .format() 渲染,正文中出现裸 {} 会直接报错

  • 分段生成必须回灌前文(messages.append({"role":"assistant","content":part_content})):否则后段看不到前段,会重复铺同一段数据、数字口径打架;生成失败的占位段不回灌

  • 环比数据:collect_ai_analysis 每次运行先采集当日盘面快照(指数+涨跌统计 JSON)写入 daily_market_stats 表(UNIQUE trade_date,upsert),再读上一交易日快照格式化为 prompt 中的"环比数据段";首跑无昨日数据时 AI 须如实标注"暂无昨日基准"

  • 连板梯队:get_market_dashboard 返回 limitLadder 字段(完整版,2连板以上全量+首板前8),涨停原因/封单金额来自涨停池按 thscode 匹配;看板 events 里的天梯仍只取每层前2(保持 UI 精简),两处用途不同不要合并

  • tokens 口径:ai_reports.tokens_used 只记"当次生成"消耗(约7万/份);同日重新生成走 UPSERT,generation_count 自增、updated_at 刷新、created_at 保留首次生成时间;表有 UNIQUE(trade_date, report_type),禁止改回 INSERT OR REPLACE 之外还要注意别用 lastrowid(UPSERT 更新时不可靠,须回查 id)

  • 旧库补列用 init_db 里的 try/except ALTER TABLE 轻量迁移(CREATE TABLE IF NOT EXISTS 不会更新旧表结构)

  • 补充数据源(services/market_extra.py):①财经快讯 get_news=新浪7x24 zhibo.sina.cn(feed.list.rich_text);②板块主力资金流=东财 push2 的 clist 接口(f62 主力净额),必须用 push2delay.eastmoney.com 镜像——push2 对部分客户端 TLS 指纹拦截(peer closed),查询串保持字面量 + 号;③两融=datacenter-web 的 RPTA_RZRQ_LSHJ(T+1 披露),两融余额=RZYE+RQYE

  • AI 报告重要消息面规则:必须基于 get_news 快讯,5-8条,格式【宏观/政策/行业/公司/海外】新闻——影响解读,禁止编造;板块资金面规则:必须引用 sectorFundFlow 的行业净流入/流出TOP3+概念TOP3

  • 截断续写:报告长导致 finish_reason=length 时,拼接已有内容并向 messages 追加"继续"指令让模型续写(最多3次),truncated 仅在续写后仍截断时为 true;call_llm 读超时 300s(续写携带全部上下文)

  • 快照入库防护:_capture_market_snapshot 校验 indices 非空且涨跌统计不全 0,fuyao 失败时跳过入库,防止空快照污染环比

  • 调试注意:独立脚本跑 backend 代码必须显式 load_dotenv("/path/to/repo/.env")——fuyao_apikey 在仓库根目录 .env(uvicorn 靠 --env-file 参数加载),backend/.env 只有 MX keys;且 stdin 脚本里 load_dotenv() 无参调用会因 frame 断言报错,须显式传路径

  • 第三档呈现:报告页按 ## 二级标题拆分为多张卡片渲染(splitReport),首卡含 # 标题+定调引用块;表格单元格数字按 A股惯例红涨绿跌(colorizeChildren 只给带 +/- 号的数字着色);标题栏显示"总第 N 期"(issue_number,latest 接口用 COUNT(trade_date<=) 子查询计算)

  • 海外指数/国内期货:fetch_global_markets 走 push2delay 的 ulist.np(海外 secid 100.NDX 等)+ clist(期货 fs m:8/113/142/114/115,只取名称含"主连/主力合约"且排除"次主连",按成交额降序取前12);接入 dashboard globalMarkets 字段

  • ⚠️ openteam 网关对 LLM 单请求有约 120s 硬超时(超时返回 502 或空 SSE),GLM reasoning 长报告一次生成必死。解法:call_llm 全流式(SSE)+ collect_ai_analysis 分三段生成(REPORT_PARTS,每段约1200-1600字,各重试3次带退避,失败占位不阻塞);工具轮拿到数据后立即 break 进分段(再问一轮只会空转120s);thinking:{type:disabled} 参数网关返回400不可用

  • 工具结果必须瘦身:get_active_core_stocks 只保留出现次数前25只+题材前5(全量145KB会撑爆上下文);get_market_dashboard 全量约13KB可接受

  • glm-5.3-flash 空返回特征:SSE 200 但只有 reasoning_content 无 content/tool_calls/finish_reason(可能流满120s被掐),按空轮次处理重试即可