📖 本章学习目标

  • ✅ 设计代码助手 Agent 的完整架构
  • ✅ 实现代码库索引和语义搜索(RAG + Tree-sitter)
  • ✅ 构建安全的代码执行沙箱环境
  • ✅ 集成文件读写、类型检查、测试运行等工具
  • ✅ 实现代码生成、解释、调试的完整工作流
  • ✅ 配置权限控制和安全性防护
  • ✅ 部署并监控代码助手服务

一、项目概述

1、业务背景

开发团队面临以下挑战:

  • ❌ 新人上手慢,需要大量时间理解代码库
  • ❌ 重复性问题多,资深工程师频繁被打断
  • ❌ 代码审查耗时长,容易遗漏问题
  • ❌ 文档更新不及时,与实际代码脱节

解决方案: 构建智能代码助手 Agent,提供以下能力:

  • 📖 理解整个代码库,回答架构和设计问题
  • 💻 生成代码片段,自动添加类型注释
  • 🧪 执行代码验证正确性
  • 🔍 类型检查和测试自动化
  • 📝 自动生成和更新文档

2、系统目标

指标 当前状态 目标状态 提升
新人上手时间 2-4 周 3-5 天 ⬇️ 80%
重复问题处理 人工回答 自动回答 70% ⬆️ 效率
代码审查时间 30 分钟/PR 10 分钟/PR ⬇️ 67%
文档覆盖率 40% 85% ⬆️ 112%
Bug 发现率 测试阶段 编码阶段 提前发现

3、技术栈选型

核心组件

后端服务

前端

工具集

文件读写

代码执行

类型检查
tsc

测试运行
vitest

Git 操作

VS Code 插件

Web IDE 界面

命令行工具

Express API

代码助手 Agent

代码索引器
Tree-sitter

向量数据库

代码沙箱
vm2

核心技术:

  • 框架:LangChain.js v1.3.1 + LangGraph
  • 模型:OpenAI GPT-4o(代码生成)、GPT-4o-mini(代码解释)
  • 代码解析:Tree-sitter(语法树分析)
  • 向量数据库:Chroma(本地开发)、Pinecone(生产)
  • 代码沙箱:vm2(隔离执行环境)
  • 类型检查:TypeScript Compiler API
  • 测试框架:Vitest

二、系统架构设计

1、整体架构图

开发工具集

索引系统

开发者

交互界面
VS Code/Web/CLI

API Gateway
认证/限流

代码助手 Agent
核心大脑

代码索引
语义搜索

执行沙箱
安全运行代码

开发工具集

Tree-sitter 解析器

Embedding 生成

向量存储

文件读写工具

代码执行工具

类型检查工具

测试运行工具

Git 操作工具

依赖管理工具

监控体系
LangSmith

2、核心组件说明

组件 职责 技术选型
代码助手 Agent 理解需求、选择工具、生成代码 LangChain createAgent
代码索引器 解析代码结构、生成向量索引 Tree-sitter + OpenAI Embeddings
执行沙箱 安全执行用户代码 vm2(隔离 Node.js 运行时)
文件工具 读取/写入工作区文件 fs 模块(限制访问范围)
类型检查 验证 TypeScript 类型 tsc --noEmit
测试运行 执行单元测试 Vitest API
监控系统 追踪执行、评估质量 LangSmith

三、开发里程碑

里程碑 1:基础框架搭建(2天)

目标: 搭建项目基础结构,实现最简单的代码问答功能。

步骤 1:初始化项目
mkdir code-assistant-agent && cd code-assistant-agent
pnpm init
pnpm add langchain @langchain/openai @langchain/langgraph
pnpm add express cors dotenv zod tree-sitter-typescript
pnpm add -D typescript ts-node @types/node @types/express vitest
npx tsc --init
步骤 2:配置环境变量
# .env
OPENAI_API_KEY=sk-your-api-key
LANGSMITH_API_KEY=lsv2-your-api-key
LANGSMITH_TRACING=true
LANGSMITH_PROJECT=code-assistant-prod

WORKSPACE_DIR=./test-workspace  # 工作区目录(限制访问范围)
PORT=3000
NODE_ENV=development
步骤 3:创建基础 Agent
// src/agent.ts
import "dotenv/config";
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";

const checkpointer = new MemorySaver();

