Homus
‹ All talks

What if the harness mattered more than the model?

AI Engineer World's Fair 2026: Online Track · Video gốc

Cùng model, cùng task, chỉ nâng harness qua bảy nấc bằng ngôn ngữ Agency: tool, handler, PFA, feedback loop, subagent và self-optimization với GEPA.

AgentsCoding AgentsSecurity

1. Nếu harness quan trọng hơn model thì sao?

Diễn giả mở đầu bằng tên mình: anh là Adit, đọc giống chữ "audit" trong "tax audit". Chủ đề anh mang tới là câu hỏi ở tiêu đề: nếu harness quan trọng hơn model thì sao?

Slide tiêu đề What if the harness mattered more than the model? By Aditya Bhargava
Slide tiêu đề, trình bày ngay trong một cửa sổ terminal: "What if the harness mattered more than the model?", by Aditya Bhargava. Cả talk là slide dạng terminal xen với demo chạy thật.

Vài dòng về bản thân. Anh là staff engineer tại Etsy, đồng thời là IC initiative lead của Etsy cho mảng agentic commerce. Anh là tác giả cuốn Grokking Algorithms, một cuốn sách minh hoạ bằng hình về thuật toán, và anh cũng viết các bài minh hoạ trên ducktyped.org.

Điều anh muốn bàn: nếu harness quan trọng hơn model, thì có lẽ chúng ta nên đầu tư nhiều hơn vào việc xây dựng chuyên môn về harness. Và đây là controversial take đầu tiên của anh. Anh nghe rất nhiều người nói: "Model bây giờ giỏi tới mức bạn cứ giữ harness đơn giản thôi. Đưa cho model vài tool là nó tự lo phần còn lại." Câu này được nhắc nhiều tới mức nó đã bắt đầu trở thành "chân lý" của ngành tech.

Câu trả lời của anh: đúng, nhưng như vậy là đang đi sai hướng, vì nó khiến chúng ta lệ thuộc vào những model proprietary đắt tiền, thứ không thể chạy local. Vậy nếu ta nói về hướng ngược lại thì sao? Nếu ta tập trung vào những model open-source chạy được trên máy mình? Nếu ta tập trung build một harness tốt tới mức đạt được hiệu năng của một model cutting-edge, nhưng bằng một model open-source chạy local?

Slide Controversial take về việc giữ harness đơn giản
"Controversial take!": trích câu quen thuộc "The models are so good, that you can keep the harness simple. Just give the model a few tools and it'll do the rest." Bên dưới: đúng, nhưng điều này khiến ta lệ thuộc vào model proprietary đắt tiền; nếu ta tập trung vào model open-source chạy được local thì sao? Câu in nghiêng cuối: liệu ta có build được một harness tốt tới mức đạt hiệu năng của một model cutting-edge thông qua một model open-source chạy local?

Vậy nên câu hỏi trung tâm là: nếu harness quan trọng hơn model, và trọng tâm của chúng ta nên đặt vào harness thì sao?

2. HarnessBench: chỉ đổi harness, điểm chênh hơn 20

Harness quan trọng tới mức nào? Đây là chủ đề anh nghiên cứu rất nhiều trong thời gian rảnh. Có một paper rất thú vị nói về Harness-Bench, một benchmark dành cho harness, thứ mà tới giờ ngành chưa có nhiều.

Benchmark này có 106 task. Nó kiểm tra các model khác nhau và các harness khác nhau. Nhưng điểm mấu chốt, theo cách anh trình bày, là nó chạy cùng một setup, cùng một cách đánh giá, cùng một model, và chỉ thử các harness khác nhau.

Kết quả khá thú vị. Điểm số dao động từ 52,4% tới 76,2%, tức là chênh nhau hơn hai mươi điểm, trong khi thứ duy nhất thay đổi là harness. Và điều thú vị thật sự là: với những model yếu hơn, harness càng quan trọng hơn.

Cùng 106 task, cùng cách đánh giá, chỉ đổi harness 52,4% harness kém nhất 76,2% harness tốt nhất hơn 20 điểm
Con số anh dẫn từ Harness-Bench: chỉ thay harness, điểm đi từ 52,4% lên 76,2%. Theo abstract của paper, benchmark đánh giá các cấu hình harness trên nhiều model backend với cùng task environment, budget và evaluation protocol.

3. Tin tốt cho những ai không train model

Nếu harness quan trọng hơn model, thì đó là tin tuyệt vời. Vì nếu model quan trọng hơn, chúng ta phụ thuộc vào một nhúm công ty có đủ khả năng build và train những model này. Còn nếu một harness tốt có thể bù lại, có thể khiến một model yếu hơn làm việc tốt hơn, thì chúng ta tự build harness của mình được. Đó là việc bất kỳ ai trong chúng ta cũng làm được, và chúng ta không phải phụ thuộc vào model trả phí.

