编程 paper2code 深度解析:当 AI 终于把「读论文」变成「跑代码」

2026-04-09 04:43:48 +0800 CST views 3

paper2code 深度解析:当 AI 终于把「读论文」变成「跑代码」

背景:每个 ML 工程师都经历过的噩梦

你读了一篇论文,激动人心——Attention Is All You Need,Transformer 架构,业界最核心的基础模型。读完之后信心满满:「这个我也能实现」。

然后你打开编辑器,光标闪了十分钟,一个字敲不下去。

论文原文 §3.2 写「we apply layer normalization before each sub-layer」,但 Figure 1 画的却是 Post-LayerNorm。§4.1 说「we trained on...」,后面跟着一堆数据集描述,batch size 呢?学习率呢?都没写。用的是 Adam 还是 AdamW?warmup 多少步?这些问题论文里根本没答案,你只能去翻附录——附录里也没有——然后去 GitHub 找官方代码,结果官方代码在 2024 年已经删库了,star 全是 404。

这就是机器学习论文的残酷真相:论文告诉你「做了什么」,但几乎从不告诉你「怎么做」。中间缺失的细节——每一个超参数、每一个架构选择、每一个假设——全都留给读者自己去猜。水平高的研究员靠经验猜,水平低的工程师靠运气猜,猜错了就复现失败,然后怀疑人生。

过去五年,AI 社区尝试过各种方案解决这个问题:

  • RAG + 论文库:把论文存进向量数据库,查询时召回相关段落。但向量相似度不等于语义理解,你搜「layer normalization」召回的段落可能跟你的具体问题八竿子打不着。
  • 代码生成模型:让 GPT-4 根据论文描述生成代码。但模型会「自信地编造」——它会用常见的默认值填充论文没写的细节,但不会告诉你它在编造。你以为你在实现论文,其实你在实现一个四不像。
  • 官方代码库:最可靠但最难得。顶级论文可能一年后才开源代码,而且官方代码往往掺杂了大量工程优化,跟论文描述的原始架构不完全一致。

直到 2026 年 4 月,一个叫 PrathamLearnsToCode 的开发者在 GitHub 上传了一个 Claude Code Skill,彻底改变了这个局面——

核心概念:paper2code 是什么

paper2code 是一个 Claude Code Agent Skill,它的功能只有一个:输入一篇 arxiv 论文 URL,输出可运行的代码实现。但跟所有之前的方案不同,它的核心设计哲学是**「诚实的不确定性」——它不假装自己能完美复现论文,它的目标是让你知道每一个代码决策的来源**。

具体来说,当你运行 /paper2code https://arxiv.org/abs/1706.03762 时,它会:

  1. 抓取并解析论文全文——包括正文、附录、脚注和图片描述
  2. 引用锚定——生成每一行代码时,标注它对应论文的哪个章节和公式
  3. 歧义审计——在写代码之前,对每一个实现决策进行分类:SPECIFIED(论文明确说了)、PARTIALLY_SPECIFIED(论文提到了但有歧义)、UNSPECIFIED(论文根本没提)
  4. 诚实标注——对于 UNSPECIFIED 的决策,代码里会标记 [UNSPECIFIED] 注释,并列出常见替代方案

最终输出的目录结构是标准化的:

attention_is_all_you_need/
├── README.md                  # 论文摘要 + 贡献点 + 快速开始
├── REPRODUCTION_NOTES.md      # 歧义审计:每个未指定决策的说明
├── requirements.txt            # 依赖包(版本锁定)
├── src/
│   ├── model.py               # 模型架构 — 每个类对应论文一个章节
│   ├── loss.py                # 损失函数(带公式引用)
│   ├── data.py                # Dataset 类骨架 + 数据获取说明
│   ├── train.py               # 训练循环(如在论文范围内)
│   ├── evaluate.py            # 评估指标计算
│   └── utils.py               # 共享工具(masking、位置编码等)
├── configs/
│   └── base.yaml              # 所有超参数 — 每个都标注来源或 [UNSPECIFIED]
└── notebooks/
    └── walkthrough.ipynb      # 教学 notebook:论文→代码→形状检查

这个结构看起来简单,但它解决了一个根本问题:论文和代码之间的信任缺口

架构解析:三层设计

