Harness Academy
Tài liệu gốc 05 7 phútTiếng Việt + English
docs/en/s02-tool-system.mdXem bản gốc
Ngôn ngữ bài đọc
Bản dịch tiếng Việt

Bản dịch đầy đủ theo đúng cấu trúc tài liệu; code, liên kết và định danh kỹ thuật được giữ nguyên.

s02: Hệ thống công cụ

s00 > s01 > [ s02 ] > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > s18 > s19 > s20 > s21 > s22 > s23 > s24 > s25 > s26 > s27

"Thêm công cụ có nghĩa là thêm một tệp duy nhất" -- không có thay đổi nào đối với vòng lặp, sổ đăng ký hoặc lớp điều phối.

Lớp khai thác: Đăng ký và gửi công cụ -- cho phép hơn 50 công cụ và công cụ bên ngoài MCP cùng tồn tại mà không ảnh hưởng lẫn nhau.

Vấn đề

Trong vòng lặp s01, run_tool() là một hộp đen. Cách triển khai trực quan nhất là chuỗi if/elif, nhưng Hermes Agent có hơn 50 công cụ tích hợp, cùng với các công cụ bên ngoài MCP có thể tham gia linh hoạt. Nếu mọi công cụ mới đều yêu cầu sửa đổi mã điều phối, hệ thống sẽ nhanh chóng vượt khỏi tầm kiểm soát.

Thông tin chi tiết quan trọng: việc thêm một công cụ không cần phải thay đổi vòng lặp hoặc bất kỳ tệp cấu hình trung tâm nào.

Giải pháp

Chuỗi nhập hệ thống công cụ

Hermes Agent chia hệ thống công cụ thành ba lớp, được kết nối bằng chuỗi nhập khẩu:

registry.py          (imports no tools)
     ^
tools/*.py           (imports registry, registers itself)
     ^
model_tools.py       (imports all tools/*.py, triggering registration)
     ^
run_agent.py         (imports model_tools.py, uses the interface)

The registry sits at the bottom and depends on no tools.
This is the key to making the whole design work.

Nó hoạt động như thế nào

1. Công cụ tự đăng ký file

Mỗi cuộc gọi tập tin công cụ register() ở cuối:

# tools/web_tools.py
from tools.registry import registry

def handle_web_search(args, **kwargs):
    query = args.get("query", "")
    # ... perform search ...
    return json.dumps({"results": [...]})

registry.register(
    name="web_search",
    toolset="web",
    schema={"name": "web_search", "description": "Search the web", "parameters": {...}},
    handler=handle_web_search,
    is_async=True,
    requires_env=["SERP_API_KEY"],
)

2. Khám phá kích hoạt lớp điều phối

Mục đích của lớp điều phối là đưa tất cả các công cụ trực tuyến một cách tự động mà không cần cấu hình từng công cụ một cách thủ công.

Nó tận dụng quy tắc cơ bản của Python: khi một mô-đun được nhập, mã cấp cao nhất của nó sẽ thực thi ngay lập tức. registry.register(...) gọi ở cuối mỗi tệp công cụ là mã cấp cao nhất -- ngay sau khi mô-đun được nhập, quá trình đăng ký sẽ tự động diễn ra.

Tất cả những gì lớp điều phối cần làm là nhập mọi mô-đun công cụ:

# model_tools.py
from tools.registry import registry

_modules = [
    "tools.web_tools",       # import -> register() at the end executes -> web_search registered
    "tools.terminal_tool",   # import -> register() executes -> terminal registered
    "tools.file_tools",      # import -> register() executes -> read_file, write_file registered
    "tools.vision_tools",
    "tools.skills_tool",
    "tools.memory_tool",
    # ... 20+ modules
]
for mod in _modules:
    importlib.import_module(mod)

# MCP external tools are also discovered and registered here
from tools.mcp_tool import discover_mcp_tools
discover_mcp_tools()

importlib.import_module("tools.web_tools") có tác dụng tương tự như viết import tools.web_tools trực tiếp, ngoại trừ tên mô-đun có thể là một biến chuỗi -- vì vậy nó có thể được đặt trong danh sách và được nhập vào một vòng lặp. Việc thêm một công cụ mới chỉ yêu cầu thêm một chuỗi vào danh sách.

Đăng ký và gửi công cụ

Dòng chảy tổng thể:

model_tools.py starts
  -> import tools.web_tools    -> register("web_search") executes automatically
  -> import tools.terminal_tool -> register("terminal")  executes automatically
  -> import tools.file_tools   -> register("read_file")  executes automatically
  -> ...
  -> discover_mcp_tools()      -> external MCP tools are also registered

Result: the registry now contains 50+ tools, and dispatch("web_search") in the loop can find it

3. Cơ quan đăng ký gửi thực thi

# tools/registry.py
class ToolRegistry:
    def dispatch(self, name, args, **kwargs):
        entry = self._tools.get(name)
        if not entry:
            return json.dumps({"error": f"Unknown tool: {name}"})
        if entry.is_async:
            return _run_async(entry.handler(args, **kwargs))
        return entry.handler(args, **kwargs)

các is_async cờ là một thiết kế độc đáo của Hermes. Vòng lặp cốt lõi là đồng bộ, nhưng các công cụ như yêu cầu mạng và hoạt động của trình duyệt không đồng bộ. Khi cơ quan đăng ký nhìn thấy cờ, nó sẽ tự động định tuyến qua cầu nối không đồng bộ. Cả tệp công cụ lẫn vòng lặp lõi đều không cần phải lo lắng về chi tiết này.

4. Cầu không đồng bộ

# model_tools.py
def _run_async(coro):
    # Don't use asyncio.run() -- it creates a new loop then closes it,
    # breaking cached httpx clients
    # Use a persistent event loop instead
    tool_loop = _get_tool_loop()
    return tool_loop.run_until_complete(coro)

Tại sao không chỉ sử dụng asyncio.run()? Bởi vì nó tạo ra một vòng lặp mới mỗi lần và sau đó đóng nó lại. Các công cụ lưu trữ nội bộ các ứng dụng khách httpx / AsyncOpenAI liên kết với vòng lặp cũ -- sau khi vòng lặp bị đóng, các ứng dụng khách đó sẽ không thể sử dụng được. Vòng lặp liên tục giữ cho bộ nhớ đệm của máy khách hợp lệ.

5. Chuyển đổi bộ công cụ và kiểm tra tính khả dụng

# Specify a check_fn at registration time
registry.register(
    name="browser_navigate",
    toolset="browser",
    check_fn=lambda: bool(os.environ.get("BROWSERBASE_API_KEY")),
    # ...
)

# get_definitions() only returns tools whose check_fn passes
# No API key -> this tool won't appear in the schema list sent to the model

Những thay đổi liên quan đến s01

Thành phầnTrước (s01)Sau (s02)
Công cụrun_tool hộp đenSổ đăng ký -> lớp điều phối -> gửi đi
Thêm một công cụ mớiYêu cầu thay đổi vòng lặpChỉ cần thêm một tệp
Công cụ không đồng bộKhông được hỗ trợis_async cờ + cầu vòng lặp sự kiện liên tục
Lọc công cụKhông cóChuyển đổi bộ công cụ + kiểm tra tính khả dụng của check_fn
Công cụ bên ngoài MCPKhông cóĐược phát hiện bởi lớp điều phối và đăng ký vào cùng một sổ đăng ký
Vòng lõiKhông thay đổiKhông thay đổi

Hãy thử nó

cd learn-hermes-agent
python agents/s02_tool_system.py

Hãy thử những lời nhắc sau:

  1. Search for what's new in Python 3.12 -- định tuyến đến công cụ web_search
  2. Read requirements.txt -- định tuyến đến công cụ read_file
  3. Run ls -la in the terminal -- định tuyến đến công cụ đầu cuối
  4. Create a hello.py file -- định tuyến tới công cụ write_file

Lưu ý: bạn không thay đổi mã vòng lặp nhưng bốn công cụ khác nhau đều hoạt động chính xác.

Khi bạn bắt đầu cảm nhận được "Công cụ không chỉ là đăng ký + gửi đi"

Đến thời điểm này, hệ thống công cụ đã được trình bày như sau:

  • lược đồ (hướng dẫn sử dụng cho mô hình)
  • trình xử lý (chức năng thực sự thực thi)
  • công văn (tra cứu theo tên và gọi)

Điều đó đúng và bạn cần phải học theo cách này trước tiên.

Nhưng khi hệ thống phát triển, bạn sẽ thấy rằng quá trình thực thi công cụ sẽ diễn ra trước và sau quá trình xử lý: kiểm tra quyền (s09), cầu nối công cụ bên ngoài MCP (s16), giới hạn kích thước kết quả và chiến lược thực hiện song song. Chúng được mở rộng trong các chương sau.

Ranh giới giảng dạy

Chương này đưa ra ba điều sau:

  1. Mẫu tự đăng ký -- các tập tin công cụ tự đăng ký; lớp điều phối chỉ nhập chúng
  2. Chuỗi nhập khẩu -- sổ đăng ký <- công cụ <- model_tools <- run_agent; không bao giờ đảo ngược
  3. Cầu không đồng bộ -- is_async cờ + vòng lặp sự kiện liên tục

Cố tình bỏ qua: quyền (s09), MCP (s16), mối quan hệ giữa kỹ năng và công cụ (s08).

Thêm một công cụ có nghĩa là thêm một tập tin duy nhất -- nếu bạn có thể làm được điều đó, bạn đã hoàn thành chương này.

Mục lục nguồn