Bốn Thành Phần Lõi: Kiến Trúc AI Agent Cơ Bản Bạn Phải Biết

Khi bắt đầu xây dựng một AI agent từ đầu, nhiều người thường bị choáng ngợp bởi các khái niệm phức tạp như Large Language Models, tool calling, hay reasoning loops. Tuy nhiên, nếu bạn hiểu rõ bốn thành phần cơ bản tạo nên bất kỳ agent nào, mọi thứ sẽ trở nên rõ ràng hơn đáng kể.
Từ kinh nghiệm xây dựng và triển khai các hệ thống AI agent trong thực tế, tôi nhận thấy rằng bốn thành phần lõi này xuất hiện trong mọi loại agent, dù bạn xây dựng một agent đơn giản bằng Python hay một hệ thống phức tạp dựa trên LLM như GPT. Hiểu rõ chúng sẽ giúp bạn thiết kế agent thông minh hơn, mở rộng khả năng của nó dễ dàng hơn, và debug các vấn đề nhanh chóng hơn.
Thành Phần Thứ Nhất: Perception (Cảm Nhận)
Perception là cách agent "nhìn" thế giới xung quanh. Đây là các input, dữ liệu hoặc tín hiệu mà agent nhận được từ người dùng hoặc môi trường. Nó có thể là một câu hỏi từ khách hàng, dữ liệu từ một API, hoặc một file mà người dùng upload lên.
Ví dụ thực tế: Khi bạn xây dựng một AI agent để hỗ trợ khách hàng tại một công ty CNTT ở Việt Nam, perception của agent là những câu hỏi mà khách hàng gửi vào. Agent cần "cảm nhận" được câu hỏi này, hiểu nó đang yêu cầu gì, rồi mới có thể xử lý tiếp.
Trong code, phần perception thường là nơi bạn nhận dữ liệu đầu vào:
user_input = input("Bạn cần tôi giúp gì? ") perception = { "query": user_input, "timestamp": datetime.now(), "user_id": current_user } Dù đơn giản hay phức tạp, perception luôn là điểm khởi đầu của bất kỳ quá trình xử lý nào trong agent.
Thành Phần Thứ Hai: Decision Making (Quyết Định)
Đây là "bộ não" của agent. Decision Making là quá trình mà agent sử dụng một hệ thống logic, mô hình AI (như LLM), hoặc quy tắc được lập trình để xác định hành động tiếp theo. Agent cần "suy nghĩ" về input và quyết định nó sẽ làm gì.
Trong các agent đơn giản, decision making có thể là những câu lệnh if-else. Trong các agent phức tạp dựa trên LLM, đây là quá trình model xử lý câu hỏi, gọi các function cần thiết, và suy luận từng bước để đến được câu trả lời.
Ví dụ trong một agent hỗ trợ bán hàng:
response = llm.chat( messages=[ {"role": "system", "content": "Bạn là nhân viên bán hàng. Giúp khách hàng tìm sản phẩm."}, {"role": "user", "content": user_input} ], tools=available_tools ) # Agent quyết định nó sẽ gọi function nào if response.tool_call: decision = response.tool_name else: decision = "respond_directly" Phần Decision Making này quyết định toàn bộ hành động của agent. Nếu phần này không tốt, agent sẽ lạc hướng, không biết mình phải làm gì tiếp theo.
Thành Phần Thứ Ba: Action (Hành Động)
Sau khi quyết định, agent cần thực hiện hành động đó. Action là lúc agent thực sự tương tác với môi trường: gửi câu trả lời cho người dùng, gọi một API bên ngoài, thay đổi dữ liệu trong cơ sở dữ liệu, hoặc thực thi một script nào đó.
Nếu Decision Making là "suy nghĩ", thì Action là "làm".
# Agent quyết định gọi tool search_product if decision == "search_product": results = search_product(product_name=extracted_param) action_output = results elif decision == "respond_directly": action_output = response.text # Gửi kết quả cho người dùng print(f"Agent: ") Bước Action này rất quan trọng vì nó biến quyết định thành kết quả thực tế mà người dùng có thể cảm nhận được.
Thành Phần Thứ Tư: Memory (Bộ Nhớ)
Một agent không thể chỉ sống trong hiện tại. Nó cần nhớ lại những cuộc hội thoại trước đó, những quyết định đã làm, hay những thông tin mà người dùng đã cung cấp. Memory giúp agent cung cấp trải nghiệm nhất quán và cá nhân hóa.
Trong thực tế, khi bạn nói chuyện với một agent hỗ trợ khách hàng, nó cần nhớ bạn đã hỏi gì trước đó, những vấn đề bạn gặp phải là gì, để không phải lặp lại từ đầu mỗi lần.
conversation_history = [ {"role": "user", "content": "Tôi muốn mua laptop"}, {"role": "assistant", "content": "Bạn muốn laptop loại nào?"}, {"role": "user", "content": "Laptop gaming, giá dưới 20 triệu"} ] # Agent sử dụng conversation_history để hiểu ngữ cảnh response = llm.chat( messages=conversation_history + [{"role": "user", "content": new_input}] ) Memory có thể là conversation history (lịch sử hội thoại), user profile (hồ sơ người dùng), hoặc vector embeddings lưu trữ trong một vector database để agent có thể tìm kiếm các thông tin liên quan nhanh chóng.
Cách Bốn Thành Phần Hoạt Động Cùng Nhau
Bốn thành phần này hoạt động theo một vòng lặp: Perception → Decision Making → Action → Memory Update → (lặp lại).
Mỗi khi người dùng gửi một tin nhắn, agent sẽ:
- Cảm nhận tin nhắn đó (Perception)
- Suy nghĩ xem nó sẽ trả lời như thế nào hoặc cần gọi những tool nào (Decision Making)
- Thực hiện hành động đó (Action)
- Lưu trữ thông tin này vào memory để dùng lần sau (Memory)
Khi bạn xây dựng một AI agent từ đầu trên GitHub hoặc bất kỳ nền tảng nào, nếu bạn đảm bảo rằng bốn thành phần này được thiết kế tốt và làm việc cùng nhau một cách mạch lạc, agent của bạn sẽ mạnh mẽ, linh hoạt, và dễ mở rộng. Đây chính là nền tảng của mọi hệ thống agent, từ những hệ thống đơn giản nhất đến những AI tự hành phức tạp nhất.
Implementation Python Đơn Giản: Tạo Agent Đầu Tiên Bằng Code Thực Tế

