mirror of
https://github.com/kennethreitz/instructor.git
synced 2026-06-05 22:50:18 +00:00
clean docs
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
# Using the Prompt Pipeline
|
||||
# Using the Prompt Pipeline
|
||||
|
||||
To get started with this api we must first instantiate a `ChatCompletion` object and build the api call
|
||||
by piping messages and functions to it.
|
||||
To use the Prompt Pipeline in OpenAI Function Call, you need to instantiate a `ChatCompletion` object and build the API call by piping messages and functions to it.
|
||||
|
||||
## The ChatCompletion Object
|
||||
|
||||
The `ChatCompletion` object is the starting point for constructing your API call. It provides the necessary methods and attributes to define the conversation flow and include function calls.
|
||||
|
||||
::: openai_function_call.dsl.completion
|
||||
|
||||
|
||||
+38
-54
@@ -1,81 +1,54 @@
|
||||
# Example: Segmenting search queries
|
||||
# Example: Segmenting Search Queries
|
||||
|
||||
This example will try to highlight a few ways of leveraging `MultiTask`, `enum.Enum`, and using methods to create powerful extrations that make using LLMS feel like regular code.
|
||||
In this example, we will demonstrate how to leverage the `MultiTask` and `enum.Enum` features of OpenAI Function Call to segment search queries. We will define the necessary structures using Pydantic and demonstrate how to execute the segmented queries.
|
||||
|
||||
## Defining the structures
|
||||
## Defining the Structures
|
||||
|
||||
Lets model the problem as breaking down a search request into a list of search requests, we'll add some enums to make it interesting and
|
||||
take advantage of the fact that these are python objects and add some additional query logic
|
||||
Let's model the problem as breaking down a search request into a list of search queries. We will use an enum to represent different types of searches and take advantage of Python objects to add additional query logic.
|
||||
|
||||
```python
|
||||
import enum
|
||||
|
||||
from pydantic import Field
|
||||
from openai_function_call import OpenAISchema
|
||||
|
||||
|
||||
class SearchType(str, enum.Enum):
|
||||
"""Enumeration representing the types of searches that can be performed."""
|
||||
|
||||
VIDEO = "video"
|
||||
EMAIL = "email"
|
||||
|
||||
|
||||
class Search(OpenAISchema):
|
||||
"""
|
||||
Class representing a single search query.
|
||||
|
||||
Args:
|
||||
title (str): The title of the request.
|
||||
query (str): The query string to search for.
|
||||
type (SearchType): The type of search to perform.
|
||||
"""
|
||||
|
||||
title: str = Field(..., description="Title of the request")
|
||||
query: str = Field(..., description="Query to search for relevant content")
|
||||
type: SearchType = Field(..., description="Type of search")
|
||||
|
||||
async def execute(self):
|
||||
print(
|
||||
f"Searching for `{self.title}` with query `{self.query}` using `{self.type}`"
|
||||
)
|
||||
print(f"Searching for `{self.title}` with query `{self.query}` using `{self.type}`")
|
||||
```
|
||||
|
||||
!!! tip "Data can have computation!"
|
||||
Notice that we can have an `execute` method on the class that routes the search query based on the enum type.
|
||||
Notice that we have added the `execute` method to the `Search` class. This method can be used to route the search query based on the enum type. You can add logic specific to each search type in the `execute` method.
|
||||
|
||||
```python
|
||||
async def execute(self)
|
||||
if self.type == SearchType.VIDEO:
|
||||
...
|
||||
else:
|
||||
...
|
||||
return
|
||||
```
|
||||
|
||||
This can be called after to run the queries
|
||||
|
||||
### Multiple queries
|
||||
|
||||
Often times a request might have multiple queries, we can manually create another class with a list attribute to represent this
|
||||
Next, let's define a class to represent multiple search queries.
|
||||
|
||||
```python
|
||||
from typing import List
|
||||
|
||||
class MultiSearch(OpenAISchema):
|
||||
"Correctly segmented set of search results"
|
||||
tasks: List[Search]
|
||||
```
|
||||
|
||||
!!! tips "Prompting is important"
|
||||
Its important to add docstrings and field descriptions to improve your prompting, even adding 'correctly' often leads to better results.
|
||||
The `MultiSearch` class has a single attribute, `tasks`, which is a list of `Search` objects.
|
||||
|
||||
!!! usage "Multiple Tasks"
|
||||
The pattern of defining a task and then multiple tasks is common enought that I made a helper `openai_function_call.dsl.MultiTask` to avoid writing generic code.
|
||||
## Using the Prompt Pipeline
|
||||
|
||||
## Putting it all together
|
||||
|
||||
Without using the lets define a function with some type hints
|
||||
To segment a search query, we will use the Prompt Pipeline in OpenAI Function Call. We can define a function that takes a string and returns segmented search queries using the `MultiSearch` class.
|
||||
|
||||
```python
|
||||
import openai
|
||||
|
||||
def segment(data: str) -> MultiSearch:
|
||||
completion = openai.ChatCompletion.create(
|
||||
model="gpt-3.5-turbo-0613",
|
||||
@@ -90,25 +63,36 @@ def segment(data: str) -> MultiSearch:
|
||||
],
|
||||
max_tokens=1000,
|
||||
)
|
||||
|
||||
return MultiSearch.from_response(completion)
|
||||
```
|
||||
|
||||
!!! tips "Typehints"
|
||||
If you're using an IDE its a great idea to have type hints as
|
||||
they make your developer experience better. Its easier to read, and intelligent autocomplete gives you more confidence.
|
||||
The `segment` function takes a string `data` and creates a completion using the Prompt Pipeline. It prompts the model to segment the data into multiple search queries and returns the result as a `MultiSearch` object.
|
||||
|
||||
## Evaluating an example
|
||||
## Evaluating an Example
|
||||
|
||||
Let's evaluate an example by segmenting a search query and executing the segmented queries.
|
||||
|
||||
```python
|
||||
queries = segment(
|
||||
"Please send me the video from last week about the investment case study and also documents about your GPDR policy?"
|
||||
)
|
||||
asyncio.gather([q.execute() for q in queries.tasks])
|
||||
import asyncio
|
||||
|
||||
queries = segment("Please send me the video from last week about the investment case study and also documents about your GDPR policy?")
|
||||
|
||||
async def execute_queries(queries: Multisearch):
|
||||
await asyncio.gather(*[q.execute() for q in queries.tasks])
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(execute_queries())
|
||||
loop.close()
|
||||
```
|
||||
|
||||
By using async we can execute the queries efficiently with fairly modular and simple code.
|
||||
In this example, we use the `segment` function to segment the search query. We then use `asyncio` to asynchronously execute the queries using the `execute` method defined in the `Search` class.
|
||||
|
||||
```bash
|
||||
Searching for `Video` with query `investment case study` using `SearchType.VIDEO`
|
||||
Searching for `Documents` with query `GPDR policy` using `SearchType.EMAIL`
|
||||
```
|
||||
The output will be:
|
||||
|
||||
```
|
||||
Searching for `Please send me the video from last week about the investment case study` with query `Please send me the video from last week about the investment case study` using `SearchType.VIDEO`
|
||||
Searching for `also documents about your GDPR policy?` with query `also documents about your GDPR policy?` using `SearchType.EMAIL`
|
||||
```
|
||||
|
||||
This demonstrates how to use the Prompt Pipeline to segment search queries and execute them asynchronously.
|
||||
+13
-14
@@ -1,34 +1,33 @@
|
||||
# Welcome to OpenAI Function Call
|
||||
|
||||
We offer a minially invasive extention of `Pydantic.BaseModel` named `OpenAISchema`. It only has two methods, one to generate the correct schema, and one to produce the class from the completion.
|
||||
OpenAI Function Call is a library that provides a minimal and non-intrusive extension to the `Pydantic.BaseModel` class called `OpenAISchema`. It offers two main methods: `openai_schema` for generating the correct schema and `from_response` for creating an instance of the class from the completion result.
|
||||
|
||||
This library is more, so a list of examples and a helper class so I'll keep the example as just structured extraction.
|
||||
The library primarily focuses on showcasing examples and providing a helper class, so I'll keep the example as a simple structured extraction.
|
||||
|
||||
If the OpenAI is a chef's knife of code, I hope you sell you a nice handle which comes with a little pamplet of cuttign techniques.
|
||||
If OpenAI is like a chef's knife for code, I aim to provide you with a nice handle and a little booklet of cutting techniques. OpenAI Function Call leverages the data validation capabilities of the Pydantic library to handle output parsing in a structured and reliable manner.
|
||||
|
||||
It leverages the data validation capabilities of the Pydantic library to handle output parsing in a more structured and reliable manner.
|
||||
If you have any feedback or need assistance, feel free to leave an issue or reach out to me on [Twitter](https://twitter.com/jxnlco).
|
||||
|
||||
If you have any feedback, leave an issue or hit me up on [twitter](https://twitter.com/jxnlco).
|
||||
|
||||
If you're looking for something more batteries included I strongly recommend [MarvinAI](https://www.askmarvin.ai/) which offers a high level api but does not provide as much access to prompting.
|
||||
If you're looking for a more comprehensive solution with batteries included, I highly recommend [MarvinAI](https://www.askmarvin.ai/). MarvinAI provides a high-level API but doesn't offer as much access to prompting.
|
||||
|
||||
!!! tip "Just rip it out!"
|
||||
If you don't want to install dependencies. I recommend literally ripping the `function_calls.py` into your own codebase. [[source code]](https://github.com/jxnl/openai_function_call/blob/main/openai_function_call/function_calls.py)
|
||||
If you don't want to install dependencies, you can literally take the `function_calls.py` file from the library's source code and add it to your own codebase. You can find the [source code here](https://github.com/jxnl/openai_function_call/blob/main/openai_function_call/function_calls.py).
|
||||
|
||||
## Installation
|
||||
|
||||
```python
|
||||
You can install OpenAI Function Call using pip:
|
||||
|
||||
```sh
|
||||
pip install openai_function_call
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Below are examples showcasing the use of function calls and schemas with OpenAI and Pydantic. In later docs we'll go over a wide array of more creative uses.
|
||||
Below are some examples that demonstrate the usage of function calls and schemas with OpenAI and Pydantic. In subsequent documentation, we will explore more creative use cases.
|
||||
|
||||
### Example 1: Extraction
|
||||
|
||||
!!! Tip
|
||||
Prompt are now sourced from docstrings and descriptions, so write clear and descriptive documentation!
|
||||
Prompts are now sourced from docstrings and field descriptions, so it's important to write clear and descriptive documentation for your schemas.
|
||||
|
||||
```python
|
||||
import openai
|
||||
@@ -38,7 +37,7 @@ from pydantic import Field
|
||||
|
||||
class UserDetails(OpenAISchema):
|
||||
"""Details of a user"""
|
||||
name: str = Field(..., description="users's full name")
|
||||
name: str = Field(..., description="User's full name")
|
||||
age: int
|
||||
|
||||
completion = openai.ChatCompletion.create(
|
||||
@@ -52,7 +51,7 @@ completion = openai.ChatCompletion.create(
|
||||
)
|
||||
|
||||
user_details = UserDetails.from_response(completion)
|
||||
print(user_details) # name="John Doe", age=30
|
||||
print(user_details) # UserDetails(name='John Doe', age=30)
|
||||
```
|
||||
|
||||
### Example 2: Function Calls
|
||||
|
||||
+12
-14
@@ -1,25 +1,23 @@
|
||||
# OpenAI Schema
|
||||
|
||||
We offer a minimally invasive extention of `Pydantic.BaseModel` named `OpenAISchema`. It only has two methods, one to generate the correct schema, and one to produce the class from the completion.
|
||||
The `OpenAISchema` is an extension of `Pydantic.BaseModel` that offers a minimally invasive way to define schemas for OpenAI completions. It provides two main methods: `openai_schema` to generate the correct schema and `from_response` to create an instance of the class from the completion result.
|
||||
|
||||
!!! note "Where does the prompt go?"
|
||||
Our philosphy is that the prompt should live beside the code. Prompting is done via dostrings and field descriptions which allows you to colocate prompts with your schema.
|
||||
## Prompt Placement
|
||||
|
||||
Our philosophy is to keep prompts close to the code. This is achieved by using docstrings and field descriptions to provide prompts and descriptions for your schema fields.
|
||||
|
||||
## Structured Extraction
|
||||
|
||||
You can directly use the class in your `openai` create calls by passing in the classes `openai_schema` and extract the class out with `from_completion`.
|
||||
|
||||
With this style of usage you get as close to the api call as possible giving you full control over configuration and prompting.
|
||||
You can directly use the `OpenAISchema` class in your `openai` API create calls by passing in the `openai_schema` class property and extracting the class out using the `from_response` method. This style of usage provides full control over configuration and prompting.
|
||||
|
||||
```python
|
||||
import openai
|
||||
from openai_function_call import OpenAISchema
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
class UserDetails(OpenAISchema):
|
||||
"""Details of a user"""
|
||||
name: str = Field(..., description="users's full name")
|
||||
name: str = Field(..., description="User's full name")
|
||||
age: int
|
||||
|
||||
completion = openai.ChatCompletion.create(
|
||||
@@ -33,25 +31,25 @@ completion = openai.ChatCompletion.create(
|
||||
)
|
||||
|
||||
user_details = UserDetails.from_response(completion)
|
||||
print(user_details) # name="John Doe", age=30
|
||||
print(user_details) # UserDetails(name='John Doe', age=30)
|
||||
```
|
||||
|
||||
!!! tip "Using the decorator"
|
||||
You can also use `@openai_schema` to decorate `BaseModels`, however, you'll lose some type hinting as a result.
|
||||
You can also use the `@openai_schema` decorator to decorate `BaseModels`, but you may lose some type hinting as a result.
|
||||
|
||||
```python
|
||||
import openai
|
||||
from openai_function_call import openai_schema
|
||||
|
||||
from pydantic import Field, BaseModel
|
||||
|
||||
@openai_schema
|
||||
class UserDetails(BaseModel):
|
||||
"""Details of a user"""
|
||||
name: str = Field(..., description="users's full name")
|
||||
name: str = Field(..., description="User's full name")
|
||||
age: int
|
||||
```
|
||||
|
||||
## Code Reference
|
||||
|
||||
::: openai_function_call.function_calls
|
||||
For more information about the code, including the complete API reference, please refer to the `openai_function_call` documentation.
|
||||
|
||||
::: openai_function_call.function_calls
|
||||
+28
-23
@@ -1,46 +1,36 @@
|
||||
# Using the ChatCompletion pipeline
|
||||
# Using the ChatCompletion Pipeline
|
||||
|
||||
The pipeline api is just syntactic sugar to help build prompts in a readable way that avoids having to remember best practices around wording and structure. Examples include adding tips, tagging data with xml, or even including the chain of thought prompt as an assistant message.
|
||||
The ChatCompletion pipeline API provides a convenient way to build prompts with clear instructions and structure. It helps avoid the need to remember best practices for wording and prompt construction. This documentation will demonstrate an example pipeline and guide you through the process of using it.
|
||||
|
||||
## Example Pipeline
|
||||
|
||||
Here we'll define a task to segment queries and add some more instructions via the prompt pipeline api.
|
||||
We will begin by defining a task to segment queries and add instructions using the prompt pipeline API.
|
||||
|
||||
### Designing the schema
|
||||
### Designing the Schema
|
||||
|
||||
First, let's design the schema for our task. In this example, we will have a `SearchQuery` schema with a single field called `query`. The `query` field will represent a detailed, comprehensive, and specific query to be used for semantic search.
|
||||
|
||||
```python
|
||||
from openai_function_call import OpenAISchema, dsl
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class SearchQuery(OpenAISchema):
|
||||
query: str = Field(
|
||||
...,
|
||||
description="Detailed, comprehensive, and specific query to be used for semantic search",
|
||||
)
|
||||
|
||||
|
||||
SearchResponse = dsl.MultiTask(
|
||||
subtask_class=SearchQuery,
|
||||
)
|
||||
```
|
||||
|
||||
!!! tip "MultiTask"
|
||||
To learn more about what multi task does, checkout the [MultiTask](multitask.md) documentation
|
||||
To learn more about the `MultiTask` functionality, you can refer to the [MultiTask](multitask.md) documentation.
|
||||
|
||||
### Building our Prompts
|
||||
|
||||
### Building our prompts
|
||||
|
||||
We dont deal with prompt templates and treat chat, message, output schema as first class citizens and then pipe them into a completion object.
|
||||
|
||||
!!! note "Whats that?"
|
||||
The pipe `|` is an overloaded operator that lets us cleanly compose our prompts.
|
||||
|
||||
`ChatCompletion` contains all the configuration for the model while we use `|` to build our prompt
|
||||
|
||||
We can then chain `|` together to add `Messages` or `OpenAISchema` and `ChatCompletion` will build out query for us while giving us a readable block to code to look ad
|
||||
|
||||
To see what 'message templates' are available check out our [docs](chat-completion.md)
|
||||
Next, let's build our prompts using the pipeline API. We will leverage the features provided by the `ChatCompletion` class and utilize the `|` operator to chain different components of our prompt together.
|
||||
|
||||
```python
|
||||
task = (
|
||||
@@ -62,15 +52,30 @@ task = (
|
||||
)
|
||||
| SearchResponse
|
||||
)
|
||||
```
|
||||
|
||||
The `ChatCompletion` class is responsible for model configuration, while the `|` operator allows us to construct the prompt in a readable manner. We can add `Messages` or `OpenAISchema` components to the prompt pipeline using `|`, and the `ChatCompletion` class will handle the prompt construction for us.
|
||||
|
||||
In the above example, we:
|
||||
|
||||
- Initialize a `ChatCompletion` object with the desired model and maximum token count.
|
||||
- Add a `SystemTask` component to segment search results.
|
||||
- Include a `TaggedMessage` component to provide a query with a specific tag.
|
||||
- Use a `TipsMessage` component to include some helpful tips related to the task.
|
||||
- Connect the `SearchResponse` schema to the pipeline.
|
||||
|
||||
Lastly, we create the `search_request` using `task.create()`. The `search_request` object will be of type `SearchResponse`, and we can print it as a JSON object.
|
||||
|
||||
!!! tip
|
||||
If you want to see the exact input sent to OpenAI, scroll to the bottom of the page.
|
||||
|
||||
```python
|
||||
search_request = task.create() # type: ignore
|
||||
assert isinstance(search_request, SearchResponse)
|
||||
print(search_request.json(indent=2))
|
||||
```
|
||||
|
||||
!!! tip
|
||||
If you want to see what its actually sent to OpenAI scroll to the bottom of the page!
|
||||
|
||||
Output
|
||||
The output will be a JSON object containing the segmented search queries.
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user