From 69eecb8d5cf244ebab0d9cfce1f35817af4dcc06 Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sun, 18 Oct 2026 10:42:00 +0300 Subject: [PATCH] docs(export): say that the GGUF converter script is not installed by the export extra forgelm export runs llama.cpp's convert_hf_to_gguf.py with ForgeLM's own Python. The installation page, the export extra's comment in pyproject.toml, the module docstring, the usage and quickstart guides and the post-training notebook said it was llama-cpp-python's "bundled" script, and the error hint advised `pip install 'llama-cpp-python>=0.2.90'`. No released wheel puts the script where ForgeLM searches (0.2.90 installs it under bin/, 0.3.x does not ship it), so a plain install ends with "convert_hf_to_gguf.py not found inside the llama-cpp-python installation" (exit 2) unless FORGELM_GGUF_CONVERTER points at the script in a llama.cpp checkout. The upstream script imports sibling modules (conversion, gguf), which is why the checkout's copy has to be used; the upstream repository and the requirements path were checked. The pages now say so, with the two commands that make it work; the error message names FORGELM_GGUF_CONVERTER and a llama.cpp checkout instead of a reinstall, and a test pins that. Searching the locations real wheels use, or bundling the script, are code changes and stay open. Refs #113, #83 Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 7 +++++++ docs/guides/quickstart-tr.md | 3 ++- docs/guides/quickstart.md | 3 ++- docs/reference/usage-tr.md | 3 ++- docs/reference/usage.md | 3 ++- .../en/getting-started/installation.md | 11 +++++++++- docs/usermanuals/en/reference/cli.md | 2 +- .../tr/getting-started/installation.md | 11 +++++++++- docs/usermanuals/tr/reference/cli.md | 2 +- forgelm/export.py | 20 ++++++++++--------- notebooks/post_training_workflow.ipynb | 6 ++++-- pyproject.toml | 6 ++++-- tests/test_export.py | 4 ++++ 13 files changed, 60 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d44dd02..fe837fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,13 @@ All notable changes to ForgeLM are documented here. ### Fixed +- Stop saying that `pip install 'forgelm[export]'` brings the GGUF converter. `forgelm export` runs llama.cpp's `convert_hf_to_gguf.py`; + no `llama-cpp-python` wheel puts it where ForgeLM searches (0.2.90 installs it under `bin/`, 0.3.x does not ship it), so a plain + install ends with `convert_hf_to_gguf.py not found inside the llama-cpp-python installation` (exit 2) unless `FORGELM_GGUF_CONVERTER` + points at the script in a llama.cpp checkout. The installation page, the CLI reference, the usage and quickstart guides, the + post-training notebook, the `export` extra's comment in `pyproject.toml`, the module docstring and the error message (which advised + `pip install 'llama-cpp-python>=0.2.90'`) now say so. Searching the locations real wheels use, or bundling the script, is a code + change and stays open (#113). - Fix the KTO bullet on the Alignment overview user-manual page (English and Turkish): it named the fields `(prompt, response, good?)`, but the KTO loader reads `prompt`, `completion` and a boolean `label` (#965). diff --git a/docs/guides/quickstart-tr.md b/docs/guides/quickstart-tr.md index 43b6ab2a..e239e28c 100644 --- a/docs/guides/quickstart-tr.md +++ b/docs/guides/quickstart-tr.md @@ -204,7 +204,8 @@ Eğitilmiş modelinizle doğrudan etkileşim kurun ve deploy edin: forgelm chat ./checkpoints/final_model # GGUF'a export (Ollama, LM Studio, llama.cpp için) -# Gerekli: pip install forgelm[export] +# Gerekli: pip install forgelm[export] VE FORGELM_GGUF_CONVERTER'ın bir llama.cpp checkout'undaki +# convert_hf_to_gguf.py'ye işaret etmesi (hiçbir llama-cpp-python wheel'i onu ForgeLM'in baktığı yere koymaz) forgelm export ./checkpoints/final_model --output model.gguf --quant q4_k_m # Deployment config'leri üret (sunucu başlatılmaz) diff --git a/docs/guides/quickstart.md b/docs/guides/quickstart.md index d91cb21d..f95362fe 100644 --- a/docs/guides/quickstart.md +++ b/docs/guides/quickstart.md @@ -191,7 +191,8 @@ Interact with and deploy your trained model directly: forgelm chat ./checkpoints/final_model # Export to GGUF (for Ollama, LM Studio, llama.cpp) -# Requires: pip install forgelm[export] +# Requires: pip install forgelm[export] AND FORGELM_GGUF_CONVERTER pointing at convert_hf_to_gguf.py +# from a llama.cpp checkout (no llama-cpp-python wheel installs it where ForgeLM looks) forgelm export ./checkpoints/final_model --output model.gguf --quant q4_k_m # Generate deployment configs (no server is started) diff --git a/docs/reference/usage-tr.md b/docs/reference/usage-tr.md index 9ebfa152..7bd9fa34 100644 --- a/docs/reference/usage-tr.md +++ b/docs/reference/usage-tr.md @@ -128,7 +128,8 @@ forgelm chat ./checkpoints/final_model --adapter ./adapter forgelm chat ./checkpoints/final_model --system "Yardımcı bir asistansın." --temperature 0.8 # GGUF'a export (Ollama, LM Studio, llama.cpp için) -# Gerekli: pip install forgelm[export] +# Gerekli: pip install forgelm[export] VE FORGELM_GGUF_CONVERTER'ın bir llama.cpp checkout'undaki +# convert_hf_to_gguf.py'ye işaret etmesi (hiçbir llama-cpp-python wheel'i onu ForgeLM'in baktığı yere koymaz) forgelm export ./checkpoints/final_model --output model.gguf --quant q4_k_m forgelm export ./checkpoints/final_model --output model.gguf --quant q8_0 --adapter ./adapter diff --git a/docs/reference/usage.md b/docs/reference/usage.md index 5676a080..4b9f1187 100644 --- a/docs/reference/usage.md +++ b/docs/reference/usage.md @@ -145,7 +145,8 @@ forgelm chat ./checkpoints/final_model --adapter ./adapter forgelm chat ./checkpoints/final_model --system "You are a helpful assistant." --temperature 0.8 # Export to GGUF (for Ollama, LM Studio, llama.cpp) -# Requires: pip install forgelm[export] +# Requires: pip install forgelm[export] AND FORGELM_GGUF_CONVERTER pointing at convert_hf_to_gguf.py +# from a llama.cpp checkout (no llama-cpp-python wheel installs it where ForgeLM looks) forgelm export ./checkpoints/final_model --output model.gguf --quant q4_k_m forgelm export ./checkpoints/final_model --output model.gguf --quant q8_0 --adapter ./adapter diff --git a/docs/usermanuals/en/getting-started/installation.md b/docs/usermanuals/en/getting-started/installation.md index 591e25f0..a943d0f0 100644 --- a/docs/usermanuals/en/getting-started/installation.md +++ b/docs/usermanuals/en/getting-started/installation.md @@ -75,7 +75,16 @@ Adds MinHash LSH (via `datasketch`) for near-duplicate detection on corpora bigg $ pip install 'forgelm[export]' ``` -Adds quantized GGUF export for local inference (Ollama, llama.cpp). Pulls in the `gguf` writer and supporting libraries. Optional because not every workflow ends in GGUF — many users hand off to vLLM or TGI directly. +Adds quantized GGUF export for local inference (Ollama, llama.cpp). Pulls in `llama-cpp-python`. Optional because not every workflow ends in GGUF — many users hand off to vLLM or TGI directly. + +**The conversion script is not included.** `forgelm export` runs llama.cpp's `convert_hf_to_gguf.py` with ForgeLM's own Python. No `llama-cpp-python` wheel puts that script where ForgeLM looks, so with only the extra installed `forgelm export` stops with `convert_hf_to_gguf.py not found inside the llama-cpp-python installation` (exit 2). Clone llama.cpp and point `FORGELM_GGUF_CONVERTER` at the script in that checkout: + +```shell +$ git clone https://github.com/ggml-org/llama.cpp +$ export FORGELM_GGUF_CONVERTER="$PWD/llama.cpp/convert_hf_to_gguf.py" +``` + +Use the copy inside the checkout: current versions import sibling modules (`conversion`, `gguf`) that sit beside it, and the script needs the Python packages listed in the checkout's `requirements/` folder importable in the environment ForgeLM runs in. K-quant levels additionally need llama.cpp's `llama-quantize` binary (see [GGUF export](#/deployment/gguf-export)). ### Distributed training (`[distributed]`) diff --git a/docs/usermanuals/en/reference/cli.md b/docs/usermanuals/en/reference/cli.md index a9423316..e286fbb8 100644 --- a/docs/usermanuals/en/reference/cli.md +++ b/docs/usermanuals/en/reference/cli.md @@ -327,7 +327,7 @@ See [Exit Codes](#/reference/exit-codes) for the full contract. | `FORGELM_OPERATOR` | Operator identity recorded in audit events (overrides `getpass.getuser()@hostname`) | | `FORGELM_ALLOW_ANONYMOUS_OPERATOR` | When `1`, permit the audit log to record an anonymous operator (otherwise an unresolved identity is an error) | | `FORGELM_AUDIT_SECRET` | HMAC signing key for the audit log chain (enables tamper-detection) | -| `FORGELM_GGUF_CONVERTER` | Path to a custom `convert-hf-to-gguf.py` script | +| `FORGELM_GGUF_CONVERTER` | Path to `convert_hf_to_gguf.py` inside a llama.cpp checkout. In practice required: no `llama-cpp-python` wheel installs the script where ForgeLM searches (see [Installation](#/getting-started/installation)) | ## Common patterns diff --git a/docs/usermanuals/tr/getting-started/installation.md b/docs/usermanuals/tr/getting-started/installation.md index 5c5517a5..bdf196c9 100644 --- a/docs/usermanuals/tr/getting-started/installation.md +++ b/docs/usermanuals/tr/getting-started/installation.md @@ -75,7 +75,16 @@ $ pip install 'forgelm[ingestion-scale]' $ pip install 'forgelm[export]' ``` -Yerel inference için (Ollama, llama.cpp) kuantize GGUF export'u ekler. `gguf` writer'ı ve destekleyici kütüphaneleri kurar. Opsiyonel çünkü her iş akışı GGUF ile bitmez — birçok kullanıcı doğrudan vLLM veya TGI'a teslim eder. +Yerel inference için (Ollama, llama.cpp) kuantize GGUF export'u ekler. `llama-cpp-python`'ı kurar. Opsiyonel çünkü her iş akışı GGUF ile bitmez — birçok kullanıcı doğrudan vLLM veya TGI'a teslim eder. + +**Dönüştürme script'i pakete dahil değildir.** `forgelm export`, llama.cpp'nin `convert_hf_to_gguf.py` script'ini ForgeLM'in kendi Python'uyla çalıştırır. Hiçbir `llama-cpp-python` wheel'i o script'i ForgeLM'in aradığı yere koymaz; bu yüzden yalnızca extra kuruluyken `forgelm export` `convert_hf_to_gguf.py not found inside the llama-cpp-python installation` hatasıyla (exit 2) durur. llama.cpp'yi klonlayın ve `FORGELM_GGUF_CONVERTER`'ı o checkout'taki script'e yöneltin: + +```shell +$ git clone https://github.com/ggml-org/llama.cpp +$ export FORGELM_GGUF_CONVERTER="$PWD/llama.cpp/convert_hf_to_gguf.py" +``` + +Checkout'un içindeki kopyayı kullanın: güncel sürümler yanında duran kardeş modülleri (`conversion`, `gguf`) import eder ve script, checkout'un `requirements/` klasöründe listelenen Python paketlerinin ForgeLM'in çalıştığı ortamda import edilebilir olmasını ister. K-quant seviyeleri ayrıca llama.cpp'nin `llama-quantize` binary'sini ister ([GGUF export](#/deployment/gguf-export) sayfasına bakın). ### Dağıtık eğitim (`[distributed]`) diff --git a/docs/usermanuals/tr/reference/cli.md b/docs/usermanuals/tr/reference/cli.md index e1da7e23..eae80b15 100644 --- a/docs/usermanuals/tr/reference/cli.md +++ b/docs/usermanuals/tr/reference/cli.md @@ -328,7 +328,7 @@ Tam kontrat için bkz. [Exit Kodları](#/reference/exit-codes). | `FORGELM_OPERATOR` | Audit event'lerinde kaydedilen operatör kimliği (`getpass.getuser()@hostname`'i override eder) | | `FORGELM_ALLOW_ANONYMOUS_OPERATOR` | `1` olduğunda audit log'un anonim operatör kaydetmesine izin verir (aksi halde çözülemeyen kimlik hatası) | | `FORGELM_AUDIT_SECRET` | Audit log chain için HMAC imza anahtarı (tahrif tespitini açar) | -| `FORGELM_GGUF_CONVERTER` | Özel `convert-hf-to-gguf.py` script'inin yolu | +| `FORGELM_GGUF_CONVERTER` | Bir llama.cpp checkout'u içindeki `convert_hf_to_gguf.py`'nin yolu. Pratikte zorunlu: hiçbir `llama-cpp-python` wheel'i script'i ForgeLM'in aradığı yere koymaz ([Kurulum](#/getting-started/installation) sayfasına bakın) | ## Sık pattern'ler diff --git a/forgelm/export.py b/forgelm/export.py index 595a6c78..367ee406 100644 --- a/forgelm/export.py +++ b/forgelm/export.py @@ -1,7 +1,7 @@ """ GGUF export for post-training model distribution. -Wraps llama-cpp-python's ``convert_hf_to_gguf.py`` conversion script to +Runs llama.cpp's ``convert_hf_to_gguf.py`` conversion script to produce quantised GGUF files that can be served by Ollama, llama.cpp, and compatible runtimes. @@ -30,7 +30,7 @@ SUPPORTED_FORMATS = frozenset({"gguf"}) SUPPORTED_QUANTS = frozenset({"q2_k", "q3_k_m", "q4_k_m", "q5_k_m", "q8_0", "f16"}) -# Name of the HF→GGUF conversion script bundled with llama-cpp-python. +# Name of the HF→GGUF conversion script (it lives in a llama.cpp checkout; no released llama-cpp-python wheel installs it where it is searched). _CONVERTER_SCRIPT = "convert_hf_to_gguf.py" # Quant types supported directly by convert_hf_to_gguf.py via --outtype. @@ -87,11 +87,13 @@ class ExportResult: def _find_converter_script() -> str: - """Locate llama-cpp-python's HF → GGUF conversion script. + """Locate the HF → GGUF conversion script. - Checks the ``FORGELM_GGUF_CONVERTER`` environment variable first, allowing - users to pin a specific converter script (useful when the bundled version is - outdated or when using a standalone llama.cpp build). + Checks the ``FORGELM_GGUF_CONVERTER`` environment variable first. In practice + that is the supported route: the script is not part of the llama-cpp-python + wheels (0.2.90 puts it in ``bin/``, 0.3.x does not ship it), so the + ``llama_cpp`` directories searched below are only a fallback for a layout that + no current wheel has. Point the variable at the copy inside a llama.cpp checkout. Raises: ImportError: When llama-cpp-python is not installed. @@ -141,9 +143,9 @@ def _find_converter_script() -> str: return path raise FileNotFoundError( - f"{_CONVERTER_SCRIPT} not found inside the llama-cpp-python installation. " - "Try: pip install 'llama-cpp-python>=0.2.90' " - f"Or set FORGELM_GGUF_CONVERTER=/path/to/{_CONVERTER_SCRIPT} to use a custom script." + f"{_CONVERTER_SCRIPT} not found inside the llama-cpp-python installation (no released wheel installs it " + "where ForgeLM looks). " + f"Set FORGELM_GGUF_CONVERTER=/path/to/llama.cpp/{_CONVERTER_SCRIPT}, the script inside a llama.cpp checkout." ) diff --git a/notebooks/post_training_workflow.ipynb b/notebooks/post_training_workflow.ipynb index 91e1171b..df3a7cf9 100644 --- a/notebooks/post_training_workflow.ipynb +++ b/notebooks/post_training_workflow.ipynb @@ -196,8 +196,10 @@ "source": [ "## 3. GGUF Export\n", "\n", - "`forgelm export` wraps `llama-cpp-python`'s bundled `convert_hf_to_gguf.py`\n", - "to produce GGUF files for Ollama / llama.cpp / compatible runtimes.\n", + "`forgelm export` runs llama.cpp's `convert_hf_to_gguf.py` to produce GGUF\n", + "files for Ollama / llama.cpp / compatible runtimes. The script is **not**\n", + "installed by `pip install 'forgelm[export]'`: clone llama.cpp and set\n", + "`FORGELM_GGUF_CONVERTER` to the copy in the checkout before running it.\n", "\n", "**K-quant note:** the script supports `f16` and `q8_0` directly. K-quants\n", "(`q2_k` / `q3_k_m` / `q4_k_m` / `q5_k_m`) need a **two-step** flow — ForgeLM\n", diff --git a/pyproject.toml b/pyproject.toml index 313b9bb6..adb6053f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,9 +123,11 @@ distributed = [ # benefit). Kept as a no-op extra so `pip install forgelm[merging]` still resolves. merging = [] -# GGUF export via llama-cpp-python's bundled convert_hf_to_gguf.py. +# GGUF export. forgelm export runs llama.cpp's convert_hf_to_gguf.py, which no +# llama-cpp-python wheel puts where ForgeLM searches: point FORGELM_GGUF_CONVERTER +# at the copy in a llama.cpp checkout (docs/usermanuals/en/getting-started/installation.md). # Produces f16 and q8_0 GGUF directly. K-quants (q4_k_m etc.) require a -# separate llama-quantize step; see docs/guides/export.md for the full flow. +# separate llama-quantize step; see docs/usermanuals/en/deployment/gguf-export.md for the full flow. # Linux and macOS only; Windows builds are available but less reliable. export = [ "llama-cpp-python>=0.2.90; sys_platform != 'win32'", diff --git a/tests/test_export.py b/tests/test_export.py index 319874bb..0fe285f5 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -292,6 +292,10 @@ def test_missing_converter_script_in_package_is_runtime_error(self, tmp_path): assert result.success is False assert result.error_kind == "runtime" + # The hint must send the operator to the route that works (the script in a llama.cpp checkout), not to a + # reinstall of llama-cpp-python, whose wheels do not carry the script. + assert "FORGELM_GGUF_CONVERTER" in result.error and "llama.cpp checkout" in result.error + assert "pip install" not in result.error def test_all_supported_quants_accepted(self, tmp_path): """Every quant in SUPPORTED_QUANTS must pass format/quant validation."""