当前位置: 首页 > news >正文

基于LangChain实现OpenAI Functions风格Tool Calling智能助手

一、先搞懂:OpenAI Functions 核心特点是什么?

很多同学会把Tool Calling和普通对话混淆,其实OpenAI Functions风格的工具调用,有三个不可替代的核心优势,也是我们本次实现的重点:

1. 需求识别自动化

模型能自动识别用户输入中需要调用工具的场景,无需人工指定“该用哪个工具”。比如用户问“现在几点”,模型会自动匹配“时间查询工具”;问“123乘以456是多少”,则自动触发“计算器工具”,完全无需额外的判断逻辑。

2. 工具调用标准化

遵循OpenAI Functions的规范,将自定义工具(如计算器、时间查询)封装成统一格式,模型能快速识别工具的功能、参数要求,避免因工具格式不统一导致的调用失败,降低开发成本。

3. 多轮交互连贯化

结合对话记忆功能,模型能记住上下文交互记录。比如用户先问“现在几点”,再问“30分钟后是几点”,模型会结合上一轮获取的当前时间,调用计算器完成计算,实现连贯的对话体验,而非孤立的单次工具调用。

二、核心实现思路:4步搭建,无复杂依赖

本次实现不依赖第三方API(除本地模型外),核心基于LangChain框架,将“模型初始化、工具定义、提示词构建、Agent封装”四大步骤串联,全程极简,重点突出OpenAI Functions的实现逻辑。

第一步:模型适配——对接兼容OpenAI规范的本地模型

OpenAI Functions的核心是“模型能识别工具描述、生成符合规范的调用指令”,因此我们无需直接使用OpenAI官方模型,只要本地部署的模型兼容OpenAI的工具调用格式(如通义千问、DeepSeek等),即可通过LangChain的ChatOpenAI封装类完成对接。

这一步的关键是配置模型的接口地址、密钥(部分本地模型无需真实密钥)、温度系数和最大生成token数,确保模型输出稳定、符合工具调用规范。

第二步:工具定义——按OpenAI Functions规范封装本地工具

按照OpenAI Functions的要求,我们将自定义工具(计算器、时间查询)封装成“名称+功能+参数描述”的标准格式,让模型能清晰识别工具的用途和调用方式。

比如计算器工具,需要明确说明“用于执行简单数学运算,输入必须是合法的算术表达式”;时间查询工具则说明“无需参数,直接返回当前系统时间”。同时,为了保证安全性,我们还会对工具的输入进行校验(如计算器的表达式白名单),避免恶意代码注入。

第三步:提示词构建——融入对话记忆与工具调用逻辑

提示词是模型触发工具调用的关键,我们需要构建包含“系统提示、对话历史、用户输入、工具调用中间步骤”的完整模板。其中,系统提示明确告知模型“需用中文回答、可自动调用工具”;对话历史占位符用于保存多轮交互记录,实现记忆功能;工具调用中间步骤占位符则用于存储模型调用工具的过程和结果,确保交互连贯。

第四步:Agent封装——整合模型、工具与记忆,实现自动流转

这是实现OpenAI Functions风格工具调用的核心步骤:通过LangChain的create_tool_calling_agent方法,将模型、封装好的工具、提示词模板整合,创建一个能自动触发工具调用的Agent;再搭配对话记忆组件和Agent执行器,实现“用户输入→模型识别→工具调用→结果返回”的全流程自动化,同时限制最大工具调用次数,避免无限循环。

三、实际体验:轻量化交互,适配多种场景

搭建完成后,启动程序即可进行交互式对话,体验完全贴合OpenAI Functions的核心逻辑:

- 基础对话:用户输入“你好”,模型直接返回问候,无需调用工具;

- 工具调用:用户输入“123乘以456是多少”,模型自动调用计算器工具,返回计算结果;输入“现在几点”,自动调用时间查询工具,返回格式化时间;

- 多轮连贯:用户先问“现在几点”,再问“1小时后是几点”,模型结合上一轮的时间结果,调用计算器完成计算,实现连贯交互。

整个过程无需人工干预,模型能自主判断是否需要调用工具、调用哪个工具,完全复刻OpenAI Functions的使用体验,且纯本地运行,无需担心网络延迟和API调用成本。

四、总结与延伸

本次实现的核心价值,在于“用极简方式复刻OpenAI Functions的工具调用逻辑”——无需复杂的代码开发,借助LangChain的封装能力,快速对接本地模型,实现自动化工具调用和多轮对话记忆。

其实,OpenAI Functions的本质不是“调用工具”,而是“让模型学会判断需求、选择工具、处理结果”,这也是大模型从“语言生成”向“实际应用”落地的关键一步。

后续我们还可以基于这个框架,扩展更多工具(如天气查询、文件读取、API调用等),只需按照相同的规范封装工具,即可实现更多场景的自动化处理,真正让大模型成为高效的辅助工具。

代码实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

# -*- coding: utf-8 -*-

