| 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 |
|
|