Trong kỷ nguyên số hóa, các mô hình ngôn ngữ lớn (LLM) đã trở thành xương sống của nhiều công cụ phát triển hiện đại và tác nhân AI. Chúng có khả năng tạo ra mã nguồn, nhưng một vấn đề lớn vẫn tồn tại: đầu ra thường là tĩnh.
Sau khi LLM tạo mã, bạn vẫn phải thực hiện các bước thủ công như sao chép, dán vào dự án, khởi động máy chủ phát triển, khắc phục lỗi xây dựng và tự tay kết nối logic hoặc trạng thái. Quá trình này trở nên phức tạp và tốn thời gian khi bạn phải xử lý hàng chục phần giao diện người dùng (UI) khác nhau.
Đây chính là lúc Thesys React SDK xuất hiện để thay đổi cuộc chơi. Nền tảng này cho phép bạn bỏ qua các bước tốn công đó, biến phản hồi từ LLM thành giao diện người dùng tương tác, được hiển thị trực tiếp và ngay lập tức.
Trong bài viết chuyên sâu này, chúng ta sẽ khám phá ý nghĩa thực sự của “Generative UI” (Giao diện người dùng tạo sinh), cách Thesys tạo cầu nối giữa LLM và lớp giao diện frontend, cũng như cách tích hợp Thesys vào hệ sinh thái AI của bạn bằng cách sử dụng C1 API và React SDK.
Mục lục
Thesys React SDK Mang Đến Điều Gì?
Thesys React SDK không chỉ là một công cụ, mà là một bước tiến lớn trong việc phát triển ứng dụng. Nó giải quyết triệt để vấn đề về tính tĩnh của mã nguồn do LLM tạo ra, mở ra một kỷ nguyên mới cho việc xây dựng giao diện người dùng động và thông minh.
Tóm tắt, chúng ta sẽ cùng nhau tìm hiểu chi tiết các chủ đề quan trọng sau:
- Generative UI là gì và tại sao nó quan trọng trong tương lai của phát triển ứng dụng?
- Cách Thesys hoạt động thông qua C1 API và GenUI React SDK, tạo nên một quy trình liền mạch.
- Hướng dẫn từng bước để xây dựng một Generative UI hoàn chỉnh với Thesys, từ khởi tạo đến triển khai.
- Tổng quan về các nền tảng AI lớn mà bạn có thể sử dụng kết hợp với Thesys để tối đa hóa hiệu quả.
Nếu bạn muốn tự mình khám phá Thesys, hãy truy cập thesys.dev và trải nghiệm trực tiếp tại playground của họ.
1. Generative UI Là Gì?
Nếu bạn đã sử dụng các ứng dụng như Slack, Gmail hoặc bất kỳ công cụ dashboard nào gần đây, bạn có thể nhận thấy một điểm chung: chúng trông giống nhau một cách đáng kinh ngạc.
Các giao diện người dùng truyền thống mang tính tĩnh. Mọi người dùng đều thấy cùng một bố cục, bất kể họ là ai hay mục đích sử dụng là gì. Generative UI thay đổi điều này bằng cách cho phép giao diện tự động lắp ráp và điều chỉnh linh hoạt cho từng người dùng dựa trên ngữ cảnh và nhu cầu cụ thể của họ.
Tuy nhiên, không phải tất cả các hệ thống UI dựa trên prompt đều giống nhau. Có ba loại chính mà bạn cần phân biệt:
- Prompt to Design: Kết hợp LLM với các mô hình thị giác máy tính (như diffusion hoặc GANs) để tạo bố cục thiết kế. Loại này thường được tích hợp trong các công cụ thiết kế như Figma, giúp nhà thiết kế nhanh chóng phác thảo ý tưởng.
- Prompt to UI: Sử dụng LLM (như GPT-4, Claude) để hiểu các prompt và tạo ra mã nguồn frontend/backend sẵn sàng cho môi trường sản xuất. Mục tiêu là tạo ra các đoạn mã có thể triển khai ngay lập tức.
- Generative UI: Loại này yêu cầu một thư viện UI có thể tùy chỉnh, khả năng lưu trữ ngữ cảnh người dùng (Memories), và một công cụ GenUI thời gian thực liên tục định hình lại giao diện. Thesys thuộc về danh mục này, tập trung vào việc tạo ra các giao diện động, thích ứng theo từng tương tác.
Để tìm hiểu sâu hơn về cơ chế hoạt động, bạn có thể tham khảo bài viết chi tiết của Thesys: Generative UI vs Prompt to UI vs Prompt to Design.
Hãy cùng tìm hiểu ngắn gọn về cách Generative UI hoạt động (về mặt khái niệm):
✅ 1. Hệ thống hiểu ngữ cảnh của bạn
Trong một hệ thống Generative UI, bố cục không bị mã hóa cứng. Nó thay đổi tùy thuộc vào người dùng là ai, họ đang làm gì và cách họ tương tác với ứng dụng. Hệ thống thu thập các ngữ cảnh như:
- Hành vi trong quá khứ của bạn.
- Sở thích của bạn (ví dụ: chế độ tối – dark mode).
- Loại thiết bị, kích thước màn hình, vị trí địa lý.
- Thậm chí cả thời gian trong ngày hoặc cài đặt trợ năng.
Ví dụ minh họa:
Giả sử bạn đang sử dụng một ứng dụng gọi xe. Ứng dụng phát hiện tín hiệu chuyển động và vị trí, nhận ra bạn đang lái xe và ngay lập tức chuyển sang giao diện ưu tiên giọng nói (voice-first UI). Điều này có nghĩa là các nút lớn hơn, ít yếu tố gây xao nhãng hơn, và các câu lệnh bằng giọng nói hướng dẫn bạn thực hiện các hành động như đón khách và điều hướng. Đây không chỉ là thiết kế đáp ứng (responsive design), mà là một giao diện hiểu ngữ cảnh của bạn và tự thích ứng theo thời gian thực để phù hợp với tình huống.
✅ 2. AI sử dụng thư viện UI hiện có, không “ảo giác”
AI không tự tạo ra các thành phần mới một cách tùy tiện hay “ảo giác” ra các nút bấm từ đầu. Thay vào đó, các nhà thiết kế và nhà phát triển cung cấp một thư viện có cấu trúc gồm các thành phần UI như thẻ (cards), biểu đồ (charts), modal, khối văn bản (text blocks), biểu mẫu (forms) và nhiều hơn nữa.
Đây là những thành phần đã được phê duyệt, có thể tái sử dụng. AI chỉ đơn giản là chọn từ các khối này, tuân thủ các ràng buộc về bố cục và thương hiệu đã được định nghĩa. Điều này đảm bảo tính nhất quán và chất lượng của giao diện được tạo ra.
✅ 3. Lớp AI tập hợp UI
Sử dụng ngữ cảnh có sẵn và thư viện UI được định nghĩa trước, lớp AI tạo ra một đặc tả UI có cấu trúc phù hợp với tình huống hiện tại. Nó định nghĩa các thành phần nào cần được hiển thị, cách sắp xếp chúng và dữ liệu hoặc thuộc tính nào cần truyền vào. Ví dụ: “Hiển thị biểu đồ số dư ở trên cùng, tiếp theo là bộ chọn tiền tệ và một biểu mẫu chuyển khoản được điền sẵn tài khoản đã sử dụng gần đây nhất.”
AI có thể sử dụng các mô hình học máy được đào tạo, các quy tắc heuristic đơn giản hoặc cả hai để đưa ra những quyết định này. Ví dụ: “Nếu hệ thống phát hiện người dùng khiếm thị, nó sẽ tự động bật chế độ tương phản cao.” Và khi ngữ cảnh của người dùng thay đổi, giao diện sẽ tự động cập nhật theo. Điều này tạo ra một trải nghiệm người dùng linh hoạt và cá nhân hóa tối đa.
Bây giờ chúng ta đã hiểu Generative UI hoạt động như thế nào về mặt khái niệm, hãy chuyển sang khía cạnh kỹ thuật của Thesys và cách nó biến tất cả những điều này thành hiện thực.
2. Thesys Hoạt Động Như Thế Nào Với C1 API và GenUI React SDK
Như bạn đã biết, Thesys là một nền tảng phát triển dành cho việc xây dựng các ứng dụng Generative UI. Nền tảng này hỗ trợ nhiều LLM khác nhau như OpenAI và Anthropic, mang đến sự linh hoạt đáng kể.
Có hai thành phần chính liên quan:
✅ 1) C1 API (Backend LLM)
Khi bạn gửi một prompt tới C1 API, nó sẽ trả về một đặc tả UI dựa trên JSON (hoặc XML) thay vì chỉ là văn bản thuần túy. Điều này là điểm khác biệt cốt lõi.
C1 API hoàn toàn tương thích với OpenAI (cùng endpoint/params), vì vậy bạn có thể gọi nó bằng bất kỳ client OpenAI nào (JS hoặc Python SDK) chỉ bằng cách trỏ baseURL
của bạn tới:
https://api.thesys.dev/v1/embed
Sau đó, bạn có thể gọi client.chat.completions.create({...})
với các tin nhắn của mình. Bằng cách sử dụng tên model đặc biệt (ví dụ: "c1-nightly"
), Thesys API sẽ gọi LLM và trả về một đặc tả UI.
client.chat.completions.create({
model: "c1-nightly",
messages: [...],
});
Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể sử dụng C1 theo hai cách:
a) Thay thế LLM hiện có của bạn bằng C1 cho các prompt ưu tiên UI
Nếu bạn đang xây dựng một ứng dụng mới và muốn có độ trễ tối thiểu, bạn có thể gửi trực tiếp các prompt đến c1-nightly
và nó sẽ trả về một đặc tả UI để hiển thị ngay lập tức. Điều này tối ưu hóa hiệu suất và trải nghiệm người dùng.
b) Xếp lớp C1 lên trên ngăn xếp LLM hiện tại của bạn
Nếu bạn đã có một pipeline LLM (chatbot/agent), bạn có thể lấy đầu ra của nó và truyền cho C1 như một bước thứ hai chỉ để tạo bố cục hình ảnh. Điều này giúp bạn thêm giao diện người dùng phong phú hơn vào các luồng hiện có mà không cần thay đổi logic cốt lõi của bạn.
✅ 2) GenUI SDK (Frontend)
Khi bạn nhận được đặc tả UI từ C1, GenUI SDK sẽ xử lý việc hiển thị ở phía frontend. SDK này là một framework React (được xây dựng trên thư viện thành phần của Crayon) đọc đặc tả UI dựa trên JSON và ánh xạ nó tới các thành phần trực quan.
Cốt lõi của nó là <C1Component>
(và <C1Chat>
cho các giao diện trò chuyện), chấp nhận phản hồi từ C1 API và biến nó thành UI động.
Đây là một đoạn mã mẫu:
import { C1Component, ThemeProvider } from "@thesys/genui-sdk";
const App = () => {
const response = await fetch("<your-backend-url>");
return (
<ThemeProvider>
<C1Component c1Response={response.text()} />
</ThemeProvider>
);
};
Bạn có thể đọc thêm chi tiết trên tài liệu và thử trực tiếp trên playground.
Đây là cách C1 và React SDK phối hợp với nhau để biến phản hồi của LLM thành một UI động theo thời gian thực.
3. Hướng Dẫn Từng Bước Xây Dựng Generative UI Với Thesys
Trong phần này, chúng ta sẽ đi sâu vào toàn bộ quy trình sử dụng Thesys. Tôi sẽ sử dụng Next.js để minh họa. Để giữ mọi thứ thực tế, chúng ta sẽ xây dựng một trợ lý dựa trên biểu mẫu hoạt động bằng cách sử dụng C1 và Thesys GenUI SDK.
Với hướng dẫn này, bạn có thể xây dựng:
- Một UI dựa trên prompt, nơi người dùng có thể yêu cầu các hành động như:
- “Tôi muốn đặt một chiếc khăn”
- “Hiển thị cho tôi mũ trong kho”
- LLM sau đó sẽ tạo cấu trúc UI (trường nhập liệu, bộ chọn, nút).
- Dữ liệu biểu mẫu được gửi lại cho trợ lý thông qua các công cụ được định nghĩa.
Hãy cùng bắt đầu nào!
Bước 1: Tạo ứng dụng Next.js và lấy khóa API
Chúng ta sẽ tích hợp từ đầu. Nếu bạn chưa có ứng dụng Next.js, bạn có thể cài đặt nó bằng lệnh sau:
npx create-next-app@latest thesys-demo
Đây là cấu trúc dự án mà chúng ta sẽ tuân theo:
Bạn sẽ cần tạo một khóa API mới từ C1 Console để đặt nó làm biến môi trường. Thêm khóa API này vào tệp .env
theo quy ước sau:
THESYS_API_KEY=<your-api-key>
Bước 2: Hiển thị giao diện Chat trên Frontend
Chúng ta sẽ cần một giao diện trò chuyện cơ bản nơi UI được tạo bởi các prompt. Đây là cách sử dụng <C1Chat>
cho mục đích đó trong tệp src/app/page.tsx
.
<C1Component />
chỉ cần JSON/text thô từ C1 API, nhưng đối với các ứng dụng trò chuyện, nên sử dụng thành phần <C1Chat>
vì nó hỗ trợ luồng tin nhắn (message streams).
'use client'
import '@crayonai/react-ui/styles/index.css'
import { C1Chat } from '@thesysai/genui-sdk'
export default function Home() {
return <C1Chat theme={{ mode: 'dark' }} apiUrl="/api/chat" />
}
Đoạn mã trên đang làm gì?
- Sử dụng thành phần
<C1Chat />
để hiển thị toàn bộ giao diện trò chuyện. apiUrl
trỏ đến route backend sẽ xử lý việc gửi prompt.
Như bạn thấy, đây là toàn bộ frontend mà không có mã HTML hoặc biểu mẫu thủ công nào.
Bước 3: Công cụ cho Kho lưu trữ Tin nhắn trong bộ nhớ (In-Memory Message Store)
Dữ liệu biểu mẫu sẽ được gửi lại cho trợ lý thông qua các tools
đã định nghĩa. Chúng ta sẽ xây dựng các công cụ tùy chỉnh như createOrder
, getInventory
và một kho lưu trữ tin nhắn trong bộ nhớ.
Để xử lý dữ liệu biểu mẫu và duy trì ngữ cảnh cuộc trò chuyện, chúng ta sẽ bắt đầu bằng cách tạo một kho lưu trữ tin nhắn. Công cụ này giúp lưu trữ tin nhắn của trợ lý theo từng luồng (thread).
Cài đặt gói openai. Đây là SDK Node.js chính thức để tương tác với các API của OpenAI (như GPT-4 hoặc Thesys C1, vốn tương thích với OpenAI).
npm install openai
Tạo một tệp mới tại src/app/api/chat/messageStore.ts
với đoạn mã sau:
import OpenAI from 'openai'
export type DBMessage = OpenAI.Chat.ChatCompletionMessageParam & {
id?: string
}
const messagesStore: {
[threadId: string]: DBMessage[]
} = {}
export const getMessageStore = (id: string) => {
if (!messagesStore[id]) {
messagesStore[id] = []
}
const messageList = messagesStore[id]
return {
addMessage: (message: DBMessage) => {
messageList.push(message)
},
messageList,
getOpenAICompatibleMessageList: () => {
return messageList.map((m) => {
const message = {
...m,
}
delete message.id
return message
})
},
}
}
Mỗi phần của đoạn mã đang làm gì?
- Duy trì một kho lưu trữ tin nhắn trò chuyện trong bộ nhớ, được tổ chức theo
threadId
. messagesStore
là một đối tượng JS đơn giản ánh xạ mỗithreadId
tới một mảng tin nhắn.- Tiếp lộ tiện ích
getMessageStore(threadId)
trả về các helper để:addMessage(message)
→ thêm tin nhắn mới vào luồng.messageList
→ trả về tất cả tin nhắn đã lưu cho luồng.getOpenAICompatibleMessageList()
→ trả về danh sách tin nhắn không có trườngid
, giúp nó tương thích với APIChatCompletion
của OpenAI.
Lưu ý: Kho lưu trữ này không bền vững, mọi thứ sẽ bị mất khi máy chủ khởi động lại. Bạn có thể thay thế nó bằng một cơ sở dữ liệu (Redis, PostgreSQL) để sử dụng trong môi trường sản xuất.
Bước 4: Công cụ Quản lý Đơn hàng (Order Management)
Công cụ này sẽ giúp trợ lý tạo và liệt kê các đơn hàng của khách hàng cho các sản phẩm khác nhau như găng tay, mũ, khăn quàng cổ. Nó sử dụng Zod để kiểm tra và đảm bảo tính an toàn của schema tại thời gian chạy, đồng thời lưu trữ các đơn hàng trong bộ nhớ.
Bạn không cần phải cài đặt Zod vì nó là một dependency bắc cầu. Nếu bạn kiểm tra trong tệp package.json
của nó (trong node_modules/@thesysai/genui-sdk/package.json
), bạn có thể sẽ tìm thấy dòng tương tự:
"dependencies": {
"zod": "^3.24.1"
}
Tạo một tệp mới tại src/app/api/chat/orderManagement.ts
với đoạn mã sau:
import { z } from 'zod'
export const gloveOrderSchema = z.object({
kind: z.literal('gloves'),
quantity: z.number(),
unit: z.enum(['boxes', 'pairs']),
deliveryDate: z.string(),
shipping: z.enum(['normal', 'express']),
})
export const hats = z.object({
kind: z.literal('hats'),
quantity: z.number(),
variants: z.enum(['top', 'beanie', 'cap']),
deliveryDate: z.string(),
shipping: z.enum(['normal', 'express']),
})
export const scarfOrderSchema = z.object({
kind: z.literal('scarves'),
quantity: z.number(),
colors: z.enum(['red', 'blue', 'green', 'yellow', 'purple', 'orange']),
deliveryDate: z.string(),
shipping: z.enum(['normal', 'express']),
})
export const orderSchema = z.object({
order: z.discriminatedUnion('kind', [
gloveOrderSchema,
hats,
scarfOrderSchema,
]),
})
type Order = z.infer<typeof orderSchema>
const orders: Order['order'][] = []
export const createOrder = async (orderJson: unknown) => {
const order = orderSchema.safeParse(orderJson)
if (!order.success) {
console.error('Invalid order', order.error)
return {
success: false,
error: order.error.message,
}
}
const deliveryDate = new Date(order.data.order.deliveryDate)
console.log('Creating order', { ...order.data.order, deliveryDate })
orders.push(order.data.order)
return {
success: true,
}
}
export const getOrderSchema = z.object({
number: z.number().optional().default(10),
})
export const getOrders = (params: unknown) => {
const parsedParams = getOrderSchema.safeParse(params)
if (!parsedParams.success) {
console.error('Invalid params', parsedParams.error)
return {
success: false,
error: parsedParams.error.message,
}
}
return {
success: true,
orders: orders.slice(0, parsedParams.data.number),
}
}
Đoạn mã trên đang làm gì?
- Hỗ trợ tạo đơn hàng động cho
gloves
,hats
,scarves
với các trường schema duy nhất. - Sử dụng
z.discriminatedUnion("kind", [...])
để phân loại đơn hàng dựa trên trườngkind
của chúng, cho phép xử lý nhiều biểu mẫu sản phẩm trong một schema thống nhất. - Định nghĩa một
orderSchema
cấp cao nhất bao bọc các schema riêng lẻ và đảm bảo đầu vào khớp với một trong các loại đơn hàng hợp lệ. - Tạo một mảng
orders[]
trong bộ nhớ để tạm thời lưu trữ các đơn hàng đến. - Tiếp lộ hàm
createOrder()
:- Chấp nhận đầu vào thô (
orderJson
). - Phân tích và xác thực bằng Zod.
- Ghi nhật ký và lưu trữ đơn hàng nếu hợp lệ.
- Trả về phản hồi thành công/thất bại.
- Chấp nhận đầu vào thô (
- Tiếp lộ hàm
getOrders()
:- Chấp nhận tham số
number
tùy chọn (mặc định: 10). - Trả về
n
đơn hàng gần nhất. - Hữu ích để liệt kê các hành động gần đây của người dùng trong chat hoặc UI.
- Chấp nhận tham số
- Chúng ta đã sử dụng
safeParse()
cho cả việc tạo và truy xuất để ngăn chặn lỗi thời gian chạy do đầu vào không hợp lệ.
Bước 5: Công cụ Tra cứu Tồn kho (Inventory Lookup)
Hãy tạo một công cụ giúp trợ lý lấy thông tin tồn kho sản phẩm có sẵn dựa trên loại như găng tay, mũ, khăn quàng cổ hoặc tất cả.
Tạo một tệp mới tại src/app/api/chat/inventory.ts
với đoạn mã sau. Tôi đang sử dụng dữ liệu giả (mock data) vì chúng ta chỉ chạy cục bộ.
import { z } from 'zod'
export const inventoryQuerySchema = z.object({
productType: z
.enum(['gloves', 'hats', 'scarves', 'all'])
.optional()
.default('all'),
})
const allInventory = [
{
productType: 'gloves',
quantity: 100,
priceInUSD: 10.0,
urgentDeliveryDate: '2025-04-15',
normalDeliveryDate: '2025-04-20',
imageSrc: 'https://images.unsplash.com/photo-1617118602199-d3c05ae37ed8',
},
{
productType: 'hats',
quantity: 200,
priceInUSD: 15.0,
urgentDeliveryDate: '2025-04-15',
normalDeliveryDate: '2025-04-20',
imageSrc: 'https://images.unsplash.com/photo-1556306535-0f09a537f0a3',
},
{
productType: 'scarves',
quantity: 300,
priceInUSD: 5.0,
urgentDeliveryDate: '2025-04-15',
normalDeliveryDate: '2025-04-20',
imageSrc: 'https://images.unsplash.com/photo-1457545195570-67f207084966',
},
]
export const getInventory = (params: unknown) => {
const parsedParams = inventoryQuerySchema.safeParse(params)
if (!parsedParams.success) {
console.error('Invalid params', parsedParams.error)
return { success: false, error: parsedParams.error.message }
}
return {
success: true,
inventory: allInventory.filter(
(item) =>
parsedParams.data.productType === 'all' ||
item.productType === parsedParams.data.productType
),
}
}
Đoạn mã trên đang làm gì?
- Định nghĩa một schema đầu vào
inventoryQuerySchema
bằng Zod:- Chấp nhận một trường
productType
tùy chọn ("gloves"
,"hats"
,"scarves"
hoặc"all"
). - Mặc định là
"all"
nếu không được cung cấp.
- Chấp nhận một trường
- Khai báo một mảng tĩnh
allInventory
với dữ liệu giả. Mỗi mục bao gồm số lượng, giá cả, ngày giao hàng, hình ảnh (thông tin này sẽ đến từ DB hoặc API trong thực tế). - Xuất một hàm
getInventory(params)
:- Xác thực đầu vào bằng
safeParse()
. - Lọc tồn kho theo loại nếu được chỉ định.
- Trả về phản hồi
success: true
với các mục đã lọc. - Trả về thông báo lỗi nếu đầu vào không hợp lệ.
- Xác thực đầu vào bằng
Để trả lời các truy vấn như “Có những loại mũ nào trong kho?” hoặc “Hiển thị tất cả sản phẩm”, công cụ này sẽ hiển thị các mặt hàng có sẵn kèm thông tin giá và tùy chọn vận chuyển.
Bước 6: Backend sử dụng API Route Chat
Bây giờ chúng ta cần một backend đơn giản để xử lý các lệnh gọi API tương thích với OpenAI.
Chúng ta cần xây dựng một backend để xử lý các tương tác AI (/api/chat
) bằng cách sử dụng các lệnh gọi API tương thích với OpenAI và truyền phản hồi với hỗ trợ các công cụ tùy chỉnh.
Trước khi xây dựng backend, hãy tìm hiểu về System Prompts, một phần quan trọng trong việc kiểm soát hành vi của C1.
Mặc dù C1 mạnh mẽ theo cách riêng của nó, việc hướng dẫn LLM bằng các prompt hợp lý là quan trọng để có được UI nhất quán. Thesys hỗ trợ các system prompt để:
- Xác định vai trò của trợ lý (ví dụ: “bạn là một người quản lý tồn kho hữu ích”) hoặc giọng điệu/ngôn ngữ cụ thể.
- Chỉ định hành vi hiển thị (ví dụ: luôn bao gồm hình ảnh trong danh sách).
- Thực thi các quy tắc định dạng bằng cách sử dụng thẻ
<ui_rules>
.
Đọc tài liệu chính thức để biết hướng dẫn từng bước về cách thêm system prompt vào ứng dụng AI của bạn.
Đây là một ví dụ từ tài liệu chính thức. Trên thực tế, bạn sẽ thêm prompt này vào mỗi lệnh gọi API:
const systemPrompt = `
You are a data assistant. Use tables for related info,
charts for comparisons, and carousels for lists of items.
`;
const resp = await client.chat.completions.create({
model: 'c1-nightly',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userQuery }
],
stream: true
});
Đây là đoạn mã cho src/app/api/chat/route.ts
:
import { NextRequest, NextResponse } from 'next/server'
import OpenAI from 'openai'
import { transformStream } from '@crayonai/stream'
import { DBMessage, getMessageStore } from './messageStore'
import {
createOrder,
getOrders,
getOrderSchema,
orderSchema,
} from './orderManagement'
import { zodToJsonSchema } from 'zod-to-json-schema'
import { JSONSchema } from 'openai/lib/jsonschema.mjs'
import { inventoryQuerySchema } from './inventory'
import { getInventory } from './inventory'
const SYSTEM_MESSAGE = `
You are a helpful assistant who can help with placing orders and checking inventory.
<ui_rules>
- When showing inventory, use the list component to show the inventory along with its image.
Always add the imageSrc to the list component.
</ui_rules>
`
export async function POST(req: NextRequest) {
const { prompt, threadId, responseId } = (await req.json()) as {
prompt: DBMessage
threadId: string
responseId: string
}
const client = new OpenAI({
baseURL: 'https://api.thesys.dev/v1/embed/',
apiKey: process.env.THESYS_API_KEY,
})
const messageStore = getMessageStore(threadId)
if (messageStore.getOpenAICompatibleMessageList().length === 0) {
messageStore.addMessage({
role: 'system',
content: SYSTEM_MESSAGE,
})
}
messageStore.addMessage(prompt)
const llmStream = client.chat.completions.runTools({ // OpenAI SDK v5+
model: 'c1-nightly',
messages: messageStore.getOpenAICompatibleMessageList(),
stream: true,
tools: [
{
type: 'function',
function: {
name: 'createOrder',
description: 'Create an order',
parameters: zodToJsonSchema(orderSchema) as JSONSchema,
function: createOrder,
parse: JSON.parse,
},
},
{
type: 'function',
function: {
name: 'getOrders',
description: 'Get all orders',
parameters: zodToJsonSchema(getOrderSchema) as JSONSchema,
function: getOrders,
parse: JSON.parse,
},
},
{
type: 'function',
function: {
name: 'getInventory',
description: 'Get the current inventory',
parameters: zodToJsonSchema(inventoryQuerySchema) as JSONSchema,
function: getInventory,
parse: JSON.parse,
},
},
],
})
const responseStream = transformStream(
llmStream,
(chunk) => {
return chunk.choices[0].delta.content
},
{
onEnd: ({ accumulated }) => {
const message = accumulated.filter((message) => message).join('')
messageStore.addMessage({
role: 'assistant',
content: message,
id: responseId,
})
},
}
) as ReadableStream<string>
return new NextResponse(responseStream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
},
})
}
Đoạn mã trên đang làm gì?
- Xử lý các yêu cầu POST đến
/api/chat
với prompt người dùng, thread ID, response ID. - Khởi tạo một system prompt hướng dẫn trợ lý cách hành xử và cách hiển thị UI (luôn bao gồm
imageSrc
khi hiển thị tồn kho). - Duy trì lịch sử trò chuyện trong bộ nhớ bằng
getMessageStore()
để giữ các tin nhắn theo từng luồng và tương thích với OpenAI. - Gọi API Chat Completion của Thesys (
/v1/embed/
) bằng phương thứcrunTools()
, tính năng này:- Truyền phản hồi LLM theo thời gian thực.
- Hỗ trợ nhiều công cụ tùy chỉnh:
createOrder
: để đặt hàng.getOrders
: để liệt kê các đơn hàng trước đó.getInventory
: để truy vấn thông tin tồn kho.
- Mỗi công cụ được đăng ký bằng một schema
zod
được chuyển đổi thành JSON Schema quazodToJsonSchema()
để LLM biết cấu trúc đầu vào/đầu ra. - Truyền đầu ra của trợ lý trở lại client bằng
transformStream()
:- Xử lý luồng để trích xuất nội dung LLM.
- Tích lũy phản hồi cuối cùng và lưu trữ nó trong lịch sử tin nhắn (
responseId
được sử dụng để gắn thẻ).
Và cuối cùng, trả về phản hồi text/event-stream
, cho phép frontend hiển thị nội dung dần dần khi nó được tạo ra.
🎉 Chúc mừng! Bạn đã tạo thành công một Generative UI.
Bước 7: Kết quả đầu ra
Để khởi động máy chủ phát triển cục bộ, hãy chạy npm run dev
trong terminal của bạn.
Bây giờ chúng ta đã kết nối frontend, backend và tất cả các công cụ hỗ trợ, hãy cùng xem kết quả cuối cùng.
Đây là giao diện người dùng trông như thế nào, được tạo kiểu bằng crayonai/react-ui
. Bạn có thể tương tác với trợ lý một cách tự nhiên, với những câu hỏi như “hi” hoặc “tôi muốn đặt hàng”. LLM hiểu prompt và tự động hiển thị một UI phù hợp dựa trên truy vấn của bạn.
Mỗi công cụ đều được ràng buộc schema bằng Zod và phản hồi theo thời gian thực với các khối UI hợp lệ.
Như bạn thấy, nó liệt kê các tùy chọn và thậm chí cung cấp các nút: “Đặt hàng mới”, “Kiểm tra tồn kho” và “Xem đơn hàng”.
Hãy cùng kiểm tra xem có gì trong kho. Trợ lý lấy tồn kho bằng công cụ getInventory()
và hiển thị các thẻ với thông tin sản phẩm, giá cả, tùy chọn giao hàng (các giá trị được mã hóa cứng).
Nhấp vào một sản phẩm như “Mũ” sẽ tạo ra một biểu mẫu đặt hàng hoàn chỉnh, được xây dựng theo thời gian thực bởi LLM dựa trên schema mà chúng ta đã cung cấp.
Trợ lý biết những đầu vào nào cần thiết, loại dữ liệu của chúng và thậm chí thêm các yếu tố UX như dropdown, bộ chọn ngày và nhóm radio. Sau đó, tất cả được hiển thị bởi SDK.
Sau khi gửi, dữ liệu biểu mẫu được truyền lại cho trợ lý và được xử lý bởi hàm backend thích hợp (createOrder()
), hàm này sẽ lưu trữ kết quả và xác nhận hành động.
Nó cũng sẽ liệt kê các tùy chọn khác để đặt một đơn hàng khác và kiểm tra các đơn hàng hiện có.
Bạn không phải viết một dòng mã HTML nào cho biểu mẫu, nhưng người dùng của bạn vẫn nhận được các trường nhập liệu hoạt động đầy đủ và các luồng động. Generative UI thực sự tuyệt vời và mở khóa vô vàn các trường hợp sử dụng mạnh mẽ.
4. Các Nền Tảng AI Lớn Tương Thích Với Thesys
Thesys được thiết kế để tích hợp liền mạch vào các ngăn xếp và quy trình làm việc AI hiện đại. Điều này đảm bảo rằng bạn có thể tận dụng tối đa các công cụ và nền tảng mà bạn đã quen thuộc.
Các hệ sinh thái AI mà Thesys hỗ trợ bao gồm:
- LLM: Anthropic, OpenAI (phiên bản xem trước), các mô hình tùy chỉnh (thông qua JSON có cấu trúc). Thesys mang đến sự linh hoạt trong việc lựa chọn mô hình ngôn ngữ lớn phù hợp với nhu cầu của bạn.
- Client SDKs: Các client tương thích với OpenAI tiêu chuẩn (Python, JS). Điều này giúp các nhà phát triển dễ dàng tích hợp Thesys vào các dự án hiện có mà không cần học các công cụ mới.
- Chaining Tools: Các pipeline của LangChain, LlamaIndex. Thesys có thể được sử dụng ở cuối chuỗi này để hiển thị UI dựa trên kết quả từ các pipeline phức tạp, mang lại một lớp tương tác trực quan.
- Agent Framework: Các tác nhân AutoGPT/BabyAGI có thể gọi các công cụ và hiển thị UI thông qua Thesys, mở rộng khả năng của các tác nhân AI tự động.
- Backend: Bất kỳ framework REST nào như Python, Node.js, FastAPI, Django, Next.js. Thesys cung cấp sự linh hoạt cho backend của bạn.
- Frontend: Bất kỳ framework React nào như Next.js. Thesys React SDK được tối ưu hóa để hoạt động hiệu quả với các ứng dụng React.
- Deployment: Vercel, Netlify, AWS, GCP, hoặc cơ sở hạ tầng của riêng bạn. Thesys dễ dàng triển khai trên nhiều nền tảng đám mây khác nhau.
Hiện tại, Thesys đang cung cấp 10$ tín dụng miễn phí cho người đăng ký mới, đây là cơ hội tuyệt vời để bạn bắt đầu thử nghiệm và khám phá tiềm năng của nền tảng này.
Generative UI chính là tương lai của frontend. Với Thesys, giao diện người dùng của bạn không chỉ phản hồi mà còn tự thích nghi và xây dựng chính nó từ ngữ cảnh. Hy vọng bạn đã tìm thấy những thông tin giá trị. Hãy thử ngay và xây dựng những ứng dụng đột phá!
Chúc bạn một ngày tốt lành! Hẹn gặp lại trong bài viết tiếp theo 🙂
Bạn có thể xem thêm các tác phẩm của tôi tại anmolbaranwal.com. Cảm ơn bạn đã đọc! 🥰