# Tool calling và JSON output với các mô hình open-weight

> Gọi hàm với các mô hình open-weight theo định dạng OpenAI: tools, tool_choice, vòng lặp gọi-và-trả lời, và response_format để có đầu ra JSON hợp lệ.

- URL: https://llmwithcrypto.com/vi/docs/tool-calling/
- Cập nhật lần cuối: 2026-10-23
- Đơn vị phát hành: LLMwithCrypto (https://llmwithcrypto.com)

Mô hình có thể yêu cầu code của bạn chạy một hàm, rồi dùng kết quả trong câu trả lời; hoặc nó có thể trả lời bằng một đối tượng JSON mà chương trình của bạn đọc trực tiếp. Cả hai đều dùng định dạng request của OpenAI, và cả hai đều phụ thuộc vào mô hình bạn chọn.

**Trả lời nhanh — Tool calling hoạt động thế nào trên LLMwithCrypto?**

Gửi các hàm của bạn trong `tools`, theo định dạng OpenAI. Khi mô hình muốn gọi một hàm, **LLMwithCrypto** trả về `finish_reason: "tool_calls"` với tên hàm và các đối số JSON; code của bạn chạy nó và gửi kết quả về dưới dạng một message `tool`. Với các câu trả lời có cấu trúc, `response_format: {"type": "json_object"}` yêu cầu JSON hợp lệ. Cả hai đều hoạt động trên các mô hình hỗ trợ chúng, theo tài liệu ngày 23 tháng 10 năm 2026.

## Những mô hình nào hỗ trợ tools và JSON?

Streaming hoạt động trên mọi model; tool calling và JSON output tuân theo những gì từng model tự hỗ trợ.

Hãy kiểm tra schema của riêng bạn trên mô hình bạn định dùng trước khi phụ thuộc vào nó. Một mô hình không hỗ trợ tools sẽ trả lời bằng văn bản thuần thay vì gọi hàm; một mô hình không hỗ trợ JSON mode sẽ trả về lỗi `400` cho `response_format`.

## Vòng lặp là gì?

1. **Mô tả các hàm** — Mỗi tool có một name, một description mà mô hình đọc để quyết định khi nào dùng nó, và parameters dưới dạng JSON Schema.
2. **Gửi cuộc hội thoại kèm tools** — Mô hình hoặc trả lời bằng văn bản, hoặc dừng với finish_reason: "tool_calls" và một hoặc nhiều lệnh gọi trong message.tool_calls.
3. **Chạy từng lệnh gọi** — Parse function.arguments (một chuỗi JSON), chạy hàm của bạn, và đừng bao giờ tin tưởng mù quáng vào các đối số: hãy validate chúng như mọi input từ người dùng.
4. **Gửi kết quả về** — Nối thêm message của assistant, rồi một message tool cho mỗi lệnh gọi với tool_call_id của nó và kết quả dưới dạng văn bản. Gọi lại API; lặp lại cho đến khi mô hình trả lời bằng văn bản.

*Python: một vòng lặp tool hoàn chỉnh với gpt-oss-120b*

```python
import json
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://llmwithcrypto.com/api/v1",
    api_key=os.environ["LLMWITHCRYPTO_API_KEY"],
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_order_status",
            "description": "Return the delivery status of an order.",
            "parameters": {
                "type": "object",
                "properties": {"order_id": {"type": "string"}},
                "required": ["order_id"],
            },
        },
    }
]


def get_order_status(order_id):
    return {"order_id": order_id, "status": "shipped", "eta": "2026-10-25"}


messages = [{"role": "user", "content": "Where is my order A-1042?"}]
while True:
    resp = client.chat.completions.create(model="gpt-oss-120b", messages=messages, tools=tools, max_tokens=300)
    msg = resp.choices[0].message
    if not msg.tool_calls:
        print(msg.content)
        break
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_order_status(**args)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

```

## Một tool call trông thế nào trong response?

Message của assistant không có văn bản, có một mảng `tool_calls`, và lựa chọn kết thúc bằng `finish_reason: "tool_calls"`. Các đối số đến dưới dạng chuỗi JSON, không phải đối tượng. Các id và số lượng bên dưới chỉ mang tính minh họa.

*Response yêu cầu gọi hàm (minh họa)*

```json
{
  "id": "chatcmpl-3c9d27e1",
  "object": "chat.completion",
  "created": 1792742400,
  "model": "gpt-oss-120b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_7f31",
            "type": "function",
            "function": {
              "name": "get_order_status",
              "arguments": "{\"order_id\": \"A-1042\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 118,
    "completion_tokens": 22,
    "total_tokens": 140
  }
}

```

## Làm sao để kiểm soát khi nào tools được dùng?

- **`"tool_choice": "auto"`** (mặc định khi `tools` được đặt): mô hình tự quyết định.
- **`"tool_choice": "none"`**: mô hình trả lời bằng văn bản dù tools đã được liệt kê.
- **`"tool_choice": "required"`**: mô hình phải gọi ít nhất một tool.
- **`{"type": "function", "function": {"name": "get_order_status"}}`**: mô hình phải gọi đúng tool đó.

Mỗi định nghĩa tool được gửi làm input trong mỗi lệnh gọi, nên mô tả dài và nhiều tool sẽ làm tăng input token. Giữ mô tả ngắn và chỉ gửi những tool mà một bước cần.

## Làm sao để nhận về JSON hợp lệ?

Đặt `response_format` thành `{"type": "json_object"}` và mô tả các key mong đợi trong system message: JSON mode đảm bảo rằng câu trả lời parse được, không đảm bảo rằng nó có các key bạn muốn. Giữ `temperature` thấp để đầu ra ổn định và kiểm tra đối tượng đã parse trong code của bạn trước khi dùng.

*Node.js: một câu trả lời JSON với response_format*

```javascript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://llmwithcrypto.com/api/v1',
  apiKey: process.env.LLMWITHCRYPTO_API_KEY,
});

const resp = await client.chat.completions.create({
  model: 'gpt-oss-120b',
  messages: [
    { role: 'system', content: 'Reply with a JSON object {"sentiment": "positive" | "negative" | "neutral", "reason": string}.' },
    { role: 'user', content: 'The delivery was late but support fixed it in an hour.' },
  ],
  response_format: { type: 'json_object' },
  temperature: 0.2,
  max_tokens: 150,
});
const result = JSON.parse(resp.choices[0].message.content);
console.log(result.sentiment, '-', result.reason);

```

## Tools và JSON: các câu hỏi thường gặp

### Tool call có tốn thêm phí không?

Không có phí riêng. Các định nghĩa tool, lệnh gọi và kết quả bạn gửi về đều là token, được tính phí như mọi token khác. Bạn trả tiền theo token từ số dư của mình: token đầu vào và đầu ra được đếm bằng tokenizer của chính model và tính theo giá của model đó trên 1M token. Một lần gọi kết thúc bằng lỗi thì không mất phí.

### Mô hình có thể gọi nhiều tool cùng lúc không?

Một số mô hình trả về nhiều hơn một lệnh gọi trong `tool_calls`. Hãy chạy tất cả và gửi một message `tool` cho mỗi lệnh gọi trước request tiếp theo.

### API có chạy các hàm của tôi không?

Không. Mô hình chỉ nói hàm nào cần gọi và với đối số nào; code của bạn chạy nó. Không có gì được thực thi ở phía chúng tôi, và không có gì của cuộc trao đổi được lưu trữ: Chúng tôi không lưu prompt của bạn hay câu trả lời của model: khi một phản hồi được gửi đi, văn bản của nó biến mất. Mỗi lần gọi để lại một dòng log với thời gian, tài khoản, model và số token, bị xóa sau 30 ngày.

---

LLMwithCrypto: LLMwithCrypto là API LLM tương thích OpenAI cho các mô hình open-weight — DeepSeek V4 Pro, DeepSeek V4.1 Flash, DeepSeek R1, Qwen3.5 397B A17B, Qwen3 235B A22B Instruct, gpt-oss-120b, gpt-oss-20b, GLM-4.7, Llama 3.3 70B Instruct, Gemma 4 31B, Mistral Large 3, Mistral Small 4 — thanh toán theo token từ số dư crypto trả trước, thấp hơn 5% so với giá trung vị của các nhà cung cấp công khai. Không cần KYC: không ID, không selfie, không giấy tờ. Prompt và output không được lưu trữ.