Hiểu Bản Chất Trước Khi Code
Trước khi viết dòng code nào, cần hiểu rõ: AI agent không phải là một khối code phức tạp, mà là một vòng lặp đơn giản gồm ba bước cơ bản—nhận input, xử lý quyết định, và thực hiện hành động. Khi bạn xây dựng agent từ scratch, thực chất bạn đang tạo một hệ thống có khả năng lắng nghe, suy nghĩ, và phản hồi.
Ở tôi, khi triển khai agent cho các khách hàng SME Việt Nam—chẳng hạn như một công ty bán lẻ muốn tự động hóa trả lời câu hỏi khách hàng—bước đầu tiên không phải là chạy API LLM, mà là thiết kế rõ ràng: agent cần làm gì, nó sẽ nói gì với người dùng, và công cụ nào nó cần để hoàn thành nhiệm vụ.
Bắt Đầu Với Một Agent Python Cơ Bản
Hãy xây dựng một agent đơn giản—một trợ lý có thể trả lời câu hỏi về sản phẩm bằng cách kiểm tra một cơ sở dữ liệu nhỏ. Agent này sẽ cho bạn thấy cơ chế lõi của mọi AI agent hiện đại.
Bước 1: Định Nghĩa Công Cụ Mà Agent Có Thể Sử Dụng
Agent cần biết nó có những công cụ gì. Trong ví dụ này, agent có thể truy vấn thông tin sản phẩm:
def get_product_info(product_name): """Công cụ để tìm thông tin sản phẩm""" products = { "laptop": "Laptop HP 15 inch, giá 15 triệu VND, pin 8h", "phone": "Điện thoại iPhone 14, giá 20 triệu VND, màu đen", "tablet": "iPad Pro 12.9 inch, giá 25 triệu VND, 256GB" } return products.get(product_name.lower(), "Sản phẩm không tìm thấy") def check_inventory(product_name): """Công cụ để kiểm tra tồn kho""" inventory = { "laptop": 5, "phone": 12, "tablet": 3 } stock = inventory.get(product_name.lower(), 0) return f"Còn chiếc trong kho" # Đăng ký các công cụ mà agent có thể gọi tools = { "get_product_info": get_product_info, "check_inventory": check_inventory } Bước 2: Tạo Vòng Lặp Agent
Vòng lặp này là trái tim của agent. Nó nhận input từ người dùng, quyết định công cụ nào cần gọi, và trả lại kết quả:
def simple_agent(user_query): """Agent đơn giản không sử dụng LLM""" query = user_query.lower() # Logic quyết định: nếu câu hỏi chứa từ khóa, gọi công cụ tương ứng if "thông tin" in query or "giá" in query: # Trích xuất tên sản phẩm từ câu hỏi for product in tools.keys(): if product in query: return get_product_info(product) return "Vui lòng chỉ rõ sản phẩm nào" elif "tồn" in query or "kho" in query: for product in ["laptop", "phone", "tablet"]: if product in query: return check_inventory(product) return "Vui lòng chỉ rõ sản phẩm nào" else: return "Tôi chỉ có thể trả lời về sản phẩm và tồn kho" # Kiểm thử agent print(simple_agent("Cho tôi thông tin về laptop")) print(simple_agent("Còn bao nhiêu phone trong kho?")) Code trên minh họa nguyên tắc: agent phân tích input, chọn công cụ phù hợp, thực hiện nó, và trả lại kết quả. Đây chính là mô hình mà ngay cả các agent dùng LLM cũng tuân theo—chỉ là phần "quyết định" được thay bằng một mô hình AI thay vì điều kiện if-else.
Bước 3: Nâng Cấp Với Hệ Thống Ghi Nhớ (Memory)
Một agent thực tế cần ghi nhớ cuộc trò chuyện. Nếu không, nó sẽ mất bối cảnh sau mỗi lần tương tác:
class SimpleAgent: def __init__(self): self.conversation_history = [] def process(self, user_input): # Lưu input của người dùng self.conversation_history.append({"role": "user", "content": user_input}) # Xử lý và tạo response response = simple_agent(user_input) # Lưu response của agent self.conversation_history.append({"role": "assistant", "content": response}) return response def get_history(self): return self.conversation_history # Sử dụng agent với memory agent = SimpleAgent() print(agent.process("Thông tin về phone?")) print(agent.process("Còn bao nhiêu cái?")) # Biết đang nói về phone nhờ history print("\nLịch sử hội thoại:") for msg in agent.get_history(): print(f": ") Thêm memory khiến agent trở nên "nhân văn" hơn—nó có thể theo dõi ngữ cảnh cuộc trò chuyện thay vì trả lời từng câu độc lập.
Áp Dụng Thực Tế
Cấu trúc này đã được tôi áp dụng cho nhiều dự án thực tế. Một công ty bán hàng online Việt Nam sử dụng mô hình tương tự để tự động xử lý 60% câu hỏi khách hàng mà không cần can thiệp con người. Khác biệt duy nhất là họ sử dụng một LLM thực sự thay cho logic điều kiện, nhưng vòng lặp cơ bản vẫn giống hệt.
Khi bạn làm quen với mô hình này, việc chuyển sang agent dùng các mô hình LLM trên GitHub trở nên tự nhiên và dễ hiểu hơn—bởi vì bạn đã hiểu được cơ chế lõi mà không bị lẫn lộn bởi độ phức tạp của API hay mô hình ngôn ngữ.
Tại Sao Hiểu Bản Chất Quan Trọng?
Nhiều người nhảy vào code LLM-based ngay mà không hiểu nguyên tắc cơ bản, dẫn đến khó gỡ lỗi và lãng phí chi phí API. Khi bạn xây dựng từ scratch, bạn không chỉ học code mà còn hiểu "vì sao" agent hoạt động như vậy. Điều này giúp bạn tối ưu chi phí, tăng độ tin cậy của hệ thống, và nhanh chóng thích ứng khi yêu cầu thay đổi—những điều cực kỳ quan trọng trong công việc thực tế.
LLM-Based Agent: Tích Hợp GPT, Tool Calling và Xử Lý Phản Hồi

Khi xây dựng AI agent từ đầu, bước quan trọng nhất là hiểu cách tích hợp một mô hình ngôn ngữ lớn (LLM) như GPT để tạo ra quyết định thông minh. Không phải tất cả agent đều cần một LLM – agent đơn giản có thể chỉ dùng logic điều kiện hoặc regex. Tuy nhiên, khi bạn muốn agent có khả năng suy luận linh hoạt, hiểu ngữ cảnh phức tạp và tự quyết định khi nào cần dùng công cụ nào, LLM trở thành thành phần không thể thiếu.
Bản chất của LLM-based Agent
LLM-based agent hoạt động theo chu kỳ: nhận yêu cầu từ người dùng → dùng LLM để suy luận và quyết định → gọi các công cụ (tool) cần thiết → xử lý kết quả → trả lời người dùng. Điểm mấu chốt là LLM không chỉ sinh ra text bình thường, mà còn sinh ra các lệnh gọi công cụ có cấu trúc. Đây là khái niệm "tool calling" hoặc "function calling" – một tính năng hiện đại của các mô hình GPT-4, GPT-3.5-turbo mà giúp agent có thể thực hiện hành động cụ thể.
Ví dụ thực tế: một agent quản lý email có thể nhận yêu cầu "gửi email tới thà[email protected] nói là lần sau họp lúc 3 giờ chiều". Agent dùng LLM để:
- Hiểu được nội dung yêu cầu (gửi email, thay đổi lịch họp)
- Quyết định cần gọi công cụ nào: send_email() và update_meeting()
- Sinh ra các tham số chính xác: email_to="thà[email protected]", time="15:00"
Cách tích hợp Tool Calling vào workflow
Trên GitHub, bạn sẽ tìm thấy những repository mẫu về cách triển khai điều này. Cơ chế hoạt động như sau:
Đầu tiên, bạn định nghĩa các công cụ mà agent có thể dùng dưới dạng JSON schema. Ví dụ, một tool "search_knowledge" có thể được mô tả như:
{ "type": "function", "function": { "name": "search_knowledge", "description": "Tìm kiếm thông tin trong cơ sở dữ liệu", "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "Từ khóa tìm kiếm"}, "category": {"type": "string", "description": "Danh mục tìm kiếm"} }, "required": ["query"] } } } Tiếp theo, bạn gửi yêu cầu của người dùng kèm danh sách công cụ này tới LLM. LLM sẽ trả lại một phản hồi có cấu trúc – nó có thể là text bình thường hoặc một lệnh gọi công cụ dạng JSON. Bước này gọi là "parsing tool call".
Ví dụ, khi người dùng hỏi "Công ty chúng ta năm ngoái doanh thu bao nhiêu?", LLM có thể sinh ra:
{ "tool_calls": [ { "id": "call_1", "function": { "name": "search_knowledge", "arguments": "{\"query\": \"doanh thu năm ngoái\", \"category\": \"financial\"}" } } ] } Agent của bạn sẽ phân tích response này, nhận diện được cần gọi search_knowledge() với các tham số đó, thực thi, sau đó gửi kết quả trở lại cho LLM để sinh ra câu trả lời hoàn chỉnh.
Xử lý phản hồi và quản lý lịch sử hội thoại
Một yếu tố thường bị bỏ qua là conversation history – lịch sử cuộc trò chuyện. Khi bạn dùng LLM, nó không có "bộ nhớ" tự động. Mỗi lần gọi API, bạn phải truyền lại toàn bộ cuộc trò chuyện cũ. Điều này rất quan trọng cho agent vì nó cho phép agent nhớ lại các công cụ đã gọi trước đó và kết quả của chúng.
Ví dụ: người dùng hỏi "Ai là CEO?" (gọi công cụ). Sau đó hỏi "Anh ấy làm việc ở đâu?" – agent cần biết rằng "anh ấy" chỉ CEO vừa tìm được. Bằng cách duy trì conversation history, agent có ngữ cảnh đầy đủ để sinh ra câu trả lời chính xác.
Cấu trúc conversation history thường như sau:
[ {"role": "user", "content": "Ai là CEO?"}, {"role": "assistant", "content": "[gọi công cụ...]"}, {"role": "tool", "content": "Nguyễn Văn A là CEO"}, {"role": "assistant", "content": "CEO là Nguyễn Văn A"}, {"role": "user", "content": "Anh ấy làm việc ở đâu?"}, ... ] Xử lý lỗi và vòng lặp lặp lại
Trong thực tế, không phải lúc nào tool calling cũng thành công. API có thể bị timeout, công cụ có thể thất bại, hoặc LLM có thể sinh ra lệnh gọi không hợp lệ. Một agent chắc chắn phải có logic xử lý lỗi – retry mechanism hoặc fallback logic. Nhiều agent trên GitHub sử dụng các strategy như:
- Gọi lại công cụ tối đa N lần nếu thất bại
- Thay thế công cụ khác nếu công cụ chính không có sẵn
- Trả lời trực tiếp từ kiến thức của LLM nếu không cần tool
Hiểu rõ cơ chế tool calling và xử lý phản hồi là nền tảng để xây dựng agent mạnh mẽ. Tìm hiểu thêm về kiến trúc agent hoàn chỉnh sẽ giúp bạn nắm vững cách thiết kế hệ thống suy luận đa bước cho agent của mình.
Vòng Lặp Agent Nâng Cao: Quản Lý State, Xử Lý Error, và Duy Trì Context

Khi bạn xây dựng AI agent từ đầu, bước đầu tiên là hiểu rõ vòng lặp chính (main loop) của agent hoạt động thế nào. Tuy nhiên, để đưa agent vào sản xuất hoặc sử dụng thực tế, bạn cần xử lý những tình huống phức tạp: khi agent gặp lỗi, khi cuộc hội thoại kéo dài hàng chục lần tương tác, khi cần nhớ thông tin từ các phiên trò chuyện trước đó, hoặc khi agent phải chạy song song nhiều tác vụ. Đây chính là phần "nâng cao" của việc xây dựng agent thực chiến.
Quản Lý State và Duy Trì Context Trong Suốt Vòng Lặp
State (trạng thái) là trái tim của mọi agent hiệu quả. Khi bạn xây dựng một agent để trả lời câu hỏi khách hàng trên website bán hàng, agent không thể quên rằng khách hàng vừa hỏi về sản phẩm X ba bước trước. Nếu quên, nó sẽ trả lời không liên quan, và trải nghiệm người dùng sẽ tệ.
Bản chất của việc duy trì context là giữ lại toàn bộ lịch sử tương tác (conversation history) và trạng thái của các tác vụ đang thực hiện. Dưới đây là cách thực hiện điều này:
class AgentState: def __init__(self): self.conversation_history = [] # Lưu tất cả tin nhắn self.tool_results = {} # Kết quả từ các công cụ self.current_task = None # Tác vụ đang thực hiện self.max_history = 20 # Giới hạn lịch sử để tiết kiệm token def add_message(self, role, content): """Thêm tin nhắn vào lịch sử""" self.conversation_history.append({ "role": role, # "user" hoặc "assistant" "content": content }) # Xóa tin nhắn cũ nếu vượt quá giới hạn if len(self.conversation_history) > self.max_history: self.conversation_history.pop(0) def get_context(self): """Trả về context hiện tại để gửi tới LLM""" return { "history": self.conversation_history, "task": self.current_task, "previous_results": self.tool_results } Điểm quan trọng ở đây: bạn không thể lưu trữ toàn bộ lịch sử mãi mãi vì nó sẽ làm tăng chi phí API và giảm tốc độ xử lý. Thay vào đó, hãy giữ lại một "cửa sổ trượt" (sliding window) của những tin nhắn gần nhất. Trong các dự án thực tế tại Việt Nam mà tôi tham gia, chúng tôi thường giữ khoảng 15-25 tin nhắn cuối cùng, đủ để agent hiểu ngữ cảnh mà không quá lãng phí.
Xử Lý Lỗi và Retry Logic Trong Vòng Lặp
Agent không phải lúc nào cũng thành công. Có thể API bị down, công cụ trả về lỗi, hoặc agent tạo ra một câu lệnh không hợp lệ. Để tạo agent đáng tin cậy, bạn cần logic retry thông minh.
import time def execute_tool_with_retry(tool_name, tool_input, max_retries=3, backoff_factor=2): """Thực thi công cụ với cơ chế retry""" retry_count = 0 last_error = None while retry_count