关于langchain使用API加载model的方式
前言:不同的模型的输出结构不同,所以用了不同的API方式。不同在调用时,具体的输出结果是不同的。
1、加载API-KEY
方式一:从.env文件导入(.env
文件应当被加入.gitignore
以避免敏感信息泄露。)
需要创建.env
文件并添加以下内容(确保文件在项目根目录):
# .envDEEPSEEK_API_KEY =sk-
from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv('DEEPSEEK_API_KEY')
方式二: 添加环境变量
import osos.environ["DEEPSEEK_API_KEY"]="sk-"
2、加载模型
2.1 langchain.chat_models
- 多模型支持:封装了 OpenAI、Anthropic、Cohere 等主流聊天模型的 API。
- 标准化输入输出:统一处理消息格式(如
HumanMessage
、AIMessage
),简化开发流程。 - 上下文管理:支持对话历史记录,实现多轮对话的连贯性。
from langchain.chat_models import ChatOpenAIllm = ChatOpenAI(model='deepseek-chat', openai_api_key=api_key, openai_api_base='https://api.deepseek.com',max_tokens=1024
)
2.2 langchain_openai
langchain_openai
是其与 OpenAI 模型集成的官方库。它简化了调用 OpenAI API(如 GPT-3.5、GPT-4)的过程,并支持链式调用、记忆管理、工具集成等高级功能,适用于聊天机器人、自动化流程、数据分析等场景。
from langchain_openai import ChatOpenAI
llm2 = ChatOpenAI(model='deepseek-chat', base_url='https://api.deepseek.com',api_key=api_key,
)
2.3 langchain_deepseek
DeepSeek 聊天模型集成,用于访问 DeepSeek API 中托管的模型。 |
from langchain_deepseek import ChatDeepSeekllm = ChatDeepSeek(model="deepseek-chat", api_key=api_key)
2.4 openai
from openai import OpenAIclient = OpenAI(base_url="https://api.deepseek.com", api_key=api_key,
)response = client.chat.completions.create(model="deepseek-chat", messages=[{"role": "user", "content": "Hello!"}]
)
3、llm.bind和llm.bind_tools
llm.bind_tool
是一种用于将外部工具或功能绑定到大型语言模型(LLM)的方法。通过这种绑定,LLM 可以调用外部工具(如 API、数据库、计算引擎等)来扩展其能力,从而实现更复杂的任务处理。
在 LangChain 中,llm.bind()
是一个用于将额外参数(如 functions
或 tools
)绑定到语言模型的方法,以便在调用模型时自动传递这些参数。它通常用于 OpenAI 风格的函数调用(Function Calling) 或 工具绑定(Tool Binding)。
3.1 直接构建工具
from langchain_core.tools import tool@tool
def search(city: str) -> str:"""查询城市天气"""return "30°C"from langchain_openai import ChatOpenAI
llm2 = ChatOpenAI(model='qwen-turbo', base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',api_key='sk-0',
)
llm2.bind_tools(tools=[search,get_current_temperature])
3.2 使用 function_call 的格式
from langchain_core.tools import tooltools = [{"name": "get_weather", "description": "查询城市天气","parameters": {"type": "object","properties": {"city": {"type": "string", "description": "城市名称"}},"required": ["city"]}
}]
from langchain_openai import ChatOpenAI
llm2 = ChatOpenAI(model='qwen-turbo', base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',api_key='sk-0',
)
llm2.bind_tools(tools=tools)
3.3 使用convert_to_openai_function函数
from langchain.chat_models import ChatOpenAI
from pydantic import BaseModel, Field
from langchain_core.utils.function_calling import convert_to_openai_function
class add(BaseModel):"""Add two integers."""a: int = Field(..., description="First integer")b: int = Field(..., description="Second integer")# Initialize the LLM with DashScope configuration
llm = ChatOpenAI(model='qwen-turbo', base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',api_key='sk-0',
)
functions = [convert_to_openai_function(f) for f in [add]
]
llm_with_tools = llm.bind(functions=functions)
response = llm_with_tools.invoke("What's 1+2")
print(response)
或者
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain.chat_models import ChatOpenAI
from langchain_core.tools import tool@tool
def get_weather(city: str) -> str:"""查询城市天气"""return f"Weather in {city}: 30°C"llm = ChatOpenAI(model='qwen-turbo', base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',api_key='sk-0',
)functions = [convert_to_openai_function(f) for f in [get_weather]
]
llm_with_tools = llm.bind(functions=functions)
response = llm_with_tools.invoke("What's the weather in Beijing?")
print(response)
在使用langchain_openai时,并没有注意到bind和bind_tools的具体区别。无论是普通格式的tool还是function_call格式的tool在代码编译时都没有报错。
在使用langchain.chat_models 时,使用bind_tools时开始报错。才开始注意两者的不同。
在使用openai 时,会有明确的定义。 在使用tool时,会有对应的tool_id 进行对应。
completion = client.chat.completions.create(model="qwen-plus", # 此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/modelsmessages=messages,# tools=tools# functions=functions)
3.4 tool 和function_call 的具体区别
在网络上简单搜索后,没有找到具体的文章来表述两者的具体区别。很多文章都是在表示function_call的用法。
1、https://zhuanlan.zhihu.com/p/707459943
在这篇文章中作者对比了不同模型的function_call。
2、https://juejin.cn/post/7490784514841673778
在这篇文章中说到”Function 这个术语实际上已经废弃了,取而代之的是 Tool。Tool 泛指指一切 LLM 能够调用的外部工具。Tool 相比 function 要更加广义,只不过目前的 tool 只有 function calling 这一种形式,因此为了文章方便理解,就这里认为 function 与 tool 是等价的。“
3、LangChain 官网
LangChain Tools contain a description of the tool (to pass to the language model) as well as the implementation of the function to call.(Tools包含工具的描述(传递给语言模型)以及要调用的函数的实现)
4、大模型FunctionCall-知识整理_function call-CSDN博客
Function Callingl(Tool_Calls)并不是通过对话让大模型执行函数,而是通过大模型与用户对话获取到函数所需的参数。Function Calling是获取函数参数用的,不是执行函数用的。
5、如何使用 Function Calling 功能_大模型服务平台百炼(Model Studio)-阿里云帮助中心
从上述文章可以简单的看出,function_call 主要是为了获取用户回答的参数,也就是简单的用户意图识别。在Function calling中,参数是连接模型和外部函数的关键。参数的解释和定义需要非常精确,以确保模型能够正确理解用户的意图,并生成符合函数要求的参数值。
3.5 具体案例实践(来源于百炼平台的Function Calling案例)
3.5.1 定义tool
定义工具函数
import random
from datetime import datetimedef get_current_weather(location: str) -> str:"""获取当前天气情况。输入地点,如'上海'"""weather_conditions = ["晴天", "多云", "雨天"]random_weather = random.choice(weather_conditions)return f"{location}今天是{random_weather}。"# 查询当前时间的工具
def get_current_time() -> str:"""获取当前时间"""current_datetime = datetime.now()formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')return f"当前时间:{formatted_time}。"
创建tool列表
请根据以下的 JSON 格式提供工具信息。
-
type
字段固定为"function"
; -
function
字段为 Object 类型;-
name
字段为自定义的工具函数名称,建议使用与函数相同的名称,如get_current_weather
或get_current_time
; -
description
字段是对工具函数功能的描述,大模型会参考该字段来选择是否使用该工具函数。 -
parameters
字段是对工具函数入参的描述,类型是 Object ,大模型会参考该字段来进行入参的提取。如果工具函数不需要输入参数,则无需指定parameters
参数。-
type
字段固定为"object"
; -
properties
字段描述了入参的名称、数据类型与描述,为 Object 类型,Key 值为入参的名称,Value 值为入参的数据类型与描述; -
required
字段指定哪些参数为必填项,为 Array 类型。
-
-
{"type": "function","function": {"name": "get_current_weather","description": "当你想查询指定城市的天气时非常有用。","parameters": {"type": "object","properties": {"location": {"type": "string","description": "城市或县区,比如北京市、杭州市、余杭区等。",}},"required": ["location"]}}
}
具体代码:
# 请将以下代码粘贴到步骤1代码后## 步骤2:创建 tools 数组tools = [{"type": "function","function": {"name": "get_current_time","description": "当你想知道现在的时间时非常有用。",}},{"type": "function","function": {"name": "get_current_weather","description": "当你想查询指定城市的天气时非常有用。","parameters": {"type": "object","properties": {"location": {"type": "string","description": "城市或县区,比如北京市、杭州市、余杭区等。",}},"required": ["location"]}}}
]
tool_name = [tool["function"]["name"] for tool in tools]
print(f"创建了{len(tools)}个工具,为:{tool_name}\n")
2.5.2 创建messages(类似于prompt)
一般分为System Message 和 User Message
System Message
你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;
如果用户提问关于时间的问题,请调用‘get_current_time’函数。
请以友好的语气回答问题。
User Message
User Message 用于传入用户提问的问题。假设用户提问“上海天气”,
# 步骤3:创建messages数组
# 请将以下代码粘贴到步骤2 代码后
messages = [{"role": "system","content": """你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;如果用户提问关于时间的问题,请调用‘get_current_time’函数。请以友好的语气回答问题。""",},{"role": "user","content": "上海天气"}
]
3. 发起 Function Calling
from openai import OpenAI
import osclient = OpenAI(# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)def function_calling():completion = client.chat.completions.create(model="qwen-plus", # 此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/modelsmessages=messages,tools=tools)print("返回对象:")print(completion.choices[0].message.model_dump_json())print("\n")return completionprint("正在发起function calling...")
completion = function_calling()
出现以下信息,说明成功:
正在发起function calling...
返回对象:
{"content":"","refusal":null,"role":"assistant","annotations":null,"audio":null,"function_call":null,"tool_calls":[{"id":"call_b17c9629164343388d9719","function":{"arguments":"{\"location\": \"上海\"}","name":"get_current_weather"},"type":"function","index":0}]}
此时输出结果为tool_call。
3.5.简单改编:使用convert_to_openai_function
from langchain_core.utils.function_calling import convert_to_openai_function
functions = [convert_to_openai_function(f) for f in [get_current_weather,get_current_time]
]
functions
functions的输出
[{'name': 'get_current_weather','description': "获取当前天气情况。输入地点,如'上海'",'parameters': {'properties': {'location': {'type': 'string'}},'required': ['location'],'type': 'object'}},{'name': 'get_current_time','description': '获取当前时间','parameters': {'properties': {}, 'type': 'object'}}]
调用function_call
# 步骤4:发起 function calling
from openai import OpenAIimport osclient = OpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)def function_calling():# messages = [{"role": "user", "content": "北京现在的天气怎么样?"}]completion = client.chat.completions.create(model="qwen-plus", # 此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/modelsmessages=messages,# tools=toolsfunctions=functions)print("返回对象:")print(completion.choices[0].message.model_dump_json())print("\n")return completionprint("正在发起function calling...")
completion = function_calling()
此时的输出为 function_call
正在发起function calling...
返回对象:
{"content":"","refusal":null,"role":"assistant","annotations":null,"audio":null,"function_call":{"arguments":"{}","name":"get_current_time"},"tool_calls":null}
Function calling的第一次响应是指模型在接收到用户的自然语言输入后,生成的包含函数调用请求的响应。在这个阶段,模型会首先解析用户的意图,判断是否需要调用外部函数来完成任务。如果需要调用函数,模型会生成一个结构化的函数调用请求,包括函数名和参数,并将其作为响应的一部分返回。
Function calling的第二次响应是指在外部函数执行完成后,模型根据函数的执行结果生成的最终回复。在这个阶段,模型会将外部函数返回的结果整合到自然语言回复中,以向用户提供完整的信息。
测试代码如下:
from openai import OpenAI
from datetime import datetime
import json
import os
import randomclient = OpenAI(# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", # 填写DashScope SDK的base_url
)# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [# 工具1 获取当前时刻的时间{"type": "function","function": {"name": "get_current_time","description": "当你想知道现在的时间时非常有用。",# 因为获取当前时间无需输入参数,因此parameters为空字典"parameters": {},},},# 工具2 获取指定城市的天气{"type": "function","function": {"name": "get_current_weather","description": "当你想查询指定城市的天气时非常有用。","parameters": {"type": "object","properties": {# 查询天气时需要提供位置,因此参数设置为location"location": {"type": "string","description": "城市或县区,比如北京市、杭州市、余杭区等。",}},"required": ["location"],},},},
]# 模拟天气查询工具。返回结果示例:“北京今天是雨天。”
def get_current_weather(arguments):# 定义备选的天气条件列表weather_conditions = ["晴天", "多云", "雨天"]# 随机选择一个天气条件random_weather = random.choice(weather_conditions)# 从 JSON 中提取位置信息location = arguments["location"]# 返回格式化的天气信息return f"{location}今天是{random_weather}。"# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():# 获取当前日期和时间current_datetime = datetime.now()# 格式化当前日期和时间formatted_time = current_datetime.strftime("%Y-%m-%d %H:%M:%S")# 返回格式化后的当前时间return f"当前时间:{formatted_time}。"# 封装模型响应函数
def get_response(messages):completion = client.chat.completions.create(model="qwen-plus", # 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/modelsmessages=messages,tools=tools,)return completiondef call_with_messages():print("\n")messages = [{"content": input("请输入:"), # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?""role": "user",}]print("-" * 60)# 模型的第一轮调用i = 1first_response = get_response(messages)assistant_output = first_response.choices[0].messageprint(f"\n第{i}轮大模型输出信息:{first_response}\n")if assistant_output.content is None:assistant_output.content = ""messages.append(assistant_output)# 如果不需要调用工具,则直接返回最终答案if (assistant_output.tool_calls == None): # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用print(f"无需调用工具,我可以直接回复:{assistant_output.content}")return# 如果需要调用工具,则进行模型的多轮调用,直到模型判断无需调用工具while assistant_output.tool_calls != None:# 如果判断需要调用查询天气工具,则运行查询天气工具tool_info = {"content": "","role": "tool","tool_call_id": assistant_output.tool_calls[0].id,}if assistant_output.tool_calls[0].function.name == "get_current_weather":# 提取位置参数信息argumens = json.loads(assistant_output.tool_calls[0].function.arguments)tool_info["content"] = get_current_weather(argumens)# 如果判断需要调用查询时间工具,则运行查询时间工具elif assistant_output.tool_calls[0].function.name == "get_current_time":tool_info["content"] = get_current_time()tool_output = tool_info["content"]print(f"工具输出信息:{tool_output}\n")print("-" * 60)messages.append(tool_info)assistant_output = get_response(messages).choices[0].messageif assistant_output.content is None:assistant_output.content = ""messages.append(assistant_output)i += 1print(f"第{i}轮大模型输出信息:{assistant_output}\n")print(f"最终答案:{assistant_output.content}")if __name__ == "__main__":call_with_messages()
------------------------------------------------------------第1轮大模型输出信息:ChatCompletion(id='chatcmpl-f9311047-dda8-9c7a-afbf-d45b7465ec3e', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_834f5ecaed4d4d95b70735', function=Function(arguments='{}', name='get_current_time'), type='function', index=0)]))], created=1748793647, model='qwen-plus', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=13, prompt_tokens=223, total_tokens=236, completion_tokens_details=None, prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0)))工具输出信息:当前时间:2025-06-02 00:00:48。------------------------------------------------------------
第2轮大模型输出信息:ChatCompletionMessage(content='现在的时间是2025年6月2日的00:00:48。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None)最终答案:现在的时间是2025年6月2日的00:00:48。
在不同的API中,有不同的用法,大家根据自己的习惯即可。