RareJob Tech Blog

レアジョブテクノロジーズのエンジニア・デザイナーによる技術ブログです

EdTech LLM元年でした!という話

どうもCTOの @jumboOrNot です。 今年は怒涛のLLMの年でしたね〜、弊社でもさまざまなトライがあり振り返ってみようと思います。

「見(ケン)」の時期

2022年11月にChatGPTが公開されて、3月にAPIが公開されるまでは私を含め弊社でも関心を持ったり注目する人は増えていましたが、実際にプロダクトへ反映するまでは割と慎重になってしまったかなと思っています。様子見をしつつ、いいプロダクトへの組み込みはなんだろうな〜と考えることが多く、あまり手数を持てていませんでした。まさに「見(ケン)」の時期で手を組んで唸ってました。しかし歩みが遅いと言われていた EdTech 界隈でも想像の何倍ものスピードでさまざまなリリースが増えてきて、だいぶ危機感を持ったことと、技術顧問でもある広木さんからも支援をいただき弊社でもプロダクトへ早期に組み込むこととなりました。

プロダクトへの組み込み

xtech.nikkei.com

思い立ってから1ヶ月、社内外の協力を得て「レッスンAIアシスタントβ」のリリースを実施できました。弊社でしかできない・わかりやすい顧客課題・LLMだからできることを考えての最初のリリースでした。弊社の PROGOS と組み合わせて、レッスン中にレベルに合った学習の支援をする仕組みでした。 多くの方からフィードバックもいただき、APIをstreamで利用できてないことでレスポンスが遅くレッスン中というシチュエーションで使い勝手がまだまだ良くないことや、プロンプトの改善などリリースしてきて見えてきたことが本当に多かったです。 またそれだけでなく「LLMを使ったプロダクト開発」における注意しなければいけないことや、必要なこと、課題なども多く見えてきてその後の開発に活かせる知見を多く得られました。

社内向けのガイドライン・イントラ内にChatGPT

また社内での活用という観点でも、早期にガイドラインを策定し直接ChatGPTを触るのでは無く、統制やユースケースを計測するために社内に ChatGPTをラップしたシンプルなチャットアプリケーションを展開しました。社内でもアンケートを取り、活用におけるハードルや関心、課題を抽出しました。

マナビアップデートソン2023

rarejob-tech-dept.hatenablog.com

初のハッカソンをオフラインで開催し、ここでもLLMを活用した多くのアイデアやプロトタイプが生まれました。 私は学生の頃にさまざまなハッカソンに出てきたんで流石に楽勝かと思いましたが、各チームともめちゃくちゃいいアイデアが多くて結構接戦する結果となりました・・・! 各チームもそうですし、LLMをはじめ技術としても価値が高いものがスピード感を持って組み込める時代になったと感じました。

CTO室の立ち上げ

弊社ではグループでさまざまなプロダクトを運用しており、なかなか横断した支援や改善がしにくいところもありました。 今期はCTO室を立ち上げて、すでにあった弊社のEdTechLabチームと協業し、各チームの支援やR&Dを推進しました。

新プロダクトのローンチ

rarejob-tech.co.jp

K12領域(幼稚園1年と12年間の初等・中等教育を含めた13年間の教育期間)のユーザーに対して、覚えた単語でオリジナル絵本を作成し、親子で楽しむカスタマイズ絵本サービス「WordWiz」をリリースしました。ここはCEO、CIO主導で企画からリリースまでメンバーを巻き込みながら進めてくれていました。 CTO室としてもこのPJに参画してもらい実際に手を動かしてもらったり、ユーザーヒアリングなどを実施していきました。

社内での活用の促進

  • OpenAI APIのお試し用・検証用のapikeyの発行、取得手順公開
  • 社内向けのLLM利用ガイドラインの準備・公開
  • 社員向けのprivate LLMの準備(Amazon Bedrock)
  • 相談用のchannel作成、アイデア募集
  • working groupの発足
  • Github copilotの導入

etc...

とにかく今年は手数だなと思っていたので触れる機会を多く社内でも作りました。

Amazon Bedrock の活用

機会をいただき弊社でも Amazon Bedrock を活用したさまざま検証を進めた結果、re:invent にロゴを掲載いただくことができました。 (まさかの私のミスでレアジョブテクノロジーズで無くて、親会社のレアジョブロゴを渡してしまい、そっちが載ってます・・・なんて親孝行なんでしょうか(違う)) 勉強会もお誘いいただき弊社メンバーにも参加してもらい(様子もブログに書いてもらいました)、弊社でもこれを使ったサービス企画やプロトタイピングがはじまりました。

そして来年

この1年、LLMのもたらす怒涛のリリースにいい意味で焦燥感を得ながら考えていたことは「人とAIが共創して価値を作ること」だなと思いました。 もちろん人の仕事をAIが奪っていくようなことは増えていく一方で、あらためてAIだけでなく「人が何をなすべきか」が EdTech サービスを提供する弊社でも再定義が必要なことだと思いました。

真面目な記事になってしまったので、ここらで共創のトライとして締めのジョークはLLM君に任せてみようと思います。

・・・

スベッてますね、バナナだけに。

まだまだ価値の創出までは遠いですが、回り道をしながらでもトライの数を増やし続けたいと思います。 良いお年を、ウホウホ

Application Integrationを使ったSaaSからのBigQueryへのデータ取り込み

こんにちはデータエンジニアの杉光です。

今年6月くらいにGAとなりデータ界隈で一瞬話題となったApplication Integrationを試した感想について書きます。
実運用で使えないか試した結果、今回は見送ることにしました。その経緯を踏まえて機能と検証内容をお伝えできればと思います。

Application Integrationとは

cloud.google.com

日本語名ではアプリケーションの統合と表記され、Google CloudのIntegration Platform as a Service(iPasS)になります。
GUIからトリガー設定や様々なアプリケーション・データソースへの接続、データ変換などのワークフローをノーコード/ローコードで作成ができます。iPasSという言葉は馴染みがなかったですが、このような機能を含むことが多いようです。 AWSでいうところのStep FunctionsApp Flowを兼ね備えたものになるでしょうか。

全体イメージは公式のアーキテクチャ図を引用します https://cloud.google.com/static/application-integration/images/overview-diagram.png?hl=ja

主な機能

Integrationデザイナ

フローを直感的に作成可能なビジュアルエディタ。
できることが多いので一通り機能を把握しないと何から触れば良いかわかりません。チュートリアルが複数用意されているので、近いユースケースで慣れていくのをお勧めします。

トリガー

一連のタスクを開始するイベント。 APIトリガーやScheduleトリガー、Pub/Sub、Error Catcherなどがあります。

統合タスク

タスクは入力を受け取り、処理を行い、出力を行います。大きく分けて統合タスクとGoogle Cloudサービスタスクがあり、統合タスクはApplication Integrationが提供するタスクです。
JavaScript、Send Email、Restエンドポイント呼び出し、ループ、フローの呼び出し、後述で説明するデータマッピングやコネクタどがあります。

データマッピング
ソースデータとターゲットデータのスキーママッピングを担います。
JSONの複雑なデータ構造のフィールド抽出が可能でマッピング関数を使うと簡単にマッピングできます。 連携値を任意に定義したり、それらをフロー全体の変数としてとして利用することも可能です。

コネクタ
Google CloudのサービスやThirdPatyアプリケーション、データストアに接続することができる。厳密にはIntegration Connectorsと連携します。
プレビュー含めると50種類以上あり、他の統合ツールのコネクタと引けをとらない感じがあります。 cloud.google.com

料金に注意
GCP以外のコネクタは無料枠がなく接続ノードあたり $0.70/時間 掛かります。

Google Cloudサービスのタスク

他のGoogle CloudサービスやGoogle Workspaceと連携するタスクです。 Cloud Function、DataFlow、Vertex AI、App Script、スプレッドシート、ドライブなど様々なサービスに対応しています。

試した理由

少し話題になったからというのもそうですが、当データ基盤ではBigQueryを利用しており、Zoho CRM API から取得するデータをBigQuery上で扱う必要がありました。
REST APIからデータを取得するケースは今後他にも可能性があり、その度に実装するのも手間(メンテナンスも含めて)なので、リードタイムを短くしたいと思っていました。予算的にFivetranやtoroccoなどのデータ統合ツールに手を出せなかったのもあり、GCPと連携できる安価なものを検討しました。料金については上述の通り、外部サービスと連携するときには注意が必要です。

試した内容

以下のフローでZoho CRMからBigQueryへデータを取り込むパターンを試しました。

  1. Zoho CRM APIを実行してデータを取得する(レスポンスはJSON形式)
  2. レスポンスから必要なKeyを取得する
  3. JSON配列をNDJSONに変換する
  4. GCSへファイルアップロード
  5. GCSのファイルをBigQueryへロード

APIトリガーを起点として、RESTエンドポイント呼び出し、GCSのコネクタ、BigQueryのコネクタをデータマッピングタスクで繋ぎ、必要な項目を選択、変換しつつ取り込む流れになります。

全体フロー

1. Zoho CRM APIを実行してデータを取得

今回の検証ではQuery APIを利用しました。リクエストBodyにSQLを指定し、レスポンスBodyにデータが返されます。

認証情報はAuthentication Profile画面から作成します。
Zoho CRM APIの認証仕様に基づき、OAuth 2.0 client credentialsを選び設定します。

Task inputにEndpoint、HTTP methodやRequest bodyを設定します。

RESTエンドポイント呼び出しタスク

今回指定したQuery APIのリクエストbodyは以下になります。

{
    "select_query":"select Account_Name, Corporate_Number, Jurisdiction_Company from Accounts Where Jurisdiction_Company = 'レアジョブ' Limit 3"
}

2. レスポンスから必要なKeyを取得する

データマッピングタスクにてリクエストbodyから必要なデータ部分を取得します。
ここでは取得した値を"data"というフロー全体で使える統合変数に入れます。この時点で取得した値はJSONのArray型になっています。

データマッピングタスク

3. JSON配列をNDJSONに変換する

最終的にBigQueryがロードできるフォーマット(NEWLINE DELIMITED JSON)に変換します。データマッピングタスクでは変換ができなかったので、JavaScriptタスクを使います。

以下では"data"変数から取得した値を変換し、"ndjson"変数に入れています。

/**
 * Function that is called during the JavaScript Task execution.
 * @param {IntegrationEvent} event
 */
function executeScript(event) {
    const resp = event.getParameter('data');
    const ndJson = resp.map(JSON.stringify).join('\n');
    event.setParameter('ndjson',ndJson);
}

4. GCSへアップロード

Google Cloud Storageのコネクタタスクを使い、変換したデータをGCSバケットへアップロードします。

各コネクタでは幾つかのサービスのAPIに準じたアクションが用意されていますが、今回は UploadObject を使います。
パラメータの指定はコネクタタスク前段のデータマッピングで行います。3で設定した"ndjson"変数の値をContentへマッピングし、BucketやObectNameなどを適切な値に設定します。

GCS UploadObject Input

5. GCSのファイルをBigQueryへロード

最後にGCSバケットへアップロードしたファイルをBigQueryに取り込みます。
BigQueryのコネクタアクションは InsertLoadJob を使います。

前手順と同様にBigQueryのコネクタタスク前段のデータマッピングからINPUTの指定を行います。GCSのURIや取り込み先のテーブルなどの他にテーブル作成や更新方法のパラメータとして以下を設定しました。

Parameter Value
CreateDispositon CREATE_IF_NEEDED
WriteDisposition WRITE_TRUNCATE
AutoDetect true

テスト実行と結果

操作の詳細は割愛しますが、フロー画面上部の「TEST」ボタンから実行します。 実行結果はGCS、BigQueryの内容は以下のようになりました。

GCSオブジェクトの内容

{"Account_Name":"株式会社ABC","id":"3743557000003706168","Jurisdiction_Company":"レアジョブ","Corporate_Number":null}
{"Account_Name":"株式会社ABC02","id":"3743557000003706229","Jurisdiction_Company":"レアジョブ","Corporate_Number":null}
{"Account_Name":"株式会社DEF","id":"3743557000003706274","Jurisdiction_Company":"レアジョブ","Corporate_Number":null}

BigQueryテーブルの内容 スキーマの自動検出でロードしたので、JSON keyがカラム名になっていることが確認できます。

採用しなかった理由

今回の検証で使ったAPIはJSONを返しますが、実際に使いたかったのはZip形式のバイナリを返すBulk APIでした。大量件数のデータを取得するためのものなので、非同期の取得になります。
これに対して、RESTエンドポイント呼び出しタスクのOUTPUTはString型で受けてしまうため、文字化けが発生するのでマッチしませんでした。
また、ステータスをポーリングするフローを書くのがプログラムを書くより手間と感じていたのとZipファイルを解凍する処理を書く必要があり、CloudFunctionのタスクで実装すれば可能だが、そこまでするなら全て実装しても変わらないことが主な理由です。

良い点

実運用としては使わないものの良い点はいくつかありました。

RESTエンドポイント呼び出しタスク

下記の認証プロファイルと併せてノーコードツールとして一番便利と感じた部分です。任意のAPIを叩けるのは利用ケースが大きく広がりそうですし、AWS Step Functionsも追従してか最近同じような機能をリリースしています。
Call third-party APIs - AWS Step Functions

認証プロファイル

RESTエンドポイント呼び出しタスクやコネクタ接続時の認証情報をタスクとは別に設定でき、サポートする認証タイプが充実していると感じました。

データマッピング

GUIの恩恵を一番受けられたところ。マッピング関数が便利でした。

フローをJSONエクスポートできる

コードで管理可能になる。但し認証プロファイルの設定は出力されない。 ノーコードツールで作っても設定内容はコードで管理したいし、デプロイも自動化したいとなる思います。 Google公式でintergrationcliというtoolが公開されています。 github.com 複数環境で管理されることが前提とされ、環境変数や認証プロファイルの出力も考慮されているのでCI/CDで組み入れできそうです。

終わりに

Application Integrationにてフローを作成し、APIから取得したデータをBigQueryへ取り込むイメージを少しでも持って頂けたら幸いです。 Google Driveやスプレッドシートなども連携できるので、コーポレート業務の効率化にも活用できそうです。

We're hiring!
弊社では、特に データマネジメントプラットフォーム(DMP) グループでは、
一緒に働いてくださるデータエンジニアを大募集しています。
rarejob-tech.co.jp

マナビアップデートソン2023

はじめに

こんにちは!CEOの山田です。

11月8日、9日に全社合宿を行ない、そこで弊社ミッションに因んで名付けたハッカソン「マナビアップデートソン2023」を開催しました。 場所は「クロス・ウェーブ府中」さんにお世話になりました。宿泊可能な大規模な研修施設で、建物は綺麗で開放感もある造りで、宿泊した部屋も広くて眺めもよく、懇親会も施設内で開催でき、満足出来る施設でお勧めです。

目的

合宿でハッカソンを開催した目的は、チームビルディングとアイディアの掘り起こしです。

チームビルディング

弊社はリモート主体の勤務体制をとっており、プロジェクトベースで業務を推進しています。対面でのコミュニケーション機会は限られていますが、今回の合宿で長時間のグループワークや懇親会を通じて、組織の活性化と心理的安全性の高い環境を目指しました。

