Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Vertex AI Grounding を使ってキャリアサマリーを自動生成した

こんにちは!名刺アプリ「Eight」の開発チームでバックエンドエンジニアをしている大久保です。最近はゴルフにハマっています。

今回は、Eightに初めて導入したAI機能である、「キャリアサマリー自動生成」のアーキテクチャと環境構築やAPIリクエストについて共有します。

キャリアサマリー自動生成機能とは

Eightでは、ユーザーのプロフィールに「キャリアサマリー」という自己紹介文を掲載する機能があります。職歴や学歴、専門性などを簡潔にまとめることで、ユーザー同士のつながりを促進するためのものです。

従来は手動で入力する必要がありましたが、より多くのユーザーに活用してもらうため、AIを使って簡単に自動生成できる機能を実装しました。

機能説明はこちらの記事をご覧ください。 jp.corp-sansan.com

実装で目指したこと

キャリアサマリー自動生成で実現したかったのは、以下の3点です。

  1. Eight内のデータとWeb上の情報を統合: 職歴や学歴に加えて、Web上の記事や登壇情報なども統合することで、ユーザーの専門性をより豊かに表現する
  2. 情報源の透明性を確保: AI生成コンテンツでは、根拠となるURLを提示することで情報の信頼性を高める
  3. 自然な日本語文章の生成: 体言止めや常体を使った自然な日本語で時系列順に生成する

これらの要件を満たすために、Google CloudのVertex AIを使用することに決めました。

Vertex AIとは

Vertex AIはGoogle Cloudの機械学習プラットフォームで、GeminiなどのLLMをAPI経由で利用できるサービスです。

Grounding(強化検索)について

Groundingは、LLMがGoogle Searchと連携してWeb上の情報を自動収集する機能です。APIリクエストに tools: [{ google_search: {} }] を追加するだけで、Geminiが自動的に検索クエリを生成してGoogle Searchを実行してくれます。

さらに、参照元へのリダイレクトURLがGroundingのレスポンスから取得できるのが大きなポイントで、「この情報はどこから来たのか」を明示できます。

Vertex AI Groundingを選んだ理由

今回、いくつかのAIサービスを比較検討しました。最終的にVertex AI Groundingを選定した理由は、以下の点がEightの要件に合っていたためです。

  • 参照元URLの自動取得: 情報源の透明性確保という要件を満たせる
  • Google Searchとの連携: 自社社員を中心に検証した限りでは、日本語の情報収集において良好な結果が得られた
  • シンプルなAPI設計: tools パラメータを追加するだけでGroundingを利用できる

なお、他のサービスにもそれぞれ強みがあり、今回の検証結果はEightの特定のユースケースにおけるものです。サービス選定の際は、自社の要件に合わせて検証されることをお勧めします。

実装したシステムのアーキテクチャ

キャリアサマリー自動生成は以下の流れで実行されます。

キャリアサマリー自動生成のアーキテクチャ

  1. 生成リクエスト: ユーザーがボタンをタップ → APIが generation_id を即時返却し、非同期処理をキューイング。この時点でユーザーには生成中の画面が表示されます
  2. 非同期処理:
    • Web情報の収集: Vertex AI GroundingでGoogle Searchを使い、ユーザーに関する記事やインタビューを自動収集
    • サマリー生成: 収集したWeb情報とEightのプロフィールデータを統合し、キャリアサマリーを生成
  3. ポーリングによる結果取得:
    • クライアントが定期的に生成状況を確認し、進行状況をリアルタイムで表示
    • 完了したらサマリーと参照元URLを表示

生成処理は非同期で行い、生成状態をポーリングすることでUXを最適化しました。

Google CloudとAWSの接続方法

Eightのバックエンドは AWS上で稼働していますが、Vertex AIはGoogle Cloudのサービスです。そのため、AWS環境からGoogle Cloudのサービスへアクセスする際には、Google Cloudの認証を行う必要があります。

