|
| 1 | +# TimeSeries LLM Forecast API Documentation |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +A [time series](https://en.wikipedia.org/wiki/Time_series) records how a measurement changes over time, while [forecasting](https://en.wikipedia.org/wiki/Forecasting) estimates future values based on past behavior. Time series forecasting is commonly used for future-looking decisions in finance, supply chains, energy, and other operations that depend on reliable projections. |
| 6 | + |
| 7 | +To ease and standardize the deployment of time series models in the LLM era, we designed the TimeSeries LLM Forecast API in Kserve so you can run forecasts with transformer-based models. This API supports both univariate and multivariate time series, provides quantile forecasting, and is designed to be extensible for future enhancements. The API is compatible with standard RESTful practices and allows for flexible options and metadata handling, making it suitable for a wide range of time series applications across industries. |
| 8 | + |
| 9 | +## Table of Contents |
| 10 | + |
| 11 | +* [Overview](#overview) |
| 12 | +* [Quick Start](#quick-start) |
| 13 | +* [Request Schema](#request-schema) |
| 14 | + * [ForecastRequest Fields](#forecastrequest-fields) |
| 15 | + * [TimeSeriesInput](#timeseriesinput) |
| 16 | + * [ForecastOptions](#forecastoptions) |
| 17 | + * [Metadata](#metadata) |
| 18 | +* [Response Schema](#response-schema) |
| 19 | + * [ForecastResponse Fields](#forecastresponse-fields) |
| 20 | + * [ForecastOutput](#forecastoutput) |
| 21 | + * [TimeSeriesForecast](#timeseriesforecast) |
| 22 | + * [Usage](#usage) |
| 23 | + * [Error Handling](#error-handling) |
| 24 | +* [Enumerations](#enumerations) |
| 25 | + * [Frequency](#frequency) |
| 26 | + * [Status](#status) |
| 27 | + * [TimeSeriesType](#timeseriestype) |
| 28 | +* [Examples](#examples) |
| 29 | + * [Request Example](#request-example) |
| 30 | + * [Response Example](#response-example) |
| 31 | +* [Best Practices](#best-practices) |
| 32 | +* [FAQ](#faq) |
| 33 | +* [Changelog](#changelog) |
| 34 | + |
| 35 | + |
| 36 | +## Quick Start |
| 37 | + |
| 38 | +### Endpoint |
| 39 | + |
| 40 | +``` |
| 41 | +POST /v1/timeseries/forecast |
| 42 | +``` |
| 43 | + |
| 44 | +### Typical Workflow |
| 45 | + |
| 46 | +1. Prepare your input time series data and specify forecasting options (e.g., horizon, quantiles). |
| 47 | +2. Compose a JSON request payload according to the [Request Schema](#request-schema). |
| 48 | +3. Send a POST request to `/v1/timeseries/forecast`. |
| 49 | +4. Parse the response for forecast results, quantiles, and usage metrics. |
| 50 | + |
| 51 | + |
| 52 | +## Request Schema |
| 53 | + |
| 54 | +### ForecastRequest Fields |
| 55 | + |
| 56 | +| Field | Type | Required | Description | |
| 57 | +| ------------------- | ---------------------- | -------- | ---------------------------------------------- | |
| 58 | +| model | string | Yes | Name/ID of the model to use | |
| 59 | +| inputs | List\[TimeSeriesInput] | Yes | List of input time series to forecast | |
| 60 | +| options | ForecastOptions | Yes | Forecasting options (e.g., horizon, quantiles) | |
| 61 | +| metadata | Metadata | No | Arbitrary user metadata | |
| 62 | +| other\_properties | any | No | Additional extensible fields | |
| 63 | + |
| 64 | +#### JSON Structure |
| 65 | + |
| 66 | +```json |
| 67 | +{ |
| 68 | + "model": "timesfm", |
| 69 | + "inputs": [...], |
| 70 | + "options": {...}, |
| 71 | + "metadata": {...}, // optional |
| 72 | + "other_properties": ... // optional |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | + |
| 77 | +### TimeSeriesInput |
| 78 | + |
| 79 | +| Field | Type | Required | Description | |
| 80 | +| ------------------ | ---------------- | -------- | ---------------------------------------------------------- | |
| 81 | +| type | TimeSeriesType | Yes | 'univariate\_time\_series' or 'multivariate\_time\_series' | |
| 82 | +| name | string | Yes | Name of the time series (unique in request) | |
| 83 | +| series | TimeSeries | Yes | Observed data: List\[float] or List\[List\[float]] | |
| 84 | +| frequency | Frequency | Yes | Frequency (see [Frequency](#frequency)) | |
| 85 | +| start\_timestamp | string (ISO8601) | No | Start timestamp of series (for aligning output) | |
| 86 | +| ...extra fields | any | No | Additional extensible fields | |
| 87 | + |
| 88 | + |
| 89 | +### ForecastOptions |
| 90 | + |
| 91 | +| Field | Type | Required | Description | |
| 92 | +| ----------- | ------------ | -------- | ---------------------------------- | |
| 93 | +| horizon | int | Yes | Number of steps to forecast | |
| 94 | +| quantiles | List\[float] | No | Quantiles (e.g., \[0.1, 0.5, 0.9]) | |
| 95 | +| ...extra | any | No | Additional extensible fields | |
| 96 | + |
| 97 | + |
| 98 | +### Metadata |
| 99 | + |
| 100 | +* Arbitrary user-provided metadata. No required or fixed fields. |
| 101 | + |
| 102 | + |
| 103 | +## Response Schema |
| 104 | + |
| 105 | +### ForecastResponse Fields |
| 106 | + |
| 107 | +| Field | Type | Required | Description | |
| 108 | +| ----------- | --------------------- | -------- | --------------------------------- | |
| 109 | +| id | string | Yes | Unique response identifier | |
| 110 | +| created\_at | int (unix ts) | Yes | Time of response creation | |
| 111 | +| status | Status | Yes | Overall status of the request | |
| 112 | +| error | Error | No | Top-level error (if any) | |
| 113 | +| model | string | Yes | The model used for forecasting | |
| 114 | +| outputs | List\[ForecastOutput] | Yes | Forecast results, one per input | |
| 115 | +| usage | Usage | No | Token usage metrics (if relevant) | |
| 116 | +| ...extra | any | No | Additional extensible fields | |
| 117 | + |
| 118 | + |
| 119 | +### ForecastOutput |
| 120 | + |
| 121 | +| Field | Type | Required | Description | |
| 122 | +| -------- | ------------------------- | -------- | --------------------------------------------- | |
| 123 | +| type | string | Yes | 'time\_series\_forecast' | |
| 124 | +| id | string | Yes | Unique forecast output identifier | |
| 125 | +| status | Status | Yes | Status of this forecast result | |
| 126 | +| content | List\[TimeSeriesForecast] | Yes | One or more time series forecasts (per input) | |
| 127 | +| error | Error | No | Error if this forecast failed | |
| 128 | +| ...extra | any | No | Additional extensible fields | |
| 129 | + |
| 130 | + |
| 131 | +### TimeSeriesForecast |
| 132 | + |
| 133 | +| Field | Type | Required | Description | |
| 134 | +| ---------------- | ---------------------- | -------- | ---------------------------------------------------------- | |
| 135 | +| type | TimeSeriesType | Yes | 'univariate\_time\_series' or 'multivariate\_time\_series' | |
| 136 | +| name | string | Yes | The name of the time series | |
| 137 | +| mean\_forecast | TimeSeries | Yes | Mean (expected) forecast values | |
| 138 | +| frequency | Frequency | Yes | Frequency of the forecasted time series | |
| 139 | +| start\_timestamp | string (ISO8601) | Yes | Start timestamp for the forecast horizon | |
| 140 | +| quantiles | Dict\[str, TimeSeries] | No | Map from quantile string (e.g., "0.1") to values | |
| 141 | +| ...extra | any | No | Additional extensible fields | |
| 142 | + |
| 143 | + |
| 144 | +### Usage |
| 145 | + |
| 146 | +| Field | Type | Required | Description | |
| 147 | +| ------------------ | ---- | -------- | ------------------------------------------- | |
| 148 | +| prompt\_tokens | int | Yes | Number of tokens in prompt (if LLM-related) | |
| 149 | +| completion\_tokens | int | Yes | Number of tokens in result | |
| 150 | +| total\_tokens | int | Yes | Total tokens used | |
| 151 | +| ...extra | any | No | Additional extensible fields | |
| 152 | + |
| 153 | + |
| 154 | +### Error Handling |
| 155 | + |
| 156 | +If an error occurs, the response may contain a top-level `error` field, or errors may be reported per-forecast (in the corresponding output object). The structure is: |
| 157 | + |
| 158 | +```json |
| 159 | +{ |
| 160 | + "error": { |
| 161 | + "code": "<string>", |
| 162 | + "message": "<description>", |
| 163 | + "param": "<string>", |
| 164 | + "type": "<string>" |
| 165 | + } |
| 166 | +} |
| 167 | +``` |
| 168 | + |
| 169 | + |
| 170 | +## Enumerations |
| 171 | + |
| 172 | +### Frequency |
| 173 | + |
| 174 | +* `SECOND`, `S`: second |
| 175 | +* `MINUTE`, `T`: minute |
| 176 | +* `HOUR`, `H`: hour |
| 177 | +* `DAY`, `D`: day |
| 178 | +* `WEEK`, `W`: week |
| 179 | +* `MONTH`, `M`: month |
| 180 | +* `QUARTER`, `Q`: quarter |
| 181 | +* `YEAR`, `Y`: year |
| 182 | + |
| 183 | +### Status |
| 184 | + |
| 185 | +* `COMPLETED`: The forecast completed successfully |
| 186 | +* `ERROR`: There was an error in processing |
| 187 | +* `PENDING`: The forecast is still running |
| 188 | +* `PARTIAL`: Partially completed |
| 189 | + |
| 190 | +### TimeSeriesType |
| 191 | + |
| 192 | +* `univariate_time_series` |
| 193 | +* `multivariate_time_series` |
| 194 | + |
| 195 | + |
| 196 | +## Examples |
| 197 | + |
| 198 | +### Deploy on KServe |
| 199 | + |
| 200 | +The steps below assume you already have a Kubernetes cluster with KServe installed and that you can pull the model weights from Hugging Face (set the `HUGGING_FACE_HUB_TOKEN` secret if the model is gated). |
| 201 | + |
| 202 | +```yaml |
| 203 | +apiVersion: serving.kserve.io/v1beta1 |
| 204 | +kind: InferenceService |
| 205 | +metadata: |
| 206 | + name: timeseries-forecast |
| 207 | + namespace: kserve-demo |
| 208 | +spec: |
| 209 | + predictor: |
| 210 | + containers: |
| 211 | + - name: timesfm |
| 212 | + image: kserve/huggingfaceserver:latest |
| 213 | + args: |
| 214 | + - "--model_id=google/timesfm-2.0-500m-pytorch" |
| 215 | + - "--model_name=timesfm2" |
| 216 | + - "--http_port=8080" |
| 217 | + resources: |
| 218 | + requests: |
| 219 | + cpu: "4" |
| 220 | + memory: "8Gi" |
| 221 | + limits: |
| 222 | + cpu: "8" |
| 223 | + memory: "16Gi" |
| 224 | + nvidia.com/gpu: "1" |
| 225 | +``` |
| 226 | +
|
| 227 | +### Request Example |
| 228 | +
|
| 229 | +```bash |
| 230 | +curl -X POST "${SERVICE_URL}/v1/timeseries/forecast" \ |
| 231 | + -H "Content-Type: application/json" \ |
| 232 | + -d '{ |
| 233 | + "model": "timesfm2", |
| 234 | + "inputs": [ |
| 235 | + { |
| 236 | + "type": "univariate_time_series", |
| 237 | + "name": "stock_price", |
| 238 | + "series": [120, 122, 125, 127, 130, 133, 135], |
| 239 | + "frequency": "D", |
| 240 | + "start_timestamp": "2025-06-05T13:10:00Z" |
| 241 | + }, |
| 242 | + { |
| 243 | + "type": "univariate_time_series", |
| 244 | + "name": "humidity", |
| 245 | + "series": [33, 34, 35, 36, 37], |
| 246 | + "frequency": "H", |
| 247 | + "start_timestamp": "2025-06-05T13:10:00Z" |
| 248 | + } |
| 249 | + ], |
| 250 | + "options": { |
| 251 | + "horizon": 4, |
| 252 | + "quantiles": [0.1, 0.5, 0.9], |
| 253 | + "other_options": "value" |
| 254 | + }, |
| 255 | + "metadata": { |
| 256 | + "request_id": "user_defined_request_id", |
| 257 | + "other_data": "value" |
| 258 | + }, |
| 259 | + "other_properties": "value" |
| 260 | + }' |
| 261 | +``` |
| 262 | + |
| 263 | + |
| 264 | +### Response Example |
| 265 | + |
| 266 | +```json |
| 267 | +{ |
| 268 | + "id": "resp_67ccd2bed1ec8190b14f964abc0542670bb6a6b452d3795b", |
| 269 | + "created_at": 1741476542, |
| 270 | + "status": "completed", |
| 271 | + "error": null, |
| 272 | + "model": "timesfm2", |
| 273 | + "outputs": [ |
| 274 | + { |
| 275 | + "type": "time_series_forecast", |
| 276 | + "id": "ts_67ccd2bf17f0819081ff3bb2cf6508e60bb6a6b452d3795b", |
| 277 | + "status": "completed", |
| 278 | + "content": [ |
| 279 | + { |
| 280 | + "type": "univariate_time_series", |
| 281 | + "name": "stock_price", |
| 282 | + "mean_forecast": [138, 141, 144, 147], |
| 283 | + "frequency": "D", |
| 284 | + "start_timestamp": "2025-06-12T13:10:00Z", |
| 285 | + "quantiles": { |
| 286 | + "0.1": [135, 138, 140, 143], |
| 287 | + "0.5": [138, 141, 144, 147], |
| 288 | + "0.9": [142, 145, 148, 151] |
| 289 | + } |
| 290 | + } |
| 291 | + ] |
| 292 | + }, |
| 293 | + { |
| 294 | + "type": "time_series_forecast", |
| 295 | + "id": "ts_67ccd2bsdf9q3wadfk439jngjmaphng0oswa34nm8we0ejrf", |
| 296 | + "status": "completed", |
| 297 | + "content": [ |
| 298 | + { |
| 299 | + "type": "univariate_time_series", |
| 300 | + "name": "humidity", |
| 301 | + "mean_forecast": [39, 40, 41, 42], |
| 302 | + "frequency": "H", |
| 303 | + "start_timestamp": "2025-06-05T18:10:00Z", |
| 304 | + "quantiles": { |
| 305 | + "0.1": [37, 38, 39, 40], |
| 306 | + "0.5": [39, 40, 41, 42], |
| 307 | + "0.9": [41, 42, 43, 44] |
| 308 | + } |
| 309 | + } |
| 310 | + ] |
| 311 | + } |
| 312 | + ], |
| 313 | + "usage": { |
| 314 | + "prompt_tokens": 4, |
| 315 | + "completion_tokens": 2, |
| 316 | + "total_tokens": 6 |
| 317 | + }, |
| 318 | + "other_properties": "value" |
| 319 | +} |
| 320 | +``` |
| 321 | + |
| 322 | + |
| 323 | +## Best Practices |
| 324 | + |
| 325 | +* Always include `start_timestamp` for correct alignment of output forecast horizon with input data. |
| 326 | +* Quantiles are returned as string keys (e.g., "0.1"). |
| 327 | +* Make use of `metadata` to pass request-tracking info (e.g., request\_id). |
| 328 | +* Check both top-level and per-output `status` and `error` fields to handle errors robustly. |
| 329 | + |
| 330 | + |
| 331 | +## FAQ |
| 332 | + |
| 333 | +**Q:** What happens if quantiles are not specified? |
| 334 | +**A:** Only mean forecast will be returned. |
| 335 | + |
| 336 | +**Q:** How is the forecast `start_timestamp` determined? |
| 337 | +**A:** It is typically `input.start_timestamp + options.horizon` intervals, but the exact logic depends on the model and frequency. |
| 338 | + |
| 339 | +**Q:** How are multivariate series represented? |
| 340 | +**A:** As `List[List[float]]`, with the first dimension for time and the second for variables. |
| 341 | + |
| 342 | +**Q:** Are additional fields allowed? |
| 343 | +**A:** Yes, both request and response models allow arbitrary extra fields for forward compatibility. |
| 344 | + |
| 345 | + |
| 346 | +## Changelog |
| 347 | + |
| 348 | +* **2025-07-24**: Initial version of API documentation created. |
| 349 | +* **2025-10-20**: Added Kubernetes deployment example. |
0 commit comments