用SDK于 Rust 的 Amazon 基岩运行时示例 - AWS SDK代码示例

AWS 文档 AWS SDK示例 GitHub 存储库中还有更多SDK示例

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

用SDK于 Rust 的 Amazon 基岩运行时示例

以下代码示例向您展示了如何使用 for Rust 和 Amazon Bedrock Runtime 来执行操作和实现常见场景。 AWS SDK

每个示例都包含一个指向完整源代码的链接,您可以在其中找到有关如何在上下文中设置和运行代码的说明。

Anthropic Claude

以下代码示例显示了如何使用 Bedrock 的 Converse 向 Anthropic Claude 发送短信。API

SDK对于 Rust
注意

还有更多相关信息 GitHub。查找完整示例,学习如何在 AWS 代码示例存储库中进行设置和运行。

使用 Bedrock 的 Converse 给 Anthropic Claude 发一条短信。API

#[tokio::main] async fn main() -> Result<(), BedrockConverseError> { tracing_subscriber::fmt::init(); let sdk_config = aws_config::defaults(BehaviorVersion::latest()) .region(CLAUDE_REGION) .load() .await; let client = Client::new(&sdk_config); let response = client .converse() .model_id(MODEL_ID) .messages( Message::builder() .role(ConversationRole::User) .content(ContentBlock::Text(USER_MESSAGE.to_string())) .build() .map_err(|_| "failed to build message")?, ) .send() .await; match response { Ok(output) => { let text = get_converse_output_text(output)?; println!("{}", text); Ok(()) } Err(e) => Err(e .as_service_error() .map(BedrockConverseError::from) .unwrap_or_else(|| BedrockConverseError("Unknown service error".into()))), } } fn get_converse_output_text(output: ConverseOutput) -> Result<String, BedrockConverseError> { let text = output .output() .ok_or("no output")? .as_message() .map_err(|_| "output not a message")? .content() .first() .ok_or("no content in message")? .as_text() .map_err(|_| "content is not text")? .to_string(); Ok(text) }

使用语句、错误实用程序和常量。

use aws_config::BehaviorVersion; use aws_sdk_bedrockruntime::{ operation::converse::{ConverseError, ConverseOutput}, types::{ContentBlock, ConversationRole, Message}, Client, }; // Set the model ID, e.g., Claude 3 Haiku. const MODEL_ID: &str = "anthropic.claude-3-haiku-20240307-v1:0"; const CLAUDE_REGION: &str = "us-east-1"; // Start a conversation with the user message. const USER_MESSAGE: &str = "Describe the purpose of a 'hello world' program in one line."; #[derive(Debug)] struct BedrockConverseError(String); impl std::fmt::Display for BedrockConverseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Can't invoke '{}'. Reason: {}", MODEL_ID, self.0) } } impl std::error::Error for BedrockConverseError {} impl From<&str> for BedrockConverseError { fn from(value: &str) -> Self { BedrockConverseError(value.to_string()) } } impl From<&ConverseError> for BedrockConverseError { fn from(value: &ConverseError) -> Self { BedrockConverseError::from(match value { ConverseError::ModelTimeoutException(_) => "Model took too long", ConverseError::ModelNotReadyException(_) => "Model is not ready", _ => "Unknown", }) } }
  • 有关API详细信息,请参见中的 Converse AWS SDK以获取 Rust API 参考

以下代码示例显示了如何使用 Bedrock 的 Converse 向 Anthropic Claude 发送短信API并实时处理响应流。

SDK对于 Rust
注意

还有更多相关信息 GitHub。查找完整示例,学习如何在 AWS 代码示例存储库中进行设置和运行。

使用 Bedrock 向 Anthropic Claude 发送短信并直播回复令牌。 ConverseStream API

#[tokio::main] async fn main() -> Result<(), BedrockConverseStreamError> { tracing_subscriber::fmt::init(); let sdk_config = aws_config::defaults(BehaviorVersion::latest()) .region(CLAUDE_REGION) .load() .await; let client = Client::new(&sdk_config); let response = client .converse_stream() .model_id(MODEL_ID) .messages( Message::builder() .role(ConversationRole::User) .content(ContentBlock::Text(USER_MESSAGE.to_string())) .build() .map_err(|_| "failed to build message")?, ) .send() .await; let mut stream = match response { Ok(output) => Ok(output.stream), Err(e) => Err(BedrockConverseStreamError::from( e.as_service_error().unwrap(), )), }?; loop { let token = stream.recv().await; match token { Ok(Some(text)) => { let next = get_converse_output_text(text)?; print!("{}", next); Ok(()) } Ok(None) => break, Err(e) => Err(e .as_service_error() .map(BedrockConverseStreamError::from) .unwrap_or(BedrockConverseStreamError( "Unknown error receiving stream".into(), ))), }? } println!(); Ok(()) } fn get_converse_output_text( output: ConverseStreamOutputType, ) -> Result<String, BedrockConverseStreamError> { Ok(match output { ConverseStreamOutputType::ContentBlockDelta(event) => match event.delta() { Some(delta) => delta.as_text().cloned().unwrap_or_else(|_| "".into()), None => "".into(), }, _ => "".into(), }) }

使用语句、错误实用程序和常量。

use aws_config::BehaviorVersion; use aws_sdk_bedrockruntime::{ error::ProvideErrorMetadata, operation::converse_stream::ConverseStreamError, types::{ error::ConverseStreamOutputError, ContentBlock, ConversationRole, ConverseStreamOutput as ConverseStreamOutputType, Message, }, Client, }; // Set the model ID, e.g., Claude 3 Haiku. const MODEL_ID: &str = "anthropic.claude-3-haiku-20240307-v1:0"; const CLAUDE_REGION: &str = "us-east-1"; // Start a conversation with the user message. const USER_MESSAGE: &str = "Describe the purpose of a 'hello world' program in one line."; #[derive(Debug)] struct BedrockConverseStreamError(String); impl std::fmt::Display for BedrockConverseStreamError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Can't invoke '{}'. Reason: {}", MODEL_ID, self.0) } } impl std::error::Error for BedrockConverseStreamError {} impl From<&str> for BedrockConverseStreamError { fn from(value: &str) -> Self { BedrockConverseStreamError(value.into()) } } impl From<&ConverseStreamError> for BedrockConverseStreamError { fn from(value: &ConverseStreamError) -> Self { BedrockConverseStreamError( match value { ConverseStreamError::ModelTimeoutException(_) => "Model took too long", ConverseStreamError::ModelNotReadyException(_) => "Model is not ready", _ => "Unknown", } .into(), ) } } impl From<&ConverseStreamOutputError> for BedrockConverseStreamError { fn from(value: &ConverseStreamOutputError) -> Self { match value { ConverseStreamOutputError::ValidationException(ve) => BedrockConverseStreamError( ve.message().unwrap_or("Unknown ValidationException").into(), ), ConverseStreamOutputError::ThrottlingException(te) => BedrockConverseStreamError( te.message().unwrap_or("Unknown ThrottlingException").into(), ), value => BedrockConverseStreamError( value .message() .unwrap_or("Unknown StreamOutput exception") .into(), ), } } }
  • 有关API详细信息,请参见ConverseStream中的 Rust AWS SDK API 参考

以下代码示例展示了如何在应用程序、生成式 AI 模型和互联工具之间建立典型的交互,或者APIs如何调解 AI 与外界之间的交互。它以将外部天气API连接到 AI 模型为例,这样它就可以根据用户输入提供实时天气信息。

SDK对于 Rust
注意

还有更多相关信息 GitHub。查找完整示例,学习如何在 AWS 代码示例存储库中进行设置和运行。

演示的主要场景和逻辑。这精心策划了用户、Amazon Bedrock Converse API 和天气工具之间的对话。

#[derive(Debug)] #[allow(dead_code)] struct InvokeToolResult(String, ToolResultBlock); struct ToolUseScenario { client: Client, conversation: Vec<Message>, system_prompt: SystemContentBlock, tool_config: ToolConfiguration, } impl ToolUseScenario { fn new(client: Client) -> Self { let system_prompt = SystemContentBlock::Text(SYSTEM_PROMPT.into()); let tool_config = ToolConfiguration::builder() .tools(Tool::ToolSpec( ToolSpecification::builder() .name(TOOL_NAME) .description(TOOL_DESCRIPTION) .input_schema(ToolInputSchema::Json(make_tool_schema())) .build() .unwrap(), )) .build() .unwrap(); ToolUseScenario { client, conversation: vec![], system_prompt, tool_config, } } async fn run(&mut self) -> Result<(), ToolUseScenarioError> { loop { let input = get_input().await?; if input.is_none() { break; } let message = Message::builder() .role(User) .content(ContentBlock::Text(input.unwrap())) .build() .map_err(ToolUseScenarioError::from)?; self.conversation.push(message); let response = self.send_to_bedrock().await?; self.process_model_response(response).await?; } Ok(()) } async fn send_to_bedrock(&mut self) -> Result<ConverseOutput, ToolUseScenarioError> { debug!("Sending conversation to bedrock"); self.client .converse() .model_id(MODEL_ID) .set_messages(Some(self.conversation.clone())) .system(self.system_prompt.clone()) .tool_config(self.tool_config.clone()) .send() .await .map_err(ToolUseScenarioError::from) } async fn process_model_response( &mut self, mut response: ConverseOutput, ) -> Result<(), ToolUseScenarioError> { let mut iteration = 0; while iteration < MAX_RECURSIONS { iteration += 1; let message = if let Some(ref output) = response.output { if output.is_message() { Ok(output.as_message().unwrap().clone()) } else { Err(ToolUseScenarioError( "Converse Output is not a message".into(), )) } } else { Err(ToolUseScenarioError("Missing Converse Output".into())) }?; self.conversation.push(message.clone()); match response.stop_reason { StopReason::ToolUse => { response = self.handle_tool_use(&message).await?; } StopReason::EndTurn => { print_model_response(&message.content[0])?; return Ok(()); } _ => (), } } Err(ToolUseScenarioError( "Exceeded MAX_ITERATIONS when calling tools".into(), )) } async fn handle_tool_use( &mut self, message: &Message, ) -> Result<ConverseOutput, ToolUseScenarioError> { let mut tool_results: Vec<ContentBlock> = vec![]; for block in &message.content { match block { ContentBlock::Text(_) => print_model_response(block)?, ContentBlock::ToolUse(tool) => { let tool_response = self.invoke_tool(tool).await?; tool_results.push(ContentBlock::ToolResult(tool_response.1)); } _ => (), }; } let message = Message::builder() .role(User) .set_content(Some(tool_results)) .build()?; self.conversation.push(message); self.send_to_bedrock().await } async fn invoke_tool( &mut self, tool: &ToolUseBlock, ) -> Result<InvokeToolResult, ToolUseScenarioError> { match tool.name() { TOOL_NAME => { println!( "\x1b[0;90mExecuting tool: {TOOL_NAME} with input: {:?}...\x1b[0m", tool.input() ); let content = fetch_weather_data(tool).await?; println!( "\x1b[0;90mTool responded with {:?}\x1b[0m", content.content() ); Ok(InvokeToolResult(tool.tool_use_id.clone(), content)) } _ => Err(ToolUseScenarioError(format!( "The requested tool with name {} does not exist", tool.name() ))), } } } #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); let sdk_config = aws_config::defaults(BehaviorVersion::latest()) .region(CLAUDE_REGION) .load() .await; let client = Client::new(&sdk_config); let mut scenario = ToolUseScenario::new(client); header(); if let Err(err) = scenario.run().await { println!("There was an error running the scenario! {}", err.0) } footer(); }

演示使用的天气工具。该脚本定义了工具规范,并实现了从Open-Mete API o检索天气数据的逻辑。

const ENDPOINT: &str = "https://api.open-meteo.com/v1/forecast"; async fn fetch_weather_data( tool_use: &ToolUseBlock, ) -> Result<ToolResultBlock, ToolUseScenarioError> { let input = tool_use.input(); let latitude = input .as_object() .unwrap() .get("latitude") .unwrap() .as_string() .unwrap(); let longitude = input .as_object() .unwrap() .get("longitude") .unwrap() .as_string() .unwrap(); let params = [ ("latitude", latitude), ("longitude", longitude), ("current_weather", "true"), ]; debug!("Calling {ENDPOINT} with {params:?}"); let response = reqwest::Client::new() .get(ENDPOINT) .query(&params) .send() .await .map_err(|e| ToolUseScenarioError(format!("Error requesting weather: {e:?}")))? .error_for_status() .map_err(|e| ToolUseScenarioError(format!("Failed to request weather: {e:?}")))?; debug!("Response: {response:?}"); let bytes = response .bytes() .await .map_err(|e| ToolUseScenarioError(format!("Error reading response: {e:?}")))?; let result = String::from_utf8(bytes.to_vec()) .map_err(|_| ToolUseScenarioError("Response was not utf8".into()))?; Ok(ToolResultBlock::builder() .tool_use_id(tool_use.tool_use_id()) .content(ToolResultContentBlock::Text(result)) .build()?) }

