news 2026/10/4 4:54:49

AI Agent上下文工程实战:从消息组装到多Agent协作完整套路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent上下文工程实战:从消息组装到多Agent协作完整套路

做 AI Agent 这段时间,我最大的一个感受是:模型本身的能力差距,远没有上下文管理带来的效果差距大。同样一个模型基座,有人做出来的 Agent 像是雇了个高级实习生,交代一遍就能把事办得妥妥帖帖;有人做出来的 Agent 就是个记性只有几秒的复读机,用户刚说过的需求转头就忘,多问两轮开始胡编乱造。差别基本不在模型,而在"上下文工程"(Context Engineering)上。

这篇文章想跟你聊聊我在这条路上摸出来的完整套路:从 Agent 的上下文由什么组成,到怎么组装一份能打的消息序列,再到上下文窗口有限时怎么裁剪、怎么摘要,以及多 Agent 协作时上下文怎么传、成本和并发怎么控、踩过的坑怎么止血。不管你是用 FastAPI+LangChain+LangGraph 自己搭,还是用扣子这类可视化平台拖拽,还是好奇 Spring AI、Rust 生态里 Agent 怎么做,底层逻辑都是同一套。把这套东西吃透,你就拿到了 Agent 开发里最绕不开的那把钥匙。

1. 先弄明白:Agent 的"上下文"里到底装着什么

1.1 一个让我印象深刻的翻车现场

先说个我真实遇到的例子。当时做一个客服 Agent,用户上来问:"我想买一张下周二去杭州的高铁票,预算 500 以内。" Agent 回答得很正常,查了车次、报了价格。接着用户又问:"那南京的呢?" 这本来是个很简单的追问——用户大概率想比较杭州和南京的交通成本。结果 Agent 直接回答"南京的票也很充足",还推荐了一趟完全不搭界的车次,因为它已经完全忘了前面聊过"去杭州"这件事。

这不是模型能力不行,这就是最典型的上下文丢失。模型的每次调用都是独立的,它不会天然记住上一轮你说了什么。你传给它的消息列表里如果没保留"用户想去杭州"这层信息,它就只能在当前这句话里猜。另一个我印象很深的场景,是做小红书自动发消息的 Agent:如果上下文里没有记录"哪个选题已经用过、哪篇文案已经发过、上次生成的 verbatim 风格是什么",它就会连续生成几乎一字不差的重复文案,用户被迫一遍遍删。

这类问题的共同点是什么?不是提示词写得不够好,而是上下文这张"小抄"本身就残缺。做 Agent 的第一课是接受一个事实:模型就是个没有瞬时记忆的考生,你每次给它递的小抄长什么样,直接决定了它能考多少分。

1.2 一次对话里,上下文其实由四类信息组成

很多人对上下文的印象就是"把历史聊天记录拼在一起发给模型"。真做项目之后你会发现,一段发给模型的上下文,通常由下面几类东西拼成,而且它们各自的作用和失效后果完全不同。

上下文组成大致占比作用失效后果
系统提示词2% ~ 8%定义角色、目标、约束、可用能力、输出格式回答风格漂移、工具乱用、输出格式不稳定
对话历史40% ~ 60%记录多轮双方发言,维持话题连续性丢需求、重复提问、逻辑断裂
工具定义与返回值10% ~ 30%告诉模型有什么函数可调、参数怎么填、调用结果是什么不会调工具、拿错误数据继续硬答
检索/知识片段5% ~ 25%注入外部知识库命中的片段、实时数据一本正经胡说八道、内容过时、编造来源

这里有个容易忽略的点:工具定义和返回值,本质上也是上下文的一部分。你如果不把 function calling 的 schema 传进去,模型再强也不可能凭空知道你要查天气。你不把工具返回的关键字段整理好再塞回去,模型就会拿着又长又乱的原始 JSON 开始"废物利用"——经常有 Agent 从报错信息里"总结"出一堆子虚乌有的结论,根源就在这。

1.3 为什么上下文工程不等于调 Prompt

现在说起 Prompt 工程的人很多,但上下文工程的范围比 Prompt 工程大得多。你可以把每次模型调用想象成:一个刚从昏迷中醒来的助手,你递给他一张任务简报。Prompt 只是简报顶部那几行字,后面真正的主体是对话记录、检索到的资料、工具返回的结果。Prompt 工程解决的是"怎么说清楚要求",上下文工程解决的是"每一轮给他带什么东西、按什么顺序排、哪些内容必须是原文、哪些可以压缩成摘要、哪些必须果断丢弃"。

