Skip to content

Commit

Permalink
New example
Browse files Browse the repository at this point in the history
  • Loading branch information
ddebowczyk committed Oct 2, 2024
1 parent 1c2837a commit adede3c
Show file tree
Hide file tree
Showing 36 changed files with 824 additions and 189 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"symfony/dom-crawler": "^7.1",
"duzun/hquery": "^3.1",
"ext-dom": "*",
"psy/psysh": "@stable"
"psy/psysh": "@stable",
"symfony/http-client": "^7.1"
},
"config": {
"allow-plugins": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ offers you #[Assert/Callback] annotation to build fully customized validation lo
$loader = require 'vendor/autoload.php';
$loader->add('Cognesy\\Instructor\\', __DIR__.'../../src/');


use Cognesy\Instructor\Events\Request\RequestSentToLLM;
use Cognesy\Instructor\Instructor;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
Expand Down
73 changes: 73 additions & 0 deletions docs/cookbook/examples/basics/validation_with_llm.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: 'Validation with LLM'
docname: 'validation_with_llm'
---

## Overview

You can use LLM capability to semantically process the context to validate
the response following natural language instructions. This way you can
implement more complex validation logic that would be difficult (or impossible)
to achieve using traditional, code-based validation.

## Example

<?php
$loader = require 'vendor/autoload.php';
$loader->add('Cognesy\\Instructor\\', __DIR__.'../../src/');

use Cognesy\Instructor\Events\Event;
use Cognesy\Instructor\Extras\Scalar\Scalar;
use Cognesy\Instructor\Instructor;
use Cognesy\Instructor\Schema\Attributes\Description;
use Cognesy\Instructor\Utils\Str;
use Cognesy\Instructor\Validation\Traits\ValidationMixin;
use Cognesy\Instructor\Validation\ValidationResult;

class UserDetails
{
use ValidationMixin;

public string $name;
#[Description('User details in format: key=value')]
/** @var string[] */
public array $details;

public function validate() : ValidationResult {
return match($this->hasPII()) {
true => ValidationResult::fieldError(
field: 'details',
value: implode('\n', $this->details),
message: "Details contain PII, remove it from the response."
),
false => ValidationResult::valid(),
};
}

private function hasPII() : bool {
$data = implode('\n', $this->details);
return (new Instructor)->respond(
messages: "Context:\n$data\n",
responseModel: Scalar::boolean('hasPII', 'Does the context contain any PII?'),
);
}
}

$text = <<<TEXT
My name is Jason. I am is 25 years old. I am developer.
My phone number is +1 123 34 45 and social security number is 123-45-6789
TEXT;

$user = (new Instructor)
->wiretap(fn(Event $e) => $e->print()) // let's check the internals of Instructor processing
->respond(
messages: $text,
responseModel: UserDetails::class,
maxRetries: 2
);

dump($user);

assert(!Str::contains(implode('\n', $user->details), '123-45-6789'));
?>
```
58 changes: 0 additions & 58 deletions docs/cookbook/examples/extras/web_crawler.mdx

This file was deleted.

5 changes: 3 additions & 2 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@
"cookbook/examples/basics/attributes",
"cookbook/examples/basics/using_config",
"cookbook/examples/basics/validation",
"cookbook/examples/basics/validation_multifield"
"cookbook/examples/basics/custom_validation",
"cookbook/examples/basics/validation_multifield",
"cookbook/examples/basics/validation_with_llm"
]
},
{
Expand All @@ -146,7 +148,6 @@
"cookbook/examples/advanced/context_cache",
"cookbook/examples/advanced/custom_client",
"cookbook/examples/advanced/custom_prompts",
"cookbook/examples/advanced/custom_validation",
"cookbook/examples/advanced/structured_input",
"cookbook/examples/advanced/function_calls",
"cookbook/examples/advanced/partials",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
$loader = require 'vendor/autoload.php';
$loader->add('Cognesy\\Instructor\\', __DIR__.'../../src/');


use Cognesy\Instructor\Events\Request\RequestSentToLLM;
use Cognesy\Instructor\Instructor;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
Expand Down
73 changes: 73 additions & 0 deletions examples/A01_Basics/ValidationWithLLM/run.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: 'Validation with LLM'
docname: 'validation_with_llm'
---

## Overview

You can use LLM capability to semantically process the context to validate
the response following natural language instructions. This way you can
implement more complex validation logic that would be difficult (or impossible)
to achieve using traditional, code-based validation.

## Example

<?php
$loader = require 'vendor/autoload.php';
$loader->add('Cognesy\\Instructor\\', __DIR__.'../../src/');

use Cognesy\Instructor\Events\Event;
use Cognesy\Instructor\Extras\Scalar\Scalar;
use Cognesy\Instructor\Instructor;
use Cognesy\Instructor\Schema\Attributes\Description;
use Cognesy\Instructor\Utils\Str;
use Cognesy\Instructor\Validation\Traits\ValidationMixin;
use Cognesy\Instructor\Validation\ValidationResult;

class UserDetails
{
use ValidationMixin;

public string $name;
#[Description('User details in format: key=value')]
/** @var string[] */
public array $details;

public function validate() : ValidationResult {
return match($this->hasPII()) {
true => ValidationResult::fieldError(
field: 'details',
value: implode('\n', $this->details),
message: "Details contain PII, remove it from the response."
),
false => ValidationResult::valid(),
};
}

private function hasPII() : bool {
$data = implode('\n', $this->details);
return (new Instructor)->respond(
messages: "Context:\n$data\n",
responseModel: Scalar::boolean('hasPII', 'Does the context contain any PII?'),
);
}
}

$text = <<<TEXT
My name is Jason. I am is 25 years old. I am developer.
My phone number is +1 123 34 45 and social security number is 123-45-6789
TEXT;

$user = (new Instructor)
->wiretap(fn(Event $e) => $e->print()) // let's check the internals of Instructor processing
->respond(
messages: $text,
responseModel: UserDetails::class,
maxRetries: 2
);

dump($user);

assert(!Str::contains(implode('\n', $user->details), '123-45-6789'));
?>
```
3 changes: 2 additions & 1 deletion notes/NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
- Extract APIClient to a separate package?
- Foreign client support - OpenAI PHP, Amazon Bedrock SDK, etc. - via some kind of adapters?
- example of integration with Laravel/Livewire

- Read rate limits from API responses
- Rate limited API calls - wait for the limit to reset



Expand Down
78 changes: 0 additions & 78 deletions src/Core/Factories/RequestFactory.php

This file was deleted.

4 changes: 4 additions & 0 deletions src/Data/RequestInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ class RequestInfo
public function isStream() : bool {
return $this->options['stream'] ?? false;
}

public function toMessages() : array {
return $this->messages;
}
}
28 changes: 28 additions & 0 deletions src/Extras/Codebase/Actions/ExtractClasses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Cognesy\Instructor\Extras\Codebase\Actions;

use Cognesy\Instructor\Extras\Codebase\Codebase;
use PhpParser\Node;
use PhpParser\NodeFinder;

class ExtractClasses
{
private Codebase $codebase;

public function __construct(Codebase $codebase) {
$this->codebase = $codebase;
}

public function __invoke(array $ast): array {
$nodeFinder = new NodeFinder();
$classes = $nodeFinder->findInstanceOf($ast, Node\Stmt\Class_::class);

$classList = [];
foreach ($classes as $class) {
$classObject = (new MakeClass($this->codebase))($class);
$classList[$classObject->name] = $classObject;
}
return $classList;
}
}
Loading

0 comments on commit adede3c

Please sign in to comment.