Source code for langchain.agents.output_parsers.tools

import json
from json import JSONDecodeError
from typing import List, Union

from langchain_core.agents import AgentAction, AgentActionMessageLog, AgentFinish
from langchain_core.exceptions import OutputParserException
from langchain_core.messages import (
    AIMessage,
    BaseMessage,
    ToolCall,
)
from langchain_core.outputs import ChatGeneration, Generation

from langchain.agents.agent import MultiActionAgentOutputParser


[docs]class ToolAgentAction(AgentActionMessageLog): tool_call_id: str """工具调用,这条消息是在回应什么。"""
[docs]def parse_ai_message_to_tool_action( message: BaseMessage, ) -> Union[List[AgentAction], AgentFinish]: """解析可能包含工具调用的AI消息。""" if not isinstance(message, AIMessage): raise TypeError(f"Expected an AI message got {type(message)}") actions: List = [] if message.tool_calls: tool_calls = message.tool_calls else: if not message.additional_kwargs.get("tool_calls"): return AgentFinish( return_values={"output": message.content}, log=str(message.content) ) # Best-effort parsing tool_calls = [] for tool_call in message.additional_kwargs["tool_calls"]: function = tool_call["function"] function_name = function["name"] try: args = json.loads(function["arguments"] or "{}") tool_calls.append( ToolCall(name=function_name, args=args, id=tool_call["id"]) ) except JSONDecodeError: raise OutputParserException( f"Could not parse tool input: {function} because " f"the `arguments` is not valid JSON." ) for tool_call in tool_calls: # HACK HACK HACK: # The code that encodes tool input into Open AI uses a special variable # name called `__arg1` to handle old style tools that do not expose a # schema and expect a single string argument as an input. # We unpack the argument here if it exists. # Open AI does not support passing in a JSON array as an argument. function_name = tool_call["name"] _tool_input = tool_call["args"] if "__arg1" in _tool_input: tool_input = _tool_input["__arg1"] else: tool_input = _tool_input content_msg = f"responded: {message.content}\n" if message.content else "\n" log = f"\nInvoking: `{function_name}` with `{tool_input}`\n{content_msg}\n" actions.append( ToolAgentAction( tool=function_name, tool_input=tool_input, log=log, message_log=[message], tool_call_id=tool_call["id"], ) ) return actions
[docs]class ToolsAgentOutputParser(MultiActionAgentOutputParser): """将消息解析为代理动作/完成。 如果传递了tool_calls参数,则将用它来获取工具名称和工具输入。 如果没有传递,则假定AIMessage是最终输出。""" @property def _type(self) -> str: return "tools-agent-output-parser"
[docs] def parse_result( self, result: List[Generation], *, partial: bool = False ) -> Union[List[AgentAction], AgentFinish]: if not isinstance(result[0], ChatGeneration): raise ValueError("This output parser only works on ChatGeneration output") message = result[0].message return parse_ai_message_to_tool_action(message)
[docs] def parse(self, text: str) -> Union[List[AgentAction], AgentFinish]: raise ValueError("Can only parse messages")