[Python] Getting ValidationError when trying to inspect the message traceback of LangGraph...

Discussão em 'Python' iniciado por Stack, Dezembro 19, 2024.

  1. Stack

    Stack Membro Participativo

    I'm trying to build a LangGraph application with MemorySaver() to retain memory in between interactions. I've been following the official documentation "Part 3: Adding Memory to the Chatbot" but I've added in a system prompt to guide the flow of the chatbot since I am using tools.

    Here is the full flow of my GraphBuilder

    def create_prompt():
    return (ChatPromptTemplate.from_messages(
    [
    (
    "system",
    converser_prompt.format(cols = cols),
    ),
    MessagesPlaceholder(variable_name="chat_history"),
    ("human", "{input}")
    ]
    ))

    memory = MemorySaver()

    class State(TypedDict):
    messages: Annotated[list, add_messages]


    graph_builder = StateGraph(State)

    llm_with_tools = llm.bind_tools(tools)

    def chatbot(state: State):
    user_input = state["messages"]

    prompt_template = create_prompt()
    formatted_prompt = prompt_template.format(
    chat_history=state["messages"][:-1],
    input=user_input
    )

    response = llm_with_tools.invoke(formatted_prompt)
    state["messages"].append({"role": "assistant", "content": response})

    return {"messages": state["messages"]}

    graph_builder.add_node("chatbot", chatbot)

    tool_node = ToolNode(tools=tools)
    graph_builder.add_node("tools", tool_node)

    graph_builder.add_conditional_edges(
    "chatbot",
    tools_condition,
    )
    # Any time a tool is called, we return to the chatbot to decide the next step
    graph_builder.add_edge("tools", "chatbot")
    graph_builder.add_edge(START, "chatbot")

    graph = graph_builder.compile(checkpointer=memory)



    After I compile the graph with memory I then follow the testing code they have provided to check it

    user_input = "Hi there! My name is Will."

    # The config is the **second positional argument** to stream() or invoke()!
    events = graph.stream(
    {"messages": [("user", user_input)]}, config, stream_mode="values"
    )
    for event in events:
    event["messages"][-1].pretty_print()


    which gives me the following error:

    ================================ Human Message =================================

    Hi there! My name is Will.
    ---------------------------------------------------------------------------
    ValidationError Traceback (most recent call last)
    ~\AppData\Local\Temp\ipykernel_43584\1084556082.py in <module>
    5 {"messages": [("user", user_input)]}, config, stream_mode="values"
    6 )
    ----> 7 for event in events:
    8 event["messages"][-1].pretty_print()

    ~\anaconda3\lib\site-packages\langgraph\pregel\__init__.py in stream(self, input, config, stream_mode, output_keys, interrupt_before, interrupt_after, debug, subgraphs)
    1654 # with channel updates applied only at the transition between steps
    1655 while loop.tick(input_keys=self.input_channels):
    -> 1656 for _ in runner.tick(
    1657 loop.tasks.values(),
    1658 timeout=self.step_timeout,

    ~\anaconda3\lib\site-packages\langgraph\pregel\runner.py in tick(self, tasks, reraise, timeout, retry_policy, get_waiter)
    165 t = tasks[0]
    166 try:
    --> 167 run_with_retry(
    168 t,
    169 retry_policy,

    ~\anaconda3\lib\site-packages\langgraph\pregel\retry.py in run_with_retry(task, retry_policy, configurable)
    38 task.writes.clear()
    39 # run the task
    ---> 40 return task.proc.invoke(task.input, config)
    41 except ParentCommand as exc:
    42 ns: str = config[CONF][CONFIG_KEY_CHECKPOINT_NS]

    ~\anaconda3\lib\site-packages\langgraph\utils\runnable.py in invoke(self, input, config, **kwargs)
    408 input = step.invoke(input, config, **kwargs)
    409 else:
    --> 410 input = step.invoke(input, config)
    411 # finish the root run
    412 except BaseException as e:

    ~\anaconda3\lib\site-packages\langgraph\utils\runnable.py in invoke(self, input, config, **kwargs)
    182 else:
    183 context.run(_set_config_context, config)
    --> 184 ret = context.run(self.func, input, **kwargs)
    185 if isinstance(ret, Runnable) and self.recurse:
    186 return ret.invoke(input, config)

    ~\anaconda3\lib\site-packages\langgraph\graph\graph.py in _route(self, input, config, reader, writer)
    86 ) -> Runnable:
    87 if reader:
    ---> 88 value = reader(config)
    89 # passthrough additional keys from node to branch
    90 # only doable when using dict states

    ~\anaconda3\lib\site-packages\langgraph\pregel\read.py in do_read(config, select, fresh, mapper)
    105 return mapper(read(select, fresh))
    106 else:
    --> 107 return read(select, fresh)
    108
    109

    ~\anaconda3\lib\site-packages\langgraph\pregel\algo.py in local_read(step, checkpoint, channels, managed, task, config, select, fresh)
    187 skip_context=True,
    188 ) as (local_channels, _):
    --> 189 apply_writes(copy_checkpoint(checkpoint), local_channels, [task], None)
    190 values = read_channels({**channels, **local_channels}, select)
    191 else:

    ~\anaconda3\lib\site-packages\langgraph\pregel\algo.py in apply_writes(checkpoint, channels, tasks, get_next_version)
    291 for chan, vals in pending_writes_by_channel.items():
    292 if chan in channels:
    --> 293 if channels[chan].update(vals) and get_next_version is not None:
    294 checkpoint["channel_versions"][chan] = get_next_version(
    295 max_version,

    ~\anaconda3\lib\site-packages\langgraph\channels\binop.py in update(self, values)
    86 values = values[1:]
    87 for value in values:
    ---> 88 self.value = self.operator(self.value, value)
    89 return True
    90

    ~\anaconda3\lib\site-packages\langgraph\graph\message.py in add_messages(left, right)
    70 left = [
    71 message_chunk_to_message(cast(BaseMessageChunk, m))
    ---> 72 for m in convert_to_messages(left)
    73 ]
    74 right = [

    ~\anaconda3\lib\site-packages\langchain_core\messages\utils.py in convert_to_messages(messages)
    355 if isinstance(messages, PromptValue):
    356 return messages.to_messages()
    --> 357 return [_convert_to_message(m) for m in messages]
    358
    359

    ~\anaconda3\lib\site-packages\langchain_core\messages\utils.py in <listcomp>(.0)
    355 if isinstance(messages, PromptValue):
    356 return messages.to_messages()
    --> 357 return [_convert_to_message(m) for m in messages]
    358
    359

    ~\anaconda3\lib\site-packages\langchain_core\messages\utils.py in _convert_to_message(message)
    328 )
    329 raise ValueError(msg) from e
    --> 330 _message = _create_message_from_message_type(
    331 msg_type, msg_content, **msg_kwargs
    332 )

    ~\anaconda3\lib\site-packages\langchain_core\messages\utils.py in _create_message_from_message_type(message_type, content, name, tool_call_id, tool_calls, id, **additional_kwargs)
    261 message: BaseMessage = HumanMessage(content=content, **kwargs)
    262 elif message_type in ("ai", "assistant"):
    --> 263 message = AIMessage(content=content, **kwargs)
    264 elif message_type in ("system", "developer"):
    265 if message_type == "developer":

    ~\anaconda3\lib\site-packages\langchain_core\messages\ai.py in __init__(self, content, **kwargs)
    177 kwargs: Additional arguments to pass to the parent class.
    178 """
    --> 179 super().__init__(content=content, **kwargs)
    180
    181 @classmethod

    ~\anaconda3\lib\site-packages\langchain_core\messages\base.py in __init__(self, content, **kwargs)
    74 kwargs: Additional fields to pass to the
    75 """
    ---> 76 super().__init__(content=content, **kwargs)
    77
    78 @classmethod

    ~\anaconda3\lib\site-packages\langchain_core\load\serializable.py in __init__(self, *args, **kwargs)
    123 def __init__(self, *args: Any, **kwargs: Any) -> None:
    124 """"""
    --> 125 super().__init__(*args, **kwargs)
    126
    127 @classmethod

    ~\anaconda3\lib\site-packages\pydantic\main.py in __init__(self, **data)
    212 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    213 __tracebackhide__ = True
    --> 214 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    215 if self is not validated_self:
    216 warnings.warn(

    ValidationError: 21 validation errors for AIMessage
    content.str
    Input should be a valid string [type=string_type, input_value=AIMessage(content='Hello ...o': 0, 'reasoning': 0}}), input_type=AIMessage]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].0.str
    Input should be a valid string [type=string_type, input_value=('content', 'Hello Will! ...tions or patient data?'), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].0.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('content', 'Hello Will! ...tions or patient data?'), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].1.str
    Input should be a valid string [type=string_type, input_value=('additional_kwargs', {'refusal': None}), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].1.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('additional_kwargs', {'refusal': None}), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].2.str
    Input should be a valid string [type=string_type, input_value=('response_metadata', {'t...top', 'logprobs': None}), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].2.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('response_metadata', {'t...top', 'logprobs': None}), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].3.str
    Input should be a valid string [type=string_type, input_value=('type', 'ai'), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].3.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('type', 'ai'), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].4.str
    Input should be a valid string [type=string_type, input_value=('name', None), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].4.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('name', None), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].5.str
    Input should be a valid string [type=string_type, input_value=('id', 'run-b6e9b042-8e95...c9-8daf-0d1584bd5cbb-0'), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].5.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('id', 'run-b6e9b042-8e95...c9-8daf-0d1584bd5cbb-0'), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].6.str
    Input should be a valid string [type=string_type, input_value=('example', False), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].6.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('example', False), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].7.str
    Input should be a valid string [type=string_type, input_value=('tool_calls', []), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].7.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('tool_calls', []), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].8.str
    Input should be a valid string [type=string_type, input_value=('invalid_tool_calls', []), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].8.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('invalid_tool_calls', []), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type
    content.list[union[str,dict[any,any]]].9.str
    Input should be a valid string [type=string_type, input_value=('usage_metadata', {'inpu...o': 0, 'reasoning': 0}}), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/string_type
    content.list[union[str,dict[any,any]]].9.dict[any,any]
    Input should be a valid dictionary [type=dict_type, input_value=('usage_metadata', {'inpu...o': 0, 'reasoning': 0}}), input_type=tuple]
    For further information visit https://errors.pydantic.dev/2.10/v/dict_type


    I tried to iterate through events and just print the result instead:

    for event in events:
    print(event)


    Which gave me this output:

    {'messages': [HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='c4baa915-7647-4682-b106-2c4ba2932192'), HumanMessage(content='Remember my name?', additional_kwargs={}, response_metadata={}, id='c97716f8-b480-4c13-b7f4-5c786510bd70'), HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='00a05be8-2a84-40b5-9158-691d2c4fce85'), HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='94e69a2e-b809-4c6a-903d-968ebc26cc91')]}


    but also the same ValidationError as before

    I also tried to inspect the documentation for stream() and astream() in LangGraph but I am not sure what to return to get the correct output from the graph. If I could have some guidance as to where my error lies (I'm guessing it's to do with the ChatPromptTemplate as that's the main variation in my code compared to the documentation) it would be really helpful - so that I can figure out how to get the response output in my application. Thanks!

    Continue reading...

Compartilhe esta Página