"""

基于 LangChain 的 Tool Calling 智能助手

- 对接兼容 OpenAI 工具调用格式的本地大模型(qwen3.5-27b-awq)

- 内置工具:数学计算器、获取当前时间(纯本地实现,无外部依赖)

- 支持多轮对话记忆,可连贯交互

- 核心架构:OpenAI 风格函数调用(Tool Calling)Agent

"""

importos

fromdatetimeimportdatetime

fromdotenvimportload_dotenv

# 导入 LangChain 核心组件:工具调用 Agent、执行器

fromlangchain.agentsimportcreate_tool_calling_agent, AgentExecutor

# 导入工具封装类

fromlangchain_core.toolsimportTool

# 导入兼容 OpenAI 接口的聊天模型

fromlangchain_openaiimportChatOpenAI

# 导入提示词模板、对话占位符

fromlangchain.promptsimportChatPromptTemplate, MessagesPlaceholder

# 导入对话记忆组件,用于保存历史对话

fromlangchain.memoryimportConversationBufferMemory

# 加载 .env 文件中的环境变量(当前代码未使用,保留以支持扩展)

load_dotenv()

# ========================

# 1. 初始化大语言模型

# 说明:使用 ChatOpenAI 封装对接本地模型,因本地模型兼容 OpenAI 工具调用协议

# ========================

# 本地模型 API Key(按需替换,部分本地部署无需真实密钥)

DEEPSEEK_API_KEY="123"

llm=ChatOpenAI(

api_key=DEEPSEEK_API_KEY,

base_url="http://192.168.0.100:8085/v1",# 本地模型接口地址

model="qwen3.5-27b-awq",# 模型名称

temperature=0.3,# 温度系数,值越低回答越确定

max_tokens=1024,# 最大生成 token 数

)

# ========================

# 2. 定义本地工具函数

# 工具会被 Agent 自动调用,用于处理模型无法直接完成的任务

# ========================

defcalculate(expression:str)->str:

"""

安全计算简单数学表达式

:param expression: 数学表达式字符串,例如 '2 + 3 * 4'

:return: 计算结果或错误信息

"""

try:

# 白名单校验:仅允许数字、运算符、括号和空格,防止恶意代码执行

allowed=set("0123456789+-*/(). ")

ifnotall(cinallowedforcinexpression):

return"错误:表达式包含非法字符"

# 安全执行表达式,禁用内置函数防止代码注入

result=eval(expression, {"__builtins__": {}}, {})

returnstr(result)

exceptException as e:

returnf"计算失败: {str(e)}"

defget_current_time(dummy:str="")->str:

"""

获取当前系统日期和时间

:param dummy: 占位参数,适配工具调用格式

:return: 格式化的当前时间字符串

"""

returndatetime.now().strftime("%Y年%m%d %H:%M:%S")

# 将自定义函数注册为 LangChain 标准工具

tools=[

Tool(

name="calculate",

func=calculate,

description="执行简单数学运算。输入必须是合法的算术表达式字符串,如 '15 * 6'。",

),

Tool(

name="get_current_time",

func=get_current_time,

description="获取当前系统时间。无需传入实际参数。",

),

]

# ========================

# 3. 构建提示词模板

# 包含系统提示、对话历史、用户输入、工具调用中间步骤

# ========================

prompt=ChatPromptTemplate.from_messages([

("system","你是一个智能助手,能调用工具完成用户请求。请始终用中文回答。"),

MessagesPlaceholder("chat_history"),# 对话历史占位符,实现多轮记忆

("human","{input}"),# 用户当前输入占位符

MessagesPlaceholder("agent_scratchpad"),# 工具调用过程占位符,Agent 内部使用

])

# ========================

# 4. 创建 Tool Calling Agent 及执行器

# ========================

# 创建支持工具调用的 Agent(OpenAI 函数调用格式)

agent=create_tool_calling_agent(llm, tools, prompt)

# 初始化对话记忆:存储聊天历史,保持多轮交互连贯性

memory=ConversationBufferMemory(

memory_key="chat_history",# 与提示词中占位符名称一致

return_messages=True,# 返回消息对象而非字符串,保证格式兼容

)

# 创建 Agent 执行器:负责运行 Agent、调用工具、管理记忆

agent_executor=AgentExecutor(

agent=agent,

tools=tools,

memory=memory,

verbose=True,# 打印详细执行过程,方便调试

handle_parsing_errors=True,# 自动处理解析错误,提升稳定性

max_iterations=5,# 最大工具调用次数,防止无限循环

)

# ========================

# 5. 启动交互式对话

# 循环接收用户输入,调用 Agent 并输出回答

# ========================

if__name__=="__main__":

print("🤖 本地模型 Tool Calling 助手启动!")

print("💡 示例:你好、现在几点?、123 乘以 456 等于多少?")

print("🛑 输入 quit / exit 可退出程序。\n")

whileTrue:

user_input=input("👤 你: ").strip()

# 退出条件判断

ifnotuser_inputoruser_input.lower()in["quit","exit"]:

print("👋 再见!")

break

try:

# 调用 Agent 执行器获取回答

response=agent_executor.invoke({"input": user_input})

# 打印原始响应(调试用)

print("原始模型响应:", response)

