はじめに
LlamaIndexはLLMとデータを扱うのに便利なオープンソースのデータフレームワークで、pythonで書かれています。これをJavaScript/TypeScript環境で使えるようにしたのがLlamaIndex.tsです。Node.jsやDeno、Vercel Edge Runtimeなど複数のJavaScriptランタイムで動作します。サーバサイドでの利用に焦点を当てており、ブラウザからの直接利用は一部APIの不足により制限があります。
Typescript版はPython版の完全な移植というわけではなく、一部使えない機能があります。また、Vercelにデプロイする場合にはサーバーレス環境特有の課題に注意する必要があるなど、導入に難しいところもありますが、レイテンシが低く軽量に動作するのは大きな利点です。また、VercelはAI SDKを提供しており、LlamaIndexといっしょに使うことが出来ます。
この記事では、Vercelで使う上での基本的な手順と注意点のメモをご紹介します。私自身初心者なので、色々間違いがあるかもしれません。何かありましたらコメントいただければ幸いです。
基礎資料
LlamaIndex.tsを使うなら以下の資料は押さえておきたいです。
基本的なセットアップ
まずはnext.js, Vercelなどを準備します。ルートになるディレクトリにて以下のコマンドを入力します
#Next.jsの準備
npx create-next-app@latest .
#Vercelプロジェクトの準備
vercel
# Node.js 22 のインストールと使用
nvm install 22
nvm use 22
# 必要なパッケージのインストール
npm install llamaindex
上の手順のあとなら既に設定済みと思いますが、tsconfig.jsonの以下のパラメーターを確認して下さい。
{
compilerOptions: {
...
moduleResolution: "bundler"
...
},
}
これは TypeScript が 最新のパッケージ配布方法(ESM + CJS + サーバーレス環境向けの conditional exports)に対応するため に必要な設定とのことです(参照)。
次に、公式の指示に従い、next.config.tsは削除して、代わりにnext.config.mjsを作ります。
import withLlamaIndex from "llamaindex/next";
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default withLlamaIndex(nextConfig);
Next.js の ESM (ECMAScript Modules) 化に適応し、最新の依存関係の問題を避けるために有用とのことです(資料)。
OpenAIのChatモデルを使ってみる
公式サンプルを更に簡略した例を使って、OpenAIのgpt-4o-miniと質疑応答します。
まず、OpenAI API呼び出しの抽象化と設定の管理を行うヘルパーモジュールと作ります。これは、本質的には公式サンプルと同じです。
import { OpenAI } from "@llamaindex/openai";
export async function getChatResponse(message: string) {
const llm = new OpenAI({ model: "gpt-4o-mini", temperature: 0.1 });
const response = await llm.chat({
messages: [{ content: message, role: "user" }],
});
return response.message.content;
}
次に、バックエンドAPIエンドポイントを作ります。これがクライアントからのリクエスト処理、エラーハンドリング、openai.tsでのOpenAI関連の処理の橋渡しをします
import { NextResponse } from 'next/server';
import { getChatResponse } from '@/lib/openai';
export async function POST(request: Request) {
try {
const { content } = await request.json();
const response = await getChatResponse(content);
return NextResponse.json({ response });
} catch (error) {
console.error('API Error:', error);
return NextResponse.json({ error: 'Error occurred' }, { status: 500 });
}
}
最後に、フロントエンドのUIコンポーネントを作ります。
'use client';
import { useState } from 'react';
export default function Home() {
const [input, setInput] = useState('');
const [response, setResponse] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const res = await fetch('/api/openai', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'chat', content: input }),
});
const data = await res.json();
setResponse(data.response);
} catch (error) {
console.error('Client Error:', error);
setResponse('エラーが発生しました。');
}
};
return (
<div className="p-8">
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
className="w-full p-2 border rounded"
/>
<button type="submit" className="mt-2 px-4 py-2 bg-blue-500 text-white rounded">
送信
</button>
</form>
{response && (
<div className="mt-4 p-4 bg-gray-100 rounded">
{response}
</div>
)}
</div>
);
}
ローカルのテスト用に、.env.localにAPIキーを登録してください。
OPENAI_API_KEY=sk-xQoeXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXQY0u
ついでに、vercelのサイトのsettingsのenvironment variableのところでも同じように設定しておいてください。こちらはデプロイしたときに使います。
準備ができたら
npm run dev
を実行し、http://localhost:3000 で動作確認してください。
上手く行ったら、Vercelプロジェクトにデプロイしてみましょう。
vercel deploy
Vercel AI SDKを使ってみる。
次は、Vercelが提供しているAI SDKを使う例を紹介します。最初に、パッケージをインストールします。
npm install ai
次に、公式サンプルのモジュールを、ほぼコピーしてきます(console.logは区別のために追加)。
import { OpenAI, SimpleChatEngine } from 'llamaindex';
import { LlamaIndexAdapter } from 'ai';
export const maxDuration = 60;
export async function POST(req: Request) {
console.log('ai sdk route');
const { prompt } = await req.json();
const llm = new OpenAI({ model: 'gpt-4o-mini' });
const chatEngine = new SimpleChatEngine({ llm });
const stream = await chatEngine.chat({
message: prompt,
stream: true,
});
return LlamaIndexAdapter.toDataStreamResponse(stream);
}
page.tsxも、公式に従って修正します。useCompletionを使うことで、大幅に簡略になることがわかります。また、テキストはストリームされます。
'use client';
import { useCompletion } from 'ai/react';
export default function Home() {
const { completion, input, handleInputChange, handleSubmit } = useCompletion({
api: '/api/aisdk',
});
return (
<div className="p-8">
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={handleInputChange}
className="w-full p-2 border rounded"
/>
<button type="submit" className="mt-2 px-4 py-2 bg-blue-500 text-white rounded">
送信
</button>
</form>
{completion && (
<div className="mt-4 p-4 bg-gray-100 rounded">
{completion}
</div>
)}
</div>
);
}
最後に
LlamaIndex.tsは、Python版に比べると情報が少なくて勉強しづらいですが、ビルド時間は短く動作もサクサクで快適なので、積極的に使っていきたいですね。