SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-03

מדריך Claude API: אפליקציית Python ראשונה ב־VPS

למדו ליצור API key, לאבטח אותו ב־Ubuntu 24.04 ולבנות כלי Python להסברת לוגים עם streaming, טיפול בשגיאות, systemd ושליטה אמיתית בעלויות.

מה אתם בונים

כלי שורת פקודה ב־Ubuntu 24.04 חדש, שאליו מזינים הודעת שגיאה או קטע לוג באמצעות pipe ומקבלים אבחון באנגלית פשוטה: journalctl -u nginx -n 50 | explain. הקוד כולל בערך שישים שורות Python, והוא מתרגל את כל הרכיבים הנדרשים ליישום אמיתי מול Claude API: מפתח שנשמר כראוי, virtualenv, מבני התגובה של ה־SDK, streaming, שרשרת החריגות הטיפוסית ויחידת systemd, כך שהכלי יפעל ללא הפעלה ידנית.

בחרתי בפרויקט הזה בכוונה. ברוב המדריכים ליישום API ראשון בונים chatbot שלא פותחים שוב. כלי להסבר לוגים שימושי בשרת כבר מהיום הראשון, והוא מאלץ אתכם להתמודד עם שתי הטעויות הנפוצות ביותר אצל מתחילים: קריאה נכונה של אובייקט התגובה ושליטה בהוצאות. ה־API מחייב לפי מספר ה־tokens, בלי תקרה מלבד זו שאתם מגדירים. לכן שליטה בעלויות היא חלק מתכנון המערכת, ולא מחשבה מאוחרת. זו אותה משמעת שתידרש כשתעברו ל־הפעלת Claude Code על אותו VPS בתוך tmux.

קבלת API key מה־Console

הגישה ל־API מנוהלת ב־Anthropic Console בכתובת platform.claude.com. הירשמו, ולאחר מכן צרו key תחת Settings → API Keys (התיעוד מפנה ישירות אל platform.claude.com/settings/keys). ה־key מוצג פעם אחת בלבד, מתחיל ב־sk-ant-, ואי־אפשר לאחזר אותו שוב. העתיקו אותו מיד, או מחקו אותו והנפיקו key חדש.

מבחינת עלויות: נכון ל־July 2026, אין ל־API מסלול חינמי קבוע. בתיעוד התמחור של Anthropic מצוין שמשתמשים חדשים מקבלים כמות קטנה של קרדיטים חינמיים לצורכי בדיקה. הסכום המדויק הוא זה שמופיע ב־Console בעת ההרשמה. לאחר שהקרדיטים נגמרים, יש להוסיף מימון לחשבון כדי שהבקשות יצליחו. הדבר נפרד ממינוי ל־claude.ai. תוכנית Pro או Max אינה כוללת קרדיט ל־API, ו־API key אינו מעניק גישה ליישום הצ'אט. אם אתם משווים בין מינוי לבין API, זהו שיקול נפרד: איזו תוכנית Claude אתם באמת צריכים.

צרו את ה־key עם הרשאות המוגבלות לפרויקט או לשרת אחד. כאשר key דולף, ובטווח זמן ארוך דיו זה יקרה, תרצו לבטל אותו בלי להשבית את כל המשאבים האחרים שבבעלותכם.

שמרו את המפתח מחוץ ל־.bashrc

התגובה האוטומטית היא export ANTHROPIC_API_KEY=sk-ant-... בתוך ~/.bashrc. אל תעשו זאת. יש לכך 3 בעיות נפרדות:

  • כל תהליך יורש אותו. משתנה סביבה שיוצא ל־export במעטפת הכניסה שלכם מופץ לכל מה שאתם מפעילים: יישום האינטרנט, מדווח הקריסות שמוסיף את משתני הסביבה לדוח תקלה, ועמוד phpinfo() שמישהו השאיר מופעל. שטח החשיפה של המפתח הופך ל״כל מה שהמשתמש הזה מפעיל אי־פעם״.
  • ההקלדה נשמרת ב־~/.bash_history. הפעילו את פקודת ה־export ידנית פעם אחת, והמפתח יישאר בקובץ טקסט גלוי ללא הגבלת זמן ויסונכרן לכל גיבוי של ספריית הבית שלכם.
  • הוא אינו זמין כאשר systemd זקוק לו. שירותים אינם קוראים את .bashrc שלכם, ולכן התבנית נכשלת בדיוק כאשר אתם הופכים את הסקריפט ליחידה, בדרך כלל עם שגיאת 401 מסתורית בשעה 6 בבוקר.

