🙆

生成AIで個社対応を減らそう!データフォーマットのGemini2.5活用事例

に公開

カンリーでは、生成AIを使った取り組みを各プロジェクトで実施しています。
そこで今日は私のチームで発生していた『データの整形』という名の沼を脱するまでの話を書きます。

HRエンジニア部では様々な求人票をお客様からお預かりしてそれを運用することがあります。
カスタマーサポートのメンバーから「このデータ形式って対応できますか....?」など
弊社サービスの導入に差し当たりこういったご相談は多々いただきます。

大変失礼な話ではあるのですが、私としては
「なんでこんなにフォーマットがバラバラなんだよ!!」
と頭を抱えていました。

別のフォーマットが来るたびにそれを取り込む暫定的なスクリプトが生まれる日々にもうせいせいしてきたのです。

生成AIを使えばいちいち暫定的なスクリプトを組まずとも解決できたのでそれを共有しようと思います。

求人票という名の混沌地獄

みなさんは求人票のフォーマットの多様さを知っていますか?

あるクライアントはWordファイルで送ってくる、別のクライアントはPDFだったりGoogle Spreadsheetだったり...。

そして最悪なのが「とりあえずメール本文に書いておきました〜」というアレです。

まるで修学旅行の班分けでにぎやかに騒いでいる小学生のように、データは好き勝手な場所で好き勝手な形で踊り狂っています。

初めて見た時は「正規表現で何とかなるさ〜」と思っていたんですよね。

結論これが甘かった...。

正規表現の複雑さが増すたび、バグの温床も肥沃になっていきました。
どこで何をどう捕捉すればいいのか、
何パターンの正規表現を用意すれば全部網羅できるのか...。

はい。不毛ですね。

そもそも正規表現なんか使うのやめましょう!

今やAIがあるじゃないですか!
ということでAIに社畜させましょう。

LLMにインポート処理を託す時代

とにかく。
まずはやってみろということで「このデータをJSON形式に直して」という単純なプロンプトで生成させてみました。

結果はご想像のとおり惨憺たるものでした...。

{
  "position": "エンジニア",
  "company": "株式会社ABC",
  "skills": "Python, JavaScript, AWS"
  // ここで生成が途切れる...
}

AIさんはいつでもよしなに生成します。
JSONでお願いとだけ伝えると、Keyをよしなに当て込んできます。

2、3個生成させるとそのJSONの構造体はそれぞれ全く別物で生成します。
この状態では全くと言って良いほど使い物にはなりません。

しかもクライアントAでは「必須スキル」、クライアントBでは「求めるスキル」、クライアントCでは単に「スキル」と記載されていると、AIはそれぞれ別物として理解してしまうんですよね。

これは「名寄せ」という問題です。
人間だと「あ、これはどれも同じことを言ってるな」とわかりますが、AIさんにそこまで求めるのは酷というものでした。

スキーマのデータを渡そう

先ほど

2、3個生成させるとそのJSONの構造体はそれぞれ全く別物で生成します。

と書きました。これを解決するにはどうしたらいいでしょうか?

答えは簡単で、生成して欲しいスキーマを渡しちゃえばいいのです!
私が担当しているプロダクトではPrismaを採用しているので、このモデルをコピペして渡しています。

// Prismaスキーマの例
model JobPost {
  id          Int      @id @default(autoincrement())
  title       String
  company     String
  location    String?
  salary      String?
  requiredSkills String[]
  description String
  contactEmail String?
  postedAt    DateTime @default(now())
}

こういったスキーマをプロンプトに含めると、AIは「ああ、出力はこの形に合わせればいいんだな」と理解します。

PrismaだけでなくYAMLスキーマや、Zodなどのバリデーションスキーマもとても効果的ですね。
Zodなんかは生成してもらった成果物をそのままバリデーションにかけれるのでそのシームレスに対応できる感じ結構いいですよ。

名寄せをTextEmbeddingで実装しよう

つづいて名寄せですが、例えば求人票の職種を推論させる場合について皆さんはどうしますか?
ざっくばらんに推論させますと、こちらもバラバラかつ複数の表現で同じような職種を生成してきます。
無法地帯です。

これも先ほどと同じように大量の職種名のリストを含める・・・
みたいなアプローチをとるとどうなるでしょうか?

世の中には約2万職種あると言われているのですがそれらをコンテキストに入れると膨大のInput量となるため、ほとんどのAIモデルはエラーになります。
しかもInputが長くなるほど料金が高くなるし、職種のリストなんて持っていないです。

なので私たちは何もコンテキストに渡さずに職種を生成してもらうことにしました。
しかしこのままだと名寄せは解決していません。

そこで生成してもらった職種名をTextEmbeddingしてベクター化した文字列をDBに保存することにしました。
また保存する前にDBに保存済みのデータをベクター検索をすることで近しい意味合いを持つデータを取得できるので、そちらに差し替えるようにしてあげることで名寄せが完成!というわけです。

