Skip to content
kefan.life
Go back

Agent架构重构的心路历程:从造轮子到选轮子

Edit page

最近在做一个 Agent 应用,起初的想法很朴素:选一个轻量框架打底,自己补充几个关键能力就行,不想引入太重的依赖。这个出发点听起来很合理——“保持简单”。但几周之后,我发现自己正在从零构建一个完整的 Agent Loop。

message填充、工具注册、自动重试、日志审计,一直到上下文压缩、权限控制、多任务管理……每一块功能单独看都不算复杂,但组合起来,整个 runtime 层已经膨胀到和项目核心逻辑差不多的体量。而且更糟糕的是,这些代码对应用场景本身没有任何增值。

这时候我开始认真问自己一个问题:为什么不用现成的?

“保持简单”为什么会走向反面?

回头看,“保持简单”这个出发点其实藏着几个没说清楚的假设:

第一个假设是:轻量框架=更少的学习成本。但实际上,框架的复杂度有两种——一种是显性的(文档、概念、API),一种是隐性的(为了业务,你必须自己补的那些坑)。pi-agent-core 确实 API 简洁,但它只提供了最底层的 primitives:tool 执行、事件流、基础的 transformContext。要用它搭一个能长期运行的 daemon,你还得自己处理 session 生命周期、消息累积、上下文压缩、重试策略、审计日志……这些隐性的复杂度,最终都变成了代码。

第二个假设是:自己写=更可控。理论上确实如此,但可控是有代价的。你拥有每一行代码的同时,也拥有每一行代码的责任。当 Agent Loop 的代码量和业务逻辑持平,这个新造的轮子也有维护成本。

第三个假设是:成熟框架=过度设计。这个直觉在很多时候是对的,但这一次不完全成立。成熟的 Agent Runtime 确实带着更多 opinionated 的东西,但这些 opinion 往往来自大量实战踩坑。比如 compaction 策略——我自己写的时候,第一反应是”旧消息offload”,但跑了几天才发现,粗暴截断会丢掉关键上下文,导致后续决策偏离。成熟框架里的 compaction 可能带着更细腻的策略:渐进式摘要、关键节点保留、结构化 offload。这些不是我拍脑袋能想到的。

于是”保持简单”走到某个临界点,就变成了”重新发明轮子”。

换路之前,先搞清楚自己到底需要什么

我一开始的判断是:既然要换,就换一个”更成熟”的。但”成熟”这个词太笼统了。

真正的问题是:我的 agent 应用究竟需要什么样的 runtime?

我想要的其实是一个任务无关的 Agent Loop——它负责那些通用的基础设施工作:API 调用、协议适配、message填充、上下文压缩、工具执行、权限控制、重试策略。而业务逻辑——prompt、自定义工具、流程编排(orchestration)——则应该由我自己来写。

我看了两个候选方案:pi-coding-agent 和 OpenCode。

pi-coding-agent 是同一作者在 pi-agent-core 基础上搭的Coding Agent。它确实比 pi-agent-core 更完整:有了 session 管理、compaction、extensions。但它的 README 明确写着”minimal terminal coding harness”,目标是提供一个可扩展的编码助手骨架,而不是一个通用的 agent runtime,但也提供SYSTEM.md以覆盖系统提示此。因此默认场景是coding也没问题,稍加改造就能变成另一种Agent,但是官方明确不支持subagent,因此多Agent管理很弱。

不过真正击碎我的,是pi不支持video。我的Agent要理解视频内容,且需要作为 multimodal input 传给模型。但是pi的消息类型只有 TextContentImageContent。没有 VideoContent。如果真的遇到了视频文件,pi会把视频降级成文本URL(Media URL: https://…) 贴在message里,模型根本看不到真正的内容。这个缺陷对我而言没有商量的余地。只能选择抛弃pi。

OpenCode 则是另一个方向。它是一个完整的 agent 平台:server/session 架构、权限系统、subagent 支持、LSP/MCP 集成。这听起来像是”过度设计”,但仔细看它的温度,发现它反而是那个更符合”任务无关 loop”预期的选项:

这两种方案的差异,不是”轻 vs 重”,而是”coding-oriented vs platform”。而我需要的,恰恰是后者——一个足够通用、足够可配置的 runtime,让我的业务逻辑能干净地建设起来。

Agent VS Agent Loop

“做 Agent 应用”和“写 Agent Loop”,我曾以为是一件事,其实大相径庭。

yage 在 OpenClaw 是什么|AI Agent 聊天工具的原理、价值与局限里的核心洞察是区分 Agentic LoopAgentic Architecture:Loop 是基础设施劳动,应该外包给成熟的 Runtime;Architecture 才是业务增值的地方,才值得自己设计。并且推荐了 OpenCode 在这种架构下的先进之处。

这篇文章帮我厘清了一个关键认知:对于做Agent应用而言,要不要写Agent Loop并不是一个选择题。值得淘金的仍然是业务场景,不是Agent Loop作为基础设施本身,它只是让 Agent 能运行;真正的价值在 prompt 设计、工具定义、orchestration——这些才是 Agentic Architecture。

所以这次迁移不是”把控制权交出去”,而是”把体力劳动外包出去”,让 OpenCode 承担主要的维护成本。

总而言之,殊途同归。我的架构选择也是 OpenCode。鸭哥牛逼!

迁移本身不是终点

迁移完成之后,代码确实变干净了。原来散落在各处的 runtime 逻辑都收敛到了 OpenCode 的调用。业务层只剩下 prompt 定义、工具实现、调度逻辑。

但这次迁移最大的收获,反而是让我看清了一个问题:

Agent Loop 的成熟度,和 Agent 应用的成熟度,不是同一件事。

换一个更成熟的 runtime,不代表你的 Agent 就变得更智能了。它只是替你省掉了那些本来就不该由你承担的基础设施劳动。真正让 agent 好用的,仍然是那些 architecture 层的东西:prompt 是否清晰、工具是否恰当、上下文是否足够、决策流程是否合理。

换句话说,这次迁移删掉的是体力代码,不是业务思考。删掉了多余的,注意力才能回归应用本身。

最后一点感想

这次折腾让我对”保持简单”这个词有了新的警惕。

很多时候,“保持简单”说出口的时候,背后其实藏着一套没说清楚的假设:轻量等于低负担、自己写等于高可控、成熟框架等于过度设计。这些假设在某些场景里是对的,但在另一些场景里则会变成陷阱。

真正的简单,不是”从零开始”,而是”让每一层只承担它该承担的事”。Agent Loop 该做的,是 Loop;Agent Architecture 该做的,是 Architecture。把 Loop 交给成熟的框架,把业务留给自己,这才是我觉得更干净的分工。


Edit page
Share this post on:

Next Post
给仓库装上记忆:当人不再拥有全部上下文