llm-agents/prompt-generator

具有拦截器的LLM代理的提示生成器

1.3.0 2024-09-15 18:48 UTC

This package is auto-updated.

Last update: 2024-09-15 21:15:08 UTC


README

PHP Latest Version on Packagist Total Downloads

本包提供了一个灵活且可扩展的系统,用于生成聊天提示,其中包含了为LLM代理所需的所有系统和用户消息。它使用基于拦截器的方法来扩展生成器的能力。

安装

您可以通过Composer安装此包

composer require llm-agents/prompt-generator

Spiral框架中的设置

要在Spiral框架项目中启动并运行站点状态检查代理,您需要注册其引导程序。

以下是步骤

  1. 打开您的 app/src/Application/Kernel.php 文件。
  2. 添加引导程序如下
    public function defineBootloaders(): array
    {
        return [
            // ... other bootloaders ...
            \LLM\Agents\PromptGenerator\Integration\Spiral\PromptGeneratorBootloader::class,
        ];
    }
  3. 为提示生成器创建一个引导程序。在您的 app/src/Application/Bootloader 目录中创建一个名为 PromptGeneratorBootloader.php 的文件
namespace App\Application\Bootloader;

use Spiral\Boot\Bootloader\Bootloader;

use LLM\Agents\PromptGenerator\Interceptors\AgentMemoryInjector;
use LLM\Agents\PromptGenerator\Interceptors\InstructionGenerator;
use LLM\Agents\PromptGenerator\Interceptors\LinkedAgentsInjector;
use LLM\Agents\PromptGenerator\Interceptors\UserPromptInjector;
use LLM\Agents\PromptGenerator\PromptGeneratorPipeline;

class PromptGeneratorBootloader extends Bootloader
{
    public function defineSingletons(): array
    {
        return [
            PromptGeneratorPipeline::class => static function (
                LinkedAgentsInjector $linkedAgentsInjector,
            ): PromptGeneratorPipeline {
                $pipeline = new PromptGeneratorPipeline();

                return $pipeline->withInterceptor(
                    new InstructionGenerator(),
                    new AgentMemoryInjector(),
                    $linkedAgentsInjector,
                    new UserPromptInjector(),
                    // ...
                );
            },
        ];
    }
}

就这样!您的Spiral应用现在可以开始使用代理了。

用法

以下是一个初始化提示生成器并生成提示的示例

use App\Domain\Chat\PromptGenerator\SessionContextInjector;
use LLM\Agents\PromptGenerator\Interceptors\AgentMemoryInjector;
use LLM\Agents\PromptGenerator\Interceptors\InstructionGenerator;
use LLM\Agents\PromptGenerator\Interceptors\LinkedAgentsInjector;
use LLM\Agents\PromptGenerator\Interceptors\UserPromptInjector;
use LLM\Agents\PromptGenerator\PromptGeneratorPipeline;

$generator = new PromptGeneratorPipeline();

$generator = $generator->withInterceptor(
    new InstructionGenerator(),
    new AgentMemoryInjector(),
    new LinkedAgentsInjector($agents, $schemaMapper),
    new SessionContextInjector(),
    new UserPromptInjector()
);

$prompt = $generator->generate($agent, $userPrompt, $context, $initialPrompt);

拦截器

该包附带几个内置拦截器

InstructionGenerator

此拦截器将代理的指令添加到提示中。它包括重要的规则,如以Markdown格式响应以及在对用户做出回应之前思考。

AgentMemoryInjector

此拦截器将代理的内存添加到提示中。它包括静态内存(在创建代理时定义)和动态内存(可以在对话期间更新)。

LinkedAgentsInjector

此拦截器将有关链接代理的信息添加到提示中。它提供了有关当前代理可以请求帮助的其他代理的详细信息,包括它们的密钥、描述和输出模式。

UserPromptInjector

此拦截器将用户的输入添加到提示中作为用户消息。

创建自定义拦截器

您可以通过实现 LLM\Agents\PromptGenerator\PromptInterceptorInterface 来创建自定义拦截器

让我们创建一个 ContextAwarePromptInjector,它根据当前时间和用户偏好添加相关上下文。此示例将演示如何创建一个更复杂的拦截器,该拦截器与外部服务交互并根据提示进行修改。

namespace App\PromptGenerator\Interceptors;

use LLM\Agents\LLM\Prompt\Chat\MessagePrompt;
use LLM\Agents\LLM\Prompt\Chat\Prompt;
use LLM\Agents\LLM\Prompt\Chat\PromptInterface;
use LLM\Agents\PromptGenerator\InterceptorHandler;
use LLM\Agents\PromptGenerator\PromptGeneratorInput;
use LLM\Agents\PromptGenerator\PromptInterceptorInterface;
use App\Services\UserPreferenceService;
use App\Services\WeatherService;

