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 Gradio
Criar espaço
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.

Código
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.py
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.txt
Este é o arquivo onde serão escritas as dependências, mas para este caso vai ser muito simples:
``` txt
huggingface_hub==0.25.2```
LEIA-ME.md
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ção
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
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

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

Vemos que nos dá uma documentação de como usar a API, tanto com Python, com JavaScript, quanto com bash.
Teste da API
Usamos o código de exemplo de Python.
from gradio_client import Clientclient = 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)
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)
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 Clientnew_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)
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)
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 Docker
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ço
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.

Código
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.py
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 osfrom 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
# Defina a função que chama o modelo
def chamar_modelo(estado: MessagesState):
""""""
Chame o modelo com as mensagens fornecidas
Argumentos:
estado: EstadoMensagens
Retorna:
um dicionário contendo o texto gerado e o ID do thread
""""""
# Converter mensagens do LangChain para o formato do HuggingFace
hf_messages = []
for msg in state["messages"]:
Se `isinstance(msg, HumanMessage)`:
hf_messages.append({"role": "user", "content": msg.content})
elif isinstance(msg, AIMessage):
hf_messages.append({"role": "assistant", "content": msg.content})
# Chamar a API
resposta = modelo.completar_chat(
mensagens=hf_mensagens,
temperature=0.5,
max_tokens=64,
top_p=0,7
)
# Converter a resposta para o formato LangChain
python
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
``` python
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
``` python
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 uvicornuvicorn.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
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()
# Token da HuggingFace
HUGGINGFACE_TOKEN = os.environ.get("HUGGINGFACE_TOKEN", os.getenv("HUGGINGFACE_TOKEN"))
# Inicialize o modelo do HuggingFace
model = InferenceClient(
model="Qwen/Qwen2.5-72B-Instruct",
api_key=os.getenv("HUGGINGFACE_TOKEN")
)
# Defina a função que chama o modelo
def chamar_modelo(estado: EstadoMensagens):
""""""
Chame o modelo com as mensagens fornecidas
Argumentos:
estado: MensagensState
Retorna:
um dicionário contendo o texto gerado e o ID do thread
""""""
# Converter mensagens do LangChain para o formato do HuggingFace
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})
# Chame a API
resposta = modelo.completar_chat(
mensagens=hf_mensagens,
temperature=0.5,
max_tokens=64,
top_p=0,7
)
# Converter a resposta para o formato LangChain
markdown
ai_message = AIMessage(content=response.choices[0].message.content)
return {"messages": state["messages"] + [ai_message]}
# Definir o gráfico
workflow = StateGraph(state_schema=MessagesState)
# Defina o nó no grafo
workflow.add_edge(START, "model")
workflow.add_node("modelo", call_model)
# Adicionar memória
memory = MemorySaver()
graph_app = workflow.compile(checkpointer=memory)
# Defina o modelo de dados para o pedidoclass QueryRequest(BaseModel):
query: str
thread_id: str = "padrão"
# Criar a aplicação FastAPI
app = FastAPI(title="LangChain FastAPI", description="API para gerar texto usando LangChain e LangGraph")
# Ponto de entrada Bem-vindo
@app.get("/")
async def api_home():
"""Ponto de entrada Welcome"""
return {"detalhe": "Bem-vindo ao tutorial de FastAPI, Langchain, Docker"}
# Gerar ponto final
@app.post("/gerar")
async def generate(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 fio
"""
tente:
# Configurar o ID da thread
config = {"configurable": {"thread_id": request.thread_id}}
# Criar 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)}")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)
Dockerfile
Agora vemos como criar o Dockerfile
Primeiro indicamos a partir de qual imagem vamos começar
``` dockerfile
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
``` dockerfile
COPY --chown=user . /app```
Exponhamos o porto 7860
``` dockerfile
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
``` dockerfile
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.txt
Criamos o arquivo com as dependências
fastapi
uvicorn
pedidos
pydantic>=2.0.0
langchainlangchain-huggingface
langchain-core
langgraph > 0.2.27
python-dotenv.2.11
README.md
Por fim, criamos o arquivo README.md com informações sobre o espaço e as instruções para o HuggingFace.
---
título: Backend do SmolLM2
emoji: 📊
colorFrom: amarelo
colorTo: vermelho
sdk: docker
pinned: false
licença: apache-2.0
short_description: Backend do chat SmolLM2
app_port: 7860
---
# Backend do SmolLM2
Este projeto implementa uma API FastAPI que usa LangChain e LangGraph para gerar texto com o modelo Qwen2.5-72B-Instruct do HuggingFace.
## Configuração
### No HuggingFace Spaces
Este projeto está projetado para ser executado em HuggingFace Spaces. Para configurá-lo:
1. Crie um novo Espaço no HuggingFace com o SDK Docker
2. Configure a variável de ambiente `HUGGINGFACE_TOKEN` ou `HF_TOKEN` na configuração do Space:
- Vá para a aba "Configurações" do seu Espaço
- Role para a seção "Secrets do repositório"
- Adicione uma nova variável com o nome `HUGGINGFACE_TOKEN` e seu token como valor
- Salve as alterações
### Desenvolvimento local
Para o desenvolvimento local:
1. Clone este repositório
2. Crie um arquivo `.env` na raiz do projeto com seu token do HuggingFace:
HUGGINGFACE_TOKEN=seu_token_aqui
3. Instale as dependências:
pip install -r requirements.txt
Por favor, forneça o texto em Markdown que você gostaria de traduzir para o português.
## Execução local
``bash
uvicorn app:app --reload
Por favor, forneça o texto em Markdown que você gostaria de traduzir para o português.
A API estará disponível em `http://localhost:8000`.
## Endpoints
### GET `/`
Ponto final de boas-vindas que retorna uma mensagem de saudação.
### POST `/gerar`
Ponto final para gerar texto usando o modelo de linguagem.
**Parâmetros da solicitação:**
``json
{
"query": "Sua pergunta aqui",
"thread_id": "identificador_de_thread_opcional"
}
Por favor, forneça o texto em markdown que você gostaria de traduzir para o português.
**Resposta:**
``json```
{
"Texto gerado pelo modelo"
"thread_id": "identificador do thread"
}
Por favor, forneça o texto em Markdown que deseja traduzir para o português.
## Docker
Para executar a aplicação em um contêiner Docker:
``bash
# Construa a imagem
docker build -t smollm2-backend .
# Executar o contêiner
docker run -p 8000:8000 --env-file .env smollm2-backend
## Documentação da API
A documentação interativa da API está disponível em:
- Swagger UI: `http://localhost:8000/docs`
- ReDoc: `http://localhost:8000/redoc`
Token do HuggingFace
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

Adicionar o token aos secrets do espaço
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ção
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 /
URL do backend
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.

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.

Se agora formos para essa URL, veremos o mesmo que no espaço.
Documentação
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
.

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

Teste da API
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

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

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

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

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?


Deploy do backend com Gradio e modelo rodando no servidor
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ço
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ódigo
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.py
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.txt
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.0torch>=2.0.0
accelerate>=0.25.0
Teste da API
Desplegamos o space e testamos diretamente a API.
from gradio_client import Clientclient = 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)
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 servidor
Agora fazemos o mesmo que antes, mas com FastAPI, LangChain e Docker.
Criar Espaço
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ódigo
app.py
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.
# Defina a função que chama o modelo
def chamar_modelo(estado: EstadoMensagens):
"""
Chame o modelo com as mensagens fornecidas
Argumentos:
estado: EstadoMensagens
Retorna:
dicionário: Um dicionário contendo o texto gerado e o ID do thread
""""""
# Converter mensagens LangChain para formato de bate-papo
mensagens = []
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 o input usando o modelo de bate-papo
input_text = tokenizer.apply_chat_template(messages, tokenize=False)
inputs = tokenizer.encode(input_text, return_tensors="pt").to(device)
# Gerar resposta
saídas = modelo.gerar(
entradas,
max_new_tokens=512, # Aumente o número de tokens para respostas mais longas
temperature=0.7,
top_p=0,9,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)
# Decodificar e limpar a resposta
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# Extrair apenas a resposta do assistente (após a última mensagem do usuário)
response = response.split("Assistant:")[-1].strip()
# Converter a resposta para o formato LangChain
markdown
ai_message = AIMessage(content=response)
return {"messages": state["messages"] + [ai_message]}
requirements.txt
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.10langgraph>=0.2.27
python-dotenv>=1.0.0
transformers>=4.36.0
torch>=2.0.0
accelerate>=0.26.0
Dockerfile
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 API
Deployamos o space e testamos a API. Neste caso, vou testar diretamente do Python.
import requestsurl = "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)
Respuesta: systemYou are a friendly Chatbot. Always reply in the language in which the user is writing to you.userHola, ¿cómo estás?assistantEstoy 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ões
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.