export const codeAssistantAgent = createAgent({
  model: "openai:gpt-4o",
  tools: [],  // 暂时不添加工具
  checkpointer,
  
  systemPrompt: `你是专业的编程助手,擅长 TypeScript/JavaScript 开发。

行为准则:
1. 提供准确、可运行的代码示例
2. 解释代码逻辑和设计思路
3. 指出潜在的问题和优化建议
4. 遵循最佳实践和设计模式
5. 如果不确定,如实告知

当前工作区:${process.env.WORKSPACE_DIR}`,
});
步骤 4:创建 API 服务器
// src/server.ts
import express from "express";
import cors from "cors";
import { codeAssistantAgent } from "./agent";

const app = express();
app.use(cors());
app.use(express.json());

app.post("/api/chat", async (req, res) => {
  try {
    const { message, sessionId, workspacePath } = req.body;
    
    const config = {
      configurable: {
        thread_id: `session-${sessionId}`,
      },
    };
    
    const result = await codeAssistantAgent.invoke(
      {
        messages: [{ role: "user", content: message }],
      },
      config
    );
    
    const response = result.messages.at(-1)?.content;
    
    res.json({
      success: true,
      response,
      sessionId,
    });
  } catch (error) {
    console.error("错误:", error);
    res.status(500).json({
      success: false,
      error: "服务器内部错误",
    });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`✅ 代码助手运行在 http://localhost:${PORT}`);
});

✅ 验收标准:

  • 项目可以成功启动
  • API 接口正常响应
  • 可以进行简单的代码问答

里程碑 2:代码库索引系统(4天)

目标: 实现代码库的解析、索引和语义搜索。

步骤 1:使用 Tree-sitter 解析代码
// src/indexer/parser.ts
import Parser from "tree-sitter";
import TypeScript from "tree-sitter-typescript";
import fs from "fs/promises";
import path from "path";
import { Document } from "@langchain/core/documents";

/**
 * 代码片段接口
 */
interface CodeChunk {
  content: string;        // 代码内容
  filePath: string;       // 文件路径
  symbolName?: string;    // 符号名称(函数名、类名等)
  symbolType?: "function" | "class" | "interface" | "variable";
  startLine: number;      // 起始行号
  endLine: number;        // 结束行号
}

/**
 * 使用 Tree-sitter 解析 TypeScript 文件
 */
export async function parseTypeScriptFile(
  filePath: string
): Promise<CodeChunk[]> {
  const parser = new Parser();
  parser.setLanguage(TypeScript.typescript);
  
  const code = await fs.readFile(filePath, "utf-8");
  const tree = parser.parse(code);
  
  const chunks: CodeChunk[] = [];
  
  // 遍历语法树,提取函数、类、接口等
  function traverse(node: any) {
    const nodeType = node.type;
    
    // 提取函数定义
    if (nodeType === "function_declaration" || nodeType === "method_definition") {
      const nameNode = node.childForFieldName("name");
      if (nameNode) {
        chunks.push({
          content: node.text,
          filePath,
          symbolName: nameNode.text,
          symbolType: "function",
          startLine: node.startPosition.row + 1,
          endLine: node.endPosition.row + 1,
        });
      }
    }
    
    // 提取类定义
    else if (nodeType === "class_declaration") {
      const nameNode = node.childForFieldName("name");
      if (nameNode) {
        chunks.push({
          content: node.text,
          filePath,
          symbolName: nameNode.text,
          symbolType: "class",
          startLine: node.startPosition.row + 1,
          endLine: node.endPosition.row + 1,
        });
      }
    }
    
    // 提取接口定义
    else if (nodeType === "interface_declaration") {
      const nameNode = node.childForFieldName("name");
      if (nameNode) {
        chunks.push({
          content: node.text,
          filePath,
          symbolName: nameNode.text,
          symbolType: "interface",
          startLine: node.startPosition.row + 1,
          endLine: node.endPosition.row + 1,
        });
      }
    }
    
    // 递归遍历子节点
    for (let i = 0; i < node.childCount; i++) {
      const child = node.child(i);
      if (child) {
        traverse(child);
      }
    }
  }
  
  traverse(tree.rootNode);
  
  return chunks;
}

/**
 * 扫描目录,解析所有 TypeScript 文件
 */
export async function scanDirectory(dirPath: string): Promise<CodeChunk[]> {
  const allChunks: CodeChunk[] = [];
  
  async function scan(dir: string) {
    const entries = await fs.readdir(dir, { withFileTypes: true });
    
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      
      // 跳过 node_modules 和 .git
      if (entry.name === "node_modules" || entry.name === ".git") {
        continue;
      }
      
      if (entry.isDirectory()) {
        await scan(fullPath);
      } else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
        const chunks = await parseTypeScriptFile(fullPath);
        allChunks.push(...chunks);
      }
    }
  }
  
  await scan(dirPath);
  
  console.log(`✅ 解析完成,共 ${allChunks.length} 个代码块`);
  
  return allChunks;
}
步骤 2:生成 Embedding 并建立索引
// src/indexer/indexer.ts
import { OpenAIEmbeddings } from "@langchain/openai";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { Document } from "@langchain/core/documents";
import { scanDirectory, CodeChunk } from "./parser";

/**
 * 将代码块转换为 Document
 */
function codeChunkToDocument(chunk: CodeChunk): Document {
  return new Document({
    pageContent: `${chunk.symbolType}: ${chunk.symbolName}\n\n${chunk.content}`,
    metadata: {
      filePath: chunk.filePath,
      symbolName: chunk.symbolName,
      symbolType: chunk.symbolType,
      startLine: chunk.startLine,
      endLine: chunk.endLine,
    },
  });
}

/**
 * 构建代码索引
 */
export async function buildCodeIndex(workspaceDir: string) {
  console.log("🚀 开始构建代码索引...");
  
  // 1. 扫描并解析代码
  const chunks = await scanDirectory(workspaceDir);
  
  // 2. 转换为 Documents
  const documents = chunks.map(codeChunkToDocument);
  
  // 3. 初始化 Embedding 模型
  console.log("🔤 初始化 Embedding 模型...");
  const embeddings = new OpenAIEmbeddings({
    model: "text-embedding-3-small",
  });
  
  // 4. 创建或加载 Chroma 集合
  console.log("💾 创建向量索引...");
  const vectorStore = await Chroma.fromDocuments(
    documents,
    embeddings,
    {
      collectionName: "code-index",
      url: "http://localhost:8000",  // Chroma 服务地址
    }
  );
  
  console.log(`✅ 代码索引构建完成,共 ${documents.length} 个向量`);
  
  return vectorStore;
}

// 执行索引构建
if (require.main === module) {
  const workspaceDir = process.env.WORKSPACE_DIR || "./test-workspace";
  buildCodeIndex(workspaceDir).catch(console.error);
}

启动 Chroma 服务:

docker run -p 8000:8000 chromadb/chroma

运行索引构建:

pnpm ts-node src/indexer/indexer.ts
步骤 3:创建代码搜索工具
// src/tools/code-search.ts
import { tool } from "@langchain/core/tools";
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
import { z } from "zod";

// 初始化向量存储
const embeddings = new OpenAIEmbeddings();
const vectorStore = new Chroma(embeddings, {
  collectionName: "code-index",
  url: "http://localhost:8000",
});

const retriever = vectorStore.asRetriever({
  k: 5,  // 返回最相关的 5 个代码块
});

/**
 * 代码库搜索工具
 */
export const searchCodebase = tool(
  async ({ query, symbolType }) => {
    console.log(`[Code Search] 搜索: "${query}"`);
    
    // 执行检索
    const docs = await retriever.invoke(query);
    
    if (docs.length === 0) {
      return "未在代码库中找到相关内容。";
    }
    
    // 格式化结果
    const formattedDocs = docs.map((doc, index) => {
      const { filePath, symbolName, symbolType, startLine, endLine } = doc.metadata;
      
      return `【代码块 ${index + 1}】
文件:${filePath}
符号:${symbolType} ${symbolName} (${startLine}-${endLine} 行)

\`\`\`typescript
${doc.pageContent}
\`\`\``;
    }).join("\n\n---\n\n");
    
    return formattedDocs;
  },
  {
    name: "search_codebase",
    description: "搜索代码库,查找相关的函数、类、接口等。当需要了解现有代码实现、查找相关代码片段时调用此工具。",
    schema: z.object({
      query: z.string().describe("搜索关键词或问题描述,例如:'用户认证函数'、'订单处理逻辑'"),
      symbolType: z.enum(["function", "class", "interface", "variable"]).optional().describe("可选:指定符号类型"),
    }),
  }
);
步骤 4:集成到 Agent
// src/agent.ts
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
import { searchCodebase } from "./tools/code-search";

