درس ۷ از ۱۱

Module 7

عنوان اصلی: Features of Claude هدف یادگیری ماژول: تسلط بر شش قابلیت ویژه‌ی Claude که آن را از یک «LLM ساده» به یک پلتفرم تولید برنامه تبدیل می‌کنند: extended thinking، image input، PDF input، citations، prompt caching، Files API و code execution. مفاهیم کلیدی: extended thinking, thinking block, signature, redacted_thinking, image block, document block, citations, cache_control, ephemeral, Files API, code execution, tool_use, tool_result.

تا اینجا یاد گرفتیم چطور یک request ساده بفرستیم، tool ها را اضافه کنیم و RAG بسازیم. در این ماژول وارد لایه‌ای می‌شویم که Anthropic خودش روی Messages API ساخته و در اختیار ما گذاشته است. هر یک از این قابلیت‌ها با چند خط کد فعال می‌شوند، اما هر کدام تله‌های مالی و کیفیتی خاص خود را دارند.

۷.۱ Extended thinking — استدلال درونی Claude

هدف: فعال‌سازی استدلال chain-of-thought درون مدل از طریق adaptive thinking (مکانیزم فعلی) و شناخت مسیر legacy با budget_tokens.

ایده‌ی محوری. در حالت معمولی، Claude بلافاصله شروع به تولید پاسخ می‌کند. در حالت extended thinking، مدل پیش از تولید پاسخ نهایی، صدها تا ده‌ها هزار token را در یک بلاک داخلی به نام thinking صرف استدلال می‌کند. این برای مسائل ریاضی، حقوقی، تحلیل کد و هر کاری که نیاز به تفکر چندمرحله‌ای دارد، کیفیت را به‌شکل قابل توجهی بالا می‌برد.

مکانیزم فعلی: adaptive thinking.

  • روی مدل‌های نسل فعلی، thinking={"type": "adaptive"} مکانیزم استاندارد است: مدل خودش تصمیم می‌گیرد چقدر فکر کند.
  • budget_tokens روی Fable 5، Opus 4.8/4.7 و Sonnet 5 حذف شده و اگر آن را بفرستید، API کد 400 برمی‌گرداند. روی Opus 4.6 و Sonnet 4.6 هنوز کار می‌کند اما deprecated است؛ فقط مدل‌های قدیمی‌تر همچنان به budget_tokens متکی‌اند.
  • روی Fable 5 فکر کردن همیشه روشن است؛ اگر صریحاً disabled بفرستید، خطای 400 می‌گیرید. روی Sonnet 5 اگر پارامتر thinking را اصلاً نفرستید، مدل به‌طور پیش‌فرض adaptive اجرا می‌شود.
  • سطح تلاش مدل را می‌توانید با output_config.effort تنظیم کنید: low / medium / high / xhigh / max (پیش‌فرض high؛ سطح xhigh از Opus 4.7 معرفی شد و Sonnet 5 اولین Sonnet با xhigh است).

پاسخ، شامل یک content block از نوع thinking است. روی مدل‌های فعلی (Fable 5، Opus 4.8/4.7، Sonnet 5) مقدار پیش‌فرض thinking.display برابر omitted است، یعنی محتوای فکر در پاسخ نمی‌آید مگر آن را تغییر دهید (روی خانواده‌ی 4.6 پیش‌فرض summarized بود). روی Fable 5 زنجیره‌ی فکر خام هرگز برگردانده نمی‌شود. نکته‌ی مالی مهم: شما برای کل token های thinking پول می‌دهید، نه فقط بخش قابل‌مشاهده.

هم‌بازی با tool use. اگر extended thinking را با tool_use ترکیب می‌کنید، در turn های بعدی حتماً بلاک‌های thinking را در history نگه دارید و همراه tool_use و tool_result برگردانید. اگر آنها را حذف کنید، cache بی‌اعتبار می‌شود و کیفیت افت می‌کند. همچنین در حالت thinking، tool_choice فقط می‌تواند auto یا none باشد — نمی‌توانید مدل را به یک tool خاص مجبور کنید.

نمونه کد.

# Current models: adaptive thinking
resp = client.messages.create(
    model="claude-opus-4-8", max_tokens=16000,
    thinking={"type": "adaptive"},
    messages=[{"role": "user", "content": "Are there infinitely many primes p with p mod 4 == 3?"}],
)