こうすることで、フォーマットの正確さは99%(私調べ)まで向上したのです。

長いコンテキストに対応できるモデルを選ぶ

ほとんどの人がOpenAIのAPIを使ってるんじゃないでしょうか?

確かに安定してますが、お高いですよね...しかも生成が遅い...。

我々株式会社カンリーではOpenRouterを使っています。
400以上のモデルから選べるので、用途やコストに応じて最適なモデルを選択できるんです。

特におすすめしたいのがGemini 2.5 Flashです。

その最大の特徴はインプット・アウトプットともにコンテキストサイズが長いこと!

以前4o-miniやGemini 2.0を使っていた時、JSONの生成が途中で切れてしまうことがありました。そうなると泣く泣く手作業...。

{
  "jobTitle": "フルスタックエンジニア",
  "company": "テックイノベーション株式会社",
  "requiredSkills": [
    "JavaScript",
    "TypeScript",
    "React",
    "Node.js"
  ],
  "preferredSkills": [
    "AWS",
    "Docker",
    "CI/CD"
  ],
  "salary": "600万円〜900万円",
  "location": "東京都渋谷区",
  "workingHours": "フレックスタイム制(コアタイム 11:00-15:00)",
  "benefits": [
    "リモートワーク可(週3日まで)",
    "書籍購入支援",
    "カンファレンス参加費用支援",
    // ここで切れる...

こんな悲劇を防ぐには、ThinkingModelを使うのも効果的です。

AIに「考える時間」を与えることで、生成途中で切れるリスクが減ります。

それでも失敗するときは失敗します...。

そこで私たちカンリーではzodなどのバリデーションを活用しています。

import { z } from 'zod';

const JobPostingSchema = z.object({
  jobTitle: z.string(),
  company: z.string(),
  requiredSkills: z.array(z.string()),
  // ... 他のフィールド
});

バリデーションで失敗した箇所を特定し、AIに「ここが間違ってるよ」と教えてあげると、AIは修正してくれます。親切ですよね。

それでも長すぎるデータは複数のインスタンスに分割して生成し、最後にマージするという荒業も効果的です。

カンリーでは大量の求人データを処理する際、この方法で99%以上の変換成功率を達成しています。

AIの生成ログはきちんと残そう

エンジニアなら分かると思いますが、「バグが起きたときに再現できない」というのは地獄です。

AIのインプットとアウトプットもきちんとログに残しておきましょう。

個人的にはLangSmithがおすすめです。

簡単に導入でき、リクエストとレスポンスをきれいな形で記録してくれます。

株式会社カンリーでも全てのAI関連処理にLangSmithを導入し、問題発生時のトラブルシューティングが格段に楽になりました。

最近は大量のレスポンスをモニタリングして、AIの精度改善にも活用しています。

これにより、スキーマの最適化や誤変換パターンの発見など、継続的な改善サイクルを回せるようになりました。

自戒と反省

最後に、AIも万能ではないということを忘れないで欲しいということを強く皆さんにお伝えをしようと思います。

データの不足やコンテキストサイズの限界を超えるデータは、どんなに面倒でも人間が整理した方が早いこともあります。この判別は前処理の観点から重要です。

AIに作業をさせるにはどのような場合でもお膳立てが重要です。

そして何より大事なのが、エラーログをとることと、それを分析することです。

これは身も蓋もない話ですが、個人で開発していたタスク管理&カレンダーリマインドAIが、知らぬ間にコンテキスト不足で再生成を繰り返し、気づいたら2万円が一晩で消えていた...という悲劇を経験しました。

自戒の念も込めて言います。

ログはしっかりとりましょう!

まとめ

求人データに限らず、様々な形式のデータを扱う上で、AIは強力な味方になります。

しかし、ただ単に「これを整形して」と言うだけではダメで、きちんとしたスキーマを教え、適切なモデルを選び、エラー時の対応も考えておく必要があります。

株式会社カンリーでは、AIを活用したデータ変換基盤を構築し、お客様の膨大なデータインポート業務の効率化に貢献しています。

正規表現のメンテナンスに頭を悩ませていた時代から、AIによるスマートな変換時代へ。

皆さんも是非、データの沼から這い上がるためにAIを活用してみてください!

何か質問や相談があれば、コメントで聞いてください!

また、こういったデータ変換の課題でお悩みの方は、ぜひカンリーにもご相談ください!

おすすめの記事

弊社の他のエンジニアの執筆したテックブログがありますのでぜひこちらもご覧くださいませ!
ClaudeAIの「拡張思考モード」について探ってみた
カスタムして理解するMCP Server ~Slack MCP Server編~
カンリー Advent Calendar 2024

Discussion