kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

2023年振り返り&2024年の抱負

あけましておめでとうございます。 めっきりコチラのブログに書くこともなくなり、普段はひたすらにZennでその名の通り「Scrap」を量産する日々です。

一応、2023年の振り返りと2024年にやっていきたいことなどをつらつらと。

目次

2023年の振り返り

会社をやめてフリーランスになった

2023年3月までは正社員としてインフラエンジニアをやっていましたが、自分のやりたいことをやっていくための時間を多めに確保したいということでフリーランスになりました。ありがたいことに今のところは安定してお仕事を頂けてまして、自分の時間もそれなりに確保できている感じです。とはいえ、もっとやりたいことをもっと仕事にしたい、という思いはあり、そのためにも引き続きいろいろやっていきたいなというところ。

反面、フリーになって改めて正社員の良さみたいなものも見えるようになった気がします。正社員に絶対戻りたいとまではいかないですが、あまりこだわりのようなものはなくなり、自分の中での選択肢が増えた感はあります。いずれにせよ、今後もやりたいことと仕事がマッチするような環境に持っていきたいなと思っています。

LLMにどっぷり浸かった

2023年はLLMの年だったというのが正直なところです。自分的には、音声・対話インタフェースがやりたいことだったのですが、今までできなかったことがLLMによってできるようになり、さらに大きな可能性を感じた1年でした。

逆の意味では、音声・対話インタフェースというのは所詮1つのインタフェースにすぎないということを感じたこともあり、以前のようにスマートスピーカーを触ることはほとんどなくなってしまったのと、LLMにより深く関わっていくには自然言語処理や検索技術などの知識や経験が自分には圧倒的に足りないということも痛感しているところです。

とはいえ、毎日新しい技術が次から次へと出てきてキャッチアップもしんどいですし、まだまだ基礎となる知識やスキルも全然足りないということを感じながらも、歴史の分岐点のような印象もあり、そういう波に毎日触れ合う日々はとても刺激的で、実際に現在は業務としてLLMアプリの開発をやっていますが、本当に幸せだなと感じています。

2024年もただひたすらに目の前のことを苦しみながら楽しみながらやっていく所存です。

技術ブログはZennに完全に移行した

技術ブログをZennに移行して約1年、記事の総数は以下のような感じです。

種類 件数
記事 5
スクラップ 187
  • 2023年中に書いたものをピックアップ
  • スクラップはメモ書きのものも含む

合計192件はまあまあ書いたほうかなと思います。当初はScrapに書いたものを記事としてまとめ直す、と言うつもりだったのですが、記事はgitで管理したことで逆にちょっと面倒になってしまった感があります。あと、記事を公開するとなるとチェックなども含めて躊躇する部分も出てくる感があります。この点では品質というところについてはあまり意識できてないかもしれませんが、自分的にはこれがハードルになって記事を積極的に書かないというのはやりたくないという思いと、ただひたすらにアウトプットしていくというスタイルがScrapとあっているように感じています。まあ多くの人に見てもらいたいという気持ちもありつつも、自分の記憶やメモを残すために書いているという目的の方が強いので、これでもいいかなと思っています。

あとScrapのいいところは、Open/Closedなどの概念があることですね、気になったことはまずOpenでスクラップを作ってしまう、Openになっているものから興味があるものを選んで文章を書いてClosedしていく、というのはなんちゃってタスク管理っぽくてよいです。

Noteあたりもいいのかもですけど、以前少し試してみたときにはMarkdownの表現力があまりよくなかった印象があって、Zennは、Markdownの見た目もいいですし、書き心地も良いので、今のところとても満足しています。自分の使い方にも合ってるのかなと思いますし。

引き続く粛々と日々気になったことを手を動かしてそれを書くというのを継続していければなと思います。

LLM用にサーバを買った

贅沢かなぁと思いつつも買ってしまいました。

  • Intel Core i9-13900F 2.00GHz[P-core][最大5.60GHz] / 24コア / 32スレッド / 36MBキャッシュ
  • メモリ 96GB
  • NVIDIA GeForce RTX 4090 24GB

約50万!

一般コンシュマー向けとしてはそれなりにハイスペックなのではないでしょうか。買った時点ではどこまで使いこなせるか全然分からず、今もフルに使いこなしているとはいえませんが、ローカルLLMを動かすスペックとしては買ってよかったなと思っています。これはもう自分への先行投資ですね。ローカルLLMもよほど大きなものでなければ動かせますし、ディスクも追加したので出てきたモデルを片っ端から保存しても当面は困らないかなというところです。欲を言えば、メモリ256GBにしてRAMディスク使いたいなとか、GPUをもう1枚追加してGPUメモリ容量増やしたいなというのはありますが。もっと使いこなせるようにやっていきたいです。

