首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >构建可靠 LLM 应用的十二要素:Agent 的本质仍是软件,上下文才是一切

构建可靠 LLM 应用的十二要素:Agent 的本质仍是软件,上下文才是一切

作者头像
不二小段
发布2026-04-09 16:19:12
发布2026-04-09 16:19:12
840
举报
文章被收录于专栏:不二小段不二小段

当整个科技圈都在为 AI Agent 的巨大潜力而疯狂时,一场深刻的「反思」也正在悄然发生。

我们似乎都听过这样的故事:一个充满激情的团队,用 LangChain 或 CrewAI 等框架,几天之内就搭起了一个看起来足够酷炫的 Agent demo,让 CEO 兴奋不已,当场拍板追加六个人力。

但然后呢?

然后,团队就会一头撞上那堵臭名昭著的「80% 质量墙」。无论如何优化 prompt,无论如何调试,Agent 的可靠性始终在 70%-80% 之间徘徊,无法真正交付给付费客户。

为了突破最后这 20%,开发者不得不深入框架源码,在层层叠叠的调用栈中迷失方向,试图搞清楚一个 prompt 究竟是如何被构建的,工具又是如何被传入的。

最终,许多人的选择是:推倒重来,从头手写。

我惊讶地发现,市面上那些自诩为『AI Agent』的产品,其『智能』程度远没有想象中那么高。

说出此话的,是 Dex Horthy,HumanLayer 的创始人,也是一位资深的 Agent 构建者。

他试用了市面上几乎所有的 Agent 框架,与上百位一线 AI 创业者和工程师深入交流后,得出了一个颠覆性的结论:

真正优秀的、能进入生产环境的 Agent,其本质大多是确定性的代码,只是在关键节点巧妙地「撒」上了一些 LLM 调用。它们遵循的根本不是「给你 prompt、给你工具包、循环执行直到达成目标」的范式,而更像是……普通的软件。

这场关于 Agent 的集体狂热,是否让我们走错了方向?我们究竟该如何构建真正可靠、可扩展、可维护的 LLM 应用?

为了回答这个问题,Dex Horthy 借鉴了云计算时代里程碑式的「12-Factor App」方法论,整理并提出了 「12-Factor Agents」——构建可靠 LLM 应用的 12 条核心原则

这不仅仅是一份技术文档,更像是一份「反思宣言」,也是写给所有 Agent 框架的「功能许愿单」。它试图将我们从对 Agent 的神化想象中拉回地面,重新用软件工程的第一性原理,审视 LLM 应用的构建之道。

接下来,就让我们深入这 12 条原则,看看它们将如何重塑我们对 AI Agent 的认知。


核心论点:Agent 是软件,不是魔法

在展开 12 要素之前,我们必须先理解 Dex 的核心思想,它贯穿了整个方法论:

  1. 1. LLM 是一个纯函数 (Pure Function):它的本质是「Tokens in, Tokens out」。你输入一串 tokens,它输出另一串 tokens。模型的可靠性,几乎完全取决于你输入 tokens 的质量。因此,上下文工程 (Context Engineering) 就是一切
  2. 2. Agent 是软件 (Agents are Software):忘掉那些关于「拥有自主意识的异星智能体」的幻想。构建 Agent,就是构建软件。if 语句、switch 判断、while 循环……这些你早已烂熟于心的编程原语,正是构建可靠 Agent 的基石。
  3. 3. 夺回控制权 (Own Your Control Flow):不要轻易将应用的核心控制流外包给一个黑箱。你必须完全掌控状态、循环和分支,这会赋予你应对复杂现实所需的灵活性。

这三大思想,构成了「12 要素」的基石。它们呼吁开发者,不要再将希望寄托于一个越来越聪明的「超级大脑」,而是要回归软件工程的本质,用确定性的方法论,驾驭 LLM 的不确定性。


第一部分:解构 Agent 的「魔法」外衣

许多人对 Agent 的着迷,源于其看似神奇的自主决策能力。但 Dex 认为,我们首先需要戳破这层「魔法」滤镜。

要素 1:自然语言到工具调用

LLM 最神奇的能力是什么?不是循环,不是推理,甚至不是代码生成。

而是将一句像「给我的团队 Slack 发个消息,说前端部署好了」这样的自然语言,精确地转化为一段像下面这样的 JSON 代码:

代码语言:javascript
复制
{
"tool":"slack.postMessage",
"parameters":{
"channel":"#devops",
"text":"Frontend deployment successful!"
}
}

