LangChain Tool Advanced Features | Tutorial
\\n\\nURL Source: https://example.com/langchain/langchain-tool-advanced.html
\\n\\n\\n\\n
In the previous section, we learned the basic usage of @tool. This section introduces advanced tool features: return_direct, InjectedToolCallId, ToolException, and error handling.
\\n\\n\\n\\n
return_directββReturn Final Result Directly
\\n\\nBy default, after tool execution, the result is returned to the model, which then generates the final response based on the tool result. However, sometimes the tool result itself is the final answer you want.
\\n\\nAfter setting return_direct=True, the tool execution immediately ends the Agent loop, and the tool's returned content is used directly as the final output.
\\n\\nExample
\\n\\nfrom dotenv import load_dotenv\\n\\n load_dotenv()\\n\\nfrom langchain.tools import tool\\n\\nfrom langchain.agents import create_agent\\n\\nfrom langchain.chat_models import init_chat_model\\n\\nfrom langchain.messages import HumanMessage\\n\\n# Normal tool: result returned to model, model then summarizes\\n\\n@tool\\n\\ndef search_normal(keyword: str) ->str:\\n\\n"""Search Tutorial TUTORIAL courses (normal mode)"""\\n\\nreturn f"Search results: Python3 Basics, Python Data Analysis, Python Scraping Basics"\\n\\n# return_direct tool: result directly as final output\\n\\n@tool(return_direct=True)\\n\\ndef search_direct(keyword: str) ->str:\\n\\n"""Search Tutorial TUTORIAL courses (direct return mode).\\nUse this tool when the user only needs search results without additional analysis.\\n\\n """\\n\\nreturn f"Search results: Python3 Basics, Python Data Analysis, Python Scraping Basics"\\n\\nmodel = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)\\n\\n# Comparison: normal mode vs direct return mode\\n\\n agent_normal = create_agent(\\n\\n model=model,\\n\\n tools=,\\n\\n system_prompt="You are a learning advisor for Online Tutorial.",\\n\\n)\\n\\nagent_direct = create_agent(\\n\\n model=model,\\n\\n tools=,\\n\\n system_prompt="You are a learning advisor for Online Tutorial.",\\n\\n)\\n\\n# Normal mode: model will generate a summary based on search results\\n\\n result = agent_normal.invoke({\\n\\n"messages": [HumanMessage(content="Search Python courses")]\\n\\n})\\n\\nprint("=== Normal mode (model will process further) ===")\\n\\nprint(result.content[:150])\\n\\n# Direct return mode: tool result is the final answer\\n\\n result = agent_direct.invoke({\\n\\n"messages": [HumanMessage(content="Search Python courses")]\\n\\n})\\n\\nprint("\\\\n=== Direct return mode (tool result is final answer) ===")\\n\\nprint(result.content[:150])\\n\\n\\nOutput:
\\n\\n=== Normal mode (model will process further) ===\\nAt Tutorial TUTORIAL, I found the following Python-related courses for you:1. Python3 Basics - Suitable for beginners2. Python Data Analysis - Advanced learning3. Python Scraping Basics - Practical projects=== Direct return mode (tool result is final answer) ===\\nSearch results: Python3 Basics, Python Data Analysis, Python Scraping Basics\\n\\n\\n| Mode | \\nAfter Tool Execution | \\nUse Case | \\n
|---|---|---|
| return_direct=False (default) | \\nModel receives tool result β model continues thinking β generates final response | \\nNeed analysis/summary/further decision | \\n
| return_direct=True | \\nEnd immediately after tool execution β tool result is final output | \\nQuery type, data retrieval, pre-formatted results | \\n
\\n\\n\\nWhen you set return_direct=True, the Agent skips the subsequent model thinking step and directly returns the tool result. This is very valuable for saving tokens and reducing latency, but it also means the model will not do any secondary processing on the tool result.
\\n
\\n\\n
InjectedToolCallIdββGet Tool Call ID
\\n\\nSometimes the tool needs to know "who called it"βInjectedToolCallId can inject the current tool_call_id into the tool function:
\\n\\nExample
\\n\\nfrom typing import Annotated\\n\\nfrom langchain.tools import tool, InjectedToolCallId\\n\\n@tool\\n\\ndef log_user_action(\\n\\n action: str,\\n\\n tool_call_id: Annotated[str, InjectedToolCallId],\\n\\n) ->str:\\n\\n"""Log user action to the logging system.\\nArgs:\\n\\n action: User action description\\n\\n tool_call_id: System automatically injected tool call ID\\n\\n """\\n\\n# In actual projects, this would write to database or send to logging service\\n\\nreturn f"Action logged (call ID: {tool_call_id}): {action}"\\n\\n# InjectedToolCallId parameter will be automatically injected, no need to pass manually\\n\\n result = log_user_action.invoke({"action": "User queried Python courses"})\\n\\nprint(result)\\n\\n\\nOutput:
\\n\\nAction logged (call ID: 00000000-0000-4000-8000-000000000001): User queried Python courses\\n\\n\\n\\n\\n\\nParameters marked with InjectedToolArg do not need to be provided by the Agent (model); they are automatically injected by the LangChain runtime framework. You don't need to describe these injected parameters in the tool function's docstring because the Agent won't see them.
\\n
\\n\\n
ToolExceptionββTool Exception Handling
\\n\\nErrors may occur during tool execution. Use ToolException to throw explicit tool exceptions, letting the Agent know that something went wrong.
\\n\\nExample
\\n\\nfrom langchain.tools import tool, ToolException\\n\\n@tool\\n\\ndef get_user_info(user_id: int) ->str:\\n\\n"""Query user information by user ID.\\nArgs:\\n\\n user_id: User ID, must be a positive integer\\n\\n """\\n\\n# Data validation\\n\\nif user_id <=0:\\n\\n# Throw ToolException, not regular Exception\\n\\n# ToolException will be caught by Agent and reported to model\\n\\nraise ToolException(f"User ID must be a positive integer, received: {user_id}")\\n\\n# Simulate database query\\n\\n users ={\\n\\n1: "Zhang San (VIP member, registered on 2024-01-15)",\\n\\n2: "Li Si (Regular user, registered on 2024-03-20)",\\n\\n}\\n\\nif user_id not in users:\\n\\nraise ToolException(f"User with ID {user_id} not found")\\n\\nreturn users\\n\\n# Normal call\\n\\nprint(get_user_info.invoke({"user_id": 1}))\\n\\n# Exception call 1: invalid ID\\n\\ntry:\\n\\n get_user_info.invoke({"user_id": -1})\\n\\nexcept ToolException as e:\\n\\nprint(f"Tool exception: {e}")\\n\\n# Exception call 2: user does not exist\\n\\ntry:\\n\\n get_user_info.invoke({"user_id": 999})\\n\\nexcept ToolException as e:\\n\\nprint(f"Tool exception: {e}")\\n\\n\\nOutput:
\\n\\nZhang San (VIP member, registered on 2024-01-15)\\nTool exception: User ID must be a positive integer, received: -1\\nTool exception: User with ID 999 not found\\n\\n\\n\\n\\n
handle_tool_errorsββLet Agent Handle Tool Errors Automatically
\\n\\nWhen the model is allowed to handle tool errors (via ToolNode configuration), the model can try to correct parameters and call again:
\\n\\nExample
\\n\\nfrom langchain.tools import tool, ToolException\\n\\nfrom langchain.agents import create_agent\\n\\nfrom langchain.chat_models import init_chat_model\\n\\nfrom langchain.messages import HumanMessage\\n\\n@tool\\n\\ndef get_weather(city: str) ->str:\\n\\n"""Query weather for specified city.\\nArgs:\\n\\n city: City name, must be full Chinese name like "Hangzhou", "Beijing"\\n\\n """\\n\\n weather_data ={\\n\\n"Hangzhou": "Sunny, 25Β°C",\\n\\n"Beijing": "Cloudy, 18Β°C",\\n\\n"Shanghai": "Light rain, 22Β°C",\\n\\n}\\n\\nif city not in weather_data:\\n\\n# Throw ToolException when city is not in data\\n\\nraise ToolException(\\n\\n f"City '{city}' not found."\\n\\n f"Available cities: {', '.join(weather_data.keys())}."\\n\\n f"Please use full Chinese city names."\\n\\n)\\n\\nreturn f"{city} weather: {weather_data}"\\n\\nmodel = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)\\n\\n# When not using Agent, you can also control behavior with handle_tool_errors\\n\\n# Method 1: Return error message string (model
YouTip