メインの言語がPythonになった

過去の業務では、インフラエンジニアだったこともあって本格的なコードを書いていたわけではなく、シェルスクリプト・Perl・Rubyが中心で、あとはスマートスピーカー向けにNode.jsを使う、という感じだったのが、すっかりPython一色になってしまいました。NLP関連やデータ解析等のライブラリの豊富さにも助けられてますね。正直Node.jsやTypeScriptはもう書けない。。。

まだまだ使いこなせているわけではないですが、もっと使いこなしたいなと思っています。

競馬のデータ解析・可視化ツールを作った

趣味でやっている競馬のオンラインサロン向けに毎週のレース結果を解析・可視化するツールを作りました。一応これについてはサロン向けにしか詳細を明かしていないので、以下の記事のコメントで少しこんな感じのものというのを紹介しています。

Streamlit/Pandas/Plotlyを使っていますが、今までPythonに触れてこなかった自分にとってはこういうデータ解析・可視化みたいなのが簡単に作れてしまうというのは正直衝撃でした。StreamlitあたりはLLMのフロントエンドとしても使えるのもよいです。

自分は馬券よりもデータ解析の方に興味が向いているとはいえやはり当てたいw 今後は予想を支援するツールを作りたいなと思っています。

2024年の抱負

こちらはもう引き続きLLMガッツリやっていくということに尽きるかなと思っています。ただひたすら世の中の流れをおっかけた2023年に比べると、ポイントを絞って注力したいなと思っています。

  • RAGの精度を上げる、そのための色々な手法を試すと同時に、その評価の仕組みを確立したい
  • 対話インタフェースとは異なるインタフェース、特にエージェントの可能性を探っていきたい
  • チャットボットサービスではなく、自分の業務フローとLLM、効果の高い組み合わせや導入方法を模索したい
  • ローカルLLMの可能性をもっと探りたい、そして実践投入したい

この辺はお仕事の中でもやっていくところなのですが、個人的に2024年に作りたいと思っているのは、競馬予想を対話で教えてくれるRAG、あとは各種の情報と連携して予想支援を行うエージェントをローカルLLMで作りたいですね。

競馬予想におけるAIの活用はデータを元にした機械学習が多いと思うのですが、単に期待値の高い馬をピックアップする、ひたすら回収率を上げるためのものという印象です。それとは違うLLMを使ったアプローチで、ユーザーの競馬予想をあくまでも支援する、それにより予想の楽しみを提供するというものを作りたいなと思っています。あとはRAGをやるにしても自分が好きで興味がある分野で、かつ、それなりに精通しているデータでやるほうがいいかなというのは感じていたので。

今年1年学んだことを活かしつつ、2024年もやっていきます

今後の技術ネタはzennに移行することにした

今後の技術系の記事はzennで書くことにしました。

これまでは技術ネタも個人的なポエムもひっくるめて全部このブログで書いていたのだけど、

  • コードとかちょっと見にくい
  • そのために色々カスタマイズするのももうやりたくないし、テーマ変えるのも面倒。
  • 前から技術ネタ書くのにzennいいなと思っていた

ということで。そのためにVSCodeの執筆環境も作りました。Boilerplateありがたいですね。

ということで、こちらのブログでは個人的な話とかだけになるかなと思います。音声関係とか技術的な話は今後はzennのほうをごらんください。

気が向いたら既存コンテンツもzennに移すかもしれません。

引き続きよろしくお願いします。

OpenAIのQuick Startをやってみる

ちょっと前にChatGPTの話をしました。

あくまでも動いているものを試して見るだけで、これをどういう風に作るのか?ということまでは踏み込んでいませんでした。

ということでOpenAIのQuick Startをやってみたいと思います。

目次

GPT-3とは

ここがわかりやすい気がします。

www.nri.com

ChatGPTは、その名からも分かる通り、GPT-3をベースとして、対話に特化した形で実装されているようです。

Quick Startをやってみる

Quick Startはここです。

https://beta.openai.com/docs/quickstart/start-with-an-instruction

ドキュメントの中でもいくつか試せるようになっていますが、実際にアプリを作って試すのは「Build your application」のところです。今回はNode.jsでやってみることにします。

サンプルのレポジトリをクローンします。

$ git clone https://github.com/openai/openai-quickstart-node.git
$ cd openai-quickstart-node

OpenAIのAPIキーを.envファイルに記載します。

$ cp .env.example .env
OPENAI_API_KEY=XXXXXXXXXXXXXXX

パッケージをインストールします。

$ npm install

アプリケーションを起動します。http://localhost:3000 で立ち上がります。

