Desplegar backend com LLM no HuggingFace

Desplegar backend com LLM no HuggingFace Desplegar backend com LLM no HuggingFace

Aviso: Este post foi traduzido para o português usando um modelo de tradução automática. Por favor, me avise se encontrar algum erro.

Neste post, vamos ver como deployar um backend no HuggingFace. Vamos ver como fazer isso de duas maneiras, através da forma comum, criando uma aplicação com Gradio, e através de uma opção diferente usando FastAPI, Langchain e Docker.

Para ambos casos será necessário ter uma conta no HuggingFace, já que vamos implantar o backend em um espaço do HuggingFace.

Desplegar backend com Gradiolink image 75

Criar espaçolink image 76

Primeiro de tudo, criamos um novo espaço na Hugging Face.

  • Colocamos um nome, uma descrição e escolhemos a licença.
  • Escolhemos o Gradio como o tipo de SDK. Ao escolher o Gradio, serão exibidas algumas templates, então escolhemos a template do chatbot.
  • Selecionamos o HW no qual vamos a desdobrar o backend, eu vou escolher a CPU gratuita, mas você escolha o que melhor considerar.
  • E por último, temos que escolher se queremos criar o espaço público ou privado.
backend gradio - criar espaço

Códigolink image 77

Ao criar o space, podemos cloná-lo ou podemos ver os arquivos na própria página do HuggingFace. Podemos ver que foram criados 3 arquivos, app.py, requirements.txt e README.md. Então, vamos ver o que colocar em cada um.

app.pylink image 78

Aqui está o código do aplicativo. Como escolhemos o template de chatbot, já temos muito feito, mas vamos ter que mudar 2 coisas: primeiro, o modelo de linguagem e o system prompt.

Como modelo de linguagem, vejo HuggingFaceH4/zephyr-7b-beta, mas vamos utilizar Qwen/Qwen2.5-72B-Instruct, que é um modelo muito capaz.

Então, procure pelo texto client = InferenceClient("HuggingFaceH4/zephyr-7b-beta") e substitua-o por client = InferenceClient("Qwen/Qwen2.5-72B-Instruct"), ou espere que colocarei todo o código mais tarde.

Também vamos alterar o system prompt, que por padrão é You are a friendly Chatbot., mas como o modelo foi treinado principalmente em inglês, é provável que se você falar com ele em outro idioma, ele responda em inglês. Então, vamos mudá-lo para You are a friendly Chatbot. Always reply in the language in which the user is writing to you..

Então, procure pelo texto gr.Textbox(value="You are a friendly Chatbot.", label="System message"), e substitua-o por gr.Textbox(value="You are a friendly Chatbot. Always reply in the language in which the user is writing to you.", label="System message"),, ou espere até eu colocar todo o código agora.

import gradio as gr
do huggingface_hub import InferenceClient

""""""
Para mais informações sobre o suporte da API de Inferência do `huggingface_hub`, consulte a documentação: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
""""""
client = InferenceClient("Qwen/Qwen2.5-72B-Instruct")


def responder(
mensagem,
história: list[tuple[str, str]],
Mensagem do sistema,
max_tokens,
temperatura,
top_p,
):
mensagens = [{"papel": "sistema", "conteúdo": system_message}]

for val in history:
if val[0]:
messages.append({"role": "user", "content": val[0]})
if val[1]:
messages.append({"role": "assistant", "content": val[1]})

messages.append({"role": "user", "content": message})

response = ""

para mensagem em client.chat_completion(
mensagens,
max_tokens=max_tokens,
stream=True,
temperature=temperature,
top_p=top_p,
):
token = message.choices[0].delta.content

response += token
yield response


""""""
Para informações sobre como personalizar a ChatInterface, consulte a documentação do gradio: https://www.gradio.app/docs/gradio/chatinterface
""""""
demo = gr.ChatInterface(
responda,

markdown

additional_inputs=[

gr.Textbox(value="Você é um chatbot amigável. Sempre responda na língua em que o usuário está escrevendo para você.", label="Mensagem do sistema"),
gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Máximo de novos tokens"),
gr.Slider(mínimo=0,1, máximo=4,0, valor=0,7, passo=0,1, rótulo="Temperatura"),
gr.Slider(
mínimo=0.1,
máximo=1.0,
value=0.95,
passo=0.05,
label="Top-p (amostragem do núcleo)"
),
],
)


if __name__ == "__main__":
demo.launch()

requirements.txtlink image 79

Este é o arquivo onde serão escritas as dependências, mas para este caso vai ser muito simples:

huggingface_hub==0.25.2

LEIA-ME.mdlink image 80

Este é o arquivo no qual vamos colocar as informações do espaço. Nos spaces da HuggingFace, no início dos readmes, coloca-se um código para que a HuggingFace saiba como exibir a miniatura do espaço, qual arquivo deve ser usado para executar o código, versão do sdk, etc.

---
título: SmolLM2
emoji: 💬
colorFrom: amarelo
colorTo: roxo
sdk: gradio
sdk_version: 5.0.1
app_file: app.py
pinned: false
licença: apache-2.0
short_description: Bate-papo com o Gradio SmolLM2
---

Um exemplo de chatbot usando [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index) e a [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).

Implantaçãolink image 81

Se nós clonamos o espaço, temos que fazer um commit e um push. Se modificamos os arquivos no HuggingFace, basta salvá-los.

Então, quando as alterações estiverem no HuggingFace, teremos que esperar alguns segundos para que o espaço seja construído e possamos usá-lo.

backend gradio - chatbot

Backendlink image 82

Muito bem, fizemos um chatbot, mas não era essa a intenção, aqui tínhamos vindo fazer um backend! Pára, pára, olha o que diz abaixo do chatbot

backend gradio - Use via API

Podemos ver um texto Use via API, onde se clicarmos, se abrirá um menu com uma API para poder usar o chatbot.

backend gradio - API

Vemos que nos dá uma documentação de como usar a API, tanto com Python, com JavaScript, quanto com bash.

Teste da APIlink image 83

Usamos o código de exemplo de Python.

	
from gradio_client import Client
client = Client("Maximofn/SmolLM2")
result = client.predict(
message="Hola, ¿cómo estás? Me llamo Máximo",
system_message="You are a friendly Chatbot. Always reply in the language in which the user is writing to you.",
max_tokens=512,
temperature=0.7,
top_p=0.95,
api_name="/chat"
)
print(result)
Copy
	
Loaded as API: https://maximofn-smollm2.hf.space ✔
¡Hola Máximo! Mucho gusto, estoy bien, gracias por preguntar. ¿Cómo estás tú? ¿En qué puedo ayudarte hoy?

Estamos fazendo chamadas à API do InferenceClient da HuggingFace, então poderíamos pensar, Para que fizemos um backend, se podemos chamar diretamente a API da HuggingFace? Bem, você vai ver isso abaixo.

	
result = client.predict(
message="¿Cómo me llamo?",
system_message="You are a friendly Chatbot. Always reply in the language in which the user is writing to you.",
max_tokens=512,
temperature=0.7,
top_p=0.95,
api_name="/chat"
)
print(result)
Copy
	
Tu nombre es Máximo. ¿Es correcto?

O modelo de bate-papo do Gradio gerencia o histórico para nós, de forma que cada vez que criamos um novo cliente, uma nova thread de conversa é criada.

Vamos a tentar criar um novo cliente e ver se uma nova thread de conversa é criada.

	
from gradio_client import Client
new_client = Client("Maximofn/SmolLM2")
result = new_client.predict(
message="Hola, ¿cómo estás? Me llamo Luis",
system_message="You are a friendly Chatbot. Always reply in the language in which the user is writing to you.",
max_tokens=512,
temperature=0.7,
top_p=0.95,
api_name="/chat"
)
print(result)
Copy
	
Loaded as API: https://maximofn-smollm2.hf.space ✔
Hola Luis, estoy muy bien, gracias por preguntar. ¿Cómo estás tú? Es un gusto conocerte. ¿En qué puedo ayudarte hoy?

Agora vamos perguntar novamente como me chamo

	
result = new_client.predict(
message="¿Cómo me llamo?",
system_message="You are a friendly Chatbot. Always reply in the language in which the user is writing to you.",
max_tokens=512,
temperature=0.7,
top_p=0.95,
api_name="/chat"
)
print(result)
Copy
	
Te llamas Luis. ¿Hay algo más en lo que pueda ayudarte?

Como podemos ver, temos dois clientes, cada um com seu próprio fio de conversa.

Deploy do backend com FastAPI, Langchain e Dockerlink image 84

Agora vamos a fazer o mesmo, criar um backend de um chatbot, com o mesmo modelo, mas nesse caso usando FastAPI, Langchain e Docker.

Criar espaçolink image 85

Temos que criar um novo espaço, mas nesse caso faremos de outra maneira

  • Colocamos um nome, uma descrição e escolhemos a licença.
  • Escolhemos Docker como o tipo de SDK. Ao escolher Docker, aparecerão modelos, então escolhemos um modelo em branco.
  • Selecionamos o HW no qual vamos a desdobrar o backend, eu vou escolher a CPU gratuita, mas você escolha o que melhor considerar.
  • E por fim, é preciso escolher se queremos criar o espaço público ou privado.
backend docker - criar espaço

Códigolink image 86

Agora, ao criar o space, vemos que temos apenas um arquivo, o README.md. Então vamos ter que criar todo o código nós mesmos.

app.pylink image 87

Vamos a criar o código do aplicativo

