> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Gemini 指南

> 雙子星漫遊指南：本站 Gemini 調用細節總覽。

## Gemini 調用方式

對於 Gemini 系列，我們提供原生調用和 Openai 相容這 2 種調用方式。\
使用前請執行 `pip install google-genai` 或 `pip install -U google-genai`，安裝（更新）原生依賴。

1️⃣ 原生調用時，需在內部傳入 AiHubMix 密鑰和請求連結。注意這個連結和常規 `base_url` 寫法不同，請參考範例：

```py theme={null}
client = genai.Client(
    api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
    http_options={"base_url": "https://aihubmix.com/gemini"},
)
```

2️⃣ Openai 相容格式則維持通用的 `v1` 端點：

```py theme={null}
client = OpenAI(
    api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
    base_url="https://aihubmix.com/v1",
)
```

3️⃣ 針對 2.5 系列，如需顯示推理過程，可用以下 2 種方式：

1. 原生調用：傳入 `include_thoughts=True`
2. OpenAI 相容方式：傳入 `reasoning_effort`

詳細調用請參考下文程式碼範例。

### Gemini 2.5 系列「推理」說明

1. 2.5 系列皆為推理模型。
2. 2.5 flash 為混合模型，類似 claude sonnet 3.7，可用 `thinking_budget` 控制推理預算以達最佳效果。
3. 2.5 pro 為純推理模型，無法關閉 thinking，也不顯式傳遞推理預算。

**Python 調用參考如下：**

<CodeGroup>
  ```py 普通非流式 theme={null}
  from google import genai
  from google.genai import types

  def generate():
      client = genai.Client(
          api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
          http_options={"base_url": "https://aihubmix.com/gemini"},
      )

      model = "gemini-2.0-flash"
      contents = [
          types.Content(
              role="user",
              parts=[
                  types.Part.from_text(text="""對於普通股票投資者：分析財報有用的话，还要运气做什么？"""),
              ],
          ),
      ]

      print(client.models.generate_content(
          model=model,
          contents=contents,
      ))

  if __name__ == "__main__":
      generate()
  ```

  ```py 2.0 系列-流式 theme={null}
  from google import genai
  from google.genai import types

  def generate():
      client = genai.Client(
          api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
          http_options={"base_url": "https://aihubmix.com/gemini"},
      )

      model = "gemini-2.0-flash"
      contents = [
          types.Content(
              role="user",
              parts=[
                  types.Part.from_text(text="""對於普通股票投資者：分析財報有用的话，还要运气做什么？"""),
              ],
          ),
      ]
      generate_content_config = types.GenerateContentConfig(
          response_mime_type="text/plain",
      )

      for chunk in client.models.generate_content_stream(
          model=model,
          contents=contents,
          config=generate_content_config,
      ):
          print(chunk.text, end="")

  if __name__ == "__main__":
      generate()
  ```

  ```py 2.5 Flash-流式 theme={null}
  from google import genai
  from google.genai import types

  def generate():
      client = genai.Client(
          api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
          http_options={"base_url": "https://aihubmix.com/gemini"},
      )

      model = "gemini-2.5-flash-preview-04-17" #gemini-2.5-pro-preview-03-25、gemini-2.5-flash-preview-04-17
      contents = [
          types.Content(
              role="user",
              parts=[
                  types.Part.from_text(text="""對於普通股票投資者：分析財報有用的话，还要运气做什么？"""),
              ],
          ),
      ]
      generate_content_config = types.GenerateContentConfig(
          thinking_config = types.ThinkingConfig(
              thinking_budget=2048, #範圍 0-16384。默認 1024，最佳邊際效果 16000
          ),
          response_mime_type="text/plain",
      )

      for chunk in client.models.generate_content_stream(
          model=model,
          contents=contents,
          config=generate_content_config,
      ):
          print(chunk.text, end="")

  if __name__ == "__main__":
      generate()
  ```

  ```py 2.5 Pro-流式 theme={null}
  from google import genai
  from google.genai import types

  def generate():
      client = genai.Client(
          api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
          http_options={"base_url": "https://aihubmix.com/gemini"},
      )

      model = "gemini-2.5-pro-preview-03-25"
      contents = [
          types.Content(
              role="user",
              parts=[
                  types.Part.from_text(text="""怎么知道我不是在浪费时间"""),
              ],
          ),
      ]
      generate_content_config = types.GenerateContentConfig(
          response_mime_type="text/plain",
      )

      for chunk in client.models.generate_content_stream(
          model=model,
          contents=contents,
          config=generate_content_config,
      ):
          print(chunk.text, end="")

  if __name__ == "__main__":
      generate()
  ```

  ```py 显示推理内容 theme={null}
  from google import genai
  from google.genai import types

  def generate():
      client = genai.Client(
          api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
          http_options={"base_url": "https://aihubmix.com/gemini"},
      )

      model = "gemini-2.5-pro-preview-05-06"
      contents = [
          types.Content(
              role="user",
              parts=[
                  types.Part.from_text(text="""金融领域的「72 法则」是如何推导的？"""),
              ],
          ),
      ]
      generate_content_config = types.GenerateContentConfig(
          response_mime_type="text/plain",
          thinking_config=types.ThinkingConfig(
              include_thoughts=True  # 🧠 啟用思考過程輸出
          ),
      )

      # 用於儲存最後一個 chunk 的 usage_metadata
      final_usage_metadata = None
      
      for chunk in client.models.generate_content_stream(
          model=model,
          contents=contents,
          config=generate_content_config,
      ):
          # 檢查是否有內容部分
          if chunk.candidates and len(chunk.candidates) > 0:
              for part in chunk.candidates[0].content.parts:
                  if part.text:
                      if part.thought:
                          # 思考過程內容
                          print(part.text, end="")
                      else:
                          # 最終答案內容
                          print(part.text, end="")
          
          # 保存最新的 usage_metadata，只有最後一個 chunk 會包含完整信息
          if chunk.usage_metadata:
              final_usage_metadata = chunk.usage_metadata
      
      # 在所有 chunk 處理完後，打印完整的 token 使用情況
      if final_usage_metadata:
          print(f"\n\n📊 Token 使用情況:")
          print(f"思考 tokens: {getattr(final_usage_metadata, 'thoughts_token_count', '不可用')}")
          print(f"輸出 tokens: {getattr(final_usage_metadata, 'candidates_token_count', '不可用')}")
          print(f"總計: {final_usage_metadata}")

  if __name__ == "__main__":
      generate()
  ```
