*   [](/v0.2/)
*   [How-to guides](/v0.2/docs/how_to/)
*   How to add a human-in-the-loop for tools

On this page

How to add a human-in-the-loop for tools
========================================

There are certain tools that we don't trust a model to execute on its own. One thing we can do in such situations is require human approval before the tool is invoked.

info

This how-to guide shows a simple way to add human-in-the-loop for code running in a jupyter notebook or in a terminal.

To build a production application, you will need to do more work to keep track of application state appropriately.

We recommend using `langgraph` for powering such a capability. For more details, please see this [guide](https://langchain-ai.github.io/langgraph/how-tos/human-in-the-loop/).

Setup[​](#setup "Direct link to Setup")
---------------------------------------

We'll need to install the following packages:

    %pip install --upgrade --quiet langchain

And set these environment variables:

    import getpassimport os# If you'd like to use LangSmith, uncomment the below:# os.environ["LANGCHAIN_TRACING_V2"] = "true"# os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()

Chain[​](#chain "Direct link to Chain")
---------------------------------------

Let's create a few simple (dummy) tools and a tool-calling chain:

*   OpenAI
*   Anthropic
*   Azure
*   Google
*   Cohere
*   FireworksAI
*   Groq
*   MistralAI
*   TogetherAI

    pip install -qU langchain-openai

    import getpassimport osos.environ["OPENAI_API_KEY"] = getpass.getpass()from langchain_openai import ChatOpenAIllm = ChatOpenAI(model="gpt-3.5-turbo-0125")

    pip install -qU langchain-anthropic

    import getpassimport osos.environ["ANTHROPIC_API_KEY"] = getpass.getpass()from langchain_anthropic import ChatAnthropicllm = ChatAnthropic(model="claude-3-sonnet-20240229")

    pip install -qU langchain-openai

    import getpassimport osos.environ["AZURE_OPENAI_API_KEY"] = getpass.getpass()from langchain_openai import AzureChatOpenAIllm = AzureChatOpenAI(    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],    azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],    openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],)

    pip install -qU langchain-google-vertexai

    import getpassimport osos.environ["GOOGLE_API_KEY"] = getpass.getpass()from langchain_google_vertexai import ChatVertexAIllm = ChatVertexAI(model="gemini-pro")

    pip install -qU langchain-cohere

    import getpassimport osos.environ["COHERE_API_KEY"] = getpass.getpass()from langchain_cohere import ChatCoherellm = ChatCohere(model="command-r")

    pip install -qU langchain-fireworks

    import getpassimport osos.environ["FIREWORKS_API_KEY"] = getpass.getpass()from langchain_fireworks import ChatFireworksllm = ChatFireworks(model="accounts/fireworks/models/mixtral-8x7b-instruct")

    pip install -qU langchain-groq

    import getpassimport osos.environ["GROQ_API_KEY"] = getpass.getpass()from langchain_groq import ChatGroqllm = ChatGroq(model="llama3-8b-8192")

    pip install -qU langchain-mistralai

    import getpassimport osos.environ["MISTRAL_API_KEY"] = getpass.getpass()from langchain_mistralai import ChatMistralAIllm = ChatMistralAI(model="mistral-large-latest")

    pip install -qU langchain-openai

    import getpassimport osos.environ["TOGETHER_API_KEY"] = getpass.getpass()from langchain_openai import ChatOpenAIllm = ChatOpenAI(    base_url="https://api.together.xyz/v1",    api_key=os.environ["TOGETHER_API_KEY"],    model="mistralai/Mixtral-8x7B-Instruct-v0.1",)

    from typing import Dict, Listfrom langchain_core.messages import AIMessagefrom langchain_core.runnables import Runnable, RunnablePassthroughfrom langchain_core.tools import tool@tooldef count_emails(last_n_days: int) -> int:    """Multiply two integers together."""    return last_n_days * 2@tooldef send_email(message: str, recipient: str) -> str:    "Add two integers."    return f"Successfully sent email to {recipient}."tools = [count_emails, send_email]llm_with_tools = llm.bind_tools(tools)def call_tools(msg: AIMessage) -> List[Dict]:    """Simple sequential tool calling helper."""    tool_map = {tool.name: tool for tool in tools}    tool_calls = msg.tool_calls.copy()    for tool_call in tool_calls:        tool_call["output"] = tool_map[tool_call["name"]].invoke(tool_call["args"])    return tool_callschain = llm_with_tools | call_toolschain.invoke("how many emails did i get in the last 5 days?")

