← 返回文章列表
Data Agent 工程实践 · 第 1 篇

Data Agent 工程实践(一):一个数据问题怎样走到查询结果

沿着“查 1 月各渠道净收入”拆开第一版 Data Agent:来源材料怎样形成语义,Pi 怎样调用受控工具,Rust 怎样绑定消息、SQL 版本与执行预算,异步结果和会话恢复怎样保持归属。结合源码、合成数据与质量测量解释实现取舍。

Data Agent
Agent Engineering
数据工程
合集目录:Data Agent 工程实践第 1 / 1 篇

Data Agent 的第一版做完后,我想把它重新读一遍。

这个项目是我指挥 Coding Agent 一步步做出来的。需求和取舍由我提出,大量代码由 AI 完成。页面能操作,查询能执行,也留下了测试和试用记录;但要解释一次请求经过哪些模块、某条规则为什么放在那里,仍需要沿着代码核对。

写这个系列,就是为了把这些细节弄清楚。四篇依次讲整体设计、语义与个人积累、查询执行与恢复,最后讨论验证和开发复盘。这一篇用一个问题贯穿全程,把关键记录、调用和失败情况展开。

本文对应合成平台 MVP。表、数据和业务说明均从零构造,查询引擎使用 SQLite;Pi、Rust 服务、MySQL、Milvus 和 Mem0 已有实际接入与本地验证,真实模型试用使用 DeepSeek Flash。真实数据平台、正式身份认证和生产容量仍待验证。下面的业务约定只属于这套演示资料。

一句“查净收入”,先确定五件事

假设用户问:

查一下 2026 年 1 月各渠道的净收入,金额用元。

生成 SQL 前,要把这句话翻译成可计算的条件。至少有五件事需要依据:

问题样例里的约定理解错了会怎样
一行代表什么一个订单商品行,主键为 (order_id, line_id)把行数当成订单数,多商品订单会重复计数
用哪个时间净收入按当前行首笔成功付款的 paid_at 归属用 order_date 会把下单月当成收入月
怎样处理退款累计付款减累计退款;退款扣回原付款期间只筛选 1 月退款,会漏掉 2 月发生、应扣回 1 月的退款
金额是什么单位付款、退款已分摊到行,单位为整数分再乘商品数量会重复计算;不换算会把分当元
统计哪些数据默认排除 is_test=1;使用当前快照测试交易会混入结果,快照之后的事件则根本不在数据里

这些答案来自表结构、加工 SQL 和业务说明。字段名只能提供线索。例如 order_status='refunded' 表示整单全退,它不能代表“这行出现过退款”。某行可能全退,整单却仍是部分退款。

加工 SQL 也决定了金额为什么可以直接相加。raw_payments 中一行是一笔付款或退款事件,同一订单商品行可以有多笔事件。加工先筛选截止快照之前的成功事件,按 (order_id, line_id) 汇总,再连接订单行。如果查询时又把事件明细连接回来,然后累加已经汇总的行金额,就会把同一笔收入算多遍。

还有一个容易藏在“1 月”后面的条件:快照截止 2026 年 2 月 4 日 00:00:00 UTC,不含截止时刻。1 月付款、2 月初退款,在这份快照中会减少 1 月净收入。因此本次问题的完整含义是“截至这份快照、归属于 1 月付款的净收入”。若要查 1 月实际发生的现金流入流出,就要改按付款事件时间计算。

这份约定可以写成下面的教学 SQL。它用于解释口径,不是某次模型回答的逐字摘录:

SELECT
    channel,
    SUM(paid_amount_cents - refunded_amount_cents) / 100.0
        AS net_revenue_yuan
FROM demo_order_detail
WHERE is_test = 0
  AND paid_at >= '2026-01-01T00:00:00Z'
  AND paid_at <  '2026-02-01T00:00:00Z'
GROUP BY channel
ORDER BY channel;

在仓库的合成数据上执行,得到:

渠道净收入(元)
app16
store8
web100

左闭右开的区间避免漏掉月底最后一秒之后的小数时间,也避免把 2 月 1 日算入 1 月。/ 100.0 保留元的小数表达。公式没有再次限制退款月份,因为退款累计值已经反映快照之前的事件。

