蛋白质-配体复合物结构
BioTender · 手搓实录

真实记录——用Claude Code手搓一个蛋白设计智能体

从RFDiffusion到Boltz-2,手搓一套零点击蛋白设计全自动Pipeline的完整踩坑记录

BIOTENDER · AI×BIO 手搓系列 2026.07
BioTender Assistant 首页
BioTender Assistant 首页——左侧工具面板,右侧对话流,功能卡片一键触发常用流程

凌晨两点,指令只有一句话:"帮我设计一个能结合锌离子的蛋白,用4个骨架,每个骨架6条序列。"六分钟后,屏幕上跳出一排pLDDT数字,全部超过93,极高置信度。中间没有人点过一次"下一步"。RFDiffusion 吐出骨架,ProteinMPNN 自动把候选序列跑了个遍,Boltz-2 挨个验证,Qwen3.6-27B 挑出前三名并写好了改进建议。整条链路,从骨架到结构验证,零点击。

这不是调用哪家公司的蛋白质设计 API。这是一套完全长在自己内网 HPC 集群里的东西,代号 BioTender Assistant,是用 Claude Code 一行一行"手搓"出来的。这篇文章记录它是怎么被搭起来的——包括那些让人半夜想砸键盘的 bug,以及最后是怎么被 Claude Code 揪出来的。

01先把家底盘清楚:三台机器,五个模型

动手之前先想清楚一件事:让语言模型"自己设计蛋白质",本质上不是训练一个新模型,而是把一堆各自独立的专业工具,用一个会规划、会调度的大脑串起来。工作台最终长这样——一个大脑,四件称手的工具:

RFDiffusion 扩散模型从头生成蛋白骨架三维坐标,支持 unconditional 和 motif scaffolding 两种模式 gpu01 · RTX 4090
ProteinMPNN 逆向折叠序列设计,接受 PDB 结构,输出满足该三维结构的氨基酸序列 gpu01 · RTX 4090
Boltz-2 端到端结构预测,序列→三维结构,输出 pLDDT 置信度指标 gpu01 · RTX 4090
OpenDDE 655M 参数蛋白质-小分子联合结构预测,接受序列 + SMILES 配体 gpu01 · RTX 4090
Qwen3.6-27B 本地部署大语言模型,用 vLLM 撑起 OpenAI 兼容 API,担任整个系统的"大脑" gpu02 · A100 80GB
侧边栏工具面板
左侧边栏实时显示语言模型与计算工具的在线状态和所在节点

硬件是三台通过 Tailscale 组内网的机器:一台 CPU 服务器 master 跑 FastAPI 后端和 API 路由;gpu01(RTX 4090)专职跑四个计算工具的推理;gpu02(A100 80GB)专门给 Qwen3.6-27B 用 vLLM 撑起一个 OpenAI 兼容接口。没有花哨的编排框架,三台机器靠最朴素的 SSH/SCP/HTTP 接起来,够用就是好架构。

02手搓第一步:把工具翻译成模型看得懂的语言

Qwen3.6-27B 本身不知道什么是 RFDiffusion。要让它"会用"这些工具,第一步是把每个工具包装成 OpenAI 格式的 function calling 定义:

generate_backboneRFDiffusion 骨架生成,支持 unconditional / motif 两种模式,返回骨架 job_id
design_sequencesProteinMPNN 批量序列设计,对所有骨架都跑一遍,返回全局排序结果
validate_structureBoltz-2 批量结构验证,接受序列列表,逐条预测并按 pLDDT 降序返回
predict_structureBoltz-2 单序列结构预测,附带 mol* 3D 可视化

后端用 FastAPI 撑起一组对应的接口。每个任务都扔进 BackgroundTasks 异步执行,状态存在内存字典 JOBS 里,前端轮询 /api/status/{job_id} 拿进度,完事之后用 /api/result/{id} 下载 PDB 文件。整套设计的哲学很朴素:后端只管把重活甩给 GPU 节点,脏活累活留给大脑去调度。

