Skip to content

Commit

Permalink
langchain[patch]: add tools renderer for various non-openai agents (#…
Browse files Browse the repository at this point in the history
…18307)

- **Description:** add tools_renderer for various non-openai agents,
make tools can be render in different ways for your LLM.
  - **Issue:** N/A
  - **Dependencies:** N/A

---------

Co-authored-by: Harrison Chase <hw.chase.17@gmail.com>
  • Loading branch information
2 people authored and hinthornw committed Mar 4, 2024
1 parent e7b0b93 commit bd22357
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 12 deletions.
8 changes: 6 additions & 2 deletions libs/langchain/langchain/agents/json_chat/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
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
from langchain.tools.render import render_text_description
from langchain.tools.render import ToolsRenderer, render_text_description


def create_json_chat_agent(
llm: BaseLanguageModel,
tools: Sequence[BaseTool],
prompt: ChatPromptTemplate,
stop_sequence: bool = True,
tools_renderer: ToolsRenderer = render_text_description,
) -> Runnable:
"""Create an agent that uses JSON to format its logic, build for Chat Models.
Expand All @@ -26,6 +27,9 @@ def create_json_chat_agent(
stop_sequence: Adds a stop token of "Observation:" to avoid hallucinates.
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`.
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
Expand Down Expand Up @@ -150,7 +154,7 @@ def create_json_chat_agent(
raise ValueError(f"Prompt missing required variables: {missing_vars}")

prompt = prompt.partial(
tools=render_text_description(list(tools)),
tools=tools_renderer(list(tools)),
tool_names=", ".join([t.name for t in tools]),
)
if stop_sequence:
Expand Down
3 changes: 2 additions & 1 deletion libs/langchain/langchain/agents/mrkl/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from langchain.agents.tools import Tool
from langchain.agents.utils import validate_tools_single_input
from langchain.chains import LLMChain
from langchain.tools.render import render_text_description


class ChainConfig(NamedTuple):
Expand Down Expand Up @@ -79,7 +80,7 @@ def create_prompt(
Returns:
A PromptTemplate with the template assembled from the pieces here.
"""
tool_strings = "\n".join([f"{tool.name}: {tool.description}" for tool in tools])
tool_strings = render_text_description(list(tools))
tool_names = ", ".join([tool.name for tool in tools])
format_instructions = format_instructions.format(tool_names=tool_names)
template = "\n\n".join([prefix, tool_strings, format_instructions, suffix])
Expand Down
7 changes: 5 additions & 2 deletions libs/langchain/langchain/agents/react/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
from langchain.agents import AgentOutputParser
from langchain.agents.format_scratchpad import format_log_to_str
from langchain.agents.output_parsers import ReActSingleInputOutputParser
from langchain.tools.render import render_text_description
from langchain.tools.render import ToolsRenderer, render_text_description


def create_react_agent(
llm: BaseLanguageModel,
tools: Sequence[BaseTool],
prompt: BasePromptTemplate,
output_parser: Optional[AgentOutputParser] = None,
tools_renderer: ToolsRenderer = render_text_description,
) -> Runnable:
"""Create an agent that uses ReAct prompting.
Expand All @@ -26,6 +27,8 @@ def create_react_agent(
tools: Tools this agent has access to.
prompt: The prompt to use. See Prompt section below for more.
output_parser: AgentOutputParser for parse the LLM output.
tools_renderer: This controls how the tools are converted into a string and
then passed into the LLM. Default is `render_text_description`.
Returns:
A Runnable sequence representing an agent. It takes as input all the same input
Expand Down Expand Up @@ -102,7 +105,7 @@ def create_react_agent(
raise ValueError(f"Prompt missing required variables: {missing_vars}")

prompt = prompt.partial(
tools=render_text_description(list(tools)),
tools=tools_renderer(list(tools)),
tool_names=", ".join([t.name for t in tools]),
)
llm_with_stop = llm.bind(stop=["\nObservation"])
Expand Down
11 changes: 8 additions & 3 deletions libs/langchain/langchain/agents/structured_chat/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
)
from langchain.agents.structured_chat.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX
from langchain.chains.llm import LLMChain
from langchain.tools.render import render_text_description_and_args
from langchain.tools.render import ToolsRenderer, render_text_description_and_args

HUMAN_MESSAGE_TEMPLATE = "{input}\n\n{agent_scratchpad}"

Expand Down Expand Up @@ -151,14 +151,19 @@ def _agent_type(self) -> str:


def create_structured_chat_agent(
llm: BaseLanguageModel, tools: Sequence[BaseTool], prompt: ChatPromptTemplate
llm: BaseLanguageModel,
tools: Sequence[BaseTool],
prompt: ChatPromptTemplate,
tools_renderer: ToolsRenderer = render_text_description_and_args,
) -> Runnable:
"""Create an agent aimed at supporting tools with multiple inputs.
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.
tools_renderer: This controls how the tools are converted into a string and
then passed into the LLM. Default is `render_text_description`.
Returns:
A Runnable sequence representing an agent. It takes as input all the same input
Expand Down Expand Up @@ -265,7 +270,7 @@ def create_structured_chat_agent(
raise ValueError(f"Prompt missing required variables: {missing_vars}")

prompt = prompt.partial(
tools=render_text_description_and_args(list(tools)),
tools=tools_renderer(list(tools)),
tool_names=", ".join([t.name for t in tools]),
)
llm_with_stop = llm.bind(stop=["Observation"])
Expand Down
11 changes: 8 additions & 3 deletions libs/langchain/langchain/agents/xml/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from langchain.agents.output_parsers import XMLAgentOutputParser
from langchain.agents.xml.prompt import agent_instructions
from langchain.chains.llm import LLMChain
from langchain.tools.render import render_text_description
from langchain.tools.render import ToolsRenderer, render_text_description


@deprecated("0.1.0", alternative="create_xml_agent", removal="0.2.0")
Expand Down Expand Up @@ -108,7 +108,10 @@ async def aplan(


def create_xml_agent(
llm: BaseLanguageModel, tools: Sequence[BaseTool], prompt: BasePromptTemplate
llm: BaseLanguageModel,
tools: Sequence[BaseTool],
prompt: BasePromptTemplate,
tools_renderer: ToolsRenderer = render_text_description,
) -> Runnable:
"""Create an agent that uses XML to format its logic.
Expand All @@ -118,6 +121,8 @@ def create_xml_agent(
prompt: The prompt to use, must have input keys
`tools`: contains descriptions for each tool.
`agent_scratchpad`: contains previous agent actions and tool outputs.
tools_renderer: This controls how the tools are converted into a string and
then passed into the LLM. Default is `render_text_description`.
Returns:
A Runnable sequence representing an agent. It takes as input all the same input
Expand Down Expand Up @@ -194,7 +199,7 @@ def create_xml_agent(
raise ValueError(f"Prompt missing required variables: {missing_vars}")

prompt = prompt.partial(
tools=render_text_description(list(tools)),
tools=tools_renderer(list(tools)),
)
llm_with_stop = llm.bind(stop=["</tool_input>"])

Expand Down
6 changes: 5 additions & 1 deletion libs/langchain/langchain/tools/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
you may want Tools to be rendered in a different way.
This module contains various ways to render tools.
"""
from typing import List
from typing import Callable, List

# For backwards compatibility
from langchain_core.tools import BaseTool
Expand All @@ -14,13 +14,17 @@
)

__all__ = [
"ToolsRenderer",
"render_text_description",
"render_text_description_and_args",
"format_tool_to_openai_tool",
"format_tool_to_openai_function",
]


ToolsRenderer = Callable[[List[BaseTool]], str]


def render_text_description(tools: List[BaseTool]) -> str:
"""Render the tool name and description in plain text.
Expand Down

0 comments on commit bd22357

Please sign in to comment.