惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
量子位
大猫的无限游戏
大猫的无限游戏
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
Google DeepMind News
Google DeepMind News
小众软件
小众软件
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
MongoDB | Blog
MongoDB | Blog
B
Blog RSS Feed
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
Recent Announcements
Recent Announcements
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
雷峰网
雷峰网
Jina AI
Jina AI
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - 【唐】三三

《python编程从入门到实践》15 生成数据 《python编程从入门到实践》10-11章 文件和异常、测试代码 《python编程从入门到实践》8-9章 函数、类 Oh-My-OpenCode 3.5.6 完整使用指南 AI工具免费模型排名对比 (2026-02-12) ABP演示 - 分布式 Event Bus(使用rabbitmq) ABP演示 - 工作单元 (UOW) ABP演示 - 异常处理 ABP演示 - 缓存 APP - 实体变更监视事件 [EntityCreatedEventData、EntityUpdatedEventData、EntityDeletedEventData] ABP演示 - 授权 ABP演示 - 本地Event Bus ABP演示 - 实现选项 OPtion ABP演示 - 简单的实现DDD LINQ:SelectMany LINQ - Concat、Union、Intersect、Except IEqualityComparer Nginx - 内置变量 vite - vue 打包 vue - 以deifne开头的 API vue - 进阶
fastcode 代码理解 AI 框架
【唐】三三 · 2026-04-06 · via 博客园 - 【唐】三三

https://github.com/HKUDS/Fastcode/

fastCode 是一款面向全面代码理解与分析的令牌高效型框架,可为大规模代码库和软件架构提供卓越速度、超高精度与高性价比。

🚀 速度优势显著 —— 运行速度比 Cursor 快 3 倍,比 Claude Code 快 4 倍。

💰 成本大幅降低 —— 费用比 Cursor 低 55%,比 Claude Code 低 44%。

⚡ 精度行业领先 —— 凭借最高准确率表现,优于 Cursor 与 Claude Code。

⚡ 性能 & 稳定性(你当前最关心的)

维度 cocoindex (ccc mcp) FastCode
Windows 稳定性 ❌(你已经遇到)
MCP 支持 ⚠️ demo级 ✅(设计更贴近 agent)
查询延迟 ⚠️ 中(embedding) ✅ 更稳定
大项目 ⚠️ 容易卡 ✅ 更可控

🚀 Quick Start

Get FastCode running in under 2 minutes:

# 1. Clone the repository
git clone https://github.com/HKUDS/FastCode.git
cd FastCode

# 2. Install dependencies
pip install -r requirements.txt

# 3. Configure your API keys
cp env.example .env
# Edit .env with your API keys

# 4. Launch the Web UI
python web_app.py --host 0.0.0.0 --port 5000

# api
cd D:\AI-Local-Tool\FastCode\ && python api.py --host 0.0.0.0 --port 8000

Open http://localhost:5000 and start asking questions about your code! 🎉

💻 Windows Installation

Prerequisites

  • Python 3.12 or higher
  • Git

Step-by-Step Guide

  1. Clone FastCode

    git clone https://github.com/HKUDS/FastCode.git
    cd FastCode
    
  2. Install Dependencies

    Option A: Using uv (Recommended)

    # Install uv
    pip install uv
    # create new env with uv
    uv venv --python=3.12
    .venv\Scripts\activate
    
    # Install dependencies with uv
    uv pip install -r requirements.txt
    

    Option B: Using pip

    pip install -r requirements.txt
    
  3. Configure Environment

    copy env.example .env
    notepad .env
    

    Add your API keys:

    OPENAI_API_KEY=your_openai_api_key_here
    MODEL=qwen/qwen3-coder-30b-a3b-instruct
    BASE_URL=https://api.openai.com/v1
    
  4. Launch FastCode

    # Web UI (Recommended)
    python web_app.py --host 0.0.0.0 --port 5000
    
    # 当前环境
    cd D:\AI-Local-Tool\FastCode && python web_app.py --host 0.0.0.0 --port 5000
    
    
    # Or use the CLI
    python main.py query --repo-path C:\path\to\your\repo --query "Your question here"
    # 示例
    python main.py query --repo-path D:\WorkSpace\pum --query "Your question here"
    

