Giới thiệu Go-Bt: Thư viện Behavior Trees tối giản dành cho Go

08 tháng 4, 2026·4 phút đọc

Go-Bt là thư viện Cây hành vi (Behavior Trees) tối giản dành cho ngôn ngữ Go, hỗ trợ xây dựng AI game, worker nền và tự động hóa tác vụ. Thư viện sử dụng mô hình đa nhiệm hợp tác, cho phép các nút trả về trạng thái ngay lập tức thay vì chặn luồng thực thi. Với tính năng "Time-Travel Testing", nhà phát triển có thể kiểm thử logic thời gian nhanh chóng mà không cần chờ đợi thực tế.

Giới thiệu Go-Bt: Thư viện Behavior Trees tối giản dành cho Go

Go-Bt là một thư viện Behavior Trees (Cây hành vi) mới được thiết kế dành riêng cho ngôn ngữ lập trình Go. Thư viện này hướng tới các nhà phát triển đang xây dựng các worker chạy ngầm, trí tuệ nhân tạo (AI) trong game, tự động hóa các tác vụ lặp lại và xử lý logic bất đồng bộ.

Thay vì sử dụng các vòng lặp vô hạn hay time.Sleep để chặn luồng thực thi, go-bt áp dụng mô hình đa nhiệm hợp tác (cooperative multitasking). Trong mô hình này, các nút (nodes) sẽ trả về trạng thái ngay lập tức và nhường quyền điều khiển lại cho bộ giám sát (supervisor), giúp hệ thống vận hành mượt mà và hiệu quả hơn.

Nguyên lý thiết kế cốt lõi

Go-Bt được xây dựng dựa trên bốn nguyên lý chính nhằm tối ưu hóa hiệu suất và khả năng bảo trì mã nguồn:

  • Nút không trạng thái (Stateless Nodes): Các nút như Sequence hay Selector không lưu trữ trạng thái runtime. Tất cả bộ nhớ tạm thời và trạng thái thực thi đều nằm gọn trong BTContext[T] chung. Điều này giúp việc tái sử dụng các nút logic trở nên an toàn và dễ dàng.
  • Các con số kỳ diệu: Phương thức Run của mỗi nút luôn trả về một trong ba số nguyên để xác định trạng thái: 1 (Thành công), 0 (Đang chạy - cần thêm thời gian/I/O), và -1 (Thất bại).
  • Context hạng nhất: BTContext[T] nhúng trực tiếp context.Context chuẩn của Go. Điều này đảm bảo cây hành vi của bạn tôn trọng tự nhiên các token hủy bỏ (cancellation tokens) và thời gian chờ toàn cục.
  • Kiểm thử du hành thời gian (Time-Travel Testing): Engine sử dụng một đồng hồ được tiêm (injected clock) trực tiếp vào context. Điều này cho phép bạn kiểm thử ngay lập tức một nút Timeout hay Sleep kéo dài 5 phút trong unit test mà không cần phải chờ đợi thực sự.

Thư viện các Nút (Node Library)

Go-Bt cung cấp một tập hợp các nút cốt lõi tối giản nhưng có thể kết hợp để tạo ra bất kỳ luồng điều khiển logic nào:

  • Composites (Tổ hợp): Bao gồm Selector (Ưu tiên/Fallback không trạng thái), Sequence (Cổng AND không trạng thái), và MemSequence (Thực thi theo trình tự thời gian có trạng thái).
  • Decorators (Trang trí): Bao gồm Inverter (Cổng NOT), Optional (Bỏ qua lỗi), Timeout, Retry và Repeat.
  • Leaves (Nút lá): Bao gồm Condition (Đọc bộ nhớ tức thì), Action (Thực thi) và Sleep (Chờ không chặn).

Bắt đầu nhanh với Go-Bt

Để sử dụng go-bt, bạn cần thực hiện ba bước chính: Định nghĩa Blackboard (trạng thái tùy chỉnh), Xây dựng cây (Tree), và Khởi chạy Supervisor.

1. Định nghĩa Blackboard

Blackboard là trạng thái tùy chỉnh mà cây của bạn sẽ đọc và thao tác. Nhờ sử dụng Generics của Go, nó có thể là bất kỳ struct nào.

type WorkerState struct {
    IsConnected  bool
    PendingTasks int
}

2. Xây dựng Cây

Bạn có thể sử dụng các nút của go-bt để lắp ráp logic. Ví dụ dưới đây sẽ đảm bảo worker đã kết nối trước khi cố gắng xử lý tác vụ:

func BuildWorkerTree(cancel context.CancelFunc) core.Command[WorkerState] {
    return composite.NewSelector(
        composite.NewSequence(
            composite.NewSelector(
                leaf.NewCondition(func(blackboard *WorkerState) bool {
                    return blackboard.IsConnected
                }),
                leaf.NewAction(func(ctx *core.BTContext[WorkerState]) int {
                    // Logic kết nối mạng ở đây
                    ctx.Blackboard.IsConnected = true
                    return 1
                }),
            ),
            leaf.NewAction(func(ctx *core.BTContext[WorkerState]) int {
                // Xử lý tác vụ nếu đã kết nối
                if ctx.Blackboard.PendingTasks <= 0 {
                    cancel()
                    return 1
                }
                ctx.Blackboard.PendingTasks--
                return 1
            }),
        ),
    )
}

3. Khởi chạy Supervisor Daemon

Go-Bt cung cấp một Supervisor an toàn (panic-safe) để điều khiển cây của bạn. Nó chạy trong nền và liên tục "tick" logic mà không chặn luồng chính của ứng dụng.

func main() {
    state := &WorkerState{IsConnected: false, PendingTasks: 2}
    ctx, cancel := context.WithCancel(context.Background())
    btCtx := core.NewBTContext(ctx, state)
    tree := BuildWorkerTree(cancel)

    // Tạo Supervisor tick mỗi 100ms
    supervisor := core.NewSupervisor(tree, 100*time.Millisecond, func(err any) {
        println("Tree panicked, safely recovered:", err)
    })

    wg := supervisor.Start(btCtx)
    wg.Wait()
}

Kiểm thử và Clock Injection

Việc kiểm thử logic thời gian (như Sleep hay Timeout) trong các pipeline CI/CD thường dẫn đến các bài test chậm và không ổn định. Go-Bt giải quyết vấn đề này bằng cách đưa ra hàm Now trực tiếp trên BTContext.

Trong các bài kiểm thử, bạn chỉ cần thay thế đồng hồ chuẩn bằng một mock closure. Điều này cho phép bạn đẩy thời gian tiến lên hàng giờ hoặc hàng ngày chỉ trong một micro giây, kích hoạt ngay lập tức các trạng thái thành công/thất bại của nút Timeout hay Sleep để khẳng định tính đúng đắn của cấu trúc.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