התבנית הנכונה בשרת היא קובץ סביבה ייעודי עם הרשאות 600, שנטען רק על ידי התהליך שזקוק לו:

sudo mkdir -p /opt/explain
sudo install -m 600 -o root -g root /dev/null /etc/claude-explain.env
printf 'ANTHROPIC_API_KEY=sk-ant-YOUR-KEY-HERE\n' | sudo tee /etc/claude-explain.env >/dev/null

השתמשו ב־tee מתוך printf במקום בעורך, אם ברצונכם למנוע את שמירת המפתח בקובצי swap של העורך. בכל מקרה, ודאו באמצעות ls -l /etc/claude-explain.env שהוא קורא את -rw------- ושהבעלות עליו היא של root. מעטפות אינטראקטיביות מקבלות את המפתח בכל הפעלה באמצעות wrapper (בהמשך), ו־systemd מקבל אותו באמצעות EnvironmentFile=. root קורא את הקובץ לפני הורדת ההרשאות, ולכן משתמש השירות לעולם אינו צריך הרשאת קריאה אליו. המפתח לעולם אינו מופיע בקוד, ב־git, בפלט של ps או בהיסטוריית המעטפת.

התקנת ה־SDK בתוך venv

Ubuntu 24.04 מגיעה עם Python 3.12 ועם אכיפת PEP 668, ולכן הפעלה ישירה של pip install anthropic מול מפרש המערכת נכשלת ומחזירה את error: externally-managed-environment. זו התנהגות תקינה של מערכת ההפעלה. השתמשו ב־virtualenv:

sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropic

בשרת אין צורך בתהליך הפעלה מיוחד: קריאה ישירה ל־/opt/explain/venv/bin/python משתמשת תמיד בחבילות של ה־venv.

הקריאה הראשונה וקריאת התגובה באופן נכון

import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Explain what a systemd unit file is in three sentences."}],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

שני דברים בשנים-עשר השורות האלה ממחישים את עיקר המודל המחשבתי של ה־API. ראשית, anthropic.Anthropic() ללא ארגומנטים קורא את המפתח מהסביבה. לעולם אל תעבירו אותו כמחרוזת ליטרלית. שנית, response.content הוא רשימה של בלוקי תוכן, ולא מחרוזת. אם מדפיסים אותו ישירות, מתקבלת התוצאה הקלאסית של משתמשים מתחילים:

[TextBlock(citations=None, text='A systemd unit file is...', type='text')]

זו אינה תקלה, אלא ה־repr של האובייקט. תגובות יכולות להכיל כמה סוגים של בלוקים, כגון טקסט, קריאות לכלים וחשיבה. לכן יש לעבור עליהם בלולאה ולבדוק את block.type == "text" לפני שניגשים אל .text. אם מוסיפים את הלולאה הזו כבר ביום הראשון, נמנעים לחלוטין מקבוצה שלמה של בלבול בסגנון "הוא מדפיס זבל".

השתמשו בדיוק במזהה המודל claude-opus-4-8. למזהים מהדור הנוכחי אין תאריך. אל תסתמכו על ההרגל להוסיף סיומת תאריך, או על פוסט ישן בבלוג שמורה לעשות זאת. פעולה כזו גורמת לשגיאת 404, כפי שמוסבר בהמשך.

הכלי בפועל: הסבר

הנה התוכנית המלאה: קלט מ־stdin, אבחון מוזרם כפלט, וטיפול בשגיאות:

#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic

MODEL = "claude-opus-4-8"

