Chuyển đến nội dung chính

Hướng dẫn Claude Agent SDK: Tạo Agent với Claude Sonnet 4.5

Tìm hiểu cách hoạt động của Claude Agent SDK bằng cách xây dựng ba dự án, từ one-shot đến agent dùng công cụ tùy chỉnh.
Đã cập nhật 5 thg 10, 2026  · 9 phút đọc

Khám phá cùng AI

ChatGPTClaudePerplexity

Anthropic đã phát hành Claude Sonnet 4.5, một mô hình lập trình tối tân đang dẫn đầu các bảng xếp hạng và benchmark trong ngành. Điểm đặc biệt khiến bản phát hành này đáng chú ý là khả năng tích hợp mượt mà với các công cụ và framework. Từ tiện ích mở rộng VS Code và tính năng chỉnh sửa ngữ cảnh đến công cụ bộ nhớ, thực thi mã, và tạo tệp (bảng tính, trang trình chiếu, tài liệu). Thậm chí còn mở rộng sang những trải nghiệm mới với Claude for Chrome và Imagine with Claude.

Nhưng tâm điểm của lần ra mắt này là Claude Agent SDK hoàn toàn mới, được xây dựng trên Claude Code. SDK này giới thiệu một khung agent mạnh mẽ, cho phép nhà phát triển xây dựng, tùy biến và mở rộng năng lực của Claude theo những cách hoàn toàn mới.

Trong hướng dẫn này, chúng ta sẽ khám phá các điểm mới của Claude 4.5, thực hành với Claude Agent SDK, thiết lập cục bộ, và xây dựng ba dự án đơn giản để thấy tiềm năng của nó trong thực tế.

Có gì mới trong Claude 4.5?

Claude Sonnet 4.5 mang đến những nâng cấp năng lực lớn. Đây là mô hình lập trình tốt nhất thế giới, mạnh nhất cho việc xây dựng các agent phức tạp, và hiệu quả nhất trong các tác vụ sử dụng máy tính, với những cải thiện đáng kể về suy luận và toán học. Mô hình này đạt chuẩn tối tân trên benchmark SWE-bench Verified và đã được ghi nhận duy trì tập trung hơn 30 giờ cho các tác vụ phức tạp, nhiều bước. 

Trên bảng xếp hạng OSWorld, hiệu năng đã tăng lên 61,4%, từ mức 42,2% chỉ bốn tháng trước. Các chuyên gia trong tài chính, luật, y khoa và các lĩnh vực STEM ghi nhận sự cải thiện rõ rệt về kiến thức miền và khả năng suy luận.

Nguồn: Introducing Claude Sonnet 4.5 \ Anthropic

Ngoài ra, đây là mô hình tiên phong được căn chỉnh tốt nhất của Anthropic cho đến nay, thể hiện sự giảm thiểu xu nịnh, dối trá, hành vi tìm kiếm quyền lực, và khuyến khích ảo tưởng. Nó cũng có phòng thủ mạnh hơn trước prompt injection. Phát hành dưới các biện pháp bảo vệ ASL-3, các bộ phân loại nâng cấp nhằm lọc nội dung rủi ro cao đồng thời giảm đáng kể dương tính giả so với các bản trước. Chúng tôi cũng thấy một chế độ nhỏ hơn mới, bạn có thể đọc trong hướng dẫn về Claude Haiku 4.5.

Tìm hiểu Claude Agent SDK

Claude Agent SDK, trước đây gọi là Claude Code SDK, cung cấp một bộ công cụ giúp bạn xây dựng các agent đa năng, mạnh mẽ bằng chính framework vận hành Claude Code. 

Nguyên lý cốt lõi rất đơn giản: cấp cho Claude quyền truy cập máy tính. Với quyền truy cập terminal và hệ thống tệp, agent có thể tìm kiếm, viết, thực thi và lặp trên mã như một nhà phát triển. Các khả năng này vượt xa lập trình, bao gồm nghiên cứu chuyên sâu, tạo video, ghi chú, phân tích dữ liệu và hơn thế nữa. 

Claude Agent SDK phác thảo một vòng lặp agent có cấu trúc gồm bốn bước chính: thu thập ngữ cảnh, thực hiện hành động, xác minh công việc, và lặp lại.

