chore: initialize repository

This commit is contained in:
2026-09-11 09:02:02 +08:00
commit 9a9804d6d8
5 changed files with 3135 additions and 0 deletions
File diff suppressed because one or more lines are too long
+777
View File
@@ -0,0 +1,777 @@
<!-- Generated by Trae Work -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>技术选型与第一阶段架构方案 — 材料物性激光参数智能匹配系统</title>
<style>
:root {
/* Page / report tokens — Business Blue */
--page-bg: #FFFFFF;
--page-surface: #F5F8FC;
--page-surface-muted: #EDF2F9;
--page-text: #1B2430;
--page-text-secondary: #3D4756;
--page-text-muted: #66717F;
--page-text-disabled: #9AA3AF;
--page-border: #DCE3EC;
--page-brand: #0969DA;
--page-brand-hover: #0757B5;
--page-brand-active: #05468C;
--page-brand-soft: #EAF2FC;
--page-brand-soft-strong: #D6E6F8;
--page-brand-text: #05468C;
/* Backward-compatible report variables */
--bg: #FFFFFF;
--bg2: #F5F8FC;
--rule: #DCE3EC;
--ink: #1B2430;
--muted: #66717F;
--text-secondary: #3D4756;
--text-disabled: #9AA3AF;
--accent: #0969DA;
--accent-hover: #0757B5;
--accent-active: #05468C;
--accent-soft: #EAF2FC;
--accent2: #8250DF;
/* Chart / data tokens */
--chart-series-1: #0969DA;
--chart-series-2: #8250DF;
--chart-series-3: #06B6D4;
--chart-series-4: #BF3989;
--chart-other: #DCE3EC;
--chart-accent: #8250DF;
--chart-accent-2: #06B6D4;
--chart-positive: #52C41A;
--chart-warning: #FAAD14;
--chart-negative: #FF4D4F;
--chart-grid: rgba(27, 36, 48, 0.12);
--chart-axis: #66717F;
--chart-label: #66717F;
--chart-tooltip-bg: #FFFFFF;
/* Semantic compatibility tokens */
--success: #52C41A;
--info: #0969DA;
--reminder: #FF7A45;
--warning: #FAAD14;
--danger: #FF4D4F;
--positive: #52C41A;
--negative: #FF4D4F;
}
/* === Structural variables === */
:root {
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--space-7: 48px;
--space-8: 64px;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-pill: 999px;
--font-sans: 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', system-ui, sans-serif;
--font-serif: Georgia, 'Times New Roman', serif;
--font-mono: 'SFMono-Regular', Consolas, 'JetBrains Mono', monospace;
--font-metric: var(--font-sans);
--max: 960px;
}
/* === Base styles === */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 16px; scroll-behavior: smooth; }
body {
font-family: var(--font-sans);
color: var(--ink);
background: var(--bg);
font-size: 14px;
line-height: 1.7;
padding: 2rem 0;
}
article.page { width: 100%; }
.page__content,
.report-intro__surface {
width: calc(100% - 2rem);
max-width: var(--max);
margin: 0 auto;
}
/* === Intro === */
.report-intro { margin-bottom: var(--space-7); }
.report-intro__surface {
position: relative;
isolation: isolate;
overflow: hidden;
color: var(--page-brand-text, var(--ink));
background: var(--page-brand-soft, var(--page-surface-muted, var(--bg2)));
border-radius: var(--radius-lg);
padding: var(--space-7);
}
.report-intro__content { position: relative; z-index: 1; max-width: 760px; }
.report-intro:not(.report-intro--integrated):not(.report-intro--stage):not(.report-intro--with-media):not(.report-intro--plain) .report-intro__surface::before,
.report-intro:not(.report-intro--integrated):not(.report-intro--stage):not(.report-intro--with-media):not(.report-intro--plain) .report-intro__surface::after {
content: "";
position: absolute;
z-index: 0;
pointer-events: none;
}
.report-intro:not(.report-intro--integrated):not(.report-intro--stage):not(.report-intro--with-media):not(.report-intro--plain) .report-intro__surface::before {
width: 180px; height: 180px; top: -72px; right: -48px;
border-radius: 50%;
background: var(--page-brand-soft-strong, var(--page-surface-muted, var(--bg2)));
opacity: 0.72;
}
.report-intro:not(.report-intro--integrated):not(.report-intro--stage):not(.report-intro--with-media):not(.report-intro--plain) .report-intro__surface::after {
width: 136px; height: 96px; right: 96px; bottom: -36px;
border-radius: var(--radius-lg);
background: var(--page-surface, var(--bg));
opacity: 0.58;
transform: rotate(-8deg);
}
.report-intro h1 { line-height: 1.25; overflow-wrap: anywhere; font-size: 28px; }
.report-intro__meta {
margin-top: var(--space-2);
font-size: 13px;
color: var(--page-text-muted);
}
.report-intro__summary {
max-width: 70ch;
margin-top: var(--space-3);
color: var(--page-text-secondary, var(--text-secondary, var(--muted)));
}
@media (max-width: 768px) {
body { padding: 1rem 0; }
.report-intro__surface { padding: var(--space-5); }
.report-intro h1 { font-size: 22px; }
}
@media print, (forced-colors: active) {
.report-intro__surface::before,
.report-intro__surface::after { display: none; }
}
/* === Sections & headings === */
main > section { margin-bottom: var(--space-7); }
h2 {
font-size: 21px;
line-height: 1.4;
margin-bottom: var(--space-4);
padding-bottom: var(--space-2);
border-bottom: 1px solid var(--rule);
}
h3 { font-size: 17px; line-height: 1.5; margin: var(--space-5) 0 var(--space-2); }
p { margin-bottom: var(--space-3); }
ul, ol { margin: 0 0 var(--space-3) 1.25em; }
li { margin-bottom: var(--space-1); }
strong { font-weight: 600; color: var(--ink); }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); text-decoration: underline; }
sup a { font-size: 11px; }
.next-step { color: var(--accent); font-weight: 600; }
/* === Tables === */
.table-wrap { width: 100%; overflow-x: auto; }
table { width: 100%; border-collapse: collapse; table-layout: auto; margin-bottom: var(--space-4); }
caption {
caption-side: top; text-align: left;
font-size: 13px; color: var(--muted);
padding-bottom: var(--space-2); font-weight: 500;
}
th, td {
padding: var(--space-2) var(--space-3);
border-bottom: 1px solid var(--rule);
text-align: left;
vertical-align: top;
overflow-wrap: anywhere;
font-size: 13.5px;
}
thead th {
background: var(--page-surface);
font-weight: 600;
color: var(--text-secondary);
border-bottom: 2px solid var(--page-border);
}
th[scope="row"] { font-weight: 500; color: var(--text-secondary); }
/* === Tags === */
.tag {
display: inline-block;
font-size: 12px;
line-height: 1;
padding: 4px 10px;
border-radius: var(--radius-pill);
border: 1px solid var(--page-border);
background: var(--page-surface);
color: var(--text-secondary);
white-space: nowrap;
}
.tag--risk-high { border-color: var(--danger); color: var(--danger); }
.tag--risk-mid { border-color: var(--warning); color: var(--reminder); }
.tag--risk-low { border-color: var(--success); color: var(--positive); }
.tag--keep { border-color: var(--accent); color: var(--accent); }
/* === Callouts === */
.callout {
background: var(--page-surface);
border: 1px solid var(--page-border);
border-radius: var(--radius-md);
padding: var(--space-3) var(--space-4);
margin: var(--space-4) 0;
font-size: 13.5px;
}
.callout__label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.05em;
margin-bottom: var(--space-1);
color: var(--page-text-secondary);
}
.callout--risk .callout__label { color: var(--reminder); }
/* === Code / tree === */
pre.tree {
background: var(--page-surface);
border: 1px solid var(--page-border);
border-radius: var(--radius-md);
padding: var(--space-4);
overflow-x: auto;
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.65;
margin-bottom: var(--space-4);
}
pre.tree .c { color: var(--muted); }
pre.tree .b { color: var(--page-brand); font-weight: 600; }
code.inline {
background: var(--page-surface-muted);
border-radius: var(--radius-sm);
padding: 1px 6px;
font-family: var(--font-mono);
font-size: 12.5px;
}
/* === Figure (diagram) === */
figure.diagram {
margin: var(--space-4) 0 var(--space-5);
border: 1px solid var(--page-border);
border-radius: var(--radius-lg);
padding: var(--space-4);
background: var(--bg);
}
figure.diagram .mermaid { display: flex; justify-content: center; }
figure.diagram figcaption {
text-align: center;
font-size: 13px;
color: var(--muted);
margin-top: var(--space-3);
}
/* === Footer sources === */
footer { border-top: 1px solid var(--rule); padding-top: var(--space-5); margin-top: var(--space-7); }
footer h2 { border-bottom: none; font-size: 17px; margin-bottom: var(--space-3); }
.sources ol { font-size: 13px; color: var(--text-secondary); margin-left: 1.25em; }
.sources li { margin-bottom: var(--space-2); overflow-wrap: anywhere; }
@media print {
body { padding: 0; }
.report-intro__surface { border: 1px solid var(--page-border); }
main > section { break-inside: auto; }
figure.diagram, table, .callout { break-inside: avoid; }
}
</style>
</head>
<body>
<article class="page">
<header class="report-intro">
<div class="report-intro__surface">
<div class="report-intro__content">
<h1>技术选型与第一阶段架构方案</h1>
<p class="report-intro__meta">基于材料物性参数的激光加工参数智能匹配系统 · SIT 创新训练项目 · 2026-09 · v1.0</p>
<p class="report-intro__summary">
经建模方法、实验设计、工程化部署三路并行调研验证:企划书的技术路线整体成立,无需推翻;本次共形成
<strong>9 项选型决策</strong>,其中新增 TabPFN 第四模型候选与 Conformal Prediction 统一不确定性层两项增强,
明确主动学习框架采用 Ax/BoTorch(避开已停止维护的方案),GPR 的 ONNX 导出列为受控风险项。
第一阶段(当前)搭建范围为<strong>数据层与工程底座</strong>,按 8 周里程碑推进。
</p>
</div>
</div>
</header>
<div class="page__content">
<main>
<section id="summary">
<h2>1. 执行摘要:决策一览</h2>
<p>下表汇总本次技术选型的全部核心决策。<span class="next-step">加粗项为相对企划书的变更或增强</span>,其余为调研确认沿用。</p>
<div class="table-wrap">
<table>
<caption>表 1 · 技术选型决策总表</caption>
<thead>
<tr>
<th scope="col" style="width:18%">决策项</th>
<th scope="col" style="width:44%">调研后决策</th>
<th scope="col" style="width:38%">关键理由</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">建模主力</th>
<td><span class="tag tag--keep">沿用</span> GPR + XGBoost + 随机森林三模型对比,GPR 为主推</td>
<td>小样本(300–500 组)下 GPR 天然输出均值与方差,不确定性估计最直接<sup><a href="#cite-2">[2]</a></sup></td>
</tr>
<tr>
<th scope="row">新增候选</th>
<td><strong>增加 TabPFN 作为第四候选</strong></td>
<td>预训练表格 Transformer,免调参,2025 年小样本基准表现突出<sup><a href="#cite-1">[1]</a></sup><sup><a href="#cite-3">[3]</a></sup></td>
</tr>
<tr>
<th scope="row">不确定性量化</th>
<td><strong>增加 Conformal Prediction 统一包装层</strong>(MAPIE 实现),与 GPR 原生区间并行输出</td>
<td>模型无关的覆盖保证,使四种模型置信区间可公平对比<sup><a href="#cite-4">[4]</a></sup></td>
</tr>
<tr>
<th scope="row">多输出策略</th>
<td>MultiOutputRegressor 独立建模三个输出(功率/速率/频率)</td>
<td>三输出相关性弱,链式回归无益;多任务学习留待 2027 扩展<sup><a href="#cite-6">[6]</a></sup></td>
</tr>
<tr>
<th scope="row">主动学习框架</th>
<td><strong>明确采用 Ax/BoTorch</strong>(qEI / qNEI 批量采集);避开 scikit-optimize 与 modAL</td>
<td>Ax 活跃维护(2026.06 发布 1.3.0),原生批量采集匹配物理实验批次模式<sup><a href="#cite-7">[7]</a></sup>skopt 已于 2024.02 归档<sup><a href="#cite-8">[8]</a></sup></td>
</tr>
<tr>
<th scope="row">超参调优</th>
<td>OptunaTPE 采样器)</td>
<td>成熟活跃,TPE 适合中小搜索空间;与 Ax 职责分离、不重复造轮子</td>
</tr>
<tr>
<th scope="row">模型导出</th>
<td><span class="tag tag--keep">沿用</span> ONNX + joblib 双格式;<strong>GPR 导出后强制做 float64 精度对比</strong></td>
<td>sklearn-onnx 官方支持 GPR,但需 DoubleTensorType,存在精度差异风险<sup><a href="#cite-11">[11]</a></sup><sup><a href="#cite-12">[12]</a></sup></td>
</tr>
<tr>
<th scope="row">数据管理</th>
<td><span class="tag tag--keep">沿用</span> SQLite + CSV;不引入 DVC / MLflow</td>
<td>500 组规模、5 人团队下为零运维方案;版本追踪交给 Git</td>
</tr>
<tr>
<th scope="row">工程规范</th>
<td><strong>明确工程骨架标准</strong>uv + src layout + pydantic-settings + pytest + ruff</td>
<td>20252026 Python 社区共识工具链,学生团队可长期维护</td>
</tr>
</tbody>
</table>
</div>
<div class="callout">
<p class="callout__label">下一步行动</p>
<p>确认本方案后,即可按第 7 节的工程结构初始化代码仓库,并启动第 8 节的 W1–W2 里程碑:工程骨架、数据模型(pydantic)、SQLite 库表三项先行。</p>
</div>
</section>
<section id="background">
<h2>2. 调研背景与方法</h2>
<p>企划书确定的技术路线为「数据采集 → 模型训练 → 封装交付」三阶段闭环:阶段一(2026.05–12)完成 5 类材料、300 组以上的物性-参数-效果映射数据;阶段二(2027)完成 GPR / XGBoost / 随机森林三模型对比与留一材料交叉验证,并扩展深度学习方法;阶段三(2028)完成 ONNX + FastAPI 推理服务封装与厂商试用。项目当前处于阶段一执行期(2026.09)。</p>
<p>企划书中已给出的技术方案属于初期调研,允许中途调整。为在正式开发前锁定第一批技术决策,本次围绕三个方向展开并行调研:</p>
<ul>
<li><strong>建模方法</strong>:小样本表格回归的模型基准、不确定性量化、跨材料泛化与多输出策略;</li>
<li><strong>实验设计与主动学习</strong>:支持物理实验批次采集的框架现状与维护状态;</li>
<li><strong>工程化部署</strong>:ONNX 导出可行性(特别是 GPR)、API 服务、数据管理与工程规范。</li>
</ul>
<p>调研重点覆盖 2024–2026 年公开资料,结论以「确认沿用 / 修改 / 新增」三类标注,与企划书方案逐项对照。</p>
</section>
<section id="modeling">
<h2>3. 建模层选型</h2>
<h3>3.1 模型池:保留三基线,新增 TabPFN</h3>
<p>企划书提出的 GPRRBF 核 + WhiteKernel)、XGBoost、随机森林三种模型组合在 2026 年仍是小样本表格回归的合理基线。GPR 在小样本场景下可同时输出预测均值与方差,是置信区间需求下最直接的方案<sup><a href="#cite-2">[2]</a></sup>;XGBoost 与随机森林提供精度与稳健性参照,且随机森林可输出特征重要性,辅助验证物性特征筛选<sup><a href="#cite-3">[3]</a></sup></p>
<p><strong>本次新增 TabPFN 作为第四候选。</strong>TabPFN 是在合成表格数据上预训练的 Transformer,无需调参即可在中小样本表格任务上取得强结果,且推理速度快;2025 年基准评测中表现突出<sup><a href="#cite-1">[1]</a></sup>。材料信息学方向的工作(如 ICL-FM 将 TabPFN 与材料嵌入结合)也验证了 in-context learning 方法在小样本材料属性预测中的潜力<sup><a href="#cite-5">[5]</a></sup>——这与本项目「留一材料」的跨材料泛化目标天然契合。TabPFN 仅作对比候选,不作为主线依赖(见第 9 节风险表)。</p>
<p>LightGBM 在小样本场景下相对不利,不纳入首轮对比<sup><a href="#cite-3">[3]</a></sup>CatBoost 留作 2027 年数据量扩展后的备选。</p>
<h3>3.2 不确定性量化:GPR 原生区间 + Conformal 统一包装</h3>
<p>预测置信区间是本系统对外的核心承诺(企划书要求覆盖率 ≥ 90%)。决策采用双轨:</p>
<ul>
<li><strong>主线</strong>:GPR 后验分布直接输出均值 ± 95% 区间,无需额外校准;</li>
<li><strong>统一层</strong>:对四种候选模型统一追加 Conformal Prediction(保形预测)包装(MAPIE 的 SplitConformalRegressor),使 GPR、XGBoost、RF、TabPFN 的区间输出在同一覆盖率标准下公平对比<sup><a href="#cite-4">[4]</a></sup></li>
</ul>
<p>Conformal Prediction 在有限校准集下提供覆盖率保证,不依赖模型形式,是当前小样本回归不确定性量化的主流做法<sup><a href="#cite-4">[4]</a></sup>。NGBoost(参数化分布输出)作为备选记录,不纳入首轮实现。</p>
<h3>3.3 多输出策略:独立建模</h3>
<p>系统输出为三维连续值(功率百分比、走光速率、脉冲频率)。三者的物理相关性较弱(分别受能量耦合、扫描机械、脉冲时序主导),调研确认小样本表格场景下<strong>独立建模三个输出(MultiOutputRegressor)是最务实的选择</strong><sup><a href="#cite-6">[6]</a></sup>;链式回归(RegressorChain)仅在输出强相关时有增益。企划书中 2027 年的多任务学习架构规划保留不变,作为数据量突破 500 组后的扩展方向。</p>
<h3>3.4 跨材料泛化:特征工程优先</h3>
<p>留一材料交叉验证(LOMO CV)是本项目区别于常规回归任务的核心评估协议。提升 LOMO 泛化的优先手段是<strong>特征工程</strong>:以物理意义明确的物性参数(反射率、吸收率、熔点/Tg、热导率、密度、粗糙度)构成统一特征空间,保证数值跨材料可比、量纲标准化一致。企划书提出的「大类独立训练 + 子类微调」分层策略保留为数据量不足时的备选方案;TabPFN 的 in-context 特性为跨材料泛化提供了额外一条低成路验证路径<sup><a href="#cite-1">[1]</a></sup></p>
</section>
<section id="active-learning">
<h2>4. 实验设计与主动学习选型</h2>
<h3>4.1 框架现状与决策</h3>
<p>本项目数据采集的特殊性在于:实验是<strong>串行批次</strong>的物理过程(一批做完再决定下一批),而非纯数字模拟,因此框架必须支持批量采集函数(batch acquisition)。调研对比如下:</p>
<div class="table-wrap">
<table>
<caption>表 2 · 主动学习 / 贝叶斯优化框架对比</caption>
<thead>
<tr>
<th scope="col">框架</th>
<th scope="col">维护状态</th>
<th scope="col">批量采集</th>
<th scope="col">结论</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Ax / BoTorch</th>
<td>活跃(Ax 1.3.02026.06<sup><a href="#cite-7">[7]</a></sup></td>
<td>原生 qEI / qNEI / qEHVI<sup><a href="#cite-9">[9]</a></sup></td>
<td><span class="tag tag--keep">主选</span></td>
</tr>
<tr>
<th scope="row">Optuna</th>
<td>活跃</td>
<td>较弱</td>
<td><span class="tag">超参调优专用</span></td>
</tr>
<tr>
<th scope="row">scikit-optimize</th>
<td>2024.02 已归档<sup><a href="#cite-8">[8]</a></sup></td>
<td></td>
<td><span class="tag tag--risk-high">避开</span></td>
</tr>
<tr>
<th scope="row">modAL</th>
<td>基本停滞</td>
<td>有限</td>
<td><span class="tag tag--risk-high">避开</span></td>
</tr>
<tr>
<th scope="row">scikit-activeml</th>
<td>活跃(1.0.02025.12</td>
<td>有限</td>
<td><span class="tag">备选</span></td>
</tr>
<tr>
<th scope="row">Dragonfly / SMAC3</th>
<td>维护中</td>
<td>支持并行 / 弱</td>
<td><span class="tag">不采用</span></td>
</tr>
</tbody>
</table>
</div>
<p>决策:主动学习环节采用 <strong>Ax/BoTorch</strong>。其 GPR 内核与建模层主力模型同源,采集函数直接复用训练好的 GPR 不确定性;qNEI 等批量采集函数支持「一次推荐一批 10–20 组参数」的物理实验节奏<sup><a href="#cite-9">[9]</a></sup>。超参调优独立使用 Optuna(TPE),两者职责清晰互不干扰。材料实验领域的自主优化平台(如 NREL ALchemist<sup><a href="#cite-10">[10]</a></sup>)验证了此类工作流在实验科学中的可行性,可作为架构参考。</p>
<h3>4.2 采集工作流:LHS 冷启动 → 主动学习</h3>
<ul>
<li><strong>初始采样</strong>:使用 <code class="inline">scipy.stats.qmc.LatinHypercube</code> 生成每种材料 30–40 组初始参数组合(拉丁超立方保证低维空间覆盖均匀);</li>
<li><strong>主动学习循环</strong>:初始数据训练 GPR 后,Ax 以 qNEI 推荐下一批 10–20 组实验,模型不确定性高的参数区域优先被探索;</li>
<li><strong>停止条件</strong>:留一材料验证误差收敛或单材料实验预算(80 组)耗尽。</li>
</ul>
<p>该工作流将企划书「主动学习引导的高效实验采集」创新点落实为可执行方案,且与阶段二的建模管线共享同一套 GPR 基础设施,无额外维护成本。</p>
</section>
<section id="engineering">
<h2>5. 工程化栈选型</h2>
<h3>5.1 模型导出:ONNX 保留,GPR 列为受控风险</h3>
<p>sklearn-onnx 官方支持 GaussianProcessRegressor 的导出<sup><a href="#cite-12">[12]</a></sup>,但官方示例明确要求使用 DoubleTensorTypefloat64)而非默认 float32,因为 GPR 的矩阵运算在 float32 下存在精度差异<sup><a href="#cite-11">[11]</a></sup>。XGBoost 与随机森林的 ONNX 导出成熟<sup><a href="#cite-12">[12]</a></sup>。决策:</p>
<ul>
<li>沿用 ONNX + joblib 双格式交付方案;</li>
<li><strong>GPR 导出流程中强制插入精度对比环节</strong>(同一测试集上 sklearn 原生预测 vs ONNX Runtime 预测,误差超过阈值即回退 joblib + FastAPI 直载方案);</li>
<li>该风险不阻塞第一阶段开发,2027 年模型定型时再验证。</li>
</ul>
<h3>5.2 API 服务与数据管理</h3>
<p>FastAPI 方案确认可行:pydantic v2 承担请求/响应校验,模型在 lifespan 钩子中单次加载(避免每请求重复加载),CPU 推理走同步 endpoint 由 FastAPI 线程池处理,满足 ≤100ms 响应要求。数据管理沿用 SQLite + CSV:单文件零运维、5 人团队可直接共享,CSV 作为对外交付格式;DVC 与 MLflow 在当前数据规模(≤500 组)下属过度工程,明确不引入,数据版本追踪由 Git 提交记录承担。</p>
<h3>5.3 设备采集与工程规范</h3>
<p>串口通信采用 pyserial(活跃维护,支持 Python 3.10+<sup><a href="#cite-13">[13]</a></sup>),按 producer-consumer 模式组织:后台读线程持续读取设备状态,主逻辑通过队列消费<sup><a href="#cite-14">[14]</a></sup>。工程规范一次性定标准,避免后期重构:</p>
<ul>
<li><strong>包管理</strong>uv20252026 Python 社区主流,速度快、锁文件确定性);</li>
<li><strong>项目结构</strong>src layout<code class="inline">src/lmpm/</code>,包名取 laser-material-parameter-matching 缩写);</li>
<li><strong>配置</strong>pydantic-settings(类型安全的环境变量与配置文件管理);</li>
<li><strong>测试与质量</strong>pytest + rufflint 与格式化二合一)。</li>
</ul>
</section>
<section id="architecture">
<h2>6. 系统架构设计</h2>
<p>系统按「数据层 → 模型层 → 服务层」三层组织,工程底座贯穿全程。主动学习闭环是架构中的关键反馈路径:模型层的不确定性评估反向驱动数据层的下一批实验设计。图中实线为数据流,蓝色虚线为主动学习反馈。</p>
<figure class="diagram">
<pre class="mermaid">
flowchart TB
IN1(["材料物性测量<br/>光谱仪 · 粗糙度仪 · DSC"])
IN2(["激光加工实验<br/>HZZ-M300U · 355nm"])
subgraph P1["阶段一 · 数据层(2026.0512 · 本次搭建)"]
direction LR
D1["实验设计 DoE<br/>LHS + Ax 主动学习"]
D2["数据采集<br/>pyserial + 显微镜"]
D3["数据存储<br/>SQLite + CSV"]
D1 --> D2 --> D3
end
subgraph P2["阶段二 · 模型层(2027"]
direction LR
M1["模型训练<br/>GPR · XGB · RF · TabPFN"]
M2["评估与 UQ<br/>LOMO CV · Conformal"]
M3["超参调优<br/>Optuna TPE"]
M1 --> M2
M3 -.-> M1
end
subgraph P3["阶段三 · 服务层(2028"]
direction LR
S1["推理引擎<br/>ONNX + joblib"]
S2["REST API<br/>FastAPI · pydantic v2"]
S3["容器交付<br/>Docker"]
S1 --> S2 --> S3
end
OUT(["激光设备控制软件 / 厂商数据产品"])
IN1 --> P1
IN2 --> P1
D3 --> M1
M2 --> S1
S3 --> OUT
M2 -. 主动学习反馈 .-> D1
classDef neutral fill:#F5F8FC,stroke:#DCE3EC,color:#1B2430;
classDef focus fill:#EAF2FC,stroke:#0969DA,color:#05468C,stroke-width:1.5px;
classDef external fill:#FFFFFF,stroke:#66717F,color:#3D4756;
class IN1,IN2,OUT external;
class D1,D2,D3 focus;
class M1,M2,M3,S1,S2,S3 neutral;
style P1 stroke:#0969DA,stroke-width:2px,fill:#FFFFFF,color:#05468C;
style P2 stroke:#DCE3EC,fill:#FFFFFF,color:#3D4756;
style P3 stroke:#DCE3EC,fill:#FFFFFF,color:#3D4756;
linkStyle 11 stroke:#0969DA,stroke-width:1.8px;
</pre>
<figcaption>图 1 · 系统三阶段技术架构(虚线为主动学习反馈闭环;阶段一为当前搭建范围)</figcaption>
</figure>
<h3>6.1 模块职责</h3>
<div class="table-wrap">
<table>
<caption>表 3 · 核心模块职责划分</caption>
<thead>
<tr>
<th scope="col" style="width:22%">模块</th>
<th scope="col" style="width:20%">所属阶段</th>
<th scope="col">职责</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">domain(领域模型)</th><td>阶段一</td><td>pydantic 定义材料物性、实验记录、加工参数、质量评分四类实体,全链路类型校验</td></tr>
<tr><th scope="row">doe(实验设计)</th><td>阶段一</td><td>LHS 初始采样、参数空间定义、主动学习批次推荐(对接 Ax)</td></tr>
<tr><th scope="row">data(数据存取)</th><td>阶段一</td><td>SQLite 读写、CSV 导入导出、数据校验与清洗</td></tr>
<tr><th scope="row">device(设备采集)</th><td>阶段一</td><td>pyserial 串口状态读取、实验参数自动同步记录</td></tr>
<tr><th scope="row">ml(模型管线)</th><td>阶段二</td><td>四模型训练、LOMO 交叉验证、Conformal 包装、超参调优</td></tr>
<tr><th scope="row">api(推理服务)</th><td>阶段三</td><td>FastAPI REST 接口、ONNX Runtime 推理、置信区间输出</td></tr>
</tbody>
</table>
</div>
</section>
<section id="structure">
<h2>7. 项目工程结构</h2>
<p>第一阶段按以下骨架初始化仓库(阶段二、三的目录预留占位,随进度填充):</p>
<pre class="tree">lemdb/
├── pyproject.toml <span class="c"># uv 管理:依赖声明、ruff/pytest 配置</span>
├── README.md
├── .gitignore <span class="c"># data/*.db 等产物不入库</span>
├── src/lmpm/ <span class="b"># 主包:laser material parameter matching</span>
│ ├── config.py <span class="c"># pydantic-settings:路径、设备、参数范围</span>
│ ├── domain/ <span class="b"># 领域数据模型(第一阶段核心)</span>
│ │ ├── material.py <span class="c"># MaterialProperty:反射率/吸收率/熔点/热导率/密度/粗糙度</span>
│ │ ├── experiment.py <span class="c"># ExperimentRecord / ProcessingParams / QualityMetrics</span>
│ │ └── doe.py <span class="c"># ParameterSpace / ExperimentDesign</span>
│ ├── data/
│ │ ├── store.py <span class="c"># SQLite 读写层</span>
│ │ ├── io_csv.py <span class="c"># CSV 导入导出(交付格式)</span>
│ │ └── validate.py <span class="c"># 入库前校验:范围/缺失/重复</span>
│ ├── doe/
│ │ ├── initial.py <span class="c"># LHS 初始采样(scipy QMC</span>
│ │ └── active.py <span class="c"># Ax 主动学习批次推荐(阶段一末启用)</span>
│ ├── device/
│ │ └── serial_recorder.py <span class="c"># pyserial 采集(协议确认后开发)</span>
│ ├── ml/ <span class="b"># 阶段二:train / evaluate / uq</span>
│ └── api/ <span class="b"># 阶段三:main.pyFastAPI</span>
├── scripts/
│ ├── init_db.py <span class="c"># 初始化 SQLite 库表</span>
│ ├── generate_doe.py <span class="c"># 生成参数网格 CSV</span>
│ └── record_experiment.py <span class="c"># 实验记录录入 CLI</span>
├── tests/ <span class="c"># pytestdomain 校验 / store 读写 / doe 生成</span>
├── data/ <span class="c"># SQLite 库文件与 CSVgitignore</span>
└── docs/
└── data_dictionary.md <span class="c"># 数据字典:字段、单位、测量方法、溯源</span></pre>
<h3>7.1 依赖清单(按阶段引入)</h3>
<div class="table-wrap">
<table>
<caption>表 4 · Python 依赖引入计划</caption>
<thead>
<tr>
<th scope="col" style="width:18%">阶段</th>
<th scope="col" style="width:52%">依赖</th>
<th scope="col">用途</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">阶段一</th>
<td><code class="inline">pydantic pydantic-settings pyserial scipy pandas typer</code></td>
<td>数据模型 / 配置 / 串口 / LHS 采样 / 数据处理 / CLI</td>
</tr>
<tr>
<th scope="row">阶段二</th>
<td><code class="inline">scikit-learn xgboost tabpfn optuna ax-platform botorch mapie</code></td>
<td>四模型训练 / 调优 / 主动学习 / Conformal 区间</td>
</tr>
<tr>
<th scope="row">阶段三</th>
<td><code class="inline">fastapi uvicorn skl2onnx onnxruntime</code></td>
<td>REST 服务 / 模型导出与推理</td>
</tr>
<tr>
<th scope="row">全程</th>
<td><code class="inline">pytest ruff</code></td>
<td>测试 / 代码质量</td>
</tr>
</tbody>
</table>
</div>
<p>分阶段引入依赖可保持前期环境轻量(阶段一无需安装 PyTorch 系的 Ax/BoTorch),也避免了当前 Windows/Linux 混合环境下的编译问题。</p>
</section>
<section id="roadmap">
<h2>8. 第一阶段实施路线(8 周)</h2>
<p>对齐企划书「2026.05–12 完成数据采集与首批 300 组数据」的目标,从当前时点起按 8 周里程碑推进:</p>
<div class="table-wrap">
<table>
<caption>表 5 · 第一阶段 8 周里程碑</caption>
<thead>
<tr>
<th scope="col" style="width:14%">周次</th>
<th scope="col" style="width:46%">交付物</th>
<th scope="col">验收标准</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">W1W2</th><td>工程骨架 + 领域模型 + SQLite 库表</td><td><code class="inline">uv sync</code> 可装、pytest 全绿、库表可建可写</td></tr>
<tr><th scope="row">W3</th><td>DoE 生成器(LHS 初始采样)</td><td>生成亚克力 40 组参数网格 CSV,范围符合设备量程</td></tr>
<tr><th scope="row">W4W5</th><td>实验记录工作流(CLI 录入 + 串口采集)</td><td>单条实验记录全字段校验入库,重复/越界被拦截</td></tr>
<tr><th scope="row">W6</th><td>首批数据:亚克力 + 椴木 ≥120 组,数据字典 v1</td><td>完整率 100%EDA 快照可复现</td></tr>
<tr><th scope="row">W7</th><td>基线模型试跑(GPR / XGBoost</td><td>LOMO 交叉验证管线跑通(不考核精度)</td></tr>
<tr><th scope="row">W8</th><td>主动学习接口预留 + 中期检查文档</td><td>Ax 环境可运行 qNEI 批量推荐 demo</td></tr>
</tbody>
</table>
</div>
<div class="callout callout--risk">
<p class="callout__label">进度风险提示</p>
<p>串口自动采集依赖厂商提供 HZZ-M300U 的通信协议文档;若 W4 前未取得,立即切换为「CLI 手工录入」模式兜底,不影响 W6 数据目标。企划书中 2026.06 完成串口开发的计划以此风险开关为条件。</p>
</div>
</section>
<section id="risks">
<h2>9. 风险登记表</h2>
<div class="table-wrap">
<table>
<caption>表 6 · 技术风险与缓解措施</caption>
<thead>
<tr>
<th scope="col" style="width:26%">风险</th>
<th scope="col" style="width:10%">等级</th>
<th scope="col" style="width:28%">影响</th>
<th scope="col">缓解措施</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">GPR 的 ONNX 导出精度差异</th>
<td><span class="tag tag--risk-mid"></span></td>
<td>线上推理结果偏离训练基线</td>
<td>导出后强制 float64 对比验证;备选 joblib + FastAPI 直载<sup><a href="#cite-11">[11]</a></sup></td>
</tr>
<tr>
<th scope="row">HZZ-M300U 串口协议未知</th>
<td><span class="tag tag--risk-mid"></span></td>
<td>自动采集延期,拖累数据目标</td>
<td>W1 起向厂商索取协议;CLI 手工录入兜底</td>
</tr>
<tr>
<th scope="row">小样本 LOMO 精度不达标</th>
<td><span class="tag tag--risk-mid"></span></td>
<td>新材料推荐误差超 8% 目标</td>
<td>特征工程优先;大类分层训练备选;主动学习提高单数据信息量</td>
</tr>
<tr>
<th scope="row">TabPFN 适用边界</th>
<td><span class="tag tag--risk-low"></span></td>
<td>第四候选失效</td>
<td>仅作对比不依赖;主线仍是 GPR / XGBoost</td>
</tr>
<tr>
<th scope="row">5 人团队协作冲突</th>
<td><span class="tag tag--risk-low"></span></td>
<td>代码互踩、数据覆盖</td>
<td>Git 分支规范 + ruff 统一格式 + SQLite 单写入口(store.py</td>
</tr>
</tbody>
</table>
</div>
</section>
</main>
<footer>
<div class="sources">
<h2>参考资料</h2>
<ol>
<li id="cite-1">TabPFN v2 小样本表格基准评测(arXiv, 2025)<a href="https://arxiv.org/html/2505.11325v2" target="_blank" rel="noopener">https://arxiv.org/html/2505.11325v2</a></li>
<li id="cite-2">Gaussian Processes for Small-Sample Regression with UncertaintyBestHub<a href="https://www.besthub.dev/articles/why-gaussian-processes-beat-neural-networks-for-small-sample-regression-with-uncertainty-601d1e4dcfe8" target="_blank" rel="noopener">https://www.besthub.dev/articles/why-gaussian-processes-beat-neural-networks-for-small-sample-regression-with-uncertainty-601d1e4dcfe8</a></li>
<li id="cite-3">表格数据机器学习模型基准综述(arXiv, 2024)<a href="https://arxiv.org/pdf/2408.14817" target="_blank" rel="noopener">https://arxiv.org/pdf/2408.14817</a></li>
<li id="cite-4">Conformal Prediction 与 MAPIE 不确定性量化实践(Python Data Bench<a href="https://pythondatabench.com/article/conformal-prediction-python-mapie-uncertainty" target="_blank" rel="noopener">https://pythondatabench.com/article/conformal-prediction-python-mapie-uncertainty</a></li>
<li id="cite-5">ICL-FM:材料属性预测的 in-context 学习框架(arXiv, 2026<a href="https://arxiv.org/html/2601.00133v1" target="_blank" rel="noopener">https://arxiv.org/html/2601.00133v1</a></li>
<li id="cite-6">scikit-learn 多输出回归实现(MultiOutputRegressor / RegressorChain<a href="https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/multioutput.py" target="_blank" rel="noopener">https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/multioutput.py</a></li>
<li id="cite-7">Ax Platform 更新日志(Meta, 2026.06 发布 1.3.0<a href="https://github.com/facebook/Ax/blob/main/CHANGELOG.md" target="_blank" rel="noopener">https://github.com/facebook/Ax/blob/main/CHANGELOG.md</a></li>
<li id="cite-8">scikit-optimize 归档状态记录(2024.02 起停止维护)<a href="https://github.com/freqtrade/freqtrade/issues/10929" target="_blank" rel="noopener">https://github.com/freqtrade/freqtrade/issues/10929</a></li>
<li id="cite-9">Deep GP 与批量采集函数在实验优化中的应用(arXiv, 2025)<a href="https://arxiv.org/html/2509.14408" target="_blank" rel="noopener">https://arxiv.org/html/2509.14408</a></li>
<li id="cite-10">NREL ALchemist:材料/化学实验主动学习平台<a href="https://github.com/NREL/ALchemist" target="_blank" rel="noopener">https://github.com/NREL/ALchemist</a></li>
<li id="cite-11">sklearn-onnx 官方 GPR 导出示例(DoubleTensorType 精度说明)<a href="https://onnx.ai/sklearn-onnx/auto_examples/plot_gpr.html" target="_blank" rel="noopener">https://onnx.ai/sklearn-onnx/auto_examples/plot_gpr.html</a></li>
<li id="cite-12">sklearn-onnx 支持的模型列表(含 GPR / XGBoost / LightGBM<a href="https://onnx.ai/sklearn-onnx/supported.html" target="_blank" rel="noopener">https://onnx.ai/sklearn-onnx/supported.html</a></li>
<li id="cite-13">pyserial 仓库(活跃维护,Python 3.10+<a href="https://github.com/pyserial/pyserial" target="_blank" rel="noopener">https://github.com/pyserial/pyserial</a></li>
<li id="cite-14">pyserial 官方文档:线程化读取模式<a href="https://www.pyserial.org/docs/performance/threading" target="_blank" rel="noopener">https://www.pyserial.org/docs/performance/threading</a></li>
</ol>
</div>
</footer>
</div>
</article>
<script src="./_shared/js/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'base',
themeVariables: {
primaryColor: '#F5F8FC',
primaryBorderColor: '#DCE3EC',
primaryTextColor: '#1B2430',
lineColor: '#66717F',
fontSize: '14px',
fontFamily: '"PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif',
clusterBkg: '#FFFFFF',
clusterBorder: '#DCE3EC'
},
flowchart: { htmlLabels: true, curve: 'basis' }
});
</script>
</body>
</html>