This is an automated email from the ASF dual-hosted git repository.

wenjin272 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new bde1069a [docs] Improve Built-in ReAct Agent usage documentation 
(#1259)
bde1069a is described below

commit bde1069ae10fcadab497ddd633a89ae090ce9e8f
Author: Yi Zhang <[email protected]>
AuthorDate: Fri Oct 16 16:42:57 2026 +0800

    [docs] Improve Built-in ReAct Agent usage documentation (#1259)
    
    Generated-by: Qoder
---
 docs/content/docs/development/react_agent.md | 233 ++++++++++++++-------------
 1 file changed, 117 insertions(+), 116 deletions(-)

diff --git a/docs/content/docs/development/react_agent.md 
b/docs/content/docs/development/react_agent.md
index 19dc49bc..6c374015 100644
--- a/docs/content/docs/development/react_agent.md
+++ b/docs/content/docs/development/react_agent.md
@@ -26,148 +26,119 @@ under the License.
 
 Flink Agents provides `ReActAgent` as a built-in subclass of `Agent` that 
implements the ReAct pattern.
 
-ReAct Agent is a general paradigm that combines reasoning and action 
capabilities to solve complex tasks. Leveraging this paradigm, the user only 
needs to specify the goal with prompt and provide available tools, and the LLM 
will decide how to achieve the goal and take actions autonomously.
+ReAct Agent is a general paradigm that combines reasoning and action 
capabilities to solve complex tasks. A `ReActAgent` requires a chat model. You 
can optionally provide a prompt, an output schema, tools, and skills; the model 
then decides how to achieve the goal and when to use the capabilities you 
expose.
 
 {{< hint info >}}
 The snippets on this page are fragments that each focus on a single concept. 
For an end-to-end runnable walkthrough, see the [Use the Built-in ReAct 
Agent]({{< ref "docs/get-started/quickstart/react_agent" >}}) and the full 
source: 
[`react_agent_example.py`](https://github.com/apache/flink-agents/blob/main/python/flink_agents/examples/quickstart/react_agent_example.py)
 (Python) and 
[`ReActAgentExample.java`](https://github.com/apache/flink-agents/blob/main/examples/src/main/java/org/apac
 [...]
 {{< /hint >}}
 
-The snippets below assume the following imports:
+## Create a ReAct Agent
 
-{{< tabs "ReAct Agent Imports" >}}
+The only required argument of a ReAct Agent is a chat model descriptor, which 
references a registered chat model connection by name. See [Chat Models]({{< 
ref "docs/development/calling-llms/chat-models" >}}) for the provider-specific 
connection and model configuration.
 
-{{< tab "Python" >}}
-```python
-from pydantic import BaseModel
-from pyflink.common.typeinfo import BasicTypeInfo, RowTypeInfo
-
-from flink_agents.api.agents.react_agent import ReActAgent
-from flink_agents.api.chat_message import ChatMessage, MessageRole
-from flink_agents.api.execution_environment import AgentsExecutionEnvironment
-from flink_agents.api.prompts.prompt import Prompt
-from flink_agents.api.resource import ResourceDescriptor, ResourceName, 
ResourceType
-from flink_agents.api.tools.tool import Tool
-```
-{{< /tab >}}
-
-{{< tab "Java" >}}
-```java
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.apache.flink.agents.api.AgentsExecutionEnvironment;
-import org.apache.flink.agents.api.agents.ReActAgent;
-import org.apache.flink.agents.api.chat.messages.ChatMessage;
-import org.apache.flink.agents.api.chat.messages.MessageRole;
-import org.apache.flink.agents.api.prompt.Prompt;
-import org.apache.flink.agents.api.resource.ResourceDescriptor;
-import org.apache.flink.agents.api.resource.ResourceName;
-import org.apache.flink.agents.api.resource.ResourceType;
-import org.apache.flink.agents.api.tools.Tool;
-import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
-import org.apache.flink.api.common.typeinfo.TypeInformation;
-import org.apache.flink.api.java.typeutils.RowTypeInfo;
-
-import java.util.Arrays;
-import java.util.List;
-```
-{{< /tab >}}
-
-{{< /tabs >}}
-
-## ReAct Agent Example
+The following example registers a chat model connection on the 
`AgentsExecutionEnvironment`, defines the chat model descriptor, and creates 
the agent:
 
-{{< tabs "ReAct Agent Example" >}}
+{{< tabs "Create a ReAct Agent" >}}
 
 {{< tab "Python" >}}
 ```python
-my_react_agent = ReActAgent(
-    chat_model=chat_model_descriptor,
-    prompt=my_prompt,
-    output_schema=MyBaseModelDataType, # or output_schema=my_row_type_info
+# Register a chat model connection under a resource name.
+agents_env.add_resource(
+    "my_ollama_connection",
+    ResourceType.CHAT_MODEL_CONNECTION,
+    ResourceDescriptor(
+        clazz=ResourceName.ChatModel.OLLAMA_CONNECTION, request_timeout=120
+    ),
 )
-```
-{{< /tab >}}
-
-{{< tab "Java" >}}
-```java
-ReActAgent myReActAgent =
-        new ReActAgent(
-                chatModelDescriptor,
-                myPrompt,
-                MyBaseModelDataType.class
-                // or myRowTypeInfo
-        );
-```
-{{< /tab >}}
-
-{{< /tabs >}}
-
-## Initialize Arguments
-### Chat Model
-User should specify the chat model used in the ReAct Agent.
-
-We use `ResourceDescriptor` to describe the chat model, includes chat model 
type and chat model arguments. See [Chat Model]({{< ref 
"docs/development/calling-llms/chat-models" >}}) for more details.
 
-{{< tabs "ChatModel ResourceDescriptor" >}}
-
-{{< tab "Python" >}}
-```python
+# Define the chat model descriptor.
 chat_model_descriptor = ResourceDescriptor(
     clazz=ResourceName.ChatModel.OLLAMA_SETUP,
     connection="my_ollama_connection",
     model="qwen3:8b",
-    tools=["my_tool1", "my_tool2"],
 )
+
+# Create the ReAct Agent.
+my_react_agent = ReActAgent(chat_model=chat_model_descriptor)
 ```
 {{< /tab >}}
 
 {{< tab "Java" >}}
 ```java
+// Register a chat model connection under a resource name.
+agentsEnv.addResource(
+        "myOllamaConnection",
+        ResourceType.CHAT_MODEL_CONNECTION,
+        
ResourceDescriptor.Builder.newBuilder(ResourceName.ChatModel.OLLAMA_CONNECTION)
+                .addInitialArgument("endpoint", "http://localhost:11434";)
+                .addInitialArgument("requestTimeout", 120)
+                .build());
+
+// Define the chat model descriptor.
 ResourceDescriptor chatModelDescriptor =
-                
ResourceDescriptor.Builder.newBuilder(ResourceName.ChatModel.OLLAMA_SETUP)
-                        .addInitialArgument("connection", "myOllamaConnection")
-                        .addInitialArgument("model", "qwen3:8b")
-                        .addInitialArgument(
-                                "tools", List.of("myTool1", "myTool2"))
-                        .build();
+        
ResourceDescriptor.Builder.newBuilder(ResourceName.ChatModel.OLLAMA_SETUP)
+                .addInitialArgument("connection", "myOllamaConnection")
+                .addInitialArgument("model", "qwen3:8b")
+                .build();
+
+// Create the ReAct Agent; pass null for the optional prompt and output schema.
+ReActAgent myReActAgent = new ReActAgent(chatModelDescriptor, null, null);
 ```
 {{< /tab >}}
 
 {{< /tabs >}}
 
-{{< hint warning >}}
-The tools listed in `tools=[...]` must be registered on the 
`AgentsExecutionEnvironment` **before** the agent runs, using a name that 
matches the entry in the list — otherwise the agent fails at runtime with a 
"resource not found" error.
-{{< /hint >}}
+You can optionally expose tools to the ReAct Agent. Register each tool on the 
`AgentsExecutionEnvironment` under a resource name (this can also be done with 
a YAML file — see [Tool Use]({{< ref 
"docs/development/calling-llms/tool_use#register-tool-to-execution-environment" 
>}}) for the full guide), then list the registered names in the chat model 
descriptor's `tools` argument. Each name must match a registered tool; 
otherwise the agent fails at runtime with a "resource not found" error.
 
-Register the referenced tools (this can also be done with a YAML file — see 
[Tool Use]({{< ref 
"docs/development/calling-llms/tool_use#register-tool-to-execution-environment" 
>}}) for the full guide):
-
-{{< tabs "Register Tools" >}}
+{{< tabs "Expose Tools" >}}
 
 {{< tab "Python" >}}
 ```python
+# Register each tool under a resource name.
 agents_env.add_resource(
     "my_tool1", ResourceType.TOOL, Tool.from_callable(my_tool1)
 )
+# Register my_tool2 the same way.
+
+# List the registered tool names in tools.
+chat_model_descriptor = ResourceDescriptor(
+    clazz=ResourceName.ChatModel.OLLAMA_SETUP,
+    connection="my_ollama_connection",
+    model="qwen3:8b",
+    tools=["my_tool1", "my_tool2"],
+)
 ```
 {{< /tab >}}
 
 {{< tab "Java" >}}
 ```java
+// Register each tool under a resource name.
 agentsEnv.addResource(
         "myTool1",
         ResourceType.TOOL,
         Tool.fromMethod(MyAgentExample.class.getMethod("myTool1", 
String.class)));
+// Register myTool2 the same way.
+
+// List the registered tool names in tools.
+ResourceDescriptor chatModelDescriptor =
+        
ResourceDescriptor.Builder.newBuilder(ResourceName.ChatModel.OLLAMA_SETUP)
+                .addInitialArgument("connection", "myOllamaConnection")
+                .addInitialArgument("model", "qwen3:8b")
+                .addInitialArgument("tools", List.of("myTool1", "myTool2"))
+                .build();
 ```
 {{< /tab >}}
 
 {{< /tabs >}}
 
-### Prompt
-User can provide prompt to instruct agent.
+Registering a Vector Store resource does not make a ReAct Agent retrieve from 
it automatically. Implement retrieval explicitly, for example by exposing it as 
a tool.
+
+### Optional Arguments
+
+#### Prompt
+The prompt is optional. Without one, the agent directly converts a Java 
`String` or primitive wrapper, a Python `str`, `bool`, `int`, `float`, or 
`None`, or a Java `Map`/Python `dict` whose only key is `input` into a user 
message. Other structured inputs require a prompt to map their fields into one 
or more user messages; otherwise, the agent rejects the input at runtime.
 
-A typical prompt contains two messages: a SYSTEM message that tells the agent 
what to do (and gives input and output examples), and a USER message that 
describes how to convert the input element into a text string. This is a 
recommended pattern, not a strict requirement — the agent uses all messages in 
the prompt, and the SYSTEM message is optional (if it is omitted, the framework 
still prepends the output-schema instruction automatically).
+A typical prompt contains two messages: a SYSTEM message that tells the agent 
what to do (and gives input and output examples), and a USER message that 
describes how to convert the input element into a text string. This is a 
recommended pattern, not a strict requirement — the agent uses all messages in 
the prompt, and the SYSTEM message is optional. When an output schema is 
configured, the ReAct Agent adds its own schema instruction as a SYSTEM 
message, right after the prompt's first SYS [...]
 
 {{< tabs "Prompt" >}}
 
@@ -188,9 +159,8 @@ system_prompt_str = """
 my_prompt = Prompt.from_messages(
     messages=[
         ChatMessage.system(system_prompt_str),
-        # For react agent, if the input element is not primitive types,
-        # framework will deserialize input element to dict and fill the prompt.
-        # Note, the input element should be primitive types, BaseModel or Row.
+        # Structured input fields (dict, BaseModel, or Row) fill the matching
+        # placeholders. A primitive input only fills {input}.
         ChatMessage.user(
             """
             "id": {id},
@@ -199,6 +169,8 @@ my_prompt = Prompt.from_messages(
         ),
     ],
 ) 
+
+my_react_agent = ReActAgent(chat_model=chat_model_descriptor, prompt=my_prompt)
 ```
 {{< /tab >}}
 
@@ -218,6 +190,8 @@ Prompt myPrompt = Prompt.fromMessages(
                 new ChatMessage(
                         MessageRole.USER,
                         "{\"id\": \"{id}\",\n" + "\"review\": 
\"{review}\"}")));
+
+ReActAgent myReActAgent = new ReActAgent(chatModelDescriptor, myPrompt, null);
 ```
 {{< /tab >}}
 
@@ -228,13 +202,13 @@ The USER-message template uses `{placeholder}` syntax. 
The placeholder names are
 - **Primitive** (`int`, `str`, `float`, `bool`, ...): a single `{input}` 
placeholder.
 - **`Row`**: one placeholder per field name (`row.as_dict()` keys in Python, 
`row.getFieldNames()` in Java).
 - **`dict` / `Map`**: the keys are used directly.
-- **`BaseModel` (Python) / Pojo (Java)**: the object's field names.
+- **`BaseModel` (Python) / POJO (Java)**: the object's field names.
 
 For example, the prompt snippet above uses `{id}` and `{review}` because the 
input element's fields are named `id` and `review`. A placeholder whose name 
does not match a field is left unchanged in the text.
 
-If the input element is primitive types, like `int`, `str` and so on, the 
second message should be
+When a prompt formats a primitive input, use the `{input}` placeholder in its 
USER message:
 
-{{< tabs "Prepare Agents Execution Environment" >}}
+{{< tabs "Primitive Input Placeholder" >}}
 
 {{< tab "Python" >}}
 ```python
@@ -252,12 +226,12 @@ new ChatMessage(MessageRole.USER, "{input}")
 
 See [Prompt]({{< ref "docs/development/calling-llms/prompts" >}}) for more 
details.
 
-### Output Schema
-User can set output schema to configure the ReAct Agent output type. If output 
schema is set, the ReAct Agent will deserialize the llm response to expected 
type. 
+#### Output Schema
+The output schema is optional. If omitted, the agent returns the text of the 
final assistant response as a `String` (Java) or `str` (Python).
 
-The output schema should be a `BaseModel` subclass (Python) / a Pojo class 
(Java), or a `RowTypeInfo` (both).
+When you set an output schema, the agent emits the parsed result instead. The 
schema should be a `BaseModel` subclass (Python), a POJO class (Java), or a 
`RowTypeInfo` (both). If the final response cannot be parsed after the 
configured retries, the chat request fails and the ReAct Agent propagates that 
failure.
 
-When the chat model's provider supports it, the schema is enforced natively by 
the provider rather than only described in the prompt. See [Structured 
Output]({{< ref "docs/development/calling-llms/structured-output" >}}) for the 
strategies, supported providers and schema rules.
+When the chat model's provider supports it, the schema is enforced natively by 
the provider rather than only described in the prompt. See [Structured 
Output]({{< ref "docs/development/calling-llms/structured-output" >}}) for the 
strategies, result types, supported providers, schema rules, and failure 
behavior.
 
 {{< tabs "Output Schema" >}}
 
@@ -273,6 +247,11 @@ my_row_type_info = RowTypeInfo(
         [BasicTypeInfo.STRING_TYPE_INFO(), BasicTypeInfo.INT_TYPE_INFO()],
         ["id", "score"],
     )
+
+my_react_agent = ReActAgent(
+    chat_model=chat_model_descriptor,
+    output_schema=MyBaseModelDataType,  # or my_row_type_info
+)
 ```
 {{< /tab >}}
 
@@ -327,15 +306,43 @@ RowTypeInfo myRowTypeInfo =
                         BasicTypeInfo.STRING_TYPE_INFO, 
BasicTypeInfo.INT_TYPE_INFO
                 },
                 new String[] {"id", "score"});
+
+ReActAgent myReActAgent =
+        new ReActAgent(
+                chatModelDescriptor,
+                null,
+                MyBaseModelDataType.class // or myRowTypeInfo
+        );
 ```
 {{< /tab >}}
 
 {{< /tabs >}}
 
-### Skills
-User can pass [skills]({{< ref "docs/development/calling-llms/skills" >}}) to 
the constructor instead of adding a `skills` argument to the chat model 
descriptor. Two forms are accepted: a list of skill names, or a `Skills` object 
declaring where the skills are loaded from.
+#### Skills
+Skills are optional. You can pass [skills]({{< ref 
"docs/development/calling-llms/skills" >}}) to the constructor in addition to, 
or instead of, a `skills` argument on the chat model descriptor; the agent uses 
both. Two forms are accepted: a list of skill names, or a `Skills` object 
declaring where the skills are loaded from.
+
+**Skill names.** First register the skill sources on the 
`AgentsExecutionEnvironment`. The resource name identifies the collection of 
sources:
+
+{{< tabs "Register Skills" >}}
+
+{{< tab "Python" >}}
+```python
+agents_env.add_resource(
+    "my_skills", ResourceType.SKILLS, Skills.from_local_dir("./skills")
+)
+```
+{{< /tab >}}
+
+{{< tab "Java" >}}
+```java
+agentsEnv.addResource(
+        "mySkills", ResourceType.SKILLS, Skills.fromLocalDir("./skills"));
+```
+{{< /tab >}}
+
+{{< /tabs >}}
 
-**Skill names.** Pass the names of skills that are already declared to the 
agent:
+Then pass the names declared in the sources' `SKILL.md` files to the 
constructor:
 
 {{< tabs "Skills" >}}
 
@@ -343,7 +350,6 @@ User can pass [skills]({{< ref 
"docs/development/calling-llms/skills" >}}) to th
 ```python
 my_react_agent = ReActAgent(
     chat_model=chat_model_descriptor,
-    prompt=my_prompt,
     skills=["math-calculator"],
 )
 ```
@@ -352,21 +358,17 @@ my_react_agent = ReActAgent(
 {{< tab "Java" >}}
 ```java
 ReActAgent myReActAgent =
