第12章 多Agent协作——从单体到集群

第12章 多Agent协作------从单体到集群

引言

在传统的编程范式中,我们习惯于思考"如何让一个程序完成一个任务"。但在 Claude Code 的世界里,思考方式发生了根本性的转变:如何让多个智能体协同完成复杂任务。这不仅仅是数量的增加,而是质的飞跃------就像从独奏到交响乐团的转变。

本章将深入探讨 Claude Code 的多 Agent 协作机制,揭示如何通过精心设计的架构,让多个智能体像乐团成员一样各司其职、默契配合,共同演奏出复杂的代码交响曲。

概念讲解

Agent 即工具:统一的设计哲学

在 Claude Code 中,Agent 和工具之间没有本质的区别。一个 Agent 可以被另一个 Agent 调用,就像调用一个 Bash 工具或文件编辑工具一样自然。这种"Agent 即工具"的设计理念,打破了传统编程中函数调用和进程调用的界限,实现了真正的统一抽象。

这种设计的核心优势在于:

  1. 递归组合:Agent 可以调用 Agent,形成任意深度的调用链
  2. 透明交互:调用者无需关心被调用者是本地工具还是远程 Agent
  3. 资源隔离:每个 Agent 都有独立的上下文和权限边界
  4. 并行执行:多个 Agent 可以同时工作,互不干扰

任务系统:状态机与生命周期

Claude Code 的任务系统是整个多 Agent 协作的基石。每个 Agent 的执行都被封装为一个 Task,Task 有明确的类型和状态,形成了一个完整的状态机。

任务类型分为 7 种:

  • local_bash:本地 Shell 命令执行
  • local_agent:本地 Agent 执行
  • remote_agent:远程 Agent 执行
  • in_process_teammate:进程内队友
  • local_workflow:本地工作流
  • monitor_mcp:MCP 监控
  • dream:梦境任务(特殊用途)

任务状态有 5 种:

  • pending:等待执行
  • running:正在执行
  • completed:执行完成
  • failed:执行失败
  • killed:被终止

递归深度控制

为了避免无限递归和资源耗尽,Claude Code 实现了递归深度控制机制。每个 Agent 调用链都有深度限制,超过限制时会自动终止,确保系统稳定性。

源码分析

1. 任务类型定义

让我们从 src/Task.ts 开始,看看任务类型和状态是如何定义的:

typescript 复制代码
export type TaskType =
  | 'local_bash'
  | 'local_agent'
  | 'remote_agent'
  | 'in_process_teammate'
  | 'local_workflow'
  | 'monitor_mcp'
  | 'dream'

export type TaskStatus =
  | 'pending'
  | 'running'
  | 'completed'
  | 'failed'
  | 'killed'

这 7 种任务类型覆盖了 Claude Code 中所有可能的执行场景。从最简单的本地命令执行到复杂的远程 Agent 调用,每种类型都有其特定的用途和实现。

2. 终止状态守卫函数

一个关键的设计是 isTerminalTaskStatus() 函数:

typescript 复制代码
/**
 * True when a task is in a terminal state and will not transition further.
 * Used to guard against injecting messages into dead teammates, evicting
 * finished tasks from AppState, and orphan-cleanup paths.
 */
export function isTerminalTaskStatus(status: TaskStatus): boolean {
  return status === 'completed' || status === 'failed' || status === 'killed'
}

这个函数是一个典型的守卫函数(Guard Function),用于判断任务是否已经处于终止状态。它的作用包括:

  • 防止向已终止的队友发送消息
  • 从 AppState 中清理已完成的任务
  • 处理孤儿清理路径

这种设计体现了防御性编程的思想------在关键操作前先检查前置条件,避免错误状态下的操作。

3. 任务 ID 生成机制

任务 ID 的生成是一个精巧的设计,结合了类型前缀和随机字符:

typescript 复制代码
// Task ID prefixes
const TASK_ID_PREFIXES: Record<string, string> = {
  local_bash: 'b', // Keep as 'b' for backward compatibility
  local_agent: 'a',
  remote_agent: 'r',
  in_process_teammate: 't',
  local_workflow: 'w',
  monitor_mcp: 'm',
  dream: 'd',
}

// Get task ID prefix
function getTaskIdPrefix(type: TaskType): string {
  return TASK_ID_PREFIXES[type] ?? 'x'
}

// Case-insensitive-safe alphabet (digits + lowercase) for task IDs.
// 36^8 ≈ 2.8 trillion combinations, sufficient to resist brute-force symlink attacks.
const TASK_ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'

export function generateTaskId(type: TaskType): string {
  const prefix = getTaskIdPrefix(type)
  const bytes = randomBytes(8)
  let id = prefix
  for (let i = 0; i < 8; i++) {
    id += TASK_ID_ALPHABET[bytes[i]! % TASK_ID_ALPHABET.length]
  }
  return id
}

这个设计的精妙之处:

  1. 类型识别:通过前缀可以快速识别任务类型,便于调试和日志分析
  2. 安全考虑:使用 8 字节随机数,产生约 2.8 万亿种组合,足以抵抗暴力破解的符号链接攻击
  3. 大小写安全:使用数字和小写字母,避免大小写敏感带来的问题
  4. 向后兼容 :保留 local_bash 的 'b' 前缀,确保不破坏现有功能

4. 任务注册机制

src/tasks.ts 中,我们看到了任务注册的模式:

typescript 复制代码
import { feature } from 'bun:bundle'
import type { Task, TaskType } from './Task.js'
import { DreamTask } from './tasks/DreamTask/DreamTask.js'
import { LocalAgentTask } from './tasks/LocalAgentTask/LocalAgentTask.js'
import { LocalShellTask } from './tasks/LocalShellTask/LocalShellTask.js'
import { RemoteAgentTask } from './tasks/RemoteAgentTask/RemoteAgentTask.js'

/* eslint-disable @typescript-eslint/no-require-imports */
const LocalWorkflowTask: Task | null = feature('WORKFLOW_SCRIPTS')
  ? require('./tasks/LocalWorkflowTask/LocalWorkflowTask.js').LocalWorkflowTask
  : null
const MonitorMcpTask: Task | null = feature('MONITOR_TOOL')
  ? require('./tasks/MonitorMcpTask/MonitorMcpTask.js').MonitorMcpTask
  : null
/* eslint-enable @typescript-eslint/no-require-imports */

/**
 * Get all tasks.
 * Mirrors the pattern from tools.ts
 * Note: Returns array inline to avoid circular dependency issues with top-level const
 */
export function getAllTasks(): Task[] {
  const tasks: Task[] = [
    LocalShellTask,
    LocalAgentTask,
    RemoteAgentTask,
    DreamTask,
  ]
  if (LocalWorkflowTask) tasks.push(LocalWorkflowTask)
  if (MonitorMcpTask) tasks.push(MonitorMcpTask)
  return tasks
}

/**
 * Get a task by its type.
 */
export function getTaskByType(type: TaskType): Task | undefined {
  return getAllTasks().find(t => t.type === type)
}

这里有几个值得注意的设计:

  1. Feature Flags :使用 feature() 函数进行条件导入,实现死代码消除
  2. 懒加载 :通过 require() 动态导入,减少启动时的内存占用
  3. 避免循环依赖:使用函数返回数组而不是顶层常量,避免循环依赖问题
  4. 类型安全:使用 TypeScript 的类型系统确保任务类型的正确性

5. 工具注册与 Agent 工具

src/tools.ts 中,我们看到了工具注册的模式,特别是与 Agent 相关的工具:

typescript 复制代码
import { toolMatchesName, type Tool, type Tools } from './Tool.js'
import { AgentTool } from './tools/AgentTool/AgentTool.js'
import { SkillTool } from './tools/SkillTool/SkillTool.js'
// ... 其他工具导入

// Lazy require to break circular dependency: tools.ts -> TeamCreateTool/TeamDeleteTool -> ... -> tools.ts
/* eslint-disable @typescript-eslint/no-require-imports */
const getTeamCreateTool = () =>
  require('./tools/TeamCreateTool/TeamCreateTool.js')
    .TeamCreateTool as typeof import('./tools/TeamCreateTool/TeamCreateTool.js').TeamCreateTool
const getTeamDeleteTool = () =>
  require('./tools/TeamDeleteTool/TeamDeleteTool.js')
    .TeamDeleteTool as typeof import('./tools/TeamDeleteTool/TeamDeleteTool.js').TeamDeleteTool
const getSendMessageTool = () =>
  require('./tools/SendMessageTool/SendMessageTool.js')
    .SendMessageTool as typeof import('./tools/SendMessageTool/SendMessageTool.js').SendMessageTool
/* eslint-enable @typescript-eslint/no-require-imports */

这里的关键点:

  1. AgentTool:Agent 被封装为工具,可以被其他 Agent 调用
  2. TeamCreateTool:创建团队级并行工作
  3. SendMessageTool:实现 Agent 间通信
  4. 懒加载函数:使用函数返回工具而不是直接导入,打破循环依赖

6. 上下文缓存机制

src/context.ts 中,我们看到了上下文收集的缓存机制:

typescript 复制代码
import memoize from 'lodash-es/memoize.js'

export const getGitStatus = memoize(async (): Promise<string | null> => {
  if (process.env.NODE_ENV === 'test') {
    // Avoid cycles in tests
    return null
  }

  const startTime = Date.now()
  logForDiagnosticsNoPII('info', 'git_status_started')

  const isGitStart = Date.now()
  const isGit = await getIsGit()
  logForDiagnosticsNoPII('info', 'git_is_git_check_completed', {
    duration_ms: Date.now() - isGitStart,
    is_git: isGit,
  })

  if (!isGit) {
    logForDiagnosticsNoPII('info', 'git_status_skipped_not_git', {
      duration_ms: Date.now() - startTime,
    })
    return null
  }

  try {
    const gitCmdsStart = Date.now()
    const [branch, mainBranch, status, log, userName] = await Promise.all([
      getBranch(),
      getDefaultBranch(),
      execFileNoThrow(gitExe(), ['--no-optional-locks', 'status', '--short'], {
        preserveOutputOnError: false,
      }).then(({ stdout }) => stdout.trim()),
      execFileNoThrow(
        gitExe(),
        ['--no-optional-locks', 'log', '--oneline', '-n', '5'],
        {
          preserveOutputOnError: false,
        },
      ).then(({ stdout }) => stdout.trim()),
      execFileNoThrow(gitExe(), ['config', 'user.name'], {
        preserveOutputOnError: false,
      }).then(({ stdout }) => stdout.trim()),
    ])

    logForDiagnosticsNoPII('info', 'git_commands_completed', {
      duration_ms: Date.now() - gitCmdsStart,
      status_length: status.length,
    })

    // Check if status exceeds character limit
    const truncatedStatus =
      status.length > MAX_STATUS_CHARS
        ? status.substring(0, MAX_STATUS_CHARS) +
          '\n... (truncated because it exceeds 2k characters. If you need more information, run "git status" using BashTool)'
        : status

    logForDiagnosticsNoPII('info', 'git_status_completed', {
      duration_ms: Date.now() - startTime,
      truncated: status.length > MAX_STATUS_CHARS,
    })

    return [
      `This is the git status at the start of the conversation. Note that this status is a snapshot in time, and will not update during the conversation.`,
      `Current branch: ${branch}`,
      `Main branch (you will usually use this for PRs): ${mainBranch}`,
      ...(userName ? [`Git user: ${userName}`] : []),
      `Status:\n${truncatedStatus || '(clean)'}`,
      `Recent commits:\n${log}`,
    ].join('\n\n')
  } catch (error) {
    logForDiagnosticsNoPII('error', 'git_status_failed', {
      duration_ms: Date.now() - startTime,
    })
    logError(error)
    return null
  }
})

/**
 * This context is prepended to each conversation, and cached for the duration of the conversation.
 */
export const getSystemContext = memoize(
  async (): Promise<{
    [k: string]: string
  }> => {
    const startTime = Date.now()
    logForDiagnosticsNoPII('info', 'system_context_started')

    // Skip git status in CCR (unnecessary overhead on resume) or when git instructions are disabled
    const gitStatus =
      isEnvTruthy(process.env.CLAUDE_CODE_REMOTE) ||
      !shouldIncludeGitInstructions()
        ? null
        : await getGitStatus()

    // Include system prompt injection if set (for cache breaking, ant-only)
    const injection = feature('BREAK_CACHE_COMMAND')
      ? getSystemPromptInjection()
      : null

    logForDiagnosticsNoPII('info', 'system_context_completed', {
      duration_ms: Date.now() - startTime,
      has_git_status: gitStatus !== null,
      has_injection: injection !== null,
    })

    return {
      ...(gitStatus && { gitStatus }),
      ...(feature('BREAK_CACHE_COMMAND') && injection
        ? {
            cacheBreaker: `[CACHE_BREAKER: ${injection}]`,
          }
        : {}),
    }
  },
)

/**
 * This context is prepended to each conversation, and cached for the duration of the conversation.
 */
