Chuyển đến nội dung chính

Fine-tune, RAG hay chỉ cần prompt tốt hơn: một quyết định bạn bảo vệ được

Cứ vài tuần lại có người chiếu đúng cái slide đó lên: ba cái hộp ghi Prompt Engineering, RAGFine-tuning, kèm mũi tên ngụ ý rằng bài toán càng nghiêm túc thì bạn càng “lên hạng” từ trái sang phải. Rồi cả phòng cãi nhau xem chọn cái nào, như thể đó là ba nhà thầu đang đấu cùng một gói việc.

Chúng không tranh nhau cùng một gói việc. Chúng tác động vào ba phần khác nhau của hệ thống, và một khi bạn gọi tên được phần nào đang hỏng, cuộc tranh luận thường kết thúc trong khoảng một phút:

  • Prompt đổi phần chỉ dẫn. Model đang được yêu cầu làm gì, dưới những ràng buộc nào.
  • Retrieval đổi phần kiến thức. Những dữ kiện nào thật sự có mặt trong context window lúc model trả lời.
  • Fine-tuning đổi phần hành vi. Model làm gì theo mặc định, dưới dạng nào, khi chỉ dẫn đã hết.

Gần như mọi quyết định sai trong mảng này đều đến từ việc đem một tầng đi chữa vấn đề nằm ở tầng khác. Fine-tune một model để nó “biết” danh mục sản phẩm của bạn là ca kinh điển — bỏ ra sáu tuần để có một model tự tin nói sai giá của tuần trước, và bạn thậm chí không biết đổ lỗi cho trọng số nào. Dựng cả một pipeline retrieval trước một model mà vấn đề thật sự chỉ là nó viết sáu đoạn trong khi bạn muốn một đoạn, cũng là đúng sai lầm đó theo chiều ngược lại.

Nên đừng bắt đầu từ kỹ thuật. Hãy bắt đầu từ triệu chứng.

Bốn tầng, không phải ba

Cái slide kia còn thiếu một hộp. Có bốn thứ bạn có thể thay đổi, và chúng khác nhau chủ yếu ở chỗ: một thay đổi tốn bao nhiêu khi hệ thống đã chạy production.

TầngThay đổi cái gìThay đổi bằng cáchChi phí cho một lần đổi
PromptChỉ dẫn và ràng buộcSửa một chuỗi stringVài phút. Quay lại được.
Schema / toolsOutput nào là khả dĩ về mặt cấu trúcMột JSON schema, một tool definitionVài giờ. Quay lại được.
RetrievalDữ kiện nào đang nằm trước mặt modelNạp hoặc index lại một tài liệuVài phút mỗi tài liệu, một khi pipeline đã có
Fine-tuningHành vi và hình thức mặc định của modelMột lần train trên dữ liệu đã gán nhãnVài ngày đến vài tuần. Thêm một artefact phải nuôi.

Tầng ở giữa là tầng các team hay bỏ qua, và nó lại chính là tầng giải quyết than phiền phổ biến nhất. “Nó không giữ đúng định dạng output” thường không phải vấn đề huấn luyện — đó là vấn đề decoding, và constrained decoding xử lý nó ở mức cấu trúc chứ không phải mức xác suất. Structured Outputs của OpenAI với strict: true, hoặc tính năng constrained generation tương đương trong stack bạn dùng, khiến một response sai định dạng trở thành bất khả thi chứ không chỉ là “ít khi xảy ra”. Không cần dataset nào cả.

Bắt đầu từ triệu chứng, đừng bắt đầu từ kỹ thuật

Đây là bản đồ tôi thật sự dùng. Hãy đọc cột trái như một câu ai đó vừa nói ra miệng trong cuộc họp.

