news 2026/9/11 6:09:01

如何在 Web-Dev-For-Beginners 用 LangChain 工具调用让 AI 执行自定义函数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何在 Web-Dev-For-Beginners 用 LangChain 工具调用让 AI 执行自定义函数

如何在 Web-Dev-For-Beginners 用 LangChain 工具调用让 AI 执行自定义函数

【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners

Web-Dev-For-Beginners 课程的 AI Framework 一课(10-ai-framework-project/README.md)演示了如何用 LangChain 的 tool calling 机制,让大模型在对话中识别并调用你自己定义的 Python 函数——比如让它执行一个加法函数add,或者调用外部 Web API 取回内容。读完并跑通本文后,你将拥有一个可以绑定自定义工具的 LangChain 客户端,并在模型判断需要某项能力时自动执行对应函数。

前提条件:

  • Python 环境,通过 pip 安装依赖;
  • 环境变量GITHUB_TOKEN可用。课程文档说明:在 GitHub Codespaces 中该 token 已经配置好;如果在本地运行,需要自行创建一个具有相应权限的 personal access token;
  • 代码连接的是 GitHub Models(base_url="https://models.github.ai/inference"),模型使用openai/gpt-4o-mini

安装依赖并连接模型

课程给出的安装命令(见文档 Quick Start 与 Assignment 的 Step 1):

pip install langchain langchain-openai

连接模型用ChatOpenAI客户端,这是后续所有工具调用代码的基础:

from langchain_openai import ChatOpenAI import os llm = ChatOpenAI( api_key=os.environ["GITHUB_TOKEN"], base_url="https://models.github.ai/inference", model="openai/gpt-4o-mini", )

仓库中的 app.py 就是这个最小客户端;如果连llm.invoke("What is the capital of France")这一步都无法返回内容,说明 token 或网络配置有问题,应先解决它再继续工具调用部分。

定义自定义函数工具

LangChain 中一个“工具”由两部分组成:一个给模型看的参数蓝图(TypedDict 类),和一个真正执行的函数实现functions字典)。课程文档用一个加法函数演示了完整写法:

from typing_extensions import Annotated, TypedDict class add(TypedDict): """Add two integers.""" # Annotations must have the type and can optionally include a default value and description (in that order). a: Annotated[int, ..., "First integer"] b: Annotated[int, ..., "Second integer"] tools = [add] functions = { "add": lambda a, b: a + b }

各部分的作用(均出自课程文档的讲解):

  • 类继承TypedDict,类的 docstring(Add two integers.)成为工具的说明,模型据此判断“这个问题该不该用这个工具”;
  • 字段用Annotated标注。文档中的注释明确了书写规则:annotation 必须包含类型,可选地按顺序附带默认值和描述;
  • tools列表是传给模型的工具清单;
  • functions字典是“工具箱”,键是工具名,值是真正执行的动作——模型只负责报出工具名和参数,执行发生在你的代码里。

绑定工具并触发调用

创建好工具后,用bind_tools把它挂到模型上:

llm_with_tools = llm.bind_tools(tools)

bind_tools调用之后,llm_with_tools这个 LLM 实例就“知道”了这些工具的存在。接下来发送请求,并检查返回值中是否产生了tool_calls

query = "What is 3 + 12?" res = llm_with_tools.invoke(query) if res.tool_calls: for tool in res.tool_calls: print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) print("CONTENT: ", res.content)

这里的执行逻辑是:模型分析 query 后,如果认定该用add工具,返回的res.tool_calls里就会有对应条目,每个条目的name指明要调哪个工具、args给出参数;functions[tool["name"]](**tool["args"])随即在你的进程里执行a + b

把上面三段拼起来的完整脚本(与文档中的全量代码一致):

from langchain_core.messages import HumanMessage, SystemMessage from langchain_openai import ChatOpenAI import os from typing_extensions import Annotated, TypedDict class add(TypedDict): """Add two integers.""" a: Annotated[int, ..., "First integer"] b: Annotated[int, ..., "Second integer"] tools = [add] functions = { "add": lambda a, b: a + b } llm = ChatOpenAI( api_key=os.environ["GITHUB_TOKEN"], base_url="https://models.github.ai/inference", model="openai/gpt-4o-mini", ) llm_with_tools = llm.bind_tools(tools) query = "What is 3 + 12?" res = llm_with_tools.invoke(query) if res.tool_calls: for tool in res.tool_calls: print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) print("CONTENT: ", res.content)

验证结果

文档给出的示例输出为(注意是“output similar to”,实际措辞和空行可能不同):

TOOL CALL: 15 CONTENT:

看到这个结果说明链路完整工作:模型从add工具的名字、描述和字段规格中识别出这是一次加法任务,functions字典里的 lambda 实际算出了 15。CONTENT:之后为空是文档示例中的正常现象——这一轮模型只报工具调用,没有另行生成文本。

如果res.tool_calls为空、只打印出CONTENT:,说明模型没有把这次请求路由到工具;文档没有给出更多排错顺序,此时可以先核对tools是否已传入bind_tools、query 是否确实匹配工具描述。

可选分支:让自定义函数调用外部 Web API

加法函数只演示机制,文档的进阶例子是让工具真正干活——joke工具会请求https://api.chucknorris.io/jokes/random?category={category}并返回 JSON 中的value字段:

class joke(TypedDict): """Tell a joke.""" category: Annotated[str, ..., "The joke category"] def get_joke(category: str) -> str: response = requests.get( f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"} ) if response.status_code == 200: return response.json().get("value", f"Here's a {category} joke!") return f"Here's a {category} joke!" functions = { "add": lambda a, b: a + b, "joke": lambda category: get_joke(category) } tools = [add, joke]

配套改动只有两处:把joke加进tools列表、把joke的实现加进functions字典,后面的bind_tools/invoke/tool_calls流程完全不变。查询换成:

query = "Tell me a joke about animals"

文档给出的示例输出(同样是“something like”):

TOOL CALL: Chuck Norris once rode a nine foot grizzly bear through an automatic car wash, instead of taking a shower. CONTENT:

两点需要注意:

  • 这段代码import requests,运行前环境中需要有requests库;
  • get_joke在接口非 200 时会返回兜底文案Here's a {category} joke!,而不是抛异常。

仓库里可直接运行的完整脚本是 app-tools.py,内容与文档全量代码一致,addjoke两个工具都已绑定。

限制与下一步

  • 工具是否被调用由模型根据工具名、描述和字段规格自行判断,文档中的说法是:模型“examined” query 后“made this determination from the tool's name, description, and field specifications”。描述写得模糊会增加误判概率,这一点由 TypedDict 的 docstring 和Annotated描述字段控制。
  • res.tool_calls可能为空(模型直接作答),代码必须像文档示例那样先判断再执行,不能假设每次都会触发工具。

文档在“Building a complete AI application”一节把工具调用和会话记忆组合成了一个CodingAssistant类(含execute_tool分发逻辑),Assignment 则要求实现至少两个教育类工具的StudyAssistant,两者都在 10-ai-framework-project/README.md 内,可作为跑通本文后的延伸练习。

【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 6:08:54

OpenClaw AI Agent开发:3.99美元专属实例深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:07:55

UEFI裸金属自检:手写21项硬件测试,从启动到一键报告的实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:06:15

一体化招聘管理系统选型指南:从流程梳理到落地避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:05:34

六轴EKF四元数姿态解算:从原理到源码实现与调参

简介:面向无人机、机器人及惯性导航等领域的开发者,这套源码以 Python 语言实现了基于扩展卡尔曼滤波(EKF)的四元数姿态解算算法,适用于六轴传感器(加速度计与陀螺仪)数据融合,可帮助…

作者头像 李华