def main() -> int:
    text = sys.stdin.read().strip()
    if not text:
        print("usage: journalctl -u nginx -n 50 | explain", file=sys.stderr)
        return 1

    client = anthropic.Anthropic()
    try:
        with client.messages.stream(
            model=MODEL,
            max_tokens=1500,
            system=(
                "You are a senior Linux sysadmin. The user pipes you server "
                "logs or error output. Name the most likely cause outright, "
                "then give the commands to confirm and fix it. Be terse."
            ),
            messages=[{"role": "user", "content": text}],
        ) as stream:
            for chunk in stream.text_stream:
                print(chunk, end="", flush=True)
        print()
    except anthropic.RateLimitError as e:
        retry_after = e.response.headers.get("retry-after", "60")
        print(f"rate limited; retry in {retry_after}s", file=sys.stderr)
        return 2
    except anthropic.APIStatusError as e:
        print(f"API error {e.status_code}: {e.message}", file=sys.stderr)
        return 2
    except anthropic.APIConnectionError:
        print("network error reaching the API", file=sys.stderr)
        return 2
    return 0

if __name__ == "__main__":
    sys.exit(main())

שמרו אותה בשם /opt/explain/explain.py, ולאחר מכן הוסיפו עטיפה שטוענת את המפתח לשימוש אינטראקטיבי:

sudo tee /usr/local/bin/explain >/dev/null <<'EOF'
#!/bin/sh
set -a; . /etc/claude-explain.env; set +a
exec /opt/explain/venv/bin/python /opt/explain/explain.py "$@"
EOF
sudo chmod 755 /usr/local/bin/explain

(העטיפה צריכה לפעול באמצעות sudo, או שקובץ הסביבה צריך להיות משויך לקבוצה שמשתמש הניהול שלכם חבר בה. בחרו באחת מהאפשרויות במכוון, במקום להחליש את הרשאות הקובץ ל־644.)

מדוע להזרים את הפלט. client.messages.stream מדפיס אסימונים כשהם מתקבלים, במקום להישאר ללא פלט במשך כל זמן ההפקה. כך נמנעות גם פקיעות זמן של HTTP בפלטים ארוכים. ה־SDK אף דוחה ערכי max_tokens גדולים מאוד בקריאות שאינן מוזרמות, בדיוק מסיבה זו. אם נדרש לכם האובייקט המורכב לאחר מכן, קראו ל־stream.get_final_message() בתוך בלוק with.

מדוע סדר החריגים הוא כזה. ה־SDK מעלה חריגים מטיפוסים מוגדרים, מהספציפי ביותר לכללי יותר: RateLimitError הוא שגיאת 429 וכולל כותרת retry-after שמציינת כמה זמן יש להמתין; APIStatusError מכסה תגובות אחרות שאינן 2xx; בדקו את e.status_code >= 500 כדי לזהות בעיה בצד השרת; APIConnectionError מציין שהבקשה לא קיבלה תגובה כלל. לפני שאתם בונים לולאת ניסיונות חוזרים, זכרו: ה־SDK כבר מבצע בעצמו ניסיונות חוזרים עבור שגיאות 429 ו־5xx, פעמיים כברירת מחדל, עם השהיה מעריכית (max_retries ב־client). כאשר except שלכם מופעל, כל הניסיונות החוזרים כבר נוצלו. לכן, ב־CLI, הפעולה הנכונה היא לדווח ולצאת, ולא להמתין ולשלוח שוב ושוב בקשות.

בקרת עלויות

סעיף זה מצדיק פרק נפרד, משום של־API אין תקרה חודשית מובנית מעבר למה שהגדרתם, וכל טעות בתחום הזה מצטברת בשקט.

