Skip to content

Commit fdacef0

Browse files
committed
feat: add inline tool definition and chain in chain 🤯
1 parent ac43c9f commit fdacef0

File tree

4 files changed

+56
-23
lines changed

4 files changed

+56
-23
lines changed

README.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,18 @@ llm_chain:
5050
system_prompt: 'You are a helpful assistant that can answer questions.' # The default system prompt of the chain
5151
include_tools: true # Include tool definitions at the end of the system prompt
5252
tools:
53+
# Referencing a service with #[AsTool] attribute
5354
- 'PhpLlm\LlmChain\Chain\Toolbox\Tool\SimilaritySearch'
55+
# Referencing a service without #[AsTool] attribute
5456
- service: 'App\Chain\Tool\CompanyName'
5557
name: 'company_name'
5658
description: 'Provides the name of your company'
5759
method: '__invoke'
58-
- 'llm_chain.chain.research'
60+
# Referencing a chain => chain in chain 🤯
61+
- service: 'llm_chain.chain.research'
62+
name: 'wikipedia_research'
63+
description: 'Can research on Wikipedia'
64+
is_chain: true
5965
research:
6066
platform: 'llm_chain.platform.anthropic'
6167
model:
@@ -64,10 +70,6 @@ llm_chain:
6470
- 'PhpLlm\LlmChain\Chain\Toolbox\Tool\Wikipedia'
6571
- 'App\Chain\Tool\CompanyName'
6672
fault_tolerant_toolbox: false # Disables fault tolerant toolbox, default is true
67-
as_tool:
68-
name: 'wikipedia_research'
69-
description: 'Answers questions based on a research in Wikipedia'
70-
input: 'Question to be researched'
7173
store:
7274
# also azure_search, mongodb and pinecone are supported as store type
7375
chroma_db:
@@ -81,11 +83,6 @@ llm_chain:
8183
model:
8284
name: 'Embeddings'
8385
version: 'text-embedding-ada-002'
84-
tools:
85-
- service: 'App\Chain\Tool\CompanyName'
86-
name: 'company_name'
87-
description: 'Provides the name of your company'
88-
method: '__invoke'
8986
```
9087
9188
## Usage

src/DependencyInjection/Configuration.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,21 @@ public function getConfigTreeBuilder(): TreeBuilder
9898
->children()
9999
->booleanNode('enabled')->defaultTrue()->end()
100100
->arrayNode('services')
101-
->scalarPrototype()->end()
101+
->arrayPrototype()
102+
->children()
103+
->scalarNode('service')->isRequired()->end()
104+
->scalarNode('name')->end()
105+
->scalarNode('description')->end()
106+
->scalarNode('method')->end()
107+
->booleanNode('is_chain')->defaultFalse()->end()
108+
->end()
109+
->beforeNormalization()
110+
->ifString()
111+
->then(function (string $v) {
112+
return ['service' => $v];
113+
})
114+
->end()
115+
->end()
102116
->end()
103117
->end()
104118
->end()

src/DependencyInjection/LlmChainExtension.php

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
use PhpLlm\LlmChain\Chain\Toolbox\Attribute\AsTool;
2727
use PhpLlm\LlmChain\Chain\Toolbox\ChainProcessor as ToolProcessor;
2828
use PhpLlm\LlmChain\Chain\Toolbox\FaultTolerantToolbox;
29+
use PhpLlm\LlmChain\Chain\Toolbox\MetadataFactory\ChainFactory;
30+
use PhpLlm\LlmChain\Chain\Toolbox\MetadataFactory\MemoryFactory;
31+
use PhpLlm\LlmChain\Chain\Toolbox\MetadataFactory\ReflectionFactory;
32+
use PhpLlm\LlmChain\Chain\Toolbox\Tool\Chain as ChainTool;
2933
use PhpLlm\LlmChain\ChainInterface;
3034
use PhpLlm\LlmChain\Embedder;
3135
use PhpLlm\LlmChain\Model\EmbeddingsModel;
@@ -249,8 +253,30 @@ private function processChainConfig(string $name, array $config, ContainerBuilde
249253
if ($config['tools']['enabled']) {
250254
// Create specific toolbox and process if tools are explicitly defined
251255
if (0 !== count($config['tools']['services'])) {
252-
$tools = array_map(static fn (string $tool) => new Reference($tool), $config['tools']['services']);
256+
$memoryFactoryDefinition = new Definition(MemoryFactory::class);
257+
$container->setDefinition('llm_chain.toolbox.'.$name.'.memory_factory', $memoryFactoryDefinition);
258+
$chainFactoryDefinition = new Definition(ChainFactory::class, [
259+
'$factories' => [new Reference('llm_chain.toolbox.'.$name.'.memory_factory'), new Reference(ReflectionFactory::class)],
260+
]);
261+
$container->setDefinition('llm_chain.toolbox.'.$name.'.chain_factory', $chainFactoryDefinition);
262+
263+
$tools = [];
264+
foreach ($config['tools']['services'] as $tool) {
265+
$reference = new Reference($tool['service']);
266+
// We use the memory factory in case method, description and name are set
267+
if (isset($tool['name'], $tool['description'])) {
268+
if ($tool['is_chain']) {
269+
$chainWrapperDefinition = new Definition(ChainTool::class, ['$chain' => $reference]);
270+
$container->setDefinition('llm_chain.toolbox.'.$name.'.chain_wrapper.'.$tool['name'], $chainWrapperDefinition);
271+
$reference = new Reference('llm_chain.toolbox.'.$name.'.chain_wrapper.'.$tool['name']);
272+
}
273+
$memoryFactoryDefinition->addMethodCall('addTool', [$reference, $tool['name'], $tool['description'], $tool['method'] ?? '__invoke']);
274+
}
275+
$tools[] = $reference;
276+
}
277+
253278
$toolboxDefinition = (new ChildDefinition('llm_chain.toolbox.abstract'))
279+
->replaceArgument('$metadataFactory', new Reference('llm_chain.toolbox.'.$name.'.chain_factory'))
254280
->replaceArgument('$tools', $tools);
255281
$container->setDefinition('llm_chain.toolbox.'.$name, $toolboxDefinition);
256282

@@ -424,10 +450,11 @@ private function processEmbedderConfig(int|string $name, array $config, Containe
424450
$modelDefinition->addTag('llm_chain.model.embeddings_model');
425451
$container->setDefinition('llm_chain.embedder.'.$name.'.embeddings', $modelDefinition);
426452

427-
$definition = (new ChildDefinition('llm_chain.embedder.abstract'))
428-
->replaceArgument('$platform', new Reference($config['platform']))
429-
->replaceArgument('$store', new Reference($config['store']))
430-
->replaceArgument('$embeddings', new Reference('llm_chain.embedder.'.$name.'.embeddings'));
453+
$definition = new Definition(Embedder::class, [
454+
'$embeddings' => new Reference('llm_chain.embedder.'.$name.'.embeddings'),
455+
'$platform' => new Reference($config['platform']),
456+
'$store' => new Reference($config['store']),
457+
]);
431458

432459
$container->setDefinition('llm_chain.embedder.'.$name, $definition);
433460
}

src/Resources/config/services.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpLlm\LlmChain\Chain\StructuredOutput\ResponseFormatFactoryInterface;
1010
use PhpLlm\LlmChain\Chain\Toolbox\ChainProcessor as ToolProcessor;
1111
use PhpLlm\LlmChain\Chain\Toolbox\MetadataFactory;
12+
use PhpLlm\LlmChain\Chain\Toolbox\MetadataFactory\MemoryFactory;
1213
use PhpLlm\LlmChain\Chain\Toolbox\MetadataFactory\ReflectionFactory;
1314
use PhpLlm\LlmChain\Chain\Toolbox\Toolbox;
1415
use PhpLlm\LlmChain\Chain\Toolbox\ToolboxInterface;
@@ -21,13 +22,6 @@
2122
->defaults()
2223
->autowire()
2324

24-
// high level feature
25-
->set('llm_chain.embedder.abstract', Embedder::class)
26-
->abstract()
27-
->args([
28-
'$embeddings' => abstract_arg('Embeddings model'),
29-
])
30-
3125
// structured output
3226
->set(ResponseFormatFactory::class)
3327
->alias(ResponseFormatFactoryInterface::class, ResponseFormatFactory::class)
@@ -41,6 +35,7 @@
4135
->autowire()
4236
->abstract()
4337
->args([
38+
'$metadataFactory' => service(MetadataFactory::class),
4439
'$tools' => abstract_arg('Collection of tools'),
4540
])
4641
->set(Toolbox::class)

0 commit comments

Comments
 (0)