Agentic Workflow智能工作流设计完全教程

教程简介

本教程全面讲解Agentic Workflow智能工作流设计,涵盖工作流设计模式(顺序/并行/条件/循环)、多Agent协作架构、任务分解与规划、工具调用与API编排、状态管理、错误处理与容错、Human-in-the-Loop、LangGraph/CrewAI/AutoGen三大框架对比及企业级部署方案。

Agentic Workflow 智能工作流设计完全教程

从单 Agent 到多 Agent 协作,系统掌握智能工作流的设计模式、实现框架与企业级部署。


目录

  1. Agentic Workflow 概述与核心概念
  2. 工作流设计模式
  3. 多 Agent 协作架构设计
  4. 任务分解与规划策略
  5. 工具调用与外部集成
  6. 状态管理与上下文传递
  7. 错误处理与容错机制
  8. 人机协作(Human-in-the-Loop)
  9. 主流框架对比
  10. 企业级工作流部署与监控

1. Agentic Workflow 概述与核心概念

1.1 什么是 Agentic Workflow

Agentic Workflow(智能体工作流)是一种将大语言模型(LLM)作为核心推理引擎,通过自主决策、工具调用和多步推理来完成复杂任务的系统架构。与传统的确定性工作流不同,Agentic Workflow 具备动态决策能力——Agent 可以根据中间结果调整执行路径,而非遵循固定的流程图。

与传统工作流的本质区别:

传统工作流(确定性):
  输入 → 步骤A → 步骤B → 步骤C → 输出
  (每一步都是预定义的,不会改变)

Agentic Workflow(非确定性):
  输入 → 思考 → 决策 → [可能调用工具] → 观察 → 再思考 → ... → 输出
  (Agent 根据中间结果自主决定下一步行动)

1.2 核心概念

Agent(智能体)

Agent 是工作流的基本执行单元,它具备以下能力:

  • 感知(Perception):接收用户输入、环境状态和工具返回结果
  • 推理(Reasoning):使用 LLM 分析问题并制定行动计划
  • 行动(Action):调用工具、生成文本或触发其他 Agent
  • 记忆(Memory):维护短期(上下文窗口)和长期(外部存储)记忆

Tool(工具)

工具是 Agent 与外部世界交互的接口:

# 工具的标准定义格式
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "搜索互联网获取最新信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "搜索关键词"
                    },
                    "num_results": {
                        "type": "integer",
                        "description": "返回结果数量",
                        "default": 5
                    }
                },
                "required": ["query"]
            }
        }
    }
]

Planning(规划)

规划是 Agent 将复杂任务分解为可执行步骤的能力:

class Planner:
    """任务规划器"""
    
    def __init__(self, llm):
        self.llm = llm
    
    def create_plan(self, task: str, context: dict = None) -> list[dict]:
        """将任务分解为执行步骤"""
        prompt = f"""你是一个任务规划专家。请将以下任务分解为清晰的执行步骤。

任务:{task}
上下文:{context or '无'}

请以JSON格式输出步骤列表,每个步骤包含:
- step_id: 步骤编号
- action: 具体行动描述
- tool: 需要使用的工具(如果有的话)
- depends_on: 依赖的前置步骤编号列表
- expected_output: 预期输出描述

输出:"""
        
        response = self.llm.generate(prompt)
        return self.parse_plan(response)
    
    def revise_plan(self, plan: list[dict], feedback: str) -> list[dict]:
        """根据反馈修改计划"""
        prompt = f"""当前执行计划遇到问题,请根据反馈修改计划。

当前计划:{json.dumps(plan, ensure_ascii=False)}
反馈/错误:{feedback}

请输出修改后的计划:"""
        
        response = self.llm.generate(prompt)
        return self.parse_plan(response)

1.3 Agentic AI 的演进路径

Level 1: 简单问答
  用户 → LLM → 回答
  (无工具、无记忆、无规划)

Level 2: 工具增强
  用户 → LLM → [工具调用] → LLM → 回答
  (有工具,但单步执行)

Level 3: ReAct 循环
  用户 → [思考→行动→观察]×N → 回答
  (多步推理,动态决策)

Level 4: 多 Agent 协作
  用户 → 协调Agent → [Agent A, Agent B, Agent C] → 协调Agent → 回答
  (分工协作,专业互补)

Level 5: 自主工作流
  用户 → [目标设定→规划→执行→反思→调整]×N → 结果
  (自主规划、自我纠错、持续优化)

2. 工作流设计模式

2.1 顺序执行模式(Sequential)

最简单的模式,步骤按顺序依次执行:

class SequentialWorkflow:
    """顺序执行工作流"""
    
    def __init__(self, agents: list):
        self.agents = agents
    
    def execute(self, initial_input: str) -> str:
        result = initial_input
        for agent in self.agents:
            result = agent.run(result)
            print(f"[{agent.name}] 完成,输出长度: {len(result)}")
        return result

# 示例:内容创作流水线
workflow = SequentialWorkflow([
    ResearchAgent(),      # 步骤1:资料收集
    OutlineAgent(),       # 步骤2:大纲生成
    WritingAgent(),       # 步骤3:内容撰写
    ReviewAgent(),        # 步骤4:质量审核
    FormattingAgent(),    # 步骤5:格式排版
])

result = workflow.execute("写一篇关于量子计算的技术博客")

适用场景: 翻译流水线、数据处理管道、文档生成流程。

2.2 并行执行模式(Parallel)

多个 Agent 同时执行独立任务,最后汇总结果:

import asyncio
from concurrent.futures import ThreadPoolExecutor

class ParallelWorkflow:
    """并行执行工作流"""
    
    def __init__(self, agents: list, aggregator):
        self.agents = agents
        self.aggregator = aggregator
    
    async def execute(self, input_data: str) -> str:
        # 并行执行所有 Agent
        tasks = [
            asyncio.create_task(agent.arun(input_data))
            for agent in self.agents
        ]
        results = await asyncio.gather(*tasks)
        
        # 汇总结果
        return self.aggregator.merge(results)

# 示例:多维度市场分析
workflow = ParallelWorkflow(
    agents=[
        CompetitorAnalysisAgent(),   # 竞品分析
        MarketTrendAgent(),          # 市场趋势
        CustomerInsightAgent(),      # 客户洞察
        TechnicalFeasibilityAgent(), # 技术可行性
    ],
    aggregator=ReportAggregator()
)

report = asyncio.run(workflow.execute("分析智能手表市场机会"))

适用场景: 多源信息聚合、并行测试、多角度分析。

2.3 条件分支模式(Conditional)

根据中间结果动态选择执行路径:

class ConditionalWorkflow:
    """条件分支工作流"""
    
    def __init__(self):
        self.routes = {}
        self.default_route = None
    
    def add_route(self, condition, agent):
        """添加条件路由"""
        self.routes[condition] = agent
    
    def set_default(self, agent):
        self.default_route = agent
    
    def execute(self, input_data: str) -> str:
        # 路由决策
        route_key = self.classify_input(input_data)
        
        if route_key in self.routes:
            agent = self.routes[route_key]
            print(f"路由到: {agent.name}")
            return agent.run(input_data)
        elif self.default_route:
            return self.default_route.run(input_data)
        else:
            raise ValueError(f"无匹配路由: {route_key}")
    
    def classify_input(self, text: str) -> str:
        """使用 LLM 进行意图分类"""
        prompt = f"""将以下用户请求分类为一个类别:

用户请求:{text}

可选类别:
- code_review: 代码审查相关
- bug_fix: Bug修复相关
- feature: 新功能开发
- documentation: 文档撰写
- general: 其他

类别:"""
        return llm.generate(prompt).strip()

# 示例:智能客服路由
workflow = ConditionalWorkflow()
workflow.add_route("technical", TechnicalSupportAgent())
workflow.add_route("billing", BillingAgent())
workflow.add_route("sales", SalesAgent())
workflow.set_default(GeneralAgent())

response = workflow.execute("我的订单为什么还没发货?")

2.4 循环模式(Loop)

Agent 反复执行直到满足退出条件:

