-
Notifications
You must be signed in to change notification settings - Fork 16.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[langchain] agents code changes (#15278)
<!-- Thank you for contributing to LangChain! Please title your PR "<package>: <description>", where <package> is whichever of langchain, community, core, experimental, etc. is being modified. Replace this entire comment with: - **Description:** a description of the change, - **Issue:** the issue # it fixes if applicable, - **Dependencies:** any dependencies required for this change, - **Twitter handle:** we announce bigger features on Twitter. If your PR gets announced, and you'd like a mention, we'll gladly shout you out!
- Loading branch information
Showing
14 changed files
with
579 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
from typing import Sequence | ||
|
||
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.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 | ||
|
||
|
||
def create_json_chat_agent( | ||
llm: BaseLanguageModel, tools: Sequence[BaseTool], prompt: ChatPromptTemplate | ||
) -> Runnable: | ||
"""Create an agent that uses JSON to format its logic, build for Chat Models. | ||
Examples: | ||
.. code-block:: python | ||
from langchain import hub | ||
from langchain.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?"), | ||
], | ||
} | ||
) | ||
Args: | ||
llm: LLM to use as the agent. | ||
tools: Tools this agent has access to. | ||
prompt: The prompt to use, must have input keys of | ||
`tools`, `tool_names`, and `agent_scratchpad`. | ||
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. | ||
""" | ||
missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference( | ||
prompt.input_variables | ||
) | ||
if missing_vars: | ||
raise ValueError(f"Prompt missing required variables: {missing_vars}") | ||
|
||
prompt = prompt.partial( | ||
tools=render_text_description(list(tools)), | ||
tool_names=", ".join([t.name for t in tools]), | ||
) | ||
llm_with_stop = llm.bind(stop=["\nObservation"]) | ||
|
||
agent = ( | ||
RunnablePassthrough.assign( | ||
agent_scratchpad=lambda x: format_log_to_messages( | ||
x["intermediate_steps"], template_tool_response=TEMPLATE_TOOL_RESPONSE | ||
) | ||
) | ||
| prompt | ||
| llm_with_stop | ||
| JSONAgentOutputParser() | ||
) | ||
return agent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# flake8: noqa | ||
TEMPLATE_TOOL_RESPONSE = """TOOL RESPONSE: | ||
--------------------- | ||
{observation} | ||
USER'S INPUT | ||
-------------------- | ||
Okay, so what is the response to my last comment? If using information obtained from the tools you must mention it explicitly without mentioning the tool names - I have forgotten all TOOL RESPONSES! Remember to respond with a markdown code snippet of a json blob with a single action, and NOTHING else - even if you just want to respond to the user. Do NOT respond with anything except a JSON snippet no matter what!""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from typing import Sequence | ||
|
||
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.agents.format_scratchpad.openai_tools import ( | ||
format_to_openai_tool_messages, | ||
) | ||
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser | ||
from langchain.tools.render import format_tool_to_openai_tool | ||
|
||
|
||
def create_openai_tools_agent( | ||
llm: BaseLanguageModel, tools: Sequence[BaseTool], prompt: ChatPromptTemplate | ||
) -> Runnable: | ||
"""Create an agent that uses OpenAI tools. | ||
Examples: | ||
.. code-block:: python | ||
from langchain import hub | ||
from langchain.chat_models import ChatOpenAI | ||
from langchain.agents import AgentExecutor, create_openai_tools_agent | ||
prompt = hub.pull("hwchase17/openai-tools-agent") | ||
model = ChatOpenAI() | ||
tools = ... | ||
agent = create_openai_tools_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?"), | ||
], | ||
} | ||
) | ||
Args: | ||
llm: LLM to use as the agent. | ||
tools: Tools this agent has access to. | ||
prompt: The prompt to use, must have input keys of `agent_scratchpad`. | ||
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. | ||
""" | ||
missing_vars = {"agent_scratchpad"}.difference(prompt.input_variables) | ||
if missing_vars: | ||
raise ValueError(f"Prompt missing required variables: {missing_vars}") | ||
|
||
llm_with_tools = llm.bind( | ||
tools=[format_tool_to_openai_tool(tool) for tool in tools] | ||
) | ||
|
||
agent = ( | ||
RunnablePassthrough.assign( | ||
agent_scratchpad=lambda x: format_to_openai_tool_messages( | ||
x["intermediate_steps"] | ||
) | ||
) | ||
| prompt | ||
| llm_with_tools | ||
| OpenAIToolsAgentOutputParser() | ||
) | ||
return agent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Sequence | ||
|
||
from langchain_core.language_models import BaseLanguageModel | ||
from langchain_core.prompts import BasePromptTemplate | ||
from langchain_core.runnables import Runnable, RunnablePassthrough | ||
from langchain_core.tools import BaseTool | ||
|
||
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 | ||
|
||
|
||
def create_react_agent( | ||
llm: BaseLanguageModel, tools: Sequence[BaseTool], prompt: BasePromptTemplate | ||
) -> Runnable: | ||
"""Create an agent that uses ReAct prompting. | ||
Examples: | ||
.. code-block:: python | ||
from langchain import hub | ||
from langchain.llms import OpenAI | ||
from langchain.agents import AgentExecutor, create_react_agent | ||
prompt = hub.pull("hwchase17/react") | ||
model = OpenAI() | ||
tools = ... | ||
agent = create_react_agent(model, tools, prompt) | ||
agent_executor = AgentExecutor(agent=agent, tools=tools) | ||
agent_executor.invoke({"input": "hi"}) | ||
# Use with chat history | ||
from langchain_core.messages import AIMessage, HumanMessage | ||
agent_executor.invoke( | ||
{ | ||
"input": "what's my name?", | ||
# Notice that chat_history is a string | ||
# since this prompt is aimed at LLMs, not chat models | ||
"chat_history": "Human: My name is Bob\nAI: Hello Bob!", | ||
} | ||
) | ||
Args: | ||
llm: LLM to use as the agent. | ||
tools: Tools this agent has access to. | ||
prompt: The prompt to use, must have input keys of | ||
`tools`, `tool_names`, and `agent_scratchpad`. | ||
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. | ||
""" | ||
missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference( | ||
prompt.input_variables | ||
) | ||
if missing_vars: | ||
raise ValueError(f"Prompt missing required variables: {missing_vars}") | ||
|
||
prompt = prompt.partial( | ||
tools=render_text_description(list(tools)), | ||
tool_names=", ".join([t.name for t in tools]), | ||
) | ||
llm_with_stop = llm.bind(stop=["\nObservation"]) | ||
agent = ( | ||
RunnablePassthrough.assign( | ||
agent_scratchpad=lambda x: format_log_to_str(x["intermediate_steps"]), | ||
) | ||
| prompt | ||
| llm_with_stop | ||
| ReActSingleInputOutputParser() | ||
) | ||
return agent |
Oops, something went wrong.