当前位置: 首页 > article >正文

[Deep Agents:LangChain的Agent Harness-07]利用PatchToolCallsMiddleware修复错乱的消息结构

作为LLM提示词的一个重要组成部分表示对话历史的消息列表在结构上有一个基本的要求如果LLM返回的AIMessage包含ToolCall对象那么Agent会期望每个ToolCall对象都有对应的ToolMessage。但是Agent在执行过程会因为一些异常导致LLM返回的AIMessage中的ToolCall对象没有得到正确的处理最终导致后续的消息列表中缺失了对应的ToolMessage。PatchToolCallsMiddleware就在面临这种情况是提供了一种补救机制自动创建并添加缺失的ToolMessage。1. ReAct工作模式导致的对话历史的交替结构作为Agent对话历史的消息列表之所以具有确定的结构是源于Agent基于ReAct的工作模式。ReActReasoning and Acting是一种让大语言模型LLM将推理与行动相结合的交互模式。它解决了模型空谈不干活只推理不调用工具或盲目干活只调工具不分析原因的问题。ReAct的核心是一个循环过程通常被称为Thought-Action-Observation循环Thought推理模型先写下当前的思考分析任务目标、目前的进度以及下一步需要做什么Action行动模型根据推理结果决定调用哪个工具如搜索、计算器、API并给出参数Observation观察系统执行工具后将结果反馈给模型循环模型根据“观察”到的结果开始新一轮的 Thought直到得出最终答案create_agent函数创建的Agent由model和tools两个核心节点组成model节点负责生成推理内容和生成工具调用tools节点则负责执行工具调用并返回结果。消息列表是Agent状态的核心成员ReAct模式清晰地体现在Agent的执行流程上当用户指定输入调用Agent时model节点生成提示词调用LLM这里的提示词包括封装了用户输入的消息列表用户可以输入描述任务的文本此时生成的消息列表中会包含一个HumanMessage对象用户也可以输入一个消息列表来模拟一段对话、工具集描述和系统指令提示词。经过LLM的推理如果它觉得此时能够提供最终的答案它会将答案封装成一个AIMessage对象返回如果它觉得还需要调用工具来获取更多信息或进行计算它会在生成的AIMessage对象中包含一个或多个ToolCall对象来调用工具Agent会将接收到的AIMessage对象添加到消息列表中。如果此AIMessage的ToolCall列表为空执行流程到此结束否则Agent会根据工具调用的信息来调用tools节点执行工具。相关的工具以并发形式的执行后执行的结果会以ToolMessage的形式被添加到消息列表中。即使工具返回的是一个Command对象也明确要求它必需返回一个ToolMessage对象来描述工具调用的结果包含ToolMessage的消息列表会被再次提交给model节点进入下一轮的推理循环。这就决定了在一个推理步骤结束时作为对话历史的消息应该具有这样的结构如果某条AIMessage中包含了一个或多个ToolCall对象那么在消息列表中必须有对应的一个或多个ToolMessage来描述工具调用的结果每条ToolMessage必须包含一个tool_call_id字段来与对应的ToolCall进行匹配以保证消息列表的结构完整性;2. 对话历史的结构为何会被破坏在 ReAct 模式中消息列表的严格交替结构Assistant提议 - Tool执行 - Assistant总结是其逻辑闭环的基础以下是导致结构破坏的常见原因并发调用与乱序返回模型一次性发出了三个工具调用Action A, B, C但外部执行环境返回结果的顺序变成了 B, A, C。如果直接按接收顺序插入消息列表而没有与其对应的tool_call_id严格匹配模型会把B的结果当成A的反馈强制插入用户干预在模型发出Action之后、Tool返回结果之前用户突然又发了一条新消息如“算了别查了换个任务”。这会导致 Assistant (Action) 后面直接跟了一个 User 消息中间缺失了必要的 Tool 响应溢出导致的截断由于ReAct循环非常多历史记录太长开发者简单粗暴地删除了中间的某些消息。如果删除了某个 Tool 消息但保留了后面基于该工具结果做的 Thought逻辑链条就会出现断层模型解析失败模型由于幻觉或受干扰没有输出预定的 Action 格式而是直接输出了乱码。系统无法提取出 Action导致流程卡死在 Assistant 这一步无法触发后续的 Tool 消息3. 错乱消息结构导致的问题ReAct模式的循环特性决定了消息列表的具有上述的交替结构而这种消息结构也反映了LLM过去的推理流程并用以指导后续的推理。一旦这种链条断裂模型就会陷入逻辑精神分裂,会产生以下后果逻辑幻觉 (Hallucination)模型会试图脑补缺失的Observation。如果它提出了查询请求但没收到结果它可能会根据训练数据编造一个虚假的结果并以此为基础继续推理;无限递归循环 (Infinite Loop)模型发现上一个Action没有对应的Observation它会认为我刚才没做成于是再次发出同样的Action。如果系统逻辑不健壮会陷入请求-等待-再次请求的死循环极快地消耗Token;拒绝执行 (Model Refusal)现代对齐后的模型如GPT-4对上下文一致性有要求。如果AIMessage消息包含ToolCall但紧接着不是ToolMessageAPI 往往会直接报错导致程序崩溃因果倒置 (Causal Confusion)如果Observation错位模型会基于错误的前提得出结论。例如搜索“A 的股价”结果返回了“B 的股价”模型会非常自信地告诉你 A 涨了实际上是B涨了4. 利用PatchToolCallsMiddleware修补错乱的消息结构我们利用下面这个实例来演示一下PatchToolCallsMiddleware针对对话历史的修补功能。我们创建了一个Agent并注册了一个工具get_weather用于获取天气信息。我们在调用Agent的时候构造了一个AIMessage其中包含了一个针对get_weather工具的ToolCall对象但是我们没有提供对应的ToolMessage。fromlangchain.agentsimportcreate_agentfromdeepagents.middleware.patch_tool_callsimportPatchToolCallsMiddlewarefromlangchain.toolsimporttoolfromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportHumanMessage,AIMessage,ToolCallfromdotenvimportload_dotenvimportasyncio load_dotenv()tooldefget_weather(location:str)-str:Get the current weather for a given location.returnfThe current weather in{location}is sunny with a high of 25°C.agentcreate_agent(modelChatOpenAI(modelgpt-5.2-chat),tools[get_weather],middleware[PatchToolCallsMiddleware()])human_messageHumanMessage(contentWhats the weather like in Suzhou today?)ai_messageAIMessage(content)tool_call:ToolCall{id:tool_call_1,name:get_weather,args:{location:Suzhou}}ai_message.tool_calls.append(tool_call)asyncdefmain():resultawaitagent.ainvoke(input{messages:[human_message,ai_message]})formessageinresult[messages]:message.pretty_print()asyncio.run(main())注册的PatchToolCallsMiddleware会自动检测到这个问题并且为这个ToolCall对象创建一个对应的ToolMessage。虽然这个ToolMessage中的内容会使用预定义的模板来生成但它至少保证了消息列表的结构完整性使得Agent可以继续执行后续的推理和行动。在如下所示的对话列表中出现的第一个ToolMessage就是PatchToolCallsMiddleware自动创建的。 Human Message Whats the weather like in Suzhou today? Ai Message Tool Calls: get_weather (tool_call_1) Call ID: tool_call_1 Args: location: Suzhou Tool Message Name: get_weather Tool call get_weather with id tool_call_1 was cancelled - another message came in before it could be completed. Ai Message Tool Calls: get_weather (call_Exlkyg84lyVTMvOEfGuzgu6N) Call ID: call_Exlkyg84lyVTMvOEfGuzgu6N Args: location: Suzhou, China Tool Message Name: get_weather The current weather in Suzhou, China is sunny with a high of 25°C. Ai Message Today in **Suzhou, China**, the weather is **sunny** with a **high around 25 °C (77 °F)**. It should be a pleasant day overall—great for being outdoors.PatchToolCallsMiddleware的实现非常简单它通过重写before_agent/after_agent方法来检测AIMessage中的ToolCall对象并且在发现缺失对应的ToolMessage时自动创建一个新的ToolMessage来进行补充。这个新创建的ToolMessage会使用一个预定义的模板来生成内容。classPatchToolCallsMiddleware(AgentMiddleware):defbefore_agent(self,state:AgentState,runtime:Runtime[Any])-dict[str,Any]|None

