构建生产级可靠AI Agent 的12条原则
2025年12月1日
受经典的 12-Factor App 启发,Dexter Horthy总结了构建可靠、可扩展大模型(LLM)Agent 的 12 条工程原则。本文呈现核心信息。
前言:Agent 的本质
Agent 是能自主完成任务的 AI 程序。
传统程序需要你告诉它每一步怎么做。比如"先查数据库,再发邮件,最后记日志"。
Agent则是,你告诉它目标,它自己决定怎么做。比如"帮我处理这个客户投诉",它会自己判断要查订单、要不要退款、要不要找人审批。
比如,数据分析 Agent,给它数据,它自己决定用什么方法分析。代码 Agent,描述需求,它自己写代码、测试、修 bug。
优秀的 Agent 并非"提供提示词 + 工具集 + 循环执行"的简单模式,而是主要由传统软件构成,仅在需要概率推理的关键节点使用 LLM。
市面上多数"AI Agent"产品实际并不那么智能体化,它们主要是确定性代码,只在恰当位置引入 LLM 来创造良好体验。
生产环境中很少看到 LangChain、LangGraph 等框架被采用,团队通常自行构建方案。
这就面临典型困境:选择框架快速开发 → 达到 70-80% 质量 → 发现质量不足以面向客户 → 需要深入框架源码优化 → 最终推倒重写。
原则 1:让 AI 把人话转成结构化指令
用户说"订明天下午 3 点的会议室",AI 要输出 {"action": "book_room", "time": "2024-12-02 15:00", "duration": 60} 这样的结构化数据。
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{role: "user", content: "订明天下午3点会议室"}],
tools: [{
type: "function",
function: {
name: "book_room",
parameters: {
type: "object",
properties: {
time: {type: "string"},
duration: {type: "number"}
}
}
}
}]
});
LLM 返回应该调用哪个工具及其参数,你的代码接收这个 JSON 后执行实际的业务逻辑。
原则 2:自己写提示词,别用框架的
提示词要明确写在你的代码里,不要让框架藏起来。
// 不推荐的做法
const result = await framework.chat(userInput);
// 推荐的做法
const prompt = `你是客服助手。
规则:
- 保持友好礼貌
- 不得泄露用户隐私
- 遇到不确定的问题回复"让我为您查询"
用户问题:${userInput}`;
const result = await openai.chat(prompt);
将提示词存放在独立文件(如 prompts/customer-service.txt),使用版本控制管理,重要改动需要团队 review。这样便于 A/B 测试、迭代优化,也避免了框架抽象带来的黑盒问题。
原则 3:自己决定给 AI 看什么
你要控制给 AI 看哪些信息、怎么组织这些信息,不要让框架自动塞一堆东西。
// 不推荐:无差别投入所有历史
const context = allMessages; // 浪费 token,信息噪音大
// 推荐:精选相关信息
const context = [
systemPrompt,
...getRecentMessages(5), // 最近 5 条消息
...getRelevantHistory(userQuery, 3) // 与当前查询相关的 3 条历史
];
优化上下文窗口包括:提高信息密度(用更少 token 表达同样内容)、灵活选择格式(XML、JSON、Markdown 等)、过滤无关信息。比如用户询问订单状态时,只需要提供最近的订单信息和当前问题上下文,无需包含一个月前的闲聊记录。
原则 4:工具调用就是 AI 输出 JSON
AI 的"工具调用"其实就是输出一段 JSON 告诉你该做什么,真的要不要做、怎么做,你的代码说了算。
const toolCall = await ai.getNextAction(context);
// toolCall = {tool: "send_email", to: "boss@company.com", subject: "..."}
// 添加业务逻辑控制
if (toolCall.tool === "send_email") {
if (needsApproval(toolCall.to)) {
// 敏感收件人需要审批
await requestApproval(toolCall);
return; // 暂停等待审批
}
if (isSpam(toolCall.subject)) {
// 内容检查
return {error: "邮件内容不当"};
}
// 通过检查后执行
await sendEmail(toolCall);
}
工具不仅是"纯函数",可以是复杂操作的抽象,可以是异步任务,可以是需要人工审批的操作。
原则 5:状态信息不要分两个地方存
不要数据库存一套状态,对话记录又是另一套。尽量从对话历史就能看出 Agent 在做什么。
// 不推荐:维护两套状态
database.save({status: "waiting_approval", step: 3});
messages.push({role: "assistant", content: "已发送请求"});
// 两边信息可能不一致
// 推荐:从消息历史推断状态
messages.push({
role: "assistant",
content: "已向张经理发送审批请求,等待回复",
metadata: {
action: "request_approval",
approver: "zhang",
timestamp: Date.now()
}
});
// 从消息历史即可判断当前状态
这简化了状态管理、支持工作流分支和回溯、提高了系统可观测性。
原则 6:Agent 能暂停、能继续运行
Agent 要能在需要等待时(等人审批、等 API 响应)优雅地停下来,拿到结果后接着跑。
class Agent {
async run(task) {
this.state = {messages: [], status: "running"};
while (this.state.status === "running") {
const action = await this.ai.getNextAction(this.state.messages);
if (action.type === "request_approval") {
this.state.status = "paused";
this.state.waitingFor = "approval";
await this.sendApprovalRequest(action);
return; // 暂停执行
}
const result = await this.execute(action);
this.state.messages.push(result);
}
}
async resume(input) {
this.state.messages.push({role: "user", content: input});
this.state.status = "running";
return this.run(); // 继续执行
}
}
// 使用示例
const agent = new Agent();
await agent.run("发邮件给老板");
// ... Agent 暂停等待审批
await agent.resume("同意"); // 带着审批结果继续
这对于长时间运行的任务、需要人工介入的场景、调试和测试都极为重要。
原则 7:找人帮忙也是一种工具
把"联系人类"当成普通工具来定义和使用,就像调用"发邮件"、"查数据库"一样。
const tools = [
{
name: "query_database",
description: "查询数据库"
},
{
name: "ask_human",
description: "向人类专家咨询不确定的问题",
parameters: {
question: {type: "string", description: "要咨询的问题"},
urgency: {type: "string", enum: ["low", "medium", "high"]}
}
}
];
// LLM 可能返回
const action = {
tool: "ask_human",
question: "此退款金额是否合理?",
urgency: "high"
};
// 执行逻辑
async function executeAskHuman(params) {
await slack.sendMessage("#support",
`🤖 AI 需要人工协助:${params.question}\n紧急程度:${params.urgency}`
);
// 暂停 Agent 等待人类响应
}
这统一了人机协作的处理方式,支持多种通知渠道(Slack、Email、Web 界面等),使人工介入成为工作流的自然组成部分。
原则 8:关键流程自己写代码控制
不要让 AI 完全控制程序怎么跑。重要的逻辑(审批、重试、安全检查)要你自己写代码保证。
// 不推荐:完全依赖 LLM 判断
while (true) {
const action = await ai.getNextAction();
await execute(action);
if (action.type === "done") break;
}
// 推荐:插入控制逻辑
let retryCount = 0;
while (true) {
const action = await ai.getNextAction();
// 审批控制
if (action.requiresApproval) {
await requestApproval(action);
break; // 暂停等待
}
const result = await execute(action);
// 错误处理
if (result.error) {
retryCount++;
if (retryCount > 3) {
await notifyHuman("连续失败 3 次,需要人工介入");
break; // 避免无限重试
}
}
if (action.type === "done") break;
}
实现复杂控制逻辑、错误处理、安全检查、重试策略等,不应依赖 LLM 的概率性判断,而应由确定性代码保证。
原则 9:把错误信息压缩后再给 AI
错误信息要简洁有用,不要把 500 行的错误堆栈直接扔给 AI。
try {
await stripe.createCharge(amount);
} catch (error) {
// 不推荐:直接放入完整错误
context.push({error: error.stack}); // 可能有 500 行
// 推荐:提取关键信息
context.push({
error: `Stripe 支付失败:${error.message}`,
code: error.code,
suggestion: "可能是信用卡余额不足或已过期"
});
}
提取的错误信息应包括:哪个服务出错、错误类型、可能的原因、建议的解决方式。这让 LLM 能理解问题并采取恰当的处理策略。
原则 10:一个 Agent 只做一件事
不要做万能 Agent,一个 Agent 专注一类任务。建议不超过 20 个工具、不超过 100 个步骤。
// 不推荐:万能 Agent
class SuperAgent {
tools = [
"查订单", "处理退款", "修改地址", "客户咨询",
"数据分析", "发送邮件", "库存管理", ...
] // 30+ 个工具,职责模糊
}
// 推荐:专注的小 Agent
class OrderQueryAgent {
tools = ["查询订单", "查询物流"];
}
class RefundAgent {
tools = ["计算退款金额", "发起退款", "通知用户"];
}
class CustomerSupportAgent {
tools = ["回答常见问题", "转接人工"];
async handle(question) {
if (isOrderRelated(question)) {
return orderQueryAgent.handle(question);
}
if (isRefundRelated(question)) {
return refundAgent.handle(question);
}
// 处理一般性咨询
}
}
复杂任务通过多个小 Agent 协作完成。即使未来 LLM 能力大幅提升,专注的 Agent 仍然更易维护、测试和调试。
原则 11:让用户在任何地方都能用 Agent
Agent 要能在 Slack、网页、命令行、API 等各种地方使用,用户在哪里工作就在哪里提供服务。
// 核心业务逻辑
class TaskAgent {
async createTask(description) {
return await database.createTask(description);
}
}
// Slack 入口
slackBot.command("/create-task", async (req) => {
const result = await taskAgent.createTask(req.text);
return `任务已创建:${result.id}`;
});
// Web API 入口
app.post("/api/tasks", async (req, res) => {
const result = await taskAgent.createTask(req.body.description);
res.json(result);
});
// 命令行入口
program.command("create <description>")
.action(async (description) => {
const result = await taskAgent.createTask(description);
console.log(`任务已创建:${result.id}`);
});
统一的后端逻辑配合多样的前端入口,满足不同用户的使用习惯。
原则 12:Agent 像纯函数一样工作
把 Agent 设计成:输入当前状态和新事件,输出新状态。不要在 Agent 里存变量。
// 不推荐:内部状态
class Agent {
private currentStep = 0;
private history = [];
async run(input) {
this.currentStep++;
this.history.push(input);
// 难以调试和重放
}
}
// 推荐:无状态 Reducer
function agentReducer(state, event) {
const newMessages = [...state.messages, event];
const action = calculateNextAction(newMessages);
return {
...state,
messages: newMessages,
nextAction: action
};
}
// 使用方式
let state = {messages: [], nextAction: null};
state = agentReducer(state, {role: "user", content: "你好"});
state = agentReducer(state, {role: "assistant", content: "您好!"});
// 优势:可以保存和恢复任意历史状态
const savedState = JSON.parse(localStorage.get("state"));
state = agentReducer(savedState, newEvent);
这种模式便于测试(输入输出明确)、调试(可重放任意时刻)、分布式部署(无状态服务易于扩展)。类似 Redux 的时间旅行调试,能够回到任何历史状态继续执行。
实践建议
渐进式采用
无需一次实现全部 12 条原则。根据当前挑战选择相关原则:
提示词难以优化? 应用原则 2(自主管理提示词)和原则 3(控制上下文窗口)
需要人工审批? 实现原则 7(人类交互)和原则 6(暂停/恢复)
调试困难? 采用原则 5(统一状态)和原则 12(无状态 Reducer)
可靠性问题? 使用原则 10(小而专注)和原则 8(控制流程)
从小功能开始
选择一个独立的小功能验证原则,例如:
客服自动回复:常见问题自动回答,不确定的转人工(原则 7)
订单查询助手:接收订单号,调用 query_order 工具返回结果(原则 1、4)
审批工作流:检查申请格式,自动分配审批人,等待审批后继续(原则 6、7、8)
验证效果后再扩展到其他功能。
工程基础设施
// 日志:记录 LLM 决策
logger.info("LLM 决策", {action, context});
// 监控:跟踪成功率
metrics.increment("agent.success");
metrics.increment("agent.failure");
// 测试:保证改动不破坏功能
test("应该识别退款请求", async () => {
const action = await ai.getNextAction([
{role: "user", content: "我要退款"}
]);
expect(action.tool).toBe("process_refund");
});
像对待传统软件一样,实施版本控制、单元测试、集成测试、可观测性监控等工程实践。
核心要点
-
Agent 本质上是软件,主要由确定性代码构成,LLM 只在需要概率推理的节点介入
-
控制关键接口:提示词、上下文窗口、控制流应该由你掌控,而非框架黑盒
-
工程纪律优先:应用传统软件工程的最佳实践,大模型只是众多组件之一
-
可靠性胜过智能性:生产环境中,可靠的 Agent 比看起来"更智能"的 Agent 更有价值
即使大模型能力持续提升,这些工程原则仍将保持价值。它们专注于使 LLM 应用更可靠、可扩展、易于维护。
相关文章
百亿美金AI大厂内部曝光:AI 让效率翻倍,却怕自己技能退化丢工作
今年8月,Anthropic对132名内部工程师做了调查、53次访谈,并分析了20万条Claude Code使用记录。 这份调查值得参考,下面是一些核心信息。 根据调查,一年前员工在28%的工作中...
2025/12/5AI 平台引用偏好深度解读
主流AI平台偏向搜索哪些内容? 一项最新研究表明,当前主流 AI 平台——ChatGPT、Google AI Overviews 和 Perplexity 在信息抓取和引用上的模式与底层理念区别巨大...
2025/11/24烧了100万美金,我们摸透了AI红人营销完整工作流
【编者按】 市面上关于红人营销的教程很多,但针对 AI/SaaS 这种高门槛产品的却很少。本文作者基于百万美金的投放经验,捅破了一层窗户纸:AI 产品的推广不靠带货,而靠演示工作流。 从如何用语义匹...
2025/11/24用AI帮房地产广告公司处理发票,每月无需任何工作赚取650美元
我合作的这家日本房地产营销公司为几十家房地产开发商在雅虎广告、谷歌广告和META上投放广告。 每个月,他们要花好几天时间手工处理发票,即从各种不同格式里提取数据,全部重新整理成符合日本会计标准的格式...
2025/11/18