Một polyfill thử nghiệm cho Prompt API

Xuất bản: Ngày 14 tháng 5 năm 2026

Với Prompt API trong Chrome, bạn có thể tương tác với một LLM bằng cách sử dụng API trình duyệt cấp cao trên window.LanguageModel. Tuy nhiên, tính năng này vẫn còn hạn chế và việc triển khai là một quy trình phức tạp.

Trình duyệt Hệ điều hành được hỗ trợ Hệ điều hành không được hỗ trợ Vị trí
Chrome Windows, macOS, Linux, ChromeOS (Chromebook Plus) Android, iOS ✅ Được hỗ trợ
Edge Windows, macOS Android, iOS ✅ Được hỗ trợ
Safari 📋 Đã quyết định vị trí
Firefox 📋 Đã quyết định vị trí

Đồng thời, các nhà phát triển trong chương trình dùng thử sớm đã bày tỏ sự hào hứng đối với Prompt API. Phạm vi cung cấp API này gây ra một vấn đề về khả năng tương thích trong tương lai gần.

Giải pháp

Đó là lý do chúng tôi phát hành một polyfill Prompt API tuân thủ quy cách thử nghiệm (xem mã nguồn trên GitHub) để triển khai chính xác Prompt API trên các nhà cung cấp phụ trợ đám mây có thể định cấu hình và cả trên nhà cung cấp phụ trợ cục bộ dưới dạng Transformers.js.

Sử dụng polyfill

Để sử dụng polyfill, hãy làm như sau:

  1. Tải polyfill xuống từ npm:

    npm install prompt-api-polyfill
    
  2. Chọn xem bạn muốn sử dụng nhà cung cấp phụ trợ đám mây hay nhà cung cấp phụ trợ cục bộ:

    • Nhà cung cấp phụ trợ đám mây: Dữ liệu người dùng được gửi lên đám mây để xử lý từ xa, nhưng bạn không phải đợi mô hình cục bộ có sẵn. Bạn chịu trách nhiệm cho mọi chi phí phát sinh theo thông tin về giá của nhà cung cấp dịch vụ đám mây.
    • Nhà cung cấp phụ trợ cục bộ: Dữ liệu người dùng vẫn nằm trong trình duyệt và được xử lý cục bộ, nhưng bạn cần tải một mô hình xuống. Không giống như Prompt API thực, mô hình này không thể dùng chung trên nhiều nguồn gốc. Việc xử lý cục bộ không mất phí.

Phần phụ trợ đám mây

Chọn một trong các phần phụ trợ đám mây và nhận khoá API (cùng mọi thông tin đăng nhập bổ sung) cho nhà cung cấp phụ trợ của bạn.

Sau khi có khoá API, hãy nhập thông tin chi tiết vào tệp cấu hình .env.json. Nếu bạn không chỉ định modelName, polyfill sẽ sử dụng mô hình mặc định của từng phần phụ trợ, nhưng nếu bạn chỉ định, bạn có thể chọn một trong các mô hình được hỗ trợ của từng phần phụ trợ.

{
  "apiKey": "y0ur-Api-k3Y",
  "modelName": "model-name"
}

Phần phụ trợ cục bộ

Nếu quyết định sử dụng nhà cung cấp phụ trợ cục bộ dựa trên Transformers.js, bạn chỉ cần một khoá API giả. Tuy nhiên, bạn có thể định cấu hình thiết bị mà Transformers.js sẽ sử dụng. Chọn "webgpu" để có hiệu suất tối đa và "wasm" để có khả năng tương thích tối đa. Bạn có thể thay đổi chế độ cài đặt mặc định (không bắt buộc). Chọn một mô hình khác trong danh mục mô hình tương thích của Hugging Face. Đối với một số mô hình, bạn có thể chọn trong số các lượng tử hoá khác nhau bằng cách sử dụng tham số dtype.

{
  "apiKey": "dummy",
  "device": "webgpu",
  "dtype": "q4f16",
  "modelName": "onnx-community/gemma-3-1b-it-ONNX-GQA"
};

Định cấu hình polyfill

Sau khi có tệp cấu hình, giờ đây, bạn có thể bắt đầu sử dụng polyfill trong ứng dụng của mình.

  1. Nhập tệp cấu hình và chỉ định tệp đó cho một biến chung có tên phù hợp, trong đó $BACKEND là phần phụ trợ bạn chọn: window.$BACKEND_CONFIG.
  2. Sử dụng tính năng nhập động để chỉ tải polyfill khi trình duyệt cơ bản không hỗ trợ tính năng này.
  3. Gọi các hàm Prompt API.
import config from './.env.json' with { type: 'json' };

// Set $BACKEND_CONFIG to select a backend
window.$BACKEND_CONFIG = config;

if (!('LanguageModel' in window)) {
  await import('prompt-api-polyfill');
}

const session = await LanguageModel.create({
  expectedInputs: [{type: 'text', languages: ['en']}],
  expectedOutputs: [{type: 'text', languages: ['en']}],
});
await session.prompt('Tell me a joke!');

Polyfill này hỗ trợ đầu ra có cấu trúc (ngoại trừ phần phụ trợ Transformers.js), xử lý đầu vào đa phương thức (ngoại trừ phần phụ trợ OpenAI không hỗ trợ đồng thời âm thanh và hình ảnh, mà chỉ hỗ trợ riêng lẻ) và được kiểm thử dựa trên bộ Web Platform Tests hoàn chỉnh cho LanguageModel.

Để biết thêm thông tin cơ bản và thông tin chi tiết về cách sử dụng cũng như mã nguồn, hãy xem tệp README trong kho lưu trữ GitHub.

Điểm khác biệt so với Prompt API của trình duyệt

Nếu polyfill được hỗ trợ bởi các mô hình trên đám mây, thì một số lợi ích khi chạy phía máy khách sẽ không còn áp dụng nữa. Cụ thể là bạn không thể đảm bảo việc xử lý dữ liệu nhạy cảm tại địa phương nữa, mặc dù chính sách quyền riêng tư của nhà cung cấp phụ trợ vẫn áp dụng. Ứng dụng của bạn cũng không thể sử dụng AI khi người dùng không có mạng. Để biết bạn đang ở trạng thái trực tuyến hay ngoại tuyến, bạn có thể theo dõi các sự kiện tương ứng.

window.addEventListener("offline", (e) => {
  console.log("offline");
});

window.addEventListener("online", (e) => {
  console.log("online");
});

Nếu suy luận AI chạy dựa trên một mô hình trên đám mây, thì sẽ không có mô hình cục bộ nào để tải xuống. Polyfill giả mạo các sự kiện downloadprogress, vì vậy đối với ứng dụng của bạn, có vẻ như mô hình tích hợp sẵn đã được tải xuống, tức là sẽ có hai sự kiện, một sự kiện có giá trị loaded0 và một sự kiện có 1, đây là yêu cầu của quy cách.

Với suy luận dựa trên đám mây, không giống như suy luận trên thiết bị, có thể sẽ phát sinh chi phí khi gọi API từ nhà cung cấp phụ trợ mà bạn chọn. Kiểm tra thông tin về giá, chẳng hạn như giá của Gemini API. Nếu biết chi phí cho mỗi mã thông báo, bạn có thể sử dụng thông tin contextUsage của Prompt API để tính toán chi phí.

const COST_PER_TOKEN = 123;
const COST_LIMIT = 456;

let costSoFar = 0;

const session = await LanguageModel.create(options);

/…/

if (costSoFar < COST_LIMIT) {
  await session.prompt('Tell me a joke.');
  costSoFar = session.contextUsage * COST_PER_TOKEN;
} else {
  // Show premium AI plan promo.
}

Khi bạn gọi một API đám mây trực tiếp từ một ứng dụng di động hoặc ứng dụng web (ví dụ: các API cho phép truy cập vào các mô hình AI tạo sinh), khoá API sẽ dễ bị các ứng dụng trái phép lợi dụng. Để giúp bảo vệ các API này, nếu sử dụng Firebase AI Logic Hybrid SDK, bạn nên dùng Firebase App Check để xác minh rằng tất cả các lệnh gọi API đến đều đến từ ứng dụng thực tế của bạn. Với một số nhà cung cấp dịch vụ đám mây như Google, bạn cũng có thể thực thi các quy trình kiểm tra nguồn gốc nghiêm ngặt để đảm bảo rằng chỉ những trang web được phép mới có thể sử dụng API.

Thay vì giới hạn của Prompt API (ví dụ: liên quan đến contextWindow của phiên), giới hạn của nhà cung cấp phụ trợ sẽ được áp dụng. Đối với contextWindow, các giới hạn này thường cao hơn nhiều so với trên thiết bị và bạn có thể xử lý lượng dữ liệu lớn hơn trên đám mây. Vì vậy, mặc dù bạn nên biết về sự khác biệt này, nhưng trên thực tế, bạn có thể sẽ không gặp phải vấn đề gì.

Tạo phần phụ trợ của riêng bạn

Để thêm nhà cung cấp phụ trợ của riêng bạn, hãy làm theo các bước sau:

Mở rộng lớp cơ sở của phần phụ trợ

Tạo một tệp mới trong thư mục backends/, ví dụ: backends/custom-backend.js. Bạn cần mở rộng lớp PolyfillBackend và triển khai các phương thức cốt lõi đáp ứng giao diện dự kiến.

import PolyfillBackend from './base.js';
import { DEFAULT_MODELS } from './defaults.js';

export default class CustomBackend extends PolyfillBackend {
  constructor(config) {
    // config typically comes from a window global (e.g., window.CUSTOM_CONFIG)
    super(config.modelName || DEFAULT_MODELS.custom.modelName);
  }

  // Check if the backend is configured (e.g., API key is present), if given
  // combinations of modelName and options are supported, or, for local model,
  // if the model is available.
  static availability(options) {
    return window.CUSTOM_CONFIG?.apiKey ? 'available' : 'unavailable';
  }

  // Initialize the underlying SDK or API client. With local models, use
  // monitorTarget to report model download progress to the polyfill.
  createSession(options, sessionParams, monitorTarget) {
    // Return the initialized session or client instance
  }

  // Non-streaming prompt execution
  async generateContent(contents) {
    // contents: Array of { role: 'user'|'model', parts: [{ text: string }] }
    // Return: { text: string, usage: number }
  }

  // Streaming prompt execution
  async generateContentStream(contents) {
    // Return: AsyncIterable yielding chunks
  }

  // Token counting for quota/usage tracking
  async countTokens(contents) {
    // Return: total token count (number)
  }
}

Đăng ký phần phụ trợ

Polyfill sử dụng chiến lược "Ưu tiên trùng khớp đầu tiên" dựa trên cấu hình chung. Bạn cần đăng ký phần phụ trợ trong tệp prompt-api-polyfill.js bằng cách thêm phần phụ trợ đó vào mảng #backends tĩnh:

// prompt-api-polyfill.js
static #backends = [
  // ... existing backends
  {
    config: 'CUSTOM_CONFIG', // The global object to look for on `window`
    path: './backends/custom-backend.js',
  },
];

Đặt mô hình mặc định

Xác định danh tính của mô hình dự phòng trong backends/defaults.js. Tham số này được dùng khi người dùng khởi tạo một phiên mà không chỉ định một modelName cụ thể.

// backends/defaults.js
export const DEFAULT_MODELS = {
  // ...
  custom: 'custom-model-pro-v1',
};

Bật tính năng phát triển và kiểm thử cục bộ

Dự án này sử dụng một tập lệnh khám phá (scripts/list-backends.js) để tạo ma trận kiểm thử. Để đưa chương trình phụ trợ mới vào trình chạy kiểm thử, hãy tạo một tệp .env-[name].json (ví dụ: .env-custom.json) trong thư mục gốc:

{
  "apiKey": "your-api-key-here",
  "modelName": "custom-model-pro-v1"
}

Xác minh bằng Web Platform Tests (WPT)

Bước cuối cùng là đảm bảo tuân thủ. Vì polyfill dựa trên thông số kỹ thuật, nên mọi phần phụ trợ mới đều phải vượt qua các Kiểm thử nền tảng web chính thức (hoặc dự kiến):

npm run test:wpt

Bước xác minh này đảm bảo rằng phần phụ trợ của bạn xử lý những việc như AbortSignal, lời nhắc hệ thống và định dạng nhật ký chính xác như quy cách Prompt API mong đợi.

Kết luận

Polyfill giúp bạn sử dụng Prompt API trên mọi nền tảng và thiết bị. Bằng cách lập trình dựa trên API được xác định rõ của Prompt API, bạn sẽ độc lập hơn với các nhà cung cấp dịch vụ đám mây và duy trì gần với nền tảng nhất có thể.

Trên các thiết bị có hỗ trợ Prompt API, polyfill thậm chí không được tải, vì vậy, người dùng sẽ không phải tải mã mà họ không thực thi. Nếu bạn có ý kiến phản hồi hoặc gặp phải lỗi, hãy mở một vấn đề trên GitHub. Chúc bạn đặt câu lệnh thành công!