アイディアの掘り起こし

深くプロダクトに関わる人たちが持つアイディアを引き出し、それを具体化するためにハッカソンを設けました。チーム活動を通じてアイディアを洗練させ、実現可能なものへと発展させることが目標です。

開催概要

合宿前知見共有

合宿前には、業界動向や技術トレンドに関するプレゼンテーションを5人のメンバーに行ってもらいました。これは、当日をアイディア決定作業だけで終わらせないための準備です。5人の中には、お願いして親会社であるレアジョブの中村CEOにも発表して頂きました。中村さんだからこそ知っている内容が多く、盛り上がりました。

ハッカソン概要

  • 3もしくは4名1チーム
  • 普段関わらない人同士のメンバー構成
  • 制限は、EdTech領域であることのみで、英語学習でなくてもOK
  • 一日目は制作、二日目は発表(二日目は会議室が12時までだった)
  • 評価軸
    • インパクト(有用性、利便性)
    • ユニーク(独創性、先進性)
    • マーケット(市場性、実現性)
  • 評価方法
    • 全員の投票で、各チームの評価軸を5段階で採点
    • 3つの評価軸と総合点の最優秀賞を選出

結果

CTO率いるチームが最優秀賞と2つの評価軸で圧倒的な成績を収めました。 ただ、発表された作品は、想像以上にクオリティが高く、みな業務の合間で真摯に向き合って合宿に臨んだことがわかりました。 多くの作品は、次の企画に入ることになる可能性が高いので、成果については非公開になります。

感想

イベントでは予期せぬトラブルに直面することもあります。今回は、ランチのお弁当が足りないという問題が発生しました。この点については、数量の見落としでご迷惑をおかけし、申し訳ありませんでした。しかし、このトラブルを通じて、チームとしての対応力が高まったと感じますね(笑)。

このイベントは、リアルな交流と新たな学びを得る貴重な機会であり、非常に楽しいものでした。今後もこのような取り組みを続けていきたいと思います。

集合写真

We're hiring!
弊社では、一緒に働いてくださるエンジニアを募集しています。
rarejob-tech.co.jp

WordWiz - 子供の学習意欲を高める新しいサービス

こんにちは、ディズニーパークとドナルドダックをこよなく愛するCIOの岩堀です。今日は初の試みで行ったプロジェクトについてお話ししようと思います。それは、私たちの会社が初めて公募にて有志が集まってスタートしたプロジェクト「WordWiz」です。これは、K12領域において、子供たちが学んだ単語を使ってオリジナルの絵本を作成し、親子で楽しみながら学ぶことができるサービスです。

wordwiz.rarejob-tech.jp

サービス導入背景

K12市場は、まだまだ成長の余地があります。そこで、私たちは「WordWiz」を通じて、この市場に新しい風を吹き込むことを目指しました。このアイデアは、社内公募プロジェクトから生まれ、チームの情熱と創造性が詰まっています。ドナルドダックのように時にはちょっとドジながらも、常に前向きに挑戦する精神でこのプロジェクトに取り組みました。

技術的な挑戦

このプロジェクトでの、フロントではこれまでレアジョブでは使っていなかった技術を採用し、バックエンドではモダンな形でAWSを中心に構築しました。これらの技術を使いこなす過程で、私たちも大きく成長しました。

フロントエンド
  • Nuxt3 x Vue3
  • TailwindCSS x DaisyUI
  • Pinia
  • Bun
バックエンド
  • Go
AWS
  • ECS
  • ALB
  • CloudFront
  • Lambda
  • SQS
OpenAI
  • GPT-4
  • DALL-E3

サービス提供目的、狙い

WordWizは、K12領域の子供とその保護者を対象に、学習体験を豊かにすることを目指しています。子供たちが楽しみながら単語を学び、親子でオリジナルの絵本を作成することで、学習への興味を深めることができます。 私たちの目標は、学習をもっと楽しく、もっと身近なものにすることです。WordWizを通じて、子供たちが自分のペースで学び、親子で共有できる経験を提供することで、学習への新たなアプローチを提案し、応援したいと思っていただけるようなサービスになることを目指しています。

絵本イメージ

今後の展望

WordWizは現在、テストマーケティングの一環としてローンチし、ユーザーニーズを探っています。私たちは、ユーザーの声を大切にし、サービスの改善と進化を続けていきます。そして、これからもドナルドダックのように、時には失敗を恐れず、常に新しい挑戦を続けていきます。

このプロジェクトは、ただの仕事以上のものでした。私たちの情熱と、子供たちの笑顔を想像しながらの開発は、まさに魔法のような体験でした。WordWizを通じて、多くの家庭に新しい学びの形を届けられることを心から楽しみにしています。

We're hiring! 弊社では、一緒に働いてくださるエンジニアを募集しています。

rarejob-tech.co.jp

Amazon Bedrock Prototyping Campに参加してきました!(BedrockとKendraの簡易ハンズオン付き)

はじめに

SMART Method・PROGOS開発グループの奥山です。

京都に引っ越して3ヶ月経ったころ、友人が京都に来たと言うので坐禅に誘いました。

