RAG + セマンティックマークアップ
他の言語: English Español 한국어 Português 中文
ソフトウェアプロジェクトにおけるドキュメンテーションの重要性は異なりますが、 その重要性がいかに高いにせよ、ドキュメンテーションは基本的に補助的な役割を果たします。 それはプログラムが正しく機能するために必要なものではありません。 ドキュメンテーションがプログラムとデータを共有している場合でも、その接続は一方向的なものです。 ユーザー向けのドキュメンテーションは製品を反映していますが、製品の動作を変えるものではありません。
これが主に技術的な理由であることは明らかです。 自然言語の指示が特定のものであることができ、コンピュータがそれを優れた解釈能力で解釈できるなら、 新機能や修正を行うためにはただドキュメンテーションを書くだけで十分です。 聞き覚えのある話ではないでしょうか?
完全に自然言語でプログラミングが可能かどうかについての議論が続いていますが、この潜在的な変化は実際には ソフトウェア開発のアクセシビリティについての問題であり、プログラムが操作する新たな方法を導入するものではありません。 最終的には、同じバイナリを得ることになりますが、その中には確かに驚くべきコンパイラが追加されることでしょう。
AIが機能を異なる方法で駆動することができますか? 今日は、直接自然言語処理を活用し、私たちの多くのドキュメンテーションを非常に有用な開発資産に変える、JetBrains IDEsの最近のAI駆動型機能の1つについて詳しく説明したいと思います。

アクション検索
バージョン2024.3から、JetBrains IDEsのAIアシスタントはIDEアクションにアクセスでき、手元の問題に対する適切なアクションを見つけるお手伝いをします。 さらに、このアクションを代わりに実行することも可能です:


先に述べたように、この機能はドキュメンテーションによって駆動されています。 既存のコードも一部は関与しているはずですが、適切なアクションの選択は、多数のLLM関数や特殊なマッピングを必要とせずに、RAG(検索強化生成)という高度な形式だけに依存しています。
詳細に移る前に、RAGの概念を簡単に再訪しましょう。
RAG
検索強化生成(RAG)とは、LLMの応答の精度を向上させ、その根拠を定めるために一般的に用いられる手法です。 この技術は、LLMがその訓練データを超えたトピックや、頻繁に変わる事実に関して応答を求められる場合、特に効果的です。
この技術の最も一般的な形式は、ドキュメンテーション上のインデックスを維持することで構成されます。 このインデックスでは、キーがドキュメント要素の意味(埋め込みによって表現される)を反映し、 値がその要素の内容やその要素自体への参照に対応します。 キーの数値表現のおかげで、対応する要素はコサイン類似度やk近傍法(KNN)などの方法を使用して意味的に比較して取得することができます。


RAGのサポートを受けたAIチャットで何かを尋ねると何が起こるかを見てみましょう。
How do I change font size?
システムはまずインデックスを検索し、成功すればその結果をプロンプトに追加します。 例えば:
How do I change font size?
Here's supplementary information that might help you answer the question:
-> the search results are inserted here <-
このアプローチにより、提供された補足情報から正確な答えが推測され、LLMからより情報量のある正確な応答が得られます。 エンドユーザーの視点からは、モデルがよりインテリジェントになったかのように見えるかもしれませんが、 実際にはモデルは変わらず、違いはプロンプトにしかありません。
さて、このアプローチをどのように強化することができるかを見てみましょう。
セマンティックマークアップ
技術文書を作成している場合、セマンティックマークアップの概念についてはおそらく既にご存知でしょう:
セマンティックマークアップでは、各要素の背後にある「意味」を指定します。
たとえば、Markdownはセマンティックではありません。 Markdownでは、見出し、段落、リストなどの一般的な文書要素、 あるいは一部のタイポグラフィー的な属性を操作します。 この構文は大まかな構造を明らかにし、プロセッサにドキュメントのレンダリング方法を伝えます。 しかし、ドキュメント内のさまざまな要素の目的、または意味を伝えるものではありません。
以下に短い例を挙げます。アスタリスクはプロセッサにフレーズをイタリック体で表示するように指示します。これは、HTMLの {<i>}
と同じ意味です:
*Look both ways before crossing the street!*
対照的に、Markdownの上位集合であるMDXにはセマンティックな性質があります。 MDXには、よくUIコンポーネントを表示するためのカスタム要素を定義する機能があり、それによりコンテンツの意図された目的を伝達することが可能です:
<Warning>
Look both ways before crossing the street!
</Warning>
バニラのMarkdownとは違い、この特定のMDXの例は視覚的な面から抽象化して、コンテンツの目的に焦点を当てています。
我々がドキュメンテーションの執筆者として心配することは、 {<Warning>}
がイタリック体になるべきか、それとも通常のテキストから何かしら目立つようになるべきかといったことではなく、
そのスタイルはコンポーネント自体やCSSスタイルシートといった別の場所で定義されています。
このような関心の分離により、コードベースが維持しやすくなり、
内容の意味に基づいて一元管理されたスタイリングを変更することが可能となります。
完全なマッチング?
JetBrainsでは、ドキュメンテーションを作成するためにWritersideというツールを使用しています。 このツールは、MarkdownとセマンティックXMLの両方をドキュメンテーションのソースフォーマットとしてサポートしています。 以下の例は、WritersideのセマンティックXMLで書かれた典型的なドキュメント構造を示しています:
<chapter title="Testing" id="testing">
... some content ...
<procedure title="Navigate to tests" type="choices">
<p>
When at a symbol declaration, you can navigate to the corresponding
tests by doing one of the following:
</p>
<step>
From the main menu, select <ui-path>Navigate | Test</ui-path>.
</step>
<step>
Press <shortcut key="GotoTest"/>.
</step>
</procedure>
... more content ...
</chapter>
提供されたスニペットにはいくつかのメタ情報が含まれていることに気づくでしょう。 既に上記したようにその価値はあるのですが、それを追加の用途に使用することを阻むものはありません。
プラットフォーム依存のキーバインドを表現する {<shortcut>}
タグを考えてみてください。
このタグは、中間レイヤーの一部であり、ショートカットの言及を一元的に管理し、検証するために使用されます。
ドキュメント内でショートカットを挿入するためには、該当するアクションIDと共に {<shortcut>}
タグを使用します。たとえば、 {<shortcut key="CoolAction">}
のようにします。
ビルドプロセス中、ツールは {<shortcut>}
要素を検証し変換し、利用可能なキーマップの実際のキーバインドに変換します。
このアプローチにより、ショートカットは製品とドキュメンテーションの間で同期され、ドキュメンテーションのユーザーは好きなキーマップを選択する自由があります。 この機能を体験するためには、IntelliJ IDEAヘルプを訪れて、Shortcutsメニューで選択したキーマップによって、テキスト内のショートカットがどのように変化するかを観察してみてください:


それが {<shortcut>}
タグの主な目的ですが、このタグがRAGの強化にどのように有益であるかです。
最も直接的な使用法は、ヘルプページと同様に、AIチャットでプラットフォーム固有のショートカットを表示することです:


しかしながら、もっと興味深い側面があります。事実や指示を取得するためのインデックスを作成することと同様に、アクションIDを探し出すためのインデックスを作成することも可能です。
前に話したよりも単純なRAGのシナリオでは、同じ要素から埋め込みを生成し、それを取得するために使います。 しかし、アクションIDのインデックスについては、以下の構造を使用します:
- キーは、
{<shortcut>}
タグを含む要素から派生した埋め込みです。 - 値は、対応する
{<shortcut>}
タグ内のアクションIDです。


例えば、 {<shortcut key="GotoTest"/>}
の囲む要素は、
{<step>}
あるいは全体の {<procedure>}
になるでしょう:
<procedure title="Navigate to tests" type="choices">
<p>
When at a symbol declaration, you can navigate to the corresponding
tests by doing one of the following:
</p>
<step>
From the main menu, select <ui-path>Navigate | Test</ui-path>.
</step>
<step>
Press <shortcut key="GotoTest"/>.
</step>
</procedure>
コンテキストは重要
囲む要素のコンテンツをインデックス化することの重要性を示すために、IntelliJ IDEAの値の設定 (Set Value)機能を例に挙げてみましょう。 この機能は、プログラムがデバッグモードで一時停止している間に変数を更新するためのものです。
対応するアクションのIDは SetValue
です。
しかし、このIDだけでは特別な記述性がありません。
SetValue
や他の多くのIDはプログラミングでは一般的な単語の組み合わせであるため、これらのIDだけに基づいたセマンティックサーチでは、
偽陽性と偽陰性が許容できないほど多くなります。
追加のコンテキストをインデックスに含めなければ、このタスクは事実上不可能になります。
対照的に、アクションIDと周囲のコンテンツとの関係を確立することで、 AIアシスタントにその機能の詳細、一般的な使用ケース、制限についての詳細を提供します。 この情報は、取得の精度を大幅に向上させます。


クライアント部分
最後に、AIアシスタントが正しいアクションIDを持っていれば、そのアクションを提案し、 さらにチャットから直接それを呼び出すボタンを表示することもできます:


もちろん、この部分は単にUIにボタンを追加する以上の少し複雑なものです。 IDEのアクションはコンテキスト依存型であるため、実装する必要がある追加のチェックもありますが、 このトピックはIntelliJ Platformの開発に非常に特化しており、 それ自体が別の議論を要するものです。
他のマークアップ要素
本記事では、主にWritersideの {<shortcut>}
タグからアクションIDを取得する「アクション検索」機能に焦点を当てていました。
しかし、セマンティックマークアップの他のさまざまな要素タイプにも同じ原理を適用することができます。
すぐに使える例としては、ui-path要素があります。 この要素は、記述されている機能にアクセスするために必要な一連のUI要素(例えばメニューアイテム)を表しています。
<step>
Open the IDE settings (<shortcut key="ShowSettings"/>),
then navigate to <ui-path>Tools | Terminal</ui-path>.
</step>
ウェブヘルプでは長いパスを提供することは理にかなっていますが、 なぜなら通常、ウェブページから製品への直接のナビゲーションは実際的ではないからです。 一方で、製品でこれについて尋ねられた場合、対応する設定ページをすぐに表示する理由はありません:


まとめ
しばらく前、多くの人々はWeb 3.0という概念を描いていました。 そのアイデアは、ウェブ全体をセマンティックマークアップに移行させ、マシンがそれを人々と同じように利用できるようにすることでした。 これは実現しませんでしたが、同じアイデアが現代のツールや技術の観点から再び関連性を持つことが面白いです。
本記事で取り上げた機能は、既