我见过不少团队,Prompt 写了几百行,效果还是不理想,因为上下文组装顺序是乱的:最新检索结果排到了最前面,被后来居上的历史消息盖住;或者把整个知识库一股脑塞进去,上下文差点撑爆,模型反而抓不住重点。这些问题靠优化 Prompt 解决不了,得靠调整"上下文"本身。上下文工程本质上是给 Agent 设计一套"信息投喂协议",它决定的是 Agent 的感知边界。

2. 从零组装一份能打的上下文

2.1 系统提示词:别写作文,写接口规范

很多人写系统提示词喜欢写成一篇文章:"你是一个友好亲切的客服助手,要耐心回答用户问题,语气热情,但不能乱说话……" 这种写法不是不行,但它太模糊了,模型很容易在执行几轮之后"漂移"。我自己的写法是把它当成一份接口规范,结构化地拆成几个固定的块:角色、目标、约束、可用知识、输出格式、安全底线。

给你一个可以参考的模板结构:

# Role 你是XX产品的官方客服助手,代号小X。 # Goal 准确解答用户关于产品功能、订单、售后的咨询;对于无法确认的信息,明确表示需要人工介入。 # Constraints - 只基于系统提供的资料回答,禁止自行推测 - 如果用户问到资料之外的信息,回复"这个我需要跟相关同事确认",不得编造 - 每轮回答控制在 80 字以内 # Output Format - 回复用纯文本,不使用 Markdown 标题 - 如果需要用户补充信息,先列缺失项 # Guardrails - 不讨论与产品无关的话题 - 不承诺补偿方案

为什么这么写?因为模型对结构化文本的理解和遵守程度,明显好过一大段自由散漫的描述;而且固定位置的固定文本能在后面作为缓存前缀使用,对成本和延迟都有好处。你还可以把"当前系统的实际情况"——比如客服坐席时间、商品在架状态——写进去,让模型时刻知道自己处在什么环境里。

2.2 工具定义:让模型知道什么情况下该掏出什么工具

工具定义是上下文里最容易被忽略却最影响体验的一块。模型能不能准确触发工具,很大程度上取决于工具描述写得清不清楚。这里有个最常见的问题:description 写得太短,模型全靠猜。比如你写query_weather(city),描述是"查天气",模型就可能在用户说"今天冷不冷"时犹豫要不要调用,或者把城市名参数填错。

更稳的做法是把触发条件、参数格式、返回内容都写清楚:

{ "name": "query_weather", "description": "当用户询问当前或未来几天的天气、气温、降水情况时调用。输入城市中文名。返回今日温度、天气状况、风力、降水概率。", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市中文名,如:杭州" } }, "required": ["city"] } }

工具返回结果的处理同样重要。我的经验是:写回上下文之前,必须先做清洗。比如原始返回是一大段带嵌套结构的 JSON,模型读起来既费 token 又容易被无关字段干扰。我会在代码里把返回结果抽成一句话:"杭州 今日 晴 5~15℃ 东北风3级 降水概率20%",再塞回消息列表。这样既保留了事实,又避免模型在复杂 JSON 里迷路。

2.3 检索与知识:RAG 不是把库搬进去

很多人在 RAG 里犯的错是:命中了几条片段,不管三七二十一全塞进上下文,总觉得"多一点总比少一点好"。实际上检索片段的质量和数量直接影响 Agent 的表现。标准其实很简单——你放进去的这段知识,如果拿掉它,模型的回答会变吗?如果会变,说明这是必要信息;如果不会变,就直接删掉。

我通常会限制最终注入的检索片段数量。top_k 取多少要看知识库切片的粒度:切片短,就多取几条;切片长,两三条可能就够。还要注意顺序,检索片段最好插在"系统提示词"后面、"对话历史"前面,作为背景资料存在。另外每条检索内容最好带来源标记,比如"[知识库: 商品手册/第3章]",这能显著降低模型把新旧信息混在一起编造的概率。

2.4 记忆分类:哪些必须原文保留,哪些可以摘要

对话历史不是越多越好,也不是越新越好。我会把记忆分成硬记忆和软记忆两类,分别处理。

  • 硬记忆:用户明确给出的关键约束,比如订单号、金额、时间、地址、价格上限。这类信息错一个字就全盘皆输,必须原文保留。
  • 软记忆:闲聊、模型自己推理的过程、已经完成的中间步骤、失败的尝试,这些信息留着只会膨胀上下文,能摘要就摘要,能弃就弃。

举个例子,用户说"帮我查一下订单 SB20240001 什么时候发货,如果延迟就换顺丰"。这里的订单号、诉求(换顺丰)就是硬记忆,要原封不动带进每一轮;至于中间查了几次、API 返回了什么中间状态,等最终拿到结果后就可以压缩成一行"订单 SB20240001 已查,当前物流为圆通,用户要求延迟则换顺丰"。这样做的好处是:即使后面对话框滚了 50 轮,模型依然记得最核心的东西,而不是只记得最近几句客套话。

3. 上下文窗口是稀缺资源,怎么分配才不浪费

3.1 先做 Token 预算再写代码

上下文窗口看着很大,128K、200K 都有,但真的用起来你会发现它远不够用,尤其当对话轮数一长、工具结果一多的时候。我在项目里的习惯是:开写代码之前,先给不同部分划定 Token 预算。以 128K 窗口为例,我一般这么分配:

上下文部分预算占比参考值
系统提示词2% ~ 5%2K ~ 5K
工具定义3% ~ 8%4K ~ 8K
检索/知识片段10% ~ 20%10K ~ 25K
对话历史50% ~ 70%50K ~ 80K
输出预留5% ~ 10%5K ~ 10K

这不是硬性公式,但它逼你思考:每个部分占多大比重,有没有必要塞那么多历史?我在代码里会直接用 tokenizer 统计长度,一旦接近阈值就让处理函数提前做裁剪,而不是等模型接口报 context_length_exceeded 错误再慌。这个习惯帮我少踩了很多坑。

3.2 滑动窗口裁剪的副作用:只留最近 N 轮,关键信息丢了

最粗暴的上下文管理方式就是滑动窗口:只保留最近 5 轮、10 轮消息,更早的一刀切。这个方法实现很简单,但它有个致命副作用:你刚刚把用户最开始说的关键需求也一起裁掉了。比如用户在第 1 轮说"预算 500 以内",到第 15 轮你只保留了最近 5 轮,模型就完全不记得预算这回事了,推荐了一堆 800 的选项。

我现在的做法是:裁剪之前,先把硬记忆抽取出来存到 session 级变量里。就像写简历一样,把最关键的事实提炼成几个字段(用户诉求、约束条件、待办事项),然后再做滑动窗口,只裁那些无关紧要的过程对话。顺序大概是:第一,提取硬记忆并单独缓存;第二,把已经完成的任务压缩成一行摘要;第三,再做最近 N 轮窗口裁剪;第四,校验总长度是否在预算内。这样既保住关键信息,又控制住了体积。

3.3 摘要记忆:把旧对话压成结构化笔记

对话历史超过一定长度后,直接裁剪不是唯一出路,更好的做法是触发摘要:让模型把"旧对话"重写成一页压缩笔记,用笔记代替原文继续喂给后面的轮次。摘要不是简单概括,而要提取结构化的关键信息。

我常用的摘要触发条件有两个:一是消息长度总和超过窗口预算的 60%;二是关键事件完成后,比如工具调用已经有最终结果了,之前中间过程就可以压掉。摘要 prompt 我一般这么写:

请把下面的对话压缩成结构化笔记,只保留: 1. 用户的明确意图和约束条件 2. 尚未完成的待办事项 3. 已经发生的关键事实(订单号、金额、地点、时间) 4. 用户表达过的偏好 不要保留寒暄、重复、中间失败尝试。

这段摘要生成之后,替换掉旧消息的位置,模型依然能知道"用户要什么、做到哪一步",而上下文体积却小了一个量级。在一些长会话 Agent 里,我会配合 LangGraph 的节点机制做一个专门的 summarize 节点,在每次对话轮次之间检查长度、决定是否触发摘要。这样上下文管理就变成了流程的一部分,而不是事后的补救。

3.4 分层记忆:短期、长期、向量记忆

再往上走一步,就是分层记忆。单次会话内的消息可以理解为短期记忆,跨会话仍然需要保留的用户画像、偏好、历史行为则属于长期记忆,还有一种方式是向量记忆:把历史消息切块向量化,之后通过语义检索召回相关片段。

这三层怎么配合?我一般的读取顺序是:先用向量检索找出当前 query 最相关的历史片段,比如用户上次说过"我喜欢靠窗座位",这次订票时就应该把这条偏好放回上下文;再把短期记忆里的最近几轮消息补上;最后把长期记忆里跟当前任务相关的稳定信息(等级、常用地址、折扣资格)也一起注入。扣子这类可视化 Agent 平台里提供的"记忆"模块,本质上就是帮你封装了这套逻辑,自己搭 Agent 时就需要一个一个实现了。

4. 多 Agent 协作里的上下文传递,比单 Agent 难一个量级

4.1 多 Agent 为什么容易"断片"

单 Agent 的上下文就是一张纸,就算丢信息,至少整张纸在一个人手里。多 Agent 则完全不一样:它更像多人协作,每个角色只拿到其他人递给他的字条。问题就出在传话的过程中。

举个例子,一个内容创作 Agent 加一个校对 Agent。用户对创作 Agent 说:"语气要轻松,别太正式。" 创作 Agent 确实按轻松风格写了一篇。但等到校对 Agent 接手时,主流程只把文稿传了过去,没有把"语气轻松"这条约束传过去。校对 Agent 看到的文本没有风格标注,于是按自己的默认偏好改得文绉绉。这种情况特别常见——不是某个 Agent 能力不行,而是上下文在节点之间传递时缺了关键约束。

4.2 LangGraph 的 State 是共享便签本,但不是所有东西都要往上贴

在用 LangGraph 这类框架时,很多人直接把所有信息塞进一个全局 State,让所有节点共享。这个思路在简单 demo 里没问题,一旦 Agent 数量变多,节点之间开始互相污染。LangGraph 的 State 本质上是一个"共享便签本",它应该只放那些真正需要跨节点流转的信息,而不是把所有脏数据都堆上去。

我会把 State 设计成字段分明的结构:

from typing import Annotated, TypedDict from langgraph.graph.message import add_messages class AgentState(TypedDict): session_id: str messages: Annotated[list, add_messages] # 主对话流 customer_info: dict # 用户相关硬记忆 task: str | None # 当前子任务描述 source_agent: str | None # 当前消息来自哪个 Agent

注意这里我故意没有放"整个知识库"或"全部检索结果",只放必要字段。send给子 Agent 的时候,我只从 State 里挑出task和customer_info,而不是把messages整个传过去。子 Agent 不需要知道全局发生了什么,它只需要知道自己当前的任务和完成这项任务必需的事实。

4.3 主管-子 Agent 协作的一个落地示例

下面是一个缩略版的主管-子 Agent 路由逻辑,重点看它是怎么控制每个子 Agent 看到的内容范围:

def route_to_child(state: AgentState): last_user_message = state["messages"][-1]["content"] if "订单" in last_user_message or "退款" in last_user_message: child_prompt = ( "你是订单处理专员。用户需要处理订单相关事务,请基于以下信息提供服务。\n" f"客户关键信息:{state['customer_info']}\n" f"用户本次诉求:{last_user_message}\n" "注意:只处理订单/退款相关事宜,不要回答其他问题。" ) return { "task": child_prompt, "source_agent": "order_agent", } elif "商品" in last_user_message: # 另一个子 Agent,只拿到商品相关背景 ...

这段逻辑的精髓是:每个子 Agent 收到的上下文是"当前任务 + 必要硬记忆 + 最近一条用户消息",而不是全部历史。子 Agent 的上下文越克制,它就越不会发散。很多时候多 Agent 效果不好,不是模型不行,是子 Agent 收到的上下文太"丰富"了,才开始发挥想象力。

4.4 FastAPI + LangGraph 部署:上下文怎么和并发共存

热搜里经常有人问"ai agent 怎么扛并发"。我在 FastAPI 里部署 LangGraph Agent 时最大的领悟是:并发瓶颈往往不在模型 API 本身,而在上下文的状态管理。单机单会话没问题,一接多用户,你就要回答这几个问题:每个 session 的 messages 存在哪?A 用户的消息会不会混进 B 用户?进程重启后会话还能不能恢复?

我的方案是:所有会话状态外部化,存到 Redis 或者数据库,按session_id建命名空间。每次请求从持久层把该 session 的上下文加载出来,组装完传给模型,返回后再写回去。LangGraph 里的 checkpointer 机制正好是为了这个场景设计的,配合 FastAPI 作为请求入口,一个请求进来先恢复 State,跑完图再保存 State。这样 Agent 进程本身保持无状态,水平扩展就容易了。

如果做 Agent 中台,我还会把"上下文组装"抽成独立服务:输入 session_id 和当前用户消息,输出组装好且已经做过裁剪/摘要的 messages 数组。这样不管下游是 LangGraph、Spring AI 还是 Rust 生态的 Agent,都能共用这一层能力。语言会换,但"会话隔离、消息组装、记忆分级"这套逻辑不会换。

5. 每一分 Token 都要花在刀刃上:成本、并发与可观测性

5.1 算一笔账:无效上下文到底烧掉多少钱

上下文越长,对成本的冲击远比想象中直接。假设你的 Agent 每次调用都会多塞 3000 个无效 token,日调用量是 10 万次,按输入侧 $0.003/千 token 算,一天多烧 $9,一个月就是 $270。这还是保守估的输入价格,如果再算上更贵的主流模型、更长的上下文、更高的调用量,一个月多烧几千块很轻松。更别说上下文越长,每次推理的延迟也越高,体验跟着一起下降。

所以我会定期统计"每次请求平均上下文长度"和"实际有效内容占比"。怎么统计?很简单,在组装上下文的代码里打点,记下每次 messages 的总 token 数,以及其中检索片段、历史消息各自占多少。出现成本异常时,先查上下文是不是在不知不觉间膨胀了。

5.2 Prompt Caching:把固定前缀变成低价缓存区

现在不少模型服务支持 prompt caching,原理是:相同前缀的 prompt 会被缓存,命中的前缀部分按更低价甚至免费计费,也能显著降低首 token 延迟。想用好它,上下文组装顺序就很讲究了。

固定不变的文本要尽量放在最前面,而且要保证前缀完全相同。所以系统提示词、工具定义、固定帮助文档应该排在最前面,并且最好保持不变。动态内容——当前问题、最新消息、每次不同的检索结果——要排在后半段。千万别把动态内容插到系统提示词中间,那样前缀会变,缓存直接失效。另外一个细节:就算你只是改了一个字,只要在缓存前缀的覆盖范围内,也会导致整段缓存失效。所以系统提示词一旦定稿,就尽量别去动它,任何调整都意味着缓存区需要重建。

5.3 并发隔离:上下文分区片是 Agent 稳定服务的前提

前面提过并发基础做法,这里再深入一点。并发场景里最容易出问题的不是模型 API 的 QPS,而是状态串台。典型症状:A 用户问订单,Agent 回答里出现了 B 用户的名字或订单号。很多情况下就是全局变量 or 缓存 key 设计不当导致的。

上下文在设计上必须严格遵守"分区片"原则:每一个 session_id 就是一个独立命名空间,messages、检索缓存、长期记忆全都按这个 key 隔离。子 Agent 之间传值只允许传拷贝,不允许共享引用可变对象。我在代码里会用类似session_context(key=session_id)这样的上下文管理器,保证无论函数调用多深,拿到的都只是当前 session 的那一份数据。做并发压测时,我一般会专门写一个"大乱斗"脚本:几十个 session 同时对话,每个 session 用一种独特标记,跑完检查标记有没有串。

5.4 可观测性:看不到每次的上下文,就无法排障

如果只能给一条调试建议,我会说:把每次调用模型前组装好的 messages 完整记下来。很多 Agent 行为异常,你光看模型输出根本猜不出原因,但只要把当次上下文翻出来,问题往往一眼就能定位——要么检索内容被排到了最后,要么某条工具返回的报错信息原样混进了历史,要么系统提示词被动态内容截断导致缓存失效。

我会在项目里给每次调用打一条结构化日志:session_id、调用时间、模型名、messages 数组、每个部分的 token 数、来源标记。调试时用 session_id 把整条链路拉出来,基本能还原 Agent 当时“看到”了什么。有条件的话用 LangSmith 这类 trace 工具也行,原理一样:Agent 出了问题,先看它这次到底看到了什么,而不是猜模型。这条经验在我排过的故障里,命中率超过八成。

6. 我踩过的四个上下文坑,以及对应的止血方案

6.1 坑一:工具报错信息被原样写回历史,Agent 学坏了

有段时间我的 Agent 经常出现诡异行为:回答里偶尔夹着 JSON 片段、状态码、甚至堆栈信息。查了半天发现是工具调用失败后,我把返回的异常内容直接塞回了消息列表。模型读到"500 Internal Server Error"这种信息,会学着把它当重要事实反复引用,甚至开始"复述"错误格式。

止血方案很简单:工具返回值写回上下文前先做一层转换。失败的时候,不要贴原始报错,转成一句面向模型的人话,比如"查询失败,原因:网络超时,请提醒用户稍后重试"。这既保留了必要信息,又不会让模型被错误格式污染。

6.2 坑二:检索内容放的位置不对,模型装着没看见

另一个高频问题是:RAG 命中的资料明明放进去了,模型还是不用,自顾自按历史消息回答。后来我把完整的上下文翻出来,发现检索片段被排在了对话历史之后、最新用户消息之前。这时候模型已经被最新几条对话带偏了节奏,检索内容夹在中间变成了"背景噪音"。

我的固定排序现在是:系统提示词 -> 检索知识/工具说明 -> 对话历史 -> 最新用户消息。检索内容作为考试时的"参考资料"放在前面,对话历史作为"过程记录"放在中间,最新消息作为"待办问题"放在最末尾。这个顺序在我自己的项目里是最稳的,你可以把它当默认起点,再根据实际效果微调。

6.3 坑三:多个 Agent 共享同一个 State,张冠李戴

多 Agent 刚跑起来的时候,我踩过一个很隐蔽的坑:两个子 Agent 共用了同一个全局 memory 对象,A Agent 在中间步骤里记下的临时结论,被 B Agent 当成自己的入参读走,结果 B 的回答里莫名出现了 A 的中间观点。

后来我规定:子 Agent 的函数签名只允许接收白名单字段,也就是它完成任务真正需要的那几个值。跨节点传递全部通过显式字段完成,禁止从全局 state 里"顺路摸一把"。如果你发现自己写代码时总想读全局变量,停一下,想想这个字段是不是真的应该给当前 Agent 看到。一旦答案犹豫,就说明上下文边界划分得不够干净。

6.4 坑四:总在窗口爆掉之后才处理,用户会话直接变废物

最后一个坑,也是我最开始常犯的:不做提前量,等模型报出上下文超限才想着处理。结果就是用户聊到一半,Agent 突然失效,前面所有对话记录因为超限被全部丢弃,体验直接归零。

现在我会在组装完成后主动算一次 token,设置两级阈值:超过预算的 60% 时触发摘要节点,把旧对话压成笔记;超过 80% 时强制裁剪并丢弃无关过程消息。这样窗口永远不会爆,用户也不会感受到 Agent"失忆"。

最后再分享一个小技巧:每次踩完坑,别急着改完就跑。把当时的坏案例存成一个固定的回归测试集,比如"用户第二次追问时不能忘记预算限制""检索片段不能被历史消息淹没""A 用户的订单不能串到 B 会话"。下次改上下文策略,先跑一遍回归集,过了再上线。我在实际项目里就是这么做的,它比对着线上案例反复瞎猜要高效得多。上下文工程说到底就是一件需要耐心打磨的事,但回报也足够直接——你的 Agent 会从"偶尔聪明"变成"稳定靠谱"。

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

MR25H40CDF+TM4C1294:SPI MRAM实现不掉电数据存储的完整方案

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

作者头像 李华
网站建设 2026/10/4 4:50:30

Python+OpenCV+YOLO:台球击球路线规划系统实战解析

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

作者头像 李华
网站建设 2026/10/4 4:50:28

川崎AS语言运动指令实测速查表:MOVJ/MOVL/ARCS参数真相

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

作者头像 李华
网站建设 2026/10/4 4:50:20

STM32精准解析PPM信号:输入捕获+状态机实战指南

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

作者头像 李华
网站建设 2026/10/4 4:48:16

YOLOv5车牌检测与OCR识别两段式架构实战指南

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

作者头像 李华