Scientific Agent Skills 之 Adaptyv 技能:用 Foundry API 打通蛋白实验从序列提交到数据回传的全链路
本篇基于 Scientific Agent Skills 仓库中的 skills/adaptyv 技能,完整讲解 Adaptyv Bio 云实验室(Foundry)API 的接入方式:如何完成认证与 SDK 安装,如何用装饰器或 FoundryClient 提交蛋白结合/热稳定性/表达/荧光实验,如何跟踪九段式实验生命周期并拉回动力学与 Tm 数据。读完后你可以让 AI Agent 直接编写可运行的 Foundry 集成代码,把"提交氨基酸序列 → 自动实验室检测 → 结构化结果回传"的约 21 天实验闭环变成几行 Python。
技能定位:它教 Agent 做什么
Adaptyv Bio 是一个云实验室:用户通过 API 或 Web 界面提交氨基酸序列,其自动化实验室执行结合(BLI/SPR)、热稳定性、表达与荧光等检测,并在约 21 天内回传实验数据(原文表述,见 skills/adaptyv/SKILL.md 第 13 行)。在仓库的 README 中,它被归入"Protein Engineering & Design"类别,定位为"Cloud laboratory platform: Adaptyv (automated protein testing and validation)"。
该技能的触发条件写在 frontmatter 的 description 中:当用户提到 Adaptyv、Foundry API、蛋白结合实验、蛋白筛选、BLI/SPR 检测、热稳定性检测,或代码中 import 了 adaptyv、adaptyv_sdk、FoundryClient,或引用了 foundry-api-public.adaptyvbio.com 时,Agent 应启用本技能。
适用前提(来自 frontmatter compatibility 字段):
- Python 3.10+;
- 拥有一个 Adaptyv Foundry 账号,以及从 Foundry 门户侧边栏获取的 API key;
- 通过
uv从 GitHub 安装adaptyv-sdk(0.1.0 beta,尚未发布到 PyPI)。
需要说明的是,从目录结构看,skills/adaptyv/ 不包含 scripts/ 目录,是一个纯文档型参考技能:仓库安全扫描报告 docs/security-report.md 也将其标注为"documentation-only reference for the Adaptyv Bio Foundry API"。它的全部价值在于把 Foundry API 的认证约定、实验生命周期和 32 个端点的请求/响应契约固化成 Agent 可执行的集成知识。
认证与 API 基础约定
- Base URL:
https://foundry-api-public.adaptyvbio.com/api/v1 - 认证方式:
Authorization请求头携带 Bearer token;token 从 Foundry 门户(foundry.adaptyvbio.com)侧边栏获取。 - 密钥来源:写代码时一律从环境变量
ADAPTYV_API_KEY或项目根目录的.env文件读取密钥——绝不硬编码 token。技能给出的实操建议是:先检查项目根目录是否存在.env文件,若存在则用python-dotenv之类的库加载它。 - 变量名约定:官方文档的 curl 示例使用
FOUNDRY_API_TOKEN,它与本技能推荐的ADAPTYV_API_KEY是同一个 Bearer token;为了与 SDK 保持一致,Python 代码和新写的 shell 脚本应统一采用ADAPTYV_API_KEY。
最小可用验证请求(除 GET /openapi.json 外,其余所有请求都需要认证):
export ADAPTYV_API_KEY="abs0_..."
curl https://foundry-api-public.adaptyvbio.com/api/v1/targets?limit=3 \
-H "Authorization: Bearer $ADAPTYV_API_KEY"
技能同时强调:token 只能存放在环境变量或 .env 文件中,绝不能提交到版本控制系统。GET /openapi.json 端点无需认证,可用于机器读取完整的 OpenAPI 规范。
安装 Python SDK 与环境变量
adaptyv-sdk 目前是 0.1.0 beta,未上 PyPI,需要从 GitHub 安装:
uv pip install "git+https://github.com/adaptyvbio/adaptyv-sdk.git"
在带 pyproject.toml 的项目里则用:
uv add "adaptyv-sdk @ git+https://github.com/adaptyvbio/adaptyv-sdk.git"
SDK 相关环境变量(设在 shell 或 .env 文件中):
| 变量 | 必填 | 说明 |
|---|---|---|
ADAPTYV_API_KEY |
是 | Foundry Bearer token |
ADAPTYV_API_URL |
否 | 默认 https://foundry-api-public.adaptyvbio.com/api/v1 |
ADAPTYV_ORGANIZATION_ID |
否 | 组织 ID |
@lab.experiment 装饰器与 FoundryClient 在显式传参之外,都会自动从环境中读取 ADAPTYV_API_KEY 和 ADAPTYV_API_URL,因此多数场景下显式传参可以省略。
供应链与安全提示:仓库的安全扫描(docs/security-report.md 中 adaptyv 条目,评级 MEDIUM)指出,上述安装命令直接拉取 SDK 仓库 HEAD 的代码,未固定 commit、tag 或版本,且 0.1.0 未发布到 PyPI,缺少注册表级别的原生完整性校验。报告的整改建议是:把安装固定到具体 tag 或 commit SHA(如 git+https://github.com/adaptyvbio/adaptyv-sdk.git@<commit-sha>),并在从源码仓库安装包前征得用户确认。此外扫描报告还提示,下文"自动化流水线"工作流中的 skip_draft + auto_accept_quote 组合会在无人工审核的情况下直接创建真实发票,生产环境使用需格外谨慎。
两种编程模式
装饰器模式:最少的样板代码
装饰器负责实验提交,返回对象带 experiment_url 可直接跳转到 Foundry 门户(代码见 skills/adaptyv/SKILL.md#L61-L70):
from adaptyv import lab
@lab.experiment(target="PD-L1", experiment_type="screening", method="bli")
def design_binders():
return {"design_a": "MVKVGVNG...", "design_b": "MKVLVAG..."}
result = design_binders()
print(f"Experiment: {result.experiment_url}")
适合"定义一批序列 → 一次性提交"的脚本化场景,target、实验类型、方法都收敛在装饰器参数里。
客户端模式:完整的生命周期控制
需要浏览目录、估价、创建、提交、回取结果时,使用 FoundryClient(代码见 skills/adaptyv/SKILL.md#L74-L106):
import os
from adaptyv import FoundryClient
client = FoundryClient(
api_key=os.environ["ADAPTYV_API_KEY"],
base_url=os.environ.get(
"ADAPTYV_API_URL",
"https://foundry-api-public.adaptyvbio.com/api/v1",
),
)
# Browse targets
targets = client.targets.list(search="EGFR", selfservice_only=True)
# Estimate cost
estimate = client.experiments.cost_estimate({
"experiment_spec": {
"experiment_type": "screening",
"method": "bli",
"target_id": "target-uuid",
"sequences": {"seq1": "EVQLVESGGGLVQ..."},
"n_replicates": 3
}
})
# Create and submit
exp = client.experiments.create({...})
client.experiments.submit(exp.experiment_id)
# Later: retrieve results
results = client.experiments.get_results(exp.experiment_id)
客户端命名空间与端点分组一一对应:client.targets、client.experiments,底层映射到参考文档中的 Experiments / Targets 等端点族。
实验类型与字段要求
五种实验类型及其检测方法(继承自 skills/adaptyv/SKILL.md#L110-L116):
| 类型 | 方法 | 测量内容 | 需要 Target |
|---|---|---|---|
affinity |
bli 或 spr |
KD、kon、koff 动力学 | 是 |
screening |
bli 或 spr |
结合与否(是/否) | 是 |
thermostability |
— | 熔解温度(Tm) | 否 |
expression |
— | 表达量 | 否 |
fluorescence |
— | 荧光强度 | 否 |
创建实验的 POST /experiments 接受 name、experiment_spec、skip_draft(默认 false)、auto_accept_quote(默认 false)、webhook_url 五个字段(见 references/api-endpoints.md#L21-L67)。experiment_spec 内各字段在不同实验类型下的要求如下:
| 字段 | Affinity | Screening | Thermostability | Fluorescence | Expression |
|---|---|---|---|---|---|
experiment_type |
必填 | 必填 | 必填 | 必填 | 必填 |
method |
必填 | 必填 | — | — | — |
target_id |
必填 | 必填 | — | — | — |
sequences |
必填 | 必填 | 必填 | 必填 | 必填 |
n_replicates |
建议(默认 3) | 建议(默认 3) | 可选 | 可选 | 可选 |
antigen_concentrations |
可选 | — | — | — | — |
值得注意的默认值:antigen_concentrations 仅用于 affinity 实验,缺省为 [1000.0, 316.2, 100.0, 31.6, 0.0] nM,即约每 3.16 倍(10^0.5)递减的五浓度梯度加零浓度对照;n_replicates 为技术重复数,最小值 1。
实验生命周期:九段状态机
实验从 Draft 起步,最终到达 Done:
Draft → WaitingForConfirmation → QuoteSent → WaitingForMaterials → InQueue → InProduction → DataAnalysis → InReview → Done
各状态由谁驱动、含义如何(继承自 skills/adaptyv/SKILL.md#L124-L137):
| 状态 | 行动方 | 说明 |
|---|---|---|
Draft |
你 | 可编辑,无费用承诺 |
WaitingForConfirmation |
Adaptyv | 审核中,报价正在生成 |
QuoteSent |
你 | 审阅并确认报价 |
WaitingForMaterials |
Adaptyv | 基因片段与靶点材料已订购 |
InQueue |
Adaptyv | 材料到位,进入实验室队列 |
InProduction |
Adaptyv | 检测正在运行 |
DataAnalysis |
Adaptyv | 原始数据处理与 QC |
InReview |
Adaptyv | 最终校验 |
Done |
你 | 结果可用 |
Canceled |
任一方 | 实验已取消 |
实验中还有一个 results_status 字段跟踪数据回传进度:none、partial 或 all。当它进入 partial/all 时,GET /results 列表里才会出现对应的分析结果。
编辑规则与状态强相关:Draft 实验可以完整编辑(PATCH /experiments/{id});报价生成之后,只有 name、description 和 webhook_url 仍可修改;序列也只能追加到 Draft 状态的实验,否则 POST /sequences 返回 409。
三大典型工作流
工作流 1:提交一个结合筛选(分步版)
这是技能给出的标准路径:找靶点 → 预览费用 → 创建 Draft → 提交审核 → 轮询/webhook → 取结果(完整代码见 skills/adaptyv/SKILL.md#L141-L177):
# 1. Find a target
targets = client.targets.list(search="EGFR", selfservice_only=True)
target_id = targets.items[0].id
# 2. Preview cost
estimate = client.experiments.cost_estimate({
"experiment_spec": {
"experiment_type": "screening",
"method": "bli",
"target_id": target_id,
"sequences": {"seq1": "EVQLVESGGGLVQ...", "seq2": "MKVLVAG..."},
"n_replicates": 3
}
})
# 3. Create experiment (starts as Draft)
exp = client.experiments.create({
"name": "EGFR binder screen batch 1",
"experiment_spec": {
"experiment_type": "screening",
"method": "bli",
"target_id": target_id,
"sequences": {"seq1": "EVQLVESGGGLVQ...", "seq2": "MKVLVAG..."},
"n_replicates": 3
}
})
# 4. Submit for review
client.experiments.submit(exp.experiment_id)
# 5. Poll or use webhooks until Done
# 6. Retrieve results
results = client.experiments.get_results(exp.experiment_id)
工作流 2:自动化流水线(跳过 Draft + 自动接受报价)
在创建时传入 skip_draft: True 直接越过 Draft 进入 WaitingForConfirmation,auto_accept_quote: True 自动接受报价并创建发票,再挂 webhook_url 接收每次状态迁移的 POST 通知:
exp = client.experiments.create({
"name": "Auto pipeline run",
"experiment_spec": {...},
"skip_draft": True,
"auto_accept_quote": True,
"webhook_url": "https://my-server.com/webhook"
})
# Webhook fires on each status transition; poll or wait for Done
再结合 POST /experiments 的响应字段看这条链路的含义:auto_accept_quote 触发发票时会返回 stripe_hosted_invoice_url 与 stripe_invoice_id——也就是说该模式会真实产生 Stripe 发票。对应仓库安全报告的提示,建议只在预算与审批机制完备的自动化环境里启用这两个开关。
工作流 3:Webhook 通知
创建实验时传入 webhook_url,Adaptyv 会在每一次状态迁移时向该 URL 发 POST,载荷包含实验 ID、前一状态与新的状态。配合 GET /updates(更新流,见下文)即可实现不依赖轮询的事件驱动集成。
报价、发票与费用估算
费用相关端点是"先估价、再确认、后开票"的结构(详见 references/api-endpoints.md):
POST /experiments/cost-estimate:不创建实验即算价。返回pricing_version(如"v1_2026-01-20",说明价格按版本管理)、assay(按类型的 base + 重复数计价)、materials(结合实验的靶点材料成本)、total_cents(美元美分)。所有价格不含 VAT,税费在开票时计算;没有自助定价的靶点会返回不完整的估算。GET /experiments/{id}/quote:报价元数据,含amount_total/amount_subtotal(最小货币单位)、currency(ISO 代码,如usd)、status、expires_at;另有/quote/pdf返回application/pdf报价单。POST /experiments/{id}/quote/confirm或POST /quotes/{quote_id}/confirm:接受报价、创建草稿发票,实验推进到WaitingForMaterials;请求体可带purchase_order_number;响应含hosted_invoice_url与invoice_id。POST /quotes/{quote_id}/reject:取消报价,关联实验回退到Draft;请求体必填reason,可附feedback。GET /experiments/{id}/invoice与GET /quotes/GET /quotes/{quote_id}:发票元数据(含托管支付 URL)与组织级报价列表/明细(含line_items逐项价格、subtotal_cents、tax_cents、total_cents)。
这套设计对应生命周期表里 QuoteSent 由"你"行动的语义:报价确认是一个显式的人工决策点,除非你显式开启 auto_accept_quote。
序列格式规则与批量追加
sequences 字段支持两种写法(继承自 skills/adaptyv/SKILL.md#L196-L202):
- 简单格式:
{"seq1": "EVQLVESGGGLVQPGGSLRLSCAAS"} - 富格式:
{"seq1": {"aa_string": "EVQLVESGGGLVQ...", "control": false, "metadata": {"type": "scfv"}}} - 多链:用冒号分隔——
"MVLS:EVQL" - 合法氨基酸:A, C, D, E, F, G, H, I, K, L, M, N, P, Q, R, S, T, V, W, Y(大小写不敏感,存储为大写)
- 硬约束:序列只能追加到
Draft状态的实验
创建后批量追加走 POST /sequences(references/api-endpoints.md#L327-L356):请求体为 experiment_code(人类可读实验码,如 "PROJ-001",注意这里用 code 而非 UUID)加 sequences 数组,每条含 aa_string(必填)、name、control、metadata;201 响应返回 added_count、experiment_id、experiment_code、sequence_ids;实验不在 Draft 时返回 409。查询侧,GET /sequences 返回全实验序列(按创建倒序,列表项只含前 50 字符的 aa_preview 与 length),GET /sequences/{id} 才返回完整 aa_string、is_control 与 metadata。
靶点目录:从目录选靶到自定义靶点
GET /targets 列出可用于实验的已验证抗原,查询参数比通用分页参数多出三个领域参数(见 references/api-endpoints.md#L401-L429):
| 参数 | 类型 | 说明 |
|---|---|---|
limit |
int | 最大条数(1–100,默认 50) |
offset |
int | 跳过条数 |
search |
string | 产品名自由文本搜索 |
sort |
string | 排序表达式 |
selfservice_only |
boolean | 仅返回有自助定价的靶点(估价前提) |
show_conjugated |
boolean | 是否包含缀合靶点(默认仅未缀合) |
detailed |
boolean | 在 details 块中填充富化数据(基因名、结构、序列、生物活性) |
列表项关键字段:id(UUID,直接用作 experiment_spec.target_id)、name、vendor_name、catalog_number(供应商目录号)、url、pricing(null 表示需要定制报价)、details。GET /targets/{target_id} 返回单个靶点目录记录。
目录里没有想要的靶点时,走 POST /targets/request-custom 提交自定义靶点供人工审核:必填 name 与组织内唯一的 product_id,sequence 与 pdb_id 至少提供其一,可选 pdb_file、molecular_weight(kDa)、note;随后用 GET /targets/request-custom(列表,可 filter=eq(status,pending_review))和 GET /targets/request-custom/{request_id} 跟踪状态,批准后会关联出 material_id。
结果回传:结果端点与字段结构
GET /results 列出已完成的分析结果(按新到旧排序),GET /experiments/{id}/results 取单个实验的结果,两者都支持 limit、offset、filter、sort(结果端点)或 search(序列端点)。结果列表项字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
uuid | 结果标识 |
title |
string | 人类可读标题 |
experiment_id |
uuid | 关联实验 |
result_type |
string | 如 "affinity"、"thermostability" |
summary |
array | 关键结果(按类型不同,见下) |
metadata |
object | 扩展元数据(如仪器信息) |
data_package_url |
string/null | 原始数据包下载 URL |
created_at |
datetime | 结果生成时间 |
summary 的类型相关结构是解读数据的关键:AffinityResult 含 kd_mean、kd_std、kon_mean、kon_log_std、koff_mean、koff_std、replicates 数组(每个重复带 kd、kon、koff、binding_strength、kon_method、koff_method、replicate 索引)、sequence、target_id;ThermostabilityResult 含 Tm 值与熔解曲线。GET /results/{result_id} 返回包含完整 summary 数组的详情。
过滤、排序与分页:s-expression 查询语法
所有列表端点统一支持分页(limit 1–100,默认 50;offset)、对 name 字段的自由文本 search,以及 sort 排序。过滤通过 filter 查询参数使用 s-expression 语法(完整清单继承自 skills/adaptyv/SKILL.md#L204-L221):
- 比较:
eq(field,value)、neq、gt、gte、lt、lte、contains(field,substring) - 范围/集合:
between(field,lo,hi)、in(field,v1,v2,...) - 逻辑:
and(expr1,expr2,...)、or(...)、not(expr) - 空值:
is_null(field)、is_not_null(field) - JSONB:
at(field,key),例如eq(at(metadata,score),42) - 类型转换:
float()、int()、text()、timestamp()、date()
排序用 asc(field) 或 desc(field),逗号分隔,最多 8 个键:
sort=desc(created_at),asc(name)
组合示例——筛选 2026 年以来完成且状态为 done 的实验:
filter=and(gte(created_at,2026-01-01),eq(status,done))
这套语法在 updates 流上同样有用,例如 filter=eq(type,status_change)、filter=in(experiment_id,uuid1,uuid2)。
更新流(Updates):轮询之外的第二通道
GET /updates 返回实验更新流(最新在前),每条含 id、experiment_id、experiment_code、name(更新描述)、timestamp;GET /experiments/{id}/updates 返回单实验的更新(最旧在前)。更新类型有三种:status_change、progress、error。webhook 负责实时推送,updates 流则提供可过滤、可分页的历史审计轨迹,二者是互补的关系。
错误处理与反馈回路
所有错误响应统一为两字段结构:
{
"error": "Human-readable description",
"request_id": "req_019462a4-b1c2-7def-8901-23456789abcd"
}
request_id 同时出现在 x-request-id 响应头中,联系支持时应附上它。这个 ID 还有第二个用途:POST /feedback/submit 端点接收 bug 报告/功能请求/一般反馈,请求体必填 request_uuid(即出问题那次的请求 UUID)与 feedback_type(feature_request、feedback 或 bug_report),json_body(结构化错误细节)与 human_note(自由描述)至少提供其一,201 响应返回 reference 与 message。这意味着错误上下文可以程序化地回流给供应商,而不是只停留在日志里。
令牌管理:基于 Biscuit 的密码学衰减
Foundry 的 token 采用 Biscuit 密码学衰减机制,支持为不同执行主体发放权限收窄的子 token(端点见 references/api-endpoints.md#L586-L643):
GET /tokens:列出调用者拥有的全部 token(root 与 attenuated),字段含kind(root/attenuated)、expires_at(null 表示永不过期)、revoked_at、parent_token_id、root_token_id、attenuation_spec。POST /tokens/attenuate:为现有 token 创建受限版本。请求体含token(格式为abs0_{slug}{biscuit_base64})、attenuation(限制规格)、name,可选attenuated_parent_token_id支持链式衰减;限制类型覆盖组织、资源(experiments/results)、动作(read/create/update)、过期时间。201 响应返回新数据库 ID 与新的衰减 token 字符串。POST /tokens/revoke:撤销调用 token 的 root 及其全部衰减后代,幂等;响应含token_id、revoked_at、children_revoked。
对 Agent 集成的实际意义:可以按任务粒度发放"只读 + 仅 experiments 资源 + 72 小时过期"的 token,让自动化流水线持有的凭证泄露面最小化,而不是全程使用 root token。
端点总览与延伸阅读
按资源分组的 32 个端点可归纳为八族,完整请求/响应字段表见 skills/adaptyv/references/api-endpoints.md:
| 资源族 | 主要端点 |
|---|---|
| Experiments | POST /experiments、GET /experiments、GET/PATCH /experiments/{id}、POST .../submit、POST /experiments/cost-estimate、GET .../quote、GET .../quote/pdf、POST .../quote/confirm、GET .../invoice、GET .../results、GET .../sequences、GET .../updates |
| Sequences | GET /sequences、GET /sequences/{id}、POST /sequences |
| Results | GET /results、GET /results/{id} |
| Targets | GET /targets、GET /targets/{id}、POST /targets/request-custom、GET /targets/request-custom、GET /targets/request-custom/{id} |
| Quotes | GET /quotes、GET /quotes/{id}、POST /quotes/{id}/confirm、POST /quotes/{id}/reject |
| Tokens | GET /tokens、POST /tokens/attenuate、POST /tokens/revoke |
| Updates | GET /updates |
| Feedback | POST /feedback/submit |
技能主文档与端点参考的相对位置关系:入口是 skills/adaptyv/SKILL.md(frontmatter version: "1.2",作者 K-Dense Inc.),端点全集在 skills/adaptyv/references/api-endpoints.md,该技能在仓库技能目录中的条目见 docs/skills.md。在 Agent 侧,只需让宿主(Cursor、Claude Code、Codex 等 Agent Skills 标准宿主)按 README 的"Getting Started"安装本技能集合,当提示词涉及 Adaptyv 或代码出现 FoundryClient 时,上述认证约定、生命周期状态机与端点契约即会被自动带入上下文,直接产出可运行的集成代码。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
