让三个不同角色的 Agent(产品经理、架构师、程序员)在 LangGraph 中"开会讨论",自主完成需求分析与代码生成任务。
1. Multi-Agent 架构概述
1.1 为什么需要 Multi-Agent?
单 Agent 在处理复杂任务时存在明显局限:
| 问题 | 说明 |
|---|---|
| 工具过多 | Agent 拥有太多工具时,决策质量下降 |
| 上下文复杂 | 单个 Agent 难以跟踪复杂的多步骤任务 |
| 领域专业化 | 不同任务需要不同领域的专业知识 |
| 可控性差 | 单 Agent 执行过程黑盒,难以精确控制 |
Multi-Agent 系统通过分而治之的策略解决这些问题:
┌─────────────────────────────────────────────────────────────┐
│ Multi-Agent 优势 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 模块化 │
│ ├── 独立开发、测试、维护 │
│ └── 职责单一,边界清晰 │
│ │
│ 专业化 │
│ ├── 每个Agent专注特定领域 │
│ └── 专业分工,效果更好 │
│ │
│ 可控性 │
│ ├── 明确控制Agent间通信 │
│ └── 流程可视化,易于调试 │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 Multi-Agent 架构模式
LangGraph 支持多种多智能体架构:
css
┌─────────────────────────────────────────────────────────────┐
│ Multi-Agent 三种核心架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Network(网络式) │
│ ┌───┐ ┌───┐ │
│ │ A │◄───▶│ B │ 任何Agent都可与其他Agent通信 │
│ └───┘ └───┘ Agent自己决定下一步调用谁 │
│ ▲ ▲ │
│ │ │ │
│ └────┬────┘ │
│ │ │
│ ┌─▼─┐ │
│ │ C │ │
│ └───┘ │
│ │
│ 2. Supervisor(监督者式) │
│ ┌─────┐ │
│ │ S │ Supervisor 决定调用哪个 Agent │
│ └──┬──┘ 所有 Agent 只与 Supervisor 通信 │
│ ┌─────┼─────┐ │
│ ▼ ▼ ▼ │
│ ┌───┐ ┌───┐ ┌───┐ │
│ │ A │ │ B │ │ C │ │
│ └───┘ └───┘ └───┘ │
│ │
│ 3. Hierarchical(层级式) │
│ ┌─────┐ │
│ │ CEO │ 多层监督者结构 │
│ └──┬──┘ 上层监督者管理下层监督者 │
│ ┌─────┴─────┐ │
│ ▼ ▼ │
│ ┌───┐ ┌───┐ │
│ │ S1│ │ S2│ │
│ └─┬─┘ └─┬─┘ │
│ ┌──┴──┐ ┌──┴──┐ │
│ ▼ ▼ ▼ ▼ │
│ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │
│ │A│ │B│ │C│ │D│ │
│ └─┘ └─┘ └─┘ └─┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2. LangGraph 核心概念
2.1 三大核心要素
python
# LangGraph 最小可用图的三个要素
from typing import TypedDict
from langgraph.graph import StateGraph, END, START
# 1. State:状态数据结构
class GraphState(TypedDict):
messages: list # 消息历史
current_agent: str # 当前活跃的 Agent
task_status: str # 任务状态
# 2. Nodes:处理节点(Python 函数)
def agent_node(state: GraphState) -> dict:
"""Agent 处理逻辑"""
# 处理 state,返回更新
return {"messages": ["处理完成"]}
# 3. Edges:连接边(控制流转)
builder = StateGraph(GraphState)
builder.add_node("agent", agent_node)
builder.add_edge(START, "agent")
builder.add_edge("agent", END)
graph = builder.compile()
2.2 条件边与循环
LangGraph 的核心优势:支持条件分支和循环
python
from typing import Literal
def router(state: GraphState) -> Literal["continue", "end"]:
"""条件路由函数"""
if len(state["messages"]) > 10:
return "end"
return "continue"
# 添加条件边
builder.add_conditional_edges(
"agent",
router,
{
"continue": "agent", # 循环回到自己
"end": END # 结束
}
)
3. 实战案例:三角色协作系统
3.1 场景描述
模拟一个软件开发团队的协作流程:
markdown
用户需求 ──▶ 产品经理分析 ──▶ 架构师设计 ──▶ 程序员编码 ──▶ 代码输出
│ │ │
└────────────────┴────────────────┘
协作讨论
角色分工:
| 角色 | 职责 | 输出 |
|---|---|---|
| 产品经理 | 需求分析、用户故事、功能列表 | 需求文档 |
| 架构师 | 技术方案、模块设计、接口定义 | 设计文档 |
| 程序员 | 代码实现、单元测试 | 可执行代码 |
3.2 系统架构设计
sql
┌─────────────────────────────────────────────────────────────┐
│ 三角色协作系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ │
│ │ START │ │
│ └────┬────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ 产品经理Agent │ │
│ │ 需求分析 │ │
│ └───────┬───────┘ │
│ │ │
│ 需求通过? │
│ │ │
│ ┌─────────┴─────────┐ │
│ │ │ │
│ ▼ ▼ │
│ 通过 需要讨论 │
│ │ │ │
│ ▼ │ │
│ ┌───────────────┐ │ │
│ │ 架构师Agent │◄───────────┘ │
│ │ 技术设计 │ │
│ └───────┬───────┘ │
│ │ │
│ 设计通过? │
│ │ │
│ ┌──────┴──────┐ │
│ │ │ │
│ ▼ ▼ │
│ 通过 需要讨论 │
│ │ │ │
│ ▼ │ │
│ ┌─────────────┐ │ │
│ │ 程序员Agent │◄──┘ │
│ │ 代码实现 │ │
│ └──────┬──────┘ │
│ │ │
│ 代码完成? │
│ │ │
│ ┌────┴────┐ │
│ │ │ │
│ ▼ ▼ │
│ 完成 需要修改 │
│ │ │ │
│ ▼ │ │
│ ┌────┐ │ │
│ │END │◄─────┘ │
│ └────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
3.3 完整代码实现
3.3.1 项目结构
bash
multi_agent_project/
├── main.py # 主程序入口
├── state.py # 状态定义
├── agents/
│ ├── __init__.py
│ ├── product_manager.py # 产品经理 Agent
│ ├── architect.py # 架构师 Agent
│ └── programmer.py # 程序员 Agent
├── graph.py # 工作流图定义
├── prompts/
│ ├── pm_prompt.py # 产品经理提示词
│ ├── arch_prompt.py # 架构师提示词
│ └── dev_prompt.py # 程序员提示词
└── requirements.txt
3.3.2 状态定义
python
# state.py
from typing import TypedDict, Annotated, List, Optional
import operator
class AgentMessage(TypedDict):
"""Agent 消息结构"""
agent: str # 发送者
content: str # 消息内容
message_type: str # 消息类型:analysis/design/code/review
class DevelopmentState(TypedDict):
"""开发工作流状态"""
# 输入
user_requirement: str # 用户原始需求
# 产品经理输出
requirement_doc: str # 需求文档
user_stories: List[str] # 用户故事列表
feature_list: List[str] # 功能列表
# 架构师输出
tech_stack: str # 技术栈选择
module_design: str # 模块设计
api_design: str # API 设计
# 程序员输出
code_files: dict # 代码文件 {filename: content}
test_cases: List[str] # 测试用例
# 协作状态
messages: Annotated[List[AgentMessage], operator.add] # 消息历史
current_stage: str # 当前阶段
iteration_count: int # 迭代次数
approved: bool # 是否通过
# 决策
next_agent: Optional[str] # 下一个要调用的 Agent
feedback: Optional[str] # 反馈意见
3.3.3 提示词模板
python
# prompts/pm_prompt.py
PRODUCT_MANAGER_SYSTEM = """你是一位资深的产品经理,拥有10年的产品规划经验。
你的职责是:
1. 理解并分析用户需求
2. 编写清晰的需求文档
3. 拆分用户故事
4. 列出功能清单
你的输出风格:
- 结构化、条理清晰
- 使用 Markdown 格式
- 关注用户价值而非技术实现
当你需要与架构师讨论时,在消息中明确标注:
[DISCUSS] 需要讨论的问题...
"""
PRODUCT_MANAGER_TEMPLATE = """
## 用户需求
{user_requirement}
## 已有讨论记录
{messages}
## 任务
请分析上述需求,输出:
1. 需求概述(一段话总结)
2. 用户故事列表(作为XX,我希望XX,以便XX)
3. 功能清单(按优先级排序)
4. 非功能性需求(性能、安全等)
如果你认为需求足够清晰,输出 [APPROVED] 标记。
如果需要进一步讨论,输出 [DISCUSS] 标记并说明问题。
"""
python
# prompts/arch_prompt.py
ARCHITECT_SYSTEM = """你是一位资深的技术架构师,拥有15年的系统设计经验。
你的职责是:
1. 根据需求选择合适的技术栈
2. 设计系统模块结构
3. 定义接口规范
4. 考虑性能、扩展性、安全性
你的输出风格:
- 技术方案具体可行
- 包含架构图描述(用 ASCII 或文字描述)
- 接口设计符合 RESTful 规范
"""
ARCHITECT_TEMPLATE = """
## 需求文档
{requirement_doc}
## 功能清单
{feature_list}
## 已有讨论记录
{messages}
## 任务
请根据需求设计技术方案,输出:
1. 技术栈选择(语言、框架、数据库、中间件)
2. 系统架构设计(模块划分、关系图)
3. 核心接口定义(API 路径、方法、参数、返回值)
4. 数据库表设计(核心表结构)
如果你认为设计足够完善,输出 [APPROVED] 标记。
如果需要与产品经理讨论,输出 [DISCUSS] 标记并说明问题。
"""
python
# prompts/dev_prompt.py
PROGRAMMER_SYSTEM = """你是一位全栈程序员,精通多种编程语言和框架。
你的职责是:
1. 根据设计文档实现代码
2. 编写单元测试
3. 确保代码质量
你的编码风格:
- 代码规范、注释清晰
- 遵循 SOLID 原则
- 包含错误处理
- 编写可测试的代码
"""
PROGRAMMER_TEMPLATE = """
## 技术栈
{tech_stack}
## 模块设计
{module_design}
## API 设计
{api_design}
## 已有讨论记录
{messages}
## 任务
请根据设计实现代码,输出:
1. 项目结构(目录树)
2. 核心代码文件(每个文件用 ```language 标注)
3. 单元测试代码
4. 运行说明
如果你认为代码实现完成,输出 [COMPLETED] 标记。
如果需要修改设计,输出 [NEED_REVISION] 标记并说明问题。
"""
3.3.4 Agent 实现
python
# agents/product_manager.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from typing import Dict
import json
import re
class ProductManagerAgent:
"""产品经理 Agent"""
def __init__(self, model: str = "gpt-4"):
self.llm = ChatOpenAI(model=model, temperature=0.3)
self.name = "产品经理"
def process(self, state: Dict) -> Dict:
"""处理需求分析"""
from prompts.pm_prompt import PRODUCT_MANAGER_SYSTEM, PRODUCT_MANAGER_TEMPLATE
# 构建消息历史
messages_str = self._format_messages(state.get("messages", []))
# 构建提示
prompt = ChatPromptTemplate.from_messages([
("system", PRODUCT_MANAGER_SYSTEM),
("human", PRODUCT_MANAGER_TEMPLATE)
])
chain = prompt | self.llm
# 执行
result = chain.invoke({
"user_requirement": state["user_requirement"],
"messages": messages_str
})
content = result.content
# 解析输出
output = self._parse_output(content)
# 判断是否批准
approved = "[APPROVED]" in content
need_discuss = "[DISCUSS]" in content
return {
"requirement_doc": output.get("requirement_doc", ""),
"user_stories": output.get("user_stories", []),
"feature_list": output.get("feature_list", []),
"messages": [{
"agent": self.name,
"content": content,
"message_type": "analysis"
}],
"current_stage": "requirement_analysis",
"approved": approved,
"next_agent": "architect" if approved else "product_manager",
"feedback": output.get("discussion_points") if need_discuss else None
}
def _format_messages(self, messages: list) -> str:
"""格式化消息历史"""
formatted = []
for msg in messages:
formatted.append(f"[{msg['agent']}]: {msg['content']}")
return "\n\n".join(formatted)
def _parse_output(self, content: str) -> dict:
"""解析输出内容"""
output = {}
# 提取需求概述
overview_match = re.search(r'需求概述[::]\s*(.+?)(?=\n\d|##)', content, re.DOTALL)
if overview_match:
output["requirement_doc"] = overview_match.group(1).strip()
# 提取用户故事
stories = re.findall(r'作为.+?,希望.+?,以便.+?', content)
output["user_stories"] = stories
# 提取功能列表
features = re.findall(r'^\d+\.\s*(.+)$', content, re.MULTILINE)
output["feature_list"] = [f.strip() for f in features if f.strip()]
return output
python
# agents/architect.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from typing import Dict
import re
class ArchitectAgent:
"""架构师 Agent"""
def __init__(self, model: str = "gpt-4"):
self.llm = ChatOpenAI(model=model, temperature=0.2)
self.name = "架构师"
def process(self, state: Dict) -> Dict:
"""处理架构设计"""
from prompts.arch_prompt import ARCHITECT_SYSTEM, ARCHITECT_TEMPLATE
# 构建消息历史
messages_str = self._format_messages(state.get("messages", []))
# 构建提示
prompt = ChatPromptTemplate.from_messages([
("system", ARCHITECT_SYSTEM),
("human", ARCHITECT_TEMPLATE)
])
chain = prompt | self.llm
# 执行
result = chain.invoke({
"requirement_doc": state.get("requirement_doc", ""),
"feature_list": "\n".join(state.get("feature_list", [])),
"messages": messages_str
})
content = result.content
# 解析输出
output = self._parse_output(content)
# 判断状态
approved = "[APPROVED]" in content
need_discuss = "[DISCUSS]" in content
return {
"tech_stack": output.get("tech_stack", ""),
"module_design": output.get("module_design", ""),
"api_design": output.get("api_design", ""),
"messages": [{
"agent": self.name,
"content": content,
"message_type": "design"
}],
"current_stage": "architecture_design",
"approved": approved,
"next_agent": "programmer" if approved else "product_manager",
"feedback": output.get("discussion_points") if need_discuss else None
}
def _format_messages(self, messages: list) -> str:
formatted = []
for msg in messages:
formatted.append(f"[{msg['agent']}]: {msg['content']}")
return "\n\n".join(formatted)
def _parse_output(self, content: str) -> dict:
output = {}
# 提取技术栈
tech_match = re.search(r'技术栈[::]\s*(.+?)(?=\n\d|##|\n\n)', content, re.DOTALL)
if tech_match:
output["tech_stack"] = tech_match.group(1).strip()
# 提取模块设计
module_match = re.search(r'(?:系统架构|模块设计)[::]\s*(.+?)(?=接口|API|##)', content, re.DOTALL)
if module_match:
output["module_design"] = module_match.group(1).strip()
# 提取 API 设计
api_match = re.search(r'(?:接口定义|API设计)[::]\s*(.+?)(?=数据库|##|$)', content, re.DOTALL)
if api_match:
output["api_design"] = api_match.group(1).strip()
return output
python
# agents/programmer.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from typing import Dict
import re
class ProgrammerAgent:
"""程序员 Agent"""
def __init__(self, model: str = "gpt-4"):
self.llm = ChatOpenAI(model=model, temperature=0.1)
self.name = "程序员"
def process(self, state: Dict) -> Dict:
"""处理代码实现"""
from prompts.dev_prompt import PROGRAMMER_SYSTEM, PROGRAMMER_TEMPLATE
# 构建消息历史
messages_str = self._format_messages(state.get("messages", []))
# 构建提示
prompt = ChatPromptTemplate.from_messages([
("system", PROGRAMMER_SYSTEM),
("human", PROGRAMMER_TEMPLATE)
])
chain = prompt | self.llm
# 执行
result = chain.invoke({
"tech_stack": state.get("tech_stack", ""),
"module_design": state.get("module_design", ""),
"api_design": state.get("api_design", ""),
"messages": messages_str
})
content = result.content
# 解析输出
output = self._parse_output(content)
# 判断状态
completed = "[COMPLETED]" in content
need_revision = "[NEED_REVISION]" in content
return {
"code_files": output.get("code_files", {}),
"test_cases": output.get("test_cases", []),
"messages": [{
"agent": self.name,
"content": content,
"message_type": "code"
}],
"current_stage": "code_implementation",
"approved": completed,
"next_agent": END if completed else "architect",
"feedback": output.get("revision_points") if need_revision else None
}
def _format_messages(self, messages: list) -> str:
formatted = []
for msg in messages:
formatted.append(f"[{msg['agent']}]: {msg['content']}")
return "\n\n".join(formatted)
def _parse_output(self, content: str) -> dict:
output = {}
# 提取代码文件
code_blocks = re.findall(r'```(\w+)?\n?([^`]+)```', content, re.DOTALL)
# 尝试提取文件名
file_patterns = re.findall(r'(?:文件名|File)[::]\s*`?([^`\n]+)`?', content)
code_files = {}
for i, (lang, code) in enumerate(code_blocks):
if i < len(file_patterns):
filename = file_patterns[i].strip()
else:
filename = f"file_{i+1}.py" if lang == 'python' else f"file_{i+1}.{lang or 'txt'}"
code_files[filename] = code.strip()
output["code_files"] = code_files
# 提取测试用例
test_match = re.search(r'测试[用例]?[::]\s*(.+?)(?=运行说明|##|$)', content, re.DOTALL)
if test_match:
output["test_cases"] = [test_match.group(1).strip()]
return output
3.3.5 工作流图定义
python
# graph.py
from langgraph.graph import StateGraph, END, START
from langgraph.checkpoint.memory import MemorySaver
from state import DevelopmentState
from agents.product_manager import ProductManagerAgent
from agents.architect import ArchitectAgent
from agents.programmer import ProgrammerAgent
from typing import Literal
class DevelopmentWorkflow:
"""开发工作流"""
def __init__(self, model: str = "gpt-4"):
# 初始化 Agent
self.pm_agent = ProductManagerAgent(model)
self.arch_agent = ArchitectAgent(model)
self.dev_agent = ProgrammerAgent(model)
# 构建图
self.graph = self._build_graph()
def _build_graph(self) -> StateGraph:
"""构建工作流图"""
# 创建构建器
builder = StateGraph(DevelopmentState)
# 添加节点
builder.add_node("product_manager", self._pm_node)
builder.add_node("architect", self._arch_node)
builder.add_node("programmer", self._dev_node)
# 添加边
builder.add_edge(START, "product_manager")
# 条件边:产品经理 -> 架构师 或 继续分析
builder.add_conditional_edges(
"product_manager",
self._pm_router,
{
"architect": "architect",
"continue": "product_manager" # 需要更多分析
}
)
# 条件边:架构师 -> 程序员 或 回到产品经理讨论
builder.add_conditional_edges(
"architect",
self._arch_router,
{
"programmer": "programmer",
"product_manager": "product_manager", # 需要讨论需求
"continue": "architect" # 需要修改设计
}
)
# 条件边:程序员 -> 结束 或 回到架构师
builder.add_conditional_edges(
"programmer",
self._dev_router,
{
"end": END,
"architect": "architect" # 需要修改设计
}
)
return builder.compile(checkpointer=MemorySaver())
def _pm_node(self, state: DevelopmentState) -> dict:
"""产品经理节点"""
print("\n" + "="*60)
print("📋 产品经理正在分析需求...")
print("="*60)
result = self.pm_agent.process(state)
print(f"\n需求文档:\n{result.get('requirement_doc', 'N/A')}")
print(f"\n用户故事:\n" + "\n".join(f"- {s}" for s in result.get('user_stories', [])))
print(f"\n功能列表:\n" + "\n".join(f"- {f}" for f in result.get('feature_list', [])))
if result.get('approved'):
print("\n✅ 需求分析完成,交给架构师...")
elif result.get('feedback'):
print(f"\n🔄 需要讨论: {result['feedback']}")
return result
def _arch_node(self, state: DevelopmentState) -> dict:
"""架构师节点"""
print("\n" + "="*60)
print("🏗️ 架构师正在进行技术设计...")
print("="*60)
result = self.arch_agent.process(state)
print(f"\n技术栈:\n{result.get('tech_stack', 'N/A')}")
print(f"\n模块设计:\n{result.get('module_design', 'N/A')[:500]}...")
print(f"\nAPI 设计:\n{result.get('api_design', 'N/A')[:500]}...")
if result.get('approved'):
print("\n✅ 架构设计完成,交给程序员...")
elif result.get('feedback'):
print(f"\n🔄 需要讨论: {result['feedback']}")
return result
def _dev_node(self, state: DevelopmentState) -> dict:
"""程序员节点"""
print("\n" + "="*60)
print("💻 程序员正在编写代码...")
print("="*60)
result = self.dev_agent.process(state)
code_files = result.get('code_files', {})
print(f"\n生成了 {len(code_files)} 个代码文件:")
for filename in code_files.keys():
print(f" - {filename}")
if result.get('approved'):
print("\n✅ 代码实现完成!")
elif result.get('feedback'):
print(f"\n🔄 需要修改: {result['feedback']}")
return result
def _pm_router(self, state: DevelopmentState) -> Literal["architect", "continue"]:
"""产品经理路由"""
if state.get("approved") and state.get("current_stage") == "requirement_analysis":
return "architect"
return "continue"
def _arch_router(self, state: DevelopmentState) -> Literal["programmer", "product_manager", "continue"]:
"""架构师路由"""
if state.get("approved") and state.get("current_stage") == "architecture_design":
return "programmer"
if state.get("feedback"):
return "product_manager"
return "continue"
def _dev_router(self, state: DevelopmentState) -> Literal["end", "architect"]:
"""程序员路由"""
if state.get("approved"):
return "end"
return "architect"
def run(self, requirement: str, thread_id: str = "default"):
"""执行工作流"""
initial_state = {
"user_requirement": requirement,
"messages": [],
"iteration_count": 0,
"approved": False
}
config = {"configurable": {"thread_id": thread_id}}
return self.graph.invoke(initial_state, config=config)
3.3.6 主程序入口
python
# main.py
import os
from dotenv import load_dotenv
from graph import DevelopmentWorkflow
# 加载环境变量
load_dotenv()
def main():
"""主程序入口"""
print("""
╔═══════════════════════════════════════════════════════════╗
║ ║
║ 🤖 Multi-Agent 软件开发协作系统 ║
║ 产品经理 + 架构师 + 程序员 ║
║ ║
╚═══════════════════════════════════════════════════════════╝
""")
# 获取用户需求
print("请输入您的需求(输入 exit 退出):")
while True:
requirement = input("\n需求 > ").strip()
if requirement.lower() == "exit":
print("再见!")
break
if not requirement:
print("请输入有效的需求描述")
continue
# 创建工作流
workflow = DevelopmentWorkflow(model="gpt-4")
# 执行
print("\n🚀 开始协作开发流程...")
result = workflow.run(requirement)
# 输出最终结果
print("\n" + "="*60)
print("📊 最终输出")
print("="*60)
print("\n📁 生成的代码文件:")
for filename, content in result.get("code_files", {}).items():
print(f"\n--- {filename} ---")
print(content[:500] + "..." if len(content) > 500 else content)
print("\n" + "="*60)
print("✨ 协作完成!")
print("="*60)
if __name__ == "__main__":
main()
3.3.7 依赖文件
text
# requirements.txt
langgraph>=0.2.0
langchain>=0.3.0
langchain-openai>=0.2.0
python-dotenv>=1.0.0
4. 运行示例
4.1 示例输入
需求 > 我需要开发一个待办事项(Todo)应用,支持添加、删除、编辑、标记完成等功能,数据需要持久化存储,支持多用户。
4.2 执行过程
ini
╔═══════════════════════════════════════════════════════════╗
║ 🤖 Multi-Agent 软件开发协作系统 ║
║ 产品经理 + 架构师 + 程序员 ║
╚═══════════════════════════════════════════════════════════╝
🚀 开始协作开发流程...
============================================================
📋 产品经理正在分析需求...
============================================================
需求文档:
开发一个多用户待办事项管理应用,核心功能包括任务的增删改查、状态管理、数据持久化和用户隔离。
用户故事:
- 作为用户,我希望能够创建新的待办事项,以便记录需要完成的任务
- 作为用户,我希望能够编辑待办事项,以便修改任务内容或截止日期
- 作为用户,我希望能够删除待办事项,以便清理不需要的任务
- 作为用户,我希望能够标记任务完成状态,以便追踪进度
- 作为用户,我希望我的数据独立存储,以便保护隐私
功能列表:
1. 用户注册/登录功能
2. 创建待办事项(标题、描述、优先级、截止日期)
3. 编辑待办事项
4. 删除待办事项
5. 标记完成/未完成
6. 任务列表展示(支持筛选排序)
7. 数据持久化存储
✅ 需求分析完成,交给架构师...
============================================================
🏗️ 架构师正在进行技术设计...
============================================================
技术栈:
- 后端: Python + FastAPI
- 数据库: PostgreSQL + SQLAlchemy ORM
- 认证: JWT Token
- 前端: Vue.js 3 + Element Plus
模块设计:
├── backend/
│ ├── main.py # FastAPI 入口
│ ├── models/ # 数据模型
│ ├── routes/ # API 路由
│ ├── services/ # 业务逻辑
│ └── utils/ # 工具函数
├── frontend/
│ ├── src/
│ │ ├── views/ # 页面组件
│ │ ├── components/ # 公共组件
│ │ └── api/ # API 调用
API 设计:
POST /api/auth/register # 用户注册
POST /api/auth/login # 用户登录
GET /api/todos # 获取待办列表
POST /api/todos # 创建待办
PUT /api/todos/{id} # 更新待办
DELETE /api/todos/{id} # 删除待办
✅ 架构设计完成,交给程序员...
============================================================
💻 程序员正在编写代码...
============================================================
生成了 5 个代码文件:
- models.py
- main.py
- routes.py
- services.py
- test_todos.py
============================================================
📊 最终输出
============================================================
📁 生成的代码文件:
--- models.py ---
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from database import Base
from datetime import datetime
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
todos = relationship("Todo", back_populates="owner")
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, nullable=True)
completed = Column(Boolean, default=False)
priority = Column(String, default="medium")
due_date = Column(DateTime, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", back_populates="todos")
...
============================================================
✨ 协作完成!
============================================================
5. 高级特性
5.1 人工干预(Human-in-the-Loop)
python
# 在关键节点添加人工审核
from langgraph.prebuilt import ToolNode
def human_review_node(state: DevelopmentState) -> dict:
"""人工审核节点"""
print("\n📋 请审核以下内容:")
print(state.get("requirement_doc", ""))
approval = input("\n是否批准?(y/n): ")
return {
"approved": approval.lower() == "y",
"feedback": None if approval.lower() == "y" else "请修改需求"
}
# 添加到图中
builder.add_node("human_review", human_review_node)
builder.add_edge("product_manager", "human_review")
5.2 状态持久化
python
from langgraph.checkpoint.sqlite import SqliteSaver
# 使用 SQLite 持久化
with SqliteSaver("checkpoints.db") as checkpointer:
graph = builder.compile(checkpointer=checkpointer)
# 恢复执行
result = graph.invoke(
initial_state,
config={"configurable": {"thread_id": "session_123"}}
)
5.3 流式输出
python
async def run_stream(requirement: str):
"""流式执行"""
async for event in graph.astream_events(
{"user_requirement": requirement},
version="v1"
):
if event["event"] == "on_chain_start":
print(f"\n🔄 开始: {event['name']}")
elif event["event"] == "on_chain_end":
print(f"✅ 完成: {event['name']}")
6. 架构对比
6.1 与其他框架对比
| 特性 | LangGraph | CrewAI | AutoGen |
|---|---|---|---|
| 状态管理 | 内置、可视化 | 简单 | 对话式 |
| 循环支持 | ✅ 原生支持 | ⚠️ 有限 | ✅ 支持 |
| 条件分支 | ✅ 原生支持 | ⚠️ 有限 | ⚠️ 通过对话 |
| 人工干预 | ✅ 原生支持 | ⚠️ 有限 | ✅ 支持 |
| 持久化 | ✅ 内置 | ❌ 需自建 | ⚠️ 需配置 |
| 调试能力 | ✅ LangSmith | ⚠️ 有限 | ⚠️ 有限 |
| 学习曲线 | 中 | 低 | 中 |
6.2 适用场景
LangGraph 适用场景:
├── 需要精确控制工作流
├── 需要状态持久化
├── 需要支持循环和分支
├── 需要人工干预点
└── 需要生产级部署
CrewAI 适用场景:
├── 快速原型开发
├── 角色扮演式协作
└── 简单的多 Agent 任务
AutoGen 适用场景:
├── 对话式交互
├── 代码生成场景
└── 研究/实验项目
7. 最佳实践
7.1 状态设计原则
python
# ✅ 好的状态设计
class GoodState(TypedDict):
# 输入输出清晰分离
user_input: str
final_output: str
# 中间状态最小化
current_step: str
# 使用 Annotated 处理累加
messages: Annotated[list, operator.add]
# ❌ 不好的状态设计
class BadState(TypedDict):
everything: dict # 太笼统
temp_data: list # 不明确用途
# 缺少类型注解
7.2 节点职责单一
python
# ✅ 好的节点设计
def analyze_node(state: State) -> dict:
"""只做分析,返回分析结果"""
result = analyze(state["input"])
return {"analysis": result}
def generate_node(state: State) -> dict:
"""只做生成,使用分析结果"""
result = generate(state["analysis"])
return {"output": result}
# ❌ 不好的节点设计
def do_everything_node(state: State) -> dict:
"""什么都做,难以维护"""
analysis = analyze(state["input"])
output = generate(analysis)
return {"output": output} # 丢失中间状态
7.3 错误处理
python
from langgraph.pregel import GraphRecursionError
def safe_invoke(workflow, requirement: str):
"""安全的执行入口"""
try:
result = workflow.run(requirement)
return result
except GraphRecursionError:
print("⚠️ 达到最大迭代次数")
return {"error": "max_iterations_reached"}
except Exception as e:
print(f"⚠️ 执行出错: {e}")
return {"error": str(e)}
8. GitHub 项目推荐
| 项目 | 描述 | 链接 |
|---|---|---|
| LangGraph | 核心框架 | github.com/langchain-a... |
| LangGraph Swarm | Swarm 架构扩展 | github.com/langchain-a... |
| LangGraph4j | Java 版本 | github.com/langgraph4j... |
| LangGraph Templates | 官方模板 | github.com/langchain-a... |
总结
本文通过一个完整的实战案例,演示了如何使用 LangGraph 构建多智能体协作系统:
- 架构设计:选择 Supervisor 模式,由工作流控制 Agent 调用顺序
- 状态管理:使用 TypedDict 定义清晰的状态结构
- 节点实现:每个 Agent 作为独立节点,职责单一
- 条件路由:根据状态动态决定下一步
- 循环支持:支持迭代修改,直到满足条件
关键收益:
- 需求分析 → 架构设计 → 代码实现,全流程自动化
- Agent 间可以"讨论"和"反馈"
- 状态可追溯,便于调试
- 支持人工干预点
欢迎关注的我的公众号《码上未来》,一起交流AI前沿技术!
添加我微信
return_not_null进群聊AI