Xây dựng agent code biết giữ bản đồ dự án
Một coding agent thường thất bại không phải vì không biết viết code. Điểm yếu phổ biến hơn nằm ở cách nó bước vào một repository: mở hàng loạt file, đoán quan hệ giữa các module, sửa một hàm rồi quên caller, hoặc thấy tài liệu cũ là chép thêm một đoạn mới. Sau vài lượt làm việc, code vẫn chạy nhưng dự án mất dần khả năng giải thích chính nó.
Với một dự án nhỏ, giải pháp không phải là dựng thêm một knowledge graph phức tạp hay bắt agent tự ghi chép mọi thay đổi. Cách bền hơn là kết hợp hai lớp rất gọn: công cụ hiểu cấu trúc code theo ngữ nghĩa và một bộ tài liệu ngắn, luôn phản ánh những quy ước thật sự của dự án.
Bài viết này trình bày cách xây workflow đó để agent có thể đọc đúng phần cần đọc, sửa đúng phạm vi và để lại repository dễ tiếp quản hơn cho người hoặc agent đến sau.
Mục tiêu không phải là để agent đọc hết code
Khi giao một task như sửa lỗi đăng nhập, thêm endpoint hay chỉnh pipeline xử lý dữ liệu, agent không cần biết toàn bộ lịch sử dự án. Nó cần trả lời được vài câu hỏi cụ thể:
- Điểm vào của luồng này nằm ở đâu?
- Hàm hoặc module nào đang chịu trách nhiệm chính?
- Những phần nào gọi đến nó hoặc phụ thuộc vào nó?
- Test nào mô tả hành vi hiện tại?
- Có quy tắc nào không được phá vỡ khi sửa?
Nếu thiếu các câu trả lời này, agent thường chọn cách an toàn bề ngoài: đọc thật nhiều file. Cách làm đó tốn context, chậm và vẫn có thể bỏ sót quan hệ quan trọng. Với repository nhỏ, chi phí còn lớn hơn lợi ích vì phần lớn nội dung được đọc sẽ không liên quan đến task.
Thay vì vậy, hãy xem codebase như một thành phố. Agent không cần đi qua mọi con phố trước khi sửa một bóng đèn. Nó cần bản đồ khu vực, biết tuyến điện liên quan và biết đâu là điểm không được ngắt nguồn.
Serena là radar, tài liệu dự án là bản đồ
Một công cụ semantic code intelligence như Serena phù hợp cho phần “radar”. Nó giúp agent làm việc trên symbol thay vì chỉ dựa vào text search:
- xem tổng quan class, function và module trong một file;
- tìm declaration hoặc implementation thật sự của một symbol;
- truy ngược references trước khi đổi tên, xóa hay chỉnh public API;
- kiểm tra diagnostics ở file vừa sửa;
- thực hiện rename/refactor có nhận thức về references.
Điểm đáng giá nhất là agent có thể bắt đầu từ yêu cầu, đi đến symbol liên quan, rồi mở rộng ra callers, implementations và tests. Đây là hướng ngược với thói quen “đọc nguyên repository rồi mới nghĩ”.
Nhưng Serena không thay thế tri thức đặc thù của dự án. Nó không tự biết nhóm đã chọn cách deploy nào, migration nào không được sửa lại, lệnh test nào cần chạy khi động vào một module, hay thư mục nào chứa artifact sinh tự động. Những thứ đó nên nằm trong AGENTS.md ở root repository.
Có thể hiểu ngắn gọn như sau:
| Thành phần | Vai trò |
|---|---|
| Serena | Tìm đúng code, symbol, references và diagnostics |
AGENTS.md | Nêu quy ước, ranh giới và cách verify của dự án |
README.md | Giúp người mới cài đặt và chạy dự án |
docs/architecture.md | Mô tả các module và luồng quan trọng khi dự án cần |
Một lớp trả lời “code đang nối với nhau thế nào”, lớp còn lại trả lời “nhóm muốn thay đổi nó theo cách nào”.
Một quy trình làm việc đủ chặt cho agent
Quy trình dưới đây phù hợp với đa số repository nhỏ và vừa. Nó không đòi hỏi hệ thống watcher, database riêng hay cron tự cập nhật graph.
1. Kiểm tra bối cảnh trước khi đụng vào code
Ngay khi bắt đầu task, agent nên kiểm tra branch và working tree. Nếu repository đã có thay đổi chưa commit, agent phải phân biệt chúng với phần việc mới thay vì vô tình ghi đè hoặc đưa tất cả vào cùng một commit.
Sau đó, agent đọc AGENTS.md. File này cần được xem như hướng dẫn vận hành ngắn, không phải bản mô tả dài dòng. Nó cho agent biết module nào quan trọng, command nào là chuẩn, khu vực nào nhạy cảm và những điều cần xin duyệt trước.
Ví dụ, một project có thể quy định rằng mọi thay đổi database phải có migration mới, mọi thay đổi API phải cập nhật contract test, còn file trong generated/ không được sửa tay. Những thông tin này không thể suy ra đáng tin cậy chỉ từ source code.
2. Kích hoạt đúng project và lần theo symbol
Sau khi có bối cảnh, agent kích hoạt đúng repository trong Serena. Từ đây, nó ưu tiên các thao tác semantic: xem overview của file liên quan, tìm symbol mục tiêu, tìm references trước khi sửa interface hoặc đổi tên, rồi mới đọc source cần thiết.
Nếu task là “sửa logic tạo đơn hàng”, một chuỗi làm việc tốt sẽ là:
- Tìm handler hoặc command nhận yêu cầu tạo đơn.
- Tìm service thực hiện nghiệp vụ.
- Xem những nơi gọi service đó.
- Tìm test hiện có cho flow này.
- Đọc đúng các đoạn source liên quan trước khi edit.
Cách làm này giúp agent thấy blast radius thực tế. Một thay đổi nhỏ ở hàm validation có thể ảnh hưởng cả API, worker và job đồng bộ. Ngược lại, một lỗi hiển thị đơn thuần có thể chỉ cần một component và test giao diện tương ứng.
3. Sửa với phạm vi nhỏ nhất
Coding agent rất dễ biến một task nhỏ thành đợt refactor rộng vì gặp code chưa đẹp. Quy tắc tốt là chỉ mở rộng phạm vi khi việc đó cần thiết để sửa bug, giữ tương thích hoặc đáp ứng yêu cầu đã giao.
Trước các thay đổi có tính phá vỡ như rename public symbol, đổi schema, xóa code hay sửa authentication flow, agent phải xem references và impact trước. Với thao tác có rủi ro cao như production config, migration đã release, dữ liệu người dùng hoặc quyền truy cập, agent cần dừng để báo rõ phạm vi và xin duyệt nếu yêu cầu ban đầu chưa nói cụ thể.
Tính tự động không có nghĩa là bỏ qua ranh giới. Agent hữu ích nhất khi nó chủ động ở phần có thể kiểm chứng và thận trọng ở phần có hậu quả khó đảo ngược.
4. Verify bằng lệnh thật
Sau khi edit, agent cần kiểm tra Git diff để biết chính xác những gì đã đổi. Tiếp đó là diagnostics, focused tests và các bước lint, typecheck hoặc build phù hợp với repository.
Một báo cáo kiểu “đã sửa xong, có vẻ ổn” không đủ giá trị. Báo cáo tốt phải nói được lệnh nào đã chạy, kết quả ra sao và có giới hạn gì còn tồn tại. Nếu test fail vì lỗi có sẵn, thông tin đó cũng cần được nêu rõ thay vì gộp chung vào kết quả của task.
Đây là lý do phần Verification trong AGENTS.md rất quan trọng. Agent không nên tự đoán giữa npm test, pytest, go test ./... hay một script CI riêng. Repository cần nói rõ cách chứng minh thay đổi là an toàn.
AGENTS.md nên ngắn, nhưng phải có ích
Nhiều nhóm bắt đầu bằng một file hướng dẫn rất dài, rồi không ai cập nhật nữa. Cách hiệu quả hơn là giữ AGENTS.md trong khoảng 60 đến 150 dòng. Nó chỉ cần chứa những thông tin làm thay đổi hành vi của agent.
Một cấu trúc thực dụng gồm năm phần:
# Agent Guide
## Project map
- `src/api/`: HTTP handlers.
- `src/services/`: business logic.
- `src/db/`: persistence và migrations.
- `tests/`: test, phản chiếu cấu trúc của `src/`.
## Critical flows
`POST /orders` → order service → repository → event publisher.
## Change rules
- Sửa `src/services/**`: chạy `pytest tests/services -q`.
- Đổi public API: cập nhật contract test và docs.
- Thay đổi schema: thêm migration mới, không sửa migration đã release.
## Invariants
- Không commit secrets hoặc sửa thủ công file trong `generated/`.
- Không đổi production config nếu chưa có yêu cầu rõ.
## Verification
- Test: `pytest -q`
- Lint: `ruff check .`
- Build: `npm run build`
Điều đáng chú ý là file này không cần kể tên mọi function. Serena đã làm tốt phần đó. AGENTS.md chỉ nên giữ project map, critical flows, change rules, invariants và definition of done.
Khi nào cần cập nhật tài liệu?
Không nên ép agent viết lại tài liệu sau mỗi lần đổi biến hay sửa một điều kiện. Làm vậy biến docs thành changelog lộn xộn và tạo thêm việc không mang lại giá trị.
Tài liệu cần cập nhật khi thay đổi có tính structural hoặc có quy ước mới lâu dài, chẳng hạn:
- thêm hoặc bỏ module, service hay folder quan trọng;
- xuất hiện entry point mới như CLI, API route, cron job hoặc worker;
- thay đổi luồng dữ liệu hoặc integration;
- thay đổi lệnh test, build, deploy;
- đưa vào invariant mới, vùng cấm sửa hoặc quy tắc bảo mật;
- có quyết định kiến trúc mà agent sau cần hiểu để không đảo ngược.
Một câu hỏi đơn giản giúp agent quyết định: “Nếu một người mới hoặc agent mới bước vào repository tuần sau, thiếu thông tin này có dễ làm sai không?” Nếu có, tài liệu nên được cập nhật trong cùng thay đổi code.
Khởi tạo đúng từ dự án mới
Workflow này hiệu quả nhất khi được đặt nền từ đầu. Với một project mới, đừng đợi codebase lớn mới viết hướng dẫn. Ngay sau khi structure ban đầu ổn định, hãy tạo README.md, AGENTS.md, .gitignore và skeleton cho test.
Repository mới cũng nên tách source, test, config và generated artifacts ngay từ đầu. Secrets chỉ tồn tại ở local environment hoặc secret manager, không nằm trong Git. Các command cài đặt, chạy thử, test và build phải tái lập được trên một máy sạch.
Một khởi đầu tốt giúp agent không phải đoán ý định kiến trúc. Nó cũng giúp đội ngũ thấy sớm những câu hỏi đáng trả lời: đâu là MVP, module nào là ranh giới chính, điều gì cần test và khi nào một thay đổi được xem là hoàn tất.
Khi nào nên dùng graph phức tạp hơn?
Với project nhỏ, Serena kết hợp tài liệu mỏng thường là đủ. Một hệ thống graph riêng, tự cập nhật theo từng edit chỉ đáng cân nhắc khi codebase đã có nhiều package phụ thuộc chéo, pull request thường xuyên chạm nhiều file, nhiều agent làm việc song song hoặc review bắt đầu tốn context đáng kể.
Ở giai đoạn đó, các công cụ như Code Review Graph có thể bổ sung phân tích blast radius, risk score và test gaps cho review. Tuy vậy, graph không nên thay thế tài liệu project. Nó biết quan hệ kỹ thuật, còn AGENTS.md mới ghi lại chủ đích, trade-off và ranh giới vận hành.
Kết luận
Một coding agent đáng tin không phải agent đọc được nhiều file nhất. Đó là agent biết bắt đầu từ đúng bối cảnh, lần theo đúng symbol, sửa trong phạm vi hợp lý, chạy verification thật và chỉ cập nhật tài liệu khi kiến trúc hoặc quy tắc dự án thay đổi.
Với phần lớn dự án nhỏ, công thức gọn nhất là: Serena để hiểu code theo ngữ nghĩa, AGENTS.md để giữ bản đồ vận hành, test và build để xác nhận kết quả. Ba lớp này đủ nhẹ để duy trì, nhưng đủ chặt để agent không biến repository thành một hộp đen sau mỗi lần tự động hóa.