FunctionCall函数调用全解析:从原理到实战,让大模型真正“动手干活”

如果你正在做AI对话类产品,不管是客服助手、内容助手还是企业内部的知识问答系统,大概率会遇到这样一个让人头疼的瞬间:用户问“帮我查一下昨天订单的物流状态”,模型回了一句“很抱歉,我无法访问你的订单系统”。不是模型不够聪明,而是它压根没有打开订单系统的钥匙。

FunctionCall(函数调用)就是用来补上这一环的:让大模型在对话中识别用户的真实意图,把它翻译成结构化的调用参数,然后由你的后端代码去执行查询、修改、推送等操作,最后再把结果交还给模型生成友好的自然语言回复。我最初接触这个概念时也觉得它有点绕,但真正跑通一遍之后会发现,它本质上是给模型插上了“手脚”,让AI从只能聊天变成可以干活。这篇文章我会完整拆解FunctionCall的运作链路、核心数据结构、实测中的高频坑位,以及在真实业务落地时值得注意的进阶配置,希望能帮正在做类似功能的朋友少走一点弯路。

1. FunctionCall到底在解决什么问题:从一次对话助手翻车说起

1.1 没有函数调用时的尴尬现场

我以前做过一个内部运维助手,核心需求很简单:让同事用自然语言查服务器状态、查日志、查告警。第一版没有接FunctionCall,模型纯粹靠对话能力硬撑,效果可以用灾难来形容。

用户问“帮我查一下192.168.1.10这台机器的CPU使用率”,模型回答了一堆“CPU使用率通常可以通过监控工具查看”之类的建议性内容,但就是给不出具体数值。它不是不想给,而是训练数据里根本没有你这套内部系统的实时数据,更不可能知道怎么连你的监控接口。

那时候我试过两种补救方案。第一种是关键词硬匹配,用正则去匹配“查CPU”“查内存”等固定句式,匹配到了就调接口把结果拼进Prompt再让模型润色。这套方案对付固定句式还算能用,但用户换一种说法就失敏了,比如“这台机器最近是不是有点卡”就完全无法映射到CPU查询。第二种是让模型直接输出JSON,告诉它“如果用户想查CPU就输出{'action': 'get_cpu'}”,结果模型经常输出格式不完整的JSON,解析一层还要再修复一层,链路的稳定性极差。

当时的困境本质上是:模型的“理解能力”和系统的“执行能力”之间横着一道沟,而FunctionCall就是这道沟上的一座桥。

1.2 函数调用的本质:把“决定干什么”和“怎么干”分开

说到底,FunctionCall做的事情只有两件:意图识别和参数抽取。

大模型本身不执行任何你的业务函数,它只负责“理解用户的话”,然后输出一个结构化的调用请求,这个请求里包含函数名和一组参数。你的后端代码接收到这个请求后,由程序员写的真实函数去查数据库、调API、写文件,再把结果以消息的形式传回给模型,模型基于这个结果组织语言,最终回复用户。

可以这么理解:模型是一个项目调度员,它极其擅长从一句模糊的话里判断出“该找哪个下游同事干活”,以及“干这个活需要哪些材料”;而真正的活由后端代码来完成,也就是那个下游同事。调度员不需要会干活,但他必须能把用户一句“这机器最近有点不对劲”翻译成“帮我查一下这台机器的CPU、内存和磁盘告警记录”,并且把材料准备齐全。

从API层面看,这个过程包含两个关键结构:tools(工具声明,描述你有哪些函数、每个函数的参数长什么样)和tool_calls(模型的调用意图,实际输出哪个函数和什么参数)。理解了这两个概念,后面看代码就不会懵。

1.3 什么样的业务场景真正需要FunctionCall

不是所有AI应用都需要接FunctionCall。纯文本生成、创意写作、意图咨询类的场景可以完全不用,硬接反而增加了链路复杂度和Token开销。但以下几类场景,FunctionCall几乎是必需品:

  • 查询类任务:查天气、查订单、查库存、查工单状态,模型需要从外部系统拿数据才能回答。
  • 操作类任务:发邮件、创建工单、修改配置、下单购买,模型识别意图后需要触发真实动作。
  • 多步骤流程编排:用户说“帮我把昨天的报表发给经理”,这需要先查报表列表、再查通讯录、最后触发邮件发送。一次工具调用往往不够,需要多个函数按依赖关系依次执行。

判断标准其实很简单:如果用户的回答完全不需要依赖你的私有系统或实时数据,就不需要FunctionCall;反过来,只要回答需要动态数据或会触发业务动作,就必须靠FunctionCall把意图和系统连接起来。

2. 完整链路从声明到回填:一个天气查询工具的实战代码

2.1 工具声明:把函数的存在和参数格式告诉模型

在调用模型之前,需要先让模型知道“你可以用哪些函数”。这一步通过构造tools参数完成。以最常见的OpenAI兼容接口为例,一个查询天气的函数声明长这样:

[ { "type": "function", "function": { "name": "get_weather", "description": "根据城市名称和日期查询当地天气情况,用于回答天气相关问题", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,例如北京、上海" }, "date": { "type": "string", "description": "查询日期,格式YYYY-MM-DD,默认当天" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位,默认celsius" } }, "required": ["city"] } } } ]

有几个细节值得留意。description字段的质量直接影响模型能不能准确选择函数和填对参数,因为它会被作为Prompt的一部分送入模型。字段描述要写清楚“什么时候用”“参数格式是什么”“有没有默认值”,这类似于给调度员一份清晰的工作手册。required数组申明哪些字段必须由模型填充,但也不是越严越好,给非关键字段留出默认值空间,能减少模型生成报错。

2.2 第一轮请求:把对话和工具清单打包发出

工具声明准备好之后,就可以构造第一轮请求。这里以Python代码示例做一个简单的演示:

import json from openai import OpenAI client = OpenAI(api_key="your-api-key") def get_weather(city: str, date: str = "2025-01-01", unit: str = "celsius") -> dict: # 这里实际上会调用真实天气服务 fake_weather = { "city": city, "date": date, "temp": 22 if unit == "celsius" else 71, "condition": "晴天", } return fake_weather messages = [ {"role": "system", "content": "你是一个智能助手,可以通过工具查询天气信息。"}, {"role": "user", "content": "帮我查一下明天北京的天气"}, ] tools = [ { "type": "function", "function": { "name": "get_weather", "description": "根据城市名称和日期查询当地天气情况", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"}, "date": {"type": "string", "description": "日期,格式YYYY-MM-DD"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}, }, "required": ["city"], }, }, } ] response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, ) print(response.choices[0].message)

关键判断点来了:当模型认为需要调用函数时,返回的message里不会直接有content文本,而是带有tool_calls字段,里面包含函数名和参数JSON字符串。我用gpt-4o-mini实测,输入“帮我查一下明天北京的天气”,返回内容大致是:

{ "content": null, "role": "assistant", "tool_calls": [ { "id": "call_xxx", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\", \"date\": \"2025-02-14\", \"unit\": \"celsius\"}" } } ] }

注意arguments是一个JSON字符串,不是对象,这就是后面很多解析坑的根源。

2.3 执行函数并把结果回填给模型

拿到tool_calls之后,工作流进入第二阶段:遍历调用真实函数,把每个结果按照指定的消息格式追加到messages里,再次调用模型。

# 继续上面的代码 if response.choices[0].message.tool_calls: tool_calls = response.choices[0].message.tool_calls messages.append(response.choices[0].message) for tool_call in tool_calls: func_name = tool_call.function.name args = json.loads(tool_call.function.arguments) if func_name == "get_weather": result = get_weather(args.get("city"), args.get("date"), args.get("unit")) else: result = {"error": "未知函数"} messages.append({ "role": "tool", "tool_call_id": tool_call.id, "name": func_name, "content": json.dumps(result, ensure_ascii=False) }) second_response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, ) print(second_response.choices[0].message.content)

