iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
自我挑戰組

Data Engineer 下班後偷學 AI系列 第 7

零資料保留 Zero Data Retention (ZDR)

  • 分享至 

  • xImage
  •  

今天在公司維護現有的 LLM API 的時候,發現帶上 previous_response_id 後竟然報錯誤 400 - Zero Data Retention,這是什麼東西?

零資料保留

零資料保留 ZDR 指的是 Model Provider 在收到請求後,只在記憶體中處理,處理完就直接刪掉,確保機密資料不會被拿去訓練或用做其他用途。ZDR 是符合資格的組織經核准、設定後啟用的,通常是使用企業 end point 時才會遇到。

OpenAI Responses API

以 OpenAI 的 Responses API 來說,正常情況下 previous_response_id 絕對是比較推薦的作法,但當組織啟用 ZDR 或是在 request 中主動設定 store=False 時,模型會進入 Stateless 模式,這時候我們只能自己管理 content。
為了讓我們在這種情況下仍能接續前次對話,Response 裡會多回傳 encrypted_content,這些 encrypted_content 是 OpenAI 加密過的 Reasoning 過程,只要原樣保存,並在下一輪 Request 中重新帶回,就能讓模型延續上一輪的推理脈絡。

First Request

準備一個 history 來儲存所有歷史對話。

history = [
    {
        "role": "user",
        "content": "跟你說個祕密,我好想離職。"
    }
]

first_response = client.responses.create(
    model=MODEL,
    input=history,
    store=False,
    reasoning={
        "context": "current_turn"
    }
)

print(first_response.output_text)
# 謝謝你把這個祕密告訴我。想離職不代表你不夠努力,很多時候只是累積太久、環境真的不適合了。
# ...

印出 first_response.output 能看到裡面有一段非常長的:

{ 
  "type": "reasoning", 
  "encrypted_content": "gAAAAABmX..."
}

Second Request

根據 issue#3008,我們直接把所有 output 全部塞進 history 就好,也不用做什麼轉換。

history.extend(first_response.output)
history.append(
    {
        "role": "user",
        "content": "剛剛我跟你說的秘密是什麼?"
    }
)

second_response = client.responses.create(
    model=MODEL,
    input=history,
    store=False,
    reasoning={
        "context": "all_turns"
    }
)

print(second_response.output_text)
# 你剛剛說的祕密是:「你很想離職。」

ZDR in OpenRouter

我們也可以在 OpenRouter 設定 ZDR,但不是所有模型都可以用 ZDR,要找模型的 Provider 旁邊有綠色盾牌的:
https://ithelp.ithome.com.tw/upload/images/20260922/20138939vtqtXppNaG.png

程式範例:

import os
from dotenv import load_dotenv
import requests
import json

load_dotenv()
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
MODEL="inclusionai/ling-3.0-flash-fin:free"

# ========== First Request ==========
history = [
            {
            "role": "user",
            "content": "跟你說個祕密,我好想離職。"
            }
        ]

response = requests.post(
    url="https://openrouter.ai/api/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {OPENROUTER_API_KEY}",
        "Content-Type": "application/json",
    },
    data=json.dumps({
        "model": MODEL,
        "provider": {
            "zdr": True,
        },
        "messages": history
    })
)

data = response.json()
assistant_message = data["choices"][0]["message"]
print(assistant_message["content"])
# 嗯,你願意這樣說出來,代表你對我有一定程度的信任 😊
# ...

# ========== Second Request ==========
history.append(assistant_message)
history.append({
    "role": "user",
    "content": "剛剛我跟你說的秘密是什麼?",
})

response = requests.post(
    url="https://openrouter.ai/api/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {OPENROUTER_API_KEY}",
        "Content-Type": "application/json",
    },
    data=json.dumps({
        "model": MODEL,
        "provider": {
            "zdr": True,
        },
        "messages": history
    })
)

data = response.json()
assistant_message = data["choices"][0]["message"]
print(assistant_message["content"])
# 你剛剛跟我說的秘密是:
# 
# > **「我好想離職。」**

每日一句

我也想把工作忘了。


上一篇
用 LangGraph 幫 Pokémon Agent 畫路
下一篇
RAG 還有必要嗎?
系列文
Data Engineer 下班後偷學 AI8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言