最近在学AI Agent,用LangChain搭了个简单的工具调用流程,比如让Agent先查数据库再调用API。但发现多轮对话里,Agent经常记不住之前的工具返回结果,比如用户问“刚才那个订单的状态是什么”,它又去重新查一遍,而不是用缓存里的数据。我试了加memory和chat_history,但感觉工具调用的结果没被塞进上下文。是不是我prompt写的有问题?还是LangChain的AgentExecutor默认就不保留工具输出?求指点正确姿势,最好能贴个代码片段,感谢!
用LangChain搭Agent,工具调用时上下文总丢,大佬们怎么解决的?
全部回复
共 4 条我也碰到过一模一样的问题,折腾了好几天才发现核心在于AgentExecutor默认不会把工具调用的结果自动塞进chat_history,它只保留了你和Agent的对话。你加的memory和chat_history大概率只存了用户的query和Agent的回复,但工具返回的中间结果压根没被写进去。我后来试了个办法:在自定义的tool里直接把返回结果用format_tool_output格式化成ToolMessage,然后手动agent.memory.chat_memory.add_message(ToolMessage(...)),这样下一轮对话时Agent就能从memory里读到之前的工具结果。不过要注意,如果你用的是ConversationBufferMemory,它默认只存HumanMessage和AIMessage,得换成ConversationSummaryBufferMemory或者自己继承一下。另外看你说的“查数据库再调API”,如果工具调用顺序是固定的,不如直接用LangChain的SequentialChain搭个确定性流程,比Agent可控得多。还有个小坑:agent的prompt里最好明确写一句“如果你已经获取过某个信息,直接使用缓存结果”,不然它确实会傻乎乎地重复调用。
我也踩过这个坑,AgentExecutor默认确实不会把工具输出自动塞进chat_history,你得自己在tool的return_direct或者回调里手动把结果拼到messages里。可以试试在agent的prompt里显式加一条“你之前的工具调用结果在历史记录中”的指令,或者用ConversationSummaryMemory把工具输出摘要进去。贴不了代码,但核心思路就是把每次工具调用的输出作为一个system message或者user message追加到memory里。
同感,这个问题我折腾了两周才摸到门道。LangChain的AgentExecutor默认确实不会把工具输出自动塞进chat_history,它只保留agent自己的思考和最终答案。你需要手动在回调里把tool的输出追加到memory里去,或者换个思路,直接在Agent的system prompt里写死“每次工具调用后,把你拿到的结果用自然语言总结一下再回复”,这样结果就自然留在对话历史里了。
另外我推荐试一下把memory的类型从默认的ConversationBufferMemory换成ConversationSummaryMemory,它能自动压缩历史,但记得把工具输出的关键字段单独存到一个dict里,在prompt里用f-string引用。比如在工具返回后,用agent_executor的中间步骤回调去更新一个全局变量,然后在下一次agent思考前注入到前缀prompt里。代码的话可以搜一下“LangChain agent cache tool output”这个issue,里面有个老哥贴了完整的callback handler实现,我就是照搬那个搞定的。
这个问题我之前也踩过坑,LangChain的AgentExecutor默认确实不会把工具输出自动塞进对话历史,你得在memory里显式存一下。可以试试在agent的prompt里加个system指令,要求每次工具调用后把结果格式化成“工具名:输出”这样的记录,然后在callback里手动把工具输出追加到chat_history。另外检查下你的memory类型是不是ConversationBufferMemory,记得设置return_messages=True,不然容易丢消息。