从零搭建一个最小 AI Agent:Python 完整示例 + AI调用机制详解
「Agent」是 LLM 应用从「能聊天」到「能干活」的关键一跃。本文先用 Python OpenAI 兼容接口实现一个最小可运行的 Agent,再详细拆解AI 是如何知道 Agent 提供了哪些工具、如何决定调用、又如何把结果回流到对话。一、什么是 Agent?30 秒理解Agent LLM 工具 循环LLM—— 大脑,负责理解、推理、决策工具(Tools)—— 手脚,负责实际干活(查数据库、调 API、跑代码)循环(Loop)—— 持续「思考 → 行动 → 观察」直到任务完成经典ReAct 模式(Reasoning Acting):循环开始 ├─ Thought: LLM 想一步 ├─ Action: LLM 决定调哪个工具 ├─ Observation: 工具执行结果回传 └─ 判断: 任务完成?没完成就回循环开头 循环结束 → 最终回答与「单次 function calling」的区别:function calling ——一轮就结束(LLM 调一次工具,拿到结果,直接答)Agent ——多轮循环(LLM 可以连续调多个工具,中间还能自我修正)二、最小可运行 Agent 示例2.1 环境准备pipinstallopenai本文使用 OpenAI 兼容接口(支持 OpenAI / DeepSeek / 通义 / 智谱 / 本地 vLLM 等)。2.2 完整代码(agent.py)# -*- coding: utf-8 -*- 最小 Agent 示例 - 2 个工具:加法、天气查询 - ReAct 循环:LLM 决策 → 执行工具 → 结果回流 → 直到 LLM 不再要工具 importsysimportjsonfromopenaiimportOpenAI sys.stdout.reconfigure(encodingutf-8)# 1. 初始化 LLM 客户端 clientOpenAI(base_urlhttps://newapi-ai.xxx.com/v1,# 替换成你的 OpenAI 兼容端点api_keysk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)MODELglm-5.2-local# 2. 定义工具(实际可执行的 Python 函数)defadd(a:float,b:float)-str:两个数字相加,返回它们的和。 Args: a: 第一个数字 b: 第二个数字 returnf{a}{b}{ab}defget_weather(city:str)-str:查询某个城市的当前天气(模拟数据)。 Args: city: 城市名称,如 北京 mock{北京:晴,18℃,上海:多云,22℃,深圳:雷阵雨,28℃,}returnmock.get(city,f未收录{city}的天气,默认晴 20℃)# 工具名 → 实际函数的映射表TOOL_FUNCTIONS{add:add,get_weather:get_weather,}# 3. 工具的 JSON Schema(给 LLM 看的「菜单」)TOOLS_SCHEMA[{type:function,function:{name:add,description:两个数字相加,返回它们的和。,parameters:{type:object,properties:{a:{type:number,description:第一个数字},b:{type:number,description:第二个数字},},required:[a,b],},},},{type:function,function:{name:get_weather,description:查询某个城市的当前天气(模拟数据)。,parameters:{type:object,properties:{city:{type:string,description:城市名称,如 \北京\},},required:[city],},},},]# 4. Agent 主循环(ReAct)defrun_agent(user_query:str,max_steps:int10)-str:运行 Agent 循环,直到 LLM 不再请求工具或达到最大步数messages[{role:system,content:你是一个有用的助手,可以调用工具回答问题。},{role:user,content:user_query},]forstepinrange(1,max_steps1):print(f\n────── Agent Step{step}──────)# 4.1 把对话历史 工具 schema 一起发给 LLMresponseclient.chat.completions.create(modelMODEL,messagesmessages,toolsTOOLS_SCHEMA,# 关键:注入工具清单tool_choiceauto,# auto:让 LLM 自己决定调不调工具)msgresponse.choices[0].message# 4.2 把 LLM 这轮的回答加回对话历史messages.append(msg)# 4.3 如果 LLM 没要求调工具 → 任务完成,直接返回ifnotmsg.tool_calls:print(f[最终回答]{msg.content})returnmsg.content# 4.4 LLM 要求调工具 → 逐个执行fortool_callinmsg.tool_calls:nametool_call.function.name argsjson.loads(tool_call.function.arguments)print(f[调用工具]{name}({args}))# 真正执行 Python 函数resultTOOL_FUNCTIONS[name](**args)print(f[工具返回]{result})# 4.5 把执行结果作为 roletool 的消息回传给 LLMmessages.append({role:tool,tool_call_id:tool_call.id,# 关键:把结果和请求对应起来content:result,})return达到最大步数,任务未完成# 5. 跑起来 if__name____main__:# 单工具调用run_agent(北京天气怎么样?)# 多工具调用 推理(需要循环)run_agent(北京和上海哪个温度更高?高多少?)2.3 跑一遍看输出输入:北京和上海哪个温度更高?高多少?────── Agent Step 1 ────── [调用工具] get_weather({city: 北京}) [工具返回] 晴,18℃ ────── Agent Step 2 ────── [调用工具] get_weather({city: 上海}) [工具返回] 多云,22℃ ────── Agent Step 3 ────── [最终回答] 上海温度更高,比北京高 4℃(上海 22℃,北京 18℃)。注意 Step 1 和 Step 2 —— LLM没有一次性把两个工具都调完,而是分两轮:第一轮调北京,第二轮调上海。这是因为某些模型在tool_choiceauto下默认每轮只调一个工具。多轮循环正是 Agent 区别于单次 function calling 的价值。三、代码结构剖析整个 Agent 由 5 部分组成:┌──────────────────────────────────────────┐ │ 1. LLM Client │ ← OpenAI 兼容接口 ├──────────────────────────────────────────┤ │ 2. Tools(Python 函数) │ ← 真正干活的代码 ├──────────────────────────────────────────┤ │ 3. Tools Schema(JSON Schema) │ ← 给 LLM 看的「菜单」 ├──────────────────────────────────────────┤ │ 4. Agent Loop(ReAct) │ ← 思考-行动-观察循环 ├──────────────────────────────────────────┤ │ 5. Entrypoint │ ← 跑起来 └──────────────────────────────────────────┘核心是第 3 和第 4 部分:第 3 部分回答「AI 怎么知道有哪些工具」第 4 部分回答「AI 怎么调、结果怎么回流」四、AI 是如何知道 Agent 提供了哪些方法的?这是本文的核心问题。拆成3 个阶段:阶段 1: 工具注入(把工具菜单交给 LLM) → 阶段 2: LLM 决策(读菜单,决定要不要用、用哪个) → 阶段 3: 结果回流(执行结果以 roletool 回传)4.1 阶段一:工具注入 ——tools字段Agent 调 LLM 时,把TOOLS_SCHEMA放进tools参数:responseclient.chat.completions.create(modelMODEL,messagesmessages,toolsTOOLS_SCHEMA,# ← 工具清单在这里tool_choiceauto,)LLM 实际收到的请求长这样(简化):{model:glm-5.2-local,messages:[{role:system,content:你是一个有用的助手...},{role:user,content:北京天气怎么样?}],tools:[{type:function,function:{name:add,description:两个数字相加,返回它们的和。,parameters:{type:object,properties:{a:{type:number,description:第一个数字},b:{type:number,description:第二个数字}},required:[a,b]}}},{type:function,function:{name:get_weather,description:查询某个城市的当前天气(模拟数据)。,parameters:{type:object,properties:{city:{type:string,description:城市名称,如 \北京\}},required:[city]}}}],tool_choice:auto}LLM 看到这份菜单后,知道了 3 件事:字段LLM 据此知道什么name工具叫什么 → 决定要不要选它description工具干嘛用的 → 判断是否匹配用户意图parameters(JSON Schema)要传什么参数、什么类型、哪些必填 → 决定怎么调关键认知:LLM 不知道你的 Python 函数长什么样,它只看到这份 JSON Schema。Schema 写得越清晰,LLM 调用越准;Schema 模糊,LLM 就乱调或瞎传参数。4.2 阶段二:LLM 决策 —— 输出tool_callsLLM 内部经过推理,如果觉得需要调工具,返回的message里会带tool_calls字段:{role:assistant,content:null,tool_calls:[{id:call_abc123,type:function,function:{name:get_weather,arguments:{\city\: \北京\}}}]}注意几个细节:content可能为 null—— LLM 决定调工具时,不一定说话(部分模型会同时输出思考过程,content 就不为空)arguments是字符串化的 JSON—— 不是 dict,需要json.loads()解析id是这次调用的唯一标识—— 回传结果时要用它把结果和请求对应起来可能同时调多个工具——tool_calls是数组,LLM 可以一次要多个工具的结果(并行调用)4.3 阶段三:结果回流 ——roletoolAgent 执行完 Python 函数,把结果以roletool的消息塞回messages:messages.append({role:tool,tool_call_id:tool_call.id,# ← 用 id 对应上 Step 2 的请求content:result,})为什么tool_call_id这么重要?设想 LLM 一次调了 3 个工具(call_1、call_2、call_3),你执行完回传 3 条roletool消息。LLM 怎么知道哪条结果对应哪个工具?靠tool_call_id。少了这个字段,API 会直接报错。回传后,下一轮调 LLM 时,它看到的对话历史变成:[{role:system,content:你是一个有用的助手...},{role:user,content:北京天气怎么样?},{role:assistant,content:null,tool_calls:[{id:call_abc123,...}]},{role:tool,tool_call_id:call_abc123,content:晴,18℃}]LLM 读到工具返回的「晴,18℃」,再生成最终回答:「北京现在是晴天,气温 18℃。」五、完整时序图用户 Agent Code LLM 工具函数 │ │ │ │ │ 北京天气? │ │ │ │──────────────────│ │ │ │ │ 1. messages tools schema │ │ │───────────────────│ │ │ │ │ │ │ │ 2. LLM 推理 → 决定调 get_weather │ │ │───────────────────│ │ │ │ tool_calls: [get_weather(北京)] │ │ │ │ │ │ │ 3. 解析 arguments,调 Python 函数 │ │ │──────────────────────────────────────│ get_weather() │ │──────────────────────────────────────│ 晴,18℃ │ │ │ │ │ │ 4. 把结果作为 roletool 回传 │ │ │───────────────────│ │ │ │ │ │ │ │ 5. LLM 生成最终回答 │ │ │───────────────────│ │ │ │ 北京晴天 18℃ │ │ │ │ │ │ │ 北京晴天 18℃ │ │ │ │──────────────────│ │ │六、关键设计点6.1tool_choice的 3 种取值tool_choiceauto# LLM 自己决定调不调(推荐)tool_choicenone# 强制不调(用于纯对话场景)tool_choicerequired# 强制必须调一个(确保 LLM 行动)tool_choice{type:function,function:{name:add}}# 指定调某个6.2 Schema 是 LLM 唯一依据LLM 完全不知道你的 Python 函数实现,它只看 schema。所以:description要写清「这个工具干嘛的」「什么时候该用」「不该用的时候怎么办」参数description要写清楚含义、单位、格式(如时间戳,毫秒而不是时间)required要准确,该必填的别漏6.3 错误处理:工具执行失败也要回传错误的做法:工具抛异常就 raise,Agent 崩了。正确的做法:工具失败时,把错误信息作为content回传,让 LLM 自己决定怎么办:try:resultTOOL_FUNCTIONS[name](**args)exceptExceptionase:resultf工具执行失败:{type(e).__name__}:{e}messages.append({role:tool,tool_call_id:tool_call.id,content:result,# 失败信息也回流})LLM 看到「工具执行失败」后,可能会:换个参数重试换另一个工具直接告诉用户「这个我做不了」这就是 Agent 的自我修正能力,前提是错误信息要回流。6.4 工具粒度太粗太细适中run_anything(query)—— LLM 不会用add_one(x)—— 上下文爆掉add(a, b)/get_weather(city)经验:一个工具做一件事,工具之间可组合。6.5 最大步数兜底forstepinrange(1,max_steps1):...LLM 偶尔会陷入「调用 → 失败 → 再调用」的死循环,设max_steps10兜底,防止 token 烧爆。七、MCP 与 Agent 的关系很多人混淆 MCP 和 Agent,这里厘清一下:维度MCPAgent是什么协议(JSON-RPC)应用模式(LLM 工具 循环)解决什么工具的标准化接入多步推理 工具调用关系提供 tools 的来源消费 tools 的主体打个比方:MCP USB 标准 —— 任何设备按 USB 协议做接口,任何电脑都能用Agent 用 USB 接了一堆设备的电脑 —— 真正干活的是电脑Agent 的工具不一定来自 MCP,可以直接在代码里定义(本文示例就是)。但 MCP 让 Agent 能动态接入任何符合协议的工具服务器,扩展性强得多。八、调试与验证8.1 打印每一轮的 messages最直接的调试方式:forstepinrange(1,max_steps1):responseclient.chat.completions.create(...)msgresponse.choices[0].message messages.append(msg)print(f[Step{step}] messages:)print(json.dumps(messages,ensure_asciiFalse,indent2))...看 messages 演化,就能看清 Agent 的「思考轨迹」。8.2 用response.usage监控 tokenprint(f[Step{step}] tokens:{response.usage.total_tokens})如果某轮 token 突增,可能是工具返回了超长内容,该截断或总结。8.3 工具执行日志每次调用工具时打印name(args) → result,方便定位「工具对不对」「参数对不对」「结果格式对不对」。九、常见坑坑 1:Schema 里description写得太简短# 反例description:查询天气# 正例description:查询某个城市的当前天气。返回格式:天气描述,温度℃。仅支持中国大陆主要城市,不支持海外。LLM 只看 description 判断用不用,描述不清就会乱调或不调。坑 2:arguments忘了json.loads# 反例:arguments 是字符串,直接 **args 会报错resultTOOL_FUNCTIONS[name](**tool_call.function.arguments)# 正例:先解析成 dictargsjson.loads(tool_call.function.arguments)resultTOOL_FUNCTIONS[name](**args)坑 3:漏传tool_call_id# 反例:不带 id,API 直接报错messages.append({role:tool,content:result})# 正例messages.append({role:tool,tool_call_id:tool_call.id,content:result,})坑 4:忘记把msg加回messages# 反例:msg.tool_calls 用了,但没把 msg 加进 messages,LLM 下一轮会困惑fortool_callinmsg.tool_calls:...messages.append({role:tool,...})# 正例:先把 assistant 消息加进去,再加 tool 结果messages.append(msg)fortool_callinmsg.tool_calls:...坑 5:工具返回 dict / 对象# 反例:返回 dict,LLM 收到 [object Object] 之类defget_weather(city):return{temp:18,weather:晴}# 正例:返回字符串,信息明确defget_weather(city):return晴,18℃如果非要返回结构化数据,json.dumps(ensure_asciiFalse)一下。坑 6:LLM 不调工具直接编答案可能原因:tools没传 / schema 写错description不清楚,LLM 觉得自己知道答案tool_choice设成了none排查:打印完整请求,看tools字段有没有正确传过去。十、进阶:从 30 行 Agent 到生产级 Agent进阶项价值多工具管理用注册器自动生成 schema,避免手写(类似 FastAPI)工具权限控制危险工具要人工确认(如删数据库)持久化记忆把对话历史存向量库,跨会话记忆RAG 注入把检索到的文档作为roleuser上下文并行工具调用LLM 一次要多个工具时,asyncio.gather 并行执行流式输出用streamTrue实时看到 LLM 思考过程多 Agent 协作Agent 调 Agent(子任务委派)MCP 接入工具来源从「代码里硬编码」升级为「动态加载 MCP Server」成熟框架:LangChain / LangGraph—— 全家桶,生态完整但偏重LlamaIndex—— RAG 向 Agent 扩展AutoGen—— 微软出品,多 Agent 协作OpenAI Assistants API—— 托管式 AgentAnthropic Claude Agent SDK—— 官方新框架十一、总结一个最小 Agent 的核心只有 3 件事:把工具清单注入 LLM 上下文(tools字段 JSON Schema)LLM 决策后输出tool_calls(namearguments)Agent 执行后以roletool回流结果(带tool_call_id)AI 知道 Agent 有什么工具、怎么调,本质是看你写的 JSON Schema——name是工具名,description是说明,parameters是入参契约。Schema 是 LLM 唯一能看到的工具文档,写得越清晰,Agent 行为越可靠。Agent 的「智能」不在循环本身,而在LLM 看 Schema 后能不能选对工具、传对参数、用好结果。这个能力的下限由 LLM 决定,但上限由你写 Schema 的认真程度决定。十二、参考OpenAI Function Calling 文档:https://platform.openai.com/docs/guides/function-callingReAct 论文:https://arxiv.org/abs/2210.03629LangChain Agent 概念:https://python.langchain.com/docs/concepts/agents/MCP 与 Agent:https://modelcontextprotocol.io

相关新闻

计算机Django毕设实战-面向租客的智能房源推荐与租房管理系统 基于 Python Django 的房屋租赁服务平台【完整源码+LW+部署说明+演示视频,全bao一条龙等】

计算机Django毕设实战-面向租客的智能房源推荐与租房管理系统 基于 Python Django 的房屋租赁服务平台【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/10/15 22:01:23 阅读更多 →
NIXL后端插件开发指南:从零构建自定义存储与通信模块

NIXL后端插件开发指南:从零构建自定义存储与通信模块

NIXL后端插件开发指南:从零构建自定义存储与通信模块 【免费下载链接】nixl NVIDIA Inference Xfer Library (NIXL) 项目地址: https://gitcode.com/gh_mirrors/ni/nixl NVIDIA Inference Xfer Library (NIXL) 是一款强大的推理传输库,支持通过插…

2026/10/19 18:46:29 阅读更多 →
主流双端面磨床厂商工况适配盘点

主流双端面磨床厂商工况适配盘点

精密机械加工领域中,双端面磨削直接决定零部件两端面平行度、厚度尺寸一致性,是精加工环节不可或缺的核心工序装备。当下制造业生产模式持续转变,单一品类长线量产模式逐步减少,多材质共用加工、工件规格频繁切换、中小批量柔性排…