class ContextAwarePromptInjector implements PromptInterceptorInterface
{
    public function __construct(
        private UserPreferenceService $userPreferenceService,
        private WeatherService $weatherService,
    ) {}

    public function generate(PromptGeneratorInput $input, InterceptorHandler $next): PromptInterface
    {
        $userId = $input->context->getUserId(); // Assuming we have this method in our context
        $userPreferences = $this->userPreferenceService->getPreferences($userId);
        $currentTime = new \DateTime();
        $currentWeather = $this->weatherService->getCurrentWeather($userPreferences->getLocation());

        $contextMessage = $this->generateContextMessage($currentTime, $userPreferences, $currentWeather);

        $modifiedPrompt = $input->prompt;
        if ($modifiedPrompt instanceof Prompt) {
            $modifiedPrompt = $modifiedPrompt->withAddedMessage(
                MessagePrompt::system($contextMessage),
            );
        }

        return $next($input->withPrompt($modifiedPrompt));
    }

    private function generateContextMessage(\DateTime $currentTime, $userPreferences, $currentWeather): string
    {
        $timeOfDay = $this->getTimeOfDay($currentTime);
        $greeting = $this->getGreeting($timeOfDay);

        return <<<PROMPT
{$greeting} Here's some context for this conversation:
- It's currently {$timeOfDay}.
- The weather is {$currentWeather->getDescription()} with a temperature of {$currentWeather->getTemperature()}°C.
- The user prefers {$userPreferences->getCommunicationStyle()} communication.
- The user's interests include: {$this->formatInterests($userPreferences->getInterests())}.

Please take this context into account when generating responses.
PROMPT;
    }

    private function getTimeOfDay(\DateTime $time): string
    {
        $hour = (int) $time->format('G');
        return match (true) {
            $hour >= 5 && $hour < 12 => 'morning',
            $hour >= 12 && $hour < 18 => 'afternoon',
            $hour >= 18 && $hour < 22 => 'evening',
            default => 'night',
        };
    }

    private function getGreeting(string $timeOfDay): string
    {
        return match ($timeOfDay) {
            'morning' => 'Good morning!',
            'afternoon' => 'Good afternoon!',
            'evening' => 'Good evening!',
            'night' => 'Hello!',
        };
    }

    private function formatInterests(array $interests): string
    {
        return \implode(', ', \array_map(fn($interest) => \strtolower($interest), $interests));
    }
}

然后,将您的自定义拦截器添加到管道

$generator = $generator->withInterceptor(new ContextAwarePromptInjector(...));

查看此UML序列图,了解提示生成过程如何与拦截器一起工作

实现PromptContextInterface

PromptGeneratorInput 包含一个类型为 PromptContextInterfacecontext 属性。此接口允许您将自定义上下文数据传递给您的拦截器。为了有效地使用它,您需要创建自己的接口实现。

以下是如何实现 PromptContextInterface 的示例

use LLM\Agents\LLM\PromptContextInterface;

class ChatContext implements PromptContextInterface
{
    public function __construct(
        private string $userId,
        private array $sessionData = [],
    ) {}

    public function getUserId(): string
    {
        return $this->userId;
    }

    public function getSessionData(): array
    {
        return $this->sessionData;
    }

    // Add any other methods you need for your specific use case
}

然后,在生成提示时,您将传递您的自定义上下文实例

$context = new ChatContext($userId, $sessionData);
$prompt = $generator->generate($agent, $userPrompt, $context);

在您的自定义拦截器中,您可以访问这些上下文数据

class ContextAwarePromptInjector implements PromptInterceptorInterface
{
    public function generate(PromptGeneratorInput $input, InterceptorHandler $next): PromptInterface
    {
        $userId = $input->context->getUserId();
        $sessionData = $input->context->getSessionData();

        // Use this data to customize your prompt
        // ...

        return $next($input);
    }
}

通过实现自己的 PromptContextInterface,您可以传递从应用程序到拦截器的任何必要数据,从而实现高度定制和上下文感知的提示生成。

想要帮忙吗? 🤝

我们喜欢贡献!如果您有让这个代理变得更酷的想法,以下是您可以如何做出贡献

  1. 分支存储库
  2. 进行更改
  3. 创建一个新的Pull Request

只需确保您的代码整洁、有注释,并遵循PSR-12编码标准。

许可证 📄

本项目使用MIT许可证 - 有关详细信息,请参阅LICENSE 文件。

就这些了,各位!如果您有任何问题或遇到任何问题,请毫不犹豫地提出问题。