news 2026/10/11 13:21:06

Go 写 Agent 框架是异端还是未来?Unreal Agent 引爆的技术栈之争

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Go 写 Agent 框架是异端还是未来?Unreal Agent 引爆的技术栈之争

Go 写 Agent 框架是异端还是未来?Unreal Agent 引爆的技术栈之争

【免费下载链接】unreal-agentAsync-first agent harness项目地址: https://gitcode.com/gh_mirrors/un/unreal-agent

2026 年 9 月,一个名为 Unreal Agent 的开源项目出现在 GitHub 周榜上,社区给出的第一反应不是"又一款 Agent 框架",而是一个更尖锐的问题:为什么是 Go?在过去两年里,Agent 框架几乎是 Python 与 TypeScript 的专属领地——LangChain、LlamaIndex 用 Python 建立生态,Claude Code、OpenClaw 用 TypeScript 定义交互范式。而 Unreal Labs 推出的这个 async-first agent harness,从协调器、收件箱到会话存储、操作运行时,整套核心用 Go 实现,声称相比 Codex 可省 40% 成本、相比 Pi 省 20%,且性能无损。当"成本优化"与"Go 语言"这两个词同时出现在 Agent 框架的描述里,一场关于技术栈归属的争论就此点燃。

本文不站队,而是把这个问题拆开来看:先复盘 Python/TS 为何成为 Agent 的默认选项,再从 Unreal Agent 的源码出发,检验 Go 在并发、部署与性能上的"反攻"到底成立几分,最后落到普通开发者身上——这场争论真正改变的是什么。

为什么 Agent 框架默认是 Python/TS 的地盘

要理解 Go 为何被视作"异端",得先看清 Agent 框架的默认技术栈是怎么被锁定的。

第一层原因是模型生态的绑定。主流推理提供商(OpenAI、Anthropic)的 SDK 与官方示例都以 Python 为第一公民,function calling、streaming、结构化输出的参考实现几乎全是 Python;TypeScript 则靠前端与 Node 生态补位。框架作者为了"开箱即用",自然顺着 SDK 走,Python 因此成为 Agent 骨架的默认母语。

第二层原因是 Agent 的抽象重心。早期 Agent 框架解决的核心问题是提示词与工具的组织,而非高并发调度。ReAct 循环、工具注册、记忆检索,本质上是一系列串行的上下文变换,Python 的胶水语言特性在原型阶段效率极高——写模型调用、拼 prompt、接 RAG,几乎不需要操心类型与内存。掘金社区对 Agent 概念的普及性讨论也从侧面印证了这一点:大量入门教程把 Agent 讲成"LLM + 工具循环"的编排脚本,而这种编排脚本用 Python 表达最顺手。

第三层原因是人才与生态的惯性。过去两年的 Agent 工程岗 JD 大量要求 Python 或 TypeScript,前端与 Python 开发者被一波波吸纳入场,框架继续朝这两个语言堆叠能力,形成正反馈。一个直接用 Go 写 Agent 核心的仓库,在"Agent 元年"的语境里,天然显得格格不入。

但问题在于:Agent 正在从"脚本"变成"服务"。当它要跑在云上、要扛住多会话并发、要崩溃恢复、要跨进程沙箱执行工具时,Python 的 GIL、TS 的运行时开销、以及两套生态里"事件循环必须单线程"的心智模型,就开始成为成本与可靠性的瓶颈。这正是 Unreal Agent 的切入角度。

Go 在并发、部署、性能上的反攻逻辑

Unreal Agent 的自我介绍只有一句话:async-first agent harness。但"异步优先"四个字背后,是一整套与 Python/TS 主流框架截然不同的运行时设计。我们逐层拆它的源码。

并发模型:goroutine 是免费的调度器

Agent 框架最容易被低估的工程点,是工具执行的并发。传统 Agent 循环里,模型发起多个工具调用后,框架要么串行执行,要么在单线程事件循环里手动管理异步回调;而 Unreal Agent 的做法是让工具调用彻底异步化——模型发出调用后立即继续,工具在后台并行运行,结果以事件形式回流唤醒新一轮 LLM 交互。

