12-Factor Agents - 构建可靠LLM应用的设计原则

12-Factor Agents是一套方法论,就像软件开发领域的"12-Factor App"原则一样,它把传统软件工程里经过验证的最佳实践,创造性地用到了大模型驱动的Agent开发里。其核心目标是弥补Agent从原型开发到生产级应用的鸿沟,让Agent在可靠性、可伸缩性、可维护性、可调试性和安全性上,达到企业级应用…

目录
  1. 自然语言到工具调用
  2. 掌控你的提示词
  3. 掌控你的上下文窗口
  4. 工具只是结构化输出
  5. 统一执行状态和业务状态
  6. 通过简单API启动/暂停/恢复
  7. 通过工具调用联系人工
  8. 掌控你的控制流
  9. 将错误压缩到上下文窗口
  10. 小而专注的Agent
  11. 从任何地方触发,在用户所在的地方与他们见面
  12. 使你的Agent成为一个无状态的reducer
文本版 · 供搜索与朗读

12-Factor Agents - 构建可靠LLM应用的设计原则

12-Factor Agents

构建可靠LLM应用的设计原则

12-Factor Agents是一套方法论,就像软件开发领域的"12-Factor App"原则一样,它把传统软件工程里经过验证的最佳实践,创造性地用到了大模型驱动的Agent开发里。其核心目标是弥补Agent从原型开发到生产级应用的鸿沟,让Agent在可靠性、可伸缩性、可维护性、可调试性和安全性上,达到企业级应用的标准。

psychology

settings

integration_instructions

1

自然语言到工具调用

将用户自然语言指令结构化转换为API调用,利用LLM的意图识别能力

2

掌控你的提示词

开发者应完全控制LLM的提示词,提示词应像代码一样被设计、版本控制和测试

3

掌控你的上下文窗口

主动管理和构建传递给LLM的上下文信息,包含LLM决策所需的一切信息

4

工具只是结构化输出

Agent中工具调用的本质是LLM生成的结构化数据,触发确定性代码执行

5

统一执行状态和业务状态

简化并统一执行状态和业务状态,Agent执行状态可从上下文窗口推断

6

通过简单API启动/暂停/恢复

为Agent提供简单、直观的API接口,方便各种系统轻松交互

7

通过工具调用联系人工

LLM通过工具调用明确与人工交互,而不是直接输出自然语言请求

8

掌控你的控制流

开发者应完全控制Agent的控制流,而不是依赖框架的预设流程

9

将错误压缩到上下文窗口

将错误信息压缩并整合到上下文窗口中,以便LLM能够理解和处理错误

10

小而专注的Agent

构建小型、专注的Agent,每个Agent负责特定任务,而不是大型多功能Agent

11

从任何地方触发,在用户所在的地方与他们见面

Agent应能从各种渠道触发,并在用户所在的地方交互

12

使你的Agent成为一个无状态的reducer

Agent应设计为无状态的reducer,接收输入状态并返回新状态

这套原则不是一个像LangChain这样可以直接拿来用的"工具箱",而是一套"方法论",帮助开发者构建生产级的LLM应用。

👍 1🚀 1

想参与讨论或点赞?登录后使用完整功能

讨论回复(23)

✨
文本版 · 供搜索与朗读

12-Factor Agents - 背景与发展历史

12-Factor Agents - 背景与发展历史

从软件工程到智能代理的演变历程

account_tree

软件工程的历史演变60年前

软件本质上是有向图(DG),早期我们用流程图表示程序。20年前,DAG编排器如Airflow、Prefect等开始流行,增加了可观察性、模块化、重试机制等功能。

psychology

机器学习与DAG的结合10-15年前

当ML模型开始变得足够有用时,我们开始在DAG中加入ML模型,如文本摘要、分类等任务。但本质上仍是确定性软件。

auto_awesome

Agent的承诺现在

Agent让我们可以抛弃DAG,不再需要软件工程师编写每个步骤和边缘情况。只需给Agent一个目标和一组转换,让LLM实时决策路径。

Agent的核心循环:LLM决定下一步 → 执行工具调用 → 结果添加到上下文窗口 → 重复直到完成

warning

Agent循环模式的挑战

最大问题:当上下文窗口过长时,Agent会迷失方向,反复尝试相同但无效的方法。即使模型支持更长的上下文窗口,小而专注的提示词和上下文总能带来更好的结果。

即使Agent正确率达到90%,也远未达到"可以交给客户使用"的标准

lightbulb

实际有效的解决方案:微代理(Micro Agents)

将Agent模式融入更广泛的确定性DAG中。语言模型管理范围明确的任务集,便于整合实时人工反馈,将其转化为工作流步骤,而不会陷入上下文错误循环。

真实案例:部署机器人(Deploybot)处理部署流程,通过LLM解析人类反馈并提出更新方案,隔离任务和上下文以保持LLM专注

architecture

Agent的本质

一个Agent由四个核心组件构成:

提示词 - 告诉LLM如何行为,有哪些可用工具

Switch语句 - 根据LLM返回的JSON决定下一步行动

累积上下文 - 存储已发生步骤及其结果

For循环 - 直到LLM发出某种"终止"工具调用

12-Factor Agents将这些模式形式化,使其可应用于任何软件项目,添加令人印象深刻的AI功能,无需完全采用"AI Agent"的传统实现/定义。

👍 1❤️ 1🚀 1👀 1
✨
文本版 · 供搜索与朗读

原则1:自然语言到工具调用

原则1:自然语言到工具调用

将用户自然语言指令结构化转换为API调用

translate
核心概念

这是Agent构建中最常见的模式之一,将自然语言转换为结构化的工具调用。这种模式允许构建能够推理任务并执行它们的Agent,利用LLM的意图识别能力。

从自然语言请求到结构化API调用,LLM作为翻译桥梁,连接人类意图与机器执行

compare_arrows
工作原理

LLM接收自然语言输入,理解用户意图,然后返回一个结构化对象,描述需要执行的工具调用。确定性代码随后接收这个结构化对象并执行相应的操作。

# LLM接收自然语言并返回结构化对象
nextStep = await llm.determineNextStep(
"""
create a payment link for $750 to Jeff
for sponsoring the february AI tinkerers meetup
"""
)

# 根据函数名称处理结构化输出
if nextStep.function == 'create_payment_link':
stripe.paymentlinks.create(nextStep.parameters)
return
elif nextStep.function == 'something_else':
# ... 其他情况
pass
else: # 模型调用了我们不知道的工具
# 执行其他操作
pass

code
实际应用示例

以下是将自然语言请求转换为Stripe API调用的示例:

自然语言请求

can you create a payment link for $750 to Terri for sponsoring the february AI tinkerers meetup?

结构化API调用

{
"function": {
"name": "create_payment_link",
"parameters": {
"amount": 750,
"customer": "cust_128934ddasf9",
"product": "prod_8675309",
"price": "prc_09874329fds",
"quantity": 1,
"memo": "Hey Jeff - see below for the payment link for the february ai tinkerers meetup"
}
}
}

实际应用中,Agent可能需要先列出客户、产品和价格,以构建包含正确ID的有效载荷,或将这些ID包含在提示词/上下文窗口中。

自然语言到工具调用是Agent构建的基础模式,它将人类意图转换为机器可执行的结构化操作,是连接用户与系统的关键桥梁。

👍 1
✨
文本版 · 供搜索与朗读

原则2:掌控你的提示词

原则2:掌控你的提示词

不要将提示词工程外包给框架

code
核心概念

开发者应该完全控制LLM的提示词,提示词应像代码一样被设计、版本控制和测试。不要依赖框架提供的"黑盒"方法,而是将提示词作为一等代码来管理。

提示词是应用逻辑和LLM之间的主要接口,拥有完全控制权对于生产级Agent至关重要

compare
框架方法 vs 直接掌控

block框架的"黑盒"方法

agent = Agent(
role="...",
goal="...",
personality="...",
tools=[tool1, tool2, tool3]
)

task = Task(
instructions="...",
expected_output=OutputModel
)

result = agent.run(task)

这种方法虽然可以快速上手,但难以调整和逆向工程,无法精确控制模型接收的指令。

check_circle直接掌控提示词

function DetermineNextStep(thread: string) ->
DoneForNow | ListGitTags | DeployBackend |
DeployFrontend | RequestMoreInformation {
prompt #"
{{ _.role("system") }}

You are a helpful assistant that manages deployments
for frontend and backend systems.
You work diligently to ensure safe and successful
deployments by following best practices...

{{ _.role("user") }}
{{ thread }}

What should the next step be?
"#
}

直接掌控提示词,可以精确控制指令,便于测试和迭代,提高透明度。

