DeepSeek-Agent-Harness-2026终极指南-第4章第17节-AgentLoop心脏-工具调用协议:Function Calling的JSON之美
工具调用协议Function Calling 的 JSON 之美上一节模型学会了说要做什么。这一节我们用一套 JSON 协议把这句话变成机器能理解、程序能执行的指令。Function Calling——让模型出手的那只手本质是两次优雅的 JSON 交换。本文导航工具调用到底在解决什么问题第一份 JSONtools 工具说明书第二份 JSONtool_calls 模型的下单第三份 JSONtool 角色回填一个工具从定义到调用的全链路用 pydantic 校验这份 JSON 之美小结下节预告第 17 节。上一节我们见识了 ReAct 的舞步但那个假装调用终究是假的。这节把假变真——用 OpenAI 兼容协议里的Function Calling功能调用机制让 DeepSeek 宣布我要调用工具并给出精确的参数。先记住一句话Function Calling 不是让模型去执行函数而是让模型声明它想调用哪个函数、参数是什么——执行的事还是你的 Harness 干的。这个声明通过 JSON 传递所以叫JSON 之美。工具调用到底在解决什么问题不用工具调用你的模型永远只能输出文字。为了让它能动手你面临两个问题怎么告诉模型有哪些工具可用—— 你不能把每个工具的实现代码塞进提示词里太长、太乱。怎么让模型精确表达我要调用 get_weather(city‘北京’)—— 让模型输出自然语言帮我查一下北京的天气你的解析代码得崩溃。Function Calling 用结构化的 JSON同时解决这两难工具的说明书是 JSON Schema模型的调用意向也是结构化的 JSON。两次交换全链路就跑通了。第一份 JSONtools 工具说明书第一份 JSON 是你写进请求里的tools参数——相当于给模型递上一份菜单让它知道自己能点什么菜。每个工具是一个对象核心是function字段下的name、description、parameters{type:function,function:{name:get_weather,description:查询指定城市的当前天气返回温度和天气状况。当用户询问某地天气时使用。,parameters:{type:object,properties:{city:{type:string,description:城市名如北京、上海、深圳}},required:[city]}}}关键点name模型的点菜口令必须唯一、稳定。description决定模型会不会用它。写得越清楚做什么/何时用模型越会用对。这是第 45 节《工具描述工程》的重头戏先埋个伏笔。parameters严格遵循JSON Schema规范描述每个参数的类型、含义、是否必填。模型严格按它填参数。这个parameters里的 JSON Schema是模型能精确输出的地基。你甚至可以手写但更聪明的做法是用 pydantic 模型反射自动生成——那是第 36 节《工具注册中心》的核心现在先知道说明书长这样。第二份 JSONtool_calls 模型的下单把tools塞进请求发给 DeepSeek如果模型认为该用工具它的响应里就不再只有content而是多出一个tool_calls数组——这就是模型的下单指令{id:call_abc123,type:function,function:{name:get_weather,arguments:{\city\:\北京\}}}注意三个细节都容易踩坑id每次调用都会生成一个唯一 id回填结果时要拿它做对账告诉模型我执行了 was 你下的那一单。arguments是字符串不是对象模型返回的 arguments 是 JSON 字符串你需要先json.loads或pydantic解析成字典再去调用真实函数。一次响应可能有多个 tool_calls模型可以一次性点上好几道菜并行调用你的循环要能处理数组。模型回答时content字段可能为空“我不说话了直接干活”也可能带着一句解释。别假定 content 一定非空。第三份 JSONtool 角色回填模型下单了你的 Harness 拿到参数执行完真实函数拿到结果。然后呢必须用role: tool的消息把结果回填给模型让它看到行动的结果从而决定下一步。这就是 Observation。messages.append({role:tool,tool_call_id:call_abc123,# 必须和下单时的 id 一致content:北京现在 26℃晴朗,# 工具执行结果})回填时必须同时满足两个要求缺一个模型就看不懂tool_call_id必须等于之前 tool_calls 里那个 id对账必须把当次响应里的assistant消息含 tool_calls一起追加。也就是说模型那轮下单的 assistant 消息必须原样保留在 messages 里工具结果才能挂到它后面。这背后是 OpenAI 协议的一条硬性约束消息历史里每次 tool_calls 之后必须紧跟对应的一组 tool 消息否则报错或模型混乱。我们后面实现的 Agent Loop 会严格遵守这条。一个工具从定义到调用的全链路把所有 JSON 串起来就是一个完整的调用时序。看这张图把它刻进脑子User工具函数DeepSeekHarnessUser工具函数DeepSeekHarness请求 messages tools 说明书响应 tool_calls [get_weather(city北京)]解析 arguments (json.loads / pydantic)调用真实函数 get_weather(北京)返回 北京 26℃ 晴朗追加 tool 消息回填结果 (tool_call_idcall_abc123)响应最终文字 北京现在26℃微风输出最终答案两次 JSON 交换下单 回填撑起了整个循环。每次模型带 tool_calls 返回你就补一手工具结果模型看到结果再决定继续调用还是收尾。这个节奏就是第 16 节 ReAct 循环在协议层的实体。用 pydantic 校验这份 JSON 之美模型输出的arguments是自由意志的产物格式可能飘参数名拼错、类型错、缺字段。跨过不可信输出这道坎靠的是我们一贯的 pydantic 强类型校验用户铁律。tool_calls_demo.py —— 用 pydantic 解析并校验模型返回的工具调用第17节 运行环境Python 3.12 uv 管理 依赖 uv add openai pydantic 用法 set DEEPSEEK_API_KEY你的key uv run python tool_calls_demo.py importjsonimportosfromopenaiimportOpenAIfrompydanticimportBaseModel,Field clientOpenAI(base_urlhttps://api.deepseek.com,api_keyos.environ.get(DEEPSEEK_API_KEY),)# 1. 用 pydantic 定义工具参数的强类型结构classWeatherParams(BaseModel):city:strField(description城市名)# 2. 构造 tools 说明书此处用 pydantic 模型生成 JSON Schema 的雏形tools[{type:function,function:{name:get_weather,description:查询指定城市的当前天气,parameters:WeatherParams.model_json_schema(),# pydantic 反射生成},}]messages[{role:system,content:你是天气助手用户问天气就调用 get_weather。},{role:user,content:北京今天的天气怎么样},]respclient.chat.completions.create(modeldeepseek-flash,messagesmessages,toolstools,)msgresp.choices[0].messageprint(content:,msg.content)print(tool_calls:,msg.tool_calls)# 3. 解析并校验模型返回的参数 —— 模型不可信必须校验ifmsg.tool_calls:fortcinmsg.tool_calls:raw_argsjson.loads(tc.function.arguments)# 先把字符串变字典validatedWeatherParams(**raw_args)# pydantic 校验并转强类型print(f校验通过 → 调用 get_weather(city{validated.city!r}))真实运行一次输出大致是我用一次实测记录content: None tool_calls: [ChatCompletionMessageToolCall(idcall_1x2y3z, typefunction, functionFunction(arguments{city:北京}, nameget_weather))] 校验通过 → 调用 get_weather(city北京)注意content: None——模型这轮没说话直接下单。arguments是字符串{city:北京}我们json.loads后再用WeatherParams校验city 被强转成北京的 Python 字符串。就算模型输出{city: 123}这种类型错误pydantic 也会当场抛校验异常而不是把脏数据喂进之后的业务逻辑。这就是模型不可信、我们用校验兜底的工程哲学。model_json_schema()这个反射能力很有用但真正的工具注册中心还会有更完整的配置第 36 节细讲。小结Function Calling 两次 JSON 交换你递tools说明书模型回tool_calls下单你回填tool结果。模型不真执行只声明的意图执行永远在 Harness 侧这是 Agent 架构的安全分界。arguments是字符串要先json.loads再校验别直接当字典用。回填必须对账tool_call_id要对上且 assistant含 tool_calls消息要原样保留。模型输出不可信用 pydantic 强类型校验参数是底线脏数据进不了业务逻辑。下节预告循环转起来了但有个坏消息模型有时永远不想停——它不停地下单、下单、下单。下节我们聊什么时候算想好了循环的三种终止条件以及那个让每个 Agent 开发者头大的模型停不下来案例。如果觉得本文对你有帮助欢迎点赞、收藏、关注三连本系列持续更新中关注不迷路~

相关新闻

文件内容搜索工具:dnGrep+TommSearch全文检索,不建索引也能搜压缩包PDF,安装包下载

文件内容搜索工具:dnGrep+TommSearch全文检索,不建索引也能搜压缩包PDF,安装包下载

昨天整理项目资料,翻出三年前的一堆文档,光文件名搜素根本不够用,我得搜文件里的内容。Everything 大家都用过,但它只搜文件名,内容搜索是另一回事。折腾了一下午,留下两款真正能打的内容搜索工具。dnGrep …

2026/9/30 11:22:36 阅读更多 →
第四篇 线程池与任务队列

第四篇 线程池与任务队列

原项目:qinguoyi/TinyWebServer 复刻仓库:L2501031968/ccTinyWebServer 完整 20 章教程:仓库内 docs/TinyWebServer-Recreation.md 第 7 章 线程池与任务队列 7.0 本章操作顺序 本章按照以下顺序修改,避免中途出现“引用了还不存…

2026/9/30 11:22:36 阅读更多 →
IO模型详解:从阻塞到epoll,高并发网络编程的基石

IO模型详解:从阻塞到epoll,高并发网络编程的基石

1. IO模型到底是什么?先分清这几个基础概念 Unix/Linux下的IO,很多人一看到就说"异步、同步、阻塞、非阻塞"四个词,但真到了写代码或者排查性能问题的时候,就发现完全对不上号。我自己带过不少刚入门的同学,…

2026/9/30 11:22:36 阅读更多 →

最新新闻

开题报告别再只问“哪个网站第一”了:智能材料与结构同学的分环节工具清单 [特殊字符]

开题报告别再只问“哪个网站第一”了:智能材料与结构同学的分环节工具清单 [特殊字符]

如果你读的是工学 / 材料类 / 智能材料与结构,大概率会遇到一种很典型的“开题焦虑”: 题目看起来又酷又前沿,比如**“基于压电传感器阵列的纤维增强复合材料冲击定位与损伤识别”**,但真到写开题报告时,问题一下子全冒…

2026/9/30 13:20:44 阅读更多 →
Linux下ORCA与xtb联用安装配置与构象筛选实践

Linux下ORCA与xtb联用安装配置与构象筛选实践

标题里的"OCRA"是个常见的笔误,圈内都写作 ORCA——量子化学里那套 ADF 之外最常被计算化学工作者搬上集群的从头算/DFT 程序。而 xtb 是另一条线上的东西:GFN 系列半经验紧束缚方法,速度比 DFT 快两三个数量级。这两个程序单拎出来…

2026/9/30 13:20:44 阅读更多 →
资源加载与缓存机制全解析:从HTTP强缓存到Service Worker实践

资源加载与缓存机制全解析:从HTTP强缓存到Service Worker实践

页面卡在白屏不动,打开控制台一看,一堆资源在排队下载,接口响应挺快,但页面就是迟迟不渲染。这种问题排查到最后,几乎都会落到两个词上:资源加载和缓存机制。尤其是系统性的前端项目或大型 Web 应用,资源加载管的是“东西怎么运过来”,缓存管的是“东西到了之后怎么存、怎么复用…

2026/9/30 13:20:44 阅读更多 →
2026深圳靠谱的高端定制网站建设公司哪家好?十大设计、开发、口碑兼优建站服务商推荐榜发布及选型避坑指南

2026深圳靠谱的高端定制网站建设公司哪家好?十大设计、开发、口碑兼优建站服务商推荐榜发布及选型避坑指南

一、2026年深圳网站建设市场现状:官网的价值定位正在被重写 2026 年,企业官网已经彻底突破"线上名片"的传统定位,进化为承载品牌信任塑造、智能流量承接、商务线索沉淀与全域市场拓展的核心数字化经营载体。据行业数据机构发布的年…

2026/9/30 13:20:44 阅读更多 →
PHP + Apache2 一键容器化:基于 Docker Compose 的 apache-php 示例完整实战指南

PHP + Apache2 一键容器化:基于 Docker Compose 的 apache-php 示例完整实战指南

示例工程 【免费下载链接】awesome-compose Awesome Docker Compose samples 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-compose 点击查看 免费下载 本指南围绕 awesome-compose 仓库中 apache-php 示例展开,讲解如何用 Docker Compose 将一…

2026/9/30 13:20:44 阅读更多 →
URP、HDRP与UE4全局光照对比:烘焙与实时GI选型指南

URP、HDRP与UE4全局光照对比:烘焙与实时GI选型指南

前阵子一个做独立游戏的朋友问了我一个挺典型的问题:同一套低模场景,在URP里烘焙完,切到HDRP之后光照颜色和亮度全变了;放到UE4里用Lightmass重新烘焙,出来的效果又是另一个味道。我说这太正常了,因为三个方…

2026/9/30 13:19:43 阅读更多 →

日新闻

Base64 图片头部特征识别:从文件头到格式判断的完整指南

Base64 图片头部特征识别:从文件头到格式判断的完整指南

1. 项目概述:为什么说看懂 base64 图片头部是基本功这几年跟 base64 打交道的机会越来越多,后端接口返回图片、前端渲染验证码、小程序里存小图、还有一些老系统导出报表,动不动就给你一段长到怀疑人生的 base64 字符串。很多人拿到字符串就直…

2026/9/30 0:00:35 阅读更多 →
Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

简介:本资源是一份面向Java初学者与课程设计学生的公交站牌广告灯箱管理系统毕业设计文档,聚焦城市公共广告资源信息化管理痛点,提供从需求分析到技术实现的完整方案。文档采用标准学术论文结构,含摘要、英文摘要、目录及五章正文…

2026/9/30 0:00:35 阅读更多 →
用 Redis Lua 构建大模型 API 多租户原子配额治理体系

用 Redis Lua 构建大模型 API 多租户原子配额治理体系

我去年年底接了一个内部 AI 平台的治理需求,背景很直接:公司把 DeepSeek、MiniMax 这类大模型 API 统一封装成内部网关,开放给几个业务团队用。结果第一个月账单出来,额度直接超了 4 倍。仔细查日志,发现原因并不复杂—…

2026/9/30 0:00:35 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/30 13:14:22 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 16:41:41 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/30 13:14:49 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/29 19:29:29 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/29 5:58:00 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/29 3:55:56 阅读更多 →