综合介绍
“12-Factor Agents” 不是一个具体的软件库或框架,而是一套用于构建可靠、可扩展且易于维护的LLM(大型语言模型)应用的设计原则。这个项目由开发者Dex发起,他发现许多团队在使用现有AI智能体框架开发面向客户的功能时,很容易达到70-80%的质量水平,但要突破这个瓶颈进入生产环境却异常困难。根本原因在于,许多高级框架隐藏了过多的底层控制,导致开发者在需要深度定制和优化时,不得不反向工程或从头开始。因此,该项目借鉴了经典软件开发方法论“12-Factor App”的思路,提出了12条核心原则。它旨在为软件工程师提供一个思想指南,让他们能将模块化的AI功能逐步、可靠地集成到现有产品中,而不是进行颠覆性的重写。其核心理念是:优秀的AI应用本质上依然是优秀的软件,其主要部分应由确定性的代码构成,而LLM的魔法则精确地应用在最需要的地方。
课程列表
- 序言:我们是如何走到这一步的:软件简史
- 原则一:自然语言到工具调用:将用户的自然语言输入,稳定地映射到一个或多个具体的工具(函数)调用上。
- 原则二:掌控你的提示词:将提示词视为应用核心代码的一部分进行版本控制和管理,而不是动态生成。
- 原则三:掌控你的上下文窗口:精确控制输入给LLM的上下文内容,将其作为实现可靠性的关键。
- 原则四:工具即结构化输出:将工具(Tools)视为一种强制LLM进行结构化输出的方式,而不仅是功能的集合。
- 原则五:统一执行状态与业务状态:将智能体的运行状态与应用的核心业务状态模型结合,实现状态的一致性。
- 原则六:通过简单的API启动/暂停/恢复:确保智能体的长时间任务可以被外部系统通过简单接口控制。
- 原则七:通过工具调用与人类交互:当智能体需要人类输入或审核时,应通过一个标准的工具调用来触发,而不是特殊处理。
- 原则八:掌控你的控制流:应用的核心业务逻辑和流程转换应由确定性代码主导,而非完全交给LLM决定。
- 原则九:将错误信息压缩到上下文窗口:当工具执行失败时,将其错误信息摘要后反馈给LLM,让其进行修正。
- 原则十:构建小而专注的智能体:倾向于组合多个小而精的智能体,而不是构建一个无所不能的庞大智能体。
- 原则十一:随处触发,随处交互:智能体应能从各种事件源(如API请求、数据库变更、定时任务)触发,并在用户所在的平台(如Slack、Email)进行交互。
- 原则十二:将智能体设计成一个无状态的Reducer:借鉴Redux思想,将智能体设计成一个纯函数,接收当前状态和事件,返回新状态。
使用帮助
“12-Factor Agents” 是一套思想和架构原则,它没有安装流程。它的“使用”指的是开发者在自己的项目中采纳并实践这些原则。下面将详细介绍如何在软件工程实践中应用这12条原则。
核心理念:AI应用首先是软件
在开始之前,最重要是理解其核心哲学:一个所谓“AI应用”或“AI智能体”,其绝大部分代码应该是传统的、确定性的软件工程代码。LLM调用只是其中的一环,被精确地用在需要进行自然语言理解、生成或决策的环节。开发者不应该将整个应用的控制权交给一个“请求-工具-循环”的黑盒,而应该将LLM看作一个可以调用的、具有特殊能力的函数。
各项原则的操作流程详解
原则一:自然语言到工具调用 (Natural Language to Tool Calls)
这是智能体与外界交互的入口。当收到用户输入(例如“帮我查下昨天北京的天气”)时,你需要一个可靠的机制将其转化为一个函数调用,如 search_weather(date="2025-07-21", city="北京")
。
- 操作方法:使用LLM的“函数调用”或“工具使用”功能。在发送给模型的请求中,你不仅要提供用户的输入,还要提供一份详细的、可供调用的工具(函数)列表及其参数的JSON Schema定义。模型会返回一个JSON对象,指明应该调用哪个函数以及传递什么参数。你的代码负责解析这个JSON并执行相应的函数。
原则二:掌控你的提示词 (Own your prompts)
不要在代码中动态生成复杂的提示词。这会使调试和迭代变得非常困难。
- 操作方法:将你的提示词(Prompts)当作静态配置文件(如
.txt
或.md
文件)来管理。在代码中加载这些提示词模板,并用变量填充它们。将这些提示词文件纳入Git等版本控制系统,就像管理main.py
或index.js
一样。这样,你可以跟踪提示词的每一次修改,并方便地进行测试和回滚。
原则三:掌控你的上下文窗口 (Own your context window)
上下文窗口是LLM唯一的“内存”。输入的质量直接决定输出的质量。不要不加选择地将所有历史消息都塞进去。
- 操作方法:实施一个精确的上下文构建策略。在每次调用LLM之前,你的代码应该根据当前任务需要,精心选择和组合信息。这可能包括:系统提示(system prompt)、最重要的几条历史消息、相关的文档片段(RAG的结果)、以及用户最新的问题。目标是为LLM提供解决当前问题所需的最少、最关键的信息。
原则四:工具即结构化输出 (Tools are just structured outputs)
虽然这些功能被称为“工具”,但从另一个角度看,它们是你强制LLM输出你想要的、格式规整的JSON的唯一可靠方法。
- 操作方法:当你需要LLM为你提取信息、分类或做任何需要确定性输出格式的任务时,就把它定义成一个“工具”。例如,你需要从一段文字中提取人名和公司,你可以定义一个
extract_entities(person: str, company: str)
的工具,LLM为了“调用”这个工具,就必须按此格式生成输出。
原则八:掌控你的控制流 (Own your control flow)
这是与许多自动化智能体框架背道而驰但至关重要的一点。应用的“下一步做什么”不应该完全由LLM在一个循环中决定。
- 操作方法:使用确定性的代码(如if/else, switch语句, 或状态机)来编写核心业务流程。例如,一个订单处理流程可能是:
接收订单 -> [LLM分类意图] -> if (查询) then call_query_api() else if (退货) then call_refund_api()
。在这里,LLM只负责“分类意tu”这一步,而整个流程是由你的代码控制的。这使得系统行为可预测、可调试。
原则十:小而专注的智能体 (Small, Focused Agents)
不要试图构建一个能处理所有事情的“超级智能体”。
- 操作方法:将复杂任务分解。例如,一个客户支持系统可以分解为:一个用于意图识别的智能体、一个用于查询知识库的智能体、一个用于处理订单的智能体。你的主控制流代码(原则八)负责在它们之间进行路由和调度。每个小智能体都有自己专注的提示词(原则二)和工具集(原则四)。
原则十二:将智能体设计成一个无状态的Reducer (Make your agent a stateless reducer)
这借鉴了前端框架(如Redux)的状态管理思想,能极大提升系统的可测试性和可预测性。
- 操作方法:将你的智能体或其中的一个步骤实现为一个纯函数,其签名类似于
(currentState, event) => newState
。currentState
是当前应用的所有状态。event
是刚刚发生的事件(比如用户的新消息或API的返回结果)。- 函数的返回值
newState
是更新后的状态。
这个函数本身是无状态的(不依赖任何外部变量),它所做的只是根据输入计算输出。这使得编写单元测试变得非常容易:你只需要提供不同的currentState
和event
组合,然后断言newState
是否符合预期。
通过遵循这些原则,你可以构建出行为更加稳定、调试更加容易、并且能够与现有软件系统和谐共存的LLM应用。
应用场景
- 为现有SaaS产品增加AI功能
对于一个已经拥有稳定业务逻辑的成熟SaaS产品(如CRM、项目管理工具),开发者希望在不重写核心代码的前提下,渐进式地引入AI功能。例如,使用原则一和原则八,将用户的自然语言指令(“创建下周一截止的任务,分配给张三”)转化为对现有API的调用,同时保持核心任务创建逻辑的稳定性。 - 开发面向最终用户的高质量AI助理
当开发一个直接与付费客户交互的AI助理时,可靠性和用户体验至关重要。直接使用通用框架可能会在处理复杂或边缘情况时出现不可预测的行为。通过应用这些原则,特别是原则三(掌控上下文)、原则八(掌控控制流)和原则九(压缩错误信息),可以确保助理在遇到问题时能优雅地处理,或者在需要时通过原则七(与人类交互)寻求帮助,而不是给出错误的答案或崩溃。 - 将AI原型产品化
许多团队使用高级框架快速构建出了一个效果惊艳的原型(Demo),但在准备将其作为正式产品发布时,发现原型在真实世界的复杂场景下表现不稳定(质量无法突破80%)。此时,”12-Factor Agents” 提供了一套“重构”指南。团队可以按照这些原则,用更健壮的软件工程实践来重新审视和改造原型代码,例如将模糊的控制流(loop-until-done)重构成明确的状态机(原则八),并将分散的提示词和状态管理进行统一(原则二和原则五)。
QA
- “12-Factor Agents”是一个可以安装的软件框架吗?
不是。它不是一个像LangChain或Griptape那样可以直接pip install
的软件包。它是一套设计理念和架构原则,旨在指导开发者如何更好地组织自己的代码和思考方式,来构建可靠的LLM应用。它是一份文档,一种方法论。 - 为什么要自己掌控控制流,而不是让LLM来决定?这不正是智能体的魅力所在吗?
这正是该方法论的核心观点之一。让LLM完全决定控制流(即“下一步做什么”)的魅力在于其灵活性和发现新路径的潜力。然而,在生产环境中,这种不确定性也带来了巨大的风险和调试困难。当应用出错时,你很难定位问题是出在LLM的决策上,还是工具的执行上。”12-Factor Agents” 主张将核心的、高风险的业务流程用确定性的代码(如状态机)来定义,而在流程的某些节点上,可以调用LLM来做出局部决策(如分类、提取信息等)。这样既利用了LLM的能力,又保证了系统的整体可预测性和稳定性。 - 这套原则是否意味着我完全不能使用现有的AI框架了?
并非如此。你完全可以在遵循这些原则的同时,使用现有框架。关键在于如何使用它们。你可以将框架看作一个提供便利工具的“库”,而不是一个控制你整个应用流程的“框架”。例如,你可以使用某个框架提供的工具调用解析功能,但自己来编写主控制流;或者使用它提供的RAG(检索增强生成)模块来填充上下文,但上下文的具体内容由你自己根据原则三来精确控制。重点在于保持对应用关键部分的掌控权,而不是将所有东西都外包给框架。 - 对于没有AI背景的传统软件工程师,这套原则是否容易上手?
非常容易,甚至可以说这套原则就是为优秀的软件工程师量身定做的。它的大部分内容(如版本控制、状态管理、模块化、确定性控制流)都是软件工程的最佳实践。它鼓励工程师用自己已经熟悉的、可靠的工程思维去驾驭LLM,而不是要求他们去学习一套全新的、基于概率的编程范式。它将LLM“降级”为一个强大的、但需要被谨慎管理的“组件”,让工程师可以在自己熟悉的领域里发挥作用。