class LoopWorkflow:
    """循环工作流 - 带退出条件的迭代执行"""
    
    def __init__(self, agent, max_iterations=10, quality_threshold=0.8):
        self.agent = agent
        self.max_iterations = max_iterations
        self.quality_threshold = quality_threshold
    
    def execute(self, input_data: str) -> str:
        result = input_data
        history = []
        
        for i in range(self.max_iterations):
            # 执行当前迭代
            result = self.agent.run(result, iteration=i, history=history)
            history.append(result)
            
            # 评估质量
            quality = self.evaluate_quality(result, input_data)
            print(f"迭代 {i+1}: 质量评分 = {quality:.2f}")
            
            if quality >= self.quality_threshold:
                print(f"达到质量阈值,退出循环")
                return result
        
        print(f"达到最大迭代次数 {self.max_iterations}")
        return result
    
    def evaluate_quality(self, result: str, original: str) -> float:
        """使用 LLM 评估输出质量"""
        prompt = f"""评估以下输出的质量(0-1分):

原始需求:{original}
当前输出:{result}

评分标准:
- 完整性:是否涵盖了所有要点
- 准确性:内容是否正确
- 清晰度:表达是否清晰易懂
- 实用性:是否可以直接使用

请只输出一个0-1之间的小数:"""
        try:
            return float(llm.generate(prompt).strip())
        except:
            return 0.5

# 示例:迭代优化写作
workflow = LoopWorkflow(
    agent=WritingRefinerAgent(),
    max_iterations=5,
    quality_threshold=0.9
)
final_article = workflow.execute("写一篇关于AI Agent的技术文章")

2.5 层级委托模式(Hierarchical)

上级 Agent 将任务委托给下级 Agent:

class HierarchicalWorkflow:
    """层级委托工作流"""
    
    def __init__(self):
        self.manager = ManagerAgent()
        self.workers = {}
    
    def register_worker(self, name: str, agent):
        self.workers[name] = agent
    
    def execute(self, task: str) -> str:
        # 管理者分解任务
        subtasks = self.manager.decompose(task, list(self.workers.keys()))
        
        results = {}
        for subtask in subtasks:
            worker_name = subtask["assigned_to"]
            worker = self.workers[worker_name]
            
            # 如果子任务还需要进一步分解
            if subtask.get("complexity", "low") == "high":
                sub_result = self._delegate(worker, subtask["description"])
            else:
                sub_result = worker.run(subtask["description"])
            
            results[subtask["id"]] = sub_result
        
        # 管理者整合结果
        return self.manager.integrate(task, results)

# 示例:软件开发团队
workflow = HierarchicalWorkflow()
workflow.register_worker("architect", ArchitectAgent())
workflow.register_worker("frontend", FrontendAgent())
workflow.register_worker("backend", BackendAgent())
workflow.register_worker("tester", QAAgent())

result = workflow.execute("开发一个用户登录系统")

2.6 设计模式选型指南

任务特征                    推荐模式          示例
─────────────────────────────────────────────────────
步骤固定、线性依赖         顺序执行          文档翻译流水线
多个独立子任务             并行执行          多源数据采集
需要根据输入动态路由       条件分支          智能客服分流
需要迭代优化直到达标       循环模式          代码生成与调试
任务复杂需要分工           层级委托          软件项目开发
混合特征                   嵌套组合          企业级自动化流程

3. 多 Agent 协作架构设计

3.1 协作模式

模式一:辩论式协作

多个 Agent 从不同角度分析问题,通过"辩论"达成共识:

class DebateWorkflow:
    """辩论式多 Agent 协作"""
    
    def __init__(self, agents: list, judge):
        self.agents = agents  # 参与辩论的 Agent
        self.judge = judge    # 裁判 Agent
    
    def execute(self, topic: str, rounds: int = 3) -> str:
        debate_history = []
        
        for round_num in range(rounds):
            round_responses = []
            
            for agent in self.agents:
                # 每个 Agent 考虑之前所有发言
                prompt = f"""讨论主题:{topic}

之前的讨论:
{self._format_history(debate_history)}

请从你的专业角度发表观点。可以支持、反对或补充之前的发言。
你的角色:{agent.role}"""
                
                response = agent.run(prompt)
                round_responses.append({
                    "agent": agent.name,
                    "round": round_num + 1,
                    "response": response
                })
            
            debate_history.extend(round_responses)
        
        # 裁判总结
        summary_prompt = f"""讨论主题:{topic}

以下是各位专家的讨论记录:
{self._format_history(debate_history)}

请综合各方观点,给出最终结论和建议:"""
        
        return self.judge.run(summary_prompt)

# 示例:技术方案评审
debate = DebateWorkflow(
    agents=[
        SecurityExpertAgent(),     # 安全专家
        PerformanceExpertAgent(),  # 性能专家
        CostExpertAgent(),         # 成本专家
    ],
    judge=ChiefArchitectAgent()
)
decision = debate.execute("选择数据库方案:PostgreSQL vs MongoDB vs TiDB")

模式二:审查式协作

一个 Agent 生成,另一个 Agent 审查并提出改进:

class ReviewWorkflow:
    """审查式协作 - 生成者 + 审查者"""
    
    def __init__(self, generator, reviewer, max_revisions=3):
        self.generator = generator
        self.reviewer = reviewer
        self.max_revisions = max_revisions
    
    def execute(self, task: str) -> str:
        # 生成初稿
        draft = self.generator.run(task)
        
        for revision in range(self.max_revisions):
            # 审查
            review = self.reviewer.run(f"""请审查以下内容:

原始任务:{task}

当前内容:
{draft}

请指出问题并给出具体修改建议:""")
            
            # 检查是否需要修改
            if self._is_approved(review):
                print(f"审查通过(第 {revision + 1} 轮)")
                return draft
            
            # 根据审查意见修改
            draft = self.generator.run(f"""请根据审查意见修改内容:

原始任务:{task}

当前内容:
{draft}

审查意见:
{review}

请输出修改后的完整内容:""")
        
        return draft
    
    def _is_approved(self, review: str) -> bool:
        """判断审查是否通过"""
        approval_keywords = ["通过", "合格", "优秀", "LGTM", "approved"]
        return any(kw in review for kw in approval_keywords)

模式三:专家委员会

多个专家 Agent 各自独立完成任务,投票选出最佳方案:

class CommitteeWorkflow:
    """专家委员会模式"""
    
    def __init__(self, experts: list, coordinator):
        self.experts = experts
        self.coordinator = coordinator
    
    def execute(self, task: str) -> dict:
        # 各专家独立完成任务
        proposals = {}
        for expert in self.experts:
            proposal = expert.run(task)
            proposals[expert.name] = proposal
        
        # 协调者评估并选择最佳方案
        evaluation_prompt = f"""任务:{task}

以下是各位专家的方案:

{self._format_proposals(proposals)}

请评估每个方案的优缺点,并选择最佳方案或组合各方案的长处,
给出最终推荐。"""
        
        final = self.coordinator.run(evaluation_prompt)
        
        return {
            "proposals": proposals,
            "final_recommendation": final
        }

3.2 Agent 角色定义

from dataclasses import dataclass
from typing import Optional

@dataclass
class AgentRole:
    """Agent 角色定义"""
    name: str
    role: str
    expertise: list[str]
    system_prompt: str
    tools: list[str]
    constraints: Optional[list[str]] = None

# 定义一个软件开发团队
team_roles = {
    "pm": AgentRole(
        name="产品经理",
        role="需求分析与项目管理",
        expertise=["需求分析", "用户故事", "优先级排序"],
        system_prompt="""你是一个经验丰富的产品经理。
        你的职责是理解用户需求,撰写清晰的用户故事和验收标准。
        始终从用户体验角度思考问题。""",
        tools=["文档编辑", "任务管理"],
        constraints=["不做技术实现决策"]
    ),
    "architect": AgentRole(
        name="架构师",
        role="系统设计与技术选型",
        expertise=["系统设计", "架构模式", "技术选型"],
        system_prompt="""你是一个资深软件架构师。
        你负责设计系统架构,选择合适的技术栈,确保系统的可扩展性和可维护性。
        你的决策需要考虑性能、安全、成本等多个维度。""",
        tools=["代码分析", "架构图生成"],
        constraints=["不直接写业务代码"]
    ),
    "developer": AgentRole(
        name="开发工程师",
        role="代码实现",
        expertise=["编码", "调试", "单元测试"],
        system_prompt="""你是一个高效的开发工程师。
        你负责根据架构设计实现功能代码,编写单元测试,确保代码质量。
        遵循 SOLID 原则和项目编码规范。""",
        tools=["代码编辑", "终端执行", "测试框架"],
        constraints=["重大设计变更需架构师确认"]
    ),
    "reviewer": AgentRole(
        name="代码审查员",
        role="代码质量把关",
        expertise=["代码审查", "最佳实践", "安全审计"],
        system_prompt="""你是一个严格的代码审查员。
        你审查代码的正确性、可读性、性能和安全性。
        给出具体的、可操作的改进建议。""",
        tools=["代码分析", "静态检查"],
        constraints=["不直接修改代码,只提建议"]
    )
}

3.3 完整的多 Agent 系统实现

import json
from typing import Any