Começamos com as bibliotecas necessárias

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
do huggingface_hub import InferenceClient

markdown

from langchain_core.messages import HumanMessage, AIMessage

from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph

import os
from dotenv import load_dotenv
load_dotenv()

Carregamos fastapi para poder criar as rotas da API, pydantic para criar o template das queries, huggingface_hub para poder criar um modelo de linguagem, langchain para indicar ao modelo se as mensagens são do chatbot ou do usuário e langgraph para criar o chatbot.

Além disso, carregamos os e dotenv para poder carregar as variáveis de ambiente.

Carregamos o token do HuggingFace

# Token da HuggingFace
HUGGINGFACE_TOKEN = os.environ.get("HUGGINGFACE_TOKEN", os.getenv("HUGGINGFACE_TOKEN"))

Criamos o modelo de linguagem

# Inicializar o modelo da HuggingFace
model = InferenceClient(
model="Qwen/Qwen2.5-72B-Instruct",
api_key=os.getenv("HUGGINGFACE_TOKEN")
)

Criamos agora uma função para chamar o modelo

# Define the function that calls the model
def call_model(state: MessagesState):
"""
Call the model with the given messages

Args:
state: MessagesState

Returns:
dict: A dictionary containing the generated text and the thread ID
"""
# Convert LangChain messages to HuggingFace format
hf_messages = []
for msg in state["messages"]:
if isinstance(msg, HumanMessage):
hf_messages.append({"role": "user", "content": msg.content})
elif isinstance(msg, AIMessage):
hf_messages.append({"role": "assistant", "content": msg.content})

# Call the API
response = model.chat_completion(
messages=hf_messages,
temperature=0.5,
max_tokens=64,
top_p=0.7
)

# Convert the response to LangChain format
ai_message = AIMessage(content=response.choices[0].message.content)
return {"messages": state["messages"] + [ai_message]}

Convertemos as mensagens do formato LangChain para o formato HuggingFace, assim podemos usar o modelo de linguagem.

Definimos uma template para as queries

class QueryRequest(BaseModel):
query: str
thread_id: str = "padrão"

As consultas terão um query, a mensagem do usuário, e um thread_id, que é o identificador do fio da conversação e mais adiante explicaremos para que o utilizamos.

Criamos um grafo de LangGraph

# Definir o gráfico
workflow = StateGraph(state_schema=MessagesState)

# Defina o nódo na gráfico
workflow.add_edge(START, "model")
workflow.add_node("modelo", call_model)

# Adicionar memória
memory = MemorySaver()
graph_app = workflow.compile(checkpointer=memory)

Com isso, criamos um grafo de LangGraph, que é uma estrutura de dados que nos permite criar um chatbot e gerenciar o estado do chatbot para nós, ou seja, entre outras coisas, o histórico de mensagens. Dessa forma, não precisamos fazer isso nós mesmos.

Criamos a aplicação de FastAPI

app = FastAPI(title="LangChain FastAPI", description="API para gerar texto usando LangChain e LangGraph")

Criamos os endpoints da API

# Ponto de entrada Bem-vindo
@app.get("/")
async def api_home():
"""Ponto de entrada Welcome"""
return {"detail": "Bem-vindo ao tutorial de FastAPI, Langchain, Docker"}

# Gerar ponto final
@app.post("/generate")
async def gerar(request: QueryRequest):
""""""
Ponto final para gerar texto usando o modelo de linguagem

Argumentos:
solicitação: QueryRequest
query: str
thread_id: str = "padrão"

Retorna:
um dicionário contendo o texto gerado e o ID do thread
""""""
tente:
# Configurar o ID da thread
config = {"configurable": {"thread_id": request.thread_id}}

# Crie a mensagem de entrada
input_messages = [HumanMessage(content=request.query)]

# Invocar o gráfico
output = graph_app.invoke({"messages": input_messages}, config)

# Obter a resposta do modelo
resposta = output["messages"][-1].conteúdo

return {
"generated_text": resposta,
"thread_id": request.thread_id
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Erro ao gerar texto: {str(e)}")

Criamos o endpoint / que nos retornará um texto quando acessarmos a API, e o endpoint /generate que é o que usaremos para gerar o texto.

Se nós olharmos para a função generate, temos a variável config, que é um dicionário que contém o thread_id. Este thread_id é o que nos permite ter um histórico de mensagens de cada usuário, desta forma, diferentes usuários podem usar o mesmo endpoint e ter seu próprio histórico de mensagens.

Por último, temos o código para que se possa executar a aplicação

if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)

Vamos escrever todo o código juntos

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from huggingface_hub import InferenceClient

from langchain_core.messages import HumanMessage, AIMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph

import os
from dotenv import load_dotenv
load_dotenv()

# HuggingFace token
HUGGINGFACE_TOKEN = os.environ.get("HUGGINGFACE_TOKEN", os.getenv("HUGGINGFACE_TOKEN"))

