使用 Gemini 进行 SAP 函数调用

本文档简要介绍了如何在 SAP BTP、ABAP 环境中使用 Vertex AI SDK for ABAP 通过 Gemini 进行 SAP 函数调用。

您可以定义自定义函数,并使用函数调用功能将其提供给 Gemini 模型。模型不会直接调用自定义函数,而是生成指定函数名称和建议参数的结构化数据输出。借助此输出,您可以编写采用结构化输出并调用外部 API 的应用。然后,可以将生成的 API 输出并入进一步的模型提示中,以便获得更全面的查询回答。

Vertex AI SDK for ABAP 通过以下方式让 ABAP 开发者有机会调用在 SAP 函数模块中编写的自定义逻辑,从而简化他们的函数调用操作:

  • SAP 函数模块名称或 OData(开放式数据协议)服务名称作为函数声明传递给模型,描述函数或服务的名称、用途和相关参数。
  • 在调用模型时,隐式设置 SAP 函数模块或 OData 服务的自动调用。

准备工作

在通过 Vertex AI SDK for ABAP 使用 Gemini 进行 SAP 函数调用之前,请确保您或您的管理员已满足以下前提条件:

通过调用 SAP 函数模块,使用 SAP 数据丰富 Gemini AI 模型上下文

本部分介绍了如何通过调用 SAP 函数模块使用 SAP 数据来丰富 Gemini AI 模型上下文。

以下是 ABAP 开发者调用 SAP 函数模块的典型流程:

  1. 用户提供输入提示。
  2. SDK 将输入提示和函数声明传递给模型。
  3. 该模型会检查提示和声明的函数,以推导要调用的函数,并建议用于调用该函数的参数值。
  4. 如果设置了自动调用,SDK 会调用 SAP 函数模块。
  5. 然后,SDK 会使用所调用函数的输出调用模型。
  6. 模型会以可靠的答案回答使用所调用函数的输出丰富的最终提示
  7. SDK 会将回答返回给用户。

如果您选择不自动调用 SAP 函数模块,则 SDK 可让您在不调用任何 SAP 函数模块的情况下使用函数调用功能。在这种情况下,您可以遵循典型的函数调用工作流程来使用外部工具,例如 API 和函数。

在 SAP BTP、ABAP 环境中使用 Gemini 进行 SAP 函数调用

实例化多模态 Gemini 调用程序类

如需在 SAP 中调用函数调用,请使用 /GOOG/CL_GENERATIVE_MODEL 类。您可以通过传递在模型生成参数中配置的模型键来实例化该类。

DATA(lo_model) = NEW /goog/cl_generative_model( iv_model_key = 'MODEL_KEY' ).

MODEL_KEY 替换为模型键名,该名称在模型生成参数中进行配置。

创建 SAP 函数模块

如需创建可由 SDK 自动调用的 SAP 函数模块,请遵循提供的架构:

类别 参数名称 关联类型
导入 IT_FUNCTION_PARAMETERS /GOOG/T_FUNCTION_PARAMETERS
导出 EV_FUNCTION_RESPONSE STRING
更改 CV_PROMPT STRING
异常 /GOOG/CX_SDK Exception Class

根据导入参数,在函数模块中编写您的自定义逻辑,该逻辑可以是通过 SELECT 查询提取 SAP 数据,也可以是调用外部 API 或模块以获取缺失的信息。

使用要反馈给 LLM 上下文的信息设置导出参数 EV_FUNCTION_RESPONSE。您还可以根据自定义逻辑和业务要求更改或修改 CV_PROMPT 中的提示文本,以便根据不同的业务场景进一步指示 LLM。

添加函数声明

如需向 LLM 上下文添加函数声明,您可以使用 ADD_FUNCTION_DECLARATION 方法。每当您需要向上下文添加函数时,都应调用 ADD_FUNCTION_DECLARATION 方法。

DATA lt_parameters TYPE /goog/cl_generative_model=>tt_parameter_properties.
APPEND VALUE #( parameter_name = 'PARAMETER_NAME'
                type           = 'PARAMETER_TYPE'
                description    = 'PARAMETER_DESCRIPTION'
                is_required    = 'PARAMETER_IS_REQUIRED' ) TO lt_parameters.
