![見出し画像](https://assets.st-note.com/production/uploads/images/165192172/rectangle_large_type_2_28d2d456b0f2aecb7131a25f59a7f643.png?width=1200)
人事が Streamlit in Snowflake で生成AIアプリケーションを社内向けに作った話
この記事は、LayerX Tech Advent Calendar 2024 の 14日目の記事です。
はじめに
こんにちは、すべての経済活動をデジタル化したい LayerX の宮本 (@juny1031) です。
LayerXでは人事として、バクラクという SaaS の開発組織の HRBP グループと、全社の採用企画・Ops グループの2つのグループのマネージャーをしています。
私はキャリアの中でソフトウェアエンジニアの経験こそありませんが、コードを書き、動くものを作ることを非常に大切にしています。
それは、開発組織の HR を担うにあたり、当社の行動指針である Bet Technology、すなわち長期的に技術を信じ、技術に賭ける選択をすることや、羅針盤の中の「技術をまず試す」を HR 自らが体現すべきであると考えているからです。
あと、動くものができると、単純に面白いし楽しいですからね。
これまでも例えば LayerX OpenDoor というカジュアル面談プラットフォームを作ったり、
ベンチマークしている他社の採用情報のアップデートをクロールして Slack に通知されるようにしたり、
当社では「息を吸うように」他社から学ぶのですが、たとえば採用。事業や採用におけるcompetitorの採用情報にアップデート(ポジション公開/クローズ)があればSlackに通知されるようになっている。ベッテク。採用ポジションの変化に、事業の変化が現れる。https://t.co/kERfXRuk80
— 石黒 卓弥|Takaya Ishiguro (@takaya_i) February 8, 2023
YOUTRUST の転職意欲変更通知に対して、emoji をつけると自動的に採用管理システム から過去に接触履歴がないかを確認して候補者体験を毀損しないようにしたり、
![](https://assets.st-note.com/img/1733142688-3f7REtPlHZgNQxrSAcG4Uo8F.png?width=1200)
などなど、主に GASやPython、Zapier を組み合わせて、手を動かしてきました。
本記事では、最新作として生成 AI を活用したスカウト文生成アプリケーションを Streamlit in Snowflake で実装した話をします。
最終的に画面としてはこのようなものができました。
![](https://assets.st-note.com/img/1733712341-FQg8uUhXHnRIlqYTc5b3GkfN.png?width=1200)
(過去在籍企業に意図せず迷惑かけないように一部マスクしています。)
Streamlit in Snowflake とは
Streamlit とは、Python を使って簡単にアプリケーションを組めるツールです。以下の画像に書いているような数行のコードで Web からアクセスできるアプリケーションを作成することができます。
![](https://assets.st-note.com/img/1733229490-apjAgikR7XShU56HZMwVCN9L.png?width=1200)
そして、この Streamlit を Snowflake が買収・ネイティブ統合しており、現在は Snowflake 上で Streamlit を簡単に使うことができます。
つまり、Snowflake 上の IDE に Python のコードを書くだけで、Streamlit アプリケーションを立ち上げることができます。
私のような非エンジニアにとって、複雑な環境構築やデプロイが不要で、サクッと動くものを作って共有ができるのは、とても便利な機能です。
なお、当社では BigQuery から Snowflake への移行を進めており、こちらの記事やスライドもぜひご覧いただけると嬉しいです。
スカウト文生成アプリケーションを設計する
本題です。
当社のリクルーターは日々各採用媒体で候補者を見ながら、スカウトメッセージを心を込めて作っています。一方で、丁寧に作り込めば作り込むほどに時間を要す作業であり、なるべく魅力的な文章を素早く作ることができると良いな、と常日頃から感じていました。
また、人の目では見落としてしまうような候補者の方の魅力や、当社の採用ポジションとのマッチングに対して、生成 AI を活用することで候補者一人ひとりへのより深い理解を促進し、質の高いコミュニケーションを実現することができるのではないかと考えました。
もちろん、GPTs や他社のスカウト文生成サービスを利用することで同じようなことはすぐにできます。しかし、スカウト文を生成するにあたり、求人票などに定義された人材要件を都度読み込ませる準備をしたり、求人票ごとにプロンプトを含む初期セットアップしたり、メンテしたり、といった工数が発生することになります。
当社は採用管理システムに Talentio を採用しており、API によって求人情報を取得できることから、これらの作業が効率化できると考え、スカウト文生成アプリケーションを内製してみることにしました。
アプリケーションのシーケンス図としては以下です。
![](https://assets.st-note.com/img/1733713361-szZ9mQDbWBOHvr0ySjUuelYT.png?width=1200)
大きく分けると、
・求人情報をインプットする
・候補者情報をインプットする
・LLM に上記2点を読み込ませてマッチングの文章を生成する
という3つの step で構成します。
なお、求職者情報のインプットについては、以下の通りプライバシー保護に配慮して利用しています。
・求職者情報は職務経歴や活動情報など、採用媒体上のプロフィールとして公開されているかつ個人情報に当たらない項目をインプットすること
・LLM は 当社が法人契約している OpenAI のAPI を介して利用することで、モデルの改善には使われないこと
Streamlit in Snowflake で実装する
まず、Snowflake の Projects から、Stramlit Apps を新規作成すると、以下のような画面がデフォルトで表示されます。
![](https://assets.st-note.com/img/1733726924-CutFp310UGx79bPBKmqOY5kI.png?width=1200)
このように、左半分に表示されるエディタでコードを書くと、右半分に実際の画面が表示されるようになっています。
header や bar_chart、dataframe など、HTML や CSS がわからなくても、簡単な記述でサクッと画面が作れるので、非常に便利です。
関数を実装する
まずはメイン処理で使う関数を実装します。Talentio の API へリクエストを送るコードのサンプルは以下になります。
import streamlit as st
import _snowflake
from snowflake.snowpark.functions import sproc
from snowflake import snowpark
# TalentioからJD一覧のマスタを取ってくる関数
@sproc(
packages=["snowflake-snowpark-python", "requests"],
secrets={"api_key": "example_db.snowflake_secrets.system.secrets.talentio_api_access_token"}, # Talentio API Access Token を格納したSnowflake Secret
replace=True,
external_access_integrations=["TALENTIO_API"],
)
def get_talentio_jd(session: snowpark.Session) -> list:
import requests
token = _snowflake.get_generic_secret_string("api_key")
'''
実際のコード部分
'''
return
特徴としては、関数の上にストアドプロシージャを記述し、secrets から APIキーを定義します。定義した APIキーは、実際の関数の中で、_snowflake.get_generic_secret_string() から呼び出します。
なお、Talentio の API は候補者の個人情報や、選考・評価情報も取得できてしまうため、API を呼び出すことのできる人は人事に絞る必要があります。
この課題に対しては、当社のデータエンジニアであり Snowflake Squad(Snowflakeチョットデキル人のこと) でもある @civitaspo さんがいい感じに権限を分けてくれたおかげで、特定のロールからしか API を呼び出すことができない仕組みを実現してくれました。
セキュリティ周りも安全かつ簡単に実装することができるという点で、とてもありがたかったです。
また、今回スカウト文の生成は OpenAI の API を利用したので、こちらも以下のようなコードで実装します。
def generate_message(session: snowpark.Session, messages: list) -> str:
import requests
from openai import OpenAI
api_key = _snowflake.get_generic_secret_string("api_key")
client = OpenAI(api_key = api_key)
completion = client.chat.completions.create(
model="gpt-4o",
messages=messages,
)
return completion.choices[0].message.content
画面を実装する
サイドバーから実装していきました。
# 職種マスタのプルダウンを作成
job_list = ast.literal_eval(get_talentio_jd())
categories = sorted(set(item[1] for item in job_list), key=custom_sort_key)
categories.insert(0, "")
choice_category = st.sidebar.selectbox('職種マスタを選択してください', categories)
# 選択した職種マスタから、紐づく求人タイトル一覧のプルダウンを作成
filterd_list = [item for item in job_list if item[1] == choice_category]
jd_list = [item[0] for item in filterd_list]
jd_list.insert(0, "")
choice_title = st.sidebar.selectbox('求人タイトルを選択してください', jd_list)
# 候補者情報を入力するテキストエリアを作成
resume = st.sidebar.text_area('候補者の職務経歴等をコピー&ペーストして、⌘+Enter を押してください', '')
これで、以下のようにサイドバーに入力項目を実装することができます。
![](https://assets.st-note.com/img/1733730615-jbA7UnmY0tiSpv1gMsDz65EH.png?width=1200)
ちなみに、Streamlit in Snowflake の少し使いにくい特徴として、input などのユーザーアクションが発生するたびに、上から下までコードが実行されるという仕様があります。
そのため、プルダウンによって取得したデータを元に次のプルダウンの選択肢を動的に変更するなどの処理も、都度バックエンドで全ての処理が動くのを数秒待つ必要がありました。また、本来フロントで保持したい情報もリセットされてしまうため、開発者としてもユーザーとしても個人的にはかなり微妙な体験で、今後改善を期待するポイントです。
(調べてみると一部キャッシュ機能が使えるようなので、今後高速化を期待して使う可能性はあります)
最後に LLM を活用してスカウト文を生成する処理を実装します。
# 求人タイトルと候補者情報が入力されている場合に、スカウト文を生成する
if choice_title != '' and resume != '':
with st.spinner('スカウト文を生成しています…'):
target_job_id = next((item[2] for item in job_list if item[0] == choice_title), None)
job_detail = get_talentio_job_detail(target_job_id)
match_prompt = [
'''
プロンプトを設定
'''
]
match_message = generate_message(match_prompt)
scout_prompt = match_prompt + [
'''
プロンプトを設定
'''
]
match_summary = generate_message(scout_prompt)
st.write(match_summary.replace("\n\n", "\n"))
st.write(match_message)
st.spinner() で処理中の待機時間にぐるぐるマークを表示させられるなども使い勝手がよくて嬉しいポイントです。最終的には以下のようにスカウト文が生成されます。
![](https://assets.st-note.com/img/1733731307-dp6VlyazmHZn3IcfGubB9DCr.png?width=1200)
(過去在籍企業に意図せず迷惑かけないように一部マスクしています。)
プロンプトとしては、求人票に定められた人材要件と候補者情報を照らし合わせて、「候補者の特徴」と「当社とのマッチ度が高い点」を根拠付きで生成し、それらを要約してスカウトメッセージを生成するという手順にしています。
あえてプロンプトを組み上げて完璧なスカウト文章としてのアウトプットにしていません。
このスカウト文生成アプリケーションは、リクルーターが候補者の経歴や特性を深く理解し、その魅力を最大限引き出すメッセージを作成するための補助ツールです。単にスカウト文作成の時間を効率化するということではなく、より良い候補者体験を生み出すためのコミュニケーションの手がかりとしての活用を目指しています。
まとめ
私は普段業務効率化のためにコードを書くことがほとんどなので、モダンなフロントエンドのフレームワークのことは全くわかりません。ですが、Streamlit in Snowflake であれば、少しでも Python を書くことができれば、誰でもすぐに何らか動くものが作れて社内で共有することができ、フィードバックをもらうことができます。
LayerXでは、爆速開発を掲げており、「動くモノ」を非常に大切にしています。私がこのアプリケーションを作ってエンジニア向けにデモをした時も、みなさん口を揃えて「動けばなんでもオッケー」とポジティブなリアクションをしていただき、とても嬉しかったです。
そして人事の私以外にも、例えばプロダクトマネージャーのメンバーが Streamlit 上で業務効率アプリケーションを実装しています。
ぜひ、Snowflake を導入されている企業にいらっしゃる非エンジニアの方も、一度触ってみてはいかがでしょうか。おすすめです!