{"product_id":"xay-dựng-llm-agent-từ-dầu-reference-implementation","title":"Xây dựng LLM Agent từ đầu — Reference Implementation","description":"\n\u003cp\u003eBạn đã nghe nhiều về AI Agents — các hệ thống AI tự động thực thi nhiệm vụ phức tạp, gọi công cụ, và đưa ra quyết định. Nhưng thực ra, một agent chỉ là \u003cstrong\u003emột vòng lặp đơn giản\u003c\/strong\u003e. Bài viết này sẽ xây dựng agent từ đầu, không dùng LangChain, AutoGen, hay bất kỳ framework nào — để bạn hiểu đúng bản chất.\u003c\/p\u003e\n\n\u003cp\u003eĐây là reference implementation chính thức từ Anthropic, được biên soạn lại cho cộng đồng Việt Nam.\u003c\/p\u003e\n\n\u003ch2\u003eAgent là gì? Tại sao không dùng framework?\u003c\/h2\u003e\n\n\u003cp\u003eMột LLM Agent về bản chất gồm 3 thứ:\u003c\/p\u003e\n\u003col\u003e\n  \u003cli\u003e\n\u003cstrong\u003eAgent Loop\u003c\/strong\u003e — vòng lặp: nhận input → gọi LLM → thực thi tool → lặp lại\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eTools\u003c\/strong\u003e — các hàm mà agent có thể gọi (search web, đọc file, tính toán...)\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eMemory\u003c\/strong\u003e — lịch sử conversation để giữ context\u003c\/li\u003e\n\u003c\/ol\u003e\n\n\u003cp\u003eFramework ẩn những thứ này đi, khiến bạn khó debug khi agent làm sai. Xây từ đầu giúp bạn:\u003c\/p\u003e\n\u003cul\u003e\n  \u003cli\u003eHiểu chính xác mỗi bước agent làm gì\u003c\/li\u003e\n  \u003cli\u003eTùy chỉnh behavior mà không bị giới hạn bởi abstraction\u003c\/li\u003e\n  \u003cli\u003eDebug dễ dàng khi agent mắc lỗi\u003c\/li\u003e\n  \u003cli\u003eMigrate sang Claude model mới không cần đợi framework update\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch2\u003eKiến trúc tổng quan\u003c\/h2\u003e\n\n\u003cp\u003eAgent loop hoạt động theo sơ đồ sau:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eUser Input\n    |\n    v\n[LLM decides: respond or use tool?]\n    |\n    +---\u0026gt; Respond to user (DONE)\n    |\n    +---\u0026gt; Call tool\n              |\n              v\n         [Execute tool]\n              |\n              v\n         [Add result to memory]\n              |\n              v\n         [Back to LLM]\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003cp\u003eVòng lặp tiếp tục cho đến khi LLM quyết định đưa ra final answer thay vì gọi thêm tool.\u003c\/p\u003e\n\n\u003ch2\u003eBước 1: Định nghĩa Tools\u003c\/h2\u003e\n\n\u003cp\u003eTool là một Python function kèm schema JSON mô tả input\/output của nó. Claude đọc schema để biết cách gọi tool.\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eimport anthropic\nimport json\n\n# Tool thực tế\ndef get_weather(city: str) -\u0026gt; str:\n    # Trong thực tế, gọi weather API\n    return f\"Thời tiết tại {city}: 28 do C, co may\"\n\ndef calculate(expression: str) -\u0026gt; str:\n    try:\n        result = eval(expression)\n        return str(result)\n    except Exception as e:\n        return f\"Loi: {e}\"\n\n# Schema cho Claude\ntools = [\n    {\n        \"name\": \"get_weather\",\n        \"description\": \"Lay thong tin thoi tiet cho mot thanh pho\",\n        \"input_schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"city\": {\n                    \"type\": \"string\",\n                    \"description\": \"Ten thanh pho can lay thoi tiet\"\n                }\n            },\n            \"required\": [\"city\"]\n        }\n    },\n    {\n        \"name\": \"calculate\",\n        \"description\": \"Tinh toan bieu thuc toan hoc\",\n        \"input_schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"expression\": {\n                    \"type\": \"string\",\n                    \"description\": \"Bieu thuc can tinh, vi du: 2 + 3 * 4\"\n                }\n            },\n            \"required\": [\"expression\"]\n        }\n    }\n]\n\n# Map tên tool sang hàm thực thi\ntool_map = {\n    \"get_weather\": get_weather,\n    \"calculate\": calculate\n}\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 2: Agent Loop\u003c\/h2\u003e\n\n\u003cp\u003eĐây là trái tim của mọi agent. Logic đơn giản nhưng mạnh mẽ:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eclient = anthropic.Anthropic()\n\ndef run_agent(user_message: str, max_iterations: int = 10):\n    \"\"\"\n    Agent loop chinh.\n    - max_iterations: bao ve khong bi loop vo han\n    \"\"\"\n    # Memory: lich su conversation\n    messages = [\n        {\"role\": \"user\", \"content\": user_message}\n    ]\n\n    print(f\"User: {user_message}\")\n    print(\"-\" * 50)\n\n    for iteration in range(max_iterations):\n        # Goi LLM\n        response = client.messages.create(\n            model=\"claude-opus-4-5\",\n            max_tokens=4096,\n            tools=tools,\n            messages=messages\n        )\n\n        # Them response vao memory\n        messages.append({\n            \"role\": \"assistant\",\n            \"content\": response.content\n        })\n\n        # Kiem tra stop reason\n        if response.stop_reason == \"end_turn\":\n            # Claude da tra loi xong, khong can goi tool\n            final_text = \"\"\n            for block in response.content:\n                if hasattr(block, \"text\"):\n                    final_text = block.text\n            print(f\"Agent: {final_text}\")\n            return final_text\n\n        elif response.stop_reason == \"tool_use\":\n            # Claude muon goi tool\n            tool_results = []\n\n            for block in response.content:\n                if block.type == \"tool_use\":\n                    tool_name = block.name\n                    tool_input = block.input\n                    tool_use_id = block.id\n\n                    print(f\"[Tool call] {tool_name}({tool_input})\")\n\n                    # Thuc thi tool\n                    if tool_name in tool_map:\n                        result = tool_map[tool_name](**tool_input)\n                    else:\n                        result = f\"Unknown tool: {tool_name}\"\n\n                    print(f\"[Tool result] {result}\")\n\n                    tool_results.append({\n                        \"type\": \"tool_result\",\n                        \"tool_use_id\": tool_use_id,\n                        \"content\": result\n                    })\n\n            # Them ket qua tool vao memory\n            messages.append({\n                \"role\": \"user\",\n                \"content\": tool_results\n            })\n\n        else:\n            print(f\"Unexpected stop reason: {response.stop_reason}\")\n            break\n\n    return \"Max iterations reached\"\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 3: Chạy thử\u003c\/h2\u003e\n\n\u003cp\u003eTest agent với câu hỏi cần dùng cả hai tools:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e# Test 1: Single tool\nresult = run_agent(\"Thoi tiet o Ha Noi hom nay the nao?\")\n\n# Test 2: Multi-step reasoning\nresult = run_agent(\n    \"Neu nhiet do Ha Noi hom nay la 28 do C, \"\n    \"cong them 15 do thi duoc bao nhieu?\"\n)\n\n# Test 3: No tool needed\nresult = run_agent(\"Claude la gi?\")\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003cp\u003eOutput sẽ trông như thế này:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eUser: Neu nhiet do Ha Noi hom nay la 28 do C, cong them 15 do thi duoc bao nhieu?\n--------------------------------------------------\n[Tool call] get_weather({'city': 'Ha Noi'})\n[Tool result] Thoi tiet tai Ha Noi: 28 do C, co may\n[Tool call] calculate({'expression': '28 + 15'})\n[Tool result] 43\nAgent: Nhiet do Ha Noi hom nay la 28 do C.\n       Neu cong them 15 do thi se la 43 do C.\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 4: Conversation Memory\u003c\/h2\u003e\n\n\u003cp\u003eMemory trong agent đơn giản chỉ là list messages. Nhưng có một số chiến lược quản lý memory quan trọng:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eclass AgentWithMemory:\n    def __init__(self, system_prompt: str = \"\"):\n        self.client = anthropic.Anthropic()\n        self.messages = []\n        self.system_prompt = system_prompt\n\n    def chat(self, user_message: str) -\u0026gt; str:\n        \"\"\"Multi-turn: giu nguyen conversation history.\"\"\"\n        self.messages.append({\n            \"role\": \"user\",\n            \"content\": user_message\n        })\n\n        response = self.client.messages.create(\n            model=\"claude-opus-4-5\",\n            max_tokens=4096,\n            system=self.system_prompt,\n            tools=tools,\n            messages=self.messages\n        )\n\n        # Xu ly tool calls neu co\n        while response.stop_reason == \"tool_use\":\n            self.messages.append({\n                \"role\": \"assistant\",\n                \"content\": response.content\n            })\n\n            tool_results = []\n            for block in response.content:\n                if block.type == \"tool_use\":\n                    result = tool_map.get(block.name, lambda **x: \"Unknown tool\")(**block.input)\n                    tool_results.append({\n                        \"type\": \"tool_result\",\n                        \"tool_use_id\": block.id,\n                        \"content\": result\n                    })\n\n            self.messages.append({\n                \"role\": \"user\",\n                \"content\": tool_results\n            })\n\n            response = self.client.messages.create(\n                model=\"claude-opus-4-5\",\n                max_tokens=4096,\n                system=self.system_prompt,\n                tools=tools,\n                messages=self.messages\n            )\n\n        # Lay final text\n        final_text = next(\n            (block.text for block in response.content if hasattr(block, \"text\")),\n            \"\"\n        )\n\n        self.messages.append({\n            \"role\": \"assistant\",\n            \"content\": final_text\n        })\n\n        return final_text\n\n    def clear_memory(self):\n        \"\"\"Reset conversation.\"\"\"\n        self.messages = []\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 5: Memory Compression — Xử lý hội thoại dài\u003c\/h2\u003e\n\n\u003cp\u003eVấn đề: khi conversation dài, context window đầy và chi phí tăng. Giải pháp: \u003cstrong\u003ecompress memory\u003c\/strong\u003e.\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef compress_memory(messages: list, keep_last_n: int = 6) -\u0026gt; list:\n    \"\"\"\n    Giu nguyen system context va n messages gan nhat.\n    Summarize phan con lai.\n    \"\"\"\n    if len(messages) \u0026lt;= keep_last_n:\n        return messages\n\n    # Phan can summarize\n    old_messages = messages[:-keep_last_n]\n    recent_messages = messages[-keep_last_n:]\n\n    # Tao summary\n    summary_response = client.messages.create(\n        model=\"claude-haiku-4-5\",\n        max_tokens=500,\n        messages=[\n            {\"role\": \"user\", \"content\": (\n                \"Hay tom tat ngan gon nhung diem chinh cua cuoc hoi thoai sau: \"\n                + json.dumps(old_messages, ensure_ascii=False)\n            )}\n        ]\n    )\n    summary = summary_response.content[0].text\n\n    # Them summary vao dau recent messages\n    compressed = [\n        {\"role\": \"user\", \"content\": f\"[Tom tat hoi thoai truoc]: {summary}\"},\n        {\"role\": \"assistant\", \"content\": \"Da hieu context. Toi se tiep tuc hoi thoai.\"},\n        *recent_messages\n    ]\n\n    return compressed\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eError Handling — Agent production-ready\u003c\/h2\u003e\n\n\u003cp\u003eAgent thực tế cần xử lý lỗi gracefully:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef safe_tool_execute(tool_name: str, tool_input: dict) -\u0026gt; str:\n    \"\"\"Thuc thi tool voi error handling day du.\"\"\"\n    try:\n        if tool_name not in tool_map:\n            return f\"Error: Tool '{tool_name}' khong ton tai\"\n\n        result = tool_map[tool_name](**tool_input)\n        return str(result)\n\n    except TypeError as e:\n        return f\"Error: Input khong hop le — {e}\"\n    except Exception as e:\n        return f\"Error: {type(e).__name__} — {e}\"\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eTổng kết: Anatomy của một Agent\u003c\/h2\u003e\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n\u003cth\u003eThành phần\u003c\/th\u003e\n\u003cth\u003eVai trò\u003c\/th\u003e\n\u003cth\u003eVí dụ\u003c\/th\u003e\n\u003c\/tr\u003e\n  \u003c\/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n\u003ctd\u003eAgent Loop\u003c\/td\u003e\n\u003ctd\u003eĐiều phối toàn bộ flow\u003c\/td\u003e\n\u003ctd\u003eVòng while cho đến end_turn\u003c\/td\u003e\n\u003c\/tr\u003e\n    \u003ctr\u003e\n\u003ctd\u003eTools\u003c\/td\u003e\n\u003ctd\u003eKhả năng tương tác thế giới\u003c\/td\u003e\n\u003ctd\u003eget_weather, calculate, search\u003c\/td\u003e\n\u003c\/tr\u003e\n    \u003ctr\u003e\n\u003ctd\u003eMemory\u003c\/td\u003e\n\u003ctd\u003eGiữ context qua các turns\u003c\/td\u003e\n\u003ctd\u003eList messages append\u003c\/td\u003e\n\u003c\/tr\u003e\n    \u003ctr\u003e\n\u003ctd\u003eError Handling\u003c\/td\u003e\n\u003ctd\u003eRobustness production\u003c\/td\u003e\n\u003ctd\u003etry\/except + fallback\u003c\/td\u003e\n\u003c\/tr\u003e\n    \u003ctr\u003e\n\u003ctd\u003eMemory Compression\u003c\/td\u003e\n\u003ctd\u003eQuản lý context window\u003c\/td\u003e\n\u003ctd\u003eSummarize old messages\u003c\/td\u003e\n\u003c\/tr\u003e\n  \u003c\/tbody\u003e\n\u003c\/table\u003e\n\n\u003cp\u003ePattern này là nền tảng của \u003cstrong\u003emọi\u003c\/strong\u003e AI agent hiện đại. Khi bạn hiểu rõ 5 thành phần này, bạn có thể xây dựng bất kỳ agent nào: coding agent, research agent, customer support agent, hay thậm chí multi-agent system.\u003c\/p\u003e\n\n\u003cp\u003eBước tiếp theo: Xem \u003ca href=\"\/collections\/nang-cao\"\u003eAutonomous Coding Agent\u003c\/a\u003e để thấy pattern này áp dụng vào bài toán thực tế, và \u003ca href=\"\/collections\/san-pham\"\u003eComputer Use Demo\u003c\/a\u003e để xem agent kiểm soát cả màn hình máy tính.\u003c\/p\u003e\n\n\u003chr\u003e\n\u003ch3\u003eBài viết liên quan\u003c\/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\/products\/calculator-tool-bai-h%E1%BB%8Dc-d%E1%BA%A7u-tien-v%E1%BB%81-tool-use-v%E1%BB%9Bi-claude\"\u003eCalculator Tool — Bài học đầu tiên về Tool Use với Claude\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/context-compaction-t%E1%BB%B1-d%E1%BB%99ng-nen-context-cho-conversations-dai\"\u003eContext Compaction — Tự động nén context cho conversations dài\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/tim-ki%E1%BA%BFm-wikipedia-v%E1%BB%9Bi-claude-research-agent-d%C6%A1n-gi%E1%BA%A3n\"\u003eTìm kiếm Wikipedia với Claude — Research agent đơn giản\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/building-effective-agents-v%E1%BB%9Bi-claude-h%C6%B0%E1%BB%9Bng-d%E1%BA%ABn-ki%E1%BA%BFn-truc\"\u003eBuilding Effective Agents với Claude — Hướng dẫn kiến trúc\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/autonomous-coding-agent-ai-t%E1%BB%B1-vi%E1%BA%BFt-code-t%E1%BB%AB-spec\"\u003eAutonomous Coding Agent — AI tự viết code từ spec\u003c\/a\u003e\u003c\/li\u003e\n\u003c\/ul\u003e","brand":"Minh Tuấn","offers":[{"title":"Default Title","offer_id":66959029338157,"sku":null,"price":0.0,"currency_code":"VND","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0763\/9531\/5245\/files\/xay-d_ng-llm-agent-t_-d_u-reference-implementation.jpg?v=1782891895","url":"https:\/\/claudeae.com\/products\/xay-d%e1%bb%b1ng-llm-agent-t%e1%bb%ab-d%e1%ba%a7u-reference-implementation","provider":"Claude.vn","version":"1.0","type":"link"}