友人は「パートナーがこっちにできたからついでに会いに来た。パートナーと予定があるから坐禅は行かぬ。」と返事をくれました。

さて、私の心もこの頃の気温も急に冷え込んできましたが、生成系AI界隈は非常にアツいです。

そんな中、AWS Japan様から招待いただき、「Amazon Bedrock Prototyping Camp」に参加してきました!

以下、参加レポートとなります。

コンテンツ

  1. Amazon Bedrock Prototyping Campのコンテンツ概要
  2. Bedrock・Kendraのハンズオン付き説明
  3. 開発する際によかったリポジトリやドキュメント
  4. 感想

Amazon Bedrock Prototyping Campのコンテンツ概要

Amazon Bedrock Prototyping Campは

  1. 生成系AIをアプリケーションに組み込む際のビジネス的・エンジニア的な観点
  2. Bedrockの説明
  3. プロンプトエンジニアリングとRAGについて
  4. Bedrockハンズオン
  5. Kendraの説明
  6. Bedrock、Kendraを利用したプロトタイピング

を7時間でやるイベントでした。

Bedrock・Kendraのハンズオン付き説明

実際に受けた説明をもとに、BedrockやKendraの説明をしていきます。

Bedrock

特徴(+解釈)として

  • 主要な基盤モデルをサポート
  • 独自のデータで基盤モデルを非公開でカスタマイズできる
  • GDPRへの準拠やHIPAAの適格性などの標準への対応

があります。

SDKなどを通じてAPIコールすることで利用可能です。

Kendra

データ自体が構造化データ・非構造化データなのかを気にせず放り込めて、それを検索可能にするサービスです。

検索エンジンには機械学習を使っているとのことです。

コネクタが非常に強力で、GoogleDrive、Confluence、S3、RDSなどに対応しているだけでなく、手軽さもあります。こちらがデータ構造をやたら気にする必要なく様々なデータソースから取り入れられるというのが非常に魅力的です。

また、KendraはQueryAPIとRetrieveAPIがあります。

詳細な説明は公式ドキュメントに譲りますが、RetrieveAPIの方がより多く意味的に関連するドキュメントを取得してきます。QueryAPIもRetrieveAPIも意味的に関連するドキュメントを取得しますが、QueryAPIは1つのドキュメントから1つの抜粋なのに対して、RetrieveAPIは1つのドキュメントから関連性の高いものを複数抜粋できるところが特徴となります。

BedrockとKendraをどう組み合わせて使うか?

つまるところ、RAGが実装できます。

Prompt Engineering Guideから引用してみます。

RAG は入力を受け取り、ソース(例えばウィキペディア)が与えられた関連/証拠立てる文書の集合を検索します。文書は文脈として元の入力プロンプトと連結され、最終的な出力を生成するテキストジェネレータに供給されます。これにより RAG は、事実が時間とともに変化するような状況にも適応できます。LLM のパラメトリック知識は静的であるため、これは非常に有用です。RAG は言語モデルが再学習を回避することを可能にし、検索ベースの(文章)生成によって信頼性の高い出力を生成するための最新情報へのアクセスを可能にします。

質問などの入力を受けた際に、参照データを検索した結果を結合して、それをもとに回答を生成してもらう仕組み、という理解で行きます。

KendraにQueryやRetrieveのAPIを用いて取得したデータをBedrockに渡すプロンプトと合わせて質問することで、RAGを実現可能です。

弊社のブログだと、LangChain(OpenAPIのGPT3.5-turboモデル利用)とChromaDBでハンズオンの記事がそれっぽいことをやってたなと思います。

BedrockとKendraのハンズオン

東京リージョン(ap-northeast-1)にて、Bedrock・Kendra共に、AWSコンソールからセットアップし、実際に呼び出して動作するところまでを試してみます。

ぜひお手元で試してみてください!

Bedrockのセットアップ

AWSのBedrockコンソール「Model Access」をクリックします。

「Manage model access」をクリックし、モデルを利用できるようリクエストします。

これで完了です。

リージョンによって利用可能モデルが違うので、公式ドキュメントをご確認ください。

ハンズオン環境

イベントで利用したSageMakerのノートブックを紹介します。

つまるところ、「AWSのサービスを利用する際に利用する諸々の変数セットアップをすっ飛ばして利用可能なJupyterNotebook」です。

SageMakerのコンソールを開き、メニューバーから「ノートブックインスタンス」を選択します。

作成には少々時間がかかります。

作成されたら、メニューから作成したノートブックを選択して「アクセス許可と暗号化」を探します。

IAMロールでの設定を通じて、ノートブックにBedrockとKendraのロールを全許可で追加します。

イベント会場では、「インラインポリシーを作成」から実行しました。

JSON形式だと下記のようになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": [
                "bedrock:*",
                "kendra:*"
            ],
            "Resource": []
        }
    ]
}

検証ではこちらを貼り付けてご利用いただければと思います。

ただし、本番ではちゃんと制限をかけて運用する必要があるので、適宜ご変更ください。

Bedrockのコード

import boto3
import json

