Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

on_chain_start callbacks crash with serialized=None in v0.3 #26773

Closed
5 tasks done
whimo opened this issue Sep 23, 2024 · 6 comments
Closed
5 tasks done

on_chain_start callbacks crash with serialized=None in v0.3 #26773

whimo opened this issue Sep 23, 2024 · 6 comments
Assignees
Labels
🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature investigate

Comments

@whimo
Copy link

whimo commented Sep 23, 2024

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).

Example Code

Any callback manager includes default callbacks such as StdOutCallbackHandler, so we can simply instantiate an agent:

from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_openai import OpenAI

llm = OpenAI()

prompt = hub.pull("hwchase17/react")
search = DuckDuckGoSearchRun()

tools = [search]
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke({"input": "what is LangChain?"})

Error Message and Stack Trace (if applicable)

Error in StdOutCallbackHandler.on_chain_start callback: AttributeError("'NoneType' object has no attribute 'get'")

Description

Starting with Langchain v0.3, on_chain_start callbacks started receiving serialized argument as None. This causes callback handlers, including the default ones, to crash.

I doubt that this is intended, but if so, the built-in callbacks should be updated, as well as the docs.

System Info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 23.5.0: Wed May 1 20:19:05 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T8112
Python Version: 3.12.1 (v3.12.1:2305ca5144, Dec 7 2023, 17:23:38) [Clang 13.0.0 (clang-1300.0.29.30)]

Package Information

langchain_core: 0.3.5
langchain: 0.3.0
langchain_community: 0.3.0
langsmith: 0.1.125
langchain_callbacks_bug: Installed. No version info available.
langchain_openai: 0.2.0
langchain_text_splitters: 0.3.0

Optional packages not installed

langgraph
langserve

Other Dependencies

aiohttp: 3.10.5
async-timeout: Installed. No version info available.
dataclasses-json: 0.6.7
httpx: 0.27.2
jsonpatch: 1.33
numpy: 1.26.4
openai: 1.47.0
orjson: 3.10.7
packaging: 24.1
pydantic: 2.9.2
pydantic-settings: 2.5.2
PyYAML: 6.0.2
requests: 2.32.3
SQLAlchemy: 2.0.35
tenacity: 8.5.0
tiktoken: 0.7.0
typing-extensions: 4.12.2

@langcarl langcarl bot added the investigate label Sep 23, 2024
@dosubot dosubot bot added the 🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature label Sep 23, 2024
@SebastianArchila
Copy link

SebastianArchila commented Sep 23, 2024

Hi! I am having the same problem using StructuredTool:

from pydantic import BaseModel, Field
from langchain.tools import StructuredTool

class TestInput(BaseModel):
    var_1: str = Field(description=".....")
    var_2: int = Field(description="......")

test_func= StructuredTool.from_function(
    name="Test",
    func=test_retrieve_func,
    args_schema=TestInput,
    description="...."
)

However using this, I am not having the problem anymore, but the agent is not working as accurate as before:

from langchain.tools import Tool