stars
掌控提示词的好处

control_camera

完全控制

编写Agent所需的确切指令,无需黑盒抽象

checklist

测试和评估

像对待其他代码一样为提示词构建测试和评估

loop

快速迭代

根据实际性能快速修改提示词

visibility

透明度

清楚了解Agent正在使用的指令

psychology

角色利用

利用支持非标准用户/助手角色使用的API

我不知道什么是最佳提示词,但我知道你希望拥有能够尝试一切的灵活性。掌控你的提示词,为生产级Agent提供所需的灵活性和精确控制。

👍 1
✨
文本版 · 供搜索与朗读

原则3:掌控你的上下文窗口

原则3:掌控你的上下文窗口

主动管理和构建传递给LLM的上下文信息

layers
核心概念

不一定需要使用标准的基于消息的格式向LLM传递上下文。上下文工程是关键——LLM是无状态函数,将输入转换为输出,要获得最佳输出,需要提供最佳输入。

在任何给定的时刻,Agent对LLM的输入都是"这是到目前为止发生的事情,下一步是什么"

compare
标准与自定义上下文格式

format_list_bulleted标准消息格式

[
{
"role": "system",
"content": "You are a helpful assistant..."
},
{
"role": "user",
"content": "Can you deploy the backend?"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "1",
"name": "list_git_tags",
"arguments": "{}"
}
]
}
]

标准格式适用于大多数用例,但可能不是最高效的上下文传递方式。

code自定义上下文格式

[
{
"role": "system",
"content": "You are a helpful assistant..."
},
{
"role": "user",
"content": |
Here's everything that happened so far:

<slack_message>
From: @alex
Channel: #deployments
Text: Can you deploy the backend?
</slack_message>

<list_git_tags>
intent: "list_git_tags"
</list_git_tags>

<list_git_tags_result>
tags: [...]
</list_git_tags_result>

what's the next step?

}
]

自定义格式可以根据用例优化,提高令牌效率和LLM理解能力。

code
上下文示例

以下是使用XML风格格式的上下文窗口示例:

<slack_message>
From: @alex
Channel: #deployments
Text: Can you deploy the latest backend to production?
</slack_message>

<list_git_tags>
intent: "list_git_tags"
</list_git_tags>

<list_git_tags_result>
tags:
- name: "v1.2.3"
commit: "abc123"
date: "2024-03-15T10:00:00Z"
- name: "v1.2.2"
commit: "def456"
date: "2024-03-14T15:30:00Z"
</list_git_tags_result>

XML风格格式只是其中一种示例——关键是你可以构建适合自己应用的格式。拥有尝试不同上下文结构的灵活性将获得更好的质量。

stars
掌控上下文窗口的好处

data_object

信息密度

以最大化LLM理解的方式构建信息

healing

错误处理

以帮助LLM恢复的格式包含错误信息

security

安全性

控制传递给LLM的信息,过滤敏感数据

autorenew

灵活性

根据学习到的最佳实践调整格式

speed

令牌效率

优化上下文格式以提高令牌效率

上下文窗口是与LLM的主要接口。控制如何构建和呈现信息可以显著提高Agent的性能。我不知道什么是最佳方法,但我知道你希望拥有能够尝试一切的灵活性。

👍 1
✨
文本版 · 供搜索与朗读

原则4:工具只是结构化输出

原则4:工具只是结构化输出

Agent中工具调用的本质是LLM生成的结构化数据,触发确定性代码执行

data_object
核心概念

工具调用本质上只是LLM生成的结构化输出,而不是特殊的API调用。LLM生成描述要执行的操作的结构化数据,然后确定性代码执行该操作。

工具调用是LLM决策与实际执行之间的桥梁,通过结构化数据实现清晰分离

sync_alt
工作流程

psychology

LLM接收上下文
生成结构化输出

arrow_forward

code

确定性代码
解析结构化数据

arrow_forward

play_arrow

执行相应操作
返回结果

// LLM生成的结构化输出示例
{
"function": {
"name": "deploy_backend",
"parameters": {
"tag": "v1.2.3",
"environment": "production"
}
}
}

// 确定性代码处理
if (output.function.name === "deploy_backend") {
const { tag, environment } = output.function.parameters;
deployBackend(tag, environment);
}

stars
优势与应用

architecture

清晰分离

LLM决策与实际执行操作之间有明确界限

bug_report

易于调试

可以检查结构化输出,更容易定位问题

settings_suggest

灵活交互

支持更复杂的交互和工作流程

integration_instructions

测试友好

可以模拟结构化输出进行单元测试

这种模式比传统函数调用更灵活,允许更复杂的交互和工作流,同时保持代码的可测试性和可维护性

将工具调用视为结构化输出而非特殊API调用,可以带来更好的灵活性和可维护性。这种思维方式帮助构建更可靠、更易于调试的Agent系统。

👍 1
✨
文本版 · 供搜索与朗读

原则5:统一执行状态和业务状态

原则5:统一执行状态和业务状态

简化并统一执行状态和业务状态,Agent执行状态可从上下文窗口推断

merge_type
核心概念

简化并统一执行状态和业务状态,使Agent执行状态可以从上下文窗口中推断。这种方法减少了复杂性,使理解和调试代理更容易。

上下文窗口成为代理状态的单一真实来源,减少状态不一致的风险

compare_arrows
状态统一

play_circle执行状态

Agent当前执行的位置、已完成的步骤、待处理的任务等执行流程相关信息。

business业务状态

业务数据、用户信息、配置参数等与业务逻辑相关的状态信息。

all_inclusive统一状态

将执行状态和业务状态统一存储在上下文窗口中,使Agent可以从上下文推断出完整状态。这种方式使状态管理更加简单,便于暂停、恢复和测试。

code
实现示例

// 从上下文窗口推断执行状态
function inferExecutionState(context) {
const lastEvent = context[context.length - 1];

if (lastEvent.type === 'deploy_backend_result') {
return {
status: 'BACKEND_DEPLOYED',
nextStep: 'deploy_frontend',
data: lastEvent.data
};
}

if (lastEvent.type === 'error') {
return {
status: 'ERROR_OCCURRED',
nextStep: 'handle_error',
error: lastEvent.data
};
}

// 默认状态
return {
status: 'INITIAL',
nextStep: 'determine_next_action'
};
}

// 暂停和恢复Agent
async function pauseAgent(context) {
// 序列化上下文以供稍后恢复
await saveToDatabase(context);
return "Agent paused successfully";
}

async function resumeAgent(agentId) {
// 从数据库恢复上下文
const context = await loadFromDatabase(agentId);

// 从上下文推断执行状态
const state = inferExecutionState(context);

// 继续执行
return await continueExecution(state, context);
}

stars
优势

psychology

简化复杂性

减少状态管理的复杂性,使系统更易理解

pause_circle

易于暂停/恢复

通过保存上下文轻松暂停和恢复Agent执行

bug_report

便于调试

通过检查上下文更容易定位和解决问题

verified

状态一致性

减少状态不一致的风险,提高系统健壮性

通过统一执行状态和业务状态,我们可以构建更可靠、更易于维护的Agent系统。上下文窗口成为状态的单一真实来源,简化了状态管理并提高了系统的健壮性。

👍 1
✨
文本版 · 供搜索与朗读

原则6:通过简单API启动/暂停/恢复

原则6:通过简单API启动/暂停/恢复

为Agent提供简单、直观的API接口,方便各种系统轻松交互

api
核心概念

为Agent提供简单、直观的API接口,使各种系统能够轻松与Agent交互。这些API应该易于使用、一致且直观,特别对于长时间运行的任务,暂停和恢复能力尤为重要。

简单API使Agent能够无缝集成到现有系统和工作流中,提高生产环境的可用性

touch_app
核心API操作

play_arrow

启动

初始化Agent并开始执行任务,可传入初始上下文和配置

pause

暂停

临时停止Agent执行,保存当前状态以便后续恢复

resume

恢复

从暂停点继续执行Agent,恢复之前保存的状态

// 简单的Agent API示例
class AgentAPI {
// 启动Agent
async launch(initialContext, config) {
const agentId = generateUniqueId();
await initializeAgent(agentId, initialContext, config);
return { agentId, status: 'running' };
}

// 暂停Agent
async pause(agentId) {
const context = await getCurrentContext(agentId);
await saveContext(agentId, context);
await stopExecution(agentId);
return { agentId, status: 'paused' };
}

// 恢复Agent
async resume(agentId) {
const context = await loadContext(agentId);
await restoreExecution(agentId, context);
return { agentId, status: 'running' };
}
}

stars
优势与应用

integration_instructions

易于集成

简单API使Agent能够轻松集成到现有系统和工作流中

update

状态管理

暂停/恢复功能使长时间运行任务的状态管理更加简单

settings

可配置性

通过API参数轻松配置Agent行为,适应不同场景

monitor_heart

监控与调试

通过API获取Agent状态,便于监控和调试

简单、一致的API接口是Agent在生产环境中可靠运行的关键,它们使开发者能够轻松控制Agent生命周期,并将其无缝集成到更广泛的系统中

通过提供简单直观的API接口,我们可以使Agent更加易于使用和集成。这种设计理念使开发者能够专注于业务逻辑,而不是复杂的Agent控制机制。

👍 1
✨
文本版 · 供搜索与朗读

原则7:通过工具调用联系人工

原则7:通过工具调用联系人工

LLM通过工具调用明确与人工交互,而不是直接输出自然语言请求

contact_support
核心概念

LLM应该使用工具调用来明确与人类交互,而不是直接输出自然语言请求。这种方法使交互更加结构化和可预测,便于将人类反馈集成到代理的工作流中。

通过工具调用明确请求人类输入或批准,比依赖自然语言解析人类响应更加健壮和可靠

compare
交互方式对比

text_format自然语言请求

LLM直接输出自然语言请求人类帮助,这种方式难以解析和处理,可能导致误解或不一致的响应。

// LLM直接输出自然语言请求
"我需要您的帮助才能继续。请告诉我是否应该部署到生产环境?"

build工具调用请求

LLM使用结构化工具调用请求人类输入,这种方式更加明确,便于系统处理和跟踪。

// LLM使用工具调用请求人类输入
{
"function": {
"name": "request_human_approval",
"parameters": {
"action": "deploy_to_production",
"details": "部署后端v1.2.3到生产环境"
}
}
}

sync_alt
交互流程

psychology

LLM识别需要人类干预

arrow_forward

build

生成结构化工具调用

arrow_forward

person

人类接收并响应请求

arrow_forward

play_arrow

LLM继续执行任务

// 工具调用示例 - 请求部署批准
{
"function": {
"name": "request_approval",
"parameters": {
"action": "deploy_backend",
"version": "v1.2.3",
"environment": "production",
"reason": "修复了关键安全漏洞"
}
}
}

// 人类响应后的处理
if (humanResponse.approved) {
// 继续执行部署
deployBackend(version, environment);
} else {
// 处理拒绝情况
handleRejection(humanResponse.reason);
}

stars
优势

architecture

结构化交互

明确的工具调用使交互更加结构化和可预测

integration_instructions

易于集成

便于将人类反馈集成到代理的工作流中

security

健壮性

比依赖自然语言解析人类响应更加健壮

fact_check

可审计性

便于跟踪和审计与代理的人类交互

通过工具调用明确与人类交互,可以使Agent系统更加可靠和可预测。这种方法不仅提高了交互质量,还使人类反馈能够更有效地集成到AI工作流中。

👍 1
✨
文本版 · 供搜索与朗读

原则8:掌控你的控制流

原则8:掌控你的控制流

开发者应完全控制Agent的控制流,而不是依赖框架的预设流程

account_tree
核心概念

开发者应该完全控制Agent的控制流,而不是依赖框架的预设流程。这种方法为开发者提供了更多的灵活性和对Agent行为的控制,使为特定用例定制代理变得更加容易。

通过拥有控制流,开发者可以实现自定义逻辑和决策过程,使Agent更加适应特定需求

compare
控制流对比

settings_applications框架控制流

框架提供预设的控制流程,开发者只需配置参数和规则,难以实现自定义逻辑。

1

初始化Agent

2

框架处理输入

3

执行预设流程

4

返回结果

code自定义控制流

开发者完全控制控制流,可以实现自定义逻辑和决策过程,更加灵活和适应性强。

1

接收输入

2

自定义预处理

3

条件判断与分支

4

自定义后处理

code
实现示例

settings框架方式

// 使用框架的预设控制流
from some_framework import Agent

// 创建Agent,配置预设参数
agent = Agent(
name="deployment_agent",
goal="Deploy applications to production",
tools=[deploy_tool, check_status_tool]
)

// 运行Agent,框架控制整个流程
result = agent.run("Deploy backend to production")

框架控制整个流程,开发者难以干预或自定义特定步骤。

developer_mode自定义方式

// 自定义控制流
async function deployWithCustomFlow(request) {
// 自定义预处理
const context = await preprocessRequest(request);

// 自定义条件判断
if (context.environment === "production") {
// 生产环境特殊处理
const approval = await requestApproval(context);
if (!approval.approved) {
return handleRejection(approval.reason);
}
}

// 自定义部署逻辑
const result = await customDeployLogic(context);

// 自定义后处理
return await postProcessResult(result);
}

开发者完全控制控制流,可以实现自定义逻辑和决策过程。

stars
优势

tune

完全控制

开发者可以完全控制Agent的行为和决策过程

settings_suggest

自定义逻辑

可以实现特定业务逻辑和决策规则

autorenew

灵活性

根据不同场景和需求灵活调整控制流

bug_report

易于调试

自定义控制流使调试和优化更加容易

掌控你的控制流使开发者能够构建更加灵活和适应性强的Agent系统。通过自定义控制流,开发者可以实现特定业务逻辑,使Agent更好地满足实际需求。

👍 1
✨
文本版 · 供搜索与朗读

原则9:将错误压缩到上下文窗口

原则9:将错误压缩到上下文窗口

将错误信息压缩并整合到上下文窗口中,以便LLM能够理解和处理错误

compress
核心概念

将错误信息压缩并整合到上下文窗口中,以便LLM能够理解和处理错误。这种方法使LLM能够更有效地理解和处理错误,防止上下文窗口变得过大,并使LLM更容易从错误中恢复。

关键是在不占用过多上下文空间的情况下,提供足够的错误信息,使LLM能够理解出了什么问题以及如何恢复

compare
错误处理对比

error_outline完整错误详情

将完整错误堆栈和详细信息包含在上下文中,占用大量空间,可能导致上下文窗口溢出。

<deploy_backend_result>
error: ConnectionError: Failed to connect to deployment service at https://api.deploy.example.com/v1/deploy
at Object.deploy (/app/src/deploy.js:45:13)
at processTicksAndRejections (node:internal/process/task_queues.js:95:5)
at async DeploymentService.execute (/app/src/services/deployment.js:23:19)
at async Agent.handleToolCall (/app/src/agent.js:67:8)
Request details: {
method: 'POST',
url: 'https://api.deploy.example.com/v1/deploy',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
},
body: '{"tag":"v1.2.3","environment":"production"}'
}
Response status: 503 Service Unavailable
Response headers: {
'content-type': 'application/json',
'retry-after': '30'
}
Response body: '{"error":"Service temporarily unavailable","retry_after":30}'
</deploy_backend_result>

data_object压缩错误信息

将错误信息压缩为关键要点,保留足够信息供LLM理解和恢复,同时节省上下文空间。

<deploy_backend_result>
error: ConnectionError
message: Failed to connect to deployment service
service: https://api.deploy.example.com/v1/deploy
status: 503 Service Unavailable
retry_after: 30 seconds
attempted_action: deploy backend v1.2.3 to production
</deploy_backend_result>

code
实现示例

// 错误压缩函数
function compressError(error, action) {
return {
type: "error",
error_type: error.name,
message: error.message,
service: error.config?.url || "unknown",
status: error.response?.status,
retry_after: error.response?.headers?.['retry-after'],
attempted_action: action
};
}

// 在Agent中使用压缩错误
async function handleToolCall(toolCall) {
try {
const result = await executeTool(toolCall);
return { type: "success", data: result };
} catch (error) {
// 压缩错误信息
const compressedError = compressError(error, toolCall);
return compressedError;
}
}

// 将压缩错误添加到上下文
async function addToContext(context, event) {
if (event.type === "error") {
// 对于已解决的错误,可以选择隐藏或简化
if (event.resolved) {
context.push({
type: "error_resolved",
original_error: event.error_type,
resolution: event.resolution
});
} else {
context.push(event);
}
} else {
context.push(event);
}
}

stars
优势

memory

上下文效率

压缩错误信息节省上下文空间,防止窗口溢出

healing

错误恢复

LLM更容易理解错误并采取恢复措施

auto_fix_high

智能处理

可以隐藏已解决的错误,避免重复处理

track_changes

错误跟踪

便于跟踪和管理Agent工作流中的错误

通过将错误信息压缩到上下文窗口,我们可以构建更加高效和可靠的Agent系统。这种方法不仅节省了宝贵的上下文空间,还使LLM能够更好地理解和处理错误情况。

👍 1
✨
文本版 · 供搜索与朗读

原则10:小而专注的Agent

原则10:小而专注的Agent

创建小而专注的Agent,专注于做好一件事,而不是试图做所有事情的大型通用Agent

center_focus_strong
核心概念

创建小而专注的Agent,每个Agent专注于做好一件事,而不是构建试图做所有事情的大型通用Agent。这种方法使代理更加可靠且易于维护,也使测试和调试代理变得更加容易。

通过专注于特定任务,Agent可以针对该任务进行优化,比构建大型、单体Agent更具可扩展性

compare
Agent设计对比

all_inclusive单体通用Agent

一个大型Agent试图处理所有任务,包含复杂的逻辑和决策过程,难以维护和优化。

// 单体通用Agent示例
class MonolithicAgent {
async handleRequest(request) {
// 处理各种类型的请求
if (request.type === "deploy") {
// 复杂的部署逻辑
return await this.handleDeploy(request);
} else if (request.type === "monitor") {
// 复杂的监控逻辑
return await this.handleMonitor(request);
} else if (request.type === "report") {
// 复杂的报告逻辑
return await this.handleReport(request);
}
// ... 更多复杂的处理逻辑
}
}

widgets小而专注的Agent

多个小型Agent,每个专注于特定任务,逻辑简单清晰,易于维护和优化。

// 专注的部署Agent
class DeploymentAgent {
async handleDeploy(request) {
// 专注于部署逻辑
const deployment = await this.prepareDeployment(request);
return await this.executeDeployment(deployment);
}
}

// 专注的监控Agent
class MonitoringAgent {
async handleMonitor(request) {
// 专注于监控逻辑
const metrics = await this.collectMetrics(request);
return await this.analyzeMetrics(metrics);
}
}

view_module
专注Agent示例

rocket_launch

部署Agent

专注于应用程序部署流程,处理版本控制、环境配置和部署验证

add

monitor_heart

监控Agent

专注于系统监控和性能分析,收集指标并生成警报

add

assessment

报告Agent

专注于数据分析和报告生成,创建可视化图表和摘要

// 组合专注Agent的工作流
async function deployAndMonitor(appConfig) {
// 1. 使用部署Agent
const deployAgent = new DeploymentAgent();
const deploymentResult = await deployAgent.handleDeploy(appConfig);

// 2. 使用监控Agent
const monitorAgent = new MonitoringAgent();
const monitoringResult = await monitorAgent.handleMonitor({
appId: deploymentResult.appId,
duration: "1h"
});

// 3. 使用报告Agent
const reportAgent = new ReportAgent();
const reportResult = await reportAgent.generateReport({
deployment: deploymentResult,
monitoring: monitoringResult
});

return reportResult;
}

stars
优势

verified

可靠性

专注的Agent更可靠,错误隔离,不会影响整个系统

build

易于维护

小型Agent代码简单,逻辑清晰,易于理解和修改

speed

性能优化

可以针对特定任务进行优化,提高执行效率

extension

可扩展性

易于添加新功能,只需创建新的专注Agent

bug_report

易于调试

问题定位更容易,每个Agent职责明确

repeat

可重用性

专注的Agent可以在不同工作流中重复使用

通过创建小而专注的Agent,我们可以构建更加可靠、可维护和可扩展的系统。每个Agent专注于做好一件事,然后通过组合这些专注的Agent来构建复杂的工作流。

👍 1
✨
文本版 · 供搜索与朗读

原则11:从任何地方触发,在用户所在的地方与他们互动

原则11:从任何地方触发,在用户所在的地方与他们互动

使用户能够从任何渠道触发Agent,并通过相同渠道获得响应

核心概念

使用户能够从Slack、电子邮件、短信或任何其他他们想要的渠道触发Agent,并使Agent能够通过相同的渠道进行响应。这种方法打破了传统应用的界限,让AI能够无缝融入用户现有的工作流程和沟通渠道。

让Agent能够从任何地方被触发,并在用户所在的地方与他们互动,创造更自然、更高效的人机协作体验

多渠道集成

Agent应该能够无缝集成到用户现有的沟通渠道和工作流中,而不是要求用户适应新的界面或工具。

Slack

电子邮件

短信

日历

交互流程

用户触发

Agent处理

原渠道响应

无论用户从哪个渠道发起请求,Agent都应该能够理解并处理,然后通过相同的渠道返回响应,创造无缝的交互体验。

核心优势

在用户所在的地方与他们互动

这有助于构建感觉像真实人类或至少是数字同事的AI应用程序。用户无需学习新工具或改变工作流程,可以在他们熟悉的渠道中与AI交互。

外循环Agent

使Agent能够被非人类触发(例如事件、定时任务、故障等),它们可能工作5、20或90分钟,但当到达关键点时,可以联系人类寻求帮助、反馈或批准。

高风险工具

如果您能够快速引入各种人类,您可以让Agent访问更高风险的操作,如发送外部电子邮件、更新生产数据等。保持清晰的标准使您能够审计并对执行更大更好事情的Agent充满信心。

通过使Agent能够从任何地方触发并在用户所在的地方互动,我们可以创造更加自然、高效的人机协作体验,打破传统应用的界限,让AI无缝融入现有工作流程。

👍 1
✨
文本版 · 供搜索与朗读

原则12:使你的Agent成为一个无状态的reducer

Just for fun!

原则12:使你的Agent成为一个无状态的reducer

Agent应设计为无状态的reducer,接收输入状态并返回新状态

核心概念

Agent应设计为无状态的reducer,接收输入状态并返回新状态。这种方法使Agent更加可预测、可测试和可扩展,同时简化了状态管理和恢复。

将Agent设计为纯函数,给定相同的输入总是产生相同的输出,不依赖于外部状态或副作用

Reducer模式

输入状态

Agent处理

输出状态

// Agent作为reducer的示例
function agentReducer(currentState, action) {
// 根据当前状态和动作计算新状态
switch (action.type) {
case 'DEPLOY_REQUEST':
return {
...currentState,
status: 'deploying',
deployment: action.payload
};

case 'DEPLOY_SUCCESS':
return {
...currentState,
status: 'deployed',
lastDeployment: action.payload
};

case 'DEPLOY_ERROR':
return {
...currentState,
status: 'error',
error: action.payload
};

default:
return currentState;
}
}

状态管理

在无状态reducer模式中,Agent不维护内部状态,而是接收完整的状态作为输入,并返回新的状态。状态由外部系统管理,使Agent更加可预测和可测试。

状态转换示例

// 初始状态
{
status: 'idle',
deployments: [],
error: null
}

// 部署请求后
{
status: 'deploying',
deployments: [],
error: null,
currentDeployment: { app: 'myapp', version: 'v1.2.3' }
}

// 部署成功后
{
status: 'deployed',
deployments: [{ app: 'myapp', version: 'v1.2.3', time: '2023-06-15T10:30:00Z' }],
error: null
}

优势

易于测试

纯函数易于单元测试,可以轻松模拟各种输入和状态

可重现性

给定相同的输入总是产生相同的输出,便于调试和问题重现

可扩展性

无状态设计使Agent更容易水平扩展和并行处理

时间旅行调试

可以轻松回放状态序列,便于调试和分析Agent行为

暂停/恢复

通过保存和恢复状态,可以轻松暂停和恢复Agent执行

容错性

状态与处理逻辑分离,使系统更加健壮和容错

通过将Agent设计为无状态的reducer,我们可以构建更加可预测、可测试和可扩展的系统。这种模式简化了状态管理,提高了系统的可靠性和可维护性。

👍 1
T

这是测试回复第1条,用于测试懒加载功能。

暂无表态
T

这是测试回复第2条,懒加载应该会触发。

暂无表态
T

这是测试回复第3条,看看HTMX的revealed触发器是否正常工作。

暂无表态
T

这是测试回复第4条,测试分页加载功能。

暂无表态
T

这是测试回复第5条,验证懒加载条件判断。

暂无表态
T

这是测试回复第6条,检查回复列表的渲染。

暂无表态
T

这是测试回复第7条,测试HTMX的hx-swap功能。

暂无表态
T

这是测试回复第8条,验证hx-target是否正确指向回复列表。

暂无表态
T

这是测试回复第9条,测试懒加载指示器是否显示。

暂无表态
T

这是测试回复第10条,最后一条测试回复。

暂无表态
合作

智谱 GLM-5 已上线

在智谱开放平台 BigModel.cn 打造 AI 应用。新一代旗舰模型 GLM-5 在推理、代码、智能体综合能力达到开源模型 SOTA。

领取 2000万 Tokens