Khai mở lớp kiểm soát Codex: cách chúng tôi xây dựng App Server
Bởi Celia Chen, Thành viên Ban Kỹ thuật
Tác nhân lập trình Codex của OpenAI có mặt trên nhiều nền tảng khác nhau: ứng dụng web(mở trong cửa sổ mới), giao diện dòng lệnh (CLI)(mở trong cửa sổ mới), tiện ích mở rộng IDE(mở trong cửa sổ mới) và ứng dụng Codex dành cho macOS mới. Bên dưới, tất cả đều được cung cấp sức mạnh bởi cùng một lớp kiểm soát Codex—vòng lặp tác nhân và logic làm nền tảng cho mọi trải nghiệm Codex. Mối liên hệ quan trọng giữa chúng? Codex App Server(mở trong cửa sổ mới), một API JSON-RPC hai chiều thân thiện với khách hàng 1.
Trong bài đăng này, chúng tôi sẽ giới thiệu Codex App Server; chúng tôi sẽ chia sẻ những kiến thức của chúng tôi cho đến nay về những cách tốt nhất để đưa khả năng của Codex vào sản phẩm của bạn để giúp người dùng của bạn tăng cường quy trình làm việc của họ. Chúng tôi sẽ đề cập đến kiến trúc và giao thức của App Server và cách nó tích hợp với các bề mặt Codex khác nhau, cũng như các mẹo về việc tận dụng Codex, cho dù bạn muốn biến Codex thành trình duyệt mã, tác nhân SRE hay trợ lý mã hóa.
Trước khi đi sâu vào kiến trúc, thật hữu ích khi biết cốt truyện của App Server. Ban đầu, App Server là một cách thiết thực để tái sử dụng lớp kiểm soát Codex trên các sản phẩm dần dần phát triển thành giao thức tiêu chuẩn của chúng tôi.
Codex CLI bắt đầu là một TUI (terminal user interface), nghĩa là Codex được truy cập thông qua thiết bị đầu cuối. Khi chúng tôi xây dựng tiện ích mở rộng VS Code (một cách thân thiện hơn với IDE để tương tác với các tác nhân Codex), chúng tôi cần một cách để sử dụng cùng một lớp kiểm soát nhằm điều khiển cùng một agent loop từ UI của IDE mà không phải triển khai lại nó. Điều đó có nghĩa là hỗ trợ các mẫu tương tác phong phú vượt ra ngoài yêu cầu/phản hồi, chẳng hạn như khám phá không gian làm việc, truyền phát tiến độ khi tác nhân suy luận và phát ra các khác biệt. Ban đầu, chúng tôi đã thử nghiệm việc hiển thị Codex như một máy chủ MCP(mở trong cửa sổ mới), nhưng việc duy trì ngữ nghĩa MCP theo cách phù hợp với VS Code lại tỏ ra khó khăn. Thay vào đó, chúng tôi đã giới thiệu một giao thức JSON-RPC phản chiếu vòng lặp TUI, và nó đã trở thành phiên bản đầu tiên không chính thức(mở trong cửa sổ mới) của App Server. Vào thời điểm đó, chúng tôi không kỳ vọng các máy khách khác sẽ phụ thuộc vào App Server, vì vậy nó không được thiết kế như một API ổn định.
Khi việc sử dụng Codex ngày càng phổ biến trong vài tháng tiếp theo, các nhóm nội bộ và đối tác bên ngoài muốn có khả năng tích hợp cùng một lớp kiểm soát vào sản phẩm của họ để đẩy nhanh quy trình phát triển phần mềm của người dùng. Ví dụ, JetBrains và Xcode muốn có trải nghiệm tác nhân đạt chuẩn IDE, trong khi ứng dụng máy tính để bàn Codex cần điều phối nhiều tác nhân Codex song song. Những yêu cầu đó đã thúc đẩy chúng tôi thiết kế một bề mặt nền tảng mà cả sản phẩm của chúng tôi lẫn các tích hợp của đối tác đều có thể an toàn dựa vào theo thời gian. Nó cần phải dễ tích hợp và tương thích ngược, nghĩa là chúng tôi có thể phát triển giao thức mà không làm hỏng các máy khách hiện có.
Tiếp theo, chúng ta sẽ hướng dẫn cách chúng tôi đã thiết kế kiến trúc và giao thức để các khách hàng khác nhau có thể sử dụng cùng một lớp kiểm soát.
Trước tiên, hãy phóng to để xem những gì nằm bên trong lớp kiểm soát Codex và cách Codex App Server hiển thị nó cho các máy khách. Trong blog Codex cuối cùng của chúng tôi, chúng tôi đã phá vỡ vòng lặp tác nhân cốt lõi điều phối sự tương tác giữa người dùng, mô hình và các công cụ. Đây là logic cốt lõi của lớp kiểm soát Codex, nhưng vẫn còn nhiều điều hơn nữa trong trải nghiệm tác nhân đầy đủ:
1. Vòng đời và tính bền vững của luồng. Một chuỗi là một cuộc trò chuyện Codex giữa một người dùng và một tác nhân. Codex tạo, tiếp tục, tạo nhánh và lưu trữ các luồng, đồng thời lưu giữ lịch sử sự kiện để các ứng dụng khách có thể kết nối lại và hiển thị một dòng thời gian nhất quán.
2. Cấu hình và xác thực. Codex tải cấu hình, quản lý mặc định và chạy các luồng xác thực như “Đăng nhập bằng ChatGPT”, bao gồm cả trạng thái xác thực.
3. Thực thi công cụ và các phần mở rộng. Codex thực thi các công cụ shell/file trong sandbox và kết nối các tích hợp như máy chủ MCP và kỹ năng để họ có thể tham gia vào vòng lặp tác nhân theo mô hình chính sách nhất quán.
Tất cả logic của tác nhân mà chúng tôi đã đề cập ở đây, bao gồm cả vòng lặp tác nhân cốt lõi, nằm trong một phần của mã nguồn Codex CLI được gọi là “Codex core(mở trong cửa sổ mới).” Lõi Codex vừa là một thư viện nơi chứa toàn bộ mã của tác nhân và vừa là một môi trường thực thi có thể được khởi động để chạy vòng lặp tác nhân và quản lý sự duy trì của một luồng Codex (cuộc trò chuyện).
Để hữu ích, lớp kiểm soát Codex cần có thể được khách hàng truy cập. Đó là nơi mà App Server xuất hiện.
App Server vừa là giao thức JSON-RPC giữa máy khách và máy chủ vừa là một quá trình tồn tại lâu dài lưu trữ các luồng lõi của Codex. Như chúng ta có thể thấy từ sơ đồ ở trên, quy trình App Server có bốn thành phần chính: trình đọc stdio, bộ xử lý tin nhắn Codex, trình quản lý luồng và luồng lõi. Trình quản lý luồng quay một phiên lõi cho mỗi luồng và bộ xử lý tin nhắn Codex sau đó giao tiếp trực tiếp với mỗi phiên lõi để gửi yêu cầu của khách hàng và nhận cập nhật.
Một yêu cầu khách hàng có thể dẫn đến nhiều bản cập nhật sự kiện và những sự kiện chi tiết này là những gì cho phép chúng tôi xây dựng một giao diện người dùng phong phú trên đầu App Server. Hơn nữa, trình đọc stdio và bộ xử lý thông điệp Codex đóng vai trò là lớp dịch giữa máy khách và các luồng lõi Codex. Chúng dịch các yêu cầu JSON-RPC của máy khách thành các thao tác cốt lõi của Codex, lắng nghe luồng sự kiện nội bộ của lõi Codex, và sau đó chuyển đổi các sự kiện cấp thấp đó thành một tập hợp nhỏ các thông báo JSON-RPC ổn định, sẵn sàng cho giao diện người dùng.
Giao thức JSON-RPC giữa máy khách và App Server hoàn toàn hai chiều. Một luồng điển hình có một yêu cầu từ máy khách và nhiều thông báo từ máy chủ. Ngoài ra, máy chủ có thể khởi tạo các yêu cầu khi tác nhân cần nhập liệu, chẳng hạn như phê duyệt, và sau đó tạm dừng lượt cho đến khi máy khách phản hồi.
Tiếp theo, chúng ta sẽ phân tích các yếu tố cơ bản của cuộc hội thoại, các khối xây dựng của giao thức App Server. Việc thiết kế API cho vòng lặp tác nhân rất phức tạp vì tương tác giữa người dùng và tác nhân không chỉ đơn thuần là yêu cầu/phản hồi. Một yêu cầu của người dùng có thể mở ra thành một chuỗi hành động có cấu trúc mà khách hàng cần thể hiện một cách trung thực: đầu vào của người dùng, tiến trình gia tăng của tác nhân, các hiện vật được tạo ra trên đường đi (ví dụ: khác biệt). Để giúp luồng tương tác đó dễ tích hợp và có khả năng chống chịu trên nhiều UI, chúng tôi đã thống nhất về ba loại dữ liệu nguyên thủy cốt lõi với các ranh giới và vòng đời rõ ràng:
1. Mục: Một mục là đơn vị cơ bản của đầu vào/đầu ra trong Codex. Các mục được phân loại theo kiểu (ví dụ: tin nhắn người dùng, tin nhắn tác nhân, thực thi công cụ, yêu cầu phê duyệt, khác biệt) và mỗi mục có một vòng đời rõ ràng:
mục/bắt đầukhi mục bắt đầu- các sự kiện tùy chọn
item/*/deltadưới dạng luồng nội dung (dành cho các loại mục truyền phát) mục/hoàn thànhkhi mục hoàn thành với tải trọng đầu cuối
Vòng đời này cho phép khách hàng bắt đầu hiển thị ngay lập tức khi bắt đầu, phát trực tuyến các bản cập nhật gia tăng trên delta và hoàn tất khi hoàn thành.
2. Lượt: Một lượt là một đơn vị công việc của tác nhân được khởi tạo bởi đầu vào của người dùng. Nó bắt đầu khi khách hàng gửi một đầu vào (ví dụ: “chạy kiểm thử và tóm tắt các lỗi”) và kết thúc khi tác nhân hoàn tất việc tạo ra đầu ra cho đầu vào đó. Một lượt bao gồm một chuỗi các mục đại diện cho các bước trung gian và các kết quả đầu ra được tạo ra trong suốt quá trình.
3. Luồng: Luồng là vùng chứa bền vững cho một phiên Codex đang diễn ra giữa người dùng và một tác nhân. Nó chứa nhiều lượt. Các luồng có thể được tạo, tiếp tục, tách nhánh và lưu trữ. Lịch sử luồng được lưu trữ để các ứng dụng khách có thể kết nối lại và hiển thị một dòng thời gian nhất quán.
Bây giờ, chúng ta sẽ xem xét một cuộc trò chuyện đơn giản giữa khách hàng và đại lý, trong đó cuộc trò chuyện được thể hiện bằng các nguyên thủy:
Khi bắt đầu cuộc trò chuyện, máy khách và máy chủ cần thiết lập bắt tay khởi tạo. Máy khách phải gửi một yêu cầu khởi tạo duy nhất trước bất kỳ phương thức nào khác và máy chủ xác nhận với một phản hồi. Điều này cho máy chủ cơ hội công bố các khả năng và cho phép cả hai bên thống nhất về quản lý phiên bản giao thức, các cờ tính năng và các giá trị mặc định trước khi công việc thực sự bắt đầu. Dưới đây là một payload ví dụ từ tiện ích mở rộng VS Code của OpenAI:
Đây là những gì máy chủ trả về:
Khi một máy khách tạo một yêu cầu mới, trước tiên nó sẽ tạo một luồng rồi đến một lượt. Máy chủ sẽ gửi lại thông báo về tiến trình (thread/started và turn/started). Nó cũng sẽ gửi lại các đầu vào mà nó ghi nhận là các mục, như tin nhắn của người dùng ở đây.
Các lệnh gọi công cụ cũng được gửi lại cho máy khách dưới dạng các mục. Ngoài ra, máy chủ yêu cầu máy khách phê duyệt trước khi có thể chạy một hành động bằng cách gửi một yêu cầu máy chủ. Việc phê duyệt sẽ tạm dừng lượt cho đến khi khách hàng trả lời bằng “cho phép” hoặc “từ chối”. Đây là quy trình phê duyệt trông như thế nào trong phần mở rộng VS Code:

Cuối cùng, máy chủ gửi một thông điệp của tác nhân và sau đó kết thúc lượt với turn/completed. Luồng sự kiện delta của tin nhắn từ tác nhân sẽ truyền từng phần của tin nhắn trở lại cho đến khi tin nhắn được hoàn tất với item/completed.
Các thông điệp trong sơ đồ được đơn giản hóa để dễ đọc. Nếu bạn muốn xem JSON trong một lượt đầy đủ, bạn có thể chạy trình khách thử nghiệm từ repo Codex CLI:
Bây giờ, hãy xem các bề mặt máy khách khác nhau nhúng Codex thông qua App Server như thế nào. Chúng tôi sẽ đề cập đến ba mẫu: ứng dụng và IDE cục bộ, thời gian chạy web Codex và TUI.
Trên cả ba, việc vận chuyển là JSON-RPC qua stdio (JSONL). JSON-RPC giúp bạn dễ dàng xây dựng các ràng buộc phía máy khách bằng ngôn ngữ mà bạn chọn. Các giao diện Codex và các tích hợp đối tác đã triển khai các máy khách App Server bằng các ngôn ngữ bao gồm Go, Python, TypeScript, Swift và Kotlin. Đối với TypeScript, bạn có thể tạo các định nghĩa trực tiếp từ giao thức Rust bằng cách chạy:
Đối với các ngôn ngữ khác, bạn có thể tạo gói JSON Schema và đưa nó vào trình tạo mã ưa thích của bạn bằng cách chạy:

Các máy khách cục bộ thường gói hoặc tìm nạp một nhị phân App Server dành riêng cho nền tảng, khởi chạy nó dưới dạng quy trình con chạy lâu dài và giữ kênh stdio hai chiều mở cho JSON-RPC. Ví dụ, trong phần mở rộng VS Code và Ứng dụng Máy tính để bàn của chúng tôi, tạo tác được gửi bao gồm nhị phân Codex dành riêng cho nền tảng và được ghim vào phiên bản đã thử nghiệm để máy khách luôn chạy các bit chính xác mà chúng tôi đã xác thực.
Không phải mọi tích hợp đều có thể phát hành các bản cập nhật phía máy khách thường xuyên. Một số đối tác như Xcode tách các chu kỳ phát hành bằng cách giữ cho máy khách ổn định và cho phép nó trỏ đến một nhị phân App Server mới hơn khi cần thiết. Bằng cách đó, họ có thể áp dụng các cải tiến phía máy chủ (ví dụ: khả năng tự động nén tốt hơn trong nhân Codex hoặc các khóa cấu hình mới được hỗ trợ) và triển khai các bản vá lỗi mà không cần chờ bản phát hành dành cho máy khách. Bề mặt JSON-RPC của App Server được thiết kế để tương thích ngược, vì vậy các máy khách cũ có thể giao tiếp an toàn với các máy chủ mới hơn.

Codex Web sử dụng lớp kiểm soát Codex, nhưng chạy nó trong môi trường container. Một công nhân cung cấp một vùng chứa với không gian làm việc đã thanh toán, khởi chạy nhị phân App Server bên trong nó và duy trì một JSON-RPC tồn tại lâu trên kênh stdio 2. Ứng dụng web (chạy trong tab trình duyệt của người dùng) nói chuyện với phụ trợ Codex qua HTTP và SSE, truyền các sự kiện tác vụ do công nhân tạo ra. Điều này giữ cho giao diện người dùng phía trình duyệt nhẹ nhàng trong khi vẫn mang lại cho chúng tôi thời gian chạy nhất quán trên máy tính để bàn và web.
Vì các phiên duyệt web chỉ diễn ra trong thời gian ngắn (các tab đóng lại, mạng bị ngắt kết nối), ứng dụng web không thể là nguồn thông tin đáng tin cậy cho các tác vụ kéo dài. Việc giữ trạng thái và tiến độ trên máy chủ có nghĩa là công việc vẫn tiếp tục ngay cả khi tab biến mất. Giao thức truyền phát và các phiên luồng đã lưu giúp một phiên mới dễ dàng kết nối lại, tiếp tục từ chỗ đã dừng lại và bắt kịp mà không cần xây dựng lại trạng thái trong máy khách.

Trong lịch sử, TUI là một máy khách “gốc” chạy trong cùng một quy trình với vòng lặp đại lý và nói chuyện trực tiếp với các loại lõi Rust thay vì giao thức máy chủ ứng dụng. Điều đó làm cho quá trình lặp lại sớm trở nên nhanh chóng, nhưng nó cũng khiến TUI trở thành một bề mặt trường hợp đặc biệt.
Bây giờ App Server đã tồn tại, chúng tôi có kế hoạch tái cấu trúc TUI(mở trong cửa sổ mới) để sử dụng nó để nó hoạt động giống như bất kỳ ứng dụng khách nào khác: khởi chạy quy trình con của App Server, nói JSON-RPC qua stdio và hiển thị các sự kiện phát trực tuyến và phê duyệt tương tự. Điều này mở khóa quy trình công việc nơi TUI có thể kết nối với máy chủ Codex chạy trên máy tính từ xa, giữ cho đại lý gần gũi với tính toán và tiếp tục công việc ngay cả khi máy tính xách tay ngủ hoặc ngắt kết nối, trong khi vẫn cung cấp các bản cập nhật và kiểm soát trực tiếp tại địa phương.
Codex App Server sẽ là phương pháp tích hợp hàng đầu mà chúng tôi duy trì trong tương lai, nhưng cũng có những phương pháp khác với chức năng hạn chế hơn. Theo mặc định, chúng tôi khuyến nghị khách hàng sử dụng Codex App Server để tích hợp với Codex, nhưng cũng đáng để xem xét các phương pháp tích hợp khác nhau và hiểu rõ ưu và nhược điểm của chúng. Dưới đây là những cách phổ biến nhất để lái Codex và khi nào mỗi cách có thể phù hợp.
Chạy codex mcp-server(mở trong cửa sổ mới) và kết nối từ bất kỳ máy khách MCP nào hỗ trợ máy chủ stdio (ví dụ: OpenAI Agents SDK(mở trong cửa sổ mới)). Đây là lựa chọn phù hợp nếu bạn đã có quy trình làm việc dựa trên MCP và muốn gọi Codex như một công cụ có thể gọi được. Nhược điểm là bạn chỉ nhận được những gì MCP cung cấp, vì vậy các tương tác dành riêng cho Codex dựa trên ngữ nghĩa phiên làm việc phong phú hơn (ví dụ: cập nhật diff) có thể không ánh xạ gọn gàng qua các điểm cuối MCP.
Một số hệ sinh thái cung cấp một giao diện di động có thể nhắm đến nhiều nhà cung cấp mô hình và môi trường chạy. Điều này có thể phù hợp với bạn nếu bạn muốn một lớp trừu tượng điều phối nhiều tác nhân. Sự đánh đổi là các giao thức này thường hội tụ về tập con năng lực chung, điều này có thể khiến các tương tác phong phú hơn khó được biểu đạt, đặc biệt là khi ngữ nghĩa công cụ và phiên theo từng nhà cung cấp là quan trọng. Lĩnh vực này đang phát triển nhanh chóng, và chúng tôi kỳ vọng rằng các tiêu chuẩn chung hơn sẽ xuất hiện khi chúng ta tìm ra những yếu tố cơ bản tốt nhất để thể hiện quy trình làm việc thực tế của các tác nhân (kỹ năng(mở trong cửa sổ mới) là một ví dụ điển hình).
Chọn App Server khi bạn muốn toàn bộ lớp kiểm soát Codex được hiển thị dưới dạng một luồng sự kiện ổn định, thân thiện với UI. Bạn nhận được cả đầy đủ chức năng của vòng lặp tác nhân và các tính năng hỗ trợ khác như Đăng nhập bằng ChatGPT, khám phá mô hình và quản lý cấu hình. Chi phí chính là công việc tích hợp, vì bạn cần xây dựng ràng buộc JSON-RPC phía máy khách bằng ngôn ngữ của bạn. Tuy nhiên, trên thực tế, Codex có thể đảm nhiệm phần lớn công việc phức tạp nếu bạn cung cấp cho nó lược đồ JSON và tài liệu. Nhiều nhóm mà chúng tôi đã làm việc cùng đã có thể nhanh chóng tạo ra một tích hợp hoạt động bằng Codex.
Chế độ CLI nhẹ, có thể viết kịch bản cho các tác vụ một lần và chạy CI. Nó phù hợp với tự động hóa và đường ống, nơi bạn muốn một lệnh duy nhất chạy đến hoàn thành không tương tác, phát trực tuyến đầu ra có cấu trúc cho nhật ký và thoát với tín hiệu thành công hoặc thất bại rõ ràng.
Một thư viện TypeScript để điều khiển các tác nhân Codex cục bộ bằng lập trình từ bên trong ứng dụng của bạn. Tốt nhất khi bạn muốn một giao diện thư viện gốc cho các công cụ và quy trình làm việc phía máy chủ mà không cần xây dựng một máy khách JSON-RPC riêng. Vì được phát hành sớm hơn App Server, hiện tại nó hỗ trợ ít ngôn ngữ hơn và phạm vi tính năng nhỏ hơn. Nếu có sự quan tâm từ phía nhà phát triển, chúng tôi có thể bổ sung thêm các SDK bọc giao thức App Server để các nhóm có thể bao phủ nhiều hơn bề mặt của lớp kiểm soát mà không cần viết các ràng buộc JSON-RPC.
Trong bài viết này, chúng tôi đã chia sẻ cách chúng tôi tiếp cận việc thiết kế một tiêu chuẩn mới để tương tác với các tác nhân và cách biến lớp kiểm soát Codex thành một giao thức ổn định, thân thiện với khách hàng. Chúng tôi đã đề cập đến cách App Server hiển thị lõi Codex, cho phép khách hàng điều khiển vòng lặp đại lý đầy đủ và cung cấp năng lượng cho một loạt các bề mặt bao gồm TUI, tích hợp IDE cục bộ và thời gian chạy web.
Nếu điều này gợi ra ý tưởng để tích hợp Codex vào quy trình làm việc của riêng bạn, bạn nên thử App Server. Toàn bộ mã nguồn nằm trong kho mã(mở trong cửa sổ mới) nguồn mở Codex CLI. Hãy thoải mái chia sẻ phản hồi và yêu cầu tính năng của bạn. Chúng tôi rất mong chờ được nghe từ bạn và sẽ tiếp tục giúp các tác nhân dễ tiếp cận hơn với mọi người.
Tác giả
Lời cảm ơn
Đặc biệt cảm ơn Michael Bolin, Owen Lin, Eric Traut và Rasmus Rygaard, những người đã đóng góp cho bài đăng này và toàn bộ nhóm Codex đã làm việc trên App Server.
Ghi chú cuối trang
- 1
Chúng tôi sử dụng một biến thể “JSON‑RPC lite”: nó giữ nguyên cấu trúc yêu cầu/phản hồi/thông báo, nhưng lược bỏ
"jsonrpc": "2.0"tiêu đề và được đóng khung là JSONL qua stdio thay vì JSON-RPC 2.0 nghiêm ngặt. - 2
“stdio” đề cập đến stdin/stdout của app-server bên trong container. Trong các thiết lập được lưu trữ, các luồng đó thường được đường hầm qua kết nối mạng liên tục (ví dụ như WebSocket-like) đến thời gian chạy vùng chứa — vì vậy nó hoạt động giống như stdio ngay cả khi nó không phải là một đường ống cục bộ theo nghĩa đen.


