forked from langchain-ai/langchain
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Structure Chat Agent (langchain-ai#3912)
Create a new chat agent that is compatible with the Multi-input tools
- Loading branch information
1 parent
ec21b71
commit c582f2e
Showing
10 changed files
with
705 additions
and
14 deletions.
There are no files selected for viewing
312 changes: 312 additions & 0 deletions
312
docs/modules/agents/agents/examples/structured_chat.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
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
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
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,130 @@ | ||
import re | ||
from typing import Any, List, Optional, Sequence, Tuple | ||
|
||
from pydantic import Field | ||
|
||
from langchain.agents.agent import Agent, AgentOutputParser | ||
from langchain.agents.structured_chat.output_parser import ( | ||
StructuredChatOutputParser, | ||
StructuredChatOutputParserWithRetries, | ||
) | ||
from langchain.agents.structured_chat.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX | ||
from langchain.base_language import BaseLanguageModel | ||
from langchain.callbacks.base import BaseCallbackManager | ||
from langchain.chains.llm import LLMChain | ||
from langchain.prompts.base import BasePromptTemplate | ||
from langchain.prompts.chat import ( | ||
ChatPromptTemplate, | ||
HumanMessagePromptTemplate, | ||
SystemMessagePromptTemplate, | ||
) | ||
from langchain.schema import AgentAction | ||
from langchain.tools import BaseTool | ||
|
||
|
||
class StructuredChatAgent(Agent): | ||
output_parser: AgentOutputParser = Field(default_factory=StructuredChatOutputParser) | ||
|
||
@property | ||
def observation_prefix(self) -> str: | ||
"""Prefix to append the observation with.""" | ||
return "Observation: " | ||
|
||
@property | ||
def llm_prefix(self) -> str: | ||
"""Prefix to append the llm call with.""" | ||
return "Thought:" | ||
|
||
def _construct_scratchpad( | ||
self, intermediate_steps: List[Tuple[AgentAction, str]] | ||
) -> str: | ||
agent_scratchpad = super()._construct_scratchpad(intermediate_steps) | ||
if not isinstance(agent_scratchpad, str): | ||
raise ValueError("agent_scratchpad should be of type string.") | ||
if agent_scratchpad: | ||
return ( | ||
f"This was your previous work " | ||
f"(but I haven't seen any of it! I only see what " | ||
f"you return as final answer):\n{agent_scratchpad}" | ||
) | ||
else: | ||
return agent_scratchpad | ||
|
||
@classmethod | ||
def _validate_tools(cls, tools: Sequence[BaseTool]) -> None: | ||
pass | ||
|
||
@classmethod | ||
def _get_default_output_parser( | ||
cls, llm: Optional[BaseLanguageModel] = None, **kwargs: Any | ||
) -> AgentOutputParser: | ||
return StructuredChatOutputParserWithRetries.from_llm(llm=llm) | ||
|
||
@property | ||
def _stop(self) -> List[str]: | ||
return ["Observation:"] | ||
|
||
@classmethod | ||
def create_prompt( | ||
cls, | ||
tools: Sequence[BaseTool], | ||
prefix: str = PREFIX, | ||
suffix: str = SUFFIX, | ||
format_instructions: str = FORMAT_INSTRUCTIONS, | ||
input_variables: Optional[List[str]] = None, | ||
) -> BasePromptTemplate: | ||
tool_strings = [] | ||
for tool in tools: | ||
args_schema = re.sub("}", "}}}}", re.sub("{", "{{{{", str(tool.args))) | ||
tool_strings.append(f"{tool.name}: {tool.description}, args: {args_schema}") | ||
formatted_tools = "\n".join(tool_strings) | ||
tool_names = ", ".join([tool.name for tool in tools]) | ||
format_instructions = format_instructions.format(tool_names=tool_names) | ||
template = "\n\n".join([prefix, formatted_tools, format_instructions, suffix]) | ||
messages = [ | ||
SystemMessagePromptTemplate.from_template(template), | ||
HumanMessagePromptTemplate.from_template("{input}\n\n{agent_scratchpad}"), | ||
] | ||
if input_variables is None: | ||
input_variables = ["input", "agent_scratchpad"] | ||
return ChatPromptTemplate(input_variables=input_variables, messages=messages) | ||
|
||
@classmethod | ||
def from_llm_and_tools( | ||
cls, | ||
llm: BaseLanguageModel, | ||
tools: Sequence[BaseTool], | ||
callback_manager: Optional[BaseCallbackManager] = None, | ||
output_parser: Optional[AgentOutputParser] = None, | ||
prefix: str = PREFIX, | ||
suffix: str = SUFFIX, | ||
format_instructions: str = FORMAT_INSTRUCTIONS, | ||
input_variables: Optional[List[str]] = None, | ||
**kwargs: Any, | ||
) -> Agent: | ||
"""Construct an agent from an LLM and tools.""" | ||
cls._validate_tools(tools) | ||
prompt = cls.create_prompt( | ||
tools, | ||
prefix=prefix, | ||
suffix=suffix, | ||
format_instructions=format_instructions, | ||
input_variables=input_variables, | ||
) | ||
llm_chain = LLMChain( | ||
llm=llm, | ||
prompt=prompt, | ||
callback_manager=callback_manager, | ||
) | ||
tool_names = [tool.name for tool in tools] | ||
_output_parser = output_parser or cls._get_default_output_parser(llm=llm) | ||
return cls( | ||
llm_chain=llm_chain, | ||
allowed_tools=tool_names, | ||
output_parser=_output_parser, | ||
**kwargs, | ||
) | ||
|
||
@property | ||
def _agent_type(self) -> str: | ||
raise ValueError |
Oops, something went wrong.