</CodeGroup>

## Gemini 2.5 Flash 支持

Openai 相容方式調用參考如下：

<CodeGroup>
  ```py Python 用於快速任務時，關閉思考 theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
      base_url="https://aihubmix.com/v1",
  )

  completion = client.chat.completions.create(
      model="gemini-2.5-flash-preview-04-17-nothink",
      messages=[
          {
              "role": "user",
              "content": "Explain the Occam's Razor concept and provide everyday examples of it"
          }
      ]
  )

  print(completion.choices[0].message.content)
  ```

  ```py Python 控制預算 theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
      base_url="https://aihubmix.com/v1",
  )

  completion = client.chat.completions.create(
      model="gemini-2.5-flash-preview-04-17",
      reasoning_effort="low", # 可選 "low", "medium" 和 "high", 分別對應 1024, 8192 和 16384 推理預算
      messages=[
          {
              "role": "user",
              "content": "Explain the Occam's Razor concept and provide everyday examples of it"
          }
      ]
  )

  print(completion.choices[0].message.content)
  ```

  ```shell Curl-基礎調用 theme={null}
  curl -X POST https://aihubmix.com/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer sk-***" \
    -d '{
      "model": "gemini-2.5-flash-preview-04-17-nothink",
      "messages": [
        {
          "role": "user",
          "content": "Explain the Occam'\''s Razor concept and provide an everyday example of it."
        }
      ]
    }'
  ```

  ```shell Curl-Thinking 顯示 theme={null}
  curl https://aihubmix.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -d '{
    "model": "gemini-2.5-pro-preview-05-06",
    "messages": [
      {
        "role": "user",
        "content": "Explain the Occam'\''s Razor concept and provide an everyday example of it."
      }
    ],
    "reasoning_effort": "low"
  }'
  ```
</CodeGroup>

<Tip>
  1. 用於複雜任務時，只需要將模型 id 設置為默認開啟思考的 `gemini-2.5-flash-preview-04-17` 即可。
  2. Gemini 2.5 Flash 通過 `budget`（思考預算）來控制思考的深度，範圍 0-16K，目前轉發采用的是默認預算 1024，最佳邊際效果為 16K。
</Tip>

