SailPoint如何在Amazon Bedrock上使用Anthropic的Claude自动生

SailPoint如何使用Anthropic的Claude在Amazon Bedrock上自动生成SaaS连接器的TypeScript代码

原创于:Erik Huckle, Tyler McDonnell, Anveshi Charuvaka, Aude Genevay, MofijulIslam, Karthik Ram, 和 Yasin Khatami 于2024年10月16日在、、。

关键要点

在这篇文章中,我们探讨了SailPoint如何利用Anthropic的Claude模型,借助AmazonBedrock平台,自动生成SaaS连接器所需的TypeScript代码。这项技术不仅显著提升了代码生成的效率,还帮助开发者专注于更高层次的问题解决。

引言

生成式人工智能正在彻底改变开发者的编程方式,通过在编程过程中提供智能辅助和自动化来提升效率。借助先进的语言模型和机器学习(ML)算法,生成式AI能够理解程序员的代码背景和意图,提供有价值的建议,完成代码片段,甚至根据高级描述生成整个函数或模块。这项技术使开发者能够专注于更高级别的问题解决和架构设计,而将繁琐的编码工作交给AI处理。大型语言模型(LLMs)在编程中的关键优势之一在于其学习自海量现有代码和编程模式的能力。这样的知识使得它们能够生成上下文感知的代码,识别潜在的错误或漏洞,并提供优化建议以提高代码质量和性能。

在本文中,我们将重点介绍与的合作,如何基于生成式AI构建一款编码助手,该助手运用Anthropic的ClaudeSonnet在上,加速开发。

Amazon Bedrock是一个完全托管的服务,通过单一API提供来自AI公司(如AI21Labs、Anthropic、Cohere、Meta、Mistral AI、StabilityAI和Amazon)的高性能基础模型(FMs),并提供构建生成式AI应用程序的一整套功能,确保安全、隐私和负责任的AI应用。

SailPoint专注于企业身份安全解决方案。全球超过3000家公司使用SailPoint来抵御当今动态的、以身份为中心的网络威胁,同时提高生产力和效率。其产品旨在通过身份的视角来管理和保护对应用和数据的访问,既包括组织内部的用户,也包括外部的非员工。SailPoint的统一、智能和可扩展的环境提供了全面的身份治理能力,包括访问认证、策略管理、访问请求和配置、密码管理及数据访问治理。这确保了合适的个人在合适的时机获得对合适资源的访问,从而维护了安全政策和合规要求。自2005年成立以来,SailPoint已发展成为身份安全领域的重要参与者,为各行各业的客户提供服务。

SailPoint连接器与SaaS连接

SailPoint的身份安全解决方案与各种软件即服务(SaaS)应用程序进行接口,以从身份安全的角度检索所需信息,例如账户和访问信息。每个SaaS应用程序以稍微不同的方式实现这些功能,并可能通过基于REST的WebAPI暴露其实现,通常支持。SailPoint连接器是与SaaS应用程序接口的TypeScript模块,将相关的身份安全信息(如账户和权限)映射到SailPoint所理解的标准化格式。根据应用程序暴露的API,SailPoint连接器可以创建、更新和删除对这些账户的访问。SailPoint连接器帮助管理用户身份及其在组织内不同环境中的访问权限,支持组织的合规和安全工作。

尽管典型连接器会暴露几个功能,但本文重点关注开发用于列出用户功能的连接器,该功能连接到API端点以列出用户,检索所有用户并将其转换为SailPoint所需的格式。

接下来的部分将详细说明我们如何在Amazon Bedrock上使用Anthropic的ClaudeSonnet自动创建列出用户连接器,这个连接器是广泛的SaaS连接的关键组成部分。

理解列出用户连接器

连接器是可以连接到外部服务并从SaaS应用程序中检索和更新相关信息的模块。为了更好地理解连接器的构建方式,我们以连接到的连接器函数为例。以下的TypeScript代码定义了一个异步函数listUsers,该函数从外部API检索用户账户列表,并为每个用户构建结构化输出:

StdAccountListOutput } from '@sailpoint/connector-sdk';

