@@ -27,6 +27,12 @@ def common_options(f: F) -> F:
2727 type = click .IntRange (min = 1 , clamp = True ),
2828 help = "Override default max tokens for generation." ,
2929 ),
30+ click .option (
31+ "--num-prompts" ,
32+ default = None ,
33+ type = click .IntRange (min = 1 , clamp = True ),
34+ help = "Limit number of prompts to use." ,
35+ ),
3036 ]
3137 for option in reversed (options ):
3238 f = option (f )
@@ -43,6 +49,30 @@ def _resolve_prompts(prompts: str) -> Path:
4349 raise click .BadParameter (str (exc )) from exc
4450
4551
52+ def _load_prompts (ctx : click .Context , prompts : str , max_tokens : int | None , num_prompts : int | None ) -> list [Any ]:
53+ """Load and prepare a prompt suite with overrides applied."""
54+ from infer_check .suites .loader import load_suite
55+
56+ # Update defaults from subcommand if provided
57+ if max_tokens is not None :
58+ ctx .obj ["max_tokens" ] = max_tokens
59+ if num_prompts is not None :
60+ ctx .obj ["num_prompts" ] = num_prompts
61+
62+ prompt_list = load_suite (_resolve_prompts (prompts ))
63+
64+ # Apply num_prompts limit
65+ if ctx .obj ["num_prompts" ] is not None :
66+ prompt_list = prompt_list [: ctx .obj ["num_prompts" ]]
67+
68+ # Apply global max_tokens only if not explicitly set in the prompt JSONL
69+ for p in prompt_list :
70+ if "max_tokens" not in p .model_fields_set :
71+ p .max_tokens = ctx .obj ["max_tokens" ]
72+
73+ return prompt_list
74+
75+
4676@click .group ()
4777@click .version_option (package_name = "infer-check" )
4878@click .option (
@@ -51,11 +81,18 @@ def _resolve_prompts(prompts: str) -> Path:
5181 show_default = True ,
5282 help = "Default max tokens for generation (applies to all prompts unless they specify their own)." ,
5383)
84+ @click .option (
85+ "--num-prompts" ,
86+ default = None ,
87+ type = click .IntRange (min = 1 , clamp = True ),
88+ help = "Limit the number of prompts to use from a suite; if omitted, all prompts are used." ,
89+ )
5490@click .pass_context
55- def main (ctx : click .Context , max_tokens : int ) -> None :
91+ def main (ctx : click .Context , max_tokens : int , num_prompts : int | None ) -> None :
5692 """infer-check: correctness and reliability testing for LLM inference engines."""
5793 ctx .ensure_object (dict )
5894 ctx .obj ["max_tokens" ] = max_tokens
95+ ctx .obj ["num_prompts" ] = num_prompts
5996
6097
6198# ---------------------------------------------------------------------------
@@ -103,6 +140,7 @@ def sweep(
103140 baseline : str | None ,
104141 base_url : str | None ,
105142 max_tokens : int | None ,
143+ num_prompts : int | None ,
106144) -> None :
107145 """Run a quantization sweep: compare pre-quantized models against a baseline.
108146
@@ -119,11 +157,8 @@ def sweep(
119157 """
120158 from infer_check .backends .base import get_backend_for_model
121159 from infer_check .runner import TestRunner
122- from infer_check .suites .loader import load_suite
123160
124- # Update max_tokens from subcommand if provided
125- if max_tokens is not None :
126- ctx .obj ["max_tokens" ] = max_tokens
161+ prompt_list = _load_prompts (ctx , prompts , max_tokens , num_prompts )
127162
128163 # Parse label=model_path pairs
129164 model_map : dict [str , str ] = {}
@@ -152,11 +187,6 @@ def sweep(
152187 for label , path in model_map .items ():
153188 tag = " (baseline)" if label == baseline_label else ""
154189 console .print (f" { label } : { path } { tag } " )
155- prompt_list = load_suite (_resolve_prompts (prompts ))
156- # Apply global max_tokens only if not explicitly set in the prompt JSONL
157- for p in prompt_list :
158- if "max_tokens" not in p .model_fields_set :
159- p .max_tokens = ctx .obj ["max_tokens" ]
160190
161191 # Build a separate backend for each model
162192 backend_map : dict [str , Any ] = {}
@@ -308,6 +338,7 @@ def compare(
308338 label_b : str | None ,
309339 report : bool ,
310340 max_tokens : int | None ,
341+ num_prompts : int | None ,
311342) -> None :
312343 """Compare two quantizations of the same model.
313344
@@ -335,11 +366,8 @@ def compare(
335366 # ── Resolve both model specs ─────────────────────────────────────
336367 from infer_check .resolve import resolve_model
337368 from infer_check .runner import TestRunner
338- from infer_check .suites .loader import load_suite
339369
340- # Update max_tokens from subcommand if provided
341- if max_tokens is not None :
342- ctx .obj ["max_tokens" ] = max_tokens
370+ prompt_list = _load_prompts (ctx , prompts , max_tokens , num_prompts )
343371
344372 resolved_a = resolve_model (model_a , base_url = base_url , label = label_a )
345373 resolved_b = resolve_model (model_b , base_url = base_url , label = label_b )
@@ -350,12 +378,6 @@ def compare(
350378 f"vs B={ resolved_b .label } ({ resolved_b .backend } )"
351379 )
352380
353- prompt_list = load_suite (_resolve_prompts (prompts ))
354- # Apply global max_tokens only if not explicitly set in the prompt JSONL
355- for p in prompt_list :
356- if "max_tokens" not in p .model_fields_set :
357- p .max_tokens = ctx .obj ["max_tokens" ]
358-
359381 console .print (f" prompts: { len (prompt_list )} from '{ prompts } '" )
360382
361383 # ── Build backends ───────────────────────────────────────────────
@@ -573,15 +595,13 @@ def diff(
573595 base_urls : str | None ,
574596 chat : bool ,
575597 max_tokens : int | None ,
598+ num_prompts : int | None ,
576599) -> None :
577600 """Compare outputs across different backends for the same model and prompts."""
578601 from infer_check .backends .base import BackendConfig , get_backend
579602 from infer_check .runner import TestRunner
580- from infer_check .suites .loader import load_suite
581603
582- # Update max_tokens from subcommand if provided
583- if max_tokens is not None :
584- ctx .obj ["max_tokens" ] = max_tokens
604+ prompt_list = _load_prompts (ctx , prompts , max_tokens , num_prompts )
585605
586606 backend_names = [b .strip () for b in backends .split ("," ) if b .strip ()]
587607 url_list : list [str | None ] = [u .strip () for u in base_urls .split ("," )] if base_urls else [None ] * len (backend_names )
@@ -591,12 +611,6 @@ def diff(
591611
592612 console .print (f"[bold cyan]diff[/bold cyan] model={ model } backends={ backend_names } quant={ quant } " )
593613
594- prompt_list = load_suite (_resolve_prompts (prompts ))
595- # Apply global max_tokens only if not explicitly set in the prompt JSONL
596- for p in prompt_list :
597- if "max_tokens" not in p .model_fields_set :
598- p .max_tokens = ctx .obj ["max_tokens" ]
599-
600614 backend_instances = []
601615 for name , url in zip (backend_names , url_list , strict = True ):
602616 config = BackendConfig (
@@ -693,15 +707,13 @@ def stress(
693707 concurrency : str ,
694708 base_url : str | None ,
695709 max_tokens : int | None ,
710+ num_prompts : int | None ,
696711) -> None :
697712 """Stress-test a backend with varying concurrency levels."""
698713 from infer_check .backends .base import get_backend_for_model
699714 from infer_check .runner import TestRunner
700- from infer_check .suites .loader import load_suite
701715
702- # Update max_tokens from subcommand if provided
703- if max_tokens is not None :
704- ctx .obj ["max_tokens" ] = max_tokens
716+ prompt_list = _load_prompts (ctx , prompts , max_tokens , num_prompts )
705717
706718 concurrency_levels = [int (c .strip ()) for c in concurrency .split ("," ) if c .strip ()]
707719
@@ -715,12 +727,6 @@ def stress(
715727 f"[bold cyan]stress[/bold cyan] model={ model } backend={ backend_instance .name } concurrency={ concurrency_levels } "
716728 )
717729
718- prompt_list = load_suite (_resolve_prompts (prompts ))
719- # Apply global max_tokens only if not explicitly set in the prompt JSONL
720- for p in prompt_list :
721- if "max_tokens" not in p .model_fields_set :
722- p .max_tokens = ctx .obj ["max_tokens" ]
723-
724730 runner = TestRunner ()
725731 stress_results = asyncio .run (
726732 runner .stress (
@@ -790,15 +796,13 @@ def determinism(
790796 runs : int ,
791797 base_url : str | None ,
792798 max_tokens : int | None ,
799+ num_prompts : int | None ,
793800) -> None :
794801 """Test whether a backend produces identical outputs across repeated runs at temperature=0."""
795802 from infer_check .backends .base import get_backend_for_model
796803 from infer_check .runner import TestRunner
797- from infer_check .suites .loader import load_suite
798804
799- # Update max_tokens from subcommand if provided
800- if max_tokens is not None :
801- ctx .obj ["max_tokens" ] = max_tokens
805+ prompt_list = _load_prompts (ctx , prompts , max_tokens , num_prompts )
802806
803807 backend_instance = get_backend_for_model (
804808 model_str = model ,
@@ -808,12 +812,6 @@ def determinism(
808812
809813 console .print (f"[bold cyan]determinism[/bold cyan] model={ model } backend={ backend_instance .name } runs={ runs } " )
810814
811- prompt_list = load_suite (_resolve_prompts (prompts ))
812- # Apply global max_tokens only if not explicitly set in the prompt JSONL
813- for p in prompt_list :
814- if "max_tokens" not in p .model_fields_set :
815- p .max_tokens = ctx .obj ["max_tokens" ]
816-
817815 runner = TestRunner ()
818816 det_results = asyncio .run (
819817 runner .determinism (
0 commit comments