Agents Course documentation

Tools là gì?

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Tools là gì?

Unit 1 planning

Một khía cạnh quan trọng của AI agents là khả năng thực hiện hành động. Như ta đã thấy, điều này xảy ra thông qua việc sử dụng Tools (công cụ).

Trong phần này, ta sẽ tìm hiểu Tools là gì, cách thiết kế chúng hiệu quả và cách tích hợp vào Agent thông qua System Message.

Bằng cách cung cấp đúng Tools cho Agent - và mô tả rõ ràng cách chúng hoạt động - bạn có thể nâng cao đáng kể khả năng của AI. Cùng tìm hiểu nhé!

AI Tools là gì?

Tool là một hàm được cung cấp cho LLM. Hàm này cần đáp ứng một mục tiêu rõ ràng.

Dưới đây là những Tools phổ biến trong AI agents:

Tool Mô tả
Web Search Cho phép agent truy cập thông tin cập nhật từ internet.
Image Generation Tạo hình ảnh dựa trên mô tả văn bản.
Retrieval Truy xuất thông tin từ nguồn bên ngoài.
API Interface Tương tác với API bên ngoài (GitHub, YouTube, Spotify, v.v.).

Đây chỉ là ví dụ - bạn hoàn toàn có thể tạo Tool cho bất kỳ use case nào!

Một Tool tốt cần bổ sung năng lực của LLM.

Ví dụ: nếu cần tính toán số học, việc cung cấp công cụ máy tính cho LLM sẽ cho kết quả tốt hơn so với dựa vào khả năng tự nhiên của mô hình.

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

Ví dụ: nếu hỏi trực tiếp LLM (không dùng công cụ tìm kiếm) về thời tiết hôm nay, LLM có thể “bịa” (hallucinate) ra một thông tin thời tiết ngẫu nhiên.

Weather
  • Một Tool cần chứa:

    • Mô tả bằng văn bản về chức năng
    • Callable (thứ để thực thi hành động)
    • Arguments với kiểu dữ liệu
    • (Tùy chọn) Đầu ra với kiểu dữ liệu

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

Như đã biết, LLM chỉ nhận đầu vào dạng text và tạo đầu ra dạng text. Chúng không thể tự gọi Tools. Khi nói về cung cấp Tools cho Agent, nghĩa là ta dạy LLM về sự tồn tại của Tools và yêu cầu mô hình tạo text để kích hoạt Tools khi cần. Ví dụ: nếu cung cấp Tool kiểm tra thời tiết từ Internet, khi hỏi LLM về thời tiết Paris, LLM sẽ nhận ra cần dùng Tool “weather”. LLM sẽ tạo text dạng code để gọi Tool. Agent có nhiệm vụ phân tích đầu ra của LLM, nhận diện lệnh gọi Tool và thực thi thay cho LLM. Đầu ra từ Tool sẽ được gửi lại LLM để tổng hợp trả lời (response) cuối cho người dùng.

Đầu ra từ Tool là một loại message khác trong hội thoại. Các bước gọi Tool thường không hiển thị cho người dùng: Agent lấy hội thoại, gọi Tool(s), nhận đầu ra, thêm chúng vào hội thoại và gửi lại LLM. Từ góc độ người dùng, trông như LLM tự dùng Tool nhưng thực chất là code ứng dụng (Agent) thực hiện.

Chúng ta sẽ nói thêm về quy trình này trong các bài sau.

Cách cung cấp Tools cho LLM?

Câu trả lời đầy đủ có vẻ phức tạp, nhưng về cơ bản ta dùng system prompt để cung cấp mô tả Tools cho mô hình:

System prompt for tools

Để điều này hoạt động, ta cần chính xác về:

  1. Chức năng của Tool
  2. Đầu vào mà nó mong đợi

Đây là lý do mô tả Tools thường dùng cấu trúc chính xác như ngôn ngữ máy tí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 nào cũng được.

Nếu lý thuyết quá trừu tượng, hãy xem qua ví dụ cụ thể.

Ta sẽ triển khai calculator Tool đơn giản để nhân hai số nguyên. Đây là code Python:

def calculator(a: int, b: int) -> int:
    """Nhân hai số nguyên."""
    return a * b

Tool của ta tên calculator, nhân hai số nguyên và cần các đầu vào:

  • a (int): Số nguyên
  • b (int): Số nguyên

Đầu ra của Tool là số nguyên:

  • (int): Tích của ab

Tất cả chi tiết này đều quan trọng. Hãy tổng hợp chúng thành chuỗi mô tả Tool cho LLM:

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

Nhắc nhở: Mô tả text này là thứ ta muốn LLM biết về Tool.

Khi đưa chuỗi trên vào đầu vào của LLM, mô hình sẽ nhận diện nó là Tool và biết cần truyền đầu vào gì, mong đợi đầu ra gì.

Nếu muốn cung cấp nhiều Tools, ta cần nhất quán định dạng. Quá trình này có thể mong manh và dễ bỏ sót chi tiết.

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

Tự động định dạng phần Tools

