# Claude API 中的 Agent Skills：如何不使用 Claude Code 就能使用現成技能

> 如何將現成的 pptx 技能連接至 Claude API：container.skills、程式碼執行工具、檢查回應，以及透過 Files API 下載簡報。

Source: https://ailoot.ai/blog/zh-hant-tw/claude-api-agent-skills/
Canonical: https://ailoot.ai/blog/zh-hant-tw/claude-api-agent-skills/
Language: zh-Hant-TW
Publisher: Ailoot (https://ailoot.ai/)
Translation: guide-039
Revision: sha256-6052bd8b659017e386a7c51f52e883f7811054ea09cf6a899e344b28fc7fc278


<div class="aside" data-semantic="key-takeaway" role="note" aria-label="本節重點">

重點

文件用的現成 Agent Skills 可以透過直接呼叫 Claude API 使用：在 `container.skills` 中指定技能，並啟用 `code_execution`。第一次提出請求時，請使用官方範例中的相容模型與工具組合。生成的檔案需另外使用其 `file_id` 下載；範例使用相同的 API 金鑰提出請求並下載檔案。

</div>



您可以在 [Ailoot 文件](https://ailoot.ai/docs/)中找到更多指引。

## 透過 Claude API 使用 Agent Skills 需要準備什麼？

本指南說明如何從程式直接呼叫 API，而不是在 Claude Code 中安裝技能。您需要 Claude API 金鑰、所選模型的使用權限，以及 Python 3。以下程式碼使用 Python 標準函式庫和 HTTP，因此不受您安裝的 SDK 版本影響。金鑰透過 `ANTHROPIC_API_KEY` 環境變數傳入；請勿將金鑰放在程式文字或對話中。

API 提供 Anthropic 的現成技能：簡報用的 `pptx`、試算表用的 `xlsx`、Word 文件用的 `docx`，以及 PDF 用的 `pdf`。這些技能透過 `type: "anthropic"` 連接。本指南使用現成技能，不會上傳自訂技能。

撰寫本資料時開啟的[官方快速入門指南](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/quickstart.md)，使用的是 `claude-opus-5-5` 與 `code_execution_20260521` 的組合。以下範例也使用這組搭配。此範例已對照文件檢查，並非付費 API 執行結果的報告。

## 需要哪些 Beta 標頭

範例遵循快速入門指南目前的 HTTP 契約：標頭為 `x-api-key`、`anthropic-version: 2023-06-01` 和 `content-type: application/json`；不會傳送 `anthropic-beta`。請勿混用不同版本文件中的模型、呼叫方式和回應格式。

[Files API 文件](https://platform.claude.com/docs/en/build-with-claude/files.md)也指出，API 已不再處於 Beta 階段。舊的 `files-api-2025-04-14` 標頭會保留舊版回應格式；移除該標頭則會切換為目前的格式。因此，使用 `client.beta.files` 的舊範例不能直接與新範例混用。

本指南不會將既有服務從舊版 Beta 契約遷移。如果您已經有這類服務，請先檢查它使用的標頭和回應格式。SDK 方法名稱中有 `beta` 一字，本身並不足以判斷；Files API 文件另有說明不同 SDK 版本的行為。





## 建立簡報並下載檔案

此範例會送出一項建立五張再生能源主題投影片的任務，將完整回應儲存到 `skill-response.json`，接著擷取生成檔案的 ID。它不會從模型回應中取得儲存路徑，而是將檔案存到新建的本機資料夾 `skill-output`。如果該資料夾已存在，程式就會停止，以免覆寫先前的結果。 資料夾在 API 呼叫之前就會建立，因此呼叫失敗後也會留下。再次執行前，先檢查並保留該次嘗試；不要只為了讓重跑通過就刪除資料夾。

```python
import json
import os
from pathlib import Path
from urllib.error import HTTPError
from urllib.request import Request, urlopen

API = "https://api.anthropic.com/v1"
KEY = os.environ["ANTHROPIC_API_KEY"]
HEADERS = {
    "x-api-key": KEY,
    "anthropic-version": "2023-06-01",
    "content-type": "application/json",
}

def request(path, payload=None, binary=False):
    data = None if payload is None else json.dumps(payload).encode("utf-8")
    req = Request(API + path, data=data, headers=HEADERS)
    try:
        with urlopen(req, timeout=600) as result:
            body = result.read()
    except HTTPError as error:
        try:
            details = json.loads(error.read().decode("utf-8"))
        except (ValueError, UnicodeError):
            details = {}
        info = details.get("error", {})
        request_id = error.headers.get("request-id") or details.get("request_id")
        diagnostic = {
            "http_status": error.code,
            "request_id": request_id,
            "error_type": info.get("type"),
            "message": str(info.get("message", "No JSON error message")).replace(KEY, "[REDACTED]")[:1000],
        }
        (out / "skill-error.json").write_text(
            json.dumps(diagnostic, ensure_ascii=False, indent=2), encoding="utf-8"
        )
        raise RuntimeError(
            f"Claude API HTTP {error.code}; request_id={request_id}; inspect skill-error.json"
        ) from None
    return body if binary else json.loads(body)

out = Path("skill-output")
out.mkdir(exist_ok=False)
response = request("/messages", {
    "model": "claude-opus-5-5",
    "max_tokens": 16000,
    "container": {
        "skills": [{"type": "anthropic", "skill_id": "pptx", "version": "latest"}]
    },
    "messages": [{
        "role": "user",
        "content": "請以我偏好的語言製作一份包含 5 張投影片、主題為再生能源的簡報。",
    }],
    "tools": [{"type": "code_execution_20260521", "name": "code_execution"}],
})
(out / "skill-response.json").write_text(
    json.dumps(response, ensure_ascii=False, indent=2), encoding="utf-8"
)
print("stop_reason:", response.get("stop_reason"))

file_ids = []
for block in response["content"]:
    if block["type"] == "bash_code_execution_tool_result":
        result = block["content"]
        if result["type"] == "bash_code_execution_result":
            for item in result["content"]:
                file_id = item.get("file_id")
                if file_id and file_id not in file_ids:
                    file_ids.append(file_id)
if not file_ids:
    raise RuntimeError("No generated file_id; inspect skill-response.json")

for index, file_id in enumerate(file_ids, start=1):
    from urllib.parse import quote
    file_path = "/files/" + quote(file_id, safe="")
    metadata = request(file_path)
    if metadata.get("downloadable") is not True:
        raise RuntimeError("This file cannot be downloaded through Files API")
    target = out / f"result-{index}.pptx"
    target.write_bytes(request(file_path + "/content", binary=True))
    print("Saved:", target)
```

`result-1.pptx` 等名稱是為這項簡報任務選用的。檔案副檔名無法證明檔案內容；請開啟下載的文件，檢查其格式、投影片數量和文字。不要只憑 HTTP 200 或出現 `file_id` 就認定結果成功。

程式會輸出 `stop_reason`，也就是回應停止的原因，並儲存完整回應供檢查。它不會繼續對話，也不會自動重複付費請求。下載到檔案不代表整項任務已完成：在決定是否需要再次提出請求前，請檢查儲存的回應和文件本身。

若嘗試失敗，請檢查是否有 `skill-error.json`。其中記錄 HTTP 狀態、供應商提供的請求 ID，以及已移除設定金鑰並限制長度的供應商錯誤訊息。分享前仍須檢查是否含有其他私人資料。請將驗證、權限／模型、帳務上限與請求格式錯誤，對照[官方錯誤參考文件](https://platform.claude.com/docs/en/api/errors)，不要認為所有失敗都需要重新付費生成。

如果 `skill-response.json` 已有生成的 `file_id`，只有下載失敗，請保留回應，以相同且獲授權的工作區權限檢查中繼資料及下載步驟。不要為了下載既有輸出就重跑生成區塊。若請求結果不明，先保留請求 ID 並查清狀態，再送出另一個生成請求。只有確認需要新生成後，才將本機輸出行改為未使用的路徑，例如 `out = Path("skill-output-attempt-2")`，並保留 `exist_ok=False`。新資料夾能避免覆寫，不能防止 API 重複收費。

## 需要哪些檔案權限

Files API 會將檔案關聯至工作區，而非您應用程式中的個別使用者或對話。根據文件說明，任何具有該工作區存取權的 API 金鑰，都能存取上傳到其中的檔案。範例使用相同金鑰進行下載與生成。請勿接受終端使用者或其他不受信任來源提供的 `file_id`。請將這些 ID 儲存在伺服器上，並在自己的應用程式中維護使用者與其檔案之間的對應關係。

請另外檢查檔案中繼資料：其中必須包含 `downloadable: true`。文件允許下載由技能或程式碼執行工具生成的檔案；您上傳的檔案則會是 `downloadable: false`，嘗試下載時會回傳 400。工作區存取權和下載特定檔案的權限是兩項不同的要求。

對於多使用者應用程式，Files API 文件建議為每位客戶使用獨立工作區，作為檔案隔離邊界。這項建議只針對檔案；未檢查相關 API 前，不要將其延伸到所有實體和權限。

## 現成技能與自訂技能

現成技能的 ID 為 `pptx`、`xlsx`、`docx` 和 `pdf`。在[技能清單參考文件](https://platform.claude.com/docs/en/api/skills/list.md)中，`custom` 來源被描述為工作區專用，而 `anthropic` 則是共用且唯讀。

第一個範例中的 `version: "latest"` 代表該技能最新發布的版本。若要建立可重現的整合，請留意所選版本可能會變動；若要切換到固定版本，必須選擇您所用技能的一個既有版本，而非使用範例中虛構的 ID。

## 限制與下一步

此範例只涵蓋使用現成技能建立簡報並下載。這裡尚未測試上傳或刪除自訂技能，以及存取第三方服務。這些工作需要另外檢查相關 API。

若您的任務涉及 Claude 介面中的檔案，請參閱另一篇指南：[如何將檔案上傳至 Claude](https://ailoot.ai/blog/zh-hant-tw/claude-file-upload/)。若要直接呼叫 API，請參閱[如何計算 API Token 使用量](https://ailoot.ai/blog/zh-hant-tw/api-token-usage-calculation/)。若要在終端機代理程式中工作，請閱讀[如何選擇 Claude Code 技能](https://ailoot.ai/blog/zh-hant-tw/choose-claude-code-skills/)：它們的連接方式不同。

初步檢查只需使用一個現成的 `pptx` 技能：檢查回應、下載允許下載的檔案，並開啟檔案。完成這項檢查後，再新增自訂技能和客戶間的存取隔離。





準備好之後，來認識 [Ailoot](https://ailoot.ai/)。

## 常見問題：Claude API 中的 Agent Skills：如何不使用 Claude Code 就能使用現成技能

### 為什麼拿到 file_id 還不能宣告簡報完成？

ID 只代表有檔案回傳，不能證明它是可用簡報。請確認中繼資料為 `downloadable: true`，透過工作區權限下載，再開啟檢查檔案格式、投影片數量與文字。

### Claude Files API 上傳的任何檔案都可以下載嗎？

不是。指南區分標示 `downloadable: true` 的生成檔案，與標示 `downloadable: false` 的上傳檔案。工作區存取與特定檔案的下載權限需分開確認，不要接受終端使用者任意提供的檔案 ID。


## Ailoot · 公司及其專案組合

Ailoot以累積的營運經驗、廣大的客戶群、穩定的服務及持續的KPI管理為基礎。

公司及其專案組合：數百萬客戶，每月銷售額達數十億。

Ailoot將這些營運經驗用於API存取，讓客戶的產品、代理、應用程式及自動化流程使用AI功能。