这些金额可以独立计算,模型却还要回答“为什么这样算”。业务说明还明确列出了未模拟的税费、运费、货币兑换和跨月分次付款等边界。字段叫 paid_amount_cents,不等于系统已经知道税费是否包含在内。这个缺口应跟着解释保留下来。

业务语义怎样从资料变成可用记录

系统有三个日常入口:工作台负责提问和结果,语义管理负责公共表、字段、指标与文档,“我的积累”保存个人偏好和分析方法。净收入的定义属于共享语义,不能只留在某一次聊天里。

先冻结本次分析能看到的材料

平台适配器提供表结构、原始注释、加工 SQL 和血缘。预填任务从目标对象出发,收集上游来源,再补充相关业务文档。当前装配器有明确上限:沿血缘最多八层、最多收集 32 份来源,再取至多 32 份相关文档;材料正文合计不超过 24,576 字节。

这些限制控制一次模型调用的体积。分配正文额度时,短材料先释放不用的份额,其余材料分摊剩余额度,避免一份长 SQL 把后面的业务文档完全挤掉。截断沿 UTF-8 字符边界进行,并记录 body_limit、原长度和已纳入长度。上游不可读、来源不完整、血缘超过范围也分别写入缺口。模型拿到的材料因此有明确的“读到了多少”。

准备完成后,任务保存来源 ID、版本、正文与覆盖情况。模型运行期间有人改了业务文档,旧分析不能悄悄以新文档的名义落库。提交前还要核对来源和目标版本;版本不再匹配,本次输出就不能成为当前建议。材料装配器可以看到这些边界。

分析和依据复核各调用一次

字段预填使用固定两阶段:先分析,再对分析结果做依据复核。第一阶段产出建议、缺口和引用;通过结构、目标覆盖和引用检查后,才进入第二次模型调用。最终结果仍要经过程序检查,再保存为建议。

这条流程没有自主规划循环。它的任务范围已知,就是给指定对象预填语义。聊天中的 Pi 则需要根据问题选择下一步调查动作。两者共用模型预算约束,但调度方式不同。

validated 只表示输出符合结构和引用规则。例如引文确实来自某个固定版本,目标条目没有遗漏。它不能证明模型从那句原文推出的业务含义正确。引用了真实加工 SQL,也可能把一段中间计算误说成最终表允许出现的值;后面的质量测量就要检查这种错误。

语义预填的输入冻结、两阶段分析、版本校验以及人工覆盖保护

根据当前源码绘制。两次模型调用之间和正式保存前都有检查;图中的“通过”表示相应程序检查通过。 查看原图

原始事实、建议和人工值分别保留

以 paid_amount_cents 的含义为例,一条语义记录中会保留几层内容:

字段保存内容重新分析时的处理
source_facts来源 ID、版本、位置及原始依据更新为本次通过检查的来源事实
suggestion模型建议、缺口、分析状态及依据保存新建议供核对
human_override人工修订及修改信息保留已有人工修改
effective_value当前读取时采用的值有人工覆盖时继续使用人工值;否则采用新建议

保存实现中的关键分支很短:

entry["source_facts"] = new["source_facts"].clone();
entry["suggestion"] = new["suggestion"].clone();
if entry["human_override"].is_null() {
    entry["effective_value"] = new["effective_value"].clone();
    entry["review_state"] = json!("unverified");
} else {
    entry["review_state"] = json!("needs_review");
}

假设维护者已经补充“按成功付款累计,金额为分;税费范围未知”,重新预填时模型又给了不同解释,人工有效值继续保留,新建议留下供复核。人工标记也不等于业务已验证,它说明的是内容来源。

清除人工覆盖是显式操作。清除后才回到建议或来源基础值。正式对象、新版本和索引待办在同一个数据库事务内保存,避免正文更新了却没有留下索引任务。

跨用户纠错还有另一层区分:普通用户提出的纠错先是个人草稿,明确提交后负责人才能看到。负责人“接受”只改变建议处理状态;核对、编辑并保存后,正式语义才产生新版本。这里的语义编辑权属于 Data Agent,数据平台的读取和执行权限仍独立检查。

