
HuggingFace Tokenizers 分词管线完全指南Normalizer、Pre-tokenizer、Model、Post-processor 与 Decoder 全组件深度解析【免费下载链接】AI-Research-SKILLsComprehensive open-source library of AI research and engineering skills for any AI model. Package the skills and your claude code/codex/gemini agent will be an AI research agent with full horsepower. Maintained by Orchestra Research.项目地址: https://gitcode.com/gh_mirrors/ai/AI-Research-SKILLs导读本文是 AI-Research-SKILLs 仓库中 huggingface-tokenizers 技能包 的管线组件专题围绕tokenizers库从原始文本到Token IDs再到还原回文本的完整生命周期系统讲解 Normalizers、Pre-tokenizers、Models、Post-processors、Decoders 五大组件的职责、API 与配置细节。读完本文你将掌握如何像搭建 BERT / GPT-2 / T5 那样从零组装一条生产级分词管线并能熟练运用 offset 对齐追踪机制解决 NER、问答等下游任务的标签映射问题。文章主体以 pipeline.md 为骨架并结合 algorithms.md、training.md、integration.md 及技能包 SKILL.md 中的实现细节进行纵深展开。管线全景文本如何一步步变成 Token IDtokenizers库的核心设计思想是把分词拆解为一条可插拔、可组合的处理链。完整的编码流程如下Raw Text ↓ Normalization (cleaning, lowercasing) ↓ Pre-tokenization (split into words) ↓ Model (apply BPE/WordPiece/Unigram) ↓ Post-processing (add special tokens) ↓ Token IDs而解码Decoding则是这条链的逆过程Token IDs ↓ Decoder (handle special encodings) ↓ Raw Text每一个环节都对应tokenizers库中的一个独立组件类型且都能被单独配置、替换甚至自定义见 pipeline.md。需要强调的是这一流水线设计正是该库Rust 核心 Python 绑定高性能架构的体现——整套管线在 Rust 层并行执行Python 端只做配置与结果读取这也是其能以极快速度处理 GB 级语料的根本原因技能包描述中给出的参考指标为 CPU 上 1GB 文本 20 秒详见 SKILL.md。Normalizers文本清洗与标准化Normalizer 位于管线最前端负责把原始文本清洗为统一形式以便后续切分。它直接影响词汇表质量和 OOVout-of-vocabulary率是整个管线中最容易被忽略却最影响效果的环节。常用 Normalizer 一览Lowercase小写化from tokenizers.normalizers import Lowercase tokenizer.normalizer Lowercase() # Input: Hello WORLD # Output: hello worldUnicode 规范化tokenizers.normalizers提供四种 Unicode 归一形式NFD / NFC / NFKD / NFKC区别在于是否分解decompose以及是否做兼容性compatibility转换from tokenizers.normalizers import NFD, NFC, NFKD, NFKC # NFD: Canonical decomposition规范分解 tokenizer.normalizer NFD() # é → e ́ (separate characters) # NFC: Canonical composition规范组合默认 tokenizer.normalizer NFC() # e ́ → é (composed) # NFKD: Compatibility decomposition兼容分解 tokenizer.normalizer NFKD() # fi → f i # NFKC: Compatibility composition兼容组合最激进 tokenizer.normalizer NFKC()去重音符号from tokenizers.normalizers import StripAccents tokenizer.normalizer StripAccents() # Input: café # Output: cafe空白处理from tokenizers.normalizers import Strip # 移除首尾空白 tokenizer.normalizer Strip() # Input: hello # Output: hello正则替换from tokenizers.normalizers import Replace # 将换行替换为空格 tokenizer.normalizer Replace(\\n, ) # Input: hello\\nworld # Output: hello world组合 NormalizerSequence单一 Normalizer 往往不够实际场景中通常需要用Sequence把多个规范化步骤串起来。BERT 风格的典型做法是Unicode 分解 → 小写 → 去重音三步走from tokenizers.normalizers import Sequence, NFD, Lowercase, StripAccents # BERT-style normalization tokenizer.normalizer Sequence([ NFD(), # Unicode decomposition Lowercase(), # Convert to lowercase StripAccents() # Remove accents ]) # Input: Café au Lait # After NFD: Café au Lait (e ́) # After Lowercase: café au lait # After StripAccents: cafe au lait面向模型架构的选型实践不同模型族对 Normalizer 的激进程度要求完全不同pipeline.md 给出了三组典型搭配大小写不敏感模型BERT——使用开箱即用的BertNormalizer四个开关参数一目了然from tokenizers.normalizers import BertNormalizer # All-in-one BERT normalization tokenizer.normalizer BertNormalizer( clean_textTrue, # 移除控制字符 handle_chinese_charsTrue, # 中文两侧加空格 strip_accentsTrue, # 去除重音 lowercaseTrue # 小写化 )大小写敏感模型GPT-2——只做最克制的 Unicode 规范化# Minimal normalization tokenizer.normalizer NFC() # Only normalize Unicode多语言模型mBERT——保留文字体系差异仅归一化字形# Preserve scripts, normalize form tokenizer.normalizer NFKC()关于大小写策略的进一步讨论可见 algorithms.mdGPT-2 这类模型不设 Normalizer 以保留大小写信息RoBERTa 则依赖词表同时容纳Hello/hello/HELLO等不同形态的 token。Pre-tokenizers把文本切分成词级单元Pre-tokenizer 在 Normalizer 之后、Model 之前执行将文本切分为词级别的单元并记录每个单元在原始文本中的字符偏移量offset。这一层的选择直接决定 Model 的训练与推理粒度也决定了后续对齐追踪的精度。常用 Pre-tokenizer 逐个击破Whitespace空白切分——最简单也最常用from tokenizers.pre_tokenizers import Whitespace tokenizer.pre_tokenizer Whitespace() # Input: Hello world! How are you? # Output: [(Hello, (0, 5)), (world!, (6, 12)), (How, (13, 16)), (are, (17, 20)), (you?, (21, 25))]注意输出是(词, (起始偏移, 结束偏移))的元组列表偏移量是相对原始文本的这正是对齐追踪能力的来源。Punctuation标点隔离——把标点从词中剥离出来from tokenizers.pre_tokenizers import Punctuation tokenizer.pre_tokenizer Punctuation() # Input: Hello, world! # Output: [(Hello, ...), (,, ...), (world, ...), (!, ...)]ByteLevel字节级GPT-2 风格——GPT-2 家族的核心将整个文本按 UTF-8 字节切分from tokenizers.pre_tokenizers import ByteLevel tokenizer.pre_tokenizer ByteLevel(add_prefix_spaceTrue) # Input: Hello world # Output: Byte-level tokens with Ġ prefix for spaces # [(ĠHello, ...), (Ġworld, ...)]关键特性字节级方案天然覆盖全部 256 种字节组合因此能处理任意 Unicode 字符包括 emoji且理论上永不产生 UNK最坏情况退回字节表示。这与 algorithms.md 中Byte-level BPE一节相互印证——它解决了标准 BPE 字符覆盖不足的问题代价是非 ASCII 文本会占用更多 token。MetaspaceSentencePiece 风格——用▁代替空格from tokenizers.pre_tokenizers import Metaspace tokenizer.pre_tokenizer Metaspace(replacement▁, add_prefix_spaceTrue) # Input: Hello world # Output: [(▁Hello, ...), (▁world, ...)]被 T5、ALBERT经由 SentencePiece使用。Digits数字切分——可按单个数字或整组数字切分from tokenizers.pre_tokenizers import Digits # 逐位切分 tokenizer.pre_tokenizer Digits(individual_digitsTrue) # Input: Room 123 # Output: [(Room, ...), (1, ...), (2, ...), (3, ...)] # 整组保留 tokenizer.pre_tokenizer Digits(individual_digitsFalse) # Input: Room 123 # Output: [(Room, ...), (123, ...)]BertPreTokenizerBERT 风格——按空白与标点切分且对 CJK 字符逐字保留from tokenizers.pre_tokenizers import BertPreTokenizer tokenizer.pre_tokenizer BertPreTokenizer() # Splits on whitespace and punctuation, preserves CJK # Input: Hello, 世界! # Output: [(Hello, ...), (,, ...), (世, ...), (界, ...), (!, ...)]组合 Pre-tokenizerSequence与 Normalizer 一样Pre-tokenizer 也支持用Sequence级联。例如先按空白切分、再隔离标点的组合from tokenizers.pre_tokenizers import Sequence, Whitespace, Punctuation tokenizer.pre_tokenizer Sequence([ Whitespace(), # Split on whitespace first Punctuation() # Then isolate punctuation ]) # Input: Hello, world! # After Whitespace: [(Hello,, ...), (world!, ...)] # After Punctuation: [(Hello, ...), (,, ...), (world, ...), (!, ...)]Pre-tokenizer 选型对照表Pre-tokenizerUse CaseExampleWhitespace简单英文Hello world → [Hello, world]Punctuation隔离符号world! → [world, !]ByteLevel多语言、emoji → byte tokensMetaspaceSentencePiece 风格Hello → [▁Hello]BertPreTokenizerBERT 风格CJK 感知世界 → [世, 界]Digits处理数字123 → [1, 2, 3] 或 [123]Models核心分词算法Model 是管线的发动机负责把词级单元进一步切成子词subword。tokenizers库支持 BPE、WordPiece、Unigram、WordLevel 四种模型对应 SKILL.md 中描述的算法族。训练细节与算法原理见 algorithms.md 与 training.md本文聚焦其模型侧参数。BPE Model字节对编码from tokenizers.models import BPE model BPE( vocabNone, # 或传入预构建的 token→id 字典 mergesNone, # 或传入合并规则列表 unk_token[UNK], # 未知 token continuing_subword_prefix, end_of_word_suffix, fuse_unkFalse # 保持未知 token 独立 ) tokenizer Tokenizer(model)参数说明vocabtoken → id 的字典merges合并规则列表如[a b, ab c]格式为左 右的字符串表示把左右两个符号合并unk_token未知词的占位 tokencontinuing_subword_prefix子词前缀GPT-2 中为空字符串end_of_word_suffix词尾子词后缀GPT-2 中为空字符串。BPE 的训练逻辑algorithms.md是从字符级词汇表出发统计相邻 pair 频次反复合并最高频 pair 直到达到目标词表大小。它的优势是 OOV 处理好、词表规模灵活适合形态丰富的语言代价是切分结果依赖合并顺序可能意外拆开常见词。WordPiece ModelBERT 风格from tokenizers.models import WordPiece model WordPiece( vocabNone, unk_token[UNK], max_input_chars_per_word100, # 单个词的最大字符数 continuing_subword_prefix## # BERT 风格续词前缀 ) tokenizer Tokenizer(model)关键差异WordPiece 使用##前缀标记续词continuation。与 BPE 的纯频次合并不同WordPiece 用score freq(pair) / (freq(first) × freq(second))打分倾向于合并共现超出预期的语义相关组合详见 algorithms.md。训练过程中continuing_subword_prefix##由WordPieceTrainer传入见 training.md。未知词若没有任何子词匹配则整体退化为[UNK]。Unigram Model概率模型from tokenizers.models import Unigram model Unigram( vocabNone, # (token, score) 元组列表 unk_id0, # 未知 token 的 ID byte_fallbackFalse # 无匹配时是否回退到字节 ) tokenizer Tokenizer(model)概率化特性Unigram 在多个合法切分中选取概率最高者天然支持子词正则化subword regularization与采样增强algorithms.md。其训练采用从大词表出发、按损失影响逐轮剔除 token的逆向策略训练超参max_piece_length、n_sub_iterations、shrinking_factor详见 training.md。WordLevel Model整词映射from tokenizers.models import WordLevel # 简单 word→ID 映射无子词 model WordLevel( vocabNone, unk_token[UNK] ) tokenizer Tokenizer(model)警告该模型需要巨大词表每个词一个 token仅适用于词表受限的场景例如字符级任务参考 training.md 中 1,000–5,000 规模的字符级词表建议。Post-processors追加特殊 token 与格式化Model 输出 token 序列后Post-processor 负责按模型约定追加[CLS]、[SEP]、s、/s、|endoftext|等特殊 token使输出满足预训练模型的输入格式。TemplateProcessing模板驱动的通用方案BERT 风格[CLS] sentence [SEP]单句与句子对from tokenizers.processors import TemplateProcessing tokenizer.post_processor TemplateProcessing( single[CLS] $A [SEP], pair[CLS] $A [SEP] $B [SEP], special_tokens[ ([CLS], 101), ([SEP], 102), ], ) # 单句 output tokenizer.encode(Hello world) # [101, ..., 102] ([CLS] hello world [SEP]) # 句子对 output tokenizer.encode(Hello, world) # [101, ..., 102, ..., 102] ([CLS] hello [SEP] world [SEP])模板中的$A/$B是占位符分别代表第一、第二段输入special_tokens列表把 token 字符串映射到其在词表中的 ID。GPT-2 风格sentence |endoftext|tokenizer.post_processor TemplateProcessing( single$A |endoftext|, special_tokens[ (|endoftext|, 50256), ], )RoBERTa 风格s sentence /s注意句子对中/s出现两次tokenizer.post_processor TemplateProcessing( singles $A /s, pairs $A /s /s $B /s, special_tokens[ (s, 0), (/s, 2), ], )T5 风格不追加特殊 token# T5 不通过 post-processor 追加特殊 token tokenizer.post_processor None实战提示在自定义训练场景中特殊 token 的 ID 应通过tokenizer.token_to_id([CLS])动态获取避免硬编码——这是 training.md 中推荐的稳健写法因为special_tokens在BpeTrainer/WordPieceTrainer中总是最先加入词表。RobertaProcessingRoBERTa 专用封装from tokenizers.processors import RobertaProcessing tokenizer.post_processor RobertaProcessing( sep(/s, 2), cls(s, 0), add_prefix_spaceTrue, # 首 token 前加空格 trim_offsetsTrue # 裁剪偏移量中的前导空格 )ByteLevelProcessing字节级偏移修正from tokenizers.processors import ByteLevel as ByteLevelProcessing tokenizer.post_processor ByteLevelProcessing( trim_offsetsTrue # 从偏移量中移除 Ġ )trim_offsetsTrue在这里至关重要ByteLevel 预切分会把空格编码进 token 的偏移范围开启该项后偏移量会被裁剪为不含前导空格的精确区间保证对齐映射的语义正确。Decoders把 Token ID 还原为文本解码是编码的逆过程但并不是简单拼接——它需要撤销各组件引入的特殊编码##前缀、▁空格标记、字节映射等。pipeline.md 强调解码器必须与编码管线严格匹配否则会输出带##或▁的脏文本。各模型配套的 DecoderByteLevel 解码器还原字节映射与空格from tokenizers.decoders import ByteLevel tokenizer.decoder ByteLevel() # Handles byte-level tokens # [ĠHello, Ġworld] → Hello worldWordPiece 解码器去掉##前缀并拼接from tokenizers.decoders import WordPiece tokenizer.decoder WordPiece(prefix##) # Removes ## prefix and concatenates # [token, ##ization] → tokenizationMetaspace 解码器把▁还原为空格from tokenizers.decoders import Metaspace tokenizer.decoder Metaspace(replacement▁, add_prefix_spaceTrue) # Converts ▁ back to spaces # [▁Hello, ▁world] → Hello worldBPEDecoder移除词尾后缀并拼接from tokenizers.decoders import BPEDecoder tokenizer.decoder BPEDecoder(suffix/w) # Removes suffix and concatenates # [token, ization/w] → tokenizationSequence 解码器多步级联例如先做字节解码再做空白清理from tokenizers.decoders import Sequence, ByteLevel, Strip tokenizer.decoder Sequence([ ByteLevel(), # Decode byte-level first Strip( , 1, 1) # Strip leading/trailing spaces ])完整管线实战BERT、GPT-2、T5 三套标准组装把上述组件串联起来即可复刻主流模型的完整分词管线。以下三套完整示例可直接复制运行tokenizers安装方式pip install tokenizers详见 SKILL.md。BERT Tokenizerfrom tokenizers import Tokenizer from tokenizers.models import WordPiece from tokenizers.normalizers import BertNormalizer from tokenizers.pre_tokenizers import BertPreTokenizer from tokenizers.processors import TemplateProcessing from tokenizers.decoders import WordPiece as WordPieceDecoder # Model tokenizer Tokenizer(WordPiece(unk_token[UNK])) # Normalization tokenizer.normalizer BertNormalizer(lowercaseTrue) # Pre-tokenization tokenizer.pre_tokenizer BertPreTokenizer() # Post-processing tokenizer.post_processor TemplateProcessing( single[CLS] $A [SEP], pair[CLS] $A [SEP] $B [SEP], special_tokens[([CLS], 101), ([SEP], 102)], ) # Decoder tokenizer.decoder WordPieceDecoder(prefix##) # Enable padding tokenizer.enable_padding(pad_id0, pad_token[PAD]) # Enable truncation tokenizer.enable_truncation(max_length512)GPT-2 Tokenizerfrom tokenizers import Tokenizer from tokenizers.models import BPE from tokenizers.normalizers import NFC from tokenizers.pre_tokenizers import ByteLevel from tokenizers.decoders import ByteLevel as ByteLevelDecoder from tokenizers.processors import TemplateProcessing # Model tokenizer Tokenizer(BPE()) # Normalization (minimal) tokenizer.normalizer NFC() # Byte-level pre-tokenization tokenizer.pre_tokenizer ByteLevel(add_prefix_spaceFalse) # Post-processing tokenizer.post_processor TemplateProcessing( single$A |endoftext|, special_tokens[(|endoftext|, 50256)], ) # Byte-level decoder tokenizer.decoder ByteLevelDecoder()T5 TokenizerSentencePiece 风格from tokenizers import Tokenizer from tokenizers.models import Unigram from tokenizers.normalizers import NFKC from tokenizers.pre_tokenizers import Metaspace from tokenizers.decoders import Metaspace as MetaspaceDecoder # Model tokenizer Tokenizer(Unigram()) # Normalization tokenizer.normalizer NFKC() # Metaspace pre-tokenization tokenizer.pre_tokenizer Metaspace(replacement▁, add_prefix_spaceTrue) # No post-processing (T5 doesnt add CLS/SEP) tokenizer.post_processor None # Metaspace decoder tokenizer.decoder MetaspaceDecoder(replacement▁, add_prefix_spaceTrue)三套管线的组件选型规律可以归纳为模型架构决定组件搭配模型NormalizerPre-tokenizerModelPost-processorDecoderBERTBertNormalizerBertPreTokenizerWordPieceTemplateProcessingWordPieceDecoderGPT-2NFCByteLevelBPETemplateProcessingByteLevelT5NFKCMetaspaceUnigramNoneMetaspace这一对照关系同时出现在 pipeline.md 的 best practices 中是复现任何预训练模型分词行为的最短路径。Alignment TrackingToken 与原始文本的对齐追踪tokenizers的杀手级能力是对齐追踪alignment tracking每个 token 都携带其在原始文本中的字符区间这为 NER、问答等需要把模型预测映射回原文的任务提供了坚实底座。与之互补的offset_mapping、word_ids()、char_to_token()等 transformers 侧接口见 integration.md。基础对齐逐 token 打印偏移text Hello, world! output tokenizer.encode(text) for token, (start, end) in zip(output.tokens, output.offsets): print(f{token:10s} → [{start:2d}, {end:2d}): {text[start:end]!r}) # Output: # [CLS] → [ 0, 0): # hello → [ 0, 5): Hello # , → [ 5, 6): , # world → [ 7, 12): world # ! → [12, 13): ! # [SEP] → [ 0, 0): 注意特殊 token[CLS]/[SEP]的偏移区间是[0, 0)——它们不对应任何原文这是判断该 token 是否为特殊 token的可靠信号。词级对齐word_idsword_ids返回每个 token 属于哪个原始词由 pre-tokenizer 的切分结果决定# Get word_ids (which word each token belongs to) encoding tokenizer.encode(Hello world) word_ids encoding.word_ids print(word_ids) # [None, 0, 0, 1, None] # None special token, 0 first word, 1 second word典型应用命名实体识别NER标签对齐——把逐 token 的模型预测聚合到词级别# Align predictions to words predictions [O, B-PER, I-PER, O, O] word_predictions {} for token_idx, word_idx in enumerate(encoding.word_ids): if word_idx is not None and word_idx not in word_predictions: word_predictions[word_idx] predictions[token_idx] print(word_predictions) # {0: B-PER, 1: O} # First word is PERSON, second is OTHER区间对齐char_to_token反向映射——给定字符区间找到对应 token 区间这是抽取式问答extractive QA的标准操作# Find token span for character span text Machine learning is awesome char_start, char_end 8, 16 # learning encoding tokenizer.encode(text) # Find token span token_start encoding.char_to_token(char_start) token_end encoding.char_to_token(char_end - 1) 1 print(fTokens {token_start}:{token_end} {encoding.tokens[token_start:token_end]}) # Tokens 2:3 [learning]这套双向映射token→offset、char→token、token→word正是快速分词器fast tokenizer独有、慢速 Python 分词器所不具备的能力也是 integration.md 中总是优先使用 fast tokenizer建议的技术根源。自定义组件编写自己的 Normalizer 与 Pre-tokenizer当内置组件无法满足领域需求如专有符号、特殊空白规则时可以像 pipeline.md 展示的那样通过鸭子类型duck-typing实现自定义组件赋值给对应属性即可。自定义 Normalizerfrom tokenizers import NormalizedString, Normalizer class CustomNormalizer: def normalize(self, normalized: NormalizedString): # Custom normalization logic normalized.lowercase() normalized.replace( , ) # Replace double spaces # Use custom normalizer tokenizer.normalizer CustomNormalizer()自定义 Pre-tokenizerfrom tokenizers import PreTokenizedString class CustomPreTokenizer: def pre_tokenize(self, pretok: PreTokenizedString): # Custom pre-tokenization logic pretok.split(lambda i, char: char.isspace()) tokenizer.pre_tokenizer CustomPreTokenizer()NormalizedString与PreTokenizedString是 Rust 核心暴露给 Python 的可原地修改句柄所有操作都会被记录从而保证偏移量在整条管线中持续有效——这是自定义组件必须通过这些句柄而非普通字符串操作的根本原因。疑难排查三类高频故障与解决方案pipeline.md 归纳了三个最常见的问题场景这里补充排查思路偏移量错位Misaligned offsets症状token 偏移量与原始文本对不上例如text hello却得到offsets [(0, 5)]。根因Normalizer 中的Strip()会改变文本长度从而破坏偏移基准。解决不要在 Normalizer 里删空白改用 post-processor 的trim_offsets# Preserve offsets tokenizer.normalizer Sequence([ Strip(), # This changes offsets! ]) # Use trim_offsets in post-processor instead tokenizer.post_processor ByteLevelProcessing(trim_offsetsTrue)特殊 token 未追加症状输出中看不到[CLS]或[SEP]。解决确认 post-processor 已设置。这是最常见的疏漏——训练完模型后忘记配置TemplateProcessingtokenizer.post_processor TemplateProcessing( single[CLS] $A [SEP], special_tokens[([CLS], 101), ([SEP], 102)], )解码结果出现##或▁症状decode()输出中包含##或▁等残留符号。解决Decoder 与 Model 不匹配必须按算法配对设置# For WordPiece tokenizer.decoder WordPieceDecoder(prefix##) # For SentencePiece tokenizer.decoder MetaspaceDecoder(replacement▁)最佳实践总结管线组件与模型架构强匹配BERT → BertNormalizer BertPreTokenizer WordPieceGPT-2 → NFC ByteLevel BPET5 → NFKC Metaspace Unigram。 选型背后的算法理由BPE 的频次合并、WordPiece 的语义打分、Unigram 的概率化切分可回溯到 algorithms.md 的完整推导。在样本输入上测试整条管线检查 Normalizer 是否过度规范化如把专有名词误伤验证 Pre-tokenizer 切分是否符合预期确保 Decoder 能无损还原文本。可借助tokenizer.normalizer.normalize_str(text)、tokenizer.pre_tokenizer.pre_tokenize_str(text)分步调试见 training.md。为下游任务保留对齐信息用trim_offsets而非在 Normalizer 中剥离空白在样本区间上验证char_to_token()与word_ids的正确性。将管线文档化保存完整的 tokenizer 配置tokenizer.save(my-tokenizer.json)记录特殊 token 及其 ID 约定注明任何自定义组件的实现与作用。训练与落地衔接自定义训练完成后可通过PreTrainedTokenizerFast包装接入 transformers 生态AutoTokenizer.from_pretrained、save_pretrained与模型一同保存完整流程见 integration.md。若要训练自己的词表管线组件Normalizer/Pre-tokenizer/Decoder应与 training.md 中BpeTrainer/WordPieceTrainer/UnigramTrainer的配置保持一致才能保证训练时的切分行为与推理时的切分行为完全一致。【免费下载链接】AI-Research-SKILLsComprehensive open-source library of AI research and engineering skills for any AI model. Package the skills and your claude code/codex/gemini agent will be an AI research agent with full horsepower. Maintained by Orchestra Research.项目地址: https://gitcode.com/gh_mirrors/ai/AI-Research-SKILLs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考