Creating Custom Tools
Tool Calling left lookup_html_tag at default names. Here you pick the tool name, add a list helper, and wrap lookup in StructuredTool.
Rename @tool
First arg to @tool is the name OpenAI gets. Your function can still be list_html_tags while the tool registers as html_tag_list.
Docstring is still the description. One line, say what comes back.
from langchain.tools import tool
@tool("html_tag_list")
def list_html_tags() -> str:
"""List HTML tag names available in this helper."""
return "<a>, <title>, <h1>"
print(list_html_tags.name) # html_tag_list, not list_html_tagsIn your file
def list_html_tags():
...
@tool("html_tag_list")Sent to OpenAI
name: html_tag_list description: List HTML tag names…
StructuredTool
For a function you already wrote without a decorator, use StructuredTool.from_function. Pass name and description in that call.
from langchain_core.tools import StructuredTool
def lookup_raw(tag_name: str) -> str:
# your lookup logic
return f"<{tag_name}>: ..."
html_tag_lookup = StructuredTool.from_function(
func=lookup_raw,
name="html_tag_lookup",
description="Look up one HTML tag by name.",
)Pass both to create_agent
tools=[list_html_tags, html_tag_lookup]. Same TAGS dict underneath. List question should hit html_tag_list; detail question should hit html_tag_lookup.
Two tools in the demo:
from langchain.agents import create_agent
tools = [list_html_tags, html_tag_lookup]
agent = create_agent(model="openai:gpt-4o-mini", tools=tools)
result = agent.invoke({
"messages": [{"role": "user", "content": "Which tags can you look up?"}],
})
print(result["messages"][-1].content)Run the demo
Venv from Project Setup. Download, then:
creating_custom_tools_demo.py
list question, then <a> question
OPENAI_API_KEY in .env, same as Tool Calling.python creating_custom_tools_demo.py
More args later: Pydantic args_schema in Tools docs.