Repository: langchain
Issue: [AIMessage]tool_calls.0.args is not always returned as a valid dictionary
Labels: 🤖:bug,stale,investigate

### Checked other resources

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

### Example Code


prompt_system = """
You are a transcription engineer. I will provide you with some code, 
and you need to transcribe it into Python. You must use the check_code_syntax tool.
If the last tool execution resulted in a code error, you need to correct the code based on the error 
message and then invoke the check_code_syntax tool again to see if it can compile successfully.
If it passes the check, meaning the return value is_success is True, you should output TASK_END + the corrected code.
"""
tools = [check_code_syntax]
def create_agent():
    prompt = ChatPromptTemplate.from_messages(
        [
        (
            "system",
            prompt_system,
        ),
        MessagesPlaceholder(variable_name='user')
    ]
)
    prompt = prompt.partial(tool_names=", ".join([tool.name for tool in tools]))
    agent  = prompt | llm.bind_tools(tools)
    return agent


rewrite_agent = create_agent()

def should_continue(state:MessagesState) -> bool:
    """Return the next node to execute."""
    last_message = state["messages"][-1]
    # If there is no function call, then we finish
    if not last_message.tool_calls:
        return END
    # Otherwise if there is, we continue
    args = last_message.tool_calls[0]['args']
    if not isinstance(args,dict):
        args = json.loads(args)
    return "tools"

def chatbot(state: State):
    return [rewrite_agent.invoke(state["messages"])]

workflow = StateGraph(MessagesState)
workflow.add_node('tools', ToolNode(tools))
workflow.add_node('rewrite_agent', chatbot)
workflow.add_edge(START, 'rewrite_agent')
workflow.add_edge('tools','rewrite_agent')
workflow.add_conditional_edges('rewrite_agent',should_continue,['tools',END])

graph = workflow.compile()


### Error Message and Stack Trace (if applicable)

[Error Message, I add some print for debug]

================================ Human Message =================================

code is 
def add(a, b):
    prnt(a+b)
add(3, 5)


_dict {'content': '', 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [{'id': '0192c19eef3bb5786799c95962fe59d0', 'function': {'arguments': '{"code": "def add(a, b):\\n    prnt(a+b)\\nadd(3, 5)", "language": "python"}', 'name': 'check_code_syntax'}, 'type': 'function'}]}
role assistant
name None
id None
raw_tool_call {'id': '0192c19eef3bb5786799c95962fe59d0', 'function': {'arguments': '{"code": "def add(a, b):\\n    prnt(a+b)\\nadd(3, 5)", "language": "python"}', 'name': 'check_code_syntax'}, 'type': 'function'}
tool_calls []_
================================== Ai Message ==================================
Tool Calls:
  check_code_syntax (0192c19eef3bb5786799c95962fe59d0)
 Call ID: 0192c19eef3bb5786799c95962fe59d0
  Args:
    code: def add(a, b):
    prnt(a+b)
add(3, 5)
    language: python
================================= Tool Message =================================
Name: check_code_syntax

FalseTraceback (most recent call last):
  File "/tmp/tmp4ljh8rbe", line 3, in <module>
    add(3, 5)
  File "/tmp/tmp4ljh8rbe", line 2, in add
    prnt(a+b)
    ^^^^
NameError: name 'prnt' is not defined. Did you mean: 'print'?

_dict {'content': "It looks like there's a typo in the code. The function `prnt` should be `print`. Let me correct that and check the code again.\n", 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [{'id': '0192c19efcad36cfccc5be45121408cf', 'function': {'arguments': '"{\\"code\\": \\"def add(a, b):\\\\n    print(a+b)\\\\nadd(3, 5)\\", \\"language\\": \\"python\\"}"', 'name': 'check_code_syntax'}, 'type': 'function'}]}
role assistant
name None
id None
raw_tool_call {'id': '0192c19efcad36cfccc5be45121408cf', 'function': {'arguments': '"{\\"code\\": \\"def add(a, b):\\\\n    print(a+b)\\\\nadd(3, 5)\\", \\"language\\": \\"python\\"}"', 'name': 'check_code_syntax'}, 'type': 'function'}
tool_calls []_
Traceback (most recent call last):
  File "/home/son1enardo/nj_rewrite/re_write_agent.py", line 167, in <module>
    for chunk in graph.stream({"messages": [input_message]},
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 1298, in stream
    for _ in runner.tick(
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langgraph/pregel/runner.py", line 56, in tick
    run_with_retry(t, retry_policy)
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langgraph/pregel/retry.py", line 29, in run_with_retry
    task.proc.invoke(task.input, config)
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langgraph/utils/runnable.py", line 409, in invoke
    input = context.run(step.invoke, input, config, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langgraph/utils/runnable.py", line 183, in invoke
    ret = context.run(self.func, input, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/nj_rewrite/re_write_agent.py", line 141, in chatbot
    return [rewrite_agent.invoke(state["messages"])]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 3024, in invoke
    input = context.run(step.invoke, input, config)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 5354, in invoke
    return self.bound.invoke(
           ^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 286, in invoke
    self.generate_prompt(
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 786, in generate_prompt
    return self.generate(prompt_messages, stop=stop, callbacks=callbacks, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 643, in generate
    raise e
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 633, in generate
    self._generate_with_cache(
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 851, in _generate_with_cache
    result = self._generate(
             ^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_openai/chat_models/base.py", line 690, in _generate
    return self._create_chat_result(response, generation_info)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_openai/chat_models/base.py", line 727, in _create_chat_result
    message = _convert_dict_to_message(res["message"])
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_openai/chat_models/base.py", line 138, in _convert_dict_to_message
    return AIMessage(
           ^^^^^^^^^^
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/messages/ai.py", line 179, in __init__
    super().__init__(content=content, **kwargs)
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/messages/base.py", line 76, in __init__
    super().__init__(content=content, **kwargs)
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/langchain_core/load/serializable.py", line 111, in __init__
    super().__init__(*args, **kwargs)
  File "/home/son1enardo/miniconda3/envs/langgraph/lib/python3.11/site-packages/pydantic/main.py", line 212, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for AIMessage
tool_calls.0.args
  Input should be a valid dictionary [type=dict_type, input_value='{"code": "def add(a, b):..., "language": "python"}', input_type=str]
    For further information visit https://errors.pydantic.dev/2.9/v/dict_type

### Description

The LLM returns two AIMessage objects, but there is inconsistency in how tool_call.0.args is structured between them.
In the first AIMessage, the tool_call.0.args is returned correctly as expected, like this:
`{'arguments': '{"code": "def add(a, b):\\n    prnt(a+b)\\nadd(3, 5)", "language": "python"}', 'name': 'check_code_syntax'}
`
However, in the second AIMessage, the tool_call.0.args is returned as a nested, escaped string, like this:
`{'arguments': '"{\\"code\\": \\"def add(a, b):\\\\n    print(a+b)\\\\nadd(3, 5)\\", \\"language\\": \\"python\\"}"'}
`
This discrepancy occurs without any additional processing on the returned results, and the second message causes issues due to the additional escaping, which requires further parsing to get the correct dictionary structure.

### System Info

System Information
------------------
> OS:  Linux
> OS Version:  #1 SMP Fri Mar 29 23:14:13 UTC 2024
> Python Version:  3.11.10 (main, Oct  3 2024, 07:29:13) [GCC 11.2.0]

Package Information
-------------------
> langchain_core: 0.3.10
> langchain: 0.3.1
> langchain_community: 0.3.1
> langsmith: 0.1.129
> langchain_elasticsearch: 0.3.0
> langchain_experimental: 0.3.2
> langchain_ollama: 0.2.0
> langchain_openai: 0.2.2
> langchain_text_splitters: 0.3.0
> langgraph: 0.2.34

Optional packages not installed
-------------------------------
> langserve

Other Dependencies
------------------
> aiohttp: 3.10.8
> async-timeout: Installed. No version info available.
> dataclasses-json: 0.6.7
> elasticsearch[vectorstore-mmr]: Installed. No version info available.
> httpx: 0.27.2
> jsonpatch: 1.33
> langgraph-checkpoint: 2.0.1
> numpy: 1.26.4
> ollama: 0.3.3
> openai: 1.50.2
> 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