class MultiAgentSystem:
    """多 Agent 协作系统"""
    
    def __init__(self):
        self.agents = {}
        self.message_bus = MessageBus()
        self.state = SharedState()
    
    def register_agent(self, name: str, agent):
        """注册 Agent"""
        self.agents[name] = agent
        self.message_bus.subscribe(name, agent.receive_message)
    
    def execute(self, task: str) -> str:
        """执行任务"""
        # 1. 任务分解
        plan = self.agents["coordinator"].plan(task)
        
        # 2. 分配并执行
        results = {}
        for step in plan["steps"]:
            agent_name = step["agent"]
            agent = self.agents[agent_name]
            
            # 传递上下文
            context = {
                "task": task,
                "step": step,
                "previous_results": results,
                "shared_state": self.state.get_all()
            }
            
            result = agent.execute(step["description"], context)
            results[step["id"]] = result
            
            # 更新共享状态
            self.state.update(step["id"], result)
            
            # 广播进展
            self.message_bus.broadcast({
                "type": "step_complete",
                "step_id": step["id"],
                "agent": agent_name,
                "summary": result[:200] + "..." if len(result) > 200 else result
            })
        
        # 3. 整合结果
        final = self.agents["coordinator"].integrate(task, results)
        return final


class MessageBus:
    """Agent 间通信的消息总线"""
    
    def __init__(self):
        self.subscribers = {}
    
    def subscribe(self, agent_name: str, callback):
        self.subscribers[agent_name] = callback
    
    def send(self, target: str, message: dict):
        if target in self.subscribers:
            self.subscribers[target](message)
    
    def broadcast(self, message: dict):
        for name, callback in self.subscribers.items():
            callback(message)


class SharedState:
    """Agent 间共享状态"""
    
    def __init__(self):
        self._state = {}
    
    def update(self, key: str, value: Any):
        self._state[key] = value
    
    def get(self, key: str, default=None):
        return self._state.get(key, default)
    
    def get_all(self) -> dict:
        return dict(self._state)

4. 任务分解与规划策略

4.1 任务分解方法

方法一:递归分解

class RecursiveDecomposer:
    """递归任务分解器"""
    
    def __init__(self, llm, max_depth=3, min_granularity="single_tool_call"):
        self.llm = llm
        self.max_depth = max_depth
        self.min_granularity = min_granularity
    
    def decompose(self, task: str, depth: int = 0) -> dict:
        if depth >= self.max_depth:
            return {"task": task, "type": "atomic", "children": []}
        
        prompt = f"""分析以下任务,判断是否可以分解为更小的子任务。

任务:{task}
当前深度:{depth}
最大深度:{self.max_depth}

如果可以分解,请输出JSON格式:
{{"decomposable": true, "subtasks": ["子任务1", "子任务2", ...]}}

如果已经是原子任务(单个工具调用或简单推理),输出:
{{"decomposable": false}}"""
        
        response = json.loads(self.llm.generate(prompt))
        
        if not response.get("decomposable", False):
            return {"task": task, "type": "atomic", "children": []}
        
        children = []
        for subtask in response["subtasks"]:
            child = self.decompose(subtask, depth + 1)
            children.append(child)
        
        return {"task": task, "type": "composite", "children": children}

方法二:基于依赖图的分解

class DependencyGraphDecomposer:
    """基于依赖图的任务分解"""
    
    def decompose(self, task: str) -> dict:
        # LLM 分析任务依赖关系
        prompt = f"""将以下任务分解为子任务,并分析它们之间的依赖关系。

任务:{task}

请输出JSON格式:
{{
    "tasks": [
        {{"id": "t1", "description": "子任务描述", "estimated_time": "短/中/长"}},
        ...
    ],
    "dependencies": [
        {{"from": "t1", "to": "t2", "type": "data|control"}},
        ...
    ]
}}"""
        
        plan = json.loads(llm.generate(prompt))
        
        # 拓扑排序确定执行顺序
        execution_order = self.topological_sort(plan["tasks"], plan["dependencies"])
        
        # 识别可并行执行的任务
        parallel_groups = self.find_parallel_groups(plan["tasks"], plan["dependencies"])
        
        return {
            "plan": plan,
            "execution_order": execution_order,
            "parallel_groups": parallel_groups
        }
    
    def topological_sort(self, tasks, dependencies):
        """拓扑排序"""
        from collections import deque
        
        graph = {t["id"]: [] for t in tasks}
        in_degree = {t["id"]: 0 for t in tasks}
        
        for dep in dependencies:
            graph[dep["from"]].append(dep["to"])
            in_degree[dep["to"]] += 1
        
        queue = deque([t for t, d in in_degree.items() if d == 0])
        order = []
        
        while queue:
            node = queue.popleft()
            order.append(node)
            for neighbor in graph[node]:
                in_degree[neighbor] -= 1
                if in_degree[neighbor] == 0:
                    queue.append(neighbor)
        
        return order
    
    def find_parallel_groups(self, tasks, dependencies):
        """识别可并行执行的任务组"""
        # 无依赖关系且无共同后续依赖的任务可以并行
        groups = []
        executed = set()
        
        for task_id in self.topological_sort(tasks, dependencies):
            deps = {d["from"] for d in dependencies if d["to"] == task_id}
            if deps.issubset(executed):
                # 可以立即执行
                if groups and not any(
                    d["to"] in [t for t in groups[-1]] 
                    for d in dependencies if d["from"] == task_id
                ):
                    groups[-1].append(task_id)
                else:
                    groups.append([task_id])
                executed.add(task_id)
        
        return groups

4.2 规划策略

ReAct(Reasoning + Acting)

class ReActAgent:
    """ReAct 模式 Agent"""
    
    def __init__(self, llm, tools: dict, max_steps=10):
        self.llm = llm
        self.tools = tools
        self.max_steps = max_steps
    
    def run(self, task: str) -> str:
        prompt = f"""你是一个能够思考和行动的AI助手。
你可以使用以下工具:{list(self.tools.keys())}

请按以下格式回答:
Thought: 我需要思考...
Action: tool_name(args)
Observation: [工具返回结果]
... (重复 Thought/Action/Observation)
Thought: 我现在可以给出最终答案了
Final Answer: 最终答案

任务:{task}"""
        
        for step in range(self.max_steps):
            response = self.llm.generate(prompt)
            
            # 解析响应
            if "Final Answer:" in response:
                return self.extract_final_answer(response)
            
            if "Action:" in response:
                tool_name, args = self.parse_action(response)
                observation = self.execute_tool(tool_name, args)
                prompt += f"\n{response}\nObservation: {observation}\n"
            else:
                prompt += f"\n{response}\n"
        
        return "达到最大步骤数限制"
    
    def execute_tool(self, tool_name: str, args: dict) -> str:
        if tool_name in self.tools:
            try:
                return str(self.tools[tool_name](**args))
            except Exception as e:
                return f"工具执行错误: {str(e)}"
        return f"未知工具: {tool_name}"

Plan-and-Execute

class PlanAndExecuteAgent:
    """先规划后执行的 Agent"""
    
    def __init__(self, planner_llm, executor_llm, tools):
        self.planner = planner_llm
        self.executor = executor_llm
        self.tools = tools
    
    def run(self, task: str) -> str:
        # 阶段1:规划
        plan = self.create_plan(task)
        print(f"计划:{len(plan['steps'])} 个步骤")
        
        # 阶段2:逐步执行
        results = []
        for i, step in enumerate(plan["steps"]):
            print(f"执行步骤 {i+1}: {step['description']}")
            
            result = self.execute_step(step, results)
            results.append({"step": step, "result": result})
            
            # 检查是否需要重新规划
            if self.should_replan(step, result, plan):
                print("检测到异常,重新规划...")
                plan = self.replan(task, results)
        
        # 阶段3:总结
        return self.summarize(task, results)
    
    def should_replan(self, step, result, plan) -> bool:
        """判断是否需要重新规划"""
        failure_indicators = ["错误", "失败", "无法", "error", "failed"]
        return any(indicator in result.lower() for indicator in failure_indicators)

5. 工具调用与外部集成

5.1 工具定义框架

from abc import ABC, abstractmethod
from typing import Any, Callable
from pydantic import BaseModel, Field

class ToolParameter(BaseModel):
    name: str
    type: str
    description: str
    required: bool = True
    default: Any = None

class ToolDefinition(BaseModel):
    name: str
    description: str
    parameters: list[ToolParameter]
    returns: str
    examples: list[dict] = []

class BaseTool(ABC):
    """工具基类"""
    
    @abstractmethod
    def definition(self) -> ToolDefinition:
        """返回工具定义"""
        pass
    
    @abstractmethod
    def execute(self, **kwargs) -> str:
        """执行工具"""
        pass
    
    def to_function_schema(self) -> dict:
        """转换为 OpenAI 函数调用格式"""
        defn = self.definition()
        properties = {}
        required = []
        
        for param in defn.parameters:
            properties[param.name] = {
                "type": param.type,
                "description": param.description
            }
            if param.required:
                required.append(param.name)
        
        return {
            "type": "function",
            "function": {
                "name": defn.name,
                "description": defn.description,
                "parameters": {
                    "type": "object",
                    "properties": properties,
                    "required": required
                }
            }
        }


# 具体工具实现示例
class WebSearchTool(BaseTool):
    """网络搜索工具"""
    
    def definition(self) -> ToolDefinition:
        return ToolDefinition(
            name="web_search",
            description="搜索互联网获取最新信息",
            parameters=[
                ToolParameter(
                    name="query",
                    type="string",
                    description="搜索关键词"
                ),
                ToolParameter(
                    name="num_results",
                    type="integer",
                    description="返回结果数量",
                    required=False,
                    default=5
                )
            ],
            returns="搜索结果列表,包含标题、URL和摘要"
        )
    
    def execute(self, query: str, num_results: int = 5, **kwargs) -> str:
        # 实际搜索实现
        import requests
        # ... 搜索逻辑
        return json.dumps(results, ensure_ascii=False)


class DatabaseQueryTool(BaseTool):
    """数据库查询工具"""
    
    def __init__(self, connection_string: str):
        self.conn = connection_string
    
    def definition(self) -> ToolDefinition:
        return ToolDefinition(
            name="query_database",
            description="执行SQL查询获取数据",
            parameters=[
                ToolParameter(
                    name="sql",
                    type="string",
                    description="SQL查询语句(只支持SELECT)"
                ),
                ToolParameter(
                    name="database",
                    type="string",
                    description="数据库名称",
                    required=False,
                    default="default"
                )
            ],
            returns="查询结果的JSON格式"
        )
    
    def execute(self, sql: str, database: str = "default", **kwargs) -> str:
        # 安全检查
        if not sql.strip().upper().startswith("SELECT"):
            return json.dumps({"error": "只允许SELECT查询"})
        
        # 执行查询
        # ... 数据库操作
        return json.dumps(results, ensure_ascii=False, default=str)

5.2 工具调用编排

class ToolOrchestrator:
    """工具调用编排器"""
    
    def __init__(self, tools: list[BaseTool]):
        self.tools = {t.definition().name: t for t in tools}
        self.schemas = [t.to_function_schema() for t in tools]
        self.call_history = []
    
    def plan_tool_calls(self, task: str, context: dict = None) -> list[dict]:
        """使用 LLM 规划工具调用序列"""
        prompt = f"""根据任务需求,规划需要调用的工具序列。

任务:{task}
可用工具:{list(self.tools.keys())}
上下文:{json.dumps(context or {}, ensure_ascii=False)}

请输出工具调用计划(JSON数组):
[
    {{"tool": "tool_name", "args": {{}}, "purpose": "调用目的"}},
    ...
]

注意:
- 考虑工具之间的数据依赖关系
- 如果后续工具需要前面工具的输出,用 $step_N 引用
- 尽量减少不必要的工具调用"""
        
        plan = json.loads(llm.generate(prompt))
        return plan
    
    def execute_plan(self, plan: list[dict]) -> dict:
        """执行工具调用计划"""
        results = {}
        
        for i, step in enumerate(plan):
            tool_name = step["tool"]
            args = step["args"]
            
            # 解析引用($step_N → 之前步骤的结果)
            resolved_args = self.resolve_references(args, results)
            
            # 执行工具
            if tool_name in self.tools:
                try:
                    result = self.tools[tool_name].execute(**resolved_args)
                    results[f"step_{i}"] = {
                        "status": "success",
                        "result": result,
                        "tool": tool_name
                    }
                except Exception as e:
                    results[f"step_{i}"] = {
                        "status": "error",
                        "error": str(e),
                        "tool": tool_name
                    }
            else:
                results[f"step_{i}"] = {
                    "status": "error",
                    "error": f"未知工具: {tool_name}"
                }
            
            self.call_history.append({
                "step": i,
                "tool": tool_name,
                "args": resolved_args,
                "result": results[f"step_{i}"]
            })
        
        return results
    
    def resolve_references(self, args: dict, results: dict) -> dict:
        """解析参数中的引用"""
        resolved = {}
        for key, value in args.items():
            if isinstance(value, str) and value.startswith("$step_"):
                step_key = value[1:]  # 去掉 $
                if step_key in results and results[step_key]["status"] == "success":
                    resolved[key] = results[step_key]["result"]
                else:
                    resolved[key] = value  # 保留原始引用
            else:
                resolved[key] = value
        return resolved

5.3 常用工具集成

# 常用工具集合
class ToolKit:
    """预置工具集合"""
    
    @staticmethod
    def get_default_tools() -> list[BaseTool]:
        return [
            WebSearchTool(),
            DatabaseQueryTool(connection_string="..."),
            FileReadTool(),
            FileWriteTool(),
            CodeExecutionTool(),
            EmailSenderTool(),
            CalendarTool(),
            APICallerTool(),
        ]

class CodeExecutionTool(BaseTool):
    """安全的代码执行工具"""
    
    def definition(self) -> ToolDefinition:
        return ToolDefinition(
            name="execute_code",
            description="在安全沙箱中执行Python代码",
            parameters=[
                ToolParameter(
                    name="code",
                    type="string",
                    description="要执行的Python代码"
                ),
                ToolParameter(
                    name="timeout",
                    type="integer",
                    description="超时时间(秒)",
                    required=False,
                    default=30
                )
            ],
            returns="代码执行的输出结果"
        )
    
    def execute(self, code: str, timeout: int = 30, **kwargs) -> str:
        import subprocess
        import tempfile
        
        # 安全检查
        dangerous_patterns = [
            "import os", "subprocess", "exec(", "eval(",
            "open('/etc", "open('/proc", "__import__"
        ]
        for pattern in dangerous_patterns:
            if pattern in code:
                return f"安全拒绝:代码包含危险操作 '{pattern}'"
        
        # 在沙箱中执行
        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
            f.write(code)
            f.flush()
            
            try:
                result = subprocess.run(
                    ["python3", f.name],
                    capture_output=True,
                    text=True,
                    timeout=timeout
                )
                return result.stdout + result.stderr
            except subprocess.TimeoutExpired:
                return f"执行超时({timeout}秒)"

6. 状态管理与上下文传递

6.1 工作流状态设计

from datetime import datetime
from enum import Enum
from typing import Any, Optional

class WorkflowStatus(Enum):
    PENDING = "pending"
    RUNNING = "running"
    PAUSED = "paused"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"

class WorkflowState:
    """工作流状态管理"""
    
    def __init__(self, workflow_id: str):
        self.workflow_id = workflow_id
        self.status = WorkflowStatus.PENDING
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
        
        # 执行状态
        self.current_step = 0
        self.total_steps = 0
        self.step_results = {}
        self.errors = []
        
        # 上下文数据
        self.context = {}
        self.variables = {}
        self.checkpoints = []
    
    def update_step(self, step_id: str, result: Any, status: str = "completed"):
        """更新步骤状态"""
        self.step_results[step_id] = {
            "result": result,
            "status": status,
            "timestamp": datetime.now().isoformat()
        }
        self.current_step += 1
        self.updated_at = datetime.now()
    
    def set_variable(self, key: str, value: Any):
        """设置工作流变量"""
        self.variables[key] = value
        self.updated_at = datetime.now()
    
    def get_variable(self, key: str, default=None) -> Any:
        """获取工作流变量"""
        return self.variables.get(key, default)
    
    def create_checkpoint(self):
        """创建检查点(用于恢复)"""
        checkpoint = {
            "step": self.current_step,
            "variables": dict(self.variables),
            "step_results": dict(self.step_results),
            "timestamp": datetime.now().isoformat()
        }
        self.checkpoints.append(checkpoint)
    
    def restore_checkpoint(self, index: int = -1):
        """从检查点恢复"""
        if not self.checkpoints:
            raise ValueError("没有可用的检查点")
        
        checkpoint = self.checkpoints[index]
        self.current_step = checkpoint["step"]
        self.variables = dict(checkpoint["variables"])
        self.step_results = dict(checkpoint["step_results"])
        self.status = WorkflowStatus.RUNNING
    
    def to_dict(self) -> dict:
        """序列化为字典(用于持久化)"""
        return {
            "workflow_id": self.workflow_id,
            "status": self.status.value,
            "current_step": self.current_step,
            "total_steps": self.total_steps,
            "step_results": self.step_results,
            "variables": self.variables,
            "errors": self.errors,
            "created_at": self.created_at.isoformat(),
            "updated_at": self.updated_at.isoformat()
        }
    
    @classmethod
    def from_dict(cls, data: dict) -> "WorkflowState":
        """从字典反序列化"""
        state = cls(data["workflow_id"])
        state.status = WorkflowStatus(data["status"])
        state.current_step = data["current_step"]
        state.total_steps = data["total_steps"]
        state.step_results = data["step_results"]
        state.variables = data["variables"]
        state.errors = data["errors"]
        return state