Trong thực tế, hãy bắt đầu với tìm kiếm theo hướng agent để lấy ngữ cảnh và bổ sung tìm kiếm ngữ nghĩa khi bạn cần tốc độ. Hành động nên tập trung vào các công cụ tín hiệu cao, script bash và tích hợp với dịch vụ bên ngoài thông qua Model Context Protocol. 

Xác minh kết hợp kiểm tra theo quy tắc, phản hồi trực quan và hỗ trợ LLM tùy chọn. Nên tiếp tục lặp để tinh chỉnh hiệu năng, mở rộng công cụ và nâng cao khả năng tìm kiếm khi các tính năng phát triển.

Tính năng chính:

  1. SDK: TypeScript và Python cho backend web/Node.js và khoa học dữ liệu, với khái niệm dùng chung để đội nhóm có thể tái sử dụng mẫu trên nhiều stack.
  2. Chế độ: Streaming cho trải nghiệm tương tác, độ trễ thấp và single-shot cho các lượt chạy theo lô hoặc quyết định—chọn theo tác vụ để cân bằng tốc độ và kiểm soát.
  3. Quản lý ngữ cảnh: Nén tự động và kiểm soát ngữ cảnh cho phiên chạy dài để tránh tràn và giữ agent đi đúng hướng trong các phiên kéo dài.
  4. Tooling: Thao tác tệp tích hợp sẵn, thực thi mã và tìm kiếm web, cùng khả năng mở rộng cho công cụ và dữ liệu bên ngoài qua MCP.
  5. Quyền hạn: Kiểm soát năng lực chi tiết (ví dụ, cho phép/từ chối theo công cụ và chế độ chính sách) để giới hạn những gì agent có thể làm trong môi trường production.
  6. Sẵn sàng production: Xử lý lỗi tích hợp, quản lý phiên và giám sát, giúp bạn triển khai agent tin cậy với khả năng quan sát ngay từ ngày đầu.
  7. Tích hợp Claude: Bộ nhớ đệm prompt tự động và tối ưu hiệu năng để giảm độ trễ và chi phí trong khi cải thiện thông lượng.
  8. Xác thực: Dùng khóa API Claude hoặc định tuyến qua các nhà cung cấp như Amazon Bedrock và Google Vertex AI để phù hợp môi trường triển khai.
  9. System prompt: Định nghĩa vai trò, chuyên môn và rào chắn để định hình hành vi agent nhất quán qua tác vụ và phiên làm việc.
  10. Tích hợp (MCP): Kết nối công cụ tùy chỉnh, cơ sở dữ liệu và API qua giao thức mở Model Context Protocol, một tiêu chuẩn do Anthropic hậu thuẫn với SDK TypeScript chính thức và hệ sinh thái đang phát triển.

Bắt đầu với Claude Agent SDK trong Python

Trước khi xây dựng bất kỳ dự án nào, bạn cần chuẩn bị một số điều kiện tiên quyết, cài đặt Claude Code CLI, và Claude Agent SDK.

Điều kiện tiên quyết

  • Đảm bảo bạn có Python phiên bản 3.10 trở lên. 
  • Để dùng hiệu quả Claude Code CLI, bạn cũng cần cài Node.js phiên bản 18 trở lên và gói NPM.

Cài đặt Claude Code CLI

Trên Windows: 

Mở PowerShell và chạy lệnh sau để tải và cài đặt Claude Code:

irm https://claude.ai/install.ps1 | iex

Sau khi cài đặt, thêm C:\Users\<user>\.local\bin vào PATH của hệ thống. Khởi động lại PowerShell và bạn sẽ thấy Claude đang chạy.

Trên nền tảng khác:

Nếu bạn đã cài Node.js và NPM, hãy thử chạy lệnh sau trong terminal để cài Claude Code:

npm i -g @anthropic-ai/claude-code

Làm theo hướng dẫn để thiết lập biến môi trường để bạn có thể truy cập Claude Code chỉ bằng cách gõ “claude” trong terminal.

Thiết lập Claude Code