用于打印消息内容块的实用工具

fn print_model_response(block: &ContentBlock) -> Result<(), ToolUseScenarioError> { if block.is_text() { let text = block.as_text().unwrap(); println!("\x1b[0;90mThe model's response:\x1b[0m\n{text}"); Ok(()) } else { Err(ToolUseScenarioError(format!( "Content block is not text ({block:?})" ))) } }

使用语句、错误实用程序和常量。

use std::{collections::HashMap, io::stdin}; use aws_config::BehaviorVersion; use aws_sdk_bedrockruntime::{ error::{BuildError, SdkError}, operation::converse::{ConverseError, ConverseOutput}, types::{ ContentBlock, ConversationRole::User, Message, StopReason, SystemContentBlock, Tool, ToolConfiguration, ToolInputSchema, ToolResultBlock, ToolResultContentBlock, ToolSpecification, ToolUseBlock, }, Client, }; use aws_smithy_runtime_api::http::Response; use aws_smithy_types::Document; use tracing::debug; /// This demo illustrates a tool use scenario using Amazon Bedrock's Converse API and a weather tool. /// The script interacts with a foundation model on Amazon Bedrock to provide weather information based on user /// input. It uses the Open-Meteo API (https://open-meteo.com) to retrieve current weather data for a given location. // Set the model ID, e.g., Claude 3 Haiku. const MODEL_ID: &str = "anthropic.claude-3-haiku-20240307-v1:0"; const CLAUDE_REGION: &str = "us-east-1"; const SYSTEM_PROMPT: &str = "You are a weather assistant that provides current weather data for user-specified locations using only the Weather_Tool, which expects latitude and longitude. Infer the coordinates from the location yourself. If the user provides coordinates, infer the approximate location and refer to it in your response. To use the tool, you strictly apply the provided tool specification. - Explain your step-by-step process, and give brief updates before each step. - Only use the Weather_Tool for data. Never guess or make up information. - Repeat the tool use for subsequent requests if necessary. - If the tool errors, apologize, explain weather is unavailable, and suggest other options. - Report temperatures in °C (°F) and wind in km/h (mph). Keep weather reports concise. Sparingly use emojis where appropriate. - Only respond to weather queries. Remind off-topic users of your purpose. - Never claim to search online, access external data, or use tools besides Weather_Tool. - Complete the entire process until you have all required data before sending the complete response. "; // The maximum number of recursive calls allowed in the tool_use_demo function. // This helps prevent infinite loops and potential performance issues. const MAX_RECURSIONS: i8 = 5; const TOOL_NAME: &str = "Weather_Tool"; const TOOL_DESCRIPTION: &str = "Get the current weather for a given location, based on its WGS84 coordinates."; fn make_tool_schema() -> Document { Document::Object(HashMap::<String, Document>::from([ ("type".into(), Document::String("object".into())), ( "properties".into(), Document::Object(HashMap::from([ ( "latitude".into(), Document::Object(HashMap::from([ ("type".into(), Document::String("string".into())), ( "description".into(), Document::String("Geographical WGS84 latitude of the location.".into()), ), ])), ), ( "longitude".into(), Document::Object(HashMap::from([ ("type".into(), Document::String("string".into())), ( "description".into(), Document::String( "Geographical WGS84 longitude of the location.".into(), ), ), ])), ), ])), ), ( "required".into(), Document::Array(vec![ Document::String("latitude".into()), Document::String("longitude".into()), ]), ), ])) } #[derive(Debug)] struct ToolUseScenarioError(String); impl std::fmt::Display for ToolUseScenarioError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Tool use error with '{}'. Reason: {}", MODEL_ID, self.0) } } impl From<&str> for ToolUseScenarioError { fn from(value: &str) -> Self { ToolUseScenarioError(value.into()) } } impl From<BuildError> for ToolUseScenarioError { fn from(value: BuildError) -> Self { ToolUseScenarioError(value.to_string().clone()) } } impl From<SdkError<ConverseError, Response>> for ToolUseScenarioError { fn from(value: SdkError<ConverseError, Response>) -> Self { ToolUseScenarioError(match value.as_service_error() { Some(value) => value.meta().message().unwrap_or("Unknown").into(), None => "Unknown".into(), }) } }
  • 有关API详细信息,请参见中的 Converse AWS SDK以获取 Rust API 参考