目录:
用 Copilot 学 Agent ------ AI 编程的新范式
深入认识 Agent ------ 实现你自己的 Agent
深入认识 Agent ------ 智能体开发框架
前文通过编码实现 Agent demo 的方式介绍了 ReAct、Plan-and-Solve、Reflection 三种模式的智能体,其主要目的是为了更好地理解 Agent 的工作方式。如果要投入到工程实践中去使用,从零开始写代码显然是不推荐的,更好的方式是使用框架。
主流 Agent 框架
本节将介绍 LangChain、LangGraph、AutoGen、Microsoft Agent Framework 等 LLM 应用框架。
LangChain
最早一批 LLM 应用框架中,比较有代表性的是 LangChain。
LangChain 旨在将"调用模型生成文本" 的简单模式扩展为构建具备推理、工具调用和数据整合能力的智能系统。它通过一套统一的抽象层,把 模型、提示词(Prompt)、外部工具(Tools)、记忆(Memory)和数据检索(Retriever)等组件组合在一起,使开发者能够以模块化的方式构建复杂的 AI 应用。
LangChain 是最早一批将 "Agent" 概念工程化的框架之一,它通过 Agent 引入了动态决策能力,让模型根据上下文自主选择是否调用工具、拆解问题并逐步完成任务。
在实际工程中, LangChain 常被用作快速原型开发和 AI 应用架构的基础层。不过由于其抽象层较多,在复杂系统中也可能带来可控性和调试上的挑战。
下面是一个简单的示例:
python
# export OPENAI_API_KEY="your-api-key"
import os
from langchain.agents import create_agent
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"It's always sunny in {city}!"
agent = create_agent(
model="azure_openai:gpt-5.4",
tools=[get_weather],
system_prompt="You are a helpful assistant",
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "What's the weather in San Francisco?"}]}
)
print(result["messages"][-1].content_blocks)
AutoGen
AutoGen 是 Microsoft 推出的一个 Multi-Agent 框架,其核心思想是:将复杂任务拆解为多个子任务,让具备不同职责的 Agent 通过对话驱动的方式协作完成。
AutoGen 从设计上分为以下几层:
Core API,作为框架的底层基础,封装了与大语言模型交互、消息传递等核心功能,保证了框架的稳定性和未来扩展性。AgentChat API,构建于Core之上,提供了用于开发对话式智能体应用的高级接口,简化了多智能体应用的开发流程。Extensions API,允许通过各种第一方和第三方的扩展来增强框架的能力。
下面通过一个实际的例子来演示 AutoGen 的基本使用。
假设任务目标为:编写一个应用程序实时显示比特币当前价格。
为了实现这一任务,需要定义四个职责分明的智能体角色:产品经理,工程师,代码评审员,用户代理。
def create_product_manager(model_client):
"""创建产品经理智能体"""
system_message = """
你是一位经验丰富的产品经理,专门负责软件产品的需求分析和项目规划。
你的核心职责包括:
1. **需求分析**: 深入理解用户需求,识别核心功能和边界条件
2. **技术规划**:基于需求制定清晰的技术实现路径
3. **风险评估**:识别潜在的技术风险和用户体验问题
4. **协调沟通**:与工程师和其他团队成员进行有效沟通
当接到开发任务时,请按以下结构进行分析:
1. 需求理解与分析
2. 功能模块划分
3. 技术选型建议
4. 实现优先级排序
5. 验收标准定义
请简洁明了地回应,并在分析完成后说"请工程师开始实现"。
"""
return AssistantAgent(
name="ProductManager",
model_client=model_client,
system_message=system_message
)
def create_engineer(model_client):
"""创建软件工程师智能体"""
system_message = """
你是一位资深的软件工程师,擅长 Python 开发和 Web 应用构建。
你的技术专长包括:
1. **Python 编程**:熟练掌握 Python 语法和最佳实践
2. **Web 开发**:精通 Streamlit、Flask、Django 等框架
3. **API 集成**:有丰富的第三方 API 集成经验
4. **错误处理**:注重代码的健壮性和异常处理
当收到开发任务时,请:
1. 仔细分析技术需求
2. 选择合适的技术方案
3. 编写完整的代码实现
4. 添加必要的注释和说明
5. 考虑边界情况和异常处理
请提供完整的可运行代码,并在完成后说"请代码审查员检查"。
"""
return AssistantAgent(
name="Engineer",
model_client=model_client,
system_message=system_message,
)
def create_code_reviewer(model_client):
"""创建代码审查员智能体"""
system_message = """
你是一位经验丰富的代码审查专家,专注于代码质量和最佳实践。
你的审查重点包括:
1. **代码质量**:检查代码的可读性、可维护性和性能
2. **安全性**:识别潜在的安全漏洞和风险点,尤其注意网站不能暴露到公网或内网
3. **最佳实践**:确保代码遵循行业标准和最佳实践
4. **错误处理**:验证异常处理的完整性和合理性
审查流程:
1. 仔细阅读和理解代码逻辑
2. 检查代码规范和最佳实践
3. 识别潜在问题和改进点
4. 提供具体的修改建议
5. 评估代码的整体质量
请提供具体的审查意见,完成后说"代码审查完成,请用户代理测试"。
"""
return AssistantAgent(
name="CodeReviewer",
model_client=model_client,
system_message=system_message,
)
def create_user_proxy():
"""创建用户代理智能体"""
system_message = """
用户代理,负责以下职责:
1. 代表用户提出开发需求
2. 执行最终的代码实现
3. 验证功能是否符合预期
4. 提供用户反馈和建议
完成测试后请回复 TERMINATE。
"""
return UserProxyAgent(
name="UserProxyAgent",
description=system_message
)
其中用到了两类智能体:
- AssistantAgent 是主要的任务解决者,本质上是一个封装好的大语言模型。通过系统消息,可以为其赋予特定的"专家 assistant"角色。
- UserProxyAgent,这是 AutoGen 中功能独特的组件。它扮演着双重角色:既是用户代理,负责发起任务和传达意图;又是执行器,可以执行代码或工具并将执行结果反馈给其他 Agent。
AsistentAgent 负责思考和推理,UserProxyAgent 负责执行和交互。
为了让以上智能体进行协作,需要一个机制来协调对话流程:
python
async def run_development_team():
"""运行软件开发团队协作"""
print("🔧正在初始化模型客户端")
model_client = create_azureopenai_model_client()
print("👥正在创建智能体")
product_manager = create_product_manager(model_client)
engineer = create_engineer(model_client)
code_reviewer = create_code_reviewer(model_client)
user_proxy = create_user_proxy()
# 终止条件
termination = TextMentionTermination("TERMINATE")
# 创建团队聊天
team_chat = RoundRobinGroupChat(
participants=[product_manager, engineer, code_reviewer, user_proxy],
termination_condition=termination,
max_turns=20
)
# 定义开发任务
task = """
我们需要开发一个比特币价格显示应用,具体要求如下:
核心功能:
- 实现显示比特币当前价格(USD)
- 显示24小时价格变化趋势(涨跌幅和涨跌额)
- 提供价格刷新功能
技能要求:
- 使用 Streamlit 框架创建 Web 应用
- 界面简洁美观,用户友好
- 添加适当的错误处理和加载状态
请团队协作完成这个任务,从需求分析到最终实现。
"""
# 执行团队协作
print("🚀启动 AutoGen 软件开发团队协作...\n" + "=" * 60)
result = await Console(team_chat.run_stream(task=task))
print("\n" + "=" * 60 + "\n✅团队协作完成")
return result
这里用到了 RoundRobinGroupChat, 这是一种明确的、顺序化的对话协调机制。工作流如下:
- 创建
RoundRobinGroupChat实例,将所有参与协作的智能体加入其中。 - 任务开始后,群聊会按照预设的顺序,激活相应的智能体。
- 被激活的智能体根据当前的对话上下文进行响应。
- 群聊将新的回复加入到对话历史,并激活下一个智能体。
- 这个过程会持续进行直到达到最大对话轮次或满足预设的终止条件。
通过这种方式,AutoGen 将复杂的协作关系简化成了一个流程清晰、易于管理的自动化圆桌会议。
接下来需要创建模型客户端,还是以 Azure OpenAI 为例:
python
import os
import asyncio
from dotenv import load_dotenv
from autogen_ext.models.openai import AzureOpenAIChatCompletionClient
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console
load_dotenv()
def create_azureopenai_model_client():
"""创建 AzureOpenAI 模型客户端"""
return AzureOpenAIChatCompletionClient(
azure_deployment=os.getenv("LLM_MODEL_ID"),
model=os.getenv("LLM_MODEL_NAME"),
api_version=os.getenv("LLM_API_VERSION"),
azure_endpoint=os.getenv("LLM_BASE_URL"),
api_key=os.getenv("LLM_API_KEY")
)
最后在异步函数中启动并运行协作流程:
python
if __name__ == '__main__':
try:
result = asyncio.run(run_development_team())
print(f"\n🗒️协作结果摘要:")
print(f"- 任务完成状态:{'成功' if result else '需要进一步处理'}")
except ValueError as e:
print(f"❌配置错误: {e}")
except Exception as e:
print(f"❌运行错误: {e}")
运行结果如下:
🔧正在初始化模型客户端
👥正在创建智能体
🚀启动 AutoGen 软件开发团队协作...
============================================================
---------- TextMessage (user) ----------
我们需要开发一个比特币价格显示应用,具体要求如下:
...
请团队协作完成这个任务,从需求分析到最终实现。
---------- TextMessage (ProductManager) ----------
### 1. 需求理解与分析
...
请工程师开始实现。
---------- TextMessage (Engineer) ----------
### 开始实现
根据需求分析和功能模块划分,我们将按照优先级逐步实现功能。
...
请代码审查员检查。
---------- TextMessage (CodeReviewer) ----------
### 代码审查
...
代码审查完成,请用户代理测试。
Enter your response: TERMINATE
---------- TextMessage (UserProxyAgent) ----------
TERMINATE
============================================================
✅团队协作完成
🗒️协作结果摘要:
- 任务完成状态:成功
局限性
AutoGen 的对话式架构在复杂任务中可能陷入死循环,难以调试和控制,缺乏确定性。
截止到目前,MicroSoft 已经将其置于维护模式,仅接受社区贡献,不再开发新功能,并推荐新项目转向 Agent Framework。
尽管有上述局限,但对于短期 PoC,AutoGen 还是一个绝佳的低门槛选择。
LangGraph
LangGraph 是 LangChain 生态的一部分,作为 LangChain 生态系统的重要扩展,它代表了智能体框架设计的一个全新方向。与基于对话的框架不同,LangGraph 将智能体的执行流程建模为一种状态机,并将其表示为有向图(Directed Graph)。在这种设计中,图的节点代表一个具体的计算步骤(如调用 LLM、执行工具),而边则定义了从一个节点到另一个节点的跳转逻辑。这种设计的好处是天然支持循环、使得构建能够进行迭代、反思和自我修正的复杂智能体工作流变得前所未有的直观和简单。
LangGraph 带来的直观好处:
- 断点续跑:内置的检查点(Checkpoint)机制能在任何节点保存状态,系统重启或出错都可以从任意点恢复。
- 人工干预:可以原生地在流程特定节点暂停,等待人工审核或输入后再继续。
- 易于调试:每一步执行都可追溯,并通过可视化界面调试。
LangGraph 三个基本构成要素分别是全局状态(State)、节点(Nodes)和边(Edges):
- 全局状态被整个图共享,所有节点都能读取和更新这个全局状态,它通常被定义为一个字典类型,包含对话历史、中间结果、迭代次数等。
- 节点实际上是一个函数,接收当前状态作为输入,并返回一个更新后的状态作为输出,它是执行具体工作的单元。
- 边负责连接节点,定义工作流的方向。边有两种:简单边和常规边。简单边将两个节点简单地连接起来,而条件边则可以通过一个函数来判断当前的状态,然后根据条件函数的结果来将工作流路由到下一个节点。这正是实现循环和复杂逻辑分支的关键。
下面用 LangGraph 来实现一个讲笑话的工作流:
python
import os
from langgraph.constants import START, END
from langgraph.graph import StateGraph
from typing_extensions import TypedDict
from dotenv import load_dotenv
from langchain_openai import AzureChatOpenAI
load_dotenv()
llm = AzureChatOpenAI(
azure_deployment=os.getenv("LLM_MODEL_ID"),
api_version=os.getenv("LLM_API_VERSION"),
azure_endpoint=os.getenv("LLM_BASE_URL"),
api_key=os.getenv("LLM_API_KEY"),
temperature=0.9
)
# 全局状态
class State(TypedDict):
topic: str
joke: str
improved_joke: str
final_joke: str
# Nodes
def generate_joke(state: State):
"""调用 LLM 生成初始的笑话"""
msg = llm.invoke(f"Write a short joke about {state['topic']}")
return {"joke": msg.content}
def improve_joke(state: State):
"""二次调用 LLM 提升笑话水平"""
msg = llm.invoke(f"Make this joke funnier by adding wordplay: {state['joke']}")
return {"improved_joke": msg.content}
def polish_joke(state: State):
"""第三次调用 LLM 生成最终结果"""
msg = llm.invoke(f"Add a surprising twist to this joke: {state['improved_joke']}")
return {"final_joke": msg.content}
# 状态判断函数
def check_punchline(state: State):
# Simple check - does the joke contain "?" or "!"
if "?" in state["joke"] or "!" in state["joke"]:
return "Pass"
return "Fail"
workflow = StateGraph(State)
# add notes
workflow.add_node("generate_joke", generate_joke)
workflow.add_node("improve_joke", improve_joke)
workflow.add_node("polish_joke", polish_joke)
# add edge
workflow.add_edge(START, "generate_joke")
workflow.add_conditional_edges(
"generate_joke", check_punchline, {"Fail": "improve_joke", "Pass": END}
)
workflow.add_edge("improve_joke", "polish_joke")
workflow.add_edge("polish_joke", END)
# compile the workflow
chain = workflow.compile()
png_data = chain.get_graph().draw_mermaid_png()
with open("graph.png", "wb") as f:
f.write(png_data)
state = chain.invoke({"topic": "dog"})
print("😂Initial joke:")
print(state["joke"])
print("--- --- --- --- ---")
if "improved_joke" in state:
print("😂Improved joke:")
print(state["improved_joke"])
print("--- --- --- --- ---")
print("😂Final joke:")
print(state["final_joke"])
else:
print("😂Final joke:")
print(state["joke"])
生成的有向图如下:

运行结果如下:
😂Initial joke:
Why did the dog sit in the shade?
Because it didn't want to be a **hot dog**! 🌭
--- --- --- --- ---
😂Final joke:
Why did the dog sit in the shade?
Because it didn't want to be a **hot dog**! 🌭
因为在第一个节点 generate_joke 之后的条件边中进行状态判断时将工作流路由到了 END 节点,而没有经过剩下的两个节点,所以全局状态中只有 joke 字段。
优点与局限性
LangGraph 的节点都是独立的函数,因此可以非常方便地在流程中插入等待人工审核的节点,为实现可靠的人机协作(Human in the loop)提供了坚实的基础。
相比于基于对话的框架,LangGraph 的开发过程更为繁琐,开发者不仅仅要考虑做什么,还要考虑如何去控制工作流程。此外,LangGraph 的行为虽然可控,但也缺少了对话式智能体那种动态的、涌现式交互,其强项在于执行一个确定的、可靠的流程,而非模拟开放式的、不可预测的社会性协作。
Microsoft Agent Framework
上文介绍 AutoGen 时说过,该项目已进入维护模式,适合在原型系统中快速验证使用。而 MAF(Microsoft Agent Framework)是官方推出的新一代多智能体框架。
直接看一个简单的例子:
python
import os
import asyncio
from agent_framework_openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
from agent_framework import Agent
load_dotenv()
async def main():
agent = Agent(
client=OpenAIChatCompletionClient(
model=os.getenv("LLM_MODEL_ID"),
api_version=os.getenv("LLM_API_VERSION"),
azure_endpoint=os.getenv("LLM_BASE_URL"),
api_key=os.getenv("LLM_API_KEY")
),
name="HaikuAgent",
instructions="You are an upbeat assistant that writes beautifully."
)
print(await agent.run("Write a haiku about Microsoft Agent Framework."))
if __name__ == '__main__':
asyncio.run(main())
运行结果如下:
Code whispers take form,
Agents dance in quiet scope,
Tasks bloom, seamless grace.
这个例子展示了 MAF 中 agent 的调用方式。接下来扩展一下,使用多 Agent 进行协作:
python
import asyncio
import os
from agent_framework import Agent, workflow
from dotenv import load_dotenv
from agent_framework_openai import OpenAIChatCompletionClient
load_dotenv()
client = OpenAIChatCompletionClient(
model=os.getenv("LLM_MODEL_ID"),
api_version=os.getenv("LLM_API_VERSION"),
azure_endpoint=os.getenv("LLM_BASE_URL"),
api_key=os.getenv("LLM_API_KEY")
)
writer = Agent(
name="WriterAgent",
instructions="Write a short poem about the given topic in Chinese.",
client=client
)
reviewer = Agent(
name="ReviewerAgent",
instructions="Review the given poem in Chinese.",
client=client
)
@workflow
async def poem_workflow(topic: str) -> str:
poem = (await writer.run(f"Write a poem about: {topic}")).text
review = (await reviewer.run(f"Review this poem: {poem}")).text
return f"Poem:\n{poem}\n\nReview:{review}"
async def main() -> None:
result = await poem_workflow.run("思乡")
print(result.get_outputs()[0])
if __name__ == '__main__':
asyncio.run(main())
运行结果如下:
Poem:
在异乡处思乡切,
心随月影绕村阶。
故土若梦藏心底,
炊烟袅袅忆童年家。
归雁声中春水涨,
驿路遥遥心更牵。
愿化微风归山谷,
拂遍桑田与荷莲。
Review:这是一首充满浓厚乡愁情感的诗,语言清丽流畅,意境优美深远,情感真挚动人。整首诗运用自然景色和情感描写,表现了远离故乡的游子对家乡的深深怀恋以及希望归乡的强烈愿望。以下是对这首诗的具体分析与点评:
**第一联:**
"在异乡处思乡切,
心随月影绕村阶。"
开篇从"异乡"入手点题,"思乡切"直接流露出浓烈的情感,句意直白却触动人心。第二句描写"月影绕村阶",以月影表达心绪,将作者的思乡情感自然地嵌入情景之中,画面感十足。这一联意境悠远,为全诗奠定了感伤基调。
**第二联:**
"故土若梦藏心底,
炊烟袅袅忆童年家。"
这一联从情感转向记忆,描绘故乡如梦般深藏于心。特别是"炊烟袅袅"这一景象,极具乡村特色,唤起了对温暖童年时光的记忆。文字生动,情景交融,让读者产生共鸣。
**第三联:**
"归雁声中春水涨,
驿路遥遥心更牵。"
这里从现实场景出发,"归雁"与"春水"象征了季节的变化,同时为表达心绪提供了契机。"驿路遥遥"直接写离家的路途遥远,"心更牵"则简明而深刻地揭示了游子心中愈发浓烈的乡愁。自然景象与情感相辅相成,结构合理。
**第四联:**
"愿化微风归山谷,
拂遍桑田与荷莲。"
结尾联情感达到了高潮,以"愿化微风"的形象化方式,表达出归乡的迫切与浓烈的情意,"桑田"与"荷莲"具体化了归乡后的画面,诗人希望自己回归乡土,融入天地自然。这一联不仅抒发了个人情感,也有某种超越具体情境的普遍性,令人动容。
**总体评价:**
这首诗在意象选择和情感表达上都非常用心,整篇意境优美,语言凝练,音韵和谐美好,使用工整的对仗手法,使得诗句节奏明快,同时在平易中蕴含深意,是一篇极为成功的五言近体诗。唯一可以进一步提升的地方是构建更为独特的意象,与其它类似的乡愁题材作品区分开来。但总体而言,这首诗非常动人,充满乡情,值得细细品味。
这个例子展示了多 Agent 通过 workflow 的方式来协作,但这个工作流仍然是链式工作流,无法实现人机协同。
下面这个例子演示图工作流:
python
import asyncio
import os
from agent_framework_openai import OpenAIChatCompletionClient
from pydantic import BaseModel
from dotenv import load_dotenv
from agent_framework import Agent, Executor, WorkflowBuilder, WorkflowContext, handler
from typing_extensions import Never
load_dotenv()
client = OpenAIChatCompletionClient(
model=os.getenv("LLM_MODEL_ID"),
api_version=os.getenv("LLM_API_VERSION"),
azure_endpoint=os.getenv("LLM_BASE_URL"),
api_key=os.getenv("LLM_API_KEY")
)
class State(BaseModel):
topic: str
joke: str | None = None
improved_joke: str | None = None
class GenerateJoke(Executor):
def __init__(self, id: str, agent: Agent):
super().__init__(id=id)
self._agent = agent
@handler
async def run(self, state: State, ctx: WorkflowContext[State]) -> None:
msg = await self._agent.run(f"Write a short joke about {state.topic}")
next_state = state.model_copy(update={"joke": str(msg).strip()})
await ctx.send_message(next_state)
class ImproveJoke(Executor):
def __init__(self, id: str, agent: Agent):
super().__init__(id=id)
self._agent = agent
@handler
async def run(self, state: State, ctx: WorkflowContext[Never, State]) -> None:
msg = await self._agent.run(
f"Make this joke funnier by adding wordplay: {state.joke}"
)
final_state = state.model_copy(update={"improved_joke": str(msg).strip()})
await ctx.yield_output(final_state)
def create_workflow():
agent = Agent(name="joke-agent", client=client, instructions="You write and improve short jokes.")
generate = GenerateJoke(id="generate_joke", agent=agent)
improve = ImproveJoke(id="improve_joke", agent=agent)
return (
WorkflowBuilder(start_executor=generate)
.add_edge(generate, improve)
.build()
)
async def main():
workflow = create_workflow()
events = await workflow.run(State(topic="dog"))
state = events.get_outputs()[0]
print("Initial joke:")
print(state.joke)
print("--- --- --- --- ---")
print("Improved joke:")
print(state.improved_joke)
if __name__ == "__main__":
asyncio.run(main())
这是最简单的图:两个节点加上一条边。对其稍加改动,让工作流在第一个节点之后进行条件判断,动态地路由到下一个节点:
python
import asyncio
import os
from agent_framework_openai import OpenAIChatCompletionClient
from dotenv import load_dotenv
from pydantic import BaseModel
from agent_framework import Agent, Executor, WorkflowBuilder, WorkflowContext, handler
load_dotenv()
client = OpenAIChatCompletionClient(
model=os.getenv("LLM_MODEL_ID"),
api_version=os.getenv("LLM_API_VERSION"),
azure_endpoint=os.getenv("LLM_BASE_URL"),
api_key=os.getenv("LLM_API_KEY")
)
class State(BaseModel):
topic: str
joke: str | None = None
improved_joke: str | None = None
final_joke: str | None = None
class GenerateJoke(Executor):
def __init__(self, id: str, agent: Agent):
super().__init__(id=id)
self._agent = agent
@handler
async def run(self, state: State, ctx: WorkflowContext[State]) -> None:
msg = await self._agent.run(f"Write a short joke about {state.topic}")
await ctx.send_message(state.model_copy(update={"joke": str(msg).strip()}))
class ImproveJoke(Executor):
def __init__(self, id: str, agent: Agent):
super().__init__(id=id)
self._agent = agent
@handler
async def run(self, state: State, ctx: WorkflowContext[State]) -> None:
msg = await self._agent.run(f"Make this joke funnier by adding wordplay: {state.joke}")
await ctx.send_message(state.model_copy(update={"improved_joke": str(msg).strip()}))
class PolishJoke(Executor):
def __init__(self, id: str, agent: Agent):
super().__init__(id=id)
self._agent = agent
@handler
async def run(self, state: State, ctx: WorkflowContext[State]) -> None:
msg = await self._agent.run(f"Add a surprising twist to this joke: {state.improved_joke}")
await ctx.send_message(state.model_copy(update={"final_joke": str(msg).strip()}))
class OutputState(Executor):
def __init__(self, id: str):
super().__init__(id=id)
@handler
async def run(self, state: State, ctx: WorkflowContext[None, State]) -> None:
if state.final_joke is None:
state = state.model_copy(update={"final_joke": state.joke})
await ctx.yield_output(state)
def check_punchline_pass(state: State) -> bool:
joke = state.joke or ""
return ("?" in joke) or ("!" in joke)
def create_workflow():
writer = Agent(name="writer", client=client, instructions="You write short jokes.")
generate = GenerateJoke(id="generate_joke", agent=writer)
improve = ImproveJoke(id="improve_joke", agent=writer)
polish = PolishJoke(id="polish_joke", agent=writer)
output = OutputState(id="output_state")
return (
WorkflowBuilder(start_executor=generate)
.add_edge(generate, output, condition=check_punchline_pass)
.add_edge(generate, improve, condition=lambda s: not check_punchline_pass(s))
.add_edge(improve, polish)
.add_edge(polish, output)
.build()
)
async def main():
workflow = create_workflow()
events = await workflow.run(State(topic="dog"))
state = events.get_outputs()[0]
print("😂Initial joke:")
print(state.joke)
print("--- --- --- --- ---")
if state.improved_joke is not None:
print("😂Improved joke:")
print(state.improved_joke)
print("--- --- --- --- ---")
print("😂Final joke:")
print(state.final_joke)
if __name__ == "__main__":
asyncio.run(main())
Graph workflow 的例子实现的功能跟上文的 LangGraph 例子是一样的。
MAF 中的几个重要概念:
Executors,独立的处理单元,可以是 AI Agents 或者特定的逻辑组件,实际上就是图的节点。Edges,连接两个节点的边,决定消息的流向。Events,提供对工作流执行结果的可观测性,包括生命周期事件、节点事件和特定事件。
参考资料
1\]. https://github.com/microsoft/agent-framework