Integre fácilmente los modelos de idiomas grandes en su código Python. Simplemente use los decoradores @prompt y @chatprompt para crear funciones que devuelvan la salida estructurada del LLM. Mezcle las consultas y las llamadas de funciones con código Python regular para crear una lógica compleja.
FunctionCall y ParallelFunctionCall .async def al definir una función magénica.pip install magentico usando UV
uv add magentic Configure su tecla API OpenAI configurando la variable de entorno OPENAI_API_KEY . Para configurar un proveedor de LLM diferente, consulte Configuración para más.
El decorador @prompt le permite definir una plantilla para un modelo de modelo de lenguaje grande (LLM) como función de Python. Cuando se llama a esta función, los argumentos se insertan en la plantilla, entonces este aviso se envía a un LLM que genera la salida de la función.
from magentic import prompt
@ prompt ( 'Add more "dude"ness to: {phrase}' )
def dudeify ( phrase : str ) -> str : ... # No function body as this is never executed
dudeify ( "Hello, how are you?" )
# "Hey, dude! What's up? How's it going, my man?" El decorador @prompt respetará la anotación de tipo de retorno de la función decorada. Este puede ser cualquier tipo compatible con Pydantic, incluido un modelo pydantic .
from magentic import prompt
from pydantic import BaseModel
class Superhero ( BaseModel ):
name : str
age : int
power : str
enemies : list [ str ]
@ prompt ( "Create a Superhero named {name}." )
def create_superhero ( name : str ) -> Superhero : ...
create_superhero ( "Garden Man" )
# Superhero(name='Garden Man', age=30, power='Control over plants', enemies=['Pollution Man', 'Concrete Woman'])Ver salidas estructuradas para más.
El decorador @chatprompt funciona como @prompt pero le permite pasar los mensajes de chat como plantilla en lugar de un solo mensaje de texto. Esto se puede utilizar para proporcionar un mensaje del sistema o para solicitar pocas disparos cuando proporcione respuestas de ejemplo para guiar la salida del modelo. Los campos de formato denotados por aparatos {example} se llenarán en todos los mensajes (excepto FunctionResultMessage ).
from magentic import chatprompt , AssistantMessage , SystemMessage , UserMessage
from pydantic import BaseModel
class Quote ( BaseModel ):
quote : str
character : str
@ chatprompt (
SystemMessage ( "You are a movie buff." ),
UserMessage ( "What is your favorite quote from Harry Potter?" ),
AssistantMessage (
Quote (
quote = "It does not do to dwell on dreams and forget to live." ,
character = "Albus Dumbledore" ,
)
),
UserMessage ( "What is your favorite quote from {movie}?" ),
)
def get_movie_quote ( movie : str ) -> Quote : ...
get_movie_quote ( "Iron Man" )
# Quote(quote='I am Iron Man.', character='Tony Stark')Vea la solicitud de chat para más.
Un LLM también puede decidir llamar a las funciones. En este caso, la función @prompt -Corated devuelve un objeto FunctionCall que se puede llamar a ejecutar la función utilizando los argumentos proporcionados por el LLM.
from typing import Literal
from magentic import prompt , FunctionCall
def search_twitter ( query : str , category : Literal [ "latest" , "people" ]) -> str :
"""Searches Twitter for a query."""
print ( f"Searching Twitter for { query !r } in category { category !r } " )
return "<twitter results>"
def search_youtube ( query : str , channel : str = "all" ) -> str :
"""Searches YouTube for a query."""
print ( f"Searching YouTube for { query !r } in channel { channel !r } " )
return "<youtube results>"
@ prompt (
"Use the appropriate search function to answer: {question}" ,
functions = [ search_twitter , search_youtube ],
)
def perform_search ( question : str ) -> FunctionCall [ str ]: ...
output = perform_search ( "What is the latest news on LLMs?" )
print ( output )
# > FunctionCall(<function search_twitter at 0x10c367d00>, 'LLMs', 'latest')
output ()
# > Searching Twitter for 'Large Language Models news' in category 'latest'
# '<twitter results>'Ver función pidiendo más.
A veces, el LLM requiere hacer una o más llamadas de funciones para generar una respuesta final. El decorador @prompt_chain resolverá los objetos FunctionCall automáticamente y volverá a pasar la salida al LLM para continuar hasta que se alcance la respuesta final.
En el siguiente ejemplo, cuando describe_weather se llama LLM primero llama a la función get_current_weather , luego usa el resultado de esto para formular su respuesta final que se devuelve.
from magentic import prompt_chain
def get_current_weather ( location , unit = "fahrenheit" ):
"""Get the current weather in a given location"""
# Pretend to query an API
return {
"location" : location ,
"temperature" : "72" ,
"unit" : unit ,
"forecast" : [ "sunny" , "windy" ],
}
@ prompt_chain (
"What's the weather like in {city}?" ,
functions = [ get_current_weather ],
)
def describe_weather ( city : str ) -> str : ...
describe_weather ( "Boston" )
# 'The current weather in Boston is 72°F and it is sunny and windy.' Las funciones con alimentación de LLM creadas usando @prompt , @chatprompt y @prompt_chain pueden suministrarse como functions a otros decoradores @prompt / @prompt_chain , al igual que las funciones regulares de Python. Esto permite una funcionalidad con alimentación de LLM cada vez más compleja, al tiempo que permite que los componentes individuales sean probados y mejorados de forma aislada.
La clase StreamedStr (y AsyncStreamedStr ) se puede usar para transmitir la salida del LLM. Esto le permite procesar el texto mientras se está generando, en lugar de recibir toda la salida a la vez.
from magentic import prompt , StreamedStr
@ prompt ( "Tell me about {country}" )
def describe_country ( country : str ) -> StreamedStr : ...
# Print the chunks while they are being received
for chunk in describe_country ( "Brazil" ):
print ( chunk , end = "" )
# 'Brazil, officially known as the Federative Republic of Brazil, is ...' Se pueden crear múltiples StreamedStr al mismo tiempo al mismo tiempo para transmitir las salidas LLM simultáneamente. En el siguiente ejemplo, generar la descripción para varios países lleva aproximadamente la misma cantidad de tiempo que para un solo país.
from time import time
countries = [ "Australia" , "Brazil" , "Chile" ]
# Generate the descriptions one at a time
start_time = time ()
for country in countries :
# Converting `StreamedStr` to `str` blocks until the LLM output is fully generated
description = str ( describe_country ( country ))
print ( f" { time () - start_time :.2f } s : { country } - { len ( description ) } chars" )
# 22.72s : Australia - 2130 chars
# 41.63s : Brazil - 1884 chars
# 74.31s : Chile - 2968 chars
# Generate the descriptions concurrently by creating the StreamedStrs at the same time
start_time = time ()
streamed_strs = [ describe_country ( country ) for country in countries ]
for country , streamed_str in zip ( countries , streamed_strs ):
description = str ( streamed_str )
print ( f" { time () - start_time :.2f } s : { country } - { len ( description ) } chars" )
# 22.79s : Australia - 2147 chars
# 23.64s : Brazil - 2202 chars
# 24.67s : Chile - 2186 chars Las salidas estructuradas también se pueden transmitir desde la LLM utilizando la anotación de tipo de retorno Iterable (o AsyncIterable ). Esto permite que cada elemento se procese mientras se genera el siguiente.
from collections . abc import Iterable
from time import time
from magentic import prompt
from pydantic import BaseModel
class Superhero ( BaseModel ):
name : str
age : int
power : str
enemies : list [ str ]
@ prompt ( "Create a Superhero team named {name}." )
def create_superhero_team ( name : str ) -> Iterable [ Superhero ]: ...
start_time = time ()
for hero in create_superhero_team ( "The Food Dudes" ):
print ( f" { time () - start_time :.2f } s : { hero } " )
# 2.23s : name='Pizza Man' age=30 power='Can shoot pizza slices from his hands' enemies=['The Hungry Horde', 'The Junk Food Gang']
# 4.03s : name='Captain Carrot' age=35 power='Super strength and agility from eating carrots' enemies=['The Sugar Squad', 'The Greasy Gang']
# 6.05s : name='Ice Cream Girl' age=25 power='Can create ice cream out of thin air' enemies=['The Hot Sauce Squad', 'The Healthy Eaters']Ver transmisión para más.
Las funciones / corutinas asíncronas se pueden usar para consultar simultáneamente el LLM. Esto puede aumentar en gran medida la velocidad total de la generación, y también permitir que se ejecute otro código asíncrono mientras espera la salida de LLM. En el siguiente ejemplo, el LLM genera una descripción para cada presidente de los Estados Unidos mientras espera el siguiente en la lista. La medición de los caracteres generados por segundo muestra que este ejemplo logra una aceleración 7x sobre el procesamiento en serie.
import asyncio
from time import time
from typing import AsyncIterable
from magentic import prompt
@ prompt ( "List ten presidents of the United States" )
async def iter_presidents () -> AsyncIterable [ str ]: ...
@ prompt ( "Tell me more about {topic}" )
async def tell_me_more_about ( topic : str ) -> str : ...
# For each president listed, generate a description concurrently
start_time = time ()
tasks = []
async for president in await iter_presidents ():
# Use asyncio.create_task to schedule the coroutine for execution before awaiting it
# This way descriptions will start being generated while the list of presidents is still being generated
task = asyncio . create_task ( tell_me_more_about ( president ))
tasks . append ( task )
descriptions = await asyncio . gather ( * tasks )
# Measure the characters per second
total_chars = sum ( len ( desc ) for desc in descriptions )
time_elapsed = time () - start_time
print ( total_chars , time_elapsed , total_chars / time_elapsed )
# 24575 28.70 856.07
# Measure the characters per second to describe a single president
start_time = time ()
out = await tell_me_more_about ( "George Washington" )
time_elapsed = time () - start_time
print ( len ( out ), time_elapsed , len ( out ) / time_elapsed )
# 2206 18.72 117.78Ver Asyncio para más.
functions a @prompt puede contener funciones de async/coroutine. Cuando los objetos FunctionCall correspondientes se llaman el resultado debe ser esperado.Annotated se puede utilizar para proporcionar descripciones y otros metadatos para los parámetros de función. Consulte la documentación pydántica sobre el uso Field para describir los argumentos de la función.@prompt y @prompt_chain también aceptan un argumento model . Puede pasar una instancia de OpenaiChatModel para usar GPT4 o configurar una temperatura diferente. Vea abajo.@prompt siguiendo el cuaderno de ejemplo para un marcado de datos PANDAS. Magentic admite múltiples "backends" (proveedores de LLM). Estos son
openai : el backend predeterminado que utiliza el paquete openai Python. Admite todas las características de Magentic. from magentic import OpenaiChatModelanthropic : usa el paquete de pitón anthropic . Admite todas las características de Magentic, sin embargo, las respuestas de transmisión se reciben actualmente de una vez. pip install " magentic[anthropic] " from magentic . chat_model . anthropic_chat_model import AnthropicChatModellitellm : utiliza el paquete litellm Python para habilitar la consulta de LLM de muchos proveedores diferentes. NOTA: Algunos modelos pueden no admitir todas las características de la función magentic EG llamadas/salida estructurada y transmisión. pip install " magentic[litellm] " from magentic . chat_model . litellm_chat_model import LitellmChatModelmistral : utiliza el paquete openai Python con algunas pequeñas modificaciones para hacer que las consultas de la API sean compatibles con la API Mistral. Admite todas las características de Magentic, sin embargo, las llamadas de herramientas (incluidas las salidas estructuradas) no se transmiten, por lo que se reciben a la vez. Nota: Una versión futura de Magentic podría cambiar a usar el paquete mistral Python. from magentic . chat_model . mistral_chat_model import MistralChatModel El backend y LLM ( ChatModel ) utilizado por magentic se pueden configurar de varias maneras. Cuando se llama a una función magénica, el ChatModel que use sigue este orden de preferencia
ChatModel proporcionada como el argumento model al decorador magénicowith MyChatModel:ChatModel global creado a partir de las variables de entorno y la configuración predeterminada en src/magentic/settings.py from magentic import OpenaiChatModel , prompt
from magentic . chat_model . litellm_chat_model import LitellmChatModel
@ prompt ( "Say hello" )
def say_hello () -> str : ...
@ prompt (
"Say hello" ,
model = LitellmChatModel ( "ollama_chat/llama3" ),
)
def say_hello_litellm () -> str : ...
say_hello () # Uses env vars or default settings
with OpenaiChatModel ( "gpt-3.5-turbo" , temperature = 1 ):
say_hello () # Uses openai with gpt-3.5-turbo and temperature=1 due to context manager
say_hello_litellm () # Uses litellm with ollama_chat/llama3 because explicitly configuredSe pueden establecer las siguientes variables de entorno.
| Variable de entorno | Descripción | Ejemplo |
|---|---|---|
| Magentic_backend | El paquete para usar como backend de LLM | antrópico / OpenAi / litellm |
| Magentic_anthrópico_model | Modelo antrópico | Claude-3-HAIKU-20240307 |
| Magentic_anthrópico_api_key | Clave de API antrópica para ser utilizada por Magentic | SK -... |
| Magentic_anthrópico_base_url | URL base para una API antrópica compatible | http: // localhost: 8080 |
| Magentic_anthrópico_max_tokens | Número máximo de tokens generados | 1024 |
| Magentic_anthrópico_temperatura | Temperatura | 0.5 |
| Magentic_litellm_model | Modelo litellm | Claude-2 |
| Magentic_litellm_api_base | La url base para consultar | http: // localhost: 11434 |
| Magentic_litellm_max_tokens | Litellm max número de tokens generados | 1024 |
| Magentic_litellm_temperature | Temperatura de litellm | 0.5 |
| Magentic_mistral_model | Modelo mistral | maldito |
| Magentic_mistral_api_key | Clave de API distral para ser utilizada por Magentic | Xeg ... |
| Magentic_mistral_base_url | URL base para una API compatible con mierda | http: // localhost: 8080 |
| Magentic_mistral_max_tokens | Número máximo de tokens generados | 1024 |
| Magentic_mistral_seed | Semilla para muestreo determinista | 42 |
| Magentic_mistral_temperatura | Temperatura | 0.5 |
| Magentic_openai_model | Modelo OPERAI | GPT-4 |
| Magentic_openai_api_key | Clave de API de OpenAI para ser utilizada por Magentic | SK -... |
| Magentic_openai_api_type | Opciones permitidas: "OpenAi", "Azure" | azur |
| Magentic_openai_base_url | URL base para una API compatible con OpenAI | http: // localhost: 8080 |
| Magentic_openai_max_tokens | OpenAi Max Número de tokens generados | 1024 |
| Magentic_openai_seed | Semilla para muestreo determinista | 42 |
| Magentic_openai_temperatura | Temperatura de OpenAi | 0.5 |
Al usar el backend openai , configurar la variable de entorno MAGENTIC_OPENAI_BASE_URL o usar OpenaiChatModel(..., base_url="http://localhost:8080") en código le permite usar magentic con cualquier API compatible con OpenAI EG Azure OpenAI Servicio, Litelm Operai Proxy Server, Localai. Tenga en cuenta que si la API no admite las llamadas de la herramienta, entonces no podrá crear funciones de inmediato que devuelvan los objetos de Python, pero otras características de magentic seguirán funcionando.
Para usar Azure con el backend de OpenAI, deberá establecer el entorno MAGENTIC_OPENAI_API_TYPE Variable en "Azure" o usar OpenaiChatModel(..., api_type="azure") , y también establece las variables de entorno necesarias por el paquete OpenAI para acceder a Azure. Ver https://github.com/openai/openai-python#microsoft-azure-openai
Muchas verificadoras de tipos aumentarán advertencias o errores para funciones con el decorador @prompt debido a que la función no tiene cuerpo o valor de retorno. Hay varias formas de lidiar con estos.
empty-body . # pyproject.toml
[ tool . mypy ]
disable_error_code = [ " empty-body " ]... (esto no satisface mypy) o raise . @ prompt ( "Choose a color" )
def random_color () -> str : ...# type: ignore[empty-body] en cada función. En este caso, puede agregar un documento en lugar de ... @ prompt ( "Choose a color" )
def random_color () -> str : # type: ignore[empty-body]
"""Returns a random color."""