#40501·长链

核心: `AsyncBaseTracer` 在 `on_tool_start` 中删除 `name` 和 `on_llm_error` 中删除 `response`, 与 `BaseTracer` 不同

作者: mrutunjay-kinagi创建于 2026年9月16日更新于 2026年9月17日
标签bugcoreexternal

22151 (introduced with_alisteners / AsyncRootListenersTracer)

Reproduction Steps / Example Code (Python)

import asyncio
from langchain_core.language_models import GenericFakeChatModel
from langchain_core.messages import AIMessageChunk
from langchain_core.outputs import ChatGenerationChunk
from langchain_core.tools import tool
from langchain_core.tracers.base import AsyncBaseTracer, BaseTracer


# --- 1. on_tool_start ignores `name` -----------------------------------------
@tool
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


# --- 2. on_llm_error ignores `response` --------------------------------------
class SyncTracer(BaseTracer):
    def __init__(self) -> None:
        super().__init__()
        self.error_outputs = []

    def _persist_run(self, run) -> None:
        pass

    def _on_llm_error(self, run) -> None:
        self.error_outputs.append(run.outputs)


class AsyncTracer(AsyncBaseTracer):
    def __init__(self) -> None:
        super().__init__()
        self.error_outputs = []

    async def _persist_run(self, run) -> None:
        pass

    async def _on_llm_error(self, run) -> None:
        self.error_outputs.append(run.outputs)


class FailsMidStream(GenericFakeChatModel):
    def _stream(self, *args, **kwargs):
        yield ChatGenerationChunk(message=AIMessageChunk(content="partial"))
        raise ValueError("boom")


async def main() -> None:
    names = []
    add.with_listeners(on_end=lambda run: names.append(run.name)).invoke(
        {"a": 1, "b": 2}, config={"run_name": "renamed"}
    )

    async def aon_end(run) -> None:
        names.append(run.name)

    await add.with_alisteners(on_end=aon_end).ainvoke(
        {"a": 1, "b": 2}, config={"run_name": "renamed"}
    )
    print("run names (sync, async):", names)

内容来源: langchain-ai/langchain