Chào mọi người! Hôm nay chúng ta sẽ khám phá một thứ cực kỳ "chất" – đó là cách tạo ra một AI Agent thông minh dùng .NET, có khả năng tự viết và chạy code C# để giải quyết cả tá công việc phức tạp. Bạn đã sẵn sàng "lặn" sâu vào thế giới này chưa? <a href="#introduction"> </a> ### Mở Màn: Thế Giới AI Đang 'Lên Đồng'! Thế giới AI tạo sinh đang tiến như vũ bão, phải không bạn? Thời cái LoL (LLM) chỉ biết 'trả bài' theo dữ liệu đã học xưa rồi Diễm ơi! Giờ đây, chúng đã trở thành những phù thủy công nghệ đích thực, biết dùng đủ thứ 'công cụ' xịn sò để làm được nhiều hơn thế nữa. Này nhé, những sáng kiến như <a href="https://modelcontextprotocol.io/introduction" target="_blank" rel="noopener noreferrer">Model Context Protocol (MCP)</a> đang mở ra một kỷ nguyên mới, và các <a href="https://mcpservers.org/" target="_blank" rel="noopener noreferrer">'server MCP'</a> thì mọc lên như nấm sau mưa. Điều này cho phép AI không chỉ nói suông mà còn hành động nữa đó! Bạn đã nghe đến khái niệm <a href="https://en.wikipedia.org/wiki/Vibe_coding" target="_blank" rel="noopener noreferrer">"vibe coding"</a> chưa? Theo ChatGPT, nó có nghĩa là: <blockquote>Vibe coding with AI is like whispering your app dreams to a super-fast coder who never sleeps—you describe what you want (“make the button red,” “add cat purring”), and the AI writes it. You review, tweak, rinse, repeat… no need to grok every line. It’s part brainstorming session, part code genie — fast, fun, and sometimes buggy magic! 😜</blockquote> Đúng là ma thuật, nhưng đôi khi cũng 'buggy' lắm nha! Mà này, Microsoft cũng vừa 'nhá hàng' .NET 10 với một loạt tính năng mới toanh. Trong đó, có một điểm sáng chói là khả năng chạy file script đơn lẻ với lệnh `dotnet run app.cs`. Tuyệt vời đúng không? Cuối cùng thì <a href="https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/" target="_blank" rel="noopener noreferrer">'single file scripts' cũng đã đến với chúng ta rồi</a>! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/gK2Jz9F.png' alt='Công thức tạo AI Agent: LLM + Tooling + .NET 10'> Ba 'nguyên liệu vàng' này – LLM đỉnh cao, khả năng gọi công cụ (tool calling) và sức mạnh của .NET 10 – sẽ giúp chúng ta 'hô biến' ra một AI Agent 'vibe coding' của riêng mình. Nó sẽ không chỉ trả lời câu hỏi mà còn tự động hoàn thành các tác vụ phức tạp nữa! Sẵn sàng 'lặn' sâu vào thế giới này chưa? Chúng ta sẽ dùng các thư viện <a href="https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai" target="_blank" rel="noopener noreferrer">Microsoft.Extensions.AI</a> để làm 'phép' nhé! <a href="#setting-up-the-stage"> </a> ### Chuẩn Bị 'Sân Khấu': Kết Nối AI và 'Công Cụ' Code Để 'phù phép', đầu tiên chúng ta cần 'triệu hồi' vài gói thư viện quan trọng và thiết lập một 'khách hàng' chat. Mình dùng một mô hình AI được host trên <a href="https://learn.microsoft.com/en-us/azure/ai-foundry/what-is-azure-ai-foundry" target="_blank" rel="noopener noreferrer">Azure AI Foundry</a>, nhưng bạn có thể dùng bất kỳ mô hình nào hỗ trợ 'tool calling' là được: ```csharp #:package Azure.AI.OpenAI #:package Microsoft.Extensions.AI #:package [email protected] #:package [email protected] using Azure.AI.OpenAI; using Microsoft.Extensions.AI; using Microsoft.Extensions.Logging; using System.ClientModel; using System.Diagnostics; var runId = Guid.NewGuid(); var azureOpenAIEndpoint = "https://<your-endpoint>.cognitiveservices.azure.com/"; var azureOpenAIModelId = "gpt-4.1"; using var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Information).AddConsole()); var client = new ChatClientBuilder( new AzureOpenAIClient(new Uri(azureOpenAIEndpoint), new ApiKeyCredential("<your-api-key>")) .GetChatClient(azureOpenAIModelId).AsIChatClient()) .UseLogging(loggerFactory) .UseFunctionInvocation(loggerFactory) .Build(); ``` Đoạn code trên nhìn có vẻ hơi 'hack não' nhỉ? Đừng lo, nó chỉ đang 'xây' cho chúng ta một 'người bạn' chat AI thông minh thôi. Cái `ChatClientBuilder` này sẽ giúp 'kết nối' AI với thế giới bên ngoài, cho phép nó 'giao tiếp' và 'hiểu' được các công cụ mà chúng ta sẽ cung cấp. Mấy dòng `runId` và `loggerFactory` thì đơn giản là để 'ghi nhật ký' và theo dõi quá trình AI làm việc thôi, tiện cho việc 'debug' sau này. Bây giờ, chúng ta đã có 'bộ não' AI, nhưng nó vẫn chưa biết 'hành động' đâu nhé! LLM tuy biết viết code nhưng cần phải có khả năng 'chạy' code đó nữa. Vậy thì, hãy cùng tạo một 'công cụ' đặc biệt để nó có thể 'thực thi' code C# của mình! Dưới đây là cách chúng ta định nghĩa công cụ 'chạy code': ```csharp var chatOptions = new ChatOptions { Tools = [ AIFunctionFactory.Create((string code) => { var logger = loggerFactory.CreateLogger("CodeExecution"); var codeFileName = @$"c:\temp\{DateTime.Now.ToString("HHmmssfff")}-{runId}.cs"; File.WriteAllText(codeFileName, code); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = $"run {codeFileName}", RedirectStandardOutput = true } }; process.Start(); process.WaitForExit(TimeSpan.FromMinutes(1)); var output = process.StandardOutput.ReadToEnd(); logger.LogInformation("Code execution output: {Output}", output); return output; }, description: "Execute the provided code.") ] }; ``` Dòng code này chính là 'trái tim' của công cụ 'thực thi code' của chúng ta. Nó nhận vào một đoạn `code` (string), sau đó 'biến' nó thành một file `.cs` tạm thời, và dùng lệnh `dotnet run` để 'hô biến' code đó thành hiện thực. Kết quả từ việc chạy code (bao gồm cả lỗi nếu có) sẽ được ghi lại và 'báo cáo' lại cho AI biết để nó 'học' hỏi và tự sửa lỗi nếu cần. À, bạn thấy `ChatOptions` và `UseFunctionInvocation` chứ? Đó chính là cách chúng ta 'kết nối' công cụ này với AI. Chúng ta 'treo' cái công cụ 'chạy code' vào `ChatOptions`, và khi AI nhận được một nhiệm vụ, nó sẽ tự động 'nghĩ' xem có cần dùng đến công cụ này để hoàn thành nhiệm vụ không. Nếu có, nó sẽ tự động 'kích hoạt' nó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/YwNq9U1.png' alt='Quy trình tương tác: User Prompt -> LLM -> Tool Execution -> Feedback'> Giờ thì cần một 'chiếc kim chỉ nam' – chính là `system prompt` – để 'dạy' AI cách viết code sao cho đúng chuẩn, đặc biệt là cách 'gọi' các gói NuGet và cấu trúc code sao cho phù hợp với .NET 10. Bởi vì sao ư? Vì các 'bộ não' AI thường được huấn luyện trên code C# cũ kỹ, nên chúng hay có thói quen viết cái `Program class` với `Main method` rườm rà lắm! Phải 'ép' nó 'quên đi lối cũ' đó bạn! ```csharp var history = new List<ChatMessage> { new(ChatRole.System, """ Write code to answer the question. If you need to use a NuGet package, specify the package name in the code like this: #:package PackageName. Some examples: #:package [email protected] #:package SemanticKernel #:package Newtonsoft.Json A code block should start with the required NuGet packages, if any, followed by one or more using statements, followed by the code. You can directly write code statements without a program class with a main method. ### Example 1 #:package [email protected] #:package SomePackage using System; Console.WriteLine("123".Humanize()); ### Example 2 #:package Microsoft.Extensions.Logging.Console using System.IO; var text = await File.ReadAllTextAsync("c:\\temp\\file.txt"); Console.WriteLine(text); ### Write and execute code to answer the question. Do not ask the user for any input, just complete all the steps below by writing and executing the code without asking for clarification or consent. """), new(ChatRole.User, """ 1. Fetch the csv file from the url 'https://raw.githubusercontent.com/fgeorges/star-wars-dataset/refs/heads/master/csv/films/films.csv' 2. Analyze the content and determine the delimiter used in the csv file. Keep in mind that text columns may contain commas as well, e.g. "A New Hope, Episode IV". 3. Determine which columns are present in the csv file and what data the columns contain. 4. Order the movies by release date, Newest first. 5. Write a .docx word document at 'c:\\temp\\star_wars_movie.docx' with one line per page with the following information: - release date - title - description """ ) }; ``` Và đây là 'nhiệm vụ bất khả thi' mà chúng ta giao cho AI: đọc file CSV từ URL, xác định dấu phân cách, phân tích cột, sắp xếp phim theo ngày phát hành, rồi ghi tất cả vào một file Word! Nghe có vẻ 'khoai' đúng không? Nhưng AI của chúng ta sẽ 'cân' hết! Bước cuối cùng là 'đẩy' những 'chỉ dẫn' này vào mô hình và chờ đợi 'buổi code' đầy cảm hứng của AI hoàn thành: ```csharp var result = await client.GetResponseAsync(history, chatOptions); Console.WriteLine($"LLM response: {result}"); ``` <a href="#reviewing-the-performance"> </a> ### 'Khám Nghiệm' Hiệu Suất: AI Tự Học Từ Lỗi Lầm Bạn có thể xem toàn bộ 'phù phép' này trong file gist tại <a href="https://gist.github.com/Expecho/0f0e30a7097676ea777bec47b764e994" target="_blank" rel="noopener noreferrer">đây</a>. Sau khi 'cầm' được nó, bạn chỉ cần chạy `dotnet run vibecoding_agent.cs` là xong! Nếu 'AI nhà mình' đang trong 'vibe' tốt, bạn sẽ thấy chỉ một file duy nhất 'xuất hiện' trong `C:\Temp`. Nhưng thường thì, 'ẻm' cần vài lần 'thử sai' mới ra được code chuẩn chỉnh. Hay ở chỗ, AI sẽ 'đọc' output từ lệnh `dotnet run`, tự nhận diện lỗi (lỗi biên dịch hay lỗi lúc chạy), rồi tự động 'sửa sai' và thử lại. Giống như một lập trình viên thực thụ vậy đó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/O6Ld04p.png' alt='Mô hình AI tự sửa lỗi và tối ưu code'> Và đây là 'thành quả' sau khi AI của mình 'vật lộn' một hồi (đây là phản hồi trực tiếp từ LLM): <blockquote> Analysis and Results: Delimiter: The delimiter used in the CSV is a comma (,). Columns present: title episode_id opening_crawl director producer release_date created edited url desc Data in Columns: title: The movie title (e.g. "A New Hope"). episode_id: The Star Wars episode number. opening_crawl: The long Star Wars intro text that appears at the start of the film. director: Film director name(s). producer: Producer name(s). release_date: Release date of the movie (e.g. "1977-05-25"). created, edited: Timestamps (likely for internal dataset management). url: URL reference for the film. desc: Another description, but appears redundant with opening_crawl. Word Document Output: The movies are ordered by release date, newest first, and written one per page. Each page includes release date, title, and description (using opening_crawl). File written: c:/temp/star_wars_movie.docx Summary of document: The document contains 7 movies, each on its own page, with release date, title, and description. Let me know if you want to see the content or need a different format! </blockquote> AI không chỉ cho ra kết quả phân tích CSV chi tiết mà còn 'tự động' tạo ra file Word với đúng định dạng yêu cầu nữa chứ! Quá đỉnh luôn! Bạn có thể tải toàn bộ 'tài liệu' này, bao gồm cả file Word cuối cùng và các 'phiên bản' code thử nghiệm của AI tại <a href="https://1drv.ms/f/c/e7c07309b5330772/EgzBSP2FZohMnJHhbGx97RYBrHt-EHheT2g2_Oc-f4BdiQ?e=3urUIh" target="_blank" rel="noopener noreferrer">đây</a>. <a href="#final-thoughts"> </a> ### Suy Ngẫm Cuối Cùng: Tiềm Năng và Cảnh Báo Mình đã thử với vài 'bộ não' AI khác nhau và kết quả thì... 'hên xui' lắm. Có em thì 'bỏ cuộc' giữa chừng, hỏi mình có muốn tiếp tục không. Có em thì viết code nhưng lại 'nhờ' mình chạy hộ, dù đã được 'trang bị' công cụ 'chạy code' rồi! Đúng là 'thuần hóa' AI cũng cần 'kiên nhẫn' và 'nghệ thuật prompt' đó bạn! **MỘT CẢNH BÁO CỰC KỲ QUAN TRỌNG:** Một điều bạn phải nhớ kỹ khi làm việc với các AI Agent có khả năng thực thi code: code do AI tạo ra (hoặc bất kỳ code nào chưa kiểm chứng) **CHỈ NÊN CHẠY TRONG MÔI TRƯỜNG CÔ LẬP, ĐƯỢC BẢO VỆ (SANDBOXED)**. Vì sao ư? Vì chúng ta không thể đảm bảo 100% rằng không có code độc hại hay các phụ thuộc 'lởm khởm' nào bị chèn vào đâu nhé! An toàn là trên hết! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/eB3R4zZ.png' alt='Môi trường sandbox an toàn cho việc thực thi code AI'> Vậy thì, những AI Agent kiểu này sẽ có 'đất diễn' ở đâu nhỉ? Thành thật mà nói, mình cũng chưa hình dung rõ lắm đâu. Mình được truyền cảm hứng từ <a href="https://microsoft.github.io/autogen-for-net/" target="_blank" rel="noopener noreferrer">AutoGen for .Net</a>, một dự án cho phép <a href="https://microsoft.github.io/autogen-for-net/articles/Run-dotnet-code.html" target="_blank" rel="noopener noreferrer">chạy các đoạn code</a>. Mình nghĩ .NET 10 đã 'hạ thấp rào cản' để chúng ta có thể tạo ra những AI Agent có khả năng 'code' đỉnh cao hơn nhiều. Bạn nghĩ sao? Đây có phải là một tính năng 'đáng đồng tiền bát gạo' không? Mình rất tò mò muốn nghe ý kiến của bạn đó, đừng ngại để lại bình luận bên dưới nhé!
MassTransit v9 sắp chuyển sang mô hình cấp phép thương mại từ 2026. Bài viết này sẽ phân tích chi tiết các tính năng, cách tích hợp với RabbitMQ, Azure Service Bus và giúp bạn đánh giá liệu có nên tiếp tục đầu tư vào MassTransit hay tìm giải pháp thay thế. Tìm hiểu về Outbox Pattern, Sagas và hiệu quả của MassTransit trong ứng dụng phân tán.
Tìm hiểu về Model Context Protocol (MCP) – tiêu chuẩn mới giúp AI Agent tương tác với các công cụ thực tế như database và GitHub. Khám phá cách .NET trở thành nền tảng lý tưởng để xây dựng các ứng dụng AI thông minh, an toàn và hiệu quả, mở ra kỷ nguyên mới cho lập trình viên.
Chào bạn, có bao giờ bạn "đau đầu" khi muốn tách bạch rạch ròi các "món" trong ứng dụng như ghi log, thao tác database hay logic nghiệp vụ chưa? Dù bạn có thể "chế biến" một kiến trúc đơn khối (monolithic) truyền thống để làm được một phần, nhưng tin tôi đi, có một cách "cao cấp" hơn nhiều! Nếu tôi nói với bạn rằng có một phong cách kiến trúc được thiết kế để phân tách các "mối quan tâm" này một cách sạch sẽ và hiệu quả thì sao? Vâng, đó chính là Clean Architecture hay còn gọi là "Kiến trúc Sạch"! Hãy cùng tôi khám phá xem tại sao nó lại "chất" đến vậy nhé!Clean Architecture về cơ bản là một kiến trúc đa tầng, thực thi sự phân tách rạch ròi các "mối quan tâm" thông qua các ranh giới cực kỳ nghiêm ngặt. Mỗi tầng có một vai trò và hướng phụ thuộc rõ ràng. Thường thì, chúng ta có bốn tầng chính trong Clean Architecture:<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sj5uwjpxd750pi719pk9.png' alt='Mô hình Clean Architecture với các lớp'>1. Tầng Domain (Vùng lõi/Trái tim):Đây là tầng cốt lõi và nằm trong cùng của kiến trúc. Nó chẳng thèm phụ thuộc vào bất kỳ tầng nào khác đâu nhé! Tầng này chứa đựng "mô hình kinh doanh thuần túy" của ứng dụng bạn, tức là những quy tắc, đối tượng "thuần khiết" nhất của nghiệp vụ. Bạn sẽ không tìm thấy bất kỳ gói NuGet hay thư viện "lung tung" nào ở đây đâu. Nó thường bao gồm: Enum (liệt kê), Model (mô hình dữ liệu), Constant (hằng số) và Value Object (đối tượng giá trị).2. Tầng Application (Điều phối viên):Tầng Application chỉ phụ thuộc vào tầng Domain mà thôi. Nó chứa đựng các "trường hợp sử dụng" (use case) và logic nghiệp vụ, có nhiệm vụ "điều phối" các thao tác bằng cách sử dụng các thực thể (entity) từ tầng Domain. Ở đây, bạn sẽ định nghĩa: Các dịch vụ ứng dụng (chính là các use case), các giao diện (interface) cho kho lưu trữ (repository) hoặc các dịch vụ bên ngoài, và các quy tắc/ràng buộc về kiểm định dữ liệu (validation rules). Ví dụ, logic về cách tạo một yêu cầu mới, hoặc khi nào một quy trình làm việc nên được kích hoạt, đều nằm gọn trong tầng này.3. Tầng Infrastructure (Hậu cần/Dịch vụ tiện ích):Tầng này cung cấp các "hiện thực" cụ thể cho các giao diện đã được định nghĩa ở tầng Application. Nó phụ thuộc vào tầng Application. Nhưng vì Application lại phụ thuộc vào Domain, nên tầng Infrastructure cũng gián tiếp phụ thuộc vào tầng Domain. Các thành phần điển hình ở đây là: Ngữ cảnh cơ sở dữ liệu (ví dụ: AppDbContext trong EF Core), các hiện thực của Repository (cách lưu trữ và truy xuất dữ liệu), các dịch vụ bên ngoài (như gửi email, lưu trữ file), và các cấu hình hay di chuyển dữ liệu (data migrations).4. Tầng Presentation (Mặt tiền/Giao diện):Đây là tầng ngoài cùng của hệ thống. Nó cung cấp giao diện người dùng (UI) hoặc API để các ứng dụng bên ngoài tương tác. Tầng này phụ thuộc vào cả tầng Application và Infrastructure. Nó thường chứa: Các điểm cuối API (ví dụ: Minimal APIs hoặc Controllers trong ASP.NET Core), các "middleware" (những đoạn mã chạy xen kẽ để xử lý yêu cầu, ví dụ: xử lý ngoại lệ toàn cục), và logic xác thực/phân quyền (Authentication & Authorization).Câu hỏi lớn: Tại sao lại chọn Clean Architecture?Hồi xưa, tôi cũng từng băn khoăn liệu Clean Architecture có "hợp cạ" với dự án của chúng tôi không — cụ thể là hiện đại hóa một loạt các ứng dụng "nhà làm". Công ty tôi đang làm có hơn 20 ứng dụng nội bộ, mỗi cái được xây dựng qua thời gian với các framework và phong cách kiến trúc khác nhau. Một số dùng Angular, số khác dùng .NET, và vài cái thì dùng React. Khi hệ thống lớn dần, việc duy trì chuyên môn trên nhiều "ngăn tủ" công nghệ như vậy trở nên cực kỳ khó khăn và kém hiệu quả. Chúng tôi không muốn phải "săn lùng" các lập trình viên có kỹ năng đặc thù cho từng ứng dụng nữa.Thế là, chúng tôi đưa ra một quyết định chiến lược: chuẩn hóa tất cả các ứng dụng mới và đã hiện đại hóa bằng một "ngăn tủ" công nghệ duy nhất — .NET kết hợp với Clean Architecture. Quyết định này mang lại khả năng mở rộng tốt hơn, phân tách nghiệp vụ rõ ràng, và quan trọng nhất là sự **nhất quán** trên tất cả các ứng dụng.Ban đầu, cách tiếp cận này nghe có vẻ "over-engineering" (quá phức tạp hóa) — đặc biệt là với các ứng dụng nhỏ hơn của chúng tôi. Clean Architecture giới thiệu nhiều tầng và cấu trúc hơn, điều này có thể gây cảm giác "nặng nề" khi ứng dụng của bạn chỉ có vài tính năng hoặc lượng người dùng hạn chế (chúng tôi có khoảng 2.000 người dùng). Nhưng nói thật nhé, kiến trúc không chỉ xoay quanh số lượng người dùng đâu — nó còn là về **mức độ phức tạp**.Ngay cả khi một ứng dụng khởi đầu nhỏ bé, logic nghiệp vụ vẫn có thể phát triển "chóng mặt". Với các cấu trúc đơn khối, bạn có nguy cơ "đổ dồn" mọi thứ vào một "tầng nghiệp vụ" khổng lồ theo thời gian. Clean Architecture giúp bạn tránh điều đó bằng cách "cắm cọc" ranh giới ngay từ đầu.Đúng, ban đầu nó có vẻ phức tạp hơn một chút. Các lập trình viên mới có thể cần thời gian để làm quen với cấu trúc. Nhưng một khi họ đã "nhập tâm", họ sẽ cực kỳ trân trọng cách nó giúp việc điều hướng, bảo trì và mở rộng codebase trở nên dễ dàng đến không ngờ — từng tầng một, từng tính năng một.Câu hỏi: Làm thế nào để triển khai?Vậy, làm thế nào để thực sự xây dựng một giải pháp Clean Architecture đây? Điều quan trọng nhất đối với chúng tôi, khi hiện đại hóa hơn 20 ứng dụng nội bộ, là phải thiết lập một **boilerplate** (một bộ khung mẫu) chung — một mẫu có thể tái sử dụng, đóng vai trò là điểm khởi đầu cho mọi ứng dụng chúng tôi sẽ xây dựng sau này.Dưới đây là cái nhìn tổng quan về cấu trúc đó:<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pqmth4j5d9g8coful1cf.png' alt='Cấu trúc mẫu tổng thể của giải pháp Clean Architecture'>Trong bài viết này, tôi sẽ giải thích cấu trúc một cách khái quát. Trong các bài viết sau, tôi sẽ đào sâu vào từng thành phần cụ thể hơn. Bây giờ, hãy bắt đầu bằng cách tạo một solution trống trong VS 2022, sau đó làm theo các bước sau:Các tệp cấu hình cho toàn bộ Solution:Những tệp này áp dụng cài đặt cho toàn bộ solution, chứ không phải chỉ riêng từng project đâu nhé!editorconfig: Chứa các quy tắc định dạng mã. Ví dụ, trong Visual Studio 2022, tệp này có thể buộc các quy ước đặt tên (ví dụ: biến readonly phải bắt đầu bằng _, biến static phải bắt đầu bằng s_). Bạn tạo nó bằng cách: Add → New Item → Editor Config (.NET).Directory.Build.props: Lưu trữ các siêu dữ liệu chung cho tất cả các project (ví dụ: tên, mô tả, URL kho Git). Bạn tạo nó bằng cách: Add → New Item → XML File. Nó sẽ chứa các cài đặt như Title, Authors, Description, TargetFramework, Nullable, ImplicitUsings, v.v., áp dụng đồng bộ cho các project con.Directory.Packages.props: Tập trung các tham chiếu gói NuGet trên toàn solution, giúp bạn tránh tình trạng "thừa thãi" và dễ dàng quản lý phiên bản. Bạn tạo nó bằng cách: Add → New Item → XML File. Nó sẽ khai báo các phiên bản gói NuGet dùng chung như Carter, Microsoft.AspNetCore.OpenApi, Microsoft.EntityFrameworkCore.Design, v.v., đảm bảo tất cả project đều dùng chung một phiên bản.src/Backend: Hậu cần theo Clean ArchitectureThư mục này chứa giải pháp backend dựa trên Clean Architecture.ISWebAppTemplate.Api: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9zwqouyc8l79hj1ubcwf.png' alt='Cấu trúc tầng Presentation trong template'> Đây là tầng Presentation (tầng ngoài cùng). Một project ASP.NET Core Web API.ISWebAppTemplate.Application: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65qiidb6nowpabds5hj3.png' alt='Cấu trúc tầng Application trong template'> Tầng Application. Một thư viện class tập trung vào logic nghiệp vụ.ISWebAppTemplate.Infrastructure: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxkob73gsbeeiyo3ziry.png' alt='Cấu trúc tầng Infrastructure trong template'> Tầng Infrastructure. Một thư viện class tập trung vào xử lý tương tác cơ sở dữ liệu và các dịch vụ bên ngoài.ISWebAppTemplate.Domain: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vyw4w7iz6uwldm7lfu2.png' alt='Cấu trúc tầng Domain trong template'> Tầng Domain (tầng cốt lõi nhất). Chứa các thực thể domain, đối tượng giá trị và các quy tắc cốt lõi.src/Frontend: Giao diện Web BlazorThư mục này chứa ứng dụng frontend. Tôi đã tạo Blazor Web App và chọn Blazor server làm renderer.ISWebAppTemplate.WebUI: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0k02k5mh5t9c3tb3dbx.png' alt='Cấu trúc UI trong template'> Một ứng dụng Blazor Server với:Radzen cho các thành phần UI.Xác thực Azure Entra MFA.Tạo Correlation ID để theo dõi các yêu cầu qua các API downstream — cực kỳ hữu ích khi gỡ lỗi và phân tích log./tests: Kiểm thử Unit và Tích hợpChúng tôi tách biệt các bài kiểm thử thành hai tầng rõ ràng:ISWebAppTemplate.Integration.Tests: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1v76tuh1zcfpbx7bt6q3.png' alt='Cấu trúc kiểm thử tích hợp trong template'>Trọng tâm: Kiểm thử toàn bộ giao dịch và hành vi.Ví dụ: Nếu người yêu cầu thuộc Band X, không cần phê duyệt; ngược lại, phải kích hoạt phê duyệt của quản trị viên. Các bài kiểm thử tích hợp sẽ xác minh logic nghiệp vụ này một cách toàn diện.ISWebAppTemplate.Unit.Tests: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com/uploads/articles/05kx2dswdshd82dxomrq.png' alt='Cấu trúc kiểm thử Unit trong template'>Trọng tâm: Kiểm định và logic ở cấp độ thực thể.Ví dụ: Tiêu đề yêu cầu phải dài ít nhất 50 ký tự.Sự khác biệt chính: Kiểm thử Unit (Unit tests) xác thực các thành phần cô lập như một trường hoặc một quy tắc. Kiểm thử Tích hợp (Integration tests) xác thực hành vi từ đầu đến cuối và cách áp dụng quy tắc.Kết luận:Tôi biết là bài này có hơi "nặng đô" một chút — đặc biệt là tôi mới chỉ "cào" được bề mặt thôi. Nhưng đừng lo, tôi sẽ đi sâu hơn nữa trong các bài viết sắp tới. Mỗi kỹ thuật và mẫu thiết kế được sử dụng trong dự án này sẽ được tôi "mổ xẻ" riêng biệt để bạn có cái nhìn rõ ràng và thực tế hơn về cách chúng hoạt động trong các kịch bản thực tế.Vậy, tại sao lại chọn Clean Architecture thay vì một kiến trúc đơn khối truyền thống? Tất cả đều quy về việc **phân tách nghiệp vụ**, **khả năng mở rộng** và **khả năng bảo trì lâu dài**. Clean Architecture đã mang lại cho chúng tôi một cấu trúc giúp quản lý logic nghiệp vụ phức tạp trên hơn 20 ứng dụng — điều mà một cấu trúc đơn khối thông thường sẽ trở nên "bất trị".Lưu ý nhỏ: Chúng tôi không sử dụng Docker hay container hóa trong thiết lập này. Vì các ứng dụng của chúng tôi phục vụ khoảng 2.000 người dùng và được lưu trữ trên một máy chủ ổn định tại chỗ (on-premise server), nhu cầu hiệu suất được đáp ứng dễ dàng. Lý do chính để áp dụng Clean Architecture là để quản lý logic nghiệp vụ phức tạp tốt hơn, chứ không phải để đáp ứng quy mô hay tính linh hoạt triển khai.Hẹn gặp lại bạn ở bài viết tiếp theo: "Tạo và Phát hành Custom .NET Project Template và Private NuGet lên GitLab Package Registry"!
Khám phá Pattern Outbox – 'người hùng' đảm bảo tính nhất quán và giao tiếp đáng tin cậy trong các hệ thống microservices phân tán. Tìm hiểu cách Brighter tích hợp và triển khai Outbox một cách 'thần kỳ', giải quyết triệt để vấn đề mất tin nhắn và lỗi giao dịch. Một giải pháp không thể thiếu cho kiến trúc hiện đại!
Khám phá các vấn đề giao tiếp phổ biến trong Microservices và cách khắc phục chúng bằng các mô hình hiện đại như nhắn tin bất đồng bộ, Circuit Breakers, Fallbacks và Observability để xây dựng hệ thống linh hoạt, mạnh mẽ.
Khám phá cách xây dựng AI Agent thông minh dùng .NET để tự động viết và thực thi code C#. Tìm hiểu về vibe coding, .NET 10, LLM và khả năng gọi công cụ để giải quyết các nhiệm vụ phức tạp. Đừng bỏ lỡ bài hướng dẫn chi tiết này!
Đâu là lựa chọn tốt nhất giữa .NET và MERN cho sự nghiệp lập trình của bạn? Khám phá lý do tại sao .NET có thể là "vũ khí bí mật" giúp bạn phát triển bền vững trong thế giới công nghệ luôn biến động.
Tìm hiểu cách khắc phục các vấn đề giao tiếp trong kiến trúc microservices bằng cách áp dụng truyền tin bất đồng bộ, resilience (timeouts, retries, circuit breakers), fallbacks và observability. Biến hệ thống của bạn trở nên mạnh mẽ hơn.
Hướng dẫn chi tiết cách chuyển đổi nội dung HTML từ các mô hình AI (LLM) thành tài liệu Word DOCX chuyên nghiệp bằng C# và thư viện OpenXML, HtmlToOpenXml. Biến phản hồi AI thành báo cáo, biên bản dễ dàng.
Tìm hiểu sâu về Caching trong ứng dụng đám mây, tập trung vào Azure Cache for Redis, các kỹ thuật caching khác trên Azure, AWS, GCP và những best practice để tối ưu hiệu suất và chi phí.
Khám phá cách triển khai Outbox Pattern "siêu đỉnh" với SQL Server và thư viện Brighter trong .NET 8+. Đảm bảo nhất quán giao dịch và tin nhắn không bao giờ thất lạc trong các hệ thống phân tán, từ thiết kế bảng Outbox đến tích hợp Dependency Injection và xử lý lỗi hiệu quả.
Bạn có "nghiện" LLM nhưng lại đau đầu với kiến trúc dự án? Khám phá Spiderly - Framework mã nguồn mở giúp xây dựng ứng dụng web nhanh chóng, chuẩn mực với khả năng tự động sinh mã quản trị Entity, xác thực, và nhiều tính năng thiết yếu khác. Tiết kiệm thời gian, tập trung vào logic nghiệp vụ và xây dựng nền tảng vững chắc cho mọi dự án.
Bạn có bao giờ cảm thấy 'lạc lối' giữa rừng kiến thức về kiến trúc phần mềm không? Bài viết này sẽ 'mổ xẻ' khi nào các mẫu kiến trúc 'đình đám' như Domain-Driven Design (DDD), Clean Architecture hay Command Query Responsibility Segregation (CQRS) thực sự 'cứu cánh' chúng ta, và khi nào thì chúng ta lại tự 'gây họa' bằng những sự trừu tượng không cần thiết – mà điển hình là anh bạn Generic IRepository 'đa năng' quá mức. Chúng ta cũng sẽ 'khui' ra một anh chàng cực kỳ hữu ích trong .NET là IServiceScopeFactory để bạn hiểu rõ hơn về cách quản lý vòng đời dịch vụ sao cho 'chuẩn bài' nhất.
Khám phá cách xây dựng ứng dụng AI tạo sinh miễn phí với GitHub Models và Semantic Kernel trong C#. Hướng dẫn chi tiết từ cài đặt, tạo token đến xây dựng chatbot.
Tưởng tượng mà xem! Bạn có bao giờ mơ ước có một anh bạn AI siêu thông thái, vừa biết tuốt về phim ảnh, vừa nhớ rõ bạn đã xem gì, lại còn gợi ý những bộ phim hay ho "đúng gu" bạn không? Nghe như câu chuyện khoa học viễn tưởng nhỉ? Nhưng không đâu, đây chính là câu chuyện có thật về cách chúng mình biến TMDB (The Movie Database) thành một "sân chơi" Gen-AI plugin cực kỳ xịn sò, với sự trợ giúp của "phù thủy" Semantic Kernel đấy! Điều bất ngờ nhất là, toàn bộ "phép thuật" này chỉ gói gọn trong vỏn vẹn 7 chức năng plugin nhỏ xíu thôi! Nào, chúng ta cùng nhau khám phá hành trình biến TMDB thành một "kho báu" AI đầy thú vị nhé! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/tmdb_ai_playground.png' alt='AI chat về phim trên nền TMDB'> 1. Vì sao TMDB + Plugin là "Mỏ Vàng" của dân Lập Trình? Bạn thắc mắc tại sao lại là TMDB mà không phải một "ngôi sao" nào khác? Đơn giản thôi, vì nó chính là một "mỏ vàng" cho các nhà phát triển! Dưới đây là những lý do khiến TMDB trở thành lựa chọn "đỉnh của chóp": Kho dữ liệu khổng lồ: Phim nào cũng có mặt từ A đến Z, từ tiêu đề, năm sản xuất, thể loại, poster "lung linh", cho đến điểm đánh giá chi tiết... Đủ để anh bạn AI của chúng ta "nghiên cứu" tẹt ga, tha hồ học hỏi. Thật tiện lợi phải không nào? API mở cửa đón chào: Tuyệt vời hơn nữa là bạn chẳng cần phải "nhảy múa" với các bước xác thực OAuth phức tạp, lại còn có gói miễn phí cực kỳ hào phóng. Cứ gọi là dùng thôi! Nó giống như một thư viện khổng lồ mở cửa 24/7, chào đón mọi nhà phát triển vậy. "Bản đồ" rõ ràng, dễ gọi: Các "điểm đến" (endpoint) như /movie/top_rated hay /search/movie đều được chỉ rõ ràng, gọi một phát là "ra ngay và luôn". Cứ như bạn có một tấm bản đồ Google Maps siêu chi tiết, chỉ đường cho từng con phố vậy đó! Đã được dọn sẵn mâm: TMDB đã tự động sắp xếp phim theo độ phổ biến và điểm số rồi. Việc của chúng ta chỉ là lọc nhẹ lại theo ý muốn thôi! Quá là "khỏe re" luôn! 2. Bảy "Chiêu Thức" Đã Được Triển Khai Ngay Hôm Nay Nghe có vẻ "lớn lao" lắm, nhưng thực ra, anh bạn AI của chúng ta chỉ cần "học thuộc lòng" 7 "chiêu" sau là đủ để "tung hoành ngang dọc" trong thế giới phim ảnh rồi. Đơn giản mà lợi hại phải không nào? "Cho tôi xem 10 phim top của TMDB đi." (Dùng tmdb.GetTopRatedMoviesAsync(take) để "triệu hồi" danh sách phim đình đám nhất.) "Tìm phim có chữ 'star wars' trong tên hộ cái." (Sử dụng tmdb.SearchMoviesAsync(query) để "lục lọi" kho phim theo từ khóa.) "Thêm phim Interstellar vào danh sách đã xem của tôi." (Với memory.AddWatchedAsync(title), bạn có thể "đánh dấu" những bộ phim đã "cày" xong.) "Gỡ Interstellar khỏi danh sách đã xem." (Xóa phim khỏi "lịch sử xem" bằng memory.RemoveWatchedAsync(title).) "Tôi đã xem những phim gì rồi?" (Hỏi memory.ListWatchedAsync() để "tra cứu" lại những bộ phim đã xem.) "Tôi mê tít phim Dune — có phim nào tương tự không?" (Đây là "chiêu" kết hợp: đầu tiên tmdb.SearchMovieIdAsync để tìm phim Dune, sau đó tmdb.GetMovieRecommendationsAsync để tìm phim "na ná".) "Gợi ý cho tôi 5 phim điểm cao mà tôi chưa xem đi!" (Tuyệt chiêu reco.RecommendMoviesAsync(top) sẽ giúp AI "đau đầu" suy nghĩ và gợi ý những phim hay ho mà bạn chưa từng xem, "đúng gu" bạn luôn!) <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/seven_skills_icons_programming.png' alt='Các icon minh họa 7 chức năng plugin'> 3. Kiến Trúc Trong Vòng 60 Giây (Dễ Hiểu Hơn Cả Xem Phim!) Kiến trúc phức tạp ư? Đừng lo lắng, chỉ 60 giây là bạn sẽ "nắm gọn trong lòng bàn tay" thôi! Semantic Kernel: Hãy hình dung nó như một "đạo diễn" tài ba của cả hệ thống AI. Anh bạn này lo mọi thứ từ việc quản lý các plugin "bé tí" của bạn cho đến việc kết nối chúng lại với nhau một cách mượt mà. Cứ yên tâm giao phó nhé, "đạo diễn" lo hết! Stepwise Planner: Đây mới chính là "bộ não" thực sự, linh hồn của sự thông minh! Khi bạn "ra lệnh" cho AI, Planner sẽ "đọc vị" yêu cầu, tự động chọn ra những chức năng (plugin) phù hợp nhất, rồi cứ thế "lần mò", "thử và sai" từng bước cho đến khi có thể trả lời bạn bằng ngôn ngữ tự nhiên, y như một người bạn vậy. Cứ như có một trợ lý siêu thông minh luôn theo sát và phục vụ bạn vậy! Còn về việc lưu trữ "lịch sử xem phim" của bạn? Hiện tại, chúng mình đang dùng bộ nhớ tạm thời (kiểu như ghi chú nhanh trên giấy nháp thôi). Nhưng nếu bạn muốn "nâng cấp" lên Redis hay SQLite để lưu trữ vĩnh viễn (kiểu như cất vào tủ sắt), thì dễ như trở bàn tay thôi! Chỉ cần thay đổi một giao diện nhỏ là xong, không cần "đập đi xây lại" gì đâu nhé! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/semantic_kernel_flow_simple.png' alt='Sơ đồ kiến trúc Semantic Kernel và Planner'> 3.5. Agent hay chỉ là gọi hàm bình thường? 🤔 (Câu hỏi "Triệu Đô" của dân Lập Trình AI) Đây là một câu hỏi "kinh điển" mà nhiều bạn mới tìm hiểu về AI hay lăn tăn. Thực ra, "function-calling" của OpenAI chỉ giống như một sợi dây kết nối, một "tín hiệu JSON có cấu trúc" giúp LLM (mô hình ngôn ngữ lớn) "bật đèn xanh" để gọi các phương thức C# của bạn. Nó giống như việc bạn bấm một nút duy nhất để bật đèn vậy. Còn "Agent" (tạm dịch là Đặc vụ AI) thì khác bọt hoàn toàn! Nó là cả một "vòng lặp thông minh", một "cỗ máy suy nghĩ" không ngừng tự hỏi: "Mình đã biết đủ để trả lời câu hỏi này chưa nhỉ?" Nếu câu trả lời là "chưa", nó sẽ không ngừng tự động chọn một plugin khác, gọi plugin đó, cập nhật lại "bối cảnh" câu chuyện, rồi lại lặp đi lặp lại quá trình này cho đến khi có thể trò chuyện với bạn y như một con người thật sự. Bốn "trụ cột" vững chắc tạo nên một Agent thực thụ chính là: Khả năng suy luận (Reasoning): Tự động "động não" để tìm ra công cụ nào hữu ích nhất cho vấn đề đang cần giải quyết. Sử dụng công cụ (Tool-use): Tự động "tay chân" gọi các plugin thông qua cơ chế function-call. Bộ nhớ (Memory): Khả năng "ghi nhớ" và tái sử dụng những gì đã học được, giống như một cuốn nhật ký thông minh. Khả năng tự chủ (Autonomy): Tự mình "xoay sở", lặp lại các bước mà không cần bạn phải viết hàng tá câu lệnh if/else để điều khiển từng ly từng tí. Khi bạn "ghép" bốn "siêu năng lực" này lại với nhau, bạn sẽ có một Agent AI cực kỳ xịn xò đó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/ai_agent_four_pillars.png' alt='Bốn trụ cột của AI Agent'> 4. Nhật Ký Lỗi: Khi Một Dấu Cách "Hạ Sát" Cả Danh Sách 🔪 (Chuyện thật như đùa của dân dev!) Trong đời lập trình viên, ai mà chẳng đôi lần "vấp phải ổ gà" phải không? Và đây là một câu chuyện "đau thương" nhưng cũng không kém phần hài hước của chúng mình. Trong lần thử nghiệm đầu tiên với chức năng "Gợi ý cho tôi 5 phim điểm cao mà tôi chưa xem," anh bạn AI của chúng ta trả về... chỉ toàn là số: 8.5, 8.4, 8.3, 8.2... Ủa, phim đâu rồi? Tên phim "đi đâu mất tiêu" vậy trời? Té ra, các plugin TMDB của chúng ta "ngây thơ" vô số tội khi nối các dòng kết quả lại với nhau bằng một... dấu cách: return string.Join(" ", lines);. Rồi cái plugin đề xuất phim lại "ngây thơ" không kém khi tách chuỗi ra cũng bằng... dấu cách: list.Split(' '). Kết quả là: Dấu cách "đi vào", dấu cách "đi ra", và thế là tên phim "bốc hơi" không một dấu vết! Cả một danh sách phim "tăm hơi đâu mất"! Giải pháp thần thánh ư? Chỉ cần thay đổi MỘT KÝ TỰ duy nhất! Thay dấu cách bằng ký tự xuống dòng (\n). Tức là return string.Join('\n', lines);. Và dĩ nhiên, hai chỗ .Split() cũng phải đổi theo để nhận diện đúng ký tự xuống dòng. Thật là một bài học "đắt giá" nhưng đáng nhớ phải không nào? Bài học rút ra: Mấy cái ký tự phân cách (delimiter) tưởng chừng "nhỏ bé hạt tiêu" nhưng lại có "võ công cao cường" lắm đấy! Một lỗi nhỏ ở "đường ống dẫn dữ liệu" cũng có thể "phá nát" cả trải nghiệm người dùng. Cứ như việc đặt một viên sỏi nhỏ mà làm tắc cả con sông lớn vậy đó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/bug_diary_space_killed_list.png' alt='Lỗi dấu cách làm mất dữ liệu'> 5. Stepwise Planning: "Phép Thuật" Có Thật! 🤖✨ (Xem AI "Diễn Xiếc" Nè!) Để bạn dễ hình dung hơn về "phép thuật" của Stepwise Planning, hãy cùng xem một ví dụ "người thật việc thật" nhé. Đảm bảo bạn sẽ "mắt chữ A, mồm chữ O" luôn! Người dùng "ra lệnh": "Tôi đã xem Fight Club và Whiplash rồi — giờ gợi ý phim mới cho tôi đi." Và đây là cách Planner (Bộ não AI) "âm thầm" làm việc: memory.AddWatchedAsync("Fight Club") ✔️ (Ok, "đánh dấu" Fight Club đã xem!) memory.AddWatchedAsync("Whiplash") ✔️ (Tiếp tục "đánh dấu" Whiplash nữa nhé!) reco.RecommendMoviesAsync(top = 20) → (Giờ thì tìm và gợi ý 20 phim khác, loại trừ những phim đã xem, siêu thông minh!) Parasite (2019) 8.5 ... (và hàng loạt gợi ý khác) Cuối cùng, anh bạn Bot của chúng ta "chảnh chọe" trả lời: Parasite (2019) 8.5 La La Land (2016) 8.0 ... (Và còn rất nhiều phim hay khác đang chờ bạn khám phá!) Bạn thấy đó, không hề có một dòng code nào "điều khiển" hay "ra lệnh" cho Planner phải làm gì cả! Nó hoàn toàn tự động "xâu chuỗi" ba plugin lại với nhau một cách mượt mà, cứ như có một "phù thủy" đang âm thầm đạo diễn vậy. Đỉnh của chóp phải không nào? <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/stepwise_planning_example_flow.png' alt='Ví dụ về Stepwise Planning'> 6. Tiếp Theo, Chúng Ta Sẽ Đi Đâu? 🚀 (Những Kế Hoạch "Khủng" Trong Tương Lai!) Dự án "Bot mê phim" này vẫn còn rất nhiều tiềm năng để phát triển! Chúng mình đã lên kế hoạch cho các bước tiếp theo "khủng" hơn nữa, hứa hẹn sẽ biến anh bạn AI này trở thành một "thư viện phim biết nói" thực thụ: Bộ lọc năm & thể loại "siêu cấp": Thêm tùy chọn để tìm phim theo năm hoặc thể loại cụ thể. Giờ thì có thể tìm phim hành động của thập niên 90 "trong vòng một nốt nhạc" rồi! Thông tin nền tảng stream "chuẩn chỉnh": Kết nối với các API như JustWatch hay Reelgood để biết phim đó có trên Netflix, HBO Go hay không. Không còn phải mất công đi tìm "mỏi mắt" nữa! Bộ nhớ "trường tồn cùng thời gian": Chuyển dữ liệu đã xem từ bộ nhớ tạm thời sang Redis hoặc SQLite để "lịch sử xem phim" không bao giờ bị mất đi, kể cả khi bạn tắt máy hay mất điện. Yên tâm "cày phim" nhé! Giao diện web "lung linh lấp lánh": Đưa toàn bộ "trái tim" AI này vào một giao diện web đẹp mắt dùng React + Tailwind. Đảm bảo mê ly, ai nhìn cũng muốn dùng ngay! "Tâm sự" với AI như tri kỷ: Thêm tính năng "nhân cách hóa" cho AI, ví dụ bạn có thể bảo "tối nay xem phim cùng trẻ con nhé" để AI gợi ý phim phù hợp. Anh bạn AI sẽ hiểu ý bạn hơn, cứ như một người bạn thân vậy! Tạo poster "thần tốc" khi cần: Nếu phim không có poster, AI sẽ dùng image_gen.text2im để tạo ra ngay một cái poster "chất lừ"! Đảm bảo phim nào cũng có ảnh minh họa đẹp mắt. Mỗi bước này đều là một "lát cắt" nhỏ, có thể là một plugin mới hoặc thêm một tham số đơn giản, chứ không hề phải viết lại từ đầu đâu nhé! Thật là hiệu quả và tiện lợi! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/future_roadmap_features.png' alt='Kế hoạch phát triển các tính năng tương lai'> 7. Lời Kết: Bí Quyết Đằng Sau "Chàng Bot" Mê Phim 🎬 (Công Thức Vàng cho AI Đàm Thoại!) Tóm lại, công thức "thần kỳ" để tạo ra những ứng dụng AI đàm thoại siêu đỉnh, mà gần như không cần "dán keo" (glue code – tức là các đoạn mã kết nối lộn xộn) là gì? Đó chính là sự kết hợp hoàn hảo giữa: Các chức năng plugin nhỏ gọn, rõ ràng + OpenAI Function-Calling + Semantic Kernel. TMDB là lựa chọn "hoàn hảo không tì vết" cho dự án này vì dữ liệu "sạch đẹp" của nó, API thân thiện "đúng điệu", và quan trọng nhất là... ai mà chẳng thích nói chuyện về phim ảnh phải không nào? Nếu bạn thấy hứng thú với "chàng bot" mê phim này, đừng ngần ngại "fork" ngay kho code này về máy, thử thay TMDB bằng lĩnh vực yêu thích của bạn (sách? nhà hàng? game? thời trang?), và bạn sẽ thấy cùng một công thức "vàng" này tỏa sáng rực rỡ trong mọi ngóc ngách của thế giới số! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/happy_coding_movie.png' alt='Người đang code và xem phim'> Repo Github: https://github.com/olavgerritsen98/SemanticKernelAgentsDemo Chúc bạn code vui vẻ — và xem phim cũng vui vẻ nhé!
Chào các bạn coder và những ai đang "đắm chìm" trong thế giới AI đầy mê hoặc! Chắc hẳn bạn đã từng trải qua cảm giác phấn khích tột độ khi "thai nghén" ra một hệ thống AI siêu việt, đúng không? Nhưng khoan đã, hành trình chưa dừng lại ở đó đâu nhé! Một trong những thử thách "khó nhằn" nhất khi phát triển AI là làm sao để hệ thống của bạn không chỉ "ngon lành" lúc mới ra lò, mà còn phải "trường tồn" và thích nghi tốt khi nó lớn mạnh, được triển khai ra thế giới thật.Tưởng tượng mà xem, việc tạo mẫu (prototyping) AI có thể rất vui và đầy hào hứng, nhưng cuối cùng, "đứa con" AI của chúng ta cần được "thả" vào đời thực và "trưởng thành" theo thời gian. Và việc "trưởng thành" này có thể đến từ vô vàn thay đổi: Thay đổi "câu thần chú" (system prompt) để AI thông minh hơn hoặc sửa lỗi. "Đổi tim" cho AI bằng cách thay thế mô hình ngôn ngữ lớn (LLM) hoặc mô hình nhúng (embedding model) đang dùng. "Trang bị thêm vũ khí" cho AI, cho phép nó gọi thêm các công cụ mới (đặc biệt trong các kịch bản gọi hàm với Semantic Kernel hay Model Context Protocol). Thay đổi "sách vở" mà AI dùng để học (dữ liệu cho Retrieval Augmentation Generation - RAG), điều này thường diễn ra tự nhiên khi dữ liệu mới được thêm vào.Dù nguyên nhân thay đổi là gì đi nữa, các tổ chức đều cần một "công cụ" hiệu quả và lặp lại được để đánh giá xem hệ thống AI đàm thoại của họ phản hồi ra sao trong các tình huống phổ biến. Đây chính là lúc "siêu anh hùng" Microsoft.Extensions.AI.Evaluation xuất hiện! Đây là một thư viện mã nguồn mở giúp bạn "thu thập" và "so sánh" các chỉ số khác nhau liên quan đến hiệu suất của hệ thống AI của mình.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AICheckup.png' alt='Kiểm tra sức khỏe AI'>Trong bài viết này, chúng ta sẽ "mổ xẻ" cái khung kiểm thử LLM này, khám phá từng chỉ số đánh giá như Độ Tương Đồng (Equivalence), Độ Căn Cứ (Groundedness), Độ Trôi Chảy (Fluency), Mức Độ Liên Quan (Relevance), Độ Mạch Lạc (Coherence), Khả Năng Truy Xuất (Retrieval) và Độ Đầy Đủ (Completeness). Tất cả đều qua những đoạn code C# "thân thiện" trong một ứng dụng .NET nhỏ xinh.Đoạn code trong bài này sẽ sử dụng OpenAI để "tạo ra" các cuộc trò chuyện và sau đó dùng Microsoft.Extensions.AI.Evaluation để "chấm điểm" kết quả. À, bật mí nhỏ: Microsoft.Extensions.AI và Microsoft.Extensions.AI.Evaluation không chỉ "chơi" được với OpenAI đâu nhé! Chúng còn có thể làm việc với các nhà cung cấp mô hình khác, kể cả các mô hình chạy cục bộ (như Ollama) hay các dịch vụ có API tương thích OpenAI (như LM Studio).<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIEvaluationFlow.png' alt='Luồng đánh giá AI'>Các chỉ số đánh giá này được tạo ra bằng cách gửi một phiên trò chuyện đến OpenAI để "chấm điểm", đồng thời cung cấp một danh sách các "giám khảo" (evaluators) để chạy trên chỉ số đó. Vì vậy, chúng ta sẽ cần kết nối với OpenAI không chỉ để AI trả lời mà còn để lấy luôn các chỉ số đánh giá cho cuộc trò chuyện đó nữa.1. Kết nối với "não bộ" OpenAI:Để kết nối, bạn chỉ cần cung cấp một API key và tùy chọn là một endpoint (nếu bạn dùng OpenAI triển khai tùy chỉnh). Chúng ta sẽ dùng OpenAIClient và IChatClient từ gói NuGet Microsoft.Extensions.AI. Đoạn code này giống như việc bạn "thiết lập đường dây nóng" để máy tính của bạn có thể "tám chuyện" với OpenAI vậy đó!2. Xây dựng "kịch bản trò chuyện" (Chat History):Cả việc đánh giá và tạo phản hồi trò chuyện đều cần có một lịch sử cuộc trò chuyện. Hãy cùng "diễn tập" một tình huống nhỏ bằng cách tạo đối tượng ChatHistory và điền vào một cuộc tương tác ngắn gọn.Lịch sử cuộc trò chuyện của chúng ta gồm một "lệnh điều hướng" (system prompt), một lời chào từ trợ lý AI, và một tin nhắn giả định từ người dùng. Bình thường thì người dùng sẽ tự gõ tin nhắn, nhưng ở đây, để tập trung vào việc đánh giá một tương tác đơn giản, chúng ta "gõ cứng" nó vào code luôn.Cái "lệnh điều hướng" (system prompt) này thường là thứ bạn sẽ muốn "mày mò" và chỉnh sửa nhiều nhất để AI hoạt động tốt hơn, nên tôi sẽ chia sẻ cái prompt đơn giản trong ví dụ này: `You are a chatbot designed to help the user with simple questions. Keep your answers to a single sentence.` Dịch nôm na là: "Bạn là một chatbot được thiết kế để giúp người dùng trả lời các câu hỏi đơn giản. Hãy giữ câu trả lời của bạn trong một câu duy nhất." Mặc dù các chỉ số đánh giá mà chúng ta sẽ thu thập liên quan đến toàn bộ hệ thống AI, nhưng trên thực tế, một trong những mục đích chính bạn dùng các chỉ số này là để "tinh chỉnh" cái system prompt, giúp AI "ăn khớp" hơn với các tình huống cụ thể.À, lưu ý thêm là tôi đang "giả lập" Retrieval Augmentation Generation (RAG) ở đây bằng cách chèn một biến ragContext chứa một chuỗi đơn giản về ngày hiện tại. RAG không phải trọng tâm chính của bài này, nhưng nó sẽ "có mặt" trong chỉ số Retrieval (Khả Năng Truy Xuất) sau này. Nếu tò mò về RAG, bạn có thể xem bài viết của tôi về RAG với Kernel Memory.3. "Thụ lý hồ sơ" và "phản hồi" từ AI (Getting Chat Completions):Việc lấy phản hồi từ AI khá đơn giản một khi chúng ta có lịch sử trò chuyện. Chỉ cần một cuộc gọi "siêu tốc" đến IChatClient:Đoạn code này sẽ "chạy" đến OpenAI với lịch sử trò chuyện giả lập và lấy phản hồi cho tin nhắn, sau đó hiển thị cho người dùng. (Lưu ý: Tôi đang dùng Spectre.Console để làm ứng dụng mẫu dễ đọc hơn, nhưng bạn hoàn toàn có thể dùng Console.WriteLine bình thường.)Tình huống mẫu của chúng ta là một cuộc trò chuyện ngắn gọn nơi người dùng hỏi AI về ngày tháng: AI: How can I help you today? User: Is today after May 1st? If so, tell me what the next month will be. AI: Yes, today is after May 1st, and the next month will be June.Vì ngày trong tương tác này là 27 tháng 5, phản hồi của AI là "chuẩn không cần chỉnh" về mặt thực tế. Tuy nhiên, kết quả đánh giá sẽ "phán" rằng nó chưa thật sự "đầy đủ" vì AI không nói rõ ngày hiện tại trong phản hồi của mình.Với IChatClient đã sẵn sàng và phản hồi AI đã có, giờ là lúc "chấm điểm" thôi!4. "Chấm điểm" phản hồi AI (Evaluating Chat Completions):Microsoft.Extensions.AI.Evaluation cho phép bạn chỉ định một hoặc nhiều đối tượng "giám khảo" (evaluator) để "chấm điểm" hiệu suất của hệ thống AI cho một tương tác mẫu.Đây là một ví dụ đơn giản với CoherenceEvaluator, dùng để đảm bảo phản hồi của AI mạch lạc và dễ đọc:Đoạn code này sẽ tạo ra một đối tượng EvaluationResult chứa duy nhất một chỉ số về "độ mạch lạc" của hệ thống AI của bạn.Chỉ số này sẽ là một NumericMetric với giá trị số từ 1 đến 5 (1 là "khá tệ" và 5 là "gần như hoàn hảo"). Mỗi chỉ số cũng sẽ bao gồm một thuộc tính Reason (Lý do), giải thích tại sao LLM lại đưa ra xếp hạng đó. Điều này giúp bạn hiểu được điều gì còn thiếu sót ở những phản hồi dưới điểm 5 và cũng rất hữu ích cho việc báo cáo.5. "Đa điểm" – Chấm nhiều chỉ số cùng lúc (Evaluating Multiple Metrics):Hầu hết thời gian, bạn sẽ muốn xem xét không chỉ một mà rất nhiều chỉ số khác nhau. Ví dụ sau đây minh họa điều này bằng cách sử dụng CompositeEvaluator – một "hội đồng giám khảo" bao gồm nhiều giám khảo nhỏ hơn:Bạn có thể nhận thấy rằng chúng ta đang định nghĩa một tập hợp context (ngữ cảnh/tài liệu tham khảo) của các đối tượng EvaluationContext và cung cấp nó cho lời gọi EvaluateAsync.Các đối tượng ngữ cảnh này rất cần thiết cho một số "giám khảo" tiên tiến hơn. Mặc dù một số giám khảo có thể tự hoạt động, nhưng một vài trong số chúng cần bạn cung cấp thêm chi tiết về thông tin nào lẽ ra phải được truy xuất, một phản hồi lý tưởng trông như thế nào, và thông tin nào tuyệt đối phải có trong phản hồi.Nếu bạn quên cung cấp các đối tượng ngữ cảnh này, sẽ không có lỗi xảy ra, nhưng các giá trị chỉ số cho các giám khảo liên quan sẽ bị thiếu.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIContext.png' alt='Ngữ cảnh cho đánh giá AI'>6. "Báo cáo" kết quả đánh giá (Displaying evaluation results):Các chỉ số đánh giá rất hữu ích, nhưng nếu cứ nhìn thủ công thì "nhức mắt" lắm. May mắn thay, chúng không quá khó để hiển thị thành một bảng bằng Spectre.Console.Đoạn code C# sau sẽ lặp qua từng chỉ số trong EvaluationResult, thêm nó vào một Table và hiển thị ra console:Kết quả sẽ trông như một "bảng điểm" đẹp mắt như hình ảnh sau:<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2cbzelppwo5u68gzw6y.png' alt='Bảng kết quả đánh giá AI'>Có một bảng hiển thị chỉ số được định dạng đẹp mắt giúp bạn dễ dàng "chụp" và chia sẻ hiệu suất của hệ thống AI, cũng như giao tiếp với người khác.Microsoft.Extensions.AI.Evaluation còn có các khả năng báo cáo HTML và JSON tuyệt vời, cùng với khả năng kiểm tra nhiều lần lặp và tình huống trong cùng một lần chạy đánh giá. Phạm vi của những tính năng này nằm ngoài bài viết này, nhưng tôi dự định sẽ đề cập đến chúng trong một bài viết tương lai.Giờ thì chúng ta đã biết cách lấy các chỉ số đánh giá, hãy cùng "giải mã" ý nghĩa của từng chỉ số đó nhé!Các chỉ số "chất lượng" của hệ thống AI:Hãy cùng khám phá các chỉ số AI hiện đang được Microsoft.Extensions.AI.Evaluation hỗ trợ nhé.1. Độ Tương Đồng (Equivalence): AI nói có giống ý mình muốn không?Độ Tương Đồng kiểm tra xem phản hồi của hệ thống có "khớp" xấp xỉ với phản hồi mẫu mà chúng ta đã "mã hóa" trong CompletenessEvaluatorContext hay không. Nói một cách đơn giản, nó đo lường xem phản hồi của AI có "gần" với những gì chúng ta mong đợi hay không. Giống như bạn ra đề bài và AI trả lời có đúng trọng tâm không vậy đó!<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIEquivalence.png' alt='Chỉ số tương đồng của AI'>2. Độ Căn Cứ (Groundedness): AI có nói "láo" không? Có dựa vào sự thật không?Độ Căn Cứ đảm bảo rằng AI đang sử dụng các "sự thật" liên quan để trả lời người dùng. Điều này giúp chắc chắn rằng LLM không đưa ra một câu trả lời "sai bét nhè" so với những gì chúng ta mong đợi. Chỉ số này rất hữu ích cho các tổ chức có danh sách các điểm cụ thể cần đề cập hoặc các thuật ngữ/định nghĩa riêng biệt có thể khác một chút so với thông tin công khai.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIGroundedness.png' alt='Chỉ số căn cứ của AI'>3. Độ Trôi Chảy (Fluency): AI nói có "thuận tai" không? Ngữ pháp đúng không?Độ Trôi Chảy kiểm tra tính đúng ngữ pháp và việc tuân thủ các quy tắc cấu trúc và cú pháp. Tóm lại, nó đánh giá xem hệ thống có đang tạo ra thứ gì đó "chuẩn tiếng Việt" (hoặc ngôn ngữ khác) hay chỉ là "một mớ bòng bong" khó hiểu. (Lưu ý: Tôi đoán Fluency cũng sẽ hoạt động với các ngôn ngữ khác mà LLM của bạn hỗ trợ, nhưng tôi chưa kiểm chứng điều này).<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIFluency.png' alt='Chỉ số trôi chảy của AI'>4. Độ Mạch Lạc (Coherence): AI nói có "dễ hiểu" không? Có trôi chảy không?Độ Mạch Lạc là một kiểm tra "độ dễ đọc" để đảm bảo câu trả lời của AI dễ đọc và có "dòng chảy" tốt. Nếu Độ Trôi Chảy có thể được coi là một "kiểm tra ngữ pháp", thì Độ Mạch Lạc giống như một "biên tập viên" giúp tối ưu hóa đầu ra của bạn để dễ đọc hơn.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AICoherence.png' alt='Chỉ số mạch lạc của AI'>5. Mức Độ Liên Quan (Relevance): AI trả lời có đúng trọng tâm không?Chỉ số này đã được dùng trong RelevanceTruthAndCompletenessEvaluator (RTC). Nó kiểm tra xem phản hồi của AI có liên quan đến câu hỏi của người dùng và các thông tin đã cung cấp hay không. Về cơ bản, nó đảm bảo AI không "lạc đề".<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIRelevance.png' alt='Chỉ số liên quan của AI'>6. Khả Năng Truy Xuất (Retrieval): RAG có tìm đúng thông tin không?Khả Năng Truy Xuất "chấm điểm" hiệu quả của các hệ thống RAG trong việc cung cấp "ngữ cảnh" (context) liên quan cho hệ thống AI để phản hồi truy vấn. Chỉ số này được thiết lập thông qua đối tượng RetrievalEvaluatorContext.Điểm truy xuất thấp có thể chỉ ra rằng bạn đang có "khoảng trống" trong nội dung của mình, nơi hệ thống không thể tìm thấy thông tin liên quan. Hoặc, bạn có thể có nội dung liên quan, nhưng nó không được tổ chức theo cách mà mô hình nhúng và chỉ mục của bạn có thể truy xuất hiệu quả.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AIRetrieval.png' alt='Chỉ số truy xuất của AI'>7. Độ Đầy Đủ (Completeness): AI nói có "đủ ý" không?Độ Đầy Đủ kiểm tra để đảm bảo rằng phản hồi của AI cho người dùng bao gồm tất cả các điểm chính mà phản hồi mẫu bạn đã cung cấp cho CompletenessEvaluatorContext chứa.Trong ví dụ của chúng ta, phản hồi của hệ thống là đúng nhưng "chưa đủ" vì nó không bao gồm ngày hiện tại trong đầu ra của mình.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AICompleteness.png' alt='Chỉ số đầy đủ của AI'>8. "Đánh giá toàn diện" – RTC Evaluators (Relevance, Truth, Completeness):Microsoft cũng cung cấp một "giám khảo" mới hơn và vẫn đang trong giai đoạn thử nghiệm – RelevanceTruthAndCompletenessEvaluator (RTC). Nó "gom" các hiệu ứng của RelevanceEvaluator, GroundednessEvaluator và CompletenessEvaluator vào một "giám khảo" duy nhất mà không cần bất kỳ ngữ cảnh nào."Giám khảo" RTC này vẫn đang trong giai đoạn xem trước và có thể thay đổi đáng kể hoặc bị loại bỏ, nhưng nó có một số ưu điểm cốt lõi so với việc sử dụng ba giám khảo riêng lẻ: Nhanh hơn: Chỉ cần một yêu cầu đánh giá duy nhất thay vì ba yêu cầu riêng biệt. Tiết kiệm: Tiêu thụ ít token hơn, dẫn đến chi phí đánh giá hệ thống của bạn rẻ hơn khi sử dụng các LLM tính phí theo token. Dễ dùng: Không yêu cầu bạn cung cấp thêm ngữ cảnh cho "giám khảo".Khi "giám khảo" RTC này thoát khỏi giai đoạn xem trước, nó có thể là một lựa chọn tốt cho các nhóm chỉ muốn làm việc với một "giám khảo" duy nhất vì lý do chi phí hoặc hiệu suất.<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AITRC.png' alt='Chỉ số RTC của AI'>Những bước "thần tốc" tiếp theo:Trong bài viết này, chúng ta đã "mục sở thị" cách bạn có thể thu thập vô vàn chỉ số liên quan đến hiệu suất của các hệ thống AI chỉ với vài dòng code C# "thần thánh".Tôi rất khuyến khích bạn "nhảy" vào khám phá mã nguồn của bài viết này trên GitHub và "vọc vạch" nó với API Key và endpoint của riêng bạn. Microsoft cũng có rất nhiều mẫu ví dụ liên quan đến thư viện của họ, rất đáng để bạn tìm hiểu thêm.Khả năng này "mở khóa" rất nhiều con đường thú vị cho các tổ chức, bao gồm: Tạo các bài kiểm tra tích hợp (integration tests) sẽ "báo động" nếu các chỉ số thấp hơn một ngưỡng nhất định cho các tương tác quan trọng. "Thử nghiệm" với các system prompt khác nhau theo cách tương tự như A/B testing, nhưng sử dụng "giám khảo" LLM để "phân xử" ai thắng. Tích hợp các bài kiểm tra này vào quy trình MLOps hoặc CI/CD để đảm bảo bạn không bao giờ "lỡ tay" triển khai các hệ thống AI bị suy giảm hiệu suất đột ngột.Là một người "rất sợ tốn kém", việc có một framework tự động để đánh giá hiệu suất của các hệ thống dựa trên LLM và có thể cung cấp các mô hình của riêng mình (bao gồm cả Ollama) là một khả năng "thiết yếu" và mở ra nhiều quy trình làm việc mà tôi thường không thể tiếp cận.Mặc dù bài viết này đã bao quát các khả năng đánh giá của Microsoft.Extensions.AI.Evaluation, nhưng nó chỉ mới "chạm nhẹ" vào bề mặt các tính năng của thư viện này thôi. Hãy "đón xem" phần hai của bài viết này, nơi chúng ta sẽ "đào sâu" vào các tùy chọn báo cáo và khả năng A/B testing nâng cao hơn nhé!<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/AInextsteps.png' alt='Các bước tiếp theo cho AI'>
Bạn là dân .NET chính hiệu? Vậy chắc hẳn đã từng "xoắn não" khi nghĩ đến chuyện "dụ dỗ" mấy em AI xịn sò như Gemini của Google vào ứng dụng của mình rồi, đúng không? Bình thường, để làm được việc này, bạn phải "đổ mồ hôi sôi nước mắt" với cả tá công đoạn: nào là setup HTTP client, nào là cân đo đong đếm payload API, rồi còn phải "đấu tranh" với giới hạn tốc độ truy cập (rate limit), và cuối cùng là "mổ xẻ" cái mớ phản hồi trả về. Nghe thôi đã thấy "khó nuốt" rồi phải không?Nhưng mà khoan đã, nếu bạn mới chập chững bước vào thế giới LLM, hoặc đơn giản là muốn một giải pháp "nhanh-gọn-lẹ-siêu-tốc", thì đây rồi, "người hùng" <a href="https://deepmain.io">MaIN.NET</a> chính là "cứu cánh" của bạn! Thư viện này sẽ giúp bạn "kết nối" với Gemini chỉ bằng VÀI DÒNG CODE. Bạn không tin ư? Cứ đọc tiếp đi, bài viết này sẽ "bật mí" cho bạn cách cấu hình ứng dụng để "bắt tay" với Gemini và thậm chí còn có một dự án ví dụ "siêu to khổng lồ" (nhưng dễ hiểu) để bạn tự mình kiểm chứng sức mạnh của nó đó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/main_net_hero.png' alt='MaIN.NET giúp tích hợp LLM dễ dàng'>Bạn cần chuẩn bị gì để "chiến" cùng MaIN.NET và Gemini?<li> **<a href="https://dotnet.microsoft.com/en-us/download">.NET SDK</a>:** Chắc chắn rồi, không có cái này thì sao "code" được đúng không?</li><li> **Khóa API Gemini:** Bạn có thể lấy từ <a href="https://aistudio.google.com/">Google AI Studio</a> hoặc Vertex AI. Đây là "chìa khóa" để ứng dụng của bạn "tám chuyện" được với Gemini đó.</li><li> **IDE hoặc trình soạn thảo văn bản:** Như Visual Studio Code, Rider, hoặc Cursor – tùy vào "gu" của bạn nhé!</li><li> **Kết nối Internet:** Cái này thì khỏi nói rồi, API mà không có mạng thì khác gì người không có "não" đâu!</li><img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/checklist_setup.png' alt='Những thứ cần chuẩn bị trước khi bắt đầu'>💡 **Bật mí cực xịn:** Tin nóng hổi đây! Hiện tại, Google đang "chiêu đãi" chúng ta một chính sách MIỄN PHÍ cực kỳ "hào phóng" cho việc sử dụng Gemini API thông qua cả AI Studio và Vertex AI. Đây chính là "thời điểm vàng" để bạn tha hồ vọc vạch, thử nghiệm các tính năng "đỉnh của chóp" của LLM mà không phải "xắn tay áo" móc ví ra đâu nhé! À, nhớ "ngó nghiêng" giới hạn quota của bạn trong Google Cloud Console hoặc tài khoản AI Studio để tránh "đụng trần" nha.Vậy MaIN.NET là “thứ” gì mà "hot" vậy?<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/main_net_architecture.png' alt='Kiến trúc MaIN.NET'>Hãy tưởng tượng MaIN.NET như một "phiên dịch viên" siêu đẳng, hay một "cánh cổng thần kỳ" vậy. Nó là một framework mã nguồn mở cực kỳ mạnh mẽ, được sinh ra để "chuẩn hóa" việc kết nối các ứng dụng .NET của bạn với đủ loại "bộ não" LLM khác nhau, dù chúng chạy "tại gia" trên máy tính của bạn hay "trên mây" ở tận đâu đó. MaIN.NET "nắm tay" rất nhiều "ngôi sao" trong giới AI như OpenAI, Gemini, Mistral, Llama, Deepseek, Qwen... và còn cả một "biệt đội" nữa đang chờ bạn khám phá.Cái "siêu hay ho" của MaIN.NET là nó "đóng gói" toàn bộ những cuộc gọi HTTP "rối rắm" cấp thấp lại, rồi "bày sẵn" cho bạn một giao diện API "đơn giản như đan rổ". Nghĩa là, bạn sẽ không còn phải "đánh vật" với từng dòng code HTTP khô khan nữa! Thay vào đó, bạn chỉ cần "chỉ mặt đặt tên" cho backend bạn muốn dùng, rồi "triệu hồi" các phương thức có sẵn của MaIN.NET, thế là xong! Nó sẽ "tự động lo liệu" mọi thứ từ A đến Z. Thật sự là DỄ NHƯ ĂN KẸO!Tích hợp Gemini vào .NET: Dễ không tưởng tượng nổi! Đến đây chắc bạn đang tò mò lắm đúng không? Vậy thì, "show hàng" luôn! Đây là toàn bộ đoạn code "thần thánh" bạn cần để "hô biến" Gemini xuất hiện trong ứng dụng .NET của mình với sự giúp sức của MaIN.NET:<pre><code>using MaIN.Core;using MaIN.Core.Hub;using MaIN.Domain.Configuration;MaINBootstrapper.Initialize(configureSettings: (options) =>{ options.BackendType = BackendType.Gemini; options.GeminiKey = "YOUR_GEMINI_API_KEY";});string prompt = "What is LLM?";var response = await AIHub.Chat() .WithModel("gemini-2.0-flash") .WithMessage(prompt) .CompleteAsync(interactive: true);string result = response.Message.Content;Console.WriteLine(result);</code></pre>Đừng quên thay `"YOUR_GEMINI_API_KEY"` bằng khóa API thật của bạn nhé! Chỉ vài dòng thế này là bạn đã có thể "chat" với Gemini rồi đó.Ứng dụng console "nhỏ nhưng có võ" để "hỏi chuyện" Gemini <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/console_app.png' alt='Ví dụ ứng dụng console giao tiếp với Gemini'>Okela! Giờ thì, hãy cùng nhau "xắn tay áo" tạo một ứng dụng console "mini" thôi, nhưng "có võ" đấy nhé! Ứng dụng này sẽ cho phép bạn "tâm sự" với Gemini, nhập câu hỏi và nhận về những câu trả lời "siêu chất lượng". Sẵn sàng chưa? "Chiến" thôi!**Từng bước một, "cầm tay chỉ việc" đây!**<ol><li> **Tạo dự án mới:**<pre><code>dotnet new console -n GeminiExamplecd GeminiExample</code></pre>Bạn đang "khai sinh" một dự án console mới tinh tươm tên là `GeminiExample` và ngay lập tức "chuyển nhà" vào thư mục của nó.</li><li> **Thêm gói MaIN.NET:**<pre><code>dotnet add package MaIN.NET</code></pre>Lệnh này sẽ "rước dâu" thư viện MaIN.NET về "nhà" dự án của bạn, sẵn sàng để bạn "khai thác" mọi tính năng tuyệt vời của nó.</li><li> **Thêm code của bạn:**Mở file `Program.cs` và dán đoạn code sau vào:<pre><code>using System;using System.Threading.Tasks;using MaIN.Core;using MaIN.Core.Hub;using MaIN.Domain.Configuration;// Khởi tạo MaIN.NET với GeminiMaINBootstrapper.Initialize(configureSettings: (options) =>{ options.BackendType = BackendType.Gemini; options.GeminiKey = "YOUR_GEMINI_API_KEY";});Console.Write("Ask Gemini something: ");var input = Console.ReadLine();var response = await AIHub.Chat() .WithModel("gemini-2.0-flash") .WithMessage(input) .CompleteAsync(interactive: true);Console.WriteLine("\nResponse:");Console.WriteLine(response.Message.Content);</code></pre>Đoạn code "thần kỳ" này sẽ "đánh thức" MaIN.NET, sau đó "nháy mắt" bảo người dùng nhập câu hỏi, rồi nó sẽ "âm thầm" gửi câu hỏi đó đến Gemini thông qua "cầu nối" MaIN.NET và cuối cùng là "trình làng" câu trả lời "độc quyền" nhận được. À, đừng quên "bí kíp" là thay khóa API "xịn" của bạn vào nhé!</li><li> **Chạy ứng dụng:**<pre><code>dotnet run</code></pre>Giờ thì, hãy cùng "thổi lửa" cho ứng dụng của bạn và "mắt tròn mắt dẹt" xem Gemini sẽ "trả lời" bạn như thế nào nhé!Bạn có thể thử hỏi những câu như:<li> `Explain how JWT tokens work` (Giải thích JWT token hoạt động thế nào)</li><li> `Generate 3 creative names for a coffee startup` (Tạo 3 cái tên sáng tạo cho một quán cà phê)</li><li> `What’s the difference between async and parallel in C#?` (Sự khác nhau giữa async và parallel trong C# là gì?)</li></ol>Đằng sau cánh gà: `CompleteAsync()` đang "làm mưa làm gió" gì thế?<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/behind_the_scenes.png' alt='Phía sau hậu trường của MaIN.NET'>Khi bạn "phẩy tay" gọi `CompleteAsync()`, đừng nghĩ MaIN.NET chỉ ngồi chơi xơi nước nha! Đây là những "bí mật" đang diễn ra "phía sau hậu trường" đó:<li> Thư viện MaIN.NET "soạn sửa" yêu cầu API với backend bạn đã chọn (ở đây là Gemini). Giống như việc bạn đang "soạn thảo" một bức thư điện tử cực kỳ chỉnh chu vậy.</li><li> Nó "đóng gói" câu hỏi (prompt) và lựa chọn mô hình của bạn vào đúng "khuôn khổ" mà Gemini mong đợi (chuyển đổi thành JSON hay các định dạng khác).</li><li> Sau đó, nó "tự động" gửi yêu cầu HTTP đi và "xuýt xoa" xử lý phần phản hồi nhận về. Bạn hoàn toàn không cần bận tâm về việc "đóng gói" hay "giải nén" dữ liệu thô nữa.</li><li> Cuối cùng, bạn nhận được kết quả dưới dạng một đối tượng được "đóng gói" gọn gàng, giúp bạn dễ dàng truy cập trực tiếp vào nội dung phản hồi. Nghe đã thấy tiện lợi "tụt quần" rồi đúng không nào?</li>Đi đâu tiếp theo? "Sân chơi" còn rộng lắm!<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/next_steps.png' alt='Khám phá thêm với MaIN.NET'>Nếu bạn đã "cảm nắng" MaIN.NET rồi và muốn "nâng tầm" kỹ năng của mình lên một level mới, vậy thì sao không thử "ra tay" xây dựng một website lung linh dựa trên Blazor và tích hợp "em" Gemini vào đó xem sao? Đây nè, có ngay <a href="https://dev.to/paweljanda/build-a-local-chatgpt-like-app-with-blazor-and-mainnet-part-1-getting-started-with-llm-16j">bài hướng dẫn cực chi tiết về việc sử dụng MaIN.NET với Blazor</a>, đảm bảo bạn sẽ "khởi động" trơn tru thôi!Tổng kết lại: "Phép thuật" MaIN.NET đã "thay đổi cuộc chơi" như thế nào? <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/magic_wand.png' alt='MaIN.NET như cây đũa thần'>Tóm lại, với MaIN.NET, việc "bắt tay" ứng dụng .NET của bạn với Gemini trở nên "nhanh như chớp" và "sạch bong kin kít" hơn bao giờ hết. Bạn không cần phải "vật lộn" với mớ bòng bong như thiết lập HTTP, giải mã JSON hay các luồng xác thực "đau tim" nữa. Nếu bạn đang "ấp ủ" những ý tưởng "điên rồ" với LLM, thì đừng chần chừ! Tầng miễn phí hiện tại của Google chính là "sân chơi" tuyệt vời để bạn tha hồ "quẩy" và kiểm chứng mọi ý tưởng mà không lo "cháy túi". Chúc bạn có những giờ phút "code" thật "phiêu" và "thăng hoa" nhé!
Chào bạn, đã bao giờ bạn nhìn vào một dự án cũ kỹ, rối như canh hẹ và tự hỏi: "Làm sao mình có thể cứu vãn nó đây?" Đừng lo lắng! "Clean Architecture" chính là siêu anh hùng mà chúng ta cần, không chỉ là một từ khóa hào nhoáng đâu nhé! Nó chính là sự khác biệt giữa một codebase có thể phát triển "phi mã" cùng doanh nghiệp và một đống hỗn độn khiến bạn muốn… đập bàn phím. Với .NET 10, chúng ta đã có nhiều công cụ xịn sò hơn, từ Record tiện lợi, Dependency Injection (DI) mạnh mẽ cho đến Minimal API siêu gọn gàng. Nhưng dù "đồ chơi" có hiện đại đến mấy, Clean Architecture vẫn phụ thuộc vào những quyết định "then chốt" của bạn, đặc biệt là ngay từ những bước thiết kế ban đầu. Trong bài viết này, chúng ta sẽ cùng "mổ xẻ" những mô hình thực chiến và cấu trúc thư mục "chuẩn chỉnh" trong thế giới thực, giúp Clean Architecture không chỉ nằm trên lý thuyết mà còn "sống khỏe" trong môi trường sản phẩm. <b>Clean Architecture Là Gì? (Nhắc Lại Nhanh)</b> Nếu bạn đã từng nghe danh "Uncle Bob" (Robert C. Martin) thì chắc hẳn cũng quen với khái niệm này. Clean Architecture đơn giản là việc "chia nhà, chia cửa" cho từng thành phần của ứng dụng. Mục tiêu là tách biệt các "mối bận tâm" và đảm bảo tính độc lập giữa các framework, giao diện người dùng (UI) và đặc biệt là các "luật kinh doanh" cốt lõi của bạn. Nói một cách dễ hình dung, nó giống như việc bạn xây một ngôi nhà mà mỗi tầng, mỗi phòng đều có chức năng riêng, không ai "lấn sân" ai. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/clean_arch_layers.png' alt='Mô hình các lớp của Clean Architecture'> <b>Những Khái Niệm Cốt Lõi:</b> <ul><li><b>Luật Phụ Thuộc (Dependency Rule):</b> Các lớp bên trong "không thèm biết" gì về các lớp bên ngoài. Hay nói cách khác, "người bên trong" không phụ thuộc vào "người bên ngoài".</li><li><b>Use Case (Trường Hợp Sử Dụng):</b> Đây chính là "bộ não" điều khiển logic nghiệp vụ của ứng dụng.</li><li><b>Entity (Thực Thể):</b> Đại diện cho các đối tượng và quy tắc nghiệp vụ cốt lõi của bạn.</li><li><b>Interface (Giao Diện):</b> Định nghĩa các "giao kèo" (contracts), sau đó sẽ được các lớp bên ngoài "thực thi" (implement).</li></ul> <b>Cấu Trúc Dự Án "Chuẩn Đét" Trong .NET 10</b> Khi bắt tay vào dự án .NET 10, đây là một cấu trúc thư mục "kinh điển" mà bạn nên tham khảo. Nó giúp mọi thứ gọn gàng, dễ quản lý: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/clean_arch_folders.png' alt='Cấu trúc thư mục dự án Clean Architecture trong .NET'> <code>/src</code> <code>├── MyApp.Api // Nơi "tiếp khách": Minimal API / MVC (giao diện người dùng web)</code> <code>├── MyApp.Application // "Bộ não vận hành": Chứa các Use Case (logic ứng dụng), các đối tượng DTOs (Data Transfer Objects) và triển khai CQRS.</code> <code>├── MyApp.Domain // "Trái tim và linh hồn": Chứa các quy tắc nghiệp vụ, Entity (thực thể), Enum (kiểu liệt kê) và các Interface (giao diện).</code> <code>├── MyApp.Infrastructure // "Hậu cần": Chứa các triển khai cụ thể như EF Core (ORM), các dịch vụ bên ngoài (gửi email, gọi API khác).</code> <code>└── MyApp.Tests // "Phòng thí nghiệm": Nơi chứa các bài kiểm tra (Unit Test & Integration Test).</code> <b>Mẹo nhỏ bỏ túi:</b> Hãy tuân thủ nguyên tắc "một trách nhiệm cho mỗi dự án". Bạn sẽ thấy mình "cảm ơn" sau này, đặc biệt là khi phải bảo trì code đấy! <b>Những Mô Hình "Sống Tốt" Trong Môi Trường Sản Phẩm</b> <h3>1. CQRS (Command Query Responsibility Segregation)</h3> Nghe có vẻ "hack não" nhưng thực ra CQRS đơn giản là việc bạn "chia đôi đường đi" cho các thao tác đọc và ghi dữ liệu. Tưởng tượng thế này: khi bạn muốn "đặt hàng" (ghi dữ liệu), bạn sẽ dùng một "đầu bếp" riêng, và khi bạn muốn "xem lại menu" (đọc dữ liệu), bạn lại dùng một "đầu bếp" khác. Việc này giúp logic của bạn rõ ràng hơn rất nhiều, tránh được sự phức tạp khi xử lý cả hai việc trên cùng một luồng. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/cqrs_concept.png' alt='Mô hình CQRS chia tác vụ đọc và ghi'> Hãy xem ví dụ đơn giản này nhé: <code>// Command - "Lệnh" để tạo đơn hàng</code> <code>public record CreateOrderCommand(string CustomerId) : IRequest<Guid>;</code> <code>// Handler - "Người xử lý" lệnh này</code> <code>public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Guid></code> <code>{</code> <code> public async Task<Guid> Handle(CreateOrderCommand cmd, CancellationToken ct)</code> <code> {</code> <code> var order = new Order(cmd.CustomerId);</code> <code> _db.Orders.Add(order);</code> <code> await _db.SaveChangesAsync(ct);</code> <code> return order.Id;</code> <code> }</code> <code>}</code> Bạn có thể dùng thư viện MediatR hoặc kỹ thuật Pure DI để xử lý các Command/Query này một cách siêu sạch sẽ. <h3>2. Interfaces + Inversion of Control (IoC)</h3> Đây là cặp đôi "hoàn cảnh" giúp code của bạn linh hoạt hơn bao giờ hết! Ý tưởng là bạn sẽ định nghĩa các "giao kèo" (Interfaces) ở lớp Domain hoặc Application, sau đó "người thực thi" (Implementation) sẽ nằm ở lớp Infrastructure. Ví dụ: Bạn cần gửi email. Thay vì gọi thẳng dịch vụ gửi email cụ thể, bạn chỉ cần "giao kèo" là: "Ai đó gửi cho tôi cái email này là được!" Rồi sau đó, "ông" SendGrid hay "bà" Mailgun sẽ là người thực thi "giao kèo" đó. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/interface_ioc.png' alt='Interfaces và Inversion of Control'> <code>// Trong Domain hoặc Application: định nghĩa "giao kèo"</code> <code>public interface IEmailSender</code> <code>{</code> <code> Task SendAsync(string to, string subject, string body);</code> <code>}</code> <code>// Trong Infrastructure: "người thực thi" giao kèo này (ví dụ dùng SendGrid)</code> <code>public class SendGridEmailSender : IEmailSender</code> <code>{</code> <code> public Task SendAsync(string to, string subject, string body) => ...; // Chi tiết triển khai gửi email qua SendGrid</code> <code>}</code> <h3>3. Đóng Gói Thực Thể (Entity Encapsulation)</h3> Hãy "cạch mặt" những mô hình "thiếu sức sống" (anemic models) – tức là những đối tượng chỉ chứa dữ liệu mà không có bất kỳ logic nghiệp vụ nào bên trong. Thay vào đó, hãy giữ logic nghiệp vụ ngay trong chính thực thể của bạn. Tưởng tượng thế này: Thay vì một cái ví chỉ biết chứa tiền mà không biết cách tự đếm hay tự động chi tiêu, thì hãy biến nó thành một cái ví "thông minh" biết tự quản lý tiền của mình. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/entity_encapsulation.png' alt='Thực thể (Entity) chứa logic nghiệp vụ'> <code>public class Order</code> <code>{</code> <code> private readonly List<OrderItem> _items = new();</code> <code> public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();</code> <code> public void AddItem(Product product, int qty)</code> <code> {</code> <code> if (qty <= 0) throw new ArgumentException("Số lượng phải dương!");</code> <code> _items.Add(new OrderItem(product, qty));</code> <code> }</code> <code>}</code> <h3>4. Minimal API + Controller "Siêu Mỏng"</h3> Với .NET 10, bạn có thể tận dụng Minimal API để tạo các endpoint "sạch bong kính coong", đặc biệt là cho các dịch vụ nhỏ (microservices). Mọi thứ sẽ trở nên cô đọng và dễ đọc hơn rất nhiều! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/minimal_api_net.png' alt='Minimal API trong .NET 10'> <code>app.MapPost("/orders", async (CreateOrderCommand cmd, ISender mediator) =></code> <code>{</code> <code> var id = await mediator.Send(cmd);</code> <code> return Results.Created($"/orders/{id}", new { id });</code> <code>});</code> Hoặc nếu bạn vẫn thích dùng Controller truyền thống, hãy giữ chúng "siêu gầy" và đẩy mọi logic phức tạp vào các Handler (như trong CQRS) để code dễ quản lý hơn. <b>Chiến Lược Kiểm Thử (Testing)</b> Kiểm thử là "chìa khóa" để đảm bảo chất lượng code của bạn. Với Clean Architecture, việc kiểm thử cũng trở nên "dễ thở" hơn nhiều: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/testing_strategy.png' alt='Chiến lược kiểm thử trong Clean Architecture'> <ul><li><b>Lớp Domain:</b> Unit test "tẹt ga" mà không cần phụ thuộc vào bất kỳ thứ gì bên ngoài.</li><li><b>Lớp Application:</b> Giả lập (mock) các dịch vụ bên ngoài (email, thanh toán, v.v.) để kiểm tra logic của các Use Case.</li><li><b>Lớp Infrastructure:</b> Thực hiện Integration Test (kiểm thử tích hợp) với các hệ thống thực sự (EF Core, các API bên ngoài).</li></ul> À, một "vũ khí" bí mật nữa là Testcontainers – giúp bạn tạo các môi trường database "thật" như Postgres/SQL Server ngay trên máy cục bộ để kiểm thử. <b>Những "Cái Bẫy" Cần Tránh</b> Đừng để những lỗi cơ bản này làm hỏng kiến trúc "xịn sò" của bạn nhé! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/pitfalls_avoid.png' alt='Những sai lầm cần tránh trong Clean Architecture'> <ul><li><b>Đừng bao giờ để UI "gọi thẳng" Infrastructure:</b> Lớp giao diện không nên biết chi tiết về cách lưu trữ dữ liệu hay giao tiếp với bên ngoài.</li><li><b>Đừng nhồi nhét logic vào Controller:</b> Controller nên "gầy gò", chỉ làm nhiệm vụ điều hướng request.</li><li><b>Tránh kết nối chặt chẽ (tight coupling) giữa Use Case và EF Core:</b> Hãy dùng các Interface và Repository Pattern để decoupling.</li><li><b>Đừng lạm dụng abstraction:</b> Chỉ tạo Interface khi thực sự cần thiết, đừng biến mọi thứ thành "mớ bòng bong" vì quá nhiều Interface không cần thiết.</li></ul> <b>Những Công Cụ "Đắc Lực" Giúp Bạn</b> Để hành trình "chinh phục" Clean Architecture của bạn thêm "mượt mà", đây là vài "người bạn" đồng hành đáng tin cậy: <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/dev_tools.png' alt='Các công cụ hỗ trợ lập trình'> <ul><li><b>MediatR:</b> Giúp tách biệt các Handler và Command/Query một cách tuyệt vời.</li><li><b>xUnit + FluentAssertions:</b> Bộ đôi hoàn hảo cho việc viết Unit Test "sạch, gọn, đẹp".</li><li><b>Mapster hoặc AutoMapper:</b> Tiết kiệm thời gian "map" dữ liệu giữa các model.</li><li><b>Serilog:</b> Giải pháp ghi log "có cấu trúc" chuyên nghiệp.</li><li><b>EF Core 8+:</b> Framework ORM "xịn xò" cho lớp Infrastructure.</li></ul> <b>Tổng Kết "Thần Chưởng"</b> Clean Architecture trong .NET 10 không phải là để "làm màu" với những sơ đồ phức tạp. Mục tiêu cuối cùng là xây dựng những ứng dụng "dễ kiểm thử, linh hoạt và dễ hiểu". Nếu bạn nắm vững các nguyên tắc cốt lõi và áp dụng các công cụ hiện đại một cách "có tâm", ứng dụng của bạn sẽ "sống thọ" và phát triển vươn xa trong nhiều năm tới. Bạn có đang áp dụng Clean Architecture trong dự án hiện tại của mình không? Đâu là "nỗi đau" hoặc "chiến thắng" lớn nhất của bạn? Chia sẻ ngay dưới phần bình luận nhé!
Khám phá Server-Side Rendering (SSR) tĩnh trong Blazor .NET 9 giúp website tải nhanh "thần tốc" và tối ưu SEO hiệu quả. Tìm hiểu lợi ích và cách triển khai để nâng tầm ứng dụng Blazor của bạn.