免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


Claude Agent SDK实战:打造开源版DeepWiki

发布日期:2025-10-25 19:13:42 浏览次数: 1539
作者:闲话AI

微信搜一搜,关注“闲话AI”

推荐语

Claude Agent SDK实战:用开源方案打造企业级项目知识库,突破DeepWiki的局限。

核心内容:
1. Claude Agent SDK如何赋能AI助手开发
2. 开源版DeepWiki的设计目标与技术实现
3. 代码验证机制确保知识库准确性的关键方案

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

前一段时间,Anthropic发布了Claude Sonnet 4.5,日常使用中我明显感觉它编码的稳定性相较于4.0有了显著提升。

同时发布的还有全新的Claude Agent SDK。这个SDK其实就是将Claude Code底层强大的Agent能力抽象出来,可以为任何应用场景赋能AI。

Claude Code的强大我在前文《Coding之外:Claude Code如何充当我的工作助手》也有聊到,它内置18个工具,包括本地文件检索、命令执行、任务规划、架构分析等。再结合MCP、自定义指令、子代理、多模态支持等完整的生态系统,让它成为了一个不局限于编程领域的全能AI助手。

说白了,有了Claude Agent SDK,咱们就能复制Claude Code的能力,为自己的业务场景定制专属的AI Agent。

今天的文章就来聊聊我是如何用这个SDK打造一个开源版DeepWiki的。

claude-deep-wiki项目已开源:https://github.com/skindhu/claude-deep-wiki

AI辅助编程的最后一公里:项目知识库

我在前文《从Vibe到Spec:让AI编程更可控的结构化思考》中提到过,目前AI辅助编程的最佳实践是Spec Coding —— 通过结构化的需求文档、技术方案、任务拆分来驾驭AI,而不是纯粹的Vibe Coding。

但这里有个关键问题:需求质量

如果项目需求不够规范,后续无论AI能力多强,生成的代码质量都会大打折扣。这时候,我们就会想到,能否让AI能辅助完善需求?

当然可以,但前提是AI得先理解咱们需求的背景知识:这个功能模块原有的逻辑细节是什么?历史上是如何演进的?有哪些坑?

这就依赖于项目知识库。

我个人觉得目前做得最好的是Devin.ai的DeepWiki。你只需要把Github仓库链接中的github改成deepwiki,就能看到它自动生成的详细项目知识库,效果挺不错。官方还提供了MCP Server支持知识库问答。

但问题来了:

  1. 项目必须开源且托管在Github上:很多公司内部项目根本做不到
  2. 没有开源:你想自己部署都不行
  3. 开源版本效果一般:Github上有人实现了open-deepwiki,但效果和官方版差距不小

这让我萌生了一个想法:能不能用Claude Agent SDK自己打造一套好用的DeepWiki工具?

claude-deep-wiki:设计思路

有了想法就干。在动手之前,我先明确了几个核心目标和设计原则。

核心目标

我希望实现的效果是:

  • 分析任何代码仓库(不限于Github,私有仓库也能用)
  • 生成面向业务的知识库(不是技术API文档,而是产品经理也能看懂的功能描述)
  • 支持165+编程语言(受益于Tree-sitter库)
  • 防止AI编造(通过代码验证机制确保分析结果真实可靠)

设计理念:多Agent协作

如果让单个AI一口气分析完整个代码仓库,基本不可行,先不说上下文是否能容纳这么多内容,最终输出的结果大概率也不可控,可能遗漏重要模块,或编造一些不存在的功能。

更好的方式是:让不同的Agent各司其职,像一个专业团队那样协作。

我设计了三个专职Agent:

  1. 结构扫描Agent:负责扫描代码仓库、识别模块层次、依赖关系
  2. 语义分析Agent:负责深入理解代码的业务逻辑和功能价值
  3. 文档生成Agent:负责将分析结果转化为产品功能文档

这三个Agent按流水线方式工作,每个阶段的输出都是下一个阶段的输入。

有了这个多Agent架构,接下来的问题是:如何让这些Agent拥有稳定地代码分析能力? 刚刚也说了,我们不能一股脑把所有的代码全部塞给它。

核心技术:SDK内置MCP Server