Bạn quan sát thấyThứ thật sự đang thiếuNên dùng
”Nó không biết sản phẩm / bảng giá / chính sách của mình”Kiến thứcRetrieval
”Nó bịa ra một internal API không tồn tại”Kiến thức, cộng với quyền được từ chốiRetrieval + một chỉ dẫn rõ ràng “không biết thì nói không biết"
"Nó trả lời cũ — tài liệu đã sửa hôm thứ Ba”Độ tươi của kiến thứcRetrieval. Tuyệt đối không fine-tuning.
”Nó dài dòng quá” / “sai giọng văn”Chỉ dẫnPrompt
”Nó tuân thủ năm trong sáu quy tắc của tôi”Quá tải chỉ dẫnCấu trúc lại prompt: tách thành hai lần gọi, hoặc đẩy một quy tắc xuống schema
”Cứ năm mươi lần gọi thì có một lần JSON hỏng”Bảo đảm về cấu trúcSchema / constrained decoding
”Đúng, nhưng nó không giống giọng của team support mình”Hình thức và phong cáchFine-tuning (sau khi few-shot đã thất bại)
“Đúng ở ca bình thường, sai ở mấy ca kỳ quặc của mình”Hành vi riêng của tác vụFew-shot trước, rồi mới fine-tuning
”Chạy được, nhưng system prompt tốn hàng ngàn token mỗi lần gọi”Chi phí và latencyPrompt caching trước, rồi mới fine-tuning
”Câu trả lời khác nhau giữa những user không được thấy cùng dữ liệu”Phân quyền truy cậpRetrieval. Fine-tuning hoàn toàn không làm được việc này.

Có hai dòng trong bảng đó là chịu lực, và cũng là hai dòng người ta hay lướt qua.

Độ tươi và phân quyền là hai điều kiện loại trực tiếp fine-tuning. Nếu một dữ kiện có thể thay đổi, hoặc nếu những user khác nhau được phép thấy những dữ kiện khác nhau, thì nó không thể nằm trong trọng số. Một index retrieval có các dòng bạn cập nhật, xoá và lọc theo quyền được. Trọng số không có bất kỳ khả năng nào trong số đó. Không có DELETE cho một dữ kiện mà model đã hấp thụ khi train, và cũng không có WHERE tenant_id = ?.

Prompt là tầng duy nhất có nút undo trong ngày

Luôn bắt đầu ở đây, không phải vì prompt mạnh, mà vì ở đây sai thì rẻ. Một thay đổi prompt đi kèm một commit, được review như code, và revert trong vài giây. Không tầng nào khác trong danh sách này làm được vậy.

Chỗ prompt thật sự hết đường:

  • Nó không cài được dữ kiện mà model vốn không có. Dán cả cuốn cẩm nang vào prompt chính là retrieval làm bằng tay — và là retrieval làm dở, vì bạn trả tiền cho toàn bộ cuốn cẩm nang ở mọi lần gọi.
  • Mức tuân thủ tụt dần khi ràng buộc chồng lên nhau. Một prompt với mười hai quy tắc đồng thời không đáng tin gấp mười hai lần một prompt có một quy tắc. Khi bạn thấy mình đang viết quy tắc thứ mười bốn, cách sửa thường là tách công việc thành hai lần gọi, hoặc hạ một quy tắc xuống thành thứ mà decoder cưỡng chế. (Tôi đã viết riêng về nghiên cứu thật sự nói gì về prompt engineering và kỹ thuật dân gian nào thật sự trụ được.)
  • Mọi token đều bị tính tiền ở mọi lần gọi. Một system prompt dài là khoản thuế cố định đánh lên toàn bộ workload.

Điểm cuối cùng chính là động cơ chính đáng để fine-tune mà người ta hay với tới quá sớm — và có một can thiệp rẻ hơn cần thử trước. Prompt caching cho phép tái sử dụng phần đầu ổn định của prompt qua nhiều lần gọi với mức giá giảm, gỡ bỏ phần lớn lập luận về chi phí mà không cần sản xuất dataset nào. Hãy thử cái đó trước khi thử train. Chi tiết hơn về đòn bẩy này nằm trong bài về chi phí.

Retrieval là miếng vá kiến thức, và chỉ là miếng vá kiến thức

Paper RAG gốc đặt vấn đề rất thẳng: đặt một bộ nhớ phi tham số bên cạnh bộ nhớ tham số, để kiến thức nằm ở chỗ bạn sửa được. Cách đóng khung đó đến giờ vẫn là cách đúng để quyết định bạn có cần nó hay không.

Retrieval là câu trả lời khi một trong những điều sau đúng:

  • dữ kiện thay đổi theo một nhịp bạn không kiểm soát
  • dữ kiện là riêng tư và chưa từng nằm trong bất kỳ corpus pre-training nào
  • số lượng dữ kiện lớn hơn nhiều so với sức chứa của context window
  • bạn cần chỉ cho người dùng thấy câu trả lời đến từ đâu
  • những user khác nhau chỉ được quyền thấy những tập con khác nhau

Cái bạn phải gánh khi nói “có”: một pipeline nạp dữ liệu, các quyết định chunking ảnh hưởng tới chất lượng trả lời theo những cách không hiển nhiên, một index phải luôn đồng bộ với nguồn sự thật, thêm một chặng network làm tăng latency, và một chế độ hỏng hoàn toàn mới — model giờ có thể sai vì retrieval đưa nhầm ba đoạn văn cho nó, và cái sai đó nhìn y hệt như model tự sai.

Vấn đề cuối cùng đó đủ sâu để xứng đáng một bài riêng; đo xem retrieval có lấy đúng thứ cần lấy không là một môn khác với đo xem model trả lời tốt không, và nó cần bộ test riêng. Với phạm vi quyết định của bài này, thứ cần khắc vào đầu chỉ đơn giản là: nói “có” với retrieval nghĩa là từ nay bạn sở hữu thêm một hệ thống search, bên cạnh một tính năng LLM.

Fine-tuning mua được hình thức, latency và giá — không mua được kiến thức

Những thứ fine-tuning thật sự mua được, một cách đáng tin cậy:

  • Hình thức nhất quán. Giọng văn, cấu trúc, văn phong, quy ước nội bộ — những thứ tả bằng cả trang style guide vẫn được áp dụng lúc được lúc không. Cho xem ví dụ dạy được điều này tốt hơn nhiều so với mô tả bằng lời.
  • Prompt ngắn hơn. Hành vi mà lẽ ra bạn phải viết ra ở mọi lần gọi được gấp gọn vào trong model. Ít token input hơn mỗi request, ít chỗ để sai hơn.
  • Latency và chi phí mỗi lần gọi thấp hơn, như hệ quả của prompt ngắn hơn — và đôi khi vì một base model nhỏ hơn, đã tune cho tác vụ hẹp của bạn, sánh ngang một model lớn hơn nhưng chưa tune.
  • Những dạng tác vụ khó mô tả bằng lời. Một hệ nhãn phân loại rất riêng, phương ngữ SQL của team bạn, một ranh giới phân loại mà ai cũng nhận ra nhưng không ai viết ra được. Nếu prompt tốt nhất bạn viết được là “nhìn là biết”, thì bạn đang có một bài toán fine-tuning.

Thứ nó không mua được là kiến thức đáng tin. Dữ kiện đã hấp thụ vào trọng số thì không có nguồn, không có phiên bản, không xoá được, và mờ đi một cách âm thầm — và không có gì báo cho bạn biết khi một dữ kiện đã hết hạn. Một bản fine-tune là một nhánh rẽ của cách bạn hiểu tác vụ, bị đóng băng tại một ngày cụ thể.

