先说个真实场景。实验室新到一批粪便样本的宏基因组双端数据下机之后直接丢进组装流程结果 contig N50 只有几百 bp物种注释里一堆环境样本常见的杂菌开会一分析才发现问题出在最前面那一步——原始数据里的接头、低质量碱基、测序仪特有的 polyG 假象全都原封不动进了下游。宏基因组流程里质控QC看起来是最没有技术含量的一环一条 fastp 命令十秒钟跑完但恰恰是这一步的参数取舍决定了后面组装、分箱、物种分类和功能注释的上限。Fastp 是目前用得最广的质控工具之一速度快、依赖少、报告直观但它对宏基因组的适配并不是默认参数一跑就完事。这篇内容围绕宏基因组流程中的 Fastp 质控环节展开把参数背后的逻辑、命令的写法、报告的读法、以及我实际踩过的坑全都摊开来讲适合刚接手宏基因组流程的同学也适合已经跑过几批数据、但总觉得结果不太对劲的人对照检查。1. 先搞清楚宏基因组的脏和单基因组的脏不是一回事1.1 下机原始数据里到底混进了什么很多人对质控的理解停留在把质量低的碱基切掉但原始 fastq 里混着的东西远不止低质量碱基。第一类是测序接头当插入片段长度小于读长时测序仪会一直读到接头序列这部分碱基在比对时会形成软剪切甚至错误比对在组装里会形成假的连接。第二类是低质量碱基尤其是 read 3 端随着测序循环推进荧光信号衰减、相位漂移累积质量值会明显下滑这类碱基的错误率可能高达百分之几。第三类是测序仪特有的系统性假象比如双色荧光系统在信号缺失时会判读为 G于是出现一长串 polyG这跟样本本身没关系纯粹是仪器特性。第四类是N 碱基当判读置信度不足时会输出 N连续的 N 在组装时会直接断开。第五类是低复杂度序列比如连续的 AT 重复、微卫星序列这类序列在多物种混合的宏基因组里特别容易造成错误拼接。还有一类容易被忽略的是人为引入的污染比如建库过程中的引物二聚体、实验室环境微生物、试剂自带的应用背景菌群。这一类 Fastp 处理不了属于去宿主和前处理环节要解决的问题但在看质控报告时要心里有数不能把污染当成真实信号。我见过有人质控后 clean ratio 只有 60%第一反应是参数设太严结果是文库本身浓度不够、引物二聚体占比过高这种数据再怎么调参数也救不回来只能重做。1.2 宏基因组比单基因组更挑质控策略的三个原因第一个原因宏基因组没有参考基因组质量这个安全网。单基因组测序里哪怕有几个错误碱基比对到参考基因组上还能靠比对算法纠回来。宏基因组绝大多数样本没有完整参考下游要么 de novo 组装要么靠 k-mer 分类错误碱基会直接变成组装断裂点或者假阳性物种信号。低丰度物种本来 reads 就少一条错误 reads 就可能让某个物种在分类结果里凭空出现或者彻底消失。第二个原因宏基因组的物种丰度分布极度不均。高丰度物种可能占 50% 以上低丰度物种可能只有万分之几。质控参数如果偏严先被砍掉的就是低丰度物种那部分 reads因为它们质量分布往往和高丰度物种不一样。这里有个反直觉的点质控过度比质控不足更危险。质控不足顶多是下游噪音多一点还能靠算法过滤质控过度直接抹掉了低丰度信号事后无从恢复。第三个原因宏基因组的数据量大、样本批次多。一个项目动辄几十上百个样本每个样本几个 GB批次之间可能用了不同的建库试剂盒、不同的测序平台。Fastp 的处理速度和批次一致性直接影响整个流程能不能按时交付。我自己的经验是宏基因组的质控参数宁可按批次统一、略微宽松也不要每个样本单独调参——单独调参看似精细实际上引入了不可控的批次效应后面做差异分析时根本说不清是生物学差异还是质控差异。1.3 Fastp 在这个流程里的位置与边界Fastp 的定位很明确在比对之前对 raw reads 做一步统一处理。它做的事情包括接头剪切、质量过滤、滑窗裁剪、长度过滤、polyG 剪切、可选的重叠纠错和去重输出 clean reads 和一份 HTML/JSON 报告。它的优势在于 C 实现、速度比 Trimmomatic 快不少、单文件无复杂依赖、报告非常直观而且支持双端数据的 overlap 分析来自动识别接头。但它的边界也要清楚。Fastp 不做去宿主宿主序列比如粪便样本里的宿主 DNA需要另外用比对工具去除常见做法是 bowtie2 比对宿主参考基因组然后筛掉比上的 reads这一步在 Fastp 之后做。Fastp 不做 rRNA 去除宏基因组里 rRNA 占比可能高达 30% 以上通常靠下游的 rRNA 预测工具或者专门的去除工具处理。Fastp 不做质量分布的可视化诊断如果要做严格的批次质量评估FastQC 那一套指标仍然值得看一眼Fastp 的 HTML 报告只能覆盖一部分。所以正确的心态是Fastp 是流程里的第一道闸门它负责把明显不合格的序列挡在外面然后交给下游更精细的工具。把它当成万能质控是不现实的把它当成跑一下就行的例行公事同样有问题。2. Fastp 核心参数逐个拆哪些该动哪些别动2.1 质量过滤三件套-q、-u、-e 的默认值与调整依据Fastp 的质量过滤有三个相关参数理解它们的分工是调参的前提。-qqualified_quality_phred定义什么算合格碱基默认 15也就是错误率大约 3.2%。-uunqualified_percent_limit定义一条 read 里不合格碱基占多少比例就整条丢掉默认 40%。-eaverage_qual定义一条 read 的平均质量低于多少就丢掉默认 0也就是不启用。这三个参数的关系是先按-q给每个碱基打标签再按-u判断整条 read 是否保留-e是额外的一道平均质量闸门。默认值的设计思路是宽松保留因为 Fastp 假设使用者会在下游再做严格过滤。宏基因组场景下我一般会把-q提到 20-u保持 40 或者降到 30。理由是这样Q20 对应错误率 1%这个阈值能挡掉大部分明显的测序错误同时不会误伤质量值在 15 到 20 之间的大量边缘碱基。如果把-q提到 25 甚至 30clean reads 的比例会明显下降而且下降的部分往往集中在 GC 含量异常的物种上——宏基因组里 GC 偏好性本来就是偏差来源之一再叠加质量过滤会进一步放大。-e这个参数我通常不动保持默认的 0。原因是平均质量是一个极不稳定的指标一条 150 bp 的 read 如果前 100 bp 质量 Q35、后 50 bp 质量 Q10平均下来可能还有 Q26看起来挺合格但后半段其实已经废了。平均质量的掩盖效应在小片段数据上尤其明显。与其用-e做粗筛不如用滑窗裁剪把该切的切掉剩下的自然就干净了。提示-q和-u是联动的。调高-q会让更多碱基被判为不合格如果-u不变就会有更多整条 read 被丢弃。这两个参数必须一起考虑不能单独调一个。2.2 滑窗裁剪--cut_right 与 --cut_front/--cut_tail 的选择滑窗裁剪是 Fastp 里对宏基因组影响最大的功能之一但它默认是关闭的必须显式开启。它有三个模式--cut_front从 5 端往 3 端滑动遇到平均质量低于阈值的窗口就切掉窗口内碱基--cut_tail从 3 端往 5 端滑动同理--cut_right从 5 端往 3 端滑动一旦遇到平均质量低于阈值的窗口就把这个窗口以及它右边的全部碱基切掉。窗口大小由--cut_window_size控制默认 4窗口平均质量阈值由--cut_mean_quality控制默认 20。以默认值为例一个 4 bp 的窗口平均质量低于 Q20就触发裁剪。这个窗口大小不算大4 bp 的窗口对单个异常碱基比较敏感好处是能精准切掉质量陡降的区域坏处是可能因为一两个碱基的随机波动就误切。宏基因组我一般用--cut_front --cut_tail --cut_window_size 4 --cut_mean_quality 20而不是--cut_right。原因是--cut_right是一刀切从触发点往右全部丢弃如果 read 中间出现一个偶然的低质量窗口右半边即使质量很好也会被整段扔掉这对低丰度物种的 reads 损失太大。--cut_front和--cut_tail只切窗口内的碱基两边都扫一遍保留中间质量好的部分损失更可控。参数值上--cut_mean_quality 20是一个比较稳的平衡点。如果数据整体质量偏差比如 Q30 比例低于 85%可以考虑降到 15先保住 reads 长度把质量问题留给下游的比对算法处理如果数据质量极好Q30 高于 95%提到 25 也无妨。但不建议超过 25因为再往上就会开始伤及真实序列。2.3 接头处理自动检测的边界在哪里Fastp 对双端数据的接头处理有两层机制。第一层是overlap 分析双端 reads 如果来自同一个 DNA 片段R1 和 R2 在 3 端会有重叠区域Fastp 通过比对这段重叠来推断接头序列并剪切。这个机制对插入片段短于两倍读长的文库特别有效。第二层是显式指定接头序列用--adapter_sequence指定 R1 接头--adapter_sequence_r2指定 R2 接头。较新版本的 Fastp 对双端数据默认会做 overlap 分析--detect_adapter_for_pe这个选项在某些版本里已经不需要显式开启。但我在实际使用中仍然倾向于显式加上--detect_adapter_for_pe同时显式指定接头序列。显式指定的理由很实际自动检测依赖 overlap 的质量如果插入片段长度分布很宽、或者文库构建方式特殊自动检测可能漏掉一部分接头显式指定相当于给了一个确定的兜底。Illumina TruSeq 系列的接头序列是固定的R1 是AGATCGGAAGAGCACACGTCTGAACTCCAGTCAR2 是AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT。这两个序列我一般直接写死在脚本里。如果是其他建库试剂盒接头序列要查对应说明书不要照抄。还有一个参数值得提--overlap_len_require默认 30。这个参数控制 overlap 分析要求的最小重叠长度。宏基因组文库插入片段通常在 300 到 500 bpPE150 测序的重叠长度在 0 到 100 bp 之间浮动默认值 30 是合理的。如果文库片段偏长比如 600 bp 以上重叠区域可能很短这时候可以降到 20但降太多会引入错误的 overlap 匹配。2.4 长度、N 碱基与 polyG三个不显眼但很关键的开关长度过滤用-llength_required控制默认 15。这个默认值非常宽松几乎等于不过滤。宏基因组我一般设到 50理由是短于 50 bp 的 reads 在组装里基本不能形成有效 contig在 k-mer 分类里也容易产生假阳性k-mer 长度通常 21 到 3550 bp 的 read 只能提供很少的 k-mer。设到 50 以后clean reads 数量会掉一点但有效信息密度反而提升。不过这里有个取舍要看下游。如果下游是组装比如用 Megahit 或 SPAdes-l 50合适如果下游是物种分类比如用 Kraken2短 reads 虽然 k-mer 少但仍能贡献信号可以放宽到 36如果下游是功能注释比对短 reads 的比对特异性差还是保持 50 比较稳妥。我一般统一用 50除非项目对 reads 数量有硬性要求。N 碱基过滤用-nn_base_limit控制默认 5。也就是一条 read 里 N 的数量超过 5 个就整条丢弃。这个默认值我基本不动。宏基因组里 N 的出现频率不高5 个的上限已经足够宽松。如果发现大量 reads 因为 N 被丢弃那说明测序质量本身有问题调参数是治标不治本。polyG 剪切用--trim_poly_g开启--poly_g_min_len控制最小长度默认 10。这个功能在检测到双色荧光测序平台NextSeq、NovaSeq 系列时会自动开启但我在脚本里会显式写上避免换平台或者换版本时行为不一致。polyG 是双色荧光系统的特有假象单色系统比如 MiSeq不会产生所以如果是 MiSeq 数据这个参数开着也无害因为找不到 polyG 就不会切。另外还有一个--trim_poly_x专门处理 PCR-free 建库产生的 polyX 假象任意碱基的连续重复。这个在宏基因组里用得少除非明确知道文库是 PCR-free 构建的否则不用开。2.5 重叠纠错和去重这两个功能我建议默认关闭Fastp 有两个看起来很诱人但宏基因组要慎用的功能。重叠纠错用--correction开启。它的原理是利用 R1 和 R2 的重叠区域当同一位置两个 read 的碱基不一致时用质量值更高的那个去纠正质量值更低的那个。听起来很合理但宏基因组的特殊性在于重叠区域的两个 read 来自同一个 DNA 片段如果这个片段属于某个低丰度物种纠错会改变它的碱基组成进而影响后续的物种分类和分箱。更麻烦的是这种改变是系统性的、和物种丰度相关的高丰度物种的 reads 纠错后基本不变低丰度物种的 reads 可能被改得面目全非。这会引入一种隐蔽的丰度偏差事后很难察觉。我的做法是默认关闭--correction。只有在数据质量确实很差Q30 比例低于 85%、而且下游只做物种分类不做定量分析时才考虑开启并且要在报告里注明。去重用--dedup开启。它去掉的是完全相同的 read 对。宏基因组里真实的重复 reads 是丰度信号的一部分高丰度物种本来就会产生大量相同序列的 reads去重会直接削平这部分丰度。虽然 Fastp 的去重是基于完全匹配的理论上只去掉 PCR 重复但宏基因组的 PCR 循环数通常不高十几轮真正的 PCR 重复占比有限去重带来的丰度失真反而更值得担心。所以这两个功能我的默认配置都是关闭。如果项目方明确要求去重比如做绝对定量那要在流程文档里写清楚并且下游分析时要意识到丰度已经被改变过。3. 一套能直接跑的宏基因组质控命令3.1 单样本命令逐行注释下面这条命令是我目前宏基因组项目里的基础版参数按上一章的逻辑设定可以直接复制改路径使用。fastp \ -i sample_R1.fastq.gz \ -I sample_R2.fastq.gz \ -o sample_clean_R1.fastq.gz \ -O sample_clean_R2.fastq.gz \ --detect_adapter_for_pe \ --adapter_sequence AGATCGGAAGAGCACACGTCTGAACTCCAGTCA \ --adapter_sequence_r2 AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT \ --cut_front \ --cut_tail \ --cut_window_size 4 \ --cut_mean_quality 20 \ -q 20 \ -u 40 \ -n 5 \ -l 50 \ --trim_poly_g \ --poly_g_min_len 10 \ -w 12 \ --json sample.fastp.json \ --html sample.fastp.html \ -R sample_qc_report \ 2 sample.fastp.log逐段解释一下关键选择。--detect_adapter_for_pe加上显式接头序列是双保险前者靠 overlap 检测后者靠序列匹配两条路都走一遍接头残留概率最低。--cut_front --cut_tail双向滑窗比--cut_right温和保留更多有效序列。-q 20 -u 40是前面说的平衡点。-l 50是宏基因组的实用下限。--trim_poly_g显式写出来保证跨平台一致性。-w 12是线程数一般设成物理核心数的 60% 到 80%留出 IO 和其他进程的空间。-R给报告加标题批量跑的时候方便在 HTML 里区分样本。2把日志单独存Fastp 的 stderr 里有关键的统计信息出错时是排查的第一手材料。关于线程数还有一个实操细节-w设太大并不会一直更快。Fastp 的主要瓶颈在 gzip 解压和写盘线程数超过 16 以后收益递减明显反而可能因为 IO 争抢导致整体变慢。我在 32 核的机器上实测-w 12和-w 24的耗时差距不到 10%但内存占用和 IO 压力差别明显。3.2 批量样本的调度脚本宏基因组项目动辄几十个样本手工跑不现实。我一般用一个简单的 shell 循环加并发控制不依赖任何流程管理框架好处是透明、好排查。#!/bin/bash set -euo pipefail RAW_DIR./raw CLEAN_DIR./clean REPORT_DIR./qc_report THREADS12 PARALLEL4 mkdir -p ${CLEAN_DIR} ${REPORT_DIR} run_one() { local sample$1 fastp \ -i ${RAW_DIR}/${sample}_R1.fastq.gz \ -I ${RAW_DIR}/${sample}_R2.fastq.gz \ -o ${CLEAN_DIR}/${sample}_clean_R1.fastq.gz \ -O ${CLEAN_DIR}/${sample}_clean_R2.fastq.gz \ --detect_adapter_for_pe \ --adapter_sequence AGATCGGAAGAGCACACGTCTGAACTCCAGTCA \ --adapter_sequence_r2 AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT \ --cut_front --cut_tail \ --cut_window_size 4 --cut_mean_quality 20 \ -q 20 -u 40 -n 5 -l 50 \ --trim_poly_g --poly_g_min_len 10 \ -w ${THREADS} \ --json ${REPORT_DIR}/${sample}.fastp.json \ --html ${REPORT_DIR}/${sample}.fastp.html \ -R ${sample} \ 2 ${REPORT_DIR}/${sample}.fastp.log } export -f run_one export RAW_DIR CLEAN_DIR REPORT_DIR THREADS ls ${RAW_DIR}/*_R1.fastq.gz \ | sed s#.*/##; s/_R1.fastq.gz// \ | xargs -I{} -P ${PARALLEL} bash -c run_one $ _ {}这段脚本的核心是xargs -P做并发控制。PARALLEL4配合THREADS12总线程占用约 48适合 64 核左右的机器。如果你的机器核数少把PARALLEL降到 2THREADS提到 8总占用控制在核数的 80% 以内。注意并发数和单任务线程数的乘积不要超过物理核心数太多。超了以后多个 Fastp 进程会互相抢 IO总耗时反而变长而且 gzip 写入可能因为缓冲不足出现异常。脚本里用set -euo pipefail是刻意的。宏基因组批量跑最怕的是某个样本静默失败等你发现的时候已经跑完了全部样本还得回头找哪个出了问题。加上这个设置任何一个样本出错脚本立即停止日志里能直接定位。3.3 报告怎么读三个必须看的指标Fastp 的 HTML 报告信息量很大但宏基因组真正要盯的只有几个指标。第一是 clean reads 比例报告里的 After filtering 部分。一般来说宏基因组数据这个比例在 90% 以上算正常85% 到 90% 需要看一眼原因低于 85% 就要深入排查了。比例低常见的原因有三个原始数据质量差、接头含量高、或者-l 50切掉了太多短片段。要区分这三种情况看报告里 Filtering result 的细分因为 too short 丢了多少、因为 too many N 丢了多少、因为 low quality 丢了多少。如果 too short 占大头说明文库片段偏短可以考虑把-l降到 36如果 low quality 占大头说明测序质量本身有问题。第二是 Q20 和 Q30 比例报告里的 Qualities 部分。质控后的 Q30 比例建议在 90% 以上Q20 在 95% 以上。如果质控后 Q30 还不到 85%说明滑窗裁剪的力度不够或者原始数据质量太差。这时候不要急着调参数先看质量分布图如果质量下滑集中在 3 端末尾几十 bp加大--cut_tail的力度有效如果整条 read 质量都偏低那是测序问题调参无用。第三是插入片段长度分布报告里的 Insert size estimation 部分。这个图能反映文库构建质量。正常的宏基因组文库应该是一个以 300 到 500 bp 为中心的宽峰。如果峰值出现在很短的区域比如 100 bp 以下说明存在大量引物二聚体或者文库片段化过度。如果分布异常宽或者出现双峰可能是建库时片段筛选没做好。这个信息对判断数据可用性非常关键但很多人看报告时直接跳过。3.4 质控之后接去宿主顺序与衔接细节Fastp 跑完之后宏基因组流程的下一步通常是去宿主。顺序上一定要先质控再去宿主理由是接头和低质量碱基会干扰比对带着接头去比对宿主参考基因组会产生大量假比对和软剪切去宿主的结果就不可信了。而且去宿主用的比对工具比如 bowtie2对 reads 长度有隐含要求太短的 reads 比对特异性差会误删真实微生物序列。去宿主的典型命令是这样bowtie2 -p 12 -x host_ref \ -1 sample_clean_R1.fastq.gz \ -2 sample_clean_R2.fastq.gz \ --un-conc-gz sample_host_removed_%.fastq.gz \ 2 bowtie2.log | \ samtools view -bS - | \ samtools sort - 4 -o sample_host_aligned.bam--un-conc-gz输出的是没有比对到宿主的 read 对这个才是下游要用的。%.fastq.gz里的%会被替换成1和2分别对应 R1 和 R2。比对上的部分存成 BAM 备查万一发现去宿主去过头了还能回溯。这里有个细节要留意bowtie2 对短于 50 bp 的 reads 默认会关闭部分比对模式这也是前面把-l设到 50 的一个连带考虑。如果质控时把长度下限设成 36去宿主阶段可能有一部分 reads 被 bowtie2 直接跳过导致结果不一致。去宿主之后的 reads 数量通常还会再掉 1% 到 10%具体取决于样本类型。粪便样本宿主占比低掉得少组织样本或者血液样本宿主占比高可能掉 50% 以上。这个比例要在项目记录里写清楚因为下游做丰度归一化时总 reads 数到底是指质控前、质控后还是去宿主后不同定义会得出完全不同的结论。4. 踩坑实录那些参数跑完才发现的问题4.1 数据量掉得离谱问题往往不在参数有一批样本质控后 clean reads 只剩下原始的 62%而同一批次的另外几个样本都在 92% 以上。第一反应是参数问题逐个排查后发现参数完全一样。于是去看--failed_out输出我没在基础命令里加这个参数排查时临时加上去的把被丢弃的 reads 导出来看发现全是富含 AT 的短序列长度集中在 30 到 45 bp 之间。这批数据的实际情况是建库时片段筛选没做好产生了大量短片段这些短片段在 PE150 测序里读穿了整个插入片段后半段全是接头。Fastp 的接头剪切把接头切掉之后剩下的有效序列自然就短了-l 50一卡整条丢掉。这不是参数错是数据本身的特征。处理办法是把-l降到 36同时在下游组装时把最小 contig 长度从 500 提到 800用更严格的组装过滤来补偿短 reads 带来的噪音。这个坑的教训是clean reads 比例异常时先看被丢弃的 reads 长什么样再决定调不调参数。--failed_out这个参数平时不用加排查时加上能省掉大量猜测时间。用法是--failed_out failed.fq.gz输出的是所有被过滤掉的 reads可以拿去 FastQC 或者直接 zcat 看几条。4.2 接头残留与 overlap 误判的辨别方法接头残留的典型症状是质控报告显示接头已经剪切但下游比对时 soft-clip 比例异常高或者组装出来的 contig 末端出现非生物学的重复序列。判断方法很直接用 grep 在 clean reads 里搜接头核心序列zcat sample_clean_R1.fastq.gz | head -400000 | grep -c AGATCGGAAGAGC如果 40 万条 reads 里能搜到几百条以上说明接头剪切不彻底。原因可能是 overlap 分析失败插入片段太长R1 和 R2 没有重叠或者接头序列和显式指定不一致用了非 TruSeq 的试剂盒。解决办法是查清试剂盒的接头序列显式指定如果插入片段确实很长考虑用专门的接头剪切工具做二次处理。overlap 误判是另一个隐蔽问题。表现是 clean reads 长度分布出现异常的双峰一部分 reads 被切得特别短。原因是 Fastp 在 overlap 分析时如果两条 reads 的 3 端偶然出现匹配可能误判为接头并剪切。这种情况在低复杂度序列比如 polyA 尾上特别容易发生。缓解办法是提高--overlap_len_require从默认 30 提到 35 或 40减少偶然匹配的概率。代价是短插入片段的接头可能漏切需要权衡。4.3 速度、线程与内存的实测数据我在一台 64 核、256 GB 内存的机器上做过一组对比测试样本是 6 GB 的 PE150 宏基因组数据gzip 压缩。线程数并行样本数单样本耗时总内存峰值备注41约 11 分钟约 1.2 GB适合小机器81约 7 分钟约 1.5 GB性价比拐点121约 6 分钟约 1.8 GB我常用配置161约 5.5 分钟约 2.2 GB收益开始递减241约 5.4 分钟约 3.0 GB基本无提升124约 8 分钟约 7 GB吞吐最优从数据看单样本线程数超过 12 以后收益很小瓶颈在 IO。但如果并行跑多个样本总吞吐会明显提升因为多个进程可以错开 IO 等待。所以批量场景下少线程多并行比多线程单并行更划算。内存方面Fastp 的内存占用主要和线程数、reads 长度相关单样本通常不超过 3 GB。但要注意 gzip 输出的缓冲如果输出目录所在磁盘 IO 慢缓冲区会堆积内存占用会比预期高。我曾经遇到过一次内存告警排查发现是输出目录挂载在网络存储上写入延迟导致缓冲堆积换成本地盘后恢复正常。4.4 常见问题速查表现象最可能原因排查方法处理建议clean reads 比例低于 80%文库片段短或质量差加--failed_out看被丢弃 reads降低-l检查建库记录质控后 Q30 仍低于 85%滑窗力度不足或原始质量差看报告质量分布图加大--cut_tail或判定数据不可用接头残留接头序列不匹配或 overlap 失败grep 接头核心序列显式指定正确接头提高 overlap 要求clean reads 长度双峰overlap 误判看长度分布图提高--overlap_len_require下游物种多样性异常低质控过严对比质控前后物种注释结果放宽-q、-l关闭--correction运行极慢IO 瓶颈或线程过少看 CPU 和 IO 占用调整线程换本地盘输出内存占用异常高输出缓冲堆积看输出目录 IO 延迟换本地盘减少并行数批次间结果差异大参数不一致对比各样本日志里的参数记录统一参数脚本版本化管理这张表里的每一条我都至少遇到过一次其中下游物种多样性异常低这一条最容易被误判。因为它不报错流程照常跑完只有在做多样性分析时才发现 alpha 多样性比预期低很多。排查方法是拿同一批数据用两套参数各跑一遍对比物种注释结果差异集中在低丰度物种上基本就能确认是质控过严。5. 工程化收尾让质控这一步不再成为返工点5.1 批次间参数一致性比参数本身更重要做宏基因组项目最忌讳的是这批数据看起来质量差一点我调一下参数。因为一旦参数不一致后面所有的比较分析都失去了基础。你今天用-q 20 -l 50跑了十个样本明天觉得另外五个样本质量差改成-q 15 -l 36看起来是因材施教实际上引入了一个无法量化的批次效应不同样本的 reads 被过滤的标准不一样物种丰度的相对关系已经被改变了。我的做法是项目启动时定一套参数整个项目不改。如果确实遇到某个样本质量特别差处理方式是要么整批重跑要么把这个样本标记为异常并在分析时单独说明绝不单独调参。参数的选择依据可以写在项目文档里比如基于预实验数据的 Q30 分布选择-q 20这样即使别人接手也能理解为什么这么选。还有一个细节是参数要跟着脚本走不能跟着人走。我见过实验室里每个人都有自己的 fastp 命令跑出来的结果互相对不上。解决办法是把命令封装成脚本脚本进版本管理每次运行记录脚本版本号。这样半年后回头看某批数据能准确知道当时用的什么参数。5.2 版本锁定与目录规范Fastp 的版本更新会带来行为变化最典型的是默认参数调整和自动检测逻辑的改动。比如某些版本对双端数据默认开启 overlap 分析某些版本对 polyG 的自动检测条件有变化。如果不在环境里锁定版本半年后重跑同一批数据可能得到不一样的结果。我的做法是用 conda 环境锁定版本环境文件里写死 fastp 的具体版本号整个项目周期不升级。同时在项目目录下留一份env_export.yml记录完整的依赖树。这样即使原始环境损坏也能精确重建。目录结构上我习惯把质控环节的输出单独放一层和原始数据、去宿主结果、组装结果平级project/ ├── 00_raw/ ├── 01_qc/ │ ├── clean/ │ ├── report/ │ └── log/ ├── 02_host_removed/ ├── 03_assembly/ └── ...这样做的实际好处是排查问题时能快速定位到某一层重跑时只需要删掉对应目录不会误删其他环节的结果。报告和日志分开存也是刻意的报告给人看日志给脚本和排查用混在一起时间长了会很乱。5.3 下游衔接前的最后检查清单质控跑完之后别急着往下走。我一般会做一个几分钟的检查能挡掉大部分后面才会暴露的问题。第一看 clean reads 数量是否满足下游最低要求。组装一般要求每个样本至少 3 Gb 有效数据物种分类要求低一些1 Gb 也能跑但低丰度物种检出率会下降。如果某个样本 clean 后不到 1 Gb要提前和项目方沟通别等组装跑完才发现数据不够。第二随机抽几条 clean reads 肉眼看一下。听起来很原始但很有效。zcat clean_R1.fastq.gz | head -8看前两条 read 的序列和质量值如果开头就是一堆低质量字符说明滑窗裁剪没生效如果序列末尾还有明显的接头特征说明接头剪切有问题。这个动作花不了一分钟但能发现很多自动化检查漏掉的问题。第三对比质控前后的 reads 数量比例是否符合预期。同一个项目里各样本的 clean ratio 应该大致接近如果某个样本明显偏离要么是数据本身异常要么是样本类型不同比如宿主占比差异大。这个偏离本身不是错误但要在分析时作为协变量考虑。第四确认报告文件和日志文件都完整生成。Fastp 偶尔会因为磁盘满或者权限问题导致报告写入失败但主流程不报错等到要汇总报告时才发现缺了几个样本。用一个简单的ls report/*.html | wc -l和样本数对比一下十几秒的事。我个人在实际操作中的体会是宏基因组质控这一步的技术门槛不高难的是保持一致性和可追溯性。参数怎么设看几篇文档就能定但能不能在几十个样本、几个月周期、多个人协作的情况下始终用同一套标准并且随时能说清楚每个样本经历了什么处理这才是真正拉开差距的地方。Fastp 这条命令本身十分钟就能学会把它用稳、用出可复现的结果需要的是流程意识而不是工具技巧。