feat(data-process): 支持思维链输出类型

This commit is contained in:
caoxiaozhu
2026-07-27 13:08:44 +08:00
parent ecafb7eb13
commit de2e8952b5
14 changed files with 443 additions and 46 deletions

View File

@@ -15,6 +15,7 @@ from app.modules.data_process.store import (
InvalidStateError,
_decode_row,
_preview_config_changed,
_reasoning_output_is_valid,
_source_storage_descriptor,
)
@@ -114,14 +115,25 @@ class _PublishConnection:
)
if normalized.startswith("INSERT INTO dataset_records"):
self.records.append(
{"dataset_id": params[1], "line_no": params[4], "split": params[5]}
{
"dataset_id": params[1],
"line_no": params[4],
"split": params[5],
"output": params[8],
"raw": json.loads(params[9]),
}
)
return _Result()
class _PublishStore(DataProcessStore):
def __init__(self, conn: _PublishConnection):
def __init__(
self,
conn: _PublishConnection,
task_config: dict[str, Any] | None = None,
):
self._conn = conn
self._task_config = task_config or {}
@contextmanager
def connect(self) -> Iterator[_PublishConnection]:
@@ -135,7 +147,7 @@ class _PublishStore(DataProcessStore):
"id": task_id,
"status": "completed",
"description": "",
"config": {},
"config": self._task_config,
"output_dataset_id": train_dataset and train_dataset["id"],
}
@@ -967,7 +979,11 @@ def test_publish_creates_three_independent_datasets_with_exact_counts() -> None:
"status": "valid",
"instruction": f"问题 {index}",
"input": "",
"output": f"答案 {index}",
"output": (
"<think>\n先读取制度条款。\n</think>\n答案 0"
if index == 0
else f"答案 {index}"
),
"preview_item_id": f"preview-{index}",
}
for index in range(28)
@@ -993,6 +1009,10 @@ def test_publish_creates_three_independent_datasets_with_exact_counts() -> None:
item["id"] for item in conn.datasets
}
assert len(conn.records) == 28
reasoning_record = next(
item for item in conn.records if item["output"].startswith("<think>")
)
assert reasoning_record["raw"]["output"] == reasoning_record["output"]
assert published["dataset"]["type"] == "train"
assert len(published["datasets"]) == 3
assert published["split_counts"] == {"train": 22, "validation": 3, "test": 3}
@@ -1078,6 +1098,49 @@ def test_publish_keeps_all_three_datasets_when_a_small_split_is_empty() -> None:
assert len(conn.files) == 3
@pytest.mark.parametrize(
("output", "expected"),
[
("<think>\n推理步骤\n</think>\n最终答案", True),
("<think></think>\n最终答案", False),
("<think>只有推理</think>", False),
("没有标签的最终答案", False),
("<think>外层<think>嵌套</think></think>答案", False),
],
)
def test_reasoning_output_validator_requires_one_complete_pair(
output: str,
expected: bool,
) -> None:
assert _reasoning_output_is_valid(output) is expected
def test_publish_rejects_invalid_reasoning_output_format() -> None:
conn = _PublishConnection(
[
{
"id": "result-reasoning-invalid",
"status": "valid",
"instruction": "需要推理的问题",
"input": "",
"output": "只有最终答案",
"preview_item_id": "preview-reasoning-invalid",
}
]
)
with pytest.raises(InvalidStateError, match="1 invalid results"):
_PublishStore(conn, {"output_type": "reasoning"}).publish(
"task-reasoning-invalid",
{
"dataset_name": "无效思维链",
"storage_type": "local",
"format": "alpaca_jsonl",
"split": {"train": 80, "validation": 10, "test": 10},
},
)
def test_source_storage_descriptor_accepts_owned_local_and_legacy_db_references() -> None:
task_id = "dpt_task"
source_file_id = "dpsf_source"