🏠

【第3回 AI Agent Hackathon】EkiPick

に公開

第3回AI Agent Hackathon with Google Cloud 応募記事

※ この記事は9/27に更新しました

課題

今回のハッカソンでは私 tonoyamaとkyotoの2名で参加することになりました。

私たちは両名ともに東京に本社がある企業に在籍しつつも、地元関西からリモートワークをしているのですが、昨今のReturn to office の流れによって東京への引越しを検討していました。

一方で生まれも育ちも関西で、地元に住んでいる私たちには、下記に記載したような幾つかの悩みがありました。

  • 出超の際とは異なり、オフィス街に近いビジネスホテルを借りるわけにはいかない。
  • 東京の乗り換えに疎い。どの駅の近くに住めば、通勤時間を短くできるのかもわからない。
  • 東京の地理にも疎い。どの駅の近くに住めば賃貸を借りれて、スーパーや病院があるのか検討がつかない。

賃貸探しは「通勤時間」・「家賃」・「周辺の立地」の3つが重要とは理解しつつも、そのいずれも分からないという課題を抱えていました。

ターゲットユーザーと解決策

上記の課題は私たちは勿論、関東圏に住んだことのない同僚・友人にとっても共通の課題でした。学生が上京するにあたっても、存在するものと考えています。

そこで今回のハッカソンではオフィスにもっとも近い駅への通勤時間・家賃想定から、幾つか住むのに向いていそうな駅を自動で推薦してくれるAI Agentシステムを開発することにしました。

システムデモ動画

https://youtu.be/khIsnBBxAxs

機能特徴

私たちの作成したシステムでは下記の機能 (Agent) が存在しています

  • 左に表示した地図に駅やスポットをピン止めする機能 (保存可能)
  • 対象駅から通勤時間・家賃想定を踏まえて提案をしてくれる機能
  • 駅周辺の情報・ハザードマップ・スポット情報について検索・ピン止めしてくれる機能
  • 会話の履歴をようやくしてくれるサマリー機能
  • 会話の流れを踏まえて第三者としてアドバイスをしてくれる機能

会話の流れは下記です

1. ユーザーがオフィス最寄り駅・賃貸・通勤時間を記載する
2. Agentが最初の会話を始める。最寄り駅にピンを打ち、そこから指定の通勤時間でな駅を3つ程度ピックアップする。1Rの家賃情報も調べて提示
3.  提案した駅についてはピンを打って場所を教えてくれる。その上でそれぞれの駅について住居環境の説明をしてくれる
4. 最後にフォローアップの質問例を提示してターン終了

その後ユーザーは追加で質問をすることで議論を深めていくことができます。例えば下記のようなことができます

  • アドバイスが欲しいと聞くと、今までの会話から更に幾つかの確認する情報を教えてくれる
  • 災害情報を教えてほしいと聞くと、今までの会話から更に幾つかの確認する情報を教えてくれる
  • 駅周辺の病院などを教えて欲しいと聞くと、駅情報を調査しピンを打って場所を教えてくれる

技術スタック

利用した技術スタックは下記のとおりです。

分野 技術スタック
Frontend React・React Router v7・Tailwind CSS
Backend FastAPI・Agents Developer Kit
Database CloudSQL
Infra CloudRun・OpenTofu
API Vertex AI・Google Map API・NAVITIME RapidAPI

今回は AI Agent の開発に注力するため、フロントエンドは Vibe coding が中心になりましたが、React / Tailwind CSS とvibe coding の組み合わせが良くスムーズに開発できました。

今回はGoogle Cloud 様協賛ということで、駅候補検索についても Google Map API を利用したかったのですが、日本の鉄道は対応しておらず、NAVITIME RapidAPIを利用しています。

実装における技術的なポイント

Agents Developer Kit 活用

Agents Developer Kit を利用することで、AI Agent 自身が使うべきツールを動的に使い分けることができる実装を容易に組み込むことができるようになりました。gemini-flash-2.0 でも十分に賢く、与えられたタスクに対して sub_agents と tool も自然に使い分けることが可能でした。

  • 会話履歴からレポートを生成する・アドバイスをする場面では sub_agents
  • タスクに対してAPIなどから外部知識を取得したい場合には tool

本機能によって、地図検索・Web検索・駅検索を Google Map API ・ Vertex AI・NAVITIME API を使い分けて呼び出してくれることで、細かいハンドリングがぐっと楽になりました。

会話戦略

最初の会話の入り方を安定させるために、会話セッションが存在しない場合のみ、
テンプレートに沿った会話を始めるAI Agentを呼び出すようにしています。

これによって下記のような流れを毎回安定して再現することが可能になり、
最初にユーザーにまとまった情報を提供することが可能になりました

  • 地図上の会社最寄り駅にピンを打つ
  • AI Agent おすすめ駅にピンを打つ
  • おすすめ駅をそれぞれ説明する
  • フォローアップの質問案を出す

会話失敗時戦略

AI Agent がユーザーの入力や外部APIの結果に左右される都合上、どうしても失敗するケースも見られました。そこで下記のような戦略を取ることにしました。

  • 家賃情報を取得する際には、tool で手元で構築した東京家賃情報データをまずは参照するように指示し、それが失敗した場合には gemini による検索で家賃情報を集めてくるようにプロンプトに記載する。これによって最初の確信度が高い情報が得られなかった場合にも、ユーザーに失敗を通知せずにリカバリーが効くようになる。

  • 意図しないプロンプトが渡された場合には失敗を通知するためのテンプレートを用意し、そのエージェントが理想的に動く入力内容をユーザーに提示する

これらの実装を通じて、世の中のAI サービスが入力テンプレートを事前に用意しているのは、こういう課題があったのかと納得する次第でした。

Streaming Response

Agents Developer Kit では sub_agents / tool を含んだ複雑な推論を行うため、応答待ち時間が長くなるのがネックでした。

そこで今回のシステムの実装では、AI Agent の会話途中に streaming で出力を返すことで、
ユーザーを待たせないことを意識しました。

また 場所のPin についても streaming で出力を返すようにしました、ピンが立つのは視覚的に分かりやすいのに加え、ユーザがピンを目で追いかけている時間を次の出力の用意をする時間としても活用しています。

別件ですが、Chat出力時にはタイプライターのアニメーションを導入することで、まとまってテキストが流れてきて読むのが大変という負担も減らしています。タイプライターのエフェクトがあるだけで、体感が変わるというのはある種不思議な経験でした

モデル使い分け

細かいTipsとして、最初の会話だけは gemini-2.0-flash ではなく gemini-2.5-flash を使うようにしました。

最初の会話では「ユーザ入力 → 駅検索・提案 → 駅情報案内」と難しめのタスクを取り組むため、
会話が失敗する可能性を減らすために良いモデルを選択しています。

最初の会話失敗はユーザーの離脱につながるため、ここぞの場面では良いモデルを使うことで品質の確保とチャットの方向付けをしています。

今後の拡張案

推論時に「今何をしているか?」を簡潔にユーザーに伝えたい

Agents Developer Kit では AI Agent 自身がタスクに合わせて tool / subagents / 推論 と使い分けられる一方で、推論が長くなっている場合は「今、XXXをしています」といった案内を出してあげられると、よりユーザー体験が良くなりそうです

ピンとテキストを連動させる

現状はAI Agent が回答した駅やスポットを左側の地図に表示させるだけになっていますが、ピンがいきなりたっても場所が分かりにくいというのもあります。

ピン情報は streaming で送信しているため、右側のチャット欄に駅やスポットのピンに飛ぶことができるカードを出せると、ピンとテキストが紐付けやすそうです

到達可能駅を具体的に

今回の例では到達可能な駅を最大3つに絞って出力していますが、更にユーザーに要件を聞く(乗り換えしたくない、始発駅にしたい)などから到達可能駅を更に絞ることができるとよいですね。

また到達可能駅から目的駅までの路線図を地図に表示したり、路線名を具体的に出力するなどの処理を追加することで、よりフレンドリーになると感じました

Github Link

インフラ・外部データは除いてありますが、こちらにGithub Repository をご用意しています。
参考になりましたら是非スターをお願い致します!

https://github.com/Tonoyama/EkiPick

Discussion