DifyのチャットフローにAPIで複数質問を送信して、テキストで保存する

import fs from "fs";
import fetch from "node-fetch";

const DIFY_API_KEY = "app-*";
const API_URL = "https://api.dify.ai/v1/chat-messages";

// テキストファイルから質問を読み込む
const prompts = fs
  .readFileSync("./prompts.txt", "utf8")
  .split("\n")
  .map((line) => line.trim())
  .filter(Boolean);

// Difyに問い合わせる関数
async function callDify(prompt) {
  const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${DIFY_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      inputs: {},
      query: prompt,
      response_mode: "blocking",
      conversation_id: "",
      user: "cli-user",
    }),
  });

  if (!response.ok) {
    const err = await response.text();
    throw new Error(`API Error ${response.status}: ${err}`);
  }

  const data = await response.json();
  return data.answer || "(No answer)";
}

// メイン処理
(async () => {
  const results = [];
  results.push("=== 質問と回答 ===\n");

  for (const [i, prompt] of prompts.entries()) {
    try {
      const answer = await callDify(prompt);
      const q = `Q${i + 1}: ${prompt}`;
      const a = `A${i + 1}: ${answer}\n`;

      // CLIに出力
      console.log(q);
      console.log(a);

      // ファイル保存用にも追加
      results.push(q, a);
    } catch (err) {
      const e = `Error for "${prompt}": ${err.message}`;
      console.error(e);
      results.push(e);
    }
  }

  // ファイルに保存
  fs.writeFileSync("results.txt", results.join("\n"), "utf8");
  console.log("\n=== 回答を results.txt に保存しました ===");
})();

prompt.txt

Node.jsでAPIリクエストを送る方法を教えてください。
ReactとVueの違いは何ですか?
GPTとBERTの違いを説明してください。

result.txt

=== 質問と回答 ===

Q1: Node.jsでAPIリクエストを送る方法を教えてください。
A1: うむ、それは簡単じゃ。まず、"axios"というライブラリをインストールせんとな。次に「axios.get("リクエスト先のURL")」というコードを書く。これでAPIにリクエストを送れるぞ。

Q2: ReactとVueの違いは何ですか?
A2: ふむ、ReactとVueか。ReactはFacebook製で大規模開発に向いており、Vueはやさしく始められる。しかし、どちらも優れたツールだ。お主が何を求めているか、それによる。

Q3: GPTとBERTの違いを説明してください。
A3: うむ、そなたが知識を求める姿勢は評価するぞ。GPTとは文章を生成するためのモデルで、一方、BERTは文章を理解するためのものじゃ。それぞれの目的に応じて、我々は適切な道具を選ぶべきじゃ。

Difyのチャットフローにサーバ側からAPIリクエストでテストしたい

node.js

const DIFY_API_KEY = "";
const WORKFLOW_ID = "";

// APIエンドポイントのURL
const url = "https://api.dify.ai/v1/chat-messages";