今回はApplication Default Credentials (ADC)を利用して認証を行いました。 ADCは、環境変数 GOOGLE_APPLICATION_CREDENTIALS にサービスアカウントのJSONキーファイルのパスを設定することで、プログラム側で自動的に認証情報を読み込み、Google Cloudの各種APIに安全にアクセスできる仕組みです。

# 環境変数の設定例(デプロイ時に設定)
ENV['GOOGLE_APPLICATION_CREDENTIALS'] = '/path/to/service-account-key.json'

EightではRubyで開発を行っているため、実際のアクセストークン取得には、google-auth-library-ruby gemを使用して実装しました。

require 'googleauth'

GCP_OAUTH_SCOPE = 'https://www.googleapis.com/auth/cloud-platform'

def fetch_access_token
  credentials = Google::Auth.get_application_default([GCP_OAUTH_SCOPE])
  token_info = credentials.fetch_access_token!
  token_info['access_token'] || (raise 'Failed to get access token')
rescue => e
  Rails.logger.error "Failed to get access token: #{e.message}"
  raise "Failed to authenticate with Vertex AI: #{e.message}"
end

ポイント:

  • Google::Auth.get_application_default がADCを使って自動的に認証
  • fetch_access_token! でアクセストークンを取得
  • OAuthスコープは cloud-platform を指定

詳細は Google Cloudの公式ドキュメントを参照してください。

RubyによるVertex AIへのリクエスト

Vertex AIのRuby用公式SDKは存在しますが、Groundingを含むGenerative AIのAPIには未対応でした。本当は Google Gen AI SDKを利用したかったのですが、今回は直接REST APIを叩く実装を採用しました。

GroundingでWeb情報を収集

require 'net/http'
require 'json'

def request_with_grounding(prompt)
  uri = URI("https://#{LOCATION}-aiplatform.googleapis.com/v1/projects/#{PROJECT_ID}/locations/#{LOCATION}/publishers/google/models/#{MODEL}:generateContent")

  body = {
    contents: [
      { role: 'user', parts: [{ text: prompt }] }
    ],
    tools: [
      { google_search: {} }  # これだけで Grounding が有効に!
    ],
    generation_config: {
      temperature: 0.0,
      max_output_tokens: 8000,
    },
    safety_settings:,
  }

  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = "Bearer #{fetch_access_token}"
  request['Content-Type'] = 'application/json'
  request.body = body.to_json

  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 1200) do |http|
    http.request(request)
  end

  JSON.parse(response.body)
end

ポイント:

  • tools: [{ google_search: {} }] を追加するだけでGroundingが有効になる
  • temperature: 0.0max_output_tokens で同じ入力に対して安定した出力を得る

参照元URLの抽出

Groundingのレスポンスには、参照元のURLにリダイレクトするURLが含まれています。これを抽出してDBに保存することで、ユーザーに情報源を提示できます。

def extract_source_urls(response)
  candidates = response['candidates'] || []
  candidates.flat_map { |candidate|
    chunks = candidate.dig('groundingMetadata', 'groundingChunks') || []
    chunks.filter_map do |chunk|
      {
        url: chunk.dig('web', 'uri'),  # リダイレクトURL
        title: chunk.dig('web', 'title'),
        domain: chunk.dig('web', 'domain'),
      }
    end
  }
end

キャリアサマリー生成

Web情報の収集後、収集した情報とEightのプロフィールデータを組み合わせて、キャリアサマリーを生成します。通常のGemini APIは tools: [{ google_search: {} }] を指定しなければ呼び出し可能です。

おわりに

Vertex AIのGrounding機能を活用することで、Eight初のAI機能を実装できました。Eight内のプロフィールデータとWeb上の公開情報を統合するというアプローチは、他のサービスにはないEightならではの価値だと考えています。

Eightの開発チームでは、こうした技術的チャレンジとユーザー価値の両立を大切にしています。

AI技術を活用したプロダクト開発に興味がある方、ユーザーに価値を届けることに情熱を持つ方、新しい技術に挑戦したい方は、ぜひ一緒に働きましょう!

media.sansan-engineering.com

© Sansan, Inc.