从零手写智能体:从大模型HTTP原始调用到工具调用实战

先说明一下:这个系列我在做的时候,给自己立了一条规矩——不动用任何现成的智能体框架,不引入任何封装好的SDK,完全从最底层、最原始的大模型调用开始写。很多人做智能体,第一反应就是装框架、拖组件、接插件,结果做了半天,连"模型到底是怎么被调起来的"都说不清楚。这不是坏事,但出了问题也很难排查。

所以我决定把这个项目直接摊开来写,第一天就老实交代:JchatMind智能体最初的样子,其实就是一段发往大模型API的HTTP请求,外加一个循环读取返回内容的终端脚本。这篇就是给你完整还原这个过程,包括我从零开始写的每一步代码、踩过的每个坑,以及为什么这么设计。

这个系列适合两类人看:一类是刚接触大模型应用开发、想弄清楚"智能体到底由什么组成"的初学者;另一类是已经用过各种框架、但想回头把地基夯实,遇到问题不至于抓瞎的开发者。

1. 先讲清楚:JchatMind的第一天,为什么非要"退回到原始时代"

很多教程会教你直接上手某个框架,把大模型的调用封装成一行函数。但我的观点很朴素:你要做一个智能体,首先得知道一次"大模型调用"在机器层面上究竟发生了什么,否则后面所有的记忆管理、工具调用、流程编排,都是踩在沙子上盖楼。

1.1 智能体的地基,其实只有三件事

我理解的智能体,剥掉所有花哨概念后只剩下三块:

  • 模型调用:让大模型根据输入文本生成输出文本。
  • 上下文管理:把"之前的聊天内容"作为输入的一部分,让模型看起来"记住了"对话。
  • 工具调用:让模型在需要的时候,输出一个"我要执行某个函数"的指令,程序去执行,再把结果喂回给模型。

这三件事,没有任何一件是非要用框架才能完成的。第一天的JchatMind,我要求自己连第一步"模型调用"都必须能徒手写出来——精确到HTTP请求长什么样、响应怎么解析。

1.2 框架隐藏了太多"本该知道"的细节

举个例子,很多人第一次用封装好的大模型库,只是传了一个prompt就拿到了结果。但模型到底是怎么"看懂"system message的?temperature调到0.9和0.2有什么差别?为什么返回内容有时候是断裂的?流式输出时data: [DONE]到底代表什么?

这些细节,框架不会替你想,但它们恰恰决定了智能体的稳定性。从原始调用开始,并不是为了炫技,而是为了给后续排查问题留一条清晰的逻辑链。我第一天踩的几个坑,后面会挨个展开,全部都是底层细节没吃透导致的。

1.3 什么时候才轮到框架出场

我也不是在否定框架。当项目跑到一定规模——要对接多个模型、要编排复杂工作流、要接入外部知识库——这时候引入框架节约成本是合理的。但前提是你已经对"一次裸调用"了如指掌。这样框架出问题的时候,你能判断出是框架的问题,还是模型本身的问题。第一天,我先把这层底子打牢。

2. "最原始调用"到底长什么样:一次HTTP请求的内在结构

先建立一个认知:目前主流的大模型API,本质上就是一个HTTP POST接口。你把一段文本通过JSON格式发过去,服务端把模型生成的结果通过JSON返回来。看起来高深莫测,拆开其实非常直白。

2.1 请求体里的每个字段,都是什么意思

大模型API的请求地址,通常形如:

POST /v1/chat/completions

请求头需要两个东西:Content-Type: application/json,以及Authorization: Bearer 你的API密钥。

请求体核心字段大概就这几个:

字段作用我的建议
model指定用哪个模型根据任务选,对话类选通用旗舰,结构化任务选支持严格JSON输出的
messages对话消息列表,包含角色和内容核心字段,智能体的所有记忆都体现在这里
temperature控制随机性,0到1或更高写代码用0.2以下,创意写作可以0.7以上
max_tokens限制本次最大生成长度不设可能超出预期,设了能控制成本
stream是否流式返回做对话产品建议true,做批量处理建议false

2.2 messages数组:智能体"记忆"的真相

这个设计很多人第一次接触会懵。它不是只把"用户最新一句话"发给模型,而是要发给模型一个数组:

[ {"role": "system", "content": "你是一个智能助手,名字叫JchatMind。"}, {"role": "user", "content": "你好,请介绍一下自己"}, {"role": "assistant", "content": "你好,我是JchatMind,一个智能体助手。"}, {"role": "user", "content": "你刚才说你叫什么?"} ]

用大白话讲,你把对话历史整个摊开在模型面前,模型"读"一遍,然后接着往下写。它没有真正记住任何东西,它只是每次都在"看完聊天记录后接着回应"。

这带来两个很重要的推论:

  • 上下文越长,花的token越多,速度越慢。
  • 程序如果把无关紧要的历史全塞进去,模型的表现会被稀释。

2.3 角色分工:system、user、assistant分别管什么

这三个角色,相当于一个团队的三种分工:

  • system:给模型定基调、立规矩。它是"幕后的导演",用户看不到但对行为影响最大。
  • user:用户的发言。
  • assistant:模型自己的历史回复。在连续对话中必须把它带上,模型才知道"自己之前说过什么"。

我在第一天犯过一个典型错误:连续对话没带assistant的历史回复,导致模型每次回答都像失忆一样。后面排查到原因,才真正想通这个数组的设计逻辑。

3. 不借助任何SDK,用curl把第一句话送给模型

理论说完了,直接动手。第一步我不写代码,先用最原始的工具——curl——来验证模型接口通不通。这个过程不需要任何依赖,是排查连通性最快的方法。

3.1 准备环境变量,别把密钥写死在代码里

我在项目根目录建了一个.env文件,把API密钥和模型名放进去:

export JCHAT_API_KEY="你的密钥" export JCHAT_MODEL="your-model-name" export JCHAT_API_BASE="https://your-api-endpoint.example.com/v1/chat/completions"

把密钥放到环境变量里是个好习惯。不然代码写错提交到仓库,密钥就泄露了。后面写Python时也需要读取这两个变量。

3.2 真正发出去的第一条请求

在终端执行:

curl "$JCHAT_API_BASE" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $JCHAT_API_KEY" \ -d '{ "model": "'"$JCHAT_MODEL"'", "messages": [ {"role": "system", "content": "你是JchatMind,一个简洁、准确的智能助手。"}, {"role": "user", "content": "请用一句话说明你的身份。"} ], "temperature": 0.3, "max_tokens": 200 }'

等几秒,会看到返回的JSON长这样:

{ "id": "chatcmpl-xxx", "object": "chat.completion", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "我是JchatMind,一个由简化流程驱动的智能助手。" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 28, "completion_tokens": 15, "total_tokens": 43 } }

看到这个返回,说明最底层的通信已经打通了。我把这个时刻视为JchatMind的"开机自检"。

3.3 响应字段逐个拆解

  • choices[0].message.content:模型生成的正文,这是主角。
  • choices[0].finish_reason:为什么结束。stop表示自然结束,length表示触达max_tokens上限,tool_calls表示模型想调用工具。
  • usage.total_tokens:本次调用消耗的token总量。做成本优化的时候盯这一个字段就够了。

有个坑值得提前说:如果你收到的content是null,但finish_reason是tool_calls,说明模型没有直接回答,而是想调用工具。这种返回值我第一天没处理,直接解析content就报了空指针,后面专门写了工具调用模块才解决。

4. 用代码完成"对话闭环":从一次请求到连续对话

curl能通,说明地基可以开工了。但JchatMind不能靠手敲curl活着,我需要把它变成可复用的Python代码。这个阶段,我不装任何第三方大模型SDK,只依赖requests库。

4.1 最小的调用函数:入参是消息数组,出参是模型回复

import os import json import requests API_BASE = os.getenv("JCHAT_API_BASE") API_KEY = os.getenv("JCHAT_API_KEY") MODEL_NAME = os.getenv("JCHAT_MODEL") def chat_once(messages, temperature=0.3, max_tokens=1024): headers = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", } payload = { "model": MODEL_NAME, "messages": messages, "temperature": temperature, "max_tokens": max_tokens, } resp = requests.post(API_BASE, headers=headers, json=payload, timeout=60) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"]

这个函数非常简单,但它划出了整条链路的边界:入参是message数组,出参是模型文本。后续所有智能体能力——记忆、工具调用、流程控制——都在这个函数外面加逻辑,不会污染它的本质。

4.2 连续对话的关键:把每轮内容都追加到messages里

我一开始天真地以为,连续对话就是把用户的新问题追加进数组。结果模型不但忘记了自己说过什么,连用户第一句话都记不住。原因是:我只追加了user消息,没把assistant的回复也追加进去。

正确做法是这样:

messages = [ {"role": "system", "content": "你是JchatMind,回复简洁准确,不编造信息。"}, ] while True: user_input = input("你: ") if user_input.lower() in ("exit", "quit"): break messages.append({"role": "user", "content": user_input}) reply = chat_once(messages) print(f"JchatMind: {reply}") messages.append({"role": "assistant", "content": reply})

这段代码就是JchatMind第一天的"对话闭环":输入、调用、输出、回填历史。

4.3 上下文无限膨胀的隐患

跑着跑着我发现一个新问题:对话越长,每次请求越慢,费用越高。原因很简单——messages被撑得越来越大。模型每次都要把全部历史重新读一遍,token成本线性上涨。

第一天的简陋策略是截断:

def trim_messages(messages, max_messages=20): if len(messages) <= max_messages: return messages return [messages[0]] + messages[-(max_messages - 1):]

默认保留system消息,然后只保留最近若干轮对话。这个策略很粗糙,但它让我理解了:智能体的记忆管理,本质上是一个"在信息和成本之间做取舍"的动态过程。后续版本会换成token数裁剪,但第一天的思路是正确的。

4.4 流式输出:让模型"边说边吐"而不是"憋完才说"

对话产品不做流式输出,体验会很差。用户发一句话,页面要转圈好几秒才一次性出结果。流式输出是让模型生成一段就传一段,终端或前端就能边收边显示。

启用流式很简单,把stream设为true:

def chat_stream(messages, temperature=0.3): headers = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", } payload = { "model": MODEL_NAME, "messages": messages, "temperature": temperature, "stream": True, } with requests.post(API_BASE, headers=headers, json=payload, stream=True, timeout=120) as resp: resp.raise_for_status() for line in resp.iter_lines(): if line: line = line.decode("utf-8") if line.startswith("data:"): data_str = line[5:].strip() if data_str == "[DONE]": break chunk = json.loads(data_str) delta = chunk["choices"][0]["delta"].get("content", "") if delta: print(delta, end="", flush=True)

这段代码的核心是处理SSE(Server-Sent Events)流。每一行以data:开头,后面跟着一段JSON。[DONE]是结束标记。我第一天在这里栽了个跟头,后面会详细说。

5. 给JchatMind装上"手和眼睛":最原始版本的工具调用设计

对话闭环打通之后,JchatMind已经能"聊"了。但智能体和聊天机器人的最大区别在于:智能体能调用外部工具,改变真实世界的状态。比如查天气、算数学、读写文件。第一天我决定做一个极其粗糙但逻辑完整的工具调用原型。

5.1 工具调用的本质:模型只出"指令",程序来执行

很多人误以为大模型调用工具是"模型直接联网执行操作"。实际上模型根本不会执行任何东西,它只是输出一段结构化文本,描述"我建议调用哪个函数、传什么参数"。真正动手的是你的程序。

打个比方:模型是个"只会发号施令的顾问",它写一张便签说"请给我拿一杯水,温度70度",你作为执行者读便签、去倒水、把水端回来,再告诉顾问"水来了"。整个过程顾问并没有真实接触到水。

5.2 用一个字典管理可用的"工具"

第一天我先给JchatMind定义了三个最简单的工具函数,并把它们放进一个字典:

def get_current_time(): import datetime return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") def calculate(expression: str): try: return str(eval(expression, {"__builtins__": {}}, {})) except Exception as e: return f"计算错误: {e}" def get_weather(city: str): fake_weather = {"北京": "晴,22度", "上海": "多云,25度", "广州": "小雨,28度"} return fake_weather.get(city, f"没有{city}的天气数据") TOOLS = { "get_current_time": {"desc": "获取当前日期和时间,无参数", "func": get_current_time}, "calculate": {"desc": "计算数学表达式,参数expression为字符串", "func": calculate}, "get_weather": {"desc": "查询城市天气,参数city为城市名", "func": get_weather}, }

注意,这里calculate用了eval,只是为了第一天演示方便,生产环境绝不能这么干,会被注入恶意代码。后面我会换成语法树解析。

5.3 让模型学会"开口要工具"

我不想接复杂的function calling协议,第一天的做法非常原始:把工具说明写进system prompt,并严格要求模型按固定JSON格式输出。

TOOL_PROMPT = """ 你可以使用以下工具: - get_current_time: 获取当前日期和时间,无参数 - calculate: 计算数学表达式,参数 expression: string - get_weather: 查询城市天气,参数 city: string 如果需要使用工具,请严格输出如下JSON格式(不要输出任何其他文字): {"tool": "工具名", "args": {"参数名": "参数值"}} 如果没有合适的工具,直接正常回答用户。 """

调用的时候,把TOOL_PROMPT拼在system消息后面:

messages = [ {"role": "system", "content": BASE_SYSTEM + "\n" + TOOL_PROMPT}, {"role": "user", "content": "现在几点了?"}, ] reply = chat_once(messages, temperature=0.1) print(reply)

温度我特意调低到0.1,因为第一步只要求模型输出稳定的JSON格式,不能让它的"创作欲望"捣乱。

5.4 解析JSON指令、执行函数、把结果"回喂"给模型

下面这段是整个工具调用骨架最关键的部分:

import json def run_tool_once(messages): reply = chat_once(messages, temperature=0.1) try: tool_call = json.loads(reply) tool_name = tool_call["tool"] tool_args = tool_call.get("args", {}) if tool_name in TOOLS: result = TOOLS[tool_name]["func"](**tool_args) messages.append({"role": "assistant", "content": reply}) messages.append({"role": "user", "content": f"工具执行结果是: {result}。请基于这个结果回答用户的原问题。"}) return chat_once(messages, temperature=0.3) except json.JSONDecodeError: # 模型没输出JSON,说明它选择了直接回答 return reply return reply

流程展开就是四步:

  1. 调用模型,得到回复文本。
  2. 尝试把回复解析成JSON,看看是不是工具调用指令。
  3. 如果解析成功,按名字找到工具函数,实参传进去,拿到真实结果。
  4. 把工具执行结果作为一条user消息追加到上下文里,再次调用模型,让它基于真实结果组织最终回复。

这一步做完,JchatMind第一次"动手做了事"。它不再是纯嘴炮,至少能报时间、算算术、报天气了。

实现完之后在终端试了一下,输入"北京天气怎么样",程序输出的链路一清二楚:

模型回复(第一轮): {"tool": "get_weather", "args": {"city": "北京"}} 工具执行结果: 晴,22度 JchatMind最终回复: 北京今天是晴天,气温22度,适合出门。

5.5 这个极简设计的边界在哪里

我必须诚实地说,这个版本的"工具调用"非常脆弱。比如:

  • 模型输出JSON时带了任何多余文字,json.loads就会失败。
  • 多轮工具调用无法自动接力,比如"算一下今天到年底有多少天"需要先取日期再计算,链式调用没做。
  • 工具函数如果内部抛异常,处理得还很粗糙。

但这些不足是正常的。第一天的目标是打通"模型出指令—程序执行—结果回喂"这条链路,不是做工业级产品。有了这条主干道,后面往上面加"链式调用""稳健解析""异常恢复"才有地方挂。

6. 第一天踩过的三个坑:完整的排查链路

写代码不可能不踩坑。这一节我把第一天里印象最深、也最具代表性的三个问题完整还原,包括现象、排查过程和最后的修复方案。这些坑都是"不亲手从底层写一遍,很难碰到的经验"。

6.1 流式输出解析错位:整个data块被当成一段JSON解析

现象:调用chat_stream时,输出了一段完整的JSON解析错误堆栈。仔细看,内容是"Expected value: line 1 column 1",后面跟了一整段包含data:前缀的文本。

排查过程:

  • 我先在iter_lines里打印每一行原始内容,看到形如data: {"choices": [{"delta": {"content": "你"}}]}这样的行。
  • 最初我直接line[5:]然后json.loads,没有考虑这一行前面可能还有连续两个换行符导致的空行,也没考虑[DONE]标记。
  • 调试发现,最后的data: [DONE]被json.loads解析,直接抛异常。

修复:把"判断[DONE]"放到json.loads之前,并且用strip()去掉空白。

if line.startswith("data:"): data_str = line[5:].strip() if data_str == "[DONE]": break chunk = json.loads(data_str)

这个坑的本质,是我对流式协议(SSE)的边界格式不熟。框架把这一切都遮住了,所以我从不后悔第一天从底层开始。

6.2 上下文膨胀导致"答非所问"和请求超时

现象:连续对话20轮后,模型回答开始变慢,更严重的是会"跑题",有时候甚至重复之前的回答。

排查过程:

  • 我先打印了每次请求的messages长度和usage.total_tokens,发现20轮之后messages已经堆了超过6000个token。
  • 大模型读入的上下文越长,注意力被稀释得越严重。模型并不是无限聪明,它只是"在给定的一段文本内接续",如果这段文本里有太多无关紧要的历史,核心问题反而被淹没。
  • 另外请求体变大导致网络传输和模型处理时间变长,终端表现就是"卡顿"。

修复:加了trim_messages截断函数,保留system和最近10轮。并通过在system里加一句"只依据最近的对话内容回答,忽略与当前问题无关的早期内容",让模型主动聚焦。

这个坑让我意识到:记忆管理不是一个"存下来"就完事的问题,而是一个动态的、有损的压缩过程。智能体必须学会"忘掉"不重要的东西,和人是类似的。

6.3 温度参数导致的"工具调用不稳定"

现象:工具调用模块偶尔好用,偶尔输出一堆散文,完全不按JSON格式来。代码里明明已经写清楚了"不要输出任何其他文字"。

排查过程:

  • 我打印了temperature的值,发现一开始用的0.7。温度高意味着随机性大,模型在"守规矩输出JSON"和"自由发挥"之间摇摆。
  • 同样一条用户问题,temperature=0.1时稳如老狗,temperature=0.7时就开始"发挥"。
  • 我又试了把工具说明从system里挪到一条单独的user消息里,效果也不如直接拼在system里稳定。

修复:工具调用分支用temperature=0.1,日常对话分支用0.3~0.7,不同场景拆成不同的调用路径。

这里总结了一条经验:想让模型做"结构化输出",就得牺牲掉一部分"创造力"。没有参数能两全,只有根据场景做取舍。

下面把三个坑汇总成一张表,方便你对照:

问题现象根因修复
流式解析错位抛JSON解析异常没处理[DONE]和多行间隔先判断[DONE],再parse
上下文膨胀答非所问、请求变慢messages无限增长,token超量截断+引导模型聚焦
温度过高工具调用不稳定随机性压过了格式约束工具分支降低temperature

7. 第一天的成果,和JchatMind接下来的路

一天写下来,JchatMind拥有的其实就三样东西:一个能通过HTTP协议跟大模型通信的Python函数;一个能维持多轮对话的messages循环;一个能触发本地工具并回喂结果的极简工具调用骨架。代码量不多,但每一步都是亲手敲出来的,每一行都知道它在干什么。

我特别想说的是,做完这些之后回头看,那些框架里"顺手一点就有的功能",在这里都变成了一个个需要自己决策的细节。比如:

  • system prompt怎么设计,才能既约束格式又不压抑个性?
  • 上下文保留多少轮,才能兼顾记忆和成本?
  • 工具调用失败,是重新让模型选一次,还是直接告诉用户"做不到"?
  • 温度、max_tokens这些参数,在不同分支应该用什么值?

这些问题,没有标准答案,只能靠实践和积累。

接下来我会继续往下走。脑子里已经列了几个方向:一是把上下文从"截断"升级成"按token数裁剪",加摘要压缩;二是把工具调用升级成可靠的function calling协议,让模型原生支持结构化调用;三是给JchatMind加一个简易的记忆持久化,让它在重启后还能记住用户偏好。每一步都会在同一套代码上迭代,继续以"从底层做起"的方式展开这个系列。

第一天的JchatMind还很简陋,但地基已经切切实实落地了。下一篇文章,我会开始处理上下文管理的升级——这也是智能体从"demo"走向"能真正连续工作"的关键一步。如果你也在做类似的事,欢迎参考这套思路,从最原始的那一次HTTP调用开始,亲手给你的智能体打好底座。

相关新闻

基于全链路开发平台的墨水屏Agent实战:从零构建智能刷新与渲染方案

基于全链路开发平台的墨水屏Agent实战:从零构建智能刷新与渲染方案

1. 从墨水屏到全链路开发&#xff1a;这个项目到底在折腾什么墨水屏这东西&#xff0c;玩过的人都知道它的好——护眼、省电、阳光下可读&#xff0c;放在桌面当个信息看板简直绝配。但它的痛点同样明显&#xff1a;刷新慢、颜色少、交互方式单一&#xff0c;想让它显示点动态内…

2026/10/20 5:01:56 阅读更多 →
AI生成答辩PPT实操指南:用PaperXie AI高效产出与避坑技巧

AI生成答辩PPT实操指南:用PaperXie AI高效产出与避坑技巧

每到答辩季&#xff0c;后台私信就会被“答辩PPT该怎么做”这类问题塞满。不是大家不努力&#xff0c;而是硕博生的答辩PPT确实是个特殊物种&#xff1a;既要体现学术深度&#xff0c;又要在十几分钟内让台下专家听懂&#xff1b;既要有完整逻辑链&#xff0c;又不能照着论文念…

2026/10/20 5:01:56 阅读更多 →
AD9910 DDS详解:相位累加器、SPI控制与STM32驱动实战

AD9910 DDS详解:相位累加器、SPI控制与STM32驱动实战

简介&#xff1a;基于AD9910的波形发生器完整工程源码&#xff0c;面向嵌入式学习者、电子竞赛队伍及DDS应用开发工程师。项目基于STM32F10x系列&#xff0c;整合AD9910驱动、方波生成、扫频控制等功能模块&#xff0c;支持输出1Hz-400MHz正弦波、幅度1mV-650mV可调&#xff0c…

2026/10/20 5:01:56 阅读更多 →

最新新闻

文件系统边界才是批量删除的隐形天花板:一次缓存清理引发的思考

文件系统边界才是批量删除的隐形天花板:一次缓存清理引发的思考

48,218 个文件&#xff0c;103 秒&#xff0c;平均每秒删掉 468 个。这个速度放在本地 SSD 上不算惊艳&#xff0c;放在机械盘安全软件钩子的业务机上&#xff0c;已经算靠谱了。真正有意思的是这次清理引发的一场争论&#xff1a;团队里有人坚持说提示词写得不够好&#xff0c…

2026/10/20 5:41:14 阅读更多 →
AI生成内容合规标注的12个硬性字段与落地实践

AI生成内容合规标注的12个硬性字段与落地实践

1. 这份清单不是合规检查表&#xff0c;而是AI内容生产者的“出厂质检单”你刚用大模型生成了一段产品说明、一份用户协议初稿、一组营销文案&#xff0c;或者一段客服应答话术——在点击“发布”前&#xff0c;有没有哪怕一秒停下来问自己&#xff1a;这段内容&#xff0c;如果…

2026/10/20 5:41:14 阅读更多 →
CloudCompare自定义插件开发实战:以SOR统计离群点去除为例

CloudCompare自定义插件开发实战:以SOR统计离群点去除为例

如果你用过CloudCompare做点云处理&#xff0c;大概率能感觉到&#xff1a;这个软件最舒服的地方是点云显示、对比、切剖面都很快&#xff0c;但最不方便的是算法一固定就不太好改&#xff0c;想加的私有功能往往找不到入口。我刚入坑的时候也被这个问题卡了很久&#xff0c;直…

2026/10/20 5:41:14 阅读更多 →
VLA模型全解析:视觉-语言-动作统一模型的关键技术与落地挑战

VLA模型全解析:视觉-语言-动作统一模型的关键技术与落地挑战

很多朋友最近都在讨论 VLA 模型&#xff0c;尤其是在机器人学习和具身智能的圈子里&#xff0c;《VLA Models: Concepts, Progress, Applications and Challenges》这篇论文被频繁提及。VLA 全称是 Vision-Language-Action&#xff0c;也就是视觉-语言-动作统一模型&#xff0c…

2026/10/20 5:41:14 阅读更多 →
CTF文件包含漏洞实战:从路径构造到PHP代码过滤绕过

CTF文件包含漏洞实战:从路径构造到PHP代码过滤绕过

做CTF的Web题做到文件包含这个专题时&#xff0c;很多人会卡在同一个地方&#xff1a;明明看懂了漏洞原理&#xff0c;也知道要用伪协议、路径穿越&#xff0c;但真拿到一道题&#xff0c;还是不知道该从哪里下手。尤其是标题里“构造访问路径过滤php代码”这两个词&#xff0c…

2026/10/20 5:41:14 阅读更多 →
OpenCV 4.8.0源码编译实战:VS2019动态与VS2022静态双链路配置

OpenCV 4.8.0源码编译实战:VS2019动态与VS2022静态双链路配置

简介&#xff1a;面向需要在 Visual Studio 2019 与 2022 中搭建 OpenCV 4.8.0 X64 开发环境的 C 开发者&#xff0c;这份资源同时提供动态与静态两种编译方案&#xff1a;VS2019 动态编译生成 DLL&#xff0c;适合追求可执行文件轻量化的场景&#xff1b;VS2022 静态编译将库代…

2026/10/20 5:40:14 阅读更多 →

日新闻

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实现详解

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

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

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在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 阅读更多 →