6.2 上下文窗口管理

class ContextManager:
    """上下文管理器 - 控制传递给 LLM 的上下文"""
    
    def __init__(self, max_tokens: int = 4096):
        self.max_tokens = max_tokens
        self.messages = []
        self.system_prompt = ""
        self.summaries = []  # 历史摘要
    
    def add_message(self, role: str, content: str):
        """添加消息"""
        self.messages.append({
            "role": role,
            "content": content,
            "timestamp": datetime.now().isoformat()
        })
        
        # 检查是否需要压缩
        if self._estimate_tokens() > self.max_tokens * 0.8:
            self._compress()
    
    def get_messages(self, include_summary: bool = True) -> list[dict]:
        """获取当前上下文消息"""
        messages = []
        
        # 系统提示词
        if self.system_prompt:
            messages.append({"role": "system", "content": self.system_prompt})
        
        # 历史摘要
        if include_summary and self.summaries:
            summary_text = "\n".join(self.summaries[-3:])  # 最近3条摘要
            messages.append({
                "role": "system", 
                "content": f"历史对话摘要:\n{summary_text}"
            })
        
        # 当前消息
        messages.extend(self.messages)
        
        return messages
    
    def _compress(self):
        """压缩历史消息"""
        if len(self.messages) < 6:
            return
        
        # 保留最近的消息
        keep_recent = 4
        old_messages = self.messages[:-keep_recent]
        
        # 生成摘要
        summary_prompt = "请用3-5句话总结以下对话的要点:\n"
        for msg in old_messages:
            summary_prompt += f"[{msg['role']}]: {msg['content'][:200]}\n"
        
        summary = llm.generate(summary_prompt)
        self.summaries.append(summary)
        
        # 只保留最近的消息
        self.messages = self.messages[-keep_recent:]
    
    def _estimate_tokens(self) -> int:
        """粗略估算 token 数"""
        total_chars = sum(len(m["content"]) for m in self.messages)
        return total_chars // 2  # 粗略估算:2字符≈1token

6.3 持久化存储

import json
import sqlite3
from pathlib import Path

class WorkflowStore:
    """工作流状态持久化存储"""
    
    def __init__(self, db_path: str = "workflows.db"):
        self.db_path = db_path
        self._init_db()
    
    def _init_db(self):
        conn = sqlite3.connect(self.db_path)
        conn.execute("""
            CREATE TABLE IF NOT EXISTS workflows (
                workflow_id TEXT PRIMARY KEY,
                state_json TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        conn.execute("""
            CREATE TABLE IF NOT EXISTS workflow_logs (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                workflow_id TEXT NOT NULL,
                step_id TEXT,
                event_type TEXT,
                event_data TEXT,
                timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (workflow_id) REFERENCES workflows(workflow_id)
            )
        """)
        conn.commit()
        conn.close()
    
    def save_state(self, state: WorkflowState):
        """保存工作流状态"""
        conn = sqlite3.connect(self.db_path)
        conn.execute(
            """INSERT OR REPLACE INTO workflows (workflow_id, state_json, updated_at)
               VALUES (?, ?, CURRENT_TIMESTAMP)""",
            (state.workflow_id, json.dumps(state.to_dict(), ensure_ascii=False))
        )
        conn.commit()
        conn.close()
    
    def load_state(self, workflow_id: str) -> Optional[WorkflowState]:
        """加载工作流状态"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.execute(
            "SELECT state_json FROM workflows WHERE workflow_id = ?",
            (workflow_id,)
        )
        row = cursor.fetchone()
        conn.close()
        
        if row:
            return WorkflowState.from_dict(json.loads(row[0]))
        return None
    
    def log_event(self, workflow_id: str, step_id: str, event_type: str, data: dict):
        """记录工作流事件"""
        conn = sqlite3.connect(self.db_path)
        conn.execute(
            """INSERT INTO workflow_logs (workflow_id, step_id, event_type, event_data)
               VALUES (?, ?, ?, ?)""",
            (workflow_id, step_id, event_type, json.dumps(data, ensure_ascii=False))
        )
        conn.commit()
        conn.close()

7. 错误处理与容错机制

7.1 错误分类与处理策略

from enum import Enum
from typing import Callable

class ErrorSeverity(Enum):
    LOW = "low"          # 可忽略,继续执行
    MEDIUM = "medium"    # 需要重试
    HIGH = "high"        # 需要回退到上一个检查点
    CRITICAL = "critical" # 需要终止工作流

class ErrorHandler:
    """统一错误处理器"""
    
    def __init__(self):
        self.strategies = {}
        self.retry_config = {
            "max_retries": 3,
            "backoff_factor": 2,
            "initial_delay": 1
        }
    
    def register_strategy(self, error_type: type, strategy: Callable):
        """注册错误处理策略"""
        self.strategies[error_type] = strategy
    
    def handle(self, error: Exception, context: dict) -> dict:
        """处理错误"""
        error_type = type(error)
        
        # 查找匹配的处理策略
        if error_type in self.strategies:
            return self.strategies[error_type](error, context)
        
        # 默认处理策略
        severity = self.classify_error(error)
        
        if severity == ErrorSeverity.LOW:
            return {"action": "continue", "message": str(error)}
        elif severity == ErrorSeverity.MEDIUM:
            return {"action": "retry", "message": str(error)}
        elif severity == ErrorSeverity.HIGH:
            return {"action": "rollback", "message": str(error)}
        else:
            return {"action": "abort", "message": str(error)}
    
    def classify_error(self, error: Exception) -> ErrorSeverity:
        """错误严重性分类"""
        if isinstance(error, (TimeoutError, ConnectionError)):
            return ErrorSeverity.MEDIUM
        elif isinstance(error, (ValueError, KeyError)):
            return ErrorSeverity.LOW
        elif isinstance(error, (PermissionError, MemoryError)):
            return ErrorSeverity.CRITICAL
        return ErrorSeverity.MEDIUM


class RetryManager:
    """重试管理器"""
    
    def __init__(self, max_retries=3, backoff_factor=2):
        self.max_retries = max_retries
        self.backoff_factor = backoff_factor
    
    def execute_with_retry(self, func: Callable, *args, **kwargs):
        """带重试的执行"""
        import time
        
        last_error = None
        delay = 1
        
        for attempt in range(self.max_retries + 1):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                last_error = e
                if attempt < self.max_retries:
                    print(f"尝试 {attempt + 1} 失败: {e}, {delay}秒后重试...")
                    time.sleep(delay)
                    delay *= self.backoff_factor
        
        raise last_error

7.2 工作流级容错

class ResilientWorkflow:
    """具备容错能力的工作流"""
    
    def __init__(self, store: WorkflowStore):
        self.store = store
        self.error_handler = ErrorHandler()
        self.retry_manager = RetryManager()
    
    def execute(self, state: WorkflowState, steps: list) -> WorkflowState:
        """容错执行工作流"""
        state.status = WorkflowStatus.RUNNING
        
        for i, step in enumerate(steps[state.current_step:], start=state.current_step):
            state.current_step = i
            
            # 创建检查点
            if i % 5 == 0:  # 每5步创建一次检查点
                state.create_checkpoint()
                self.store.save_state(state)
            
            try:
                # 带重试的步骤执行
                result = self.retry_manager.execute_with_retry(
                    step.execute, state.context
                )
                state.update_step(step.id, result)
                
            except Exception as e:
                # 错误处理
                action = self.error_handler.handle(e, {
                    "step": step,
                    "state": state,
                    "attempt": i
                })
                
                if action["action"] == "continue":
                    state.update_step(step.id, None, status="skipped")
                    continue
                elif action["action"] == "retry":
                    # 已在重试管理器中处理
                    pass
                elif action["action"] == "rollback":
                    state.restore_checkpoint()
                    i = state.current_step - 1  # 回退后重新开始
                    continue
                else:  # abort
                    state.status = WorkflowStatus.FAILED
                    state.errors.append({
                        "step": i,
                        "error": str(e),
                        "action": "abort"
                    })
                    self.store.save_state(state)
                    raise
        
        state.status = WorkflowStatus.COMPLETED
        self.store.save_state(state)
        return state

