BTQL query syntax
Braintrust Query Language (BTQL) is a precise, SQL-like syntax for querying your experiments, logs, and datasets. You can use BTQL to filter and run more complex queries to analyze your data.
Why use BTQL?
BTQL gives you precise control over your AI application data. You can:
- Filter and search for relevant logs and experiments
- Create consistent, reusable queries for monitoring
- Build automated reporting and analysis pipelines
- Write complex queries to analyze model performance
Query structure
BTQL queries follow a familiar SQL-like structure that lets you define what data you want and how to analyze it:
Each clause serves a specific purpose:
select
: choose which fields to retrievefrom
: specify the data source - can be an identifier (likeproject_logs
) or a function call (likeexperiment("id")
)filter
: define conditions to filter the datasort
: set the order of results (asc
ordesc
)limit
andcursor
: control result size and enable pagination
You can also use dimensions
, measures
, and pivot
instead of select
for aggregation queries.
Understanding traces and spans
When querying experiments or logs, BTQL returns results at the trace level by default. Each row represents a complete interaction with all its associated spans (like prompt construction, model call, post-processing). This helps you understand the full context and flow of each interaction.
For example:
This will return 10 complete traces, not 10 individual spans.
Available operators
Here are the operators you can use in your queries:
Available functions
Here are all the functions you can use in any context (select, filter, dimensions, measures):
Field access
BTQL provides flexible ways to access nested data in arrays and objects:
Array indices are 0-based, and negative indices count from the end (-1 is the last element).
Select clause
The select
clause determines which fields appear in your results. You can select specific fields, compute values, or use *
to get everything:
Working with expressions
Transform your data directly in the select clause:
Using functions
Transform values and create meaningful aliases for your results:
Dimensions and measures
Instead of select
, you can use dimensions
and measures
to group and aggregate data:
Aggregate functions
Common aggregate functions for measures:
Pivot results
The pivot
clause transforms your results to make comparisons easier by converting rows into columns. This is especially useful when comparing metrics across different categories or time periods.
Syntax:
Here are some examples:
Pivot columns are automatically named by combining the dimension value and measure name. For example, if you pivot by metadata.model
and a model named "gpt-4" to measure avg_score
, the name becomes gpt-4_avg_score
.
Unpivot
The unpivot
clause transforms columns into rows, which is useful when you need to analyze arbitrary scores and metrics without specifying each score name. This is particularly helpful when working with dynamic sets of metrics or when you need to know all possible score names in advance.
Conditional expressions
BTQL supports conditional logic using the ternary operator (? :
):
Time intervals
BTQL supports intervals for time-based operations:
Filter clause
The filter
clause lets you specify conditions to narrow down results. It supports a wide range of operators and functions:
Note: Negative filters on tags (e.g., NOT tags includes "resolved"
) may not work as expected. Since tags are only applied to the root span of a trace, and queries return complete traces, negative tag filters will match child spans (which don't have tags) and return the entire trace. We recommend using positive tag filters instead.
Sort clause
The sort
clause determines the order of results:
Limit and cursor
Control result size and implement pagination:
Cursors are automatically returned in the response when using limit
. However, cursors can only be used for pagination when no sort
clause is specified. If you need sorted results, you'll need to implement offset-based pagination by using the last value from your sort field as a filter in the next query, as shown in the example above.
API access
Access BTQL programmatically through our API:
The API accepts these parameters:
query
(required): your BTQL query stringfmt
: response format (json
orparquet
, defaults tojson
)tz_offset
: timezone offset in minutes for time-based operationsuse_columnstore
: enable columnstore for faster large queriesaudit_log
: include audit log data
For correct day boundaries, set tz_offset
to match your timezone. For example, use 480
for US Pacific Standard Time.
Examples
Let's look at some real-world examples:
Tracking token usage
This query helps you monitor token consumption across your application:
The response shows daily token usage:
Model quality monitoring
Track model performance across different versions and configurations:
Error analysis
Identify and investigate errors in your application:
Latency analysis
Monitor and optimize response times:
Prompt analysis
Analyze prompt effectiveness and patterns:
Tag-based analysis
Use tags to track and analyze specific behaviors: