Multi-Agent 系统实战:用 Python + LangGraph 搭建多智能体协作工作流

一、单 Agent vs Multi-Agent:什么时候需要多智能体?

1.1 单 Agent 的瓶颈

单个 Agent 面临以下问题:

  • 上下文膨胀:复杂任务的中间状态全部堆在一个对话里,token 消耗爆炸
  • 专业性不足:一个 Agent 身兼数职,System Prompt 臃肿,质量下降
  • 无法并行:所有步骤串行执行,耗时长
  • 错误传播:某步出错,整个任务失败,无法局部重试

1.2 Multi-Agent 适用场景

场景 适合 Multi-Agent 的原因
软件开发流程(需求→代码→测试→审查) 各角色专业不同,可并行
复杂报告生成(搜集→分析→撰写→校对) 步骤解耦,质量更高
数据处理流水线(提取→转换→验证→入库) 天然流水线结构
客服升级流程(初筛→专业判断→人工兜底) 条件路由,降本增效

判断标准:如果任务可以拆解为 3 个以上专业子任务,且子任务之间有明确的输入输出边界,就适合 Multi-Agent。


二、LangGraph 核心抽象详解

LangGraph 是 LangChain 官方推出的 Agent 编排框架,用**图(Graph)**的方式定义 Agent 工作流:

bash 复制代码
核心概念:
State(状态)  → 贯穿整个图的共享数据结构
Node(节点)   → 每个 Agent 或处理函数
Edge(边)     → 节点间的流转关系
Graph(图)    → 节点 + 边组成的完整工作流

2.1 安装依赖

bash 复制代码
pip install langgraph langchain-openai langchain-core python-dotenv

2.2 State 设计------最重要的第一步

State 是所有 Agent 共享的"工作台",设计好 State 结构是 Multi-Agent 成功的关键:

python 复制代码
# state.py
from typing import TypedDict, Annotated, List, Optional
from langgraph.graph.message import add_messages


class DevWorkflowState(TypedDict):
    """软件开发工作流的共享状态"""
    # 原始需求
    requirement: str

    # 各阶段输出
    analysis_result: Optional[str]    # 需求分析结果
    code_result: Optional[str]        # 编码结果
    test_result: Optional[str]        # 测试结果
    review_result: Optional[str]      # 代码审查结果

    # 流程控制
    current_step: str                 # 当前步骤
    errors: List[str]                 # 错误收集
    approved: bool                    # 是否通过审查

    # 消息历史(使用 add_messages 自动追加)
    messages: Annotated[list, add_messages]

三、实战:四角色 Agent 流水线

3.1 配置大模型客户端

python 复制代码
# llm_config.py
import os
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

# 使用 DeepSeek V4 Flash(性价比最高)
def get_llm(temperature: float = 0.3):
    return ChatOpenAI(
        model="deepseek-v4-flash",
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        base_url="https://api.deepseek.com",
        temperature=temperature,
    )

# 复杂推理用 Pro 版
def get_pro_llm(temperature: float = 0.1):
    return ChatOpenAI(
        model="deepseek-v4-pro",
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        base_url="https://api.deepseek.com",
        temperature=temperature,
    )

3.2 定义四个专业 Agent 节点

python 复制代码
# agents.py
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from state import DevWorkflowState
from llm_config import get_llm, get_pro_llm


# ── Agent 1:需求分析师 ──────────────────────────────────────────
def analyst_agent(state: DevWorkflowState) -> DevWorkflowState:
    """分析需求,输出技术方案和任务拆解"""
    llm = get_llm()
    system = SystemMessage(content="""你是一个资深需求分析师。
    分析用户需求,输出:
    1. 功能点列表(按优先级排序)
    2. 技术方案选型
    3. 数据结构设计
    4. 接口定义(输入/输出)
    格式要求:结构清晰,用 Markdown 呈现""")

    response = llm.invoke([
        system,
        HumanMessage(content=f"请分析以下需求:\n\n{state['requirement']}")
    ])

    print(f"✅ [需求分析师] 分析完成")
    return {
        **state,
        "analysis_result": response.content,
        "current_step": "analyzed",
        "messages": [AIMessage(content=response.content, name="analyst")]
    }


# ── Agent 2:编码工程师 ──────────────────────────────────────────
def coder_agent(state: DevWorkflowState) -> DevWorkflowState:
    """根据需求分析结果编写代码"""
    llm = get_pro_llm()  # 编码用 Pro 版,质量更高
    system = SystemMessage(content="""你是一个资深 Python 工程师。
    根据需求分析结果,编写完整、可运行的代码:
    - 代码结构清晰,有适当注释
    - 包含异常处理
    - 遵循 PEP8 规范
    - 只输出代码和必要说明,不要重复需求分析内容""")

    response = llm.invoke([
        system,
        HumanMessage(content=f"""
需求分析结果:
{state['analysis_result']}

原始需求:
{state['requirement']}

请编写实现代码:""")
    ])

    print(f"✅ [编码工程师] 编码完成")
    return {
        **state,
        "code_result": response.content,
        "current_step": "coded",
        "messages": [AIMessage(content=response.content, name="coder")]
    }


# ── Agent 3:测试工程师 ──────────────────────────────────────────
def tester_agent(state: DevWorkflowState) -> DevWorkflowState:
    """为代码编写测试用例"""
    llm = get_llm()
    system = SystemMessage(content="""你是一个 QA 测试工程师,专注 Python 单元测试。
    为给定代码编写完整测试:
    - 使用 pytest 框架
    - 覆盖正常流程、边界条件、异常情况
    - 每个测试函数有清晰的命名和注释
    - 覆盖率目标 80% 以上""")

    response = llm.invoke([
        system,
        HumanMessage(content=f"""
请为以下代码编写测试用例:

{state['code_result']}

需求背景:{state['requirement']}""")
    ])

    print(f"✅ [测试工程师] 测试用例生成完成")
    return {
        **state,
        "test_result": response.content,
        "current_step": "tested",
        "messages": [AIMessage(content=response.content, name="tester")]
    }


# ── Agent 4:代码审查员 ──────────────────────────────────────────
def reviewer_agent(state: DevWorkflowState) -> DevWorkflowState:
    """审查代码质量,给出通过/拒绝决定"""
    llm = get_pro_llm()
    system = SystemMessage(content="""你是一个严格的代码审查员。
    审查代码质量,重点关注:
    1. 代码正确性(逻辑是否有 bug)
    2. 安全性(有无注入、越界等风险)
    3. 性能(有无明显性能问题)
    4. 可维护性(代码是否清晰)
    5. 测试充分性(测试是否覆盖关键场景)

    最后必须给出明确结论:
    【审查结果】APPROVED 或 REJECTED
    【原因】xxx
    【修改建议】xxx(如果 REJECTED)""")

    response = llm.invoke([
        system,
        HumanMessage(content=f"""
请审查以下代码和测试:

== 实现代码 ==
{state['code_result']}

== 测试代码 ==
{state['test_result']}

需求:{state['requirement']}""")
    ])

    content = response.content
    approved = "APPROVED" in content.upper()

    print(f"✅ [代码审查员] 审查完成 → {'通过 ✅' if approved else '拒绝 ❌'}")
    return {
        **state,
        "review_result": content,
        "approved": approved,
        "current_step": "reviewed",
        "messages": [AIMessage(content=content, name="reviewer")]
    }

3.3 构建图结构

python 复制代码
# workflow.py
from langgraph.graph import StateGraph, END
from state import DevWorkflowState
from agents import analyst_agent, coder_agent, tester_agent, reviewer_agent


def should_continue(state: DevWorkflowState) -> str:
    """条件路由:审查通过则结束,否则重新编码"""
    if state.get("approved"):
        return "end"
    # 检查错误次数,避免无限循环
    errors = state.get("errors", [])
    if len(errors) >= 2:
        print("⚠️ 已重试 2 次,强制结束")
        return "end"
    return "recode"


def add_error(state: DevWorkflowState) -> DevWorkflowState:
    """记录审查失败,准备重试"""
    errors = state.get("errors", [])
    errors.append(f"审查失败,原因:{state.get('review_result', '')[:100]}")
    return {**state, "errors": errors}


