Series 2 - Bài 2: JSON Schema là ngôn ngữ LLM dùng hiểu tool

LLM đọc JSON Schema để hiểu tool — giống như developer đọc API docs. Chất lượng schema quyết định LLM có dùng đúng tool không. Bài này phân tích anatomy của schema tốt và các anti-patterns.

5 phút đọc
Tập này đang được chuẩn bị, quay lại sau nhé.

JSON Schema trong tool definition không phải chỉ là validation spec. Đây là documentation mà LLM sẽ đọc để quyết định: có nên dùng tool này không, khi nào dùng, và truyền gì vào.

Chất lượng schema ảnh hưởng trực tiế đến behavior của agent.

Anatomy của một Tool Definition

┌────────────────────────────────────────────────────────────┐
│  Tool Definition                                          │
│                                                          │
│  name: "read_file"                                       │
│    └─ LLM dùng tên này khi gọi tool                      │
│    └─ Phải unique trong registry                         │
│    └─ Snake_case, mô tả action (động từ + noun)         │
│                                                          │
│  description: "Read the content of a file..."           │
│    └─ LLM đọc để quyết định có nên dùng không         │
│    └─ Phải rõ khi nào nên dùng, khi nào không          │
│    └─ Quan trọng hơn name                               │
│                                                          │
│  input_schema:                                           │
│    type: "object"                                        │
│    properties:                                           │
│      path:                                               │
│        type: "string"                                    │
│        description: "Absolute or relative path..."      │
│      encoding:                                           │
│        type: "string"                                    │
│        enum: ["utf8", "base64"]                          │
│        default: "utf8"                                   │
│    required: ["path"]                                    │
└────────────────────────────────────────────────────────────┘

Description là phần quan trọng nhất

Nhiều developer tập trung vào schema structure và bỏ qua description. Đầu tư vào description cho ROI cao hơn nhiều.

LLM đọc description để quyết định:

  • Tool này làm gì?
  • Khi nào nên dùng cái này thay vì tool khác?
  • Có side effects không?
  • Giới hạn là gì?
Weak description:
  name: "run_command"
  description: "Run a shell command"

  Problem: LLM không biết:
  - Command nào được phép?
  - Có cần confirm không?
  - Side effects như thế nào?

Strong description:
  name: "run_command"
  description: "Execute a shell command in the project
    working directory. Use for: running tests (npm test,
    jest), type checking (tsc --noEmit), linting. Do NOT
    use for commands that modify system state outside the
    project (rm, sudo, git push). Commands with
    significant side effects require user confirmation."

  LLM biết chính xác:
  - Dùng khi nào
  - Tránh khi nào
  - Expectation về confirmation

Parameter Descriptions

Mỗi parameter cũng cần description riêng:

Weak:
  properties:
    path:
      type: string

Strong:
  properties:
    path:
      type: string
      description: "File path relative to project root
        or absolute. Examples: 'src/user.service.ts',
        './config/database.ts', '/project/package.json'.
        Do not use ~ for home directory."

LLM sẽ dùng description để format input đúng cách. Nếu description chưa nói rõ format, LLM gứ — đôi khi đúng, đôi khi sai.

Enum và Constraints giúp LLM đưa ra better decision

Thay vì:
  encoding:
    type: string
    description: "Encoding to use"

Dùng:
  encoding:
    type: string
    enum: ["utf8", "base64", "hex"]
    default: "utf8"
    description: "File encoding. Use utf8 for text files,
      base64 for binary files (images, PDFs)."

enum giới hạn LLM đến valid values. Không có enum, LLM có thể gửi "UTF-8", "utf-8", "UTF8" — tất cả sai format mà code bạn expect.

default cho LLM biết không cần specify parameter nếu dùng case phổ biến, giảm noise trong tool calls.

Required vs Optional: Thiết kế cẩn thận

Required parameters:
  Làm required khi không có reasonable default
  LLM sẽ luôn phải cung cấp
  → Validation error nếu thiếu

Optional parameters:
  Có default hoặc không luôn cần
  LLM chỉ specify khi cần override
  → Giảm cognitive load cho LLM

Anti-pattern: quá nhiều required parameters
  read_file(path, encoding, maxBytes, skipBOM, normalize)
  → LLM phải specify 5 thứ cho một file read
  → Thấy phức tạp → có thể chọn tool khác

Tool Naming: Convention quan trọng

Pattern: {verb}_{noun} hoặc {verb}_{noun}_{qualifier}

Good:
  read_file
  write_file
  list_directory
  run_command
  search_files
  get_git_status

Bad:
  file        ← không rõ action
  fileOps     ← quá generic
  handleFile  ← "handle" không có nghĩa
  doSomething ← useless

LLM dùng tên tool để reason về các lựa chọn. Tên rõ ràng = nhất quán hơn trong việc chọn tool đúng.

Disambiguating Similar Tools

Khi có nhiều tools tương tự, descriptions phải explicit về sự khác biệt:

search_files:
  description: "Search for files by name pattern or
    file type. Use when you know what FILE to look
    for but not where it is. Example: find all
    *.service.ts files."

grep_content:
  description: "Search for text patterns within
    file contents. Use when you know WHAT TEXT to
    look for but not which file contains it.
    Example: find all usages of processPayment."

Không có sự rõ ràng này, LLM sẽ dùng sai tool hoặc gọi cả hai khi chỉ cần một.

Schema như Documentation: Quy trình viết

Quy trình tốt nhất để viết tool definition:

1. Viết description như viết README cho team member

2. Hỏi: "Nếu team member chỉ đọc description này,
   họ có biết khi nào dùng và khi nào không không?"

3. Nếu không → rõ hơn

4. Kiểm tra: Gửi tool definition cho LLM với một
   vài task examples. LLM có chọn đúng tool không?
   Có truyền đúng parameters không?

Trade-off: Verbose vs Concise Schema

Verbose schema:
  + LLM nhất quán hơn, ít lỗi hơn
  - Tốn nhiều token (schema được gửi trong mỗi request)
  - Maintain phức tạp hơn

Concise schema:
  + Token efficient
  - LLM có thể misinterpret
  - Nhiều unexpected behavior hơn

Midpoint tốt nhất:
  Description: 2-4 câu rõ ràng về purpose và when-to-use
  Parameters: description ngắn cho mỗi param, enum khi có finite options
  Không verbose hơn cần thiết

Kết luận

  • JSON Schema là documentation cho LLM, không chỉ là validation spec.
  • Description quan trọng hơn tên tool — LLM đọc để quyết định khi nào dùng.
  • Enum giới hạn LLM vào valid values, giảm sai format.
  • Similar tools cần explicit disambiguation trong description.
  • Viết schema như viết README — nếu team member hiểu, LLM cũng sẽ hiểu.
  • Balance verbosity với token cost — 2-4 câu description là sweet spot.