全托管功能上线,内存保留、代码解释解锁畅快开发体验!

6293cbd2c02b59be42fbbf2cb37c94fd.gif

通过 Agents for Amazon Bedrock,生成式 AI 应用程序可以跨不同系统和数据源运行多步骤任务。几个月前,我们简化了 Agent 的创建和配置。近期,我们在预览版中推出了两项新的全托管功能:

跨多个交互保留内存 - Agent 现在可以保留与每个用户对话的摘要,并能够提供流畅、自适应的体验,尤其是对于诸如用户交互和企业自动化解决方案(如预订航班或处理保险理赔)等复杂的多步骤任务。

支持代码解释 - Agent 现在可以在安全的沙箱环境中动态生成和运行代码片段,并能够解决诸如数据分析、数据可视化、文本处理、求解方程和优化问题等复杂用例。为了更方便地使用此功能,我们还增加了直接将文档上传到 Agent 的功能。

让我们更详细地了解这些新功能是如何工作的。

跨多次交互保留内存

通过内存保留,您可以构建能够随着时间推移学习和适应每个用户独特需求和偏好的 Agent通过维护持久内存,Agent 可以从用户停止的地方继续,为复杂的多步骤任务提供流畅的对话和工作流程。

想象一下,用户正在预订航班。由于能够保留内存,Agent 可以了解他们的旅行偏好,并利用这些知识来简化后续的预订请求,创造个性化和高效的体验。例如,它可以自动为用户推荐合适的座位或与之前选择相似的餐食。

使用内存保留提高上下文意识也可以简化业务流程自动化。例如,企业使用的 Agent 现在可以意识到与同一客户之前和正在进行的互动,而无需处理定制集成。

每个用户的对话历史和上下文都安全地存储在唯一的内存标识符(ID)下,确保用户之间完全分离。通过内存保留,更容易构建能够提供无缝、自适应和个性化体验的 Agent,这些体验会随着时间的推移而不断改进。让我们看看这在实践中是如何工作的。

在 Agents for Amazon Bedrock 

中使用内存保留

在 Amazon Bedrock 控制台中,我从导航窗格的构建者工具部分选择 Agent,并开始创建一个 Agent。

对于该 Agent,我将使用 Agent-book-flight 作为其名称,描述如下:

e12ded1f88089f5c5852266096bcb2c9.png

Amazon Bedrock 控制台

扫码了解更多

Help book a flight.

然后,在 Agent Builder 中,我选择了一个大语言模型,并输入了以下指令:

To book a flight, you should know the origin and destination airports and the day and time the flight takes off.

左右滑动查看更多

在附加设置中,我启用了用户输入功能,允许该 Agent 询问澄清性的问题,以获取必要的输入信息。当预订航班的请求缺少必要信息时(如起飞地和目的地或航班日期和时间),这将很有帮助。

在新的内存部分,我启用了内存功能,以在每个会话结束时生成并存储会话摘要,并使用默认的 30 天作为内存持续时间。

041c152dc65c9676508d4e0675e39d85.png

然后,我添加了一个动作组来搜索和预订航班。我使用 search-and-book-flights 作为名称,描述如下:

Search for flights between two destinations on a given day and book a specific flight.

左右滑动查看更多

接着,我选择使用函数详细信息来定义动作组,然后创建一个新的 Lambda 函数。这个 Lambda 函数将实现该动作组中所有函数的业务逻辑。

我在这个动作组中添加了两个函数:一个用于搜索航班,另一个用于预订航班。

第一个函数是 search-for-flights,其描述如下:

Search for flights on a given date between two destinations.

左右滑动查看更多

这个函数的所有参数都是必需的,且类型为字符串。下面是各个参数的名称和描述:

origin_airport – Origin IATA airport codedestination_airport – Destination IATA airport codedate – Date of the flight in YYYYMMDD format

第二个函数是 book-flight,使用以下描述:

Book a flight at a given date and time between two destinations.

左右滑动查看更多

再次说明,所有参数都是必需的,且类型为字符串。以下是各个参数的名称和描述:

origin_airport – Origin IATA airport codedestination_airport – Destination IATA airport codedate – Date of the flight in YYYYMMDD formattime – Time of the flight in HHMM format

为了完成创建 Agent,我选择“创建”。

要访问 Lambda 函数的源代码,我选择“search-and-book-flights”操作组,然后选择“查看”(位于“选择 Lambda 函数设置”附近)。通常情况下,我会使用这个 Lambda 函数与现有系统(如旅行预订平台)集成。在这种情况下,我使用这段代码来模拟 Agent 的预订平台。

import json
import random
from datetime import datetime, time, timedelta




def convert_params_to_dict(params_list):
    params_dict = {}for param in params_list:
        name = param.get("name")
        value = param.get("value")if name is not None:
            params_dict[name] = value
    return params_dict




def generate_random_times(date_str, num_flights, min_hours, max_hours):# Set seed based on input date
    seed = int(date_str)
    random.seed(seed)# Convert min_hours and max_hours to minutes
    min_minutes = min_hours * 60
    max_minutes = max_hours * 60# Generate random times
    random_times = set()while len(random_times) < num_flights:
        minutes = random.randint(min_minutes, max_minutes)
        hours, mins = divmod(minutes, 60)
        time_str = f"{hours:02d}{mins:02d}"
        random_times.add(time_str)return sorted(random_times)def get_flights_for_date(date):
    num_flights = random.randint(1, 6) # Between 1 and 6 flights per day
    min_hours = 6 # 6am
    max_hours = 22 # 10pm
    flight_times = generate_random_times(date, num_flights, min_hours, max_hours)return flight_times
    
    
def get_days_between(start_date, end_date):# Convert string dates to datetime objects
    start = datetime.strptime(start_date, "%Y%m%d")
    end = datetime.strptime(end_date, "%Y%m%d")# Calculate the number of days between the dates
    delta = end - start
    
    # Generate a list of all dates between start and end (inclusive)
    date_list = [start + timedelta(days=i) for i in range(delta.days + 1)]# Convert datetime objects back to "YYYYMMDD" string formatreturn [date.strftime("%Y%m%d") for date in date_list]def lambda_handler(event, context):print(event)
    agent = event['agent']
    actionGroup = event['actionGroup']
    function = event['function']
    param = convert_params_to_dict(event.get('parameters', []))if actionGroup == 'search-and-book-flights':if function == 'search-for-flights':
            flight_times = get_flights_for_date(param['date'])
            body = f"On {param['date']} (YYYYMMDD), these are the flights from {param['origin_airport']} to {param['destination_airport']}:\n{json.dumps(flight_times)}"elif function == 'book-flight':
            body = f"Flight from {param['origin_airport']} to {param['destination_airport']} on {param['date']} (YYYYMMDD) at {param['time']} (HHMM) booked and confirmed."elif function == 'get-flights-in-date-range':
            days = get_days_between(param['start_date'], param['end_date'])
            flights = {}for day in days:
                flights[day] = get_flights_for_date(day)
            body = f"These are the times (HHMM) for all the flights from {param['origin_airport']} to {param['destination_airport']} between {param['start_date']} (YYYYMMDD) and {param['end_date']} (YYYYMMDD) in JSON format:\n{json.dumps(flights)}"else:
            body = f"Unknown function {function} for action group {actionGroup}."else:
        body = f"Unknown action group {actionGroup}."# Format the output as expected by the agent
    responseBody =  {"TEXT": {"body": body
        }}


    action_response = {'actionGroup': actionGroup,'function': function,'functionResponse': {'responseBody': responseBody
        }}


    function_response = {'response': action_response, 'messageVersion': event['messageVersion']}print(f"Response: {function_response}")return function_response

左右滑动查看更多

我准备在控制台中测试该 Agent,并提出以下问题:

Which flights are available from London Heathrow to Rome Fiumicino on July 20th, 2024?

左右滑动查看更多

Agent 返回了一个时间列表。我选择“显示追踪”以获取更多关于 Agent 如何处理我的指令的信息。

在“追踪”选项卡中,我探索追踪步骤,以了解 Agent 编排所使用的思维链。例如,在这里我看到 Agent 在调用 Lambda 函数之前处理了将机场名称转换为代码(LHR 代表伦敦希思罗机场,FCO 代表罗马菲乌米奇诺机场)。

