Bỏ qua đến nội dung chính

Building durable Agents with Workflow DevKit & AI SDK - Peter Wielander, Vercel

TL;DR

  • Workflow Development Kit (WDK) giải quyết vấn đề phức tạp khi đưa các agent AI từ phát triển cục bộ lên production, đặc biệt với các agent chạy dài cần khả năng mở rộngđộ bền mà không phải viết nhiều code xử lý state thủ công.
  • WDK giới thiệu workflow pattern như một lớp orchestration, phân tách code thành các bước độc lập, có state được duy trì, dễ dàng retry và cung cấp khả năng quan sátkhả năng tiếp tục tích hợp sẵn.
  • Bằng cách thêm các directive đơn giản vào code hiện có, nhà phát triển có thể nhanh chóng biến coding agent thành một workflow mạnh mẽ, chạy được trên mọi Claude và tối ưu hóa cho môi trường serverless.

Điểm chính

  • Cài đặt & Cấu hình: Cài đặt thư viện workflow@workflow/AI, sau đó cấu hình Next.js compiler với @workflow/next trong next.config.js để hỗ trợ biên dịch workflow codeTypeScript.
  • Định nghĩa Workflow Orchestration: Tạo một hàm riêng biệt cho workflow chính và đánh dấu nó với directive "use workflow"; để khai báo lớp orchestration có tính deterministic.
  • Đánh dấu Steps: Sử dụng directive "use step"; bên trong các hàm thực thi tool callsLLM calls để biến chúng thành các bước độc lập, có state được duy trì, cacheretry tự động.
  • Khởi động Workflow: Kích hoạt một workflow mới bằng cách gọi start từ @workflow/API, truyền các đối số cần thiết và nhận về một run instance để theo dõi và lấy stream đầu ra.
  • Quản lý Stream Bền bỉ: Tận dụng getWritable từ workflow để có một luồng dữ liệu độc lập, bền bỉ, cho phép ghi output từ bất kỳ step nào hoặc workflowclient có thể tiếp tục nhận dữ liệu bất cứ lúc nào.
  • Khả năng Quan sát Cục bộ: Chạy npx workflow web để khởi động một giao diện người dùng web cục bộ, cung cấp khả năng quan sát chi tiết về các phiên chạy workflow, bao gồm input, outputevent của từng bước, hỗ trợ debug.
  • Tích hợp Tính năng Nâng cao: WDK hỗ trợ các tính năng như resumable streams, khả năng tạm dừng (suspend) và tiếp tục (resume) workflow tại bất kỳ điểm nào, cùng với việc tích hợp webhooks dễ dàng cho các quy trình human-in-the-loop dài hạn.

Từ vựng

  • Workflow Development Kit — Bộ Công cụ Phát triển Quy trình Làm việc
  • workflow pattern — mô hình quy trình làm việc
  • Agent Loop — Vòng lặp Agent
  • khả năng quan sát (observability) — observability
  • độ bền (durability) — durability
  • khả năng tiếp tục (resumability) — resumability
  • orchestration layer — lớp điều phối
  • bước (steps) — steps
  • directive — chỉ thị (như "use workflow", "use step")
  • deterministic — xác định

Nội dung chi tiết

Giới thiệu Workflow Development Kit

Cảm ơn tất cả các bạn đã đến. Xin chào. Tôi không biết các bạn thế nào, nhưng các Tác nhân của tôi thích tập trung vào các khả năngtính năng, còn tôi thì không muốn bận tâm về tất cả những nỗ lực bổ sung cần thiết để đưa một thứ hoạt động cục bộ vào production. Một điều rất hữu ích cho việc này là một workflow pattern, và đó là lý do tại sao chúng tôi đã phát triển Workflow Development Kit, là điều chúng ta sẽ nói đến hôm nay. Có lẽ nếu bạn ở đây, bạn cũng đã gặp phải những vấn đề tương tự. Và hôm nay, chúng ta sẽ biến một coding agent thành một workflow, hỗ trợ một coding agent trong suốt phiên này.

Thiết lập môi trường và ví dụ ban đầu

Tôi sẽ tập trung vào slide này. Chúng ta có một ví dụ open source đã sẵn sàng. Nó nằm trên repository Vercel/examples. Bạn có thể clone nó và xem ứng dụng bip-coding-patch-app bên trong. Chúng ta sẽ sử dụng ứng dụng này cho bản demo hôm nay. Và sau khi hoàn thành, chúng ta sẽ có khả năng quan sát (observability) hạng nhất được tích hợp sẵn, cùng với độ bền (durability) và độ tin cậy (reliability). Chúng ta sẽ có rất nhiều tính năng bổ sung như khả năng tiếp tục (resumability), và Workflow Development Kit giúp việc thêm các workflow mới, bền bỉ và những thứ tương tự trở nên rất dễ dàng.

Vấn đề với Agent Loop truyền thống

Vì vậy, nếu bạn nghĩ về Agent Loop chung mà tất cả chúng ta đã thấy trước đây, chúng ta chủ yếu có các lệnh gọi qua lại từ Mô hình Ngôn ngữ Lớn (LLM) đến các tool callsbackend code của chúng ta, bao gồm MCP server, tương tự như các async tasks. Và cách thông thường để thực hiện điều này là kết nối một số queues và một database, đặc biệt nếu bạn đang xây dựng các tác nhân chạy dài có thể mất hàng giờ. Và bạn muốn mở rộng quy mô, đồng thời bạn đang chạy trên serverless, ví dụ, bạn muốn một lớp độ tin cậy nào đó ở giữa, mà thông thường được thực hiện bởi các queues.

Bạn cũng sẽ cần thêm rất nhiều code xử lý lỗi và retry. Bạn sẽ cần lưu trữ tất cả các tin nhắn mà mọi người đang gửi, và quản lý các chuyển đổi trạng thái. Và bạn có thể cũng cần thêm một lớp khả năng quan sát nào đó ở giữa. Tất cả những điều đó, chúng ta sẽ thực hiện hôm nay chỉ bằng một thư viện duy nhất, đó là Workflow Development Kit. Nó là open source, và nó chạy với bất kỳ frontend TypeScript hoặc backend nào của bạn, và cũng có thể chạy trên bất kỳ Claude nào. Hôm nay chúng ta sẽ triển khai lên Vercel, nhưng điều này cũng có thể dễ dàng chạy trên bất kỳ Claude stacks nào của bạn, hoặc server-based, hoặc bất kỳ custom stacks nào của bạn.

Giới thiệu về Workflow Pattern

Được rồi, ai ở đây đã từng nghe về workflow pattern, hoặc đã sử dụng workflow library trước đây? Giơ tay lên nào. Được rồi, chưa đến một nửa. Tôi sẽ nhanh chóng giải thích workflow pattern là gì để làm rõ những gì chúng ta đang làm, và sau đó trong khoảng hai phút, tôi sẽ cho các bạn thấy tôi sẽ làm gì.

Workflow pattern về cơ bản là một lớp orchestration tách code của bạn thành các bước có thể chạy độc lập, có thể được retry và có dữ liệu của chúng được persisted. Lớp orchestration này chúng tôi gọi là một workflow, mặc dù một số nền tảng có thể có các tên khác cho nó. Trong trường hợp của chúng ta ở đây, phần workflowloop gọi các LLM calls, rồi quay lại các tool calls, và sau đó lại quay lại các LLM calls. Và các bước sẽ là các tool callsLLM calls thực tế của chúng ta.

Kế hoạch DemoWorkshop

Được rồi, nhìn vào chương trình của chúng ta hôm nay, chúng ta sẽ đi sâu vào code. Chúng ta sẽ thêm Workflow Development Kit, việc này sẽ khá nhanh chóng, và sau đó chúng ta có rất nhiều thời gian để nói về các tính năng bổ sung thú vị mà nó mang lại như resumable streams sẵn có, cách tạm dừng (suspend) và tiếp tục (resume) tại bất kỳ điểm nào, và cách thêm webhooks cho các quy trình human-in-the-loop. Cuối cùng, sẽ có đủ thời gian cho câu hỏi, nhưng có một lý do bạn ở đây trong workshop chứ không phải xem trực tuyến, đó là bạn có thể đặt câu hỏi. Vui lòng làm như vậy bất cứ lúc nào; cứ giơ tay hoặc nói lên câu hỏi của bạn, và chúng tôi sẽ giải quyết.

Chuẩn bị môi trường Codebase

Được rồi, như tôi đã nói, chúng ta đang làm việc với repository Vercel/examples, và chúng ta sẽ làm việc trên branch conf/1-base. Tại sao lại là branch này? Tôi đã loại bỏ một loạt các boilerplate code khỏi ví dụ để đảm bảo chúng ta có thể tập trung vào những phần quan trọng nhất. Và mỗi điểm kiểm tra từ workshop này sẽ có branch riêng của nó. Vì vậy, nếu bạn không trực tiếp code theo, bạn cũng có thể kiểm tra các bước từng bước và sau đó kiểm tra các diffs để xem điều gì đã thay đổi giữa các lần chạy của chúng ta.