Sau khi cài Claude Code, mở bằng cách gõ “claude” trong terminal và đăng nhập. Nếu bạn có gói Claude Pro hoặc Max, chọn “Log in with your subscription account” để việc sử dụng tính vào gói của bạn.

Nếu bạn thích trả theo mức dùng, hãy xác thực bằng khóa API; thanh toán sẽ qua Anthropic Console. 

Cuối cùng, đặt chủ đề và tùy chọn giao diện/CLI để mọi thứ phù hợp quy trình làm việc của bạn ngay từ ngày đầu.

Tôi đã thiết lập Claude Code bằng khóa API. Bạn có thể xem phần cài đặt ở đây:

Claude Code set up

Cài đặt Claude Agent SDK

Đảm bảo đã cài Python, sau đó mở terminal. Để cài Claude Agent SDK, chạy:

pip install claude-agent-sdk

Lưu ý: Nếu bạn gặp lỗi CLINotFoundError, hãy đảm bảo bạn đã cài CLI ở trên và Claude có trong PATH.

Xây dựng dự án với Claude Agent SDK và Claude Sonnet 4.5

Giờ chúng ta sẽ xây dựng ba dự án đơn giản dùng Claude Agent SDK làm framework, Claude Code cho công cụ và sử dụng máy tính, và Claude Sonnet 4.5 làm mô hình AI.

  1. One-shot phác thảo blog: Truy vấn one-shot đơn giản cho thấy cách dùng cơ bản Claude Agent SDK không cần công cụ.
  2. InspireBot CLI: Dự án này kết hợp khả năng tìm kiếm web với công cụ dự phòng tùy chỉnh cho các câu trích dẫn truyền cảm hứng.
  3. Ứng dụng đa công cụ NoteSmith: Ứng dụng ghi chú toàn diện với nhiều công cụ, hook an toàn và theo dõi mức sử dụng.

Toàn bộ mã nguồn có tại kho GitHub: kingabzpro/claude-agent-projects

1. Phác thảo blog one-shot

Trong dự án này, chúng ta dùng hàm query() của SDK với Claude Sonnet 4.5 để tạo dàn ý blog. Đây là truy vấn one-shot trực diện cho thấy cách dùng cơ bản Claude Agent SDK không cần công cụ.

Mã gồm có: 

  1. Streaming bất đồng bộ: Dùng asyncio với iterator bất đồng bộ query() của SDK để xuất kết quả theo token không chặn.
  2. Prompt & tùy chọn: Định nghĩa PROMPT cho dàn ý blog và cấu hình model/persona qua ClaudeAgentOptions.
  3. Luồng thông điệp có kiểu: Lặp qua thông điệp; chỉ trích xuất nội dung AssistantMessage → TextBlock.
  4. Xuất theo thời gian thực: In văn bản khi đến (end="") để có giao diện console streaming gọn gàng.
  5. Xử lý kết quả: Bỏ qua ResultMessage, để luồng kết thúc tự nhiên.
  6. Điểm vào: Chạy mọi thứ với asyncio.run(main()) khi thực thi script.
  7. Tối giản & dễ tùy biến: Dễ thay model/prompt; script nhẹ, lý tưởng cho demo hoặc pipeline.

oneshot_outline.py:

import asyncio
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    AssistantMessage,
    TextBlock,
    ResultMessage,
)

PROMPT = """Create a crisp markdown outline (H2/H3 bullets) for a 500-word blog post:
Title: Why Sovereign AI Compute Matters in 2026
Audience: CTOs and Heads of AI
Tone: pragmatic, non-hype
Include: 3 buyer pains, 3 evaluation criteria, 1 closing CTA
"""

async def main():
    options = ClaudeAgentOptions(
        model="sonnet", 
        system_prompt="You are a precise technical copy strategist."
    )

    async for msg in query(prompt=PROMPT, options=options):
        if isinstance(msg, AssistantMessage):
            for block in msg.content:
                if isinstance(block, TextBlock):
                    print(block.text, end="")  # only the outline
        elif isinstance(msg, ResultMessage):
            pass  # let the iterator end naturally

if __name__ == "__main__":
    asyncio.run(main())

Chúng ta sẽ chạy script và lưu đầu ra thành tệp markdown. 

python oneshot_outline.py > outline.md 

Bạn có thể mở tệp markdown và thấy rằng nó đã tạo nội dung kỹ thuật phù hợp. 

Claude Agent SDK Blog Outline

Bạn có thể quay lại bảng điều khiển tại https://console.anthropic.com/usage để kiểm tra mức sử dụng. Như bạn thấy, mô hình đang dùng Claude Sonnet 4.5.

Claude Agent SDK Usage

2. InspireBot CLI

Trong dự án này, chúng ta xây dựng một trình tạo động lực thân thiện với terminal, stream các câu trích dẫn bằng Claude Sonnet 4.5. Nó thử WebSearch trước, rồi dự phòng sang công cụ tùy chỉnh inspire_me trả về trích dẫn ngẫu nhiên.

Mã gồm có:

  • Công cụ dự phòng tùy chỉnh: Định nghĩa inspire_me với các trích dẫn truyền cảm hứng định sẵn, đăng ký qua create_sdk_mcp_server.
  • Trợ giúp CLI: is_tty, typewrite, bold, faint thêm hiệu ứng gõ máy và kiểu chữ trong terminal.
  • Prompt & tùy chọn: Cấu hình với ClaudeAgentOptions, cho phép công cụ (WebSearch + inspire_me) và persona hệ thống “InspireBot.”
  • Gọi công cụ dạng stream: Lặp qua thông điệp, hiển thị việc dùng công cụ (ToolUseBlock), kết quả (ToolResultBlock), và đầu ra cuối (TextBlock).
  • Logic dự phòng: Nếu không có đầu ra hữu ích, sẽ mặc định dùng câu trích dẫn cục bộ ngẫu nhiên.
  • UX tương tác: Hiển thị đầu vào/kết quả công cụ dạng stream, sau đó animate câu truyền cảm hứng cuối bằng hiệu ứng gõ máy.

inspire_web.py:

import sys
import json
import asyncio
import random
import time
from typing import Any

from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    tool,
    create_sdk_mcp_server,
    AssistantMessage,
    TextBlock,
    ToolUseBlock,
    ToolResultBlock,
    ResultMessage,
)

# -------------------------
# Custom fallback tool
# -------------------------
QUOTES = [
    "Dream big, start small -- but start.",
    "Stay curious, stay humble, keep building.",
    "Every expert was once a beginner.",
    "Small wins stack into big victories.",
    "Consistency beats intensity when intensity is inconsistent.",
]

@tool("inspire_me", "Return a random motivational quote", {})
async def inspire_me(_: dict) -> dict:
    return {"content": [{"type": "text", "text": random.choice(QUOTES)}]}

UTILS = create_sdk_mcp_server("inspire_util", "1.0.0", [inspire_me])

# -------------------------
# Tiny terminal helpers
# -------------------------
def is_tty() -> bool:
    try:
        return sys.stdout.isatty()
    except Exception:
        return False

def typewrite(text: str, delay: float = 0.02) -> None:
    """Print with a typewriter effect if TTY; otherwise plain print."""
    if not is_tty():
        print(text)
        return
    for ch in text:
        print(ch, end="", flush=True)
        time.sleep(delay)
    print()

def faint(s: str) -> str:
    """Dim text if terminal supports ANSI."""
    return s if not is_tty() else f"\033[2m{s}\033[0m"

def bold(s: str) -> str:
    return s if not is_tty() else f"\033[1m{s}\033[0m"