# Initialize the HuggingFace model
model = InferenceClient(
model="Qwen/Qwen2.5-72B-Instruct",
api_key=os.getenv("HUGGINGFACE_TOKEN")
)

# Define the function that calls the model
def call_model(state: MessagesState):
"""
Call the model with the given messages

Args:
state: MessagesState

Returns:
dict: A dictionary containing the generated text and the thread ID
"""
# Convert LangChain messages to HuggingFace format
hf_messages = []
for msg in state["messages"]:
if isinstance(msg, HumanMessage):
hf_messages.append({"role": "user", "content": msg.content})
elif isinstance(msg, AIMessage):
hf_messages.append({"role": "assistant", "content": msg.content})

# Call the API
response = model.chat_completion(
messages=hf_messages,
temperature=0.5,
max_tokens=64,
top_p=0.7
)

# Convert the response to LangChain format
ai_message = AIMessage(content=response.choices[0].message.content)
return {"messages": state["messages"] + [ai_message]}

# Define the graph
workflow = StateGraph(state_schema=MessagesState)

# Define the node in the graph
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)

# Add memory
memory = MemorySaver()
graph_app = workflow.compile(checkpointer=memory)

# Define the data model for the request
class QueryRequest(BaseModel):
query: str
thread_id: str = "default"

# Create the FastAPI application
app = FastAPI(title="LangChain FastAPI", description="API to generate text using LangChain and LangGraph")

# Welcome endpoint
@app.get("/")
async def api_home():
"""Welcome endpoint"""
return {"detail": "Welcome to FastAPI, Langchain, Docker tutorial"}

# Generate endpoint
@app.post("/generate")
async def generate(request: QueryRequest):
"""
Endpoint to generate text using the language model

Args:
request: QueryRequest
query: str
thread_id: str = "default"

Returns:
dict: A dictionary containing the generated text and the thread ID
"""
try:
# Configure the thread ID
config = {"configurable": {"thread_id": request.thread_id}}

# Create the input message
input_messages = [HumanMessage(content=request.query)]

# Invoke the graph
output = graph_app.invoke({"messages": input_messages}, config)

# Get the model response
response = output["messages"][-1].content

return {
"generated_text": response,
"thread_id": request.thread_id
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error al generar texto: {str(e)}")

if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)

Dockerfilelink image 88

Agora vemos como criar o Dockerfile

Primeiro indicamos a partir de qual imagem vamos começar

FROM python:3.13-slim

Agora criamos o diretório de trabalho

RUN useradd -m -u 1000 user
WORKDIR /app

Copiamos o arquivo com as dependências e instalamos

COPY --chown=user ./requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt

Copiamos o resto do código

COPY --chown=user . /app

Exponhamos o porto 7860

EXPOSE 7860

Criamos as variáveis de ambiente

RUN --mount=type=secret,id=HUGGINGFACE_TOKEN,mode=0444,required=true \
test -f /run/secrets/HUGGINGFACE_TOKEN && echo "Segredo existe!"

Por último, indicamos o comando para executar a aplicação

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]

Agora colocamos tudo junto

FROM python:3.13-slim

RUN useradd -m -u 1000 user
WORKDIR /app

COPY --chown=user ./requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt

COPY --chown=user . /app

EXPOSE 7860

RUN --mount=type=secret,id=HUGGINGFACE_TOKEN,mode=0444,required=true \
test -f /run/secrets/HUGGINGFACE_TOKEN && echo "Segredo existe!"

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]

requirements.txtlink image 89

Criamos o arquivo com as dependências

fastapi
uvicorn
pedidos
pydantic>=2.0.0
langchain
langchain-huggingface
langchain-core
langgraph > 0.2.27
python-dotenv.2.11

README.mdlink image 90

Por fim, criamos o arquivo README.md com informações sobre o espaço e as instruções para o HuggingFace.


      ---
      title: SmolLM2 Backend
      emoji: 📊
      colorFrom: yellow
      colorTo: red
      sdk: docker
      pinned: false
      license: apache-2.0
      short_description: Backend of SmolLM2 chat
      app_port: 7860
      ---
      
      # SmolLM2 Backend
      
      This project implements a FastAPI API that uses LangChain and LangGraph to generate text with the Qwen2.5-72B-Instruct model from HuggingFace.
      
      ## Configuration
      
      ### In HuggingFace Spaces
      
      This project is designed to run in HuggingFace Spaces. To configure it:
      
      1. Create a new Space in HuggingFace with SDK Docker
      2. Configure the `HUGGINGFACE_TOKEN` or `HF_TOKEN` environment variable in the Space configuration:
         - Go to the "Settings" tab of your Space
         - Scroll down to the "Repository secrets" section
         - Add a new variable with the name `HUGGINGFACE_TOKEN` and your token as the value
         - Save the changes
      
      ### Local development
      
      For local development:
      
      1. Clone this repository
      2. Create a `.env` file in the project root with your HuggingFace token:
         ```
         HUGGINGFACE_TOKEN=your_token_here
         ```
      3. Install the dependencies:
         ```
         pip install -r requirements.txt
         ```
      
      ## Local execution
      
      ```bash
      uvicorn app:app --reload
      ```
      
      The API will be available at `http://localhost:8000`.
      
      ## Endpoints
      
      ### GET `/`
      
      Welcome endpoint that returns a greeting message.
      
      ### POST `/generate`
      
      Endpoint to generate text using the language model.
      
      **Request parameters:**
      ```json
      {
        "query": "Your question here",
        "thread_id": "optional_thread_identifier"
      }
      ```
      
      **Response:**
      ```json
      {
        "generated_text": "Generated text by the model",
        "thread_id": "thread identifier"
      }
      ```
      
      ## Docker
      
      To run the application in a Docker container:
      
      ```bash
      # Build the image
      docker build -t smollm2-backend .
      
      # Run the container
      docker run -p 8000:8000 --env-file .env smollm2-backend
      ```
      
      ## API documentation
      
      The interactive API documentation is available at:
      - Swagger UI: `http://localhost:8000/docs`
      - ReDoc: `http://localhost:8000/redoc`

Token do HuggingFacelink image 91

Se você notou no código e no Dockerfile, usamos um token do HuggingFace, então vamos ter que criar um. Em nossa conta do HuggingFace, criamos um novo token, damos um nome a ele e concedemos as seguintes permissões:

  • Acesso de leitura aos conteúdos de todos os repositórios sob o seu namespace pessoal
  • Acesso de leitura aos conteúdos de todos os repositórios sob seu namespace pessoal
  • Fazer chamadas para provedores de inferência
  • Fazer chamadas para Pontos de Extremidade de Inferência
backend docker - token

Adicionar o token aos secrets do espaçolink image 92

Agora que já temos o token, precisamos adicioná-lo ao espaço. Na parte superior do aplicativo, poderemos ver um botão chamado Settings, clicamos nele e poderemos ver a seção de configuração do espaço.

Se formos para baixo, poderemos ver uma seção onde podemos adicionar Variables e Secrets. Neste caso, como estamos adicionando um token, vamos adicioná-lo aos Secrets.

Damos o nome HUGGINGFACE_TOKEN e o valor do token.

Implantaçãolink image 93

Se nós clonamos o espaço, temos que fazer um commit e um push. Se modificamos os arquivos no HuggingFace, basta salvá-los.

Então, quando as alterações estiverem no HuggingFace, teremos que esperar alguns segundos para que o espaço seja construído e possamos usá-lo.

Neste caso, construímos apenas um backend, portanto o que vamos ver ao entrar no espaço é o que definimos no endpoint /

backend docker - espaço

URL do backendlink image 94

Precisamos saber a URL do backend para poder fazer chamadas à API. Para isso, temos que clicar nos três pontos no canto superior direito para ver as opções.

backend docker - opções

No menu suspenso, clicamos em Embed this Spade. Será aberta uma janela indicando como incorporar o espaço com um iframe e também fornecerá a URL do espaço.

backend docker - embed

Se agora formos para essa URL, veremos o mesmo que no espaço.

Documentaçãolink image 95

FastAPI, além de ser uma API extremamente rápida, tem outra grande vantagem: gera documentação automaticamente.

Se adicionarmos /docs à URL que vimos anteriormente, poderemos visualizar a documentação da API com o Swagger UI.

backend docker - swagger doc

Também podemos adicionar /redoc à URL para ver a documentação com ReDoc.

backend docker - redoc doc

Teste da APIlink image 96

O bom da documentação Swagger UI é que nos permite testar a API diretamente do navegador.

Adicionamos /docs à URL que obtivemos, abrimos o menu suspenso do endpoint /generate e clicamos em Try it out, modificamos o valor da query e do thread_id e clicamos em Execute.

No primeiro caso vou colocar

  • query: Olá, como você está? Sou Máximo
  • thread_id: user1
backend docker - test API

Recebemos a seguinte resposta Olá Máximo! Estou muito bem, obrigado por perguntar. Como você está? Em que posso ajudar hoje?

backend docker -response 1 - user1

Vamos testar agora a mesma pergunta, mas com um thread_id diferente, neste caso user2.

backend docker - query 1 - user2

E nos responde isso Olá Luis! Estou muito bem, obrigado por perguntar. Como você está? No que posso ajudar hoje?

backend docker - response 1 - user2

Agora pedimos nosso nome com os dois usuários e obtemos isso

  • Para o usuário user1: Você se chama Máximo. Há algo mais em que eu possa ajudar você?
  • Para o usuário user2: Você se chama Luis. Há mais alguma coisa em que eu possa ajudá-lo hoje, Luis?
