Agent production bắt đầu từ lớp harness

Agent production bắt đầu từ lớp harness

Muốn agent đáng tin, đừng hỏi model nào mạnh hơn trước. Hãy mổ lớp harness: tool, permission, memory, retry, cost và guardrail.

"Agent của em chạy được rồi, nhưng em chưa dám cho nó đụng production."

Câu này mình nghe nhiều tới mức có thể đoán phần sau: demo thì mượt, tool calling cũng ổn, log nhìn khá đẹp, nhưng hễ giao việc thật là cả team bắt đầu nín thở. Không phải vì model kém. Mà vì hệ thống chưa có harness — lớp dây đai vận hành giữ agent không lao thẳng vào vách đá.

Luận điểm hôm nay hơi trái tai một chút: agent production không bắt đầu từ prompt, cũng không bắt đầu từ framework mới nhất. Nó bắt đầu từ runtime có orchestration và guardrail rõ ràng.

Dịch sang tiếng người: trước khi hỏi "nên dùng agent framework nào", bạn nên hỏi "khi agent định làm sai, hệ thống của mình chặn nó ở đâu?"

Sơ đồ minh họa cho bài Agent production bắt đầu từ lớp harness

Sơ đồ tóm tắt ý chính của bài viết.

Mục tiêu: dựng agent như một hệ địa tầng, không như một cú gọi LLM

Một cú gọi LLM đơn lẻ giống như khoan thử một điểm trên mặt đất: bạn biết bên dưới có gì đó, nhưng chưa biết lớp nào chịu lực, lớp nào dễ sụt. Agent production thì khác. Nó có nhiều lớp trầm tích kỹ thuật chồng lên nhau:

Điểm quan trọng: những lớp này không phải đồ trang trí. Chúng là nơi production sống hoặc nứt.

Checklist trước khi cho agent cầm tool thật

Nếu team bạn đang build agent nội bộ, hãy dùng checklist này trước khi mở quyền cho nó gọi API, sửa file, chạy script, hoặc đụng dữ liệu khách hàng.

| Lớp cần kiểm | Câu hỏi phải trả lời | Dấu hiệu chưa sẵn sàng |
|---|---|---|
| Tool schema | Tool nhận input gì, output gì, lỗi gì? | Tool mô tả mơ hồ, input dạng any |
| Permission | Hành động nào cần user approve? | Agent có thể ghi/xóa/chạy lệnh ngay |
| Observation | Tool trả về gì cho model sau khi chạy? | Chỉ trả text dài, không có status/error |
| Memory | Cái gì được nhớ, trong bao lâu? | Memory lưu mọi thứ vì "biết đâu cần" |
| Hooks | Có log trước/sau tool call không? | Debug bằng cách đọc console rời rạc |
| Retry | Lỗi provider và lỗi nghiệp vụ tách chưa? | Fail là gọi lại vô điều kiện |
| Cost | Có budget theo task/session không? | Chỉ biết tốn sau khi hóa đơn về |
| Delegation | Subagent được làm gì, bị giới hạn gì? | Spawn agent con không có hợp đồng rõ |

Nhiều team nhảy thẳng vào phần "agent tự quyết" vì nhìn hấp dẫn. Nhưng chấn tâm của sự cố thường nằm ở mấy lớp ít hào nhoáng hơn: quyền, log, retry, và giới hạn side effect.

Bước 1: đóng khung control loop trước khi chọn framework

Một agent runtime tối thiểu nên có vòng lặp rõ như sau:

user task
  -> build context
  -> model decides: answer or tool_call
  -> validate tool_call
  -> check permission
  -> execute tool
  -> return observation
  -> update memory/log/cost
  -> continue or stop

Đừng để model "nói gì cũng được" rồi backend cố đoán ý. Hãy bắt model trả về hành động theo cấu trúc.

Ví dụ một tool schema đơn giản:

{
  "name": "write_file",
  "description": "Ghi nội dung vào virtual filesystem",
  "input_schema": {
    "path": "string",
    "content": "string",
    "mode": "overwrite | append"
  },
  "permission": "ask_before_write"
}

Ở đây có hai guardrail đáng tiền:

  1. input_schema ép agent gọi đúng kiểu.
  2. permission buộc hệ thống hỏi trước khi tạo side effect.

Nếu bạn đang dùng LangChain, MCP, hay một framework agent khác, câu hỏi không phải là "framework có tool calling không?" mà là tool calling đó có đi qua validation, permission, observation, và audit trail không?

Bước 2: phân quyền theo bề mặt rủi ro, không theo độ tiện

Một hiểu lầm phổ biến: càng bật nhiều tool, agent càng thông minh. Thực tế, càng bật nhiều tool, bề mặt sự cố càng rộng.

Mình thích cách tiếp cận "blank slate": bắt đầu với rất ít quyền, rồi mở dần. Với team builder, bạn có thể chia tool thành 4 vùng:

Ví dụ cụ thể: giả sử team bạn 5 người đang làm agent hỗ trợ xử lý bug report. Đừng cho agent tự push fix ngay. Cho nó quyền đọc repo, tìm log, tạo patch nháp, rồi mở Pull Request ở chế độ cần review. Như vậy agent vẫn giảm việc lặp lại, nhưng không biến repo thành miệng núi lửa đang phun vào thứ Sáu chiều.

Một rule thực dụng: tool càng gần dữ liệu sống hoặc tiền thật, càng phải có permission rõ và log dễ đọc.

Bước 3: memory và skill phải là opt-in, không phải cái kho vô đáy

Memory là lớp giúp agent nhớ thông tin qua nhiều phiên. Skill là năng lực đóng gói sẵn, ví dụ quy trình đọc log, format báo cáo, hoặc cách dùng API nội bộ.

Hai thứ này dễ bị lạm dụng vì tạo cảm giác agent "ngày càng khôn". Nhưng trong production, câu hỏi cần hỏi là:

Một thiết kế an toàn hơn là để agent load skill theo nhu cầu, thay vì nhét toàn bộ cẩm nang công ty vào context. Với memory cũng vậy: lưu ít nhưng có cấu trúc thường tốt hơn lưu nhiều rồi cầu may.

Một mẫu memory entry nên có metadata tối thiểu:

{
  "type": "project_preference",
  "value": "Dùng pnpm cho frontend repo",
  "source": "approved_by_user",
  "created_at": "2026-06-24",
  "scope": "repo:customer-portal"
}

Nếu không có sourcescope, memory rất dễ biến thành lớp dung nham cũ: nhìn đã nguội, nhưng đụng vào vẫn làm cháy workflow.

Bước 4: retry và cost tracking phải nằm trong runtime, không nằm trong niềm tin

Agent production sẽ gặp lỗi. Provider timeout. Tool trả về 500. Search không ra. File bị lock. Model gọi sai tham số. Đây không phải ngoại lệ hiếm; đây là thời tiết hằng ngày.

Vì vậy, retry không nên là while true try again. Hãy tách ít nhất 3 loại lỗi:

  1. Provider error: lỗi từ model/API, có thể retry với backoff.
  2. Tool validation error: model gọi sai schema, nên trả observation để model sửa.
  3. Business rule error: hành động bị cấm, không retry, cần dừng hoặc hỏi người dùng.

Ví dụ observation tốt:

{
  "status": "error",
  "error_type": "permission_denied",
  "message": "write_file requires approval for path /prod/config.yml",
  "recoverable": false
}

Observation tệ:

Something went wrong.

Cost tracking cũng vậy. Đừng đợi cuối tháng mới biết agent đã đào một đường hầm token dài tới đâu. Runtime nên ghi token, số tool call, số vòng lặp, và ước tính chi phí theo task. Với builder, đây không chỉ là chuyện tiền; nó còn là tín hiệu để phát hiện agent bị kẹt loop.

Bước 5: multi-agent chỉ đáng bật khi có hợp đồng vai trò

Multi-agent coordination là điều phối nhiều agent để chia việc. Nó hữu ích khi task có vai trò thật sự khác nhau: planner lập kế hoạch, researcher thu thập dữ liệu, coder sửa code, reviewer kiểm tra.

Nhưng nếu bạn chỉ spawn thêm agent vì muốn "song song hóa trí thông minh", coi chừng. Bạn đang thêm đường đứt gãy vào hệ thống.

Trước khi bật subagent, hãy viết hợp đồng ngắn:

agent: reviewer
allowed_tools:
  - read_file
  - search_text
blocked_tools:
  - write_file
  - run_shell
input:
  - patch
  - acceptance_criteria
output:
  - risks
  - suggested_changes
stop_condition: "review_complete"

Điểm mấu chốt: agent con không nên thừa hưởng toàn bộ quyền của agent cha. Delegation mà không giới hạn quyền là cách rất nhanh để biến một bug nhỏ thành sự cố khó truy vết.

Một buổi chiều để kiểm tra runtime của bạn

Nếu bạn đang có agent prototype, hãy dành một buổi để làm 5 việc này:

  1. Vẽ control loop hiện tại: từ user task tới tool execution, observation, stop condition.
  2. Liệt kê tool theo rủi ro: read-only, draft-only, approval-required, blocked.
  3. Thêm typed schema cho 3 tool nguy hiểm nhất: đặc biệt là write, shell, API side effect.
  4. Gắn lifecycle hooks: log trước tool call, sau tool call, khi retry, khi permission denied.
  5. Chạy 3 failure test: model gọi sai schema, tool timeout, agent cố làm việc bị cấm.

Bạn sẽ nghĩ khác điều gì sau bài này? Hy vọng là thế này: agent đáng tin không phải agent trả lời hay hơn, mà là agent có đường đi được kiểm soát khi nó chuẩn bị làm điều gì đó thật.

Framework có thể đổi. Model có thể đổi. Nhưng harness — lớp runtime giữ tool, memory, permission, retry, cost và coordination đi đúng rãnh — mới là nền đá chịu lực.

Chốt gọn: đừng hỏi con agent có thông minh không; hỏi nó có biết dừng đúng chỗ không đã.

---
Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng

Nguồn tham khảo