Tôi đã chạy npm run dev cục bộ trên nền tảng này, chỉ để cho các bạn thấy nó trông như thế nào. Tôi sẽ chạy một query đơn giản. Vậy đây là một coding agent, đúng không? Nó giống như một code editor, nhưng không có chức năng chỉnh sửa code thực tế. Và nó có thể nhận một lời nhắc (prompt) để tạo file, và cuối cùng nó sẽ hiển thị cho bạn một iframe với ứng dụng hoàn chỉnh đã được triển khai (deployed). Vì vậy, nó chủ yếu là UI với một vài tool calls đơn giản mà chúng ta sẽ xem xét trong giây lát, và file systemoutput chạy qua Vercel sandbox, nhưng bạn cũng có thể dễ dàng chạy cái này cục bộ.

Tổng quan về Code hiện tại và các Công cụ

Nhìn vào code, tôi sẽ đi và kiểm tra branch hiện tại của chúng ta. Nhìn vào code, chúng ta có một điểm cuối API (endpoint) chấp nhận các tin nhắn chat của chúng ta, đúng không? Và nó thực hiện một số kiểm tra model ID thông thường, để xem mô hình có được hỗ trợ hay không. Và cuối cùng, nó sẽ chỉ đơn giản tạo một tác nhân AI.

(Có người hỏi) Branch đó là gì lại một lần nữa? Branchconf/1-base. Bạn vừa tìm thấy à? Vâng. Và bạn có thể thấy chúng ta sẽ chuyển sang conf/2-base, v.v. Cứ tìm theo số và bạn sẽ tìm thấy tất cả các điểm kiểm tra.

Vâng, điểm cuối API chính của chúng ta chỉ chấp nhận một số tin nhắn và gọi AI SDK agent, về cơ bản cũng giống như một stream text call. Chúng ta sẽ truyền một số công cụ (tools) và sau đó bật loop cho các stream text calls. Và sau đó nó sẽ stream tất cả các chunk được tạo ra trở lại client theo một định dạng mà client dễ hiểu. Đây là tất cả code thông thường của AI SDK mà bạn có thể thay thế bằng một thư viện khác nếu muốn. Code này chủ yếu phục vụ để hỗ trợ UI. Nhưng một lần nữa, tất cả các phần tác nhân thực tế đều rất đơn giản. Nó xảy ra ở đây.

Vậy hãy cùng xem các công cụ mà chúng ta có. Chúng ta có bốn công cụ: createSandbox, getSandboxUrl. Chúng rất đơn giản. Chúng ta chỉ wrap các hàm sandbox.createsandbox.getURL của Vercel. Tương tự với runCommand, về cơ bản nó wrap sandbox.runCommand, và runWriteFiles sẽ tạo file từ một lời nhắc đơn giản. Và chúng ta sẽ xem xét một trong những công cụ này. Ví dụ, chúng ta có một lời nhắc trông giống như một tệp Markdown, phác thảo những gì nên làm và những gì không nên làm. Và trường hợp khó của tôi là tôi không làm việc. Đó là một tool call thú vị.

Chúng ta cũng có một input schema, đó là một Zod schema cho những gì AI SDK mong đợi. Tất cả những điều này đều rất chuẩn. Và sau đó là một hàm execute wrap sandbox.runCommand với một số xử lý lỗi. Vậy đó về cơ bản là toàn bộ code tác nhân của chúng ta. Được thiết lập trong một ứng dụng. Và sau đó chúng ta chỉ cần gọi useChat từ AI SDK để tiêu thụ stream và hiển thị mọi thứ trên UI.

Bắt đầu tích hợp Workflow

Vậy hãy bắt đầu thêm workflow vào đây. Có câu hỏi nào trước khi tôi bắt đầu không? Tuyệt vời.

Được rồi. Bước một, chúng ta sẽ chạy các cài đặt môi trường cho workflow@workflow/AI, điều này sẽ cung cấp cho chúng ta phiên bản mới nhất. Workflowthư viện chính, và @workflow/AI cung cấp một số hàm trợ giúp để làm việc hiệu quả với Workflow Development Kit.

Bây giờ chúng ta đã cài đặt xong, chúng ta đang chạy một Next.js app ở đây. Vì vậy, chúng ta sẽ mở rộng compiler để biên dịch workflow code của chúng ta bằng cách sử dụng useWorkflow với workflow. Chúng ta có thể import điều này từ @workflow/next. Và điều đó sẽ thiết lập Next.js. Vâng. Rất tốt, câu hỏi hay. Bạn đang ở trong thư mục example/bip-coding. Vâng.

Vì vậy, tôi nghĩ điều này sẽ cho compiler biết để cũng biên dịch các workflow của chúng ta một cách riêng biệt, điều mà chúng ta sẽ đi sâu hơn một chút trong giây lát. Và sau đó để tiện lợi, chúng ta cũng có thể thêm một TypeScript plugin vào tsconfig của chúng ta. Cùng package đó. Và điều đó sẽ cung cấp cho chúng ta một số auto-completions tốt hơn cho workflow code của chúng ta.

Viết lớp Orchestration và đánh dấu Bước

Và vì vậy chúng ta đã nói về workflow của chúng ta có một lớp orchestration và có một số bước. Điều đầu tiên chúng ta sẽ làm là viết lớp orchestration. Trong trường hợp của chúng ta, đó về cơ bản chỉ là loop gọi các bước qua lại. Chúng ta sẽ thêm một file mới. Bạn có thể đặt tên nó là gì tùy thích. Và chúng ta sẽ lấy agent call của chúng ta và chuyển nó sang đó. Và tôi sẽ gọi đây là our_code_workflow, đây sẽ là tất cả workflow code của chúng ta. Và sau đó tôi sẽ thêm một loạt các imports. (Cảm ơn, AI.)

Vậy là chúng ta chỉ đơn giản là truyền hầu hết các arguments mà chúng ta sẽ nhận được từ đây sang đó. Và điều này về cơ bản hoàn thành việc không làm gì khác ngoài việc kéo một số workflow code vào file của chúng ta.

Đây là điều thú vị. Bây giờ đây là code (đây là một hàm riêng biệt), chúng ta có thể sử dụng directive useWorkflow, điều này sẽ đánh dấu hàm này cho compiler của chúng ta như một hàm workflow. Vậy điều này làm gì, under the hood, là nó biên dịch tất cả code liên quan đến hàm này, và nó đảm bảo rằng không có imports nào gây ra side effects. Bởi vì workflow orchestration layer cần phải deterministic. Để nó có thể được chạy lại một cách deterministic và không có lo ngại về state pollution.

Xử lý StreamRuntime

Vậy bây giờ chúng ta có điều này, chúng ta sẽ cần đánh dấu các LLM calls của chúng ta là các bước. Và bởi vì các LLM calls đang diễn ra bên trong tác nhân, điều này hơi khó thực hiện ở đây. Và vì vậy, chúng tôi đã tạo ra một durable agent class, về cơ bản là tương tự như tác nhân nhưng có useStep được đánh dấu trong các LLM calls thực tế mà nó thực hiện under the hood.

Vậy thì, sau khi thiết lập xong, chúng ta sẽ await quá trình streaming thực tế. Và hãy xem liệu có gì nữa không. Chúng ta cần kiểm tra lỗi. Ồ, vâng, chúng ta cần một stream để ghi vào. Trước đây, chúng ta có thể ghi trực tiếp vào streamAPI handler cung cấp. Bây giờ, chúng ta sẽ phải tạo một stream mới để ghi vào. Chúng tôi export một hàm getWritable từ workflow, mà nó sẽ ngầm lấy một stream được liên kết với workflow để ghi dữ liệu vào. Và chúng ta sẽ đi sâu hơn vào điều đó trong giây lát. Nhưng bây giờ, chúng ta sẽ chỉ truyền nó vào tác nhân của chúng ta. Và chúng ta sẽ xem liệu type này có đúng không.

Và cuối cùng, trở lại trong workflow thực tế của chúng ta, chúng ta cần gọi workflow theo cách mà framework hiểu, đó là một lệnh gọi start với các arguments được truyền riêng biệt, về cơ bản là yêu cầu nó bắt đầu một workflow mới trên hàm này. Và start có thể được import từ @workflow/API.

Vậy là bây giờ chúng ta về cơ bản đã tích hợp workflow hoàn chỉnh. Và phần lớn điều này chỉ là kéo một phần code ra và thêm một directive. Và có tình nguyện viên sẵn sàng giúp đỡ bất kỳ ai đang theo dõi và có câu hỏi về debug. Cứ thoải mái hỏi.

