Neste tutorial passo a passo, você usará o LM Studio com o modelo de código aberto IBM® Granite 3.3-8b instructem sua máquina local. Inicialmente, você testará o modelo local como está e, em seguida, escreverá funções em Python que o modelo pode usar para chamadas de ferramentas automáticas. Por fim, você desenvolverá mais funções para jogar xadrez com um agente de IA. Este tutorial também pode ser encontrado no Granite Snack Cookbook GitHub da Comunidade IBM Granite na forma de um Jupyter Notebook.
O LM Studio é uma aplicação para trabalhar com [grandes modelos de linguagem] locais (https://www.ibm.com/br-pt/think/topics/large-language-models) (LLMs). Você pode usar qualquer modelo de código aberto com o LM Studio, como modelos Mistral IA, Gemma do Google, Llama da Meta ou série R1 da DeepSeek .
Com um modelo de IA local, você pode fazer um ajuste fino, inferência e muito mais sem ter que se preocupar com chamadas de API externas (como as interfaces de programação de aplicativos da OpenAI ou do IBM watsonx.ai, ou APIs) ou uso de tokens. O LM Studio também permite que os usuários “conversam com documentos” de forma local e privada. Um usuário pode anexar um documento a uma sessão de bate-papo e fazer perguntas sobre o documento. Nos casos em que o documento for longo, o LM Studio configurará um sistema de geração aumentada de recuperação (RAG) para consultas.
Embora os LLMs se destaquem em entender e gerar texto semelhante ao humano, eles muitas vezes enfrentam limitações quando as tarefas exigem computação precisa, acesso a dados externos em tempo real ou a execução de procedimentos específicos e bem definidos. Ao implementar chamada de ferramenta, equipamos os LLMs com um conjunto de "ferramentas" (funções externas) que eles podem optar por chamar, e que podem ampliar significativamente seus recursos. Este tutorial vai demonstrar como definir essas ferramentas e integrá-las, permitindo que o LLM execute uma gama mais ampla de tarefas com maior confiabilidade.
Antes de instalar o LM Studio, verifique se sua máquina local atende aos requisitos mínimos do sistema.
Em seguida, baixe o instalador apropriado para o sistema operacional do seu computador (Windows, macOS ou Linux). Em seguida, siga estas instruções para baixar os modelos em sua máquina local.
Usaremos o modelo Granite 3.3-8b instruct para esta receita, mas fique à vontade para usar qualquer LLM de sua escolha. Se estiver usando o modelo Granite, você pode pesquisar o espaço de strings específico do usuário/modelo
Em seguida, inicie o servidor local do LM Studio navegando até o ícone verde
Primeiro, precisamos instalar as bibliotecas necessárias, incluindo o LM Studio SDK e a biblioteca de xadrez.
%pip install git+https://github.com/ibm-granite-community/utils \
lmstudio \
chess
import lmstudio as lms
Em seguida, especificaremos o modelo que queremos usar nesta receita. Em nosso caso, será o modelo que baixamos no LM Studio, o Granite 3.3-8b instruct.
Também começaremos a conversar com ele chamando "model.respond()" com uma mensagem inicial.
model = lms.llm("ibm-granite/granite-3.3-8b-instruct-GGUF")
print(model.respond("Hello Granite!"))
Vamos começar pedindo ao modelo que faça um cálculo simples.
print(model.respond("What is 26.97 divided by 6.28? Don't round."))
Embora o modelo possa conseguir fornecer uma boa aproximação, ele não retornará a resposta exata porque não consegue calcular o quociente sozinho.
Para resolver esse problema, forneceremos o modelo com ferramentas. Ferramentas são funções do Python que fornecemos ao modelo na inferência. O modelo pode optar por chamar uma ou mais dessas ferramentas para responder à consulta do usuário.
Avalie a documentação doLM Studio para obter mais informações sobre como escrever ferramentas. Em geral, você deve se certificar de que as funções do seu tooling têm um nome apropriado, tipos de entrada e saída definidos e uma descrição que explique a finalidade da ferramenta. Todas essas informações são passadas para o modelo e podem ajudá-lo a selecionar a ferramenta correta para responder à sua consulta.
Escreveremos várias funções matemáticas simples para o modelo usar como ferramentas:
def add(a: float, b:float):
"""Given two numbers a and b, return a + b."""
return a + b
def subtract(a: float, b:float):
"""Given two numbers a and b, return a - b."""
return a - b
def multiply(a: float, b: float):
"""Given two numbers a and b, return a * b."""
return a * b
def divide(a: float, b: float):
"""Given two numbers a and b, return a / b."""
return a / b
def exp(a: float, b:float):
"""Given two numbers a and b, return a^b"""
return a ** b
Agora, podemos executar novamente a mesma consulta, mas fornecer ao modelo algumas ferramentas para ajudá-lo a responder. Usaremos a chamada "model.act()" chamadas de ferramentas automáticas e indicaremos ao modelo que ele pode usar as funções que criamos.
model.act(
"What is 26.97 divided by 6.28? Don't round.",
[add, subtract, multiply, divide, exp],
on_message=print,
)
Podemos ver que o modelo foi capaz de selecionar a ferramenta correta em "ToolCallRequest", "name", usou as entradas apropriadas em "arguments" (os argumentos a serem passados para a função) e evitou usar as ferramentas irrelevantes. Finalmente, a resposta em "AssistantResponse", "content", "text" mostra a resposta do modelo, uma resposta exata à pergunta.
Uma pergunta muito simples, mas que surpreende até mesmo os modelos de linguagem mais inteligentes. Quase todos os LLMs com um corte de treinamento antes de 2024 respondem que existem apenas 2 Rs na palavra "strawberry". Como bônus, pode até alucinar posições incorretas para as letras.
Hoje em dia, os LLMs tendem a acertar essa pergunta específica, puramente porque sua viralidade os levou à maioria dos conjuntos de dados de treinamento. No entanto, os LLMs ainda costumam falhar em tarefas semelhantes de contagem de letras.
print(model.respond("How many Bs are in the word 'blackberry'?"))
Vamos escrever uma ferramenta para ajudar o modelo a fazer um trabalho melhor.
def get_letter_frequency(word: str) -> dict:
"""Takes in a word (string) and returns a dictionary containing the counts of each letter that appears in the word. """
letter_frequencies = {}
for letter in word:
if letter in letter_frequencies:
letter_frequencies[letter] += 1
else:
letter_frequencies[letter] = 1
return letter_frequencies
Agora, podemos passar a ferramenta para o modelo e executar o prompt novamente.
model.act(
"How many Bs are in the word 'blackberry'?",
[get_letter_frequency],
on_message=print,
)
Usando a ferramenta "get_letter_frequency()", o modelo foi capaz de contar com precisão o número de "b"s na palavra "blackberry".
Um dos melhores casos de uso desse fluxo de trabalho de chamadas automáticas de ferramentas é dar a seu modelo a capacidade de interagir com o ambiente externo. Vamos criar um agente que use ferramentas para jogar xadrez!
Embora os modelos de linguagem possam ter um forte conhecimento conceitual de xadrez, eles não são inerentemente projetados para entender um tabuleiro de xadrez. Se você tentar jogar xadrez com um chatbot online, ele muitas vezes se perde após várias jogadas, fazendo jogadas ilegais ou irracionais.
Estamos fornecendo ao modelo várias ferramentas que o ajudam a entender e interagir.
Não é muito, mas é o suficiente para o modelo jogar uma partida completa de xadrez sem alucinações e usar algum raciocínio inteligente para basear suas decisões.
import chess
import chess.polyglot
from IPython.display import display, SVG, clear_output
import random
import os, requests, shutil, pathlib
board = chess.Board()
ai_pos = 0
# Download book moves
RAW_URL = ("https://raw.githubusercontent.com/"
"niklasf/python-chess/master/data/polyglot/performance.bin")
DEST_FILE = "performance.bin"
if not os.path.exists(DEST_FILE):
print("Downloading performance.bin …")
try:
with requests.get(RAW_URL, stream=True, timeout=15) as r:
r.raise_for_status()
with open(DEST_FILE, "wb") as out:
shutil.copyfileobj(r.raw, out, 1 << 16) # 64 KB chunks
except requests.exceptions.RequestException as e:
raise RuntimeError(f"Download failed: {e}")
def legal_moves() -> list[str]:
"""
Returns a list of legal moves in standard algebraic notation.
"""
return [board.san(move) for move in board.legal_moves]
def possible_captures() -> list[dict]:
"""
Returns all legal captures with metadata:
- san: SAN notation of the capture move.
- captured_piece: The piece type being captured ('P','N','B','R','Q','K').
- is_hanging: True if the captured piece was undefended before the capture.
"""
result = []
for move in board.generate_legal_captures():
piece = board.piece_at(move.to_square)
piece_type = piece.symbol().upper() if piece else "?"
# Check defenders of the target square
defenders = board.attackers(not board.turn, move.to_square)
is_hanging = len(defenders) == 0 # no defenders => hanging
result.append({
"san": board.san(move),
"captured_piece": piece_type,
"is_hanging": is_hanging
})
return result
def possible_checks() -> list[dict]:
"""
Returns all legal checking moves with metadata:
- san: SAN notation of the checking move.
- can_be_captured: True if after the move, the checking piece can be captured.
- can_be_blocked: True if the check can be legally blocked.
- can_escape_by_moving_king: True if the king can move out of check.
"""
result = []
for move in board.legal_moves:
if not board.gives_check(move):
continue
temp = board.copy()
temp.push(move)
can_capture = any(
temp.is_capture(reply) and reply.to_square == move.to_square
for reply in temp.legal_moves
)
# King escapes by moving
king_sq = temp.king(not board.turn)
can_escape = any(
reply.from_square == king_sq for reply in temp.legal_moves
)
# Blocking: legal non-capture, non-king move that resolves check
can_block = any(
not temp.is_capture(reply)
and reply.from_square != king_sq
and not temp.gives_check(reply)
for reply in temp.legal_moves
)
result.append({
"san": board.san(move),
"can_be_captured": can_capture,
"can_be_blocked": can_block,
"can_escape_by_moving_king": can_escape
})
return result
def get_move_history() -> list[str]:
"""
Returns a list of moves made in the game so far in standard algebraic notation.
"""
return [board.san(move) for move in board.move_stack]
def get_book_moves() -> list[str]:
"""
Returns a list of book moves in standard algebraic notation from performance.bin
for the current board position. If no book moves exist, returns an empty list.
"""
moves = []
with chess.polyglot.open_reader("performance.bin") as reader:
for entry in reader.find_all(board):
san_move = board.san(entry.move)
moves.append(san_move)
return moves
def is_ai_turn() -> bool:
return bool(board.turn) == (ai_pos == 0)
def make_ai_move(move: str) -> None:
"""
Given a string representing a valid move in chess notation, pushes move onto chess board.
If non-valid move, raises a ValueError with message "Illegal move.
If called when it is not the AI's turn, raises a ValueError with message "Not AI's turn."
THIS FUNCTION DIRECTLY ENABLES THE AI TO MAKE A MOVE ON THE CHESS BOARD.
"""
if is_ai_turn():
try:
board.push_san(move)
except ValueError as e:
raise ValueError(e)
else:
raise ValueError("Not AI's turn.")
def make_user_move(move: str) -> None:
"""
Given a string representing a valid move in chess notation, pushes move onto chess board.
If non-valid move, raises a ValueError with message "Illegal move.
If called when it is not the player's turn, raises a ValueError with message "Not player's turn."
If valid-move, updates the board and displays the current state of the board.
"""
if not is_ai_turn():
try:
board.push_san(move)
except ValueError as e:
raise ValueError(e)
else:
raise ValueError("Not player's turn.")
def print_fragment(fragment, round_index=0):
print(fragment.content, end="", flush=True)
Em seguida, prepararemos a partida de xadrez com um agente de IA. Ao usar a chamada "lms.Chat()", forneceremos instruções ao nosso agente de IA de xadrez para quando o agente estiver jogando com as brancas ou pretas.
chat_white = lms.Chat("""You are a chess AI, playing for white. Your task is to make the best move in the current position, using the provided tools.
You should use your overall chess knowledge, including openings, tactics, and strategies, as your primary method to determine good moves.
Use the provided tools as an assistant to improve your understanding of the board state and to make your moves. Always use the book moves
if they are available. Be prudicious with your checks and captures. Understand whether the capturable piece is hanging, and its value in
comparison to the piece you are using to capture. Consider the different ways the opponent can defend a check, to pick the best option.""")
chat_black = lms.Chat("""You are a chess AI, playing for black. Your task is to make the best move in the current position, using the provided tools.
You should use your overall chess knowledge, including openings, tactics, and strategies, as your primary method to determine good moves.
Use the provided tools as an assistant to improve your understanding of the board state and to make your moves. Always use the book moves
if they are available. Be prudicious with your checks and captures. Understand whether the capturable piece is hanging, and its value in
comparison to the piece you are using to capture. Consider the different ways the opponent can defend a check, to pick the best option.""")
Finalmente, configuraremos duas funções para rastrear a correspondência: "update_board()" e "get_end_state()".
Ao usar a chamada "model.act()" que usávamos para as chamadas de ferramentas anteriormente, alimentaremos as instruções do agente ("chat") que definimos, as ferramentas disponíveis para seu uso e estabeleceremos um "max_prediction_rounds". Essa função mostra o número máximo de chamadas de ferramentas independentes que o agente pode fazer para executar um movimento específico.
Depois de executar a próxima célula, um campo de entrada vazio deve aparecer para você escrever suas jogadas. Se você não tiver certeza dos movimentos disponíveis, digite "ajuda", e as anotações dos movimentos disponíveis serão exibidas, onde a primeira inicial é o nome inicial da peça (\"B\" é bispo, "\Q\" é dama e assim por diante. Mas "\N\" é cavalo, já que "\K\" representa o rei, e nenhuma inicial é um peão). A próxima letra e o número listados são a linha e a coluna para onde migrar essa peça. Para a notação de casos especiais, como fazer o roque ou movimentos ambíguos de peças, consulte a página da Wikipedia sobre notação algébrica (xadrez) .
Boa sorte!
move = 0
import chess.svg
board.reset()
ai_pos = round(random.random())
def update_board(move = move, ai_pos = ai_pos):
"""
Updates the chess board display in the notebook.
"""
clear_output(wait=True) # Clear previous output
print(f"Board after move {move+1}")
if (ai_pos == 1):
display(SVG(chess.svg.board(board, size=400)))
else:
display(SVG(chess.svg.board(board, size=400, orientation = chess.BLACK)))
def get_end_state():
"""
Returns the end state of the chess game.
"""
if board.is_checkmate():
return "Checkmate!"
elif board.is_stalemate():
return "Stalemate!"
elif board.is_insufficient_material():
return "Draw by insufficient material!"
elif board.is_seventyfive_moves():
return "Draw by 75-move rule!"
elif board.is_fivefold_repetition():
return "Draw by fivefold repetition!"
else:
return None
clear_output(wait=True) # Clear any previous output from the cell
if (ai_pos == 1):
display(SVG(chess.svg.board(board, size=400)))
else:
display(SVG(chess.svg.board(board, size=400, orientation = chess.BLACK)))
# 2. Loop through moves, apply each move, clear previous output, and display new board
userEndGame = False
while True:
if ai_pos == 0:
# AI's turn
model.act(
chat_white,
[get_move_history, legal_moves, possible_captures, possible_checks, get_book_moves, make_ai_move],
on_message=print,
max_prediction_rounds = 8,
)
if is_ai_turn(): # failsafe in case AI does not make a move
make_ai_move(legal_moves()[0]) # Default to the first legal move if AI does not respond
update_board(move)
move += 1
game_over_message = get_end_state()
if game_over_message:
print(game_over_message)
break
# User's turn
while True:
user_move = input("User (Playing Black): Input your move. Input 'help' to see the list of possible moves. Input 'quit' to end the game ->")
if user_move.lower() == 'quit':
print("Game ended by user.")
userEndGame = True
break
if user_move.lower() == 'help':
print("Possible moves:", legal_moves())
continue
try:
make_user_move(user_move)
break
except ValueError as e:
print(e)
if userEndGame:
break
update_board(move)
move += 1
game_over_message = get_end_state()
if game_over_message:
print(game_over_message)
break
else:
# User's turn
while True:
user_move = input("User (Playing White): Input your move. Input 'help' to see the list of possible moves. Input 'quit' to end the game ->")
if user_move.lower() == 'quit':
print("Game ended by user.")
userEndGame = True
break
if user_move.lower() == 'help':
print("Possible moves:", legal_moves())
continue
try:
make_user_move(user_move)
break
except ValueError as e:
print(e)
if userEndGame:
break
update_board(move)
move += 1
game_over_message = get_end_state()
if game_over_message:
print(game_over_message)
break
model.act(
chat_black,
[get_move_history, legal_moves, possible_captures, possible_checks, get_book_moves, make_ai_move],
max_prediction_rounds = 8,
on_message=print,
)
if is_ai_turn(): # failsafe in case AI does not make a move
make_ai_move(legal_moves()[0]) # Default to the first legal move if AI does not respond
update_board(move)
move += 1
game_over_message = get_end_state()
if game_over_message:
print(game_over_message)
break
Neste caderno, demonstramos como a integração de ferramentas pode aprimorar a utilidade e os recursos agênticos dos LLMs. Ilustramos que, ao fornecer a um LLM acesso a funções externas predefinidas, ele pode transcender seus principais recursos de processamento de linguagem para realizar tarefas como cálculos precisos ou interface com sistemas externos. Ela não pode fazer isso de forma confiável por conta própria. A conclusão principal é que o uso da ferramenta capacita os LLMs a delegar subproblemas específicos a rotinas especializadas, permitindo que fundamentam suas respostas em dados factuais ou operações precisas. Essa abordagem não só melhora a precisão, mas também permite que os LLMs se envolvam em fluxos de trabalho mais complexos e interativos, transformando-os efetivamente em assistentes mais versáteis e poderosos.
Crie, implemente e gerencie assistentes e agentes de IA potentes que automatizam fluxos de trabalho e processos com a IA generativa.
Construa o futuro do seu negócio com soluções de IA em que você pode confiar.
Os serviços de IA da IBM Consulting ajudam a reinventar a forma como as empresas trabalham com IA para gerar transformação.