TECH PLAY

HTML

イベント

マガジン

技術ブログ

はじめに LLM+RAG。とても効果的な仕組みだと思われるかと思います。 ただ、RAGのデータは私が個別に対応しているタスクのことを知らないし、過去やってきたことも知りません。 なので自分専用のRAGを構築したんですが、思ったより使い勝手が良かったので、同じような状況の人の参考になればと思い、手順/効果をまとめてみました! ご紹介する環境では VS Code(Copilot Chat)にローカルRAGを繋ぎ、Confluence やローカル環境のファイルを検索して回答に活用させています。 またRAGのソースにはベクターDB(Chroma)を使っているので、単純に Markdown を
CTO の川口( id:dmnlk )です。 最近、社内で「とりあえず HTML にして置いておくね」という会話を当たり前のように耳にするようになりました。きっかけは、社内 HTML をホストするだけのささやかな環境をひとつ用意したことです。たったそれだけのことなのに、気づけばエンジニア以外のメンバーまで使い始め、社内の情報の流れそのものが変わっていきました。 この記事では、なぜそんな環境を作ったのか、どう作ったのか、そして実際に何が変わったのかを書きます。 きっかけ:AI が生むドキュメントは「流通するが、読まれない」 AI コーディングが日常になって、社内には実装計画 (plan) や設計メモのようなドキュメントが一気に増えました。Claude Code などに計画を立てさせると、その plan ファイルがそのまま成果物として共有されます。これ自体はとても良い変化でした。 ただ、困ったことがひとつありました。 流通はするのに、人間が読むのに適していない のです。 Markdown やテキストのまま Slack や Git に流れてくる とにかく長く、構造はあるはずなのにプレーンテキストだと頭に入ってこない リンクや図が活きず、コードブロックと地の文が地続きで視線が迷子になる 「内容は良いはずなのに、最後まで読む気にならない」。AI が書いたドキュメントが増えれば増えるほど、この摩擦が社内のあちこちで起きていました。 なぜ Notion ではなく HTML だったのか 「読みやすく共有したいだけなら Notion に貼ればいいのでは」とも考えました。実際、しばらくはそうしていました。けれど、どうもしっくりきませんでした。 自由度が足りない 。レイアウトや見せ方が Notion の枠に収まってしまう 凝った表現や、AI に「読みやすい形に整形して」と頼んだときのアウトプットを、そのまま再現できない 結果として「読みやすくしたいから貼り直す」手間が発生し、誰もやらなくなる 一方、AI に「この plan を読みやすい HTML にして」と頼むと、見出し・目次・強調・配色まで含めて、驚くほど読みやすい 1 枚の HTML を出してくれます。 HTML はそのまま渡せばそのまま表示できます 。この「変換を挟まない素直さ」が、Notion にはない強みでした。 足りないのは「その HTML を、社内の人だけがサッと見られる置き場所」だけです。それなら作ろう、と考えました。他社事例を多く見るタイミングでもあり、自作することに決めました。 最近、社内でHTMLで共有する事が多くなってきたので、空き時間にサクッと社内でHTMLを共有するサービスを作った。公開範囲を柔軟に設定できたり、Slackで簡単に共有できたり、esaやNotionに埋め込みで貼り付けれたり、かゆいところに手が届く感じで非常に便利。 Goodpatch社内のみです。 pic.twitter.com/iQPEXY5kT0 — 土屋尚史 / Goodpatch (@tsuchinao83) 2026年6月3日 ssss-app.com https://t.co/yBJmpJId6P — 鈴木慎吾 / TSUMIKI INC. (@shingo2000) 2026年6月15日 作ったもの:GCS + Cloud Run + IAP 構成はできるだけ薄く、運用に手がかからないことを最優先にしました。 保管: Google Cloud Storage (GCS) — HTML と付随アセットをそのまま置くだけです。バケットにアップロードすれば、それが 1 つのページになります。 配信: Cloud Run — GCS の中身を返すだけの薄いサーバーを 1 つ置きます。フルマネージドなので、アクセスがなければゼロまでスケールインし、コストもほぼかかりません。 認証: Identity-Aware Proxy (IAP) — この環境の肝です。Cloud Run の手前に IAP を噛ませ、社内の Google Workspace アカウントを持つ人だけがアクセスできるようにしました。社内の人はすでに Google にログインしているので、URL を開くだけで(追加ログインなしで)中身が見えます。逆に、社外の人にはそもそも到達できません。 昔は IAP を利用するには Load Balancer などが必要で大変でしたが、今は Cloud Run に IAP を直接設定できるため、低コストで実現できました。 ポイントは、 認証を自分たちで実装していない ことです。社内ドキュメントのホスティングで一番こわいのは「うっかり世界に公開してしまう」ことですが、そこを IAP に丸ごと預けられます。「Google にログインできる社内の人だけ」という、最初から欲しかったアクセス制御が、ほぼ設定だけで手に入りました。 あとは「HTML をアップロードしたら社内 URL が発行される」という体験さえ整えれば、書き手は中身に集中できます。 何が起きたか:エンジニアから、全職種へ 最初の使われ方は、ごく素朴なものでした。 エンジニアが plan を読みやすくするため だけに使っていたのです。AI が出した実装計画を HTML にして置き、URL を共有します。レビューする側も「これは読む気になる」と言ってくれます。それだけでも十分に元は取れていました。 変化が面白くなったのは、ここからです。 その URL を見たエンジニア以外のメンバーが、「自分の資料もこうやって置けるの?」と気づき始めました。やがて 財務・経理のメンバーが、自分たちの資料を HTML にして共有する ようになっていきました。スプレッドシートや長い文章ではなく、要点が整理された 1 枚の読みやすいページとしてです。 気づけば、社内の情報共有のデフォルトが少し変わっていました。 「資料を作る=読みやすい 1 枚にまとめて、URL で渡す」が自然な選択肢になった 部署をまたいで「あの URL 見た?」という会話が増えた AI に整形を任せられるので、 読みやすい資料を作るコスト自体が下がった 「読みやすく共有する」ことのハードルが下がると、共有される情報の量と質が両方とも上がります。情報の流れが変わるとは、こういうことかと実感しました。 運用してわかったこと 薄く作って正解でした。 凝った CMS にせず「HTML を置くだけ」にしたことで、書き手は自由に表現でき、運用側もほぼメンテ不要です。 認証を IAP に寄せたのは精神的に大きいです。 社内ドキュメントを置くうえで「公開事故が構造的に起きにくい」という安心感が、気軽さを支えています。 置きっぱなしのドキュメントが肥大化しないよう、デフォルトでは 7 日で自動削除されるようにしました。 API を用意し、CI 環境からも受け付けられるようにして、パフォーマンスレポートなどを CI で更新できるようにしました。 MCP も簡易的に作り、Claude Code や Codex などから手軽にアップロードできるようにして、敷居を下げました。 重要なこと 社内で広く使われるようになった一因は、システムの名前だと思っています。キャッチーな名前にすると、社内の文脈に浸透しやすくなります。元々「ファイルをポンと置きたい」くらいの気持ちで始めたので、サービス名は「pon」にしました。すると社内では「資料を pon しました」といった形で話題に上がるようになり、一気に広まったように思います。社内ツールの名前は、想像以上に重要です。 まとめ 社内に HTML をホストする環境を作ったのは、「AI が生む読みづらいドキュメントを読みやすくしたい」という小さな動機からでした。GCS + Cloud Run + IAP という薄い構成で、認証は IAP に任せきりです。技術的には派手さのない仕組みです。 それでも、エンジニアの plan 共有から始まった使われ方がエンジニア以外の職種にまで広がり、社内の情報の流れそのものを少し変えていきました。「読みやすく共有するコストを下げる」だけで組織の情報の流れはこんなに変わるのか——というのが、作ってみての一番の発見です。 似たような「ドキュメントは増えたのに読まれない」課題を抱えている方の参考になれば嬉しいです。
こんにちは。BUYMA TRAVELのWebエンジニアの赤間です! BUYMA TRAVELは BUYMA を運営する株式会社エニグモのグループサービスです。 1. はじめに 弊社では日本語対応のオプショナルツアー・貸切ガイド予約サイト’’BUYMA TRAVEL’’を開発・運営しています。 その中でも「エリアページ」と「スポットページ」は検索エンジンから流入したユーザが最初に訪れることの多い主要なページです。 ここ数ヶ月でユーザにとってより使いやすいページを目標に、クチコミやおすすめ商品の掲載など様々な要素・機能の追加を行ってきました。しかしその一方で表示速度が低下し、商品数の多いページによっては表示完了まで最大3秒かかってしまう状況でした。 そこでこれらのページを対象に、Railsアプリケーションのパフォーマンス改善を実施しました。本記事では調査の流れから改善内容、その改善を通して得られた知見をご紹介します。 2. エリアページ・スポットページとは ここで簡単にサービス紹介もかねて、この2つのページのご紹介です。 エリアページ https://travel.buyma.com/service/a040118/ その名の通り、エリア(地域)単位で商品をまとめている特設ページです。 スポットページ https://travel.buyma.com/service/a040118/s0000001/ こちらは、観光スポット単位で商品をまとめている特設ページです。 どちらのページも人気商品やプライベート商品、クチコミ、おすすめスポットなどのコンテンツを掲載しています。 一見すると単純な一覧ページですが、実際にはユーザに新鮮な情報を提供するための複数の検索処理や集計処理、共通コンポーネントによって構成されており、システム的に比較的処理の多い重いページとなっています。 3. なぜ改善が必要だったのか これらのページは検索エンジンから’’BUYMA TRAVEL’’に流入したユーザが最初に目にするページです。 そのため表示速度の低下は単なる技術的な課題ではなく、サービス全体の利用率や売り上げにも直結する可能性があります。 また、エリアページとスポットページはサービス内でもアクセス数が多く、改善効果が大きいページでもありました。 実際に計測したところ、改善前ではページ表示までに最大3秒程度かかってしまうケースも確認できました。 ページ表示速度と離脱率には相関があると言われており、ユーザがページの表示を待っている間に離脱してしまえば、どんなに魅力のある商品を掲載していても見てもらうことはできません。 そこで、本格的なパフォーマンス改善に取り組むこととなりました。 4. AIを活用したボトルネック調査 エリアページは長年運用されてきたページであり、コードベースも大規模化していました。 そのため単純に「とりあえずSQLを削減する」といった場当たり的な改善ではなく、本当にボトルネックとなっている処理を特定する必要がありました。 Railsアプリケーションではコントローラ・モデル・ビュー(・ヘルパー)に処理が分散しているため、どこで処理時間を消費しているかを把握するだけでも手間がかかります。 今回はDatadogで遅いトランザクションを特定し、Cursorを利用してコードベースの調査を行いました。 AIに「TTFBを悪化させている箇所を探して欲しい」 という依頼を行い、懸念箇所や修正候補をリストアップしてもらいました。 5. 調査して見つかった問題箇所 分析の結果、大きく以下の3つの課題が見つかりました。 SQLの発行数が多い 同一リクエスト内で重複した計算が発生している キャッシュが十分に活用できていない 特にSQL関連の問題が深刻で、全体処理時間の約60%を占めている有り様でした。 6. 実施した改善 SQL発行数の削減 調査の結果、レスポンス時間の大部分をデータベースアクセスが占めていることがわかりました。 特に商品一覧の表示処理では、関連データを取得する際にN+1問題が発生している箇所が複数存在していました。 N+1問題とは、一覧取得後に各レコードごとに追加のSQLが発行されてしまう問題です。 たとえば商品を10件まとめて表示する場合、本来1回で済むはずが11回以上のDBアクセスが必要になることがあります。 さらにデータ量が増えるほどSQL実行回数も増加するため、パフォーマンスへ大きな影響を与えてしまうのです。 今回の改善では includes を利用したEager Loadingを積極的に導入し、必要な関連データを事前にまとめて取得するように変更しました。 また、同じ情報を異なるコンポーネントで個別に取得している箇所も存在していたため、取得処理を集約し不要なクエリ発行を削減しました。 結果として、SQL発行数を大幅に削減でき、レスポンス改善に最も大きく貢献した施策となりました。 同一リクエストで同じ計算をしていた 調査を進める中で、同一リクエスト内で何度も同じ計算を行なっている箇所も見つかりました。これは本当にもったい無いですね、、、 単体で見ると小さな処理ですが、ページ全体では何度も呼び出されるため無視できないコストになります。 そこでメモ化を導入し、一度計算した結果を再利用するように変更しました。 また、一部の集計処理にはキャッシュを活用することで再計算そのものを削減しています。 大きな改善ではありませんが、細かな最適化の積み重ねが最終的なレスポンス改善につながりました。 お気に入り機能とキャッシュの見直し 今回の改善で特に興味深い問題が、お気に入り機能とキャッシュの関係でした。 商品カードはページ内で大量に表示されるため、本来であればカード単位でキャッシュしたいコンテンツです。商品名や価格、評価、パートナー情報などは頻繁には変化しないため、一度生成したHTMLを再利用できることで大きな効果が期待できます。 しかし、お気に入りの状態はユーザごとに異なる情報です。 同じ商品であってもあるユーザにとっては「お気に入り登録済」、別ユーザにとっては「未登録」という状態があります。 そのため商品カード全体をキャッシュしてしまうと、 ユーザごとに異なるキャッシュを生成する必要がある キャッシュキーが複雑になる キャッシュヒット率が低下する という問題が発生します。 実際に、改善前はこの問題を回避するために、お気に入りボタンを除いた「パートナー・評価」「商品情報」の2つの領域に分けて個別にキャッシュしていました。 この構成でもキャッシュがない状態より圧倒的に効率的ですが、キャッシュの管理が複雑であったり、テンプレートも読みづらい実装になっていました。 そこで今回の修正では、商品カードとお気に入りの状態を分離し、商品カード全体を共通キャッシュできる構成へ変更しました。 商品カード本体は全ユーザ共通のHTMLとしてキャッシュし、商品IDごとのお気に入りの状態は別で取得する形です。 これにより商品カード自体は1つのキャッシュとして扱えるようになり、キャッシュ構成をシンプルにしつつ、高いキャッシュ効率を実現しています。 結果としてレスポンス速度だけでなく、今後の保守性や機能追加のしやすさという点でも大きな効果を得ることができました。 7. 改善結果 改善前ではページ表示までに最大3秒程度かかる状態でした。 改善後は1秒に満たない時間で表示できるケースが大半となり、体感速度も大きく向上しました。 今回の改善では特定の1箇所を直したのではなく、 SQLの最適化 重複処理の削減 キャッシュの見直し といった複数の小さな改善を積み重ねたことが、この結果につながりました。 8. まとめ 当サイトの主要ページである、エリアページ・スポットページの速度改善についてご紹介しました。 パフォーマンス改善というと大規模なアーキテクチャ変更をイメージするかと思います。私自身はそのような印象を持っていました。 しかし実際には特別な技術ではなく、N+1の解消やメモ化、キャッシュ設計の見直しといった、比較的小さな改善の積み重ねでも、十分な効果が出せると実感しました。 Railsには優秀なキャッシュ機構や様々な最適化手法がありますが、まずは基本的なSQLの見直しが重要です。 普段のレビューでもN+1の有無や効率的なデータの取得については確認していますが、改めて見直してみると、どうしても漏れは出てくるものだと感じました。機能追加を重ねてきたページほど、定期的にパフォーマンスの棚卸しは必要だと思います。 今回で大きくレスポンスを改善できましたが、まだ課題は残っています。 特にレビュー集計処理にはサマリーテーブル導入の余地がありますし、ページビューカウントの非同期化など、更なる高速化が可能です。 今後もユーザ体験向上のため、継続的な改善を続けていきます。

動画

書籍