[{"content":"Trong quá trình thiết kế hệ thống có quy mô lớn (Scale-up), việc lựa chọn Khóa chính (Primary Key) thường là một trong những quyết định kỹ thuật quan trọng nhất nhưng lại ít được thảo luận chuyên sâu. Một lựa chọn sai lầm ở bước này có thể dẫn đến rủi ro bảo mật (Insecure Direct Object Reference) hoặc suy giảm hiệu suất ghi nghiêm trọng khi dữ liệu đạt ngưỡng hàng triệu bản ghi.\nUUIDv7, chính thức được chuẩn hóa trong RFC 9562 vào tháng 5/2024, ra đời để giải quyết bài toán nan giải này.\n1. Phân tích giới hạn của các phương pháp định danh truyền thống Auto-increment Integer (BigInt) -- Ví dụ: Định danh tuần tự 1, 2, 3, 4, 5... Rủi ro: Đây là \u0026ldquo;mồi ngon\u0026rdquo; cho các cuộc tấn công thu thập dữ liệu (Scraping). Nếu một Endpoint để lộ ID như invoice/1001, kẻ tấn công có thể dễ dàng đoán được các bản ghi khác và ước tính được tốc độ tăng trưởng kinh doanh của bạn thông qua số lượng bản ghi tạo mới mỗi ngày. Giới hạn: Gặp khó khăn trong các hệ thống phân tán (Distributed Systems) khi nhiều Node cần tạo ID đồng thời mà không muốn xảy ra xung đột hoặc phụ thuộc vào một Centralized Counter. UUIDv4 (Random UUID) -- Ví dụ: Hoàn toàn không có quy luật f47ac10b-58cc-4372-a567-0e02b2c3d479 Vấn đề hiệu suất: Do tính ngẫu nhiên tuyệt đối, UUIDv4 gây ra hiện tượng Index Fragmentation nghiêm trọng. Khi chèn dữ liệu, Database phải thực hiện \u0026ldquo;Page Split\u0026rdquo; liên tục để nhét ID mới vào giữa các Node của B-Tree, làm tăng đáng kể Disk I/O. 2. UUIDv7: Kiến trúc kết hợp Time-ordered UUIDv7 được thiết kế để kết hợp ưu điểm của cả hai thế giới: [48-bit Timestamp] + [12-bit Random/Version] + [62-bit Random].\n-- Ví dụ UUIDv7: Tuần tự theo thời gian nhưng vẫn đảm bảo tính ngẫu nhiên 018f3a5b-7a12-7b3e-8a5c-1234567890ab -- T0 018f3a5b-7a13-7b3e-8a5c-fedcba987654 -- T0 + 1ms Hình 1: Cấu trúc 128-bit của UUIDv7 giúp tối ưu hóa việc sắp xếp.\nVới 48-bit đầu tiên là Unix timestamp (độ chính xác đến mili giây), các UUIDv7 được tạo ra sẽ luôn có thứ tự tăng dần. Điều này mang lại sự thay đổi mang tính bước ngoặt cho tầng lưu trữ.\n3. Hiệu suất Database qua lăng kính B-Tree Index Hầu hết các RDBMS hiện đại sử dụng cấu trúc B-Tree để quản lý Index. Hãy phân tích cơ chế này để thấy sự vượt trội của UUIDv7:\nCơ chế B-Tree: Database sắp xếp Index theo thứ tự từ thấp đến cao trên đĩa cứng. Sự sụp đổ của UUIDv4: Khi bạn chèn hàng triệu UUIDv4, chúng rơi vào các vị trí ngẫu nhiên trong cây. Hệ thống phải liên tục nạp các \u0026ldquo;Page\u0026rdquo; dữ liệu từ đĩa lên RAM, thay đổi và ghi lại. Khi một Page đầy, nó phải bị chia đôi (Split), dẫn đến việc lưu trữ bị phân mảnh (Fragmentation) và dung lượng file Index phình to bất thường. Sự tối ưu của UUIDv7: Vì luôn tăng dần, ID mới luôn được chèn vào phía bên phải cùng của B-Tree. Thao tác này cực kỳ \u0026ldquo;nhẹ\u0026rdquo; cho Database vì nó chỉ cần cập nhật các Page hiện tại ở cuối cây, giảm thiểu tối đa việc di chuyển dữ liệu trên đĩa. Kết quả thực tế: Việc chuyển sang UUIDv7 có thể giúp giảm kích thước Index tới 30-40% và tăng tốc độ ghi (Write throughput) đáng kể so với UUIDv4.\n4. Đánh đổi (Trade-offs) và Lộ trình áp dụng Không có giải pháp nào là hoàn hảo. Khi chọn UUIDv7, bạn cần cân nhắc:\nDung lượng lưu trữ: UUIDv7 chiếm 16 bytes, gấp đôi so với BigInt (8 bytes). Điều này làm tăng kích thước bảng và bộ nhớ đệm Index. Lộ thông tin thời gian: Vì chứa timestamp, kẻ tấn công có thể biết chính xác thời điểm bản ghi được tạo. Nếu thời điểm tạo là thông tin nhạy cảm, bạn cần cân nhắc kỹ. Hiện trạng adoption:\nPostgreSQL 18: Hỗ trợ hàm uuidv7() native. Frameworks: Laravel, Spring Boot, và các thư viện Go/Rust đã hỗ trợ rộng rãi. Đúc kết UUIDv7 không chỉ là một kiểu dữ liệu mới; nó là một lựa chọn chiến lược về kiến trúc. Nó cung cấp sự cân bằng tối ưu: An toàn trước các cuộc tấn công thu thập dữ liệu (như UUIDv4) nhưng lại hiệu quả về mặt cơ học (như Integer).\nBài học rút ra: Trong kỹ thuật phần mềm, hiệu năng thường không nằm ở code xử lý, mà nằm ở cách bạn tổ chức cấu trúc dữ liệu để \u0026ldquo;chiều lòng\u0026rdquo; phần cứng bên dưới.\nBạn có đang cân nhắc việc migrate ID hệ thống sang UUIDv7? Hãy chia sẻ những thách thức bạn đang gặp phải.\n","permalink":"https://thaig2pro.github.io/posts/uuidv7-performance-and-standardization/","summary":"\u003cp\u003eTrong quá trình thiết kế hệ thống có quy mô lớn (Scale-up), việc lựa chọn Khóa chính (Primary Key) thường là một trong những quyết định kỹ thuật quan trọng nhất nhưng lại ít được thảo luận chuyên sâu. Một lựa chọn sai lầm ở bước này có thể dẫn đến rủi ro bảo mật (Insecure Direct Object Reference) hoặc suy giảm hiệu suất ghi nghiêm trọng khi dữ liệu đạt ngưỡng hàng triệu bản ghi.\u003c/p\u003e","title":"UUIDv7: Phân tích Kiến trúc Định danh và Hiệu suất Index trong Hệ thống Hiện đại"},{"content":"Tháng trước, khi bắt tay vào xây dựng hệ thống AI Agent, tôi bắt đầu bằng một file script đơn giản dài khoảng 200 dòng. Mọi thứ hoạt động hoàn hảo cho đến khi tôi thêm công cụ (Tool) thứ 5 và bắt đầu xử lý các tác vụ bất đồng bộ. Code trở thành một mớ bòng bong (Spaghetti code) không thể debug.\nĐó là lúc tôi nhận ra: Xây dựng AI Agent không phải là bài toán viết Prompt hay gọi API mô hình ngôn ngữ. Nó là bài toán về Kỹ thuật Phần mềm (Software Engineering). Tệp tin loop.py mà tôi thiết kế lại sau đó chính là minh chứng cho việc áp dụng 4 nguyên lý OOP kinh điển để kiểm soát sự phức tạp của vòng lặp ReAct (Reasoning and Acting).\n1. Tính Đóng Gói (Encapsulation): Tránh \u0026ldquo;đầu độc\u0026rdquo; Context Trong kiến trúc của tôi, lớp AgentLoop hoạt động như một máy trạng thái (State machine) khép kín. Việc đóng gói không chỉ để code trông \u0026ldquo;sạch\u0026rdquo; hơn, mà để giải quyết một lỗi chí mạng: Context poisoning. Khi LLM trả về một phản hồi lỗi (ví dụ: HTTP 400), nếu không được cách ly, lỗi này sẽ bị ghi vào lịch sử hội thoại, khiến Agent kẹt vĩnh viễn trong một vòng lặp lỗi.\nThực thi: Tôi khóa chặt các logic nhạy cảm như _run_agent_loop hay _process_message thành phương thức private. Trạng thái self._running và self._processing_lock đảm bảo Agent không bao giờ xử lý chồng chéo tin nhắn. class AgentLoop: def __init__(self, ...): self._running = False self._processing_lock = asyncio.Lock() async def run(self) -\u0026gt; None: \u0026#34;\u0026#34;\u0026#34;EntryPoint duy nhất để hệ thống bên ngoài tương tác\u0026#34;\u0026#34;\u0026#34; async with self._processing_lock: self._running = True await self._run_agent_loop() 2. Tính Trừu Tượng (Abstraction): Chống \u0026ldquo;Vendor Lock-in\u0026rdquo; Khi OpenAI gặp sự cố diện rộng, tôi cần chuyển sang hệ thống Claude của Anthropic ngay lập tức. Nếu gọi trực tiếp API của OpenAI trong vòng lặp, toàn bộ hệ thống sẽ tê liệt.\nGiải pháp: AgentLoop chỉ giao tiếp với một Interface trừu tượng là LLMProvider. Thực thi: Tại thời điểm chạy, self.provider có thể là bất kỳ mô hình nào. AgentLoop không cần biết việc chuẩn bị Payload cho GPT-4 khác với Claude 3.5 ra sao. # Gọi LLM thông qua interface chung, miễn nhiễm với sự thay đổi của Vendor response = await self.provider.chat( messages=messages, tools=self.tools.get_definitions(), model=self.model, ) 3. Tính Hợp Thành (Composition): Giải quyết \u0026ldquo;Diamond Problem\u0026rdquo; Điều tôi đã thử và thất bại: Ban đầu, tôi dùng tính Kế thừa (Inheritance) để tạo ra CoderAgent kế thừa từ BaseAgent. Nhưng khi cần một Agent vừa biết code vừa biết tìm kiếm (Researcher), kiến trúc phả hệ vỡ vụn vì vấn đề đa kế thừa (Diamond problem).\nGiải pháp: Chuyển sang tính Hợp thành (Composition - \u0026ldquo;Has-a\u0026rdquo;). Tôi thiết kế AgentLoop như một nhạc trưởng, không tự làm gì cả mà chỉ điều phối các module chuyên biệt. Cấu trúc: self.context = ContextBuilder(): Xử lý build prompt. self.sessions = SessionManager(): Quản lý bộ nhớ. self.tools = ToolRegistry(): Quản lý kỹ năng. def __init__(self, ...): # AgentLoop không tự quản lý bộ nhớ hay tool, nó sở hữu các module thực hiện việc đó self.context = ContextBuilder(workspace) self.sessions = SessionManager(workspace) self.tools = ToolRegistry() 4. Tính Đa Hình (Polymorphism): Plug-and-Play Architecture Làm sao để Agent biết cách gọi một công cụ tìm kiếm web so với một công cụ đọc file local, khi mà bản chất hai hành động này hoàn toàn khác nhau? Câu trả lời là Đa hình.\nThực thi: Mọi công cụ (từ ReadFileTool đến WebSearchTool) đều tuân thủ chung một interface có hàm execute(). Lợi ích: Trong vòng lặp ReAct, đoạn code thực thi công cụ luôn cố định. Khi cần cắm thêm giao thức mới như MCP (Model Context Protocol), tôi không phải sửa dù chỉ một dòng code bên trong loop.py. # Một lời gọi duy nhất, nhưng hành vi thực thi biến hóa theo từng Tool cụ thể for tool_call in response.tool_calls: result = await self.tools.execute(tool_call.name, tool_call.arguments) messages = self.context.add_tool_result(messages, tool_call.id, tool_call.name, result) Sơ đồ kiến trúc tối giản Sơ đồ dưới đây minh họa sự phối hợp nhịp nhàng của 4 tính chất OOP để tạo nên một bộ điều phối hoàn chỉnh:\nHình 1: Kiến trúc điều phối của AgentLoop.\nĐúc kết Sự khác biệt giữa một bản \u0026ldquo;demo chạy cho vui\u0026rdquo; và một hệ thống AI dùng trong Production không nằm ở việc bạn viết Prompt khéo đến đâu. Nó nằm ở việc bạn tổ chức kiến trúc phần mềm như thế nào.\nBài học tôi rút ra sau khi đập đi xây lại loop.py: Mô hình ngôn ngữ (LLM) là bộ não, nhưng nếu không có một khung xương (Architecture) vững chắc, bộ não đó cũng không thể nâng đỡ được một cơ thể hoạt động bền bỉ.\n","permalink":"https://thaig2pro.github.io/posts/agentic-workflow-oop-architecture/","summary":"\u003cp\u003eTháng trước, khi bắt tay vào xây dựng hệ thống AI Agent, tôi bắt đầu bằng một file script đơn giản dài khoảng 200 dòng. Mọi thứ hoạt động hoàn hảo cho đến khi tôi thêm công cụ (Tool) thứ 5 và bắt đầu xử lý các tác vụ bất đồng bộ. Code trở thành một mớ bòng bong (Spaghetti code) không thể debug.\u003c/p\u003e\n\u003cp\u003eĐó là lúc tôi nhận ra: Xây dựng AI Agent không phải là bài toán viết Prompt hay gọi API mô hình ngôn ngữ. Nó là bài toán về \u003cstrong\u003eKỹ thuật Phần mềm (Software Engineering)\u003c/strong\u003e. Tệp tin \u003ccode\u003eloop.py\u003c/code\u003e mà tôi thiết kế lại sau đó chính là minh chứng cho việc áp dụng 4 nguyên lý OOP kinh điển để kiểm soát sự phức tạp của vòng lặp ReAct (Reasoning and Acting).\u003c/p\u003e","title":"Phân tích Kiến trúc Agentic Workflow qua lăng kính OOP: Case Study loop.py"},{"content":"i am Thai.\n","permalink":"https://thaig2pro.github.io/posts/bai-viet-dau-tien/","summary":"\u003cp\u003ei am Thai.\u003c/p\u003e","title":"Bai Viet Dau Tien"},{"content":"Chuyển đổi tư duy từ soạn thảo sang xuất bản kỹ thuật Trong kỷ nguyên của sự tối giản và hiệu suất, việc xây dựng blog cá nhân không còn dừng lại ở việc chọn một nền tảng có sẵn. Xu hướng hiện đại đang chuyển dịch mạnh mẽ sang các bộ tạo trang tĩnh (Static Site Generators - SSG). Hugo, khi kết hợp cùng giao diện PaperMod, không chỉ là một công cụ; đó là một hệ sinh thái được tối ưu hóa để chuyển đổi nội dung từ định dạng Markdown thô sơ sang một sản phẩm kỹ thuật số hoàn thiện với độ trễ gần như bằng không.\nPhân tích luồng vận hành hệ thống Quy trình từ ý tưởng đến khi bài viết xuất hiện trên Internet được vận hành qua một chuỗi các lớp xử lý dữ liệu chặt chẽ và nhất quán.\nHình 1: Luồng dữ liệu từ môi trường cục bộ đến người dùng cuối qua hạ tầng GitHub Pages.\n1. Lớp dữ liệu và Siêu dữ liệu (Front Matter) Mọi thực thể nội dung trong Hugo đều bắt đầu bằng Markdown. Tuy nhiên, khả năng điều phối của hệ thống nằm ở Front Matter. Đây là nơi chứa các siêu dữ liệu giúp Hugo định nghĩa logic hiển thị, phân loại (taxonomies) và các tham số SEO.\nCấu trúc tệp tin tiêu chuẩn:\n--- title: \u0026#34;Kiến trúc Blog hiện đại\u0026#34; date: 2026-03-06 tags: [\u0026#34;tech\u0026#34;, \u0026#34;blog\u0026#34;] categories: [\u0026#34;Architecture\u0026#34;] draft: false --- Nội dung bài viết bắt đầu tại đây. Sử dụng **Markdown** giúp tách biệt hoàn toàn giữa tầng dữ liệu và tầng hiển thị (Presentation layer). 2. Sức mạnh của bộ máy biên dịch Go-based Hugo được phát triển bằng ngôn ngữ Go, tận dụng khả năng xử lý song song để đạt tốc độ biên dịch huyền thoại. Thay vì truy vấn cơ sở dữ liệu (Database) tại thời điểm người dùng yêu cầu (Runtime), Hugo thực hiện việc \u0026ldquo;kết xuất\u0026rdquo; (Rendering) toàn bộ trang web ngay tại thời điểm xây dựng (Build-time).\nCơ chế Lookup Order và Rendering Hugo vận hành dựa trên hệ thống Lookup Order (Thứ tự tìm kiếm template) và Template Inheritance (Kế thừa bản mẫu). Quy trình diễn ra qua 3 giai đoạn:\nParsing: Quét thư mục content/ để phân tích Markdown và bóc tách Front Matter. Mapping: Ánh xạ loại nội dung vào bản thiết kế (Layout) phù hợp nhất trong PaperMod (ví dụ: single.html cho bài viết lẻ). Injections: Sử dụng bộ máy Go Template để bơm dữ liệu vào các vị trí được định nghĩa sẵn. Minh họa cơ chế bơm dữ liệu:\n\u0026lt;article\u0026gt; \u0026lt;h1\u0026gt;{{ .Title }}\u0026lt;/h1\u0026gt; \u0026lt;!-- Lấy tiêu đề từ Front Matter --\u0026gt; \u0026lt;div class=\u0026#34;meta\u0026#34;\u0026gt;{{ .Date.Format \u0026#34;02/01/2006\u0026#34; }}\u0026lt;/div\u0026gt; \u0026lt;div class=\u0026#34;content\u0026#34;\u0026gt; {{ .Content }} \u0026lt;!-- Nội dung đã được render sang HTML --\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/article\u0026gt; Kết quả kiểm thử hiệu năng thực tế (Build Log):\nStart building sites … hugo v0.146.0+extended linux/amd64 Total in 85 ms Với tốc độ này, Live Reload diễn ra gần như tức thời, giúp quá trình sáng tạo nội dung không bị ngắt quãng.\n3. Hệ thống Shortcodes: Cầu nối giữa Markdown và HTML Để vượt qua giới hạn của văn bản thuần túy mà vẫn giữ cho tệp Markdown sạch sẽ, Hugo sử dụng Shortcodes. Đây là các \u0026ldquo;macro\u0026rdquo; cho phép nhúng các thành phần giao diện phức tạp.\nVí dụ chèn ảnh có chú thích (Figure):\n{{\u0026lt; figure src=\u0026#34;/images/architecture.png\u0026#34; title=\u0026#34;Sơ đồ hệ thống\u0026#34; \u0026gt;}} Ví dụ hộp ghi chú (Note Box) tùy chỉnh:\n{{\u0026lt; note title=\u0026#34;Insight\u0026#34; \u0026gt;}} Sử dụng SSG giúp giảm bề mặt tấn công bảo mật vì không có cơ sở dữ liệu phía server. {{\u0026lt; /note \u0026gt;}} 4. Tự động hóa với CI/CD (GitHub Actions) Một blog chuyên nghiệp cần một quy trình phát hành tin cậy. Khi bạn thực hiện lệnh git push, GitHub Actions sẽ tự động thực thi quy trình biên dịch và triển khai lên GitHub Pages.\nCấu hình YAML tiêu chuẩn:\njobs: build: runs-on: ubuntu-latest steps: - name: Checkout Source uses: actions/checkout@v4 - name: Build Minified Site run: hugo --gc --minify - name: Deploy uses: actions/deploy-pages@v4 Nhận định và Đánh đổi (Trade-offs) Mặc dù Hugo và PaperMod mang lại hiệu suất vượt trội, người dùng cần cân nhắc các yếu tố sau:\nƯu điểm: Tốc độ phản hồi cực nhanh, điểm Google Lighthouse gần như tuyệt đối (100/100), bảo mật cao và quản lý nội dung bằng Git giúp theo dõi lịch sử thay đổi hoàn hảo. Đánh đổi: Đường cong học tập ban đầu (Learning curve) cao hơn các nền tảng kéo-thả. Việc tùy chỉnh sâu đòi hỏi kiến thức cơ bản về HTML/Go Template. Bài học rút ra: Performance issue thường không nằm ở dung lượng ảnh, mà nằm ở kiến trúc hệ thống. Việc chọn một \u0026ldquo;Static-first\u0026rdquo; architecture như Hugo là bước đi chiến lược để tối ưu hóa trải nghiệm người đọc trong dài hạn.\nTìm hiểu thêm về cách tùy chỉnh CSS hoặc cấu hình nâng cao trong các bài viết tiếp theo.\n","permalink":"https://thaig2pro.github.io/posts/hugo-papermod-guide-for-beginners/","summary":"\u003ch2 id=\"chuyển-đổi-tư-duy-từ-soạn-thảo-sang-xuất-bản-kỹ-thuật\"\u003eChuyển đổi tư duy từ soạn thảo sang xuất bản kỹ thuật\u003c/h2\u003e\n\u003cp\u003eTrong kỷ nguyên của sự tối giản và hiệu suất, việc xây dựng blog cá nhân không còn dừng lại ở việc chọn một nền tảng có sẵn. Xu hướng hiện đại đang chuyển dịch mạnh mẽ sang các bộ tạo trang tĩnh (Static Site Generators - SSG). Hugo, khi kết hợp cùng giao diện PaperMod, không chỉ là một công cụ; đó là một hệ sinh thái được tối ưu hóa để chuyển đổi nội dung từ định dạng Markdown thô sơ sang một sản phẩm kỹ thuật số hoàn thiện với độ trễ gần như bằng không.\u003c/p\u003e","title":"Kiến trúc Blog hiện đại: Tại sao Hugo và PaperMod là sự lựa chọn tối ưu?"},{"content":"Trong kiến trúc của một AI Agent, \u0026ldquo;Loop\u0026rdquo; chính là bộ não điều hành. Tuy nhiên, một sai lầm phổ biến là thiết kế Loop theo dạng tuần tự (synchronous). Nếu Agent đang thực hiện một task nặng (như crawl web hoặc chạy một script dài), nó sẽ hoàn toàn \u0026ldquo;mù điếc\u0026rdquo; trước các lệnh mới của người dùng cho đến khi task đó xong.\nHôm nay, chúng ta sẽ phân tích cách ứng dụng asyncio để biến một vòng lặp vô tận trở thành một hệ thống điều hành Agent chuyên nghiệp, đảm bảo tính phản hồi (responsiveness) và khả năng kiểm soát (controllability).\nTổng quan kiến trúc Loop Mô hình chung của một Agent System hiện đại thường vận hành theo cơ chế không đồng bộ để tách biệt các luồng dữ liệu.\nFlow đồ hiển thị sự tách biệt giữa Inbound Message Queue, Loop Dispatcher, và Tool Execution Layer\n1. Non-blocking Dispatcher: Tách biệt việc \u0026ldquo;Nhận\u0026rdquo; và \u0026ldquo;Xử lý\u0026rdquo; Vấn đề lớn nhất của các Agent sơ khai là: Khi đang suy nghĩ, nó không thể nghe.\nTrong một kiến trúc Loop chuẩn, thay vì đợi quá trình xử lý tin nhắn hoàn thành mới nhận tin nhắn tiếp theo, chúng ta sử dụng asyncio.create_task để đẩy logic xử lý vào background. Điều này giúp vòng lặp chính (while self._running) luôn sẵn sàng tiếp nhận tín hiệu mới.\n# Trích đoạn logic từ vòng lặp chính while self._running: try: # Chờ message từ bus với timeout để tránh treo loop msg = await asyncio.wait_for(self.bus.consume_inbound(), timeout=1.0) except asyncio.TimeoutError: continue if msg.content.strip().lower() == \u0026#34;/stop\u0026#34;: await self._handle_stop(msg) else: # Dispatch message thành một task độc lập task = asyncio.create_task(self._dispatch(msg)) self._active_tasks.setdefault(msg.session_key, []).append(task) # Tự động dọn dẹp task khi hoàn thành task.add_done_callback(lambda t, k=msg.session_key: self._active_tasks.get(k, []) and self._active_tasks[k].remove(t)) Cái hay ở đây là gì?\nVòng lặp chính luôn nhạy bén với lệnh /stop. Mỗi yêu cầu được xử lý trong một \u0026ldquo;green thread\u0026rdquo; riêng biệt thông qua _dispatch. Hệ thống có thể quản lý đồng thời nhiều session khác nhau mà không block lẫn nhau. 2. Surgical Cancellation: Cơ chế \u0026ldquo;Dừng khẩn cấp\u0026rdquo; Nếu Agent của bạn bị lặp vô tận (looping) hoặc đang thực thi một tool tốn kém, bạn cần một nút \u0026ldquo;Emergency Stop\u0026rdquo;. Nhờ việc lưu trữ các task đang chạy trong self._active_tasks theo session_key, chúng ta có thể thực hiện dừng chính xác tác vụ đó:\nasync def _handle_stop(self, msg: InboundMessage) -\u0026gt; None: \u0026#34;\u0026#34;\u0026#34;Hủy toàn bộ active tasks của một session cụ thể.\u0026#34;\u0026#34;\u0026#34; tasks = self._active_tasks.pop(msg.session_key, []) cancelled = sum(1 for t in tasks if not t.done() and t.cancel()) for t in tasks: try: await t # Đảm bảo task đã dừng hẳn except (asyncio.CancelledError, Exception): pass # Hủy luôn các sub-agents đang chạy liên quan await self.subagents.cancel_by_session(msg.session_key) Việc quản lý task theo session giúp hệ thống đa người dùng hoạt động ổn định: Dừng task của người dùng A không ảnh hưởng đến tiến trình của người dùng B.\n3. Real-time Progress qua Async Callbacks Người dùng sẽ cảm thấy rất \u0026ldquo;bất an\u0026rdquo; nếu màn hình đứng yên trong 30 giây khi AI đang suy nghĩ. Một kiến trúc Agent tốt cần stream được tiến độ thực hiện (progress) về client ngay khi nó đang diễn ra.\nMinh họa cách Assistant Thought và Tool Call Result được gửi về UI thông qua Async Callback trong khi Loop vẫn đang chạy\n# Stream suy nghĩ và công cụ đang dùng trong lúc chạy loop if response.has_tool_calls: if on_progress: thought = self._strip_think(response.content) if thought: # Gửi suy nghĩ (thought) về UI ngay lập tức await on_progress(thought) # Gửi hint về công cụ (tool) chuẩn bị được gọi await on_progress(self._tool_hint(response.tool_calls), tool_hint=True) Nhờ await, việc gửi tiến độ không làm block logic chính của Agent, tạo ra trải nghiệm UX mượt mà, giúp người dùng biết Agent vẫn đang \u0026ldquo;sống\u0026rdquo;.\n4. Lock Management: Đảm bảo tính nhất quán (Consistency) Dù chạy async để tăng hiệu suất, nhưng việc thay đổi trạng thái session (history, memory) cần sự cẩn trọng tuyệt đối để tránh Race Condition. Nếu không có Lock, hai message gửi gần nhau có thể ghi đè dữ liệu lên nhau.\nasync def _dispatch(self, msg: InboundMessage) -\u0026gt; None: \u0026#34;\u0026#34;\u0026#34;Xử lý message dưới một global lock để đảm bảo thứ tự.\u0026#34;\u0026#34;\u0026#34; async with self._processing_lock: try: response = await self._process_message(msg) if response is not None: await self.bus.publish_outbound(response) except asyncio.CancelledError: logger.info(\u0026#34;Task cancelled for session {}\u0026#34;, msg.session_key) raise Sử dụng asyncio.Lock() đảm bảo rằng dù ta nhận message không đồng bộ, nhưng việc cập nhật trạng thái hệ thống và sinh phản hồi luôn diễn ra theo một trình tự an toàn.\nTổng kết Việc khai thác asyncio trong Agent Loop không chỉ đơn thuần là để chạy nhanh hơn. Đó là về:\nResponsiveness: Luôn lắng nghe và phản hồi người dùng bất cứ lúc nào. Controllability: Khả năng can thiệp và dừng các tác vụ sai lầm ngay lập tức. Observability: Minh bạch hóa quá trình suy nghĩ của AI theo thời gian thực. Nếu bạn đang xây dựng một Agent System nghiêm túc, hãy đầu tư vào một Async Heartbeat. Đó là sự khác biệt giữa một script chạy tự động đơn giản và một hệ thống Agent thực thụ.\n","permalink":"https://thaig2pro.github.io/posts/async-agent-loop-engineering/","summary":"\u003cp\u003eTrong kiến trúc của một AI Agent, \u0026ldquo;Loop\u0026rdquo; chính là bộ não điều hành. Tuy nhiên, một sai lầm phổ biến là thiết kế Loop theo dạng tuần tự (synchronous). Nếu Agent đang thực hiện một task nặng (như crawl web hoặc chạy một script dài), nó sẽ hoàn toàn \u0026ldquo;mù điếc\u0026rdquo; trước các lệnh mới của người dùng cho đến khi task đó xong.\u003c/p\u003e\n\u003cp\u003eHôm nay, chúng ta sẽ phân tích cách ứng dụng \u003ccode\u003easyncio\u003c/code\u003e để biến một vòng lặp vô tận trở thành một hệ thống điều hành Agent chuyên nghiệp, đảm bảo tính phản hồi (responsiveness) và khả năng kiểm soát (controllability).\u003c/p\u003e","title":"Async Agent Loop: Đảm bảo khả năng kiểm soát và phản hồi thời gian thực cho AI Agent"},{"content":"This is your new vault.\nMake a note of something, [[create a link]], or try the Importer!\nWhen you\u0026rsquo;re ready, delete this note and make the vault your own.\n","permalink":"https://thaig2pro.github.io/blog/welcome/","summary":"\u003cp\u003eThis is your new \u003cem\u003evault\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eMake a note of something, [[create a link]], or try \u003ca href=\"https://help.obsidian.md/Plugins/Importer\"\u003ethe Importer\u003c/a\u003e!\u003c/p\u003e\n\u003cp\u003eWhen you\u0026rsquo;re ready, delete this note and make the vault your own.\u003c/p\u003e","title":""}]