Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python: [WIP] Bedrock agent #10307

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

TaoChenOSU
Copy link
Contributor

Motivation and Context

Address #10284

Integration of AWS Bedrock agent to SK Python

Description

Contribution Checklist

@TaoChenOSU TaoChenOSU added PR: in progress Under development and/or addressing feedback python Pull requests for the Python Semantic Kernel labels Jan 27, 2025
@TaoChenOSU TaoChenOSU self-assigned this Jan 27, 2025
@TaoChenOSU TaoChenOSU requested a review from a team as a code owner January 27, 2025 18:31
@github-actions github-actions bot changed the title [WIP] Bedrock agent Python: [WIP] Bedrock agent Jan 27, 2025
@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Jan 27, 2025

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
semantic_kernel/agents/bedrock
   action_group_utils.py28280%3–108
   bedrock_agent.py1591590%4–398
   bedrock_agent_base.py1371370%3–390
semantic_kernel/agents/bedrock/models
   bedrock_action_group_model.py880%3–21
   bedrock_agent_event_type.py880%3–19
   bedrock_agent_model.py11110%3–24
   bedrock_agent_status.py12120%4–23
semantic_kernel/agents/channels
   bedrock_agent_channel.py83830%3–210
TOTAL17526230587% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
3041 4 💤 0 ❌ 0 🔥 1m 33s ⏱️

python/pyproject.toml Outdated Show resolved Hide resolved
import asyncio
import uuid

from samples.concepts.agents.bedrock_agent.setup_utils import use_existing_agent, use_new_agent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally a simple chat sample shouldn't have to import a bunch of stuff, I think for this only doing create a new agent would be fine


# If you want to enable streaming, set this to True.
# In order to perform streaming, you need to have the permission on action: bedrock:InvokeModelWithResponseStream
STREAMING = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also just choose this one

# [Note] You may have to request access to the foundation model if you don't have it.
# [Note] When using function calling, the success rate of function calling may vary
# depending on the foundation model. Advanced models may have better performance.
FOUNDATION_MODEL = os.getenv("FOUNDATION_MODEL")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be moved into a BedrockAgentSettings/BedrockSettings envar?


return bedrock_agent

async def create_agent(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we use the same pattern for create as with OpenAIAssistantAgent?

channel_type: ClassVar[type[BedrockAgentChannel]] = BedrockAgentChannel

@classmethod
async def create_new_agent(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on aligning this create_new_agent method to be similar with other agents (like the Assistant Agent) that have a create method?

) -> "BedrockAgent":
"""Create a new agent asynchronously."""
agent_base_class_kwargs = {}
if "kernel" in kwargs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why we can't add an explicit kernel argument to the method? Similarly arguments: KernelArguments | None as well as a prompt_template_config: PromptTemplateConfig | None?

kwargs.setdefault("streamingConfigurations", {})["streamFinalResponse"] = True
kwargs.setdefault("sessionState", {})

for request_index in range(self.function_choice_behavior.maximum_auto_invoke_attempts):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the function_choice_behavior that drives the interaction of invoking the agent the only possible way of handling this?

"""List associated agent knowledge bases."""
return await self._list_associated_agent_knowledge_bases(**kwargs)

async def invoke(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our agents should support both kernel arguments and kernel invoke-time overrides. Reference for handling those items: https://github.com/microsoft/semantic-kernel/blob/d0157424b4600a65ad58d699250b80c7162c17e4/python/semantic_kernel/agents/chat_completion/chat_completion_agent.py#L121C9-L127C52

python/semantic_kernel/agents/bedrock/bedrock_agent.py Outdated Show resolved Hide resolved
if not isinstance(agent, BedrockAgent):
raise AgentChatException(f"Agent is not of the expected type {type(BedrockAgent)}.")
if not self.messages:
raise AgentChatException("No chat history available.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ChatHistory we have: messages: list[ChatMessageContent] = Field(default_factory=list, kw_only=False). This exception wouldn't get hit?

raise AgentChatException("No chat history available.")

# Preprocess chat history
if await agent.reduce_history(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies - this chat history reducer stuff was influx as you were doing this -- I removed the reduce_history method from the agent. The history reduce is called directly on the reducer object now, outside of this -- and for a group chat, there's a specific agent group chat message to reduce the history.

# Agent Model
agent_model: BedrockAgentModel | None = None

def __init__(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to include this on how instructions/prompt template config is handled, with precedence to prompt_template_config's template for instructions:

https://github.com/microsoft/semantic-kernel/blob/d0157424b4600a65ad58d699250b80c7162c17e4/python/semantic_kernel/agents/chat_completion/chat_completion_agent.py#L84C9-L99C71

Comment on lines +1 to +2
AGENT_ROLE_AMAZON_RESOURCE_NAME=[YOUR_AGENT_ROLE_AMAZON_RESOURCE_NAME]
FOUNDATION_MODEL=[YOUR_FOUNDATION_MODEL]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these env variable names fixed or up to us? If up to us, it would be good to have 'bedrock' in there somewhere.

Comment on lines +32 to +35
if CREATE_NEW_AGENT:
bedrock_agent = await use_new_agent(AGENT_NAME, INSTRUCTION)
else:
bedrock_agent = await use_existing_agent(AGENT_ID, AGENT_NAME)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep it simple I would suggest separating the new and existing scenarios into separate samples. That will allow people to navigate to the scenario that fit's their needs and copy paste to get started.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, I think the rest of the samples are ok to support new and existing with a flag, but it would be good to start with a single sample for chat using an existing agent and one using new agent creation.

cls,
agent_name: str,
foundation_model: str,
role_arn: str,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be obvious to others, but I can't tell what role_arn is from the name. Is there something more descriptive?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation PR: in progress Under development and/or addressing feedback python Pull requests for the Python Semantic Kernel
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants