Skip to content

Commit acfbc5a

Browse files
committed
Updates README
1 parent b8067a1 commit acfbc5a

File tree

1 file changed

+246
-2
lines changed

1 file changed

+246
-2
lines changed

README.md

Lines changed: 246 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
# Prompt generator for LLM Agents
1+
# LLM Agents Prompt Generator
22

33
[![PHP](https://img.shields.io/packagist/php-v/llm-agents-php/agent-site-status-checker.svg?style=flat-square)](https://packagist.org/packages/llm-agents/prompt-generator)
44
[![Latest Version on Packagist](https://img.shields.io/packagist/v/llm-agents/prompt-generator.svg?style=flat-square)](https://packagist.org/packages/llm-agents/prompt-generator)
55
[![Total Downloads](https://img.shields.io/packagist/dt/llm-agents/prompt-generator.svg?style=flat-square)](https://packagist.org/packages/llm-agents/prompt-generator)
66

7+
This package provides a flexible and extensible system for generating chat prompts with all required system and user
8+
messages for LLM agents. It uses an interceptor-based approach to expand generator abilities.
9+
710
### Installation
811

9-
First things first, let's get this package installed:
12+
You can install the package via Composer:
1013

1114
```bash
1215
composer require llm-agents/prompt-generator
@@ -30,9 +33,250 @@ bootloader.
3033
];
3134
}
3235
```
36+
3. Create a bootloader for the prompt generator. Create a file named `PromptGeneratorBootloader.php`
37+
in your `app/src/Application/Bootloader` directory:
38+
39+
```php
40+
namespace App\Application\Bootloader;
41+
42+
use Spiral\Boot\Bootloader\Bootloader;
43+
44+
use LLM\Agents\PromptGenerator\Interceptors\AgentMemoryInjector;
45+
use LLM\Agents\PromptGenerator\Interceptors\InstructionGenerator;
46+
use LLM\Agents\PromptGenerator\Interceptors\LinkedAgentsInjector;
47+
use LLM\Agents\PromptGenerator\Interceptors\UserPromptInjector;
48+
use LLM\Agents\PromptGenerator\PromptGeneratorPipeline;
49+
50+
class PromptGeneratorBootloader extends Bootloader
51+
{
52+
public function defineSingletons(): array
53+
{
54+
return [
55+
PromptGeneratorPipeline::class => static function (
56+
LinkedAgentsInjector $linkedAgentsInjector,
57+
): PromptGeneratorPipeline {
58+
$pipeline = new PromptGeneratorPipeline();
59+
60+
return $pipeline->withInterceptor(
61+
new InstructionGenerator(),
62+
new AgentMemoryInjector(),
63+
$linkedAgentsInjector,
64+
new UserPromptInjector(),
65+
// ...
66+
);
67+
},
68+
];
69+
}
70+
}
71+
```
3372

3473
And that's it! Your Spiral app is now ready to use the agent.
3574

75+
## Usage
76+
77+
Here's an example of how to initialize the prompt generator and generate a prompt:
78+
79+
```php
80+
use App\Domain\Chat\PromptGenerator\SessionContextInjector;
81+
use LLM\Agents\PromptGenerator\Interceptors\AgentMemoryInjector;
82+
use LLM\Agents\PromptGenerator\Interceptors\InstructionGenerator;
83+
use LLM\Agents\PromptGenerator\Interceptors\LinkedAgentsInjector;
84+
use LLM\Agents\PromptGenerator\Interceptors\UserPromptInjector;
85+
use LLM\Agents\PromptGenerator\PromptGeneratorPipeline;
86+
87+
$generator = new PromptGeneratorPipeline();
88+
89+
$generator = $generator->withInterceptor(
90+
new InstructionGenerator(),
91+
new AgentMemoryInjector(),
92+
new LinkedAgentsInjector($agents, $schemaMapper),
93+
new SessionContextInjector(),
94+
new UserPromptInjector()
95+
);
96+
97+
$prompt = $generator->generate($agent, $userPrompt, $context, $initialPrompt);
98+
```
99+
100+
## Interceptors
101+
102+
The package comes with several built-in interceptors:
103+
104+
### InstructionGenerator
105+
106+
This interceptor adds the agent's instruction to the prompt. It includes important rules like responding in markdown
107+
format and thinking before responding to the user.
108+
109+
### AgentMemoryInjector
110+
111+
This interceptor adds the agent's memory to the prompt. It includes both static memory (defined when creating the agent)
112+
and dynamic memory (which can be updated during the conversation).
113+
114+
### LinkedAgentsInjector
115+
116+
This interceptor adds information about linked agents to the prompt. It provides details about other agents that the
117+
current agent can call for help, including their keys, descriptions, and output schemas.
118+
119+
### UserPromptInjector
120+
121+
This interceptor adds the user's input to the prompt as a user message.
122+
123+
## Creating Custom Interceptors
124+
125+
You can create custom interceptors by implementing the `LLM\Agents\PromptGenerator\PromptInterceptorInterface`:
126+
127+
Let's create a `ContextAwarePromptInjector` that adds relevant context to the prompt based on the current time of day
128+
and
129+
user preferences. This example will demonstrate how to create a more sophisticated interceptor that interacts with
130+
external services and modifies the prompt accordingly.
131+
132+
```php
133+
namespace App\PromptGenerator\Interceptors;
134+
135+
use LLM\Agents\LLM\Prompt\Chat\MessagePrompt;
136+
use LLM\Agents\LLM\Prompt\Chat\Prompt;
137+
use LLM\Agents\LLM\Prompt\Chat\PromptInterface;
138+
use LLM\Agents\PromptGenerator\InterceptorHandler;
139+
use LLM\Agents\PromptGenerator\PromptGeneratorInput;
140+
use LLM\Agents\PromptGenerator\PromptInterceptorInterface;
141+
use App\Services\UserPreferenceService;
142+
use App\Services\WeatherService;
143+
144+
class ContextAwarePromptInjector implements PromptInterceptorInterface
145+
{
146+
public function __construct(
147+
private UserPreferenceService $userPreferenceService,
148+
private WeatherService $weatherService,
149+
) {}
150+
151+
public function generate(PromptGeneratorInput $input, InterceptorHandler $next): PromptInterface
152+
{
153+
$userId = $input->context->getUserId(); // Assuming we have this method in our context
154+
$userPreferences = $this->userPreferenceService->getPreferences($userId);
155+
$currentTime = new \DateTime();
156+
$currentWeather = $this->weatherService->getCurrentWeather($userPreferences->getLocation());
157+
158+
$contextMessage = $this->generateContextMessage($currentTime, $userPreferences, $currentWeather);
159+
160+
$modifiedPrompt = $input->prompt;
161+
if ($modifiedPrompt instanceof Prompt) {
162+
$modifiedPrompt = $modifiedPrompt->withAddedMessage(
163+
MessagePrompt::system($contextMessage),
164+
);
165+
}
166+
167+
return $next($input->withPrompt($modifiedPrompt));
168+
}
169+
170+
private function generateContextMessage(\DateTime $currentTime, $userPreferences, $currentWeather): string
171+
{
172+
$timeOfDay = $this->getTimeOfDay($currentTime);
173+
$greeting = $this->getGreeting($timeOfDay);
174+
175+
return <<<PROMPT
176+
{$greeting} Here's some context for this conversation:
177+
- It's currently {$timeOfDay}.
178+
- The weather is {$currentWeather->getDescription()} with a temperature of {$currentWeather->getTemperature()}°C.
179+
- The user prefers {$userPreferences->getCommunicationStyle()} communication.
180+
- The user's interests include: {$this->formatInterests($userPreferences->getInterests())}.
181+
182+
Please take this context into account when generating responses.
183+
PROMPT;
184+
}
185+
186+
private function getTimeOfDay(\DateTime $time): string
187+
{
188+
$hour = (int) $time->format('G');
189+
return match (true) {
190+
$hour >= 5 && $hour < 12 => 'morning',
191+
$hour >= 12 && $hour < 18 => 'afternoon',
192+
$hour >= 18 && $hour < 22 => 'evening',
193+
default => 'night',
194+
};
195+
}
196+
197+
private function getGreeting(string $timeOfDay): string
198+
{
199+
return match ($timeOfDay) {
200+
'morning' => 'Good morning!',
201+
'afternoon' => 'Good afternoon!',
202+
'evening' => 'Good evening!',
203+
'night' => 'Hello!',
204+
};
205+
}
206+
207+
private function formatInterests(array $interests): string
208+
{
209+
return \implode(', ', \array_map(fn($interest) => \strtolower($interest), $interests));
210+
}
211+
}
212+
```
213+
214+
Then, add your custom interceptor to the pipeline:
215+
216+
```php
217+
$generator = $generator->withInterceptor(new ContextAwarePromptInjector(...));
218+
```
219+
220+
## Implementing PromptContextInterface
221+
222+
The `PromptGeneratorInput` includes a `context` property of type `PromptContextInterface`. This interface allows you to
223+
pass custom context data to your interceptors. To use it effectively, you need to create your own implementation of this
224+
interface.
225+
226+
Here's an example of how you might implement the `PromptContextInterface`:
227+
228+
```php
229+
use LLM\Agents\LLM\PromptContextInterface;
230+
231+
class ChatContext implements PromptContextInterface
232+
{
233+
public function __construct(
234+
private string $userId,
235+
private array $sessionData = [],
236+
) {}
237+
238+
public function getUserId(): string
239+
{
240+
return $this->userId;
241+
}
242+
243+
public function getSessionData(): array
244+
{
245+
return $this->sessionData;
246+
}
247+
248+
// Add any other methods you need for your specific use case
249+
}
250+
```
251+
252+
Then, when generating a prompt, you would pass an instance of your custom context:
253+
254+
```php
255+
$context = new ChatContext($userId, $sessionData);
256+
$prompt = $generator->generate($agent, $userPrompt, $context);
257+
```
258+
259+
In your custom interceptors, you can then access this context data:
260+
261+
```php
262+
class ContextAwarePromptInjector implements PromptInterceptorInterface
263+
{
264+
public function generate(PromptGeneratorInput $input, InterceptorHandler $next): PromptInterface
265+
{
266+
$userId = $input->context->getUserId();
267+
$sessionData = $input->context->getSessionData();
268+
269+
// Use this data to customize your prompt
270+
// ...
271+
272+
return $next($input);
273+
}
274+
}
275+
```
276+
277+
By implementing your own `PromptContextInterface`, you can pass any necessary data from your application to your
278+
interceptors, allowing for highly customized and context-aware prompt generation.
279+
36280
## Want to help out? 🤝
37281

38282
We love contributions! If you've got ideas to make this agent even cooler, here's how you can chip in:

0 commit comments

Comments
 (0)