2026/10/19 16:23:21 阅读更多 →

最新新闻

AI平台选型指南:从通用对话到开源自部署的实战策略

AI平台选型指南:从通用对话到开源自部署的实战策略

1. 主流AI平台的全景地图与选型逻辑1.1 为什么现在聊“AI平台”比聊“AI模型”更实际过去一年我接触了不少团队,从几个人的小工作室到上百人的产品线,大家问得最多的问题早就不是“哪个模型最强”,而是“我该把活儿交给哪个平台”。这个转变很…

2026/10/20 21:33:02 阅读更多 →
Win11 25H2下WPS频繁未响应:一个从证据到方向的完整排查记录

Win11 25H2下WPS频繁未响应:一个从证据到方向的完整排查记录

先说结论:我遇到的这个“Win11 25H2 WPS 频繁未响应”问题,直到现在还没有一个确定的根因。但是经过几天反复测试和收集证据,基本可以锁定它并不是WPS软件自身单独惹的祸,而是系统底层和当前环境里某个驱动层组件有兼容性冲突。这…

2026/10/20 21:33:02 阅读更多 →
MCP / Agent / Skill 技术生态分类汇总:用 TaoToken 统一 Key 打通三类工具链

MCP / Agent / Skill 技术生态分类汇总:用 TaoToken 统一 Key 打通三类工具链

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

