不用再一個個拉紅框了!Gemini 3 新功能教學:我如何用Agentic Vision,在LINE裡標註目標?
不用再一個個拉紅框了!Gemini 3 新功能教學:我如何用Agentic Vision,在LINE裡標註目標?
2026.02.03 | AI與大數據

在完成 LINE Bot 的 Multi-Agent Orchestration 架構 之後,原本的圖片分析功能是直接將圖片送到 gemini-2.5-flash 做識別。但 Google 在 2026 年 1 月發布了 Gemini 3 Flash 的 Agentic Vision 功能,讓模型不再只是「看」圖片,而是能主動寫 Python 程式碼來放大、裁切、標註圖片。

這讓我想到一個有趣的使用場景:

使用者傳一張照片,說「幫我把咖啡標記出來」,AI 不只回覆文字描述,還會畫出 bounding box 標註在圖片上,把標註後的圖片傳回 LINE。

本文記錄了實作這個功能的完整過程,包括踩到的坑和解決方案。

Agentic Vision 是什麼?

傳統的圖片分析是靜態的:丟圖片給模型,模型回傳文字描述。

Agentic Vision 把圖片理解變成一個主動的調查過程,使用 Think → Act → Observe 循環:

Agentic Vision 流程                         │
│                                                             │
│  1. Think  - 分析圖片,規劃要怎麼深入調查                     │
│  2. Act    - 寫 Python 程式碼(裁切、放大、標註、計算)         │
│  3. Observe - 觀察程式碼執行結果(包括生成的標註圖片)          │
│  4. 重複以上步驟直到完成分析                                   │
└─────────────────────────────────────────────────────────────┘

技術核心

模型: gemini-3-flash-preview
關鍵功能: code_execution 工具 — 讓模型能寫並執行 Python 程式碼
輸出: 除了文字分析,還能回傳模型生成的標註圖片

# 啟用 Agentic Vision 的 API 呼叫
response = client.models.generate_content(
    model="gemini-3-flash-preview",
    contents=[image_part, "幫我把咖啡標記出來"],
    config=types.GenerateContentConfig(
        tools=[types.Tool(code_execution=types.ToolCodeExecution)],
        thinking_config=types.ThinkingConfig(thinkingBudget=2048),
    )
)

# Response 包含多種 part:文字、程式碼、執行結果、標註圖片
for part in response.candidates[0].content.parts:
    if part.text:           # 文字分析
    if part.executable_code: # 模型寫的 Python 程式碼
    if part.code_execution_result:  # 程式碼執行結果
    if part.as_image():     # 生成的標註圖片!
    

功能設計

使用者體驗流程

原本收到圖片就直接分析,改成先讓使用者選擇模式:

使用者傳送圖片
     │
     ▼
┌─────────────────────────────────────┐
│  📷 已收到圖片,請選擇分析方式:      │
│                                     │
│  ┌──────────┐  ┌─────────────────┐  │
│  │ 識別圖片  │  │ Agentic Vision │  │
│  └──────────┘  └─────────────────┘  │
│         (Quick Reply Buttons)        │
└─────────────────────────────────────┘
     │                    │
     ▼                    ▼
 gemini-2.5-flash    使用者輸入指令
 直接回傳文字描述    「幫我把咖啡標記出來」
                         │
                         ▼
                  gemini-3-flash-preview
                  + code_execution
                         │
                    ┌────┴────┐
                    ▼         ▼
               文字分析    標註圖片
               (Text)    (Image)
                    │         │
                    ▼         ▼
               LINE TextMsg + ImageSendMessage

為什麼要分兩步?

Agentic Vision 需要使用者提供具體指令(例如「標記出所有人」「數一數有幾隻貓」),不像一般識別只需要「描述圖片」。所以選擇 Agentic Vision 後,會先請使用者輸入想要達成的目標。

實作細節

1. 圖片暫存機制

因為 LINE 的 Quick Reply 是異步的(使用者點按鈕觸發 PostbackEvent),圖片需要暫存:

# main.py
image_temp_store: Dict[str, bytes] = {}        # 暫存圖片(user_id → bytes)
pending_agentic_vision: Dict[str, bool] = {}    # 等待使用者輸入指令

