Applied AI School
v0 · 規劃中
Anthropic

Temperature 與 Structured Outputs

用 temperature 控制隨機性;用 prefill + stop_sequence 穩穩拿到 JSON / 結構化資料。

TL;DR

  • temperature 是 0–1 的「創意度」旋鈕。0 趨近 deterministic、1 最發散
  • 想穩拿 JSON:prefill 一段 assistant 訊息開頭 + 設 stop_sequence 收尾
  • 真的要鐵口直斷的 JSON:用 tool use 的 schema 機制(後面章節)

一個情境:從 email 抽欄位

「這封報名信寫了報名人姓名、活動日期、繳費金額——幫我抽出來,回 JSON 給我寫進 DB。」

直覺寫法:

add_user(messages, f"從這封信抽出 name、date、amount,回 JSON:\n\n{email}")
res = chat(messages)
print(res.content[0].text)

實際拿到:

這是抽取結果:

```json
{
  "name": "陳小明",
  "date": "2026-05-10",
  "amount": 1500
}
```

如果還需要其他欄位請告訴我。

JSON 是對的,但包在 markdown code fence 裡 + 前後有解釋文字json.loads() 直接吃下去會炸。Claude「太熱心」是這個任務的反效果。

Temperature:第一個調的旋鈕

Temperature 控制 model 在「下個 token 機率分佈」上的銳利度:

temperature行為適用
0.0幾乎只挑機率最高的——每次跑結果接近一樣抽欄位、分類、code、事實題
0.3略有變化,但仍偏 deterministic摘要、客服回信
0.7平衡一般 chat、教學內容
1.0(API 預設)最發散,常見較稀有的選擇brainstorm、創意寫作、笑話

「temperature=0 就 deterministic」是常見誤解。Anthropic API 在 0 也不保證每次結果一樣(內部仍有少量隨機性,特別是平手的 token),但會「很接近」。

res = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    temperature=0,        # ← 結構化任務通常設 0
    messages=messages,
)

三招拿到乾淨 JSON

招 1:prompt 寫死格式

最弱但最簡單:

add_user(messages, """從信件抽欄位,**只回 JSON**,不要任何解釋或 markdown。
格式:{"name": str, "date": "YYYY-MM-DD", "amount": int}

信件:
""" + email)

成功率取決於 model;Sonnet 4.6 大致穩,Haiku 偶爾會包 markdown。不是首選

招 2:Prefill + stop_sequence(穩很多)

關鍵手法:用一個 assistant message 假裝 Claude 已經開始講了。它就會「順著講下去」。

messages = [
    {"role": "user", "content": f"從信件抽 name、date、amount,回 JSON。信件:\n{email}"},
    {"role": "assistant", "content": "{"},  # ← prefill 一個開頭
]

res = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    temperature=0,
    messages=messages,
    stop_sequences=["}"],  # ← 看到 "}" 就停(簡單 schema 用)
)

raw = "{" + res.content[0].text + "}"  # 補回 prefill 開頭跟結尾
data = json.loads(raw)

兩個容易踩到的點:

  1. Prefill 的字不會出現在 content[0].text——Claude 是「順著 prefill 繼續講」,所以拿回來的 text 不含開頭的 {,要自己補。
  2. Stop token 也不在 response 裡——stop_sequences 命中時,命中的字串本身不會回給你(API 行為),所以結尾的 } 也要自己補。stop_reason 會是 stop_sequencestop_sequence 欄位告訴你命中哪一個。

原理:Claude 看到 assistant: "{" 會以為自己已經開始寫 JSON 了,不會再加 markdown fence、不會加解釋文字

招 3:Tool use schema(最穩)

Anthropic 後面章節會講的 tool use 機制可以強制 Claude 輸出符合 JSON schema 的結果。tool call 本來就是 schema-validated。

預告寫法(細節見 tool use 章):

tools = [{
    "name": "extract_email",
    "description": "從信件抽欄位",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
            "amount": {"type": "integer"},
        },
        "required": ["name", "date", "amount"],
    },
}]

API 確保 Claude 回的是 valid JSON 符合 schema。production 抽欄位首選

三招怎麼選

任務用哪招
一次性 prototyping招 1(prompt 寫死)
簡單扁平 schema、跑量大招 2(prefill + stop)
巢狀結構、production、不能 fail招 3(tool schema)

接下來

Section 1 到這裡完整把 request、multi-turn、streaming、temperature、結構化輸出都串起來了。下一章換個角度——怎麼客觀衡量 prompt 改得好不好。沒 eval 的 prompt engineering 就是猜,先把工程基礎建好。