# bedrockクライアント初期化
# bedrock_client = boto3.client(service_name='bedrock')
bedrock_runtime_client = boto3.client(service_name='bedrock-runtime')

prompt = "日本で一番高い山はなんですか?"

body = json.dumps({
    "prompt": prompt,
    "max_tokens_to_sample": 300,
    "temperature": 0.1,
    "top_k": 250,
    "top_p": 1,
    "stop_sequences": ["\n\nHuman:"]
})
modelId = "anthropic.claude-instant-v1"  # change this to use a different version from the model provider
accept = "application/json"
contentType = "application/json"

# モデル呼び出し
response = bedrock_runtime_client.invoke_model(
    body=body, 
    modelId=modelId,
    accept=accept,
    contentType=contentType
)

response_body = json.loads(response.get('body').read())
print(response_body.get('completion'))


# LangChainパターン
from langchain.chat_models import BedrockChat
from langchain.schema import HumanMessage

llm = BedrockChat(
    client=bedrock_runtime_client,
    model_id="anthropic.claude-instant-v1",
    model_kwargs={
        "temperature":0.1,
        "max_tokens_to_sample": 1000},
)

result = llm([
    HumanMessage(content=prompt)
])

print(result.content)

Bedrock利用する際に重要なこと

端的に言うと、「プロンプトをしっかり検証する。そのためにプロンプトエンジニアリングを把握する。」です。(とはいえ、これはLLM全般を利用する際に言えることだと思います。)

当日配布されたコードをそのまま貼り付けておくので、是非お手元で改善されていく様を観察してみてください。

比較が楽になるよう、メソッドを定義します。

def invoke_claude(text, max_tokens_to_sample=1000): 

    body = json.dumps({
        "prompt": f"\n\nHuman:{text}\n\nAssistant: ",
        "max_tokens_to_sample": max_tokens_to_sample,
        "temperature": 0.1,
        "top_p": 0.9,
    })

    modelId = 'anthropic.claude-instant-v1'
    accept = 'application/json'
    contentType = 'application/json'

    response = bedrock_runtime.invoke_model(body=body, modelId=modelId, accept=accept, contentType=contentType)

    response_body = json.loads(response.get('body').read())

    return response_body.get('completion')[1:]

初期プロンプト

prompt_template = """
以下のようなシステムのアーキテクチャを考えてください。  
システム概要: {about}
システム規模: {scale}  
機能: {features}
"""

prompt = prompt_template.format(
    about="衣料品を販売するECサイト", 
    scale="ピーク時には毎分10000リクエストに対応できる必要があります。また、グローバルに利用可能である必要があります。また、応答性が高く高速である必要があります。", 
    features="""次の3つのページを含んでいる必要があります。
    1.製品について解説したランディングページ。 2. 会社概要を説明するページ 3. 採用情報ページ
    """
)

print('Prompt:', prompt)
print('Output:', invoke_claude(prompt))

改善1回目のプロンプト:ロールを与えている

prompt_template = """
あなたは熟達したシステムアーキテクトです。初心者にとっても専門用語を噛み砕いて分かりやすい説明をすることで有名です。
以下のようなシステムのアーキテクチャを考えてください。 
システム概要: {about}
システム規模: {scale}  
機能: {features}
"""

prompt = prompt_template.format(
    about="衣料品を販売するECサイト", 
    scale="ピーク時には毎分10000リクエストに対応できる必要があります。また、グローバルに利用可能である必要があります。また、応答性が高く高速である必要があります。", 
    features="""次の3つのページを含んでいる必要があります。
    1.製品について解説したランディングページ。 2. 会社概要を説明するページ 3. 採用情報ページ
    """
)

print('Prompt:', prompt)
print('Output:', invoke_claude(prompt))

改善2回目のプロンプト:タグを利用し、プロンプトを構造化する

prompt_template = """
<Instruction>
あなたは熟達したシステムアーキテクトです。初心者にとっても専門用語を噛み砕いて分かりやすい説明をすることで有名です。
システムの概要、規模、機能の情報をもとにお客様の要求を分析し、セキュリティ・パフォーマンス・運用性・信用性・コスト最適といった観点でアーキテクチャを考案してください。
また、高校生にもわかるように、専門用語を噛み砕いて説明してください。
</Instruction> 
<Requirements>
    <About>
        {about}
    </About>
    <Scale>
        {scale}
    </Scale>
    <Feature>
        {features}
    </Feature>
</Requirements>
"""

prompt = prompt_template.format(
    about="ECサイトのためのウェブサイト", 
    scale="ピーク時には毎秒10000リクエストに対応できる必要があります。また、グローバルに利用可能である必要があります。また、応答性が高く高速である必要があります。", 
    features="""次の3つのページを含んでいる必要があります。
    1.製品について解説したランディングページ。 2. 会社概要を説明するページ 3. 採用情報ページ
    """
)

print('Prompt:', prompt)
print('Output:', invoke_claude(prompt))

Kendraのハンズオン

Kendra自体のセットアップやコネクター自体は、コンソールで直感的に操作できるので、注意点だけにとどめます。

Kendraのセットアップ手順はざっくりと

  1. Indexの作成
  2. Indexにコネクターを通じてデータを投入する

です。