Slide If the harness matters more than the model, that's great news
"If the harness matters more than the model, that's great news": nếu model quan trọng hơn, ta phụ thuộc vào một nhúm công ty có thể build model; nhưng nếu một harness tốt giúp một model yếu hơn chạy tốt ngang một model proprietary bleeding-edge, thì ta tự build harness của mình và không phải phụ thuộc vào model trả phí.

Vì vậy anh đã dành rất nhiều thời gian nghiên cứu xem cụ thể cần những gì để build một harness thật sự tốt. Và từ rất sớm anh nhận ra rằng không công cụ hay framework nào hiện có làm được điều anh muốn. Thứ thật sự cần là một giải pháp ở tầng ngôn ngữ (language-level).

4. Harness cần hỗ trợ ở tầng ngôn ngữ: Agency

Đây là controversial take thứ hai của talk: anh nghĩ để build một harness tốt thì thật ra cần sự hỗ trợ ở tầng ngôn ngữ. Nghiên cứu của anh trong sáu tháng qua đi theo hướng đó, và anh đã dành phần lớn sáu tháng ấy để build một ngôn ngữ mới tên là Agency, một ngôn ngữ để build agent.

Trước khi đi tiếp, anh nói nhanh về thuật ngữ, vì hai chữ agent và harness trong ngành vẫn chưa rõ ràng, chưa được định nghĩa chặt. Trong talk này anh sẽ dùng chúng gần như thay thế cho nhau. Nhưng khi anh nói "agent", ý anh là harness cộng với model. Lấy Claude Code làm ví dụ: Claude Code là một agent. Nó dùng Opus, đó là model, còn mọi thứ khác là harness. Khi nói về Agency thì nó là thứ để build agent, nhưng cái nó thật sự cung cấp là harness.

Agent vd: Claude Code = Model vd: Opus + Harness mọi thứ còn lại phần Agency cung cấp
Định nghĩa dùng trong talk: agent là model cộng harness. Với Claude Code, Opus là model, mọi thứ còn lại là harness.

Agency rất tốt, anh nói, nhưng nó vẫn còn mới. Build một ngôn ngữ là rất nhiều việc, và nó mới được sáu tháng. Anh rất thích câu của Alan Kay: "Simple things should be simple. Complex things should be possible." Việc đơn giản thì phải đơn giản, việc phức tạp thì phải làm được. Đó là điều anh thích ở Agency. Khi người ta build agent, có rất nhiều primitive, rất nhiều thứ mà agent nào cũng cần làm được, và những thứ đó phải đơn giản. Đồng thời có rất nhiều việc phức tạp chúng ta muốn làm với agent, và lẽ ra phải làm được chúng trong framework mình chọn. Với Agency thì làm được.

Vậy là giờ ta có một mục tiêu rõ ràng: cố build harness tốt nhất có thể. Và ta có một công cụ tốt để làm việc đó: Agency.

5. Lộ trình của talk và đoạn code cần sửa

Phần còn lại của talk là build một coding agent bằng Agency. Khán giả sẽ thấy cùng một agent tiến hoá qua bảy ví dụ. Cùng một model, cùng một task, nhưng harness được cải thiện sau mỗi lần, và ta sẽ thấy harness nâng hiệu năng của agent lên ở mỗi bước.

Như đã nói, anh nghiên cứu chuyện này rất nhiều. Mục tiêu của talk có ba phần:

  • Những điều cơ bản để build một harness. Khi nói build một harness tốt thì nghĩa là gì? Nếu bạn bắt đầu từ con số không, phần cơ bản là những gì?
  • Agent safety, khá nhiều. Khi build agent, điều ta thật sự muốn là chúng hành động thay mình. Nhưng vấn đề lớn là: làm sao trao cho agent đủ capability để hành động, mà không trao quá nhiều tới mức nó làm điều không an toàn? Khi bàn về chất lượng và capability của agent, safety luôn đi kèm.
  • Phần nâng cao ở cuối: subagent và self-optimization. Theo anh, đó là chỗ mọi thứ bắt đầu thú vị hơn, chỗ ta bàn về mọi khả năng, vì khi nói tới build một harness tốt thì có quá nhiều thứ để khám phá. Anh mong khán giả theo tới cuối vì đó là phần hay nhất.

Đây là đoạn code mà coding agent sẽ được yêu cầu sửa. Nó tính median của một danh sách số đã sắp xếp. Nếu danh sách có độ dài lẻ, chỉ cần lấy phần tử ở giữa. Nếu độ dài chẵn, phải lấy hai phần tử ở giữa rồi tính trung bình của chúng. Nhưng hiện tại function này không làm vậy, tức là có một bug. Có một test cho thấy lỗi đó, và ta sẽ bảo agent sửa đoạn code này.

Slide The code to edit: function median có bug với danh sách độ dài chẵn
"The code to edit": một bug duy nhất trong demo/median.py. Function sắp xếp danh sách, lấy middle = len(ordered) // 2 rồi trả về ordered[middle], với chú thích "wrong for even-length lists!". File demo/test_median.py fail với AssertionError: median() returned 3, expected 2.5. Dòng cuối: "Same model, same task for every example. Only the harness changes."
def median(numbers):
    ordered = sorted(numbers)
    middle = len(ordered) // 2
    return ordered[middle]   # wrong for even-length lists!

Vậy bắt đầu thôi. Đây là ví dụ đầu tiên, và đây đã là code Agency. Bạn sẽ thấy Agency trông rất giống TypeScript: nó lấy cảm hứng nặng từ TypeScript, có thêm một chút cú pháp Python.

6. Bước 0: chỉ có model

Entry point là node main. Bên trong có một prompt đơn giản: function Python median trong demo/median.py có bug, hãy sửa bug đó. Anh chỉ việc truyền prompt đó vào function llm, nhận kết quả và in kết quả ra.

Slide 01 Just the model với node main gọi llm(prompt)
"01 - Just the model": node main() khai báo prompt, gọi llm(prompt) rồi print(result). Ghi chú bên dưới: nó không đọc hay ghi được file. Lệnh chạy: npx agency examples/01-llm.agency.
node main() {
  const prompt = """
  The Python function median(numbers) in demo/median.py has a bug. Please fix the bug.
  """
  const result = llm(prompt)
  print(result)
}

Tất nhiên cách này sẽ không chạy được, vì model không đọc hay ghi được file đó. Anh chạy thử. Đúng như dự đoán, model trả lời đại ý: "Để giúp bạn sửa bug, tôi cần xem đoạn code hiện có." Đây chỉ là một model với rất ít harness, và dĩ nhiên nó không làm được gì.

Cải tiến hiển nhiên nhất cho bất kỳ harness nào là: đưa cho nó vài tool.

7. Tool trong Agency: mọi function đều là tool

Anh nói nhanh về cách tool hoạt động trong Agency, vì nó rất đơn giản. Anh định nghĩa một function, ở đây chỉ để làm ví dụ, là function greet chào một người dùng. Sau đó anh gọi LLM với câu "Use your greet tool to greet Adit" và truyền tool đó vào.

Slide Intro to tools in Agency với function greet
"Intro to tools in Agency": function greet(name: string): string có docstring mô tả nó chào người dùng và dùng để minh hoạ cách tạo, dùng custom tool trong agent; nó trả về "Howdy, ${name}!". node main() gọi llm với tools: [greet]. Dòng cuối: "Every function is a tool in Agency."
export def greet(name: string): string {
  """
  Greet the user with a message. This tool is used to demonstrate how to create and use custom tools in an agent.
  """
  return "Howdy, ${name}!"
}

node main() {
  const result = llm("Use your `greet` tool to greet Adit", {
    tools: [greet]
  })
  print(result)
}

Trong Agency, mọi function đều tự động dùng được như một tool, không phải làm gì thêm. Agency tạo một JSON Schema từ function này và gửi nó kèm lời gọi LLM. Docstring sẽ được dùng làm mô tả của tool.

Anh chạy ví dụ thứ hai. Gõ npx agency... rồi tự sửa: "Oops", thật ra là npx agency example, và là ví dụ 01b vì phần tool được nói trước. Kết quả: "Howdy, Adit".

Nhưng làm sao biết nó thật sự đã chạy tool đó, chứ không phải chỉ tự sinh ra một câu chào trông giống thế? Anh cho xem: Agency ghi log, và có sẵn một log viewer rất tốt. Mở lần chạy gần nhất ra, có thể thấy model gọi tool greet với các tham số tương ứng, tool trả về "Howdy, Adit", và assistant chỉ việc chuyển nguyên câu đó lại cho ta. Đó là tool.

8. Bước 1: tool, nhưng theo cách unsafe

Giờ tới phần dùng tool trong agent. Đây là bước tiếp theo của agent: đưa cho nó tool. Ví dụ này đưa cho agent hai tool read và write. Một lần nữa, read và write chỉ là những function có sẵn trong Agency, và vì function nào cũng dùng được như tool, anh truyền thẳng chúng vào LLM.

Slide 02 Tools, the unsafe way với tools read và write
"02 - Tools, the unsafe way": cùng prompt, nhưng llm(prompt, { tools: [read, write] }). Ba gạch đầu dòng: cho agent quyền đọc và ghi file là unsafe; tính năng human-in-the-loop của Agency sẽ đòi người duyệt; ta không cung cấp cách duyệt ở đâu cả, nên code này sẽ crash.

Có điều, cho agent quyền đọc và ghi file tuỳ ý trên file system của mình là rất không an toàn. Nên mặc định, Agency sẽ không cho làm vậy. Agency có một tính năng human-in-the-loop đòi phải có một kiểu phê duyệt nào đó. Ở đây ta không cung cấp phê duyệt ở đâu cả, nên đoạn code sẽ crash và in ra lỗi.

Anh chạy để khán giả thấy lỗi trông thế nào. Interrupt std::read không được xử lý. Đây là thông điệp của interrupt: "Are you sure you want to read this file?" Có thể thấy tên file mà nó đang muốn đọc. Về cơ bản, Agency đang báo rằng ta chưa phê duyệt interrupt này, và chỉ tới một guide hướng dẫn cách dùng handler.

Terminal báo Interrupt std::read was not handled
Kết quả chạy: Interrupt "std::read" was not handled, kèm câu hỏi "Are you sure you want to read this file?" và tham số với "filename":"demo/median.py". Agency yêu cầu bọc các interrupt trong một handler và chỉ tới guide handlers.

9. Bước 2: handler, an toàn nhưng chậm

Tóm lại tới giờ: ta bắt đầu chỉ với model, rồi thử thêm tool. Bước kế tiếp là làm cho tool an toàn. Anh làm đúng điều thông báo lỗi bảo: dùng một handler.

Đây vẫn là đoạn code cũ, vẫn truyền read và write vào làm tool, nhưng giờ nó được bọc trong một khối handle, và có một handler function ở bên dưới. Khi các tool đó được gọi và raise một interrupt, đoạn code này sẽ chạy. Nó in thông tin về interrupt, hỏi người dùng bằng function input có sẵn, và nếu người dùng đồng ý thì lời gọi tool được approve.

Slide 03 Handlers: khối handle với handler hỏi Approve y/n
"03 - Handlers": khối handle { ... } with (data) { ... }. Handler in "Tool wants to run:" và data.message, hỏi input("Approve? (y/n) "), nếu trả lời "y" thì approve(), ngược lại reject(). Ghi chú: hỏi người dùng; cách này chạy được, an toàn, nhưng cũng rất chậm.
handle {
  const result = llm(prompt, {
    tools: [read, write]
  })
} with (data) {
  print("Tool wants to run:")
  print(data.message)
  const approval = input("Approve? (y/n) ")
  if (approval.toLowerCase() === "y") {
    return approve()
  }
  return reject()
}

Anh thừa nhận mình cứ nói "interrupt" mà chưa định nghĩa, và sẽ quay lại sau. Về cơ bản, interrupt là một cách để tạm dừng thực thi tại một điểm nào đó và hỏi ý kiến con người. Interrupt là một tính năng rất hay của Agency. Mọi function trong standard library của Agency có thay đổi code, thay đổi thứ gì đó, có hành động mang tính phá huỷ, hoặc đọc dữ liệu nhạy cảm đều sẽ throw một interrupt trước.

Vậy đây là phiên bản an toàn của agent: các tool mặc định raise interrupt, và giờ code sẽ hỏi người dùng "Do you approve?". Anh chạy ví dụ. "Are you sure you want to read this file?" Anh trả lời yes. Có thể thấy nó đang đọc. Giờ nó đang muốn ghi vào file đó. Đó là một ví dụ về việc làm agent an toàn hơn bằng cách hỏi người dùng.

Cách này tốt hơn, và nó an toàn, nhưng nó cũng rất chậm.

10. Bước 3: partial function application, an toàn mà không cần người duyệt

Việc tiếp theo là làm cho agent tự chủ (autonomous) mà vẫn an toàn, và đó là phần khó. Làm sao trao cho nó vừa đủ capability để bạn không phải tự tay duyệt từng hành động, mà không trao nhiều tới mức nó có thể làm điều gì đó phá huỷ trên file system của bạn?

Agency có một tính năng rất hay cho việc này, gọi là partial function application (PFA). Đó là khái niệm mượn từ functional programming, một thuật ngữ nghe rất kêu cho một ý tưởng khá đơn giản.

Đây là signature của tool read: nó nhận một tên file và một thư mục. Khi đọc file, nó tìm file có tên đó bên trong thư mục đó. Với partial function application, ta lấy function read, gọi .partial trên nó và đưa vào một thư mục. Việc ta đang làm là khoá tham số dir vào demo.

Slide 04 Partial function application với read.partial và write.partial
"04 - Partial function application (PFA)": tools là [read.partial(dir: "demo"), write.partial(dir: "demo")], khối handle kết thúc bằng with approve. Signature của tool read: read(filename: string, dir: string): Result. Ghi chú: ta khoá tham số dir vào "demo", nên agent chỉ đọc được file trong thư mục đó; không cần người duyệt, nhưng vẫn an toàn.
handle {
  const result = llm(
    prompt,
    {
      tools: [read.partial(dir: "demo"), write.partial(dir: "demo")]
    },
  )
} with approve

