微信扫码
添加专属顾问
我要投稿
探索AI Agent智能体的进化之路,从workflow模式到ReAct框架的突破。核心内容:1. AI Agent与传统workflow模式Agent的区别2. 运维案例中LLM在workflow模式中的应用3. ReAct框架对Agent智能化水平的提升作用
▲关注公众号,可查看更多精彩内容
本号之前文章中介绍了用dify工具实现的针对故障拍照进行智能检索的运维神器,这个案例中Agent是使用典型的workflow方式配置出来的,“先进行OCR,然后检索知识,最后生成答案”这个执行步骤是我们预先定义好的,包括网上很多Agent文章中描述大多也和我们这个案例类似,但这似乎和AI Agent的标准定义还是有差距,我们先随便找个大模型,问问AI Agent的标准定义大概如下:
AI Agent(智能体)是一种具备自主决策与执行能力的智能实体,能够通过感知环境、动态调整行为以实现预设目标。其本质是通过融合大语言模型(LLM)的推理能力和工具调用机制,将传统AI的被动响应升级为主动任务执行能力。
Agent这个标准定义,是包含了感知环境-思考决策-行动执行的闭环逻辑,也就是要符合ReAct框架(Reasoning+Action),以下说明workflow模式与ReAct框架Agent实现逻辑的不同。
使用workflow模式的Agent
我们先分析之前运维案例中的workflow,它们执行步骤和逻辑是在workflow中预设好的:
这不由得让人反思我们这类智能体的“智能”体现在哪里呢?答案是这些Agent中不仅仅有workflow,更关键是其中用到的LLM。
比如在这个运维案例中,是利用LLM的文字生成和整合能力,输出故障的最终解决方案,虽然前序知识检索环节有可能检索到故障对应的答案,但这些答案往往比较简略,还需要LLM根据Prompt指令“按【原因分析】、【影响范围】、【处置建议】结构化输出”,并且指定如果当前序环节没有检索到答案时,还需要LLM能自行分析并生成解决办法。
我们再看看笔者之前另外一个中考小助手案例中,利用的是LLM进行语义理解和意图识别,要区分用户输入的问题是在问某个学校的分数线,还是在问某个分数能上什么学校,还是其他问题等,然后在workflow中才能根据不同的意图,走不同分支的处理逻辑。
所以在我们大多数场景中,用workflow这种模式,再结合LLM的语义理解、意图识别、文字生成和整合能力就能够实现一个较好的Agent。
使用Function Call实现ReAct框架
以上workflow模式的Agent核心是执行逻辑是可预设的,但有些业务场景中业务执行逻辑是不确定的,是要依据前序环节的执行结果,动态决策下一步该怎么做,也就是对应ReAct框架的思考-行动-观察的闭环,如下图所示(源图来自https://react-lm.github.io/):
这个图很好地说明了右边ReAct框架相比原有模式的区别,每次要观察observe上一次行动action的结果,也就是将上次调用结果作为输入,再输入给LLM,一起去思考下一步该如何action。
ReAct框架(Reasoning + Acting)是一种结合推理与行动的多步骤高阶任务执行范式,而上图中LLM与外部工具/环境ENV交互action的基础能力,就是依靠Function Call作为底层支撑技术。
Function Call是大型语言模型(LLM)通过语义理解与结构化输出调用外部工具的核心能力,其实现依赖以下关键环节:
get_weather()函数
)。import openai
import json
from typing import get_type_hints
# 示例函数定义
def get_current_weather(location: str, unit: str = "celsius") -> str:
"""获取指定地区的当前天气情况"""
# 这里模拟天气数据
weather_data = {
"beijing": {"celsius": 22, "fahrenheit": 72},
"new york": {"celsius": 18, "fahrenheit": 64}
}
returnf"{location}天气:{weather_data.get(location.lower(), {}).get(unit, '未知')}°{unit}"
def calculate(expression: str) -> float:
"""执行数学计算(支持加减乘除)"""
try:
returneval(expression.replace("^", "**"))
except:
return"计算错误"
# 生成函数描述JSON Schema
def generate_function_schema(func):
hints = get_type_hints(func)
doc = func.__doc__.split("\n") if func.__doc__ else""
return {
"name": func.__name__,
"description": doc,
"parameters": {
"type": "object",
"properties": {
param: {
"type": "string"if hints.get(param) == strelse"number",
"description": f"{param}参数"
} for param inlist(hints.keys())[:-1] # 排除返回类型
},
"required": list(get_type_hints(func).keys())[:-1]
}
}
# 可用函数列表
available_functions = {
"get_current_weather": get_current_weather,
"calculate": calculate
}
# 生成函数描述列表
functions = [generate_function_schema(func) for func in available_functions.values()]
# 与LLM交互的核心函数
def run_conversation(user_query: str):
# 第一次LLM调用(选择函数)
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613", # 要选择支持函数调用的模型
messages=[{"role": "user", "content": user_query}],
functions=functions, # 输入函数定义
function_call="auto"
)
response_message = response["choices"]["message"]
# 如果LLM选择调用函数,就会在输出response_message中,把要调用的函数和对应参数都输出
if response_message.get("function_call"):
function_name = response_message["function_call"]["name"]
function_args = json.loads(response_message["function_call"]["arguments"])
print(f"LLM选择调用函数: {function_name}")
print(f"参数: {function_args}")
# 执行对应函数
if function_name in available_functions:
function_to_call = available_functions[function_name]
# 参数类型转换
try:
args = {k: str(v) for k,v in function_args.items()} # 统一转为字符串
if function_name == "calculate":
args["expression"] = args["expression"].replace(" ", "")
# 敲黑板 注意:实际执行函数还是本地代码,并不是LLM直接去调用哈
result = function_to_call(**args)
returnf"执行结果: {result}"
except Exception as e:
returnf"执行错误: {str(e)}"
else:
return"未知函数调用"
else:
return"未触发函数调用"
# 测试用例
if __name__ == "__main__":
test_cases = [
"北京现在的气温是多少?",
"帮我计算(3 + 5) * 2^3的值",
"今天纽约的天气怎么样?用华氏度"
]
for query in test_cases:
print(f"\n用户问:{query}")
print("->", run_conversation(query))
笔者个人理解如果Prompt中把执行步骤描述得很清楚,就应该算是workflow模式,无非它是用文字来表达执行逻辑,同时利用LLM的function call能力,根据预定的执行逻辑调用预设好的插件。
但如果Prompt只是描述目标,没有对执行步骤做详细描述,那应该可以说是ReAct模式,它通过右边的插件设置,将所有可以调用的工具/函数都提前注册进来,运行时和Prompt一起输入给LLM,由LLM自行规划处理路径,中间何时要调用外部插件,都是LLM自行决策的。
无论怎么理解,只能说Coze的这个智能体已经很智能了。
从Function Call到MCP
搞清楚ReAct框架和Function Call的关系以后,我们再看看MCP(Model Context Protocol)大模型上下文协议,去年Anthropic推出的MCP概念,今年以来热度持续上升,尤其是OpenAI也宣布支持MCP以后,似乎一页之间万能手、通用agent等概念都有了落脚点。官网对MCP架构的介绍可以参考这个链接,主要架构图如下(https://modelcontextprotocol.io/introduction):
其实笔者认为mcp和function call本质上没有太大区别,只是把函数调用的规范做了统一,按统一规范由mcp client发给远程某个MCP Server再执行具体tool。为了更直观地对比在ReAct框架中MCP和function call区别,我们画个图来表示,如下:
要实现mcp这种方式的工具调用,首先也是需要将函数/工具的描述信息schema先要输入给LLM,只不过functioncall是在本地生成函数描述的,而mcp则是远程从mcp server中自动拉取的工具描述,远程mcp server端有哪些工具的描述,是基于server端工具在开发时用注解的方式描述函数名、用途和参数信息来自动生成的。
和上文介绍的function call机制一样,LLM本身也不会真的去调用mcp server里的工具,LLM是个语言模型,它的输入输出永远是一段文本,它只是识别需要调用哪个工具,并将要调用的工具名、参数以json格式结构化文本输出,然后是由LLM所在的Host去调用。
这个Host有一个误区,网上看到的各种mcp文章,都是用Claude desktop、cursor或者dify、cherry studio这种工具来举例,很容易让人和mcp client这个概念混淆起来,实际这个host更常见的是Agent所在的代码,是通过在这个代码中引入mcp client包去发给远程mcp server去执行的。
以上就是AI Agent从workflow固化流程到基于Function Call的ReAct框架,再从Function Call到统一标准的MCP的一个发展过程,但AI领域生态发展是飞速向前的。
4.10日Google又发布了开源协议A2A(Agent-to-Agent),使得基于不同底层框架和供应商平台创建的 AI Agent 之间能够实现相互通信,实现多智能体之间的协作,也是Agent这个领域的最近最为火热的发展方向,但本质上如果你将MCP Server后面对接另外一个Agent,实际也能实现多智能体的协作,笔者推测A2A可能也就是对Host Agent中LLM通过mcp client调用mcp server端的另一个Agent的过程做了一个简化封装,当然有待后续实践后再进行详细分享。
注:笔者在以往案例基础上结合实际项目经验,从应用AI和落地AI的视角出发,按照LM、RAG、Agent、Training这样的顺序梳理一套基础技术体系,对应投入和落地难度从小到大,本文是其中对Agent板块的部分总结,欢迎读者持续关注完整合集。
—End—
如果您觉得这篇文章对您有帮助欢迎转发和分享,也恳请您关注以下公众号,里面有更多精彩思考和总结
注:原创不易,合作请在公众号后台留言,未经许可,不得随意修改及盗用原文。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2025-02-04
2025-02-04
2024-09-18
2024-07-11
2024-07-09
2024-07-11
2024-07-26
2025-02-05
2025-01-27
2025-02-01