相关文章:

[Deep Agents:LangChain的Agent Harness-07]利用PatchToolCallsMiddleware修复错乱的消息结构

作为LLM提示词的一个重要组成部分,表示对话历史的消息列表在结构上有一个基本的要求:如果LLM返回的AIMessage包含ToolCall对象,那么Agent会期望每个ToolCall对象都有对应的ToolMessage。但是Agent在执行过程会因为一些异常导致LLM返回的AIMes…...

Godot任务系统设计:数据驱动与事件驱动的游戏任务框架

1. 项目概述:为Godot游戏注入灵魂的“任务系统”如果你用Godot引擎做过游戏,尤其是RPG、冒险或者任何需要引导玩家推进流程的类型,你肯定琢磨过一件事:怎么搞一个靠谱的任务系统?是硬编码一堆if-else判断任务状态&…...

基于Git日志与AI的开发者行为画像分析工具设计与实现

1. 项目概述:当Git仓库遇上AI侦探在团队协作开发中,信息不对称是常态。你经常听到“我在推进中”,但没人知道推进的究竟是核心功能,还是午休后的咖啡。当线上出现一个棘手的Bug时,git blame命令那冰冷的输出&#xff0…...

AI知识库构建实战:从RAG原理到工程化实现

1. 项目概述:一个面向AI的知识库构建方案最近在GitHub上看到一个挺有意思的项目,叫mcglothi/ai-knowledge-base。乍一看名字,你可能会觉得这又是一个关于如何用AI构建知识库的教程或者工具集。但当我深入去研究它的代码、文档和设计思路后&am…...