这一步有两个容易搞错的地方。第一,第一轮的assistant消息必须原样append回messages,不能省略,因为模型需要知道它自己刚才做了调用工具的决策。第二,每个工具执行结果都要用role=tool来追加,并且必须带上对应的tool_call_id,这样模型才能把“哪个调用请求”和“哪条执行结果”对应起来,尤其是多个工具并行调用时,一一对应特别重要。执行完的结果不再是JSON Schema格式,而是一个纯文本内容,模型会基于这个内容去组织最终的自然语言回答。

2.4 把多轮串联起来:一个完整的简化执行循环

上面只是两轮请求,实际业务里往往会遇到“工具结果返回后,模型还需要再调另一个工具”的情况。比如用户说“明天北京适合安排户外活动吗”,单查天气不够,可能还要查空气质量。这就需要一个循环来持续判断,直到模型最终不再返回tool_calls为止。

def run_conversation(client, messages, tools, max_steps=5): for _ in range(max_steps): response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, ) msg = response.choices[0].message if not msg.tool_calls: return msg.content messages.append(msg) for tool_call in msg.tool_calls: func_name = tool_call.function.name args = json.loads(tool_call.function.arguments) if func_name == "get_weather": result = get_weather(**args) else: result = {"error": "未知函数"} messages.append({ "role": "tool", "tool_call_id": tool_call.id, "name": func_name, "content": json.dumps(result, ensure_ascii=False) }) return "达到最大工具调用轮次,停止执行"

max_steps这个参数建议一定要加,不加的话极端情况下模型可能来回调用工具停不下来,白烧Token。我一般是控制在3到5轮,既覆盖绝大多数业务链路的串联需求,又避免了失控。

3. 实测最容易踩的四个坑:参数解析、循环调用、并发依赖与超时

3.1 参数解析失败:arguments不是普通JSON对象

第一个高频坑出现在解析arguments上。很多人在工具调用结果里直接做json.loads,代码写得没问题,但实际运行中还是会偶发失败。原因主要在于模型偶尔会在JSON字符串里混入多余内容,比如参数值里带了注释、字符串没有正确转义、甚至是模型把布尔值写成了字符串。

我处理的方案分三层。第一层,用json.loads解析,如果失败就进入第二层:把字符串里的换行符、制表符清理后再解析。第二层仍然失败,就尝试正则提取最外层大括号之间的内容,再解析。第三层还是失败,直接给模型返回一条错误消息,内容类似“工具参数解析失败,请使用合法JSON重新调用”,让模型自己修正。这个方法虽然有点粗糙,但是实测下来能把偶发失败的恢复率提得很高。

import re def safe_parse_arguments(arguments: str) -> dict: try: return json.loads(arguments) except json.JSONDecodeError: cleaned = arguments.replace("\n", "").replace("\t", "") try: return json.loads(cleaned) except json.JSONDecodeError: match = re.search(r"\{.*\}", cleaned, re.DOTALL) if match: return json.loads(match.group(0)) raise

另外还有一类情况需要警惕:模型生成的参数值超出了业务可接受范围。比如城市字段传了一个不存在的城市名,日期字段传了一个不合法格式。这时候不用硬解析,先做一次白名单或格式校验,校验不过就返回结构化错误让模型调整,或者直接告诉用户暂不支持该查询。

3.2 循环调用陷阱:同一个工具被反复执行

第二个坑是模型会在工具结果里绕圈。我遇到过最典型的场景:工具返回了“权限不足”的错误信息,按说模型应该就此打住告诉用户没有权限,但它不,它会再次调用同一个工具,试图换一组参数碰碰运气,然后又一次拿到错误信息,又再次尝试,直到撞上max_steps上限。

这种行为的根因在于错误信息写得太笼统,模型不知道下一步该怎么办。解决思路是让工具返回的内容不仅包含错误码,还包含“建议的下一步行为”。比如权限不足时,结果里写明“当前用户无权限,请直接告知用户无权访问,不要重试”。模型读到这种明确指令后,一般就不会再做无用功。

result = { "error_code": "PERMISSION_DENIED", "message": "当前用户无权限访问该资源", "suggestion": "请直接告知用户没有权限,不要尝试其他参数重试" }

这种“带建议的错误返回”我强烈推荐,它在遇到模型自我修复能力不足的时候,是一种很有效的兜底策略。

3.3 并发工具调用的顺序依赖问题

OpenAI兼容接口支持模型一次返回多个tool_calls,允许并行执行。但“能并行”和“该并行”是两码事。如果你的两个工具之间存在依赖关系,比如先要查order_id才能调用发货接口,而模型一股脑把两个都发出来了,那发货接口就会因为缺少order_id而失败。

我的处理办法是两段式执行:第一轮把所有tool_calls都跑一遍,但先检查是否存在依赖关系。如果发现某个函数的必填参数需要另一个函数的结果,先停止执行下游函数,等上游结果回填给模型后,让模型自行决定要不要继续调。这个逻辑可以简单用“参数传递检查”来实现:定义函数时额外声明一个依赖字段,执行前校验参数是否就绪。

def resolve_dependencies(tool_calls, context): pending = [] for call in tool_calls: args = json.loads(call.function.arguments) if "order_id" in args and args["order_id"] is None: if "order_id" not in context: pending.append(call) continue args["order_id"] = context["order_id"] # 执行函数,把结果存入context return pending

依赖检查的细节可以按业务需求调整,但原则只有一个:不要盲目相信模型给出的并行调用顺序,涉及关键参数的传递链,后端要做校验。

3.4 工具超时与异常:不能让用户一直等

最后一个坑是工具执行耗时。模型调用函数的逻辑是同步的,工具不返回,这轮对话就卡住了。内部API再慢一点,用户端就会看到一个长时间不回复的对话,体验很差。

我建议给每个工具执行加上超时控制。Python里可以用concurrent.futures轻松实现:

from concurrent.futures import ThreadPoolExecutor, TimeoutError def execute_with_timeout(func, args, timeout=8): with ThreadPoolExecutor(max_workers=1) as executor: future = executor.submit(func, **args) try: return future.result(timeout=timeout) except TimeoutError: return { "error_code": "TIMEOUT", "message": "工具执行超时", "suggestion": "请告知用户服务暂时繁忙,建议稍后再试" }

超时阈值建议设置为8到10秒,太短容易频繁打断正常查询,太长用户又等不起。返回超时错误后,模型会生成一句相对自然的安抚话术,而不是干巴巴地抛异常给用户。这里顺便说一句,工具执行的异常一定要在业务代码层消化掉,千万不要把堆栈信息传给模型,既浪费Token又会让模型说出听不懂的话。

风险点常见原因处理方案
arguments解析失败模型输出JSON字符串中混入多余内容多层解析+兜底错误回传
工具循环调用错误信息缺少下一步指引返回带suggestion的结构化错误
并行调用顺序依赖下游函数缺少上游参数依赖检查后分轮执行
工具执行超时内部API慢、外部依赖阻塞设置超时并返回可对话错误

4. 让FunctionCall在真实业务里更稳的进阶配置

4.1 用tool_choice控制模型调用行为

默认情况下,模型会自己决定到底要不要调用工具以及调用哪个。有些场景下这种自主性不够用,需要手动干预。接口提供了tool_choice参数,有几种取值:

  • "auto":模型自主决定,默认值。
  • "none":禁用工具调用,模型只能生成普通文本。
  • "required":强制模型至少调用一个工具。
  • 指定函数对象:例如{"type": "function", "function": {"name": "get_weather"}},强制模型只调用该函数。

