Python: feat: add Amazon Bedrock Knowledge Base tool and context provider - #8173
Python: feat: add Amazon Bedrock Knowledge Base tool and context provider#8173Vidyadhar Pogul (PVidyadhar) wants to merge 6 commits into
Conversation
- Created BedrockKnowledgeBaseTool with async run() + get_tool_definition() - Created BedrockKnowledgeBaseProvider (ContextProvider subclass) with before_run() - Two integration points: standalone tool + automatic context injection - Supports managed search and agentic retrieval with fallback - Unit tests included - Added BEDROCK_MANAGED_KB.md design doc
Addresses reviewer feedback (@moonbox3): when the provider is used with BedrockChatClient, injecting retrieved context as a separate user message produced two consecutive user turns in _prepare_bedrock_messages (which does not coalesce same-role messages). Route the retrieved context through extend_instructions() so it lands in Bedrock's system field, separate from the conversation array. This is model-agnostic and also avoids adding untrusted content as a system conversation message. - provider uses context.extend_instructions(self.source_id, ...) - removed unused Message import - updated tests to assert on context.instructions - 65 tests pass, verified E2E via agent.run() with BedrockChatClient + live KB
|
This PR continues from #7066, which could not be reopened after a force-push (GitHub rejected the reopen with a validation error). All prior review feedback from #7066 is carried over here. Notably addressing Evan Mattson (@moonbox3)'s comment from #7066 about consecutive cc Evan Mattson (@moonbox3) Eduard van Valkenburg (@eavanvalkenburg) — thanks for the earlier reviews on #7066. |
There was a problem hiding this comment.
🟡 Changes recommended
Retrieved content is elevated to system instructions, the lockfile is stale, and package guidance needs updating.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds Amazon Bedrock Knowledge Base retrieval as an agent tool and automatic context provider, replacing #7066.
Changes:
- Adds agentic retrieval with standard retrieval fallback.
- Adds automatic Knowledge Base context injection.
- Adds samples, tests, documentation, and newer AWS SDK requirements.
File summaries
| File | Description |
|---|---|
tests/test_bedrock_knowledge_base.py |
Tests tool and provider behavior. |
samples/README.md |
Documents sample patterns and permissions. |
samples/bedrock_kb_tool.py |
Demonstrates tool-based retrieval. |
samples/bedrock_kb_context_provider.py |
Demonstrates provider-based retrieval. |
samples/__init__.py |
Initializes the samples package. |
pyproject.toml |
Raises AWS SDK dependency floors. |
BEDROCK_MANAGED_KB.md |
Documents managed Knowledge Base support. |
_knowledge_base.py |
Implements the retrieval tool. |
_knowledge_base_provider.py |
Implements automatic context retrieval. |
__init__.py |
Exports the new public APIs. |
Review details
- Files reviewed: 10/10 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| "boto3>=1.43.32,<2.0.0", | ||
| "botocore>=1.43.32,<2.0.0", |
| from ._knowledge_base import BedrockKnowledgeBaseTool | ||
| from ._knowledge_base_provider import BedrockKnowledgeBaseProvider |
- Keep retrieved KB passages as untrusted user-role context instead of elevating to system instructions (matches azure-cosmos-memory convention; avoids stored prompt-injection). Solve Bedrock role alternation by coalescing adjacent user-role messages in _prepare_bedrock_messages (assistant turns left untouched to preserve tool-use/tool-result pairing). - Regenerate python/uv.lock for the boto3/botocore >=1.43.32 floor. - Add BedrockKnowledgeBaseTool/Provider to bedrock AGENTS.md class list. - Tests: coalescing + no-coalesce-across-assistant cases; 67 pass. Verified E2E via agent.run() with BedrockChatClient + live KB.
|
Thanks Copilot — addressed all three in 9f8ea75:
67 unit tests pass; lint clean. |
There was a problem hiding this comment.
🟡 Changes recommended
Agentic results are incorrectly formatted, valid source types are omitted, and the implementation contradicts the stated context-injection design.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
python/packages/bedrock/agent_framework_bedrock/_knowledge_base.py:45
- This extractor omits valid Retrieve location variants, so citations are blank for Salesforce, Kendra, SQL, OneDrive, and Google Drive knowledge-base results even though the supported SDK response union includes them. Handle every location variant exposed by the dependency floor/current supported releases.
python/packages/bedrock/agent_framework_bedrock/_knowledge_base.py:153 - AgenticRetrieveStream synthesizes a generated answer by default, but this implementation discards both
generatedResponseandresponseEventand only formats retrieved items. That adds avoidable model latency and cost on every agentic lookup; disable response generation when requesting retrieval-only output.
python/packages/bedrock/agent_framework_bedrock/_knowledge_base_provider.py:139 - This provider does not implement the PR description's stated fix: the description says retrieved passages now use
context.extend_instructions()and that tests assertcontext.instructions, while this code and its test still add a user-role context message and rely on a new global serializer behavior. Please align the implementation/tests and description so the intended trust boundary and compatibility behavior are reviewable.
- Files reviewed: 13/14 changed files
- Comments generated: 2
- Review effort level: Balanced
Addresses second Copilot review on microsoft#8173: 1. AgenticRetrieveStream results use a different schema (content/metadata/ sourceRetriever) than standard Retrieve (score/location). Previously every agentic result was normalized to score 0 with a blank source. Now parse the source URI from metadata._source_uri and omit the score (managed reranking does not expose one); the formatter only renders a score when present. Updated the agentic test mock to the real SDK schema. 2. Restrict _prepare_bedrock_messages coalescing to messages whose ORIGINAL role is 'user', so tool-result turns (role='tool', which map to Bedrock 'user') are never merged into a preceding user text turn. This keeps function-call/tool-result serialization unchanged. Added a regression test for the tool-call/tool-result path. Verified E2E against live KB: agentic results show real source URLs and no fabricated scores. 68 unit tests pass.
|
Thanks Copilot — both addressed in dfd0d2f:
68 unit tests pass; lint clean. |
There was a problem hiding this comment.
🟡 Changes recommended
Agentic retrieval performs unused response generation, the IAM examples deny agentic calls, and provider behavior contradicts the PR description.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
python/packages/bedrock/BEDROCK_MANAGED_KB.md:59
bedrock:AgenticRetrieveStreamdoes not support resource-level permissions, so this KB-scoped policy will deny the agentic request and force the tool down its fallback path. Grant that action in a separate statement withResource: "*", while retaining the KB ARN forbedrock:Retrieve.
python/packages/bedrock/samples/README.md:35bedrock:AgenticRetrieveStreamis not resource-scopable, so granting it only on a knowledge-base ARN produces an implicit deny. Split it into a separate statement withResource: "*"; keepbedrock:Retrievescoped to the KB ARN.
- Files reviewed: 13/14 changed files
- Comments generated: 2
- Review effort level: Balanced
| context.extend_messages( | ||
| self.source_id, | ||
| [Message(role="user", contents=[f"{self.context_prompt}\n\n{retrieved_context}"])], | ||
| ) |
Addresses third Copilot review on microsoft#8173: - AgenticRetrieveStream defaults to generating a response (verified: 331 streamed responseEvents when omitted vs 0 with generateResponse=False). The tool only formats retrieval passages and discards generation, so pass generateResponse=False to avoid unnecessary model generation latency/cost. - Added a test asserting generateResponse=False is sent. - PR description updated separately to match the actual implementation (user-role injection + serializer coalescing, not extend_instructions). 68 unit tests pass; verified generateResponse behavior against live API.
|
Thanks Copilot — both addressed:
68 unit tests pass; lint clean. |
There was a problem hiding this comment.
🟡 Changes recommended
IAM guidance, citation handling, public namespace exports, serializer documentation, and formatting need correction.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (5)
Previously missed (4) — in code that hasn't changed since the last review.
python/packages/bedrock/agent_framework_bedrock/init.py:8
- These package-level exports are not wired into the repository's documented public connector namespace.
agent_framework.amazon.__init__.pyand its.pyicurrently omit both names, sofrom agent_framework.amazon import BedrockKnowledgeBaseToolfails and type checkers cannot discover either API. Add both lazy runtime mappings and stub/__all__exports, consistent with the existing Bedrock classes there.
python/packages/bedrock/agent_framework_bedrock/_knowledge_base.py:45 - The fallback currently drops citations for valid Bedrock
Retrievelocation variants: the supported response union also includes Google Drive, OneDrive, Kendra, Salesforce, and SQL. Those results are still returned, but both the tool and provider render an empty source. Handle every location variant supported by the new SDK floor.
python/packages/bedrock/BEDROCK_MANAGED_KB.md:61 bedrock:AgenticRetrieveStreamhas no resource-level IAM type, so scoping it to a Knowledge Base ARN implicitly denies the agentic call and makes the documented tool silently fall back to standard retrieval. Keepbedrock:Retrievescoped to the KB ARN, but grantAgenticRetrieveStreamin a separate statement withResource: "*".
python/packages/bedrock/samples/README.md:37bedrock:AgenticRetrieveStreamis not resource-scopable, so this sample policy denies that action and the default tool never performs agentic retrieval. Split it into a statement withResource: "*", while retaining the Knowledge Base ARN restriction forbedrock:Retrieve.
python/packages/bedrock/agent_framework_bedrock/_chat_client.py:505
- This changes provider serialization but the required function-calling scenario matrix has not been updated.
python/AGENTS.md:60-67requires every provider-serialization change to updatedocs/specs/004-python-function-calling-loop.mdand its scenario-to-test mapping; add the adjacent-user invariant and the new Bedrock regression tests there.
# Coalesce adjacent genuine user-role turns only. Context providers
# (e.g. the Bedrock Knowledge Base provider) inject retrieved passages as
# separate user messages that would otherwise sit next to the real user
# input and violate Bedrock's role-alternation requirement. We restrict
- Files reviewed: 13/14 changed files
- Comments generated: 1
- Review effort level: Balanced
| import asyncio | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| from agent_framework import FunctionTool, ContextProvider |
|
please use the default PR template Vidyadhar Pogul (@PVidyadhar) |
feat: add Amazon Bedrock Knowledge Base tool and context provider
Continues from #7066 (that PR could not be reopened via the UI after a force-push). Same branch, all prior review feedback addressed.
Motivation & Context
Enables Agent Framework agents to retrieve context from Amazon Bedrock Knowledge Bases. Adds RAG capabilities using AWS's managed infrastructure without requiring users to manage their own vector stores or embedding pipelines.
Description & Review Guide
Major changes:
BedrockKnowledgeBaseTool— subclassesFunctionToolwith agentic retrieval (AgenticRetrieveStream, query decomposition + managed reranking) and automatic fallback to standardRetrieve. Can be passed directly to any Agent or ChatClient. Response generation is disabled (generateResponse=False) since the tool returns passages only and the agent's own model generates the answer.BedrockKnowledgeBaseProvider— subclassesContextProviderwithbefore_run()for automatic context injection on every agent invocation.BedrockChatClient._prepare_bedrock_messagesto coalesce adjacent genuine user-role turns (see below).Impact: Additive feature + one scoped serializer change.
How the reviewer feedback was addressed
Role alternation with
BedrockChatClient(Evan Mattson (@moonbox3), #7066): The provider injects retrieved passages as an untrusted user-role message (consistent withazure-cosmos-memory's convention of not elevating retrieved content to system instructions, which would open a stored prompt-injection path). To satisfy Bedrock's role-alternation requirement,_prepare_bedrock_messagesnow coalesces adjacent user-role turns. This is scoped to messages whose original role isuser, so tool-result turns (role="tool", which map to the Bedrockuserrole) are never merged — function-call/tool-result serialization is unchanged. Regression tests cover both the coalescing and the tool-call/tool-result path.Agentic result schema:
AgenticRetrieveStreamresults exposecontent/metadata/sourceRetriever(noscore/location). The source URI is read frommetadata._source_uri, and no numeric score is fabricated for agentic results (managed reranking doesn't expose one); the formatter only renders a score when present.Other Copilot items: regenerated
python/uv.lockfor theboto3/botocore >=1.43.32floor; added the two KB classes to the packageAGENTS.md; IAM examples wrapped as full policy documents; feature usage recorded viamark_feature_used(FeatureIndex.BEDROCK); logger nameagent_framework.bedrock; non-fatal retrieval error handling withCancelledErrorre-raise.Testing
agent.run()withBedrockChatClient+ the provider — single valid conversation, correct grounded response.generateResponse=Falseconfirmed to suppress the streamed generation events.boto3 >= 1.43.32Contribution Checklist