7.3 LLM 调用容错

class LLMFallbackChain:
    """LLM 降级链 - 主模型失败时自动切换备选"""
    
    def __init__(self):
        self.models = []
    
    def add_model(self, name: str, client, model: str, priority: int = 0):
        """添加模型到降级链"""
        self.models.append({
            "name": name,
            "client": client,
            "model": model,
            "priority": priority
        })
        self.models.sort(key=lambda x: x["priority"], reverse=True)
    
    def generate(self, prompt: str, **kwargs) -> str:
        """带降级的 LLM 调用"""
        errors = []
        
        for model_info in self.models:
            try:
                response = model_info["client"].chat.completions.create(
                    model=model_info["model"],
                    messages=[{"role": "user", "content": prompt}],
                    **kwargs
                )
                return response.choices[0].message.content
            except Exception as e:
                errors.append(f"{model_info['name']}: {str(e)}")
                print(f"模型 {model_info['name']} 失败,尝试下一个...")
                continue
        
        raise RuntimeError(f"所有模型均失败:\n" + "\n".join(errors))

# 使用示例
llm_chain = LLMFallbackChain()
llm_chain.add_model("primary", openai_client, "gpt-4o", priority=10)
llm_chain.add_model("secondary", deepseek_client, "deepseek-chat", priority=5)
llm_chain.add_model("fallback", local_client, "qwen2.5-7b", priority=1)

8. 人机协作(Human-in-the-Loop)

8.1 HITL 设计模式

from abc import ABC, abstractmethod
from enum import Enum
from typing import Optional

class ApprovalStatus(Enum):
    APPROVED = "approved"
    REJECTED = "rejected"
    MODIFIED = "modified"
    PENDING = "pending"

class HumanCheckpoint:
    """人工检查点"""
    
    def __init__(self, checkpoint_id: str, prompt: str, options: list[str] = None):
        self.checkpoint_id = checkpoint_id
        self.prompt = prompt
        self.options = options or ["approve", "reject", "modify"]
        self.status = ApprovalStatus.PENDING
        self.feedback = None
        self.modified_result = None
    
    def to_dict(self) -> dict:
        return {
            "checkpoint_id": self.checkpoint_id,
            "prompt": self.prompt,
            "options": self.options,
            "status": self.status.value,
            "feedback": self.feedback
        }

class HumanInTheLoopWorkflow:
    """支持人机协作的工作流"""
    
    def __init__(self):
        self.checkpoints = {}
        self.pending_approvals = []
        self.approval_callbacks = {}
    
    def register_checkpoint(self, step_id: str, checkpoint: HumanCheckpoint,
                           on_approve: Callable = None, on_reject: Callable = None):
        """注册需要人工审批的检查点"""
        self.checkpoints[step_id] = checkpoint
        if on_approve:
            self.approval_callbacks[f"{step_id}_approve"] = on_approve
        if on_reject:
            self.approval_callbacks[f"{step_id}_reject"] = on_reject
    
    def request_approval(self, step_id: str, context: dict) -> ApprovalStatus:
        """请求人工审批"""
        if step_id not in self.checkpoints:
            return ApprovalStatus.APPROVED  # 无检查点则自动通过
        
        checkpoint = self.checkpoints[step_id]
        
        # 展示给用户
        print(f"\n{'='*60}")
        print(f"⏳ 需要人工审批")
        print(f"步骤: {step_id}")
        print(f"说明: {checkpoint.prompt}")
        print(f"上下文: {json.dumps(context, ensure_ascii=False, indent=2)[:500]}")
        print(f"选项: {', '.join(checkpoint.options)}")
        print(f"{'='*60}")
        
        # 等待用户输入
        user_input = input("请输入决策 (approve/reject/modify): ").strip().lower()
        
        if user_input == "approve":
            checkpoint.status = ApprovalStatus.APPROVED
            if f"{step_id}_approve" in self.approval_callbacks:
                self.approval_callbacks[f"{step_id}_approve"]()
        elif user_input == "reject":
            checkpoint.status = ApprovalStatus.REJECTED
            checkpoint.feedback = input("请输入拒绝原因: ")
            if f"{step_id}_reject" in self.approval_callbacks:
                self.approval_callbacks[f"{step_id}_reject"]()
        elif user_input == "modify":
            checkpoint.status = ApprovalStatus.MODIFIED
            checkpoint.modified_result = input("请输入修改后的内容: ")
        
        return checkpoint.status

# 使用示例
hitl = HumanInTheLoopWorkflow()

# 在关键步骤注册审批点
hitl.register_checkpoint(
    step_id="send_email",
    checkpoint=HumanCheckpoint(
        checkpoint_id="email_approval",
        prompt="即将发送以下邮件,请确认",
        options=["approve", "reject", "modify"]
    ),
    on_approve=lambda: print("邮件已发送"),
    on_reject=lambda: print("邮件已取消")
)

8.2 异步审批系统

import asyncio
from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class ApprovalRequest:
    request_id: str
    workflow_id: str
    step_id: str
    description: str
    data: dict
    status: str = "pending"
    created_at: datetime = field(default_factory=datetime.now)
    resolved_at: Optional[datetime] = None
    resolver: Optional[str] = None
    decision: Optional[str] = None
    comments: Optional[str] = None

class AsyncApprovalSystem:
    """异步审批系统"""
    
    def __init__(self):
        self.pending_requests: dict[str, ApprovalRequest] = {}
        self.approval_events: dict[str, asyncio.Event] = {}
    
    async def request_approval(self, request: ApprovalRequest) -> ApprovalRequest:
        """发起审批请求并等待"""
        self.pending_requests[request.request_id] = request
        self.approval_events[request.request_id] = asyncio.Event()
        
        # 通知审批者(可通过邮件、Slack、Web UI等)
        await self.notify_approvers(request)
        
        # 等待审批结果
        try:
            await asyncio.wait_for(
                self.approval_events[request.request_id].wait(),
                timeout=3600  # 1小时超时
            )
        except asyncio.TimeoutError:
            request.status = "timeout"
        
        return request
    
    def resolve_approval(self, request_id: str, decision: str,
                        resolver: str, comments: str = None):
        """审批者做出决定"""
        if request_id in self.pending_requests:
            request = self.pending_requests[request_id]
            request.status = decision
            request.decision = decision
            request.resolver = resolver
            request.comments = comments
            request.resolved_at = datetime.now()
            
            # 通知等待中的工作流
            if request_id in self.approval_events:
                self.approval_events[request_id].set()
    
    async def notify_approvers(self, request: ApprovalRequest):
        """通知审批者"""
        # 集成通知系统
        notification = {
            "title": f"需要审批: {request.description}",
            "workflow_id": request.workflow_id,
            "step": request.step_id,
            "data_preview": str(request.data)[:200],
            "action_url": f"/approval/{request.request_id}"
        }
        # 发送到 Slack/邮件/Webhook 等
        print(f"审批通知已发送: {notification['title']}")

8.3 渐进式自动化

class ProgressiveAutomation:
    """渐进式自动化 - 随信任度提升逐步减少人工干预"""
    
    def __init__(self):
        self.trust_scores = {}  # 步骤 → 信任度
        self.success_history = {}  # 步骤 → 成功记录
        self.approval_threshold = 0.9  # 信任度阈值
    
    def should_require_approval(self, step_id: str, context: dict) -> bool:
        """判断是否需要人工审批"""
        trust = self.trust_scores.get(step_id, 0.5)
        
        # 高风险操作始终需要审批
        high_risk_operations = ["delete", "send_email", "deploy", "payment"]
        if any(risk in step_id.lower() for risk in high_risk_operations):
            return True
        
        # 根据信任度决定
        return trust < self.approval_threshold
    
    def update_trust(self, step_id: str, success: bool):
        """更新信任度"""
        if step_id not in self.success_history:
            self.success_history[step_id] = []
        
        self.success_history[step_id].append(success)
        
        # 计算近期成功率
        recent = self.success_history[step_id][-20:]  # 最近20次
        success_rate = sum(recent) / len(recent)
        
        # 平滑更新信任度
        current_trust = self.trust_scores.get(step_id, 0.5)
        self.trust_scores[step_id] = current_trust * 0.7 + success_rate * 0.3
        
        print(f"[{step_id}] 信任度更新: {current_trust:.2f} → {self.trust_scores[step_id]:.2f}")

9. 主流框架对比

9.1 LangGraph

LangGraph 是 LangChain 团队开发的图状态机框架,适合构建复杂的、有状态的 Agent 工作流。

# LangGraph 核心概念示例
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
import operator

