Xây AI agent trong .NET mà không trói nghiệp vụ vào framework AI
Microsoft Agent Framework 1.0 đã phát hành. Bài hướng dẫn dựng AI agent hỗ trợ khách hàng trong .NET theo Clean Architecture: ranh giới bốn tầng, tool calling an toàn, chạy model local bằng Ollama trước khi lên hosted, kèm checklist đưa agent vào production.
Xây AI agent trong .NET mà không trói nghiệp vụ vào framework AI
Cách gắn LLM vào ứng dụng mà nhiều đội làm đầu tiên trông thế này: nhận prompt, gửi cho model, lấy câu trả lời, trả về cho người dùng. Nó chạy được cho demo, nhưng là ngõ cụt kiến trúc. Ngày bạn đổi nhà cung cấp model, đổi framework agent, hay chỉ đơn giản muốn model gọi được một hàm nghiệp vụ có kiểm soát, bạn sẽ viết lại từ đầu.
Cách thoát khỏi ngõ cụt đó có tên: agent. Không phải chatbot trả lời cho hay, mà một vòng lặp có kỷ luật, model hiểu ý định, chọn tool phù hợp trong số các tool ứng dụng cho phép, gọi tool, rồi dùng kết quả để trả lời. Bài này dựng một agent như thế trong .NET với Microsoft Agent Framework, theo Clean Architecture, và chạy model local bằng Ollama trước khi nghĩ đến hosted.
Lưu ý về version: Microsoft Agent Framework 1.0 đã phát hành, là sản phẩm kế thừa hợp nhất Semantic Kernel và AutoGen. API và tên package có thể đổi giữa các version, nên mọi đoạn mã dưới đây là minh họa theo nguyên tắc, luôn đối chiếu docs đúng version bạn dùng.
Agent khác LLM gọi thẳng ở chỗ nào
Tích hợp LLM thông thường chỉ có bốn bước: nhận prompt, gửi model, nhận câu trả lời, trả về. Agent thì đi vòng lặp dài hơn:
- Nhận yêu cầu của người dùng.
- Hiểu ý định.
- Chọn tool khi cần.
- Gọi tool với tham số có cấu trúc.
- Dùng kết quả của tool để soạn câu trả lời.
Ví dụ khách hàng hỏi: "Đơn hàng 1052 của tôi đang ở đâu?" Agent hiểu cần tra cứu đơn hàng, chọn tool GetOrderStatus, ứng dụng chạy method C# tương ứng, lấy trạng thái đơn, và model diễn đạt lại bằng ngôn ngữ tự nhiên.
Điểm mấu chốt về an toàn nằm ở một câu: model không tự nhiên có quyền truy cập database của bạn. Nó chỉ được dùng những năng lực mà ứng dụng mở ra và cho phép. Thiết kế tốt là thiết kế sao cho câu này luôn đúng, dù sau này bạn đổi model hay đổi framework.
Dựng ranh giới bốn tầng trước khi viết agent
Clean Architecture chia ứng dụng thành các tầng có trách nhiệm rõ ràng, mục tiêu là giữ quy tắc nghiệp vụ cốt lõi độc lập với hạ tầng và framework ngoài. Khi tích hợp AI, điều này cực kỳ đáng giá vì nhà cung cấp AI, API model và framework agent đều thay đổi theo thời gian. Hôm nay bạn chạy model local qua Ollama, mai bạn chuyển sang hosted, nghiệp vụ quản lý đơn hàng không nên phải viết lại.
Một solution điển hình có bốn project:
| Tầng | Chứa gì | Tuyệt đối không chứa gì |
|---|---|---|
| Domain | Entity, quy tắc nghiệp vụ cốt lõi (Order, Product, trạng thái đơn) | Framework agent, SDK model, HTTP client, database |
| Application | Use case, điều phối nghiệp vụ, abstraction repository | Cách cấu hình agent, chi tiết AI provider |
| Infrastructure | Triển khai repository, client gọi model, tích hợp Agent Framework, API ngoài | Quy tắc nghiệp vụ |
| API | Endpoint HTTP, validate ở tầng transport | Logic nghiệp vụ, chi tiết LLM provider |
Ví dụ ở tầng Domain, entity Order chỉ là dữ liệu và quy tắc, không biết gì về AI:
namespace MyApp.Domain.Entities;
public class Order
{
public int Id { get; private set; }
public string Status { get; private set; }
public Order(int id, string status)
{
Id = id;
Status = status;
}
}
Ở tầng Application, use case "lấy trạng thái đơn hàng" được định nghĩa qua abstraction, không cần biết request đến từ controller web, background job hay AI agent:
namespace MyApp.Application.Abstractions;
public interface IOrderRepository
{
Task GetByIdAsync(int orderId, CancellationToken cancellationToken);
}
namespace MyApp.Application.Orders;
public sealed class GetOrderStatusService
{
private readonly IOrderRepository _repository;
public GetOrderStatusService(IOrderRepository repository)
{
_repository = repository;
}
public async Task ExecuteAsync(int orderId, CancellationToken cancellationToken)
{
var order = await _repository.GetByIdAsync(orderId, cancellationToken);
return order?.Status;
}
}
Tầng Infrastructure mới là nơi cấu hình agent và triển khai repository thật. Tầng API chỉ nhận câu hỏi, gọi abstraction agent của application, trả về HTTP. Controller không cần biết đang dùng LLM provider nào hay tool được đăng ký ra sao.
Định nghĩa tool: hợp đồng giữa model và code của bạn
Tool calling, hay function calling, là khái niệm quan trọng nhất khi làm agent. Tool là một hàm mà model AI có thể yêu cầu ứng dụng thực thi. Hàm chạy trong ứng dụng của bạn; model chỉ quyết định gọi tool nào với tham số gì, còn framework và ứng dụng mới là bên thực thi code thật.
Việc định nghĩa một method C# bình thường chưa làm nó thành tool. Method phải được đăng ký qua cơ chế của framework, và quan trọng hơn, phải có hợp đồng rõ ràng:
- Tên tool:
GetOrderStatus - Mô tả: lấy trạng thái đơn hàng mà khách hàng hiện tại được phép xem.
- Tham số:
orderId, có kiểm tra hợp lệ. - Kết quả trả về: trạng thái đơn, hoặc một câu trả lời "không tìm thấy" an toàn.
public async Task GetOrderStatusAsync(int orderId, CancellationToken cancellationToken)
{
var status = await _orderStatusService.ExecuteAsync(orderId, cancellationToken);
return status ?? "Order not found.";
}
Mô tả tool không phải thủ tục hành chính. So sánh hai mô tả: "Gets data." với "Retrieves the current status of an order using its ID. Use this tool when a customer asks about order progress." Mô tả thứ hai cho model biết khi nào nên dùng tool. Nhưng mô tả hay không thay thế kiểm tra quyền và validate đầu vào, việc đó vẫn nằm trong code của bạn, ví dụ chỉ cho phép tra cứu đơn của đúng khách hàng đang đăng nhập.
Nguyên tắc vàng: mở ra một tập nhỏ các thao tác được định nghĩa chặt chẽ, thay vì để model thực thi code tùy ý.
Đăng ký tool với framework
Tùy version của Microsoft Agent Framework, method C# được expose thành tool bằng factory, annotation hay cơ chế đăng ký riêng. Về mặt khái niệm, luồng đăng ký trông như sau:
// Minh họa khái niệm, không phải API đầy đủ của framework.
var tools = new[]
{
CreateTool(
method: GetOrderStatusAsync,
description: "Retrieve the current status of an order.")
};
// Đăng ký tools vào agent đã cấu hình.
Điểm cần nhớ: phần đăng ký này sống ở tầng Infrastructure, ngoài Domain. Ngày framework đổi API, bạn sửa một chỗ, nghiệp vụ không động đậy.
Chạy local với Ollama trước
Ollama cho phép chạy model ngôn ngữ ngay trên máy trong quá trình phát triển, để bạn thử hành vi của agent mà không gửi mọi prompt lên hosted. Quy trình chuẩn:
- Cài Ollama.
- Tải model phù hợp với môi trường của bạn.
- Khởi động service model local.
- Trỏ ứng dụng .NET sang endpoint local.
Khi agent đã chạy ổn local, việc chuyển sang hosted provider chỉ là thay cấu hình ở tầng Infrastructure, đúng như ranh giới đã dựng từ đầu.
Checklist trước khi đưa agent vào production
- Mỗi tool có tên, mô tả rõ ràng, tham số validate và giá trị trả về an toàn.
- Tool chỉ expose thao tác tối thiểu cần thiết, kèm kiểm tra quyền ở tầng Application.
- Không có chi tiết framework AI nào lọt vào Domain và Application.
- Đã chạy thử end-to-end với model local qua Ollama trước khi bật hosted.
- Đã đối chiếu API với docs đúng version Microsoft Agent Framework đang dùng.
- Có log ghi lại tool nào được gọi với tham số gì, để debug khi agent hành xử lạ.
Bài học lớn nhất không nằm ở framework nào thắng, mà ở thứ tự làm việc: dựng ranh giới trước, chọn model sau. Agent là phần dễ thay nhất trong hệ thống khi kiến trúc đúng, và là phần đắt nhất khi kiến trúc sai.
Nguồn tham khảo: Building an AI Agent in .NET Using Microsoft Agent Framework and Clean Architecture — DEV Community. Thông tin Microsoft Agent Framework 1.0 đã phát hành được kiểm chứng chéo qua hai bài viết độc lập trên DEV Community (tháng 4/2026). Đoạn mã trong bài là minh họa rút gọn theo bài gốc; triển khai thực tế cần đối chiếu tài liệu của đúng version framework đang dùng.