Day 2: Tracking Use Cases with @track
📋Overview
The Pay-i Python SDK offers a powerful function decorator, @track, that makes it easy to organize and track your GenAI consumption at the function level. This decorator provides inheritance capabilities that are especially useful for sequences of related GenAI calls that share the same business context.
Purpose of the @track Decorator
This decorator is used to annotate your functions with metadata such as:
- Use Case Names
- Limit IDs for budget tracking and governance
The @track decorator helps maintain consistent tracking across multiple API calls while reducing boilerplate code.
Best Suited For
The @track decorator is particularly well-suited for:
- Function-level annotations that remain consistent across multiple API calls
- Hierarchical tracking structures where nested functions inherit parameters
- Consistent metadata like use case names or organizational limit IDs
- Complex applications with many GenAI calls
Basic Example: Tracking Use Cases
In this example, we decorate the summarize_document() function with @track(). In @track, we define a use_case_name of "document_summary". This means that each time the summarize_document() function is called, an Instance of the document_summary use case will automatically be created by Pay-i and given a randomly generated Instance ID.
All GenAI calls that occur within summarize_document() or any methods it invokes (i.e., the entire call stack) will be treated as requests within the newly generated Instance. In a later example, we will demonstrate how to specify custom Instance IDs or re-use ones generated by Pay-i so that multiple executions can be treated as part of the same Instance, if needed.
Note that before you can use the @track decorator, you must initialize payi_instrument().
import os
from dotenv import load_dotenv
from openai import OpenAI
from payi.lib.instrument import payi_instrument
from payi.lib.instrument import track # Newly added import.
# Load environment variables from .env file
load_dotenv()
# Initialize Pay-i instrumentation
payi_instrument()
# Initialize OpenAI
client = OpenAI()
# Decorate a function with @track to add business context
@track(use_case_name='document_summary')
def summarize_document(client, document_text):
# Every GenAI call inside this function will automatically
# include the use_case_name, limit_ids and user_id defined in the decorator
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": f"Summarize this: {document_text}"}]
)
# Other GenAI calls here...
return response.choices[0].message.contentWhen using the @track decorator:
- All GenAI calls inside the function automatically inherit the parameters of the decorator
- When specifying
use_case_namewithoutuse_case_id, the decorator will create an ID automatically - If you have multiple methods decorated with
@track, then there are two types of behaviors depending on whether the parameter is a singleton (e.g.,use_case_name) or a list (e.g.,limit_ids).- For singletons, the annotation method that executes latest in the code flow takes precedence.
- For lists, the fields are unioned together.
Supported Parameters
The @track decorator supports the below parameters. All parameters are optional. However, not all parameters are recommended for use at the decorator scope, since they likely require details that are typically only available at runtime (such as the user_id), and these fields are not easily parameterized in a decorator. Though they are provided in @track for completeness, Pay-i provides two lower-level instrumentation approaches which are more suited to these types of parameters: track_context() and custom headers. These are both described in their own sections to follow.
| Parameter | Description | Type | Recommended |
|---|---|---|---|
use_case_name | Name of the use case for tracking purposes | str | ✅ |
use_case_id | A custom ID for the use case Instance. | str | ❌ |
use_case_version | Version number of the use case | int | ✅ |
limit_ids | List of limit IDs to apply to the wrapped function | list[str] | ✅ |
user_id | ID of the user initiating the use case | str | ❌ |
account_name | The account to which the user belongs, for grouping purposes | str | ❌ |
request_properties | Any custom key:value properties to be added to all requests made in the decorator call stack. | dict[str,str] | ✅ |
use_case_properties | Any custom key:value properties to be added to all use case Instances made in the decorator call stack. | dict[str,str] | ✅ |
For request-specific parameters not directly supported by @track, see the track_context() function and Custom Headers documentation.
Note: For combining
@trackwith request-specific parameters, see Combined Annotations.
Understanding Parameter Inheritance
When nesting decorated functions or using them with other annotation methods, Pay-i follows a "latest wins" strategy based on execution order.
Here's a simple example showing how parameter inheritance works when calling a decorated function from another decorated function:
from payi.lib.instrument import track
@track(use_case_name='outer_function')
def outer_function():
# All API calls here use use_case_name='outer_function'
# Call another decorated function
inner_function() # Inherits use_case_name='outer_function'
# Call a function with its own annotation
specific_function() # Does NOT inherit - uses its own use_case_name
@track() # Empty decorator - will inherit from caller
def inner_function():
# When called from outer_function():
# - Inherits use_case_name='outer_function'
client.chat.completions.create(...)
@track(use_case_name='specific_function')
def specific_function():
# Always uses its own annotation regardless of caller
# - use_case_name='specific_function' (overrides any inherited value)
client.chat.completions.create(...)This shows the basic pattern of inheritance. For comprehensive details on parameter precedence, including how different parameter types behave and how they combine with other annotation methods, see:
- Combined Annotations - For practical examples of combining different annotation approaches
- Parameter Precedence in Pay-i Instrumentation - For detailed technical reference on parameter behavior
Related Resources
- Annotation Methods Overview
- track_context() Function
- get_context() Function - Access context values at runtime
- Combined Annotations
- Parameter Precedence
- Custom Headers
Updated about 1 month ago