class AgentState(TypedDict):
    """工作流状态定义"""
    messages: Annotated[list, operator.add]
    current_agent: str
    task: str
    results: dict
    iteration: int

def researcher(state: AgentState) -> AgentState:
    """研究Agent"""
    task = state["task"]
    # 执行研究...
    research_result = f"关于'{task}'的研究结果..."
    return {
        "messages": [f"研究员: {research_result}"],
        "results": {"research": research_result}
    }

def writer(state: AgentState) -> AgentState:
    """写作Agent"""
    research = state["results"].get("research", "")
    article = f"基于研究撰写的文章..."
    return {
        "messages": [f"作者: {article}"],
        "results": {**state["results"], "article": article}
    }

def reviewer(state: AgentState) -> AgentState:
    """审阅Agent"""
    article = state["results"].get("article", "")
    review = "审阅通过,质量良好"
    return {
        "messages": [f"审阅者: {review}"],
        "results": {**state["results"], "review": review}
    }

def should_continue(state: AgentState) -> str:
    """条件路由"""
    if state["iteration"] >= 3:
        return "end"
    review = state["results"].get("review", "")
    if "通过" in review:
        return "end"
    return "revise"

# 构建工作流图
graph = StateGraph(AgentState)

# 添加节点
graph.add_node("researcher", researcher)
graph.add_node("writer", writer)
graph.add_node("reviewer", reviewer)

# 添加边
graph.add_edge(START, "researcher")
graph.add_edge("researcher", "writer")
graph.add_edge("writer", "reviewer")
graph.add_conditional_edges(
    "reviewer",
    should_continue,
    {
        "end": END,
        "revise": "writer"  # 审阅不通过则重新写作
    }
)

# 编译并运行
workflow = graph.compile()
result = workflow.invoke({
    "messages": [],
    "current_agent": "researcher",
    "task": "写一篇关于AI Agent的技术博客",
    "results": {},
    "iteration": 0
})

LangGraph 特点:

  • ✅ 图结构清晰,状态流转可视化
  • ✅ 内置检查点和恢复机制
  • ✅ 与 LangChain 生态深度集成
  • ❌ 学习曲线较陡
  • ❌ 对简单场景显得过于复杂

9.2 CrewAI

CrewAI 采用"团队协作"隐喻,让多个 Agent 扮演不同角色共同完成任务。

# CrewAI 核心概念示例
from crewai import Agent, Task, Crew, Process

# 定义 Agent(角色)
researcher = Agent(
    role="资深研究分析师",
    goal="收集和分析关于{topic}的最新、最准确的信息",
    backstory="""你是一位经验丰富的研究分析师,
    擅长从多个信息源获取数据并进行深入分析。
    你的分析总是基于事实和数据。""",
    verbose=True,
    allow_delegation=False,
    tools=[search_tool, browse_tool]
)

writer = Agent(
    role="技术内容创作者",
    goal="将复杂的技术概念转化为通俗易懂的优质内容",
    backstory="""你是一位出色的技术写作者,
    擅长将深奥的技术知识用生动的语言表达出来。
    你的文章总是兼具深度和可读性。""",
    verbose=True,
    allow_delegation=False,
    tools=[file_write_tool]
)

editor = Agent(
    role="资深编辑",
    goal="确保内容质量达到发布标准",
    backstory="""你是一位严格但公正的编辑,
    对内容质量有极高的要求。
    你关注准确性、逻辑性和可读性。""",
    verbose=True,
    allow_delegation=True
)

# 定义任务
research_task = Task(
    description="""研究{topic}的最新发展,包括:
    1. 核心技术原理
    2. 最新研究进展
    3. 实际应用案例
    4. 未来发展趋势""",
    expected_output="详细的研究报告,包含数据来源",
    agent=researcher
)

writing_task = Task(
    description="""基于研究报告,撰写一篇技术博客文章:
    - 标题吸引人
    - 结构清晰(引言、正文、结论)
    - 包含代码示例
    - 适合中级开发者阅读""",
    expected_output="2000-3000字的技术博客文章",
    agent=writer
)

review_task = Task(
    description="""审阅文章并提出修改建议:
    - 事实准确性
    - 逻辑连贯性
    - 技术细节正确性
    - 语言表达质量""",
    expected_output="审阅报告和具体修改建议",
    agent=editor
)

# 组建团队
crew = Crew(
    agents=[researcher, writer, editor],
    tasks=[research_task, writing_task, review_task],
    process=Process.sequential,  # 顺序执行
    verbose=True
)

# 执行任务
result = crew.kickoff(inputs={"topic": "Agentic AI"})
print(result)

CrewAI 特点:

  • ✅ 角色隐喻直观,易上手
  • ✅ 内置任务委派和协作机制
  • ✅ 适合模拟团队工作场景
  • ❌ 自定义控制能力有限
  • ❌ 复杂工作流表达能力不如 LangGraph

9.3 AutoGen

微软开源的多 Agent 对话框架,强调 Agent 间的自然对话协作。

# AutoGen 核心概念示例
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager

# 配置 LLM
llm_config = {
    "model": "gpt-4o",
    "temperature": 0.7,
    "api_key": "your-api-key"
}

# 创建 Agent
planner = AssistantAgent(
    name="Planner",
    system_message="""你是一个项目规划专家。
    你的职责是分析需求、制定计划、分配任务。
    当你认为计划已经完善时,说 'PLAN_COMPLETE'。""",
    llm_config=llm_config
)

coder = AssistantAgent(
    name="Coder",
    system_message="""你是一个高级Python开发者。
    你根据计划编写高质量的代码。
    你只写代码,不做其他事情。
    代码块请用 ```python ... ``` 包裹。""",
    llm_config=llm_config
)

reviewer = AssistantAgent(
    name="Reviewer",
    system_message="""你是一个代码审查专家。
    你审查代码的质量、安全性和最佳实践。
    如果代码符合要求,说 'CODE_APPROVED'。
    否则,给出具体的修改建议。""",
    llm_config=llm_config
)

# 用户代理(代表人类参与对话)
user_proxy = UserProxyAgent(
    name="User",
    human_input_mode="TERMINATE",  # 最终结果时询问用户
    max_consecutive_auto_reply=10,
    code_execution_config={
        "work_dir": "workspace",
        "use_docker": True  # 安全沙箱执行
    }
)

# 创建群聊
group_chat = GroupChat(
    agents=[user_proxy, planner, coder, reviewer],
    messages=[],
    max_round=20,
    speaker_selection_method="auto"  # 自动选择下一个发言者
)

manager = GroupChatManager(
    groupchat=group_chat,
    llm_config=llm_config
)

# 启动对话
user_proxy.initiate_chat(
    manager,
    message="请帮我开发一个命令行待办事项管理工具,支持增删改查和优先级排序。"
)

AutoGen 特点:

  • ✅ 对话式协作,自然灵活
  • ✅ 内置代码执行沙箱
  • ✅ 支持人类随时介入对话
  • ❌ 对话式架构难以精确控制流程
  • ❌ 复杂工作流需要大量提示词工程

9.4 框架选型指南

需求场景                          推荐框架      理由
──────────────────────────────────────────────────────────
复杂有状态工作流                  LangGraph    图结构,状态管理强大
团队协作模拟                      CrewAI       角色隐喻,开箱即用
探索性研究/头脑风暴               AutoGen      对话式,灵活自由
需要精确流程控制                  LangGraph    显式状态机
快速原型/简单场景                 CrewAI       上手最快
代码生成与执行                    AutoGen      内置沙箱
企业级生产部署                    LangGraph    检查点、监控最完善

10. 企业级工作流部署与监控

10.1 部署架构

# docker-compose.yml - 工作流服务部署
version: '3.8'

services:
  # 工作流引擎
  workflow-engine:
    build: ./engine
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/workflows
      - REDIS_URL=redis://redis:6379
      - LLM_API_KEY=${LLM_API_KEY}
    depends_on:
      - db
      - redis
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 4G
          cpus: '2'

  # 任务队列
  task-worker:
    build: ./worker
    environment:
      - BROKER_URL=redis://redis:6379
      - DATABASE_URL=postgresql://user:pass@db:5432/workflows
    depends_on:
      - redis
      - db
    deploy:
      replicas: 5

  # 数据库
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: workflows
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass

  # 缓存与消息队列
  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

  # 监控
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    depends_on:
      - prometheus

volumes:
  pgdata:
  redisdata:

10.2 监控指标

from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time

# 定义监控指标
workflow_total = Counter(
    'workflow_total',
    '工作流执行总数',
    ['workflow_type', 'status']
)

