Study notesWeek 10: Building With An LLM API
Week 10 / AI and LLMs from zero

Building With An LLM API

Outcomes

What You Will Be Able To Do

Recap

Recap Of Week 9

Concepts

What An API Is

Keys and environment

Setup Safely

python3 -m venv .venv
source .venv/bin/activate
pip install anthropic
export ANTHROPIC_API_KEY="paste-your-key"
Code

Your First Call

import os
from anthropic import Anthropic

client = Anthropic()
MODEL = os.environ.get('MODEL', 'claude-sonnet-4-5')

r = client.messages.create(
    model=MODEL, max_tokens=300,
    messages=[{'role': 'user', 'content': 'Explain RAG in two sentences.'}])
print(r.content[0].text)
print(r.usage.input_tokens, r.usage.output_tokens)
Setting the role

System Prompts

r = client.messages.create(
    model=MODEL, max_tokens=300,
    system='You are a patient study helper. Answer in under 80 words.',
    messages=[{'role': 'user', 'content': 'What is an embedding?'}])
Chat basics

The API Has No Memory

056011201680224020050090014002000Turn 1Turn 2Turn 3Turn 4Turn 5
Code

A Chat Loop

history = []
while True:
    text = input('you> ')
    if text == 'quit':
        break
    history.append({'role': 'user', 'content': text})
    r = client.messages.create(model=MODEL, max_tokens=500,
        system='You are a study helper.', messages=history)
    reply = r.content[0].text
    history.append({'role': 'assistant', 'content': reply})
    print('bot>', reply)
Latency

Streaming

with client.messages.stream(model=MODEL, max_tokens=500,
        messages=history) as stream:
    for piece in stream.text_stream:
        print(piece, end='', flush=True)
print()
JSON

Structured Output

SYSTEM = ('Extract tasks. Reply with JSON only: '
  '{"tasks": [{"title": str, "due": str or null}]}')
Reliability

Validate And Retry

import json

def extract(text, tries=3):
    msgs = [{'role': 'user', 'content': text}]
    for _ in range(tries):
        r = client.messages.create(model=MODEL, max_tokens=500,
            system=SYSTEM, messages=msgs)
        raw = r.content[0].text
        try:
            data = json.loads(raw)
            assert isinstance(data['tasks'], list)
            return data
        except Exception as e:
            msgs += [{'role': 'assistant', 'content': raw},
                     {'role': 'user', 'content': f'Invalid: {e}. Fix it.'}]
    raise ValueError('no valid JSON')
Money

Counting Cost

IN_PRICE, OUT_PRICE = 3.0, 15.0   # example: check the price page
total = 0
# after each call:
total += (r.usage.input_tokens * IN_PRICE
          + r.usage.output_tokens * OUT_PRICE) / 1_000_000
print(f'${total:.4f}')
Practical levers

Reducing Cost And Latency

Robustness

Errors And Retries

StatusMeaningWhat to do
400Bad requestFix the input
401Not authorisedCheck the API key
429Too many requestsWait and retry
500Server errorRetry with backoff
import time
for wait in (1, 2, 4):
    try:
        r = client.messages.create(...)
        break
    except Exception as e:
        print('retrying:', e)
        time.sleep(wait)
Week 10 in five lines

Recap

Week 11

Next Week: AI And Society

Your turn

Questions And Exercise