langchain-ai / langchain

🦜🔗 Build context-aware reasoning applications
https://python.langchain.com
MIT License
92.26k stars 14.73k forks source link

Tool calling agent: Function name error in calling tool #25211

Open vikasr111 opened 1 month ago

vikasr111 commented 1 month ago

Checked other resources

Example Code

from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool, StructuredTool
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate

load_dotenv()

def add_numbers(a: int, b: int) -> int:
    """Adds a and b.

    Args:
        a: first int
        b: second int
    """
    return a + b

def multiply_numbers(a: int, b: int) -> int:
    """Multiplies a and b.

    Args:
        a: first int
        b: second int
    """
    return a * b

add_numbers_tool = StructuredTool.from_function(
    func=add_numbers, name="Add numbers", description="Adds a and b."
)

multiply_numbers_tool = StructuredTool.from_function(
    func=multiply_numbers, name="Multiply numbers", description="Multiplies a and b."
)

llm = ChatOpenAI(model="gpt-4o", temperature=0)

tools = [add_numbers_tool, multiply_numbers_tool]

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful assistant. Make sure to respond to teh user with most accurate results and information.",
        ),
        ("placeholder", "{chat_history}"),
        ("human", "{input}"),
        ("placeholder", "{agent_scratchpad}"),
    ]
)

# Construct the Tools agent
agent = create_tool_calling_agent(llm, tools, prompt)

query = "What is 3 * 12? Also, what is 11 + 49?"

agent_executor = AgentExecutor(
    agent=agent, tools=tools, verbose=True, return_intermediate_steps=True
)
result = agent_executor.invoke({"input": query})

print(result)

Error Message and Stack Trace (if applicable)

(.venv) Cipher@Crippd assistcx-agent % python task.py

Entering new AgentExecutor chain... Traceback (most recent call last): File "/Users/Cipher/AssistCX/assistcx-agent/task.py", line 63, in result = agent_executor.invoke({"input": query}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/chains/base.py", line 166, in invoke raise e File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/chains/base.py", line 156, in invoke self._call(inputs, run_manager=run_manager) File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/agents/agent.py", line 1612, in _call next_step_output = self._take_next_step( ^^^^^^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/agents/agent.py", line 1318, in _take_next_step [ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/agents/agent.py", line 1318, in [ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/agents/agent.py", line 1346, in _iter_next_step output = self.agent.plan( ^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain/agents/agent.py", line 580, in plan for chunk in self.runnable.stream(inputs, config={"callbacks": callbacks}): File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 3253, in stream yield from self.transform(iter([input]), config, kwargs) File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 3240, in transform yield from self._transform_stream_with_config( File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 2053, in _transform_stream_with_config chunk: Output = context.run(next, iterator) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 3202, in _transform for output in final_pipeline: File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 1271, in transform for ichunk in input: File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 5267, in transform yield from self.bound.transform( File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/runnables/base.py", line 1289, in transform yield from self.stream(final, config, kwargs) File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 373, in stream raise e File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_core/language_models/chat_models.py", line 353, in stream for chunk in self._stream(messages, stop=stop, kwargs): File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/langchain_openai/chat_models/base.py", line 521, in _stream response = self.client.create(payload) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/openai/_utils/_utils.py", line 277, in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/openai/resources/chat/completions.py", line 646, in create return self._post( ^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/openai/_base_client.py", line 1266, in post return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/openai/_base_client.py", line 942, in request return self._request( ^^^^^^^^^^^^^^ File "/Users/Cipher/AssistCX/assistcx-agent/.venv/lib/python3.11/site-packages/openai/_base_client.py", line 1046, in _request raise self._make_status_error_fromresponse(err.response) from None openai.BadRequestError: Error code: 400 - {'error': {'message': "Invalid 'tools[0].function.name': string does not match pattern. Expected a string that matches the pattern '^[a-zA-Z0-9-]+$'.", 'type': 'invalid_request_error', 'param': 'tools[0].function.name', 'code': 'invalid_value'}} (.venv) Cipher@Crippd assistcx-agent %

Description

I have setup a simple tool calling agent following the guide here: https://python.langchain.com/v0.1/docs/modules/agents/agent_types/tool_calling/

I have defined tools using StructuredTool class as shown in my code. When I try to run this code I get the error that shared above. If I remove the space in tool names and replace it with dash (-) or underscore (_), the code works fine and agent execution happens successfully.

I haven't seen anywhere that tool name shouldn't include space and several Langchain documentation uses space in tool names. Am I missing something or making any silly error?

System Info

langchain==0.2.11 langchain-community==0.2.10 langchain-core==0.2.25 langchain-groq==0.1.8 langchain-ollama==0.1.0 langchain-openai==0.1.19 langchain-text-splitters==0.2.2 langchain-together==0.1.4

platform: Mac python version: 3.11.7

gbaian10 commented 1 month ago

The function name can't contain space. You can change it to this:

add_numbers_tool = StructuredTool.from_function(
    func=add_numbers,
    name="Add_numbers",  # fixed
    description="Adds a and b.",
    parse_docstring=True,
)

multiply_numbers_tool = StructuredTool.from_function(
    func=multiply_numbers,
    name="Multiply_numbers",  # fixed
    description="Multiplies a and b.",
    parse_docstring=True,
)

parse_docstring = True is not mandatory, but I see you used Google-style docstrings, so maybe it will work better this way.

You can use print(add_numbers_tool.get_input_schema().schema()) to see the difference between the two. Or you can check on LangSmith.

image