## 多媒體文件

Aihubmix 目前只支持**小於 20MB** 的多媒體文件（圖片、音頻、視頻），用 `inline_data` 上傳。\
大於 20M 的多媒體需要用 File API（尚未支持），待完善狀態跟踪，返回 `upload_url`。

<CodeGroup>
  ```py 圖片 theme={null}
  from google import genai
  from google.genai import types

  # 讀取文件為二進制數據
  file_path = "yourpath/file.jpeg"
  with open(file_path, "rb") as f:
      file_bytes = f.read()

  client = genai.Client(
      api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
      http_options={"base_url": "https://aihubmix.com/gemini"}
  )

  response = client.models.generate_content(
      model="gemini-2.0-flash",
      contents=types.Content(
          parts=[
              types.Part(
                  inline_data=types.Blob(
                      data=file_bytes,
                      mime_type="image/jpeg"
                  )
              ),
              types.Part(
                  text="Describe the image."
              )
          ]
      )
  )

  print(response.text)
  ```

  ```py 音频 theme={null}
  from google import genai
  from google.genai import types

  # 讀取文件為二進制數據
  file_path = "yourpath/file.m4a"
  with open(file_path, "rb") as f:
      file_bytes = f.read()

  client = genai.Client(
      api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
      http_options={"base_url": "https://aihubmix.com/gemini"}
  )

  response = client.models.generate_content(
      model="gemini-2.0-flash",
      contents=types.Content(
          parts=[
              types.Part(
                  inline_data=types.Blob(
                      data=file_bytes,
                      mime_type="audio/m4a"
                  )
              ),
              types.Part(
                  text="Transcribe the audio to text."
              )
          ]
      )
  )

  print(response.text)
  ```

  ```py 视频 theme={null}
  from google import genai
  from google.genai import types

  # 讀取文件為二進制數據
  file_path = "yourpath/file.mp4"
  with open(file_path, "rb") as f:
      file_bytes = f.read()

  client = genai.Client(
      api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
      http_options={"base_url": "https://aihubmix.com/gemini"}
  )

  response = client.models.generate_content(
      model="gemini-2.0-flash",
      contents=types.Content(
          parts=[
              types.Part(
                  inline_data=types.Blob(
                      data=file_bytes,
                      mime_type="video/mp4"
                  )
              ),
              types.Part(
                  text="Summarize this video. Then create a quiz with an answer key based on the information in this video."
              )
          ]
      )
  )

  print(response.text)
  ```

  ```py Youtube 链接 theme={null}
  from google import genai
  from google.genai import types

  client = genai.Client(
      api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
      http_options={"base_url": "https://aihubmix.com/gemini"}
  )

  response = client.models.generate_content(
      model="gemini-2.0-flash",
      contents=types.Content(
          parts=[
              types.Part(
                  file_data=types.FileData(
                      file_uri="https://www.youtube.com/watch?v=OoU7PwNyYUw"
                  )
              ),
              types.Part(
                  text="Please summarize the video in 3 sentences."
              )
          ]
      )
  )

  print(response.text)
  ```
</CodeGroup>

## Code Execution

自动代码解析器用例参考：

```py Python theme={null}
from google import genai
from google.genai import types

# 讀取文件為二進制數據
file_path = "yourpath/file.csv"
with open(file_path, "rb") as f:
    file_bytes = f.read()

client = genai.Client(
    api_key="sk-***", # 🔑 換成你在 AiHubMix 生成的密鑰
    http_options={"base_url": "https://aihubmix.com/gemini"}
)

response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents=types.Content(
        parts=[
            types.Part(
                inline_data=types.Blob(
                    data=file_bytes,
                    mime_type="text/csv"
                )
            ),
            types.Part(
                text="Please analyze this CSV and summarize the key statistics. Use code execution if needed."
            )
        ]
    ),
    config=types.GenerateContentConfig(
        tools=[types.Tool(
            code_execution=types.ToolCodeExecution
        )]
    )
)

for part in response.candidates[0].content.parts:
    if part.text is not None:
        print(part.text)
    if getattr(part, "executable_code", None) is not None:
        print("Generated code:\n", part.executable_code.code)
    if getattr(part, "code_execution_result", None) is not None:
        print("Execution result:\n", part.code_execution_result.output)
```

## Interactions API