这就是 LLM 在 Agent 系统中最核心、最不可替代的价值。它是一个通用的、非结构化到结构化的数据转换器。至于拿到这个 JSON 之后做什么,那是其他要素需要解决的问题。但只要你的应用中包含了这一步,你就已经抓住了 Agent 的精髓。

要素 4:工具只是结构化输出

有了上面的认知,我们就能得出一个有些「离经叛道」的结论:「工具调用 (Tool Use)」这个概念是有害的

Dex 在这里引用了计算机科学史上著名的论文《Go To 语句被认为是有害的》。当年,goto 语句因为会破坏代码结构,导致程序逻辑混乱而备受诟病。

今天,「工具调用」这个术语也给我们带来了类似的困扰。它让我们误以为,Agent 是一个「有意识的实体」在与「环境」进行「交互」。

但实际上发生了什么?LLM 输出了 JSON,我们用确定性的代码 (比如一个 switch 语句) 去解析这个 JSON,然后执行相应的函数。

代码语言:javascript
复制
# 这不是魔法,这只是代码
tool_call = llm.output_json()

switch tool_call.name:
case"slack.postMessage":
        slack_client.post_message(...)
case"github.create_pr":
        github_client.create_pr(...)
    default:
        handle_unknown_tool()

所以,不要再把工具看作什么神秘的东西。它就是 JSON 和代码。这个视角的转变,是夺回控制权的第一步。

要素 8:掌控你自己的控制流

这是整个方法论中最核心、最具颠覆性的要素之一。

Agent 框架最初的承诺是什么?是让你扔掉有向无环图 (DAG)。你不再需要像使用 Airflow 或 Prefect 那样,预先定义好工作流的每一步和每一个分支。你只需给 LLM 一个目标和一堆工具,它就能自己规划路径。

这种模式通常被实现为一个简单的循环:

代码语言:javascript
复制
context = [initial_event]
whileTrue:
    next_step = llm.determine_next_step(context)
if is_done(next_step):
break
    result = execute_step(next_step)
    context.append(result)

这个看似美好的模型,在现实中却根本行不通

主要原因是,随着循环次数增加,上下文窗口 (Context Window) 会变得越来越长、越来越臃肿。即使是 Gemini 1.5 Pro 这样拥有百万级 Token 窗口的模型,当上下文变得混乱时,其输出质量也会急剧下降。没有人会否认,一个精简、清晰的上下文,永远比一个庞大、嘈杂的上下文更能产出高质量的结果

那么,什么才是有效的模式?

答案是:回归 DAG,但让 LLM 成为其中的「超级节点」

这个理念的最佳实践,就是 Dex 在 HumanLayer 内部构建的 DevOps 机器人。

案例研究:HumanLayer 的部署机器人

HumanLayer 的大部分部署流程是确定性的 CI/CD 代码

  1. 1. 当一个 GitHub PR 被合并,并且在开发环境上通过了所有测试后,流程暂停。
  2. 2. 此时,一个微型 Agent 被激活。它调用 LLM,问道:「接下来该怎么部署?」
  3. 3. LLM 可能会提议:「好的,我将先部署前端。」这个提议(一个 JSON 对象)被发送到团队的 Slack 频道。
  4. 4. 团队成员可以直接在 Slack 中回复:「不,先部署后端。」
  5. 5. 这个自然语言的反馈,被 Agent 转化为一个新的 JSON 指令,后端服务被部署。
  6. 6. 部署成功后,Agent 知道自己还有一个任务没完成(部署前端),于是继续执行。
  7. 7. 当前后都成功部署后,Agent 的生命周期结束,控制权交还给确定性的 CI/CD 流程,开始运行生产环境的端到端测试。

看到了吗?整个流程是一个巨大的、由工程师编写的、确定性的 DAG。而 Agent 只是其中一个小小的、专注的、生命周期很短的循环。它只负责一件事:在需要灵活决策的节点,将自然语言转化为结构化的下一步指令。

这就是「掌控你的控制流」的真谛。你拥有一个宏观的、可靠的软件架构,然后在这个架构中,策略性地嵌入一些小而美的 Agent 循环,来实现「人机协同」或「动态决策」的魔法。


第二部分:上下文工程的艺术

如果说 LLM 是一个函数,那么上下文就是它的唯一参数。如何精心雕琢这个参数,决定了应用的成败。

要素 2:掌控你的提示词

Prompt 框架和库非常适合快速入门,它们能帮你生成一个不错的基准 prompt。

但如果你想突破 80% 的质量瓶颈,你最终会需要逐字逐句地手写每一个 token。因为只有你,才最了解你的业务逻辑、你的数据结构和你的目标。

