ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PCF与单细胞测序联合分析:用CODEX空间蛋白组学拆解组织微环境异质性

PCF与单细胞测序联合分析:用CODEX空间蛋白组学拆解组织微环境异质性 1. 从单细胞图谱到空间邻域组织微环境研究到底卡在哪单细胞测序scRNA-seq这几年在肿瘤免疫、炎症组织研究里几乎是标配。你把一块组织消化成悬液上机跑完拿到的是几万个细胞的转录谱聚类之后能看到 CD8 T 细胞、Treg、髓系细胞、肿瘤上皮、成纤维、内皮等一大堆亚群。问题是消化这一步本身就把组织结构打碎了。你知道样本里有 Treg也知道它有某种抑制性转录状态但你不知道它在切片上离 CD8 T 细胞有多远、是不是贴着肿瘤边界、周围是不是一圈巨噬细胞。PCFPhenocycler-Fusion基于 CODEX 的空间蛋白组学平台解决的正是这个断层。它在同一张 FFPE 或新鲜冷冻切片上用几十个抗体 panel 做多轮荧光成像每个细胞拿到一套蛋白表达向量加一个空间坐标。把 scRNA-seq 的“细胞有哪些、转录状态如何”和 PCF 的“这些细胞在组织里怎么排、挨着谁”拼起来才能从细胞图谱走到组织生态系统。这篇面向的是做肿瘤/炎症微环境的生信和实验同学你已经有或即将有 scRNA-seq 数据想加一层空间蛋白定位但不确定分析配置怎么搭、AI 辅助注释怎么接。下面给一套可复制的骨架包含 config.toml 与 settings.json 示例以及用 TaoToken 统一 Key 接入 AI 辅助细胞注释的验证动作目标是产出一张可复现的微环境细胞邻域图谱。2. TaoToken 前置统一 Key 接入 AI 辅助注释空间蛋白组学的 panel 动辄 30 抗体手动给每个 cluster 查 marker、对文献、写注释一个项目下来非常耗时间。我的做法是把 cluster marker 列表丢给大模型做初筛注释人工再复核。这里用 TaoToken 的统一 Key 来接入好处是一个 Key 走多家模型做注释时可以在不同模型间对比结果不用来回换配置。先拿 Key打开 https://taotoken.net/api-keys 登录后创建一个 API Key复制保存。注意这个 Key 只在创建时完整显示一次。拿到 Key 之后模型对话入口在 https://taotoken.net/models 可以先用网页端试一下注释 prompt 的效果确认输出格式符合预期再写进脚本。如果你后面要做长期的 coding 或 Agent 化批量注释流程可以看 Coding Plan https://taotoken.net/coding-plan 。接入文档在 https://taotoken.net/doc API 基地址是 https://taotoken.net/api 兼容 OpenAI 风格的调用方式。下面所有配置里的 Key 都从环境变量读不要硬编码进文件。3. 可复制配置config.toml 与 settings.json 骨架这一节给两个配置文件。config.toml 管分析流程参数panel、邻域半径、聚类分辨率等settings.json 管 AI 辅助注释的模型接入。两者分开是为了让分析参数可版本化而 Key 相关配置走环境变量。3.1 config.tomlPCF 与 scRNA-seq 联合分析参数# config.toml — PCF scRNA-seq 联合分析骨架 [project] name tme_niche_analysis species human tissue tumor # tumor | inflammation output_dir ./results [scrna] matrix ./data/scrna_matrix.h5ad min_genes 200 min_cells 3 n_pcs 30 n_neighbors 15 leiden_resolution 0.8 batch_key sample_id # 细胞类型注释结果回写列 celltype_col cell_type_ai [pcf] # CODEX / Phenocycler 多轮成像导出的细胞表 cell_table ./data/pcf_cells.csv # 每个细胞一行列为抗体名另含 x, y, sample_id marker_prefix ab_ panel_size 37 # 邻域构建半径单位与坐标一致通常为像素 neighborhood_radius 50 min_cells_per_neighborhood 10 # 邻域聚类 niche_kmeans_k 7 [integration] # scRNA-seq 与 PCF 的标签对齐方式 label_transfer marker_overlap # marker_overlap | harmony | scanorama shared_markers [CD3, CD8, CD4, FOXP3, CD68, CD163, PD1, CD45RA, EPCAM, PANCK]几个参数说明一下。neighborhood_radius是最关键的它决定“邻近”的定义。文献里常见的做法是把每个细胞周围一定半径内的细胞作为它的邻域再统计邻域内各细胞类型比例。半径太小邻域里没几个细胞太大就糊成一团。建议先用 30、50、80 三档跑一遍看邻域组成的分布是否稳定。niche_kmeans_k是邻域聚类数文献里 CODEX 常聚出 7 类左右比如肿瘤丰富、肿瘤-免疫交界、基质、泛免疫、巨噬细胞丰富、淋巴细胞丰富等你可以按自己组织类型调整。3.2 settings.jsonAI 辅助注释接入{ ai_annotation: { provider: taotoken, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model: claude-sonnet-4-20250514, temperature: 0.2, max_tokens: 2000, system_prompt: 你是单细胞与空间蛋白组学注释助手。根据给定的 cluster marker 基因列表和 PCF 抗体 panel输出每个 cluster 的候选细胞类型、置信度和判断依据。只输出 JSON不要额外解释。, batch_size: 10, output_col: cell_type_ai }, pcf_annotation: { provider: taotoken, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model: claude-sonnet-4-20250514, temperature: 0.2, system_prompt: 你是空间蛋白组学注释助手。根据邻域内抗体表达均值和细胞组成给出该邻域的微环境区域命名如肿瘤丰富区、免疫交界区、基质区等。只输出 JSON。 } }Key 通过环境变量注入export TAOTOKEN_API_KEY你的Key这样 settings.json 可以进 gitKey 不会泄露。模型名按你实际可用的填网页端 https://taotoken.net/models 能查到当前可用列表。4. 验证请求从 marker 到邻域图谱的完整链路配置搭好之后先做一次最小验证确认 AI 注释链路通再跑全量。4.1 验证 AI 注释接口import os, json, requests API_KEY os.environ[TAOTOKEN_API_KEY] BASE https://taotoken.net/api def annotate_cluster(markers): payload { model: claude-sonnet-4-20250514, temperature: 0.2, max_tokens: 2000, messages: [ {role: system, content: 你是单细胞注释助手。根据 marker 基因输出候选细胞类型 JSON。}, {role: user, content: fcluster markers: {markers}} ] } r requests.post( f{BASE}/v1/chat/completions, headers{Authorization: fBearer {API_KEY}, Content-Type: application/json}, jsonpayload, timeout60 ) r.raise_for_status() return r.json()[choices][0][message][content] # 用一个已知 cluster 试 print(annotate_cluster([CD3D, CD3E, CD8A, GZMB, PDCD1]))预期返回类似{cell_type: CD8 exhausted T cell, confidence: 0.85, reason: ...}。如果返回 401检查 Key 和环境变量返回 404检查 base_url 是否带了/v1路径对话接口是/v1/chat/completions基地址本身是https://taotoken.net/api。4.2 构建邻域图谱验证通过后跑邻域构建。核心逻辑对 PCF 细胞表用 KDTree 找每个细胞半径内的邻居统计邻居的细胞类型组成再做 KMeans 聚成邻域类型。import pandas as pd, numpy as np from scipy.spatial import cKDTree from sklearn.cluster import KMeans cells pd.read_csv(./data/pcf_cells.csv) coords cells[[x, y]].values tree cKDTree(coords) R 50 neighbors tree.query_ball_point(coords, rR) # 邻域细胞类型组成矩阵 celltypes cells[cell_type_ai].values ct_list sorted(set(celltypes)) comp np.zeros((len(cells), len(ct_list))) for i, idx in enumerate(neighbors): for j in idx: comp[i, ct_list.index(celltypes[j])] 1 comp comp / comp.sum(axis1, keepdimsTrue) # 邻域聚类 km KMeans(n_clusters7, random_state0, n_init10).fit(comp) cells[niche] km.labels_ cells.to_csv(./results/niche_map.csv, indexFalse) print(cells[niche].value_counts())跑完你会得到每个细胞一个 niche 标签。把 niche 标签和 scRNA-seq 的细胞类型对齐就能回答“Treg 主要富集在哪个 niche”“PD1 CD8 T 细胞是否集中在肿瘤-免疫交界”这类问题。文献里用 37 抗体 panel 构建的邻域本质上就是这个流程只是 panel 和聚类数不同。4.3 结果对照分析层输入输出回答的问题scRNA-seq表达矩阵细胞类型 转录状态有哪些细胞、什么状态PCF抗体表达 坐标蛋白表达 空间位置细胞在哪、表达什么蛋白邻域分析细胞类型 坐标niche 标签细胞如何组成微环境AI 注释marker 列表候选注释加速人工复核5. 本篇常见错排查邻域半径设错导致 niche 全糊在一起。症状是 KMeans 出来的 7 类 niche 组成几乎一样。原因通常是半径太大每个细胞的邻域都覆盖了整张切片。排查打印邻域内细胞数的分布中位数应该在 10–50 之间。如果中位数上百把半径调小。AI 注释返回格式不稳定。有时模型会输出一段解释而不是纯 JSON。解决system prompt 里强调“只输出 JSON”并在代码里加一层解析兜底比如用正则提取第一个{...}。temperature 设 0.2 以下能明显改善一致性。scRNA-seq 和 PCF 的细胞类型标签对不上。scRNA-seq 注释出的是转录层面的亚群PCF 抗体 panel 可能没有对应 marker。解决在 config.toml 的shared_markers里只保留两边都有的 marker用 marker overlap 做标签映射不要强行一一对应。Key 泄露风险。不要把 Key 写进 config.toml 或 settings.json 提交到仓库。统一走TAOTOKEN_API_KEY环境变量。如果怀疑泄露去 https://taotoken.net/api-keys 吊销重建。PCF 坐标单位不一致。不同平台导出的坐标可能是像素、微米或归一化值。邻域半径必须和坐标单位匹配。排查算一下切片坐标的范围和实际组织尺寸对比确认单位。6. 接入路径与后续动作整条链路跑通之后日常使用就是三件事scRNA-seq 注释、PCF 邻域构建、两者对齐。AI 辅助注释这一步用统一 Key 接入能省掉大量查 marker 的时间尤其是 panel 大的时候。排障和接入细节看接入文档 https://taotoken.net/doc Key 管理在 https://taotoken.net/api-keys 。想先试模型输出效果用模型对话 https://taotoken.net/models 。如果你要把这套注释流程做成长期跑的 Agent 或批量 coding 任务Coding Plan 更合适 https://taotoken.net/coding-plan 。最后提醒一句AI 注释结果始终是候选进下游分析前一定人工复核关键 cluster尤其是 Treg、耗竭 T 细胞、TAM 这些和结论强相关的亚群。邻域图谱的价值在于把转录线索放回组织原位别让注释错误把空间结论带偏。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进