はじめに
先日10/29に発表されたNovaのWeb Groundingを試してみました。
現状対応しているモデルはNova Premierのみで、他のNovaモデルも近日中にサポートされるようです。
料金
1,000リクエストあたり $30 です。
簡単に試算してみるとこんな感じになります。
| ユーザー数 | リクエスト/日 | 利用日数/月 | リクエスト/月 | $/月 |
|---|---|---|---|---|
| 10 | 10 | 20 | 2,000 | 60 |
| 100 | 10 | 20 | 20,000 | 600 |
個人的には高価な印象を受けましたが、Nova Premierだからなのかもしれません。
安全性
検索内容がAWSの外に出ることはないそうです。
これはセキュリティ面でありがたいと感じました。
Your data never leaves AWS infrastructure. Model-generated queries stay within AWS services and are never sent to the broader internet. Our expansive internal web search index and knowledge graphs prioritize trustworthy and high quality sources and filter malicious content on ingress. Web Grounding further refines the information at runtime by cross-referencing from multiple sources. Finally, we protect your application against indirect prompt injection and misinformation with runtime filtering (note that this mitigation is limited for non-English languages).
(翻訳)
お客様のデータはAWSインフラストラクチャ外に出ることはありません。モデルが生成したクエリはAWSサービス内に留まり、外部インターネットへ送信されることはありません。当社の広範な内部ウェブ検索インデックスとナレッジグラフは、信頼性の高い高品質な情報源を優先し、悪意のあるコンテンツを流入時にフィルタリングします。Web Groundingは複数の情報源からの相互参照により、実行時に情報をさらに精緻化します。最後に、実行時フィルタリングにより間接的なプロンプト注入や誤情報からアプリケーションを保護します(非英語言語ではこの対策に制限がある点にご注意ください)。
試してみた
こちらのブログに記載されているコードを動かしてみました。
グラウンディング無し
まずはグラウンディング無しで、Novaが知らないと思われることを聞いてみました。
import boto3
def main():
session = boto3.Session(region_name="us-east-1")
client = session.client("bedrock-runtime")
question = "Bedrock NovaにWeb Groundingが実装されたのはいつですか?"
conversation = [
{
"role": "user",
"content": [{"text": question}],
}
]
model_id = "us.amazon.nova-premier-v1:0"
response = client.converse(
modelId=model_id,
messages=conversation,
)
print(response["output"]["message"]["content"][0]["text"])
if __name__ == "__main__":
main()
回答は下記のとおりで、見事にハルシネーションが発生しています。
Amazon Bedrockのエージェント機能であるAgents for Amazon Bedrockにおいて、Web Grounding機能が発表されたのは2024年7月です。この機能により、エージェントはAPIを介して外部データソースとリアルタイムでやり取りし、より正確な回答を生成
できるようになりました。ただし、具体的な実装日については、公式のAWSドキュメントやリリースノートで確認することをお勧めします。
グラウンディング有り(リージョン制限有り環境)
Converse APIのパラメータにnova_groundingを付与するだけでWeb検索が利用できます。
シンプルでとても簡単です。
import json
import boto3
def main():
session = boto3.Session(region_name="us-east-1")
client = session.client("bedrock-runtime")
question = "Bedrock NovaにWeb Groundingが実装されたのはいつですか?"
conversation = [
{
"role": "user",
"content": [{"text": question}],
}
]
model_id = "us.amazon.nova-premier-v1:0"
response = client.converse(
modelId=model_id,
messages=conversation,
toolConfig={"tools": [{"systemTool": {"name": "nova_grounding"}}]},
)
print(json.dumps(response, indent=2, ensure_ascii=False))
if __name__ == "__main__":
main()
しかし、下記のエラーが発生しました。SCPにより拒否されたようです。
botocore.errorfactory.AccessDeniedException: An error occurred (AccessDeniedException) when calling the Converse operation: User: arn:aws:sts::012345678912:assumed-role/xxx is not authorized to perform: bedrock:InvokeTool on resource: arn:aws:bedrock::012345678912:system-tool/amazon.nova_grounding with an explicit deny in a service control policy
試した環境は、Control Towerによりリージョンが制限されている環境でしたが、us.amazon.nova-premier-v1:0で利用されるリージョンus-east-1 us-east-2 us-west-2は許可されていました。
気になったのは、InvokeToolというアクションが初見なような気がしたことと、ARN arn:aws:bedrock::012345678912:system-tool/amazon.nova_groundingにリージョンが記載されていない点でした。
Web Groundingのドキュメントを見てみると、このエラーに関連しそうなことが書いてありました。
Web Grounding has the aws:requestedRegion condition key set to “unspecified”. If your existing policies or Service Control Policies (SCPs) enforce this condition, you may encounter access issues. Updating the condition to allow an "unspecified" requestedRegion can resolve this problem.
(翻訳)
Web Grounding では、aws:requestedRegion 条件キーが「unspecified」に設定されています。既存のポリシーまたはサービス制御ポリシー (SCP) でこの条件が強制されている場合、アクセス問題が発生する可能性があります。条件を更新して「unspecified」の requestedRegion を許可することで、この問題を解決できます。
Control Towerのリージョン拒否コントロール GRREGIONDENY では、まさにaws:RequestedRegionが利用されているため、今回のエラーはエラーメッセージのとおりリージョン拒否のSCPによりアクセス拒否されたことが原因であることがわかりました。
対処としては
「unspecified」の requestedRegion を許可する
ことですが、unspecifiedを単純に追加してよいのか、想定外のアクセス許可を付与することにならないか、確認した方が良さそうな気がします。
Claude Sonnet4.5に聞いてみたら以下の回答でした。
潜在的なリスク
"unspecified" を追加することで許可される可能性があるもの:リスク1: 将来の新サービス
- 将来追加されるグローバルサービスで、NotAction に含まれていないもの
- 例: 新しいAIサービスのグローバル機能
リスク2: 既存サービスの新機能
- 既存サービスに追加される "unspecified" を使う新機能
- 例: BedrockのWeb Grounding以外の将来の機能
なお、InvokeToolアクションは、11/4時点ではまだサービス認可リファレンスに記載がありませんでした。
グラウンディング有り(リージョン制限無し環境)
ということで、ひとまずリージョン制限が無い環境で試してみることにしました。
同じコードを実行したところ、正常にレスポンスが返ってきて、正しい情報を回答してくれました!
{
"ResponseMetadata": {
"RequestId": "cb87f67f-6186-4888-aef9-414a39939264",
"HTTPStatusCode": 200,
"HTTPHeaders": {
"date": "Fri, 31 Oct 2025 11:44:47 GMT",
"content-type": "application/json",
"content-length": "2303",
"connection": "keep-alive",
"x-amzn-requestid": "cb87f67f-6186-4888-aef9-414a39939264"
},
"RetryAttempts": 0
},
"output": {
"message": {
"role": "assistant",
"content": [
{
"text": "<thinking>The user asks if I know about web grounding in Bedrock Nova. Need to verify this feature's existence first.</thinking>
},
{
"toolUse": {
"toolUseId": "tooluse_KCcpbIEQC41lR1KEjM424A",
"name": "nova_grounding",
"input": {
"query": "Bedrock NovaにWeb Groundingが実装されたことを知っていますか?"
},
"type": "server_tool_use"
}
},
{
"toolResult": {
"toolUseId": "tooluse_KCcpbIEQC41lR1KEjM424A",
"content": [
{
"text": "[HIDDEN]"
}
],
"status": "success",
"type": "nova_grounding_result"
}
},
{
"text": "<thinking>The user's question requires confirmation about the implementation of Web Grounding in Bedrock Nova. The search resultcifically mentioning Nova Premier. The feature was announced as generally available and allows retrieval of real-time information to enhance accuraNova Premier initially), and the purpose of reducing hallucinations via citations. The response should directly acknowledge the feature's existenceingが実装されました"
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://cloudsteak.com/aws-web-grounding-build-accurate-ai-applications-with-amazon-nova-models/",
"domain": "cloudsteak.com"
}
}
}
]
}
},
{
"text": "。この機能は2025年10月29日に発表され、Novaモデルで利用できるようになりました"
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://cloudsteak.com/aws-web-grounding-build-accurate-ai-applications-with-amazon-nova-models/",
"domain": "cloudsteak.com"
}
]
}
},
{
"text": "。Web Groundingを使用すると、リアルタイムの情報を取得して回答に組み込むことができ、出力の正確性が向上します"
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://cloudsteak.com/aws-web-grounding-build-accurate-ai-applications-with-amazon-nova-models/",
"domain": "cloudsteak.com"
}
}
}
]
}
},
{
"text": "。"
}
]
}
},
"stopReason": "end_turn",
"usage": {
"inputTokens": 365,
"outputTokens": 223,
"totalTokens": 588
},
"metrics": {
"latencyMs": 10870
}
}
ブログの以下の記載のとおり、ツール実行結果は[HIDDEN]となっています。
The content of the responses from these external calls appear as [HIDDEN] – a standard practice in AI systems that both protects sensitive information and helps manage output size.
(翻訳)
これらの外部呼び出しからの応答内容は[HIDDEN]として表示されます。これはAIシステムにおける標準的な手法であり、機密情報を保護すると同時に出力サイズの管理にも役立ちます。
nova_web_grounding_tutorial を参考にして、レスポンスの整形もやってみました。
※チュートリアルのformat_bedrock_response関数を利用しましたが、同じURLが複数回登場した際に別の引用ソースとして列記されるので、重複が排除されるよう変更しています。
import json
import re
import boto3
def format_bedrock_response(response):
"""
Format the Bedrock response to show clean text with citations
Args:
response: Raw Bedrock response dictionary
Returns:
Formatted text with inline citations and sources list
"""
if not response or "output" not in response:
return "No response to format."
message = response["output"]["message"]
content = message.get("content", [])
result_parts = []
citation_counter = 1
all_citations = {}
url_to_citation_num = {}
# Process content items sequentially
i = 0
while i < len(content):
item = content[i]
# Handle text content
if "text" in item:
text = item["text"]
# Skip tool use items
if "toolUse" in item:
i += 1
continue
# Remove thinking tags completely
text = re.sub(r"<thinking>.*?</thinking>", "", text, flags=re.DOTALL)
text = re.sub(r"</?thinking[^>]*>", "", text)
# Clean up the text
text = text.strip()
# Only process non-empty text
if text:
# Collect all citations following this text
citations_for_this_text = []
j = i + 1
# Process all consecutive citationsContent items
while j < len(content) and "citationsContent" in content[j]:
citation_data = content[j]["citationsContent"]
if "citations" in citation_data:
for citation in citation_data["citations"]:
if "location" in citation and "web" in citation["location"]:
web_info = citation["location"]["web"]
url = web_info.get("url", "")
domain = web_info.get("domain", "")
if url and domain:
# Check if this URL is already tracked
if url not in url_to_citation_num:
# New citation - add it
url_to_citation_num[url] = citation_counter
all_citations[citation_counter] = (domain, url)
citations_for_this_text.append(citation_counter)
citation_counter += 1
else:
# Duplicate - reuse existing citation number
citations_for_this_text.append(
url_to_citation_num[url]
)
j += 1
# Add citation numbers to this text
if citations_for_this_text:
for cit_num in citations_for_this_text:
text += f"[{cit_num}]"
# Skip all the citation items we processed
i = j - 1
result_parts.append(text)
i += 1
# Join all text parts with proper spacing
result = "".join(result_parts)
# Clean up any double spaces or formatting issues
result = re.sub(r"\s+", " ", result)
result = re.sub(r"\n\s*\n", "\n\n", result)
# Add sources section if we have citations
if all_citations:
result += "\n\n**Sources:**\n"
for num, (domain, url) in all_citations.items():
result += f"{num}. {domain}: {url}\n"
# Final cleanup
result = re.sub(r"\n\n\n+", "\n\n", result)
result = result.strip()
return result
def main():
session = boto3.Session(region_name="us-east-1")
client = session.client("bedrock-runtime")
question = "Bedrock NovaにWeb Groundingが実装されたのはいつですか?"
conversation = [
{
"role": "user",
"content": [{"text": question}],
}
]
model_id = "us.amazon.nova-premier-v1:0"
response = client.converse(
modelId=model_id,
messages=conversation,
toolConfig={"tools": [{"systemTool": {"name": "nova_grounding"}}]},
)
print("=== Raw Response ===")
print(json.dumps(response, indent=2, ensure_ascii=False))
result = format_bedrock_response(response)
print("=== Formatted Response ===")
print(result)
if __name__ == "__main__":
main()
今回は、ソースとしては的確なものを参照できていますが、日付が10/27になっていました。
タイムゾーンを考慮しても10/29が10/27にはならないような気がします・・・
Bedrock NovaにWeb Groundingが実装されたのは、2025年10月27日です[1][2][3]。 この機能は、Amazon BedrockのNovaモデルに組み込まれた新しいツールで、公開されている情報を引用しながら回答を生成することができます[1]。 これにより、出力の信頼性が向上し、ハルシネーションが減少することが期待されます[1]。
**Sources:**
1. amazon.com: https://aws.amazon.com/tw/blogs/aws/build-more-accurate-ai-applications-with-amazon-nova-web-grounding/
2. mwpro.co.uk: https://mwpro.co.uk/blog/2025/10/29/web-grounding-build-accurate-ai-applications-with-amazon-nova-models/
3. thetechstreetnow.com: https://www.thetechstreetnow.com/tech/build-more-accurate-ai-applications-with-amazon-nova-web-grounding/15510060202664548815/15510060202664548815/
レスポンス全量
{
"ResponseMetadata": {
"RequestId": "48da13b5-1aa2-433a-9956-3a6c22bc78b1",
"HTTPStatusCode": 200,
"HTTPHeaders": {
"date": "Tue, 04 Nov 2025 05:51:10 GMT",
"content-type": "application/json",
"content-length": "2384",
"connection": "keep-alive",
"x-amzn-requestid": "48da13b5-1aa2-433a-9956-3a6c22bc78b1"
},
"RetryAttempts": 0
},
"output": {
"message": {
"role": "assistant",
"content": [
{
"text": "<thinking>Bedrock Nova's web grounding release date needed.</thinking>\n"
},
{
"toolUse": {
"toolUseId": "tooluse_XbYgrM63wOLM-T82-UTcZQ",
"name": "nova_grounding",
"input": {
"query": "When was web grounding implemented in Bedrock Nova?"
},
"type": "server_tool_use"
}
},
{
"toolUse": {
"toolUseId": "tooluse_BqbMzWOA3pKs3nwVhON8Mw",
"name": "nova_grounding",
"input": {
"query": "Bedrock Nova web grounding release date"
},
"type": "server_tool_use"
}
},
{
"toolResult": {
"toolUseId": "tooluse_XbYgrM63wOLM-T82-UTcZQ",
"content": [
{
"text": "[HIDDEN]"
}
],
"status": "success",
"type": "nova_grounding_result"
}
},
{
"toolResult": {
"toolUseId": "tooluse_BqbMzWOA3pKs3nwVhON8Mw",
"content": [
{
"text": "[HIDDEN]"
}
],
"status": "success",
"type": "nova_grounding_result"
}
},
{
"text": "Bedrock NovaにWeb Groundingが実装されたのは、2025年10月27日です"
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://aws.amazon.com/tw/blogs/aws/build-more-accurate-ai-applications-with-amazon-nova-web-grounding/",
"domain": "amazon.com"
}
}
}
]
}
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://mwpro.co.uk/blog/2025/10/29/web-grounding-build-accurate-ai-applications-with-amazon-nova-models/",
"domain": "mwpro.co.uk"
}
}
}
]
}
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://www.thetechstreetnow.com/tech/build-more-accurate-ai-applications-with-amazon-nova-web-grounding/15510060202664548815/15510060202664548815/",
"domain": "thetechstreetnow.com"
}
}
}
]
}
},
{
"text": "。\n\nこの機能は、Amazon BedrockのNovaモデルに組み込まれた新しいツールで、公開されている情報を引用しながら回答を生成することができます"
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://aws.amazon.com/tw/blogs/aws/build-more-accurate-ai-applications-with-amazon-nova-web-grounding/",
"domain": "amazon.com"
}
}
}
]
}
},
{
"text": "。\n\nこれにより、出力の信頼性が向上し、ハルシネーションが減少することが期待されます"
},
{
"citationsContent": {
"citations": [
{
"location": {
"web": {
"url": "https://aws.amazon.com/tw/blogs/aws/build-more-accurate-ai-applications-with-amazon-nova-web-grounding/",
"domain": "amazon.com"
}
}
}
]
}
},
{
"text": "。"
}
]
}
},
"stopReason": "end_turn",
"usage": {
"inputTokens": 44,
"outputTokens": 144,
"totalTokens": 188
},
"metrics": {
"latencyMs": 10280
}
}
ストリーミング
ストリーミングも試してみました。
import boto3
def main():
session = boto3.Session(region_name="us-east-1")
client = session.client("bedrock-runtime")
question = "サッカー男子日本代表はブラジルに勝ったことがありますか?2025年の情報を教えてください。"
conversation = [
{
"role": "user",
"content": [{"text": question}],
}
]
model_id = "us.amazon.nova-premier-v1:0"
response = client.converse_stream(
modelId=model_id,
messages=conversation,
toolConfig={"tools": [{"systemTool": {"name": "nova_grounding"}}]},
)
for chunk in response["stream"]:
if "contentBlockDelta" in chunk:
delta = chunk["contentBlockDelta"]["delta"]
if "text" in delta:
print(delta["text"], end="", flush=True)
elif "toolUse" in delta:
print(f"\n[TOOL_USE: {delta['toolUse']}]\n", end="", flush=True)
elif "citation" in delta:
print(f"\n[CITATION: {delta['citation']}]\n", end="", flush=True)
if __name__ == "__main__":
main()
レスポンスは下記のようになりました。今回は直近の情報を取得することができなかったようです。
<thinking>日本代表vsブラジルの試合結果を調べるべき</thinking>
[TOOL_USE: {'input': '{"query":"サッカー男子日本代表はブラジルに勝ったことがありますか?2025年の情報を教えてください。"}'}]
<thinking>現時点でサッカー男子日本代表がブラジルに勝利したことはありません。直近の試合結果を確認しても、日本がブラジルに勝利した記録は見つかりませんでした。両チームの過去の対戦成績を振り返っても、日本がブラジルに勝ったことはないという事実が確認できます。</thinking>
サッカー男子日本代表は、これまでブラジルに勝利したことはありません。
両チームのこれまでの対戦成績は以下の通りです:
- 1995年 アンブロ・カップ:日本 0-5 ブラジル
- 1996年 アトランタ五輪:日本 0-1 ブラジル
- 1999年 コパ・アメリカ:日本 0-4 ブラジル
- 2001年 コンフェデレーションズカップ:日本 0-0 ブラジル (PK戦 0-2)
- 2002年 日韓ワールドカップ:日本 0-2 ブラジル
- 2003年 コンフェデレーションズカップ:日本 1-2 ブラジル
- 2005年 コンフェデレーションズカップ:日本 2-2 ブラジル
- 2006年 親善試合:日本 0-1 ブラジル
- 2013年 コンフェデレーションズカップ:日本 0-3 ブラジル
- 2017年 親善試合:日本 1-3 ブラジル
- 2022年 親善試合:日本 0-1 ブラジル
日本はブラジルと過去11回対戦していますが、未だ勝利したことはありません。最近の対戦は2022年11月の親善試合で、この試合でも日本は0-1で敗れています。2025年も現時点では日本とブラジルの対戦は予定されていないため、新たな勝利記録は生まれていません。
精度
サッカーに関する会話では、最初の数回は正しく回答してくれず、何度か試しました。
今回少し試したかぎりでは、すごく良いかというと、そうでもないような印象を受けました。
シンプルに利用できるところは魅力的ですが、その分カスタマイズできないので、精度を上げるためには質問文を変えてみたり複数回聞いてみたりする工夫が必要なのかもしれません。
さいごに
軽く使ってみての個人的な感想です。
- 利用するのが容易
- 検索内容がAWS外に出ない
- コストが高いかも
- 精度面が不安
弊社では一緒に働く仲間を募集中です!
現在、様々な職種を募集しております。
カジュアル面談も可能ですので、ご連絡お待ちしております!
募集内容等詳細は、是非採用サイトをご確認ください。