我在实际项目中用得最多的是指定函数对象。比如在一段多轮对话里,我已经判断出用户进入了“下单流程”,后面几轮系统都会强制调用create_order这个函数,避免模型跑偏。而收到用户询问天气的意图时,我会把工具列表裁剪到只剩天气相关函数,再配合指定函数对象,效果非常稳。

response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, tool_choice={"type": "function", "function": {"name": "get_weather"}} )

tool_choice还有一个容易被忽略的好处是节省Token。因为不需要让模型在多个工具之间做选择,也就减少了内部推理消耗,响应速度会快不少。

4.2 用strict模式减少参数格式漂移

现在不少兼容接口支持在function声明中加"strict": true,让模型严格按JSON Schema生成参数。这个功能对参数解析的稳定性提升明显,尤其是enum字段、嵌套对象、数组类型的参数。

开启strict模式后,模型生成参数的概率性错误明显降低,几乎不会再出现类型混用问题。不过它也有代价:对生成速度有小幅影响,而且一旦Schema写得有歧义,模型反而更容易触发校验失败。所以开strict前一定要把description写清楚,required列表也尽量精简。

{ "type": "function", "function": { "name": "create_order", "description": "创建商品订单", "strict": true, "parameters": { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "sku_id": {"type": "string"}, "quantity": {"type": "integer", "minimum": 1} }, "required": ["sku_id", "quantity"] } } }, "required": ["items"] } } }

4.3 把错误处理设计成“可对话的错误”

这个理念贯穿了我后面所有工具开发:工具的返回结果分两类,一类是正常业务结果,一类是结构化的错误。正常结果直接原样回传,错误则统一包装成下面这种格式:

{ "status": "error", "error_code": "ORDER_NOT_FOUND", "message": "订单不存在或已被删除", "suggestion": "告知用户未找到该订单,并引导重新确认订单号" }

为什么强调“可对话”?因为工具返回的内容最终是由模型读取的,模型需要根据这些内容组织对用户说的话。如果返回的是“Exception: 5743”这类程序员友好字符串,模型就只能复读错误码,用户完全听不懂。加上suggestion字段后,模型就有了明确的行为指引,能生成一句连贯的安抚和引导话术。这套设计成本极低,但对最终用户体验的提升非常显著。

4.4 Token开销的优化:函数声明和结果都要瘦身

FunctionCall的Token开销通常来自三个部分:工具声明的参数描述、模型生成的tool_calls参数、工具执行结果的原文回传。声明部分可以通过精简description来省,比如只描述关键触发场景,不写过长示例;结果部分则要刻意做摘要,不要把整个业务对象的完整字段全塞回去。

比如查订单,数据库返回了50个字段,但模型回复用户时通常只需要订单号、状态、金额、物流单号,那么我在工具执行层就做一次字段裁剪,只把这四五个字段拼成JSON返回。这能省下大量Token,尤其是查询大对象的时候,效果立竿见影。

def summarize_order(order: dict) -> dict: return { "order_id": order["order_id"], "status": order["status"], "amount": order["amount"], "tracking_number": order.get("tracking_number", "未发货"), }

每次工具调用回来都要思考一个问题:模型真的需要这50个字段吗?不需要的字段留在结果里,只会稀释模型对关键信息的注意力,还可能让模型复述出本不该提到的内部信息。

4.5 多工具场景下的命名规范与权限控制

当工具数量超过十个,模型的选择准确率会肉眼可见地下降。这时候命名和描述的作用就凸显出来了。

命名要遵循“动词+名词”的自然习惯,比如get_order_status、create_refund_request、update_user_profile。避免用简写和编号,模型对自然词组的理解能力远强于对代码风格的缩写。描述里要写清楚边界,比如“本函数仅用于查询订单状态,不处理退款”“如果用户要退款,请调用create_refund_request”,这种显式提示能让模型在模糊场景下做出更准确的选择。

权限控制则是后端层面的硬约束。模型只是生成调用意图,真正到业务系统执行时必须做用户级鉴权。我曾经遇到过一个工具暴露了全部订单查询能力,结果模型在上下文中吸收了另一个用户的订单号,把别人的订单信息带了出来。这类问题必须在执行层对参数做归属校验,不能完全依赖模型“每次都能给出合法参数”这样的假设。

