构建能够处理真实生产用例的AI代理是一项复杂任务。虽然创建概念验证可以展示潜力,但推进到生产环境需要解决在开发环境中不会出现的可扩展性、安全性、可观测性和运营问题。
本文探讨了某中心的AgentCore服务如何帮助您将代理应用从实验性概念验证转变为生产就绪系统。我们跟踪一个客户支持代理的演进过程,从简单的本地原型发展为能够处理多个并发用户同时保持安全性和性能标准的全面企业级解决方案。
某中心AgentCore是一套全面的服务套件,旨在帮助您构建、部署和扩展代理AI应用。
客户支持是代理AI最常见且最具吸引力的用例之一。现代企业每天处理数千个客户查询,从简单的政策问题到复杂的技术故障排除。传统方法往往不足:基于规则的聊天机器人用僵化响应让客户感到沮丧,而纯人工支持团队则难以实现可扩展性和一致性。
智能客户支持代理需要无缝处理各种场景:管理客户订单和账户、查找退货政策、搜索产品目录、通过网络研究进行技术问题排查,以及记住跨多个交互的客户偏好。最重要的是,它必须在保持企业环境期望的安全性和可靠性标准的同时完成所有这些任务。
考虑许多组织在构建此类代理时遵循的典型演进路径:
每个生产系统都从概念验证开始,我们的客户支持代理也不例外。在这个第一阶段,我们构建一个功能原型,展示客户支持所需的核心能力。
代理依靠工具来采取行动并与实时系统交互。客户支持代理中使用了几种工具,但为保持示例简单,我们专注于三个核心能力来处理最常见的客户查询:
工具可用后,让我们创建代理。我们概念验证的架构如下图所示。
您可以在GitHub存储库中找到本文的端到端代码。为简单起见,我们在此仅显示端到端代码的基本部分:
from strands import Agent
from strands.models import BedrockModel
@tool
def get_return_policy(product_category: str) -> str:
"""获取特定产品类别的退货政策信息。"""
# 返回结构化政策信息:窗口、条件、流程、退款
# 查看github获取完整代码
return {"return_window": "10天", "conditions": ""}
@tool
def get_product_info(product_type: str) -> str:
"""获取电子产品的详细技术规格和信息。"""
# 返回保修、规格、功能、兼容性详情
# 查看github获取完整代码
return {"product": "ThinkPad X1 Carbon", "info": "ThinkPad X1 Carbon信息"}
@tool
def web_search(keywords: str, region: str = "us-en", max_results: int = 5) -> str:
"""搜索网络以获取更新的故障排除信息。"""
# 提供对当前技术解决方案和指南的访问
# 查看github获取完整代码
return "网络搜索结果"
# 初始化模型
model = BedrockModel(
model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
temperature=0.3
)
# 创建客户支持代理
agent = Agent(
model=model,
tools=[
get_product_info,
get_return_policy,
web_search
],
system_prompt="""您是一家电子产品公司的有用客户支持助手。
使用适当的工具提供准确信息,并始终提供额外帮助。"""
)
当我们使用真实的客户查询测试原型时,代理展示了正确的工具选择以及与真实世界系统的交互:
# 退货政策查询
response = agent("我的ThinkPad X1 Carbon的退货政策是什么?")
# 代理正确使用get_return_policy与"笔记本电脑"类别
# 技术故障排除
response = agent("我的iPhone 14发热,如何修复?")
# 代理使用web_search查找当前故障排除解决方案
代理在这些单独查询中运行良好,正确将笔记本电脑查询映射到退货政策查找,将复杂技术问题映射到网络搜索,提供全面且可操作的响应。
我们的概念验证成功证明了代理可以使用正确的工具组合和推理处理各种客户支持场景。代理在您的本地机器上完美运行并正确处理查询。然而,这正是概念验证差距变得明显的地方。工具在代理代码中定义为本地函数,代理响应迅速,一切似乎都已为生产做好准备。但当您考虑超越单用户测试时,几个关键限制变得明显:
这些基本架构障碍可能阻止真实的客户部署。代理构建团队可能需要数月时间来解决这些问题,这会延迟他们工作的价值实现时间并显著增加应用程序成本。这正是某中心AgentCore服务变得必不可少的地方。与其花费数月从头构建这些生产能力,某中心AgentCore提供托管服务,系统地解决每个差距。
我们在概念验证中识别的第一个主要限制是记忆丢失——我们的代理在会话间忘记所有内容,迫使客户每次重复他们的上下文。这种"金鱼代理"行为破坏了使AI代理有价值的对话体验。
某中心AgentCore Memory通过提供在两个互补级别上操作的托管持久内存来解决这个问题:
在将某中心AgentCore Memory添加到我们的客户支持代理后,我们的新架构将如下图所示。
在开始之前,让我们安装依赖项:boto3、AgentCore SDK和AgentCore Starter Toolkit SDK。这些将帮助我们快速将某中心AgentCore功能添加到我们的代理概念验证中。参见以下代码:
pip install boto3 bedrock-agentcore bedrock-agentcore-starter-toolkit
某中心AgentCore Memory使用可配置策略来确定要提取和存储的信息。对于我们的客户支持用例,我们使用两个互补策略:
参见以下代码:
from bedrock_agentcore.memory import MemoryClient
from bedrock_agentcore.memory.constants import StrategyType
memory_client = MemoryClient(region_name=region)
strategies = [
{
StrategyType.USER_PREFERENCE.value: {
"name": "CustomerPreferences",
"description": "捕获客户偏好和行为",
"namespaces": ["support/customer/{actorId}/preferences"],
}
},
{
StrategyType.SEMANTIC.value: {
"name": "CustomerSupportSemantic",
"description": "存储对话中的事实",
"namespaces": ["support/customer/{actorId}/semantic"],
}
},
]
# 使用两种策略创建内存资源
response = memory_client.create_memory_and_wait(
name="CustomerSupportMemory",
description="客户支持代理内存",
strategies=strategies,
event_expiry_days=90,
)
使内存无缝工作的关键是自动化——客户不应该需要考虑它,代理不应该需要手动内存管理。代理提供了一个强大的钩子系统,让您拦截代理生命周期事件并自动处理内存操作。钩子系统使内置组件和用户代码都能够通过强类型事件回调对代理行为做出反应或修改。
对于我们的用例,我们创建CustomerSupportMemoryHooks来检索客户上下文并保存支持交互:
参见以下代码:
class CustomerSupportMemoryHooks(HookProvider):
def retrieve_customer_context(self, event: MessageAddedEvent):
"""在处理查询前注入客户上下文"""
user_query = event.agent.messages[-1]["content"][0]["text"]
# 从两种策略检索相关记忆
all_context = []
for context_type, namespace in self.namespaces.items():
memories = self.client.retrieve_memories(
memory_id=self.memory_id,
namespace=namespace.format(actorId=self.actor_id),
query=user_query,
top_k=3,
)
# 格式化并添加到上下文
for memory in memories:
if memory.get("content", {}).get("text"):
all_context.append(f"[{context_type.upper()}] {memory['content']['text']}")
# 将上下文注入用户查询
if all_context:
context_text = "\n".join(all_context)
original_text = event.agent.messages[-1]["content"][0]["text"]
event.agent.messages[-1]["content"][0]["text"] = f"客户上下文:\n{context_text}\n\n{original_text}"
def save_support_interaction(self, event: AfterInvocationEvent):
"""在代理响应后保存交互"""
# 获取最后客户查询和代理响应 查看github获取实现
customer_query = "这是一个示例查询"
agent_response = "LLM给出了示例响应"
# 提取客户查询和代理响应
# 保存到内存以供将来检索
self.client.create_event(
memory_id=self.memory_id,
actor_id=self.actor_id,
session_id=self.session_id,
messages=[(customer_query, "USER"), (agent_response, "ASSISTANT")]
)
在此代码中,我们可以看到我们的钩子是与某中心AgentCore Memory交互以保存和检索内存事件的钩子。
将内存添加到我们现有的代理只需要最小的代码更改;您可以简单地实例化内存钩子并将其传递给代理构造函数。然后代理代码只需要与内存钩子连接即可使用某中心AgentCore Memory的全部功能。我们将为每个会话创建一个新钩子,这将帮助我们处理不同的客户交互。参见以下代码:
# 为此客户会话创建内存钩子
memory_hooks = CustomerSupportMemoryHooks(
memory_id=memory_id,
client=memory_client,
actor_id=customer_id,
session_id=session_id
)
# 创建具有内存能力的代理
agent = Agent(
model=model,
tools=[get_product_info, get_return_policy, web_search],
system_prompt=SYSTEM_PROMPT
)
让我们看看内存如何改变客户体验。当我们调用代理时,它使用先前交互的内存来显示客户对游戏耳机、ThinkPad笔记本电脑和MacBook散热问题的兴趣:
# 测试个性化推荐
response = agent("您推荐哪款耳机?")
# 代理记住:"偏好竞技FPS游戏的低延迟"
# 响应包括以游戏为重点的推荐
# 测试偏好回忆
response = agent("我偏好的笔记本电脑品牌是什么?")
# 代理记住:"偏好ThinkPad型号"和"需要Linux兼容性"
# 响应确认ThinkPad偏好并建议兼容型号
转变立即显现。代理现在根据客户的陈述偏好和过去交互提供个性化推荐,而不是通用响应。客户不需要重新解释他们的游戏需求或Linux要求——代理已经知道。
通过集成某中心AgentCore Memory,我们的代理现在提供以下好处:
然而,我们仍然有需要解决的限制。我们的工具仍然嵌入在代理代码中,阻止在不同支持代理或团队间重用。安全性和访问控制最小,我们仍然无法在生产环境中同时处理多个客户。
解决内存问题后,我们的下一个挑战是工具架构。目前,我们的工具直接嵌入在代理代码中——这种模式适用于原型,但在规模上会产生显著问题。当您需要多个代理时,每个代理都会复制相同的工具,导致代码冗长、行为不一致和维护噩梦。
某中心AgentCore Gateway通过将工具集中到代理可以访问的可重用安全端点来简化此过程。与用于身份验证的某中心AgentCore Identity结合,它创建了企业级的工具共享基础设施。
我们现在将更新我们的代理以使用某中心AgentCore Gateway和某中心AgentCore Identity。架构将如下图所示。
在这种情况下,我们将网络搜索工具转换为在网关中使用,并将退货政策和获取产品信息工具保留在此代理本地。这很重要,因为网络搜索是可以在组织中不同用例间重用的通用能力,而退货政策和产品信息是通常与客户支持服务相关的能力。通过某中心AgentCore服务,您可以决定使用哪些能力以及如何组合它们。在这种情况下,我们还使用其他团队可能已经开发的两个新工具:检查保修和获取客户档案。因为这些团队已经使用某中心Lambda函数公开了这些工具,我们可以将它们用作某中心AgentCore Gateway的目标。某中心AgentCore Gateway也支持REST API作为目标。这意味着如果我们有OpenAPI规范或Smithy模型,我们也可以使用某中心AgentCore Gateway快速公开我们的工具。
某中心AgentCore Gateway使用模型上下文协议标准化代理访问工具的方式。将现有Lambda函数转换为MCP端点需要最小的更改——主要是添加工具模式和处理MCP上下文。要使用此功能,我们将本地工具转换为Lambda函数并创建工具模式定义,使这些函数可被代理发现:
# 原始Lambda函数
def web_search(keywords: str, region: str = "us-en", max_results: int = 5) -> str:
# web_search功能
def lambda_handler(event, context):
if get_tool_name(event) == "web_search":
query = get_named_parameter(event=event, name="query")
search_result = web_search(keywords)
return {"statusCode": 200, "body": search_result}
以下代码是工具模式定义:
{
"name": "web_search",
"description": "使用DuckDuckGo搜索网络以获取更新信息",
"inputSchema": {
"type": "object",
"properties": {
"keywords": {
"type": "string",
"description": "搜索查询关键词"
},
"region": {
"type": "string",
"description": "搜索区域"
},
"max_results": {
"type": "integer",
"description": "返回的最大结果数"
}
},
"required": [
"keywords"
]
}
}
出于演示目的,我们从头构建一个新的Lambda函数。实际上,组织已经有不同的功能可作为REST服务或Lambda函数使用,这种方法允许您将现有企业服务公开为代理工具,而无需重建它们。
某中心AgentCore Gateway需要对入站和出站连接进行身份验证。某中心AgentCore Identity通过标准OAuth流程处理此问题。设置OAuth授权配置后,您可以创建新网关并将此配置传递给它。参见以下代码:
# 创建基于JWT身份验证的网关
auth_config = {
"customJWTAuthorizer": {
"allowedClients": [cognito_client_id],
"discoveryUrl": cognito_discovery_url
}
}
gateway_response = gateway_client.create_gateway(
name="customersupport-gw",
roleArn=gateway_iam_role,
protocolType="MCP",
authorizerType="CUSTOM_JWT",
authorizerConfiguration=auth_config,
description="客户支持AgentCore网关"
)
对于入站身份验证,代理必须呈现有效的JWT令牌才能访问某中心AgentCore Gateway工具。
对于出站身份验证,某中心AgentCore Gateway可以使用IAM角色、API密钥或OAuth令牌向下游服务进行身份验证。
出于演示目的,我们创建了一个具有虚拟用户名和密码的用户池。对于您的用例,您应该设置适当的身份提供商并相应地管理用户。此配置确保只有授权代理才能访问特定工具,并提供完整的审计跟踪。
设置某中心AgentCore Gateway后,将Lambda函数添加为工具目标很简单:
lambda_target_config = {
"mcp": {
"lambda": {
"lambdaArn": lambda_function_arn,
"toolSchema": {"inlinePayload": api_spec},
}
}
}
gateway_client.create_gateway_target(
gatewayIdentifier=gateway_id,
name="LambdaTools",
targetConfiguration=lambda_target_config,
credentialProviderConfigurations=[{
"credentialProviderType": "GATEWAY_IAM_ROLE"
}]
)
网关现在将您的Lambda函数公开为MCP工具,授权代理可以发现和使用。
将我们的代理转换为使用集中式工具需要更新工具配置。我们保留一些工具本地化,例如特定于客户支持且可能不会在其他用例中重用的产品信息和退货政策,并对共享能力使用集中式工具。因为代理具有对MCP工具的本机集成,我们可以简单地使用带有streamablehttp_client的MCPClient。参见以下代码:
# 获取网关访问的OAuth令牌
gateway_access_token = get_token(
client_id=cognito_client_id,
client_secret=cognito_client_secret,
scope=auth_scope,
url=token_url
)
# 创建经过身份验证的MCP客户端
mcp_client = MCPClient(
lambda: streamablehttp_client(
gateway_url,
headers={"Authorization": f"Bearer {gateway_access_token['access_token']}"}
)
)
# 组合本地和MCP工具
tools = [
get_product_info, # 本地工具
get_return_policy, # 本地工具
] + mcp_client.list_tools_sync() # 来自网关的集中式工具
agent = Agent(
model=model,
tools=tools,
hooks=[memory_hooks],
system_prompt=SYSTEM_PROMPT
)
通过集成集中式工具,我们的代理现在可以访问企业能力,如保修检查:
# 使用集中式工具测试网络搜索
response = agent("如何修复Lenovo ThinkPad蓝屏问题?")
# 代理使用来自AgentCore Gateway的web_search
代理无缝结合本地工具和集中式工具,提供全面的支持能力,同时保持安全性和访问控制。
然而,我们仍然有一个显著的限制:我们的整个代理在开发机器上本地运行。对于生产部署,我们需要可扩展的基础设施、全面的可观测性以及处理多个并发用户的能力。
工具集中化和安全化后,我们的最后一个主要障碍是生产部署。我们的代理当前在您的笔记本电脑上本地运行,这适合实验但不适合真实客户。生产需要可扩展的基础设施、全面监控、自动错误恢复以及可靠处理多个并发用户的能力。
某中心AgentCore Runtime以最小的代码更改将您的本地代理转变为生产就绪服务。结合某中心AgentCore Observability,它提供了企业级的可靠性、自动扩展和全面监控能力,运营团队需要这些能力来维护生产中的代理应用。
我们的架构将如下图所示。
转换您的本地代理只需要添加四行代码:
# 您现有的代理代码保持不变
model = BedrockModel(model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0")
memory_hooks = CustomerSupportMemoryHooks(memory_id, memory_client, actor_id, session_id)
agent = Agent(
model=model,
tools=[get_return_policy, get_product_info],
system_prompt=SYSTEM_PROMPT,
hooks=[memory_hooks]
)
def invoke(payload):
user_input = payload.get("prompt", "")
response = agent(user_input)
return response.message["content"][0]["text"]
if __name__ == "__main__":
BedrockAgentCoreApp自动创建具有所需/invocations和/ping端点的HTTP服务器,处理适当的内容类型和响应格式,根据标准管理错误处理,并提供代理代码和某中心AgentCore Runtime之间的基础设施桥梁。
生产部署需要适当的身份验证和访问控制。某中心AgentCore Runtime与某中心AgentCore Identity集成以提供企业级安全性。使用AgentCore Starter Toolkit,我们可以通过三个简单步骤部署我们的应用程序:配置、启动和调用。
在配置期间,创建Docker文件来指导我们代理的部署。它包含有关代理及其依赖项的信息、某中心AgentCore Identity配置以及要使用的某中心AgentCore Observability配置。在启动步骤期间,使用某中心CodeBuild运行此Dockerfile,并创建某中心ECR存储库来存储代理依赖项。然后创建某中心AgentCore Runtime代理,使用ECR存储库的镜像,并生成端点用于在应用程序中调用代理。如果您的代理配置了通过某中心AgentCore Identity的OAuth身份验证,如我们的代理将配置,您还需要在代理调用步骤期间传递身份验证令牌。下图说明了此过程。
在我们的代理上配置和启动某中心AgentCore Runtime的代码将如下所示:
from bedrock_agentcore_starter_toolkit import Runtime
# 使用身份验证配置安全部署
agentcore_runtime = Runtime()
response = agentcore_runtime.configure(
entrypoint="lab_helpers/lab4_runtime.py",
execution_role=execution_role_arn,
auto_create_ecr=True,
requirements_file="requirements.txt",
region=region,
agent_name="customer_support_agent",
authorizer_configuration={
"customJWTAuthorizer": {
"allowedClients": [cognito_client_id],
"discoveryUrl": cognito_discovery_url,
}
}
)
# 部署到生产环境
launch_result = agentcore_runtime.launch()
此配置创建一个安全端点,仅接受来自您的身份提供商的有效JWT令牌的请求。对于我们的代理,我们使用虚拟设置,但您的应用程序可以使用您选择的身份提供商。部署过程自动将您的代理构建到容器中,创建必要的基础设施,并建立监控和日志记录管道。
代理最关键的生产功能之一是适当的会话管理。某中心AgentCore Runtime自动处理会话隔离,确保不同客户的对话不会相互干扰:
# 客户1对话
response1 = agentcore_runtime.invoke(
{"prompt": "我的iPhone蓝牙不工作。我该怎么办?"},
bearer_token=auth_token,
session_id="session-customer-1"
)
# 客户1跟进
response2 = agentcore_runtime.invoke(
{"prompt": "我已经打开和关闭蓝牙但仍然不工作"},
bearer_token=auth_token,
session_id="session-customer-1" # 相同会话,上下文保留
)
# 客户2对话
response3 = agentcore_runtime.invoke(
{"prompt": "仍然不工作。怎么回事?"},
bearer_token=auth_token,
session_id="session-customer-2" # 不同会话,无上下文
)
客户1的跟进保持关于其iPhone蓝牙问题的完整上下文,而客户2的消息在不同的会话中没有任何上下文,代理适当地要求更多信息。这种自动会话隔离对于生产客户支持场景至关重要。
生产代理需要全面监控来诊断问题、优化性能和保持可靠性。某中心AgentCore Observability自动检测您的代理代码并将遥测数据发送到某中心CloudWatch,您可以在其中实时分析模式和排除问题。可观测性数据包括会话级跟踪,因此您可以跟踪单个客户会话交互并准确了解支持交互期间发生的情况。
通过某中心AgentCore Runtime部署,您的代理已准备好用于生产。然而,我们仍然有一个限制:我们的代理只能通过SDK或API调用访问,要求客户编写代码或使用技术工具与之交互。对于真正的面向客户的部署,我们需要客户可以通过浏览器访问的用户友好Web界面。
在以下部分中,我们通过构建使用Streamlit的示例Web应用程序来演示完整旅程,提供一个直观的聊天界面,可以与我们的生产就绪某中心AgentCore Runtime端点交互。暴露的端点保持我们在从概念验证到生产的旅程中构建的安全性、可扩展性和可观测性能力。在真实场景中,您会将此端点与现有的面向客户的应用程序和UI框架集成。
随着我们的代理部署到生产环境,最后一步是创建客户可以用来与代理交互的面向客户的UI。虽然SDK访问适用于开发人员,但客户需要直观的Web界面以实现无缝支持交互。
为了演示完整的解决方案,我们构建了一个基于Streamlit的示例Web应用程序,连接到我们的生产就绪某中心AgentCore Runtime端点。前端包括安全的身份验证、实时流式响应、持久会话管理和干净的聊天界面。虽然我们使用Streamlit进行快速原型设计,但企业通常会将其端点与现有界面或首选UI框架集成。
端到端应用程序保持跨会话的完整对话上下文,同时提供我们在此文章中构建的安全性、可扩展性和可观测性能力。结果是一个完整的客户支持代理系统,处理从初始身份验证到复杂多轮故障排除对话的所有内容,展示了某中心AgentCore服务如何将原型转变为生产就绪的客户应用程序。
我们从原型到生产的旅程展示了某中心AgentCore服务如何解决部署企业就绪代理应用的传统障碍。从一个简单的本地客户支持聊天机器人开始,转变为一个全面的生产级系统,能够为多个并发用户提供服务,具有持久内存、安全工具共享、全面可观测性和直观的Web界面,而无需数月的自定义基础设施开发。
转变在每个步骤都需要最小的代码更改,展示了某中心AgentCore服务如何协同工作以解决通常使有前景的概念验证停滞的操作挑战。内存能力避免了"金鱼代理"问题,通过某中心AgentCore Gateway的集中式工具管理创建了安全服务多个用例的可重用基础设施,某中心AgentCore Runtime提供了具有自动扩展的企业级部署,某中心AgentCore Observability提供了运营团队维护生产系统所需的监控能力。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。