Còn đây là mặt chi phí, nói thẳng. Không phải hoá đơn tiền train — hoá đơn tiền train thường là khoản nhỏ nhất trong danh sách này.

  1. Một dataset đã gán nhãn. Đây mới là phần việc thật: những ví dụ vừa đúng vừa nhất quán với nhau. Hai người gán nhãn bất đồng thì không “triệt tiêu lẫn nhau”; nó đi vào model dưới dạng nhiễu, và về sau lộ ra thành một hành vi không ai giải thích nổi.
  2. Bảo trì dataset. Tác vụ dịch chuyển. Một quy tắc thay đổi. Thế là một phần ví dụ của bạn đang dạy sai, và bạn phải đi tìm xem phần nào.
  3. Một vòng lặp retrain. Mỗi thay đổi đáng kể của tác vụ là thêm một lần train, thêm một artefact, thêm một lần rollout.
  4. Một bộ evaluation mà bạn tự sở hữu. Bạn không còn dựa vào benchmark của nhà cung cấp được nữa, vì model không còn là của họ. Bạn cần một tập held-out, các kiểm tra hồi quy so với phiên bản trước, và một kiểm tra rằng bạn không làm hỏng những gì model vốn giỏi bên ngoài tác vụ hẹp đó.
  5. Một model phải giữ đồng bộ. Đây là thứ cắn bạn sau mười tám tháng. Base model bị deprecate và bị thay thế. Khi một base tốt hơn ra mắt, bản fine-tune của bạn vẫn ngồi trên base cũ, và muốn chuyển thì phải train lại — rồi thẩm định lại toàn bộ, vì một dataset dạy tốt base cũ không tự động dạy base mới đúng bài học đó.

Bản thân phần kỹ thuật thì dễ, và chính vì thế các chi phí bên trên hay bị đánh giá thấp. Một tập supervised fine-tuning chỉ là các đoạn hội thoại:

{"messages": [{"role": "system", "content": "You are a support triage assistant."}, {"role": "user", "content": "card declined at checkout, third time today"}, {"role": "assistant", "content": "{\"category\": \"billing.payment_failure\", \"severity\": \"high\", \"needs_human\": true}"}]}
{"messages": [{"role": "system", "content": "You are a support triage assistant."}, {"role": "user", "content": "how do I change my avatar"}, {"role": "assistant", "content": "{\"category\": \"account.profile\", \"severity\": \"low\", \"needs_human\": false}"}]}
job = client.fine_tuning.jobs.create(
    training_file=train_file.id,
    validation_file=val_file.id,   # hold this out. always.
    model="<base-model-id>",
    suffix="triage-v3",            # version it; you will have a v4
)

Hai dòng trong đoạn code đó là toàn bộ lập luận. validation_file không phải phép lịch sự tuỳ chọn — không có tập held-out thì bạn không có cách nào phân biệt một model đã học được tác vụ với một model chỉ học thuộc ví dụ của bạn. Và suffix là một số hiệu phiên bản, bởi vì sẽ có v4, và sẽ có thứ gì đó trên production cần được ghim vào v3 trong lúc bạn đánh giá v4.

LoRA và adapter: khoảng giữa giá rẻ

Fine-tuning đầy đủ cập nhật mọi trọng số, nghĩa là một bản sao model đầy đủ cho mỗi tác vụ. LoRA làm một việc nhẹ hơn nhiều: đóng băng trọng số gốc, và huấn luyện một phần cập nhật hạng thấp nhỏ bên cạnh chúng. Artefact thu được nặng vài megabyte thay vì cả một model, nên bạn có thể giữ nhiều adapter trên chung một base và tráo chúng theo tác vụ, theo tenant, hoặc theo thí nghiệm.

Với PEFT, việc này chỉ là vài dòng đặt lên trên một vòng train bình thường:

from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,                    # rank of the update
    lora_alpha=32,
    lora_dropout=0.05,
    target_modules=["q_proj", "v_proj"],
    task_type="CAUSAL_LM",
)
model = get_peft_model(base_model, config)
model.print_trainable_parameters()   # a small fraction of the base

Đây thật sự là khoảng giữa thực dụng của thị trường hiện nay, và nó thay đổi bài toán kinh tế đủ nhiều để câu “bọn tôi không đủ tiền fine-tune” hiếm khi còn đúng. Nhưng hãy nói chính xác về thứ nó làm rẻ đi. LoRA giảm chi phí tính toán và chi phí lưu trữ của việc huấn luyện. Nó không giảm chi phí dataset, chi phí giữ nhãn nhất quán, chi phí evaluation, hay chi phí giữ đồng bộ — mà đó mới luôn là những phần đắt. Một lần train rẻ trên một dataset tệ chỉ tạo ra một model tệ nhanh hơn.

Quy tắc thứ tự, và vì sao nó là chuyện bảo trì

Vắt kiệt từng tầng trước khi thêm tầng kế tiếp: prompt → schema → retrieval → fine-tune. Không phải vì các tầng sau khó dựng hơn — với một API được quản lý, fine-tune có khi còn gọn hơn một buổi chiều dựng pipeline retrieval — mà vì mỗi bậc đi lên đều nhân vĩnh viễn diện tích bề mặt bạn phải bảo trì.

Bạn đã nhậnTừ giờ bạn sở hữu, mãi mãi
PromptMột chuỗi string trong version control, và eval cho nó
+ SchemaMột hợp đồng, cộng việc migrate khi hợp đồng đổi
+ RetrievalMột pipeline nạp dữ liệu, một index, việc đồng bộ, và eval chất lượng retrieval
+ Fine-tuningMột dataset, một quy trình gán nhãn, một pipeline huấn luyện, eval theo phiên bản model, và một cuộc migrate base model mà bạn không quyết được thời điểm

Hãy đọc dòng cuối như một câu hỏi về nhân sự chứ không phải về kỹ thuật. Một năm nữa vẫn phải có người làm tất cả những việc đó.

Cũng cần nói thẳng, vì cách đóng khung “chọn một trong ba” che mất điều này: chúng kết hợp được với nhau, và những hệ thống tốt nhất dùng nhiều hơn một. Hình hài trưởng thành phổ biến là fine-tuning cho hình thức cộng retrieval cho dữ kiện — một model đã tune luôn sinh đúng cấu trúc output nội bộ của bạn, được nạp tài liệu mới nhất tại thời điểm request. Chọn một thứ và loại trừ các thứ còn lại thường tự nó đã là sai lầm.

Bảng quyết định

Tình huốngPromptRetrievalFine-tune
Model thiếu dữ kiện riêng tư hoặc mớiKhôngKhông
Dữ kiện thay đổi hằng tuầnKhôngCó hại
Câu trả lời phải trích nguồnKhôngKhông
User khác nhau thấy dữ liệu khác nhauKhôngBất khả thi
Output dài quá, sai giọng, sai trọng tâmKhôngChỉ khi prompt đã chạm trần
Định dạng output thỉnh thoảng hỏngCó íchKhôngSchema trước đã
Văn phong nội bộ, áp dụng hàng ngàn lần mỗi ngàyThử trướcKhông
Tác vụ hiển nhiên với người, khó viết thành lờiFew-shot trướcKhông
Prompt cố định khổng lồ là nguyên nhân tốn tiềnCaching trướcKhông
Cần model nhỏ hơn, nhanh hơn cho một tác vụ hẹpKhôngKhông
Đang là prototype và bạn còn đang hiểu dần tác vụCó thểKhông

Dòng cuối là dòng tôi sẽ bảo vệ mạnh nhất. Fine-tuning mã hoá một quyết định về “thế nào là tốt”. Cam kết điều đó khi tác vụ còn chưa đứng yên, và bạn sẽ dành cả quý sau để bảo trì một model đang giữ giùm bạn một quan điểm mà bạn không còn giữ nữa.

FAQ

Tôi cứ fine-tune trên tài liệu của công ty để model biết nó, được không?

