diff --git a/README.md b/README.md index 431e6e76..d8fb29de 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,11 @@ flowchart LR | 环节 | 做法 | |---|---| | 起草 | 探查时读外键和唯一约束;按 `xxx_id`、`xxxId` 推断关联,表名带业务前缀的也认;可选让模型起草中文名、粒度、表类型、业务主键、业务日期和每列的含义、单位、度量类型。导入表格的源已有系统按核对结果生成的说明,目录不重复、不改写它 | -| 模型起草 | 作为后台任务逐表进行,每张表记下状态和原因,写完一张就并入目录;关掉对话框不停,可以停止、只重试失败的表,清单上标出上次起草失败或只完成一部分的表。服务重启时没跑完的任务标成中断,不会自己续跑,点重试接上。保留模型的思考,输出额度 32768(服务方不收时退回 8192);每次调用最多 40 列,宽表先起草表级的项、再把列均分成几段起草,按表的先后排队,不插到窄表前面;额度用完或超时就拆小再问(超时的两半同时问,拆到每段 10 列仍接连超时就不再拆),累计两次后新开始的段减半(最低 10 列),每段连同它分开、拆小的各块最多调用 8 次,缺的表和列只补问缺的,被截断的回复先留下已经写完整的部分;最近 6 次调用有 4 次没写出来时提醒换模型。没写出来的原因写清是第几段、哪几列。重新起草时模型这次留空或没通过校验的项不删以前起草的;模型拿不准、留空的列(目录里还没有中文名和含义的)逐表记下,可以补充起草要求后重起草。库注释就是表名、列名本身或者是标识符写法的,不记进目录(不当中文名,也不当说明、含义)。数据源上存的「起草要求」和这次的补充说明一起交给模型,帮它理解业务、统一用词,不能推翻「只记数据事实」的规矩,交回的内容照样逐项校验。用哪个模型在「设置 → 偏好设置」的「起草模型」里选,空着跟随助手的模型;按配方导入表格的 AI 起草也用它 | +| 模型起草 | 作为后台任务逐表进行,每张表记下状态和原因,写完一张就并入目录,宽表每写完一段就并入;关掉对话框不停,可以停止、只重试失败的表,清单上标出上次起草失败或只完成一部分的表。停止、服务重启时已经写进目录的段保留;服务重启时没跑完的任务标成中断,不会自己续跑,点重试重新起草这些表(已写进的不会丢)。不设总时长上限,靠止损和手动停止:最近 10 次调用有 7 次没写出来时后面的段不再拆小,同一张表接连 3 段都没写出来就跳过它剩下的段。保留模型的思考,输出额度 32768(服务方不收时退回 8192);每次调用最多 40 列,宽表先起草表级的项、再把列均分成几段起草,按表的先后排队,不插到窄表前面;额度用完或超时就拆小再问(超时的两半同时问,拆到每段 10 列仍接连超时就不再拆),累计两次后新开始的段减半(最低 10 列),每段连同它分开、拆小的各块最多调用 8 次,进度上看得到段被分成了几块,缺的表和列只补问缺的,被截断的回复先留下已经写完整的部分;最近 6 次调用有 4 次没写出来时提醒换模型。没写出来的原因写清是第几段、哪几列,「已拆小重试」只跟在真拆过的段后面。同步起草和后台任务互斥。重新起草时模型这次留空或没通过校验的项不删以前起草的;模型拿不准、留空的列(目录里还没有中文名和含义的)逐表记下,可以补充起草要求后重起草。库注释就是表名、列名本身或者是标识符写法的,不记进目录(不当中文名,也不当说明、含义)。数据源上存的「起草要求」和这次的补充说明一起交给模型,帮它理解业务、统一用词,不能推翻「只记数据事实」的规矩,交回的内容照样逐项校验。用哪个模型在「设置 → 偏好设置」的「起草模型」里选,空着跟随助手的模型;按配方导入表格的 AI 起草也用它 | +| 防错事实的提议 | 模型起草时另提议「有效记录条件」(一段 SQL 条件)和「去重规则」,各带依据;开了剖析的源把目录里的码值一起交给模型(遮罩列不给)。条件按数据源方言用 sqlglot 解析,只能引用这张表的列,不能有子查询、聚合、窗口函数,只允许几个常用函数,不过就不收(逐表说明里写原因);开了剖析的源上经只读守卫数出排除比例,排除 0% 或 100% 的不收,收下的在说明里写「剖析核对:排除 x% 的行」。这些都记为推断,SQL 检查的错误级规则只认人确认过的,提议在审阅队列里排在前面 | +| 审阅队列 | 只列推断的项,按「表被运行用到的次数 × 这一项多影响数字 × 来源」排序:有效记录条件、去重规则、业务日期、关联关系最前,业务主键、度量类型次之,中文名、含义、单位靠后,每项写明排在这里的理由;按类别和表筛选,多选批量确认、驳回或撤销审阅(逐表乐观锁,冲突逐条标出);看得到一张表被哪些运行用过,以及常用表、全部和影响数字的项各确认了多少 | +| 表助手 | 表详情页里和助手对话完善这一张表:它看得到表结构、目录现状(每项的来源和状态)、关联关系、剖析结果、起草要求和上次起草留空的列(遮罩列只给列名),按你的指示成批提出修改,每项带改前、改后和依据(照目录的校验:公式不收、列名要在表结构里),拿不准的会反过来问你;只在开了剖析的源上经只读守卫跑查询核实(每次请求最多 5 条,结果先遮)。提案攒在「待保存的修改」里,确认后一次保存(一次最多 200 项),记为人工确认。对话不存服务端,只改目录、不碰业务库 | +| 导出与导入 | 导出成一个 JSON 文件(全部表的目录、各项状态和起草要求),在另一个实例或数据源上导入:先预览哪些表、列对得上,每一项会新增、更新还是保留,冲突和跳过的逐条列出;人确认、驳回过的项照带,目标里已经确认过而值不同的保留目标、记成冲突,文件里推断的项只填空缺,表结构里没有的列跳过并写原因;有起草在进行时不能导入。起草要求只在目标没有时写入 | | 数据剖析 | 默认关闭,按数据源开启。只读、经过守卫,单条查询和整次剖析都有上限,大表用统计信息估算行数,遮罩的列不取样。抽样核实推断出的关联,补上覆盖率和基数,站得住的升为已验证;状态列给出码值候选,含义等人填写 | | 对话里纠正 | 用户说「status=9 表示作废」,助手给出一条目录修改提案,列出改前、改后和理由,人确认后才保存;公式不收,留给口径卡 | | 版本与提醒 | 目录随表结构快照冻结进证据,每次运行用的是哪一版查得到。发布时记下模板引用的表的目录版本,正式运行时目录有变化就提醒;agent 运行时才写 SQL 的,按「可能涉及」单独提醒。只提醒,不拦运行 | diff --git a/frontend/src/pages/catalog/DraftDialog.tsx b/frontend/src/pages/catalog/DraftDialog.tsx index d9970f06..2e5b71c2 100644 --- a/frontend/src/pages/catalog/DraftDialog.tsx +++ b/frontend/src/pages/catalog/DraftDialog.tsx @@ -543,6 +543,8 @@ function TaskRow({ task: t, jobError }: { task: CatalogDraftTask; jobError: stri const changes = DT.taskAdded(t.added, t.updated) const blank = blankOf(t) const sample = t.blank_sample?.filter(Boolean) ?? [] + // 起草时记下的几句话(服务端原话,不算失败):没收下的有效记录条件和原因,照原样列在这张表下面 + const notes = t.log?.filter(Boolean) ?? [] return (
{DT.blank(blank)}
)} + {notes.map((line, i) => ( +{line}
+ ))} ) } diff --git a/frontend/src/types.ts b/frontend/src/types.ts index ce384f4e..c1b8f6f8 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -2911,6 +2911,11 @@ export interface CatalogDraftTask { blank_columns?: number /** 留空的列里的前几个(最多 5 个,列名照表结构原样)。老服务端没有这个键 */ blank_sample?: string[] + /** + * 这张表起草时记下的几句话(服务端整句中文,不算失败),比如模型提议的有效记录条件没有收下的原因。最多 10 句; + * 老服务端没有这个键 + */ + log?: string[] /** 整张表没起草的原因:表结构里没有、写入一直冲突、服务重启中断 */ error: string | null /** 模型那部分没写出来的原因和办法(第几段、哪些列、为什么) */ diff --git a/scripts/check-catalog.mjs b/scripts/check-catalog.mjs index d39059b3..371a0eb0 100644 --- a/scripts/check-catalog.mjs +++ b/scripts/check-catalog.mjs @@ -1589,6 +1589,12 @@ await section('数据目录 · 起草:逐段写进目录、块进度与停止 check('……接着写:「已写进目录 2 段」「2 / 3 段」「4 / 5 块」', await until(async () => (await text('store_sales', '[data-draft-task-written]')) === '已写进目录 2 段') && (await text('store_sales', '[data-draft-task-parts]')) === '2 / 3 段' && (await text('store_sales', '[data-draft-task-chunks]')) === '4 / 5 块') check('……还没开始的表不写段进度、块进度、已写进目录', await task('members').locator('[data-draft-task-parts], [data-draft-task-chunks], [data-draft-task-written]').count() === 0) + // 起草时记下的几句话(服务端原话):没收下的有效记录条件和原因,列在这张表下面,不算失败 + settle(state, job, 'store_sales', { status: 'running', parts_done: 2, parts_written: 2, chunks_total: 5, chunks_done: 4, + log: ['有效记录条件按剖析核对排除了全部行(共 1,200 行),模型提议的这一条没有收下:status <> 9'] }) + check('……起草时记下的说明(没收下的有效记录条件)照原话列在这张表下面', await until(async () => (await text('store_sales', '[data-draft-task-log]')).includes('模型提议的这一条没有收下:status <> 9')), + await text('store_sales', '[data-draft-task-log]')) + check('……没有说明的表不写这一行', await task('members').locator('[data-draft-task-log]').count() === 0) await shot(page, 'catalog-draft-chunks') // 停止:已写进的段保留。说法照服务端:写过段的表记已停止,原因写已写进几段、剩下几段没起草