manuelkiessling/ai-tool-bridge

无缝提升您的AI集成能力,使其与您的代码和服务交互

v0.1.1 2023-05-24 10:08 UTC

README

无缝提升您的AI集成能力,使其与您的代码和服务交互

注意:本产品为独立开发,与OpenAI无关,未获得其认可、赞助或支持。

安装

使用 Composer 将此包作为依赖项安装。

composer require manuelkiessling/ai-tool-bridge

概述

将AI集成到任何项目的主要挑战是管理AI与应用程序其他部分的交互。当AI需要调用API以检索信息或触发操作时,这变得尤为复杂。

PHP的AI Tool Bridge优雅地解决了这个问题,它提供了一个简单的接口来定义AI可以利用的“工具函数”,以便在与外部系统交互时使用。

一个重要的优化是库能够生成工具函数所需的JSON结构。它通过仅从AI请求所需值,然后根据提供的JSON模式生成JSON来完成。这种方法确保了最终到达您的应用程序代码的JSON的有效性。

此库的关键特性包括

  • 促进定义AI可以用于外部交互的工具。
  • 提供强大的提示结构,以指导AI何时以及如何使用这些工具。
  • 确保工具以完整和正确格式化的JSON触发。

示例

假设您有一家电商业务,并希望提供一个AI聊天界面,允许浏览您的产品目录。为此,您决定通过ChatGPT API与OpenAI的GPT-4模型集成。

您可能会提示AI助手“您是一个友好而乐于助人的购物助手,向用户介绍我们的产品目录...”等等。

但是,您不能将整个产品目录添加到提示中。因此,当用户要求AI“告诉我一些在售的厨房助手”时,您需要识别在这个对话阶段,AI需要从您的电商后端系统(例如,通过向您的产品搜索API发出带有查询“厨房助手”的请求)获取信息,您需要为AI检索这些信息,并将结果信息返回给AI助手,然后AI助手可以为用户总结产品信息。

AI最清楚何时需要从外部世界获取这些信息。由于让您的代码监听对话并猜测何时进行产品搜索API调用既复杂又容易出错,这使使用强大AI的想法变得有些毫无意义。

最佳方法是让AI认识到与外部世界交谈的时机已经到来,并以结构化和明确的方式进行。

解决方案是在初始系统提示中教会AI,它有一或多个工具可供使用。

这是通过首先编写所谓的工具函数定义来完成的,如下所示

<?php

declare(strict_types=1);

namespace ManuelKiessling\AiToolBridge\Example;

use ManuelKiessling\AiToolBridge\ToolFunctionCallResult;
use ManuelKiessling\AiToolBridge\ToolFunctionCallResultStatus;
use ManuelKiessling\AiToolBridge\ToolFunction;

class MyProductSearchToolFunction implements ToolFunction
{
    public function getName(): string
    {
        return 'productSearch';
    }

    public function getDescription(): string
    {
        return 'allows to search the product catalogue and retrieve information about products';
    }

    public function getInputJsonSchema(): string
    {
        return <<<'JSON'
{
  "type": "object",
  "properties": {
    "searchterms": {
      "type": "string"
    }
  },
  "required": [
    "searchterms"
  ]
}
JSON;
    }

    public function invoke(string $json): ToolFunctionCallResult
    {
        // we will talk about this in a minute
        return new ToolFunctionCallResult(
            $this,
            ToolFunctionCallResultStatus::SUCCESS,
            '',
            []
        );
    }
}

确保名称、描述和JSON模式中的对象键是有用且描述性的 - 这有助于AI理解何时以及如何使用此工具函数。

您可以定义多个工具函数定义 - 例如,可以添加另一个工具函数,当用户要求时,使AI能够将产品放入购物车。尽管如此,我们将保持此示例简单。

接下来,您需要将工具桥接器与现有的AI设置集成。这是使用AiToolBridge辅助程序完成的。

class Example
{
    private AiToolBridge $aiToolBridge;
    private MyAiService $myAiService;

    public function __construct()
    {
        $this->myAiService = new MyAiService();

        $myProductSearchToolFunction = new MyProductSearchToolFunction();

        $this->aiToolBridge = new AiToolBridge(
            new $this->myAiService,
            [$myProductSearchToolFunction],
        );

        $this->myAiService->setSystemPrompt(
            "You are a friendly and helpful shopping assistant that informs the user about our product catalog...
             {$this->aiToolBridge->getPrompt()}"
        );
    }
}

这显然需要做出几个假设 - 您的应用程序结构和您如何集成AI服务可能会有很大的不同。

尽管如此,集成点始终相同。因为这个库需要能够与AI助手交流,您必须提供一个实现了接口AiAssistantMessenger的对象。请参阅src/Example/MyAiService.php以获取一个基本示例。

您还需要在创建AiToolBridge对象时附加您定义的工具函数。

接下来,为了使AI理解它可以使用您的工具,您需要将此库生成的提示扩展到您自己的AI“系统”提示中。为此,使用上面显示的方法AiToolBridge::getPrompt