流程:

  1. 收到圖片 → 存入 image_temp_store[user_id]
  2. 使用者點「Agentic Vision」→ 設定 pending_agentic_vision[user_id] = True
  3. 使用者輸入文字 → 偵測到 pending 狀態,取出圖片 + 文字一起送去分析

2. Quick Reply 實作

使用 LINE SDK 的 PostbackAction ,與現有的 YouTube 摘要、地點搜尋 Quick Reply 保持一致的模式:

quick_reply_buttons = QuickReply(
    items=[
        QuickReplyButton(
            action=PostbackAction(
                label="識別圖片",
                data=json.dumps({"action": "image_analyze", "mode": "recognize"}),
                display_text="識別圖片"
            )
        ),
        QuickReplyButton(
            action=PostbackAction(
                label="Agentic Vision",
                data=json.dumps({"action": "image_analyze", "mode": "agentic_vision"}),
                display_text="Agentic Vision"
            )
        ),
    ]
)

3. Agentic Vision 分析核心

# tools/summarizer.py
def analyze_image_agentic(image_data: bytes, prompt: str) -> dict:
    client = _get_vertex_client()

    contents = [
        types.Part.from_text(text=prompt),
        types.Part.from_bytes(data=image_data, mime_type="image/png")
    ]

    response = client.models.generate_content(
        model="gemini-3-flash-preview",
        contents=contents,
        config=types.GenerateContentConfig(
            temperature=0.5,
            max_output_tokens=4096,
            tools=[types.Tool(code_execution=types.ToolCodeExecution)],
            thinking_config=types.ThinkingConfig(thinkingBudget=2048),
        )
    )

    result_parts = []
    generated_images = []

    for part in response.candidates[0].content.parts:
        if hasattr(part, 'thought') and part.thought:
            continue  # 跳過 thinking parts
        if part.text is not None:
            result_parts.append(part.text)
        if part.code_execution_result is not None:
            result_parts.append(f"[Code Output]: {part.code_execution_result.output}")
        # 提取模型生成的標註圖片
        img = part.as_image()
        if img is not None:
            generated_images.append(img.image_bytes)

    return {
        "status": "success",
        "analysis": "\n".join(result_parts),
        "images": generated_images  # 標註後的圖片 bytes
    }

4. 圖片回傳機制

LINE 的 ImageSendMessage 需要公開的 HTTPS URL。因為我們部署在 Cloud Run(本身就是公開 HTTPS),所以直接在 FastAPI 上加一個圖片 serving endpoint:

# 暫存標註圖片(UUID → bytes,5 分鐘 TTL)
annotated_image_store: Dict[str, dict] = {}

@app.get("/images/{image_id}")
def serve_annotated_image(image_id: str):
    """提供暫存的標註圖片給 LINE 下載"""
    entry = annotated_image_store.get(image_id)
    if not entry:
        raise HTTPException(status_code=404)
    if time.time() - entry["created_at"] > 300:  # 5 分鐘過期
        annotated_image_store.pop(image_id, None)
        raise HTTPException(status_code=404)
    return Response(content=entry["data"], media_type="image/png")

自動偵測 App 的 base URL(從 webhook request 的 headers):

@app.post("/")
async def handle_webhook_callback(request: Request):
    global app_base_url
    if not app_base_url:
        forwarded_proto = request.headers.get('x-forwarded-proto', 'https')
        host = request.headers.get('x-forwarded-host') or request.headers.get('host', '')
        if host:
            app_base_url = f"{forwarded_proto}://{host}"

最後組合成 ImageSendMessage

def _create_image_send_message(image_bytes: bytes):
    image_id = store_annotated_image(image_bytes)
    image_url = f"{app_base_url}/images/{image_id}"
    return ImageSendMessage(
        original_content_url=image_url,
        preview_image_url=image_url,
    )

成果展示

 Agentic Vision
圖/ Evan提供
 Agentic Vision
圖/ Evan提供

踩到的坑

坑 1: from_image_bytes 不存在

ERROR: Error analyzing image: from_image_bytes

原因: google-genai SDK 中沒有 **types.Part.from_image_bytes() ** 這個方法,正確的是 types.Part.from_bytes()

# ❌ 錯誤
types.Part.from_image_bytes(data=image_data, mime_type="image/png")

# ✅ 正確
types.Part.from_bytes(data=image_data, mime_type="image/png")

