SkillAgentSearch skills...

Aimirror

🚀 200倍速!AI时代的下载神器 | Docker/PyPI/HuggingFace/CRAN 全加速 | 并行分片+智能缓存,让下载飞起来

Install / Use

/learn @livehl/Aimirror

README

🚀 aimirror

Python FastAPI License PyPI

AI 时代的下载镜像加速器 —— 被慢速网络逼疯的工程师的自救工具

一个服务 = PyPI + Docker Hub + CRAN + HuggingFace 全加速,还能任意扩展更多源

💡 项目背景

作为一名 AI 工程师,每天的工作离不开:

  • pip install torch —— 几百 MB 的 wheel 包下载到地老天荒
  • docker pull nvidia/cuda —— 几个 GB 的镜像层反复下载
  • huggingface-cli download —— 模型文件从 HuggingFace 蜗牛般爬过来

公司内网有代理,但单线程下载大文件依然慢得让人崩溃。重复下载相同的包?不存在的缓存。忍无可忍,于是写了这个工具。

aimirror = 智能路由 + 并行分片下载 + 本地缓存,让下载速度飞起来。

✨ 功能特性

  • ⚡ 并行下载 —— HTTP Range 分片,多线程并发,榨干带宽
  • 💾 智能缓存 —— 基于文件 digest 去重,LRU 自动淘汰
  • 🎯 动态路由 —— 小文件直接代理,大文件自动并行
  • 🔗 多源支持 —— Docker Hub、PyPI、CRAN、HuggingFace 开箱即用
  • 🔌 任意扩展 —— 只要是 HTTP 下载,配置一条规则即可几十倍加速
  • 📝 内容改写 —— 自动改写 HTML/JSON 响应中的链接,无缝代理
  • 🎛️ 特殊处理 —— 支持自定义 Handler 处理复杂场景(如 Docker Registry)
  • 🚦 并发控制 —— 全局下载并发限制,防止资源耗尽
  • 🔄 路径重写 —— 灵活的路径替换规则,适配各种 API 差异
  • 🔑 缓存优化 —— 支持原始 URL 作为缓存 key,解决临时签名问题

🔥 性能实测

PyPI 包安装加速对比

使用 uv pip install 安装 148 个依赖包(含 torch、transformers 等大包):

| 模式 | 解析依赖 | 准备包 | 总耗时 | 加速比 | |------|---------|--------|--------|--------| | ❌ 仅代理 (900KB/s) | 17m 04s | 14m 20s | ~31 分钟 | 1x | | ✅ aimirror (170MB/s) | 34.78s | 45.81s | ~80 秒 | 23x |

💡 实测环境: 公司内网代理,带宽瓶颈明显。使用 aimirror 后从 900KB/s 飙升至 170MB/s,提速近 200 倍

缓存效果

| 场景 | 耗时 | 速度 | 说明 | |------|------|------|------| | 首次下载 | 80s | 170MB/s | 并行下载 + 写入缓存 | | 缓存命中 | <1s | 3000+ MB/s | 万兆内网实测,本地 SSD 更快,瞬开 |

多源同时加速

一个 aimirror 服务,同时加速多种包管理器:

| 包管理器 | 配置方式 | 加速效果 | |---------|---------|---------| | pip/uv | export HTTPS_PROXY=http://localhost:8081pip install -i http://localhost:8081/simple | PyPI 包 23x 加速 | | docker | /etc/docker/daemon.json 中设置 registry-mirrors | 镜像拉取并行分片 | | R CRAN | options(repos = c(CRAN = "http://localhost:8081")) | R 包下载加速 | | huggingface-cli | export HF_ENDPOINT=http://localhost:8081 | 模型文件秒下 | | conda | .condarc 中配置 channels | 同理可扩展 | | npm/maven | 配置 registry 指向 aimirror | 任意 HTTP 源均可 |

🔌 扩展能力: 只要是 HTTP 下载,在 config.yaml 中添加一条规则即可接入加速,无需启动多个服务。

🏗️ 架构