5. 关于评估、成本与工具边界的落地体会

5.1 评估不能只看“是否成功调用了函数”

FunctionCall上线之后,评估工作比模型对话质量更难量化。我一开始只看“tool_calls返回率”和“调用成功率”,后来发现这两个指标都很片面。举例来说,用户问“北京的天气适合穿什么衣服”,模型成功调用了get_weather并不代表回答合格,因为它可能把参数填成了上海。

我建议在一个评测集上同时考察三个维度:该调用的工具是否真的被调用、工具参数是否准确、工具返回后模型的最终回复是否解决了用户问题。前两个维度可以自动化检查,第三个维度需要抽样人工评价。我自己保持了一套约300条覆盖典型场景的评测集,每次改动工具声明或调整提示词后,都会跑一遍看看分数变化。

5.2 成本控制:FunctionCall并不是免费的能力

接入FunctionCall之后,这个功能的真实成本常常被低估。每轮对话的Token消耗不只是用户的输入和模型的回复,还包括完整的工具声明、模型的tool_calls输出、工具结果的回传,以及多轮串联带来的多倍调用。

我粗略估算过一个中高频工具场景:平均每轮用户问询会产生两次模型API调用,一次出tool_calls,一次汇总最终回复。加上工具声明和系统Prompt的路程,单次交互消耗大约是无工具场景的2到3倍。这个倍数放大了,月成本差距就很可观。

节省成本的实践路径有几个:一是动态裁剪工具列表,根据当前对话上下文只传入可能用到的3到5个工具,而不是把全量工具都塞进去;二是结果摘要如前面所说,只返回模型需要的字段;三是对高频重复查询场景做结果缓存,比如同一个用户短时间内查同一个订单状态,直接复用上一次的工具执行结果,省掉一轮调用。

5.3 最后想说的:FunctionCall是一条需要前后端共同打磨的链路

和我合作过的一些团队,总把FunctionCall当成“前端调用模型时附带一个tools参数”那么简单,等真正上线才发现,工具声明、执行层、错误处理、权限控制、监控告警,每一环都有它自己的复杂度。

我个人最大的体会是:不要把工具描述写得过于模糊,也不要指望模型能自动理解你代码里那些内部术语。最好的状态是,工具声明写得像一本给新同事看的工作手册,把触发条件、参数示例、边界情况都讲明白。这样做之后,模型的表现会稳定很多。

另外,链路中的日志和追踪一定要在早期就做好。每一次tool_calls的原始返回、执行耗时、结果长度、是否成功,都应该被记录下来。遇到用户投诉“AI乱回答”的时候,这些日志能帮你快速定位是模型选错了工具、参数填错了,还是工具执行出错了,省下大量排查时间。

FunctionCall这个能力发展到今天,已经比较成熟了,但成熟的工具也只是地基。真正决定上限的,还是你如何围绕它设计整个执行链路。希望这篇分享能帮你少踩几个我踩过的坑,把这套机制用得更顺手。

最后再提醒一个小技巧:如果你刚开始接入,不要一口气写十几个工具,先挑三四个高频且边界清晰的功能跑通,再逐步扩展。工具太多,模型的选择准确率会下降,而且维护成本也在往上走——这是我在项目中反复验证过的一点。

相关新闻

PyInstaller打包Python脚本实战:从原理到多平台发布

PyInstaller打包Python脚本实战:从原理到多平台发布

Python 脚本写完之后,最常被问到的一个问题就是:怎么把它交给一个没装 Python 的人也能跑起来?你总不能让人家先装解释器、再配环境变量、再 pip install 一堆依赖。PyInstaller就是干这个的——把.py文件连同解释器和依赖库一起打包成单个可…

2026/10/20 5:19:03 阅读更多 →
Pulsar创新实践:消息中间件架构演进与生产落地指南