Interactions 是 Gemini 新一代推理介面，返回結構化的 `Interaction` 物件，支援文字生成、原生圖像生成（Nano Banana）及多步推理。目前已支援**同步模式**（`interactions.create()`）；非同步模式（Background Interactions）敬請期待。

<Warning>
  SDK 版本要求：`@google/genai` **>= 2.0.0**（JS/TS）或 `google-genai` **>= 2.0.0**（Python）。低版本 SDK 呼叫 Interactions 會被 Google 後端拒絕（`legacy Interactions schema no longer supported`）。
</Warning>

### 文字生成

呼叫 `interactions.create()` 發起推理，返回的 `Interaction` 物件提供 `output_text` 便捷屬性。

<CodeGroup>
  ```js JavaScript theme={null}
  import { GoogleGenAI } from "@google/genai";

  const ai = new GoogleGenAI({
    apiKey: "sk-***", // 替換為你在 AIHubMix 生成的 API Key
    httpOptions: { baseUrl: "https://aihubmix.com/gemini" },
  });

  const interaction = await ai.interactions.create({
    model: "gemini-3.5-flash",
    input: "用一句話解釋量子計算",
  });

  console.log(interaction.output_text);
  console.log(interaction.usage);
  // { total_tokens, total_input_tokens, total_output_tokens, ... }
  ```

  ```py Python theme={null}
  from google import genai

  client = genai.Client(
      api_key="sk-***",  # 替換為你在 AIHubMix 生成的 API Key
      http_options={"base_url": "https://aihubmix.com/gemini"},
  )

  interaction = client.interactions.create(
      model="gemini-3.5-flash",
      input="用一句話解釋量子計算",
  )

  print(interaction.output_text)
  ```
</CodeGroup>

### 原生圖像生成

透過 `response_format` 配置輸出模態為圖像，返回的 `Interaction` 物件提供 `output_image` 便捷屬性。

<Tip>
  * 推薦模型 `gemini-3.1-flash-image`（Nano Banana 2，通用生圖模型）。
  * `response_modalities` 值必須為**小寫** `['text', 'image']`；大寫為 `generateContent` API 的寫法，在 Interactions API 中會返回 `400`。
  * 勿傳 `delivery: 'inline'`（`400 Image delivery mode is not supported`），結果預設即以 inline 方式返回。
</Tip>

<CodeGroup>
  ```js JavaScript theme={null}
  import { GoogleGenAI } from "@google/genai";
  import fs from "node:fs";

  const ai = new GoogleGenAI({
    apiKey: "sk-***", // 替換為你在 AIHubMix 生成的 API Key
    httpOptions: { baseUrl: "https://aihubmix.com/gemini" },
  });

  const interaction = await ai.interactions.create({
    model: "gemini-3.1-flash-image",
    input: "A translucent banana-shaped glass lamp on a white desk, soft studio lighting.",
    response_modalities: ["text", "image"],
    response_format: { type: "image", aspect_ratio: "1:1", image_size: "1K" },
  });

  // output_image 便捷屬性（取最後一張生成圖像）
  if (interaction.output_image?.data) {
    fs.writeFileSync("output.png", Buffer.from(interaction.output_image.data, "base64"));
  }
  ```

  ```py Python theme={null}
  import base64
  from google import genai

  client = genai.Client(
      api_key="sk-***",  # 替換為你在 AIHubMix 生成的 API Key
      http_options={"base_url": "https://aihubmix.com/gemini"},
  )

  interaction = client.interactions.create(
      model="gemini-3.1-flash-image",
      input="A translucent banana-shaped glass lamp on a white desk, soft studio lighting.",
      response_format={
          "type": "image",
          "aspect_ratio": "1:1",
          "image_size": "1K",
      },
  )

  if interaction.output_image:
      with open("output.png", "wb") as f:
          f.write(base64.b64decode(interaction.output_image.data))
  ```
</CodeGroup>

### 串流輸出

傳入 `stream: true` 啟用 SSE 串流傳輸。增量文字透過 `event.delta.text` 取得。

```js JavaScript theme={null}
const stream = await ai.interactions.create({
  model: "gemini-3.5-flash",
  input: "寫一首關於月亮的俳句",
  stream: true,
});

for await (const event of stream) {
  if (event.event_type === "step.delta" && event.delta?.type === "text") {
    process.stdout.write(event.delta.text);
  }
  if (event.event_type === "interaction.completed") {
    console.log("\nUsage:", JSON.stringify(event.interaction?.usage));
  }
}
```