paper2code 的架构分为三个层次,每层解决一个具体问题:

第一层:引用锚定(Citation Anchoring)

这是 paper2code 区别于其他所有方案的核心创新。

传统代码生成的问题是:模型输出的代码是「扁平的」——你只知道整体思路是从论文来的,但具体到第 47 行的 eps=1e-5,你完全不知道这是论文里规定的,还是模型自己猜的。

paper2code 的解决方案是在每一行关键代码旁边标注论文引用。看一个实际输出例子:

# §3.2 — "We apply layer normalization before each sub-layer" (Pre-LN variant)
class TransformerBlock(nn.Module):
    def forward(self, x):
        # §3.2, Eq. 2 — attention_weights = softmax(QK^T / sqrt(d_k))
        attn_out = self.attention(self.norm1(x))  # (batch, seq_len, d_model)
        x = x + attn_out  # §3.2 — residual connection

        # [UNSPECIFIED] Paper does not state epsilon for LayerNorm — using 1e-6 (common default)
        # Alternatives: 1e-5 (PyTorch default), 1e-8 (some implementations)
        self.norm = nn.LayerNorm(d_model, eps=1e-6)

        # [ASSUMPTION] Using pre-norm based on "we found pre-norm more stable" in §4.1
        # The paper uses post-norm in Figure 1 but pre-norm in experiments — ambiguous

你能清楚看到:

  • attention 调用对应 §3.2 和 Eq. 2——论文明确说了
  • residual connection 对应 §3.2——论文明确说了
  • eps=1e-6 标记为 [UNSPECIFIED]——论文没写,这是我的选择,并列出了 PyTorch 默认值和其他实现常用的值
  • Pre-norm vs Post-norm 标记为 [ASSUMPTION]——论文的 Figure 1 和实验描述互相矛盾,我根据 §4.1 的描述选择了 pre-norm,并解释了我的推理过程

这种标注体系让代码变成了可验证的论文实现,而不是黑箱生成。

第二层:歧义审计(Ambiguity Audit)

在生成任何代码之前,paper2code 会先对论文进行一次系统性审计,将每个实现决策分为四类:

标签含义处理方式
§X.Y论文第 X.Y 节明确指定直接实现
§X.Y, Eq. N论文第 X.Y 节的第 N 个公式按公式实现
[UNSPECIFIED]论文没有提到用常用默认值 + 标注替代选项
[ASSUMPTION]论文描述模糊,需推理记录推理过程
[FROM_OFFICIAL_CODE]来自作者官方代码标注来源

这个审计过程本身就是一个高价值的文档。REPRODUCTION_NOTES.md 记录了论文的所有歧义点,即使你不运行 paper2code,直接读这个审计报告就能知道实现这篇论文的关键难点在哪里。

以 Transformer 论文为例,审计会告诉你:

  • 位置编码是绝对位置还是相对位置?(绝对,§3.5 明确说了)
  • Encoder 和 Decoder 各有多少层?(6层,§5.3)
  • Attention 的 d_k、d_v、d_model 分别是多少?(64、64、512,§5.3)
  • Label smoothing 用的是多少?(0.1,§5.4)
  • Dropout 率是多少?(0.1,遍布全文)
  • 哪些是根本没写的:LayerNorm 的 epsilon、学习率调度具体公式、Warmup 步数(虽然 §5.3 说了用了 warmup,但具体多少步没写)

这种审计的价值在于:它把「论文→代码」的映射过程显式化了。之前这个映射过程发生在研究员脑子里,只有最终结果(代码)可见;现在这个过程被完整记录下来,任何人都可以验证。

第三层:分层输出(Layered Output)

paper2code 的输出不是单一代码文件,而是一套分层文档

README.md — 论文摘要、贡献点列表、快速开始指南。这是给「只是想了解这篇论文大概在做什么」的读者看的。

REPRODUCTION_NOTES.md — 歧义审计报告。这是给「想复现论文、想了解论文细节」的工程师看的。每个决策都有分类和理由。

src/model.py — 模型架构代码。这是给「已经有一定了解、想看具体实现」的开发者看的。

notebooks/walkthrough.ipynb — 教学 notebook。用小维度数据跑通整个流程,展示每一步的输入输出和形状变化,结合论文引用,让读者理解论文的每个概念具体对应代码的哪一部分。

configs/base.yaml — 所有超参数。每一项都标注来源:要么是论文里明确说的,要么是 [UNSPECIFIED] 标记的默认值。这个文件是复现实验的核心配置清单。

这种分层设计意味着:不管你是哪个层次的读者——只想了解、想复现、想深入理解、想改写实验——你都能找到适合你的入口。

代码实战:从 Transformer 论文到可运行代码

下面演示 paper2code 处理一篇经典论文的完整过程。

输入

npx skills add PrathamLearnsToCode/paper2code/skills/paper2code
# 选择 Claude Code 作为 Agent
# 选择 Global scope
# 选择 Symlink 方式

# 在 Claude Code 中运行
/paper2code https://arxiv.org/abs/1706.03762

第一步:论文抓取与解析

paper2code 首先通过 arxiv API 获取论文 PDF,解析全文,包括:

  • 标题、摘要、作者
  • 正文所有章节(§1-7)
  • 附录(A、B、C...)
  • 脚注和图片描述

特别值得注意的是:它把附录当成一等公民。很多工程师复现论文失败,就是因为他们只看正文,忽略了附录——而真正重要的实验细节(超参数范围、数据集描述、消融实验设计)往往藏在附录里。

第二步:歧义审计

对 Transformer 论文的审计会产生类似以下的决策清单:

【SPECIFIED — 可直接实现】
- Encoder: 6层, d_model=512, d_ff=2048, 8头注意力, d_k=d_v=64 (§5.3)
- Decoder: 6层, 额外一个注意力头关注 Encoder 输出 (§5.3)
- 位置编码: 绝对位置编码,sin/cos 函数 (§3.5)
- 激活函数: ReLU (§3.3, Eq. 4)
- Dropout: P_drop=0.1 (遍布全文)

【PARTIALLY_SPECIFIED — 有歧义】
- Pre-LN vs Post-LN: Figure 1 画 Post-LN,但 §4.1 描述实验用 Pre-LN
  → 论文内部矛盾,选择 Pre-LN(实验描述优先于架构图)
  
【UNSPECIFIED — 论文未提及】
- LayerNorm epsilon: 未指定 → 选用 1e-6(常见默认值)
- Adam beta1/beta2: 未指定 → 选用 0.9/0.98(Transformer 论文原始实现)
- 学习率调度: warmup + linear decay,但 warmup 步数未指定 → 4000 步(大多数实现的标准值)
- Label smoothing value: 未指定 → 0.1(基于 §5.4 的描述推断)

第三步:代码生成

基于审计结果,生成标准化的项目结构。以 model.py 为例,关键部分如下:

# src/model.py
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Optional

class PositionalEncoding(nn.Module):
    """§3.5 — "We use sin and cos functions of different frequencies"
    
    Implements fixed positional encoding using sinusoidal functions.
    Max sequence length is configurable via max_len parameter.
    """
    def __init__(self, d_model: int, max_len: int = 5000, dropout: float = 0.1):
        super().__init__()
        self.dropout = nn.Dropout(p=dropout)
        
        # §3.5, Eq. (5) and (6) — positional encoding formula
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)
        )
        pe[:, 0::2] = torch.sin(position * div_term)     # §3.5, Eq. (5)
        pe[:, 1::2] = torch.cos(position * div_term)     # §3.5, Eq. (6)
        pe = pe.unsqueeze(0)  # (1, max_len, d_model)
        self.register_buffer('pe', pe)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        # §3.5 — "The same positional encoding is added to all layers"
        x = x + self.pe[:, :x.size(1), :]
        return self.dropout(x)


class TransformerBlock(nn.Module):
    """§5.3 — Standard Transformer encoder/decoder block.
    
    Architecture: Multi-head attention → Add & Norm → Feed Forward → Add & Norm
    Uses Pre-LayerNorm (stable training, §4.1 inference).
    """
    def __init__(self, d_model: int, nhead: int, d_ff: int, dropout: float = 0.1):
        super().__init__()
        # [UNSPECIFIED] LayerNorm epsilon — using PyTorch default 1e-5
        # Alternative: 1e-6 (BERT default), 1e-8 (some modern implementations)
        self.norm1 = nn.LayerNorm(d_model, eps=1e-5)
        self.norm2 = nn.LayerNorm(d_model, eps=1e-5)
        
        self.attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout, batch_first=True)
        self.ff = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),  # §3.3 — "We use ReLU activation"
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model),
            nn.Dropout(dropout),
        )

    def forward(self, x: torch.Tensor, mask: Optional[torch.Tensor] = None) -> torch.Tensor:
        # §3.2 — "We apply layer normalization before each sub-layer" (Pre-LN)
        # §3.2, Eq. 2 — attention: LayerNorm → MultiHead(Q,K,V)
        attn_out, _ = self.attn(self.norm1(x), self.norm1(x), self.norm1(x), attn_mask=mask)
        x = x + attn_out  # §3.2 — residual connection
        
        # §3.2 — Feed Forward sub-layer: LayerNorm → FF → residual
        x = x + self.ff(self.norm2(x))
        return x


class Transformer(nn.Module):
    """§3.1 & §3.3 — Full Transformer architecture.
    
    Stacks N encoder/decoder blocks as specified in §5.3.
    """
    def __init__(self, 
                 d_model: int = 512,      # §5.3
                 nhead: int = 8,            # §5.3
                 num_layers: int = 6,       # §5.3
                 d_ff: int = 2048,          # §5.3
                 vocab_size: int = 37000,   # §5.3 — approximate BPE vocab
                 max_len: int = 5000,
                 dropout: float = 0.1):     # §5.4
        super().__init__()
        self.d_model = d_model
        
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_enc = PositionalEncoding(d_model, max_len, dropout)
        
        # §5.3 — "N=6 layers for both encoder and decoder"
        self.encoder_layers = nn.ModuleList([
            TransformerBlock(d_model, nhead, d_ff, dropout) 
            for _ in range(num_layers)
        ])
        self.decoder_layers = nn.ModuleList([
            TransformerBlock(d_model, nhead, d_ff, dropout)
            for _ in range(num_layers)
        ])
        
        self.output_proj = nn.Linear(d_model, vocab_size)
        # §3.4 — "share parameters between embedding and pre-softmax layer"
        self.output_proj.weight = self.embedding.weight

    def encode(self, src: torch.Tensor, src_mask: Optional[torch.Tensor] = None) -> torch.Tensor:
        x = self.embedding(src) * math.sqrt(self.d_model)  # §3.4
        x = self.pos_enc(x)
        for layer in self.encoder_layers:
            x = layer(x, src_mask)
        return x

    def decode(self, tgt: torch.Tensor, memory: torch.Tensor, 
               tgt_mask: Optional[torch.Tensor] = None) -> torch.Tensor:
        x = self.embedding(tgt) * math.sqrt(self.d_model)
        x = self.pos_enc(x)
        for layer in self.decoder_layers:
            x = layer(x, tgt_mask)
        return self.output_proj(x)

第四步:配置文件

configs/base.yaml 记录所有超参数:

# configs/base.yaml — All hyperparameters with source annotations

# Architecture (from §5.3)
d_model: 512          # §5.3
nhead: 8               # §5.3
num_layers: 6          # §5.3 — "N=6"
d_ff: 2048             # §5.3 — "ffn dimension is 2048"
d_k: 64                # §5.3 — derived from d_model/nhead
d_v: 64                # §5.3 — derived from d_model/nhead

# Vocab & tokenization (from §5.3)
vocab_size: 37000      # §5.3 — "Byte-pair encoding with 37k subword tokens"
max_len: 5000          # §5.3

# Regularization (scattered throughout paper)
dropout: 0.1           # §5.4 — "dropout rate P_drop = 0.1"
label_smoothing: 0.1   # §5.4 — inferred from "label smoothing of ε_LS = 0.1"

# Training (from §5.3 & Appendix A)
# [UNSPECIFIED] Adam beta1/beta2 — using BERT defaults (0.9, 0.999)
adam_beta1: 0.9
adam_beta2: 0.999
# [UNSPECIFIED] Adam epsilon — using 1e-6 (standard)
adam_eps: 1e-6

# [UNSPECIFIED] Warmup steps — standard value from most implementations
# Paper says "warmup_steps" but doesn't specify the number
warmup_steps: 4000

# [UNSPECIFIED] Learning rate formula — using standard formula
# Paper describes: lr = d_model^-0.5 * min(step^-0.5, step*warmup_steps^-1.5)
base_lr: 1.0          # paper's base learning rate (not directly stated, inferred)
max_lr: null           # computed from formula

# Loss (from §2)
loss: cross_entropy    # §2 — standard language modeling objective

这份配置文件的标注方式让任何想复现论文的人都能清楚知道:哪些参数是论文明确规定的,哪些是我推测的,哪些是业界标准默认值。如果你的复现效果跟论文不一致,你可以逐一排查这些 [UNSPECIFIED] 的参数。

深层价值:为什么这个项目值得关注

表面上 paper2code 是一个「论文转代码」的工具,但它的深层价值在于重新定义了 AI 生成代码的信任模型

传统 AI 编程的信任危机

当 GPT-4 或 Claude 给你生成一段代码时,你面临一个根本问题:你无法区分它「知道的」和它「猜的」。模型总是用流畅、自信的语气输出代码,即使它在编造超参数、编造 API 调用、编造实现细节。这种「过度自信的不确定性」是当前 AI 编程工具最大的工程障碍——你花半小时阅读 AI 生成的代码,发现有个 bug,修复了,发现还有 bug,继续修,最后发现是 AI 用了错误的库版本,整个实现都得重来。

paper2code 的设计哲学是把不确定性显式化:不确定的地方就标 [UNSPECIFIED],不假装知道。这看起来是个「弱点」,实际上是最大的「优点」——因为工程师最怕的不是「不知道」,而是「以为自己知道其实不知道」。

知识蒸馏的逆向工程

更进一步,paper2code 的架构本质上是对机器学习知识蒸馏过程的逆向工程

当你阅读一篇论文时,你在做一件非常复杂的事情:从自然语言描述中提取可执行的算法约束。论文给你的是「模糊约束」(比如「we use dropout of 0.1」),你需要把它转化为「精确约束」(比如 nn.Dropout(p=0.1))。

这个过程需要一个「中间表示」——既不是论文的原始文本,也不是最终代码。paper2code 的中间表示就是歧义审计。它把论文中的每一个模糊约束翻译成四类标签:明确指定、部分指定、未指定、假设。然后基于这些标签生成代码。

这个流程跟人类的思维过程惊人地相似:读论文时,有经验的工程师脑子里也会做类似的事情——「这个论文说了」「这个论文没说」「这个论文说的时候有歧义」「我猜这里应该是这样」。区别是 paper2code 把这个过程记录下来了,而人类的推理过程往往只存在于脑子里,代码 review 的时候早就丢了。

科学复现的开源协议

paper2code 还提出了一个有趣的理念:worked examples as a protocol

项目鼓励社区贡献「完整复现案例」:选择一个经典论文,用 paper2code 生成代码,然后写一份诚实的 review.md,评价 skill 的表现:哪些做对了、哪些做错了、哪些边缘情况处理得好或差。这些案例形成了一个可验证的论文复现数据库

这相当于给机器学习领域建立了一个「论文实现白名单」:对于某篇论文,经过验证的实现有哪些,它们的假设分别是什么,有哪些分歧点。这种白名单比单一官方代码库更有价值——因为它记录了所有合理的实现路径,而不是只推荐一条。

性能优化与工程边界

paper2code 不会做什么

项目文档明确列出了边界,这对工程实践非常重要:

不会保证正确性 — 实现匹配论文描述,不保证匹配论文性能
不会编造细节 — 论文没写的参数,代码会标记 [UNSPECIFIED],不会悄无声息地填默认值
不会下载数据集 — data.py 提供骨架,说明数据从哪获取、如何预处理
不会搭建训练基础设施 — 不包含分布式训练、实验追踪、checkpoint(除非论文贡献需要)
不会实现 baseline — 只实现论文核心贡献,不实现对比实验的 baseline 模型
不会重新实现标准组件 — 论文说「standard transformer encoder」,代码只 import 不重写

这个边界定义非常清晰,它避免了一个常见的陷阱:把论文实现变成一个功能完整的研究框架。paper2code 的目标只是「把论文的算法变成代码」,这个目标小而精确,容易达到。

局限性分析

尽管设计精妙,paper2code 也有明显的局限:

1. 长上下文依赖:处理超长论文(比如 80+ 页的综述文章)时,上下文窗口容易溢出,导致后面的章节被截断。

2. 数学公式解析:论文中的公式表示形式多样(LaTeX、图片、ASCII art),解析的一致性有待提高。某些复杂公式可能解析错误,导致代码实现与论文描述不符。

3. 多模态论文处理:对于涉及图像、音频或视频的论文,paper2code 目前只处理文本,对多模态内容的处理能力有限。

4. 最新论文的结构不确定性:arXiv 上的论文格式多样,有些论文的章节编号不规范,导致自动引用锚定出错。

这些问题大多数可以通过工程迭代解决,但它们提醒我们:paper2code 目前仍然是一个辅助工具,不是银弹。专业研究者在使用时应保持批判性思维。

与现有工具的对比

维度paper2code官方代码库RAG + LLM传统代码生成
代码可验证性✅ 每个决策有引用✅ 可验证❌ 黑箱❌ 黑箱
歧义标注✅ 完整审计❌ 无❌ 无❌ 无
时效性✅ 论文发布即可用❌ 数月/年后才出✅ 即时✅ 即时
完整性⚠️ 基础实现✅ 完整工程⚠️ 依赖模型能力⚠️ 依赖模型能力
正确性保证⚠️ 匹配描述不保证性能✅ 通常可靠⚠️ 不确定❌ 常有错误
学习价值✅ 高(带论文引用)⚠️ 中(代码无论文映射)❌ 低(无推理过程)❌ 低

总结与展望

paper2code 的出现填补了机器学习领域一个长期存在的基础设施空白:论文到代码的自动化翻译

它不追求完美——它追求诚实。每一行代码都标注来源,每一个不确定的地方都明确标记。这种「诚实的不确定性」设计哲学,可能是未来 AI 编程工具最重要的演进方向——与其让模型假装知道一切,不如让它准确表达自己知道什么、不知道什么、推测什么。

对于工程师来说,paper2code 的直接价值是降低论文复现的门槛。以前需要几天甚至几周才能把一篇论文「翻译」成可运行的代码,现在可能只需要几分钟——当然,代码需要人工 review,但它提供了一个极好的起点,大幅减少了从头开始的痛苦。

对于 AI 领域来说,paper2code 的更大意义在于建立了一套可验证的知识蒸馏流程。当社区积累了大量经过验证的 paper2code 案例后,我们就能清楚地知道:对于不同类型的论文(架构类、训练方法类、应用类),AI 复现的成功率分别是多少,常见错误模式是什么,哪些领域特别容易出现歧义。这将成为训练更好代码生成模型的关键数据。

最后,这个项目本身也是一个绝佳的AI 赋能个体叙事——一个开发者,用一个 Claude Code Skill,解决了一个困扰整个 ML 社区数十年的问题。不是大公司,不是千万元融资,就是一个 Skill,一个下午,一行一行地写 prompt。这大概就是 2026 年 AI 时代最典型的创业故事模板了。

推荐文章

JavaScript 的模板字符串
2024-11-18 22:44:09 +0800 CST
H5端向App端通信(Uniapp 必会)
2025-02-20 10:32:26 +0800 CST
联系我们
2024-11-19 02:17:12 +0800 CST
php微信文章推广管理系统
2024-11-19 00:50:36 +0800 CST
平面设计常用尺寸
2024-11-19 02:20:22 +0800 CST
rangeSlider进度条滑块
2024-11-19 06:49:50 +0800 CST
markdowns滚动事件
2024-11-19 10:07:32 +0800 CST
微信内弹出提示外部浏览器打开
2024-11-18 19:26:44 +0800 CST
Golang 中你应该知道的 noCopy 策略
2024-11-19 05:40:53 +0800 CST
Nginx 防盗链配置
2024-11-19 07:52:58 +0800 CST
imap_open绕过exec禁用的脚本
2024-11-17 05:01:58 +0800 CST
使用Rust进行跨平台GUI开发
2024-11-18 20:51:20 +0800 CST
一些实用的前端开发工具网站
2024-11-18 14:30:55 +0800 CST
Vue3中怎样处理组件引用?
2024-11-18 23:17:15 +0800 CST
程序员茄子在线接单