在新的“内存”选项卡中,我看到内存的内容。控制台使用了一个特定的测试内存 ID。在应用程序中,为了让每个用户的内存分开,我可以为每个用户使用不同的内存 ID。

我查看航班列表,并要求预订其中一个航班:

Book the one at 6:02pm.

Agent 回复确认了预订。

几分钟后,会话过期后,我在“内存”选项卡中看到了我们对话的摘要。

067aa0f49ca54c1a05596ab3f68dc831.png

我选择“扫帚”图标开始新的对话,并提出一个单独来看并不能为 Agent 提供完整上下文的问题:

Which other flights are available on the day of my flight?

左右滑动查看更多

Agent 从我们之前的对话中回忆起我预订的航班。为了给我一个答复,Agent 要求我确认航班详情。需要注意的是,Lambda 函数只是一个模拟,并没有将预订信息存储在任何数据库中。航班详情是从 Agent 的记忆中检索出来的。

3bc89ca0e966959c2c06914815f6418d.png

我确认那些航班详情,并获取了当天从同一出发地到同一目的地的其他航班列表。

Yes, please.

为了更好地演示记忆保留的好处,让我们使用适用于 Python 的 Amazon SDK (Boto3)来调用 Agent 。为此,我首先需要创建一个 Agent 别名和版本。我记下了 Agent ID和别名 ID,因为在调用 Agent 时需要它们。

6eba8a14f37ef24909c2014363c64000.png

Amazon SDK (Boto3)

扫码了解更多

在 Agent 调用中,我添加了新的 memoryid 选项来使用记忆。通过包含这个选项,我可以获得两个好处:

  • Agent 会使用为该 memoryid 保留的任何记忆(如果有)来改善其响应。

  • 当前会话的对话摘要将保留在该 memoryid 下,以便在另一个会话中使用。

使用 Amazon SDK,我还可以获取或删除特定 memoryid 的记忆内容。

import random
import string
import boto3
import json


DEBUG = False # Enable debug to see all trace steps
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"


AGENT_ID = 'URSVOGLFNX'
AGENT_ALIAS_ID = 'JHLX9ERCMD'


SESSION_ID_LENGTH = 10
SESSION_ID = "".join(
    random.choices(string.ascii_uppercase + string.digits, k=SESSION_ID_LENGTH))# A unique identifier for each user
MEMORY_ID = 'danilop-92f79781-a3f3-4192-8de6-890b67c63d8b' 
bedrock_agent_runtime = boto3.client('bedrock-agent-runtime', region_name='us-east-1')def invoke_agent(prompt, end_session=False):
    response = bedrock_agent_runtime.invoke_agent(
        agentId=AGENT_ID,
        agentAliasId=AGENT_ALIAS_ID,
        sessionId=SESSION_ID,
        inputText=prompt,
        memoryId=MEMORY_ID,
        enableTrace=DEBUG,
        endSession=end_session,)


    completion = ""for event in response.get('completion'):if DEBUG:print(event)if 'chunk' in event:
            chunk = event['chunk']
            completion += chunk['bytes'].decode()return completion




def delete_memory():try:
        response = bedrock_agent_runtime.delete_agent_memory(
            agentId=AGENT_ID,
            agentAliasId=AGENT_ALIAS_ID,
            memoryId=MEMORY_ID,)except Exception as e:print(e)return Noneif DEBUG:print(response)def get_memory():
    response = bedrock_agent_runtime.get_agent_memory(
        agentId=AGENT_ID,
        agentAliasId=AGENT_ALIAS_ID,
        memoryId=MEMORY_ID,
        memoryType='SESSION_SUMMARY',)
    memory = ""for content in response['memoryContents']:if 'sessionSummary' in content:
            s = content['sessionSummary']
            memory += f"Session ID {s['sessionId']} from {s['sessionStartTime'].strftime(DATE_FORMAT)} to {s['sessionExpiryTime'].strftime(DATE_FORMAT)}\n"
            memory += s['summaryText'] + "\n"if memory == "":
        memory = "<no memory>"return memory




def main():print("Delete memory? (y/n)")if input() == 'y':
        delete_memory()print("Memory content:")print(get_memory())


    prompt = input('> ')if len(prompt) > 0:print(invoke_agent(prompt, end_session=False)) # Start a new session
        invoke_agent('end', end_session=True) # End the sessionif __name__ == "__main__":
    main()

左右滑动查看更多

我从笔记本电脑上运行 Python 脚本。我选择删除当前的记忆(即使现在应该是空的),然后要求预订某个特定日期的上午航班。

Delete memory? (y/n)
y
Memory content:
<no memory>
> Book me on a morning flight on July 20th, 2024 from LHR to FCO.
I have booked you on the morning flight from London Heathrow (LHR) to Rome Fiumicino (FCO) on July 20th, 2024 at 06:44.

左右滑动查看更多

我等待了几分钟,然后再次运行脚本。每次运行脚本时都会创建一个新的会话。这次我没有删除记忆,而是查看了使用相同 memoryid 的之前互动的摘要。然后,我询问我的航班预订在哪一天。尽管这是一个新的会话,但 Agent 在记忆内容中找到了之前的预订记录。

Delete memory? (y/n)
n
Memory content:
Session ID MM4YYW0DL2 from 2024-07-09 15:35:47 to 2024-07-09 15:35:58
The user's goal was to book a morning flight from LHR to FCO on July 20th, 2024. The assistant booked a 0644 morning flight from LHR to FCO on the requested date of July 20th, 2024. The assistant successfully booked the requested morning flight for the user. The user requested a morning flight booking on July 20th, 2024 from London Heathrow (LHR) to Rome Fiumicino (FCO). The assistant booked a 0644 flight for the specified route and date.
> Which date is my flight on? 
I recall from our previous conversation that you booked a morning flight from London Heathrow (LHR) to Rome Fiumicino (FCO) on July 20th, 2024. Please confirm if this date of July 20th, 2024 is correct for the flight you are asking about.

左右滑动查看更多

是的,那就是我预订的航班!

根据不同的使用场景,保留记忆可以帮助跟踪同一用户之前的互动和偏好,并在不同会话之间提供无缝体验。

会话摘要包括一般概述以及用户和助手的观点。对于像这样简短的会话,会导致一些重复。

代码解释支持

Agents for Amazon Bedrock 现在支持代码解释,因此 Agent 可以在安全的沙箱环境中动态生成和运行代码片段,大大扩展了它们可以解决的用例,包括数据分析、可视化、文本处理、方程求解和优化问题等复杂任务。

Agent 现在能够处理各种数据类型和格式的输入文件,包括 CSV、XLS、YAML、JSON、DOC、HTML、MD、TXT 和 PDF。代码解释还允许 Agent 生成图表,增强用户体验,使数据解释更加易于访问。

当大型语言模型(LLM)确定代码解释可以更准确地解决特定问题时,Agent 会使用代码解释,但设计上不支持用户请求任意代码生成的场景。为了安全,每个用户会话都提供了一个隔离的、沙箱代码运行环境。

让我们快速测试一下,看看这如何帮助 Agent 处理复杂任务。

在 Agents for Amazon Bedrock 

中使用代码解释

在 Amazon Bedrock 控制台中,我选择与之前演示相同的 Agent(agent-book-flight),并选择在 Agent Builder 中编辑。在 Agent Builder 中,我在“附加设置”下启用“代码解释器”,然后保存。

a8efedccdb6468fb8a59d93630376c30.png

我准备好 Agent 并直接在控制台中进行测试。首先,我提出一个数学问题。

Compute the sum of the first 10 prime numbers.

左右滑动查看更多

几秒钟后,我从 Agent 那里得到了答案:

The sum of the first 10 prime numbers is 129.

左右滑动查看更多

这个答案是准确的。查看过程,Agent 构建并运行了这个 Python 程序来计算我所询问的内容:

import math


def is_prime(n):if n < 2:return Falsefor i in range(2, int(math.sqrt(n)) + 1):if n % i == 0:return Falsereturn True


primes = []
n = 2while len(primes) < 10:if is_prime(n):
        primes.append(n)
    n += 1print(f"The first 10 prime numbers are: {primes}")print(f"The sum of the first 10 prime numbers is: {sum(primes)}")

左右滑动查看更多