# -------------------------
# Main
# -------------------------
async def main():
    topic = "engineering focus" if len(sys.argv) < 2 else " ".join(sys.argv[1:])

    options = ClaudeAgentOptions(
        model="sonnet",  # switch to "sonnet-4.5" if your CLI lists it
        system_prompt=(
            "You are InspireBot.\n"
            "- First, try WebSearch to find a short, uplifting quote relevant to the user's topic.\n"
            "- If WebSearch is unhelpful or no clear quote is found, call the custom 'inspire_me' tool.\n"
            "- Output ONE short line only. No preface, no commentary, <= 120 characters."
        ),
        allowed_tools=[
            "WebSearch",
            "mcp__inspire_util__inspire_me",
        ],
        mcp_servers={"inspire_util": UTILS},
    )

    prompt = (
        "Find a short, uplifting quote for today's inspiration. "
        f"Topic: {topic}. Prefer something crisp and modern.\n"
        "If search yields multiple options, pick the best single line."
    )

    final_line_parts: list[str] = []

    if is_tty():
        print(bold("🌐 InspireBot (WebSearch + fallback tool)"))
        print(faint("Tip: pass a custom topic:  python inspire_web_animated.py \"women in leadership\""))
        print()

    async for message in query(prompt=prompt, options=options):
        # Stream assistant messages for tool usage + final text
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, ToolUseBlock):
                    tool_name = block.name
                    tool_input = block.input or {}
                    print(f"{bold('🛠️  Tool used:')} {tool_name}")
                    print(f"{faint('   input:')} {json.dumps(tool_input, ensure_ascii=False)}")
                elif isinstance(block, ToolResultBlock):
                    # Show summarized tool result text if present
                    shown = False
                    if isinstance(block.content, list):
                        for part in block.content:
                            if isinstance(part, dict) and part.get("type") == "text":
                                text = (part.get("text") or "").strip()
                                if text:
                                    preview = text if len(text) <= 200 else (text[:197] + "...")
                                    print(f"{faint('   result:')} {preview}")
                                    shown = True
                                    break
                    if not shown:
                        print(f"{faint('   result:')} (no textual content)")
                elif isinstance(block, TextBlock):
                    # This should be the final "inspiration" line content
                    final_line_parts.append(block.text)

        elif isinstance(message, ResultMessage):
            # allow the iterator to finish naturally (no break)
            pass

    final_line = " ".join(part.strip() for part in final_line_parts).strip()
    if not final_line:
        final_line = random.choice(QUOTES)  # ultimate fallback, just in case

    # Animate the final line (typewriter), or plain if not a TTY
    typewrite(final_line, delay=0.02)

if __name__ == "__main__":
    asyncio.run(main())

Chúng ta sẽ chạy script với chủ đề mặc định bằng lệnh sau:  

python inspire_web.py

Như ta thấy, nó hiển thị các công cụ đã dùng, đầu vào cho các công cụ đó, rồi xuất ra một câu truyền cảm hứng.  

Hãy cung cấp cho script Python một chủ đề tùy chỉnh:  

python inspire_web.py "Sadness and Love"

Lệnh này trả về một câu trích dẫn truyền cảm hứng có chứa các từ khóa "love" và "sadness."

3. Ứng dụng đa công cụ NoteSmith

Trong dự án này, chúng ta xây dựng một trợ lý nghiên cứu đa công cụ có thể lưu và tìm kiếm ghi chú cục bộ, tóm tắt trang web và stream kết quả với Claude Sonnet 4.5. Nó kết hợp công cụ MCP tùy chỉnh, công cụ tích hợp sẵn và một safety hook để mang lại trải nghiệm CLI phong phú hơn.

Mã gồm có:

  • Lưu trữ cục bộ: Lưu ghi chú xuống đĩa kèm timestamp; hỗ trợ tìm kiếm không phân biệt hoa thường bằng grep đơn giản.
  • Công cụ MCP tùy chỉnh: save_note (lưu văn bản) và find_note (tìm kiếm ghi chú), đăng ký bằng create_sdk_mcp_server.
  • Safety hook: block_dangerous_bash chặn lệnh shell gây hại (ví dụ, rm -rf /) trước khi thực thi công cụ.
  • System prompt & lệnh: Định nghĩa /summarize, /note, /find, /help, /exit; prompt điều hướng việc dùng công cụ (WebFetch, save_note, find_note).
  • Tương tác streaming: Dùng ClaudeSDKClient để xử lý AssistantMessage, ToolUseBlock, ToolResultBlock, in văn bản và kết quả công cụ theo thời gian thực.
  • Theo dõi mức sử dụng: In chân trang với tên mô hình, token và chi phí ra stderr trong khi giữ đầu ra chính sạch sẽ.
  • Giao diện chat: Hoạt động như REPL gọn nhẹ nơi bạn gõ lệnh (/note, /find, /summarize) và nhận phản hồi tức thì, tạo cảm giác như đang trò chuyện với trợ lý.