Claude Agent SDK比较强大的地方,就是支持创建in-process MCP Server,不需要启动子进程,直接在同一个进程里运行。

这样,我就可以用@tool装饰器快速定义自己的工具集,然后通过create_sdk_mcp_server把它们打包成一个MCP Server,让Agent调用。

我定义了6个核心工具:

from claude_agent_sdk import tool, create_sdk_mcp_server

@tool(
    name="scan_repository_structure",
    description="扫描代码仓库结构,返回目录树、文件统计和语言分布信息"
)

asyncdef scan_repo_tool(args: Dict[str, Any]) -> Dict[str, Any]:
    """扫描仓库结构"""
    result = scan_repository_structure(
        repo_path=args["repo_path"],
        max_depth=args.get("max_depth"5)
    )
    return {"content": [{"type""text""text": json.dumps(result)}]}

@tool(name="extract_imports_and_exports", ...)
asyncdef extract_imports_tool(args): ...

@tool(name="analyze_code_block", ...)
asyncdef analyze_code_tool(args): ...

@tool(name="build_dependency_graph", ...)
asyncdef build_dependency_tool(args): ...

@tool(name="search_code_patterns", ...)
asyncdef search_patterns_tool(args): ...

@tool(name="validate_analysis_result", ...)
asyncdef validate_analysis_tool(args): ...

# 创建MCP Server
mcp_server = create_sdk_mcp_server(
    name="code-analysis-tools",
    tools=[
        scan_repo_tool,
        extract_imports_tool,
        analyze_code_tool,
        build_dependency_tool,
        search_patterns_tool,
        validate_analysis_tool
    ]
)

这6个工具分别负责:

  • scan_repository_structure:扫描目录结构,统计文件类型

  • extract_imports_and_exports:提取文件的导入导出关系(主要基于Tree-sitter AST解析)

  • analyze_code_block:深度分析代码片段,提取结构化信息(函数、类、导入导出等)

  • build_dependency_graph:构建模块依赖图,分析循环依赖

  • search_code_patterns:搜索特定代码模式(API路由、数据库模型等)

  • validate_analysis_result:验证AI分析结果是否准确(防止编造)

关键点在于:这些工具直接调用Tree-sitter解析AST,提取的都是真实代码结构,AI无法编造。

三阶段分析流程

有了工具集和多Agent架构,接下来就是具体的执行流程了。整个分析过程我分为三个阶段,每个阶段由对应的Agent负责,层层递进。

阶段1:结构扫描 - 搞清楚有什么

结构扫描Agent的任务很明确,就是搞清楚这个项目有哪些模块,它们之间的依赖关系是什么。

但这里有个关键设计:分三步走,提升可调试行,同时避免一次性塞爆上下文。

class StructureScannerAgent:
    async def scan_repository(self, repo_path: str):
        # 步骤1: 扫描结构,识别模块(1次工具调用)
        structure = await self._scan_and_identify_modules(repo_path)

        # 步骤2: 提取依赖关系(N次工具调用)
        dependencies = await self._analyze_file_dependencies(structure, repo_path)

        # 步骤3: 整合数据,精确分层(0次工具调用)
        final = await self._finalize_structure(structure, dependencies)

步骤1:扫描与识别

只调用1次scan_repository_structure工具,快速扫描目录结构。这一步Claude只看目录名和文件名,就能识别出模块:

  • src/services/chatService.ts → "聊天服务模块"
  • src/components/Button/ → "按钮组件"
  • src/utils/validator.ts → "验证工具"

同时我让Claude为每个模块选出5-10个关键文件,比如入口文件、管理类、核心业务逻辑文件等。

步骤2:依赖分析

针对步骤1选出的关键文件,逐个调用extract_imports_and_exports工具提取导入导出关系。这一步是纯事实提取,AI无法编造:

# chatService.ts的导入导出
{
  "imports": ["axios""./chatUtils""../config"],
  "exports": ["ChatService""sendMessage"],
  "language""typescript"
}

步骤3:综合分析

拿到了模块列表和依赖关系,最后一步是整合数据。Agent会让Claude分析:

  • 模块分层:被多个模块依赖的是core层,依赖core的是business层
  • 依赖关系图:谁依赖谁,有没有循环依赖
  • 文件映射:每个文件属于哪个模块

