您好,欢迎来到花生壳b2b外贸网信息发布平台!
18951535724
  • 如何将代码库转化为知识图谱

       2026-10-07 网络整理佚名1320
    核心提示:我们的仓库包含超过50万行代码,分布在API、微服务、事件消费者、定时任务、共享库和基础设施代码中。

    知识图谱构建

    六个月前,我们的AI编码助手遇到了一个问题。

    问它:

    "如果我修改支付工作流,哪些服务会受到影响?"

    它会自信地返回一个只有部分正确的答案。

    问题不在于LLM。

    问题在于上下文。

    我们的仓库包含超过50万行代码,分布在API、微服务、事件消费者、定时任务、共享库和基础设施代码中。

    传统的向量搜索可以找到相关文件。

    但它难以理解所有内容是如何连接的。

    所以我们将代码库从文档集合转变为知识图谱。

    结果是一个AI系统,可以回答架构问题、执行影响分析、识别隐藏依赖关系,并帮助工程师更准确地导航大型代码库。

    以下是我们构建它的方法。

    1、为什么AI在大型代码库中挣扎

    大多数AI编码工具严重依赖语义搜索。

    过程大致如下:

    用户问题
          ↓
    向量搜索
          ↓
    相关文件
          ↓
        LLM
          ↓
        答案
    

    这对于小型项目效果出奇地好。

    然而,大型企业系统是不同的。

    想象以下依赖链:

    UserService
        ↓
    BillingService
        ↓
    PaymentGateway
        ↓
    StripeAdapter
    

    现在问:

    如果StripeAdapter更改会破坏什么?

    向量搜索可能会检索:

    StripeAdapter.ts
    PaymentGateway.ts
    

    但它可能会完全错过:

    BillingService
    UserService
    OrderProcessing
    RefundWorkflow
    

    问题是向量搜索理解相似性。

    它不自然地理解关系。

    软件系统是由关系构建的。

    函数调用函数。

    类继承类。

    服务发布事件。

    消费者订阅事件。

    模块导入模块。

    没有这些关系,AI看到的是代码片段而不是架构。

    2、将代码视为图

    一旦我们退后一步,解决方案就变得显而易见。

    代码库自然是一个图。

    Function
        │
     calls
        
    Function
    Class
        │
    inherits
        
    Class
    Service
        │
    publishes
        
    Event
    Consumer
        │
    subscribes
        
    Event
    

    每个节点代表有意义的内容。

    示例:

    File
    Class
    Method
    Function
    Service
    Event
    Database Table
    API Endpoint
    Queue
    

    每条边代表一种关系。

    示例:

    CALLS
    IMPORTS
    INHERITS
    PUBLISHES
    SUBSCRIBES
    READS
    WRITES
    DEPENDS_ON
    

    一旦你以这种方式对仓库建模,回答架构问题就变得容易得多。

    3、从仓库中提取结构

    第一步是构建一个解析器。

    对于TypeScript服务,我们使用ts-morph遍历抽象语法树(AST)。

    import { Project } from "ts-morph";
    const project = new Project();
    project.addSourceFilesAtPaths("src*.ts");
    for (const file of project.getSourceFiles()) {
      const imports = file.getImportDeclarations();
      imports.forEach((imp) => {
        console.log({
          source: file.getBaseName(),
          target: imp.getModuleSpecifierValue(),
          relation: "IMPORTS"
        });
      });
    }
    

    这给了我们这样的关系:

    UserService
        IMPORTS
    BillingService
        IMPORTS
    PaymentGateway
    

    接下来,我们提取:

    目标不是索引代码。

    目标是映射关系。

    4、构建知识图谱

    提取关系后,我们将它们存储在Neo4j中。

    示例:

    CREATE
    (a:Service {name: "UserService"})
    -[:DEPENDS_ON]->
    (b:Service {name: "BillingService"})
    

    另一个示例:

    CREATE
    (a:Service {name: "BillingService"})
    -[:CALLS]->
    (b:Service {name: "PaymentGateway"})
    

    图很快开始增长。

    我们不再有数千个孤立的文件,而是拥有:

    20,000+ 节点
    85,000+ 关系
    

    这就是事情变得有趣的地方。

    5、影响分析变得简单

    以前,回答这个问题很痛苦:

    如果我修改PaymentGateway会破坏什么?

    工程师会手动检查:

    有时需要几个小时。

    有了图:

    MATCH p=(n)-[*]->(m)
    WHERE n.name = "PaymentGateway"
    RETURN p
    

    答案立即出现。

    图显示了每个下游依赖关系。

    这成为我们构建的最有价值的能力之一。

    6、将图搜索与LLM结合

    图本身很有用。

    真正的突破发生在我们将它连接到LLM时。

    架构:

    用户问题
           ↓
    图查询
           ↓
    相关子图
           ↓
    代码检索
           ↓
    LLM
           ↓
    答案
    

    假设开发者问:

    哪些服务受支付重试影响?

    工作流程变为:

    步骤1:识别实体。

    payment retries
    PaymentService
    RetryProcessor
    

    步骤2:查询图关系。

    PaymentService
        ↓
    RetryProcessor
        ↓
    NotificationService
        ↓
    BillingService
    

    步骤3:检索实际代码。

    payment.service.ts
    retry.processor.ts
    billing.service.ts
    

    步骤4:仅将相关上下文发送给LLM。

    我们不是将数百个文件转储到上下文窗口中,而是提供仓库的高度连接子集。

    答案质量显著提高。

    7、最让我们惊讶的是

    我们最初构建图是为了帮助AI。

    出乎意料的是,人类开始比AI更频繁地使用它。

    工程师开始问这样的问题:

    以前这些答案需要部落知识。

    现在可以查询它们。

    图成为了一个活的架构图。

    8、超越RAG

    大多数试图改进AI编码助手的团队专注于更好的检索。

     
    举报收藏 0打赏 0评论 0
    更多>相关评论
    暂时没有评论,来说点什么吧
    更多>同类百科知识
    推荐图文
    推荐百科知识