From f5a4bf0ce4e401104424296f2cdd145459193804 Mon Sep 17 00:00:00 2001 From: Harrison Chase Date: Wed, 29 Mar 2023 14:38:21 -0700 Subject: [PATCH] remove prep (#2136) agents should be stateless or async stuff may not work --- .../agents/agents/examples/react.ipynb | 24 +-- langchain/agents/agent.py | 8 - langchain/agents/react/base.py | 20 +-- langchain/agents/react/textworld_prompt.py | 22 +-- langchain/agents/react/wiki_prompt.py | 158 +++++++----------- tests/unit_tests/agents/test_react.py | 14 +- 6 files changed, 96 insertions(+), 150 deletions(-) diff --git a/docs/modules/agents/agents/examples/react.ipynb b/docs/modules/agents/agents/examples/react.ipynb index 8e7d05bfe1..5519e0fa6c 100644 --- a/docs/modules/agents/agents/examples/react.ipynb +++ b/docs/modules/agents/agents/examples/react.ipynb @@ -52,15 +52,19 @@ "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3m\n", - "Thought 1: I need to search David Chanoff and find the U.S. Navy admiral he collaborated\n", - "with.\n", - "Action 1: Search[David Chanoff]\u001b[0m\n", - "Observation 1: \u001b[36;1m\u001b[1;3mDavid Chanoff is a noted author of non-fiction work. His work has typically involved collaborations with the principal protagonist of the work concerned. His collaborators have included; Augustus A. White, Joycelyn Elders, Đoàn Văn Toại, William J. Crowe, Ariel Sharon, Kenneth Good and Felix Zandman. He has also written about a wide range of subjects including literary history, education and foreign for The Washington Post, The New Republic and The New York Times Magazine. He has published more than twelve books.\u001b[0m\n", - "Thought 2:\u001b[32;1m\u001b[1;3m The U.S. Navy admiral David Chanoff collaborated with is William J. Crowe.\n", - "Action 2: Search[William J. Crowe]\u001b[0m\n", - "Observation 2: \u001b[36;1m\u001b[1;3mWilliam James Crowe Jr. (January 2, 1925 – October 18, 2007) was a United States Navy admiral and diplomat who served as the 11th chairman of the Joint Chiefs of Staff under Presidents Ronald Reagan and George H. W. Bush, and as the ambassador to the United Kingdom and Chair of the Intelligence Oversight Board under President Bill Clinton.\u001b[0m\n", - "Thought 3:\u001b[32;1m\u001b[1;3m The President William J. Crowe served as the ambassador to the United Kingdom under is Bill Clinton.\n", - "Action 3: Finish[Bill Clinton]\u001b[0m\n", + "Thought: I need to search David Chanoff and find the U.S. Navy admiral he collaborated with. Then I need to find which President the admiral served under.\n", + "\n", + "Action: Search[David Chanoff]\n", + "\u001b[0m\n", + "Observation: \u001b[36;1m\u001b[1;3mDavid Chanoff is a noted author of non-fiction work. His work has typically involved collaborations with the principal protagonist of the work concerned. His collaborators have included; Augustus A. White, Joycelyn Elders, Đoàn Văn Toại, William J. Crowe, Ariel Sharon, Kenneth Good and Felix Zandman. He has also written about a wide range of subjects including literary history, education and foreign for The Washington Post, The New Republic and The New York Times Magazine. He has published more than twelve books.\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m The U.S. Navy admiral David Chanoff collaborated with is William J. Crowe. I need to find which President he served under.\n", + "\n", + "Action: Search[William J. Crowe]\n", + "\u001b[0m\n", + "Observation: \u001b[36;1m\u001b[1;3mWilliam James Crowe Jr. (January 2, 1925 – October 18, 2007) was a United States Navy admiral and diplomat who served as the 11th chairman of the Joint Chiefs of Staff under Presidents Ronald Reagan and George H. W. Bush, and as the ambassador to the United Kingdom and Chair of the Intelligence Oversight Board under President Bill Clinton.\u001b[0m\n", + "Thought:\u001b[32;1m\u001b[1;3m William J. Crowe served as the ambassador to the United Kingdom under President Bill Clinton, so the answer is Bill Clinton.\n", + "\n", + "Action: Finish[Bill Clinton]\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -84,7 +88,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cc4a6efe", + "id": "09604a7f", "metadata": {}, "outputs": [], "source": [] diff --git a/langchain/agents/agent.py b/langchain/agents/agent.py index 0587228f01..ea9a3f46a1 100644 --- a/langchain/agents/agent.py +++ b/langchain/agents/agent.py @@ -135,10 +135,6 @@ class Agent(BaseModel): full_inputs = {**kwargs, **new_inputs} return full_inputs - def prepare_for_new_call(self) -> None: - """Prepare the agent for new call, if needed.""" - pass - @property def finish_tool_name(self) -> str: """Name of the tool to use to finish the chain.""" @@ -493,8 +489,6 @@ class AgentExecutor(Chain, BaseModel): def _call(self, inputs: Dict[str, str]) -> Dict[str, Any]: """Run text through and get agent response.""" - # Do any preparation necessary when receiving a new input. - self.agent.prepare_for_new_call() # Construct a mapping of tool name to tool for easy lookup name_to_tool_map = {tool.name: tool for tool in self.tools} # We construct a mapping from each tool to a color, used for logging. @@ -525,8 +519,6 @@ class AgentExecutor(Chain, BaseModel): async def _acall(self, inputs: Dict[str, str]) -> Dict[str, str]: """Run text through and get agent response.""" - # Do any preparation necessary when receiving a new input. - self.agent.prepare_for_new_call() # Construct a mapping of tool name to tool for easy lookup name_to_tool_map = {tool.name: tool for tool in self.tools} # We construct a mapping from each tool to a color, used for logging. diff --git a/langchain/agents/react/base.py b/langchain/agents/react/base.py index 7839e2a8d5..bae6478be5 100644 --- a/langchain/agents/react/base.py +++ b/langchain/agents/react/base.py @@ -28,8 +28,6 @@ class ReActDocstoreAgent(Agent, BaseModel): """Return default prompt.""" return WIKI_PROMPT - i: int = 1 - @classmethod def _validate_tools(cls, tools: Sequence[BaseTool]) -> None: if len(tools) != 2: @@ -40,18 +38,14 @@ class ReActDocstoreAgent(Agent, BaseModel): f"Tool names should be Lookup and Search, got {tool_names}" ) - def _prepare_for_new_call(self) -> None: - self.i = 1 - def _fix_text(self, text: str) -> str: - return text + f"\nAction {self.i}:" + return text + "\nAction:" def _extract_tool_and_input(self, text: str) -> Optional[Tuple[str, str]]: - action_prefix = f"Action {self.i}: " - if not text.split("\n")[-1].startswith(action_prefix): + action_prefix = "Action: " + if not text.strip().split("\n")[-1].startswith(action_prefix): return None - self.i += 1 - action_block = text.split("\n")[-1] + action_block = text.strip().split("\n")[-1] action_str = action_block[len(action_prefix) :] # Parse out the action and the directive. @@ -68,16 +62,16 @@ class ReActDocstoreAgent(Agent, BaseModel): @property def observation_prefix(self) -> str: """Prefix to append the observation with.""" - return f"Observation {self.i - 1}: " + return "Observation: " @property def _stop(self) -> List[str]: - return [f"\nObservation {self.i}:"] + return ["\nObservation:"] @property def llm_prefix(self) -> str: """Prefix to append the LLM call with.""" - return f"Thought {self.i}:" + return "Thought:" class DocstoreExplorer: diff --git a/langchain/agents/react/textworld_prompt.py b/langchain/agents/react/textworld_prompt.py index b832a6bb6c..f01b9a6dd9 100644 --- a/langchain/agents/react/textworld_prompt.py +++ b/langchain/agents/react/textworld_prompt.py @@ -16,9 +16,9 @@ should have stuff on it? You don't like doors? Why not try going east, that entranceway is unguarded. -Thought 1: I need to travel east -Action 1: Play[go east] -Observation 1: -= Office =- +Thought: I need to travel east +Action: Play[go east] +Observation: -= Office =- You arrive in an office. An ordinary one. You can make out a locker. The locker contains a binder. You see a case. The @@ -29,18 +29,18 @@ be empty. If you haven't noticed it already, there seems to be something there by the wall, it's a table. Unfortunately, there isn't a thing on it. Hm. Oh well There is an exit to the west. Don't worry, it is unguarded. -Thought 2: I need to take the binder from the locker -Action 2: Play[take binder] -Observation 2: You take the binder from the locker. +Thought: I need to take the binder from the locker +Action: Play[take binder] +Observation: You take the binder from the locker. -Thought 3: I need to place the binder on the mantelpiece -Action 3: Play[put binder on mantelpiece] +Thought: I need to place the binder on the mantelpiece +Action: Play[put binder on mantelpiece] -Observation 3: You put the binder on the mantelpiece. +Observation: You put the binder on the mantelpiece. Your score has just gone up by one point. *** The End *** -Thought 4: The End has occurred -Action 4: Finish[yes] +Thought: The End has occurred +Action: Finish[yes] """ ] diff --git a/langchain/agents/react/wiki_prompt.py b/langchain/agents/react/wiki_prompt.py index 879a554ad3..866facd1fd 100644 --- a/langchain/agents/react/wiki_prompt.py +++ b/langchain/agents/react/wiki_prompt.py @@ -2,110 +2,66 @@ from langchain.prompts.prompt import PromptTemplate EXAMPLES = [ - """Question: What is the elevation range for the area that the eastern sector of the -Colorado orogeny extends into? -Thought 1: I need to search Colorado orogeny, find the area that the eastern sector -of the Colorado orogeny extends into, then find the elevation range of the -area. -Action 1: Search[Colorado orogeny] -Observation 1: The Colorado orogeny was an episode of mountain building (an orogeny) in -Colorado and surrounding areas. -Thought 2: It does not mention the eastern sector. So I need to look up eastern -sector. -Action 2: Lookup[eastern sector] -Observation 2: (Result 1 / 1) The eastern sector extends into the High Plains and is called -the Central Plains orogeny. -Thought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I -need to search High Plains and find its elevation range. -Action 3: Search[High Plains] -Observation 3: High Plains refers to one of two distinct land regions -Thought 4: I need to instead search High Plains (United States). -Action 4: Search[High Plains (United States)] -Observation 4: The High Plains are a subregion of the Great Plains. From east to west, the -High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130 -m).[3] -Thought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer -is 1,800 to 7,000 ft. -Action 5: Finish[1,800 to 7,000 ft]""", - """Question: Musician and satirist Allie Goertz wrote a song about the "The Simpsons" -character Milhouse, who Matt Groening named after who? -Thought 1: The question simplifies to "The Simpsons" character Milhouse is named after -who. I only need to search Milhouse and find who it is named after. -Action 1: Search[Milhouse] -Observation 1: Milhouse Mussolini Van Houten is a recurring character in the Fox animated -television series The Simpsons voiced by Pamela Hayden and created by Matt -Groening. -Thought 2: The paragraph does not tell who Milhouse is named after, maybe I can look up -"named after". -Action 2: Lookup[named after] -Observation 2: (Result 1 / 1) Milhouse was named after U.S. president Richard Nixon, whose -middle name was Milhous. -Thought 3: Milhouse was named after U.S. president Richard Nixon, so the answer is -Richard Nixon. -Action 3: Finish[Richard Nixon]""", - """Question: Which documentary is about Finnish rock groups, Adam Clayton Powell or The -Saimaa Gesture? -Thought 1: I need to search Adam Clayton Powell and The Saimaa Gesture, and find which -documentary is about Finnish rock groups. -Action 1: Search[Adam Clayton Powell] -Observation 1 Could not find [Adam Clayton Powell]. Similar: [’Adam Clayton Powell -III’, ’Seventh Avenue (Manhattan)’, ’Adam Clayton Powell Jr. State Office -Building’, ’Isabel Washington Powell’, ’Adam Powell’, ’Adam Clayton Powell -(film)’, ’Giancarlo Esposito’]. -Thought 2: To find the documentary, I can search Adam Clayton Powell (film). -Action 2: Search[Adam Clayton Powell (film)] -Observation 2: Adam Clayton Powell is a 1989 American documentary film directed by -Richard Kilberg. The film is about the rise and fall of influential -African-American politician Adam Clayton Powell Jr.[3][4] It was later aired -as part of the PBS series The American Experience. -Thought 3: Adam Clayton Powell (film) is a documentary about an African-American -politician, not Finnish rock groups. So the documentary about Finnish rock -groups must instead be The Saimaa Gesture. -Action 3: Finish[The Saimaa Gesture]""", + """Question: What is the elevation range for the area that the eastern sector of the Colorado orogeny extends into? +Thought: I need to search Colorado orogeny, find the area that the eastern sector of the Colorado orogeny extends into, then find the elevation range of the area. +Action: Search[Colorado orogeny] +Observation: The Colorado orogeny was an episode of mountain building (an orogeny) in Colorado and surrounding areas. +Thought: It does not mention the eastern sector. So I need to look up eastern sector. +Action: Lookup[eastern sector] +Observation: (Result 1 / 1) The eastern sector extends into the High Plains and is called the Central Plains orogeny. +Thought: The eastern sector of Colorado orogeny extends into the High Plains. So I need to search High Plains and find its elevation range. +Action: Search[High Plains] +Observation: High Plains refers to one of two distinct land regions +Thought: I need to instead search High Plains (United States). +Action: Search[High Plains (United States)] +Observation: The High Plains are a subregion of the Great Plains. From east to west, the High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130 m).[3] +Thought: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer is 1,800 to 7,000 ft. +Action: Finish[1,800 to 7,000 ft]""", + """Question: Musician and satirist Allie Goertz wrote a song about the "The Simpsons" character Milhouse, who Matt Groening named after who? +Thought: The question simplifies to "The Simpsons" character Milhouse is named after who. I only need to search Milhouse and find who it is named after. +Action: Search[Milhouse] +Observation: Milhouse Mussolini Van Houten is a recurring character in the Fox animated television series The Simpsons voiced by Pamela Hayden and created by Matt Groening. +Thought: The paragraph does not tell who Milhouse is named after, maybe I can look up "named after". +Action: Lookup[named after] +Observation: (Result 1 / 1) Milhouse was named after U.S. president Richard Nixon, whose middle name was Milhous. +Thought: Milhouse was named after U.S. president Richard Nixon, so the answer is Richard Nixon. +Action: Finish[Richard Nixon]""", + """Question: Which documentary is about Finnish rock groups, Adam Clayton Powell or The Saimaa Gesture? +Thought: I need to search Adam Clayton Powell and The Saimaa Gesture, and find which documentary is about Finnish rock groups. +Action: Search[Adam Clayton Powell] +Observation: Could not find [Adam Clayton Powell]. Similar: [’Adam Clayton Powell III’, ’Seventh Avenue (Manhattan)’, ’Adam Clayton Powell Jr. State Office Building’, ’Isabel Washington Powell’, ’Adam Powell’, ’Adam Clayton Powell (film)’, ’Giancarlo Esposito’]. +Thought: To find the documentary, I can search Adam Clayton Powell (film). +Action: Search[Adam Clayton Powell (film)] +Observation: Adam Clayton Powell is a 1989 American documentary film directed by Richard Kilberg. The film is about the rise and fall of influential African-American politician Adam Clayton Powell Jr.[3][4] It was later aired as part of the PBS series The American Experience. +Thought: Adam Clayton Powell (film) is a documentary about an African-American politician, not Finnish rock groups. So the documentary about Finnish rock groups must instead be The Saimaa Gesture. +Action: Finish[The Saimaa Gesture]""", """Question: What profession does Nicholas Ray and Elia Kazan have in common? -Thought 1: I need to search Nicholas Ray and Elia Kazan, find their professions, then -find the profession they have in common. -Action 1: Search[Nicholas Ray] -Observation 1: Nicholas Ray (born Raymond Nicholas Kienzle Jr., August 7, 1911 - June 16, -1979) was an American film director, screenwriter, and actor best known for -the 1955 film Rebel Without a Cause. -Thought 2: Professions of Nicholas Ray are director, screenwriter, and actor. I need -to search Elia Kazan next and find his professions. -Action 2: Search[Elia Kazan] -Observation 2: Elia Kazan was an American film and theatre director, producer, screenwriter -and actor. -Thought 3: Professions of Elia Kazan are director, producer, screenwriter, and actor. -So profession Nicholas Ray and Elia Kazan have in common is director, -screenwriter, and actor. -Action 3: Finish[director, screenwriter, actor]""", +Thought: I need to search Nicholas Ray and Elia Kazan, find their professions, then find the profession they have in common. +Action: Search[Nicholas Ray] +Observation: Nicholas Ray (born Raymond Nicholas Kienzle Jr., August 7, 1911 - June 16, 1979) was an American film director, screenwriter, and actor best known for the 1955 film Rebel Without a Cause. +Thought: Professions of Nicholas Ray are director, screenwriter, and actor. I need to search Elia Kazan next and find his professions. +Action: Search[Elia Kazan] +Observation: Elia Kazan was an American film and theatre director, producer, screenwriter and actor. +Thought: Professions of Elia Kazan are director, producer, screenwriter, and actor. So profession Nicholas Ray and Elia Kazan have in common is director, screenwriter, and actor. +Action: Finish[director, screenwriter, actor]""", """Question: Which magazine was started first Arthur’s Magazine or First for Women? -Thought 1: I need to search Arthur’s Magazine and First for Women, and find which was -started first. -Action 1: Search[Arthur’s Magazine] -Observation 1: Arthur’s Magazine (1844-1846) was an American literary periodical published -in Philadelphia in the 19th century. -Thought 2: Arthur’s Magazine was started in 1844. I need to search First for Women -next. -Action 2: Search[First for Women] -Observation 2: First for Women is a woman’s magazine published by Bauer Media Group in the -USA.[1] The magazine was started in 1989. -Thought 3: First for Women was started in 1989. 1844 (Arthur’s Magazine) < 1989 (First -for Women), so Arthur’s Magazine was started first. -Action 3: Finish[Arthur’s Magazine]""", +Thought: I need to search Arthur’s Magazine and First for Women, and find which was started first. +Action: Search[Arthur’s Magazine] +Observation: Arthur’s Magazine (1844-1846) was an American literary periodical published in Philadelphia in the 19th century. +Thought: Arthur’s Magazine was started in 1844. I need to search First for Women next. +Action: Search[First for Women] +Observation: First for Women is a woman’s magazine published by Bauer Media Group in the USA.[1] The magazine was started in 1989. +Thought: First for Women was started in 1989. 1844 (Arthur’s Magazine) < 1989 (First for Women), so Arthur’s Magazine was started first. +Action: Finish[Arthur’s Magazine]""", """Question: Were Pavel Urysohn and Leonid Levin known for the same type of work? -Thought 1: I need to search Pavel Urysohn and Leonid Levin, find their types of work, -then find if they are the same. -Action 1: Search[Pavel Urysohn] -Observation 1: Pavel Samuilovich Urysohn (February 3, 1898 - August 17, 1924) was a Soviet -mathematician who is best known for his contributions in dimension theory. -Thought 2: Pavel Urysohn is a mathematician. I need to search Leonid Levin next and -find its type of work. -Action 2: Search[Leonid Levin] -Observation 2: Leonid Anatolievich Levin is a Soviet-American mathematician and computer -scientist. -Thought 3: Leonid Levin is a mathematician and computer scientist. So Pavel Urysohn -and Leonid Levin have the same type of work. -Action 3: Finish[yes]""", +Thought: I need to search Pavel Urysohn and Leonid Levin, find their types of work, then find if they are the same. +Action: Search[Pavel Urysohn] +Observation: Pavel Samuilovich Urysohn (February 3, 1898 - August 17, 1924) was a Soviet mathematician who is best known for his contributions in dimension theory. +Thought: Pavel Urysohn is a mathematician. I need to search Leonid Levin next and find its type of work. +Action: Search[Leonid Levin] +Observation: Leonid Anatolievich Levin is a Soviet-American mathematician and computer scientist. +Thought: Leonid Levin is a mathematician and computer scientist. So Pavel Urysohn and Leonid Levin have the same type of work. +Action: Finish[yes]""", ] SUFFIX = """\nQuestion: {input} {agent_scratchpad}""" diff --git a/tests/unit_tests/agents/test_react.py b/tests/unit_tests/agents/test_react.py index bfd5238677..a0a486bcb9 100644 --- a/tests/unit_tests/agents/test_react.py +++ b/tests/unit_tests/agents/test_react.py @@ -55,7 +55,7 @@ class FakeDocstore(Docstore): def test_predict_until_observation_normal() -> None: """Test predict_until_observation when observation is made normally.""" - outputs = ["foo\nAction 1: Search[foo]"] + outputs = ["foo\nAction: Search[foo]"] fake_llm = FakeListLLM(responses=outputs) tools = [ Tool(name="Search", func=lambda x: x, description="foo"), @@ -77,16 +77,16 @@ def test_predict_until_observation_repeat() -> None: ] agent = ReActDocstoreAgent.from_llm_and_tools(fake_llm, tools) output = agent.plan([], input="") - expected_output = AgentAction("Search", "foo", "foo\nAction 1: Search[foo]") + expected_output = AgentAction("Search", "foo", "foo\nAction: Search[foo]") assert output == expected_output def test_react_chain() -> None: """Test react chain.""" responses = [ - "I should probably search\nAction 1: Search[langchain]", - "I should probably lookup\nAction 2: Lookup[made]", - "Ah okay now I know the answer\nAction 3: Finish[2022]", + "I should probably search\nAction: Search[langchain]", + "I should probably lookup\nAction: Lookup[made]", + "Ah okay now I know the answer\nAction: Finish[2022]", ] fake_llm = FakeListLLM(responses=responses) react_chain = ReActChain(llm=fake_llm, docstore=FakeDocstore()) @@ -98,8 +98,8 @@ def test_react_chain_bad_action() -> None: """Test react chain when bad action given.""" bad_action_name = "BadAction" responses = [ - f"I'm turning evil\nAction 1: {bad_action_name}[langchain]", - "Oh well\nAction 2: Finish[curses foiled again]", + f"I'm turning evil\nAction: {bad_action_name}[langchain]", + "Oh well\nAction: Finish[curses foiled again]", ] fake_llm = FakeListLLM(responses=responses) react_chain = ReActChain(llm=fake_llm, docstore=FakeDocstore())