深入分析tool_choice循环陷阱、max_iterations误解、Oracle langchain补丁等Agent工程实际问题,含具体复现次数和阈值数字。
Reddit 和 GitHub Issues 上的 Agent 讨论已经变了。一年前的主题是"Agent 能做什么",现在变成了"为什么我的 Agent 调用同一个工具 19 次"以及"8 月 26 日之后我的线程会怎样"。
以下是会反复出现的五个问题,每个都附有我挖出来的具体事实。每一个都关联着一个数字,因为"视情况而定"不是能交付的答案。
大家给的建议都是设置 max_iterations。这能控制账单,但修复不了 bug。
当你把 tool_choice 设置为 required 或指定某个函数名时,这个设置会在模型调用之间持久化。你的框架运行工具、返回结果,同样的强制设置会一路跟随。模型再次被告知必须调用某个工具。它照做了。这就是循环。
openai-agents-python 中的合并修复在工具执行后将 tool_choice 重置为 auto。所以第一步是升级,而不是写护栏代码。
第二步几乎没人做。循环不是"很多次调用"——而是相同的调用。Oracle 的 langchain-oracle patch 通过匹配工具名和连续相同参数来检测重复,并提供了一个默认为 8 的 max_sequential_tool_calls 后备方案。他们早期的修复在任何工具结果返回后将 tool_choice 设置为 none,这确实阻止了循环,但也破坏了一个四步诊断 Agent 在其第一次调用之后的行为。
迭代计数器无法区分六步工作流和六步循环。参数身份可以。
完整分析:你的 Agent 永远循环。问题很可能出在 tool_choice。
如果你仍在使用 /v1/threads,你只有几天时间,而不是几个月。OpenAI 的弃用页面将移除日期定在 2026 年 8 月 26 日,也就是通知发出后一年。没有降级模式,没有宽限期。
迁移本身很小。Assistant 变成 Prompt,Thread 变成 Conversation,Run 变成 Response,Run step 变成 Item,create-then-poll 循环压缩成单个 responses.create 调用。
真正会咬人的是迁移指南中的一句话:OpenAI 不会提供将 Threads 迁移到 Conversations 的自动化工具。如果你的产品展示聊天历史,那这些历史是用户可见的数据,位于别人服务器上,架设在一个不再响应的端点之后。
这周就导出原始 JSON,即使你还没选定目标格式。导出的数据可以等待;删除的数据不能。
让我惊讶的两件事:向量存储和文件在切换后保留,只需将 vector_store_ids 传给文件搜索工具——但线程创建的存储在最后一次使用后七天内过期,所以其中一半已经消失了。Azure 的截止日期相同但目的地不同:微软的文档指引 Azure 用户去 Foundry Agents,而不是 Responses API。
完整分析:Assistants API 于 8 月 26 日关闭。现在就迁移。
直接引自 AutoGen README:"AutoGen 现在处于维护模式。它不会获得新功能或增强,未来的管理由社区负责。"
Microsoft Agent Framework 是后继者,由与 AutoGen 和 Semantic Kernel 合并的相同团队构建。单个 Agent 一个下午就能迁移。多 Agent 团队不行,因为 AutoGen 的事件驱动 Team 变成了你需要声明边的基于类型的图 Workflow。你重画流程而不是翻译它。
两个变化完全不会抛出错误。Agent 是无状态的,不像 AssistantAgent 那样在调用之间保留历史——你的代码运行了,你的 Agent 忘记了上一轮,你附加 AgentSession 来修复它。而且 Agent 现在会持续调用工具直到任务完成,而不是在你设定的计数后停止,这对简单任务更友好,但对定价来说更难。
在规划之前先检查你的模型提供商。微软自己的页面说法不一致:迁移指南列出 Anthropic 和 Ollama 客户端为计划支持,而更新的概述页面列出两者都支持。在你投入一个 Sprint 之前,先对你的实际提供商跑一个 spike 测试。
完整分析:AutoGen 处于维护模式。现在迁移到哪里。
Agent 记忆被当作存储问题来处理——选一个向量存储,窗口填满时做摘要。这忽略了账单。
缓存是前缀匹配。记忆想待在提示词的高处,靠近系统指令,那正是请求中编辑成本最高的地方。Anthropic 的缓存参考给出了数字:缓存读取费用是基础输入的 0.1 倍,五分钟写入是 1.25 倍,一小时写入是 2 倍。把一次读取换成五分钟写入,同样的 tokens 成本是 12.5 倍。
还有一个没人提的底限。最小可缓存前缀在 Opus 5 上是 512 tokens,在 Sonnet 5 上是 1,024,在 Haiku 4.5 上是 4,096。达不到这个门槛不会报错——请求只是不会被缓存,你会从账单上发现它。这就是为什么把廉价的后台摘要路由到小模型往往帮不上忙。
另一个有用的区分:清理不等于摘要。上下文编辑按顺序删除旧的工具结果并就地换入占位符,默认为 100,000 tokens 触发阈值,同时保留最后三次工具使用。它不花额外的模型调用,保持对话形态。压缩需要一次调用,将历史重写为叙述文,并永久丢失摘要器认为不重要的东西。对于使用工具密集的 Agent,主体是旧的工具输出——先清理那个。
完整分析:不会搞砸提示词缓存的 Agent 记忆。
LangChain 的 Agent 工程状态调查(1,340 份回复,2025 年末)发现 89% 的组织有 Agent 可观测性,52.4% 运行离线评估。大多数团队能看到失败,但无法先一步捕获。
有趣的是为什么有门禁的团队仍然漏掉东西。2026 年 6 月的一篇关于层隔离评估的论文一次破坏一个 Agent 层然后观察指标。总体通过率移动了 1.7 到 5.9 个百分点。匹配被破坏层的测试切片移动了 25 到 91 个百分点。
把它当作发布门禁来理解。破坏你的路由层,端到端套件报告几个点的噪声——你会批准发布。按层切片,它在尖叫。
便宜的修复是 Agent 的大部分是普通软件。路由规则、Schema 验证、升级阈值、记忆写入:这些都不是非确定性的。同篇论文的套件是 238 个案例横跨 23 个切片,其中 225 个在 2.39 秒内运行完毕,完全没有模型调用。先构建那一层,把 Judge 留给真正需要的地方。
如果你确实用 Judge,按对比校准。2026 年 5 月的一项研究表明,在你比较的模型之间共享一个校准可以反转结果的符号——你交付了更差的 Agent,而报告显示你交付了更好的。
完整分析:89% 观察 Agent 失败。只有一半在发布前测试。
这五个中有四个是同一形态:默认值变了,或者设置持久化了,但没有任何错误抛出。粘性的 tool_choice、无状态的 Agent、未缓存的前缀、被平均掉的回归。Agent 静默失败远比崩溃常见,这就是为什么修复大多关于让失败可见,而不是让模型更聪明。
如果你遇到了其中一个并用不同方式解决了,我真的很想听听——特别是参数身份循环检查,感觉应该有更多框架默认提供。