feat: 新增外部数据源拉取与 DPO 输出格式支持
- 支持从 PostgreSQL 数据库拉取结构化数据作为训练来源 - 新增 DPO (Direct Preference Optimization) 输出类型 - 支持 chosen/rejected 字段的编辑、校验和发布 - 完善数据预处理切分逻辑和元数据管理 - 移除 OCR 扫描 PDF 功能,保持基础文本解析能力 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -88,6 +88,74 @@ def test_generate_model_records_uses_prompt_auth_and_stable_split() -> None:
|
||||
assert progress_updates == [(1, 1)]
|
||||
|
||||
|
||||
def test_generate_model_records_builds_native_dpo_pair() -> None:
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
payload = json.loads(request.content)
|
||||
system_prompt = payload["messages"][0]["content"]
|
||||
assert '"chosen"' in system_prompt
|
||||
assert '"rejected"' in system_prompt
|
||||
assert "直接偏好优化" in system_prompt
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"choices": [{
|
||||
"message": {
|
||||
"content": json.dumps({
|
||||
"items": [{
|
||||
"instruction": "系统如何处理扫描 PDF?",
|
||||
"input": "",
|
||||
"chosen": "仅在没有文本层时调用 OCR,并保留页码。",
|
||||
"rejected": "所有 PDF 都重复执行 OCR。",
|
||||
}],
|
||||
}, ensure_ascii=False),
|
||||
},
|
||||
}],
|
||||
},
|
||||
)
|
||||
|
||||
records = generate_model_records(
|
||||
[{"id": "preview-dpo", "edited_content": "扫描 PDF 缺少文本层时执行 OCR。"}],
|
||||
model={"name": "model", "api_url": "https://model.example/v1"},
|
||||
config={"output_type": "dpo", "generation_retries": 0},
|
||||
task_id="task-dpo",
|
||||
split={"train": 100, "validation": 0, "test": 0},
|
||||
qa_pairs_per_item=1,
|
||||
client=httpx.Client(transport=httpx.MockTransport(handler)),
|
||||
)
|
||||
|
||||
assert records[0]["status"] == "valid"
|
||||
assert records[0]["chosen"] == "仅在没有文本层时调用 OCR,并保留页码。"
|
||||
assert records[0]["rejected"] == "所有 PDF 都重复执行 OCR。"
|
||||
assert records[0]["output"] == records[0]["chosen"]
|
||||
|
||||
|
||||
def test_generate_model_records_rejects_equal_dpo_pair() -> None:
|
||||
def handler(_request: httpx.Request) -> httpx.Response:
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={"choices": [{"message": {"content": json.dumps({
|
||||
"items": [{
|
||||
"instruction": "问题",
|
||||
"chosen": "相同回答",
|
||||
"rejected": "相同回答",
|
||||
}],
|
||||
}, ensure_ascii=False)}}]},
|
||||
)
|
||||
|
||||
records = generate_model_records(
|
||||
[{"id": "preview-dpo-invalid", "edited_content": "来源"}],
|
||||
model={"name": "model", "api_url": "https://model.example/v1"},
|
||||
config={"output_type": "dpo", "generation_retries": 0},
|
||||
task_id="task-dpo-invalid",
|
||||
split={"train": 100, "validation": 0, "test": 0},
|
||||
qa_pairs_per_item=1,
|
||||
client=httpx.Client(transport=httpx.MockTransport(handler)),
|
||||
)
|
||||
|
||||
assert records[0]["status"] == "invalid"
|
||||
assert "chosen equals rejected" in records[0]["error"]
|
||||
|
||||
|
||||
def test_minimax_m3_uses_split_reasoning_and_completion_token_budget() -> None:
|
||||
requests: list[dict[str, object]] = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user