Citations
讓 Claude 把答案的「每句話來自原文哪段」結構化標註出來——比叫 model 「請引用」可靠,是 API 層級保證的格式。
TL;DR
citations: {enabled: true}加在 document block 裡,response 的 text block 會自帶citations陣列- 每筆 citation 包
cited_text(原文片段)+start_page_number/end_page_number(PDF)或 char index(純文字) - 比 prompt 寫「請引用頁碼」可靠很多——API 層級保證格式,不會幻覺出不存在的頁碼
一個情境:法務 AI 助手要敢被質疑
你做了一個合約 QA 工具:user 上傳合約 PDF,問「違約金條款是什麼?」Claude 回「違約金為合約金額的 20%」。
法務看到只會回你一句話:「根據哪一條?哪一頁?字面怎麼寫?」 沒辦法說清楚的話,整個工具沒人敢用——做合約決策不能靠 LLM 一句話。
Citations 就是這個問題的官方答案。response 不只是文字,每段陳述都附 source location:哪份文件、哪幾頁、原文哪一段支持這個說法。
怎麼開
在 document block 多加兩個欄位:title(顯示用名稱)+ citations: {enabled: true}。
import base64
with open("contract.pdf", "rb") as f:
pdf_b64 = base64.standard_b64encode(f.read()).decode("utf-8")
messages = [{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": pdf_b64,
},
"title": "供應合約-2026.pdf", # ← 顯示用
"citations": {"enabled": True}, # ← 開關
},
{"type": "text", "text": "違約金條款是什麼?依據哪一條?"},
],
}]
Response 結構:text block 多一個 citations 欄位
開了 citations 之後 res.content 結構變了。text block 不再是單純的字串,而是句子被切片、每片帶 citation:
[
{"type": "text",
"text": "根據合約第 12 條,違約金為合約總金額的 20%。",
"citations": [
{
"type": "page_location",
"cited_text": "若任一方未能履行本合約義務,違約方應支付合約總金額之 20% 作為違約金⋯⋯",
"document_index": 0,
"document_title": "供應合約-2026.pdf",
"start_page_number": 4,
"end_page_number": 4,
}
]},
{"type": "text",
"text": "另須於 30 日內補正⋯⋯",
"citations": [...]
},
]
關鍵欄位:
| 欄位 | 意思 |
|---|---|
cited_text | 原文「字面字串」——逐字從你的文件來 |
document_index | 第幾份文件(多份的時候 0、1、2⋯) |
document_title | 你給的 title |
start_page_number / end_page_number | PDF 頁碼範圍 |
純文字 source 改用 char_location,給 start_char_index / end_char_index 而不是頁碼。
純文字也能 cite
不一定要 PDF——把段落塞進 document block 即可:
{
"type": "document",
"source": {
"type": "text",
"media_type": "text/plain",
"data": article_text,
},
"title": "earth_article",
"citations": {"enabled": True},
}
回的 citation 變成 citation_char_location,告訴你 cited_text 在原文的字元 index——拿來在 UI highlight 那段文字超直接。
為什麼比 prompt 寫「請引用」可靠
直覺寫法:
請依據文件回答,並在每段後面附上頁碼,例如「(p.4)」。
問題:
- 頁碼有時候是幻覺——model 會自己編一個聽起來合理的頁碼
- 格式不穩——時而「(p.4)」、時而「第 4 頁」、時而忘了寫
- 拆不開答案跟引用——要 regex parse 才知道哪句對哪段
Citations API 是 server-side enforce:cited_text 必定是文件裡真的存在的字串,頁碼必定對應實際的頁碼。不需要解析、不會幻覺、結構穩定。
prompt 寫「請引用」 → 字串裡塞 (p.4),要正則解,可能幻覺
citations API → 結構化 JSON,server 保證 cited_text 來自原文
UI 怎麼接
兩種常見呈現——句子尾巴掛角標 hover 看 cited_text,或左右雙欄(左答案、右原文 highlight)。後者對長 PDF 特別有用,user 直接看到原始合約哪一段被 cite。
跟 RAG 一起用
RAG 那章 講過:embedding 把文件切片、retrieve 相關幾段、塞進 prompt 給 Claude。Citations 正好補上 RAG 缺的最後一塊:不只 retrieve 對的段,還能讓 user 驗證 model 真的有用那段。
[檢索 top-k 段] → [塞進 document block 並 enable citations]
↓
[Claude 答案 + cited_text 對到 retrieved 段]
↓
[UI 顯示原文片段,用戶可點開 source]
很多 production RAG 系統會把 citations 跟 retrieved chunks 對映回原始文件位置(page、URL、段落 anchor),做出**「答案 → 引文 → 原始來源」**的完整 trace。
多份文件一起 cite
messages 裡可以塞多個 document block,每個給一個 title——Claude 自動追蹤是哪份的哪頁:
content = [
{"type": "document", "source": {...}, "title": "合約 A", "citations": {"enabled": True}},
{"type": "document", "source": {...}, "title": "合約 B", "citations": {"enabled": True}},
{"type": "document", "source": {...}, "title": "公司政策", "citations": {"enabled": True}},
{"type": "text", "text": "比較三份文件的違約金條款。"},
]
response 的 citation 用 document_index(0、1、2)+ document_title 標明出處。
什麼時候開、什麼時候不開
| 情境 | 開? |
|---|---|
| 法務 / 醫療 / 金融文件 QA | 必開——一定要可驗證 |
| RAG-based 客服系統 | 開——user 看了更信 |
| 一般聊天、創意寫作 | 不必——沒有「source」這個概念 |
| 純摘要任務 | 看情況——要可追溯就開 |
計費
Citations 本身不另外收費,但 model 會被引導「多生 quote 字串」,所以 output token 通常會比沒開時多一點。實測差異不大、可忽略;真要省可以在 prompt 寫「精簡引用」。
接下來
下一篇看 Section 6 最後兩個 server-side 能力:code execution + Files API——讓 Claude 在 Anthropic 的 Python sandbox 裡跑 code、產生圖表,然後用 Files API 在 multi-turn 裡共享檔案。

