Criação de serviços de IA
Para implantar um serviço de IA, você pode criar um serviço de IA diretamente em um notebook. Você deve definir seu serviço de IA em Python e ele deve atender a determinados requisitos. Para implantar um serviço de IA, você deve criar um ativo do repositório de tempo de execução watsonx.ai e carregar o arquivo Python no ativo.
Definição de um serviço de IA com a biblioteca de clientes Python
Para definir um serviço de IA em um notebook usando a biblioteca cliente watsonx.ai Python, siga estas etapas:
Para trabalhar com o serviço de IA em Python, instale o SDK Python '
ibm-watsonx-ai:pip install ibm-watsonx-aiDepois de instalar a biblioteca do cliente Python, inicialize o cliente e defina o espaço de implantação padrão:
from ibm_watsonx_ai import APIClient from ibm_watsonx_ai import Credentials credentials = Credentials( url=url, api_key=apikey ) client = APIClient(credentials) client.set.default_space(space_id=space_id)Defina seu serviço de IA em Python usando o seguinte layout:
def basic_generate_demo(context, model="google/flan-t5-xl", **parameters): # "parameters" is a reserved argument and will be enabled in future # generate token from task credentials api task_token = context.generate_token() def generate(context): user_token = context.get_token() # extract token from header user_headers = context.get_headers() json_body = context.get_json() # example 1: json return { "headers": { "Content-Type": "application/json", "user-custom-header": "my-header-x1", }, "body": { "model": model }, } def generate_stream(context): user_token = context.get_token() # extract token from header user_headers = context.get_headers() json_body = context.get_json() # return a generator data_to_stream = json_body.get("sse", "Default message!") for x in data_to_stream: yield x def generate_batch(input_data_references, output_data_reference): # generate token from task credentials api task_token = context.generate_token() # do something. # ... return generate, generate_stream, generate_batchNota:Dependendo do seu caso de uso, você deve incluir pelo menos uma dessas funções como uma função aninhada:
generate()generate_stream()generate_batch()
Para obter mais informações, consulte Requisitos para criar um serviço de IA.
Requisitos para definir um serviço de IA
O serviço de IA captura a lógica de seu caso de uso de IA generativa (por exemplo, um aplicativo de geração aumentada por recuperação) e lida com a chamada da API REST para o ponto de extremidade de implantação ' /ml/v4/deployments.
Siga estas diretrizes para definir um serviço de IA:
Crie uma função Python. Você pode especificar qualquer nome para sua função. Para saber mais sobre os parâmetros da função, consulte a documentação da API RESTwatsonx.ai.
Dependendo do seu caso de uso, a função Python que você deseja implantar deve incluir pelo menos uma dessas funções como uma função aninhada em seu escopo:
generate()generate_stream()generate_batch()
Quando você usa a biblioteca cliente watsonx.ai Python para salvar a função Python que contém uma referência a uma função externa, somente o código no escopo da função externa (incluindo suas funções aninhadas) é salvo. Portanto, o código fora do escopo da função externa não será salvo e, assim, não estará disponível quando você implementar a função.
Diretrizes para definir a função generate()
A função " generate() pode ser usada para processar seu token de autorização. Essa função lida com a chamada REST para o ponto de extremidade de inferência ' /ml/v4/deployments/{id_or_name}/ai_service.
Siga estas diretrizes para definir a função ' generate() dentro do serviço de IA:
- Você deve usar o nome '
generatepara definir a função. - Você só pode fornecer um argumento para a função '
generate(): 'context. - A função '
generate()deve retornar um valor do tipo de dados 'dict(dicionário). - Opcional: Opcionalmente, você pode especificar as chaves "
bodyou "header.
Exemplo
def generate(context):
user_token = context.get_token()
headers = context.get_headers()
json_body = context.get_json()
return {
"headers": {
"Content-Type": "text/plain"
},
"body": "Hello WatsonX"
}
Diretrizes para definir a função generate_stream()
Você pode usar a função " generate_stream() para casos de uso de IA generativa que exigem streaming. Essa função lida com a chamada REST para o ponto de extremidade de inferência de eventos enviados pelo servidor (SSE) ' POST /ml/v4/deployments/{id_or_name}/ai_service_stream.
Siga estas diretrizes para definir a função ' generate_stream() dentro do serviço de IA:
- Você deve usar o nome '
generate_streampara definir a função. - Você só pode fornecer um argumento para a função '
generate_stream(): 'context.
Exemplo
def generate_stream(context):
user_token = context.get_token()
headers = context.get_headers()
json_body = context.get_json()
for x in ["Hello", "WatsonX", "!"]:
yield x
Saída
id: 1
event: message
data: Olá
id: 2
event: message
data: WatsonX
id: 3
event: message
data: !
id: 4
event: eos
Diretrizes para a definição da função generate_batch()
A função " generate_batch() pode ser usada para casos de uso que exigem inferência em lote. Essa função lida com a chamada da API REST para o ponto de extremidade de trabalhos ' /ml/v4/deployments_jobs.
Siga estas diretrizes para definir a função ' generate_batch() dentro do serviço de IA:
- Você deve usar o nome '
generate_batch()para definir a função.
Exemplo
def generate_batch(input_data_references: list[dict], output_data_reference: dict):
# context from outer function is visible
batch_token = context.generate_token()
print(f"batch_token: {batch_token[-5:]}", flush=True)
print(
f"generate_batch:\n{input_data_references=}\n{output_data_reference=}",
flush=True,
)
Código de amostra para criar um serviço de IA
O código de exemplo define um serviço de IA " deployable_ai_service_f1. Quando uma solicitação da API REST é enviada para o endpoint " /ml/v4/deployments, o " deployable_ai_service_f1 é chamado. A função recebe uma carga útil de entrada JSON e inclui as seguintes funções aninhadas como parte de seu escopo:
generate(): Faz uma chamada da API REST para o ponto de extremidade '/ml/v4/deployments/{id_or_name}/ai_service. Ele recebe um objeto de contexto, extrai o token, os cabeçalhos e o corpo JSON e retorna uma resposta com base na chave de modo no corpo JSON. O formato da resposta pode ser JSON, bytes ou string, com cabeçalhos personalizados opcionais.generate_stream(): Faz uma chamada à API REST para o ponto de extremidade de inferência SSE (Server-Sent Events) '/ml/v4/deployments/{id_or_name}/ai_service_stream. Ele recebe um objeto de contexto, extrai o token, os cabeçalhos e o corpo JSON e retorna um fluxo de eventos SSE marcados por 'eos(Fim do fluxo).generate_batch(): Faz uma chamada da API REST para o ponto de extremidade dos trabalhos '/ml/v4/deployments_jobs. Ele recebe 'input_data_referencese 'output_data_referencedo corpo JSON da solicitação, gera um token de lote e registra as referências de dados de entrada e saída.
def deployable_ai_service_f1(context, params={"k1": "v1"}, **custom):
"""
The outer function handles the REST call to the deployment endpoint
POST /ml/v4/deployments
context.generate_token() - generate a token from the task credentials
To use `generate` and `generate_stream`, the deployment has to be ONLINE
To use `generate_batch`, the deployment has to be BATCH
"""
task_token = context.generate_token()
print(f"outer function: {task_token[-5:]}", flush=True)
def generate(context) -> dict:
"""
The `generate` function handles the REST call to the inference endpoint
POST /ml/v4/deployments/{id_or_name}/ai_service
context.get_token() - get the Bearer token from the header of the request
context.get_json() - get the body of the request
context.get_headers() - get the headers of the request
The generate function should return a dict
The following optional keys are supported currently
- body
- headers
This particular example accepts a json body of the format:
{ "mode" : <value> }
Depending on the <value> of the mode, it will return different response
"""
user_token = context.get_token()
headers = context.get_headers()
json_body = context.get_json()
print(f"my_generate: {user_token=}", flush=True)
print(f"request headers: {headers=}", flush=True)
print(f"json body: {json_body=}", flush=True)
match json_body.get("mode", "no-match"):
case "json":
# response Content-Type is "application/json"
return {
"headers": {
"Content-Type": "application/json",
"User-Defined-Head": "x-genai",
},
"body": {
"user_token": user_token[-5:],
"task_token": task_token[-5:],
"json_body": json_body,
"params": params,
"custom": custom,
},
}
case "json-no-header":
# response Content-Type is "application/json"
return {
"body": {
"user_token": user_token[-5:],
"task_token": task_token[-5:],
"json_body": json_body,
"params": params,
"custom": custom,
},
}
case "json-custom-header":
# response Content-Type is "text/plain; charset=utf-8; test-2"
return {
"headers": {
"Content-Type": "text/plain; charset=utf-8; test-2",
"User-Defined-Head": "x-genai",
},
"body": {
"user_token": user_token[-5:],
"task_token": task_token[-5:],
"json_body": json_body,
"params": params,
"custom": custom,
},
}
case "bytes":
# response Content-Type is "application/octet-stream"
return {
"headers": {
"Content-Type": "application/octet-stream",
"User-Defined-Head": "x-genai",
},
"body": b"12345678910",
}
case "bytes-no-header":
# response Content-Type is 'text/html; charset=utf-8'
return {
"body": b"12345678910",
}
case "bytes-custom-header":
# response Content-Type is "text/plain; charset=utf-8; test-2"
return {
"headers": {
"Content-Type": "text/plain; charset=utf-8; test-2",
"User-Defined-Head": "x-genai",
},
"body": b"12345678910",
}
case "str":
# response Content-Type is "text/plain"
return {
"headers": {
"Content-Type": "text/plain",
"User-Defined-Head": "x-genai",
},
"body": f"Hello WatsonX: {json_body}",
}
case "str-no-header":
# response Content-Type is "text/html; charset=utf-8"
return {
"body": f"Hello WatsonX: {json_body}",
}
case "str-custom-header":
# response Content-Type is "application/octet-stream; charset=utf-8; test-2"
return {
"headers": {
"Content-Type": "application/octet-stream; charset=utf-8; test-2",
"User-Defined-Head": "x-genai",
},
"body": f"Hello WatsonX: {json_body}",
}
case "negative-str-return":
# Bad request
return "Should give 400 bad request"
case _:
# response Content-Type is "text/html; charset=utf-8"
return {"body": "No match"}
def generate_stream(context):
"""
The generate_stream function handles the REST call to the SSE inference endpoint
POST /ml/v4/deployments/{id_or_name}/ai_service_stream
context.get_token() - get the Bearer token from the header of the request
context.get_json() - get the body of the request
context.get_headers() - get the headers of the request
The generate_stream function be a python `generator` with yield
The data in yield will the "data" for the SSE event
Example: The following request json
{ "sse": ["Hello" , "", "WatsonX"," ", "!"]}
will return the following stream of events
--------------
id: 1
event: message
data: Hello
id: 2
event: message
data:
id: 3
event: message
data: WatsonX
id: 4
event: message
data:
id: 5
event: message
data: !
id: 6
event: eos
---------------
The end of the stream will be marked by the event "eos"
"""
user_token = context.get_token()
headers = context.get_headers()
json_body = context.get_json()
print(f"generate_stream: {user_token=}", flush=True)
print(f"generate_stream: {headers=}", flush=True)
print(f"generate_stream: {json_body=}", flush=True)
import time
for x in json_body.get("sse", ["default", "message"]):
time.sleep(1)
yield x
def generate_batch(input_data_references: list[dict], output_data_reference: dict) -> None:
"""
The generate_batch function handles the REST jobs endpoint
POST /ml/v4/deployments_jobs
Arguments to the function are from the json body of the request to jobs
- input_data_references : scoring.input_data_references
- output_data_reference : scoring.output_data_reference
context.generate_token() : can access context object
from outer function scope if token is required
"""
batch_token = context.generate_token()
print(f"batch_token: {batch_token[-5:]}", flush=True)
print(
f"generate_batch:\n{input_data_references=}\n{output_data_reference=}",
flush=True,
)
return generate, generate_stream, generate_batch
Saiba mais
Tópico principal: Implementação de serviços de IA com codificação direta