12-Factor Agents: Patterns of reliable LLM applications
Jul 3, 2025, 视频: 12-Factor Agents: Patterns of reliable LLM applications — Dex Horthy, HumanLayer (YouTube)
开场与动机
- 询问现场有多少人做过代理(10 个、100 个)的举手互动,铺垫“大家都在做 agents”的共同经历。
- 个人经历:最初决定做一个 agent,确定目标后为了快,用各种库堆起来,很快做到 70–80% 质量,足以让 CEO 兴奋、团队扩编。
- 碰壁:想从 70–80% 冲到更高质量时,发现深陷库的调用栈里,难以追踪 prompt 如何构造、工具如何注入,只能推倒重来;有时还会发现“这根本不是适合 agent 的问题”。
反思案例:DevOps Agent 失败教训
- 尝试做 DevOps agent:让它读 makefile、执行构建命令。
- 不断加细 prompt,甚至细到“准确的步骤顺序”,最终意识到:这类任务 90 秒写个 bash 脚本就能搞定——并非所有问题都需要 agent。
田野调研与模式洞察
- 访谈 100+ 位创始人/工程师,总结出行业里的共性做法。
- 结论 1:大多数“生产级 agent”其实并不“agentic”,更像普通软件。
- 结论 2:大家并非重写一切,而是在现有系统里引入一组没有名字、没有定义但行之有效的小型模块化概念。
- 这些都是“软件工程基本功”,不需要 AI 背景就能运用。
“12-Factor Agents” 背景与定位
- 基于一线实践整理出“AI agents 的 12 个因子”,并开源成文档与代码库,得到社区热烈反馈(快速涨星、多人贡献)。
- 不是“反框架演讲”,更像是对框架的“需求清单”:让框架更好地服务追求高可靠与高迭代速度的工程师。
核心目标与方法
- 邀请大家“抛开成见”,从一线软件工程原则出发,重新思考如何打造“真正可靠”的 agents。
- 本演讲不按编号逐一讲 12 因子,而是打包串讲若干关键主题;详细内容可会后自查。
因子一(本质魔法):句子 → JSON
- LLM 最神奇的能力与代码/循环/工具无关,而是把自然语言稳健地结构化成 JSON。
- 后续因子解决“拿到 JSON 之后怎么用”的问题,但“稳定产出 JSON”本身即可立刻融入现有应用。
因子四(观点):将“工具使用”去神秘化
- 类比“goto 有害”的历史争论,提出“工具使用有害(的抽象)”——不是说不给 agent 外部能力,而是反对把工具想象成“灵体操控环境”的神秘过程。
- 现实是:LLM 输出 JSON → 交给确定性代码执行 →(可回灌)。这不过是“JSON + 普通代码 + 循环/分支”,没什么神秘。
因子八(打包主题):掌控你的控制流
回顾软件中的 DAG 思维(if/else 也是图),Airflow/Prefect 等把流程拆成节点以换取可靠性。
“朴素 agent 循环”抽象:事件 → prompt → 产生“下一步动作” → 执行 → 把结果放回上下文 → 再喂给模型,直到“完成”。
问题:对长流程不可靠,尤其是超长上下文;即便 API 支持超大上下文,受控、精简的上下文常常更可靠。
将 agent 拆解为 4 个可控部件:
- 选择下一步的 prompt(决策器)
- 把模型 JSON 结果交给确定性代码的 switch/loop 执行
- 构建传给模型的 上下文窗口
- 驱动整体的 循环与退出条件
当你“拥有控制流”后,可以灵活地 break/切换/汇总/引入评审(LM-as-judge) 等策略。
执行态与业务态的区分与管理
框架常见执行态字段:当前步骤、下一步、重试计数等。
业务态则是“对用户展示的数据、消息历史、等待的审批”等。
目标:像常规服务一样支持 启动/暂停/恢复。
实践建议:把 agent 暴露成 REST API 或 MCP 服务。
- 普通请求:加载对应上下文 → 喂给 LLM。
- 长时工具:能 中断 流程,将 上下文序列化入库(因为上下文本就归你管)。
- 回调到来:用 state_id 从数据库加载状态 → 把工具结果追加到“程序轨迹” → 再送回 LLM,agent 本身“无感”后台发生过什么。
结论:agents 只是软件;要构建高质量,就必须“拿下内环”(inner loop)的主导权。
因子二:拥有你的 Prompt(以及可试验性)
- 现成模版能快速打出“还不错”的提示词,但要越过质量门槛,迟早要 手写每一个关键 token。
- 观点:LLM 是“纯函数”(tokens in → tokens out),质量几乎完全取决于你喂进去的 tokens。
- 方法:多尝试、多旋钮、多评测,系统化探索。
上下文构建的主导权(Context Engineering)
- 不要被特定消息格式束缚:可把“到目前为止发生了什么”压成 一条 user 消息 或放进 system,自由地建模事件流/线程模型并序列化。
- 关键在 密度与清晰度:每个 token 都要物尽其用。
- 广义“上下文工程”= prompt + memory + RAG + 历史 等一切“喂给模型的东西”。
失败恢复与错误上下文处理
当模型调用了错误的工具或遇到下游 API 故障,不要“盲目把完整错误堆进上下文”让它重试。
实践:
- 当随后的工具调用成功,清理待处理的错误痕迹;
- 错误要 摘要化,避免把长堆栈污染上下文;
- 明确“告诉模型什么”才最有助于下一次成功。
与人协作:把“人与工具的分叉”前置到自然语言层
- 很多系统在最初输出就需要在“工具调用”与“回人类消息”之间选择。
- 将这个选择推到 自然语言首 token(例如“我完成了/我需要澄清/我需要经理介入”),模型更擅长在自然语言上表达意图,也更利于后续分流。
- 由此形成包含人类输入的轨迹与协议,也可扩展到 自动外环(auto outloop) 场景(此处不展开)。
触发与接入的无处不在
- 让用户 在他们所在之处 与 agent 交互:邮件、Slack、Discord、SMS 等,而不是逼用户开 N 个聊天页签。
小而聚焦的“微型 agents”
方案对比:巨大、长环路的 agent 往往不稳;经验有效的是 “确定性 DAG + 微小 agent 回合(3–10 步)”。
实际案例(HumanLayer 内部部署 bot):
- 绝大部分 CI/CD 为确定性代码;
- 当 PR 合入、开发环境测试过后,把“发布”阶段交给模型:它提议“先发前端”,人类可自然语言纠正“先发后端”,这会被结构化为下一步 JSON;
- 后端部署获批并完成后,agent 再回到前端部署;
- 成功后回到确定性流程执行端到端测试;如失败,交给“回滚 agent”。
规模宣称:100 个工具、20 个步骤 也能驾驭——因为上下文可控、职责清晰。
展望:从“撒点模型”到“全代理化”的渐进式演进
- 现状:在主要是确定性的系统里“撒”小块 LLM 能力;
- 随模型能力提升,LLM 可承接更大段落,直至某个 API/管线完全由 agent 驱动;
- 即便如此,工程可靠性 仍靠“上下文与控制流的精细工程”取胜。
- 经验法:寻找“模型刚好不太稳”的边界任务,通过工程化手段把它做稳,就能造出“超越同行的魔法”。
状态观:agent 应“无状态”,状态归你管
- 借由“reducer/transducer”梗强调:agent 自身应当 无状态,把状态外置,完全由你掌控。
抽象仍在演化:框架 vs 库
- 参考历史讨论:是追求抽象、还是允许一定重复?
- 方向感:与其套一层不透明封装,不如提供类似 shadcn 的 可脚手架、可完全自持 的“create 12-factor agent”风格起步方案。
总结要点
- Agents 是软件:会写 switch/while 的人都能上手。
- LLM 是无状态纯函数:关键是把“对的东西”塞进上下文,换取“稳的输出”。
- 掌控状态与控制流:为灵活性与可靠性买单。
- 在人机协作中取胜:让 agent 与人高效协作。
- 把难点留给自己:工具应替你挡住“非 AI 的繁琐”,让你专注于 prompt、流程与 token 质量这些“真正的 AI 难题”。
尾声与在做的事
- 演讲者经营一家小公司,多数工作与思考开源共享,但也在做一些“重要但无趣”的基础设施以减负。
- 正在推进 A2 协议,希望促成“agent 如何联系人的”行业收敛。
- 个人热爱自动化,已为找房、公司内部业务等做了大量 agents。
- 号召与致谢:欢迎会后交流,继续一起把东西造出来。
注:以下要点严格按视频叙述顺序梳理,时间段为近似区间,信息主要来源于视频原文;在涉及通用概念或案例时,附上外链以便核验与延伸。
[00:02–00:34] 开场与“造 Agent 的共同经历”
- 与会者互动:有多少人在做 agents?做过 10+ / 100+ 个的也有。
- 引出主题:很多团队把 agent 做到 70–80% 质量时就“卡住”了——CEO 被 demo 激动、团队扩编,但要继续提升就很痛苦。
[00:34–01:08] 框架/库导致的“黑箱”复杂度
- 遇到问题:为了追过 80% 质量线,你会在多层调用栈里“反向工程”prompt 与工具调用的来源与拼装方式,难以把控。
- 常见结局:推倒重来,或承认“这不是适合用 agent 的问题”。
[01:08–01:28] DevOps Agent 反例
- 尝试做“看懂 Makefile、能编译项目”的 DevOps agent,结果步骤全错。不断加 prompt 细节,最后基本变成“精确下发每一步”。
- 复盘结论:这类任务 90 秒写个 bash 脚本更靠谱——不是所有问题都需要 agent。
[01:28–02:07] 100+ 个一线 Builder 的访谈观察
- 生产中的“agent”大多并不很 agentic,本质更像普通软件,但存在一组有效且可复用的工程模式,显著提升 LLM 应用的可靠性。
[02:07–02:39] 渐进式引入而非重写
- 这些模式通常是小而清晰的模块化做法,能直接嵌入既有代码,不需要“从零起步的大重构”。
- 这不是“AI 专业背景”才能做的事,更多是软件工程基本功。
[02:22–03:26] 12-Factor Agents 由来与定位
- 参考 Heroku 的“12-Factor App”精神,整理出12 条构建可靠 LLM 应用的原则,开源合辑得到社区广泛响应(HN 置顶、stars 快速增长)。(12factor.net, humanlayer.dev, Hacker News)
- 不是“反框架宣言”,更像是框架功能愿望清单:让框架更好地服务对可靠性与迭代速度都有高要求的开发者。
[03:26–03:43] 方法论姿态
- 邀请大家“忘掉成见”,回到一原则:把软件工程中行之有效的做法用于打造“真正可靠”的 agents。
[03:43–04:23] 因子示例:Structured Output 是魔法起点
- LLM 的“魔法”与循环、switch、工具无关,而在于:把一句话稳稳变成结构化 JSON(随后再进入其他因子的处理)。
- 结构化输出/函数调用即此范式的工程化形态。(OpenAI Platform, OpenAI Cookbook, OpenAI Help Center, Anthropic)
[04:23–05:01] 因子4:Tool Use is “Harmful”(语义层面)
- 不是否定“让模型访问外部世界”的价值;而是指出“工具调用被神秘化”会遮蔽其本质:LLM 输出 JSON → 确定性代码执行 →(可选)结果回填。
- 因而可用普通的循环/分支来组织工具调用,不必神化“工具”。(“Considered harmful”用法源自 Dijkstra “GOTO 语句有害”文章标题的范式。)(Wikipedia, CWI Homepages)
[05:01–05:40] 拥有你的控制流:从 DAG 思维到 Agent Loop
- 代码本来就是图;DAG 编排(Airflow/Prefect 等)通过拆成节点获得可观测性与可靠性。(Apache Airflow, docs.prefect.io, prefect.io)
- 朴素 agent 循环:LLM 选下一步→执行→把结果并入上下文→继续,直到“完成”。
[05:40–06:18] 朴素循环的局限:长上下文 & 稳定性
- “把所有东西都塞进上下文”在长流程上常不奏效;控制上下文大小与密度通常更可靠。
[06:18–07:13] 把 Agent 分解为 4 个部件
- Prompt(选步骤)、Switch(把模型 JSON 交给确定性代码)、上下文构建、循环与退出条件。
- 当你拥有控制流时,就能插入 “break/summarize/LLM as judge”等策略。
[07:13–08:06] 执行态 vs 业务态,Pause/Resume 与可序列化
- 除了“当前步骤、重试计数”等执行态,还要管理业务态(过往消息、用户可见数据、待审批项)。
- 最佳实践:把 agent 作为标准 API(REST)或 MCP 服务器来封装;遇到长时工具调用时序列化上下文到数据库,回调携带 state id 继续执行,无缝恢复。(Model Context Protocol, Anthropic, The Verge)
[08:06–08:37] 核心宗旨
- Agents 本质是软件:为了灵活性与可靠性,务必自己掌控内循环。
[08:37–09:33] 因子2:拥有你的 Prompt(可测可调)
- 高质量门槛之后,最终会回到“逐 Token 手写/可组合/可评测”的 Prompt 工程。
- LLM 是“纯函数”:输入 Token → 输出 Token;可靠性的关键是“把对的 Token 放进去”。
[09:33–10:12] 拥有你的上下文构建
- 不局限于 OpenAI “messages”格式;可把事件/线程模型自由序列化成一段输入,精准告诉模型“到目前为止发生了什么”。
[10:12–10:55] 错误处理 ≠ 盲目堆栈
- 工具报错时,把“错误+调用”送回模型重试是常见做法,但易“旋涡失控”。
- 要掌控上下文:成功一次就清理历史错误、只保留浓缩后的关键信号,避免堆栈/日志污染上下文。
[10:55–11:34] 用“联系人的工具”把人纳入回路(HITL)
- 在**“工具调用 vs 与人交流”的第一拍**就做清晰区分;把“需要澄清/需要经理批准”等意图落在自然语言 token 上,提升决策的稳定性与可解释性。
- 对应工程化:在 Slack/Email/SMS 等触达渠道上引入审批/沟通。(humanlayer.dev, Y Combinator)
[11:34–12:25] 从任意地方触发,与用户“就地相逢”
- 让用户在现有工作流里(邮件、Slack、短信等)直接与 agent 交互,而不是开多个“Chat”标签。(humanlayer.dev)
[12:25–13:32] 小而专注的 Micro-agents(关键做法)
- 有效模式:主要流程保持确定性 DAG,把 3–10 步的小 agent loop 嵌入关键分支。
- 真实用例:HumanLayer 内部部署机器人——CI/CD 多数是确定性;合并通过后,交给模型“决定下一步部署前后端顺序”,人可插话修正,自然语义→下一步 JSON,随后再回到确定性流程(E2E 测试/回滚小 agent 等)。
[13:32–14:19] 随模型演进逐步“撒胡椒面”
- 随着模型可做的“可靠边界”扩大,可逐渐把更多步骤从确定性迁往 agent。
- 经验法:找“模型刚刚够得到但不稳定”的任务,通过工程化(上下文/控制流/评测)把它压到稳定边界内,形成差异化能力。
- 提到 NotebookLM 的做法,作为“在边界上做好工程化”的示意参考。(Google NotebookLM, blog.google, The Verge)
[14:19–15:01] 状态应由你来管:Agent 近似“无状态变换器”
- Agent 自身保持无状态,把状态外置并可观测/可持久化,你获得最大灵活度。
- 行业仍在找抽象;“框架 vs 库”的老话题仍适用。
[15:01–15:18] 脚手架理念:像 shadcn/ui 一样可接管
- 与其包一层黑盒,不如生成 scaffold 让开发者全盘接管(提到“create-12-factor-agent”的方向性想法)。
[15:18–16:11] 总结五点
- Agents 是软件;LLM 是无状态纯函数——把“对的上下文”放进去就有更可靠输出。
- 拥有状态与控制流,为灵活性与可靠性服务。
- 在“模型能力边界”处,通过工程化把不稳定变稳定。
- 人-机协作常使 agent 更强。
- 框架应帮忙解决“非 AI 的难点”,让开发者把精力聚焦在 prompt/流控/token 质量上。
[16:11–16:48] HumanLayer & A2(Agent-to-Human)方向与收尾
- 其公司专注“人与 agent 协作”的难题(审批、异步沟通、触达渠道)。提到在做 A2 协议来统一“agent 如何联系到人”的语义。相关理念与落地可参考其产品与文档。(humanlayer.dev, GitHub)
术语与案例延伸(外链)
- 12-Factor Agents 合辑(HumanLayer):原则清单与示例。(GitHub, humanlayer.dev)
- 12-Factor App(Heroku 原始方法论):本文方法论的精神来源。(12factor.net)
- “Considered Harmful”标题范式与 Dijkstra 1968 论文:理解“Tool use is harmful”表述的来历。(Wikipedia, CWI Homepages)
- DAG 编排参考(Airflow / Prefect):传统可观测、可恢复的工作流抽象。(Apache Airflow, docs.prefect.io)
- 结构化输出/函数调用(OpenAI / Anthropic / Azure 文档):LLM 输出 JSON → 你执行 → (可选)回填的工程范式。(OpenAI Platform, OpenAI Cookbook, Microsoft Learn, Anthropic)
- MCP(Model Context Protocol):将 agent 以“服务器/客户端”模式接入工具与数据的开放协议。(Model Context Protocol, Anthropic, The Verge)
- 长上下文的现实与边界(Gemini 1.5/2.x 2M tokens):官方宣介与开发者文档,印证“超长上下文并非银弹”的语境。(Google Developers Blog, Google AI for Developers, Google Cloud Storage)
- Human-in-the-Loop(HumanLayer 产品页/文档/YC 介绍):将“联系/审批/回执”变成可编排的工程能力。(humanlayer.dev, Y Combinator)