03让AI自己把链路串起来:零点击的野心

光有工具还不够,真正的难点是让 AI 在拿到一个结果后,自己判断"接下来该干什么",而不是每一步都要人点一下"继续"。

用户提问与AI任务规划
用户发出指令后,AI在 thinking 模式下完整拆解任务:确认三步走的工具调用顺序和各步参数

这靠两轮对话接口撑起来:/api/chat 负责第一轮,Qwen 决定调用哪个工具;/api/chat/resume 负责把工具结果喂回去,让 Qwen 决定是链式调用下一个工具还是收工写总结。一条完整的自动流程长这样:

Qwen 解析意图,先用一两句话说明设计思路,随即调用 generate_backbone
前端轮询直到骨架生成完成,把结果反馈给 Qwen
Qwen 收到骨架 job_id 后立即调用 design_sequences
ProteinMPNN 批量设计完成,Qwen 挑出 score 最低的三条,调用 validate_structure
Boltz-2 批量验证完成,Qwen 生成综合分析——pLDDT 对比、改进建议
AI推断工具参数的thinking过程
AI 在 thinking 过程中自主推断工具接口含义——比如 num_seqs 是每个骨架的序列数、pdb_job_id 应接收 backbone 返回的 ID

这条链路能不能真的"自动"跑下去,几乎全靠一份写得够狠的 SYSTEM_PROMPT。三条硬约束缺一不可:第一,先解释后执行——调工具前必须先说明设计意图和参数选择理由;第二,链式自动调用——拿到工具结果之后立刻调下一步,不等用户确认;第三,批量验证指引——明确要求从序列结果里挑 score 最低的三条,作为列表传进验证工具。没有这三条约束,模型要么调用一次就停下来等指令,要么一次只验证一条序列,整条流水线根本跑不完。

04四步自动跑下来是什么感觉

AI 说完计划就立刻触发骨架生成,对话区弹出工具完成卡片,mol* viewer 同步渲染骨架的 3D 结构:

RFDiffusion骨架生成完成卡片
RFDiffusion Backbone Generation Complete · 4 backbones · 100 aa · Download PDB
骨架3D可视化
mol* viewer 渲染出的 100aa α螺旋束骨架——AI 说明"这通常适合作为构建锌离子结合位点的稳定结构支架"

拿到骨架 job_id 之后,AI 在 thinking 里推断参数含义,随即自动调用 design_sequences,112 条候选序列全局按 score 排序,界面展示来源骨架编号:

design_sequences调用结果
PROTEINMPNN · SEQUENCE DESIGN · 112 candidates · lower score = better,每条序列标注来源骨架编号和 score 值

Boltz-2 批量验证 top-3 序列:

批量验证完成
Batch Validation Complete (3 sequences) · 三条候选序列的完整氨基酸序列展示

AI 输出综合分析,发现问题并主动给出改进方向:

AI综合分析结果
AI 总结:Top 3 的 pLDDT 均 >93,结构预测极高置信;同时指出 unconditional 模式下序列缺乏 CXXC/HXH 等锌结合基序,建议后续用 Motif Scaffolding 引入结合位点

全程耗时约 6 分钟,零次点击,最优候选 Sequence 1 的 pLDDT 达 93.8。

步骤工具输出耗时
骨架生成RFDiffusion4 个 100aa 骨架 PDB~90秒
序列设计ProteinMPNN112 条候选,全局按 score 排序~40秒
批量验证Boltz-2top-3 pLDDT:93.8 / 93+ / 93+~3分钟
综合分析Qwen3.6-27B候选推荐 + Motif Scaffolding 改进建议~30秒

05Claude Code踩坑记:六个让流水线卡死的瞬间

把这套系统从"能跑通一次"改造成"零点击全自动",中间踩的坑比想象中密集。以下六个是最典型的——每一个都靠 Claude Code 逐层排查日志、对照代码、定位到具体行才解决。记下来是因为它们背后的教训比 bug 本身更值钱。

Bug 01 · 前端渲染

