Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/refactor chain processor #159

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/chat-claude-anthropic.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
Message::forSystem('You are a pirate and you write funny.'),
Message::ofUser('What is the Symfony framework?'),
);
$response = $chain->call($messages);
$response = $chain->process($messages);

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/chat-gpt-azure.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@
Message::forSystem('You are a pirate and you write funny.'),
Message::ofUser('What is the Symfony framework?'),
);
$response = $chain->call($messages);
$response = $chain->process($messages);

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/chat-gpt-openai.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
Message::forSystem('You are a pirate and you write funny.'),
Message::ofUser('What is the Symfony framework?'),
);
$response = $chain->call($messages, [
$response = $chain->process($messages, [
'max_tokens' => 500, // specific options just for this call
]);

Expand Down
2 changes: 1 addition & 1 deletion examples/chat-llama-ollama.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
Message::forSystem('You are a helpful assistant.'),
Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'),
);
$response = $chain->call($messages);
$response = $chain->process($messages);

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/chat-llama-replicate.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
Message::forSystem('You are a helpful assistant.'),
Message::ofUser('Tina has one brother and one sister. How many sisters do Tina\'s siblings have?'),
);
$response = $chain->call($messages);
$response = $chain->process($messages);

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/chat-o1-openai.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@
at the beginning and end, not throughout the code.
PROMPT;

$response = (new Chain($platform, $llm))->call(new MessageBag(Message::ofUser($prompt)));
$response = (new Chain($platform, $llm))->process(new MessageBag(Message::ofUser($prompt)));

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/image-describer-binary.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
new Image(dirname(__DIR__).'/tests/Fixture/image.png'),
),
);
$response = $chain->call($messages);
$response = $chain->process($messages);

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/image-describer-url.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
new Image('https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Webysther_20160423_-_Elephpant.svg/350px-Webysther_20160423_-_Elephpant.svg.png'),
),
);
$response = $chain->call($messages);
$response = $chain->process($messages);

echo $response->getContent().PHP_EOL;
6 changes: 3 additions & 3 deletions examples/store-mongodb-similarity-search.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@

