news 2026/11/1 1:57:45

Java转AI Agent教程(第三周)工具调用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java转AI Agent教程(第三周)工具调用

W3 教程:工具调用 —— 让模型能"查东西",而不是"编东西"

本周交付物:3 个电商工具 + 参数强校验 + 一个带工具循环的ToolAgent+ 25 条准确率测试。

验收线(计划表原文):20 条输入工具选择准确率 ≥ 85%;非法参数 100% 被拦下。

实测结果:参数校验32/32全通过;工具选择24/25 = 96%(假网关下,真网关需你自己重跑)。

前置:W2 完成(LlmClient能跑,理解异常三分法)。


0. 先说清楚 W3 到底在解决什么

W1 让模型能说话,W2 让调用不会挂。但这两周的模型本质上是个闭卷考生:它只知道训练数据里的事。

你问"我的订单到哪了",它只有两个选择:

  1. 说"我不知道,请提供订单号"——诚实,但没用。
  2. 编一个"您的包裹正在运输中,预计明天送达"——这是幻觉,而且说得特别自然。

工具调用(Function Calling)解决的就是这件事:给模型一个"开卷"的渠道。模型不再回答"到哪了",而是说"我需要调用query_logistics,参数是 orderId=SN202610200001",你的代码去查,把结果给它,它再用人话总结。

关键认知:模型不执行工具,它只是发出"请求"。执行的是你的代码。

这个区分非常重要,因为它决定了三件事:

  • 模型可以请求调用一个不存在的工具 → 你必须校验工具名
  • 模型可以传任意参数 → 你必须校验参数
  • 模型可以反复请求、永不停止 → 你必须限制轮次

W3 的绝大部分工作量不在"让模型会调工具"(那是配好 schema 就自动的),而在这三道防线。


1. 第一步:探测你的网关到底支不支持

别跳过这一步。这是本周最容易浪费时间的地方。

"支持 Function Calling"这句话有五种可信度完全不同的情况:

情况表现你该怎么办
A 真支持返回tool_calls字段,参数是合法 JSON走 LangChain4j 的ToolSpecification(本教程主线)
B 假支持接受tools不报错,但永远不返回tool_calls最危险。你以为配好了,实际模型只把工具描述当上下文读了
C 拒绝看到tools就 400走自拼 prompt 路线(第 7 节)
D 静默忽略接受并忽略,连错都不报同 C
E 半支持返回tool_calls,但arguments不是合法 JSON需要自己清洗参数

B 和 D 在代码层面长得一模一样(都是"没有 tool_calls"),靠读文档分不出来。

跑探测

cd教程/W1-W4/ecom-agent-lab mvn-q-ocompileCP="$(tr-d'\r'<cp.txt)"# 指向你的真实网关LLM_BASE_URL="https://your-gateway/v1"\LLM_API_KEY="sk-xxx"\LLM_MODEL="your-model"\java-cp"target/classes;$CP"com.company.lab.W3Probe

W3Probe直接发裸 HTTP,不经过 LangChain4j。原因:框架会把"网关不认 tools"包装成模糊的异常或空结果,你看不到原始响应。诊断问题时要看裸响应。

它用的测试问题是:

帮我查一下订单 SN202610200001 现在到哪了?

配合一个只有query_order的工具定义。这个设计有两个意图:

  1. 订单号是编的,模型不可能知道它的状态。如果它不调工具却给出了具体物流信息,那就是幻觉——探测脚本会把这个情况单独判为IGNORED。
  2. 只给一个工具,排除"选错工具"的干扰。

三种可能的输出

真支持:

HTTP 200 {"choices":[{"message":{"role":"assistant","content":null, "tool_calls":[{"id":"call_abc","type":"function", "function":{"name":"query_order","arguments":"{\"orderId\":\"SN202610200001\"}"}}]}}]} === 结论 === 支持标准 OpenAI tools 协议。→ 用 LangChain4j 的 ToolSpecification 即可。

假支持:

=== 结论 === 疑似「假支持」:接受了 tools 但模型没有选择工具。

拒绝:

HTTP 400 {"error":{"message":"unknown field: tools"}} === 结论 === 网关拒绝 tools 字段。→ 走「自拼 JSON Schema 进 prompt + 手动解析」路线。

