langchain-ai / langchain

šŸ¦œšŸ”— Build context-aware reasoning applications
https://python.langchain.com
MIT License
92.22k stars 14.72k forks source link

Adding DuckDuckGo search HTTPError handling #13556

Closed edwardmfho closed 6 months ago

edwardmfho commented 9 months ago

System Info

Bumped into HTTPError when using DuckDuckGo search wrapper in an agent, currently using langchain==0.0.336.

Here's the snippet of the traceback as below.

  File "/path/to/venv/lib/python3.10/site-packages/langchain/utilities/duckduckgo_search.py", line 64, in run
    snippets = self.get_snippets(query)
  File "/path/to/venv/lib/python3.10/site-packages/langchain/utilities/duckduckgo_search.py", line 55, in get_snippets
    for i, res in enumerate(results, 1):
  File "/path/to/venv/lib/python3.10/site-packages/duckduckgo_search/duckduckgo_search.py", line 96, in text
    for i, result in enumerate(results, start=1):
  File "/path/to/venv/lib/python3.10/site-packages/duckduckgo_search/duckduckgo_search.py", line 148, in _text_api
    resp = self._get_url("GET", "https://links.duckduckgo.com/d.js", params=payload)
  File "/path/to/venv/lib/python3.10/site-packages/duckduckgo_search/duckduckgo_search.py", line 55, in _get_url
    raise ex
  File "/path/to/venv/lib/python3.10/site-packages/duckduckgo_search/duckduckgo_search.py", line 48, in _get_url
    raise httpx._exceptions.HTTPError("")