const listUsers: StdAccountListHandler = async (context: Context, input:
undefined, res: Response) => { let apiKey = context.apiKey; let hostUrl =
context.hostUrl; let hasMore = true;

    
    
    let url = `https://${hostUrl}/Management/v2/organizations/${context.organizationId}/users`;
    
    while (hasMore) {
        let response = await fetch(url, {
            headers: {
                'Authorization': `Bearer ${apiKey}`
            }
        });
        let results = await response.json();
    
        let users = results.users;
        for (const user of users) {
            const output: StdAccountListOutput = {
                identity: user.id,
                attributes: {
                    user_name: user.user_name,
                    first_name: user.first_name,
                    last_name: user.last_name,
                    user_status: user.user_status,
                    membership_status: user.membership_status,
                    email: user.email,
                    created_on: user.created_on,
                    membership_created_on: user.membership_created_on,
                    ds_group_id: user.company_groups.map(group => group.ds_group_id),
                    ds_group_account_id: user.company_groups.map(group => group.ds_group_account_id)
                }
            };
        }
    
        // 页面处理
        if (results.paging.next) {
            url = results.paging.next;
        } else {
            hasMore = false;
        }
    }
    

} ```

上述代码的各个部分说明:

  * **导入** :代码从`@sailpoint/connector-sdk`导入几种类型和接口,包括`Context、Response、StdAccountListHandler、StdAccountListOutput`,这些用于规范化处理函数的输入和输出。
  * **函数定义** :`listUsers`被定义为兼容于`StdAccountListHandler`的异步函数。它使用`Context`访问API密钥和基础URL的配置详情,并通过`Response`来结构化输出。
  * **获取API密钥和主机URL** :从`context`参数中提取,供身份验证和请求URL构建之用。
  * **URL构建** :使用context中的hostUrl和organizationId构建初始URL,指向返回与特定组织关联用户的端点。
  * **循环翻页** :`while`循环在存在更多数据页面时持续进行。其功能包括:
  * **数据获取** :在`while`循环内向API端点发送`fetch`请求。请求包括一个包含`apiKey`的`Authorization`头,API的响应也被转换为JSON格式。
  * **用户处理** :从API响应中提取用户数据。该过程循环遍历每个用户,为每个用户构建一个`StdAccountListOutput`对象,包含用户标识符和如用户名、名字、姓氏、状态、邮箱和组ID等属性信息。
  * **分页逻辑** :在循环内部,检查响应中的分页信息是否存在`next`页面URL。如果存在,则更新`url`以供下一次循环使用;如果不存在,则将`hasMore`设置为false以停止循环。

理解这个例子有助于我们逐步了解在连接器中构建此功能的过程。我们的目标是利用LLM实现这一过程,并采用提示链策略。

## 使用LLM提示链生成TypeScript连接器

使用预训练LLM进行代码生成的方法有多种,复杂度各不相同:

  * **单个提示** :通过直接提示,您可以使用像Anthropic的Claude这样的模型生成代码。此类模型可以以多种语言生成代码,包括TypeScript,但它们通常没有与构建连接器任务相关的特定领域知识。所有所需的信息,包括API规范和格式说明,必须在提示中提供,就像给开发者的指令一样。然而,当给出一长串复杂指令时,LLM往往会遇到困难。提示工程师也很难理解哪些步骤对LLM来说是具有挑战性的。
  * **与LLM结合的代理框架** :代理是一种复杂的框架,能够使用工具执行一系列复杂的任务。在这种情况下,代理首先通过分解用户请求成步骤,然后使用工具查找必要的信息(例如知识库或网页),并自主生成从头到尾的代码。虽然它们能力强大,但这些框架的实施通常复杂,行为不稳定,并且与其他方法相比,控制性较弱。代理还需要进行多次LLM调用来执行一个任务,这在实践中导致速度较慢。如果执行任务的逻辑是固定的步骤顺序,那么代理并不是一个高效的选择。
  * **提示链** :一个在两种前述方法之间取得良好折衷的解决方案涉及使用提示链技术。这种方法将复杂问题分解为一系列更易于管理的步骤,并将它们整合以 Craft 最终代码。每个步骤都有明确的说明,更便于LLM遵循,并且可以有人为干预以控制每个步骤的输出,并在需要时纠正LLM。这种方法在灵活性与控制力之间找到了平衡,避免了其他两种方法的极端情况。

我们最初测试了LLM基于单个提示生成连接器代码的能力,发现其在生成涉及所有问题方面的代码时存在困难,例如分页或嵌套数据结构。为了确保LLM覆盖连接器功能所需的所有必要组件,并且因为创建连接器遵循固定步骤序列,提示链成为改进生成代码的最自然的方法。

我们用于连接器生成的链由以下高层步骤组成:

  1. 将API响应的数据模型解析成规定的TypeScript类。
  2. 生成用户扁平化所需的函数,符合连接器接口的格式。
  3. 理解API规范的分页,并制定高层解决方案。
  4. 通过结合所有中间步骤生成`ListUsers`函数的代码。

第一步的输出用作第二步的输入,但第三步是独立的。这两者的结果都被输送到第四步以获得最终结果。以下图示说明了这一工作流程。

![生成提示链流程图](https://d2908q01vomqb2.cloudfront.net/f1f836cb4ea6efb2a0b1b99f41ad8b103eff4b59/2024/09/20/sailpoint-
删除)

接下来的部分将深入探讨我们在每个步骤中使用的提示技术。

## 系统提示

系统提示是LLM提示的一个重要组成部分,通常提供初始上下文以引导模型的响应。在链中的所有提示中,我们使用了以下系统提示:

```text """ 您是一位具有出色RESTAPI和使用TypeScript进行后台API开发的专家级Web开发者。您的目标是理解提供的API规范(例如OpenAPI规范或Swagger规范的YAML文件),并根据任务描述撰写TypeScript代码、XML、API描述等。请不要偏离提供的规范和文档。如果在规范中存在不明确的地方,请在注释中提及您的不确定性,不要编造规格或描述中未包含的信息。

编写TypeScript代码时,请提供简洁但有意义的注释。 """ ```

更加具体地说,系统提示用于建立LLM的角色(专家级Web开发者),给予其普遍目标(理解API规格并撰写TypeScript代码),给出高层次的指示(添加注释),并设定边界(不编造信息)。

## 数据模型解析

在这一步,我们提示LLM理解API响应的结构,并创建与响应中的对象相对应的TypeScript类。尽管此步骤并非生成响应所必需,但它可以极大地帮助LLM生成准确的连接器。类似于链式思维()推理适用于算术问题,它强迫LLM在回应前“思考”。

这一步骤的两个主要好处如下:

  * **详细API响应简化** :文档中规定的API响应可能非常详细。通过将响应结构转换为TypeScript类,可以将信息压缩为更少的代码行,使其更简洁、更易于LLM理解。这一步确保了关键信息在开始时显现。
  * **处理用户响应的碎片化** :在某些API中,用户响应由于数据结构重用而由多个碎片组成。OpenAPI规范使用`$ref`标签来引用这些可重用组件。通过将用户响应转化为TypeScript类,我们可以将所有相关信息集中在一个地方。此整合简化了后续步骤,提供了集中信息源。

我们使用以下任务提示将API响应转换为规定的TypeScript类:

```text """ 你将得到一个RESTAPI端点的OpenAPI或Swagger规范,它提供了一个SaaS应用程序的用户列表。你将被要求提取API端点的JSON响应中用户的结构。

以下是提供在 之间的API规范。理解并记住API规范。

{api_spec}

请根据用户的结构使用以下说明创建TypeScript接口。  \- 在 XML标签之间提供代码。 \- 如果有嵌套对象,请将它们扩展为自己的接口。 \-
要全面,包含所有属性。 \- 获取所有属性,包括标记为非强制、非必需或可空的属性。 \- 属性在`properties`部分列出。 \-
输出仅一个用户接口,包含从其扩展的所有属性。

输出的预期格式如下:  // 用户 interface User {{ id: number; first_name: string; last_name:
string; email: string; is_active: boolean; company_groups_ids: number[];
other_attribute: string; nested_type: NestedType[]; }}

// 一些复杂类型 interface NestedType {{ type_id: string; some_string_attribute:
string; some_number_attribute: number; }}  """ ```

在之前的提示模板中,变量`{api_spec}`被替换为端点的API规范。DocuSign `ListUsers`端点的具体示例在后附中提供。

以下代码是应用于DocuSign API规范时LLM生成的类的示例,这些类被解析出`<data-model>`标签:

```typescript // 用户 interface User { id: string; // 格式: uuid user_name: string; first_name: string; last_name: string; user_status: string; // 之一: 'active' | 'created' | 'closed' membership_status: string; // 之一: 'activation_required' | 'activation_sent' | 'active' | 'closed' | 'disabled' email: string; created_on: string; // 格式: date-time membership_created_on: string; // 格式: date-time ds_groups: DsGroup[]; }

// 组 interface DsGroup { ds_group_id: string; // 格式: uuid account_id: string;
// 格式: uuid source_product_name: string; group_id: string; group_name: string;
description: string; is_admin: boolean; last_modified_on: string; // 格式: date-
time user_count: number; // 格式: int32 external_account_id: number; // 格式:
int64 account_name: string; membership_id: string; // 格式: uuid } ```

## 用户扁平化函数生成

每个用户的预期结构是一个由两部分组成的对象:一个标识符和一个属性字典。属性字典是一个将字符串键与原始属性(数字、布尔值或字符串)或原始属性数组关联的映射。由于API响应中可能存在任意嵌套的JSON对象结构,我们利用LLM的能力生成用户扁平化和转换函数。该函数同时提取用户ID及其属性。通过采用这种方法,我们有效地将将用户结构从RESTAPI响应转换为为SailPoint连接器SDK(以下简称为连接器SDK)所需格式的复杂任务进行了分离。

这种方法的好处有两个。首先,它实现了更清晰和模块化的代码设计,因为复杂的转换过程被抽象化,不

Leave a Reply

Required fields are marked *