はじめに
株式会社Housmartのプロダクトチームです。
弊社はイタンジのグループ会社であり、プロダクトチームでは売買仲介・買取再販業者向けの営業支援サービス「PropoCloud」を開発しています。
今回は社内で開催したAIハッカソンについて、その経緯や得られた知見を共有します。
なぜ私たちはAIハッカソンを開催したのか
『AIで何ができるのか?』― 私たちはずっとこの問いに向き合ってきました。「日々の開発にAIを活かしたい。でも、AIをどう使えば良いのか分からない…」そんなモヤモヤを抱えていた私たちは、ある挑戦を決意しました。
それが、2025年2月に企画したAIハッカソンです。このハッカソンの狙いは、AIツールを活用してPropoCloudの新機能を開発し、実際に手を動かして検証することでした。
私たちがハッカソン開催に至った理由は、主に以下の3点です。
a. AIで開発効率を高めたい
当時、AIツールを開発に利用するメンバーはまだ多くありませんでした。AIの有用性には期待がある一方で、実務でどれだけ活用できるのかを模索している段階でした。そこでAIハッカソンを通じて、AIツールが実務でどの程度有効かを検証してみることにしてみました。
b. "AIに何ができるか"を体験したい
当時、PropoCloudにはAIを活用した機能がなく、要望はあったものの具体的な開発計画はありませんでした。「AIで何ができるか」を机上の空論で終わらせず、エンジニア自身の手でサービス開発を推進したい、そんな思いがありました。
c. 最新LLMモデルの可能性を探求したい
AIハッカソン開催当時は、GoogleからGemini 1.5シリーズが発表されたばかりでした。それまで最も性能が良いとされていたClaude 3.5 Sonnetを上回るコーディング生成能力を持つという噂があり、その実力を確かめてみたいという好奇心が後押ししました。
こうした背景を経て、私たちはAIハッカソンの開催を決断しました。
AIハッカソンは2月13日(水)から15日(金)までの3日間開催。初日は社内会議室で各メンバーが持ち寄った開発アイデアを元に、どの機能を開発するかディスカッションしました。二日目以降はAIハッカソンに集中するために、コワーキングスペースを貸切り、本格的に開発に取り組みました。
初日のディスカッションでは様々なアイデアが検討され、最終的に以下の二機能を開発対象としました。
- 物件情報要約 & 手動提案メール文生成
- 画像認識による営業活動実績データの自動入力
AIハッカソンにはプロダクトチームから計6名が参加。1名のシニアエンジニアとCTOはアドバイザーとしてハッカソンでの開発をサポートし、残りの4名が中心となり、開発を進めました。
開発タスクはNotionで管理し、要件定義から実装までを1機能あたり1日で進める計画で取り組みました。
活用した主なAIツールおよびLLMモデルは以下の通りです。
- Roo Cline: 効率的な開発を行うためのツール
- Google Vertex AI(Gemini 1.5 Flash): コード自動生成・回答データ生成に活用
- Claude 3.5-sonnet: コード自動生成に使用
開発の流れとしては、まず要件定義と同時にシーケンス図を作成し、実装方針を固めました。以下は、『2. 画像認識による営業活動実績データの自動入力機能』を開発した際に使用したシーケンス図の一例です。
シーケンス図と要件定義の完成後、Notionでチケットを発行し、メンバーがカンバンボード上から担当するチケットを選んで開発を進めました。
1. 物件情報要約 & 手動提案メール文章生成
開発機能の背景
この機能は、PropoCloudのデータベースに存在する物件情報を元に、顧客一人ひとりに最適な提案文を生成する機能です。PropoCloudでは物件購入を検討している顧客向けに、条件に合った物件をメールで提案する機能があります。その文章作成にAIを活用することで、プロダクト開発に繋がる可能性があると考え、今回採用しました。
技術的背景:Google Vertex AIとGemini API
この手動提案メール文章生成機能は、Google Vertex AIを基盤として構築し、特に高性能な言語モデルであるGemini APIを呼び出すことで、高品質な文章生成を実現しています。
API連携にはRubyのgoogleauthというgemを使用し、Google Cloudのサービスアカウントを使った安全な認証と、Gemini APIへのスムーズなアクセスを可能にしました。
以下のコードは認証とリクエスト送信の一例です。
api_key = ENV['GOOGLE_GEMINI_API_KEY'] raise 'Google Gemini API key is not configured' if api_key.nil? authorizer = Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: StringIO.new(api_key), scope: "https://www.googleapis.com/auth/cloud-platform" ) auth_response = authorizer.fetch_access_token! token = auth_response["access_token"] uri = URI(ENV['GOOGLE_GEMINI_API_URL']) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri.request_uri) request["Content-Type"] = "application/json; charset=utf-8" request["Authorization"] = "Bearer #{token}" prompt = get_prompt(kind) # ここでプロンプトを生成 request.body = { contents: [ { role: "user", parts: [ { text: prompt } ] } ], generation_config: { temperature: 0.0, # 創造性をコントロール max_output_tokens: 8192, response_mime_type: "text/plain" } }.to_json response = http.request(request)
上記のコードでは、Google Cloudで発行したクレデンシャル情報(GOOGLE_GEMINI_API_KEY
に格納)を使って認証を行い、Gemini APIのURL(GOOGLE_GEMINI_API_URL
)に対してリクエストを送信しています。特に注目すべきは、temperature: 0.0
という設定です。これは生成される文章の創造性(ランダム性)を最小限に抑えることで、プロンプトで指定した文末・文体ルールを忠実に守り、安定した文章を生成するために調整しています。
以下は文章生成のためのプロンプトの一例です。
"指示:\n" "以下の要件に従い、複数の物件を提案するメール本文を作成し、出力形式に沿って出力してください。\n\n" \ "要件:\n" \ "- 役割: あなたは優秀な不動産エージェントです\n" \ "- 文字数: 100~200文字以内\n" \ "- 文体: 親しみやすく、わかりやすい表現、「~が整っています」や「~が期待できます」などの柔らかい表現を用いる\n" \ "- 専門用語: 控えめにし、平易な言葉を使用\n" \ "- 情報の優先度: 買主が重視するポイントを最優先に記載し、不要な情報は省く\n" \ "- 行動喚起: 「今すぐ内見」「お問い合わせ」などのCTAを含める\n" \ "- 統一感: フォーマットを統一し、提案ごとに文体や語調が大きく変わらないようにする\n" \ "- ライフスタイルの考慮: 入力情報の買主情報からライフスタイルや価値観を推測し、入力情報の物件情報とマッチする最適な提案文を生成\n" \ "- 買主のライフスタイルに合うポイントを強調し、自然な流れで物件を紹介する\n" \ "- 物件の共通点を訴求: 共通の特徴や魅力を強調する\n" \ "- 絵文字や文字化けするリスクのある文字は使用不可\n" \ "- 物件情報の一般化: 個別の物件情報ではなく、選定全体の意図や特徴を伝える\n" \ "- 個人情報・物件固有情報の除外: 名前(買主、担当者の氏名)、物件名、住所、その他、個別に特定できる情報(建物固有の名称など)を出力しない\n" \ "- 表記の統一: 駅名やエリアは一般的な地域名で表現し、詳細な地番は記載しない\n\n" \ "- 最後に: あなたなら素晴らしい提案文を生成できることを信じています\n\n" \ "入力情報:\n" \ "#{user_profile}\n\n" \ "#{property_list}\n\n" \ "出力形式:\n" \ "#{customer_name}様\n" \ "お世話になっております。\n" \ "#{company_name}の#{agent_name}でございます。\n\n" \ "お住まい探しのご状況はいかがでしょうか?\n" \ "こちらのメールで、物件の紹介をさせていただきます。\n\n" \ "{生成した文章を入れてください}\n\n" \ "その他、物件についてのご不明点・ご質問や気になる物件等ございましたら何なりとお気軽にお申し付けくださいませ。\n" \ "何卒、宜しくお願い申し上げます。\""
プロンプト作成にあたり意識したことは「役割」「指示」「指示の詳細」を与えることです。これは現在ではRTF(Role, Task, Format)フレームワークと呼ばれています。
加えて、あなたなら素晴らしい提案文を生成できることを信じています
というポジティブワードを挿入しています。これは当時、生成精度向上に寄与すると噂されていたためです。実際、このポジティブワードを追加する前後で、体感レベルにはなりますが、比較的より良い品質の文章が生成できているように感じました。
これらの工夫を経て、最終的に完成したのが以下です。
2. 画像認識による営業活動実績データの自動入力
機能開発の背景
PropoCloudでは、販売中の物件の閲覧数やお気に入り数などの営業活動実績データを入力すると、売主顧客向けのマイページにて上記のデータが閲覧できる機能があります。しかし、これらのデータは手動で入力する必要があり、掲載するポータルサイトが増えるにつれて、入力するデータ量が増え、作業工数が増大していました。
この課題に対し、画像認識技術を用いた自動化で解決を目指し、機能開発に取り組みました。
実装
実装の選択肢としては、OCR(光学的文字認識)と、LLMを活用した方法の2種類が候補に挙がりました。当初はオープンソースのOCRライブラリでの実装を検討しましたが、文字列抽出範囲の指定や、エラーハンドリングの仕様策定と実装に時間がかかり、短期間での実現は困難だと判断しました。
そこで、画像データを直接Gemini APIへリクエストする方法を試したところ、想像以上に画像認識の精度が高く、課題を解決できました。
最後にフロントエンドとバックエンド間で発生していた軽微なエラーを修正し、無事に機能を完成させました。
完成イメージとしては、読み込み元にあるスクリーンショットなどの画像データをPropoCloudに読み取らせると、読み取り後のように自動的にデータが反映されます。
この時の学びの詳細は後述しますが、AIが課題解決を「ショートカット」してくれる力を実感できました。机上の議論だけでは得られない、「手を動かす」ことで実感できた学びでした。
AIハッカソンを終えて:AIとの"距離感"がわかった日
今回のAIハッカソンを通じて、大きく3つの学びがありました。
1. "AIはすごい"の解像度が上がった
ハッカソンを終えた今でも「AIはすごい」という認識は変わりませんが、その言葉に対する解像度は格段に上がりました。
参加前は、AIツールはWebのGUI越しに触ったことはあっても、API経由での利用やAIを組み込んだ機能開発の経験はありませんでした。そのため、自社プロダクトにAI機能を実装するのは、まだ先の未来の話だと考えており、技術的なイメージもほとんど持てていませんでした。
世間では「AIで数日でアプリが作れた」といった華やかなニュースや呟きが飛び交っていますが、複雑なビジネスロジックを含むtoB向けでのプロダクトへの応用は難しいと感じていました。
しかし今回のハッカソンを通じて、AIは想像以上に多くの場面で活用できることを実感しました。特に、従来の実装方法では多岐にわたる考慮が必要な処理を、AIを活用することでシンプルに実装できるという発見は大きな知見です。
例えば、今回開発した「画像認識による営業活動実績データ自動入力機能」は、その好例です。
データ入力の自動化を目的にした場合、一般にはCSVファイルを介して連携する方法を検討すると思います。その際、連携先のデータ構造の定義やエラーハンドリングなど、考慮すべき点は多岐にわたります。
そのため、プロトタイプでのクオリティでかつ限られた期間内で目的達成のためにOCRといった画像認識系タスクを使った実装方法を検討していました。その場合でも読み取り範囲の座標指定やエラーハンドリングという別の課題に直面しましたが、AIはそれすらも乗り越えました。
2. 開発の意思決定にも変化の兆し
開発する機能の優先順位付けという観点でも、重要な示唆を得られました。
ソフトウェア開発において、どの機能を開発するかを意思決定をするために、開発工数は大きな要素です。
LLM登場以前は、従来手法での工数見積もりの結果、本来解決すべき課題であっても実装難易度や工数の問題から着手を断念したり、優先度を下げざるを得ないケースも少なくありませんでした。 今回の経験から、そうした課題にもAIという新たなアプローチで解決が困難だった課題に挑める可能性があると感じています。
もしAIハッカソンでの経験がなければ、AIのできることを過小評価し、うまく活用できなかったかもしれませんし、上記の気づきを得ることはなかったと思います。
3. ハッカソン自体の楽しさと"手を動かす"ことの価値
ハッカソンで得られる体験は、純粋に楽しいものでした。
普段の業務では一人でタスクに取り組むことが多い中、ワンチームで一つの機能開発に取り組む体験は貴重でした。皆で生み出したアイデアが議論を経て洗練され、形になっていく過程は、何物にも代えがたい経験です。
加えて、情報は追うだけでは得られない、実践を通じて初めて見えてくるものがあります。 想像上の「AIでできること」と現実の「AIでできること」の間にはギャップが存在していましたが、今回のAIハッカソンは、このギャップを埋める絶好の機会となりました。一エンジニアとしてプロダクト開発における実装の選択肢が大幅に広がっただけでなく、チーム開発の楽しさも再発見できる素晴らしい体験となったのです。
今後はプロダクト開発で直面する課題に対し、解決策の一つとしてAIを用いたアプローチも視野に入れて取り組んでいきたいと考えています。
余談:AI文章生成機能をリリースしました
この度、私たちはAIハッカソンをきっかけに、AIを活用した文章生成機能を開発し、先日リリースしました。
リリースした機能について
今回リリースしたのは、主に不動産業界のお客様に喜んでいただけるような、物件の魅力を最大限に引き出す文章をAIが自動で生成する機能です。詳細はこちらのプレスリリースを見てみてください。
この機能は、単に物件情報を羅列するだけでなく、部屋の広さや間取り、最寄駅の情報などから、お客様が新しい生活を具体的に想像できるような表現をAIが考案し、提案することで、より効果的な物件紹介を可能にすると考えています。
ハッカソンから生まれた改善とこだわり:プロンプトエンジニアリングの試行錯誤
この機能のアイデアは、社内ハッカソンから生まれました。ハッカソン後も、いかに高品質な文章を生成するかという点にこだわり、プロンプトの改善に力を入れてきました。特に、AIが生成する文章の品質をコントロールするため、詳細な文末・文体指定をプロンプトに盛り込んだ点が大きな特徴です。
具体的には、以下のルールをプロンプトに設定し、AIが「お客様が魅力を感じる文章」を生成するように試行錯誤を重ねました。
【禁止する文末】
以下のような、AIが安易に使いがちな曖昧な表現や断定を避けるための文末表現は、一切使わないようにプロンプトで厳しく指定しています。
- 「〜でしょう。」
- 「〜できるしょう。」
- 「〜いただけるでしょう。」
- 「〜してくれることでしょう。」
- 「〜ではないでしょうか。」
【許可する文末】
一方で、お客様への丁寧さを保ちつつ、物件の魅力を明確に伝えるために、プロンプトではAIに以下の文末表現の中から必ず選んで使うように指示しています。
- 「〜かと存じます。」
- 「〜と思います。」
- 「〜でございます。」
- 「〜と考えております。」
- 「〜ではないかと存じます。」
このように、お客様への丁寧な対応を意識した文体調整を行いました。
さらに、このような細かいプロンプトエンジニアリングによって、単なる事実の記述に留まらず、物件の部屋の広さや間取り、最寄駅の情報などから、お客様が新しい生活を具体的に想像できるような、感情に訴えかける文章を生成するための基盤を構築しました。お客様のニーズや興味を引き出すキーワードを抽出し、魅力的なストーリーとして紡ぎ出すことに重点を置いています。