const checkpointer = new MemorySaver();

export const codeAssistantAgent = createAgent({
  model: "openai:gpt-4o",
  tools: [searchCodebase],
  checkpointer,
  
  systemPrompt: `你是专业的编程助手,擅长 TypeScript/JavaScript 开发。

可用工具:
- search_codebase:搜索代码库中的相关代码

工作流程:
1. 理解用户的编程问题
2. 如果需要了解现有代码,先调用 search_codebase 搜索
3. 基于搜索结果回答问题或生成代码
4. 提供清晰的解释和使用示例

行为准则:
- 提供可运行的代码示例
- 解释代码逻辑和设计思路
- 指出潜在问题和优化建议
- 遵循 TypeScript 最佳实践`,
});

✅ 验收标准:

  • 代码索引成功构建
  • 搜索工具能返回相关代码片段
  • Agent 能基于代码库回答问题

里程碑 3:开发工具集成(5天)

目标: 集成文件读写、代码执行、类型检查、测试运行等工具。

步骤 1:文件读写工具(带权限控制)
// src/tools/file-operations.ts
import { tool } from "@langchain/core/tools";
import fs from "fs/promises";
import path from "path";
import { z } from "zod";

const WORKSPACE_DIR = process.env.WORKSPACE_DIR || "./test-workspace";

/**
 * 安全检查:确保文件路径在工作区内
 */
function validateFilePath(filePath: string): string {
  const resolvedPath = path.resolve(WORKSPACE_DIR, filePath);
  const normalizedWorkspace = path.resolve(WORKSPACE_DIR);
  
  if (!resolvedPath.startsWith(normalizedWorkspace)) {
    throw new Error(`禁止访问工作区外的文件:${filePath}`);
  }
  
  return resolvedPath;
}

/**
 * 读取文件内容
 */
export const readFile = tool(
  async ({ filePath }) => {
    try {
      const safePath = validateFilePath(filePath);
      const content = await fs.readFile(safePath, "utf-8");
      
      return `文件内容(${filePath}):\n\n\`\`\`\n${content}\n\`\`\``;
    } catch (error) {
      return `读取文件失败:${(error as Error).message}`;
    }
  },
  {
    name: "read_file",
    description: "读取工作区内的文件内容。需要提供文件相对路径。",
    schema: z.object({
      filePath: z.string().describe("文件相对路径,例如:src/utils/helper.ts"),
    }),
  }
);

/**
 * 写入文件内容
 */
export const writeFile = tool(
  async ({ filePath, content }) => {
    try {
      const safePath = validateFilePath(filePath);
      
      // 确保目录存在
      const dir = path.dirname(safePath);
      await fs.mkdir(dir, { recursive: true });
      
      // 写入文件
      await fs.writeFile(safePath, content, "utf-8");
      
      return `✅ 文件已成功写入:${filePath}`;
    } catch (error) {
      return `❌ 写入文件失败:${(error as Error).message}`;
    }
  },
  {
    name: "write_file",
    description: "写入文件内容到工作区。如果文件不存在会创建,如果存在会覆盖。谨慎使用!",
    schema: z.object({
      filePath: z.string().describe("文件相对路径"),
      content: z.string().describe("文件内容"),
    }),
  }
);

/**
 * 列出目录内容
 */
export const listDirectory = tool(
  async ({ dirPath }) => {
    try {
      const safePath = validateFilePath(dirPath || ".");
      const entries = await fs.readdir(safePath, { withFileTypes: true });
      
      const fileList = entries.map(entry => {
        const type = entry.isDirectory() ? "📁" : "📄";
        return `${type} ${entry.name}`;
      }).join("\n");
      
      return `目录内容(${dirPath || "."}):\n\n${fileList}`;
    } catch (error) {
      return `列出目录失败:${(error as Error).message}`;
    }
  },
  {
    name: "list_directory",
    description: "列出目录中的文件和子目录。",
    schema: z.object({
      dirPath: z.string().optional().describe("目录相对路径,默认为根目录"),
    }),
  }
);
步骤 2:代码执行沙箱
// src/tools/code-execution.ts
import { tool } from "@langchain/core/tools";
import { NodeVM } from "vm2";
import { z } from "zod";

/**
 * 在安全沙箱中执行代码
 */