max_tokens הוא תקרת ההוצאה לכל קריאה. פלט יקר יותר מקלט: ב־Opus 4.8 מחירו גבוה פי 5 ממחיר הקלט, ו־max_tokens מגביל את מספר הטוקנים שהמודל רשאי להפיק. גם prompt שיצא משליטה לא יוכל לייצר יותר פלט ממה שאישרתם. התאימו את הערך למשימה: 1,500 מספיקים לאבחון לוג, ואילו משימת סיווג זקוקה ל־100. אם התשובות נקטעות באמצע משפט עם stop_reason: "max_tokens", הערך נמוך מדי. הגדילו אותו במכוון, במקום לעבור כברירת מחדל לערכים גדולים.

ספרו לפני השליחה. גם קלט עולה כסף, ולוגים תופסים נפח רב. ל־API יש endpoint לספירה, שניתן להשתמש בו ללא עלות. יש לו מגבלות rate limit משלו, נפרדות מאלה של יצירת הודעות:

count = client.messages.count_tokens(
    model="claude-opus-4-8",
    messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)

השתמשו בו כדי למנוע הזרמה מקרית של לוג בנפח 2 GB דרך הכלי. אין להשתמש ב־tiktoken למטרה זו. זהו ה־tokenizer של OpenAI, והוא סופר פחות מדי טוקנים של Claude בכ־15–20% בטקסט טיפוסי, ואף יותר בקוד.

בחרו את המודל לפי המשימה, לא מתוך נאמנות למודל מסוים. נכון ליולי 2026, ‏Opus 4.8 ‏(claude-opus-4-8) עולה $5 לכל מיליון טוקני קלט ו־$25 לכל מיליון טוקני פלט. ‏Haiku 4.5 ‏(claude-haiku-4-5) עולה $1/$5 ותומך ב־context של 200K. ‏Sonnet 5 ‏(claude-sonnet-5) נמצא באמצע, במחיר של $3/$15, עם מחיר היכרות של $2/$10 עד 31 באוגוסט 2026. בפועל, קטע לוג של 2,000 טוקנים ותשובה של 500 טוקנים עולים כ־$0.0225 ב־Opus וכ־$0.0045 ב־Haiku. התחילו ב־Opus בזמן שאתם מעריכים את איכות הפלט, ולאחר מכן נסו את אותן prompts ב־Haiku. במשימות פשוטות בנפח גבוה, ההבדל לרוב אינו מורגש, אף שהמחיר הוא חמישית. בדקו את הנתונים העדכניים בדף התמחור לפני שאתם מקבעים אותם בתקציב.

השתמשו ב־Batches לכל משימה שיכולה להמתין. ה־Batches API מעבד בקשות באופן אסינכרוני, במחיר של 50% מהמחיר הרגיל, ורוב ה־batches מסתיימים בתוך שעה. דוחות ליליים, השלמות נתונים, סיווג בכמות גדולה וכל משימה שאינה דורשת המתנה של אדם שייכים לשם.

