Skip to content

Commit e2b9ef8

Browse files
authored
docs: add documentation for async tool usage and error handling (#9054)
* docs: add documentation for async tool usage and error handling - Introduced a new section in tools.md detailing the use of async tools with examples for `acall` and synchronous calls using `allow_tool_async_sync_conversion`. - Updated error message in Tool class to clarify how to handle async tool calls. - Enhanced test for async tool call in sync mode to match the updated error message. Signed-off-by: TomuHirata <tomu.hirata@gmail.com> * docs: enhance async tool documentation and usage examples - Added a new section on using async tools in synchronous contexts, including examples for temporary and global configuration of async-to-sync conversion. - Updated the Yahoo Finance tutorial to reflect the new async tool capabilities and link to the async tools documentation. Signed-off-by: TomuHirata <tomu.hirata@gmail.com> * docs: add asyncio import to async tool documentation example - Included the `import asyncio` statement in the example for calling async tools from synchronous code to clarify usage. Signed-off-by: TomuHirata <tomu.hirata@gmail.com> --------- Signed-off-by: TomuHirata <tomu.hirata@gmail.com>
1 parent e08bf0e commit e2b9ef8

File tree

5 files changed

+82
-4
lines changed

5 files changed

+82
-4
lines changed

docs/docs/learn/programming/tools.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,52 @@ the screenshot below:
213213

214214
Native function calling automatically detects model support using `litellm.supports_function_calling()`. If the model doesn't support native function calling, DSPy will fall back to manual text-based parsing even when `use_native_function_calling=True` is set.
215215

216+
## Async Tools
217+
218+
DSPy tools support both synchronous and asynchronous functions. When working with async tools, you have two options:
219+
220+
### Using `acall` for Async Tools
221+
222+
The recommended approach is to use `acall` when working with async tools:
223+
224+
```python
225+
import asyncio
226+
import dspy
227+
228+
async def async_weather(city: str) -> str:
229+
"""Get weather information asynchronously."""
230+
await asyncio.sleep(0.1) # Simulate async API call
231+
return f"The weather in {city} is sunny"
232+
233+
tool = dspy.Tool(async_weather)
234+
235+
# Use acall for async tools
236+
result = await tool.acall(city="New York")
237+
print(result)
238+
```
239+
240+
### Running Async Tools in Sync Mode
241+
242+
If you need to call an async tool from synchronous code, you can enable automatic conversion using the `allow_tool_async_sync_conversion` setting:
243+
244+
```python
245+
import asyncio
246+
import dspy
247+
248+
async def async_weather(city: str) -> str:
249+
"""Get weather information asynchronously."""
250+
await asyncio.sleep(0.1)
251+
return f"The weather in {city} is sunny"
252+
253+
tool = dspy.Tool(async_weather)
254+
255+
# Enable async-to-sync conversion
256+
with dspy.context(allow_tool_async_sync_conversion=True):
257+
# Now you can use __call__ on async tools
258+
result = tool(city="New York")
259+
print(result)
260+
```
261+
216262
## Best Practices
217263

218264
### 1. Tool Function Design

docs/docs/tutorials/async/index.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,33 @@ async def main():
9999
asyncio.run(main())
100100
```
101101

102+
#### Using Async Tools in Synchronous Contexts
103+
104+
If you need to call an async tool from synchronous code, you can enable automatic async-to-sync conversion:
105+
106+
```python
107+
import dspy
108+
109+
async def async_tool(x: int) -> int:
110+
"""An async tool that doubles a number."""
111+
await asyncio.sleep(0.1)
112+
return x * 2
113+
114+
tool = dspy.Tool(async_tool)
115+
116+
# Option 1: Use context manager for temporary conversion
117+
with dspy.context(allow_tool_async_sync_conversion=True):
118+
result = tool(x=5) # Works in sync context
119+
print(result) # 10
120+
121+
# Option 2: Configure globally
122+
dspy.configure(allow_tool_async_sync_conversion=True)
123+
result = tool(x=5) # Now works everywhere
124+
print(result) # 10
125+
```
126+
127+
For more details on async tools, see the [Tools documentation](../../learn/programming/tools.md#async-tools).
128+
102129
Note: When using `dspy.ReAct` with tools, calling `acall()` on the ReAct instance will automatically
103130
execute all tools asynchronously using their `acall()` methods.
104131

docs/docs/tutorials/yahoo_finance_react/index.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import yfinance as yf
2323

2424
# Configure DSPy
2525
lm = dspy.LM(model='openai/gpt-4o-mini')
26-
dspy.configure(lm=lm)
26+
dspy.configure(lm=lm, allow_tool_async_sync_conversion=True)
2727

2828
# Convert LangChain Yahoo Finance tool to DSPy
2929
yahoo_finance_tool = YahooFinanceNewsTool()
@@ -152,6 +152,10 @@ When you run the agent with a query like "What's the latest news about Apple?",
152152
Analysis: Given the current price of Apple (AAPL) at $196.58 and the slight increase of 0.48%, it appears that the stock is performing steadily in the market. However, the inability to access the latest news means that any significant developments that could influence investor sentiment and stock price are unknown. Investors should keep an eye on upcoming announcements or market trends that could impact Apple's performance, especially in comparison to other tech stocks like Microsoft (MSFT), which is also showing a positive trend.
153153
```
154154

155+
## Working with Async Tools
156+
157+
Many Langchain tools use async operations for better performance. For details on async tools, see the [Tools documentation](../../learn/programming/tools.md#async-tools).
158+
155159
## Key Benefits
156160

157161
- **Tool Integration**: Seamlessly combine LangChain tools with DSPy ReAct

dspy/adapters/types/tool.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,9 @@ def __call__(self, **kwargs):
179179
return self._run_async_in_sync(result)
180180
else:
181181
raise ValueError(
182-
"You are calling `__call__` on an async tool, please use `acall` instead or set "
183-
"`allow_async=True` to run the async tool in sync mode."
182+
"You are calling `__call__` on an async tool, please use `acall` instead or enable "
183+
"async-to-sync conversion with `dspy.configure(allow_tool_async_sync_conversion=True)` "
184+
"or `with dspy.context(allow_tool_async_sync_conversion=True):`."
184185
)
185186
return result
186187

tests/adapters/test_tool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ async def test_async_concurrent_calls():
385385
def test_async_tool_call_in_sync_mode():
386386
tool = Tool(async_dummy_function)
387387
with dspy.context(allow_tool_async_sync_conversion=False):
388-
with pytest.raises(ValueError):
388+
with pytest.raises(ValueError, match=r".*acall.*allow_tool_async_sync_conversion.*"):
389389
result = tool(x=1, y="hello")
390390

391391
with dspy.context(allow_tool_async_sync_conversion=True):

0 commit comments

Comments
 (0)