Hoàn thành bài "Xây dựng MCP Server đầu tiên của bạn" trước để mở khoá bài này.Đến bài trước

Giới thiệu

MCP primitive là các đơn vị thiết kế chính kết nối ứng dụng AI với các khả năng và ngữ cảnh bên ngoài. Khi xây dựng MCP server, câu hỏi thiết kế cốt lõi không phải là nên cung cấp bao nhiêu endpoint. Vấn đề là quyết định mỗi khả năng nên được biểu diễn dưới dạng tool, resource hay prompt. Chọn sai primitive có thể khiến agent không an toàn, làm cho ngữ cảnh khó được khám phá hoặc buộc người dùng phải lặp lại hướng dẫn theo cách thủ công.

Ba primitive có các mô hình kiểm soát và tương tác khác nhau. Tools nhìn chung do model kiểm soát: agent có thể quyết định gọi chúng khi cần thực hiện một hành động hoặc phép tính. Resources nhìn chung do ứng dụng kiểm soát: ứng dụng host quyết định thời điểm truy xuất và cung cấp nội dung của chúng. Prompts nhìn chung do người dùng kiểm soát: người dùng chọn hoặc gọi một template tương tác có thể tái sử dụng. Đây là các quy ước thiết kế MCP phổ biến, không chỉ là những tên gọi khác nhau cho cùng một thao tác.

Bài học này đưa ra một phương pháp lựa chọn thực tiễn, các quy tắc thiết kế contract và một helper quyết định nhỏ. Mục tiêu là giúp việc lựa chọn primitive trở nên nhất quán trước khi bắt đầu triển khai.

Sơ đồ ba cột so sánh tools, resources và prompts của MCP, với các mũi tên luồng kiểm soát từ model đến tools, từ ứng dụng đến resources và từ người dùng đến prompts

Ba Primitive

Tool biểu diễn một thao tác mà model hoặc agent có thể yêu cầu. Thao tác này có thể đọc dữ liệu, biến đổi dữ liệu, gọi một service hoặc tạo ra tác động phụ. Ví dụ gồm tìm kiếm trong hệ thống ticket, tính phí vận chuyển, tạo hóa đơn nháp hoặc hủy đặt chỗ. Một tool nên có tên cụ thể, mô tả rõ ràng, schema đầu vào được xác định và đầu ra mà model có thể diễn giải.

Resource biểu diễn thông tin có thể định địa chỉ, được xác định bằng một URI. Nó phù hợp với tài liệu, cấu hình, bản ghi, schema, báo cáo hoặc ngữ cảnh khác mà ứng dụng có thể tải và cung cấp cho model. Resource có thể là tĩnh, chẳng hạn như tài liệu chính sách, hoặc động, chẳng hạn như bản ghi khách hàng có URI xác định một thực thể hiện tại. Việc đọc một resource nên được xem là truy xuất ngữ cảnh, không phải là chỉ thị thực hiện một hành động.

Prompt là một template tương tác có thể tái sử dụng và có mục đích xác định. Nó có thể định nghĩa các message được đề xuất, các đối số và cấu trúc dự kiến của một tác vụ. Ví dụ, một ứng dụng hỗ trợ khách hàng có thể cung cấp prompt để tóm tắt khiếu nại của khách hàng, trong khi một ứng dụng review code có thể cung cấp prompt để review một pull request. Prompt không thay thế cho tool và không nên che giấu một thao tác làm thay đổi trạng thái bên ngoài.

Chọn primitive phù hợp

Bắt đầu bằng việc xác định những gì người dùng hoặc agent cần nhận được. Nếu yêu cầu là một thao tác, phép tính, tra cứu có tham số hoặc tác động phụ ra bên ngoài, hãy bắt đầu bằng một tool. Việc một thao tác chỉ đọc dữ liệu không tự động khiến nó trở thành resource. Tìm kiếm có tham số đối với các đơn hàng hiện tại thường là một tool vì model yêu cầu thực hiện phép tính và nhận về kết quả dựa trên các đối số được cung cấp.

Chọn resource khi giá trị chính là ngữ cảnh có thể truy xuất và có danh tính ổn định. Một tài liệu như chính sách đổi trả, URI của bản ghi cơ sở dữ liệu hoặc báo cáo được tạo có thể được biểu diễn dưới dạng resource khi ứng dụng có thể quyết định thời điểm cần tải nó. Resource đặc biệt hữu ích khi người dùng cần duyệt, đính kèm, lưu vào bộ nhớ đệm, làm mới hoặc kiểm tra ngữ cảnh một cách độc lập với quyết định của agent.

Chọn prompt khi yêu cầu là đóng gói một mô hình hội thoại có thể lặp lại cho người dùng. Một prompt có thể hướng dẫn model cách sử dụng ngữ cảnh hiện có, nhưng không nên giả vờ là một thao tác nghiệp vụ có thể thực thi. Nếu yêu cầu là “hãy giúp tôi chuẩn bị yêu cầu hoàn tiền”, prompt có thể cấu trúc cuộc hội thoại. Nếu yêu cầu là “thực hiện hoàn tiền”, một tool phải thực hiện thao tác đã được cấp quyền.