lo_model->add_function_declaration( iv_name        = 'FUNCTION_MODULE_NAME'
                                    iv_description = 'FUNCTION_MODULE_DESCRIPTION'
                                    it_parameters  = lt_parameters ).

替换以下内容:

  • PARAMETER_NAME:参数的名称。
  • PARAMETER_TYPE:参数的数据类型,例如 stringintegerboolean
  • PARAMETER_DESCRIPTION:清楚地说明参数的用途和预期格式。
  • PARAMETER_IS_REQUIRED:如果此参数是函数运行所必需的,请将其值设置为 ABAP_TRUE
  • FUNCTION_MODULE_NAME:SAP 函数模块的名称。
  • FUNCTION_MODULE_DESCRIPTION:SAP 函数模块的说明。

您还可以声明不带参数的函数,该函数可用作回退或备用函数。如果用户提示未提供足够的信息来调用特定函数,您可以指示 Gemini 选择此回退函数。

设置 SAP 函数模块的自动调用

如需设置模型选择的所选 SAP 函数的自动调用,您可以使用 SET_AUTO_INVOKE_SAP_FUNCTION 方法。如果在导入参数 IV_AUTO_INVOKE 中传递 ABAP_TRUE,则 SDK 会调用函数模块,并且其回答会包含在 LLM 上下文中,以生成最终回答。

您必须按照创建 SAP 函数模块部分中所述的架构定义函数模块。

lo_model->set_auto_invoke_sap_function( abap_true ).

使用函数调用生成内容

如需将提示文本传递给 Gemini 模型,您可以使用 GENERATE_CONTENT 方法。如需获取 Gemini 生成的回答以及通过函数调用从 SAP 函数模块添加的额外上下文,请使用 GET_TEXT 方法。

DATA(lv_response) = lo_model->generate_content( iv_prompt_text ='PROMPT'
                           )->get_text( ).

PROMPT 替换为您的文本提示

获取所选函数名称和参数值

如需获取 Gemini 选择的函数(从声明的函数中选择)及其建议的参数,请使用 GET_FUNCTION_CALL 方法。

DATA(lo_response) = lo_model_key->set_auto_invoke_sap_function( abap_true
                               )->generate_content( iv_prompt_text = 'PROMPT' ).
lo_response->get_function_call( IMPORTING ev_function_name       = DATA(lv_function_name)
                                          et_function_parameters = DATA(lt_function_parameters) ).

PROMPT 替换为您的文本提示

您可以从 LV_FUNCTION_NAME 获取 Gemini 所选函数的名称,并从 LT_FUNCTION_PARAMETERS 获取建议的参数。您可以根据贵企业的安全信息和事件管理指南,使用这些信息验证、跟踪和记录 Gemini 操作。

代码示例

以下代码示例展示了如何使用 SAP 函数调用来接收模型的最终回答。

DATA lt_parameters TYPE /goog/cl_generative_model=>tt_parameter_properties.
TRY.
  DATA(lo_model) = NEW /goog/cl_generative_model( iv_model_key = 'MODEL_KEY' ).
  APPEND VALUE #( parameter_name = 'PARAMETER_NAME'
                  type           = 'PARAMETER_TYPE'
                  description    = 'PARAMETER_DESCRIPTION'
                  is_required    = 'PARAMETER_IS_REQUIRED' ) TO lt_parameters.
  DATA(lv_response) = lo_model->add_function_declaration(
                                    iv_name        = 'FUNCTION_MODULE_NAME'
                                    iv_description = 'FUNCTION_MODULE_DESCRIPTION'
                                    it_parameters  = lt_parameters
                              )->set_auto_invoke_sap_function( abap_true
                              )->generate_content( iv_prompt_text ='PROMPT'
                              )->get_text( ).
  IF lv_response IS NOT INITIAL.
      cl_demo_output=>display( lv_response ).

  ENDIF.
 CATCH /goog/cx_sdk INTO DATA(lo_cx_sdk).
  cl_demo_output=>display( lo_cx_sdk->get_text( ) ).

ENDTRY.

替换以下内容:

  • MODEL_KEY:模型键名,可在模型生成参数中配置。
  • PARAMETER_NAME:参数的名称。
  • PARAMETER_TYPE:参数的数据类型,例如 stringintegerboolean
  • PARAMETER_DESCRIPTION:清楚地说明参数的用途和预期格式。
  • PARAMETER_IS_REQUIRED:如果此参数是函数运行所必需的,请将其值设置为 ABAP_TRUE
  • FUNCTION_MODULE_NAME:SAP 函数模块的名称。
  • FUNCTION_MODULE_DESCRIPTION:SAP 函数模块的说明。
  • PROMPT:您的文本提示

通过调用 OData 服务,使用 SAP 数据丰富 Gemini AI 模型上下文

本部分介绍了如何通过调用 OData 服务使用 SAP 数据来丰富 Gemini AI 模型上下文。

以下是 ABAP 开发者调用 OData 服务的典型流程:

  1. 用户提供输入提示。
  2. SDK 将输入提示和函数声明传递给模型。
  3. 该模型会检查提示和声明的函数,以推导要调用的函数,并建议用于调用该函数的参数值。
  4. 如果设置了自动调用,SDK 会调用 OData 服务。
  5. 然后,SDK 会使用所调用 OData 服务的输出调用模型。
  6. 模型会以可靠的答案回答使用所调用 OData 服务的输出丰富的最终提示
  7. SDK 会将回答返回给用户。

如果您选择不自动调用 OData 服务,则 SDK 可让您在不调用任何 OData 服务的情况下使用函数调用功能。在这种情况下,您可以遵循典型的函数调用工作流程来使用外部工具,例如 API 和函数。

在 SAP BTP、ABAP 环境中使用 Gemini 进行 SAP 函数调用

创建 OData 服务

如需创建可由 SDK 作为函数自动调用的 OData 服务,请使用以下架构:

{
    "UserRequest": "Input Prompt as user request",
    "FunctionResponse": null,
    "ModifiedUserRequest": null,
    "ContextParameters": [
        {
            "ParameterName": "Parameter 1",
            "ParameterValue": "Value 1"
        },
        {
            "ParameterName": "Parameter 2",
            "ParameterValue": "Value 2"
        }
    ]
}

下表提供了此架构中使用的字段的相关信息:

架构字段 字段类型 输入/输出模式 说明
UserRequest String 仅限输入 用户输入的输入提示。
FunctionResponse String 仅限输出 OData 服务的输出。它可以是单个值,也可以是序列化的 JSON 字符串。
ModifiedUserRequest String 仅限输出 经过修改的 UserRequest,将作为提示馈送给 Gemini。
ContextParameters Table of parameters 仅限输入 参数表,其中包含参数名称和值。
ParameterName String 仅限输入 函数参数的名称。
ParameterValue String 仅限输入 Gemini 建议的函数参数值。

创建 OData 服务实体

  1. 使用上述架构创建实体。

    此实体会将用户请求作为提示接受,将其转发给 Gemini,并使用 Vertex AI SDK for ABAP 声明为函数。此实体还会将 OData 函数响应从后端 SAP 系统传回到 BTP,然后将其添加到 Gemini AI 模型上下文中。

    1. 为新项设置合适的名称。
    2. 为以下属性设置值。保留所有其他属性的默认值。

      名称 是关键吗? EDM 核心类型 ABAP 字段名称
      UserRequest Edm.String USER_REQUEST
      FunctionResponse Edm.String FUNCTION_RESPONSE
      ModifiedUserRequest Edm.String MODIFIED_USER_REQUEST

    如果您想在同一 OData 服务中放置更多实体,请使用相同的架构创建这些实体。

  2. 创建另一个名为 ContextParameters 的实体,并为其指定以下属性。保留所有其他属性的默认值。

    此实体包含 Gemini 模型提供的函数参数及其值。

    名称 是关键吗? EDM 核心类型 ABAP 字段名称
    ParameterName Edm.String PARAMETER_NAME
    ParameterValue Edm.String PARAMETER_VALUE
  3. 为您在前面的步骤中创建的所有实体创建 entity 集。

  4. 将您在第 1 步中创建的每个实体与您在第 2 步中创建的 ContextParameters 实体相关联,如下所示:

    1. 为关联设置名称。
    2. Principal Entity(主要实体)字段中,设置您在第 1 步中创建的实体的名称。
    3. 主要实体基数字段中,设置 M
    4. 依赖项字段中,设置 ContextParameters
    5. 依赖实体基数字段中,设置 M
    6. 保存并生成 OData 运行时工件。
  5. 在 SAP Gateway 中添加创建的 OData 服务,并激活 ICF 节点。

  6. 为 OData 元数据生成 EDMX 文件,如下所示:

    1. 前往 TCode /iwfnd/maint_services,获取 OData 服务的元数据。
    2. 设置格式并以 .edmx 文件扩展名保存生成的 XML。

