0%

agentscope 源码分析(7):ReActAgent 核心

这篇文章我们将开始学习 AgentScope 最核心的功能,即 ReActAgent,它为开发者提供了开箱即用的、ReAct 架构的(Reasoning + Acting)模式的智能体。

什么是 ReAct?

ReAct (Reasoning + Acting) 是一种 Agent 架构模式,由 Yao 等人在 2022 年提出。其核心思想是将 Agent 的行为分解为两个交替进行的阶段:

  • Reasoning(推理):LLM 思考下一步该做什么
  • Acting(行动):执行具体操作(如调用工具)
1
2
3
4
5
6
7
8
9
10
11
┌─────────────────────────────────────────────────────────┐
│ ReAct Loop │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Reasoning │───►│ Acting │───► │ Observe │ │
│ │ (思考) │ │ (执行) │ │ (观察) │ |
│ └──────────┘ └──────────┘ └──────────┘ │
│ ▲ │ │
│ └──────────────────────────────────┘ │
│ (循环直到完成) │
└─────────────────────────────────────────────────────────┘

AgentScope 的 ReActAgent 除了实现 Reasoning-Acting 循环之外,还实现了知识库集成、记忆压缩、任务规划等功能,是一个可在生产环境中直接使用的智能体。

整体结构

ReActAgent 的实现主要位于文件 _react_agent_base.py_react_agent.py 中,类的继承关系如下:

1
2
3
4
5
6
7
8
9
10
StateModule


AgentBase (metaclass=_AgentMeta)


ReActAgentBase (metaclass=_ReActAgentMeta)


ReActAgent

ReActAgent 除了实现本身的 推理-行动 之外,还包括了智能体所需要的 LLM 调用、工具调用、记忆机制、知识库、任务规划等等,因此 ReActAgent 依赖于我们之前所介绍的各种组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌─────────────────────────────────────────────────────────────────────┐
│ ReActAgent │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Core Components │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ │
│ │ │ Model │ │ Toolkit │ │ Memory │ │ Formatter │ │ │
│ │ │ (LLM) │ │ (Tools) │ │ (History)│ │ (API Format) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Extended Features │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────────┐ │ │
│ │ │LongTermMemory│ │ Knowledge │ │ PlanNotebook │ │ │
│ │ │ (持久记忆) │ │ (RAG) │ │ (任务规划) │ │ │
│ │ └──────────────┘ └──────────────┘ └─────────────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌──────────────────────────────────┐ │ │
│ │ │CompressionConfig │ │ TTSModel │ │ │
│ │ │ (记忆压缩) │ │ (语音合成) │ │ |
│ │ └──────────────────┘ └──────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

ReActAgentBase

ReActAgent 的基类是 ReActAgentBase,其定义如下:

1
class ReActAgentBase(AgentBase, metaclass=_ReActAgentMeta):
  • ReActAgentBase 继承自 AgentBase,关于 AgentBase 的功能和实现,已经在上一篇文章详细介绍
  • ReActAgentBase 的元类是 _ReActAgentMeta,而 _ReActAgentMeta 继承自 _AgentMeta_ReActAgentMeta_AgentMeta 的原有钩子(replyprintobserve)的基础上,继续支持了对 _reasoning_acting 两个方法支持 hook 函数的执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class _ReActAgentMeta(_AgentMeta):
"""The ReAct metaclass that adds pre- and post-hooks for the _reasoning
and _acting functions."""

def __new__(mcs, name: Any, bases: Any, attrs: Dict) -> Any:
# 对 _reasoning 和 _acting 函数,添加 hook 逻辑
for func_name in [
"_reasoning",
"_acting",
]:
if func_name in attrs:
attrs[func_name] = _wrap_with_hooks(attrs[func_name])

return super().__new__(mcs, name, bases, attrs)

ReActAgentBase 的核心就是定义了 _reasoning_acting 两个抽象方法,以及对这两个抽象方法支持 hooks 机制,包括类级别、实例级别的 pre/post hooks 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ReActAgentBase(AgentBase, metaclass=_ReActAgentMeta):
_class_pre_reasoning_hooks = OrderedDict()
_class_post_reasoning_hooks = OrderedDict()
_class_pre_acting_hooks = OrderedDict()
_class_post_acting_hooks = OrderedDict()

def __init__(
self,
) -> None:
"""Initialize the ReAct agent base class."""
super().__init__()

# Init reasoning and acting hooks
self._instance_pre_reasoning_hooks = OrderedDict()
self._instance_post_reasoning_hooks = OrderedDict()
self._instance_pre_acting_hooks = OrderedDict()
self._instance_post_acting_hooks = OrderedDict()

@abstractmethod
async def _reasoning(
self,
*args: Any,
**kwargs: Any,
) -> Any:
"""The reasoning process of the ReAct agent, which will be wrapped
with pre- and post-hooks."""

@abstractmethod
async def _acting(self, *args: Any, **kwargs: Any) -> Any:
"""The acting process of the ReAct agent, which will be wrapped with
pre- and post-hooks."""

ReActAgent

接下来分析 ReActAgent 类的实现,首先分析其初始化函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class ReActAgent(ReActAgentBase):
def __init__(
self,
name: str,
sys_prompt: str,
model: ChatModelBase,
formatter: FormatterBase,
toolkit: Toolkit | None = None,
memory: MemoryBase | None = None,
long_term_memory: LongTermMemoryBase | None = None,
long_term_memory_mode: Literal[
"agent_control",
"static_control",
"both",
] = "both",
enable_meta_tool: bool = False,
parallel_tool_calls: bool = False,
knowledge: KnowledgeBase | list[KnowledgeBase] | None = None,
enable_rewrite_query: bool = True,
plan_notebook: PlanNotebook | None = None,
print_hint_msg: bool = False,
max_iters: int = 10,
tts_model: TTSModelBase | None = None,
compression_config: CompressionConfig | None = None,
) -> None:
  • name 为 Agent 的名称,sys_prompt 表示系统提示词
  • model: ChatModelBase:所使用的 LLM 模型
  • formatter: FormatterBase:所使用的 formatter
  • toolkit: Toolkit:工具集合
  • memory: MemoryBase:短期记忆
  • long_term_memory: LongTermMemoryBase:所使用的长期记忆
  • long_term_memory_mode:长期记忆的添加方式
  • enable_meta_tool:是否动态加载工具,参见 agentscope 源码分析(1):Toolkit 类实现
  • parallel_tool_calls:是否允许并行工具调用
  • knowledge:所使用的知识库
  • enable_rewrite_query:是否允许改写输入,如果开启的话(默认),允许根据 RAG 知识库中的相关文档,改写用户输入
  • plan_notebook: PlanNotebook:计划管理
  • print_hint_msg:是否输出 hint 消息
  • max_iters:最大迭代次数
  • tts_model TTSModelBase:所使用的 tts 模型
  • compression_config CompressionConfig:压缩配置

因为 ReActAgent 使用组合的方式来使用 ToolkitPlanNotebook 等各个基础组件,因此在 __init__ 函数中,其主要工作就是将这些参数赋值给 ReActAgent 的属性,另外就是根据一些控制属性,完成 Toolkit 中相关工具的初始化:

  • 如果长期记忆是由 Agent 自己控制,注册 long_term_memory.record_to_memorylong_term_memory.retrieve_from_memory 工具
  • 如果开启了 enable_meta_tool,则注册 reset_equipped_tools 工具
  • 如果提供了 plan_notebook,则添加 PlanNotebook 所提供的工具

由于 ReActAgent 最终也会继承 StateModule,因此可以完整状态的管理,手动注册了如下状态属性,其他继承自 StateModule 的状态属性会自动进行状态跟踪,无需手动注册,参见 agentscope 源码分析(6):Agent 的元类与基类

1
2
self.register_state("name")
self.register_state("_sys_prompt")

Reply 实现

上篇文章介绍 AgentBase 类时说过,所有具体的 Agent 实现类都需要实现 reply 方法,这个方法是智能体的核心方法,用于处理输入消息并产生回复,而 智能 的魔法就是在 reply() 方法中实现的。我们先从整体上梳理下 reply() 方法的核心逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌─────────────────────────────────────────────────────────────────┐
│ reply(msg) │
├─────────────────────────────────────────────────────────────────┤
│ 1. memory.add(msg) # 记录输入消息 │
│ 2. _retrieve_from_long_term_memory() # 长期记忆检索 │
│ 3. _retrieve_from_knowledge() # RAG 知识检索 │
├─────────────────────────────────────────────────────────────────┤
│ ▼ ReAct 循环 (max_iters) ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 4. _compress_memory_if_needed() # 内存压缩 │ │
│ │ 5. _reasoning() # 推理阶段 │ │
│ │ 6. _acting() for each tool_call # 行动阶段 │ │
│ │ 7. 检查终止条件 │ │
│ │ - 有结构化输出 → 生成文本响应 │ │
│ │ - 无工具调用 → 返回文本消息 │ │
│ │ - 否则 → 继续循环 │ │
│ └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ 8. 如果达到 max_iters → _summarizing() # 生成总结响应 │
│ 9. long_term_memory.record() # 记录到长期记忆 │
│ 10. return reply_msg │
└─────────────────────────────────────────────────────────────────┘

而下面则是简化版的 reply() 方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
```python
@trace_reply
async def reply(self, msg: Msg, structured_model: Type[BaseModel] = None) -> Msg:
# 1. 在记忆中记录输入
await self.memory.add(msg)

# 2. 检索增强
await self._retrieve_from_long_term_memory(msg)
await self._retrieve_from_knowledge(msg)

# 3. 结构化输出设置
if structured_model:
self.toolkit.register_tool_function(self.generate_response)
tool_choice = "required"

# 4. ReAct 循环
for _ in range(self.max_iters):
# 4.1 记忆压缩(如需要)
await self._compress_memory_if_needed()

# 4.2 推理
msg_reasoning = await self._reasoning(tool_choice)

# 4.3 行动
futures = [self._acting(tc) for tc in msg_reasoning.get_content_blocks("tool_use")]
structured_outputs = await asyncio.gather(*futures)

# 4.4 检查退出条件
if structured_outputs:
# 结构化输出完成
break
elif not msg_reasoning.has_content_blocks("tool_use"):
# 无工具调用,返回文本
break

# 达到最大迭代次数,仍然没有应答消息
if reply_msg is None:
# 将当前内容进行汇总,并返回这个汇总消息
reply_msg = await self._summarizing()
reply_msg.metadata = structured_output
await self.memory.add(reply_msg)

# 5. 记录到长期记忆
if self._static_control:
await self.long_term_memory.record(...)

return reply_msg
  • 首先将当前的消息添加到智能体的 记忆,这个记忆有时候也被称为 短期记忆。因为大模型的上下文窗口是有限的,短期记忆 是算法/系统侧面的管理策略,用来决定哪些内容留在上下文窗口里、什么时候对短期记忆里的内容进行压缩/总结。关于 ReActAgent 的 短期记忆 实现与管理,后续文章再详细分析。总而言之,可以认为,短期记忆是指智能体在当前任务或当前会话中实时处理和保留信息的能力,或者更简单认为,短期记忆就是管理当前任务会话的 LLM 上下文窗口

  • 根据当前 Msg,分别从 长期记忆知识库 中检索相关的信息,这些检索出来的信息都会以 Msg 的形式添加到 短期记忆 中,为后续的模型推理提供更多有用的信息

  • 如果希望从 Agent 获得结构化输出,则会将 self.finish_function_name 所对应的方法注册为一个工具,并将工具的输出模型设置为用户所要求的 structured_model

1
2
3
4
5
6
7
8
9
10
11
self.toolkit.register_tool_function(
getattr(self, self.finish_function_name),
)

self.toolkit.set_extended_model(
self.finish_function_name,
structured_model,
)

# 必须使用 tool choice
tool_choice = "required"
  • 默认的 finish_function_namegenerate_response,它的核心逻辑就是将模型传递的输入进行验证,判断是否符合 structured_model 的要求,如果符合则返回成功,并在 ToolResponse 的 metadata 中包含这个结构化数据,否则返回失败,Agent 的循环会继续执行,直到 LLM 返回符合要求的结构化的数据为止
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def generate_response(self, **kwargs: Any,) -> ToolResponse:
structured_output = None
# Prepare structured output
if self._required_structured_model:
try:
structured_output = (
self._required_structured_model.model_validate(
kwargs,
).model_dump()
)

except ValidationError as e:
return ToolResponse(
content=[
TextBlock(
type="text",
text=f"Arguments Validation Error: {e}",
),
],
metadata={
"success": False,
"structured_output": {},
},
)
else:
logger.warning(
"The generate_response function is called when no structured "
"output model is required.",
)

# 成功了,表示返回生成最终的响应
return ToolResponse(
content=[
TextBlock(
type="text",
text="Successfully generated response.",
),
],
# 包含 metadata
metadata={
"success": True,
"structured_output": structured_output,
},
is_last=True,
)
  • 完成上述步骤之后,则进行 ReAct 循环了,每次 ReAct 循环开始,都判断是否需要对当前的上下文进行压缩。之后调用 self._reasoning() 进行一次推理,然后获取推理结果中的所有 tool_use,对每个 tool_use 调用 self._acting() 进行行动
  • 每一轮循环结束后,都要判断是否可以退出 ReAct 循环了,以下详细分析各种情况下 ReAct 循环是继续还是终止:
    • 如果需要需要结构化输出 (structured_model 已指定)

      • 成功生成结构化输出 + 有文本回复 → 直接退出
      • 成功生成结构化输出 + 无文本回复,此时添加提示,要求模型继续生成回复文本→ 继续一轮后退出
      • 无结构化输出 + 无工具调用,要求使用 generate_response 工具来获得结构化输出 → 继续循环,强制工具
      • 无结构化输出 + 有工具调用(普通的工具调用) → 继续循环(正常工作流)
    • 如果不需要结构化输出

      • 无工具调用,直接返回响应文本→ 直接退出
      • 有工具调用,正常执行工具 → 继续循环
    • 产生的结构化输出总是会保存到到 reply_msg 的 metadata 中,Agent 应用可以通过这个字段获取结构化输出

1
2
3
4
5
6
reply_msg = Msg(
self.name,
msg_reasoning.get_content_blocks("text"),
"assistant",
metadata=structured_output,
)
  • 从这个终止流程可以看出,无论是否用户要求结构化输出,ReAct 循环最终都需要给出一段回复文本,防止 Agent 默默完成任务后不给用户任何反馈。
  • 如果超过最大迭代次数,仍然有效的应答消息,则把当前过程进行总结,并返回这个汇总消息
  • 最后,将整个会话过程记录到长期记忆中

推理过程 (_reasoning)

以上我们分析了 ReActAgent 的 reply() 实现,接下来我们分析其中的一个关键步骤,即推理函数 _reasoning() 的实现,以下是其核心逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
async def _reasoning(self, tool_choice) -> Msg:
# 1. 注入计划提示
if self.plan_notebook:
hint_msg = await self.plan_notebook.get_current_hint()
await self.memory.add(hint_msg, marks=_MemoryMark.HINT)

# 2. 格式化 prompt
prompt = await self.formatter.format([
Msg("system", self.sys_prompt, "system"),
*await self.memory.get_memory(exclude_mark=_MemoryMark.COMPRESSED),
])

# 3. 清理 hint 消息
await self.memory.delete_by_mark(mark=_MemoryMark.HINT)

# 4. 调用模型
res = await self.model(
prompt,
tools=self.toolkit.get_json_schemas(),
tool_choice=tool_choice,
)

# 5. 处理流式输出
msg = Msg(name=self.name, content=[], role="assistant")
if self.model.stream:
async for chunk in res:
msg.content = chunk.content
await self.print(msg, False)

# 6. 记录到记忆
await self.memory.add(msg)

return msg
  • 可以看到,其核心逻辑是根据当前的 短期记忆 来生成 prompt,然后调用模型进行推理
  • 这里我们也可以,在 memory 中 _MemoryMark.HINT 标记的 Msg,只用于为当前推理步骤来生成提示词,可以认为是标记一次性的提示消息,当前推理完成之后,就会将 HINT 标记的 Msg 从短期记忆中删除。因为这种类型的信息只是为了推动当前步骤的完成,它本身提供的信息对整个任务来说是没有帮助的,因此可以直接删除
  • 推理完成后,会将得到的结果添加到 短期记忆

以上流程只是 _reasoning() 的核心逻辑,其还会处理音频模型、用户中断(需要保证已经产生的 ToolUse 有对应的 ToolResult)等逻辑,这里就不再展开了。

行动过程 (_acting)

接下来再来看其行动过程 _acting() 的实现,以下是其核心逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
async def _acting(self, tool_call: ToolUseBlock) -> dict | None:
tool_res_msg = Msg("system", [ToolResultBlock(...)], "system")

try:
# 1. 执行工具
tool_res = await self.toolkit.call_tool_function(tool_call)

# 2. 处理流式结果
async for chunk in tool_res:
tool_res_msg.content[0]["output"] = chunk.content
await self.print(tool_res_msg, chunk.is_last)

# 3. 检查是否为终结工具
if (
tool_call["name"] == self.finish_function_name
and chunk.metadata.get("success")
):
return chunk.metadata.get("structured_output")

return None

finally:
# 4. 记录结果
await self.memory.add(tool_res_msg)
  • _acting() 的核心就是执行工具调用
  • 如果调用的是 finish_function_name 工具,则会从其 metadata 中判断产生的结果是否符合用户要求的 structured_model,如果符合则直接返回这个结构化数据。这块逻辑与 generate_response(默认的 finish_function_name 相匹配)。如果是其他工具调用或者产生的结果不符合要求,则返回 None
  • _acting() 的返回值逻辑其实对 reply() 中判断是否已经获取结构化输出是很重要的

结构化输出

以上我们就分析了整个 ReActAgent reply() 的核心实现原理,其中比较复杂的部分就是对 结构化输出 的处理,以下列出了 结构化输出 的工作原理,帮助理解。这个过程在上面的代码分析中也有详细的解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
用户请求结构化输出


┌───────────────────────────┐
│ 注册 generate_response 工具 │
│ 设置 tool_choice="required"
└───────────────────────────┘


LLM 推理


┌───────────────────────────┐
│ LLM 调用 generate_response │
│ 传入符合 schema 的参数 │
└───────────────────────────┘


┌───────────────────────────┐
│ Pydantic 验证参数 │
│ - 成功 → success=True │
│ - 失败 → success=False │
└───────────────────────────┘


┌───────────────────────────┐
│ _acting 检测到 finish_func │
│ 返回 structured_output │
└───────────────────────────┘


循环退出,返回结果

ReActAgent 实例

接下来通过一个实际例子来展示 ReActAgent 的使用,并通过其实际运行中所产生的消息记录,帮助理解其工作原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# -*- coding: utf-8 -*-
"""
ReActAgent 结构化输出 Demo - 基于 OpenAI 模型 (gpt-5.1)

运行方式:
export OPENAI_API_KEY='your-api-key'
python ai_demo/demo3_structured_output.py
"""

import asyncio
import json
import os
from typing import Literal

from pydantic import BaseModel, Field

from agentscope.agent import ReActAgent
from agentscope.formatter import OpenAIChatFormatter
from agentscope.memory import InMemoryMemory
from agentscope.message import Msg, TextBlock
from agentscope.model import OpenAIChatModel
from agentscope.tool import Toolkit, ToolResponse


class WeatherReport(BaseModel):
"""天气报告结构化输出模型"""

city: str = Field(description="城市名称")
temperature: int = Field(description="温度(摄氏度)", ge=-50, le=60)
weather_condition: Literal["晴天", "多云", "阴天", "小雨", "大雨", "暴雨", "雪"] = (
Field(description="天气状况")
)
humidity: int = Field(description="湿度百分比", ge=0, le=100)
recommendation: str = Field(description="出行建议")


def get_weather(city: str) -> ToolResponse:
"""获取指定城市的天气信息(模拟工具)"""
mock_weather_data = {
"北京": {"temp": 25, "condition": "晴天", "humidity": 45},
"上海": {"temp": 28, "condition": "多云", "humidity": 60},
"广州": {"temp": 32, "condition": "小雨", "humidity": 85},
"深圳": {"temp": 30, "condition": "多云", "humidity": 70},
"成都": {"temp": 22, "condition": "阴天", "humidity": 55},
}
data = mock_weather_data.get(
city, {"temp": 20, "condition": "晴天", "humidity": 50}
)
return ToolResponse(
content=[
TextBlock(
type="text",
text=f"{city}天气:温度 {data['temp']}°C,{data['condition']},湿度 {data['humidity']}%",
)
],
is_last=True,
)


async def main() -> None:
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
print("请设置环境变量: export OPENAI_API_KEY='your-api-key'")
return

toolkit = Toolkit()
toolkit.register_tool_function(get_weather)

agent = ReActAgent(
name="WeatherAgent",
sys_prompt=(
"你是一个天气分析助手。"
"当用户提供城市信息时,你需要:"
"1. 调用 get_weather 工具获取天气数据"
"2. 分析数据并给出精简的出行建议"
"3. 使用 generate_response 返回结构化报告"
),
model=OpenAIChatModel(model_name="gpt-5.1", api_key=api_key, stream=True),
formatter=OpenAIChatFormatter(),
toolkit=toolkit,
memory=InMemoryMemory(),
max_iters=5,
)

msg = Msg("user", "请分析上海今天的天气情况", "user")
response = await agent(msg, structured_model=WeatherReport)

print(f"\n文本回复: {response.get_text_content()}")
# response.metadata 包含了结构化数据
print(
f"\n结构化数据:\n{json.dumps(response.metadata, indent=2, ensure_ascii=False)}"
)


if __name__ == "__main__":
asyncio.run(main())

实际运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 消息记录部分

# Agent 产生工具调用请求,以获取当前天气
WeatherAgent: {
"type": "tool_use",
"id": "call_bHslPJpcVFqXO5OViNcagtmg",
"name": "get_weather",
"input": {
"city": "上海"
},
"raw_input": "{\"city\":\"上海\"}"
}

# 系统返回工具调用结果
system: {
"type": "tool_result",
"id": "call_bHslPJpcVFqXO5OViNcagtmg",
"name": "get_weather",
"output": [
{
"type": "text",
"text": "上海天气:温度 28°C,多云,湿度 60%"
}
]
}

# Agent 产生 `generate_response` 工具调用请求,以生成结构化响应
WeatherAgent: {
"type": "tool_use",
"id": "call_lj2D6muF2KXyipucKKiHhQJX",
"name": "generate_response",
"input": {
"city": "上海",
"humidity": 60,
"recommendation": "上海今日多云,气温28°C,体感较为舒适但略偏闷热,建议穿短袖或薄长袖,户外活动注意适当补水 。如果晚间外出,可备一件薄外套以防风。空气湿度中等,适宜开窗通风,但如对温差较敏感,可避免长时间吹空调直风。",
"temperature": 28,
"weather_condition": "多云"
},
"raw_input": "{\"city\":\"上海\",\"humidity\":60,\"recommendation\":\"上海今日多云,气温28°C,体感较为舒适但略偏闷热,建议穿短袖或薄长袖,户外活动注意适当补水。如果晚间外出,可备一件薄外套以防风。空气湿度中等,适宜开窗通风,但如对温差较敏感,可避免长时间吹空调直风。\",\"temperature\":28,\"weather_condition\":\"多云\"}"
}

# 系统返回工具调用结果,验证模型产生的结构化输出符合要求
system: {
"type": "tool_result",
"id": "call_lj2D6muF2KXyipucKKiHhQJX",
"name": "generate_response",
"output": [
{
"type": "text",
"text": "Successfully generated response."
}
]
}

# Agent 产生最终的文本答复
WeatherAgent: 上海今天:多云,约28°C,湿度60%左右,整体偏暖、略闷但比较舒适。

出行简要建议:
- 穿着:短袖或薄长袖即可,怕热可以选择透气面料;室内空调环境建议随身带一件薄外套。
- 出门活动:适合户外活动,注意多喝水、防止闷热导致不适。
- 通风与空调:湿度中等,可以适当开窗通风;如果开空调,避免直吹,注意温差别太大,以免着凉。

# 结果打印部分
# 文本答复部分
文本回复: 上海今天:多云,约28°C,湿度60%左右,整体偏暖、略闷但比较舒适。

出行简要建议:
- 穿着:短袖或薄长袖即可,怕热可以选择透气面料;室内空调环境建议随身带一件薄外套。
- 出门活动:适合户外活动,注意多喝水、防止闷热导致不适。
- 通风与空调:湿度中等,可以适当开窗通风;如果开空调,避免直吹,注意温差别太大,以免着凉。

# 结构化输出部分
结构化数据:
{
"city": "上海",
"temperature": 28,
"weather_condition": "多云",
"humidity": 60,
"recommendation": "上海今日多云,气温28°C,体感较为舒适但略偏闷热,建议穿短袖或薄长袖,户外活动注意适当补水。如果 晚间外出,可备一件薄外套以防风。空气湿度中等,适宜开窗通风,但如对温差较敏感,可避免长时间吹空调直风。"
}

若能理解上述示例的运行结果,便说明已正确掌握 ReActAgent 智能体的运行原理。

小结

推理-行动 这种 Agent 架构模式是当前非常主流的一种智能体架构,这篇文章我们详细分析了 ReActAgent 的实现原理,包括其 Reply() 方法的核心逻辑,以及其中的 _reasoning()_acting() 方法是如何实现的,最后通过一个实际例子演示了 ReActAgent 的使用方法。