CLI tool for running LLM batch processing jobs on HPC systems
Project description
LLMFlux: LLM Batch Processing Pipeline for HPC Systems
A streamlined solution for running Large Language Models (LLMs) in batch mode on HPC systems powered by Slurm. LLMFlux uses the OpenAI-compatible API format with a JSONL-first architecture, enabling your prompts to flow efficiently through LLM engines at scale.
Architecture
JSONL Input Batch Processing Results
(OpenAI Format) (Ollama/vLLM + Model) (JSON Output)
│ │ │
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ Batch │ │ │ │ Output │
│ Requests │─────────────────▶ │ Model on │─────────────────▶ │ Results │
│ (JSONL) │ │ GPU(s) │ │ (JSON) │
└──────────┘ │ │ └──────────┘
└──────────────┘
LLMFlux processes JSONL files in a standardized OpenAI-compatible batch API format, enabling efficient processing of thousands of prompts on HPC systems with minimal overhead.
Documentation
- Configuration Guide - How to configure LLMFlux
- Models Guide - Supported models and requirements
- Repository Structure - Codebase organization
- Testing Guide - How to run tests
Installation
Prerequisites: LLMFlux runs models inside Apptainer (formerly Singularity) containers on HPC systems. Apptainer must be available on your cluster — confirm with apptainer --version or contact your cluster admin.
pip install llmflux
Or for development:
-
Create and Activate Conda Environment:
conda create -n llmflux python=3.11 -y conda activate llmflux
-
Install Package:
pip install -e .
-
Environment Setup:
cp .env.example .env # Edit .env with your SLURM account and model details
Confirm the installation by running a base command and ensuring your system gives the correct output:
$llmflux -h
usage: llmflux [-h] [--version] {run,serve,connect,benchmark,show-models,jobs,status,logs,cancel} ...
LLMFlux CLI
positional arguments:
{run,serve,connect,benchmark,show-models,jobs,status,logs,cancel}
run Submit a batch processing job
serve Start a model as a long-running service on a compute node
connect Show connection info for a running serve job
benchmark Run a benchmark job
show-models List all available model keys from models.yaml
jobs List LLMFlux tracked Slurm jobs
status Show detailed status for a job
logs Show last lines of stdout and stderr for a tracked job
cancel Cancel a tracked running/pending job
options:
-h, --help show this help message and exit
--version, -V Show llmflux version and exit
Quick Start
Core Batch Processing on SLURM
The primary workflow for LLMFlux is submitting JSONL files for batch processing on SLURM:
from llmflux.slurm import SlurmRunner
from llmflux.core.config import Config
# Setup SLURM configuration
config = Config()
slurm_config = config.get_slurm_config()
slurm_config.account = "myaccount"
# Initialize runner
runner = SlurmRunner(config=slurm_config)
# Submit JSONL file directly for processing
job_id = runner.run(
input_path="prompts.jsonl",
output_path="results.json",
model="Llama-3.2-3B-Instruct",
batch_size=4
)
print(f"Job submitted with ID: {job_id}")
JSONL Input Format
JSONL input format follows the OpenAI Batch API specification:
{"custom_id":"request1","method":"POST","url":"/v1/chat/completions","body":{"messages":[{"role":"system","content":"You are a helpful assistant"},{"role":"user","content":"Explain quantum computing"}],"temperature":0.7,"max_tokens":500}}
{"custom_id":"request2","method":"POST","url":"/v1/chat/completions","body":{"messages":[{"role":"system","content":"You are a helpful assistant"},{"role":"user","content":"What is machine learning?"}],"temperature":0.7,"max_tokens":500}}
For advanced options like custom batch sizes, processing settings, or SLURM configuration, see the Configuration Guide.
For advanced model configuration, see the Models Guide.
Command-Line Interface
LLMFlux uses vLLM as its default engine. Model keys come from models.yaml (see llmflux show-models). --output is optional — if omitted, results are written to a timestamped file in your configured output directory.
# Minimal: engine defaults to vllm, output path is auto-generated
llmflux run --model Llama-3.2-3B-Instruct --input data/prompts.jsonl
# Explicit engine and output path
llmflux run --model Llama-3.2-3B-Instruct --input data/prompts.jsonl --output results/output.json --engine vllm
# Use the Ollama engine instead
llmflux run --model Llama-3.2-3B-Instruct --input data/prompts.jsonl --engine ollama
# With SLURM account and partition
llmflux run \
--account your-account \
--partition gpu \
--model Llama-3.2-3B-Instruct \
--input data/prompts.jsonl \
--output results/output.json
The --model value must match a key from models.yaml (e.g. MistralLite, Llama-3.2-3B-Instruct). LLMFlux resolves the correct HuggingFace repo name (hf_name) and Ollama tag (name) automatically from that key.
Note that in order to use some HuggingFace models, you will need a token from HF. Once you have a token, update your
local copy of the .env file:
HUGGINGFACE_TOKEN=hf_XXXXXXXXXXXXXXX
For some gated repos, you will also need to visit the HuggingFace repository directly and accept the terms of access. The model cache defaults to ~/.cache/huggingface/hub. To change this, add to your .env:
HF_HOME=/path/to/dir
LLMFlux will automatically download the appropriate models for both Ollama and vLLM.
For detailed command options:
llmflux --help
Job Control Commands
LLMFlux tracks submitted jobs in a local registry (~/.llmflux/jobs.json) and
combines that metadata with Slurm state.
# List tracked jobs (default: active states only)
llmflux jobs
# Include historical states
llmflux jobs --all
# Filter by one or more states
llmflux jobs --state RUNNING --state FAILED
# Show detailed merged status for one job
llmflux status <job-id>
# Tail logs (default: 100 lines)
llmflux logs <job-id>
llmflux logs <job-id> --tail 200
llmflux logs <job-id> -f
# Cancel a tracked job
llmflux cancel <job-id>
llmflux cancel <job-id> --force
Notes:
jobsandstatusderive live state from Slurm JSON output.logsandcancelonly operate on jobs present in the LLMFlux registry.
Output Format
Results are saved in the user's workspace:
[
{
"input": {
"custom_id": "request1",
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"messages": [
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "Original prompt text"}
],
"temperature": 0.7,
"max_tokens": 1024
},
"metadata": {
"source_file": "example.txt"
}
},
"output": {
"id": "chat-cmpl-123",
"object": "chat.completion",
"created": 1699123456,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Generated response text"
},
"finish_reason": "stop"
}
]
},
"metadata": {
"model": "llama3.2:3b",
"timestamp": "2023-11-04T12:34:56.789Z",
"processing_time": 1.23
}
}
]
Utility Converters
LLMFlux provides utility converters to help prepare JSONL files from various input formats.
These are Python functions in llmflux.converters — there is no llmflux convert CLI
command. Call them from a script, then pass the resulting JSONL file to llmflux run.
Supported source types:
csv_to_jsonl— CSV files; useprompt_templatewith{column_name}placeholdersdirectory_to_jsonl— directories of text files (.txt,.md,.json,.py,.yaml,.yml); userecursive=Trueto traverse subdirectoriesjson_to_jsonl— existing JSON files already in batch or messages format
prompt_template syntax: Wrap column or field names in {braces} to interpolate values into the prompt. For example, "Summarize the following paper: {abstract}" pulls the abstract column from each CSV row.
from llmflux.converters import csv_to_jsonl, directory_to_jsonl, json_to_jsonl
# Convert CSV to JSONL using a prompt template
csv_to_jsonl(
input_path="data/papers.csv",
output_path="data/papers.jsonl",
prompt_template="Summarize: {text}",
)
# Convert a directory of text files to JSONL
directory_to_jsonl(
input_path="data/documents/",
output_path="data/docs.jsonl",
recursive=True,
)
# Convert an existing JSON file (batch or messages format) to JSONL
json_to_jsonl(
input_path="data/prompts.json",
output_path="data/prompts.jsonl",
)
See examples/csv_jsonl_example.py, examples/directory_jsonl_example.py, and
examples/json_jsonl_example.py for complete, runnable versions of the above.
Interactive Serving
In addition to batch processing, LLMFlux can start a model as a long-running OpenAI-compatible service on a compute node.
Start a serve job
llmflux serve \
--model Llama-3.2-3B-Instruct \
--email you@example.com \
--time 02:00:00 \
--engine vllm
--model— model key frommodels.yaml(same asllmflux run)--email— you will receive an email when the model is ready (not just when the job starts)--time— how long to keep the service alive (e.g.02:00:00,08:00:00)--engine—vllm(default) orollama
LLMFlux generates a unique API key for the session and prints the job ID:
Serve job submitted: 2301062
Model: Llama-3.2-3B-Instruct
Engine: vllm
Time: 02:00:00
Email: you@example.com
You will receive an email at you@example.com when the service is ready.
Then run: llmflux connect 2301062
Connect once the model is ready
After receiving the ready email, run:
llmflux connect 2301062
This pings the endpoint and prints everything you need:
Service is ready.
Endpoint: http://gpu-node-04:8031/v1
API Key: llmflux-57de4141f7d9b52a24481f05438c166c
Model: meta-llama/Llama-3.2-3B-Instruct
Engine: vllm
Example usage:
from openai import OpenAI
client = OpenAI(base_url="http://gpu-node-04:8031/v1", api_key="llmflux-57de4141f7d9b52a24481f05438c166c")
response = client.chat.completions.create(
model="meta-llama/Llama-3.2-3B-Instruct",
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
Check status and shut down
# See endpoint, API key, and email for a serve job
llmflux status 2301062
# Shut the service down early
llmflux cancel 2301062
llmflux jobs also shows a TYPE column (serve / batch) so you can
distinguish long-running services from batch jobs at a glance.
Benchmarking
LLMFlux ships with a benchmarking workflow that can source prompts, submit the SLURM job, and collect results/metrics for you.
llmflux benchmark \
--model Llama-3.2-3B-Instruct \
--name nightly \
--num-prompts 60 \
--account ACCOUNT_NAME \
--partition PARTITION_NAME \
--nodes 1
- Prompt sources: omit
--inputto automatically download and cache LiveBench categories (benchmark_data/). Provide--input path/to/prompts.jsonlto reuse an existing JSONL file instead. Use--num-prompts,--temperature, and--max-tokensto control synthetic dataset generation. - Outputs: results default to
results/benchmarks/<name>_results.jsonand a metrics summary (<name>_metrics.txt) containing elapsed SLURM runtime and number of prompts processed. - Batch tuning: adjust
--batch-sizefor throughput. Pass model arguments such as--temperatureand--max-tokensto forward them to the runner. - SLURM overrides: forward scheduler settings with
--account,--partition,--nodes,--gpus-per-node,--time,--mem, and--cpus-per-task. - Job controls: add
--rebuildto force an Apptainer image rebuild or--debugto keep the generated job script for inspection.
For the complete option reference:
llmflux benchmark --help
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llmflux-1.0.0.tar.gz.
File metadata
- Download URL: llmflux-1.0.0.tar.gz
- Upload date:
- Size: 92.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a9f122511b7fea316156af38f297ec16bf406ebb57c242f61d5ceac865a64b9
|
|
| MD5 |
90b69db4cb01af057d7eb390149a1a87
|
|
| BLAKE2b-256 |
4f7ac0ec819a18f246d4a28092da7998d90daa1fc9dd25cd11ec98d3ab352c6d
|
Provenance
The following attestation bundles were made for llmflux-1.0.0.tar.gz:
Publisher:
publish.yml on Center-for-AI-Innovation/LLMFlux
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llmflux-1.0.0.tar.gz -
Subject digest:
4a9f122511b7fea316156af38f297ec16bf406ebb57c242f61d5ceac865a64b9 - Sigstore transparency entry: 2129048434
- Sigstore integration time:
-
Permalink:
Center-for-AI-Innovation/LLMFlux@ff658ce5f08e0ee40da1153027e5ebfc713191fa -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/Center-for-AI-Innovation
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff658ce5f08e0ee40da1153027e5ebfc713191fa -
Trigger Event:
release
-
Statement type:
File details
Details for the file llmflux-1.0.0-py3-none-any.whl.
File metadata
- Download URL: llmflux-1.0.0-py3-none-any.whl
- Upload date:
- Size: 82.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e339cb3ef59bd76b945a874519d1d66d0cc04c8365f6069a68897940bfbb5dd1
|
|
| MD5 |
bdbfc4f00db116f1af8afc2bd9afbc24
|
|
| BLAKE2b-256 |
2ec238fe301170e9b36b2022e7041c45813b342de238f506f041d055bf045374
|
Provenance
The following attestation bundles were made for llmflux-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on Center-for-AI-Innovation/LLMFlux
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llmflux-1.0.0-py3-none-any.whl -
Subject digest:
e339cb3ef59bd76b945a874519d1d66d0cc04c8365f6069a68897940bfbb5dd1 - Sigstore transparency entry: 2129048787
- Sigstore integration time:
-
Permalink:
Center-for-AI-Innovation/LLMFlux@ff658ce5f08e0ee40da1153027e5ebfc713191fa -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/Center-for-AI-Innovation
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ff658ce5f08e0ee40da1153027e5ebfc713191fa -
Trigger Event:
release
-
Statement type: