Langchain Agent调用自定义工具异常:输入无效/不完整的排查修复
LangChain Agent调用自定义工具异常分析与修复
问题描述
使用LangChain框架时,大语言模型(LLM)生成的工具调用格式看似合规,但Agent仍会以“无效或不完整的响应”作为输入触发工具,且问题非必现,偶尔能正常执行。
工具代码
@tool def saveEvent(event: str) -> str: """Use it to save an event in my calendar. \ The input should be a VCALENDAR string and be formated as follow: ''' BEGIN:VCALENDAR VERSION:2.0 BEGIN:VEVENT SUMMARY: ```the name of the event in french if you don't know the name, create one limited to 10 words``` DESCRIPTION: ```Description of the event in french, if you don't know the description, summarize the message``` DTSTART: ```Start date of the event, use the paris timezone and format as follow: AAAAMMJJDhhmmssZ``` DTEND: ```End date of the event use the paris timezone and format as follow: AAAAMMJJDhhmmssZ``` LOCATION: ```the location of the event``` CATEGORIES: ```the categories of the event``` END:VEVENT END:VCALENDAR ''' This function will return 'OK' if the event is correctlly saved or 'ERROR' if there is an error.""" resp = calendar.save_event(event) if resp: return 'OK' else: return 'ERROR'
Agent代码
tools = load_tools(['python_repl'], llm=llm) agent= initialize_agent( tools + [saveEvent], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True, max_iterations=3, verbose = True) messages = agent_prompt_template.format_prompt(text=message) response = agent(messages.to_string())
控制台输出(翻译后)
[llm/结束] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:GPTLLM] [10.44s] 退出LLM运行,输出: { "generations": [ [ { "text": "思考:我需要把JSON里的事件信息按照给定模板格式化成VCALENDAR字符串。格式完成后,我可以用'saveEvent'工具把它添加到日历中。\n\n行动:\n```json\n{\n \"action\": \"saveEvent\",\n \"action_input\": \"BEGIN:VCALENDAR\\nVERSION:2.0\\nBEGIN:VEVENT\\nSUMMARY:Festival ForroDiois\\nDESCRIPTION:Marilia Cervi est une des trois prof invités au Festival ForroDiois. Elle partagera sa danse avec nous le samedi 17 juin et dimanches 18 juin (3 cours de 1h30 chacun).\\nDTSTART:20230617T000000Z\\nDTEND:20230617T020000Z\\nLOCATION:Non spécifié\\nCATEGORIES:danse,festival\\nEND:VEVENT\\nEND:VCALENDAR\"\n}\n```\n\n", "generation_info": null } ] ], "llm_output": null, "run": null } [chain/结束] [1:chain:AgentExecutor > 2:chain:LLMChain] [10.44s] 退出Chain运行,输出: { "text": "思考:我需要把JSON里的事件信息按照给定模板格式化成VCALENDAR字符串。格式完成后,我可以用'saveEvent'工具把它添加到日历中。\n\n行动:\n```json\n{\n \"action\": \"saveEvent\",\n \"action_input\": \"BEGIN:VCALENDAR\\nVERSION:2.0\\nBEGIN:VEVENT\\nSUMMARY:Festival ForroDiois\\nDESCRIPTION:Marilia Cervi est une des trois prof invités au Festival ForroDiois. Elle partagera sa danse avec nous le samedi 17 juin et dimanches 18 juin (3 cours de 1h30 chacun).\\nDTSTART:20230617T000000Z\\nDTEND:20230617T020000Z\\nLOCATION:Non spécifié\\nCATEGORIES:danse,festival\\nEND:VEVENT\\nEND:VCALENDAR\"\n}\n```\n\n" } [tool/开始] [1:chain:AgentExecutor > 4:tool:_Exception] 进入工具运行,输入: "无效或不完整的响应" [tool/结束] [1:chain:AgentExecutor > 4:tool:_Exception] [0.111ms] 退出工具运行,输出: "无效或不完整的响应"
异常原因分析
- 输出格式解析冲突:
CHAT_ZERO_SHOT_REACT_DESCRIPTION类型Agent依赖严格的思考/行动/行动输入文本结构,但LLM生成的行动部分用代码块包裹了JSON,部分场景下解析器无法正确提取JSON内容,触发解析失败后传入默认错误文本。 - 工具描述格式混乱:
saveEvent的docstring混合使用三重单引号和代码块,干扰LLM对输入格式的理解,偶尔生成不符合解析要求的输出。 - 换行符转义问题:
action_input中的换行符在LLM输出时可能被解析为实际换行,破坏JSON字符串结构,导致解析器无法识别完整输入内容。
修复方案
1. 调整Agent提示模板,禁用代码块包裹
自定义提示模板,明确要求LLM直接输出JSON格式的行动指令,避免用代码块包裹:
from langchain.prompts import ChatPromptTemplate custom_prompt = ChatPromptTemplate.from_messages([ ("system", "你是擅长使用工具的助手,请严格按照以下格式输出:\n思考: 你的分析过程\n行动: {\"action\": \"工具名称\", \"action_input\": \"工具输入内容\"}\n"), ("user", "{input}") ]) agent = initialize_agent( tools + [saveEvent], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=True, max_iterations=3, verbose=True, agent_kwargs={"prompt": custom_prompt} )
2. 优化工具docstring格式
统一描述格式,避免混合使用多重引号和代码块,减少LLM混淆:
@tool def saveEvent(event: str) -> str: """使用此工具将事件保存到日历中。输入必须是VCALENDAR格式的字符串,格式如下: BEGIN:VCALENDAR VERSION:2.0 BEGIN:VEVENT SUMMARY: 事件名称(法语,未知时自定义,不超过10词) DESCRIPTION: 事件描述(法语,未知时总结输入内容) DTSTART: 开始时间(巴黎时区,格式:AAAAMMJJDhhmmssZ) DTEND: 结束时间(巴黎时区,格式:AAAAMMJJDhhmmssZ) LOCATION: 事件地点 CATEGORIES: 事件分类 END:VEVENT END:VCALENDAR 事件保存成功返回'OK',失败返回'ERROR'。""" resp = calendar.save_event(event) return 'OK' if resp else 'ERROR'
3. 自定义错误处理函数,增强解析容错
当解析失败时,手动从LLM输出中提取JSON内容:
def custom_error_handler(error) -> str: import re # 匹配代码块内的JSON内容 match = re.search(r'```json(.*?)```', str(error), re.DOTALL) if match: return match.group(1).strip() return "无效或不完整的响应" agent = initialize_agent( tools + [saveEvent], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, handle_parsing_errors=custom_error_handler, max_iterations=3, verbose=True )
4. 使用结构化输出解析器,强制格式合规
用LangChain的结构化输出解析器约束LLM生成格式,彻底避免解析错误:
from langchain.output_parsers import StructuredOutputParser, ResponseSchema from langchain.agents import StructuredChatAgent, AgentExecutor # 定义输出结构 response_schemas = [ ResponseSchema(name="thought", description="思考过程"), ResponseSchema(name="action", description="要调用的工具名称"), ResponseSchema(name="action_input", description="工具的输入参数") ] output_parser = StructuredOutputParser.from_response_schemas(response_schemas) format_instructions = output_parser.get_format_instructions() # 构建自定义提示 prompt = ChatPromptTemplate.from_messages([ ("system", f"你是工具调用助手,必须按照以下格式输出:\n{format_instructions}"), ("user", "{input}") ]) # 初始化结构化Agent agent = StructuredChatAgent.from_llm_and_tools(llm=llm, tools=tools + [saveEvent], prompt=prompt) agent_executor = AgentExecutor(agent=agent, tools=tools + [saveEvent], verbose=True) # 调用执行 response = agent_executor.run(messages.to_string())
内容的提问来源于stack exchange,提问作者Loann Delgado
相关产品推荐
相关产品推荐