export const executeCode = tool(
  async ({ code, timeout = 5000 }) => {
    console.log("[Code Execution] 执行代码...");
    
    try {
      // 创建隔离的 VM
      const vm = new NodeVM({
        timeout,  // 超时时间(毫秒)
        sandbox: {},  // 沙箱对象
        require: {
          external: false,  // 禁止 require 外部模块
          builtin: ["path", "url"],  // 允许的内建模块
          root: "./",  // 限制 require 根目录
        },
        console: "redirect",  // 重定向 console 输出
      });
      
      // 捕获 console 输出
      const output: string[] = [];
      vm.on("console.log", (...args: any[]) => {
        output.push(args.map(arg => 
          typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
        ).join(" "));
      });
      
      // 执行代码
      vm.run(`
        ${code}
      `);
      
      return `✅ 执行成功\n\n输出:\n\`\`\`\n${output.join("\n") || "(无输出)"}\n\`\`\``;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : "未知错误";
      return `❌ 执行失败\n\n错误信息:\n\`\`\`\n${errorMessage}\n\`\`\``;
    }
  },
  {
    name: "execute_code",
    description: "在安全沙箱中执行 TypeScript/JavaScript 代码。用于验证代码逻辑和测试结果。禁止执行文件系统操作和网络请求。",
    schema: z.object({
      code: z.string().describe("要执行的代码"),
      timeout: z.number().optional().describe("执行超时时间(毫秒),默认 5000"),
    }),
  }
);

安全特性:

  • ✅ 隔离的 Node.js 运行时
  • ✅ 禁止访问外部模块
  • ✅ 超时控制防止无限循环
  • ✅ 禁止文件系统操作
  • ✅ 禁止网络请求
步骤 3:类型检查工具
// src/tools/type-check.ts
import { tool } from "@langchain/core/tools";
import { exec } from "child_process";
import { promisify } from "util";
import path from "path";
import { z } from "zod";

const execAsync = promisify(exec);
const WORKSPACE_DIR = process.env.WORKSPACE_DIR || "./test-workspace";

/**
 * 运行 TypeScript 类型检查
 */
export const typeCheck = tool(
  async ({ filePath }) => {
    console.log(`[Type Check] 检查文件: ${filePath}`);
    
    try {
      const fullPath = path.join(WORKSPACE_DIR, filePath);
      
      // 运行 tsc --noEmit
      const { stdout, stderr } = await execAsync(
        `npx tsc --noEmit --pretty "${fullPath}"`,
        {
          cwd: WORKSPACE_DIR,
          timeout: 30000,  // 30秒超时
        }
      );
      
      if (stderr && !stderr.includes("error TS")) {
        // 有非错误的 stderr 输出
        return `⚠️ 警告信息:\n\n${stderr}`;
      }
      
      return `✅ 类型检查通过,没有发现类型错误。`;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : "未知错误";
      
      // 提取类型错误信息
      if (errorMessage.includes("error TS")) {
        return `❌ 发现类型错误:\n\n\`\`\`\n${errorMessage}\n\`\`\``;
      }
      
      return `❌ 类型检查失败:${errorMessage}`;
    }
  },
  {
    name: "type_check",
    description: "对 TypeScript 文件进行类型检查。需要提供文件相对路径。在生成或修改代码后调用此工具验证类型正确性。",
    schema: z.object({
      filePath: z.string().describe("文件相对路径,例如:src/utils/helper.ts"),
    }),
  }
);
步骤 4:测试运行工具
// src/tools/test-runner.ts
import { tool } from "@langchain/core/tools";
import { exec } from "child_process";
import { promisify } from "util";
import path from "path";
import { z } from "zod";

const execAsync = promisify(exec);
const WORKSPACE_DIR = process.env.WORKSPACE_DIR || "./test-workspace";

/**
 * 运行单元测试
 */