export const getUserContext = memoize(
  async (): Promise<{
    [k: string]: string
  }> => {
    const startTime = Date.now()
    logForDiagnosticsNoPII('info', 'user_context_started')

    // CLAUDE_CODE_DISABLE_CLAUDE_MDS: hard off, always.
    // --bare: skip auto-discovery (cwd walk), BUT honor explicit --add-dir.
    // --bare means "skip what I didn't ask for", not "ignore what I asked for".
    const shouldDisableClaudeMd =
      isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS) ||
      (isBareMode() && getAdditionalDirectoriesForClaudeMd().length === 0)
    // Await the async I/O (readFile/readdir directory walk) so the event
    // loop yields naturally at the first fs.readFile.
    const claudeMd = shouldDisableClaudeMd
      ? null
      : getClaudeMds(filterInjectedMemoryFiles(await getMemoryFiles()))
    // Cache for the auto-mode classifier (yoloClassifier.ts reads this
    // instead of importing claudemd.ts directly, which would create a
    // cycle through permissions/filesystem → permissions → yoloClassifier).
    setCachedClaudeMdContent(claudeMd || null)

    logForDiagnosticsNoPII('info', 'user_context_completed', {
      duration_ms: Date.now() - startTime,
      claudemd_length: claudeMd?.length ?? 0,
      claudemd_disabled: Boolean(shouldDisableClaudeMd),
    })

    return {
      ...(claudeMd && { claudeMd }),
      currentDate: `Today's date is ${getLocalISODate()}.`,
    }
  },
)

这个设计的精妙之处:

  1. Memoize 缓存 :使用 lodash 的 memoize 函数缓存结果,避免重复计算
  2. 并行执行 :使用 Promise.all 并行执行多个 git 命令,提高效率
  3. 日志记录:详细的性能日志,便于诊断和优化
  4. 条件缓存:根据环境变量和配置决定是否缓存某些上下文
  5. 缓存破坏 :通过 cacheBreaker 机制支持强制刷新缓存

7. 初始化流程中的并行预取

src/setup.ts 中,我们看到了初始化流程中的并行预取策略:

typescript 复制代码
profileCheckpoint('setup_before_prefetch')
// Pre-fetch promises - only items needed before render
logForDiagnosticsNoPII('info', 'setup_prefetch_starting')
// When CLAUDE_CODE_SYNC_PLUGIN_INSTALL is set, skip all plugin prefetch.
// The sync install path in print.ts calls refreshPluginState() after
// installing, which reloads commands, hooks, and agents. Prefetching here
// races with the install (concurrent copyPluginToVersionedCache / cachePlugin
// on the same directories), and the hot-reload handler fires clearPluginCache()
// mid-install when policySettings arrives.
const skipPluginPrefetch =
  (getIsNonInteractiveSession() &&
    isEnvTruthy(process.env.CLAUDE_CODE_SYNC_PLUGIN_INSTALL)) ||
  // --bare: loadPluginHooks → loadAllPlugins is filesystem work that's
  // wasted when executeHooks early-returns under --bare anyway.
  isBareMode()
if (!skipPluginPrefetch) {
  void getCommands(getProjectRoot())
}
void import('./utils/plugins/loadPluginHooks.js').then(m => {
  if (!skipPluginPrefetch) {
    void m.loadPluginHooks() // Pre-load plugin hooks (consumed by processSessionStartHooks before render)
    m.setupPluginHookHotReload() // Set up hot reload for plugin hooks when settings change
  }
})

这里的关键点:

  1. 并行预取 :使用 void 关键字启动并行任务,不等待完成
  2. 条件跳过:根据环境变量和模式决定是否跳过某些预取
  3. 性能检查点 :使用 profileCheckpoint 标记关键时间点
  4. 热重载支持:预取时同时设置热重载机制

8. 查询引擎中的性能优化

src/QueryEngine.ts 中,我们看到了查询引擎的性能优化:

typescript 复制代码
import { feature } from 'bun:bundle'
import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
import { randomUUID } from 'crypto'
import last from 'lodash-es/last.js'
import {
  getSessionId,
  isSessionPersistenceDisabled,
} from 'src/bootstrap/state.js'
import type {
  PermissionMode,
  SDKCompactBoundaryMessage,
  SDKMessage,
  SDKPermissionDenial,
  SDKStatus,
  SDKUserMessageReplay,
} from 'src/entrypoints/agentSdkTypes.js'
import { accumulateUsage, updateUsage } from 'src/services/api/claude.js'
import type { NonNullableUsage } from 'src/services/api/logging.js'
import { EMPTY_USAGE } from 'src/services/api/logging.js'
import stripAnsi from 'strip-ansi'
import type { Command } from './commands.js'
import { getSlashCommandToolSkills } from './commands.js'
import {
  LOCAL_COMMAND_STDERR_TAG,
  LOCAL_COMMAND_STDOUT_TAG,
} from './constants/xml.js'
import {
  getModelUsage,
  getTotalAPIDuration,
  getTotalCost,
} from './cost-tracker.js'
import type { CanUseToolFn } from './hooks/useCanUseTool.js'
import { loadMemoryPrompt } from './memdir/memdir.js'
import { hasAutoMemPathOverride } from './memdir/paths.js'
import { query } from './query.js'
import { categorizeRetryableAPIError } from './services/api/errors.js'
import type { MCPServerConnection } from './services/mcp/types.js'
import type { AppState } from './state/AppState.js'
import { type Tools, type ToolUseContext, toolMatchesName } from './Tool.js'
import type { AgentDefinition } from './tools/AgentTool/loadAgentsDir.js'
import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js'
import type { Message } from './types/message.js'
import type { OrphanedPermission } from './types/textInputTypes.js'
import { createAbortController } from './utils/abortController.js'
import type { AttributionState } from './utils/commitAttribution.js'
import { getGlobalConfig } from './utils/config.js'
import { getCwd } from './utils/cwd.js'
import { isBareMode, isEnvTruthy } from './utils/envUtils.js'
import { getFastModeState } from './utils/fastMode.js'
import {
  type FileHistoryState,
  fileHistoryEnabled,
  fileHistoryMakeSnapshot,
} from './utils/fileHistory.js'
import {
  cloneFileStateCache,
  type FileStateCache,
} from './utils/fileStateCache.js'
import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
import { registerStructuredOutputEnforcement } from './utils/hooks/hookHelpers.js'
import { getInMemoryErrors } from './utils/log.js'
import { countToolCalls, SYNTHETIC_MESSAGES } from './utils/messages.js'
import {
  getMainLoopModel,
  parseUserSpecifiedModel,
} from './utils/model/model.js'
import { loadAllPluginsCacheOnly } from './utils/plugins/pluginLoader.js'
import {
  type ProcessUserInputContext,
  processUserInput,
} from './utils/processUserInput/processUserInput.js'
import { fetchSystemPromptParts } from './utils/queryContext.js'
import { setCwd } from './utils/Shell.js'
import {
  flushSessionStorage,
  recordTranscript,
} from './utils/sessionStorage.js'
import { asSystemPrompt } from './utils/systemPromptType.js'
import { resolveThemeSetting } from './utils/systemTheme.js'

这里的关键优化点:

  1. Feature Flags :使用 feature() 函数进行条件导入,实现死代码消除
  2. 类型导入:只导入类型,避免运行时开销
  3. 性能分析 :使用 headlessProfilerCheckpoint 进行性能检查点标记
  4. 文件状态缓存 :使用 FileStateCache 缓存文件状态,减少重复计算

设计启示

1. 统一抽象的力量

Claude Code 的核心设计哲学是"Agent 即工具"。这种统一抽象带来了巨大的优势:

  • 简单性:开发者只需理解一种抽象,不需要区分函数调用和进程调用
  • 可组合性:Agent 可以递归调用 Agent,形成任意复杂的协作模式
  • 可扩展性:新的 Agent 类型可以轻松添加,不影响现有代码

这种设计类似于 Unix 的"一切皆文件"哲学------通过统一的抽象,实现强大的组合能力。

2. 状态机的严谨性

任务系统使用严谨的状态机设计,每个状态转换都有明确的规则:

typescript 复制代码
export type TaskStatus =
  | 'pending'
  | 'running'
  | 'completed'
  | 'failed'
  | 'killed'

export function isTerminalTaskStatus(status: TaskStatus): boolean {
  return status === 'completed' || status === 'failed' || status === 'killed'
}

这种设计的优势:

  • 可预测性:状态转换规则明确,行为可预测
  • 可调试性:状态变化清晰可见,便于调试
  • 安全性:守卫函数防止错误操作

3. 缓存策略的艺术

Claude Code 使用了多层缓存策略:

  1. Memoize 缓存:函数级别的缓存
  2. 上下文缓存:会话级别的缓存
  3. 文件状态缓存:文件系统级别的缓存
  4. 性能分析缓存:诊断数据的缓存

这种分层缓存策略,确保了不同粒度的数据都有合适的缓存机制。

4. 并行执行的智慧

Claude Code 在多个层面使用了并行执行:

  1. 初始化并行预取:在启动时并行加载必要资源
  2. Git 命令并行 :使用 Promise.all 并行执行多个 git 命令
  3. Agent 并行执行:多个 Agent 可以同时工作

这种并行策略,充分利用了现代计算机的多核能力,显著提升了性能。

5. 防御性编程

Claude Code 代码中充满了防御性编程的实践:

  • 守卫函数isTerminalTaskStatus() 防止向已终止的任务发送消息
  • 错误处理:每个异步操作都有完善的错误处理
  • 边界检查:检查状态长度是否超过限制,进行截断处理
  • 环境检查:根据环境变量和配置调整行为

这种防御性编程的思想,确保了系统的健壮性和可靠性。

类比:交响乐团的协作

多 Agent 协作就像一个交响乐团:

  • 指挥:主 Agent 负责整体协调和调度
  • 乐器组:不同类型的 Agent 就像不同的乐器组,各司其职
  • 乐谱:任务定义和状态机就像乐谱,规定了演奏的规则
  • 节奏:并行执行和调度机制就像节奏控制,确保和谐
  • 和声:Agent 间的通信和协作就像和声,产生美妙的效果

每个 Agent 都是一个独立的"乐手",有自己的专长和职责。指挥(主 Agent)通过"乐谱"(任务定义)协调所有乐手,共同演奏出复杂的"交响曲"(完成复杂任务)。

思考题

  1. 设计一个多 Agent 系统:假设你要设计一个代码审查系统,需要多个 Agent 协作工作。你会如何划分 Agent 的职责?如何设计它们之间的通信机制?

  2. 状态机扩展 :如果要在现有的任务状态机中添加一个新的状态 paused(暂停),需要修改哪些代码?如何确保状态转换的正确性?

  3. 缓存策略优化:在什么情况下应该清除缓存?如何设计一个智能的缓存失效策略?

  4. 递归深度控制:如何实现递归深度控制?如果递归深度超过限制,应该如何处理?

  5. 性能权衡:并行执行可以提高性能,但也会增加复杂度。在实际项目中,如何平衡性能和可维护性?

小结

本章深入探讨了 Claude Code 的多 Agent 协作机制,从任务系统到工具注册,从上下文缓存到性能优化。我们看到了统一抽象的力量、状态机的严谨性、缓存策略的艺术、并行执行的智慧,以及防御性编程的重要性。

多 Agent 协作不仅仅是技术的实现,更是一种设计哲学的体现------通过精心设计的架构,让多个智能体协同工作,完成单个智能体无法完成的复杂任务。这种设计思想,不仅适用于 AI 系统,也适用于任何需要协同工作的软件系统。

在下一章中,我们将探讨性能优化的艺术,看看 Claude Code 如何通过毫秒级的优化,实现快速启动和流畅运行。

相关推荐
ZHW_AI课题组1 小时前
腾讯云驾车路线规划实现 —— 从 API 调用到代码解析的深度实践
人工智能·机器学习·信息可视化
数琨创享TQMS质量数智化1 小时前
2026 专业质量管理系统(QMS)推荐榜
人工智能·qms质量管理系统
暗夜猎手-大魔王1 小时前
hermes源码学习4-Prompt 组装
人工智能·prompt
五号厂房1 小时前
🔥 Claude Code 源码解析(四):揭秘状态管理与数据流机制
人工智能
SelectDB技术团队1 小时前
预约发布会|核心产品力首发,如何构建面向 Agent 时代的企业级数据引擎
数据库·数据仓库·人工智能·数据分析·可观测·apache doris·selectdb
qq3621967052 小时前
APK版本选择完全指南——beta/stable/arm64/x86/bundle/universal怎么选?
网络·人工智能
张飞飞飞飞飞2 小时前
多模态目标检测-LLVIP数据集处理(清洗+YOLO格式)
人工智能·深度学习·目标检测
大树882 小时前
一滴冷却液,烧掉2000万算力
大数据·运维·服务器·人工智能
醒醒该学习了!2 小时前
人工智能的核心算法基础(理论篇)
人工智能