Một phép thử hữu ích là hoàn thành câu “Ai khởi tạo tương tác này?”. Nếu model nên quyết định thời điểm gọi một thao tác, hãy dùng tool. Nếu ứng dụng host nên truy xuất hoặc đính kèm thông tin, hãy dùng resource. Nếu người dùng nên chọn một quy trình đã được chuẩn bị, hãy dùng prompt. Một số quy trình thực sự có thể sử dụng cả ba primitive theo trình tự.

Thiết kế contract vững chắc

Một contract tốt cho tool sẽ giảm thiểu sự mơ hồ. Tên của tool nên mô tả thao tác, không phải cách triển khai. Phần mô tả nên nêu rõ khi nào nên sử dụng, khi nào không nên sử dụng, tool yêu cầu những quyền gì và các ràng buộc quan trọng nào được áp dụng. Các trường đầu vào nên có kiểu dữ liệu rõ ràng, mô tả có ý nghĩa, quy tắc xác thực và các giá trị được giới hạn trong phạm vi có thể. Một tool chấp nhận một object dạng tự do cho mọi yêu cầu sẽ khiến cả model lẫn server khó phát hiện lỗi hơn.

Đầu ra của tool nên phân biệt dữ liệu thành công với thông tin lỗi. Hãy trả về kết quả có cấu trúc khi client cần kiểm tra các trường bằng chương trình, đồng thời thêm nội dung ngắn gọn, dễ đọc khi kết quả sẽ được hiển thị cho model hoặc người dùng. Không báo cáo thành công chỉ vì một yêu cầu đã đến được server. Với các tool tạo tác động phụ, kết quả phải làm rõ thao tác đã được hoàn tất, bị từ chối, hoàn tất một phần hay chỉ mới được chuẩn bị dưới dạng bản nháp.

Thiết kế resource phụ thuộc vào các mã định danh ổn định và nội dung có thể dự đoán. Hãy sử dụng các URI xác định đối tượng miền hoặc tài liệu mà không nhúng những chi tiết triển khai ngẫu nhiên. Quyết định xem resource là bất biến, có thể làm mới hay được quản lý theo phiên bản, đồng thời mô tả cách xử lý nội dung lỗi thời. Resource chứa dữ liệu nhạy cảm cũng cần có chính sách ủy quyền; URI là mã định danh, không phải quyền đọc dữ liệu bên dưới.

Thiết kế prompt chỉ nên đưa ra các đối số mà người dùng hoặc ứng dụng có thể cung cấp một cách hợp lý. Phần mô tả prompt nên nêu rõ kết quả mong muốn và ngữ cảnh bắt buộc. Hãy tách biệt hướng dẫn vận hành khỏi dữ liệu người dùng và tránh nhúng các khẳng định mà model phải coi là có thẩm quyền, trừ khi ứng dụng có thể duy trì tính chính xác của chúng. Prompt có thể đề xuất một lần gọi tool, nhưng việc cấp quyền và xác thực phải vẫn nằm ở các lớp tool và server.

Ví dụ minh họa

Hãy hình dung một ứng dụng hỗ trợ khách hàng với ba yêu cầu. Ứng dụng phải tìm các đơn hàng đang mở của khách hàng, cung cấp chính sách đổi trả hiện tại và hướng dẫn agent trong một cuộc hội thoại về việc đổi trả. Yêu cầu đầu tiên là một thao tác tra cứu có tham số trên hệ thống đang hoạt động, nên phù hợp với tool. Yêu cầu thứ hai là một tài liệu có thể định địa chỉ mà ứng dụng có thể tải khi cần, nên phù hợp với resource. Yêu cầu thứ ba là một mô hình hội thoại có thể lặp lại do người dùng lựa chọn, nên phù hợp với prompt.

Trình trợ giúp JavaScript cục bộ sau đây thể hiện quy tắc ra quyết định đó. Đây không phải là một máy chủ MCP và không thay thế việc đăng ký giao thức. Mục đích của nó là làm cho các buổi rà soát thiết kế trở nên rõ ràng trước khi triển khai. Kết quả bao gồm primitive được chọn và lý do hỗ trợ cho lựa chọn đó.

