Local LLMs for automated schema identification in MSstatsConvert.
MSstatsConvertLLM uses locally-hosted large language models (LLMs) to
automatically map the columns of arbitrary mass-spectrometry proteomics tool
output onto the standardized MSstats
analysis schema. Instead of relying on hand-written, tool-specific converters,
the package prompts a local LLM to infer column mappings (and quality-control
filters) and then feeds that mapping into the existing
MSstatsConvert pipeline, reducing
the manual overhead required to onboard new input formats.
The package provides two things:
- A generic converter —
LLMtoMSstatsFormat()takes raw tool output plus an LLM-produced mapping and returns a data.table in MSstats format, ready forMSstats::dataProcess(). - A benchmarking harness — tooling to evaluate how well different local models, prompt strategies, and tools recover the correct schema mapping, scored against curated ground truth.
This work was presented as a poster at ASMS 2026.
# install.packages("remotes")
remotes::install_github("Vitek-Lab/MSstatsConvertLLM")Or, from a local clone:
# install.packages("devtools")
devtools::install(".")- R >= 4.0
- MSstatsConvert (Bioconductor) — installed automatically as a dependency.
ellmer— the LLM chat interface, installed automatically as a dependency.- For live inference: Ollama running locally with at least one model pulled.
- (Optional) an
ANTHROPIC_API_KEYenvironment variable to benchmark against Claude models via the API. - (Optional) MSstats (Bioconductor) for the downstream comparison scripts.
library(MSstatsConvertLLM)
# Load a raw tool export (any proteomics tool: Spectronaut, DIA-NN, PD, ...)
input <- load_test_dataset("spectronaut") # or data.table::fread("your_file.csv")
# Ask a local model to infer the column mapping + filters
trial <- run_trial(
model_key = "llama3.1-8b",
tool_name = "spectronaut",
prompt_key = "constrained_filter",
acquisition = "DIA"
)
# Feed the LLM mapping into the MSstats converter
msstats_input <- LLMtoMSstatsFormat(
input = input,
annotation = "path/to/annotation.csv", # Run / Condition / BioReplicate
llm_mapping = trial$mapping
)
# Continue with the standard MSstats workflow
# processed <- MSstats::dataProcess(msstats_input)LLMtoMSstatsFormat() applies the LLM's discovered filters, renames and fills
columns to the MSstats schema, coerces types, merges the run annotation, removes
shared peptides, summarizes duplicate PSMs, and records diagnostics (e.g.
hallucinated columns, skipped filters) in attr(result, "diagnostics").
# Interactive single-trial test (edit the model/tool/prompt at the top)
Rscript run_one.R
# Full benchmark matrix (all models x tools x prompts x reps)
Rscript run_all.R
# Run a subset
Rscript run_all.R --models llama3.1-8b,deepseek-r1-14b --tools spectronaut --reps 1The runner scripts call library(MSstatsConvertLLM), so install the package (or
devtools::load_all(".")) before running them.
Each predicted field is scored against ground truth:
- ✅ exact_match — predicted column == primary expected column (case/punctuation normalized)
- 🟢 acceptable_match — predicted column matches the primary or an accepted alternate
- 🟡 candidate_hit — wrong primary pick, but the correct column appears in the
candidateslist - ❌ miss — neither the primary pick nor the candidates contain the correct mapping
MSstatsConvertLLM/
├── DESCRIPTION # Package metadata and dependencies
├── NAMESPACE # Exports / imports (generated by roxygen2)
├── R/
│ ├── MSstatsConvertLLM-package.R # Package doc, imports, globalVariables
│ ├── config.R # Model registry, ground truth, MSstats schema, helpers
│ ├── prompts.R # Lean / constrained / filter-aware prompt templates
│ ├── benchmark.R # create_chat(), run_trial(), score_trial(), print_scorecard()
│ └── LLMtoMSstatsFormat.R # Generic LLM-driven converter
├── man/ # Generated function documentation
├── run_one.R # Interactive single-trial driver
├── run_all.R # Full benchmark-matrix driver
├── analysis.R # Plots/summaries of benchmark results
├── compare_downstream.R # LLM vs. native converter -> dataProcess -> groupComparison
├── compare_navarro.R # Downstream comparison on the Navarro 2016 DIA benchmark
├── data/ # Local benchmark inputs (not shipped with the package)
└── results/ # Benchmark outputs (CSV / RDS / plots; not shipped)
The benchmark registries live in R/config.R. After editing them,
reinstall the package or re-run devtools::load_all(".") to pick up the changes.
In MODEL_REGISTRY:
MODEL_REGISTRY[["phi3-3.8b"]] <- list(
provider = "ollama",
model = "phi3:3.8b",
label = "Phi-3 3.8B"
)Then pull it in Ollama (ollama pull phi3:3.8b) and run:
Rscript run_all.R --models phi3-3.8b- Make the test file accessible (or use
MSstatsConverttest data). - In
R/config.R, register the dataset path inload_test_dataset()and add its ground-truth mapping toGROUND_TRUTH:
# In load_test_dataset() paths list:
diann_v18 = "/path/to/diann_v18_report.tsv"
# In GROUND_TRUTH (a character vector lists acceptable alternates):
GROUND_TRUTH[["diann_v18"]] <- list(
ProteinName = "Protein.Group",
PeptideSequence = "Modified.Sequence",
PrecursorCharge = "Precursor.Charge",
FragmentIon = NULL,
ProductCharge = NULL,
Run = "Run",
Intensity = "Fragment.Quant.Raw",
Qvalue = "Q.Value"
)Optionally set the acquisition type (TOOL_ACQUISITION) and whether to enable
packed-column transform detection (TOOL_TRANSFORMS) for the new tool.
In R/prompts.R, define your prompt string and register it:
PROMPT_FEWSHOT <- "..."
PROMPT_VERSIONS[["fewshot"]] <- PROMPT_FEWSHOTThe comparison scripts run both the LLM converter and the native
MSstatsConvert converter through the full MSstats workflow
(dataProcess() → groupComparison()) and compare summarized intensities,
log2 fold-changes, adjusted p-values, and empirical FDR:
compare_downstream.R— general downstream comparison.compare_navarro.R— species-labeled Navarro 2016 DIA benchmark, including FDR calibration.analysis.R— plots and summaries of the accuracy benchmark.
The data/ directory (Spectronaut input + annotation for the Navarro 2016 DIA
benchmark) is not versioned — the input file is large and lives on shared
storage. The next developer can obtain it from the Vitek Lab share:
/projects/VitekLab/Data/MS/Benchmarking/DIA_Navarro2016
Copy the Spectronaut input and annotation into a local data/ directory (or
update the RAW_PATH / ANNOT_PATH paths at the top of
compare_navarro.R to point at the share directly).
Imports (installed automatically): data.table, ellmer (LLM chat
interface), jsonlite, MSstatsConvert.
Suggests (optional; used by the downstream comparison scripts): MSstats,
ggplot2, stringr, testthat.
External: Ollama running locally with the desired models pulled (required for live inference).
If you use this work, please cite the associated ASMS 2026 poster (citation details TBD).