现在,让我们回到 Agent-book-flight  Agent。我想更好地了解一段较长时间内可用的所有航班。为此,我首先在同一操作组中添加一个新功能,以获取某个日期范围内可用的所有航班。

我将新功能命名为 get-flights-in-date-range,并使用以下描述:

Get all the flights between two destinations for each day in a date range.

左右滑动查看更多

所有参数都是必需的,并且类型为字符串。以下是参数名称和描述:

origin_airport – Origin IATA airport codedestination_airport – Destination IATA airport codestart_date – Start date of the flight in YYYYMMDD formatend_date – End date of the flight in YYYYMMDD format

如果查看我之前分享的 Lambda 函数代码,您会发现它已经支持了这个 Agent 功能。

现在 Agent 有了通过单个函数调用提取更多信息的方式,我要求 Agent 以图表的形式可视化航班信息数据。

Draw a chart with the number of flights each day from JFK to SEA for the first ten days of August, 2024.

左右滑动查看更多

Agent 的回复包括一个图表:

4230046e526f8d2aef9f6f28c3878cd3.png

我选择下载图像链接到我的计算机上:

448575d19d3548020bdf738bd57575ce.png

没错,事实上,正如图表所示,Lambda 函数中的模拟器每天会生成 1 到 6 个航班。

使用带有附件文件的代码解释

由于代码解释允许 Agent 处理和提取数据信息,我们引入了在调用 Agent 时包含文档的功能。例如,我有一个 Excel 文件,其中包含了不同航班的预订航班数量:

e3756c059713e6112c8180a1873f2448.png

使用测试界面中的剪辑图标,我附加了文件,然后询问(Agent 的回复将以粗体显示):

What is the most popular route? And the least one?

左右滑动查看更多

根据分析,最受欢迎的航线是 JFK -> SEA,预订量为 921 次,而最不受欢迎的航线是 FCO -> LHR,预订量为 456 次。

How many flights in total have been booked?

左右滑动查看更多

所有航线的预订航班总数是 2557 次。

Draw a chart comparing the % of flights booked for these routes compared to the total number.

左右滑动查看更多

f9bf10ef7c25bafa7cbfa52f78dd42d3.png

我可以查看追踪记录,看到用于从文件中提取信息并传递给 Agent 的 Python 代码。我可以附加多个文件,并使用不同的文件格式。这些选项可在 Amazon SDK 中使用,让 Agent 在您的应用程序中使用文件。

需要了解的事项

内存保留功能在提供 Agents for Amazon Bedrock 亚马逊云科技区域中可以预览。代码解释功能在美国东部(弗吉尼亚北部)、美国西部(俄勒冈州)和欧洲(法兰克福)等区域可以预览。

在预览期间,使用内存保留和代码解释功能与您的 Agent 无需额外费用。使用具有这些功能的 Agent 时,将适用正常的模型使用费用。启用内存保留功能时,您需为用于总结会话的模型付费。

要了解更多信息,请参阅用户指南中的 Agents for Amazon Bedrock 部分。

5cbacb2a1327a34571a51ef5070836a4.png

Amazon Bedrock 定价页面

扫码了解更多

6df2b01e77c59c5d55d99bb24b3c9f79.png

用户指南

扫码了解更多

072530da8cf79aaa4fd45a38776f8c1e.png

community.Amazon

扫码了解更多

左右滑动查看更多

本篇作者

94a7f6830f29722fc6415a30612cd336.png

Danilo

Danilo 与初创公司和不同规模的公司合作,支持他们的创新。作为亚马逊云科技的首席布道师 (EMEA),他利用自己的经验帮助人们将想法变为现实,专注于无服务器架构、事件驱动编程以及机器学习和边缘计算的技术和商业影响。他是 Manning 出版的《Amazon Web Services Lambda in Action》一书的作者。

0e37fba89033e22a0c7d73659dfabaf4.png

41397566034ee6ba9287472008816b46.gif

星标不迷路,开发更极速!

关注后记得星标「亚马逊云开发者」

听说,点完下面4个按钮

就不会碰到bug了!

c76c8e466856e3eca22ba4c49b44bef6.gif

点击阅读原文查看博客,获得更详细内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值