Trong đó, bài viết trước nói về việc làm cho một tác tử hoạt động đáng tin cậy: vòng lặp thực thi, định tuyến công cụ, nén ngữ cảnh, phiên làm việc an toàn khi gặp sự cố. Tầng đó trả lời câu hỏi "làm thế nào để một tác tử hoàn thành nhiệm vụ mà không bị gián đoạn?" Bài viết này nói về tầng phía trên — điều gì xảy ra khi một tác tử là chưa đủ và công việc cần được chia cho một nhóm.
Đây là điều mọi người thường muốn nói khi nhắc đến điều phối đa tác tử: một tác tử trưởng phụ trách cuộc trò chuyện chia yêu cầu thành nhiều phần, giao từng phần cho một tác tử phụ chuyên biệt, đợi những tác tử cần thiết hoàn thành trước khi bắt đầu bước tiếp theo, chuyển tiếp kết quả và giữ toàn bộ quá trình đi đúng hướng khi một bước thất bại. Orkas chạy toàn bộ quy trình này trên chính máy của người dùng. Dưới đây là cách tầng điều phối đó được xây dựng — mã đã được lược bỏ thông tin nhạy cảm và khái quát hóa, nhưng cấu trúc là có thật.
Tác tử trưởng và các tác tử phụ
Có thể hình dung đây là một nhóm nhỏ với hệ thống chỉ huy rõ ràng. Một tác tử trưởng (chúng tôi gọi là commander) phụ trách cuộc trò chuyện và ngữ cảnh tổng thể. Nó không tự làm tất cả; nhiệm vụ của nó là quyết định cần làm gì, theo thứ tự nào và do ai thực hiện. Các tác tử phụ là những chuyên gia — mỗi tác tử được cấu hình với lời nhắc hệ thống, các công cụ được phép dùng và bộ kỹ năng riêng. Một tác tử phụ giỏi một phần công việc và được gọi khi cần đến phần đó.
Hai điều khiến khái niệm này không chỉ là một thuật ngữ thời thượng. Thứ nhất, tác tử phụ và kỹ năng là những đơn vị được hỗ trợ trực tiếp, không phải mẹo viết lời nhắc: tác tử phụ là một tác tử thực sự, được cấu hình riêng, và việc giao nhiệm vụ cho nó là một lần bàn giao thực sự với ngữ cảnh riêng. Thứ hai, việc phối hợp không phụ thuộc vào thiện chí của mô hình — nó được dẫn dắt bởi một cấu trúc tường minh mà hệ thống, chứ không phải mô hình, giữ cho đúng thực tế. Cấu trúc đó là kế hoạch.
Kế hoạch là một đồ thị, không phải kịch bản
Khi tác tử trưởng quyết định rằng một yêu cầu cần nhiều hơn một bước, nó viết một kế hoạch. Kế hoạch không phải văn xuôi tự do, cũng không phải danh sách kiểm tra tuyến tính — đó là một đồ thị phụ thuộc nhỏ (DAG). Mỗi nút là một bước, và mỗi bước chứa mọi thứ bộ điều phối cần để giao nhiệm vụ:
interface PlanStep {
index: number; // 1-based, stable, never renumbered
title: string; // human-readable, shown in the UI
assignee: string; // who runs it: "user" | "commander" | a sub-agent
input?: string; // the dispatch payload — a template (see below)
wait_for?: number[]; // upstream step indexes; defaults to [index - 1]
on_failure?: "abort_plan" | "continue" | "ask_commander";
// --- runtime state, owned by the orchestrator, NOT written by the model ---
status: "pending" | "in_progress" | "done" | "failed" | "skipped" | "blocked";
output_summary?: string; // short summary of what the step produced
output_files?: string[]; // files the step produced
failure_reason?: string;
}Trong đó, wait_for là trường biến một danh sách thành đồ thị. Theo mặc định, một bước đợi bước ngay trước nó (một chuỗi đơn giản), nhưng một bước có thể khai báo rằng nó phụ thuộc vào nhiều bước trước đó — "tóm tắt" có thể đợi cả "nghiên cứu thị trường" và "khảo sát đối thủ". Đó là hình thoi, không phải đường thẳng, và bộ điều phối xử lý nó đúng như vậy.
Ai nắm giữ sự thật: bộ điều phối, không phải mô hình
Hãy nhìn lại sự phân chia trong cấu trúc đó. Mô hình điền phần ý định — tiêu đề, người được giao, đầu vào, quan hệ phụ thuộc — khi viết kế hoạch lần đầu. Nhưng mọi thứ liên quan đến trạng thái thực thi — status, output_summary, failure_reason — đều do riêng bộ điều phối quản lý. Mô hình đề xuất kế hoạch một lần; nó không bao giờ được tự đánh dấu các bước của mình là "đã xong".
Sự phân tách này là có chủ đích và là quyết định quan trọng nhất trong toàn bộ thiết kế. Một mô hình ngôn ngữ hoàn toàn có thể vui vẻ thông báo "bước 3 đã hoàn tất" khi bước 3 gặp lỗi, hoặc quên những bước nào còn chưa xong giữa một cuộc trò chuyện dài. Nếu trạng thái chỉ nằm trong đầu mô hình, kế hoạch sẽ dần lệch khỏi thực tế. Bằng cách biến trạng thái thành một cấu trúc dữ liệu mà chỉ bộ thực thi được ghi — và chỉ ghi khi một bước thực sự kết thúc — kế hoạch luôn phản ánh chính xác những gì đã xảy ra. Mô hình quyết định cấu trúc công việc; môi trường thực thi quyết định sự thật về tiến độ.
Giao các bước đã sẵn sàng
Khi đã có kế hoạch, một bộ máy nhỏ — bộ thực thi — thúc đẩy nó tiến lên. Thao tác cốt lõi là "tìm các bước đã sẵn sàng và giao chúng". Một bước được coi là sẵn sàng khi nó vẫn ở trạng thái pending và mọi bước mà nó chờ đều đã đạt trạng thái kết thúc đủ điều kiện thành công:
function findReadySteps(plan): PlanStep[] {
return plan.steps.filter((s) => {
if (s.status !== "pending") return false;
const deps = s.wait_for ?? (s.index > 1 ? [s.index - 1] : []);
return deps.every((d) => isTerminal(plan.step(d).status)); // done or skipped
});
}Quy trình này không chạy theo bộ hẹn giờ mà phản ứng với sự kiện. Mỗi khi một bước kết thúc — tác tử phụ trả kết quả, commander kết thúc lượt tổng hợp — bộ thực thi tiến hành đối soát: ghi lại kết quả của bước vừa kết thúc, rồi quét lại để tìm những bước vừa trở nên sẵn sàng và giao chúng. Điều phối chính là vòng lặp đối soát này, lặp đi lặp lại cho đến khi không còn bước nào.
Việc giao nhiệm vụ diễn ra trong cùng cuộc trò chuyện, không qua kênh riêng
Đây là một lựa chọn giúp hệ thống luôn minh bạch: giao một bước không sử dụng kênh RPC ẩn. Nó đăng một tin nhắn vào chính cuộc trò chuyện nhóm mà người dùng đang theo dõi, từ tác tử trưởng, nhắc tên tác tử phụ bằng @. Với tác tử phụ, được giao nhiệm vụ không khác gì được gọi tên trong cuộc trò chuyện — nó chỉ thực hiện lượt bình thường của mình. Không có luồng thực thi thứ hai cần giữ đồng bộ với luồng đầu tiên.
Bên được giao có thể thuộc một trong ba loại, và cách giao cho mỗi loại hơi khác nhau:
- Một tác tử phụ — trường hợp phổ biến. Bộ thực thi phân giải tên tác tử thành ID của nó và đăng
@<agent> <rendered input>từ commander. Tác tử phụ nhận tin nhắn và thực hiện một lượt tác tử đầy đủ. - Người dùng — khi một bước thực sự cần thông tin từ con người, bước đó biến thành một biểu mẫu và tạm dừng kế hoạch (chi tiết bên dưới). Không bước phía sau nào được tiếp tục cho đến khi người dùng trả lời.
- Chính commander — dành cho các bước tổng hợp hoặc quyết định ("đọc mọi thứ ở trên và viết bản tóm tắt"). Đây là một lần kích hoạt nội bộ, không đăng thêm tin nhắn thừa cho người dùng thấy; tác tử trưởng chỉ thực hiện một lượt với ngữ cảnh đã thu thập.
Chuyển ngữ cảnh từ bước này sang bước tiếp theo
Một nhóm chỉ hữu ích khi công việc được luân chuyển giữa các thành viên. Cơ chế đó là mẫu input . Khi tác tử trưởng viết một bước, đầu vào không phải chuỗi cố định — nó có thể tham chiếu các kết quả trước đó, và bộ thực thi thay các tham chiếu bằng nội dung tương ứng khi giao nhiệm vụ:
// step 3.input, as written by the lead agent
"Using the findings below, draft the launch note.\n\n{{step_1.output_summary}}"
// what the sub-agent actually receives at dispatch time
"Using the findings below, draft the launch note.\n\n- Market is growing ~20% YoY; two incumbents…"Hãy chú ý nội dung được chuyển tiếp: output_summary, mã ngắn gọn là bản tóm tắt của mỗi bước đã hoàn thành — không phải toàn bộ bản ghi. Đây là quyết định về ngân sách và cũng xuất phát từ cùng tư duy với việc nén ngữ cảnh của khung thực thi. Nếu mỗi bước phía sau kế thừa toàn bộ lịch sử từng token của mọi thứ trước đó, ngữ cảnh sẽ phình to và chi phí sẽ bùng nổ chỉ sau vài lần chuyển tiếp. Các bản tóm tắt giữ chi phí mỗi lần bàn giao ở mức thấp và giúp mỗi tác tử phụ tập trung vào những gì nó thực sự cần từ các bước trước, thay vì phải lần theo cách các bước trước đi đến kết quả. Tin nhắn ban đầu của người dùng và mọi tệp đính kèm cũng được mang theo, nên một bước cách ba lần chuyển tiếp trong chuỗi vẫn biết yêu cầu gốc.
Mặc định chạy tuần tự — và lý do
Bạn có thể kỳ vọng rằng khi nhiều bước cùng sẵn sàng — chẳng hạn hai nhánh của một hình thoi — bộ điều phối sẽ khởi chạy tất cả song song. Nó có thể làm vậy; nhưng hiện tại, nó giao mỗi lần một bước đã sẵn sàng, ưu tiên bước có chỉ số nhỏ nhất và để các bước còn lại chờ lần đối soát tiếp theo. Cho cả nhóm chạy nghiêm ngặt từng bước một là một lựa chọn thận trọng có chủ đích, và cần nói rõ lý do.
Lý do là tính đúng đắn khi có thực thi đồng thời. Hãy hình dung hai tác tử phụ kết thúc gần như cùng lúc. Cả hai lần hoàn thành đều kích hoạt đối soát; cả hai lần đối soát đều đọc kế hoạch; cả hai đều thấy cùng một bước phía sau vẫn ở trạng thái pending — và cả hai đều giao bước đó. Giờ cùng một bước chạy hai lần. Để ngăn điều này, mọi chu kỳ đọc-sửa-giao trong một cuộc trò chuyện đều được tuần tự hóa bằng khóa riêng cho cuộc trò chuyện đó:
// all state-changing paths for one conversation run under one mutex
planLock(uid, cid).runExclusive(async () => {
const plan = await readPlan(uid, cid);
applyOutcomeOfFinishedStep(plan); // mark done / failed / skipped
await dispatchReady(plan); // dispatch the next ready step
});Khóa bảo đảm rằng "ghi lại những gì đã kết thúc" và "quyết định bước tiếp theo" diễn ra như một đơn vị không thể chia tách, nên một bước phía sau không bao giờ bị giao hai lần. Khi đã có khóa đó, giao từng bước một là cách đơn giản nhất có thể thấy rõ là đúng. Phân nhánh song song thực sự là phần mở rộng khả thi trên nền tảng này — nhưng nền tảng phải là một bộ thực thi tuần tự, không có tranh chấp, và thứ tự ưu tiên đó (đúng trước, nhanh sau) mới là điều cốt lõi.
Khi một bước gặp sự cố
Khi chạy trên máy thực và làm việc với API mô hình bên ngoài, lỗi là chuyện thường xuyên, và bộ điều phối phân loại chúng thành vài trường hợp thay vì xử lý mọi lỗi như nhau.
Trước hết, nó xem lỗi có chỉ là tạm thời — mất kết nối, giới hạn tốc độ, một trục trặc thoáng qua. Nếu đúng, và bước đó chưa dùng hết số lần thử lại ít ỏi được cho phép, bước đó được âm thầm đưa về pending để lần đối soát tiếp theo giao lại. (Cơ chế này nằm phía trên cơ chế thử lại trong lượt chạy của chính khung thực thi; kế hoạch chỉ giao lại sau khi tác tử đã dùng hết các lần thử của mình, với giới hạn cứng để một bước thực sự hỏng không thể lặp vô tận.)
Nếu lỗi là thực sự, chính sách on_failure đã khai báo của bước quyết định nhóm sẽ làm gì tiếp theo:
abort_plan— bước này quan trọng đến mức không có nó thì các bước phía sau đều vô nghĩa. Đánh dấu bước đó thất bại, rồi lan truyền: mọi bước còn đang chờ đều được đánh dấuskipped. Kế hoạch dừng gọn gàng thay vì tiếp tục xây trên một nền tảng còn thiếu.continue— bước này là tùy chọn. Đánh dấu nó làskippedvà để các bước phía sau tiếp tục như thể nó đơn giản là không tạo ra gì.ask_commander(mặc định) — không hủy bỏ mù quáng, cũng không tiếp tục mù quáng. Đánh dấu thất bại và kích hoạt tác tử trưởng để xem điều gì đã xảy ra rồi quyết định — thử lại theo cách khác, tìm đường vòng, hoặc dừng và hỏi người dùng.
Có một trạng thái thứ sáu cần nhắc đến: blocked. Một tác tử phụ đang thực hiện bước của mình có thể nhận ra nó cần thứ mà chỉ người dùng mới cung cấp được, rồi hiển thị biểu mẫu hoặc câu hỏi. Bước đó không thất bại — nó chuyển sang blocked, và toàn bộ kế hoạch tạm dừng. Ngay khi người dùng trả lời, bộ thực thi đối soát và nhóm tiếp tục đúng từ chỗ đã dừng. Kế hoạch bị chặn là kế hoạch đang tạm dừng, không phải kế hoạch bị hỏng.
Mỗi bước là một lượt chạy tác tử đầy đủ
Cần kết nối lại với bài viết trước. Khi bộ điều phối giao một bước cho tác tử phụ, tác tử phụ đó không chạy một quy trình rút gọn — nó chạy toàn bộ vòng lặp của khung thực thi: vòng lặp thực thi dạng luồng riêng, các lệnh gọi công cụ riêng, cửa sổ ngữ cảnh riêng có nén, phiên làm việc riêng an toàn khi gặp sự cố. Tầng điều phối nằm tách bạch phía trên môi trường thực thi đơn tác tử; nó không bao giờ can thiệp vào bên trong. Tác tử trưởng quyết định cấu trúc công việc và thứ tự bàn giao; mỗi tác tử phụ, khi đã nhận phần việc của mình, là một tác tử hoàn chỉnh độc lập.
Chính cách phân tầng đó khiến hai bài viết bổ sung cho nhau. Khung thực thi làm cho một tác tử đáng tin cậy khi thực hiện một nhiệm vụ. Bộ điều phối kết hợp nhiều tác tử đáng tin cậy thành một nhóm có thể đảm nhận nhiệm vụ quá lớn hoặc quá đa dạng đối với bất kỳ tác tử riêng lẻ nào.
Một vài quyết định quan trọng
Bộ điều phối quản lý trạng thái thực thi, mô hình quản lý ý định. Mô hình đề xuất kế hoạch; chỉ môi trường thực thi mới đánh dấu các bước là đã xong, thất bại hoặc bỏ qua, và chỉ khi có việc thực sự xảy ra. Chính ranh giới này giữ cho kế hoạch phản ánh trung thực thực tế thay vì phỏng đoán lạc quan của mô hình.
Giao nhiệm vụ qua cùng cuộc trò chuyện, không qua kênh riêng. Một bước được giao chỉ là một tin nhắn từ tác tử trưởng tới tác tử phụ. Một luồng thực thi duy nhất, không có thứ gì ẩn có thể mất đồng bộ, và người dùng có thể theo dõi nhóm làm việc trong chính luồng trò chuyện họ đang đọc.
Giữa các bước là bản tóm tắt, không phải toàn bộ bản ghi. Mỗi lần bàn giao mang theo một bản tóm tắt ngắn về đầu ra của các bước trước. Điều này giữ ngân sách ngữ cảnh hợp lý trên các chuỗi dài và giúp mỗi tác tử phụ tập trung vào những gì nó cần, không phải cách tác tử trước đi đến kết quả.
Đúng trước, song song sau. Khóa riêng cho mỗi cuộc trò chuyện tuần tự hóa mọi chu kỳ đọc-sửa-giao, và các bước được giao từng bước một. Chạy hoàn toàn tuần tự là phiên bản rõ ràng không có tranh chấp dẫn đến giao trùng; phân nhánh song song là tối ưu hóa được thêm lên một nền tảng vốn đã đúng.
Lời kết
Tầng điều phối của Orkas không có thuật toán kỳ lạ nào làm cốt lõi. Giá trị của nó nằm ở vài ranh giới được giữ vững: kế hoạch là đồ thị phụ thuộc thay vì kịch bản; trạng thái thực thi do môi trường thực thi quản lý thay vì mô hình; việc giao nhiệm vụ diễn ra trong chính cuộc trò chuyện người dùng đang theo dõi; ngữ cảnh chuyển giữa các bước dưới dạng tóm tắt; và bộ thực thi đặt tính đúng đắn lên trước khả năng chạy đồng thời. Từng điều riêng lẻ đều đơn giản. Kết hợp lại, chúng biến một tác tử đáng tin cậy thành một nhóm biết chia việc, chuyển tiếp công việc và phục hồi khi một phần gặp sự cố.
Nếu bạn muốn tìm hiểu tầng bên dưới, hãy đọc cách một tác tử được thiết kế để chạy đáng tin cậy. Nếu bạn muốn tìm hiểu tầng giúp mỗi tác tử tiến bộ qua quá trình sử dụng, hãy đọc cách các tác tử Orkas học từ chính công việc của mình. Và nếu bạn muốn chỉ đạo tầng này thay vì tự xây dựng, Orkas cung cấp nó dưới dạng hệ thống điều phối tác tử AI mã nguồn mở chạy trên chính máy của bạn.