1. 工程化封装导论
量子算法在论文里通常以数学形式出现:一个酉算子 U、一组量子比特、若干次测量,最后给出期望值或概率分布。但真实工程中,用户不会直接调用一个酉矩阵,他们需要的是一个可安装、可配置、可观测、可回滚的软件组件。两者之间的差距,就是本章要讨论的“工程化封装鸿沟”。
先看一个具体例子。假设我们实现了一个 4 比特的量子近似优化算法(QAOA)求解 MaxCut。在 Jupyter Notebook 中,它可能长这样:
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
def qaoa_maxcut(edges, gamma, beta):
n = max(max(e) for e in edges) + 1
qc = QuantumCircuit(n)
# 初始叠加态
qc.h(range(n))
# 代价层
for i, j in edges:
qc.cx(i, j)
qc.rz(2 * gamma, j)
qc.cx(i, j)
# 混合层
for q in range(n):
qc.rx(2 * beta, q)
qc.measure_all()
return qc
sim = AerSimulator()
result = sim.run(qaoa_maxcut([(0,1),(1,2),(2,3)], 0.8, 0.4), shots=1024).result()
print(result.get_counts())
这段代码能跑,但它不是一个可部署组件。它缺少输入校验、参数边界、后端选择、错误重试、结果结构化输出、日志与指标。更关键的是,调用者必须懂 Qiskit、懂 QAOA、懂如何解释 counts。工程化封装要做的,就是把这些“懂”收敛到组件内部,对外只暴露稳定的接口契约。
为了把“鸿沟”讲清楚,我们用一个分层视图来对比理论态与工程态。下图左侧是算法研究者眼中的对象,右侧是部署工程师眼中的对象,中间是封装层需要补齐的能力。
这张图不是流程,而是“对象与能力”的对照:左边是算法对象,右边是部署对象,中间是封装层必须补齐的六类能力。理解这张图,就能理解为什么“能跑通”和“能上线”是两件事。
课程项目总览
本课程围绕一个贯穿项目展开:将 QAOA MaxCut 封装为可部署的量子计算微服务。项目分四个阶段推进,每个阶段都有可运行的交付物。
| 阶段 | 目标 | 关键交付物 | 验收方式 |
|---|---|---|---|
| P1 算法基线 | 跑通 QAOA 并得到稳定 counts | 可复现的 Notebook + 固定随机种子 | 相同输入两次运行 counts 分布一致 |
| P2 组件封装 | 把算法包装成 Python 类 | QaoaMaxCutSolver 类 + 输入校验 | 非法输入抛出明确异常 |
| P3 服务化 | 暴露 HTTP 接口 | FastAPI 服务 + 配置加载 | curl 调用返回结构化 JSON |
| P4 可观测与部署 | 容器化并接入日志指标 | Dockerfile + 健康检查 + 日志 | 容器启动后 /health 返回 200 |
项目示例参数统一约定:MaxCut 图使用 4 节点环 [(0,1),(1,2),(2,3),(3,0)],QAOA 层数 p=1,参数 gamma=0.8、beta=0.4,shots 默认 1024。这些是教学示例值,不是最优参数;后续章节会讨论参数优化。
开发环境搭建
环境的目标是“可复现”。推荐使用 Python 3.11 + 虚拟环境,依赖锁定到具体版本。以下命令在 Linux/macOS 下执行,Windows 可将 source 替换为对应激活脚本。
python3.11 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install qiskit==1.1.0 qiskit-aer==0.14.2 fastapi==0.111.0 uvicorn==0.30.1 pydantic==2.7.4
pip freeze > requirements.txt
安装完成后,用一段最小脚本验证环境是否可用。注意这里显式固定了随机种子,目的是让结果可复现。
import numpy as np
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
sim = AerSimulator(seed_simulator=42)
tqc = transpile(qc, sim)
counts = sim.run(tqc, shots=1024).result().get_counts()
print(counts) # 预期接近 {'00': 512, '11': 512}
判断环境是否正常的标准有三条:第一,qiskit.__version__ 输出 1.1.0;第二,上述脚本能打印出 counts 且 00 与 11 数量接近;第三,pip check 无依赖冲突。若第二条不满足,优先检查是否误用了真实后端或未设置种子。
config.yaml,把后端类型、shots、超时、日志级别外置。这样从 P1 到 P4 的代码不需要硬编码环境差异,也为后续容器化部署做好准备。
本章建立了三个基本认知:第一,量子算法的理论态与可部署组件之间存在接口、行为、故障、资源四类鸿沟;第二,封装层的价值是把这些鸿沟收敛为稳定的对外契约;第三,贯穿项目将以 QAOA MaxCut 为载体,从 Notebook 逐步演进为可观测的微服务。环境搭建完成后,下一阶段就可以开始把算法本身写得更规范、更可测。