Skip to content
Lesson 5/12 · Khoá học AI Agent (Hugging Face)

Tool là gì?

Tool là hàm giao cho LLM; cách tool hoạt động, cách mô tả tool trong system prompt, tự sinh mô tả bằng decorator và vai trò của MCP.

This content is currently available in Vietnamese only.

Beginner@shine190411 min read

Một khía cạnh then chốt của AI agent là khả năng thực hiện hành động. Như đã thấy, điều này diễn ra thông qua việc dùng tool. Trong bài này, chúng ta sẽ tìm hiểu tool là gì, cách thiết kế tool hiệu quả và cách tích hợp chúng vào agent qua system message.

Bảng kế hoạch unit 1

Bằng cách trao cho agent đúng tool, và mô tả rõ ràng cách các tool đó hoạt động, bạn có thể tăng đáng kể những gì AI của mình làm được. Bắt đầu nào!

AI tool là gì?

Tool là một hàm được giao cho LLM. Hàm này cần phục vụ một mục tiêu rõ ràng.

Dưới đây là một số tool thường dùng trong AI agent:

ToolMô tả
Web SearchCho phép agent lấy thông tin mới nhất từ internet.
Image GenerationTạo ảnh từ mô tả bằng văn bản.
RetrievalTruy xuất thông tin từ một nguồn bên ngoài.
API InterfaceTương tác với một API bên ngoài (GitHub, YouTube, Spotify…).

Đó chỉ là ví dụ, vì thực tế bạn có thể tạo tool cho bất kỳ trường hợp sử dụng nào!

Một tool tốt nên là thứ bổ trợ cho sức mạnh của LLM.

Ví dụ, nếu cần làm phép tính số học, việc đưa cho LLM một tool máy tính sẽ cho kết quả tốt hơn là dựa vào khả năng sẵn có của model.

Hơn nữa, LLM dự đoán phần tiếp nối của prompt dựa trên dữ liệu huấn luyện, nghĩa là kiến thức bên trong của chúng chỉ gồm các sự kiện trước thời điểm huấn luyện. Vì vậy, nếu agent cần dữ liệu mới nhất, bạn phải cung cấp qua một tool nào đó.

Chẳng hạn, nếu bạn hỏi thẳng LLM (không có tool tìm kiếm) thời tiết hôm nay, LLM có thể "ảo giác" (hallucinate) ra một thời tiết ngẫu nhiên.

Thời tiết

Một tool nên có:

  • Một mô tả bằng văn bản về việc hàm làm.
  • Một Callable (thứ thực hiện hành động).
  • Các đối số (argument) có kiểu dữ liệu.
  • (Tuỳ chọn) Đầu ra có kiểu dữ liệu.

Tool hoạt động thế nào?

Như đã thấy, LLM chỉ nhận đầu vào văn bản và sinh đầu ra văn bản. Chúng không có cách nào tự gọi tool. Khi nói về việc cung cấp tool cho agent, ý chúng ta là dạy LLM biết các tool này tồn tại và hướng dẫn nó sinh ra lời gọi dạng văn bản khi cần.

Ví dụ, nếu cung cấp một tool kiểm tra thời tiết tại một địa điểm từ internet rồi hỏi LLM thời tiết ở Paris, LLM sẽ nhận ra đây là cơ hội dùng tool "weather". Thay vì tự lấy dữ liệu thời tiết, LLM sẽ sinh văn bản thể hiện một lời gọi tool, như call weather_tool('Paris').

Sau đó agent đọc phản hồi này, xác định cần gọi tool, thay LLM thực thi tool và lấy dữ liệu thời tiết thực tế.

Các bước gọi tool thường không hiển thị cho người dùng: agent nối chúng vào như một tin nhắn mới trước khi đưa cuộc hội thoại đã cập nhật lại cho LLM. Sau đó LLM xử lý ngữ cảnh bổ sung này và sinh câu trả lời tự nhiên cho người dùng. Từ góc nhìn người dùng, có vẻ như LLM đã trực tiếp tương tác với tool, nhưng thực ra chính agent đã xử lý toàn bộ việc thực thi ở phía sau.

Chúng ta sẽ nói nhiều hơn về quá trình này ở các phần sau.

Giao tool cho LLM bằng cách nào?

Câu trả lời đầy đủ có thể hơi choáng ngợp, nhưng về cơ bản chúng ta dùng system prompt để cung cấp cho model mô tả bằng văn bản của các tool có sẵn:

System prompt khai báo tool

Để cách này hiệu quả, chúng ta phải mô tả thật chính xác:

  1. Tool làm gì
  2. Tool cần chính xác những đầu vào nào

Đó là lý do mô tả tool thường dùng các cấu trúc giàu biểu đạt nhưng chính xác, như ngôn ngữ lập trình hoặc JSON. Không bắt buộc phải làm vậy, bất kỳ định dạng chính xác và nhất quán nào cũng được.

Nếu nghe quá lý thuyết, chúng ta hãy hiểu qua một ví dụ cụ thể.

Chúng ta sẽ cài đặt một tool calculator đơn giản chỉ nhân hai số nguyên. Đây có thể là phần cài đặt bằng Python:

python
def calculator(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

Vậy tool của chúng ta tên là calculator, nó nhân hai số nguyên, và cần các đầu vào sau:

  • a (int): một số nguyên.
  • b (int): một số nguyên.

Đầu ra của tool là một số nguyên khác, có thể mô tả như sau:

  • (int): tích của a và b.

Mọi chi tiết này đều quan trọng. Chúng ta hãy ghép chúng thành một chuỗi văn bản mô tả tool để LLM hiểu.

text
Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int

Nhắc lại: mô tả bằng văn bản này là những gì chúng ta muốn LLM biết về tool.

Khi đưa chuỗi trên vào đầu vào của LLM, model sẽ nhận ra đó là một tool, biết cần truyền gì làm đầu vào và đầu ra sẽ như thế nào.

Nếu muốn cung cấp thêm tool, chúng ta phải nhất quán và luôn dùng cùng một định dạng. Quá trình này có thể dễ vỡ và chúng ta có thể vô tình bỏ sót vài chi tiết.

Có cách nào tốt hơn không?

Tự động định dạng phần mô tả tool

Tool của chúng ta được viết bằng Python, và phần cài đặt đã có sẵn mọi thứ cần thiết:

  • Một cái tên mô tả việc nó làm: calculator
  • Một mô tả dài hơn, lấy từ docstring của hàm: Multiply two integers.
  • Các đầu vào và kiểu của chúng: hàm rõ ràng cần hai int.
  • Kiểu của đầu ra.

Người ta dùng ngôn ngữ lập trình là có lý do: chúng giàu biểu đạt, ngắn gọn và chính xác.

Chúng ta có thể đưa source code Python làm đặc tả của tool cho LLM, nhưng cách tool được cài đặt không quan trọng. Điều quan trọng là tên, việc nó làm, đầu vào nó cần và đầu ra nó trả về.

Chúng ta sẽ tận dụng tính năng introspection của Python để đọc source code và tự động dựng mô tả tool. Tất cả những gì cần là phần cài đặt tool dùng type hint, docstring và tên hàm hợp lý. Chúng ta sẽ viết chút code để trích các phần liên quan từ source code.

Xong việc đó, chúng ta chỉ cần dùng một decorator Python để đánh dấu hàm calculator là một tool:

python
@tool
def calculator(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

print(calculator.to_string())

Để ý decorator @tool trước định nghĩa hàm.

Với phần cài đặt sẽ xem ngay sau đây, chúng ta có thể tự động lấy đoạn văn bản sau từ source code qua hàm to_string() mà decorator cung cấp:

text
Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int

Như bạn thấy, nó giống hệt những gì chúng ta đã viết tay trước đó!

Cài đặt Tool tổng quát

Chúng ta tạo một class Tool tổng quát để tái sử dụng mỗi khi cần dùng tool.

Lưu ý: phần cài đặt ví dụ này là hư cấu nhưng rất giống cách cài đặt thực tế trong hầu hết thư viện.

python
from typing import Callable


class Tool:
    """
    A class representing a reusable piece of code (Tool).

    Attributes:
        name (str): Name of the tool.
        description (str): A textual description of what the tool does.
        func (callable): The function this tool wraps.
        arguments (list): A list of arguments.
        outputs (str or list): The return type(s) of the wrapped function.
    """
    def __init__(self,
                 name: str,
                 description: str,
                 func: Callable,
                 arguments: list,
                 outputs: str):
        self.name = name
        self.description = description
        self.func = func
        self.arguments = arguments
        self.outputs = outputs

    def to_string(self) -> str:
        """
        Return a string representation of the tool,
        including its name, description, arguments, and outputs.
        """
        args_str = ", ".join([
            f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments
        ])

        return (
            f"Tool Name: {self.name},"
            f" Description: {self.description},"
            f" Arguments: {args_str},"
            f" Outputs: {self.outputs}"
        )

    def __call__(self, *args, **kwargs):
        """
        Invoke the underlying function (callable) with provided arguments.
        """
        return self.func(*args, **kwargs)

Trông có vẻ phức tạp, nhưng đi chậm từng phần sẽ thấy nó làm gì. Chúng ta định nghĩa class Tool gồm:

  • name (str): tên của tool.
  • description (str): mô tả ngắn việc tool làm.
  • function (callable): hàm mà tool thực thi.
  • arguments (list): các tham số đầu vào cần có.
  • outputs (str hoặc list): đầu ra mong đợi của tool.
  • __call__(): gọi hàm khi instance của tool được gọi.
  • to_string(): chuyển các thuộc tính của tool thành dạng văn bản.

Chúng ta có thể tạo một Tool bằng class này với code như sau:

python
calculator_tool = Tool(
    "calculator",                   # name
    "Multiply two integers.",       # description
    calculator,                     # function to call
    [("a", "int"), ("b", "int")],   # inputs (names and types)
    "int",                          # output
)

Nhưng chúng ta cũng có thể dùng module inspect của Python để lấy toàn bộ thông tin! Đó chính là việc decorator @tool làm.

Code của decorator (tham khảo)

Nếu quan tâm, bạn có thể xem phần cài đặt decorator dưới đây.

python
import inspect

def tool(func):
    """
    A decorator that creates a Tool instance from the given function.
    """
    # Get the function signature
    signature = inspect.signature(func)

    # Extract (param_name, param_annotation) pairs for inputs
    arguments = []
    for param in signature.parameters.values():
        annotation_name = (
            param.annotation.__name__
            if hasattr(param.annotation, '__name__')
            else str(param.annotation)
        )
        arguments.append((param.name, annotation_name))

    # Determine the return annotation
    return_annotation = signature.return_annotation
    if return_annotation is inspect._empty:
        outputs = "No return annotation"
    else:
        outputs = (
            return_annotation.__name__
            if hasattr(return_annotation, '__name__')
            else str(return_annotation)
        )

    # Use the function's docstring as the description (default if None)
    description = func.__doc__ or "No description provided."

    # The function name becomes the Tool name
    name = func.__name__

    # Return a new Tool instance
    return Tool(
        name=name,
        description=description,
        func=func,
        arguments=arguments,
        outputs=outputs
    )

Nhắc lại, khi đã có decorator này, chúng ta có thể cài đặt tool như sau:

python
@tool
def calculator(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

print(calculator.to_string())

Và có thể dùng phương thức to_string của Tool để tự động lấy đoạn văn bản phù hợp làm mô tả tool cho LLM:

text
Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int

Mô tả này được chèn vào system prompt. Với ví dụ ở đầu bài, đây là system prompt sau khi thay tools_description:

System prompt sau khi chèn mô tả tool

Trong bài Action, chúng ta sẽ tìm hiểu thêm cách agent gọi tool vừa tạo.

Model Context Protocol (MCP): giao diện tool thống nhất

Model Context Protocol (MCP) là một giao thức mở chuẩn hoá cách ứng dụng cung cấp tool cho LLM. MCP mang lại:

  • Danh sách các bản tích hợp (integration) dựng sẵn ngày càng nhiều mà LLM của bạn có thể cắm vào trực tiếp
  • Sự linh hoạt khi chuyển đổi giữa các nhà cung cấp LLM
  • Các thực hành tốt nhất để bảo mật dữ liệu trong hạ tầng của bạn

Điều này có nghĩa là mọi framework cài đặt MCP đều có thể tận dụng các tool định nghĩa trong giao thức, không cần cài đặt lại cùng một giao diện tool cho từng framework.

Nếu muốn tìm hiểu sâu hơn về MCP, bạn có thể xem khoá học MCP.

Tổng kết

Tool đóng vai trò then chốt trong việc nâng cao khả năng của AI agent. Tóm lại, chúng ta đã học:

  • Tool là gì: các hàm trao thêm khả năng cho LLM, như tính toán hoặc truy cập dữ liệu bên ngoài.
  • Cách định nghĩa tool: cung cấp mô tả rõ ràng bằng văn bản, đầu vào, đầu ra và một hàm callable.
  • Vì sao tool thiết yếu: chúng giúp agent vượt qua giới hạn của dữ liệu huấn luyện tĩnh, xử lý tác vụ thời gian thực và thực hiện các hành động chuyên biệt.

Giờ chúng ta có thể chuyển sang Quy trình của agent, nơi bạn sẽ thấy agent quan sát, suy nghĩ và hành động thế nào. Phần này kết nối mọi thứ đã học và chuẩn bị cho việc tạo AI agent hoàn chỉnh của riêng bạn.

Nguồn