Cursor AI 编码规则启动器:模块化配置与工程化实践指南

1. 项目概述:一个为 Cursor 编辑器量身定制的规则启动器如果你和我一样,日常重度依赖 Cursor 这款 AI 驱动的代码编辑器,那你一定对它的“规则”(Rules)功能又爱又恨。爱的是,它能通过预设的指令集&#xf…...

LobsterPress v5.0:为AI Agent构建长期记忆系统的架构与实践

1. 项目概述:为AI Agent构建“数字海马体”如果你和我一样,长期与ChatGPT、Claude这类大语言模型打交道,一定会被一个核心问题困扰:它们记性太差了。无论你昨天花了多少时间与AI深入探讨一个项目细节,今天开启新对话时…...

深入STM32以太网驱动层:DP83848 PHY芯片初始化、中断处理与lwip数据收发的HAL库实现详解

STM32与DP83848以太网驱动开发实战:从PHY初始化到lwIP协议栈深度整合 在嵌入式系统开发中,以太网通信已成为工业控制、物联网网关等场景的标配功能。本文将深入探讨基于STM32F1系列微控制器与DP83848物理层芯片的以太网驱动开发全流程,重点剖…...

多智能体协同AI Coding:Multica、vibe-kanban、Maestro、OpenCove

AI辅助编码系列包括: Vibe Coding、AI IDE/插件Claude Code实战AI IDE/插件(二):Zed、SpecKit、OpenCode、Roo Code、Plandex、Flyde、iFlow CLIAI IDE/插件(三):OpenHands、TaskMaster、DeepCode、cc-swi…...

极简终端AI聊天工具gptcli:单文件Python脚本实现OpenAI API兼容客户端

1. 项目概述:一个极简的终端AI聊天工具如果你和我一样,经常需要在终端里和AI模型对话,但又觉得官方网页版太重、第三方客户端功能太杂,那么这个项目可能就是你的菜。gptcli是一个用单个Python脚本实现的、功能纯粹的终端聊天客户端…...