// Signature of the read tool
read(filename: string, dir: string): Result

LLM sẽ không thể thay đổi tham số đó. Nó thậm chí không biết tham số đó tồn tại. Khi ta truyền tool read vào, nó chỉ thấy một tham số duy nhất là tên file. Nó truyền tên file vào, và tool sẽ đọc file đó từ thư mục đã định. Ta đã khoá tham số thư mục, nên giờ agent chỉ đọc được file từ thư mục này và ghi file vào thư mục này.

Partial function application là một cách rất tốt để giới hạn capability của agent. Giờ không cần người duyệt nữa, mà vẫn an toàn.

Anh cho chạy thử. Lại npx agency examples, và PFA là partial function application. Agent đang suy nghĩ, và có thể thấy nó đã đọc file mà không cần xin phép. Rồi nó nói, đại ý để sửa vấn đề này thì đây là đoạn code mới, nhưng nó không cập nhật code. Nó hỏi: "Would you like me to update the file with this corrected function?" Nó không tự làm việc đó.

Phiên bản agent này là phiên bản tốt nhất tới giờ, vì nó đưa ra lời giải đúng mà không cần người duyệt, nhưng nó chưa thật sự sửa code. Bước tiếp theo là khiến nó sửa code thật. Và đó là chỗ feedback loop xuất hiện.

11. Bước 4: feedback loop theo kiểu ReAct

Có một agent pattern rất phổ biến tên là ReAct, viết tắt của reason and act. Về cơ bản, bạn yêu cầu agent làm việc theo một vòng lặp: reason (suy luận), act (hành động), observe (quan sát hệ quả của hành động), rồi quyết định làm gì tiếp.

Trong trường hợp này: reason, đọc hai file; act, chạy test; observe xem test có fail không, đọc lỗi; rồi reason tiếp, tức là nhìn vào lỗi test và nghĩ xem muốn làm gì tiếp theo. Cứ lặp như vậy cho tới khi test pass. Đây là một pattern then chốt để làm agent tốt hơn.

Slide 05 The feedback loop với system message bốn bước
"05 - The feedback loop": system message liệt kê các bước cho coding agent. Hai gạch đầu dòng: test-driven development; agent suy nghĩ, hành động, quan sát hệ quả rồi quyết định làm gì tiếp. Dòng cuối: Reason, Act, Observe, Reason.
const sysMessage = """
  You are a coding agent fixing a Python project. Steps:
  (1) read median.py and test_median.py;
  (2) run the tests with the exec tool using command 'python'
      and args ['test_median.py'];
  (3) if the tests fail, read the error, fix median.py with the write tool, then run the tests again;
  (4) repeat until the tests pass.

  Always finish by running the tests one final time to confirm they pass.
"""
Reason đọc 2 file, nghĩ Act sửa file, chạy test Observe test fail? đọc lỗi còn fail thì lặp lại; pass thì chạy test lần cuối để xác nhận ReAct: reason and act
Vòng lặp ReAct áp vào bài median: đọc, chạy test, xem lỗi, sửa, chạy lại cho tới khi pass.

Giờ ta xem lại cùng agent đó. Thứ duy nhất thay đổi là prompt, và agent được quyền chạy test. Lần này agent sẽ làm tốt hơn. Anh cũng cho in ra mọi tool call để khán giả thấy chuyện gì đang xảy ra.

Lúc chạy thì có trục trặc. "Well, shoot. Maybe..." anh bật cười, "All right. Hang on." Và một chút loay hoay của demo trực tiếp, rồi "There we go. Okay." Giờ thì xem nó chạy.

Terminal: agent chạy test fail, ghi median.py, chạy lại test và pass
Log tool call của lần chạy feedback loop: lần exec đầu tiên chạy python test_median.py và fail với median() returned 3, expected 2.5; agent gọi write ghi lại median.py để lấy trung bình hai phần tử giữa khi độ dài chẵn; hai lần exec sau đều ra "All tests passed". Agent kết luận bug đã được sửa và test cuối xác nhận mọi test pass.

Có thể thấy nó đang gọi tool. Nó đọc hai file, đúng như ta nói. Nó chạy test. Test fail. Nó ghi vào file. Nó chạy test lần nữa và xác nhận thành công.

Đây là một giai đoạn rất quan trọng trong việc phát triển harness, vì giờ ta cuối cùng đã có một agent tự tìm ra task, kiểm tra rằng code đang fail, sửa code, rồi kiểm tra rằng code giờ đã pass.

