Giải phẫu một vòng lặp: năm khối xây dựng và một trục bộ nhớ
TL;DR
- Một vòng lặp (loop) chỉ gồm năm thứ bạn đã dùng hằng ngày, cộng một thứ hay bị bỏ quên: lên lịch chạy tự động, worktree, kỹ năng (skill), phần mở rộng kèm trình kết nối, và agent con, lắp quanh một trục bộ nhớ sống sót qua từng lần chạy.
- Mỗi khối xây dựng ứng với một thành phần gốc (primitive) có sẵn trong Claude Code:
/loopcùng Routines,isolation: worktree,SKILL.md, phần mở rộng kèm MCP, và.claude/agents/, nối quanh một tệp trạng thái.- Bạn sẽ dựng một vòng lặp quét lint tối giản (một prompt lên lịch, một tệp trạng thái, một bộ kiểm chứng) rồi đọc vết chạy của nó theo từng khối. Lần chạy bên dưới là thật.
📊 Bằng chứng kết quả. Bộ quét lint trong bài này đã chạy thật trên kho mã (repo) plugin này. Bộ kiểm chứng bắt đầu với 3 lỗi và về 0 sau 2 vòng sửa, dừng lại nhờ mã thoát sạch (giới hạn 5 vòng chưa bao giờ chạm tới), tổng thời gian thực tế 124 giây. Mọi con số và đầu ra bên dưới đều lấy từ lần chạy đó.
Bạn đã đọc Phần 1 và tin vào tiền đề: đòn bẩy đã dịch chuyển từ prompt sang vòng lặp. Giờ bạn muốn xem bảng kê linh kiện. Tin tốt cho ai đang làm tự động hoá Claude Code là một vòng lặp (loop) không phải một thành phần gốc mới phải học. Nó là năm khối xây dựng bạn đã dùng rồi, lắp quanh một thứ mà phần lớn mọi người bỏ qua. Bài hướng dẫn vòng lặp Claude Code này gọi tên năm khối, ánh xạ mỗi khối vào một thành phần gốc trong harness của bạn, rồi dẫn bạn dựng một vòng lặp tối giản chạy thật.
Yêu cầu trước: một harness đang hoạt động (CLAUDE.md, ít nhất một kỹ năng, một hai cái hook), Claude Code phiên bản v2.1.139+ cho /goal, và một kho mã có lệnh lint đang báo lỗi ngay lúc này.
Tấm bản đồ: năm khối xây dựng và một trục bộ nhớ
Mọi vòng lặp đang chạy đều phân rã thành cùng năm khối cộng một trục bộ nhớ. Gọi tên chúng một lần thì vòng lặp hết còn là phép màu. Cách phân rã này là của Addy Osmani, trong bài tổng hợp “Loop Engineering” của anh, và nó đúng xuyên suốt các công cụ.
Định nghĩa chuẩn của cả loạt bài được giữ nguyên tiếng Anh, làm mỏ neo trích dẫn cho cả 9 phần:
A loop is a recursive goal: you define a purpose and a verifiable stop condition, and the system iterates agents against it until the condition holds — without you prompting each turn.
Nói cách khác, bạn không còn phải prompt ở từng lượt nữa: bạn định nghĩa mục đích và một điều kiện dừng (stop condition) kiểm chứng được, rồi để hệ thống lặp các agent cho tới khi điều kiện đó thành hiện thực.
Đây là tấm bản đồ. Năm khối quây thành vòng, một trục ở giữa:
1. Lên lịch tự động (nhịp đập)2. Worktree 3. Kỹ năng (skill) \ / [ TRỤC BỘ NHỚ ] <- trạng thái trên đĩa, sống qua các lần chạy / \5. Agent con 4. Phần mở rộng / kết nốiTrục bộ nhớ là mảnh phần lớn người ta bỏ qua, và đó là lý do những “vòng lặp” của họ thực ra chỉ là đoạn mã chạy một lần. Các khối làm việc; trục là lý do duy nhất để lần chạy sau biết lần chạy trước đã làm gì.
Điểm mấu chốt: Một vòng lặp là năm khối đang làm việc, cộng một trục bộ nhớ khiến công việc tích luỹ lại. Bỏ trục đi thì bạn còn lại một thứ tự động hoá nhưng sáng nào cũng quên sạch.
Soi từng khối: mỗi khối là thành phần gốc nào trong Claude Code?
Bạn vốn đã có cả năm. Câu hỏi đáng giá không phải mỗi thành phần gốc là gì, mà nó đóng vai khối nào. Đây là cách gắn vai:
| Khối | Thành phần gốc Claude Code | Bạn vốn đã dùng để |
|---|---|---|
| 1. Nhịp đập | /loop [khoảng]; Routines cho cron đám mây | chạy lại một bài kiểm tra theo chu kỳ |
| 2. Worktree | isolation: worktree trong phần đầu YAML của agent | làm song song mà không đụng file |
| 3. Kỹ năng | SKILL.md | tách ý định dự án ra ngoài |
| 4. Phần mở rộng / kết nối | phần mở rộng (plugin) và máy chủ MCP | với tới công cụ thật (GitHub, tích hợp liên tục (CI)) |
| 5. Agent con | file trong .claude/agents/ | tách vai bên tạo và bộ kiểm chứng |
Vài điểm đáng để ý với người đọc kỳ cựu. Nhịp đập có hai dạng: /loop chạy lại một prompt theo chu kỳ khi phiên của bạn còn mở, còn Routines chạy theo lịch trên đám mây với cron, máy đóng nắp vẫn chạy (với một giới hạn mỗi tài khoản về số lần chạy có thể khởi động trong ngày). Kỹ năng là ý định dự án được tách ra ngoài; nếu bạn muốn phần giải thích ở mức thành phần gốc, hãy đọc thành phần và kỹ năng, chứ bài này không dạy lại. Phần mở rộng và trình kết nối là cánh tay vòng lặp với ra công cụ thật, nói kỹ trong hướng dẫn cài phần mở rộng. Người anh em theo sự kiện của nhịp đập là hook, có tài liệu riêng trong hướng dẫn hook; bài này chỉ nhắc hook đúng một dòng.
Trục bộ nhớ ngoài thực tế chỉ là một file nhỏ trên đĩa. snarktank/ralph (14.3k sao) giữ bộ nhớ trong git cộng một progress.txt và một prd.json, rồi dừng khi mọi câu chuyện trong PRD đều passes: true. Vòng lặp lõi nằm dưới tất cả thứ này thật ra chỉ là while stop_reason == tool_use, đúng như cách diễn giải của learn-claude-code. Nhỏ, dễ grep, nằm trên đĩa.
Điểm mấu chốt: Không có gì trong tấm bản đồ là lạ lẫm. Kỹ năng thật sự nằm ở khâu lắp ráp: chọn xem một việc cần những khối nào, rồi nối chúng quanh một tệp trạng thái.
Làm sao dựng một vòng lặp agent trong Claude Code? (bộ quét lint tối giản)
Hãy dựng vòng lặp nhỏ nhất mà vẫn còn là vòng lặp: một bộ quét lint. Một prompt lên lịch chạy trình kiểm tra mã tĩnh (lint), ghi lỗi vào một tệp trạng thái (state file), và dừng khi lint sạch. Đặc tả dùng mẫu khởi động chuẩn (theo định dạng thẻ của loops.elorm.xyz), khớp với hợp đồng của /goal:
# lint-sweeper.loopgoal: "flake8 --extend-ignore=E501 scripts/*.py exits 0"max_iterations: 5between_iterations_check: "flake8 --extend-ignore=E501 scripts/*.py"exit_when: "check exits 0 OR iteration == max_iterations"one_step: "fix one batch of findings (batch = one file), then re-run the check"self_pace: "stop as soon as exit_when holds; do not keep going"state_file: "drafts/lint-sweeper-state.md"Thử ngay (Try It Now). Dán và chạy ba bước dưới đây trên một kho mã có lệnh lint đang báo lỗi. Mỗi bước kết thúc bằng một dòng kiểm chứng để bạn biết nó đã chạy được.
Bước 1: chọn một bộ kiểm chứng thật. Bài kiểm tra chính là tín hiệu dừng, nên nó phải kiểm chứng được bằng máy. Tôi chạy cái này trên các file Python trong kho mã plugin content-agent này, vì shipwithai.io không có lệnh lint. Phần trung thực nằm ở chỗ thay thế đó: flake8 báo 41 lỗi, nhưng 38 lỗi là E501 (dòng quá dài), vốn nhiễu và mang tính chủ quan. Nên bộ kiểm chứng được thu hẹp về các lỗi cấu trúc thật: flake8 --extend-ignore=E501 scripts/*.py. Phạm vi đó viết thẳng vào mục tiêu, không giấu.
Kiểm chứng: chạy một lần và xác nhận nó thoát khác 0. Đúng vậy, với 3 lỗi.
Bước 2: viết tệp trạng thái (cái trục). Một file markdown nhỏ, dễ grep, có ba phần:
goal: flake8 --extend-ignore=E501 scripts/*.py exits 0cap: 5 iterationsiteration: 0## open- gen-agent-map.py:19 F401 'os' imported but unused- gen-dist-metadata.py:23 E301 expected 1 blank line- gen-dist-metadata.py:27 E301 expected 1 blank line## fixed## skippedKiểm chứng: mọi lỗi từ Bước 1 nằm dưới ## open trước lần sửa đầu tiên.
Bước 3: nối nhịp đập rồi chạy. Với bản chạy thử ngay trong phiên, nhịp đập là /loop, nó chạy lại bước-một-việc cho tới khi bộ kiểm chứng đạt. Bước-một-việc sửa một đợt (một file), cập nhật tệp trạng thái, rồi chạy lại bài kiểm tra. Cả vòng lặp chỉ có vậy. Ô bằng chứng kết quả ở trên chính là đầu ra của nó.
Đọc vết chạy: mỗi khối đóng góp gì trong một lần chạy?
Vòng lặp hội tụ sau 2 vòng sửa và dừng lại nhờ mã thoát sạch, không bao giờ chạm giới hạn 5 vòng. Đây là vết chạy (trace) thật, rồi tới phần gắn vai.
# nền (nhịp đập kích hoạt, trước khi sửa gì)$ flake8 --extend-ignore=E501 scripts/*.pyscripts/gen-agent-map.py:19:1: F401 'os' imported but unusedscripts/gen-dist-metadata.py:23:5: E301 expected 1 blank line, found 0scripts/gen-dist-metadata.py:27:5: E301 expected 1 blank line, found 0# thoát 1, 3 lỗi -> vào vòng lặp
# vòng 1: đợt = gen-agent-map.py (bỏ import thừa)$ flake8 --extend-ignore=E501 scripts/*.pyscripts/gen-dist-metadata.py:23:5: E301 expected 1 blank line, found 0scripts/gen-dist-metadata.py:27:5: E301 expected 1 blank line, found 0# thoát 1, 2 lỗi -> tiếp tục
# vòng 2: đợt = gen-dist-metadata.py (thêm 2 dòng trống)$ flake8 --extend-ignore=E501 scripts/*.py# không có đầu ra, thoát 0, 0 lỗi -> điều kiện dừng đạt, DỪNGBản khác biệt (diff) mà vòng lặp tạo ra rất nhỏ: 2 file đổi, 2 dòng thêm, 1 dòng xoá.
--- a/scripts/gen-agent-map.py+++ b/scripts/gen-agent-map.py@@ -16,7 +16,6 @@ import argparse-import os import sys--- a/scripts/gen-dist-metadata.py+++ b/scripts/gen-dist-metadata.py@@ -20,10 +20,12 @@ try: import yaml as _yaml+ def _load_yaml(text: str) -> dict:Giờ gắn từng hiệu ứng nhìn thấy được vào một khối:
- Nhịp đập chạy bài kiểm tra 3 lần (lần nền cộng hai lần sau mỗi đợt sửa). Chính nhịp đó biến cái này thành một vòng lặp chứ không phải một lần chạy duy nhất.
- Bộ kiểm chứng chốt chặn mỗi vòng dựa trên mã thoát của flake8. Thoát 1 thì lặp tiếp; thoát 0 thì dừng. Vòng lặp kết thúc vì điều kiện đã đạt, không phải vì một mô hình tự nhận là xong.
- Trục bộ nhớ ghi lại từng lỗi chuyển từ
## opensang## fixed, kèm vòng đã đóng nó. Sau lần chạy, cả 3 lỗi đều mang nhãn(iter 1)hoặc(iter 2). Đó là dấu vân tay bạn grep khi một vòng lặp giở chứng. - Bên tạo tạo ra bản khác biệt ở trên rồi giao mỗi kết quả cho bộ kiểm chứng. Nó không bao giờ tự nhận là xong.
Hai khối hoàn toàn không chạy. Worktree không được dùng (một agent, một kho mã, không có làn song song nào để cô lập). Phần mở rộng và trình kết nối cũng không (không mở pull request, không cập nhật phiếu việc nào). Như vậy là trung thực, và đó chính là ý nghĩa của một vòng lặp tối giản: bạn không cần đủ mọi khối. Về chi phí, tôi không đo lượng token hay chi phí cho lần chạy thủ công trong phiên này, nên tôi sẽ không trích một con số mà mình không có.
Điểm mấu chốt: Vết chạy là cách bạn gỡ lỗi một vòng lặp. Mỗi khối để lại một dấu vân tay, và mã thoát của bộ kiểm chứng, chứ không phải sự tự tin của agent, mới là cái kết thúc lần chạy.
Một lưu ý trung thực nữa về khối agent con. Lần chạy này dùng một agent đơn với mã thoát của lint làm bộ kiểm chứng, đó là dạng bên-tạo và bộ-kiểm-chứng tối giản nhất. Bản tách vai agent con đầy đủ, nơi một agent riêng chấm công việc, là có thật nhưng thuộc Phần 3 và Phần 5. Ở đây tôi chỉ gọi tên nó, không tuyên bố là nó đã chạy.
Mỗi khối rò rỉ gì khi thiếu
Một vòng lặp thiếu khối không báo lỗi. Nó âm thầm xuống cấp. Khác biệt giữa “thiếu” và “đơn giản là không cần” chính là toàn bộ nửa sau của loạt bài này.
- Thiếu một điều kiện dừng kiểm chứng được thì vòng lặp tuyên bố thắng lợi giả. Điều kiện dừng được mổ xẻ đầy đủ ở Phần 3, gồm các nấc từ một bài kiểm tra trần tới
/goal(nơi một mô hình Haiku riêng chấm điều kiện ở mỗi lượt) lên tới Stop hook với cơ chế ghi đè của nó. Ở đây gọi tên, ở đó mới dạy. - Thiếu trục bộ nhớ thì mỗi lần chạy bắt đầu lại từ số 0, không nối tiếp được. Đó là Phần 4.
- Thiếu worktree và thiếu bên-tạo/bộ-kiểm-chứng thì các agent song song đụng nhau trên cùng file. Đó là Phần 5. Bộ quét lint của ta bỏ qua khối này vì nó chạy một agent, và như vậy là ổn.
- Thiếu một nhịp đập thật thì bạn có một đoạn mã chạy một lần, không phải một vòng lặp. Đó là Phần 6, nơi Routines và CI biến một lần chạy thủ công thành một nhịp đều.
Bộ quét lint dùng bốn mảnh và trung thực bỏ qua hai. Biết việc của bạn cần mảnh nào chính là phần thiết kế mà việc prompt chưa bao giờ đòi hỏi ở bạn.
Câu hỏi thường gặp
Các khối xây dựng của một vòng lặp agent là gì?
Năm khối cộng một trục: lên lịch chạy tự động (nhịp đập), worktree, kỹ năng, phần mở rộng kèm trình kết nối, và agent con, lắp quanh một file bộ nhớ ngoài sống sót qua từng lần chạy. Cách đóng khung này là của Addy Osmani.
Làm sao dựng một vòng lặp trong Claude Code?
Viết một đặc tả theo mẫu khởi động (mục tiêu, giới hạn, lệnh kiểm tra, điều kiện dừng, bước-một-việc, tự định nhịp), thêm một tệp trạng thái làm trục, rồi nối một nhịp đập (/loop trong phiên, hoặc một Routine cho cron đám mây). Mã thoát của bộ kiểm chứng định nghĩa “xong”.
/loop và Routines khác nhau thế nào?
/loop chạy lại một prompt theo chu kỳ khi phiên của bạn còn mở. Routines chạy theo lịch trên đám mây với cron, máy đóng nắp vẫn chạy (giới hạn số lần chạy mỗi ngày theo tài khoản). Cùng khối nhịp đập, khác tầm với.
Vòng lặp một agent có cần worktree không?
Không. Worktree chỉ đáng dùng khi nhiều hơn một agent đụng vào kho mã. Bộ quét lint ở đây chạy tốt mà không cần.
Đọc tiếp
- Phần 3: Điều kiện dừng, để “xong” có nghĩa (
loop-stop-conditions-verification, sắp ra trong loạt Loop Engineering). Phần này biến khối bộ kiểm chứng bạn vừa gọi tên thành kỷ luật của một điều kiện dừng mà một mô hình khác kiểm tra được. - Thành phần và kỹ năng, thành phần gốc mà khối 3 dựng lên từ đó.
- Từ harness tới vòng lặp, Phần 1, nếu bạn bỏ qua tiền đề mà bài này giả định.
{ "@context": "https://schema.org", "@type": "Article", "headline": "Giải phẫu một vòng lặp: năm khối xây dựng và một trục bộ nhớ", "author": { "@type": "Organization", "name": "ShipWithAI" }, "datePublished": "2026-06-20", "description": "Hướng dẫn dựng vòng lặp Claude Code: gọi tên năm khối xây dựng và trục bộ nhớ, ánh xạ mỗi khối vào tính năng có sẵn, rồi chạy thật một vòng lặp quét lint.", "image": "/images/blog/loop-anatomy-five-building-blocks-cover.png", "articleSection": "tutorial", "keywords": "claude-code, automation, tutorial, vietnamese", "mainEntityOfPage": "https://shipwithai.io/vi/blog/loop-anatomy-five-building-blocks/"}{ "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "Các khối xây dựng của một vòng lặp agent là gì?", "acceptedAnswer": { "@type": "Answer", "text": "Năm khối cộng một trục: lên lịch chạy tự động (nhịp đập), worktree, kỹ năng, phần mở rộng kèm trình kết nối, và agent con, lắp quanh một file bộ nhớ ngoài sống sót qua từng lần chạy. Cách đóng khung này là của Addy Osmani." } }, { "@type": "Question", "name": "Làm sao dựng một vòng lặp trong Claude Code?", "acceptedAnswer": { "@type": "Answer", "text": "Viết một đặc tả theo mẫu khởi động (mục tiêu, giới hạn, lệnh kiểm tra, điều kiện dừng, bước-một-việc, tự định nhịp), thêm một tệp trạng thái làm trục, rồi nối một nhịp đập (/loop trong phiên, hoặc một Routine cho cron đám mây). Mã thoát của bộ kiểm chứng định nghĩa \"xong\"." } }, { "@type": "Question", "name": "/loop và Routines khác nhau thế nào?", "acceptedAnswer": { "@type": "Answer", "text": "/loop chạy lại một prompt theo chu kỳ khi phiên của bạn còn mở. Routines chạy theo lịch trên đám mây với cron, máy đóng nắp vẫn chạy (giới hạn số lần chạy mỗi ngày theo tài khoản). Cùng khối nhịp đập, khác tầm với." } }, { "@type": "Question", "name": "Vòng lặp một agent có cần worktree không?", "acceptedAnswer": { "@type": "Answer", "text": "Không. Worktree chỉ đáng dùng khi nhiều hơn một agent đụng vào kho mã. Bộ quét lint ở đây chạy tốt mà không cần." } } ]}{ "@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": 1, "name": "Blog", "item": "https://shipwithai.io/vi/blog/" }, { "@type": "ListItem", "position": 2, "name": "Giải phẫu một vòng lặp: năm khối xây dựng và một trục bộ nhớ", "item": "https://shipwithai.io/vi/blog/loop-anatomy-five-building-blocks/" } ]}