langchain-learning/tools/tool_demo.py
2026-04-15 10:45:46 +08:00

99 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.tools import tool, StructuredTool
from pydantic import BaseModel, Field
import logging
from langchain_openai import ChatOpenAI
import os
import dotenv
# 定义函数/tool
## 方式1使用注解
class FieldInfo(BaseModel):
city: str = Field(description="要查询的城市名称")
## 注解中可以通过传参覆盖原有函数的描述等信息
@tool(
name_or_callable="get_weather",
args_schema=FieldInfo,
description="查询某个城市的天气,并返回温度信息",
return_direct=True
)
def get_weather(city: str) -> str:
"""查询指定城市的最新天气信息"""
# 通过api调用天气网站的接口得到最新的天气信息
return f"{city}当前的温度为18°C"
@tool
def test(city: str) -> str:
"""这个是一个测试函数"""
# 通过api调用天气网站的接口得到最新的天气信息
return f"{city}当前的温度为18°C"
######################################################################
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
dotenv.load_dotenv()
## 设置环境变量
# os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
# os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
os.environ['OPENAI_API_KEY'] = os.getenv("OLLAMA_API_KEY")
os.environ['OPENAI_BASE_URL'] = os.getenv("OLLAMA_BASE_URL")
# os.environ['OPENAI_API_KEY'] = os.getenv("MINIMAX_API_KEY")
# os.environ['OPENAI_BASE_URL'] = os.getenv("MINIMAX_BASE_URL")
# 如果要使用函数调用,需要选择支持的模型
# 如果不支持会报错Error code: 400 - {'code': 20037, 'message': 'Function call is not supported for this model.', 'data': None}
# llm = ChatOpenAI(model="Qwen/Qwen2.5-7B-Instruct")
llm = ChatOpenAI(model="gemma4:e2b")
# llm = ChatOpenAI(model="MiniMax-M2.7")
## 将模型与工具进行绑定
llm_with_tools = llm.bind_tools([get_weather,test],tool_choice="auto")
messages = [HumanMessage(content="巴黎现在的气温是多少")]
## 使用哪个工具,由大模型自己选择
response = llm_with_tools.invoke(messages)
print(response)
## 模型会返回需要调用get_weather并且识别出来传参为 Paris但是不会进行真正的调用
# 如果需要调用工具,则执行并把结果回传
for call in getattr(response, "tool_calls", []) or []:
# print(call)
# {'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': '019a305388b40ad0d961da5696e9fd2f', 'type': 'tool_call'}
if call["name"] == "get_weather":
args = call["args"] # 例如 {"city": "Paris"}
result = get_weather.invoke(args)
messages.append(response) # 把模型消息加入对话
messages.append(
ToolMessage(
content=result,
tool_call_id=call["id"], # 必须把这次tool调用的id对上
)
)
# 5) 第二轮:把工具结果交回给模型,让它产出最终回答
final_msg = llm.invoke(messages)
print("FINAL:", final_msg.content)
break
else:
# 模型未请求调用工具,直接给出回答
print("FINAL(no-tool):", response.content)