Dalam tutorial ini, Anda akan menggunakan LM Studio dengan model sumber terbuka IBM Granite 3.3-8b instruct di mesin lokal Anda. Pertama-tama, Anda akan menguji model lokal apa adanya dan kemudian menulis fungsi Python yang dapat digunakan oleh model tersebut untuk pemanggilan alat otomatis. Terakhir, Anda akan mengembangkan lebih banyak fungsi untuk memainkan permainan catur dengan agen AI. Tutorial ini juga dapat ditemukan di Granite Snack Cookbook GitHub IBM Granite Community dalam bentuk Jupyter Notebook.
LM Studio adalah aplikasi untuk bekerja dengan [model bahasa besar] lokal (https://www.ibm.com/id-id/think/topics/large-language-models) (LLM). Anda dapat menggunakan [model sumber terbuka] apa pun (https://www.ibm.com/id-id/think/topics/open-source-llms) dengan LM Studio, seperti model [Mistral AI] (https://www.ibm.com/id-id/think/topics/mistral-ai), Gemma dari Google, Llama Meta, atau seri [R1 dari DeepSeek] (https://www.ibm.com/id-id/think/topics/deepseek) .
Dengan menggunakan LM Studio, pengguna pemula hingga yang lebih mahir dapat menjalankan LLM dengan CPU komputer mereka atau bahkan dengan [GPU] (https://www.ibm.com/id-id/think/topics/gpu). LM Studio menawarkan antarmuka seperti obrolan untuk berinteraksi dengan LLM lokal yang mirip dengan obrolan [ChatGPT] (https://www.ibm.com/id-id/think/topics/chatgpt) .
Dengan model AI lokal, Anda dapat [menyempurnakan] (https://www.ibm.com/id-id/think/topics/fine-tuning), (https://www.ibm.com/id-id/think/topics/ai-inference) dan banyak lagi tanpa harus mengkhawatirkan panggilan [API] eksternal (https://www.ibm.com/id-id/think/topics/api) (seperti antarmuka pemrograman aplikasi OpenAI atau IBM watsonx.ai, atau API) atau penggunaan token. LM Studio juga memungkinkan pengguna secara lokal dan pribadi “mengobrol dengan dokumen.” Pengguna dapat melampirkan dokumen ke sesi obrolan dan mengajukan pertanyaan tentang dokumen tersebut. Dalam kasus di mana dokumennya panjang, LM Studio akan menyiapkan [retrieval augmented generation] (https://www.ibm.com/id-id/think/topics/retrieval-augmented-generation) sistem (RAG) untuk kueri.
Meskipun LLM unggul dalam memahami dan menghasilkan teks seperti manusia, namun mereka sering menghadapi keterbatasan ketika tugas membutuhkan komputasi yang tepat, akses ke data eksternal secara real-time, atau eksekusi prosedur yang spesifik dan didefinisikan dengan baik. Dengan mengimplementasikan [pemanggilan alat] (https://www.ibm.com/id-id/think/topics/tool-calling), kami melengkapi LLM dengan seperangkat "alat", fungsi eksternal, yang dapat mereka pilih untuk dipanggil yang dapat memperluas kemampuan mereka secara signifikan. Tutorial ini akan mendemonstrasikan cara mendefinisikan alat bantu ini dan mengintegrasikannya, sehingga memungkinkan LLM untuk melakukan berbagai tugas yang lebih luas dengan keandalan yang lebih tinggi.
Sebelum menginstal LM Studio, periksa apakah komputer lokal Anda memenuhi persyaratan sistem minimum.
Selanjutnya, unduh penginstal yang sesuai untuk sistem operasi komputer Anda (Windows, macOS, atau Linux). Kemudian, ikuti petunjuk ini untuk mengunduh model ke mesin lokal Anda.
Kami akan menggunakan model instruksi Granite 3.3-8b untuk resep ini, tetapi jangan ragu untuk menggunakan LLM pilihan Anda. Jika Anda menggunakan model Granite, Anda dapat mencari untai pengguna/model tertentu
Selanjutnya, mulai server lokal LM Studio dengan menemukan
Pertama-tama kita perlu menginstal pustaka yang diperlukan, termasuk LM Studio SDK dan pustaka catur.
%pip install git+https://github.com/ibm-granite-community/utils \
lmstudio \
chess
import lmstudio as lms
Kami akan menentukan model yang ingin kami gunakan dalam resep ini selanjutnya. Dalam kasus kami, itulah model yang kami unduh di LM Studio, Granite 3.3-8b instruc.
Kami juga akan mulai mengobrol dengannya dengan memanggil model.respond() dengan pesan awal.
model = lms.llm("ibm-granite/granite-3.3-8b-instruct-GGUF")
print(model.respond("Hello Granite!"))
Mari kita mulai dengan meminta model untuk melakukan perhitungan langsung.
print(model.respond("What is 26.97 divided by 6.28? Don't round."))
Sementara model ini mungkin dapat memberikan perkiraan yang mendekati, namun tidak akan memberikan jawaban yang tepat karena tidak dapat menghitung hasil bagi sendiri.
Untuk mengatasi masalah ini, kami akan memberikan alat kepada model. Alat adalah fungsi Python yang kami sediakan untuk model pada inferensi. Model dapat memilih untuk memanggil satu alat ini atau lebih untuk menjawab permintaan pengguna.
Tinjau Dokumen LM Studio untuk informasi lebih lanjut tentang cara menulis alat. Umumnya, Anda harus memastikan bahwa fungsi alat Anda memiliki nama yang sesuai, jenis input dan output yang ditentukan, dan deskripsi yang menjelaskan tujuan alat. Semua informasi ini diteruskan ke model dan dapat membantunya memilih alat yang benar untuk menjawab pertanyaan Anda.
Kami akan menulis beberapa fungsi matematika sederhana untuk digunakan model sebagai alat:
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
Sekarang, kami dapat menjalankan kembali kueri yang sama tetapi memberikan model beberapa alat untuk membantunya menjawab. Kita akan menggunakan panggilan model.act () untuk pemanggilan alat otomatis dan menunjukkan kepada model bahwa ia dapat menggunakan fungsi yang kami buat.
model.act(
"What is 26.97 divided by 6.28? Don't round.",
[add, subtract, multiply, divide, exp],
on_message=print,
)
Kami dapat melihat bahwa model dapat memilih alat yang benar di bawah ToolCallRequest, name, menggunakan input yang sesuai di bawah arguments (argumen yang akan diteruskan ke fungsi) dan menghindari penggunaan alat yang tidak relevan. Terakhir, respons di bawah AssistantResponse, content, text menunjukkan respons dari model, jawaban yang tepat untuk pertanyaan.
Pertanyaan yang sangat sederhana yang bahkan mengganggu model bahasa paling cerdas sekalipun. Hampir setiap LLM dengan batas waktu pelatihan sebelum tahun 2024 menjawab bahwa hanya ada 2 huruf R dalam kata "strawberry." Sebagai bonus, bahkan mungkin berhalusinasi posisi yang salah untuk surat-surat itu.
Saat ini, para LLM cenderung menjawab pertanyaan spesifik ini dengan benar, semata-mata karena kecenderungannya membuatnya masuk ke sebagian besar kumpulan data pelatihan. Namun, LLM umumnya masih gagal pada tugas penghitungan huruf serupa.
print(model.respond("How many Bs are in the word 'blackberry'?"))
Mari kita tulis alat untuk membantu model melakukan pekerjaan yang lebih baik.
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
Sekarang kita dapat meneruskan alat ini ke model dan menjalankan kembali prompt.
model.act(
"How many Bs are in the word 'blackberry'?",
[get_letter_frequency],
on_message=print,
)
Menggunakan alat get_letter_frequency (), model mampu menghitung secara akurat jumlah b dalam kata 'blackberry'.
Salah satu contoh penggunaan terbaik dari alur kerja ini adalah memberi model Anda kemampuan untuk berinteraksi dengan lingkungan eksternalnya. Mari kita membangun agen yang menggunakan alat untuk bermain catur!
Meskipun model bahasa dapat memiliki pengetahuan konseptual yang kuat tentang catur, model bahasa tidak dirancang secara inheren untuk memahami papan catur. Jika Anda mencoba memainkan permainan catur dengan chatbot online, sering kali permainan akan gagal setelah beberapa kali putaran, membuat gerakan yang ilegal, atau tidak rasional.
Kami menyediakan model beberapa alat yang membantunya memahami dan berinteraksi dengan papan.
Memang tidak banyak, tetapi cukup bagi model untuk memainkan permainan catur penuh tanpa berhalusinasi, dan menggunakan penalaran yang cerdas untuk mendasari keputusannya.
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)
Selanjutnya, kami akan menyiapkan pertandingan catur dengan agen AI. Dengan menggunakan panggilan lms.Chat(), kami akan memberikan instruksi kepada agen AI catur kami, kapan agen bermain untuk putih atau hitam.
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.""")
Terakhir kita akan mengatur dua fungsi untuk melacak kecocokan: update_board() dan get_end_state().
Dengan menggunakan model.act () yang kita gunakan untuk pemanggilan alat sebelumnya, kita akan memberikan agen instruksi (chat) yang kita tetapkan, alat yang tersedia untuk penggunaannya, dan menetapkan max_prediction_rounds. Fungsi ini menunjukkan jumlah maksimum panggilan alat independen yang dapat dilakukan agen untuk mengeksekusi gerakan tertentu.
Setelah menjalankan sel berikutnya, bidang input kosong akan muncul bagi Anda untuk menuliskan pindah Anda. Jika Anda tidak yakin dengan pindah yang tersedia, ketik `help` dan notasi gerakan yang tersedia akan ditampilkan di mana inisial pertama adalah inisial nama bidak (\"B\" adalah gajah, \"Q\" adalah ratu, dan seterusnya. Tapi\ " N\ " adalah kuda karena\ " K\ " menunjukkan raja dan tidak ada inisial pertama untuk pion). Huruf dan angka berikutnya yang tercantum adalah baris dan kolom untuk menggerakkan bidak. Untuk notasi kasus khusus seperti rokade atau gerakan bidak yang ambigu, lihat halaman Wikipedia notasi aljabar (catur).
Semoga berhasil!
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
Dalam notebook ini, kami mendemonstrasikan bagaimana alat pengintegrasian dapat meningkatkan utilitas dan kemampuan agen LLM. Kami mengilustrasikan bahwa dengan memberikan LLM akses ke fungsi eksternal yang telah ditentukan, ia dapat melewati kemampuan intinya untuk melakukan tugas-tugas seperti perhitungan yang akurat atau antarmuka dengan sistem eksternal. LLM tidak dapat melakukannya sendiri dengan andal. Poin pentingnya adalah bahwa penggunaan alat memberdayakan LLM untuk mendelegasikan submasalah tertentu ke rutinitas khusus, memungkinkan mereka untuk mendasarkan tanggapan mereka dalam data faktual atau Operasi. Pendekatan ini tidak hanya meningkatkan akurasi, tetapi juga memungkinkan LLM untuk terlibat dalam alur kerja yang lebih kompleks dan interaktif, yang secara efektif mengubah mereka menjadi asisten yang lebih fleksibel dan kuat.
Bangun, terapkan, dan kelola asisten dan agen AI yang kuat yang mengotomatiskan alur kerja dan proses dengan AI generatif.
Bangun masa depan bisnis Anda dengan solusi AI yang dapat Anda percaya.
Layanan IBM Consulting AI membantu merancang ulang cara kerja bisnis dengan AI untuk transformasi.