ReAct模式
1.简述
LLM根据当前的结果(Observation),推理和思考(Thought),决定执行什么行动(Action),通过function call的机制得到最新的结果(Observation),然后再使用LLM推理和思考,循环执行,直到LLM自己判断完成任务,则结束。
2.具体实现:
System prompt:
react_prompt = """
你是一个中文AI助手。除了格式关键词外,请始终使用中文回复。
尽可能好地回答以下问题。你可以使用以下工具:
{tools}
使用以下格式:
Question: 你必须回答的输入问题
Thought: 你应该始终用中文思考下一步该做什么
Action: 要采取的行动,必须是[{tool_names}]其中之一
Action Input: 行动的输入内容
Observation: 行动的结果
...(这个Thought/Action/Action Input/Observation可以重复N次)
Thought: 我现在知道最终答案了
Final Answer: 对原始输入问题的最终答案
Begin!
Question: {input}
"""
大模型会自动规划执行路径:“Thought” -> "Action" -> "Observation" -> “Thought” -> "Action" -> "Observation" -> “Thought” ->···,循环执行这些动作,通过LLM的自我推理和判断能力,思考-执行-观察-再思考-再执行-再观察···。
“Thought”:LLM自我推理的能力。
“Action”:具体的行动,也就是执行特定的tool,就是function call的能力。
“Observation”:执行具体action的结果。
结束条件:prompt中定义了“Final Answer”,在具体实现的时候,是循环执行调用LLM,如果大模型的结果中包含“Final Answer”内容了,则结束整个过程。
核心代码:
def react(question: str, tools: List[Callable]) -> str:
react_prompt = """ ***"""
tool_descriptions = "\n".join([f"{tool.name}: {tool.description}" for tool in tools])
tool_names = ", ".join([tool.name for tool in tools])
user_prompt = react_prompt.format(
tools=tool_descriptions,
tool_names=tool_names,
input=question
)
messages = [{"role": "user", "content": user_prompt}]
last_content_length = 0
while True:
# 构造message
last_content_length = format_message(messages, last_content_length)
# 调用LLM思考,thought
response = get_model_response_sync(model_name="deepseek-chat", messages=messages, stop=["Observation", " Observation"])
messages[-1]["content"] += response
# 结束条件
if "Final Answer:" in response:
break
# 解析 function call的内容,tool的名称和参数
regex = r"Action: [(.*?)][\s]*Action Input: (.*?)(?:\n|$)"
action_match = re.search(regex, response, re.DOTALL)
# 如果发现有tool被选中
if action_match:
action = action_match.group(1)
action_input = action_match.group(2).strip()
tool = next((t for t in tools if t.name == action), None)
if tool:
observation = tool(action_input) # 执行tool,获得observation结果
# 更新message,把当前的observation加进来
messages[-1]["content"] += f"\nObservation: {observation}\nThought: "
# 打印最后的新内容
format_message(messages, last_content_length)
final_answer = re.search(r"Final Answer:(.*)", response, re.DOTALL)
return final_answer.group(1).strip() if final_answer else "未找到最终答案。"
3.ReAct模式缺点和问题
-
问题:
-
“回复多样性” 与“工具选择确定性” 两个要求之间的悖论
- 大模型通过“温度”这个超参数来控制输出概率的发散性,温度较小,输出比较固定,温度较大,输出比较发散,很多时候我们希望大模型的回复有更多的创造性和发散性。
- 但是在ReAct模式中,在“Thought”环节需要依赖LLM的可靠性和稳定性,即希望LLM能准确选择tool并输出正确格式的回复。这就需要我们尽可能把“温度”调低一点,这样LLM就能更稳定的选择并执行“工具调用”。
- 上面两个要求就是鱼和熊掌不可兼得。
-
“非常多工具”的情况很难处理.
-
循环过程需要多次带冗余前缀的LLM调用,消耗更多token和时间。
-
如果我们定义的tool有非常多,比如50个甚至100个,在ReAct模式中,system prompt需要将所有tool的name和description拼接进去,这将会非常长,带来的挑战是:
- 需要一个训练良好的LLM,可以非常擅长区分多工具描述的细微差异,并做出正确判断,而通用的LLM很难做到。
- 当面对非常多的工具,就需要用户的描述更清晰和确定,而我们很难控制用户的输入质量,不清晰的用户query就会导致工具选择错误,甚至会导致LLM进入不断错误循环之中。
-
解决方案:
-
细分场景:尽可能的拆分业务场景,每个场景构建独立的Agent。
-
流程拆分:不能完全依赖LLM的“Thougnt”能力,有一些判断的逻辑需要根据业务情况代码实现,需要结合到一起。比如:“待办事项”的判断,可以结合句法解析来辅助实现。比如多模态问答,要先判断类型,把类别抽取出来,比如“花草”、“车”,构建不同的prompt喂给大模型,回复效果会更好。
-
多Agent合作:当场景和流程都拆分之后,就需要考虑怎么将多个Agent融合到一起。有一些好的框架和解决方案,比如OpenAI开源的Swarm框架。
-
参考:
Plan-and-Execute模式
1.简述
这种模式的流程是:
-
借助LLM执行“Plan”,拆解产生待执行“任务列表”。
-
迭代执行“Execute”每一个任务,当完成一个特定的任务。
-
每完成一个任务,可以更新状态,重新执行“Plan”修改“任务列表”。
-
循环“Plan”-“Execute”-“Plan”-“Execute”这个过程,直到完成整个任务。
3.问题:
- 规划模式更适合目标达成路径不明确且需要灵活适应问题并提出解决方案的场景,适合深度推理和多步推理的任务。例如,要实现一个修复软件bug的Agent,需要能够自主拆解执行过程,比如“读bug的log信息”、“定位相关代码段”、“思考错误原因列表”、“选择合适的调整策略”、“运行修复的代码”、“观察log信息”、 “若失败则调整方案”。
- 可能导致简单问题复杂化。
2.相比较ReAct模式的优势:
- 先进行任务拆解,显性地进行长距离任务规划,即使非常厉害的LLM也很难直接执行任务。
- 这种模式,将“Plan”和“Execute”解耦,可以灵活地设计agent,只需要在“Plan”阶段使用更大更强的模型,在“Execute”环节可以使用更小的模型。
- Agent能够自主地将复杂任务拆解成更细粒度的子任务(“Plan”),提升了推理能力,增强问题解决能力,减少幻觉,提高输出的可靠性。
ReWOO(Reasoning WithOut Observation)模式
1.简述
ReAct是典型的Reasoning with Observation模式,需要循环执行“Thought”(T),“Action”(A)和“Observation”(O)。而ReWOO是没有“Observation”,ReWOO模式包括三部分:
- Planner:充分利用LLM的推理和规划能力生成“问题解决蓝图”,生成任务执行列表,每一步任务用(Plan,#E)来描述,其中“Plan”是文字描述当前的执行步骤,是用约定的格式来表示需要执行的tool,下标s表示执行的第几步。这种模式,让ReWOO能够解决多步和更复杂的问题,尤其是子任务需要依赖前面某个任务结果(observation)的情况,只需要将依赖步骤的observation通过prompt拼接起来送给Worker即可,可以看下面的例子。
- Worker:ReWOO通过function call的能力与环境交互,得到结果Evidence。
- Solver:通过prompt汇总所有的plan和evidence来模拟解决原始的问题,这里我们在prompt中让LLM尽可能谨慎可以提高最终的表现。
一个ReWOO的例子:
ReWOO模式的执行过程:
- Planner接受用户输入,输出详细的“计划列表”(plan,P)。Planner的prompt需要包含所有可以使用的tools,以及生成“任务列表”的格式规范。
- Worker接收到“任务列表”,按照顺序调用tool与环境交互,获得结果,文中称为证据(evidence,E)。
- Solver结合所有“计划P”和“证据E”以及用户的原始任务,生成最终响应。
2.具体实现:
prompt设定:
3.优势
-
相比较ReAct,ReWOO通过一次推理生成完整链路的tools,中可以大大减少token消耗和时间消耗。
-
简化了微调过程,在ReWOO模型中,将planner和woker解耦了,plan过程不依赖于tool的输出,因此我们可以单独微调推理模型,让plan结果更好,这样更简单、可行性更高。
-
比较擅长某个子任务依赖前面任务结果(Observation)的情况,只需要把前面的observation通过prompt拼接送到Worker即可。
参考:
Reflection模式
1.简述
反思模式,通过prompt让agent观察过去执行步骤的结果(observation)来评估选择执行动作的质量,生成评估结果和改进建议,用经验来重构prompt,循环执行持续优化结果,需要设定一个最大循环次数或者通过LLM来判断生成的结果是否正确,作为结束条件。
2.具体实现
System prompt: "You are an essay assistant tasked with writing excellent 5-paragraph essays. Generate the best essay possible for the user's request. If the user provides critique, respond with a revised version of your previous attempts.",
Reflect prompt: "You are a teacher grading an essay submission. Generate critique and recommendations for the user's submission. Provide detailed recommendations, including requests for length, depth, style, etc.",
参考: