Skip to content

Commit 9b105d1

Browse files
committed
fix: refine tool call handling and improve logging for missing tool IDs
--bug=1066032@tapd-62980211 --user=刘瑞斌 【技能】工作流中的AI对话节点调用工具技能时,入参显示为空 https://www.tapd.cn/62980211/s/1840607
1 parent 1491b24 commit 9b105d1

File tree

1 file changed

+28
-24
lines changed

1 file changed

+28
-24
lines changed

apps/application/flow/tools.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
323323
response = agent.astream({"messages": message_list}, config={"recursion_limit": recursion_limit},
324324
stream_mode='messages')
325325

326-
# 用于存储工具调用信息(按 tool_id)以及按 index 聚合分片
327-
tool_calls_info = {}
328-
_tool_fragments = {} # index -> {'id':..., 'name':..., 'arguments':...}
326+
# 用于存储工具调用信息
327+
tool_calls_info = {} # tool_id -> {'name': ..., 'input': ...}
328+
_tool_fragments = {} # index -> {'id': ..., 'name': ..., 'arguments': ...}
329329

330330
async for chunk in response:
331331
if isinstance(chunk[0], AIMessageChunk):
@@ -334,21 +334,21 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
334334
idx = tool_call.get('index')
335335
if idx is None:
336336
continue
337+
337338
entry = _tool_fragments.setdefault(idx, {'id': '', 'name': '', 'arguments': ''})
338339

339-
# 更新 id 与 name(如果有)
340+
# 更新 id
340341
if tool_call.get('id'):
341342
entry['id'] = tool_call.get('id')
342343

344+
# 更新 name 和 arguments
343345
func = tool_call.get('function', {})
344-
# arguments 可能在 function.arguments 或顶层 arguments
345-
part_args = ''
346-
if isinstance(func, dict) and 'arguments' in func:
347-
part_args = func.get('arguments') or ''
346+
if isinstance(func, dict):
348347
if func.get('name'):
349348
entry['name'] = func.get('name')
349+
part_args = func.get('arguments', '')
350350
else:
351-
part_args = tool_call.get('arguments', '') or ''
351+
part_args = tool_call.get('arguments', '')
352352

353353
# 统一为字符串
354354
if not isinstance(part_args, str):
@@ -359,27 +359,27 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
359359

360360
entry['arguments'] += part_args
361361

362-
# 若 arguments 为空字符串,替换为 '{}'
363-
if entry['arguments'] == '':
364-
entry['arguments'] = '{}'
365-
366-
# 尝试判断 JSON 是否完整(若 arguments 是 JSON),完整则提交到 tool_calls_info
367-
try:
368-
json.loads(entry['arguments'])
369-
if entry['id']:
362+
# 尝试解析 JSON,判断是否完整
363+
if entry['id'] and entry['arguments']:
364+
try:
365+
json.loads(entry['arguments'])
366+
# JSON 完整,保存到 tool_calls_info
370367
tool_calls_info[entry['id']] = {
371-
'name': entry.get('name', ''),
368+
'name': entry['name'],
372369
'input': entry['arguments']
373370
}
374-
_tool_fragments.pop(idx, None)
375-
except Exception:
376-
# 如果不是完整 JSON,继续等待后续片段
377-
pass
371+
# 从 fragments 中移除
372+
del _tool_fragments[idx]
373+
except (json.JSONDecodeError, ValueError):
374+
# JSON 不完整,继续等待
375+
pass
378376

379377
yield chunk[0]
380378

381379
if mcp_output_enable and isinstance(chunk[0], ToolMessage):
382-
tool_id = _extract_tool_id(chunk[0].tool_call_id)
380+
# 直接使用 tool_call_id,不进行提取
381+
tool_id = chunk[0].tool_call_id
382+
383383
if tool_id in tool_calls_info:
384384
tool_info = tool_calls_info[tool_id]
385385
content = generate_tool_message_complete(
@@ -388,10 +388,14 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
388388
chunk[0].content
389389
)
390390
chunk[0].content = content
391+
else:
392+
# 如果找不到对应的工具信息,记录日志
393+
maxkb_logger.warning(
394+
f"Tool ID {tool_id} not found in tool_calls_info. Available IDs: {list(tool_calls_info.keys())}")
395+
391396
yield chunk[0]
392397

393398
except ExceptionGroup as eg:
394-
395399
def get_real_error(exc):
396400
if isinstance(exc, ExceptionGroup):
397401
return get_real_error(exc.exceptions[0])

0 commit comments

Comments
 (0)