Troubleshooting:

Troubleshooting: 故障排除:

  • If you get SSL errors: pip install --upgrade certifi
    如果遇到SSL错误:pip install --upgrade certifi
  • For permission errors, run Command Prompt as Administrator
    如果遇到权限错误,请以管理员身份运行命令提示符
  • If faiss-cpu fails to install: pip install faiss-cpu --no-cache-dir
    如果faiss-cpu安装失败:pip install faiss-cpu --no-cache-dir
  • If you run ./run_nanobot.sh (bash script) on Windows, use Git Bash or WSL, and keep .sh files in LF line endings. This repo enforces LF for *.sh via .gitattributes, but older clones may need a one-time re-checkout.如果你在Windows上运行./run_nanobot.sh(bash脚本),
    请使用Git Bash或WSL</b2,并将.sh文件的行尾保持为LF。此仓库通过.gitattributes强制要求*.sh文件使用LF,但旧版本的克隆可能需要一次性重新检出。

![[Pasted image 20260325110134.png]]

2026-03-25 10:50:46,402 - fastcode.cache - INFO - Initialized disk cache at D:\AI-Local-Tool\记忆\FastCode\data\cache
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)
INFO:     127.0.0.1:53764 - "GET / HTTP/1.1" 200 OK
INFO:     127.0.0.1:53764 - "GET /assets/FastCode.svg HTTP/1.1" 304 Not Modified
2026-03-25 10:50:51,139 - fastcode.vector_store - INFO - Scanning available indexes...
2026-03-25 10:50:51,140 - fastcode.vector_store - INFO - Index scan complete: found 0 repositories
INFO:     127.0.0.1:53764 - "GET /api/status HTTP/1.1" 200 OK
INFO:     127.0.0.1:51442 - "GET /api/sessions HTTP/1.1" 200 OK
INFO:     127.0.0.1:51442 - "GET /api/sessions HTTP/1.1" 200 OK
INFO:     127.0.0.1:52507 - "GET /api/status HTTP/1.1" 200 OK
2026-03-25 10:51:03,200 - web_app - INFO - Indexing 1 repositories
2026-03-25 10:51:03,201 - fastcode - INFO - Loading 1 repositories
2026-03-25 10:51:03,201 - fastcode - INFO - [1/1] Loading repository: file:///D:/WorkSpace/pum/
2026-03-25 10:51:03,201 - fastcode - INFO - [1/1] Auto-detected source type as URL
2026-03-25 10:51:03,202 - fastcode.loader - INFO - Cloning repository from file:///D:/WorkSpace/pum/
2026-03-25 10:51:03,202 - fastcode.loader - WARNING - Repository path D:\AI-Local-Tool\记忆\FastCode\repos\pum already exists, moving to backup: D:\AI-Local-Tool\记忆\FastCode\repo_backup\pum_20260325_105103_202305
2026-03-25 10:51:08,449 - fastcode.loader - INFO - Successfully cloned to D:\AI-Local-Tool\记忆\FastCode\repos\pum
2026-03-25 10:51:08,579 - fastcode.loader - INFO - Scanning files in D:\AI-Local-Tool\记忆\FastCode\repos\pum
2026-03-25 10:51:08,580 - fastcode.loader - INFO - Loaded 56 patterns from .gitignore
2026-03-25 10:51:11,837 - fastcode.loader - INFO - Found 1326 supported files (17.59 MB total)
2026-03-25 10:51:11,837 - fastcode - INFO - Indexing repository: pum
2026-03-25 10:51:11,837 - fastcode.vector_store - INFO - Initializing vector store with dimension 384
2026-03-25 10:51:11,837 - fastcode.vector_store - INFO - Initialized HNSW index with cosine distance
2026-03-25 10:51:12,566 - fastcode.indexer - INFO - Starting repository indexing
2026-03-25 10:51:12,566 - fastcode.loader - INFO - Scanning files in D:\AI-Local-Tool\记忆\FastCode\repos\pum
2026-03-25 10:51:12,567 - fastcode.loader - INFO - Loaded 56 patterns from .gitignore
2026-03-25 10:51:15,599 - fastcode.loader - INFO - Found 1326 supported files (17.59 MB total)
2026-03-25 10:51:15,599 - fastcode.indexer - INFO - Indexing 1326 files for repository: pum
2026-03-25 10:51:15,613 - fastcode.repo_overview - INFO - Generating overview for repository: pum
2026-03-25 10:51:15,700 - fastcode.vector_store - INFO - Saved repository overview for pum
2026-03-25 10:51:15,700 - fastcode.indexer - INFO - Generated and saved repository overview for pum
Indexing files: 100%|██████████████████████████████████████████████████████████████| 1326/1326 [00:19<00:00, 68.66it/s]
2026-03-25 10:51:35,013 - fastcode.indexer - INFO - Indexed 6713 code elements for pum
2026-03-25 10:51:35,013 - fastcode.indexer - INFO - Generating embeddings for code elements
2026-03-25 10:51:35,248 - fastcode.embedder - INFO - Generating embeddings for 6713 code elements
Batches:  50%|███████████████████████████████████▌                                   | 105/210 [10:09<10:43,  6.13s/it]

