From 8fab6c41d93af258351a76c8701bc5908ec528cf Mon Sep 17 00:00:00 2001 From: chamsechan Date: Sun, 20 Sep 2026 17:30:13 +0800 Subject: [PATCH 1/2] refactor(demo): provide execution settings solely via profile (RFC-0063) --- demo/common/demo_options.cpp | 140 ++++--------- demo/common/demo_options.h | 39 ++-- demo/common/demo_profile_defaults.h | 13 ++ demo/json_prompt_demo.py | 1 - demo/main.cpp | 10 +- demo/profiles.json | 8 +- demo/profiles_kite.json | 14 +- doc/CHANGELOG.md | 9 + doc/VERIFIABLE_SELECTION.md | 2 +- doc/dev_guide/business_onboarding.md | 4 + doc/dev_guide/operator_output_allocation.md | 4 +- doc/rfcs/0063-demo-profile-only-tuning.md | 47 +++++ doc/rfcs/README.md | 1 + output/pipeline_associated/demo-profile.json | 14 ++ .../pipeline_doc_qa_assoc/demo-profile.json | 14 ++ output/pipeline_fixture/demo-profile.json | 14 ++ output/pipeline_paired/demo-profile.json | 14 ++ output/pipeline_replaced/demo-profile.json | 14 ++ output/pipeline_restart/demo-profile.json | 14 ++ output/pipeline_revision/demo-profile.json | 14 ++ output/pipeline_rollback/demo-profile.json | 14 ++ output/pipeline_targets/demo-profile.json | 14 ++ src/tools/alg_pipeline_tool.cpp | 65 +++--- tests/integration/demo/test_demo_runner.cpp | 189 +++++++++--------- tests/tooling/test_pipeline_studio.py | 14 +- tools/pipeline_studio/README.md | 13 +- tools/pipeline_studio/server.py | 60 +++--- tools/verify_selection.py | 3 +- 28 files changed, 433 insertions(+), 329 deletions(-) create mode 100644 demo/common/demo_profile_defaults.h create mode 100644 doc/rfcs/0063-demo-profile-only-tuning.md create mode 100644 output/pipeline_associated/demo-profile.json create mode 100644 output/pipeline_doc_qa_assoc/demo-profile.json create mode 100644 output/pipeline_fixture/demo-profile.json create mode 100644 output/pipeline_paired/demo-profile.json create mode 100644 output/pipeline_replaced/demo-profile.json create mode 100644 output/pipeline_restart/demo-profile.json create mode 100644 output/pipeline_revision/demo-profile.json create mode 100644 output/pipeline_rollback/demo-profile.json create mode 100644 output/pipeline_targets/demo-profile.json diff --git a/demo/common/demo_options.cpp b/demo/common/demo_options.cpp index 0b940859..9531b1a0 100644 --- a/demo/common/demo_options.cpp +++ b/demo/common/demo_options.cpp @@ -60,19 +60,19 @@ bool ParseComputePlatform(const std::string& chip_str, if (lower == "ax650") { *out_type = ComputePlatform::kAx650; return true; - } else if (lower == "ascend310p" || lower == "ascend_310p") { + } else if (lower == "ascend310p") { *out_type = ComputePlatform::kAscend310P; return true; - } else if (lower == "ascend910b" || lower == "ascend_910b") { + } else if (lower == "ascend910b") { *out_type = ComputePlatform::kAscend910B; return true; } else if (lower == "rk3588") { *out_type = ComputePlatform::kRk3588; return true; - } else if (lower == "cuda" || lower == "nvidia_gpu" || lower == "nvidiagpu") { + } else if (lower == "cuda") { *out_type = ComputePlatform::kCuda; return true; - } else if (lower == "cpu" || lower == "cpu_generic") { + } else if (lower == "cpu") { *out_type = ComputePlatform::kCpu; return true; } @@ -152,68 +152,6 @@ int ParseCommandLine(int argc, char* argv[], DemoOptions* out_options, return 2; } out_options->output_dir = argv[++i]; - out_options->has_output_dir = true; - } else if (arg == "--batch-size") { - if (i + 1 >= argc) { - if (error_msg) *error_msg = "Missing value for argument: " + arg; - return 2; - } - int64_t val = 0; - if (!ParseStrictInt64(argv[++i], &val) || val <= 0 || val > 100000) { - if (error_msg) { - *error_msg = "Invalid integer for --batch-size: '" + - std::string(argv[i]) + "' (Must be integer 1..100000)"; - } - return 2; - } - out_options->batch_size = static_cast(val); - out_options->has_batch_size = true; - } else if (arg == "--device-id") { - if (i + 1 >= argc) { - if (error_msg) *error_msg = "Missing value for argument: " + arg; - return 2; - } - int64_t val = 0; - if (!ParseStrictInt64(argv[++i], &val) || val < 0 || val > 1024) { - if (error_msg) { - *error_msg = "Invalid integer for --device-id: '" + - std::string(argv[i]) + "' (Must be integer 0..1024)"; - } - return 2; - } - out_options->device_id = static_cast(val); - out_options->has_device_id = true; - } else if (arg == "--chip") { - if (i + 1 >= argc) { - if (error_msg) *error_msg = "Missing value for argument: " + arg; - return 2; - } - out_options->chip = argv[++i]; - ComputePlatform dummy; - if (!ParseComputePlatform(out_options->chip, &dummy)) { - if (error_msg) { - *error_msg = "Unsupported chip type: '" + out_options->chip + - "'. Allowed: ax650, ascend310p, ascend910b, rk3588, " - "cuda, cpu"; - } - return 2; - } - out_options->has_chip = true; - } else if (arg == "--depth") { - if (i + 1 >= argc) { - if (error_msg) *error_msg = "Missing value for argument: " + arg; - return 2; - } - int64_t val = 0; - if (!ParseStrictInt64(argv[++i], &val) || val <= 0 || val > 100000) { - if (error_msg) { - *error_msg = "Invalid integer for --depth: '" + std::string(argv[i]) + - "' (Must be integer 1..100000)"; - } - return 2; - } - out_options->depth_num = static_cast(val); - out_options->has_depth_num = true; } else if (arg == "--control-cmd") { int64_t value = 0; if (i + 1 >= argc || !ParseStrictInt64(argv[++i], &value) || value <= 0 || @@ -440,32 +378,15 @@ int LoadAndValidateProfilesDocument(const std::string& profiles_path, return 0; } -int GetProfilesForSuite(const std::string& profiles_path, - const std::string& suite_name, - std::vector* out_profiles, - std::string* error_msg) { - if (!out_profiles) { - if (error_msg) *error_msg = "Null out_profiles pointer"; - return 3; - } - out_profiles->clear(); - - nlohmann::json root; - int ret = LoadAndValidateProfilesDocument(profiles_path, &root, error_msg); - if (ret != 0) { - return ret; - } - - const auto& profiles = root["profiles"]; - for (const auto& [name, p] : profiles.items()) { - std::string s = - p.contains("suite") ? p["suite"].get() : "smoke"; - if (suite_name == "all" || s == suite_name) { - out_profiles->push_back(name); +std::vector SelectProfilesForSuite(const nlohmann::json& root, + const std::string& suite_name) { + std::vector profiles; + for (const auto& [name, profile] : root["profiles"].items()) { + if (suite_name == "all" || profile.value("suite", "smoke") == suite_name) { + profiles.push_back(name); } } - - return 0; + return profiles; } int LoadAndMergeProfiles(const std::string& profiles_path, @@ -489,6 +410,17 @@ int LoadAndMergeProfiles(const std::string& profiles_path, return ret; } + return MergeProfileOptions(root, cli_options, out_options, error_msg); +} + +int MergeProfileOptions(const nlohmann::json& root, + const DemoOptions& cli_options, + DemoOptions* out_options, std::string* error_msg) { + if (!out_options) { + if (error_msg) *error_msg = "Null out_options pointer"; + return 3; + } + *out_options = cli_options; const auto& profiles = root["profiles"]; if (!profiles.contains(cli_options.profile)) { if (error_msg) { @@ -523,16 +455,16 @@ int LoadAndMergeProfiles(const std::string& profiles_path, if (p.contains("suite") && !cli_options.has_suite) { out_options->suite = p["suite"].get(); } - if (p.contains("batch_size") && !cli_options.has_batch_size) { + if (p.contains("batch_size")) { out_options->batch_size = static_cast(p["batch_size"].get()); } - if (p.contains("device_id") && !cli_options.has_device_id) { + if (p.contains("device_id")) { out_options->device_id = static_cast(p["device_id"].get()); } - if (p.contains("chip") && !cli_options.has_chip) { + if (p.contains("chip")) { out_options->chip = p["chip"].get(); } - if (p.contains("depth") && !cli_options.has_depth_num) { + if (p.contains("depth")) { out_options->depth_num = static_cast(p["depth"].get()); } if (p.contains("control_file") && !cli_options.has_control_file) { @@ -558,6 +490,8 @@ void PrintHelp(const char* program_name) { std::cout << "Usage: " << program_name << " [options]\n\n" << "Profile & Suite Options:\n" + << " --profiles-file Profile document (default: " + "demo/profiles.json)\n" << " -p, --profile Run with a pre-configured profile\n" << " --suite Run an entire suite of profiles\n" << " -l, --list List all available biz cases and " @@ -569,18 +503,7 @@ void PrintHelp(const char* program_name) { << " -d, --dataset Business dataset path\n" << " -o, --output-dir Results output directory (default: " "./results)\n\n" - << "Execution Tuning Options:\n" - << " --batch-size Max batch size for Operator execution " - "(default: 1)\n" - << " --device-id Target hardware device ID (default: 0)\n" - << " --profiles-file Profile document (default: " - "demo/profiles.json)\n" - << " --chip Compute platform name (ax650, " - "ascend310p, " - "ascend910b,\n" - << " rk3588, cuda, cpu)\n" - << " --depth Output descriptor depth count (default: " - "1)\n" + << "Runtime Control & Output Options:\n" << " --example-control Apply the built-in Demo example update " "(keyword_match)\n" << " --control-file Runtime control parameters JSON file\n" @@ -590,6 +513,11 @@ void PrintHelp(const char* program_name) { << " --allow-fallback-sample Allow using fallback inline samples if " "dataset is missing\n" << " -h, --help Display this help message\n\n" + << "Execution settings are read only from Profile JSON: " + "chip, device_id, batch_size, depth.\n" + << "Defaults without Profile values: " << alg_demo::kDemoChip << ", " + << alg_demo::kDemoDeviceId << ", " << alg_demo::kDemoBatchSize << ", " + << alg_demo::kDemoDepth << ".\n" << std::endl; } diff --git a/demo/common/demo_options.h b/demo/common/demo_options.h index 0875515c..e0c0a7ff 100644 --- a/demo/common/demo_options.h +++ b/demo/common/demo_options.h @@ -6,6 +6,7 @@ #include #include +#include "demo/common/demo_profile_defaults.h" #include "edgeflow/operator/interface.h" #include "nlohmann/json.hpp" @@ -30,10 +31,12 @@ struct DemoOptions { std::string dataset_path; // 业务测试集文件路径 std::string output_dir = "./results"; // 结果输出根目录 - int batch_size = 1; // 最大批大小 (支持按批分块分发) - int device_id = 0; // 设备 ID - std::string chip = "cpu"; // 计算平台芯片类型字符串 (受严格白名单校验) - uint32_t depth_num = 1; // 输出结构体预分配深度 + // Execution settings are configured only by Profile JSON (or defaults). + int batch_size = alg_demo::kDemoBatchSize; // 最大批大小 (支持按批分块分发) + int device_id = alg_demo::kDemoDeviceId; // 设备 ID + std::string chip = alg_demo::kDemoChip; // 计算平台芯片类型字符串 + // (受严格白名单校验) + uint32_t depth_num = alg_demo::kDemoDepth; // 输出结构体预分配深度 std::optional control_file; // 运行时 Control JSON 文件路径 std::optional control_cmd; // 节点命令 ID;必须配合 control_file @@ -50,11 +53,6 @@ struct DemoOptions { bool has_biz = false; bool has_config_path = false; bool has_dataset_path = false; - bool has_output_dir = false; - bool has_batch_size = false; - bool has_device_id = false; - bool has_chip = false; - bool has_depth_num = false; bool has_control_file = false; bool has_control_cmd = false; bool has_suite = false; @@ -94,9 +92,17 @@ int LoadAndValidateProfilesDocument(const std::string& profiles_path, nlohmann::json* out_root, std::string* error_msg); +// Select and merge only documents returned by LoadAndValidateProfilesDocument. +// These operations reuse the same validated snapshot without reopening files. +std::vector SelectProfilesForSuite(const nlohmann::json& root, + const std::string& suite_name); +int MergeProfileOptions(const nlohmann::json& root, + const DemoOptions& cli_options, + DemoOptions* out_options, std::string* error_msg); + /** * @brief 从 demo/profiles.json 读取并与 CLI 参数进行合并 - * 优先级: 命令行显式参数 > Profile 配置 > 默认值 + * 执行参数仅从 Profile 读取;其余参数优先级: CLI > Profile > 默认值 * @param profiles_path profiles.json 路径 * @param cli_options 命令行选项 * @param out_options 合并后的最终选项 @@ -107,19 +113,6 @@ int LoadAndMergeProfiles(const std::string& profiles_path, const DemoOptions& cli_options, DemoOptions* out_options, std::string* error_msg); -/** - * @brief 根据套件名称获取满足条件的 Profile 名称列表 - * @param profiles_path profiles.json 路径 - * @param suite_name 套件名 ("smoke", "real", "all") - * @param out_profiles 输出 Profile 标识列表 - * @param error_msg 错误输出信息 - * @return 0 成功, 非 0 错误码 (3: 格式或配置错误) - */ -int GetProfilesForSuite(const std::string& profiles_path, - const std::string& suite_name, - std::vector* out_profiles, - std::string* error_msg); - /** * @brief 打印 Demo CLI 帮助信息 * @param program_name 应用程序名称 diff --git a/demo/common/demo_profile_defaults.h b/demo/common/demo_profile_defaults.h new file mode 100644 index 00000000..00c93522 --- /dev/null +++ b/demo/common/demo_profile_defaults.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace alg_demo { + +// Shared Demo/Profile defaults for the executable and tooling projections. +inline constexpr int kDemoBatchSize = 1; +inline constexpr int kDemoDeviceId = 0; +inline constexpr char kDemoChip[] = "cpu"; +inline constexpr uint32_t kDemoDepth = 1; + +} // namespace alg_demo diff --git a/demo/json_prompt_demo.py b/demo/json_prompt_demo.py index 1d1e1962..1aaecc5f 100644 --- a/demo/json_prompt_demo.py +++ b/demo/json_prompt_demo.py @@ -62,7 +62,6 @@ def _run_demo_impl(requests, config, biz, work_dir, executable): command = [ str(executable), "--biz", biz, "--config", str(config), "--dataset", str(dataset), "--output-dir", str(output_dir), - "--batch-size", "1", "--chip", "cpu_generic", ] # Keep native diagnostic output out of the JSON string response stream. with (work_dir / "demo.log").open("w", encoding="utf-8") as log: diff --git a/demo/main.cpp b/demo/main.cpp index e76e1e58..62d5b002 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -58,16 +58,17 @@ void ListProfilesAndBizs(const std::string& profiles_file) { } int RunSuite(const std::string& suite_name, const DemoOptions& base_cli_opts) { - std::vector target_profiles; + nlohmann::json profiles; std::string err; - int ret = GetProfilesForSuite(base_cli_opts.profiles_file, suite_name, - &target_profiles, &err); + int ret = LoadAndValidateProfilesDocument(base_cli_opts.profiles_file, + &profiles, &err); if (ret != 0) { std::cerr << "[Main ERROR] Failed to load suite '" << suite_name << "': " << err << std::endl; return ret; } + const auto target_profiles = SelectProfilesForSuite(profiles, suite_name); if (target_profiles.empty()) { std::cerr << "[Main WARN] No profiles found matching suite: " << suite_name << std::endl; @@ -87,8 +88,7 @@ int RunSuite(const std::string& suite_name, const DemoOptions& base_cli_opts) { cli_opt.has_profile = true; DemoOptions merged_opt; - ret = - LoadAndMergeProfiles(cli_opt.profiles_file, cli_opt, &merged_opt, &err); + ret = MergeProfileOptions(profiles, cli_opt, &merged_opt, &err); if (ret != 0) { std::cerr << "[Main ERROR] Failed to load profile '" << prof << "': " << err << std::endl; diff --git a/demo/profiles.json b/demo/profiles.json index d9c5abd5..35dfb770 100644 --- a/demo/profiles.json +++ b/demo/profiles.json @@ -18,7 +18,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "keyword_match_rules": { @@ -48,7 +48,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "doc_qa_rerank_mock": { @@ -68,7 +68,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "dialogue_audit_mock": { @@ -118,7 +118,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "entity_extract_custom_mock": { diff --git a/demo/profiles_kite.json b/demo/profiles_kite.json index c1a28838..74ef0b6e 100644 --- a/demo/profiles_kite.json +++ b/demo/profiles_kite.json @@ -8,7 +8,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "doc_qa_kite": { @@ -18,7 +18,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "doc_qa_rerank_kite": { @@ -28,7 +28,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "dialogue_audit_kite": { @@ -38,7 +38,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "ocr_doc_qa_kite": { @@ -48,7 +48,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "keyword_match_rules": { @@ -68,7 +68,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 }, "doc_qa_kite_embeddings": { @@ -78,7 +78,7 @@ "suite": "real", "batch_size": 1, "device_id": 0, - "chip": "cpu_generic", + "chip": "cpu", "depth": 1 } } diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 48d91528..d8fbdbed 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 2026-09-20 Demo 执行参数收敛至 Profile(RFC-0063) + +- 删除 Demo 的 `--chip`、`--device-id`、`--batch-size`、`--depth` 及 CLI 覆盖标记;旧参数返回未知选项错误。 +- 四项设置仅由 Profile JSON 提供,未配置时保留 `cpu`、`0`、`1`、`1` 默认值;Profile schema 与 SDK 接口保持不变。 +- Studio 将运行设置保存为 Profile 后调用 Demo;同步迁移 JSON Prompt、效果验证工具及运行文档。 +- 删除无用输出目录标记和 Studio 重复配置参数;Demo 与 Catalog 共享默认值,Studio 保留 Profile 缺省字段,使用单个运行 Profile 文件,删除哈希快照与默认值查询协议。 +- Suite 与 Catalog 列举复用一次加载的 Profile;工具和 Studio 统一复用原生 `.conf` 解析,删除项目根目录同名文件回退。 +- 删除 `output_pool` 旧字段、Studio 内存状态旧字段回退和 Demo 平台别名;输出统一用 `output_pools`,仓内 Profile 平台名统一为规范名称。 + ## 2026-09-17 Integration 部署解析入口统一实施(RFC-0062) - **统一共享部署准备流程(`PrepareDeploymentDocument`)**: diff --git a/doc/VERIFIABLE_SELECTION.md b/doc/VERIFIABLE_SELECTION.md index b789c746..175f3e6e 100644 --- a/doc/VERIFIABLE_SELECTION.md +++ b/doc/VERIFIABLE_SELECTION.md @@ -28,7 +28,7 @@ Pipeline JSON 根对象的 `deployment.model_paths` 可覆盖 `models` 中的权 `--root` 是部署根目录,默认当前目录;`--depth` 与 Demo 的 batch size、depth 两者最大值 一致,省略时为 Operator 默认值 25。响应中的 `model_paths` 标明每个模型路径的来源与 -解析结果,`effective_pipeline` 包含 Node/Model/Backend 默认值,`output_pool` 给出容量。 +解析结果,`effective_pipeline` 包含 Node/Model/Backend 默认值,`output_pools` 按逻辑槽位给出容量。 非法部署字段、输出池容量和 Pipeline 会直接报错。此命令不加载权重,不证明业务效果。 Studio 的“另存为可运行方案”和“运行草稿”共用配置生成与原生预检,按当前模型选择重建 diff --git a/doc/dev_guide/business_onboarding.md b/doc/dev_guide/business_onboarding.md index b7eaa07f..76f3f480 100644 --- a/doc/dev_guide/business_onboarding.md +++ b/doc/dev_guide/business_onboarding.md @@ -141,6 +141,10 @@ JSON 请求是不同的输入约定。已有 Nodes 能完成算法,也不代 `.conf` 仅作为定位文件,包含单一字段 `pipe_path`,相对 `.conf` 所在目录解析(例如在 `configs/pipeline_keyword_match_rules.conf` 中填写 `pipeline_keyword_match_rules.json`)。宿主直接调用 Operator 时,部署根为 Create 的 `model_path`;同时在 Pipeline JSON 的 `deployment` 中核对 `model_paths` 覆盖与 `io.output_allocations` 输出容量。Profile 不会自动指向新方案,详细命令见[运行当前方案](../../tools/pipeline_studio/README.md#运行当前方案)。 +Demo 的 `chip`、`device_id`、`batch_size`、`depth` 只从 Profile JSON 读取;对应 CLI +选项已删除。使用 `--profiles-file --profile ` 选择自有配置。未选 Profile +或未提供字段时使用 `cpu`、`0`、`1`、`1`。业务、配置路径、数据集等其他 CLI 覆盖仍有效。 + ## 6. 输出容量与生命周期 宿主输入是借用视图,底层字符串、数组和结构体必须保持有效直到 `Process` 返回。 diff --git a/doc/dev_guide/operator_output_allocation.md b/doc/dev_guide/operator_output_allocation.md index 9cfa500c..b6b8432e 100644 --- a/doc/dev_guide/operator_output_allocation.md +++ b/doc/dev_guide/operator_output_allocation.md @@ -142,7 +142,7 @@ binding.normalize_parameters = `alg_pipeline_tool resolve-conf` 在 `configuration.output_pools` 按逻辑槽位展示有效 方案与框架容量,`params` 是交给结构体解析函数的**字符串**(例如 -`"{\"kind\":1,\"capacity\":8}"`),不包含该解析函数内部补齐的默认值。单输出还保留 -相同内容的 `output_pool`。现有 Demo/Studio Profile 使用原单输出 +`"{\"kind\":1,\"capacity\":8}"`),不包含该解析函数内部补齐的默认值。单输出同样通过 `output_pools` 按槽位读取。 +现有 Demo/Studio Profile 使用原单输出 业务;新多输出业务由其宿主调用或相应 Demo 扩展验证。公开 C ABI 的输出契约不受 Operator 方案选择影响;若新增 C ABI 动态输出,应另外定义完整的缓冲区所有权契约。 diff --git a/doc/rfcs/0063-demo-profile-only-tuning.md b/doc/rfcs/0063-demo-profile-only-tuning.md new file mode 100644 index 00000000..6f157b3b --- /dev/null +++ b/doc/rfcs/0063-demo-profile-only-tuning.md @@ -0,0 +1,47 @@ +# RFC 0063: Demo 执行参数仅由 Profile 提供 + +- **RFC 编号**:0063-demo-profile-only-tuning +- **创建日期**:2026-09-20 +- **文档状态**:Completed +- **关联分支**:`refactor/demo-profile-only-tuning` +- **目标版本**:当前开发版本 +- **负责人 / 作者**:LLM-EdgeFlow maintainers +- **关联决策**:局部取代 RFC-0005 §6.2–6.3 的四项执行参数 CLI 与覆盖规则。 + +## 1. 范围与决策 + +删除 Demo 的 `--chip`、`--device-id`、`--batch-size`、`--depth` 及覆盖标记; +旧参数返回退出码 2。Profile 保留原校验,缺省值为 `cpu / 0 / 1 / 1`。 +其他 CLI 覆盖、SDK 接口、Pipeline schema、批次分块与输出池语义不变。 + +删除无消费者的 `has_output_dir` 和 Suite 文件读取包装函数;Suite 在一次校验后的文档上 +选择、合并。Catalog 列举也只读取一次 Profile。C++ 默认值由 Demo 公共辅助头拥有; +Studio 只复制显式执行字段,预检直接按 batch/depth 缺省 1 计算,不增加默认值查询协议。 +工具使用 `DeploymentIoConfig`,Studio 使用已有 `resolve-conf` 的 `pipeline_path`, +删除项目根目录同名文件回退;SDK 业务绑定与容量校验保留。 + +## 2. 兼容与迁移 + +调用方使用 `--profiles-file --profile `;工具缺省平台从 `ax650` 统一为 `cpu`。 +Studio 在输出目录写入 `demo-profile.json`,只包含业务、配置、数据集和显式执行字段, +不复制 Control。每次保存更新此文件,生成命令读取最新配置;不维护哈希快照或版本冲突协议。 +临时任务结束清理 Profile;持久命令需保留输出目录中的 Profile 文件。 +JSON Prompt 和效果验证工具删除与默认值等价的 CLI 参数。原生 `resolve-conf --depth` 保留。 +相对 `pipe_path` 基于 `.conf` 目录解析并禁止越界;Studio 在选择 Profile 时执行原生部署预检。 + +不保留本次范围内旧接口兼容:删除 `resolve-conf` 的单输出别名 `output_pool`,统一按槽位 +读取 `output_pools`;Studio 内存状态只保留 `conf_path`,部署 I/O 只取 Pipeline 文档。 +Demo 平台名统一为 `ax650`、`ascend310p`、`ascend910b`、`rk3588`、`cuda`、`cpu` +(大小写不敏感),删除其他名称别名并迁移仓内 Profile。 + +## 3. 验证与完成条件 + +保留旧参数拒绝、Profile 非默认/缺省/非法值、Suite 与业务实跑、原生配置解析和保存命令 +实跑测试;删除生成文件布局、命令结构、帮助文案及重复解析路径测试。执行统一门禁 +`./scripts/run_all_tests.sh`。浏览器、真实模型与硬件验收不属于本次范围。 + +## 4. 实施结果 + +代码、测试与文档已按上述范围收敛;独立评审、聚焦测试与最终统一门禁确认完成。 +用法见 [Demo 接入](../dev_guide/business_onboarding.md#5-统一-demo-接入) 和 +[Studio 运行指南](../../tools/pipeline_studio/README.md#运行当前方案)。 diff --git a/doc/rfcs/README.md b/doc/rfcs/README.md index 0c91841b..85fc8e5c 100644 --- a/doc/rfcs/README.md +++ b/doc/rfcs/README.md @@ -88,6 +88,7 @@ RFC-0054 是接续 RFC-0052 与已交付 RFC-0053、RFC-0055 的实施规格。` | **RFC-0060** | 删除 C ABI,仅保留 C++ Operator API | `Completed` | `v11.0.0` / ABI 7.0.0 | 接入适配层、流程编排层 / Tooling / Docs | [0060-cpp-operator-only.md](0060-cpp-operator-only.md) | | **RFC-0061** | Pipeline JSON 集中管理部署配置 | `Completed` | `v11.x` | 接入适配层、流程编排层 / Tooling / Docs | [0061-pipeline-owned-deployment-configuration.md](0061-pipeline-owned-deployment-configuration.md) | | **RFC-0062** | Integration 部署解析入口统一实施设计 | `Completed` | 投产前 | 接入适配层、流程编排层 / Tooling | [0062-unified-integration-deployment-preparation.md](0062-unified-integration-deployment-preparation.md) | +| **RFC-0063** | Demo 执行参数仅由 Profile 提供 | `Completed` | 当前开发版本 | Demo / Tooling | [0063-demo-profile-only-tuning.md](0063-demo-profile-only-tuning.md) | ## 专项验收与评审归档 diff --git a/output/pipeline_associated/demo-profile.json b/output/pipeline_associated/demo-profile.json new file mode 100644 index 00000000..1f90f7ac --- /dev/null +++ b/output/pipeline_associated/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "doc_qa": { + "biz": "doc_qa", + "config": "build/rfc0057-test-et79khec/configs/pipeline_associated.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_doc_qa.txt", + "batch_size": 1, + "device_id": 0, + "chip": "cpu", + "depth": 1 + } + } +} diff --git a/output/pipeline_doc_qa_assoc/demo-profile.json b/output/pipeline_doc_qa_assoc/demo-profile.json new file mode 100644 index 00000000..58b07979 --- /dev/null +++ b/output/pipeline_doc_qa_assoc/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "doc_qa": { + "biz": "doc_qa", + "config": "build/rfc0057-test-lyqkkw70/configs/pipeline_doc_qa_assoc.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_doc_qa.txt", + "batch_size": 1, + "device_id": 0, + "chip": "cpu", + "depth": 1 + } + } +} diff --git a/output/pipeline_fixture/demo-profile.json b/output/pipeline_fixture/demo-profile.json new file mode 100644 index 00000000..831b1e87 --- /dev/null +++ b/output/pipeline_fixture/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "entity_extract": { + "biz": "entity_extract", + "config": "build/studio-test-g6f8oba0/configs/pipeline_fixture.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", + "batch_size": 1, + "device_id": 0, + "chip": "cpu", + "depth": 1 + } + } +} diff --git a/output/pipeline_paired/demo-profile.json b/output/pipeline_paired/demo-profile.json new file mode 100644 index 00000000..1b070437 --- /dev/null +++ b/output/pipeline_paired/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "entity_extract": { + "biz": "entity_extract", + "config": "build/studio-test-dsu8dyfg/configs/pipeline_paired.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", + "batch_size": 1, + "device_id": 0, + "chip": "cpu", + "depth": 1 + } + } +} diff --git a/output/pipeline_replaced/demo-profile.json b/output/pipeline_replaced/demo-profile.json new file mode 100644 index 00000000..7914b41e --- /dev/null +++ b/output/pipeline_replaced/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "entity_extract": { + "biz": "entity_extract", + "config": "build/studio-test-g6f8oba0/configs/pipeline_replaced.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", + "batch_size": 1, + "device_id": 0, + "chip": "cpu", + "depth": 1 + } + } +} diff --git a/output/pipeline_restart/demo-profile.json b/output/pipeline_restart/demo-profile.json new file mode 100644 index 00000000..c2634ee1 --- /dev/null +++ b/output/pipeline_restart/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "entity_extract": { + "biz": "entity_extract", + "config": "build/studio-test-m4e6gg8z/configs/pipeline_restart.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", + "batch_size": 1, + "device_id": 0, + "chip": "cpu", + "depth": 1 + } + } +} diff --git a/output/pipeline_revision/demo-profile.json b/output/pipeline_revision/demo-profile.json new file mode 100644 index 00000000..416e5f66 --- /dev/null +++ b/output/pipeline_revision/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "keyword_match": { + "biz": "keyword_match", + "config": "build/studio-test-u42wj1nb/configs/pipeline_revision.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_keyword_match.txt", + "batch_size": 2, + "device_id": 0, + "chip": "cpu", + "depth": 2 + } + } +} diff --git a/output/pipeline_rollback/demo-profile.json b/output/pipeline_rollback/demo-profile.json new file mode 100644 index 00000000..21e8d7c3 --- /dev/null +++ b/output/pipeline_rollback/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "keyword_match": { + "biz": "keyword_match", + "config": "build/studio-test-b4091sqq/configs/pipeline_rollback.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_keyword_match.txt", + "batch_size": 2, + "device_id": 0, + "chip": "cpu", + "depth": 2 + } + } +} diff --git a/output/pipeline_targets/demo-profile.json b/output/pipeline_targets/demo-profile.json new file mode 100644 index 00000000..ef973748 --- /dev/null +++ b/output/pipeline_targets/demo-profile.json @@ -0,0 +1,14 @@ +{ + "schema_version": 2, + "profiles": { + "keyword_match": { + "biz": "keyword_match", + "config": "build/studio-test-ase2krek/configs/pipeline_targets.conf", + "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_keyword_match.txt", + "batch_size": 2, + "device_id": 0, + "chip": "cpu", + "depth": 2 + } + } +} diff --git a/src/tools/alg_pipeline_tool.cpp b/src/tools/alg_pipeline_tool.cpp index c02a40a4..687e8919 100644 --- a/src/tools/alg_pipeline_tool.cpp +++ b/src/tools/alg_pipeline_tool.cpp @@ -17,6 +17,7 @@ #include "core/diagnostic_code.h" #include "core/pipeline_catalog.h" #include "core/pipeline_validator.h" +#include "demo/common/demo_profile_defaults.h" #include "edgeflow/operator/interface.h" #include "nlohmann/json.hpp" #include "pipeline_document_validation.h" @@ -70,32 +71,15 @@ bool ReadJson(const std::string& path, nlohmann::json* output, } } -std::optional ProfilePipeline( - const std::string& profile, nlohmann::json* profile_json = nullptr) { - std::ifstream profiles_stream("demo/profiles.json"); - if (!profiles_stream.is_open()) return std::nullopt; - nlohmann::json root; - profiles_stream >> root; - if (!root.contains("profiles") || !root["profiles"].contains(profile)) - return std::nullopt; - const auto& selected = root["profiles"][profile]; - if (profile_json) *profile_json = selected; - fs::path conf_path = selected["config"].get(); - std::ifstream conf_stream(conf_path); - if (!conf_stream.is_open()) return std::nullopt; - nlohmann::json conf; - conf_stream >> conf; - if (!conf.is_object() || !conf.contains("pipe_path") || - !conf["pipe_path"].is_string()) { +std::optional ProfilePipeline(const nlohmann::json& profile) { + llm_edgeflow::DeploymentIoConfig config; + std::string error; + if (!profile.contains("config") || !profile["config"].is_string() || + !llm_edgeflow::DeploymentIoConfig::ReadFromFile( + profile["config"].get(), "operator", &config, &error)) { return std::nullopt; } - fs::path pipe_path = conf["pipe_path"].get(); - if (pipe_path.is_relative()) { - if (!fs::exists(pipe_path)) { - pipe_path = conf_path.parent_path() / pipe_path; - } - } - return pipe_path.lexically_normal(); + return fs::path(config.resolved_pipe_path); } nlohmann::json ProfilesJson(const std::string& biz_filter) { @@ -106,22 +90,24 @@ nlohmann::json ProfilesJson(const std::string& biz_filter) { try { stream >> root; for (const auto& [name, profile] : root["profiles"].items()) { - auto pipeline_path = ProfilePipeline(name); + auto pipeline_path = ProfilePipeline(profile); if (!pipeline_path) continue; nlohmann::json pipeline; std::string error; if (!ReadJson(pipeline_path->string(), &pipeline, &error)) continue; std::string pipeline_biz = pipeline.value("biz_name", ""); if (!biz_filter.empty() && pipeline_biz != biz_filter) continue; - result.push_back({{"name", name}, - {"biz", profile.value("biz", "")}, - {"pipeline_biz", pipeline_biz}, - {"config", profile.value("config", "")}, - {"dataset", profile.value("dataset", "")}, - {"suite", profile.value("suite", "smoke")}, - {"batch_size", profile.value("batch_size", 1)}, - {"device_id", profile.value("device_id", 0)}, - {"chip", profile.value("chip", "ax650")}}); + result.push_back( + {{"name", name}, + {"biz", profile.value("biz", "")}, + {"pipeline_biz", pipeline_biz}, + {"config", profile.value("config", "")}, + {"dataset", profile.value("dataset", "")}, + {"suite", profile.value("suite", "smoke")}, + {"batch_size", + profile.value("batch_size", alg_demo::kDemoBatchSize)}, + {"device_id", profile.value("device_id", alg_demo::kDemoDeviceId)}, + {"chip", profile.value("chip", std::string(alg_demo::kDemoChip))}}); } } catch (...) { return nlohmann::json::array(); @@ -199,9 +185,6 @@ nlohmann::json ResolveConf(const std::string& file, const std::string& root, {"effective_pipeline", std::move(effective)}, {"model_paths", std::move(paths)}, {"output_pools", output_pools}}; - if (output_pools.size() == 1) { - configuration["output_pool"] = output_pools.begin().value(); - } return {{"schema_version", 1}, {"ok", true}, {"configuration", std::move(configuration)}}; @@ -354,8 +337,14 @@ int main(int argc, char* argv[]) { {"models", nlohmann::json::array()}, {"pipeline", nlohmann::json::array()}}; if (!profile.empty()) { - auto path = ProfilePipeline(profile); std::string error; + nlohmann::json profiles; + std::optional path; + if (ReadJson("demo/profiles.json", &profiles, &error) && + profiles.contains("profiles") && profiles["profiles"].is_object() && + profiles["profiles"].contains(profile)) { + path = ProfilePipeline(profiles["profiles"][profile]); + } if (!path || !ReadJson(path->string(), &pipeline, &error) || pipeline.value("biz_name", "") != biz) { std::cout << ToolError("PROFILE_MISMATCH", diff --git a/tests/integration/demo/test_demo_runner.cpp b/tests/integration/demo/test_demo_runner.cpp index 47a4d597..b0bfe888 100644 --- a/tests/integration/demo/test_demo_runner.cpp +++ b/tests/integration/demo/test_demo_runner.cpp @@ -185,7 +185,7 @@ TEST(DemoRunnerTest, RealKiteEntityExtractionThroughOperator) { opts.config_path = (temporary.path / "pipeline.conf").string(); opts.dataset_path = (temporary.path / "input.txt").string(); opts.output_dir = (temporary.path / "output").string(); - opts.chip = "cpu_generic"; + opts.chip = "cpu"; opts.device_id = 0; opts.batch_size = 1; const auto* desc = DemoRegistry::Instance().Find(opts.biz); @@ -249,14 +249,6 @@ TEST(DemoRunnerTest, CommandLineParsingSuccess) { "data/corpus_entity_extract.txt", "--output-dir", "./results/test_out", - "--batch-size", - "4", - "--device-id", - "1", - "--chip", - "cpu_generic", - "--depth", - "2", "--suite", "smoke", "--append", @@ -273,14 +265,11 @@ TEST(DemoRunnerTest, CommandLineParsingSuccess) { "demo/fixtures/mock/pipeline_entity_extract.conf"); EXPECT_EQ(opts.dataset_path, "data/corpus_entity_extract.txt"); EXPECT_EQ(opts.output_dir, "./results/test_out"); - EXPECT_EQ(opts.batch_size, 4); - EXPECT_EQ(opts.device_id, 1); - EXPECT_EQ(opts.chip, "cpu_generic"); - EXPECT_EQ(opts.depth_num, 2u); + EXPECT_EQ(opts.batch_size, 1); + EXPECT_EQ(opts.device_id, 0); + EXPECT_EQ(opts.chip, "cpu"); + EXPECT_EQ(opts.depth_num, 1u); EXPECT_EQ(opts.suite, "smoke"); - EXPECT_TRUE(opts.has_batch_size); - EXPECT_TRUE(opts.has_device_id); - EXPECT_TRUE(opts.has_chip); EXPECT_TRUE(opts.has_suite); EXPECT_TRUE(opts.append); EXPECT_TRUE(opts.allow_fallback_sample); @@ -306,7 +295,7 @@ TEST(DemoRunnerTest, RejectsLegacyBusinessFlag) { EXPECT_NE(err.find("Unknown CLI option"), std::string::npos); } -// P2-1: 测试 CLI 参数严格解析 (尾随字符拦截与错误退出码 2) +// CLI errors retain exit code 2. TEST(DemoRunnerTest, CommandLineParsingErrors) { DemoOptions opts; std::string err; @@ -319,41 +308,24 @@ TEST(DemoRunnerTest, CommandLineParsingErrors) { const char* argv2[] = {"alg_demo", "--profile"}; EXPECT_EQ(ParseCommandLine(2, const_cast(argv2), &opts, &err), 2); - // 非法 batch_size (负数) - const char* argv3[] = {"alg_demo", "--batch-size", "-1"}; - EXPECT_EQ(ParseCommandLine(3, const_cast(argv3), &opts, &err), 2); - - // 非法 batch_size (超大数值溢出拦截) - const char* argv3_overflow[] = {"alg_demo", "--batch-size", "4294967297"}; - EXPECT_EQ( - ParseCommandLine(3, const_cast(argv3_overflow), &opts, &err), 2); - - // P2-1: 非法 batch_size (含尾随非法字符 "1abc") - const char* argv3_trailing[] = {"alg_demo", "--batch-size", "1abc"}; - EXPECT_EQ( - ParseCommandLine(3, const_cast(argv3_trailing), &opts, &err), 2); - - // P2-1: 非法 device-id (含尾随字符 "0xyz") - const char* argv_dev_trailing[] = {"alg_demo", "--device-id", "0xyz"}; - EXPECT_EQ( - ParseCommandLine(3, const_cast(argv_dev_trailing), &opts, &err), - 2); - - // P2-1: 非法 depth (含尾随字符 "2foo") - const char* argv_depth_trailing[] = {"alg_demo", "--depth", "2foo"}; - EXPECT_EQ( - ParseCommandLine(3, const_cast(argv_depth_trailing), &opts, &err), - 2); - - // 非法 chip - const char* argv4[] = {"alg_demo", "--chip", "unsupported_dsp"}; - EXPECT_EQ(ParseCommandLine(3, const_cast(argv4), &opts, &err), 2); - // 非法 suite const char* argv5[] = {"alg_demo", "--suite", "invalid_suite"}; EXPECT_EQ(ParseCommandLine(3, const_cast(argv5), &opts, &err), 2); } +TEST(DemoRunnerTest, RejectsProfileOnlyExecutionFlags) { + for (const char* flag : + {"--batch-size", "--device-id", "--chip", "--depth"}) { + SCOPED_TRACE(flag); + const char* argv[] = {"alg_demo", flag, "1"}; + DemoOptions options; + std::string error; + EXPECT_EQ(ParseCommandLine(3, const_cast(argv), &options, &error), + 2); + EXPECT_EQ(error, "Unknown CLI option: '" + std::string(flag) + "'"); + } +} + // 2. 测试芯片白名单解析 TEST(DemoRunnerTest, ComputePlatformWhitelistValidation) { EXPECT_EQ(DemoOptions{}.chip, "cpu"); @@ -375,22 +347,21 @@ TEST(DemoRunnerTest, ComputePlatformWhitelistValidation) { EXPECT_TRUE(ParseComputePlatform("rk3588", &type)); EXPECT_EQ(type, ComputePlatform::kRk3588); - EXPECT_TRUE(ParseComputePlatform("nvidia_gpu", &type)); + EXPECT_TRUE(ParseComputePlatform("cuda", &type)); EXPECT_EQ(type, ComputePlatform::kCuda); - EXPECT_TRUE(ParseComputePlatform("cpu_generic", &type)); + EXPECT_TRUE(ParseComputePlatform("cpu", &type)); EXPECT_EQ(type, ComputePlatform::kCpu); + EXPECT_FALSE(ParseComputePlatform("cpu_generic", &type)); EXPECT_FALSE(ParseComputePlatform("invalid_hardware", &type)); EXPECT_EQ(type, ComputePlatform::kUnknown); } -// 3. 测试 Profile 加载、合并与 P1-1 CLI 显式默认值覆盖 +// 3. Profile loading and remaining CLI overrides. TEST(DemoRunnerTest, ProfileLoadAndMerge) { DemoOptions cli_opts; cli_opts.profile = "entity_extract_mock"; - cli_opts.batch_size = 8; - cli_opts.has_batch_size = true; DemoOptions merged; std::string err; @@ -402,29 +373,62 @@ TEST(DemoRunnerTest, ProfileLoadAndMerge) { "demo/fixtures/mock/pipeline_entity_extract.conf"); EXPECT_EQ(merged.dataset_path, "data/corpus_entity_extract.txt"); EXPECT_EQ(merged.chip, "cpu"); - EXPECT_EQ(merged.batch_size, 8); // CLI 覆盖 Profile 的默认 1 + EXPECT_EQ(merged.batch_size, 1); } -// P1-1: 验证 CLI 显式传入默认值 (例如 --batch-size 1) 可以可靠覆盖 Profile 中非 -// 1 的 batch_size -TEST(DemoRunnerTest, CliOverridesProfileEvenWithExplicitDefault) { - const char* argv[] = {"alg_demo", "--profile", "cross_rerank_cpu", - "--batch-size", "1"}; - int argc = 5; - - DemoOptions cli_opts; - std::string err; - int ret = ParseCommandLine(argc, const_cast(argv), &cli_opts, &err); - ASSERT_EQ(ret, 0); - EXPECT_TRUE(cli_opts.has_batch_size); - EXPECT_EQ(cli_opts.batch_size, 1); - - DemoOptions merged; - ret = LoadAndMergeProfiles("demo/profiles.json", cli_opts, &merged, &err); - ASSERT_EQ(ret, 0) << "Error: " << err; - - // 即使 CLI 显式给出默认值 1,也必须保留该显式覆盖语义。 +TEST(DemoRunnerTest, ProfileOwnsExecutionSettings) { + KiteDemoDirectory temporary; + const std::string path = (temporary.path / "profiles.json").string(); + const nlohmann::json profile = { + {"biz", "keyword_match"}, + {"config", "configs/pipeline_keyword_match_rules.conf"}, + {"dataset", "data/corpus_keyword_match.txt"}, + {"batch_size", 4}, + {"device_id", 2}, + {"chip", "cuda"}, + {"depth", 8}}; + auto write_profile = [&](const nlohmann::json& value) { + std::ofstream(path) << nlohmann::json( + {{"schema_version", 2}, {"profiles", {{"execution", value}}}}); + }; + write_profile(profile); + const char* args[] = {"alg_demo", "--profile", "execution", "--dataset", + "custom.txt"}; + DemoOptions cli, merged; + std::string error; + ASSERT_EQ(ParseCommandLine(5, const_cast(args), &cli, &error), 0); + ASSERT_EQ(LoadAndMergeProfiles(path, cli, &merged, &error), 0) << error; + EXPECT_EQ(merged.batch_size, 4); + EXPECT_EQ(merged.device_id, 2); + EXPECT_EQ(merged.chip, "cuda"); + EXPECT_EQ(merged.depth_num, 8u); + EXPECT_EQ(merged.dataset_path, "custom.txt"); + + auto defaults = profile; + for (const char* field : {"batch_size", "device_id", "chip", "depth"}) + defaults.erase(field); + write_profile(defaults); + ASSERT_EQ(LoadAndMergeProfiles(path, cli, &merged, &error), 0) << error; EXPECT_EQ(merged.batch_size, 1); + EXPECT_EQ(merged.device_id, 0); + EXPECT_EQ(merged.chip, "cpu"); + EXPECT_EQ(merged.depth_num, 1u); + + for (const auto& invalid : + std::vector>{{"batch_size", 0}, + {"batch_size", "2"}, + {"device_id", -1}, + {"device_id", "0"}, + {"chip", "invalid"}, + {"chip", 1}, + {"depth", 0}, + {"depth", "2"}}) { + auto bad = profile; + bad[invalid.first] = invalid.second; + write_profile(bad); + EXPECT_EQ(LoadAndMergeProfiles(path, cli, &merged, &error), 3); + EXPECT_NE(error.find(invalid.first), std::string::npos) << error; + } } TEST(DemoRunnerTest, ProfileBizMismatchRejection) { @@ -508,11 +512,6 @@ TEST(DemoRunnerTest, ProfileSchemaStrictValidation) { 3); EXPECT_NE(err.find("suite"), std::string::npos); - // 验证 GetProfilesForSuite 对该非法文件同样返回 3 且不崩溃 - std::vector prof_list; - EXPECT_EQ(GetProfilesForSuite(temp_invalid_json, "smoke", &prof_list, &err), - 3); - // Case 4: batch_size 数值超界溢出 (4294967297) 防御拦截 { std::ofstream ofs(temp_invalid_json); @@ -629,14 +628,12 @@ TEST(DemoRunnerTest, DemoOptions cli; cli.profile = profile; cli.output_dir = temporary.path.string(); - cli.has_output_dir = true; - cli.batch_size = 2; - cli.has_batch_size = true; DemoOptions options; std::string error; ASSERT_EQ(LoadAndMergeProfiles("demo/profiles.json", cli, &options, &error), 0) << error; + options.batch_size = 2; // Exercise multi-request custom-node execution. const auto* descriptor = DemoRegistry::Instance().Find(options.biz); ASSERT_NE(descriptor, nullptr); ASSERT_EQ(descriptor->run(options), 0); @@ -1047,7 +1044,6 @@ TEST(DemoRunnerTest, OcrDemoAppliesExplicitControlBeforeProcessing) { DemoOptions cli; cli.profile = "ocr_doc_qa_mock"; cli.output_dir = temporary.path.string(); - cli.has_output_dir = true; DemoOptions options; std::string error; ASSERT_EQ(LoadAndMergeProfiles("demo/profiles.json", cli, &options, &error), @@ -1149,7 +1145,6 @@ TEST(DemoRunnerTest, OperatorBatchChunking) { // 指定 batch_size = 1 (数据集有 2 条样本,必须分 2 批执行) opts.batch_size = 1; - opts.has_batch_size = true; opts.output_dir = "./results/test_chunking_out"; EXPECT_EQ(desc->run(opts), 0); @@ -1177,15 +1172,19 @@ TEST(DemoRunnerTest, EndToEndAllMockSmokeBusinesses) { "entity_extract_mock", "keyword_match_rules", "doc_qa_mock", "dialogue_audit_mock", "ocr_doc_qa_mock", "audio_asr_mock"}; + nlohmann::json profiles; + std::string err; + ASSERT_EQ( + LoadAndValidateProfilesDocument("demo/profiles.json", &profiles, &err), 0) + << err; + for (const auto& prof_name : smoke_profiles) { DemoOptions cli_opt; cli_opt.profile = prof_name; cli_opt.output_dir = "./results/test_ci_out"; DemoOptions merged_opt; - std::string err; - int ret = - LoadAndMergeProfiles("demo/profiles.json", cli_opt, &merged_opt, &err); + int ret = MergeProfileOptions(profiles, cli_opt, &merged_opt, &err); ASSERT_EQ(ret, 0) << "Profile merge failed for " << prof_name << ": " << err; @@ -1213,10 +1212,11 @@ TEST(DemoRunnerTest, DeploymentProfilesFileSelection) { << error; EXPECT_EQ(merged.biz, "entity_extract"); EXPECT_EQ(merged.config_path, "configs/pipeline_entity_extract_kite.conf"); - std::vector profiles; + nlohmann::json profiles; ASSERT_EQ( - GetProfilesForSuite(options.profiles_file, "real", &profiles, &error), 0); - EXPECT_EQ(profiles.size(), 8U); + LoadAndValidateProfilesDocument(options.profiles_file, &profiles, &error), + 0); + EXPECT_EQ(SelectProfilesForSuite(profiles, "real").size(), 8U); const char* missing[] = {"alg_demo", "--profiles-file"}; EXPECT_EQ(ParseCommandLine(2, const_cast(missing), &options, &error), 2); @@ -1228,21 +1228,20 @@ TEST(DemoRunnerTest, RealKiteDeploymentProfiles) { GTEST_SKIP() << "Set LLM_EDGEFLOW_TEST_KITELLM_DEMOS=1 after fetching --kite models"; ASSERT_TRUE(llm_edgeflow::BackendRegistry::Instance().Find("kite_llm")); - std::vector profiles; + nlohmann::json profiles; std::string error; - ASSERT_EQ( - GetProfilesForSuite("demo/profiles_kite.json", "real", &profiles, &error), - 0) + ASSERT_EQ(LoadAndValidateProfilesDocument("demo/profiles_kite.json", + &profiles, &error), + 0) << error; auto ops = Get_LLM_EDGEFLOW_OperatorTable(); ASSERT_EQ(ops.Init(), 0); - for (const auto& name : profiles) { + for (const auto& name : SelectProfilesForSuite(profiles, "real")) { DemoOptions cli; cli.profile = name; cli.output_dir = "results/kite-deployment-tests"; DemoOptions options; - const int merged = - LoadAndMergeProfiles("demo/profiles_kite.json", cli, &options, &error); + const int merged = MergeProfileOptions(profiles, cli, &options, &error); EXPECT_EQ(merged, 0) << error; if (merged) continue; const auto* descriptor = DemoRegistry::Instance().Find(options.biz); diff --git a/tests/tooling/test_pipeline_studio.py b/tests/tooling/test_pipeline_studio.py index 9ce0436e..6cd57f52 100644 --- a/tests/tooling/test_pipeline_studio.py +++ b/tests/tooling/test_pipeline_studio.py @@ -306,17 +306,11 @@ def setUp(self): def tearDown(self): self.temporary.cleanup() - def test_saved_pair_runs_the_selected_pipeline_with_explicit_arguments(self): + def test_saved_command_runs_the_selected_pipeline(self): self.keyword["pipeline"][0]["config"]["categories"] = {"SAVED_RULE": ["VIP"]} filename = f"pipeline_saved_{uuid.uuid4().hex}.json" saved = self.service.save_solution(filename, self.keyword, "keyword_match_rules") - self.assertEqual(json.loads((self.configs / filename).read_text()), self.keyword) - conf = json.loads((self.configs / saved["conf_filename"]).read_text()) - self.assertEqual(conf["pipe_path"], filename) command = shlex.split(saved["command"]) - self.assertEqual(command[:3], ["cd", str(ROOT), "&&"]) - self.assertNotIn("--no-default-control", command) - self.assertFalse(Path(command[command.index("--config") + 1]).is_absolute()) output = Path(command[command.index("--output-dir") + 1]) try: process = subprocess.run(command[3:], cwd=command[1], text=True, capture_output=True, timeout=30) @@ -448,8 +442,10 @@ def test_draft_uses_the_same_selected_paths_under_project_root_and_cleans_up(sel observed = {} original_popen = SHOW.subprocess.Popen def inspect_launch(args, **kwargs): - if "--config" in args: - conf_path = ROOT / args[args.index("--config") + 1] + if "--profiles-file" in args: + document = json.loads(Path(args[args.index("--profiles-file") + 1]).read_text()) + profile = document["profiles"][args[args.index("--profile") + 1]] + conf_path = ROOT / profile["config"] observed["directory"] = conf_path.parent observed["conf"] = json.loads(conf_path.read_text()) observed["pipeline"] = json.loads((conf_path.parent / "pipeline.json").read_text()) diff --git a/tools/pipeline_studio/README.md b/tools/pipeline_studio/README.md index 5bd38b84..e60e52bb 100644 --- a/tools/pipeline_studio/README.md +++ b/tools/pipeline_studio/README.md @@ -210,9 +210,20 @@ CLI 的 `--config` 覆盖 Profile 原配置,因此不需要新增 Profile。 显式传入业务、配置和数据集: ```bash -./build/alg_demo --biz keyword_match --config configs/pipeline_first_solution.conf --dataset data/corpus_keyword_match.txt --chip cpu --batch-size 2 --output-dir results/first-solution +./build/alg_demo --biz keyword_match --config configs/pipeline_first_solution.conf --dataset data/corpus_keyword_match.txt --output-dir results/first-solution ``` +`chip`、`device_id`、`batch_size`、`depth` 仅从 Profile JSON 读取,不支持同名 CLI +选项。需要自定义时修改 Profile,或通过 `--profiles-file --profile ` 选择自有 +Profile;未指定时默认值分别为 `cpu`、`0`、`1`、`1`。无 Profile 的命令按单条提交。 +平台名只接受 `ax650`、`ascend310p`、`ascend910b`、`rk3588`、`cuda`、`cpu` +(大小写不敏感);旧别名如 `cpu_generic`、`nvidia_gpu` 已删除。 +Studio 将这四项连同业务、配置和数据集写入运行 Profile;保存方案返回的命令引用输出目录 +中的 `demo-profile.json`;每次保存更新该文件,复制的命令读取最新运行配置。 +Studio 不为缺失执行字段补值,预检按批次和深度缺省 1 计算。 +选择 Profile 时通过原生 `resolve-conf` 获取实际 Pipeline 路径, +相对 `pipe_path` 始终基于 `.conf` 所在目录,不搜索项目根目录下的同名文件。 + 只有原 Profile 已指向本次方案时,才能直接用它证明本次修改已运行。 检查 `results/first-solution/keyword_match_rules/results.jsonl` 和 `summary.json`: diff --git a/tools/pipeline_studio/server.py b/tools/pipeline_studio/server.py index 9ab982f0..dfbc804e 100755 --- a/tools/pipeline_studio/server.py +++ b/tools/pipeline_studio/server.py @@ -255,7 +255,7 @@ def pipelines(self) -> dict[str, Any]: def save_targets(self, path: Path) -> list[str]: if path.name in self.generated_solutions: - conf_name = self.generated_solutions[path.name].get("conf_name", path.with_suffix(".conf").name) + conf_name = self.generated_solutions[path.name]["conf_path"].name return [path.name, conf_name] return [path.name] @@ -518,7 +518,7 @@ def update_solution(self, path: Path, pipeline: Any, expected_revision: str | No model_path_actions: Any = None) -> dict[str, Any]: with self.solution_lock: managed = self.generated_solutions[path.name] - conf_path = managed.get("conf_path") or path.with_suffix(".conf") + conf_path = managed["conf_path"] def check_revisions() -> tuple[bytes, bytes]: if path.is_symlink() or conf_path.is_symlink() or not path.is_file() or not conf_path.is_file(): @@ -584,18 +584,8 @@ def profile_inputs(self, pipeline: Any, profile_name: str) -> tuple[dict, Any]: if not profile: raise StudioError("UNKNOWN_PROFILE", profile_name) profile_conf = PROJECT_ROOT / profile["config"] - conf = read_json(profile_conf) - if not isinstance(conf, dict) or "pipe_path" not in conf or not isinstance(conf["pipe_path"], str): - raise StudioError( - "INVALID_PROFILE_CONFIG", "Profile .conf 必须包含 pipe_path" - ) - original_pipeline_path = Path(conf["pipe_path"]) - if not original_pipeline_path.is_absolute(): - if (PROJECT_ROOT / original_pipeline_path).exists(): - original_pipeline_path = PROJECT_ROOT / original_pipeline_path - else: - original_pipeline_path = profile_conf.parent / original_pipeline_path - original = read_json(original_pipeline_path.resolve()) + configuration = self.resolve_run_conf(profile_conf, profile) + original = read_json(Path(configuration["pipeline_path"])) orig_biz = original.get("biz_name") curr_biz = pipeline.get("biz_name") if orig_biz != curr_biz: @@ -676,13 +666,7 @@ def deployment_candidate( pipeline.setdefault("deployment", {})["model_paths"] = overrides elif "deployment" in pipeline and "model_paths" in pipeline["deployment"]: del pipeline["deployment"]["model_paths"] - if "deployment" in original and "io" in original["deployment"]: - pipeline.setdefault("deployment", {})["io"] = copy.deepcopy(original["deployment"]["io"]) - elif "outputs" in managed and managed["outputs"]: - io_dict = pipeline.setdefault("deployment", {}).setdefault("io", {}) - io_dict["output_allocations"] = copy.deepcopy(managed["outputs"]) - if managed.get("io_binding"): - io_dict["io_binding"] = managed["io_binding"] + pipeline.setdefault("deployment", {})["io"] = copy.deepcopy(original["deployment"]["io"]) return profile, {"pipe_path": path.name} def resolve_run_conf(self, conf_path: Path, profile: dict[str, Any]) -> dict[str, Any]: @@ -694,12 +678,24 @@ def resolve_run_conf(self, conf_path: Path, profile: dict[str, Any]) -> dict[str @staticmethod def demo_command(profile: dict[str, Any], conf_path: Path, output_dir: Path) -> list[str]: + # Snapshot only settings previously passed to Demo, not runtime Control. + name = str(profile["biz"]) + run_profile = { + "biz": name, "config": str(conf_path), + "dataset": str(PROJECT_ROOT / profile["dataset"]), + } + for field in ("batch_size", "device_id", "chip", "depth"): + if field in profile: + run_profile[field] = profile[field] + output_dir.mkdir(parents=True, exist_ok=True) + profile_path = output_dir / "demo-profile.json" + if profile_path.is_symlink(): + raise StudioError("SYMLINK_REJECTED", "拒绝覆盖符号链接运行 Profile", 409) + profile_path.write_text(json.dumps({"schema_version": 2, "profiles": {name: run_profile}}, + ensure_ascii=False, indent=2) + "\n", encoding="utf-8") return [ - str(DEMO_BINARY), "--biz", str(profile["biz"]), - "--config", str(conf_path), "--dataset", str(PROJECT_ROOT / profile["dataset"]), - "--output-dir", str(output_dir), "--batch-size", str(profile.get("batch_size", 1)), - "--device-id", str(profile.get("device_id", 0)), "--chip", str(profile.get("chip", "ax650")), - "--depth", str(profile.get("depth", 1)), + str(DEMO_BINARY), "--profiles-file", str(profile_path), "--profile", name, + "--output-dir", str(output_dir), ] def save_solution(self, requested: str, pipeline: Any, profile_name: str, model_root: str = "models") -> dict[str, Any]: @@ -714,7 +710,6 @@ def save_solution(self, requested: str, pipeline: Any, profile_name: str, model_ if target.exists(): raise StudioError("FILE_EXISTS", f"另存目标已存在:{target.name}", 409) profile, conf = self.deployment_candidate(pipeline, profile_name, model_root, path.name) - outputs = pipeline.get("deployment", {}).get("io", {}).get("output_allocations", {}) encoded = (json.dumps(pipeline, ensure_ascii=False, indent=2) + "\n").encode() conf_encoded = (json.dumps(conf, ensure_ascii=False, indent=2) + "\n").encode() created = [] @@ -737,15 +732,15 @@ def save_solution(self, requested: str, pipeline: Any, profile_name: str, model_ raise raise StudioError("SAVE_FAILED", str(error), 500) from error self.generated_solutions[path.name] = { - "profile": profile, "outputs": outputs, "model_root": model_root, - "conf_path": conf_path, "conf_name": conf_path.name, + "profile": profile, "model_root": model_root, + "conf_path": conf_path, "pipeline_revision": revision_for(encoded), "conf_revision": revision_for(conf_encoded), } return self.solution_result(path, pipeline, conf, encoded, profile, model_root, configuration) def solution_result(self, path: Path, pipeline: Any, conf: Any, encoded: bytes, profile: dict[str, Any], model_root: str, configuration: Any) -> dict[str, Any]: - conf_path = self.generated_solutions.get(path.name, {}).get("conf_path") or path.with_suffix(".conf") + conf_path = self.generated_solutions[path.name]["conf_path"] command_str = "" if profile and profile.get("dataset"): command = self.demo_command(profile, conf_path.relative_to(PROJECT_ROOT), PROJECT_ROOT / "output" / path.stem) @@ -833,16 +828,11 @@ def associate_deployment( if pipe_path.read_bytes() != pipe_raw or conf_path.read_bytes() != conf_raw: raise StudioError("REVISION_CONFLICT", "关联期间文件已改变,请重新关联", 409) - outputs = pipeline.get("deployment", {}).get("io", {}).get("output_allocations", {}) - io_binding = pipeline.get("deployment", {}).get("io", {}).get("io_binding", "") with self.solution_lock: self.generated_solutions[pipe_path.name] = { "conf_path": conf_path, - "conf_name": conf_path.name, "conf_revision": revision_for(conf_raw), "pipeline_revision": revision_for(pipe_raw), - "outputs": outputs, - "io_binding": io_binding, "model_root": model_root, "profile": prof, "is_associated": True, diff --git a/tools/verify_selection.py b/tools/verify_selection.py index 04b3b7c0..3507d25c 100644 --- a/tools/verify_selection.py +++ b/tools/verify_selection.py @@ -268,8 +268,7 @@ def evaluate(pipeline, selection, tool, model_root, spec_path, conf_path, demo): (temporary / "pipeline.json").write_text(json.dumps(pipeline)) (temporary / "pipeline.conf").write_text(json.dumps(generated_conf)) command = [str(Path(demo).resolve()), "--biz", biz, "--config", str(relative / "pipeline.conf"), - "--dataset", str(dataset), "--output-dir", str(temporary / "results"), - "--chip", "cpu", "--device-id", "0", "--batch-size", "1", "--depth", "1"] + "--dataset", str(dataset), "--output-dir", str(temporary / "results")] process = subprocess.run(command, cwd=bundle_root, text=True, capture_output=True, timeout=1800, check=False) if process.returncode: raise ValueError("Effect run failed: " + (process.stdout + process.stderr)[-3000:]) From 5467040d6a84bbab1ea4523735f50f34b1a1390e Mon Sep 17 00:00:00 2001 From: chamsechan Date: Sun, 20 Sep 2026 17:37:36 +0800 Subject: [PATCH 2/2] refactor(demo): simplify ProfileOwnsExecutionSettings test --- output/pipeline_associated/demo-profile.json | 2 +- output/pipeline_doc_qa_assoc/demo-profile.json | 2 +- output/pipeline_fixture/demo-profile.json | 2 +- output/pipeline_paired/demo-profile.json | 2 +- output/pipeline_replaced/demo-profile.json | 2 +- output/pipeline_restart/demo-profile.json | 2 +- output/pipeline_revision/demo-profile.json | 2 +- output/pipeline_rollback/demo-profile.json | 2 +- output/pipeline_targets/demo-profile.json | 2 +- tests/integration/demo/test_demo_runner.cpp | 5 +---- 10 files changed, 10 insertions(+), 13 deletions(-) diff --git a/output/pipeline_associated/demo-profile.json b/output/pipeline_associated/demo-profile.json index 1f90f7ac..513925b6 100644 --- a/output/pipeline_associated/demo-profile.json +++ b/output/pipeline_associated/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "doc_qa": { "biz": "doc_qa", - "config": "build/rfc0057-test-et79khec/configs/pipeline_associated.conf", + "config": "build/rfc0057-test-c32es6gh/configs/pipeline_associated.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_doc_qa.txt", "batch_size": 1, "device_id": 0, diff --git a/output/pipeline_doc_qa_assoc/demo-profile.json b/output/pipeline_doc_qa_assoc/demo-profile.json index 58b07979..ddc2c477 100644 --- a/output/pipeline_doc_qa_assoc/demo-profile.json +++ b/output/pipeline_doc_qa_assoc/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "doc_qa": { "biz": "doc_qa", - "config": "build/rfc0057-test-lyqkkw70/configs/pipeline_doc_qa_assoc.conf", + "config": "build/rfc0057-test-bps7t01f/configs/pipeline_doc_qa_assoc.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_doc_qa.txt", "batch_size": 1, "device_id": 0, diff --git a/output/pipeline_fixture/demo-profile.json b/output/pipeline_fixture/demo-profile.json index 831b1e87..57d2e651 100644 --- a/output/pipeline_fixture/demo-profile.json +++ b/output/pipeline_fixture/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "entity_extract": { "biz": "entity_extract", - "config": "build/studio-test-g6f8oba0/configs/pipeline_fixture.conf", + "config": "build/studio-test-ti3beu7q/configs/pipeline_fixture.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", "batch_size": 1, "device_id": 0, diff --git a/output/pipeline_paired/demo-profile.json b/output/pipeline_paired/demo-profile.json index 1b070437..0cca596f 100644 --- a/output/pipeline_paired/demo-profile.json +++ b/output/pipeline_paired/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "entity_extract": { "biz": "entity_extract", - "config": "build/studio-test-dsu8dyfg/configs/pipeline_paired.conf", + "config": "build/studio-test-n6q61kj3/configs/pipeline_paired.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", "batch_size": 1, "device_id": 0, diff --git a/output/pipeline_replaced/demo-profile.json b/output/pipeline_replaced/demo-profile.json index 7914b41e..8f4ebed9 100644 --- a/output/pipeline_replaced/demo-profile.json +++ b/output/pipeline_replaced/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "entity_extract": { "biz": "entity_extract", - "config": "build/studio-test-g6f8oba0/configs/pipeline_replaced.conf", + "config": "build/studio-test-ti3beu7q/configs/pipeline_replaced.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", "batch_size": 1, "device_id": 0, diff --git a/output/pipeline_restart/demo-profile.json b/output/pipeline_restart/demo-profile.json index c2634ee1..0c3693c9 100644 --- a/output/pipeline_restart/demo-profile.json +++ b/output/pipeline_restart/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "entity_extract": { "biz": "entity_extract", - "config": "build/studio-test-m4e6gg8z/configs/pipeline_restart.conf", + "config": "build/studio-test-af9c8p02/configs/pipeline_restart.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_entity_extract.txt", "batch_size": 1, "device_id": 0, diff --git a/output/pipeline_revision/demo-profile.json b/output/pipeline_revision/demo-profile.json index 416e5f66..6eef0c41 100644 --- a/output/pipeline_revision/demo-profile.json +++ b/output/pipeline_revision/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "keyword_match": { "biz": "keyword_match", - "config": "build/studio-test-u42wj1nb/configs/pipeline_revision.conf", + "config": "build/studio-test-5wifs6y5/configs/pipeline_revision.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_keyword_match.txt", "batch_size": 2, "device_id": 0, diff --git a/output/pipeline_rollback/demo-profile.json b/output/pipeline_rollback/demo-profile.json index 21e8d7c3..5882a6cc 100644 --- a/output/pipeline_rollback/demo-profile.json +++ b/output/pipeline_rollback/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "keyword_match": { "biz": "keyword_match", - "config": "build/studio-test-b4091sqq/configs/pipeline_rollback.conf", + "config": "build/studio-test-qnmwvq0u/configs/pipeline_rollback.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_keyword_match.txt", "batch_size": 2, "device_id": 0, diff --git a/output/pipeline_targets/demo-profile.json b/output/pipeline_targets/demo-profile.json index ef973748..dc8c3003 100644 --- a/output/pipeline_targets/demo-profile.json +++ b/output/pipeline_targets/demo-profile.json @@ -3,7 +3,7 @@ "profiles": { "keyword_match": { "biz": "keyword_match", - "config": "build/studio-test-ase2krek/configs/pipeline_targets.conf", + "config": "build/studio-test-un9yc4ks/configs/pipeline_targets.conf", "dataset": "/home/ubuntu/project/llm-ops-agy/data/corpus_keyword_match.txt", "batch_size": 2, "device_id": 0, diff --git a/tests/integration/demo/test_demo_runner.cpp b/tests/integration/demo/test_demo_runner.cpp index b0bfe888..aa2d1150 100644 --- a/tests/integration/demo/test_demo_runner.cpp +++ b/tests/integration/demo/test_demo_runner.cpp @@ -392,17 +392,14 @@ TEST(DemoRunnerTest, ProfileOwnsExecutionSettings) { {{"schema_version", 2}, {"profiles", {{"execution", value}}}}); }; write_profile(profile); - const char* args[] = {"alg_demo", "--profile", "execution", "--dataset", - "custom.txt"}; DemoOptions cli, merged; + cli.profile = "execution"; std::string error; - ASSERT_EQ(ParseCommandLine(5, const_cast(args), &cli, &error), 0); ASSERT_EQ(LoadAndMergeProfiles(path, cli, &merged, &error), 0) << error; EXPECT_EQ(merged.batch_size, 4); EXPECT_EQ(merged.device_id, 2); EXPECT_EQ(merged.chip, "cuda"); EXPECT_EQ(merged.depth_num, 8u); - EXPECT_EQ(merged.dataset_path, "custom.txt"); auto defaults = profile; for (const char* field : {"batch_size", "device_id", "chip", "depth"})