检索命中以后,为什么还要回 MySQL

对净收入问题,Agent 通常需要找到指标定义、订单行表、金额字段和业务说明。当前检索把名称与关键词匹配、向量候选结合使用。

词法通道对名称命中给更高权重,也会检查正文;中文查询使用二元词等分词结果。精确对象 ID 或精确名称优先。其余候选按两通道名次融合,当前分值可简写为:

score = 1 / (20 + lexical_rank) + 1 / (20 + vector_rank)

名次从零开始,某通道没命中时该项为零。使用名次而非直接相加向量距离和关键词分,避免把不同尺度的数值混在一起。当返回上限至少为六时,选取过程还会尽量保留表、字段、指标、文档、关联、术语的类型覆盖,防止结果全被一类对象占满。具体排序没有使用另一个模型判断相关性。

正文向量化按 360 个字符切窗口,步长 280,重叠部分有助于保留跨边界的语句。索引片段标识包含对象、版本、条目、位置和模型版本。文档编辑时的业务章节与检索窗口是两种边界,不能把一个窗口当作完整章节。

Milvus 返回的仍然只是候选。服务端根据候选 ID 回 MySQL 核对空间、启用状态、正式版本和来源依赖,随后从正式正文重建命中摘录。位置和内容指纹不匹配时,不能直接把向量库中的旧文字交出去。

例如“净收入”文档从 v7 改成 v8,旧向量暂时还没更新。v7 即使排在第一,也不能借这个排名继续充当当前口径。停用文档同样如此:停止使用要在正式读取时成立,不能等待后台删完向量才生效。

共享语义与个人记忆分开检索,经过权限、版本、状态的回源检查后才进入当前对话

复用项目已有的 GPT Image 概念插画。两个索引集合负责找候选,MySQL 保存正式记录。

交给模型的第一次结果以短目录和摘录为主。工具会给出 content_page.complete 和 next_offset;不完整时,模型可用 read_knowledge 按同一版本继续读取。来源原文另用 read_source 补读。摘要短不是问题,把没读完的材料说成全文才是问题。

当前候选检索有数量上限,会返回 bounded、candidate_limit 等覆盖提示。合成规模检查可以验证候选处理和版本过滤,尚不能证明真实千表环境中的召回率。检索漏掉了关键文档,后面的模型再认真也可能建立在不完整资料上。

Pi 怎样调查,Rust 怎样接住工具调用

先看这次问题由哪些进程负责:

部分对这次请求负责什么
React / TypeScript接收输入,展示文字、SQL、状态和结果,保存未发送草稿等界面状态
Rust API 与 Worker保存会话、任务和查询,核对权限、版本、执行依据与预算,跟踪平台状态
Node.js / Pi SDK理解问题、调查、澄清、选择工具、生成回答,维持会话和原生上下文压缩
Python / Mem0提取与检索个人记忆候选,不决定共享指标定义
平台适配器提供目录资料、SQL 检查、执行状态和结果;当前目标是合成 SQLite 平台

Data Agent 架构总览:前端、Rust 业务服务、Pi、Mem0、正式存储与检索索引

架构图来自仓库当前实现。已有真实模型试用主要使用 Flash,工作台也支持选择 Pro。

Rust API 和 Worker 复用同一个业务库。HTTP 路由、Pi 工具请求与后台作业进入各自的具名用例,再由用例组合业务模块。模块保存自己的状态,用例确定跨模块事务边界。例如执行查询既要读消息、锁分析任务,又要确认 SQL,不能让三个入口各写一套稍有区别的规则。

Node.js 的会话入口调用 Pi 的 createAgentSession,传入模型、思考等级、会话管理器、受控资源和工具,再调用 session.prompt。取消使用 session.abort,上下文压缩使用 Pi 原生能力。应用没有再建一个规划器决定“第一步必须检索、第二步必须生成 SQL”。

以当前工具说明为例,模型可以:

工具用途及限制
search_knowledge查共享语义、本人记忆和当前已选 Skill 的目录;命中内容作为资料
read_knowledge / read_source按版本分页读取正式正文或来源,检查是否已读完整
update_analysis_task登记消息属于哪个任务,保存条件、修订或澄清问题
validate_sql检查 SQL 与目标能力,不执行
request_query保存完整 SQL、参数、目标、口径和依据,供用户查看
execute_query根据当前用户的明确执行意图申请执行,接受宿主校验
get_query读取已有查询状态和结果,不创建或重跑查询

