CoolFace
Datasetpublic

EnRaoufi/warehouse-dpo-preference-pairs

Warehouse Short-Order DPO Preference Pairs Dataset Description This dataset contains {prompt, chosen, rejected} preference pairs for training a warehouse short-order assistant with Direct Preference Optimization (DPO). Each pair asks a real warehouse-inventory question (stockout risk, backorders, KPI summaries, why a warehouse is failing fulfillment - at a single-warehouse, tier, region, or dataset-wide comparison level) grounded in real tool-call output… See the full description on the dataset page: https://huggingface.co/datasets/EnRaoufi/warehouse-dpo-preference-pairs.

sourceHugging Facecc-by-4.0updated 1mo agoView on Hugging Face
0likes62downloads
Dataset Card

Warehouse Short-Order DPO Preference Pairs

Dataset Description

This dataset contains {prompt, chosen, rejected} preference pairs for training a warehouse short-order assistant with Direct Preference Optimization (DPO). Each pair asks a real warehouse-inventory question (stockout risk, backorders, KPI summaries, why a warehouse is failing fulfillment - at a single-warehouse, tier, region, or dataset-wide comparison level) grounded in real tool-call output, alongside a chosen response and a rejected response.

This is a derived work. The underlying warehouse facts (ids, quantities, categories, issue codes) come entirely from `electricsheepafrica/warehouse-inventory-management` (CC BY 4.0). The chosen/rejected response pairs themselves are not LLM-generated or collected from human annotators - they're built programmatically: chosen is constructed directly from real tool-call output (get_stockouts, get_warehouse_kpis, etc. run against the source data), and rejected is the same text with one or more deliberate flaws injected (a wrong warehouse id, a corrupted number, an invented category, an unwarranted hedge on a fully-answerable question, a degenerate repeated/looping response, or similar). See Preference Construction below for exactly how each pair was labeled, and Code for where every step of this actually happens.

Code

Full source: [github.com/EnsiyehRaoufi/DPO-Warehouse](https://github.com/EnsiyehRaoufi/DPO-Warehouse)

Three files are required to reproduce this dataset - it's a real dependency chain, not one standalone script:

filerole
data_utils.pyloads the source CSVs, and the underlying tool functions (get_stockouts, get_backorders, rank_shortage_risk, get_kpis/get_warehouse_kpis, get_dominant_issue/explain_inventory_issue) that return real, grounded values
assistant.pyanswer() formats real tool output into the chosen text; break_it()/_break() is where every rejected-generation flaw mode lives
gen_pairs.pybuild_prompts() generates the questions, gen_pair() calls into the two files above per prompt, label_pairs() scores both candidates (via score()) and assigns chosen/rejected

run.py orchestrates the full pipeline (data load -> prompts -> pairs -> DPO training -> eval) end to end; see the repo's README.md for exact run instructions and RUBRIC.md for the full scoring-dimension definitions referenced below.

Source Data

Source datasetelectricsheepafrica/warehouse-inventory-management
Source licenseCC BY 4.0
Source files usedwarehouse_district_store.csv, warehouse_national_central_medical_store.csv, warehouse_regional_warehouse.csv (one per warehouse tier)
Source size~30,000 rows across 297 unique warehouses (99 warehouse ids x 3 tiers)
This dataset's size400 preference pairs, built from a 210-row stratified sample of the source (see the companion source-data card, linked below, for exactly how that sample is built)

Known source-data gotcha, carried into this dataset's `scope`/`tool_out` fields: warehouse_id (e.g. WH_0009) is not globally unique in the source data - it's reused identically across all 3 tier files, so WH_0009 in district_store and WH_0009 in national_CMS are two different physical warehouses with different attributes (verified: 137 sqm vs. 3440 sqm). This dataset resolves that with a uid field ({warehouse_level}:{warehouse_id}), which is the real unique key used everywhere internally - never the bare warehouse_id alone.

Dataset Structure

Data Fields

Each line of dpo_pairs.jsonl or eval_pairs.jsonl is one preference pair (records.jsonl, also included in this repo, is a different schema entirely - see "Included Support File" below):

fieldtypedescription
qidstringunique id for this prompt (e.g. "T89")
promptstringthe full prompt sent to the model - a fixed system instruction, a tool call: <intent>(<scope>) -> <real tool output> context string, and the question
chosenstringthe higher-scoring of the two candidate responses (see Preference Construction)
rejectedstringthe lower-scoring candidate
chosen_score / rejected_scorefloat (0-1)the two candidates' scores under the project's 7-dimension rubric, equally weighted across all 7 (full definitions in RUBRIC.md)
tool_outobjectthe real tool-call output (numbers/ids) this prompt is grounded in - used at evaluation time to re-check any model's response against ground truth
scopeobjectthe warehouse/filter/compare scope this prompt targets, e.g. {"uid": "district_store:WH_0065"}, {"warehouse_level": "national_CMS"}, or {"compare_by": "region_type", "compare_values": [...]}
uncertainboolwhether the ground truth for this prompt genuinely has missing/provisional data. used two ways: to judge whether hedging language in a response is appropriate, and to decide whether the unwarranted-hedge negative examples (see Preference Construction) apply - those are only generated when this is false, i.e. real data was actually available
familystring"tool" (a full tool-call answer) or "field" (a single-field lookup) - all 400 pairs in the default 210-row sample run are "tool"; "field" pairs (qids prefixed S) only appear as a fallback if more prompts are requested than this generation scheme produces
intentstringwhich tool/question type this is: kpis, explain_issue, stockouts, backorders, or shortage_risk

Example Record

json
{
  "qid": "T89",
  "prompt": "You're a warehouse assistant. Answer using only the data given. Separate FACTS from RECOMMENDATION. Say if you're not sure. Don't make stuff up.\n\ntool call: kpis({'uid': 'district_store:WH_0065'}) -> {'n_records': 1, 'avg_inventory_accuracy_pct': 10.0, 'avg_order_fulfilment_rate_pct': 24.6, 'months_with_stockout': 0, 'issue_counts': {'FEFO_not_followed': 1}, 'uid': 'district_store:WH_0065', 'warehouse_id': 'WH_0065', 'warehouse_level': 'district_store'}\n\nQ: how is WH_0065 at the district_store doing overall?\nA:",
  "chosen": "FACTS: WH_0065 (district_store): avg inventory accuracy 10.0%, avg fulfilment 24.6%, 0 months w/ stockout (based on 1 records), issues on record: {'FEFO_not_followed': 1}\nRECOMMENDATION: looks fine.",
  "rejected": "FACTS: WH_0065 (district_store): avg inventory accuracy 25.8%, avg fulfilment 24.6%, 0 months w/ stockout (based on 1 records), issues on record: {'FEFO_not_followed': 1}\nRECOMMENDATION: looks fine.\nFACTS: WH_0065 (district_store): avg inventory accuracy 25.8%, avg fulfilment 24.6%, 0 months w/ stockout (based on 1 records), issues on record: {'FEFO_not_followed': 1}\nRECOMMENDATION: looks fine.",
  "chosen_score": 1.0,
  "rejected_score": 0.9286,
  "tool_out": {"n_records": 1, "avg_inventory_accuracy_pct": 10.0, "avg_order_fulfilment_rate_pct": 24.6, "months_with_stockout": 0, "issue_counts": {"FEFO_not_followed": 1}, "uid": "district_store:WH_0065", "warehouse_id": "WH_0065", "warehouse_level": "district_store"},
  "scope": {"uid": "district_store:WH_0065"},
  "uncertain": false,
  "family": "tool",
  "intent": "kpis"
}

Note this specific rejected example shows two flaws compounded onto one response, not just one: a corrupted number (10.0% -> 25.8%) plus the entire FACTS/RECOMMENDATION block repeated verbatim (a degenerate looping flaw). This is deliberate, not a bug - see Preference Construction below for why looping/redundancy flaws are only ever added on top of an already-substantive flaw like this one, never alone.

Splits

400 total pairs, split 340 train / 60 eval (an 85/15 split - the eval split is never seen during DPO training; it's scored before and after training to measure improvement). Provided as two separate files: dpo_pairs.jsonl (train) and eval_pairs.jsonl (eval).

Distribution by Intent

Uniform across all 5 intents, by design - each gets the same 16 fixed structural prompts (unscoped, tier filter, region filter, tier/region compare-all, tier/region compare-named) plus 64 single-warehouse prompts, drawn from one shared, stratified sample of warehouses (not picked independently per intent) that maximizes both tier and real issue-type variety - see the source-data card for how that sample is built.

intentcount
kpis80
explain_issue80
stockouts80
backorders80
shortage_risk80

Included Support File: records.jsonl

This repo also includes records.jsonl - the 210 raw, normalized warehouse records the pairs above were generated from. This is not a new or independently-sampled file - it's the exact same content published standalone as [`EnRaoufi/warehouse-inventory-stratified-sample`](https://huggingface.co/datasets/EnRaoufi/warehouse-inventory-stratified-sample), re-uploaded here for a practical reason specific to this project's evaluation design, not because it's a different dataset: the evaluation script (eval_model.py) needs the underlying records themselves - not just the per-pair tool_out already embedded above - to build the real, valid sets of commodity categories, issue reason codes, and tier/region labels it checks model responses against, and to score tool-selection accuracy. Without it, evaluation can still run but skips those checks. Including it here means this repo alone is enough to run training and evaluation end to end, without also needing to fetch the source-data card separately.

For the schema, and the stratified-sampling method used to build it in the first place, see that source data card directly - it isn't repeated here.

Preference Construction

No human annotators and no LLM were used to generate or label candidates. For each prompt:

  1. 1.`chosen` is built by calling the real tool function against the source data, then formatting the real output into a FACTS: ...\nRECOMMENDATION: ... template.
  2. 2.`rejected` is the same chosen text with one or more deliberate flaws injected, drawn from 14 distinct modes (plus a generic fallback) covering every one of the 7 scoring dimensions (full list and design rationale for each in RUBRIC.md/README.md) - including fabricated warehouse ids, corrupted numbers, invented categories/reasons/tiers/regions, dropped or mislabeled comparison groups, and a degenerate repeated/looping response. a structural-only flaw (looping or redundant repetition) is never the SOLE reason a response is rejected - it's only ever added on top of an already-substantive flaw, at a capped rate, so structure alone can't account for the whole gap between chosen and rejected. Specifically for prompts where the ground truth data genuinely IS available (uncertain: false), one of three distinct unwarranted-hedge shapes may also be injected: a generic refusal, the real facts kept intact but the recommendation hedges anyway, or a hedge phrase embedded within the facts themselves - weighted toward whichever shape best matches real observed model failures.
  3. 3.Both candidates are scored with the same 7 rubric dimensions used for evaluation (grounding against tool_out, structural quality, appropriate uncertainty, and freedom from fabricated ids/categories/reasons/tiers/regions), combined with equal weighting across all 7 to decide chosen/rejected. A separate, differently-weighted aggregate (operational_quality counted less heavily) is used only for the before/after comparison in the project's evaluation reports - not for labeling these pairs. Whichever candidate scores higher under the equal weighting becomes chosen; by construction this is almost always the real, uncorrupted answer.

Considerations

  • Synthetic preferences, not human feedback. This is a stand-in for human preference labeling - useful for a small-scale DPO demonstration, but the "preferences" reflect a fixed rubric's judgment, not real human raters. Don't treat chosen/rejected as ground truth for what a human would actually prefer.
  • Reflects the source data's real-world limitations, including whatever collection/coverage gaps exist in electricsheepafrica/warehouse-inventory-management itself. This dataset does not independently verify the source CSVs' accuracy.
  • Small scale. 400 pairs is enough for a demonstration DPO run on a small model, not a production-scale preference dataset.

Related Datasets

Licensing and Attribution

This dataset is a derivative of `electricsheepafrica/warehouse-inventory-management`, licensed CC BY 4.0 by Electric Sheep Africa. In keeping with that license's attribution requirement, this derived dataset is released under the same license, CC BY 4.0. The code that generates it (linked above) is separately licensed Apache-2.0, per the GitHub repository's LICENSE file.

Attribution: Warehouse facts derived from electricsheepafrica/warehouse-inventory-management (Electric Sheep Africa), https://huggingface.co/datasets/electricsheepafrica/warehouse-inventory-management, licensed CC BY 4.0.

Citation

bibtex
@misc{warehouse_dpo_pairs,
  title = {Warehouse Short-Order DPO Preference Pairs},
  author = {Raoufi, Ensiyeh},
  note = {Derived from electricsheepafrica/warehouse-inventory-management (CC BY 4.0). Code: https://github.com/EnsiyehRaoufi/DPO-Warehouse},
  howpublished = {\url{https://huggingface.co/datasets/EnRaoufi/warehouse-dpo-preference-pairs}}
}

Source dataset citation:

bibtex
@dataset{warehouse_inventory_management,
  author = {Electric Sheep Africa},
  title = {warehouse-inventory-management},
  publisher = {Hugging Face},
  howpublished = {\url{https://huggingface.co/datasets/electricsheepafrica/warehouse-inventory-management}}
}