| | from typing import List, Sequence, Union |
| |
|
| | from langchain_core.language_models import BaseLanguageModel |
| | from langchain_core.prompts.chat import ChatPromptTemplate |
| | from langchain_core.runnables import Runnable, RunnablePassthrough |
| | from langchain_core.tools import BaseTool |
| | from langchain_core.tools.render import ToolsRenderer, render_text_description |
| |
|
| | from langchain.agents.format_scratchpad import format_log_to_messages |
| | from langchain.agents.json_chat.prompt import TEMPLATE_TOOL_RESPONSE |
| | from langchain.agents.output_parsers import JSONAgentOutputParser |
| |
|
| |
|
| | def create_json_chat_agent( |
| | llm: BaseLanguageModel, |
| | tools: Sequence[BaseTool], |
| | prompt: ChatPromptTemplate, |
| | stop_sequence: Union[bool, List[str]] = True, |
| | tools_renderer: ToolsRenderer = render_text_description, |
| | template_tool_response: str = TEMPLATE_TOOL_RESPONSE, |
| | ) -> Runnable: |
| | """Create an agent that uses JSON to format its logic, build for Chat Models. |
| | |
| | Args: |
| | llm: LLM to use as the agent. |
| | tools: Tools this agent has access to. |
| | prompt: The prompt to use. See Prompt section below for more. |
| | stop_sequence: bool or list of str. |
| | If True, adds a stop token of "Observation:" to avoid hallucinates. |
| | If False, does not add a stop token. |
| | If a list of str, uses the provided list as the stop tokens. |
| | |
| | Default is True. You may to set this to False if the LLM you are using |
| | does not support stop sequences. |
| | tools_renderer: This controls how the tools are converted into a string and |
| | then passed into the LLM. Default is `render_text_description`. |
| | template_tool_response: Template prompt that uses the tool response (observation) |
| | to make the LLM generate the next action to take. |
| | Default is TEMPLATE_TOOL_RESPONSE. |
| | |
| | Returns: |
| | A Runnable sequence representing an agent. It takes as input all the same input |
| | variables as the prompt passed in does. It returns as output either an |
| | AgentAction or AgentFinish. |
| | |
| | Raises: |
| | ValueError: If the prompt is missing required variables. |
| | ValueError: If the template_tool_response is missing |
| | the required variable 'observation'. |
| | |
| | Example: |
| | |
| | .. code-block:: python |
| | |
| | from langchain import hub |
| | from langchain_community.chat_models import ChatOpenAI |
| | from langchain.agents import AgentExecutor, create_json_chat_agent |
| | |
| | prompt = hub.pull("hwchase17/react-chat-json") |
| | model = ChatOpenAI() |
| | tools = ... |
| | |
| | agent = create_json_chat_agent(model, tools, prompt) |
| | agent_executor = AgentExecutor(agent=agent, tools=tools) |
| | |
| | agent_executor.invoke({"input": "hi"}) |
| | |
| | # Using with chat history |
| | from langchain_core.messages import AIMessage, HumanMessage |
| | agent_executor.invoke( |
| | { |
| | "input": "what's my name?", |
| | "chat_history": [ |
| | HumanMessage(content="hi! my name is bob"), |
| | AIMessage(content="Hello Bob! How can I assist you today?"), |
| | ], |
| | } |
| | ) |
| | |
| | Prompt: |
| | |
| | The prompt must have input keys: |
| | * `tools`: contains descriptions and arguments for each tool. |
| | * `tool_names`: contains all tool names. |
| | * `agent_scratchpad`: must be a MessagesPlaceholder. Contains previous agent actions and tool outputs as messages. |
| | |
| | Here's an example: |
| | |
| | .. code-block:: python |
| | |
| | from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder |
| | |
| | system = '''Assistant is a large language model trained by OpenAI. |
| | |
| | Assistant is designed to be able to assist with a wide range of tasks, from answering \ |
| | simple questions to providing in-depth explanations and discussions on a wide range of \ |
| | topics. As a language model, Assistant is able to generate human-like text based on \ |
| | the input it receives, allowing it to engage in natural-sounding conversations and \ |
| | provide responses that are coherent and relevant to the topic at hand. |
| | |
| | Assistant is constantly learning and improving, and its capabilities are constantly \ |
| | evolving. It is able to process and understand large amounts of text, and can use this \ |
| | knowledge to provide accurate and informative responses to a wide range of questions. \ |
| | Additionally, Assistant is able to generate its own text based on the input it \ |
| | receives, allowing it to engage in discussions and provide explanations and \ |
| | descriptions on a wide range of topics. |
| | |
| | Overall, Assistant is a powerful system that can help with a wide range of tasks \ |
| | and provide valuable insights and information on a wide range of topics. Whether \ |
| | you need help with a specific question or just want to have a conversation about \ |
| | a particular topic, Assistant is here to assist.''' |
| | |
| | human = '''TOOLS |
| | ------ |
| | Assistant can ask the user to use tools to look up information that may be helpful in \ |
| | answering the users original question. The tools the human can use are: |
| | |
| | {tools} |
| | |
| | RESPONSE FORMAT INSTRUCTIONS |
| | ---------------------------- |
| | |
| | When responding to me, please output a response in one of two formats: |
| | |
| | **Option 1:** |
| | Use this if you want the human to use a tool. |
| | Markdown code snippet formatted in the following schema: |
| | |
| | ```json |
| | {{ |
| | "action": string, \\ The action to take. Must be one of {tool_names} |
| | "action_input": string \\ The input to the action |
| | }} |
| | ``` |
| | |
| | **Option #2:** |
| | Use this if you want to respond directly to the human. Markdown code snippet formatted \ |
| | in the following schema: |
| | |
| | ```json |
| | {{ |
| | "action": "Final Answer", |
| | "action_input": string \\ You should put what you want to return to use here |
| | }} |
| | ``` |
| | |
| | USER'S INPUT |
| | -------------------- |
| | Here is the user's input (remember to respond with a markdown code snippet of a json \ |
| | blob with a single action, and NOTHING else): |
| | |
| | {input}''' |
| | |
| | prompt = ChatPromptTemplate.from_messages( |
| | [ |
| | ("system", system), |
| | MessagesPlaceholder("chat_history", optional=True), |
| | ("human", human), |
| | MessagesPlaceholder("agent_scratchpad"), |
| | ] |
| | ) |
| | """ |
| | missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference( |
| | prompt.input_variables + list(prompt.partial_variables) |
| | ) |
| | if missing_vars: |
| | raise ValueError(f"Prompt missing required variables: {missing_vars}") |
| |
|
| | if "{observation}" not in template_tool_response: |
| | raise ValueError( |
| | "Template tool response missing required variable 'observation'" |
| | ) |
| |
|
| | prompt = prompt.partial( |
| | tools=tools_renderer(list(tools)), |
| | tool_names=", ".join([t.name for t in tools]), |
| | ) |
| | if stop_sequence: |
| | stop = ["\nObservation"] if stop_sequence is True else stop_sequence |
| | llm_to_use = llm.bind(stop=stop) |
| | else: |
| | llm_to_use = llm |
| |
|
| | agent = ( |
| | RunnablePassthrough.assign( |
| | agent_scratchpad=lambda x: format_log_to_messages( |
| | x["intermediate_steps"], template_tool_response=template_tool_response |
| | ) |
| | ) |
| | | prompt |
| | | llm_to_use |
| | | JSONAgentOutputParser() |
| | ) |
| | return agent |
| |
|