workflow_duration = Histogram(
    'workflow_duration_seconds',
    '工作流执行耗时',
    ['workflow_type'],
    buckets=[1, 5, 10, 30, 60, 120, 300, 600]
)

active_workflows = Gauge(
    'active_workflows',
    '当前活跃工作流数量'
)

agent_calls = Counter(
    'agent_calls_total',
    'Agent 调用次数',
    ['agent_name', 'tool_name', 'status']
)

llm_tokens = Counter(
    'llm_tokens_total',
    'LLM Token 使用量',
    ['model', 'type']  # type: input/output
)

llm_latency = Histogram(
    'llm_latency_seconds',
    'LLM 调用延迟',
    ['model']
)


class MetricsCollector:
    """指标收集器"""
    
    def __init__(self):
        self.start_http_server()
    
    def start_http_server(self):
        """启动指标暴露端口"""
        start_http_server(9100)
    
    def record_workflow_start(self, workflow_type: str):
        active_workflows.inc()
    
    def record_workflow_end(self, workflow_type: str, status: str, duration: float):
        active_workflows.dec()
        workflow_total.labels(workflow_type=workflow_type, status=status).inc()
        workflow_duration.labels(workflow_type=workflow_type).observe(duration)
    
    def record_agent_call(self, agent_name: str, tool_name: str, 
                          status: str, duration: float):
        agent_calls.labels(
            agent_name=agent_name,
            tool_name=tool_name,
            status=status
        ).inc()
    
    def record_llm_usage(self, model: str, input_tokens: int, output_tokens: int,
                         latency: float):
        llm_tokens.labels(model=model, type="input").inc(input_tokens)
        llm_tokens.labels(model=model, type="output").inc(output_tokens)
        llm_latency.labels(model=model).observe(latency)

10.3 可观测性

import logging
import json
from datetime import datetime
from contextlib import contextmanager

class WorkflowLogger:
    """结构化工作流日志"""
    
    def __init__(self, workflow_id: str):
        self.workflow_id = workflow_id
        self.logger = logging.getLogger(f"workflow.{workflow_id}")
        self.logger.setLevel(logging.INFO)
        
        # JSON 格式化器
        handler = logging.StreamHandler()
        handler.setFormatter(JsonFormatter())
        self.logger.addHandler(handler)
    
    @contextmanager
    def trace_step(self, step_id: str, agent_name: str):
        """步骤执行追踪"""
        start_time = time.time()
        span = {
            "workflow_id": self.workflow_id,
            "step_id": step_id,
            "agent": agent_name,
            "start_time": datetime.now().isoformat()
        }
        
        self.logger.info(f"步骤开始: {step_id}", extra={"span": span, "event": "step_start"})
        
        try:
            yield span
            span["status"] = "success"
        except Exception as e:
            span["status"] = "error"
            span["error"] = str(e)
            self.logger.error(f"步骤失败: {step_id} - {e}", extra={"span": span, "event": "step_error"})
            raise
        finally:
            span["duration_ms"] = (time.time() - start_time) * 1000
            self.logger.info(f"步骤完成: {step_id}", extra={"span": span, "event": "step_end"})
    
    def log_decision(self, decision_point: str, options: list, chosen: str, reasoning: str):
        """记录决策点"""
        self.logger.info("决策点", extra={
            "event": "decision",
            "workflow_id": self.workflow_id,
            "decision_point": decision_point,
            "options": options,
            "chosen": chosen,
            "reasoning": reasoning
        })

class JsonFormatter(logging.Formatter):
    """JSON 日志格式化器"""
    def format(self, record):
        log_data = {
            "timestamp": datetime.now().isoformat(),
            "level": record.levelname,
            "message": record.getMessage(),
            "logger": record.name
        }
        
        if hasattr(record, 'span'):
            log_data["span"] = record.span
        if hasattr(record, 'event'):
            log_data["event"] = record.event
        
        return json.dumps(log_data, ensure_ascii=False)

10.4 成本控制

class CostController:
    """成本控制器"""
    
    def __init__(self, budget_config: dict):
        self.budget = budget_config
        self.usage = {
            "tokens": 0,
            "api_calls": 0,
            "compute_seconds": 0
        }
    
    def check_budget(self, estimated_cost: float) -> bool:
        """检查是否超出预算"""
        daily_budget = self.budget.get("daily_limit_usd", 100)
        current_spend = self.get_current_spend()
        
        if current_spend + estimated_cost > daily_budget:
            return False
        return True
    
    def get_optimization_suggestions(self) -> list[str]:
        """获取成本优化建议"""
        suggestions = []
        
        # 分析 token 使用
        if self.usage["tokens"] > 1000000:
            suggestions.append(
                "Token 使用量过高,考虑:\n"
                "1. 使用更短的提示词模板\n"
                "2. 限制输出长度(max_tokens)\n"
                "3. 使用更便宜的模型处理简单任务"
            )
        
        # 分析模型选择
        suggestions.append(
            "成本优化建议:\n"
            "- 简单分类/提取任务 → 使用 GPT-4o-mini\n"
            "- 代码生成 → 使用 DeepSeek Coder\n"
            "- 复杂推理 → 使用 GPT-4o 或 Claude"
        )
        
        return suggestions

    def estimate_cost(self, model: str, input_tokens: int, output_tokens: int) -> float:
        """估算调用成本"""
        pricing = {
            "gpt-4o": {"input": 2.5, "output": 10.0},       # $/1M tokens
            "gpt-4o-mini": {"input": 0.15, "output": 0.6},
            "deepseek-chat": {"input": 0.14, "output": 0.28},
            "claude-3-5-sonnet": {"input": 3.0, "output": 15.0},
        }
        
        if model not in pricing:
            return 0.0
        
        rate = pricing[model]
        cost = (input_tokens * rate["input"] + output_tokens * rate["output"]) / 1_000_000
        return cost

10.5 生产部署清单

## 生产环境部署清单

### 安全性
- [ ] API Key 使用环境变量或密钥管理服务,不硬编码
- [ ] 用户输入进行严格的提示词注入防护
- [ ] 工具调用设置权限白名单
- [ ] 敏感数据脱敏后再传给 LLM
- [ ] 代码执行在沙箱环境中进行

### 可靠性
- [ ] LLM 调用设置超时和重试机制
- [ ] 关键步骤设置检查点,支持断点恢复
- [ ] 异常情况有降级方案(如使用更小的模型)
- [ ] 工作流状态持久化到数据库
- [ ] 实现幂等性(重复执行不产生副作用)

### 性能
- [ ] 非关键路径使用异步执行
- [ ] LLM 响应流式输出,降低感知延迟
- [ ] 相似请求结果缓存
- [ ] 合理设置上下文窗口大小
- [ ] 监控并优化 token 使用量

### 可观测性
- [ ] 结构化日志,包含 workflow_id、step_id
- [ ] 关键指标暴露给 Prometheus
- [ ] Grafana 面板:成功率、延迟、成本
- [ ] 异常告警(失败率 > 5%、延迟 > 阈值)
- [ ] 定期生成成本报告

### 运维
- [ ] 工作流版本管理,支持回滚
- [ ] 灰度发布新版本工作流
- [ ] 文档化的故障排查手册
- [ ] 定期备份工作流定义和执行历史

总结

Agentic Workflow 是构建下一代 AI 应用的核心架构模式。本教程覆盖了从基础概念到企业级部署的完整知识体系:

  1. 设计模式:掌握顺序、并行、条件、循环、层级五种基本模式,能够组合应对各种复杂场景
  2. 多 Agent 协作:理解辩论式、审查式、委员会式等协作模式,合理设计 Agent 角色分工
  3. 任务规划:运用 ReAct、Plan-and-Execute 等策略,实现智能任务分解与动态调整
  4. 工具集成:构建标准化的工具接口,实现安全可控的外部系统集成
  5. 状态管理:设计健壮的状态持久化和上下文管理机制
  6. 容错机制:实现重试、降级、检查点恢复等多层次容错
  7. 人机协作:在关键节点引入人工审批,实现渐进式自动化
  8. 框架选型:根据场景选择 LangGraph、CrewAI 或 AutoGen
  9. 企业部署:构建完整的监控、日志、成本控制体系

从简单的工作流开始,逐步迭代优化,最终构建出可靠、高效、可观测的智能工作流系统。


下一步学习建议:

  • 使用 LangGraph 构建一个简单的 ReAct Agent,体验状态流转
  • 用 CrewAI 搭建一个 3 人协作团队,完成一个实际任务
  • 为你的工作流添加人工审批节点和错误处理逻辑
  • 搭建 Prometheus + Grafana 监控面板,观察工作流运行指标

本教程最后更新:2025年6月

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录