编写 OData 函数逻辑

  1. 在生成的 MPC_EXT 类中,添加并启用深度实体类型:

    TYPES:
      BEGIN OF ts_function_deep_entity,
        user_request          TYPE string,
        function_response     TYPE string,
        modified_user_request TYPE string,
        context_parameters    TYPE TABLE OF ts_contextparameters WITH DEFAULT KEY,
    
      END OF ts_function_deep_entity.
    
  2. 请完成以下步骤,重新定义生成的 DPC_EXT 类的 CREATE_DEEP_ENTITY 方法:

    1. 如果您在创建 OData 服务实体部分创建了多个 OData 实体,请为每个 OData 实体添加一个 CASE 语句。
    2. 将 ABAP 逻辑写入响应的 getprepare,以在 BTP 应用中为 Gemini 增强上下文。
    3. FUNCTION_RESPONSE 字段中,设置响应。
    4. MODIFIED_USER_REQUEST 字段中,设置修改后的提示。
    5. 使用 COPY_DATA_TO_REF OData 方法,在消息中绑定整个响应。

    以下代码段是 ABAP 逻辑示例:

    TRY.
         DATA: ls_request TYPE <z*_mpc_ext>=>ts_function_deep_entity.
    
         CASE io_tech_request_context->get_entity_type_name( ).
           WHEN <z*_mpc_ext>=>gc_ENTITY_NAME.
             CALL METHOD io_data_provider->read_entry_data
               IMPORTING
                 es_data = ls_request.
    
     <ABAP logic to formulate OData function response>
    
             ls_request-modified_user_request = 'MODIFIED_GEMINI_PROMPT'.
             ls_request-function_response = 'ODATA_FUNCTION_RESPONSE'.
    
             CALL METHOD me->copy_data_to_ref
               EXPORTING
                 is_data = ls_request
               CHANGING
                 cr_data = er_deep_entity.
     ENDCASE.
         CATCH /iwbep/cx_mgw_busi_exception.
         CATCH /iwbep/cx_mgw_tech_exception.
     ENDTRY.
     ```
    

替换以下内容:

  • ENTITY_TYPE:您在创建 OData 服务实体部分的第 1 步中创建的 OData 实体的名称
  • MODIFIED_GEMINI_PROMPT:Gemini 提供的修改版提示
  • ODATA_FUNCTION_RESPONSE:OData 服务提供的响应

如果您有多个字段,或者有要作为函数响应传递的嵌套结构或表,则可以使用 SDK 的 /GOOG/CL_JSON_UTIL 类的 SERIALIZE_JSON 方法将 ABAP 类型序列化为字符串。

在 SAP BTP 上将 OData 服务定义为服务使用模型

创建 OData 服务后,您需要在 SAP BTP 环境中将其定义为服务使用模型。为此,您需要创建服务使用模型、HTTP 出站服务、通信场景和通信安排。

创建服务使用模型

  1. 在 ABAP 项目中,打开上下文菜单,然后依次选择新建 > 其他 ABAP 代码库对象 > 企业服务 > 服务使用模型
  2. 新服务使用模式窗口中,完成以下步骤:
    1. Package 字段中,选择并上传您在上一部分中生成的 EDMX 文件。
    2. 输入名称和说明。
    3. 远程使用模式字段中,选择 OData
    4. 点击完成

创建 HTTP 出站服务

  1. 在 ABAP 项目中,打开上下文菜单。
  2. 选择您的软件包,然后依次点击新建 > 其他 ABAP 代码库对象
  3. 服务类型字段中,选择 HTTP 服务
  4. Default Path Prefix(默认路径前缀)字段中,输入后端 SAP 系统中 OData 服务的路径前缀。

    您可以访问 SAP Gateway 客户端来查找 OData 路径前缀。您在请求 URI 字段中看到的值是 OData 服务的路径前缀。

  5. 点击下一步

创建通信场景

创建 HTTP 出站服务后,您必须创建通信场景并将出站服务分配给该场景。为此,请完成以下步骤:

  1. 在 ABAP 项目中,选择通信场景,然后点击下一步
  2. New Communication Scenario 窗口中,完成以下步骤:
    1. 输入名称和说明。
    2. 点击下一步
    3. Communication Scenario Type 字段中,选择 Customer Managed
    4. 前往出站标签页。
    5. Allowed Instances 字段中,选择 Per scenario & communication system one instance
    6. 支持的身份验证方法字段中,选中以下复选框:基本X.509OAuth 2.0
    7. OAuth 2.0 Grant Type(OAuth 2.0 授权类型)字段中,选择 SAML 2.0 Bearer Assertion(SAML 2.0 Bearer Assertion)。
    8. 出站服务部分下,点击添加,然后选择您在上一部分创建的出站服务。
    9. Outbound Service 部分,确保 Default Path Prefix(默认路径前缀)正确无误。如果未同步,请点击同步
    10. 保存通信场景。

创建通信安排

  1. 访问安装了 ABAP SDK for Google Cloud 的 BTP ABAP 系统的 SAP Fiori launchpad。
  2. 打开 Communication Arrangement 应用。

    1. 点击 New(新建)。
    2. 在显示的 New Communication Arrangement 对话框中,输入以下字段的值:

      • 场景:选择您在创建通信场景部分中创建的通信场景。
      • Arrangement name:输入通信安排的名称。
    3. 点击创建

    4. 对于显示的通信安排,请在 Communication System 字段中,选择您在上一步中创建的通信系统。

    5. 点击保存

实例化多模态 Gemini 调用程序类

如需在 SAP 中调用函数调用,请使用 /GOOG/CL_GENERATIVE_MODEL 类。您可以通过传递在模型生成参数中配置的模型键来实例化该类。

DATA(lo_model) = NEW /goog/cl_generative_model( iv_model_key = 'MODEL_KEY' ).

MODEL_KEY 替换为模型键名称,该名称在模型生成参数中进行配置。

添加函数声明

如需将 OData 服务作为函数声明添加到 LLM 上下文,您可以使用 ADD_FUNCTION_DECLARATION 方法。每当您需要将 OData 服务作为函数添加到上下文时,都应调用 ADD_FUNCTION_DECLARATION 方法。

DATA lt_parameters TYPE /goog/cl_generative_model=>tt_parameter_properties.
DATA ls_connection_parameters TYPE /goog/cl_generative_model=>ty_connection_parameters.

APPEND VALUE #( parameter_name = 'PARAMETER_NAME'
                type           = 'PARAMETER_TYPE'
                description    = 'PARAMETER_DESCRIPTION'
                is_required    = 'PARAMETER_IS_REQUIRED' ) TO lt_parameters.

ls_connection_parameters-connection_type       = 'ODATA'.
ls_connection_parameters-comm_scenario         = 'COMMUNICATION_SCENARIO'.
ls_connection_parameters-service_id            = 'ODATA_SERVICE_ID'.
ls_connection_parameters-proxy_model_id        = 'ODATA_SERVICE_CONSUMPTION_MODEL_ID'.
ls_connection_parameters-relative_service_root = 'ODATA_ROOT_URI'.
ls_connection_parameters-entity_set_name       = 'ODATA_ENTITY_SET_NAME'.

lo_model->add_function_declaration( iv_name                  = 'FUNCTION_NAME'
                                    iv_description           = 'FUNCTION_DESCRIPTION'
                                    it_parameters            = lt_parameters
                                    is_connection_parameters = ls_connection_parameters ).

替换以下内容:

  • PARAMETER_NAME:参数的名称
  • PARAMETER_TYPE:参数的数据类型,例如 stringintegerboolean
  • PARAMETER_DESCRIPTION:清楚地说明参数的用途和预期格式
  • PARAMETER_IS_REQUIRED:如果此参数是函数运行所必需的,请将其值设置为 ABAP_TRUE
  • COMMUNICATION_SCENARIO:您创建的通信场景的 ID
  • ODATA_SERVICE_ID:您为 OData 服务创建的出站服务的 ID
  • ODATA_SERVICE_CONSUMPTION_MODEL_ID:您为 OData 服务创建的服务使用模型的 ID
  • ODATA_ROOT_URI:后端 SAP 系统中 OData 服务的根 URI
  • ODATA_ENTITY_SET_NAME:要声明为函数的 OData 服务的实体集名称
  • FUNCTION_NAME:您为要使用的 OData 服务声明的函数的名称
  • FUNCTION_DESCRIPTION:您为要使用的 OData 服务声明的函数的说明

设置 OData 服务的自动调用

如需设置 Gemini 模型选择的 SAP 函数 OData 服务的自动调用,您可以使用 SET_AUTO_INVOKE_SAP_FUNCTION 方法。如果在导入参数 IV_AUTO_INVOKE 中传递 ABAP_TRUE,则 SDK 会调用函数模块,并且其回答会包含在 LLM 上下文中,以生成最终回答。

您必须按照创建 SAP 函数模块部分中所述的架构定义函数模块。

lo_model->set_auto_invoke_sap_function( abap_true ).

使用函数调用生成内容

如需将提示文本传递给 Gemini 模型,您可以使用 GENERATE_CONTENT 方法。如需获取 Gemini 生成的回答以及通过函数调用从 SAP 函数模块添加的额外上下文,请使用 GET_TEXT 方法。

DATA(lv_response) = lo_model->generate_content( iv_prompt_text ='PROMPT'
                           )->get_text( ).

PROMPT 替换为您的文本提示

获取所选函数名称和参数值

如需获取 Gemini 选择的函数(从声明的函数中选择)及其建议的参数,请使用 GET_FUNCTION_CALL 方法。

DATA(lo_response) = lo_model_key->set_auto_invoke_sap_function( abap_true
                               )->generate_content( iv_prompt_text = 'PROMPT' ).
lo_response->get_function_call( IMPORTING ev_function_name       = DATA(lv_function_name)
                                          et_function_parameters = DATA(lt_function_parameters) ).

代码示例

以下代码示例展示了如何将 SAP 函数调用与 Odata 服务搭配使用,以接收模型的最终回答:

DATA lt_parameters TYPE /goog/cl_generative_model=>tt_parameter_properties.
DATA ls_connection_parameters TYPE /goog/cl_generative_model=>ty_connection_parameters.
TRY.
     DATA(lo_model) = NEW /goog/cl_generative_model( iv_model_key = 'MODEL_KEY' ).
     APPEND VALUE #( parameter_name = 'PARAMETER_NAME'
                     type           = 'PARAMETER_TYPE'
                     description    = 'PARAMETER_DESCRIPTION'
                     is_required    = 'PARAMETER_IS_REQUIRED' ) TO lt_parameters.

     ls_connection_parameters-connection_type       = 'ODATA'.
     ls_connection_parameters-comm_scenario         = 'COMMUNICATION_SCENARIO'.
     ls_connection_parameters-service_id            = 'ODATA_SERVICE_ID'.
     ls_connection_parameters-proxy_model_id        = 'ODATA_SERVICE_CONSUMPTION_MODEL_ID'.
     ls_connection_parameters-relative_service_root = 'ODATA_ROOT_URI'.
     ls_connection_parameters-entity_set_name       = 'ODATA_ENTITY_SET_NAME'.

     DATA(lv_response) = lo_model_key->add_function_declaration(
                                         iv_name                  = 'FUNCTION_NAME'
                                         iv_description           = 'FUNCTION_DESCRIPTION'
                                         it_parameters            = lt_parameters
                                         is_connection_parameters = ls_connection_parameters
                                   )->set_auto_invoke_sap_function( abap_true
                                   )->generate_content( iv_prompt_text ='PROMPT'
                          )->get_text( ).
        IF lv_response IS NOT INITIAL.
          out->write( lv_response ).

      ENDIF.

  CATCH /goog/cx_sdk INTO DATA(lo_cx_sdk).
      out->write( lo_cx_sdk->get_text( ) ).
ENDTRY.

后续步骤