对“退款率”,模型可能先读定义,发现有订单退款率和退款金额比例,再保存澄清问题并询问分母;用户回答后继续同一个任务。对定义已经明确的净收入,则可以调查后直接生成草稿。选择哪个工具由模型判断,工具能造成什么状态变化由程序限制。

一次工具调用经过 Node.js 时,先按 packages/contracts 中的同源 Schema 校验参数,然后把 SDK 调用 ID、工具名称、参数、会话检查点和宿主绑定的运行身份送给 Rust。Rust 先登记稳定操作身份,再执行业务用例。模型无法靠自己填一个 user_id 就切换归属,也不能在普通工具里获得任意文件读写或数据库执行能力。

工具有确定回执以后,结果回到 Pi,模型可以继续调查或结束回答。流式文字则通过 message_update 中的 text_delta 单独提交给宿主,前端能先展示过程。最终交付还会检查最近一条助手消息的停止原因:输出被截断、模型报错或已取消,都不能当作成功回答。

最后,Rust 核对已保存的文字片段与最终全文一致,把最终回答、检查点、消息消费状态和租约释放放进一次事务。由此可以区分“界面已经显示了一部分字”和“这一轮已经正式完成”。相关边界分别在 Pi 会话入口和 最终交付用例。

跨进程和跨语言会增加运维与排错成本。这里换来的是职责边界:模型保留调查空间,正式业务状态有明确的写入者。Schema 能检查形状、程序能检查版本,但“净收入是否理解正确”依然要看内容证据。

从 SQL 草稿到执行,绑定的到底是什么

第一条问题处理完,用户看到的是 SQL、参数和口径说明。接下来两句话会产生不同动作:

只看 app。

只看 app,再执行。

前一句修订条件,后一句还要求执行。Pi 负责理解这层差别。Rust 不再做一遍自然语言分类,而是检查这次执行请求的依据和目标是否成立。

条件版本和 SQL 版本各自变化

对话、分析任务、查询和 Agent 运行是不同记录。对话容纳长期交流;任务保存一次分析的目标、条件与修订;查询保存某份具体 SQL;运行表示 Agent 此刻处理一条输入的执行过程。

条件由“全渠道”改成“app”时,任务产生新的 condition_version,旧待执行稿失效。模型修订 SQL 后,保存新的查询及 draft_version。如果条件不变,只纠正 JOIN 写法,也要明确指出被替换的旧查询,防止用户仍能执行那份已知有问题的稿子。

这里采用了一个比较保守的顺序:先让被纠正的旧稿失效,再做新 SQL 的外部检查。若新 SQL 检查失败,界面应提示修订没有完成,旧稿也不会因此恢复执行权。否则用户明明已经指出错误,系统却可能因为新稿失败而继续允许执行旧稿。

可把一次修订理解成下面的示意记录;其中编号用于讲解:

时刻任务条件查询草稿能否确认执行
首次展示v1:1 月、全渠道qA / 草稿 v1等待用户明确要求
用户改为 appv2:1 月、appqA 已失效不能执行旧稿
新 SQL 检查完成v2:1 月、appqB / 草稿 v2可根据当前有效授权执行

全文引述把授权连回真实消息

execute_query 携带 query_id、draft_version、condition_version 和 instruction_quote。最后一个字段必须是当前用户完整原话,不能只摘其中的“执行”两个字。

执行入口检查消息仍可处理、引述与完整正文匹配,并排除系统查询结果通知。随后检查消息已归属正确任务,查询属于当前对话和任务,上下文依赖仍然有效。确认时继续核对 SQL 草稿版本、任务条件版本、检查状态和取消状态。

全文匹配解决的是出处与截断问题。“先别执行,只解释一下”不能被裁成“执行”当作授权依据。但它不能证明模型理解一定正确:模型如果误读了完整原话,单靠字符串匹配仍然不够。当前行为还依赖工具说明、模型判断和相应负例测试,需要如实保留这个边界。

