Siapa pun yang telah mengirimkan produk agen tahu perasaan itu: membuat demo bekerja itu cepat, tetapi mengubahnya menjadi sesuatu yang dipercaya pengguna setiap hari - sesuatu yang berjalan sepanjang hari di mesin mereka sendiri tanpa jatuh - itu sulit. Dan bagian yang sulit adalah tidak memasang kabel model. Ini adalah seluruh lapisan yang berada di sekitar model.
Lapisan itu memiliki beberapa nama; yang akan saya gunakan adalah Agent Harness. Itu berada di antara "model besar" dan "fitur produk," dan itu adalah runtime yang sebenarnya: itu mengubah satu permintaan pengguna menjadi putaran demi putaran percakapan dengan model, memanggil alat threading di antaranya, memberi makan hasil kembali, memadatkan konteks sebelum meluap, mencoba lagi melalui cegukan jaringan, dan memulihkan percakapan bahkan setelah prosesnya macet. Model melakukan pemikiran; harness membuat tanah pemikiran itu sebagai urutan tindakan yang dapat diandalkan.
Orkas adalah aplikasi agen desktop yang berjalan di mesin pengguna sendiri, dan harness-nya hidup sepenuhnya di klien. Artikel ini menjelaskan bagaimana lapisan itu dibangun: bagaimana itu dibagi menjadi beberapa lapisan, seperti apa tampilan run loop, bagaimana alat dan model diabstraksikan, dan bagaimana memori dan sesi ditangani. Detail kode telah digosok dan digeneralisasikan, tetapi struktur tekniknya nyata.
Lapisan
Letakkan produk agen rata dan Anda mendapatkan kira-kira lapisan-lapisan ini, ditumpuk dari bawah ke atas:
┌─────────────────────────────────────────┐
│ Product features (chat / skills / connectors / sync) │
├─────────────────────────────────────────┤
│ Agent Harness (run loop / tools / session) │
├─────────────────────────────────────────┤
│ Provider abstraction (unify many LLM vendors) │
├─────────────────────────────────────────┤
│ Infrastructure (types / errors / logging / config) │
└─────────────────────────────────────────┘Ada satu pilihan konsekuensial yang dipanggang di sini: Semua inferensi model terjadi pada klien. Aplikasi desktop bukanlah klien tipis — aplikasi ini memegang harness itu sendiri dan memanggil model secara langsung. Server hanya menangani akun, sinkronisasi multi-perangkat, dan penagihan; itu tidak menjalankan agen sama sekali. Keputusan ini membentuk hampir semua hal di hilir: sesi mendarat di disk lokal, alat beroperasi langsung di direktori kerja pengguna, dan data sensitif tidak pernah meninggalkan mesin.
Harness itu sendiri terbagi menjadi beberapa bagian: loop lari (pelari), sesi, alat, lapisan Penyedia, dan memori. Mari kita ambil mereka satu per satu.
Run loop: sebuah generator streaming
Jantung dari harness adalah pelari. Dalam satu kalimat, apa yang dilakukannya adalah: Berbicara dengan model berulang-ulang sampai model mengatakan "Saya sudah selesai."
Ini diimplementasikan sebagai generator asinkron, dan pilihan itu penting. Satu agen berjalan jauh lebih dari "kirim permintaan, tunggu hasilnya." Banyak yang terjadi di antaranya — model memancarkan token, ingin memanggil alat, alat selesai, konteksnya cukup lama untuk memicu pemadatan, jaringan gagal dan kami mencoba lagi. Dengan panggilan balik atau Janji biasa, keadaan perantara tersebut sulit untuk muncul secara bersih kepada penelepon. Sebagai generator, mereka semua menjadi aliran dari yield-Ed acara:
type AgentRunEvent =
| { type: "text_delta"; text: string } // model emitting tokens
| { type: "tool_start"; name: string; input: unknown } // a tool starts executing
| { type: "tool_end"; name: string; result: string } // a tool finished
| { type: "compaction"; tokensBefore: number; tokensAfter: number } // context compacted
| { type: "retry"; attempt: number; reason: string } // error, retrying
| { type: "done"; result: AgentRunResult } // terminalUI berlangganan aliran acara ini dan melukis output model dan eksekusi alat secara real time. Titik masuk non-streaming secara internal hanya "mengkonsumsi aliran sampai akhir, ambil yang terakhir done" — kedua titik masuk berbagi satu implementasi, jadi tidak ada jalur kode kedua yang tidak sinkron.
Apa yang terjadi di dalam belokan
Tidak digulung, satu belokan terlihat kira-kira seperti ini:
- Dorong pesan pengguna (mungkin dengan gambar) ke dalam riwayat sesi.
- Merakit prompt sistem, menyuntikkan alat yang tersedia saat ini, indeks keterampilan, dan sebagainya.
- Parsing string model dan selesaikan menjadi Penyedia konkret dan ID model.
- Ubah semua alat menjadi definisi yang dipahami model, dan kirimkan bersama dengan riwayat.
- Mengkonsumsi aliran respons model,
yield-Ing token teks demi token saat mengumpulkan panggilan alat apa pun yang dibuat model. - Ketika aliran berakhir, lihat alasan berhenti model:
- Jika itu
tool_use, model ingin memanggil alat — jalankan alat, lalu kembali ke langkah 5 dan tanyakan model lagi. - Jika tidak, giliran sudah berakhir — kumpulkan hasilnya,
yield done, dan kembali.
Ada satu invarian yang harus Anda pegang di sini: Setiap panggilan alat yang dibuat model harus segera diikuti dalam riwayat dengan hasil alat yang cocok. Model API memberlakukan pemasangan ini dengan keras — hancurkan dan permintaan berikutnya akan mengalami kesalahan atau hanya hang. Kita akan kembali ke ini ketika kita berbicara tentang sesi penyembuhan diri.
Bagaimana panggilan alat dialihkan kembali
Model tidak menjalankan alat itu sendiri; itu hanya mengatakan "Saya ingin memanggil read_file Dengan argumen-argumen ini." Setelah pelari mengambil niat itu:
for (const call of toolUseBlocks) {
yield { type: "tool_start", name: call.name, input: call.input };
const tool = this.tools.get(call.name);
const ctx = { workingDir, signal, state: { sandboxEnv } };
const result = await tool.execute(call.input, ctx);
// append the result to the session as a tool-result message
session.addToolResult(call.id, result);
yield { type: "tool_end", name: call.name, result: result.content };
}Alat berjalan secara berurutan, hasil ditulis kembali ke riwayat dalam urutan model mendeklarasikannya, dan kemudian model ditanya lagi dengan hasil tersebut di tangan. Melihat hasilnya, model mungkin memanggil alat lain atau hanya memberikan jawaban terakhirnya. Lingkaran "tanya → panggil → jawab → tanya lagi" ini adalah apa yang memungkinkan agen menyelesaikan tugas multi-langkah.
Satu detail layak disebutkan sendiri: beberapa alat mengembalikan gambar — tangkapan layar, gambar yang dihasilkan. Tetapi banyak model yang tidak menerima gambar di saluran hasil alat. Orkas menangani ini dengan membagi gambar menjadi pesan pengguna terpisah yang ditempatkan Sesudah Hasil alat - model pertama-tama membaca "alat mengembalikan teks ini," kemudian pada giliran berikutnya melihat gambar yang sesuai. Sebuah kompromi kecil yang mengarahkan di sekitar perbedaan kemampuan antara Penyedia.
Apa yang harus dilakukan ketika konteks akan meluap
Tugas panjang dinding yang paling sering terjadi adalah jendela konteks. Orkas tidak menunggu sampai penuh — itu menetapkan sebuah 60% tanda air: setelah setiap putaran alat, itu memperkirakan berapa banyak jendela yang ditempati token saat ini, dan setelah melewati 60% itu secara proaktif memicu pemadatan.
Pemadatan itu sendiri meminta model untuk meringkas percakapan sebelumnya, lalu mengganti pesan lama dengan ringkasan itu, hanya menyimpan ekor terbaru. Kedengarannya sederhana, tetapi ada jebakan: setelah pertukaran, ekor yang dipertahankan tidak boleh dimulai dengan "hasil alat yatim piatu" - tidak mungkin ada "hasil tanpa panggilan yang cocok," atau Anda telah memecahkan invarian pasangan lagi. Jadi logika pemadatan memastikan potongan mendarat di batas yang bersih.
Ada pilihan yang lebih menarik yang layak dibongkar di sini: mengapa pendekatan kasar "meringkas seluruh blok pada 60%", daripada sesuatu yang lebih halus - menilai setiap pesan dan memangkas berdasarkan kepentingan, ekstraksi terstruktur dari output alat, mempertahankan pohon memori berlapis? Pendekatan itu terlihat bagus di koran, tetapi kami sengaja tidak melakukannya seperti itu, karena tiga alasan.
Pertama, Menyimpan cache. Cache prompt model mengenai awalan: selama awalan riwayat tidak berubah, rentang itu mengenai cache, menghemat uang dan latensi. Pemadatan berbutir halus terus-menerus menulis ulang bagian tengah sejarah, yang berarti berulang kali menghancurkan awalan yang di-cache - setiap pengeditan memaksa pengisian ulang yang besar. Strategi "biarkan saja, lalu padatkan sekali pada tanda air" menjaga awalan tetap stabil di sebagian besar belokan, dengan hanya pemadatan tunggal yang membatalkannya. Jauh lebih ramah terhadap cache.
Kedua, Kompleksitas. Bahwa "setiap panggilan alat harus dipasangkan" invarian yang terus kami tekan - semakin halus Anda memangkas riwayat, semakin besar kemungkinan Anda memecahkannya di beberapa sudut. Ringkasan kasar hanya harus melindungi satu titik potong yang bersih; ada banyak tempat yang lebih sedikit untuk salah. Satu kelas kasus tepi yang lebih sedikit adalah satu kelas insiden produksi yang lebih sedikit.
Ketiga, Mengendarai dividen dari model yang lebih baik. Jendela konteks telah berkembang dengan mantap selama beberapa tahun terakhir, dan model menangani konteks panjang dengan lebih baik dan lebih baik. Menuangkan upaya hari ini ke dalam algoritma pemadatan yang rumit pada dasarnya melawan masalah yang menyusut - kemungkinan Anda selesai menyetelnya sama seperti generasi berikutnya menggandakan jendelanya, dan kompleksitas Anda menjadi tanggung jawab murni. Sebaliknya, menyerahkan ringkasan ke model itu sendiri secara otomatis menjadi lebih baik seiring dengan peningkatan model: semakin baik dalam memilih apa yang penting, semakin tinggi kualitas ringkasannya, dan kita tidak mengubah satu baris pun. Kompleksitas yang dapat dibawa model untuk Anda adalah kompleksitas yang seharusnya tidak Anda bawa sendiri.
Estimasi token menyembunyikan satu masalah yang mudah dilewatkan: Cina. Perkirakan bahasa Mandarin menggunakan intuisi bahasa Inggris (kira-kira satu token per beberapa karakter) dan Anda akan sangat kurang menghitung. Orkas menimbang karakter CJK secara terpisah dalam perkiraannya; jika tidak, tanda air untuk percakapan semua-Cina dibaca salah, dan pemadatan tidak akan menyala ketika seharusnya.
Kesalahan dan pengulangan
Berjalan di mesin pengguna dan bergantung pada API model eksternal, kesalahan adalah norma, bukan pengecualian. Pelari menyortir mereka ke dalam beberapa kelas dan memperlakukan masing-masing secara berbeda:
- Dapat dicoba ulang: batas kecepatan, batas waktu, koneksi terputus, 5xx. Backoff eksponensial dengan jitter, dibatasi pada 30 detik; jika itu adalah batas tarif dan server mengirim
retry-after, hormati itu. - Tidak dapat dicoba ulang: hal-hal seperti kegagalan auth — tidak ada jumlah percobaan ulang yang akan membantu, jadi segera keluar dari kesalahan.
- Spesial: konteks meluap. Coba pemadatan terlebih dahulu, coba lagi sekali setelahnya, dan hanya kesalahan jika itu masih gagal.
Ada satu kelas lagi: "alat itu sendiri gagal." Ini tidak tenggelam seluruh giliran - kegagalan alat itu sendiri adalah informasi untuk model, yang, melihat "perintah itu salah," dapat dengan sangat baik mencoba pendekatan yang berbeda. Harness membedakan kesalahan alat sementara ini dari kesalahan nyata: tidak mengganggu aliran atau kehilangannya - mereka muncul dalam statistik setelah fakta. (Data itu kemudian memberi makan mekanisme evolusi diri, yang merupakan subjek dari artikel berikutnya.)
Sinyal pembatalan eksternal (AbortSignal) diperiksa di setiap titik kunci. Pengguna menekan "berhenti," dan belokan saat ini segera berhenti — tidak ada persalahan ulang yang dimulai.
Alat abstraksi: cukup sederhana untuk diperluas
Antarmuka alat sengaja tipis:
interface AgentTool {
readonly name: string;
readonly description: string; // shown to the model
readonly inputSchema: Record<string, unknown>; // JSON Schema to constrain inputs
execute(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>;
}Sebuah alat hanyalah "nama + deskripsi untuk model + skema input + fungsi eksekusi." Bawaan - baca file, tulis file, jalankan perintah shell, pencarian web dan ambil - semuanya mengimplementasikan antarmuka ini. Lapisan desktop menumpuk kumpulan alat rasa lokal di bagian atas (pencarian basis pengetahuan, pembuatan gambar, memanggil konektor eksternal), tetapi antarmukanya sama.
Imbahan dari antarmuka tipis adalah dari mana alat berasal tidak relevan dengan pelari: bawaan, ditentukan pengguna, atau dimuat dari keterampilan - semuanya adalah hal yang sama, terdaftar menjadi satu Map<string, AgentTool> Dan diubah menjadi definisi yang dapat dibaca model setiap giliran.
Alat efek samping seperti perintah shell melewati eksekutor yang terisolasi: batas waktu, batas panjang keluaran, daftar blok perintah, dan variabel lingkungan yang diteruskan secara terpisah daripada mengubah lingkungan global proses - yang terakhir akan bocor ke dalam segerombolan proses anak dan, dalam arsitektur multi-proses seperti Electron, dapat dengan mudah merusak startup.
Lapisan Penyedia: meratakan banyak model menjadi satu antarmuka
Preferensi model pengguna ada di seluruh peta, dan sebuah produk tidak dapat mengikat secara keras ke satu vendor. Di bawah harness, Orkas meletakkan abstraksi Penyedia yang menyatukan model vendor yang berbeda di balik satu antarmuka:
interface LLMProvider {
readonly id: string;
complete(params: CompletionParams): Promise<CompletionResult>;
stream(params: CompletionParams): AsyncIterable<StreamEvent>;
validateAuth(): Promise<boolean>;
}Pelari di atas hanya pernah berbicara dengan antarmuka ini; tidak tahu vendor mana yang berada di belakangnya. Registri menangani perutean dengan string model: eksplisit provider/model Bentuk dibagi secara langsung; nama model kosong dikaitkan dengan awalan. Auth (kunci API atau token OAuth) juga dikelola di sini, dan token OAuth yang kedaluwarsa disegarkan secara otomatis.
Meratakan banyak model, sakit kepala yang sebenarnya bukanlah penyelesaian teks - itu adalah sudut di mana semantik vendor tidak setuju. Dua contoh yang menggigit kita.
Salah satunya adalah Melestarikan blok pemikiran di seluruh vendor. Model penalaran memancarkan rentang konten "berpikir"; beberapa vendor mengenkripsinya dan mengharuskan Anda untuk menggemakannya kembali kata demi kata, yang lain mewakilinya dengan serangkaian bidang yang berbeda. Jika pengguna beralih dari vendor A ke vendor B di tengah percakapan, tanda tangan pada rentang pemikiran itu dalam riwayat tidak lagi cocok. Perbaikannya adalah dengan mencap setiap pesan dalam riwayat dengan "model mana yang menghasilkan ini," sehingga lapisan transformasi dapat memutuskan apakah akan mempertahankannya kata demi kata: model yang sama, mempertahankannya; model yang berbeda, menurunkan versi sesuai aturan.
Yang lainnya adalah Cache prompt. Di seluruh giliran satu sesi, awalannya sangat berulang, dan cachingnya menghemat biaya dan latensi yang berarti. Implementasi meneruskan ID sesi sebagai kunci cache ke vendor yang mendukungnya, menangani batas panjang kunci masing-masing vendor di sepanjang jalan (potong atau hash jika terlalu panjang, katakanlah).
Ini semua adalah pekerjaan mendengus - tetapi justru lapisan pekerjaan mendengus inilah yang membuat pelari di atas berpura-pura "hanya ada satu jenis model."
Memori: dua mekanisme, masing-masing untuk tugasnya sendiri
"Memori" dalam Orkas sebenarnya adalah dua mekanisme paralel yang memecahkan dua masalah yang sama sekali berbeda. Salah satunya adalah basis pengetahuan berbasis pengambilan, untuk materi massal Anda "cari saat dibutuhkan." Yang lainnya adalah memori lintas sesi, untuk kumpulan kecil fakta kunci yang "harus selalu Anda ingat." Banyak produk yang menggabungkan keduanya bersama-sama; menjaga mereka terpisah membuat segalanya jauh lebih jelas.
Basis pengetahuan: pengambilan hibrida
Mekanisme pertama menargetkan konten yang besar tetapi hanya sesekali relevan — dokumen pengguna, catatan sebelumnya, pengetahuan domain. Ini adalah basis pengetahuan lokal dengan pengambilan vektor, dalam dua backend: versi memori murni yang ringan (untuk pengujian dan penggunaan sementara), dan versi yang bertahan ke basis data lokal (untuk produksi, dengan pengindeksan teks lengkap dan vektor).
Data masuk di sepanjang jalur ini:
documents → chunk on line boundaries (with overlap) → dual indexing
├─ full-text index (keywords, no embedding cost)
└─ vector index (if an embedding model is configured)Potongan dipotong pada batas garis dengan sedikit tumpang tindih di antara mereka, untuk menghindari mengiris sepotong makna yang lengkap di tengah. Pengambilan adalah Hibrida: lintasan vektor (dekat secara semantik) dan lintasan kata kunci (hits literal), dengan dua set hasil yang digabungkan melalui RRF (Reciprocal Rank Fusion):
score = Σ 1 / (k + rank_i)Semakin tinggi peringkat hasil dalam satu lintasan, semakin banyak kontribusinya; dijumlahkan di kedua lintasan, Anda berdua menghormati relevansi semantik dan tidak kehilangan kecocokan literal yang tepat. Bobot vektor dan kata kunci dapat disetel, secara default mendukung semantik. Setelah penggabungan, hasil dideduplikasi dengan "(dokumen, garis awal)," hanya menyimpan yang terbaik per lokasi, kemudian apa pun di bawah ambang batas dipotong, mengembalikan K teratas.
Mengapa tidak mengandalkan vektor saja? Karena pengambilan vektor sering kali menghadapi kata benda yang tepat, simbol kode, dan string literal yang tepat - pertanyaan yang tidak khusus secara semantik tetapi di mana literal sangat penting - sementara kata kunci saja tidak dapat menangkap "makna yang sama, frasa yang berbeda." Menjalankan keduanya adalah pertukaran yang sangat praktis antara kualitas pengambilan dan biaya.
Memori lintas sesi: mengingat pengguna
Basis pengetahuan memecahkan "terlalu banyak materi untuk dipegang." Tetapi ada kelas lain - volumenya kecil, namun harus diingat setiap saat: siapa pengguna ini, apa yang mereka sukai, apa yang disepakati terakhir kali. Ini seharusnya tidak bergantung pada pengambilan untuk "mendapatkan keberuntungan dan mengingat" - mereka harus hadir di setiap giliran.
Untuk ini, Orkas membangun lapisan terpisah dari memori lintas sesi, dibagi berdasarkan konten menjadi dua bagian:
- Profil pengguna: fakta stabil tentang Orang — peran, preferensi, gaya komunikasi, tumpukan teknologi.
- Catatan fakta: fakta yang tahan lama tentang Bekerja — keputusan, tonggak sejarah, konvensi proyek.
Keduanya kecil, masing-masing dengan topi keras beberapa ribu karakter, yang memaksa mereka untuk hanya menyimpan apa yang benar-benar berguna dalam jangka panjang. Mereka tidak melalui pengambilan; sebaliknya mereka dibekukan langsung ke prompt sistem di awal setiap giliran - yang berarti agen hanya "tahu" hal-hal ini, tanpa harus ingat untuk mencarinya. Itu adalah sikap yang berlawanan dari basis pengetahuan: basis pengetahuan adalah "mengambil hanya saat dibutuhkan, pergi setelah," memori lintas sesi adalah "selalu ada, selalu terlihat."
Menulis melalui alat memori khusus yang dipanggil model ketika menilai, di tengah percakapan, bahwa "ini layak diingat dalam jangka panjang," mendukung penambahan, penggantian substring, dan penghapusan. Apa yang harus disimpan dan apa yang tidak boleh dijabarkan dengan jelas dalam deskripsi alat: koreksi dan preferensi pengguna adalah prioritas utama; keputusan dan konvensi yang tahan lama disimpan; sementara keadaan sementara tugas saat ini, info debug satu kali, dan apa pun yang mudah ditemukan kembali tidak — memori adalah untuk "fakta tahan lama tentang pengguna dan proyek," bukan untuk "di mana saya sampai saat ini."
Ada detail yang mudah diabaikan tetapi cukup penting: Pemindaian keamanan berjalan sebelum setiap penulisan. Konten ini masuk ke sistem prompt kata demi kata dan bertahan di seluruh sesi untuk waktu yang lama — secara efektif permukaan injeksi yang tahan lama. Jadi setiap memori yang akan ditulis ke disk pertama-tama dipindai untuk mencari pola yang mencurigakan - frasa injeksi prompt klasik ("abaikan semua instruksi sebelumnya" dan sejenisnya), perintah yang mencoba mengekstraksi kunci, karakter unicode yang tidak terlihat tersembunyi dalam teks - dan kecocokan ditolak secara langsung. Dengan deduplikasi dan pemangkasan batas berlebih di atasnya, lapisan memori ini tetap berguna tanpa menjadi kewajiban.
Bersama-sama, dua mekanisme mencakup kedua ujungnya - "besar tetapi sesekali" dan "kecil tetapi konstan": basis pengetahuan menangani yang pertama, memori lintas sesi yang terakhir. Tambahkan ke itu pemahaman agen tentang Sendiri (Subjek artikel berikutnya), dan seorang agen Orkas masuk membawa tiga jenis memori sekaligus — tentang materi, tentang pengguna, dan tentang dirinya sendiri.
Sesi: dibangun untuk jatuh, dibangun untuk menyembuhkan
Sesi mengelola riwayat pesan. Versi dasarnya hanyalah susunan pesan dalam memori dengan pemangkasan dan pemadatan riwayat. Tetapi apa pun yang berjalan di mesin pengguna harus berasumsi bahwa itu dapat dibunuh kapan saja - pengguna keluar dari aplikasi, sistem reboot, batas waktu pengawas mengeluarkan proses. Jadi produksi menggunakan sesi persisten, ditulis ke file JSONL lokal, satu pesan per baris.
Ada dua strategi penulisan: menambahkan pesan baru menggunakan lampiran atom; apa pun yang menulis ulang seluruh file (pemadatan, pembersihan) menggunakan "menulis file sementara + mengganti nama atom." Dengan begitu, bahkan jika daya terputus di tengah penulisan, Anda tidak akan pernah meninggalkan setengah dari catatan yang rusak.
Bagian yang paling menarik adalah Menyembuhkan panggilan alat yatim piatu. Kembali ke invarian pasangan itu: model membuat panggilan alat, harness mengeksekusinya, hasilnya ditulis kembali - mengganggu salah satu dari tiga langkah itu dan Anda meninggalkan anak yatim piatu di disk, "panggilan tanpa hasil." Muat sesi itu lain kali dan kirimkan apa adanya ke model, dan API akan menolaknya atau hang.
Logika penyembuhan berjalan setiap kali sesi dimuat dari disk, dan itu idempotent:
- Pindai semua pesan asisten dan kumpulkan ID panggilan alat yang mereka buat.
- Nantikan hasil alat yang cocok.
- Untuk setiap panggilan yang tidak memiliki hasil yang cocok, sintesiskan yang ditandai "terganggu."
- Sepanjang jalan, selaraskan urutan hasil dengan urutan deklarasi panggilan, dan lepaskan hasil yatim piatu yang tidak memiliki panggilan yang cocok.
Setelah melewati ini, sesi dijamin berada dalam keadaan yang memenuhi persyaratan pemasangan API dan aman untuk dikirim. Mekanismenya terlihat biasa-biasa saja, tetapi itu adalah jaring pengaman yang menjaga "percakapan pengguna tidak terkunci secara permanen hanya karena satu kecelakaan."
Beberapa keputusan yang penting dalam melihat ke belakang
Merangkai semua ini bersama-sama, beberapa keputusan terlihat sangat berharga setelah fakta.
Generator sebagai antarmuka utama. Streaming dan non-streaming berbagi satu implementasi, permukaan keadaan menengah secara alami, dan UI dapat melukis detail sebanyak yang diinginkan. Ini menyelamatkan seluruh kelas bug ketidakkonsistenan yang akan dibuat "menerapkan non-streaming terlebih dahulu, menyalakan streaming nanti".
Kompak pada 60%, bukan saat penuh. Ini meninggalkan ruang kepala untuk pemadatan itu sendiri (yang juga membutuhkan panggilan model) dan menghindari perebutan pada saat-saat terakhir.
Invarian pasangan berjalan melalui segalanya. Dari titik potong pemadatan, hingga menulis ke disk, hingga penyembuhan waktu beban, setiap tempat yang menyentuh sesi memiliki aturan yang sama. Dengan satu aturan, tidak ada tempat yang harus menciptakan logika tambalannya sendiri.
Pekerjaan grunt terkonsentrasi di lapisan Penyedia. Semua kecanggungan lintas vendor - blok pemikiran, kunci cache, perbedaan kemampuan - dicerna dalam satu lapisan ini, dengan imbalan pelari bersih di atas. Tambahkan vendor model baru suatu hari nanti dan perubahannya hampir tidak tumpah.
Membungkus
Harness Orkas tidak memiliki algoritma yang menakjubkan. Nilainya adalah dalam mengambil "membuat agen berjalan dengan andal di lingkungan nyata" dan membaginya menjadi satu set modul dengan batas-batas yang bersih, masing-masing memiliki satu irisan: pelari memiliki loop dan mencoba ulang, alat memiliki kemampuan sendiri, lapisan Penyedia memiliki perataan banyak model, memori memiliki pengambilan, sesi memiliki kegigihan dan penyembuhan. Tak satu pun dari mereka yang kompleks dengan sendirinya; hanya bersama-sama mereka memegang sesuatu yang digunakan orang setiap hari.
Jika ada sesuatu yang harus diambil: buat loop berjalan generator streaming dan keadaan menengah menjadi jauh lebih mudah untuk ditangani; setelah invarian inti diatur (seperti "panggilan alat harus dipasangkan"), tahan secara konsisten di seluruh pemadatan, penulisan disk, dan pemuatan - jangan biarkan sudut apa pun menjadi pengecualian; berkonsentrasikan pekerjaan dengusan lintas vendor dalam satu lapisan dan jauhkan itu dari logika bisnis; dan - yang paling jelas dari semuanya - anggap proses Anda akan mati pada saat terburuk, dan tulis penyembuhan untuk saat itu sebelumnya.
Artikel berikutnya masuk ke bagian yang lebih menarik dari Orkas: bagaimana agen ini belajar dari penggunaannya sendiri, menyaring pengalaman menjadi keterampilan yang dapat digunakan kembali, dan perlahan-lahan membuat dirinya lebih berguna.