httpx.HTTPError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/path/to/src/single_host.py", line 179, in <module>
    response = chain({"topic": "Why did Sam Altman got fired by OpenAI.", 
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 310, in __call__
    raise e
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 306, in __call__
    else self._call(inputs)
  File "/path/to/src/single_host.py", line 163, in _call
    script = script_chain.run({"topic": inputs["topic"], "focuses": inputs["focuses"], "keypoints": keypoints})
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 505, in run
    return self(args[0], callbacks=callbacks, tags=tags, metadata=metadata)[
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 310, in __call__
    raise e
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 306, in __call__
    else self._call(inputs)
  File "/path/to/src/single_host.py", line 117, in _call
    information = agent.run(background_info_search_formatted)
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 505, in run
    return self(args[0], callbacks=callbacks, tags=tags, metadata=metadata)[
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 310, in __call__
    raise e
  File "/path/to/venv/lib/python3.10/site-packages/langchain/chains/base.py", line 304, in __call__
    self._call(inputs, run_manager=run_manager)
  File "/path/to/venv/lib/python3.10/site-packages/langchain/agents/agent.py", line 1245, in _call
    next_step_output = self._take_next_step(
  File "/path/to/venv/lib/python3.10/site-packages/langchain/agents/agent.py", line 1095, in _take_next_step
    observation = tool.run(
  File "/path/to/venv/lib/python3.10/site-packages/langchain/tools/base.py", line 344, in run
    raise e
  File "/path/to/venv/lib/python3.10/site-packages/langchain/tools/base.py", line 337, in run
    self._run(*tool_args, run_manager=run_manager, **tool_kwargs)
  File "/path/to/venv/lib/python3.10/site-packages/langchain/tools/base.py", line 510, in _run
    self.func(
  File "/path/to/venv/lib/python3.10/site-packages/langchain/tools/base.py", line 344, in run
    raise e
  File "/path/to/venv/lib/python3.10/site-packages/langchain/tools/base.py", line 337, in run
    self._run(*tool_args, run_manager=run_manager, **tool_kwargs)
  File "/path/to/venv/lib/python3.10/site-packages/langchain/tools/ddg_search/tool.py", line 36, in _run
    return self.api_wrapper.run(query)
  File "/path/to/venv/lib/python3.10/site-packages/langchain/utilities/duckduckgo_search.py", line 67, in run
    raise ToolException("DuckDuckGo Search encountered HTTPError.")

I tried to add an error handling in the method run() in langchain/utilities/duckduckgo_search.py, something look like below:

def run(self, query: str) -> str:
        try:
            snippets = self.get_snippets(query)
            return " ".join(snippets)
        except httpx._exceptions.HTTPError as e:
            raise ToolException("DuckDuckGo Search encountered HTTPError.")

I have also added handle_tool_error, where it was copied from the langchain documentation

def _handle_error(error: ToolException) -> str:
    return (
        "The following errors occurred during tool execution:"
        + error.args[0]
        + "Please try another tool."
    )

However these methods do not seems to stop and still cause the error showed in first code block above. Am I implementing this incorrectly? or should there be other mechanism to handle the error occuried?

Who can help?

No response

Information

Related Components

Reproduction

  1. Adding handle_tool_errors and passing the _handle_error function into it.
news_tool = Tool.from_function(name="News Search", 
                   func=news_duckduckgo.run, 
                   description="News search to help you look up latest news, which help you to understand latest current affair, and being up-to-date.",
                   handle_tool_errors=_handle_error)
  1. Does not seems to work, so I tried to change the DuckDuckGo Wrapper, as described above.
  2. HTTPError still lead to abrupt stop of Agent actions.

Expected behavior

Expecting a proper error handling method, if tool fails, Agent moves on, or try n time before moving on to next step.

dosubot[bot] commented 9 months ago

šŸ¤–

Hello @edwardmfho,

Nice to meet you! I'm a bot here to assist you with your LangChain issues while we wait for a human maintainer. I'm here to help you debug issues, answer any questions, and guide you through your contribution journey.

I'm currently looking into the issue you've reported regarding the HTTPError handling in the DuckDuckGo search wrapper. I'll get back to you with a full response soon. Hang tight!

dosubot[bot] commented 9 months ago

šŸ¤–

Hello @edwardmfho,

Nice to meet you! I'm here to assist you with any issues you're encountering with the LangChain repository. While we wait for a human maintainer to join us, I'll do my best to help you solve bugs, answer questions and guide you in contributing to the project. Please remember I'm here to help!

Looking forward to working together!

From the traceback you provided, it seems that the HTTPError is being raised from the duckduckgo_search package, which is used by the DuckDuckGoSearch tool in LangChain. The error is not being caught and handled within the DuckDuckGoSearch tool, which is why it's propagating up the call stack and causing the agent to stop execution.

The handle_tool_error attribute and the _handle_error function you added are correctly implemented according to the LangChain documentation. However, they are not being invoked because the HTTPError is not being caught and converted into a ToolException within the DuckDuckGoSearch tool.

To fix this issue, you need to catch the HTTPError within the DuckDuckGoSearch tool and raise a ToolException instead. Here's how you can modify the run method in langchain/utilities/duckduckgo_search.py:

def run(self, query: str) -> str:
    try:
        snippets = self.get_snippets(query)
        return " ".join(snippets)
    except httpx.HTTPError as e:
        raise ToolException("DuckDuckGo Search encountered HTTPError.") from e

This will ensure that the HTTPError is caught and a ToolException is raised instead. The ToolException will then be handled by the LangChain framework according to the handle_tool_error attribute of the DuckDuckGoSearch tool.

Please note that you need to import the ToolException class at the top of your duckduckgo_search.py file:

from langchain.tools.base import ToolException

I hope this helps! Let me know if you have any other questions.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a šŸ‘ if this is helpful and šŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

edwardmfho commented 9 months ago

@dosu-bot the proposed solution does not seems to be working, HTTPError still lead to the execution stopped.

Traceback as below:

raise ToolException("DuckDuckGo Search encountered HTTPError. See error message: {e}")
langchain.tools.base.ToolException: DuckDuckGo Search encountered HTTPError. See error message: {e}
dosubot[bot] commented 9 months ago

šŸ¤–

From the traceback you've provided, it seems like the error message isn't being formatted correctly. The {e} in your error message is supposed to be a placeholder for the actual error message, but it's not being replaced with the error message because you're not using an f-string. Here's how you can fix it:

def run(self, query: str) -> str:
    try:
        snippets = self.get_snippets(query)
        return " ".join(snippets)
    except httpx.HTTPError as e:
        raise ToolException(f"DuckDuckGo Search encountered HTTPError. See error message: {e}") from e

In the above code, I've added an f before the string to make it an f-string, which allows for embedded expressions inside string literals.

As for the _handle_error function, it seems like you're trying to concatenate a string with an exception, which will raise a TypeError. You should convert the exception to a string before concatenating it with another string. Here's how you can do it:

def _handle_error(error: ToolException) -> str:
    return (
        "The following errors occurred during tool execution:"
        + str(error.args[0])
        + "Please try another tool."
    )

In the above code, I've used the str function to convert the exception to a string.

I hope this helps! Let me know if you have any other questions.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a šŸ‘ if this is helpful and šŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

edwardmfho commented 9 months ago

@dosu-bot good spot on the error message in the duckduckgo file. However, execution still stopped when HTTPError was raised:

The expected error handling message returned by _handle_error did not return the following:

"The following errors occurred during tool execution:"
        + error.args[0]
        + "Please try another tool."
dosubot[bot] commented 9 months ago

šŸ¤–

Based on the code snippets you've provided, it seems like you're correctly raising the ToolException when an httpx.HTTPError is encountered. However, the _handle_error function isn't being called when the exception is raised. This could be because the ToolException isn't being caught and handled properly.

In LangChain, the ToolException is typically caught and handled in the run_tool function, which is where the run method of the tool is called. Here's an example of how the run_tool function might look like:

def run_tool(self, tool: Tool, *args, **kwargs) -> Any:
    try:
        return tool.run(*args, **kwargs)
    except ToolException as e:
        return self._handle_error(e)

In this function, the run method of the tool is called inside a try block. If a ToolException is raised during the execution of the run method, it's caught in the except block and the _handle_error function is called with the caught exception.

If you've implemented the run_tool function in a similar way and the _handle_error function is still not being called, it could be because the ToolException is being caught and handled somewhere else before it reaches the run_tool function. In that case, you might want to check the rest of your code to see if there's anywhere where a ToolException could be caught and handled before it reaches the run_tool function.

If you're still having trouble, could you provide more information about how you're using the run_tool function and where it's located in your code? This could help identify why the _handle_error function isn't being called as expected.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a šŸ‘ if this is helpful and šŸ‘Ž if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

edwardmfho commented 9 months ago

To check if the handle_error function works, the following is implemented.

def _handle_error(error: ToolException) -> str:
    return (
        "The following errors occurred during tool execution:"
        + error.args[0]
        + "Please try another tool."
    )

def test_tool(test_input):
    raise ToolException("This tool is to test ToolException.")

t_tool = Tool.from_function(name="Test Tool", 
                   func=test_tool,
                   description="This tool is to test custom handle_tool_error.",
                   handle_tool_errors=_handle_error)

However, when I use agent.run to run, and force it to use the tool, the agent still stopped and the following error message is generated in console:

langchain.tools.base.ToolException: This tool is to test ToolException.

dosubot[bot] commented 6 months ago

Hi, @edwardmfho,

I'm helping the LangChain team manage their backlog and am marking this issue as stale. It looks like you encountered an HTTPError when using the DuckDuckGo search wrapper in an agent. You attempted to add error handling in the run() method of langchain/utilities/duckduckgo_search.py and also added a handle_tool_error method, but the error persists and causes the agent to abruptly stop. There was a back-and-forth discussion with the bot to troubleshoot the issue, including suggestions on using f-strings for error message formatting and checking the implementation of the run_tool function.

Could you please confirm if this issue is still relevant to the latest version of the LangChain repository? If it is, please let the LangChain team know by commenting on the issue. Otherwise, feel free to close the issue yourself, or the issue will be automatically closed in 7 days. Thank you!