Loading...
正在加载...
请稍候

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

✨步子哥 (steper) 2025年09月16日 12:48
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,接收输入状态并返回新状态

讨论回复

13 条回复
✨步子哥 (steper) #1
09-16 12:55
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发出某种"终止"工具调用
✨步子哥 (steper) #2
09-16 13:05
原则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包含在提示词/上下文窗口中。

✨步子哥 (steper) #3
09-16 13:09
原则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

✨步子哥 (steper) #4
09-16 13:29
原则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

令牌效率

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

✨步子哥 (steper) #5
09-16 13:33
原则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

测试友好

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

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

✨步子哥 (steper) #6
09-16 13:33
原则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

状态一致性

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

✨步子哥 (steper) #7
09-16 13:37
原则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生命周期,并将其无缝集成到更广泛的系统中

✨步子哥 (steper) #8
09-16 13:38
原则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

可审计性

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

✨步子哥 (steper) #9
09-16 13:39
原则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

易于调试

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

✨步子哥 (steper) #10
09-16 13:39
原则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工作流中的错误

✨步子哥 (steper) #11
09-16 13:40
原则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可以在不同工作流中重复使用

✨步子哥 (steper) #12
09-16 13:55
原则11:从任何地方触发,在用户所在的地方与他们互动 @fortawesome/fontawesome-free@6.4.0/css/all.min.css">

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

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

核心概念

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

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

多渠道集成

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

Slack

电子邮件

短信

日历

交互流程

用户触发

Agent处理

原渠道响应

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

核心优势

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

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

外循环Agent

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

高风险工具

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

✨步子哥 (steper) #13
09-16 14:07
原则12:使你的Agent成为一个无状态的reducer @fortawesome/fontawesome-free@6.4.0/css/all.min.css">
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执行

容错性

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