Szkolenie dostosowanego modelu w Azure ML i wywoływanie go z agenta Foundry
Szkolimy, rejestrujemy i wdrażamy model churn na zarządzanym punkcie końcowym Azure ML, a następnie udostępniamy go agencie Foundry jako FunctionTool, wraz z informacjami dotyczącymi autoryzacji i warunków produkcji.
Źródła: Building and Serving a Custom Model with Azure ML, Then Wiring It Into a Foundry Agent
Katalog modeli Foundry jest szeroki, ale niektóre zadaania wykraczają poza jego zakres. Wyobraźmy sobie przewidywanie odejść klientów na podstawie własnych rekordów firmy lub ocenianie oszustw na podstawie jej historii transakcji. To są typowe zadania uczenia maszynowego na prywatnych danych tabelarycznych, a rozwiązaniem Microsoftu w tym zakresie jest Azure Machine Learning – odrębny produkt z własnym SDK, indywidualną przestrzenią roboczą oraz własną metodą wdrażania modeli.
Poniższy proces obejmuje całą ścieżkę: szkolenie modelu za pomocą SDK Azure ML, jego rejestrację, udostępnianie go z zarządzanego punktu końcowego, a następnie udostępnianie tego punktu końcowego agentowi Foundry jako narzędzia funkcyjnego. Agent może wtedy wywołać ten specjalny model w trakcie rozmowy dokładnie tak samo, jak wywoływałby każde inne narzędzie.
Gdzie spotykają się te dwie platformy
Dwa te produkty działają w oddzielnych środowiskach wykonawczych, ale należą do jednego ekosystemu, a Microsoft stara się utrzymać między nimi jak najmniejszą przerwę. Wiedza o dokładnym miejscu tej przerwy ułatwia śledzenie procesu budowania. W grę wchodzą cztery elementy:
- Zadanie poleceń. Tutaj odbywają się procesy szkolenia. SDK jest skierowane na skrypt, cel obliczeniowy oraz dane wejściowe i wykonuje kod jako zapisane, powtarzalne zadanie.
- Rejestr modeli. Szkolony model przekształca się w nazwany, zversionowany artefakt, który istnieje niezależnie od zadania, które go stworzyło, dzięki czemu jedna wersja może zostać wprowadzona do produkcji bez konieczności ponownego przeprowadzenia procesu szkolenia.
- Zarządzany online endpoint. Służy do dostarczania prognoz na podstawie zarejestrowanego modelu. Jest to prawdziwa infrastruktura, zawsze dostępna lub skalowana automatycznie, posiadająca własną adresację URL, mechanizmy autoryzacji oraz koszty, i znajduje się w przestrzeni roboczej Azure ML, a nie w Foundry.
FunctionTool. To jest most łączący obie platformy. Foundry nie wie ani go to nie obchodzi, że funkcja znajdująca się za tym narzędziem wywołuje punkt końcowy Azure ML. Dla agenta jest to po prostu nazwa, schemat oraz wynik.Wymagania wstępne
- Przestrzeń robocza Azure ML oraz projekt Foundry. Mogą znajdować się w tych samych lub różnych grupach zasobów, ponieważ nic tutaj nie wymaga wspólnej infrastruktury.
- Python 3.9 lub nowsza wraz z oboma SDK:
pip install azure-ai-ml azure-ai-projects azure-identity
MLClient uwierzytelnia się i skierowuje do przestrzeni roboczej:
from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential
ml_client = MLClient(
DefaultAzureCredential(),
subscription_id="<subscription-id>",
resource_group_name="<resource-group>",
workspace_name="<aml-workspace-name>",
)
Szkolenie jako zadanie poleceń
Krok szkolenia to zadanie poleceń. Bierze ono skrypt szkoleniowy, w tym przypadku zwykły klasyfikator scikit-learn, i wykonuje go na zarządzanej mocy obliczeniowej:
from azure.ai.ml import command, Input, Output
train_job = command(
code="./src",
command="python train.py --data ${{inputs.training_data}} --model_output ${{outputs.model_output}}",
inputs={"training_data": Input(type="uri_folder", path="azureml://datastores/workspaceblobstore/paths/churn-training/")},
outputs={"model_output": Output(type="uri_folder")},
environment="azureml://registries/azureml/environments/sklearn-1.5/labels/latest",
compute="cpu-cluster",
display_name="churn-model-training",
)
returned_job = ml_client.jobs.create_or_update(train_job)
ml_client.jobs.stream(returned_job.name)
Wezwanie do ml_client.jobs.stream czeka i wyświetla logi aż trening się zakończy. Należy go używać w każdym skrypcie, który rzeczywiście ma zostać uruchomiony. Zadanie, które zawodzi w tle bez żadnych komunikatów, to nieprzyjemny sposób na odkrycie awarii w łańcuchu przetwarzania.
Rегистrowanie modelu
Rегистrowanie przekształca wyniki zadania w nazwany, zwersjonowany artefakt, który można odwoływać się do niego niezależnie:
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes
model = ml_client.models.create_or_update(
Model(
path=f"azureml://jobs/{returned_job.name}/outputs/model_output",
name="churn-classifier",
type=AssetTypes.MLFLOW_MODEL,
description="Customer churn classifier, trained on 18 months of account history.",
)
)
Wybór MLFLOW_MODEL jako typu jest celowy. Jeśli skrypt treningowy rejestruje model za pomocą automatycznego logowania MLflow, zarządzane punkty końcowe mogą go wdrożyć przy użyciu wbudowanego kontenera oceny, bez konieczności stosowania własnego skryptu inferencji score.py. Dzięki temu oszczędza się czas w czasie rzeczywistym, a skrypt treningowy powinien być od początku zaprojektowany wokół tego rozwiązania.
Wdrażanie za pomocą punktu końcowego
Punkt końcowy w połączeniu z procesem wdrażania umożliwia udostępnienie modelu online:
from azure.ai.ml.entities import ManagedOnlineEndpoint, ManagedOnlineDeployment
endpoint = ManagedOnlineEndpoint(name="churn-endpoint", auth_mode="key")
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
deployment = ManagedOnlineDeployment(
name="blue",
endpoint_name="churn-endpoint",
model=model,
instance_type="Standard_DS3_v2",
instance_count=1,
)
ml_client.online_deployments.begin_create_or_update(deployment).result()
endpoint.traffic = {"blue": 100}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
Nazwa wdrożenia blue nie jest obowiązkowa, ale warto ją zachować, ponieważ ułatwia przyzwyczajenie się do tej praktyki już przy pierwszej nowej wersji modelu. Stwórz kolejne wdrożenie green obok blue, rozdziel ruch między nimi i przenieś go całkowicie, gdy nowa wersja zyska zaufanie. Zastąpienie blue i liczenie na najlepszy scenariusz to ryzykowna alternatywa.
Zanim podłączysz cokolwiek innego, uzyskaj bezpośrednią, rzeczywistą prognozę:
import json
test_input = {"input_data": {"columns": ["tenure_months", "monthly_spend", "support_tickets"], "data": [[14, 89.50, 3]]}}
response = ml_client.online_endpoints.invoke(
endpoint_name="churn-endpoint",
request_file=None,
deployment_name="blue",
input_data=json.dumps(test_input),
)
print(response)
Doprowadzanie do porządku uszkodzonego punktu końcowego za pomocą pętli wywoływania funkcji agenta jest znacznie trudniejsze niż jego bezpośrednie naprawianie, dlatego najpierw upewnij się, że działa poprawnie.
Łączenie punktu końcowego z agentem Foundry
Agent nigdy nie wywołuje bezpośrednio Azure ML. Kod aplikacji to robi, gdy agent o to prosi. Konfiguracja deklaruje FunctionTool, tworzy agenta i definiuje funkcję, która wysyła żądanie HTTP do punktu końcowego:
import os
import requests
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition, Tool, FunctionTool
from azure.identity import DefaultAzureCredential
def get_churn_score(tenure_months: int, monthly_spend: float, support_tickets: int) -> dict:
payload = {"input_data": {"columns": ["tenure_months", "monthly_spend", "support_tickets"], "data": [[tenure_months, monthly_spend, support_tickets]]}}
resp = requests.post(
"https://churn-endpoint.<region>.inference.ml.azure.com/score",
headers={"Authorization": f"Bearer {os.environ['AML_ENDPOINT_KEY']}", "Content-Type": "application/json"},
json=payload,
timeout=10,
)
resp.raise_for_status()
return {"churn_probability": resp.json()[0]}
func_tool = FunctionTool(
name="get_churn_score",
description="Predict churn probability for a customer given tenure, spend, and support ticket history.",
parameters={
"type": "object",
"properties": {
"tenure_months": {"type": "integer", "description": "How many months the customer has been active."},
"monthly_spend": {"type": "number", "description": "Average monthly spend in dollars."},
"support_tickets": {"type": "integer", "description": "Number of support tickets in the last 90 days."},
},
"required": ["tenure_months", "monthly_spend", "support_tickets"],
"additionalProperties": False,
},
strict=True,
)
project = AIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=DefaultAzureCredential())
tools: list[Tool] = [func_tool]
agent = project.agents.create_version(
agent_name="retention-agent",
definition=PromptAgentDefinition(
model="gpt-4.1-mini",
instructions="Help the team assess churn risk. Call get_churn_score whenever specific customer numbers are provided.",
tools=tools,
),
)
Następnie odbywa się rozmowa, wywołanie funkcji modelu zostaje przechwycone, a wynik jest zwracany:
import json
from openai.types.responses.response_input_param import FunctionCallOutput
openai_client = project.get_openai_client()
conversation = openai_client.conversations.create()
response = openai_client.responses.create(
input="A customer's been with us 14 months, spends about $90/month, and filed 3 tickets recently. Churn risk?",
conversation=conversation.id,
extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
)
for item in response.output:
if item.type == "function_call" and item.name == "get_churn_score":
result = get_churn_score(**json.loads(item.arguments))
follow_up = openai_client.responses.create(
input=[FunctionCallOutput(type="function_call_output", call_id=item.call_id, output=json.dumps(result))],
conversation=conversation.id,
extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
)
print(follow_up.output_text)
Model decyduje, czy pytanie wymaga wywołania funkcji get_churn_score. Gdy tak jest, kod aplikacji wysyła żądanie HTTP do Azure ML, a wynik jest zwracany do tej samej rozmowy, aby model mógł dokończyć swoją odpowiedź. Nic w definicji agenta ani we wywołaniach API Responses nie zależy od tego, co funkcja robi w tle. Może ona korzystać z bazy danych, wywoływać funkcję Lambda lub łączyć się z innym pracownikiem Azure ML, tak jak to ma miejsce tutaj.
Dwa zasoby, dwa obszary autoryzacji
Jedna kwestia pozostaje niewyjaśniona w dokumentacji SDK. Zarządzany punkt końcowy w Azure ML oraz punkt końcowy projektu w Foundry to dwa zasoby znajdujące się za dwiema odrębnymi ścianami autoryzacji, a nic w tym ustawieniu ich nie łączy. Azure ML posiada własny klucz lub zarządzaną tożsamość dla przestrzeni roboczej, podczas gdy Foundry ma inne dane uwierzytelniające. Deklaracja FunctionTool nie buduje żadnego zaufania pomiędzy nimi; daje jedynie modelowi nazwę i schemat, aby mógł poprosić Twój kod o coś. Cała autoryzacja wobec Azure ML odbywa się wewnątrz Twojej funkcji, dokładnie tak jak przy wywoływaniu dowolnej innej zewnętrznej API.
To jest zaleta. Strona Azure ML może być zarządzana, zabezpieczana i aktualizowana niezależnie od Foundry, nawet przez inny zespół, a żadna ze stron nie potrzebuje uprawnień do edycji zasobów drugiej strony.
Uwagi dotyczące produkcji
- Wywołanie funkcji wygasa po 10 minutach. Wyniki muszą zostać przesłane z powrotem do rozmowy przed zamknięciem okna, w przeciwnym razie proces się nie powiedzie. Jeśli wywołanie HTTP do Azure ML jest wolne, należy traktować to jako ścisły termin i uwzględnić to w planach.
- Przejdź na zarządzaną tożsamość poza fazą prototypowania. Klucz przechowywany w zmiennych środowiskowych jest w porządku w warunkach lokalnych, ale stanowi zagrożenie w przypadku systemów bez nadzoru. Nadaj tożsamości uruchamiającej kod narzędzia rolę
AzureML Data Scientistlub węższą, dostosowaną rolę skierowaną wyłącznie na ten konkretny punkt końcowy, a nie na całe środowisko pracy. - Wprowadzaj nowe modele stopniowo. Uruchom nową wersję obok istniejącej i stopniowo przenoś na nią ruch. To jedyny sposób, aby zauważyć problemy z ponownym szkoleniem modeli, zanim każde rzeczywiste żądanie będzie od nich zależeć.
strict=True. Ścisłe schematy zapobiegają wysyłaniu przez model niekompletnych lub błędnie sformatowanych argumentów do get_churn_score, co w przeciwnym razie mogłoby spowodować awarię wewnątrz funkcji, a nie przed jej wywołaniem.get_churn_score w miejscu dostępnym do przeglądania oraz regularnie sprawdzaj dane treningowe, a nie tylko wtedy, gdy prognozy wyraźnie się pogorszą.Wybór odpowiedniej platformy
Dla większości zadań związanych z sztuczną inteligencją generatywną katalog Foundry jest odpowiednim narzędziem, a zespoły bez własnych danych treningowych prawdopodobnie nigdy nie będą potrzebować niczego więcej. Gdy pytanie zmienia się w prognozę dotyczącą twoich własnych klientów na podstawie twojej historii, lepszym wyborem jest Azure ML. W przeciwnym razie model językowy musi być wykorzystywany do zadań, do których nie został zaprojektowany, albo infrastruktura serwisowa musi być budowana ręcznie. Wszystko sprowadza się do kilku elementów: jedno zadanie treningowe, jeden zarejestrowany model, jeden zarządzany punkt końcowy oraz pojedynczy FunctionTool. Platformy pozostają oddzielne, każda realizując to, w czym jest najlepsza.
Literatura pokrewna
- Agent handlowy LangChain wspierany przez aktualne dane rynkowe EODHD, krok po kroku — Dlaczego agenci handlowe oparte na LLM zawodzą bez rzeczywistych danych, jak działa pętla ReAct oraz jak stworzyć agenta LangChain wykorzystującego trzy narzędzia do analizy cen EODHD, danych fundamentalnych i wskaźnika RSI.
- Praktyczne notatki: Microsoft stworzył serwer MCP Playwright. A potem powiedział wam to — Szczegółowy przewodnik po praktycznych notatkach: Microsoft stworzył serwer MCP Playwright. A potem powiedział wam to: umowy, sprawdzania oraz gotowe fragmenty kodu dla zespołów wdrażających ten model.