工具能力增加后,页面很容易变成一长串参数:尺寸、编码、质量、批量数、阈值、输出格式、覆盖方式。全部开放,普通用户无法判断组合是否有效;全部隐藏,专业用户又无法完成必要选择。更严重的是,如果页面参数被直接拼进 Worker 命令,所谓"高级设置"会成为不受控的执行入口。
本文用脱敏任务 PT-20261009-002 说明怎样把复杂参数转为受控配置。用户只选择"网页交付"预设和少量业务选项;服务端负责填充默认值、验证依赖、阻止危险组合,并保存可审计的配置快照。示例数据均为教学用途。
环境边界:Java 17、Spring Boot 风格服务层、Python 3.11 Worker、MySQL 8.x。本文讨论配置治理,不公开真实命令、内部模型参数或任何账户自动化能力。
目录
- 参数越多,为什么越不能全靠用户填写
- 固定案例:用户选择意图,系统负责落实细节
- 预设与高级项:哪些该开放,哪些必须固定
- 表单校验:字段正确不等于组合可执行
- 危险参数与审计:拒绝任意命令入口
- 服务层实现:规范化、校验与配置快照
- 预期输出与自动测试
- [SQL 验证与上线验收](#SQL 验证与上线验收)
- 小结和延伸阅读
一、参数越多,为什么越不能全靠用户填写
参数名看起来独立,实际往往互相约束:选择"保留音频"时不能同时选择无音频输出;输入尺寸低于目标尺寸时不能启用强制放大;批处理数量受文件大小和资源配额限制。只做前端必填校验,用户仍会把逻辑矛盾的配置提交到 Worker,失败原因最后变成难以理解的命令报错。
正确目标不是让用户认识所有底层参数,而是让用户能完成明确的业务选择,同时让系统能解释最终使用了哪些值。用户选择的是意图;规范配置才是 Worker 的输入。

图1:页面输入不是 Worker 命令;中间需要预设、依赖校验和规范化配置。
二、固定案例:用户选择意图,系统负责落实细节
任务 PT-20261009-002 只允许用户选择交付目标、是否保留音频和输出语言;系统根据 WEB_DELIVERY 预设固定输出容器、编码策略、最大高度和验收规则。
| 层次 | 示例 | 谁负责 |
|---|---|---|
| 用户意图 | 网页交付、保留音频 | 普通用户 |
| 预设定义 | WEB_DELIVERY |
产品与技术负责人 |
| 执行配置 | maxHeight=1080、container=mp4 |
服务端归一化 |
| 危险项 | 自定义命令、任意输出路径 | 不向普通表单开放 |
| 审计事实 | 预设版本、提交者、规范 JSON | 系统自动记录 |
这不是限制能力,而是把变化放在正确位置:需要新增高质量预设时由配置发布流程评审;用户每次提交只在被允许的范围中组合选项。

图2:预设是能力契约,不是换一个下拉框名称。
三、预设与高级项:哪些该开放,哪些必须固定
是否开放一个参数,取决于它是否能由目标用户安全理解、是否会改变资源上限或安全边界、是否有明确验收方式。
| 参数类型 | 处理方式 | 原因 |
|---|---|---|
| 交付目标、输出语言 | 直接选择 | 用户能理解,影响结果意图 |
| 已定义的清晰度档位 | 受限选择 | 由预设映射到确定值 |
| 批量数量、并行度 | 受配额限制 | 影响资源和排队公平性 |
| 输出路径、命令片段、环境变量 | 不开放 | 会绕过隔离和安全边界 |
| 仅供排障的开关 | 受角色和有效期控制 | 需要留审计证据 |
高级项也不应只是"显示更多"。它需要角色校验、允许范围、有效期和审计理由。否则一次临时排障配置会悄悄成为长期默认值。

图3:开放给用户的选项必须可理解、可验证;影响安全边界的项应留在受控流程。
四、表单校验:字段正确不等于组合可执行
校验至少有三层:字段格式、字段依赖和任务环境。前端负责即时提示,服务端负责最终裁决;不能因为页面已经校验就信任请求。
java
public NormalizedConfig normalize(SubmitOptions options, InputAsset asset) {
Preset preset = presetCatalog.require(options.presetCode());
if (options.keepAudio() && !asset.mediaSummary().hasAudio()) {
throw new IllegalArgumentException("INPUT_HAS_NO_AUDIO");
}
if (options.batchSize() > quotaService.maxBatchSize(options.operatorId())) {
throw new IllegalArgumentException("BATCH_SIZE_EXCEEDED");
}
return preset.apply(options); // 只产出预设允许字段
}
例如"输入没有音频却要求保留音频"是输入与选项的依赖错误;"一次提交 50 个大文件"是配额错误;"传入未知字段"则是契约错误。三者应返回不同错误码和用户提示,不能统一为"参数错误"。
五、危险参数与审计:拒绝任意命令入口
危险参数不是只能靠黑名单过滤。最可靠的做法是白名单:Worker 接收枚举预设和规范字段,不接收 command、outputPath、shellArgs 等自由文本。即便管理角色需要临时覆盖,也应形成受限配置记录,而非将原始字符串传给执行器。
sql
CREATE TABLE tool_config_audit (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
job_id BIGINT NOT NULL,
preset_code VARCHAR(40) NOT NULL,
preset_version VARCHAR(40) NOT NULL,
normalized_json JSON NOT NULL,
risk_level VARCHAR(16) NOT NULL,
operator_id BIGINT NOT NULL,
reason VARCHAR(255) NULL,
created_at DATETIME NOT NULL,
CONSTRAINT ck_risk_level CHECK (risk_level IN ('NORMAL', 'RESTRICTED')),
CONSTRAINT fk_audit_job FOREIGN KEY (job_id) REFERENCES tool_job(id)
);
审计记录的是已生效配置,不是未经处理的页面原文。这样才能回查某个结果是按什么预设、什么版本、由谁以何种理由提交;同时避免把密钥、路径或敏感内容写进日志。

图4:配置审计记录"最终生效了什么",而不是把页面原始请求或敏感信息完整落库。
六、服务层实现:规范化、校验与配置快照
服务层的责任是以同一份预设定义完成校验和归一化,随后创建任务和审计记录。Worker 只读取不可变快照,不能回头读取今天的表单默认值。
java
@Transactional
public String submit(SubmitOptions options) {
InputAsset asset = assetRepository.requireAccepted(options.assetId());
NormalizedConfig config = configService.normalize(options, asset);
ToolJob job = ToolJob.queued(JobNo.next(), asset.getId(), config.fingerprint());
jobRepository.insert(job);
auditRepository.insert(ConfigAudit.of(job.getId(), config, options.operatorId()));
outboxRepository.insert(OutboxEvent.forJob(job.getId()));
return job.getJobNo();
}
fingerprint 应来自预设版本和规范 JSON,而不是字段排列顺序不同的原始请求。这样"1080p"和"1080P"这类展示差异不会制造两种技术配置。
七、预期输出与自动测试
成功受理后,任务查询应展示预设和可解释的摘要:
json
{"jobNo":"PT-20261009-002","preset":"WEB_DELIVERY","presetVersion":"v3","status":"QUEUED","configurationSummary":{"maxHeight":1080,"keepAudio":true}}
java
@Test
void unknownFieldIsRejectedBeforeJobCreation() {
assertThatThrownBy(() -> service.submit(optionsWith("shellArgs", "-x")))
.hasMessage("UNKNOWN_OPTION");
assertThat(jobRepository.count()).isZero();
}
@Test
void audioRequirementMustMatchInputFacts() {
assertThatThrownBy(() -> service.submit(videoWithoutAudioButKeepAudio()))
.hasMessage("INPUT_HAS_NO_AUDIO");
}
还应测试预设升级:新提交可使用 v4,历史任务的审计快照仍然显示 v3 的规范参数。
八、SQL 验证与上线验收
sql
-- 预期结果:0 行。每个任务必须有一份生效配置审计记录。
SELECT j.job_no FROM tool_job j
LEFT JOIN tool_config_audit a ON a.job_id = j.id
WHERE a.id IS NULL;
-- 预期结果:0 行。受限配置必须说明理由。
SELECT job_id FROM tool_config_audit
WHERE risk_level = 'RESTRICTED' AND (reason IS NULL OR reason = '');
-- 预期结果:0 行。Worker 不应收到未定义的预设版本。
SELECT job_id FROM tool_config_audit
WHERE preset_code = '' OR preset_version = '';
上线验收至少覆盖:正常预设提交、字段依赖冲突、超过配额、未知字段、受限配置无理由。预期是只有正常组合进入队列,失败原因可理解,审计记录不包含自由命令或敏感路径。

图5:好用的表单不是参数更少,而是每个开放选项都有边界、校验和可追溯的结果。
九、小结和延伸阅读
参数治理的本质是把"自由输入"转化为"受控意图":预设固定能力边界,服务端验证组合与资源条件,危险项不进入普通请求,最终配置随任务形成审计快照。这样工具既能让用户完成工作,也不会因一个高级输入框失去安全和可复现性。
后续将继续完善质量回归和上线维护:当代码、模型或依赖升级后,如何用固定样本、预期结果和运行证据及时发现结果退化。
参考资料: