前回の記事でVue.js + Cubism SDK for Webを使って、Live2Dモデルをブラウザ上で表示しました。
今回はFucntion Callingを用いることでAIにLive2Dモデルの表情を制御してもらいます。
Function Calling とは

Function Callingとは、ChatGPTが外部のAPIや関数を呼び出し、その結果を基に回答を生成する仕組みです。例えば、ユーザーが「今日の天気を教えて」と尋ねると、ChatGPTは天気情報を取得するAPIを実行し、その結果を元に回答します。
この機能を活用すると、ChatGPTはリアルタイム情報の取得や、カレンダーへの予定追加、ニュースの取得など、さまざまな操作が可能になります。
Ollamaもこの機能に対応しており、Toolsに対応したモデルを使うことでローカルLLMでもFunction Callingを利用できます。

実行環境

動作を確認した環境は以下のとおりです。今回はローカルLLMを動かすのでNVIDIAのGPUはほぼ必須。
- Windows 11
- Nvidia RTX4080 16GB
- デスクトップ版のOllama
- デスクトップ版のVOICEVOX
- Node.js v22.14.0 (64-bit)
- Cubism SDK for Web 5-r.3
LLMモデルはLlama3.1を使用しました。
モデルのダウンロードは次のコマンドで行えます。
ollama pull llama3.1
コードと解説

Function Callingで表情の制御する部分について解説します。
Function Callingの実行
OllamaはOpenAI API互換のエンドポイントを提供しているので、openai
パッケージを使ってリクエストを投げることができます。
openai.chat.completions.create()
メソッドに tools
パラメータを渡すことで、Function Callingを利用できます。
// CharacterChatWithExpression.ts の一部抜粋
const tools: ChatCompletionTool[] = [
{
type: 'function',
function: {
name: 'change_character_expression',
description: "Change the character's expression",
parameters: {
type: 'object',
properties: {
expressionType: {
type: 'string',
enum: ['normal', 'happy', 'sad', 'angry', 'surprised', 'blush'],
description: 'Expression',
},
},
required: ['expressionType'],
},
},
},
]
// APIリクエストに関数定義を含める
const response = await openai.chat.completions.create({
model,
messages: [...systemMessages, ...this.conversationHistory],
tools: this.tools,
tool_choice: 'auto', // AIに関数呼び出しの判断を委ねる
temperature: 0.7,
})
// AIの応答を取得
const message = response.choices[0].message
関数が呼び出されると、message.tool_calls
に関数の呼び出し情報が格納されて返ってきます。
// 関数呼び出しを処理
if (message.tool_calls) {
const functionCall = message.tool_calls[0]
if (functionCall.function.name === 'change_character_expression') {
// 関数の引数をJSONとしてパース
const args = JSON.parse(functionCall.function.arguments) as ChangeCharacterExpressionArgs
// ... 関数呼び出しの処理等 ...
}
}
今回の場合、message.tool_calls[0]
には以下のような情報が格納されていました。
{
"id": "...",
"index": 0,
"type": "function",
"function": {
"name": "change_character_expression",
"arguments": "{\"expressionType\":\"happy\"}"
}
}
arguments
に expressionType: "happy"
という情報が含まれています。これを基にLive2Dモデルを制御できますね。
Live2Dモデルの表情制御
Vue.jsのコンポーネント内では、Function Callingの結果を元にLive2Dモデルの表情を制御します。
respoinse.expression
を基にLive2Dモデルの表情・モーションをセットしています。
<script setup lang="ts">
// LlmChatView.vue の一部抜粋
function onSubmit(){
// ... 省略 ...
// APIからの応答を取得
logger.debug('Sending message to LLM:', userMessage);
const response = await characterChat.value.completion(userMessage);
logger.debug('Received response:', response);
if (response.text) {
speechText.value = response.text;
// キャラクターの応答を追加
chatMessages.value.push({ text: response.text, isUser: false });
// 表情とモーションを設定
switch (response.expression) {
case 'happy':
expressionIndex.value = 1;
motionGroupName.value = 'TapBody';
motionIndex.value = 2;
break;
case 'sad':
expressionIndex.value = 4;
motionGroupName.value = 'TapBody';
motionIndex.value = 1;
break;
case 'angry':
expressionIndex.value = 7;
motionGroupName.value = 'TapBody';
motionIndex.value = 0;
break;
// ...
// ... 省略 ...
}
デモ動画
下記の動画は、Function CallingによってLive2Dモデルの表情を制御するデモです。
簡単なチャット画面を作成し、会話してみました。自然言語による指示で表情が変化しているのがわかると思います。
まとめ
今回はFunction Callingを使って、Live2Dモデルの表情を制御してみました。
AIに感情を選択させることで、より生きたキャラクターらしく感じられるのではないかと思います。
Function Callingは色々おもしろい使い方ができそうですね。
たとえば、
- 好感度を上げ下げする関数を作成し、LLMに好感度を操作させる
- システムプロンプトに好感度を含めることで、AIの反応を変化させる
というようにすれば、ゲームっぽく作れるのではないでしょうか。
コメント