离线环境下的高效远程开发:手把手搭建VS Code Remote-SSH离线开发环境

1. 为什么需要离线远程开发环境 在不少企业研发场景中,开发机往往处于严格的内网隔离环境。我去年参与过一个军工项目,所有开发设备都禁止连接互联网,第一次遇到这种情况时,传统在线安装方式完全失效,团队花了整整两天…...

嵌入式GUI设计:硬件选型与OpenGL优化实战

1. 嵌入式GUI设计的核心价值与市场驱动力在智能设备爆发的时代,嵌入式图形用户界面(GUI)已经从"锦上添花"变成了"不可或缺"的核心竞争力。我亲历过多个项目,那些仅关注硬件性能而忽视交互体验的产品&#xff…...

AI大模型选型指南:构建开源比较平台的技术实践与架构解析

1. 项目概述:为什么我们需要一个AI模型“选型指南”?最近在GitHub上闲逛,发现了一个挺有意思的项目,叫ai-llm-comparison。光看名字,你大概就能猜到它是干嘛的——一个关于人工智能大语言模型的比较项目。说实话&#…...

App安全测试实战:OWASP ZAP 2.8 代理配置进阶与场景化应用

1. OWASP ZAP 2.8代理配置的核心价值 如果你做过移动应用安全测试,一定遇到过这样的困境:抓不到HTTPS流量、内网环境难以调试、自动化测试时代理频繁断开。这些问题看似简单,实际会浪费大量时间在环境搭建上。我在去年的一次金融App测试中&am…...

网络中心性(Centrality)选型指南:从业务问题出发的指标匹配方法

1. 为什么 centrality 不是“算出来就行”,而是网络分析的命脉所在在 R 里敲下centr_degree(g)或closeness(g),几毫秒就出结果——但如果你真以为这就完成了“节点重要性评估”,那大概率会在后续建模、解释或决策中栽跟头。我带过七届数据科学…...

微信单向好友终极检测指南:如何快速发现谁已悄悄删除或拉黑你

微信单向好友终极检测指南:如何快速发现谁已悄悄删除或拉黑你 【免费下载链接】WechatRealFriends 微信好友关系一键检测,基于微信ipad协议,看看有没有朋友偷偷删掉或者拉黑你 项目地址: https://gitcode.com/gh_mirrors/we/WechatRealFrie…...

告别环境配置噩梦:用Shell脚本一键搞定VCS与Verdi的联调环境

芯片验证工程师的效率革命:Shell脚本全自动构建VCSVerdi联调环境 每次开始新项目都要重复配置验证环境?还在为VCS编译选项和Verdi波形调试的手动操作浪费时间?资深验证工程师的日常,不该被这些重复劳动占据。本文将带你用Shell脚本…...

509-qwen3.5-9b csdn tmux

技术文章大纲:Qwen(通义千问)技术解析与应用实践 Qwen概述 背景与研发团队:阿里巴巴达摩院推出的开源大语言模型系列核心定位:支持多语言、多模态的通用AI助手版本迭代:从Qwen-7B到Qwen-72B的模型规模演进 …...

KV缓存压缩技术:IsoQuant在大语言模型中的应用

1. KV缓存压缩的技术背景与挑战在大语言模型(LLM)的推理过程中,键值(KV)缓存的内存占用已成为制约长上下文处理能力的核心瓶颈。以典型的Llama-2 70B模型为例,当处理32k长度的上下文时,KV缓存需…...

蓝牙技术与FPGA实现:原理、优化与实践

1. 蓝牙技术基础与核心原理蓝牙技术自1994年由爱立信首次提出以来,已成为短距离无线通信领域的事实标准。这项技术之所以能在众多无线方案中脱颖而出,关键在于其独特的物理层设计和灵活的协议架构。1.1 2.4GHz ISM频段特性蓝牙工作在2.4GHz工业、科学和医…...

KMS智能激活终极指南:5分钟永久激活Windows和Office全系列