backend docker - response 2 - user1 backend docker - response 2 - user2

Deploy do backend com Gradio e modelo rodando no servidorlink image 97

Os dois backends que criamos na verdade não estão executando um modelo, mas sim fazendo chamadas para Inference Endpoints da HuggingFace. Mas pode ser que queiramos que tudo rode no servidor, inclusive o modelo. Pode ser que você tenha feito um fine-tuning de um LLM para seu caso de uso, por isso já não pode fazer chamadas para Inference Endpoints.

Então vamos ver como modificar o código dos dois backends para executar um modelo no servidor e não fazer chamadas para Inference Endpoints.

Criar Espaçolink image 98

Na hora de criar o space no HuggingFace fazemos o mesmo que antes, criamos um novo space, colocamos um nome e uma descrição, selecionamos Gradio como SDK, selecionamos o HW em que vamos deployar, no meu caso selecionei o HW mais básico e gratuito, e selecionamos se o faremos privado ou público.

Códigolink image 99

Temos que fazer alterações em app.py e em requirements.txt para que, em vez de fazer chamadas a Inference Endpoints, o modelo seja executado localmente.

app.pylink image 100

As mudanças que temos que fazer são

Importar AutoModelForCausalLM e AutoTokenizer da biblioteca transformers e importar torch

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

Em vez de criar um modelo com InferenceClient, criamos com AutoModelForCausalLM e AutoTokenizer.

# Carregar o modelo e o tokenizer
model_name = "HuggingFaceTB/SmolLM2-1.7B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
nome_do_modelo,
torch_dtype=torch.float16,
device_map="auto"
)

Utilizo HuggingFaceTB/SmolLM2-1.7B-Instruct porque é um modelo bastante capaz com apenas 1.7B de parâmetros. Como escolhi o hardware mais básico, não posso usar modelos muito grandes. Você, se quiser usar um modelo maior, tem duas opções: usar o hardware gratuito e aceitar que a inferência será mais lenta, ou usar um hardware mais potente, mas pago.

Modificar a função respond para que construa o prompt com a estrutura necessária pela biblioteca transformers, tokenizar o prompt, fazer a inferência e destokenizar a resposta.

def responder(
mensagem,
histórico: list[tuple[str, str]],
Mensagem do sistema,
max_tokens,
temperatura,
top_p,
):
# Construir o prompt com o formato correto
prompt = f"<|system|>\n{system_message}</s>\n"

for val in history:
if val[0]:
prompt += f"<|user|>\n{val[0]}</s>\n"
if val[1]:
prompt += f"<|assistant|>\n{val[1]}</s>\n"

prompt += f"<|user|>\n{message}</s>\n<|assistant|>\n"

# Tokenizar o prompt
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

# Gerar a resposta
outputs = model.generate(
**entradas,**
max_new_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)

# Decodificar a resposta
response = tokenizer.decode(outputs[0], skip_special_tokens=True)

# Extrair apenas a parte da resposta do assistente
response = response.split("<|assistant|>\n")[-1].strip()

yield response

A seguir deixo todo o código

import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

""""""
Para mais informações sobre o suporte à API de Inferência do `huggingface_hub`, consulte a documentação: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
""""""

# Carregar o modelo e o tokenizer
model_name = "HuggingFaceTB/SmolLM2-1.7B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
nome_do_modelo,
torch_dtype=torch.float16,
device_map="auto"
)

def responder(
mensagem,
história: list[tuple[str, str]],
Mensagem do sistema,
max_tokens,
temperatura,
top_p,
):
# Construir o prompt com o formato correto
prompt = f"<|system|>\n{system_message}</s>\n"

for val in history:
if val[0]:
prompt += f"<|user|>\n{val[0]}</s>\n"
if val[1]:
prompt += f"<|assistant|>\n{val[1]}</s>\n"

prompt += f"<|user|>\n{message}</s>\n<|assistant|>\n"

# Tokenizar o prompt
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

# Gerar a resposta
saídas = modelo.gerar(
**entradas,**
max_new_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)

# Decodificar a resposta
response = tokenizer.decode(outputs[0], skip_special_tokens=True)

# Extrair apenas a parte da resposta do assistente
response = response.split("<|assistant|>\n")[-1].strip()

yield response


""""""
Para informações sobre como personalizar o ChatInterface, consulte a documentação do Gradio: https://www.gradio.app/docs/gradio/chatinterface
""""""
demo = gr.ChatInterface(
responda,

markdown

additional_inputs=[

gr.Textbox(
value="Você é um Chatbot amigável. Sempre responda na língua em que o usuário está escrevendo para você."
rótulo="Mensagem do sistema"
),
gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Máximo de novos tokens"),
gr.Slider(mínimo=0,1, máximo=4,0, valor=0,7, passo=0,1, rótulo="Temperatura"),
gr.Slider()
mínimo=0.1,
máximo=1.0,
value=0.95,
passo=0.05,
label="Top-p (amostragem do núcleo)"
),
],
)


