beta: logger (#307)

harrison/agent_multi_inputs
Harrison Chase 1 year ago committed by GitHub
parent 36b4c58acf
commit e02d6b2288
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,7 +12,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 6,
"id": "4e272b47",
"metadata": {},
"outputs": [],
@ -32,13 +32,13 @@
" )\n",
"]\n",
"\n",
"llm = OpenAI(temperature=0)\n",
"llm = OpenAI(temperature=0, model_name=\"text-davinci-002\")\n",
"react = initialize_agent(tools, llm, agent=\"react-docstore\", verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"id": "8078c8f1",
"metadata": {},
"outputs": [
@ -46,9 +46,31 @@
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new ReActDocstoreAgent chain...\u001b[0m\n",
"Author David Chanoff has collaborated with a U.S. Navy admiral who served as the ambassador to the United Kingdom under which President?\n",
"Thought 1:"
"Thought 1:\u001b[32;1m\u001b[1;3m 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 William J. Crowe served as the ambassador to the United Kingdom under President Bill Clinton.\n",
"Action 3: Finish[Bill Clinton]\u001b[0m\n",
"\u001b[1m> Finished ReActDocstoreAgent chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'Bill Clinton'"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@ -81,7 +103,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
"version": "3.10.8"
}
},
"nbformat": 4,

@ -15,6 +15,7 @@ from langchain.chains import (
)
from langchain.docstore import InMemoryDocstore, Wikipedia
from langchain.llms import Cohere, HuggingFaceHub, OpenAI
from langchain.logger import BaseLogger, StdOutLogger
from langchain.prompts import (
BasePromptTemplate,
FewShotPromptTemplate,
@ -25,6 +26,9 @@ from langchain.serpapi import SerpAPIChain, SerpAPIWrapper
from langchain.sql_database import SQLDatabase
from langchain.vectorstores import FAISS, ElasticVectorSearch
logger: BaseLogger = StdOutLogger()
verbose: bool = False
__all__ = [
"LLMChain",
"LLMBashChain",

@ -2,24 +2,18 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, ClassVar, Dict, List, NamedTuple, Optional, Tuple
from typing import Any, ClassVar, Dict, List, Optional, Tuple
from pydantic import BaseModel
from langchain.agents.input import ChainedInput
from langchain.agents.tools import Tool
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.input import ChainedInput, get_color_mapping
from langchain.input import get_color_mapping
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
class Action(NamedTuple):
"""Action to take."""
tool: str
tool_input: str
log: str
from langchain.schema import AgentAction
class Agent(Chain, BaseModel, ABC):
@ -99,7 +93,7 @@ class Agent(Chain, BaseModel, ABC):
llm_chain = LLMChain(llm=llm, prompt=cls.create_prompt(tools))
return cls(llm_chain=llm_chain, tools=tools, **kwargs)
def get_action(self, text: str) -> Action:
def get_action(self, text: str) -> AgentAction:
"""Given input, decided what to do.
Args:
@ -119,7 +113,7 @@ class Agent(Chain, BaseModel, ABC):
full_output += output
parsed_output = self._extract_tool_and_input(full_output)
tool, tool_input = parsed_output
return Action(tool, tool_input, full_output)
return AgentAction(tool, tool_input, full_output)
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
"""Run text through and get agent response."""
@ -145,7 +139,7 @@ class Agent(Chain, BaseModel, ABC):
# Call the LLM to see what to do.
output = self.get_action(chained_input.input)
# Add the log to the Chained Input.
chained_input.add(output.log, color="green")
chained_input.add_action(output, color="green")
# If the tool chosen is the finishing tool, then we end and return.
if output.tool == self.finish_tool_name:
return {self.output_key: output.tool_input}
@ -159,8 +153,9 @@ class Agent(Chain, BaseModel, ABC):
observation = f"{output.tool} is not a valid tool, try another one."
color = None
# We then log the observation
chained_input.add(f"\n{self.observation_prefix}")
chained_input.add(observation, color=color)
# We then add the LLM prefix into the prompt to get the LLM to start
# thinking, and start the loop all over.
chained_input.add(f"\n{self.llm_prefix}")
chained_input.add_observation(
observation,
self.observation_prefix,
self.llm_prefix,
color=color,
)

@ -0,0 +1,44 @@
"""Input manager for agents."""
from typing import Optional
import langchain
from langchain.schema import AgentAction
class ChainedInput:
"""Class for working with input that is the result of chains."""
def __init__(self, text: str, verbose: bool = False):
"""Initialize with verbose flag and initial text."""
self._verbose = verbose
if self._verbose:
langchain.logger.log_agent_start(text)
self._input = text
def add_action(self, action: AgentAction, color: Optional[str] = None) -> None:
"""Add text to input, print if in verbose mode."""
if self._verbose:
langchain.logger.log_agent_action(action, color=color)
self._input += action.log
def add_observation(
self,
observation: str,
observation_prefix: str,
llm_prefix: str,
color: Optional[str],
) -> None:
"""Add observation to input, print if in verbose mode."""
if self._verbose:
langchain.logger.log_agent_observation(
observation,
color=color,
observation_prefix=observation_prefix,
llm_prefix=llm_prefix,
)
self._input += f"\n{observation_prefix}{observation}\n{llm_prefix}"
@property
def input(self) -> str:
"""Return the accumulated input."""
return self._input

@ -2,7 +2,9 @@
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Extra
from pydantic import BaseModel, Extra, Field
import langchain
class Memory(BaseModel, ABC):
@ -28,12 +30,16 @@ class Memory(BaseModel, ABC):
"""Save the context of this model run to memory."""
def _get_verbosity() -> bool:
return langchain.verbose
class Chain(BaseModel, ABC):
"""Base interface that all chains should implement."""
memory: Optional[Memory] = None
verbose: bool = False
verbose: bool = Field(default_factory=_get_verbosity)
"""Whether to print out response text."""
@property

@ -3,8 +3,8 @@ from typing import Any, Dict, List, Union
from pydantic import BaseModel, Extra
import langchain
from langchain.chains.base import Chain
from langchain.input import print_text
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
@ -55,12 +55,13 @@ class LLMChain(Chain, BaseModel):
selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
prompt = self.prompt.format(**selected_inputs)
if self.verbose:
print("Prompt after formatting:")
print_text(prompt, color="green", end="\n")
langchain.logger.log_llm_inputs(selected_inputs, prompt)
kwargs = {}
if "stop" in inputs:
kwargs["stop"] = inputs["stop"]
response = self.llm(prompt, **kwargs)
if self.verbose:
langchain.logger.log_llm_response(response)
return {self.output_key: response}
def predict(self, **kwargs: Any) -> str:

@ -27,25 +27,3 @@ def print_text(text: str, color: Optional[str] = None, end: str = "") -> None:
else:
color_str = _TEXT_COLOR_MAPPING[color]
print(f"\u001b[{color_str}m\033[1;3m{text}\u001b[0m", end=end)
class ChainedInput:
"""Class for working with input that is the result of chains."""
def __init__(self, text: str, verbose: bool = False):
"""Initialize with verbose flag and initial text."""
self._verbose = verbose
if self._verbose:
print_text(text, color=None)
self._input = text
def add(self, text: str, color: Optional[str] = None) -> None:
"""Add text to input, print if in verbose mode."""
if self._verbose:
print_text(text, color=color)
self._input += text
@property
def input(self) -> str:
"""Return the accumulated input."""
return self._input

@ -0,0 +1,65 @@
"""BETA: everything in here is highly experimental, do not rely on."""
from typing import Any, Optional
from langchain.input import print_text
from langchain.schema import AgentAction
class BaseLogger:
"""Base logging interface."""
def log_agent_start(self, text: str, **kwargs: Any) -> None:
"""Log the start of an agent interaction."""
pass
def log_agent_end(self, text: str, **kwargs: Any) -> None:
"""Log the end of an agent interaction."""
pass
def log_agent_action(self, action: AgentAction, **kwargs: Any) -> None:
"""Log agent action decision."""
pass
def log_agent_observation(self, observation: str, **kwargs: Any) -> None:
"""Log agent observation."""
pass
def log_llm_inputs(self, inputs: dict, prompt: str, **kwargs: Any) -> None:
"""Log LLM inputs."""
pass
def log_llm_response(self, output: str, **kwargs: Any) -> None:
"""Log LLM response."""
pass
class StdOutLogger(BaseLogger):
"""Interface for printing things to stdout."""
def log_agent_start(self, text: str, **kwargs: Any) -> None:
"""Print the text to start the agent."""
print_text(text)
def log_agent_action(
self, action: AgentAction, color: Optional[str] = None, **kwargs: Any
) -> None:
"""Print the log of the action in a certain color."""
print_text(action.log, color=color)
def log_agent_observation(
self,
observation: str,
color: Optional[str] = None,
observation_prefix: Optional[str] = None,
llm_prefix: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Print the observation in a special color."""
print_text(f"\n{observation_prefix}")
print_text(observation, color=color)
print_text(f"\n{llm_prefix}")
def log_llm_inputs(self, inputs: dict, prompt: str, **kwargs: Any) -> None:
"""Print the prompt in green."""
print("Prompt after formatting:")
print_text(prompt, color="green", end="\n")

@ -0,0 +1,11 @@
"""Common schema objects."""
from typing import NamedTuple
class AgentAction(NamedTuple):
"""Agent's action to take."""
tool: str
tool_input: str
log: str

@ -3,7 +3,8 @@
import sys
from io import StringIO
from langchain.input import ChainedInput, get_color_mapping
from langchain.agents.input import ChainedInput
from langchain.input import get_color_mapping
def test_chained_input_not_verbose() -> None:
@ -18,11 +19,11 @@ def test_chained_input_not_verbose() -> None:
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
chained_input.add("bar")
chained_input.add_observation("bar", "1", "2", None)
sys.stdout = old_stdout
output = mystdout.getvalue()
assert output == ""
assert chained_input.input == "foobar"
assert chained_input.input == "foo\n1bar\n2"
def test_chained_input_verbose() -> None:
@ -37,19 +38,19 @@ def test_chained_input_verbose() -> None:
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
chained_input.add("bar")
chained_input.add_observation("bar", "1", "2", None)
sys.stdout = old_stdout
output = mystdout.getvalue()
assert output == "bar"
assert chained_input.input == "foobar"
assert output == "\n1bar\n2"
assert chained_input.input == "foo\n1bar\n2"
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
chained_input.add("baz", color="blue")
chained_input.add_observation("baz", "3", "4", "blue")
sys.stdout = old_stdout
output = mystdout.getvalue()
assert output == "\x1b[36;1m\x1b[1;3mbaz\x1b[0m"
assert chained_input.input == "foobarbaz"
assert output == "\n3\x1b[36;1m\x1b[1;3mbaz\x1b[0m\n4"
assert chained_input.input == "foo\n1bar\n2\n3baz\n4"
def test_get_color_mapping() -> None:

Loading…
Cancel
Save