KMS智能激活终极指南:5分钟永久激活Windows和Office全系列 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统频繁弹出激活提示而烦恼吗?Office文档突然变…...

SincNet实战:用PyTorch复现说话人识别,并探讨其对抗攻击的脆弱性与防御思路

SincNet实战:从说话人识别到对抗防御的全链路技术解析 当声纹识别系统在智能门锁中误将陌生人识别为业主时,背后可能是精心设计的音频对抗样本在作祟。SincNet作为直接从原始波形学习的CNN变体,其带通滤波器设计带来的可解释性优势&#xff0…...

AI助力船舶稳性计算:Gemini3.1Pro设计辅助新思路

在船舶设计工作中,稳性计算一直是非常核心、也非常严谨的环节。无论是新船方案设计、改装评估,还是载况校核,都需要围绕重心、浮心、横稳心、复原力臂、装载状态、自由液面影响等内容进行系统分析。过去这些资料往往分散在规范条文、设计手册…...

手把手教你排查华为MDC-300F与激光雷达的通信故障:从接口定义到信号测量

手把手教你排查华为MDC-300F与激光雷达的通信故障:从接口定义到信号测量 当自动驾驶系统的传感器突然"失声",整个项目进度可能因此停滞。作为硬件工程师,我们常常在深夜的实验室里面对着一堆闪烁的指示灯和沉默的设备——MDC-300F与…...

LLM应用可观测性实战:基于OpenTelemetry与OpenLLMetry的监控方案

1. 项目概述:当LLM应用遇见可观测性如果你正在开发或维护一个基于大语言模型的应用,那么下面这个场景你一定不陌生:用户反馈说“AI助手刚才的回答很奇怪”,或者“昨天还能正常调用的功能今天突然报错了”。你打开日志,…...

【ROS进阶-1】从零构建自定义消息:实战配置与编译全解析

1. 为什么需要自定义ROS消息 在ROS开发中,消息是节点间通信的基础载体。虽然ROS已经提供了丰富的标准消息类型,比如std_msgs、geometry_msgs等,但在实际项目中,我们经常会遇到标准消息无法满足需求的情况。就像在C编程中&#xff…...

为LLM构建持久化知识大脑:基于知识图谱与向量搜索的Memento MCP实战

1. 项目概述:为LLM构建一个持久化、可理解的知识大脑如果你用过Claude Desktop、Cursor或者GitHub Copilot,可能会发现一个痛点:这些AI助手虽然聪明,但它们的“记忆”是短暂的、碎片化的。每次对话都像是一次全新的邂逅&#xff0…...

从零部署私有AI助手:igogpt项目实战与优化指南

1. 项目概述与核心价值最近在折腾AI应用部署的时候,发现了一个挺有意思的项目,叫igolaizola/igogpt。乍一看这个名字,可能会有点摸不着头脑,但如果你对开源AI模型部署和WebUI界面搭建感兴趣,那这个项目绝对值得你花时间…...

GTK+命令行神器Zenity:在Ubuntu 22.04上快速创建图形对话框的保姆级指南

GTK命令行神器Zenity:在Ubuntu 22.04上快速创建图形对话框的保姆级指南 如果你是一位Linux桌面用户或开发者,经常需要在命令行和图形界面之间切换,那么Zenity绝对是你的得力助手。这款轻量级的GTK命令行工具,能够让你在Shell脚本中…...

Memorix分布式内存缓存系统:架构解析与部署实践

1. 项目概述:Memorix,一个为现代应用设计的分布式内存缓存系统如果你正在构建一个需要处理高并发请求、对响应延迟有苛刻要求的应用,比如一个实时排行榜、一个秒杀系统,或者一个需要频繁读取用户会话的社交平台,那么你…...

双模型工作流架构解析:从原理到实践,构建高效AI应用

1. 项目概述:双模型工作流的魅力与挑战最近在GitHub上看到一个挺有意思的项目,叫cait52099/openclaw-dual-model-workflow。光看名字,openclaw(开放之爪)和dual-model-workflow(双模型工作流)这…...