for b in resp.content:
    if b.type == "thinking": print("[thinking]:", b.thinking[:200], "…")
    elif b.type == "text":   print("[answer]:",   b.text)

# Legacy path (Sonnet 4.6 / Opus 4.6 only, deprecated): manual budget
resp = client.messages.create(
    model="claude-sonnet-4-6", max_tokens=16000,
    thinking={"type": "enabled", "budget_tokens": 10000},
    messages=[{"role": "user", "content": "Same question."}],
)

اشتباهات رایج.

  • فرستادن budget_tokens به Fable 5، Opus 4.8/4.7 یا Sonnet 5 → خطای 400. روی مدل‌های فعلی از adaptive thinking استفاده می‌شود.
  • حذف بلاک thinking از history در turn بعدی → cache می‌شکند، کیفیت افت می‌کند.
  • فراموش کردن این که شما برای کل thinking token ها پول می‌دهید، نه فقط خلاصه‌ی نمایش داده‌شده.

منابع: Extended thinking · Adaptive thinking.

۷.۲ Image input — ورودی تصویر

هدف: ارسال تصویر به Claude از سه راه (base64، URL، Files API) و پرسیدن سوال vision.

vision در Anthropic API یک endpoint جداگانه نیست؛ صرفاً یک content block جدید است. در یک پیام user، می‌توانید چند بلاک تصویر و متن را در کنار هم بگذارید. سه منبع تصویر در دسترس است:

  1. base64: برای فایل‌های محلی. تصویر را به base64 encode کنید و در data بگذارید.
  2. URL: Anthropic از طرف شما تصویر را fetch می‌کند. سریع‌تر اگر تصویر روی CDN است.
  3. Files API (source.type = "file" با file_id): اگر یک تصویر را قرار است در چندین request دوباره استفاده کنید، یک بار upload کنید و بعد فقط file_id را بفرستید.

فرمت‌های قابل‌قبول: JPEG, PNG, WebP و GIF غیرمتحرک (فقط فریم اول). Claude تصاویر بزرگ‌تر از حدود ۱.۱۵ مگاپیکسل (لبه‌ی بزرگ ≤ 1568px) را به‌طور silent کوچک می‌کند. اگر می‌خواهید coordinate ها را روی تصویر اصلی استفاده کنید (مثلاً برای computer use)، حواس‌تان باشد که Claude در فضای resized گزارش می‌دهد.

import base64
img_b64 = base64.b64encode(open("receipt.jpg", "rb").read()).decode()

resp = client.messages.create(
    model="claude-opus-4-8", max_tokens=1024,
    messages=[{"role": "user", "content": [
        {"type": "image", "source": {
            "type": "base64", "media_type": "image/jpeg", "data": img_b64,
        }},
        {"type": "text", "text": "Extract vendor, total, and date from this receipt."},
    ]}],
)

کاربردهای رایج: استخراج فاکتور، QA روی نمودار، classification محصولات، توضیح اسکرین‌شات، OCR از resume.

اشتباهات رایج.

  • ارسال raw bytes به‌جای base64 (خطای ۴۰۰).
  • تصاویر بسیار بزرگ → silent downsampling. اگر دقت مهم است، خودتان pre-resize کنید.
  • GIF متحرک → فقط فریم اول خوانده می‌شود. نگران نشوید که Claude همه‌ی فریم‌ها را می‌بیند.

منابع: Vision documentation.

۷.۳ PDF input — ورودی PDF

هدف: ارسال PDF به‌صورت document content block و ترکیب آن با citations.

PDF در Claude شهروند درجه‌یک است. در یک پیام user، یک بلاک از نوع document می‌سازید و source را به سه شکل تعیین می‌کنید:

  • base64: PDF محلی encoded.
  • url: PDF عمومی روی وب.
  • file: file_id از Files API.

Anthropic متن PDF را extract می‌کند و در سطح جمله chunk می‌سازد. اگر citations.enabled = true فعال باشد، Claude در پاسخ خود به ازای هر claim یک page_location (شماره‌ی صفحه ۱-indexed) برمی‌گرداند. اگر PDF شما اسکن بدون OCR است، citation در دسترس نیست — قبلش OCR کنید.