השתמשו ב־prompt caching עבור context שחוזר על עצמו. אם בכל קריאה אתם שולחים מחדש את אותו system prompt גדול או את אותו runbook, סמנו אותו כניתן לשמירה ב־cache:

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1000,
    system=[{
        "type": "text",
        "text": RUNBOOK_TEXT,  # the same 30K tokens on every call
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": question}],
)
print(response.usage.cache_read_input_tokens)  # non-zero from the second call on

כתיבות ל־cache עולות בערך פי 1.25 ממחיר הקלט, וקריאות מה־cache עולות בערך פי 0.1, עם TTL של 5 דקות. לכן הקריאה השנייה בתוך חלון הזמן כבר מכסה את עלות הקריאה הראשונה. יש לכך שתי מגבלות. הקידומת הנשמרת ב־cache חייבת לעבור סף מינימלי שתלוי במודל, בדרך כלל כמה אלפי טוקנים ב־Opus. לכן system prompt קצר עלול לא להישמר ב־cache כלל. בנוסף, אם cache_read_input_tokens נשאר 0 בקריאות זהות, משהו בקידומת משתנה בכל בקשה. timestamp הוא הגורם הנפוץ לכך.

זכרו מה נחשב לקלט. system prompts, הגדרות כלים, ובשיחות מרובות־תורות כל ההיסטוריה שאתם שולחים מחדש בכל תור, מחויבים כולם כטוקני קלט. לולאת chat שאינה מקצרת את ההיסטוריה צוברת עלות בקצב ריבועי. חשוב להבין את החשבון המלא לפני שבונים מערכת שיחה: כיצד השימוש בטוקנים והחיוב של Claude מצטברים בפועל.

הפעלת השירות באמצעות systemd

התועלת של הקפדה על קובץ סביבה היא timer שמסכם בכל בוקר את השגיאות מאתמול.

# /etc/systemd/system/log-digest.service
[Unit]
Description=Daily error-log digest via the Claude API

[Service]
Type=oneshot
User=explain
Group=systemd-journal
EnvironmentFile=/etc/claude-explain.env
ExecStart=/bin/sh -c 'journalctl -p err --since yesterday | /opt/explain/venv/bin/python /opt/explain/explain.py >> /var/log/log-digest.txt'
# /etc/systemd/system/log-digest.timer
[Unit]
Description=Run the log digest every morning

[Timer]
OnCalendar=06:15
Persistent=true

[Install]
WantedBy=timers.target
sudo useradd -r -s /usr/sbin/nologin explain
sudo touch /var/log/log-digest.txt && sudo chown explain /var/log/log-digest.txt
sudo systemctl daemon-reload
sudo systemctl enable --now log-digest.timer
sudo systemctl start log-digest.service   # test it once, right now

שימו לב מה EnvironmentFile= מאפשר: systemd קורא את הקובץ שבבעלות root ובמצב 600 לפני שהוא עובר למשתמש חסר ההרשאות explain, ולכן התהליך מקבל את המשתנה, אך המשתמש אינו יכול לקרוא את קובץ המפתח. הקבוצה systemd-journal מעניקה גישה ללוגים. בדקו זאת באמצעות systemctl start ידני וקראו את journalctl -u log-digest.service; אל תחכו לשעה 06:15 כדי לגלות שגיאת כתיב. כאשר התבנית הזו חורגת מהיקף של צינור shell, אותה גישה של שמירת המפתח בקובץ הסביבה עוברת ישירות גם אל תהליכי עבודה של n8n המופעלים באמצעות Claude באותו שרת.

תרחישי כשל, עם המחרוזות שיופיעו

401 עם מפתח תקין. החריגה מכילה:

anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}

אם המפתח עובד ב־shell אך השירות מחזיר 401, השירות לא קיבל אותו. זכרו ש־systemd אינו קורא את .bashrc; בדקו ש־EnvironmentFile= מפנה לנתיב הנכון. סיבות נוספות: מרכאות שהודבקו בקובץ הסביבה (ANTHROPIC_API_KEY="sk-ant-..."; systemd מסיר את המרכאות, אך ה־wrapper של ה־shell עם . file משאיר אותן בערך אם ציינתם את המרכאות באופן שגוי), רווחים בסוף השורה, או מפתח שביטלתם ב־Console בשבוע שעבר.

404 בגלל שגיאה בשם המודל. המקרה הנפוץ ביותר הוא הוספת סיומת תאריך למזהה מודל נוכחי:

anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-4-8-20260115'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}

מזהי המודלים מהדור הנוכחי חייבים להופיע בדיוק כפי שנכתבו: claude-opus-4-8, claude-haiku-4-5, claude-sonnet-5. העתיקו אותם מתיעוד המודלים, ולא מהזיכרון או ממדריך ישן.

429 rate_limit_error. מחרוזת סוג השגיאה היא rate_limit_error, והתגובה כוללת כותרת retry-after המציינת כמה שניות להמתין. ה־SDK כבר ניסה שוב פעמיים עם backoff לפני שהחריגה הופיעה. לכן, 429 מתמשכים מצביעים על כך שקצב הבקשות המתמשך שלכם אכן חורג מהמגבלה של הרמה שלכם. חלקו את העבודה לאצוות או פרסו אותה על פני זמן, ואל תקצרו את לולאת הניסיונות החוזרים.

