langchain
langchain copied to clipboard
Async Support | Search Tools
Feature request
None of the search tools have async support.
Motivation
Async calls are being used langchain setup with FastAPI. Not having async support for these tools blocks there use.
Your contribution
Happy to help out where needed.
I faced the same problem and created a custom tool to handle it. here's the code for your reference.
import os
from langchain.agents import Tool
from dotenv import load_dotenv
import aiohttp
async def search_bing(query):
subscription_key = str(os.getenv("BING_SUBSCRIPTION_KEY"))
endpoint = str(os.getenv("BING_SEARCH_URL"))
headers = {"Ocp-Apim-Subscription-Key": subscription_key}
params = {"q": query, "count": 3}
async with aiohttp.ClientSession() as session:
async with session.get(endpoint, headers=headers, params=params) as response:
response.raise_for_status()
return await response.json()
a_bing_tool = Tool(
name = "search",
func=search_bing,
description="useful for when you need to answer questions about current events",
coroutine=search_bing
)
Hi, @jordanparker6! I'm Dosu, and I'm helping the LangChain team manage their backlog. I wanted to let you know that we are marking this issue as stale.
From what I understand, this issue is a feature request to add async support to the search tools. It seems that not having async support is blocking the use of these tools in a FastAPI setup. Another user named somethingwentwell faced the same problem and created a custom tool to handle it, providing code as a reference. This comment received positive reactions from other users, indicating that it may be a viable solution.
Before we close this issue, we wanted to check with you if it is still relevant to the latest version of the LangChain repository. If it is, please let us know by commenting on the issue. Otherwise, feel free to close the issue yourself or it will be automatically closed in 7 days.
Thank you for your understanding and contribution to the LangChain project!
I think a more general purpose solution available to make any tool async (not fully native async but does the purpose) Use asyncer library to convert a sync function to async. For example DuckDuckGo search tool doesn't have a _arun
function
but it is pretty easy to implement one
from asyncer import asyncify
class DuckDuckGoSearchRun(BaseTool):
"""Tool that queries the DuckDuckGo search API."""
name = "duckduckgo_search"
description = ("...")
...
def _run(...) -> Any:
"..."
def _arun(self, *args: Any, **kwargs: Any) -> Any:
"""Async version of the tool"""
return asyncify(self._run, cancellable=True)(*args, **kwargs)
@baskaryan Could you please help @jordanparker6 with this issue? They have indicated that the issue is still relevant and provided a potential solution using the asyncer library. Thank you!
Please disregard as this has been addressed in https://github.com/langchain-ai/langchain/pull/10058 recently. No need anymore
Please disregard as this has been addressed in #10058 recently. No need anymore
Is there an example of how to use this async tool? I have used the arun and run but still it is calling run though I run this tool with the agent using await
Also can we use async with tool decorator ? I am using latest version and when I use the code like below it says tool doesnt support async
@tool
async def profile_summary_data_retriever() -> str:
"""Use this for finding user specific portfolio summary and alters performance"""
try:
api_url = "http://api"
# response = requests.get(api_url)
async with httpx.AsyncClient() as client:
response = await client.get(api_url)
alters_data = response.json()
return alters_data
except Exception as e: print(f"Error: {e}")
I have the same problem. My agent chain needs to call the function several times for different parameters, and it doesn't seem to perform that asynchronously. I'm using llm_agent.ainvoke function, and defined my tool function to have _run and _arun properly. Doesn't seem to work. It is still calling tool sequencially
🤖
Thank you for your feature request and your willingness to contribute. It seems there might be a misunderstanding about the current async support in LangChain. The search tools in LangChain, specifically the TavilySearchAPIWrapper
class, already have async support. This is evident from the raw_results_async
and results_async
methods in the class. These methods use the aiohttp
library to make asynchronous HTTP requests to the Tavily Search API. Here is the code for these methods:
# raw_results_async method
async def raw_results_async(
self,
query: str,
max_results: Optional[int] = 5,
search_depth: Optional[str] = "advanced",
include_domains: Optional[List[str]] = [],
exclude_domains: Optional[List[str]] = [],
include_answer: Optional[bool] = False,
include_raw_content: Optional[bool] = False,
include_images: Optional[bool] = False,
) -> Dict:
"""Get results from the Tavily Search API asynchronously."""
# Function to perform the API call
async def fetch() -> str:
params = {
"api_key": self.tavily_api_key.get_secret_value(),
"query": query,
"max_results": max_results,
"search_depth": search_depth,
"include_domains": include_domains,
"exclude_domains": exclude_domains,
"include_answer": include_answer,
"include_raw_content": include_raw_content,
"include_images": include_images,
}
async with aiohttp.ClientSession() as session:
async with session.post(f"{TAVILY_API_URL}/search", json=params) as res:
if res.status == 200:
data = await res.text()
return data
else:
raise Exception(f"Error {res.status}: {res.reason}")
results_json_str = await fetch()
return json.loads(results_json_str)
# results_async method
async def results_async(
self,
query: str,
max_results: Optional[int] = 5,
search_depth: Optional[str] = "advanced",
include_domains: Optional[List[str]] = [],
exclude_domains: Optional[List[str]] = [],
include_answer: Optional[bool] = False,
include_raw_content: Optional[bool] = False,
include_images: Optional[bool] = False,
) -> List[Dict]:
results_json = await self.raw_results_async(
query=query,
max_results=max_results,
search_depth=search_depth,
include_domains=include_domains,
exclude_domains=exclude_domains,
include_answer=include_answer,
include_raw_content=include_raw_content,
include_images=include_images,
)
return self.clean_results(results_json["results"])
You can find these methods in the TavilySearchAPIWrapper class.
However, if you're referring to other search tools in the LangChain codebase, such as BingSearchRun
, DuckDuckGoSearchRun
, GoogleSearchResults
, GoogleSearchRun
, MetaphorSearchResults
, GoogleSerperResults
, GoogleSerperRun
, SearchAPIResults
, SearchAPIRun
, SearxSearchResults
, SearxSearchRun
, or RedditSearchRun
, could you please provide more specific details about the async support you're looking for? This will help us understand your request better and provide a more accurate response.
Sources
- libs/community/langchain_community/utilities/tavily_search.py
- libs/langchain/langchain/tools/ddg_search/init.py
- libs/langchain/langchain/tools/google_search/init.py
- libs/langchain/langchain/agents/load_tools.py
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.