完整用户消息经过 Pi 意图理解与 Rust 校验,绑定查询、版本、消息和预算

根据聊天执行入口绘制。业务文档、工具结果和后台完成通知都不能作为新的用户执行授权。 查看原图

首次确认时,查询授权、消息已应用标记和预算归属原子提交。重复请求拿到原查询,不会重新执行,也不会把已有操作转到一份新预算上。用户如果明确要求“重新跑一次”,就需要创建新的查询记录,保留两次执行的区别。

SQL 的只读性和平台权限还要单独检查。当前 SQLite 适配器实际使用只读连接、EXPLAIN 与 authorizer 等机制,不能只看语句是不是以 SELECT 开头。未来接入真实平台,需重新实现其方言、身份与执行协议;本地 SQLite 的通过不能证明真实 Datasight 权限已经正确接入。

从提问、SQL 展示、聊天执行到结果下载的查询过程

复用已有 GPT Image 流程插画。用户可以返回修改条件,已提交查询继续按自己的任务和版本跟踪。

查询在后台运行,晚到的结果怎样不串题

用户要求执行后,查询先进入队列,再由 Worker 提交给平台。平台可能返回运行中、成功、失败,也可能因超时暂时无法判断提交是否成立。

这时用户仍可以继续输入。假设 1 月净收入查询 A 还在运行,用户又提出 2 月问题 B。系统需要同时保存两件事:当前正在讨论 B;A 仍有一条未完成的平台查询。

同一 Pi 会话的推进串行化,避免两条模型运行同时写会话树。平台查询独立运行,所以等待 A 不必占住整个对话。A 完成后,系统按原查询、原任务、原条件版本发出结果唤醒,再让 Pi 解释结果。后台通知不算新的用户要求,也不能授予另一条 SQL 执行权。

最终交付还会核对任务版本。旧版本的结果可以作为那次查询的历史结果展示,但不能把已经修订的任务推进成“当前问题已回答”。预算也沿用原执行归属,不能因为结果回来晚了,就借 B 的新消息继续支付 A 的模型调用。

并行平台查询的结果归属,以及 Pi 日志、精确检查点和稳定操作身份的恢复关系

根据当前实现绘制。查询 A、B 是讲解用编号;同一 Pi 会话串行推进,平台查询可独立运行。 查看原图

超时以后,先查证有没有做成

查询提交超时有两种可能:平台没收到请求,或者平台已经执行,只是回执没回来。把它们都当失败再提交一次,会造成重复执行。

因此状态里有 submission_unknown。Worker 根据稳定查询身份先查证平台状态,保留未知,或在确认条件满足时有限重试。取消也分开保存 cancel_state 与 execution_state:“已发出停止请求”只说明本地提出了取消,不说明平台已经终止。

Agent 工具具有类似问题。Rust 把 SDK 调用 ID 映射到稳定 operation_id。进程恢复后,新 run_id 证明当前运行的执行资格,原副作用仍使用原操作身份。同一个操作、同一份参数可接回原回执;同 ID 配不同参数则冲突。未知操作不能通过换 ID 变成一笔看似全新的动作。

会话日志要回到正确的叶子

Pi 的完整会话树、工具历史和压缩记录保存在原生 JSONL;MySQL 保存该会话文件、session ID 与精确 leaf 的引用。恢复时打开对应日志,再切回已经提交的 leaf,不能简单拿“文件最后一行”当作已提交状态。

一个具体的崩溃窗口是:Pi 已把新条目写进日志,Rust 还没提交最终回答。磁盘上有条目,不代表业务事务已经承认这一轮完成。保存精确 leaf,才能把 SDK 历史与业务提交位置对齐。日志恢复实现直接使用 Pi 的 session 和 branch 接口。

压缩摘要也属于需要检查的历史。系统记录已经交给模型的知识、来源、记忆和 Skill 的版本依赖,按同一会话累积;不会因为最近一页没出现某条资料就删除依赖。因为那条资料可能仍在压缩摘要里。

