- AIのコンテキスト理解を深めるため、非構造化データを『セマンティックHTML』へ自動変換
- h1/h2やasideタグを戦略的に配置し、RAGの検索精度と回答の正確性を極限まで向上
- Power Automateによる1問1ファイルのナレッジ生成術と、CLIコマンドのパースのコツ
データの「点」を、AIが理解できる「線」の文脈へ
日常業務で蓄積されるSharePointリストやExcelのログ。これらは人間には読みやすくても、そのままRAG(検索拡張生成)のデータソースに放り込むだけでは、AI(LLM)はその真の文脈を理解してくれません。
私は、社内のトラブル対応記録を「AI専用のナレッジ」へと昇華させるため、Power Automateを用いて**「セマンティックなHTML形式」**へ自動変換するロジックを自ら構築・実装しました。単なるテキスト変換ではない、AIの回答精度を極限まで高めるための「タグ設計」のこだわりを共有します。
なぜ「セマンティックHTML」なのか?(実装の狙い)
RAGの検索精度が出ない最大の要因は、「LLMがデータの構造と情報の重みを判別できていないこと」にあります。 検証を繰り返す中で確信したのは、LLMはプレーンテキストや中途半端なマークダウンよりも、HTMLのタグ構造(h1, h2, pre等)を「情報の親子関係」として極めて正確にパース(解析)する特性を持っているという点です。
この特性をハックし、Power Automateで以下のような「AIへのヒント」を埋め込んだ構造化ナレッジを自動生成する仕組みを作りました。
[自作したデータ循環フローの構成]
graph TD
A["SharePoint List / Excel入力"] -->| Power Automate発動 | B["<b>タグ埋め込みエンジン</b>"]
B -->| h1, h2, preタグ等でカプセル化 | C["セマンティックHTML文書"]
C -->| RAGソースとして公開 | D["AIエージェントの理解が深化"]
D -->| 根拠の明確な回答生成 | E["ユーザーへ還元"]
style C fill:#dff,stroke:#0078d4,stroke-width:2px
私が実装時にこだわった「AI専用マッピング」
AIが情報を誤認しないよう、各データ項目を以下のHTMLタグに厳密にマッピングしています。
<h1>タグ: 障害名や事象のタイトル。AIに「これが最重要の検索キーである」と認識させます。<h2>タグ: 「原因」「解決手順」などの見出し。情報の境界線を明確に引きます。<pre><code>タグ: 機器のコンフィグやCLIコマンド。AIに「ここは改変してはいけないリテラルな情報である」と教え込み、回答時の正確なコピペを可能にします。<aside>タグ: 「※注意点」や「特記事項」。メインの文脈から切り離した「補足的な警告」として認識させます。
🗜️ 実装環境・パラメータシート
| コンポーネント | 設定値 / 実装のポイント |
|---|---|
| 実装プラットフォーム | Power Automate Cloud Flow |
| 変換トリガー | SharePointリストのアイテム作成・更新を検知 |
| 保存フォーマット | HTML5 (UTF-8) ※文字化け防止のため明示的に指定 |
| 構造化のこだわり | 1問1ファイルの原則(1つのファイルに複数の情報を混ぜない) |
| メタデータ | last-modified をHTML内にコメントアウトで埋め込み、鮮度を管理 |
実装・検証から得られた具体的な手順
実際に私がフローを組んだ際の手順と、ハマりどころを回避するポイントです。
- セグメント化された変数の初期化: SharePointの各列(事象、手順、コマンド)をそのまま結合せず、一度Power Automate内の変数で受け取り、HTMLタグでラップする「サンドイッチ構造」をアクション内で組み立てます。
preタグ内の改行コードの制御: CLIコマンドを扱う際、通常のHTMLアクションでは改行が消えてしまいます。私はreplace()関数を使い、改行コードを適切に維持したまま<pre><code>内に流し込むことで、インデントが崩れないように調整しました。- 動的なファイル命名:
utcNow()と機器名、事象名を組み合わせたユニークなファイル名を自動生成し、SharePointのナレッジ保存用フォルダへ.htmlとして自動書き出しを行います。
得られた成果: この「1問1ファイルのセマンティックHTML化」を導入した結果、RAGの検索ノイズが劇的に減少し、特に「機器の設定コマンドの正確性」において、従来のテキスト形式比で圧倒的な改善が見られました。
私がよく受ける質問(FAQ)
Q: Markdownではなく、なぜわざわざ手間のかかるHTMLを採用したのですか?
A: Copilot StudioやM365のインデックスエンジンにおいて、HTMLタグ(h1〜h2)が持つ「重み付け」は、マークダウンよりも階層構造として強力に尊重される傾向があるためです。AIに「情報の親子関係」を確実に叩き込むには、HTMLが最適解でした。
Q: 過去の膨大な対応ログ(Excel)も同じ手法でいけますか?
A: いけますし、強くお勧めします。私も過去の500件近いExcelデータを、Power Automateのループ処理を使って一括で「1ファイル1問のHTML」に分解・変換しました。埋もれていた古いトラブル事例が、AIにとっての「最高級のナレッジ」として蘇りました。
Q: 変換時にHTMLタグがエスケープされて「そのままの文字」として表示されてしまいます。
A: Power Automateの「HTMLテーブルの作成」など一部のアクションでは特殊記号がエスケープされます。私は文字列の結合時にあえて「文字列変数」を使い、直接タグを記述して流し込むことで、ブラウザ(およびAIのクローラー)が正しくタグとして認識できる出力を維持しています。
よくやらかす失敗パターンと対処法
Power Automateでセマンティックなhtml変換フローを実装する際にハマった失敗と、その解決策をまとめた。
❌ HTMLタグが二重エスケープされてAIがテキストとして認識した
「文字列変数の初期化」アクションで <h1>障害名</h1> を設定すると、後続の「SharePointファイルの作成」アクションで <h1>障害名</h1> に変換されてしまった。対策は「SharePointへのファイルの作成(バイナリ)」アクションを使い、UTF-8エンコードされたバイナリとして渡すこと。
// Power Automate 式エディタで使用(コンテンツをバイナリ化)
base64ToBinary(base64(concat('<h1>', variables('title'), '</h1>')))
❌ <pre><code> 内の改行が消えてCLIコマンドが1行に結合した
改行文字(\n)をそのまま文字列変数に入れても、HTMLファイル出力後に空白扱いになってしまった。replace() 関数で改行コードを に変換することで解決した。
replace(variables('cliCommand'), '\n', ' ')
❌ utcNow() のタイムゾーンがUTCのままでファイル名が9時間ずれた
ファイル名に utcNow('yyyyMMdd') を使ったところ、日本時間深夜0〜9時に実行すると前日付のファイル名になってしまった。convertTimeZone(utcNow(), 'UTC', 'Tokyo Standard Time', 'yyyyMMdd') に変更して解決した。ファイル名だけでなく、HTML内の last-modified コメントも同様に日本時間で出力するよう修正した。
❌ 1ファイルに複数事象を詰め込んでRAGの精度が下がった
「似たカテゴリだから」とFirewallの複数エラー事例を1ファイルにまとめたところ、RAGが関係ない事例を引っ張ってきて誤回答が増えた。1問1ファイルの原則に戻したら誤回答率が元に戻った。これは量の問題ではなく構造の問題であり、ファイル数を増やすことを恐れないことが大切だと理解した。
❌ SharePointフォルダのパスに日本語が含まれてファイル書き出しが失敗した
ナレッジ保存用フォルダのパスに日本語文字列(例:「ナレッジDB」)が入っていたところ、Power AutomateのSharePointアクションがURLエンコードと日本語パスの組み合わせを正しく処理できずエラーになった。フォルダ名を英数字(例:knowledge-db)に変更したことで即座に解決した。
私が手元で確認したこと
ここで書いた手順は、自分の作業ログをベースに整理した記録です。途中で詰まった箇所・遠回りした箇所・想定と違った挙動も、後から同じ場面に遭遇した自分が読み返せるよう、できるだけ生のままメモしています。環境差で再現しないケースもあるため、ベンダー公式情報と本記事を見比べて取捨選択していただくのが一番確実です。