[Bug] 同一轮对话内第二次调用同一工具,LLM 未传的参数残留为上一次调用的值(v4.14.2~v4.16.2 复现)
- Dominant language
- TypeScript
- Stars
- 29.6k
- Forks
- 7.3k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 152
Description
## 问题描述
在同一个聊天交互(一次对话的 agent 循环)内,当 LLM 第二次调用同一个工具节点(实测 MCP 工具,普通插件/workflow tool 走同一路径),且第二次的 `tool_calls.arguments` 省略了某些参数时,这些参数**没有回退到节点配置的默认值,而是残留为第一次调用写入的值**,并被原样发送给工具服务端。
## 复现版本
- v4.14.2 ✅ 复现
- v4.15.1 ✅ 复现
- v4.16.2 ✅ 复现(截至最新发布版仍存在)
## 复现步骤
1. 给 agent / 工具调用节点配置一个 MCP 工具,参数包含多个可选字段(例如 `query` + `filter`)
2. 一轮对话中让 LLM 先以 `{query: "A", filter: "x"}` 调用该工具
3. 继续对话,让 LLM 再次调用同一工具,且第二次只传 `{query: "B"}`
4. 对比 chat 详情中 LLM 的 `tool_calls.arguments` 与工具节点实际发出的 `toolInput`(或 MCP 服务端收到的请求):第二次实际发送的是 `{query: "B", filter: "x"}` —— `filter` 残留了第一次的值,而 LLM 本次并没有传它
## 根因分析(基于 v4.16.2 源码核对)
**环节 1:每次工具执行都在共享的 runtimeNodes 上原地修改节点 inputs**
`packages/service/core/workflow/dispatch/ai/agentLoopCore/application/runtime/workflowToolRunner.ts` L114-133,`initAgentLoopCoreWorkflowToolNodes` 直接执行 `node.inputs = updateAgentLoopCoreWorkflowToolInputValue(...)`,且 `runTool` 每次调用都会执行(L353-355)。
**环节 2:LLM 未传的 key 回退到 `input.value`(已被上一轮污染)**
同文件 L78-85:
```ts
const hasAgentGeneratedValue = Object.prototype.hasOwnProperty.call(mergedParams, input.key);
return {
...input,
value: hasAgentGeneratedValue ? (mergedParams[input.key] ?? input.value) : input.value
};
```
LLM 本次没传的 agent 生成参数不在 `mergedParams` 中 → 落入 `: input.value` 分支 → 沿用的是**上一次调用写入的值**,而非节点配置的默认值。
该文件 L313-314 的注释也承认了这一架构问题:
```
已知问题:普通 Workflow Tool 的首次执行和交互恢复都会复用并修改父流程的 runtime graph。
当前保留原有状态传递行为,后续需要通过子流程快照和显式同步完成隔离。
```
**环节 3:MCP 分支把节点全部 inputs 发送给服务端**
`packages/service/core/workflow/dispatch/child/runTool.ts` L300-302:
```ts
toolInput = params;
assertToolRuntimeParams({ jsonSchema: mcpTool?.inputSchema, params });
const result = await mcpClient.toolCall({ toolName, params, closeConnection: false });
```
残留值能通过 ajv 校验(它们本来就是上一次的合法值),最终被原样发给 MCP 服务端。
## 预期行为
LLM 未传的参数应回退到节点配置的默认值(或视为未提供),而不是上一次调用的值。
## 修复建议
- 按注释中已规划的方向:`runTool` 每次执行使用子图快照(深拷贝副本),不再原地修改共享 runtimeNodes;
- 或最小修复:agent 生成模式下,LLM 未传的 key 显式置 `undefined` / 不发送给工具端。
## 备注
- v4.16.x 已引入 agent 生成/固定值双模式和 `mergeToolRuntimeParams` 白名单(LLM 无法再注入任意 key),但"未传 key 残留上次值"的行为被完整保留;
- 已检索 issues / discussions,未发现同症状报告。
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with packages/service/core/workflow/dispatch/ai/agentLoopCore/application/runtime/workflowToolRunner.ts, tracing initAgentLoopCoreWorkflowToolNodes and runTool, then inspect packages/service/core/workflow/dispatch/child/runTool.ts. Reproduce the two-call MCP scenario and verify that an omitted parameter in the second call is no longer inherited from the first call while the tool receives the configured default or no value.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- ai, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100