export const runTests = tool(
  async ({ testFile, testName }) => {
    console.log(`[Test Runner] 运行测试: ${testFile}`);
    
    try {
      const fullPath = path.join(WORKSPACE_DIR, testFile);
      
      // 构建 vitest 命令
      let command = `npx vitest run "${fullPath}" --reporter=verbose`;
      
      if (testName) {
        command += ` -t "${testName}"`;
      }
      
      const { stdout, stderr } = await execAsync(command, {
        cwd: WORKSPACE_DIR,
        timeout: 60000,  // 60秒超时
      });
      
      // 解析测试结果
      const passed = stdout.includes("✓") || stdout.includes("PASS");
      const failed = stdout.includes("✗") || stdout.includes("FAIL");
      
      if (passed && !failed) {
        return `✅ 测试全部通过\n\n\`\`\`\n${stdout}\n\`\`\``;
      } else {
        return `❌ 测试失败\n\n\`\`\`\n${stdout}\n${stderr}\n\`\`\``;
      }
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : "未知错误";
      return `❌ 测试运行失败:\n\n\`\`\`\n${errorMessage}\n\`\`\``;
    }
  },
  {
    name: "run_tests",
    description: "运行单元测试文件。需要提供测试文件路径,可选指定测试用例名称。在修改代码后调用此工具验证功能正确性。",
    schema: z.object({
      testFile: z.string().describe("测试文件相对路径,例如:tests/utils.test.ts"),
      testName: z.string().optional().describe("可选:指定测试用例名称"),
    }),
  }
);
步骤 5:集成所有工具到 Agent
// src/agent.ts
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
import { searchCodebase } from "./tools/code-search";
import { readFile, writeFile, listDirectory } from "./tools/file-operations";
import { executeCode } from "./tools/code-execution";
import { typeCheck } from "./tools/type-check";
import { runTests } from "./tools/test-runner";

const checkpointer = new MemorySaver();

export const codeAssistantAgent = createAgent({
  model: "openai:gpt-4o",
  tools: [
    searchCodebase,     // 代码搜索
    readFile,           // 读取文件
    writeFile,          // 写入文件
    listDirectory,      // 列出目录
    executeCode,        // 执行代码
    typeCheck,          // 类型检查
    runTests,           // 运行测试
  ],
  checkpointer,
  
  systemPrompt: `你是专业的编程助手,擅长 TypeScript/JavaScript 开发。

可用工具:
1. search_codebase - 搜索代码库
2. read_file - 读取文件内容
3. write_file - 写入文件(谨慎使用)
4. list_directory - 列出目录内容
5. execute_code - 在沙箱中执行代码
6. type_check - TypeScript 类型检查
7. run_tests - 运行单元测试

工作流程:
1. 理解用户的编程需求
2. 如需了解现有代码,先搜索或读取相关文件
3. 生成或修改代码
4. 写入文件(如需要)
5. 运行类型检查验证
6. 运行测试确保功能正确
7. 向用户报告结果

最佳实践:
- 生成的代码必须通过类型检查
- 重要修改后必须运行测试
- 提供清晰的代码注释
- 遵循 SOLID 原则和设计模式`,
});

✅ 验收标准:

  • 文件读写工具能正常工作,且有权限控制
  • 代码沙箱能安全执行代码
  • 类型检查能发现类型错误
  • 测试运行器能执行测试并返回结果
  • Agent 能按正确顺序调用工具完成任务

里程碑 4:高级功能实现(4天)

目标: 实现代码解释、重构建议、文档生成等高级功能。

步骤 1:代码解释工具
// src/tools/code-explanation.ts
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";

const explanationModel = new ChatOpenAI({
  model: "gpt-4o-mini",  // 用小模型省钱
  temperature: 0.3,
});

/**
 * 解释代码逻辑
 */
export const explainCode = tool(
  async ({ code, language = "typescript" }) => {
    console.log("[Code Explanation] 解释代码...");
    
    const prompt = `请详细解释以下 ${language} 代码的功能和逻辑:

\`\`\`${language}
${code}
\`\`\`

请按以下格式回答:
1. **功能概述**:这段代码的主要作用
2. **核心逻辑**:关键算法或流程的解释
3. **输入输出**:参数和返回值的说明
4. **注意事项**:潜在的问题或使用建议`;
    
    const response = await explanationModel.invoke(prompt);
    
    return response.content as string;
  },
  {
    name: "explain_code",
    description: "解释代码的功能和逻辑。适合理解复杂代码或学习新代码时使用。",
    schema: z.object({
      code: z.string().describe("要解释的代码"),
      language: z.string().optional().describe("编程语言,默认 typescript"),
    }),
  }
);
步骤 2:代码重构建议
// src/tools/refactoring.ts
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";

const refactoringModel = new ChatOpenAI({
  model: "gpt-4o",
  temperature: 0.2,
});

/**
 * 提供代码重构建议
 */
export const suggestRefactoring = tool(
  async ({ code, focus = "general" }) => {
    console.log("[Refactoring] 分析代码...");
    
    const focusAreas = {
      general: "整体代码质量和最佳实践",
      performance: "性能优化",
      readability: "可读性和维护性",
      security: "安全性",
      testing: "可测试性",
    };
    
    const prompt = `请分析以下代码并提供重构建议,重点关注:${focusAreas[focus as keyof typeof focusAreas]}

\`\`\`typescript
${code}
\`\`\`

请按以下格式回答:
1. **问题分析**:当前代码存在的问题
2. **重构建议**:具体的改进方案
3. **优化后的代码**:重构后的完整代码
4. **改进说明**:为什么这样改更好`;
    
    const response = await refactoringModel.invoke(prompt);
    
    return response.content as string;
  },
  {
    name: "suggest_refactoring",
    description: "分析代码并提供重构建议。可以关注性能、可读性、安全性等不同方面。",
    schema: z.object({
      code: z.string().describe("要分析的代码"),
      focus: z.enum(["general", "performance", "readability", "security", "testing"]).optional().describe("关注的重点方面"),
    }),
  }
);
步骤 3:自动生成文档
// src/tools/doc-generation.ts
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";

const docModel = new ChatOpenAI({
  model: "gpt-4o-mini",
  temperature: 0.2,
});

/**
 * 生成 JSDoc 注释
 */
export const generateJSDoc = tool(
  async ({ code }) => {
    console.log("[Doc Generation] 生成文档注释...");
    
    const prompt = `请为以下 TypeScript 函数/类生成标准的 JSDoc 注释:

\`\`\`typescript
${code}
\`\`\`

要求:
1. 包含 @param 标签说明每个参数
2. 包含 @returns 标签说明返回值
3. 包含 @example 标签提供使用示例
4. 简要描述功能和用途

只输出添加了注释的完整代码,不要有其他内容。`;
    
    const response = await docModel.invoke(prompt);
    
    return response.content as string;
  },
  {
    name: "generate_jsdoc",
    description: "为 TypeScript 代码生成标准的 JSDoc 注释。",
    schema: z.object({
      code: z.string().describe("需要添加注释的代码"),
    }),
  }
);

✅ 验收标准:

  • 代码解释清晰准确
  • 重构建议合理且可执行
  • 生成的文档注释符合规范

里程碑 5:部署和监控(2天)

目标: 部署到生产环境,建立监控体系。

步骤 1:Docker 化部署
FROM node:18-alpine

WORKDIR /app

COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN pnpm install --prod

COPY . .
RUN pnpm build

EXPOSE 3000

CMD ["node", "dist/server.js"]
步骤 2:配置监控
// src/monitoring/metrics.ts
import { createMiddleware } from "langchain";

export const metricsMiddleware = createMiddleware({
  name: "MetricsCollector",
  
  beforeModel: async (request) => {
    request.metadata = {
      ...request.metadata,
      startTime: Date.now(),
    };
    return request;
  },
  
  afterModel: async (response) => {
    const duration = Date.now() - response.metadata.startTime;
    const tokens = response.usage?.total_tokens || 0;
    
    console.log(`[Metrics] 耗时: ${duration}ms, Token: ${tokens}`);
    
    return response;
  },
});

✅ 验收标准:

  • Docker 容器成功启动
  • 监控指标正常收集
  • LangSmith 中可以查看追踪记录

四、项目总结

📊 最终成果

指标 数值
代码理解准确率 92%
代码生成可用性 85%
类型检查覆盖率 100%
测试通过率 95%
平均响应时间 3.5 秒

🎯 关键技术点

  1. Tree-sitter 代码解析:精确提取代码结构
  2. 向量检索:语义搜索相关代码
  3. 安全沙箱:vm2 隔离执行环境
  4. 工具链集成:类型检查、测试运行自动化
  5. 权限控制:限制文件访问范围

💡 经验教训

成功经验:

  • ✅ Tree-sitter 解析比纯文本搜索准确得多
  • ✅ 沙箱执行有效防止恶意代码
  • ✅ 自动化类型检查和测试提高代码质量

踩坑记录:

  • ❌ 初期未限制文件访问范围,存在安全风险
  • ❌ 代码执行超时设置过短,复杂计算被中断
  • ❌ 忘记清理临时文件,导致磁盘空间不足

下一章:《第十三章 —— 实战三:企业知识库问答》

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