TECH PLAY

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

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

610

こんにちは、サイオステクノロジーの佐藤陽です。 今日はAzure AI Searchのインデクシングに関する記事になります。 RAGの構築にあたっても非常に重要となる「Azure AI Search」の基本的なところを解説していきます! はじめに 正直なところ、今までなんとなくでAI Search使っていました。 AzurePortalのAI Searchから「データをインポート」としたら、いい感じにインデックスが作成された サンプルコードとか見ると、良い感じにインデックス作成するプログラムが既に提供されていた とりあえず適当にデータ投入しても、RAGに組み込んだらそれなりの回答返ってくる といった感じで、何となくでも使えてはいたのですが「これでいいのか…?」と思い、 腰を据えて公式ドキュメントや、様々な記事を読んでまとめてみました。 目新しい情報は無いかもしれないですが 「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の情報で検索すると、ヒットしないことが分かります。 ただ、今回はベクトル検索をしているわけでもないので、特に検索の真新しさはないですね…。 今回の記事はあくまでインデクシングにフォーカスしているので、 また検索周りについては調査して記事にしていきたいと思います。 まとめ 今回はAzure AI Searchに対してインデックスを作成し、実際にデータを導入する流れを解説しました。 インデックスのスキーマ設計に関しては、非常に詳細な部分まで設定が可能で、ここがAzure AI Searchの性能を決める肝かと思いました。 RDBMSでもテーブル設計は非常に重要とされていますが、AI Searchのスキーマ設計はそれ以上に気を付けて行わなければいけ名ように感じます。 そのためにも、しっかりと投入元のデータの性質などに関して理解を深める必要がありそうですね。 また、今回はインデクシングに関して概要をさらっただけであり、まだまだ機能は多く存在しています。 ベクトル検索のためのスキーマ設計 セマンティック検索のためのスキーマ設計 プル型のデータ投入 スキルセット そのあたりにもまた触れて、しっかりと理解していきたいと思います。 ではまた! 余談 AI Searchはよく価格が高い事が言われてます。 実際ちょっとお高めだよなぁ、とは思います。 確かに、そのぶん高機能なのは今回勉強してみて感じましたが…。 一方で、最近CosmosDBがベクトル検索に対応したことで非常に盛り上がっており シンプルなRAGの構築するくらいなら、CosmosDBでもいいんじゃないか?という話も出てます。 ということでAI Searchのキャッチアップと並行して、CosmosDBを使った場合の検索についてもまた検討していきたいと思います。 参考資料 Azure AI Search ドキュメント – Microsoft 基本概念から理解するAzure AI Search – 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アカウントの [アカウント設定] > [ID] を選択し、Azureロールの割り当てを押下する スコープを リソースグループ とし、VMが所属するリソースグループである fiap-pub を選択する。役割は 仮想マシン共同作成者 (共同作成者 = Contributor)として保存。 ※ ここで私の場合、リソースグループに対する操作権限をアカウントに割り当てる権限がないため、エラーとなり、アカウント管理者にロールの割り当てを依頼 ※ 仮想マシン共同作成者 は、仮想マシンの作成と管理、ディスクの管理、ソフトウェアのインストールと実行 etc… の権限を持つRole。(仮想ネットワークは別) 3. ギャラリーからRunbookの作成 ロールの割り当てが完了したら、[プロセスオートメーション] > [Runbook] を選択。 [ギャラリーを参照] を押下。 ギャラリーから、[Start Azure V2 VMs] を選択。 Runbookに名前を付けてインポートする Automationアカウントのメニューから、[プロセスオートメーション] > [Runbook]を確認すると、以下のように新規としてRunbookが作成されたことが確認できる。 4. Runbookの動作テスト 次に、[fiap-pub-auto-VM-start] を選択し、[編集] > [ポータルで編集] を選択すると、[テストウィンドウ] が開き、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のメニューの [操作] > [自動シャットダウン] を選択。 以下のように設定し、保存をするだけ。 おまけ②: 正しく動いているかの確認方法 これまで、設定の方法を紹介しましたが、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": "東京の天気は雨のち曇り"// <= ここに外部関数の結果を入れる。 } ], "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     ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 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に関連した ブログ記事 がたくさん出るはずですので、皆さんぜひ読んでみてください! 参考 今回はネット上で公開してくださっている こちら の資料を参考にさせていただきました!   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 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) => { const file = SpreadsheetApp.getActiveSpreadsheet() const sheet = file.getSheetByName(sheetName) return sheet } RSSから情報を取得する ここで実装していく内容としては、「RSSフィードに問い合わせを行い、すでに取得している情報であればそぎ落としてスプレッドシートに保存」になります。 まずは、RSSフィードから情報を取得する部分になります。サンプルとしては、弊社のブログのRSSフィードを利用します。(ぜひウォッチしてね(>_<)) const getRSSFeed = () => { // RSSフィードのURLを指定 const rssUrl = '<https://tech-lab.sios.jp/feed>'; // ここに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('channel').getChildren('item'); const data = []; items.forEach(function (item) { const title = item.getChild('title').getText(); const link = item.getChild('link').getText(); const pubDate = new Date(item.getChild('pubDate').getText()); data.push([title, link, pubDate]); }); return data } こちらでは、XMLで返答されたデータをJSONに変換して構造化しています。この関数を利用して、重複削除を行うコードが以下になります。 function stackSheetFromRSSFeed() { // 定期実行することでRSSからの情報をスプレッドシートに情報をためる // GoogleスプレッドシートのIDを指定 const sheet = accessSheet("元データ") const lastRow = sheet.getLastRow() // Logger.log(lastRow) // 重複削除の必要があるため現在のリストを取得 const linkList = sheet.getRange(2, 2, lastRow - 1, 1).getValues().map((row) => row[0]) // RSSから情報取得 const dataFromRSS = getRSSFeed() // 重複削除処理 const data = [] dataFromRSS.forEach((value) => { const link = value[1] if (!linkList.includes(link)) data.push(value) }) // 更新なしの場合は処理終了 if (data.length == 0) return // シートに書き込み処理 sheet.getRange(lastRow, 1, data.length, data[0].length).setValues(data) } すでに存在しているURLを一覧で取得し、そこから重複を削除してデータの保存を行っています。 URLから記事の情報を取得する ここで、実装していく内容としては「記事のURLから記事のHTML情報を取得して、スプレッドシート保存」になります。 なぜ?一度HTMLの情報を取得するのか? AOAIでは、URLから情報を取得することができないからです。一度テキストデータとして取得する必要があります。この辺は初耳情報でしたね。 const getPageHTML = (url) => { var response = UrlFetchApp.fetch(url); var html = response.getContentText(); // HTMLを解析 var document = HtmlService.createHtmlOutput(html).getContent(); // 必要な部分を抽出(この記事の内容が <section> タグ内にあると仮定します) var content = ''; var regex = /<section class="entry-content"[^>]*>([\\\\s\\\\S]*?)<\\\\/section>/; var match = regex.exec(document); if (match && match[1]) { content = match[1]; } else { content = '記事の内容を取得できませんでした。'; } return content } ここでは、GASの機能を使用してHTMLを取得して正規表現で本文部分のみを取得しています。 こちらを用いて、重複削除や情報を取得済みのものに関しては情報を取得しない処理などを追記したものを記載します。 function createRowData() { const sheet = accessSheet("元データ") const lastRow = sheet.getLastRow() const header = ["Title","Link","PubDate","RowData"] const dataList = sheet.getRange(2, 1, lastRow - 1, header.length).getValues() dataList.forEach((value, index) =>{ const [,link,,rowData] = value // すでに情報がある場合はスルー if(rowData!="")return const htmlData = getPageHTML(link) value[3] = htmlData // 書き込み処理 sheet.getRange(index + 2, 1, 1, header.length).setValues([value]) // HTML取得に関しては攻撃にもなるので人間的な挙動にしてます。 Utilities.sleep(1000); }) } スプレッドシートに記載している情報がない場合は、スルーすることで取得済み判定を行っています。 記事内容からXへの投稿内容を取得する ここで実装する内容としては、「取得済みのHTML情報からAOAIに問い合わせを行い、Xへの投稿内容を作成」になります。問い合わせに使用するプロンプトは以下になります。 System あなたはSNS担当者です。送付した内容からXの投稿を作成してください。内容は日本語の300文字以内で作成してください。ブログの導入などのリンクはつける必要はありません。 --- HTML情報 --- まずは、AOAIに問い合わせする処理を関数として切り出します。 const createPostUseAOAI = (text) => { const apiEndpoint = PropertiesService.getScriptProperties().getProperty("AOAI_API_URL"); const modelName = PropertiesService.getScriptProperties().getProperty("AOAI_API_MODEL"); const apiVersion = PropertiesService.getScriptProperties().getProperty("AOAI_API_VERSION"); const apiKey = PropertiesService.getScriptProperties().getProperty("AOAI_API_KEY");; // ここにAzure APIキーを入力 const apiUrl = `${apiEndpoint}/openai/deployments/${modelName}/chat/completions?api-version=${apiVersion}`; // ここにAzure OpenAIエンドポイントURLを入力 // OpenAI APIに送信するデータ const payload = { model: modelName, // 'model'パラメータのみ使用 messages: [{ role: "system", content: "あなたはSNS担当者です。送付した内容からXの投稿を作成してください。内容は日本語の300文字以内で作成してください。ブログの導入などのリンクはつける必要はありません。" }, { role: "user", content: text }], // プロンプトをメッセージリストの形式に変更 }; const options = { method: 'POST', headers: { "Content-Type": "application/json", "api-key": apiKey }, payload: JSON.stringify(payload), muteHttpExceptions: true }; try { const response = UrlFetchApp.fetch(apiUrl, options); const responseJson = JSON.parse(response.getContentText()); const res = responseJson.choices[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("元データ") const lastRow = sheet.getLastRow() const header = ["Title","Link","PubDate","RowData","PostData"] const dataList = sheet.getRange(2, 1, lastRow - 1, header.length).getValues() dataList.forEach((value, index) =>{ const [,link,,rowData,postData] = value // すでに情報がある場合はスルー if(postData!="")return const postDataAOAI = createPostUseAOAI(rowData) // AOAI側のエラーの場合は作成しないので処理終了 if(!postDataAOAI) return // 定型文の情報を追記する const createPost = "ブログ紹介:Botによる自動投稿です \\\\n" + postDataAOAI + "\\\\n"+ link Logger.log(createPost) value[4] = createPost sheet.getRange(index + 2, 1, 1, header.length).setValues([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/<2.でメモしたディレクトリID>/v2.0 client_id = <2.でメモしたクライアントID> [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コードの表示などまだ不完全な部分はありますが、便利に利用できる機能だと思います。 今後の開発に期待します。   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 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 { "totalScore": 116, "words": [ {"word": "美味しい", "score": 71}, {"word": "ご飯を", "score": 32}, {"word": "食べる", "score": 13}, ], } Few Shot Learning また、例題を入力と出力を二組与えています。データとしては、以下を与えました。 例:いつも色々と配慮して頂き本当に感謝です { "totalScore": 127, "words": [ {"word": "いつも", "score": 3}, {"word": "色々と", "score": -7}, {"word": "配慮して", "score": 14}, {"word": "頂き", "score": 38}, {"word": "本当に", "score": 6}, {"word": "感謝です", "score": 73}, ], } 例:今週は忙しすぎてしんどい { "totalScore": -84, "words": [ {"word": "今週は", "score": 19}, {"word": "忙しすぎて", "score": -21}, {"word": "しんどい", "score": -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を挟み込んでいきますね!ではまた… ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 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の倍数の場合は”Fizz”を返す」のケースのテストを書いていきます。 既存の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=…)] を書かなくても以下の内容を提案してくれました。 [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 && 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); } いいですね。 テストは想定通り失敗するので、アプリ側の実装を修正します。 …と、ここまで順調だったのですが、 なぜか最後の入力値をそのままreturnする実装だけは提案されませんでした。 Buzzをreturnする部分はif文の追加を提案してくれたのですが、最後の return number の部分がどうしても提案してくれませんでした。 仕方ないので自分でreturn文を追加します。 public string FizzBuzzFunction(int number){     if(number % 3 == 0 && 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スマートフォン   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) => { console.log('デバイス名 : ' + device['nickname']) device['signals'].map((signal) => { console.log(signal['name'] + " : " + signal['id']) }) }) } 関数を実行すると、実行ログに登録された機器名と各操作のシグナルIDが出力されるので、その中からライト点灯のIDを探してコピーします。 ・APIをデプロイする 先程とは別のスクリプトを作成します。左のメニューより「スクリプト」を選択してください。   以下のコードを入力します。今回は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) }   APIをデプロイします。画面上部の「デプロイ」ボタンから「新しいデプロイ」をクリックします。 種類の選択から「ウェブアプリ」、アクセスできるユーザーの欄で必ず「全員」を選択してください。 デプロイを実行するとウェブアプリのURLが表示され、すでにAPIでライトを操作できる状態になっています。早速呼び出してみましょう。 Andriodスマートフォンに「Sleep」アプリをインストールしてセットアップ アラームが鳴るのと同時にAPIを呼び出せるアプリ「 Sleep 」を使います。 [設定] > [各種サービス] > [オートメーション] の順に選択、「Webhooks」を有効化し先ほど表示されたウェブアプリのURLを入力します。 このアプリからAPIの呼び出しが行われるタイミングは複数あるのですが、今回呼び出してほしいタイミングはアラームが鳴ったときだけなので、上にある「イベント」から「ALARM_ALERT_START」以外のチェックを外しておきます。 これで設定は完了です。アラームを鳴らして動作を確認しましょう。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Androidスマホのアラームが鳴ったら部屋の電気を自動でつけたい【Nature Remo】 first appeared on SIOS Tech. Lab .
こんにちは! サイオステクノロジーの安藤 浩です。 エンタープライズ向けブロックチェーンのデファクトスタンダードといわれているHyperledger Fabricの入門の続きとして、Hyperledger Fabricでいうところの合意形成の仕組みであるトランザクションフローについて説明していきます。説明や用語などは以下の前回の記事をもとにしています。 Hyperledger Fabric 入門 – Hyperledger Fabricとは、Hyperledger Fabricのコンポーネントの説明 – はじめに Hyperledger Fabricには以下の3つのステップで構成されるトランザクションフローによって合意形成がなされます。 ステップ1: Endorsement トランザクションの内容について合意するステップです。(Chaincode実行結果にPeerが署名したもの) ステップ2: Ordering トランザクションの順序を確定しプロックを生成・配布するステップです。 ステップ3: Validation & Commit トランザクションの有効性を検証したうえで反映するステップです。 ステップ1~3のトランザクションフローが完了したときにクライアントアプリケーションにLedger(台帳)の更新が通知されます。   ここからはそれぞれのステップにおいてどのような処理がされているか詳しく見ていきます。 ステップ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を収集しなければならない条件。   ステップ2: Ordering   目的: Transactionの集合を適切な順序で配置し、それらをBlockにまとめることです。そのBlockをPeerに配布して最終的なValidation を実施して、Ledgerに書き込みます。 理由: Transaction の順序を決めないとデータの不整合が発生してしまうため。 以下の図に記載の順でOrderingのステップ(緑色の部分)は実行されます。   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を受信します。   ステップ3: Validation & Commit   目的: 最終的に Transaction の有効性を検証したうえでLedger に反映したい。 理由: ステップ1で実行した結果と一致するか、署名やTransaction が改変されていないかなどの不正が起こっていないかをチェックするため。 以下の図に記載の順でValidation & 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 のブロックで囲まれた箇所です。 <TxReadWriteSet> <NsReadWriteSet name="chaincode1"> <read-set> <read key=" WaterB ottle1 ", version="0"> <read key=" WaterB ottle2 ", version="0"> </read-set> <write-set> <write key=" WaterB ottle1 ", value="LION"> <write key=" WaterB ottle2 ", value="MAMMOTH"> <write key=" WaterB ottle3 ", isDelete="true"> </write-set> </NsReadWriteSet> <TxReadWriteSet> 「 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をしています。   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 & Commit (Transaction の有効性を検証したうえで反映)   参考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 .
こんにちは、サイオステクノロジーの佐藤 陽です。 今回もRAGの構築に関する記事を書いていきます! これまでも何本かRAGに関して書いてきましたが、 今回はそれらの集大成として、 PDFを外部情報とするRAGを実装し、Ragasで評価する ところまで、ソースコードと合わせて一挙ご紹介していこうと思います。 これを読めば、今日からRAGが構築ができるような記事になってます! ぜひ最後までご覧ください! はじめに 今回一番伝えたいことは、 「評価を回しながらRAGの開発を進めてください!!」 という事です。 RAGというと、どうしても回答を出す部分に注目が行きがちですが、評価の方も非常に大切です。 生成AIを利用していることもあり、RAGの回答内容は不安定であり、人間が評価するのが難しいことがよく言われています。 更にRAGを構築する要素の設計は多岐にわたります。 プロンプト変更 チャンキング戦略 検索方法 LLMのモデル and more! そのため、今回扱うようなRagasを利用し、定量的に評価をしながら開発を進めていくことが大切になります。 今回の記事を通じ、評価までを含んだシステムを構築し、よきRAG開発ライフを送っていただければ幸いです。 ポイント 今回のポイントとしては以下の通りです。 詳細に関してはそれぞれリンクしてある記事でも紹介してます。 DocumentIntelligenceを使ったPDFの読み込み   RAGパイプラインの実装 RagasによるRAGパイプラインの評価   それぞれの技術要素については、これまでにも解説してきましたが いざシステム化するとうまく動かなかったり、つなぎ方が分からない点もあるかと思うので 今回は、実際にこれらを組み合わせたアプリケーションを構築していきたいと思います。 そのため本記事では各要素について深い解説を行いません。 本記事で読んでいて分からない点があれば、各記事にて詳細を確認ください! 題材 今回RAGに組み込むPDFファイルとしては、デジタル庁が提供する テキスト生成AI利活用におけるリスクへの対策ガイドブック を利用したいと思います。 環境 今回利用する技術としては以下のようなものです。 併せて利用したpythonライブラリのバージョンも記載しておきます。 ※ragasが現状最新の0.1.10を使った場合、エラー発生したのでバージョン注意です。 python(3.1.23) LangChain(0.2.9) Azure OpenAI Service Azure AI Document Intelligence(1.0.0b3) Azure AI Search(11.6.0b3) Ragas(0.1.9) システム構成図としては以下のような形となります。 ステップ 全体のステップとしては以下の流れです。 DocumentIntelligenceを利用し、PDFを読み込んでMarkdownとして出力する LangChainを利用して、Markdownのファイルをセマンティックチャンキングする セマンティックチャンキングした情報をベクトル化してAI Searchに格納する RAG Pipelineを構築する ユーザーからの質問に基づきAI Searchからコンテキスト情報を取得する ユーザーからの質問に対してテンプレートを適用する テンプレートを適用したプロンプトをAzure OpenAI Serviceに対して投げかけ、回答を得る Ragasを利用して評価する Ragasを利用して評価用のテストセットを構築する 4.1(context) と 4.3(answer) と 5.1(question, ground_truth) で得られたパラメータを用いてRAGパイプラインを評価する ではそれぞれのステップを、ソースコードと合わせてみていきたいと思います。 事前準備 今回のプロジェクト構成としては以下の通りです。 └── Project/     ├── rag.ipynb    //ソースコード     ├── .env    //環境変数用のファイル     ├── ai_guidebook.pdf    //RAGに組み込む情報     └── documents/         └── splits    //チャンク化した情報を格納するフォルダ             ├── split_0.txt             └── split_1.txt ライブラリ 必要なライブラリのインストールとインポートを行います。 ! pip install python-dotenv langchain langchain-community langchain-openai langchainhub openai tiktoken azure-ai-documentintelligence azure-identity azure-search-documents==11.6.0b3 ragas==0.1.9 unstructured ipywidgets from langchain_openai import AzureChatOpenAI from langchain_community.document_loaders import AzureAIDocumentIntelligenceLoader from langchain_openai import AzureOpenAIEmbeddings from langchain.schema import StrOutputParser from langchain.schema.runnable import RunnablePassthrough from langchain.text_splitter import MarkdownHeaderTextSplitter from langchain.vectorstores.azuresearch import AzureSearch 環境変数 次に、環境変数の読み込みを行います。 事前にAzure上に作成したリソースから、エンドポイント名やkeyを参照し.envファイルに記載しておいてください。 今回必要となるリソースとしては以下3つです。 Azure OpenAI Service Azure AI Search Azure AI Document Intelligence ※keyに関してはGitHubなどのバージョン管理ツールにはpushしないよう注意しましょう。 import os from dotenv import load_dotenv load_dotenv() os.environ["AZURE_OPENAI_ENDPOINT"] = os.getenv("AZURE_OPENAI_ENDPOINT") os.environ["AZURE_OPENAI_API_KEY"] = os.getenv("AZURE_OPENAI_API_KEY") doc_intelligence_endpoint = os.getenv("AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT") doc_intelligence_key = os.getenv("AZURE_DOCUMENT_INTELLIGENCE_KEY") envファイルとしては以下のような内容になります。 AZURE_OPENAI_ENDPOINT = "https://{resource-name}.openai.azure.com/" AZURE_OPENAI_API_KEY = "{KEY}" AZURE_SEARCH_ENDPOINT = "https:/{resource-name}.search.windows.net" AZURE_SEARCH_ADMIN_KEY = "{KEY}" AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT= "https://{resource-name}.cognitiveservices.azure.com/" AZURE_DOCUMENT_INTELLIGENCE_KEY = "{KEY}" PDFの読み込み まず、AI Document Intelligenceを利用し、PDFから文章をMarkdownの形式で抽出します。 Markdownで出力するためのパラメータはDefaultでONになっているため特に設定する必要はありません。 ただapi_modelとしては、Markdown出力が可能なモデルであるprebuild-layoutを選択しましょう。 今回、RAGに組み込むPDF(ai_guidebook.pdf)は本プログラムと同じ階層に置いてあります。 loader = AzureAIDocumentIntelligenceLoader(file_path="ai_guidebook.pdf", api_key = doc_intelligence_key, api_endpoint = doc_intelligence_endpoint, api_model="prebuilt-layout") docs = loader.load() セマンティックチャンキング 出力したMarkdownをLangchainの MarkdownHeaderTextSplitter 関数を利用してチャンキングします。 今回はHeaderレベルに合わせてチャンク化の方を行いました。 このチャンク化の粒度というものもRAGnお品質に関わってくる部分になります。 チャンキングした情報を、ローカルに作成しておいたdocuments/splitsというフォルダの中に保存します。 # Split the document into chunks base on markdown headers. headers_to_split_on = [     ("#", "Header 1"),     ("##", "Header 2"),     ("###", "Header 3"), ] text_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on) docs_string = docs[0].page_content splits = text_splitter.split_text(docs_string) for i, split in enumerate(splits):     with open(f"documents/splits/split_{i}.txt", "w") as f:         f.write(split.page_content) AI Searchへの格納 次に、分割した情報をベクトルストアであるAzure AI Searchに登録していきます。 ここでもLangchain経由で操作を行います。 まずはAI Searchにアクセスするためのインスタンスを作成します。 ベクトル化のため、Azure AI Searchのコンストラクタのパラメータとして、embeddingsモデルのLLMを指定します。 embeddingsモデルに関しては事前にAzure OpenAI Service上でデプロイしておいてください。 aoai_embeddings = AzureOpenAIEmbeddings(     azure_deployment="text-embedding-ada-002",     openai_api_version="2024-02-15-preview",  # e.g., "2023-12-01-preview" ) vector_store_address: str = os.getenv("AZURE_SEARCH_ENDPOINT") vector_store_password: str = os.getenv("AZURE_SEARCH_ADMIN_KEY") index_name: str = "sios_sample_index" vector_store: AzureSearch = AzureSearch(     azure_search_endpoint=vector_store_address,     azure_search_key=vector_store_password,     index_name=index_name,     embedding_function=aoai_embeddings.embed_query, ) 実行すると、AI Search上にインデックスが作成できていることが確認できます。 まだこのインデックスには何も情報が含まれていないため、先程チャンク化した情報を追加します。 add_documentsを誤って複数回実行すると、のちの関連情報の取得に影響出るため注意してください。 from langchain_community.document_loaders import DirectoryLoader loader = DirectoryLoader("documents/splits") documents = loader.load() vector_store.add_documents(documents) 少し時間が経過するとデータの追加が確認できます。 RAGパイプラインの構築 実際にRAGのパイプラインを構築していきます。 LangChainの LCEL を利用し、チェーンを組み立てます。 Chainの構築に関しては こちら のブログで紹介しています。 今回組み立てるChainは2本です。 Answerを得るためのChain Contextを得るためのChain Answer用のChain ユーザーからの質問に対する回答を得るためのChainです。 以下のようなChainを組みます ChatLLMに対して投げるプロンプトのためのテンプレートを構築 questionに対して、ベクトルストアから関連情報を収集 関連情報と質問事項をテンプレートに組み込み、プロンプトを投げる 回答を出力する Context用のChain ユーザーからの質問に対する関連情報を得るためのChainです。 こちらのChainに関しては1ステップのみです。 questionに対して、ベクトルストアから関連情報を収集 RAGを構築するためだけであればこのパイプラインは必須ではありません。 今回はRagasでの評価にて利用するため構築します。 from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate from langchain_core.messages import SystemMessage llm = AzureChatOpenAI(     openai_api_version="2024-02-01",  # e.g., "2023-12-01-preview"     azure_deployment="gpt-35-turbo-16k",     temperature=0, ) prompt = ChatPromptTemplate.from_messages(     [SystemMessage(          """質問に対して、関連情報を参照に回答してください。          関連する情報を参照しても分からない場合は、「分かりません」と回答してください。"""     ),      HumanMessagePromptTemplate.from_template(          """ 関連情報:{context}                      ## 質問:{question}          ## 回答: """     )      ]     ) retriever = vector_store.as_retriever(search_type="similarity") # Documetを連結する def format_docs(docs):     return "\n\n".join(doc.page_content for doc in docs) # answerを得るためのchain answer_chain = (     {"context": retriever | format_docs, "question": RunnablePassthrough()}     | prompt     | llm     | StrOutputParser() ) # contextを得るためのchain context_chain = retriever 回答取得 ここでRAGのパイプラインが構築できたので、RAGから回答の方を取得したいと思います。 実行する内容としては、answerのchainに質問を与えてあげればOKです。 answer_chain.invoke("本資料の対象の読者は誰ですか?") 得られた回答としては以下の通りです。 '本資料の対象の読者は、テキスト生成AIのサービス開発者やサービス提供者です。' これでRAGのパイプラインの構築は完了です。 では続いて評価のフェーズに映りたいと思います。 Ragasでの評価 テストセットの作成 Ragasでテストセット(評価に用いるQuestion,Ground_truth)を作成する場合は filename のmetadataを保持している必要があります。 そのため、今回の場合は source のmetadata(ファイル名)を filename の値として設定します。 Each Document object contains a metadata dictionary, which can be used to store additional information about the document accessible via Document.metadata. Ensure that the metadata dictionary includes a key called filename, as it will be utilized in the generation process. The filename attribute in metadata is used to identify chunks belonging to the same document. For instance, pages belonging to the same research publication can be identified using the filename. ref : Generate a Synthetic Test Set from langchain_community.document_loaders import DirectoryLoader loader = DirectoryLoader("documents/splits") documents = loader.load() for document in documents:     document.metadata['filename'] = document.metadata['source'] 次に、Ragasの機能でテストセットを作成します。 テストセットの作成にはLLMを利用するため、Azure OpenAI Service上にChatモデルとEmbeddingsモデルをデプロイしておきます。 デプロイしたモデルのapi versionや、モデル名を各種パラメータに設定します。 また今回は日本語でテストセットを作成するため、adaptの language の設定を japanese とします。 その他、test_sizeやdistributionsの値は適宜調整してください。 from ragas.testset.generator import TestsetGenerator from ragas.testset.evolutions import simple, reasoning, multi_context from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings # generator with openai models generator_llm = AzureChatOpenAI(     openai_api_version="2024-02-01",     azure_deployment="gpt-35-turbo-16k", ) critic_llm = AzureChatOpenAI(     openai_api_version="2024-02-01",     azure_deployment="gpt-35-turbo", ) embeddings = AzureOpenAIEmbeddings(     openai_api_version="2024-02-01",     azure_deployment="text-embedding-ada-002" ) generator = TestsetGenerator.from_langchain(     generator_llm,     critic_llm,     embeddings ) generator.adapt(     language="japanese",     evolutions=[simple, reasoning, multi_context] ) # generate testset testset = generator.generate_with_langchain_docs(documents, test_size=2, distributions={simple: 0.5, reasoning: 0.25, multi_context: 0.25}) テストセットの表示 どのようなテストセットが作成されたか見てみます。 testset.to_pandas() もちろんこれらのテストセットは自分で用意してもらってもOKです。 ただ、Ragasで生成できるようにしておくと、膨大なテスト量をこなせたり、自動化したりしやすいのでよいですね。 評価項目のインポート Ragasで評価する項目をimportし、あとで設定可能なようにListとして定義しておきます。 Ragasには多くの評価項目がありますが、全てを評価しようとするとLLMのトークン数を多く利用します。 その場合、リソースが枯渇したり、思わぬ金額が請求されたりするため注意してください。 今回は以下の4つのみを評価対象とします。 context_precision faithfulness context_recall, context_relevancy from ragas.metrics import (     context_precision,     faithfulness,     context_recall,     context_relevancy ) # list of metrics we're going to use metrics = [     context_precision,     faithfulness,     context_recall,     context_relevancy ] 評価パラメータの整備 評価に使うための question ground_truth context answer を用意していきます。 questionとground_truthに関しては、先程Ragasの機能で生成したtestsetの値を利用します。 この時、回答が生成されないケース( nan )があるため、”回答無し”という表記に変換します。 次に、先程構築した2つのchainを利用して、contextとanswerの内容を取得します。 df = testset.to_pandas() df = df.fillna("回答なし") #nanは"回答なし"に変換する def get_answer_contexts(question: str):     answer = answer_chain.invoke(question)     # langchainのDocumentからRagas評価時に使うテキストデータだけ取り出す。     contexts = context_chain.invoke(question)     contexts = [c.page_content for c in contexts]     return {"answer": answer, "contexts": contexts} results = [get_answer_contexts(s) for s in df["question"]] 評価パラメータのセット 作成した各種パラメータをdatasetsの中に代入します。 from datasets import Dataset result_ds = Dataset.from_dict(     {         "question" : df["question"],         "answer" : [r["answer"] for r in results],         "contexts": [r["contexts"] for r in results],         "ground_truth": df["ground_truth"]     } ) result_ds.to_pandas() 評価に利用するLLMパラメータの設定 評価に利用するLLMのパラメータを設定します。 先程まで利用していたモデルと同一のものでも、別に用意してただいてもOKです。 from langchain_openai.chat_models import AzureChatOpenAI from langchain_openai.embeddings import AzureOpenAIEmbeddings from ragas import evaluate chat_llm = AzureChatOpenAI(     openai_api_version="2024-02-01",     azure_deployment="gpt-35-turbo" ) embeddings = AzureOpenAIEmbeddings(     openai_api_version="2024-02-01",     azure_deployment="text-embedding-ada-002" ) 評価の実施 evaluate関数で実際に評価を行います。 result = evaluate(     result_ds, metrics=metrics, llm=chat_llm, embeddings=embeddings ) 結果の表示 RAGパイプライン全体の結果の表示 result 以下のような結果となりました。 {'context_precision': 0.9028, 'faithfulness': 0.5000, 'context_recall': 0.5000, 'context_relevancy': 0.1732} 次に、各質問に対する結果の表示 をします。 result.to_pandas() まとめ 今回は、RAGのパイプライン構築から、Ragasでの評価まで一気に解説しました。 最初にも書きましたが、構築とともに評価を行っていることが今回の大きなポイントです。 「開発して、評価して、開発して、評価して…」と、いいループが回せるとよいかと思います。 是非今回の内容をベースに、RAGの構築の方に取り組んでみてください! ではまた! 参考文献 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【AOAI】RAGパイプラインの構築から評価フェーズまでの実装を一挙解説!【Ragas】 first appeared on SIOS Tech. Lab .
今号では、前号に引き続き nmcli コマンドの使い方やオプションについてご紹介します! 今回は、接続 (ネットワーク) 編です。 nmcli connection コマンドについて 今回ご紹介する nmcli connection は、ネットワークのプロファイル情報を参照したり編集するためのコマンドです。 nmcli コマンドの中で、最も使用頻度が多いと言えるでしょう。 また、ネットワークの有効化/無効化も nmcli コマンドから行うことができます。 基本の書式 サブコマンドに “connection” もしくは “con” 、 “c” を指定すると、このシステムで 使用可能なプロファイルの情報を表示します。 なお、これはオプションに “show” を指定した時と同じ動作になります。 # nmcli con show NAME UUID TYPE DEVICE System eth0 5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03 ethernet eth0 lo 8515cb3c-66df-419b-b813-b5bb9c5e7e15 loopback lo nmcli connection コマンドのオプション よく使用されると考えられるオプションを抜粋してご紹介します。 オプションに “up” 、その後に対象となるプロファイルを指定すると、当該プロファイルの ネットワークをアクティブ (有効) にします。 # nmcli con up "System eth0" Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3) なお、上記はインタフェースの名前 (id) を指定していますが、他にも uuid を指定することも できます。 # nmcli con up uuid 5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03 オプションに “down” 、その後に対象となるプロファイルを指定すると、当該プロファイルの ネットワークを非アクティブ (無効) にします。 # nmcli con down "System eth0" ※ nmcli con up と同様に、id 以外にも uuid を指定することもできます。 オプションに “modify” 、その後に対象となるプロファイル、値を変更したいパラメータを 指定すると、指定したパラメータの値を変更できます。 例えば、eth0 の id (System eth0) を変更したい場合、下記の様に実行します。 # nmcli con modify "System eth0" connection.id "eth0" # nmcli con show NAME UUID TYPE DEVICE eth0 5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03 ethernet eth0 lo f6681442-22fa-4cc3-9ea5-a92f0c45ee7f loopback lo オプションに “clone” 、その後に対象となるプロファイル、新しく作成 (複製) する プロファイル名を指定すると、既存のプロファイルから新しいプロファイルを複製します。 例えば、既存のプロファイル eth0 から eth1 を作成 (複製) したい場合、下記の様に実行します。 # nmcli con clone eth0 eth1 eth0 (5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03) cloned as eth1 (3fc59d00-c73c-4c75-8a9b-72730224d2be). # nmcli con show NAME UUID TYPE DEVICE eth0 5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03 ethernet eth0 lo ad8c3d7a-0d6b-43c8-b709-40d980150fa3 loopback lo eth1 3fc59d00-c73c-4c75-8a9b-72730224d2be ethernet -- ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!nmcli コマンドの使い方 ~接続編~ first appeared on SIOS Tech. Lab .
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 アメリカの大学生が、Google Drive から Linuxを起動することに成功しました。 Booting Linux off of Google Drive https://ersei.net/en/blog/fuse-root Windows がブルースクリーンになり、強制的に再起動を繰り返すという事象が話題になりましたが、今回の問題が発生する以前にも Debian や Rocky Linux でも同様の問題が発生していたことが分かりました。 CrowdStrikeによるPC起動不能問題は過去にLinuxディストリビューションでも発生していた https://gigazine.net/news/20240722-crowdstrike-debian-rocky-linux/ 2024/7/10、Zed Industries が Rust で実装されたオープンソースのコードエディタ「Zed」の Linux 版を公開しました。 オープンソースのRust製コードエディタ「Zed」、Linux版を公開 https://atmarkit.itmedia.co.jp/ait/articles/2407/16/news036.html ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2024年7月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech. Lab .
はじめに こんにちは、サイオステクノロジーの藤井です。 Azureのリソースを検索したいってことありますよね。私はありました。 実は私、部署内にてクラウドコスト改善チームという、部署内で利用しているazure等のクラウドリソースの無駄遣いを減らす活動をしているのですが、その活動の一環として、無駄遣いなリソースをAzure Resource Graphで検索してslackにて通知する、というシステムを作成しました。この記事では、そこで得た知見について書いていきたいと思います。 基本的には、本日(2024/7/19(金))に行ったPS Liveで話した内容と同じです。 Azure Resource Graphとは Azure Resource Graphは、KQLを使って、サブスクリプション内の様々なリソースやリソースの変更履歴などを検索できるサービスです。 KQLとは KQLとは、Kusto Query Languageの略で、今回紹介しているResource Graphの他、 Log AnalyticsやData Explorer等のサービスでも使われるSQLライクなクエリ言語です。 KQLの詳しい使い方については、以下の公式ページに載っています。 https://learn.microsoft.com/ja-jp/azure/data-explorer/kusto/query/tutorials/learn-common-operators 例として「東日本リージョンにある仮想マシンを検索する」場合のクエリーで説明します。 東日本リージョンは他の、例えばアメリカ東海岸リージョン1などと比較して高いですから、東日本リージョンのリソースを検索出来れば、コスト削減につながると思います。 1行目のresourcesでどこから検索するか指定します。この場合はこのサブスクリプションのAzureリソース全てです。 その次のproject句で、表示する項目を絞り込みます。この例では、name・type・location・resourceGroupの4項目のみ表示する用にしています。 最後にwhere句で、表示するリソースを絞り込みます。この例では、typeが仮想マシン、resourveGroupが今回の検証用のリソースグループ、locationが東日本リージョンとなるように絞り込んでいます。 Azure Resource Graphの使い方 話を戻しまして、Azure Resource Graphの実際の使い方について説明します。 ここではKQLの例と同じく、東日本リージョンにあるVMを検索しようと思います。 まず検証用として東日本リージョンとそれ以外のリージョン(今回はEast US)にVMを作成しておきます。 「Resource Graphエクスプローラー」を選択します。 画面上側に、先ほどKQLの説明の時に例に出したクエリを入力して、「クエリの実行」ボタンを押すと、画面下側に検索結果が表示されます。この例では、先ほど作成した2つのVMの内、東日本リージョンのVMのみ検索する事が出来ました。 自動化する方法 さて、Azure Resource Graphはリソースを簡単に検索できますが、無駄遣いなリソース探しでは、一回検索したらOKでは無く、継続的に検索する必要があります。しかし、毎回手動でクエリーを実行するのは面倒なので、検索を自動化する必要があります。 この記事では二種類の検索自動化方法を紹介します。 1個目はlog analyticsを使う方法で、2個目はAzure Logic Appsを使う方法です。 Log Analyticsを使う方法 まず、Log Analyticsを使って、リソース検索を自動化する方法を解説します。 Log Analyticsは、Azureサービスなどのログを収集し分析するサービスです。 Log Analyticsを使った検索自動化の概要としては、以下の図のように、まず、Log Analyticsを使って対象リソース(先ほどの例では、「東日本リージョンのVM」)の個数を監視します。この対象リソースが1個以上あるとメールで通知する、というアラートルールを作成することで、自動的に検索し続けることが出来ます。 詳しくは以下の公式ページに載っています。 https://learn.microsoft.com/ja-jp/azure/governance/resource-graph/alerts-query-quickstart?tabs=azure-resource-graph log analyticsを使うメリットは、高頻度で検索し続けられる事です。 デメリットとしては、メール以外・SMSなどいくつかの通知方法以外(例えばslackなど)で通知しようとすると、実装が複雑になってしまうことです。 通知はメールでも良いので、検索対象のリソースが出来たらすぐ知りたいという場合は、log analyticsを使う方法が適していると思います。 Azure Logic Appsを使う方法 次に、Azure Logic Appsを使って、リソース検索を自動化する方法を解説します。 Azure Logic Appsとは、ノーコードまたはローコードワークフローを作成しサーバーレスで実行できるサービスです。 Azure Logic Appsを使った検索自動化の概要としては、以下の図のように3つのトリガー・コネクターを持ったLogic Appsを作成します。 まず上段の定期実行トリガーによってこのLogic Appsが定期的に実行されます。 次に、中段のHTTPコネクターで、Resource GraphのREST APIに検索条件のKQLを含むリクエストを投げることで、検索を実行して、結果を取得します。 最後に、下段のslackコネクターで、取得した検索結果をもとにslackに通知を送ります。 詳しくは以下の公式ページに載っています。 https://learn.microsoft.com/ja-jp/azure/governance/resource-graph/tutorials/logic-app-calling-arg Azure Logic Appsを使うメリットは、カスタマイズ性が高いところです。コネクターが豊富なのでいろんな機能と組み合わせたり、条件によって検索内容・通知内容を変えたりできます。 この例で使っているslackなどのメール以外の手段で通知したい・通知内容をカスタマイズしたい場合などは、Azure Logic Appsを使う方法が適しています。 まとめ この記事では、Azure Resource Graphで簡単に検索する方法と、Azure Logic AppsまたはLog Analyticsを利用して検索を自動化する方法を説明しました。 ちなみに、冒頭で話題に出した、私が作成した、「無駄遣いなリソースを検索してslackにて通知するシステム」は、「検索は週に1回で良い」と「slackで通知する」という要件のためAzure Logic Appsを利用して実装しました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure Resource Graphで簡単にリソースを検索する方法 first appeared on SIOS Tech. Lab .
サイオステクノロジー武井です。僭越ながら、5回目のMicrosoft MVPを再受賞致しました。今年で通算5年目となります。これからも有益な情報を発信していきますので、何卒よろしくお願い致しますm(_ _)m 受賞カテゴリの変更 特筆すべき変更として、今年は私の受賞カテゴリが昨年の「Microsoft Azure」から「AI Platform」に変更されました。ちなみに、Microsoft MVPはカテゴリというのがありまして、得意分野ごとに表彰される仕組みとなっています。 プロフィール見るとたしかにAI Platformに変更になっています。 昨年は、AI関連の発信が多かったこともあり、カテゴリが変更になったのかと思います。今年もAI関連はどんどん発信していきますー。 Microsoft MVPとは? そもそも Microsoft MVP (Most Valuable Professional) 制度というのがどんなものかを説明します。これは、Microsoft が、社外のエンジニアを「MVP」として表彰する制度になります。 マイクロソフト製品(AzureとかOffice365など)などに対する深い専門知識を待ち、そしてその知識をブログや登壇などを通じて世に広く広めてくれる人たちに送られる表彰制度です。 肝なのは、「深い専門知識を待ち」だけではなく「 その知識をブログや登壇などを通じて世に広く広めてくれる人 」であることですね。ここが大きな特徴で、技術コミュニティへの貢献度が大きく問われるということになります。 受賞しますと、Azureの月数万円分無料利用可能なサブスクリプションが頂けたりなど、今後のアウトプットをさらに充実するためのさまざまな支援があります。 これから 5回目の受賞ができたのも、ひとえに皆様のご支援・ご協力のおかげでございます。改めて御礼申し上げますm(_ _)m カテゴリがAIになりましたので、AI関連の情報を更に提供していきたいと思います。それだけではなく、引き続きAzureに関する全方位的な情報を「わかりみ深く」届けたいと思います。 ということで、以下のYoutubeチャンネルも引き続き宜しくお願いしますm(_ _)m ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Microsoft MVPを再受賞しました first appeared on SIOS Tech. Lab .
こんにちは!サイオステクノロジーの安藤 浩です。今回はエンタープライズ向けブロックチェーンのデファクトスタンダードといわれているHyperledger Fabricについてご紹介します。入門として、Hyperledger Fabricの説明とHyperledger Fabricの各コンポーネントについて説明したいと思います。 Hyperledger Fabric とは Hyperledger Fabric は、Linux Foundation の下で設立されたHyperledger プロジェクトのひとつであり、オープンソースのエンタープライズ向けの許可型(Permissioned) 分散台帳テクノロジー(DLT) プラットフォームです。 Hyperledger Fabric は金融、保険、ヘルスケア、人事、サプライチェーン、デジタル音楽配信などの幅広い業界のユースケースに利用可能です。 Hyperledger Fabricの特徴 Hyperledger Fabricの特徴としては以下が挙げられます。 1.許可型ネットワーク Member Shipservice Provider(MSP)を使用してネットワークに参加するユーザーを管理し、許可されたメンバーのみがアクセスできます。 2.機密性の高い 共有したいデータのみを、共有したいメンバーに公開することが可能です。 3.Chaincode(スマートコントラクト)やFabric SDKでカスタム言語の習得は不要 Ethereum ではSolidity を利用するのが一般的かと思いますが、Hyperledger FabricのChaincode(スマートコントラクト)ではGo、Node.js、Java でコードが書けるので、独自の言語の習得は不要です。Fabric SDK(クライアントアプリケーションで利用)はNode.js、Javaの公式で提供されています。 ネットワークモデルによるブロックチェーンの分類 ブロックチェーンは、ネットワークモデルにより大きく以下の3つに分類されます。Hyperledger Fabricではプライベートブロックチェーンとコンソーシアムブロックチェーンの構築が可能です。 1. パブリックブロックチェーン 誰でも参加でき、全ての取引が公開されます。例としてはBitcoin, Ethereumです。 2. プライベートブロックチェーン 特定の組織内で利用され、アクセスが制限されています。例としてはHyperledger FabricやGoQuorumです。 3. コンソーシアムブロックチェーン 複数の組織が共同で運営し、参加メンバーが制限されています。例としてはHyperledger FabricやGoQuorumです。 主要なコンポーネントの説明 以下にHyperledger Fabricの主要なコンポーネントの説明をします。概念をつかみたいと思いますので、各コンポーネントの詳細はここでは省略します。(Hyperledger Fabric v2 系での説明) Organization コンポーネント(Peer, Orderer など)、ユーザが必ずいずれかのOrganizationに所属する。 Membership Service Provider (MSP) ネットワーク上のすべてのコンポーネント(クライアントアプリケーション、Peer、Ordererなど)/ユーザーを管理および認証する。 クライアントアプリケーション Hyperledger Fabricを利用するアプリケーションのこと。Fabric SDKを利用してPeer上のChaincodeを実行する。 Peer(ピア) Chaincodeの処理やブロックの承認などを行うノードのこと。 Peerは以下の特徴がある。 ・Ledger(台帳)を保持する ・Chaincodeを実行する Ledger(台帳) Organization間のトランザクションの履歴と現在の状態のデータのこと。 LedgerはBlockchainとWorldStateで構成される。Blockchainはトランザクションの履歴のことで、WorldStateはトランザクションの履歴が現在の状態に至ったデータのこと。※WorldStateは現在の状態しか持たない。 これはBlockchainのどの時点を切り取ってもWorldStateが生成できることを意味している。 Chaincode(チェーンコード) Ledger(台帳)の更新、参照をするビジネスロジックのこと。異なるOrganizationの間のルール、規則をコードによって定義する。 一般的にブロックチェーンではSmart Contract(スマートコントラクト)というが、Hyperledger FabricではSmart ContractとChaincodeは同じ意味で使っている。クライアントアプリケーションは、台帳に記録されるトランザクションを生成するために、Fabric SDKを利用してChaincodeを呼び出す。 Orderer(オーダラー) トランザクションの順序付けを行い、ブロックを生成するノードのこと。 Ordererは以下の特徴がある。 ・Ordering Service(Orderer ノードの群のこと)を構成する ・トランザクションの順序を確定し、ブロックを生成する ・生成したブロックをPeerノードに配布する CA(Certification Authority) コンポーネントやユーザに対して、アイデンティティ(証明書)を発行するPKIの認証局のこと。通常、Fabric CAを使うが、ほかのCAを利用してもよい。 Channel(チャネル) Hyperledger Fabricのネットワーク内に構成される 特定のOrganizationの間で通信を行うためのサブネットワークのこと。 システム構成図   図の説明と注意 Organization: ORG1, ORG2, ORG3がHyperledger Fabricのネットワークに参加しています。 Channel: Channel1, Channel2 があり、Channel1にはORG1, ORG2が参加しており、Channel2にはORG1, ORG2, ORG3が参加しています。(Channel 内のChannel PolicyというものでMSPの設定がされるようです) Client Appはクライアントアプリケーションのことです。Fabric SDKを利用して、Peer上のChaincodeを実行します。 Identityは CAによって発行された証明書です。各ノードには証明書があります。 CAは各Organizationに1つは必要なようですが、MSPやCAは現状よくわかっておらず、正確に表現できていない可能性があります。CAと通信する際はFabric CA Clientを利用して通信します。 チャネル内のLedger   各PeerにはChaincodeをインストールと有効化する仕組みがあり、Chaincodeに紐づくLedgerが生成されるので上記のシステム構成図ではChannel ごとに各PeerにLedgerが上記の図のように設定できるようになります。Channel1ではORG3が参加していないため、ORG1,ORG2に関するトランザクションのデータはORG3には共有されません。 まとめ Hyperledger Fabricの特徴とコンポーネントの概略が把握できたかと思います。別の記事でHyperledger Fabricのトランザクションフローについて記載します。 ※誤り等ありましたらコメントいただけますと幸いです。 参考URL https://hyperledger-fabric.readthedocs.io/en/release-2.5/whatis.html https://hyperledger-fabric.readthedocs.io/en/release-2.5/key_concepts.html https://hyperledger-fabric.readthedocs.io/en/release-2.5/glossary.html https://hyperledger-fabric-ca.readthedocs.io/en/latest/operations_guide.html#topology https://go.oracle.com/LP=130709   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Hyperledger Fabric 入門 – Hyperledger Fabricとは、Hyperledger Fabricのコンポーネントの説明 – first appeared on SIOS Tech. Lab .
はじめに 7月2日に岐阜県の長良川国際会議場で開催された国際会議 ERDSE2024 に参加してきました。 大学時代の研究を卒業前に本会議に投稿していたのですが、晴れて採録となったため発表に行ってきました。 このブログには発表した研究の内容と発表した際の感想をまとめようと思います。 研究内容 ざっくり説明するとYes/Noチャートを用いて情報検索をするためのシステムを提案しました。 アキネーターというサービスがありますが、あれに近しいものです。 既存の検索手法は、入力するクエリや膨大な検索結果を吟味する必要があり、検索結果にこだわろうとすると膨大な時間を要してしまうことになります。 一方で、Yes/Noチャートを検索に用いることができると、ユーザは質問にYesかNoで答えるだけで自分にぴったりな情報を入手することができます。 実装上の課題としては、YesかNoで答えられる質問をどのように生成するかがネックになったのですが、ChatGPTに生成してもらうことにしました。 いくつかの入力情報をもとに、それらの特徴を捉えた質問を生成するのはLLMが得意とするところかなと考えてのことです。 ユーザ実験の結果としては、既存の検索手法(Web検索やChatGPT)と比較し、検索時間の短縮や操作の簡便さに大きく寄与することがわかりました。 他方で、システムから提示された情報に納得がいかないユーザが少し多かったことが確認されました。 ChatGPTが生成した質問と、ユーザに提示される情報がかみ合っていないことがしばしばあり、ChatGPTの出力を上手く制御する必要があると感じました。 発表した感想 国際会議ということで英語で発表を行ってきました。 発表の方は事前に練習を重ねていたこともあり、流暢に話すことができました。 一方で、質疑応答についてはかなり苦戦しました。特に訛りの強い英語で質問を受けた際は、内容が聞き取れず狼狽してしまいました。 一旦落ち着いて質問の内容を聞き返すと良かったと思いますが、焦ってしまい的確に応答することができませんでした。 経験をたくさん重ねることで、落ち着いて英語でもコミュニケーションをとれるようになっていければと思いました。 いずれ仕事でも英語を用いる機会があるかもしれませんが、その際に今回の学会発表の経験が生きれば良いかなと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post ERDSE2024参加報告 first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジーの木村です。 今回は、Flutterの環境構築(Macでの手順)から Hello World を表示するまでを書きたいと思います。 コードエディタにはVisual Studio Codeを使います。Visual Studio Codeのインストール手順は含んでおりませんのでインストールしていない方は事前にインストールしておいてください。 Flutterとは Googleが開発したオープンソースのアプリケーション開発用フレームワーク。Dart言語を使用し、単一のコードベースでiOSやAndroid、Web、デスクトップアプリ など様々なプラットフォームのアプリを構築できます。 環境構築 Macでの環境構築の手順を記載します。 拡張機能のインストール VSCodeにて、Flutterの拡張機能をインストールします。 1. VSCodeを起動し、サイドバーの拡張機能のアイコンをクリックします。 2. 「Flutter」と入力すると、検索結果に表示されますので、「インストール」をクリックします。 Flutterをインストールすると、「Dart」の拡張機能も自動でインストールされます。 Flutter SDK のインストール VSCodeにて、Flutter SDK をインストールします。 1. VSCodeにて、メニューバーより「表示」-「コマンドパレット」をクリックしてコマンドパレットを開きます。 2. コマンドパレットにて「flutter」と入力すると、「Flutter:New Project」が表示されるので、選択します。 3. 以下の画像のような SDK のダウンロードを促すプロンプトが表示されますので、「Download SDK」をクリックします。 4. 任意のフォルダを指定し「Clone Flutter」をクリックします。 指定したフォルダ配下に、「flutter」というフォルダが作成されます。こちらのパスをメモしておきます。(メモしたパスは、以降の Path の設定の手順で使います。) Path の設定 FlutterのPathを通します。 1. お使いの Mac のシェルを確認します。ターミナルを起動し、以下のコマンドを実行します。 echo $SHELL 「/bin/zsh」と表示された場合、シェルは zsh です。 「/bin/bash」と表示された場合、シェルは bash です。 2. 以下のコマンドを入力して Path の設定を行います。(以下はシェルが「zsh」の場合のコマンドです。お使いの環境が「bash」の場合は .zshrc のところを .bash_profile としてください。) echo export PATH="$PATH: /bin" >> ~/.zshrc 3. 以下のコマンドを実行して設定を反映させます。(以下はシェルが「zsh」の場合のコマンドです。お使いの環境が「bash」の場合は .zshrc のところを .bash_profile としてください。) source ~/.zshrc 4. ターミナルにて、「flutter」と入力して以下のように表示されれば、Path の設定は完了です。 Android Studio のインストールと設定 1. Android Studio の公式サイト にアクセスします。 2. 「Android Studio Koala をダウンロード」をクリックします。 3. 利用規約の同意にチェックを入れ、お使いの Mac が使用しているチップに応じたもの(チップが「intel」の人は Intel を、「Apple M1」「Apple M2」の人は Apple をダウンロード)をダウンロードします。 お使いの Mac が使用しているチップは、画面の左上にあるメニューバーのAppleアイコンをクリックし、[このMacについて]より確認することができます。 4. ダウンロードしたファイルを開き、案内通りにインストールを進めます。 5. インストールが完了したら、Android Studio を開きます。 6. 画面左の[Plugins]をクリックし、検索欄に「flutter」と入力します。Flutterが検索結果に表示されるので「Install」をクリックします。 7. 「Restart IDE」をクリックします。 8. 「Restart」をクリックします。 9. Android Studio が再起動されます。「More Actions」より「SDK manager」をクリックします。 10. 「SDK Tools」タブを選択し、「Android SDK Command-line Tools」にチェックを入れ、「Apply」をクリックします。 11. 確認ダイアログが表示されますので「OK」をクリックします。 12. 「Finish」をクリックします。 13. ターミナルを起動し、以下のコマンドを実行します。 flutter doctor --android-licenses 何度か確認メッセージが表示されますので、全て「y」を入力します。 以下のメッセージが出れば完了です。 XCode のインストール 1. App Store を起動します。 2. App Store の検索欄に「xcode」と入力し検索します。検索結果に XCode が表示されますので「入手」をクリックしてインストールします。以降は案内通りにインストールを進めます。 Google Chrome のインストール Google Chrome の公式サイト より、ダウンロードしてインストールします。 flutter doctor で確認 環境構築が正しく行えているか確認します。 ターミナルを起動し、以下のコマンドを入力します。 flutter doctor 以下のように、全て緑のチェックマークが表示されれば、完了構築完了です。 「!」や、「×」が表示された場合は、環境に何らかの問題があります。表示されるメッセージの内容に従って対応しましょう。 サンプルアプリで動作確認 VSCodeにて、サンプリアプリを動かしてみましょう。 プロジェクトの作成 1. VSCodeにて、メニューバーより「表示」-「コマンドパレット」をクリックしてコマンドパレットを開きます。 2. コマンドパレットにて「flutter」と入力すると、「Flutter:New Project」が表示されるので、選択します。 3. 「Application」を選択します。 4. 作成するプロジェクトをどこに配置するか聞かれるので、任意のフォルダを選択して「Select a folder to create the project in」をクリックします。 5. 任意のプロジェクト名を入力します。ここでは「flutter_hello_world」とします。 6. プロジェクトの作成が完了すると、以下のように表示されます。 カウンターアプリの実行 作成したプロジェクトにはデフォルトでサンプルアプリとして「カウンターアプリ」の実装が含まれています(lib 配下の main.dart というファイルに記載されています)。まずはこちらをビルドし、動作させてみましょう。 1. 画面右下の「macOS(darwin)」をクリックします。 2. 今回は、iOSのシミュレータで立ち上げます。「Start iOS Simulator」を選択します。 3. シミュレータが立ち上がります。 4. サイドバーの「実行とデバッグ」のアイコンをクリックします。 5. 「実行とデバッグ」をクリックします。 6. シミュレータにて、カウンターアプリが立ち上がります。 右下の「+」をタップすると、画面中央に表示される数字がカウントアップされます。 7. アプリの実行を終了するには、赤い四角のボタンをクリックします。 Hello World 先ほどのカウンターアプリを変更して、Hello World を表示するようにしてみましょう。 「main.dart」の実装を以下のように修正します。 import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'My App', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: const MyHomePage(), debugShowCheckedModeBanner: false, ); } } class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), backgroundColor: Theme.of(context).colorScheme.primaryContainer, ), body: const Center( child: Text( 'Hello, World!', style: TextStyle(fontSize: 24,), ), ), ); } } 以下、コードの簡単な説明です。 3〜5行目 Flutterアプリでは、lib配下にある「main.dart」ファイルの main 関数がエントリーポイントとなり、ここからアプリが開始されます。 runApp 関数には、アプリケーションのルートウィジェット(アプリ上で最初に展開して欲しいウィジェット)を指定します。ここでは MyApp を呼び出しています。 7〜22行目 MyAppでは MaterialApp というウィジェットで、アプリケーション全体の基本的な設定と構造を定義しています。画面の中身の部分は MyHomePage を呼び出しています。 debugShowCheckedModeBanner: false, と記載すると、画面右上に表示されるDEBUGバナーを非表示にします。 24〜42行目 MyHomePageでは、アプリバーの表示と、「Hello, World!」の文字を画面中央に表示するようにしています。 実行すると、以下のような画面が表示されます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【Dart】 Flutter × VSCode で、環境構築 から HelloWorld まで(Mac) first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジーの塙です。 今回は、OpenShift(以下、OCP)上で、VMを実行するための機能となるOpenShift Virtualization(以下、OCP Virt)について説明したいと思います。 前提情報 本記事では、現時点では、以下のバージョンを対象としています。 ■バージョン OpenShift v4.15 OpenShift Virtualization v4.15 *1 *1 OCP Virt のバージョンは、v4.8 から OCP と同じになり、OCPと同様に推移していきます。 https://access.redhat.com/support/policy/updates/openshift_operators 概要 OCP Virt は、OCP 上で VM を動作、管理するためのコンポーネントとなります。 OCP Virt は OCP v4.5 から GA となり、OCP WebUI の OperatorHub から OCP Virt の Operator をインストールすることで利用可能となります。 サブスクリプション は、OCP のサブスクリプションで利用できるようになります。 また、OCP Virt は CNCF の Incubating Project である KubeVirt を利用して開発されているようです。 https://www.cncf.io/projects/kubevirt/ 休暇 アーキテクチャの基礎部分 VM を動作させる仕組みとして KVM を使用します。 KVM が RHCOS のカーネルで実行され、QEMU、libvirt はコンテナの内部で実行される形式となります。 概要では、Kubernetes の他の Pod と同様に、以下の枠組みを使用します。 CNI CSI CRD 内部のコンポーネント VM を動作させるには、主に3つのコンポーネントがあります。 ( Building a unified hybrid cloud strategy with Red Hat OpenShift Virtualization  より 引用) virt-controller :CRD で定義された VM リソースを監視し、VM リソースの Pod をノードに割り当てる virt-handler :各 Worker ノードで実行される DaemonSet。API や virt-controller と連携して、Pod の作成などの操作を、virt-launcher に指示する役割がある virt-launcher :libvirtd と連携し、VM の作成や削除を制御する VM のリソース VM のリソースは Kubernetes の CRD を用いて定義を行う形となります。 # VMリソースの例 apiVersion: kubevirt.io/v1alpha3 kind: VirtualMachine metadata: label: app: demo name: test-vm spec: dataVolumeTemplates: - metadata: name: example-dv spec: pvc: accessModes: - ReadWriteOnce resources: requests: storage: 1G source: http: url: "" running: false template: spec: domain: devices: disks: - name: containerdisk disk: bus: virtio interfaces: - masquerade: {} name: default resources: requests: memory: 1024M networks: - name: default pod: {} volumes: - name: containerdisk containerDisk: image: kubevirt/fedora-cloud-container-disk-demo VirtualMachine(VM)リソース:VMIを作成するためのテンプレートを構成するリソース VirtualMachineInstance(VMI) リソース:VM リソースの定義の、稼働中の実態を表すインスタンスのリソース VirtualMachineInstanceMigration リソース:VM をライブマイグレーションするときに構成するリソース DataVolume(DV) リソース:VM のディスクイメージなどのストレージ側の設定を定義するリソース サポート対象のノードと OS サポート対象のノード VM を動作させるノードは、ベアメタルになります。 OCP Virt の サポート対象 のクラスターノードは以下のとおりです。 ブレインメタルサーバー AWS ベアメタル インスタンス IBM Cloud ベアメタルサーバー (TechPreview機能) サポート対象のOS VM の OS としてサポート対象となっている OS が確認できます。 https://access.redhat.com/articles/973163#ocpvirt 参考までに、rhel OS のライセンスは OCP に含まれており、Windows は別途ライセンスが必要になります。 利用のポイント OCP Virt の利用を考える時のポイントを以下に記載していきます。 1. VM管理のメリット VM のディスク、ネットワークなどのリソース定義は、OCP の Pod と同様に、yaml ファイルのマニフェストで管理出来る形になっています。VM 自体を IaC で管理することで、ある程度 VMの管理自体もしやすく、自動化出来る部分もあるのではないでしょうか。 例えば、現在コンテナ環境も運用されており、コンテナ運用を見据えた取り組みをしたいという考えがある場合は、VM と コンテナの運用管理を統一することができ、効率化を図ることができます。 2. コンテナ環境とシームレスに接続 Kubernetes の仕組みとして CSI(Container Storage Interface)*1、CNI(Container Network Interface)*2 を他のPodと同じように使用できます。 これは、VM と Pod 間で通信を行いたいときに、ネットワークがクラ​​スター内で完結できることを意味します。 そして、他のPodの通信方法と同じように、通信の際のVMのIPを意識せずに良いという所もポイントとなります。ただ、IPを指定して通信を行いたいといった要件の場合は、少し難点があるかもしれません。 *1 CSI(Container Storage Interface):異なるストレージ技術を利用してコンテナに永続的なストレージを提供する仕組み *2 CNI(Container Network Interface): コンテナ間でのネットワーク接続を管理するためのプラグインを提供する仕組み 3. 他環境からのマイグレーションや、稼働中の変更時のダウンタイム OCP Virt は、MTV というツールを用いて、他の VM 環境から VM をマイグレーションすることが可能です。 これは非常に便利な機能ですが、注意点が一つあります。 現時点では、他環境からマイグレーションをするときに VM のダウンタイムが発生します。移行規模にもよりますが、ダウンタイムを考慮した移行を計画する必要があります。 また、OCP Virt で稼働中のリソースを変更する場合、マニフェストを変更、適用する形となります。マニフェスト適用後に Pod の再起動が発生するので、VM のリブートでダウンタイムが発生することを考慮する必要があります。 まとめ 今回は、OpenShift(以下、OCP)上で、VMを実行するための機能となるOpenShift Virtualization(以下、OCP Virt)について説明しました。 また、より詳細のOCP Virt の機能について紹介出来ればと思います。 本書の記載が読者のお役に立てば幸いです。 参考文献 https://docs.redhat.com/ja/documentation/openshift_container_platform/4.15/html-single/virtualization/index OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (1) OpenShift Virtualization、コンテナ基盤で仮想マシンを動かす ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift Virtualization – OpenShift でのVM管理についてご紹介 first appeared on SIOS Tech. Lab .