
在本篇文章中,我们将深入探讨如何运用langgraph与langchain来构建多人工智能智能体(multi - AI Agents)。文中所涉及的代码均已通过验证,具有较高的可靠性与实用性。当您认真读完这篇文章后,便具备了独立构建属于自己的多智能体系统的能力。如调试代码时有困难,请关注本账号,线下沟通

LangGraph 是基于 LangChain 构建的 AI 智能体框架,使开发者能够创建更复杂、更灵活的智能体工作流。与传统的 LangChain 链式结构和智能体不同,LangGraph 将智能体交互建模为循环图(cyclic graphs),支持多步骤处理、分支和循环逻辑,从而无需再手动编写复杂的信息流转控制代码。
正如其名,LangGraph 采用图结构(graph)的工作流,由节点(nodes)和边(edges)组成:
若初次接触 LangGraph,在构建智能体前需掌握三个核心概念:
1. 节点(Nodes)
2. 边(Edges)
3. 状态(State)
类比说明:
想象一个快递分拣系统:
节点=分拣机器(扫描/分箱/贴标)
边=传送带(决定包裹去向)
状态=包裹信息(实时更新物流状态)
掌握这三个概念后,即可通过组合它们来构建任意复杂度的智能体工作流。
下图直观展示了 LangGraph 的高层运行机制:

LangGraph 智能体及其组件的高层架构
LangGraph 智能体接收的输入可以是用户请求或其他智能体的输出。一般情况下,基于 LLM 的智能体会先处理输入,判断是否需要调用工具(Tools),也可能直接生成响应并进入图的下一阶段。
当智能体决定调用工具时:
这只是 LangGraph 智能体的一种基础工作模式。开发者可以通过不同节点(nodes)和边(edges)的组合实现更复杂的功能。
持久化机制(Persistence)
LangGraph 区别于传统 LangChain 智能体的核心特性是其内置的持久化系统:
循环图结构(Cycles)
LangGraph 突破传统 DAG(有向无环图)限制,支持循环交互:
人工干预能力(Human-in-the-loop)
LangGraph 的关键管控特性:
以下是本文涵盖的关键技术要点:
概念 | 说明 |
什么是LangGraph? | LangGraph是一个将智能体交互建模为状态化图结构的AI框架。节点代表函数或计算步骤,通过边进行连接,所有节点共享智能体状态。相比LangChain,它能实现更复杂的智能体工作流,具备内置持久化、人工干预支持,以及处理循环/分支流程的能力。 |
构建LangGraph智能体 | 通过逐步添加节点和边构建状态化图是理解框架核心的最佳方式。LangGraph Python库采用模块化设计,支持集成工具(如ArXiv论文检索工具)扩展智能体能力。框架还提供预置的ReACT(推理-行动)智能体模板加速开发。 |
LangGraph记忆管理 | 默认无状态的智能体无法记忆历史对话,需通过短期/长期记忆机制增强。LangGraph原生支持基础记忆功能,并可结合Zep Memory实现扩展。 |
Zep长期记忆系统 | Zep作为专为AI智能体设计的记忆层,能自动提取用户对话中的实际并存储为长期记忆对象,有效突破LangGraph原生记忆的限制。 |
开发指南 | LangGraph是构建智能体架构的首选框架,提议: 1) 集成工具链扩展LLM原生能力 2) 使用Zep等第三方SDK快速实现生产级长期记忆功能 |
在 LangGraph 出现之前,LangChain 的链式结构(Chains)和智能体(Agents)是构建 LLM 应用的主流方案。下表清晰展示了两者的核心差异:
特性 | LangGraph 智能体 | LangChain 智能体 |
结构 | 基于图结构(支持循环/分支) | 线性或树状结构(需自定义实现复杂逻辑) |
持久化 | 内置自动状态持久化 | 需手动实现 |
状态管理 | 自动化共享状态 | 需手动维护 |
人工干预 | 原生支持暂停审核机制 | 需自行开发 |
循环控制 | 直接支持多轮循环交互 | 无原生支持 |
灵活性 | 高(自由组合节点/边) | 有限(适合简单任务) |
适用场景 | 复杂工作流(如多工具迭代调用) | 简单链式任务(如线性检索生成) |
总结:LangGraph 在支持复杂工作流(如带循环/分支的逻辑)和开发灵活性上显著优于传统 LangChain 方案,尤其适合需要状态持久化、人工审核或多轮交互的高级应用场景。
目前我们用LangGraph从零开始构建一个完整的多智能体系统。该系统包含一个可与其他专业智能体通信的监督智能体(Supervisor Agent),每个智能体都配备专属工具集——这也正是我们Futuresmart AI构建企业级AI解决方案的架构方式。

多AI智能体
环境配置
第一需要安装以下依赖项
%%capture --no-stderr
%pip install -U langgraph langchain_community langchain_openai langchain_experimental langchain-chroma pypdf sentence-transformers在开始构建LangGraph AI智能体之前,务必先配置好API密钥。这些密钥能让您的智能体安全地调用Tavily搜索和OpenAI GPT模型等外部工具。没有这些密钥,相关工具将无法正常运作。
本文示例使用的是OpenAI模型,但您完全可以根据需求选择其他任意LLM模型。
import getpass
import os
def _set_env(var: str):
if not os.environ.get(var):
os.environ[var] = getpass.getpass(f"{var}: ")
_set_env("TAVILY_API_KEY")
_set_env("OPENAI_API_KEY")创建LLM对象
初始化LLM对象(使用LangChain的ChatOpenAI)
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model_name="gpt-4o")创建监督智能体
监督智能体负责管理不同专业智能体之间的对话流程,决定由哪个智能体处理当前请求以及何时完成任务。具体实现如下:
from typing import Literal
from typing_extensions import TypedDict
from langgraph.graph import MessagesState, START, END
from langgraph.types import Command
# Define available agents
members = ["web_researcher", "rag", "nl2sql"]
# Add FINISH as an option for task completion
options = members + ["FINISH"]
# Create system prompt for supervisor
system_prompt = (
"You are a supervisor tasked with managing a conversation between the"
f" following workers: {members}. Given the following user request,"
" respond with the worker to act next. Each worker will perform a"
" task and respond with their results and status. When finished,"
" respond with FINISH."
)
# Define router type for structured output
class Router(TypedDict):
"""Worker to route to next. If no workers needed, route to FINISH."""
next: Literal["web_researcher", "rag", "nl2sql", "FINISH"]
# Create supervisor node function
def supervisor_node(state: MessagesState) -> Command[Literal["web_researcher", "rag", "nl2sql", "__end__"]]:
messages = [
{"role": "system", "content": system_prompt},
] + state["messages"]
response = llm.with_structured_output(Router).invoke(messages)
goto = response["next"]
print(f"Next Worker: {goto}")
if goto == "FINISH":
goto = END
return Command(goto=goto)
监督智能体的工作流程如下:
实现独立智能体
目前,我们将通过自定义函数为每个专业智能体创建独立的LangGraph图结构。这种方法既能让每个智能体保持各自的工作流程,又能确保它们在请求处理和工具使用上的一致性。
第必定义create_agent函数:
class AgentState(TypedDict):
"""The state of the agent."""
messages: Annotated[Sequence[BaseMessage], add_messages]
def create_agent(llm, tools):
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: AgentState):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
graph_builder = StateGraph(AgentState)
graph_builder.add_node("agent", chatbot)
tool_node = ToolNode(tools=tools)
graph_builder.add_node("tools", tool_node)
graph_builder.add_conditional_edges(
"agent",
tools_condition,
)
graph_builder.add_edge("tools", "agent")
graph_builder.set_entry_point("agent")
return graph_builder.compile()该自定义函数实现以下功能:
目前使用该函数创建专业智能体:
Web Research Agent
websearch_agent = create_agent(llm, [web_search_tool])
def web_research_node(state: MessagesState) -> Command[Literal["supervisor"]]:
result = websearch_agent.invoke(state)
return Command(
update={
"messages": [
HumanMessage(content=result["messages"][-1].content, name="web_researcher")
]
},
goto="supervisor",
)RAG Agent
rag_agent = create_agent(llm, [retriever_tool])
def rag_node(state: MessagesState) -> Command[Literal["supervisor"]]:
result = rag_agent.invoke(state)
return Command(
update={
"messages": [
HumanMessage(content=result["messages"][-1].content, name="rag")
]
},
goto="supervisor",
)NL2SQL Agent
nl2sql_agent = create_agent(llm, [nl2sql_tool])
def nl2sql_node(state: MessagesState) -> Command[Literal["supervisor"]]:
result = nl2sql_agent.invoke(state)
return Command(
update={
"messages": [
HumanMessage(content=result["messages"][-1].content, name="nl2sql")
]
},
goto="supervisor",
)整体集成
最后,我们将创建连接所有智能体的主图结构:
builder = StateGraph(MessagesState)
builder.add_edge(START, "supervisor")
builder.add_node("supervisor", supervisor_node)
builder.add_node("web_researcher", web_research_node)
builder.add_node("rag", rag_node)
builder.add_node("nl2sql", nl2sql_node)
graph = builder.compile()
这样就构建了一个完整的多智能体系统,其工作流程如下:
可视化LangGraph架构
from IPython.display import Image, display
try:
display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
# You can put your exception handling code here
pass
系统测试
目前通过几个示例来测试我们的多智能体系统:
# Example: Complex Query Using Multiple Agents
input_question = "Find the founder of FutureSmart AI and then do a web research on him"
for s in graph.stream(
{"messages": [("user", input_question)]},
subgraphs=True
):
print(s)
print("----")输出
Next Worker: rag
((), {'supervisor': None})
----
INSIDE RETRIEVER NODE
(('rag:7c5458df-0abd-944a-27f7-b0bad49ccf3d',), {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_fK9lMHGrtubenQ697xpd2ZZ2', 'function': {'arguments': '{"question":"Who is the founder of FutureSmart AI?"}', 'name': 'retriever_tool'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 25, 'prompt_tokens': 70, 'total_tokens': 95, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_d28bcae782', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-e538251e-24e9-45ac-a5b7-b4ce111615ad-0', tool_calls=[{'name': 'retriever_tool', 'args': {'question': 'Who is the founder of FutureSmart AI?'}, 'id': 'call_fK9lMHGrtubenQ697xpd2ZZ2', 'type': 'tool_call'}], usage_metadata={'input_tokens': 70, 'output_tokens': 25, 'total_tokens': 95, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}})
----
(('rag:7c5458df-0abd-944a-27f7-b0bad49ccf3d',), {'tools': {'messages': [ToolMessage(content='FutureSmart AI provides customized speech to text services, employing cutting-
edge speech recognition technologies to cater to specific client needs. Ideal for
creating efficient documentation and enabling voice-driven commands, this
solution boosts productivity and accessibility.
FutureSmart AI provides custom Natural Language Processing (NLP)
solutions for companies looking to get ahead of the future. Our
dedicated team of Data Scientists and ML Engineers provides an end-
to-end solution from data labeling to modeling and deploying an ML
model tailored to your specific use case.
Founder: Pradip Nichite
Services:
Text Classification
At FutureSmart AI, we develop custom text classification solutions using
advanced NLP techniques tailored to your specific business requirements.
Leveraging Python, Pytorch, and Hugging Face transformers, we enable precise
data categorization across applications such as intent detection, document
categorization, and sentiment analysis, enhancing your decision-making
processes and operational efficiency.
Chatbots
We specialize in creating custom chatbots that integrate seamlessly with your
business environment. Using semantic search and large language models, our', name='retriever_tool', id='fe12dcaa-a380-437f-8c24-5a7cbf6ab031', tool_call_id='call_fK9lMHGrtubenQ697xpd2ZZ2')]}})
----
(('rag:7c5458df-0abd-944a-27f7-b0bad49ccf3d',), {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_nvmRMsfWcg0YVC9xeTqxZO7z', 'function': {'arguments': '{"question": "Who is Pradip Nichite?"}', 'name': 'retriever_tool'}, 'type': 'function'}, {'id': 'call_IGzCvWkpkzlpwlhFR1MR80U4', 'function': {'arguments': '{"question": "What is the professional background of Pradip Nichite?"}', 'name': 'retriever_tool'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 67, 'prompt_tokens': 322, 'total_tokens': 389, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_d28bcae782', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-a4c6ec42-3aec-449c-ab39-ac029109eaad-0', tool_calls=[{'name': 'retriever_tool', 'args': {'question': 'Who is Pradip Nichite?'}, 'id': 'call_nvmRMsfWcg0YVC9xeTqxZO7z', 'type': 'tool_call'}, {'name': 'retriever_tool', 'args': {'question': 'What is the professional background of Pradip Nichite?'}, 'id': 'call_IGzCvWkpkzlpwlhFR1MR80U4', 'type': 'tool_call'}], usage_metadata={'input_tokens': 322, 'output_tokens': 67, 'total_tokens': 389, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}})
----
INSIDE RETRIEVER NODE
INSIDE RETRIEVER NODE
(('rag:7c5458df-0abd-944a-27f7-b0bad49ccf3d',), {'tools': {'messages': [ToolMessage(content='FutureSmart AI provides customized speech to text services, employing cutting-
edge speech recognition technologies to cater to specific client needs. Ideal for
creating efficient documentation and enabling voice-driven commands, this
solution boosts productivity and accessibility.
FutureSmart AI provides custom Natural Language Processing (NLP)
solutions for companies looking to get ahead of the future. Our
dedicated team of Data Scientists and ML Engineers provides an end-
to-end solution from data labeling to modeling and deploying an ML
model tailored to your specific use case.
Founder: Pradip Nichite
Services:
Text Classification
At FutureSmart AI, we develop custom text classification solutions using
advanced NLP techniques tailored to your specific business requirements.
Leveraging Python, Pytorch, and Hugging Face transformers, we enable precise
data categorization across applications such as intent detection, document
categorization, and sentiment analysis, enhancing your decision-making
processes and operational efficiency.
Chatbots
We specialize in creating custom chatbots that integrate seamlessly with your
business environment. Using semantic search and large language models, our', name='retriever_tool', id='57d1c6f3-b789-4ae1-84c4-c156ca34d3c1', tool_call_id='call_nvmRMsfWcg0YVC9xeTqxZO7z'), ToolMessage(content='FutureSmart AI provides customized speech to text services, employing cutting-
edge speech recognition technologies to cater to specific client needs. Ideal for
creating efficient documentation and enabling voice-driven commands, this
solution boosts productivity and accessibility.
FutureSmart AI provides custom Natural Language Processing (NLP)
solutions for companies looking to get ahead of the future. Our
dedicated team of Data Scientists and ML Engineers provides an end-
to-end solution from data labeling to modeling and deploying an ML
model tailored to your specific use case.
Founder: Pradip Nichite
Services:
Text Classification
At FutureSmart AI, we develop custom text classification solutions using
advanced NLP techniques tailored to your specific business requirements.
Leveraging Python, Pytorch, and Hugging Face transformers, we enable precise
data categorization across applications such as intent detection, document
categorization, and sentiment analysis, enhancing your decision-making
processes and operational efficiency.
Chatbots
We specialize in creating custom chatbots that integrate seamlessly with your
business environment. Using semantic search and large language models, our', name='retriever_tool', id='a498df53-f77a-4bfb-abbf-9153790295e5', tool_call_id='call_IGzCvWkpkzlpwlhFR1MR80U4')]}})
----
(('rag:7c5458df-0abd-944a-27f7-b0bad49ccf3d',), {'agent': {'messages': [AIMessage(content="The founder of FutureSmart AI is Pradip Nichite. Unfortunately, the current retrieval did not provide additional information specifically about Pradip Nichite's professional background or further personal details. For more comprehensive insights, you might consider conducting a more extensive web search or accessing professional networking sites like LinkedIn.", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 63, 'prompt_tokens': 888, 'total_tokens': 951, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_d28bcae782', 'finish_reason': 'stop', 'logprobs': None}, id='run-bc47c29c-0693-41c5-88be-b322e1fbb096-0', usage_metadata={'input_tokens': 888, 'output_tokens': 63, 'total_tokens': 951, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}})
----
((), {'rag': {'messages': [HumanMessage(content="The founder of FutureSmart AI is Pradip Nichite. Unfortunately, the current retrieval did not provide additional information specifically about Pradip Nichite's professional background or further personal details. For more comprehensive insights, you might consider conducting a more extensive web search or accessing professional networking sites like LinkedIn.", additional_kwargs={}, response_metadata={}, name='rag')]}})
----
Next Worker: web_researcher
((), {'supervisor': None})
----
(('web_researcher:509bb5e2-bf9e-2c1d-5c65-978a73d5e94c',), {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_L5d4KhCSPsT5HmHTpHmnyryx', 'function': {'arguments': '{"query":"Pradip Nichite"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 23, 'prompt_tokens': 161, 'total_tokens': 184, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_e161c81bbd', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-35518542-a3b6-424b-b4c7-f8fbb56cffd6-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'Pradip Nichite'}, 'id': 'call_L5d4KhCSPsT5HmHTpHmnyryx', 'type': 'tool_call'}], usage_metadata={'input_tokens': 161, 'output_tokens': 23, 'total_tokens': 184, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}})
----
(('web_researcher:509bb5e2-bf9e-2c1d-5c65-978a73d5e94c',), {'tools': {'messages': [ToolMessage(content='[{"url": "https://www.youtube.com/c/PradipNichiteAI", "content": "Hello, my name is Pradip Nichite. I am a Top Rated Plus Data Science Freelancer with 8+ years of experience, specializing in NLP and Back-End Development. Founder of FutureSmart AI, helping"}, {"url": "https://www.youtube.com/channel/UCwpCmuWq_NPVLNyr8z1IGGQ", "content": "I'm Pradip Nichite, a Top Rated Plus freelance Data Scientist on Upwork , a successful digital nomad , and an entrepreneur. My journey in freelancing has led me to earn over $200K "}]', name='tavily_search_results_json', id='5daeafe8-e673-425e-9d7e-35f49ccae710', tool_call_id='call_L5d4KhCSPsT5HmHTpHmnyryx', artifact={'query': 'Pradip Nichite', 'follow_up_questions': None, 'answer': None, 'images': [], 'results': [{'title': 'Pradip Nichite - YouTube', 'url': 'https://www.youtube.com/c/PradipNichiteAI', 'content': 'Hello, my name is Pradip Nichite. I am a Top Rated Plus Data Science Freelancer with 8+ years of experience, specializing in NLP and Back-End Development. Founder of FutureSmart AI, helping', 'score': 0.8080827, 'raw_content': None}, {'title': 'Pradip Nichite - YouTube', 'url': 'https://www.youtube.com/channel/UCwpCmuWq_NPVLNyr8z1IGGQ', 'content': "I'm Pradip Nichite, a Top Rated Plus freelance Data Scientist on Upwork , a successful digital nomad , and an entrepreneur. My journey in freelancing has led me to earn over $200K ", 'score': 0.7636429, 'raw_content': None}], 'response_time': 1.73})]}})
----
(('web_researcher:509bb5e2-bf9e-2c1d-5c65-978a73d5e94c',), {'agent': {'messages': [AIMessage(content='Pradip Nichite is a Top Rated Plus Data Science Freelancer with over 8 years of experience, specializing in Natural Language Processing (NLP) and Back-End Development. He is the founder of FutureSmart AI. Additionally, Pradip is recognized as a successful digital nomad and entrepreneur, having earned over $200K through freelancing, primarily on platforms like Upwork. For more insights, you can explore his [YouTube channel](https://www.youtube.com/c/PradipNichiteAI), where he shares more about his experiences and expertise.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 116, 'prompt_tokens': 346, 'total_tokens': 462, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_e161c81bbd', 'finish_reason': 'stop', 'logprobs': None}, id='run-32d923b8-a3be-420a-a06f-35a7e27c68bb-0', usage_metadata={'input_tokens': 346, 'output_tokens': 116, 'total_tokens': 462, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}})
----
((), {'web_researcher': {'messages': [HumanMessage(content='Pradip Nichite is a Top Rated Plus Data Science Freelancer with over 8 years of experience, specializing in Natural Language Processing (NLP) and Back-End Development. He is the founder of FutureSmart AI. Additionally, Pradip is recognized as a successful digital nomad and entrepreneur, having earned over $200K through freelancing, primarily on platforms like Upwork. For more insights, you can explore his [YouTube channel](https://www.youtube.com/c/PradipNichiteAI), where he shares more about his experiences and expertise.', additional_kwargs={}, response_metadata={}, name='web_researcher')]}})
----
Next Worker: FINISH
((), {'supervisor': None})
----
通过本教程,我们使用LangGraph构建了一个先进的多智能体系统,展示了专业智能体在中央监督下协同工作的完整实现。该系统体现了智能体编排、工具集成和状态管理等核心技术——这些正是我们Futuresmart AI在企业级解决方案中屡经验证的优势领域。
该架构具有以下核心优势:
模块化:各智能体职责明确,可独立修改
可扩展:新增智能体无需改动现有架构
灵活性:监督智能体动态选择最优执行单元
可控性:工作流清晰定义且易于管理
参考资料:
1. LangGraph Tutorial: Building Agents with LangChain's Agent Framework
2.Build a Multi-Agent System with LangGraph: A Complete Tutorial on Agent Orchestration