# ── 构建图 ──────────────────────────────────────────────────────
def build_dev_workflow() -> StateGraph:
    graph = StateGraph(DevWorkflowState)

    # 添加节点
    graph.add_node("analyst", analyst_agent)
    graph.add_node("coder",   coder_agent)
    graph.add_node("tester",  tester_agent)
    graph.add_node("reviewer", reviewer_agent)
    graph.add_node("add_error", add_error)

    # 设置入口
    graph.set_entry_point("analyst")

    # 添加普通边(顺序流转)
    graph.add_edge("analyst", "coder")
    graph.add_edge("coder",   "tester")
    graph.add_edge("tester",  "reviewer")

    # 条件边:审查结果决定下一步
    graph.add_conditional_edges(
        "reviewer",
        should_continue,
        {
            "end":    END,
            "recode": "add_error"   # 记录错误后重新编码
        }
    )
    graph.add_edge("add_error", "coder")   # 重新编码

    return graph.compile()

3.4 运行工作流

python 复制代码
# main.py
from workflow import build_dev_workflow

def run_dev_workflow(requirement: str):
    app = build_dev_workflow()

    initial_state = {
        "requirement": requirement,
        "analysis_result": None,
        "code_result": None,
        "test_result": None,
        "review_result": None,
        "current_step": "start",
        "errors": [],
        "approved": False,
        "messages": [],
    }

    print(f"\n{'='*60}")
    print(f"🚀 启动开发工作流")
    print(f"需求:{requirement}")
    print(f"{'='*60}\n")

    final_state = app.invoke(initial_state)

    print(f"\n{'='*60}")
    print(f"📋 工作流执行完成")
    print(f"最终状态:{'✅ 通过' if final_state['approved'] else '⚠️ 未通过(已达重试上限)'}")
    print(f"重试次数:{len(final_state.get('errors', []))}")
    print(f"{'='*60}")

    return final_state


if __name__ == "__main__":
    result = run_dev_workflow(
        "实现一个 Python 装饰器,用于统计函数执行时间,"
        "支持设置超时时间,超时自动抛出 TimeoutError,"
        "并将统计结果写入日志文件。"
    )
    print("\n== 最终代码 ==")
    print(result["code_result"])

四、并行执行:让测试和文档同时生成

python 复制代码
# parallel_workflow.py
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, List
from langgraph.graph.message import add_messages


class ParallelState(TypedDict):
    requirement: str
    code_result: str
    test_result: str
    doc_result: str        # 新增:文档生成
    messages: Annotated[list, add_messages]


def doc_writer_agent(state: ParallelState) -> ParallelState:
    """并行生成 API 文档(与测试同时进行)"""
    from llm_config import get_llm
    from langchain_core.messages import SystemMessage, HumanMessage

    llm = get_llm()
    response = llm.invoke([
        SystemMessage(content="你是技术文档工程师,为代码生成 README 和 API 文档。"),
        HumanMessage(content=f"为以下代码生成文档:\n\n{state['code_result']}")
    ])
    return {**state, "doc_result": response.content}


def build_parallel_workflow():
    graph = StateGraph(ParallelState)

    from agents import analyst_agent, coder_agent, tester_agent, reviewer_agent

    graph.add_node("analyst",    analyst_agent)
    graph.add_node("coder",      coder_agent)
    graph.add_node("tester",     tester_agent)
    graph.add_node("doc_writer", doc_writer_agent)
    graph.add_node("reviewer",   reviewer_agent)

    graph.set_entry_point("analyst")
    graph.add_edge("analyst", "coder")

    # 编码完成后,测试和文档并行执行
    graph.add_edge("coder", "tester")
    graph.add_edge("coder", "doc_writer")

    # 并行结果汇聚到审查节点
    graph.add_edge("tester",     "reviewer")
    graph.add_edge("doc_writer", "reviewer")

    graph.add_edge("reviewer", END)
    return graph.compile()

五、Human-in-the-Loop:人工介入节点

生产环境中,某些关键决策不能完全交给 AI。LangGraph 支持在任意节点暂停,等待人工确认:

python 复制代码
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver


def build_workflow_with_human():
    """带人工介入的工作流"""
    graph = StateGraph(DevWorkflowState)

    graph.add_node("analyst",  analyst_agent)
    graph.add_node("coder",    coder_agent)
    graph.add_node("tester",   tester_agent)
    graph.add_node("reviewer", reviewer_agent)

    graph.set_entry_point("analyst")
    graph.add_edge("analyst", "coder")
    graph.add_edge("coder",   "tester")
    graph.add_edge("tester",  "reviewer")
    graph.add_edge("reviewer", END)

    # 使用内存检查点(生产环境用 SqliteSaver 或 PostgresSaver)
    memory = MemorySaver()
    return graph.compile(
        checkpointer=memory,
        interrupt_before=["coder"]   # 在编码前暂停,等待人工确认需求分析
    )