Tool của ta được viết bằng Python, và phần triển khai đã cung cấp mọi thứ cần thiết:

  • Tên mô tả: calculator
  • Mô tả dài trong docstring: Multiply two integers.
  • Đầu vào và kiểu dữ liệu: hàm mong đợi hai int
  • Kiểu đầu ra.

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

Ta có thể đưa mã nguồn Python làm đặc tả Tool cho LLM, nhưng cách triển khai Tool không quan trọng. Điều quan trọng là tên, chức năng, đầu vào và đầu ra.

Ta sẽ tận dụng tính năng introspection của Python để tự động xây dựng mô tả Tool từ mã nguồn. Điều kiện là phần triển khai Tool phải dùng type hints, docstrings và tên hàm hợp lý. Ta sẽ viết code để trích xuất thông tin từ mã nguồn.

Sau đó, ta chỉ cần dùng Python decorator để đánh dấu hàm calculator là Tool:

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

print(calculator.to_string())

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

Với phần triển khai sẽ học tiếp theo, ta có thể tự động lấy text mô tả Tool thông qua hàm to_string() từ decorator:

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

Như bạn thấy, nó giống hệt phần ta viết tay trước đó!

Triển khai Tool tổng quát

Ta tạo lớp Tool tổng quát để tái sử dụng khi cần dùng Tool.

Lưu ý: Ví dụ này là giả định nhưng gần với phần triển khai thực tế trong các thư viện.

class Tool:
    """
    Lớp đại diện cho Tool có thể tái sử dụng.
    
    Thuộc tính:
        name (str): Tên Tool
        description (str): Mô tả chức năng
        func (callable): Hàm được wrap
        arguments (list): Danh sách tham số
        outputs (str hoặc list): Kiểu dữ liệu trả về
    """
    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:
        """
        Trả về chuỗi biểu diễn Tool,
        bao gồm tên, mô tả, arguments và 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):
        """
        Gọi hàm cơ sở với arguments được cung cấp.
        """
        return self.func(*args, **kwargs)

Trông có vẻ phức tạp, nhưng nếu xem kỹ ta sẽ hiểu cách hoạt động. Lớp Tool bao gồm:

  • name (str): Tên Tool
  • description (str): Mô tả chức năng
  • function (callable): Hàm thực thi
  • arguments (list): Tham số đầu vào
  • outputs (str hoặc list): Đầu ra mong đợi
  • __call__(): Gọi hàm khi Tool được invoke
  • to_string(): Chuyển thuộc tính Tool thành chuỗi mô tả

Ta có thể tạo Tool bằng code như sau:

calculator_tool = Tool(
    "calculator",                   # tên
    "Multiply two integers.",       # mô tả
    calculator,                     # hàm gọi
    [("a", "int"), ("b", "int")],   # đầu vào (tên và kiểu)
    "int",                          # đầu ra
)

Nhưng ta cũng có thể dùng module inspect của Python để tự động lấy thông tin! Đây chính là cách decorator @tool hoạt động.

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

decorator code
def tool(func):
    """
    Decorator tạo instance Tool từ hàm được cung cấp.
    """
    # Lấy signature của hàm
    signature = inspect.signature(func)
    
    # Trích xuất cặp (tên tham số, kiểu dữ liệu) cho đầu vào
    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))
    
    # Xác định kiểu trả về
    return_annotation = signature.return_annotation
    if return_annotation is inspect._empty:
        outputs = "Không có chú thích kiểu trả về"
    else:
        outputs = (
            return_annotation.__name__ 
            if hasattr(return_annotation, '__name__') 
            else str(return_annotation)
        )
    
    # Dùng docstring của hàm làm mô tả (mặc định nếu không có)
    description = func.__doc__ or "Không có mô tả."
    
    # Tên hàm trở thành tên Tool
    name = func.__name__
    
    # Trả về instance Tool mới
    return Tool(
        name=name, 
        description=description, 
        func=func, 
        arguments=arguments, 
        outputs=outputs
    )

Tóm lại, với decorator này ta có thể triển khai Tool như sau:

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

print(calculator.to_string())

Và dùng method to_string của Tool để tự động lấy text mô tả phù hợp cho LLM:

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

Mô tả này được đưa vào system prompt. Xem ví dụ ban đầu sau khi thay thế tools_description:

System prompt for tools

Trong phần Actions, ta sẽ học cách Agent Gọi Tool vừa tạo.


Tools đóng vai trò quan trọng trong việc nâng cao năng lực của AI agents.

Tóm lại, ta đã học:

  • Tools là gì: Các hàm mở rộng khả năng của LLM như tính toán hay truy cập dữ liệu ngoài

  • Cách định nghĩa Tool: Bằng cách cung cấp mô tả rõ ràng, đầu vào, đầu ra và hàm thực thi

  • Tại sao Tools quan trọng: Chúng giúp Agent vượt giới hạn của mô hình tĩnh, xử lý tác vụ thời gian thực và thực hiện hành động chuyên biệt

Giờ ta có thể chuyển sang Agent Workflow để xem cách Agent quan sát, tư duy và hành động. Đây là tổng hợp mọi thứ đã học và đặt nền móng để bạn tạo AI agent chức năng hoàn chỉnh.

Nhưng trước hết, hãy cùng làm Kiểm tra nhanh!

< > Update on GitHub