前回、名乗ったサイトが応えるサイトになる、と最後に書いた。今回はその二段目、「問い合わせる」に上がる。
一段目の「見る」で、サイトは自分の意味を機械に差し出した。ただし、それは静的な差し出しだ。名札と地図を置いても、エージェントの側はまだ、ページを集めて読み、目当ての答えを自分で組み立てなければならない。二段目は、その手間をサイト側が引き受ける層だ。エージェントが自然言語で問い、サイトがその問いに、自分の持つ意味から答える。静的な地図が、応答する窓口になる。
静的な地図から、応える窓口へ
前回積んだSchema.orgのマークアップを思い出してほしい。あれは、ページの中に「これは商品」「価格は税込1,200円」という札を貼る作業だった。札は正確だが、受け身だ。エージェントが価格を知りたければ、ページを取得し、JSON-LDを解析し、目当ての値を自分で拾い出す。サイトは差し出すだけで、こちらから何かを返しはしない。
NLWebは、この関係を反転させる。「予算3万円以内で、在庫のある商品は?」と自然言語で問われたら、サイト側がその問いを解釈し、自分の持つデータから答えを組み立てて返す。ページを一枚ずつ読ませる代わりに、問い合わせられる窓口を一つ立てる。
NLWebは、Microsoftが2025年5月のBuild 2025で発表したオープンプロジェクトだ。構想し主導するのはR.V. Guha ―― RSS、RDF、そしてSchema.orgの生みの親で、MicrosoftにCVP兼Technical Fellowとして加わった。この血筋は偶然ではない。NLWebは新しい語彙を発明しない。前回整えたSchema.orgを、そのまま入力として使う。名札を貼る作業と、その札で会話する仕組みが、同じ人物の設計思想でつながっている。
位置づけを一言で表すなら、NLWeb自身の言葉が要を突いている。NLWebは、MCPやA2Aにとって、HTMLがHTTPに対して果たしたのと同じ役割を果たす、と。HTTPが通信の土管で、HTMLがその上を流れる中身の型だったように、MCPがエージェント通信の土管なら、NLWebはその上を流れる「自然言語で問い、意味で答える」中身の型にあたる。
NLWebの導入は、オープンソースの参照実装(Python)を自分で動かすことから始まる。自社サイトのデータを指し、自分で選んだLLMとベクトルストアの上で走らせる。手元のノートPCからクラウドまで、軽量に動くよう作られている。
どう動くのか ― 意味を、ベクトルに変えて問い合わせ可能にする
窓口の内側では、四つの段が順に動く。
まず、既存の構造化データを取り込む。Schema.org、RSS、JSONL、サイトマップ ―― サイトがすでに公開している半構造化データが入力になる。新しく何かを書き起こす必要は、原則ない。前回積んだ意味が、そのまま材料になる。
次に、それを埋め込み(ベクトル化)して、ベクトルストアに索引化する。ベクトルストアは選べる。Qdrant、PostgreSQL(pgvector)、Milvus、Azure AI Search、Elasticsearch、Snowflakeなど、主要なものはおおむね揃っている。ここで、テキストの意味が数値の座標に変換され、「意味の近いものを引く」検索が可能になる。
問いが来ると、三段目が動く。自然言語の質問を解釈し、ベクトルストアから関連するものを検索し、順位づけ(再ランク)する。この段は見た目より重い。参照実装では、一つの問いが、脱文脈化やランキングのために何度もLLMを呼び出すことがある。窓口の裏で、それだけの計算が走っている。
最後に、検索結果をもとにLLMが回答を組み立て、Schema.org形式のJSONで返す。返ってくる型は、Article、Product、Place、Recipe、Reviewなど、前回見たSchema.orgの型そのものだ。人間向けのUIはそれを整形して見せ、エージェントはそのまま構造として受け取る。
この流れで、二つ、押さえておきたい点がある。
一つは、答えの根拠が「あなたのデータ」だという点だ。NLWebは、LLMが世界一般について知っていることで答えるのではなく、あなたが索引化した内容から答えを引く。外部の知識を補助的に足すこともあるが、幹はあくまで自社データだ。これは、根拠を自社の一次情報に置く仕組み ―― 第6回で扱うRAGの考え方 ―― の、この層での現れだ。
もう一つは、この窓口が、そのままエージェント用の道具になるという点だ。すべてのNLWebインスタンスは、同時にMCPサーバーでもある。/askが人やアプリ向けの入口なら、/mcpはエージェント向けの入口で、askという一つのメソッドで自然言語の問いを受ける。つまり、MCP対応のアシスタントは、サイトごとの個別対応なしに、この窓口を呼べる。前回の名札が「読める」ための整備だったなら、今回の窓口は「呼べる」ための整備だ。(MCPを含む全体像は、以前まとめた。)
呼び方(どう問うか)は、いま見たとおり標準化されている。だが、その手前の見つけ方 ―― エージェントが、そもそも「untype.jpに窓口がある」とどう知るか ―― は、まだ固まっていない。今の主流は、使う側が接続先をあらかじめ登録しておく方式だ。生成AIに外部サービスを繋ぐ「コネクタ」の設定を思い浮かべればいい。誰かが繋いで、はじめて呼ばれる。窓口を立てただけで、世界中のエージェントが勝手に見つけに来るわけではない。
自動発見を標準化する動きは、始まってはいる。サイトが自分の能力の「目録」を決まった場所に置き、レジストリがそれを拾い、エージェントは「これに答えられる窓口はどこか」と問い合わせて辿り着く ―― 2026年6月、GoogleやMicrosoftなど11社が公開した共通仕様(ARD)の草案が出た。呼び方が先に決着し、見つけ方が後を追っている。この発見の層は、連載の後半で改めて扱う。
どこに、何を置くか
NLWebの実体は、サイトの隣に置くサーバーだ。自社サイトのデータを指し示し、/askと/mcpの二つのエンドポイントを立てる。感触をつかむだけなら、手順は短い。
git clone https://github.com/nlweb-ai/NLWeb
cd NLWeb
python -m venv myenv
source myenv/bin/activate
cd code
pip install -r requirements.txt
# .env.template を .env にコピーし、使うLLMとベクトルストアのキーを設定
python -m tools.db_load https://www.untype.jp/blog/rss.xml untype
python app-file.py
# → localhost:8000 に窓口が立つ
db_loadが、指定したフィードやSchema.orgデータを読み込み、ベクトルストアに索引化する。あとはサーバーを起動すれば、ローカルに問い合わせ可能な窓口ができる。既存のマークアップやRSSが揃っていれば、試作の立ち上げは速い。私が手元のRSSで試したところ、30分ほどでローカルに窓口が動いた。
ただし、これはあくまで試作の姿だ。本番については、参照実装のリポジトリ自身が釘を刺している。データはコピーせず「生きた」データベースに直結せよ(コピーは必ず鮮度のずれを生む)、スタンドアロンのサーバーを別に立てるより自分のアプリ環境にコードを組み込め、UIは付属のものでなく自前で作れ、と。試作は30分でも、実運用は別の仕事だ。
もう一段、取り込みの実際に踏み込んでおく。開発寄りの余談なので、判断だけ知りたい向きは読み飛ばしてかまわない。手間を分けるのは、意外にも「JSON-LDをHTMLに直書きするか、外部ファイルにするか」ではない。NLWebは入力が何であれ、内部ではSchema.orgのJSON-LDに正規化してから索引化する。だから効くのは別の軸だ ―― すでに一覧化されたフィード(RSSやJSONL、CSV)をdb_loadにそのまま渡すのか、それともページ群をクロールして各ページの<script type="application/ld+json">を抜き出すのか。前者はHTMLを経由せず、いちばん軽い。私が30分で動かしたのも、この経路だ。後者は抽出用のツールこそ用意されているが、ページの発見・取得・抽出という段取りが増える。さらに、JSON-LDをJavaScriptで後から差し込む作りだと、素のクロールでは見えず、もっとも重くなる。
だから、直書きのJSON-LDがすでにあるサイトでも、それをクロールさせるより、同じ情報源からフィードを一つ吐き出してdb_loadに渡すほうが速い。そのフィードを元データから毎回生成すれば、さきほどの「コピーは鮮度のずれを生む」も避けられる。そして置き場所以上に効くのが、型の質だ。直書きでもフィードでも、Productに価格や在庫、FAQPage、Articleと型がリッチなほど、ベクトルに載る意味が濃くなり、問い合わせの当たりがよくなる。どこに置くかより、どう型付けするか。前回のSchema.orgへの投資が、ここで二度目の配当を生む。
貼れる最小実例
窓口に問うのは、/askへのHTTPリクエスト一つだ。仕様はREST APIのドキュメントにまとまっている。最小の呼び出しはこうなる。
curl -X POST http://localhost:8000/ask \
-H "Content-Type: application/json" \
-d '{"query": "南青山で相談できるコミュニケーションデザインの会社は?", "site": "untype", "mode": "list"}'
返ってくるのは、Schema.orgの語彙で組まれたJSONだ。
{
"query_id": "…",
"results": [
{
"url": "https://www.untype.jp/service",
"name": "コミュニケーションデザイン",
"score": 87,
"description": "Web制作と、AIエージェント対応の診断・設計。",
"schema_object": { "@type": "Service", "provider": "株式会社アンタイプ" }
}
]
}
ここで効くパラメータが二つある。範囲設計の要になるので、名前だけでも覚えておきたい。
siteは、答えの土俵を絞る指定だ。一つのバックエンドが複数サイト分のデータを持つとき、siteでどのサイトの範囲で答えるかを限定できる。何でも答える窓口ではなく、「この範囲について答える窓口」に仕立てるための取っ手だ。
modeは、答え方の指定だ。listは該当するものを一覧で返す。summarizeは要約して返す。generateは、検索結果をもとにLLMが文章で答える ―― 従来のRAGに近い振る舞いをする。エージェントは選択肢の一覧(list)を欲しがることが多く、人間向けUIは要約(summarize)を好み、生成(generate)はうまくはまる場面が限られる。生成は便利だが、事実を作文する余地 ―― 幻覚の面積 ―― がいちばん大きいモードでもある。
なお、参照実装はサーバー側に会話の状態を持たない。だから複数ターンの会話では、直前までの問いをprevに渡して文脈を繋ぐ。窓口は毎回、渡された文脈のぶんだけを覚えている。
何を答えさせ、何を答えさせないか
この層の実装の勘所は、コードより設計にある。何を索引化し、どのモードを既定にし、どの範囲(site)で答えさせるか ―― この三つが、窓口の性格をほぼ決める。
取り違えは、だいたい四つの形で現れる。
一つ目は、NLWebを「チャットボットを置くこと」と混同する取り違えだ。NLWebの設計思想は、派手な対話UIを足すことではなく、安定した契約(contract)を一つ用意することにある。どのUIから来ても、どのエージェントから来ても、同じ問い合わせ方で、同じ構造の答えが返る。見た目のチャット窓ではなく、裏の契約を作っている ―― この認識がずれると、評価軸ごとずれる。
二つ目は、generateモードを安易に既定にする取り違えだ。生成は口当たりがいいが、根拠の薄い合成回答を許しやすい。窓口の目的が「自社データを正確に引く」ことなら、既定はlistやsummarize寄りにして、生成は要る場面に限る、という判断がいる。
三つ目は、索引した対象=答えられる範囲、という当たり前を意識しないまま、手元のデータを全部入れてしまう取り違えだ。入れれば、答える。だから、答えてほしくないもの ―― 下書き、内部向けの情報、古い版 ―― を混ぜれば、窓口はそれも平然と差し出す。何を入れないか、が範囲設計の半分を占める。
四つ目は、鮮度だ。前回のSchema.orgと同じ急所が、ここにもある。索引をコピーで作ると、元データを直しても索引は古いまま答え続ける。リポジトリが「生きたデータベースに直結せよ」と言うのは、この陳腐化を避けるためだ。
どの規模で、意味を持つか
NLWebが効くのは、問い合わせるに足る中身が、構造化された形である場所だ。早期採用の顔ぶれがそれを物語っている。Shopify、Allrecipes、Tripadvisorといった、商品・レシピ・旅行情報を大量に持ち、以前からSchema.orgに投資してきたサイトだ。ほかにEventbrite、O'Reilly Media、Hearstなども名を連ね、WordPress向けにはYoastが2026年3月、構造化データを一つにまとめるSchema Aggregation機能として実装した。カタログ、ドキュメント、レシピ、旅行情報 ―― 項目が多く、人もエージェントも「探して絞りたい」場所ほど、窓口の価値が立つ。
逆に、数ページの会社案内サイトには過剰だ。窓口を立てるコストが、問い合わせられる中身の薄さに見合わない。
コスト面も直視しておく。さきほど触れたとおり、一つの問いが裏で何度もLLM呼び出しに展開されうる。つまり費用は、問い合わせの量に比例して積み上がる。加えて、インフラの運用、データの整備、そしてこの技術がまだ発展途上で、事例も道具もこれから増える段階だという現実がある。「流行っているから置く」で始めると、費用だけが先に立つ。
だから判断はこうなる。問い合わせに足るだけの構造化された中身があり、人やエージェントがそこを「探して絞る」ことが事業上ありうるなら、窓口を立てる価値がある。そうでなければ、まだ早い。(NLWeb単体の費用対効果は、以前詳しく扱った。今回は、実装ガイドの一層として、他の層との接続の中に置き直している。)
この層で確かめること(観点だけ)
前回と同じく、この層も二段で見る。何を入れるか(Do)は、ここまでに書いた。既存のSchema.org/RSSを索引化し、siteとmodeで範囲と答え方を設計し、/askと/mcpで窓口を立てる。では、それが意図どおりに働いているかを、どの観点で見るか。四つ挙げる。合否をどこで切るかという判定基準は、ここには書かない。見るべき観点までを示す。
第一に、意図した意味と範囲で答えているか。索引した対象、siteの指定、modeの既定 ―― この設計が、事業として答えさせたい範囲と一致しているか。窓口は設計どおりにしか答えない。設計が曖昧なら、答えも曖昧になる。
第二に、答えるべきでない情報に答えていないか。範囲外のデータが索引に紛れていないか。generateが、根拠のない合成回答を返していないか。人間向けの表示では隠れている内部情報を、窓口が平然と差し出していないか。この「範囲外露出」は、入れた覚えのないものではなく、入れた覚えのあるものから漏れる。
第三に、答えが一次情報(正典)に基づいているか。コピーした索引が陳腐化して、実態と違う答えを返していないか。答えの出所が、推測や外部の一般知識ではなく、自社の正しいデータに根ざしているか。この観点は、第6回のRAG ―― 根拠をどう据えるか ―― に直接つながる。
第四に、会話ゆえの新しい入口を塞げているか。自然言語で問いを受ける以上、悪意ある問い ―― プロンプトインジェクション ―― で、窓口を範囲外の振る舞いへ誘導される危険がある。読み取り中心のこの層でも、入口が言葉である以上、そのリスクはゼロにならない。ここも第6回のセキュリティで正面から扱う。
この四つのうち、機械にすぐ任せられるものと、そうでないものがある。エンドポイントが立っているか、JSONが仕様どおり返るか、といった形式面は、自動で確かめられる。だが「意図した範囲で答えているか」「範囲外を漏らしていないか」「正典に基づいているか」は、窓口の中身と事業の実態を突き合わせなければ判断できない。窓口が動くことと、正しく答えることは、別のことだ。前者は機械に、後者は人に残る。前回と同じ線引きが、この層でも引かれる。
次回
問いに答える窓口ができたら、次は動かす。第4回は「操作の層」、WebMCPを扱う。この連載の主役だ。会話までは、基本が読み取りだった。間違っても、間違った答えが返るだけで済む。だが操作は副作用を持つ。予約を入れる、注文を出す、設定を変える。エージェントに渡す権限が、ここで一段上がる。応えるサイトが、動かせるサイトになる話だ。
参考情報
この記事をシェアする