Và cuối cùng, lệnh gọi này trả về một run instancestream mà chúng ta vừa ghi vào, và chúng ta có thể trả về stream đó cho UI. Vậy là chúng ta đã hoàn thành định nghĩa workflow.

Đánh dấu Công cụ là các Bước

Và bây giờ, chúng ta cũng đã nói rằng chúng ta sẽ cần đánh dấu mọi thứ là steps. Cái durable agent class đã tự động đánh dấu các LLM callssteps. Nhưng các công cụ của chúng ta hiện tại chưa được đánh dấu là steps. May mắn thay, điều này rất dễ. Trong hàm execute của mỗi công cụ này, bạn chỉ cần viết useStep. Và điều đó sẽ cho compiler biết rằng đây là một chunk code riêng biệt để thực thi trong một instance riêng biệt. Đúng vậy. Nếu điều này được triển khai lên production, nó sẽ chạy trong một serverless instance riêng biệt. Và các inputoutput sẽ được cache nếu nó đã chạy rồi, và nó sẽ được retry nếu thất bại.

Vì vậy, tôi sẽ đi qua các tool calls khác và cũng thêm useStep vào chúng. May mắn thay, chúng ta chỉ có bốn công cụ. Và điều đó sẽ hoàn tất quá trình chuyển đổi của chúng ta.

Kiểm tra tích hợp Workflow

Vậy bây giờ chúng ta có thể chạy npm run dev. Xem liệu điều này có hoạt động như mong đợi không. Chúng ta sẽ tải lại trang của mình. Có vẻ như không có gì thay đổi. Hãy thực sự chạy một query. Và chúng ta có thể thấy rằng nó vẫn đang streaming như mong đợi.

Vậy đối với chúng ta, khi phát triển cục bộ, tất cả những gì chúng ta phải làm là kéo một hàm ra và sau đó thêm một vài directives. Nhưng bây giờ, nếu tôi triển khai nó lên bất kỳ adapter nào — ví dụ, Vercel hoặc một AWS adapter, hoặc có thể là adapter của riêng bạn — thì nó sẽ chạy trong môi trường isolation với durability và tất cả những điều tốt đẹp đó.

Phát Triển Cục Bộ và Khả Năng Quan Sát

Và một điều thực sự tuyệt vời cho việc phát triển cục bộ là nếu tôi truy cập vào cùng thư mục này và chạy npx workflow web, đây chỉ là một lệnh CLI để khởi động một giao diện người dùng web cục bộ nhằm kiểm tra các phiên chạy của chúng ta. Bạn có thể thấy phiên chạy của chúng ta hiện vẫn đang chạy. Mỗi bước, mọi thứ không chỉ là một bước sẽ có một span tại đây, và bạn có thể kiểm tra đầu vào, đầu rasự kiện liên quan. Và chúng ta có thể thấy quy trình làm việc của chúng ta vừa hoàn thành, tôi nghĩ vậy. Và vâng, phần này được tích hợp sẵn. Mỗi khi bạn nhắc mã hoặc đó là một phiên bản của quy trình làm việc chạy hoàn thành. Vậy thì mỗi cái đều là, vâng, chính xác là như vậy. Và bạn có thể mô hình hóa điều này theo bất kỳ cách nào bạn muốn. Bạn cũng có thể mô hình hóa toàn bộ một phiên người dùng như một quy trình làm việc duy nhất và để quy trình làm việc đợi truy vấn tiếp theo. Và sau đó, chúng ta có thể chạy mã trong nhiều tuần nếu cần, về cơ bản, và tôi sẽ đi sâu vào một số công cụ cho việc đó trong giây lát.

Bây giờ chúng ta đã thiết lập xong, bạn có thể thấy ở phía bên phải, chúng ta không nhận được bất kỳ phản hồi hữu ích nào. Nhưng nếu tôi truy cập liên kết này, vì nó có thể đã được tạo đúng cách, hoặc nó có khách hàng. Dù bằng cách nào, chúng ta cũng không nhận được đầu ra nào ở phía bên phải. Lý do điều này xảy ra là chúng ta đang truyền trực tiếp đầu ra của tác nhân đến máy khách, nhưng các công cụ của chúng ta hiện không thực hiện bất kỳ lệnh gọi stream nào. Vậy chúng ta có thể làm gì là tương tự trong các lệnh gọi công cụ của mình, chúng ta có thể lấy rightable, vốn sẽ lấy cùng phiên bản rightable như bất kỳ quy trình làm việc nào khác. Có một lượng luồng dữ liệu vô hạn mà chúng ta có thể tạo và tiêu thụ trong một quy trình làm việc. Và bạn cũng có thể định kiểu chúng với một tên nhất định và sau đó tìm nạp chúng từ đó. Nhưng điều này sẽ lấy phiên bản mặc định. Và một khi chúng ta có một rightable, chúng ta thực sự có thể kết nối với rightable bằng cách lấy công cụ ghi. Và bây giờ chúng ta có thể ghi bất kỳ loại thông tin nào vào giao diện người dùng, tới người tiêu dùng. Tôi nghĩ chúng ta muốn thứ gì đó như data creates samples. Tôi nghĩ đó là thứ tôi đã kết nối trong UI. Và sau đó chúng ta sẽ gọi ID, chúng ta muốn ID của môi trường biệt lập, chúng ta sẽ phải làm điều đó ở đây. Vậy đây là tôi đang viết một gói dữ liệuUI của chúng ta biết cách tiêu thụ. Vậy thì không phải là nó đang như thế. Và tôi tải lại ứng dụng. Và vì vậy, chúng ta sẽ thấy rằng ít nhất lệnh gọi tạo sandbox có vẻ sẽ khởi động khá tốt. Bạn nói rằng bạn chưa nghe hoặc thậm chí có một luồng dữ liệu có thể được tạo. Và tôi biết ý bạn là gì.

Quản Lý Luồng Dữ Liệu và Tính Bền Vững

Vâng, một luồng dữ liệu, quy trình làm việc, vậy dữ liệu mà chúng sử dụng cho quy trình làm việc trong phát triển cục bộ, đúng không, là chỉ qua tệp trong môi trường sản xuất. Đây có thể là một phiên bản ghi. Hỗ trợ quy trình làm việc gọi nó để tạo một luồng dữ liệu mới, ví dụ, trong Redis, đúng không, và sau đó truyền luồng dữ liệu đó trở lại. Và vì vậy, bất cứ khi nào bạn gọi rightable đó, nó sẽ tạo một luồng dữ liệu, ví dụ, một lần nữa, trong Redis với ID của quy trình làm việc đó. Và nó sẽ truyền lại. Vì vậy, bất kỳ bước nào cũng có thể đính kèm vào đó và bất kỳ máy khách nào cũng có thể đính kèm vào đó. Và trong localhost, điều này sẽ được ghi vào một tệp và đọc từ một tệp. Bạn đang thiết lập ngay bây giờ.

Trước đây, chúng ta có một trình xử lý API giao tiếp với các thông báo gọi tác nhân và sau đó truyền trực tiếp các thông báo trở lại trên trình xử lý API đó. Bây giờ chúng ta có một trình xử lý API gọi nó, nó bắt đầu một quy trình làm việc. Và nó sẽ truyền lại luồng dữ liệuquy trình làm việc này tạo ra. Nhưng điều này cũng cho phép chúng ta làm, tôi nghĩ rằng đã có một số công việc được thực hiện đúng. Khi chúng ta khởi động máy chủ để xem liệu điều đó có đúng không. Bất cứ điều gì khác, nhưng cho đến nay, việc thiết lập điều này đến đây. Nó sẽ giúp chúng ta. Có vẻ tốt. Điểm mà bạn đã đề cập, điều này cho phép chúng ta làm là luồng dữ liệu không bị ràng buộc với trình xử lý API. Điều này có nghĩa là bất cứ lúc nào chúng ta cũng có thể tiếp tục luồng dữ liệu này. Nếu bạn mất kết nối với trình xử lý API của mình và sau đó có một kết nối lại. Luồng dữ liệu này vẫn tồn tại và chúng ta có thể kết nối lại với luồng dữ liệu để tiếp tục phiên. Điều này cũng là một phần của khía cạnh bền vững nơi mọi thứ bạn làm trong một quy trình làm việc, bạn có thể tiếp tục bất cứ lúc nào. Tôi sẽ khởi động lại truy vấn này và hy vọng rằng nó sẽ hoạt động lần này.

Vâng. Bây giờ tôi đã kết nối gói dữ liệu này, bạn có thể thấy tính năng xử lý giao diện người dùng đặc biệt để tạo môi trường biệt lập hoạt động. Nhưng ngay cả sau khi hoàn thành, nó vẫn không hiển thị là đã xong. Điều này là do chúng ta chỉ đang ghi các gói dữ liệu trạng thái tải. Tôi có thể xem xét tất cả các công cụ của chúng ta, tôi có thể thêm nhiều gói dữ liệu hơn và làm giao diện người dùng phong phú hơn. Nhưng tôi sẽ kiểm tra một nhánh khác, đó là nhánh Conf-slash 3-slip, là bước tiếp theo, vốn đã có những điều này. Tôi sẽ chọn quy trình làm việc số hai, Conf-slash 2-workflow. Nhưng đã có tất cả các lệnh gọi ghi này được điền sẵn. Không có sự khác biệt nào khác. Vì vậy, bây giờ tất cả các công cụ của chúng ta đều có các lệnh gọi ghi này, luồng dữ liệu một lần nữa có lẽ sẽ trông giống như khi chúng ta bắt đầu trong ứng dụng này.

Tiếp Tục Phiên và Khả Năng Triển Khai

Được rồi, bây giờ chúng ta đã có luồng dữ liệu hoạt động trở lại, mọi thứ đều hoạt động như mong đợi. Chúng ta có nhiều khả năng quan sát hơn và chúng ta có thể triển khai điều này với tính bền vững. Tôi đã nói về luồng dữ liệu có thể tiếp tục trước đây. Chúng ta sẽ xem liệu chúng ta có thể làm cho luồng dữ liệu này tiếp tục để có các phiên kép hay không. Điều duy nhất chúng ta cần làm để điều đó hoạt động là truy cập điểm cuối API của chúng ta. Và điều chúng ta nhận được, ví dụ, chúng ta cũng sẽ trả về ID của quy trình làm việc như thông tin bổ sung. Vì vậy, tôi có thể trả về run.run ID, chẳng hạn. Điều này chỉ là, một lần nữa, bất kỳ cách nào bạn làm điều này đều ổn. Tôi nghĩ nó là một tiêu đề ở đây vì chúng ta đã trả về một luồng dữ liệu. Nhưng bất kỳ cách nào bạn truyền ID đến giao diện người dùng là điều mà giao diện người dùng có thể sử dụng để tiếp tục luồng dữ liệu từ đó.

Vì vậy, điều chúng ta làm từ đây là giao diện người dùng sẽ có thể quyết định liệu nó có một ID hay không và liệu nó có nên tiếp tục một luồng dữ liệu hay không. Vì vậy, chúng ta sẽ tạo một điểm cuối mới. Hãy gọi nó là ID cho kiểu /ID hiện có. Sau đó, chúng ta sẽ tạo một thư mục stream. Và chúng ta sẽ thêm một trình xử lý tuyến. Vì vậy, đây chỉ là cấu hình để thêm một tuyến API tại /chat/ID/stream. Và chúng ta sẽ tự động hoàn thành bằng AI. Điều chúng ta đang làm về cơ bản là chúng ta lấy ID từ các tham số. Và sau đó điều chúng ta sẽ làm là gọi get run đến API của quy trình làm việc, vốn sẽ lấy một phiên bản chạy. Và sau đó chúng ta có thể trả về cùng luồng dữ liệu mà chúng ta trả về trong các điểm cuối khác mà không cần gọi tác nhân thực sự, chỉ thực hiện luồng dữ liệu. Và tôi nghĩ điều đó sẽ ổn. Chúng ta cũng đang lấy chỉ mục bắt đầu của mình, điều này rất hữu ích từ AI. Chúng ta có thể lấy một luồng dữ liệu đọc được từ một điểm bắt đầu nhất định. Tôi nghĩ đó là lý do tại sao tất cả các máy tính đều như vậy. Vì vậy, nếu bạn đang cố gắng tiếp tục một luồng dữ liệu giữa chừng, bạn có thể truyền khối mà bạn đang ở khi bạn dừng lại ban đầu.

Tích Hợp Giao Diện Người Dùng và Các Tính Năng Mở Rộng

Bây giờ điều này đã xong, tôi sẽ bỏ chú thích những thứ chúng ta hiện không cần. Chúng ta cần giao diện người dùng để hỗ trợ toán tử bổ sung này để tiếp tục hoặc để bắt đầu một cuộc trò chuyện mới. Vì vậy, tôi sẽ truy cập giao diện người dùng trò chuyện của chúng ta và tôi sẽ kéo một số mã từ một nhánh khác để đơn giản, nằm trên nhánh bốn-gạch-ngang-stream, mà tôi sẽ chỉ hiển thị để hoàn thành. Chúng ta đã thực hiện một lệnh gọi use chat trong giao diện người dùng để tiêu thụ luồng dữ liệu. Và tất cả những gì chúng ta đã thêm bây giờ là một lớp vận chuyển, là khối lớn này ở đây có một số middleware cho luồng dữ liệu nói rằng nếu tôi đang cố gắng bắt đầu lệnh gọi này, tôi sẽ kiểm tra trước liệu chúng ta có một ID hiện có hay không. Và nếu có, tôi sẽ bắt đầu kết nối lại bằng cách gọi điểm cuối API khác này. Tôi đang nói qua điều này một chút vì đây là xử lý phía máy khách dành cho các chuyên gia. Nếu có thêm câu hỏi về điều này, xin vui lòng hỏi.

Được rồi. Điều đó mang lại cho chúng ta luồng dữ liệu có thể tiếp tục. Và tôi cũng sẽ trình diễn điều gì sẽ xảy ra nếu chúng ta muốn triển khai điều này và xem nó trong môi trường sản xuất. Vì vậy, tôi sẽ gọi cái khác này. Và sau đó chúng ta có thể xem ví dụ xem trước sản xuất trong lúc chờ đợi. Điều tiếp theo chúng ta sẽ làm là chúng ta nói về ý nghĩa và khả năng tiếp tục. Các quy trình làm việc, vì cách chúng chạy là mỗi bước chạy trên phiên bản serverless riêng của nó trong môi trường sản xuất. Lớp orchestration của quy trình làm việc thực tế chỉ được gọi rất ngắn gọn để tạo điều kiện cho các bước chạy. Điều này cho phép chúng ta có một quy trình làm việc kéo dài bất kỳ khoảng thời gian nào. Một quy trình làm việc có thể chờ trong một tuần mà không tiêu thụ bất kỳ tài nguyên nào. Điều này được tích hợp vào bộ công cụ phát triển quy trình làm việc. Theo một cách mà chúng ta có thể bên trong một quy trình làm việc, bất cứ điều gì có use workflow, chúng ta có thể đơn giản gọi sleep ba ngày, ví dụ. Và điều đó sẽ, tôi chắc chắn sẽ nói điều này, điều đó sẽ tạm dừng quy trình làm việc trong ba ngày và sau đó tiếp tục từ nơi nó dừng lại. Nếu ai đó đang cố gắng kết nối lại với luồng dữ liệu, ví dụ, đúng không, điều này sẽ ngủ một giờ. Luồng dữ liệu sẽ chỉ kết nối lại với cùng một điểm cuối và mọi thứ sẽ tiếp tục từ đó. Vì vậy, chúng ta không mất gì khi mất phiên bản chạy mã, vì chúng ta luôn có thể khởi động lại nó, tiếp tục từ nơi chúng ta dừng lại. Và điều này hữu ích cho các tác nhân AI, vì chúng ta có thể thực hiện một lệnh gọi thực. Chúng ta có thể có giao diện người dùngtác nhân AI, và chúng ta gọi nó nói rằng, ngủ một khoảng thời gian, và sau đó sử dụng nó để tạo một tác nhân về cơ bản sử dụng tác vụ định kỳ, nơi nó nói rằng mỗi ngày đọc email của tôi và làm điều này. Vì vậy, đó sẽ là ngủ một ngày.

Trạng Thái Tác Nhân và Cơ Chế Khôi Phục