您的应用程序和此库现在已完全集成和设置。不过,还缺少一个核心部分 - 当AI使用您的工具函数时应该触发的实际行为。

让我们再次看看类MyProductSearchToolFunction中的方法invoke

public function invoke(string $json): ToolFunctionCallResult
{
    return new ToolFunctionCallResult(
        $this,
        ToolFunctionCallResultStatus::SUCCESS,
        '',
        []
    );
}

这里需要发生魔法 - 也就是说,这是实现所有逻辑的地方 - 您的逻辑 - 以执行实际的产品搜索。

在这里,您根本不需要考虑任何AI集成 - 这正是此库的目的,为您承担重任。

更准确地说,当调用invoke方法时,繁重的工作已经完成 - 您可以放心,该方法将以一个JSON字符串调用,该字符串一方面具有您在方法MyProductSearchToolFunction::getInputJsonSchema中定义的精确结构,另一方面填充了AI在使用工具函数时认为有用的值。

因此,例如,如果AI与用户的对话是这样的

AI: Hello, how can I help you?

User: Tell me about some kitchen helpers on offer.

那么AI将认识到它应该使用工具函数productSearch来搜索kitchen helpers,这最终导致调用MyProductSearchToolFunction::invoke并带有以下JSON字符串

{
    "searchterms": "kitchen helpers"
}

您对如何实现此方法有完全的自由(只要返回一个ToolFunctionCallResult对象)。在我们的示例中,实际上执行产品搜索显然是有意义的,但如何执行这一点完全取决于您。查询数据库、与API交谈或任何其他检索有关“厨房助手”的生产信息的方法。

您需要返回的ToolFunctionCallResult对象上的两个感兴趣的领域是messagedata。在我们的示例中,它可能看起来像这样

public function invoke(string $json): ToolFunctionCallResult
{
    $jsonAsArray = json_decode($json, true);
    
    // use $jsonAsArray['searchterm'] when talking to a DB or an API...
    
    return new ToolFunctionCallResult(
        $this,
        ToolFunctionCallResultStatus::SUCCESS,
        'Found 2 matching products',
        [
            [
                'id' => 84,
                'name' => 'Kawaii Chick Egg Separator',
                'price' => 14.99,
                'description' => 'Whether you’re a beginner baker or an experienced cook, the Kawaii Chick Egg Separator is a must-have kitchen tool that will make separating eggs a breeze.'
            ],
            [
                'id' => 2389,
                'name' => 'BlendJet 2',
                'price' => 49.99,
                'description' => 'Imagine the freedom of being able to go anywhere and blend your favorite smoothies, shakes, margaritas, frappés, or baby food without the limitations of a regular blender.'
            ]
        ]
    );
}

data格式不受任何特定模式的限制。

让我们来看看最后一部分,并回到我们的Example类。我们假设在您的实现中有一个方法handleAssistantMessage,每当您的应用程序检索到新的AI助手消息时就会调用它 - 这又是您的应用程序的一个非常具体的实现细节。

这是我们在将消息发送给用户之前“挂钩”到对话的地方。这允许工具库检测AI中的任何工具函数请求并相应地处理它。

如果工具函数已调用并成功,我们需要将结果反馈给AI助手 - 这样,它就可以了解与它的产品搜索相匹配的产品。

<?php

declare(strict_types=1);

class Example
{

    // ...

    public function handleAssistantMessage(string $message): void
    {
        $toolFunctionCallResult = $this->aiToolBridge->handleAssistantMessage($message);
    
        if (is_null($toolFunctionCallResult)) {
            // The AI didn't use a tool function, thus its message is meant for the user
            $this->sendAssistantMessageToUser($message);
        } else {
            // The AI used a tool function, we now need to send the result to the AI
            $dataAsJson = json_encode($toolFunctionCallResult->data);
            $this->sendUserMessageToAssistant($toolFunctionCallResult->message . ' ' . $dataAsJson);
        }
    }
    
    public function sendAssistantMessageToUser(string $message): void
    {
        // whatever code is needed to show an AI assistant message to the user
    }
    
    public function sendUserMessageToAssistant(string $message): void
    {
        // whatever code is needed to send a message to the AI assistant
    }
}

如您所见,当我们向AI助手告知卷函数结果时,我们充当用户向助手告知这一信息。这是因为从AI助手的视角来看,它最初确实是用户提供给AI的工具!请参阅src/AiToolBridge.php方法,了解为什么是这样的。

贡献

欢迎贡献!要贡献,请熟悉CONTRIBUTING.md

协调披露

确保用户信息的安全和保密是我们的首要任务,我们欢迎外部安全研究者的贡献。如果您认为您在此存储库维护的软件中发现了安全漏洞,请阅读SECURITY.md以获取提交漏洞报告的说明。

版权和许可

PHP的AI工具桥由Manuel Kießling版权所有,并按照自由软件基金会发布的GNU通用公共许可证(GPL-3.0-or-later)的条款许可使用。

请参阅LICENSENOTICE以获取更多信息。