*   [](/v0.2/)
*   [How-to guides](/v0.2/docs/how_to/)
*   How to use callbacks in async environments

On this page

How to use callbacks in async environments
==========================================

Prerequisites

This guide assumes familiarity with the following concepts:

*   [Callbacks](/v0.2/docs/concepts/#callbacks)
*   [Custom callback handlers](/v0.2/docs/how_to/custom_callbacks/)

If you are planning to use the async APIs, it is recommended to use and extend [`AsyncCallbackHandler`](https://api.python.langchain.com/en/latest/callbacks/langchain_core.callbacks.base.AsyncCallbackHandler.html) to avoid blocking the event.

danger

If you use a sync `CallbackHandler` while using an async method to run your LLM / Chain / Tool / Agent, it will still work. However, under the hood, it will be called with [`run_in_executor`](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor) which can cause issues if your `CallbackHandler` is not thread-safe.

danger

If you're on `python<=3.10`, you need to remember to propagate `config` or `callbacks` when invoking other `runnable` from within a `RunnableLambda`, `RunnableGenerator` or `@tool`. If you do not do this, the callbacks will not be propagated to the child runnables being invoked.

    import asynciofrom typing import Any, Dict, Listfrom langchain_anthropic import ChatAnthropicfrom langchain_core.callbacks import AsyncCallbackHandler, BaseCallbackHandlerfrom langchain_core.messages import HumanMessagefrom langchain_core.outputs import LLMResultclass MyCustomSyncHandler(BaseCallbackHandler):    def on_llm_new_token(self, token: str, **kwargs) -> None:        print(f"Sync handler being called in a `thread_pool_executor`: token: {token}")class MyCustomAsyncHandler(AsyncCallbackHandler):    """Async callback handler that can be used to handle callbacks from langchain."""    async def on_llm_start(        self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any    ) -> None:        """Run when chain starts running."""        print("zzzz....")        await asyncio.sleep(0.3)        class_name = serialized["name"]        print("Hi! I just woke up. Your llm is starting")    async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:        """Run when chain ends running."""        print("zzzz....")        await asyncio.sleep(0.3)        print("Hi! I just woke up. Your llm is ending")# To enable streaming, we pass in `streaming=True` to the ChatModel constructor# Additionally, we pass in a list with our custom handlerchat = ChatAnthropic(    model="claude-3-sonnet-20240229",    max_tokens=25,    streaming=True,    callbacks=[MyCustomSyncHandler(), MyCustomAsyncHandler()],)await chat.agenerate([[HumanMessage(content="Tell me a joke")]])

**API Reference:**[ChatAnthropic](https://api.python.langchain.com/en/latest/chat_models/langchain_anthropic.chat_models.ChatAnthropic.html) | [AsyncCallbackHandler](https://api.python.langchain.com/en/latest/callbacks/langchain_core.callbacks.base.AsyncCallbackHandler.html) | [BaseCallbackHandler](https://api.python.langchain.com/en/latest/callbacks/langchain_core.callbacks.base.BaseCallbackHandler.html) | [HumanMessage](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.human.HumanMessage.html) | [LLMResult](https://api.python.langchain.com/en/latest/outputs/langchain_core.outputs.llm_result.LLMResult.html)

    zzzz....Hi! I just woke up. Your llm is startingSync handler being called in a `thread_pool_executor`: token: HereSync handler being called in a `thread_pool_executor`: token: 'sSync handler being called in a `thread_pool_executor`: token:  aSync handler being called in a `thread_pool_executor`: token:  littleSync handler being called in a `thread_pool_executor`: token:  jokeSync handler being called in a `thread_pool_executor`: token:  forSync handler being called in a `thread_pool_executor`: token:  youSync handler being called in a `thread_pool_executor`: token: :Sync handler being called in a `thread_pool_executor`: token: WhySync handler being called in a `thread_pool_executor`: token:  canSync handler being called in a `thread_pool_executor`: token: 'tSync handler being called in a `thread_pool_executor`: token:  aSync handler being called in a `thread_pool_executor`: token:  bicycleSync handler being called in a `thread_pool_executor`: token:  stanSync handler being called in a `thread_pool_executor`: token: d upSync handler being called in a `thread_pool_executor`: token:  bySync handler being called in a `thread_pool_executor`: token:  itselfSync handler being called in a `thread_pool_executor`: token: ?Sync handler being called in a `thread_pool_executor`: token:  BecauseSync handler being called in a `thread_pool_executor`: token:  itSync handler being called in a `thread_pool_executor`: token: 'sSync handler being called in a `thread_pool_executor`: token:  twoSync handler being called in a `thread_pool_executor`: token: -Sync handler being called in a `thread_pool_executor`: token: tirezzzz....Hi! I just woke up. Your llm is ending

    LLMResult(generations=[[ChatGeneration(text="Here's a little joke for you:\n\nWhy can't a bicycle stand up by itself? Because it's two-tire", message=AIMessage(content="Here's a little joke for you:\n\nWhy can't a bicycle stand up by itself? Because it's two-tire", id='run-8afc89e8-02c0-4522-8480-d96977240bd4-0'))]], llm_output={}, run=[RunInfo(run_id=UUID('8afc89e8-02c0-4522-8480-d96977240bd4'))])

Next steps[​](#next-steps "Direct link to Next steps")
------------------------------------------------------

You've now learned how to create your own custom callback handlers.

Next, check out the other how-to guides in this section, such as [how to attach callbacks to a runnable](/v0.2/docs/how_to/callbacks_attach/).

[Edit this page](https://github.com/langchain-ai/langchain/edit/master/docs/docs/how_to/callbacks_async.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

Caching

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

Next

How to attach callbacks to a runnable

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

*   [Next steps](#next-steps)