最后,配置MCP。(#放弃)

{
  "mcpServers": {
    "fastcode": {
      "command": "python",
      "args": [
        "D:/AI-Local-Tool/FastCode/mcp_server.py"
      ],
      "env": {
        "MODEL": "qwen3-coder-plus",
        "BASE_URL": "https://apis.iflow.cn/v1",
        "OPENAI_API_KEY": "sk-fd89e9c7402b782b44acde88e71521"
      }
    }
  }
}

或者使用命令

python D:\AI-Local-Tool\FastCode\main.py query --repo-path D:\WorkSpace\pum\ --query "Your question here"

python D:\AI-Local-Tool\FastCode\main.py query --repo-path D:\WorkSpace\pum\ --query "分析订单编辑页面 edit.cshtml 的保存功能实现,查找:\n1. Save 方法的入口和实现\n2. 订单项目明细(OrderItem/ItemList)的数据处理逻辑\n3. IsDelete 字段的使用场景\n4. 数据保存流程中涉及的 Service 层方法"

删除自动备份的代码,给我备份了几十个GB

D:\AI-Local-Tool\FastCode\fastcode\loader.py

原代码 :

        if os.path.exists(repo_path):
            self._backup_existing_repo(repo_path)

        return repo_path

改为 :

        if os.path.exists(repo_path):
            self.logger.info(f"Repository path {repo_path} already exists, using 
            existing repository")
            return repo_path

        return repo_path

这样修改后,FastCode 会:

  1. 检查仓库是否已存在
  2. 如果存在,直接使用,不重新加载
  3. 如果不存在,才进行加载

项目中使用API写代码

当前它提供的 MCP 不好用,自己写一个调用API的方法,更方便

先启动

cd D:\AI-Local-Tool\FastCode\ && python api.py --host 0.0.0.0 --port 8000

写一个python放到项目根目录

fastcode_client.py

#!/usr/bin/env python
# ================================================================================
# -*- coding: utf-8 -*-
"""
FastCode API Client - PUM 项目代码搜索工具


================================================================================
                              命令汇总
================================================================================


# 状态查询
python fastcode_client.py --status                                    # 查看API状态
python fastcode_client.py --status -o json                           # JSON格式查看状态


# 仓库加载与索引
python fastcode_client.py --init                                     # 初始化仓库(加载+索引)
python fastcode_client.py --load-and-index                           # 一步完成加载和索引
python fastcode_client.py --force                                    # 强制重新索引


# 仓库管理
python fastcode_client.py --delete-repos "d:\\WorkSpace\\pum-index-fastcode"        # 删除仓库及索引
python fastcode_client.py --load-repos "pum-index-fastcode"          # 加载多个已索引的仓库


# 代码查询
python fastcode_client.py -q "搜索内容"                              # 单次查询
"python fastcode_client.py -q "搜索内容" -s "session-name""            # 指定会话ID
python fastcode_client.py -q "搜索内容" -m                            # 多轮对话模式
python fastcode_client.py -q "搜索内容" -o json                      # JSON格式输出


# ================================================================================


使用方法:
    python fastcode_client.py --question "搜索问题" [--session-id "session-name"] [--multi-turn]


示例:
    python fastcode_client.py --question "分析订单保存功能"
    python fastcode_client.py --question "OrderController Save方法" --session-id "order-analysis" --multi-turn
"""


import argparse
import json
import requests
import sys
from typing import Optional, Dict, Any, List




class FastCodeClient:
    """FastCode API 客户端"""


    DEFAULT_URL = "http://localhost:8000"
    DEFAULT_REPO_NAME = "pum-index-fastcode"
    DEFAULT_REPO_PATH = "d:\\WorkSpace\\pum-index-fastcode"


    def __init__(self, base_url: str = None, repo_path: str = None):
        self.base_url = base_url or self.DEFAULT_URL
        self.repo_path = repo_path or self.DEFAULT_REPO_PATH
        self.repo_name = self.DEFAULT_REPO_NAME
        self.session = requests.Session()
    
    def load_repo(self) -> Dict[str, Any]:
        """加载仓库"""
        url = f"{self.base_url}/load"
        payload = {"source": self.repo_path}
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()
    
    def index_repo(self, force: bool = False) -> Dict[str, Any]:
        """索引仓库"""
        url = f"{self.base_url}/index?force={str(force).lower()}"
        payload = {"source": self.repo_path}
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()
    
    def get_status(self) -> Dict[str, Any]:
        """获取状态"""
        url = f"{self.base_url}/status"
        response = self.session.get(url)
        response.raise_for_status()
        return response.json()


    def load_and_index(self) -> Dict[str, Any]:
        """加载并索引仓库(一步完成)"""
        url = f"{self.base_url}/load-and-index"
        payload = {"source": self.repo_path, "is_url": False}
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()


    def delete_repos(self, repo_names: List[str], delete_source: bool = True) -> Dict[str, Any]:
        """删除仓库及其索引"""
        url = f"{self.base_url}/delete-repos"
        payload = {"repo_names": repo_names, "delete_source": delete_source}
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()


    def load_repositories(self, repo_names: List[str]) -> Dict[str, Any]:
        """加载多个已索引的仓库"""
        url = f"{self.base_url}/load-repositories"
        payload = {"repo_names": repo_names}
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()
    
    def query(
        self,
        question: str,
        session_id: Optional[str] = None,
        multi_turn: bool = True,
        filters: Optional[Dict] = None,
        repo_filter: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """
        执行查询
        
        Args:
            question: 查询问题
            session_id: 会话ID(用于多轮对话)
            multi_turn: 是否启用多轮对话
            filters: 过滤条件
            repo_filter: 仓库过滤列表
        
        Returns:
            查询结果
        """
        url = f"{self.base_url}/query"
        payload = {
            "question": question,
            "filters": filters,
            "repo_filter": repo_filter or [self.repo_name],
            "multi_turn": multi_turn,
            "session_id": session_id or "default-session"
        }
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()
    
    def ensure_ready(self, force: bool = False) -> bool:
        """确保仓库已加载并索引"""
        try:
            status = self.get_status()
            if status.get("repo_indexed"):
                return True
        except:
            pass
        
        try:
            print("正在加载仓库...")
            self.load_repo()
            print("正在索引仓库...")
            self.index_repo(force=force)
            print("仓库准备完成!")
            return True
        except Exception as e:
            print(f"仓库准备失败: {e}")
            return False




def main():
    parser = argparse.ArgumentParser(
        description="FastCode API Client - PUM 项目代码搜索工具",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例:
  # 埥询
  python fastcode_client.py -q "分析订单保存功能"
  
  # 多轮对话
  python fastcode_client.py -q "OrderController Save方法" -s "order-analysis" -m
  
  # 检查状态
  python fastcode_client.py --status
  
  # 初始化仓库
  python fastcode_client.py --init


# 强制索引
  python fastcode_client.py --force


        """
    )
    
    parser.add_argument(
        "-q", "--question",
        type=str,
        help="查询问题"
    )
    parser.add_argument(
        "-s", "--session-id",
        type=str,
        default=None,
        help="会话ID(用于多轮对话)"
    )
    parser.add_argument(
        "-m", "--multi-turn",
        action="store_true",
        default=True,
        help="启用多轮对话(默认启用)"
    )
    parser.add_argument(
        "--status",
        action="store_true",
        help="获取API状态"
    )
    parser.add_argument(
        "--init",
        action="store_true",
        help="初始化仓库(加载并索引)"
    )
    parser.add_argument(
        "--force",
        action="store_true",
        help="强制重新索引"
    )
    parser.add_argument(
        "--load-and-index",
        action="store_true",
        help="加载并索引仓库(一步完成)"
    )
    parser.add_argument(
        "--delete-repos",
        type=str,
        nargs="+",
        help="删除仓库及其索引(提供仓库名列表)"
    )
    parser.add_argument(
        "--load-repos",
        type=str,
        nargs="+",
        help="加载多个已索引的仓库(提供仓库名列表)"
    )
    parser.add_argument(
        "--url",
        type=str,
        default="http://localhost:8000",
        help="FastCode API URL(默认:  http://localhost:8000 )"
    )
    parser.add_argument(
        "--repo",
        type=str,
        default="d:\\WorkSpace\\pum-index-fastcode",
        help="仓库路径(默认: d:\\WorkSpace\\pum-index-fastcode)"
    )
    parser.add_argument(
        "-o", "--output",
        type=str,
        choices=["text", "json"],
        default="text",
        help="输出格式(默认: text)"
    )
    
    args = parser.parse_args()
    
    client = FastCodeClient(base_url=args.url, repo_path=args.repo)
    
    if args.status:
        try:
            status = client.get_status()
            if args.output == "json":
                print(json.dumps(status, indent=2, ensure_ascii=False))
            else:
                print(f"状态: {status.get('status')}")
                print(f"仓库已加载: {status.get('repo_loaded')}")
                print(f"仓库已索引: {status.get('repo_indexed')}")
                if status.get("repo_info"):
                    info = status["repo_info"]
                    print(f"仓库名: {info.get('name')}")
                    print(f"文件数: {info.get('file_count')}")
        except Exception as e:
            print(f"错误: {e}")
            sys.exit(1)
        return
    
    if args.force:
        try:
            print("正在强制重新索引仓库...")
            client.index_repo(force=True)
            print("索引完成!")
            return
        except Exception as e:
            print(f"索引失败: {e}")
            sys.exit(1)


    if args.load_and_index:
        try:
            print("正在加载并索引仓库...")
            client.load_and_index()
            print("加载并索引完成!")
            return
        except Exception as e:
            print(f"加载并索引失败: {e}")
            sys.exit(1)


    if args.delete_repos:
        try:
            print(f"正在删除仓库: {args.delete_repos}...")
            client.delete_repos(args.delete_repos)
            print("删除完成!")
            return
        except Exception as e:
            print(f"删除失败: {e}")
            sys.exit(1)


    if args.load_repos:
        try:
            print(f"正在加载仓库: {args.load_repos}...")
            result = client.load_repositories(args.load_repos)
            print("加载完成!")
            print(json.dumps(result, indent=2, ensure_ascii=False))
            return
        except Exception as e:
            print(f"加载失败: {e}")
            sys.exit(1)
    
    if args.init:
        try:
            client.ensure_ready(force=args.force)
        except Exception as e:
            print(f"初始化失败: {e}")
            sys.exit(1)
        return
    
    if not args.question:
        parser.print_help()
        sys.exit(1)
    
    try:
        if not client.ensure_ready():
            print("仓库未准备好,请先运行 --init")
            sys.exit(1)
        
        result = client.query(
            question=args.question,
            session_id=args.session_id,
            multi_turn=args.multi_turn
        )
        
        if args.output == "json":
            print(json.dumps(result, indent=2, ensure_ascii=False))
        else:
            answer = result.get("answer", "")
            print(answer)
            if result.get("sources"):
                print("\n--- 相关文件 ---")
                for source in result.get("sources", []):
                    print(f"  - {source}")
    except Exception as e:
        print(f"查询错误: {e}")
        sys.exit(1)




if __name__ == "__main__":
    main()