输出是一个完整的项目结构,包括模块清单、依赖图、分层信息。

为什么分三步?

说白了,就是为了准确性。如果让AI一次性扫描全部代码,它可能会遗漏关键信息。分步进行,每步任务明确,结果更可靠,过程中出问题的可调试性也更高。

阶段2:语义分析 - 理解做什么

结构扫描只是识别了“有哪些模块”,但还不知道“这些模块干什么”。语义分析Agent就是来回答这个问题的。

这个阶段有两个关键设计:两轮分析 + 智能分批

先不急着读每个文件,而是让Claude看模块的整体结构,理解业务价值:

prompt = f"""
你是资深架构师。请分析模块'{module_name}'的业务价值。

关键文件:
- src/services/chatService.ts
- src/utils/chatUtils.ts

请回答:
1. 这个模块的业务目的是什么?
2. 核心功能有哪些?
3. 和其他模块如何交互?

Claude会返回:

{
  "business_purpose""智能客服对话引擎,处理用户问答交互",
  "core_features": [
    "实时消息收发",
    "内容安全过滤",
    "多格式消息支持"
  ],
  "external_interactions": [
    "调用后端AI服务",
    "使用状态管理存储对话"
  ]
}

有了这个概览,第二轮分析就有了上下文。

第二轮:细节挖掘(批处理)

这里是整个项目最复杂的部分。一个模块可能有几十甚至上百个文件,全部塞给Claude会超过上下文限制。

我的解法是:智能分批 + 按关联度分组。

我设计了FileAnalysisBatchManager ,它会:

  1. 估算token消耗:按字符数 / 3来大致估算,咱们也不需要非常准确
  2. 按关联度分组:互相导入的文件尽量分到同一批
  3. 控制批次大小:每批不超过150K tokens,这样可以为200k上下文留一些安全边际
class FileAnalysisBatchManager:
    def create_file_batches(self, files):
        """按关联度智能分批"""
        # 1. 计算文件间的关联度(基于导入关系)
        cohesion_scores = self._calculate_cohesion(files)

        # 2. 贪心分批:优先将高关联度文件放同一批
        batches = []
        for file in sorted(files, key=lambda f: cohesion_scores[f], reverse=True):
            # 找能容纳这个文件的批次
            for batch in batches:
                if batch['tokens'] + file['tokens'] < 150000:
                    batch['files'].append(file)
                    break
            else:
                # 创建新批次
                batches.append({'files': [file], 'tokens': file['tokens']})

        return batches

为什么按关联度分组?

我这里的思考是,Claude分析代码时需要上下文。例如,如果把chatService.tschatUtils.ts分到不同批次,Claude就看不到它们的调用关系,分析质量会下降。

每个批次分析完后,Agent会合并结果:

# 批次1结果
{
"files_analysis": [
    {"file""chatService.ts""functions": [...]},
    {"file""chatUtils.ts""functions": [...]}
  ]
}

# 批次2结果
{
"files_analysis": [
    {"file""messageFilter.ts""functions": [...]}
  ]
}

# 智能合并
merged = {
"files_analysis": [...],  # 所有文件的分析
"cross_file_relationships": [...],  # 跨文件关系
"summary": {"total_functions"4:扫描与识别5"total_classes"12}
}

阶段3:文档生成 - 翻译成业务表述

前两个阶段已经把所有技术细节都分析清楚了,但这些内容对于产品经理或业务人员来说还是太技术化。

文档生成Agent主要做三件事:智能分组 → 生成PRD → 生成索引

步骤1:产品功能域分组

这一步比较有意思,Agent会让Claude扮演资深产品经理,将技术模块重新组织:

prompt = f"""
你是资深产品经理。请将以下技术模块按产品功能域分组:

技术模块:
- components: 通用UI组件
- pages: 各业务页面
- services: API服务调用
- stores: 状态管理
- assets: 静态资源

分组原则:
1. 按业务价值,不是技术架构
2. 每个功能域对应一个独立的产品能力
3. 基础模块可以被多个功能域复用
"""

这里我考虑的关键点是,最终文档的呈现结构应该是基于业务价值,而不是技术架构。

这就是为什么最终文档产品经理能看懂,因为它是用户视角组织的,而不是从代码结构组织的。

步骤2:生成PRD文档

对每个功能域,Agent会生成一份完整的PRD,包含4个标准章节:

第1章:功能域概述

  • 功能定位(这是干什么的)
  • 业务价值(能带来什么好处)
  • 核心能力列表(提供哪些能力)
  • 子域结构(如果功能域很大,如何进一步划分)

第2章:功能详细说明

  • 每个核心能力的详细描述
  • 使用场景举例
  • 业务流程图(用Mermaid绘制)
  • 业务规则和异常处理

第3章:跨功能交互

  • 对外交互(和其他功能域如何协作)

  • 数据依赖(依赖哪些外部数据或服务)

第4章:业务约束与限制

  • 性能约束、并发限制等

如果功能域包含的文件太多,还会分批生成再智能合并

async def _generate_prd_multi_batch(self, domain_info, modules_data):
    """大功能域分批生成"""
    # 批次1:生成完整框架 + 部分详细内容
    batch1 = await self._generate_first_batch(domain_info, modules_data[:10])

    # 批次2-N:只生成详细内容
    batch2 = await self._generate_continuation(domain_info, modules_data[10:20])

    # 智能合并:将批次2的内容插入批次1的"功能详细说明"章节
    merged = self._merge_prd_batches([batch1, batch2])

步骤3:质量验证

生成完文档后,Agent会自动检查质量:

def _validate_prd_quality(self, doc):
    """验证PRD质量"""
    issues = []

    # 检查是否包含技术术语(不应该有)
    tech_terms = ['function''class''API''parameter']
    for term in tech_terms:
        if term in doc:
            issues.append(f"包含技术术语: {term}")

    # 检查必要章节
    required = ['功能详细说明''业务流程']
    for section in required:
        if section notin doc:
            issues.append(f"缺少章节: {section}")

    return issues

如果发现问题,会输出警告,方便我们手动修正。

最终输出的PRD文档,就可以尽量保障是完全面向业务人员的,几乎没有技术术语。

防止AI编造的机制

三个阶段的流程看起来很完整,但有个关键问题:如何确保AI的分析是真实可靠的?

这应该是所有DeepWiki类工具都要面对的难题。

为此,我设计了两层防护:

第一层:结构验证

所有的函数名、类名、导入关系都是通过Tree-sitter从AST中提取的,这些是编译器级别的真实数据,AI无法编造。

@tool(name="validate_analysis_result")
asyncdef validate_analysis_tool(args):
    """验证AI分析结果"""
    analysis = args["analysis"]
    source_code = args["source_code"]

    # 1. 用Tree-sitter解析源代码,提取真实结构
    actual_functions = extract_functions_from_ast(source_code)
    actual_classes = extract_classes_from_ast(source_code)

    # 2. 检查AI声称的函数是否都存在
    claimed_functions = set(f["name"for f in analysis["functions"])
    fake_functions = claimed_functions - actual_functions

    if fake_functions:
        return {
            "is_valid"False,
            "errors": [f"编造的函数: {list(fake_functions)}"]
        }

    return {"is_valid"True}

第二层:交叉验证

在语义分析阶段,Agent会先让Claude分析代码,然后立即调用validate_analysis_result工具验证。如果发现编造,会要求重新分析。

# 分析代码
analysis = await self._analyze_code(file_content)

# 立即验证
validation = await self._validate_analysis(analysis, file_content)

if not validation["is_valid"]:
    # 重新分析或标记错误
    self._log(f"验证失败: {validation['errors']}")

有了这两层防护,我基本消除了AI编造的风险。实测下来,验证失败率不到5%,而且一旦发现问题立即重新分析,这样就能尽量保障最终输出的准确率。

Claude Agent SDK的设计哲学

说完了具体的实现,再聊聊这个过程中我对Claude Agent SDK的一些理解。

Claude Agent SDK的设计哲学,就是对开发者仅暴露出一个结构化的代理循环:收集上下文、执行操作、验证工作和重复。

其它复杂的细节,如工具调用的序列化和反序列化、多轮对话的状态管理、MCP协议的实现细节全部在SDK底层默默做好。而针对不同的工具调用,SDK还提供了多种权限模式,能帮助我们尽量控制代理的安全性。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询