המערכת מדפיסה את האובייקט במקום את הטקסט. הפלט נראה כך: [TextBlock(citations=None, text='...', type='text')]. הדפסתם את response.content במקום לעבור על הבלוקים ולקרוא את .text מהבלוקים שבהם block.type == "text". כל דוגמאות ה־SDK לעיל עושות זאת נכון; העתיקו את הלולאה.

error: externally-managed-environment. הרצתם את pip install מול ה־Python המערכתי של Ubuntu 24.04. השתמשו ב־venv, ולעולם אל תשתמשו ב־--break-system-packages בשרת שחשוב לכם.

תשובות שנקטעו. response.stop_reason == "max_tokens" פירושו שהמודל הגיע למגבלת הפלט באמצע המענה. זו ההתנהגות המתוכננת; הגדילו את המגבלה באופן מכוון.

לאחר שהיישום הראשון שלכם פועל, בניית סוכן AI עם Claude הופכת את אותן קריאות API לסוכן שמשתמש בכלים.

FAQ

כמה עולה לנסות את Claude API?

מעט מאוד, באופן ממשי, עבור כלי כזה. נכון ליולי 2026, Opus 4.8 עולה $5 לכל מיליון אסימוני קלט ו־$25 לכל מיליון אסימוני פלט. לכן אבחון לוגים טיפוסי, עם כמה אלפי אסימונים בקלט וכמה מאות בפלט, עולה בערך שני סנטים. עם Haiku 4.5 ($1/$5) העלות נמוכה מחצי סנט. חודש של תקצירים יומיים עולה פחות מקפה. הסיכון אינו המחיר לכל קריאה, אלא לולאות ללא הגבלה ו־max_tokens ללא הגבלה. לכן המדריך הזה מגדיר את שניהם במפורש.

האם יש מסלול חינמי ל־Claude API?

לא קיים מסלול חינמי מתמשך נכון ליולי 2026. לפי תיעוד התמחור של Anthropic, משתמשים חדשים מקבלים כמות קטנה של קרדיטים חינמיים לבדיקת ה־API, כניסיון חד־פעמי. הסכום המדויק מוצג ב־Console בעת ההרשמה. לאחר מכן יש לממן את החשבון. אם המטרה היא עלות שולית אפסית לכל בקשה, ולא איכות ברמת המודלים המתקדמים ביותר, החלופה היא אירוח עצמי של מודל בעל משקולות פתוחות באמצעות Ollama ותשלום בזיכרון RAM במקום באסימונים.

כיצד שומרים על מפתח API מאובטח בשרת?

לעולם לא שומרים אותו בקוד, ב־git או כמשתנה שיוצא מ־.bashrc. אין להקליד אותו ב־shell שבו היסטוריית הפקודות תשמור אותו. יש למקם אותו בקובץ שבבעלות root, עם הרשאות 600, ולטעון אותו בנפרד לכל תהליך. לשימוש אינטראקטיבי אפשר להשתמש ב־wrapper script, ול־systemd ב־EnvironmentFile=. הגדירו מפתח נפרד לכל שרת או פרויקט, כדי שביטול מפתח שדלף יהיה פעולה ממוקדת ולא השבתה רחבה. אם המפתח הגיע אי־פעם לאתר paste או ל־commit של git, בטלו אותו מיד ב־Console. מחיקת ה־commit אינה מבטלת את הדליפה.

באיזה מודל Claude כדאי להתחיל?

התחילו עם claude-opus-4-8 בזמן שאתם בודקים אם הפלטים איכותיים מספיק להמשך פיתוח. כך תוכלו להעריך את הרעיון באיכות מלאה, ובנפח שימוש חובבני ההבדל בעלות מסתכם בסנטים. לאחר שהנחיית המודל התייצבה, הריצו שוב את הקלטים האמיתיים שלכם באמצעות claude-haiku-4-5. עבור סיכום, סיווג ומיון ראשוני של לוגים, הוא לעיתים קרובות טוב באותה מידה, בחמישית מהמחיר. עברו ל־Haiku או ל־Sonnet על סמך מדידה, ולא כברירת מחדל.