def run_with_human_approval(requirement: str):
    app = build_workflow_with_human()
    config = {"configurable": {"thread_id": "dev-session-001"}}

    # 初始状态
    state = {
        "requirement": requirement,
        "analysis_result": None, "code_result": None,
        "test_result": None, "review_result": None,
        "current_step": "start", "errors": [], "approved": False, "messages": []
    }

    # 运行到 coder 节点前暂停
    for event in app.stream(state, config):
        print(f"节点执行:{list(event.keys())}")

    # 此时工作流暂停,等待人工决策
    print("\n⏸️  工作流已暂停,请审核需求分析结果...")
    current = app.get_state(config)
    print("需求分析结果:", current.values.get("analysis_result", "")[:200])

    human_input = input("\n是否继续执行编码?(y/n): ")
    if human_input.lower() != 'y':
        print("❌ 用户取消执行")
        return None

    # 人工确认后继续执行
    print("▶️  继续执行...")
    for event in app.stream(None, config):
        print(f"节点执行:{list(event.keys())}")

    return app.get_state(config).values

六、监控与调试:LangSmith 追踪执行链路

python 复制代码
# 在项目根目录 .env 文件添加
# LANGCHAIN_TRACING_V2=true
# LANGCHAIN_API_KEY=your-langsmith-api-key
# LANGCHAIN_PROJECT=my-multi-agent-project

import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-key"

# 之后所有 LangGraph 执行都会自动上传到 LangSmith
# 在 https://smith.langchain.com 查看:
# - 每个 Agent 的输入/输出
# - Token 消耗明细
# - 执行时间
# - 错误堆栈

本地调试替代方案:

python 复制代码
# 打印每步执行细节
for step in app.stream(initial_state):
    for node_name, node_output in step.items():
        print(f"\n{'─'*40}")
        print(f"节点:{node_name}")
        print(f"当前步骤:{node_output.get('current_step', 'N/A')}")
        if "errors" in node_output and node_output["errors"]:
            print(f"错误:{node_output['errors']}")

七、完整项目结构与运行

bash 复制代码
multi-agent-dev/
├── .env
├── state.py          # 状态定义
├── llm_config.py     # LLM 配置
├── agents.py         # 四个 Agent 定义
├── workflow.py       # 图构建
├── main.py           # 入口
└── requirements.txt
bash 复制代码
# requirements.txt
langgraph>=0.2.0
langchain-openai>=0.2.0
langchain-core>=0.3.0
python-dotenv

# 运行
python main.py

总结

Multi-Agent 的核心价值在于分工专业化 + 并行提速 + 局部容错。LangGraph 的图结构让复杂工作流可视化且可调试。

实践要点:

  1. State 设计先行:State 结构决定了信息如何在 Agent 间流转,改动成本高
  2. 节点职责单一:每个 Agent 只做一件专业的事,System Prompt 简洁
  3. 条件边控制流conditional_edges 是实现重试、分支、人工介入的关键
  4. 先用 Flash 模型,确认流程正确后再切换 Pro 版
相关推荐
bang冰冰1 小时前
Trae工具安装和使用教程(新手零基础入门,全程无坑)
java·人工智能·python
User_芊芊君子1 小时前
聊聊自由开发者常用的学习机会全解析
开发语言·人工智能·python
weixin_376593222 小时前
使用pyhon脚本方式将超链接保存到第一列以数字方式显示
python
byzh_rc2 小时前
[AI编程从入门到入土] 装饰器decorator
开发语言·python·ai编程
贫民窟的勇敢爷们3 小时前
Java 与 Python 如何选型与融合
java·开发语言·python
2303_821287383 小时前
c++ RAII机制详解 c++如何利用RAII管理资源
jvm·数据库·python
yuanpan4 小时前
Python 网页数据爬取入门教程:requests + BeautifulSoup 从解析到保存
开发语言·python·beautifulsoup
谙弆悕博士4 小时前
Python快速学习——第8章:循环语句
python·学习·servlet
idingzhi4 小时前
A股量化策略日报(2026年05月09日)
python