坑 2: ThinkingLevel enum 不存在

ERROR: module 'google.genai.types' has no attribute 'ThinkingLevel'

原因: google-genai==1.49.0ThinkingConfig 只支援 thinkingBudget (整數),不支援 thinking_level enum。Context7 和官方文件的範例是基於更新版本的 SDK。

# ❌ 在 v1.49.0 不存在
types.ThinkingConfig(thinking_level=types.ThinkingLevel.MEDIUM)

# ✅ v1.49.0 支援的寫法
types.ThinkingConfig(thinkingBudget=2048)

教訓 :AI 生成的程式碼範例可能基於較新或較舊的 SDK 版本,永遠要用 python -c "help(types.ThinkingConfig)" 確認實際可用的參數。

坑 3: 識別圖片結果不完整

原因: gemini-2.5-flash 預設啟用 thinking,thinking tokens 會消耗 max_output_tokens 的額度。原本設定 max_output_tokens=2048,thinking 用掉一大半後,實際回覆被截斷。

# ❌ 改前:thinking 消耗了大部分 token 額度
config=types.GenerateContentConfig(
    max_output_tokens=2048,
)

# ✅ 改後:關閉 thinking + 加大 token 額度
config=types.GenerateContentConfig(
    max_output_tokens=8192,
    thinking_config=types.ThinkingConfig(thinkingBudget=0),  # 關閉 thinking
)

重點: 對於簡單的圖片描述,thinking 是多餘的開銷。thinkingBudget=0 可以關閉 thinking,讓全部 token 用在回覆上。

修改的檔案

原本的 VisionAgent 只有一條路徑,現在變成:

LINE Image Message
     │
     ▼
handle_image_message()
     │
     ├── image_temp_store[user_id] = image_bytes
     │
     ▼
Quick Reply: "識別圖片" / "Agentic Vision"
     │                         │
     ▼                         ▼
handle_image_analyze_      pending_agentic_vision[user_id] = True
postback()                     │
     │                         ▼
     │                   使用者輸入文字指令
     │                         │
     │                         ▼
     │                   handle_agentic_vision_with_prompt()
     │                         │
     ▼                         ▼
orchestrator               orchestrator
.process_image()           .process_image_agentic(prompt=使用者指令)
     │                         │
     ▼                         ▼
VisionAgent.analyze()      VisionAgent.analyze_agentic()
     │                         │
     ▼                         ▼
analyze_image()            analyze_image_agentic()
gemini-2.5-flash           gemini-3-flash-preview
thinkingBudget=0           + code_execution
                           + thinkingBudget=2048
     │                         │
     ▼                         ├── 文字分析 → TextSendMessage
TextSendMessage                ├── 標註圖片 → /images/{uuid} → ImageSendMessage
                               └── push_message([text, image])

開發心得

1. SDK 版本差異是最大的坑

這次開發最花時間的不是功能設計,而是 SDK 版本差異。 google-genai 的 API 變動頻繁:

  • from_image_bytesfrom_bytes(方法名稱變更)
  • ThinkingLevel enum 在 v1.49.0 不存在(需要用 thinkingBudget 整數)
  • thinkingmax_output_tokens 的影響沒有文件說明

建議:開發前先跑 pip show google-genai 確認版本,再用 help() 確認實際可用的 API。

2. LINE Bot 回傳圖片的限制

LINE 的 ImageSendMessage 要求圖片必須是公開的 HTTPS URL,不能直接傳 bytes。解決方案:

方案 優點 缺點
GCS 上傳 穩定、持久 需要設定 bucket 和權限
FastAPI endpoint 自行 serve 簡單、不需外部服務 重啟後消失、記憶體佔用
Base64 嵌入文字 最簡單 LINE 不支援

我選擇 FastAPI endpoint 方案,因為:

  • Cloud Run 本身就是公開 HTTPS
  • 標註圖片只需要短暫存在(5 分鐘 TTL)
  • 不需要額外設定 GCS bucket

3. Thinking 是一把雙刃劍

gemini-2.5-flash 預設啟用 thinking,這對複雜推理有幫助,但對簡單的圖片描述反而是負擔:

  • 消耗 max_output_tokens 額度
  • 增加延遲
  • 回覆可能被截斷

原則:簡單任務關閉 thinking(thinkingBudget=0),複雜的 Agentic Vision 才開啟。