$similaritySearch = new SimilaritySearch($platform, $embeddings, $store);
$toolBox = new ToolBox(new ToolAnalyzer(), [$similaritySearch]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(
Message::forSystem('Please answer all user questions only using SimilaritySearch function.'),
Message::ofUser('Which movie fits the theme of the mafia?')
);
$response = $chain->call($messages);
$response = $chain->process(messages: $messages, chainProcessor: $processor);

echo $response->getContent().PHP_EOL;
6 changes: 3 additions & 3 deletions examples/store-pinecone-similarity-search.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@

$similaritySearch = new SimilaritySearch($platform, $embeddings, $store);
$toolBox = new ToolBox(new ToolAnalyzer(), [$similaritySearch]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(
Message::forSystem('Please answer all user questions only using SimilaritySearch function.'),
Message::ofUser('Which movie fits the theme of the mafia?')
);
$response = $chain->call($messages);
$response = $chain->process(messages: $messages, chainProcessor: $processor);

echo $response->getContent().PHP_EOL;
2 changes: 1 addition & 1 deletion examples/stream-claude-anthropic.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
Message::forSystem('You are a thoughtful philosopher.'),
Message::ofUser('What is the purpose of an ant?'),
);
$response = $chain->call($messages, [
$response = $chain->process($messages, [
'stream' => true, // enable streaming of response text
]);

Expand Down
2 changes: 1 addition & 1 deletion examples/stream-gpt-openai.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
Message::forSystem('You are a thoughtful philosopher.'),
Message::ofUser('What is the purpose of an ant?'),
);
$response = $chain->call($messages, [
$response = $chain->process($messages, [
'stream' => true, // enable streaming of response text
]);

Expand Down
10 changes: 6 additions & 4 deletions examples/structured-output-clock.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@

$clock = new Clock(new SymfonyClock());
$toolBox = new ToolBox(new ToolAnalyzer(), [$clock]);
$toolProcessor = new ToolProcessor($toolBox);
$toolProcessor = (new ToolProcessor())->withToolBox($toolBox);
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$structuredOutputProcessor = new StructuredOutputProcessor(new ResponseFormatFactory(), $serializer);
$chain = new Chain($platform, $llm, [$toolProcessor, $structuredOutputProcessor], [$toolProcessor, $structuredOutputProcessor]);
$structuredOutputProcessor->setOutputProcessors([$toolProcessor, $structuredOutputProcessor]);
$structuredOutputProcessor->setInputProcessors([$toolProcessor, $structuredOutputProcessor]);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(Message::ofUser('What date and time is it?'));
$response = $chain->call($messages, ['response_format' => [
$response = $chain->process($messages, ['response_format' => [
'type' => 'json_schema',
'json_schema' => [
'name' => 'clock',
Expand All @@ -51,6 +53,6 @@
'additionalProperties' => false,
],
],
]]);
]], $structuredOutputProcessor);

dump($response->getContent());
4 changes: 2 additions & 2 deletions examples/structured-output-math.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);

$processor = new ChainProcessor(new ResponseFormatFactory(), $serializer);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$chain = new Chain($platform, $llm);
$messages = new MessageBag(
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
Message::ofUser('how can I solve 8x + 7 = -23'),
);
$response = $chain->call($messages, ['output_structure' => MathReasoning::class]);
$response = $chain->process($messages, ['output_structure' => MathReasoning::class], $processor);

dump($response->getContent());
6 changes: 3 additions & 3 deletions examples/toolbox-clock.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

$clock = new Clock(new SymfonyClock());
$toolBox = new ToolBox(new ToolAnalyzer(), [$clock]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(Message::ofUser('What date and time is it?'));
$response = $chain->call($messages);
$response = $chain->process($messages, [], $processor);

echo $response->getContent().PHP_EOL;
6 changes: 3 additions & 3 deletions examples/toolbox-serpapi.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@

$serpApi = new SerpApi(HttpClient::create(), $_ENV['SERP_API_KEY']);
$toolBox = new ToolBox(new ToolAnalyzer(), [$serpApi]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(Message::ofUser('Who is the current chancellor of Germany?'));
$response = $chain->call($messages);
$response = $chain->process(messages: $messages, chainProcessor: $processor);

echo $response->getContent().PHP_EOL;
6 changes: 3 additions & 3 deletions examples/toolbox-weather.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

$wikipedia = new OpenMeteo(HttpClient::create());
$toolBox = new ToolBox(new ToolAnalyzer(), [$wikipedia]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(Message::ofUser('How is the weather currently in Berlin?'));
$response = $chain->call($messages);
$response = $chain->process($messages, [], $processor);

echo $response->getContent().PHP_EOL;
6 changes: 3 additions & 3 deletions examples/toolbox-wikipedia.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

$wikipedia = new Wikipedia(HttpClient::create());
$toolBox = new ToolBox(new ToolAnalyzer(), [$wikipedia]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(Message::ofUser('Who is the current chancellor of Germany?'));
$response = $chain->call($messages);
$response = $chain->process(messages: $messages, chainProcessor: $processor);

echo $response->getContent().PHP_EOL;
8 changes: 4 additions & 4 deletions examples/toolbox-youtube.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@

$transcriber = new YouTubeTranscriber(HttpClient::create());
$toolBox = new ToolBox(new ToolAnalyzer(), [$transcriber]);
$processor = new ChainProcessor($toolBox);
$chain = new Chain($platform, $llm, [$processor], [$processor]);
$processor = (new ChainProcessor())->withToolBox($toolBox);
$chain = new Chain($platform, $llm);

$messages = new MessageBag(Message::ofUser('Please summarize this video for me: https://www.youtube.com/watch?v=6uXW-ulpj0s'));
$response = $chain->call($messages, [
$response = $chain->process($messages, [
'stream' => true, // enable streaming of response text
]);
], $processor);

foreach ($response->getContent() as $word) {
echo $word;
Expand Down
50 changes: 9 additions & 41 deletions src/Chain.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use PhpLlm\LlmChain\Chain\InputProcessor;
use PhpLlm\LlmChain\Chain\Output;
use PhpLlm\LlmChain\Chain\OutputProcessor;
use PhpLlm\LlmChain\Exception\InvalidArgumentException;
use PhpLlm\LlmChain\Exception\MissingModelSupport;
use PhpLlm\LlmChain\Model\LanguageModel;
use PhpLlm\LlmChain\Model\Message\MessageBag;
Expand All @@ -18,37 +17,23 @@

final readonly class Chain implements ChainInterface
{
/**
* @var InputProcessor[]
*/
private array $inputProcessor;

/**
* @var OutputProcessor[]
*/
private array $outputProcessor;

/**
* @param InputProcessor[] $inputProcessor
* @param OutputProcessor[] $outputProcessor
*/
public function __construct(
private PlatformInterface $platform,
private LanguageModel $llm,
iterable $inputProcessor = [],
iterable $outputProcessor = [],
) {
$this->inputProcessor = $this->initializeProcessors($inputProcessor, InputProcessor::class);
$this->outputProcessor = $this->initializeProcessors($outputProcessor, OutputProcessor::class);
}

/**
* @param array<string, mixed> $options
*/
public function call(MessageBag $messages, array $options = []): ResponseInterface
public function process(MessageBag $messages, array $options = [], ?ChainAwareProcessor $chainProcessor = null): ResponseInterface
{
$chainProcessor?->setChain($this);

$input = new Input($this->llm, $messages, $options);
array_map(fn (InputProcessor $processor) => $processor->processInput($input), $this->inputProcessor);
if ($chainProcessor) {
array_map(fn (InputProcessor $processor) => $processor->processInput($input), $chainProcessor->getInputProcessors());
}

if ($messages->containsImage() && !$this->llm->supportsImageInput()) {
throw MissingModelSupport::forImageInput($this->llm::class);
Expand All @@ -61,28 +46,11 @@ public function call(MessageBag $messages, array $options = []): ResponseInterfa
}

$output = new Output($this->llm, $response, $messages, $options);
array_map(fn (OutputProcessor $processor) => $processor->processOutput($output), $this->outputProcessor);

return $output->response;
}

/**
* @param InputProcessor[]|OutputProcessor[] $processors
*
* @return InputProcessor[]|OutputProcessor[]
*/
private function initializeProcessors(iterable $processors, string $interface): array
{
foreach ($processors as $processor) {
if (!$processor instanceof $interface) {
throw new InvalidArgumentException(sprintf('Processor %s must implement %s interface.', $processor::class, $interface));
}

if ($processor instanceof ChainAwareProcessor) {
$processor->setChain($this);
}
if ($chainProcessor) {
array_map(fn (OutputProcessor $processor) => $processor->processOutput($output), $chainProcessor->getOutputProcessors());
}

return $processors instanceof \Traversable ? iterator_to_array($processors) : $processors;
return $output->response;
}
}
28 changes: 26 additions & 2 deletions src/Chain/ChainAwareProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,33 @@

namespace PhpLlm\LlmChain\Chain;

use PhpLlm\LlmChain\Chain;
use PhpLlm\LlmChain\ChainInterface;

interface ChainAwareProcessor
{
public function setChain(Chain $chain): void;
public function setChain(ChainInterface $chain): void;

public function addOutputProcessor(OutputProcessor $outputProcessor): self;

public function addInputProcessor(InputProcessor $outputProcessor): self;

/**
* @return array<InputProcessor>
*/
public function getInputProcessors(): array;

/**
* @return array<OutputProcessor>
*/
public function getOutputProcessors(): array;

/**
* @param array<InputProcessor> $inputProcessors
*/
public function setInputProcessors(array $inputProcessors): self;

/**
* @param array<OutputProcessor> $outputProcessors
*/
public function setOutputProcessors(array $outputProcessors): self;
}
Loading