👌

GitHub Actionsでオープンウェイトなモデルを使ってLLM推論をする

に公開

あんまり想定された使い方じゃない気もしますが、ActionsでオープンウェイトなLLMを動かせると色々便利なので llama.cpp を使って動かせるようにしてみました。

ちなみにActionsではCPUしか使えずコア数も少なく性能も良くないためパラメータ数が多いモデルは使えないです。
Gemma 4 E4Bとかも使えるんですが、Bonsaiという1bitのLLMが出ていて省メモリでActions向けなのでここでは採用しています。

name: Run

on:
  workflow_dispatch:

env:
  LLAMA_CPP_VERSION: b8967
  LLAMA_CPP_HF_MODEL: prism-ml/Bonsai-8B-gguf:Q1_0

jobs:
  generate:
    runs-on: ubuntu-latest
    timeout-minutes: 60

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version-file: go.mod

      - name: Download llama.cpp
        run: |
          gh release download "${{ env.LLAMA_CPP_VERSION }}" \
            --repo ggml-org/llama.cpp \
            --pattern 'llama-*-bin-ubuntu-x64.tar.gz' \
            --dir /tmp
          mkdir -p /tmp/llama.cpp
          tar -xvf /tmp/llama-*-bin-ubuntu-x64.tar.gz -C /tmp/llama.cpp --strip-components=1
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Cache Hugging Face models
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.cache/huggingface
          key: hf-${{ env.LLAMA_CPP_HF_MODEL }}

      - name: Start llama-server
        run: |
          /tmp/llama.cpp/llama-server \
            -hf "${{ env.LLAMA_CPP_HF_MODEL }}" \
            --host 127.0.0.1 \
            --port 8080 \
            --ctx-size 4096 &

          for i in $(seq 1 120); do
            if curl -fsS http://127.0.0.1:8080/health; then
              exit 0
            fi
            sleep 5
          done

          echo "llama-server did not become healthy" >&2
          exit 1

      - name: Run
        run: go run .

このコードはGoを使っているんですが、OpenAI互換のHTTPサーバーを立てているのでPythonでもなんでも使えます。

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	reqBody, err := json.Marshal(map[string]any{
		"messages": []map[string]string{
			{"role": "user", "content": "こんにちは"},
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	resp, err := http.Post("http://127.0.0.1:8080/v1/chat/completions", "application/json", bytes.NewReader(reqBody))
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	if resp.StatusCode != http.StatusOK {
		log.Fatalf("status %d: %s", resp.StatusCode, body)
	}

	var result struct {
		Choices []struct {
			Message struct {
				Content string `json:"content"`
			} `json:"message"`
		} `json:"choices"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		log.Fatal(err)
	}

	if len(result.Choices) == 0 {
		log.Fatal("no choices returned")
	}

	fmt.Println(result.Choices[0].Message.Content)
}

それでは良きGitHub Actionsライフを!

GitHubで編集を提案

Discussion