Avoid draft files in product-data generation
This commit is contained in:
@@ -53,3 +53,15 @@ cat input.json | python skills/product-data/scripts/<tool>.py
|
||||
在 ZK Data Agent 里,前链路输入文本化和 review 状态机仍使用平台注册的 `data_agent_*` 工具;格式转换、校验和导出使用 `python_exec` 直接执行本目录 `scripts/` 下的 portable scripts。
|
||||
|
||||
通过 `python_exec` 运行时,脚本会根据 `PYTHON_EXEC_SCRATCHPAD` 自动把逻辑路径 `output/...` 路由到当前会话 output 目录。独立运行时,仍按当前目录下的 `output/` 输出。
|
||||
|
||||
大批量生成时,不要先写 `draft_part*.txt`。推荐每批最多 8 条,通过 stdin 调用 `normalize_dataset_draft.py`,并设置:
|
||||
|
||||
```json
|
||||
{
|
||||
"records_output_path": "scratchpad/normalized_records.jsonl",
|
||||
"append": true,
|
||||
"return_records": false
|
||||
}
|
||||
```
|
||||
|
||||
最后从 `scratchpad/normalized_records.jsonl` 统一校验和导出。
|
||||
|
||||
@@ -3,7 +3,7 @@ name: product-data
|
||||
description: 从产品/标签定义、手写边界规则或示例 query 中提取标签边界,并生成可 review 的数据计划、dataset draft text 和 canonical metadata records。
|
||||
when_to_use: 当用户提供产品定义、标签规则、路由边界文档、示例 query、手写标签边界,并希望生成训练/评测/专项数据时使用。
|
||||
aliases: definition-data, label-data
|
||||
allowed_tools: read_file, write_file, edit_file, grep_search, glob_search, ask_user_question, python_exec, data_agent_load_input_sources, data_agent_render_source_context, data_agent_extract_case_evidence, data_agent_prepare_generation_goal, data_agent_confirm_generation_goal, data_agent_prepare_generation_plan, data_agent_show_generation_plan, data_agent_update_generation_plan, data_agent_confirm_generation_plan
|
||||
allowed_tools: read_file, edit_file, grep_search, glob_search, ask_user_question, python_exec, data_agent_load_input_sources, data_agent_render_source_context, data_agent_extract_case_evidence, data_agent_prepare_generation_goal, data_agent_confirm_generation_goal, data_agent_prepare_generation_plan, data_agent_show_generation_plan, data_agent_update_generation_plan, data_agent_confirm_generation_plan
|
||||
---
|
||||
|
||||
使用这个 skill 作为“产品/标签定义/手写规则/示例 query -> 输入文本化 -> generation goal 草案 -> 人工 review -> 生成计划 review -> dataset draft text -> canonical metadata records”的统一入口。
|
||||
@@ -168,9 +168,9 @@ review 展示必须简短清晰,不要重复解释工具和流程。每次 rev
|
||||
8. 展示计划后停止本轮,等待用户 review。
|
||||
9. 用户提出修改意见时,调用 `data_agent_update_generation_plan`,再展示计划。
|
||||
10. 用户明确确认当前计划版本后,调用 `data_agent_confirm_generation_plan`。
|
||||
11. 生成 dataset draft text v1。
|
||||
12. 使用 `python_exec` 执行 `skills/product-data/scripts/normalize_dataset_draft.py`,必须在输入 JSON 中传入 `confirmed_plan_id`;draft 中每条 case 都必须有 `complex: true/false`。
|
||||
13. 使用 `python_exec` 执行 `skills/product-data/scripts/validate_dataset_records.py`。
|
||||
11. 分批生成 dataset draft text v1,每批最多 8 条,不要用 `write_file` 保存 `draft_part*.txt` 这类中间草稿。
|
||||
12. 每生成一批,立刻使用 `python_exec` 执行 `skills/product-data/scripts/normalize_dataset_draft.py`:通过 `stdin` 传入小批量 JSON,必须带 `confirmed_plan_id`、`records_output_path="scratchpad/normalized_records.jsonl"`、`append=true`、`return_records=false`;draft 中每条 case 都必须有 `complex: true/false`。
|
||||
13. 所有批次 normalize 完成后,使用 `python_exec` 执行 `skills/product-data/scripts/validate_dataset_records.py`,传 `records_path="scratchpad/normalized_records.jsonl"`。
|
||||
14. 如果用户要求落盘 canonical records,使用 `python_exec` 执行 `skills/product-data/scripts/export_dataset_records.py`,逻辑输出固定为 `output/records.jsonl`,默认导出紧凑 JSONL,并同时生成同目录 `records.csv` 表格,不要用 `write_file` 手写 JSON 或 CSV。
|
||||
15. 如果用户已经明确要训练数据,使用 `python_exec` 执行 `skills/product-data/scripts/export_training_jsonl.py`,优先传 `records_path`,输出固定为 `output/training.jsonl`。
|
||||
16. 如果用户已经明确要评测 planningPrompt 数据,使用 `python_exec` 执行 `skills/product-data/scripts/export_planning_eval_csv.py`,优先传 `records_path`,输出固定为 `output/eval_planning.csv`。
|
||||
@@ -178,11 +178,11 @@ review 展示必须简短清晰,不要重复解释工具和流程。每次 rev
|
||||
|
||||
生成阶段要避免一次性把大量数据塞进工具参数:
|
||||
|
||||
- 单次 `normalize_dataset_draft.py` 最多处理 8 条 case;计划数量更多时,分批生成、分批 normalize,再汇总校验和导出。
|
||||
- 单次 `normalize_dataset_draft.py` 最多处理 8 条 case;计划数量更多时,分批生成、分批 normalize 到同一个 `scratchpad/normalized_records.jsonl`,再统一校验和导出。
|
||||
- dataset draft 中的 Agent target 推荐写成单引号形式,例如 `target: Agent(tag='地图导航')`。工具会规范化为 `Agent(tag="地图导航")`,这样可以降低 tool call JSON 里双引号转义失败的概率。
|
||||
- `complex:` 独立写一行,不要写进 `target:`;工具会在导出训练数据和流转表格时自动组合成 `complex=false\nAgent(...)`。
|
||||
- 如果 draft 已经保存在文件中,优先传 `draft_path`,不要再把大段 `draft_text` 作为工具参数传入。
|
||||
- 校验和导出 records 时,如果 records 已经保存在 JSON/JSONL 文件中,优先传 `records_path`。
|
||||
- 不要调用 `write_file` 保存模型新生成的 dataset draft;只有用户已经提供 draft 文件时,才使用 `draft_path`。
|
||||
- 校验和导出 records 时,优先传 `records_path="scratchpad/normalized_records.jsonl"`,不要把大量 records 数组塞进工具参数。
|
||||
|
||||
## 数据生成输出格式
|
||||
|
||||
@@ -384,6 +384,20 @@ skills/product-data/scripts/normalize_dataset_draft.py
|
||||
|
||||
用途:把 dataset draft text v1 转成 canonical records。每条 case 推荐包含 `complex: true/false`;旧草稿缺失时会按 `false` 兼容。
|
||||
|
||||
大批量生成时必须把每批 normalize 结果追加到同一个 records 文件,避免大段 records 在模型上下文和工具参数里来回传递:
|
||||
|
||||
```json
|
||||
{
|
||||
"draft_text": "# dataset_label: 地图导航\n\n### case: ...",
|
||||
"batch_id": "map_nav_batch_01",
|
||||
"source_type": "generated",
|
||||
"confirmed_plan_id": "data_plan_000001",
|
||||
"records_output_path": "scratchpad/normalized_records.jsonl",
|
||||
"append": true,
|
||||
"return_records": false
|
||||
}
|
||||
```
|
||||
|
||||
调用方式示例:
|
||||
|
||||
```text
|
||||
@@ -502,7 +516,6 @@ skills/product-data/scripts/export_planning_eval_csv.py
|
||||
## 当前可用工具
|
||||
|
||||
- `read_file`:读取用户提供的产品定义、标签定义、样例 query 文件。
|
||||
- `write_file`:在用户确认后落盘 draft、校验结果或说明文档;不要用它手写 canonical records 文件。
|
||||
- `edit_file`:修改已有的计划、说明文档或生成结果文件。
|
||||
- `grep_search`:在项目中搜索已有标签定义、历史数据样例或相关文档。
|
||||
- `glob_search`:按路径模式查找定义文件、样例文件或历史产物。
|
||||
@@ -517,7 +530,7 @@ skills/product-data/scripts/export_planning_eval_csv.py
|
||||
- `data_agent_show_generation_plan`:用户要求查看当前计划,或继续上下文时需要恢复计划详情时使用。
|
||||
- `data_agent_update_generation_plan`:用户对计划提出修改意见后使用,更新计划并重新展示。
|
||||
- `data_agent_confirm_generation_plan`:用户明确确认当前计划版本后使用,获取 `confirmed_plan_id`。
|
||||
- `normalize_dataset_draft.py`:用户确认计划后,把 dataset draft text v1 转成 canonical records;输入 JSON 必须带 `confirmed_plan_id`;支持 `draft_text` 或 `draft_path`,大草稿优先 `draft_path`;每条 case 要写 `complex: true/false`。
|
||||
- `normalize_dataset_draft.py`:用户确认计划后,把 dataset draft text v1 转成 canonical records;输入 JSON 必须带 `confirmed_plan_id`;模型新生成的数据优先用小批量 `draft_text` 直接 stdin 输入,设置 `records_output_path`、`append=true`、`return_records=false`;只有用户已提供草稿文件时才使用 `draft_path`。
|
||||
- `validate_dataset_records.py`:对 canonical records 做结构、标签、时间戳和多轮上下文校验;支持 `records` 或 `records_path`。
|
||||
- `export_dataset_records.py`:校验 canonical records 并落盘;支持 `records` 或 `records_path`;默认写紧凑 JSONL,一行一条,固定传 `output/records.jsonl`,并同时生成 `output/records.csv` 表格,不要再用 `write_file` 手写 records 或表格文件。
|
||||
- `export_training_jsonl.py`:把 canonical records 转成训练 JSONL;支持 `records` 或 `records_path`;默认写 `output/training.jsonl`;`output` 自动包含 `complex` 行。
|
||||
|
||||
@@ -21,6 +21,20 @@
|
||||
},
|
||||
"base_timestamp": {"type": "integer"},
|
||||
"timestamp_step_ms": {"type": "integer", "minimum": 1, "default": 60000},
|
||||
"default_request_id": {"type": "string", "default": "aabbccdd"}
|
||||
"default_request_id": {"type": "string", "default": "aabbccdd"},
|
||||
"records_output_path": {
|
||||
"type": "string",
|
||||
"description": "Optional JSONL output path for normalized records. In platform runtime, scratchpad/... and output/... are routed to the current session."
|
||||
},
|
||||
"append": {
|
||||
"type": "boolean",
|
||||
"description": "Append normalized records to records_output_path instead of overwriting it.",
|
||||
"default": false
|
||||
},
|
||||
"return_records": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to include records in stdout. Prefer false when records_output_path is set for large batches.",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
"ok": {"type": "boolean"},
|
||||
"records": {"type": "array"},
|
||||
"confirmed_plan_id": {"type": "string"},
|
||||
"records_output_path": {"type": "string"},
|
||||
"record_count": {"type": "integer"},
|
||||
"warnings": {"type": "array", "items": {"type": "string"}},
|
||||
"error": {"type": "string"}
|
||||
},
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from product_data_portable import (
|
||||
DEFAULT_REQUEST_ID,
|
||||
DEFAULT_TIMESTAMP_STEP_MS,
|
||||
@@ -29,6 +31,19 @@ def main() -> int:
|
||||
timestamp_step_ms=int(payload.get("timestamp_step_ms") or DEFAULT_TIMESTAMP_STEP_MS),
|
||||
default_request_id=str(payload.get("default_request_id") or DEFAULT_REQUEST_ID),
|
||||
)
|
||||
records_output_path = str(payload.get("records_output_path") or "").strip()
|
||||
return_records = bool(payload.get("return_records", not records_output_path))
|
||||
if records_output_path:
|
||||
output_path = resolve_portable_path(records_output_path)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
mode = "a" if bool(payload.get("append", False)) else "w"
|
||||
with output_path.open(mode, encoding="utf-8") as fh:
|
||||
for record in result["records"]:
|
||||
fh.write(json.dumps(record, ensure_ascii=False, separators=(",", ":")) + "\n")
|
||||
result["records_output_path"] = str(output_path)
|
||||
result["record_count"] = len(result["records"])
|
||||
if not return_records:
|
||||
result.pop("records", None)
|
||||
if confirmed_plan_id:
|
||||
result["confirmed_plan_id"] = confirmed_plan_id
|
||||
emit_success(result)
|
||||
|
||||
@@ -1601,8 +1601,11 @@ class LocalCodingAgent:
|
||||
f'工具:{name};位置:line {exc.lineno} column {exc.colno};'
|
||||
f'原因:{exc.msg};参数片段:{preview!r}。'
|
||||
'请回复“继续”,我会要求模型重新生成合法 JSON 参数;'
|
||||
'对于大段 dataset draft,应分批或使用 draft_path/records_path,'
|
||||
'不要把大量带引号的文本一次性塞进工具参数。'
|
||||
'对于 product-data 生成数据,不要用 write_file 写大段 draft;'
|
||||
'应每批最多 8 条,直接用 python_exec 调用 '
|
||||
'skills/product-data/scripts/normalize_dataset_draft.py,'
|
||||
'通过 stdin 传入小批量 JSON,并把 normalize 结果追加到 '
|
||||
'scratchpad/normalized_records.jsonl。'
|
||||
) from exc
|
||||
if not isinstance(arguments, dict):
|
||||
raise OpenAICompatError(
|
||||
|
||||
Reference in New Issue
Block a user