大規模な言語モデルをPythonコードに簡単に統合できます。 @promptと@chatpromptデコレータを使用して、LLMから構造化された出力を返す関数を作成するだけです。 LLMクエリと機能呼び出しを通常のPythonコードと組み合わせて、複雑なロジックを作成します。
FunctionCallおよびParallelFunctionCallリターンタイプ。async defを使用するだけです。pip install magenticまたはUVを使用します
uv add magentic OPENAI_API_KEY環境変数を設定して、OpenAI APIキーを構成します。別のLLMプロバイダーを構成するには、詳細については構成を参照してください。
@promptデコレーターを使用すると、大規模な言語モデル(LLM)プロンプトのテンプレートをPython関数として定義できます。この関数が呼び出されると、引数がテンプレートに挿入され、このプロンプトが関数出力を生成するLLMに送信されます。
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?" @promptデコレーターは、装飾された関数の返品タイプの注釈を尊重します。これは、 pydanticモデルを含む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'])詳細については、構造化された出力を参照してください。
@chatpromptデコレーターは@promptのように動作しますが、1つのテキストプロンプトではなくテンプレートとしてチャットメッセージを渡すことができます。これを使用して、システムメッセージを提供するために、またはモデルの出力をガイドするためのサンプル応答を提供する場合の少数のショットプロンプトのために使用できます。 Curly Braces {example}で示されるフォーマットフィールドは、すべてのメッセージ( 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')詳細については、チャットのプロンプトを参照してください。
LLMは、関数を呼び出すこともできます。この場合、 @prompt廃棄された関数は、LLMが提供する引数を使用して関数を実行するように呼び出すことができるFunctionCallオブジェクトを返します。
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>'詳細を求める関数を参照してください。
LLMは、最終的な回答を生成するために1つ以上の関数呼び出しを行う必要がある場合があります。 @prompt_chainデコレーターは、 FunctionCallオブジェクトを自動的に解決し、出力をLLMに戻し、最終回答に到達するまで続行します。
次の例では、 describe_weatherがLLMと呼ばれる場合、最初にget_current_weather関数を呼び出し、その結果を使用して、返される最終回答を策定します。
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.' @prompt 、 @chatprompt 、および@prompt_chainを使用して作成されたLLM駆動の関数は、通常のPython関数と同様に、他の@prompt / @prompt_chainデコレーターにfunctionsとして提供できます。これにより、ますます複雑になっているLLM駆動の機能が可能になり、個々のコンポーネントをテストおよび改善して単独で改善できます。
StreamedStr (およびAsyncStreamedStr )クラスを使用して、LLMの出力をストリーミングできます。これにより、テキストが生成されている間に生成中に処理することができます。
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 ...'複数のStreamedStrを同時に作成して、LLM出力を同時にストリーミングできます。以下の例では、複数の国の説明を生成するには、単一の国とほぼ同じ時間がかかります。
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構造化された出力は、リターンタイプの注釈Iterable (またはAsyncIterable )を使用して、LLMからストリーミングすることもできます。これにより、次のアイテムが生成されている間、各アイテムを処理できます。
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']詳細については、ストリーミングを参照してください。
非同期関数 /コルーチンを使用して、LLMを同時に照会できます。これにより、生成の全体的な速度が大幅に向上し、LLM出力を待っている間に他の非同期コードが実行される可能性があります。以下の例では、LLMは、リストの次の大統領を待っている間に、各米国大統領の説明を生成します。 1秒あたりの生成された文字を測定すると、この例がシリアル処理よりも7倍のスピードアップを達成することを示しています。
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.78詳細については、Asyncioを参照してください。
@promptへのfunctions引数には、async/coroutine関数を含めることができます。対応するFunctionCallオブジェクトが呼ばれる場合、結果を待つ必要があります。Annotatedタイプの注釈は、関数パラメーターに説明およびその他のメタデータを提供するために使用できます。 Fieldを使用して関数引数を説明するためのPydanticドキュメントを参照してください。@promptおよび@prompt_chainデコレーターもmodel引数を受け入れます。 OpenaiChatModelのインスタンスを渡してGPT4を使用したり、異なる温度を設定したりできます。以下を参照してください。@prompt関数のリターンタイプアノテーションとして使用する他のタイプを登録します。 Magenticは、複数の「バックエンド」(LLMプロバイダー)をサポートします。これらは
openai : openai Pythonパッケージを使用するデフォルトのバックエンド。 Magenticのすべての機能をサポートします。 from magentic import OpenaiChatModelanthropic : anthropic Pythonパッケージを使用します。 Magenticのすべての機能をサポートしていますが、ストリーミング応答は現在一度にすべて受信されています。 pip install " magentic[anthropic] " from magentic . chat_model . anthropic_chat_model import AnthropicChatModellitellm : litellm Pythonパッケージを使用して、多くの異なるプロバイダーからのLLMのクエリを有効にします。注:一部のモデルは、 magentic EG機能呼び出し/構造化出力とストリーミングのすべての機能をサポートしない場合があります。 pip install " magentic[litellm] " from magentic . chat_model . litellm_chat_model import LitellmChatModelmistral : openai Pythonパッケージをいくつかの小さな変更で使用して、APIクエリをMistral APIと互換性のあるものにします。 Magenticのすべての機能をサポートしますが、ツール呼び出し(構造化された出力を含む)はストリーミングされていないため、一度に受信されます。注:Magenticの将来のバージョンは、 mistral Pythonパッケージの使用に切り替える可能性があります。 from magentic . chat_model . mistral_chat_model import MistralChatModel magenticが使用するバックエンドとLLM( ChatModel )は、いくつかの方法で構成できます。マージェント関数が呼び出されると、使用するChatModelこの好みの順序に従います
model引数として提供されたChatModelインスタンスwith MyChatModel:ChatModelと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 configured次の環境変数を設定できます。
| 環境変数 | 説明 | 例 |
|---|---|---|
| Magentic_backend | LLMバックエンドとして使用するパッケージ | 人類 / openai / litellm |
| Magentic_anthropic_model | 人類モデル | Claude-3-Haiku-20240307 |
| Magentic_anthropic_api_key | Magenticが使用する人類APIキー | SK -... |
| Magentic_anthropic_base_url | 人類互換APIのベースURL | http:// localhost:8080 |
| Magentic_anthropic_max_tokens | 生成されたトークンの最大数 | 1024 |
| Magentic_anthropic_temperature | 温度 | 0.5 |
| Magentic_litellm_model | litellmモデル | クロード-2 |
| Magentic_litellm_api_base | クエリするベースURL | http:// localhost:11434 |
| Magentic_litellm_max_tokens | litellm max生成されたトークンの数 | 1024 |
| Magentic_litellm_temperature | litellm温度 | 0.5 |
| Magentic_mistral_model | ミストラルモデル | ミストラル - レイテスト |
| Magentic_mistral_api_key | Magenticが使用するMistral APIキー | xeg ... |
| Magentic_mistral_base_url | ミストラル互換APIのベースURL | http:// localhost:8080 |
| Magentic_mistral_max_tokens | 生成されたトークンの最大数 | 1024 |
| Magentic_mistral_seed | 決定論的なサンプリングのためのシード | 42 |
| Magentic_mistral_temperature | 温度 | 0.5 |
| Magentic_openai_model | Openaiモデル | GPT-4 |
| Magentic_openai_api_key | Magenticが使用するOpenai APIキー | SK -... |
| Magentic_openai_api_type | 許可オプション:「Openai」、「Azure」 | azure |
| Magentic_openai_base_url | OpenAI互換APIのベースURL | http:// localhost:8080 |
| Magentic_openai_max_tokens | Openai Max生成されたトークンの数 | 1024 |
| Magentic_openai_seed | 決定論的なサンプリングのためのシード | 42 |
| Magentic_openai_temperature | Openai温度 | 0.5 |
openaiバックエンドを使用する場合、 MAGENTIC_OPENAI_BASE_URL環境変数を設定するか、 OpenaiChatModel(..., base_url="http://localhost:8080")を使用するとmagentic Openaiに適合するAzureサービス、liTellmmmmmmm Openai Proxy Server、Localai。 APIがツール呼び出しをサポートしていない場合、Pythonオブジェクトを返すプロンプトファンションを作成することはできませんが、 magenticの他の機能は引き続き機能します。
OpenaiバックエンドでAzureを使用するには、 MAGENTIC_OPENAI_API_TYPE環境変数を「Azure」に設定するか、 OpenaiChatModel(..., api_type="azure")を使用し、Openaiパッケージがアクセスするために必要な環境変数を設定する必要があります。 https://github.com/openai/openai-python#microsoft-azure-openaiを参照してください
多くのタイプチェッカーは、ボディまたはリターン値がない関数のために、 @promptデコレータで機能の警告またはエラーを提起します。これらに対処する方法はいくつかあります。
empty-body 。 # pyproject.toml
[ tool . mypy ]
disable_error_code = [ " empty-body " ]... (これはmypyを満たしません)またはraise 。 @ prompt ( "Choose a color" )
def random_color () -> str : ...# type: ignore[empty-body] 。この場合、 ...の代わりにDocstringを追加できます。 @ prompt ( "Choose a color" )
def random_color () -> str : # type: ignore[empty-body]
"""Returns a random color."""