股票 Agent 为什么会把旧数据当成今天?交易日、空数据和失败状态处理实战
2026/7/23 13:26:30 网站建设 项目流程

摘要

股票 Agent 最危险的错误之一,不是接口请求失败,而是请求成功后把上一交易日数据写成“今天”。周末、节假日、盘前、数据晚到和无权限,都可能表现为空数组或旧日期。本文给出一套可落地的统一返回结构、日期状态判断、错误分类与验收方法,适用于 Tushare、AkShare、自建数据库、实时行情 API 和 MCP 工具层。

关键词:股票 Agent、交易日、数据日期、空数据、错误处理、Tushare、AkShare、MCP、A股自动复盘

为什么 HTTP 200 仍然可能生成错误答案

很多股票数据接口在技术上请求成功时都会返回 HTTP 200,但业务状态可能完全不同:

  • 今天不是交易日,接口返回最近一个交易日;
  • 盘前日线尚未生成,结果仍然停留在昨天;
  • 个股当天没有龙虎榜记录,返回空数组;
  • 账号没有某个接口权限,返回错误文本或空结果;
  • 上游数据晚到,部分工具已经更新,部分仍是旧日期;
  • 网络请求失败,被适配层错误地转换成空列表。

如果工具层只向模型返回[]或一组没有日期的记录,Agent 很容易自行补全语义。它可能把“没有数据”写成“今天没有事件”,也可能把昨天的涨停梯队放进今天的复盘。

先设计一个统一返回信封

不同数据源的原始字段可以不同,但进入 Agent 之前,建议统一包一层业务信封:

typeDateStatus=|'CURRENT'|'LATEST_TRADING_DAY'|'STALE'|'NOT_APPLICABLE'|'UNKNOWN';typeResultStatus=|'OK'|'NO_DATA'|'NOT_READY'|'INVALID_ARGUMENTS'|'PERMISSION_DENIED'|'RATE_LIMITED'|'UPSTREAM_ERROR';interfaceAgentDataResult<T>{status:ResultStatus;queryDate?:string;actualTradeDate?:string;dateStatus:DateStatus;source:string;retryable:boolean;data:T;message?:string;}

这不是要求所有上游都使用同一套状态码,而是让适配层把不同供应商的结果转换成 Agent 能稳定理解的业务语义。

第一步:不要用自然日代替交易日

用户说“今天”时,系统至少要判断四种情况:

  1. 今天是交易日且数据已经更新;
  2. 今天是交易日,但当前数据尚未生成;
  3. 今天是周末或节假日,应回退到最近交易日;
  4. 数据返回日期早于最近交易日,属于陈旧数据。

一个简化判断函数可以这样写:

functiongetDateStatus(params:{requestedDate:string;latestTradingDay:string;actualTradeDate?:string;supportsTradeDate:boolean;}):DateStatus{if(!params.supportsTradeDate)return'NOT_APPLICABLE';if(!params.actualTradeDate)return'UNKNOWN';if(params.actualTradeDate<params.latestTradingDay){return'STALE';}if(params.requestedDate===params.latestTradingDay){return'CURRENT';}return'LATEST_TRADING_DAY';}

生产环境还要结合市场时区、开收盘时间、数据频率和具体接口的更新时间,不能只比较字符串日期。

第二步:区分“没有记录”和“调用失败”

以龙虎榜为例,空结果至少可能代表三种情况:

  • 这只股票当天没有龙虎榜记录;
  • 请求日期还没有完成数据更新;
  • 请求失败或账号无权限。

正确的返回应该保留差异:

{"status":"NO_DATA","queryDate":"2026-07-22","actualTradeDate":"2026-07-22","dateStatus":"CURRENT","source":"dragon_tiger_list","retryable":false,"data":[],"message":"该股票在指定交易日没有龙虎榜记录"}

如果是数据晚到,应返回NOT_READY并允许稍后重试;如果是权限问题,应返回PERMISSION_DENIED,不能伪装成市场上没有记录。

第三步:建立可重试错误表

建议把失败分成两类。

通常可以重试:

  • 网络超时;
  • 上游 5xx;
  • 数据尚未更新;
  • 临时限流,且服务返回了等待时间。

通常不应原样重试:

  • 股票代码格式错误;
  • 日期格式错误;
  • 账号没有权限;
  • 查询范围超过接口限制;
  • 业务上确实没有记录。

Agent 不应该自己决定无限重试。适配层可以给出retryable、最大次数和退避时间,超过阈值后在最终报告中标记“未知”。

第四步:多工具结果必须做日期对齐

自动复盘经常同时调用市场概览、涨停池、题材、资金、龙虎榜、公告和自选股工具。即使每个工具单独都成功,也可能对应不同日期。

合并前应先检查:

functionassertSameTradeDate(results:Array<AgentDataResult<unknown>>):{ok:boolean;dates:string[]}{constdates=[...newSet(results.map((item)=>item.actualTradeDate).filter((item):itemisstring=>Boolean(item)))];return{ok:dates.length<=1,dates};}

发现日期不一致时,不要把结果静默拼接。可以重新请求尚未更新的工具,或者在报告中明确标注各章节的数据日期。

第五步:给最终提示词加上数据纪律

提示词不能代替数据校验,但可以约束最终输出:

仅使用工具返回的数据。 每个章节必须标注 actualTradeDate。 status 不是 OK 时,不得推断缺失内容。 NO_DATA 表示指定范围内没有记录;UPSTREAM_ERROR 表示查询失败,两者不得混用。 多个工具的 actualTradeDate 不一致时,停止生成统一的“今日复盘”,改为逐项说明。

第六步:用边界日期做验收

上线前至少测试以下场景:

场景预期行为
周末查询今天行情回退最近交易日,并标记LATEST_TRADING_DAY
交易日盘前查询日线返回NOT_READY或明确使用上一交易日
查询无龙虎榜记录的股票返回NO_DATA,不是技术错误
使用无权限账号查询返回PERMISSION_DENIED
上游超时返回可重试错误,不转换为空数组
两个工具日期不一致阻止生成统一口径的今日复盘
参数日期格式错误返回INVALID_ARGUMENTS,不调用模型猜参数

这组测试应覆盖 Tushare、AkShare、自建数据库、实时行情 API 或 MCP 的真实响应,不要只测试模拟数据。

不同数据源如何接入这层适配

Tushare 官方 MCP 或 API 适合历史行情、财务和量化研究,适配层需要保留接口日期、积分权限和频率信息。

AkShare、Baostock 适合学习与原型,长期运行时要处理上游变化、运行环境和字段差异。

实时行情 API 和 WebSocket 需要额外记录快照时间、延迟、连接状态和断线重连。

面向 Agent 的研究工具层也应该接受同样检查。例如悟道 A股股票数据 MCP 提供 63 个远程只读工具,适合 A股复盘任务,但 Agent 仍需读取返回日期、业务状态和失败项,不能因为使用 MCP 就跳过数据质量验证。

结论

股票 Agent 把旧数据当成今天,通常不是模型单方面的问题,而是工具层没有明确表达交易日期、空数据和失败状态。

解决方案可以概括为四步:统一返回信封、使用交易日而不是自然日、区分业务空值与技术失败、多工具合并前检查日期一致性。

无论底层使用 Tushare、AkShare、数据库、实时 API 还是 MCP,都应该把这套数据纪律放在模型之前。模型可以负责解释数据,但不能负责猜测数据是否新鲜。

本文讨论数据工程与 Agent 接入,不构成投资建议。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询