news 2026/10/30 1:43:09

Macro 用户态代码模式实战:用 Deno 运行真实 Macro SDK 的 ExecuteCode 工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Macro 用户态代码模式实战:用 Deno 运行真实 Macro SDK 的 ExecuteCode 工具
  • 后端
  • 前端
  • 协同办公
  • 即时通讯
  • 企业应用
  • CRM
  • AI Agent
  • 人工智能

【免费下载链接】macro

Macro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — @-linked together with shared AI memory.

项目地址:https://gitcode.com/GitHub_Trending/macro3/macro
点击查看免费下载

在 Macro 的 Code Mode 中,模型不必逐条调用原生工具,而是直接编写一段 JavaScript ES 模块,在 Deno 沙箱里操作真实的 Macro SDK。本文聚焦**用户态(user scope)**这一入口:它不是 Agent 会话内部的执行通道,而是面向公共 MCP 等"已登录但不在会话中"的客户端。读完后你将掌握ExecuteCode的程序契约、参数上限、沙箱边界、鉴权与凭证传递方式,以及DescribeCodeTools/ReadCodeDocs构成的发现流程。

一、用户态 Code Mode 的定位:同一套运行时,不同的身份来源

仓库里有两条 Code Mode 装配路径,共用同一份程序契约与运行时说明,但上下文类型不同:

维度会话态(Session)用户态(User)
工具集合toolset()user_toolset()
上下文CodeModeToolContext(含AgentSession)UserCodeModeToolContext(仅 service + cognition)
服务抽象SessionCodeModeUserCodeMode
回执ExecutionReceipt(含execution_id)UserExecutionReceipt(不落库)
评审(reviews)允许明确拒绝

工具集合的定义在 toolset.rs:

/// Code mode for clients outside agent sessions, such as the public MCP. pub fn user_toolset() -> AsyncToolCollection<UserCodeModeToolContext> { AsyncToolCollection::new() .add_tool::<UserExecuteCode, UserCodeModeToolContext>() .add_tool::<DescribeCodeTools, UserCodeModeToolContext>() .add_tool::<ReadCodeDocs, UserCodeModeToolContext>() }

也就是说,用户态对外只暴露三个工具:执行、发现、读文档。测试 toolset/test.rs 进一步断言了这一点,并确认ExecuteCode的输入 schema 中没有execution_id:

assert_eq!(names, ["DescribeCodeTools", "ExecuteCode", "ReadCodeDocs"]); let schema = serde_json::to_value(&tools.tools["ExecuteCode"].input_schema).unwrap(); assert!(schema["properties"].get("execution_id").is_none()); assert!(schema["properties"].get("source").is_some());

会话态需要execution_id、turn_id、acting_as等字段来绑定"哪一轮对话、以谁的身份执行";用户态没有这些概念——身份来自请求本身携带的登录凭证,因此字段被刻意裁掉,避免生成代码伪造身份。

在服务层,这两条路径最终都汇入agent_harness_service。会话态使用RunCredentials(先过 owner 审批门,再为 Agent 铸造令牌),用户态使用UserRunCredentials(直接为登录用户铸造令牌),见 code_mode.rs:

/// Credentials for public MCP runs: the signed-in user, with no session or agent. /// The MCP client asks the user before each tool call, so there is no owner gate. pub struct UserRunCredentials { pub signer: MacroApiTokenSigner, pub hosts: BTreeMap<String, String>, }

注释直接说明了为什么用户态没有 owner gate:MCP 客户端在每次工具调用前已经向用户征得同意。这是理解"为什么用户态更简洁"的关键设计取舍。

二、程序契约:main({macro})与{data}返回

2.1 关联文档原文要义

overview.md 用一段话概括了全部契约:

Use the real Macro SDK, prebundled for Deno. Write an ES module exporting async main({macro}); optionally import {Macro} from "@macro-inc/sdk" or Handlebars from "handlebars". The provided macro is already authenticated as the signed-in user; main also receives token and hosts for explicit construction. Never expose the token. Return plain JSON as {data}. Nothing is saved between executions.