Vâng. Khi tác nhân ngừng hoạt động, điều đó có nghĩa là tất cả trạng thái đều bị mất. Vâng. Vậy khi nó ngủ ba ngày? Không, thì chúng tạm dừng, nhưng một cái sẽ bị hủy, bởi vì đối với một người lo lắng rằng trạng thái trở nên tồi tệ. Trạng thái đó là cách nó hoạt động là bất kỳ lệnh gọi bước nào đều được lưu vào bộ nhớ đệm. Vì vậy, khi bạn muốn một đầu vào đi đến một lệnh gọi bước, chúng ta đăng ký điều đó như một sự kiện, và chúng ta chạy bước. Và nếu bước hoàn thành, chúng ta lưu các đầu ra vào bộ nhớ đệm và nói rằng điều này đã chạy đến khi hoàn thành, đúng không? Vì vậy, nếu nó, nếu nó là một cái gì đó như thế này, nơi chúng ta chạy tác nhân trước, đúng không? Giả sử chúng ta chạy tác nhân, và chúng ta chạy một loạt các bước. Trạng thái của hàm quy trình làm việc tại thời điểm này sẽ được lưu, và tất cả các đầu ra từ tất cả các lệnh gọi bắt đầu sẽ được lưu. Và tại thời điểm chúng ta khởi động lại quy trình làm việc, từ dòng mã cụ thể này, nó sẽ khôi phục toàn bộ trạng thái, và nó sẽ chỉ đi từ đây. Và điều này xảy ra tiềm năng để một lần nữa, chúng ta không phải phát lại bất kỳ điều gì khác theo cách tiêu tốn bất kỳ tài nguyên thực tế nào. Vâng, vì vậy chúng ta có thể sử dụng điều này để tạo một tác nhân về cơ bản là một tác vụ định kỳ một lần nữa, và chúng ta có thể sử dụng nó để tạo các tác nhân chạy trong nhiều tuần, hoặc chuyển hướng với bất kỳ thông tin nào của bạn trong một khoảng thời gian dài rất dài.

Trực Quan Hóa và Triển Khai Trong Môi Trường Sản Xuất

Và trong khi tôi đang nói chuyện, chúng ta đã triển khai ứng dụng hiện tại của chúng ta lên cell, vì vậy tôi có thể kiểm tra nhánh xem trước này, ví dụ, và bạn có thể thấy rằng bây giờ nó trực tuyến và hoạt động giống như thường lệ. Và vâng, nó hoạt động hoàn hảo. Và nếu sau đó, một lần nữa, tôi có thể làm, tôi có thể sử dụng giao diện người dùng để kiểm tra điều này bất cứ lúc nào. Nếu tôi gọi workflow inspect web, hoặc chỉ workflow web với biểu tượng gạch ngang tới celltham số xem trước, ví dụ, chúng sẽ chỉ cho nó biết triển khai của chúng ta được tìm thấy ở đâu, và sau đó chúng sẽ khởi tạo cùng một giao diện người dùng, và bây giờ chúng ta có thể kiểm tra phiên chạy này đang chạy trong môi trường sản xuất, và bạn có thể thấy chúng ta đang nhận được cùng một loại thông tin ở đây. Vâng, đây không phải là để hủy phiên chạy, tôi có thể hủy nó. Hãy hủy nó. Điều này để cho thấy rằng cách nó hoạt động cục bộ chính xác là cách nó hoạt động trong môi trường sản xuất từ quan điểm khái niệm, đó là trải nghiệm người dùng mà chúng ta đang hướng tới.

Tạo Công Cụ Ngủ (Sleep Tool)

Được rồi, tôi đã nói một chút về ngủ và trạng thái chờ. Chúng ta hãy viết lệnh gọi công cụ ngủ này. Nó sẽ rất đơn giản. Tôi sẽ sao chép, ý tôi là, tôi sẽ cập nhật nó ở trên, nhưng tôi sẽ sao chép cái này và viết nó từ đầu. Chúng ta sẽ viết một lệnh gọi công cụ ngủ. Tôi sẽ gọi nó là sleep. Vâng. Và chúng ta sẽ giảm đầu vào sleep out thành một cái gì đó như lượng mili giâylệnh chạy thực tế không phải là cái này. Và thay vào đó chỉ cần gọi sleep.

Tích hợp SleepQuan Sát Workflow

Bởi vì sleep đã là một step mà chúng ta xuất từ thư viện workflow, chúng ta không cần phải đánh dấu phần mở rộng là một step mới. Nhưng bây giờ, hãy xem liệu đây có phải là... đây phải là một con số. Đó. (Một người khác hỏi): "Bạn nói lại điều đó, tại sao không cần step mới?" Vậy đây đã là một step mà chúng ta xuất từ workflow. khả năng quan sát cũng sẽ hiển thị nó như một step, điều này chúng ta sẽ thấy trong giây lát. Và điều này sẽ hoạt động. lời nhắc đã tốt, chúng ta sẽ sửa đổi nó thành, ví dụ, thế này: "Vâng. Nó chỉ được sử dụng như một công cụ nếu người dùng yêu cầu bạn." Được rồi.

Thiết lập Công Cụ và Hiển thị UI

Chúng ta thiết lập và gọi nó là run_sleep_commandsleep_tool. Chúng ta sẽ thêm điều này vào danh sách công cụ của mình. TypeScript có vẻ hoạt động rất tốt. Bây giờ chúng ta có công cụ này. Chúng ta cũng muốn UI hiển thị khi nó đang sleep. Chúng ta không thể ghi trực tiếp vào một stream từ một workflow vì khi đó nó sẽ không còn xác định nữa, bởi vì mỗi lần chạy workflow sẽ ghi vào stream một lần nữa.

Để giải quyết vấn đề này, chúng tôi sẽ thêm một cái gọi là writable và sử dụng Google ID. Điều này sẽ ghi vào stream, cho phép chúng ta hiển thị nó trong UI một cách chính xác. Sau khi ứng dụng tải, chúng ta có thể thử lời nhắc thứ hai: "ngủ 30 giây rồi trả về right". Điều này cho thấy ứng dụng diễn giải chính xác lệnh gọi sleep. Dù không hiển thị data packet trực tiếp, chúng ta có thể kiểm tra web UI để thấy nó đang thực hiện lệnh gọi sleep và sẽ trả về sau 30 giây.

Webhook và Khả năng Tạm dừng/Tiếp tục Workflow

Một tính năng khác là webhook và khả năng tiếp tục dễ dàng từ webhook. Triển khai webhook thường khá phức tạp, nhưng trong trường hợp của chúng ta, chúng ta có thể thêm một công cụ mới tương tự như cách chúng ta thực hiện sleep. Lệnh gọi công cụ thực tế chỉ là một lệnh gọi log, sau đó chúng ta tạo một webhook được phơi bày về mặt chức năng từ workflow. Chúng ta có thể ghi URL webhook này cho client hoặc bất kỳ ai khác. Điều này sẽ tạm dừng workflow cho đến khi ai đó nhấp vào URL.

Hệ thống sẽ chờ sự chấp thuận của con người trước khi tiếp tục. Khi thay đổi nhánh, có thể cần khởi động lại máy chủ. Cách hoạt động là chúng ta tạo một URLsleep workflow cho đến khi một lệnh gọi đến điểm cuối API đó. Tính năng này đi kèm với nhiều khả năng bổ sung, như phản hồi bằng một đối tượng yêu cầu hoặc kiểm tra body so với một Zod schema trước khi tiếp tục. Điều này mang lại toàn quyền kiểm soát, đồng thời URL được liên kết nội bộ. Khi chạy trên localhost, đó là liên kết localhost; trong môi trường sản xuất, đó sẽ là URL triển khai của bạn. Sau khi nhấp vào URL, workflow sẽ tiếp tục.

Trạng thái Workflow và Tương tác Sandbox

Workflow hoàn toàn bao gồm các step, và các step luôn chạy đến hoàn thành. Sleep là một step có tính chất tạm dừng hoàn toàn workflow và tất cả các step. Không có gì đang chạy trong khi chúng ta sleep. Sleep được mô hình hóa như một step để khả năng quan sát, và nó hoạt động như một lệnh gọi step theo nghĩa nó là một quá trình thực thi mất nhiều thời gian, có thể sử dụng cú pháp await.

Nếu bạn có một tác nhân đang chạy với một workflow, nó sẽ tiếp tục chạy. Nếu bạn kết nối lại thông qua một phiên khác và gọi sleep trong phiên đó, workflow trước sẽ dừng lại. Ví dụ, nếu một workflow đang tính toán số pi và bạn kết nối với cùng một môi trường biệt lập rồi gọi sleep, nó sẽ dừng tính toán.

môi trường biệt lậpcell sandbox, hoạt động như một EC2 instance, giúp khởi tạo một instance để chạy tác nhân mã hóa. Lệnh gọi sleep trong workflow khác với lệnh gọi sleep trong terminal của môi trường biệt lập. Workflow sleep tạm dừng toàn bộ workflow, trong khi lệnh terminal sleep chỉ tạm dừng quá trình trong môi trường biệt lập.

Quản lý Phiên Mã HóaQuyền Truy Cập của Tác Nhân

(Khán giả hỏi): Làm thế nào để khởi tạo các phiên mã hóađiều phối các tác nhân? (Người thuyết trình): Điều đó có thể. Claude Code, đặc biệt là ứng dụng terminal, không sử dụng nhiều tính năng workflow nội bộ. Bạn có thể tự viết phiên bản Claude Code hoặc sử dụng mã nguồn Claude Code và thêm workflow vào đó.

Một tác nhân mã hóa chạy các lệnh trong một step chống lại một môi trường biệt lập (là một VM). Trạng thái VM không được quản lý bởi workflow. Nếu bạn gọi Claude Code trên VM, điều đó giống như một phiên SSH. Tuy nhiên, nếu bạn chạy bất kỳ tác nhân hoặc step nào trong workflow, những step đó sẽ có thể tiếp tụccó thể quan sát được thông qua mô hình workflow.

(Khán giả hỏi): Làm thế nào để kiểm soát quyền truy cập Internet của tác nhân? (Người thuyết trình): Điều này phụ thuộc vào những gì bạn đang thực hiện cho tác nhân. Nếu bạn đang thực hiện lệnh gọi công cụlệnh gọi stream tới nhà cung cấp LLM, các quyền được kiểm soát trong của bạn. Ví dụ, nếu lệnh gọi công cụ cho phép xóa một tài nguyên trong S3, bạn sẽ định cấu hình nó trong của công cụ đó. Workflow là một lớp điều phối chung cho thực thi bền vững và không cung cấp môi trường biệt lập cho việc chạy hoặc tạo tệp. Đó là vai trò của môi trường biệt lập, nơi mỗi khởi tạo môi trường biệt lập là một VM mới chỉ tồn tại trong suốt phiên của bạn.

Mô Hình Triển KhaiNâng Cấp Workflow

Nếu bạn triển khai nhiều workflow tác nhân, ví dụ lên Vercel, mỗi lần triển khai là một URL trực tiếp riêng biệt, sẽ khởi tạo một instance serverless. Các workflow của bạn được gắn với lần triển khai đó. Nếu một tác nhân chạy trong một tuần nhưng bạn triển khai năm lần trong tuần đó, các lần triển khai mới sẽ được cô lập khỏi workflow gốc. Workflow gốc sẽ chạy đến hoàn thành, và bất kỳ workflow mới nào sẽ chạy trên các lần triển khai mới. Hệ thống cũng cho phép nâng cấp giữa các lần triển khai.

Nếu bạn có một workflow chạy trong một năm nhưng có mới và muốn workflow sử dụng trạng thái hiện tại và mới, sẽ có một nút nâng cấp trong UI. Nút này kiểm tra tính tương thích giữa workflow cũ và mới bằng cách kiểm tra chữ ký các step và tất cả sự kiện hiện có. Bạn có thể nâng cấp workflow hoặc hủychạy lại với workflow mới.

Thời Gian Chờ cho các Step Workflow

(Khán giả hỏi): Có thời gian chờ cho các step workflow không? (Người thuyết trình): Có. Trong serverless, các hàm serverless sẽ có thời gian chờ. Điều hay là mỗi step chạy trong hàm serverless riêng của nó, nên thời gian chờ chỉ áp dụng cho từng step. Nếu một step có nguy cơ chạy quá năm hoặc 15 phút (tùy nền tảng), bạn có thể chia nó thành hai step. Nếu một step hết thời gian chờ, nó sẽ thất bại, thử lại, và có thể nhanh hơn. Bạn sẽ thấy trong UI rằng trạng thái đã thử lại nhiều lần sau 15 phút, và sau đó bạn có thể chia nó thành hai step.

Xếp hàng và Kiểm soát Đồng thời

Bạn có thể nâng cấp quy trình làm việc và nó sẽ tiếp tục từ điểm đó. Một vấn đề khác là về việc xếp hàng các quy trình làm việc, ví dụ như tôi kích hoạt agent nhiều lần. Bạn có thể mô hình hóa điều này theo nhiều cách khác nhau. Hiện tại, chúng tôi đang thực hiện điều này từ các API routes, nơi mỗi API call đến API route này sẽ tạo ra một quy trình làm việc mới, và trong trường hợp này, output tương tác duy nhất bạn có là một stream. Nó sẽ thực hiện các tác vụ và ghi vào stream này; không ai theo dõi stream. Chúng ta không biết quy trình làm việc có đang chạy hay không. Bạn có thể kích hoạt việc sử dụng và chúng sẽ chạy ngầm. Về cơ bản, không có giới hạn về số lượng quy trình làm việc bạn có thể tạo vì tất cả chúng đều chạy trong các serverless functions, cho phép bạn mở rộng quy mô theo tài nguyên điện toán (compute) của nhà cung cấp, đây là một lượng lớn.

Bạn cũng có thể liệt kê các lần chạy (runs) đang hoạt động; có một API để giao tiếp với các lần chạy của bạn. Bạn có thể xem tất cả các lần chạy đang hoạt động, chúng đang ở phiên bản nào, trên stack nào, và hủy chúng. Về tính đồng thời (concurrency), hiện tại nó có tính đồng thời vô hạn (infinite concurrency), nhưng rất sớm, chúng tôi sẽ thêm tính đồng thời theo bước hoặc theo quy trình làm việc. Bạn có thể chỉ định rằng quy trình làm việc này chỉ được phép chạy tối đa 10 lần cùng một lúc. Mọi yêu cầu khởi tạo thêm sẽ được xếp hàng chờ (queue) cho đến khi số lượng đang chạy giảm xuống và sau đó sẽ tiếp tục. Bạn cũng có thể sử dụng tính năng này để tạo ra một cấp độ miễn phí (free tier) cho sản phẩm của mình, nơi có các phiên bản chạy cho free tier tại bất kỳ thời điểm nào, và những người dùng đến sau sẽ phải chờ trong hàng đợi. Nhưng pro tier của bạn thì có tính đồng thời vô hạn.

Hoàn tác Bước và Quản lý Trạng thái

Tôi có thể hoàn tác (roll back) các bước theo cách, ví dụ tôi có 10 bước nhưng ở bước thứ bảy tôi muốn quay lại bước thứ ba không? Liệu có thể đặt lại trạng thái (state) của quy trình làm việc không? Về mặt kỹ thuật, bạn có thể làm điều này. Chúng tôi hiện chưa hỗ trợ nhưng nó sẽ rất quan trọng vì đầu vào (inputs) và đầu ra (outputs) của mỗi bước đều được lưu vào bộ nhớ đệm (cached). Chúng tôi có thể bắt đầu lại quy trình làm việc từ bất kỳ điểm nào và tiếp tục từ đó. Vì vậy, chúng tôi cần hiển thị chức năng này trong giao diện người dùng (UI) để tiếp tục từ một bước cụ thể, nhưng vâng, điều đó hoàn toàn có thể.

Nhiều khả năng, điều bạn muốn làm là kiểm soát quy trình làm việc, sau đó giám sát các bước và xem liệu chúng có đang được sử dụng hay không, hoặc ghi lại trạng thái của mã và có thể thực hiện bước này và thay đổi trạng thái hoặc làm gì đó, nhưng nhật ký sự kiện (event log) đang được triển khai. Bạn có thể vào nhật ký model.

Gắn Metadata vào Quy trình làm việc

Có cách nào để đính kèm metadata vào các inputsoutputs được truyền qua lại và lưu vào bộ nhớ đệm không, hay nó luôn phải nằm trong inputs/outputs của frontend? Bạn cũng có thể đính kèm metadata. Chúng tôi sẽ sớm có API gắn thẻ (tagging API) nơi bạn có thể thêm các tag tùy ý vào quy trình làm việc tại bất kỳ thời điểm nào trong quá trình chạy quy trình làm việc, và bạn cũng có thể sử dụng các tag đó để quyết định liệu có nên dừng sớm hay trùng lặp các lần chạy của mình.

Kiến trúc Triển khai và Backend

Về việc triển khai, liệu chúng ta có bị ràng buộc với một nền tảng cụ thể nào không? Như tôi đã đề cập trước đây, có hai khía cạnh. Một là phía frontend của framework. Các tài liệu đang được sử dụng. Bạn có thể thấy đối với các trang frontend, đó là lớp API mà nó có thể hoạt động cùng. Chúng tôi hiện đang hỗ trợ tất cả các nền tảng này và nhiều hơn nữa sẽ sớm ra mắt. Và sau đó là mục tiêu frontend riêng biệt. Hiện tại, bạn có thể triển khai lên bất kỳ nền tảng frontend nào.

Điều này sẽ hoạt động với bất kỳ tool nào bạn có thể triển khai, ví dụ như tool của Next.js hoặc bất kỳ framework nào khác. Chúng tôi có các triển khai, triển khai đầu tiên cho một ví dụ PostgreSQL sử dụng PostgreSQL làm lớp bền vững (durability level). Khi chúng tôi phát triển và cộng đồng tham gia, chúng tôi sẽ hỗ trợ về cơ bản bất kỳ backend nào, bởi vì loại framework này kết nối với bất kỳ lớp lưu trữ (storage) hoặc hàng đợi (queue) nào. Bất kỳ thứ gì cung cấp cơ sở dữ liệu lưu trữ (storage database) hoặc hàng đợi (queue) đều có thể được sử dụng làm backend.