note_smith.py:

import sys
import json
import asyncio
from datetime import datetime
from pathlib import Path
from typing import Any

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AssistantMessage,
    TextBlock,
    ToolUseBlock,
    ToolResultBlock,
    ResultMessage,
    tool,
    create_sdk_mcp_server,
    HookMatcher,
    HookContext,
)

# ----------------------------
# Storage (simple local notes)
# ----------------------------

NOTES_DIR = Path(__file__).parent / "notes"
NOTES_DIR.mkdir(exist_ok=True)

def _ts() -> str:
    return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

def save_note_to_disk(text: str) -> str:
    path = NOTES_DIR / f"note_{_ts()}.txt"
    path.write_text(text.strip() + "\n", encoding="utf-8")
    return str(path)

def grep_notes(pattern: str) -> list[str]:
    pat = pattern.lower()
    out: list[str] = []
    for p in NOTES_DIR.glob("*.txt"):
        for i, line in enumerate(p.read_text(encoding="utf-8").splitlines(), start=1):
            if pat in line.lower():
                out.append(f"{p.name}:{i}: {line}")
    return out

# ----------------------------
# Custom MCP tools
# ----------------------------

@tool("save_note", "Save a short note to local disk", {"text": str})
async def save_note(args: dict[str, Any]) -> dict[str, Any]:
    path = save_note_to_disk(args["text"])
    return {"content": [{"type": "text", "text": f"Saved note → {path}"}]}

@tool("find_note", "Find notes containing a pattern (case-insensitive)", {"pattern": str})
async def find_note(args: dict[str, Any]) -> dict[str, Any]:
    hits = grep_notes(args["pattern"])
    body = "\n".join(hits) if hits else "No matches."
    return {"content": [{"type": "text", "text": body}]}

UTILS_SERVER = create_sdk_mcp_server(
    name="notes_util",
    version="1.0.0",
    tools=[save_note, find_note],
)

# ----------------------------
# Optional safety hook (Bash)
# ----------------------------

async def block_dangerous_bash(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
):
    if input_data.get("tool_name") == "Bash":
        cmd = str(input_data.get("tool_input", {}).get("command", "")).strip().lower()
        if "rm -rf /" in cmd or "format c:" in cmd:
            return {
                "hookSpecificOutput": {
                    "hookEventName": "PreToolUse",
                    "permissionDecision": "deny",
                    "permissionDecisionReason": "Dangerous command blocked"
                }
            }
    return {}

# ----------------------------
# Prompts & UI
# ----------------------------

SYSTEM_PROMPT = """You are NoteSmith, a concise research assistant.
- Prefer bullet answers with crisp takeaways.
- When the user asks to /summarize <url>, use WebFetch to retrieve and then summarize 5 key points + a 1-line TL;DR.
- When the user types /note <text>, call the custom save_note tool.
- When the user types /find <pattern>, call the custom find_note tool.
- Keep answers short unless asked to expand.
"""

HELP = """Commands:
  /summarize <url>      Summarize a webpage (WebFetch)
  /note <text>          Save a note locally
  /find <pattern>       Search saved notes
  /help                 Show this help
  /exit                 Quit
"""

# Use the broadest model label for compatibility; switch to "sonnet-4.5" if your CLI lists it.
MODEL = "sonnet"

# ----------------------------
# Main app
# ----------------------------

