diff --git a/docs/examples/search.md b/docs/examples/search.md new file mode 100644 index 0000000..5391d81 --- /dev/null +++ b/docs/examples/search.md @@ -0,0 +1,114 @@ +# 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. + +## 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 + +```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}`" + ) +``` + +!!! 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. + + ```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 + +```python +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. + +!!! 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. + +## Putting it all together + +Without using the lets define a function with some type hints + +```python +def segment(data: str) -> MultiSearch: + completion = openai.ChatCompletion.create( + model="gpt-3.5-turbo-0613", + temperature=0.1, + functions=[MultiSearch.openai_schema], + function_call={"name": MultiSearch.openai_schema["name"]}, + messages=[ + { + "role": "user", + "content": f"Consider the data below: '\n{data}' and segment it into multiple search queries", + }, + ], + 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. + +## Evaluating an example + +```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]) +``` + +By using async we can execute the queries efficiently with fairly modular and simple code. + +```bash +Searching for `Video` with query `investment case study` using `SearchType.VIDEO` +Searching for `Documents` with query `GPDR policy` using `SearchType.EMAIL` +``` \ No newline at end of file diff --git a/docs/openai_schema.md b/docs/openai_schema.md index 21f190e..bbc7fc8 100644 --- a/docs/openai_schema.md +++ b/docs/openai_schema.md @@ -5,9 +5,8 @@ It has a method to help you produce the schema and parse the result of function This library is moreso a list of examples and a helper class so I'll keep the example as just structured extraction. -## Where does the prompts go? - -Instead of defining your prompts in the messages the prompts you would usually use are now defined as part of the dostring of your class and the field descriptions. This is nice since it allows you to colocate the schema with the class you use to represent the structure. +!!! note "Where does the prompt go?" + Instead of defining your prompts in the messages the prompts you would usually use are now defined as part of the dostring of your class and the field descriptions. This is nice since it allows you to colocate the schema with the class you use to represent the structure. ## Structured Extraction @@ -36,9 +35,8 @@ user_details = UserDetails.from_response(completion) print(user_details) # name="John Doe", age=30 ``` -## Using the decorator - -You can also use a decorator but i recommend the class since you get nice autocompletes with VSCode +!!! tip "Using the decorator" + You can also use `@openai_schema` to decorate `BaseModels`, however, you'll lose some type hinting as a result. ```python import openai diff --git a/mkdocs.yml b/mkdocs.yml index 563e68e..7101ca3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,6 +29,7 @@ markdown_extensions: - pymdownx.superfences - attr_list - md_in_html + - admonition nav: - Home: 'index.md' - API Reference: @@ -37,4 +38,4 @@ nav: - "Example: Pipeline API": "pipeline-example.md" - "Docs": "chat-completion.md" - Examples: - - 'Missing': 'help.md' \ No newline at end of file + - 'Segmented Search': 'examples/search.md' \ No newline at end of file