برای PDF های فارسی، دو نکته‌ی مهم: ترتیب RTL را در OCR step حفظ کنید، و کاراکترهای عربی را به فارسی normalize کنید (ي → ی، ك → ک).

resp = client.messages.create(
    model="claude-opus-4-8", max_tokens=2048,
    messages=[{"role": "user", "content": [
        {
            "type": "document",
            "source": {"type": "base64", "media_type": "application/pdf",
                       "data": base64.b64encode(open("contract.pdf","rb").read()).decode()},
            "title": "Master Services Agreement",
            "context": "Contract between Pippa London and SupplierCo, signed 2025-06-01.",
            "citations": {"enabled": True},
        },
        {"type": "text", "text": "What is the indemnification cap?"},
    ]}],
)

اشتباهات رایج.

  • فراموش کردن citations: {enabled: true} → هیچ citation برنمی‌گردد.
  • ترکیب اسناد citation-on و citation-off در یک request → خطا. باید all-or-nothing باشند.
  • citations + structured outputs → ناسازگار. خطای ۴۰۰. یکی را انتخاب کنید.

منابع: PDF support · Citations.

۷.۴ Citations — استناد ساختاریافته

هدف: فعال کردن citations روی اسناد و parse انواع char_location، page_location و content_block_location.

citations جواب Claude را از یک «بلاک متن» به یک «درخت ادعا–مدرک» تبدیل می‌کند. وقتی فعال است، مدل پاسخ را به قطعات کوچک می‌شکند و هر قطعه می‌تواند یک آرایه‌ی citations داشته باشد که به محدوده‌ای از سند مبدا اشاره می‌کند.

سه نوع مختصات.

نوع سند نوع citation indexing
متن خام (type: "text") char_location کاراکتر، 0-indexed
PDF page_location صفحه، 1-indexed
custom content (type: "content") content_block_location بلاک، 0-indexed

نکته‌ی مالی شیرین. فیلد cited_text (تا ۱۵۰ کاراکتر) در پاسخ گنجانده می‌شود اما در شمارش output token حساب نمی‌شود. وقتی هم در turn بعدی به‌عنوان context فرستاده می‌شود، در input token حساب نمی‌شود. این یعنی citation عملاً رایگان است.

Custom content برای RAG. اگر RAG دارید و chunk های شما ساختار خاص دارند (لیست FAQ، رکوردهای DB، bullet)، به‌جای text یا PDF از custom content استفاده کنید. هر chunk یک واحد citable مستقل می‌شود و مدل خیلی دقیق‌تر استناد می‌کند.

resp = client.messages.create(
    model="claude-opus-4-8", max_tokens=1024,
    messages=[{"role": "user", "content": [
        {
            "type": "document",
            "source": {"type": "content", "content": [
                {"type": "text", "text": chunk_1},
                {"type": "text", "text": chunk_2},
                {"type": "text", "text": chunk_3},
            ]},
            "title": "Pippa returns FAQ",
            "citations": {"enabled": True},
            "cache_control": {"type": "ephemeral"},
        },
        {"type": "text", "text": "What is the return window?"},
    ]}],
)
for b in resp.content:
    if b.type == "text":
        print(b.text)
        for c in (b.citations or []):
            print(f"  ↳ chunk {c.start_block_index} of {c.document_title}")

ترکیب با cache_control. اگر یک سند بزرگ را قرار است صدها بار query کنید، cache_control: {"type": "ephemeral"} روی document block بگذارید. cache hit بعدی فقط ۰.۱× هزینه‌ی input دارد.

اشتباهات رایج.

  • mix کردن اسناد citation-on و citation-off → ۴۰۰.
  • citations + structured outputs → ۴۰۰. یکی را انتخاب کنید.
  • شمارش cited_text به‌عنوان output token در محاسبه‌ی هزینه (رایگان است).

منابع: Citations.

۷.۵ Prompt caching — قواعد

هدف: قرار دادن breakpoint های cache_control: {"type": "ephemeral"} روی پیشوندهای ثابت تا هزینه‌ی request های تکراری ۹۰٪ کاهش یابد.

ایده‌ی بنیادی. Claude برای هر request ابتدا attention را روی کل prompt محاسبه می‌کند. اگر بخش زیادی از prompt شما در همه‌ی request ها یکسان است (system prompt بزرگ، tool definitions، KB، document)، چرا هر بار از نو محاسبه شود؟ prompt caching می‌گوید: «این پیشوند را hash کن، attention state را cache کن، در request بعدی اگر همین پیشوند آمد، از cache بخوان.»

