- Cấu trúc cốt lõi của trợ lý lập trình AI không phải là ma thuật phức tạp mà được tạo thành từ khoảng 200 dòng mã Python đơn giản
- Hệ thống dựa trên vòng lặp hội thoại với LLM; khi LLM yêu cầu gọi công cụ, mã cục bộ sẽ thực thi và gửi lại kết quả
- Ba công cụ cơ bản cần có là đọc tệp (
read), liệt kê tệp (list), chỉnh sửa tệp (edit); nhờ đó có thể khám phá dự án và sửa đổi mã
- Dựa trên chữ ký và mô tả (docstring) của công cụ, LLM tự quyết định nên gọi công cụ nào và vào lúc nào
- Cấu trúc này cũng chính là phần cốt lõi của các sản phẩm thương mại như Claude Code, và ngay cả cấu trúc đơn giản cũng có thể hiện thực một coding agent mạnh mẽ
Khái niệm cơ bản của coding agent
- Coding agent là hệ thống dựa trên hội thoại với LLM, nhận lệnh từ người dùng và thực hiện thao tác với tệp thật thông qua việc gọi công cụ
- Người dùng nhập yêu cầu như “tạo một tệp mới có chứa hàm hello world”
- LLM phản hồi bằng lời gọi công cụ cần thiết ở định dạng JSON
- Chương trình thực thi công cụ đó rồi chuyển kết quả lại cho LLM
- LLM không truy cập trực tiếp vào hệ thống tệp mà chỉ đưa ra yêu cầu, còn công việc thực tế do mã cục bộ xử lý
Ba công cụ cần thiết
- read_file: đọc và trả về toàn bộ nội dung của tệp được chỉ định
- list_files: trả về danh sách tệp và thư mục trong một thư mục
- edit_file: thay thế chuỗi hiện có bằng chuỗi mới, hoặc nếu
old_str rỗng thì tạo tệp mới
- Nếu không tìm thấy chuỗi cần thay thế thì trả về “old_str not found”
- Chỉ với ba công cụ này cũng đã có thể tạo, sửa và khám phá tệp
Đăng ký công cụ và tích hợp với LLM
- Tất cả công cụ được đăng ký trong TOOL_REGISTRY bằng tên và hàm để LLM có thể gọi
- Docstring và chữ ký của từng công cụ được trích xuất và chuyển cho LLM
- System prompt nói rõ cho LLM về “danh sách công cụ khả dụng” và “định dạng gọi”
- Việc gọi công cụ bị giới hạn ở định dạng
'tool: TOOL_NAME({JSON_ARGS})'
- Kết quả thực thi công cụ được chuyển cho LLM dưới dạng
tool_result(...)
Phân tích lời gọi công cụ và xử lý phản hồi của LLM
- Tìm các dòng bắt đầu bằng
tool: trong phản hồi của LLM để trích xuất tên công cụ và đối số (JSON)
- Sau khi thực thi từng công cụ, kết quả được tuần tự hóa thành JSON và thêm vào lịch sử hội thoại
- Hàm execute_llm_call gọi API của LLM và trả về văn bản phản hồi
- run_coding_agent_loop nhận đầu vào người dùng và duy trì vòng lặp hội thoại với LLM
- Vòng lặp bên trong lặp lại cho đến khi LLM không còn yêu cầu gọi công cụ nữa
Ví dụ chạy thử và khả năng mở rộng
- Ví dụ hội thoại:
- “Hãy tạo tệp
hello.py và triển khai hello world” → gọi edit_file để tạo tệp mới
- “Thêm hàm nhân hai số vào
hello.py” → gọi read_file rồi edit_file
- Có thể hiện thực một trợ lý lập trình hoàn chỉnh chỉ với khoảng 200 dòng mã
- Các sản phẩm thương mại bổ sung thêm xử lý lỗi, phản hồi streaming, quản lý ngữ cảnh, công cụ bổ sung, quy trình phê duyệt v.v.
- Nhưng cấu trúc cốt lõi vẫn như nhau: một vòng lặp đơn giản nơi LLM quyết định và mã thực thi
Thực hành và mở rộng
- Toàn bộ mã nguồn dài khoảng 200 dòng, có thể mở rộng bằng cách thay LLM provider khác hoặc thêm công cụ mới
- Ngay cả với cấu trúc đơn giản, bạn vẫn có thể tự tay hiện thực prototype AI coding agent mạnh mẽ
1 bình luận
Ý kiến trên Hacker News
Điều tôi muốn bổ sung là planning
Cốt lõi của việc dùng công cụ hiệu quả là nhận ra chúng hoạt động trên một danh sách TODO động
Chế độ Plan đóng vai trò bootstrap cách danh sách đó được khởi tạo và thời điểm từng mục được thực thi
Tương tác của người dùng hoạt động theo cách sắp xếp lại danh sách đó
Tháng trước tôi đã thử nghiệm xem Claude Code giải các bài CTF tốt đến mức nào, và khi tắt công cụ TodoList cùng planning thì hiệu năng giảm 1–2 bậc
Xem video liên quan tại Breaking Bots: Cheating at Blue Team CTFs with AI Speed Runs
Điều thú vị là nhiều người chỉ tập trung vào chuyện “có nên dùng plan mode hay không”, nhưng thực ra danh sách TODO luôn ở trạng thái hoạt động
Ngoài ra, đọc những bài viết coi “quản lý ngữ cảnh thông minh” chỉ như vài mục TODO đơn giản cũng khá buồn cười
Nhiều người tự triển khai rồi lại mất cả năm vì kết quả đánh giá bị vỡ trong môi trường production
Bạn có thể chỉ thêm phần này bằng reasoning token, nhưng trên thực tế triển khai bằng công cụ lưu trữ tường minh với một khóa duy nhất lại dễ dự đoán và hiệu quả hơn nhiều
Có vẻ cách tiếp cận đơn giản này cũng có thể áp dụng cho các ý tưởng công cụ khác dùng để lưu cấu trúc ngôn ngữ
Khi thử Codex, tôi dành khoảng 10 phút để sắp xếp lại đặc tả, chia nó thành danh sách thay đổi, lưu vào file, rồi chỉ thị để mô hình rà soát và chỉnh lại kế hoạch sau mỗi thay đổi
Làm như vậy giúp LLM tập trung vào các tác vụ ngắn, định hướng theo mục tiêu mà không cần nhập prompt liên tục
Hiệu quả thực tế gần giống như có thêm subagent
Thậm chí còn chỉ thị mục todo cuối cùng là “rà soát lại toàn bộ công việc và kiểm tra chất lượng bằng linter hoặc công cụ tương tự”
Khi nén context, nó cũng được dùng như một biểu diễn cô đọng của phiên làm việc
Cốt lõi của coding agent thực ra chỉ là một vòng lặp và cấu trúc gọi công cụ đơn giản
Nhưng nếu định viết bài kiểu “The Emperor Has No Clothes: How to Code Claude Code in 200 Lines of Code” thì nhất định nên tham khảo How to Build an Agent của Thorsten Ball
Bài đó là nơi đầu tiên đưa ra ý tưởng rằng “bản chất của agent là đơn giản”
Dĩ nhiên trên thực tế vẫn cần TODO và nhiều lớp scaffolding khác nhau, còn bản thân Claude Code cũng có rất nhiều cấu hình phức tạp, plugin và tính năng UI
Dù vậy, chỉ với vòng lặp tối thiểu, bạn vẫn có thể bootstrap để nó tự mở rộng chức năng
Nếu muốn xem hoạt động bên trong, có thể dùng claude-trace để theo dõi tương tác giữa LLM và các lệnh gọi công cụ
Ngoài vòng lặp đơn giản còn có rất nhiều thành phần phức tạp như uuid threading, xử lý hàng đợi tin nhắn, snapshot thay đổi file, sidechain cho subagent, v.v.
Vì vậy “200 dòng” đúng về mặt khái niệm, nhưng ở mức production thực tế thì phức tạp hơn nhiều
Codex hiện vẫn chưa có tính năng queueing nhưng vẫn rất mạnh
Tôi đã tạo một ứng dụng macOS tên là Contextify để theo dõi transcript CLI của Claude Code và Codex theo thời gian thực, đồng thời cho phép truy vấn lịch sử hội thoại bằng tính năng Total Recall
Các mô hình Claude được huấn luyện với schema công cụ str replace riêng
Việc ghi lại toàn bộ file là kém hiệu quả, nên chỉnh sửa từng phần mới là cốt lõi
Trên thực tế còn nhiều yếu tố khác
Ví dụ có trường hợp agent bị early stopping và tự kết thúc công việc
Ngay cả các mô hình reasoning mới nhất cũng chưa giải quyết được
Claude Code xử lý việc này bằng cách tiêm TODO vào mọi prompt để nhắc lại phần việc còn lại
Kho lưu trữ công khai của HolmesGPT có nhiều benchmark thử nghiệm khác nhau
Ban đầu tôi thấy khá sốc với ý tưởng “chỉ cần cho LLM biết danh sách công cụ và định dạng gọi là đủ”
Tôi từng nghĩ LLM chỉ sinh văn bản thì làm sao gọi công cụ được, nhưng khi nhận ra đúng là chỉ có vậy thôi thì nó thật kỳ diệu
Trong kỳ nghỉ tôi đã thử làm một coding agent dựa trên Prolog DSL bằng Opus (quá 200 dòng)
Điều đáng ngạc nhiên là nó gần như hoạt động tốt ngay lập tức
Có vẻ các mô hình thế hệ mới nhất đã đạt đến giai đoạn mà tầm quan trọng của agent harness giảm đi
Xem thử nghiệm liên quan ở bài này
Một năm trước thì bài viết này khá chính xác, nhưng bây giờ harness đã tiến bộ hơn nhiều nên mô hình vòng lặp đơn giản khó mà giải thích đúng cách Claude Code thực sự vận hành
Ngay cả agent đơn giản cũng không thua kém quá nhiều nếu dùng cùng một mô hình
Nó hơi giống các bài hướng dẫn “tự xây DB” chỉ ra B-tree cơ bản
Subagent, MCP và Skills chỉ ở mức trung gian, còn tối ưu hóa context chỉ thực sự có ý nghĩa với các tác vụ chạy dài
Tôi trực tiếp xây dựng agent loop cho doanh nghiệp và đang xử lý hơn 1 tỷ token mỗi tháng
Vòng lặp đơn giản đúng là phần cốt lõi, nhưng trong môi trường thực tế, vô số chi tiết làm độ phức tạp tăng bùng nổ
Ví dụ nếu người dùng gửi tin nhắn giữa chừng thì phải xử lý vòng lặp thế nào, đồng bộ đầu vào webhook như Slack ra sao,
rồi còn phê duyệt, guardrail, xử lý Task bất đồng bộ và nhiều thứ khác cần cân nhắc
Tôi đang nghĩ có lẽ nên viết một bài blog tổng hợp lại các kinh nghiệm này
Một số bài đáng tham khảo là You Should Write An Agent và How To Build An Agent
Nhóm SWE-bench của chúng tôi đã công bố một agent mã nguồn mở 100 dòng
Đó là mini-swe-agent, và nó khá được ưa chuộng trong cả học thuật lẫn công nghiệp
Đây là điểm khởi đầu tốt để tìm hiểu thế giới agent
Năm 2023 từng có một bài viết tên là “tái triển khai LangChain bằng 100 dòng”
Sau khi đọc bài đó, tôi đã tự triển khai và dùng nó cho nhiều dự án