typellm 0.2.3__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {typellm-0.2.3/typellm.egg-info → typellm-0.2.5}/PKG-INFO +5 -4
- {typellm-0.2.3 → typellm-0.2.5}/README.md +4 -3
- {typellm-0.2.3 → typellm-0.2.5}/pyproject.toml +1 -1
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_concurrency.py +32 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_grammar_fields.py +1 -1
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_permutations.py +1 -1
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_typellm.py +26 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/cli.py +3 -2
- {typellm-0.2.3 → typellm-0.2.5}/typellm/runtime.py +40 -13
- {typellm-0.2.3 → typellm-0.2.5}/typellm/sglang.py +33 -20
- {typellm-0.2.3 → typellm-0.2.5/typellm.egg-info}/PKG-INFO +5 -4
- {typellm-0.2.3 → typellm-0.2.5}/LICENSE +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/setup.cfg +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_batching.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_dependencies.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_images.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_nullable.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_prefill.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_probabilities.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_prompts.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_protocols.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/tests/test_text.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/__init__.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/__main__.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/benchmark.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/images.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/protocol.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm/schema.py +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm.egg-info/SOURCES.txt +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm.egg-info/dependency_links.txt +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm.egg-info/entry_points.txt +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm.egg-info/requires.txt +0 -0
- {typellm-0.2.3 → typellm-0.2.5}/typellm.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typellm
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Type-Safe Decoding for Autoregressive LLMs
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://typellm.ai/
|
|
@@ -347,19 +347,20 @@ result = client.generate(
|
|
|
347
347
|
Only opted-in fields return `value` and `probabilities`; other fields return plain values.
|
|
348
348
|
The option is not supported on open Numeric or Text fields.
|
|
349
349
|
|
|
350
|
-
|
|
350
|
+
`temperature` is 0 by default: each field gets its most likely answer. Above 0,
|
|
351
|
+
TypeLLM samples at that temperature:
|
|
351
352
|
|
|
352
353
|
```python
|
|
353
354
|
client = TypeLLMClient(
|
|
354
355
|
"http://127.0.0.1:30000",
|
|
355
|
-
mode="sample",
|
|
356
356
|
temperature=0.8,
|
|
357
357
|
seed=42,
|
|
358
358
|
)
|
|
359
359
|
```
|
|
360
360
|
|
|
361
361
|
Sampling applies to finite candidates for Choice fields and to token generation
|
|
362
|
-
for Numeric and Text fields. `temperature`
|
|
362
|
+
for Numeric and Text fields. `generate(temperature=...)` sets it for one call.
|
|
363
|
+
The older `mode="argmax"` / `mode="sample"` still works for now but is deprecated.
|
|
363
364
|
|
|
364
365
|
A seed fixes TypeLLM's own random choices. SGLang's log probabilities can shift
|
|
365
366
|
with its prefix cache and batching, so the same seed may still give different
|
|
@@ -332,19 +332,20 @@ result = client.generate(
|
|
|
332
332
|
Only opted-in fields return `value` and `probabilities`; other fields return plain values.
|
|
333
333
|
The option is not supported on open Numeric or Text fields.
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
`temperature` is 0 by default: each field gets its most likely answer. Above 0,
|
|
336
|
+
TypeLLM samples at that temperature:
|
|
336
337
|
|
|
337
338
|
```python
|
|
338
339
|
client = TypeLLMClient(
|
|
339
340
|
"http://127.0.0.1:30000",
|
|
340
|
-
mode="sample",
|
|
341
341
|
temperature=0.8,
|
|
342
342
|
seed=42,
|
|
343
343
|
)
|
|
344
344
|
```
|
|
345
345
|
|
|
346
346
|
Sampling applies to finite candidates for Choice fields and to token generation
|
|
347
|
-
for Numeric and Text fields. `temperature`
|
|
347
|
+
for Numeric and Text fields. `generate(temperature=...)` sets it for one call.
|
|
348
|
+
The older `mode="argmax"` / `mode="sample"` still works for now but is deprecated.
|
|
348
349
|
|
|
349
350
|
A seed fixes TypeLLM's own random choices. SGLang's log probabilities can shift
|
|
350
351
|
with its prefix cache and batching, so the same seed may still give different
|
|
@@ -212,6 +212,38 @@ class DeadlineTests(unittest.TestCase):
|
|
|
212
212
|
client._generate({"text": "x"})
|
|
213
213
|
self.assertNotIsInstance(caught.exception, GenerationTimeout)
|
|
214
214
|
|
|
215
|
+
def dropping(self, error, times):
|
|
216
|
+
"""A client whose server drops the first `times` requests with `error`."""
|
|
217
|
+
seen = []
|
|
218
|
+
|
|
219
|
+
def handler(request):
|
|
220
|
+
seen.append(request)
|
|
221
|
+
if len(seen) <= times:
|
|
222
|
+
raise error("connection dropped", request=request)
|
|
223
|
+
return httpx.Response(200, json={"text": "ok"})
|
|
224
|
+
|
|
225
|
+
client = SGLangClient()
|
|
226
|
+
client._http_client = httpx.Client(transport=httpx.MockTransport(handler))
|
|
227
|
+
return client, seen
|
|
228
|
+
|
|
229
|
+
def test_a_dropped_connection_is_retried_once(self):
|
|
230
|
+
for error in (httpx.ReadError, httpx.RemoteProtocolError, httpx.WriteError):
|
|
231
|
+
client, seen = self.dropping(error, 1)
|
|
232
|
+
with self.subTest(error=error.__name__):
|
|
233
|
+
self.assertEqual(client._request("/generate", {"text": "x"}), {"text": "ok"})
|
|
234
|
+
self.assertEqual(len(seen), 2)
|
|
235
|
+
client, seen = self.dropping(httpx.ReadError, 2)
|
|
236
|
+
with self.assertRaisesRegex(SGLangError, "Could not reach"):
|
|
237
|
+
client._request("/generate", {"text": "x"})
|
|
238
|
+
self.assertEqual(len(seen), 2)
|
|
239
|
+
|
|
240
|
+
def test_a_refused_connection_is_not_retried(self):
|
|
241
|
+
for error in (httpx.ConnectError, httpx.ReadTimeout):
|
|
242
|
+
client, seen = self.dropping(error, 1)
|
|
243
|
+
with self.subTest(error=error.__name__), self.assertRaises(SGLangError):
|
|
244
|
+
client._request("/generate", {"text": "x"})
|
|
245
|
+
self.assertEqual(len(seen), 1)
|
|
246
|
+
|
|
215
247
|
def test_invalid_budgets_are_rejected(self):
|
|
216
248
|
class Recording(FakeServer):
|
|
217
249
|
def _request(self, path, payload=None, *, allow_text=False):
|
|
@@ -87,7 +87,7 @@ class GrammarNumberTests(unittest.TestCase):
|
|
|
87
87
|
self.assertIn("null", patterns[3])
|
|
88
88
|
|
|
89
89
|
def test_sampling_passes_the_temperature_and_no_truncation(self):
|
|
90
|
-
client = TypeLLMClient(model="fake",
|
|
90
|
+
client = TypeLLMClient(model="fake", temperature=0.7, seed=1)
|
|
91
91
|
client.sglang = FakeServer()
|
|
92
92
|
client.generate(context="Receipt", questions={"a": {"type": "integer"}})
|
|
93
93
|
[params] = regex_requests(client.sglang)[0]["sampling_params"]
|
|
@@ -39,7 +39,7 @@ class PermutationTests(unittest.TestCase):
|
|
|
39
39
|
|
|
40
40
|
def test_sampling_uses_averaged_distribution(self):
|
|
41
41
|
with patch('typellm.runtime._sample', return_value='B') as sample:
|
|
42
|
-
_client, result = self.run_case(False, ['one', 'two', 'three'],
|
|
42
|
+
_client, result = self.run_case(False, ['one', 'two', 'three'], temperature=.5)
|
|
43
43
|
self.assertEqual(result['roll']['value'], 'two')
|
|
44
44
|
self.assertEqual(sample.call_count, 2) # one final choice plus the boolean
|
|
45
45
|
for p in sample.call_args_list[0].args[0].values():
|
|
@@ -909,3 +909,29 @@ class JsonSchemaExecutionTests(unittest.TestCase):
|
|
|
909
909
|
|
|
910
910
|
if __name__ == "__main__":
|
|
911
911
|
unittest.main()
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
class DecodingTests(unittest.TestCase):
|
|
915
|
+
def test_temperature_alone_decides(self):
|
|
916
|
+
from typellm.runtime import _resolve_decoding
|
|
917
|
+
|
|
918
|
+
self.assertEqual(_resolve_decoding(None, None), ("argmax", 0.0))
|
|
919
|
+
self.assertEqual(_resolve_decoding(None, 0), ("argmax", 0.0))
|
|
920
|
+
self.assertEqual(_resolve_decoding(None, 0.7), ("sample", 0.7))
|
|
921
|
+
for bad in (-1, float("nan"), True, "1"):
|
|
922
|
+
with self.assertRaises(ValueError):
|
|
923
|
+
_resolve_decoding(None, bad)
|
|
924
|
+
|
|
925
|
+
def test_deprecated_mode_still_works(self):
|
|
926
|
+
from typellm.runtime import _resolve_decoding
|
|
927
|
+
|
|
928
|
+
with self.assertWarns(DeprecationWarning):
|
|
929
|
+
self.assertEqual(_resolve_decoding("sample", None), ("sample", 1.0))
|
|
930
|
+
with self.assertWarns(DeprecationWarning):
|
|
931
|
+
self.assertEqual(_resolve_decoding("argmax", 0.7)[0], "argmax")
|
|
932
|
+
with self.assertWarns(DeprecationWarning), self.assertRaises(ValueError):
|
|
933
|
+
_resolve_decoding("sample", 0)
|
|
934
|
+
|
|
935
|
+
def test_call_temperature_overrides_client(self):
|
|
936
|
+
client = TypeLLMClient(model="fake", temperature=0.7)
|
|
937
|
+
self.assertEqual((client.mode, client.temperature), ("sample", 0.7))
|
|
@@ -51,8 +51,9 @@ def main() -> None:
|
|
|
51
51
|
default=os.environ.get("TYPELLM_TOKENIZER"),
|
|
52
52
|
help="Tokenizer path or Hugging Face ID; normally discovered from SGLang",
|
|
53
53
|
)
|
|
54
|
-
parser.add_argument("--
|
|
55
|
-
|
|
54
|
+
parser.add_argument("--temperature", type=float, default=0.0,
|
|
55
|
+
help="0 picks the most likely answer; above 0 samples")
|
|
56
|
+
parser.add_argument("--mode", choices=("argmax", "sample"), help="deprecated; use --temperature")
|
|
56
57
|
parser.add_argument("--numeric-max-digits", type=int, default=32)
|
|
57
58
|
parser.add_argument("--seed", type=int, default=0)
|
|
58
59
|
parser.add_argument("--probabilities", action="store_true")
|
|
@@ -8,6 +8,7 @@ import math
|
|
|
8
8
|
import os
|
|
9
9
|
import random
|
|
10
10
|
import threading
|
|
11
|
+
import warnings
|
|
11
12
|
from contextlib import nullcontext
|
|
12
13
|
from contextvars import ContextVar
|
|
13
14
|
from dataclasses import dataclass, replace
|
|
@@ -149,8 +150,8 @@ class TypeLLMClient:
|
|
|
149
150
|
base_url: str = "http://127.0.0.1:30000",
|
|
150
151
|
model: str | None = None,
|
|
151
152
|
*,
|
|
152
|
-
mode: str =
|
|
153
|
-
temperature: float =
|
|
153
|
+
mode: str | None = None,
|
|
154
|
+
temperature: float | None = None,
|
|
154
155
|
seed: int | None = None,
|
|
155
156
|
timeout: float = 120.0,
|
|
156
157
|
label_pool: Sequence[str] | None = None,
|
|
@@ -159,7 +160,10 @@ class TypeLLMClient:
|
|
|
159
160
|
thinking_budget: int | None = None,
|
|
160
161
|
text_max_tokens: int = 128,
|
|
161
162
|
) -> None:
|
|
162
|
-
|
|
163
|
+
"""temperature 0 (the default) picks the most likely answer; above 0
|
|
164
|
+
samples at that temperature. mode is deprecated: temperature alone decides.
|
|
165
|
+
"""
|
|
166
|
+
mode, temperature = _resolve_decoding(mode, temperature)
|
|
163
167
|
if type(numeric_max_digits) is not int or numeric_max_digits <= 0:
|
|
164
168
|
raise ValueError("numeric_max_digits must be a positive integer")
|
|
165
169
|
self.sglang = SGLangClient(
|
|
@@ -387,9 +391,13 @@ class TypeLLMClient:
|
|
|
387
391
|
if not isinstance(questions, Mapping):
|
|
388
392
|
raise SchemaError("questions must be a mapping of field names to definitions")
|
|
389
393
|
schema = {"type": "object", "properties": questions}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
394
|
+
if mode is None and temperature is None:
|
|
395
|
+
active_mode, active_temperature = self.mode, self.temperature
|
|
396
|
+
else:
|
|
397
|
+
# A call's own temperature decides for it, whatever the client's mode.
|
|
398
|
+
if temperature is None:
|
|
399
|
+
temperature = self.temperature or None
|
|
400
|
+
active_mode, active_temperature = _resolve_decoding(mode, temperature)
|
|
393
401
|
rng = self.rng if seed is None else random.Random(seed)
|
|
394
402
|
# The time budget covers compiling too: labels are tokenized by SGLang.
|
|
395
403
|
with call_scope(timeout, cancel) as scope:
|
|
@@ -462,11 +470,30 @@ def _sample(probs: Mapping[str, float], rng: random.Random) -> str:
|
|
|
462
470
|
return last
|
|
463
471
|
|
|
464
472
|
|
|
465
|
-
def
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
473
|
+
def _resolve_decoding(mode: str | None, temperature: float | None) -> tuple[str, float]:
|
|
474
|
+
"""The (mode, temperature) that temperature, and the deprecated mode, ask for.
|
|
475
|
+
|
|
476
|
+
temperature 0 picks the most likely answer (argmax); above 0 samples. For
|
|
477
|
+
older code, mode="sample" without a temperature samples at 1.0 and
|
|
478
|
+
mode="argmax" is argmax whatever the temperature.
|
|
479
|
+
"""
|
|
480
|
+
if mode is not None:
|
|
481
|
+
warnings.warn("mode is deprecated; temperature 0 picks the most likely answer and "
|
|
482
|
+
"above 0 samples", DeprecationWarning, stacklevel=3)
|
|
483
|
+
if mode not in {"argmax", "sample"}:
|
|
484
|
+
raise ValueError("mode must be 'argmax' or 'sample'")
|
|
485
|
+
if mode == "sample" and temperature is None:
|
|
486
|
+
temperature = 1.0
|
|
487
|
+
if temperature is None:
|
|
488
|
+
temperature = 0.0
|
|
489
|
+
if (isinstance(temperature, bool) or not isinstance(temperature, (int, float))
|
|
490
|
+
or not math.isfinite(temperature) or temperature < 0):
|
|
491
|
+
raise ValueError("temperature must be a finite number >= 0")
|
|
492
|
+
if mode == "argmax":
|
|
493
|
+
return "argmax", float(temperature)
|
|
494
|
+
if mode == "sample" and temperature == 0:
|
|
495
|
+
raise ValueError("temperature must be > 0 in sample mode")
|
|
496
|
+
return ("sample" if temperature > 0 else "argmax"), float(temperature)
|
|
470
497
|
|
|
471
498
|
|
|
472
499
|
def _numeric_text_is_complete(text: str, numeric_type: str) -> bool:
|
|
@@ -922,8 +949,8 @@ def _print_final_prompts(prefixes: Sequence[str]) -> None:
|
|
|
922
949
|
def run_schema(
|
|
923
950
|
context: str | None = None,
|
|
924
951
|
schema: Mapping[str, Any] | None = None,
|
|
925
|
-
mode: str =
|
|
926
|
-
temperature: float =
|
|
952
|
+
mode: str | None = None,
|
|
953
|
+
temperature: float | None = None,
|
|
927
954
|
*,
|
|
928
955
|
state: str | None = None,
|
|
929
956
|
questions: Mapping[str, Any] | None = None,
|
|
@@ -252,9 +252,11 @@ class SGLangClient:
|
|
|
252
252
|
def _http(self) -> httpx.Client:
|
|
253
253
|
with self._load_lock:
|
|
254
254
|
if self._http_client is None:
|
|
255
|
-
# Keep-alive connections: one call makes many small requests.
|
|
255
|
+
# Keep-alive connections: one call makes many small requests. Idle
|
|
256
|
+
# ones are dropped before SGLang closes them (5 s), so a request
|
|
257
|
+
# rarely goes out on a connection the server has just closed.
|
|
256
258
|
self._http_client = httpx.Client(limits=httpx.Limits(
|
|
257
|
-
max_connections=None, max_keepalive_connections=64,
|
|
259
|
+
max_connections=None, max_keepalive_connections=64, keepalive_expiry=2.0,
|
|
258
260
|
))
|
|
259
261
|
return self._http_client
|
|
260
262
|
|
|
@@ -269,24 +271,15 @@ class SGLangClient:
|
|
|
269
271
|
scope = _call_scope.get()
|
|
270
272
|
timeout = self.timeout if scope is None else scope.socket_timeout(self.timeout)
|
|
271
273
|
try:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
try:
|
|
282
|
-
detail = response.read().decode("utf-8", errors="replace")
|
|
283
|
-
except httpx.HTTPError as read_error:
|
|
284
|
-
detail = f"Could not read error response: {read_error}"
|
|
285
|
-
raise SGLangError(
|
|
286
|
-
f"SGLang {path} returned HTTP {response.status_code}: {detail}",
|
|
287
|
-
status=response.status_code,
|
|
288
|
-
)
|
|
289
|
-
raw = response.read().decode("utf-8")
|
|
274
|
+
try:
|
|
275
|
+
raw = self._send(path, payload is None, body, timeout)
|
|
276
|
+
except (httpx.ReadError, httpx.WriteError, httpx.RemoteProtocolError):
|
|
277
|
+
# The connection dropped before an answer, most often a pooled one
|
|
278
|
+
# the server had just closed. SGLang is fine: try once on a new one.
|
|
279
|
+
if scope is not None:
|
|
280
|
+
scope.check()
|
|
281
|
+
timeout = scope.socket_timeout(self.timeout)
|
|
282
|
+
raw = self._send(path, payload is None, body, timeout)
|
|
290
283
|
except httpx.HTTPError as exc:
|
|
291
284
|
# Connection failures, timeouts, resets and truncated responses.
|
|
292
285
|
raise SGLangError(
|
|
@@ -301,6 +294,26 @@ class SGLangClient:
|
|
|
301
294
|
f"SGLang {path} returned non-JSON data: {raw[:500]}"
|
|
302
295
|
) from exc
|
|
303
296
|
|
|
297
|
+
def _send(self, path: str, get: bool, body: bytes | None, timeout: float) -> str:
|
|
298
|
+
# Streamed so a failed body read still reports the status it follows.
|
|
299
|
+
with self._http().stream(
|
|
300
|
+
"GET" if get else "POST",
|
|
301
|
+
self.base_url + path,
|
|
302
|
+
content=body,
|
|
303
|
+
headers={"Content-Type": "application/json"},
|
|
304
|
+
timeout=timeout,
|
|
305
|
+
) as response:
|
|
306
|
+
if response.status_code >= 400:
|
|
307
|
+
try:
|
|
308
|
+
detail = response.read().decode("utf-8", errors="replace")
|
|
309
|
+
except httpx.HTTPError as read_error:
|
|
310
|
+
detail = f"Could not read error response: {read_error}"
|
|
311
|
+
raise SGLangError(
|
|
312
|
+
f"SGLang {path} returned HTTP {response.status_code}: {detail}",
|
|
313
|
+
status=response.status_code,
|
|
314
|
+
)
|
|
315
|
+
return response.read().decode("utf-8")
|
|
316
|
+
|
|
304
317
|
@contextmanager
|
|
305
318
|
def images(self, images: Sequence[str]) -> Iterator[None]:
|
|
306
319
|
"""Attach encoded images to every /generate request made in this block."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typellm
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Type-Safe Decoding for Autoregressive LLMs
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://typellm.ai/
|
|
@@ -347,19 +347,20 @@ result = client.generate(
|
|
|
347
347
|
Only opted-in fields return `value` and `probabilities`; other fields return plain values.
|
|
348
348
|
The option is not supported on open Numeric or Text fields.
|
|
349
349
|
|
|
350
|
-
|
|
350
|
+
`temperature` is 0 by default: each field gets its most likely answer. Above 0,
|
|
351
|
+
TypeLLM samples at that temperature:
|
|
351
352
|
|
|
352
353
|
```python
|
|
353
354
|
client = TypeLLMClient(
|
|
354
355
|
"http://127.0.0.1:30000",
|
|
355
|
-
mode="sample",
|
|
356
356
|
temperature=0.8,
|
|
357
357
|
seed=42,
|
|
358
358
|
)
|
|
359
359
|
```
|
|
360
360
|
|
|
361
361
|
Sampling applies to finite candidates for Choice fields and to token generation
|
|
362
|
-
for Numeric and Text fields. `temperature`
|
|
362
|
+
for Numeric and Text fields. `generate(temperature=...)` sets it for one call.
|
|
363
|
+
The older `mode="argmax"` / `mode="sample"` still works for now but is deprecated.
|
|
363
364
|
|
|
364
365
|
A seed fixes TypeLLM's own random choices. SGLang's log probabilities can shift
|
|
365
366
|
with its prefix cache and batching, so the same seed may still give different
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|