2026/10/20 21:33:02 阅读更多 →
Claude账号防封全攻略:避开风控红线,让账号长期稳定

Claude账号防封全攻略:避开风控红线,让账号长期稳定

说来有点丢人,我在刚接触 Claude 的头两个月里,就亲眼看着身边三个朋友先后被提示账号异常,其中一个甚至用了不到三天就进小黑屋。那时候大家的第一反应都是"平台是不是疯了",但后来我对照着官方使用条款和自己的操作记…

2026/10/20 21:33:02 阅读更多 →
AI漫剧工业化生产流水线:人机协作边界与六层技术栈实战

AI漫剧工业化生产流水线:人机协作边界与六层技术栈实战

1. 项目概述:这不是“白嫖教程”,而是一套可落地的AI漫剧工业化生产流水线“AI漫剧制作全教程”这个标题,乍看是知识付费圈常见的流量钩子,但真正拆开来看,它背后指向的是一整套正在快速成型的数字内容工业化新范式。我…

2026/10/20 21:33:01 阅读更多 →
FPGA开发者必看:SRIO协议从IP配置到数据收发的完整调试指南

FPGA开发者必看:SRIO协议从IP配置到数据收发的完整调试指南

简介:面向FPGA与嵌入式系统开发者,这套Xilinx SRIO使用例程围绕Serial RapidIO高速串行互连协议在Spartan6系列中的实际部署,系统覆盖硬核配置、端口速率选择、测试平台搭建与仿真验证,解决高带宽低延迟场景下的接口设计与调试难题…

2026/10/20 21:31:57 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/20 9:50:45 阅读更多 →