拆解成可执行规则:

  1. 必须是 ES 模块,且导出async的main函数;没有默认导出、没有 CommonJS。
  2. macro已鉴权,直接用它即可,无需自己构造客户端。
  3. 可选 import:{Macro}来自@macro-inc/sdk,Handlebars来自handlebars,两者均已预打包。
  4. main还能收到token和hosts,用于显式构造Macro实例。
  5. 绝不暴露 token:不打印、不返回、不写入。
  6. 返回纯 JSON,形状为{data: ...}。
  7. 执行之间不保留任何状态。

2.2 Rust 侧的输入类型

UserExecuteCode 只有两个字段,并开启了deny_unknown_fields:

#[derive(Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] pub struct UserExecuteCode { pub source: String, #[serde(default = "default_timeout")] pub timeout_ms: u64, }

deny_unknown_fields意味着传入execution_id、acting_as、turn_id这类会话态字段会直接反序列化失败,而不是被静默忽略。这既是安全边界,也是给调用方的明确信号:用户态没有"以某个 Agent 身份运行"这件事。

2.3 返回值校验:为什么reviews会被判失败

main的返回值并非原样透传。执行结束后由 settle() 按契约校验,用户态传入的是Reviews::Rejected:

if reviews == Reviews::Rejected { // Shared guides end with `reviews: []`; an empty list asks for nothing. if let Some(object) = value.as_object_mut() && object.get("reviews") == Some(&serde_json::json!([])) { object.remove("reviews"); } let valid = value .as_object() .is_some_and(|object| object.len() == 1 && object.contains_key("data")); return if valid { (ExecutionStatus::Succeeded, Some(value), None) } else { ( ExecutionStatus::Failed, Some(value), Some("main must return exactly {data: JSON}; reviews are unavailable here.".into()), ) }; }

两个容易踩的坑:

  • 共享指南(如 templates.md)的程序示例普遍以reviews: []结尾。用户态会先把空数组这个"无害形式"删掉,因此照抄这些示例仍然能成功。
  • 一旦真的返回了非空reviews(例如[{kind:'email', id:'x'}]),结果为Failed,错误信息包含reviews are unavailable。测试 domain/user/test.rs 固定了这个行为:
assert_eq!(receipt.status, ExecutionStatus::Failed); assert!(receipt.error.unwrap().contains("reviews are unavailable"));

原因是评审栈需要在会话里展示,而用户态"没有任何地方可以呈现评审",所以UserCodeMode的注释写明 "with no session, journal or reviews"。

2.4 一个最小可用程序

// 工具入参:source export async function main({macro}) { const me = await macro.users.me(); return {data: {userId: me.id}}; }

注意两点:macro已经是登录用户身份,不需要传任何 token;返回对象只能有data一个键。

三、参数取值与准入校验

3.1 两个入参的边界

参数类型约束默认值依据
sourcestring非空、去除空白后不能为空;UTF-8 长度 ≤ 64 KiB无(必填)validate_request
timeout_msu641 ≤timeout_ms≤ 30000,含排队与 API 调用30000default_timeout

校验发生在铸造凭证之前,因此非法请求不会消耗签名开销:

pub(super) fn validate_request(request: &ExecuteRequest) -> Result<(), CodeModeError> { if request.source.trim().is_empty() || request.source.len() > Limits::default().max_source_bytes || request.timeout_ms == 0 || request.timeout_ms > 30_000 { return Err(CodeModeError::Invalid("Provide a nonempty JavaScript module exporting main() of at most 64 KiB and timeout_ms between 1 and 30000.".into())); } Ok(()) }

测试 invalid_requests_are_rejected_before_minting_a_credential 覆盖了"空白源码""timeout 超限"两种情况,并断言凭证签发器未被调用。

3.2 服务端还有一层更宽的硬限制

Limits::default()定义在 code_execution/models.rs:

限制项默认值含义
max_running8同时运行的 Deno 进程数
max_queued16允许排队等待进程槽的执行数
max_duration30s单次执行最长生命周期
max_source_bytes64 KiB源码上限
max_frame_bytes256 KiB单帧上限,含最终返回给模型的 JSON
max_output_bytes2 MiB单次执行 stdout + stderr 合计预算
max_events1024常规事件数

模型可见的返回值受 256 KiB 约束。这意味着"把 300 封邮件正文全量返回"会被判为Limit失败——正确做法是返回精简证据(ID、时间、片段)。

公共 MCP 还拥有独立的准入预算,避免外部客户端挤占 Agent 会话的槽位,见 agent_harness_service/src/main.rs:max_running: 4, max_queued: 8。

四、运行时沙箱:全新进程、白名单出网、无持久化

4.1 "Nothing is saved between executions" 的实现

shared/runtime.md 明确:每次执行都是全新进程,30 秒(含排队)、64 KiB 源码、256 KiB 最终 JSON 帧;依赖预打包;API 流量仅限已配置的 Macro 服务主机;不允许文件写入、任意 import、子进程或环境变量访问。

DenoRunner::execute每次调用都会新建临时目录并写入四个文件,见 deno.rs:

tokio::fs::write(root.join("main.mjs"), &job.request.source).await?; tokio::fs::write(&bootstrap, BOOTSTRAP).await?; tokio::fs::write(root.join("sdk.mjs"), SDK).await?; tokio::fs::write(root.join("handlebars.mjs"), HANDLEBARS).await?; tokio::fs::write( root.join("imports.json"), r#"{"imports":{"@macro-inc/sdk":"./sdk.mjs","handlebars":"./handlebars.mjs"}}"#, ).await?;

imports.json就是"预打包"的落地方式:@macro-inc/sdk与handlebars被 import map 指向本地内联文件,因此任何网络包安装都不需要也不允许。执行结束后临时目录随tempfile::TempDir生命周期销毁,进程被reap()回收:

reap(&mut child).await; // Drop the directory only after the process is reaped. drop(directory);

4.2 Deno 权限旗标

启动参数在 deno.rs 中一次性收紧:

.args([ "run", "--no-prompt", "--no-config", "--no-lock", "--no-remote", "--no-npm", "--deny-write", "--deny-env", "--deny-run", "--deny-ffi", "--deny-sys", "--deny-import", ]) .arg(network) .arg(format!("--allow-read={}", root.display())) .arg(format!("--import-map={}", root.join("imports.json").display())) .arg(format!("--v8-flags=--max-old-space-size={}", self.heap_mb)) .arg(&bootstrap)

对照 runtime.md 的表述逐条对应:

  • --deny-write→ 没有文件系统写入;
  • --no-remote --no-npm --deny-import+ import map → 没有任意 import 与包下载;
  • --deny-run→ 没有子进程;
  • --deny-env+env_clear()→ 没有环境变量访问(注释说明APP_SECRETS_JSON、AWS 凭证、代理设置等都无法泄漏到生成代码);
  • --allow-read=<scratch>→ 只能读取本次临时目录。

网络权限按需生成:从environment.hosts提取 host:port 组成白名单,为空时直接--deny-net。

4.3 Deno 版本被强校验

DENO_VERSION = "2.9.6",启动时执行deno --version并比对前缀,不匹配则拒绝启动。这避免了"本地能跑、线上行为不同"的隐性差异。

4.4 运行时还做了哪些防护

deno.rs 的桥接层有两条值得注意的实现:

  • 输出预算:stdout/stderr 各按LinesCodec限长读取,累计超过max_output_bytes立即返回FailureCode::Limit;同时为 SDK 诊断保留 64 KiB 独立额度,避免内部诊断吃掉用户程序的输出额度。
  • Token 脱敏:每行在 JSON 解析前先做字符串替换,把本次凭证替换为[REDACTED],覆盖"值"和"对象键",且不破坏 JSON 结构:
fn redact_token(line: String, token: &str) -> String { if token.is_empty() { line } else { line.replace(token, "[REDACTED]") } }

注释也诚实地说明了边界:这是防误泄而非密码学保证——程序本身持有凭证,刻意编码后传出不在防护范围内。这正是文档反复强调"Never expose the token"的原因:最终仍需程序自律,服务端只兜底。

五、macro从哪来:一次性的凭证传递

5.1 凭证只走私有管道

bootstrap.mjs 是可信引导脚本,顺序固定:

const context = await new Response(Deno.stdin.readable).json(); // ... 安装 fetch 观测与追踪头注入 ... const macro = new Macro({token: context.token, hosts: context.hosts}); const session = context.sessionId ? macro.agentSessions.byId(context.sessionId) : undefined; const execution = session && context.executionId ? session.codeExecutions.byId(context.executionId) : undefined; const program = new URL("./main.mjs", import.meta.url).href; const { main } = await import(program); if (typeof main !== "function") throw new Error("Export an async main({macro, session, execution}) function."); const value = await main({...context, macro, session, execution}); emit({type: "result", value: value ?? null});

由此可得几个文档未明说但很重要的事实:

  1. main收到的参数是{...context, macro, session, execution},因此token、hosts、traceHeaders、sessionId、executionId都会出现。用户态下sessionId/executionId为None,所以session与execution为undefined——不要写execution.reviews.create,那是会话态独有的。
  2. 凭证从 stdin 单向传入,写入后立即drop(stdin),不经过 argv,也不落盘(deno.rs)。
  3. 动态 import 的路径由字符串拼出而非字面量,注释说明这样能让整个模块图在运行时加载、从而受 scratch 读权限约束。

5.2 凭证的生命周期

用户态令牌由MacroApiTokenSigner::mint_for(user, 60)铸造,注释写明"与 30 秒 deadline 一致,外加时钟余量",且不提供 refresh credential。凭证签发点在 domain/user.rs:

validate_request(&request)?; let environment = self.credentials.issue(user).await?;

注意user来自request.user_id(已认证请求),而非来自生成代码——UserExecutionCredentials的注释写得很直白:"The user comes from the authenticated request, never from generated code."

5.3hosts决定了两件事

sdk_hosts()在 code_mode.rs 中把各服务 URL 收敛为一张表:document-content、static-content、storage、search、properties、auth、agent-harness、email、calendar、cognition、notification、scheduled-action、static-files、connection、contacts、unfurl。这张表同时是:

  • SDK 构造参数(new Macro({token, hosts}));
  • Deno 出网白名单(--allow-net=host:port,...)。

也就是说,"API 流量仅限已配置的 Macro 服务主机"不是策略声明,而是进程级网络权限。

六、回执结构:activity、activity_truncated、result、error

用户态返回 UserExecutionReceipt:

pub struct UserExecutionReceipt { pub status: ExecutionStatus, pub activity: Vec<ExecutionActivity>, pub activity_truncated: bool, pub result: Option<Value>, pub error: Option<String>, }

含义逐项说明:

  • status:Succeeded/Failed/Cancelled/TimedOut等终态。
  • activity:观测到的 SDK 操作序列,不含参数与响应(observing SDK operations, without arguments or responses)。它由 bootstrap 中的observeRequests产生,并以{type:"progress"}帧回传。
  • activity_truncated:SDK 操作数超过记录上限(bootstrap 中为 128 次 started,超出只发一次{truncated:true})。
  • result:只有main显式返回的值,console.log不会进入结果。
  • error:失败时的安全文本。

测试 runs_as_the_authenticated_user_and_returns_data_with_activity 把这条链路固定下来:程序拿到的是本次签发的凭证、session_id与execution_id均为None,最终activity里出现一条Get Agent Coding Preferences且状态为Completed。

result与error可以同时非空:当返回形状不合法(例如带了非空reviews)时,status=Failed但result保留原始返回值,便于定位问题。

七、发现流程:先描述任务,再读符号

ExecuteCode的描述里有一句强约束(见 user/execute_code.md):

Before writing a program, call DescribeCodeTools with task set to what the program must do, unless the entity indexes it needs are already in this conversation, then read the symbols the program uses with ReadCodeDocs, all together in one call. The SDK is large; do not guess method names or options.

这条建议有实际成本依据:SDK 目录有 30 个实体、1799 条符号引用(见 documentation.json 的统计),猜测方法名的失败率远高于一次发现调用。

7.1DescribeCodeTools的三个参数

参数约束作用
task可选,自然语言交给 Jev 排序,返回最相关实体的索引("entities are most relevant first")
names≤ 5 个实体名直接点名要索引,如documents、email、core
topics≤ 4 个直接拉取工作流指南:search/ai/templates/examples

约束在 DescribeCodeTools::describe 中硬编码,超限返回Invalid。用户态还额外有一条限制:

if host == CodeHost::User && self.topics.iter().any(|topic| matches!(topic, CodeGuideTopic::Templates | CodeGuideTopic::Examples)) { return Err(CodeModeError::Invalid("Only the search and ai guides are available here.".into())); }

为什么只放行search与ai?因为templates指南的核心示例是execution.reviews.create(...),而用户态根本没有execution句柄;examples指向会话态的SKILL.md,同样包含评审与turn_id语义。与其给出不可执行的指南,不如明确拒绝——这正是用户态与共享文档之间的一致性问题,测试 toolset/test.rs 同时验证了共享契约一致、会话态描述含execution.reviews.create而用户态不含。

7.2task的选择算法与预算

documentation_for_task在 documentation.rs 中实现:

  • 调用rank_entities,把每个实体的name作为问题、把description拼进提示,让 Jev 输出概率;
  • 只保留score >= 0.5且有限的实体,按分数降序、同名按字典序稳定排序;
  • 单个结果总预算DOCUMENTATION_BYTES = 32 KiB,超出预算的实体进入omitted,调用方可再按名请求;
  • status非selected时(unconfigured/cancelled/provider_error/timeout),entities为空,此时应按 user/discovery.md 的指示:"pick entities from the catalog and request them by name, up to five together"。

超时策略也不同:这里是 5 秒("The agent is waiting on this call"),而每轮提示注入路径只用 1 秒,且失败即回退到紧凑目录。

7.3ReadCodeDocs:按符号读引用

pub struct ReadCodeDocs { pub symbols: Vec<String>, }
  • 数量必须在 1..=10,否则Invalid;
  • 按请求顺序返回,unknown收集目录里不存在的符号,omitted收集因 32 KiB 预算被跳过的符号;
  • 第一条引用总是返回,因为单条引用不会超过预算。

测试 symbols_from_an_index_read_as_their_own_references 验证了三点:方法级符号TaskNamespace.create可读、其引用里包含`opts.name`这类可继续追溯的符号、不存在的TaskNamespace.missing落入unknown。

八、可运行的程序范式

8.1 带边界的并发搜索

guides/search.md 在用户态可用(search指南被放行)。它的关键手法是"多查询并发 + 早停 + 保留失败分支":

export async function main({macro}) { const queries = ['launch decision', 'release readiness']; const outcomes = await Promise.allSettled(queries.map(async query => { const evidence = []; let stoppedEarly = false; for await (const document of macro.documents.search(query, {searchOn:'content'})) { if (evidence.length === 5) { stoppedEarly = true; break; } evidence.push({id:document.id, text:(await document.content()).slice(0,3000)}); } return {query, evidence, stoppedEarly}; })); return {data: outcomes.map((item, index) => item.status === 'fulfilled' ? item.value : {query:queries[index], error:String(item.reason)})}; }

请注意两点:示例中去掉了reviews:[](用户态也不需要),并且显式标注stoppedEarly——指南反复强调"a short sample cannot establish corpus-wide completeness or absence",即不能把提前停止的迭代器说成穷尽结果。

8.2 工作区概览:按类别小页并发

shared/program.md 给出了一类高效范式:

export async function main({macro}) { const types = ['email', 'channel_thread', 'calendar_event']; const pages = await Promise.all(types.map(type => macro.workspace.page({includeTypes:[type], limit:3}) )); return {data: types.map((type, i) => ({ type, hasMore: pages[i].hasMore, items: pages[i].items.map(item => ({id:item.id, type:item.type, name:item.name ?? item.subject})) }))}; }

其中两条约束来自同一份文档:单个混合分页会被某一类实体占满,所以要按类别分别取页;每页只是样本,不是类别总量,因此只返回hasMore与精简元数据。任务属于文档,需用includeTypes:["document"]配合df:{l:{dst:"task"}};AST 的&与|都是二元操作符,单个条件不要包一层。

8.3 结构化抽取与分类

ai指南同样在用户态可用。典型组合是先把源文本取到本地,再对文本做macro.ai.structuredCompletion(配合toolset:{type:'none'}),或对一批条目做macro.ai.decide。SKILL.md的提醒是:"check the returned outcome rather than assuming success"——即必须检查返回结构里的结果状态,而不是假定调用成功。

8.4 用 Handlebars 做本地渲染

用户态仍然可以import Handlebars from 'handlebars'并使用它——只是不能创建评审栈。渲染本身不产生任何 API 调用:

import Handlebars from 'handlebars'; export async function main() { const render = Handlebars.compile('Hi {{name}},\n\n{{body}}', {strict:true, noEscape:true}); const drafts = [ {name:'Alex', body:'Launch update'}, {name:'Sam', body:'Release readiness'} ].map(v => ({recipient: v.name, text: render(v)})); return {data: {drafts, note: 'Rendered locally; nothing was sent.'}}; }

noEscape:true的用途见 templates.md:Markdown 正文需要保留 Markdown 语法;若目标是 HTML 则应使用默认转义。

九、失败处理与重试纪律

runtime.md里最重要的一句是:

SDK writes, including sending messages and email, take effect immediately; completed writes survive cancellation or errors. Inspect state before retrying, never blindly replay writes.

配合代码看,这一点是被架构强化的:

  1. 取消只停进程,不回滚写入。Outcome::Cancelled对应的错误文案是 "Execution cancelled. Unfinished calls may have taken effect."(service.rs)。
  2. 超时同理:30 秒是含排队的墙钟预算,超时不代表没有副作用。
  3. 用户态没有幂等键。会话态可以用execution_id重放同一份源码拿回已存回执("Reusing your existing ID with identical source returns its saved receipt without running again"),但UserExecuteCode没有这个字段,所以用户态重试必然是重新执行。这正是"先查状态再重试"在用户态更为关键的原因。
  4. 失败分类可用于决策。FailureCode区分Runtime/Protocol/Limit/Internal:Limit说明要缩小返回体积或降低并发,Protocol通常意味着输出接错了形状,Runtime才是程序逻辑问题。

排查顺序建议:先看status与error,再看activity判断"写操作是否已经发生",最后才决定是否重试;对邮件、消息等不可逆操作,重试前应先用macro.email.search/macro.channels之类只读调用确认状态。

十、可观测性与日志

  • console.log/info/debug/warn/error都被 bootstrap 重写为{type:"log"}帧,经EventKind::Log进入事件流;它们只用于诊断,不会成为模型可见结果。
  • 用户态执行会打一条 span:code_mode.user_execution,字段包含source_bytes、timeout_ms、status、activity,见 domain/user.rs。注意skip_all与不记录源码,避免把用户数据写进追踪。
  • 生成的代码发出的 SDK 请求会带上traceparent/tracestate,并加一个标记头x-macro-code-execution: 1(bootstrap),用于在服务端区分"程序发起"与"人发起"的调用。

十一、把代码读下去:推荐入口

按阅读顺序整理关键文件,便于继续深入:

  1. 契约与提示词:user/overview.md、user/execute_code.md、user/discovery.md、shared/program.md、shared/runtime.md
  2. 工具装配与参数:inbound/toolset.rs
  3. 用户态服务与凭证:domain/user.rs、domain/user/test.rs
  4. 返回值校验与准入:domain/service.rs
  5. SDK 文档选择:domain/documentation.rs
  6. 运行时与沙箱:code_execution/models.rs、deno.rs、bootstrap.mjs
  7. 生产装配:services/agent_harness_service/src/code_mode.rs、services/agent_harness_service/src/public_mcp.rs

小结

用户态 Code Mode 的本质是:把"真实 SDK + 真实身份"塞进一个一次性 Deno 进程。文档用一段话规定了程序形状(ES 模块、main({macro})、{data}、不泄露 token、不跨执行保存状态),而仓库用三层机制把这些规定变成硬约束——输入层的deny_unknown_fields与 64 KiB/30 秒校验,执行层的 deny-write/deny-env/白名单出网与 token 脱敏,输出层的{data}形状校验与 256 KiB 帧上限。理解这三层,就能判断一段程序"能不能跑、跑完会不会留下东西、失败后该不该重试"。

  • 后端
  • 前端
  • 协同办公
  • 即时通讯
  • 企业应用
  • CRM
  • AI Agent
  • 人工智能

【免费下载链接】macro

Macro is a unified workspace for teams: email, chat, docs, tasks, agents, calls, and CRM — @-linked together with shared AI memory.

项目地址:https://gitcode.com/GitHub_Trending/macro3/macro
点击查看免费下载

相关推荐

上一篇:FFmpeg libav码率控制:CBR、VBR、ABR模式详解
下一篇:VirtualMotionCapture虚拟摄像机使用教程:创建专业级拍摄效果

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

JSP+Servlet+MySQL游戏购物网站源码解析与实战指南

简介&#xff1a;这份资源是一套基于JSPServletMySQL的游戏购买网站完整项目源码&#xff0c;面向学习Java Web开发的学生与初级开发者&#xff0c;可用于课程设计、毕业设计或实战练手&#xff0c;帮助理解从页面展示到数据持久化的完整链路。压缩包共246个文件、约14.85MB&am…

作者头像 李华
网站建设 2026/10/30 1:39:01

Binder 简述

Binder Binder使用Client&#xff0d;Server(c/s架构)通信方式。Binder框架定义了四个角色&#xff1a;Server,Client,ServiceManager以及Binder驱动。其中Server,Client,ServiceManager运行于用户空间&#xff0c;驱动运行于内核空间。ServiceManager&#xff0c;负责把Binder…

作者头像 李华
网站建设 2026/10/30 1:37:20

24G显存部署DeepSeek-R1:Ollama安装、量化选型与知识库排错

简介&#xff1a;《deepseek应用手册》是一份面向深度学习、自然语言处理与API集成学习者的实操型文档&#xff0c;适合希望系统掌握DeepSeek多模型协作、私有知识库搭建及参数调优的初中级用户。压缩包内仅含1个docx文件&#xff0c;体积约207KB&#xff0c;便于轻量下载与随时…

作者头像 李华
网站建设 2026/10/30 1:37:14

Hadoop分布式计算下的朴素贝叶斯文本分类:从MapReduce原理到实现与调优

简介&#xff1a;这是基于Hadoop的朴素贝叶斯文本分类项目&#xff0c;利用MapReduce实现训练与评估&#xff0c;适用于Hadoop课程设计、毕业设计或文本分类入门实践。项目包含词频统计、文档计数、模型构建与测试集分类等核心步骤&#xff0c;并输出精确率、召回率和F1评估结果…

作者头像 李华