Semantic Kernel 集成 Amazon Bedrock Agents:在 AWS 上构建、调用与编排 AI Agent 的完整指南
【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel
导读
Amazon Bedrock Agents 是 AWS 提供的托管式 Agent 服务,可以在 AWS 云端快速创建并运行 AI Agent;而 Semantic Kernel 的 Bedrock 集成层(Microsoft.SemanticKernel.Agents.Bedrock)则把两者打通,让开发者用统一的 Semantic Kernel Agent 抽象去创建、配置、调用 Bedrock Agent,并把 Kernel 函数直接注册为 Agent 的工具(action group)。读完本文,你将掌握:如何在 .NET 中创建并调用 Bedrock Agent、如何为其接入 Kernel 函数、代码解释器、用户输入与知识库等能力,以及流式调用、会话线程、Trace 观测和声明式 YAML 定义等进阶用法。
本文以 dotnet/src/Agents/Bedrock/README.md 为主线,结合该集成模块的源码与示例深入展开。
一、集成概览:Bedrock Agents 与 Semantic Kernel 的角色分工
根据模块 README 的定义,AWS Bedrock Agents 是一项托管服务,允许用户在 AWS 云中快速搭建并运行 AI Agent。Semantic Kernel 的集成包Microsoft.SemanticKernel.Agents.Bedrock(见 Agents.Bedrock.csproj)在此基础上提供了一层 .NET 抽象:
BedrockAgent:继承自 Semantic Kernel 的Agent,是对 Bedrock Agent 服务的专门实现(BedrockAgent.cs)。它同时持有两个 AWS SDK 客户端——IAmazonBedrockAgent(管理面,用于创建/准备/删除 Agent)与IAmazonBedrockAgentRuntime(运行时面,用于执行会话)。BedrockAgentThread:代表一次对话会话,底层对应 Bedrock 的 session(BedrockAgentThread.cs)。BedrockAgentChannel:是AgentChannel的专门实现,让 Bedrock Agent 可以参与AgentGroupChat等多方协作场景(BedrockAgentChannel.cs)。
从工程层面看,该包通过 NuGet 引用AWSSDK.BedrockAgent与AWSSDK.BedrockAgentRuntime两个官方 AWS SDK,目标框架为net10.0;net8.0;netstandard2.0。需要说明的是,项目源码中以SKEXP0110实验性警告标注了该集成,VersionSuffix为alpha,属于评估期特性,API 在未来版本中可能调整。
1.1 从源码看调用链路
一个典型的调用会经过如下链路(见 BedrockAgent.cs 与 BedrockAgentInvokeExtensions.cs):
BedrockAgent.InvokeAsync校验消息非空、确保最后一条是用户消息,并创建/复用BedrockAgentThread;- 构造
InvokeAgentRequest,其中AgentAliasId默认使用工作草稿别名TSTALIASID(即BedrockAgent.WorkingDraftAgentAlias常量),也可通过BedrockAgentInvokeOptions.AgentAliasId覆盖; - 通过
RuntimeClient.InvokeAgentAsync发起调用,并逐事件消费响应流; - 响应流中的事件会被分别处理为普通文本(
PayloadPart)、文件(FilePart)、函数调用(ReturnControlPayload)与 Trace(TracePart); - 当收到函数调用事件且函数自动调用被启用时,集成层会直接在本地
Kernel中执行对应的 Kernel 函数,并把结果封装为SessionState.ReturnControlInvocationResults回传给 Bedrock,形成一轮完整的工具调用闭环。
1.2 两个关键 API 形态
BedrockAgent同时提供两种调用形态(详见 BedrockAgent.cs):
InvokeAsync(...):非流式调用,返回IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>,将多个响应片段聚合成一个ChatMessageContent;InvokeStreamingAsync(...):流式调用,返回IAsyncEnumerable<AgentResponseItem<StreamingChatMessageContent>>。从源码看,Bedrock 对流式与非流式使用同一 API,集成层通过设置StreamingConfigurations.StreamFinalResponse = true开启流式,并将响应逐块转换为流式消息。
每次调用都需要至少一条消息,否则会抛出InvalidOperationException("The Bedrock agent requires a message to be invoked.")。
二、前置条件:AWS 账号、模型访问权限与 IAM 配置
在开始编码前,需要完成 AWS 侧的准备。示例目录的说明文件 GettingStartedWithAgents/BedrockAgent/README.md 给出了完整的准备工作:
- AWS 账号与模型访问权限:需要在 AWS 控制台为账号开通对目标基础模型(Foundation Model)的访问权限;
- 安装并配置 AWS CLI:本地需要安装 AWS CLI 并完成凭据配置(如
aws configure),因为示例与运行时都会通过默认凭据链访问 Bedrock 服务; - 准备 IAM 角色(AgentResourceRoleArn):Agent 执行需要委托给某个 IAM 角色。在 AWS 控制台 IAM 服务的Roles中找到目标角色,其摘要页中的 ARN 即所需值;
- 开通
bedrock:InvokeModelWithResponseStream权限:运行时调用依赖该动作,需在角色的权限策略中手动添加。
2.1 用 user-secrets 管理配置
示例使用 .NET User Secrets 存储敏感配置:
dotnet user-secrets set "BedrockAgent:AgentResourceRoleArn" "arn:aws:iam::...:role/..." dotnet user-secrets set "BedrockAgent:FoundationModel" "..."FoundationModel的值即你在 AWS 侧有权访问的模型 ID(例如 Anthropic Claude 系列等),必须以 AWS 控制台实际开通的模型为准。此外,知识库场景还需要BedrockAgent:KnowledgeBaseId(见声明式示例 Step07_BedrockAgent_Declarative.cs)。
三、快速开始:创建 Agent 并完成首次对话
示例 Step01_BedrockAgent.cs 展示了最基础的用法,包含「新建 Agent」「使用已有 Agent」「流式调用」三个场景。
3.1 新建一个 Bedrock Agent
// 1. 在 Bedrock Agent 服务上创建 Agent 并等待其进入 PREPARED 状态 var agentModel = await this.Client.CreateAndPrepareAgentAsync(this.GetCreateAgentRequest(agentName)); // 2. 包装为 Semantic Kernel 的 BedrockAgent var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient); // 3. 创建会话线程并调用 AgentThread bedrockAgentThread = new BedrockAgentThread(this.RuntimeClient); var responses = bedrockAgent.InvokeAsync( new ChatMessageContent(AuthorRole.User, "Why is the sky blue in one sentence?"), bedrockAgentThread, null); await foreach (ChatMessageContent response in responses) { Console.WriteLine(response.Content); } // 4. 清理资源 await bedrockAgent.Client.DeleteAgentAsync(new() { AgentId = bedrockAgent.Id }); await bedrockAgentThread.DeleteAsync();这里的关键扩展方法CreateAndPrepareAgentAsync在 BedrockAgentExtensions.cs 中实现:先CreateAgentAsync创建,再等待 Agent 从CREATING进入NOT_PREPARED状态,随后调用PrepareAgentAndWaitUntilPreparedAsync依次等待PREPARING与PREPARED两个状态。状态轮询默认每 2 秒一次、最多 5 次尝试,超时抛出TimeoutException——这解释了为什么创建后需要等待片刻才能调用。
3.2 使用 AWS 上已存在的 Agent
如果 Agent 已在 AWS 控制台创建好,只需通过 ID 获取并包装:
var getAgentResponse = await this.Client.GetAgentAsync(new() { AgentId = "bedrock-agent-id" }); var bedrockAgent = new BedrockAgent(getAgentResponse.Agent, this.Client, this.RuntimeClient);BedrockAgent的构造函数会从 AWS 的 Agent 模型中同步Id、Name、Description、Instructions等属性。需要特别留意的是,源码注释明确指出:Bedrock Agent 不支持在运行时替换指令,因此该 Agent 类型不支持 prompt template(详见 BedrockAgent.cs 的构造函数注释)。
3.3 流式调用
var streamingResponses = bedrockAgent.InvokeStreamingAsync( new ChatMessageContent(AuthorRole.User, UserQuery), bedrockAgentThread, null); await foreach (StreamingChatMessageContent response in streamingResponses) { Console.WriteLine(response.Content); }四、Tools/Functions:把 Kernel 函数注册为 Bedrock 工具
这是集成层的核心能力。README 指出:Bedrock Agents 通过action group(动作组)使用工具,而该集成允许用户把 Kernel 函数直接注册为 Bedrock Agent 的工具。
4.1 一行代码注册全部 Kernel 函数
示例 Step03_BedrockAgent_Functions.cs 展示了完整流程:
// 1. 创建 Kernel 并挂载插件 Kernel kernel = new(); kernel.Plugins.Add(KernelPluginFactory.CreateFromType<WeatherPlugin>()); // 2. 包装 Bedrock Agent 并绑定 Kernel var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient); // 3. 一键创建 Kernel 函数 action group 并重新 prepare Agent await bedrockAgent.CreateKernelFunctionActionGroupAsync(); // 4. 调用,Agent 会在需要时自动调用 Kernel 函数 var responses = bedrockAgent.InvokeAsync( new ChatMessageContent(AuthorRole.User, "What is the weather in Seattle?"), null);其中插件用标准的[KernelFunction]与[Description]声明,例如:
[KernelFunction, Description("Provides real-time weather information.")] public string Current([Description("The location to get the weather for.")] string location) => $"The current weather in {location} is 72 degrees.";4.2 底层实现:函数 Schema 的自动映射
CreateKernelFunctionActionGroupAsync的无参重载会调用agent.Kernel.ToFunctionSchema()(见 BedrockAgentExtensions.cs),其实现位于 BedrockFunctionSchemaExtensions.cs:
- 遍历
Kernel.Plugins中所有插件的所有函数,生成Function(含Name、Description、Parameters); - 参数类型通过
ToAmazonType映射为 Bedrock 的类型体系:string → String、bool → Boolean、整数类型 →Integer、浮点类型 →Number、数组类型 →Array;遇到不支持的参数类型会抛出ArgumentException; RequireConfirmation固定为DISABLED——源码注释说明,Bedrock 支持在调用函数前要求用户确认,但当前集成尚未实现该特性,因此统一关闭;- action group 采用
RETURN_CONTROL自定义控制方式,即模型输出工具调用意图后交回给客户端(Semantic Kernel 侧)真正执行函数。
4.3 函数自动调用的闭环
在 BedrockAgentInvokeExtensions.cs 中,响应流的ReturnControlPayload事件会被解析为FunctionCallContent列表(保留函数名、参数与InvocationId,并在元数据中记录ActionGroup与ActionInvocationType)。随后:
- 若函数调用开关开启(复用
FunctionCallsProcessor读取FunctionChoiceBehavior.Auto()配置),集成层调用FunctionCallContent.InvokeAsync(agent.Kernel, ...)在本地并行执行函数; - 结果通过
SessionState.ReturnControlInvocationResults回传给 Bedrock,触发下一轮模型推理; - 循环带有请求序号上限,防止函数调用陷入死循环;
- 由于 Bedrock 不支持多模态工具结果,当函数返回图片(
ImageContent)时会返回一个固定的不支持错误消息(ImageContentNotSupportedErrorMessage)。
该示例还演示了并行函数调用:"What is the current weather in Seattle and what is the weather forecast in Seattle?"会触发Current与Forecast两个函数的并行执行;复杂类型(如返回MenuItem[])也能被序列化为文本结果供模型使用。
五、启用代码解释(Code Interpretation)
README 指出:Bedrock Agents 可以借助code interpretation特性编写并执行代码,这与 OpenAI 提供的 Code Interpreter 能力类似。
在 Semantic Kernel 中启用只需调用 BedrockAgentExtensions.cs 中的CreateCodeInterpreterActionGroupAsync:
var bedrockAgent = new BedrockAgent(agentModel, this.Client, this.RuntimeClient); await bedrockAgent.CreateCodeInterpreterActionGroupAsync();示例 Step02_BedrockAgent_CodeInterpreter.cs 中,用户让 Agent 根据数据画柱状图,Agent 自动生成并执行 Python 代码,最终把生成的图表文件返回给客户端。集成层在响应中把FilePart事件转换为BinaryContent(见 BedrockAgentInvokeExtensions.cs 的HandleFilesEvent),文件名记录在Metadata["Name"]中,开发者可以这样落盘:
if (response.Items.Count > 0) { var binaryContent = response.Items.OfType<BinaryContent>().FirstOrDefault(); var filePath = Path.Combine(dir, binaryContent.Metadata!["Name"]!.ToString()!); binaryContent.WriteToFile(filePath, overwrite: true); }从实现看,CreateCodeInterpreterActionGroupAsync本质上是为 Agent 创建一个基于AMAZON.CodeInterpreter父签名(ParentActionGroupSignature)的 action group,并在创建后自动等待 Agent 重新进入PREPARED状态。
六、启用用户输入(User Input)
README 说明:Bedrock Agents 可以在工具调用缺少必要信息时向用户请求补充输入。启用该能力后,Agent 会主动向用户提问缺失信息;如果关闭,Agent 则会自行猜测缺失信息。
Semantic Kernel 集成通过EnableUserInputActionGroupAsync开启(同样位于 BedrockAgentExtensions.cs):
await bedrockAgent.EnableUserInputActionGroupAsync();其实现与代码解释器类似,为 Agent 创建基于AMAZON.UserInput父签名的 action group 并重新 prepare。这意味着该能力是云端 Agent 级别的配置,一旦启用,Agent 在推理过程中遇到参数缺失时会生成「询问用户」的意图,而不再是自行补全。
七、知识库(Knowledge Base):开箱即用的 RAG
README 指出:Bedrock Agents 可以引用 AWS 上保存的数据执行 RAG 任务,在 AWS 中称为knowledge base。Semantic Kernel 集成通过 BedrockAgentExtensions.cs 中的三个方法管理知识库关联:
// 关联知识库(需要有效的 KnowledgeBaseId,并附上用途描述) await bedrockAgent.AssociateAgentKnowledgeBaseAsync( knowledgeBaseId, "You will find information here."); // 解除关联 await bedrockAgent.DisassociateAgentKnowledgeBaseAsync(knowledgeBaseId); // 列出当前关联的知识库 var response = await bedrockAgent.ListAssociatedKnowledgeBasesAsync();从实现细节看,关联/解除关联都以AgentVersion ?? "DRAFT"作为版本号发起请求,并在操作完成后自动等待 Agent 重新 prepare——也就是说知识库变更同样会触发 Agent 的重新准备流程。
示例 Step05_BedrockAgent_FileSearch.cs 展示了「Agent 关联知识库后回答What is Semantic Kernel?」的完整用法,前提是你已经在 AWS 上创建好知识库并把文档数据同步进去。关联后,Agent 会在需要时自动从知识库检索信息并基于检索结果作答,形成完整的 RAG 链路。
八、多代理协作(Multi-agent):当前集成不支持,及原因
README 在最后一部分明确给出了边界:Bedrock Agents 本身支持 multi-agent workflows,用于处理更复杂的任务;但它的多代理模式与 Semantic Kernel 采用的不同,因此当前集成不支持该能力。
从源码结构看,该结论是合理的:Semantic Kernel 的多代理协作建立在AgentGroupChat/AgentChannel抽象之上,而BedrockAgentChannel(见 BedrockAgentChannel.cs)走的是「单 Agent 单会话」的对话通道模型,并不对接 Bedrock 云端的多代理编排协议。
不过,这不代表 Bedrock Agent 无法参与多代理会话。示例 Step06_BedrockAgent_AgentChat.cs 演示了在 Semantic Kernel 侧让一个 Bedrock Agent 与一个ChatCompletionAgent组成AgentGroupChat互相对话:
var chat = new AgentGroupChat(bedrockAgent, chatCompletionAgent) { ExecutionSettings = new() { TerminationStrategy = new MultiTurnTerminationStrategy(2), } }; chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, userQuery)); await foreach (var response in chat.InvokeAsync()) { /* 处理回复 */ }BedrockAgentChannel在这里承担了桥接职责。由于Bedrock 要求对话历史在 user/assistant 之间严格交替,该通道会在相邻消息角色相同时插入内容为[SILENCE]的占位消息(源码中MessagePlaceholder常量),并在发送前确保最后一条消息是用户消息(EnsureLastMessageIsUser)。这些细节保证了 Bedrock Agent 可以在 Semantic Kernel 的多方会话中稳定工作,同时规避了云端「多代理编排」这一不兼容点。
九、进阶:Trace 观测、会话线程与声明式定义
9.1 用 Trace 观察 Agent 的思考过程
BedrockAgentInvokeOptions(见 BedrockAgentInvokeOptions.cs)提供两个可选参数:
| 参数 | 类型 | 说明 |
|---|---|---|
AgentAliasId | string? | 要调用的 Agent 别名 ID;不设置时使用工作草稿别名TSTALIASID |
EnableTrace | bool | 是否启用 Trace,以观测 Agent 的思考过程 |
示例 Step04_BedrockAgent_Trace.cs 展示了如何开启并消费 Trace:
BedrockAgentInvokeOptions options = new() { EnableTrace = true }; var responses = bedrockAgent.InvokeAsync( [new ChatMessageContent(AuthorRole.User, userQuery)], agentThread, options); await foreach (ChatMessageContent response in responses) { if (response.InnerContent is List<object?> innerContents) { var traceParts = innerContents.OfType<TracePart>().ToList(); foreach (var tracePart in traceParts) { // 读取 tracePart.Trace,例如 OrchestrationTrace } } }从 BedrockAgentInvokeExtensions.cs 的HandleTraceEvent看,TracePart事件会被包装为ChatMessageContent存入InnerContent。示例的输出展示了 orchestration trace 中模型调用前后的完整输入输出与 token 用量(InputTokens/OutputTokens),可用于调试工具调用决策、估算成本与排查问题。
9.2 会话线程与生命周期管理
BedrockAgentThread(BedrockAgentThread.cs)把 Bedrock 的 session 封装为可复用的对话线程:
- 创建线程:调用运行时 SDK 的
CreateSessionAsync,返回SessionId; - 删除线程:依次调用
EndSessionAsync与DeleteSessionAsync清理云端会话; - 也可以直接
new BedrockAgentThread(runtimeClient, sessionId)携带既有 session id 继续对话。
示例代码中普遍使用try/finally在会话结束后删除线程,避免云端资源泄漏。另外,BedrockAgent.CreateSessionId()提供了生成唯一会话 id 的便捷方法。
9.3 声明式 YAML 定义 Agent
通过 BedrockAgentFactory.cs(AgentFactory的专门实现,类型标识为bedrock_agent),Bedrock Agent 可以像其他 SK Agent 一样用 YAML 声明式创建。示例 Step07_BedrockAgent_Declarative.cs 提供了 5 种声明式用法:
(1)基础创建:
type: bedrock_agent name: StoryAgent description: Story Telling Agent instructions: Tell a story suitable for children about the topic provided by the user. model: id: ${BedrockAgent:FoundationModel} connection: type: bedrock agent_resource_role_arn: ${BedrockAgent:AgentResourceRoleArn}(2)复用已有 Agent(只需 id 与 type):
id: ${BedrockAgent:AgentId} type: bedrock_agent(3)启用代码解释器:
tools: - type: code_interpreter(4)注册函数工具(需在options.parameters中声明每个参数的名称、类型、是否必填与描述):
tools: - id: Current type: function description: Provides real-time weather information. options: parameters: - name: location type: string required: true description: The location to get the weather for.(5)关联知识库:
tools: - type: knowledge_base description: You will find information here. options: knowledge_base_id: ${BedrockAgent:KnowledgeBaseId}工厂的解析逻辑在 BedrockAgentDefinitionExtensions.cs 中:按工具类型分别调用CreateCodeInterpreterActionGroupAsync、CreateKernelFunctionActionGroupAsync(从 YAML 中的function工具生成FunctionSchema)和AssociateAgentKnowledgeBaseAsync,然后统一等待 Agent prepare 完成。创建时通过agent_resource_role_arn(来自model.connection的扩展数据)指定 IAM 角色 ARN。创建后即可通过factory.CreateAgentFromYamlAsync(text, ...)获得可调用的Agent实例。
十、能力边界与注意事项小结
结合 README 与源码,汇总该集成的关键边界:
| 能力 | 支持情况 | 说明 |
|---|---|---|
| Kernel 函数作为工具(action group) | ✅ 支持 | 自动映射 Schema,RETURN_CONTROL+ 本地自动执行 |
| 代码解释器 | ✅ 支持 | 云端执行代码,返回文件(BinaryContent) |
| 用户输入 | ✅ 支持 | 缺失信息时向用户提问而非猜测 |
| 知识库 RAG | ✅ 支持 | 关联/解除关联/列出知识库 |
| 多代理工作流 | ❌ 不支持 | Bedrock 的编排模式与 SK 不同;可用AgentGroupChat在 SK 侧编排 |
| Prompt 模板 | ❌ 不支持 | Bedrock 运行时不允许替换指令 |
| 函数调用用户确认(RequireConfirmation) | ❌ 暂不支持 | 固定为DISABLED |
| 多模态工具结果 | ❌ 不支持 | 图片结果返回固定的不支持消息 |
此外还需注意:本集成属于实验性特性(SKEXP0110),API 可能变更;所有云端操作依赖 AWS 账号的模型访问权限、IAM 角色与bedrock:InvokeModelWithResponseStream权限;Agent 创建、prepare、action group 变更后都必须等待其进入PREPARED状态才能调用,示例中默认的轮询间隔为 2 秒、最多 5 次尝试。
十一、结语
Semantic Kernel 的 Bedrock 集成把「AWS 托管 Agent 服务」与「SK 统一的 Agent 抽象」结合起来:你在 AWS 侧获得稳定的托管运行时,在 .NET 侧则复用 SK 的 Kernel、插件、函数调用、群聊与声明式定义等一整套开发体验。源码与示例(GettingStartedWithAgents/BedrockAgent 目录下的 Step01~Step07)完整覆盖了从基础调用、函数工具、代码解释、知识库到 Trace 观测与 YAML 声明式的全部路径,可作为上手该集成的最佳参考。
【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考