本文旨在通过手搓Tool Calling来帮助新手理解Tool Calling的整个循环。在项目逐渐扩大后,可以选择使用官方SDK或者Langchain框架等方式。

一、Tool和Tool Calling的区别

1.Tool

        简单来说,就类似于一个函数。

def weather_tool():

2.Tool Calling

       指的是Agent如何决定、调用、执行、处理Tool,这一整套流程。

        (1)Tool定义

        (2)LLM决定是否调用Tool

        (3)Python解析Tool请求

        (4)Python执行Tool

        (5)结果传回LLM

二、本节初始脚本

        将[01]中的脚本进行了完善,函数进行了封装。内容分别如下所示:

1..env

SiliconFlow_API_KEY=sk-faevswcryuqddrihwxescutiisvqpfztfvixhtimfomyffzc

2.config.py

#配置文件
#管理接入的LLM模型名称、API地址、API_KEY等信息
MODEL_NAME = "deepseek-ai/DeepSeek-V3.2"
BASE_URL = "https://api.siliconflow.cn/v1"
API_KEY_ENV = "SiliconFlow_API_KEY"

3.llm_client.py

#LLM客户端文件
#创建一个OpenAI client对象,后续所有的大模型请求都通过client发送
from openai import OpenAI
from dotenv import load_dotenv
import config
import os

#读取当前目录下的.env文件,会把.env中的内容加载到环境变量中
load_dotenv()

def create_client():

    client = OpenAI(
        #从环境变量中读取API Key
        api_key=os.getenv(config.API_KEY_ENV),
        #设置请求的基础URL,默认是https://api.openai.com/v1。如果使用的是SiliconFlow的API,需要修改为https://api.siliconflow.cn/v1
        base_url=config.BASE_URL
    )

    return client

4.prompts.py

#Prompt文件

#定义系统Prompt,告诉模型的角色和身份等
SYSTEM_PROMPT = """
你是一名目标检测领域,具有前瞻目光的期刊编辑
"""

5.chat.py

#对话文件
#用户向LLM发送一次对话请求,LLM返回一次回答
import config

def chat_with_llm(client, messages):
    #使用client这个客户端,在它的聊天补全功能中,创建一个新的请求
    response = client.chat.completions.create(
        #指定使用的模型,DeepSeek-V3.2是模型名称
        model=config.MODEL_NAME,

        #messages表示对话历史,传入的messages是一个列表
        messages=messages
    )
    
    #返回llm的回答。response是完整返回结果;choices[0]表示第一个回答;message.content表示回答文本
    return response.choices[0].message.content

6.main.py

import llm_client
import prompts
import chat

#创建一个OpenAI client对象
client = llm_client.create_client()
print("\n欢迎使用QM_AgentDemo!(输入'Q'或'q'结束对话)\n")

#保存对话历史,添加系统信息
messages = [
    {
        #role表示消息角色,system表示系统消息;#content表示消息内容,即给系统拟定的前提条件
        "role": "system",
        "content": prompts.SYSTEM_PROMPT
    }
]

#向大模型开启循环对话请求
while True:

    #获取用户输入
    user_input = input("你:")

    #程序结束条件
    if user_input.lower() in['Q', 'q']:
        print("对话结束")
        break

    #添加用户信息
    messages.append({
        #role表示消息角色,user表示用户输入;#content表示消息内容,即用户真正说的话
        "role": "user",
        "content": user_input
    })
    
    #打印LLM回复内容
    agent_reply = chat.chat_with_llm(client, messages)
    print(f"模型回复:{agent_reply}\n")
    
    #将LLM回复也加入到对话历史
    messages.append({
        "role": "assistant",
        "content": agent_reply
    })

三、搭建Tool Calling最小可运行版本(Minimum Viable Product,MVP)

1.构建TOOL_PROMPT

        (1)在tool_prompts.py中构建字符串TOOL_PROMPT

        目前只构建一个Tool,weather_tool(city):查询天气。

TOOL_PROMPT = """
你是一个Agent。

你可以使用以下工具:

1.weather_tool(city)
功能:
查询天气。

如果用户需要查询天气:

请严格按照一下格式输出:

TOOL:weather_tool
ARGS:城市名

例如:

TOOL:weather_tool
ARGS:大连

不要输出其他内容。

如果不需要调用工具:
直接正常回答。
"""

      (2)在main.py中,将TOOL_PROMPT也加入到messages[]

#保存对话历史,添加系统信息
messages = [
    {
        #role表示消息角色,system表示系统消息;#content表示消息内容,即给系统拟定的前提条件
        "role": "system",
        "content": prompts.SYSTEM_PROMPT
    },
    {
        #role表示消息角色,system表示系统消息;#content表示消息内容,即给系统拟定的前提条件
        "role": "system",
        "content": tool_prompts.TOOL_PROMPT
    }
]

        (3)在tools.py中,构建weather_tool(city)

#测试流程
def weather_tool(city):
    return f"{city}今天25度"

        注:以上weather_tool(city)仅适用于流程测试,并非最终代码。

2.main.py中,获取LLM返回的结果

#获取LLM返回的结果
agent_reply = chat.chat_with_llm(client, messages)

        若用户询问普通问题,则LLM正常回答;若用户询问天气相关问题,LLM回答如下所示:

3.Python解析Tool调用

    #判断是否调用工具
    if "TOOL:" in agent_reply:
        
        #提取参数
        lines = agent_reply.split("\n")
        tool_name = lines[0].replace("TOOL:", "").strip()
        args = lines[1].replace("ARGS:", "").strip()

        if tool_name == "weather_tool":
            
            #这里的tool_replay是Python执行Tool后返回的结果,不是LLM返回的结果
            tool_replay = tools.weather_tool(args)
            print(f"天气情况:{tool_replay}\n")
    
    else:
        
        #这里的agent_reply才是LLM返回的结果
        print(f"模型回复:{agent_reply}\n")

        若调用Tool,则执行tools.weather_tool(city),获取Tool的返回值;若不调用Tool,则正常返回模型回复。

4.当前完整main.py

import llm_client
import system_prompts
import tool_prompts
import chat
import tools

#创建一个OpenAI client对象
client = llm_client.create_client()
print("\n欢迎使用QM_AgentDemo!(输入'Q'或'q'结束对话)\n")

#保存对话历史,添加系统信息
messages = [
    {
        #role表示消息角色,system表示系统消息;#content表示消息内容,即给系统拟定的前提条件
        "role": "system",
        "content": system_prompts.SYSTEM_PROMPT
    },
    {
        #role表示消息角色,system表示系统消息;#content表示消息内容,即给系统拟定的前提条件
        "role": "system",
        "content": tool_prompts.TOOL_PROMPT
    }
]

#向大模型开启循环对话请求
while True:

    #获取用户输入
    user_input = input("你:")

    #程序结束条件
    if user_input.lower() in['Q', 'q']:
        print("对话结束")
        break
    
    #添加用户信息
    messages.append({
        #role表示消息角色,user表示用户输入;#content表示消息内容,即用户真正说的话
        "role": "user",
        "content": user_input
    })
    
    #获取LLM返回的结果
    agent_reply = chat.chat_with_llm(client, messages)

    #判断是否调用工具
    if "TOOL:" in agent_reply:
        
        #提取参数
        lines = agent_reply.split("\n")
        tool_name = lines[0].replace("TOOL:", "").strip()
        args = lines[1].replace("ARGS:", "").strip()

        if tool_name == "weather_tool":
            
            #这里的tool_replay是Python执行Tool后返回的结果,不是LLM返回的结果
            tool_replay = tools.weather_tool(args)
            print(f"天气情况:{tool_replay}\n")
    
    else:
        
        #这里的agent_reply才是LLM返回的结果
        print(f"模型回复:{agent_reply}\n")
    
    #将LLM回复也加入到对话历史
    messages.append({
        "role": "assistant",
        "content": agent_reply
    })

        当前运行结果:

        至此,已经将一个固定返回结果的天气Tool加入了AgentDemo中。但我们接收到的天气情况只是Python执行函数返回的固定结果,并非LLM总结结果过后输出的内容。因此,还需继续完善以下内容:

        (1)将Python执行Tool后的结果传回LLM,LLM继续思考,将最终回答返回给用户。实现Observation Loop。

        (2)拓展Tool,并完善Tool的执行机制。

        (3)实现真正的Tool。

四、下期规划——完善脚本

1.实现Observation Loop

2.Tool Registry(工具注册表)

3.实现真正的Tool

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