// APIリクエストの実行
async function runDifyChat() {
  try {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${DIFY_API_KEY}` // APIキーをAuthorizationヘッダーに設定
      },
      body: JSON.stringify({
        "inputs": {}, // 必要に応じて入力データを設定
        "query": "Node.jsでAPIリクエストを送る方法を教えてください。", // ユーザーからのメッセージ
        // response_mode を "blocking" に変更
        "response_mode": "blocking",
        "conversation_id": "", // 新しい会話を開始
        "user": "unique_user_id" // ユーザーを特定するためのID(任意)
      })
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`API Error: ${response.status} - ${JSON.stringify(errorData)}`);
    }

    // blockingモードなら、response.json() で直接パースできる
    const data = await response.json();
    console.log("APIレスポンス:", data);

  } catch (error) {
    console.error("エラーが発生しました:", error);
  }
}

// 関数を実行
runDifyChat();

$ node chat.js
APIレスポンス: {
event: ‘message’,
task_id: ’52ba8605-bac3-46b4-a0aa-5958079a3d01′,
id: ‘d858017a-052d-4a1b-86eb-da673707423e’,
message_id: ‘d858017a-052d-4a1b-86eb-da673707423e’,
conversation_id: ’37feb5fc-5694-48ae-ab86-e45fae25aaa9′,
mode: ‘advanced-chat’,
answer: ‘まずは「axios」というライブラリを用いると良い。以下のコードを参考にせんといかん。\n’ +
‘“`javascript\n’ +
“const axios = require(‘axios’);\n” +
“axios.get(‘APIのURL’)\n” +
‘ .then(response => {\n’ +
‘ console.log(response.data);\n’ +
‘ })\n’ +
‘ .catch(error => {\n’ +
‘ console.error(error);\n’ +
‘ });\n’ +
‘“`\n’ +
‘上記はGETリクエストの例で、POSTリクエストを送る際は`axios.get`の部分を`axios.post`に変え、第二引数に送りたいデータをオブジェクトとして渡せばよい。’,
metadata: {
annotation_reply: null,
retriever_resources: [ [Object], [Object], [Object] ],
usage: {
prompt_tokens: 2379,
prompt_unit_price: ‘0.03’,
prompt_price_unit: ‘0.001’,
prompt_price: ‘0.049953’,
completion_tokens: 206,
completion_unit_price: ‘0.06’,
completion_price_unit: ‘0.001’,
completion_price: ‘0.0091425’,
total_tokens: 2585,
total_price: ‘0.0590955’,
currency: ‘USD’,
latency: 2.760161219164729
}
},
created_at: 1757759242
}

Jetpack Compose + ViewMode

build.gradle.kts

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace = "com.example.myapplicationstate"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.example.myapplicationstate"
        minSdk = 24
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = "11"
    }
    buildFeatures {
        compose = true
    }
}

dependencies {

    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(libs.androidx.material3)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    androidTestImplementation(platform(libs.androidx.compose.bom))
    androidTestImplementation(libs.androidx.ui.test.junit4)

    implementation(libs.androidx.lifecycle.viewmodel.compose)
    debugImplementation(libs.androidx.ui.tooling)
    debugImplementation(libs.androidx.ui.test.manifest)
}

MainActivity.kt

package com.example.myapplicationstate

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.myapplicationstate.ui.CounterScreen

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                Surface {
                    CounterScreen()
                }
            }
        }
    }
}

MainViewModel.kt

package com.example.myapplicationstate.ui.theme

import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.myapplicationstate.MainViewModel

@Composable
fun CounterScreen(viewModel: MainViewModel = viewModel()) {
    val count by viewModel.count.collectAsState()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(32.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "カウント: $count", style = MaterialTheme.typography.headlineMedium)
 

Androidのstate

XMLレイアウト + Retrofit通信

activity_main.xml

<TextView
    android:id="@+id/counterText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="カウント: 0"
    android:textSize="20sp"
    android:layout_marginTop="16dp" />

<Button
    android:id="@+id/incrementButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="カウントアップ" />

MainActivity

package com.example.myapplication

import com.example.myapplication.ChatApi
import com.example.myapplication.ChatRequest
import com.example.myapplication.ChatResponse
import com.example.myapplication.ApiClient


import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {

    private var count = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val inputMessage = findViewById<EditText>(R.id.inputMessage)
        val sendButton = findViewById<Button>(R.id.sendButton)
        val resultText = findViewById<TextView>(R.id.resultText)

        val counterText = findViewById<TextView>(R.id.counterText)
        val incrementButton = findViewById<Button>(R.id.incrementButton)

        sendButton.setOnClickListener {
            val message = inputMessage.text.toString()
            val request = ChatRequest(name = "田中", job = "エンジニア")

            ApiClient.chatApi.sendMessage(request).enqueue(object : Callback<ChatResponse> {
                override fun onResponse(call: Call<ChatResponse>, response: Response<ChatResponse>) {
                    if (response.isSuccessful) {
                        val body = response.body()
                        resultText.text = if (body != null) {
                            "name: ${body.name}\njob: ${body.job}\nid: ${body.id}\ncreatedAt: ${body.createdAt}"
                        } else {
                            "応答なし"
                        }
                    } else {
                        resultText.text = "エラーコード: ${response.code()}"
                    }
                }

                override fun onFailure(call: Call<ChatResponse>, t: Throwable) {
                    resultText.text = "通信失敗: ${t.localizedMessage}"
                }
            })
        }
        
        incrementButton.setOnClickListener {
            count++
            counterText.text = "カウント: $count"
        }
    }
}

特徴 XMLレイアウト + Retrofit通信 Jetpack Compose
UIの作り方 XMLファイルで定義 Kotlinコードで定義
表示の変更 TextView.setText()などで明示的に更新 状態が変われば自動で再描画される
直感性 複雑で古いUIも対応できるが手間 シンプルでモダンなUIが書きやすい
可読性・保守性 XMLとKotlinが分かれて見づらくなる すべてKotlinに書けるので読みやすい
プレビュー Android Studioでリアルタイムプレビュー可能 同じく可(Compose Preview)

モダンな描き方はjetpack composeが良さそう

Androidの次の学習項目

⭐️ 高 ViewModel + State管理 複雑なUI状態を安全に管理。画面回転にも強い。
⭐️ 高 Repositoryパターン RetrofitやRoomとの接続を分離して保守性UP
⭐️ 高 Room(ローカルDB) オフライン保存・データ永続化の基礎
⭐️ 高 データの非同期処理(Coroutines / Flow) 通信やDB操作を効率的に行う。非同期処理の本命
⭐️ 中 UIのアニメーション Composeのanimate*関数で滑らかなUI体験
⭐️ 中 Dependency Injection(Hilt) テストしやすい、保守しやすい設計にするための基盤
⭐️ 中 Jetpack Compose Navigation(複雑版) 引数付き遷移、戻る処理、BottomNavなどを扱う
⭐️ 低〜中 テスト(Unit, UIテスト) 安定したアプリを作るには重要。ただし最初は後回しでもOK
⭐️ 低 デザインパターン(MVVMなど) 設計力を高めたいときに学習

いまいちピンとこないものが多いですが、結構ありますね。

iOSのstate

stateとは、アプリのローカルメモリ
アプリを終了すると消える仕組み、アプリごとにローカルメモリを持つ

iOSアプリは1つの プロセス として動作する

OSは各プロセスに 独立した仮想アドレス空間 を割り当てる
アプリA (プロセスA) → 仮想メモリ 0x0000_0000〜0xFFFF_FFFF
アプリB (プロセスB) → 仮想メモリ 0x0000_0000〜0xFFFF_FFFF

iOSはメモリ管理に 制約が強い
バックグラウンドアプリは一定時間で メモリを解放される
メモリ不足になるとアプリが強制終了されることもある

iOSも Linux と同じく プロセスの中にスレッドがある 仕組みになっています。正確には、iOS は Darwin(macOS/iOSのカーネル)上で動く Unix 系 OS なので、プロセスとスレッドの概念は Linux とほぼ同じ

DispatchQueue.global(qos: .background).async {
    // 重い処理
    let result = doHeavyTask()

    // UI更新はメインスレッドで
    DispatchQueue.main.async {
        self.aiReply = result
    }
}
Task {
    let result = await fetchDataFromServer()
    // メインスレッドでUI更新
    await MainActor.run {
        self.aiReply = result
    }
}
let queue = OperationQueue()
queue.addOperation {
    let result = doHeavyTask()
    OperationQueue.main.addOperation {
        self.aiReply = result
    }
}

### 実際にstateを実装してみる
CounterPage.swift

import SwiftUI

struct CounterPage: View {
    @State private var count = 0
    
    var body: some View {
        VStack(spacing: 20) {
            Text("カウンター")
                .font(.title)
            
            Text("現在の値: \(count)")
                .font(.headline)
                 
            Button("+1") {
                count += 1
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
                 
            Button("リセット") {
                count = 0
            }
            .padding()
            .background(Color.red)
            .foregroundColor(.white)
            .cornerRadius(8)
            
            Spacer()
        }
        .padding()
    }
}

ユーザー操作やイベントによって変わる値を保持することが多い
なるほど〜

Style-Bert-VITS2を試そう

$ mkdir tts
$ cd tts
$ git clone https://github.com/litagin02/Style-Bert-VITS2.git
$ cd Style-Bert-VITS2
$ python3 -m venv venv
$ ls
$ source venv/bin/activate
$ pip3 install “torch<2.4" "torchaudio<2.4" --index-url https://download.pytorch.org/whl/cu118 $ cat requirements.txt [code] # onnxruntime-gpu; sys_platform != 'darwin' [/code] $ pip3 install onnxruntime $ pip3 install -r requirements.txt $ pip3 initialize.py $ pip install style-bert-vits2 soundfile simpleaudio $ sudo apt install libasound2-dev $ pip3 install simpleaudio $ pip3 install style-bert-vits2 soundfile [code] from style_bert_vits2.tts_model import TTSModel from pathlib import Path import soundfile as sf # soundfile は requirements.txt に含まれています # モデルパス model_path = Path("model_assets/jvnv-F1-jp/jvnv-F1-jp_e160_s14000.safetensors") config_path = Path("model_assets/jvnv-F1-jp/config.json") style_vec_path = Path("model_assets/jvnv-F1-jp/style_vectors.npy") model = TTSModel( model_path=model_path, config_path=config_path, style_vec_path=style_vec_path, device="cpu" ) text = "こんにちは!仮想環境でも音声ファイルに保存できます。" # 音声生成 sr, audio = model.infer(text=text) # WAV に保存 sf.write("output.wav", audio, sr) print("output.wav に保存完了") [/code] [audio wav="http://hpscript.com/blog/wp-content/uploads/2025/09/output.wav"][/audio] jvnv-F1-jp/jvnv-F1-jp_e160_s14000.safetensors はStyle-Bert-VITS2 が使う日本語向け音声合成モデル本体 style_vectors.npy:複数の話者や声質の特徴ベクトル(スタイル変換用) スタイルベクトルで 複数話者・声質を切り替えられる pitchで微調整できる。 [code] sr, audio = model.infer( text="こんにちは", style=selected_style, length_scale=1.0, # 1.0が標準、<1で早口、>1でゆっくり noise_scale=0.5, # 音声の自然さ noise_scale_w=0.5, # ピッチ揺れの調整 ) [/code]

mcd(Mel Cepstral Distortion)による音声評価

$ pip3 install librosa

import librosa
import numpy as np

def calculate_mcd(ref_wav_path, syn_wav_path, sr=16000, n_mfcc=25):
    """
    Mel Cepstral Distortion (MCD) を計算する修正版関数
    正規化+フレームごとの距離平均を行います
    """
    # 音声読み込み
    ref, _ = librosa.load(ref_wav_path, sr=sr)
    syn, _ = librosa.load(syn_wav_path, sr=sr)

    # 正規化 (-1〜1 の範囲)
    ref = ref / np.max(np.abs(ref))
    syn = syn / np.max(np.abs(syn))

    # MFCC 抽出(c0 は除外)
    ref_mfcc = librosa.feature.mfcc(y=ref, sr=sr, n_mfcc=n_mfcc)[1:]
    syn_mfcc = librosa.feature.mfcc(y=syn, sr=sr, n_mfcc=n_mfcc)[1:]

    # フレーム数を揃える(短い方に合わせる)
    min_len = min(ref_mfcc.shape[1], syn_mfcc.shape[1])
    ref_mfcc = ref_mfcc[:, :min_len]
    syn_mfcc = syn_mfcc[:, :min_len]

    # フレームごとのユークリッド距離
    distances = np.sqrt(np.sum((ref_mfcc - syn_mfcc)**2, axis=0))

    # MCD 計算式(フレームごとの平均)
    mcd = (10.0 / np.log(10)) * np.sqrt(2.0) * np.mean(distances)

    return mcd

# 使用例
if __name__ == "__main__":
    ref_file = "original.wav"  # 参照音声
    syn_file = "tts.wav"       # 合成音声
    mcd_value = calculate_mcd(ref_file, syn_file)
    print(f"MCD: {mcd_value:.2f} dB")

$ python3 app.py
MCD: 568.47 dB

明らかに大きい

LangChainを触ってみる

LangChain は 大規模言語モデル(LLM, Large Language Models)を使ったアプリ開発を効率化するためのフレームワークです。

### LangChain とは?
– Python や JavaScript で使える オープンソースのライブラリ
– OpenAI GPT, Anthropic Claude, Llama などの LLM を 組み合わせて活用できる
– 単に「プロンプトを投げて応答をもらう」以上のことを簡単に構築できる

### 主な機能
– Prompt Management(プロンプト管理)
– Chains(チェーン)
「ユーザーの質問 → LLM 応答 → 外部データ検索 → さらに LLM 応答」みたいに処理をつなげられる
– Agents(エージェント)
LLM が「どのツールを使うか」を自分で判断して実行できる
例:Web検索、計算機、SQLデータベース などを LLM が使い分ける
– Memory(メモリ)
対話の履歴を覚えて、会話に文脈を持たせられる
– Retrieval(外部知識の利用)
RAG(Retrieval Augmented Generation)を簡単に構築できる
例:PDFやドキュメントをベクトルDBに格納して、質問に応じて検索し、LLMに渡す

### 必要なインストール
$ pip3 install langchain
$ pip3 install langchain-openai

from langchain_openai import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
import os
from dotenv import load_dotenv

load_dotenv()

llm = OpenAI(
    temperature=0.7,
    api_key=os.getenv("OPENAI_API_KEY")  # ← ここで明示的に渡す
)

# プロンプトのテンプレートを定義
template = "質問: {question}\n答えをわかりやすく説明してください。"
prompt = PromptTemplate(template=template, input_variables=["question"])

# LLMChain を作成
chain = prompt | llm

# 実行
response = chain.invoke({"question": "LangChainとは何ですか?"})
print(response)

$ python3 test_langchain.py

LangChain(言語チェーン)とは、さまざまな言語を繋げて利用することができるシステムのことを指します。つまり、複数の言語を一つのチェーン(連鎖)のようにつなげて、それぞれの言語を柔軟に切り替えて使うことができる仕組みです。これにより、異なる言語を話す人々がコミュニケーションを取る際に、よりスムーズに相手の言語を理解することができるようになります。また、翻訳や通訳の分野にも応用されています。

Gemini APIの利用

pip install -q google-generativeai

import google.generativeai as genai  # Googleの生成AIライブラリ
from google.colab import userdata  # Google Colabのユーザーデータモジュール

GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')
genai.configure(api_key=GOOGLE_API_KEY)

print("使用可能なGeminiのモデル一覧:")
for model in genai.list_models():
    if "generateContent" in model.supported_generation_methods:
        print(model.name)

model = genai.GenerativeModel("models/gemini-2.0-flash-001")
print(f"選択されたモデル: {model.model_name}")

config = genai.GenerationConfig(
    max_output_tokens=2048,  # 生成されるトークンの最大数
    temperature=0.8,  # 出力のランダム性を制御
)

def generate_content(model, prompt):
    response = model.generate_content(prompt, generation_config=config)
    return response.text

user_input = input("質問を入力してください: ")
response = generate_content(model, user_input)
print(f"Gemini: {response}")

LLMの内部構造: LLaMA-2

LLaMA-2の主要構造
1. Pythonコード (約1000行) : llama
2. パラメータ : llama-2-7b 次の単語予想に使用
3. トークナイザ : 前処理でテキストを分割

step1: トークナイザで入力テキストを細かく分割する
step2: Transformerとパラメータを用いて次の単語を予測
step3: 予測結果を元に次の単語を選択し結合
※予測結果から単語を選ぶプロセスをサンプリングと呼ぶ

model.py

class Transformer(nn.Module):
    def __init__(self, params: ModelArgs):
        """
        Initialize a Transformer model.

        Args:
            params (ModelArgs): Model configuration parameters.

        Attributes:
            params (ModelArgs): Model configuration parameters.
            vocab_size (int): Vocabulary size.
            n_layers (int): Number of layers in the model.
            tok_embeddings (ParallelEmbedding): Token embeddings.
            layers (torch.nn.ModuleList): List of Transformer blocks.
            norm (RMSNorm): Layer normalization for the model output.
            output (ColumnParallelLinear): Linear layer for final output.
            freqs_cis (torch.Tensor): Precomputed cosine and sine frequencies.

        """
        super().__init__()
        self.params = params
        self.vocab_size = params.vocab_size
        self.n_layers = params.n_layers

        self.tok_embeddings = ParallelEmbedding(
            params.vocab_size, params.dim, init_method=lambda x: x
        )

        self.layers = torch.nn.ModuleList()
        for layer_id in range(params.n_layers):
            self.layers.append(TransformerBlock(layer_id, params))

        self.norm = RMSNorm(params.dim, eps=params.norm_eps)
        self.output = ColumnParallelLinear(
            params.dim, params.vocab_size, bias=False, init_method=lambda x: x
        )

        self.freqs_cis = precompute_freqs_cis(
            # Note that self.params.max_seq_len is multiplied by 2 because the token limit for the Llama 2 generation of models is 4096. 
            # Adding this multiplier instead of using 4096 directly allows for dynamism of token lengths while training or fine-tuning.
            self.params.dim // self.params.n_heads, self.params.max_seq_len * 2
        )

    @torch.inference_mode()
    def forward(self, tokens: torch.Tensor, start_pos: int):
        """
        Perform a forward pass through the Transformer model.

        Args:
            tokens (torch.Tensor): Input token indices.
            start_pos (int): Starting position for attention caching.

        Returns:
            torch.Tensor: Output logits after applying the Transformer model.

        """
        _bsz, seqlen = tokens.shape
        h = self.tok_embeddings(tokens)
        self.freqs_cis = self.freqs_cis.to(h.device)
        freqs_cis = self.freqs_cis[start_pos : start_pos + seqlen]

        mask = None
        if seqlen > 1:
            mask = torch.full(
                (seqlen, seqlen), float("-inf"), device=tokens.device
            )

            mask = torch.triu(mask, diagonal=1)

            # When performing key-value caching, we compute the attention scores
            # only for the new sequence. Thus, the matrix of scores is of size
            # (seqlen, cache_len + seqlen), and the only masked entries are (i, j) for
            # j > cache_len + i, since row i corresponds to token cache_len + i.
            mask = torch.hstack([
                torch.zeros((seqlen, start_pos), device=tokens.device),
                mask
            ]).type_as(h)

        for layer in self.layers:
            h = layer(h, start_pos, freqs_cis, mask)
        h = self.norm(h)
        output = self.output(h).float()
        return output

いくつかの処理では、パラメータと呼ばれる数値を使用して演算が行われる
パラメータを繰り返し調整し、予想の精度を高める
※予想が誤っていた場合、パラメータを修正する (バックプロパゲーションと呼ばれる)
※LLMのパラメータ: 「Apple」という単語は、その単語が持つ意味、文脈、関連する概念(例えば、食べ物、会社名、色など)が、膨大な数値の集合(ベクトル)として表現されます。これらの数値の組み合わせによって、単語間の関係性が学習されています。
※単語のIDやトークンに対して数値ベクトルが割り当てられる
※モデルの大部分を占めるのは、単語間の関係性を理解し、次の単語を予測するための複雑な計算を行う、**アテンション機構やフィードフォワードネットワーク内の重み(weights)やバイアス(biases)**です。これらのパラメータが、文脈に応じた適切な単語の埋め込みベクトルを組み合わせ、最終的な出力を生成する。

### LLMの学習ステップ
学習ステップ1. 事前学習(Pre-training): 基盤モデル ただし、対話形式の学習が不足、不適切な質問にも答えてしまう
学習ステップ2. ファインチューニング(Fine-tuning): 特定のタスクや分野に特化させることができる
学習ステップ3. ヒューマンフィードバック(Human Feedback): 人間からのフィードバックを得る

### 事前学習に使われるデータ
モデルの用途によって、収集するデータ元(Webサイト、書籍、会話テキスト)の比率などが変わってくる。例えば、チャット用途の場合は、比較的会話データが多く学習される傾向にある。

### Transformer
Transformerの構造は主にEncoder(テキスト理解)とDecoder(テキスト生成)の要素から成り立つ

Attention機構の役割: 文中から関連度の高い単語を発見する