# GLM-4.7-Flash：如何本地运行

GLM-4.7-Flash 是 Z.ai 全新的 30B MoE 推理模型，专为本地部署打造，在编码、智能体工作流和聊天方面提供同类最佳性能。它仅使用约 3.6B 参数，支持 200K 上下文，并在 SWE-Bench、GPQA 以及推理/聊天基准测试中领先。

GLM-4.7-Flash 可运行于 **24GB RAM**/VRAM/统一内存（完整精度需 32GB），现在你也可以使用 Unsloth 进行微调。要通过 vLLM 运行 GLM 4.7 Flash，请参见 [#glm-4.7-flash-in-vllm](#glm-4.7-flash-in-vllm "mention")

{% hint style="success" %}
1 月 21 日更新： `llama.cpp` 修复了一个指定错误的 bug `scoring_func`: `"softmax"` （应为 `"sigmoid"`）。这会导致循环和糟糕的输出。我们已更新 GGUF 文件——请重新下载模型以获得更好的输出。

你现在可以使用 Z.ai 推荐的参数并获得很好的结果：

* **对于通用场景：** `--temp 1.0 --top-p 0.95`
* **对于工具调用：** `--temp 0.7 --top-p 1.0`
* **重复惩罚：** 禁用它，或设置 `--repeat-penalty 1.0`

1 月 22 日：更快的推理已上线，因为 CUDA 的 FA 修复已合并。
{% endhint %}

<a href="#run-glm-4.7-flash" class="button primary">运行教程</a><a href="#fine-tuning-glm-4.7-flash" class="button secondary">微调</a>

要运行的 GLM-4.7-Flash GGUF： [unsloth/GLM-4.7-Flash-GGUF](https://huggingface.co/unsloth/GLM-4.7-Flash-GGUF)

### ⚙️ 使用指南

为了获得最佳性能，请确保你的可用总内存（VRAM + 系统 RAM）超过你正在下载的量化模型文件大小。如果不够，llama.cpp 仍可通过 SSD/HDD 卸载运行，但推理会更慢。

在与 Z.ai 团队沟通后，他们建议使用其 GLM-4.7 采样参数：

| 默认设置（大多数任务）                                                        | Terminal Bench、SWE Bench Verified                                  |
| ------------------------------------------------------------------ | ------------------------------------------------------------------ |
| <mark style="background-color:green;">**temperature = 1.0**</mark> | <mark style="background-color:green;">**temperature = 0.7**</mark> |
| <mark style="background-color:green;">**top\_p = 0.95**</mark>     | <mark style="background-color:green;">**top\_p = 1.0**</mark>      |
| repeat penalty = disabled or 1.0                                   | repeat penalty = disabled or 1.0                                   |

* 对于通用场景：  `--temp 1.0 --top-p 0.95`
* 对于工具调用：  `--temp 0.7 --top-p 1.0`
* 如果使用 llama.cpp，请设置 `--min-p 0.01` 因为 llama.cpp 的默认值是 0.05
* 有时你需要试验哪些数值最适合你的使用场景。

{% hint style="warning" %}
目前，我们 **不建议** 使用 **Ollama** 运行此 GGUF，因为可能存在聊天模板兼容性问题。该 GGUF 在 llama.cpp（或如 LM Studio、Jan 等后端）上运行良好。

**记得关闭重复惩罚！或者设置** `--repeat-penalty 1.0`
{% endhint %}

* **最大上下文窗口：** `202,752`

### 🖥️ 运行 GLM-4.7-Flash

根据你的使用场景，你需要使用不同的设置。由于模型架构（如 [gpt-oss](https://unsloth.ai/docs/zh/mo-xing/gpt-oss-how-to-run-and-fine-tune)）的某些维度不能被 128 整除，因此某些部分无法量化到更低位。

因为本指南使用 4 位，你将需要大约 18GB RAM/统一内存。我们建议至少使用 4 位精度以获得最佳性能。

{% hint style="warning" %}
目前，我们 **不建议** 使用 **Ollama** 运行此 GGUF，因为可能存在聊天模板兼容性问题。该 GGUF 在 llama.cpp（或如 LM Studio、Jan 等后端）上运行良好。

**记得关闭重复惩罚！或者设置** `--repeat-penalty 1.0`
{% endhint %}

#### 🦥 Unsloth Studio 指南

GLM-4.7-Flash 可以运行并微调于 [Unsloth Studio](https://unsloth.ai/docs/zh/xin-zeng/studio)中运行和微调，这是我们新推出的本地 AI 开源 Web UI。使用 Unsloth Studio，你可以在以下平台本地运行模型： **MacOS、Windows**、Linux，以及：

{% columns %}
{% column %}

* 搜索、下载、 [运行 GGUF](https://unsloth.ai/docs/zh/xin-zeng/studio#run-models-locally) 和 safetensor 模型
* [**自我修复** 工具调用](https://unsloth.ai/docs/zh/xin-zeng/studio#execute-code--heal-tool-calling) + **网页搜索**
* [**代码执行**](https://unsloth.ai/docs/zh/xin-zeng/studio#run-models-locally) （Python、Bash）
* [自动推理](https://unsloth.ai/docs/zh/xin-zeng/studio#model-arena) 参数调优（temp、top-p 等）
* 通过 llama.cpp 实现快速 CPU + GPU 推理
* [训练 LLM](https://unsloth.ai/docs/zh/xin-zeng/studio#no-code-training) 速度提升 2 倍，VRAM 减少 70%
  {% endcolumn %}

{% column %}

<div data-with-frame="true"><figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FFeQ0UUlnjXkDdqhcWglh%2Fskinny%20studio%20chat.png?alt=media&#x26;token=c2ee045f-c243-4024-a8e4-bb4dbe7bae79" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}
{% endcolumns %}

{% stepper %}
{% step %}
**安装 Unsloth**

在你的终端中运行：

MacOS、Linux、WSL：

```bash
curl -fsSL https://unsloth.ai/install.sh | sh
```

Windows PowerShell：

```bash
irm https://unsloth.ai/install.ps1 | iex
```

{% hint style="success" %}
**安装会很快，约需 1-2 分钟。**
{% endhint %}
{% endstep %}

{% step %}
**启动 Unsloth**

MacOS、Linux、WSL 和 Windows：

```bash
unsloth studio -H 0.0.0.0 -p 8888
```

然后打开 `http://localhost:8888` 在你的浏览器中。
{% endstep %}

{% step %}
**搜索并下载 GLM-4.7-Flash**

首次启动时，你需要创建密码以保护你的账户，并在之后重新登录。随后你会看到一个简短的新手引导向导，用于选择模型、数据集和基本设置。你可以随时跳过它。

然后前往 [Studio Chat](https://unsloth.ai/docs/zh/xin-zeng/studio/chat) 标签页并搜索 **GLM-4.7-Flash** 在搜索栏中输入，并下载你想要的模型和量化版本。

<div data-with-frame="true"><figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2F4oQKFbYhEz7h2K9H3EuP%2FScreenshot%202026-04-02%20at%201.59.45%E2%80%AFAM.png?alt=media&#x26;token=bf78de14-cbcb-4f99-b9b4-65a500a6dd20" alt="" width="375"><figcaption></figcaption></figure></div>
{% endstep %}

{% step %}
**运行 GLM-4.7-Flash**

使用 Unsloth Studio 时，推理参数应会自动设置，不过你仍然可以手动更改。你也可以编辑上下文长度、聊天模板和其他设置。

更多信息，请查看我们的 [Unsloth Studio 推理指南](https://unsloth.ai/docs/zh/xin-zeng/studio/chat).

<div data-with-frame="true"><figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FXPQGEEr1YoKofrTatAKK%2Ftoolcallingif.gif?alt=media&#x26;token=25d68698-fb13-4c46-99b2-d39fb025df08" alt="" width="563"><figcaption></figcaption></figure></div>
{% endstep %}
{% endstepper %}

#### Llama.cpp 教程（GGUF）：

在 llama.cpp 中运行的说明（注意我们将使用 4 位以适配大多数设备）：

{% stepper %}
{% step %}
获取最新的 `llama.cpp` 在 [GitHub 这里](https://github.com/ggml-org/llama.cpp)。你也可以按照下面的构建说明进行操作。把 `-DGGML_CUDA=ON` 改为 `-DGGML_CUDA=OFF` 如果你没有 GPU，或者只是想进行 CPU 推理。 **对于 Apple Mac / Metal 设备**，设置 `-DGGML_CUDA=OFF` ，然后照常继续——Metal 支持默认开启。

{% code overflow="wrap" %}

```bash
apt-get update
apt-get install pciutils build-essential cmake curl libcurl4-openssl-dev -y
git clone https://github.com/ggml-org/llama.cpp
cmake llama.cpp -B llama.cpp/build \
    -DBUILD_SHARED_LIBS=OFF -DGGML_CUDA=ON
cmake --build llama.cpp/build --config Release -j --clean-first --target llama-cli llama-mtmd-cli llama-server llama-gguf-split
cp llama.cpp/build/bin/llama-* llama.cpp
```

{% endcode %}
{% endstep %}

{% step %}
你可以直接从 Hugging Face 拉取。随着你的 RAM/VRAM 允许，你可以将上下文增加到 200K。

你也可以尝试 Z.ai 推荐的 GLM-4.7 采样参数：

* 对于通用场景：  `--temp 1.0 --top-p 0.95`
* 对于工具调用：  `--temp 0.7 --top-p 1.0`
* **记得关闭重复惩罚！**

按以下方式用于 **通用指令** 用例：

```bash
./llama.cpp/llama-cli \
    -hf unsloth/GLM-4.7-Flash-GGUF:UD-Q4_K_XL \\
    --ctx-size 16384 \
    --temp 1.0 --top-p 0.95 --min-p 0.01
```

按以下方式用于 **工具调用** 用例：

```bash
./llama.cpp/llama-cli \
    -hf unsloth/GLM-4.7-Flash-GGUF:UD-Q4_K_XL \\
    --ctx-size 16384 \
    --temp 0.7 --top-p 1.0 --min-p 0.01
```

{% endstep %}

{% step %}
通过以下方式下载模型（在安装后 `pip install huggingface_hub`）。你可以选择 `UD-Q4_K_XL` 或其他量化版本。如果下载卡住，请参见 [hugging-face-hub-xet-debugging](https://unsloth.ai/docs/zh/ji-chu/troubleshooting-and-faqs/hugging-face-hub-xet-debugging "mention")

{% code overflow="wrap" %}

```bash
pip install -U huggingface_hub
hf download unsloth/GLM-4.7-Flash-GGUF \\
    --local-dir unsloth/GLM-4.7-Flash-GGUF \\
    --include "*UD-Q2_K_XL*"
```

{% endcode %}
{% endstep %}

{% step %}
然后以对话模式运行模型：

{% code overflow="wrap" %}

```bash
./llama.cpp/llama-cli \
    --model unsloth/GLM-4.7-Flash-GGUF/GLM-4.7-Flash-UD-Q4_K_XL.gguf \\
    --ctx-size 16384 \
    --seed 3407 \
    --temp 1.0 \
    --top-p 0.95 \
    --min-p 0.01
```

{% endcode %}

另外，按需调整 **上下文窗口** 按需，最多到 `202752`
{% endstep %}
{% endstepper %}

### :loop:减少重复和循环

{% hint style="success" %}
**1 月 21 日更新：llama.cpp 修复了一个指定错误的 bug** `"scoring_func": "softmax"` **它会导致循环和糟糕的输出（应为 sigmoid）我们已更新 GGUF 文件。请重新下载模型以获得更好的输出。**
{% endhint %}

这意味着你现在可以使用 Z.ai 推荐的参数并获得很好的结果：

* 对于通用场景：  `--temp 1.0 --top-p 0.95`
* 对于工具调用：  `--temp 0.7 --top-p 1.0`
* 如果使用 llama.cpp，请设置 `--min-p 0.01` 因为 llama.cpp 的默认值是 0.05
* **记得关闭重复惩罚！或者设置** `--repeat-penalty 1.0`

我们添加了 `"scoring_func": "sigmoid"` 改为 `config.json` 用于主模型 - [见](https://huggingface.co/unsloth/GLM-4.7-Flash/commit/3fd53b491e04f707f307aef2f70f8a7520511e6d).

{% hint style="warning" %}
目前，我们 **不建议** 使用 **Ollama** 运行此 GGUF，因为可能存在聊天模板兼容性问题。该 GGUF 在 llama.cpp（或如 LM Studio、Jan 等后端）上运行良好。
{% endhint %}

### :bird:使用 UD-Q4\_K\_XL 的 Flappy Bird 示例

作为示例，我们通过以下方式使用 UD-Q4\_K\_XL 完成了一段很长的对话： `./llama.cpp/llama-cli --model unsloth/GLM-4.7-Flash-GGUF/GLM-4.7-Flash-UD-Q4_K_XL.gguf --fit on --temp 1.0 --top-p 0.95 --min-p 0.01` :

```
你好
2+2 等于多少
创建一个 Python Flappy Bird 游戏
用 Rust 创建一个完全不同的游戏
找出两者中的 bug
把我刚才提到的第一个游戏做成一个独立的 HTML 文件
找出 bug 并展示修复后的游戏
```

这会在 HTML 形式下渲染出以下 Flappy Bird 游戏：

<details>

<summary>HTML 中的 Flappy Bird 游戏（可展开）</summary>

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Flappy Bird Fixed</title>
    <style>
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #222;
            font-family: 'Arial', sans-serif;
            overflow: hidden;
            user-select: none;
            -webkit-user-select: none;
            touch-action: none; /* 防止移动端缩放 */
        }

        #game-container {
            position: relative;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
        }

        canvas {
            background-color: #87CEEB;
            display: block;
            border-radius: 4px;
        }

        /* UI 覆盖层 */
        #ui-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            text-align: center;
        }

        #score-display {
            position: absolute;
            top: 40px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 48px;
            font-weight: bold;
            color: white;
            text-shadow: 3px 3px 0 #000;
            z-index: 10;
            font-family: 'Courier New', Courier, monospace;
        }

        #start-screen, #game-over-screen {
            background: rgba(0, 0, 0, 0.7);
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            color: white;
            pointer-events: auto; /* 允许点击 */
            cursor: pointer;
        }

        h1 { margin: 0 0 10px 0; font-size: 60px; text-shadow: 4px 4px 0 #000; line-height: 1; }
        p { font-size: 22px; margin: 10px 0; color: #ddd; }
        
        .btn {
            background: linear-gradient(to bottom, #ffeb3b, #fbc02d);
            border: 3px solid #fff;
            color: #333;
            padding: 15px 40px;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            border-radius: 8px;
            box-shadow: 0 6px 0 #c49000, 0 10px 10px rgba(0,0,0,0.3);
            text-transform: uppercase;
            transition: all 0.1s;
            margin-top: 10px;
        }

        .btn:active {
            transform: translateY(4px);
            box-shadow: 0 2px 0 #c49000, 0 4px 4px rgba(0,0,0,0.3);
        }

        .score-board {
            background: #ded895;
            border: 2px solid #543847;
            padding: 20px 40px;
            border-radius: 10px;
            box-shadow: 4px 4px 0 #543847;
            margin-bottom: 30px;
            display: none;
            border: 4px solid #543847;
        }
        
        .score-board h2 { margin: 0 0 5px 0; color: #e86101; font-size: 40px; }
        .score-board span { font-size: 20px; color: #543847; display: block; text-align: center; }

    </style>
</head>
<body>

    <div id="game-container">
        <canvas id="gameCanvas" width="400" height="600"></canvas>
        
        <div id="score-display">0</div>

        <div id="ui-layer">
            <div id="start-screen">
                <h1>FLAPPY<br>BIRD</h1>
                <p>点击或按空格开始</p>
                <button class="btn" style="display:none;" id="touch-instruction">点击开始</button>
            </div>

            <div id="game-over-screen">
                <h1>游戏结束</h1>
                <div class="score-board" id="score-board">
                    <h2>得分：<span id="final-score">0</span></h2>
                </div>
                <button class="btn" id="restart-btn">再试一次</button>
            </div>
        </div>
    </div>

<script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');

    // --- 常量 ---
    const GRAVITY = 0.35; // 稍微更强的重力以获得更好的手感
    const JUMP_STRENGTH = -6.5;
    const PIPE_GAP = 180;
    const PIPE_WIDTH = 60;
    const PIPE_SPEED = 2.5;
    const PIPE_SPAWN_RATE = 100;

    // --- 状态 ---
    let frames = 0;
    let score = 0;
    let isGameOver = false;
    let isPlaying = false;
    let gameLoopId;

    const ui = {
        startScreen: document.getElementById('start-screen'),
        gameOverScreen: document.getElementById('game-over-screen'),
        scoreDisplay: document.getElementById('score-display'),
        scoreBoard: document.getElementById('score-board'),
        finalScore: document.getElementById('final-score'),
        restartBtn: document.getElementById('restart-btn')
    };

    const bird = {
        x: 80,
        y: 150,
        radius: 12, // 修正后的半径
        velocity: 0,
        
        draw: function() {
            // 根据速度旋转小鸟以增加视觉效果
            let angle = Math.min(Math.PI / 4, Math.max(-Math.PI / 4, (this.velocity * 0.1)));
            
            ctx.save();
            ctx.translate(this.x, this.y);
            ctx.rotate(angle);
            
            // 绘制身体
            ctx.fillStyle = '#FFD700';
            ctx.beginPath();
            ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
            ctx.fill();
            
            // 眼睛
            ctx.fillStyle = 'white';
            ctx.beginPath();
            ctx.arc(4, -4, 4, 0, Math.PI * 2);
            ctx.fill();
            ctx.fillStyle = 'black';
            ctx.beginPath();
            ctx.arc(6, -4, 2, 0, Math.PI * 2);
            ctx.fill();
            
            // 翅膀
            ctx.fillStyle = '#FFA500';
            ctx.beginPath();
            ctx.arc(-4, 4, 5, 0, Math.PI * 2);
            ctx.fill();

            ctx.restore();
        },

        update: function() {
            this.velocity += GRAVITY;
            this.y += this.velocity;
        },

        jump: function() {
            this.velocity = JUMP_STRENGTH;
        },

        reset: function() {
            this.y = 150;
            this.velocity = 0;
        }
    };

    let pipes = [];

    function createPipe() {
        const minHeight = 50;
        const maxPos = canvas.height - PIPE_GAP - minHeight;
        const topHeight = Math.floor(Math.random() * (maxPos - minHeight + 1)) + minHeight;
        
        pipes.push({
            x: canvas.width,
            topHeight: topHeight,
            bottomY: topHeight + PIPE_GAP,
            width: PIPE_WIDTH,
            passed: false
        });
    }

    function drawPipes() {
        ctx.fillStyle = '#2ecc71';
        ctx.strokeStyle = '#27ae60';
        ctx.lineWidth = 2;
        
        pipes.forEach(pipe => {
            // 上方管道
            ctx.fillRect(pipe.x, 0, pipe.width, pipe.topHeight);
            ctx.strokeRect(pipe.x, 0, pipe.width, pipe.topHeight);
            
            // 下方管道
            ctx.fillRect(pipe.x, pipe.bottomY, pipe.width, canvas.height - pipe.bottomY);
            ctx.strokeRect(pipe.x, pipe.bottomY, pipe.width, canvas.height - pipe.bottomY);

            // 管口
            const capH = 20;
            ctx.fillStyle = '#27ae60'; 
            ctx.fillRect(pipe.x - 2, pipe.topHeight - capH, pipe.width + 4, capH);
            ctx.fillRect(pipe.x - 2, pipe.bottomY, pipe.width + 4, capH);
        });
    }

    function updatePipes() {
        if (frames % PIPE_SPAWN_RATE === 0) createPipe();

        for (let i = 0; i < pipes.length; i++) {
            let p = pipes[i];
            p.x -= PIPE_SPEED;

            // --- 修正后的碰撞检测 ---
            // 将小鸟视为半径为 'bird.radius' 的圆
            // 管道是矩形：x、x+w、y_top、y_bottom
            let birdLeft = bird.x - bird.radius;
            let birdRight = bird.x + bird.radius;
            let birdTop = bird.y - bird.radius;
            let birdBottom = bird.y + bird.radius;

            // 水平重叠
            if (birdRight > p.x && birdLeft < p.x + p.width) {
                // 垂直重叠（撞到上管道 或 撞到下管道）
                if (birdTop < p.topHeight || birdBottom > p.bottomY) {
                    gameOver();
                }
            }

            // --- 修正后的计分 ---
            // 如果管道已离开屏幕左侧，并且还未计分
            if (p.x + p.width < 0 && !p.passed) {
                score++;
                p.passed = true;
                ui.scoreDisplay.innerText = score;
            }

            if (p.x < -60) {
                pipes.shift();
                i--;
            }
        }
    }

    function checkCollisions() {
        // 地面
        if (bird.y + bird.radius >= canvas.height) {
            gameOver();
        }
        // 天花板
        if (bird.y - bird.radius <= 0) {
            bird.y = bird.radius;
            bird.velocity = 0;
        }
    }

    function drawBackground() {
        // 清空
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        // 地面
        ctx.fillStyle = '#654321';
        ctx.fillRect(0, canvas.height - 10, canvas.width, 10);
        
        // 云朵
        ctx.fillStyle = "rgba(255, 255, 255, 0.6)";
        for(let i=0; i<4; i++) {
            let x = (frames * 0.5 + i * 150) % (canvas.width + 100) - 50;
            let y = (i * 40) + 20;
            let scale = 1 + (Math.sin(frames * 0.02 + i) * 0.1);
            let size = 30 * scale;
            ctx.beginPath();
            ctx.arc(x, y, size, 0, Math.PI * 2);
            ctx.arc(x + 20*scale, y - 10*scale, size * 1.2, 0, Math.PI * 2);
            ctx.arc(x + 40*scale, y, size, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    function update() {
        if (!isPlaying) return;
        bird.update();
        updatePipes();
        checkCollisions();
        frames++;
    }

    function draw() {
        drawBackground();
        drawPipes();
        bird.draw();
    }

    function loop() {
        update();
        draw();
        if (isPlaying || !isGameOver) {
            gameLoopId = requestAnimationFrame(loop);
        }
    }

    function startGame() {
        isPlaying = true;
        isGameOver = false;
        
        // UI
        ui.startScreen.style.display = 'none';
        ui.gameOverScreen.style.display = 'none';
        ui.scoreBoard.style.display = 'none';
        
        // 逻辑
        bird.reset();
        pipes = [];
        score = 0;
        frames = 0;
        ui.scoreDisplay.innerText = '0';
        
        loop();
    }

    function gameOver() {
        isPlaying = false;
        isGameOver = true;
        cancelAnimationFrame(gameLoopId);
        
        ui.finalScore.innerText = score;
        ui.gameOverScreen.style.display = 'flex';
        ui.scoreBoard.style.display = 'block';
    }

    // --- 输入处理 ---

    function handleInput(e) {
        if (e.type === 'keydown' && e.code === 'Space') e.preventDefault();

        if (isPlaying) {
            bird.jump();
        } else if (!isGameOver) {
            // 点击开始界面（或游戏尚未开始时的任意点击）
            startGame();
        }
    }

    // 键盘
    window.addEventListener('keydown', (e) => {
        if (e.code === 'Space') handleInput(e);
    });

    // 鼠标 / 触摸
    window.addEventListener('mousedown', handleInput);
    window.addEventListener('touchstart', (e) => {
        // 防止缩放/滚动
        // e.preventDefault(); 
        handleInput(e);
    }, {passive: false});

    // UI 交互
    ui.restartBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        startGame();
    });
    
    // 允许点击 Game Over 覆盖层进行重启
    ui.gameOverScreen.addEventListener('mousedown', (e) => {
        if(e.target === ui.gameOverScreen) startGame();
    });
    ui.gameOverScreen.addEventListener('touchstart', (e) => {
        if(e.target === ui.gameOverScreen) {
            e.preventDefault();
            startGame();
        }
    });

    // 初始绘制
    drawBackground();
    bird.reset();
    bird.draw();

</script>
</body>
</html>
```

</details>

而且我们还截取了一些截图（4bit 可用）：

<div align="left"><figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FJ85uzHPDWinaXPe6kWyU%2Fimage.png?alt=media&#x26;token=6547f49d-2544-4c48-a7d5-5c1c67d34a87" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FHAc2SjNLo1OsyAC4dArm%2Fimage.png?alt=media&#x26;token=87d4bfea-4ac9-41ef-be1c-1e51664d30b1" alt="" width="188"><figcaption></figcaption></figure></div>

### 🦥 微调 GLM-4.7-Flash

Unsloth 现在支持对 GLM-4.7-Flash 进行微调，不过你需要使用 `transformers v5`。30B 模型无法放入免费的 Colab GPU；不过，你可以使用我们的 notebook。GLM-4.7-Flash 的 16 位 LoRA 微调将使用大约 **60GB VRAM**:

* [GLM-4.7-Flash SFT LoRA notebook](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/GLM_Flash_A100\(80GB\).ipynb)

{% hint style="warning" %}
在使用 A100 40GB VRAM 时你可能会偶尔遇到显存不足。为了更顺畅地运行，你需要使用 H100/A100 80GB VRAM。
{% endhint %}

{% embed url="<https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/GLM_Flash_A100(80GB).ipynb>" %}

在微调 MoE 时，最好不要微调路由层，因此我们默认禁用了它。如果你想保留其推理能力（可选），可以使用直接回答和思维链示例的混合。请至少使用 <mark style="background-color:green;">75% 推理</mark> 和 <mark style="background-color:green;">25% 非推理</mark> 的数据集，让模型保留其推理能力。

### 🦙Llama-server 服务与部署

要将 GLM-4.7-Flash 部署到生产环境，我们使用 `llama-server` 在一个新的终端中，例如通过 tmux，使用以下命令部署模型：

{% code overflow="wrap" %}

```bash
./llama.cpp/llama-server \\
    --model unsloth/GLM-4.7-Flash-GGUF/GLM-4.7-Flash-UD-Q4_K_XL.gguf \\
    --alias "unsloth/GLM-4.7-Flash" \\
    --seed 3407 \
    --temp 1.0 \
    --top-p 0.95 \
    --min-p 0.01 \
    --ctx-size 16384 \
    --port 8001
```

{% endcode %}

然后在一个新的终端中，在执行 `pip install openai`之后，执行：

{% code overflow="wrap" %}

```python
from openai import OpenAI
import json
openai_client = OpenAI(
    base_url = "http://127.0.0.1:8001/v1",
    api_key = "sk-no-key-required",
)
completion = openai_client.chat.completions.create(
    model = "unsloth/GLM-4.7-Flash",
    messages = [{"role": "user", "content": "2+2 等于多少？"},],
)
print(completion.choices[0].message.content)
```

{% endcode %}

它将输出

{% code overflow="wrap" %}

```
用户提出一个简单问题："2+2 等于多少？" 答案是 4。请给出答案。

2 + 2 = 4.
```

{% endcode %}

### :computer: vLLM 中的 GLM-4.7-Flash

你现在可以使用我们新的 [FP8 动态量化](https://huggingface.co/unsloth/GLM-4.7-Flash-FP8-Dynamic) 版本模型进行高性能且快速的推理。首先从 nightly 安装 vLLM：

{% code overflow="wrap" %}

```bash
uv pip install --upgrade --force-reinstall vllm --torch-backend=auto --extra-index-url https://wheels.vllm.ai/nightly/cu130
uv pip install --upgrade --force-reinstall git+https://github.com/huggingface/transformers.git
uv pip install --force-reinstall numba
```

{% endcode %}

然后启动 [Unsloth 的动态 FP8 版本](https://huggingface.co/unsloth/GLM-4.7-Flash-FP8-Dynamic) 模型。我们启用了 FP8 以将 KV 缓存内存占用减少 50%，并在 4 张 GPU 上运行。如果你只有 1 张 GPU，请使用 `CUDA_VISIBLE_DEVICES='0'` 并设置 `--tensor-parallel-size 1` 或者移除此参数。要禁用 FP8，请移除 `--quantization fp8 --kv-cache-dtype fp8`

```bash
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:False
CUDA_VISIBLE_DEVICES='0,1,2,3' vllm serve unsloth/GLM-4.7-Flash-FP8-Dynamic \\
    --served-model-name unsloth/GLM-4.7-Flash \\
    --tensor-parallel-size 4 \\
    --tool-call-parser glm47 \\
    --reasoning-parser glm45 \\
    --enable-auto-tool-choice \\
    --dtype bfloat16 \\
    --seed 3407 \
    --max-model-len 200000 \\
    --gpu-memory-utilization 0.95 \\
    --max_num_batched_tokens 16384 \\
    --port 8001 \
    --kv-cache-dtype fp8
```

然后你可以通过 OpenAI API 调用已部署的模型：

```python
from openai import AsyncOpenAI, OpenAI
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8001/v1"
client = OpenAI( # 或 AsyncOpenAI
    api_key=openai_api_key,
    base_url=openai_api_base,
)
```

#### :star: vLLM GLM-4.7-Flash 推测解码

我们发现使用 GLM 4.7 Flash 的 MTP（多 token 预测）模块会使生成吞吐量从 1 个 B200 上的 13,000 tokens 降到 1,300 tokens！(慢 10 倍) 在 Hopper 上，希望应该没问题。

```bash
    --speculative-config.method mtp \\
    --speculative-config.num_speculative_tokens 1
```

在 1xB200 上仅有 1,300 tokens/s 吞吐量（每个用户解码 130 tokens/s）

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FCJPJYh1uIS1yL8vskiOF%2Fimage.png?alt=media&#x26;token=f07aaad9-93bd-4507-836f-967a3d39b0e5" alt=""><figcaption></figcaption></figure>

以及在 1xB200 上 13,000 tokens/s 吞吐量（每个用户仍为 130 token/s 解码）

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FrXaHEknUb1QW1v0arO0q%2Fimage.png?alt=media&#x26;token=dd81b731-90bb-4d1b-a647-a64618f5952a" alt=""><figcaption></figcaption></figure>

### :hammer:使用 GLM-4.7-Flash 进行工具调用

见 [tool-calling-guide-for-local-llms](https://unsloth.ai/docs/zh/ji-chu/tool-calling-guide-for-local-llms "mention") 以了解如何进行工具调用的更多细节。在一个新终端中（如果使用 tmux，请使用 CTRL+B+D），我们创建一些工具，例如添加两个数字、执行 Python 代码、执行 Linux 函数，以及更多：

{% code expandable="true" %}

```python
import json, subprocess, random
from typing import Any
def add_number(a: float | str, b: float | str) -> float:
    return float(a) + float(b)
def multiply_number(a: float | str, b: float | str) -> float:
    return float(a) * float(b)
def substract_number(a: float | str, b: float | str) -> float:
    return float(a) - float(b)
def write_a_story() -> str:
    return random.choice([
        "很久很久以前，在一个遥远的银河系里……",
        "有两个朋友，他们热爱树懒和代码……",
        "世界即将终结，因为每只树懒都进化出了超人般的智慧……",
        "一位朋友并不知道，另一位朋友不小心写了一个让树懒进化的程序……",
    ])
def terminal(command: str) -> str:
    if "rm" in command or "sudo" in command or "dd" in command or "chmod" in command:
        msg = "Cannot execute 'rm, sudo, dd, chmod' commands since they are dangerous"
        print(msg); return msg
    print(f"Executing terminal command `{command}`")
    try:
        return str(subprocess.run(command, capture_output = True, text = True, shell = True, check = True).stdout)
    except subprocess.CalledProcessError as e:
        return f"Command failed: {e.stderr}"
def python(code: str) -> str:
    data = {}
    exec(code, data)
    del data["__builtins__"]
    return str(data)
MAP_FN = {
    "add_number": add_number,
    "multiply_number": multiply_number,
    "substract_number": substract_number,
    "write_a_story": write_a_story,
    "terminal": terminal,
    "python": python,
}
tools = [
    {
        "type": "function",
        "function": {
            "name": "add_number",
            "description": "添加两个数字。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "第一个数字。",
                    },
                    "b": {
                        "type": "string",
                        "description": "第二个数字。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "multiply_number",
            "description": "将两个数字相乘。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "第一个数字。",
                    },
                    "b": {
                        "type": "string",
                        "description": "第二个数字。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "substract_number",
            "description": "将两个数字相减。",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "description": "第一个数字。",
                    },
                    "b": {
                        "type": "string",
                        "description": "第二个数字。",
                    },
                },
                "required": ["a", "b"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_a_story",
            "description": "写一个随机故事。",
            "parameters": {
                "type": "object",
                "properties": {},
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "terminal",
            "description": "在终端执行操作。",
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "您希望启动的命令，例如 `ls`、`rm` 等。",
                    },
                },
                "required": ["command"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "python",
            "description": "调用 Python 解释器并运行一些 Python 代码。",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "要运行的 Python 代码",
                    },
                },
                "required": ["code"],
            },
        },
    },
]
```

{% endcode %}

然后我们使用下面的函数（复制并粘贴后执行），它们会自动解析函数调用，并为任何模型调用 OpenAI 端点：

{% code overflow="wrap" expandable="true" %}

```python
from openai import OpenAI
def unsloth_inference(
    messages,
    temperature = 0.7,
    top_p = 1.0,
    top_k = -1,
    repetition_penalty = 0.0,
):
    messages = messages.copy()
    openai_client = OpenAI(
        base_url = "http://127.0.0.1:8001/v1",
        api_key = "sk-no-key-required",
    )
    model_name = next(iter(openai_client.models.list())).id
    print(f"Using model = {model_name}")
    has_tool_calls = True
    original_messages_len = len(messages)
    while has_tool_calls:
        print(f"Current messages = {messages}")
        response = openai_client.chat.completions.create(
            model = model_name,
            messages = messages,
            temperature = temperature,
            top_p = top_p,
            tools = tools if tools else None,
            tool_choice = "auto" if tools else None,
            extra_body = {"top_k": top_k, "min_p": min_p, "dry_multiplier" :repetition_penalty,}
        )
        tool_calls = response.choices[0].message.tool_calls or []
        content = response.choices[0].message.content or ""
        tool_calls_dict = [tc.to_dict() for tc in tool_calls] if tool_calls else tool_calls
        messages.append({"role": "assistant", "tool_calls": tool_calls_dict, "content": content,})
        for tool_call in tool_calls:
            fx, args, _id = tool_call.function.name, tool_call.function.arguments, tool_call.id
            out = MAP_FN[fx](**json.loads(args))
            messages.append({"role": "tool", "tool_call_id": _id, "name": fx, "content": str(out),})
        else:
            has_tool_calls = False
    return messages
```

{% endcode %}

在通过以下方式启动 GLM-4.7-Flash 之后 `llama-server` 像在 [#deploy-with-llama-server-and-openais-completion-library](#deploy-with-llama-server-and-openais-completion-library "mention") 或参见 [tool-calling-guide-for-local-llms](https://unsloth.ai/docs/zh/ji-chu/tool-calling-guide-for-local-llms "mention") 了解更多详情后，我们就可以进行一些工具调用：

**GLM 4.7 的数学运算工具调用**

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "今天的日期加 3 天是多少？"}],
}]
unsloth_inference(messages, temperature = 1.0, top_p = 0.95, top_k = -1, min_p = 0.01)
```

{% endcode %}

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FoFkZ20QOSGdzT4iz2SOB%2Fimage.png?alt=media&#x26;token=e4ca30b0-dcec-4a26-b019-dd33f0600949" alt=""><figcaption></figcaption></figure>

**用于执行生成的 Python 代码的工具调用，适用于 GLM-4.7-Flash**

{% code overflow="wrap" %}

```python
messages = [{
    "role": "user",
    "content": [{"type": "text", "text": "用 Python 创建一个斐波那契函数并求 fib(20)。"}],
}]
unsloth_inference(messages, temperature = 1.0, top_p = 0.95, top_k = -1, min_p = 0.01)
```

{% endcode %}

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FhS8sWtZwjwerElezCc2C%2Fimage.png?alt=media&#x26;token=39032ef8-386e-4837-8dd2-c552c80a3ee3" alt="" width="563"><figcaption></figcaption></figure>

### 基准测试

GLM-4.7-Flash 是除 AIME 25 之外所有基准测试中表现最好的 30B 模型。

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FuU8GDqR2ni6slcQ1pWzL%2Fglm4.7%20benchmarks.jpg?alt=media&#x26;token=1f609b73-c20b-4e4c-bbf8-0e7213c00b44" alt="" width="375"><figcaption></figcaption></figure>

| 基准                 | GLM-4.7-Flash | Qwen3-30B-A3B-Thinking-2507 | GPT-OSS-20B |
| ------------------ | ------------- | --------------------------- | ----------- |
| AIME 25            | 91.6          | 85.0                        | 91.7        |
| GPQA               | 75.2          | 73.4                        | 71.5        |
| LCB v6             | 64.0          | 66.0                        | 61.0        |
| HLE                | 14.4          | 9.8                         | 10.9        |
| SWE-bench Verified | 59.2          | 22.0                        | 34.0        |
| τ²-Bench           | 79.5          | 49.0                        | 47.7        |
| BrowseComp         | 42.8          | 2.29                        | 28.3        |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://unsloth.ai/docs/zh/mo-xing/glm-4.7-flash.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
