spring-projects / spring-projects/spring-ai
Feature Request: Expose advisor context to tool functions for read and write access during tool execution
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
Title
Feature Request: Expose advisor context to tool functions for read and write access during tool execution
Body
Expected Behavior
Tool functions should be able to read and write the advisor ChatClientRequest.context() while a tool is executing.
Preferred developer experience example (Option A: expose advisor context via ToolContext API):
@Tool
public String queryDatabase(ToolContext toolContext) {
// Read advisor context value propagated from advisor chain
String tenantId = (String) toolContext.getAdvisorContext().get("tenantId");
// Write execution state back into advisor context for downstream advisors
toolContext.getAdvisorContext().put("tool.db.execution.ms", 120L);
return "query result";
}
After tool execution completes, values written by the tool inside getAdvisorContext() should be visible to subsequent advisor after() callbacks in the advisor chain.
Alternative acceptable options:
- Built‑in bidirectional mirroring advisor to sync keys between
request.context()andrequest.toolContext(). - Tool lifecycle hooks (
onToolStart/onToolComplete) within advisor layer providing access to bothChatClientRequestand tool execution result.
Current Behavior
Spring AI 2.0 maintains two fully isolated context containers:
ChatClientRequest.context()— advisor‑chain context, accessible only in advisorbefore()/after()methods. Tool functions cannot access this context at all.ChatClientRequest.toolContext()— passed to tool functions as a snapshot. Modifications inside tool functions do not flow back to the originalChatClientRequest.
There is no native framework way for tool logic to:
- Read state populated by advisors.
- Publish runtime state from tool execution back into advisor chain for logging, metrics, agent state management in downstream advisors.
Context
Use cases driving this feature
I am building agent and observability logic that spans both advisors and tool invocations:
- Propagate trace/correlation id, tenant information from advisor layer into every tool call.
- Capture tool runtime metadata (latency, custom business metrics) inside tool implementation and let later advisors aggregate, persist or export those metrics.
- Build multi‑step agent workflows where tool execution needs to signal state changes to advisor chain.
Known workaround
Today the only workaround is manually sharing a thread‑safe mutable container (e.g. ConcurrentHashMap), injecting the same object reference into both request.context() and request.toolContext().
// Setup shared mutable state
ConcurrentHashMap<String, Object> sharedState = new ConcurrentHashMap<>();
chatClient.prompt()
.user("user query")
.context(Map.of("sharedState", sharedState))
.toolContext(Map.of("sharedState", sharedState))
.advisors(new MyObservabilityAdvisor())
.tools(myTool)
.call();
// Tool implementation
@Tool
public String myTool(ToolContext toolContext) {
ConcurrentHashMap<String,Object> state =
(ConcurrentHashMap<String, Object>) toolContext.getContext().get("sharedState");
state.put("tool.latency.ms", 78);
return "finished";
}
This workaround works but has significant downsides:
- Requires repetitive boilerplate for every prompt invocation.
- No type‑safety, relies on raw Object casts and string keys.
- Easy to make mistakes: if developer forgets to inject identical reference to both contexts, state sharing silently breaks with no warning.
- No discoverable framework API; developers have to invent this pattern themselves.
Related references
- #4079: Advisor context feature (external context passing to advisors, does not cover tool‑advisor sharing)
- #4997: Tool execution moved into advisor layer, makes this feature technically feasible, but advisor context is still not exposed to tool functions.
Note: Parallel tool‑calling thread‑safety must be considered for any mutable context exposed to tool functions.
中文翻译 Chinese Translation
期望行为(Expected Behavior)
工具函数在执行期间应当可以读取、写入 advisor 的 ChatClientRequest.context()。
理想编码示例(方案A:通过 ToolContext API 暴露 advisor 上下文):
@Tool
public String queryDatabase(ToolContext toolContext) {
// 读取 advisor 链传递过来的上下文数据
String tenantId = (String) toolContext.getAdvisorContext().get("tenantId");
// 将工具运行状态写回 advisor 上下文,供后续 advisor after() 使用
toolContext.getAdvisorContext().put("tool.db.execution.ms", 120L);
return "query result";
}
工具执行完成后,工具写入 advisor context 的数据,能够在后续 advisor 的 after() 回调中可见。
其他可接受方案:
- 提供内置双向同步 Advisor,自动双向同步
request.context()和request.toolContext()指定 key。 - 在 Advisor 层提供工具生命周期钩子
onToolStart/onToolComplete,同时暴露ChatClientRequest和工具执行结果。
当前行为(Current Behavior)
Spring AI 2.0 存在两套完全隔离的上下文容器:
ChatClientRequest.context():Advisor 链上下文,仅能在 Advisor 的before()/after()访问;工具函数完全无法读取。ChatClientRequest.toolContext():传递给工具函数的是一份快照;工具内部修改不会回流原始ChatClientRequest。
框架原生没有能力实现:
- 工具读取 Advisor 设置的状态;
- 工具运行时产生状态回传给 Advisor 链,用于日志、指标、Agent 状态管理。
背景说明(Context)
使用场景
我正在开发横跨 Advisor 和工具调用的 Agent 与可观测能力:
- 将 trace、租户信息从 Advisor 层透传到每一次工具调用;
- 在工具内部采集运行元数据(耗时、业务指标),交由下游 Advisor 做聚合、落库;
- 构建多步 Agent,工具执行需要向 Advisor 链回传状态变更。
当前变通方案
现有的唯一方案:手动创建线程安全可变容器 ConcurrentHashMap,把同一个对象引用同时放入 request.context() 和 request.toolContext()。
该方案存在明显缺陷:
- 每次调用 Prompt 都需要重复样板代码;
- 无类型安全,强制类型转换 + 字符串 key;
- 极易出错:漏放任意一处,上下文共享静默失效,无报错提示;
- 不属于框架公开API,开发者需要自己摸索这套模式。
相关 Issue
- #4079:Advisor context,解决外部传入上下文到 Advisor,未覆盖工具‑Advisor互通;
- #4997:工具执行逻辑迁移到 Advisor 层,为本特性提供实现基础,但尚未把 advisor context 暴露给工具。
注意:开放可变上下文给工具,需要考虑并行工具调用场景下的线程安全问题。
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the ToolContext and ChatClientRequest context/toolContext entry points through advisor before() and after() callbacks, including the related designs in issues #4079 and #4997. Define and validate one context-sharing approach, including write-back visibility after tool execution and behavior for parallel tool calls; done means the selected API and its semantics are covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- ai, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100