1. Multi‑App là gì và vì sao bạn cần
Từ trước tới nay, ta nhìn GiftGenius như một App bên ngoài duy nhất trong một cuộc trò chuyện cụ thể: người dùng chọn App của bạn trong danh sách, ChatGPT nâng các tools của bạn lên, và bạn là “nhân vật chính”. Trong Store thực tế thì khác: người dùng có thể kết nối ngay nhiều Apps, và ChatGPT sẽ quyết định gọi App nào để phản hồi yêu cầu cụ thể.
Ví dụ, trong một cuộc trò chuyện có thể có:
- App lịch nội bộ biết ngày sinh của đồng nghiệp;
- GiftGenius chuyên gợi ý ý tưởng quà tặng;
- commerce‑App của công ty có thể tạo đơn hàng và thanh toán.
Người dùng viết: “Hãy nhắc tôi về sinh nhật đồng nghiệp và gợi ý ngay nên tặng gì và mua thế nào”. Mô hình có thể lần lượt gọi ba App khác nhau: một — để lấy lịch, hai — để gợi ý quà, ba — để checkout.
Điều quan trọng: người dùng không có nút “hãy gọi App số 2 và đây là HTTP‑endpoint của nó”. Họ giao tiếp bằng ngôn ngữ tự nhiên, còn ChatGPT đóng vai trò bộ định tuyến — đọc descriptions và metadata của tất cả ứng dụng sẵn có và quyết định khi nào gọi ai.
Từ đây rút ra ba ý chính:
- Có cạnh tranh về ngữ cảnh. App của bạn phải được chọn giữa hàng chục App khác dựa trên mô tả, tên gọi và hành vi.
- Metadata trở thành “SEO cho LLM” — chính chúng quyết định mô hình có nhìn thấy GiftGenius đúng lúc hay bỏ qua.
- Cần nghĩ về khả năng tương tác: câu trả lời của bạn nên hữu ích không chỉ cho con người trong chat, mà còn cho các App khác đang đọc cùng ngữ cảnh.
Về bản chất, ta biến một ChatGPT App cô lập thành một thành phần của hệ thống lớn hơn.
2. Mô hình chọn App như thế nào: mô hình tư duy về routing
Routing trong kịch bản Multi‑App được sắp xếp đại khái như sau (đã đơn giản hóa để hữu ích cho phát triển):
- ChatGPT có danh sách App sẵn có và các tool của chúng cùng metadata (tên, mô tả, JSON Schema tham số, annotation và _meta).
- Người dùng gửi một tin nhắn.
- Mô hình xây dựng biểu diễn nội bộ về intent và về cơ bản thực hiện tìm kiếm ngữ nghĩa qua descriptions của tools và ứng dụng để hiểu công cụ nào phù hợp.
- Nếu tiêu chí khớp — nó gọi tool hoặc đề nghị mở App.
Có một điểm quan trọng: descriptions phải đủ phân biệt (discriminative). Cụm “Tìm kiếm sản phẩm” không khác mấy so với “Tìm kiếm quà tặng” hay “Tìm kiếm sách”, trong khi “Tìm ý tưởng quà tặng từ cơ sở dữ liệu đối tác của GiftGenius” thu hẹp miền và tăng cơ hội công cụ của bạn được chọn cho các truy vấn quà tặng.
Điểm thứ hai — tránh xung đột tên. Một tool tên get_data trong thế giới hàng chục App không nói lên điều gì, còn giftgenius_get_gift_catalog rõ ràng hơn nhiều, đặc biệt khi kết hợp với description mạch lạc.
Và cuối cùng, mô hình dựa vào ngữ cảnh: nếu trong chat đã nhắc đến “quà tặng”, “sinh nhật” và thậm chí tên GiftGenius, điều đó sẽ làm nổi bật App của bạn trong mắt bộ định tuyến.
3. Metadata và descriptions như LLM‑SEO
Đừng coi metadata như “thủ tục bắt buộc trong JSON”, hãy nghĩ về chúng như công việc viết nội dung sản phẩm. Khuyến nghị chính thức nói rõ: treat metadata like product copy và thiết kế “one job per tool”.
Có thể phân thành vài cấp độ mô tả:
| Cấp độ | Dành cho | Mô tả điều gì |
|---|---|---|
| Manifest description | Con người + mô hình | Nhiệm vụ của toàn bộ App: vì sao nên bật nó trong chat |
| Tool description | Mô hình (routing) | Khi nào dùng tool cụ thể và cho nhiệm vụ nào |
| Parameter descriptions | Mô hình (slot fill) | Cách điền tham số, giá trị nào hợp lệ |
|
Mô hình (UI) | Widget hiển thị chính xác điều gì và có cần trùng lặp bằng câu trả lời văn bản của mô hình không |
widgetDescription đặc biệt quan trọng trong thế giới widget: mô hình không “nhìn thấy” mã React của bạn, nó chỉ biết bạn sẽ truyền props gì và để làm gì. Trường này được điền tốt sẽ giúp nó không “bịa thay bạn”, mà ngược lại điều chỉnh câu trả lời văn bản dựa trên UI đã hiển thị.
Tài liệu Apps SDK nhấn mạnh: ChatGPT quyết định khi nào và cách gọi connector (App) của bạn dựa trên metadata. Các descriptions cẩn thận và docs về tham số nâng cao recall — tỷ lệ tình huống mà mô hình nhớ đến App của bạn — và giảm false positive.
Ví dụ nhỏ: description cũ vs mới cho GiftGenius
Giả sử trước đây ta có gì đó như:
export const appDescription = `
GiftGenius — trợ lý tìm và mua quà tặng.
`;
Với người dùng thì ổn, nhưng cho routing trong thế giới Multi‑App tốt hơn là nhấn mạnh khi nào dùng App và điều gì nó không làm:
export const appDescription = `
GiftGenius — trợ lý về ý tưởng quà tặng.
Hãy dùng ứng dụng này khi người dùng muốn nghĩ ra quà
cho một người hoặc dịp cụ thể và trong một mức ngân sách.
Không dùng cho mua sắm trực tuyến nói chung hay lập kế hoạch tài chính cá nhân.
`;
Giờ thì mô hình dễ phân biệt GiftGenius với e‑commerce App chung hay cố vấn tài chính.
4. _meta["openai/widgetDescription"]: giải thích UI của bạn cho mô hình
Trong bảng phía trên, ta đã nhắc riêng đến _meta["openai/widgetDescription"]. Giờ tập trung vào mức này: nó giúp mô hình “hình dung” widget của bạn và hiểu phần nào của câu trả lời đã được UI thể hiện, phần nào cần nói bằng văn bản.
Giả sử tool chính của ta suggest_gifts trả về danh sách quà, và widget render chúng như một băng chuyền thẻ ngang. Trong mô tả tool ta đã giải thích khi nào dùng nó, còn trong widgetDescription ta giải thích kết quả trông như thế nào.
Ví dụ đoạn mô tả tool (đơn giản hóa, dựa trên khuyến nghị):
const suggestGiftsTool = {
name: "suggest_gifts",
description: "Use this to generate gift ideas within user's budget.",
inputSchema: { /* ... */ },
_meta: {
"openai/widgetDescription":
"Hiển thị danh sách ngang các thẻ quà tặng với giá và nút 'Mua'. Đừng lặp lại tên quà trong phần trả lời văn bản."
}
};
Ở đây ta đạt được vài mục tiêu:
- Mô hình biết UI đã hiển thị tên và giá — vì vậy trong câu trả lời văn bản có thể tập trung vào giải thích và lời khuyên thay vì lặp danh sách.
- Các Apps khác (thông qua mô hình) hiểu rằng toolOutput không chỉ là một đoạn văn, mà là danh sách có cấu trúc, có thể “tiếp nhận” trong ngữ cảnh của họ.
Và đúng là viết các mô tả như vậy chán hơn code, nhưng chính chúng sẽ tiết kiệm cho bạn nhiều giờ debug hành vi kỳ lạ của mô hình.
5. Annotation của tools: readOnlyHint, destructiveHint, openWorldHint
Trong thế giới Multi‑App, quan trọng không chỉ là “khi nào gọi”, mà còn gọi có an toàn không đối với tool cụ thể. Apps SDK đưa vào một tập annotation trong descriptor của tool để hỗ trợ điều này.
Ý tưởng: annotation là các gợi ý mềm cho mô hình về bản chất thao tác. Chúng không thay thế ủy quyền phía server, nhưng ảnh hưởng mạnh đến cách ChatGPT hành xử trong chuỗi.
Tóm tắt ngắn (mang tính khái niệm):
| Chú thích | Ý nghĩa | Hành vi điển hình của mô hình |
|---|---|---|
|
Không thay đổi dữ liệu | Có thể gọi thường xuyên, không cần xác nhận rườm rà |
|
Thay đổi trạng thái (mua hàng, xóa, ...) | Hỏi người dùng xác nhận trước khi gọi |
|
Đi ra “thế giới bên ngoài” (tìm kiếm, web) | Mô hình thận trọng hơn với khối lượng và chất lượng kết quả |
Các annotation (readOnlyHint, destructiveHint, openWorldHint) là một phần của mô tả tool chuẩn và có thể dùng không chỉ trong ChatGPT. Trường _meta["openai/isConsequential"] — một tín hiệu hẹp, đặc thù cho ChatGPT, giúp mô hình phân biệt thêm giữa lời gọi “an toàn” và “có hệ quả”.
Xem hai tool của GiftGenius:
- suggest_gifts — đọc catalog, an toàn.
- create_checkout_session — tạo checkout, hành động có side‑effect rõ ràng.
Ví dụ mô tả tool suggest_gifts
const suggestGiftsTool = {
name: "suggest_gifts",
description:
"Use this when the user asks for gift ideas for a person or occasion.",
inputSchema: { /* ... */ },
annotations: {
readOnlyHint: true
},
_meta: {
"openai/widgetDescription": "Băng chuyền quà tặng với giá và liên kết.",
"openai/isConsequential": false
}
};
Một tool như vậy có thể được mô hình gọi nhiều lần liên tiếp, kể cả “đón đầu”, để chuẩn bị sẵn các phương án, không cần hỏi người dùng cho mỗi hành động.
Ví dụ mô tả tool create_checkout_session
const createCheckoutTool = {
name: "create_checkout_session",
description:
"Finalize purchase of selected gifts via Instant Checkout.",
inputSchema: { /* ... */ },
annotations: {
destructiveHint: true
},
_meta: {
"openai/isConsequential": true
}
};
Ở đây ta báo rõ: đây là write‑operation, có hệ quả (tiền bị trừ, đơn hàng được tạo), và mô hình cần yêu cầu người dùng xác nhận trước khi gọi, nhất là trong các chuỗi dài có nhiều App.
Đừng kỳ vọng phép màu: ngay cả với destructiveHint, bạn vẫn phải kiểm tra lại dữ liệu vào, token và quyền trên server, như đã bàn trong các mô‑đun về bảo mật và ủy quyền. Nhưng xét về orchestrations Multi‑App, các annotation giúp mô hình không “bắn” các tool như vậy khi không cần thiết.
6. App cô lập vs hệ sinh thái: làm rõ ranh giới của GiftGenius
Khi GiftGenius là App duy nhất trong chat, ta có thể cho phép scope khá rộng: chọn quà, tư vấn gói quà, nhắc ngày lễ, thậm chí viết vài đoạn chúc mừng. Mô hình dù sao cũng chỉ gọi các tool của bạn.
Trong kịch bản Multi‑App, cách “tôi làm mọi thứ” bắt đầu gây hại:
- bộ định tuyến khó phân biệt khi nào bạn là ứng viên lý tưởng, khi nào nên dùng App khác;
- bạn chồng lấn với lịch, trình quản lý tác vụ chung, cố vấn tài chính, v.v.;
- khi dùng chung nhiều ứng dụng, mô hình có thể chọn “nhầm” và lẫn lộn công cụ.
Cách tốt hơn — giới hạn rõ ràng phạm vi trách nhiệm:
- GiftGenius: chỉ ý tưởng quà tặng + hỗ trợ mua qua ACP/Checkout;
- CalendarApp: sự kiện và nhắc nhở;
- Finance‑App: ngân sách tổng thể của người dùng, kế hoạch tài chính cá nhân.
Trong mô tả App và tool, hữu ích khi ghi rõ không chỉ “Use this when…”, mà cả “Do not use when…”. Discovery‑playbook chính thức cũng khuyến nghị như vậy.
Ví dụ nhỏ về mô tả tool:
description: `
Use this tool when the user explicitly asks for gift suggestions.
Do not use for generic product discovery or price comparison.
`
Các ràng buộc như vậy không chỉ giúp routing, mà còn làm hành vi App của bạn dễ dự đoán hơn cho sản phẩm và QA.
7. Mẫu composition Apps: pipeline, handoff, shared context
Trong các kịch bản Multi‑App, ba ý liên quan sau thường xuất hiện:
- pipeline — nhiều App chạy nối tiếp (lịch → quà → commerce), mỗi App làm một bước;
- handoff — đầu ra của App này trở thành đầu vào của App tiếp theo;
- shared context — toàn bộ truyền đạt diễn ra qua ngữ cảnh văn bản chung của chat, không có HTTP‑call trực tiếp giữa ứng dụng.
Như đã gợi ý, kịch bản Multi‑App không phải phép màu “App A gọi App B qua HTTP”. Ở phiên bản hiện tại của ChatGPT Apps, sự cô lập khá chặt: ứng dụng không gọi nhau trực tiếp, giao tiếp diễn ra qua ngữ cảnh văn bản chung.
Mẫu cơ bản có thể mô tả như sau:
- App A trả về văn bản hoặc JSON vào chat (thường bên trong structuredContent/widget).
- Mô hình đọc đầu ra này.
- Ở lượt sau, nó có thể gọi App B, điền chi tiết từ câu trả lời A vào tham số của tool bên B.
Đây được gọi là text/context handoff: “Đầu ra App A → mô hình → đầu vào App B”.
Ví dụ: CalendarApp + GiftGenius + CommerceApp
Hãy phân tích một kịch bản cụ thể.
Người dùng: “Sếp có sinh nhật vào ngày mai, hãy chọn quà và tạo đơn mua luôn.”
Theo từng bước:
-
Mô hình hiểu cần xác định ngày và người. Nó gọi tool của App lịch, giả sử corporate_calendar.list_upcoming_birthdays, và nhận cấu trúc:
[ { "name": "Aleksey Bykov", "date": "2025-11-22", "relation": "manager" } ] -
Sau đó mô hình quyết định đã đến lúc gọi GiftGenius. Nó gọi suggest_gifts của bạn với tham số lấy từ lịch:
{ "recipientName": "Aleksey", "occasion": "birthday", "budget": 150, "relationship": "manager" }Widget GiftGenius hiển thị băng chuyền quà tặng, còn câu trả lời văn bản giải thích vì sao các ý tưởng này phù hợp.
-
Người dùng chọn một hai phương án (bằng nút trong widget → widgetState), và mô hình gọi tool của commerce‑App, ví dụ corp_checkout.create_gift_order, với ID SKU đã chọn và địa chỉ giao hàng.
Với ChatGPT đây là ba ứng dụng khác nhau, nhưng với người dùng — một cuộc trò chuyện thống nhất. Chìa khóa để điều này hoạt động:
- descriptions rõ ràng cho tool của mỗi App;
- tên gọi cẩn thận (corporate_calendar.list_upcoming_birthdays, thay vì chỉ list_events);
- định dạng dữ liệu có cấu trúc thống nhất (để ý tưởng quà được mô tả theo cách commerce‑App có thể hiểu).
Sơ đồ trực quan
Có thể minh họa pipeline như sau:
sequenceDiagram
participant U as Người dùng
participant C as ChatGPT (Router)
participant Cal as CalendarApp
participant G as GiftGenius
participant Com as CommerceApp
U->>C: Sếp mai sinh nhật, hãy chọn và mua quà
C->>Cal: tools.call(list_upcoming_birthdays)
Cal-->>C: [{ name, date, relation }]
C->>G: tools.call(suggest_gifts, { recipient, occasion, budget })
G-->>C: gift suggestions (+ widget)
C-->>U: Giải thích + widget GiftGenius
U->>C: Thích phương án #2, hãy mua nó
C->>Com: tools.call(create_gift_order, { skuId, address })
Com-->>C: Xác nhận đơn hàng
C-->>U: Xong, đã đặt hàng
Nhiệm vụ của bạn với tư cách người phát triển GiftGenius — để “giọng” của bạn vang lên rõ ràng và đúng chỗ trong “dàn hợp xướng” này, không gây nhiễu những người khác.
8. Khả năng tương tác: làm cho câu trả lời hữu dụng với App khác
Trong thế giới Multi‑App, chỉ “trả lời đẹp cho người” là chưa đủ. Tốt nhất, toolOutput của bạn có thể được xử lý bằng máy bởi ứng dụng khác: commerce‑App, agent phân tích, workflow‑orchestrator, v.v.
Điều này kéo theo vài điểm thực tế:
- dùng JSON có cấu trúc trong phản hồi của tools, thay vì chuỗi “tự nhiên”;
- cố gắng giữ các trường ổn định, dễ hiểu.
Ví dụ, có thể định kiểu kết quả của suggest_gifts như sau:
export type GiftSuggestion = {
id: string;
title: string;
description: string;
price: number;
currency: string;
forPerson: string;
occasion: string;
purchaseUrl: string;
};
Và tool trả về một mảng đối tượng kiểu này:
{
"gifts": [
{
"id": "sku_123",
"title": "Mô hình thiên văn để bàn",
"description": "Máy chiếu bầu trời sao mini...",
"price": 89.99,
"currency": "USD",
"forPerson": "Aleksey",
"occasion": "birthday",
"purchaseUrl": "https://shop.example.com/sku_123"
}
]
}
Widget GiftGenius nhận chúng làm props và render thẻ đẹp mắt, còn commerce‑App, khi thấy JSON này trong ngữ cảnh, có thể lấy id và purchaseUrl để tiếp tục checkout.
Thực tế Multi‑App cho thấy: một App tốt trả dữ liệu theo cách App khác có thể “ăn được”, không chỉ để mắt người đọc.
9. Refactor thực tiễn GiftGenius cho Multi‑App
Hãy gom lại thành vài thay đổi cụ thể cho ứng dụng học tập của ta.
Làm rõ manifest‑description
Giả sử ta có openai-app.json (hoặc tương đương trong mẫu Next.js) với mô tả:
{
"name": "GiftGenius",
"description": "Gift assistant for finding and buying presents."
}
Ta làm nó rõ ràng hơn cho routing:
{
"name": "GiftGenius",
"description": "Assistant for gift ideas and purchase flows. Use this app when the user asks what to gift a specific person or for a specific occasion within a budget. Do not use for generic online shopping or personal finance planning."
}
Giờ từ văn bản này đã thấy ngay đây không phải mua sắm chung, không phải cố vấn tài chính và cũng không phải lịch.
Viết lại descriptions của tools
Tool tìm kiếm quà:
const suggestGiftsTool = {
name: "giftgenius_suggest_gifts",
description: `
Use this when the user asks for gift ideas for a specific person or group,
optionally with a budget or occasion.
Do not use for non-gift product recommendations or travel booking.
`
};
Tool kéo chi tiết SKU từ catalog của bạn (read‑only):
const getGiftDetailsTool = {
name: "giftgenius_get_gift_details",
description: `
Use this to fetch more details for a gift suggested earlier by GiftGenius,
for example when the user asks “tell me more about option #2”.
`,
annotations: { readOnlyHint: true }
};
Tool mua hàng — với destructiveHint, như đã minh họa.
Cập nhật _meta["openai/widgetDescription"]
Giả sử widget của ta đã có các thẻ với CTA “Mua”. Hãy gợi ý điều này cho mô hình:
const giftWidgetMeta = {
_meta: {
"openai/widgetDescription": `
Hiển thị danh sách thẻ quà tặng với mô tả, giá và nút 'Mua'.
Mô hình không nên lặp lại toàn bộ danh sách trong văn bản, chỉ nên bình luận cách chọn và hỗ trợ quyết định.
`
}
};
Giờ mô hình sẽ ít khi viết một “tấm chăn” mười món quà trong chat nếu chúng đã hiển thị trong widget, mà tập trung vào giải thích và lý do — vừa tốt cho UX vừa tiết kiệm token.
10. Tư duy Multi‑App cho sản phẩm tương lai của bạn
Quan trọng là chuyển tư duy từ “làm sao đánh bại mọi đối thủ và trở thành App duy nhất của người dùng” sang “làm sao khiến App của mình trở thành mô‑đun lý tưởng trong hệ sinh thái lớn”.
Cách tiếp cận này đem lại vài lợi ích thực tế:
- bạn dễ giải thích cho người dùng và reviewer của Store là vì sao App của bạn cần thiết và khi nào phù hợp;
- mô hình dễ quyết định routing hơn: ít nhầm lẫn, ít lời gọi “không đúng chỗ”;
- bạn có thể chủ động thiết kế composition: hôm nay — với lịch và commerce, ngày mai — với HR‑bot nội bộ hoặc CRM bên trong.
Các hướng dẫn chính thức về discovery nhấn mạnh: thiết kế “one job per tool”, và coi metadata là một artefact sống, cần test và cập nhật, không phải văn bản tĩnh từ commit đầu tiên.
Những gì bạn đã làm ở các chủ đề trước của Module 20 sẽ rất hữu ích: golden‑cases, LLM‑evals, CI‑run. Bạn có thể mở rộng bộ case với kịch bản “trong chat có cả GiftGenius và CalendarApp”, và theo dõi cách thay đổi mô tả ảnh hưởng đến việc chọn App và chất lượng trả lời.
11. Các lỗi điển hình khi làm việc với Multi‑App và composition
Lỗi số 1: mô tả App kiểu “tôi làm được mọi thứ”.
Nếu bạn viết trong manifest‑description kiểu “trợ lý thông minh cho mọi nhiệm vụ”, bạn cạnh tranh không chỉ với App khác mà còn với ChatGPT gốc. Bộ định tuyến khó hiểu khi nào buộc phải gọi bạn, khi nào chỉ cần khả năng tích hợp sẵn. Trong thế giới Multi‑App, thắng thế là các ứng dụng có mục đích rõ, hẹp: “chọn quà”, “quản lý lịch”, “phân tích log”.
Lỗi số 2: descriptions tool mơ hồ và xung đột tên.
Các tool tên get_data, process_request và mô tả “xử lý dữ liệu người dùng” rất phù hợp... để làm mô hình bối rối. Trong thế giới nhiều App, bạn dễ rơi vào tình huống tool của bạn được gọi sai miền. Cách đúng — gắn miền và hành động (giftgenius_get_gift_catalog, calendar.list_birthdays) và mô tả rõ “Use this when… / Do not use when…”.
Lỗi số 3: bỏ qua _meta["openai/widgetDescription"].
Nhà phát triển thường chỉ điền description, còn _meta thì cùng lắm nhớ tới vì locale. Hệ quả: mô hình không hiểu widget hiển thị gì, và hoặc lặp UI bằng văn bản, hoặc hứa với người dùng “bảng giá” mà widget của bạn không có. Vài dòng trong widgetDescription giúp tránh nhiều hiểu lầm như vậy.
Lỗi số 4: thiếu annotation readOnlyHint/destructiveHint.
Nếu tất cả tool của bạn trông “trung tính” như nhau, mô hình không phân biệt tool nào an toàn để gọi thường xuyên, tool nào cần người dùng xác nhận. Trong các kịch bản nhiều bước với nhiều App, điều này đặc biệt nghiêm trọng: có thể vô tình thực hiện vài write‑operation liên tiếp mà không có sự tham gia rõ ràng của người. Đừng quên đánh dấu read‑only‑tools và làm nổi bật các hành động consequential/destructive.
Lỗi số 5: câu trả lời chỉ nhắm tới con người, không nhắm tới App khác.
Trả về từ tool chỉ là “danh sách quà” trong một dòng văn bản nghe có vẻ hấp dẫn, nhưng khi đó mọi App khác khó dùng kết quả này. JSON có cấu trúc với các trường rõ ràng (id, price, currency, purchaseUrl, occasion) cho bạn lợi thế cả trong UI lẫn composition: mô hình có thể nhét các dữ liệu này vào tham số tool khác mà không cần parse ngôn ngữ tự nhiên.
Lỗi số 6: cố gắng nhét mọi thứ người dùng có thể cần vào một App.
Đôi khi ta muốn: “đã làm GiftGenius thì để nó quản lý lịch, gửi mail cho đồng nghiệp, và lập ngân sách luôn”. Trong thế giới cô lập có thể còn chịu được, nhưng trong bối cảnh Multi‑App bạn biến thành máy “tất cả trong một” xung đột với các App hẹp, tinh gọn khác. Đúng hơn là thỏa thuận với chính mình: App của tôi làm X và làm X thật tuyệt; còn lại là trách nhiệm của người khác. Thiết kế như vậy đơn giản hóa mạnh UX và phát triển hệ sinh thái.
Lỗi số 7: không test hành vi trong môi trường có App khác.
Nhà phát triển thường test App của mình ở Dev Mode trong chat “sạch”, không có App khác. Nhưng trong Store, người dùng dễ có cả chục App được kết nối, một phần trong số đó trùng khái niệm với bạn. Hãy tạo kịch bản test có App lân cận (lịch, mua sắm chung, tài chính), và chạy golden‑cases: mô hình có chọn GiftGenius đúng cho truy vấn quà không, và có nhầm với người tham gia khác không?
GO TO FULL VERSION