No history yet

Data as Code

Data as Code

When you interact with a large language model, you're not just sending words; you're sending structured data. Python is the primary tool for shaping this data, turning your instructions into a format the AI can understand and then translating its complex output back into something you can use. Let's move past the theory of LLMs and get hands-on with the data structures that drive AI workflows.

Batching with Lists

Sending one prompt at a time is inefficient. A more common workflow involves sending a batch of prompts to the model in a single API call. Python lists are perfect for this. You can package dozens or even hundreds of prompts into a single list.

prompts = [
  "What is the capital of France?",
  "Translate 'hello' into Spanish.",
  "Write a short poem about the moon."
]

# This list is now ready to be sent to an AI model's API.
# The model would process all three prompts in one go.

In return, the API will typically send back a list of responses, where each element corresponds to a prompt you sent. You can then loop through this list to handle each output individually.

# Fictional response from an API
responses = [
  {'status': 'success', 'answer': 'Paris'},
  {'status': 'success', 'answer': 'Hola'},
  {'status': 'success', 'answer': 'Silver orb in velvet night...'}
]

for response in responses:
  print(response['answer'])

Structuring Data with Dictionaries

Modern AI interactions are more than just a single prompt. You need to provide context, assign roles (like system, user, or assistant), and sometimes request specific output formats. Dictionaries are the data structure for this job. They use key-value pairs to organize this information clearly.

For example, you might structure a message to an API to tell the model it's a helpful assistant and then provide the user's actual question.

message_payload = {
  "model": "gpt-4o",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "What's the weather like in Tokyo?"}
  ]
}

The response you get back is also a dictionary, often a nested one. Your main task is to parse this structure to find the information you need, like the model's text reply or a request to use an external tool.

Extracting the answer usually means navigating through several layers of the dictionary. For instance, the actual text might be buried under keys like choices, then message, then content. You might also see a key called , which is how modern agents perform actions.

# A simplified example of a complex API response
api_response = {
  'id': 'chatcmpl-123',
  'object': 'chat.completion',
  'created': 1677652288,
  'model': 'gpt-4o-2024-05-13',
  'choices': [
    {
      'index': 0,
      'message': {
        'role': 'assistant',
        'content': 'The weather in Tokyo is sunny with a high of 22°C.'
      },
      'finish_reason': 'stop'
    }
  ]
}

# Accessing the nested content
reply_text = api_response['choices'][0]['message']['content']
print(reply_text) 
# Output: The weather in Tokyo is sunny with a high of 22°C.

Speaking the Language of APIs

When you send a Python dictionary to a web API, it must first be converted into a universally understood format. That format is (JavaScript Object Notation). Similarly, when you receive data from an API, it arrives as a JSON string, which you must convert back into a Python object.

Fortunately, Python's built-in json library makes this easy. The two essential functions are:

  • json.dumps(): Dumps a Python object (like a dict or list) into a JSON string.
  • json.loads(): Loads a JSON string into a Python object.
import json

# 1. Prepare your Python dictionary
python_dict = {"query": "Tell me a joke", "user_id": 42}

# 2. Serialize it to a JSON string for the API request
json_string_to_send = json.dumps(python_dict)
print(f"Sending: {json_string_to_send}")

# 3. Receive a JSON string from the API (as a hypothetical example)
json_string_from_api = '{"response": "Why don\'t scientists trust atoms? Because they make up everything!"}'

# 4. Deserialize it back into a Python dictionary to work with
python_dict_received = json.loads(json_string_from_api)
print(f"Received and parsed: {python_dict_received['response']}")

Indexing and Slicing Text

LLMs operate on tokens, not just characters or words. Sometimes you need to manage the size of your input to fit within a model's context window or process a very long generated text in chunks. Python's indexing and slicing are fundamental for this.

Slicing lets you grab a piece of a string or a list. It's essential for tasks like trimming a prompt that's too long or breaking a long model output into paragraphs for easier processing.

long_text = "This is a very long text generated by an AI. It has multiple sentences and we might only want to process the beginning of it to get a summary or the key idea before handling the rest of the content separately."

# Get the first 50 characters
first_chunk = long_text[:50]
print(f"First chunk: {first_chunk}...")

# Get characters from index 50 to 100
middle_chunk = long_text[50:100]
print(f"Middle chunk: {middle_chunk}")

# Get the last 50 characters
last_chunk = long_text[-50:]
print(f"Last chunk: ...{last_chunk}")

This same slicing syntax works on lists, which is useful if your text is pre-processed into a list of words or tokens. Mastering these simple commands gives you precise control over the data you send to and receive from any AI model.

Quiz Questions 1/5

You need to send 50 separate prompts to an LLM in a single API call for efficiency. Which Python data structure is best suited for this task?

Quiz Questions 2/5

To communicate effectively with a modern LLM, you need to provide not just a message but also the role of the sender (e.g., 'user'). Which data structure is used to package this role and message content together?