highlight.js 的 CDN 版本选错,整条链路悄无声息地断了

现象:用了 CDN 上 highlight.js 的 CommonJS 格式(lib/core.min.js),浏览器里直接报 module is not defined。渲染 Markdown 时抛出异常被外层 try-catch 悄悄吞掉,后续工具调用逻辑根本没被触发——骨架生成完之后,流水线就这么没声没息地停了,连报错都看不见。

解法:换成 cdnjs 上的浏览器版本 highlight.min.js,再在高亮调用外套一层 try-catch 做降级保护。

Bug 02 · 字节级坑

SFTP 传文件把转义符传成了真换行,整个 script 块直接报废

现象:SFTP 写文件时,split('\n') 里的转义序列被写成了真实的 0x0A 字节,JS 字符串字面量里混进真换行符,整个 <script> 块解析失败——所有前端函数全部变成 undefined,页面彻底罢工,连点击都没反应。

解法:上 Python 做字节级搜索替换,把误写进去的 [0x0a] 精确换回 [0x5c, 0x6e](转义序列本身)。

Bug 03 · 依赖地狱

ESMFold 需要的 openfold,装不上

现象:pip install openfold 装到的只是 0.0.1 占位包,真正能用的 openfold 需要现场 CUDA 编译,在现有环境里根本装不起来,验证工具一调用就报 ModuleNotFoundError

解法:不再纠结装环境,直接把 run_esmfold() 函数体换成调用 run_boltz()——输出同样是 pLDDT,接口完全兼容,改一个函数体,问题就没了。

Bug 04 · thinking 模式

AI 明明说了话,用户却什么都看不到

现象:Qwen 在 thinking 模式下把调工具前的说明文字写进 <think>...</think> 标签里,后端硬编码返回 text: ""——"先解释后执行"这条约束表面上生效了,用户却完全看不到 AI 说了什么。

解法:把完整内容取出来,用正则去掉 think 标签,剩下的纯文字部分才是真正要展示的说明。

Bug 05 · 交互设计债

"零点击"承诺被自己的一个按钮打破了

现象:骨架生成跑完之后,前端会在对话区插入一个"下一步:ProteinMPNN 设计序列"的按钮,得等用户手动点一下才触发——这跟"零点击自动流程"的设计目标直接矛盾。

解法:把这个按钮插入逻辑整个删掉,骨架生成完成后直接把结果传给下一层处理函数,自动继续走下一步。

Bug 06 · 参数设计缺陷

四个骨架,只有一个被真正设计了序列

现象:验证工具参数是单数 sequence,AI 只能选一条去验证;往上查,run_mpnn() 只取第一个骨架,四个骨架跑完 RFDiffusion 之后,只有第一个真正被 ProteinMPNN 设计了序列。

解法:两处一起改:工具参数从单数改成列表 sequences,后端逐条调用 Boltz-2 按 pLDDT 降序返回;run_mpnn() 改成遍历所有骨架,每条序列标注 backbone_idx,全局按 score 排序。

一点体会

这六个 bug 有个共同点——没有一个是模型不够聪明导致的,全部出在"胶水层":CDN 版本、字节编码、依赖安装、字段解析、交互逻辑、参数形状。用 Claude Code 手搓 agent 的大部分时间,其实花在这些看起来最不起眼的接缝上;调度大脑越"聪明",越需要胶水层稳,一处松动就会让整条链路在用户完全无感的情况下悄悄断掉。

06接下来打算加什么

回头看这套系统最值钱的部分,可能不是四个工具本身,而是那条把它们串起来的、写得足够狠的 SYSTEM_PROMPT,和六个被 Claude Code 一个一个揪出来的胶水层 bug。工具会变——RFDiffusion 换成别的骨架生成模型,Boltz-2 换成下一代结构预测器,架构本身几乎不用动。这大概就是"手搓 agent"和"调用别人 API"最大的区别:前者踩完坑之后,坑是自己的经验;后者出了问题,只能等别人发公告。