你需要能够自由地测试不同的 prompt 结构、不同的措辞、不同的示例,找到那个能让模型性能最大化的「天选之 prompt」。不要让框架的抽象,成为你优化性能的阻碍。

要素 3:掌控你的上下文窗口构建)

这比掌控 prompt 更进了一步。你不仅要控制 prompt 的内容,还要控制整个上下文的构建方式

标准的 OpenAI 消息格式 ([{role: "system", ...}, {role: "user", ...}]) 是一种选择,但绝不是唯一选择。

在决定下一步时,你真的需要把之前所有的对话历史、工具调用结果、错误信息原封不动地塞进去吗?

或许,你可以把所有历史信息压缩成一段摘要。或许,你可以用一种自定义的、更紧凑的格式来表示事件流。

例如,一个自定义的事件流可能长这样:

代码语言:javascript
复制
EVENT: user_message | "Book a flight to SF"
TOOL_CALL: search_flights | {"destination": "SFO"}
TOOL_ERROR: api_timeout | "Flight search timed out"
TOOL_CALL: search_flights | {"destination": "SFO", "retry": 1}
TOOL_RESULT: flights_found | [{"flight": "UA123", ...}]

这里的关键是,你有能力尝试任何一种你认为最高效的上下文表示方法。你的目标是,在传递给 LLM 的信息密度和清晰度上,做到极致的优化。

要素 9:将错误压缩进上下文

当 Agent 调用工具出错时(比如 API 超时、参数错误),一个常见的做法是把错误信息和堆栈跟踪 (stack trace) 直接追加到上下文中,然后让 Agent 重试。

这很容易导致 Agent 陷入「死亡循环」,不断重复同样的错误,或者被无用的错误信息干扰,丢失了原始的目标。

一个更可靠的策略是:智能地处理错误

  • 压缩信息:不要把整个 stack trace 丢给模型,而是提取出关键的错误信息,比如「Invalid parameter: destination_city」。
  • 清理上下文:当一次重试成功后,应该将之前相关的错误记录从上下文中移除总结,避免它们干扰后续的决策。
  • 拥有重试逻辑:不要让 LLM 来决定是否重试。重试逻辑应该由你的确定性代码来控制 (比如,最多重试 3 次)。

记住,上下文窗口是你最宝贵的资源,不要用垃圾信息污染它。


第三部分:面向未来的可靠架构

好的 Agent,首先必须是好的软件。这意味着它需要遵循现代软件架构的最佳实践。

要素 10:小而专注的 Agent

正如前面 HumanLayer 的例子所示,微型 Agent 的模式远比一个大而全的单体 Agent (Monolithic Agent) 要可靠得多。

将复杂的任务分解成一个由确定性代码粘合的、多个微型 Agent 组成的 DAG。每个 Agent 只有单一、明确的职责,上下文窗口保持短小精悍,从而实现极高的可靠性。

Google NotebookLM 团队的一位成员曾分享过一个观点,Dex 对此深表赞同:

在 AI 领域创造卓越体验的唯一途径,就是找到一件恰好处于模型能力边界、它无法 100% 搞定的事情,然后通过你的工程能力,让它变得 100% 可靠。

微型 Agent 架构,正是实现这一目标的完美路径。

要素 5 & 6:统一状态管理,提供标准 API

Agent 的运行也需要状态管理。比如 current_stepretry_count执行状态,以及 messagesuser_data业务状态。一个常见的错误,是把这两者割裂开来。

正确的做法是,将它们统一管理,并将 Agent 的整个状态(包括上下文窗口)序列化后存入数据库 (如 Redis, Postgres)。

这带来了下一个顺理成章的好处:你可以为你的 Agent 提供标准的启动/暂停/恢复 (Launch/Pause/Resume) API

想象一下这个流程:

  1. 1. 一个 HTTP 请求进来,启动 Agent。
  2. 2. Agent 开始运行,加载状态,调用 LLM。
  3. 3. Agent 决定调用一个需要人类审批的长时间运行工具 (long-running tool)。
  4. 4. 此时,Agent 将自己的完整状态存入数据库,并返回一个 state_id。整个执行流程被暂停
  5. 5. 几天后,当人类审批完成,一个回调请求带着 state_id 和审批结果被发送回来。
  6. 6. 系统根据 state_id 从数据库中加载 Agent 的状态,将审批结果追加到上下文中,然后无缝恢复 Agent 的执行。

对于 LLM 来说,它甚至不知道自己中间被「冷冻」了几天。

这就是将 Agent 视作普通软件的威力。你可以用所有熟悉的工具和模式来管理它。

要素 12:让你的 Agent 成为一个无状态的 Reducer

这个要素是对上述思想的总结。Agent 本身应该是无状态的。它就像一个 Redux 中的 reducer 函数:(state, event) => newState

它接收当前的状态和新的事件(比如一个工具调用的结果),然后决定下一步的动作,并产生一个新的状态。而状态的持久化和管理,则由外部的、确定性的应用逻辑来负责。


第四部分:与人共存,无处不在

最后,可靠的 Agent 必须能够无缝地融入人类的工作流和沟通渠道。

要素 7:用工具调用来联系人类

许多 Agent 框架在输出时,会让 LLM 在「调用工具」和「回复用户」之间二选一。这其实是一个糟糕的设计。

一个更优雅的模式是:将「联系人类」也视为一种工具调用

代码语言:javascript
复制
{
"tool":"contact_human",
"parameters":{
"message":"I need clarification on the budget.",
"reason":"clarification_needed"
}
}

这样做有两大好处:

  1. 1. 意图更明确:你可以定义不同类型的「人类联系」,比如 ask_for_clarification, request_approval, escalate_to_manager。这让后续的确定性逻辑处理起来更容易。
  2. 2. 提升模型性能:让模型专注于生成结构化的工具调用 JSON,通常比让它在工具调用和自由文本回复之间做决策,更容易获得稳定和高质量的输出。

要素 11:从任何地方触发,在任何地方与用户相遇

用户不想为了和你的 Agent 交互,而打开第七个聊天窗口。

可靠的 LLM 应用应该能与用户现有的工具无缝集成。让用户可以通过 Email, Slack, Discord, SMS 等任何他们熟悉的渠道来与 Agent 互动。这意味着你的 Agent 需要被设计成可以从各种事件源(Webhook, Cron Job, 消息队列)触发,并将结果返回到相应的渠道。


结论:从「框架」到「脚手架」,夺回 AI 开发的主导权

通篇读下来,你可能会觉得这是一篇「反框架」的檄文。

但 Dex 强调,他的本意并非抨击框架,而是希望我们能共同思考:我们真正需要什么样的工具?

「十二要素 Agent 方法论」并未提供任何银弹,它更像是一次「正本清源」的呼吁。

他认为,目前许多 Agent 框架更像是 Bootstrap:一个大而全的包裹,为你隐藏了内部细节,但也限制了你的自由度。

而我们真正需要的,可能更像是 shadcn/ui:它不是一个组件库,而是一个脚手架 (Scaffolding)。你用它一键生成代码,然后这些代码就完全属于你了,你可以任意修改和掌控。

许多工具试图将问题中困难的 AI 部分抽离出去,让你即插即用。我认为这应该是反过来的。好的工具,应该将其他困难的部分(如状态管理、API 接口、可观测性)抽离出去,从而让我们能将所有时间,都花在真正困难的 AI 部分上:打磨 prompts,优化控制流,雕琢每一个 token。

「12-Factor Agents」的发布,或许标志着 AI 应用开发领域一个重要转折点的到来。它宣告了「黑箱式」Agent 构建范式的局限性,并吹响了「回归软件工程」的号角。

正如一位 Hacker News 用户评论道:

在职业发展上,学习底层的 LLM 接口,远比依赖某个框架要明智得多。一旦你掌握了底层,切换到任何平台都轻而易举,但反过来则充满挑战。尤其是在 AI 领域,没人知道明年的最佳实践会是什么样。所以,花时间学习底层,而不是把自己绑在一个一年后可能就过时的框架上。

或许,我们离真正可靠的 LLM 应用,差的不是一个更聪明的模型,而是一套更成熟、更回归本质的工程方法论。

或许,当 AI 的浪潮将我们推向一个又一个技术奇点时,我们最需要的,恰恰是回头看看那些早已被验证过的、最朴素的工程原则。

毕竟,无论外面的世界如何变化,工程师的本分,始终是构建可靠、可信的系统。


参考资料:

  • • 12-Factor Agents GitHub Repository: https://github.com/humanlayer/12-factor-agents
  • • Hacker News Discussion: https://news.ycombinator.com/item?id=43699271
  • • 12-Factor Agents: Patterns of reliable LLM applications — Dex Horthy, HumanLayer https://www.youtube.com/watch?v=8kMaTybvDUw
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 核心论点:Agent 是软件,不是魔法
  • 第一部分:解构 Agent 的「魔法」外衣
  • 第二部分:上下文工程的艺术
  • 第三部分:面向未来的可靠架构
  • 第四部分:与人共存,无处不在
  • 结论:从「框架」到「脚手架」,夺回 AI 开发的主导权
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档