if __name__ == "__main__":
demo.launch()

requirements.txtlink image 101

Neste arquivo, devemos adicionar as novas bibliotecas que vamos utilizar, neste caso transformers, accelerate e torch. O arquivo completo ficaria:

huggingface_hub==0.25.2
gradio>=4.0.0
transformers>=4.36.0
torch>=2.0.0
accelerate>=0.25.0

Teste da APIlink image 102

Desplegamos o space e testamos diretamente a API.

	
from gradio_client import Client
client = Client("Maximofn/SmolLM2_localModel")
result = client.predict(
message="Hola, ¿cómo estás? Me llamo Máximo",
system_message="You are a friendly Chatbot. Always reply in the language in which the user is writing to you.",
max_tokens=512,
temperature=0.7,
top_p=0.95,
api_name="/chat"
)
print(result)
Copy
	
Loaded as API: https://maximofn-smollm2-localmodel.hf.space ✔
Hola Máximo, soy su Chatbot amable y estoy funcionando bien. Gracias por tu mensaje, me complace ayudarte hoy en día. ¿Cómo puedo servirte?

Surpreende-me o quão rápido o modelo responde, mesmo estando em um servidor sem GPU.

Deploy de backend com FastAPI, Langchain e Docker e modelo rodando no servidorlink image 103

Agora fazemos o mesmo que antes, mas com FastAPI, LangChain e Docker.

Criar Espaçolink image 104

Ao criar o space no HuggingFace, fazemos o mesmo que antes: criamos um novo espaço, colocamos um nome e uma descrição, selecionamos Docker como SDK, escolhemos o HW em que vamos implantá-lo, no meu caso, escolho o HW mais básico e gratuito, e decidimos se o faremos privado ou público.

Códigolink image 105

app.pylink image 106

Já não importamos InferenceClient e agora importamos AutoModelForCausalLM e AutoTokenizer da biblioteca transformers e importamos torch.

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

Instanciamos o modelo e o tokenizer com AutoModelForCausalLM e AutoTokenizer.

# Inicialize o modelo e o tokenizador
print("Carregando modelo e tokenizer...")
dispositivo = "cuda" if torch.cuda.is_available() else "cpu"
model_name = "HuggingFaceTB/SmolLM2-1.7B-Instruct"

tente:
# Carregar o modelo no formato BF16 para melhor desempenho e menor uso de memória
tokenizer = AutoTokenizer.from_pretrained(model_name)

if device == "cuda":
print("Usando GPU para o modelo...")
model = AutoModelForCausalLM.from_pretrained(
nome_do_modelo,
torch_dtype=torch.bfloat16,
device_map="auto",
low_cpu_mem_usage=True
)
else:
print("Usando CPU para o modelo...")
model = AutoModelForCausalLM.from_pretrained(
nome_do_modelo,
device_map={"": device},
torch_dtype=torch.float32
)

print(f"Modelo carregado com sucesso em: {device}")
except Exception as e:
print(f"Erro ao carregar o modelo: {str(e)}")
aumentar

Re definimos a função call_model para que faça a inferência com o modelo local.

# Define the function that calls the model
def call_model(state: MessagesState):
"""
Call the model with the given messages

Args:
state: MessagesState

Returns:
dict: A dictionary containing the generated text and the thread ID
"""
# Convert LangChain messages to chat format
messages = []
for msg in state["messages"]:
if isinstance(msg, HumanMessage):
messages.append({"role": "user", "content": msg.content})
elif isinstance(msg, AIMessage):
messages.append({"role": "assistant", "content": msg.content})

# Prepare the input using the chat template
input_text = tokenizer.apply_chat_template(messages, tokenize=False)
inputs = tokenizer.encode(input_text, return_tensors="pt").to(device)

# Generate response
outputs = model.generate(
inputs,
max_new_tokens=512, # Increase the number of tokens for longer responses
temperature=0.7,
top_p=0.9,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)

# Decode and clean the response
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# Extract only the assistant's response (after the last user message)
response = response.split("Assistant:")[-1].strip()

# Convert the response to LangChain format
ai_message = AIMessage(content=response)
return {"messages": state["messages"] + [ai_message]}

requirements.txtlink image 107

Temos que remover langchain-huggingface e adicionar transformers, accelerate e torch no arquivo requirements.txt. O arquivo ficaria:

fastapi
uvicorn
solicitações
pydantic>=2.0.0
langchain>=0.1.0
langchain-core>=0.1.10
langgraph>=0.2.27
python-dotenv>=1.0.0
transformers>=4.36.0
torch>=2.0.0
accelerate>=0.26.0

Dockerfilelink image 108

Já não precisamos ter RUN --mount=type=secret,id=HUGGINGFACE_TOKEN,mode=0444,required=true porque como o modelo vai estar no servidor e não vamos fazer chamadas para Inference Endpoints, não precisamos do token. O arquivo ficaria:

FROM python:3.13-slim

RUN useradd -m -u 1000 user
WORKDIR /app

COPY --chown=user ./requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt

COPY --chown=user . /app

EXPOSE 7860

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]

Teste da APIlink image 109

Deployamos o space e testamos a API. Neste caso, vou testar diretamente do Python.

	
import requests
url = "https://maximofn-smollm2-backend-localmodel.hf.space/generate"
data = {
"query": "Hola, ¿cómo estás?",
"thread_id": "user1"
}
response = requests.post(url, json=data)
if response.status_code == 200:
result = response.json()
print("Respuesta:", result["generated_text"])
print("Thread ID:", result["thread_id"])
else:
print("Error:", response.status_code, response.text)
Copy
	
Respuesta: system
You are a friendly Chatbot. Always reply in the language in which the user is writing to you.
user
Hola, ¿cómo estás?
assistant
Estoy bien, gracias por preguntar. Estoy muy emocionado de la semana que viene.
Thread ID: user1

Este demora um pouco mais que o anterior. Na verdade, demora o normal para um modelo sendo executado em um servidor sem GPU. O estranho é quando o deployamos no Gradio. Não sei o que a HuggingFace faz por trás, ou talvez tenha sido coincidência.

Conclusõeslink image 110

Vimos como criar um backend com um LLM, tanto fazendo chamadas ao Inference Endpoint da HuggingFace, quanto fazendo chamadas a um modelo rodando localmente. Vimos como fazer isso com Gradio ou com FastAPI, Langchain e Docker.

A partir daqui você tem o conhecimento para poder implantar seus próprios modelos, mesmo que não sejam LLMs, podem ser modelos multimodais. A partir daqui você pode fazer o que quiser.

Continuar lendo

MCP Durabilidade: Servidor e Cliente com Persistência para Tarefas de Longa Duração

MCP Durabilidade: Servidor e Cliente com Persistência para Tarefas de Longa Duração

Aprenda a construir servidor e cliente MCP com durabilidade para tarefas de longa duração. Tutorial completo do Model Context Protocol com persistência de dados usando SQLite, gerenciamento de tarefas em background e monitoramento em tempo real. Implemente migração de dados, processamento em lote e treinamento de modelos ML que sobrevivem a reinicializações do servidor. Código Python com FastMCP, recursos, ferramentas e padrões de durabilidade para aplicações enterprise.

Stream Informações em MCP: Guia Completo para Atualizações de Progresso em Tempo Real com FastMCP

Stream Informações em MCP: Guia Completo para Atualizações de Progresso em Tempo Real com FastMCP

Aprenda como implementar streaming em tempo real em aplicações MCP (Model Context Protocol) usando FastMCP. Este guia abrangente mostra como criar servidores e clientes MCP que suportam atualizações de progresso e informações streaming para tarefas de longa duração. Você construirá ferramentas habilitadas para streaming que fornecem feedback em tempo real durante processamento de dados, upload de arquivos, tarefas de monitoramento e outras operações que demandam muito tempo. Descubra como usar StreamableHttpTransport, implementar manipuladores de progresso com Context e criar barras de progresso visuais que melhoram a experiência do usuário ao trabalhar com aplicações MCP que requerem feedback contínuo.

Últimos posts -->

Você viu esses projetos?

Horeca chatbot

Horeca chatbot Horeca chatbot
Python
LangChain
PostgreSQL
PGVector
React
Kubernetes
Docker
GitHub Actions

Chatbot conversacional para cozinheiros de hotéis e restaurantes. Um cozinheiro, gerente de cozinha ou serviço de quarto de um hotel ou restaurante pode falar com o chatbot para obter informações sobre receitas e menus. Mas também implementa agentes, com os quais pode editar ou criar novas receitas ou menus

Naviground

Naviground Naviground

Subtify

Subtify Subtify
Python
Whisper
Spaces

Gerador de legendas para vídeos no idioma que você desejar. Além disso, coloca uma legenda de cor diferente para cada pessoa

Ver todos os projetos -->

Quer aplicar IA no seu projeto? Entre em contato!

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Flow edit

Flow edit Flow edit

Edite imagens com este modelo de Flow. Baseado em SD3 ou FLUX, você pode editar qualquer imagem e gerar novas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos os contêineres -->

Quer aplicar IA no seu projeto? Entre em contato!

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

Dataset com piadas em inglês

opus100

Dataset com traduções de inglês para espanhol

netflix_titles

Dataset com filmes e séries da Netflix

Ver mais datasets -->