QueryやRetrieveのAPIを利用する際、利用する言語をデータ投入時の言語に合わせないと取得が0件になりました。

弊社はデータをjaで入れましたが、QueryAPIは言語指定しない場合、enで取得する仕様です。

そのため、当初SDK経由で利用していたとき、言語設定をjaにしていないことが原因で、取得が0件のケースに遭遇しました。

データ投入の際の言語設定は、下記写真の画面からできます。ご注意ください。

下記は、イベント当日、弊社がプロトタイピングする際に利用したコードになります。

弊社は当日、自社のConfluenceのデータを用いるため、jaでデータを入れました。

KendraのIndexIDが必要なので、対象のIndexを選択して、Index Settingsの項目から探してください。

import os
from typing import Dict, Literal

import boto3

kendra_client = boto3.client("kendra", region_name='ap-northeast-1')

indexId = 'KendraのIndexIDを入れてください'

kwargs = f"""{question}"""

response = kendra_client.query(
    IndexId=indexId,
    QueryText=kwargs,
    AttributeFilter={
        'AndAllFilters': [
            {"EqualsTo":{"Key":"_language_code","Value":{"StringValue":"ja"}}}
        ]
    },
    PageNumber=1,
    PageSize=20,
    DocumentRelevanceOverrideConfigurations=[
        {
            'Name': 'string',
            'Relevance': {
                'RankOrder': 'DESCENDING'
            }
        },
    ],
)

# print(response)
# print(response['ResultItems'])

for result in response['ResultItems']:
    print(result['DocumentId'])
    print(result['DocumentTitle'])
    print(result['DocumentExcerpt']['Text'])
    print(result['DocumentURI'])
    print(result['DocumentAttributes'])
    print(result['ScoreAttributes'])
    print(result['DocumentTitle'])

Kendraにリクエストする箇所のコードに注目します。

response = kendra_client.query(
    IndexId=indexId,
    QueryText=kwargs,
    AttributeFilter={
        'AndAllFilters': [
            {"EqualsTo":{"Key":"_language_code","Value":{"StringValue":"ja"}}}
        ]
    },
    PageNumber=1,
    PageSize=20,
    DocumentRelevanceOverrideConfigurations=[
        {
            'Name': 'string',
            'Relevance': {
                'RankOrder': 'DESCENDING'
            }
        },
    ],
)

特に

AttributeFilter={
        'AndAllFilters': [
            {"EqualsTo":{"Key":"_language_code","Value":{"StringValue":"ja"}}}
        ]
    },

の部分は、「Kendraのデータを日本語で検索する」場合必要となります。

以上、ハンズオンでした。

開発する際によかったリポジトリやドキュメント

Bedrock

正直なところ、Bedrockについてはプロトタイピングする際に困ったことが特にありませんでした。(と言うのも渡されたサンプルが充実してたので・・・)

公式のGithubリポジトリでよくまとまっているのはこちらかと思います。

github.com

Kendra

2つの公式ドキュメントが役立ちます。

1つ目はKendraの該当するAPIのドキュメントです。

2つ目はSDK for Python自体のKendra部分のドキュメントです。

1つ目でKendraのQueryAPIのリクエスト構造を把握した上で、2つ目でどうSDKに落とし込むかを把握できます。

そのほか有用なGithubリポジトリ

AWSは公式のGithubリポジトリを有してます。

実際に紹介されたものをいくつか載せます。

https://github.com/aws-samples/generative-ai-use-cases-jp

https://github.com/aws-samples/bedrock-claude-chat

https://github.com/aws-samples/simple-lex-kendra-jp

イベント終了後に読んでから気付いたのですが、スライドの一番後ろにあったこちらのWorkshopも非常に良いです。(KendraをSDK for Pythonで利用する際のサンプルコードも乗ってます。)

catalog.us-east-1.prod.workshops.aws

感想

イベントに参加したことで、細かいテクニックから自社サービスの見方、開発する際のマインドセットに至るまで、さまざまな気づきを得られました。

個人的に、LLM導入の肝はプロンプトエンジニアリングである、と気づけたのは非常に大きかったです。(今後のLLMの発展でこの見解が覆ることもあるかもしれませんが。)

同時に、プロダクト価値の向上に資する開発とは何か?に対する手の動かし方の見識を広める入り口に立てた気がして、気分が非常に高揚しました。

手を動かして必死に導入しようと考える作業をもっとやりたいなあと思いました。

最後に

We're hiring!
弊社では、一緒に働いてくださるエンジニアを募集しています。
rarejob-tech.co.jp

「少人数エンジニア組織でサービス成長させるには?座談会」 に登壇しました

はじめに

こんにちは、 DevOps グループの中島です。
AWS 社主催のイベントでつながったココナラ社の方よりお誘いがあり、勉強会を共同主催しました。 今回はその登壇レポートになります。

ココナラ テックブログでも執筆いただきました。
「ココナラ×レアジョブテクノロジーズ+AWS 少人数エンジニア組織でサービス成長させるには?座談会」を開催しました!

connpass リンク: ココナラ×レアジョブテクノロジーズ+AWS 少人数エンジニア組織でサービス成長させるには?座談会