12. Nhìn lại năm bước đầu

Anh tóm tắt cách harness đã được cải thiện tới đây:

  • Bắt đầu chỉ với model: không làm được gì.
  • Thêm tool: nhưng agent không an toàn.
  • Thêm handler: có safety, nhưng cần con người trả lời.
  • Thêm partial function application: an toàn mà không cần con người trả lời.
  • Cuối cùng, bước vừa xem là feedback loop, thêm phần reasoning. Agent tự thực hiện thay đổi và xác nhận thay đổi đó chạy đúng.
chỉ modelkhông làm gì toolsunsafe handlerssafe, cần người PFAsafe, tự chủ feedback loopsửa và tự kiểm cùng model, cùng task; chỉ harness thay đổi
Năm nấc đầu tiên trên cùng một bài toán median.

Còn hai ví dụ nữa. Ví dụ tiếp theo rẽ sang một hướng hơi khác, và đây là chỗ ta đi vào những khái niệm nâng cao hơn.

13. Bước 5: subagent, để agent làm được nhiều việc hơn

Ví dụ này là subagent. Mọi thứ ta làm tới giờ đều giúp cùng một task được làm tốt hơn. Còn với subagent, câu hỏi là: làm sao để agent làm được nhiều việc hơn?

Anh bắt đầu bằng prompt, vì nó hơi khác: sửa test đang fail trong test_median.py, sau đó dùng Wikipedia agent để tìm hiểu Jensen's inequality cho median, rồi giải thích cho tôi dưới dạng một bài thơ limerick. (Lúc đọc prompt anh vấp chữ "Jensen" một nhịp.)

Code main của ví dụ subagents với tools codingAgent và wikipediaAgent
node main() trong examples/06-subagents.agency: system message "You are a general-purpose agent. Use your subagents to handle each part of the request.", lời gọi llm với prompt sửa test rồi tìm hiểu Jensen's inequality, và tools: [codingAgent, wikipediaAgent]. Phía trên là một callback("onToolCallStart") in tên tool và tham số mỗi khi có tool call.
Fix the failing test in test_median.py. Then research Jensen's inequality for medians with the wikipedia agent and explain it to me in limerick form.

Đây là trường hợp ta thật sự bảo agent làm nhiều hơn một chút. Và điều thú vị là: đây là agent chính, nhưng phần tool thì ta không đưa cho nó read và write. Thay vào đó, ta đưa cho nó hai subagent làm tool.

Anh rất thích pattern này trong Agency, vì anh thấy nhiều framework biến subagent thành một khái niệm riêng, khiến nó khó nắm bắt. Trong Agency, subagent chỉ là một function khác: bạn gọi nó, dùng nó như một tool, y hệt ở mọi chỗ khác. Sự nhất quán đó có rất nhiều lợi ích, khiến code dễ viết và dễ suy luận.

Đây là coding agent dưới dạng subagent. Vẫn giống như trước: có system message, subagent có lời gọi LLM riêng và bộ tool riêng.

Function codingAgent với read.partial, write.partial và exec.partial
def codingAgent(task: string): string, docstring "Use for coding tasks: read, edit, and test code in this project." System message bảo nó là coding agent, sửa code bằng tool write và chạy test bằng exec cho tới khi pass. Bộ tool: read.partial(dir: "demo"), write.partial(dir: "demo") và exec.partial(cwd: "examples/demo", allowedExecutables: ["python"]), bọc trong handle { ... } with approve.

Tương tự là Wikipedia agent. Nó có tool riêng là tool search, một tool có sẵn trong standard library của Agency cho phép tìm trên Wikipedia. Agency có một standard library lớn để làm đủ thứ việc, trong đó có tool tìm Wikipedia này. Anh cũng dùng tính năng callback để in thông tin tool call ra.

Function wikipediaAgent với tool search
def wikipediaAgent(query: string): string, docstring "Use for general-knowledge questions. Searches Wikipedia." System message "You answer general-knowledge questions using the search tool." và tools: [search]. Bên dưới là callback onToolCallStart.

Rồi anh chạy ví dụ, trường hợp ta bảo agent làm nhiều hơn một chút và đưa cho nó hai subagent để hoàn thành nhiệm vụ. Có thể thấy nó gọi hai subagent, và gọi song song: Wikipedia agent đang search, còn coding agent đang sửa file. Lỗi đã được sửa, và đây là bài limerick.

14. Vì sao subagent giúp agent chọn đúng hơn

Subagent hay ở chỗ nó cho phép thêm capability mới mà không làm phình context. Đây là một pattern tốt vì khi agent có rất nhiều tool khác nhau trong tay, nó giúp agent làm đúng việc một cách nhất quán hơn.

Thường khi agent bối rối và fail, đó là vì context bị phình quá mức, nhưng cũng vì trong context có quá nhiều khái niệm không liên quan tới nhau, và có quá nhiều tool không liên quan, nên nó khó chọn đúng tool để dùng. Ở đây ta làm vấn đề đó gọn hơn nhiều. Với agent cấp trên, ta chỉ nói: "Chọn subagent bạn muốn gọi." Còn các subagent thì giữ những tool được nhóm lại theo cách hợp lý.

Slide 06 Subagents (doing more)
"06 - Subagents (doing more)": mọi thứ trước đó làm cùng một task tốt hơn; ví dụ này khác: làm sao để agent làm nhiều hơn? tools: [codingAgent, wikipediaAgent], mỗi cái có llm() và tool riêng: codingAgent đọc, ghi, chạy test; wikipediaAgent tìm kiến thức chung. "Not a better fix, but a new capability." Hai lợi ích: giảm context bloat, và làm đúng việc một cách nhất quán hơn.
agent chính chỉ chọn subagent codingAgent llm() riêng wikipediaAgent llm() riêng read · write · exec search hai subagent chạy song song; context của agent chính không phải chứa mọi tool
Cấu trúc ví dụ subagent: agent chính chỉ thấy hai "tool" là hai subagent; mỗi subagent tự giữ nhóm tool của mình.

15. Bước 6: self-optimization với GEPA

Ví dụ cuối cùng là self-optimization. Agency có sẵn một optimizer GEPA. Thật ra nó có sẵn vài optimizer, nhưng GEPA là một cái rất thú vị.

Cách tính năng optimization hoạt động: bạn đánh dấu những biến mà bạn muốn optimizer tối ưu, chỉ cần dùng modifier optimize, rồi chạy optimizer và đưa cho nó một mục tiêu (goal). Trong ví dụ này, có thể thấy hai prompt ban đầu rất sơ sài, anh gần như không đưa cho nó thông tin gì. Còn mục tiêu anh đưa là: sửa bug trong median.py bằng TDD.

Slide 07 Self-optimization: optimize const và lệnh npx agency optimize
"07 - Self-optimization": đánh dấu biến cần tối ưu bằng optimize const sysMessage và optimize const prompt; chạy optimizer với một goal. Slide ghi optimizer là GEPA (Genetic-Pareto) và câu "No more trial and error. Instead we sy[stematically] mea[sure]..." bị khung camera che một phần.
npx agency optimize examples/07-optimize.agency \
  --goal "fix the bug in median.py using TDD" \
  --optimizer gepa

Lý do đây là một bước tuyệt vời cho harness: ta không còn làm theo kiểu thử và sai nữa. Ta không còn cứ thử đủ thứ để xem cái gì chạy. Thay vào đó, giờ ta có một cách để đo và cải thiện hiệu năng một cách có hệ thống.

Anh chạy đoạn code này, nhưng trước đó anh reset lại và sửa đoạn code một chút. Anh không cho xem toàn bộ lần chạy vì optimizer mất khá lâu, nhưng có thể thấy đầu tiên nó kiểm tra xem có những prompt nào cần tối ưu. Nó sẽ chạy agent để lập baseline. Baseline objective là 0,2, và nó sẽ cố cải thiện từ đó.

Terminal chạy npx agency optimize với GEPA
Lần chạy trực tiếp: npx agency optimize ... --optimizer gepa, phần grading lấy đúng goal "fix the bug in median.py using TDD"; dòng tiêu đề cho biết có 2 target, 1 input, tối đa 5 iteration; hai target là main:prompt và main:sysMessage.

Anh đã chạy optimizer từ trước để cho xem một lần chạy trọn vẹn trông thế nào. Ở lần đó, có thể thấy nó đạt mục tiêu ngay trong những iteration đầu tiên, thật ra khá nhanh, và có thể thấy nó đã viết lại prompt này.

Kết quả optimizer: iter 1/5 accepted objective 1.000 và prompt được viết lại
Lần chạy trọn vẹn làm từ trước: trên màn hình ghi baseline objective 0.000, rồi iter 1/5 accepted objective 1.000 và đạt mức objective tối đa. Prompt cũ "The Python function median has a bug..." bị thay bằng một prompt mới yêu cầu sửa bug theo nguyên tắc TDD: liệt kê test trước, viết test trước khi sửa code, và có một check cho trường hợp danh sách một phần tử.

Self-optimization tuyệt vời vì ta không đoán rồi kiểm tra nữa. Ta đo đạc và cải thiện một cách có hệ thống, và đó là một bước tiến lớn.

16. Cái thang cải tiến harness

Đây là "cái thang" ta vừa đi qua để cải thiện harness:

  • Bước đầu: không có gì, chỉ model, thậm chí không đọc được file.
  • Thêm tool, nhưng theo cách unsafe và không được phép trong Agency.
  • Thêm handler: có safety nhưng làm mọi thứ chậm hơn vì cần con người trả lời.
  • Thêm partial function application: an toàn và nhanh.
  • Thêm reasoning: tin tưởng hơn vào output của agent.
  • Rẽ sang hướng subagent: thêm capability.
  • Cuối cùng là self-optimization: cải thiện có đo đạc, không phải đoán rồi kiểm.
Slide The ladder: bảng L0 tới L6, harness thêm gì và kết quả
"The ladder": L0 nothing, không đọc nổi file; L1 tools, unsafe (không được phép trong Agency); L2 interrupts + handlers, safe nhưng chậm; L3 PFA, safe và nhanh; L4 reasoning, tin output hơn; L5 subagents, thêm capability; L6 self-optimization, cải thiện có đo, không phải guess-and-check.

17. Agency hỗ trợ gì ở tầng ngôn ngữ: true pause and resume

Anh mong những ví dụ này cho khán giả hình dung cách build harness rồi từ từ cải thiện chúng. Anh cũng mong mọi người thử làm như vậy và cùng anh thử nghiệm xem ta có build được harness tốt hơn không. Vì nếu harness quan trọng hơn model thì sao? Nếu ta build được một harness đủ tốt để bắt đầu dùng model local mà vẫn đạt hiệu năng cần cho những việc mình muốn làm thì sao?

Vậy Agency cung cấp sự hỗ trợ gì ở tầng ngôn ngữ? Ta đã dùng Agency cho mọi ví dụ trên. Nó giúp được gì?

  • Cú pháp đơn giản để định nghĩa tool. Lại là "việc đơn giản thì phải đơn giản". Agent nào cũng cần tool, vậy hãy làm cho việc dùng tool thật dễ.
  • Công cụ cho safety, rất quan trọng với agent: interrupt, handler, PFA.
  • True pause and resume execution.

Phần thứ ba anh không đi sâu nhiều vì không muốn talk quá dài, nhưng đó là một trong những tính năng "đinh" của Agency. Khi bạn raise interrupt, nó thật sự tạm dừng thực thi và trả quyền điều khiển về cho người dùng, theo cách mà bạn có thể tiếp tục thực thi sau đó. Theo hiểu biết của anh, rất ít ngôn ngữ cho phép làm điều này.

Thông thường, hầu hết framework bạn dùng, nếu có tính năng human-in-the-loop, thì nó có rất nhiều giới hạn, rất nhiều thứ bạn phải làm để lách quanh nó. Agency hoàn toàn khác. Nếu muốn, bạn có thể raise interrupt bên trong một vòng for, bên trong một tool call, bên trong một subagent, và nó sẽ tạm dừng thực thi đúng cách, quay về người dùng, rồi tiếp tục thực thi tại đúng điểm đó: bên trong subagent đó, bên trong tool call đó, tại đúng vị trí đó trong vòng for. Rất hay.

subagent tool call for loop, lần lặp thứ i interrupt trả quyền về người dùng serialize, có thể để cả tuần resume đúng tại điểm đó không phải sửa code
True pause and resume: interrupt có thể nằm sâu trong for loop, trong tool call, trong subagent; Agency dừng, trả quyền về người dùng, rồi tiếp tục đúng vị trí cũ.

Bạn có thể serialize trạng thái thực thi. Bạn có thể quay lại với nó một tuần sau, và không cần thay đổi gì trong toàn bộ đoạn code ta vừa xem. Nó cứ thế chạy, rất hay.

Agency cũng có sẵn các optimizer, rất tốt, giúp bạn đi tới một cách cải tiến mang tính phân tích, toán học hơn.

18. Cài thử và những điều nên mang về

Nếu muốn thử, cứ thử. Tất cả những gì bạn cần là package và một API key là xong:

pnpm install agency-lang

Những điều nên mang về, lặp lại một lần nữa:

  • Agent là model cộng harness, ít nhất là trong phạm vi talk này.
  • Harness tốt hơn thì hiệu năng tốt hơn, đặc biệt với những model yếu hơn.
  • Vậy build harness tốt hơn bằng cách nào? Cho nó tool, làm cho nó an toàn, làm cho nó tự chủ, cho nó reasoning, cho nó subagent, và để nó tự tối ưu.
give tools make safe autonomous reason subagents self-optimize harness tốt hơn = hiệu năng tốt hơn, nhất là với model yếu
Công thức kết talk: sáu việc để build một harness tốt hơn.

Anh cảm ơn khán giả, nhắc lại tên mình là Adit Bhargava, mời mọi người xem Agency tại agency-lang.com, và theo dõi anh trên Bluesky nếu muốn. "Thank you. Take care."

Nguồn và liên kết