tools_list = [
    Tool(
        name="Current Date",
        func=get_current_date,
        description="......",
    ),
    Tool(
        name="Current Time",
        func=get_current_time,
        description="......",
    )

prompt = ChatPromptTemplate.from_messages(template_messages)
agent = create_structured_chat_agent(llm, tools, prompt)

agent_conversational = AgentExecutor.from_agent_and_tools(
    agent=agent,
    tools=tools,
    memory=memory,
    verbose=True,
    handle_parsing_errors=True,
)

response = agent_conversational.invoke({"input": user_input, "chat_history": message})

@eyurtsev
Copy link
Collaborator

Fix merged will be resolved in the next langchain-core release

@whimo
Copy link
Author

whimo commented Sep 26, 2024

The issue is fixed in the new release, thank you!

I'll add to clarify, that the removal of serialized argument is indeed intended. Here's the relevant PR: #26270
So the fix here included only the switch to the name argument in StdOutCallbackHandler.

@whimo whimo closed this as completed Sep 26, 2024
@104-wonohfor
Copy link

104-wonohfor commented Oct 3, 2024

Edit: I have solved this problem by modifying "on_chain_start" in my code.

class LoggingHandler(BaseCallbackHandler):
    def on_chat_model_start(
        self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs
    ) -> None:
        print("Chat model started")

    def on_llm_end(self, response: LLMResult, **kwargs) -> None:
        print(f"Chat model ended, response: {response.generations}")

    def on_chain_start(
        self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
    ) -> None:
        if "name" in kwargs:
            name = kwargs["name"]
        else:
            if serialized:
                name = serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
            else:
                name = "<unknown>"
        print(f"Chain {name} started")

    def on_chain_end(self, outputs: Dict[str, Any], **kwargs) -> None:
        print(f"Chain ended, outputs: {outputs}")

I have updated langchain_core to 0.3.8 but still get "serialized=None" for "on_chain_start" callbacks. I have tried the exact code from How to pass callbacks in at runtime, but I did not get the expected result.
Here is my output:

Error in LoggingHandler.on_chain_start callback: AttributeError("'NoneType' object has no attribute 'get'")
Chain ChatPromptTemplate started
Chain ended, outputs: messages=[HumanMessage(content='What is 1 + 2?', additional_kwargs={}, response_metadata={})]
Chat model started
Chat model ended, response: generations=[[ChatGeneration(text='1 + 2 = 3.', generation_info={'finish_reason': 'stop', 'logprobs': None}, message=AIMessage(content='1 + 2 = 3.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 43, 'total_tokens': 52, 'completion_tokens_details': None, 'acceptance_rate': 13, 'completion_tokens_after_first_per_sec': 92.96195573877678, 'completion_tokens_after_first_per_sec_first_ten': 309.2477909232183, 'completion_tokens_per_sec': 23.30748255798628, 'end_time': 1727973713.9831414, 'is_last_response': True, 'start_time': 1727973713.5400455, 'time_to_first_token': 0.357039213180542, 'total_latency': 0.38614208881671613, 'total_tokens_per_sec': 134.66545477947628}, 'model_name': 'Meta-Llama-3.1-405B-Instruct', 'system_fingerprint': 'fastcoe', 'finish_reason': 'stop', 'logprobs': None}, id='run-296bbd75-6e2c-4a5e-a446-fe16ff349120-0', usage_metadata={'input_tokens': 43, 'output_tokens': 9, 'total_tokens': 52}))]] llm_output={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 43, 'total_tokens': 52, 'completion_tokens_details': None, 'acceptance_rate': 13, 'completion_tokens_after_first_per_sec': 92.96195573877678, 'completion_tokens_after_first_per_sec_first_ten': 309.2477909232183, 'completion_tokens_per_sec': 23.30748255798628, 'end_time': 1727973713.9831414, 'is_last_response': True, 'start_time': 1727973713.5400455, 'time_to_first_token': 0.357039213180542, 'total_latency': 0.38614208881671613, 'total_tokens_per_sec': 134.66545477947628}, 'model_name': 'Meta-Llama-3.1-405B-Instruct', 'system_fingerprint': 'fastcoe'} run=None type='LLMResult'
Chain ended, outputs: content='1 + 2 = 3.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 43, 'total_tokens': 52, 'completion_tokens_details': None, 'acceptance_rate': 13, 'completion_tokens_after_first_per_sec': 92.96195573877678, 'completion_tokens_after_first_per_sec_first_ten': 309.2477909232183, 'completion_tokens_per_sec': 23.30748255798628, 'end_time': 1727973713.9831414, 'is_last_response': True, 'start_time': 1727973713.5400455, 'time_to_first_token': 0.357039213180542, 'total_latency': 0.38614208881671613, 'total_tokens_per_sec': 134.66545477947628}, 'model_name': 'Meta-Llama-3.1-405B-Instruct', 'system_fingerprint': 'fastcoe', 'finish_reason': 'stop', 'logprobs': None} id='run-296bbd75-6e2c-4a5e-a446-fe16ff349120-0' usage_metadata={'input_tokens': 43, 'output_tokens': 9, 'total_tokens': 52}

This is my code:

from typing import Any, Dict, List
import os

from langchain_openai import ChatOpenAI
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.messages import BaseMessage
from langchain_core.outputs import LLMResult
from langchain_core.prompts import ChatPromptTemplate


class LoggingHandler(BaseCallbackHandler):
    def on_chat_model_start(
        self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs
    ) -> None:
        print("Chat model started")

    def on_llm_end(self, response: LLMResult, **kwargs) -> None:
        print(f"Chat model ended, response: {response}")

    def on_chain_start(
        self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs
    ) -> None:
        print(f"Chain {serialized.get('name')} started")

    def on_chain_end(self, outputs: Dict[str, Any], **kwargs) -> None:
        print(f"Chain ended, outputs: {outputs}")



callbacks = [LoggingHandler()]

llm = ChatOpenAI(
    model='Meta-Llama-3.1-405B-Instruct',
    base_url="https://api.sambanova.ai/v1",
    api_key=os.environ.get("SAMBANOVA_API_KEY"),
)

prompt = ChatPromptTemplate.from_template("What is 1 + {number}?")

chain = prompt | llm

chain_with_callbacks = chain.with_config(callbacks=callbacks)

result = chain_with_callbacks.invoke({"number": "2"})

@danielkerwin
Copy link

danielkerwin commented Oct 4, 2024

@eyurtsev this is still an issue - serialized is coming through as None in on_chain_start, and on_retriever_start

Per the officially documented example, that code fails with the attribute error.

@104-wonohfor
Copy link

104-wonohfor commented Oct 4, 2024

@danielkerwin Make the following changes in your code:

    def on_chain_start(
        self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
    ) -> None:
        if "name" in kwargs:
            name = kwargs["name"]
        else:
            if serialized:
                name = serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
            else:
                name = "<unknown>"
        print(f"Chain {name} started")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤖:bug Related to a bug, vulnerability, unexpected error with an existing feature investigate
Projects
None yet
Development

No branches or pull requests

5 participants