Opentrons 液体处理实战指南:Protocol API v2 命令分层、吸头策略与液体分类编程
【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills
本篇技术指南以 scientific-agent-skills 仓库中 skills/opentrons-integration/references/liquid_handling.md 为骨架,完整讲解 Opentrons Flex 与 OT-2 机器人上 Python Protocol API v2 协议中液体处理的命令选型、源目标映射、吸头污染策略、流速与位置控制、液体分类(liquid class)、液体存在检测、部分吸头拾取与序列稀释等核心实操;并结合仓库内的模板脚本与仿真测试,给出可模拟、可验证、可直接落地的完整方案。读完本文,你将能够根据实验的物理需求(而非命令长短)正确选型液体处理命令,写出可审计、可仿真、可安全部署到真机上的 Protocol API v2 协议。
选命令的原则:从实验物理行为出发
在 Opentrons Protocol API v2 中,液体处理存在多个调用层级。一个最常见的错误是"哪个调用写起来最短就选哪个"。液体处理指南明确要求:从实验所需的物理行为选择命令,而不是从编码便利性出发。
无论选择哪一层命令,以下物理量始终是每一条命令的隐含前提:
- 正确的液体体积(源体积、目标体积、死体积、抛洒体积);
- 正确的耗材几何(板/孔/储液槽尺寸与高度偏移);
- 正确的移液器量程与吸头容量;
- 吸头状态(已拾取、已污染、可复用)与污染控制边界。
这三类要素共同决定了命令展开后的物理动作是否安全、准确。
命令分层:三种编程模型
构建块命令(Building-block commands):显式控制每一拍
当吸液与分液需要独立控制(例如粘稠、易挥发、易起泡、低体积或含磁珠工作流)时,使用底层原语:
pipette.pick_up_tip() pipette.aspirate(50, source.bottom(z=1), flow_rate=25) protocol.delay(seconds=1) pipette.dispense(50, destination.bottom(z=2), flow_rate=20, push_out=5) pipette.blow_out(destination.top(z=-1)) pipette.drop_tip()优势:
- 位置与顺序完全显式,命令间不存在隐式行为;
- 每步可独立设置流速与延时;
- 对粘稠、易挥发、易起泡、低体积或磁珠类工作流提供精细控制。
代价:
- 作者必须自行管理吸头状态与体积状态;
- 更容易出现"无吸头时吸液""超出移液器容量""残留体积未处理"等错误。
从仓库的 api_reference.md 可以看到,构建块命令还包括air_gap()、touch_tip()、move_to()等,且 API 2.27 之后aspirate()/dispense()增加了end_location与movement_delay参数、新增了dynamic_mix()。
标准复杂命令:常规源-目标映射
对常规的一对一、一对多、多对一映射,使用高层命令:
pipette.transfer( volume=50, source=source_plate.wells()[:8], dest=destination_plate.wells()[:8], new_tip="always", mix_after=(3, 30), )三个命令的分工:
transfer():一个或多个源到目标的转移;distribute():一个源到多个目标,通常带一个额外的抛洒(disposal)体积;consolidate():多个源汇集到一个目标。
务必检查仿真运行日志。复杂命令会被展开为大量构建块,而展开方式随参数与 API 级别变化。仓库的 test_scripts.py 正是据此断言序列稀释模板的展开结果:11 步稀释对应 11 次 Mixing、1 + 11 + 1次拾取/丢弃吸头、11×2+1次 100 µL 吸液。
液体分类复杂命令(Flex API 2.24+):借用 Opentrons 验证过的液体行为
当吸头/移液器组合受支持、且实验液体与验证模型接近时,使用 Opentrons 验证的液体分类(liquid class):
viscous = protocol.get_liquid_class("glycerol_50") pipette.transfer_with_liquid_class( liquid_class=viscous, volume=50, source=reservoir["A1"], dest=plate["A1"], new_tip="always", trash_location=trash, )相关方法:distribute_with_liquid_class()、consolidate_with_liquid_class()。
已验证的液体分类包括 water(水)、80% 乙醇、50% 甘油。一个液体分类会同时控制多个耦合属性:流速、浸入与回缩行为、延时、空气间隙、位置与 push-out。指南明确警告:不要随意覆盖其中单个属性而不做完整测试——这些属性相互耦合,单独改动可能破坏整体行为。
需要特别注意的适用范围:Opentrons 验证的液体分类仅适用于受支持的 Flex 移液器与吸头组合,不适用于 OT-2 移液器。API 2.24 才引入液体分类(见 api_reference.md 的版本门控表)。
源与目标映射:把映射关系显式化
复杂命令接受单个孔或一个序列。把预期的映射关系写清楚:
| 映射 | 实现方式 |
|---|---|
| 单源 → 单目标 | 一次transfer() |
| 单源 → 多目标 | 重复 transfer 或一次distribute() |
| 多源 → 单目标 | 重复 transfer 或一次consolidate() |
| 等长源/目标列表 | 成对transfer() |
不要假设行优先顺序。耗材迭代通常是按列优先(column-major)进行的(api_reference.md),在安全关键场景中应使用命名孔或显式列表:
# 显式样本顺序更易于审计 sample_wells = [plate[name] for name in ("A1", "B1", "C1", "D1")]多通道移液器的锚定规则:所引用的孔锚定的是移液器的主通道(primary channel)。
- 满 8 通道移液器通常通过引用 A 行孔来寻址整列;
- 满 96 通道移液器寻址整个 96 孔板架或整块板;
- 部分列(partial-column)布局的主通道不同,必须查阅对应布局文档,不能沿用满列的假设。
吸头策略:new_tip是一次污染决策
new_tip本质上是污染边界的编码,而不只是吸头用量优化:
| 策略 | 典型用途 | 主要风险 |
|---|---|---|
"always" | 独立样本、对照、独立的源-目标对 | 吸头消耗更高 |
"once" | 同一污染域内的试剂分发 | 被污染的吸头回到共享源 |
"never" | 显式外包pick_up_tip()与drop_tip() | 隐藏或无效的吸头状态 |
共享试剂的吸头复用判断要点:
- 同一吸头反复从同一源吸液,仅在吸头永不接触不兼容的目标液体时才可能可接受;
- 浸入式分液(submerged dispense)可能润湿吸头外壁或内壁;
touch_tip、混匀或底部接触式分液都会增加污染风险;- 对照与样本通常必须分开吸头。
为每一条条件分支计算吸头用量。多通道操作消耗的是整组吸头(tip sets),不是单个命令调用数。仓库 serial_dilution_template.py 的序列稀释步骤使用new_tip="always"(每步新吸头),而加稀释液步骤使用new_tip="once",测试断言总吸头数为1 + 11 + 1(稀释液 1 支 + 11 步各 1 支 + 末列移走 1 支),正是"按污染边界逐分支计算吸头"的落地示例。
流速、位置与延时
相对流速与绝对流速
rate=是对已配置流速的乘法因子:
pipette.aspirate(50, source, rate=0.5)受支持的现代 API 也接受绝对流速参数(单位 µL/s):
pipette.aspirate(50, source, flow_rate=25)规则:每个动作只用一种形式。绝对值的单位是 µL/s;数值应通过针对具体液体的测试建立,而不是照抄其他移液器的设置。api_reference 同样强调"不要同时提供两种形式"(api_reference.md)。
位置(Position)
source.bottom(z=1) source.top(z=-2) destination.center()- 底部吸液可减少残留体积,但增加碰撞与扰动沉淀(pellet)的风险;
- 顶部或近顶部分液可减少接触污染,但可能飞溅;
- 侧向偏移可减少起泡,但要求已知的孔几何;
touch_tip()在大孔与储液槽中可能不安全;API 2.28+ 会拒绝某些大空间用法。
空气间隙与 push-out
空气间隙可减少滴落,但占用移液器容量:
pipette.aspirate(80, source) pipette.air_gap(10) pipette.dispense(90, destination)液体加空气的总量必须能装进移液器。分液后用push_out让柱塞再多推进一小段距离:
pipette.dispense(80, destination, push_out=5)更大幅度的排空使用 blowout。当气溶胶、气泡或交叉污染重要时,避免对着液体吹气。
混匀:标准 mix 与动态混匀
标准混匀:
pipette.mix( repetitions=5, volume=40, location=plate["A1"].bottom(z=1), aspirate_flow_rate=20, dispense_flow_rate=30, final_push_out=5, )混匀体积必须低于可用液体体积与移液器上限;同时要考虑沉淀、磁珠、细胞、起泡与封板膜(plate seals)。
API 2.27 增加动态混匀(移动过程中同时吸/排):
well = plate["A1"] pipette.dynamic_mix( aspirate_start_location=well.bottom(z=1), aspirate_end_location=well.bottom(z=4), dispense_start_location=well.bottom(z=4), dispense_end_location=well.bottom(z=1), repetitions=3, volume=50, )动态运动对几何非常敏感:先用仿真检查路径,再用真实耗材做干跑(dry-run),之后才允许用于样本。
动态吸液与分液(API 2.27)
API 2.27 可以在一次柱塞动作中在两个位置之间移动:
pipette.aspirate( volume=100, location=well.bottom(z=1), end_location=well.bottom(z=5), movement_delay=1, )这可用于跟随变化的液面(meniscus)或扫过一段液柱。注意:它并不能自动证明声明的液体体积或几何是正确的——声明值与实际物理状态必须单独验证。
液体定义与弯月面:define_liquid、load_liquid与meniscus()
声明液体与装载体积
用耗材级方法声明设置体积:
buffer = protocol.define_liquid( name="Buffer", description="Assay buffer", display_color="#1F77B4", ) reservoir.load_liquid( wells=["A1"], volume=12_000, liquid=buffer, )API 2.22+ 提供load_liquid_by_well()(按孔传入体积字典)与load_empty()(标记空孔),旧的Well.load_liquid()已在 API 2.22+ 协议中弃用(api_reference.md)。仓库的 runtime_parameters_template.py 与 serial_dilution_template.py 都是先define_liquid、再load_liquid的标准用法;测试会断言声明体积足以覆盖整个运行的消耗(如序列稀释模板声明 12 mL ≥ 8×11×100 µL = 8800 µL,见 test_scripts.py)。
弯月面位置(API 2.23+)
start_surface = reservoir["A1"].meniscus(z=-1, target="start") end_surface = reservoir["A1"].meniscus(z=-1, target="end")计算出的液面位置取决于液体体积与耗材几何。配合动态吸液/分液时,target="start"与target="end"表示操作两端预期的液面位置。
安全底线:在机器人上确认声明的体积、孔几何与液面行为之前,不要依赖弯月面定位。
液体存在检测:Flex 压力传感器
Flex 压力传感移液器支持三种显式操作:
present = pipette.detect_liquid_presence(reservoir["A1"]) pipette.require_liquid_presence(reservoir["A1"]) height = pipette.measure_liquid_height(reservoir["A1"])或者在每次吸液前全局启用检查:
pipette = protocol.load_instrument( "flex_1channel_1000", "left", tip_racks=[tips], liquid_presence_detection=True, )运行约束(务必遵守):
- 必须使用全新、干燥、空的吸头;
- 每次检查可能增加5–50 秒运行时间,取决于孔深与体积;
- 8 通道移液器仅在通道 1 与通道 8 有压力传感器;
- 96 通道移液器仅在通道 1 与通道 96 有压力传感器;
- 湿吸头会导致"缺液"检测失效;
- 检测不能替代源体积规划。
当全局检测耗时过高时,在关键源上使用显式检查(require_liquid_presence/detect_liquid_presence)更划算。相关能力门控:液体存在检测自 API 2.20 起可用(api_reference.md)。
部分吸头拾取:喷嘴布局配置
支持的布局与最低 API 版本:
| 移液器 | 布局 | 最低 API |
|---|---|---|
| Flex 96 通道 | column(整列) | 2.16 |
| Flex 96 通道 | row、single | 2.20 |
| Flex 8 通道 | single、partial column | 2.20 |
| OT-2 多通道 | single、partial column | 2.20 |
from opentrons.protocol_api import ALL, COLUMN pipette.configure_nozzle_layout( style=COLUMN, start="A12", tip_racks=[partial_rack], ) # 部分列操作... pipette.configure_nozzle_layout( style=ALL, tip_racks=[full_rack], )关键规则:
configure_nozzle_layout()会重置pipette.tip_racks;- 全量拾取与部分拾取必须使用分开的吸头架变量;
- Flex 96 通道全架拾取需要适配器(adapter);
- Flex 96 通道部分拾取不得使用适配器;
- 绝不要把拾取或目标孔位置传给会让活动喷嘴悬在架/耗材之外的布局;
- 台面边缘可达范围取决于布局与起始喷嘴;
- 台面可达允许时,优先用 96 通道移液器的12 列喷嘴做整列拾取;
- 首次物理使用前必须仿真并做纯吸头干跑。
可用常量包括ALL、COLUMN、ROW、SINGLE、PARTIAL_COLUMN,支持范围取决于移液器与 API(api_reference.md)。关于各布局的目标孔选取规则,可参见仓库整理的官方资料索引 references/sources.md。
序列稀释模式:8 通道 × 96 孔板的完整实现
对满 96 孔板 + 8 通道移液器,推荐流程:
- 第 1 列预装母液(stock);
- 第 2–12 列加入稀释液;
- 从第 1 列转移到第 2 列并混匀,再 2→3,依此类推;
- 每一步稀释使用新吸头组,除非已验证的方法另有规定;
- 若需要等量终体积,从第 12 列移走一个转移体积。
引用 A 行孔即可寻址整列:
pipette.transfer( 100, source=plate.rows()[0][0:11], dest=plate.rows()[0][1:12], mix_after=(3, 50), new_tip="always", )吸头预算必须覆盖 11 步序列转移 + 稀释液添加 + 末列终体积移除。
仓库提供了这一模式的完整可运行模板 serial_dilution_template.py:它加载两架opentrons_flex_96_tiprack_200ul、一个 15 mL 储液槽与一块 96 孔板,用group_steps()(API 2.29 步骤分组)把"加稀释液→序列稀释→终体积均一化"三个阶段组织成三个逻辑组,稀释液阶段用new_tip="once"一次吸头连做 11 列,序列阶段new_tip="always",最后pick_up_tip()/aspirate(100)/dispense(100, trash)/drop_tip()把第 12 列抽至 100 µL。仿真测试逐项验证了这些物理行为(test_scripts.py):11 次混匀、13 次吸头拾取/丢弃、23 次 100 µL 吸液、恰好 1 次丢弃到 Trash、且稀释液绝不进入第 1 列(母液列)。
液体处理最终审查清单
在把协议交给仿真与真机之前,逐项核对:
- 每个体积都在移液器与吸头量程内;
- 空气 + 液体总量不超容量;
- 源包含死体积与抛洒体积;
- 目标在每个中间步骤都不超容量;
- 混匀体积物理可得;
- 位置不接触孔底或沉淀;
- 吸头策略与污染边界一致;
- 多通道孔引用与当前喷嘴布局一致;
- 液体检测使用全新干燥吸头;
- 仿真展开结果与预期命令顺序一致;
- 液体特异性行为已通过干跑验证。
落地验证:本地仿真与测试资产
液体处理代码必须在钉版(pinned)opentrons 包下仿真。仓库钉版环境(requirements-flex.txt、requirements-ot2.txt):
- Flex:
opentrons==9.1.1,API 2.29(uv run --with "opentrons==9.1.1" opentrons_simulate protocol.py); - OT-2:
opentrons==9.0.0,API 2.28 兼容仿真;9.1.1 包在 Flex/OT-2 产品线分叉后会直接拒绝 OT-2 协议,OT-2 分析必须在 OT-2 App 中完成。
仓库 tests/opentrons-integration/test_scripts.py 展示了如何把"液体处理正确性"变成可断言的事实:对每个 Flex 模板调用opentrons.simulate.simulate(),再对运行日志统计吸液/分液次数、吸头拾取/丢弃次数、混匀次数与最终注释,从而锁定体积预算与步骤数——例如"8 孔 × 50 µL + 3 次 20 µL 抛洒 = 460 µL 缓冲液,且单次吸液不超过 200 µL 吸头容量"(test_scripts.py)。这套"仿真→日志断言"的方法可以直接复用到你自己的液体处理协议上。
完整的分层验证流程(语法编译 → 本地仿真 → 资源审计 → App 分析 → 操作者复核 → 干跑 → 受控放行)见 references/validation_and_operations.md;液体处理在整个 Opentrons skill 中的定位与其余参考文档的索引见 SKILL.md。
最后重申安全边界:成功的 Python 语法与本地仿真绝不等于可以上真机。物理执行前必须完成 App 分析、操作者复核与无害液体干跑,并随时可触达急停按钮。
【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考