OpenClaw工具拆解之 sessions_list+sessions_history

一、sessions_list 工具

1.1 工具概述

功能 :列出所有会话(包括子 agent 会话)
核心特性

  • 支持按类型过滤(main/group/cron/hook/node/other)
  • 支持按活跃度过滤(activeMinutes)
  • 可包含最后 N 条消息(messageLimit,最大 20)
  • 会话可见性检查(visibility guard)
  • 沙盒隔离支持

1.2 Schema 定义

位置:第 109015 行

javascript 复制代码
const SessionsListToolSchema = Type.Object({
    kinds: Type.Optional(Type.Array(Type.String())),
    limit: Type.Optional(Type.Number({ minimum: 1 })),
    activeMinutes: Type.Optional(Type.Number({ minimum: 1 })),
    messageLimit: Type.Optional(Type.Number({ minimum: 0 }))
});

1.3 完整执行代码

位置:第 109015 行

javascript 复制代码
function createSessionsListTool(opts) {
    return {
        label: "Sessions",
        name: "sessions_list",
        description: "List sessions with optional filters and last messages.",
        parameters: SessionsListToolSchema,
        execute: async (_toolCallId, args) => {
            const params = args;
            const cfg = opts?.config ?? loadConfig();
            
            // 1. 解析沙盒会话工具上下文
            const { mainKey, alias, requesterInternalKey, restrictToSpawned } = resolveSandboxedSessionToolContext({
                cfg,
                agentSessionKey: opts?.agentSessionKey,
                sandboxed: opts?.sandboxed
            });
            const effectiveRequesterKey = requesterInternalKey ?? alias;
            
            // 2. 解析会话可见性
            const visibility = resolveEffectiveSessionToolsVisibility({
                cfg,
                sandboxed: opts?.sandboxed === true
            });
            
            // 3. 解析类型过滤
            const allowedKindsList = (readStringArrayParam(params, "kinds")?.map((value) => 
                value.trim().toLowerCase()
            ) ?? []).filter((value) => [
                "main", "group", "cron", "hook", "node", "other"
            ].includes(value));
            const allowedKinds = allowedKindsList.length ? new Set(allowedKindsList) : void 0;
            
            // 4. 解析其他参数
            const limit = typeof params.limit === "number" && Number.isFinite(params.limit) ? 
                Math.max(1, Math.floor(params.limit)) : void 0;
            const activeMinutes = typeof params.activeMinutes === "number" && Number.isFinite(params.activeMinutes) ? 
                Math.max(1, Math.floor(params.activeMinutes)) : void 0;
            const messageLimitRaw = typeof params.messageLimit === "number" && Number.isFinite(params.messageLimit) ? 
                Math.max(0, Math.floor(params.messageLimit)) : 0;
            const messageLimit = Math.min(messageLimitRaw, 20);  // 最大 20 条
            
            // 5. 调用 Gateway 获取会话列表
            const gatewayCall = opts?.callGateway ?? callGateway;
            const list = await gatewayCall({
                method: "sessions.list",
                params: {
                    limit,
                    activeMinutes,
                    includeGlobal: !restrictToSpawned,
                    includeUnknown: !restrictToSpawned,
                    spawnedBy: restrictToSpawned ? effectiveRequesterKey : void 0
                }
            });
            
            const sessions = Array.isArray(list?.sessions) ? list.sessions : [];
            const storePath = typeof list?.path === "string" ? list.path : void 0;
            
            // 6. 创建可见性检查器
            const visibilityGuard = await createSessionVisibilityGuard({
                action: "list",
                requesterSessionKey: effectiveRequesterKey,
                visibility,
                a2aPolicy: createAgentToAgentPolicy(cfg)
            });
            
            const rows = [];
            const historyTargets = [];
            
            // 7. 处理每个会话
            for (const entry of sessions) {
                if (!entry || typeof entry !== "object") continue;
                const key = typeof entry.key === "string" ? entry.key : "";
                if (!key) continue;
                
                // 可见性检查
                if (!visibilityGuard.check(key).allowed) continue;
                if (key === "unknown") continue;
                if (key === "global" && alias !== "global") continue;
                
                // 分类会话类型
                const kind = classifySessionKind({
                    key,
                    gatewayKind: typeof entry.kind === "string" ? entry.kind : void 0,
                    alias,
                    mainKey
                });
                
                // 类型过滤
                if (allowedKinds && !allowedKinds.has(kind)) continue;
                
                // 解析显示键
                const displayKey = resolveDisplaySessionKey({
                    key,
                    alias,
                    mainKey
                });
                
                // 8. 解析渠道和交付上下文
                const entryChannel = typeof entry.channel === "string" ? entry.channel : void 0;
                const deliveryContext = entry.deliveryContext && typeof entry.deliveryContext === "object" ? 
                    entry.deliveryContext : void 0;
                const deliveryChannel = typeof deliveryContext?.channel === "string" ? 
                    deliveryContext.channel : void 0;
                const deliveryTo = typeof deliveryContext?.to === "string" ? deliveryContext.to : void 0;
                const deliveryAccountId = typeof deliveryContext?.accountId === "string" ? 
                    deliveryContext.accountId : void 0;
                
                const lastChannel = deliveryChannel ?? (typeof entry.lastChannel === "string" ? entry.lastChannel : void 0);
                const lastAccountId = deliveryAccountId ?? (typeof entry.lastAccountId === "string" ? entry.lastAccountId : void 0);
                
                const derivedChannel = deriveChannel({
                    key,
                    kind,
                    channel: entryChannel,
                    lastChannel
                });
                
                // 9. 解析会话元数据
                const sessionId = typeof entry.sessionId === "string" ? entry.sessionId : void 0;
                const sessionFileRaw = entry.sessionFile;
                const sessionFile = typeof sessionFileRaw === "string" ? sessionFileRaw : void 0;
                
                let transcriptPath;
                if (sessionId) {
                    try {
                        const agentId = resolveAgentIdFromSessionKey(key);
                        const trimmedStorePath = storePath?.trim();
                        let effectiveStorePath;
                        
                        if (trimmedStorePath && trimmedStorePath !== "(multiple)") {
                            if (trimmedStorePath.includes("{agentId}") || trimmedStorePath.startsWith("~")) {
                                effectiveStorePath = resolveStorePath(trimmedStorePath, { agentId });
                            } else if (path.isAbsolute(trimmedStorePath)) {
                                effectiveStorePath = trimmedStorePath;
                            }
                        }
                        
                        const filePathOpts = resolveSessionFilePathOptions({
                            agentId,
                            storePath: effectiveStorePath
                        });
                        transcriptPath = resolveSessionFilePath(sessionId, sessionFile ? { sessionFile } : void 0, filePathOpts);
                    } catch {
                        transcriptPath = void 0;
                    }
                }
                
                // 10. 构建会话行
                const row = {
                    key: displayKey,
                    kind,
                    channel: derivedChannel,
                    label: typeof entry.label === "string" ? entry.label : void 0,
                    displayName: typeof entry.displayName === "string" ? entry.displayName : void 0,
                    deliveryContext: deliveryChannel || deliveryTo || deliveryAccountId ? {
                        channel: deliveryChannel,
                        to: deliveryTo,
                        accountId: deliveryAccountId
                    } : void 0,
                    updatedAt: typeof entry.updatedAt === "number" ? entry.updatedAt : void 0,
                    sessionId,
                    model: typeof entry.model === "string" ? entry.model : void 0,
                    contextTokens: typeof entry.contextTokens === "number" ? entry.contextTokens : void 0,
                    totalTokens: typeof entry.totalTokens === "number" ? entry.totalTokens : void 0,
                    estimatedCostUsd: typeof entry.estimatedCostUsd === "number" ? entry.estimatedCostUsd : void 0,
                    status: typeof entry.status === "string" ? entry.status : void 0,
                    startedAt: typeof entry.startedAt === "number" ? entry.startedAt : void 0,
                    endedAt: typeof entry.endedAt === "number" ? entry.endedAt : void 0,
                    runtimeMs: typeof entry.runtimeMs === "number" ? entry.runtimeMs : void 0,
                    childSessions: Array.isArray(entry.childSessions) ? 
                        entry.childSessions.filter((value) => typeof value === "string")
                            .map((value) => resolveDisplaySessionKey({ key: value, alias, mainKey })) : void 0,
                    thinkingLevel: typeof entry.thinkingLevel === "string" ? entry.thinkingLevel : void 0,
                    verboseLevel: typeof entry.verboseLevel === "string" ? entry.verboseLevel : void 0,
                    systemSent: typeof entry.systemSent === "boolean" ? entry.systemSent : void 0,
                    abortedLastRun: typeof entry.abortedLastRun === "boolean" ? entry.abortedLastRun : void 0,
                    sendPolicy: typeof entry.sendPolicy === "string" ? entry.sendPolicy : void 0,
                    lastChannel,
                    lastTo: deliveryTo ?? (typeof entry.lastTo === "string" ? entry.lastTo : void 0),
                    lastAccountId,
                    transcriptPath
                };
                
                // 11. 如果需要消息,添加到获取队列
                if (messageLimit > 0) {
                    const resolvedKey = resolveInternalSessionKey({
                        key,
                        alias,
                        mainKey
                    });
                    historyTargets.push({ row, resolvedKey });
                }
                
                rows.push(row);
            }
            
            // 12. 并发获取消息(如果需要)
            if (messageLimit > 0 && historyTargets.length > 0) {
                const maxConcurrent = Math.min(4, historyTargets.length);
                let index = 0;
                
                const worker = async () => {
                    while (true) {
                        const next = index;
                        index += 1;
                        if (next >= historyTargets.length) return;
                        
                        const target = historyTargets[next];
                        const history = await gatewayCall({
                            method: "chat.history",
                            params: {
                                sessionKey: target.resolvedKey,
                                limit: messageLimit
                            }
                        });
                        
                        const filtered = stripToolMessages(
                            Array.isArray(history?.messages) ? history.messages : []
                        );
                        target.row.messages = filtered.length > messageLimit ? 
                            filtered.slice(-messageLimit) : filtered;
                    }
                };
                
                await Promise.all(Array.from({ length: maxConcurrent }, () => worker()));
            }
            
            return jsonResult({
                count: rows.length,
                sessions: rows
            });
        }
    };
}

1.4 会话类型分类

javascript 复制代码
function classifySessionKind(params) {
    const { key, gatewayKind, alias, mainKey } = params;
    
    // 1. Gateway 已分类
    if (gatewayKind) return gatewayKind;
    
    // 2. 根据键分类
    if (key === "global") return "other";
    if (key === mainKey) return "main";
    if (key === alias) return "main";
    
    // 3. 根据前缀分类
    if (key.startsWith("cron:")) return "cron";
    if (key.startsWith("hook:")) return "hook";
    if (key.startsWith("node:")) return "node";
    if (key.startsWith("group:")) return "group";
    
    return "other";
}

1.5 可见性检查

javascript 复制代码
const visibilityGuard = await createSessionVisibilityGuard({
    action: "list",
    requesterSessionKey: effectiveRequesterKey,
    visibility,  // session_tools.visibility 配置
    a2aPolicy: createAgentToAgentPolicy(cfg)  // Agent-to-Agent 策略
});

// 检查会话是否可见
if (!visibilityGuard.check(key).allowed) continue;

1.6 执行流程图

复制代码
sessions_list 工具调用
    ↓
1. 解析沙盒上下文
   ├─ mainKey, alias
   ├─ requesterInternalKey
   └─ restrictToSpawned
    ↓
2. 解析会话可见性配置
    ↓
3. 解析类型过滤(kinds)
    ↓
4. 解析其他参数(limit/activeMinutes/messageLimit)
    ↓
5. 调用 Gateway 获取会话列表
    ↓
6. 创建可见性检查器
    ↓
7. 处理每个会话
   ├─ 可见性检查
   ├─ 类型分类
   ├─ 类型过滤
   ├─ 解析渠道信息
   └─ 解析元数据
    ↓
8. 构建会话行对象
    ↓
9. 如果需要消息,添加到获取队列
    ↓
10. 并发获取消息(最多 4 个并发)
    ↓
11. 返回结果

1.7 返回结果格式

json 复制代码
{
  "count": 5,
  "sessions": [
    {
      "key": "main",
      "kind": "main",
      "channel": "feishu",
      "label": "Main Session",
      "displayName": "主会话",
      "updatedAt": 1711716000000,
      "sessionId": "abc123",
      "model": "qwen3.5-plus",
      "contextTokens": 50000,
      "totalTokens": 100000,
      "estimatedCostUsd": 0.05,
      "status": "idle",
      "startedAt": 1711710000000,
      "runtimeMs": 6000000,
      "thinkingLevel": "high",
      "messages": [
        { "role": "user", "content": "Hello" },
        { "role": "assistant", "content": "Hi there!" }
      ]
    }
  ]
}

二、sessions_history 工具

2.1 工具概述

功能 :获取指定会话的历史消息
核心特性

  • 敏感内容脱敏(redact sensitive text)
  • 文本截断(最大 4000 字符)
  • 图片省略(只保留元数据)
  • 思考过程签名删除
  • 使用/成本信息删除
  • 80KB 硬性限制

2.2 Schema 定义

位置:第 108788 行

javascript 复制代码
const SessionsHistoryToolSchema = Type.Object({
    sessionKey: Type.String(),
    limit: Type.Optional(Type.Number({ minimum: 1 })),
    includeTools: Type.Optional(Type.Boolean())
});

// 硬性限制
const SESSIONS_HISTORY_MAX_BYTES = 80 * 1024;  // 80KB
const SESSIONS_HISTORY_TEXT_MAX_CHARS = 4000;   // 4000 字符

2.3 文本截断函数

位置:第 108798 行

javascript 复制代码
function truncateHistoryText(text) {
    // 1. 敏感内容脱敏
    const sanitized = redactSensitiveText(text);
    const redacted = sanitized !== text;
    
    // 2. 检查是否超过限制
    if (sanitized.length <= SESSIONS_HISTORY_TEXT_MAX_CHARS) {
        return {
            text: sanitized,
            truncated: false,
            redacted
        };
    }
    
    // 3. 截断并添加标记
    return {
        text: `${truncateUtf16Safe(sanitized, SESSIONS_HISTORY_TEXT_MAX_CHARS)}\n...(truncated)...`,
        truncated: true,
        redacted
    };
}

2.4 内容块清理函数

位置:第 108816 行

javascript 复制代码
function sanitizeHistoryContentBlock(block) {
    if (!block || typeof block !== "object") {
        return { block, truncated: false, redacted: false };
    }
    
    const entry = { ...block };
    let truncated = false;
    let redacted = false;
    const type = typeof entry.type === "string" ? entry.type : "";
    
    // 1. 文本内容
    if (typeof entry.text === "string") {
        const res = truncateHistoryText(entry.text);
        entry.text = res.text;
        truncated ||= res.truncated;
        redacted ||= res.redacted;
    }
    
    // 2. 思考过程
    if (type === "thinking") {
        if (typeof entry.thinking === "string") {
            const res = truncateHistoryText(entry.thinking);
            entry.thinking = res.text;
            truncated ||= res.truncated;
            redacted ||= res.redacted;
        }
        // 删除思考签名(安全考虑)
        if ("thinkingSignature" in entry) {
            delete entry.thinkingSignature;
            truncated = true;
        }
    }
    
    // 3. 部分 JSON(工具调用)
    if (typeof entry.partialJson === "string") {
        const res = truncateHistoryText(entry.partialJson);
        entry.partialJson = res.text;
        truncated ||= res.truncated;
        redacted ||= res.redacted;
    }
    
    // 4. 图片(省略数据,只保留元数据)
    if (type === "image") {
        const data = typeof entry.data === "string" ? entry.data : void 0;
        const bytes = data ? data.length : void 0;
        
        if ("data" in entry) {
            delete entry.data;  // 删除 Base64 数据
            truncated = true;
        }
        
        entry.omitted = true;  // 标记为已省略
        if (bytes !== void 0) entry.bytes = bytes;  // 保留大小信息
    }
    
    return { block: entry, truncated, redacted };
}

2.5 消息清理函数

位置:第 108879 行

javascript 复制代码
function sanitizeHistoryMessage(message) {
    if (!message || typeof message !== "object") {
        return { message, truncated: false, redacted: false };
    }
    
    const entry = { ...message };
    let truncated = false;
    let redacted = false;
    
    // 1. 删除敏感元数据
    if ("details" in entry) {
        delete entry.details;
        truncated = true;
    }
    if ("usage" in entry) {
        delete entry.usage;  // token 使用量
        truncated = true;
    }
    if ("cost" in entry) {
        delete entry.cost;  // 成本
        truncated = true;
    }
    
    // 2. 处理文本内容
    if (typeof entry.content === "string") {
        const res = truncateHistoryText(entry.content);
        entry.content = res.text;
        truncated ||= res.truncated;
        redacted ||= res.redacted;
    } else if (Array.isArray(entry.content)) {
        const updated = entry.content.map((block) => sanitizeHistoryContentBlock(block));
        entry.content = updated.map((item) => item.block);
        truncated ||= updated.some((item) => item.truncated);
        redacted ||= updated.some((item) => item.redacted);
    }
    
    // 3. 处理 text 字段
    if (typeof entry.text === "string") {
        const res = truncateHistoryText(entry.text);
        entry.text = res.text;
        truncated ||= res.truncated;
        redacted ||= res.redacted;
    }
    
    return { message: entry, truncated, redacted };
}

2.6 硬性限制函数

位置:第 108921 行

javascript 复制代码
function enforceSessionsHistoryHardCap(params) {
    // 1. 检查是否超过限制
    if (params.bytes <= params.maxBytes) {
        return {
            items: params.items,
            bytes: params.bytes,
            hardCapped: false
        };
    }
    
    // 2. 尝试只保留最后一条消息
    const last = params.items.at(-1);
    const lastOnly = last ? [last] : [];
    const lastBytes = jsonUtf8Bytes(lastOnly);
    
    if (lastBytes <= params.maxBytes) {
        return {
            items: lastOnly,
            bytes: lastBytes,
            hardCapped: true
        };
    }
    
    // 3. 如果最后一条也太大,返回占位符
    const placeholder = [{
        role: "assistant",
        content: "[sessions_history omitted: message too large]"
    }];
    
    return {
        items: placeholder,
        bytes: jsonUtf8Bytes(placeholder),
        hardCapped: true
    };
}

2.7 完整执行代码

位置:第 108941 行

javascript 复制代码
function createSessionsHistoryTool(opts) {
    return {
        label: "Session History",
        name: "sessions_history",
        description: "Fetch message history for a session.",
        parameters: SessionsHistoryToolSchema,
        execute: async (_toolCallId, args) => {
            const params = args;
            const gatewayCall = opts?.callGateway ?? callGateway;
            
            // 1. 解析 sessionKey(必填)
            const sessionKeyParam = readStringParam$1(params, "sessionKey", { required: true });
            const cfg = opts?.config ?? loadConfig();
            
            // 2. 解析沙盒上下文
            const { mainKey, alias, effectiveRequesterKey, restrictToSpawned } = resolveSandboxedSessionToolContext({
                cfg,
                agentSessionKey: opts?.agentSessionKey,
                sandboxed: opts?.sandboxed
            });
            
            // 3. 解析会话引用
            const resolvedSession = await resolveSessionReference({
                sessionKey: sessionKeyParam,
                alias,
                mainKey,
                requesterInternalKey: effectiveRequesterKey,
                restrictToSpawned
            });
            
            if (!resolvedSession.ok) {
                return jsonResult({
                    status: resolvedSession.status,
                    error: resolvedSession.error
                });
            }
            
            // 4. 检查可见性
            const visibleSession = await resolveVisibleSessionReference({
                resolvedSession,
                requesterSessionKey: effectiveRequesterKey,
                restrictToSpawned,
                visibilitySessionKey: sessionKeyParam
            });
            
            if (!visibleSession.ok) {
                return jsonResult({
                    status: visibleSession.status,
                    error: visibleSession.error
                });
            }
            
            const resolvedKey = visibleSession.key;
            const displayKey = visibleSession.displayKey;
            
            // 5. 创建可见性检查器
            const a2aPolicy = createAgentToAgentPolicy(cfg);
            const access = (await createSessionVisibilityGuard({
                action: "history",
                requesterSessionKey: effectiveRequesterKey,
                visibility: resolveEffectiveSessionToolsVisibility({
                    cfg,
                    sandboxed: opts?.sandboxed === true
                }),
                a2aPolicy
            })).check(resolvedKey);
            
            if (!access.allowed) {
                return jsonResult({
                    status: access.status,
                    error: access.error
                });
            }
            
            // 6. 解析参数
            const limit = typeof params.limit === "number" && Number.isFinite(params.limit) ? 
                Math.max(1, Math.floor(params.limit)) : void 0;
            const includeTools = Boolean(params.includeTools);
            
            // 7. 获取历史消息
            const result = await gatewayCall({
                method: "chat.history",
                params: {
                    sessionKey: resolvedKey,
                    limit
                }
            });
            
            const messages = Array.isArray(result?.messages) ? result.messages : [];
            
            // 8. 清理消息
            const sanitized = messages.map((msg) => sanitizeHistoryMessage(msg));
            const cleanedMessages = sanitized.map((item) => item.message);
            
            // 9. 应用硬性限制
            const totalBytes = jsonUtf8Bytes(cleanedMessages);
            const capped = enforceSessionsHistoryHardCap({
                items: cleanedMessages,
                bytes: totalBytes,
                maxBytes: SESSIONS_HISTORY_MAX_BYTES
            });
            
            return jsonResult({
                sessionKey: displayKey,
                messages: capped.items,
                hardCapped: capped.hardCapped,
                totalBytes: capped.bytes
            });
        }
    };
}

2.8 执行流程图

复制代码
sessions_history 工具调用
    ↓
1. 解析 sessionKey(必填)
    ↓
2. 解析沙盒上下文
    ↓
3. 解析会话引用
   ├─ 检查会话是否存在
   └─ 解析内部键
    ↓
4. 检查可见性
   ├─ 可见性配置
   ├─ A2A 策略
   └─ 访问检查
    ↓
5. 解析参数(limit/includeTools)
    ↓
6. 调用 Gateway 获取历史消息
    ↓
7. 清理消息
   ├─ 删除敏感元数据(usage/cost/details)
   ├─ 文本截断(4000 字符)
   ├─ 思考签名删除
   └─ 图片数据省略
    ↓
8. 应用硬性限制(80KB)
   ├─ 未超限 → 返回全部
   ├─ 超限 → 只保留最后一条
   └─ 最后一条也超限 → 返回占位符
    ↓
9. 返回结果

2.9 返回结果格式

正常

json 复制代码
{
  "sessionKey": "main",
  "messages": [
    {
      "role": "user",
      "content": "Hello",
      "timestamp": 1711716000000
    },
    {
      "role": "assistant",
      "content": "Hi there!",
      "timestamp": 1711716001000
    }
  ],
  "hardCapped": false,
  "totalBytes": 5000
}

被截断

json 复制代码
{
  "sessionKey": "main",
  "messages": [...],
  "hardCapped": true,
  "totalBytes": 81920
}

图片消息

json 复制代码
{
  "role": "user",
  "content": [{
    "type": "image",
    "omitted": true,
    "bytes": 1048576
  }],
  "timestamp": 1711716000000
}

三、关键机制对比

3.1 过滤能力

特性 sessions_list sessions_history
类型过滤 kinds 数组 不支持
活跃度过滤 activeMinutes 不支持
数量限制 limit limit
消息获取 messageLimit(最大 20) 全部消息

3.2 安全限制

限制类型 sessions_list sessions_history
可见性检查 visibilityGuard visibilityGuard
沙盒隔离 restrictToSpawned restrictToSpawned
内容脱敏 不需要 redactSensitiveText
硬性限制 80KB

3.3 并发处理

特性 sessions_list sessions_history
并发获取 最多 4 个并发 单次获取
并发目标 messageLimit > 0 的会话 不适用

四、使用示例

4.1 sessions_list 工具调用

用户列出最近 10 分钟活跃的主会话

大模型返回

json 复制代码
{
  "tool_call": {
    "name": "sessions_list",
    "arguments": { 
      "kinds": ["main"],
      "activeMinutes": 10,
      "limit": 10
    }
  }
}

执行结果

json 复制代码
{
  "count": 1,
  "sessions": [{
    "key": "main",
    "kind": "main",
    "channel": "feishu",
    "updatedAt": 1711716000000,
    "status": "idle"
  }]
}

4.2 sessions_history 工具调用

用户获取主会话的最后 20 条消息

大模型返回

json 复制代码
{
  "tool_call": {
    "name": "sessions_history",
    "arguments": { 
      "sessionKey": "main",
      "limit": 20
    }
  }
}

执行结果

json 复制代码
{
  "sessionKey": "main",
  "messages": [
    { "role": "user", "content": "Hello" },
    { "role": "assistant", "content": "Hi there!" }
  ],
  "hardCapped": false,
  "totalBytes": 5000
}
相关推荐
奔跑中的小象2 小时前
统信UOS + 天数AI卡部署SGLang服务手册
人工智能·uos·sglang·天数智芯
DevSecOps选型指南2 小时前
中国版Mythos,为何是悬镜安全灵脉CodeAI?
人工智能·安全
Shockang2 小时前
LangGraph 状态机实战
人工智能
DLYSB_2 小时前
存储运维实战:基于 Ceph Event 监听与 Python 适配器的分布式存储健康度物理声光响应架构
运维·ceph·python·报警灯
刹那芳华19922 小时前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作2 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门2 小时前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜2 小时前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟2 小时前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能
天国梦3 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能