🦙

Node.jsで実現するLLMの新しい可能性 〜llama2をTypeScriptで呼び出す方法〜

2024/02/18に公開

はじめに

先日、Python 環境(と言いつつ、C++でビルドしたやつを呼び出すライブラリ)で meta が作って公開してる LLM モデルの llama2 をローカルで動かしてみた
TypeScript でもできるのかなと思って調べてみた

https://github.com/abetlen/llama-cpp-python
https://zenn.dev/optimisuke/articles/08e064fe2c1fdf

ちなみに、本家は PyTorch を使うっぽいけど、いまいち使い方わからない・・・。Mac で動くんやろか?
https://github.com/facebookresearch/llama
https://github.com/facebookresearch/llama-recipes/

調べると、node-llama-cpp ってのを作ってる人がいた
llama.cpp って、llama を C++で動くようにしたやつを Node.js から呼べるようにしたもの
https://github.com/withcatai/node-llama-cpp

さらに、langchain.js からも呼び出せるみたい
https://js.langchain.com/docs/integrations/llms/llama_cpp
https://js.langchain.com/docs/integrations/chat/llama_cpp

llama.cpp

まず、llama.cpp は Apple silicon で使えることを目的としてて、Apple シリコンの GPU を使うための Apple 版 CUDA の Metal に対応してくれている。すごい。
Apple silicon is a first-class citizen - optimized via ARM NEON, Accelerate and Metal frameworks

https://github.com/ggerganov/llama.cpp

Metal 部分を使ってるコードはここっぽいけど、これ以上突き進む気力はなかった。
ちなみに、ファイル名にもある GGML ってのが LLM のフォーマットらしい。ただ、llama.cpp は GGML じゃなくて GGUF 使うようになったみたい。
GGUF は、GGML Universal Format らしい。
https://github.com/ggerganov/llama.cpp/blob/master/ggml-metal.m

モデルは llama 派生モデルがたくさんあって、それは huggingface 上でたくさん提供されているので、気になるものを取得したら ok
https://huggingface.co/TheBloke

node-llama-cpp 試してみた

簡単だった
node-llama-cpp が、プリビルドされたバイナリも提供してくれているみたい
ビルドする方法も提供してくれているので楽ちん

こんな感じで、node-llama-cppは使える。ここでは、ELYZA の日本語モデルを使ってみた。

import { fileURLToPath } from "url";
import path from "path";
import { LlamaModel, LlamaContext, LlamaChatSession } from "node-llama-cpp";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const model = new LlamaModel({
  modelPath: path.join(
    __dirname,
    "models",
    "ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M.gguf"
  ),
});
const context = new LlamaContext({ model });
const session = new LlamaChatSession({ context });

const q1 = "元気?";
console.log("User: " + q1);
const a1 = await session.prompt(q1);
console.log("AI: " + a1);

langchain 試してみた

こっちも簡単

import { LlamaCpp } from "@langchain/community/llms/llama_cpp";

const llamaPath =
  "/Users/hoge/hello-node-llama-cpp/models/ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M.gguf";

const model = new LlamaCpp({ modelPath: llamaPath });

const question = "ラマって何?";
console.log(`You: ${question}`);
const response = await model.invoke(question);
console.log(`AI : ${response}`);

Chat model もこんな感じで stream 出力できて楽ちん。

import { ChatLlamaCpp } from "@langchain/community/chat_models/llama_cpp";

const llamaPath =
  "/Users/hoge/hello-node-llama-cpp/models/ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M.gguf";

const model = new ChatLlamaCpp({ modelPath: llamaPath, temperature: 0.7 });

const stream = await model.stream("ラマって何?");

for await (const chunk of stream) {
  console.log(chunk.content);
}

コードを見てみた

node-llama-cpp で、どうやって、llama.cpp を呼び出しているか気になったのでコードを見てみた
どうも、llama/addon.cppNode-API ってのを使って呼び出せるようにしているみたい。
https://github.com/withcatai/node-llama-cpp/blob/master/llama/addon.cpp

ビルドしたものは require で呼び出せるようになるみたい
https://github.com/withcatai/node-llama-cpp/blob/master/src/utils/getBin.ts

langchain.js の方は単に node-llama-cpp を呼び出しているだけみたい
https://github.com/langchain-ai/langchainjs/blob/main/libs/langchain-community/src/llms/llama_cpp.ts

llama.cpp は ggml-metal.m あたりがそれっぽい処理書かれてそう
Makefile も環境によってビルドするものが変わるから興味深い感じ。Mac だと 以下のように Metal 環境のそれっぽいビルドの依存関係が書かれてる。

ifdef LLAMA_METAL
	MK_CPPFLAGS += -DGGML_USE_METAL
	MK_LDFLAGS  += -framework Foundation -framework Metal -framework MetalKit
	OBJS		+= ggml-metal.o
ifdef LLAMA_METAL_NDEBUG
	MK_CPPFLAGS += -DGGML_METAL_NDEBUG
endif
endif # LLAMA_METAL

ifdef LLAMA_METAL
ggml-metal.o: ggml-metal.m ggml-metal.h
	$(CC) $(CFLAGS) -c $< -o $@
endif # LLAMA_METAL

https://github.com/ggerganov/llama.cpp/blob/master/Makefile

サクッとしか書いてないけど、よくわからなかったので、chatgpt に聞きながら読んでた(そこは llama に聞けよ)

補足

llama.cpp は他の言語でも呼び出せるように色々取り組みがあるみたい。すごい。
https://github.com/ggerganov/llama.cpp/tree/master?tab=readme-ov-file#description

自分の PC で動かしたいだけなら、Ollama がコマンドラインでいい感じに生成できるし、API サーバーっぽくも動くのでおすすめ
https://github.com/ollama/ollama

おわりに

  • llama すごい
  • llama.cpp すごい
  • Node-API すごい
  • 生成 AI は 別に Python じゃなくてもいんじゃね?
GitHubで編集を提案

Discussion