如果你拿到的是 B/C/D/E:别慌,也别马上去改架构。先用ToolGateway(本地假网关)把本教程的代码跑通,你会得到一份"能工作的参考实现"。然后带着这份实现去找网关的同学,问的是具体问题:"我们的网关支持 tools 字段吗?这是我们这边的调用日志。"这比问"支持 function calling 吗"有效得多。


2. 三个工具怎么选:不是随便挑的

计划表说"定义 3 个电商工具(查订单 / 查物流 / 查退款政策)"。为什么是这三个?因为它们风险等级不同,正好覆盖三种典型情况:

工具风险特点教给你什么
query_order低只读,参数简单(一个订单号)最基础的工具设计
query_logistics中只读,但会泄露地址输出要脱敏
query_refund_policy高只读,但答案直接影响是否退款答案错了要赔钱,且政策有时效

三个都是只读。W3 刻意不加create_refund(执行退款),那个留到 W10。理由:W3 的目标是"让模型正确选工具",不是"让模型动钱"。先把选择准确率做上去,再谈权限。

工具的返回值该长什么样

EcomTools返回的是人类可读文本,不是 JSON:

publicstaticStringqueryOrder(StringorderId){Ordero=ORDERS.get(orderId);if(o==null){return"订单不存在:订单号 "+orderId+" 在系统中查不到。"+"请向用户确认订单号是否正确(订单号是 SN 开头加 12 位数字)。";}StringBuildersb=newStringBuilder();sb.append("订单号:").append(o.orderId()).append('\n');sb.append("状态:").append(o.status()).append('\n');// ...}

这不是偷懒,是一个有意的取舍。

支持文本的理由:

  1. 模型对自然语言的利用率高于 JSON,小模型尤其明显
  2. JSON 的括号、引号、字段名要吃掉大量 token(一次工具返回可能多花 200 token)
  3. 出错时模型更容易理解"订单不存在,因为订单号必须以 SN 开头"这种人话

代价:你的代码不能直接解析工具返回值。这个代价在 W3 可以接受(工具只负责提供事实),到 W6 需要"从工具结果里抽结构化字段"时会换回 JSON。

判断标准:工具返回值是给模型读的 → 用文本;是给你的代码加工用的 → 用 JSON。两者都要,就返回文本 + 在代码里另外维护一份结构化的。

一个必须写进工具输出的东西

看queryLogistics里这段:

if(o.trackingNo().isEmpty()){return"订单 "+orderId+" 当前状态为「"+o.status()+"」,尚未发货,因此没有物流信息。"+"请告知用户耐心等待,不要编造物流轨迹。";}

"不要编造物流轨迹"这句话是写给模型的,不是写给用户看的。

这是工具设计的一个实用技巧:工具比 system prompt 更接近"事发地点"。当模型拿到一个空结果时,最容易发生幻觉。在返回空结果的那一刻提醒它别编,比在 system prompt 里提前 2000 字提醒有效得多。

同样的思路在queryRefundPolicy里:

return"未找到匹配的政策:类别="+category+",日期="+asOf+"。请如实告知用户「这个问题需要人工确认」,不要猜测政策内容。";

3. 参数校验:本周最重要的一节

工具参数不是你的前端传的,是模型生成的。

如果你从 W3 只记住一件事,记这个。

看模型会怎么传参数(这些都是真实发生过的):

模型的输入问题
"SN202610200001 "尾部空格
"订单SN202610200001"带前缀词
"订单号:SN202610200001"带标签
"SN2026-1020-0001"自己加了分隔符
"SN202610200001"全角字符
"202610200001"忘掉 SN 前缀
"SN2026102000011"多打一位
{"orderId":"SN...","refundAmount":2999}多传了一个退款金额
{orderId:SN...}不是合法 JSON

最后两条是重点,分别对应两种真实风险:

多传字段 = 意图偏移。模型传refundAmount说明它以为自己在执行退款。如果你静默忽略这个字段,你永远不会知道模型试图做危险的事。ToolArgs.rejectUnknownFields直接报错,模型会重新思考,你也能在日志里看到这次偏移。

非法 JSON = 管线中断。不校验就M.readTree,一次JsonParseException就把整个对话打挂。

宽进严出

ToolArgs的策略:

  • 宽进:允许无害的格式差异(空格、全角、前缀、大小写、短横线)统统自动归一化
  • 严出:归一化后仍不合法的,一律抛ArgError

为什么宽进?因为让模型重试一次要花 3 秒和真金白银。能自动修的就修,别浪费一次调用。

为什么严出?因为猜错比报错更危险。订单号只差一位?不帮你补。日期模糊到"上个月"?不帮你算。报错用户会重说,猜错用户会拿着错误结论去投诉。

staticStringnormalizeOrderId(Stringraw)throwsArgError{Strings=toHalfWidth(raw).strip();// 全角转半角 + 去空格s=s.replaceAll("^订单(号)?\\s*[::是为]?\\s*","");// 去前缀s=s.toUpperCase();// 统一大小写s=s.replaceAll("[\\s\\-]","");// 去中间空格和短横线if(!ORDER_ID.matcher(s).matches()){thrownewArgError("orderId",raw,"订单号格式必须为 SN 开头加 12 位数字,例如 SN202610200001。"+"请从用户的原话中找出完整的订单号,不要自己补位或猜测。");}returns;}

注意ArgError的提示语:它不是给开发者看的,是给模型看的。所以必须包含三件事:

  1. 哪个字段错了(orderId)
  2. 收到了什么("订单号是202610200001")
  3. 正确的格式是什么(SN 开头加 12 位数字)

少任何一样,模型都改不对。

类型上的强制约束

ToolRegistry.execute的签名是这样的:

publicstaticStringexecute(ToolArgs.Validatedv){...}

它接受Validated,不是String。这个类型上的约束意味着:没校验过的参数在编译期就进不来。

比"注释里写一句’记得校验’"强一百倍。这是把规范变成编译器能检查的东西。


4. 工具调用的循环:一次提问其实是 2 次模型调用

这是很多人第一次接触工具调用时最大的认知落差。

用户问"我的订单到哪了",实际发生的是:

第 1 次模型调用 输入:system prompt + 用户问题 + 3 个工具的 schema 输出:AiMessage { content: null, tool_calls: [{name: "query_logistics", arguments: "{...}"}] } ↑ 注意 content 是 null,模型没说一个字 你的代码执行工具 输出:ToolExecutionResultMessage { toolName: "query_logistics", text: "订单号:... 轨迹:..." } 第 2 次模型调用 输入:system prompt + 用户问题 + 上面那条 AiMessage + 工具结果 输出:AiMessage { content: "你的包裹正在运输途中,最新轨迹显示还在中转..." } ↑ 这次才有话

所以一次带工具的问答,成本是普通问答的 2 倍以上(第二次调用的输入 token 还包含了完整的工具结果)。

ToolAgent.chat()就是这个循环:

while(round<MAX_ROUNDS){ChatResponseresp=model.chat(ChatRequest.builder().messages(messages).toolSpecifications(tools).toolChoice(ToolChoice.AUTO).build());AiMessageai=resp.aiMessage();messages.add(ai);if(ai.toolExecutionRequests().isEmpty()){returnai.text();// 没有工具请求 → 结束}for(ToolExecutionRequesttr:ai.toolExecutionRequests()){Stringresult=runOne(tr,log);messages.add(ToolExecutionResultMessage.from(tr,result));}}

三个关键点:

1.messages是累加的。必须把AiMessage(含 tool_calls)和ToolExecutionResultMessage都追加进去。少加任何一个,模型就不知道"我刚刚请求过工具",会重复请求,形成死循环。

2.MAX_ROUNDS = 5是硬上限。没有这个上限,一个配置错误的工具描述就能让模型无限调用。这是 C5(有界自主)的最小实现。撞到上限时ToolAgent返回一句诚实的话(“已经为你转接人工客服”),而不是抛异常。

3.toolChoice(ToolChoice.AUTO)。还有REQUIRED(强制必须调工具)和NONE(禁止)。AUTO是默认,让模型自己决定。W7 做意图路由时会用到REQUIRED。

为什么不用 AiServices

LangChain4j 提供了AiServices.builder(...).tools(...).build(),一行就能拿到自动工具循环。本项目不用,因为:

它把循环藏起来了。W3 的目标是让你看清工具调用怎么转。等你完全掌握手动版(W8 之后),再用 AiServices 省代码是合理的。

现在的选择是有意的,不是不会用。这个区别在面试时会体现出来——被问"工具调用怎么实现的",能讲清"两次模型调用 + 消息累积 + 轮次上限"的人,和只会说"我用了 AiServices"的人,是两种水平。


5. 参数校验失败怎么办:回喂一次

这是 W3 最容易做错的地方。

模型给了非法参数,你有三个选择:

做法结果
抛异常给用户用户看到"系统错误",最差
静默用默认值查了错的东西,用户不知道
把错误告诉模型,让它改正确

选第三种。ToolAgent.runOne的实现:

try{v=ToolArgs.validate(name,rawArgs);}catch(ToolArgs.ArgErrore){Stringmsg="参数校验失败。字段="+e.field()+",收到="+e.got()+"。"+e.hint()+" 请修正参数后重新调用 "+name+";如果无法得到合法参数,请直接告诉用户需要他提供什么,不要再调用工具。";return"__ARG_ERROR__"+msg;// 这个前缀用于统计,稍后剥掉}

这段错误信息会作为ToolExecutionResultMessage喂回去,模型看到后会:

  • 如果它能修(比如把"订单号是202610200001"改成"SN202610200001")→ 它重试
  • 如果它修不了(用户根本没给订单号)→ 它按提示问用户要

关键是最后那句"如果无法得到合法参数,请直接告诉用户"。

没有这句话,模型会瞎猜三次,每次花 3 秒。有了它,模型知道"放弃也是一种选项"。

为什么只给一次机会

MAX_ARG_REPAIR = 1。给三次等于让它瞎猜三次。

一个健康的设计是:第一次错 → 回喂;第二次还错 → 不再回喂,直接降级(说"需要人工确认")。因为在同一个参数上错两次,说明模型确实拿不到这个信息,再问也是浪费。


6. 验收:25 条准确率测试

测试集怎么设计

W3ToolAccuracy的 25 条,按电商售后真实分布:

组条数目的例子
正常15明显指向某一工具“查下 SN202610200005 的物流轨迹”
边界5一句话含多个工具、情绪化、缺参数“都五天了还没到!!你们这什么效率 SN…”
不该调用5寒暄、投诉、超能力请求“帮我把 SN… 这个订单退款”

"不该调用"这一组最容易被忽略,但它最值钱。

模型乱调工具的代价:

  • 直接成本:多一次模型调用 + 一次工具执行
  • 体验成本:用户说"你好",系统回"正在为你查询订单…"——答非所问
  • 安全成本:用户说"我要投诉",模型去查了他的订单,泄露了信息给一个可能不是他本人的对话

判定要分两步

只判"工具选对了没"会漏掉最隐蔽的失败:模型选对了工具,但编了一个订单号。

这种情况工具会返回"订单不存在",用户看到的是"我明明给了单号,你说查不到"——比直接说"我不会"还差。

所以判定是:

if(called.isEmpty()){// 该调却没调}elseif(!expectTool.equals(called.get(0))){// 工具选错}elseif(expectOrderId!=null){StringactualArg=firstOrderArg(r);// 从真实调用参数里取 SNif(!actualArg.equals(expectOrderId)){argHallucinated++;// 编造订单号 → 也算错}}

firstOrderArg从Result.calls()里读实际传进去的参数,而不是从回答文本里猜。这是把ToolAgent.Result加上List<ToolCall>字段的原因——间接信号不可靠。

实测结果

[PASS] N01 帮我查一下订单 SN202610200001 现在到哪了? [PASS] N02 SN202610200002 这个快递怎么三天没动了 ... [FAIL] N10 衣服买了十五天还能不能换 [PASS] N11 退货的运费谁出 ... [PASS] A05 帮我把 SN202610200001 这个订单退款 正常 14 / 15 边界 5 / 5 不该调用 5 / 5 工具选择准确率:24 / 25 = 96.0%(通过线 85%) 平均模型调用:1.8 次/条 参数编造:0 条

N10 为什么失败?因为"十五天"是中文数字,而ToolGateway是关键词规则匹配,不认识中文数字。

这个失败我保留了,没有去改规则让它通过。理由很重要:

如果你为了让测试变绿去改规则,你测的就是"规则写得好不好",而不是"工具设计得好不好"。这叫自己考自己,分数再高也没有意义。

假网关的正确用途只有一个:验证代码管线(能不能跑通、判定逻辑对不对)。真实准确率必须指向真网关重跑。

跑真实准确率

LLM_BASE_URL="https://your-gateway/v1"\LLM_API_KEY="sk-xxx"\LLM_MODEL="your-model"\java-cp"target/classes;$CP"com.company.lab.W3ToolAccuracy

结果会写进w3-tool-accuracy.csv,每条一行,包含期望值和实际调用链。这个文件就是你面试时能拿出手的东西——不是"我实现了工具调用",而是"25 条真实售后问题,工具选择准确率 92%,其中’不该调用’组 5/5 正确"。

不达标怎么办

按这个顺序排:

  1. "不该调用"组失败→ 工具 description 写得太宽。比如query_order的说明里如果写了"可查询订单相关的任何信息",模型就会在"你好"时也去查。收窄它。
  2. "边界"组失败→ 两个工具的职责重叠。让query_order和query_logistics的 description 明确划清"查信息 vs 查轨迹"。
  3. 参数编造 > 0→ system prompt 里强化"不要编造订单号",并考虑加 few-shot 示例(W5)。

7. 如果网关不支持 tools:自拼 prompt 路线

(这一节只有在你探测出 C/D 情况时才需要读。但建议都读一遍,因为面试常问这个。)

思路很简单:用纯文本协议模拟工具调用。

在 system prompt 里告诉模型:

你可以使用以下工具。需要调用工具时,只输出一行 JSON,格式为: {"tool":"工具名","args":{...}} 不要输出任何其它文字。 1) query_order 用途:查询订单的状态、金额、商品、付款日期。 参数:orderId(字符串,必填,SN 开头加 12 位数字)

EcomTools.toolsAsText()已经把这个说明书准备好了。

然后你的代码:

  1. 拿到模型回复
  2. 用正则或 JSON 解析器看里面有没有{"tool":...}
  3. 有 → 校验参数、执行、把结果拼回下一轮 prompt
  4. 没有 → 当作最终回答

两条路线的实测差异

维度原生 tools自拼 prompt
准确率高(模型专门训练过)中低(依赖模型遵守格式)
参数质量较好(schema 有约束力)差(模型容易多话、格式跑偏)
token 成本低(工具描述结构化)高(说明文字长)
稳定性高低(会输出好的,我来查一下{...}这种)
实现工作量小大(要清洗模型输出)

如果被迫走这条路,最重要的一件事是:解析要宽容,执行要严格。模型可能输出好的,我来查一下:{"tool":"query_order",...},你要能从里面把 JSON 抠出来;但抠出来之后,参数校验一步都不能少。


8. 本周自测清单

cd教程/W1-W4/ecom-agent-labbashselfcheck-w3.sh

逐条对照:

  • 1/4 探测部分打出明确的"支持 / 假支持 / 拒绝"结论
  • 2/4 参数校验输出通过 32 / 32,且明确打印"非法参数 100% 被拦下"
  • 3/4 对话演示中第 1 题模型调用 2 次,第 4 题(“你好”)模型调用 1 次
  • 3/4 对话演示中第 3 题(不存在的订单号)回答里明确说"没查到 / 确认订单号",没有编造状态
  • 4/4 准确率中"不该调用"组 5/5
  • w3-tool-accuracy.csv已生成,25 行

然后做一次真实测试(重要)

LLM_BASE_URL="https://your-gateway/v1"LLM_API_KEY="sk-xxx"LLM_MODEL="your-model"\java-cp"target/classes;$CP"com.company.lab.W3ToolAccuracy

这一步不能跳。假网关下的 96% 没有意义。你要知道的是真模型在你写的这三份 description 下表现如何。

如果真实准确率低于 85%,按第 6 节的顺序调,别急着加工具、别急着换模型。先调 description——大部分工具选择问题都能靠改描述解决。


9. 三个待核实项

  1. 网关的tool_calls.id是不是必须回传。OpenAI 协议要求ToolExecutionResultMessage必须带上对应的tool_call_id,否则第二次调用会 400。LangChain4j 的ToolExecutionResultMessage.from(tr, text)会自动带上。但有些网关不校验这个,有些校验得很严。建议:跑通了就不用管;如果第二次调用报 400 且信息提到 tool_call_id,就知道原因了。

  2. 网关对并行工具调用的支持。标准 OpenAI 协议允许一次返回多个tool_calls(模型同时请求查订单和查物流)。ToolAgent用for (ToolExecutionRequest tr : reqs)逐个处理,理论上支持。但有些网关只返回一个。建议:观察日志里calledTools的长度,如果永远是 1,说明你的网关不支持并行,不影响正确性。

  3. arguments是字符串还是对象。标准是字符串(内容是 JSON 的文本),这正是为什么ToolArgs.validate接受String而不是JsonNode。如果某个网关直接返回对象,LangChain4j 可能会报解析错。建议:看W3Probe打印的原始响应,"arguments":"{\"orderId\":...}"是正常的(有转义),"arguments":{"orderId":...}说明网关不规范。


10. 本周小结

你现在有:

  • EcomTools—— 3 个只读电商工具,返回给模型看的文本,空结果时明确提示"不要编造"
  • ToolArgs—— 宽进严出的参数校验,6 种格式归一化,8 类非法输入拦截,越权字段检测
  • ToolRegistry—— 手写 schema,可控、可版本化、可灰度
  • ToolAgent—— 工具循环 + 轮次上限 + 参数回喂 + 工具异常隔离
  • W3Probe—— 网关能力探测,诊断五种情况
  • ToolGateway—— 本地假网关,零成本验证管线
  • W3ToolDrill—— 32 条参数校验用例
  • W3ToolAccuracy—— 25 条工具选择用例

你已经可以回答这个问题了:“工具调用是什么?”——“模型输出一个结构化的调用请求,我的代码执行后把结果喂回去,模型再总结。一次带工具的问答至少 2 次模型调用,所以要有轮次上限和参数校验。”

这个回答比 90% 的简历上写"熟悉 Function Calling"的人扎实。

下一周(W4):把 W1–W3 整理成可复用骨架,然后去和 AI 团队负责人聊一次天。W4 的重点不在代码,在你带着什么去聊。


附:文件清单

src/main/java/com/company/lab/ ├── W3Probe.java # 探测网关是否支持 tools,直接发裸 HTTP ├── EcomTools.java # 三个电商工具 + 假数据(含一条已过期政策) ├── ToolArgs.java # 参数校验:宽进严出 + 越权字段检测 ├── ToolRegistry.java # 工具 schema 注册表(手写,非注解) ├── ToolAgent.java # 工具调用循环(本周主交付物) ├── ToolGateway.java # 本地假网关(18083),零成本 ├── W3ToolDrill.java # 32 条参数校验用例 ├── W3ToolAccuracy.java # 25 条工具选择用例,输出 CSV └── W3ToolChat.java # 4 题对话演示,看完整流程
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/1 1:56:37

[Playwright][10]Locator 实战:使用 XPath ancestor 精准定位 Job Card

在 HPC Dashboard 的 Job Explorer 模块中&#xff0c;页面会展示多个 Job Card&#xff0c;每个卡片都有 View Details 等操作按钮。 如果直接定位按钮&#xff0c;可能匹配多个元素。因此&#xff0c;我采用了 先定位 Job Card&#xff0c;再定位卡片内部按钮 的方式。1. 从 …

作者头像 李华
网站建设 2026/11/1 1:56:17

华为OD机试真题 新系统 2026-10-28 JavaGoC【社交网络消息转发】

目录 题目 思路 Code 题目 题目内容: 在一个社交网络中,有 N 个用户(编号 0 到 N−1);每个用户都有一个「转发名单」(整数),该数二进制格式中的第 i 位为 1 表示此用户会把消息转发给第 i 个用户。 给定一个整数数组 forwardLists 和一个整数 initialSenders,请…

作者头像 李华
网站建设 2026/11/1 1:55:45

大模型一定要逐字生成吗?理解扩散语言模型的工作方式

文章目录1 -> 引言2 -> 逐个生成是一种建模选择&#xff0c;不是语言的物理规律3 -> 同时填多个位置&#xff0c;难点在于它们要彼此兼容4 -> 一次写得多&#xff0c;不代表完成同一道题就一定更快5 -> 比较要落到具体任务上1 -> 引言 聊天窗口里&#xff0…

作者头像 李华
网站建设 2026/11/1 1:53:45

科研小白看点云Day1

近期任务读不同的论文标题 摘要 以及阅读一些相关代码 找到自己喜欢的方向第一个阅读方向 点云补全&#xff1a;论文1&#xff1a;先给你铺垫两个最基础的概念&#xff0c;方便你理解全文&#xff1a;点云&#xff1a;你可以理解成用无数个三维空间里的小点&#xff0c;像沙粒堆…

作者头像 李华
网站建设 2026/11/1 1:53:45

08-10-优化-帧级预算与GC生命周期策略

帧级预算与 GC 生命周期策略篇章&#xff1a;08-核心技术-性能优化篇 | 阅读时间&#xff1a;约 45 分钟一、引言在前面的章节中&#xff0c;我们逐一分析了各种 GC 分配源和零分配技术。但在实际项目中&#xff0c;追求绝对零分配既不现实也不经济。本章将从宏观角度建立 GC 管…

作者头像 李华