langchain-ai / langchain

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

Nested ainvoke does not show as child in tracing #23811

Open MartinoMensio opened 2 months ago

MartinoMensio commented 2 months ago

Checked other resources

Example Code

from dotenv import load_dotenv
from langchain_core.runnables import Runnable, RunnableConfig, chain
from langchain_core.tracers.context import tracing_v2_enabled
from phoenix.trace.langchain import LangChainInstrumentor

LangChainInstrumentor().instrument()
load_dotenv()

@chain
def inner_chain(input):
    print("inner chain")
    return {"inner": input}

@chain
def outer_chain(input):
    print("outer chain")
    return inner_chain.invoke(input={"inner": "foo_sync"})

@chain
async def outer_chain_async(input):
    print("outer chain async")
    return await inner_chain.ainvoke(input={"inner": "foo_async"})

async def main_async():
    # call async the outsider that inside has a sync call
    await outer_chain.ainvoke(input={"outer": "foo"})
    # call async the outsider that inside has a async call
    await outer_chain_async.ainvoke(input={"outer": "foo_async_outer"})

def main():
    outer_chain.invoke(input={"outer": "foo"})

if __name__ == "__main__":
    with tracing_v2_enabled(project_name="test"):
        # call sync
        main()
        # call async
        import asyncio

        asyncio.run(main_async())

Error Message and Stack Trace (if applicable)

The inner chain should be attached as child to the outer chain. Instead the async calls are shown as independent traces.

Arize-phoenix traces: image

Langsmith traces: image

Description

I am analysing the traces generated with invoke and ainvoke function on a chain that is innerly calling another chain.

For the sync run, the inner chain is properly traced under the outer chain. Instead when the ainvoke is called on the outer chain, the inner chain is traced as separate. I would expect that both invoke and ainvoke produce the same traces.

I think the problem might be in the run_in_executor function that is called in the Runnable.ainvoke, that may be missing some parameters to the self.invoke about the context of the parent chain.

I tested it with two different tracing solutions:

Environment requirements:

langchain
arize-phoenix
python-dotenv
langsmith

Environment variables:

LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
LANGCHAIN_API_KEY="<my_key_here>"
LANGCHAIN_PROJECT="test"

System Info

python -m langchain_core.sys_info:


System Information
------------------
> OS:  Linux
> OS Version:  #1 SMP Fri Mar 29 23:14:13 UTC 2024
> Python Version:  3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]

Package Information
-------------------
> langchain_core: 0.2.11
> langchain: 0.2.6
> langsmith: 0.1.83
> langchain_text_splitters: 0.2.2

Packages not installed (Not Necessarily a Problem)
--------------------------------------------------
The following packages were not found:

> langgraph
> langserve
eyurtsev commented 2 months ago

Could you verify with python 3.11? Quick glance doesn't look like a bug, but issue with user code not propagating callbacks. We can't do it automatically in versions prior to 3.11 since it's not supported by asyncio

MartinoMensio commented 2 months ago

Hi @eyurtsev , thank you for your response. I investigated with python3.11, and everything works as expected. The traces are now shown under the same root trace πŸ˜„ I will now check with my project to make the python version requirement stricter.