Bạn chạy job được, và kết quả sẽ rất khích lệ trong mười lần thử tay đầu tiên — model bắt được từ vựng và giọng văn của bạn, và điều đó đọc lên giống như “nó biết”. Rồi nó bịa ra một tham số không tồn tại, không kèm trích dẫn, và không có cách nào truy ngược xem tài liệu nào đã dạy nó thế. Fine-tune trên tài liệu dạy được phong cách tài liệu của bạn một cách đáng tin, còn nội dung thì không. Nếu mục tiêu là trả lời đúng dữ kiện trong tài liệu, đó là việc của retrieval.

Tôi cần bao nhiêu ví dụ huấn luyện?

Không ai trả lời được từ bên ngoài, và ai đưa ra một con số duy nhất cho mọi tác vụ là đang đoán. Cách trung thực là thực nghiệm: gom một tập vừa phải, train, đo trên tập held-out, rồi gấp đôi dữ liệu và đo lại. Khi đường cong đi ngang, số lượng ví dụ không còn là nút thắt nữa — chất lượng và tính nhất quán của nhãn mới là. Tác vụ hẹp, định nghĩa rõ, gán nhãn nhất quán cần ít dữ liệu hơn nhiều so với tác vụ rộng và mang tính chủ quan.

Context window lớn có làm retrieval trở nên thừa không?

Nó gỡ bỏ lý do “không nhét vừa”, vốn chỉ là một trong năm lý do. Nó không giúp gì cho độ tươi, phân quyền theo user, truy nguồn, hay chi phí — và đẩy cả corpus qua context ở mỗi request là một cách đắt đỏ để né việc dựng index. Context window lớn làm retrieval dễ hơn vì giảm áp lực chunking; nó không làm retrieval trở nên không cần thiết.

Bọn tôi fine-tune xong thì nó giỏi hơn ở tác vụ đó nhưng dở đi ở mọi thứ khác. Chuyện gì vậy?

Đó là kết quả được dự đoán trước, không phải bug: bạn đã kéo model về phía phân phối dữ liệu của mình, và nó rời xa mọi thứ còn lại. Đây chính là lý do bộ evaluation phải bao gồm cả những năng lực bạn không hề định thay đổi. Nếu model vẫn cần giỏi tổng quát, một adapter nhẹ tay cùng learning rate nhỏ hơn phù hợp hơn là fine-tune toàn phần quyết liệt — hoặc phần việc tổng quát nên được định tuyến sang base model chưa tune.

Rốt cuộc cái nào rẻ nhất?

Tính trên mỗi lần gọi, một model đã fine-tune với prompt ngắn thường rẻ nhất, và đó là con số người ta hay đem ra so. Tính trên mỗi quý thì hiếm khi sát nhau: dataset, gán nhãn, eval và các đợt migrate base model là chi phí con người lặp lại, không hiện lên trên hoá đơn. Prompt là thứ rẻ nhất để làm sai, và ở giai đoạn đầu điều đó quan trọng hơn nhiều so với rẻ nhất để vận hành.


Mô hình phân tầng ở đây — chỉ dẫn, kiến thức, hành vi — là cách đóng khung của riêng tôi để ra quyết định cho nhanh, không phải một chuẩn ngành; còn các khẳng định bên dưới về việc mỗi kỹ thuật làm được và không làm được gì thì không phải ý kiến cá nhân. Mọi thứ phụ thuộc phiên bản (endpoint fine-tuning hiện có, mức hỗ trợ structured output, lịch deprecate base model) đều thay đổi thường xuyên — hãy kiểm tra tài liệu chính thức của nhà cung cấp trước khi xây dựng lên trên nó.


Bài viết gốc đăng tại FlutterCook. Bản trên đó là bản được cập nhật mới nhất.

Nhận xét

Bài đăng phổ biến từ blog này

Thiết kế giao diện với DotNetBar (Phần 1)

Đây là phiên bản DotNetBar hỗ trợ C# và Visual Basic https://www.dropbox.com/s/wx80jpvgnlrmtux/DotNetBar.rar  , phiên bản này hỗ trợ giao diện Metro cực kỳ “dễ thương” Các bạn load về và cài đặt, khi cài đặt xong sẽ có source code mẫu của tất cả các control. Để sử dụng được các control của DotNetBar các bạn nhớ add item vào controls box. Thiết kế giao diện với DotNetBar, giao diện sẽ rất đẹp. Link các video hướng dẫn chi tiết cách sử dụng và coding: http://www.devcomponents.com/dotnetbar/movies.aspx Hiện tại DotNetBar có rất nhiều công cụ cực mạnh, trong đó có 3 công cụ dưới đây: DotNetBar for Windows Forms Requires with Visual Studio 2003, 2005, 2008, 2010 or 2012.   DotNetBar for WPF Requires with Visual Studio 2010 or 2012 and Windows Presentation Foundation.   DotNetBar for Silverlight Requires with Visual Studio 2010 or 2012 and Silverlight. Dưới đây là một số hình ảnh về các control trong DotnetBar.   Metro User Interface  controls with Metro Tiles, toolba...

5 concepts every Flutter dev should know

  Phụ lục: State management architecture Testing IDE Shortcuts Platform channel Maintaining a project Tôi đã làm việc với Flagship trong một thời gian dài, và đây là những điều mà tôi phát hiện ra là điều cần phải có đối với bất kỳ nhà phát triển Flagship nào, về tổng thể nó sẽ khiến bạn trở thành một nhà phát triển Flagship giỏi trong thời gian dài. 1. State management architecture Đây là một trong những chủ đề quan trọng nhất trong cộng đồng thiết bị rung, nó khá quan trọng nếu bạn muốn duy trì một dự án rung kích thước trung bình hoặc lớn. Nó sẽ giúp tạo một dự án suôn sẻ và thêm các tính năng mới một cách hoàn hảo.  2. Testing Đây là một chủ đề duy nhất mà tôi không hiểu tại sao nó lại quan trọng trước đó trong sự nghiệp của tôi, nhưng khi tôi tiến lên trong sự nghiệp của mình và có kinh nghiệm với nhiều dự án và vấn đề xảy ra trong môi trường sản xuất. Tôi đã nhận ra một cách khó khăn, tại sao điều này lại quan trọng như vậy. Nếu bạn vẫn muốn có thêm lý do để cân nhắc thử...

Announcing Flutter 2

  Phụ lục: Flutter on the web Flutter 2 on desktops, foldables, and embedded devices The growing Flutter ecosystem Dart: The secret sauce behind Flutter Flutter 2: Available now Hôm nay, chúng tôi sẽ công bố Flutter 2: một bản nâng cấp lớn cho Flutter cho phép các nhà phát triển tạo các ứng dụng đẹp, nhanh chóng và di động cho bất kỳ nền tảng nào. Với Flutter 2, bạn có thể sử dụng cùng một cơ sở mã để gửi các ứng dụng gốc cho năm hệ điều hành: IOS, Android, Windows, macOS và Linux; cũng như trải nghiệm web nhắm mục tiêu các trình duyệt như Chrome, Firefox, Safari hoặc Edge. Flutter thậm chí có thể được nhúng vào ô tô, TV và thiết bị gia dụng thông minh, mang đến trải nghiệm di động và lan tỏa nhất cho thế giới điện toán xung quanh. Mục tiêu của chúng tôi là thay đổi cơ bản cách các nhà phát triển nghĩ về việc xây dựng ứng dụng, bắt đầu không phải với nền tảng bạn đang nhắm mục tiêu mà là với trải nghiệm bạn muốn tạo. Flutter cho phép bạn tạo ra những trải nghiệm tuyệt đẹp trong đó ...