サイオステクノロジー(Tech.Lab)のブログ - TECH PLAY

TECH PLAY

サイオステクノロジー(Tech.Lab)

サイオステクノロジー(Tech.Lab) の技術ブログ

全739件

サイオステクノロジーの藤原です。 今回はApache Syncopeを構築してみました。手順は公式ドキュメント(https://syncope.apache.org/docs/)を参考に進めます。 前提条件 AlmaLinux 9.4 Java 17 Apache Syncope 3.0.7 Javaインストール # dnf -y install java-17-openjdk # java -version openjdk version "17.0.11" 2024-04-16 LTS OpenJDK Runtime Environment (Red_Hat-17.0.11.0.9-3) (build 17.0.11+9-LTS) OpenJDK 64-Bit Server VM (Red_Hat-17.0.11.0.9-3) (build 17.0.11+9-LTS, mixed mode, sharing) Apache Syncopeインストール ダウンロード ここ(https://syncope.apache.org/downloads)からZIPをダウンロードします。Signaturesのsha512の値を控えておきます # curl -LkvOf https://dlcdn.apache.org/syncope/3.0.7/syncope-standalone-3.0.7-distribution.zip フィンガープリントの確認 # sha512sum syncope-standalone-3.0.7-distribution.zip acb26d01d244e7bd33339f64c9811286e9178e5cd3b7e472fbeabf8be83bb8e77ccc8849f3e587ebacfec34887fd6ce73aa3333231952a60f316e4b71f624f8b  syncope-standalone-3.0.7-distribution.zip   先ほど控えたSignaturesのsha512の値とフィンガープリントが一致していることを確認します。 インストール 配置 ダウンロードしたパッケージを解凍して配置します。 # unzip syncope-standalone-3.0.7-distribution.zip # mv syncope-standalone-3.0.7 /opt/apache-syncope syncopeユーザを作成 # useradd syncope 権限を付与 # chown -R syncope. /opt/apache-syncope systemdで起動するように設定を追加 # vim /usr/lib/systemd/system/syncope.service [Unit] Description=Apache Syncope Service [Service] Type=forking User=syncope Group=syncope ExecStart=/opt/apache-syncope/apache-tomcat-9.0.89/bin/startup.sh ExecStop=/opt/apache-syncope/apache-tomcat-9.0.89/bin/shutdown.sh WorkingDirectory=/opt/apache-syncope/apache-tomcat-9.0.89/bin [Install] WantedBy=multi-user.target   サービス起動 SELinuxの無効化 # setenforce 0 systemd設定のリロード # systemctl daemon-reload サービス起動 # systemctl start syncope ログイン サービスはポート9080で起動します。 今回はポートフォワードでローカルポート8080からSyncopeサーバのポート9080にアクセスしています。 http://localhost:8080/syncope-console   ユーザー名:admin パスワード:password 構築からログインまで完了です。 初期設定ではDBのH2 Databaseがインメモリで起動するように設定されており、再起動するたび初期化されてしまいます。 DBにはこちら(https://syncope.apache.org/docs/getting-started.html#internal-storage)のものが使用可能なようなのでPostgreSQLにしたいなと思うのですが、現時点では設定方法が分かりません。。。       ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Apache Syncopeを構築してみた first appeared on SIOS Tech. Lab .
サイオステクノロジーの藤原です。 今回はmidPointをDistribution Packageから構築してみました。手順は( https://docs.evolveum.com/midpoint/install/bare-installation/distribution/ )を参考に進めます。 構築から初回ログインまでの流れについて説明していきます。 前提条件 AlmaLinux 9.4 Java 21 midPoint 4.8.3 Javaインストール # dnf -y install java-21-openjdk # java -version openjdk version "21.0.4" 2024-07-16 LTS OpenJDK Runtime Environment (Red_Hat-21.0.4.0.7-1) (build 21.0.4+7-LTS) OpenJDK 64-Bit Server VM (Red_Hat-21.0.4.0.7-1) (build 21.0.4+7-LTS, mixed mode, sharing) midPointインストール ダウンロード # curl -OL https://evolveum.com/downloads/midpoint/4.8.3/midpoint-4.8.3-dist.tar.gz 解凍 # tar zxvf midpoint-4.8.3-dist.tar.gz 配置 # mv midpoint-4.8.3 /opt/midpoint-4.8.3 # ln /opt/midpoint-4.8.3 /opt/midpoint midpointユーザ作成 # useradd -r -d /opt/midpoint/var -s /sbin/nologin -c "Midpoint daemon" midpoint 権限変更 # chown -R midpoint. /opt/midpoint-4.8.3 systemd設定 今回はこちら( https://docs.evolveum.com/midpoint/install/bare-installation/systemd/ )を参考にsystemdで起動するように設定してみました。 # vim /etc/systemd/system/midpoint.service [Unit] Description=MidPoint Standalone Service ###Requires=postgresql.service ###After=postgresql.service [Service] User=midpoint WorkingDirectory=/opt/midpoint ExecStart=/usr/bin/java -Xmx2048m -Dmidpoint.home=/opt/midpoint/var -jar /opt/midpoint/lib/midpoint.jar SuccessExitStatus=143 ###TimeoutStopSec=120s [Install] WantedBy=multi-user.target サービスの起動と自動起動設定 # systemctl daemon-reload # systemctl enable midpoint # systemctl start midpoint # systemctl status midpoint 初回ログイン administratorのパスワード確認 初回起動時のログにadministratorのパスワードが記載されているので確認します。 # grep "Administrator initial password" /opt/midpoint/var/log/midpoint.log 2024-08-27 05:00:20,660 [] [main] WARN (com.evolveum.midpoint.init.DataImport): Administrator initial password (except double quotes): "hogehoge" ログインする ポート8080でサービスが起動するので、midPointにログインします。 今回はポートフォワードでローカルポート28080からmidPointサーバのポート8080にアクセスしています。 https://localhost:28080/midpoint/ ユーザー名:administrator パスワード:hogehoge ホーム画面が表示されたら初回ログインまで完了です。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post midPointを構築してみた(From Distribution Package) first appeared on SIOS Tech. Lab .
サイオステクノロジーの藤原です。 前回はmidPointを構築しました(https://tech-lab.sios.jp/?p=42755)。 今回はmidPointでCSVからアカウントを作成したいと思います。   CSVの用意 源泉となるCSVを作成します。CSVはmidPointが載っているサーバ上に配置します。 ファイルにはmidPointが書き込みできる権限を与えます。 # vim /opt/midpoint/var/csv/csvresource.csv ユーザID 姓(漢字) 名(漢字) メールアドレス sios-test1 最雄 太郎 sios-test1@siostest02.com sios-test2 最雄 次郎 sios-test2@siostest02.com sios-test3 最雄 三郎 sios-test3@siostest02.com   リソースの作成 midPointと接続されるシステムはリソースとして定義されます。CSVのリソースを作成していきます。 ホーム画面から左ペインの「リソース」>「新規リソース」を選択します 「スクラッチ」を選択します 「CsvConnector」を選択します 基本情報を入力し、「次へ:設定→」へ進みます 最初に配置したCSVのファイルパスを指定し、「次へ:ディスカバリー→」へ進みます CSVファイルに書き込み権限がない場合、ここでエラーになります。   各項目を入力し、「次へ:スキーマ→」へ進みます デフォルトでAccountObjectClassにチェックが入っているので、そのまま「リソースの作成」を選択します リソースが作成できたので、「ウィザードを終了」からリソース一覧に戻ります 「CSVリソースblog用」が作成されました リソース・オブジェクトが認識されていることを確認します CSVに記載されたアカウントが認識されています リソースの設定 midPointは基本的にリソースを作成しただけでは何も処理が発生しません。midPoint側にCSVのリソース・オブジェクトに対応するユーザーが存在しない場合に、ユーザーを作成するように設定します。 オブジェクトタイプの追加 先ほど作成したリソースを選択し、「スキーマ処理」を開きます 基本情報を入力し、「次へ:リソース・データ→」へ進みます 種類はアカウントを選択します。CSVリソースに記載されているのはアカウントであるためです。 リソース・データを入力し、「次へ:MidPointデータ→」へ進みます ここはデフォルトのまま進めます。 MidPointデータを入力し、「設定を保存」を選択します タイプはユーザー、アーキタイプはPersonを選択します オブジェクトタイプが作成されます オブジェクトタイプの設定 作成したオブジェクトタイプにマッピングと同期の設定を行います マッピングを設定します。「インバウンドの追加」を選択します CSVリソースのアカウントの属性と、midPoint側のアカウントの属性との紐づけを行います。 今回は以下のように属性をマッピングしました 次に同期の設定を行います リソース側のアカウントとmidPoint側のアカウントを比較した時に、どのように処理を行うか定義します。 今回はリソース側のアカウントに対応するアカウントがmidPoint側に存在しない場合に、ユーザーを新規作成するような設定を行いました。   アカウント作成 リソースのライフサイクル状態をActiveにして、変更が反映されるようにします リソース・オブジェクトから対象アカウントを選択し、右側のアイコンから「インポート」をクリックしてアカウントをインポートします 状況がLINKEDになっていれば、midPoint側にユーザーとアカウントが新規作成され、CSV側のアカウントと紐づいた状態になっています。 左ペインのユーザー>すべてのユーザーを開きます 先程インポートしたアカウントからユーザーが作成されたことが確認できます。         ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post midPointでCSVからアカウントを作成する first appeared on SIOS Tech. Lab .
はじめに こんにちは!今月から生成AI活用事業がメイン業務になったなーがです。前回から少し時間が空いてしまいましたが、今回はAzure OpenAI Serviceの機能の一つであるOn Your Dataについて書こうと思います。 Azure OpenAI On Your Dataとは? Azure OpenAI On Your DataはAzure OpenAI Serviceの機能の一つで、簡単にRAGが構築できるサービスです。RAGって何?という方は、弊社ブログで解説していますので以下の記事をご覧ください。 RAG構築のためのAzure OpenAI Serviceリファレンスアーキテクチャ詳解 Azure OpenAI ServiceによるRAG実装ガイドを公開しました 【7/24無料開催】Azure OpenAI ServiceによるRAGハンズオン 〜独自データを用いた生成AIの利活用を学ぶ〜初級編 こちらは9月にも開催予定です! 【徹底解説】Document Intelligenceを利用してRAGを構築する【セマンティックチャンキング】 【初心者向け】RAG評価フレームワーク Ragasを必要最低限で使ってみる 【AOAI】RAGパイプラインの構築から評価フェーズまでの実装を一挙解説!【Ragas】 RAGを自前で構築するには以下の4つのリソースが必要となり、Azureを使用する場合はそれぞれ以下のようになります。 インデクサー:自前で作成 オーケストレーター:自前で作成 検索エンジン:Azure AI Search 生成AI:Azure OpenAI Service 弊社ブログでも「 RAG構築のためのAzure OpenAI Serviceリファレンスアーキテクチャ詳解 」として解説を行っていますが、あまりリソースを作ったことがない場合やコードはよく分からないからGUIでポチポチやって出来ないかな?と思われている方もいると思います。Azure OpenAI On Your Dataを使うと、以下のように自前で作成が必要だったインデクサーとオーケストレーターをAzure側でいい感じにやってくれます。 インデクサー: Azure OpenAI Service オーケストレーター: Azure OpenAI Service 検索エンジン:Azure AI Search 生成AI:Azure OpenAI Service 使い方 まず、作成が必要なリソースは以下になります。各リソースの作成方法に関しては長くなるのでここでは割愛します。 Azure OpenAI Service モデルのデプロイ Azure AI Search Azure ストレージアカウント Azure OpenAI Studioのプレイグラウンドを開くと、「セットアップ」の中に「データを追加する」があると思うので、クリックします。 ※新UIでやっています。旧UIの場合は「設定」の中に「データを追加する」があります。 「データソースの追加」をクリックします。 ローカルのファイルをアップロードするため、「データソースを選択する」で「Upload files (preview)」を選択して「次へ」をクリックします。 「サブスクリプション」、「Azureストレージアカウント」、「AI Search」を選択し、「インデックス名(今回はdocsとしました)」を入力します。 ※「Azureストレージアカウント」の「リソースの共有 (CORS)」が設定されていない場合は、下記のようにエラーが発生します。「CORSをオンにする」をクリックすることで、「リソースの共有 (CORS)」が設定されます。 ドラッグアンドドロップまたはファイルを参照して選択したファイル名が表示されたら「ファイルのアップロード」をクリックします。 「ファイルは正常にアップロードされました。」と表示されたら「次へ」をクリックします。 「検索の種類(今回はセマンティックにしました)」、「チャンクサイズ(今回はアップロードするファイルが小さいので256としました」を選択して「次へ」をクリックします。 「Azure リソース認証の種類」で「APIキー」を選択して「次へ」をクリックします。 「保存して閉じる」をクリックします。 インデクシングが開始されます。 しばらくすると、データソース作成が完了します。 AI Seachの「インデックス」を確認すると、アップロードしたファイルがインデックスとして登録されていることが分かります。 それではプロンプトで「テスト就業規則.pdf」に記載されている始業時間を質問をしてみます。望んだとおりの回答を得ることが出来ました。 回答に参照があるので開いてみると、参照元の情報(今回だとテスト就業規則.pdf)が表示されています。 データの削除 「データソースの削除」から「続行」をクリックすることでアップロードしたデータソースを削除できます。(※AI Searchのインデックスは削除されません) さいごに 今回はAzure OpenAI Serviceの機能の一つであるOn Your Dataについて書きました。生成AI活用事業に取り組み始めて1か月が経ち、少しずつ生成AIやRAGについての知識が付いてきたと思います。今後も業務で学んだことをブログにしていきたいと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure OpenAI Service の On Your Dataを使ってみた first appeared on SIOS Tech. Lab .
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 2024/7/31、株式会社グローバルインフォメーションは、市場調査レポート「Linuxソフトウェア市場:タイプ別、用途別:世界の機会分析と産業予測、2024年~2032年」の販売を開始しました。 Linuxソフトウェア市場:タイプ別、用途別:世界の機会分析と産業予測、2024年~2032年 https://newscast.jp/news/4939282 2024/8/7、Linux Foundation Research が「Open Source License Compliance」の日本語版「オープンソース ライセンス コンプライアンス」を公開しました。 オープンソース ライセンス コンプライアンス https://www.linuxfoundation.jp/publications/2024/08/open-source-license-compliance-jp/ 2024/8 の Windows セキュリティ更新プログラムが Windows / Linux のデュアルブート環境に影響があり、Linux 環境が起動しなくなる事象が発生する可能性があると発表しました。 August 2024 security update might impact Linux boot in dual-boot setup devices https://learn.microsoft.com/en-us/windows/release-health/status-windows-11-22h2#3377msgdesc ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2024年8月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech. Lab .
今号では、Linux における 標準入力 、 標準出力 、 標準エラー出力 について解説します! 標準入力・標準出力・標準エラー出力とは 標準入力 とは、プログラムが使うデータを受け取るための読み込み元を意味します。 主な標準入力として、 キーボード などがあります。 標準出力 とは、プログラムが使うデータの出力先を示します。 それに対して 標準エラー出力 とは、プログラムが使うデータのうち、エラーの出力先を意味します。 主な標準出力・標準エラー出力として、 コンソール、ディスプレイ などがあります。 また、コマンド操作における標準入力・標準出力・標準エラー出力では、 パイプライン 、 リダイレクト という仕組みを使用することができます。 パイプライン パイプラインとは、コマンドの出力を別のコマンドの入力として扱う仕組みです。 &#8220;|&#8221; で表現します。 例えば、text.txt というファイルの内容から grep コマンドで特定の文字列を抽出する場合、下記の様なコマンドを実行します。 # cat text.txt | grep aaa aaa 前提として、text.txt の内容は下記の通りです。 # cat text.txt aaa bbb ccc ddd eee この時、cat text.txt にて出力された内容が &#8220;|&#8221; (パイプライン) を通じて grep コマンドに渡され、grep コマンドはその 標準入力からデータを受け取っています 。 リダイレクト リダイレクトとは、コマンドの出力先を別の出力先 (ファイルなど) に変更することができる仕組みです。 &#8220;>&#8221; や &#8220;<" で表現します。 標準出力のリダイレクト 例えば、ls コマンドでカレントディレクトリのファイル一覧を表示させた場合、結果をコンソールではなくファイルに出力する場合、下記の様なコマンドを実行します。 # ls > /tmp/file.txt # file.txt の内容は下記の通りとなります。 # cat /tmp/file.txt file1 file2 file3 標準エラー出力のリダイレクト 上記で解説した標準出力 &#8220;>&#8221; の場合、 エラーとなる実行結果、つまり標準エラー出力 はリダイレクトしません。 例えば、先ほどと同様に ls コマンドの実行結果を標準エラー出力のリダイレクト &#8220;2>&#8221; を使用してファイルに出力してみますが、出力先ファイルには何も記録されません。 代わりに、デフォルトの標準出力であるコンソールに実行結果が表示されています。 # ls 2> /tmp/file.txt file1 file2 file3 # cat /tmp/file.txt # では、ls コマンドで存在しないファイルを指定して実行した場合はどうでしょうか。 この場合、コンソールには何も表示されず実行結果が file2.txt にリダイレクトされたことが分かります。 # ls file4 2> /tmp/file2.txt # cat /tmp/file2.txt ls: file4 にアクセスできません: そのようなファイルやディレクトリはありません 標準出力、標準エラー出力両方のリダイレクト 上記で解説した標準出力、標準エラー出力を両方同時にリダイレクトさせることもできます。 先ほどの 2通りの ls コマンドを下記の様にそれぞれ実行すると、いずれの場合も実行結果が各ファイルへ書き込まれた事が分かります。 # ls > /tmp/file.txt 2>&1 # ls file4 > /tmp/file2.txt 2>&1 # cat /tmp/file.txt file1 file2 file3 # cat /tmp/file2.txt ls: file4 にアクセスできません: そのようなファイルやディレクトリはありません 標準入力のリダイレクト パイプラインの章で解説した grep コマンドの実行例ですが、標準入力のリダイレクトを使用しても同じことができます。 # grep aaa ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!標準入力・標準出力・標準エラー出力について first appeared on SIOS Tech. Lab .
はじめに 皆さんこんにちは。 エンジニアの細川です! 今月のSIOS Technologyのアドベントカレンダー、テーマは「生成AI」ということで、生成AIを活用した次世代エディターのCursorについて紹介します!無料で試せるので気になる方はぜひこの記事を読んで試してみてください! Cursorとは? Cursorは生成AIによるサポートが組み込まれたエディターになります。 VSCodeをフォークしているので、使い勝手などは基本的にVSCodeと変わらず、多くの拡張機能にも対応しています。 コーディングの際に、サジェストしてくれたり、chatで相談できたりするような使い勝手としてはGithub Copilotがデフォルトで入っているエディターというような印象です。 例えばコーディングしていると以下のように、サジェストをしてくれます。 &nbsp; また、chatでコードについての質問などを自然言語で投げることができます。 以下はある関数のテストコードを書いてもらっている例です。 &nbsp; &nbsp; 利用料金 料金プランは無料プラン、Proプラン、Businessプランの3つです。 個人的に無料で始められるのが、かなり推しポイントです! Cursor導入手順 まずは こちら のページからCursorをダウンロードします。 ダウンロードしたファイルを開いて、Cursorをインストールしてください。 ダイアログ中の language 欄には「日本語」を入力します。 他はお好きなように設定してください! VSCodeで導入済みの拡張機能をワンクリックで導入してくれるので非常に便利です! おすすめ設定 続いて、日本語化の設定と、VSCodeのようにサイドバー表示にする設定のやり方を紹介します。 日本語化 まず日本語化です。 以下の「 Japanese Language Pack for Visual Studio Code 」の拡張機能が入っていない方は導入してください。 その後、「Ctrl + Shift + P」でコマンドパレットを開き、検索欄に「Language」と入力します。 検索結果の中から、以下のConfigure Display Languageの項目をクリックして、日本語を選択してください。 Cursorを再起動すれば、日本語になっていると思います。 サイドバー表示 続いてサイドバー表示の設定方法についてです。Cursorはデフォルトでは以下のようにツールバーが上部に表示されているのですが、こちらも設定で左サイドに表示させることができます。 まずは、以下のようにファイル→ユーザー設定→ 設定をクリックして、設定画面を開きます。 そして設定画面で検索欄に「activity」と入力して、以下のWorkbench &gt; Activity Bar: Orientationをクリックし、「vertical」を選択してください。 選択後再起動すると、VSCodeのように、左側にツールバーを表示させることができます。 権利系について ビジネス面で利用するうえで気になるのが権利系ではないでしょうか? 少し公式ページをあさってみたところ、 こちら の箇所に生成物の権利等はすべて利用者が所有するという記載がありました。生成物については権利上は問題なさそうです。 また、chatやソースコードなどの情報がモデルの学習に使われるのではないか?という懸念もあると思いますが、そちらはプライバシーモードを使うことで解決できます。 無料プランでもプライバシーモードを利用できるので、業務利用をする場合はプライバシーモードで利用すると良いかと思います。 Github Copilotとの違い 僕は業務でGithub Copilotを利用しているのですが、 Github Copilot と今回紹介したCursorとの違いについて紹介したいと思います。 Github Copilotは既にご存知の方も多いと思いますが、VSCodeなどの拡張機能で、導入するとCursorと同じようにコードをサジェストしてくれたり、chatでやり取りを行うことができます。両方使ってみた感想としても、どちらも非常に使い勝手が良くかなり似ている印象がありました。 違いを挙げるとすれば以下の3つかと思います。 無料プランの有無 利用できるモデルの違い 有料プランの価格の違い 無料プランの有無 まず、無料プランの有無ですが、Cursorには無料のプランがあるのに対し、Github Copilotには永続的な無料プランはありません。30日限定で無料で使うことはできますが、それ以降は基本的に最低のプランでも毎月10$かかってしまいます。 利用できるモデルの違い Github Copilotでは裏側で利用されるモデルをユーザー側で指定することはできません。現在はGPT4oが使われています。それに対して、Cursorではユーザーが使うモデルを自由に設定することができます。GPT4などはもちろんのこと、自身で契約しているAPIキーを入力することで、AzureのOpenAIやGeminiなど様々なモデルを利用することができます。自身で好きなモデルを利用できることはかなり良いんじゃないかと思います。 有料プランの価格の違い 最後は有料プランの価格の違いです。 Github Copilotは1番安い個人プランの場合月額10$となっています。 それに対して、Cursorは有料プランの場合安いプランでも月額20$とGithub Copilotと比べると高めの設定となっています。もちろん無料プランでも永続的に利用することができますが、本格的に利用する場合は有料プランを契約するかと思いますので、その際は価格も念頭に置いて吟味してみてください! まとめ Cursorはデフォルトでコードサジェストやチャットなどのサポート機能が搭載されたエディター 無料で利用できる! VSCodeと似ており、移行も簡単 プライバシーモードを利用することで業務利用も可能そう Github Copilotとも近い使い心地。有料プラン契約の場合は要吟味 おわりに 今回は少し前に注目されていたCursorを紹介させていただきました。 永続的に無料で使えるというのはやっぱりうれしいですね。 個人開発ではぜひ積極的に利用していきたいと思います! 他にも生成AI関連の記事がたくさん出ると思うのでぜひ そちら もチェックしてみてください! 参考にさせていただいた記事 https://roboin.io/article/2024/08/02/github-copilot-chat-now-powered-by-gpt-4o/ https://qiita.com/k1mu0419/items/2d903660d1f571abb8f2 https://note.com/harunorika/n/na8b374cd774e &nbsp; ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post AIエディターCursor使ってみた! first appeared on SIOS Tech. Lab .
初めに PS/SLの佐々木です。 PS/SLではweb3の新しい取り組みとしてHyperledger Fabricというコンソーシアム型ブロックチェーンを用いたPoC開発を進めています。 Hyperledger Fabricのキャッチアップをしていく中でローカル環境での開発のやりずらさを感じました。 具体的にはchaincodeをGitでバージョン管理するための方法やチーム開発時の環境構築、すべてがスクリプト化されていてコマンドの挙動検証がしずらいといったことがありました。 そこで今回Hyperledger Fabricのネットワークは用意されている test-network を使用し、Chaincodeとクライアントアプリケーションのレイヤーは別のリポジトリに切り出して、ビジネスロジックの実装に集中できる環境を作成したので紹介します。 リポジトリ 以下のことは紹介しません。 peer コマンドのオプションや引数の詳細な説明 chaincodeのコードの解説 クライアントアプリケーション(API)のコードの詳細な解説 では行きましょう https://hyperledger-fabric.readthedocs.io/ja/latest/prereqs.html ↑の事前準備は完了しているものとして進みます。 ネットワークの起動 ネットワークの構成は今回意識せずにビジネスロジックの開発に集中したいので事前に用意されているサンプルを使用します。 先ほどから紹介しているサンプルは以下のコマンドを実行することのよって取得することができます。 curl -sSLO &lt;https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh&gt; &amp;&amp; chmod +x install-fabric.sh ./install-fabric.sh docker samples binary ダウンロードが完了したら、 test-network ディレクトリに移動して以下のコマンドを順番に実行します。 cd abric-samples/test-network // ネットワークを初期化しておく ./network.sh down // ネットワーク起動 ./network.sh up createChannel // モニタリングに便利 ./monitordocker.sh fabric_test この先で peer コマンドを実行したいのでパスを通しておきます。 peer コマンドは fabric-samples/bin にあるので fabric-samples ディレクトリで以下のコマンドを実行してください。 // peerコマンドを実行するためのパス fabric-sample配下にbinファイルはあるので指定します export PATH=${PWD}/bin:$PATH 以上でネットワーク準備の完了です。 証明書管理 ネットワークを起動するとPeer, Orderer, Userなどの証明書が作成されます。 しかし fabric-sample の中にあると扱いが面倒なので自分のアプリケーションリポジトリにコピーします。 まず以下のコマンドで今回使用するアプリケーションのテンプレートをcloneします。 git@github.com:atomic-kanta-sasaki/hyperledger-fabric-client-application.git 続けて以下の証明書をCloneしてきたリポジトリにコピーします。 Ordererの各種証明書 `test-network/organizations/ordererOrganizations` を `hyperledger-fabric-application/certificate` にすべてコピー Peer, Userの各種証明書 `test-network/organizations/peerOrganizations` を `hyperledger-fabric-application/certificate` にすべてコピー Userの秘密鍵のファイル名変更(わかりやすくするため) `certificate/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/` にある秘密鍵をkey.pemに変更 `certificate/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/keystore/` にある秘密鍵をkey.pemに変更 左が今回のアプリケーションテンプレートで右側がHyperledger Fabricのテンプレートです。 証明書に関する作業は以上で終了です。 Chaincode 次に先ほど起動したpeerにchaincodeをinstallしていきましょう。 まず環境変数の設定です。 peer の設定ファイル core.yaml が hyperledger-fabric-application/config に入っているのでパスを以下のように環境変数設定します。 export FABRIC_CFG_PATH=$PWD/config/ 続いてchaincodeをinstallするためにはnode.js(typescript)をパッケージ化する必要があります。 以下のコマンドを実行して下さい。 依存ファイルのinstallとビルド npm install npm run build chaincodeのパッケージ化 peer lifecycle chaincode package basic.tar.gz --path ./ --lang node --label basic_1.0 *これ以降の環境変数をセットするときは  hyperledger-fabric-application  ディレクトリで実行します Org1のPeerにchaincodeをinstallする export CORE_PEER_TLS_ENABLED=true export CORE_PEER_LOCALMSPID="Org1MSP" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/certificate/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/certificate/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp export CORE_PEER_ADDRESS=localhost:7051 install cd chaincode peer lifecycle chaincode install basic.tar.gz Org2のPeerにchaincodeをinstallする export CORE_PEER_LOCALMSPID="Org2MSP" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/certificate/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/certificate/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp export CORE_PEER_ADDRESS=localhost:9051 install cd chaincode peer lifecycle chaincode install basic.tar.gz chaincodeの承認 chaincodeがPeerにinstallされたら組織ごとに承認する必要があります。 現在エンドースメントポリシーは設定していないので組織の過半数の承認が必要です。(組織の数が二つなのですべての組織から承認が必要) また承認フローにinstallしたパッケージIDが必要なので以下のコマンドで確認します。 peer lifecycle chaincode queryinstalled // 実行結果 Installed chaincodes on peer: Package ID: basic_1.0:4c7f4fd3119f70763b3ffbeb86566eccb3d2af8d6ab1ebe595eca7d37e9d98a7, Label: basic_1.0 パッケージIDを環境変数にセット export CC_PACKAGE_ID=basic_1.0:4c7f4fd3119f70763b3ffbeb86566eccb3d2af8d6ab1ebe595eca7d37e9d98a7 OrdererのTLS証明書のパスをセット export ORDERER_TLS_CERT=${PWD}/certificate/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem Org2 chaincodeの承認 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/certificate/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem //以下のログならOK 2024-08-23 16:04:06.118 JST 0001 INFO [chaincodeCmd] ClientWait -&gt; txid [39ecbbee6887f82f5a1684e584d7a65ae0a691f0733ff6b1d803f3ce0853844c] committed with status (VALID) at localhost:9051 Org1 chaincodeの承認 Org1で実行するための環境変数の設定 export CORE_PEER_LOCALMSPID="Org1MSP" export CORE_PEER_MSPCONFIGPATH=${PWD}/certificate/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/certificate/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt export CORE_PEER_ADDRESS=localhost:7051 承認 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${ORDERER_TLS_CERT} ↑一つのコマンドです chaincodeをチャネルにcommit チャネルメンバがchaincodeの定義を承認しているかを確認 peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json // 両方の組織が承認していることが確認できる { "approvals": { "Org1MSP": true, "Org2MSP": true } } commit peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0 --sequence 1 --tls --cafile ${ORDERER_TLS_CERT} --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/certificate/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/certificate/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt ↑一つのコマンドです commitの確認 peer lifecycle chaincode querycommitted --channelID mychannel --name basic --cafile ${ORDERER_TLS_CERT} // シーケンスとバージョンが返ってくる Committed chaincode definition for chaincode 'basic' on channel 'mychannel': Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true] これによりすべてのPeerでChaincodeを実行することができるようになりました。 クライアントアプリケーション 最後にクライアントアプリケーションの起動です。 今回はnest.jsを使用してAPIを作成しました。 ORMはprismaです。 ディレクトリは hyperledger-fabric-application/application になります。 依存関係のinstall npm install Migrationと初期データ投入 npx prisma migrate dev npx prisma db seed アプリケーションの実行 npm run start これでアプリケーションの起動完了です。 ではchaincodeにも初期データを入れて、データを取得してみましょう 初期化 POST &lt;http://localhost:3000/asset/init&gt; レスポンスは特にありませんが、初期データの登録が完了しました。 登録したデータの取得 GET &lt;http://localhost:3000/asset/all&gt; すべてのデータを取得できることが確認できます。 クライアントアプリケーションの実装 chaincodeで実装した関数を引数に渡せば呼び出せるようにしてあります。 chaincodeの呼び出しはRepository層にあり、Repository層でFabricGatewayServiceをDIしています。 FabricServiceGatewayにchaincodeとの接続設定がすでにあるので各Repository層でconnectionを作成しTransactionを発行することができます。 以下実際のソースコードです。 import { Contract } from "@hyperledger/fabric-gateway"; import { FabricGatewayService } from "src/repository/hyperledger/fabric-gateway/fabric-gateway.service"; import { Injectable } from '@nestjs/common'; import { Asset } from "src/domain/asset/asset"; @Injectable() export class AssetRepository { private readonly channelName = 'mychannel'; private readonly chaincodeName = 'basic'; private contract: Contract; private utf8Decoder = new TextDecoder(); constructor( // private readonly prismaService: PrismaService, private readonly fabricGatewayService: FabricGatewayService, ) {} // async onModuleInit() { // await this.fabricGatewayService.createConnection(); // this.contract = this.fabricGatewayService.getContract(this.channelName, this.chaincodeName); // } /** * TODO 本当はonModuleInitで呼び出すべきだが、ScopeをRequestServiceに定義していると動かないためいったん直接呼び出す方式で対応 */ private async ensureConnection() { await this.fabricGatewayService.createConnection(); this.contract = this.fabricGatewayService.getContract(this.channelName, this.chaincodeName); } async initLedger() { await this.ensureConnection() await this.contract.submitTransaction('InitLedger'); } async getAllAssets() { await this.ensureConnection() const resultBytes = await this.contract.evaluateTransaction('GetAllAssets'); const resultJson = this.utf8Decoder.decode(resultBytes); return JSON.parse(resultJson); } async getAssetById(assetId: string): Promise&lt;Asset&gt; { await this.ensureConnection() const resultBytes = await this.contract.evaluateTransaction('ReadAsset', assetId); if (!resultBytes || resultBytes.length === 0) { throw new Error(`Asset ${assetId} does not exist`); } const resultJson = this.utf8Decoder.decode(resultBytes); console.log(resultJson); const json = JSON.parse(resultJson); return Asset.create(json.ID, json.Color, json.Size, json.Owner, json.AppraisedValue); } async createAsset(asset: Asset) { await this.ensureConnection() await this.contract.submitTransaction('CreateAsset', asset.getId(), asset.getColor(), asset.getSize(), asset.getOwner(), asset.getValue()); } async transferAsset(asset: Asset) { await this.ensureConnection() console.log('\\n--&gt; Async Submit Transaction: TransferAsset, updates existing asset owner'); const commit = await this.contract.submitAsync('TransferAsset', { arguments: [asset.getId(), asset.getOwner()], }); const oldOwner = this.utf8Decoder.decode(commit.getResult()); console.log(`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`); console.log('*** Waiting for transaction commit'); const status = await commit.getStatus(); if (!status.successful) { throw new Error(`Transaction ${status.transactionId} failed to commit with status code ${status.code}`); } } } やや修正したほうが良い箇所はありますが、おおむねこのような形です。 あとは好きなようにUseCase層で呼び、自分たちの作りたいアプリケーションのビジネスロジックを組み立ててもらえればと思います。 課題 環境変数のセットに関しては同じことを複数回繰り返しているのでスクリプト化していきたいです。 またnest.jsの使い方やfabric-gatewayもすべて終えているわけではないので引き続きキャッチアップを進めていきます。 あと、Chaincode実行するまで問題点がわからない(install、承認、commitでは間違いに気づけない)のはちょっと辛いなと思いました。 終わりに ここまで読んでくださりありがとうございました。 これからも引き続きweb3の有益情報や新しいアウトプットがありましたらこちらで紹介しますのでよろしくお願いいたします。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Hyperledger Fabricの開発環境テンプレート公開しました first appeared on SIOS Tech. Lab .
AIに「ハルシネーションしないで」(「嘘つかないで」くらいの意味)と言うだけで効果があると話題になっています。 最近リリースされた macOS Sequoia ベータ版に搭載された新しい Apple Intelligence AI 機能のテスターが、AIが不正確な回答をしないようにするための条件を列挙したファイルを発見しました。※1 その中には、次のような文言が含まれていました。 “Do not hallucinate”(ハルシネーションしないで) ここでの「ハルシネーション」は「幻覚」を意味し、AI関連の用語では、AIが事実に基づかない回答をすることを指します。 簡単に言えば、AIが回答で嘘をつくことが「ハルシネーション」です。 そのため、「do not hallusinate」は、「嘘をつかないで」や「変なことを言わないで」という意味合いでしょうか。 これはテンプレートのプロンプトとなっており、AIにテキストで命令をする際に、毎回命令文と併せて利用されます。 つまり、Appleの技術者たちは、生成AIの不正確な回答を防ぐために、単純に「嘘をつかないでね」とお願いしているわけです。 このシンプルすぎるアプローチが話題になっていたので、本当に効果があるのか、実際に検証してみました。 ※1 https://arstechnica.com/gadgets/2024/08/do-not-hallucinate-testers-find-prompts-meant-to-keep-apple-intelligence-on-the-rails/ より翻訳 目次 検証 検証には、無料で複数のAIモデルを同時比較できるサービス、 天秤AI を利用します。(後日こちらの紹介記事もUP予定) AIに質問をして、ハルシネーションを起こさせた後、「ハルシネーションしないで」と付け加えて、再度同じ質問をしてみます。 chatGPTより、まあまあの賢さと早い回答速度が売りのGPT4-o miniと、 geminiより、こちらもまあまあの賢さと早い回答速度が売りのGemini1.5 Flashを利用して検証してみます。 まずは、ハルシネーションが起きやすそうな、芸能関係の質問をしてみます。 音楽バンド「ミセスグリーンアップル」と全てが逆の存在、「ミスターイエローポテト」が何人組か聞いてみます。 GPT4-o miniは大ハルシネーションです。 あまりにも堂々とした回答だったので僕のほうが弱気になって検索してみましたが、 音楽バンド ミスターイエローポテトはさすがに存在していませんでした。 geminiのほうではミスター・ポテト・ヘッド(存在するキャラクター)と間違われました。これはハルシネーションではないですね。 それでは、改めて、”ハルシネーションしないで” をつけて質問してみます。 効きました。 &nbsp; 結論 上記の検証に加えて、「ハルシネーションしないで」という指示で他の質問も試してみましたが、多少効果があるように感じました。 推測になりますが、AIは真面目な回答もできれば、ふざけた大喜利的な回答もするため、「ハルシネーションしないで」というお願いが、AIに真面目に答えてほしいという意図を伝え、一定の効果を発揮しているのかもしれません。 &nbsp; ボツにした検証 まずはじめに、各社の賢いモデルたちに質問してみました。 3モデルともまともすぎる回答が返ってきました。(検証にならなかったのでボツ) 賢さが売りのモデルでは、きちんとデフォルトでハルシネーションが抑えられているようです。 &nbsp; ボツ検証2 検証前に軽く試した感じだと、お願いしてもハルシネーションを起こすことが多かったです。 &nbsp; ハルシネーションしないでと頼むと、1人減りました。幻のメンバーだったらしいです。 &nbsp; &nbsp; プロンプトを強化してもダメでした。 なぜか聞く度にメンバーが減ります。 &nbsp; 「音楽グループのミスターイエローポテト」と指定したところ、うまくいきました。 いくら幻覚を見るなと言っても、質問が簡素すぎるといけないようです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post chatGPTに「ハルシネーションしないで」とお願いしたら効果がある? first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの佐藤陽です。 今日はAzure AI Searchのインデクシングに関する記事になります。 RAGの構築にあたっても非常に重要となる「Azure AI Search」の基本的なところを解説していきます! はじめに 正直なところ、今までなんとなくでAI Search使っていました。 AzurePortalのAI Searchから「データをインポート」としたら、いい感じにインデックスが作成された サンプルコードとか見ると、良い感じにインデックス作成するプログラムが既に提供されていた とりあえず適当にデータ投入しても、RAGに組み込んだらそれなりの回答返ってくる といった感じで、何となくでも使えてはいたのですが「これでいいのか&#8230;?」と思い、 腰を据えて公式ドキュメントや、様々な記事を読んでまとめてみました。 目新しい情報は無いかもしれないですが 「AI Search全然わからん」から「AI Searchなんとなく分かった」となれば幸いです。 (自分としては、公式のサンプルのインデクシングのサンプルコードは理解できるようになりました。) 今回の記事で扱うテーマとしては、AI Searchの中でも スキーマ設計の基本 や、 データ投入の実装 の部分とし、 スキーマの各種パラメータの解説や、設計からデータの投入までの基本的な流れを解説してきます。 また、まだまだ勉強中の身なので、見当違いのことを書いていたらコメントなどで教えていただけると幸いです! AI Searchの主な機能 Azure AI Searchの主たる機能としては以下2つです。 Azure AI Searchにデータを追加する処理(インデクシング) Azure AI Searchに対する検索処理(クエリの実行) MSの公式でも描かれている以下の図が分かりやすいです。 インデクシング 各種データをAI Searchに登録し、検索可能な状態とします。 特徴としては テキストとして登録するだけではなく、ベクトル値としても登録が可能 投入するデータに関して、細かいレベルで変換や検索の設定を行う事が可能(検索性能に直結) といった点が挙げられるかと思います。 繰り返しにはなりますが、今日はこのインデクシングの機能にフォーカスし スキーマの定義 インデックスの作成 データ投入 あたりの話をメインに書いていきます。 クエリの実行 ユーザーからの質問に対して回答を出す機能です。 ユーザーからの質問事項に対して、関連するデータを返すことが可能です。 この時単なるテキスト検索も可能ですし、ベクトル検索やセマンティック検索といった高度な検索も行うことが可能です。 クエリの実行に関しは、弊社武井が分かりみ深く紹介しているので、こちらを参照ください! (そのため本記事ではスコープ外とします。) 生成AI時代の様々な検索手法を検証する 〜Azure AI Searchによるベクトル/セマンティック/ハイブリッド検索〜 インデクシングとは MSの ドキュメント を確認すると、以下のように定義されています。 検索インデックスを設定するテキストのコンテンツとトークンを取り込み、解析し、格納することを指します。 インデックス作成により、情報取得をサポートする逆インデックスやその他の物理的なデータ構造が作成されます。 スキーマにベクター フィールドが含まれている場合は、ベクトル インデックスが作成されます。 ちなみにこの「Indexing」という単語ですが、日本語だと「インデクシング」と「インデックスの作成」と訳されることがあります。 また、他にも「インデクサー」という表現もあり、やや混乱しがちです。 本記事では以下のように使い分けたいと思います。 インデックス コンテンツを格納する場所(データ構造) インデックス作成 Azure AI Search上にインデックスを作成する事 インデクシング 作成されたインデックスに対してデータを投入する事 インデクサー インデクサーを行うアプリケーション インデックスのスキーマ定義 まずはインデックスの、おもにスキーマの設計について見ていきたいと思います。 いわゆるインデックスのデータ構造を決める部分になります。 スキーマに関しては、公式の ドキュメント に以下のようなjsonの形で定義されていました。  {   "name": "name_of_index, unique across the service",   "fields": [     {       "name": "name_of_field",       "type": "Edm.String | Collection(Edm.String) | Collection(Edm.Single) | Edm.Int32 | Edm.Int64 | Edm.Double | Edm.Boolean | Edm.DateTimeOffset | Edm.GeographyPoint",       "searchable": true (default where applicable) | false (only Edm.String and Collection(Edm.String) fields can be searchable),       "filterable": true (default) | false,       "sortable": true (default where applicable) | false (Collection(Edm.String) fields cannot be sortable),       "facetable": true (default where applicable) | false (Edm.GeographyPoint fields cannot be facetable),       "key": true | false (default, only Edm.String fields can be keys),       "retrievable": true (default) | false,       "analyzer": "name_of_analyzer_for_search_and_indexing", (only if 'searchAnalyzer' and 'indexAnalyzer' are not set)       "searchAnalyzer": "name_of_search_analyzer", (only if 'indexAnalyzer' is set and 'analyzer' is not set)       "indexAnalyzer": "name_of_indexing_analyzer", (only if 'searchAnalyzer' is set and 'analyzer' is not set)       "normalizer":  "name_of_normalizer", (applies to fields that are filterable)       "synonymMaps": "name_of_synonym_map", (optional, only one synonym map per field is currently supported)       "dimensions": "number of dimensions used by an emedding models", (applies to vector fields only, of type Collection(Edm.Single))       "vectorSearchProfile": "name_of_vector_profile" (indexes can have many configurations, a field can use just one)     }   ],   "suggesters": [ ],   "scoringProfiles": [ ],   "analyzers":(optional)[ ... ],   "charFilters":(optional)[ ... ],   "tokenizers":(optional)[ ... ],   "tokenFilters":(optional)[ ... ],   "defaultScoringProfile": (optional) "...",   "corsOptions": (optional) { },   "encryptionKey":(optional){ },   "semantic":(optional){ },   "vectorSearch":(optional){ } } 一部抽出して図に起こすと以下のような形となります。 イメージとしてはRDBMSのテーブル設計にも近いのかな、と個人的には思っています。 name がテーブル名、 fields が各カラムに対応している感じです。 RDBMSでも各カラムに対して型の定義をしたり、nullableに設定したりできますよね。 AI Searchはこれに加えて、「検索対象とするかどうか」などの検索に特化したパラメータを持っているような形となります。 スキーマ内容 このインデックスを構成するための値について、「何となく理解できる」レベルを目標に、表にまとめてみました。 一応わかりやすさのため「RDBMSでいうと?」という項目を付けてますが、あくまでイメージをつかむ程度で読んでください。 おそらくですが RDBMSのテーブル設計とAI Searchのスキーマ設計では考え方が異なる部分が多い かと思います。 key velue RDMBSでいうと? name インデックス名です。 テーブル名 fields インデックスの主役です。 データを投入するにあたって、データの形式などの詳細を決定します カラム fields.name フィールドの名称です。 カラム名 fields.type 投入するデータの型. Edm.StringやEdm.Singleなどがあります。 ベクトル値を入れる際はCollection[Edm.single]を利用します。 カラムの型 fields.searchable 全文またはベクトル検索を可能とするか否かを設定します。 fields.filterable 検索時の$filterクエリに対応するか否かを設定します。 fields.sortable 検索結果の並べ替え可能か否かを設定します。 デフォルトではAI Searchで算出されたスコアが高い順に並び替えられますが、 sortableを利用することでそのfieldの値で並べ替えることが可能となります。 fields.facetable フィールドの値での集約などが行えます。 例えば商品のデータをAI Searchに登録する場合、 fields.nameをcategoryしておき、「food」「clothes」などの値を登録します。 すると検索結果として、「food」のデータが何件、「clothes」のデータが何件、 といったような集約情報を確認することが可能です。 fields.key 各フィールドを一意に定めるための値。 typeとしてはEdm.Stringである必要があります 主キー(Primary Key) fields.retrievable 検索結果として値を返すか否かを設定します。 「FilterやSortの対象としては利用したいが、ユーザーには値を返したくない!」 といった要望の時に利用できるかと思います。 fields.analyzer テキストをトークンに変換するためのアナライザの設定です。 文章を 形態素解析 する際に利用されます。 明示的な指定がなければ標準でLuceneというアナライザが利用されます。 データが日本語の場合はひとまずja.luceneの利用をお勧めします。 fields. searchAnalyzer 上記のanalyzerはインデクシングとクエリ検索の場合に同じAnalyzerを使いますが、 それらを分けたい場合に個別に設定することも可能です fields. indexAnalyzer 同上 fields.normalizer Normalizerは、filterableやsortableとして指定されたフィールドに対する検索テキストを事前に処理する機能です。 処理内容としては、例えば検索テキストをlowercaseに変換したりといった内容で、表記揺れなどに対応可能です。 デフォルトはnullとなっているため、必要とする場合は設定します。 fields.synonymMaps 類義語をまとめたsynonymMapを指定します。 例えば「にわか雨」「夕立」「ゲリラ豪雨」といった言葉はどれも似たような事象を示しています。 その時にこれらをMapに変換しておくことで「にわか雨」という検索クエリが来た場合でも、 「夕立」として扱うことができる機能です。 fields.dimensions ベクトル化のデータの次元数になります。 fields.vectorSearchProfile ベクトル化をする際に行うプロファイルを指定します(後述) suggesters オートコンプリートやサジェストの入力に使用するフィールドを指定します。 scoringProfiles スコア付けをする際に、各フィールドに対して重みづけを行うことができます。 例えば「メニュー」というフィールドを重視するように設定した場合、 「コーヒー」というユーザーからの検索に対して、 ①「メニュー」のフィールドの中に「コーヒー」が含まれているデータ ②「詳細説明」というフィールドの中に「コーヒー」が含まれているデータ があった場合、①の方ががスコアが高くなります。 analyzers fields.analyzerでカスタムアナライザー利用する場合は、ここでカスタムアナライザーの内容を設定します corsOptions CORSの設定を行います encryptionKey インデックス内のデータを二重で暗号化します。 semantic セマンティックランカーの構成パラメータの指定を行います(後述) vectorSearch ベクトル検索のためのアルゴリズムおよびパラメータの指定を行います(後述) Fieldに中身に着目すると、searchableやfilterable, sortableなど、RDBMSではクエリを工夫して実行している部分を AI Searchではインデックス定義の時に細かく定義していることが分かります。 恐らくこれが膨大なデータから正確かつ高速に検索するためのポイントなのかと思います。 それだけAI Searchにおいてスキーマ設計が重要である、という事もうかがえます。 ここで、 semantic と vectorSearch に関しては重要なパラメータであるので、もう少し深堀してみてみたいと思います。 semantic 公式のドキュメントにsemanticの値のサンプルがありました。 "semantic": {     "defaultConfiguration": "my-semantic-config-default",     "configurations": [         {             "name": "my-semantic-config-default",             "prioritizedFields": {                 "titleField": {                     "fieldName": "HotelName"                 },                 "prioritizedContentFields": [                     {                         "fieldName": "Description"                     }                 ],                 "prioritizedKeywordsFields": [                     {                         "fieldName": "Tags"                     }                 ]             }         },                     {             "name": "my-semantic-config-desc-only",             "prioritizedFields": {                 "prioritizedContentFields": [                     {                         "fieldName": "Description"                     }                 ]             }         }     ] } 大きな流れとしては、 configurationsの配列の中で各セマンティックランカーの設定を行い それらを検索時に指定して利用する形になります。 各値の説明としては こちら に書いてありました。  今回設定する項目としては以下3つです。 titleField prioritizedContentFields prioritizedKeywordsFields それぞれのパラメータ(Title, Content, Keyword)として、どのフィールドを重視するかを設定します。 最低限prioritizedContentFieldsのみ設定されていればOKです。 これらの設定によって、セマンティックのランク付けの精度が変わってきます。 vectorSearch 次にvectorSearchの内容についてもみていきます。 こちらも公式のサンプルを載せます。 "vectorSearch": {      "algorithms": [          {              "name": "my-hnsw-config-1",              "kind": "hnsw",              "hnswParameters": {                  "m": 4,                  "efConstruction": 400,                  "efSearch": 500,                  "metric": "cosine"              }          },          {              "name": "my-hnsw-config-2",              "kind": "hnsw",              "hnswParameters": {                  "m": 8,                  "efConstruction": 800,                  "efSearch": 800,                  "metric": "cosine"              }          },          {              "name": "my-eknn-config",              "kind": "exhaustiveKnn",              "exhaustiveKnnParameters": {                  "metric": "cosine"              }          }      ],      "profiles": [        {          "name": "my-default-vector-profile",          "algorithm": "my-hnsw-config-2"        }      ]  } 大きく分けて algorithms と profiles の2つの値があります。 algorithmsとして、ベクトル検索に利用するアルゴリズムの詳細を定義します。 次に、profileの値としてnameと、使用するalgorithmを設定し、 nameの値(my-default-vector-profile)の値を、 fields.vectorSearchProfile に設定します。 "fields": [ { "vectorSearchProfile" = "my-default-vector-profile" } ] 今回、ベクトル検索のアルゴリズム内容の細かい設定に関しては割愛させていただきます。 インデックスの作成方法 次に、非常にシンプルなインデックスを実際に作成してみたいと思います。 作成に関してはRESTや各種SDKで作成可能です。 今回はRESTを使っていきたいと思います。 RESTの場合は、先程定義したjsonをbodyに入れて実行すればOKです。 今回は簡略化のためAPI Keyを利用して実行します。 ※今回、検索時の検証のためTagsのフィールドに関しては searchable はfaleseとしています。 POST /indexes?api-version=2024-07-01 HTTP/1.1 Host: {{resourceName}}.search.windows.net Content-Type: application/json api-key: {{apyKey}} Content-Length: 1090 {     "name": "idx-users",     "fields": [         {             "name": "UserId",             "type": "Edm.String",             "key": true,             "filterable": true         },         {             "name": "UserName",             "type": "Edm.String",             "searchable": true,             "filterable": true,             "facetable": false         },         {             "name": "Profile",             "type": "Edm.String",             "searchable": true,             "filterable": false,             "sortable": false,             "facetable": false,             "analyzer": "ja.lucene"         },         {             "name": "Age",             "type": "Edm.Int32",             "searchable": false,             "filterable": true,             "sortable": true,             "facetable": true         },         {             "name": "Tags",             "type": "Collection(Edm.String)",             "searchable": false, //falseとする             "filterable": true,             "sortable": false,             "facetable": true         }     ] } Azure Portal上からみると、正しく生成できていることが確認できました。 なお、もちろんAzure Portal上からでもインデックスの作成は可能です。 GUIベースでインデックスの作成や、フィールドの追加が行えます。 注意ポイント 感覚的にも分かることですが、  多くのフィールドを追加したり、フィールドに対するパラメータを複雑に設定すると インデックス作成の速度が低下します。 インデックスが小さいほど、インデックス作成は速くなります。 また、同様にパラメータを複雑にすることにより、格納するデータ量が増え、ストレージを圧迫するといったことも起こります。 パフォーマンスや、コスト影響する部分なので、このあたり気にしながら設計が必要かと思います。 インデクシング 定義したインデックスに対してデータを投入していきます。 データの投入方法としては、プッシュ型とプル型の2種類があります。 今回はプッシュ型を例に挙げてデータの投入を行っていきます。 先程作成したインデックスに対して、ダミーのデータを10件ほど用意します。 ChatGPTさんに、インデックス作成時に利用したbodyの内容を提示して、サンプルデータを作ってもらいました。 地味にこういう時に生成AIの便利さを痛感しますね。   {     "UserId": "1001",     "UserName": "田中 一郎",     "Profile": "東京都出身で大学卒業後に大手SIerに就職。Azureを使ったアプリケーションの開発に携わり、Azure Developer Associateの資格も取得している。趣味は本を読むことで、無類のミステリー好き",     "Age": 36,     "Tags": ["Engineer", "Azure"]   },   .... これらのサンプルをアップロードしていきます。 注意点としては、 リクエストのパスパラメータとして対象のインデックス名を入れる bodyのパラメータに @search.action を追加する の2点です。 POST /indexes/idx-users/docs/index?api-version=2024-07-01 HTTP/1.1 Host: {{resourceName}}.search.windows.net Content-Type: application/json api-key: {{apiKey}} Content-Length: 3518 {     "value": [         {             "@search.action": "upload",             "UserId": "1001",             "UserName": "田中 一郎",             "Profile": "東京都出身で大学卒業後に大手SIerに就職。Azureを使ったアプリケーションの開発に携わり、Azure Developer Associateの資格も取得している。趣味は本を読むことで、無類のミステリー好き",             "Age": 36,             "Tags": [                 "Engineer",                 "Azure"             ]         },         {             "@search.action": "upload",             "UserId": "1002",             "UserName": "鈴木 花子",             "Profile": "神奈川県出身。デザイン専門学校を卒業後、デザイナーとして活動。UI/UXデザインに興味があり、最近はフリーランスとして様々なプロジェクトに参加。趣味は絵を描くこと",             "Age": 28,             "Tags": [                 "Designer",                 "Freelance"             ]         },         {             "@search.action": "upload",             "UserId": "1003",             "UserName": "佐藤 次郎",             "Profile": "大阪府出身。マーケティングマネージャーとして多くの企業で経験を積む。デジタルマーケティングに精通しており、現在は自社のマーケティング戦略を担当。趣味はゴルフ",             "Age": 42,             "Tags": [                 "Marketing",                 "Manager"             ]         },         {             "@search.action": "upload",             "UserId": "1004",             "UserName": "山田 真美",             "Profile": "福岡県出身。大学卒業後、プロジェクトマネージャーとして多くのプロジェクトを成功に導く。現在はIT企業でPMとして活躍。趣味は旅行で、特に海外旅行が好き",             "Age": 33,             "Tags": [                 "Project Manager",                 "IT"             ]         },         {             "@search.action": "upload",             "UserId": "1005",             "UserName": "中村 健",             "Profile": "北海道出身。大学で情報工学を学び、現在は札幌のスタートアップ企業でエンジニアとして働く。クラウド技術に強く、AWSやAzureの資格を多数保有。趣味はキャンプ",             "Age": 29,             "Tags": [                 "Engineer",                 "Cloud"             ]         },         {             "@search.action": "upload",             "UserId": "1006",             "UserName": "伊藤 美咲",             "Profile": "名古屋市出身。大学で経営学を学び、現在は企業コンサルタントとして働く。経営戦略や財務分析に強く、多くの企業をサポート。趣味は読書で、特にビジネス書が好き",             "Age": 37,             "Tags": [                 "Consultant",                 "Business"             ]         },         {             "@search.action": "upload",             "UserId": "1007",             "UserName": "小林 隆",             "Profile": "千葉県出身。大学卒業後、大手メーカーでエンジニアとしてキャリアをスタート。現在はチームリーダーとして多くのプロジェクトを指揮。趣味は釣り",             "Age": 45,             "Tags": [                 "Engineer",                 "Leader"             ]         },         {             "@search.action": "upload",             "UserId": "1008",             "UserName": "松本 由美",             "Profile": "京都府出身。大学で心理学を学び、現在は人事部門で働く。社員のメンタルヘルスケアに力を入れており、多くの研修を実施。趣味はヨガ",             "Age": 31,             "Tags": [                 "HR",                 "Psychology"             ]         },         {             "@search.action": "upload",             "UserId": "1009",             "UserName": "高橋 大輔",             "Profile": "福島県出身。大学で化学を専攻し、現在は研究所で働く。新素材の研究に従事しており、多くの論文を発表。趣味は山登り",             "Age": 39,             "Tags": [                 "Researcher",                 "Chemistry"             ]         },         {             "@search.action": "upload",             "UserId": "1010",             "UserName": "森 美佳",             "Profile": "広島県出身。大学で文学を学び、現在は出版社で編集者として働く。多くのベストセラーを手がけ、業界で高い評価を受ける。趣味は料理",             "Age": 34,             "Tags": [                 "Editor",                 "Literature"             ]         }     ] } 実行後しばらくすると、10件のデータが投入されていることが確認できます。 なお今回、ベクトルデータは入れてないのでベクトルインデックスのサイズは0のままです。 せっかくなので、このインデックスに対して検索をしてみたいと思います。 例えば「広島」と入れて検索すると、Profileに広島が入っているドキュメントが抽出されます。  また、先程 searchable をfalseとしたTagsの情報で検索すると、ヒットしないことが分かります。 ただ、今回はベクトル検索をしているわけでもないので、特に検索の真新しさはないですね&#8230;。 今回の記事はあくまでインデクシングにフォーカスしているので、 また検索周りについては調査して記事にしていきたいと思います。 まとめ 今回はAzure AI Searchに対してインデックスを作成し、実際にデータを導入する流れを解説しました。 インデックスのスキーマ設計に関しては、非常に詳細な部分まで設定が可能で、ここがAzure AI Searchの性能を決める肝かと思いました。 RDBMSでもテーブル設計は非常に重要とされていますが、AI Searchのスキーマ設計はそれ以上に気を付けて行わなければいけ名ように感じます。 そのためにも、しっかりと投入元のデータの性質などに関して理解を深める必要がありそうですね。 また、今回はインデクシングに関して概要をさらっただけであり、まだまだ機能は多く存在しています。 ベクトル検索のためのスキーマ設計 セマンティック検索のためのスキーマ設計 プル型のデータ投入 スキルセット そのあたりにもまた触れて、しっかりと理解していきたいと思います。 ではまた! 余談 AI Searchはよく価格が高い事が言われてます。 実際ちょっとお高めだよなぁ、とは思います。 確かに、そのぶん高機能なのは今回勉強してみて感じましたが&#8230;。 一方で、最近CosmosDBがベクトル検索に対応したことで非常に盛り上がっており シンプルなRAGの構築するくらいなら、CosmosDBでもいいんじゃないか?という話も出てます。 ということでAI Searchのキャッチアップと並行して、CosmosDBを使った場合の検索についてもまた検討していきたいと思います。 参考資料 Azure AI Search ドキュメント &#8211; Microsoft 基本概念から理解するAzure AI Search &#8211; Azure OpenAI Serviceとの連携まで Azure Cognitive Search で日本語全文検索をするためのアナライザー実装メモ Azure Search 大全 生成AI時代の様々な検索手法を検証する 〜Azure AI Searchによるベクトル/セマンティック/ハイブリッド検索〜 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure AI Searchにおけるインデクシング入門ガイド first appeared on SIOS Tech. Lab .
はじめに こんにちは、tinaです。気が付けば新卒3年目となっていました。今回は、1年ぶりのブログ更新です。 この記事の内容はほぼ、2024/7/19(金)に行ったPS Live https://www.youtube.com/watch?v=NUu41GQ-G9g で話したものと同じです。 VMの自動起動を行う目的 今回は、Azure AutomationによるVMの自動起動の設定方法について紹介します。 AzureのVMは、自動停止の設定は簡単にできるのですが、自動起動の設定にはちょっとした手順を踏む必要があります。今回はそれについて説明していこうと思います。 例えば、テスト用のサーバーを特定の時刻だけONにしておきたい場合に、自動起動と自動停止の設定を組み合わせることで、常時サーバーを起動する場合に比べ、大幅なコストカットが実現できます。 以下は、2024年7月のAzureリソースの価格を利用して、常時VMを起動していたときと、平日の9時から22時までVMを起動していた場合の課金をそれぞれ計算した例です。全体のコストはほぼ半分ほどになる試算となりました。 さらに、利用するVMなどのリソースの価格が上がるほど、このような細かなコスト削減の恩恵は大きくなっていくはずです。 用語解説 Azure Automationとは 今回利用するAzure Automationは、Azure上やオンプレミス上で、繰り返し行われるタスクを自動化するためのツールです。LinuxとWindows両方のOSに対応しています。 Azure Automationはタスクの自動実行、構成管理、更新管理など、多くの自動化を実現することができる機能を持ちます。 今回は、Runbookを使ったタスクの自動実行を利用してVM自動起動の設定を行います。 Runbookとは ここで登場したRunbookについて説明を行います。Runbookは、Azure Automationの中で特定の自動化タスクを実行するためスクリプトやワークフローのことで、以下のような特徴があります。 Runbookの作成には、GUI、PowerShell、Pythonが利用できる Runbookの実行は、スケジュールや、Webhookによってトリガーすることができる 以下の図は、RunbookがAutomationアカウントによってどのように利用されるかを示すイメージ図です。 RunbookとAutomationアカウントとVMの関係図 Webhook Webhookを使うと、特定のイベントが発生したときに、通知を受け取って Runbook を開始することができます。例えば、Azureのリソースが変更されたり、新しいデータが追加された利した場合をトリガーとして操作を開始することができます。 手順 ここから、今回の目標を達成するための手順について紹介します。 細かい操作についての紹介になるので、実際に設定をしたいタイミングで参照することをオススメします。(こちらの手順は、2024年7月時点で作成しました。) 前提 コスト削減のため、VMが平日の9時に起動し、22時に停止する設定をしたい VMのシャットダウンはAzure PortalのUIから簡単にできるため、メインでAzure Automationを使ったVMの自動起動の手順について説明する(最後に、おまけとして自動停止の方法も紹介する) 詳細手順 以下の1~6の大まかな流れに沿って、詳細手順を紹介します。 事前準備 Automationアカウントの作成とRoleの設定 ギャラリーからRunbookの作成 Runbookの動作テスト Runbookの公開 スケジュール、パラメータ、実行の設定 1. 事前準備 起動対象のVMは作成済 fiap-pub リソースグループの、 fiap-pub-grafana-VM というVM 2. Automationアカウントの作成とAzure Role(役割) の設定 リソースグループはVMと同じ fiap-pub で、 fiap-pub-automation という名前のAutomationアカウントを作成 詳細設定は、システム割り当てマネージドIDで、パブリックアクセスを許可 AutomationアカウントにVMを操作するための権限を割り当てる Automationアカウントの [アカウント設定] &gt; [ID] を選択し、Azureロールの割り当てを押下する スコープを リソースグループ とし、VMが所属するリソースグループである fiap-pub を選択する。役割は 仮想マシン共同作成者 (共同作成者 = Contributor)として保存。 ※ ここで私の場合、リソースグループに対する操作権限をアカウントに割り当てる権限がないため、エラーとなり、アカウント管理者にロールの割り当てを依頼 ※ 仮想マシン共同作成者 は、仮想マシンの作成と管理、ディスクの管理、ソフトウェアのインストールと実行 etc… の権限を持つRole。(仮想ネットワークは別) 3. ギャラリーからRunbookの作成 ロールの割り当てが完了したら、[プロセスオートメーション] &gt; [Runbook] を選択。 [ギャラリーを参照] を押下。 ギャラリーから、[Start Azure V2 VMs] を選択。 Runbookに名前を付けてインポートする Automationアカウントのメニューから、[プロセスオートメーション] &gt; [Runbook]を確認すると、以下のように新規としてRunbookが作成されたことが確認できる。 4. Runbookの動作テスト 次に、[fiap-pub-auto-VM-start] を選択し、[編集] &gt; [ポータルで編集] を選択すると、[テストウィンドウ] が開き、Runbookの動作テストが行える。このRunbookはVMを起動するので、VMをOFFにした状態で[開始]を押下してテストする。 「実行中…」の表示が終了すると、以下のように「fiap-pub-grafana-VM has been startedと」表示され、正常に対象のVMが起動されたことが確認できる。 テストが正常に終了したら、テストウィンドウは [×] で閉じる。 5. Runbookの公開 作成したRunbookの編集メニューから、[公開] ボタンを押してRunbookを発行する 公開を行うと、作成状態のステータスが発行済みとなる 発行前は押下できなかった[開始] が押下できるようになった 6. スケジュール、パラメータ、実行の設定 [スケジュールへのリンク] を押下し、毎朝9時に起動するように設定を行う。 次にこのページが表示されるので、[スケジュール] を選択。 [スケジュールの追加] を押下し、来週以降、平日の朝に起動するように新しいスケジュールを設定し、[作成] を押下。 スケジュールへのリンクが作成されたら、以下のページの [パラメーターと実行設定] へ。 以下のようにテストの際に使用したのと同じ情報を入力し、OKを押下。これでVMの自動起動の設定が完了。 これでVMの自動起動の詳細手順は完了です。 私が初めてここまでの設定を行ったとき、テストの画面からそのままRunbookの実行に繋がるページが出るかと思ったが現れず、一度Runbookを公開してから、実行なりスケジュールの設定なりを行わなければいけないというフローがわからず、若干ハマりました。 おまけ①: 自動シャットダウンの設定 コスト削減のためにもっと重要な、自動シャットダウンの設定はポータルから簡単に行うことができます。以下手順を紹介します。 (自動起動も簡単にできるようにしてくれたら嬉しいです、、) VMのメニューの [操作] &gt; [自動シャットダウン] を選択。 以下のように設定し、保存をするだけ。 おまけ②: 正しく動いているかの確認方法 これまで、設定の方法を紹介しましたが、Azure Automationでスケジュールを設定しRunbookを実行した後で、正しく動作しているかを監視する方法を紹介します。 VMのメニューの [概要] 内の [監視] タブで、以下のように可用性のメトリクスを確認でき、VMがON/OFFしたタイミングをあとから確認することができる。 まとめ ここまで、Azure Automationについて説明し、Azure AutomationでVMを自動起動する方法を紹介しました。この方法は、VMを自動起動するだけの設定としては、ちょっと手間がかかるが、スクリプトを編集せずにVMに操作をかけられるのは便利ですね。Azure Automationによる自動化は、他でも色々応用が効きそうなので、活用していきたいです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure AutomationによるVMの自動起動 first appeared on SIOS Tech. Lab .
はじめに 皆さん、こんにちは! エンジニアの細川です。 皆さん、ChatGPTのFunction calling使ってますか? 今回はFunction callingを手軽にさくっとノーコードで試してみようということで、Postman flowsを使って試していこうと思います! Function callingって? 既にご存知の方も多いと思いますが、軽く説明してみます! 既にご存知の方は こちら まで読み進めてみてください! Function callingはChatGPTが外部関数の呼び出しが必要かどうか判断し、呼び出すタイミングを教えてくれる仕組みとなります! まず、Function callingがなぜ必要かというとずばり、ChatGPTなどのLLMの応答の不安定さにあります。 LLMは自然言語で利用でき、非常に便利なのですが、ChatGPTからのレスポンスをもとに、他のAPIを呼び出すときには応答の不安定さが弱点となってしまいます。 プロンプト内で「 {content: “xxxx”} のようなjson形式で出力して」のように指定したとしても、違う形式で返ってきたり、余分な文字列がついていたりして、他のAPIを呼んだりするときにはエラーとなってしまいます。 また、レスポンスが特定の値のときのみ、外部APIにリクエストを投げたい場合も多々あると思いますが、その条件分岐もresponse形式が正しくないとエラーとなってしまいます。そういったLLMの弱点を解決する方法がFunction callingとなります。 Function callingの具体的な方法①リクエスト 実際にどのようにFunction callingを行うか説明します。 まず、エンドポイントですが、通常のChatGPTのAPIなどのエンドポイントと変わりません。 Azure OpenAIを利用している場合は以下のようになるかと思います。 POST https://{Azure OpenAIのエンドポイント}.openai.azure.com/openai/deployments/{デプロイメント名}/chat/completions?api-version=2024-06-01 そして、RequestBody部分が以下のようになります。 リクエストBody1 { "messages": [ { "role": "user", "content": "今日の東京の天気は?" } ], "functions": [ { "name": "get_weather", "description": "与えられた地域の天気を取得します。", "parameters": { "type": "object", "properties": { "area": { "type": "string", "description": "天気予報取得対象の地域" } }, "required": ["area"], "additionalProperties": false } } ], "function_call": "auto" } messages プロパティは通常時の呼び方と同じくuserからのプロンプトの想定です。 それに functions という項目を追加しています。 functions では呼び出したい外部APIの名前、説明、呼び出すためのパラメータなどを指定します。詳細については ドキュメント をご参照ください。 また、 function_call というプロパティについては、autoにしておくと、投げたプロンプトによって、関数呼び出しが必要かどうかをChatGPT側が自動で判断してくれるようになります。 例えば、上の例だと天気の外部関数を登録しているので、「東京の天気は?」と聞くと外部関数を呼び出してくれますが、「今日の晩御飯はの献立は?」のように関係のない質問を投げると通常通りにGPTが返答をしてくれるようになります。 追記 先ほど教えてもらったのですが、 functions と function_call は現在非推奨となっており、 tools と tool_choice というプロパティになっているそうです。今はまだ使えそうですが、近々使えなくなるかもしれない点にご注意ください!( 参考 ) Function callingの具体的な方法②レスポンス 上記のように、リクエストボディーに functions を含めてリクエストを送ると、chatGPTが外部関数呼び出しが必要かどうかを判断し、必要な場合は以下のようなレスポンスを返してくれます。 レスポンスBody { "choices": [ { "content_filter_results": {}, "finish_reason": "function_call", "index": 0, "logprobs": null, "message": { "content": null, "function_call": { "arguments": "{\n\"area\": \"東京\"\n}", "name": "get_weather" }, "role": "assistant" } } ], "created": 1723356892, "id": "chatcmpl-9uw8q1ZXVFuvthhCPiqmmFHyI7lH0", "model": "gpt-35-turbo-16k", "object": "chat.completion", "prompt_filter_results": [ { "prompt_index": 0, "content_filter_results": {} } ], "system_fingerprint": null, "usage": { "completion_tokens": 16, "prompt_tokens": 82, "total_tokens": 98 } } まず、 choices の中の finish_reason というプロパティに注目します。 外部関数呼び出しを行う場合は、この finish_reason が function_call という値になっています。 リクエストで、 functions を渡していても、外部関数呼び出しが不要だとGPTが判断した場合はこの finish_reason が stop という値で返ってきます。 つまり、 finish_reason が function_call の時に外部関数を呼び出すようにアプリを実装することで、アプリをいつ呼び出すかを判断できるようになります。 続いて、 message の中身を見てみましょう。 "message": { "content": null, "function_call": { "arguments": "{\n\"area\": \"東京\"\n}", "name": "get_weather" }, "role": "assistant" } message の中身は呼び出す関数の種類とパラメータが返されています。 この arguments に返ってくるのはrequestを投げるときに指定した parameters の設定に応じた形式で返されます。 今回の場合は以下のような形式で、ユーザーが投げた質問から自動でパラメータの形式にしてくれます。 { "area": string } これをそのまま使って外部関数の呼び出しを行うことができます。 そして外部関数から受け取った結果を再びGPTに渡してあげることで、外部関数の結果をもとにした応答をユーザーに返すことができます。 リクエストBody2 { "messages": [ { "role": "user", "content": "東京の天気は、どうですか?" }, { "role": "function", "name": "get_weather", "content": "東京の天気は雨のち曇り"// &lt;= ここに外部関数の結果を入れる。 } ], "functions": [ { "name": "get_weather", "description": "与えられた地域の天気を取得します。", "parameters": { "type": "object", "properties": { "area": { "type": "string", "description": "天気予報取得対象の地域" } }, "required": ["area"], "additionalProperties": false } } ], "function_call": "auto" } 以上がざっくりとしたFunction callingの方法になります。 ではこれをノーコードでパパっと作るために利用するPostman flowsの紹介をしていきます。 Postman flowsとは Postman flowsはノーコードでAPIのフローを作れるツールとなります。 画面上にリクエストを送信するブロックなどを配置し、レスポンスをグラフに出力したり、1つ目のAPIのレスポンスをもとに2つ目のAPIにリクエストを送信するものなどを手軽に作成することができます。 Postmanのサイドバーのフローを押すとフロー作成画面に遷移し、そこから新しいフローを作成することができます。 今回はこのツールを使ってFunction callingをパット試してみたいと思います! 今回Function callingで呼び出すAPI 今回、Function callingで呼び出す外部関数の想定として、一つ簡単なAzure Functionsを作ってみました。 module.exports = async function (context, req) { context.log(`${req.body.area}の天気予報`); const SupportedAreas = { Tokyo: "東京", Osaka: "大阪" }; switch (req.body.area) { case SupportedAreas.Tokyo: context.res = { body: "東京の天気は雨のち晴れです。めっちゃ暑いです!" }; break; case SupportedAreas.Osaka: context.res = { body: "大阪の天気は霧です。寒いです。" }; break; default: context.res = { status: 400, body: "未対応の地域です。" } break; } } リクエストに応じて東京、もしくは大阪の天気を返す簡単なAPIです。 これを使ってFunction callingを試していきます。 事前にPostman上で用意しておくリクエスト Postman flowsは既に保存済みのリクエストをブロックとして配置して使っていくので事前に以下の3つのリクエストをPostman上に保存しておきます。 ChatGPTにユーザーからの質問想定で投げるリクエスト 外部関数を呼び出すリクエスト 外部関数の結果を踏まえてChatGPTに投げるリクエスト それぞれの詳細は以下のようになります。 ちなみに {{question}} などの二重波カッコで囲われているものはPostmanでは変数として認識されます。 ChatGPTにユーザーからの質問想定で投げるリクエスト // Endpoint(Azure OpenAIの場合) https://{azureのOpenAIエンドポイント}/openai/deployments/{デプロイ名}/chat/completions?api-version=2024-06-01 // Header api-key: Azure OpenAIのAPIキー // RequestBody { "messages": [ { "role": "user", "content": "{{question}}" } ], "functions": [ { "name": "get_weather", "description": "与えられた地域の天気を取得します。", "parameters": { "type": "object", "properties": { "area": { "type": "string", "description": "天気予報取得対象の地域" } }, "required": ["area"], "additionalProperties": false } } ], "function_call": "auto" } 外部関数を呼び出すリクエスト // Endpoint 関数のエンドポイント // RequestBody {{WeatherArea}} 外部関数の結果を踏まえてChatGPTに投げるリクエスト // Endpoint(Azure OpenAIの場合) https://{azureのOpenAIエンドポイント}/openai/deployments/{デプロイ名}/chat/completions?api-version=2024-06-01 // Header api-key: Azure OpenAIのAPIキー // RequestBody { "messages": [ { "role": "user", "content": "東京の天気は、どうですか?" }, { "role": "function", "name": "get_weather", "content": "{{WeatherResponse}}" } ], "functions": [ { "name": "get_weather", "description": "与えられた地域の天気を取得します。", "parameters": { "type": "object", "properties": { "area": { "type": "string", "description": "天気予報取得対象の地域" } }, "required": ["area"], "additionalProperties": false } } ], "function_call": "auto" } この3つのリクエストを用意できたら、いよいよPostman flowsで作っていきましょう! Postman flowを使ってパッと実践 実際に作ってみたフローがこちらになります。 流れとしては、最初にGPTにユーザーの質問想定でリクエストを投げ、外部関数呼び出しが必要でなければそのまま出力を表示し、外部関数呼び出しが必要であれば、Azure Functionsにリクエストを投げ、その結果を含めてもう一度GPTに投げて最終的に質問の回答を出力しています。 start直後のブロックのquestionという部分で質問を入力する想定です。 例えば「東京の天気は?」と入力すると。右下の緑のブロックに以下のように返答が出力されます。 それに対して、「今日は卵かけご飯を食べます」のように関係のない質問を投げると、中央辺りの水色のブロックに外部関数呼び出しをしなかった場合の返答が出力されます。 このようにPostman flowsを使うことでほとんど実装しなくても手軽にfunction callingを試すことができます! デプロイ 実は、Postman flowsはAPIとして公開することができます。Web Hookを作成し、Publishすることでブラウザなどから叩けるURLを発行してくれます。ただし、現時点では、レスポンスをカスタムできず、任意のレスポンスを返すことができないためあまり実用には向いていないかもしれません。ただ、レスポンスのカスタムにも近々対応するようで、もし対応されれば、Function callingを組み込んだアプリケーションとして実際に利用できるかもしれません。 まとめ Function callingを利用すると、ChatGPTをアプリに組み込みやすくなる! 外部関数の呼び出しタイミングや、JSON形式の安定出力など Postman flowsを使うことで、ほぼノーコードでFunction callingを試すことができる! 終わりに 今回はPostman flowsを使ってFunction callingを試してみました。アプリを作るのは少しハードルが高いかもしれませんがPostman flowsを使えば、ノーコードでお試しできるので皆さんもぜひ試してみてください!! 他にも生成AIの ブログ がジャンジャン出る予定ですので、ぜひチェックしてみてください! 参考にさせていただいた記事 https://zenn.dev/microsoft/articles/azure-openai-add-function-calling &nbsp; &nbsp; ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 1人がこの投稿は役に立ったと言っています。 The post ノーコードでFunction calling !? Postman flowsでFunction callingを試してみた! first appeared on SIOS Tech. Lab .
はじめに 皆さんこんにちは。 エンジニアの細川です! 今月のSIOS Technologyのアドベントカレンダー、テーマは「生成AI」ということで、Postmanの様々な機能をサポートしてくれるAIエージェントのPostbotについて紹介したいと思います! Postmanとは? Postman 皆さんもきっとよく使ってますよね? 説明するまでもないかもしれませんが、Postmanは主にAPIをテストするために様々な機能を提供してくれるツールになります。 APIにリクエストを投げる際、curlコマンドなどを叩かなくても、GUIですぐにリクエストを投げることができます。 クエリパラメータやbodyの値なども含めてrequestを保存することができ、環境ごとにtokenを切り替えたり、テストを自動化したりなど、非常に機能が豊富なツールになります。 僕も普段から大変お世話になっております… Postbotとは Postmanは非常に機能が豊富ですが、その豊富な機能を使う際にサポートしてくれるAIエージェントのPostbotという機能があります。 なんとこちら無料で使うことができます! 早速使ってみましょう! Postmanを開いて以下の画像の場所をクリックしてみてください! デスクトップアプリでも、ブラウザでも利用することができます。 上記の場所をクリックするとチャット画面が開きます。 後はChatGPTなどのように、自然言語で様々なお願いをすることができます。 日本語でお願いすると日本語で返してくれます! (絶賛開発中のようで、たまに、英語で返ってきたりもあります…) ドキュメント生成 では少し実践的に使ってみましょう! まずはリクエストからドキュメントを生成してくれます。 リクエストを開いた状態でPostbotに「このリクエストのドキュメントを書いて」とお願いしてみました。 すると、以下のようにマークダウンでドキュメントを書いてくれます! これは、Azure OpenAIServiceのDALL-Eにリクエストを投げる際の例になります(DALL-Eの詳しいリクエストの投げ方は こちら )。 RequesyBodyやヘッダー、クエリパラメータなどがある少し複雑なリクエストですが、一瞬でマークダウンのドキュメントを作成してくれました。 現在はドキュメントは英語のみの出力のようですが、リクエストからドキュメントを一瞬で作ってくれるのは非常に便利かと思います! テストコード自動生成 続いて、テストコードを書く際にサポートしてもらおうと思います。 ご存知の方も多いと思いますが、Postmanではリクエストごとにテストコードを記述することができ、自動実行もすることができます。先ほどのDALL-Eのリクエストのテストを書いてもらおうと思います。 リクエストを開いた状態で、Postbotに「このリクエストのテストを書いて」とお願いしてみました。すると以下のように一般的によく使われるテストケースでテストを自動で書いてくれます! また、テストケースを編集・追加したい場合などはもちろんエディター部分で直接変更することができます。さらに!テストの説明分まで書いた時点で以下のようにサジェストしてくれる機能がついています! いたれり尽くせりですね! その他の機能 今回紹介した以外にも質問に関連したPostmanのドキュメントのURLを教えてくれたり、エラーが起こった場合の原因の推測など幅広い用途に活用することができます! Postmanで困ったことがあればとりあえずPostbotに聞いてみるのが良さそうです! まとめ Postbotは無料で利用可能! ドキュメント生成 テスト自動生成(サジェストも) その他諸々サポート! おわりに 今回はPostbotについて紹介させていただきました。 Postman自体非常に便利で、普段から大変お世話になっていますが、このPostbotを利用することで今まで以上にPostmanを使いこなせそうな気がします。 今月は生成AIがテーマということで、他にも生成AIに関連した ブログ記事 がたくさん出るはずですので、皆さんぜひ読んでみてください! 参考 今回はネット上で公開してくださっている こちら の資料を参考にさせていただきました! &nbsp; ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post PostmanのAIエージェントPostbotが便利! first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの山﨑です。 6月末に OSC北海道 に参加し、生成AIを活用したエンタメアプリを展示してきました。中身としては、人間が発した文章から、喜び・悲しみ・怒り・恐れ・驚きの5つの感情の度合いを採点して得点にするというものです。しかし、プロンプトに採点させたところ、下記のような出力になりました。 概ね期待通りではありますが、かなり大雑把な点数なので、もう少し詳細に点数を出力してほしい所です。 そこでプロンプトを工夫して、5の倍数ではない中途半端な数字を出力させるための調査をしました。 調査内容 試したのは以下の2つです。 詳細な指示を与える フューショット学習 また調査する上での前提条件は下記です。 Azure OpenAIのGPT-4oを利用 喜び、悲しみ、怒り、恐れ、驚きの5感情について調査 5つの感情の強さの度合いを合計100点になるように採点 詳細な指示を与えた場合 まずは詳細な指示を与えた場合です。下記のような指示を与えました。 1点刻みで採点してください 5の倍数である必要はありません 詳細に採点してください。5の倍数である必要はありません 5の倍数にしないでください 順にプロンプトの内容とその出力結果を載せていきます。 1点刻みで採点してください この場合、最初の出力と採点結果は変わらず、意味はありませんでした。 5の倍数である必要はありません。 前までの出力は10点刻みだったので、先ほどと比べると詳細に採点してくれるようにはなりましたが、5の倍数である必要はないという指示は考慮されていません。 詳細に採点してください。5の倍数である必要はありません。 この場合、点数の採点理由を詳細に説明するようになりました。こちらも5の倍数である必要はないという内容は考慮されていません。 5の倍数にならないようにしてください 5の倍数にしないようにと強めに指示したところ、5の倍数ではない採点結果の箇所がありました。5の倍数にしないでという強めの命令には従うようになりましたが、半ば無理やり5の倍数にしないようにしているので、正しい採点とはいいがたいようにも思います。 フューショット学習 次にフューショット学習を試しました。 例文とその採点結果の例を1~5つ与えました。その際、採点結果は5の倍数ではないものを与えるようにしました。プロンプトは下記になります。 「ある文章について、喜び、悲しみ、怒り、恐れ、驚きの5つの感情のそれぞれの度合いを採点します。5つの感情の点数の合計が100点になるようにします。 (例をいくつか提示) 下記文章を採点してください。」 まずは1つ例を与えます。例の内容は下記になります(スクリーンショットは長くなるので、テキストにしました)。 負けて悔しいけど、次は勝てそう ・喜び:22点 ・悲しみ:27点 ・怒り:19点 ・恐れ:8点 ・驚き:24点 結果は下記のようになりました。 喜び:85点 悲しみ:0点 怒り:0点 恐れ:0点 驚き:15点 次に2つ例を与えます。例の内容は下記になります。 「負けて悔しいけど次は勝てそう」という文章の採点結果は次のとおりです。 ・喜び:22点 ・悲しみ:27点 ・怒り:19点 ・恐れ:8点 ・驚き:24点 「天気はいいが暑いのは苦手だ」という文章の採点結果は次のとおりです。 ・喜び:23点 ・悲しみ:21点 ・怒り:13点 ・恐れ:17点 ・驚き:26点 結果は下記のようになりました。 喜び:80点 悲しみ:3点 怒り:2点 恐れ:5点 驚き:10点 次に3つ例を与えます。例は下記のようになります。 「負けて悔しいけど次は勝てそう」という文章の採点結果は次のとおりです。 ・喜び:22点 ・悲しみ:27点 ・怒り:19点 ・恐れ:8点 ・驚き:24点 「天気はいいが暑いのは苦手だ」という文章の採点結果は次のとおりです。 ・喜び:23点 ・悲しみ:21点 ・怒り:13点 ・恐れ:17点 ・驚き:26点 「私と結婚してください」という文章の採点結果は次のとおりです。 ・喜び:41点 ・悲しみ:4点 ・怒り:6点 ・恐れ:18点 ・驚き:31点 結果は下記のようになります。 喜び:50点 悲しみ:5点 怒り:5点 恐れ:5点 驚き:35点 4つ、5つも与えましたが、3つ目と同じような採点結果になり、5の倍数にはなりませんでした。 考察 人間に対しても採点を頼んだら、テストでない限り80点や50点のように切りのいい数字を答えがちです。何となくAIだったら詳細な点数を返してくれるのではないかと期待しましたが、生成AIも人間に近い思考回路をしているのではないかと今回の検証で感じました。 また具体的な指示だということを聞いてくれそうだと感じました。今回の例の場合だと、「5の倍数」のような具体的な数値を出すと、AI側もそれを意識した回答をしてくれるように感じました。一方で、「必要はありません」のようなどちらでも構わないと解釈できてしまう指示だということを聞いてくれず、「してはいけない」のような指示でギリギリ聞いてくれそうでした。 最後にフューショット学習を試しましたが、例が増えるとなぜか中途半端な数字を出力しなくなりました。2個までだと期待する出力をしてくれましたが、数が増えると期待通りではない出力になりました。フューショット学習については要調査といった感じです。 AIに理由を聞いてみた 最後に、なぜ切りのいい数字ばかりを出力するのかAIに聞いてみました。そしたら、5つの理由を答えてくれました。 トレーニングデータの影響 生成AIは膨大なテキストデータをもとにトレーニングされています。これらのデータには、切りのいい数字(例えば10、20、50、100など)が頻繁に含まれていることが多いため、AIもそれに従う傾向があります。 ユーザーの期待に応えるため 人間はしばしば切りのいい数字を好む傾向があります。例えば、100点満点中の評価では80点や90点といった切りのいい数字がわかりやすく、受け入れやすいです。生成AIもこの傾向を学習し、ユーザーの期待に応えるために切りのいい数字を出すことがあります。 計算の簡便さ 切りのいい数字は計算や理解が簡単です。AIが生成する際にも、複雑な計算を避けるために切りのいい数字を選ぶことがあるかもしれません。 確率的傾向 生成AIは確率に基づいて次に出すべき情報を決定します。切りのいい数字は一般的に使用される頻度が高いため、その確率が高くなりやすいです。 簡素化と一般化 AIはしばしば情報を簡素化し、一般化する傾向があります。切りのいい数字はその一環として出てくることがあります。 以上の5つがAIの回答でした。ただしAIの出力であるため、必ずしも正しいとは限らないため、参考程度にしておくのがいいかもしれません。 最後に 今回はプロンプトで如何に5の倍数を出させないかというテーマでプロンプトエンジニア初心者が試行錯誤してプロンプトに色々な入力を試すという内容でした。生成AIを活用する上でプロンプトエンジニアリングのテクニックは必須なので、もっと積極的に触っていきたいですね。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post プロンプトでいかに5の倍数を出させないか first appeared on SIOS Tech. Lab .
ブログの投稿と連動してX(旧Twitter)に自動投稿するアプリのプロトタイプを紹介します。Google Apps Script(GAS)を使ってRSSフィードから情報を取得し、Azure OpenAI Serviceを利用して投稿内容を生成します。SNS担当者の負担を減らすためのシステム設計と実装方法を詳しく解説します。 挨拶 ども!生成AIのアドベントカレンダーが始まってブログ執筆を全力で取り組んでいる龍ちゃんです。検証は終わっているけど、ブログ化していないネタが大量にあるので指が大忙しです。 今回のネタは、ブログのPRに関係する活動のネタになります。内容としては、「RSSからブログの更新を取得して、Azure OpenAI Serviceを用いてブログの投稿内容を作成」する内容となります。まだ、検証の段階なので今回の記事ではTwitter APIを使用した自動投稿については扱いません。あらかじめご了承ください。今月中にはそこまで接続したアプリにしてまとめておきます。 それでは、タイトルの回収に参りたいと思います。 モチベーション 今回の記事でのモチベーションは、「SNS担当者の負担を減らす」というものになります。お恥ずかしいところですが、文面はAIが考えていますが投稿は人力で行っています。エンジニアが大量にいる会社なので、その辺をシステムチックに解消したいところが出発点となります。 理想とする姿としては、「ブログの投稿と連動して、決まった時間にXへポストする。もしブログの投稿がない場合は、宣伝に切り替える」となります。 今回の記事の内容では、「ブログの更新を取得する」と「AIに文面を考えてもらう」という部分までのプロトタイプになります。 設計 今回は、プロトタイプということもありGoogle Apps Script(以降:GAS)を使用しています。全体像としては、以下の画像のイメージになります。 GASでやることは以下の三つになります。 RSSへ問い合わせをして記事情報を取得 URLから記事の内容を取得する 記事の内容からAOAIにXへのポスト内容を作成依頼 記事の情報は、Google Spreadsheet上ですべて管理を行っています。重複した情報を投稿しないようになどの工夫が入っているので、実装の際に紹介をしていきたいと思います。 今回のゴールとしては、以下のようなスプレッドシートが出来上がります。 ヘッダー情報としては、Title/Link(記事URL)/PubDate(執筆日)/RowData(記事HTML)/PostData(Xへのポスト)になります。 実装 各段階に分けて、コードの記載を行っていきます。スプレッドシートにアクセスする部分に関しては共通処理なので、シート名を渡すと有効なシートが返答されるように関数化しておきます。 const accessSheet = (sheetName) =&gt; { const file = SpreadsheetApp.getActiveSpreadsheet() const sheet = file.getSheetByName(sheetName) return sheet } RSSから情報を取得する ここで実装していく内容としては、「RSSフィードに問い合わせを行い、すでに取得している情報であればそぎ落としてスプレッドシートに保存」になります。 まずは、RSSフィードから情報を取得する部分になります。サンプルとしては、弊社のブログのRSSフィードを利用します。(ぜひウォッチしてね(&gt;_&lt;)) const getRSSFeed = () =&gt; { // RSSフィードのURLを指定 const rssUrl = &#039;&lt;https://tech-lab.sios.jp/feed&gt;&#039;; // ここにRSSフィードのURLを入力してください // RSSフィードを取得 const response = UrlFetchApp.fetch(rssUrl); const xml = response.getContentText(); const document = XmlService.parse(xml); const root = document.getRootElement(); // RSSフィードのエントリを解析 const items = root.getChild(&#039;channel&#039;).getChildren(&#039;item&#039;); const data = &#x5B;]; items.forEach(function (item) { const title = item.getChild(&#039;title&#039;).getText(); const link = item.getChild(&#039;link&#039;).getText(); const pubDate = new Date(item.getChild(&#039;pubDate&#039;).getText()); data.push(&#x5B;title, link, pubDate]); }); return data } こちらでは、XMLで返答されたデータをJSONに変換して構造化しています。この関数を利用して、重複削除を行うコードが以下になります。 function stackSheetFromRSSFeed() { // 定期実行することでRSSからの情報をスプレッドシートに情報をためる // GoogleスプレッドシートのIDを指定 const sheet = accessSheet(&quot;元データ&quot;) const lastRow = sheet.getLastRow() // Logger.log(lastRow) // 重複削除の必要があるため現在のリストを取得 const linkList = sheet.getRange(2, 2, lastRow - 1, 1).getValues().map((row) =&gt; row&#x5B;0]) // RSSから情報取得 const dataFromRSS = getRSSFeed() // 重複削除処理 const data = &#x5B;] dataFromRSS.forEach((value) =&gt; { const link = value&#x5B;1] if (!linkList.includes(link)) data.push(value) }) // 更新なしの場合は処理終了 if (data.length == 0) return // シートに書き込み処理 sheet.getRange(lastRow, 1, data.length, data&#x5B;0].length).setValues(data) } すでに存在しているURLを一覧で取得し、そこから重複を削除してデータの保存を行っています。 URLから記事の情報を取得する ここで、実装していく内容としては「記事のURLから記事のHTML情報を取得して、スプレッドシート保存」になります。 なぜ?一度HTMLの情報を取得するのか? AOAIでは、URLから情報を取得することができないからです。一度テキストデータとして取得する必要があります。この辺は初耳情報でしたね。 const getPageHTML = (url) =&gt; { var response = UrlFetchApp.fetch(url); var html = response.getContentText(); // HTMLを解析 var document = HtmlService.createHtmlOutput(html).getContent(); // 必要な部分を抽出(この記事の内容が &lt;section&gt; タグ内にあると仮定します) var content = &#039;&#039;; var regex = /&lt;section class=&quot;entry-content&quot;&#x5B;^&gt;]*&gt;(&#x5B;\\\\s\\\\S]*?)&lt;\\\\/section&gt;/; var match = regex.exec(document); if (match &amp;&amp; match&#x5B;1]) { content = match&#x5B;1]; } else { content = &#039;記事の内容を取得できませんでした。&#039;; } return content } ここでは、GASの機能を使用してHTMLを取得して正規表現で本文部分のみを取得しています。 こちらを用いて、重複削除や情報を取得済みのものに関しては情報を取得しない処理などを追記したものを記載します。 function createRowData() { const sheet = accessSheet(&quot;元データ&quot;) const lastRow = sheet.getLastRow() const header = &#x5B;&quot;Title&quot;,&quot;Link&quot;,&quot;PubDate&quot;,&quot;RowData&quot;] const dataList = sheet.getRange(2, 1, lastRow - 1, header.length).getValues() dataList.forEach((value, index) =&gt;{ const &#x5B;,link,,rowData] = value // すでに情報がある場合はスルー if(rowData!=&quot;&quot;)return const htmlData = getPageHTML(link) value&#x5B;3] = htmlData // 書き込み処理 sheet.getRange(index + 2, 1, 1, header.length).setValues(&#x5B;value]) // HTML取得に関しては攻撃にもなるので人間的な挙動にしてます。 Utilities.sleep(1000); }) } スプレッドシートに記載している情報がない場合は、スルーすることで取得済み判定を行っています。 記事内容からXへの投稿内容を取得する ここで実装する内容としては、「取得済みのHTML情報からAOAIに問い合わせを行い、Xへの投稿内容を作成」になります。問い合わせに使用するプロンプトは以下になります。 System あなたはSNS担当者です。送付した内容からXの投稿を作成してください。内容は日本語の300文字以内で作成してください。ブログの導入などのリンクはつける必要はありません。 --- HTML情報 --- まずは、AOAIに問い合わせする処理を関数として切り出します。 const createPostUseAOAI = (text) =&gt; { const apiEndpoint = PropertiesService.getScriptProperties().getProperty(&quot;AOAI_API_URL&quot;); const modelName = PropertiesService.getScriptProperties().getProperty(&quot;AOAI_API_MODEL&quot;); const apiVersion = PropertiesService.getScriptProperties().getProperty(&quot;AOAI_API_VERSION&quot;); const apiKey = PropertiesService.getScriptProperties().getProperty(&quot;AOAI_API_KEY&quot;);; // ここにAzure APIキーを入力 const apiUrl = `${apiEndpoint}/openai/deployments/${modelName}/chat/completions?api-version=${apiVersion}`; // ここにAzure OpenAIエンドポイントURLを入力 // OpenAI APIに送信するデータ const payload = { model: modelName, // &#039;model&#039;パラメータのみ使用 messages: &#x5B;{ role: &quot;system&quot;, content: &quot;あなたはSNS担当者です。送付した内容からXの投稿を作成してください。内容は日本語の300文字以内で作成してください。ブログの導入などのリンクはつける必要はありません。&quot; }, { role: &quot;user&quot;, content: text }], // プロンプトをメッセージリストの形式に変更 }; const options = { method: &#039;POST&#039;, headers: { &quot;Content-Type&quot;: &quot;application/json&quot;, &quot;api-key&quot;: apiKey }, payload: JSON.stringify(payload), muteHttpExceptions: true }; try { const response = UrlFetchApp.fetch(apiUrl, options); const responseJson = JSON.parse(response.getContentText()); const res = responseJson.choices&#x5B;0].message.content.trim(); return res } catch (e) { Logger.log(`error:${e}`) return } } AOAIのREST APIを使用して実装しています 。またシークレット情報を記載するわけにはいきませんので、スクリプトプロパティとして保存しています。書き方設定周りはおいておきます。 2023-03-28 Google Apps Scriptを最大限活用していきたいなぁ~ こちらの関数を利用して、重複削除などを追加しておきます。 function createPostData(){ const sheet = accessSheet(&quot;元データ&quot;) const lastRow = sheet.getLastRow() const header = &#x5B;&quot;Title&quot;,&quot;Link&quot;,&quot;PubDate&quot;,&quot;RowData&quot;,&quot;PostData&quot;] const dataList = sheet.getRange(2, 1, lastRow - 1, header.length).getValues() dataList.forEach((value, index) =&gt;{ const &#x5B;,link,,rowData,postData] = value // すでに情報がある場合はスルー if(postData!=&quot;&quot;)return const postDataAOAI = createPostUseAOAI(rowData) // AOAI側のエラーの場合は作成しないので処理終了 if(!postDataAOAI) return // 定型文の情報を追記する const createPost = &quot;ブログ紹介:Botによる自動投稿です \\\\n&quot; + postDataAOAI + &quot;\\\\n&quot;+ link Logger.log(createPost) value&#x5B;4] = createPost sheet.getRange(index + 2, 1, 1, header.length).setValues(&#x5B;value]) // 鬼のように叩かないようにリスクヘッジ Utilities.sleep(1000); }) } 処理としては、ほぼ先ほどの「URLから記事の情報を取得する」と同一です。 運用に必要な考慮事項 検証したこととしては、以上です。ここからは、運用まで検討するにあたって必要な考慮事項の整理をしたいと思います。プロトタイプなので、これからの作成の礎を作っておきます。 定期実行にはラグがある 次に投稿されるメッセージの管理をどうするか? 投稿済みのフラグの管理をどうするか? エラーハンドリング 定期実行にはラグがある GASの問題ですが、定期実行は数分単位のずれがあります。今回の構成では、スプレッドシートのセルに情報があるかどうかで処理をしているので問題はありません。効果的な実行をするためには、RSSから情報取得の終了時に次の処理をトリガーを発行する数珠繋ぎ方式などありそうです。 投稿予定の表示 スプレッドシートで管理をしているので、投稿予定の内容を見るには見にくいと思います。この辺は裏の構成を含めて回収する必要がありそうですね。フロントの画面でも作って管理さえすれば特に問題はなさそうです。管理画面的なものを作ると時間は食いますが、やはりスプレッドシートだと見にくい側面もあるので、次の課題にしようと思います。 投稿済みのフラグ管理をどうするのか? これは、スプレッドシートでの管理をやめるしかないのではないでしょうか?いや考えれば行けると思うんですが、データベースに置換してしまった方が話が速い気がするんですよね。 エラーハンドリング 今回は、エラーが起きても処理を落とさない力技を行っています。GASの管理画面で一個ずつ確認するしかないのが辛いところです。 単純なエラーだけでなく、Azure側のエラーに関してはどうしようもないので、構成をAzureに寄せて解決するのが一番手っ取り早いです。 おわりに ども!久しぶりの実装と執筆でした。プロトですが、効果がありそうなのでがっつり作っていきたいかなと思います。 では!また! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post GASでブログの投稿と連動してAIにPR文を考えてもらう:プロトタイプ first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの服部です。 Ubuntu公式で現在開発中の authd を検証してみましたので、簡単に手順をまとめていきます。 authdはUbuntuにてEntra IDやOIDCに対応したIdPを使用したログインを実現するためのデーモンとなります。 Ubuntu 23.04、23.10では、 aad-auth というモジュールを利用してAzure AD(現Entra ID)を使用したログインを実現していましたが、Entra ID以外のOIDCベースのIdPなどへの対応を実現するために、authdの開発が開始されています。 インストール手順 基本的にはauthdのWikiページの 手順 に従ってインストールを実施していきます。 PPAの追加 開発中のパッケージということでPPAの追加が必要となりますが、正式リリース後は公式リポジトリに追加されるものと思います。PPAの追加は以下のコマンドで行います。 sudo add-apt-repository ppa:ubuntu-enterprise-desktop/authd sudo apt update APTからパッケージのインストール デスクトップ環境の場合は以下のパッケージをインストールします。 sudo apt install authd gnome-shell yaru-theme-gnome-shell yaru-theme-gtk yaru-theme-icon yaru-theme-sound サーバ環境の場合はGUI関係のパッケージは必要ないため、 authd パッケージのみインストールします。 sudo apt install authd snapからEntra ID用のブローカーのインストール authdはモジュール化されているため、Entra ID用のモジュールを別でインストールします。インストールはsnapより実施します。 sudo snap install authd-msentraid 設定手順 設定ファイルのコピー sudo mkdir -p /etc/ authd /brokers.d/ sudo cp /snap/ authd-msentraid /current/ conf /authd/m sentraid.conf /etc/ authd /brokers.d/ Entra ID上でのアプリケーション作成 Microsoft Entra 管理センター⇒アプリの登録 にアクセスします。 「新規登録」を選択 適当な名前を設定し、登録を行います。「サポートされているアカウントの種類」は「この組織ディレクトリのみ~」を選択しておくのが安全かと思われます。 メニューから「認証」を選択し、「パブリッククライアントフローを許可する」にて「はい」を選択し保存します。 次の状態になるようにアクセス許可を設定します。 メニューから「概要」を選択し、「アプリケーション (クライアント) ID」と「ディレクトリ (テナント) ID」をメモします。 ブローカーの設定 /var/snap/authd-msentraid/current/broker.conf を以下の内容で作成します。 [oidc] issuer = https://login.microsoftonline.com/&lt;2.でメモしたディレクトリID&gt;/v2.0 client_id = &lt;2.でメモしたクライアントID&gt; [users] # The directory where the home directory will be created for new users. # Existing users will keep their current directory. # The user home directory will be created in the format of {home_base_dir}/{username} # home_base_dir = /home # The username suffixes that are allowed to login via ssh without existing previously in the system. # The suffixes must be separated by commas. # ssh_allowed_suffixes = @example.com,@anotherexample.com サービスの再起動 以下のコマンドでサービスを再起動します。 sudo systemctl restart authd sudo snap restart authd-msentraid ログインチェック SSH経由のログインはまだ不完全な状態のようなので、今回はコンソール経由でのログインを試してみます。 ユーザー名にEntra IDのUPNを入力すると、ログインプロバイダーの選択が表示されるので Microsoft Entra ID を選択します。 QRコードとログインコードが表示されます。 QRコードをスキャンもしくは、 https://microsoft.com/devicelogin にアクセスします。 コンソールに表示されているコードを入力し、次に進みます。 ログイン確認が行われるので続行します。 これでブラウザ側での操作は完了となります。 初回ログイン時はローカルパスワードを設定するプロンプトが表示され、設定後ログインが完了します。 グループについて Entra ID経由でログインしたユーザーの所属するグループは UPNと同名のプライマリグループ Entra ID側で所属するグループ となります。 Entra IDのグループが以下の状態のとき、 Linux側のグループは次のようになります。 Entra ID側でユーザーを linux-sudo 、 test-group の2つのグループに参加させます。 linux- をプレフィックスに付けるとプレフィックスを取り除いた名称のLinuxのローカル側のグループ(この場合は sudo )に追加される形となります。 Linux側で確認を行うと以下のようにグループに追加されていることが分かります。 所感 SSH経由の初回ログインや、QRコードの表示などまだ不完全な部分はありますが、便利に利用できる機能だと思います。 今後の開発に期待します。 &nbsp; ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Ubuntu 24.04でEntra ID認証を実現するauthdを試してみた first appeared on SIOS Tech. Lab .
挨拶 ども!半年ぶりのブログ執筆で言葉がうまく出てこない龍ちゃんです。ブログのデザインが無事変更されて良かったです。最近は、「Azure OpenAI Service(以降:AOAI)」のキャッチアップやそれに伴うアプリケーション開発などをしていました。 さて、今回のネタは「AOAIで遊んでみた!」という内容になります。タイトルにあるとおりに、送信した文章がポジティブよりかネガティブよりかを判別するアプリケーションを作ったので共有です。 タイトルの内容について知りたいかた向けまとめ Gpt-4oでJSON出力がうまくいかない場合は、Gpt-4oで出力した情報をGpt-3.5-Turboで再度JSONに成型するプロンプトを投げることでほぼ100%で成型がうまくいくよ!ってのが書いてあります。 モチベーション 今回のモチベーションは「Azure上でOpenAIを叩くことができるAOAIを使って、何か面白いものを作る!」というものです。社内で、AI Serviceのサービス提供の話もあったりなかったりで社内外問わず注目度が高かったので作ってみました。 要約すると、「最近話題だから遊びでキャッチアップしようや」というものですね。 作ったもの まずはふんわりとした理解から始めましょう。やっていることはシンプルに2つです。 受け取った文章を文節ごとに(ポジティブ:100点)(ネガティブ:-100点)で採点 結果をJSONで返答 使用しているプロンプトについて紹介しますね。 性格付け 精度向上のために、条件とフォーマットを渡しています。実際のプロンプトとしては、以下になります。 以下の条件で文字列を採点してください。 - 文節ごとに区切って、文節ごとに得点をつけてください。 - ポジティブな単語ほど高い得点をつけてください。 - ネガティブな単語ほど低い得点をつけてください。 - 得点は100点から-100点までの範囲で評価してください。 - 得点が5の倍数にならないようにしてください。 - 同じ単語が複数回出てきた場合は、2つ目以降は得点を0にしてください。 - 文節ごとに得点を加算してください。 - 合計得点と文節ごとの得点を出力してください。 - 出力をJSON形式にしてフォーマットとしては以下に従ってください。また、このJSON以外は出力しないでください。 ```json { &quot;totalScore&quot;: 116, &quot;words&quot;: &#x5B; {&quot;word&quot;: &quot;美味しい&quot;, &quot;score&quot;: 71}, {&quot;word&quot;: &quot;ご飯を&quot;, &quot;score&quot;: 32}, {&quot;word&quot;: &quot;食べる&quot;, &quot;score&quot;: 13}, ], } Few Shot Learning また、例題を入力と出力を二組与えています。データとしては、以下を与えました。 例:いつも色々と配慮して頂き本当に感謝です { &quot;totalScore&quot;: 127, &quot;words&quot;: &#x5B; {&quot;word&quot;: &quot;いつも&quot;, &quot;score&quot;: 3}, {&quot;word&quot;: &quot;色々と&quot;, &quot;score&quot;: -7}, {&quot;word&quot;: &quot;配慮して&quot;, &quot;score&quot;: 14}, {&quot;word&quot;: &quot;頂き&quot;, &quot;score&quot;: 38}, {&quot;word&quot;: &quot;本当に&quot;, &quot;score&quot;: 6}, {&quot;word&quot;: &quot;感謝です&quot;, &quot;score&quot;: 73}, ], } 例:今週は忙しすぎてしんどい { &quot;totalScore&quot;: -84, &quot;words&quot;: &#x5B; {&quot;word&quot;: &quot;今週は&quot;, &quot;score&quot;: 19}, {&quot;word&quot;: &quot;忙しすぎて&quot;, &quot;score&quot;: -21}, {&quot;word&quot;: &quot;しんどい&quot;, &quot;score&quot;: -82}, ], } 成果物 入力すると、一定時間後に採点されたデータが返答されます。検証のために生のJsonデータも一緒に出力をしています。(ちゃんとJSONがハイライトされていて見やすい!) システム構成図としては、以下になります。 サービスは、すべてAzure上に収まるように設計しました。ローカルで動けばよいのですが、デモをするときにURLを叩けばよいという状況にしておくのが一番良いですからね。 苦労話 ソースコードをそのまま乗っけてしまうと、膨大になってしまうので構築方法についてはまた別のブログで投稿しようと思います。 5の倍数になって数字が出力される これは、採点ロジックの話です。出力される点数がどうしても、5の倍数になっていました。なので、キリの良い数字になって出力されてしまいます。ランダム性があまりないので、困りました。結果的に、Few Shot Learningとプロンプトに「得点が5の倍数にならないようにしてください」というプロンプトで解消しました。この辺の検証は後輩ズがやってくれていたので、きっとまとめてブログにしてくれるでしょう! JSONデータとして出力されない タイトルにもなっていますが、今回の苦労はすべてここに集約されています。今回はモデルにGPT-4oを使用していました。テキストを入力しても5回送信して、4回はJSONで読み込めない形で返答されて帰ってきました。デモとしては最悪ですね。 どうやら GPT-4oはJSONスキーマを尊重してくれない ようです。検証していた時は、問題なく動いていたというのがさらにたちが悪いですね。 こちらは現在解決しました。解決方法としては、「 Gpt-4oで生成した解答をGpt-3-TuroでJsonに生成しなおす 」となります。実験したところ、30回送信しても、30回Jsonデータとして返答されました。 ここで面白い点は、「JSONに成型する単純なタスクには低いバージョンのほうが適している」という点です。実際、新しいバージョンのほうが高性能です。ですが、作業内容によっては高性能である必要がなかったりします。この辺は人間が判断しなければならない点ですね。 こんなこともあって、まだエンジニアの仕事がいきなりAIに切り替わることもないなと一安心しています。 終わりに 今回は、プロンプトエンジニアリングのちょっとした落とし穴についてお話しました。どこかの誰かの助けになれば幸いです。今回の内容は、「2024OSC京都」にて掲載していた内容になります。当日はライブデモで動かないを連発してしまって申し訳ありません。今後とも参加してより面白いデモを作っていくのでよろしくお願いします。 最近は、「 プロジェクトの進め方 」や「 フロントエンド 」のブログを書いていたので、ここにAIを挟み込んでいきますね!ではまた&#8230; ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post AOAI:Gpt-4oでJSON出力に失敗する対症療法 first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの佐藤 陽です。 今月はSIOS Technologyのアドベントカレンダー月間であり、テーマは 「生成AI」 です。 いろんなメンバーが生成AI活用に関する記事を投稿していくので、楽しみにしててください。 1日目の今日は、わたくし佐藤が「GitHub Copilotと一緒にTDDしてみた」と題した記事を書いていきたいと思います。 はじめに 本記事は以下の記事にインスパイアされた記事になります。 内容としてはほぼ同じで、それを.NET環境で実際に試してみました。 AI時代にこそTDDだと思う話 テストのフレームワークとしては xUnit を利用します。 Abstract 時間がない方向けに結論を先に書いておきます。 TDDのアプローチをとることで、Copilotの提案する内容の質が向上することは確認できました。 GitHubCopilotから質の高い提案を受けるためには、こちらから様々な情報を与える必要があるように感じました。 TDDの細かいサイクル(TODOリストを書く→テストを書く→失敗する→実装を行う→成功する→リファクタリング and more)でヒントを与えながら実装をすることで、Copilotの提案の質が向上することを実感しました。 実装 環境構築 まず.NETの環境を構築します。 VisualStudio上でポチポチやってもらってもOKですし、以下のようなコマンドを叩いていただいてもOKです。 dotnet new sln -o ai-tdd-dotnet cd ai-tdd-dotnet dotnet new classlib -o FizzBuzzTdd mv ./FizzBuzzTdd/Class1.cs ./FizzBuzzTdd/FizzBuzzTdd.cs dotnet sln add ./FizzBuzzTdd/FizzBuzzTdd.csproj dotnet new xunit -o FizzBuzzTdd.Tests dotnet add ./FizzBuzzTdd.Tests/FizzBuzzTdd.Tests.csproj reference ./FizzBuzzTdd/FizzBuzzTdd.csproj dotnet sln add ./FizzBuzzTdd.Tests/FizzBuzzTdd.Tests.csproj アプリ本体の方は以下のような形でクラスが構成されます。 namespace FizzBuzzTdd; public class Class1 { } テストプロジェクトの方は以下のような形です。 namespace FizzBuzzTdd.Tests; public class UnitTest1 {     [Fact]     public void Test1()     {     } } TDDフロー では早速テスト書いていきましょう。 まずはテストの部分に早速TodoListを追記します。 using FizzBuzz; namespace FizzBuzz.Tests {     public class UnitTest1     {         [Fact]         public void Test1()         {         }         /**          * TODO List          * - [] 3の倍数の場合は"Fizz"を返す          */     } } 1つTODO Listを記載すると、以下のように他の内容も提案されました。     public class UnitTest1     {         [Fact]         public void Test1()         {         }     /**     * TODO List     * - [] 3の倍数の場合は"Fizz"を返す     * - [] 5の倍数の場合は"Buzz"を返す     * - [] 3と5の倍数の場合は"FizzBuzz"を返す     * - [] それ以外の場合はそのまま返す     */     } では、TDDを始めていきます。 まず「3の倍数の場合は&#8221;Fizz&#8221;を返す」のケースのテストを書いていきます。 既存のUnitTest1に以下の説明文を追加して、Copilotから提案を受けます。 [Fact(DisplayName = "3の倍数の場合はFizzを返す")] public void Test1() { } 最初に提案してきたテスト内容は以下の通りです。 [Fact(DisplayName = "3の倍数の場合はFizzを返す")] public void Test1() {     //Arrange     var fizzBuzz = new FizzBuzz.FizzBuzz();     //Act     var result = fizzBuzz.FizzBuzzFunction(1);     //Assert     Assert.Equal("1", result); } インスタンスの生成方法も誤っているし、Assertの部分も異なっています。 これを一度正しく修正します。 最初のテストが今後の学習内容にもなるため、丁寧に書き直します。 [Fact(DisplayName = "3の倍数の場合はFizzを返す")] public void Test1() {     //Arrange     var fizzBuzz = new FizzBuzz();     //Act     var result = fizzBuzz.FizzBuzzFunction(3);     //Assert     Assert.Equal("Fizz", result); } これを実行すると、テストは失敗します。 TDDの流れとしては想定通りです。 ではこのテストが通るように本体のアプリを書き直します。 クラス名を修正し、提案を受けると以下のような形で実装されました。 namespace FizzBuzzTdd; public class FizzBuzz {     public string FizzBuzzFunction(int number)     {         if (number % 3 == 0)         {             return "Fizz";         }         return number.ToString();     } } しっかり3で割り切れるかどうかの判定も実装できています。 ただ、元記事に書いてあるようにTDDの実践のため、あえて質素な実装に置き換えます。 namespace FizzBuzzTdd; public class FizzBuzz {     public string FizzBuzzFunction(int number)     {         return "Fizz";     } } このように実装することで、テストが通ることが確認できたかと思います。 では2つ目のテストに移りたいと思います。 [Fact(DisplayName = "5の倍数の場合はBuzzを返す")] と記載し、提案を受けます。 [Fact(DisplayName = "5の倍数の場合はBuzzを返す")] public void Test2() {     //Arrange     var fizzBuzz = new FizzBuzz();     //Act     var result = fizzBuzz.FizzBuzzFunction(5);     //Assert     Assert.Equal("Buzz", result); } すると、先程のTest1の実装に則り、求めるテストコードが実装されました。 ここでテストを実装すると、もちろんTest2は失敗しますね。 アプリの実装を修正します。 一度先程の実装を消して、再度提案を受けます。 public string FizzBuzzFunction(int number){     if(number % 3 == 0){         return "Fizz";     }     return "Buzz"; } 良い感じですね。 テストを実行すると通ることが確認できます。 では次に3つ目のテストの実装をしていきます。 もうわざわざ [Fact(DisplayName=&#8230;)] を書かなくても以下の内容を提案してくれました。 [Fact(DisplayName = "3と5の倍数の場合はFizzBuzzを返す")] public void Test3() {     //Arrange     var fizzBuzz = new FizzBuzz();     //Act     var result = fizzBuzz.FizzBuzzFunction(15);     //Assert     Assert.Equal("FizzBuzz", result); } 恐らくファイル下部に書いてある TODO Listの内容から察してくれた のかと思います。 テストを実行すると、こちらも失敗します。 ではテストが通るようにアプリ側の実装を修正します。 アプリ側の実装において以下のような提案を受けました。 public string FizzBuzzFunction(int number){     if(number % 3 == 0 &amp;&amp; number % 5 == 0){         return "FizzBuzz";     }     if(number % 3 == 0){         return "Fizz";     }     return "Buzz"; } こちらも通ります。 では最後に4つ目のテストを実装します。 [Fact(DisplayName = "それ以外の場合はそのまま返す")] public void Test4() {     //Arrange     var fizzBuzz = new FizzBuzz();     //Act     var result = fizzBuzz.FizzBuzzFunction(7);     //Assert     Assert.Equal("7", result); } いいですね。 テストは想定通り失敗するので、アプリ側の実装を修正します。 &#8230;と、ここまで順調だったのですが、 なぜか最後の入力値をそのままreturnする実装だけは提案されませんでした。 Buzzをreturnする部分はif文の追加を提案してくれたのですが、最後の return number の部分がどうしても提案してくれませんでした。 仕方ないので自分でreturn文を追加します。 public string FizzBuzzFunction(int number){     if(number % 3 == 0 &amp;&amp; number % 5 == 0){         return "FizzBuzz";     }     if(number % 3 == 0){         return "Fizz";     }     if(number % 5 == 0){         return "Buzz";     }     return number; //ここだけ自前で実装 } これですべてのテストが通るようになり、実装の方が完了です。 細かなリファクタリングの必要などはあるかと思いますが、今回は省略します。 まとめ 最後だけ若干うまくいきませんでしたが、 おおむねCopilotが正しい内容を提案してくれて実装の方をスイスイ行えた印象があります。 また、最初は提案された実装内容に誤りがありましたが、次第に解消され、質の高い提案がされていく事も実感できました。 TODOリストを書いていること テストコードを書いていること が、質の高い提案につながったように見えます。 ただGitHub CopilotとTDDの相性が良いようには感じましたが、即効性のあるものというよりじわじわ効いてくる感じだなぁと感じました。 この手法を採るためにTDDを採用する、という判断は少し行き過ぎで あくまでTDDを既に採用している方に導入をオススメするくらいかな、と個人的には感じました。 とはいいつつ、今回のような形で生成AIを使いこなし、開発効率を上げていきたいですね! また様々な手法を試してみたいと思います。 ではまた! 余談 どこかのコメントで「FizzBuzzの実装は膨大な実装がGitHubに挙がっており、通常のコードよりも学習がされてるのでは?」という意見も見られました。 確かにプログラミング学び始めはFizzBuzz問題に取り組み、GitHubなどに上げがちなので、かなりコードの学習がされているかもしれません。 もしかしたら実務においてCopilotとTDDをした場合は、こんなに質の高い提案が行われないかもしれないですね。 そのあたりも含めてまた検証する機会があれば触ってみたいと思います ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post GitHub Copilotと一緒にTDDしてみた first appeared on SIOS Tech. Lab .
今回はGoogle Apps Script(GAS)を使い、Androidスマートフォンのアラームと部屋の電気を連動させる方法をご紹介します。 コードをコピーして簡単にできるので、Nature製品をお持ちの方はぜひ試してみてください。 必要なもの googleアカウント 部屋のライトを登録したNature Remo Androidスマートフォン &nbsp; Nature Remo APIへの登録 https://api.nature.global/login にアクセスし、Natureアカウントに登録しているメールアドレスでログインします。 Access tokens一覧より「Generate access token」を選択し、アクセストークンを作成します。 アクセストークンは一度しか表示されないため、忘れずにコピーしましょう。(クリップボードの履歴はWindowsの場合[Win] + [V]キーで確認できます) Google Apps ScriptでAPIを作成 Google Apps Script(GAS)ではGET、POSTメソッドのAPIを作成する機能が提供されています。 Googleドライブの任意の場所に新しいGASファイルを作成しましょう。特にディレクトリにこだわりがなければ、 ここ から作成できます。 ・ライトのシグナルIDを取得する 操作するデバイス(信号)のIDを特定します。以下のコードを入力してください。 function findSignalId() { apiAccessKey = 'コピーしたアクセスキー' baseURL = 'https://api.nature.global/1' headers = { 'Authorization' : 'Bearer ' + apiAccessKey, 'accept' : 'application/json', 'Content-Type' : 'application/x-www-form-urlencoded', } options = { 'method' : 'GET', 'headers' : headers, } response = JSON.parse(UrlFetchApp.fetch(baseURL + '/appliances', options).getContentText()) response.map((device) =&gt; { console.log('デバイス名 : ' + device['nickname']) device['signals'].map((signal) =&gt; { console.log(signal['name'] + " : " + signal['id']) }) }) } 関数を実行すると、実行ログに登録された機器名と各操作のシグナルIDが出力されるので、その中からライト点灯のIDを探してコピーします。 ・APIをデプロイする 先程とは別のスクリプトを作成します。左のメニューより「スクリプト」を選択してください。 &nbsp; 以下のコードを入力します。今回はPOSTメソッドのAPIを作りたいのでdoPostメソッドを使います。 function doPost() { apiAccessKey = 'コピーしたアクセスキー' signalId = 'ライト点灯のシグナルID' baseURL = ' https://api.nature.global/1 ' headers = { 'Authorization' : 'Bearer ' + apiAccessKey, 'accept' : 'application/json', 'Content-Type' : 'application/x-www-form-urlencoded' } options = { 'method' : 'POST', 'headers' : headers, } response = JSON.parse(UrlFetchApp.fetch(baseURL + '/signals/' + signalId + '/send', options)) //今回は使用しませんが、APIの疎通を確認するアプリを使うとレスポンスとしてメッセージを取得できます。 message = 'ライトを点灯しました' return ContentService.createTextOutput(message).setMimeType(ContentService.MimeType.TEXT) } &nbsp; APIをデプロイします。画面上部の「デプロイ」ボタンから「新しいデプロイ」をクリックします。 種類の選択から「ウェブアプリ」、アクセスできるユーザーの欄で必ず「全員」を選択してください。 デプロイを実行するとウェブアプリのURLが表示され、すでにAPIでライトを操作できる状態になっています。早速呼び出してみましょう。 Andriodスマートフォンに「Sleep」アプリをインストールしてセットアップ アラームが鳴るのと同時にAPIを呼び出せるアプリ「 Sleep 」を使います。 [設定] &gt; [各種サービス] &gt; [オートメーション] の順に選択、「Webhooks」を有効化し先ほど表示されたウェブアプリのURLを入力します。 このアプリからAPIの呼び出しが行われるタイミングは複数あるのですが、今回呼び出してほしいタイミングはアラームが鳴ったときだけなので、上にある「イベント」から「ALARM_ALERT_START」以外のチェックを外しておきます。 これで設定は完了です。アラームを鳴らして動作を確認しましょう。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Androidスマホのアラームが鳴ったら部屋の電気を自動でつけたい【Nature Remo】 first appeared on SIOS Tech. Lab .
こんにちは! サイオステクノロジーの安藤 浩です。 エンタープライズ向けブロックチェーンのデファクトスタンダードといわれているHyperledger Fabricの入門の続きとして、Hyperledger Fabricでいうところの合意形成の仕組みであるトランザクションフローについて説明していきます。説明や用語などは以下の前回の記事をもとにしています。 Hyperledger Fabric 入門 &#8211; Hyperledger Fabricとは、Hyperledger Fabricのコンポーネントの説明 &#8211; はじめに Hyperledger Fabricには以下の3つのステップで構成されるトランザクションフローによって合意形成がなされます。 ステップ1: Endorsement トランザクションの内容について合意するステップです。(Chaincode実行結果にPeerが署名したもの) ステップ2: Ordering トランザクションの順序を確定しプロックを生成・配布するステップです。 ステップ3: Validation &amp; Commit トランザクションの有効性を検証したうえで反映するステップです。 ステップ1~3のトランザクションフローが完了したときにクライアントアプリケーションにLedger(台帳)の更新が通知されます。 &nbsp; ここからはそれぞれのステップにおいてどのような処理がされているか詳しく見ていきます。 ステップ1: Endorsement 目的: 複数の組織で複数のPeerを所有する場合、Chaincodeを実行することで同一の結果が得られることを確認したい 理由: Peerに対して不正を働いた、不具合があった、ミスや障害などで不正な状態のLedgerのデータをもとにTransaction が処理されることを防ぎたい。 以下の図に記載の順でEndorsementのステップ(青色の部分)は実行されます。 1.Transaction Proposal 送付 まず、クライアントアプリケーション(図内のClient App)がPeer に対して、Chaincodeを実行するように要求を行います。これをTransaction Proposalといいます。この要求はLedger に対しての読み込みや書き込みが該当します。 2.Chaincode 実行 Peer 内のChaincodeを実行し、署名を付けます。この結果をEndorsementといいます。※ここでは実際にLedgerに対して反映することはないため、シミュレーション実行とも呼ばれます。 3.Endorsement 返却 2のEndorsementをクライアントアプリケーション(図内のClient App)に返却します。 4.Endorsement Policy に基づきEndorsementを収集 Client AppはPeerから返却されたEndorsementをあらかじめ決められたEndorsement Policyに基づいてEndorsementを収集します。Endorsement Policyとは、 あるTransaction をLedgerに反映するために、どのようなEndorsementを集めてこなければならないかをあらかじめ定義した条件のこと。 例:Organization1, Organization2, Organization3 で構成されるネットワークとしたとき。 ・ Organization1, Organization2のどちらからもEndorsementを収集しなければならない条件。 ・Organization1, Organization2, Organization3のいずれか2つのOrganizationからEndorsementを収集しなければならない条件。 &nbsp; ステップ2: Ordering &nbsp; 目的: Transactionの集合を適切な順序で配置し、それらをBlockにまとめることです。そのBlockをPeerに配布して最終的なValidation を実施して、Ledgerに書き込みます。 理由: Transaction の順序を決めないとデータの不整合が発生してしまうため。 以下の図に記載の順でOrderingのステップ(緑色の部分)は実行されます。 &nbsp; 5.Transaction 送付 Endorsementを収集したクライアントアプリケーション(図内のClient App)がTransactionをOrdering Service に送付します。まず、図の点線部分でPeerのFabric Gateway(v2.4で導入された)を介して、TransactionをOrdering Service に送付されます。 ※ここでOrdering Serviceは複数ノードで構成されます。 Transaction には Peerから署名済のTransaction Proposalへのレスポンスが含まれます。 6.Block生成 1. Ordering Service で受け取ったTransaction の順序を合意し、決定します。( コンセンサスアルゴリズム: Raft を利用) 2. Ordering ServiceがTransactionを組み込んだBlockを生成します。 7.Block配布 Ordering Serviceは生成したBlockをPeer に配布します。 また、 Peerが停止していた、または後からChannelに参加した場合はOrdering Service に再接続した際にBlockを受信します。 &nbsp; ステップ3: Validation &amp; Commit &nbsp; 目的: 最終的に Transaction の有効性を検証したうえでLedger に反映したい。 理由: ステップ1で実行した結果と一致するか、署名やTransaction が改変されていないかなどの不正が起こっていないかをチェックするため。 以下の図に記載の順でValidation &amp; Commit のステップ(紫色の部分)は実行されます。 8.Validation → Commit 1.Peer はOrdering Service から配布されたBlock内のTransaction を検証(Validation)します。 2.Validationが完了したら、Ledgerに対して反映(Commit)します。 Validationの際にはやることは以下です。 ・各Transactionを検証 ・Transaction が必要な組織のPeerによってエンドース(署名がついている)されていること ・Endorsementが一致していること ・Read-Set に含まれるKeyに対するVersionが現在の World State のKeyのVersionから変更されていなければTransaction を有効する。変更されていればTransaction を無効とする。 最後の点が分かりにくいので、用語の説明とともに詳細を説明していきます。 用語の説明 World State ここでWorld Stateとは、World StateはKeyの現在のValueを格納されているデータストアです。 また、各Keyに対するVersionも持っており、レコードがどのBlockのどのTransaction によって書き込まれたかを表します。 以下の例のようなデータをもっています。 Read-Set Read-Setとは、ステップ1のEndorsementの際にChaincodeの実行によって取得されたKeyとVersionのリストです。 以下は仮想的な例ですが、 read-set のブロックで囲まれた箇所です。 &lt;TxReadWriteSet&gt; &lt;NsReadWriteSet name="chaincode1"&gt; &lt;read-set&gt; &lt;read key=" WaterB ottle1 ", version="0"&gt; &lt;read key=" WaterB ottle2 ", version="0"&gt; &lt;/read-set&gt; &lt;write-set&gt; &lt;write key=" WaterB ottle1 ", value="LION"&gt; &lt;write key=" WaterB ottle2 ", value="MAMMOTH"&gt; &lt;write key=" WaterB ottle3 ", isDelete="true"&gt; &lt;/write-set&gt; &lt;/NsReadWriteSet&gt; &lt;TxReadWriteSet&gt; 「 Read-Set に含まれるKeyに対するVersionが現在の World State のKeyのVersionから変更されていなければTransaction を有効する。変更されていればTransaction を無効とする。 」について 用語の説明はできたと思うので、「 ・Read-Set に含まれるKeyに対するVersionが現在の World State のKeyのVersionから変更されていなければTransaction を有効する。変更されていればTransaction を無効とする。 」については、ステップ1のEndorsementでChaincodeを実行した際に生成されたRead-Setと現在のLedger内のWorld State の状態が一致するかということを検証しています。 Endorsement からValidationまでにほかのTransaction などによってWorld StateのKeyに対するValueが変更されている可能性があるため、最終的にValidationをしています。 &nbsp; 9.BlockがLedgerにCommitされたことを通知 最後にBlockがPeer内のLedgerに反映されたことをもって、トランザクションフローが完了します。これをクライアントアプリケーション(図内のClient App)に通知して終わりです。 また、 Ordering Service に接続していないPeerの場合はほかのPeerからGossip プロトコルによりBlockが配布されます。Private DataについてもGossip プロトコルによってPrivate DataをもっているPeerから配布されます。 まとめ トランザクションフローは3つのステップで実行され、システム全体の合意形成がなされることを説明しました。 ステップ1: Endorsement (Transaction の内容について合意) ステップ2: Ordering (Transaction の順序を確定しプロックを生成・配布) ステップ3: Validation &amp; Commit (Transaction の有効性を検証したうえで反映) &nbsp; 参考URL Transaction Flow — hyperledger-fabricdocs main ドキュメント Glossary (用語集) — hyperledger-fabricdocs main ドキュメント ピア — hyperledger-fabricdocs main ドキュメント The Ordering Service — hyperledger-fabricdocs main ドキュメント Blockchain GIG 集中講座 #1 Hyperledger Fabric(再)入門 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Hyperledger Fabric 入門 – トランザクションフローの説明 – first appeared on SIOS Tech. Lab .