### Installing draive Gemini Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `gemini` integration for `draive` using pip. This allows users to access Google AI Studio services client, including Gemini models. ```Bash pip install 'draive[gemini]' ``` -------------------------------- ### Installing draive VLLM Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `vllm` integration for `draive` using pip. This allows users to utilize VLLM services through the OpenAI client. ```Bash pip install 'draive[vllm]' ``` -------------------------------- ### Installing draive Ollama Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `ollama` integration for `draive` using pip. This enables the use of Ollama services client. ```Bash pip install 'draive[ollama]' ``` -------------------------------- ### Installing draive Cohere Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `cohere` integration for `draive` using pip. This allows users to utilize Cohere services client. ```Bash pip install 'draive[cohere]' ``` -------------------------------- ### Installing draive Core Library with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the core `draive` library using pip, the Python package installer. It provides the fundamental functionalities for building LLM-based applications with draive. ```Bash pip install draive ``` -------------------------------- ### Configuring OpenAI LLM Provider and Model in Draive Context Source: https://github.com/miquido/draive/blob/main/guides/BasicUsage.md This example illustrates how to set up the OpenAI LLM provider and select a specific model (e.g., `gpt-4o-mini`) within a Draive context scope. It uses `ctx.scope` to define the current LLM and its configuration, then invokes the `text_completion` function within this context. ```python from draive import ctx from draive.openai import OpenAIChatConfig, OpenAI async with ctx.scope( # prepare new context "basics", OpenAI().lmm_invoking(), # set currently used LMM to OpenAI OpenAIChatConfig(model="gpt-4o-mini"), # select used model ): result: str = await text_completion( text="Roses are red...", ) print(result) ``` -------------------------------- ### Installing draive OpenAI Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `openai` integration for `draive` using pip. This allows users to utilize OpenAI services, including GPT, DALL-E, and embedding models, and also supports Azure services. ```Bash pip install 'draive[openai]' ``` -------------------------------- ### Integrating Draive Tools with OpenAI LLM for Text Generation in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This example shows how to integrate Draive tools with an LLM (OpenAI GPT-4o-mini) to extend its capabilities. The `generate_text` function automatically handles tool calls and incorporates their results into the LLM's response. It requires loading environment variables for the OpenAI API key and configuring the LLM within the Draive context. ```python from draive import generate_text, load_env from draive.openai import OpenAIChatConfig, OpenAI load_env() async with ctx.scope( "basics", # define used LMM to be OpenAI within the context OpenAI().lmm_invoking(), OpenAIChatConfig(model="gpt-4o-mini"), ): result: str = await generate_text( instruction="You are a helpful assistant", input="What is the time in New York?", tools=[current_time], # or `Toolbox(current_time)` ) print(result) ``` -------------------------------- ### Installing draive Mistral Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `mistral` integration for `draive` using pip. This enables the use of Mistral services client and also supports Azure services. ```Bash pip install 'draive[mistral]' ``` -------------------------------- ### Installing draive Anthropic Integration with pip Source: https://github.com/miquido/draive/blob/main/README.md This command installs the optional `anthropic` integration for `draive` using pip. This enables the use of Anthropic services client, including Claude models. ```Bash pip install 'draive[anthropic]' ``` -------------------------------- ### Instantiating and Updating Draive State (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This example illustrates how to create an instance of a `BasicState` and perform immutable updates using the `updated` method. Draive's `State` objects are immutable by default, preventing direct modification and ensuring data integrity. The `updated` method creates a new instance with specified changes, preserving the original state. ```python # create an instance of BasicState basic_state: BasicState = BasicState( identifier="basic", value=42, ) # BasicState( # identifier=0, # error! can't instantiate state with wrong data # value=42, # ) # prepare an update updated_state: BasicState = basic_state.updated( value=21 ) # value of `identifier` field won't change # basic_state.value = 0 # error! can't mutate the state ``` -------------------------------- ### Locally Updating Contextual State in Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This comprehensive example demonstrates how to locally update a contextual state within a Draive application. It shows entering an initial context, accessing the state, then using `ctx.updated` to create a nested scope with a modified state. Upon exiting the nested scope, the context reverts to the previous state, illustrating Draive's structured concurrency for state management. ```python async with ctx.scope("basics", basic_state): # here we have access to the state from the context print("Initial:") do_something_contextually() # then we can update it locally with ctx.updated(basic_state.updated(identifier="updated")): print("Updated:") # and access its updated version do_something_contextually() print("Final:") # when leaving the updated scope we go back to previously defined state do_something_contextually() # do_something_contextually() # calling it outside of any context scope will cause an error ``` -------------------------------- ### Inspecting and Combining Attribute Requirements - Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example illustrates how to inspect the components (lhs, operator, rhs) of an existing `AttributeRequirement`. It further demonstrates combining multiple requirements using the bitwise AND operator (`&`) to create a more complex validation rule, and then checks this combined requirement against a `PathModel` instance. ```Python print("lhs:", requirement.lhs) print("operator:", requirement.operator) print("rhs:", requirement.rhs) combined_requirement: AttributeRequirement[PathModel] = requirement & AttributeRequirement[ PathModel ].contained_in( [12, 21], path=PathModel._.value, ) combined_requirement.check(path_model_instance) ``` -------------------------------- ### Generating JSON Schema for DataModel in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example shows how to generate a JSON-schema compatible description for a `DataModel` class using the `json_schema()` static method. The schema is automatically derived from the class's type annotations. ```python class BasicModel(DataModel): field: str print(BasicModel.json_schema(indent=2)) ``` -------------------------------- ### Customizing DataModel Fields with Alias and Description in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example illustrates how to customize `DataModel` fields using `Field`. It shows how to define a description for a field and an alias, which is used in schema generation and allows instantiation with both regular and aliased names. ```python from draive import Field class CustomizedSchemaModel(DataModel): described: int = Field(description="Field description") aliased: str = Field(aliased="field_alias") print(f"JSON schema:\n{CustomizedSchemaModel.json_schema(indent=2)}") print(f"Simplified schema:\n{CustomizedSchemaModel.simplified_schema(indent=2)}") ``` -------------------------------- ### Customizing Schema Specification for DataModel Fields in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example shows how to provide a fully custom schema specification for a `DataModel` field using the `specification` argument in `Field`. This allows overriding the automatically generated schema for that specific field. ```python class CustomizedSpecificationModel(DataModel): value: int = Field(specification={"type": "integer", "description": "Fully custom"}) print(CustomizedSpecificationModel.json_schema(indent=2)) ``` -------------------------------- ### Using AttributePath to Access Nested DataModel Fields in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example demonstrates how to use `AttributePath` to create a pointer to a nested element within a `DataModel` instance. The path can then be used to retrieve the value of that specific field from any instance of the model. ```python from typing import cast from draive import AttributePath class NestedPathModel(DataModel): values: Sequence[int] class PathModel(DataModel): nested: NestedPathModel value: int # we can construct the path for any given field inside path: AttributePath[PathModel, Sequence[int]] = cast( AttributePath[PathModel, Sequence[int]], PathModel._.nested.values, ) path_model_instance: PathModel = PathModel( value=21, nested=NestedPathModel( values=[42, 21], ), ) # and use it to retrieve that field value from any instance print(path(path_model_instance)) ``` -------------------------------- ### Performing Immutable Mutations on DataModel in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example illustrates how to update `DataModel` instances, which are immutable by default. Mutations are performed by creating a new copy of the model using the `updated()` method, ensuring the original instance remains unchanged. ```python class Mutable(DataModel): identifier: str value: int # prepare an instance of state initial: Mutable = Mutable( identifier="pre", value=42, ) # update one of the fields by creating a copy updated: Mutable = initial.updated(identifier="post") # update initial state once more - this will be another copy final: Mutable = initial.updated(value=21) print("initial", initial) print("updated", updated) print("final", final) ``` -------------------------------- ### Adding Custom Verification to DataModel Fields in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This example shows how to add custom verification logic to a `DataModel` field using the `verifier` argument in `Field`. The `verifier` function receives the already type-validated value and can raise an `Exception` if the value does not meet additional criteria. ```python # verifier gets pre-validated value, it already have required type def verifier(value: int) -> None: if value < 0: # raise an Exception if something is wrong with the value raise ValueError("Value can't be less than zero!") class VerifiedModel(DataModel): value: int = Field(verifier=verifier) ``` -------------------------------- ### Initializing Python Logging with Draive Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet demonstrates how to initialize the Python logging system using the `setup_logging` function from the `draive` framework. It sets up a logger with the specified name, enabling proper log management for the application. ```python setup_logging("logging") ``` -------------------------------- ### Setting Up Draive Logging (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet shows the import statement for `setup_logging` from the `draive` module. This function is used to configure the logging system within a Draive application, allowing for control over log output and verbosity, which is crucial for debugging and monitoring. ```python from draive import setup_logging ``` -------------------------------- ### Loading Environment Variables with Draive Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet shows how to load environment variables from `.env` files using the `load_env` function provided by the `draive` framework. This ensures that application configurations are correctly loaded from the environment. ```python from draive import load_env load_env() ``` -------------------------------- ### Logging LLM Execution Metrics in Draive Source: https://github.com/miquido/draive/blob/main/guides/BasicUsage.md This snippet demonstrates how to set up logging and capture detailed execution metrics for LLM interactions within Draive. By using `setup_logging` and `MetricsLogger.handler()`, users can gain insights into arguments, configurations, token usage, and results of LLM invocations. ```python from draive import MetricsLogger, setup_logging setup_logging("basics") # setup logger async with ctx.scope( # prepare the context and see the execution metrics report "basics", OpenAI().lmm_invoking(), OpenAIChatConfig( # define GPT model configuration model="gpt-3.5-turbo", temperature=0.4, ), metrics=MetricsLogger.handler() ): await text_completion( text="Roses are red...", ) with ctx.updated( ctx.state(OpenAIChatConfig).updated( model="gpt-4o", ), ): await text_completion( text="Roses are red...", ) ``` -------------------------------- ### Initializing Draive MCP Client with OpenAI and Filesystem Server (Python) Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicMCP.md This snippet demonstrates how to initialize a Draive application to use ModelContextProtocol (MCP) with an OpenAI Large Language Model (LLM) and an external filesystem server. It sets up logging, loads environment variables, configures OpenAI's gpt-4o-mini model, and establishes an MCPClient.stdio connection to a server-filesystem instance, allowing the LLM to access files in a specified directory. Finally, it uses conversation_completion to query the LLM about the files in the directory, leveraging the external tools provided by MCP. ```python from draive import ( ConversationMessage, Toolbox, conversation_completion, ctx, load_env, setup_logging, ) from draive.mcp import MCPClient from draive.openai import OpenAIChatConfig, OpenAI load_env() # load .env variables setup_logging("mcp") # initialize dependencies and configuration async with ctx.scope( "mcp", OpenAI().lmm_invoking(), # define used LMM to use OpenAI OpenAIChatConfig(model="gpt-4o-mini"), # configure OpenAI model # prepare MCPClient, it will handle connection lifetime through context # and provide associated state with MCP functionalities disposables=[ # we are going to use stdio connection with one of the example servers MCPClient.stdio( command="npx", args=[ "-y", "@modelcontextprotocol/server-filesystem", "/Users/myname/checkmeout", ], ), ] ): # request model using any appropriate method, i.e. conversation for chat response: ConversationMessage = await conversation_completion( # provide a prompt instruction instruction="You can access files on behalf of the user on their machine using available tools." " Desktop directory path is `/Users/myname/checkmeout`", # add user input input="What files are in checkmeout directory?", # define tools available to the model from MCP extensions tools=await Toolbox.external(), ) print(response.content) ``` -------------------------------- ### Customizing LLM Configuration and Context Updates Source: https://github.com/miquido/draive/blob/main/guides/BasicUsage.md This snippet demonstrates advanced LLM configuration, showing how to set model and temperature parameters using `OpenAIChatConfig` within `ctx.scope`. It also illustrates how to update configuration for nested contexts using `ctx.updated` and how to override parameters for a single `generate_text` call. ```python from draive.openai import OpenAIChatConfig async with ctx.scope( # prepare the new context "basics", OpenAI().lmm_invoking(), # define GPT model configuration as a context scope state OpenAIChatConfig( model="gpt-3.5-turbo", temperature=0.4, ), ): # now we are using gpt-3.5-turbo with temperature of 0.4 result: str = await text_completion( text="Roses are red...", ) print("RESULT GPT 3.5 | temperature 0.4:", result) # we can update the configuration to change any parameter for nested context with ctx.updated( # we are updating the current context value instead of making a new one # this allows to preserve other elements of the configuration ctx.state(OpenAIChatConfig).updated( model="gpt-4o", ), ): # now we are using gpt-4o with temperature of 0.4 result = await text_completion( text="Roses are red...", ) print("RESULT GPT 4o | temperature 0.4:", result) # we can also update the configuration for a single call # when using generate_text function directly # here we are using gpt-3.5-turbo with temperature of 0.7 result = await generate_text( instruction="Prepare simplest completion of given text", input="Roses are red...", temperature=0.7, ) print("RESULT GPT 3.5 | temperature 0.7:", result) ``` -------------------------------- ### Handling Metrics with Draive's MetricsLogger Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet demonstrates how to use `MetricsLogger` within a `draive` context scope to capture and log application metrics. It shows how to define a metrics handler, record custom metrics (`BasicState`), and create nested scopes for hierarchical metric tracking, with a summary provided upon scope exit. ```python from draive import MetricsLogger async with ctx.scope( # we can explicitly pass the logger as an argument # or use the assigned label as the default logger name "logging", # define the scope completion method to log the scope details metrics=MetricsLogger.handler(), ): ctx.log_info("Now we can see the logs!") # we can see recorded custom metrics for the context scope as well ctx.record(BasicState(identifier="recorded", value=42)) # or we can create nested context scope which creates # a separate subtree for metrics with ctx.scope("nested"): # now we can record the same thing again # but this time it will be associated with the nested context scope ctx.record(BasicState(identifier="recorded-nested", value=11)) # additionally when we exit the context scope we get the execution summary # including all recorded metrics ``` -------------------------------- ### Loading Environment Variables with Draive Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicDataExtraction.md This snippet initializes the environment by loading variables from a `.env` file. It is a prerequisite for authenticating with services like OpenAI, which requires the `OPENAI_API_KEY` to be set. This ensures that sensitive API keys are not hardcoded directly into the application. ```Python from draive import load_env load_env() # load .env variables ``` -------------------------------- ### Tracing LMM and Tool Usage with Draive Metrics in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This snippet demonstrates how to set up logging and trace the execution of a Large Language Model (LLM) invocation within a Draive context. It uses `MetricsLogger` to capture details about LMM calls and tool usage, including `current_time` and `customized` tools, providing insights into the interaction and token consumption. ```python from draive import MetricsLogger, setup_logging setup_logging("basics") async with ctx.scope( "basics", # define used LMM to be OpenAI within the context OpenAI().lmm_invoking(), OpenAIChatConfig(model="gpt-4o-mini"), metrics=MetricsLogger.handler(), ): result: str = await generate_text( instruction="You are a funny assistant", input="What is the funny thing about LLMs?", # we will now be able to see what tools were used # and check the details about its execution tools=Toolbox.of( current_time, customized, suggest=customized, ), ) print(f"\nResult:\n{result}\n") ``` -------------------------------- ### Managing Draive Tools with Toolbox for LLM Interaction in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This snippet demonstrates the use of `Toolbox` to manage a collection of tools for LLM interaction. It allows defining multiple tools, suggesting a specific tool for the initial LLM call (`suggest`), and setting a limit on the number of repeated tool calls (`repeated_calls_limit`) before the final result is returned, providing fine-grained control over tool execution. ```python from draive import Toolbox async with ctx.scope( "basics", # define used LMM to be OpenAI within the context OpenAI().lmm_invoking(), OpenAIChatConfig(model="gpt-4o-mini"), ): result: str = await generate_text( instruction="You are a funny assistant", input="What is the funny thing about LLMs?", tools=Toolbox.of( # we can define any number of tools within a toolbox current_time, customized, # we can also force any given tool use within the first LLM call suggest=customized, # we can limit how many tool calls are allowed # before the final result is returned repeated_calls_limit=2, ), ) print(result) ``` -------------------------------- ### Loading Environment Variables with Draive Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicRAG.md This snippet demonstrates how to load environment variables using `draive.load_env()`. This is a prerequisite for accessing API keys and other configurations, such as `OPENAI_API_KEY`, required by the application. ```python from draive import load_env load_env() # load .env variables ``` -------------------------------- ### Loading Environment Variables for API Keys Source: https://github.com/miquido/draive/blob/main/guides/BasicUsage.md Before interacting with external LLM services like OpenAI, it's crucial to load necessary API keys. This snippet shows how to use `draive.load_env()` to load variables from a `.env` file, specifically mentioning `OPENAI_API_KEY` as a prerequisite. ```python from draive import load_env load_env() # load .env variables ``` -------------------------------- ### Logging and Recording Metrics in Draive Context (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet demonstrates how to leverage Draive's context scopes for logging and recording custom metrics. By assigning a label to the context, diagnostic information can be easily identified. `ctx.log_info` allows logging with associated metadata, and `ctx.record` enables recording custom metrics based on `State` subclasses, providing valuable insights into program execution. ```python # we can assign label to the context to better identify it async with ctx.scope("logging"): ctx.log_info("We can use associated logger with additional metadata") # finally we can record custom metrics based on the state we already know # by using a subclass of `State` ctx.record(BasicState(identifier="recorded", value=42)) ``` -------------------------------- ### Loading Environment Variables with draive in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicConversation.md This snippet demonstrates how to load environment variables, specifically the OPENAI_API_KEY, using the `draive.load_env()` function. This is a crucial first step to ensure the application can authenticate and access OpenAI services. ```python from draive import load_env load_env() # loads OPENAI_API_KEY from .env file ``` -------------------------------- ### Initializing Draive Context with Application State (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet demonstrates how to initialize a Draive context scope with an instance of an application state. By passing `basic_state` to `ctx.scope`, this state becomes available within the context, allowing functions executed inside to access it without explicit argument passing. Only one instance per state type can be provided within a given context. ```python # when defining context scope we can provide any number of state objects, # there can be only a single instance for any given type though async with ctx.scope("basics", basic_state): pass # now we are using the defined state in this scope # out of the scope, state is not defined here ``` -------------------------------- ### Generating Structured Data Model with OpenAI and Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/BasicModelGeneration.md This snippet illustrates the core process of generating a structured `InterestingPlace` model using `draive` and OpenAI. It initializes the `draive` context with `OpenAI` as the LMM and configures `gpt-4o-mini`, then uses `generate_model` with a specific instruction and user input to produce the structured data. ```python from draive import ctx, generate_model from draive.openai import OpenAIChatConfig, OpenAI # initialize dependencies and configuration async with ctx.scope( "basics", OpenAI().lmm_invoking(), # define used LMM use OpenAI OpenAIChatConfig(model="gpt-4o-mini"), # configure OpenAI model ): # request model generation generated: InterestingPlace = await generate_model( # define model to generate InterestingPlace, # provide a prompt instruction instruction="You are a helpful assistant.", # add user input input="What is the most interesting place to visit in London?", ) print(generated) ``` -------------------------------- ### Defining a Basic Text Completion Function with Draive Source: https://github.com/miquido/draive/blob/main/guides/BasicUsage.md This snippet demonstrates the simplest way to generate text using Draive's `generate_text` function. It defines an asynchronous Python function that takes an input text and returns its completion, specifying an instruction for the LLM. ```python from draive import generate_text async def text_completion(text: str) -> str: # generate_text is a simple interface for generating text return await generate_text( # We have to provide instructions / system prompt to instruct the model instruction="Prepare the simplest completion of a given text", # input is provided separately input=text, ) ``` -------------------------------- ### Customizing Data Extraction Prompt and Schema Injection Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicDataExtraction.md This snippet shows how to customize the data extraction process by taking more control over the prompt and schema injection. It uses a custom instruction string with a `{schema}` placeholder to explicitly include the data model's schema. By setting `schema_injection='simplified'`, it instructs Draive to use a simplified schema description, which can be beneficial for smaller LLMs. It also prints both the full JSON schema and the simplified schema for comparison. ```Python from draive import ctx, generate_model async with ctx.scope( "customized_extraction", # define used LMM to be OpenAI within the context OpenAI().lmm_invoking(), OpenAIChatConfig(model="gpt-4o-mini") ): result: PersonalData = await generate_model( PersonalData, instruction=( # provide extended instructions and take full control over the prompt "Please extract information from the given input." " Put it into the JSON according to the following description:\n" "{schema}" # 'schema' is the name of the format argument used to fill in the schema ), input=document, # we will use the simplified schema description # you can also skip adding schema at all schema_injection="simplified", ) print(f"JSON schema:\n{PersonalData.json_schema(indent=2)}") print(f"Simplified schema:\n{PersonalData.simplified_schema(indent=2)}") print(f"Result:\n{result}") ``` -------------------------------- ### Performing Basic Data Extraction with Draive and OpenAI Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicDataExtraction.md This snippet demonstrates how to perform basic structured data extraction using `draive.generate_model`. It sets up an execution context with `ctx.scope`, configuring OpenAI as the LMM with `gpt-4o-mini`. The `generate_model` function is then called with the `PersonalData` model, an instruction, and the `document` as input, automatically decoding the LLM's response into a `PersonalData` object. ```Python from draive import ctx, generate_model from draive.openai import OpenAIChatConfig, OpenAI async with ctx.scope( "data_extraction", # define used LMM to be OpenAI within the context OpenAI().lmm_invoking(), OpenAIChatConfig(model="gpt-4o-mini") ): result: PersonalData = await generate_model( # define model to generate PersonalData, # provide additional instructions # note that the data structure will be automatically explained to LLM instruction="Please extract information from the given input", # we will provide the document as an input input=document, ) print(result) ``` -------------------------------- ### Advanced Draive Tool Customization with Direct Result and Formatting in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This code illustrates further customization options for Draive tools. It shows how to use `direct_result=True` to return the tool's output directly without an additional LLM call, `format_result` to modify how LLMs perceive the tool's output, and `availability_check` to contextually control the tool's presence in the available tools list at runtime. ```python @tool( # this time we will use different arguments within tool annotation # direct result allows returning the result without additional LLM call direct_result=True, # format_result allows altering the way LLMs will see tool results # we can also use format_failure to format tool issues format_result=lambda result: f"Formatted: {result}", # we can also contextually limit tool availability in runtime # by removing it from available tools list on given condition availability_check=lambda: True ) async def customized_more() -> str: return "to be changed" ``` -------------------------------- ### Loading Environment Variables with Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/BasicModelGeneration.md This snippet demonstrates how to load environment variables, specifically `OPENAI_API_KEY`, using the `draive.load_env()` function. This is a crucial prerequisite for allowing the application to access OpenAI services by reading credentials from a `.env` file. ```python from draive import load_env load_env() # loads OPENAI_API_KEY from .env file ``` -------------------------------- ### Customizing Draive Tool Arguments with Aliases and Descriptions in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This snippet demonstrates advanced tool customization using the `@tool` decorator with additional arguments. It shows how to define an alias for the tool name (`name`), provide a detailed description for the tool's purpose, and annotate individual arguments using `Argument` to specify aliases, descriptions, and default values, enhancing LLM understanding. ```python from draive import Argument @tool( # this time we will use additional arguments within tool annotation # we can define an alias used as the tool name when explaining it to LLM, # default name is the name of python function name="fun_fact", # additionally we can explain the tool purpose by using description description="Find a fun fact in a given topic", ) async def customized( # we can also annotate arguments to provide even more details # and specify argument handling logic arg: str = Argument( # we can alias each argument name aliased="topic", # further describe its use description="Topic of a fact to find", # provide default value or default value factory default="random", # end more, including custom validators ), ) -> str: return f"{arg} is very funny on its own!" # we can examine tool specification which is similar to # how `State` and `DataModel` specification/schema is built print(customized.specification) ``` -------------------------------- ### Searching Vector Index via LLM Tool in Draive Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicRAG.md This code defines an asynchronous `search` tool that queries the `VectorIndex` for relevant document chunks based on a given query. It then configures a Draive context with OpenAI's LMM invoking and embedding services, and the previously created `vector_index`. Finally, it uses `generate_text` with an instruction and input, suggesting the `index_search_tool` to allow the LLM to retrieve information and answer the question. ```python from draive import Toolbox, generate_text, tool from draive.openai import OpenAIChatConfig, OpenAI @tool(name="search") # prepare a simple tool for searching the index async def index_search_tool(query: str) -> str: results: Sequence[DocumentChunk] = await ctx.state(VectorIndex).search( DocumentChunk, query=query, limit=3, ) return "\n---\n".join(result.content for result in results) async with ctx.scope( "searching", # define used dependencies and services OpenAI().lmm_invoking(), OpenAIChatConfig(model="gpt-4o-mini"), OpenAI().lmm_invoking(), OpenAIEmbeddingConfig(model="text-embedding-3-small"), # use our vector index vector_index, ): # use the tool to augment LLM generation by suitable document parts result: str = await generate_text( instruction="Answer the questions based on provided data", input="Where is John Doe living?", # suggest the tool to ensure its usage tools=Toolbox.of(index_search_tool, suggest=index_search_tool), ) ``` -------------------------------- ### Defining and Using DataModel for JSON Serialization in Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet demonstrates defining a `DataModel` in Draive, which is designed for serializable data with associated schema descriptions. It shows how to define fields, including optional ones, and how to deserialize a JSON string into a `DataModel` instance using `from_json`. It also illustrates accessing the generated JSON schema using `json_schema` for validation and documentation purposes. ```python from collections.abc import Sequence from draive import DataModel # prepare a class, inherit from DataModel this time class BasicModel(DataModel): username: str tags: Sequence[str] | None = None json: str = """\ { "username": "John Doe", "tags": ["example", "json"] }\ """ # note that the model will be fully validated during decoding decoded_model: BasicModel = BasicModel.from_json(json) print(f"Decoded model:\n{decoded_model}") # we can also get the json schema of the model print(f"JSON Schema:\n{BasicModel.json_schema(indent=2)}") ``` -------------------------------- ### Performing Conversation Completion with draive and OpenAI in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicConversation.md This snippet illustrates how to perform a conversation completion using `draive` with OpenAI. It initializes the `ctx.scope` to define OpenAI as the LMM and configures the `gpt-3.5-turbo-0125` model. It then sends an instruction and user input, providing the previously defined `utc_datetime` tool, and prints the model's response. ```python from draive import ConversationMessage, conversation_completion, ctx from draive.openai import OpenAIChatConfig, OpenAI # initialize dependencies and configuration async with ctx.scope( "basics", OpenAI().lmm_invoking(), # define used LMM to use OpenAI OpenAIChatConfig(model="gpt-3.5-turbo-0125"), # configure OpenAI model ): # request conversation completion response: ConversationMessage = await conversation_completion( # provide a prompt instruction instruction="You are a helpful assistant.", # add user input input="Hi! What is the time now?", # define tools available to the model tools=[utc_datetime], ) print(response) ``` -------------------------------- ### Creating an Asynchronous Context Scope in Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet shows how to create a new asynchronous context scope using `ctx.scope` in Draive. Context scopes are essential for managing contextual state and dependencies. By using an `async with` statement, operations executed within this block will operate under the defined scope, ensuring proper state propagation. ```python from draive import ctx # ctx.scope creates a new instance of the context scope # we can enter it by using async context manager: async with ctx.scope("basics"): pass # now everything executed inside will use that scope ``` -------------------------------- ### Indexing Document Chunks into a Volatile Vector Index with OpenAI Embeddings Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicRAG.md This snippet demonstrates how to index the prepared document chunks into an in-memory, volatile vector index. It configures the context with an OpenAI text embedding provider using `text-embedding-3-small` model. The `vector_index.index` method is then called to embed and store the `content` of each `DocumentChunk` for efficient retrieval. ```python from collections.abc import Sequence from draive import VectorIndex from draive.openai import OpenAIEmbeddingConfig, OpenAI # prepare vector index vector_index: VectorIndex = VectorIndex.volatile() async with ctx.scope( "indexing", # define embedding provider for this context OpenAI().text_embedding(), OpenAIEmbeddingConfig(model="text-embedding-3-small"), # use vector index vector_index, ): # add document chunks to the index await vector_index.index( DocumentChunk, values=document_chunks, # define what value will be embedded for each chunk indexed_value=DocumentChunk._.content, ) ``` -------------------------------- ### Preparing Document Chunks for Embedding in Python Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicRAG.md This code prepares a document for embedding by splitting it into smaller, manageable chunks. It defines a `DocumentChunk` data model to store the full document and individual chunk content. The `split_text` function is used with specified separators, part size, and overlap to create chunks, which are then tokenized using an OpenAI `gpt-3.5-turbo` tokenizer within a Draive context. ```python from draive import DataModel, count_text_tokens, ctx, split_text from draive.openai import OpenAI # document is a short text about John Doe document: str = """ ... """ # define chunk data structure class DocumentChunk(DataModel): full_document: str content: str # prepare data chunks document_chunks: list[DocumentChunk] async with ctx.scope( "basic_rag", # define tokenizer for this context await OpenAI().tokenizer("gpt-3.5-turbo"), ): document_chunks = [ DocumentChunk( full_document=document, content=chunk, ) # split document text into smaller parts for chunk in split_text( text=document, separators=("\n\n", " "), part_size=64, part_overlap_size=16, count_size=count_text_tokens, ) ] ``` -------------------------------- ### Generating Text with Tools using draive and OpenAI in Python Source: https://github.com/miquido/draive/blob/main/README.md This snippet demonstrates how to use draive to generate text with an LLM (OpenAI's gpt-4o-mini) and integrate custom tools. It defines a `current_time` tool, sets up an execution context with OpenAI configuration, and then uses `TextGeneration.generate` to invoke the LLM with an instruction, input, and the defined tool. The expected output is the time in Kraków, leveraging the `current_time` tool. ```Python from draive import ctx, TextGeneration, tool from draive.openai import OpenAI, OpenAIChatConfig @tool # simply annotate a function as a tool async def current_time(location: str) -> str: return f"Time in {location} is 9:53:22" async with ctx.scope( # create execution context "example", # give it a name OpenAIChatConfig(model="gpt-4o-mini"), # prepare configuration disposables=[OpenAI()], # define resources and service clients available ): result: str = await TextGeneration.generate( # choose a right generation abstraction instruction="You are a helpful assistant", # provide clear instructions input="What is the time in Kraków?", # give it some input (including multimodal) tools=[current_time], # and select any tools you like ) print(result) ``` -------------------------------- ### Defining a BasicState Class in Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This snippet demonstrates how to define a basic application state using Draive's `State` class. By inheriting from `State`, class fields like `identifier` and `value` are automatically converted into instance properties with built-in validation and immutability. This allows for structured, type-safe state management within the application. ```python from draive import State # inherit from the base class class BasicState(State): # fields are automatically converted to instance properties identifier: str value: int ``` -------------------------------- ### Executing a Draive Tool as a Regular Function in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This code illustrates how to call a defined Draive tool (`current_time`) as a regular asynchronous function. It emphasizes that tool execution must occur within a `draive.ctx.scope` to ensure proper context management, and arguments are automatically validated. ```python from draive import ctx async with ctx.scope("basics"): # we can still use it as a regular function # but it has to be executed within context scope print(await current_time(location="London")) # await current_time(location="London") # error! out of context ``` -------------------------------- ### Accessing Contextual State in Draive Functions (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This function illustrates how to retrieve a contextual state object within a Draive function using `ctx.state()`. By specifying the state's type, the function can access the currently active instance of `BasicState` propagated through the context scope, simplifying state management and reducing the need for explicit argument passing. ```python def do_something_contextually() -> None: # access contextual state through the ctx state: BasicState = ctx.state(BasicState) print(state) # then you can use it in the scope of the function ``` -------------------------------- ### Defining a Structured Data Model with Draive (Python) Source: https://github.com/miquido/draive/blob/main/guides/BasicModelGeneration.md This code defines a structured data model named `InterestingPlace` by inheriting from `draive.DataModel`. It specifies `name` as a required string and `description` as an optional string, outlining the exact schema for the structured data that will be generated by the language model. ```python from draive import DataModel # define a Model class to describe the data class InterestingPlace(DataModel): name: str description: str | None = None ``` -------------------------------- ### Defining a Basic Draive Tool in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicToolsUse.md This snippet demonstrates how to define a simple asynchronous function as a tool in Draive using the `@tool` decorator. Tools can accept arguments with basic types and return values, extending LLM capabilities by allowing the model to request and execute them. ```python from draive import tool @tool # simply annotate function as a tool, tools can have arguments using basic types async def current_time(location: str) -> str: # return result of tool execution, we are using fake time here return f"Time in {location} is 9:53:22" ``` -------------------------------- ### Defining a draive Tool for Current UTC Datetime in Python Source: https://github.com/miquido/draive/blob/main/guides/BasicConversation.md This code defines a simple asynchronous tool named `utc_datetime` using the `@tool` decorator from `draive`. This tool, described as 'UTC time and date now', returns the current UTC date and time as a formatted string, making it available for language models to invoke. ```python from datetime import UTC, datetime from draive import tool # prepare a basic tool for getting current date and time @tool(description="UTC time and date now") async def utc_datetime() -> str: return datetime.now(UTC).strftime("%A %d %B, %Y, %H:%M:%S") ``` -------------------------------- ### Converting DataModel to/from Dictionary in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This snippet demonstrates how to convert a `DataModel` instance to and from a dictionary using `as_dict()` and `from_dict()` methods. This allows for easy serialization and deserialization of `DataModel` objects into basic Python types. ```python from draive import BasicValue, DataModel class DictConverted(DataModel): name: str value: int # all of this applies to the `DataModel` as well dict_converted: DictConverted = DictConverted(name="converted", value=42) dict_converted_as_dict: dict[str, BasicValue] = dict_converted.as_dict() dict_converted_from_dict: DictConverted = DictConverted.from_dict(dict_converted_as_dict) print(dict_converted_from_dict) ``` -------------------------------- ### Accessing State via Function Arguments (Python) Source: https://github.com/miquido/draive/blob/main/guides/Basics.md This simple function definition illustrates the traditional method of accessing state by passing it directly as a function argument. While effective for isolated operations, this approach can become cumbersome when state needs to be propagated through many layers of function calls, leading to redundant argument passing. ```python def do_something(state: BasicState) -> None: pass # use the state here ``` -------------------------------- ### Defining Data Structure with Draive DataModel Source: https://github.com/miquido/draive/blob/main/cookbooks/BasicDataExtraction.md This snippet defines a Python class `PersonalData` that inherits from `draive.DataModel`. This class specifies the desired structure for the extracted information, including `first_name`, `last_name`, `age`, and `country`. Using `DataModel` allows Draive to automatically explain the required output format to the LLM and decode the LLM's response into a Python object, ensuring type safety and structured output. ```Python from draive import DataModel class PersonalData(DataModel): first_name: str last_name: str age: int | None = None country: str | None = None ``` -------------------------------- ### Converting DataModel to/from JSON in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This snippet demonstrates how to serialize a `DataModel` instance to a JSON string using `as_json()` and deserialize it back from a JSON string using `from_json()`. This leverages the intermediate dictionary conversion for JSON serialization. ```python from draive import DataModel class JSONConverted(DataModel): name: str value: int json_converted: JSONConverted = JSONConverted(name="converted", value=42) json_converted_as_json: str = json_converted.as_json() json_converted_from_json: JSONConverted = JSONConverted.from_json(json_converted_as_json) print(json_converted_from_json) ``` -------------------------------- ### Generating Simplified Schema for DataModel in Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This snippet demonstrates generating a simplified schema description for a `DataModel` using `simplified_schema()`. This compact representation can be particularly useful for scenarios like requesting structured data from Large Language Models (LLMs). ```python print(BasicModel.simplified_schema(indent=2)) ``` -------------------------------- ### Defining and Checking an Attribute Requirement - Python Source: https://github.com/miquido/draive/blob/main/guides/AdvancedState.md This snippet demonstrates how to define an `AttributeRequirement` that checks if a specific nested value in a `PathModel` instance is equal to 42. It then shows how to execute this requirement against an instance using the `check` method, returning a boolean result. ```Python requirement: AttributeRequirement[PathModel] = AttributeRequirement[PathModel].equal( 42, # here we require value to be equal to 42 path=PathModel._.nested.values[0], # under this specific path ) # requirement can be executed to check value on any instance requirement.check(path_model_instance) ```