javascript
function chooseMcpPrimitive(requirement) {
const text = requirement.toLowerCase();
if (text.includes("perform") || text.includes("create") || text.includes("update") ||
text.includes("delete") || text.includes("search") || text.includes("calculate") ||
text.includes("send") || text.includes("live")) {
return {
primitive: "tool",
reason: "The requirement describes an operation, computation, parameterized lookup, or side effect."
};
}
if (text.includes("document") || text.includes("policy") || text.includes("record") ||
text.includes("report") || text.includes("read") || text.includes("context")) {
return {
primitive: "resource",
reason: "The requirement describes addressable information that an application can retrieve and attach as context."
};
}
if (text.includes("guide") || text.includes("workflow") || text.includes("template") ||
text.includes("conversation") || text.includes("summarize")) {
return {
primitive: "prompt",
reason: "The requirement describes a reusable interaction pattern selected by a user or application."
};
}
return {
primitive: "review",
reason: "The requirement does not provide enough information to distinguish action, context, and interaction template."
};
}
console.log(chooseMcpPrimitive("search live open orders for a customer"));
console.log(chooseMcpPrimitive("read the current return policy document"));
console.log(chooseMcpPrimitive("guide an agent through a return conversation"));

Lần gọi đầu tiên sẽ tạo ra quyết định về tool, lần gọi thứ hai là quyết định về resource, và lần gọi thứ ba là quyết định về prompt. Trình trợ giúp này cố ý thận trọng trước những điểm mơ hồ. Một buổi rà soát thiết kế thực tế nên kiểm tra việc ủy quyền, độ mới của dữ liệu, quyền kiểm soát của người dùng và liệu thao tác có tác dụng phụ hay không trước khi đăng ký bất kỳ thành phần nào.

Các lỗi thường gặp

Một lỗi phổ biến là đưa mọi capability ra dưới dạng tool vì agent có thể dễ dàng gọi tool. Điều này tạo ra một danh mục tool quá lớn và khuyến khích model truy xuất tài liệu thông qua các thao tác vốn nên được duyệt hoặc do ứng dụng kiểm soát. Hãy tách ngữ cảnh truy xuất khỏi các hành động, đặc biệt khi ngữ cảnh ổn định và có thể được lưu vào bộ nhớ đệm.

Một lỗi khác là viết mô tả tool quá mơ hồ. Một tên như process_request không cho model biết liệu nó tìm kiếm, phê duyệt, gửi hay xóa nội dung nào đó. Mô tả không rõ ràng làm tăng số lần gọi sai và khiến việc rà soát ủy quyền trở nên khó khăn. Hãy nêu trực tiếp thao tác, các input bắt buộc, những trường hợp loại trừ quan trọng và hành vi có tác dụng phụ.

Một resource cũng có thể được thiết kế không chính xác nếu URI của nó làm lộ thông tin bí mật, phụ thuộc vào các chi tiết nội bộ không ổn định của cơ sở dữ liệu hoặc ngụ ý quyền truy cập mà không thực thi quyền đó. Hãy sử dụng các định danh không mang ngữ nghĩa khi phù hợp, xác thực quyền ủy quyền ở mỗi lần đọc và xác định cách báo cáo nội dung bị thiếu, đã cũ hoặc không khả dụng. Đối với prompt, tránh xem prompt như một ranh giới bảo mật. Các chỉ dẫn bên trong prompt không thể thay thế việc xác thực phía máy chủ.

Cuối cùng, đừng cho rằng việc kết hợp các primitive sẽ tự động tạo ra một workflow tốt. Hãy kiểm tra xem host có cung cấp resource đúng thời điểm hay không, người dùng có thể hiểu các đối số của prompt hay không và tool có từ chối các request sai định dạng hoặc không được ủy quyền hay không. Khả năng quan sát nên ghi lại tên primitive, kết quả xác thực, kết quả ủy quyền và nhóm lỗi mà không ghi log các giá trị nhạy cảm một cách không cần thiết.

Tóm tắt

Tool dành cho các thao tác, phép tính, truy vấn có tham số và các tác dụng phụ. Resource dành cho thông tin có thể định địa chỉ mà ứng dụng có thể truy xuất và cung cấp làm ngữ cảnh. Prompt dành cho các mẫu tương tác có thể tái sử dụng mà người dùng có thể chọn hoặc gọi. Điểm khác biệt giữa chúng liên quan đến cả hình dạng dữ liệu và quyền sở hữu việc kiểm soát.

Một quy trình thiết kế đáng tin cậy bắt đầu từ yêu cầu, xác định ai khởi tạo tương tác, kiểm tra xem kết quả là một hành động hay ngữ cảnh, sau đó định nghĩa một contract có phạm vi hẹp. Với mỗi primitive, phần mô tả, schema, quyền, lỗi và cách xử lý độ mới của dữ liệu cần được nêu rõ.

Khi một workflow liên quan đến nhiều mối quan tâm, hãy kết hợp các primitive một cách có chủ đích. Người dùng có thể chọn một prompt, ứng dụng có thể đính kèm một resource và model có thể gọi một tool. Việc duy trì sự tách biệt giữa các trách nhiệm này tạo ra hành vi rõ ràng hơn, cơ chế ủy quyền an toàn hơn và các tích hợp MCP dễ kiểm thử, bảo trì hơn.

Luyện tập sau buổi học

Bài kiểm tra cuối bài

Ôn lại kiến thức, thử sức và nhận góp ý cho bài làm.

0/1
Đã trả lời · 0/1