0

Hướng dẫn chi tiết tự động hóa tác vụ bằng Function Calling

Trong thế hệ AI Agent hiện nay, việc mô hình có thể tự thực thi hành động thay vì chỉ phản hồi văn bản là bước tiến lớn trong tự động hóa. Một trong những cơ chế giúp điều đó trở nên khả thi chính là Function Calling, tính năng cho phép LLM gọi các hàm do bạn định nghĩa, để thực hiện những tác vụ thực tế như truy xuất dữ liệu, gửi email, hoặc kích hoạt workflow tự động.

Bài viết này dành cho developer, hướng dẫn cách định nghĩa, xử lý và triển khai Function Calling trên OpenAI API và Ollama, đồng thời chia sẻ các pattern, kinh nghiệm và biện pháp bảo mật trong môi trường sản xuất.

Khái niệm Function Calling

Function Calling giúp mô hình ngôn ngữ (như GPT-4 hoặc Ollama) hiểu được rằng một yêu cầu của người dùng tương ứng với việc gọi hàm cụ thể. Thay vì trả về text thuần túy, mô hình có thể kích hoạt logic code thật mà bạn đã định nghĩa trước.

Các hành động thường gặp:

  • Gọi API và lấy dữ liệu động.
  • Tạo hoặc chỉnh sửa tệp tin.
  • Thực thi các quy trình tự động: gửi email, ghi log, cập nhật CRM, xử lý đơn hàng...

Nói cách khác, Function Calling chính là giao diện API giữa LLM và hệ thống backend, biến mô hình từ “người trả lời” thành Agent có khả năng hành động. function-calling-17613600048768.png

Cấu trúc hoạt động tổng quan

Luồng cơ bản (Single-Step)

  1. Người dùng nhập câu lệnh tự nhiên.
  2. Model phân tích và quyết định nên gọi hàm nào (function_call).
  3. Ứng dụng backend của bạn thực thi hàm thật (API, DB, CRM…).
  4. Kết quả trả lại cho model để tổng hợp và phản hồi lại người dùng.

Luồng nâng cao (Multi-Step / Agent)

AI có thể lặp nhiều vòng, sau mỗi lần nhận kết quả, model tiếp tục chọn hành động kế tiếp cho đến khi hoàn thành mục tiêu hoặc chạm giới hạn số bước.

Lưu ý rằng mô hình không có khả năng tự truy cập hệ thống, bạn phải định nghĩa rõ hàm nào được phép gọi, với tham số nào, trong phạm vi nào.

Định nghĩa Function bằng JSON Schema (OpenAI)

Bạn cần mô tả từng function với tên, mô tả và kiểu tham số để model hiểu cách gọi đúng:

// functions.js
export const functions = [
  {
    name: "get_weather",
    description: "Truy xuất thời tiết hiện tại theo thành phố",
    parameters: {
      type: "object",
      properties: {
        city: { type: "string", description: "Ví dụ: Hà Nội" },
        unit: { type: "string", enum: ["c", "f"], default: "c" }
      },
      required: ["city"]
    }
  },
  {
    name: "send_email",
    description: "Gửi email xác nhận cho khách hàng",
    parameters: {
      type: "object",
      properties: {
        to: { type: "string", description: "Địa chỉ email người nhận" },
        subject: { type: "string" },
        body: { type: "string" }
      },
      required: ["to", "subject", "body"]
    }
  }
];

Tips khi mô tả hàm:

  • Viết ngắn, mô tả chính xác hành vi.
  • Ghi rõ điều kiện kích hoạt để model route đúng logic.
  • Hạn chế mô tả mơ hồ dễ khiến model gọi sai ngữ cảnh.

Triển khai luồng Function Calling với OpenAI (Node.js)

Ví dụ sau minh họa: người dùng hỏi thời tiết → model gọi get_weather() → hệ thống gọi API thật → trả kết quả → model viết phản hồi hoàn chỉnh.

import OpenAI from "openai";
import { functions } from "./functions.js";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// Logic thật
async function getWeather({ city, unit = "c" }) {
  const data = { city, temp_c: 29, condition: "Nắng nhẹ" };
  return unit === "f" ? { ...data, temp_f: 84.2 } : data;
}

async function sendEmail({ to, subject, body }) {
  return { status: "ok", to, subject };
}

const toolMap = { get_weather: getWeather, send_email: sendEmail };

export async function ask(messages) {
  const resp = await client.chat.completions.create({
    model: "gpt-4o-mini",
    messages,
    functions,
    function_call: "auto",
    temperature: 0.2,
  });

  const msg = resp.choices[0]?.message;

  if (msg?.function_call) {
    const { name, arguments: argsJson } = msg.function_call;
    const args = JSON.parse(argsJson || "{}");
    if (!toolMap[name]) return { role: "assistant", content: "Hàm không tồn tại." };

    const result = await toolMap[name](args);

    const followResp = await client.chat.completions.create({
      model: "gpt-4o-mini",
      messages: [...messages, msg, { role: "function", name, content: JSON.stringify(result) }],
    });

    return followResp.choices[0]?.message;
  }
  return msg;
}

Function Calling cục bộ với Ollama (Python)

Nếu bạn dùng mô hình nội bộ, có thể mô phỏng function calling qua định dạng JSON thủ công:

import json, ollama

def get_time(_args=None):
    return {"now": "2025-10-16 10:30:00"}

TOOLS = {"get_time": get_time}

SYSTEM_HINT = """Bạn là trợ lý có thể gọi công cụ.
Khi cần lấy thời gian, hãy trả JSON:
{"call":"get_time","args":{}}"""

def route_and_call(model, user_text):
    res = ollama.chat(model=model, messages=[
        {"role":"system","content": SYSTEM_HINT},
        {"role":"user","content": user_text}
    ])
    content = res["message"]["content"]

    try:
        blob = json.loads(content)
        if "call" in blob:
            fn, args = blob["call"], blob.get("args", {})
            if fn in TOOLS:
                tool_out = TOOLS[fn](args)
                res2 = ollama.chat(model=model, messages=[
                    {"role":"system","content": SYSTEM_HINT},
                    {"role":"user","content": user_text},
                    {"role":"assistant","content": content},
                    {"role":"system","content": f"Kết quả: {json.dumps(tool_out, ensure_ascii=False)}"}
                ])
                return res2["message"]["content"]
    except Exception:
        pass
    return content

Mẹo: Khi Ollama hoặc model local chưa hỗ trợ tool natively, bạn có thể quy ước format JSON riêng để kiểm soát hành vi. Nên đặt guard bằng regex để tránh injection.

Xác thực dữ liệu và phòng chống Prompt Injection

Model có thể “tự bịa” tham số hoặc bị chèn yêu cầu độc hại. Để đảm bảo an toàn:

  • Validate input bằng Zod (Node.js) hoặc Pydantic (Python).
  • Áp dụng whitelist tên hàm được phép gọi.
  • Không cho phép I/O hệ thống hoặc shell command nếu không có quyền xác thực.
import { z } from "zod";
const SendEmailSchema = z.object({
  to: z.string().email(),
  subject: z.string().min(1),
  body: z.string().min(1)
});

async function sendEmailSafe(args) {
  const parsed = SendEmailSchema.safeParse(args);
  if (!parsed.success) throw new Error("Invalid arguments");
  return sendEmail(parsed.data);
}

Logging & Testing

Luôn theo dõi hoạt động function bằng log có cấu trúc:

console.log(JSON.stringify({
  level: "info",
  event: "tool_call",
  fn: name,
  args,
  ts: Date.now()
}));

Gợi ý test thực tế:

  • Đúng function được gọi theo intent (“thời tiết” → get_weather).
  • Không gọi function thiếu dữ liệu.
  • Dừng sau N bước để tránh loop.
  • Lưu lại cặp (messages, tool_result) để replay khi nâng cấp model.

Pattern triển khai phổ biến

  • Single-Tool Router: Tối ưu prompt cho 1–3 tool chính.
  • ReAct + Function Calling: Cho chuỗi hành động phức tạp (phân tích – gọi hàm – quan sát – lặp lại).
  • Guarded Tools: Tool nhạy cảm yêu cầu xác nhận hai bước.
  • Caching Tool Results: Lưu kết quả tạm để tiết kiệm token & latency.

Case thực tế – Tự động hóa CRM

Ví dụ quy trình “tạo lead → gửi email chào mừng”:

  1. Model trích ý định và gọi create_lead({name, email}).
  2. Backend tạo lead trên BizCRM.
  3. Sau khi có leadId, model gọi send_email().
  4. BizMail gửi email xác nhận.
  5. Model phản hồi: “Đã tạo lead #1001 và gửi email chào mừng.”

Khi kết hợp streaming (SSE), bạn có thể hiển thị tiến trình thời gian thực như “Đang tạo lead…”, “Đã gửi email…”, giúp UX thân thiện và minh bạch.

Bảo mật và tối ưu

  • Giới hạn rate limit & quota theo user.
  • Thiết lập RBAC (role-based access control).
  • Lưu audit log ít nhất 90 ngày.
  • Mã hóa dữ liệu cá nhân (email, số điện thoại).
  • Dùng model nhẹ cho routing (gpt-4o-mini, llama-3-8b), model lớn chỉ khi cần ngữ nghĩa cao cấp.
  • Đặt system prompt rõ ràng để giảm vòng lặp → tiết kiệm token.

Checklist triển khai nhanh

  • Xác định các tác vụ cần tự động hóa (CRUD, Email, Ticket, CRM...).
  • Viết function schema ngắn, dễ hiểu.
  • Áp dụng validation & whitelist.
  • Dựng hệ thống log + replay test.
  • Giới hạn vòng lặp (max_steps, timeout).
  • Viết prompt hệ thống mô tả điều kiện gọi hàm rõ ràng.

Kết luận

Function Calling là chìa khóa giúp AI Agent thực sự hành động trong thế giới thực. Khi được triển khai đúng chuẩn với schema rõ ràng, validation nghiêm ngặt, logging và bảo mật, bạn có thể biến bất kỳ workflow nào thành quy trình tự động an toàn và có thể kiểm soát, dù là trên nền tảng OpenAI hay Ollama.

Nguồn tham khảo: https://bizfly.vn/techblog/huong-dan-chi-tiet-tu-dong-hoa-tac-vu-qua-function-calling.html


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí