
一、先搞懂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调用等只需按照相同的规范封装工具即可实现更多场景的自动化处理真正让大模型成为高效的辅助工具。代码实现123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141# -*- coding: utf-8 -*-基于 LangChain 的 Tool Calling 智能助手- 对接兼容 OpenAI 工具调用格式的本地大模型qwen3.5-27b-awq- 内置工具数学计算器、获取当前时间纯本地实现无外部依赖- 支持多轮对话记忆可连贯交互- 核心架构OpenAI 风格函数调用Tool CallingAgentimportosfromdatetimeimportdatetimefromdotenvimportload_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_KEY123llmChatOpenAI(api_keyDEEPSEEK_API_KEY,base_urlhttp://192.168.0.100:8085/v1,# 本地模型接口地址modelqwen3.5-27b-awq,# 模型名称temperature0.3,# 温度系数值越低回答越确定max_tokens1024,# 最大生成 token 数)# # 2. 定义本地工具函数# 工具会被 Agent 自动调用用于处理模型无法直接完成的任务# defcalculate(expression:str)-str:安全计算简单数学表达式:param expression: 数学表达式字符串例如 2 3 * 4:return: 计算结果或错误信息try:# 白名单校验仅允许数字、运算符、括号和空格防止恶意代码执行allowedset(0123456789-*/(). )ifnotall(cinallowedforcinexpression):return错误表达式包含非法字符# 安全执行表达式禁用内置函数防止代码注入resulteval(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(namecalculate,funccalculate,description执行简单数学运算。输入必须是合法的算术表达式字符串如 15 * 6。,),Tool(nameget_current_time,funcget_current_time,description获取当前系统时间。无需传入实际参数。,),]# # 3. 构建提示词模板# 包含系统提示、对话历史、用户输入、工具调用中间步骤# promptChatPromptTemplate.from_messages([(system,你是一个智能助手能调用工具完成用户请求。请始终用中文回答。),MessagesPlaceholder(chat_history),# 对话历史占位符实现多轮记忆(human,{input}),# 用户当前输入占位符MessagesPlaceholder(agent_scratchpad),# 工具调用过程占位符Agent 内部使用])# # 4. 创建 Tool Calling Agent 及执行器# # 创建支持工具调用的 AgentOpenAI 函数调用格式agentcreate_tool_calling_agent(llm, tools, prompt)# 初始化对话记忆存储聊天历史保持多轮交互连贯性memoryConversationBufferMemory(memory_keychat_history,# 与提示词中占位符名称一致return_messagesTrue,# 返回消息对象而非字符串保证格式兼容)# 创建 Agent 执行器负责运行 Agent、调用工具、管理记忆agent_executorAgentExecutor(agentagent,toolstools,memorymemory,verboseTrue,# 打印详细执行过程方便调试handle_parsing_errorsTrue,# 自动处理解析错误提升稳定性max_iterations5,# 最大工具调用次数防止无限循环)# # 5. 启动交互式对话# 循环接收用户输入调用 Agent 并输出回答# if__name____main__:print( 本地模型 Tool Calling 助手启动)print( 示例你好、现在几点、123 乘以 456 等于多少)print( 输入 quit / exit 可退出程序。\n)whileTrue:user_inputinput( 你: ).strip()# 退出条件判断ifnotuser_inputoruser_input.lower()in[quit,exit]:print( 再见)breaktry:# 调用 Agent 执行器获取回答responseagent_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 * 456responded:56088