> 完整的 SDK 接入指南（含 Embeddings、顯式快取 CRUD、能力矩陣等）請參考 [Gemini 原生 SDK 接入](/zh-Hant/api/Gemini-SDK)。

## 上下文快取

Gemini 在原生 API 下預設啟用了**隱式上下文快取**，無需開發者手動操作。每一次 `generate_content` 請求，系統會自動為輸入內容建立快取。當後續請求與此前內容完全一致時，將直接命中快取，返回上一次的推理結果，大幅提升回應速度並有機會節省 token 消耗。

* **快取自動生效，無需手動配置。**
* 快取僅在內容、模型、參數完全一致時生效；任何欄位不同都會視為新請求，不命中快取。
* 快取有效期（TTL）由開發者設定，也可以不設定。如果未指定，預設為 1 小時。無最小或最大時長限制，費用取決於快取 token 數與快取時間。
  * 雖然 Google 官方對 TTL 不設上下限，但由於我們作為轉發平台，**僅支援有限的 TTL 配置範圍，不保證永久有效**。

### 注意事項

* **無成本節省保證**：快取 token 的計費為輸入原價的 25%，理論上輸入部分可最多節省 75% 成本，[**但 Google 官方並未承諾必然節省**](https://ai.google.dev/gemini-api/docs/caching?lang=python)，實際帳單還需結合快取命中率、token 類型與儲存時長共同評估。
* **快取命中條件**：建議將重複的上下文放在請求前部，將易變內容（如用戶輸入）置於後部，以提高快取命中率。
* **快取命中回饋**：如果回應結果命中快取，在 `response.usage_metadata` 中會包含 `cache_tokens_details` 欄位，並有 `cached_content_token_count`，開發者可以據此判斷本次請求是否命中快取。\
  範例回應欄位（命中快取時）：

  ```
  cache_tokens_details=[ModalityTokenCount(modality=<MediaModality.TEXT: 'TEXT'>, token_count=2003)]
  cached_content_token_count=2003
  ```

**程式碼範例：**

```python theme={null}
from google import genai

client = genai.Client(
    http_options={"base_url": "https://aihubmix.com/gemini"},
    api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
)

prompt = """
《三国演义》词曰：打开字典    滚滚长江东逝水，浪花淘尽英雄。是非成败转头空：青山依旧在，几度夕阳红。白发渔樵江渚上，惯看秋月春风。一壶浊酒喜相逢：古今多少事，都付笑谈中。2 打开字典  宴桃园豪... : 话说天下大势，分久必合，合久必分：周末七国分争，并入于秦。及秦灭之后，楚、汉分争，又并入于汉。汉朝自高祖斩白蛇而起义，一统天下。后来光武中兴，传至献帝，遂分为三国。推其致乱之由，殆始于桓、灵二帝。桓帝禁锢善类，崇 信宦官。及桓帝崩，灵帝即位，大将军窦武、太傅陈蕃，共相辅佐。时有宦官曹节等弄权，窦武、陈蕃谋诛之，作事不密，反为所害。中涓自此愈横。3 打开字典  宴桃园豪... : 建宁二年四月望日，帝御温德殿。方升座，殿角狂风骤起，只 见一条大青蛇，从梁上飞将下来，蟠于椅上。帝惊倒，左右急救入宫，百官俱奔避。须臾，蛇不见了。忽然大雷大雨，加以冰雹，落到半夜方止，坏却房屋无数。建宁四年二月，洛阳地震；又海水泛溢，沿海居民，尽被大浪卷入海中。光和元 年，雌鸡化雄。六月朔，黑气十馀丈，飞入温德殿中。秋七月，有虹见于玉堂；五原山岸，尽皆崩裂。种种不祥，非止一端。4 打开字典  宴桃园豪... : 帝下诏问群臣以灾异之由，议郎蔡邕上疏，以为霓堕鸡化，乃妇寺干政之所致，言颇切 直。帝览奏叹息，因起更衣。曹节在后窃视，悉宣告左右·遂以他事陷邕于罪，放归田里。后张让，赵忠，封諝，段圭，曹节，候览，蹇硕，程旷，夏恽，郭胜十人朋比为奸，号为"十常侍"。帝尊信张让，呼为"阿父"，朝政日非，以致天下人心思乱，盗贼蜂起。5 打开字典  宴桃园豪... : 时钜鹿郡有兄弟三人：一名张角，一名张宝，一名张梁。那张角本是个不第秀才。因入山采药，遇一老人，碧眼童颜，手执藜杖，唤角至一洞中，以天书三卷授之，曰："此名太平要术。汝得之，当代天宣化，普救世人；若萌异心，必获恶报。"角拜问姓名。老人曰："吾乃南华老仙也。"言讫，化阵清风而去。6 打开字典  宴桃园豪... : 角得此书，晓夜攻习，能呼风唤雨，号为太平道人。中平元年正月内，疫气流行，张角散施符水，为人治病，自称大贤良师。角有徒弟五百馀人，云游四方，皆能书符念咒。次后徒众日多，角乃立三十六方，─大方万馀人，小方六七千─，各立渠帅，称为将军。讹言"苍天已死，黄天当立。"又云"岁在甲子，天下大吉。"令人各以白土，书"甲子"二字于家中大门上。青、幽、徐、冀、荆、扬、兖、豫八州之人，家家侍奉大贤良师张角名字。角遣其党马元义，暗赍金帛，结交中涓封諝，以为内应。角与二弟商议曰："至难得者，民心也。今民心已顺，若不乘势取天下，诚为可惜。"遂一面私造黄旗，约期举事；一面使弟子唐州，驰书报封諝。唐州乃迳赴省中告变。帝召大将军何进调兵擒马元义，斩之；次收封諝等一干人下狱。7 打开字典  宴桃园豪... : 张角闻知事露，星夜举兵，自称天公将军，─张宝称地公将军，张梁称人公将军─。申言于众曰："今汉运将终，大圣人出；汝等皆宜顺从天意，以桨太平。"四方百姓，裹黄巾从张角反者，四五十万。贼势浩大，官军望风而靡。何进奏帝火速降诏，令各处备御，讨贼立功；一面遣中郎将卢植，皇甫嵩，朱隽，各引精兵，分三路讨之。8 打开字典  宴桃园豪... : 且说张角一军，前犯幽州界分。幽州太守刘焉，乃江夏竟陵人氏，汉鲁恭王之后也；当时闻得贼兵将至，召校尉邹靖计议。靖曰："贼兵众，我兵寡，明公宜作速招军应敌。"刘焉然其说，随 即出榜招募义兵。榜文行到涿县，乃引出涿县中一个英雄。9 打开字典  宴桃园豪... : 那人不甚好读书；性宽和，寡言语，喜怒不形于色；素有大志，专好结交天下豪杰；生得身长七尺五寸，两耳垂肩，双手过膝，目能自顾其耳，面如冠玉，唇若涂脂；中山靖王刘胜之后，汉景帝阁下玄孙；姓刘，名备，字玄德。昔刘胜之子刘贞，汉武时封涿鹿亭侯，后坐酬金失侯，因此遗这一枝在涿县。玄德祖刘雄，父刘弘。弘曾举孝廉，亦尝作吏，早丧。玄德幼孤，事母至孝；家贫，贩屦 织席为业。家住本县楼桑村。其家之东南，有一大桑树，高五丈馀，遥望之，童童如车盖。相者云："此家必出贵人。"10 打开字典 宴桃园豪... : 玄德幼时，与乡中小儿戏于树下，曰："我为天子，当乘此车盖。"叔父刘元起奇其言，曰："此儿非常人也！"因见玄德家贫，常资给之。年十五岁，母使游学，尝师事郑玄、卢植；与公孙瓒等为友。及刘焉发榜招军时，玄德年己二十八岁矣。当日见了榜文，慨然长叹。随后一人厉声言曰："大丈夫不与国家出力，何故长叹？"11 打开字 典 宴桃园豪... : 玄德回视其人：身长八尺，豹头环眼，燕颔虎须，声若巨雷，势如奔马。玄德见他形貌异常，问其姓名。其人曰："某姓张，名飞，字翼德。世居涿郡，颇有庄田，卖酒屠猪，专好结交天下豪杰。适才见公看榜而叹，故此相 问。"玄德曰："我本汉室宗亲，姓刘，名备。今闻黄巾倡乱，有志欲破贼安民；恨力不能，故长叹耳。"飞曰："吾颇有资财，当招募乡勇，与公同举大事，如何？"玄德甚喜，遂与同入村店中饮酒。12 打开字典 宴桃园豪... : 正饮间，见一大汉，推著一辆车子，到店门首歇了；入店坐下，便唤酒保："快斟酒来吃，我待赶入城去投军。"玄德看其人：身长九尺，髯长二尺：面如重枣，唇若涂脂；丹凤眼，卧蚕眉：相貌堂堂，威风凛凛。玄德就邀他同坐，叩其姓名。其人曰："吾姓关，名羽，字寿长，后改云长，河东解良人也。因本处势豪，倚势凌人，被吾杀了；逃难江湖，五六年矣。今闻此处招军破贼，特来应募。"玄德遂以己志告之。云长大喜。同到张飞庄上，共议大事。13 打开字典相关讨论 宴桃园豪... : 飞曰："吾庄后有一桃园，花开正盛；明日当于园中祭告天地，我三人结为兄弟，协力同心，然后可图大事。"玄德、云长、齐声应曰："如此甚好。"次日，于桃园中，备下乌牛白马祭礼等项，三人焚香，再拜而说誓曰："念刘备、关羽、张飞，虽然异姓，既结为兄弟，则同心协力，救困扶危；上报国家，下安黎庶；不求同年同月同日生，但愿同年同月同日死。皇天后土，实鉴此心。背义忘恩，天人共戮。"誓毕，拜玄德为兄，关羽次之，张飞为弟。祭罢天地，复宰牛设酒，聚乡中勇士，得三百馀人，就桃园中痛饮一醉。来日收拾军器，但恨无马匹可乘。14 打开字典 宴桃园豪... : 正思虑间，人报"有两个客人，引一夥伴当，赶一群马，投庄上来。"玄德曰："此天佑我也！"三人出庄迎接。原来二客乃中山大商：一名张世平，一名苏双，每年往北贩马，近因寇发而回。玄德请二人到庄，置酒管待，诉说欲讨贼安民之意。二客大喜，愿将良马五十匹相送；又赠金银五百两，镔铁一千斤，以资器用。玄德谢别二客，便命良匠打造双股剑。云长造青龙偃月刀，又名冷艳 锯，重八十二斤。张飞造丈八点钢矛。各置全身铠甲。共聚乡勇五百馀人，来见邹靖。邹靖引见太守刘焉。三人参见毕，各通姓名。玄德说起宗派，刘焉大喜，遂认玄德为侄。
"""

def generate_content_sync():
    response = client.models.generate_content(
        model="gemini-2.5-flash-preview-05-20",
        contents=prompt + "三國演義這一回出現了幾個任務 ",
    )
    print(response.usage_metadata)  # 命中快取時會顯示 cache_tokens_details 和 cached_content_token_count 欄位
    return response

generate_content_sync()
```

> 命中快取時，`response.usage_metadata` 會包含如下結構：
>
> ```
> cache_tokens_details=[ModalityTokenCount(modality=<MediaModality.TEXT: 'TEXT'>, token_count=2003)]
> cached_content_token_count=2003
> ```

\*\*核心結論：\*\*隱式快取支援自動命中與命中回饋。開發者可以通過 usage\_metadata 判斷命中情況。成本節省非保證，實際效果因請求結構和使用場景而異。

## Function calling

使用 openai 相容方式調用 Gemini 的 function calling 功能時，需要在請求體內部傳入`tool_choice="auto"`，否則會報錯。

<CodeGroup>
  ```py Python theme={null}
  from openai import OpenAI

  # 定義模型的 function 宣告
  def schedule_meeting_function = {
      "name": "schedule_meeting",
      "description": "Schedules a meeting with specified attendees at a given time and date.",
      "parameters": {
          "type": "object",
          "properties": {
              "attendees": {
                  "type": "array",
                  "items": {"type": "string"},
                  "description": "List of people attending the meeting.",
              },
              "date": {
                  "type": "string",
                  "description": "Date of the meeting (e.g., '2024-07-29')",
              },
              "time": {
                  "type": "string",
                  "description": "Time of the meeting (e.g., '15:00')",
              },
              "topic": {
                  "type": "string",
                  "description": "The subject or topic of the meeting.",
              },
          },
          "required": ["attendees", "date", "time", "topic"],
      },
  }

  # 配置 client
  client = OpenAI(
      api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
      base_url="https://aihubmix.com/v1",
  )

  # 用 OpenAI 相容格式發送帶有 function 宣告的請求
  response = client.chat.completions.create(
      model="gemini-2.0-flash",
      messages=[
          {"role": "user", "content": "Schedule a meeting with Bob and Alice for 03/14/2025 at 10:00 AM about the Q3 planning."}
      ],
      tools=[{"type": "function", "function": schedule_meeting_function}],
      tool_choice="auto" ## 📍 此處追加了 Aihubmix 相容，更穩定的請求方式
  )

  # 檢查是否有 function call
  if response.choices[0].message.tool_calls:
      tool_call = response.choices[0].message.tool_calls[0]
      function_call = tool_call.function
      print(f"Function to call: {function_call.name}")
      print(f"Arguments: {function_call.arguments}")
      print(response.usage)
      #  在實際應用中，這裡可以調用你的 function：
      #  result = schedule_meeting(**json.loads(function_call.arguments))
  else:
      print("No function call found in the response.")
      print(response.choices[0].message.content)
  ```
</CodeGroup>

**輸出結果示例：**

```bash theme={null}
Function to call: schedule_meeting
Arguments: {"attendees":["Bob","Alice"],"date":"2025-03-14","time":"10:00","topic":"Q3 planning"}
CompletionUsage(completion_tokens=28, prompt_tokens=111, total_tokens=139, completion_tokens_details=None, prompt_tokens_details=None)
```

## Tokens 用量追踪

1. Gemini 原生采用 `usage_metadata` 來[追踪使用的 token](https://ai.google.dev/gemini-api/docs/tokens?lang=python)，其中的字段对应如下：

* prompt\_token\_count: 輸入 token 數
* candidates\_token\_count: 輸出 token 數
* thoughts\_token\_count: 推理使用的 token 數，性質上也是輸出 token
* total\_token\_count: 總 token 使用量（輸入+輸出）

2. 對於 OpenAI 相容格式，則採用 `.usage` 來追蹤，欄位對應如下：

* usage.completion\_tokens: 輸入 token 數
* usage.prompt\_tokens: 輸出 token 數（包含推理使用的 token 數）
* usage.total\_tokens: 總 token 使用量

**使用方法如下:**

<CodeGroup>
  ```py Gemini 原生 theme={null}
  from google import genai
  from google.genai import types
  import time

  def generate():
      client = genai.Client(
          api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
          http_options={"base_url": "https://aihubmix.com/gemini"},
      )

      model = "gemini-2.5-pro-preview-03-25"
      contents = [
          types.Content(
              role="user",
              parts=[
                  types.Part.from_text(text="""金融領域的「72 法則」是如何推導的？"""),
              ],
          ),
      ]
      generate_content_config = types.GenerateContentConfig(
          response_mime_type="text/plain",
      )

      final_usage_metadata = None
      
      for chunk in client.models.generate_content_stream(
          model=model,
          contents=contents,
          config=generate_content_config,
      ):
          print(chunk.text, end="")
          if chunk.usage_metadata:
              final_usage_metadata = chunk.usage_metadata
      
      # 在所有 chunk 處理完後，打印完整的 token 使用情況
      if final_usage_metadata:
          print(f"\nUsage: {final_usage_metadata}")

  if __name__ == "__main__":
      generate()
  ```

  ```py OpenAI 相容 theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="sk-***", # 換成你在 AiHubMix 生成的密鑰
      base_url="https://aihubmix.com/v1",
  )

  completion = client.chat.completions.create(
      model="gemini-2.5-flash-preview-04-17",
      reasoning_effort="low", #"low", "medium", and "high", which behind the scenes we map to 1K, 8K, and 24K thinking token budgets. If you want to disable thinking, you can set the reasoning effort to "none".
      messages=[
          {
              "role": "user",
              "content": "金融領域的「72 法則」是如何推導的？"
          }
      ],
      stream=True
  )

  #print(completion.choices[0].message.content)

  for chunk in completion:
      print(chunk.choices[0].delta)
      # 只在最後一個 chunk（包含完整 usage 資料）時打印 usage 資訊
      if chunk.usage and chunk.usage.completion_tokens > 0:
          print(f"輸出 tokens: {chunk.usage.completion_tokens}")
          print(f"輸入 tokens: {chunk.usage.prompt_tokens}")
          print(f"總 tokens: {chunk.usage.total_tokens}")
  ```
</CodeGroup>

***

最後更新：2026-07-07
