AI Agent 如何处理工具调用返回超大结果的问题?有哪些实用的解决方案?

魏远标 Lv7

参考答案

Agent 调用工具时,返回结果可能远超预期,比如查数据库吐出上千条记录、搜代码返回整个文件、调 API 拿到一个几十 KB 的 JSON。这些超大结果直接塞进上下文窗口,轻则浪费 token 拉高延迟和成本,重则直接撑爆上下文让后续推理崩掉。

解决方案分三个阶段:事前控制、事中截断、事后摘要

事前控制最高效,在调用工具之前就限死返回数据的规模。数据库查询自动加 LIMIT,搜索接口限制返回条数,API 请求只拿需要的字段。关键在于工具设计阶段就把 limit、fields 这些参数暴露出来,让 Agent 能主动控制粒度。

事中截断是在工具返回后、送入模型前做裁剪。简单粗暴的按 token 数砍,聪明点的做法是结构化截断,比如保留前几条记录当样本,附上总数和统计信息,让模型知道全貌。

事后摘要是额外调一次 LLM 把大结果压缩成关键信息。信息保留度最高,但多了一次 LLM 调用的开销。适合结果虽大但关键细节不能丢的场景,比如分析一份完整的错误日志。

扩展知识

分页加载策略

对于数据库查询、文件列表这类天然支持分页的数据源,最优雅的方案是让 Agent 学会翻页。工具设计时支持 offset 和 limit 参数,Agent 先查第一页了解大概情况,然后根据需要决定是否继续往下翻。

1
2
3
4
5
6
7
8
9
10
11
12
13
14


python

复制代码

def search_database(query: str, limit: int = 20, offset: int = 0):
"""搜索数据库,默认返回 20 条,支持翻页"""
results = db.execute(query, limit=limit, offset=offset)
return {
"data": results,
"total_count": db.count(query),
"has_more": offset + limit < db.count(query)
}

这种方式让 Agent 自己决定需要看多少数据,既不会一次性灌入过多信息,又保留了按需获取更多细节的能力。像 Cursor 的 Agent 模式在搜索代码时就是这么做的,默认只返回前 20 个匹配结果,Agent 觉得不够再继续翻。

结构化截断的技巧

截断不是简单砍掉后面的内容,而是保留对模型有用的”元信息”。一个好的截断结果包含三样东西:前几条完整记录让模型理解数据结构、总记录数让模型知道规模、关键统计信息帮助决策。

比如原始结果有 5000 条用户数据,截断后变成:

1
2
3
4
5
6
7
8
9
10


text

复制代码

查询返回 5000 条记录,以下是前 5 条示例:
[前 5 条完整数据]
...
统计:平均年龄 28.5 岁,男女比例 6:4,最活跃城市前三:北京、上海、深圳

模型拿到这个,既了解了数据的结构,也掌握了整体分布,后续分析和决策就有足够的上下文了。

引用机制与按需读取

更高级的方案是引入引用机制。工具返回的大结果不塞进上下文,而是存到一个临时存储里,只给模型一个引用 ID 和摘要。模型需要查看某个特定部分的详细内容,再通过引用 ID 去取。

这跟 MCP 协议中的 Resources 概念一个思路:把大数据变成按需读取的资源,而不是一股脑推送到模型面前。OpenAI 的 Assistants API 里的 file_search 工具也是类似逻辑,搜索结果先存起来,模型通过 annotation 引用具体片段。

多级压缩策略

实际生产环境中,上面几种方案往往组合使用,形成多级压缩管线:

1)第一级:工具层面的参数控制,limit 设成 100 条

2)第二级:返回后做结构化截断,只保留前 10 条样本加统计摘要

3)第三级:如果截断后仍然超过 token 预算,再用一次 LLM 做语义压缩

每一级的 token 阈值可以根据模型的上下文窗口大小动态计算。比如模型 A 有 128K 上下文,可以给工具结果留 20K 的预算;模型 B 有 200K 上下文,可以宽裕一些给到 40K。

流式处理与提前终止

还有一种思路是流式处理。工具不一次性返回全部结果,而是流式输出,Agent 边看边判断。

一旦找到需要的信息就提前终止,不用等全部数据跑完。这在搜索场景特别有用,Agent 搜代码找 bug,可能看到第 3 条结果就定位到问题了,后面 97 条压根不用看。

LangChain 的 Tool 抽象里有个 return_direct 选项可以配合使用,Anthropic 的 tool_use 也支持在 streaming 模式下让模型决定是否继续接收后续 chunk。

面试官追问

提问:如果 Agent 需要对超大结果做聚合分析,比如统计平均值、找最大最小值,截断和摘要都会丢信息,怎么处理?

回答:最靠谱的做法是把聚合逻辑下推到工具层。因为让 Agent 拿到全部数据再自己算,不如在工具里直接支持聚合查询参数,比如 SQL 工具支持 GROUP BY 和 AVG/MAX/MIN,搜索工具支持 facet 聚合。Agent 只需要构造出正确的聚合查询,拿到的就是精简的统计结果而不是原始大表。

提问:事后摘要用的 LLM 和主推理用的 LLM 需要是同一个模型吗?有什么考量?

回答:不需要,而且通常不应该是同一个。摘要任务相对简单,用一个便宜快速的小模型就够了,比如主推理用 Claude Opus 4.6,摘要压缩用 Claude Haiku 就行。这样既省成本又降低延迟。但要注意小模型的上下文窗口可能更短,如果待摘要的内容本身就很长,可能需要先做一次机械截断再送去摘要。

提问:分页方案在实际中有没有什么坑?Agent 会不会陷入无限翻页的循环?

回答:会的,这是个常见问题。Agent 有时候不知道什么时候该停,会一直翻页直到把所有页都看完。解决办法是在系统 prompt 里明确告诉它翻页预算,比如”最多翻 3 页,如果 3 页内找不到答案就用已有信息回答”。另外工具返回的 total_count 也很关键,Agent 看到总共 50000 条记录,自然会意识到不可能全看完,被迫换策略。

目录
AI Agent 如何处理工具调用返回超大结果的问题?有哪些实用的解决方案?