使用Amazon Bedrock内联代理构建动态AI助手

在本笔记本中,我们将介绍设置和调用内联代理的过程,展示其在创建动态AI助手方面的灵活性和功能。通过遵循渐进式方法,我们将全面了解如何使用内联代理来处理各种用例和复杂级别。在单个交互式对话中,我们将演示代理如何在保持正在进行的讨论上下文的同时,即时增强新的工具和指令。

我们将采取渐进式方法来构建我们的助手:

  1. 简单的内联代理:我们将从一个基本的内联代理开始,带有代码解释器。
  2. 添加知识库:我们将通过引入基于角色的访问知识库来增强我们的代理。
  3. 集成动作组:最后,我们将添加自定义工具来扩展代理的功能。

什么是内联代理?

内联代理 是Amazon Bedrock的一个强大功能,允许开发人员创建灵活和可适应的AI助手。

与传统的静态代理不同,内联代理可以在运行时动态配置,实现对其行为、功能和知识库的实时调整。

内联代理的关键特性包括:

  1. 动态配置:在运行时修改代理的指令、动作组和其他参数。
  2. 灵活集成:根据需要轻松整合外部API和服务。
  3. 上下文适应:根据用户角色、偏好或特定场景调整代理的响应。

为什么使用内联代理?

内联代理为构建AI应用程序提供了几个优势:

  1. 快速原型制作:无需重新部署应用程序即可快速试验不同的配置。
  2. 个性化:实时定制代理的功能以满足个人用户或用例需求。
  3. 可扩展性:有效管理单个代理,使其能够适应多个角色或功能。
  4. 成本效益:通过动态选择每次交互所需的工具和知识来优化资源使用。

先决条件

在开始之前,请确保我们具备以下条件:

  1. 一个活跃的AWS帐户,可以访问Amazon Bedrock。
  2. 创建和调用内联代理所需的必要权限。
  3. 请务必完成其他先决条件,访问Amazon Bedrock内联代理先决条件文档 了解更多信息。

安装先决条件

让我们从安装所需的软件包开始。这一步很重要,因为我们需要使用boto3版本1.35.68或更高版本来使用内联代理。

# uncomment to install the required python packages
!pip install --upgrade -r requirements.txt
# # restart kernel
from IPython.core.display import HTML
HTML("<script>Jupyter.notebook.kernel.restart()</script>")

设置和导入

首先,让我们导入必要的库并设置我们的Bedrock客户端。

import os
import json
from pprint import pprint
import boto3
from datetime import datetime
import random
import pprint
from termcolor import colored
from rich.console import Console
from rich.markdown import Markdown

session = boto3.session.Session()
region = session.region_name

# Runtime Endpoints
bedrock_rt_client = boto3.client(
    "bedrock-agent-runtime",
    region_name=region
)

sts_client = boto3.client("sts")
account_id = sts_client.get_caller_identity()["Account"]

# To manage session id:
random_int = random.randint(1,100000)

配置内联代理

接下来,我们将设置Amazon Bedrock内联代理的基本配置。这包括指定基础模型、会话管理和基本指令。

# change model id as needed:
model_id = "anthropic.claude-3-sonnet-20240229-v1:0"

sessionId = f'custom-session-id-{random_int}'
endSession = False
enableTrace = True

# customize instructions of inline agent:
agent_instruction = """You are a helpful AI assistant helping Octank Inc employees with their questions and processes. 
You write short and direct responses while being cheerful. You have access to python coding environment that helps you extend your capabilities."""

基本内联代理调用

让我们从调用一个只有基础模型和基本指令的简单内联代理开始。

# prepare request parameters before invoking inline agent
request_params = {
    "instruction": agent_instruction,
    "foundationModel": model_id,
    "sessionId": sessionId,
    "endSession": endSession,
    "enableTrace": enableTrace,
}

# define code interpreter tool
code_interpreter_tool = {
    "actionGroupName": "UserInputAction",
    "parentActionGroupSignature": "AMAZON.CodeInterpreter"
}

# add the tool to request parameter of inline agent
request_params["actionGroups"] = [code_interpreter_tool]

# enable traces
request_params["enableTrace"] = True
# enter the question you want the inline agent to answer
request_params['inputText'] = 'what is the time right now in pacific timezone?'

调用简单的内联代理

我们将向代理发送一个请求,让它执行一个简单的计算或代码执行任务。这将展示代理如何即时解释和运行代码。

为此,我们将使用boto3 bedrock-agent-runtime客户端通过InvokeInlineAgent API。

我们的函数invoke_inline_agent_helper还可以帮助我们处理代理跟踪请求并格式化它以便更容易阅读。我们不需要在我们的系统中使用这个函数,但它会使观察代码解释器使用的代码、函数调用和知识库内容更加容易。

我们还提供了代理调用时间和输入输出令牌的指标。

def invoke_inline_agent_helper(client, request_params, trace_level="core"):
    # ...
    # (code omitted for brevity)
    # ...
invoke_inline_agent_helper(bedrock_rt_client, request_params, trace_level="core")

添加知识库

现在,我们将演示如何将知识库纳入我们的内联代理调用。让我们首先使用虚构的HR政策文件创建一个知识库,我们稍后将在内联代理中使用它。

我们将使用Amazon Bedrock知识库 来创建我们的知识库。为此,我们使用create_knowledge_base.py文件中可用的支持函数create_knowledge_base。它将抽象出创建底层向量数据库、使用适当的分块策略创建向量索引以及将文档索引到知识库的工作。请查看create_knowledge_base.py文件了解更多详细信息。

