概述
大语言模型(LLM)拥有强大的文本生成和理解能力,但在需要获取外部实时信息或执行特定功能时却存在固有的限制。为了解决这一局限,Amazon Bedrock引入了工具调用(Tool use)功能,通常也被称为函数调用(Function calling),本文章将使用Amazon Bedrock中工具调用这一定义。
工具调用允许模型识别何时需要调用外部工具来完成用户请求,并指明应该使用什么参数。这使得模型能够访问实时数据、查询专有信息库或执行特定操作,从而显著提升其实用价值和应用范围。
您可以使用Amazon Bedrock API为模型提供工具调用的能力,使其生成更加准确、实时且有价值的响应。例如,您可能有一个聊天应用程序,允许用户查询电台播放的最受欢迎的歌曲。要响应这一请求,模型需要一个能够查询并返回歌曲信息的工具。
本例会向模型提供一个工具定义,该工具能够返回特定电台的最受欢迎歌曲。当用户询问相关问题时,模型会分析请求并识别出需要使用该工具。但模型不会直接执行工具调用,而是返回一个调用请求,明确指出需要调用的工具及其所需参数(如电台名称),您的程序会作为模型的Agents来执行工具的调用操作。
您可以根据业务需求灵活实现工具,可以是REST API、数据库查询、Lambda函数或任何其他适合的技术实现。您的程序会将工具调用结果作为新的消息再发送给大模型,最终模型会生成一个完整的响应,为用户提供准确答案。
您可以使用Converse API(Converse或ConverseStream)在Amazon Bedrock中实现工具调用的功能。本文中的示例代码将会展示如何使用Converse API构建一个能够查询电台热门歌曲的应用。
使用Converse API实现工具调用
要让模型通过调用工具来完成响应,您需要向模型发送消息以及一个或多个工具的定义。如果模型确定其中某个工具可以帮助生成响应,它会返回一个请求,要求您的程序调用该工具并将结果发送回模型。随后,模型会利用这些结果为原始消息生成响应。
以下步骤展示了如何通过Converse API使用工具。有关示例代码,请参阅“Converse API工具使用示例”。
Converse API工具使用示例:
https://docs.aws.amazon.com/zh_cn/bedrock/latest/userguide/tool-use-examples.html
向模型发送用户消息和工具定义
工具的定义是一个.json模式,您需要在调用Converse操作时通过toolConfig来传递参数。以下是一个工具定义示例,该工具用于获取电台播放的最受欢迎的歌曲。
{
"tools": [
{
"toolSpec": {
"name": "top_song",
"description": "Get the most popular song played on a radio station.",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"sign": {
"type": "string",
"description": "The call sign for the radio station for which you want the most popular song. Example calls signs are WZPZ and WKRP."
}
},
"required": [
"sign"
]
}
}
}
}
]
}
左右滑动查看完整示意
在同一请求中,您还需要通过messages参数传递用户消息。
[
{
"role": "user",
"content": [
{
"text": "What is the most popular song on WZPZ?"
}
]
}
]
左右滑动查看完整示意
模型返回工具调用请求
当您使用消息和工具定义调用Converse API时,模型会根据工具定义来确定是否需要使用该工具来查询信息。例如,如果您的聊天应用用户发送消息“WZPZ电台最受欢迎的歌曲是什么?”,模型会将这条消息和top_song工具定义中的描述进行匹配,并确定该工具可以帮助生成响应。
当模型决定需要使用工具来生成响应时,模型会将返回中的stopReason字段设置为tool_use。模型会识别您需要使用的工具(top_song)及其所需参数(如电台编码WZPZ),并在返回的消息中包含这些信息。您可以使用toolUseId字段在后续调用中标识工具请求。
以下示例展示了模型的响应结果。
{
"output": {
"message": {
"role": "assistant",
"content": [
{
"toolUse": {
"toolUseId": "tooluse_kZJMlvQmRJ6eAyJE5GIl7Q",
"name": "top_song",
"input": {
"sign": "WZPZ"
}
}
}
]
}
},
"stopReason": "tool_use"
}
左右滑动查看完整示意
应用程序代表模型执行工具请求
应用程序会从模型响应的toolUse字段中获取name值来识别并调用您实现的工具,将工具响应结果和您在上一步中获取的工具请求ID作为参数传递给大模型。
{
"role": "user",
"content": [
{
"toolResult": {
"toolUseId": "tooluse_kZJMlvQmRJ6eAyJE5GIl7Q",
"content": [
{
"json": {
"song": "Elemental Hotel",
"artist": "8 Storey Hike"
}
}
]
}
}
]
}
左右滑动查看完整示意
模型返回最终响应
接下来模型将根据您在请求参数中提供的信息,为原始问题(“WZPZ电台最受欢迎的歌曲是什么?”)生成最终回复。
{
"output": {
"message": {
"role": "assistant",
"content": [
{
"text": "The most popular song on WZPZ is Elemental Hotel by 8 Storey Hike."
}
]
}
},
"stopReason": "end_turn"
左右滑动查看完整示意
Converse API工具使用示例
以下Python示例展示了如何实现工具调用。
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
Shows how to use tools with the <noloc>Converse</noloc> API and the Cohere Command R model.
"""
import logging
import json
import boto3
from botocore.exceptions import ClientError
class StationNotFoundError(Exception):
"""Raised when a radio station isn't found."""
pass
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
def get_top_song(call_sign):
"""Returns the most popular song for the requested station.
Args:
call_sign (str): The call sign for the station for which you want
the most popular song.
Returns:
response (json): The most popular song and artist.
"""
song = ""
artist = ""
if call_sign == 'WZPZ':
song = "Elemental Hotel"
artist = "8 Storey Hike"
else:
raise StationNotFoundError(f"Station {call_sign} not found.")
return song, artist
def generate_text(bedrock_client, model_id, tool_config, input_text):
"""Generates text using the supplied Amazon Bedrock model. If necessary,
the function handles tool use requests and sends the result to the model.
Args:
bedrock_client: The Boto3 Bedrock runtime client.
model_id (str): The Amazon Bedrock model ID.
tool_config (dict): The tool configuration.
input_text (str): The input text.
Returns:
Nothing.
"""
logger.info("Generating text with model %s", model_id)
# Create the initial message from the user input.
messages = [{
"role": "user",
"content": [{"text": input_text}]
}]
response = bedrock_client.converse(
modelId=model_id,
messages=messages,
toolConfig=tool_config
)
output_message = response['output']['message']
messages.append(output_message)
stop_reason = response['stopReason']
if stop_reason == 'tool_use':
# Tool use requested. Call the tool and send the result to the model.
tool_requests = response['output']['message']['content']
for tool_request in tool_requests:
if 'toolUse' in tool_request:
tool = tool_request['toolUse']
logger.info("Requesting tool %s. Request: %s",
tool['name'], tool['toolUseId'])
if tool['name'] == 'top_song':
tool_result = {}
try:
song, artist = get_top_song(tool['input']['sign'])
tool_result = {
"toolUseId": tool['toolUseId'],
"content": [{"json": {"song": song, "artist": artist}}]
}
except StationNotFoundError as err:
tool_result = {
"toolUseId": tool['toolUseId'],
"content": [{"text": err.args[0]}],
"status": 'error'
}
tool_result_message = {
"role": "user",
"content": [
{
"toolResult": tool_result
}
]
}
messages.append(tool_result_message)
# Send the tool result to the model.
response = bedrock_client.converse(
modelId=model_id,
messages=messages,
toolConfig=tool_config
)
output_message = response['output']['message']
# print the final response from the model.
for content in output_message['content']:
print(json.dumps(content, indent=4))
def main():
"""
Entrypoint for tool use example.
"""
logging.basicConfig(level=logging.INFO,
format="%(levelname)s: %(message)s")
model_id = "cohere.command-r-v1:0"
input_text = "What is the most popular song on WZPZ?"
tool_config = {
"tools": [
{
"toolSpec": {
"name": "top_song",
"description": "Get the most popular song played on a radio station.",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"sign": {
"type": "string",
"description": "The call sign for the radio station for which you want the most popular song. Example calls signs are WZPZ, and WKRP."
}
},
"required": [
"sign"
]
}
}
}
}
]
}
bedrock_client = boto3.client(service_name='bedrock-runtime')
try:
print(f"Question: {input_text}")
generate_text(bedrock_client, model_id, tool_config, input_text)
except ClientError as err:
message = err.response['Error']['Message']
logger.error("A client error occurred: %s", message)
print(f"A client error occured: {message}")
else:
print(
f"Finished generating text with model {model_id}.")
if __name__ == "__main__":
main()
左右滑动查看完整示意
有关其他代码示例,请参阅使用Amazon SDK的Amazon Bedrock Runtime代码示例。
使用Amazon SDK的Amazon Bedrock Runtime代码示例:
https://docs.aws.amazon.com/zh_cn/bedrock/latest/userguide/service_code_examples_bedrock-runtime.html
本篇作者
李玉光
北京聚云科技有限公司联合创始人兼首席架构师,前亚马逊云科技合作伙伴大使。拥有十几年的亚马逊云科技云服务开发与架构等经验,协助各类行业客户部署和优化生成式AI应用,显著提升企业的生产力与创新效率。
诚邀您参与「云上探索实验室」,扫描下方二维码,立即体验Amazon Bedrock,开启大模型选型的实战之旅!
星标不迷路,开发更极速!
关注后记得星标「亚马逊云开发者」
听说,点完下面4个按钮
就不会碰到bug了!
点击阅读原文查看博客!获得更详细内容!