承载这套并发模型的,正是 Go 的 goroutine 与 channel。看协调器的核心循环(harness/coordinator/loop.go):主循环用一个select同时监听五个事件源——收件箱输入、操作完成更新、心跳、宽限期结束、模型响应。每一次模型推理之间,框架不阻塞等待工具结果,而是让操作管理器在后台推进:

select { case <-ctx.Done(): return ctx.Err() case received, open := <-inboxOutput: if err := current.processInputs(ctx, []inbox.Input{received}); err != nil { return err } case received, open := <-operationUpdates: if err := current.processOperations(ctx, []operation.Operation{received}); err != nil { return err } case <-heartbeat: if err := current.postHeartbeat(ctx); err != nil { return err } case received := <-modelResponses: ... }

在 Python 里,这套多路复用要么用asyncio手动编排协程,要么引入第三方调度;在 Go 里,channel + select 是语言内置的惯用法,类型系统还顺带把"哪个事件源"写死在分支里。这不是炫技,而是把 Agent 的并发本质——多个外部事件(输入、工具结果、控制指令)在时间上任意交错——直接映射为语言原语。

操作与工具的分离:把异步落成可恢复的账本

Unreal Agent 最关键的设计,是Tool(模型可见的能力)与 Operation(可持久化的工作单)的分离。README 的术语表写得很清楚(README.md):工具翻译器(translator)在协调器事件循环上同步运行,只负责把模型产生的工具调用"翻译"成一个或多个操作引用,自身不做任何 I/O;真正的执行交给操作管理器(operation manager),一个独立 actor 运行时。

看 harness/operation/operation.go 中Operation的定义:每个操作带 ID、类型、版本、状态与可序列化状态,状态机从ready、awaiting一路走到completed、failed、canceled。这个"每个操作都是一份可序列化、可幂等、可恢复的工作单"的模型,正是 async-first 的落地保证:模型推理与工具执行被彻底解耦,工具跑多久都不阻塞推理预算,模型推理也不阻塞工具推进。

本地操作管理器(harness/operation/local_manager.go)把每个操作映射到一个状态机 handler——shell 有 shell 的相位机(创建目录→写输出→读结果→读尾部),viewimage 有 viewimage 的处理器——操作通过 channel 提交、取消、上报更新,整个管理器以独立 goroutine 运行:

func NewLocalOperationManager(ctx context.Context, remoteJobHandlers ...RemoteJobHandler) *LocalOperationManager { manager := &LocalOperationManager{ ctx: ctx, adds: make(chan localAddRequest), cancellations: make(chan localCancelRequest), primitiveEvents: make(chan primitives.PrimitiveEvent), updates: make(chan Operation), } go manager.run() return manager }

更重要的是,操作管理器的接口(Add/Cancel/Updates)被刻意做成可替换的——README 明确建议用一个"代理操作管理器"把序列化后的操作转发到远程沙箱中的本地管理器执行。这意味着工具可以在隔离容器里跑,而协调器只持有操作状态。这种"运行时与沙箱解耦"的能力,Python 框架往往要借助额外的进程管理库才能实现,而 Go 的静态二进制 + 标准库os/exec让这件事变得异常自然。

成本优势从哪来:异步执行 = 更少的空转 token

社区情报里最引人注目的数字是"相比 Codex 省 40% 成本、Pi 省 20%"。成本优势的直接来源就是异步化:传统 Agent 在工具执行期间让模型空等,每次轮询都可能产生新的上下文与推理开销;Unreal Agent 让模型在工具运行时继续推进其他工作,或者干脆结束本轮、等结果回来再唤醒,把"等待"从 token 账单里剔除。

源码层面有两处直接证据。其一是上下文构建器(harness/contextbuilder/builder.go)中未完成工具调用的占位文案:

const ToolCallRunningPayload = "Tool call is still running. Its result arrives in a later turn: continue with independent work, or end your turn to wait for it."

模型被告知"别干等,继续做独立的工作,或结束本轮去等结果"——这是把异步语义写进系统提示里,引导模型主动减少空转轮次。

其二是 system preamble(harness/contextbuilder/prompts/preamble.md),它直接要求模型"一次多开工具调用、同轮并行、不要串行链式等待":