停用资产、撤权或改版后,新输入可以重建上下文;对于同一输入的恢复,如果旧上下文已经失效,则拒绝继续,避免一边忘掉旧工具记录、一边把副作用重做。这里保证的是失效内容不再进入后续模型调用,不意味着物理删除全部历史日志。

每次实际模型调用还有预算预留和结算。未知用量继续占用预留,不按零费用处理;会话恢复、任务拆分或结果唤醒也不能重置额度。这些记录使故障处理有账可查,但恢复依然依赖 MySQL 和 Pi 日志共同存在,只备份向量库远远不够。

查询结果、个人记忆和 Skill 怎样留下来

查询成功后,工作台可以预览、复制最终 SQL、下载 CSV,并继续追问。当前表格预览前 10 行,合成平台最多保存 1,000 行,超过保存上限会提示截断。下载读取该查询已经保存的结果,不会隐式重新跑 SQL。

实际工作台中的合成订单明细、CSV 下载和最终 SQL 入口

另一条订单明细查询的实际截图,用来展示结果界面;它不是前面按渠道汇总的三行结果。

假如用户接着说“以后金额默认用元”,这条偏好可以跨会话保留。“这次用元”则仍是当前要求。共享指标继续以分定义,展示偏好不改公共口径,用户当次明确指定的条件优先。

当前 Mem0 从完整原始消息中提取候选。候选先处于 pending,不能马上进入正常召回。Rust 核验并把正式正文、用户、空间、版本和状态存入 MySQL 后,再推进个人记忆索引到 ready。如果数据库保存失败,向量库里一个相似度很高的 pending 候选也不能假装已经保存成功。

人工编辑记忆正文时,索引采用 infer=False,不再让模型重新改写人工内容。检索先按用户、空间和提交状态过滤,再核对当前映射与版本,最后仍回 Rust 的正式记录。正文对了而适用范围被扩写,也会导致误用,所以正式 body 和 scope 使用同一份最终提取文字;名称只作显示标签。

另一类积累是分析方法。例如“核对付款期间与退款归属,检查一对多关联,再生成净收入 SQL”,可以保存为 Skill。Skill 需要用户明确选用,Pi 才能按需读取对应正文、说明和文本模板。个人 Skill 可直接使用,也可以明确发布为当前空间的独立公共副本;公共副本以后独立维护,不带走私人聊天、记忆或来源备注。

个人 Skill 经明确发布形成公共副本,两类方法都经用户选用后进入 Pi 当前对话

复用项目已有 GPT Image 概念插画。个人方法无需先公开才能使用。

存储分工随这些边界确定:

记录保存位置恢复或读取时需要什么
共享语义、个人资产、任务、SQL、预算MySQL当前状态、版本、归属和依赖
共享语义与个人记忆的向量Milvus 的独立集合候选回源;索引可由正式内容重建
Pi 会话树、工具历史、压缩记录Pi 原生 JSONL与 MySQL 中 session/leaf 引用对应
Mem0 历史与技术回执本地 SQLiteSDK 操作连续性;正式个人资产仍在 MySQL
业务数据和查询结果平台;当前为合成 SQLite平台查证状态,按结果引用读取

“记住用户偏好用元”和“记住那次查询已提交但回执未知”都需要持久化,保存规则却完全不同。前者可以修改和停用,后者关系到是否会重复执行。把它们分开,后续查错时才能找到负责这条事实的记录。

跑通以后,还要检查回答对不对

2026 年 10 月 12 日,为这篇文章在当前代码上重新运行了固定场景。结果需要先说清楚:正式测量在第三个场景中止,没有得到新的 16 题整体准确率。

本次怎样测

先通过全 16 场景的协议检查,再用真实 DeepSeek Flash/high 跑 S01 问答、P01 字段预填两个小样。小样使用独立账本,最多 24 次调用、US$0.50;正式轮另有最多 200 次调用、US$5 的固定账本。小样不并入正式得分,不用后来的成功覆盖原来的失败。

这里使用原业务验收入口:真实 Flash、可执行合成 SQLite、词法检索和内置个人记忆路径。它没有接入当前完整栈中的 Mem0、Qwen,也仍按原题面使用显式确认接口。因此它可以与历史同题结果对照,不能据此声称完整工作台所有路径都测过。

