
Tối ưu mô hình tác nhân Claude: Nâng cao hiệu suất làm việc AI
Một lập trình viên bận rộn muốn tự động hóa quy trình kiểm thử code của mình. Anh ta đã nghe nói về khả năng của Claude trong việc tạo ra các tác nhân thông minh, nhưng không chắc chắn làm thế nào để triển khai chúng một cách hiệu quả để tiết kiệm hàng giờ làm việc mỗi tuần.
Viết unit test hay review pull request là những công việc tốn thời gian nhưng lại quan trọng. Nếu bạn từng nghĩ đến việc giao chúng cho AI, thì "tác nhân" (agent) chính là câu trả lời. Khác với chatbot chỉ sinh văn bản, tác nhân Claude có thể chủ động dùng tool, gọi API và thực hiện các chuỗi lệnh phức tạp. Bài viết này sẽ hướng dẫn bạn từ bước setup môi trường, xây dựng agent tự viết unit test, cho đến nâng cấp nó để review code tự động trên GitHub.
Mô hình tác nhân (Agent) là gì, dưới góc nhìn của dev?
Với lập trình viên, một mô hình tác nhân (AI Agent) không chỉ là chatbot sinh văn bản. Mình hình dung nó như một vòng lặp liên tục: suy nghĩ, chọn công cụ phù hợp, thực thi công cụ đó và quan sát kết quả. Đây là một bước tiến đáng kể so với việc chỉ gọi API của các mô hình ngôn ngữ lớn (LLM) đơn thuần.
Sự khác biệt cốt lõi của agent nằm ở khả năng thực hiện hành động (action) thông qua các "tool" mà bạn cung cấp. Thay vì chỉ trả về một đoạn text, agent có thể yêu cầu hệ thống của bạn chạy một hàm cụ thể. Ví dụ, nó có thể yêu cầu hàm `getWeather(city: string)` để lấy thông tin thời tiết, hoặc một script Python để tương tác với API của Jira.
Điều quan trọng cần nhớ là Claude hay bất kỳ LLM nào cũng không tự chạy code. Chúng chỉ phân tích yêu cầu của bạn, xác định tool cần dùng, và tạo ra lời gọi tool với đúng tham số. Công việc của bạn là xây dựng các tool này và một "agent runtime" để nhận yêu cầu từ Claude, thực thi tool, sau đó trả kết quả về cho Claude xử lý tiếp.
Các tác nhân AI tự động đang được dự báo sẽ trở thành một thị trường lớn, có thể đạt vài tỷ USD vào năm 2026 và tăng trưởng mạnh mẽ hơn nữa vào năm 2030 [F1]. Điều này cho thấy việc đầu tư thời gian tìm hiểu và phát triển kỹ năng với AI agent là rất đáng giá cho các lập trình viên.

🛠️ Setup môi trường: Claude API và Tool-Use trong 15 phút
Để Claude có thể tương tác với thế giới bên ngoài, chúng ta cần thiết lập môi trường phát triển và kết nối với API của Anthropic. Việc này khá đơn giản và mình sẽ hướng dẫn bạn từng bước.
Lấy API Key và cài đặt SDK
Đầu tiên, bạn cần truy cập vào console của Anthropic để lấy API key. Sau khi đăng nhập, bạn sẽ tìm thấy mục API Keys và tạo một khóa mới. Hãy lưu trữ khóa này cẩn thận, vì nó sẽ được dùng để xác thực các yêu cầu của bạn.
Tiếp theo, chúng ta sẽ cài đặt SDK của Anthropic. Mình sẽ minh họa cho cả TypeScript và Python:
# Cho TypeScript (Node.js)
npm install @anthropic-ai/sdk
# Cho Python
pip install anthropicVí dụ "Hello World" với Tool-Use
Bây giờ, chúng ta sẽ tạo một ví dụ đơn giản về việc sử dụng tool. Mình sẽ xây dựng một agent cho phép Claude thực thi lệnh terminal. Điều quan trọng cần nhớ là code thực thi tool (ví dụ: `execSync` trong Node.js) sẽ chạy ở phía client của bạn, không phải trên server của Anthropic. Điều này đảm bảo an toàn và cho phép agent tương tác với môi trường local hoặc mạng nội bộ của bạn.
Hãy xem qua file `agent.ts` hoặc `agent.py` dưới đây. Nó nhận một câu lệnh tự nhiên (ví dụ: 'liệt kê các file trong thư mục hiện tại'), gọi Claude, nhận yêu cầu dùng tool, thực thi lệnh `ls -la`, và trả kết quả lại cho Claude để tóm tắt.
import Anthropic from '@anthropic-ai/sdk';
import { execSync } from 'child_process';
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
async function runAgent(userInput: string) {
const messages: Anthropic.Messages.MessageParam[] = [
{
role: 'user',
content: userInput,
},
];
const response = await anthropic.messages.create({
model: 'claude-3-opus-20240229', // Hoặc model mới nhất
max_tokens: 1024,
messages: messages,
tools: [
{
name: 'execute_terminal_command',
description: 'Executes a terminal command and returns its output.',
input_schema: {
type: 'object',
properties: {
command: {
type: 'string',
description: 'The terminal command to execute.',
},
},
required: ['command'],
},
},
],
});
if (response.stop_reason === 'tool_use') {
const toolUse = response.content.find(block => block.type === 'tool_use');
if (toolUse && toolUse.type === 'tool_use' && toolUse.name === 'execute_terminal_command') {
const command = toolUse.input.command;
try {
const output = execSync(command, { encoding: 'utf8' });
console.log(`Executing command: ${command}`);
console.log(`Output: ${output}`);
messages.push(response.content[0]); // Add tool_use message
messages.push({
role: 'user',
content: [
{
type: 'tool_result',
tool_use_id: toolUse.id,
content: output,
},
],
});
const finalResponse = await anthropic.messages.create({
model: 'claude-3-opus-20240229',
max_tokens: 1024,
messages: messages,
});
console.log('Claude says:', finalResponse.content[0].text);
} catch (error) {
console.error(`Error executing command: ${error.message}`);
messages.push(response.content[0]);
messages.push({
role: 'user',
content: [
{
type: 'tool_result',
tool_use_id: toolUse.id,
content: `Error: ${error.message}`,
},
],
});
const finalResponse = await anthropic.messages.create({
model: 'claude-3-opus-20240229',
max_tokens: 1024,
messages: messages,
});
console.log('Claude says:', finalResponse.content[0].text);
}
}
} else {
console.log('Claude says:', response.content[0].text);
}
}
runAgent('liệt kê các file trong thư mục hiện tại');Với đoạn code trên, bạn đã có một agent cơ bản có khả năng thực thi lệnh terminal. Đây là nền tảng để bạn mở rộng sang các công cụ phức tạp hơn, giúp Claude tương tác sâu hơn với môi trường làm việc của bạn.
Xây dựng tác nhân đầu tiên: Tự động tạo Unit Test cho code
Để bắt đầu xây dựng tác nhân AI, mình sẽ giải quyết một bài toán quen thuộc với dev: tự động hóa việc viết unit test. Đây là một công việc lặp đi lặp lại và tốn thời gian, nhưng lại cực kỳ quan trọng để đảm bảo chất lượng code.
Đầu tiên, chúng ta cần định nghĩa một tool để Claude có thể tương tác với hệ thống file. Tool này có tên `write_file` và sẽ cho phép Claude ghi nội dung vào một file cụ thể trên đĩa. Mình định nghĩa tool này bằng JSON Schema để Claude hiểu rõ các tham số cần thiết.
{
"name": "write_file",
"description": "Ghi nội dung vào một file.",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Đường dẫn file (ví dụ: src/utils/myFunction.ts)"
},
"content": {
"type": "string",
"description": "Nội dung cần ghi vào file"
}
},
"required": ["path", "content"]
}
}Tiếp theo, mình sẽ viết một system prompt chi tiết. Prompt này yêu cầu Claude đóng vai một lập trình viên Senior, chuyên viết test bằng Jest cho TypeScript. Điều này giúp Claude tập trung vào đúng vai trò và tạo ra code test chất lượng.
const systemPrompt = `
You là một lập trình viên TypeScript Senior. Nhiệm vụ của bạn là viết unit test sử dụng Jest.
Hãy đảm bảo test case bao phủ đầy đủ các trường hợp biên, các luồng dữ liệu chính và các lỗi tiềm ẩn.
Bạn chỉ được trả về lời gọi tool 'write_file' để tạo file test.
`;Sau đó, mình cung cấp một function TypeScript phức tạp làm input cho Claude. Đây là function mà Claude cần viết unit test. Toàn bộ prompt gửi đến Claude sẽ bao gồm system prompt, định nghĩa tool và code của function cần test.
const userCode = `
function calculateDiscount(price: number, discountPercentage: number): number {
if (price < 0 || discountPercentage < 0 || discountPercentage > 100) {
throw new Error('Invalid input: Price and discount percentage must be valid.');
}
const discountAmount = price * (discountPercentage / 100);
return price - discountAmount;
}
export { calculateDiscount };
`;
// Toàn bộ prompt gửi đến Claude:
// systemPrompt + JSON.stringify(tool_definition) + userCodeKhi nhận được prompt này, Claude sẽ phân tích và trả về một yêu cầu sử dụng tool `write_file`. Path sẽ là `__tests__/calculateDiscount.test.ts` và content là code unit test hoàn chỉnh, đã được Claude tự động tạo ra dựa trên logic của function `calculateDiscount`.
// Ví dụ về response từ Claude (dạng tool_use block):
// {
// "type": "tool_use",
// "id": "toolu_01A09C0D9E0F1G2H3I4J5K6L7M8N9O",
// "name": "write_file",
// "input": {
// "path": "__tests__/calculateDiscount.test.ts",
// "content": "import { calculateDiscount } from '../src/calculateDiscount';\n\ndescribe('calculateDiscount', () => {\n // ... code test do Claude tạo ra ...\n});"
// }
// }Phía client, chúng ta cần có code để xử lý response này. Khi nhận được `tool_use` block, client sẽ trích xuất `path` và `content`, sau đó thực sự tạo file test trên đĩa cứng. Điều này hoàn tất chu trình tự động hóa.
import fs from 'fs';
async function handleClaudeResponse(response: any) {
if (response.type === 'tool_use' && response.name === 'write_file') {
const { path, content } = response.input;
fs.writeFileSync(path, content);
console.log(`Đã tạo file test: ${path}`);
}
}Chất lượng code test do AI tạo ra thường rất tốt cho các trường hợp cơ bản và biên. Tuy nhiên, vai trò review của con người vẫn cực kỳ quan trọng. Mình luôn khuyến nghị dev nên xem lại các test case, bổ sung những trường hợp phức tạp hoặc đặc thù mà AI có thể bỏ qua. Đây là cách tốt nhất để tận dụng sức mạnh của AI mà vẫn đảm bảo tính chính xác và độ tin cậy của phần mềm.

Nâng cấp tác nhân: Review Pull Request tự động trên GitHub
Sau khi đã làm quen với các tác nhân đơn giản, chúng ta cùng đi sâu vào một kịch bản phức tạp hơn: tự động review Pull Request (PR) trên GitHub. Kịch bản này đòi hỏi tác nhân phải sử dụng nhiều công cụ và thực hiện nhiều bước suy luận (multi-step reasoning) để hoàn thành nhiệm vụ.
Để thực hiện tác vụ này, mình định nghĩa một bộ ba công cụ cần thiết. Mỗi công cụ có một JSON schema riêng để Claude hiểu cách gọi và các tham số cần truyền vào.
[
{
"name": "get_pr_diff",
"description": "Lấy nội dung diff của một Pull Request từ URL.",
"input_schema": {
"type": "object",
"properties": {
"pr_url": {
"type": "string",
"description": "URL đầy đủ của Pull Request."
}
},
"required": ["pr_url"]
}
},
{
"name": "analyze_code_for_issues",
"description": "Phân tích đoạn mã để tìm các vấn đề dựa trên một bộ quy tắc.",
"input_schema": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Đoạn mã cần phân tích."
},
"rules": {
"type": "array",
"items": {
"type": "string"
},
"description": "Danh sách các quy tắc hoặc tiêu chí để phân tích."
}
},
"required": ["code", "rules"]
}
},
{
"name": "post_github_comment",
"description": "Đăng một bình luận lên Pull Request trên GitHub.",
"input_schema": {
"type": "object",
"properties": {
"pr_url": {
"type": "string",
"description": "URL đầy đủ của Pull Request."
},
"comment": {
"type": "string",
"description": "Nội dung bình luận."
}
},
"required": ["pr_url", "comment"]
}
}
]Luồng hoạt động của tác nhân review PR sẽ diễn ra theo các bước sau. Đầu tiên, bạn cung cấp URL của Pull Request cho tác nhân. Sau đó, tác nhân sẽ gọi công cụ `get_pr_diff` để lấy về toàn bộ nội dung thay đổi của PR đó. Khi đã có code diff, tác nhân tiếp tục gọi `analyze_code_for_issues`.
Công cụ `analyze_code_for_issues` sẽ nhận code diff và một danh sách các quy tắc được định sẵn trong prompt (ví dụ: 'kiểm tra console.log còn sót', 'đảm bảo có xử lý lỗi cho promise'). Sau khi phân tích, nó trả về danh sách các vấn đề tìm được. Cuối cùng, tác nhân sử dụng công cụ `post_github_comment` để đăng các vấn đề này dưới dạng bình luận trên PR.
Đoạn code ví dụ dưới đây minh họa cách client xử lý vòng lặp tool-use này, nơi tác nhân tự động gọi các công cụ và xử lý kết quả để hoàn thành nhiệm vụ phức tạp.
def review_pull_request(pr_url: str, rules: list[str]):
# Bước 1: Lấy diff của PR
diff = call_tool("get_pr_diff", {"pr_url": pr_url})
if not diff:
return "Không thể lấy diff của PR."
# Bước 2: Phân tích code dựa trên các quy tắc
issues = call_tool("analyze_code_for_issues", {"code": diff, "rules": rules})
if not issues:
comment = "Không tìm thấy vấn đề nào dựa trên các quy tắc đã cho."
else:
comment = "Các vấn đề được tìm thấy:\n" + "\n".join(issues)
# Bước 3: Đăng bình luận lên GitHub
result = call_tool("post_github_comment", {"pr_url": pr_url, "comment": comment})
return resultCần lưu ý rằng các tác vụ nhiều bước như review PR tự động sẽ tiêu tốn nhiều token và thời gian xử lý hơn so với các tác vụ đơn giản. Do đó, bạn cần cân nhắc kỹ khi lựa chọn mô hình phù hợp và tối ưu hóa prompt để giảm thiểu chi phí và độ trễ.
📊 Chọn model Claude nào cho tác vụ Agent: Haiku, Sonnet, hay Opus?
Khi xây dựng tác nhân AI, việc lựa chọn model Claude phù hợp là rất quan trọng để cân bằng giữa hiệu suất và chi phí. Mỗi phiên bản Claude – Haiku, Sonnet, và Opus – đều có những ưu điểm riêng, phục vụ các tác vụ tác nhân khác nhau.
Claude Haiku thường là lựa chọn tốt cho các tác vụ nhanh, cần phản hồi tức thì và không đòi hỏi suy luận phức tạp. Đây là model lý tưởng cho các tác nhân cần xử lý lượng lớn dữ liệu đầu vào hoặc thực hiện các hành động đơn giản, lặp đi lặp lại.
Claude Sonnet mang lại sự cân bằng giữa tốc độ và khả năng suy luận. Mình thường dùng Sonnet cho các tác nhân cần phân tích dữ liệu ở mức độ trung bình, đưa ra quyết định dựa trên nhiều yếu tố hoặc tương tác với các công cụ bên ngoài. Sonnet phù hợp cho các tác vụ như tóm tắt tài liệu, phân loại email, hoặc quản lý quy trình làm việc.
Claude Opus là model mạnh mẽ nhất, phù hợp cho các tác vụ tác nhân đòi hỏi suy luận sâu, lập kế hoạch phức tạp và hiểu biết ngữ cảnh rộng. Đây là lựa chọn hàng đầu cho các tác nhân cần giải quyết vấn đề đa bước, viết code phức tạp, hoặc thực hiện nghiên cứu chuyên sâu. Model Claude 4 được công nhận là một trong những LLM hàng đầu năm 2025, với 200.000 token và 2.5-3 nghìn tỷ tham số [F4].
Mặc dù Claude Opus rất mạnh, nhưng có những trường hợp các model khác vượt trội. Ví dụ, Gemini 3 Deep Think đạt 84.6% trên các điểm chuẩn ARC-AGI-2, vượt trội so với Claude Opus 4.6 với 68.8% [F5]. Điều này cho thấy việc đánh giá hiệu suất trên các benchmark cụ thể là cần thiết. Đến năm 2026, khoảng hai phần ba chu kỳ tính toán AI dự kiến sẽ dành cho suy luận (inference) thay vì đào tạo (training) [F2], nên việc tối ưu model cho tác vụ tác nhân sẽ ngày càng quan trọng.
Tóm lại, tác nhân Claude là công cụ thực tế để tự động hóa workflow của dev, từ viết test đến review PR. Việc chọn đúng model giữa Haiku, Sonnet, và Opus sẽ quyết định sự cân bằng giữa chi phí và tốc độ. Bạn có thể xem lại video gốc để hình dung rõ hơn về quá trình debug.