[Bug]: `FunctionTool` turns an empty list result into empty content instead of `[]`

这个报错通常出现在用 FunctionTool 包装“可能返回空列表”的函数(例如分页查询、筛选、搜索类工具)并通过 agent 调用时:函数确实返回了 [] ,但工具输出里 content 变成空字符串 '' ,模型看到的是“无内容”而不是“空数组”。优先排查 FunctionTool._pars

快速结论:这个报错通常出现在用 FunctionTool 包装“可能返回空列表”的函数(例如分页查询、筛选、搜索类工具)并通过 agent 调用时:函数确实返回了 [],但工具输出里 content 变成空字符串 '',模型看到的是“无内容”而不是“空数组”。优先排查 FunctionTool._parse_tool_output 对空列表的处理逻辑。

适用环境:Issue 中已确认:llama-index-core 0.14.25,以及 main 分支 619d746;Python 3.12;Linux。Issue 正文未提供 CUDA、PyTorch、显卡信息。

最快修复方案:暂无确认的一步修复方案(Issue 讨论中给出的 callback 写法属于绕过手段,不是代码层修复)。

注意事项:该问题同时影响同步 call() 和异步 acall();如果只改一个列表分支,BaseNode/Document 列表分支仍可能把 [] 解析为零个内容块,因此需要两个分支都加非空判断,或在两个分支之前显式处理空列表。回归测试应覆盖同步与异步两条路径。

问题场景

用户用 FunctionTool.from_defaults() 定义了一个返回 list 的工具(示例中为返回 list(range(n))),并通过 agent 调用该工具。当函数返回非空列表如 [0, 1] 时,工具输出被正确序列化为 "[0, 1]";但当返回空列表 [] 时,ToolOutput.content 变成空字符串,导致 agent 无法区分“工具返回了空数组”和“工具没有返回内容”。

报错原文

[Bug]: `FunctionTool` turns an empty list result into empty content instead of `[]`

'' '[0, 1]'

原因分析

FunctionTool._parse_tool_output 在判断 raw_output 是否为内容块列表时使用了 all(isinstance(item, ...) for item in raw_output)。对空列表而言,all(...) 的返回值恒为 True,于是 [] 进入“内容块列表”分支,被解析成零个内容块,最终 content 为 "";而 [0, 1] 不满足该判断,落到常规列表序列化,得到 "[0, 1]"。Issue 讨论还指出,后续的 BaseNode/Document 列表分支同样使用 all(...),存在相同的空列表穿透问题,因此只给第一个分支加非空判断并不够。

环境排查

  • 确认 llama-index-core 版本:Issue 中复现于 0.14.25 及 main 分支 619d746,请比对当前版本是否仍包含旧逻辑。
  • 确认 Python 版本(Issue 为 3.12)。
  • 确认工具函数是否可能返回空列表,或返回由列表组成的结果(如内容块列表、BaseNode/Document 列表)。
  • 确认触发路径是同步 call() 还是异步 acall(),两者都走同一解析器。
  • Issue 未提供 CUDA、PyTorch、显卡相关信息,无需按这些项排查。

解决步骤

  1. 先用 Issue 中的最小复现脚本确认现象:定义返回 list(range(n)) 的 FunctionTool,打印 tool.call(n=0).content 与 tool.call(n=2).content,若分别得到 '' 与 '[0, 1]',即命中此问题。
  2. 临时绕过(可优先尝试):不改动原函数,通过 callback 覆盖展示内容,仅在结果为列表且为空时返回字符串 "[]",其余情况返回 None 以保留默认行为。字符串回调结果会覆盖显示内容,但原始 raw_output 保留;同步回调同样适用于异步调用。
  3. 如需根治:检查 _parse_tool_output 中两个列表分支的 all(...) 判断,改为要求列表非空(例如 bool(raw_output) and all(...)),或在两个分支之前先显式处理空列表;注意不要只改第一个分支。
  4. 若已升级到包含修复的版本,直接验证修复效果即可,无需保留 callback 绕过。

验证方法

重新运行最小复现脚本,确认 tool.call(n=0).content 输出为 '[]',tool.call(n=2).content 仍为 '[0, 1]';再对异步 acall() 做同样断言,确保同步与异步路径行为一致。使用 callback 绕过时,还需确认传参非空列表和标量返回值的结果未被改变。

参考来源

run-llama/llama_index #23862

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 31716

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注