**API Reference:**[AIMessage](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.ai.AIMessage.html) | [Runnable](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html) | [RunnablePassthrough](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.passthrough.RunnablePassthrough.html) | [tool](https://api.python.langchain.com/en/latest/tools/langchain_core.tools.tool.html)

    [{'name': 'count_emails',  'args': {'last_n_days': 5},  'id': 'toolu_01QYZdJ4yPiqsdeENWHqioFW',  'output': 10}]

Adding human approval[​](#adding-human-approval "Direct link to Adding human approval")
---------------------------------------------------------------------------------------

Let's add a step in the chain that will ask a person to approve or reject the tall call request.

On rejection, the step will raise an exception which will stop execution of the rest of the chain.

    import jsonclass NotApproved(Exception):    """Custom exception."""def human_approval(msg: AIMessage) -> AIMessage:    """Responsible for passing through its input or raising an exception.    Args:        msg: output from the chat model    Returns:        msg: original output from the msg    """    tool_strs = "\n\n".join(        json.dumps(tool_call, indent=2) for tool_call in msg.tool_calls    )    input_msg = (        f"Do you approve of the following tool invocations\n\n{tool_strs}\n\n"        "Anything except 'Y'/'Yes' (case-insensitive) will be treated as a no.\n >>>"    )    resp = input(input_msg)    if resp.lower() not in ("yes", "y"):        raise NotApproved(f"Tool invocations not approved:\n\n{tool_strs}")    return msg

    chain = llm_with_tools | human_approval | call_toolschain.invoke("how many emails did i get in the last 5 days?")

    Do you approve of the following tool invocations{  "name": "count_emails",  "args": {    "last_n_days": 5  },  "id": "toolu_01WbD8XeMoQaRFtsZezfsHor"}Anything except 'Y'/'Yes' (case-insensitive) will be treated as a no. >>> yes

    [{'name': 'count_emails',  'args': {'last_n_days': 5},  'id': 'toolu_01WbD8XeMoQaRFtsZezfsHor',  'output': 10}]

    try:    chain.invoke("Send sally@gmail.com an email saying 'What's up homie'")except NotApproved as e:    print()    print(e)

    Do you approve of the following tool invocations{  "name": "send_email",  "args": {    "recipient": "sally@gmail.com",    "message": "What's up homie"  },  "id": "toolu_014XccHFzBiVcc9GV1harV9U"}Anything except 'Y'/'Yes' (case-insensitive) will be treated as a no. >>> no``````outputTool invocations not approved:{  "name": "send_email",  "args": {    "recipient": "sally@gmail.com",    "message": "What's up homie"  },  "id": "toolu_014XccHFzBiVcc9GV1harV9U"}

[Edit this page](https://github.com/langchain-ai/langchain/edit/master/docs/docs/how_to/tools_human.ipynb)

* * *

#### Was this page helpful?

  

#### You can also leave detailed feedback [on GitHub](https://github.com/langchain-ai/langchain/issues/new?assignees=&labels=03+-+Documentation&projects=&template=documentation.yml&title=DOC%3A+%3CPlease+write+a+comprehensive+title+after+the+%27DOC%3A+%27+prefix%3E).

[

Previous

How to use few-shot prompting with tool calling

](/v0.2/docs/how_to/tools_few_shot/)[

Next

How to bind model-specific tools

](/v0.2/docs/how_to/tools_model_specific/)

*   [Setup](#setup)
*   [Chain](#chain)
*   [Adding human approval](#adding-human-approval)