👌
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ライフを!
Discussion