Khả năng Quan sát

Bạn có một câu hỏi rất hay về khả năng quan sát mới. Chúng tôi cũng có các nhà cung cấp cho DataDog và các công cụ thuật toán. Chúng tôi có nhiều thứ. Chúng tôi có một API mà bạn có thể sử dụng để truy cập dữ liệu trực tiếp, và chúng tôi cũng có các thành phần UI mã nguồn mở mà bạn có thể sử dụng để hiển thị dữ liệu. Sau đó, nếu muốn, bạn có thể xuất dữ liệu này sang DataDog.

Lập lịch và Điều khiển Luồng trong Quy trình làm việc

Bạn đã nói về quy trình làm việc sẵn sàng. Vì đây chỉ là TypeScript, nếu bạn đang ở trong một quy trình làm việc, bạn có thể làm những thứ như gọi trạng thái. Đây là điều chúng ta có thể tiếp tục sau một ngày. Điều bạn cũng có thể làm là coi đây là một promise hoặc lấy nó dưới dạng một promise. Vì vậy, bạn có thể thực hiện while true, sleep một ngày, rồi chạy mã của mình, và nó sẽ chạy mỗi ngày một lần. Nếu bạn muốn chạy mỗi ngày một lần vào lúc 2 giờ sáng, bạn có thể tính toán thời gian đến 1 giờ sáng ngày mai. Sau đó là xong.

Bạn cũng có thể thức dậy mỗi giờ, thực hiện một số kiểm tra xem bạn có thực sự muốn chạy phần còn lại của mã hay không. Việc sleep không phải là hoàn hảo. Nếu bạn muốn kiểm soát tính đồng thời hoặc bất kỳ loại điều khiển xác định tự động nào, bạn có một luồng hoàn chỉnh bằng TypeScript ở đây. Bạn có thể kiểm tra các API bên ngoài, ví dụ, bạn phải đóng gói chúng trong một bước (step), nhưng bạn có thể thực hiện các fetch call nếu muốn kiểm tra dữ liệu và sau đó xác định từ đó. Nếu bạn muốn có một agent chạy định kỳ nhưng mỗi ngày, bạn có thể có một wrapper lập lịch, một sổ làm việc lập lịch hoạt động và các luồng agent khác.

Bạn cũng có thể bắt đầu các quy trình làm việc từ các quy trình làm việc khác, hoặc bạn có thể làm điều này: sleep một ngày và sau đó gọi agent của bạn. Tùy thuộc vào stream bạn muốn ghi vào, điều này đều nằm trong cùng một stream. Có lẽ bạn không muốn điều đó. Có lẽ bạn cũng có thể có writeable cho phép bạn sử dụng namespace. Bạn có thể lấy một writeable mới ở đây và sau đó mỗi khi nó chạy, bạn có thể có một stream mới có tên xác định và bạn có thể chọn stream nào để kết nối.

Hủy bỏ Quy trình làm việc

Có logic hủy bỏ không? Giả sử tôi có thứ gì đó đang chờ rất lâu và sau đó tôi quyết định không muốn nó nữa. Làm thế nào tôi có thể dừng một sleep hiện có khỏi việc đánh thức? Đúng vậy. Bạn có thể hủy các quy trình làm việc từ UI của khả năng quan sát, hoặc từ API, hoặc CLI. Tất cả các kênh đó đều có chức năng hủy. Hoặc bạn có thể nói, tôi không biết liệu tôi có muốn sleep một ngày rồi tiếp tục hay không. Điều bạn có thể làm là thực hiện một cái gì đó như this.race, và bạn có thể sleep một ngày và làm một điều gì đó khác, thực ra, sự chấp thuận của con người. Có thể thức dậy sớm hơn nếu một người dùng bấm nút thay vì chờ một ngày.

Giao tiếp giữa các Tác nhân

Nếu bạn có nhiều tác nhân đang chạy, cách được khuyên dùng để chúng giao tiếp với nhau là gì? Điều đó phụ thuộc vào loại giao tiếp bạn đang tìm kiếm.

Trong các bước (steps), bạn có quyền truy cập vào tất cả các API mã hoặc API của Node.js, như fetch. Bạn có thể sử dụng cơ sở dữ liệu. Nếu bạn muốn tự động hóa trên nguồn dữ liệu của riêng mình, bạn có một cơ sở dữ liệu. Nếu bạn muốn có nhiều tác nhân, bạn có thể sử dụng cùng một số stream để chia sẻ stream.

Đối với lớp quy trình làm việc, không có side effects vì nếu bạn cố gắng nhập mã gây side effects, nó sẽ bị chặn. Tuy nhiên, các bước (steps) thì có thể có side effects – đó chính là mục đích của chúng. Vì vậy, nếu một bước thất bại, chúng ta cần đảm bảo rằng stream của nó được cập nhật và có thể chạy lại trong cơ sở dữ liệu của chúng ta.

Xử lý Lỗi và Thử lại

Có một số điều khiển bạn có thể thêm vào đây, nơi nếu một bước thất bại, nó thường sẽ thất bại với một lỗi và quy trình làm việc có thể được thử lại. Bạn cũng có thể bắt lỗi này và nói, nếu đó là loại lỗi này, đừng thử lại mà thay vào đó hãy báo hiệu cho con người làm điều gì đó hoặc thử một con đường khác.

Công cụ và Nhánh Phát triển

Bạn có một trong các nhánh chứa mã hoàn chỉnh cho những gì bạn vừa làm. Vâng. Tất cả chúng đều xây dựng dựa trên nhau. Ví dụ, nhánh Conf/five-webhookstool phê duyệt của con người, tool sleep được gọi là Resumable Streams và đây là quy trình làm việc. Tôi sẽ xem làm thế nào tôi có thể đăng một cái lên quyền truy cập chung. Chỉ đọc. Vâng, chúng tôi sẽ làm điều đó. Các quy trình làm việc đang ở giai đoạn beta, v.v. Chúng ta sẽ thấy các hộp. Vâng, tôi quên đề cập rằng phát triển quy trình làm việc quan trọng này đang ở giai đoạn beta và sẽ được truy cập vào tháng Giêng, tôi tin vậy.

Tình trạng và Đóng góp Cộng đồng

Và chúng tôi có GitHub. Cuối cùng, tôi nghĩ rằng hơn một triệu quy trình làm việc đã được chạy trong một ngày. Được rồi. Vì vậy, các bạn biết đó, việc làm cho API ổn định và giải quyết nhiều vấn đề là một quá trình, nhưng tôi nghĩ nhiều thứ chúng tôi đã đạt được là một phần của các tham vọng khác.

Đây là bất kỳ tính năng nào bạn cần hoặc thực sự muốn thấy. Chúng tôi có một phần RFC (Yêu cầu nhận xét) trên GitHub discussions dành cho các tính năng sắp tới. Cảm ơn vì tất cả chúng ta đã tham gia bởi General Availability (GA) hoặc ngay sau đó. Và sau đó là các open issues nơi bạn có thể thêm một vấn đề và có lẽ chúng tôi sẽ xem xét sớm hoặc ai đó sẽ gặp lại.

Đây là tất cả các adapter giúp phát triển quy trình làm việc chạy trên bất kỳ loại backend đám mây nào hoặc backend nhóm của riêng bạn. Tất cả chúng đều là mã nguồn mở (open source). Vì vậy, bạn có thể thấy chính xác điều gì đang xảy ra và bạn có thể kết nối nó với backend của riêng mình chỉ bằng cách xem mã đó. Và chúng tôi rất vui được giúp bạn.

Quản lý Phiên bản và Nâng cấp Quy trình làm việc

Về việc quản lý phiên bản (versioning), tôi đã nói một chút về khả năng nâng cấp các lần chạy (runs) qua các phiên bản. Việc quản lý phiên bản sẽ rất đơn giản, chúng tôi có một giao diện đám mây cho tất cả các phiên bản mà bạn đã tạo, đối với hầu hết mọi người sẽ là một lần triển khai (deployment). Nếu bạn triển khai mã của mình đến môi trường tiền sản xuất (pre-development) hoặc sản xuất (production), mỗi lần triển khai sẽ là một phiên bản. Và bạn có thể liệt kê các phiên bản đó bất kỳ lúc nào bằng cách sử dụng workflow API. Và lần chạy sẽ biết nó đang chạy trên phiên bản nào, và bạn có thể gọi run.upgrade để xem liệu nó có tương thích với phiên bản mới hay không, được nhắm mục tiêu đến phiên bản đó.