Pulsar创新实践:消息中间件架构演进与生产落地指南

最近不少技术群都在倒计时:COSCon‘25 同场活动 Pulsar Developer Day 还有 3 天就要开了。这个开发者日把主题定在“消息中间件创新实践”,我个人觉得比泛泛的技术布道更有看头。原因很简单:消息中间件这几年变化太快,快到“选型…

2026/10/20 5:19:03 阅读更多 →
把LLM代理当成一等优化手段:GPU Kernel调优闭环实践

把LLM代理当成一等优化手段:GPU Kernel调优闭环实践

1. 从"人翻手册"到"代理提方案":kernel优化的玩法变了1.1 以前的优化流程是什么样的在把LLM代理接入优化闭环之前,一个典型的GPU算子性能优化流程大概是这样的:先用profiler拿到kernel的运行时间和各阶段硬件利用率&…

2026/10/20 5:19:03 阅读更多 →

最新新闻

主动学习新思路:损失预测模块如何精准筛选高价值样本

主动学习新思路:损失预测模块如何精准筛选高价值样本

1. 为什么主动学习要换一种采样思路做深度学习项目,尤其在数据标注预算有限的时候,大家最先想到的办法多半是“先随便标一部分,训练一版模型,再用模型挑一些‘难样本’送给标注员”。这套逻辑本身没问题,难就难在“难样…

2026/10/20 6:02:23 阅读更多 →
REA架构:React+Electron+Ant Design桌面应用开发实战

REA架构:React+Electron+Ant Design桌面应用开发实战

项目标题: "rea"这个标题乍一看像拼写错误,也像某个缩写,又像随手打出来的三个字母——但正因如此,它在当前语境下反而具备极强的信号价值。过去半年里,我在多个技术社区、设计协作平台和前端开发群组中反复观察到&…

2026/10/20 6:02:23 阅读更多 →
验证码逆向分析实战:某DN验证码机制与加固思路

验证码逆向分析实战:某DN验证码机制与加固思路

验证码逆向分析这个方向,我前前后后接触了不少轮。最近一次是在评估某内部系统的登录安全时,碰到某DN验证码这个环节,于是专门花了一段时间,把它从请求链路、JS执行逻辑、参数生成到服务端校验机制整个拆了一遍。这篇文章就是基于…

2026/10/20 6:02:23 阅读更多 →
PyTorch实战:从零搭建神经网络全流程指南

PyTorch实战:从零搭建神经网络全流程指南

1. 为什么选择 PyTorch 快速搭建神经网络1.1 从零手写到框架搭建的认知转变很多刚入门深度学习的朋友,第一次接触神经网络时,往往是从 NumPy 手写反向传播开始的。我自己当年也是这样,用 NumPy 实现一个两层全连接网络,光矩阵求导…

2026/10/20 6:02:23 阅读更多 →
ArtCraft:数字工具与实体材料融合的创意生产方法论

ArtCraft:数字工具与实体材料融合的创意生产方法论

1. 项目概述:ArtCraft 不是“艺术手作”的简单拼接,而是一套可落地的创意生产方法论ArtCraft 这个词乍看像英文单词组合,但实际在中文语境里它早已脱离字面意思,成为一类特定创作实践的代称——它指的不是泛泛而谈的“手工艺术”&…

2026/10/20 6:02:23 阅读更多 →
PLMS自适应滤波器:脉冲噪声下的LMS鲁棒性改进原理与Matlab实现

PLMS自适应滤波器:脉冲噪声下的LMS鲁棒性改进原理与Matlab实现

前几天,一位做车载音频的工程师朋友跟我抱怨,说他的回声消除算法在实验室里测得好好的,一到实际路测就“抽风”:安静路段收敛得很干净,可一旦出现开关门、喇叭鸣笛这类突发噪声,滤波器的权值就像被弹弓弹了…

2026/10/20 6:01:22 阅读更多 →

日新闻

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/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →