90% mã nguồn tại Anthropic được viết bởi các agent Claude. Không phải do kỹ sư gõ trong cửa sổ chat. Mà là các agent tự động chạy vòng lặp, gọi công cụ và đẩy mã nguồn trong khi nhóm đang ngủ.
Theo dõi Substack của tôi để nhận thông tin AI mới nhất:
Đây là thiết lập chính xác. Từng bước một. Từ lần gọi API đầu tiên đến một agent hoạt động mà bạn có thể giao bất kỳ tác vụ nào.
Bài viết này sẽ đề cập:
1 - tại sao hầu hết "agent" mọi người xây dựng không phải là agent
2 - 5 phần mà mọi agent hoạt động cần có
3 - cách xây dựng từng phần với Claude, kèm mã nguồn
4 - những sai lầm giết chết agent trước khi chúng được đưa vào sử dụng
Đánh dấu trang này. Mọi khối mã bên dưới đều hoạt động.
01. Hầu hết "AI agent" không phải là agent
Tôi đã xây dựng và phá hỏng nhiều agent hơn tôi có thể đếm. Đã chứng kiến chúng đốt token suốt đêm và chẳng tạo ra gì. Chứng kiến chúng viết lại cùng một tệp 30 lần. Chứng kiến chúng vượt qua bài kiểm tra của chính mình bằng cách xóa bài kiểm tra đó.

Mỗi thất bại đều dạy tôi cùng một bài học: mô hình không phải là vấn đề. Kiến trúc xung quanh nó mới là vấn đề. Hướng dẫn này là tất cả những gì tôi học được, được nén lại thành con đường ngắn nhất tôi có thể đưa cho bạn.
Đây là những gì hầu hết mọi người xây dựng khi họ nói "AI agent":
1while True:2 user_input = input("> ")3 response = call_claude(user_input)4 print(response)
Đó là một chatbot. Nó chờ bạn. Nó làm theo những gì bạn nói. Nó quên mọi thứ giữa các phiên. Khi bạn đóng tab, nó dừng lại.
Một agent là một hệ thống hoạt động hướng tới một mục tiêu mà không cần bạn ngồi trước nó. Nó khám phá những gì cần làm, lập kế hoạch, thực thi, kiểm tra kết quả, và nếu chưa xong - nó thử lại. Bạn đặt hướng đi. Agent làm công việc.
"Claude Code đã từ con số 0 lên doanh thu 400 triệu đô la trong vài tháng. Nó bắt đầu như một dự án hackathon. Nó vẫn chỉ sử dụng public API." -
Boris Cherny, Trưởng nhóm Claude Code
Cùng API mà bạn có quyền truy cập ngay bây giờ. Cùng mô hình. Sự khác biệt là kiến trúc xung quanh mô hình.

02. 5 phần của một agent thực thụ
Mọi agent hoạt động - Claude Code, Devin, Codex, hay bất cứ thứ gì bạn tự xây dựng - đều được lắp ráp từ năm phần. Thiếu một là hỏng.

03. Tầng API
Mọi thứ bắt đầu từ đây. Bạn gọi Claude, Claude trả lời. Nhưng cách bạn gọi nó quyết định bạn có được một chatbot hay một agent.

Ba điều quan trọng: system prompt, đầu ra có cấu trúc và temperature.
System prompt không phải là lời chào. Nó là sổ tay vận hành của agent bạn. Mọi quy tắc, ràng buộc và hành vi đều được đặt ở đây. Nếu không có nó, Claude sẽ đoán bạn muốn gì. Có nó, Claude sẽ tuân theo đặc tả của bạn.
1import anthropic23client = anthropic.Anthropic()45response = client.messages.create(6 model="claude-sonnet-4-6",7 max_tokens=4096,8 system="""Bạn là một agent đánh giá mã nguồn.910Quy tắc:11- Đọc toàn bộ diff trước khi bình luận12- Chỉ gắn cờ lỗi thực sự, không phải sở thích về phong cách13- Nếu không có gì sai, hãy nói "LGTM" và dừng lại14- Không bao giờ đề xuất thay đổi mà bạn chưa kiểm tra trong đầu15- Định dạng đầu ra: mảng JSON gồm {file, line, issue, fix}""",16 messages=[{"role": "user", "content": diff_content}]17)
Đầu ra có cấu trúc giúp phản hồi của agent có thể đọc được bằng máy. Nếu Claude trả về văn bản tự do, mã của bạn phải phân tích cú pháp nó. Nếu Claude trả về JSON, mã của bạn có thể sử dụng trực tiếp.
1# Buộc đầu ra JSON bằng cách cho Claude biết hình dạng chính xác2system = """Chỉ trả về JSON hợp lệ. Không markdown. Không giải thích.3Schema:4{5 "status": "pass" | "fail",6 "issues": [{"file": str, "line": int, "issue": str}],7 "summary": str8}"""
Temperature. Đặt nó về 0 cho các agent xác định. Đặt từ 0.3-0.5 cho công việc sáng tạo. Mặc định (1.0) thêm tính ngẫu nhiên mà bạn hầu như không bao giờ muốn trong một agent.
04. Công cụ
Một mô hình không có công cụ có thể suy luận nhưng không thể hành động. Nó có thể cho bạn biết tệp nào cần sửa nhưng không thể sửa nó. Nó có thể mô tả một truy vấn nhưng không thể chạy nó.

Tính năng sử dụng công cụ của Claude cho phép bạn định nghĩa các hàm mà mô hình có thể gọi. Bạn mô tả hàm. Claude quyết định khi nào gọi nó. Bạn thực thi nó và trả về kết quả. Claude sử dụng kết quả để tiếp tục suy luận.
1tools = [{2 "name": "run_sql",3 "description": "Thực hiện một truy vấn SQL chỉ đọc trên cơ sở dữ liệu",4 "input_schema": {5 "type": "object",6 "properties": {7 "query": {8 "type": "string",9 "description": "Truy vấn SQL SELECT để thực thi"10 }11 },12 "required": ["query"]13 }14},15{16 "name": "write_file",17 "description": "Ghi nội dung vào một tệp trên đĩa",18 "input_schema": {19 "type": "object",20 "properties": {21 "path": {"type": "string"},22 "content": {"type": "string"}23 },24 "required": ["path", "content"]25 }26}]
Mô tả công cụ quan trọng hơn bạn nghĩ. Claude đọc nó để quyết định khi nào và cách sử dụng công cụ. Mô tả mơ hồ dẫn đến các lệnh gọi sai. Mô tả chính xác dẫn đến các lệnh gọi chính xác.
Bắt đầu với 3-5 công cụ. Đọc tệp, ghi tệp, chạy lệnh, tìm kiếm và một công cụ dành riêng cho trường hợp sử dụng của bạn. Điều đó bao phủ 90% tác vụ của agent.

05. Vòng lặp
Đây là phần biến một tập lệnh thành một agent. Nếu không có vòng lặp, mã của bạn gọi Claude một lần và dừng lại. Có vòng lặp, mã của bạn gọi Claude, kiểm tra kết quả và gọi lại cho đến khi công việc hoàn thành.

Ba thành phần:
- Trình xác minh. Thứ kiểm tra xem đầu ra có tốt không. Một bộ kiểm thử, một trình kiểm tra kiểu, một trình linter, một lần gọi Claude thứ hai với tiêu chí nghiêm ngặt. Nếu không có cái này, bạn có agent tự đồng ý với chính nó lặp đi lặp lại.
- Trạng thái. Bản ghi về những gì đã xảy ra. Cái gì đã hoạt động, cái gì thất bại, cái gì cần thử tiếp theo. Nếu không có trạng thái, agent mắc cùng một sai lầm ở mỗi lần.
- Điều kiện dừng. Mục tiêu đã đạt được, hoặc một giới hạn cứng nói "sau N lần, dừng lại và báo cáo." Nếu không có cái này, vòng lặp chạy mãi mãi và tiêu hết tài khoản của bạn.
1import json2from pathlib import Path34def run_agent(task: str, max_attempts: int = 5):5 state = {"task": task, "attempts": [], "done": False}67 for i in range(max_attempts):8 # Build context from state9 context = build_prompt(state)1011 # Call Claude with tools12 result = call_claude(context, tools)1314 # Execute any tool calls15 output = execute_tools(result)1617 # Verify the result18 check = verify(output)1920 # Update state21 state["attempts"].append({22 "attempt": i + 1,23 "action": result.summary,24 "passed": check.passed,25 "reason": check.reason26 })2728 if check.passed:29 state["done"] = True30 break3132 # Save state for next run33 Path("state.json").write_text(json.dumps(state, indent=2))34 return state
Đây là bộ xương hoàn chỉnh. Mọi agent trong sản xuất đều là một biến thể của mẫu này. Chi tiết thay đổi. Hình dạng thì không.
06. Bộ nhớ
Nếu không có bộ nhớ, mọi phiên đều bắt đầu từ con số không. Agent khám phá lại cấu trúc dự án của bạn. Học lại các quy ước của bạn. Mắc lại những sai lầm nó đã mắc ngày hôm qua.

Các agent Claude sử dụng ba lớp bộ nhớ:
CLAUDE.md là một tệp markdown tại thư mục gốc của dự án bạn. Claude Code tự động đọc nó khi bắt đầu mỗi phiên. Quy tắc của bạn, ngăn xếp công nghệ của bạn, các quy ước của bạn. Viết một lần, đọc mãi mãi.
1# CLAUDE.md23## Dự án4API quản lý tác vụ. Python 3.12, FastAPI, PostgreSQL.56## Quy tắc7- Tất cả phản hồi: schema {data, error, meta}8- Yêu cầu kiểm thử cho mọi endpoint mới9- Tin nhắn commit: type(scope): description10- Không bao giờ dùng print() để ghi log. Dùng structlog.1112## Vấn đề đã biết13- Middleware xác thực mong đợi x-auth-token, không phải Authorization14- Bộ kiểm thử mất 45s để chạy đầy đủ. Dùng --filter để lặp.
Kỹ năng nắm bắt toàn bộ quy trình làm việc. Không chỉ prompt - toàn bộ hình dạng: định dạng đầu vào, các bước, định dạng đầu ra, quy tắc xác thực. Lần chạy đầu tiên mất 20 phút. Phát lại mất 30 giây.
Tệp học tập là một nhật ký chạy về các sai lầm. Agent ghi vào nó sau mỗi phiên. Phiên tiếp theo đọc nó. Sai lầm lặp lại cho đến khi chúng được ghi lại. Sau đó chúng dừng lại.
1# learnings.md23- Payment API mong đợi idempotency key trong header, không phải body4- PostgreSQL NOTIFY cần LISTEN rõ ràng trong connection pool5- Bộ giới hạn tốc độ đếm theo key, không theo IP. Kiểm thử cần key duy nhất.
07. Cổng xác minh
Cổng là phần khó xây dựng nhất và dễ bỏ qua nhất. Hầu hết mọi người bỏ qua nó. Đó là lý do tại sao hầu hết agent hỏng trong sản xuất.

Cổng xác minh là thứ kiểm tra công việc của agent mà không để agent tự chấm điểm. Mô hình đã viết mã quá hào phóng khi chấm bài tập của chính nó. Bạn cần một kiểm tra thứ hai.
Ba mẫu hoạt động:
1. Kiểm thử tự động. Agent viết mã. Bộ kiểm thử chạy. Nếu kiểm thử thất bại, agent nhận được đầu ra lỗi và thử lại. Đây là cách Claude Code hoạt động bên trong.
1def verify(output):2 # Run the test suite3 result = subprocess.run(4 ["pytest", "tests/", "-x", "--tb=short"],5 capture_output=True, text=True6 )7 return {8 "passed": result.returncode == 0,9 "reason": result.stdout if result.returncode != 0 else "all tests pass"10 }
2. Trình kiểm tra kiểu / linter. Chạy mypy, ruff hoặc tsc --noEmit sau mỗi thay đổi. Bắt toàn bộ các loại lỗi mà không cần viết một kiểm thử nào.
3. Mô hình thứ hai làm người đánh giá. Sử dụng một lần gọi Claude riêng với system prompt nghiêm ngặt chỉ tìm kiếm vấn đề. Người viết nhanh và rẻ. Người đánh giá chậm và nghiêm ngặt. Sự tách biệt đó là phần lớn chất lượng.
1# Prompt người đánh giá - tách biệt khỏi người xây dựng2reviewer_system = """Bạn là một người đánh giá mã nghiêm khắc.3Công việc DUY NHẤT của bạn là tìm ra vấn đề.45Kiểm tra:6- Mã có đúng với đặc tả không?7- Có các trường hợp ngoại lệ chưa được xử lý không?8- Tất cả kiểm thử có thực sự kiểm tra đúng thứ không?910Nếu mọi thứ đều chính xác, hãy phản hồi: {"passed": true}11Nếu có bất cứ điều gì sai, hãy phản hồi: {"passed": false, "issues": [...]}1213Đừng đề xuất cải tiến. Chỉ gắn cờ các lỗi thực sự."""
Người viết nhanh và rẻ. Người đánh giá chậm và nghiêm ngặt. Sự tách biệt đó là phần lớn chất lượng.
08. Kết hợp tất cả lại với nhau
Đây là một agent hoàn chỉnh nhận URL issue GitHub, đọc issue, viết mã, chạy kiểm thử và mở PR. Năm phần hoạt động cùng nhau.
1import anthropic, subprocess, json2from pathlib import Path34client = anthropic.Anthropic()5CLAUDE_MD = Path("CLAUDE.md").read_text()6LEARNINGS = Path("learnings.md").read_text()78SYSTEM = f"""Bạn là một agent lập trình.9Đọc issue. Viết bản sửa. Chạy kiểm thử.1011Ngữ cảnh dự án:12{CLAUDE_MD}1314Vấn đề đã biết:15{LEARNINGS}1617Quy tắc:18- Đọc toàn bộ mã nguồn trước khi thay đổi bất kỳ điều gì19- Viết kiểm thử cho mọi thay đổi20- Nếu kiểm thử thất bại, sửa mã, không sửa kiểm thử21- Dừng khi tất cả kiểm thử đều đạt"""2223TOOLS = [24 read_file_tool,25 write_file_tool,26 run_command_tool,27 search_codebase_tool,28]2930def run(issue_text, max_attempts=5):31 messages = [{"role": "user", "content": issue_text}]3233 for attempt in range(max_attempts):34 # Call Claude35 response = client.messages.create(36 model="claude-sonnet-4-6",37 max_tokens=8192,38 system=SYSTEM,39 tools=TOOLS,40 messages=messages41 )4243 # Execute tool calls44 messages = handle_tool_use(response, messages)4546 # Verify: run tests47 test_result = subprocess.run(48 ["pytest", "-x", "--tb=short"],49 capture_output=True, text=True50 )5152 if test_result.returncode == 0:53 print(f"Hoàn thành sau {attempt + 1} lần thử")54 return True5556 # Feed failure back into the loop57 messages.append({58 "role": "user",59 "content": f"Kiểm thử thất bại:\n{test_result.stdout}\nSửa và thử lại."60 })6162 return False
Đó là một agent hoạt động. Tầng API với system prompt và CLAUDE.md. Công cụ cho các thao tác tệp. Một vòng lặp với thử lại. Bộ nhớ từ learnings.md. Một cổng xác minh qua pytest.
Dưới 50 dòng. Cùng kiến trúc mà Claude Code sử dụng bên trong.
09. 5 sai lầm phá hỏng mọi agent
- Không có cổng xác minh. Agent tự chấm bài tập của chính nó. Nó viết mã, nói "có vẻ ổn" và tiếp tục. Đầu ra có vẻ đúng nhưng hỏng trong sản xuất.
- Không có điều kiện dừng. Vòng lặp chạy cho đến khi hóa đơn API của bạn là 200 đô la. Nếu không có giới hạn cứng, agent thử lại mãi mãi, viết lại cùng một tệp 40 lần. Luôn đặt max_attempts. Luôn luôn.
- Không có tệp trạng thái. Cùng sai lầm ở lần thử #1 và lần thử #50. Agent không biết nó đã thử những gì. Nó đề xuất cùng một bản sửa lỗi ba lần liên tiếp vì không có gì ghi lại sự thất bại.
- Quá nhiều công cụ. Bạn đưa cho Claude 20 công cụ và nó chọn sai công cụ. Một mô hình với 5 công cụ rõ ràng đưa ra lựa chọn tốt hơn một mô hình với 20 công cụ chồng chéo. Bắt đầu nhỏ. Chỉ thêm công cụ khi agent gặp tường.
- System prompt mơ hồ. "Hãy là một trợ lý lập trình tốt" cho bạn đầu ra chung chung. "Tất cả phản hồi phải là JSON hợp lệ, yêu cầu kiểm thử cho mọi thay đổi, không bao giờ sửa đổi tệp bên ngoài /src" cho bạn một agent có hành vi.
Kết luận:
Một agent hoạt động không phải là một prompt tốt hơn. Nó là một hệ thống: API + công cụ + vòng lặp + bộ nhớ + cổng xác minh. Năm phần. Thiếu một là hỏng.
Hầu hết mọi người sẽ đọc bài này, đánh dấu nó và tiếp tục sử dụng Claude như một chatbot. Họ sẽ dán từng câu hỏi một và sao chép phản hồi vào cơ sở mã của mình bằng tay.
Những người xây dựng vòng lặp sẽ hoàn thành công việc trong khi họ ngủ. Cùng mô hình. Cùng API. Cùng mức giá. Kiến trúc khác.
Các khối mã bên trên đều hoạt động. Sao chép chúng. Chạy chúng. Sửa đổi chúng cho trường hợp sử dụng của bạn.
Hãy xây dựng một agent trong tuần này. Hãy giao cho nó một tác vụ bạn làm mỗi ngày. Để nó chạy.





