
Sansanモバイルブログリレーとは
SansanのMobile Application グループでは、iOSDC Japan 2026やDroidKaigi 2026の開催にあわせて、モバイルアプリ業界をより一層盛り上げるために、日々の開発で得た知見をブログリレー形式で発信することを始めました。 アプリ開発の設計、運用、チームでの取り組みなど、実際のプロダクト開発を通じて得られた学びを共有することで、モバイルアプリの開発に携わる方々の参考になれば幸いです。
はじめに
皆さんこんにちは。技術本部 Sansan Engineering Unit Mobile Application Groupのパク(@ParkJong-Hun)です。Sansanには2025年6月に参画し、モバイルを主軸としてアプリ開発に携わっています。
今回は最近SansanでリリースしたAIチャット型の新機能である「AIサーチ」の開発プロセスと、そこで得られた技術的な知見や挑戦についてお話ししたいと思います。
AIサーチとは?
2026年9月1日に公開した新機能です。
営業担当者が気になる人物や企業に関する多角的な情報(例:企業サマリー、売上、組織・部署構成など)を、ユーザーの好みの形式で出力したり、対話形式で確認したりできる機能です。
単に固定化されたデータを取得するだけでなく、Sansanに蓄積された豊富な企業・人物・名刺・ニュースなどの内部データに加え、最新の外部情報をリアルタイムでリサーチします。これらをSansan独自のアルゴリズムで統合・処理することで、データの「鮮度」「正確性」、リスクコントロールを含めた「ユーザーへの最適化」を高いレベルで実現しています。
アプリはどういう仕様?
アプリはChatGPTやGeminiのような、直感的なAIチャットUIをユーザーに提供します。
ユーザーがチャット形式でテキスト(プロンプト)を送信すると、Sansan Labsのサーバー側で生成・処理された結果が、リアルタイムにアニメーションしながら画面上に順次表示されていきます。
なぜ一括表示ではなく、ストリーミング形式で表示する必要があるのでしょうか?
AIによる回答生成は、全文がそろうまでに数秒から数十秒かかるケースがあります。全文の生成を待ってから一括で描画しようとすると、ユーザーは何も変化がない画面を長時間見つめることになり、「アプリがフリーズした」「レスポンスが遅い」と感じて離脱につながる可能性があります。
エンジニアの方であれば、ChatGPTだけでなくClaude CodeやCursorといったツールで、テキストやコードがリアルタイムに表示されていく挙動に安心感を覚えた経験があるのではないでしょうか。表示可能なテキストから即座に画面へ反映(ストリーミング表示)することで、ユーザーの体感速度を大幅に向上させ、ストレスのない快適な体験を提供できます。

今までなかった技術的課題は?
Sansanのモバイルアプリ通信は、主にRESTful HTTP(Request-Response)モデルを中心に構築されていました。しかし、今回のストリーミング形式でのAIチャット体験を提供するに当たり、従来のアーキテクチャでは対応が難しい、以下の技術的課題に直面しました。
- リアルタイムで、非定期的にデータを受信すること
- 快適な双方向通信の体験を作ること
- 逐次送られてくる(不完全な)Markdownデータを崩さず、リアルタイムにUIへ表現すること
単体であれば既存の知見で解決できるものもありましたが、これら3つを同時に、かつ高品質に解決するためには、従来とは全く異なる新しいアプローチが必要でした。
採択技術とその理由
上記3つの課題を解決するため、慎重な検証を経て以下の技術スタックを選定・自作しました。
- KMP(Kotlin Multiplatform): iOS / Android間でロジックや状態管理を共通化
- SSE(Server-Sent Events): リアルタイムな単方向ストリーミング受信
- RESTful HTTP+SSE: 双方向通信の体験設計
- Canonical Data Model(JetBrains markdown+自作Parser): 段階的なMarkdown解析とUIモデル変換
- 遅延読み込み(LazyColumn / LazyVStack): 大量のチャットログやストリーミング描画の最適化
SSE vs WebSocket vs Polling
リアルタイムなストリーミングデータ受信において、なぜWebSocketやPollingではなくSSE(Server-Sent Events)を採用したのか、比較表とともに解説します。
| 項目 | Polling (Short Polling) | Server-Sent Events (SSE) 【採択】 | WebSocket |
|---|---|---|---|
| 通信方向 | 単方向 (Client → Server) | 単方向 (Server → Client) | 双方向 (Client ←→ Server) |
| プロトコル | HTTP / HTTPS | HTTP / HTTPS | WS / WSS (TCPベース独立) |
| 接続方式 | 非持続的 (リクエスト毎に切断) | 単一 Persistent HTTP 接続 | 全二重 (Full-Duplex) 持続接続 |
| データ形式 | Text, JSON | text / event-stream | Text, Binary |
| リアルタイム性 | 低 (間隔に依存) | 高 (サーバー発生時に即時送信) | 極めて高 |
| オーバーヘッド | 極めて大 (ヘッダー再送) | 小 (初回接続後はデータのみ) | 極めて小 |
| 自動再接続 | 自前実装が必要 | 標準サポート (標準仕様として定義) | 自前実装が必要 |
| 主なユースケース | 低頻度更新データ | AIストリーミング、リアルタイム通知 | チャット、オンラインゲーム |
なぜSSEなのか?
LLMのチャットにおいて、クライアントからの「質問送信」は標準的なHTTP POST(REST API)で十分であり、双方向の全二重通信を行うWebSocketのオーバーヘッドやステートフルな接続管理の複雑さはオーバースペックでした。
一方でPollingはレイテンシが高く、サーバー負荷も増大します。
「送信はREST API、サーバーからの回答受信はHTTPベースで軽量かつ自動再接続を標準サポートするSSE」という組み合わせが、インフラ・アプリ双方にとって最もシンプルで堅牢、かつ要件に合致した構成であると判断しました。

Canonical Data Model-based Parser vs Markdown表示ライブラリ
ストリーミングで送られてくるデータを表示するに当たり、既存のMarkdown描画ライブラリやSwiftUI・Jetpack Composeが提供するインラインMarkdown表示機能に依存せず、KMP領域にCanonical Data Model(中間データモデル)ベースのParserを自前構築するアプローチを採択しました。
なぜ既存ライブラリやOS標準機能を採用しなかったのか?
Sansan独自のコンポーネント・データの表現:
AIサーチでは、一般的なMarkdownの要素(見出し、太字、リストなど)だけでなく、Sansanが持つ企業・人物・名刺・ニュースといったコンテキストに応じた「独自のUIコンポーネントやデータタイプ」をリッチに表示する必要があります。既存のMarkdownライブラリでは、こうした独自構造を柔軟に拡張・レンダリングすることが困難でした。
UI/UXデザインの完全な制御性:
OS標準のテキスト表示機能(SwiftUIのAttributedStringなど)や既存ライブラリに依存してしまうと、ストリーミング中のデザイン、フォント、間隔、インタラクションなどのUI/UXをSansanのブランドやデザインシステムに最適化させて自由に変更することが難しくなります。
なぜ自作Parser + JetBrains Markdown parserなのか?
一方で、Markdownの基礎的な構文解析(Lexing/Parsing)をすべてゼロから手作業で実装すると、エッジケースへの対応や仕様変更に伴うメンテナンスコスト、品質上のリスクが非常に高くなります。
そこで、「基盤となるMarkdownのパースロジック」と「UIモデルへの変換ロジック」を分離する設計にしました。
Parsingの基盤(JetBrains
markdownライブラリ):Kotlin公式でも使われている信頼性の高いJetBrains製
markdownパイプラインをKMP領域に導入しました。これにより、複雑なMarkdown構文のパース品質とメンテナビリティを担保しています。Canonical Data Modelへの変換(自前実装):
JetBrains Parserが生成したAST(Abstract Syntax Tree)をベースに、ストリーミング途中の不完全な構文を安全に補完(Normalize)しながら、Sansan独自データを含む中間データ構造(Canonical Data Model)へとリアルタイムで変換します。
この構成により、「高品質でメンテナンスしやすいAST解析」と「SansanのUI/UXを100%自由にコントロールできる柔軟性」の両立を実現しました。

まとめ
今回のAIサーチの開発は、普段のモバイルアプリ開発ではなかなか触れる機会の少ないSSE(Server-Sent Events)やストリーミングデータのリアルタイムパースといった先進的な技術に挑戦できる、非常に刺激的なプロジェクトでした。
単にWebViewでWeb画面を埋め込む手法や既存ライブラリ任せにする方法と比べ、KMPと自作パース基盤を活用したネイティブ実装だからこそ、圧倒的にスムーズなストリーミングアニメーション、ストレスのないレスポンス、そしてSansan独自の表現力を備えた上質なユーザー体験を届けることができたと感じています。
Sansanはこれからも、プロダクトと技術の強みを活かし、ビジネスシーンで活躍する営業の皆さんを支え続けていきます。まだまだ提供したい価値や解決すべき課題はたくさんあります。これからも我々Sansanの可能性を追求し、新しいチャレンジを続けていきます!
Sansan技術本部ではカジュアル面談を実施しています
Sansan技術本部では、中途の方向けにカジュアル面談を実施しています。 現役エンジニアと、Sansanでの働き方や仕事の魅力について気軽にお話しできます。
「実際に働く人の話を聞いてみたい」という方は、ぜひお気軽にご参加ください。カジュアル面談に申し込む