flowchart LR
    subgraph Client["客户端"]
        PIP[pip install]
        DOCKER[docker pull]
        HF[huggingface-cli]
        R[R install.packages]
    end

    subgraph aimirror["aimirror 服务"]
        ROUTER[路由匹配器<br/>router.py]
        HANDLER[特殊处理器<br/>handlers/]
        PROXY[直接代理<br/>proxy]
        DOWNLOADER[并行下载器<br/>downloader.py]
        CACHE[缓存管理器<br/>cache.py]
        REWRITE[内容改写<br/>content_rewrite]
    end

    subgraph UpstreamProxy["上游代理 (可选)"]
        COMPANY_PROXY[公司代理]
    end

    subgraph Upstream["上游服务"]
        PYPI[PyPI]
        DOCKER_HUB[Docker Hub]
        HF_HUB[HuggingFace]
        CRAN[CRAN]
    end

    PIP --> ROUTER
    DOCKER --> ROUTER
    HF --> ROUTER
    R --> ROUTER

    ROUTER -->|匹配 handler| HANDLER
    ROUTER -->|小文件/代理策略| PROXY
    ROUTER -->|大文件/并行策略| DOWNLOADER

    HANDLER --> PROXY
    PROXY -->|需要改写| REWRITE
    REWRITE --> Client
    PROXY -->|直接返回| Client
    
    DOWNLOADER --> CACHE
    CACHE -->|命中| Client
    CACHE -->|未命中| UpstreamProxy
    PROXY --> UpstreamProxy

    UpstreamProxy -.->|可选| Upstream
    UpstreamProxy -->|直连| Upstream

    DOCKER_HUB -->|返回文件| CACHE
    PYPI -->|返回文件| CACHE
    HF_HUB -->|返回文件| CACHE
    CRAN -->|返回文件| CACHE

🚀 快速开始

方式一:pip 安装(推荐)

# 安装
pip install aimirror

# 启动
aimirror

# 使用
curl http://localhost:8081/health

方式二:源码安装

# 克隆仓库
git clone https://github.com/livehl/aimirror.git
cd aimirror

# 安装依赖
pip install -r requirements.txt

# 启动
python main.py

# 使用
curl http://localhost:8081/health

🔧 客户端配置

pip / uv

# 临时使用(单次安装)
pip install torch --index-url http://localhost:8081/simple --trusted-host localhost:8081

# 全局配置(推荐)
pip config set global.index-url http://localhost:8081/simple
pip config set global.trusted-host localhost:8081

# 使用 uv(速度更快)
uv pip install torch --index-url http://localhost:8081/simple

# 或使用环境变量
export HTTPS_PROXY=http://localhost:8081
pip install torch

Docker

# 配置 daemon.json
sudo tee /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["http://localhost:8081"]
}
EOF
sudo systemctl restart docker

# 或临时拉取
docker pull --registry-mirror=http://localhost:8081 nginx

⚠️ 重要提示:Docker 镜像层文件通常很大(GB 级别),建议将 chunk_size 设置为 0(自动模式)。

自动模式下,chunk_size = 文件总大小 / concurrency,这样可以:

  • 避免固定小分片导致分片数量过多
  • 减少 Docker Registry token 因超时失效的概率
  • 保持并发数不变,同时优化分片大小

配置示例见 config.yaml 中的 docker-blob 规则。

HuggingFace (huggingface-cli)

# 设置环境变量
export HF_ENDPOINT=http://localhost:8081

# 下载模型(支持所有文件类型:.gguf, .bin, .safetensors, .json 等)
huggingface-cli download TheBloke/Llama-2-7B-GGUF llama-2-7b.Q4_K_M.gguf

# 下载整个仓库
huggingface-cli download meta-llama/Llama-2-7b-hf --local-dir ./models

或使用 Python:

import os
os.environ["HF_ENDPOINT"] = "http://localhost:8081"

from huggingface_hub import hf_hub_download, snapshot_download

# 下载单个文件
hf_hub_download(repo_id="TheBloke/Llama-2-7B-GGUF", filename="llama-2-7b.Q4_K_M.gguf")

# 下载整个仓库
snapshot_download(repo_id="meta-llama/Llama-2-7b-hf", local_dir="./models")

R (CRAN)

# 在 R 控制台中设置
options(repos = c(CRAN = "http://localhost:8081"))

# 或在 .Rprofile 中永久配置
cat('options(repos = c(CRAN = "http://localhost:8081"))\n', file = "~/.Rprofile")

Conda

# 修改 .condarc
cat >> ~/.condarc <<EOF
channels:
  - http://localhost:8081/conda-forge
  - http://localhost:8081/bioconda
EOF

npm / yarn

# 临时使用
npm install --registry http://localhost:8081/registry/npm

# 全局配置
npm config set registry http://localhost:8081/registry/npm
yarn config set registry http://localhost:8081/registry/npm

📖 API

代理端点

| 路径 | 方法 | 说明 | |------|------|------| | /{full_path:path} | GET/HEAD/POST/PUT/DELETE | 通用代理入口,根据路由规则转发到对应上游 |

管理端点

| 路径 | 方法 | 说明 | 响应示例 | |------|------|------|----------| | /health | GET | 健康检查 | {"status": "ok", "active_downloads": 0, "downloads": []} | | /stats | GET | 缓存统计信息 | {"cache": {"total_size_mb": 1024, "file_count": 100}} |

健康检查响应详情

curl http://localhost:8081/health

