Skip to content
目录

Hub 加载、路径与缓存

1. 资源路径三元组

buildResourcePaths 把「模型 id 或本地目录」解析为:

  • requestURL:逻辑路径(repoId/filename);
  • localPath:本地映射(HF id 时拼 env.localModelPath);
  • remoteURLenv.remoteHost + remotePathTemplate(含 {model}{revision})。
125:156:packages/transformers/src/utils/hub.js
export function buildResourcePaths(path_or_repo_id, filename, options = {}, cache = null) {
    const revision = options.revision ?? 'main';
    const requestURL = pathJoin(path_or_repo_id, filename);

    const validModelId = isValidHfModelId(path_or_repo_id);
    const localPath = validModelId ? pathJoin(env.localModelPath, requestURL) : requestURL;
    const remoteURL = pathJoin(
        env.remoteHost,
        env.remotePathTemplate
            .replaceAll('{model}', path_or_repo_id)
            .replaceAll('{revision}', encodeURIComponent(revision)),
        filename,
    );

设计原因

  • 同一套代码兼容 完全离线(仅 localPath)与 Hub 在线remoteURL);
  • revision 固定时可把缓存 key 与分支/commit 绑定,避免 main 漂移 导致缓存污染(见 proposedCacheKey 分支逻辑)。

2. Fetch 与 Node 头

getFetchHeadersNode 环境为 HF 请求附加 User-AgentAuthorizationHF_TOKEN / HF_ACCESS_TOKEN);浏览器刻意不加 Token,避免密钥进前端 bundle。

84:107:packages/transformers/src/utils/hub.js
export function getFetchHeaders(urlOrPath) {
    const isNode = typeof process !== 'undefined' && process?.release?.name === 'node';
    ...
    if (isNode) {
        ...
        const isHFURL = isValidUrl(urlOrPath, ['http:', 'https:'], ['huggingface.co', 'hf.co']);
        if (isHFURL) {
            const token = process.env?.HF_TOKEN ?? process.env?.HF_ACCESS_TOKEN;
            if (token) {
                headers.set('Authorization', `Bearer ${token}`);
            }
        }
    } else {
        // Running in a browser-environment, so we use default headers
        // NOTE: We do not allow passing authorization headers in the browser,
        // since this would require exposing the token to the client.
    }

简明表述:这是安全与易用性的权衡 —— 私有模型在浏览器中应通过代理或预置缓存,而不是把 token 写进网页。

3. 缓存层级:getCache

utils/cache.js 按优先级尝试:

  1. env.useCustomCache + env.customCache(需实现 Cache API 风格的 match/put);
  2. 实验性 CrossOriginStorage(跨域存储,需环境支持);
  3. env.useBrowserCachecaches.open(env.cacheKey)iframe/隐身模式可能失败,捕获异常并降级为无缓存);
  4. env.useFSCacheFileCache(Node 等本地文件系统)。
22:71:packages/transformers/src/utils/cache.js
export async function getCache(file_cache_dir = null) {
    ...
    if (env.useCustomCache) {
        ...
    }

    if (!cache && env.experimental_useCrossOriginStorage && CrossOriginStorage.isAvailable()) {
        cache = new CrossOriginStorage();
    }

    if (!cache && env.useBrowserCache) {
        ...
        try {
            cache = await caches.open(env.cacheKey);
        } catch (e) {
            logger.warn('An error occurred while opening the browser cache:', e);
        }
    }

    if (!cache && env.useFSCache) {
        ...
        cache = new FileCache(file_cache_dir ?? env.cacheDir);
    }

    return cache;

依据:不同宿主能力差异极大(Extension、PWA、Node、Deno),可插拔缓存比单一实现更可持续。

4. 与 Pipeline 进度的衔接

pipeline() 在下载前用 get_file_metadata 填充每个文件的 total 字节,再交给 DefaultProgressCallback,实现 聚合进度条(多文件并行下载时仍可按权重累加)。

5. 最佳实践

  • 生产环境:对大型模型配合 Service Worker + Cache API自建 CDN,并设置合理 revision
  • CI/离线测试local_files_only: true + 本地目录或 env.allowRemoteModels = false
  • 隐私合规:浏览器端避免依赖需 Token 的私有 Hub URL,改用同域代理。

下一篇:ONNX 后端、执行提供者与推理串行化

MIT License.