4. 狀態管理的取捨

Agentic Vision 需要兩步互動(選模式 → 輸入指令),這引入了狀態管理:

image_temp_store: Dict[str, bytes] = {}       # 圖片暫存
pending_agentic_vision: Dict[str, bool] = {}   # 等待指令

用 in-memory dict 最簡單,但有個風險:Cloud Run 可能在兩次請求之間重啟。對於個人 Bot 這是可接受的,但如果要做成產品級服務,應該改用 Redis 或 Firestore。

本文授權轉載自Evan部落格,原文標題為:[Gemini 3 Flash] 在 LINE Bot 中實現 Agentic Vision:讓 AI 主動標註圖片甚至做更多 AI 處理

往下滑看下一篇文章
從 CDP 到 Agent,beBit TECH 如何打造懂企業、懂行銷的 AI 代理人?
從 CDP 到 Agent,beBit TECH 如何打造懂企業、懂行銷的 AI 代理人?

當眾多 AI 新創仍將焦點放在追求更強大的模型能力,或尋找下一個成功案例時,beBit TECH 已開始思考另一個層次的問題:如何打造一家能夠持續成長、且具備規模化複製能力的企業級 AI 公司。

近期,beBit TECH 完成與日本 beBit 集團的戰略分拆,不僅確立台灣為全球總部,也同步完成逾億元首輪募資,並預計不久後啟動在台 IPO 規劃。然而,真正值得市場與投資人關注的,不單是分拆或募資本身,而是這一連串布局背後所釋放的訊號—— beBit TECH 已正式跨越產品與市場驗證階段,邁向規模化擴張的新成長階段。

而產品、產業應用及海外市場,就是驅動 beBit TECH 下一階段成長的三大引擎。beBit TECH 創辦人暨執行長陳鼎文表示, 未來將聚焦三大布局,包括持續深化企業級 AI 產品、擴大跨產業應用版圖,以及拓展日本與東南亞等海外市場。首先,在產品面,將持續強化 AgentBit 智慧代理人的能力,結合 OmniSegment CDP 的數據底座與產業 Know-how,打造真正懂企業、懂行銷的 AI Agent。

beBit TECH 創辦人暨執行長陳鼎文
beBit TECH 創辦人暨執行長陳鼎文
圖/ 數位時代

產品布局:從理解數據的大腦,進化為「自主執行」的虛擬員工

陳鼎文進一步說明,近年企業紛紛導入各種 AI 或 AI Agent 應用,希望提升營運效率與員工生產力,但 AI 能否真正創造價值,關鍵並不在模型本身,而是資料品質。若企業的會員資料分散、格式不一致,甚至充滿錯誤,即使導入再先進的 AI 模型,也難以產出可靠的分析與決策。換句話說,企業唯有先建立穩固的數據底座,才能真正發揮代理式 AI 的價值。

正因如此,beBit TECH 選擇將 AgentBit 建立在 OmniSegment CDP 上,形成以 CDP 為數據底座、Agent 為執行核心的新一代企業級 AI 架構。陳鼎文形容,OmniSegment 就像一顆智慧大腦,可以完成跨通路數據整合,並進行資料清理與標準化,而 AgentBit 則是智慧代理人,它可以根據 CDP 大腦所提供的數據做出決策,自主完成受眾分群、內容生成、活動執行、成效監測與優化建議等行銷工作。

更重要的是,OmniSegment 多年來已累積眾多不同產業的實戰經驗與行銷 Know-how,使 AgentBit 不只具備內容生成的能力,更理解不同產業的會員經營模式與行銷邏輯,能依據企業情境挑選最適合的受眾、生成更精準的溝通內容,並持續優化策略。

以中秋節的節慶行銷活動為例,當過去行銷人員必須自行篩選受眾、撰寫文案,再依據活動成效反覆調整策略,整個促銷活動期間都要處於備戰狀態;如今,只要以自然語言輸入活動目標,AgentBit 即可串接 OmniSegment 的數據,自主完成後續工作。當行銷成效未達預期目標時,它還會持續分析結果、修正策略,直到找出轉換率更高的路徑為止,真正讓企業累積的數據,轉化為持續創造營收的智慧資產。

