上一章介绍的ReAct是一次的流程:提问、AI判断是否使用工具、调用、最后返回结果,但是任务如果是复杂的,并不是单一的话,就会使用到状态管理这个概念,需要记住一些状态,比如:规划一个新疆自驾游,需要考虑天气、自驾的路线、热门景点以及住宿等信息,需要进行多次判断,下面我们进入学习。
1.复杂问题步骤
1.1拆解
我们可以想一个复杂的流程问题,我们就拿上面说的问题为例:帮我规划一下去新疆北疆自驾游,大概10天左右,需要知道自驾路线、天气、景点以及每天的住宿信息。
首先第一步,我们写一个计划的函数将这个问题拆开处理
python
def plan(self, task: str) -> list:
"""规划:将任务拆解成多个步骤"""
plan_prompt = f"""
你是一个专业的自驾游规划专家。请将以下任务拆解成具体的执行步骤。
任务:{task}
具体要求:
- 任务必须包含自驾游的路线、天气、景点以及每天的住宿信息。
- 任务必须包含至少10天的自驾游时间。
- 地点:新疆北疆。
- 还可以加上推荐的当地美食、活动等。
可用工具:
- get_weather_xj(city): 查天气
- get_time(): 查当前时间
- search_attractions(city): 查景点
请输出JSON格式的步骤列表,每个步骤包含:
- step_id: 步骤编号
- tool: 使用的工具名
- params: 工具参数
- description: 步骤描述
示例输出:
[
{{"step_id": 1, "tool": "get_weather_xj", "params": {{"city": "乌鲁木齐"}}, "description": "查询乌鲁木齐天气"}},
{{"step_id": 2, "tool": "search_attractions", "params": {{"city": "可可托海"}}, "description": "查询可可托海景点"}}
]
如果不需要工具,返回:
[{{"step_id": 1, "tool": "answer", "params": {{}}, "description": "直接回答"}}]
请输出:
"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": plan_prompt}],
temperature=0.3
)
content = response.choices[0].message.content
# 提取 JSON
import re
json_match = re.search(r'\[.*\]', content, re.DOTALL)
if json_match:
try:
steps = json.loads(json_match.group())
return steps
except:
pass
# 默认返回
return [{"step_id": 1, "tool": "answer", "params": {}, "description": "直接回答"}]
这部分主要核心点就在于提示词的描述,添加了几个我们用过的工具函数:
python
def get_weather_xj(self, city: str) -> str:
"""查天气"""
weather_db = {
"乌鲁木齐": "晴天,25°C",
"可可托海": "多云,22°C",
"天山": "晴天,20°C",
"布尔津": "阵雨,24°C",
"喀纳斯": "晴天,24°C",
"阿勒泰": "晴天,21°C",
"克拉玛依": "晴天,22°C",
"赛里木湖": "晴天,24°C",
"伊宁": "晴天,22°C",
"那拉提": "阴天,15°C",
"巴音鲁克镇": "阵雨,18°C",
"奎屯市": "小雨,14°C",
}
return weather_db.get(city, f"{city}:晴天,20°C")
def get_time(self) -> str:
"""查时间"""
return datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")
def search_attractions(self, city: str) -> str:
"""查景点"""
attractions = {
"北京": ["故宫", "长城", "天坛"],
"上海": ["外滩", "东方明珠", "迪士尼"],
"广州": ["广州塔", "长隆", "沙面"],
"乌鲁木齐": ["天山天池", "国际大巴扎", "红山公园"],
"阿勒泰": ["喀纳斯湖", "禾木村", "白哈巴村"],
"布尔津": ["五彩滩", "额尔齐斯河", "布尔津夜市"],
"伊宁": ["那拉提草原", "赛里木湖", "薰衣草庄园"],
"克拉玛依": ["魔鬼城", "黑油山", "艾里克湖"]
}
return ", ".join(attractions.get(city, ["暂无推荐"]))
我们还可以添加其他的工具类,但是我们要明白天家工具类的作用,就是有些实时信息没法查到,理论上我们要去请求一个比如时间的API然后得到结果数据,所以这个工具类的添加根据自己的具体情况,比如我们还可以加住宿的工具,关于是否需要添加,AI是如下回答的,总结下面回答就是:提供了工具的调用,可以提高AI回答的准确性和效率


1.2 拆开执行
我们第一步拆开了许多任务,第二步就是去执行,拿到结果,主要是循环plan函数返回的数据,包括到哪一步了,描述,用的工具等信息,然后该用工具的用设置好的工具,不用的直接回答,就比如饮食,路线等
python
print("\n🔧 步骤2: 执行步骤...")
for step in steps:
step_id = step.get("step_id")
description = step.get("description", "")
tool = step.get("tool", "")
print(f"\n 📍 执行步骤 {step_id}: {description}")
print(f" 工具: {tool}")
# 执行
result = self.execute_step(step)
if result:
print(f" 结果: {result[:100]}...")
# 保存中间结果
self.state["intermediate_results"][f"step_{step_id}"] = result
self.state["completed_steps"].append({
"step_id": step_id,
"description": description,
"result": result
})
else:
print(f" 无需工具,直接回答")
1.3 总结输出
python
print("\n💭 步骤3: 思考总结...")
conclusion = self.think_next(
task,
self.state["completed_steps"],
self.state["intermediate_results"]
)
if conclusion.get("is_complete"):
final_answer = conclusion.get("final_answer", "任务完成")
else:
# 如果未完成,让 AI 基于中间结果生成回答
final_answer = self.generate_final_answer(task, self.state["intermediate_results"])
self.state["final_answer"] = final_answer
return final_answer
def generate_final_answer(self, task: str, results: dict) -> str:
"""基于中间结果生成最终回答"""
prompt = f"""
原始任务:{task}
收集到的信息:
{json.dumps(results, ensure_ascii=False, indent=2)}
请根据以上信息,给出一个完整、友好的回答。
"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
中间思考过程看回答有没有完成,是否要进行下一步,直接看提示词就好,先判断是否完成,数据来源于上一步请求提问以及调用工具的结果:
python
def think_next(self, task: str, completed_steps: list, results: dict) -> dict:
"""思考下一步:判断是否需要继续"""
think_prompt = f"""
原始任务:{task}
已完成的步骤:
{json.dumps(completed_steps, ensure_ascii=False, indent=2)}
中间结果:
{json.dumps(results, ensure_ascii=False, indent=2)}
请判断:
1. 任务是否已经完成?
2. 如果完成,给出最终答案
3. 如果未完成,说明还需要什么
输出JSON格式:
{{"is_complete": true/false, "final_answer": "最终答案(如果完成)", "next_action": "下一步说明(如果未完成)"}}
"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": think_prompt}],
temperature=0.1
)
content = response.choices[0].message.content
# 提取 JSON
import re
json_match = re.search(r'\{.*\}', content, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group())
except:
pass
return {"is_complete": True, "final_answer": "处理完成", "next_action": ""}
2.运行结果




整个计划其实是不错的,因为我去过一次新疆自驾,走的路线时间和设计的差不多,很棒的计划。
3.代码
python
from openai import OpenAI
import os
import json
from datetime import datetime
from dotenv import load_dotenv
load_dotenv()
class StatefulAgent:
"""带状态管理的 Agent - 支持多步推理"""
def __init__(self):
self.client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com"
)
# 状态管理
self.reset()
def reset(self):
"""重置 Agent 状态(开始新任务时调用)"""
self.state = {
"task": None, # 当前任务
"step": 0, # 当前步骤数
"completed_steps": [], # 已完成的步骤
"pending_steps": [], # 待完成的步骤
"intermediate_results": {}, # 中间结果
"final_answer": None, # 最终答案
"max_steps": 10 # 最大步数限制
}
# ========== 工具定义 ==========
def get_weather(self, city: str) -> str:
"""查天气"""
weather_db = {
"北京": "晴天,25°C",
"上海": "多云,22°C",
"广州": "阵雨,28°C",
}
return weather_db.get(city, f"{city}:晴天,20°C")
def get_weather_xj(self, city: str) -> str:
"""查天气"""
weather_db = {
"乌鲁木齐": "晴天,25°C",
"可可托海": "多云,22°C",
"天山": "晴天,20°C",
"布尔津": "阵雨,24°C",
"喀纳斯": "晴天,24°C",
"阿勒泰": "晴天,21°C",
"克拉玛依": "晴天,22°C",
"赛里木湖": "晴天,24°C",
"伊宁": "晴天,22°C",
"那拉提": "阴天,15°C",
"巴音鲁克镇": "阵雨,18°C",
"奎屯市": "小雨,14°C",
}
return weather_db.get(city, f"{city}:晴天,20°C")
def get_time(self) -> str:
"""查时间"""
return datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")
def search_attractions(self, city: str) -> str:
"""查景点"""
attractions = {
"乌鲁木齐": ["天山天池", "国际大巴扎", "红山公园"],
"阿勒泰": ["喀纳斯湖", "禾木村", "白哈巴村"],
"布尔津": ["五彩滩", "额尔齐斯河", "布尔津夜市"],
"伊宁": ["那拉提草原", "赛里木湖", "薰衣草庄园"],
"克拉玛依": ["魔鬼城", "黑油山", "艾里克湖"]
}
return ", ".join(attractions.get(city, ["暂无推荐"]))
# ========== 核心方法 ==========
def plan(self, task: str) -> list:
"""规划:将任务拆解成多个步骤"""
plan_prompt = f"""
你是一个专业的自驾游规划专家。请将以下任务拆解成具体的执行步骤。
任务:{task}
具体要求:
- 任务必须包含自驾游的路线、天气、景点以及每天的住宿信息。
- 任务必须包含至少10天的自驾游时间。
- 地点:新疆北疆。
- 还可以加上推荐的当地美食、活动等。
可用工具:
- get_weather_xj(city): 查天气
- get_time(): 查当前时间
- search_attractions(city): 查景点
请输出JSON格式的步骤列表,每个步骤包含:
- step_id: 步骤编号
- tool: 使用的工具名
- params: 工具参数
- description: 步骤描述
示例输出:
[
{{"step_id": 1, "tool": "get_weather_xj", "params": {{"city": "乌鲁木齐"}}, "description": "查询乌鲁木齐天气"}},
{{"step_id": 2, "tool": "search_attractions", "params": {{"city": "可可托海"}}, "description": "查询可可托海景点"}}
]
如果不需要工具,返回:
[{{"step_id": 1, "tool": "answer", "params": {{}}, "description": "直接回答"}}]
请输出:
"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": plan_prompt}],
temperature=0.3
)
content = response.choices[0].message.content
# 提取 JSON
import re
json_match = re.search(r'\[.*\]', content, re.DOTALL)
if json_match:
try:
steps = json.loads(json_match.group())
return steps
except:
pass
# 默认返回
return [{"step_id": 1, "tool": "answer", "params": {}, "description": "直接回答"}]
def execute_step(self, step: dict) -> str:
"""执行单个步骤"""
tool = step.get("tool", "answer")
params = step.get("params", {})
if tool == "get_weather_xj":
city = params.get("city", "")
return self.get_weather_xj(city)
elif tool == "get_time":
return self.get_time()
elif tool == "search_attractions":
city = params.get("city", "")
return self.search_attractions(city)
elif tool == "answer":
# 直接回答,不需要工具
return None
else:
return f"未知工具: {tool}"
def think_next(self, task: str, completed_steps: list, results: dict) -> dict:
"""思考下一步:判断是否需要继续"""
think_prompt = f"""
原始任务:{task}
已完成的步骤:
{json.dumps(completed_steps, ensure_ascii=False, indent=2)}
中间结果:
{json.dumps(results, ensure_ascii=False, indent=2)}
请判断:
1. 任务是否已经完成?
2. 如果完成,给出最终答案
3. 如果未完成,说明还需要什么
输出JSON格式:
{{"is_complete": true/false, "final_answer": "最终答案(如果完成)", "next_action": "下一步说明(如果未完成)"}}
"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": think_prompt}],
temperature=0.1
)
content = response.choices[0].message.content
# 提取 JSON
import re
json_match = re.search(r'\{.*\}', content, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group())
except:
pass
return {"is_complete": True, "final_answer": "处理完成", "next_action": ""}
def run(self, task: str) -> str:
"""主入口:执行多步任务"""
print(f"\n{'='*60}")
print(f"📋 新任务: {task}")
print(f"{'='*60}")
# 1. 重置状态
self.reset()
self.state["task"] = task
# 2. 规划步骤
print("\n📝 步骤1: 规划任务...")
steps = self.plan(task)
print(f" 规划出 {len(steps)} 个步骤:")
for s in steps:
print(f" - 步骤{s.get('step_id')}: {s.get('description')}")
self.state["pending_steps"] = steps.copy()
# 3. 执行步骤(循环)
print("\n🔧 步骤2: 执行步骤...")
for step in steps:
step_id = step.get("step_id")
description = step.get("description", "")
tool = step.get("tool", "")
print(f"\n 📍 执行步骤 {step_id}: {description}")
print(f" 工具: {tool}")
# 执行
result = self.execute_step(step)
if result:
print(f" 结果: {result[:100]}...")
# 保存中间结果
self.state["intermediate_results"][f"step_{step_id}"] = result
self.state["completed_steps"].append({
"step_id": step_id,
"description": description,
"result": result
})
else:
print(f" 无需工具,直接回答")
# 4. 思考总结
print("\n💭 步骤3: 思考总结...")
conclusion = self.think_next(
task,
self.state["completed_steps"],
self.state["intermediate_results"]
)
if conclusion.get("is_complete"):
final_answer = conclusion.get("final_answer", "任务完成")
else:
# 如果未完成,让 AI 基于中间结果生成回答
final_answer = self.generate_final_answer(task, self.state["intermediate_results"])
self.state["final_answer"] = final_answer
return final_answer
def generate_final_answer(self, task: str, results: dict) -> str:
"""基于中间结果生成最终回答"""
prompt = f"""
原始任务:{task}
收集到的信息:
{json.dumps(results, ensure_ascii=False, indent=2)}
请根据以上信息,给出一个完整、友好的回答。
"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}],
temperature=0.5
)
return response.choices[0].message.content
# ========== 测试 ==========
if __name__ == "__main__":
agent = StatefulAgent()
# 测试用例
tests = [
"帮我规划一下去新疆北疆自驾游,大概10天左右,需要知道自驾路线、天气、景点以及每天的住宿信息。"
]
for test in tests:
result = agent.run(test)
print(f"\n{'='*60}")
print(f"✅ 最终回答: {result}")
print(f"{'='*60}\n")
4.总结
| 概念 | 理解 |
|---|---|
| 状态管理 | Agent 需要记住做了什么、还需要做什么 |
| 任务规划 | 复杂任务拆解成多个小步骤 |
| 循环执行 | 按步骤执行,保存中间结果 |
| 最终整合 | 用中间结果生成完整回答 |
这种设计使得 Agent 能够清晰地跟踪执行过程,为后续的思考和决策提供完整的上下文信息,是 ReAct 模式的重要组成部分,这个是有区别于一次回答的,关键写好提示词,返回好数据,然后根据回答调用工具函数,记录下结果以及当前到哪一步了,再次进行思考,进行下一步,最后总结,差不多就这样了。