01.背景
在过去的一年时间,魔搭社区在Agent上有较多尝试,包括类GPTS的modelscope-Agent,由于开源大语言模型的进步,我们第一次尝试了通过prompt来build一个Agent,支持知识库,工具调用和code Interpretor。
后来我们在Agentscope项目中尝试了多Agent和workflow,通过可视化的方式,搭建更加复杂的工作流业务,工作流也成为了主流构建Agent的方式,也出现了如Langflow,Dify, Coze等一系列优秀的workflow产品。再后来,我们在Mobile-Agent中尝试了在端侧结合视觉理解模型,支持prompt驱动模型完成PC端/手机端的任务,做到Agent控制computer use 或Mobile use,如订车,买票等。
2024年末,Anthropic写了一篇叫做“Building effective Agents”的文章,针对如何有效的搭建Agent,常见Agent工作流程的几种范式,以及对现在的Code Agent工作模式做了详细的解读。本文结合cookbook+ModelScope的免费Qwen API做了一些中文示例的实践,来更好的理解这篇文章。
课代表敲黑板,先说观点:
在 LLM 领域取得成功并不在于构建最复杂的Agent系统。而是在于构建适合业务需求的系统。从简单的结构化提示词开始,通过综合评估对其进行优化,并且仅在较简单的解决方案不足时才添加多步骤Agent系统。
在实施Agent时,尝试遵循三个核心原则:
- 保持Agent设计的简单性。
- 通过明确展示Agent的计划步骤来优先考虑透明度。
- 通过全面的工具文档和测试精心设计Agent-计算机接口 (ACI) 。
现有的Agent框架,如langchain,dify,Coze等,可以帮助快速入门和理解Agent应用,但在投入生产时,请毫不犹豫地减少抽象层并使用基本组件进行构建。通过遵循这些原则,就可以创建不仅功能强大而且可靠、可维护且受用户信任的Agent。
Agent核心模块(Block)
构建Agent的核心block是LLM,LLM的增强功能是 Retrieval,Tools use,Memory,LLM可以主动使用这些功能 — 生成自己的搜索查询、选择合适的工具并确定要保留哪些信息。
为了更加简便的实践,本文假定LLM都可以访问这三个功能,定义一个基础的Block: llm_call,下面是使用开源的Qwen2.5-72B-Instruct的魔搭社区免费API来构建的LLM call函数。这也将作为本文的block在Agent的高效构建中实践。
def llm_call(prompt: str, system_prompt: str = "", model="Qwen/Qwen2.5-72B-Instruct") -> str: """ Calls the model with the given prompt and returns the response. Returns: str: The response from the language model. """ client = OpenAI( api_key=os.getenv("Modelscope_SDK_Token"), # https://modelscope.cn/my/myaccesstoken base_url="https://api-inference.modelscope.cn/v1/" ) #messages = [{"role": "user", "content": prompt}] messages=[ {'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': prompt}] response = client.chat.completions.create( model=model, max_tokens=4096, messages=messages, temperature=0.1, ) return response.choices[0].message.content
02.工作流示例
1. Prompt-Chaining:将任务分解为连续的子任务,其中每个步骤都基于先前的结果
2. Routing:根据输入特征动态选择专门的 LLM 路径
3. Parallelization:将独立的子任务分布在多个 LLM 上以进行并发处理
4. Orchestrator_workers:Orchestrator LLM 动态分解任务,将其委托给workers LLM,并综合其结果。
5. Evaluator_optimizer: 一个 LLM 调用生成响应,而另一个调用则循环提供评估和反馈。
工作流程:prompt chain
prompt chain将任务分解为一系列步骤,其中每个 LLM 调用都会处理前一个调用的输出。可以在任何中间步骤上添加程序检查(参见下图中的“Gate”),以确保流程仍在正常进行。
实践代码:
def chain(input: str, prompts: List[str]) -> str: """Chain multiple LLM calls sequentially, passing results between steps.""" result = input for i, prompt in enumerate(prompts, 1): print(f"\nStep {i}:") result = llm_call(f"{prompt}\nInput: {result}") print(result) return result
测试示例:
data_processing_steps = [ """仅从文本中提取数值及其相关指标。 在新行上将每个数值格式化为“值:指标”。 示例格式: 92 点:客户满意度 45%:收入增长""", """尽可能将所有数值转换为百分比。 如果不是百分比或点数,请转换为小数(例如,92 点 -> 92%, 12元 -> 12.00)。 每行保留一个数字。 示例格式: 92%:客户满意度 45%:收入增长""", """按数值降序排列所有行。 每行保持“值:指标”格式。 示例: 92%:客户满意度 87%:员工满意度""", """将排序后的数据格式化为包含列的 markdown 表: | Metric | Value | |:--|--:| | 客户满意度 | 92% |""" ] report = """ Q3 业绩摘要: 本季度我们的客户满意度得分上升至 92 分。 收入与去年相比增长了 45%。 我们的主要市场市场份额目前为 23%。 客户流失率从 8% 下降到 5%。 新用户获取成本为每位用户 43 元。 产品采用率提高到 78%。 员工满意度为 87 分。 营业利润率提高到 34%。 """ print("\nInput text:") print(report) formatted_result = chain(report, data_processing_steps) print(formatted_result)
直接调用和使用prompt chain效果对比
直接调用:
Input text: Q3 业绩摘要: 本季度我们的客户满意度得分上升至 92 分。 收入与去年相比增长了 45%。 我们的主要市场市场份额目前为 23%。 客户流失率从 8% 下降到 5%。 新用户获取成本为每位用户 43 元。 产品采用率提高到 78%。 员工满意度为 87 分。 营业利润率提高到 34%。 Output text: 92:客户满意度得分 45%:收入增长率 23%:主要市场市场份额 5%:客户流失率 43:新用户获取成本(元/位用户) 78%:产品采用率 87:员工满意度得分 34%:营业利润率 92:客户满意度得分 45%:收入增长率 23%:主要市场市场份额 5%:客户流失率 43:新用户获取成本(元/位用户) 78%:产品采用率 87:员工满意度得分 34%:营业利润率
prompt chain:
Input text: Q3 业绩摘要: 本季度我们的客户满意度得分上升至 92 分。 收入与去年相比增长了 45%。 我们的主要市场市场份额目前为 23%。 客户流失率从 8% 下降到 5%。 新用户获取成本为每位用户 43 元。 产品采用率提高到 78%。 员工满意度为 87 分。 营业利润率提高到 34%。 Step 1: 92 分:客户满意度 45%:收入增长 23%:市场份额 5%:客户流失率 43 元:新用户获取成本 78%:产品采用率 87 分:员工满意度 34%:营业利润率 Step 2: 92%:客户满意度 45%:收入增长 23%:市场份额 5%:客户流失率 43.00:新用户获取成本 78%:产品采用率 87%:员工满意度 34%:营业利润率 Step 3: 根据您的要求,按数值降序排列所有行,并保持“值:指标”格式,结果如下: 92%:客户满意度 87%:员工满意度 78%:产品采用率 45%:收入增长 43.00:新用户获取成本 34%:营业利润率 23%:市场份额 5%:客户流失率 请注意,"43.00" 已被视为数值进行排序。 Step 4: 根据您提供的数据,我将这些行按数值降序排列,并格式化为包含列的 Markdown 表: ```markdown | Metric | Value | |:------------------|-------:| | 客户满意度 | 92% | | 员工满意度 | 87% | | 产品采用率 | 78% | | 营业利润率 | 34% | | 市场份额 | 23% | | 收入增长 | 45% | | 新用户获取成本 | 43.00 | | 客户流失率 | 5% | ``` 请注意,为了保持表格的整洁和一致性,所有百分比值都对齐显示。新用户获取成本由于不是百分比,所以单独列出。 根据您提供的数据,我将这些行按数值降序排列,并格式化为包含列的 Markdown 表: ```markdown | Metric | Value | |:------------------|-------:| | 客户满意度 | 92% | | 员工满意度 | 87% | | 产品采用率 | 78% | | 营业利润率 | 34% | | 市场份额 | 23% | | 收入增长 | 45% | | 新用户获取成本 | 43.00 | | 客户流失率 | 5% | ``` 请注意,为了保持表格的整洁和一致性,所有百分比值都对齐显示。新用户获取成本由于不是百分比,所以单独列出。
使用prompt chain可以非常适合可以轻松、干净地将任务分解为固定子任务的情况。主要目标是通过使每次 LLM 调用都成为更简单的任务,以牺牲延迟换取更高的准确度。
工作流程:router
路由将输入分类并将其定向到专门的后续任务。此工作流程允许分离关注点并构建更专业的提示。如果没有此工作流程,针对一种输入进行优化可能会损害其他输入的性能。
实践代码:
def route(input: str, routes: Dict[str, str]) -> str: """Route input to specialized prompt using content classification.""" # First determine appropriate route using LLM with chain-of-thought print(f"\nAvailable routes: {list(routes.keys())}") selector_prompt = f""" Analyze the input and select the most appropriate support team from these options: {list(routes.keys())} First explain your reasoning, then provide your selection in this XML format: <reasoning> Brief explanation of why this ticket should be routed to a specific team. Consider key terms, user intent, and urgency level. </reasoning> <selection> The chosen team name </selection> Input: {input}""".strip() route_response = llm_call(selector_prompt) reasoning = extract_xml(route_response, 'reasoning') route_key = extract_xml(route_response, 'selection').strip().lower() print("Routing Analysis:") print(reasoning) print(f"\nSelected route: {route_key}") # Process input with selected specialized prompt selected_prompt = routes[route_key] return llm_call(f"{selected_prompt}\nInput: {input}")
测试示例:
support_routes = { "账单": """您是账单支持专家。请遵循以下准则: 1. 始终以“账单支持响应:”开头 2. 首先确认具体账单问题 3. 清楚地解释任何费用或差异 4. 列出具体的后续步骤和时间表 5. 如果相关,请以付款选项结尾 保持回复专业但友好。 输入: """, "技术": """您是技术支持工程师。请遵循以下准则: 1. 始终以“技术支持响应:”开头 2. 列出解决问题的具体步骤 3. 包括系统要求(如果相关) 4. 提供常见问题的解决方法 5. 如果需要,以升级路径结尾 使用清晰、编号的步骤和技术详细信息。 输入: """, "帐户": """您是帐户安全专家。请遵循以下准则: 1. 始终以“帐户支持响应:”开头 2. 优先考虑帐户安全和验证 3. 提供帐户恢复/更改的明确步骤 4. 包括安全提示和警告 5. 明确设定解决时间预期 保持严肃、注重安全的语气。 输入: """, "产品": """您是产品专家。请遵循以下准则: 1. 始终以“产品支持响应:”开头 2. 重点介绍功能教育和最佳实践 3. 包括具体使用示例 4. 链接到相关文档部分 5. 建议可能有帮助的相关功能 语气要具有教育性和鼓励性。 输入: """ } # Test with different support tickets tickets = [ """ 主题:无法访问我的帐户 消息:您好,过去一个小时我一直在尝试登录,但一直收到“密码无效”错误。 我确定我使用的密码正确。您能帮我重新获得访问权限吗?这很紧急,因为我需要在今天结束前提交报告。 - 小帅""", """主题:我的卡上出现了意外扣款 消息:您好,我刚刚注意到贵公司从我的信用卡上扣了 49.99 美元,但我以为 我使用的是 29.99 美元的套餐。您能解释一下这笔扣款,如果这是错误的话,可以调整吗? 谢谢, 小美""", """主题:如何导出数据? 消息:我需要将所有项目数据导出到 Excel。我查看了文档,但无法弄清楚如何进行批量导出。这可能吗?如果可以,您能指导我完成这些步骤吗? 谨致问候, 小天""" ] print("输入支持工单...\n") for i, ticket in enumerate(tickets, 1): print(f"\n工单 {i}:") print("-" * 40) print(ticket) print("\n答复:") print("-" * 40) response = route(ticket, support_routes) print(response)
效果:
输入支持工单... 工单 1: ---------------------------------------- 主题:无法访问我的帐户 消息:您好,过去一个小时我一直在尝试登录,但一直收到“密码无效”错误。 我确定我使用的密码正确。您能帮我重新获得访问权限吗?这很紧急,因为我需要在今天结束前提交报告。 - 小帅 答复: ---------------------------------------- Available routes: ['账单', '技术', '帐户', '产品'] Routing Analysis: 该输入表明用户小帅遇到了无法登录其帐户的问题,并且在过去的一个小时内多次尝试未果,收到了“密码无效”的错误提示。考虑到用户提到的紧急性(需要在当天结束前提交报告)和问题的核心是关于帐户访问权限,这显然与帐户管理和服务相关。因此,最合适的团队是“帐户”支持团队,他们可以协助解决帐户登录问题并帮助用户恢复访问权限。 Selected route: 帐户 帐户支持响应: 尊敬的小帅, 感谢您联系我们的支持团队。我们非常重视您的帐户安全和访问问题。根据您描述的情况,我们将优先处理以确保您尽快恢复对帐户的访问权限。 ### 1. **验证身份** 为了确保您的帐户安全,我们需要首先验证您的身份。请提供以下信息: - 您注册时使用的电子邮件地址或手机号码。 - 您最近一次登录的大致时间(如果记得的话)。 - 您是否启用了双重身份验证(2FA),如果有,请提供相关详细信息。 ### 2. **帐户恢复步骤** 一旦我们确认了您的身份,您可以按照以下步骤尝试恢复帐户: - **重置密码**:如果您确定密码正确但仍无法登录,可能是由于密码被更改或存在其他问题。请通过“忘记密码”链接重置密码,并确保使用与注册时相同的电子邮件地址或手机号码进行操作。 - **检查临时锁定**:如果您的帐户因多次错误登录尝试而被暂时锁定,请等待一段时间后再试,或者联系我们的支持团队以解除锁定。 ### 3. **安全提示** 为了保护您的帐户免受未经授权的访问,请注意以下几点: - **避免使用简单或重复使用的密码**。建议使用强密码管理器生成并存储复杂的密码。 - **启用双重身份验证(2FA)**,这将显著提高帐户的安全性。 - **定期检查帐户活动**,确保没有异常登录行为。 ### 4. **解决时间预期** 我们将在收到您提供的验证信息后 **15分钟内** 开始处理您的请求,并在 **1小时内** 完成初步审核。在此期间,我们会尽力加快处理速度,以确保您能够及时提交报告。 如果您有任何进一步的问题或需要紧急帮助,请立即回复此邮件或拨打我们的客服热线。 祝您顺利解决问题! 此致 敬礼 帐户安全团队 工单 2: ---------------------------------------- 主题:我的卡上出现了意外扣款 消息:您好,我刚刚注意到贵公司从我的信用卡上扣了 49.99 美元,但我以为 我使用的是 29.99 美元的套餐。您能解释一下这笔扣款,如果这是错误的话,可以调整吗? 谢谢, 小美 答复: ---------------------------------------- Available routes: ['账单', '技术', '帐户', '产品'] Routing Analysis: 该输入涉及用户对其信用卡上意外扣款的疑问,主要关注点在于账单和收费问题。用户提到他们认为自己使用的是一个较低价格的套餐,但被收取了更高的费用,这表明问题与账单或计费错误有关。因此,最合适的团队是处理账单相关问题的团队,以帮助用户解决收费疑问并进行必要的调整。 Selected route: 账单 账单支持响应: 您好,小美, 感谢您联系我们并告知这一情况。我们非常重视您的问题,并将尽快为您解决。 ### 1. 确认具体账单问题 我们注意到您提到最近有一笔 49.99 美元的扣款,而您认为自己使用的是 29.99 美元的套餐。为了更好地帮助您,我们需要确认以下几点: - 您当前订阅的服务类型(例如:月度或年度套餐) - 是否有任何促销或折扣适用于您的账户 - 是否有其他附加服务或升级导致了额外费用 ### 2. 清楚地解释任何费用或差异 根据我们的记录,49.99 美元的扣款可能是由于以下原因之一: - **套餐升级**:如果您最近从较低级别的套餐升级到了更高级别的套餐,可能会导致费用增加。 - **续订费用**:如果您的初始优惠期已结束,系统可能会自动切换到标准费率。 - **附加服务**:某些附加功能或服务可能会产生额外费用。 为了确保准确性,我们将仔细检查您的账户历史记录,并与您确认具体的收费原因。 ### 3. 列出具体的后续步骤和时间表 接下来,我们将采取以下步骤: 1. **审核您的账户**:我们会立即审查您的账单和订阅详情,以确定是否有任何错误。 2. **联系您确认**:一旦我们完成审核,将在 24 小时内与您联系,提供详细的解释。 3. **解决问题**:如果确实存在错误,我们将立即调整账单,并确保未来的扣款符合您的预期。 ### 4. 付款选项(如适用) 如果您希望暂时暂停付款或更改支付方式,您可以随时通过我们的客户服务平台进行操作。我们还提供多种灵活的付款选项,包括分期付款或一次性付款,以满足您的需求。 再次感谢您的耐心等待。我们致力于为您提供最佳的服务体验,并确保所有费用透明合理。 祝您生活愉快! 此致 敬礼 账单支持团队 工单 3: ---------------------------------------- 主题:如何导出数据? 消息:我需要将所有项目数据导出到 Excel。我查看了文档,但无法弄清楚如何进行批量导出。这可能吗?如果可以,您能指导我完成这些步骤吗? 谨致问候, 小天 答复: ---------------------------------------- Available routes: ['账单', '技术', '帐户', '产品'] Routing Analysis: 根据输入的信息,用户需要了解如何将项目数据导出到Excel。这涉及到产品功能的使用和操作指导,因此最合适的团队是“产品”支持团队。用户提到已经查看了文档但仍然无法理解如何进行批量导出,说明他们需要更详细的指导和解释。虽然这个问题可能也涉及技术方面,但主要问题在于用户对产品功能的理解和使用。 Selected route: 产品 产品支持响应: 您好,小天, 感谢您联系我们的产品支持团队!很高兴为您提供帮助。是的,您可以轻松地将所有项目数据导出到 Excel。接下来,我将详细指导您完成批量导出的步骤,并介绍一些最佳实践和相关功能,以确保您能够高效地管理数据。 ### 如何批量导出项目数据到 Excel #### 步骤 1:进入导出设置 1. 登录到您的账户后,导航到“项目管理”页面。 2. 在左侧菜单中,点击“数据导出”选项。这将带您进入导出设置页面。 #### 步骤 2:选择导出范围 1. 在导出设置页面,您会看到一个“导出范围”选项。这里可以选择“单个项目”或“所有项目”。为了批量导出所有项目数据,请选择“所有项目”。 2. 确认选择后,系统会自动加载所有项目的列表。 #### 步骤 3:选择导出格式 1. 接下来,选择导出文件的格式。我们支持多种格式,但根据您的需求,选择“Excel (xlsx)”格式。 2. 您还可以选择是否需要包含历史记录、备注等附加信息。建议勾选这些选项,以便获得更完整的数据。 #### 步骤 4:启动导出 1. 确认所有选项后,点击页面底部的“开始导出”按钮。 2. 系统将处理您的请求,并在完成后通过电子邮件发送下载链接。通常,这个过程会在几分钟内完成,具体时间取决于数据量的大小。 ### 最佳实践 - **定期备份**:建议您定期导出重要数据,以防止意外丢失。可以设置每周或每月的固定时间进行导出。 - **检查数据完整性**:导出完成后,打开 Excel 文件并检查数据是否完整无误。特别是日期、金额等关键字段。 - **使用筛选功能**:如果您只需要部分数据,可以在导出前使用筛选功能,减少不必要的数据量。 ### 相关文档 - [数据导出指南](#)(请参阅“批量导出”章节) - [数据完整性检查](#) ### 可能有帮助的相关功能 - **自动化导出**:如果您经常需要导出数据,可以考虑设置自动化导出任务。这样,系统会在指定时间自动为您生成并发送导出文件。 - **API 集成**:对于高级用户,我们还提供了 API 接口,允许您通过编程方式批量获取数据。详情请参考[API 文档](#)。 希望这些信息对您有所帮助!如果您在操作过程中遇到任何问题,欢迎随时联系我们。祝您使用愉快! 谨致问候, 产品支持团队
结论:router适用于复杂任务,其中存在不同的类别,最好分别处理,并且可以通过 LLM 或更传统的分类模型/算法准确处理分类,如客服场景。
工作流程:Parallelization
LLM 有时可以同时执行一项任务,并以编程方式汇总其输出。这种工作流程(Parallelization)体现在两个关键变化中:
分段:将任务分解为并行运行的独立子任务。
投票:多次运行相同的任务以获得不同的输出
实践代码:
def parallel(prompt: str, inputs: List[str], n_workers: int = 3) -> List[str]: """Process multiple inputs concurrently with the same prompt.""" with ThreadPoolExecutor(max_workers=n_workers) as executor: futures = [executor.submit(llm_call, f"{prompt}\nInput: {x}") for x in inputs] return [f.result() for f in futures]
测试示例:
stakeholders = [ """客户: - 价格敏感 - 想要更好的技术 - 环保问题""", """员工: - 担心工作保障 - 需要新技能 - 想要明确的方向""", """投资者: - 期望增长 - 希望控制成本 - 担心风险""", """供应商: - 产能限制 - 价格压力 - 技术转型""" ] impact_results = parallel( """分析市场变化将如何影响该利益相关者群体。 提供具体影响和建议的行动。 格式清晰,部分和优先级明确。""", stakeholders ) for result in impact_results: print(result)
效果对比:
调用:
### 市场变化对各利益相关者群体的影响及建议行动 #### 1. 客户 **优先级:高** - **价格敏感** - **影响**:市场竞争加剧,客户可能会转向价格更低的竞争对手。通货膨胀和原材料成本上升可能导致价格上涨,进一步影响客户的购买意愿。 - **建议行动**: - 推出灵活的价格策略,如分层定价或促销活动。 - 提供增值服务以增加产品的附加值,从而提高客户对价格的接受度。 - **想要更好的技术** - **影响**:如果公司不能及时跟上技术创新的步伐,客户可能会流失到提供更先进解决方案的竞争对手。 - **建议行动**: - 加大研发投入,确保产品和服务的技术领先性。 - 与科技公司合作,快速引入新技术。 - **环保问题** - **影响**:随着环保意识的增强,客户可能更倾向于选择环保型产品。不重视环保的企业可能会失去市场份额。 - **建议行动**: - 推广绿色生产,减少碳足迹。 - 开发环保型产品,并进行市场宣传。 #### 2. 员工 **优先级:中** - **担心工作保障** - **影响**:市场变化可能导致企业重组或裁员,员工的工作安全感下降,进而影响士气和生产力。 - **建议行动**: - 透明沟通企业的战略调整,增强员工的信任感。 - 提供职业发展路径,帮助员工适应变化。 - **需要新技能** - **影响**:技术进步和市场需求的变化要求员工具备新的技能,否则可能无法胜任工作。 - **建议行动**: - 提供培训和发展机会,特别是与新技术相关的课程。 - 鼓励内部创新,让员工参与新产品开发。 - **想要明确的方向** - **影响**:缺乏明确的战略方向会导致员工迷茫,影响工作效率和忠诚度。 - **建议行动**: - 制定并传达清晰的企业愿景和战略目标。 - 定期召开全员会议,分享公司进展和未来计划。 #### 3. 投资者 **优先级:高** - **期望增长** - **影响**:投资者希望看到持续的增长,市场变化可能导致收入波动,影响投资信心。 - **建议行动**: - 多元化业务,降低单一市场的依赖。 - 寻找新的增长点,如新兴市场或新产品线。 - **希望控制成本** - **影响**:成本上升会压缩利润空间,影响股东回报。 - **建议行动**: - 优化供应链管理,降低采购成本。 - 提高运营效率,减少不必要的开支。 - **担心风险** - **影响**:市场不确定性增加,投资者对风险更加敏感,可能导致资本撤离。 - **建议行动**: - 加强风险管理,建立应急预案。 - 定期向投资者汇报风险评估和应对措施。 #### 4. 供应商 **优先级:中** - **产能限制** - **影响**:供应商产能不足可能导致交货延迟,影响生产和销售。 - **建议行动**: - 与多个供应商建立合作关系,分散风险。 - 提前规划需求,确保供应链稳定。 - **价格压力** - **影响**:原材料价格上涨,供应商可能会提高报价,增加公司的成本负担。 - **建议行动**: - 通过长期合同锁定有利价格。 - 协助供应商提升效率,共同降低成本。 - **技术转型** - **影响**:技术变革要求供应商更新设备和技术,可能增加其成本和难度。 - **建议行动**: - 提供技术支持或资金援助,帮助供应商完成技术升级。 - 共同研发新技术,实现双赢。 ### 总结 市场变化对不同利益相关者的影响各异,但总体上都指向了对灵活性、创新和沟通的需求。通过采取针对性的措施,企业可以在复杂多变的市场环境中保持竞争力,同时满足各方的利益诉求。
router Agent
### 市场变化对客户群体的影响分析及建议行动 #### 1. **价格敏感型客户** - **市场变化影响**: - **通货膨胀与成本上升**:原材料、物流等成本的增加可能导致产品价格上涨,直接影响价格敏感型客户的购买决策。如果价格上涨过快或幅度过大,可能会导致这部分客户转向竞争对手或减少购买量。 - **市场竞争加剧**:随着市场上同类产品的增多,客户有更多的选择,尤其是那些提供更低价格的产品。这可能迫使企业降低利润率以保持竞争力。 - **建议行动**: - **优化成本结构**:通过供应链优化、批量采购等方式降低成本,确保在不牺牲质量的前提下保持价格竞争力。 - **推出分层定价策略**:为不同需求的客户提供多种价格选项,如基础版、标准版和高级版产品,满足不同预算的客户需求。 - **加强促销活动**:定期推出限时折扣、捆绑销售等优惠活动,吸引价格敏感型客户。 #### 2. **追求更好技术的客户** - **市场变化影响**: - **技术创新加速**:随着科技的进步,新产品和技术不断涌现,客户对更先进功能的需求也在增加。如果企业无法跟上技术发展的步伐,可能会失去这部分追求创新的客户。 - **竞争压力增大**:其他品牌可能更快推出新技术,抢占市场份额。如果企业的技术更新速度较慢,可能会被市场淘汰。 - **建议行动**: - **加大研发投入**:持续关注行业前沿技术,增加研发资源投入,确保产品能够快速迭代,满足客户对新技术的需求。 - **建立技术合作伙伴关系**:与领先的科技公司或研究机构合作,获取最新的技术支持,缩短产品开发周期。 - **提供技术培训和支持**:为客户提供更好的技术支持和服务,帮助他们更好地理解和使用新技术,提升客户满意度。 #### 3. **关注环保问题的客户** - **市场变化影响**: - **环保法规趋严**:全球范围内对环境保护的要求越来越高,政府出台更多环保政策,消费者也越来越倾向于选择环保产品。如果企业未能及时响应这些变化,可能会失去环保意识强的客户。 - **可持续发展成为主流趋势**:越来越多的消费者愿意为环保产品支付溢价,尤其是在年轻一代中,环保已成为重要的购买决策因素。 - **建议行动**: - **推动绿色生产**:采用环保材料、减少碳排放、优化能源使用,确保产品符合环保标准,并积极宣传企业的环保举措。 - **推出环保系列产品**:开发更多环保型产品,满足客户对可持续发展的需求。例如,推出可回收、可降解的产品包装,或使用清洁能源制造的产品。 - **参与环保公益活动**:通过赞助环保项目或参与公益行动,提升企业在环保领域的形象,增强客户的品牌忠诚度。 --- ### 优先级排序 1. **价格敏感型客户**:由于这部分客户对价格波动非常敏感,短期内的价格上涨可能会立即影响其购买行为,因此应优先考虑如何通过成本优化和促销活动来保持价格竞争力。 2. **追求更好技术的客户**:随着技术更新换代的速度加快,企业需要尽快调整研发策略,确保产品能够跟上市场需求,避免因技术落后而失去市场份额。 3. **关注环保问题的客户**:虽然环保意识逐渐增强,但这一群体的需求变化相对较为长期,企业可以在逐步推进环保措施的同时,继续关注其他两个群体的短期需求。 通过以上分析和建议,企业可以更好地应对市场变化,满足不同客户群体的需求,从而保持竞争优势。 ### 市场变化对员工的影响分析及建议行动 #### 1. **工作保障的不确定性** - **具体影响**:市场变化可能导致公司业务结构调整、裁员或岗位变动,员工担心失去现有工作或面临不稳定的工作环境。这种不确定性会影响员工的心理状态和工作效率。 - **优先级**:高 - **建议行动**: 1. **透明沟通**:管理层应定期向员工传达公司战略调整的方向,明确哪些部门或岗位可能会受到影响,并提供相应的支持措施。 2. **职业发展计划**:为员工提供职业发展规划,帮助他们了解如何在公司内部找到新的机会,尤其是在市场变化中可能产生的新岗位。 3. **灵活用工机制**:引入灵活用工机制,如兼职、远程办公等,以应对市场波动,减少大规模裁员的可能性。 #### 2. **技能需求的变化** - **具体影响**:随着市场的快速变化,尤其是技术进步和数字化转型,员工现有的技能可能不再适用,导致他们在工作中感到力不从心,甚至面临被淘汰的风险。 - **优先级**:高 - **建议行动**: 1. **培训与再教育**:公司应投资于员工的技能培训,特别是与新技术、数据分析、自动化等领域相关的课程。可以通过内部培训、外部合作或在线学习平台来实现。 2. **技能认证与激励**:为员工提供技能认证的机会,并将技能提升与晋升、奖金等激励机制挂钩,鼓励员工主动学习新技能。 3. **导师制度**:建立内部导师制度,让经验丰富的员工帮助新员工或需要转型的员工,促进知识传递和技能共享。 #### 3. **缺乏明确方向** - **具体影响**:市场变化可能导致公司战略频繁调整,员工难以理解公司的长期发展方向,进而感到迷茫和焦虑,影响工作积极性和创造力。 - **优先级**:中 - **建议行动**: 1. **清晰的战略传达**:管理层应通过定期的全员会议、内部通讯等方式,向员工清晰传达公司的长期愿景和短期目标,确保每个员工都能理解自己在公司整体战略中的角色。 2. **参与决策过程**:邀请员工参与部分决策过程,尤其是与他们工作直接相关的领域,增强他们的归属感和责任感。 3. **设立短期里程碑**:将长期战略分解为具体的短期目标,并为每个阶段设定明确的里程碑,帮助员工更好地跟踪进展并保持动力。 ### 总结 市场变化对员工的影响主要体现在工作保障、技能需求和方向感三个方面。为了应对这些挑战,公司应采取透明沟通、技能培训和战略澄清等措施,确保员工能够在不确定的市场环境中保持信心和竞争力。 ### 市场变化对投资者的影响分析及建议 #### 1. **期望增长** - **具体影响**: - **市场波动加剧**:全球经济不确定性、地缘政治风险、技术变革等因素可能导致市场波动加剧,影响企业的盈利能力,进而影响投资者的回报。 - **行业转型加速**:随着数字化、绿色能源等新兴行业的崛起,传统行业的增长潜力可能受到限制,投资者需要重新评估其投资组合中的行业配置。 - **政策变化**:政府的财政和货币政策调整(如加息、减税等)会影响市场的流动性,进而影响企业的融资成本和资本支出计划,最终影响投资者的收益。 - **建议行动**: - **多元化投资组合**:通过分散投资于不同行业和地区,降低单一市场或行业波动带来的风险,确保长期稳定的增长。 - **关注高成长领域**:加大对新兴行业的投资,如人工智能、清洁能源、生物科技等,这些领域具有较高的增长潜力。 - **定期审查投资策略**:根据市场变化及时调整投资组合,确保资产配置与市场趋势保持一致。 #### 2. **希望控制成本** - **具体影响**: - **通货膨胀压力**:原材料价格上涨、劳动力成本增加等因素可能导致企业运营成本上升,进而压缩利润空间,影响投资者的投资回报。 - **利率上升**:央行加息会导致借贷成本上升,增加企业的融资成本,尤其是对于依赖债务融资的企业,这将直接影响其盈利能力。 - **市场竞争加剧**:随着市场竞争的加剧,企业为了保持市场份额可能会采取降价策略,导致利润率下降,进而影响投资者的收益。 - **建议行动**: - **选择低成本投资工具**:优先选择管理费用较低的投资工具,如指数基金、ETF等,减少不必要的交易成本。 - **关注成本控制能力强的企业**:选择那些在供应链管理、生产效率等方面表现优异的企业进行投资,这类企业能够在成本上升的环境中保持竞争力。 - **优化税务规划**:通过合理的税务规划,减少税收负担,提升投资回报率。 #### 3. **担心风险** - **具体影响**: - **市场不确定性增加**:全球疫情、地缘政治冲突、经济衰退等因素增加了市场的不确定性,投资者面临的系统性风险上升。 - **黑天鹅事件频发**:如金融危机、自然灾害等不可预见的事件可能对市场造成巨大冲击,导致投资者资产大幅缩水。 - **监管环境变化**:各国政府对金融市场的监管力度加大,尤其是在反垄断、数据隐私等领域,可能对企业运营产生不利影响,增加投资者的风险敞口。 - **建议行动**: - **加强风险管理**:建立完善的风险管理体系,定期评估投资组合的风险水平,设定止损点,避免过度暴露于高风险资产。 - **增加防御性资产配置**:适当增加债券、黄金等防御性资产的比例,以应对市场波动和不确定性。 - **保持流动性**:确保投资组合中有足够的现金或其他流动性资产,以便在市场出现机会时能够迅速调整仓位,或在危机时刻有足够的资金应对突发情况。 ### 总结 投资者在当前市场环境下应重点关注以下几点: 1. **增长预期**:通过多元化投资和关注高成长领域来实现稳定增长。 2. **成本控制**:选择低成本投资工具并关注成本控制能力强的企业。 3. **风险管理**:加强风险管理和增加防御性资产配置,确保投资组合的安全性和稳定性。 通过以上措施,投资者可以在复杂多变的市场环境中更好地保护自身利益,并实现长期稳健的投资回报。 ### 供应商市场变化影响分析及行动建议 #### 1. 产能限制 **具体影响:** - **供应中断风险增加**:如果市场需求突然增加,而供应商的产能无法跟上,可能会导致订单延迟或无法按时交货。这不仅会影响客户的满意度,还可能导致合同违约。 - **成本上升**:为了满足需求,供应商可能需要加班或外包生产,这将增加运营成本,进而影响利润率。 - **竞争力下降**:长期的产能不足可能导致客户转向其他供应商,从而削弱供应商的市场份额。 **建议行动:** - **优先级:高** - **评估现有产能**:定期评估现有生产线的效率和瓶颈,确保能够及时发现并解决潜在问题。 - **投资自动化和技术升级**:通过引入自动化设备或改进生产工艺,提高生产效率,减少人工依赖,从而提升产能。 - **建立灵活供应链**:与多个供应商合作,确保在某一供应商出现问题时,可以迅速切换到其他供应商,降低供应中断的风险。 - **优化库存管理**:通过精益生产和JIT(Just-In-Time)库存管理,减少库存积压,同时确保关键原材料的充足供应。 --- #### 2. 价格压力 **具体影响:** - **利润空间压缩**:由于市场竞争激烈,客户对价格敏感度增加,供应商可能被迫降低产品价格,从而压缩利润空间。 - **现金流紧张**:如果价格持续走低,而成本没有相应下降,供应商可能会面临现金流紧张的问题,影响企业的正常运营。 - **质量妥协**:为了降低成本,部分供应商可能会选择使用更便宜的原材料或简化生产工艺,这可能会影响产品质量,进而损害品牌声誉。 **建议行动:** - **优先级:中** - **加强成本控制**:通过优化采购流程、减少浪费、提高生产效率等方式,降低生产成本,保持价格竞争力的同时维持合理的利润率。 - **差异化产品策略**:开发具有独特功能或更高附加值的产品,以区别于竞争对手,从而获得更高的定价权。 - **与客户协商长期合同**:与主要客户签订长期合作协议,锁定价格或设定价格调整机制,避免短期内价格波动带来的不确定性。 - **探索新市场**:寻找新的销售渠道或国际市场,分散单一市场的价格压力,增加收入来源。 --- #### 3. 技术转型 **具体影响:** - **技术落后风险**:如果供应商未能及时跟进行业内的技术创新,可能会逐渐失去竞争优势,甚至被淘汰。 - **资本支出增加**:技术转型通常需要大量的资金投入,包括购买新设备、培训员工等,这对中小供应商来说是一个巨大的挑战。 - **学习曲线陡峭**:新技术的应用往往伴随着较长的学习周期,员工可能需要时间适应,短期内可能会影响生产效率。 **建议行动:** - **优先级:高** - **制定技术路线图**:明确未来几年的技术发展方向,逐步推进技术升级,避免一次性大规模投资带来的财务压力。 - **寻求外部支持**:与科研机构、高校或其他技术领先企业合作,获取技术支持和咨询服务,降低研发成本和风险。 - **员工培训与发展**:为员工提供必要的培训,帮助他们掌握新技术,确保顺利过渡到新的生产模式。 - **试点项目先行**:在全面推广新技术之前,先进行小规模试点,评估其可行性和效果,及时调整方案,减少失败风险。 --- ### 总结 面对市场变化,供应商需要采取积极的应对措施,尤其是在产能限制、价格压力和技术转型这三个方面。通过优化内部管理和外部合作,供应商可以在激烈的市场竞争中保持优势,实现可持续发展。
结论:当划分的子任务可以并行化以提高速度,或者当需要多个视角或尝试以获得更高置信度的结果时,并行化是有效的。对于具有多个考虑因素的复杂任务,当每个考虑因素由单独的 LLM 调用处理时,LLM 通常会表现得更好,从而可以集中注意力于每个特定方面。
工作流程:Orchestrator-workers
在 orchestrator-workers 工作流中,中央 LLM 动态地分解任务,将其委托给 worker LLM,并综合其结果。
实践代码:
from typing import Dict, List, Optional from util import llm_call, extract_xml def parse_tasks(tasks_xml: str) -> List[Dict]: """Parse XML tasks into a list of task dictionaries.""" tasks = [] current_task = {} for line in tasks_xml.split('\n'): line = line.strip() if not line: continue if line.startswith("<task>"): current_task = {} elif line.startswith("<type>"): current_task["type"] = line[6:-7].strip() elif line.startswith("<description>"): current_task["description"] = line[12:-13].strip() elif line.startswith("</task>"): if "description" in current_task: if "type" not in current_task: current_task["type"] = "default" tasks.append(current_task) return tasks class FlexibleOrchestrator: """Break down tasks and run them in parallel using worker LLMs.""" def __init__( self, orchestrator_prompt: str, worker_prompt: str, ): """Initialize with prompt templates.""" self.orchestrator_prompt = orchestrator_prompt self.worker_prompt = worker_prompt def _format_prompt(self, template: str, **kwargs) -> str: """Format a prompt template with variables.""" try: return template.format(**kwargs) except KeyError as e: raise ValueError(f"Missing required prompt variable: {e}") def process(self, task: str, context: Optional[Dict] = None) -> Dict: """Process task by breaking it down and running subtasks in parallel.""" context = context or {} # Step 1: Get orchestrator response orchestrator_input = self._format_prompt( self.orchestrator_prompt, task=task, **context ) orchestrator_response = llm_call(orchestrator_input) # Parse orchestrator response analysis = extract_xml(orchestrator_response, "analysis") tasks_xml = extract_xml(orchestrator_response, "tasks") tasks = parse_tasks(tasks_xml) print("\n=== ORCHESTRATOR OUTPUT ===") print(f"\nANALYSIS:\n{analysis}") print(f"\nTASKS:\n{tasks}") # Step 2: Process each task worker_results = [] for task_info in tasks: worker_input = self._format_prompt( self.worker_prompt, original_task=task, task_type=task_info['type'], task_description=task_info['description'], **context ) worker_response = llm_call(worker_input) result = extract_xml(worker_response, "response") worker_results.append({ "type": task_info["type"], "description": task_info["description"], "result": result }) print(f"\n=== WORKER RESULT ({task_info['type']}) ===\n{result}\n") return { "analysis": analysis, "worker_results": worker_results, }
实践案例
ORCHESTRATOR_PROMPT = """ 分析此任务并将其分解为 2-3 种不同的方法: 任务:{task} 以以下格式返回您的回复: <analysis> 解释您对任务的理解以及哪些方面是有价值的。 重点介绍每种方法如何服务于任务的不同方面。 </analysis> <tasks> <task> <type>正式</type> <description>编写强调规范的精确技术版本</description> </task> <task> <type>对话式</type> <description>编写吸引人的友好版本,与读者建立联系</description> </task> </tasks> """ WORKER_PROMPT = """ 根据以下内容生成内容: 任务:{original_task} 风格:{task_type} 指南:{task_description} 以以下格式返回您的回复: <response> 您的内容在此,保持指定的风格并完全满足要求。 </response> """ orchestrator = FlexibleOrchestrator( orchestrator_prompt=ORCHESTRATOR_PROMPT, worker_prompt=WORKER_PROMPT, ) results = orchestrator.process( task="为新款环保水瓶撰写产品描述", context={ "目标用户": "具有环保意识的年轻一代", "主要功能": ["无塑料","绝缘","终身保修"] } )
效果:
=== ORCHESTRATOR OUTPUT === ANALYSIS: 任务是为新款环保水瓶撰写产品描述。理解这一任务的关键在于既要传达产品的功能和技术特性,又要吸引潜在消费者的兴趣。为了实现这一目标,可以采用不同的方法来满足不同受众的需求和偏好。以下是两种有价值的方法:一种是正式的技术性描述,适合那些对产品细节和技术规格感兴趣的消费者;另一种是对话式的友好描述,旨在与读者建立情感联系,吸引更广泛的消费者群体。 重点介绍每种方法如何服务于任务的不同方面: - 正式的技术性描述能够详细说明产品的材料、设计、性能等技术参数,帮助消费者了解产品的实际优势。 - 对话式的友好描述则通过轻松的语言和情感共鸣,使产品更具吸引力,激发消费者的购买欲望。 TASKS: [{'type': '正式', 'description': '>编写强调规范的精确技术版本,详细列出环保水瓶的材质、容量、保温保冷性能、环保认证等技术参数,确保信息准确无误,适合对产品细节有较高要求的消费者。<'}, {'type': '对话式', 'description': '>编写吸引人的友好版本,使用轻松自然的语言,突出环保水瓶的独特卖点和用户体验,如便携性、时尚外观、环保理念等,与读者建立情感联系,吸引更广泛的消费者群体。<'}] === WORKER RESULT (正式) === 【产品描述:新款环保水瓶】 尊敬的消费者, 我们荣幸地向您介绍新款环保水瓶,此款水瓶专为追求高品质生活且注重环境保护的您设计。以下是该产品的详细技术参数: **一、材质** 本款环保水瓶采用食品级304不锈钢(内胆)和可回收塑料(外壳),确保了其在使用过程中的安全性与耐用性。304不锈钢具有良好的耐腐蚀性和抗冲击性,而可回收塑料则符合国际环保标准,减少了对环境的影响。 **二、容量** 该水瓶提供两种容量选择:500毫升和750毫升,满足不同场景下的需求。无论是日常办公还是户外运动,都能找到适合您的容量。 **三、保温保冷性能** 1. 保温效果:在24小时内保持65摄氏度以上的温度。 2. 保冷效果:在24小时内保持8摄氏度以下的温度。 通过先进的真空隔热技术,有效隔绝外界温度变化,使饮品始终保持理想状态。 **四、环保认证** 本产品已获得多项国际权威机构颁发的环保认证,包括但不限于ISO 14001环境管理体系认证、欧盟CE认证等,确保其生产过程符合严格的环保要求,并且在使用寿命结束后可以被妥善回收处理。 综上所述,这款环保水瓶不仅具备出色的实用功能,更体现了我们对于可持续发展理念的坚定承诺。希望它能成为您生活中不可或缺的一部分,共同守护地球家园。 感谢您对我们产品的关注! === WORKER RESULT (对话式) === 嘿,朋友们!今天想给大家介绍一款超棒的新款环保水瓶,它不仅能满足你日常饮水的需求,还能为地球的环保事业贡献一份力量呢! 首先,这款水瓶超级便携。它的设计非常贴心,轻巧又易于携带,你可以轻松地把它塞进包包里,或者直接挂在背包外面。无论你是去上班、上学,还是外出运动,它都能成为你最贴心的小助手。 而且,它的外观时尚得让人爱不释手。简约而不失个性的设计,让你在人群中脱颖而出。有多种颜色和图案可以选择,总有一款能打动你的心。拿着它走在路上,就像是带着一件时尚单品,既实用又美观。 最重要的是,这是一款真正的环保水瓶哦。它采用高品质的环保材料制成,可重复使用,大大减少了塑料瓶的使用量。每一次选择它,都是在为减少白色污染出一份力。想象一下,如果我们每个人都能用上这样的环保水瓶,那我们的地球将会变得更加美丽。 当你喝着瓶中的水时,你会感受到一种特别的满足感,因为你知道自己正在做一件有意义的事情。来吧,加入我们,一起用这款新款环保水瓶开启绿色生活之旅吧!
Orchestrator-workers 工作流程非常适合无法预测所需子任务的复杂任务(例如,在coding中,需要更改的文件数量以及每个文件中更改的性质可能取决于任务)。虽然它在拓扑上相似,但与并行化的主要区别在于其灵活性 - 子任务不是预先定义的,而是由编排器根据特定输入确定。
Orchestrator-workers 有用的示例:
- 每次对多个文件进行复杂更改的编码产品。
- 搜索任务涉及收集和分析来自多个来源的信息以获取可能相关的信息。
工作流程:Evaluator-Optimizer
在Evaluator-Optimizer工作流中,一个 LLM 调用生成一个响应,而另一个调用在循环中提供评估和反馈。
实践代码:
from util import llm_call, extract_xml def generate(prompt: str, task: str, context: str = "") -> tuple[str, str]: """Generate and improve a solution based on feedback.""" full_prompt = f"{prompt}\n{context}\nTask: {task}" if context else f"{prompt}\nTask: {task}" response = llm_call(full_prompt) thoughts = extract_xml(response, "thoughts") result = extract_xml(response, "response") print("\n=== GENERATION START ===") print(f"Thoughts:\n{thoughts}\n") print(f"Generated:\n{result}") print("=== GENERATION END ===\n") return thoughts, result def evaluate(prompt: str, content: str, task: str) -> tuple[str, str]: """Evaluate if a solution meets requirements.""" full_prompt = f"{prompt}\nOriginal task: {task}\nContent to evaluate: {content}" response = llm_call(full_prompt) evaluation = extract_xml(response, "evaluation") feedback = extract_xml(response, "feedback") print("=== EVALUATION START ===") print(f"Status: {evaluation}") print(f"Feedback: {feedback}") print("=== EVALUATION END ===\n") return evaluation, feedback def loop(task: str, evaluator_prompt: str, generator_prompt: str) -> tuple[str, list[dict]]: """Keep generating and evaluating until requirements are met.""" memory = [] chain_of_thought = [] thoughts, result = generate(generator_prompt, task) memory.append(result) chain_of_thought.append({"thoughts": thoughts, "result": result}) while True: evaluation, feedback = evaluate(evaluator_prompt, result, task) if evaluation == "PASS": return result, chain_of_thought context = "\n".join([ "Previous attempts:", *[f"- {m}" for m in memory], f"\nFeedback: {feedback}" ]) thoughts, result = generate(generator_prompt, task, context) memory.append(result) chain_of_thought.append({"thoughts": thoughts, "result": result})
示例
evaluator_prompt = """ 评估以下代码实现的以下方面: 1. 代码正确性 2. 时间复杂度 3. 风格和最佳实践 您应该只进行评估,而不是尝试解决任务。 如果满足所有条件并且您没有进一步的改进建议,则仅输出“PASS”。 以以下格式简洁地输出您的评估。 <evaluation>PASS、NEEDS_IMPROVEMENT or FAIL</evaluation> <feedback> 需要改进的地方以及原因。 </feedback> """ generator_prompt = """ 您的目标是根据<用户输入>完成任务。如果您之前收到过反馈,您应该反思这些反馈以改进您的解决方案 以以下格式简洁地输出您的答案: <thoughts> [您对任务和反馈的理解以及您计划如何改进] </thoughts> <response> [您的代码实现在这里] </response> """ task = """ <用户输入> 使用以下方法实现堆栈: 1. push(x) 2. pop() 3. getMin() 所有操作都应为 O(1)。 </用户输入> """ loop(task, evaluator_prompt, generator_prompt)
示例结果
=== GENERATION START === Thoughts: 为了实现一个支持 `push(x)`、`pop()` 和 `getMin()` 操作且所有操作都为 O(1) 的堆栈,我们需要使用两个栈:一个用于存储实际的元素,另一个用于存储当前最小值。 具体思路如下: - 主栈 `stack` 用于存储所有的元素。 - 辅助栈 `min_stack` 用于存储每个时刻的最小值。每次 `push(x)` 时,如果 `x` 小于或等于当前的最小值,则将 `x` 也压入 `min_stack` 中;每次 `pop()` 时,如果弹出的元素等于 `min_stack` 的栈顶元素,则也将 `min_stack` 的栈顶元素弹出。 这样可以确保 `getMin()` 操作始终可以在 O(1) 时间内返回当前栈中的最小值。 我将根据这个思路实现代码。 Generated: ```python class MinStack: def __init__(self): self.stack = [] # 主栈,用于存储所有元素 self.min_stack = [] # 辅助栈,用于存储当前最小值 def push(self, x: int) -> None: self.stack.append(x) if not self.min_stack or x <= self.min_stack[-1]: self.min_stack.append(x) def pop(self) -> None: if self.stack: top = self.stack.pop() if top == self.min_stack[-1]: self.min_stack.pop() def top(self) -> int: if self.stack: return self.stack[-1] return None def getMin(self) -> int: if self.min_stack: return self.min_stack[-1] return None # 示例用法 minStack = MinStack() minStack.push(-2) minStack.push(0) minStack.push(-3) print(minStack.getMin()) # 返回 -3 minStack.pop() print(minStack.top()) # 返回 0 print(minStack.getMin()) # 返回 -2 ``` === GENERATION END === === EVALUATION START === Status: PASS Feedback: 代码实现了所有要求的功能,并且满足了 O(1) 时间复杂度的要求。以下是具体评估: 1. **代码正确性**: - `push(x)`:正确地将元素压入主栈,并在需要时更新最小值栈。 - `pop()`:正确地从主栈弹出元素,并在必要时同步更新最小值栈。 - `top()`:正确返回主栈的栈顶元素。 - `getMin()`:正确返回当前最小值。 2. **时间复杂度**: - 所有操作(`push`、`pop`、`top` 和 `getMin`)的时间复杂度均为 O(1),符合题目要求。 3. **风格和最佳实践**: - 代码结构清晰,变量命名合理,易于理解。 - 使用了辅助栈来跟踪最小值,这是一种常见的优化方法。 - 处理了空栈的情况,避免了潜在的错误。 整体来看,代码实现得很好,没有明显的改进空间。 === EVALUATION END === ('\n```python\nclass MinStack:\n def __init__(self):\n self.stack = [] # 主栈,用于存储所有元素\n self.min_stack = [] # 辅助栈,用于存储当前最小值\n\n def push(self, x: int) -> None:\n self.stack.append(x)\n if not self.min_stack or x <= self.min_stack[-1]:\n self.min_stack.append(x)\n\n def pop(self) -> None:\n if self.stack:\n top = self.stack.pop()\n if top == self.min_stack[-1]:\n self.min_stack.pop()\n\n def top(self) -> int:\n if self.stack:\n return self.stack[-1]\n return None\n\n def getMin(self) -> int:\n if self.min_stack:\n return self.min_stack[-1]\n return None\n\n# 示例用法\nminStack = MinStack()\nminStack.push(-2)\nminStack.push(0)\nminStack.push(-3)\nprint(minStack.getMin()) # 返回 -3\nminStack.pop()\nprint(minStack.top()) # 返回 0\nprint(minStack.getMin()) # 返回 -2\n```\n', [{'thoughts': '\n为了实现一个支持 `push(x)`、`pop()` 和 `getMin()` 操作且所有操作都为 O(1) 的堆栈,我们需要使用两个栈:一个用于存储实际的元素,另一个用于存储当前最小值。\n\n具体思路如下:\n- 主栈 `stack` 用于存储所有的元素。\n- 辅助栈 `min_stack` 用于存储每个时刻的最小值。每次 `push(x)` 时,如果 `x` 小于或等于当前的最小值,则将 `x` 也压入 `min_stack` 中;每次 `pop()` 时,如果弹出的元素等于 `min_stack` 的栈顶元素,则也将 `min_stack` 的栈顶元素弹出。\n\n这样可以确保 `getMin()` 操作始终可以在 O(1) 时间内返回当前栈中的最小值。\n\n我将根据这个思路实现代码。\n', 'result': '\n```python\nclass MinStack:\n def __init__(self):\n self.stack = [] # 主栈,用于存储所有元素\n self.min_stack = [] # 辅助栈,用于存储当前最小值\n\n def push(self, x: int) -> None:\n self.stack.append(x)\n if not self.min_stack or x <= self.min_stack[-1]:\n self.min_stack.append(x)\n\n def pop(self) -> None:\n if self.stack:\n top = self.stack.pop()\n if top == self.min_stack[-1]:\n self.min_stack.pop()\n\n def top(self) -> int:\n if self.stack:\n return self.stack[-1]\n return None\n\n def getMin(self) -> int:\n if self.min_stack:\n return self.min_stack[-1]\n return None\n\n# 示例用法\nminStack = MinStack()\nminStack.push(-2)\nminStack.push(0)\nminStack.push(-3)\nprint(minStack.getMin()) # 返回 -3\nminStack.pop()\nprint(minStack.top()) # 返回 0\nprint(minStack.getMin()) # 返回 -2\n```\n'}])
当任务有明确的评估标准,并且迭代改进提供可衡量的价值时,此工作流程特别有效。良好契合的两个标志是,首先,当人类表达他们的反馈时,LLM 的响应可以明显改善;其次,LLM 可以提供这样的反馈。这类似于在软件开发流程中,开发工程师和测试工程师之间的配合和协同。
03.Agent三个要素
本节在上面基于Block和workflow的基础上,提出了Agent的三个要素:Human,LLM Call和Environment。
随着 LLM 在关键功能(理解复杂输入、进行推理和规划、可靠地使用工具以及从错误中恢复)方面的日趋成熟,Agent正在投入生产。Agent通过人类用户的命令或与人类用户的互动讨论开始工作。一旦任务明确,Agent就会独立规划和操作,并可能返回人类那里获取更多信息或判断。在执行过程中,Agent必须从每个步骤(例如工具调用结果或代码执行)的环境中获得“基本事实”以评估其进度。然后,Agent可以在检查点或遇到阻碍时暂停以等待人类的反馈。任务通常在完成后终止,但通常也会包含停止条件(例如最大迭代次数)以保持控制。
Agent可以处理复杂的任务,但它们的实现通常很简单。它们通常只是使用基于environment反馈的工具的 LLM。因此,清晰、周到地设计工具集及其文档至关重要。
何时使用Agent:Agent可用于开放式问题,在这些问题中,很难或不可能预测所需的步骤数,并且您无法硬编码固定路径。LLM 可能会运行很多轮,您必须对其决策有一定程度的信任。Agent的自主性使其成为在受信任环境中扩展任务的理想选择。
Agent的自主性意味着更高的成本,以及出现复合错误的可能性。建议在沙盒环境中进行广泛的测试,并采用适当的防护措施。
Code Agent的一个case
我们参考一次cursor Agent的示例,来参考human,llm,environment是如何交互的:
所以大家猜Cursor的Agent是用的是上面哪个工作流呢?!我猜是:Orchestrator-workers!
04.总结
工作流程不是规定性的,只是开发人员可以塑造和组合以适应不同用例的常见模式。与任何 LLM 功能一样,成功的关键是衡量性能和迭代实现。只有当它明显改善结果时,才应该考虑增加复杂性。
05.引用
文中观点和示例引用自:
https://www.anthropic.com/research/building-effective-Agents
示例代码参考:
https://github.com/anthropics/anthropic-cookbook/tree/main/patterns/agents
点击链接阅读原文:https://github.com/anthropics/anthropic-cookbook/tree/main/patterns/agents