一、Agent调用tool

定义tool函数,其中注释 “add two int number”,必须要有否则会报错;

@tool
def  add(a:int, b:int) -> int:
    """add two int number""" # 这个必须有,而且很重要,是要输入到LLM;
    return a + b

完整代码:

from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.types import Command, interrupt

llm = ChatOpenAI(
    model="Qwen3-4B-Instruct-2507",  
    openai_api_base="http:/localhost:8000/v1",  # vLLM 服务的地址
    openai_api_key="EMPTY",  # vLLM 通常不需要 API key,但 LangChain 要求设置,可设为任意值如 "EMPTY"
    temperature=0.7,
    max_tokens=1024
)

class State(TypedDict):
    messages: Annotated[list, add_messages]

graph_builder = StateGraph(State)

@tool
def  add(a:int, b:int) -> int:
    """add two int number""" 
    return a + b


tools = [add]
llm_with_tools = llm.bind_tools(tools)

def chatbot(state: State):
    message = llm_with_tools.invoke(state["messages"])
    assert(len(message.tool_calls) <= 1)
    return {"messages": [message]}

graph_builder.add_node("chatbot", chatbot)

tool_node = ToolNode(tools=tools)
graph_builder.add_node("tools", tool_node)

graph_builder.add_conditional_edges(
    "chatbot",
    tools_condition,
)
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge(START, "chatbot")
graph = graph_builder.compile()

def print_stream(stream):
    for s in stream:
        message = s["messages"][-1]
        if isinstance(message, tuple):
            print(message)
        else:
            message.pretty_print()

while True:
    try:
        user_input = input("User: ")
        if user_input.lower() in ["quit", "exit", "q"]:
            print("Goodbye!")
            break

        print_stream(graph.stream({"messages": [{"role": "user", "content": user_input}]}, stream_mode="values"))

    except:
        user_input = "What do you know about LangGraph?"
        print("User: " + user_input)
        print_stream(graph.stream({"messages": [{"role": "user", "content": user_input}]}, stream_mode="values"))
        break

执行的过程:

1、user输入 “1+1”,调用LLM

2、LLM返回调用工具说明 “Tool Calls”,

3、调用工具生成结果 “2”;

4、将结果输入到LLM;

5、LLM 返回最终的结果 “The result of 1 + 1 is 2.”

输出如下:

User: 1+1
================================ Human Message =================================

1+1
================================== Ai Message ==================================
Tool Calls:
  add (chatcmpl-tool-2b1940050a9548d68a299f1a2ee88ede)
 Call ID: chatcmpl-tool-2b1940050a9548d68a299f1a2ee88ede
  Args:
    a: 1
    b: 1
================================= Tool Message =================================
Name: add

2
================================== Ai Message ==================================

The result of 1 + 1 is 2.

二、LLM服务

从LLM服务的后台日志,查看Agent调用tool的流程;

1、第一次调用LLM

当客户端输入 “1+1”时,LLM服务端接受的输入,如下:

prompt: '<|im_start|>system\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n
<tools>\n{
	"type": "function",
	"function": {
		"name": "add",
		"description": "add two int number",
		"parameters": {
			"properties": {
				"a": {
					"type": "integer"
				},
				"b": {
					"type": "integer"
				}
			},
			"required": ["a", "b"],
			"type": "object"
		}
	}
}\n</tools>
\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n
<tool_call>\n{
	"name": < function -name > ,
	"arguments": < args - json - object >
}\n</tool_call><|im_end|>\n
<|im_start|>user\n1+1<|im_end|>\n<|im_start|>assistant\n', 

上述输入包含了:

系统提示词 :“system\n# Tools\n\nYou may ...”

函数定义的说明 <tools>...</tools>

函数调用返回的格式<tool_call>...</tool_call>

用户的输入 “1+1”

2、LLM的Response:

LLM的输出见下图:

content字段是None;

tool_calls 字段说明的调用的tool函数的名称、参数等;

3、第二次调用LLM

前端根据上述大模型的结果,调用tool后生成结果“2”,再次调用LLM,输入

prompt: '<|im_start|>system\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>\n
{
	"type": "function",
	"function": {
		"name": "add",
		"description": "add two int number",
		"parameters": {
			"properties": {
				"a": {
					"type": "integer"
				},
				"b": {
					"type": "integer"
				}
			},
			"required": ["a", "b"],
			"type": "object"
		}
	}
}\n
</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n
<tool_call>\n
{
	"name": < function -name > ,
	"arguments": < args - json - object >
}
</tool_call><|im_end|>\n<|im_start|>user\n1+1<|im_end|>\n<|im_start|>assistant\n<tool_call>\n
{
	"name": "add",
	"arguments": {
		"a": 1,
		"b": 1
	}
}\n
</tool_call><|im_end|>\n<|im_start|>user\n
<tool_response>\n 
2
\n</tool_response>
<|im_end|>\n<|im_start|>assistant\n'

上述包含了除了之前的系统提示、函数说明等,还追加了调用具体函数的名称、参数以及返回的结果;

4、LLM第二次reponse

content字段是大模型输出结果

(完)

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