مکانیک. شما با cache_control: {"type": "ephemeral"} روی آخرین بلاکی که می‌خواهید در prefix cache شود breakpoint می‌گذارید. سیستم:

  1. کل request را از ابتدا تا breakpoint hash می‌کند.
  2. اگر hash موجود است (cache hit) → ۰.۱× هزینه‌ی input.
  3. اگر نیست (cache miss) → cache write با ۱.۲۵× هزینه (TTL پیش‌فرض ۵ دقیقه) یا ۲× (TTL یک ساعته).

ترتیب جست‌وجو. breakpoint ها در این ترتیب اسکن می‌شوند: tools → system → messages. در هر بخش، فقط ۲۰ بلاک آخر قبل از breakpoint بررسی می‌شوند.

حداقل token برای cache (وابسته به مدل است):

  • Opus 4.8/4.7/4.6/4.5 و Haiku 4.5 → 4096 token.
  • Fable 5 و Sonnet 4.6 → 2048 token.
  • Sonnet 4.5 → 1024 token.

اگر prefix شما زیر این آستانه است، cache silent no-op می‌کند — هیچ خطایی نمی‌گیرید، فقط cache_creation_input_tokens و cache_read_input_tokens هر دو صفر می‌مانند.

حداکثر breakpoint. هر request می‌تواند تا ۴ breakpoint داشته باشد. این برای caching لایه‌ای فوق‌العاده است: یک breakpoint برای tools (TTL یک ساعته)، یکی برای system (روزانه)، یکی برای KB، یکی برای session.

resp = client.messages.create(
    model="claude-opus-4-8", max_tokens=1024,
    system=[
        {"type": "text", "text": "You are a tax compliance assistant."},
        {
            "type": "text",
            "text": LARGE_TAX_CODE_TEXT,                       # 50k tokens
            "cache_control": {"type": "ephemeral", "ttl": "1h"},
        },
    ],
    messages=[{"role": "user", "content": "What's the rate for export of services?"}],
)
print("read:",   resp.usage.cache_read_input_tokens)
print("write:",  resp.usage.cache_creation_input_tokens)
print("uncached:", resp.usage.input_tokens)

اشتباهات رایج.

  • breakpoint بعد از یک timestamp یا UUID رندوم → هر request hash جدید می‌سازد، فقط write می‌شود، هرگز read نمی‌شود.
  • prefix زیر آستانه → silent no-op.
  • تغییر tools یا tool_choice بین call ها → cache بی‌اعتبار.
  • ترتیب اشتباه TTL: TTL طولانی‌تر باید زودتر بیاید.

منابع: Prompt caching.

۷.۶ Prompt caching در عمل

هدف: اعمال caching روی یک chatbot، یک agent loop و یک RAG pipeline؛ اندازه‌گیری hit rate.

دو شکل عملیاتی:

۱. Automatic caching (پیشنهادی برای chat). پارامتر cache_control={"type": "ephemeral"} را در سطح بالای request می‌گذارید. سیستم خودش breakpoint را روی آخرین بلاک قابل cache می‌گذارد و با گسترش مکالمه آن را جلو می‌برد. حدود ۹۰٪ ارزش breakpoint های دستی را با صفر زحمت می‌گیرید.

۲. Explicit breakpoints (برای کنترل دقیق). تا ۴ breakpoint: یکی برای tools (که به‌ندرت تغییر می‌کنند)، یکی برای system (روزانه تغییر می‌کند)، یکی برای history مکالمه، یکی برای document بزرگ. با ترکیب TTL های مختلف هزینه‌ی refresh را بهینه می‌کنید.

نکته‌ی keep-alive. هر cache read به‌طور خودکار TTL ۵-min را refresh می‌کند. اگر می‌خواهید cache‌تان زنده بماند، کافی است هر چند دقیقه یک call ارزان به همان prefix بزنید.

Workspace isolation. از ۵ فوریه ۲۰۲۶ به بعد، cache های هر workspace مستقل هستند — بین workspace ها نشت نمی‌کند.

TOOLS = [tool_def_1, tool_def_2, tool_def_3]
TOOLS[-1] = {**TOOLS[-1], "cache_control": {"type": "ephemeral", "ttl": "1h"}}  # cache tools for 1h

SYSTEM = [
    {"type": "text", "text": "You are an internal IT helpdesk agent."},
    {"type": "text", "text": LONG_RUNBOOK_TEXT,
     "cache_control": {"type": "ephemeral"}},                                   # cache for 5 min
]

def run(user_msg, history):
    history.append({"role": "user", "content": user_msg})
    return client.messages.create(
        model="claude-opus-4-8", max_tokens=1024,
        tools=TOOLS, system=SYSTEM, messages=history,
    )

اشتباهات رایج.

  • اضافه/حذف کردن tool وسط مکالمه → کل tool prefix invalid.
  • روشن/خاموش کردن extended thinking وسط مکالمه → message cache invalid.
  • اضافه/حذف image وسط history → کل cache invalid.

منابع: Prompt caching — in action.

۷.۷ Code execution و Files API

هدف: استفاده از code_execution (server-side tool) همراه با Files API برای اجرای Python روی داده‌ی upload شده.

Code execution. یک server tool است: شما فعالش می‌کنید، Claude کد Python می‌نویسد، در یک sandbox میزبان Anthropic اجرا می‌شود، خروجی (stdout, stderr, return_code، نمودارهای تولیدشده) را می‌بیند و iteration می‌کند. کتابخانه‌های pandas، numpy، matplotlib از پیش نصب هستند. Sandbox air-gapped است — اینترنت ندارد. این یک ویژگی امنیتی است، نه bug.

Files API. اجازه می‌دهد یک بار CSV / PDF / image را upload کنید و بعد در چندین request به آن ارجاع بدهید بدون این که هر بار upload کنید. این API هنوز beta است؛ همیشه header anthropic-beta: files-api-2025-04-14 را اضافه کنید.

عملیات Files API.

  • POST /v1/files (multipart upload، حداکثر ۵۰۰ MB).
  • GET /v1/files.
  • GET /v1/files/{id}.
  • DELETE /v1/files/{id}.

ارجاع در پیام: {"type": "document", "source": {"type": "file", "file_id": "file_011..."}}.

# Upload a CSV
file = client.beta.files.upload(
    file=("sales.csv", open("sales.csv", "rb"), "text/csv"),
)
print(file.id)   # file_011CN…

# Ask Claude to analyze it
resp = client.beta.messages.create(
    model="claude-opus-4-8", max_tokens=4096,
    tools=[{"type": "code_execution_20250522", "name": "code_execution"}],
    messages=[{"role": "user", "content": [
        {"type": "document", "source": {"type": "file", "file_id": file.id}},
        {"type": "text", "text": "Compute monthly revenue per category and plot it."},
    ]}],
    betas=["files-api-2025-04-14", "code-execution-2025-05-22"],
)

کاربرد در دنیای واقعی. این ترکیب یعنی شما در چند خط، یک «data analyst on demand» دارید: کاربر یک Excel فروش می‌فرستد، Claude pandas می‌نویسد، summary می‌سازد، نمودار می‌کشد، و در ادامه جواب سوالات follow-up را می‌دهد. در پروژه‌ی zoho-audit Pippa Iran، می‌توان CSV های ماهانه را upload کرد و Claude را برای reconciliation مالی استفاده کرد.

اشتباهات رایج.

  • فراموشی header های beta → ۴۰۴ یا ۴۰۰.
  • نگه داشتن file ها برای همیشه (هزینه‌ی retention دارند) → پاک کنید.
  • فرض اینکه sandbox اینترنت دارد → ندارد.

منابع: Files API · Code execution tool.

۷.۸ Quiz سریع Module 7

سوالات نمونه:

  • چه زمانی نمی‌توانید budget_tokens بفرستید؟ → روی Fable 5، Opus 4.8/4.7 و Sonnet 5. (آن‌جا adaptive است.)
  • حداقل token برای caching روی Opus 4.8؟ → ۴۰۹۶.
  • citations + structured outputs؟ → ناسازگار.
  • چند breakpoint در یک request؟ → حداکثر ۴.
  • معنی cache_read_input_tokens چیست؟ → token هایی که از cache hit آمدند، ۰.۱× هزینه دارند.