- Thiết kế sản phẩm cho các tác nhân AI đòi hỏi một cách tiếp cận khác biệt đáng kể so với thiết kế cho con người, do những hạn chế cố hữu của AI trong các khía cạnh như khám phá, lặp lại và ngữ cảnh.
- Nhiều máy chủ MCP hiện tại được xem là chưa tốt vì chúng thường chỉ là lớp wrapper đơn giản, thiếu tư duy sản phẩm phù hợp để tối ưu hóa cho cách các tác nhân AI thực sự tương tác và xử lý thông tin.
- Nguyên tắc cốt lõi cho các nhà phát triển MCP là "curate" (chọn lọc, sắp xếp) các giao diện, tập trung vào "kết quả chứ không phải thao tác" để tạo ra các công cụ hiệu quả hơn cho tác nhân.
Your MCP Server is Bad (and you should feel bad) - Jeremiah Lowin, Prefect
- AI Agents require tailored interfaces: Unlike humans who use products (websites, SDKs, apps), AI agents need their own optimized interfaces, as they interact with APIs in fundamentally different ways.
- Costly Discovery for AI: AI agents find discovery (enumerating tools, reading descriptions) expensive and token-consuming because it often re-occurs with each invocation, whereas humans perform it once.
- Slow Iteration for AI: Iteration is a major bottleneck for AI agents; each additional call may resend the entire history, making repeated attempts slow and costly in terms of tokens and time.
- Limited Context for AI: LLMs have very small "brains" with limited context windows (e.g., 200,000 tokens), making them unable to retain information across long interactions like humans.
- "Curate" is Key for MCP Design: The most important concept for MCP developers is to "curate" information and interfaces, presenting a problem/solution to AI agents in a controlled and optimized manner.
- Focus on Outcomes, Not Operations: When designing LLM servers/tools, prioritize the desired end "outcome" for the agent rather than exposing raw "operations" (sequential API calls) which AI struggles to orchestrate efficiently.
- Need for Best Practices: There's a critical need for documented best practices for LLM/Agent product design, similar to established human UI/UX guidelines, to improve the quality of agentic products.
- MCP as a Standard Interface: MCP provides a standard way to deliver information to agents controllably, aiming to optimize how tools are discovered and executed, despite current client implementation challenges.
- Tác nhân AI — AI Agent
- Thiết kế sản phẩm tác nhân — Agentic Product Design
- Mã thông báo — Token
- Ngữ cảnh — Context
- Mô hình ngôn ngữ lớn (LLM) — Large Language Model (LLM)
- Thực tiễn tốt nhất — Best Practices
- Kết quả chứ không phải thao tác — Outcomes not Operations
- Orchestration — Điều phối/Điều hành
- Trải nghiệm nhà phát triển — Developer Experience (DX)
- Giao diện cấp cao / Nguyên thủy cấp thấp — High-level interface / Low-level primitives
Bài nói chuyện này trình bày những kiến thức sâu sắc về thiết kế sản phẩm dành cho các Tác nhân AI, tập trung vào sự khác biệt giữa cách con người và Tác nhân tương tác với API và các công cụ.
Giới thiệu và Kinh nghiệm Cá nhân
Tôi thực sự đánh giá cao cơ hội này. Tôi sẽ cố gắng trình bày nội dung này một cách phổ quát nhất có thể. Chúng ta sẽ không có phần tương tác; thay vào đó, chúng ta sẽ cùng nhau thảo luận. Tôi sẵn lòng đi chệch khỏi kịch bản, và tôi sẵn lòng trả lời các câu hỏi. Nếu có điều gì chúng ta muốn khám phá tại bất kỳ thời điểm nào, mục tiêu của tôi là chia sẻ với các bạn rất nhiều điều tôi đã học được. Tôi sẽ cố gắng biến chúng thành những thông tin có tính ứng dụng cao nhất có thể, để có những điều thực tế để thực hiện ở đây, nhiều hơn so với một bài nói chuyện cấp cao hơn. Nhưng hãy thành thật mà nói: đã muộn rồi, có rất nhiều điều để nói, và đây sẽ là một buổi khá dài. Hãy cùng nói về MCP. Tôi hy vọng rằng các bạn ở đây đều quan tâm đến MCP. Đó là lý do bạn đến với bài nói chuyện này. Nếu bạn đến đây để tìm hiểu về MCP, cách tiếp cận này có thể sẽ hơi khác một chút. Xin hãy giơ tay: Ai đã từng nghe nói về MCP? Ai đã sử dụng MCP? Ai đã viết một máy chủ MCP? Được rồi. Có ai cảm thấy không thoải mái với MCP không? Hoàn toàn không sao cả; chúng ta có thể điều chỉnh. Được rồi, vậy thì, hãy bắt đầu thôi. Hãy đi sâu vào vấn đề.
Đây là tôi. Tôi là nhà sáng lập và Giám đốc điều hành của một công ty tên là Prefect Technologies trong bảy hoặc tám năm qua. Chúng tôi đã xây dựng phần mềm tự động hóa dữ liệu và phần mềm orchestration. Trước đó, tôi là thành viên của Apache Airflow PMC. Ban đầu, tôi bắt đầu Prefect để đưa những ý tưởng orchestration tương tự vào khoa học dữ liệu. Ngày nay, chúng tôi vận hành toàn bộ full stack. Sau đó vài năm, tôi đã phát triển một khung làm việc tác nhân gọi là Marvin, mà tôi sẽ không mô tả là cực kỳ phổ biến, nhưng đó là bước chân của tôi vào thế giới AI, ít nhất là từ góc độ trải nghiệm nhà phát triển, và tôi đã học được rất nhiều từ đó. Gần đây hơn, tôi đã giới thiệu một phần mềm có tên là Fast MCP, vốn đã trở nên cực kỳ, cực kỳ phổ biến, thậm chí có thể là quá phổ biến. Do đó, tôi có mặt ở đây hôm nay. Tôi hơi choáng ngợp. Tôi thấy mình lại trở về vị trí duy trì mã nguồn mở, một vị trí mà tôi đã không đảm nhiệm trong vài năm, điều này cũng khá thú vị. Nhưng điều quan trọng nhất là Fast MCP đã mang lại cho tôi một góc nhìn rất đặc biệt, vốn là cơ sở cho bài nói chuyện này hôm nay.
Đây là số lượt tải xuống của chúng tôi. Tôi chưa từng thấy điều gì như thế này. Tôi chưa từng làm việc trên một dự án nào như thế này. Nó đã được tải xuống một triệu rưỡi lần chỉ riêng ngày hôm qua. Có rất nhiều máy chủ MCP ngoài kia. Fast MCP đã trở thành cách thức tiêu chuẩn trên thực tế để xây dựng máy chủ MCP. Tôi đã giới thiệu nó gần như chính xác một năm trước, như nhiều bạn có lẽ đã biết, bản thân MCP cũng được giới thiệu gần như chính xác một năm trước. Vài ngày sau đó, tôi đã giới thiệu phiên bản đầu tiên của Fast MCP. David từ Anthropic đã gọi cho tôi, nói rằng "Tôi nghĩ điều này thật tuyệt vời. Tôi nghĩ rằng nhiều người nên xây dựng máy chủ." Chúng tôi đã đưa một phiên bản của nó vào SDK chính thức, điều này thật tuyệt vời. Và sau đó, khi MCP phát triển bùng nổ trong năm qua, chúng tôi nhận thấy việc định vị Fast MCP (mà tôi đang duy trì) như một giao diện cấp cao (high-level interface) cho hệ sinh thái MCP, trong khi SDK tập trung vào các nguyên thủy cấp thấp (low-level primitives), là hữu ích. Và trên thực tế, chúng tôi sẽ loại bỏ thuật ngữ Fast MCP khỏi SDK cấp thấp trong vài tháng tới. Nó đã trở nên hơi, hơi khó hiểu, nhưng có hai thứ này gọi là Fast MCP. Vì vậy, Fast MCP sẽ là một giao diện cấp cao cho thế giới.
Thực trạng Máy chủ MCP và Mục tiêu Bài nói chuyện
Kết quả là, chúng tôi thấy rất nhiều máy chủ MCP không tốt. Tôi đã đặt tên cho bài nói chuyện này theo một meme và sau đó tôi tự hỏi, liệu mọi người có còn biết meme này là gì nữa không? Đối với tôi, nó rất hài hước và rất thời sự. Nó xuất phát từ một tập phim Futurama năm 1999. Vì vậy, nếu bạn chưa xem, tiêu đề bài nói chuyện của tôi không có ý xấu. Tôi là một người khá lạc quan. Tôi chọn cách diễn giải điều này như là "những gì bạn có thể làm tốt hơn". Và vì vậy, chúng ta sẽ tìm cách để làm tốt hơn. Đó là mục tiêu của bài nói chuyện hôm nay. Trên thực tế, nói chính xác hơn, điều tôi muốn làm hôm nay là thực sự xây dựng một trực giác cho thiết kế sản phẩm tác nhân (agentic product design). Tôi không thấy điều này được thảo luận nhiều như lẽ ra phải có, với số lượng Tác nhân đang được sử dụng trong bao nhiêu sản phẩm ngày nay. Và ý tôi là điều này hoàn toàn tương tự như việc tôi sẽ nói chuyện về cách xây dựng một sản phẩm tốt cho người dùng, cho con người. Khi đó, chúng ta sẽ nói về các nguyên tắc giao diện người dùng (human interface guidelines), về trải nghiệm người dùng (user experience), và về các câu chuyện người dùng (user stories). Tôi thấy rất hữu ích khi bắt đầu nói về những điều đó từ góc độ tác nhân, bởi vì một máy chủ MCP không là gì khác ngoài một giao diện (interface) cho một Tác nhân. Và chúng ta nên thiết kế nó phù hợp với điểm mạnh và điểm yếu của những Tác nhân đó, giống như cách chúng ta làm với mọi thứ khác.
Sự Khác biệt: AI và Con người Tương tác với API
Khi tôi đưa ra ý tưởng này, tôi rất, rất, rất thường xuyên nhận được phản hồi trái chiều này: "Nếu con người có thể sử dụng một API, tại sao AI lại không thể?" Và có rất nhiều điều sai trong câu hỏi này. Điều sai số một trong câu hỏi này là nó chứa một giả định mà tôi thấy rất nhiều trong thiết kế sản phẩm AI (AI product design), và nó khiến tôi phát điên, đó là AI hoàn hảo, hoặc chúng là những nhà tiên tri, hoặc chúng giỏi mọi thứ. Chúng thực sự là những công cụ rất, rất, rất mạnh mẽ. Nhưng tôi cho rằng, dựa trên phản hồi của các bạn trước đó, tôi nghĩ mọi người trong căn phòng này đều đã có những trải nghiệm không mấy dễ chịu về việc chúng có thể sai lầm, hoặc chúng bị hạn chế, hoặc chúng không hoàn hảo. Vì vậy, tôi không thích câu hỏi này bởi vì nó giả định rằng chúng siêu phàm một cách thần kỳ trong mọi việc.
Nhưng tôi thực sự không thích câu hỏi này. Đây là một câu hỏi nhỏ mà tôi đã nhận được. Tôi không diễn giải lại. Tôi thực sự không thích câu hỏi này vì con người không sử dụng API. Rất, rất hiếm khi con người sử dụng API. Con người sử dụng sản phẩm. Chúng ta làm mọi cách để đặt một thứ gì đó ở giữa chúng ta và một API. Chúng ta xây dựng một website. Chúng ta xây dựng một SDK. Chúng ta xây dựng một client. Chúng ta xây dựng một ứng dụng di động (mobile app). Chúng ta không thích sử dụng API trừ khi chúng ta buộc phải làm vậy hoặc chúng ta là người chịu trách nhiệm xây dựng giao diện đó. Và vì vậy, một trong những lập luận cốt lõi của tôi, và lý do tôi yêu MCP rất nhiều, là tôi tin rằng các Tác nhân xứng đáng có giao diện riêng của chúng, được tối ưu hóa cho chúng và trường hợp sử dụng (use case) của chúng. Và để thiết kế giao diện đó, điều mà tôi muốn trình bày hôm nay, chúng ta phải suy nghĩ một chút về sự khác biệt giữa con người và AI. Và đây là một trong những câu hỏi nghe có vẻ thực sự ngớ ngẩn khi bạn nói ra thành tiếng, nhưng lại rất hữu ích khi thực sự xem xét.
Ba Yếu tố khác biệt chính: Khám phá, Lặp lại và Ngữ cảnh
Và tôi muốn lập luận với bạn rằng sự khác biệt này tồn tại ở ba khía cạnh: khám phá (discovery), lặp lại (iteration) và ngữ cảnh (context). Để bắt đầu, đối với con người, chúng ta thấy việc khám phá rất rẻ. Chúng ta có xu hướng thực hiện nó chỉ một lần. Nếu bạn nghĩ về việc bất kỳ ai trong số các bạn đã phải triển khai một cái gì đó dựa trên một REST API, bạn làm gì? Bạn truy cập tài liệu hoặc Swagger hay bất cứ thứ gì. Bạn xem nó. Bạn xem nó một lần, bạn tìm ra những gì bạn cần. Bạn sẽ không bao giờ làm lại điều đó. Và vì vậy, mặc dù bạn có thể mất một thời gian để thực hiện việc khám phá, nhưng nó rẻ trong vòng đời của ứng dụng (application) mà bạn đang xây dựng. AI thì không hẳn như vậy. Mỗi lần AI khởi động, nó "bắt tay" với một máy chủ, nó tìm hiểu về máy chủ, nó liệt kê từng công cụ và từng mô tả trên máy chủ đó. Vì vậy, việc khám phá thực sự rất tốn kém đối với các Tác nhân. Nó tiêu thụ rất nhiều mã thông báo.
Tiếp theo là lặp lại (iteration). Tương tự. Nếu bạn là một nhà phát triển (developer) và bạn đang viết mã dựa trên một API, bạn có thể lặp lại rất nhanh. Tại sao? Bởi vì bạn thực hiện khám phá một lần, bạn tìm ra ba đường dẫn (routes) bạn sẽ gọi và sau đó bạn viết một script để gọi chúng liên tiếp nhanh nhất có thể theo ngôn ngữ của bạn. Vì vậy, việc lặp lại rất rẻ. Nó nhanh. Đối với các Tác nhân, tôi nghĩ tất cả chúng ta đều biết việc lặp lại rất chậm. Lặp lại là kẻ thù. Mỗi lời gọi (call) bổ sung, tùy thuộc vào cài đặt bộ nhớ đệm (caching setup) của bạn, cũng gửi toàn bộ lịch sử của tất cả các lời gọi trước đó qua mạng. Nghĩa là, bạn không muốn lặp lại nếu có thể tránh được. Vì vậy, đó sẽ là một điều quan trọng mà chúng ta cần xem xét.
Và điều cuối cùng là về ngữ cảnh. Điều này hơi chung chung, nhưng nó quan trọng. Với tư cách là con người, trong cuộc trò chuyện này, tôi đang nói, bạn đang nghe tôi và bạn đang so sánh điều này với những ký ức khác nhau bạn có và những kinh nghiệm khác nhau bạn có trên các thang thời gian (time scales) khác nhau. Và tất cả đều đang thực hiện những điều tuyệt vời, đáng kinh ngạc trong não bạn. Và khi bạn kết nối một Mô hình ngôn ngữ lớn (LLM) vào bất kỳ trường hợp sử dụng (use case) nào, nó chỉ nhớ 200.000 mã thông báo cuối cùng mà nó nhìn thấy. Và đó là giới hạn bộ nhớ (memory) của nó cộng với bất cứ điều gì được nhúng (embedded) đâu đó trong các trọng số (weights) của nó. Và chỉ vậy thôi. Và vì vậy, chúng ta cần phải rất, rất, rất ý thức về thực tế rằng nó có một bộ não (brain) rất nhỏ vào thời điểm này. Tôi nghĩ nó giống hơn nhiều khi mọi người nói về việc đưa Apollo 11 lên mặt trăng và với một kilobyte RAM hoặc bất cứ điều gì đó. Tôi nghĩ đó thực sự là cách chúng ta cần suy nghĩ về những điều mà thành thật mà nói, cảm thấy khá kỳ diệu bởi vì chúng có thể mở các PR (Pull Requests) cho tôi hoặc bất cứ điều gì chúng làm. Vì vậy, đây là ba khía cạnh chính trong tâm trí tôi về sự khác biệt. Và chúng ta không nên xây dựng các API tốt cho con người trên bất kỳ khía cạnh nào trong số này và giả vờ rằng chúng cũng tốt cho các Tác nhân.
Tầm quan trọng của "Curate" và Mục đích của MCP
Và một cách mà tôi bắt đầu nói về điều này là ý tưởng rằng một Tác nhân có thể tìm thấy một cây kim trong đống cỏ khô. Vấn đề là nó sẽ xem xét từng cọng cỏ và quyết định xem nó có phải là kim hay không. Điều đó không hoàn toàn đúng theo nghĩa đen, nhưng theo một cách trực quan, đó là cách chúng ta nên suy nghĩ về những gì chúng ta đặt trước các Tác nhân và cách chúng ta đặt ra một vấn đề. Và một máy chủ MCP không là gì khác ngoài một giao diện cho vấn đề đó và/hoặc giải pháp. Và vì vậy, cuối cùng, để quay lại tuyên bố về trực giác sản phẩm của chúng ta, tôi đã lập luận với bạn rằng từ quan trọng nhất trong vũ trụ đối với các nhà phát triển MCP là curate. Làm thế nào để bạn curate từ một lượng lớn thông tin, vốn có thể dễ hiểu đối với một nhà phát triển con người, một giao diện phù hợp cho một trong những Tác nhân AI cực kỳ hạn chế này, ít nhất là trên các khía cạnh mà chúng ta vừa xem xét.
Và điều đó dẫn chúng ta đến slide này: YMPP (Why MCP?). Và tôi gần như đã làm điều này giống như slide Derek Zoulander "Why MCP?", nhưng tôi vừa nói với bạn "Why MCP", Derek, đó là bởi vì nó làm tất cả những điều này. Nó cung cấp cho chúng ta một cách tiêu chuẩn để truyền thông tin đến các Tác nhân một cách có thể kiểm soát, nơi chúng ta có thể kiểm soát không chỉ cách nó được khám phá mà còn cả cách nó được thực hiện. Có một dấu hoa thị lớn (big asterisk) ở đó bởi vì các triển khai client (client implementations) trong không gian MCP hiện tại không tuyệt vời. Và chúng làm một số điều mà bản thân chúng không tuân thủ đặc tả MCP (MCP spec). Có lẽ cuối cùng chúng ta sẽ đi sâu vào điều đó. Nó không liên quan trực tiếp đến bây giờ, ngoại trừ việc tất cả những gì chúng ta có thể làm là cố gắng xây dựng các máy chủ tốt nhất có thể tùy thuộc vào các giới hạn của các client sẽ sử dụng chúng. Và một lần nữa, tôi đưa điều này vào đây. Tôi nghĩ chúng ta không cần phải đi qua MCP là gì cho đối tượng này. Vì vậy, chúng ta sẽ lướt nhanh qua điều này, nhưng tất nhiên là vì mục đích của bản transcript. Câu nói sáo rỗng là nó giống như USB-C cho internet. Đó là một cách tiêu chuẩn để kết nối Mô hình ngôn ngữ lớn (LLM) với các công cụ hoặc dữ liệu.
Và nếu bạn chưa từng thấy Fast MCP, đây là cách nó trông như thế nào khi xây dựng một máy chủ MCP đầy đủ chức năng. Cái này tôi sống ở Washington, DC. Tàu điện ngầm ở đó thường xuyên bốc cháy. Và vì vậy cái này kiểm tra xem tàu điện ngầm có đang bốc cháy hay không. Và thực sự là có. Bây giờ, câu hỏi mà chúng ta thực sự ở đây để khám phá là tại sao lại có quá nhiều máy chủ MCP tồi tệ? Có lẽ một câu hỏi tốt hơn là tất cả các bạn có đồng ý với tôi rằng có nhiều máy chủ MCP tồi tệ không? Tôi có vẻ như tuyên bố điều này như thể nó là sự thật. Tôi không cố gắng đưa ra một tuyên bố gây tranh cãi. Có rất nhiều máy chủ MCP tồi tệ trên thế giới. Tôi thấy rất nhiều trong số chúng bởi vì mọi người đang sử dụng khung làm việc của tôi để xây dựng chúng. Điều đó có làm ai ngạc nhiên không khi tôi có vẻ như tuyên bố điều đó. Tôi thực sự tò mò liệu đó có phải là tôi đã đưa ra một giả định sai không. Tôi không nghĩ kinh nghiệm của tôi với mọi MCP mà tôi cung cấp công cụ là như vậy. Nhưng tôi biết rằng chúng giống như ABA wrapper. Họ chỉ đặt cái đó vào như thể họ muốn ABA và thế là xong. Và thế là xong. Họ gọi đó là một MCP. Vâng. Và tôi nghĩ ngay cả tôi cũng sẽ đưa ra những lập luận hơi ngoài phạm vi nhưng tôi sẽ lập luận rằng rất nhiều trong số chúng, ngay cả khi chúng không phải là wrapper, chỉ là những sản phẩm tồi tệ vì không có sự cân nhắc nào được đưa vào chúng.
Tầm quan trọng của Thực tiễn Tốt nhất (Best Practices)
Một so sánh mà tôi thường nói chuyện với nhóm của mình là: nếu bạn truy cập một trang web tồi, bạn biết ngay đó là một trang web tồi. Chúng ta không cần phải ngồi đó để tìm hiểu tại sao nó xấu, khó sử dụng, khó tìm kiếm thứ bạn cần, hay chỉ toàn là hiệu ứng flash. Tôi không biết chính xác điều gì tạo nên một trang web tồi, nhưng bạn nhận ra ngay khi truy cập. Chúng ta không thích chỉ ra tất cả những lỗi lầm vì chúng có vô số; thay vào đó, chúng ta cố gắng tìm những ví dụ tuyệt vời về các trang web tốt. Và vì vậy, điều tôi nghĩ chúng ta cần hơn bất cứ thứ gì khác chính là các thực tiễn tốt nhất (best practices) cho LLM. Một trong những ưu tiên lớn của tôi hiện tại và là lý do ra đời bài nói chuyện này là tôi muốn đảm bảo rằng chúng ta có càng nhiều best practices được tài liệu hóa càng tốt.
Tôi muốn khen ngợi một vài công ty. Đây là ảnh chụp màn hình từ Block, họ có một playbook tuyệt vời mà nếu bạn không thích bài nói chuyện này, hãy đọc bài blog của họ. Nó giống như một phiên bản tốt hơn của những gì tôi đang làm bây giờ. Và GitHub gần đây cũng đã phát hành một cái, cùng với nhiều công ty khác. Tôi có thể đưa ra nhiều ví dụ ở đây, nhưng đây là hai tài liệu tôi thường xuyên tham khảo và tôi khuyên bạn nên đọc chúng. Nhóm Block đặc biệt xuất sắc trong những gì họ đang làm về LLM. Thật trùng hợp, cùng một nhóm này đã là khách hàng của tôi trong sáu năm về mảng dữ liệu, và tôi thực sự yêu thích công việc họ làm. Bài blog mà họ đưa ra rất sâu sắc và tôi đặc biệt khuyên bạn nên đọc chúng. Tôi muốn thấy nhiều hơn nữa những nỗ lực như thế này, và hôm nay là một trong những cố gắng khiêm tốn của tôi để đưa một phần trong số đó ra thế giới.
Từ Thao tác đến Kết quả: Tư duy sản phẩm cho Máy chủ LLM
Hôm nay, tôi nghĩ chúng ta sẽ cùng nhau khắc phục một máy chủ thông qua các slide, thay vì yêu cầu bạn mở máy tính xách tay, thiết lập environment và viết mã với tôi vì bây giờ là 4:25 chiều thứ Bảy. Điều này sẽ là một cách tiếp cận nhẹ nhàng và hy vọng mang lại tính khả thi.
Đây là máy chủ mà bạn đã mô tả một lúc trước, phải không? Ai đó đã viết máy chủ này. Tôi hy vọng cú pháp đủ rõ ràng cho mọi người: chúng ta có một decorator nói rằng một hàm là một tool, và sau đó là chính tool đó. Tha thứ cho tôi, tôi không muốn làm bạn nhàm chán với các chi tiết vì chúng ta nghĩ đây là một máy chủ tồi ngay từ đầu.
Trong máy chủ này, ví dụ của chúng ta là gì? Chúng ta muốn kiểm tra trạng thái đơn hàng. Để kiểm tra trạng thái đơn hàng, chúng ta cần tìm hiểu rất nhiều điều về người dùng và đơn hàng của họ, chúng ta cần lọc chúng, chúng ta cần thực sự kiểm tra trạng thái. Và nếu đây là một REST API (mà có lẽ là vậy), chúng ta biết chính xác mình sẽ làm gì: chúng ta sẽ thực hiện một cuộc gọi đến từng hàm theo một trình tự và trả về kết quả đó dưới dạng một đầu ra cho người dùng. Nó sẽ dễ dàng, có thể quan sát được (observable), nhanh chóng và có thể kiểm thử được (testable). Mọi thứ sẽ tốt đẹp.
Nhưng thay vào đó, nếu chúng ta để một Agent tiếp cận điều này, nó sẽ gọi các hàm này theo thứ tự nào? Nó có biết định dạng của các đối số (argument) không? Sẽ mất bao lâu cho ít nhất ba lượt đi lại (round trip) mà điều này yêu cầu? Đây là tất cả các vấn đề mà chúng ta đang gặp phải chỉ bằng cách nhìn vào nó. Chúng ta không giải quyết chúng, nhưng đó là những vấn đề tôi thấy nếu tôi đang xem xét điều này như một nỗ lực hướng tới sản phẩm.
Vì vậy, điều đầu tiên chúng ta sẽ nghĩ đến – và tôi nghĩ đây có lẽ là điều quan trọng nhất khi chúng ta nghĩ về một máy chủ LLM hiệu quả, bởi vì đó là tư duy sản phẩm – là kết quả chứ không phải thao tác (outcomes not operations). Chúng ta muốn đạt được điều gì? Điều này đôi khi hơi khó chịu đối với các kỹ sư vì nó buộc phải tư duy sản phẩm. Không phải ai đó đưa ra một user story và phác thảo mọi thứ, nói rằng "chúng ta cần triển khai điều này". Chúng ta không thể đưa một thứ gì đó vào máy chủ này trừ khi chúng ta biết chắc chắn nó sẽ hữu ích và mang lại kết quả tốt. Chúng ta phải bắt đầu từ đó. Không có đủ context để chúng ta có thể tùy tiện.
Đây là cảm giác khi bạn rơi vào cái bẫy đó: bạn có một loạt các thao tác nguyên tử (atomic operations). Điều này thật tuyệt vời nếu bạn đang xây dựng một REST API – đó là best practice nếu bạn đang xây dựng một REST API. Nhưng nó tệ nếu bạn đang xây dựng một máy chủ LLM. Thay vào đó, chúng ta muốn những thứ như "theo dõi đơn hàng mới nhất" và "gửi email". Rất khó để làm hỏng và bạn biết kết quả là gì khi bạn gọi nó.
Phiên bản khác của cái bẫy là Agent làm "chất keo" (agent as glue) hoặc Agent làm "điều phối viên" (agent as orchestrator). Xin hãy tin tôi, vì tôi đã dành cả sự nghiệp để xây dựng phần mềm orchestration và tự động hóa: có những thứ thực sự giỏi trong việc orchestration và có những thứ thực sự tệ trong việc orchestration. Agent nằm ngay giữa vì chúng có thể làm được, nhưng nó tốn kém, chậm chạp, gây khó chịu và khó gỡ lỗi. Đó là gánh nặng. Vì vậy, nếu bạn có thể tránh được điều đó, xin hãy làm. Nếu không thể, có những lúc bạn không biết thuật toán và bạn không biết cách viết mã, và nó không mang tính lập trình. Đó là thời điểm hoàn hảo để sử dụng một LLM như một điều phối viên. Tìm hiểu trạng thái đơn hàng là một thời điểm thực sự tệ, rất tốn kém để chọn sử dụng một LLM làm dịch vụ orchestration của bạn.
Vì vậy, đừng làm vậy. Thay vào đó, hãy tập trung vào câu chuyện "một tool bằng một agent". Và một lần nữa, ngay cả ở đây, chúng ta đang cố gắng giới thiệu một từ vựng mới: đó không phải là user story, bởi vì user story khiến mọi người nghĩ về con người, mặc dù không phải vậy. Đó là một agent story – một điều gì đó mà một Agent tự động, có lập trình, với một mục tiêu và cửa sổ ngữ cảnh hạn chế, đang cố gắng đạt được. Và chúng ta cần đáp ứng điều đó nhiều nhất có thể.
Và đây là một trong những mẹo nhỏ có vẻ hiển nhiên nhưng tôi nghĩ rất quan trọng: hãy đặt tên tool cho Agent, đừng đặt tên cho bạn. Nó không phải là một REST API. Nó không nhằm mục đích rõ ràng cho các nhà phát triển tương lai cần viết mã. Bạn không viết một API để thay đổi. Bạn viết một API để Agent chọn đúng tool vào đúng thời điểm. Đừng ngại sử dụng những cái tên có vẻ ngớ ngẩn nhưng mang tính giải thích cho tool của bạn. Tôi không nên nói là ngớ ngẩn; chúng có thể cảm thấy hơi ngớ ngẩn, nhưng chúng rất hướng tới người dùng trong khoảnh khắc này, mặc dù cảm giác như một API sâu sắc.
Chỉ trong trường hợp bất kỳ ai trong số các bạn chưa đọc bài blog của Block, tôi thấy phần này của nó rất quan trọng, nơi họ về cơ bản nói điều gì đó rất giống nhau: "Thiết kế từ trên xuống theo luồng công việc (workflow), không phải từ dưới lên từ các API endpoint." Hai cách khác nhau để đến cùng một nơi, nhưng chúng sẽ dẫn đến những hình thức tư duy sản phẩm rất khác nhau và các máy chủ LLM rất khác nhau. Vì vậy, một lần nữa, tôi thực sự khuyến khích bạn đọc bài blog đó.
Và nếu chúng ta quay lại ví dụ mã tệ mà tôi đã cho bạn xem một lúc trước và bắt đầu viết lại nó (nếu có máy tính xách tay, bạn có thể theo dõi, mã về cơ bản sẽ chạy nhưng không cần thiết), đây là những gì nó có thể trông giống như. Chúng ta đã làm điều mà một con người sẽ làm: chúng ta thực hiện ba cuộc gọi theo trình tự được cấu hình tới API của chúng ta, nhưng chúng ta đã ẩn chúng trong một tool hướng tới Agent. Và đó là cách chúng ta chuyển từ thao tác sang kết quả. Các cuộc gọi API vẫn phải xảy ra, không có phép thuật nào ở đây, nhưng câu hỏi là: chúng ta sẽ yêu cầu Agent tìm ra kết quả và cách ghép chúng lại với nhau để đạt được nó, hay chúng ta sẽ chỉ làm điều đó vì chúng ta biết cách làm thay mặt cho nó?
Đơn giản hóa đối số (Argument Flattening)
Điều thứ nhất là kết quả hơn thao tác. Điều thứ hai – thực tế, rất nhiều điều này sẽ có vẻ hơi ngớ ngẩn khi tôi nói ra. Xin hãy tin tôi từ biểu đồ tải xuống, đây là những điều quan trọng nhất mà tôi có thể đưa ra làm lời khuyên. Và nếu không có lời khuyên nào trong số đó áp dụng cho bạn, hãy nghĩ mình thuộc top 1% các nhà phát triển LLM.
Đơn giản hóa đối số của bạn (flatten your arguments). Tôi thấy điều này rất thường xuyên, tôi cũng làm điều này, tôi sẽ thú nhận với bạn, khi bạn nói: "Đây là tool của tôi và một trong những đầu vào là một từ điển cấu hình (configuration dictionary)." Hy vọng rằng nó được ghi lại ở đâu đó, có thể trong hướng dẫn của Agent hoặc trong docstring. Bạn sẽ gặp vấn đề thực sự khi (nhân tiện, tôi không nhớ liệu tôi có điểm này sau không, nên tôi sẽ nói ngay bây giờ) một cái bẫy rất thường xuyên mà bạn có thể mắc phải với các đối số phức tạp là bạn sẽ đặt giải thích cách sử dụng chúng vào một thứ gì đó như system prompt hoặc định nghĩa subagent hoặc tương tự. Và sau đó bạn sẽ thay đổi tool trong máy chủ, và bây giờ bạn thậm chí còn tệ hơn một tool được ghi lại kém: bạn có một tool được ghi lại gấp đôi, và một cái sai, một cái đúng, và chỉ có thông báo lỗi mới có thể cứu bạn. Điều đó thực sự tệ.
Đây là một phiên bản nhẹ nhàng hơn của điều đó: đừng yêu cầu LLM của bạn phát minh ra các đối số phức tạp. Bây giờ bạn có thể hỏi: "Nếu đó là mô hình Pydantic với mọi trường được chú thích thì sao?" Tốt thôi, điều đó tốt hơn từ điển, nhưng nó vẫn sẽ khó. Cho đến gần đây, có thể vẫn có một lỗi (có thể không phải là lỗi, không ai có vẻ sửa nó) nhưng trong Claude Desktop, tất cả các đối số có cấu trúc, như đối số đối tượng, sẽ được gửi dưới dạng chuỗi (string). Và điều này đã tạo ra một vấn đề thực sự vì chúng tôi không muốn hỗ trợ chuyển đổi chuỗi tự động sang đối tượng. Nhưng Claude Desktop là một trong những LLM client phổ biến nhất, vì vậy chúng tôi thực sự phải nhượng bộ điều này như một sự cần thiết. Và vì vậy Fast LLM bây giờ sẽ thử, nếu bạn đang cung cấp một đối số chuỗi cho một thứ gì đó rõ ràng là một đối tượng có cấu trúc, nó sẽ cố gắng giải tuần tự (deserialize) nó. Nó sẽ cố gắng làm điều đúng đắn. Tôi thực sự ghét việc chúng tôi phải làm điều đó; điều đó cảm thấy rất sai với tôi khi chúng tôi có một sơ đồ kiểu (type schema) nói rằng "Tôi cần một đối tượng" nhưng chúng tôi lại làm những việc cẩu thả như vậy. Và đây là một ví dụ về một hệ sinh thái đang phát triển, nó hơi lộn xộn.
Nhưng trông như thế nào khi bạn làm đúng? Nâng cấp các kiểu nguyên thủy (up-level primitives). Đây là các đối số đưa vào hàm: limit là gì, status là gì, email là gì? Được định nghĩa rõ ràng, giống như đặt tên tool cho Agent, hãy đặt tên đối số cho Agent.
Và đây là hình ảnh khi chúng ta đưa điều đó vào mã: thay vì có config: dict, chúng ta có email là một chuỗi, chúng ta có include_cancelled là một cờ. Và sau đó tôi đặc biệt khuyên dùng literals hoặc enums bất cứ khi nào bạn có thể. Tốt hơn nhiều so với một chuỗi nếu bạn biết các tùy chọn tại thời điểm này. Rất ít LLM biết rằng loại cú pháp này được hỗ trợ, và vì vậy chúng thường sẽ viết điều này (nếu bạn có Claude Code hoặc tương tự) nó thường sẽ viết format: string = basic (điều này hoạt động, nó chỉ không biết cách làm điều này). Vì vậy, đó là một trong những mẹo nhỏ có thể thực hiện được: sử dụng literal hoặc enum một cách tương đương khi bạn có một lựa chọn bị giới hạn. Agent của bạn sẽ cảm ơn bạn.
Hướng dẫn và Ví dụ cho Tác nhân
Tôi có hướng dẫn hoặc context nên tôi đã đi trước bản thân, xin lỗi mọi người, bây giờ là 4:35 chiều thứ Bảy. Điều tiếp theo tôi muốn nói đến là các hướng dẫn bạn cung cấp cho Agent. Điều này có hai mặt. Cách hiển nhiên nhất là khi bạn không có gì. Chúng ta đã đề cập điều đó một lúc trước: nếu bạn không nói cho Agent cách sử dụng máy chủ LLM của bạn, nó sẽ đoán, nó sẽ thử, nó có thể sẽ tự làm mình bối rối, và tất cả những phỏng đoán đó sẽ hiển thị trong lịch sử của nó và đó không phải là một kết quả tốt.
Xin hãy tài liệu hóa máy chủ LLM của bạn. Tài liệu hóa chính máy chủ, tài liệu hóa tất cả các tool trên đó, đưa ra các ví dụ. Các ví dụ là một con dao hai lưỡi. Một mặt, chúng cực kỳ hữu ích để chỉ cho Agent cách nó nên sử dụng một tool. Mặt khác, nó gần như luôn luôn sẽ làm bất cứ điều gì có trong ví dụ. Đây chỉ là một trong những quirks, có lẽ khi các mô hình được cải thiện, nó sẽ ngừng làm điều đó. Nhưng theo kinh nghiệm của tôi, nếu bạn có một ví dụ, giả sử bạn có một trường cho tags (thẻ), bạn muốn thu thập các tags cho một cái gì đó. Nếu ví dụ của bạn có hai tags, bạn sẽ không bao giờ nhận được 10 tags. Bạn sẽ nhận được hai tags gần như mọi lúc. Chúng sẽ chính xác, nó sẽ không làm việc tệ, nhưng nó thực sự sử dụng các ví dụ đó cho nhiều chiều hơn là chỉ thực tế là chúng hoạt động, nếu điều đó có ý nghĩa. Vì vậy, hãy sử dụng ví dụ, nhưng hãy cẩn thận với các ví dụ của bạn. Vâng, thưa ngài, bạn đang cho.
Sức mạnh của Ví dụ và Hiện tượng Out of Distribution
Hiện tượng các ví dụ out of distribution là một cách để giải quyết vấn đề. Khi tôi nói out of distribution, ý tôi là những ví dụ không được đại diện trong dữ liệu thực tế. Điều này rất thú vị và tôi không có một ý kiến mạnh mẽ nào về nó; nó có vẻ hoàn toàn hợp lý đối với tôi.
Trong kinh nghiệm của tôi, việc một ví dụ có một mẫu ngầm định nào đó, như số lượng đối tượng trong một array, đã trở thành một tín hiệu mạnh mẽ đến mức tôi gần như coi nó là một điểm riêng, gọi là "ví dụ là hợp đồng". Nếu bạn cung cấp một ví dụ, hãy mong đợi nhận được một cái gì đó tương tự. Out of distribution là một cách thực sự thú vị để chống lại sự "quán tính" đó. Tôi hình dung rằng làm theo cách đó sẽ tốt hơn, nhưng tôi sẽ cẩn thận để không rơi vào cái bẫy lớp cơ sở hơn này.
Điều đó hoàn toàn hợp lý và tôi sẽ tán thành. Tôi nghĩ đây chỉ là một điều rộng hơn: bất kỳ ví dụ nào bạn đưa ra, những đặc điểm kỳ lạ của nó sẽ xuất hiện. Trên một máy chủ mcp mà tôi đang xây dựng, tôi đã gặp phải vấn đề về thẻ này chỉ hôm qua và nó thực sự làm tôi bối rối. Dù tôi có cố gắng sử dụng ít nhất 10 thẻ, nó luôn chỉ trả về hai. Cuối cùng tôi đã tìm ra là do một trong những ví dụ của tôi chỉ có hai thẻ. Vì vậy, vâng, đó là một chiến lược tốt, có thể đủ hoặc không đủ để vượt qua những cảnh báo cơ bản này. Tôi xin lỗi, tôi có đề cập đến "ví dụ là hợp đồng" ở mục 37.
Lỗi là Lời nhắc (Errors are Prompts)
Điều này, tôi nghĩ, là một trong những điều thú vị nhất trên slide này: lỗi là lời nhắc. Mọi phản hồi mà công cụ của bạn đưa ra, Mô hình ngôn ngữ lớn (LLM) của bạn không biết rằng nó "xấu". Nó không giống như nhận được lỗi 400 hay 500. Thay vào đó, nó nhận được những gì nó xem là thông tin về việc nó không thành công trong những gì nó đang cố gắng làm.
Vì vậy, nếu bạn chỉ cho phép Python, trong trường hợp fast mcp hoặc bất kỳ công cụ nào bạn chọn, để báo lỗi ví dụ như empty value error hoặc cryptic mcp error với mã số nguyên, đó là thông tin được gửi trở lại LLM của bạn. Và liệu nó có biết phải làm gì với thông tin đó hay không? Có lẽ nó biết ít nhất là thử lại vì nó biết đó là lỗi. Nhưng bạn thực sự có cơ hội để tài liệu hóa API của mình thông qua các lỗi.
Điều này dẫn đến một số chiến lược thú vị mà tôi không muốn hoàn toàn tán thành nhưng sẽ đề cập đến, chẳng hạn như, nếu bạn có một API phức tạp (bởi vì bạn không thể tránh khỏi điều đó), thay vì tài liệu hóa mọi khả năng trong chuỗi doc string mô tả toàn bộ công cụ, bạn thực sự có thể tài liệu hóa cách khôi phục từ những lỗi phổ biến nhất.
Đây là một hình thức tiết lộ thông tin dần dần rất kỳ lạ (progressive disclosure), nơi bạn thừa nhận rằng có khả năng tác nhân này sẽ thực hiện lệnh gọi đầu tiên sai, nhưng dựa trên cách nó sai, bạn thực sự có cơ hội gửi thêm thông tin trở lại trong thông báo lỗi. Như tôi đã nói, đây không phải là một cách tuyệt vời để nghĩ về việc xây dựng phần mềm, nhưng nó là phiên bản cuối cùng của những gì tôi đang đề xuất: hãy hữu ích nhất có thể trong các thông báo lỗi của bạn. Đừng quá đà. Chúng trở thành một phần của lời nhắc tiếp theo đối với tác nhân. Và vì vậy, chúng thực sự quan trọng. Nếu chúng quá mạnh tay hoặc quá đáng sợ, nó có thể vĩnh viễn tránh công cụ đó, nó có thể quyết định công cụ đó không thể hoạt động. Vì vậy, lỗi thực sự quan trọng, và tôi không nghĩ điều này cần quá nhiều lời giải thích, nhưng đây là những gì nó trông giống như khi bạn có một doc string đầy đủ và một ví dụ, v.v.
Gợi ý Read Only cho Công cụ
Block trong bài đăng blog của họ đưa ra một điểm mà tôi chưa thấy được sử dụng rộng rãi, mặc dù ChatGPT có tận dụng điều này trong chế độ nhà phát triển, đó là gợi ý read only. Đặc tả mcp có hỗ trợ annotations, là một tập hợp con hạn chế của annotations mà bạn có thể đặt trên các thành phần khác nhau. Một trong số đó dành cho công cụ là liệu nó có phải là read only hay không, và nếu bạn cung cấp tùy chọn này, các client có thể chọn xử lý công cụ đó hơi khác một chút.
Vì vậy, động lực đằng sau gợi ý read only về cơ bản là để giúp thiết lập permissions. Và tôi không biết ai ở đây là fan của --yolo hoặc --dangerous-disabled-permissions hoặc bất cứ tên gọi nào của chúng trong các thiết bị đầu cuối khác nhau, nhưng nếu bạn không quan tâm đến điều này thì thôi. Nhưng ví dụ, ChatGPT sẽ yêu cầu bạn cấp thêm permission nếu một công cụ không có annotation này, bởi vì nó cho rằng công cụ đó có thể tạo ra tác dụng phụ và có thể có ảnh hưởng bất lợi. Vì vậy, hãy sử dụng những điều này để tận dụng lợi thế của bạn; đó là một hình thức thiết kế khác mà client có thể chọn để cung cấp trải nghiệm nhà phát triển tốt hơn.
Tôn trọng Ngân sách Mã thông báo (Token Budget)
Tôi đã nói về điều này một chút rồi: tôn trọng ngân sách mã thông báo. Tôi nghĩ hiện tại, câu chuyện vui là máy chủ GitHub gửi khoảng 200.000 mã thông báo khi bạn thực hiện handshake với nó. Đây là một vấn đề thực tế, và tôi không nghĩ nó tự động làm cho máy chủ GitHub trở nên tệ. Tôi nghĩ nó thực sự khiến những người như tôi, những người xây dựng framework, và những người xây dựng client phải tìm cách giải quyết vấn đề này, bởi vì câu trả lời không phải lúc nào cũng là "làm ít hơn". Trên thực tế, hiện tại chúng ta muốn làm nhiều hơn; chúng ta muốn có rất nhiều chức năng. Và vì vậy, chúng ta sẽ nói về điều đó có thể sau một chút, nhưng sự tôn trọng ngân sách mã thông báo thực sự quan trọng. Đó là một tài nguyên rất khan hiếm và máy chủ của bạn không phải là máy chủ duy nhất mà tác nhân sẽ nói chuyện cùng.
Gần đây tôi có một cuộc gọi với một khách hàng của mình, họ rất vui mừng vì đang triển khai mcp. Tôi đã gặp đội ngũ kỹ thuật, và để rõ ràng, đây là một công ty lớn, có tầm nhìn xa, hiệu suất cao mà tôi vô cùng kính trọng. Tôi sẽ không nói họ là ai nhưng tôi thực sự tôn trọng họ. Họ tham gia cuộc gọi và rất hào hứng, họ nói: "Chúng tôi đang trong quá trình chuyển đổi mọi thứ sang mcp để có thể sử dụng nó." Và họ có một lập luận mạnh mẽ rằng tại sao nó thực sự phải là API của họ (đó thậm chí không phải là điểm mấu chốt của câu chuyện này, bản thân nó là một câu chuyện hoàn toàn khác). Nhưng về cơ bản, vấn đề nằm ở đây: họ có 800 endpoints phải được phơi bày.
Và tôi đã có suy nghĩ này: vào thời điểm bạn đọc xong điều này, đây chính là ngân sách mã thông báo cho mỗi trong số 800 công cụ đó nếu bạn giả định 200.000 mã thông báo trong cửa sổ ngữ cảnh. Vì vậy, nếu mỗi trong số 800 công cụ đó chỉ có bấy nhiêu không gian để tự tài liệu hóa (thậm chí không phải tự tài liệu hóa, mà là chia sẻ schema, chia sẻ tên cộng với tài liệu), đây là lượng không gian bạn sẽ có. Và khi bạn hoàn thành việc sử dụng không gian này, bởi vì bạn rất cẩn thận và mỗi công cụ thực sự vừa vặn trong đó, bạn sẽ "phẫu thuật thùy não" tác nhân trong quá trình handshake bởi vì nó sẽ không còn chỗ cho bất cứ thứ gì khác. Vì vậy, ngân sách mã thông báo thực sự quan trọng. Nếu tác nhân này kết nối với một máy chủ chỉ có thêm một công cụ với một doc string một từ, nó sẽ thất bại. Nó sẽ gặp lỗi tràn (overflow) hiệu quả.
Vì vậy, ngân sách mã thông báo rất quan trọng. Có lẽ có một ngân sách phù hợp cho bất kỳ công việc nào bạn đang làm. Bạn có thể biết nó là gì, bạn có thể không biết nó là gì. Hãy giả vờ bạn biết nó là gì và lưu tâm đến nó. Trong trường hợp xấu nhất, hãy cố gắng tiết kiệm, cố gắng hiệu quả nhất có thể. Đó là lý do tại sao chúng ta thực hiện các thử nghiệm như gửi thêm hướng dẫn trong thông báo lỗi; đó là một cách để tiết kiệm ngân sách mã thông báo khi handshake. Và handshake rất "đau đớn". Tôi không chắc mọi người có biết rằng khi một LLM kết nối với một máy chủ mcp, nó thường tải xuống tất cả các mô tả cùng một lúc để nó biết những gì có sẵn cho nó, và điều đó thường không được thực hiện theo cách tiết lộ dần dần (progressively disclosed) mà được thực hiện hoàn toàn ngay lập tức. Vâng, hoàn toàn chính xác.
Thách thức về Tuân thủ Spec và Meta Tools
Được rồi, vậy điều đó thật tuyệt vời. Hãy nói về ý tưởng này một chút vì nó là một thiết kế thực sự thú vị. Hiện tại có một cuộc tranh luận về những gì bạn có thể làm tuân thủ spec so với những gì bạn làm không tuân thủ spec. Và miễn là bạn làm những điều tuân thủ spec thì cứ làm chúng thôi, ai quan tâm chứ?
Một trong những vấn đề là có những client không tuân thủ spec. Claude Desktop là một trong số đó. Tôi đã đề cập đến nó vài lần. Tôi có một lịch sử với Claude Desktop. Claude Desktop caches tất cả các công cụ nó nhận được trong lần tiếp xúc đầu tiên và đặt chúng vào một cơ sở dữ liệu SQLite. Nó không quan tâm bạn làm gì; nó không quan tâm đến việc spec cho phép bạn gửi thêm thông tin. Tôi nghĩ giải pháp của bạn sẽ vượt qua điều này vì nó là một gọi công cụ (tool call), nhưng nhiều nỗ lực đầu tiên mà mọi người sử dụng các kỹ thuật tuân thủ spec để giải quyết vấn đề này, chẳng hạn như thông báo, đều thất bại trong Claude Desktop. Thường thì bạn đã thất bại trước điều này trong Claude Desktop.
Tôi không phải là fan của Claude Desktop cho máy chủ mcp. Tôi nghĩ đó là một cơ hội bị bỏ lỡ thực sự vì nó là một sản phẩm chủ lực của công ty đã giới thiệu mcp. Tôi nghĩ đó là một cơ hội bị bỏ lỡ thực sự. Claude Code thì tuyệt vời. Nó caches mọi thứ trong cơ sở dữ liệu SQLite nên nó không thành vấn đề bạn làm gì.
Các kỹ thuật tương tự như những gì bạn đã mô tả, nơi bạn cung cấp các cơ chế để tìm hiểu thêm về một công cụ, đó là một ý tưởng tuyệt vời. Tôi thực sự thích điều đó. Có một thách thức là bây giờ bạn trở lại trong một thế giới arguments phẳng vì bạn có meta tools nơi tôi cần sử dụng công cụ để tìm hiểu về công cụ và sử dụng công cụ để gọi công cụ trong một số trường hợp cực đoan hoặc hơn thế nữa. Vì vậy, bạn cần thiết kế điều này rất cẩn thận. Đó là lý do tại sao nó thường xuất hiện như một sản phẩm chuyên dụng. Cảm ơn bạn đã chia sẻ rằng có nhiều kỹ thuật thực sự thú vị để cố gắng giải quyết vấn đề này.
Tiết lộ Dần dần (Progressive Disclosure) và Tối ưu hóa Token Budget
Bạn nói về tiết lộ dần dần (progressive disclosure) hoặc nói về các "cổng" (gates). Chẳng hạn, tôi kết nối với máy chủ trusted endpoints của mình và thông tin credentials của tôi chỉ cấp cho tôi một số quyền nhất định. Do đó, có 28 công cụ mà tôi không có quyền truy cập, vì vậy bạn không cần phải nói cho tôi biết. Vậy khi bạn nói "tôi có hỗ trợ điều đó không", ý bạn là mcp có hỗ trợ điều đó không, hay sản phẩm của tôi có hỗ trợ điều đó không? Vâng, bây giờ tôi chỉ hỏi, có điều gì đó tôi đã đọc về cách tôi dự đoán phần còn lại của điều này không?
Được rồi, spec không đưa ra tuyên bố nào về điều này. Spec nói rằng khi bạn gọi list tools, bạn sẽ nhận được các công cụ và cách điều đó xảy ra là tùy thuộc vào triển khai. fast mcp biến đó thành một hook có thể ghi đè thông qua middleware, nhưng một lần nữa, không đưa ra tuyên bố nào về cách điều đó diễn ra. Các sản phẩm thương mại có tiền tố, mà tôi không ở đây để quảng cáo, cho phép tool masking trên bất kỳ cơ sở nào và chúng tôi xem đó là một nơi để có một ý kiến có chủ đích trong bối cảnh thương mại, trái ngược với một ý kiến trong bối cảnh mã nguồn mở, trái ngược với protocol mà không nên có ý kiến gì cả. Vì vậy, nếu điều đó thú vị, chúng ta có thể trò chuyện về điều này.
Bạn có thể đang đi sâu vào vấn đề này, nhưng nếu bạn coi vấn đề này, ví dụ này như một cách tiếp cận "bảng mục lục" quản lý chung, thì có, không có cách tiếp cận nào như kiểu bạn nhìn vào bốn đoạn khác nhau, hoặc có thể 800 đoạn, tất cả đều không cần thiết phải có máy chủ mcp riêng của chúng, hoặc đó là gì đối với chúng? Chúng không thể làm được. Không có giải pháp nào cho phép chúng có nhiều thông tin như chúng muốn trên cửa sổ ngữ cảnh. Chúng không cần nó, và nó trở thành một câu hỏi thiết kế. Thành thật mà nói, cuộc gọi này có lẽ là cách đây bốn tháng rồi, và nó chỉ là cuộc gọi sau cuộc gọi sau cuộc gọi như thế này, khiến tôi nhận ra rằng chúng ta cần có nhiều cuộc nói chuyện như thế này hơn và chỉ nói về việc thiết kế một sản phẩm cho một tác nhân là như thế nào.
Mối lo lắng của tôi là mcp được coi là hạ tầng hoặc công nghệ truyền tải, và đúng là như vậy. Và tôi rất hào hứng, tôi nghĩ một năm nữa, chúng ta sẽ nói về context products thay vì mcp servers. Tôi rất hào hứng về điều đó, chúng ta sẽ vượt qua lớp truyền tải nhưng chúng ta cần tìm cách sử dụng nó. Và vì vậy, tôi nghĩ đó là cách chúng ta nói về nó.
Giải pháp thay thế duy nhất khác mà tôi đã thảo luận với một vài người, một vài công ty khi bạn gặp vấn đề như thế này là nếu bạn kiểm soát client, những điều thú vị hơn nhiều sẽ trở nên khả dụng cho bạn. Nếu bạn có thể hướng dẫn client của mình thực hiện mọi việc theo một cách nhất định, ví dụ, nếu bạn có một ứng dụng di động trình bày một tác nhân để giao diện với người dùng cuối, thì bạn kiểm soát client là điều tôi muốn nói. Hoặc nếu đó là nội bộ và bạn có thể ra lệnh client nào hoặc custom client nào một nhóm sử dụng, thì bây giờ bạn có thể làm được nhiều điều thú vị hơn bởi vì bạn thực sự biết nhiều hơn về ngân sách mã thông báo đó và cách tối ưu hóa nó. Nhưng đối với một client bên ngoài...
Hạn chế số lượng công cụ
Tôi nghĩ đến giờ chúng ta đã nói qua tất cả những điều này, vì vậy tôi sẽ để lại nó cho hậu thế. Về việc tiết kiệm thời gian, chúng ta đã nói về việc "quản lý" như một động từ khóa trong bài nói chuyện này. Tôi cho rằng, đó là những gì chúng ta đã và đang làm trong mỗi ví dụ nhỏ mà chúng ta đã thực hiện với mã. Chúng ta đang quản lý cùng một bộ thông tin để đưa về một dạng dễ tiếp cận và dễ nhận biết hơn đối với một Tác nhân.
50 công cụ là giới hạn mà tôi đặt ra cho các vấn đề về hiệu suất. Tôi nghĩ con số này có vẻ rất thấp đối với nhiều người, một số người thậm chí còn nói thấp hơn, trong khi một số khác có thể nói cao hơn. Nếu bạn có hơn 50 công cụ trên một máy chủ mà không biết bất kỳ thông tin nào khác về nó, tôi sẽ bắt đầu nghĩ rằng đó không phải là một máy chủ tốt. Máy chủ GitHub mà tôi biết có khoảng 170 công cụ, liệu điều đó có nghĩa nó không phải là một máy chủ tốt không? Không, có một lập luận hợp lý ở đây. Đội ngũ GitHub đã công bố rất nhiều bài đăng blog thú vị về semantic routing mà họ đang thực hiện. Họ vừa có một bài đăng vào hôm qua về một số kỹ thuật thú vị mà họ đang sử dụng trong phần mềm của mình, giống như kỹ thuật bạn vừa đề cập, điều này giúp giải quyết vấn đề này. Vì vậy, việc có nhiều công cụ như vậy không tự động biến nó thành một máy chủ tệ, nhưng đó là một dấu hiệu đáng quan tâm. Nó khiến tôi tự hỏi: liệu chúng ta có thể chia chúng ra không? Bạn có công cụ quản trị lẫn lộn với công cụ người dùng không? Chúng ta có thể đặt namespace cho các công cụ này một cách khác không? Liệu có đáng để có hai máy chủ thay vì một không? Đó là một dấu hiệu nhỏ. Nếu bạn có thể giảm xuống còn 5-15 công cụ, đó sẽ là lý tưởng. Tôi biết điều đó không khả thi đối với hầu hết mọi người, vì vậy đây là một trong những lời khuyên có thể thực hiện được nhưng có lẽ không quá dễ áp dụng. Đó là một khát vọng mà bạn nên có và chỉ cần cẩn thận trừ khi bạn sẵn sàng đầu tư nhiều công sức vào việc chăm sóc và đánh giá. 50 công cụ mỗi Tác nhân — tôi nên nói là mỗi Tác nhân. Nếu tôi có một máy chủ 50 công cụ và bạn cũng có một máy chủ 50 công cụ, thì đó là 100 công cụ cho Tác nhân. Đó là nơi xảy ra nút thắt cổ chai về hiệu suất, không phải trên máy chủ. Xin lỗi, các slide nên được sửa lại: 50 công cụ cho Tác nhân là nơi bạn bắt đầu thấy hiệu suất suy giảm.
Bài học từ thực tế về tối ưu hóa công cụ
Tôi rất thích câu chuyện này. Kelly Koleffel là người mà tôi đã biết từ lâu, hiện anh ấy đang làm việc tại 5.3. Khi tôi đang chuẩn bị bài nói chuyện này, tôi tình cờ đọc được hai bài đăng blog của anh ấy, giống như một 'mũi tên trúng đích' vậy. Chúng được viết cách nhau gần đúng một tháng, một bài vào tháng 10 và một bài vào tháng 11. Trong bài đầu tiên, anh ấy nói về việc xây dựng một máy chủ và chuyển từ một vài công cụ cơ bản lên tới khoảng 155-188 công cụ. Trong bài đăng blog thứ hai, anh ấy kể về cách anh ấy đã quản lý máy chủ đó, giảm số lượng công cụ từ 188 xuống còn 5. Bạn có thể đọc bất kỳ bài đăng blog nào trong số này; bạn có thể xem chúng độc lập như một câu chuyện thành công về hành trình học MCP của anh ấy. Tôi nghĩ rằng, khi được đọc cùng nhau, chúng kể một câu chuyện thực sự thú vị về việc làm cho một cái gì đó hoạt động, và sau đó làm cho nó hoạt động tốt, đó chính là hành trình sản phẩm theo một nghĩa nào đó. Và điều này đưa chúng ta đến cái mà tôi – xin lỗi, bạn có câu hỏi không? À, xin lỗi, điều này đưa chúng ta đến điều mà tôi đã tìm thấy là phiên bản rõ ràng nhất của vấn đề này.
Đừng chuyển đổi REST API thành MCP server
Tôi đã viết một bài đăng blog khá viral về chủ đề này, đó là lý do tại sao tôi thường xuyên nói về nó: xin vui lòng, nếu không có gì khác, hãy dừng việc chuyển đổi REST API thành MCP server! Đó là cách nhanh nhất để vi phạm mọi điều chúng ta đã nói hôm nay, mọi phương pháp heuristic mà chúng ta đã trình bày về các Tác nhân. Nó thực sự không hoạt động, và còn rất phức tạp. Bởi vì đây là tài liệu fast MCP – một bài đăng blog mà tôi phải viết – và bài đăng blog đó về cơ bản nói rằng: "Tôi biết tôi đã giới thiệu khả năng này, nhưng làm ơn hãy dừng lại." Đó là một điều thực sự phức tạp, bản thân nó có thể là một buổi workshop. Tôi cũng phải chịu một chút trách nhiệm ở đây. Đây không chỉ là một tính năng của fast MCP mà còn là một trong những tính năng phổ biến nhất của fast MCP, đó là lý do tại sao, nói thật, nó sẽ không biến mất. Thay vào đó, chúng tôi sẽ viết tài liệu xung quanh thực tế đó. Nhưng đây là vấn đề: bạn không thể chuyển đổi nó. Tôi sẽ không giải thích, bạn chỉ không thể chuyển đổi nó như thể các bạn trong nhóm devs đã phục vụ. Tuy nhiên, nó là một cách tuyệt vời để khởi động khi bạn đang cố gắng tìm hiểu xem liệu một cái gì đó có hoạt động hay không. Đừng viết quá nhiều mã để rồi lại tạo ra những cách mới để bạn nhận ra mình đã thất bại. Hãy bắt đầu bằng cách chọn một vài endpoint chính, mirror chúng bằng công cụ chuyển đổi tự động của fast MCP hoặc bất kỳ công cụ nào khác bạn thích, hoặc thậm chí tự viết mã đó. Hãy đảm bảo bạn giải quyết từng vấn đề một, và vấn đề đầu tiên là liệu bạn có thể khiến Tác nhân sử dụng công cụ của bạn không. Khi nó đã sử dụng được, bằng mọi cách, hãy loại bỏ phần regurgitates REST API và bắt đầu curate nó, bắt đầu áp dụng một số điều chúng ta đã nói hôm nay. Điều này chỉ là một trong những điều thẳng thắn: đó là cách nhanh nhất để bắt đầu. Bạn không cần phải làm theo cách này. Tôi bắt đầu theo cách này, nhưng đừng kết thúc bằng cách triển khai REST API lên môi trường production như một MCP server. Bạn sẽ hối hận, bạn sẽ phải trả giá sau này, mặc dù ban đầu có thể có một cảm giác 'dopamine hit'.
Các nguyên tắc chính
Vì vậy, đây là năm điều chính mà chúng ta đã nói đến hôm nay trong buổi workshop giả định của chúng ta – một buổi nói chuyện hành động chứ không phải vận hành thực sự.
- Tập trung vào
quy trình làm việctừ trên xuống: Đừng quá sa đà vào các thao tác nhỏ. Đừng yêu cầuTác nhâncủa bạn trở thànhbộ điều phốitrừ khi thực sự cần thiết. - Làm phẳng các đối số của bạn: Cố gắng không gửi các
tải trọnglớn. Cố gắng không gây nhầm lẫn choTác nhân. Cố gắng không cho nó quá nhiều lựa chọn. Tôi không nghĩ mình đã nói rõ điều này khi chúng ta thảo luận, nhưng cố gắng đừng có các đối sốtightly coupled(ràng buộc chặt chẽ) vì điều đó thực sự khiếnTác nhânbối rối. Hãy xem liệu bạn có thể thiết kế xung quanh vấn đề đó nếu có thể; không phải lúc nào cũng khả thi, nhưng nếu có thể, hãy làm. - Hướng dẫn là
ngữ cảnh: Nghe có vẻ hiển nhiên, và tất nhiên là vậy. Chúng là thông tin choTác nhân. Hãy sử dụng chúng làmngữ cảnh, thiết kế chúng nhưngữ cảnh. Thực sự hãy suy nghĩ kỹ về các hướng dẫn, giống như cách bạn suy nghĩ vềchữ ký công cụvàlược đồcủa mình. - Tôn trọng ngân sách
mã thông báo: Bạn phải làm điều này. Đây là điều duy nhất trong danh sách này mà nếu bạn không thực hiện, bạn sẽ đơn giản là không có mộtmáy chủcó thể sử dụng được. Những điều khác bạn có thể bỏ qua. Thành thật mà nói, nghệ thuật của trực giác này là bắt đầu với những quy tắc này và sau đó làm việc ngược lại để đi đến tính thực tế. Nhưng đây là điều duy nhất mà tôi nghĩ bạn không thể thực sự vượt qua giới hạn. - Gần đây, nếu bạn không làm gì khác, hãy bắt đầu với cái gì hoạt động và sau đó loại bỏ những thứ không cần thiết: Tôi đã viết
MCP servergần như lâu bằng bất kỳ ai vào thời điểm này – khoảng một năm – và tôi vẫn thấy mình bắt đầu bằng cách đưa quá nhiềucông cụvào thế giới đôi khi, bởi vì tôi không chắcTác nhânsẽ sử dụng cái nào hoặc tôi đang thử nghiệm. Và tôi phải tự nhắc nhở mình quay lại và loại bỏ chúng, điều đó thật khó khăn. Tôi nghĩ với tư cách là một kỹ sư, đặc biệt khi thiết kế cácAPIthông thường, bạn sẽ nghĩ: "Được rồi, đây làcông cụcủa tôi, đây là phiên bản 2, nó tương thích ngược phải không?" Và bạn cứ tiếp tục thêm mọi thứ, đó là một cách làm việc rất tự nhiên và có thể là mộtbest practice. Nhưng nó không hiệu quả ở đây. Bạn đang sử dụnggiao diện người dùngmà chỉ hiển thịREST APIcho người dùng. Đây là một lời chỉ trích mà tôi đã đưa ra cho các sản phẩm của chính mình đôi khi, khi tôi nghĩ: "Cái này trông quá giống tài liệuREST APIcủa chúng ta." Chúng ta không làm tốt công việc của mình để cung cấp điều này cho người dùng một cách dễ hiểu.
Tác nhân như một giao diện người dùng
Vậy, nếu tôi có thể để lại cho bạn chỉ một, nhưng chỉ một suy nghĩ, thì đó là điều này: bạn không xây dựng một công cụ, bạn đang xây dựng một giao diện người dùng. Hãy coi nó như một giao diện người dùng, bởi vì đó chính là giao diện mà Tác nhân của bạn sẽ sử dụng. Bạn có thể làm tốt hơn hoặc làm tệ hơn, và dù sao thì bạn hay người dùng của bạn cũng sẽ được hưởng lợi từ điều đó. Tôi nghĩ chúng ta đã hết thời gian, vì vậy tôi sẽ mở phần hỏi đáp hoặc những gì tiếp theo, hoặc những thách thức khác mà chúng ta có thể giải quyết. Tôi hy vọng tôi đã tìm thấy sự cân bằng giữa những điều hữu ích cho tất cả các bạn nhưng không yêu cầu bạn phải viết bất kỳ mã nào vào lúc 4:54 sáng thứ Bảy này. Nhưng tôi hy vọng tôi đã có một số thông tin hữu ích cho bạn, nhiều hơn những gì bạn đã có khi đến đây, và rất vui được trả lời bất kỳ câu hỏi nào nếu có.
Hỏi đáp về các công cụ và giao thức MCP
Câu hỏi: tightly coupled arguments là gì?
Đáp: Đó là khi bạn có một đối số như "loại tệp là gì" và một đối số khác như "chúng ta nên xử lý tệp như thế nào", và đầu vào của đối số "loại tệp" sẽ xác định các đầu vào hợp lệ cho đối số còn lại. Vì vậy, chúng tightly coupled (ràng buộc chặt chẽ). Một số đối số cho yếu tố thứ hai sẽ không hợp lệ tùy thuộc vào những gì bạn đã chọn cho yếu tố thứ nhất. Đó chỉ là một điều phụ thêm để theo dõi. Đó là một câu hỏi hay, xin lỗi vì tôi đã không định nghĩa nó.
Tôi sẽ bắt đầu với câu hỏi đầu tiên: khi bạn cung cấp cho một Tác nhân một máy chủ thực thể, liệu có nên tài liệu hóa các lệnh gọi hoặc khả năng của máy chủ trong máy chủ và trong Tác nhân không? Ý tưởng là như vậy, phải không?
Vâng, điều này phụ thuộc vào việc bạn có kiểm soát máy khách hay không. Nếu bạn kiểm soát máy khách, thì đây là một lựa chọn thực sự và có nhiều cách khác nhau để suy nghĩ về nó. Ví dụ, trong một số thứ tôi viết mà tôi biết đang sử dụng mã để truy cập, tôi có thể tài liệu hóa MCP server của mình dưới dạng tệp hoặc các skill cụ thể, bởi vì tôi biết các quy trình làm việc sẽ như thế nào. Tôi biết rằng một số quy trình làm việc của tôi không thường xuyên và tôi không muốn làm ô nhiễm không gian ngữ cảnh với chúng. Vì vậy, nếu bạn kiểm soát máy khách, bạn có một lựa chọn thực sự để đưa ra. Nếu bạn không kiểm soát máy khách, thì bạn không có nhiều lựa chọn như vậy; bạn phải tài liệu hóa nó ở đây vì bạn phải giả định rằng bạn đang làm việc với máy khách tệ nhất có thể. Thành thật mà nói, nhiều câu trả lời trong không gian MCP đều quy về câu hỏi: bạn có kiểm soát máy khách không? Nếu có, bạn có thể làm những điều thực sự thú vị ở cả hai phía của giao thức. Từ góc độ tác giả máy chủ, bạn thực sự cần tài liệu hóa mọi thứ trong doc string của nó. Một lối thoát duy nhất là bạn có thể tài liệu hóa chính máy chủ. Vì vậy, mỗi máy chủ có một trường instructions (hướng dẫn). Nó không được mọi máy khách tôn trọng. Tôi tin rằng nhóm của tôi đã nộp báo cáo lỗi khi chúng tôi xác định điều đó là đúng. Vì vậy, hy vọng đó không phải là một điều vĩnh viễn, nhưng hầu hết các máy khách khi handshake sẽ tải xuống không chỉ các công cụ và tài nguyên, mà còn một blob instructions (khối hướng dẫn) cho chính máy chủ. Bạn có thể đặt bao nhiêu thông tin vào đó? Tôi sẽ cẩn thận; tôi không nghĩ nó muốn đọc một cuốn tiểu thuyết, nhưng bạn có một cơ hội khác để tài liệu hóa có thể là cấp độ cao của máy chủ của bạn.
À vâng, vậy tại sao chúng ta không kết hợp lại và chúng ta sẽ quay lại. Bạn có câu hỏi nào không?
Vâng, tôi không phải là thành viên của ủy ban cốt lõi nhưng tôi có liên hệ rất chặt chẽ với họ, vì vậy có lẽ tôi có thể trả lời câu hỏi của bạn. Tôi rất hào hứng về điều này, vâng! Vâng, điều này tôi biết rất nhiều về nó. Nó sẽ mở rộng, nhưng thực tế sẽ không thay đổi nhiều vì cách nó được triển khai. Tôi có thể trả lời câu hỏi gì? Liệu tôi có hào hứng về nó không? Tôi rất hào hứng về... vì vậy, tất cả các quy tắc vẫn được áp dụng, đó là một câu hỏi tuyệt vời. Hãy nói về điều này trong một giây. Một số bạn, tôi không biết liệu có ai trong số các bạn đã tham dự buổi gặp mặt chúng tôi tổ chức tối qua, nơi đồng nghiệp của tôi đã trình bày không. Ồ, bạn đã tham dự à? Vâng, đúng vậy. Tôi đã nghĩ, tôi biết ít nhất có ai đó sẽ đến. Đồng nghiệp của tôi, Adam, đã có một bài nói chuyện rất hay về điều này mà tôi có thể chia sẻ sau. Tôi sẽ gửi cho bạn một liên kết đến phiên bản của nó. Nhưng phiên bản tóm tắt là: đây là SEP 1686, tên của đề xuất, và nó bổ sung các asynchronous background tasks (tác vụ nền bất đồng bộ) vào giao thức MCP không chỉ cho các công cụ mà cho mọi hoạt động. Và chúng ta không cần nói quá nhiều về điều đó. Lý do nó không liên quan đến việc thay đổi bất kỳ quy tắc nào trong số này là bởi vì đây về cơ bản là một chế độ hoạt động opt-in (chọn tham gia) trong đó máy khách đang nói: "Tôi muốn cái này được chạy bất đồng bộ", và do đó máy khách đảm nhận các trách nhiệm mới về việc kiểm tra nó và poll (truy vấn định kỳ).
Backgrounding và Tác vụ Chặn trong Thiết kế Server
...cho kết quả và thực sự thu thập kết quả. Nhưng giao diện thực tế của việc tìm hiểu về tool hoặc gọi công cụ, v.v., hoàn toàn giống như hiện tại. Vì vậy, đây là một opt-in hoàn toàn ở phía client. Và đó là lý do tại sao từ góc độ thiết kế, không có gì thay đổi. Câu hỏi duy nhất từ góc độ của nhà thiết kế server là: "Đây có phải là một việc phù hợp để chạy nền (backgrounded) thay vì thực hiện đồng bộ (synchronously) trên server không?" À, xin lỗi, để tôi nói lại. Bạn có thể chạy nền bất cứ điều gì vì nó là một framework Python, vì vậy bạn có thể đưa bất cứ thứ gì vào một framework Python. Câu hỏi đặt ra là client có nên đợi nó không, hay nó có nên là một blocking task (tác vụ chặn) không? Đó thực sự là thuật ngữ đúng cho vấn đề này. Và đó chỉ là một câu hỏi thiết kế cho người duy trì server. Liệu tôi có đang nói đúng ý của bạn không? Ồ, không đùa đâu. Vâng, điều này thực sự xảy ra rất nhiều, nhưng cho đến khi bạn nói ra, tôi không nghĩ nó là một pattern (mô hình), nhưng tôi đã thấy điều này rất nhiều. Đó là một vấn đề thực sự. Vâng, có lẽ chúng tôi sẽ viết một bài blog về nó, điều đó sẽ rất vui. Vâng, hy vọng rằng mọi thứ sẽ vẫn tiến triển. Nhưng liên quan đến elicitation, bạn thực hiện điều đó như thế nào?
Kích hoạt (Elicitation) Nâng cao trong MCP
Elicitation thực sự rất thú vị. Bây giờ chúng ta đang nói về elicitation MCP nâng cao. Có ai không quen thuộc với nó không? Vâng, elicitation về cơ bản là một cách để yêu cầu client cung cấp thêm đầu vào giữa chừng trong quá trình thực thi tool. Vì vậy, bạn lấy các đối số ban đầu cho tool, bạn thực hiện một elicitation. Đó là một yêu cầu MCP chính thức, và bạn nói: "Tôi cần thêm thông tin." Điều thú vị ở nó là nó có cấu trúc. Vì vậy, trường hợp sử dụng phổ biến nhất của điều này ở các client hỗ trợ nó là để phê duyệt, nơi bạn nói: "Tôi cần một câu trả lời có hoặc không về việc tôi có thể tiếp tục thực hiện điều gì đó có thể gây ra tác dụng phụ không thể đảo ngược hay không." Khi nó hoạt động, nó hoạt động rất tốt. Một lần nữa, đây là một trong những thứ không có sự hỗ trợ client tuyệt vời và do đó rất nhiều người không đưa nó vào server của họ, bởi vì nó sẽ làm hỏng server của bạn nếu bạn gửi thứ này đi mà client không biết phải làm gì với nó. Vì vậy, bạn phải cẩn thận một chút. Nó có thay đổi thiết kế không? Đó là một câu hỏi tuyệt vời. Tôi ước nó được sử dụng nhiều hơn để tôi có thể nói có, và bạn nên phụ thuộc vào nó nếu tất cả các client đều hỗ trợ nó và nó được sử dụng rộng rãi. Và lý do tất cả các client không hỗ trợ cái này, nhân tiện, tôi không cố ý nói rằng các client tệ. Rất phức tạp để biết cách xử lý elicitation bởi vì một số client là user-facing (hướng người dùng), khi đó rất dễ dàng, chỉ cần hỏi người dùng và cung cấp cho họ một form (biểu mẫu). Một số client được tự động hóa, một số được chạy nền ở đâu đó. Và vì vậy, việc bạn làm gì với một elicitation thực sự khá phức tạp. Nếu bạn chỉ điền nó vào như một LLM, có thể bạn đã hài lòng, có thể bạn chưa. Rất khó để biết. Vì vậy, nếu nó được sử dụng rộng rãi, tôi chắc chắn sẽ nói rằng nó mang lại cho bạn cơ hội để đưa các đối số được kết nối chặt chẽ vào một elicitation prompt hoặc các xác nhận. Rất nhiều lần bạn sẽ thấy đối với các destructive tools (công cụ phá hủy), bạn sẽ thấy xác nhận và nó sẽ mặc định là false (sai), và bạn đang buộc LLM phải thừa nhận, ít nhất là một cách để, bạn biết đấy, hy vọng đưa nó vào một chế độ hoạt động hợp lý hơn. Elicitation là một cách tốt hơn để thiết kế cho điều đó. Tôi không nghĩ điều đó đã được đưa vào ví dụ nào trong số này. Vì vậy, một câu hỏi tuyệt vời, ước gì tôi có thể nói có. Tôi hy vọng sẽ nói có về điều đó.
Xây dựng Tác nhân: MCPC so với Khung làm việc Agent
Câu hỏi thứ hai của bạn. Vâng, trong công việc của tôi, điều chính tôi làm là xây dựng các Tác nhân. Và tôi làm những thứ như Sangra hoặc Popo Nihai, TG hoặc tương tự. Và tôi thường chỉ viết các tool, và các tool đó đi vào các API. Và tôi thực sự không thấy nhu cầu về MCPC trong không gian đó. Bạn có đồng ý rằng MCPC giống như... Tôi nghĩ tôi sẽ không khuyên bạn viết một MCPC server. Vâng, tôi nghĩ rằng trong vòng một năm, lý do bạn chọn viết một MCPC server là vì bạn sẽ có khả năng quan sát tốt hơn và hiểu được những gì đã thất bại, trong khi các khung làm việc LLM không tốt lắm. Bởi vì một phần công việc của toàn bộ các khung làm việc LLM là không thất bại trong gọi công cụ và thực sự đưa nó trở lại LLM, tương tự như những gì chúng ta đã nói một lúc trước. Vì vậy, bạn thường không có khả năng quan sát tốt về các thất bại của gọi công cụ. Một số có, nhưng không phải tất cả. Và vì vậy, một trong những lý do sử dụng MCPC server ngay cả cho một trường hợp cục bộ như vậy là vì bây giờ bạn có một cơ sở hạ tầng tự động để bạn thực sự có thể debug (gỡ lỗi) và diagnose (chẩn đoán) mọi thứ. Tôi không nghĩ đó là lý do mạnh nhất để làm điều đó. Tôi nghĩ điều đó sẽ xảy ra trong một năm khi hệ sinh thái trở nên "ấm áp" hơn. Tôi nghĩ nếu bạn, nếu bạn kiểm soát hoàn toàn client và bạn đang thực hiện client orchestration (điều phối client), và bạn đang viết... nếu bạn đang viết agent loop và bạn là người duy nhất, hãy làm bất cứ điều gì bạn muốn. Tôi nghĩ rằng tất cả các lời khuyên bạn sẽ đưa ra cũng áp dụng khi bạn xây dựng các tool. Hoàn toàn đúng. Điều này, điều này, vâng, mọi thứ chúng tôi đã nói hôm nay đều áp dụng cho một tool Python, hoàn toàn đúng. Và đó là, ý tôi là, đó là cách Fast MCPC xử lý nó. Đó là một câu hỏi hay.
Chế độ Mã hóa (Code Mode)
Còn câu hỏi cuối cùng nào không? Tôi rất sẵn lòng trả lời. Vâng, vâng, vâng. Code Mode là một điều mà Anthropic, Cloudflare thực sự đã viết blog về nó đầu tiên và sau đó Anthropic đã tiếp nối. Trong Code Mode, bạn thực sự yêu cầu giải quyết một số vấn đề tôi vừa mô tả ở đây, bạn yêu cầu LLM viết mã gọi các MCP tools theo trình tự. Và đó là một cách sidestep (bỏ qua một bên) thực sự thú vị đối với rất nhiều điều tôi vừa nói ở đây. Lý do tôi không khuyến nghị nó một cách hết lòng là vì nó mang lại các vấn đề khác như sandboxing (môi trường biệt lập) và code exit (thoát mã); có những vấn đề khác với nó. Nhưng nếu bạn ở một vị trí do đó, nó có thể cực kỳ thú vị. Tôi thực sự có một đồng nghiệp đã viết bản mở rộng FastMCP hỗ trợ nó, mà chúng tôi đã đưa vào một package (gói) nào đó. Ban đầu, chúng tôi không muốn đưa vào FastMCP main vì chúng tôi không chắc chắn. FastMCP cố gắng có quan điểm riêng (opinionated), và chúng tôi không chắc chắn làm thế nào để tích hợp điều đó. Và sau đó, nó thực sự thành công đến mức chúng tôi quyết định sẽ thêm một experiments flag (cờ thử nghiệm) vào CLI (giao diện dòng lệnh) và có nó. Nhưng tôi không biết liệu nó đã được đưa vào chưa. Vâng, điều này sẽ đi vào cái mới này, tôi quên mất liệu chúng tôi gọi nó là experiments hay optimize. Nó nằm trong roadmap (lộ trình) của chúng tôi ngay bây giờ và điều này sẽ được đưa vào đó. Và sau đó, có cả một thế giới hiện nay về việc tối ưu hóa các gọi công cụ và các thứ.
Kết luận
Nhưng tôi muốn tôn trọng thời gian của bạn và cho phép tất cả các bạn trở lại cuộc sống của mình. Bạn rất tốt bụng đã dành một giờ nói chuyện về MCP với tôi. Tôi rất sẵn lòng tiếp tục nói chuyện nếu ai có câu hỏi, nhưng tôi muốn kết thúc hội nghị. Tôi hy vọng tất cả các bạn đã thích buổi nói chuyện và cảm ơn rất nhiều vì đã tham dự.
TL;DR
- Thiết kế sản phẩm cho các tác nhân AI đòi hỏi một cách tiếp cận khác biệt đáng kể so với thiết kế cho con người, do những hạn chế cố hữu của AI trong các khía cạnh như khám phá, lặp lại và ngữ cảnh.
- Nhiều máy chủ MCP hiện tại được xem là chưa tốt vì chúng thường chỉ là lớp wrapper đơn giản, thiếu tư duy sản phẩm phù hợp để tối ưu hóa cho cách các tác nhân AI thực sự tương tác và xử lý thông tin.
- Nguyên tắc cốt lõi cho các nhà phát triển MCP là "curate" (chọn lọc, sắp xếp) các giao diện, tập trung vào "kết quả chứ không phải thao tác" để tạo ra các công cụ hiệu quả hơn cho tác nhân.
Điểm chính
- AI Agents require tailored interfaces: Unlike humans who use products (websites, SDKs, apps), AI agents need their own optimized interfaces, as they interact with APIs in fundamentally different ways.
- Costly Discovery for AI: AI agents find discovery (enumerating tools, reading descriptions) expensive and token-consuming because it often re-occurs with each invocation, whereas humans perform it once.
- Slow Iteration for AI: Iteration is a major bottleneck for AI agents; each additional call may resend the entire history, making repeated attempts slow and costly in terms of tokens and time.
- Limited Context for AI: LLMs have very small "brains" with limited context windows (e.g., 200,000 tokens), making them unable to retain information across long interactions like humans.
- "Curate" is Key for MCP Design: The most important concept for MCP developers is to "curate" information and interfaces, presenting a problem/solution to AI agents in a controlled and optimized manner.
- Focus on Outcomes, Not Operations: When designing LLM servers/tools, prioritize the desired end "outcome" for the agent rather than exposing raw "operations" (sequential API calls) which AI struggles to orchestrate efficiently.
- Need for Best Practices: There's a critical need for documented best practices for LLM/Agent product design, similar to established human UI/UX guidelines, to improve the quality of agentic products.
- MCP as a Standard Interface: MCP provides a standard way to deliver information to agents controllably, aiming to optimize how tools are discovered and executed, despite current client implementation challenges.
Từ vựng
- Tác nhân AI — AI Agent
- Thiết kế sản phẩm tác nhân — Agentic Product Design
- Mã thông báo — Token
- Ngữ cảnh — Context
- Mô hình ngôn ngữ lớn (LLM) — Large Language Model (LLM)
- Thực tiễn tốt nhất — Best Practices
- Kết quả chứ không phải thao tác — Outcomes not Operations
- Orchestration — Điều phối/Điều hành
- Trải nghiệm nhà phát triển — Developer Experience (DX)
- Giao diện cấp cao / Nguyên thủy cấp thấp — High-level interface / Low-level primitives
Nội dung chi tiết
Bài nói chuyện này trình bày những kiến thức sâu sắc về thiết kế sản phẩm dành cho các Tác nhân AI, tập trung vào sự khác biệt giữa cách con người và Tác nhân tương tác với API và các công cụ.
Giới thiệu và Kinh nghiệm Cá nhân
Tôi thực sự đánh giá cao cơ hội này. Tôi sẽ cố gắng trình bày nội dung này một cách phổ quát nhất có thể. Chúng ta sẽ không có phần tương tác; thay vào đó, chúng ta sẽ cùng nhau thảo luận. Tôi sẵn lòng đi chệch khỏi kịch bản, và tôi sẵn lòng trả lời các câu hỏi. Nếu có điều gì chúng ta muốn khám phá tại bất kỳ thời điểm nào, mục tiêu của tôi là chia sẻ với các bạn rất nhiều điều tôi đã học được. Tôi sẽ cố gắng biến chúng thành những thông tin có tính ứng dụng cao nhất có thể, để có những điều thực tế để thực hiện ở đây, nhiều hơn so với một bài nói chuyện cấp cao hơn. Nhưng hãy thành thật mà nói: đã muộn rồi, có rất nhiều điều để nói, và đây sẽ là một buổi khá dài. Hãy cùng nói về MCP. Tôi hy vọng rằng các bạn ở đây đều quan tâm đến MCP. Đó là lý do bạn đến với bài nói chuyện này. Nếu bạn đến đây để tìm hiểu về MCP, cách tiếp cận này có thể sẽ hơi khác một chút. Xin hãy giơ tay: Ai đã từng nghe nói về MCP? Ai đã sử dụng MCP? Ai đã viết một máy chủ MCP? Được rồi. Có ai cảm thấy không thoải mái với MCP không? Hoàn toàn không sao cả; chúng ta có thể điều chỉnh. Được rồi, vậy thì, hãy bắt đầu thôi. Hãy đi sâu vào vấn đề.
Đây là tôi. Tôi là nhà sáng lập và Giám đốc điều hành của một công ty tên là Prefect Technologies trong bảy hoặc tám năm qua. Chúng tôi đã xây dựng phần mềm tự động hóa dữ liệu và phần mềm orchestration. Trước đó, tôi là thành viên của Apache Airflow PMC. Ban đầu, tôi bắt đầu Prefect để đưa những ý tưởng orchestration tương tự vào khoa học dữ liệu. Ngày nay, chúng tôi vận hành toàn bộ full stack. Sau đó vài năm, tôi đã phát triển một khung làm việc tác nhân gọi là Marvin, mà tôi sẽ không mô tả là cực kỳ phổ biến, nhưng đó là bước chân của tôi vào thế giới AI, ít nhất là từ góc độ trải nghiệm nhà phát triển, và tôi đã học được rất nhiều từ đó. Gần đây hơn, tôi đã giới thiệu một phần mềm có tên là Fast MCP, vốn đã trở nên cực kỳ, cực kỳ phổ biến, thậm chí có thể là quá phổ biến. Do đó, tôi có mặt ở đây hôm nay. Tôi hơi choáng ngợp. Tôi thấy mình lại trở về vị trí duy trì mã nguồn mở, một vị trí mà tôi đã không đảm nhiệm trong vài năm, điều này cũng khá thú vị. Nhưng điều quan trọng nhất là Fast MCP đã mang lại cho tôi một góc nhìn rất đặc biệt, vốn là cơ sở cho bài nói chuyện này hôm nay.
Đây là số lượt tải xuống của chúng tôi. Tôi chưa từng thấy điều gì như thế này. Tôi chưa từng làm việc trên một dự án nào như thế này. Nó đã được tải xuống một triệu rưỡi lần chỉ riêng ngày hôm qua. Có rất nhiều máy chủ MCP ngoài kia. Fast MCP đã trở thành cách thức tiêu chuẩn trên thực tế để xây dựng máy chủ MCP. Tôi đã giới thiệu nó gần như chính xác một năm trước, như nhiều bạn có lẽ đã biết, bản thân MCP cũng được giới thiệu gần như chính xác một năm trước. Vài ngày sau đó, tôi đã giới thiệu phiên bản đầu tiên của Fast MCP. David từ Anthropic đã gọi cho tôi, nói rằng "Tôi nghĩ điều này thật tuyệt vời. Tôi nghĩ rằng nhiều người nên xây dựng máy chủ." Chúng tôi đã đưa một phiên bản của nó vào SDK chính thức, điều này thật tuyệt vời. Và sau đó, khi MCP phát triển bùng nổ trong năm qua, chúng tôi nhận thấy việc định vị Fast MCP (mà tôi đang duy trì) như một giao diện cấp cao (high-level interface) cho hệ sinh thái MCP, trong khi SDK tập trung vào các nguyên thủy cấp thấp (low-level primitives), là hữu ích. Và trên thực tế, chúng tôi sẽ loại bỏ thuật ngữ Fast MCP khỏi SDK cấp thấp trong vài tháng tới. Nó đã trở nên hơi, hơi khó hiểu, nhưng có hai thứ này gọi là Fast MCP. Vì vậy, Fast MCP sẽ là một giao diện cấp cao cho thế giới.
Thực trạng Máy chủ MCP và Mục tiêu Bài nói chuyện
Kết quả là, chúng tôi thấy rất nhiều máy chủ MCP không tốt. Tôi đã đặt tên cho bài nói chuyện này theo một meme và sau đó tôi tự hỏi, liệu mọi người có còn biết meme này là gì nữa không? Đối với tôi, nó rất hài hước và rất thời sự. Nó xuất phát từ một tập phim Futurama năm 1999. Vì vậy, nếu bạn chưa xem, tiêu đề bài nói chuyện của tôi không có ý xấu. Tôi là một người khá lạc quan. Tôi chọn cách diễn giải điều này như là "những gì bạn có thể làm tốt hơn". Và vì vậy, chúng ta sẽ tìm cách để làm tốt hơn. Đó là mục tiêu của bài nói chuyện hôm nay. Trên thực tế, nói chính xác hơn, điều tôi muốn làm hôm nay là thực sự xây dựng một trực giác cho thiết kế sản phẩm tác nhân (agentic product design). Tôi không thấy điều này được thảo luận nhiều như lẽ ra phải có, với số lượng Tác nhân đang được sử dụng trong bao nhiêu sản phẩm ngày nay. Và ý tôi là điều này hoàn toàn tương tự như việc tôi sẽ nói chuyện về cách xây dựng một sản phẩm tốt cho người dùng, cho con người. Khi đó, chúng ta sẽ nói về các nguyên tắc giao diện người dùng (human interface guidelines), về trải nghiệm người dùng (user experience), và về các câu chuyện người dùng (user stories). Tôi thấy rất hữu ích khi bắt đầu nói về những điều đó từ góc độ tác nhân, bởi vì một máy chủ MCP không là gì khác ngoài một giao diện (interface) cho một Tác nhân. Và chúng ta nên thiết kế nó phù hợp với điểm mạnh và điểm yếu của những Tác nhân đó, giống như cách chúng ta làm với mọi thứ khác.
Sự Khác biệt: AI và Con người Tương tác với API
Khi tôi đưa ra ý tưởng này, tôi rất, rất, rất thường xuyên nhận được phản hồi trái chiều này: "Nếu con người có thể sử dụng một API, tại sao AI lại không thể?" Và có rất nhiều điều sai trong câu hỏi này. Điều sai số một trong câu hỏi này là nó chứa một giả định mà tôi thấy rất nhiều trong thiết kế sản phẩm AI (AI product design), và nó khiến tôi phát điên, đó là AI hoàn hảo, hoặc chúng là những nhà tiên tri, hoặc chúng giỏi mọi thứ. Chúng thực sự là những công cụ rất, rất, rất mạnh mẽ. Nhưng tôi cho rằng, dựa trên phản hồi của các bạn trước đó, tôi nghĩ mọi người trong căn phòng này đều đã có những trải nghiệm không mấy dễ chịu về việc chúng có thể sai lầm, hoặc chúng bị hạn chế, hoặc chúng không hoàn hảo. Vì vậy, tôi không thích câu hỏi này bởi vì nó giả định rằng chúng siêu phàm một cách thần kỳ trong mọi việc.
Nhưng tôi thực sự không thích câu hỏi này. Đây là một câu hỏi nhỏ mà tôi đã nhận được. Tôi không diễn giải lại. Tôi thực sự không thích câu hỏi này vì con người không sử dụng API. Rất, rất hiếm khi con người sử dụng API. Con người sử dụng sản phẩm. Chúng ta làm mọi cách để đặt một thứ gì đó ở giữa chúng ta và một API. Chúng ta xây dựng một website. Chúng ta xây dựng một SDK. Chúng ta xây dựng một client. Chúng ta xây dựng một ứng dụng di động (mobile app). Chúng ta không thích sử dụng API trừ khi chúng ta buộc phải làm vậy hoặc chúng ta là người chịu trách nhiệm xây dựng giao diện đó. Và vì vậy, một trong những lập luận cốt lõi của tôi, và lý do tôi yêu MCP rất nhiều, là tôi tin rằng các Tác nhân xứng đáng có giao diện riêng của chúng, được tối ưu hóa cho chúng và trường hợp sử dụng (use case) của chúng. Và để thiết kế giao diện đó, điều mà tôi muốn trình bày hôm nay, chúng ta phải suy nghĩ một chút về sự khác biệt giữa con người và AI. Và đây là một trong những câu hỏi nghe có vẻ thực sự ngớ ngẩn khi bạn nói ra thành tiếng, nhưng lại rất hữu ích khi thực sự xem xét.
Ba Yếu tố khác biệt chính: Khám phá, Lặp lại và Ngữ cảnh
Và tôi muốn lập luận với bạn rằng sự khác biệt này tồn tại ở ba khía cạnh: khám phá (discovery), lặp lại (iteration) và ngữ cảnh (context). Để bắt đầu, đối với con người, chúng ta thấy việc khám phá rất rẻ. Chúng ta có xu hướng thực hiện nó chỉ một lần. Nếu bạn nghĩ về việc bất kỳ ai trong số các bạn đã phải triển khai một cái gì đó dựa trên một REST API, bạn làm gì? Bạn truy cập tài liệu hoặc Swagger hay bất cứ thứ gì. Bạn xem nó. Bạn xem nó một lần, bạn tìm ra những gì bạn cần. Bạn sẽ không bao giờ làm lại điều đó. Và vì vậy, mặc dù bạn có thể mất một thời gian để thực hiện việc khám phá, nhưng nó rẻ trong vòng đời của ứng dụng (application) mà bạn đang xây dựng. AI thì không hẳn như vậy. Mỗi lần AI khởi động, nó "bắt tay" với một máy chủ, nó tìm hiểu về máy chủ, nó liệt kê từng công cụ và từng mô tả trên máy chủ đó. Vì vậy, việc khám phá thực sự rất tốn kém đối với các Tác nhân. Nó tiêu thụ rất nhiều mã thông báo.
Tiếp theo là lặp lại (iteration). Tương tự. Nếu bạn là một nhà phát triển (developer) và bạn đang viết mã dựa trên một API, bạn có thể lặp lại rất nhanh. Tại sao? Bởi vì bạn thực hiện khám phá một lần, bạn tìm ra ba đường dẫn (routes) bạn sẽ gọi và sau đó bạn viết một script để gọi chúng liên tiếp nhanh nhất có thể theo ngôn ngữ của bạn. Vì vậy, việc lặp lại rất rẻ. Nó nhanh. Đối với các Tác nhân, tôi nghĩ tất cả chúng ta đều biết việc lặp lại rất chậm. Lặp lại là kẻ thù. Mỗi lời gọi (call) bổ sung, tùy thuộc vào cài đặt bộ nhớ đệm (caching setup) của bạn, cũng gửi toàn bộ lịch sử của tất cả các lời gọi trước đó qua mạng. Nghĩa là, bạn không muốn lặp lại nếu có thể tránh được. Vì vậy, đó sẽ là một điều quan trọng mà chúng ta cần xem xét.
Và điều cuối cùng là về ngữ cảnh. Điều này hơi chung chung, nhưng nó quan trọng. Với tư cách là con người, trong cuộc trò chuyện này, tôi đang nói, bạn đang nghe tôi và bạn đang so sánh điều này với những ký ức khác nhau bạn có và những kinh nghiệm khác nhau bạn có trên các thang thời gian (time scales) khác nhau. Và tất cả đều đang thực hiện những điều tuyệt vời, đáng kinh ngạc trong não bạn. Và khi bạn kết nối một Mô hình ngôn ngữ lớn (LLM) vào bất kỳ trường hợp sử dụng (use case) nào, nó chỉ nhớ 200.000 mã thông báo cuối cùng mà nó nhìn thấy. Và đó là giới hạn bộ nhớ (memory) của nó cộng với bất cứ điều gì được nhúng (embedded) đâu đó trong các trọng số (weights) của nó. Và chỉ vậy thôi. Và vì vậy, chúng ta cần phải rất, rất, rất ý thức về thực tế rằng nó có một bộ não (brain) rất nhỏ vào thời điểm này. Tôi nghĩ nó giống hơn nhiều khi mọi người nói về việc đưa Apollo 11 lên mặt trăng và với một kilobyte RAM hoặc bất cứ điều gì đó. Tôi nghĩ đó thực sự là cách chúng ta cần suy nghĩ về những điều mà thành thật mà nói, cảm thấy khá kỳ diệu bởi vì chúng có thể mở các PR (Pull Requests) cho tôi hoặc bất cứ điều gì chúng làm. Vì vậy, đây là ba khía cạnh chính trong tâm trí tôi về sự khác biệt. Và chúng ta không nên xây dựng các API tốt cho con người trên bất kỳ khía cạnh nào trong số này và giả vờ rằng chúng cũng tốt cho các Tác nhân.
Tầm quan trọng của "Curate" và Mục đích của MCP
Và một cách mà tôi bắt đầu nói về điều này là ý tưởng rằng một Tác nhân có thể tìm thấy một cây kim trong đống cỏ khô. Vấn đề là nó sẽ xem xét từng cọng cỏ và quyết định xem nó có phải là kim hay không. Điều đó không hoàn toàn đúng theo nghĩa đen, nhưng theo một cách trực quan, đó là cách chúng ta nên suy nghĩ về những gì chúng ta đặt trước các Tác nhân và cách chúng ta đặt ra một vấn đề. Và một máy chủ MCP không là gì khác ngoài một giao diện cho vấn đề đó và/hoặc giải pháp. Và vì vậy, cuối cùng, để quay lại tuyên bố về trực giác sản phẩm của chúng ta, tôi đã lập luận với bạn rằng từ quan trọng nhất trong vũ trụ đối với các nhà phát triển MCP là curate. Làm thế nào để bạn curate từ một lượng lớn thông tin, vốn có thể dễ hiểu đối với một nhà phát triển con người, một giao diện phù hợp cho một trong những Tác nhân AI cực kỳ hạn chế này, ít nhất là trên các khía cạnh mà chúng ta vừa xem xét.
Và điều đó dẫn chúng ta đến slide này: YMPP (Why MCP?). Và tôi gần như đã làm điều này giống như slide Derek Zoulander "Why MCP?", nhưng tôi vừa nói với bạn "Why MCP", Derek, đó là bởi vì nó làm tất cả những điều này. Nó cung cấp cho chúng ta một cách tiêu chuẩn để truyền thông tin đến các Tác nhân một cách có thể kiểm soát, nơi chúng ta có thể kiểm soát không chỉ cách nó được khám phá mà còn cả cách nó được thực hiện. Có một dấu hoa thị lớn (big asterisk) ở đó bởi vì các triển khai client (client implementations) trong không gian MCP hiện tại không tuyệt vời. Và chúng làm một số điều mà bản thân chúng không tuân thủ đặc tả MCP (MCP spec). Có lẽ cuối cùng chúng ta sẽ đi sâu vào điều đó. Nó không liên quan trực tiếp đến bây giờ, ngoại trừ việc tất cả những gì chúng ta có thể làm là cố gắng xây dựng các máy chủ tốt nhất có thể tùy thuộc vào các giới hạn của các client sẽ sử dụng chúng. Và một lần nữa, tôi đưa điều này vào đây. Tôi nghĩ chúng ta không cần phải đi qua MCP là gì cho đối tượng này. Vì vậy, chúng ta sẽ lướt nhanh qua điều này, nhưng tất nhiên là vì mục đích của bản transcript. Câu nói sáo rỗng là nó giống như USB-C cho internet. Đó là một cách tiêu chuẩn để kết nối Mô hình ngôn ngữ lớn (LLM) với các công cụ hoặc dữ liệu.
Và nếu bạn chưa từng thấy Fast MCP, đây là cách nó trông như thế nào khi xây dựng một máy chủ MCP đầy đủ chức năng. Cái này tôi sống ở Washington, DC. Tàu điện ngầm ở đó thường xuyên bốc cháy. Và vì vậy cái này kiểm tra xem tàu điện ngầm có đang bốc cháy hay không. Và thực sự là có. Bây giờ, câu hỏi mà chúng ta thực sự ở đây để khám phá là tại sao lại có quá nhiều máy chủ MCP tồi tệ? Có lẽ một câu hỏi tốt hơn là tất cả các bạn có đồng ý với tôi rằng có nhiều máy chủ MCP tồi tệ không? Tôi có vẻ như tuyên bố điều này như thể nó là sự thật. Tôi không cố gắng đưa ra một tuyên bố gây tranh cãi. Có rất nhiều máy chủ MCP tồi tệ trên thế giới. Tôi thấy rất nhiều trong số chúng bởi vì mọi người đang sử dụng khung làm việc của tôi để xây dựng chúng. Điều đó có làm ai ngạc nhiên không khi tôi có vẻ như tuyên bố điều đó. Tôi thực sự tò mò liệu đó có phải là tôi đã đưa ra một giả định sai không. Tôi không nghĩ kinh nghiệm của tôi với mọi MCP mà tôi cung cấp công cụ là như vậy. Nhưng tôi biết rằng chúng giống như ABA wrapper. Họ chỉ đặt cái đó vào như thể họ muốn ABA và thế là xong. Và thế là xong. Họ gọi đó là một MCP. Vâng. Và tôi nghĩ ngay cả tôi cũng sẽ đưa ra những lập luận hơi ngoài phạm vi nhưng tôi sẽ lập luận rằng rất nhiều trong số chúng, ngay cả khi chúng không phải là wrapper, chỉ là những sản phẩm tồi tệ vì không có sự cân nhắc nào được đưa vào chúng.
Tầm quan trọng của Thực tiễn Tốt nhất (Best Practices)
Một so sánh mà tôi thường nói chuyện với nhóm của mình là: nếu bạn truy cập một trang web tồi, bạn biết ngay đó là một trang web tồi. Chúng ta không cần phải ngồi đó để tìm hiểu tại sao nó xấu, khó sử dụng, khó tìm kiếm thứ bạn cần, hay chỉ toàn là hiệu ứng flash. Tôi không biết chính xác điều gì tạo nên một trang web tồi, nhưng bạn nhận ra ngay khi truy cập. Chúng ta không thích chỉ ra tất cả những lỗi lầm vì chúng có vô số; thay vào đó, chúng ta cố gắng tìm những ví dụ tuyệt vời về các trang web tốt. Và vì vậy, điều tôi nghĩ chúng ta cần hơn bất cứ thứ gì khác chính là các thực tiễn tốt nhất (best practices) cho LLM. Một trong những ưu tiên lớn của tôi hiện tại và là lý do ra đời bài nói chuyện này là tôi muốn đảm bảo rằng chúng ta có càng nhiều best practices được tài liệu hóa càng tốt.
Tôi muốn khen ngợi một vài công ty. Đây là ảnh chụp màn hình từ Block, họ có một playbook tuyệt vời mà nếu bạn không thích bài nói chuyện này, hãy đọc bài blog của họ. Nó giống như một phiên bản tốt hơn của những gì tôi đang làm bây giờ. Và GitHub gần đây cũng đã phát hành một cái, cùng với nhiều công ty khác. Tôi có thể đưa ra nhiều ví dụ ở đây, nhưng đây là hai tài liệu tôi thường xuyên tham khảo và tôi khuyên bạn nên đọc chúng. Nhóm Block đặc biệt xuất sắc trong những gì họ đang làm về LLM. Thật trùng hợp, cùng một nhóm này đã là khách hàng của tôi trong sáu năm về mảng dữ liệu, và tôi thực sự yêu thích công việc họ làm. Bài blog mà họ đưa ra rất sâu sắc và tôi đặc biệt khuyên bạn nên đọc chúng. Tôi muốn thấy nhiều hơn nữa những nỗ lực như thế này, và hôm nay là một trong những cố gắng khiêm tốn của tôi để đưa một phần trong số đó ra thế giới.
Từ Thao tác đến Kết quả: Tư duy sản phẩm cho Máy chủ LLM
Hôm nay, tôi nghĩ chúng ta sẽ cùng nhau khắc phục một máy chủ thông qua các slide, thay vì yêu cầu bạn mở máy tính xách tay, thiết lập environment và viết mã với tôi vì bây giờ là 4:25 chiều thứ Bảy. Điều này sẽ là một cách tiếp cận nhẹ nhàng và hy vọng mang lại tính khả thi.
Đây là máy chủ mà bạn đã mô tả một lúc trước, phải không? Ai đó đã viết máy chủ này. Tôi hy vọng cú pháp đủ rõ ràng cho mọi người: chúng ta có một decorator nói rằng một hàm là một tool, và sau đó là chính tool đó. Tha thứ cho tôi, tôi không muốn làm bạn nhàm chán với các chi tiết vì chúng ta nghĩ đây là một máy chủ tồi ngay từ đầu.
Trong máy chủ này, ví dụ của chúng ta là gì? Chúng ta muốn kiểm tra trạng thái đơn hàng. Để kiểm tra trạng thái đơn hàng, chúng ta cần tìm hiểu rất nhiều điều về người dùng và đơn hàng của họ, chúng ta cần lọc chúng, chúng ta cần thực sự kiểm tra trạng thái. Và nếu đây là một REST API (mà có lẽ là vậy), chúng ta biết chính xác mình sẽ làm gì: chúng ta sẽ thực hiện một cuộc gọi đến từng hàm theo một trình tự và trả về kết quả đó dưới dạng một đầu ra cho người dùng. Nó sẽ dễ dàng, có thể quan sát được (observable), nhanh chóng và có thể kiểm thử được (testable). Mọi thứ sẽ tốt đẹp.
Nhưng thay vào đó, nếu chúng ta để một Agent tiếp cận điều này, nó sẽ gọi các hàm này theo thứ tự nào? Nó có biết định dạng của các đối số (argument) không? Sẽ mất bao lâu cho ít nhất ba lượt đi lại (round trip) mà điều này yêu cầu? Đây là tất cả các vấn đề mà chúng ta đang gặp phải chỉ bằng cách nhìn vào nó. Chúng ta không giải quyết chúng, nhưng đó là những vấn đề tôi thấy nếu tôi đang xem xét điều này như một nỗ lực hướng tới sản phẩm.
Vì vậy, điều đầu tiên chúng ta sẽ nghĩ đến – và tôi nghĩ đây có lẽ là điều quan trọng nhất khi chúng ta nghĩ về một máy chủ LLM hiệu quả, bởi vì đó là tư duy sản phẩm – là kết quả chứ không phải thao tác (outcomes not operations). Chúng ta muốn đạt được điều gì? Điều này đôi khi hơi khó chịu đối với các kỹ sư vì nó buộc phải tư duy sản phẩm. Không phải ai đó đưa ra một user story và phác thảo mọi thứ, nói rằng "chúng ta cần triển khai điều này". Chúng ta không thể đưa một thứ gì đó vào máy chủ này trừ khi chúng ta biết chắc chắn nó sẽ hữu ích và mang lại kết quả tốt. Chúng ta phải bắt đầu từ đó. Không có đủ context để chúng ta có thể tùy tiện.
Đây là cảm giác khi bạn rơi vào cái bẫy đó: bạn có một loạt các thao tác nguyên tử (atomic operations). Điều này thật tuyệt vời nếu bạn đang xây dựng một REST API – đó là best practice nếu bạn đang xây dựng một REST API. Nhưng nó tệ nếu bạn đang xây dựng một máy chủ LLM. Thay vào đó, chúng ta muốn những thứ như "theo dõi đơn hàng mới nhất" và "gửi email". Rất khó để làm hỏng và bạn biết kết quả là gì khi bạn gọi nó.
Phiên bản khác của cái bẫy là Agent làm "chất keo" (agent as glue) hoặc Agent làm "điều phối viên" (agent as orchestrator). Xin hãy tin tôi, vì tôi đã dành cả sự nghiệp để xây dựng phần mềm orchestration và tự động hóa: có những thứ thực sự giỏi trong việc orchestration và có những thứ thực sự tệ trong việc orchestration. Agent nằm ngay giữa vì chúng có thể làm được, nhưng nó tốn kém, chậm chạp, gây khó chịu và khó gỡ lỗi. Đó là gánh nặng. Vì vậy, nếu bạn có thể tránh được điều đó, xin hãy làm. Nếu không thể, có những lúc bạn không biết thuật toán và bạn không biết cách viết mã, và nó không mang tính lập trình. Đó là thời điểm hoàn hảo để sử dụng một LLM như một điều phối viên. Tìm hiểu trạng thái đơn hàng là một thời điểm thực sự tệ, rất tốn kém để chọn sử dụng một LLM làm dịch vụ orchestration của bạn.
Vì vậy, đừng làm vậy. Thay vào đó, hãy tập trung vào câu chuyện "một tool bằng một agent". Và một lần nữa, ngay cả ở đây, chúng ta đang cố gắng giới thiệu một từ vựng mới: đó không phải là user story, bởi vì user story khiến mọi người nghĩ về con người, mặc dù không phải vậy. Đó là một agent story – một điều gì đó mà một Agent tự động, có lập trình, với một mục tiêu và cửa sổ ngữ cảnh hạn chế, đang cố gắng đạt được. Và chúng ta cần đáp ứng điều đó nhiều nhất có thể.
Và đây là một trong những mẹo nhỏ có vẻ hiển nhiên nhưng tôi nghĩ rất quan trọng: hãy đặt tên tool cho Agent, đừng đặt tên cho bạn. Nó không phải là một REST API. Nó không nhằm mục đích rõ ràng cho các nhà phát triển tương lai cần viết mã. Bạn không viết một API để thay đổi. Bạn viết một API để Agent chọn đúng tool vào đúng thời điểm. Đừng ngại sử dụng những cái tên có vẻ ngớ ngẩn nhưng mang tính giải thích cho tool của bạn. Tôi không nên nói là ngớ ngẩn; chúng có thể cảm thấy hơi ngớ ngẩn, nhưng chúng rất hướng tới người dùng trong khoảnh khắc này, mặc dù cảm giác như một API sâu sắc.
Chỉ trong trường hợp bất kỳ ai trong số các bạn chưa đọc bài blog của Block, tôi thấy phần này của nó rất quan trọng, nơi họ về cơ bản nói điều gì đó rất giống nhau: "Thiết kế từ trên xuống theo luồng công việc (workflow), không phải từ dưới lên từ các API endpoint." Hai cách khác nhau để đến cùng một nơi, nhưng chúng sẽ dẫn đến những hình thức tư duy sản phẩm rất khác nhau và các máy chủ LLM rất khác nhau. Vì vậy, một lần nữa, tôi thực sự khuyến khích bạn đọc bài blog đó.
Và nếu chúng ta quay lại ví dụ mã tệ mà tôi đã cho bạn xem một lúc trước và bắt đầu viết lại nó (nếu có máy tính xách tay, bạn có thể theo dõi, mã về cơ bản sẽ chạy nhưng không cần thiết), đây là những gì nó có thể trông giống như. Chúng ta đã làm điều mà một con người sẽ làm: chúng ta thực hiện ba cuộc gọi theo trình tự được cấu hình tới API của chúng ta, nhưng chúng ta đã ẩn chúng trong một tool hướng tới Agent. Và đó là cách chúng ta chuyển từ thao tác sang kết quả. Các cuộc gọi API vẫn phải xảy ra, không có phép thuật nào ở đây, nhưng câu hỏi là: chúng ta sẽ yêu cầu Agent tìm ra kết quả và cách ghép chúng lại với nhau để đạt được nó, hay chúng ta sẽ chỉ làm điều đó vì chúng ta biết cách làm thay mặt cho nó?
Đơn giản hóa đối số (Argument Flattening)
Điều thứ nhất là kết quả hơn thao tác. Điều thứ hai – thực tế, rất nhiều điều này sẽ có vẻ hơi ngớ ngẩn khi tôi nói ra. Xin hãy tin tôi từ biểu đồ tải xuống, đây là những điều quan trọng nhất mà tôi có thể đưa ra làm lời khuyên. Và nếu không có lời khuyên nào trong số đó áp dụng cho bạn, hãy nghĩ mình thuộc top 1% các nhà phát triển LLM.
Đơn giản hóa đối số của bạn (flatten your arguments). Tôi thấy điều này rất thường xuyên, tôi cũng làm điều này, tôi sẽ thú nhận với bạn, khi bạn nói: "Đây là tool của tôi và một trong những đầu vào là một từ điển cấu hình (configuration dictionary)." Hy vọng rằng nó được ghi lại ở đâu đó, có thể trong hướng dẫn của Agent hoặc trong docstring. Bạn sẽ gặp vấn đề thực sự khi (nhân tiện, tôi không nhớ liệu tôi có điểm này sau không, nên tôi sẽ nói ngay bây giờ) một cái bẫy rất thường xuyên mà bạn có thể mắc phải với các đối số phức tạp là bạn sẽ đặt giải thích cách sử dụng chúng vào một thứ gì đó như system prompt hoặc định nghĩa subagent hoặc tương tự. Và sau đó bạn sẽ thay đổi tool trong máy chủ, và bây giờ bạn thậm chí còn tệ hơn một tool được ghi lại kém: bạn có một tool được ghi lại gấp đôi, và một cái sai, một cái đúng, và chỉ có thông báo lỗi mới có thể cứu bạn. Điều đó thực sự tệ.
Đây là một phiên bản nhẹ nhàng hơn của điều đó: đừng yêu cầu LLM của bạn phát minh ra các đối số phức tạp. Bây giờ bạn có thể hỏi: "Nếu đó là mô hình Pydantic với mọi trường được chú thích thì sao?" Tốt thôi, điều đó tốt hơn từ điển, nhưng nó vẫn sẽ khó. Cho đến gần đây, có thể vẫn có một lỗi (có thể không phải là lỗi, không ai có vẻ sửa nó) nhưng trong Claude Desktop, tất cả các đối số có cấu trúc, như đối số đối tượng, sẽ được gửi dưới dạng chuỗi (string). Và điều này đã tạo ra một vấn đề thực sự vì chúng tôi không muốn hỗ trợ chuyển đổi chuỗi tự động sang đối tượng. Nhưng Claude Desktop là một trong những LLM client phổ biến nhất, vì vậy chúng tôi thực sự phải nhượng bộ điều này như một sự cần thiết. Và vì vậy Fast LLM bây giờ sẽ thử, nếu bạn đang cung cấp một đối số chuỗi cho một thứ gì đó rõ ràng là một đối tượng có cấu trúc, nó sẽ cố gắng giải tuần tự (deserialize) nó. Nó sẽ cố gắng làm điều đúng đắn. Tôi thực sự ghét việc chúng tôi phải làm điều đó; điều đó cảm thấy rất sai với tôi khi chúng tôi có một sơ đồ kiểu (type schema) nói rằng "Tôi cần một đối tượng" nhưng chúng tôi lại làm những việc cẩu thả như vậy. Và đây là một ví dụ về một hệ sinh thái đang phát triển, nó hơi lộn xộn.
Nhưng trông như thế nào khi bạn làm đúng? Nâng cấp các kiểu nguyên thủy (up-level primitives). Đây là các đối số đưa vào hàm: limit là gì, status là gì, email là gì? Được định nghĩa rõ ràng, giống như đặt tên tool cho Agent, hãy đặt tên đối số cho Agent.
Và đây là hình ảnh khi chúng ta đưa điều đó vào mã: thay vì có config: dict, chúng ta có email là một chuỗi, chúng ta có include_cancelled là một cờ. Và sau đó tôi đặc biệt khuyên dùng literals hoặc enums bất cứ khi nào bạn có thể. Tốt hơn nhiều so với một chuỗi nếu bạn biết các tùy chọn tại thời điểm này. Rất ít LLM biết rằng loại cú pháp này được hỗ trợ, và vì vậy chúng thường sẽ viết điều này (nếu bạn có Claude Code hoặc tương tự) nó thường sẽ viết format: string = basic (điều này hoạt động, nó chỉ không biết cách làm điều này). Vì vậy, đó là một trong những mẹo nhỏ có thể thực hiện được: sử dụng literal hoặc enum một cách tương đương khi bạn có một lựa chọn bị giới hạn. Agent của bạn sẽ cảm ơn bạn.
Hướng dẫn và Ví dụ cho Tác nhân
Tôi có hướng dẫn hoặc context nên tôi đã đi trước bản thân, xin lỗi mọi người, bây giờ là 4:35 chiều thứ Bảy. Điều tiếp theo tôi muốn nói đến là các hướng dẫn bạn cung cấp cho Agent. Điều này có hai mặt. Cách hiển nhiên nhất là khi bạn không có gì. Chúng ta đã đề cập điều đó một lúc trước: nếu bạn không nói cho Agent cách sử dụng máy chủ LLM của bạn, nó sẽ đoán, nó sẽ thử, nó có thể sẽ tự làm mình bối rối, và tất cả những phỏng đoán đó sẽ hiển thị trong lịch sử của nó và đó không phải là một kết quả tốt.
Xin hãy tài liệu hóa máy chủ LLM của bạn. Tài liệu hóa chính máy chủ, tài liệu hóa tất cả các tool trên đó, đưa ra các ví dụ. Các ví dụ là một con dao hai lưỡi. Một mặt, chúng cực kỳ hữu ích để chỉ cho Agent cách nó nên sử dụng một tool. Mặt khác, nó gần như luôn luôn sẽ làm bất cứ điều gì có trong ví dụ. Đây chỉ là một trong những quirks, có lẽ khi các mô hình được cải thiện, nó sẽ ngừng làm điều đó. Nhưng theo kinh nghiệm của tôi, nếu bạn có một ví dụ, giả sử bạn có một trường cho tags (thẻ), bạn muốn thu thập các tags cho một cái gì đó. Nếu ví dụ của bạn có hai tags, bạn sẽ không bao giờ nhận được 10 tags. Bạn sẽ nhận được hai tags gần như mọi lúc. Chúng sẽ chính xác, nó sẽ không làm việc tệ, nhưng nó thực sự sử dụng các ví dụ đó cho nhiều chiều hơn là chỉ thực tế là chúng hoạt động, nếu điều đó có ý nghĩa. Vì vậy, hãy sử dụng ví dụ, nhưng hãy cẩn thận với các ví dụ của bạn. Vâng, thưa ngài, bạn đang cho.
Sức mạnh của Ví dụ và Hiện tượng Out of Distribution
Hiện tượng các ví dụ out of distribution là một cách để giải quyết vấn đề. Khi tôi nói out of distribution, ý tôi là những ví dụ không được đại diện trong dữ liệu thực tế. Điều này rất thú vị và tôi không có một ý kiến mạnh mẽ nào về nó; nó có vẻ hoàn toàn hợp lý đối với tôi.
Trong kinh nghiệm của tôi, việc một ví dụ có một mẫu ngầm định nào đó, như số lượng đối tượng trong một array, đã trở thành một tín hiệu mạnh mẽ đến mức tôi gần như coi nó là một điểm riêng, gọi là "ví dụ là hợp đồng". Nếu bạn cung cấp một ví dụ, hãy mong đợi nhận được một cái gì đó tương tự. Out of distribution là một cách thực sự thú vị để chống lại sự "quán tính" đó. Tôi hình dung rằng làm theo cách đó sẽ tốt hơn, nhưng tôi sẽ cẩn thận để không rơi vào cái bẫy lớp cơ sở hơn này.
Điều đó hoàn toàn hợp lý và tôi sẽ tán thành. Tôi nghĩ đây chỉ là một điều rộng hơn: bất kỳ ví dụ nào bạn đưa ra, những đặc điểm kỳ lạ của nó sẽ xuất hiện. Trên một máy chủ mcp mà tôi đang xây dựng, tôi đã gặp phải vấn đề về thẻ này chỉ hôm qua và nó thực sự làm tôi bối rối. Dù tôi có cố gắng sử dụng ít nhất 10 thẻ, nó luôn chỉ trả về hai. Cuối cùng tôi đã tìm ra là do một trong những ví dụ của tôi chỉ có hai thẻ. Vì vậy, vâng, đó là một chiến lược tốt, có thể đủ hoặc không đủ để vượt qua những cảnh báo cơ bản này. Tôi xin lỗi, tôi có đề cập đến "ví dụ là hợp đồng" ở mục 37.
Lỗi là Lời nhắc (Errors are Prompts)
Điều này, tôi nghĩ, là một trong những điều thú vị nhất trên slide này: lỗi là lời nhắc. Mọi phản hồi mà công cụ của bạn đưa ra, Mô hình ngôn ngữ lớn (LLM) của bạn không biết rằng nó "xấu". Nó không giống như nhận được lỗi 400 hay 500. Thay vào đó, nó nhận được những gì nó xem là thông tin về việc nó không thành công trong những gì nó đang cố gắng làm.
Vì vậy, nếu bạn chỉ cho phép Python, trong trường hợp fast mcp hoặc bất kỳ công cụ nào bạn chọn, để báo lỗi ví dụ như empty value error hoặc cryptic mcp error với mã số nguyên, đó là thông tin được gửi trở lại LLM của bạn. Và liệu nó có biết phải làm gì với thông tin đó hay không? Có lẽ nó biết ít nhất là thử lại vì nó biết đó là lỗi. Nhưng bạn thực sự có cơ hội để tài liệu hóa API của mình thông qua các lỗi.
Điều này dẫn đến một số chiến lược thú vị mà tôi không muốn hoàn toàn tán thành nhưng sẽ đề cập đến, chẳng hạn như, nếu bạn có một API phức tạp (bởi vì bạn không thể tránh khỏi điều đó), thay vì tài liệu hóa mọi khả năng trong chuỗi doc string mô tả toàn bộ công cụ, bạn thực sự có thể tài liệu hóa cách khôi phục từ những lỗi phổ biến nhất.
Đây là một hình thức tiết lộ thông tin dần dần rất kỳ lạ (progressive disclosure), nơi bạn thừa nhận rằng có khả năng tác nhân này sẽ thực hiện lệnh gọi đầu tiên sai, nhưng dựa trên cách nó sai, bạn thực sự có cơ hội gửi thêm thông tin trở lại trong thông báo lỗi. Như tôi đã nói, đây không phải là một cách tuyệt vời để nghĩ về việc xây dựng phần mềm, nhưng nó là phiên bản cuối cùng của những gì tôi đang đề xuất: hãy hữu ích nhất có thể trong các thông báo lỗi của bạn. Đừng quá đà. Chúng trở thành một phần của lời nhắc tiếp theo đối với tác nhân. Và vì vậy, chúng thực sự quan trọng. Nếu chúng quá mạnh tay hoặc quá đáng sợ, nó có thể vĩnh viễn tránh công cụ đó, nó có thể quyết định công cụ đó không thể hoạt động. Vì vậy, lỗi thực sự quan trọng, và tôi không nghĩ điều này cần quá nhiều lời giải thích, nhưng đây là những gì nó trông giống như khi bạn có một doc string đầy đủ và một ví dụ, v.v.
Gợi ý Read Only cho Công cụ
Block trong bài đăng blog của họ đưa ra một điểm mà tôi chưa thấy được sử dụng rộng rãi, mặc dù ChatGPT có tận dụng điều này trong chế độ nhà phát triển, đó là gợi ý read only. Đặc tả mcp có hỗ trợ annotations, là một tập hợp con hạn chế của annotations mà bạn có thể đặt trên các thành phần khác nhau. Một trong số đó dành cho công cụ là liệu nó có phải là read only hay không, và nếu bạn cung cấp tùy chọn này, các client có thể chọn xử lý công cụ đó hơi khác một chút.
Vì vậy, động lực đằng sau gợi ý read only về cơ bản là để giúp thiết lập permissions. Và tôi không biết ai ở đây là fan của --yolo hoặc --dangerous-disabled-permissions hoặc bất cứ tên gọi nào của chúng trong các thiết bị đầu cuối khác nhau, nhưng nếu bạn không quan tâm đến điều này thì thôi. Nhưng ví dụ, ChatGPT sẽ yêu cầu bạn cấp thêm permission nếu một công cụ không có annotation này, bởi vì nó cho rằng công cụ đó có thể tạo ra tác dụng phụ và có thể có ảnh hưởng bất lợi. Vì vậy, hãy sử dụng những điều này để tận dụng lợi thế của bạn; đó là một hình thức thiết kế khác mà client có thể chọn để cung cấp trải nghiệm nhà phát triển tốt hơn.
Tôn trọng Ngân sách Mã thông báo (Token Budget)
Tôi đã nói về điều này một chút rồi: tôn trọng ngân sách mã thông báo. Tôi nghĩ hiện tại, câu chuyện vui là máy chủ GitHub gửi khoảng 200.000 mã thông báo khi bạn thực hiện handshake với nó. Đây là một vấn đề thực tế, và tôi không nghĩ nó tự động làm cho máy chủ GitHub trở nên tệ. Tôi nghĩ nó thực sự khiến những người như tôi, những người xây dựng framework, và những người xây dựng client phải tìm cách giải quyết vấn đề này, bởi vì câu trả lời không phải lúc nào cũng là "làm ít hơn". Trên thực tế, hiện tại chúng ta muốn làm nhiều hơn; chúng ta muốn có rất nhiều chức năng. Và vì vậy, chúng ta sẽ nói về điều đó có thể sau một chút, nhưng sự tôn trọng ngân sách mã thông báo thực sự quan trọng. Đó là một tài nguyên rất khan hiếm và máy chủ của bạn không phải là máy chủ duy nhất mà tác nhân sẽ nói chuyện cùng.
Gần đây tôi có một cuộc gọi với một khách hàng của mình, họ rất vui mừng vì đang triển khai mcp. Tôi đã gặp đội ngũ kỹ thuật, và để rõ ràng, đây là một công ty lớn, có tầm nhìn xa, hiệu suất cao mà tôi vô cùng kính trọng. Tôi sẽ không nói họ là ai nhưng tôi thực sự tôn trọng họ. Họ tham gia cuộc gọi và rất hào hứng, họ nói: "Chúng tôi đang trong quá trình chuyển đổi mọi thứ sang mcp để có thể sử dụng nó." Và họ có một lập luận mạnh mẽ rằng tại sao nó thực sự phải là API của họ (đó thậm chí không phải là điểm mấu chốt của câu chuyện này, bản thân nó là một câu chuyện hoàn toàn khác). Nhưng về cơ bản, vấn đề nằm ở đây: họ có 800 endpoints phải được phơi bày.
Và tôi đã có suy nghĩ này: vào thời điểm bạn đọc xong điều này, đây chính là ngân sách mã thông báo cho mỗi trong số 800 công cụ đó nếu bạn giả định 200.000 mã thông báo trong cửa sổ ngữ cảnh. Vì vậy, nếu mỗi trong số 800 công cụ đó chỉ có bấy nhiêu không gian để tự tài liệu hóa (thậm chí không phải tự tài liệu hóa, mà là chia sẻ schema, chia sẻ tên cộng với tài liệu), đây là lượng không gian bạn sẽ có. Và khi bạn hoàn thành việc sử dụng không gian này, bởi vì bạn rất cẩn thận và mỗi công cụ thực sự vừa vặn trong đó, bạn sẽ "phẫu thuật thùy não" tác nhân trong quá trình handshake bởi vì nó sẽ không còn chỗ cho bất cứ thứ gì khác. Vì vậy, ngân sách mã thông báo thực sự quan trọng. Nếu tác nhân này kết nối với một máy chủ chỉ có thêm một công cụ với một doc string một từ, nó sẽ thất bại. Nó sẽ gặp lỗi tràn (overflow) hiệu quả.
Vì vậy, ngân sách mã thông báo rất quan trọng. Có lẽ có một ngân sách phù hợp cho bất kỳ công việc nào bạn đang làm. Bạn có thể biết nó là gì, bạn có thể không biết nó là gì. Hãy giả vờ bạn biết nó là gì và lưu tâm đến nó. Trong trường hợp xấu nhất, hãy cố gắng tiết kiệm, cố gắng hiệu quả nhất có thể. Đó là lý do tại sao chúng ta thực hiện các thử nghiệm như gửi thêm hướng dẫn trong thông báo lỗi; đó là một cách để tiết kiệm ngân sách mã thông báo khi handshake. Và handshake rất "đau đớn". Tôi không chắc mọi người có biết rằng khi một LLM kết nối với một máy chủ mcp, nó thường tải xuống tất cả các mô tả cùng một lúc để nó biết những gì có sẵn cho nó, và điều đó thường không được thực hiện theo cách tiết lộ dần dần (progressively disclosed) mà được thực hiện hoàn toàn ngay lập tức. Vâng, hoàn toàn chính xác.
Thách thức về Tuân thủ Spec và Meta Tools
Được rồi, vậy điều đó thật tuyệt vời. Hãy nói về ý tưởng này một chút vì nó là một thiết kế thực sự thú vị. Hiện tại có một cuộc tranh luận về những gì bạn có thể làm tuân thủ spec so với những gì bạn làm không tuân thủ spec. Và miễn là bạn làm những điều tuân thủ spec thì cứ làm chúng thôi, ai quan tâm chứ?
Một trong những vấn đề là có những client không tuân thủ spec. Claude Desktop là một trong số đó. Tôi đã đề cập đến nó vài lần. Tôi có một lịch sử với Claude Desktop. Claude Desktop caches tất cả các công cụ nó nhận được trong lần tiếp xúc đầu tiên và đặt chúng vào một cơ sở dữ liệu SQLite. Nó không quan tâm bạn làm gì; nó không quan tâm đến việc spec cho phép bạn gửi thêm thông tin. Tôi nghĩ giải pháp của bạn sẽ vượt qua điều này vì nó là một gọi công cụ (tool call), nhưng nhiều nỗ lực đầu tiên mà mọi người sử dụng các kỹ thuật tuân thủ spec để giải quyết vấn đề này, chẳng hạn như thông báo, đều thất bại trong Claude Desktop. Thường thì bạn đã thất bại trước điều này trong Claude Desktop.
Tôi không phải là fan của Claude Desktop cho máy chủ mcp. Tôi nghĩ đó là một cơ hội bị bỏ lỡ thực sự vì nó là một sản phẩm chủ lực của công ty đã giới thiệu mcp. Tôi nghĩ đó là một cơ hội bị bỏ lỡ thực sự. Claude Code thì tuyệt vời. Nó caches mọi thứ trong cơ sở dữ liệu SQLite nên nó không thành vấn đề bạn làm gì.
Các kỹ thuật tương tự như những gì bạn đã mô tả, nơi bạn cung cấp các cơ chế để tìm hiểu thêm về một công cụ, đó là một ý tưởng tuyệt vời. Tôi thực sự thích điều đó. Có một thách thức là bây giờ bạn trở lại trong một thế giới arguments phẳng vì bạn có meta tools nơi tôi cần sử dụng công cụ để tìm hiểu về công cụ và sử dụng công cụ để gọi công cụ trong một số trường hợp cực đoan hoặc hơn thế nữa. Vì vậy, bạn cần thiết kế điều này rất cẩn thận. Đó là lý do tại sao nó thường xuất hiện như một sản phẩm chuyên dụng. Cảm ơn bạn đã chia sẻ rằng có nhiều kỹ thuật thực sự thú vị để cố gắng giải quyết vấn đề này.
Tiết lộ Dần dần (Progressive Disclosure) và Tối ưu hóa Token Budget
Bạn nói về tiết lộ dần dần (progressive disclosure) hoặc nói về các "cổng" (gates). Chẳng hạn, tôi kết nối với máy chủ trusted endpoints của mình và thông tin credentials của tôi chỉ cấp cho tôi một số quyền nhất định. Do đó, có 28 công cụ mà tôi không có quyền truy cập, vì vậy bạn không cần phải nói cho tôi biết. Vậy khi bạn nói "tôi có hỗ trợ điều đó không", ý bạn là mcp có hỗ trợ điều đó không, hay sản phẩm của tôi có hỗ trợ điều đó không? Vâng, bây giờ tôi chỉ hỏi, có điều gì đó tôi đã đọc về cách tôi dự đoán phần còn lại của điều này không?
Được rồi, spec không đưa ra tuyên bố nào về điều này. Spec nói rằng khi bạn gọi list tools, bạn sẽ nhận được các công cụ và cách điều đó xảy ra là tùy thuộc vào triển khai. fast mcp biến đó thành một hook có thể ghi đè thông qua middleware, nhưng một lần nữa, không đưa ra tuyên bố nào về cách điều đó diễn ra. Các sản phẩm thương mại có tiền tố, mà tôi không ở đây để quảng cáo, cho phép tool masking trên bất kỳ cơ sở nào và chúng tôi xem đó là một nơi để có một ý kiến có chủ đích trong bối cảnh thương mại, trái ngược với một ý kiến trong bối cảnh mã nguồn mở, trái ngược với protocol mà không nên có ý kiến gì cả. Vì vậy, nếu điều đó thú vị, chúng ta có thể trò chuyện về điều này.
Bạn có thể đang đi sâu vào vấn đề này, nhưng nếu bạn coi vấn đề này, ví dụ này như một cách tiếp cận "bảng mục lục" quản lý chung, thì có, không có cách tiếp cận nào như kiểu bạn nhìn vào bốn đoạn khác nhau, hoặc có thể 800 đoạn, tất cả đều không cần thiết phải có máy chủ mcp riêng của chúng, hoặc đó là gì đối với chúng? Chúng không thể làm được. Không có giải pháp nào cho phép chúng có nhiều thông tin như chúng muốn trên cửa sổ ngữ cảnh. Chúng không cần nó, và nó trở thành một câu hỏi thiết kế. Thành thật mà nói, cuộc gọi này có lẽ là cách đây bốn tháng rồi, và nó chỉ là cuộc gọi sau cuộc gọi sau cuộc gọi như thế này, khiến tôi nhận ra rằng chúng ta cần có nhiều cuộc nói chuyện như thế này hơn và chỉ nói về việc thiết kế một sản phẩm cho một tác nhân là như thế nào.
Mối lo lắng của tôi là mcp được coi là hạ tầng hoặc công nghệ truyền tải, và đúng là như vậy. Và tôi rất hào hứng, tôi nghĩ một năm nữa, chúng ta sẽ nói về context products thay vì mcp servers. Tôi rất hào hứng về điều đó, chúng ta sẽ vượt qua lớp truyền tải nhưng chúng ta cần tìm cách sử dụng nó. Và vì vậy, tôi nghĩ đó là cách chúng ta nói về nó.
Giải pháp thay thế duy nhất khác mà tôi đã thảo luận với một vài người, một vài công ty khi bạn gặp vấn đề như thế này là nếu bạn kiểm soát client, những điều thú vị hơn nhiều sẽ trở nên khả dụng cho bạn. Nếu bạn có thể hướng dẫn client của mình thực hiện mọi việc theo một cách nhất định, ví dụ, nếu bạn có một ứng dụng di động trình bày một tác nhân để giao diện với người dùng cuối, thì bạn kiểm soát client là điều tôi muốn nói. Hoặc nếu đó là nội bộ và bạn có thể ra lệnh client nào hoặc custom client nào một nhóm sử dụng, thì bây giờ bạn có thể làm được nhiều điều thú vị hơn bởi vì bạn thực sự biết nhiều hơn về ngân sách mã thông báo đó và cách tối ưu hóa nó. Nhưng đối với một client bên ngoài...
Hạn chế số lượng công cụ
Tôi nghĩ đến giờ chúng ta đã nói qua tất cả những điều này, vì vậy tôi sẽ để lại nó cho hậu thế. Về việc tiết kiệm thời gian, chúng ta đã nói về việc "quản lý" như một động từ khóa trong bài nói chuyện này. Tôi cho rằng, đó là những gì chúng ta đã và đang làm trong mỗi ví dụ nhỏ mà chúng ta đã thực hiện với mã. Chúng ta đang quản lý cùng một bộ thông tin để đưa về một dạng dễ tiếp cận và dễ nhận biết hơn đối với một Tác nhân.
50 công cụ là giới hạn mà tôi đặt ra cho các vấn đề về hiệu suất. Tôi nghĩ con số này có vẻ rất thấp đối với nhiều người, một số người thậm chí còn nói thấp hơn, trong khi một số khác có thể nói cao hơn. Nếu bạn có hơn 50 công cụ trên một máy chủ mà không biết bất kỳ thông tin nào khác về nó, tôi sẽ bắt đầu nghĩ rằng đó không phải là một máy chủ tốt. Máy chủ GitHub mà tôi biết có khoảng 170 công cụ, liệu điều đó có nghĩa nó không phải là một máy chủ tốt không? Không, có một lập luận hợp lý ở đây. Đội ngũ GitHub đã công bố rất nhiều bài đăng blog thú vị về semantic routing mà họ đang thực hiện. Họ vừa có một bài đăng vào hôm qua về một số kỹ thuật thú vị mà họ đang sử dụng trong phần mềm của mình, giống như kỹ thuật bạn vừa đề cập, điều này giúp giải quyết vấn đề này. Vì vậy, việc có nhiều công cụ như vậy không tự động biến nó thành một máy chủ tệ, nhưng đó là một dấu hiệu đáng quan tâm. Nó khiến tôi tự hỏi: liệu chúng ta có thể chia chúng ra không? Bạn có công cụ quản trị lẫn lộn với công cụ người dùng không? Chúng ta có thể đặt namespace cho các công cụ này một cách khác không? Liệu có đáng để có hai máy chủ thay vì một không? Đó là một dấu hiệu nhỏ. Nếu bạn có thể giảm xuống còn 5-15 công cụ, đó sẽ là lý tưởng. Tôi biết điều đó không khả thi đối với hầu hết mọi người, vì vậy đây là một trong những lời khuyên có thể thực hiện được nhưng có lẽ không quá dễ áp dụng. Đó là một khát vọng mà bạn nên có và chỉ cần cẩn thận trừ khi bạn sẵn sàng đầu tư nhiều công sức vào việc chăm sóc và đánh giá. 50 công cụ mỗi Tác nhân — tôi nên nói là mỗi Tác nhân. Nếu tôi có một máy chủ 50 công cụ và bạn cũng có một máy chủ 50 công cụ, thì đó là 100 công cụ cho Tác nhân. Đó là nơi xảy ra nút thắt cổ chai về hiệu suất, không phải trên máy chủ. Xin lỗi, các slide nên được sửa lại: 50 công cụ cho Tác nhân là nơi bạn bắt đầu thấy hiệu suất suy giảm.
Bài học từ thực tế về tối ưu hóa công cụ
Tôi rất thích câu chuyện này. Kelly Koleffel là người mà tôi đã biết từ lâu, hiện anh ấy đang làm việc tại 5.3. Khi tôi đang chuẩn bị bài nói chuyện này, tôi tình cờ đọc được hai bài đăng blog của anh ấy, giống như một 'mũi tên trúng đích' vậy. Chúng được viết cách nhau gần đúng một tháng, một bài vào tháng 10 và một bài vào tháng 11. Trong bài đầu tiên, anh ấy nói về việc xây dựng một máy chủ và chuyển từ một vài công cụ cơ bản lên tới khoảng 155-188 công cụ. Trong bài đăng blog thứ hai, anh ấy kể về cách anh ấy đã quản lý máy chủ đó, giảm số lượng công cụ từ 188 xuống còn 5. Bạn có thể đọc bất kỳ bài đăng blog nào trong số này; bạn có thể xem chúng độc lập như một câu chuyện thành công về hành trình học MCP của anh ấy. Tôi nghĩ rằng, khi được đọc cùng nhau, chúng kể một câu chuyện thực sự thú vị về việc làm cho một cái gì đó hoạt động, và sau đó làm cho nó hoạt động tốt, đó chính là hành trình sản phẩm theo một nghĩa nào đó. Và điều này đưa chúng ta đến cái mà tôi – xin lỗi, bạn có câu hỏi không? À, xin lỗi, điều này đưa chúng ta đến điều mà tôi đã tìm thấy là phiên bản rõ ràng nhất của vấn đề này.
Đừng chuyển đổi REST API thành MCP server
Tôi đã viết một bài đăng blog khá viral về chủ đề này, đó là lý do tại sao tôi thường xuyên nói về nó: xin vui lòng, nếu không có gì khác, hãy dừng việc chuyển đổi REST API thành MCP server! Đó là cách nhanh nhất để vi phạm mọi điều chúng ta đã nói hôm nay, mọi phương pháp heuristic mà chúng ta đã trình bày về các Tác nhân. Nó thực sự không hoạt động, và còn rất phức tạp. Bởi vì đây là tài liệu fast MCP – một bài đăng blog mà tôi phải viết – và bài đăng blog đó về cơ bản nói rằng: "Tôi biết tôi đã giới thiệu khả năng này, nhưng làm ơn hãy dừng lại." Đó là một điều thực sự phức tạp, bản thân nó có thể là một buổi workshop. Tôi cũng phải chịu một chút trách nhiệm ở đây. Đây không chỉ là một tính năng của fast MCP mà còn là một trong những tính năng phổ biến nhất của fast MCP, đó là lý do tại sao, nói thật, nó sẽ không biến mất. Thay vào đó, chúng tôi sẽ viết tài liệu xung quanh thực tế đó. Nhưng đây là vấn đề: bạn không thể chuyển đổi nó. Tôi sẽ không giải thích, bạn chỉ không thể chuyển đổi nó như thể các bạn trong nhóm devs đã phục vụ. Tuy nhiên, nó là một cách tuyệt vời để khởi động khi bạn đang cố gắng tìm hiểu xem liệu một cái gì đó có hoạt động hay không. Đừng viết quá nhiều mã để rồi lại tạo ra những cách mới để bạn nhận ra mình đã thất bại. Hãy bắt đầu bằng cách chọn một vài endpoint chính, mirror chúng bằng công cụ chuyển đổi tự động của fast MCP hoặc bất kỳ công cụ nào khác bạn thích, hoặc thậm chí tự viết mã đó. Hãy đảm bảo bạn giải quyết từng vấn đề một, và vấn đề đầu tiên là liệu bạn có thể khiến Tác nhân sử dụng công cụ của bạn không. Khi nó đã sử dụng được, bằng mọi cách, hãy loại bỏ phần regurgitates REST API và bắt đầu curate nó, bắt đầu áp dụng một số điều chúng ta đã nói hôm nay. Điều này chỉ là một trong những điều thẳng thắn: đó là cách nhanh nhất để bắt đầu. Bạn không cần phải làm theo cách này. Tôi bắt đầu theo cách này, nhưng đừng kết thúc bằng cách triển khai REST API lên môi trường production như một MCP server. Bạn sẽ hối hận, bạn sẽ phải trả giá sau này, mặc dù ban đầu có thể có một cảm giác 'dopamine hit'.
Các nguyên tắc chính
Vì vậy, đây là năm điều chính mà chúng ta đã nói đến hôm nay trong buổi workshop giả định của chúng ta – một buổi nói chuyện hành động chứ không phải vận hành thực sự.
- Tập trung vào
quy trình làm việctừ trên xuống: Đừng quá sa đà vào các thao tác nhỏ. Đừng yêu cầuTác nhâncủa bạn trở thànhbộ điều phốitrừ khi thực sự cần thiết. - Làm phẳng các đối số của bạn: Cố gắng không gửi các
tải trọnglớn. Cố gắng không gây nhầm lẫn choTác nhân. Cố gắng không cho nó quá nhiều lựa chọn. Tôi không nghĩ mình đã nói rõ điều này khi chúng ta thảo luận, nhưng cố gắng đừng có các đối sốtightly coupled(ràng buộc chặt chẽ) vì điều đó thực sự khiếnTác nhânbối rối. Hãy xem liệu bạn có thể thiết kế xung quanh vấn đề đó nếu có thể; không phải lúc nào cũng khả thi, nhưng nếu có thể, hãy làm. - Hướng dẫn là
ngữ cảnh: Nghe có vẻ hiển nhiên, và tất nhiên là vậy. Chúng là thông tin choTác nhân. Hãy sử dụng chúng làmngữ cảnh, thiết kế chúng nhưngữ cảnh. Thực sự hãy suy nghĩ kỹ về các hướng dẫn, giống như cách bạn suy nghĩ vềchữ ký công cụvàlược đồcủa mình. - Tôn trọng ngân sách
mã thông báo: Bạn phải làm điều này. Đây là điều duy nhất trong danh sách này mà nếu bạn không thực hiện, bạn sẽ đơn giản là không có mộtmáy chủcó thể sử dụng được. Những điều khác bạn có thể bỏ qua. Thành thật mà nói, nghệ thuật của trực giác này là bắt đầu với những quy tắc này và sau đó làm việc ngược lại để đi đến tính thực tế. Nhưng đây là điều duy nhất mà tôi nghĩ bạn không thể thực sự vượt qua giới hạn. - Gần đây, nếu bạn không làm gì khác, hãy bắt đầu với cái gì hoạt động và sau đó loại bỏ những thứ không cần thiết: Tôi đã viết
MCP servergần như lâu bằng bất kỳ ai vào thời điểm này – khoảng một năm – và tôi vẫn thấy mình bắt đầu bằng cách đưa quá nhiềucông cụvào thế giới đôi khi, bởi vì tôi không chắcTác nhânsẽ sử dụng cái nào hoặc tôi đang thử nghiệm. Và tôi phải tự nhắc nhở mình quay lại và loại bỏ chúng, điều đó thật khó khăn. Tôi nghĩ với tư cách là một kỹ sư, đặc biệt khi thiết kế cácAPIthông thường, bạn sẽ nghĩ: "Được rồi, đây làcông cụcủa tôi, đây là phiên bản 2, nó tương thích ngược phải không?" Và bạn cứ tiếp tục thêm mọi thứ, đó là một cách làm việc rất tự nhiên và có thể là mộtbest practice. Nhưng nó không hiệu quả ở đây. Bạn đang sử dụnggiao diện người dùngmà chỉ hiển thịREST APIcho người dùng. Đây là một lời chỉ trích mà tôi đã đưa ra cho các sản phẩm của chính mình đôi khi, khi tôi nghĩ: "Cái này trông quá giống tài liệuREST APIcủa chúng ta." Chúng ta không làm tốt công việc của mình để cung cấp điều này cho người dùng một cách dễ hiểu.
Tác nhân như một giao diện người dùng
Vậy, nếu tôi có thể để lại cho bạn chỉ một, nhưng chỉ một suy nghĩ, thì đó là điều này: bạn không xây dựng một công cụ, bạn đang xây dựng một giao diện người dùng. Hãy coi nó như một giao diện người dùng, bởi vì đó chính là giao diện mà Tác nhân của bạn sẽ sử dụng. Bạn có thể làm tốt hơn hoặc làm tệ hơn, và dù sao thì bạn hay người dùng của bạn cũng sẽ được hưởng lợi từ điều đó. Tôi nghĩ chúng ta đã hết thời gian, vì vậy tôi sẽ mở phần hỏi đáp hoặc những gì tiếp theo, hoặc những thách thức khác mà chúng ta có thể giải quyết. Tôi hy vọng tôi đã tìm thấy sự cân bằng giữa những điều hữu ích cho tất cả các bạn nhưng không yêu cầu bạn phải viết bất kỳ mã nào vào lúc 4:54 sáng thứ Bảy này. Nhưng tôi hy vọng tôi đã có một số thông tin hữu ích cho bạn, nhiều hơn những gì bạn đã có khi đến đây, và rất vui được trả lời bất kỳ câu hỏi nào nếu có.
Hỏi đáp về các công cụ và giao thức MCP
Câu hỏi: tightly coupled arguments là gì?
Đáp: Đó là khi bạn có một đối số như "loại tệp là gì" và một đối số khác như "chúng ta nên xử lý tệp như thế nào", và đầu vào của đối số "loại tệp" sẽ xác định các đầu vào hợp lệ cho đối số còn lại. Vì vậy, chúng tightly coupled (ràng buộc chặt chẽ). Một số đối số cho yếu tố thứ hai sẽ không hợp lệ tùy thuộc vào những gì bạn đã chọn cho yếu tố thứ nhất. Đó chỉ là một điều phụ thêm để theo dõi. Đó là một câu hỏi hay, xin lỗi vì tôi đã không định nghĩa nó.
Tôi sẽ bắt đầu với câu hỏi đầu tiên: khi bạn cung cấp cho một Tác nhân một máy chủ thực thể, liệu có nên tài liệu hóa các lệnh gọi hoặc khả năng của máy chủ trong máy chủ và trong Tác nhân không? Ý tưởng là như vậy, phải không?
Vâng, điều này phụ thuộc vào việc bạn có kiểm soát máy khách hay không. Nếu bạn kiểm soát máy khách, thì đây là một lựa chọn thực sự và có nhiều cách khác nhau để suy nghĩ về nó. Ví dụ, trong một số thứ tôi viết mà tôi biết đang sử dụng mã để truy cập, tôi có thể tài liệu hóa MCP server của mình dưới dạng tệp hoặc các skill cụ thể, bởi vì tôi biết các quy trình làm việc sẽ như thế nào. Tôi biết rằng một số quy trình làm việc của tôi không thường xuyên và tôi không muốn làm ô nhiễm không gian ngữ cảnh với chúng. Vì vậy, nếu bạn kiểm soát máy khách, bạn có một lựa chọn thực sự để đưa ra. Nếu bạn không kiểm soát máy khách, thì bạn không có nhiều lựa chọn như vậy; bạn phải tài liệu hóa nó ở đây vì bạn phải giả định rằng bạn đang làm việc với máy khách tệ nhất có thể. Thành thật mà nói, nhiều câu trả lời trong không gian MCP đều quy về câu hỏi: bạn có kiểm soát máy khách không? Nếu có, bạn có thể làm những điều thực sự thú vị ở cả hai phía của giao thức. Từ góc độ tác giả máy chủ, bạn thực sự cần tài liệu hóa mọi thứ trong doc string của nó. Một lối thoát duy nhất là bạn có thể tài liệu hóa chính máy chủ. Vì vậy, mỗi máy chủ có một trường instructions (hướng dẫn). Nó không được mọi máy khách tôn trọng. Tôi tin rằng nhóm của tôi đã nộp báo cáo lỗi khi chúng tôi xác định điều đó là đúng. Vì vậy, hy vọng đó không phải là một điều vĩnh viễn, nhưng hầu hết các máy khách khi handshake sẽ tải xuống không chỉ các công cụ và tài nguyên, mà còn một blob instructions (khối hướng dẫn) cho chính máy chủ. Bạn có thể đặt bao nhiêu thông tin vào đó? Tôi sẽ cẩn thận; tôi không nghĩ nó muốn đọc một cuốn tiểu thuyết, nhưng bạn có một cơ hội khác để tài liệu hóa có thể là cấp độ cao của máy chủ của bạn.
À vâng, vậy tại sao chúng ta không kết hợp lại và chúng ta sẽ quay lại. Bạn có câu hỏi nào không?
Vâng, tôi không phải là thành viên của ủy ban cốt lõi nhưng tôi có liên hệ rất chặt chẽ với họ, vì vậy có lẽ tôi có thể trả lời câu hỏi của bạn. Tôi rất hào hứng về điều này, vâng! Vâng, điều này tôi biết rất nhiều về nó. Nó sẽ mở rộng, nhưng thực tế sẽ không thay đổi nhiều vì cách nó được triển khai. Tôi có thể trả lời câu hỏi gì? Liệu tôi có hào hứng về nó không? Tôi rất hào hứng về... vì vậy, tất cả các quy tắc vẫn được áp dụng, đó là một câu hỏi tuyệt vời. Hãy nói về điều này trong một giây. Một số bạn, tôi không biết liệu có ai trong số các bạn đã tham dự buổi gặp mặt chúng tôi tổ chức tối qua, nơi đồng nghiệp của tôi đã trình bày không. Ồ, bạn đã tham dự à? Vâng, đúng vậy. Tôi đã nghĩ, tôi biết ít nhất có ai đó sẽ đến. Đồng nghiệp của tôi, Adam, đã có một bài nói chuyện rất hay về điều này mà tôi có thể chia sẻ sau. Tôi sẽ gửi cho bạn một liên kết đến phiên bản của nó. Nhưng phiên bản tóm tắt là: đây là SEP 1686, tên của đề xuất, và nó bổ sung các asynchronous background tasks (tác vụ nền bất đồng bộ) vào giao thức MCP không chỉ cho các công cụ mà cho mọi hoạt động. Và chúng ta không cần nói quá nhiều về điều đó. Lý do nó không liên quan đến việc thay đổi bất kỳ quy tắc nào trong số này là bởi vì đây về cơ bản là một chế độ hoạt động opt-in (chọn tham gia) trong đó máy khách đang nói: "Tôi muốn cái này được chạy bất đồng bộ", và do đó máy khách đảm nhận các trách nhiệm mới về việc kiểm tra nó và poll (truy vấn định kỳ).
Backgrounding và Tác vụ Chặn trong Thiết kế Server
...cho kết quả và thực sự thu thập kết quả. Nhưng giao diện thực tế của việc tìm hiểu về tool hoặc gọi công cụ, v.v., hoàn toàn giống như hiện tại. Vì vậy, đây là một opt-in hoàn toàn ở phía client. Và đó là lý do tại sao từ góc độ thiết kế, không có gì thay đổi. Câu hỏi duy nhất từ góc độ của nhà thiết kế server là: "Đây có phải là một việc phù hợp để chạy nền (backgrounded) thay vì thực hiện đồng bộ (synchronously) trên server không?" À, xin lỗi, để tôi nói lại. Bạn có thể chạy nền bất cứ điều gì vì nó là một framework Python, vì vậy bạn có thể đưa bất cứ thứ gì vào một framework Python. Câu hỏi đặt ra là client có nên đợi nó không, hay nó có nên là một blocking task (tác vụ chặn) không? Đó thực sự là thuật ngữ đúng cho vấn đề này. Và đó chỉ là một câu hỏi thiết kế cho người duy trì server. Liệu tôi có đang nói đúng ý của bạn không? Ồ, không đùa đâu. Vâng, điều này thực sự xảy ra rất nhiều, nhưng cho đến khi bạn nói ra, tôi không nghĩ nó là một pattern (mô hình), nhưng tôi đã thấy điều này rất nhiều. Đó là một vấn đề thực sự. Vâng, có lẽ chúng tôi sẽ viết một bài blog về nó, điều đó sẽ rất vui. Vâng, hy vọng rằng mọi thứ sẽ vẫn tiến triển. Nhưng liên quan đến elicitation, bạn thực hiện điều đó như thế nào?
Kích hoạt (Elicitation) Nâng cao trong MCP
Elicitation thực sự rất thú vị. Bây giờ chúng ta đang nói về elicitation MCP nâng cao. Có ai không quen thuộc với nó không? Vâng, elicitation về cơ bản là một cách để yêu cầu client cung cấp thêm đầu vào giữa chừng trong quá trình thực thi tool. Vì vậy, bạn lấy các đối số ban đầu cho tool, bạn thực hiện một elicitation. Đó là một yêu cầu MCP chính thức, và bạn nói: "Tôi cần thêm thông tin." Điều thú vị ở nó là nó có cấu trúc. Vì vậy, trường hợp sử dụng phổ biến nhất của điều này ở các client hỗ trợ nó là để phê duyệt, nơi bạn nói: "Tôi cần một câu trả lời có hoặc không về việc tôi có thể tiếp tục thực hiện điều gì đó có thể gây ra tác dụng phụ không thể đảo ngược hay không." Khi nó hoạt động, nó hoạt động rất tốt. Một lần nữa, đây là một trong những thứ không có sự hỗ trợ client tuyệt vời và do đó rất nhiều người không đưa nó vào server của họ, bởi vì nó sẽ làm hỏng server của bạn nếu bạn gửi thứ này đi mà client không biết phải làm gì với nó. Vì vậy, bạn phải cẩn thận một chút. Nó có thay đổi thiết kế không? Đó là một câu hỏi tuyệt vời. Tôi ước nó được sử dụng nhiều hơn để tôi có thể nói có, và bạn nên phụ thuộc vào nó nếu tất cả các client đều hỗ trợ nó và nó được sử dụng rộng rãi. Và lý do tất cả các client không hỗ trợ cái này, nhân tiện, tôi không cố ý nói rằng các client tệ. Rất phức tạp để biết cách xử lý elicitation bởi vì một số client là user-facing (hướng người dùng), khi đó rất dễ dàng, chỉ cần hỏi người dùng và cung cấp cho họ một form (biểu mẫu). Một số client được tự động hóa, một số được chạy nền ở đâu đó. Và vì vậy, việc bạn làm gì với một elicitation thực sự khá phức tạp. Nếu bạn chỉ điền nó vào như một LLM, có thể bạn đã hài lòng, có thể bạn chưa. Rất khó để biết. Vì vậy, nếu nó được sử dụng rộng rãi, tôi chắc chắn sẽ nói rằng nó mang lại cho bạn cơ hội để đưa các đối số được kết nối chặt chẽ vào một elicitation prompt hoặc các xác nhận. Rất nhiều lần bạn sẽ thấy đối với các destructive tools (công cụ phá hủy), bạn sẽ thấy xác nhận và nó sẽ mặc định là false (sai), và bạn đang buộc LLM phải thừa nhận, ít nhất là một cách để, bạn biết đấy, hy vọng đưa nó vào một chế độ hoạt động hợp lý hơn. Elicitation là một cách tốt hơn để thiết kế cho điều đó. Tôi không nghĩ điều đó đã được đưa vào ví dụ nào trong số này. Vì vậy, một câu hỏi tuyệt vời, ước gì tôi có thể nói có. Tôi hy vọng sẽ nói có về điều đó.
Xây dựng Tác nhân: MCPC so với Khung làm việc Agent
Câu hỏi thứ hai của bạn. Vâng, trong công việc của tôi, điều chính tôi làm là xây dựng các Tác nhân. Và tôi làm những thứ như Sangra hoặc Popo Nihai, TG hoặc tương tự. Và tôi thường chỉ viết các tool, và các tool đó đi vào các API. Và tôi thực sự không thấy nhu cầu về MCPC trong không gian đó. Bạn có đồng ý rằng MCPC giống như... Tôi nghĩ tôi sẽ không khuyên bạn viết một MCPC server. Vâng, tôi nghĩ rằng trong vòng một năm, lý do bạn chọn viết một MCPC server là vì bạn sẽ có khả năng quan sát tốt hơn và hiểu được những gì đã thất bại, trong khi các khung làm việc LLM không tốt lắm. Bởi vì một phần công việc của toàn bộ các khung làm việc LLM là không thất bại trong gọi công cụ và thực sự đưa nó trở lại LLM, tương tự như những gì chúng ta đã nói một lúc trước. Vì vậy, bạn thường không có khả năng quan sát tốt về các thất bại của gọi công cụ. Một số có, nhưng không phải tất cả. Và vì vậy, một trong những lý do sử dụng MCPC server ngay cả cho một trường hợp cục bộ như vậy là vì bây giờ bạn có một cơ sở hạ tầng tự động để bạn thực sự có thể debug (gỡ lỗi) và diagnose (chẩn đoán) mọi thứ. Tôi không nghĩ đó là lý do mạnh nhất để làm điều đó. Tôi nghĩ điều đó sẽ xảy ra trong một năm khi hệ sinh thái trở nên "ấm áp" hơn. Tôi nghĩ nếu bạn, nếu bạn kiểm soát hoàn toàn client và bạn đang thực hiện client orchestration (điều phối client), và bạn đang viết... nếu bạn đang viết agent loop và bạn là người duy nhất, hãy làm bất cứ điều gì bạn muốn. Tôi nghĩ rằng tất cả các lời khuyên bạn sẽ đưa ra cũng áp dụng khi bạn xây dựng các tool. Hoàn toàn đúng. Điều này, điều này, vâng, mọi thứ chúng tôi đã nói hôm nay đều áp dụng cho một tool Python, hoàn toàn đúng. Và đó là, ý tôi là, đó là cách Fast MCPC xử lý nó. Đó là một câu hỏi hay.
Chế độ Mã hóa (Code Mode)
Còn câu hỏi cuối cùng nào không? Tôi rất sẵn lòng trả lời. Vâng, vâng, vâng. Code Mode là một điều mà Anthropic, Cloudflare thực sự đã viết blog về nó đầu tiên và sau đó Anthropic đã tiếp nối. Trong Code Mode, bạn thực sự yêu cầu giải quyết một số vấn đề tôi vừa mô tả ở đây, bạn yêu cầu LLM viết mã gọi các MCP tools theo trình tự. Và đó là một cách sidestep (bỏ qua một bên) thực sự thú vị đối với rất nhiều điều tôi vừa nói ở đây. Lý do tôi không khuyến nghị nó một cách hết lòng là vì nó mang lại các vấn đề khác như sandboxing (môi trường biệt lập) và code exit (thoát mã); có những vấn đề khác với nó. Nhưng nếu bạn ở một vị trí do đó, nó có thể cực kỳ thú vị. Tôi thực sự có một đồng nghiệp đã viết bản mở rộng FastMCP hỗ trợ nó, mà chúng tôi đã đưa vào một package (gói) nào đó. Ban đầu, chúng tôi không muốn đưa vào FastMCP main vì chúng tôi không chắc chắn. FastMCP cố gắng có quan điểm riêng (opinionated), và chúng tôi không chắc chắn làm thế nào để tích hợp điều đó. Và sau đó, nó thực sự thành công đến mức chúng tôi quyết định sẽ thêm một experiments flag (cờ thử nghiệm) vào CLI (giao diện dòng lệnh) và có nó. Nhưng tôi không biết liệu nó đã được đưa vào chưa. Vâng, điều này sẽ đi vào cái mới này, tôi quên mất liệu chúng tôi gọi nó là experiments hay optimize. Nó nằm trong roadmap (lộ trình) của chúng tôi ngay bây giờ và điều này sẽ được đưa vào đó. Và sau đó, có cả một thế giới hiện nay về việc tối ưu hóa các gọi công cụ và các thứ.
Kết luận
Nhưng tôi muốn tôn trọng thời gian của bạn và cho phép tất cả các bạn trở lại cuộc sống của mình. Bạn rất tốt bụng đã dành một giờ nói chuyện về MCP với tôi. Tôi rất sẵn lòng tiếp tục nói chuyện nếu ai có câu hỏi, nhưng tôi muốn kết thúc hội nghị. Tôi hy vọng tất cả các bạn đã thích buổi nói chuyện và cảm ơn rất nhiều vì đã tham dự.