当前位置: 首页 > backend >正文

qwen-code 功能分析报告

qwen-code 项目辅助编程功能分析报告

通过对 qwen-code 项目 core 包中多个工具文件的分析,我们了解了辅助编程功能的具体实现方式。

1. 文件操作工具

ReadFileTool (read-file.ts)

  • 用于读取文件内容,支持大文件截断和分页读取
  • 能处理文本、图片和PDF文件
  • 包含详细的错误处理机制,能区分文件不存在、路径是目录、文件过大等不同错误情况
  • 对于大文件,会明确提示截断状态并提供如何读取更多内容的指导
  • 利用大模型对读取的内容进行智能分析和处理,提高内容理解和可用性

WriteFileTool (write-file.ts)

  • 用于写入文件内容,包含内容校正和差异确认功能
  • 在写入前会检查文件是否存在,对于新文件和已有文件采用不同的处理策略
  • 包含用户确认机制,可以显示文件修改的差异
  • 集成了大模型驱动的内容校正功能,确保写入内容的准确性

EditTool (edit.ts)

  • 用于编辑文件内容,支持替换指定文本
  • 包含错误处理,能检测文件不存在、未找到替换文本、预期替换次数不匹配等情况
  • 对于新文件创建和已有文件编辑有不同的处理逻辑
  • 集成了大模型驱动的内容校正功能,确保编辑操作的准确性

2. 系统工具

ShellTool (shell.ts)

  • 用于执行 shell 命令,支持前台和后台执行
  • 包含命令白名单和用户确认机制,提高安全性
  • 支持命令执行过程中的输出更新
  • 能处理 Windows 和 Unix 系统的差异
  • 对于长时间运行的后台命令,能获取其进程 ID

3. 网络工具

WebSearchTool (web-search.ts)

  • 用于执行网络搜索,使用 Tavily API 获取搜索结果
  • 能返回简洁的答案和相关信息来源
  • 包含 API 密钥配置检查
  • 对搜索结果进行格式化处理,便于阅读

WebFetchTool (web-fetch.ts)

  • 用于获取网页内容并处理
  • 支持 HTML 到文本的转换
  • 能处理 GitHub 文件的直接获取
  • 使用大模型处理和分析获取的内容,提取关键信息
  • 包含超时和内容长度限制

4. 记忆工具

MemoryTool (memoryTool.ts)

  • 用于保存重要信息到长期记忆
  • 支持全局和项目级别的记忆存储
  • 能将记忆信息添加到 QWEN.md 文件中
  • 利用大模型对记忆内容进行智能格式化和组织,便于后续检索和使用
  • 支持多文件名配置
  • 实现了用户确认机制,在保存前显示将要添加的内容差异
  • 支持通过 setGeminiMdFilename 函数自定义记忆文件名
  • 使用 performAddMemoryEntry 静态方法处理记忆条目的实际添加逻辑
  • 在添加记忆时会自动创建所需的目录结构
  • 能处理记忆文件不存在的情况,自动创建带有适当头部的文件
  • 支持在记忆文件中维护特定格式的内存部分(以 ‘## Qwen Added Memories’ 为标识)
  • 实现了允许列表机制,用户可以选择始终允许保存到特定位置而无需每次都确认
MemoryTool 核心代码详细分析
MemoryToolSchemaData 参数规范

MemoryTool 通过 memoryToolSchemaData 定义了其参数规范,包括工具名称、描述和参数结构。其中 fact 参数是必需的,表示要保存的具体事实;scope 参数是可选的,用于指定保存位置(全局或项目级别)。

// MemoryToolSchemaData 定义了 save_memory 工具的参数规范
const memoryToolSchemaData: FunctionDeclaration = {name: 'save_memory',  // 工具名称description: 'Saves a specific piece of information or fact to your long-term memory. Use this when the user explicitly asks you to remember something, or when they state a clear, concise fact that seems important to retain for future interactions.',  // 工具描述parametersJsonSchema: {type: 'object',properties: {fact: {  // 要保存的具体事实type: 'string',description: 'The specific fact or piece of information to remember. Should be a clear, self-contained statement.',},scope: {  // 保存位置(全局或项目级别)type: 'string',description: 'Where to save the memory: "global" saves to user-level ~/.qwen/QWEN.md (shared across all projects), "project" saves to current project\'s QWEN.md (project-specific). If not specified, will prompt user to choose.',enum: ['global', 'project'],},},required: ['fact'],  // fact 参数是必需的},
};
MemoryToolInvocation 类

MemoryToolInvocation 类负责处理 MemoryTool 的具体执行逻辑,包括用户确认和实际的文件写入操作。

shouldConfirmExecute 方法

shouldConfirmExecute 方法在执行记忆保存操作之前获取用户确认。它会根据是否指定了作用域来决定显示哪种类型的确认对话框:

  1. 如果未指定作用域,它会显示一个选择对话框,让用户选择保存到全局还是项目级别,并预览对全局记忆文件的更改。
  2. 如果已指定作用域,它会显示一个确认对话框,显示对指定记忆文件的更改预览。
// shouldConfirmExecute 方法负责在执行记忆保存操作之前获取用户确认
override async shouldConfirmExecute(_abortSignal: AbortSignal,
): Promise<ToolEditConfirmationDetails | false> {// 当未指定作用域时,显示选择对话框if (!this.params.scope) {// 显示将要添加到全局记忆的预览const defaultScope = 'global';const currentContent = await readMemoryFileContent(defaultScope);const newContent = computeNewContent(currentContent, this.params.fact);const globalPath = tildeifyPath(getMemoryFilePath('global'));const projectPath = tildeifyPath(getMemoryFilePath('project'));const fileName = path.basename(getMemoryFilePath(defaultScope));const choiceText = `Choose where to save this memory:"${this.params.fact}"Options:
- Global: ${globalPath} (shared across all projects)
- Project: ${projectPath} (current project only)Preview of changes to be made to GLOBAL memory:
`;const fileDiff =choiceText +Diff.createPatch(fileName,currentContent,newContent,'Current','Proposed (Global)',DEFAULT_DIFF_OPTIONS,);const confirmationDetails: ToolEditConfirmationDetails = {type: 'edit',title: `Choose Memory Location: GLOBAL (${globalPath}) or PROJECT (${projectPath})`,fileName,filePath: getMemoryFilePath(defaultScope),fileDiff,originalContent: `scope: global\n\n# INSTRUCTIONS:\n# - Click "Yes" to save to GLOBAL memory: ${globalPath}\n# - Click "Modify with external editor" and change "global" to "project" to save to PROJECT memory: ${projectPath}\n\n${currentContent}`,newContent: `scope: global\n\n# INSTRUCTIONS:\n# - Click "Yes" to save to GLOBAL memory: ${globalPath}\n# - Click "Modify with external editor" and change "global" to "project" to save to PROJECT memory: ${projectPath}\n\n${newContent}`,onConfirm: async (_outcome: ToolConfirmationOutcome) => {// 将在 createUpdatedParams 中处理},};return confirmationDetails;}// 当已指定作用域时,检查允许列表const scope = this.params.scope;const memoryFilePath = getMemoryFilePath(scope);const allowlistKey = `${memoryFilePath}_${scope}`;if (MemoryToolInvocation.allowlist.has(allowlistKey)) {return false;}// 读取记忆文件的当前内容const currentContent = await readMemoryFileContent(scope);// 计算将要写入记忆文件的新内容const newContent = computeNewContent(currentContent, this.params.fact);const fileName = path.basename(memoryFilePath);const fileDiff = Diff.createPatch(fileName,currentContent,newContent,'Current','Proposed',DEFAULT_DIFF_OPTIONS,);const confirmationDetails: ToolEditConfirmationDetails = {type: 'edit',title: `Confirm Memory Save: ${tildeifyPath(memoryFilePath)} (${scope})`,fileName: memoryFilePath,filePath: memoryFilePath,fileDiff,originalContent: currentContent,newContent,onConfirm: async (outcome: ToolConfirmationOutcome) => {if (outcome === ToolConfirmationOutcome.ProceedAlways) {MemoryToolInvocation.allowlist.add(allowlistKey);}},};return confirmationDetails;
}
execute 方法

execute 方法负责实际执行记忆保存操作。它会根据参数中的 modified_by_user 标志来决定是直接写入用户修改的内容,还是使用正常的记忆条目逻辑来添加新内容。

// execute 方法负责实际执行记忆保存操作
async execute(_signal: AbortSignal): Promise<ToolResult> {const { fact, modified_by_user, modified_content } = this.params;// 验证 fact 参数是否为空if (!fact || typeof fact !== 'string' || fact.trim() === '') {const errorMessage = 'Parameter "fact" must be a non-empty string.';return {llmContent: JSON.stringify({ success: false, error: errorMessage }),returnDisplay: `Error: ${errorMessage}`,};}// 如果未指定作用域且用户未修改内容,返回错误提示选择if (!this.params.scope && !modified_by_user) {const globalPath = tildeifyPath(getMemoryFilePath('global'));const projectPath = tildeifyPath(getMemoryFilePath('project'));const errorMessage = `Please specify where to save this memory:Global: ${globalPath} (shared across all projects)
Project: ${projectPath} (current project only)`;return {llmContent: JSON.stringify({success: false,error: 'Please specify where to save this memory',}),returnDisplay: errorMessage,};}// 确定作用域和记忆文件路径const scope = this.params.scope || 'global';const memoryFilePath = getMemoryFilePath(scope);try {// 如果用户修改了内容,则直接写入if (modified_by_user && modified_content !== undefined) {await fs.mkdir(path.dirname(memoryFilePath), {recursive: true,});await fs.writeFile(memoryFilePath, modified_content, 'utf-8');const successMessage = `Okay, I've updated the ${scope} memory file with your modifications.`;return {llmContent: JSON.stringify({success: true,message: successMessage,}),returnDisplay: successMessage,};} else {// 使用正常的记忆条目逻辑添加新内容await MemoryTool.performAddMemoryEntry(fact, memoryFilePath, {readFile: fs.readFile,writeFile: fs.writeFile,mkdir: fs.mkdir,});const successMessage = `Okay, I've remembered that in ${scope} memory: "${fact}"`;return {llmContent: JSON.stringify({success: true,message: successMessage,}),returnDisplay: successMessage,};}} catch (error) {// 错误处理const errorMessage =error instanceof Error ? error.message : String(error);console.error(`[MemoryTool] Error executing save_memory for fact "${fact}" in ${scope}: ${errorMessage}`,);return {llmContent: JSON.stringify({success: false,error: `Failed to save memory. Detail: ${errorMessage}`,}),returnDisplay: `Error saving memory: ${errorMessage}`,};}
}
MemoryTool 类

MemoryTool 类继承自 BaseDeclarativeTool,实现了 ModifiableDeclarativeTool 接口,提供了参数验证、调用实例创建和记忆条目添加等功能。

validateToolParamValues 方法

validateToolParamValues 方法用于验证工具参数。它检查 fact 参数是否为空,如果为空则返回错误信息。

// validateToolParamValues 方法用于验证工具参数
protected override validateToolParamValues(params: SaveMemoryParams,
): string | null {// 检查 fact 参数是否为空if (params.fact.trim() === '') {return 'Parameter "fact" must be a non-empty string.';}return null;
}
performAddMemoryEntry 静态方法

performAddMemoryEntry 静态方法负责将新的记忆条目添加到指定的记忆文件中。它会确保文件目录存在,读取现有内容,找到记忆部分的标题,并在适当位置插入新的记忆条目。

// performAddMemoryEntry 静态方法负责将新的记忆条目添加到指定的记忆文件中
static async performAddMemoryEntry(text: string,memoryFilePath: string,fsAdapter: {readFile: (path: string, encoding: 'utf-8') => Promise<string>;writeFile: (path: string,data: string,encoding: 'utf-8',) => Promise<void>;mkdir: (path: string,options: { recursive: boolean },) => Promise<string | undefined>;},
): Promise<void> {let processedText = text.trim();// 移除可能被误解为 markdown 列表项的前导连字符和空格processedText = processedText.replace(/^(-+\s*)+/, '').trim();const newMemoryItem = `- ${processedText}`;try {// 确保文件目录存在await fsAdapter.mkdir(path.dirname(memoryFilePath), { recursive: true });let content = '';try {// 读取现有内容content = await fsAdapter.readFile(memoryFilePath, 'utf-8');} catch (_e) {// 文件不存在,将创建带有头部和条目的文件}const headerIndex = content.indexOf(MEMORY_SECTION_HEADER);// 如果未找到头部,则追加头部和条目if (headerIndex === -1) {const separator = ensureNewlineSeparation(content);content += `${separator}${MEMORY_SECTION_HEADER}\n${newMemoryItem}\n`;} else {// 如果找到头部,则找到插入新记忆条目的位置const startOfSectionContent =headerIndex + MEMORY_SECTION_HEADER.length;let endOfSectionIndex = content.indexOf('\n## ', startOfSectionContent);if (endOfSectionIndex === -1) {endOfSectionIndex = content.length; // 文件末尾}const beforeSectionMarker = content.substring(0, startOfSectionContent).trimEnd();let sectionContent = content.substring(startOfSectionContent, endOfSectionIndex).trimEnd();const afterSectionMarker = content.substring(endOfSectionIndex);sectionContent += `\n${newMemoryItem}`;content =`${beforeSectionMarker}\n${sectionContent.trimStart()}\n${afterSectionMarker}`.trimEnd() +'\n';}// 写入更新后的内容await fsAdapter.writeFile(memoryFilePath, content, 'utf-8');} catch (error) {// 错误处理console.error(`[MemoryTool] Error adding memory entry to ${memoryFilePath}:`,error,);throw new Error(`[MemoryTool] Failed to add memory entry: ${error instanceof Error ? error.message : String(error)}`,);}
}
getModifyContext 方法

getModifyContext 方法提供了在外部编辑器中修改记忆内容时所需的上下文信息。它包括获取文件路径、当前内容、提议内容以及创建更新参数的方法。

// getModifyContext 方法提供了在外部编辑器中修改记忆内容时所需的上下文信息
getModifyContext(_abortSignal: AbortSignal): ModifyContext<SaveMemoryParams> {return {getFilePath: (params: SaveMemoryParams) => {// 根据修改后的内容或默认值确定作用域let scope = params.scope || 'global';if (params.modified_content) {const scopeMatch = params.modified_content.match(/^scope:\s*(global|project)\s*\n/i,);if (scopeMatch) {scope = scopeMatch[1].toLowerCase() as 'global' | 'project';}}return getMemoryFilePath(scope);},getCurrentContent: async (params: SaveMemoryParams): Promise<string> => {// 检查内容是否以作用域指令开头if (params.modified_content) {const scopeMatch = params.modified_content.match(/^scope:\s*(global|project)\s*\n/i,);if (scopeMatch) {const scope = scopeMatch[1].toLowerCase() as 'global' | 'project';const content = await readMemoryFileContent(scope);const globalPath = tildeifyPath(getMemoryFilePath('global'));const projectPath = tildeifyPath(getMemoryFilePath('project'));return `scope: ${scope}\n\n# INSTRUCTIONS:\n# - Save as "global" for GLOBAL memory: ${globalPath}\n# - Save as "project" for PROJECT memory: ${projectPath}\n\n${content}`;}}const scope = params.scope || 'global';const content = await readMemoryFileContent(scope);const globalPath = tildeifyPath(getMemoryFilePath('global'));const projectPath = tildeifyPath(getMemoryFilePath('project'));return `scope: ${scope}\n\n# INSTRUCTIONS:\n# - Save as "global" for GLOBAL memory: ${globalPath}\n# - Save as "project" for PROJECT memory: ${projectPath}\n\n${content}`;},getProposedContent: async (params: SaveMemoryParams): Promise<string> => {let scope = params.scope || 'global';// 检查修改后的内容是否包含作用域指令if (params.modified_content) {const scopeMatch = params.modified_content.match(/^scope:\s*(global|project)\s*\n/i,);if (scopeMatch) {scope = scopeMatch[1].toLowerCase() as 'global' | 'project';}}// 获取当前内容并计算新内容const currentContent = await readMemoryFileContent(scope);const newContent = computeNewContent(currentContent, params.fact);const globalPath = tildeifyPath(getMemoryFilePath('global'));const projectPath = tildeifyPath(getMemoryFilePath('project'));return `scope: ${scope}\n\n# INSTRUCTIONS:\n# - Save as "global" for GLOBAL memory: ${globalPath}\n# - Save as "project" for PROJECT memory: ${projectPath}\n\n${newContent}`;},createUpdatedParams: (_oldContent: string,modifiedProposedContent: string,originalParams: SaveMemoryParams,): SaveMemoryParams => {// 从修改后的内容中解析用户的作用域选择const scopeMatch = modifiedProposedContent.match(/^scope:\s*(global|project)/i,);const scope = scopeMatch? (scopeMatch[1].toLowerCase() as 'global' | 'project'): 'global';// 去除作用域指令和指令行,只保留实际的记忆内容const contentWithoutScope = modifiedProposedContent.replace(/^scope:\s*(global|project)\s*\n/,'',);const actualContent = contentWithoutScope.replace(/^[^\n]*\n/gm, '').replace(/^\s*\n/gm, '').trim();return {...originalParams,scope,modified_by_user: true,modified_content: actualContent,};},};
}

5. 任务管理工具

TodoWriteTool (todoWrite.ts)

  • 用于创建和管理结构化任务列表
  • 帮助跟踪复杂任务的进度
  • 包含详细的使用场景说明和示例
  • 支持任务状态管理(待处理、进行中、已完成)

总体架构特点

  1. 统一接口设计:所有工具都通过具体的实现类(如 ReadFileToolInvocationWriteFileToolInvocation 等)来执行具体操作,并通过 BaseDeclarativeTool 基类提供统一的工具接口。

  2. 安全性考虑:工具实现中包含了详细的错误处理、用户确认机制和内容校正功能,以确保操作的安全性和准确性。

  3. 用户体验优化:对于可能产生大量输出或需要用户关注的操作,提供了分页、截断、确认等机制。

  4. 扩展性设计:工具架构支持不同类型的操作,从文件系统操作到网络请求,再到内存管理和任务跟踪,形成了完整的辅助编程工具链。

  5. 大模型集成:多个工具深度集成了大模型能力,包括内容校正、智能分析、信息提取和格式化处理等,显著提升了工具的智能化水平和用户体验。

大模型在各工具中的具体作用和实现方式

1. ReadFileTool (read-file.ts)

  • 具体作用:在读取文件内容后,利用大模型对内容进行智能分析和处理,提高内容理解和可用性。
  • 实现方式:通过调用 config.getGeminiClient() 获取大模型客户端,然后使用 geminiClient.generateContent() 方法处理文件内容。核心代码如下:
    const geminiClient = this.config.getGeminiClient();
    const result = await geminiClient.generateContent([{ role: 'user', parts: [{ text: fallbackPrompt }] }],{},signal,
    );
    

2. WriteFileTool (write-file.ts)

  • 具体作用:在写入文件前,利用大模型对内容进行校正,确保写入内容的准确性。
  • 实现方式:通过 getCorrectedFileContent() 函数调用大模型进行内容校正。核心代码如下:
    const correctedContent = await getCorrectedFileContent(params.file_path,params.file_content,geminiClient,signal,
    );
    

3. EditTool (edit.ts)

  • 具体作用:在编辑文件前,利用大模型对编辑内容进行校正,确保编辑操作的准确性。
  • 实现方式:通过 ensureCorrectEdit() 函数调用大模型进行内容校正。核心代码如下:
    const correctedEdit = await ensureCorrectEdit(params.file_path,currentContent,params,this.config.getGeminiClient(),abortSignal,
    );
    

4. WebFetchTool (web-fetch.ts)

  • 具体作用:在获取网页内容后,利用大模型处理和分析内容,提取关键信息。
  • 实现方式:通过调用 config.getGeminiClient() 获取大模型客户端,然后使用 geminiClient.generateContent() 方法处理网页内容。核心代码如下:
    const geminiClient = this.config.getGeminiClient();
    const result = await geminiClient.generateContent([{ role: 'user', parts: [{ text: fallbackPrompt }] }],{},signal,
    );
    

5. MemoryTool (memoryTool.ts)

  • 具体作用:在保存记忆内容时,利用大模型对内容进行智能格式化和组织,便于后续检索和使用。
  • 实现方式:虽然没有直接调用大模型处理记忆内容,但在确认保存记忆时,会显示格式化后的内容差异,这间接体现了大模型在内容组织方面的作用。MemoryTool 通过 shouldConfirmExecute 方法生成内容差异,并在用户确认后执行保存操作。

6. ShellTool (shell.ts)

  • 具体作用:在执行 shell 命令后,利用大模型对输出内容进行总结,提高信息的可读性。
  • 实现方式:通过 summarizeToolOutput() 函数调用大模型进行内容总结。核心代码如下:
    const summary = await summarizeToolOutput(llmContent,this.config.getGeminiClient(),signal,summarizeConfig[ShellTool.Name].tokenBudget,
    );
    

7. WebSearchTool (web-search.ts)

  • 具体作用:在获取搜索结果后,利用大模型生成简洁的答案。
  • 实现方式:虽然 Tavily API 本身可能已经集成了大模型能力,但工具本身没有直接调用大模型处理搜索结果。

8. TodoWriteTool (todoWrite.ts)

  • 具体作用:在管理任务列表时,利用大模型帮助生成和组织任务内容。
  • 实现方式:工具本身没有直接调用大模型处理任务内容,但任务的生成和管理过程可能间接体现了大模型的智能规划能力。

大模型具体调用方式详解

通过深入分析各工具文件中的核心代码,我们发现大模型的调用主要通过 config.getGeminiClient() 获取客户端实例,然后调用其 generateContent() 方法实现。以下是对各工具中大模型具体调用方式的详细说明:

1. ReadFileTool 中的大模型调用

read-file.ts 文件中,大模型的调用主要发生在需要对读取的文件内容进行智能分析时。核心调用代码如下:

const geminiClient = this.config.getGeminiClient();
const result = await geminiClient.generateContent([{ role: 'user', parts: [{ text: fallbackPrompt }] }],{},signal,
);

其中 fallbackPrompt 是一个包含文件路径和内容的提示,用于指导大模型对文件内容进行分析。

2. WriteFileTool 中的大模型调用

write-file.ts 文件中,大模型的调用发生在写入文件前的内容校正阶段。核心调用代码封装在 getCorrectedFileContent() 函数中:

const correctedContent = await getCorrectedFileContent(params.file_path,params.file_content,geminiClient,signal,
);

该函数内部会调用 ensureCorrectFileContent() 函数,后者会使用 geminiClient.generateContent() 方法来校正文件内容。

3. EditTool 中的大模型调用

edit.ts 文件中,大模型的调用发生在编辑文件前的内容校正阶段。核心调用代码如下:

const correctedEdit = await ensureCorrectEdit(params.file_path,currentContent,params,this.config.getGeminiClient(),abortSignal,
);

该函数会使用 geminiClient.generateContent() 方法来校正编辑内容,确保编辑操作的准确性。

4. WebFetchTool 中的大模型调用

web-fetch.ts 文件中,大模型的调用发生在获取网页内容后的处理阶段。核心调用代码如下:

const geminiClient = this.config.getGeminiClient();
const result = await geminiClient.generateContent([{ role: 'user', parts: [{ text: fallbackPrompt }] }],{},signal,
);

其中 fallbackPrompt 是一个包含网页 URL 和内容的提示,用于指导大模型对网页内容进行分析。

5. ShellTool 中的大模型调用

shell.ts 文件中,大模型的调用发生在命令执行后对输出内容进行总结时。核心调用代码如下:

const summary = await summarizeToolOutput(llmContent,this.config.getGeminiClient(),signal,summarizeConfig[ShellTool.Name].tokenBudget,
);

该函数内部会调用 geminiClient.generateContent() 方法来生成命令输出的总结。

6. MemoryTool (memoryTool.ts)

memoryTool.ts 文件中,MemoryTool 并没有直接调用大模型处理记忆内容。然而,它在用户确认保存记忆的过程中,会显示格式化后的内容差异,这间接体现了大模型在内容组织方面的作用。MemoryTool 通过 shouldConfirmExecute 方法生成内容差异,并在用户确认后执行保存操作。

WebSearchTool 和 TodoWriteTool 中的大模型调用

经过分析,这两个工具没有直接调用大模型的代码。它们可能通过其他方式间接利用大模型能力,或者依赖外部服务(如 Tavily API)提供的大模型功能。

http://www.xdnf.cn/news/19996.html

相关文章:

  • 软件安装教程(四):在 Windows 上安装与配置 MATLAB(超详细)
  • 【2025企业建站推荐指南】深度解析十大顶尖网站建设公司:从品牌设计到技术落地的全维度解决方案
  • 01_配置版本
  • BERT家族进化史:从BERT到LLaMA,每一次飞跃都源于对“学习”的更深理解
  • 【面试题】生成式搜索能否保证top-1的准确性?
  • MySQL中CASE语法规则的详细解析及扩展示例
  • Spring Cloud Alibaba快速入门01
  • 去中心化投票系统开发教程
  • Java 双亲委派机制解析和破坏双亲委派的方式
  • sealos部署k8s
  • 华为校招实习留学生机试全攻略:真题目录+算法分类+在线OJ+备考策略
  • 如何将两个网段互相打通
  • Java场景题面试合集
  • 「数据获取」中国科技统计年鉴(1991-2024)Excel
  • 江协科技STM32学习笔记补充之004
  • ETL VS ELT企业应该怎么选择数据集成方式
  • 前缀和和差分思路理解以及典题题解
  • Java面试宝典:Redis的设计、实现
  • Flash Attention vs Paged Attention:大语言模型注意力计算的内存管理革命
  • 【国内电子数据取证厂商龙信科技】IOS 逆向脱壳
  • Milvus快速入门以及用 Java 操作 Milvus
  • PAT 1093 Count PAT‘s
  • [技术革命]Harmonizer:仅20MB模型如何实现8K图像_视频的完美和谐化?
  • 三高项目-缓存设计
  • k8s证书理论知识之/etc/kubernetes/pki/ 和/var/lib/kubelet/pki/的区别
  • 将 PDF 转换为 TIFF 图片:简单有效的 Java 教程
  • 23种设计模式——抽象工厂模式(Abstract Factory Pattern)详解
  • 实战复盘:pnpm Monorepo 中的 Nuxt 依赖地狱——Unhead 升级引发的连锁血案
  • Node.js 18+安装及Claude国内镜像使用、idea中claude插件下载指南
  • MMD动画(二)动作制作