Claude API Skills: готовые навыки docx, xlsx и pptx
MarkdownПодключение готового навыка pptx к Claude API: настройка container.skills и code_execution, проверка ответа и скачивание презентации через Files API.
Читать статью полностью
Коротко о главном
Готовый Agent Skill для работы с документами можно использовать через прямой вызов Claude API: добавьте навык в container.skills и активируйте code_execution. Для первого запроса выберите совместимую модель и инструмент из официального примера. Созданный документ скачивается отдельно по file_id; в этом примере один API-ключ служит и для запроса, и для загрузки файла.
Другие инструкции собраны в документации Ailoot.
Что потребуется
Материал посвящён прямому обращению к API из программы, а не установке навыка в Claude Code. Подготовьте API-ключ Claude, доступ к выбранной модели и Python 3. Приведённый пример использует встроенные средства Python для HTTP-запросов, поэтому ему не нужна конкретная версия SDK. Ключ задаётся в переменной окружения ANTHROPIC_API_KEY; не записывайте его в исходный код или сообщения.
Anthropic предоставляет готовые навыки для API: pptx для презентаций, xlsx для электронных таблиц, docx для документов Word и pdf для файлов PDF. Для подключения используется тип "anthropic". Ниже применяется готовый навык, без загрузки собственного.
В официальном quickstart, изученном при подготовке этого материала, приведено сочетание claude-opus-5-5 и code_execution_20260521. Ниже используется именно оно. Это пример, сверенный с документацией, а не свидетельство выполненного платного API-вызова.
Нужные beta-заголовки
В HTTP-примере сохранены параметры текущего контракта из quickstart: x-api-key, anthropic-version: 2023-06-01 и content-type: application/json. Заголовок anthropic-beta не добавляется. Не смешивайте модель, формат ответа и способ вызова из разных поколений документации.
Согласно документации Files API, этот API вышел из beta. Устаревший заголовок files-api-2025-04-14 оставляет прежние форматы ответов; если его убрать, используются актуальные форматы. Поэтому старый вызов через client.beta.files не следует без изменений сочетать с новым контрактом.
Здесь речь не идёт о переносе уже работающего сервиса со старого beta-контракта. Если такой сервис у вас есть, сперва проверьте его заголовки и структуру ответов. Наличие слова beta в названии метода SDK само по себе ничего не решает: документация Files API отдельно описывает различия между версиями SDK.
Создайте презентацию и скачайте её
В примере API получает задание подготовить пять слайдов о возобновляемой энергетике. Весь ответ сохраняется в skill-response.json, после чего программа находит идентификаторы созданных файлов. Путь для сохранения не берётся из ответа модели: файлы записываются в новую локальную папку skill-output. Если эта папка уже создана, выполнение прекращается, чтобы не затереть имеющиеся результаты. Папка создаётся до запроса API, поэтому остаётся и после неудачного вызова. Сначала изучите и сохраните эту попытку; не удаляйте её только для того, чтобы повторный запуск прошёл.
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": "Create a presentation about renewable energy with 5 slides in my preferred language.",
}],
"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-статус, идентификатор запроса, если он был передан, и ограниченное сообщение провайдера с удалённым значением настроенного API-ключа. Перед передачей другим людям проверьте сообщение на иные приватные данные. Сопоставляйте ошибки аутентификации, прав или модели, платёжных лимитов и формата запроса с официальным справочником ошибок; не всякая ошибка требует новой платной генерации.
Если в skill-response.json уже есть созданные file_id, а сбой произошёл при скачивании, сохраните ответ и проверяйте метаданные и загрузку файла с тем же разрешённым доступом к workspace. Не запускайте генерацию заново ради существующего результата. При неизвестном исходе запроса сохраните его ID и выясните статус до новой генерации. Только если новая генерация действительно нужна, задайте свободный путь, например out = Path("skill-output-attempt-2"), сохранив exist_ok=False. Новая папка предотвращает локальную перезапись, но сама по себе не предотвращает повторный платёж. FileExistsError — локальная коллизия папки, а не ответ API.
Какие разрешения требуются для работы с файлами
Files API связывает файлы с workspace — рабочим пространством, — а не с пользователем вашего приложения или конкретной перепиской. Как сказано в документации, доступ к файлам этого workspace может получить любой API-ключ, которому разрешено работать с ним. Для генерации и скачивания в примере применяется один и тот же ключ. Не принимайте file_id от конечного пользователя или из другого недоверенного источника. Храните идентификаторы на сервере, а связь между пользователями и их файлами учитывайте в собственном приложении.
Проверьте и метаданные файла: в них должно быть downloadable: true. Документация допускает скачивание файлов, созданных навыками или инструментом выполнения кода. Для загруженных вами файлов значение downloadable: false, и попытка получить такой файл вернёт ошибку 400. Доступ к workspace сам по себе не гарантирует возможности скачать каждый файл.
Для приложения с несколькими клиентами документация Files API советует выделять каждому клиенту отдельный workspace, чтобы разделять доступ к файлам. Это рекомендация касается именно файлов; не распространяйте её на другие сущности и разрешения без проверки документации соответствующего API.
Готовый навык и пользовательский навык
Для готовых навыков предусмотрены идентификаторы pptx, xlsx, docx и pdf. В справке по списку навыков указано, что источник custom означает навык, закрытый для workspace, а anthropic — общий, доступный только для чтения.
В первом примере version: "latest" обозначает последнюю опубликованную версию навыка. Для интеграции, результаты которой должны воспроизводиться, учитывайте: выбранная версия со временем может измениться. Чтобы закрепить конкретную версию, укажите существующую версию используемого навыка, а не придумывайте идентификатор по образцу.
Ограничения и дальнейшие действия
Этот пример показывает только создание презентации с готовым навыком и скачивание результата. Загрузка и удаление собственных навыков, а также обращение к сторонним сервисам здесь не рассматривались. Для каждого такого сценария отдельно проверьте соответствующий API.
Если вы работаете с файлами через интерфейс Claude, ознакомьтесь с отдельным материалом о загрузке файла в Claude. Для прямых API-вызовов пригодится руководство по расчёту расхода токенов. Если же вы используете терминальный агент, прочитайте о выборе навыков Claude Code: это другой способ подключения.
Для начальной проверки возьмите один готовый навык pptx, проверьте ответ API, скачайте файл с разрешённым доступом и откройте его. Подключайте собственные навыки и настраивайте разделение доступа между клиентами после этой проверки.
Когда будете готовы, познакомьтесь с Ailoot.
Подробнее
Вопросы и ответы
Почему file_id недостаточно для завершения задачи с презентацией?
Идентификатор подтверждает возврат файла, но не пригодность презентации. Проверьте метаданные downloadable: true, скачайте файл с доступом к рабочему пространству и откройте его. Проверьте формат, число слайдов и текст.
Можно ли скачать любой файл, загруженный в Claude Files API?
Нет. Руководство различает созданные файлы с downloadable: true и загруженные с downloadable: false. Доступ к рабочему пространству и разрешение скачивать конкретный файл проверяются отдельно. Не принимайте от конечных пользователей произвольные идентификаторы файлов.