GPT-Live, mô hình giọng nói full-duplex của OpenAI, được thiết kế sẵn cho hội thoại thời gian thực. Thay vì chờ người dùng nói xong một lượt, nó xử lý luồng âm thanh đang đến một cách liên tục và quyết định ngay lúc đó cần làm gì.
Điều này dẫn tới một câu hỏi đơn giản: liệu ta có thể dạy một mô hình ngôn ngữ nhỏ sẵn có tương tác theo cách tương tự, mà không phải huấn luyện lại từ đầu?
Vì sao chỉ dùng văn bản?
GPT-Live được xây cho giọng nói: đầu vào là âm thanh và đầu ra cũng là âm thanh. Dự án của chúng tôi thì ngược lại, chỉ dùng văn bản.
Lý do chính là thực tế. Huấn luyện một mô hình giọng nói thời gian thực từ đầu sẽ cần lượng dữ liệu âm thanh rất lớn cùng năng lực tính toán đáng kể — thứ mà chúng tôi tiếc là không có.
Tuy nhiên, phần lớn những câu hỏi chúng tôi muốn trả lời lại không gắn riêng với giọng nói. Mô hình nên hành xử thế nào khi đầu vào vẫn đang đến? Khi nào thì nên trả lời, nên chờ, hay nên hành động? Những hành vi này có học được qua post-training không? Dù giọng nói là bối cảnh rõ ràng nhất cho tương tác thời gian thực, ta vẫn có thể nghiên cứu đúng những câu hỏi đó bằng một phiên bản xấp xỉ dựa trên văn bản, thay luồng âm thanh liên tục bằng một luồng token văn bản liên tục.
Văn bản cũng khiến hệ thống dễ soi xét hơn. Âm thanh phải được phiên âm và cắt đoạn trước khi con người đọc được, trong khi ở thiết lập của chúng tôi, mọi ảnh chụp đầu vào, mọi quyết định và mọi hành động đều đã được ghi lại dưới dạng văn bản. Nhờ vậy ta có thể lần lại chính xác mô hình đã nhận được gì và hành vi của nó thay đổi ra sao khi đầu vào mới xuất hiện.
Khả năng
Đưa tương tác thời gian thực vào bên trong mô hình mở ra những khả năng mà bình thường phải để phần khung chương trình xử lý. Các demo dưới đây cho thấy một số hành vi mà chúng tôi đã huấn luyện cho mô hình.
Xen lời. Mô hình có thể trả lời khi ngữ cảnh cho phép, thay vì chờ người dùng gõ xong.
Dịch trực tiếp. Mô hình có thể dịch ngay trong lúc người dùng đang gõ, thay vì chờ một tin nhắn hoàn chỉnh.
Điều phối hội thoại. Mô hình có thể suy ra người dùng đang suy nghĩ, đang ngập ngừng, hay đang mời mình lên tiếng, nhờ đó tự quyết định khi nào im lặng và khi nào nói.
Gọi công cụ song song. Mô hình có thể tiếp tục tương tác với người dùng trong khi khởi chạy nhiều tác vụ chạy song song ở nền, rồi lồng kết quả trở lại cuộc trò chuyện khi từng tác vụ hoàn tất.
Cách tiếp cận
Chúng tôi biểu diễn đầu vào đang thay đổi của người dùng thành các sự kiện có dấu thời gian, huấn luyện mô hình chọn một hành động cho mỗi sự kiện, rồi tối ưu suy luận để những quyết định đó kịp thời gian thực.
Thay đổi đầu tiên nằm ở cách biểu diễn tương tác. Trong một hệ thống theo lượt, mô hình chờ người dùng viết xong tin nhắn rồi mới trả lời. Thiết lập của chúng tôi thay những lượt hoàn chỉnh đó bằng một luồng liên tục. Khi người dùng gõ, hệ thống chụp lại trạng thái hiện tại của ô nhập liệu mỗi 650 ms và thêm vào lịch sử của mô hình.
Theo lượt
Đầu vào và đầu ra bị làm phẳng thành một chuỗi token có thứ tự
Theo micro-turn, gắn với thời gian
Luồng đầu vào và đầu ra liên tục, được chia thành các micro-turn
→
Một luồng liên tục giữ lại những khoảnh khắc mà tương tác theo lượt thường bỏ đi. Một quãng dừng không kết thúc cuộc tương tác, và một ô nhập liệu trống hoặc không đổi vẫn là một quan sát. Những quan sát này giúp mô hình suy ra người dùng đang gõ tiếp, đang nghĩ, đang sửa, hay đang chờ câu trả lời.
Mỗi quan sát trở thành một sự kiện luồng có dấu thời gian. Các sự kiện này được đan xen với những hành động trước đó của mô hình, tạo thành một lịch sử gồm cả những gì mô hình đã thấy lẫn cách nó đã phản ứng.
<stream_event index="1" source="user" state="active" time="t+650ms">
Do you think I should
</stream_event>
<action>idle()</action>
<stream_event index="2" source="user" state="active" time="t+1300ms">
Do you think I should call it a night?
</stream_event>
<action>respond({"for":2,"message":"You should!"})</action>
<stream_event index="3" source="user" state="idle" time="t+1950ms">
</stream_event>
<PREDICT_THIS_ACTION>
Với lịch sử sự kiện này, mô hình dự đoán đúng một hành động cho sự kiện mới nhất. Nó phải quyết định không chỉ nên làm gì, mà còn là khoảnh khắc hiện tại có cần hành động nào hay không.
Mô hình chọn từ một bộ ngữ pháp đóng gồm sáu hành động:
idle— im lặng; hành động mặc định và cũng là hành động đúng phổ biến nhất.respond— trả lời, xác nhận, dịch, hoặc bắn một lời nhắc.highlight— đánh dấu một lần xuất hiện cụ thể của một đoạn văn bản.delegate— khởi chạy một tác vụ nền bất đồng bộ.web_search— gửi một truy vấn tìm kiếm và nhận kết quả về dưới dạng một sự kiện đến sau.translate_commit— nối thêm một đơn vị bản dịch đã ổn định trong khi văn bản gốc vẫn đang đến.
Bộ ngữ pháp hành động đóng này khiến mỗi dự đoán đều dễ kiểm chứng và dễ thực thi. Vì chính mô hình chọn hành động, phần runtime chỉ việc thi hành. Runtime không quyết định người dùng đã nói xong hay chưa, mô hình có nên xen vào hay không, hay có nên im lặng hay không.
Những sự kiện có dấu thời gian này cũng cho mô hình một cách biểu diễn thời
gian tường minh. Thay vì nhận thời gian như một chiều đầu vào có sẵn, mô hình
đọc các dấu thời gian như t+1950ms, so sánh sự kiện mới nhất với lịch sử
trước đó, rồi quyết định khoảnh khắc hiện tại có đòi hỏi hành động hay không.
Tổng quan hệ thống
Hệ thống của chúng tôi đi theo cùng một mẫu hai mô hình mà interaction models của Thinking Machines Lab và GPT-Live của OpenAI sử dụng: một mô hình thời gian thực giữ liên hệ trực tiếp với người dùng, còn phần việc nặng hơn thì được uỷ thác bất đồng bộ. Tuy nhiên, cách hiện thực của chúng tôi khác ở ba quyết định thiết kế.
Quyết định thứ nhất liên quan tới việc uỷ thác. Trong khi kiến trúc tham chiếu chỉ có một mô hình nền duy nhất, hệ thống của chúng tôi cho phép mỗi lần uỷ thác sinh ra một tác vụ nền riêng. Các tác vụ này có thể chạy song song, nhờ đó Text GPT-Live vẫn tiếp tục tương tác với người dùng trong khi nhiều việc nặng được hoàn tất cùng lúc.
Quyết định thứ hai liên quan tới việc dùng công cụ. Trong khi kiến trúc tham chiếu chủ yếu giao công cụ cho mô hình nền, hệ thống của chúng tôi giao công cụ cho cả Text GPT-Live lẫn các tác vụ nền được sinh ra. Bộ công cụ của hai bên phản ánh hai vai trò khác nhau: tác vụ nền dùng những công cụ nặng về tính toán cho các việc như sinh giao diện, hình ảnh hay mã nguồn, còn Text GPT-Live dùng những công cụ nhẹ phục vụ trực tiếp cho tương tác đang diễn ra, chẳng hạn đánh dấu văn bản và dịch tăng dần. Cách phân chia này cho phép mô hình thời gian thực tác động lên giao diện chung mà không phải gánh phần việc làm gián đoạn tương tác.
Quyết định thứ ba liên quan tới cách các tác vụ nền trao đổi với Text GPT-Live. Trong khi mô hình nền của Thinking Machines Lab có thể gửi lại một phản hồi có nội dung cho mô hình tương tác, các tác vụ nền của chúng tôi chỉ phát ra những cập nhật trạng thái có cấu trúc và một kết quả cuối cùng. Những cập nhật này cho biết một tác vụ đã bắt đầu, đã xong, hay đã thất bại, nhờ đó Text GPT-Live theo dõi được nhiều tác vụ cùng lúc và lồng kết quả trở lại cuộc trò chuyện khi chúng lần lượt về. Giao thức đơn giản hơn này khiến việc uỷ thác song song dễ quản lý hơn, nhưng cũng giới hạn những loại tác vụ mà hệ thống hỗ trợ được: một số tác vụ cần làm rõ yêu cầu, cần phản hồi trung gian, hoặc cần một cuộc trao đổi kéo dài giữa mô hình trực tiếp và mô hình nền, chứ không chỉ một cập nhật trạng thái và một kết quả cuối. Hỗ trợ những tác vụ đó sẽ đòi hỏi một giao thức trao đổi phong phú hơn.
Dữ liệu
Chúng tôi huấn luyện mô hình đưa ra từng quyết định một, thay vì hoàn tất trọn một cuộc hội thoại. Để tạo ra những quyết định này, chúng tôi dùng các tác tử LLM để viết ra những kịch bản tương tác hoàn chỉnh theo lược đồ có cấu trúc. Mỗi kịch bản quy định người dùng gõ gì, chỗ nào có quãng dừng hay chỉnh sửa, và chỗ nào mô hình nên hành động.
Sau đó, một trình biên dịch tất định khai triển mỗi kịch bản thành một luồng liên tục các ảnh chụp ô nhập liệu, cách nhau 650 ms. Mọi ảnh chụp đều ở lại trong lịch sử sự kiện, cùng với tất cả hành động trước đó của mô hình. Từ luồng này, chúng tôi chọn ra những khoảnh khắc mà quyết định mang nhiều thông tin nhất: ngay trước khi một hành động trở nên phù hợp, đúng lúc nó trở nên phù hợp, và ngay sau khi nó đã được thực hiện. Chúng tôi cũng đưa vào những khoảnh khắc yên ắng bình thường và những trường hợp gây nhiễu có thể khiến mô hình hành động quá sớm.
Ví dụ:
Do you think I should call it a night? → respond("You should!")
[tick 1] Do you think → idle() [tick 2] Do you think I should call it → idle() [tick 3] Do you think I should call it a night? → respond("You should!") [tick 4] Do you think I should call it a night? → idle()
History: [tick 1] Do you think → idle() [tick 2] Do you think I should call it → <PREDICT_THIS_ACTION> Target: idle()
History: [tick 1] Do you think → idle() [tick 2] Do you think I should call it → idle() [tick 3] Do you think I should call it a night? → <PREDICT_THIS_ACTION> Target: respond("You should!")
History: [tick 1] Do you think → idle() [tick 2] Do you think I should call it → idle() [tick 3] Do you think I should call it a night? → respond("You should!") [tick 4] Do you think I should call it a night? → <PREDICT_THIS_ACTION> Target: idle()
Những nhịp được chọn sau đó trở thành ví dụ huấn luyện. Mỗi ví dụ chứa toàn bộ lịch sử tương tác có được tại khoảnh khắc đó, bao gồm cả những hành động trước đó của mô hình, còn hành động kế tiếp được kỳ vọng thì trở thành mục tiêu.
Cấu trúc này biến thời điểm thành một phần của việc giám sát. Bằng cách lấy mẫu các khoảnh khắc trước, trong và sau một hành động, mô hình học được cách chờ cho tới khi hành động là phù hợp, hành động đúng lúc, và không lặp lại một hành động đã làm.
Chúng tôi áp dụng phương pháp này qua ba lượt SFT nối tiếp, mỗi giai đoạn bổ
sung thêm dữ liệu và khả năng mới. Ở lượt đầu tiên, khoảng 68,5% số ví dụ có
mục tiêu là idle(). Sự mất cân bằng này là có chủ ý: vì phần lớn khoảnh khắc
trong một cuộc tương tác trực tiếp lẽ ra không nên kích hoạt hành động nào, học
được khi nào cần im lặng là hành vi đầu tiên và quan trọng nhất của mô hình.
Để tăng tính đa dạng, chúng tôi dùng nhiều mô hình viết kịch bản khác nhau, với các chỉ dẫn, tính cách, lĩnh vực và văn phong khác nhau. Những kịch bản sinh ra sau đó phải qua các bước kiểm tra tự động về cú pháp hành động hợp lệ, tham chiếu văn bản có cơ sở, và mức trùng lặp, rồi mới được đưa vào tập dữ liệu.
Huấn luyện
Lựa chọn đầu tiên và tự nhiên của chúng tôi là supervised fine-tuning (SFT), vì điều chúng tôi muốn dạy mô hình là một hành vi mong muốn đã biết trước. Với mỗi nhịp gõ, chúng tôi có thể chỉ rõ hành động đúng — im lặng, lên tiếng, tìm kiếm, hay dịch — nên bài toán tự nhiên mang tính giám sát. Vì vậy chúng tôi đóng khung việc huấn luyện thành học hành động đúng từ các minh hoạ.
Chúng tôi dùng Qwen3.5-4B làm mô hình nền và huấn luyện qua ba giai đoạn SFT nối tiếp, mỗi giai đoạn tiếp tục từ checkpoint trước với learning rate thấp hơn. Giai đoạn đầu dạy các hành vi tương tác cốt lõi, giai đoạn hai bổ sung những khả năng mới như dịch và tìm kiếm web, còn giai đoạn ba sửa những lỗi phát hiện được trong quá trình đánh giá.
Những lỗi đó cho thấy các khoảng trống còn lại phản ánh việc thiếu khả năng tương tác chứ không phải sở thích sai lệch. Do đó, bổ sung thêm dữ liệu có giám sát là bước tiếp theo hợp lý hơn so với reinforcement learning hay các phương pháp tối ưu theo sở thích.
Nhờ dùng Tinker, cả ba giai đoạn huấn luyện tốn khoảng $50 tổng cộng.
Trước huấn luyện
Sau huấn luyện
% số mục vượt qua
Suy luận
Tương tác thời gian thực đòi hỏi suy luận nhanh, vì mô hình phải xử lý mọi nhịp gõ một cách kịp thời.
Bản hiện thực BF16 ngây thơ ban đầu của chúng tôi quá chậm. Vì mỗi nhịp lại xử lý lại một ngữ cảnh ngày càng dài, độ trễ trung vị chạm 2,9 giây và tăng lên hơn 60 giây sau 7,5 phút tương tác.
Bản hiện thực này cũng cho thấy prefix caching tiêu chuẩn không phát huy tác
dụng. Mỗi nhịp gõ làm đầu vào thay đổi một chút, khiến engine suy luận không
tái sử dụng được phần tính toán trước đó. Để vượt qua giới hạn này, chúng tôi
lượng tử hoá mô hình xuống 4-bit, thay suy luận trên ảnh chụp toàn phần bằng
cache có giới hạn theo từng phiên, nạp trước phần tiền tố bất biến của prompt,
và dừng giải mã ngay sau token </action> được sinh ra. Cùng với nhau, những
thay đổi này giảm độ trễ trung vị 80%, xuống còn 572 ms, nằm trong ngân sách
650 ms.
Tuy nhiên, thử nghiệm thêm cho thấy mô hình 4-bit không giữ được đầu ra một cách đáng tin cậy. Chúng tôi vì thế đối mặt với đánh đổi giữa tốc độ và độ chính xác: mô hình 4-bit đạt mục tiêu độ trễ, còn mô hình 8-bit đáng tin hơn thì không. Cuối cùng chúng tôi chọn mô hình 8-bit cho các demo, chấp nhận độ trễ trung vị cao hơn ở mức 972 ms để đổi lấy đầu ra ổn định.
Hạn chế
Dữ liệu tổng hợp. Tương tác bằng văn bản vốn dĩ diễn ra theo lượt, nên có rất ít dữ liệu ghi lại hành vi thời gian thực. Chúng tôi vì vậy phải dựa vào dữ liệu tổng hợp, và nhận ra mô hình thường bắt chước các khuôn mẫu trong tập dữ liệu thay vì thật sự ra quyết định thời gian thực dựa trên ngữ cảnh. Chẳng hạn, chúng tôi sinh các nhịp huấn luyện bằng cách cắt những tương tác hoàn chỉnh theo một khoảng ký tự cố định. Trên 318.462 nhịp, không một nhịp nào tiến thêm quá bảy ký tự. Giới hạn này vô tình chỉ cho mô hình thấy một dải tốc độ gõ rất hẹp, nên nó hoạt động kém hơn hẳn khi người dùng gõ nhanh hơn lúc thử nghiệm. Chúng tôi dự định sinh dữ liệu tổng hợp đa dạng hơn, trải rộng hơn về tốc độ gõ và kiểu tương tác.
Những khả năng thất bại. Chúng tôi cũng huấn luyện thêm hai khả năng nữa — nhắc hẹn và sửa lỗi ngữ pháp — nhưng đã bỏ cả hai vì chúng thất bại khi thử trực tiếp. Với nhắc hẹn, mô hình cần hành động khi một lời nhắc đã đến hạn. Nhưng nó vẫn im lặng ngay cả khi đầu vào chỉ rõ rằng lời nhắc đã tới hạn, cho thấy lỗi nằm ở việc kích hoạt hành động chứ không phải ở việc tính thời gian. Với sửa lỗi ngữ pháp, mô hình cần nhận ra và sửa lỗi ngay trong lúc người dùng đang gõ. Khác với highlight, vốn chỉ cần khớp một đoạn, việc này còn đòi hỏi suy luận về bản thân lỗi và cách sửa. Dù kết quả trên tập kiểm định rất tốt, nó lại không đáng tin khi chạy thật. Kích thước mô hình nhỏ có thể góp phần vào cả hai thất bại, nhưng chúng tôi chưa kiểm chứng giả thuyết này. Chúng tôi dự định thử các mô hình lớn hơn và cải thiện phần giám sát cho những khả năng này.
Ngữ cảnh phình to. Trong lúc luồng chạy, hệ thống nối thêm một ảnh chụp mới của văn bản người dùng ở mỗi nhịp. Vì mỗi ảnh chụp lặp lại gần hết phần văn bản trước đó, ngữ cảnh nhanh chóng đầy những tiền tố trùng lặp và phình theo bậc hai, tức O(N²). Khi tương tác kéo dài hơn, mức dùng bộ nhớ và độ trễ suy luận đều tăng, khiến việc duy trì tương tác thời gian thực khó hơn. Chúng tôi dự định thay các ảnh chụp lặp lại bằng một cách biểu diễn ngữ cảnh gọn hơn.
Lời cảm ơn
Dự án này ban đầu được truyền cảm hứng từ Tiny Interaction Models của Rajan Agarwal, bài viết đã giới thiệu cho tôi về interaction models và cho thấy ý tưởng này có thể khám phá được bằng một mô hình mở, cỡ nhỏ. Hướng đi rộng hơn cũng được định hình bởi công trình interaction models của Thinking Machines Lab và GPT-Live của OpenAI, cả hai đều cho thấy mô hình có thể liên tục quan sát, phản hồi và ra quyết định tương tác, thay vì chờ những lượt hội thoại cố định.