内容

以下のテーマについて、それぞれレアテク社、ココナラ社で交互に LT する形式で行われました。 (言葉の選び方が上手だなあと感じます)

  • 少人数でもサービスを安定運用?超具体How to+やっぱり辛いこと
  • 技術負債って正直どうする?限界と現実、究極天秤の実情
  • 少人数の成長組織で戦い抜く秘訣

各 LT の内容は以下のとおりです。

★少人数でリスタート! DevOps チームの工夫と実践 (株式会社レアジョブテクノロジーズ 中島)

私からは少人数チームにおけるミッションの策定、稼働の削減、タスクの選定方法についてお話させていただきました。

★少人数で複数サービス運用するための日々の取り組み (株式会社ココナラ 吉川さん)

ココナラの吉川さんからは、AWS インフラ運用にまつわる具体的な取り組みについて発表がありました。
Terraform の plan 結果が自動でプルリクに貼り付けられる仕組みは参考になりました。 当社では AWS CDK を利用しているので、cdk diff の結果を貼り付けるのをやってみようと思います。

★大きく返す技術負債 システムリプレイスとその後のはなし (株式会社レアジョブテクノロジーズ 鈴木)

当社の鈴木からは、大規模リプレイスを行った際の進め方やそこで学んだ知見について発表させていただきました。

★スロークエリ撲滅委員会 (株式会社ココナラ 橋本さん)

ココナラの橋本さんからは、パフォーマンス委員会を設けてスロークエリに対処した具体的な方法について発表がありました。
Active Record を使っている場合に、遅い SQL から対象のコードを特定するのに苦労するのはどこでも共通の課題があるなと感じます。

★少人数チームで行う機械学習モデルの保守と新規R&D (株式会社レアジョブテクノロジーズ 齋藤)

当社の齋藤からは、機械学習モデルが増え続け運用が複雑になっていく中で、どのように少人数で対応しているかについて発表させていただきました。

★品質向上のためのモニタリング改善 X-Ray導入物語 (株式会社ココナラ 光吉さん)

ココナラの光吉さんからは、OpenTelemetry Ruby with AWS X-Ray の導入時に工夫した内容について発表がありました。
OTEL の SDK にモンキーパッチを当てて、足りない機能を追加してしまうところに高いエンジニアリング力を感じます。

★GenerativeAIを活用した開発生産性向上 (アマゾン ウェブ サービス ジャパン合同会社 大磯さん)

最後に AWS 社の大磯さんから Generative AI 関連 AWS サービスの紹介がありました。
CodeWhisperer がコードの diff を見てプルリクにコメントするデモをされていて、 こういった定形な文書作成の半自動化ができるとだいぶ楽ができるなと思います。

最後に登壇者で集合写真を一枚。

感想

コロナ禍からのリモートワークの流れもあり、久々に勉強会にリアル参加しました。
登壇者との交流は、ブログ記事を読むだけでは分からない生の情報が得られ、大変良い刺激を受けることができました。 ココナラの登壇者さんは魅力的なエンジニアの方ばかりで、機会があればまた技術的な話で親交を深めたいですね。
今後も定期的にこういったイベントに参加していきたいと思います。

We're hiring!
弊社では、一緒に働いてくださるエンジニアを募集しています。
rarejob-tech.co.jp

PHPカンファレンス2023 でブース出展してきました

こんにちは。レアジョブ英会話開発グループの鈴木です。

前回の投稿でお知らせしていたとおり、10/8 (日) に開催されましたPHPカンファレンス2023にてブース出展をしました。
当日は多くの方にお越しいただきカンファレンス運営スタッフ、スポンサーブースの皆さまお疲れさまでした。そしてご来場された皆さまありがとうございました。

今回はノベルティとしてステッカー、チョコ、書籍、不織布バッグを用意しました。 不織布バッグは他企業ブースのスタッフの方にも好評をいただきました。

好評だった弊社ロゴ入りバッグ

弊社は2018年にもブース出展しており、そのときは英語に関する質問をさせていただきました。
コロナ禍を経て皆さまの英語との関わりにどのような変化があったかを可視化できたらなと思い、今回も英語に関する質問をさせていただきました。

2023年の質問結果

前回と同じ「仕事で英語を使う?」という質問を設けました。ここでは「英語のドキュメントを読むこと」も YES に含めて回答していただきました。
前回同様に YES と回答される方が多い質問ではあるのですが、「話す」「書く」で利用する方は比較的少なく、「読み」での利用時はChatGPTを利用して翻訳しているという方が多かったです。

AIが多くの作業を肩代わりしてくれる時代に、英語を習得することだけが目標ではなく、学習者がマナビを通じて得た能力や経験によって、グローバルに活躍できることの意味を再考する機会となりました。

それ以外にも CEFR の認知度やレアジョブ英会話の利用経験に関して来年はもっと YES をもらえるよう、蓄積されたデータとAIの技術を駆使して、より充実した学習体験をこれからも提供していきます。
そして引き続きPHPコミュニティへの貢献も継続していきます💪

We're hiring!
私たちと一緒に「マナビ、アップデート」してくれるエンジニアを大募集しています。
rarejob-tech.co.jp