# 输出最终回答

print(f"🤖 助手: {response['output']}\n")

exceptException as e:

print(f"❌ 错误: {e}\n")

对话内容:

🤖 本地模型 Tool Calling 助手启动!
💡 示例:你好、现在几点?、123 乘以 456 等于多少?
🛑 输入 quit / exit 可退出程序。

👤 你: 你好


> Entering new AgentExecutor chain...


你好!我是你的智能助手,很高兴为你服务。

我可以帮助你:
- 进行数学计算
- 获取当前时间
- 回答各种问题
- 完成其他任务

请问有什么我可以帮你的吗?

> Finished chain.
原始模型响应: {'input': '你好', 'chat_history': [HumanMessage(content='你好'), AIMessage(content='\n\n你好!我是你的智能助手,很高兴为你服务。\n\n我可以帮助你:\n- 进行数学计算\n- 获取当前时间\n- 回答各种问题\n- 完成其他任务\n\n请问有什么我可以帮你的吗?')], 'output': '\n\n你好!我是你的智能助手,很高兴为你服务。\n\n我可以帮助你:\n- 进行数学计算\n- 获取当前时间\n- 回答各种问题\n- 完成其他任务\n\n请问有什么我可以帮你的吗?'}
🤖 助手:

你好!我是你的智能助手,很高兴为你服务。

我可以帮助你:
- 进行数学计算
- 获取当前时间
- 回答各种问题
- 完成其他任务

请问有什么我可以帮你的吗?

👤 你: 现在几点?


> Entering new AgentExecutor chain...

Invoking: `get_current_time` with ``
responded:



2026年0413 10:31:00

现在是 2026 年 4 月 13 日 10:31:00。

> Finished chain.
原始模型响应: {'input': '现在几点?', 'chat_history': [HumanMessage(content='你好'), AIMessage(content='\n\n你好!我是你的智能助手,很高兴为你服务。\n\n我可以帮助你:\n- 进行数学计算\n- 获取当前时间\n- 回答各种问题\n- 完成其他任务\n\n请问有什么我可以帮你的吗?'), HumanMessage(content='现在几点?'), AIMessage(content='\n\n现在是 2026 年 4 月 13 日 10:31:00。')], 'output': '\n\n现在是 2026 年 4 月 13 日 10:31:00。'}
🤖 助手:

现在是 2026 年 4 月 13 日 10:31:00。

👤 你: 123 乘以 456 等于多少?


> Entering new AgentExecutor chain...

Invoking: `calculate` with `123 * 456`
responded:



56088

http://www.cnnetsun.cn/news/2991190.html

相关文章:

  • Fourtune_ML_CTF_Challenge
  • 【置顶干货】博主介绍,各类系统源码领取途径
  • 凸松弛紧密度分析:割多面体、度量多面体与椭球体的体积比较
  • React Navigation 核心原理与工程实践指南
  • 移动设备远程控制风险剖析与防御实战:从漏洞利用到企业安全管控
  • JavaScript错误处理三界:哪些能catch,哪些必须绕过
  • 听书APP哪个好用?帆书、喜马拉雅、微信读书、番茄畅听适合不同需求
  • Redux在2024:状态契约、RTK Query与现代React分层实践
  • 如何三步快速下载B站高清视频:BilibiliDown完全指南
  • 医疗AI跨平台泛化实战:任务熵与后验集中性提升眼底影像分析鲁棒性
  • 如何让老旧安卓电视流畅播放高清直播?MyTV-Android轻量级解决方案详解
  • WorkBuddy+GLM:开发者私有AI工作流的轻量级操作系统
  • Maven命令三大断点解析:生命周期、参数作用域与执行上下文
  • LinkedIn人才流动分析实战:从数据获取到仪表盘构建
  • NLP技术如何量化评估本地新闻与移民社区需求的匹配度
  • Navicat重置试用期终极指南:macOS用户必备的14天试用期破解方案
  • 【Springboot毕设全套源码+文档】基于vue+springboot高校教师绩效管理系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • Exchange自签名证书深度解析:从核心原理到实战管理
  • Triton GPU编程:用Python编写高性能AI算子的原理与实践
  • 用LoRA微调Qwen2-1.5B实现法律文书摘要生成
  • VLM视觉语言模型实战:从原理到电商图文搜索落地
  • 自动驾驶静态障碍物感知:多传感器融合的工业级实现
  • 多面体苹果皮式展开算法:从阿基米德立体到连续切割路径
  • Claude Opus 4.8实测:为什么‘不偷懒’是技术AI的新基准
  • SAM G51 ADC精度提升:增强分辨率与数字平均模式实战解析
  • 嵌入式开发中SIM模块与智能卡通信:从ATR解析到T=0/T=1协议实战
  • Vanilla JavaScript原生拖拽实现与避坑指南
  • Codex不是网页版ChatGPT:三种开发者级集成方式详解
  • OpenClaw+Kimi K2.5+Moltbook:AI Agent本地调试到云上部署闭环实战
  • 硬件加密锁逆向工程:从MicroDog原理到软件模拟实现