Each turn re-sends the whole conversation, so prefer to go wider with tool calls — they are cheap — rather than chaining them across a longer sequence of turns... issuing one never blocks you and many run at once.

会话内的每一轮都会重发完整上下文,所以"尽量在同一轮内并行发工具调用"不仅省时间,还省 token——少几轮,就少几次完整的上下文重发。Harbor 适配器的轨迹输出也证实了缓存 token 被显式统计(benchmarks/harbor/src/harness_harbor/trajectory.py 中total_cached_tokens与cache_write_tokens),prompt cache 友好性是框架的一等公民设计目标,而非事后优化。

部署形态:单二进制是 Agent 基础设施的刚需

Agent 框架在云端运行时,交付物通常是一个长驻服务或 CLI。Go 的部署优势在 Agent 场景被放大了:无运行时依赖的单静态二进制、跨平台交叉编译、Docker 镜像极小。仓库里 cmd/unreal-agent-runner 就是一个可直接go install的 CLI runner,还附带多架构 Linux 镜像;cmd/unreal-agent-tui 则用同一套 harness 库实现了一个终端交互客户端——一个库同时长出 CLI、TUI、云端 runner 三种形态,这正是"基础设施级"框架该有的交付密度。

再看 Go 模块依赖(go.mod):整个仓库对第三方库的依赖极少,LLM 客户端、SSE 流解析、重试策略、会话存储几乎全部自研。对想长期维护 Agent 基础设施的团队来说,这是可审计性与可控性的胜利——你不会被一层层第三方编排库的抽象泄漏拖垮。

可靠性:崩溃恢复与会话分叉是"生产级"的门票

异步化的代价是状态分散:工具可能在模型推理期间完成,会话可能在工具运行时崩溃。Unreal Agent 的回应是把"可恢复性"做成骨架而非补丁。

会话存储(harness/sessionstore/localfile/store.go)把每次输入、每轮推理、每个工具调用状态、每个操作进度全部追加写入.session.jsonl文件;收件箱(harness/inbox/inbox.go)为每个外部/控制/崩溃输入分配全局唯一 ID 并做会话级去重,保证重放不会产生重复效果。崩溃后恢复会话,等于把这些追加式记录重新灌回内存——append-only 账本天然适合崩溃恢复。会话还支持分叉(fork):从历史某个 turn 长出平行分支,这在 Agent 调试、A/B 策略试验里是杀手级能力。

这些能力在 Python/TS 生态并非不存在,但要拼装齐整——事件溯源、幂等收件箱、actor 运行时、版本化序列化格式——往往是"理论上可以,实际上没人拼"。Unreal Agent 用 Go 把它拼成了完整骨架,这本身就是对"Go 不适合 Agent"最有力的反驳。

技术栈之争对普通开发者的实际影响

这场争论如果只停留在"语言优越性"的嘴仗,就没有写这篇文章的必要。真正值得关注的是它对三类普通开发者的实际意义。

对 Python/TS 生态的开发者:争论的结论不是"必须学 Go",而是"Agent 框架正在分层"。Python/TS 依旧统治提示词工程、评估工具、数据管线与快速原型;但一旦 Agent 需要以服务形态长期运行、需要扛并发与恢复,Go(以及 Rust)写的运行时将越来越多地成为"基础设施层"的选择。你可以继续用 Python 做 Agent 的应用逻辑,但理解 async-first 的心智模型——操作可持久化、输入可幂等、工具执行与模型推理解耦——会成为新的通用技能。

对 Go 开发者:这是技术栈的一次复利兑现。Agent 框架的运行时需求——高并发事件循环、channel 编排、静态类型约束的接口抽象、单二进制交付、低依赖审计——几乎每一项都是 Go 的主场。Unreal Agent 的架构(README.md 中列出的八大组件:收件箱、协调器、会话存储、上下文构建器、LLM 适配器、工具注册表、工具翻译器、操作管理器)展示了一条清晰的路径:用 Go 的并发原语承载 Agent 的异步本质。如果你的团队有 Go 基础,现在评估 Agent 框架时,语言不再是"跟着模型生态走"的单选题。

对技术选型决策者:最直接的信号来自成本模型。异步优先 + prompt cache 友好 + 崩溃恢复,这三个特性组合在一起,直接回应了 Agent 落地的两大痛点:token 账单失控与长任务不稳定。社区对"Async-First 到底省多少"的讨论还在发酵,Unreal Agent 的 Harbor 适配器(benchmarks/harbor)给出了可复现的评测路径——轨迹导出为 ATIF-v1.7 格式、按 prompt/completion/cached 分项统计 token。这意味着"省 40% 还是省 20%"不再是一句营销话术,而是一份可以自己跑出来的基准。

结语:异端与未来的边界,由工程问题划出

回到标题的问题:Go 写 Agent 框架是异端还是未来?诚实的答案是:它既不是异端,也不必然是未来,而是 Agent 工程成熟化的必然产物。当 Agent 还停留在"提示词编排"阶段,Python/TS 的优势无可撼动;当 Agent 开始承担生产级任务——并发工具执行、崩溃恢复、成本控制、沙箱隔离——它就不再是脚本,而是一个分布式运行时,而这恰好落在 Go 的优势区间。

Unreal Agent 的价值不在于证明 Go 优于 Python,而在于把"Agent 框架可以用 Go 写,而且可以写得很扎实"变成了一个可验证的事实:并发原语直接映射异步语义,操作与工具分离换来可恢复性,单一二进制换来部署自由度。技术栈之争的终局,从来不是语言之战,而是工程问题之战——谁先把 Agent 从 demo 变成可靠、省钱的运行时,谁就定义了下一个时代。在这场争夺里,Go 显然已经拿到了入场券。

【免费下载链接】unreal-agentAsync-first agent harness项目地址: https://gitcode.com/gh_mirrors/un/unreal-agent

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/11 13:20:03

影刀RPA新手教程:调试三板斧——日志、断点与单步执行

影刀RPA新手教程&#xff1a;调试三板斧——日志、断点与单步执行 流程跑一半报错&#xff0c;日志里只有一行看不懂的英文&#xff0c;你盯着几十条指令不知道从哪查起——这是每个影刀RPA新手都会卡住的地方。我自己也是非技术出身&#xff0c;第一年做采集流程时&#xff0c…

作者头像 李华
网站建设 2026/10/11 13:18:11

多关键字排序实战:从奖学金题学透排序规则与自定义比较函数

某天我在一个在线题库里整理题单的时候&#xff0c;又看到了这道编号1106的老朋友——《奖学金》。说它是"老朋友"&#xff0c;是因为这类多关键字排序的题目在信息学竞赛入门阶段太常见了&#xff0c;几乎每本教材、每个模拟赛里都会换着花样出现一次。第一次见到它…

作者头像 李华
网站建设 2026/10/11 13:16:32

Atomic Chat硬件配置清单:8GB到32GB内存如何选对本地大模型

【免费下载链接】Atomic-Chat Local AI app and inference engine for agents. Run open-weight LLMs locally — private, 100% offline on your computer. Join our Discord: https://discord.com/invite/8wGSsvmg4V 项目地址&#xff1a; https://gitcode.com/gh_mirrors/at…

作者头像 李华
网站建设 2026/10/11 13:16:17

无重复字符最长子串:滑动窗口与哈希表优化全解析

1. 题目解读&#xff1a;无重复、连续、一刀切&#xff0c;哪个才是命门LeetCode Hot100 刷到第 7 题&#xff0c;撞上的是原题第 3 题“无重复字符的最长子串”。这题在 Hot100 里的地位不用多说&#xff0c;属于那种“面试官闭着眼睛也能从题库里点出来”的常客。题目很短&am…

作者头像 李华
网站建设 2026/10/11 13:15:29

Ghostty Blackhole参数完整清单:30+个可调常量逐个详解

【免费下载链接】ghostty-blackhole Ghostty Blackhole puts a real, ray-traced black hole inside your terminal. It grows as Claude Codes context window fills up, live. A fresh session is a quiet hole in the corner. A full one swallows half your screen. Youll …

作者头像 李华