检查本次结果能说明什么
16 场景协议检查全部通过,0 次真实模型调用固定策略可以走通受控工具和宿主链路
真实小样 S01、P01两题机器检查通过,7 次调用接线、预填采集和账本可用;内容仍有错误
正式轮 S01、S02机器检查通过S01 内容复核发现遗漏;S02 的 SQL 与解释通过复核
正式轮 S03时间条件断言失败原稿与 app 修订稿已保存,完整场景未完成
正式轮其余 13 题未运行不能计为通过,也不能据此计算内容准确率

为什么 SQL 算对了,场景仍然失败

S03 的题目是先查 1 月净收入,再补充“只看 app,其他条件保持”。模型给出了两份 SQL,也让旧稿失效、新稿等待确认,但持久条件写成了:

任务条件:2026-01-01 至 2026-01-31,timezone=UTC
SQL 参数:[2026-01-01T00:00:00Z, 2026-02-01T00:00:00Z)

原验收要求任务条件保存完整 UTC 时间戳,开始时间必须是 2026-01-01T00:00:00Z。实际为 2026-01-01,断言失败后 runner 停止了后续场景。

中止后,只读提取两份已保存 SQL,用独立 SQLite 核算器验证:全渠道为 12400 分,app 为 1600 分,两份 SQL 各五个数据变体也通过。这说明不能把本次失败简单写成“净收入算错”。问题出在任务条件与 SQL 参数采用了不同的日期表达,尚未满足原验收契约;条件结束写 1 月 31 日,SQL 的右开边界却是 2 月 1 日。

后续应核对条件字段的语义,决定怎样统一表达。本轮没有因为模型这样输出就放宽断言,也没有继续执行 S03 后面的旧版确认拒绝、新查询确认和结果解释。保存状态显示旧稿失效,并不能替这些未执行步骤算通过。

机器通过仍不等于解释正确

正式轮 S01 对成功付款、快照筛选和补零解释正确,却把“已付款的整单里能否有付款为零的商品行”说成资料未说明。加工 SQL 已分别按行补零、按整单累计金额决定状态,可以推导出这种组合在结构上允许;需要查数的是样例中是否实际存在。内容复核因此没有把 S01 算作完整通过。S02 的整月已知支付客户数为 5,SQL、匿名客户边界和七个独立数据变体则通过复核。

小样 P01 的再次预填在解释金额字段时写了:

与 order_id、line_id 一起构成主键 (order_id, line_id)

DDL 的主键只有订单号和行号,金额列不在其中。结构检查、引用检查和人工保护都通过了,这句话却仍然有错。两阶段预填完成后,最终文字仍要逐条核对。

历史测量也出现过类似差距。2026 年 10 月 5 日固定 16 场景的流程全部通过,内容复核为 12/16:把测试标记误当成零金额成因、把已经运行的查询说成待确认、遗漏税费与运费未知范围等。原报告继续保留,75% 仍只属于那一次历史测量。

本次小样加正式轮共 27 次真实调用,全部结算、未知预留为零,按配置价格估算 US$0.208708;这不是服务商账单。正式产物与当前 233 份输入的指纹一致,原始输出、失败日志和独立核算分别保留。模型、提示和验收要求没有为获得更好分数而修改。

本文的三行金额只是教学 SQL 的独立结果;模型回答、语义预填、聊天授权和页面操作各有自己的验证范围。独立答案文件不进入模型知识、索引或 Skill,未完成的测量也不能在写文章时变成一个看起来完整的分数。

第二篇会继续展开语义编辑、个人记忆提取和 Skill 采用:分别检查正式内容怎样生效,适用范围如何保留,以及改版后旧资料怎样退出下一轮上下文。四篇的阅读顺序放在系列目录。

本文实现依据固定在 Data Agent 的 f482a51 提交。架构图与产品截图来自仓库;封面、查询流程、知识召回、Skill 复用插画由 GPT Image 在此前生成,本次复用。三张实现细节图依据源码用 SVG 绘制并导出 PNG。示意编号和示例状态不冒充真实运行日志,图片中的业务资料均为合成内容。

分享这篇文章

复制链接,或分享到你常用的地方。

评论

发表评论

0 / 1000