响应字段说明:

  • status: 服务状态,ok 表示正常运行
  • active_downloads: 当前正在进行的下载任务数
  • downloads: 正在下载的文件列表(缓存 key)

缓存统计响应详情

curl http://localhost:8081/stats | jq

响应包含缓存目录的总大小、文件数量等信息。

🚀 快速开始

方式一:pip 安装(推荐)

# 安装
pip install aimirror

# 启动
aimirror

# 使用
curl http://localhost:8081/health

方式二:源码安装

# 克隆仓库
git clone https://github.com/livehl/aimirror.git
cd aimirror

# 安装依赖
pip install -r requirements.txt

# 启动
python main.py

# 使用
curl http://localhost:8081/health

🐳 Docker 部署

使用 GitHub Container Registry

# 拉取镜像
docker pull ghcr.io/livehl/aimirror:latest

# 运行(基础版)
docker run -d -p 8081:8081 \
  -v $(pwd)/cache:/data/fast_proxy/cache \
  ghcr.io/livehl/aimirror:latest

# 运行(带自定义配置)
docker run -d -p 8081:8081 \
  -v $(pwd)/config.yaml:/app/config.yaml \
  -v $(pwd)/cache:/data/fast_proxy/cache \
  ghcr.io/livehl/aimirror:latest

Docker Compose 示例

version: '3.8'

services:
  aimirror:
    image: ghcr.io/livehl/aimirror:latest
    container_name: aimirror
    ports:
      - "8081:8081"
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./cache:/data/fast_proxy/cache
      - ./logs:/data/fast_proxy
    restart: unless-stopped

注意:上游代理请在 config.yaml 中配置 server.upstream_proxy,不支持环境变量方式。

⚙️ 配置示例

# fast_proxy 配置文件
server:
  host: "0.0.0.0"
  port: 8081
  upstream_proxy: ""  # 上游代理,默认空表示直连
  public_host: "127.0.0.1:8081"  # 对外访问地址,用于 HTML 链接改写
  max_concurrent_downloads: 100  # 全局最大并发下载数,超过则排队

cache:
  dir: "/data/fast_proxy/cache"
  max_size_gb: 100
  lru_enabled: true

rules:
  # Docker Registry 代理(/v2/ 和 /v2/auth 在代码中特殊处理)
  - name: docker-blob
    pattern: "/v2/.*/blobs/sha256:[a-f0-9]+"
    upstream: "https://registry-1.docker.io"
    strategy: parallel
    min_size: 1       # all
    concurrency: 20
    chunk_size: 0     # 自动模式:总大小/concurrency,避免超大文件分片过多导致 token 超时
  - name: docker-registry
    pattern: "/v2/.*"
    upstream: "https://registry-1.docker.io"
    strategy: proxy
    handler: handlers.docker  # 特殊处理模块路径
    
  - name: pip-packages
    pattern: "/packages/.+\\.(whl|tar\\.gz|zip)$"
    upstream: "https://pypi.org"
    strategy: parallel
    min_size: 1       # all
    concurrency: 20
    chunk_size: 5242880      # 5MB per chunk
    
  - name: r-package
    pattern: "/src/contrib/.*"
    upstream: "https://cran.r-project.org"
    strategy: parallel
    min_size: 102400       # 100K
    concurrency: 20
    chunk_size: 5242880

  - name: huggingface-files
    pattern: '/.*/(blob|resolve)/[^/]+/.+'
    upstream: "https://huggingface.co"
    strategy: parallel
    min_size: 102400       #100k
    concurrency: 20
    chunk_size: 10485760    # 10MB per chunk
    cache_key_source: original  # 使用原始 URL 作为缓存 key(避免临时签名影响缓存命中)
    path_rewrite:
      - search: "/blob/"
        replace: "/resolve/"
    # HEAD 请求时需要额外保留的响应头(用于元数据获取)
    head_meta_headers:
      - "x-repo-commit"
      - "x-linked-etag"
      - "x-linked-size"
      - "etag"

  - name: huggingface-api
    pattern: '/api/models/.*'
    upstream: "https://huggingface.co"
    strategy: proxy

  # 示例:其他使用临时签名 URL 的站点
  # - name: example-signed-url
  #   pattern: '/signed-download/.*'
  #   upstream: "https://example.com"
  #   strategy: parallel
  #   min_size: 10485760
  #   concurrency: 10
  #   cache_key_source: original  # 使用原始 URL 作为缓存 key

  - name: default
    pattern: ".*"
    upstream: "https://pypi.org"
    strategy: proxy
    content_rewrite:         # 响应内容改写配置
      content_
View on GitHub
GitHub Stars242
CategoryEducation
Updated1h ago
Forks18

Languages

Python

Security Score

100/100

Audited on Mar 29, 2026

No findings