讓數據自己跑出營收!AgentBit 結合 CDP 乾淨數據與實戰 Know-how,只需輸入指令即
讓數據自己跑出營收!AgentBit 結合 CDP 乾淨數據與實戰 Know-how,只需輸入指令即可全自動執行行銷並自主優化成效,打造不斷線的 AI 營收引擎。
圖/ beBit TECH

市場布局:以電商護城河,打造 OMO 與金融雙成長引擎

其次,在產業應用面,beBit TECH 將持續擴大在實體零售、生活服務與金融業的市場布局。「電商是 beBit TECH 的核心基本盤,而實體零售與金融業則是我們下一波的成長引擎。」陳鼎文說。

beBit TECH 成軍初期聚焦於品牌電商,透過客戶數據平台 OmniSegment CDP 協助客戶整合並應用手中的第一方數據,提升會員價值與營收。至今,beBit TECH 已累積上百家品牌電商客戶,並在不同產業情境與應用需求中,持續驗證及優化 OmniSegment CDP 的產品能力。這些豐富的導入經驗,讓 beBit TECH 更深入掌握企業在數據應用上的實際痛點,進而推動產品與 AI 模型持續迭代成熟, 築起一條競業難以跨越的數據護城河。

有了電商戰場的成功經驗,beBit TECH 開始將目光投向線下與實體場域,運用 OmniSegment CDP 協助零售品牌打通線上與線下的會員數據,真正做到跨通路的數據即時整合,讓 OMO 經營不再只是口號。

過去一年,beBit TECH 更成功將觸角延伸至同樣擁有龐大數據的金融業,包括國際保險集團及指標金控,皆已導入 OmniSegment CDP,由系統依據客戶在不同通路的行為,即時判定其意圖並推薦最合適的金融產品。這意味著金融業也能運用電商「千人千面、即時觸及」的行銷模式,一改過去亂槍打鳥、只能照著名單一一撥電話的傳統做法。

「金融業的 AI 個人化行銷現在才剛開始,beBit TECH 能與多家指標性金融客戶合作,代表我們的數據安全和隱私合規性,已經通過了市場上最嚴格的標準,這對於未來跨足其他產業有非常大的幫助。」陳鼎文強調。

海外布局:立足台灣,加速拓展日本與東南亞市場

第三,在海外發展上,則是加速拓展日本與東南亞市場。陳鼎文表示,相較於多數台灣新創進軍日本市場,往往需要一、兩年才能站穩腳步,beBit TECH 憑藉與日本 beBit 集團的緊密合作,已經成功「逆向」打回日本市場,短短兩年多便累積超過 30 家大型企業客戶,涵蓋航空、餐飲集團等不同產業,未來日本仍將是 beBit TECH 拓展海外營收的核心關鍵。

除了日本之外,beBit TECH 也將東南亞視為下一階段的戰略要地。一方面,看好當地人口結構年輕與數位應用快速成長所帶來的商機;另一方面,隨著全球 AI 人才競爭白熱化,東南亞更是重要的人才庫,有助於 beBit TECH 持續推動產品全球化與技術迭代。

「我們希望將 beBit TECH 打造為『亞太區企業級 AI 的領導品牌』。」陳鼎文感性表示,這也是團隊確立將全球總部設在台灣的初衷。未來,beBit TECH 將持續以台灣為核心,向外輻射至日本、東南亞、甚至更廣泛的國際市場,讓世界看見來自台灣的 AI 技術實力與商業價值。

從台灣品牌電商起家,一路跨足實體、金融、日本與東南亞市場,beBit TECH 想做的不只是一套好用的 AI 工具,而是一個能讓企業把數據轉化為營收的企業級 AI 平台。當全球 AI 競爭開始從模型能力,轉向商業化與規模化,這家台灣新創正用清晰的策略布局,寫下屬於自己的下一個成長故事。

登入數位時代會員

開啟專屬自己的主題內容,

每日推播重點文章

閱讀會員專屬文章

請先登入數位時代會員

看更多獨享內容

請先登入數位時代會員

開啟收藏文章功能,

請先登入數位時代會員

開啟訂閱文章分類功能,

請先登入數位時代會員

我還不是會員, 註冊去!
追蹤我們
台達電全解讀
© 2026 Business Next Media Corp. All Rights Reserved. 本網站內容未經允許,不得轉載。
106 台北市大安區光復南路102號9樓