-        new ReActAgent(chatModelDescriptor, myPrompt, null, 
List.of("math-calculator"));
+        new ReActAgent(chatModelDescriptor, null, null, 
List.of("math-calculator"));
 ```
 {{< /tab >}}
 
 {{< /tabs >}}
 
-The constructor skills are combined with any `skills` already set on the chat 
model descriptor:
+Skills passed to the constructor are combined with those configured on the 
chat model descriptor, with duplicate names included only once. Referenced 
skills must be declared on the agent or its execution environment.
 
-- The descriptor's skills come first, followed by the constructor skills; a 
name listed more than once is kept only at its first occurrence.
-- Passing no skills, or an empty list, adds nothing: the descriptor is used 
exactly as given.
-- The descriptor you pass in is not modified; the agent uses a copy with the 
combined skills.
-- Only skill names are combined. The command policy of the built-in `bash` 
tool, such as `allowed_commands`, is always taken from the chat model 
descriptor, so set it there.
-- The sources behind those names have to be declared somewhere the agent can 
see them: a `@Skills`/`@skills` method, the execution environment, or the agent 
itself.
+Configure `allowed_commands` on the chat model descriptor to control which 
commands the built-in `bash` tool may execute.
 
-**Skill sources.** Pass a `Skills` object to declare the sources and let the 
framework resolve the skill names at runtime:
+**Skill sources.** Alternatively, pass a `Skills` object directly to the 
constructor. The constructor registers the sources on the agent, so no separate 
registration on the execution environment is required:
 
 {{< tabs "Skill Sources" >}}
 
@@ -374,7 +376,6 @@ The constructor skills are combined with any `skills` 
already set on the chat mo
 ```python
 my_react_agent = ReActAgent(
     chat_model=chat_model_descriptor,
-    prompt=my_prompt,
     skills=Skills.from_local_dir("./skills"),
 )
 ```
@@ -385,7 +386,7 @@ my_react_agent = ReActAgent(
 ReActAgent myReActAgent =
         new ReActAgent(
                 chatModelDescriptor,
-                myPrompt,
+                null,
                 null,
                 Skills.fromLocalDir("./skills"));
 ```
@@ -393,7 +394,7 @@ ReActAgent myReActAgent =
 
 {{< /tabs >}}
 
-The constructor registers those sources on the agent, so they do not also need 
`add_resource(..., ResourceType.SKILLS, ...)` on the execution environment. 
Every skill found in the sources becomes available, and the resolved names are 
appended after any explicitly named ones. A single `Skills` object may declare 
several sources; to combine sources held in separate objects, gather them into 
one `Skills`, declare further `@Skills`/`@skills` methods, or register them on 
the agent with `addRe [...]
+Every skill found in the sources becomes available, and the resolved names are 
appended after any explicitly named ones. A single `Skills` object may declare 
several sources; to combine sources held in separate objects, gather them into 
one `Skills`, declare further `@Skills`/`@skills` methods, or register them on 
the agent with `addResource(..., ResourceType.SKILLS, ...)`.
 
 **Which declaration wins.** Sources reach the agent from three levels. 
`@Skills`/`@skills` methods are merged first, then the execution environment's 
`SKILLS` resources, then the agent's own. A declaration from a later level wins 
when two of them resolve to the same skill name.
 

Reply via email to