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 582d7f15 [docs] Clarify Tool Use injection and parallel-call guidance 
(#1261)
582d7f15 is described below

commit 582d7f15974a39b39c6fac8d1a0c977d5d48c452
Author: daierenao <[email protected]>
AuthorDate: Fri Oct 16 14:27:14 2026 +0800

    [docs] Clarify Tool Use injection and parallel-call guidance (#1261)
    
    Generated-by: Codex CLI 0.162.0-alpha.17.2 (GPT-6)
---
 docs/content/docs/development/calling-llms/chat.md |   2 +-
 .../docs/development/calling-llms/tool_use.md      | 181 +++++++++++++++------
 docs/content/docs/development/create-agent/yaml.md |   2 +
 docs/content/docs/operations/configuration.md      |   8 +-
 4 files changed, 134 insertions(+), 59 deletions(-)

diff --git a/docs/content/docs/development/calling-llms/chat.md 
b/docs/content/docs/development/calling-llms/chat.md
index eb6a00f0..b9216033 100644
--- a/docs/content/docs/development/calling-llms/chat.md
+++ b/docs/content/docs/development/calling-llms/chat.md
@@ -297,7 +297,7 @@ the text blocks and exclude media.
 
 ## Tool Calling {#built-in-events-and-actions}
 
-A chat model can use tools to perform operations while answering a request. To 
enable this, define or register the tools and reference their names in the 
model setup's `tools` list. See [Tool Use]({{< ref 
"docs/development/calling-llms/tool_use" >}}) for configuration and examples.
+A chat model can use tools to perform operations while answering a request. To 
enable this, define or register the tools and reference their names in the 
model setup's `tools` list. See [Local Function as Tool]({{< ref 
"docs/development/calling-llms/tool_use#local-function-as-tool" >}}) for 
declaration and registration examples, [Tool Parameter Injection]({{< ref 
"docs/development/calling-llms/tool_use#tool-parameter-injection" >}}) for 
framework-provided arguments, and [Parallel tool-ca [...]
 
 Send a `ChatRequestEvent` as usual. The model decides whether to answer 
directly or request tool calls:
 
diff --git a/docs/content/docs/development/calling-llms/tool_use.md 
b/docs/content/docs/development/calling-llms/tool_use.md
index dc7fef4e..e4035fa0 100644
--- a/docs/content/docs/development/calling-llms/tool_use.md
+++ b/docs/content/docs/development/calling-llms/tool_use.md
@@ -26,19 +26,36 @@ under the License.
 
 ## Overview
 
-Flink Agents provides a flexible and extensible tool use mechanism. Developers 
can define the tool as a local Python function, or they can integrate with a 
remote MCP server to use the tools provided by the MCP server.
+Tools let a model request work from a Java or Python function, or from an
+[MCP server]({{< ref "docs/development/calling-llms/mcp" >}}). This page 
explains how
+to declare function tools, supply runtime parameters, and configure tool 
execution.
+For the chat request, tool-call, and response flow, see
+[Tool Calling in Chat with Models]({{< ref 
"docs/development/calling-llms/chat#built-in-events-and-actions" >}}).
 
 ## Local Function as Tool
 
-Developer can define the tool as a local Python/Java function, and there are 
two ways to define and register a local function as a tool:
+Declare a tool as a static method in an Agent class, or register it on the
+execution environment to share it across agents. In both cases, reference the
+registered tool name in the chat model setup's `tools` list.
+
+The following snippets show the tool declaration and registration parts of a 
job.
+They assume a connection named `ollamaChatModelConnection` has been registered 
as
+explained in [Declare the Resources]({{< ref 
"docs/development/calling-llms/chat-models" >}}).
+The notification helper is application code; the complete
+{{< gh_link 
file="python/flink_agents/examples/quickstart/react_agent_example.py" 
name="Python example" >}}
+and {{< gh_link 
file="examples/src/main/java/org/apache/flink/agents/examples/ReActAgentExample.java"
 name="Java example" >}}
+show how to connect a tool to a ReAct Agent and a Flink job.
 
 {{< hint info >}}
-Flink Agents uses the docstring of the python tool function to generate the 
tool metadata. The docstring of the python function should accurately describe 
the tool's purpose, parameters, and return value, so that the LLM can 
understand the tool and use it effectively.
+Flink Agents uses a Python function's docstring to describe the tool to the 
model.
+Describe its purpose, parameters, and return value accurately. In Java, use
+`@Tool(description = "...")` and `@ToolParam` to describe the function and 
name its parameters.
 {{< /hint >}}
 
 ### Define Tool as Static Method in Agent Class
 
-Developer can define the tool as a static method in the agent class while 
defining the Agent, and use the `@tool` decorator to mark the function as a 
tool in python (or `@Tool` annotation in java). The tool can be referenced by 
its name in the `tools` list of the `ResourceDescriptor` when creating the chat 
model in the agent.
+Use `@tool` in Python or `@Tool` in Java to declare a static method as a tool.
+The chat model setup references that method by name:
 
 {{< tabs "Define Tool as Static Method in Agent Class" >}}
 
@@ -67,7 +84,8 @@ class ReviewAnalysisAgent(Agent):
         """ChatModel which focus on review analysis."""
         return ResourceDescriptor(
             clazz=ResourceName.ChatModel.OLLAMA_SETUP,
-            ...,
+            connection="ollamaChatModelConnection",
+            model="qwen3:8b",
             tools=["notify_shipping_manager"], # reference the tool by its name
         )
     
@@ -89,12 +107,10 @@ public class ReviewAnalysisAgent extends Agent {
     public static ResourceDescriptor reviewAnalysisModel() {
         return 
ResourceDescriptor.Builder.newBuilder(ResourceName.ChatModel.OLLAMA_SETUP)
                 .addInitialArgument("connection", "ollamaChatModelConnection")
-                ...
+                .addInitialArgument("model", "qwen3:8b")
                 .addInitialArgument("tools", 
Collections.singletonList("notifyShippingManager")) // reference the tool by 
its name
                 .build();
     }
-    
-    ...
 }
 ```
 {{< /tab >}}
@@ -108,7 +124,8 @@ public class ReviewAnalysisAgent extends Agent {
 
 ### Register Tool to Execution Environment
 
-Developer can register the tool to the execution environment, and then 
reference the tool by its name. This allows the tool to be reused by multiple 
agents.
+Register a tool on the execution environment when multiple agents need it.
+Each agent references the registered resource name in its chat model setup.
 
 {{< tabs "Register Tool to Execution Environment" >}}
 
@@ -140,9 +157,10 @@ agents_env.add_resource(
 review_analysis_react_agent = ReActAgent(
     chat_model=ResourceDescriptor(
         clazz=ResourceName.ChatModel.OLLAMA_SETUP,
+        connection="ollamaChatModelConnection",
+        model="qwen3:8b",
         tools=["notify_shipping_manager"], # reference the tool by its name
     ),
-    ...
 )
 ```
 {{< /tab >}}
@@ -152,7 +170,7 @@ review_analysis_react_agent = ReActAgent(
 @Tool(description = "Notify the shipping manager when product received a 
negative review due to shipping damage.")
 public static void notifyShippingManager(
         @ToolParam(name = "id") String id, @ToolParam(name = "review") String 
review) {
-    ...
+    CustomTypesAndResources.notifyShippingManager(id, review);
 }
 
 // Add notify shipping manager tool to the execution environment.
@@ -167,11 +185,13 @@ agentsEnv
 // Create react agent with notify shipping manager tool.
 ReActAgent reviewAnalysisReactAgent = new ReActAgent(
         
ResourceDescriptor.Builder.newBuilder(ResourceName.ChatModel.OLLAMA_SETUP)
+                .addInitialArgument("connection", "ollamaChatModelConnection")
+                .addInitialArgument("model", "qwen3:8b")
                 .addInitialArgument(
                         "tools", 
Collections.singletonList("notifyShippingManager")) // reference the tool by 
its name
-                ...
                 .build(),
-        ...);
+        null,
+        null);
 ```
 {{< /tab >}}
 
@@ -225,6 +245,29 @@ Some tools need runtime data that should not be chosen by 
the model, such as a t
 
 The model only sees and provides normal tool parameters. The built-in 
`tool_call_action` resolves injected values and overwrites any model-supplied 
values for the same parameters before calling the tool.
 
+Choose the source according to where the value is available when the tool runs:
+
+| Source | Runtime value | Python declaration |
+| --- | --- | --- |
+| `config` | A value in the agent execution environment configuration | 
`InjectedArg.from_config("tenant_id")` |
+| `sensory_memory` | A value at a path in the current run's sensory memory | 
`InjectedArg.from_sensory_memory("request.trace_id")` |
+| `short_term_memory` | A value at a path in the agent's short-term memory | 
`InjectedArg.from_short_term_memory("session.tenant_id")` |
+
+For memory sources, write the value to the selected path before requesting the
+tool call. The path must exist and refer to a value, rather than a nested 
memory
+object. The injection key identifies the configuration entry or memory path;
+it can differ from the tool parameter name.
+
+In Java annotations, set `@ToolParam(injected = true)` to hide the parameter 
from
+the model, and use `source` and `key` to bind its value. The default source is
+`sensory_memory`; an omitted key uses the parameter name. For YAML 
declarations,
+see the [`injected_args` reference]({{< ref 
"docs/development/create-agent/yaml#resources" >}}),
+which covers the configuration shape, defaults, and examples.
+
+For the following example, set `tenant_id` on the agent execution environment
+with `agents_env.get_config().set_str("tenant_id", "tenant-a")` in Python or
+`agentsEnv.getConfig().setStr("tenant_id", "tenant-a")` in Java.
+
 {{< tabs "Inject Tool Parameters" >}}
 
 {{< tab "Python" >}}
@@ -271,7 +314,7 @@ public class OrderAgent extends Agent {
 
 {{< /tabs >}}
 
-Configure the injected value on the agent execution environment. Python uses 
`agents_env.get_config().set_str("tenant_id", "tenant-a")`; Java uses 
`agentsEnv.getConfig().setStr("tenant_id", "tenant-a")`.
+The model supplies only `order_id`; the framework supplies `tenant_id`.
 
 Injected values can also come from memory when the value is attached to the 
current request or session instead of static environment configuration:
 
@@ -311,61 +354,91 @@ public static String lookupOrder(
 
 {{< /tabs >}}
 
-The supported sources are `config`, `sensory_memory`, and `short_term_memory`.
-If `source` is omitted, it defaults to `sensory_memory`.
-For Java annotation-based tools, `@ToolParam(injected = true)` is what marks 
the
-parameter as framework-injected and hidden from the model; `source` and `key` 
only
-configure where the value is read from.
-If the same injected parameter is declared both on the tool function and by a
-descriptor such as YAML, the declarations must resolve to the same source and 
key;
-conflicting declarations fail during agent plan construction.
+### Overrides and failures
+
+The built-in `tool_call_action` resolves injection before invoking a function 
tool:
 
-Injected parameters are part of the tool execution contract, not the model 
contract:
+- Injected parameters are excluded from the model-facing JSON schema.
+- A framework value overrides any model-supplied value for the same parameter.
+  The original `ToolRequestEvent` arguments remain unchanged.
+- A missing configuration entry, missing memory path, or invalid injected value
+  fails the tool call without invoking the function. Model-supplied values are
+  never used as a fallback.
+- If the function and a descriptor such as YAML both declare an injected
+  parameter, their source and key must agree. A conflict fails during agent 
plan
+  construction, before the tool can run.
 
-- They are not included in the JSON schema sent to the model.
-- They are not written back to the original `ToolRequestEvent`.
-- If a model supplies an argument with the same name, the framework-provided 
value takes precedence.
+This resolution is part of the built-in tool-call flow. When calling a function
+tool directly, supply its required arguments yourself.
 
 ## Parallel tool-call batches
 
-When `tool-call.async` is enabled, the built-in `tool_call_action` runs all 
tool calls from one
-`ToolRequestEvent` as a single durable batch. Set `async.batch.parallelism` to 
control concurrency:
+A model may request several tool calls in one `ToolRequestEvent`. The built-in
+`tool_call_action` can execute the tools registered by the agent, possibly
+including ordinary functions or MCP tool calls, as parallel operations. Use the
+following settings on the agent execution environment:
 
-- `1` — serial execution (one tool at a time).
-- `> 1` — parallel batch with a sliding window of at most that many in-flight 
tool calls.
+| Option | Default | Effect on tool execution |
+| --- | --- | --- |
+| `tool-call.async` | `true` | Enables durable async tool calls. With `false`, 
tools execute synchronously, one at a time. |
+| `async.batch.parallelism` | Available CPU count | Maximum concurrent calls 
in one async batch. `1` executes tools one at a time while keeping async 
execution enabled. |
 
-Java and Python support concurrent tool-call batches on all supported JDK 
versions.
+For example, allow up to four concurrent calls per batch:
 
-Tool batches share a `num-async-threads` pool **per operator subtask** (every 
key routed to
-that subtask). On JDK 21+ and in Python, chat and RAG calls also use this 
pool. On older JDKs,
-Java batches use a separate pool from the Action workers. The default batch 
parallelism is
-the host CPU count.
+{{< tabs "Configure Tool Parallelism" >}}
+{{< tab "Python" >}}
+```python
+from flink_agents.api.core_options import AgentExecutionOptions
 
-Parallel tool calls share execution capacity with other external calls. A 
large tool
-batch may delay other model calls or retrieval requests. Use 
`async.batch.parallelism`
-to limit how many tools run concurrently.
+agents_env.get_config().set(AgentExecutionOptions.TOOL_CALL_ASYNC, True)
+agents_env.get_config().set(AgentExecutionOptions.ASYNC_BATCH_PARALLELISM, 4)
+```
+{{< /tab >}}
+{{< tab "Java" >}}
+```java
+import org.apache.flink.agents.api.agents.AgentExecutionOptions;
 
-{{< hint warning >}}
-**Cross-key impact:** with defaults (`num-async-threads = 2× cores`, 
`async.batch.parallelism =
-cores`), one full tool batch can use up to half the subtask pool; several hot 
keys can saturate it.
-If your job mixes heavy tool batches with chat/RAG on the same subtask, lower
-`async.batch.parallelism` or increase `num-async-threads`.
-{{< /hint >}}
+agentsEnv.getConfig().set(AgentExecutionOptions.TOOL_CALL_ASYNC, true);
+agentsEnv.getConfig().set(AgentExecutionOptions.ASYNC_BATCH_PARALLELISM, 4);
+```
+{{< /tab >}}
+{{< /tabs >}}
 
-`async.batch.timeout.ms` applies to the whole batch. On timeout, completed 
slots keep their
-outcome; slots that started but did not finish are recorded as failures; slots 
that never started
-executing (for example, queued in a saturated pool) stay pending, so they are 
re-executed after
-recovery instead of recording a false failure. Timeout cancellation is 
best-effort; side-effecting
-tools should be idempotent or provide a reconciler.
+With async execution enabled and `async.batch.parallelism` greater than `1`,
+multiple tool calls can run concurrently. This limit also applies to batches
+created with `ctx.gather(...)`. The `num-async-threads` setting further limits
+available concurrency. Tool batches share execution capacity with other 
external
+calls, so a large batch may delay other model calls or retrieval requests. 
Lower
+the batch limit to leave capacity for other calls or avoid overwhelming an
+external service. Actual concurrency can be lower than the batch limit.
 
 {{< hint warning >}}
-**Thread reclamation:** a timeout unblocks the batch but cannot interrupt a 
tool that is still
-running. Its worker thread stays in the shared `num-async-threads` pool until 
the tool returns on
-its own, so a tool that never returns permanently reduces pool capacity. Bound 
blocking work inside
-the tool (for example an HTTP client read timeout) rather than relying on this 
batch timeout to free
-the thread.
+Calls in a parallel batch must be independent: a tool must not wait for another
+call in the same batch to complete. Concurrency is an optimization and does not
+guarantee that calls overlap or finish in request order. If one operation 
depends
+on another's result, request it in a later step instead of the same batch.
 {{< /hint >}}
 
+### Timeouts and external effects
+
+`async.batch.timeout.ms` sets an overall timeout for a parallel batch of 
ordinary
+tool calls. Its default is `-1`; non-positive values disable it. When it 
expires,
+completed calls keep their results and unfinished calls are reported to the 
model
+as failed tool calls.
+
+For requests containing only ordinary tools, the batch timeout is not used when
+`tool-call.async` is `false`, when `async.batch.parallelism` is `1` or less, 
or when
+the request has a single tool call. Configure timeouts for blocking operations
+inside each tool, such as an HTTP client read timeout.
+
+A batch timeout does not undo external effects or guarantee that an already
+running tool stops. Tools that change external systems should be idempotent,
+because a call may run again after recovery. See
+[Configuration]({{< ref "docs/operations/configuration" >}}) for the full 
async batch
+and execution-capacity options, and
+[Durable Execution]({{< ref 
"docs/development/create-agent/actions#durable-execution" >}})
+for recovery guarantees.
+
 ## Tool response content and metadata
 
 For simple tools, return a value and the framework converts it to response 
text.
diff --git a/docs/content/docs/development/create-agent/yaml.md 
b/docs/content/docs/development/create-agent/yaml.md
index cb18bda1..b00b0f65 100644
--- a/docs/content/docs/development/create-agent/yaml.md
+++ b/docs/content/docs/development/create-agent/yaml.md
@@ -179,6 +179,8 @@ agents:
 
 The supported `source` values are `config`, `sensory_memory`, and 
`short_term_memory`. If omitted, `source` defaults to `sensory_memory`. For 
`config`, `key` is read from the agent execution environment configuration. For 
memory sources, `key` is the memory path.
 
+See [Tool Parameter Injection]({{< ref 
"docs/development/calling-llms/tool_use#tool-parameter-injection" >}}) for 
runtime value resolution, overriding model-supplied arguments, and 
missing-value behavior.
+
 For Java tools loaded from YAML, the `injected_args` entry itself marks the 
parameter
 as framework-injected and hides it from the model-facing schema. The Java 
method may
 use `@ToolParam(name = "...")` to provide stable parameter names, but it does 
not need
diff --git a/docs/content/docs/operations/configuration.md 
b/docs/content/docs/operations/configuration.md
index d9bc526b..a934ca92 100644
--- a/docs/content/docs/operations/configuration.md
+++ b/docs/content/docs/operations/configuration.md
@@ -130,11 +130,11 @@ Here is the list of all built-in core configuration 
options.
 | `max-retries`             | 0                          | int                 
  | Number of additional attempts per model call, including routing judge 
calls. Defaults to 0 (no retries).                                              
                                                                                
                                                                       |
 | `retry-wait-interval`     | 1                          | int                 
  | Base wait interval in seconds between retries. Uses exponential backoff: 
the actual wait time for the Nth retry is `retry-wait-interval * 2^(N-1)` 
seconds. For example, with default 1s, waits are 1s, 2s, 4s, etc. Retry count 
and total wait time are reported in `ChatResponseEvent` and recorded as metrics 
(`retryCount`, `retryWaitSec`) under the configured ChatModel resource name. |
 | `chat.async`              | true                       | boolean             
  | Whether chat asynchronously for built-in chat action.                       
                                                                                
                                                                                
                    |
-| `tool-call.async`         | true                       | boolean             
  | Whether the built-in tool-call action runs each tool via durable async 
execution.                                                                      
                                                                                
                         |
-| `async.batch.parallelism` | os cpu count | int | Maximum concurrent calls in 
one `ctx.gather(...)` batch, including ordinary calls, durable calls, and 
built-in async tool calls. `1` runs calls sequentially. Actual concurrency is 
also limited by `num-async-threads`; lower this per-batch limit to leave 
capacity for other calls on the same subtask. Java and Python support batch 
concurrency on all supported JDK versions. |
-| `async.batch.timeout.ms` | -1 (disabled) | long (milliseconds) | Overall 
timeout for one async batch, including ordinary calls, durable calls, and 
built-in async tool calls. Non-positive values disable it. Completed calls keep 
their outcomes; unfinished calls receive timeout failures. For durable calls, 
started calls are recorded as failures while unstarted calls remain pending for 
recovery. Running callbacks may continue after timeout, occupy workers, and 
produce external effects, so  [...]
+| `tool-call.async`         | true                       | boolean             
  | Whether the built-in tool-call action runs each tool via durable async 
execution. See [Parallel tool-call batches]({{< ref 
"docs/development/calling-llms/tool_use#parallel-tool-call-batches" >}}) for 
how this switch works with the batch settings below. |
+| `async.batch.parallelism` | os cpu count | int | Maximum concurrent calls in 
one async batch, including batches created with `ctx.gather(...)`. `1` runs 
calls sequentially. Actual concurrency is also limited by `num-async-threads`. 
See [Parallel tool-call batches]({{< ref 
"docs/development/calling-llms/tool_use#parallel-tool-call-batches" >}}). |
+| `async.batch.timeout.ms` | -1 (disabled) | long (milliseconds) | Overall 
timeout for one async batch. Non-positive values disable it. A timeout does not 
guarantee that running calls stop or undo their external effects. See [Timeouts 
and external effects]({{< ref 
"docs/development/calling-llms/tool_use#timeouts-and-external-effects" >}}) for 
tool-call behavior and constraints. |
 | `rag.async`               | true                       | boolean             
  | Whether retrieve context asynchronously for built-in context retrieval 
action.                                                                         
                                                                                
                         |
-| `num-async-threads`       | os cpu count * 2           | int                 
  | Size of the async worker pool shared by all keys on an operator subtask. On 
JDK 21+ and in Python, chat, RAG, and batches use this pool. On older JDKs, 
Java uses a separate batch pool of this size in addition to its Action workers. 
Default `async.batch.parallelism` is `os cpu count`, so one full batch can 
occupy up to half of this pool; multiple keys running large batches can 
saturate it. |
+| `num-async-threads` | os cpu count * 2 | int | Controls execution capacity 
for asynchronous calls. `async.batch.parallelism` separately limits concurrency 
within each batch. See [Parallel tool-call batches]({{< ref 
"docs/development/calling-llms/tool_use#parallel-tool-call-batches" >}}) for 
tool-call concurrency guidance. |
 | `parallel-execution.enabled` | true                    | boolean             
  | Whether plans with only **Java Actions** run Actions concurrently on the 
parallel execution engine when the continuation-based engine is unavailable 
(**JDK < 21**). Plans declaring Python Resources additionally require a Flink 
version supporting [cross-language async calls]({{< ref 
"docs/development/create-agent/actions#cross-language-async-requirements" >}}). 
Same-key input records commit in input order,  [...]
 | `max-in-flight-input-records` | 100                   | int                  
 | Maximum number of input records that may be in flight concurrently. Only 
enforced by the **JDK < 21** parallel execution engine for plans with only 
**Java Actions**; the JDK 21 coroutine engine and plans containing **Python** 
actions ignore it. Every admitted record consumes one unit of budget; at the 
cap, admission of further records blocks until an in-flight record retires. |
 | `job-identifier`          | none                       | String              
  | The unique identifier of job, remaining consistent after restoring from a 
savepoint. If not set, uses flink job id.                                       
                                                                                
                      |

Reply via email to