LangChainLangChain 1.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
43 small wins to finish your pathNext lesson

Two tools at once

A model can ask for several tools in one message. The agent runs them all before calling the model again, and return_direct can end the run with their results.

Lesson 8's question about A17 and C40 produced two tool calls in one AI message. Each call carries its own id, and each result comes back tagged with it, so the model can tell which answer belongs to which request.

Exampleagent.py
from langchain.agents import create_agent
from shop_model import ShopModel
from tools import lookup_order

agent = create_agent(ShopModel(), tools=[lookup_order])
Example
result = agent.invoke({"messages": [{"role": "user", "content": "Where are A17, B22 and C40?"}]})

for message in result["messages"][1:-1]:
    if message.type == "ai":
        for call in message.tool_calls:
            print("asked ", call["id"])
    else:
        print("result", message.tool_call_id, "->", message.text)

Three calls went out together and three results came back, all before the model was called a second time. Most hosted models make parallel calls by default; OpenAI and Anthropic let you turn it off with parallel_tool_calls=False when binding tools.

Skipping the last model call

The final answer here only repeats what the tools said. A tool with return_direct=True ends the run as soon as it returns, and its result is the answer.

Exampletools.py, with return_direct
@tool(return_direct=True)
def lookup_order(order_id: str) -> str:
    """Look up an order's shipping status by its id, such as A17."""
    status = ORDERS.get(order_id)
    return f"{order_id} {status}." if status else f"{order_id} is not an order we have."
Example
from langchain.agents import create_agent
from shop_model import ShopModel
from tools import lookup_order

agent = create_agent(ShopModel(), tools=[lookup_order])
result = agent.invoke({"messages": [{"role": "user", "content": "Where are A17 and C40?"}]})

for message in result["messages"]:
    print(f"{message.type:<5} {message.text or len(message.tool_calls)}")

The run ends on the two tool messages, with no AI message after them: one model call instead of two. When the model calls several tools in one step, the run stops only if every one of them has return_direct; otherwise all results go back to the model as usual.

Try it yourself
  • Ask about one order with return_direct on and count the messages.
  • Stream the return_direct agent and check which step comes last.
  • Print each message.id for the tool messages and compare them with the tool call ids.

You understood something today that you didn't yesterday.