Mỗi lần triển khai sẽ có URL riêng của nó, không chỉ trong Vercel mà còn trong AWS Lambda chẳng hạn. Mỗi lần triển khai có URL riêng của nó. Vì vậy, các webhook sẽ áp dụng cho các URL riêng của nó, có nghĩa là bạn không cần phải lo lắng về việc quản lý phiên bản ngoại trừ việc gắn thẻ một phiên bản khi bạn triển khai lần đầu. Và sau đó, bất cứ điều gì bạn nghĩ là phiên bản chính của bạn là phiên bản bạn định tuyến thông qua API của bên thứ ba.

Tôi nghĩ, xin lỗi, rõ ràng tôi sẽ sử dụng công việc như một bước tiếp theo cho trải nghiệm công nghệ và những thứ khác. Tôi nghĩ rất nhiều người làm việc trong môi trường biệt lập, nhưng đôi khi điều phù hợp là những thứ đã được nhóm lại. Di chuyển (migrations) hoặc di chuyển agent sang phiên bản mới. Vâng, điều này giống như việc nâng cấp theo nghĩa đó, phải không?

Nhưng nếu bạn có một loạt các lần chạy đều trên một phiên bản nhất định và bạn đã triển khai mã mới, và bạn muốn tất cả các lần chạy đó được nâng cấp lên phiên bản mới hoặc di chuyển, phải không? Trong UI, bạn sẽ có thể chọn bao nhiêu lần chạy bạn muốn hoặc thông qua CLI, tôi muốn có thể lấy danh sách và sau đó nói rằng đối với 20 ID này, tôi muốn nâng cấp lần chạy lên phiên bản này. Nó sẽ thực hiện kiểm tra nội bộ và tôi tiếp tục các quy trình làm việc này từ một điểm nhất định. Giống như liệu tôi có thể di chuyển chúng tại chỗ (in place) vì các signature của bước chồng chéo hay không, hoặc nếu không, nó sẽ cung cấp cho bạn tùy chọn hủy tất cả các lần chạy hiện có và chạy lại chúng trên một phiên bản mới với cùng inputs.

Khả năng Tương thích Mã và Quản lý Phiên bản

Nếu bạn viết code theo cách tương thích, sẽ có các tùy chọn khác nhau cho việc in-place migrations. Làm thế nào bạn có thể phát hiện điều đó chỉ bằng việc các phần của code không bị thay đổi? Bởi vì chúng tôi về cơ bản có một plugin trình biên dịch, chúng tôi có thể đạt được khả năng tương thích AST hoàn toàn và chúng tôi đang lưu AST, các chữ ký đầu vào và đầu ra này, vào một manifest mà chúng tôi tải lên cho các phiên bản. Do đó, đối với mỗi phiên bản, chúng tôi có thể biết các chữ ký cho mỗi bước và cho chính workflow cũng như tất cả những thứ khác đang diễn ra ở giữa.

Ngoài ra, một điểm khác ở đây là chính hàm workflow. Bạn có thể thấy chúng tôi đã chạy lại rất nhiều lần trong quá trình thực thi. Chúng tôi không cần bất kỳ cách nào để thực thi code của bạn. Vì vậy, bạn muốn nâng cấp và liên quan đến việc chạy lại. Nó sẽ phát triển dựa trên đó. Bạn có thể lấy event log của chúng tôi, tạo một phiên bản code mới mà bạn đã xây dựng trên event log so với sự kiện dự kiến. Có rất nhiều biến thể giữa kiểu, tôi thực hiện một bước, tất cả các bước trước đó vẫn giữ nguyên hoặc bước này đã bị thay đổi.

Vì vậy, nếu mọi thứ được thực hiện tự động, cảm giác như, được rồi, tôi có thể xử lý ngay lập tức với tất cả các tác nhân của mình đang hoạt động. Có hai cách bạn có thể quản lý phiên bản, và bạn đang, hãy đặt điều này đúng chỗ, và tôi nghĩ điều thú vị là anh ấy đã xây dựng cho một nền tảng mà bạn giả định rằng code đều giống nhau, ở cùng một nơi. Vì vậy, những gì chúng tôi đã thấy là bạn kết thúc với việc, bạn bắt đầu phiên bản đầu tiên của sản phẩm chủ lực của mình, và sau đó bắt đầu thực hiện cập nhật cho từng phiên bản nhỏ của chúng tôi. Bây giờ code có tất cả những thứ đầy đủ có những điều này. Bạn cũng có thể phải sử dụng một phiên bản đầy đủ hoặc tải trên code thực tế mà bạn đang chạy. Giả định mặc định là code của tôi có thể đang chạy trong một append log, và bạn kết thúc với dark squid, và sau đó bạn phải làm tất cả mọi thứ từ đó, nhưng nó giống như Errol. Vì vậy, tôi vẫn duy trì và duy trì hệ thống.

Kết quả tốt đẹp là gì? Cơ sở mã đã có vô số component từ trước. Có một bước tự nhiên để nói rằng, code hoạt động. Bạn có thể giả định rằng bạn đang đẩy công việc của mình lên từ những gì có trong mọi thứ. Và vì vậy bạn không phải lo lắng về mô hình động lực đó và đó là code quan trọng. Nhưng thay vào đó, đã đến lúc đi đến phần của bạn, và bạn đẩy nó đi, bạn có thể phải sử dụng nó. Tôi có thể sử dụng toàn bộ event log, hoặc bạn có thể trực tiếp chọn chính xác bao nhiêu phần trong đó cần được chạy lại và đó là gì. Có rất nhiều thứ bạn có thể làm trên đầu điều này và xem nó hoạt động như thế nào. Điều tuyệt vời là đó là một US khó khăn và bạn biết đấy, để chúng tôi làm tốt. Hy vọng bạn rất tự hào. Tôi rất muốn có một kết quả gần như vậy. Tôi nghĩ chúng tôi gần hoàn thành.

Khả năng Quan sát (Observability)

Chúng tôi sẽ ở lại để trả lời thêm câu hỏi. Vậy thì, được rồi, tôi nghĩ phần khác là khả năng quan sát. Tôi không thích đặt nó xung quanh chính nó. Tôi không thấy nhiều điều đáng chú ý. Tôi mong đợi rằng, rõ ràng, bạn sẽ xây dựng một cái. Và sau đó tôi cũng muốn nhập nó vào máy tính của mình. Rõ ràng, bạn sẽ không làm điều đó. Còn về dịch vụ khả năng quan sát này thì sao? OpenTelemetry spans sẽ cung cấp cho chúng ta một chút. Chúng tôi sẽ thêm một số ngữ cảnh vào các span theo mặc định, có lẽ. Vì vậy, nếu bạn chuyển các span của mình qua DataDog, nó sẽ có rất nhiều thông tin về các bước và event log. Và bạn cũng có thể theo dõi telemetry của mình, rõ ràng.

Vậy đó là kế hoạch hay bạn có bên thứ nhất? Kế hoạch là chúng tôi sẽ hỗ trợ thêm một số hoặc tất cả các loại ngữ cảnh liên quan đến bước và event log này trước. Chúng tôi có lẽ sẽ xuất helper để thêm thông tin này vào các span. Và sau đó, mọi tự động hóa mà bạn muốn gắn thẻ vào đó là tùy thuộc vào bạn.

Quản lý Bí mật và Môi trường

Tôi có thể đính kèm các secret vào một workflow theo cách mà khi tôi cần cập nhật chúng, tất cả chúng đều, bạn biết đấy...? Vâng, vậy thì, hiện tại, nó có thể kiểm tra tất cả dữ liệu nhúng, đúng không? Và rõ ràng là dành cho bạn với tư cách là người có quyền truy cập vào API, điều mà người tiêu thụ workflow hoặc bắt đầu workflow cho một API thường sẽ không có. Vâng, vì vậy các workflow chạy trong cùng một triển khai như chúng thường làm và có quyền truy cập vào môi trường xử lý. Vì vậy, bạn có thể tương tác với các biến môi trường theo cách bạn thường làm. Và miễn là bạn không ghi nhật ký chúng, điều mà bạn có lẽ sẽ không làm, thì nó giống như một điểm cuối API. Và sau đó, nếu bạn muốn dữ liệu của mình là secret, hiện tại, chúng tôi hiển thị nó trong khả năng truy cập nếu bạn có quyền truy cập, nhưng chúng tôi cũng sẽ cho phép bạn thực hiện mã hóa tại chỗ cho bất kỳ dữ liệu nào.

Kết thúc Phiên

Được rồi, vậy thì chúng tôi sẽ kết thúc phiên, nhưng chúng tôi sẽ ở lại thêm một chút để trả lời câu hỏi nếu bạn muốn xem qua code.

Góp ý / Báo lỗiPhát hiện sai sót hoặc có ý tưởng cải thiện?