async def main():
    options = ClaudeAgentOptions(
        model=MODEL,
        system_prompt=SYSTEM_PROMPT,
        permission_mode="acceptEdits",
        allowed_tools=[
            # Built-ins (Claude may use these if relevant)
            "WebFetch", "Read", "Write", "Grep", "Glob",
            # Our MCP tools (SDK prefixes mcp__<alias>__<toolname>)
            "mcp__utils__save_note",
            "mcp__utils__find_note",
        ],
        mcp_servers={"utils": UTILS_SERVER},
        hooks={"PreToolUse": [HookMatcher(hooks=[block_dangerous_bash])]},
        setting_sources=None,  # no filesystem settings; everything is programmatic
    )

    print("💡 NoteSmith (Claude Sonnet)\n")
    print(HELP)

    async with ClaudeSDKClient(options=options) as client:
        while True:
            user = input("\nYou: ").strip()
            if not user:
                continue
            if user.lower() in {"/exit", "exit", "quit"}:
                print("Bye!")
                break
            if user.lower() in {"/help", "help"}:
                print(HELP)
                continue

            # Lightweight command parsing (the system prompt also guides tool usage)
            if user.startswith("/summarize "):
                url = user.split(" ", 1)[1].strip()
                prompt = f"Summarize this URL using WebFetch and return 5 bullets + TL;DR:\n{url}"
            elif user.startswith("/note "):
                text = user.split(" ", 1)[1]
                prompt = f'Please call tool save_note with text="{text}"'
            elif user.startswith("/find "):
                patt = user.split(" ", 1)[1]
                prompt = f'Please call tool find_note with pattern="{patt}"'
            else:
                prompt = user

            await client.query(prompt)

            # -------- Response streaming with footer to STDERR --------
            model_used = None
            usage = None
            cost = None

            async for message in client.receive_response():
                if isinstance(message, AssistantMessage):
                    if model_used is None:
                        model_used = message.model  # e.g., "sonnet" or "sonnet-4.5"
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(block.text, end="", flush=True)  # stdout
                        elif isinstance(block, ToolUseBlock):
                            print(f"\n🛠️  Using tool: {block.name} with input: {json.dumps(block.input)}")
                        elif isinstance(block, ToolResultBlock):
                            if isinstance(block.content, list):
                                for part in block.content:
                                    if isinstance(part, dict) and part.get("type") == "text":
                                        print(f"\n🔎 Tool says: {part.get('text')}")
                elif isinstance(message, ResultMessage):
                    usage = message.usage or {}
                    cost = message.total_cost_usd
                    # Do not break early; let stream end naturally

            # Footer (model + tokens + cost) → STDERR so normal output stays clean
            def _token_summary(u: dict) -> str:
                total = u.get("total_tokens")
                if total is None:
                    it, ot = u.get("input_tokens"), u.get("output_tokens")
                    if it is not None or ot is not None:
                        total = (it or 0) + (ot or 0)
                if total is None:
                    return "tokens=?"
                if "input_tokens" in u or "output_tokens" in u:
                    return f"tokens={total} (in={u.get('input_tokens','?')}, out={u.get('output_tokens','?')})"
                return f"tokens={total}"

            footer = (
                f"\n\n-- Turn done. model={(model_used or options.model)} "
                f"{_token_summary(usage or {})} cost={cost if cost is not None else '?'} --"
            )
            print(footer, file=sys.stderr)

# Entry
if __name__ == "__main__":
    asyncio.run(main())

Để chạy ứng dụng, gõ lệnh sau trong terminal:

python note_smith.py

Lệnh này sẽ khởi động giao diện chat CLI với các lệnh hữu ích.

Trước tiên, hãy tóm tắt trang web. Tôi đã cung cấp URL trang portfolio của mình:

/summarize abid.work

Đầu tiên, agent sẽ xác định công cụ cần dùng, lấy nội dung từ trang, trích xuất năm điểm chính và hiển thị trong giao diện chat. Cuối cùng, nó sẽ hiển thị báo cáo sử dụng gồm tên mô hình, số token và chi phí.

I'll fetch and summarize the content from that URL for you.                                    
🛠️  Using tool: WebFetch with input: {"url": "https://abid.work", "prompt": "Extract the main content and key information from this page, including what the person does, their background, projects, and any notable achievements or areas of focus."}


**5 Key Points:**

• **Prolific Tech Educator** - Authored 500+ articles making data science & ML accessible through tutorials, cheat sheets, and practical guides

• **Certified Data Scientist** - Professional focus on building innovative machine learning solutions across NLP, computer vision, and MLOps

• **Multi-Domain Expertise** - Covers Python, SQL, AI, and end-to-end ML workflows with hands-on project demonstrations

• **Content-First Philosophy** - Maintains extensive portfolio including blogs, tutorials, book reviews, and career resources

• **Open Contributor** - Active on GitHub (kingabzpro) sharing code and projects with the community

**TL;DR:** Abid Ali Awan is a certified data scientist who's authored 500+ educational articles and tutorials, specializing in ML, NLP, and making complex tech concepts accessible to learners.

-- Turn done. model=claude-sonnet-4-5-20250929 tokens=326 (in=6, out=320) cost=0.062402849999999996 --

Tiếp theo, chúng ta lưu một ghi chú:

/note what is love

Chúng ta đã yêu cầu lưu ghi chú với nội dung “what is love”.

🛠️  Using tool: mcp__utils__save_note with input: {"text": "what is love"}


✓ Note saved: "what is love"

-- Turn done. model=claude-sonnet-4-5-20250929 tokens=81 (in=6, out=75) cost=0.07421549999999999 --

Cuối cùng, chúng ta sẽ tìm ghi chú bằng cách cung cấp một từ khóa trong ghi chú:

/find love

Như bạn thấy, nó đã tìm được tệp và hiển thị nội dung từ đó.

🛠️  Using tool: mcp__utils__find_note with input: {"pattern": "love"}


**Found 1 note matching "love":**

• `note_2025-09-30_17-18-02.txt` - "what is love"

-- Turn done. model=claude-sonnet-4-5-20250929 tokens=105 (in=6, out=99) cost=0.08423339999999999 --

Kết luận 

Claude Agent SDK rất dễ thiết lập, đặc biệt nếu bạn đã cài Claude Code cục bộ. Tất cả những gì cần là cài gói SDK. 

SDK Python cung cấp hai cách chính để tương tác với Claude:

  • query() – API tạo văn bản đơn giản, phù hợp các trường hợp nhẹ, dù không hỗ trợ công cụ.
  • ClaudeSDKClient – API agent đầy đủ tính năng cho phép tiếp tục phiên, dùng công cụ, duy trì kiểm soát thủ công, và hơn thế nữa.

Trong hướng dẫn này, chúng ta đã khám phá mô hình mới nhất của Anthropic, Claude Sonnet 4.5, và giới thiệu Claude Agent SDK mới. Chúng ta đã đi qua quá trình cài đặt và xây dựng ba dự án mẫu để minh họa khả năng của nó.

Nếu bạn quan tâm thử nghiệm quy trình làm việc theo hướng agent, tôi rất khuyến nghị dùng thử SDK này.


Abid Ali Awan's photo
Author
Abid Ali Awan
LinkedIn
Twitter

Là một nhà khoa học dữ liệu được chứng nhận, tôi đam mê tận dụng công nghệ tiên tiến để tạo ra các ứng dụng học máy đổi mới. Với nền tảng vững chắc về nhận dạng giọng nói, phân tích và báo cáo dữ liệu, MLOps, AI hội thoại và NLP, tôi đã rèn giũa kỹ năng phát triển các hệ thống thông minh có thể tạo ra tác động thực sự. Bên cạnh chuyên môn kỹ thuật, tôi cũng là một người truyền đạt tốt, có khả năng chắt lọc các khái niệm phức tạp thành ngôn ngữ rõ ràng, súc tích. Nhờ đó, tôi trở thành một blogger được nhiều người quan tâm trong lĩnh vực khoa học dữ liệu, chia sẻ góc nhìn và kinh nghiệm với cộng đồng các chuyên gia dữ liệu ngày càng lớn. Hiện tại, tôi tập trung vào sáng tạo và biên tập nội dung, làm việc với các mô hình ngôn ngữ lớn để phát triển nội dung mạnh mẽ và hấp dẫn, giúp doanh nghiệp và cá nhân tận dụng tối đa dữ liệu của mình.

Chủ đề
AI Agents
Mô hình Ngôn ngữ Lớn
Trí tuệ Nhân tạo
Liên quan

blog

Claude Opus 4.6: Tính năng, Điểm chuẩn, Bài kiểm tra thực hành và hơn thế nữa

Mô hình mới nhất của Anthropic dẫn đầu ở mã hóa tác tử và lập luận phức tạp. Thêm vào đó, nó có cửa sổ ngữ cảnh 1M.
Matt Crabtree's photo

Matt Crabtree

10 phút

Xem ThêmXem Thêm