$ npm run dev

> openai-quickstart-node@0.1.0 dev
> next dev

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
(snip)

ブラウザでアクセスするとこういうのが立ち上がります。

動物を入れるとその名前を生成してくれるようですね。Quick Startの最初で紹介されていた通りに試してみましょう。

"horse"を入力します。

結果はこうなります。

もう一度同じく"horse"を入力するとこうなります。

1回めと違いますね。"Temperature"により意図的に精度を下げて結果としてバリエーションが生まれるということですね。

https://beta.openai.com/docs/quickstart/adjust-your-settings

少し絞り込んでみましょう。"black horse"で。

"black"に関連しそうなキーワードが選ばれていますね。

コードを読んで見る

デモアプリはNext.jsを使っています。で、GPT-3へのAPI処理はpages/api/generate.jsになります。

import { Configuration, OpenAIApi } from "openai";

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

export default async function (req, res) {
  if (!configuration.apiKey) {
    res.status(500).json({
      error: {
        message: "OpenAI API key not configured, please follow instructions in README.md",
      }
    });
    return;
  }

  const animal = req.body.animal || '';
  if (animal.trim().length === 0) {
    res.status(400).json({
      error: {
        message: "Please enter a valid animal",
      }
    });
    return;
  }

  try {
    const completion = await openai.createCompletion({
      model: "text-davinci-003",
      prompt: generatePrompt(animal),
      temperature: 0.6,
    });
    res.status(200).json({ result: completion.data.choices[0].text });
  } catch(error) {
    // Consider adjusting the error handling logic for your use case
    if (error.response) {
      console.error(error.response.status, error.response.data);
      res.status(error.response.status).json(error.response.data);
    } else {
      console.error(`Error with OpenAI API request: ${error.message}`);
      res.status(500).json({
        error: {
          message: 'An error occurred during your request.',
        }
      });
    }
  }
}

function generatePrompt(animal) {
  const capitalizedAnimal =
    animal[0].toUpperCase() + animal.slice(1).toLowerCase();
  return `Suggest three names for an animal that is a superhero.

Animal: Cat
Names: Captain Sharpclaw, Agent Fluffball, The Incredible Feline
Animal: Dog
Names: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot
Animal: ${capitalizedAnimal}
Names:`;
}

順番に見ていきましょう。

createCompletionでテキスト補完の初期化を行っています。

  try {
    const completion = await openai.createCompletion({
      model: "text-davinci-003",
      prompt: generatePrompt(animal),
      temperature: 0.6,
    });

GPT-3は、用途に応じて4つのモデルを提供しています。これをmodelで指定します。精度やレイテンシー、費用などが異なるようです。

https://beta.openai.com/docs/models/gpt-3

temperatureは上で紹介したとおりですね。

promptでAPIに渡す文字列を指定します。ここでgeneratePromptが呼ばれていますね。

function generatePrompt(animal) {
  const capitalizedAnimal =
    animal[0].toUpperCase() + animal.slice(1).toLowerCase();
  return `Suggest three names for an animal that is a superhero.

Animal: Cat
Names: Captain Sharpclaw, Agent Fluffball, The Incredible Feline
Animal: Dog
Names: Ruff the Protector, Wonder Canine, Sir Barks-a-Lot
Animal: ${capitalizedAnimal}
Names:`;
}

Quick Startにもあったように、いくつかの例をヒントとしてモデルに渡すことで、より自分たちが期待する方向に寄せるような感じになります。

https://beta.openai.com/docs/quickstart/add-some-examples

日本語について

GPT-3は日本語にも対応しています。

ということで少し修正してみましょう。以下の関数を追加します。

function generatePromptJa(animal) {
  return `動物の日本っぽいクラシカルな名前を3つ挙げて。

動物名: 猫
名前: シロ, タマ, ミケ
動物名: 犬
名前: ポチ, ラッシー, ハチ
動物名: ${animal}
名前:`;
}

呼び出し元で関数名を上記に変えます。

   const completion = await openai.createCompletion({
      model: "text-davinci-003",
      prompt: generatePromptJa(animal),
      temperature: 0.6,
    });

試してみましょう。

どうでしょうか。そう言われてみれば、って感じかなと思います。

まとめ

とてもシンプルに使えていい感じですね。パラメータやヒントなどを色々変えて試してみると良いかと思いますし、プロンプトの例もあります。

https://beta.openai.com/examples

また、ビジネスのユースケースで使うには、コンテキストをあわせるような工夫も必要になるかなと思いますが、そのあたりも考えられているようです。ここはキーになるかなと思っているのでもう少し調べてみます。

https://beta.openai.com/docs/guides/fine-tuning