Gemini Nano in Chrome 137: notes for AI Engineers

Shawn Wang

Chrome 137의 Gemini Nano: AI 엔지니어를 위한 노트

원문은 Shawn Wang님이 에 게재했습니다. 이 블로그 구독하기

드디어 Gemini Nano가 모든 Chrome 사용자에게 거의 다가왔습니다 (원래는 Chrome 138에 들어온다고 잘못 알고 있었는데 — 직접 확인해보니 Chrome 137+부터 제한적인 상황에서 플래그 없이 제공되기 시작했습니다). 이 HN 게시물 덕분에 다시 떠올랐습니다. 연말까지는 완전히 플래그 없이 제공될 것으로 예상합니다.

저는 구글이 문서를 쓰는 방식이 마음에 들지 않아서, 이 블로그 글은 기본적으로 그들의 문서를 제 머릿속에 맞게 다시 쓴 것입니다.

자주 쓰이는 패턴을 위한 API를 몇 가지 제공하지만, 솔직히 엔지니어로서 당신이 신경 써야 할 핵심은 Prompt API이며, 가장 유연하고 개방적인 API입니다.

이미지

설정

초기에 과장됐던 window.ai(이를 모방한 xanderchromeai 같은 shim이 여럿 생겼지만 현재 활발하게 유지되는 것은 하나도 없습니다)와는 달리, 현재 릴리스된 구현은 훨씬 덜 “깔끔”합니다. 어쨌든 현재 설정 방법은 다음과 같습니다.

  1. Chrome 137 이상 버전을 사용 중인지 확인하세요
  2. chrome://flags/#prompt-api-for-gemini-nano 로 이동해 활성화하세요 (아쉽게도 Chrome을 다시 시작해야 합니다)
  3. 그런 다음 LangaugeModel.create()를 처음 호출해 모델을 다운로드하세요 — 집 와이파이 기준으로 몇 분 정도 걸립니다. Gemini에 따르면 “대략적인 다운로드 용량은 1.5GB에서 2.4GB 사이”라고 하니, 4~8비트 양자화된 4~6B 모델이라고 보면 될 것 같습니다.
const session = await LanguageModel.create({
monitor(m) {
  m.addEventListener("downloadprogress", (e) => {
    console.log(`Downloaded ${e.loaded * 100}%`);
  });
},
// // uncomment if want multimodal input https://developer.chrome.com/docs/ai/prompt-api#multimodal_capabilities 
// expectedInputs: [
//  { type: "audio" },
//  { type: "image" }
//  ]
})

알아두면 중요한 기본 사항

로드된 모델의 컨텍스트는 6k 토큰입니다 (initialPrompts 없이 inputQuota를 조회하면 됩니다):

session.inputQuota
// 6144

저는 Gemini Nano 팀과는 달리 function calling/JSON 출력이 매우 중요하다고 생각하는 사람이라, Gemini Nano에서 이를 어떻게 구현하는지 Hamel과 Jason에게서 가져온 프롬프트 예제로 살펴보겠습니다:

const JSONschema = `<schema>
{
    "description": "Correctly extracted \`UserDetail\` with all the required parameters with correct types",
    "name": "UserDetail",
    "parameters": {
        "properties": {
            "age": {
                "title": "Age",
                "type": "integer"
            },
            "name": {
                "title": "Name",
                "type": "string"
            }
        },
        "required": [
            "age",
            "name"
        ],
        "type": "object"
    }
}
</schema>`
const JSONsession = await LanguageModel.create({
  initialPrompts: [
    { role: 'system', content: 'You are a helpful LLM that only responds in valid JSON fitting a schema: ' + JSONschema },
    { role: 'user', content: "Extract Jason is 35 years old" },
    { role: 'assistant', content: '{age: 35, name: Jason}'},
  ]
});

const result1 = await JSONsession.prompt("Extract sarah is 22 years old");
console.log(result1);
// {age: 22, name: Sarah}

함정

지시 사항을 잘 따르지 못해서, 필수 필드가 제대로 지켜지지 않습니다:

const result1 = await JSONsession.prompt("its been a year since vibhu's birthday, he was 28 last year, guess how old he is now");
console.log(result1);
// { "age": 29 }

또 다른 점은 세션이 기본적으로 상태를 유지(stateful)한다는 것으로, 잊어버리면 좀 골치 아플 수 있습니다. 그래서 무상태(stateless) 버전은 이렇게 생겼습니다:

const baseSession = await LanguageModel.create({
  initialPrompts: // blah blah, as above
})

// you can also implement this as a class if you want to force users to use`new` keyword to make super clear it is stateless
const statelessSession = {  
    async prompt(str) {
        const clonedSession = await session.clone()
        return clonedSession.prompt(str)
    }
}

// these are all stateless calls now! yay repeatability and predictability!
const result1 = await statelessSession.prompt("Extract sarah is 22 years old");
console.log(result1);
const result2 = await statelessSession.prompt("Extract tanisha is 30 years old");
console.log(result2);

이런 함정들 때문에 직접 간단한 래퍼 라이브러리를 만들거나 https://github.com/kstonekuan/simple-chromium-ai 같은 것을 참조하고 싶어질 겁니다

JS에 익숙하지 않은 분들을 위한 마지막 팁은, ESM 문법을 사용해 브라우저 환경에서(즉, npm install이나 빌드 단계 없이) 이러한 래퍼 라이브러리를 import하는 방법입니다 (<script type="module">가 필요할 수 있습니다 - localhost나 CSP가 느슨한 사이트에서 실행하세요):

// alternatively use https://cdn.jsdelivr.net/npm/[email protected]/dist/simple-chromium-ai.mjs
const ChromiumAI = await import('https://unpkg.com/[email protected]/dist/simple-chromium-ai.mjs');

const ai = await ChromiumAI.initialize("You are a friendly assistant");
const response = await ChromiumAI.prompt(ai, "Tell me a joke");
console.log(response);
const ChromiumAI = await import('https://unpkg.com/[email protected]/dist/simple-chromium-ai.mjs');

const ai = await ChromiumAI.initialize("You are a friendly assistant");
const response = await ChromiumAI.prompt(ai, "Tell me a joke");
console.log(response);
// Why don't scientists trust atoms?  Because they make up everything! 

// and of course... the structured output implementation now works:
const schema = {
  type: "object",
  properties: {
    sentiment: {
      type: "string",
      enum: ["positive", "negative", "neutral"]
    },
    confidence: {
      type: "number",
      minimum: 0,
      maximum: 1
    },
    keywords: {
      type: "array",
      items: { type: "string" },
      maxItems: 5
    }
  },
  required: ["sentiment", "confidence", "keywords"]
};

// Create session with response constraint
const response = await ChromiumAI.prompt(
  ai, 
  "Analyze the sentiment of this text: 'I love this new feature!'",
  undefined, // no timeout
  { responseConstraint: schema }
);

// Response will be valid JSON matching the schema
const result = JSON.parse(response);
console.log(result);

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.

댓글