import os
from create_knowledge_base import create_knowledge_base

# Configuration
bucket_name = f"inline-agent-bucket-{random_int}"
kb_name = f"policy-kb-{random_int}"
data_path = "policy_documents"

# Create knowledge base and upload documents
kb_id, bucket_name, kb_metadata = create_knowledge_base(region, bucket_name, kb_name, data_path)

设置调用内联代理的知识库配置

现在,让我们设置调用内联代理的知识库配置。

# define number of chunks to retrieve
num_results = 3
search_strategy = "HYBRID"

# provide instructions about knowledge base that inline agent can use
kb_description = 'This knowledge base contains information about company HR policies, code or conduct, performance reviews and much more'

# lets define access level for metadata filtering
user_profile = 'basic'
access_filter = {
    "equals": {
        "key": "access_level",
        "value": user_profile
    }
}

# lets revise our Knowledge bases configuration
kb_config = {
    "knowledgeBaseId": kb_id,
    "description": kb_description,
    "retrievalConfiguration": {
        "vectorSearchConfiguration": {
            "filter": access_filter,
            "numberOfResults": num_results,
            "overrideSearchType": "HYBRID"
        }
    }
}

# lets add knowledge bases to our request parameters
request_params["knowledgeBases"] = [kb_config]
    
# update the agent instructions to inform inline agent that it has access to a knowlegde base
new_capabilities = """You have access to Octank Inc company policies knowledge base. 
Use this database to search for information about company policies, company HR policies, code or conduct, performance reviews and much more. And use them to briefly answer the use question."""
request_params["instruction"] += f"\n\n{new_capabilities}"

# check updated request parameters including instructions for the inline agent
print(request_params)

查询增强的代理

我们将发送一个需要代理从知识库中检索信息并提供有见地的响应的查询。

# enter the question that will use knowledge bases
request_params['inputText'] = 'How much is the employee compensation bonus?'
# invoke the inline agent
invoke_inline_agent_helper(bedrock_rt_client, request_params)

分析知识库集成

我们看到知识库中定义了两种访问级别:基本和管理。薪酬相关的访问权限仅限于"管理”。让我们用正确的过滤器尝试同样的查询。

# lets define access level for metadata filtering
user_profile = 'Manager'
# user_profile = 'basic'
access_filter = {
    "equals": {
        "key": "access_level",
        "value": user_profile
    }
}

# lets revise our Knowledge bases configuration
kb_config = {
    "knowledgeBaseId": kb_id,
    "description": kb_description,
    "retrievalConfiguration": {
        "vectorSearchConfiguration": {
            "filter": access_filter,
            "numberOfResults": num_results,
            "overrideSearchType": "HYBRID"
        }
    }
}

# lets add knowledge bases to our request parameters
request_params["knowledgeBases"] = [kb_config]

# invoke the inline agent
invoke_inline_agent_helper(bedrock_rt_client, request_params)

集成动作组

在本节中,我们将展示如何将自定义工具(动作组)添加到我们的代理调用中。这说明了如何通过API将外部服务集成到代理中。

让我们首先创建一个lambda函数,我们稍后将在内联代理中使用它。

# run lambda function creation
from lambda_creator import create_lambda_function_and_its_resources
import os

present_directory = os.getcwd()
lambda_function_code_path = str(present_directory) + "/pto_lambda/lambda_function.py"

# Create all resources
resources = create_lambda_function_and_its_resources(
    region=region,
    account_id=account_id,
    custom_name=f"hr-inlineagent-lambda-{random_int}",
    lambda_code_path=lambda_function_code_path
)

# Access the created resources
lambda_function = resources['lambda_function']
lambda_function_arn = lambda_function['FunctionArn']
print(lambda_function_arn)

配置带有动作组的代理

我们将更新代理配置,包括新的动作组,允许它与外部服务交互。 对于这个例子,我们提供了一个OpenAPI模式来定义我们的动作组工具。我们也可以使用函数定义来做同样的事情,但我们的lambda函数甚至会有所不同。有关更多信息,请参见文档

apply_vacation_tool = {
            'actionGroupName': 'FetchDetails',
            "actionGroupExecutor": {
                "lambda": lambda_function_arn
            }, "apiSchema": {
                "payload": """
    {
    "openapi": "3.0.0",
    "info": {
        "title": "Vacation Management API",
        "version": "1.0.0",
        "description": "API for managing vacation requests"
    },
    "paths": {
        "/vacation": {
            "post": {
                "summary": "Process vacation request",
                "description": "Process a vacation request or check balance",
                "operationId": "processVacation",
                "parameters": [
                    {
                        "name": "action",
                        "in": "query",
                        "description": "The type of vacation action to perform",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": ["check_balance", "check balance", "apply", "request"],
                            "description": "Action type for vacation management"
                        }
                    },
                    {
                        "name": "days",
                        "in": "query",
                        "description": "Number of vacation days requested",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Request processed successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "status": {
                                            "type": "string",
                                            "enum": ["approved", "pending", "rejected", "info"],
                                            "description": "Status of the vacation request"
                                        },
                                        "message": {
                                            "type": "string",
                                            "description": "Detailed response message"
                                        },
                                        "ticket_url": {
                                            "type": "string",
                                            "description": "Ticket URL for long vacation requests"
                                        }
                                    },
                                    "required": ["status", "message"]
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
    """
            },
            "description": "Process vacation and check leave balance"
}
            
# update the tools that inline agent has access to
request_params["actionGroups"] =