Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Zurzeit wird folgendes angezeigt:Foundry (klassische) Portalversion - Wechseln zur Version für das neue Foundry-Portal
Wenn eine oder mehrere Funktionen in Ihrer Anforderung enthalten sind, bestimmt das Modell, ob eine der Funktionen basierend auf dem Kontext der Eingabeaufforderung aufgerufen werden soll. Wenn das Modell bestimmt, dass eine Funktion aufgerufen werden soll, antwortet es mit einem JSON-Objekt, einschließlich der Argumente für die Funktion.
Die Modelle formulieren API-Aufrufe und Strukturdatenausgaben, alle basierend auf den von Ihnen angegebenen Funktionen. Es ist wichtig zu beachten, dass während die Modelle diese Aufrufe generieren können, es liegt an Ihnen, sie auszuführen, um sicherzustellen, dass Sie die Kontrolle behalten.
Auf hoher Ebene können Sie die Arbeit mit Funktionen in drei Schritte unterteilen:
- Aufrufen der API für Chatabschlusse mit Ihren Funktionen und der Benutzereingabe
- Verwenden der Antwort des Modells zum Aufrufen Ihrer API oder Funktion
- Rufen Sie die Chat Completion API erneut auf, einschließlich der Antwort Ihrer Funktion, um eine endgültige Antwort zu erhalten.
Voraussetzungen
- Ein Azure OpenAI-Modell bereitgestellt
- Für die Microsoft Entra ID-Authentifizierung:
- Eine benutzerdefinierte Unterdomäne konfiguriert. Weitere Informationen finden Sie unter Benutzerdefinierte Unterdomänennamen.
- Pakete:
pip install openai azure-identity.
Beispiel für einzelne Tool-/Funktionsaufrufe
Zeigen Sie zunächst einen Toy-Funktionsaufruf, der die Zeit an drei hartcodierten Stellen mit einem einzelnen Tool/einer einzelnen definierten Funktion überprüfen kann. Wir haben Druckanweisungen hinzugefügt, um die Codeausführung einfacher zu verfolgen:
import os
import json
from openai import OpenAI
from datetime import datetime
from zoneinfo import ZoneInfo
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
token_provider = get_bearer_token_provider(
DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = OpenAI(
base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",
api_key=token_provider,
)
# Define the deployment you want to use for your chat completions API calls
deployment_name = "<YOUR_DEPLOYMENT_NAME_HERE>"
# Simplified timezone data
TIMEZONE_DATA = {
"tokyo": "Asia/Tokyo",
"san francisco": "America/Los_Angeles",
"paris": "Europe/Paris"
}
def get_current_time(location):
"""Get the current time for a given location"""
print(f"get_current_time called with location: {location}")
location_lower = location.lower()
for key, timezone in TIMEZONE_DATA.items():
if key in location_lower:
print(f"Timezone found for {key}")
current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
return json.dumps({
"location": location,
"current_time": current_time
})
print(f"No timezone data found for {location_lower}")
return json.dumps({"location": location, "current_time": "unknown"})
def run_conversation():
# Initial user message
messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
#messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined
# Define the function for the model
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get the current time in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
},
"required": ["location"],
},
}
}
]
# First API call: Ask the model to use the function
response = client.chat.completions.create(
model=deployment_name,
messages=messages,
tools=tools,
tool_choice="auto",
)
# Process the model's response
response_message = response.choices[0].message
messages.append(response_message)
print("Model's response:")
print(response_message)
# Handle function calls
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
if tool_call.function.name == "get_current_time":
function_args = json.loads(tool_call.function.arguments)
print(f"Function arguments: {function_args}")
time_response = get_current_time(
location=function_args.get("location")
)
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": "get_current_time",
"content": time_response,
})
else:
print("No tool calls were made by the model.")
# Second API call: Get the final response from the model
final_response = client.chat.completions.create(
model=deployment_name,
messages=messages,
)
return final_response.choices[0].message.content
# Run the conversation and print the result
print(run_conversation())
Ausgabe:
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_pOsKdUlqvdyttYB67MOj434b', function=Function(arguments='{"location":"San Francisco"}', name='get_current_time'), type='function')])
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
The current time in San Francisco is 09:24 AM.
Wenn wir eine Modellbereitstellung verwenden, die parallele Funktionsaufrufe unterstützt, können wir dies in ein Beispiel für parallele Funktionsaufrufe konvertieren, indem sie das Nachrichtenarray so ändern, dass die Zeit an mehreren Stellen anstelle einer von ihnen angefordert wird.
Um dies zu erreichen, tauschen Sie die Kommentare in diesen beiden Zeilen aus:
messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
#messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined
Um so auszusehen, führen Sie den Code erneut aus.
#messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined
Dadurch wird die folgende Ausgabe generiert:
Ausgabe:
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_IjcAVz9JOv5BXwUx1jd076C1', function=Function(arguments='{"location": "San Francisco"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_XIPQYTCtKIaNCCPTdvwjkaSN', function=Function(arguments='{"location": "Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_OHIB5aJzO8HGqanmsdzfytvp', function=Function(arguments='{"location": "Paris"}', name='get_current_time'), type='function')])
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
Function arguments: {'location': 'Tokyo'}
get_current_time called with location: Tokyo
Timezone found for tokyo
Function arguments: {'location': 'Paris'}
get_current_time called with location: Paris
Timezone found for paris
As of now, the current times are:
- **San Francisco:** 11:15 AM
- **Tokyo:** 03:15 AM (next day)
- **Paris:** 08:15 PM
Parallele Funktionsaufrufe ermöglichen es Ihnen, mehrere Funktionsaufrufe zusammen auszuführen, wodurch parallele Ausführung und Abruf von Ergebnissen ermöglicht werden. Dadurch wird die Anzahl der Aufrufe an die API reduziert, die getätigt werden müssen, und kann die Gesamtleistung verbessern.
In unserer einfachen Zeit-App haben wir beispielsweise mehrmals gleichzeitig abgerufen. Dies führte zu einer Chatabschlussnachricht mit drei Funktionsaufrufen im tool_calls Array, jeweils mit einem eindeutigen id. Wenn Sie auf diese Funktionsaufrufe antworten möchten, fügen Sie der Unterhaltung drei neue Nachrichten hinzu, die jeweils das Ergebnis eines Funktionsaufrufs enthalten, mit einem tool_call_id Verweis auf die id von tool_calls.
Um zu erzwingen, dass das Modell eine bestimmte Funktion aufruft, legen Sie tool_choice es auf ein benanntes Toolobjekt fest, z. B.: tool_choice={"type": "function", "function": {"name": "get_current_time"}}. Um eine benutzerorientierte Nachricht zu erzwingen, legen Sie fest tool_choice="none".
Hinweis
Das Standardverhalten (tool_choice: "auto") dient dem Modell, sich selbst zu entscheiden, ob eine Funktion aufgerufen werden soll und welche Funktion aufgerufen werden soll.
Paralleler Funktionsaufruf mit mehreren Funktionen
Nun demonstrieren wir ein weiteres Beispiel für das Aufrufen von Spielzeugfunktionen, dieses Mal mit zwei definierten unterschiedlichen Tools oder Funktionen.
import os
import json
from openai import OpenAI
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
token_provider = get_bearer_token_provider(
DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = OpenAI(
base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",
api_key=token_provider,
)
# Provide the model deployment name you want to use for this example
deployment_name = "YOUR_DEPLOYMENT_NAME_HERE"
# Simplified weather data
WEATHER_DATA = {
"tokyo": {"temperature": "10", "unit": "celsius"},
"san francisco": {"temperature": "72", "unit": "fahrenheit"},
"paris": {"temperature": "22", "unit": "celsius"}
}
# Simplified timezone data
TIMEZONE_DATA = {
"tokyo": "Asia/Tokyo",
"san francisco": "America/Los_Angeles",
"paris": "Europe/Paris"
}
def get_current_weather(location, unit=None):
"""Get the current weather for a given location"""
location_lower = location.lower()
print(f"get_current_weather called with location: {location}, unit: {unit}")
for key in WEATHER_DATA:
if key in location_lower:
print(f"Weather data found for {key}")
weather = WEATHER_DATA[key]
return json.dumps({
"location": location,
"temperature": weather["temperature"],
"unit": unit if unit else weather["unit"]
})
print(f"No weather data found for {location_lower}")
return json.dumps({"location": location, "temperature": "unknown"})
def get_current_time(location):
"""Get the current time for a given location"""
print(f"get_current_time called with location: {location}")
location_lower = location.lower()
for key, timezone in TIMEZONE_DATA.items():
if key in location_lower:
print(f"Timezone found for {key}")
current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
return json.dumps({
"location": location,
"current_time": current_time
})
print(f"No timezone data found for {location_lower}")
return json.dumps({"location": location, "current_time": "unknown"})
def run_conversation():
# Initial user message
messages = [{"role": "user", "content": "What's the weather and current time in San Francisco, Tokyo, and Paris?"}]
# Define the functions for the model
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
}
},
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get the current time in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
},
"required": ["location"],
},
}
}
]
# First API call: Ask the model to use the functions
response = client.chat.completions.create(
model=deployment_name,
messages=messages,
tools=tools,
tool_choice="auto",
)
# Process the model's response
response_message = response.choices[0].message
messages.append(response_message)
print("Model's response:")
print(response_message)
# Handle function calls
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"Function call: {function_name}")
print(f"Function arguments: {function_args}")
if function_name == "get_current_weather":
function_response = get_current_weather(
location=function_args.get("location"),
unit=function_args.get("unit")
)
elif function_name == "get_current_time":
function_response = get_current_time(
location=function_args.get("location")
)
else:
function_response = json.dumps({"error": "Unknown function"})
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
})
else:
print("No tool calls were made by the model.")
# Second API call: Get the final response from the model
final_response = client.chat.completions.create(
model=deployment_name,
messages=messages,
)
return final_response.choices[0].message.content
# Run the conversation and print the result
print(run_conversation())
Ausgabe
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_djHAeQP0DFEVZ2qptrO0CYC4', function=Function(arguments='{"location": "San Francisco", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_q2f1HPKKUUj81yUa3ITLOZFs', function=Function(arguments='{"location": "Tokyo", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_6TEY5Imtr17PaB4UhWDaPxiX', function=Function(arguments='{"location": "Paris", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_vpzJ3jElpKZXA9abdbVMoauu', function=Function(arguments='{"location": "San Francisco"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_1ag0MCIsEjlwbpAqIXJbZcQj', function=Function(arguments='{"location": "Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_ukOu3kfYOZR8lpxGRpdkhhdD', function=Function(arguments='{"location": "Paris"}', name='get_current_time'), type='function')])
Function call: get_current_weather
Function arguments: {'location': 'San Francisco', 'unit': 'celsius'}
get_current_weather called with location: San Francisco, unit: celsius
Weather data found for san francisco
Function call: get_current_weather
Function arguments: {'location': 'Tokyo', 'unit': 'celsius'}
get_current_weather called with location: Tokyo, unit: celsius
Weather data found for tokyo
Function call: get_current_weather
Function arguments: {'location': 'Paris', 'unit': 'celsius'}
get_current_weather called with location: Paris, unit: celsius
Weather data found for paris
Function call: get_current_time
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
Function call: get_current_time
Function arguments: {'location': 'Tokyo'}
get_current_time called with location: Tokyo
Timezone found for tokyo
Function call: get_current_time
Function arguments: {'location': 'Paris'}
get_current_time called with location: Paris
Timezone found for paris
Here's the current information for the three cities:
### San Francisco
- **Time:** 09:13 AM
- **Weather:** 72°C (quite warm!)
### Tokyo
- **Time:** 01:13 AM (next day)
- **Weather:** 10°C
### Paris
- **Time:** 06:13 PM
- **Weather:** 22°C
Is there anything else you need?
Wichtig
Die JSON-Antwort ist möglicherweise nicht immer gültig, daher müssen Sie Ihrem Code zusätzliche Logik hinzufügen, um Fehler behandeln zu können. Bei einigen Anwendungsfällen müssen Sie möglicherweise Feinabstimmung verwenden, um die Leistung von Funktionsaufrufen zu verbessern.
Prompt Engineering mit Funktionen
Wenn Sie eine Funktion als Teil Ihrer Anforderung definieren, werden die Details mithilfe bestimmter Syntax, auf die das Modell trainiert wurde, in die Systemmeldung eingefügt. Dies bedeutet, dass Funktionen Token in Ihrer Eingabeaufforderung nutzen und Prompt Engineering-Techniken anwenden können, um die Leistung Ihrer Funktionsaufrufe zu optimieren. Das Modell verwendet den vollständigen Kontext der Eingabeaufforderung, um festzustellen, ob eine Funktion aufgerufen werden soll, einschließlich Funktionsdefinition, Systemmeldung und Benutzermeldungen.
Verbesserung der Qualität und Zuverlässigkeit
Wenn das Modell Ihre Funktion nicht aufruft, wann oder wie Sie es erwarten, gibt es ein paar Dinge, die Sie versuchen können, die Qualität zu verbessern.
Bereitstellen weiterer Details in der Funktionsdefinition
Es ist wichtig, dass Sie eine aussagekräftige description Funktion bereitstellen und Beschreibungen für jeden Parameter bereitstellen, der für das Modell möglicherweise nicht offensichtlich ist. Beispielsweise können Sie in der Beschreibung für den location Parameter zusätzliche Details und Beispiele für das Format des Speicherorts einfügen.
"location": {
"type": "string",
"description": "The location of the hotel. The location should include the city and the state's abbreviation (i.e. Seattle, WA or Miami, FL)"
},
Bereitstellen von mehr Kontext in der Systemmeldung
Die Systemmeldung kann auch verwendet werden, um mehr Kontext für das Modell bereitzustellen. Wenn Sie beispielsweise eine Funktion namens search_hotels haben, könnten Sie eine Systemmeldung wie die folgende einschließen, um das Modell anzuweisen, die Funktion aufzurufen, wenn ein Benutzer nach Hilfe bei der Suche nach einem Hotel fragt.
{"role": "system", "content": "You're an AI assistant designed to help users search for hotels. When a user asks for help finding a hotel, you should call the search_hotels function."}
Weisen Sie das Modell an, klärende Fragen zu stellen
In einigen Fällen möchten Sie das Modell anweisen, fragende Fragen zu stellen, um annahmen zu verhindern, welche Werte mit Funktionen verwendet werden sollen. Zum Beispiel möchten Sie, dass das Modell nach einer Klarstellung fragt, search_hotels falls die Benutzeranforderung keine Details zu location enthält. Um das Modell anzuweisen, eine klarstellende Frage zu stellen, könnten Sie Inhalte wie das nächste Beispiel in Ihre Systemnachricht einschließen.
{"role": "system", "content": "Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous."}
Reduzieren von Fehlern
Ein weiterer Bereich, in dem das Prompt Engineering hilfreich sein kann, besteht darin, Fehler in Funktionsaufrufen zu reduzieren. Die Modelle werden geschult, um Funktionsaufrufe zu generieren, die dem von Ihnen definierten Schema entsprechen, aber die Modelle erzeugen einen Funktionsaufruf, der nicht mit dem von Ihnen definierten Schema übereinstimmt, oder versuchen, eine Funktion aufzurufen, die Sie nicht eingeschlossen haben.
Wenn Sie feststellen, dass das Modell Funktionsaufrufe generiert, die nicht bereitgestellt wurden, versuchen Sie, einen Satz in die Systemmeldung einzugeben, die besagt "Only use the functions you have been provided with.".
Verantwortungsvolles Verwenden von Funktionsaufrufen
Wie jedes KI-System stellt die Verwendung von Funktionsaufrufen zur Integration von Sprachmodellen mit anderen Tools und Systemen potenzielle Risiken dar. Es ist wichtig, die Risiken zu verstehen, die Funktionsaufrufe darstellen können, und Maßnahmen zu ergreifen, um sicherzustellen, dass Sie die Fähigkeiten verantwortungsbewusst nutzen.
Hier sind einige Tipps, mit denen Sie Funktionen sicher und sicher verwenden können:
- Überprüfen von Funktionsaufrufen: Überprüfen Sie immer die vom Modell generierten Funktionsaufrufe. Dazu gehören die Überprüfung der Parameter, die aufgerufene Funktion und die Sicherstellung, dass der Aufruf an die beabsichtigte Aktion ausgerichtet ist.
- Verwenden Sie vertrauenswürdige Daten und Tools: Verwenden Sie nur Daten aus vertrauenswürdigen und überprüften Quellen. Nicht vertrauenswürdige Daten in der Ausgabe einer Funktion können verwendet werden, um das Modell anzuweisen, Funktionsaufrufe auf eine andere Weise als beabsichtigt zu schreiben.
- Befolgen Sie das Prinzip der geringsten Rechte: Gewähren Sie nur den minimalen Zugriff, der für die Funktion erforderlich ist, um ihre Aufgabe auszuführen. Dies reduziert die potenziellen Auswirkungen, wenn eine Funktion missbraucht oder ausgenutzt wird. Wenn Sie beispielsweise Funktionsaufrufe zum Abfragen einer Datenbank verwenden, sollten Sie Ihrer Anwendung nur schreibgeschützten Zugriff auf die Datenbank gewähren. Sie sollten sich auch nicht ausschließlich darauf verlassen, Funktionalitäten in der Funktionsdefinition als Sicherheitskontrolle auszuschließen.
- Berücksichtigen Sie die Auswirkungen in der realen Welt: Seien Sie sich der realen Auswirkungen von Funktionsaufrufen bewusst, die Sie ausführen möchten, insbesondere diejenigen, die Aktionen auslösen, wie zum Beispiel das Ausführen von Code, das Aktualisieren von Datenbanken oder das Senden von Benachrichtigungen.
- Implementieren Von Benutzerbestätigungsschritten: Insbesondere für Funktionen, die Aktionen ausführen, empfehlen wir, einen Schritt einzunehmen, in dem der Benutzer die Aktion vor der Ausführung bestätigt.
Weitere Informationen zu unseren Empfehlungen zur verantwortungsvollen Verwendung von Azure OpenAI-Modellen finden Sie in der Overview of Responsible AI practices for Azure OpenAI models.
Wichtig
Die Parameter functions und function_call wurden mit der 2023-12-01-preview-Version der API abgekündigt. Der Ersatz für functions ist der tools Parameter. Der Ersatz für function_call ist der tool_choice Parameter.
Unterstützung für Funktionsaufrufe
Paralleler Funktionsaufruf
-
gpt-4(2024-04-09) -
gpt-4o(2024-05-13) -
gpt-4o(2024-08-06) -
gpt-4o(2024-11-20) -
gpt-4o-mini(2024-07-18) -
gpt-4.1(2025-04-14) -
gpt-4.1-mini(2025-04-14) -
gpt-5(2025-08-07) -
gpt-5-mini(2025-08-07) -
gpt-5-nano(2025-08-07) -
gpt-5-codex(2025-09-11) -
gpt-5.1(2025-11-13) -
gpt-5.1-chat(2025-11-13) -
gpt-5.1-codex(2025-11-13) -
gpt-5.1-codex-mini(2025-11-13) -
gpt-5.1-codex-max(2025-12-04) -
gpt-5.2(2025-12-11) -
gpt-5.2-chat(2025-12-11) -
gpt-5.2-codex(2026-01-14) -
gpt-5.2-chat(2026-02-10) -
gpt-5.3-codex(2026-02-24) -
gpt-5.3-chat(2026-03-03) -
gpt-5.4(2026-03-05) -
gpt-5.4-mini(2026-03-17) -
gpt-5.4-nano(2026-03-17)
Unterstützung für parallele Funktion wurde zuerst in der API-Version 2023-12-01-preview hinzugefügt.
Grundlegende Funktionsaufrufe mit Tools
- Alle Modelle, die parallele Funktionsaufrufe unterstützen
-
gpt-5.4-pro(2026-03-05) -
gpt-5-pro(2025-10-06) -
codex-mini(2025-05-16) -
o3-pro(2025-06-10) -
o4-mini(2025-04-16) -
o3(2025-04-16) -
gpt-4.1-nano(2025-04-14) -
o3-mini(2025-01-31) -
o1(2024-12-17)
Hinweis
Der tool_choice Parameter wird jetzt mit o3-mini und o1unterstützt. Weitere Informationen finden Sie im Leitfaden zu Gründen von Modellen.
Wichtig
Beschreibungen von Tools/Funktionen sind derzeit auf 1.024 Zeichen mit Azure OpenAI beschränkt. Wir aktualisieren diesen Artikel, wenn dieser Grenzwert geändert wird.
Nächste Schritte
- Learn Sie mehr über Azure OpenAI.
- Weitere Beispiele zum Arbeiten mit Funktionen finden Sie im Azure OpenAI Samples GitHub Repository