[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"similar-unit-mesh--build-your-ai-coding-assistant":3,"tool-unit-mesh--build-your-ai-coding-assistant":61},[4,18,26,36,44,53],{"id":5,"name":6,"github_repo":7,"description_zh":8,"stars":9,"difficulty_score":10,"last_commit_at":11,"category_tags":12,"status":17},4358,"openclaw","openclaw\u002Fopenclaw","OpenClaw 是一款专为个人打造的本地化 AI 助手，旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚，能够直接接入你日常使用的各类通讯渠道，包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息，OpenClaw 都能即时响应，甚至支持在 macOS、iOS 和 Android 设备上进行语音交互，并提供实时的画布渲染功能供你操控。\n\n这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地，用户无需依赖云端服务即可享受快速、私密的智能辅助，真正实现了“你的数据，你做主”。其独特的技术亮点在于强大的网关架构，将控制平面与核心助手分离，确保跨平台通信的流畅性与扩展性。\n\nOpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者，以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力（支持 macOS、Linux 及 Windows WSL2），即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你",349277,3,"2026-04-06T06:32:30",[13,14,15,16],"Agent","开发框架","图像","数据工具","ready",{"id":19,"name":20,"github_repo":21,"description_zh":22,"stars":23,"difficulty_score":10,"last_commit_at":24,"category_tags":25,"status":17},3808,"stable-diffusion-webui","AUTOMATIC1111\u002Fstable-diffusion-webui","stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面，旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点，将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。\n\n无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师，还是想要深入探索模型潜力的开发者与研究人员，都能从中获益。其核心亮点在于极高的功能丰富度：不仅支持文生图、图生图、局部重绘（Inpainting）和外绘（Outpainting）等基础模式，还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外，它内置了 GFPGAN 和 CodeFormer 等人脸修复工具，支持多种神经网络放大算法，并允许用户通过插件系统无限扩展能力。即使是显存有限的设备，stable-diffusion-webui 也提供了相应的优化选项，让高质量的 AI 艺术创作变得触手可及。",162132,"2026-04-05T11:01:52",[14,15,13],{"id":27,"name":28,"github_repo":29,"description_zh":30,"stars":31,"difficulty_score":32,"last_commit_at":33,"category_tags":34,"status":17},1381,"everything-claude-code","affaan-m\u002Feverything-claude-code","everything-claude-code 是一套专为 AI 编程助手（如 Claude Code、Codex、Cursor 等）打造的高性能优化系统。它不仅仅是一组配置文件，而是一个经过长期实战打磨的完整框架，旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。\n\n通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能，everything-claude-code 能显著提升 AI 在复杂任务中的表现，帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略，使得模型响应更快、成本更低，同时有效防御潜在的攻击向量。\n\n这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库，还是需要 AI 协助进行安全审计与自动化测试，everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目，它融合了多语言支持与丰富的实战钩子（hooks），让 AI 真正成长为懂上",157379,2,"2026-04-15T23:32:42",[14,13,35],"语言模型",{"id":37,"name":38,"github_repo":39,"description_zh":40,"stars":41,"difficulty_score":32,"last_commit_at":42,"category_tags":43,"status":17},2271,"ComfyUI","Comfy-Org\u002FComfyUI","ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎，专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式，采用直观的节点式流程图界面，让用户通过连接不同的功能模块即可构建个性化的生成管线。\n\n这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景，也能自由组合模型、调整参数并实时预览效果，轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性，不仅支持 Windows、macOS 和 Linux 全平台，还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构，并率先支持 SDXL、Flux、SD3 等前沿模型。\n\n无论是希望深入探索算法潜力的研究人员和开发者，还是追求极致创作自由度的设计师与资深 AI 绘画爱好者，ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能，使其成为当前最灵活、生态最丰富的开源扩散模型工具之一，帮助用户将创意高效转化为现实。",108322,"2026-04-10T11:39:34",[14,15,13],{"id":45,"name":46,"github_repo":47,"description_zh":48,"stars":49,"difficulty_score":32,"last_commit_at":50,"category_tags":51,"status":17},6121,"gemini-cli","google-gemini\u002Fgemini-cli","gemini-cli 是一款由谷歌推出的开源 AI 命令行工具，它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言，它提供了一条从输入提示词到获取模型响应的最短路径，无需切换窗口即可享受智能辅助。\n\n这款工具主要解决了开发过程中频繁上下文切换的痛点，让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用，还是执行复杂的 Git 操作，gemini-cli 都能通过自然语言指令高效处理。\n\n它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口，具备出色的逻辑推理能力；内置 Google 搜索、文件操作及 Shell 命令执行等实用工具；更独特的是，它支持 MCP（模型上下文协议），允许用户灵活扩展自定义集成，连接如图像生成等外部能力。此外，个人谷歌账号即可享受免费的额度支持，且项目基于 Apache 2.0 协议完全开源，是提升终端工作效率的理想助手。",100752,"2026-04-10T01:20:03",[52,13,15,14],"插件",{"id":54,"name":55,"github_repo":56,"description_zh":57,"stars":58,"difficulty_score":32,"last_commit_at":59,"category_tags":60,"status":17},4721,"markitdown","microsoft\u002Fmarkitdown","MarkItDown 是一款由微软 AutoGen 团队打造的轻量级 Python 工具，专为将各类文件高效转换为 Markdown 格式而设计。它支持 PDF、Word、Excel、PPT、图片（含 OCR）、音频（含语音转录）、HTML 乃至 YouTube 链接等多种格式的解析，能够精准提取文档中的标题、列表、表格和链接等关键结构信息。\n\n在人工智能应用日益普及的今天，大语言模型（LLM）虽擅长处理文本，却难以直接读取复杂的二进制办公文档。MarkItDown 恰好解决了这一痛点，它将非结构化或半结构化的文件转化为模型“原生理解”且 Token 效率极高的 Markdown 格式，成为连接本地文件与 AI 分析 pipeline 的理想桥梁。此外，它还提供了 MCP（模型上下文协议）服务器，可无缝集成到 Claude Desktop 等 LLM 应用中。\n\n这款工具特别适合开发者、数据科学家及 AI 研究人员使用，尤其是那些需要构建文档检索增强生成（RAG）系统、进行批量文本分析或希望让 AI 助手直接“阅读”本地文件的用户。虽然生成的内容也具备一定可读性，但其核心优势在于为机器",93400,"2026-04-06T19:52:38",[52,14],{"id":62,"github_repo":63,"name":64,"description_en":65,"description_zh":66,"ai_summary_zh":67,"readme_en":68,"readme_zh":69,"quickstart_zh":70,"use_case_zh":71,"hero_image_url":72,"owner_login":73,"owner_name":74,"owner_avatar_url":75,"owner_bio":76,"owner_company":77,"owner_location":77,"owner_email":77,"owner_twitter":77,"owner_website":78,"owner_url":79,"languages":80,"stars":93,"forks":94,"last_commit_at":95,"license":77,"difficulty_score":96,"env_os":97,"env_gpu":98,"env_ram":97,"env_deps":99,"category_tags":108,"github_topics":109,"view_count":32,"oss_zip_url":77,"oss_zip_packed_at":77,"status":17,"created_at":112,"updated_at":113,"faqs":114,"releases":115},7935,"unit-mesh\u002Fbuild-your-ai-coding-assistant","build-your-ai-coding-assistant","《AI 研发提效：构建 AI 辅助编码助手》 —— 介绍如何 DIY 一个端到端（从 IDE  插件、模型选型、数据集构建到模型微调）的 AI 辅助编程工具，类似于 GitHub Copilot、JetBrains AI Assistant、AutoDev 等。","build-your-ai-coding-assistant 是一套由 Thoughtworks 开源社区推出的实战指南，旨在帮助开发者从零开始构建属于自己的端到端 AI 辅助编程助手。它不仅仅是一个简单的教程，更提供了从 IDE 插件开发、模型选型、高质量数据集构建到模型微调的完整解决方案，让企业或个人能够打造类似 GitHub Copilot 或 JetBrains AI Assistant 的定制化工具。\n\n该方案主要解决了通用 AI 编码工具难以完全适配企业内部特定需求、数据隐私顾虑以及特定场景（如需求生成、自动化测试、代码审查）优化不足的问题。通过提供 AutoDev 插件（支持 IntelliJ 和 VSCode）、Unit Eval 数据集工具等配套开源项目，用户可以灵活定义 AI 能力边界。\n\n这套方案特别适合希望提升研发效能的开发团队、对 AI 工程化感兴趣的研究人员，以及想要深入理解大模型在代码领域应用的技术极客。其独特的技术亮点在于提出了“一大一中一微”的三模型架构策略：利用大模型处理复杂重构与需求分析，中模型保障代码补全与审查的响应速度，微模型负责本地向量化检索","build-your-ai-coding-assistant 是一套由 Thoughtworks 开源社区推出的实战指南，旨在帮助开发者从零开始构建属于自己的端到端 AI 辅助编程助手。它不仅仅是一个简单的教程，更提供了从 IDE 插件开发、模型选型、高质量数据集构建到模型微调的完整解决方案，让企业或个人能够打造类似 GitHub Copilot 或 JetBrains AI Assistant 的定制化工具。\n\n该方案主要解决了通用 AI 编码工具难以完全适配企业内部特定需求、数据隐私顾虑以及特定场景（如需求生成、自动化测试、代码审查）优化不足的问题。通过提供 AutoDev 插件（支持 IntelliJ 和 VSCode）、Unit Eval 数据集工具等配套开源项目，用户可以灵活定义 AI 能力边界。\n\n这套方案特别适合希望提升研发效能的开发团队、对 AI 工程化感兴趣的研究人员，以及想要深入理解大模型在代码领域应用的技术极客。其独特的技术亮点在于提出了“一大一中一微”的三模型架构策略：利用大模型处理复杂重构与需求分析，中模型保障代码补全与审查的响应速度，微模型负责本地向量化检索，从而在生成质量与响应延迟之间取得最佳平衡。无论你是想微调 DeepSeek Coder 等开源模型，还是希望设计专属的 AI 编码工作流，build-your-ai-coding-assistant 都能为你提供坚实的技术底座与实践路径。","# [AI 研发提效：构建 AI 辅助编码助手](https:\u002F\u002Funit-mesh.github.io\u002Fbuild-your-ai-coding-assistant\u002F)\n\n![Cover](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_79b72214cc92.jpeg)\n\n2023 年，生成式 AI 的火爆，让越来越多的组织开始引入 AI 辅助编码。与在 2021 年发布的 GitHub Copilot 稍有差异的是，代码补全只是众多场景中的一个。\n大量的企业内部在探索结合需求生成完整代码、代码审查等场景，也引入生成式 AI，来提升开发效率。\n\n在这个背景下，我们（Thoughtworks 开源社区）也开源了一系列的 AI 辅助工具，以帮助更多的组织构建自己的 AI 辅助编码助手：\n\n- [AutoDev for Intellij](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev)，基于 JetBrains 平台的全流程 AI 辅助编码工具。\n- [AutoDev for VSCode](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev-vscode)，基于 VSCode 编辑器的全流程 AI 辅助编码工具。\n- [Unit Eval](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval)，代码补全场景下的高质量数据集构建与生成工具。\n- [Unit Minions](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-minions)，在需求生成、测试生成等测试场景下，基于数据蒸馏的数据集构建工具。\n\n由于，我们设计 AutoDev 时，各类开源模型也在不断演进。在这个背景下，它的步骤是：\n\n- 构建 IDE 插件与度量体系设计。基于公开模型 API，编写和丰富 IDE 插件功能。\n- 模型评估体系与微调试验。\n- 围绕意图的数据工程与模型演进。\n\n也因此，这个教程也是围绕于这三个步骤展开的。 除此，基于我们的经验，本教程的示例技术栈：\n\n- 插件：Intellij IDEA。AutoDev 是基于 Intellij IDEA 构建的，并且自带静态代码分析能力，所以基于它作为示例。我们也提供了 VSCode\n  插件版本：[AutoDev for VSCode](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev-vscode)，你可以在这个基础上进行开发。\n- 模型：[DeepSeek Coder 6.7b](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-instruct)。基于 Llama 2 架构，与 Llama\n  生态兼容\n- 微调：Deepspeed + 官方脚本 + Unit Eval。\n- GPU：RTX 4090x2 + [OpenBayes](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU)。（PS: 用我的专用邀请链接，注册\n  OpenBayes，双方各获得 60 分钟 RTX 4090 使用时长，支持累积，永久有效：\n  https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU ）\n\n由于，我们在 AI 方面的经验相对比较有限，难免会有一些错误，所以，我们也希望能够与更多的开发者一起，来构建这个开源项目。\n\n## 功能设计：定义你的 AI 助手\n\n结合 JetBrains 2023《开发者生态系统》报告的[人工智能部分](https:\u002F\u002Fwww.jetbrains.com\u002Fzh-cn\u002Flp\u002Fdevecosystem-2023\u002Fai\u002F)\n，我们可以总结出一些通用的场景，这些场景反映了在开发过程中生成式 AI 可以发挥作用的领域。以下是一些主要的场景：\n\n- 代码自动补全： 在日常编码中，生成式 AI 可以通过分析上下文和学习代码模式，提供智能的代码自动补全建议，从而提高开发效率。\n- 解释代码： 生成式 AI 能够解释代码，帮助开发者理解特定代码片段的功能和实现方式，提供更深层次的代码理解支持。\n- 生成代码： 通过学习大量的代码库和模式，生成式 AI 可以生成符合需求的代码片段，加速开发过程，尤其在重复性工作中发挥重要作用。\n- 代码审查： 生成式 AI 能够进行代码审查，提供高质量的建议和反馈，帮助开发者改进代码质量、遵循最佳实践。\n- 自然语言查询： 开发者可以使用自然语言查询与生成式 AI 进行交互，提出问题或请求，以获取相关代码片段、文档或解释，使得开发者更轻松地获取需要的信息。\n- 其它。诸如于重构、提交信息生成、建模、提交总结等。\n\n而在我们构建 AutoDev 时，也发现了诸如于创建 SQL DDL、生成需求、TDD 等场景。所以。我们提供了自定义场景的能力，以让开发者可以自定义自己的\nAI\n能力，详细见：[https:\u002F\u002Fide.unitmesh.cc\u002Fcustomize](https:\u002F\u002Fide.unitmesh.cc\u002Fcustomize)。\n\n### 场景驱动架构设计：平衡模型速度与能力\n\n在日常编码时，会存在几类不同场景，对于 AI 响应速度的要求也是不同的（仅作为示例）：\n\n| 场景          | 响应速度 | 生成质量要求 | 大小预期 | 说明                                    |\n|-------------|------|--------|------|---------------------------------------|\n| 代码补全        | 快    | 中      | 1~6B   | 代码补全是日常编码中最常用的场景，响应速度至关重要。            |\n| 文档生成        | 中    | 中      | 1~6B~  | 文档生成需要充分理解代码结构，速度和质量同样重要。             |\n| 代码审查        | 快    | 中      | 1~6B~  | 代码审查需要高质量的建议，同时响应速度也需尽可能快。            |\n| 单元测试生成      | 快    | 中      | 6B~  | 单元测试生成的上下文较少，响应速度和AI质量同样重要。           |\n| 代码重构        | 中    | 高      | 32B~ | 代码重构可能需要更多上下文理解，响应速度可适度减缓。            |\n| 需求生成        | 中    | 高      | 32B~ | 需求生成是相对复杂的场景，响应速度可以适度放缓，确保准确性。        |\n| 自然语言代码搜索与解释 | 中-低  | 高      | 32B~ | 自然语言代码搜索与解释是相对复杂的场景，响应速度可以适度放缓，确保准确性。 |                                |\n\nPS：这里的 32B 仅作为一个量级表示，因为在更大的模型下，效果会更好。\n\n因此，我们将其总结为：**一大一中一微**三模型，提供全面 AI 辅助编码：\n\n- 高质量大模型：32B~。用于代码重构、需求生成、自然语言代码搜索与解释等场景。\n- 高响应速度中模型：6B~。用于代码补全、单元测试生成、文档生成、代码审查等场景。\n- 向量化微模型：~100M。用于在 IDE 中进行向量化，诸如：代码相似度、代码相关度等。\n\n#### 重点场景介绍：补全模式\n\nAI 代码补全能结合 IDE 工具分析代码上下文和程序语言的规则，由 AI 自动生成或建议代码片段。在类似于 GitHub Copilot 的代码补全工具中，\n通常会分为三种细分模式：\n\n**行内补全（Inline）**\n\n类似于 FIM（fill in the middle）的模式，补全的内容在当前行中。诸如于：`BlotPost blogpost = new`，补全为：` BlogPost();`，\n以实现：`BlogPost blogpost = new BlogPost();`。\n\n我们可以 [Deepseek Coder](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-base) 作为例子，看在这个场景下的效果：\n\n```bash\n\u003C｜fim▁begin｜>def quick_sort(arr):\n    if len(arr) \u003C= 1:\n        return arr\n    pivot = arr[0]\n    left = []\n    right = []\n\u003C｜fim▁hole｜>\n        if arr[i] \u003C pivot:\n            left.append(arr[i])\n        else:\n            right.append(arr[i])\n    return quick_sort(left) + [pivot] + quick_sort(right)\u003C｜fim▁end｜>\n```\n\n在这里，我们就需要结合光标前和光标后的代码。\n\n**块内补全（InBlock）**\n\n通过上下文学习（In-Context Learning）来实现，补全的内容在当前函数块中。诸如于，原始的代码是：\n\n```kotlin\nfun createBlog(blogDto: CreateBlogDto): BlogPost {\n\n}\n```\n\n补全的代码为：\n\n```kotlin\n    val blogPost = BlogPost(\n    title = blogDto.title,\n    content = blogDto.content,\n    author = blogDto.author\n)\nreturn blogRepository.save(blogPost)\n```\n\n**块间补全（AfterBlock）**\n\n通过上下文学习（In-Context Learning）来实现，在当前函数块之后补全，如：在当前函数块之后补全一个新的函数。诸如于，原始的代码是：\n\n```kotlin\nfun createBlog(blogDto: CreateBlogDto): BlogPost {\n    \u002F\u002F...\n}\n```\n\n补全的代码为：\n\n```kotlin\nfun updateBlog(id: Long, blogDto: CreateBlogDto): BlogPost {\n    \u002F\u002F...\n}\n\nfun deleteBlog(id: Long) {\n    \u002F\u002F...\n}\n```\n\n在我们构建对应的 AI 补全功能时，也需要考虑应用到对应的模式数据集，以提升补全的质量，提供更好的用户体验。\n\n编写本文里的一些相关资源：\n\n- [Why your AI Code Completion tool needs to Fill in the Middle](https:\u002F\u002Fcodeium.com\u002Fblog\u002Fwhy-code-completion-needs-fill-in-the-middle)\n- [Exploring Custom LLM-Based Coding Assistance Functions](https:\u002F\u002Ftransferlab.ai\u002Fblog\u002Fautodev\u002F)\n\n#### 重点场景介绍：代码解释\n\n代码解释旨在帮助开发者更有效地管理和理解大型代码库。这些助手能够回答关于代码库的问题、 提供文档、搜索代码、识别错误源头、减少代码重复等，\n从而提高开发效率、降低错误率，并减轻开发者的工作负担。\n\n在这个场景下，取决于我们预期的生成质量，通常会由一大一微或一中一微两个模型组成，更大的模型在生成的质量上结果更好。结合，我们在\n[Chocolate Factory](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fchocolate-factory) 工具中的设计经验，通常这样的功能可以分为几步：\n\n- 理解用户意图：借助大模型理解用户意图，将其转换为对应的 AI Agent 能力调用或者 function calling 。\n- 转换意图搜索：借助模型将用户意图转换为对应的代码片段、文档或解释，结合传统搜索、路径搜索和向量化搜索等技术，进行搜索及排序。\n- 输出结果：交由大模型对最后的结果进行总结，输出给用户。\n\n作为一个 RAG 应用，其分为 indexing 和 query 两个部分。\n\n在 indexing 阶段，我们需要将代码库进行索引，并涉及到文本分割、向量化、数据库索引等技术。\n其中最有挑战的一个内容是拆分，我们参考的折分规则是：https:\u002F\u002Fdocs.sweep.dev\u002Fblogs\u002Fchunking-2m-files 。即：\n\n- 代码的平均 Token 到字符比例约为1:5（300 个 Token），而嵌入模型的 Token 上限为 512 个。\n- 1500 个字符大约对应于 40 行，大致相当于一个小到中等大小的函数或类。\n- 挑战在于尽可能接近 1500 个字符，同时确保分块在语义上相似且相关上下文连接在一起。\n\n在不同的场景下，我们也可以通过不同的方式进行折分，如在 [Chocolate Factory](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fchocolate-factory)\n是通过 AST 进行折分，以保证生成上下文的质量。\n\n在 querying 阶段，需要结合我们一些传统的搜索技术，如：向量化搜索、路径搜索等，以保证搜索的质量。同时，在中文场景下，我们也需要考虑到转换为中文\n的问题，如：将英文转换为中文，以保证搜索的质量。\n\n- 相关工具：[https:\u002F\u002Fgithub.com\u002FBloopAI\u002Fbloop](https:\u002F\u002Fgithub.com\u002FBloopAI\u002Fbloop)\n- 相关资源：\n    - [Prompt 策略：代码库 AI 助手的语义化搜索设计](https:\u002F\u002Fwww.phodal.com\u002Fblog\u002Fprompt-strategy-code-semantic-search\u002F)\n\n#### 其它：日常辅助\n\n对于日常辅助来说，我们也可以通过生成式 AI 来实现，如：自动创建 SQL DDL、自动创建测试用例、自动创建需求等。这些只需要通过自定义提示词，\n结合特定的领域知识，便可以实现，这里不再赘述。\n\n## 架构设计：上下文工程\n\n除了模型之外，上下文也是影响 AI 辅助能力的重要因素。在我们构建 AutoDev 时，我们也发现了两种不同的上下文模式：\n\n- 相关上下文：基于静态代码分析的上下文生成，可以构建更好质量的上下文，以生成更高质量的代码和测试等，依赖于 IDE 的静态代码分析能力。\n- 相似上下文：基于相似式搜索的上下文，可以构建更多的上下文，以生成更多的代码和测试等，与平台能力无关。\n\n简单对比如下：\n\n|        | 相关上下文            | 相似上下文         |\n|--------|------------------|---------------|\n| 检索技术   | 静态代码分析           | 相似式搜索         |\n| 数据结构信息 | AST、CFG          | Similar Chunk |\n| 跨平台能力  | 依赖于 IDE，或者独立的解析器 | 不依赖具体平台       |\n| 上下文质量  | 极高               | 高             |\n| 生成结果   | 极高               | 高             |\n| 构建成本   | 依赖于语言、平台         | 低             |\n\n在支持 IDE 有限时，相关上下文的才会带来更高的**性价高**。\n\n### 相似上下文架构：GitHub Copilot 案例\n\nGitHub Copilot 采用了相似上下文的架构模式，其精略的架构分层如下：\n\n- 监听用户操作（IDE API ）。监听用户的 Run Action、快捷键、UI 操作、输入等，以及最近的文档操作历史（20 个文件）。\n- IDE 胶水层（Plugin）。作为 IDE 与底层 Agent 的胶水层，处理输入和输出。\n- 上下文构建（Agent）。JSON RPC Server，处理 IDE 的各种变化，对源码进行分析，封装为 “prompt” （疑似） 并发送给服务器。\n- 服务端（Server）。处理 prompt 请求，并交给 LLM 服务端处理。\n\n在 “公开” 的 [Copilot-Explorer](https:\u002F\u002Fgithub.com\u002Fthakkarparth007\u002Fcopilot-explorer) 项目的研究资料里，可以看到 Prompt\n是如何构建出来的。如下是发送到的 prompt 请求：\n\n```json\n{\n  \"prefix\": \"# Path: codeviz\\\\app.py\\n#....\",\n  \"suffix\": \"if __name__ == '__main__':\\r\\n    app.run(debug=True)\",\n  \"isFimEnabled\": true,\n  \"promptElementRanges\": [\n    {\n      \"kind\": \"PathMarker\",\n      \"start\": 0,\n      \"end\": 23\n    },\n    {\n      \"kind\": \"SimilarFile\",\n      \"start\": 23,\n      \"end\": 2219\n    },\n    {\n      \"kind\": \"BeforeCursor\",\n      \"start\": 2219,\n      \"end\": 3142\n    }\n  ]\n}\n```\n\n其中：\n\n- 用于构建 prompt 的 `prefix` 部分，是由 promptElements\n  构建了，其中包含了：`BeforeCursor`, `AfterCursor`, `SimilarFile`, `ImportedFile`, `LanguageMarker`, `PathMarker`, `RetrievalSnippet`\n  等类型。从几种 `PromptElementKind` 的名称，我们也可以看出其真正的含义。\n- 用于构建 prompt 的 `suffix` 部分，则是由光标所在的部分决定的，根据 tokens 的上限（2048 ）去计算还有多少位置放下。而这里的\n  Token 计算则是真正的 LLM 的 token 计算，在 Copilot 里是通过 Cushman002 计算的，诸如于中文的字符的 token\n  长度是不一样的，如： `{ context: \"console.log('你好，世界')\", lineCount: 1, tokenLength: 30 }` ，其中 context 中的内容的\n  length 为 20，但是 tokenLength 是 30，中文字符共 5 个（包含 `，` ）的长度，单个字符占的 token 就是 3。\n\n如下是一个更详细的 Java 应用的上下文示例：\n\n```java\n\u002F\u002F Path: src\u002Fmain\u002Fcc\u002Funitmesh\u002Fdemo\u002Finfrastructure\u002Frepositories\u002FProductRepository.java\n\u002F\u002F Compare this snippet from src\u002Fmain\u002Fcc\u002Funitmesh\u002Fdemo\u002Fdomain\u002Fproduct\u002FProduct.java:\n\u002F\u002F ....\n\u002F\u002F Compare this snippet from src\u002Fmain\u002Fcc\u002Funitmesh\u002Fdemo\u002Fapplication\u002FProductService.java:\n\u002F\u002F ...\n\u002F\u002F @Component\n\u002F\u002F public class ProductService {\n\u002F\u002F     \u002F\u002F...\n\u002F\u002F }\n\u002F\u002F \npackage cc.unitmesh.demo.repositories;\n\n\u002F\u002F ...\n\n@Component\npublic class ProductRepository {\n\u002F\u002F...\n```\n\n在计算上下文里，GitHub Copilot 采用的是 [Jaccard 系数](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FJaccard_index) (Jaccard Similarity)\n，这部分的实现是在 Agent 实现，更详细的逻辑可以参考：\n[花了大半个月，我终于逆向分析了Github Copilot](https:\u002F\u002Fgithub.com\u002Fmengjian-github\u002Fcopilot-analysis)。\n\n相关资源：\n\n- [上下文工程：基于 Github Copilot 的实时能力分析与思考](https:\u002F\u002Fwww.phodal.com\u002Fblog\u002Fllm-context-engineering\u002F)\n\n### 相关上下文架构：AutoDev 与 JetBrains AI Assistant 案例\n\n如上所述，相关代码依赖于**静态代码分析**，主要借助于代码的结构信息，如：AST、CFG、DDG 等。在不同的场景和平台之下，我们可以结合不同的静态代码分析工具，\n如下是常见的一些静态代码分析工具：\n\n- [TreeSitter](https:\u002F\u002Ftree-sitter.github.io\u002Ftree-sitter\u002F)，由 GitHub 开发的用于生成高效的自定义语法分析器的框架。\n- [Intellij PSI](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fpsi.html) （Program Structure Interface），由 JetBrains 开发的用于其\n  IDE 的静态代码分析接口。\n- [LSP](https:\u002F\u002Flangserver.org\u002F)（Language Server Protocol），由微软开发的用于 IDE 的通用语言服务器协议。\n- [Chapi](https:\u002F\u002Fgithub.com\u002Fphodal\u002Fchapi) (common hierarchical abstract parser implementation)\n  ，由笔者（@phodal）开发的用于通用的静态代码分析工具。\n\n在补全场景下，通过静态代码分析，我们可以得到当前的上下文，如：当前的函数、当前的类、当前的文件等。如下是一个 AutoDev\n的生成单元测试的上下文示例：\n\n```java\n\u002F\u002F here are related classes:\n\u002F\u002F 'filePath: \u002FUsers\u002Fphodal\u002FIdeaProjects\u002Funtitled\u002Fsrc\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Funtitled\u002Fdemo\u002Fservice\u002FBlogService.java\n\u002F\u002F class BlogService {\n\u002F\u002F   blogRepository\n\u002F\u002F   + public BlogPost createBlog(BlogPost blogDto)\n\u002F\u002F   + public BlogPost getBlogById(Long id)\n\u002F\u002F   + public BlogPost updateBlog(Long id, BlogPost blogDto)\n\u002F\u002F   + public void deleteBlog(Long id)\n\u002F\u002F }\n\u002F\u002F 'filePath: \u002FUsers\u002Fphodal\u002FIdeaProjects\u002Funtitled\u002Fsrc\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Funtitled\u002Fdemo\u002Fdto\u002FCreateBlogRequest.java\n\u002F\u002F class CreateBlogRequest ...\n\u002F\u002F 'filePath: \u002FUsers\u002Fphodal\u002FIdeaProjects\u002Funtitled\u002Fsrc\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Funtitled\u002Fdemo\u002Fentity\u002FBlogPost.java\n\u002F\u002F class BlogPost {...\n@ApiOperation(value = \"Create a new blog\")\n@PostMapping(\"\u002F\")\npublic BlogPost createBlog(@RequestBody CreateBlogRequest request) {\n```\n\n在这个示例中，会分析 `createBlog` 函数的上下文，获取函数的输入和输出类： `CreateBlogRequest`、`BlogPost` 信息，以及\nBlogService 类信息，作为上下文（在注释中提供）提供给模型。在这时，模型会生成更准确的构造函数，以及更准确的测试用例。\n\n由于相关上下文依赖于对不同语言的静态代码分析、不同 IDE 的 API，所以，我们也需要针对不同的语言、不同的 IDE\n进行适配。在构建成本上，相对于相似上下文成本更高。\n\n## 步骤 1：构建 IDE 插件与度量体系设计\n\nIDE、编辑器作为开发者的主要工具，其设计和学习成本也相对比较高。首先，我们可以用官方提供的模板生成：\n\n- [IDEA 插件模板](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-platform-plugin-template)\n- [VSCode 插件生成](https:\u002F\u002Fcode.visualstudio.com\u002Fapi\u002Fget-started\u002Fyour-first-extension)\n\n然后，再往上添加功能（是不是很简单），当然不是。以下是一些可以参考的 IDEA 插件资源：\n\n- [Intellij Community 版本源码](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community)\n- [IntelliJ SDK Docs Code Samples](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-sdk-code-samples)\n- [Intellij Rust](https:\u002F\u002Fgithub.com\u002Fintellij-rust\u002Fintellij-rust)\n\n当然了，更合适的是参考[AutoDev 插件](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev)。\n\n### JetBrains 插件\n\n可以直接使用官方的模板来生成对应的插件：[https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-platform-plugin-template](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-platform-plugin-template)\n\n![Use this template](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_8264c006edf4.png)\n\n对于 IDEA 插件实现来说，主要是通过 Action 和 Listener 来实现的，只需要在 `plugin.xml` 中注册即可。\n详细可以参考官方文档：[IntelliJ Platform Plugin SDK](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fwelcome.html)\n\n#### 版本兼容与兼容架构\n\n由于我们前期未 AutoDev 考虑到对 IDE 版本的兼容问题，后期为了兼容旧版本的 IDE，我们需要对插件进行兼容性处理。所以，如官方文档：[Build Number Ranges](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fbuild-number-ranges.html)\n中所描述，我们可以看到不同版本，对于 JDK 的要求是不一样的，如下是不同版本的要求：\n\n| Branch number                                                   | IntelliJ Platform version                                                                                                            |\n|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|\n| [233](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F233) | 2023.3                                                                                                                               |\n| [232](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F232) | 2023.2                                                                                                                               |\n| [231](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F231) | 2023.1                                                                                                                               |\n| [223](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F223) | 2022.3                                                                                                                               |\n| [222](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F222) | 2022.2 NOTE Java 17 is now required ([blog post](https:\u002F\u002Fblog.jetbrains.com\u002Fplatform\u002F2022\u002F08\u002Fintellij-project-migrates-to-java-17\u002F)) |\n| [221](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F221) | 2022.1                                                                                                                               |\n| [213](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F213) | 2021.3                                                                                                                               |\n| [212](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F212) | 2021.2                                                                                                                               |\n| [211](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F211) | 2021.1                                                                                                                               |\n| [203](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F203) | 2020.3 NOTE Java 11 is now required ([blog post](https:\u002F\u002Fblog.jetbrains.com\u002Fplatform\u002F2020\u002F09\u002Fintellij-project-migrates-to-java-11\u002F)) |\n\n并配置到 `gradle.properties` 中：\n\n```properties\npluginSinceBuild = 223\npluginUntilBuild = 233.*\n```\n\n后续配置兼容性比较麻烦，可以参考 AutoDev 的设计。\n\n#### 补全模式：Inlay\n\n在自动代码补全上，国内的厂商主要参考的是 GitHub Copilot 的实现，逻辑也不复杂。\n\n**采用快捷键方式触发**\n\n其主要是在 Action 里监听用户的输入，然后:\n\n| 功能                 | 快捷键         | 说明                    |\n|--------------------|-------------|-----------------------|\n| requestCompletions | `Alt` + `\u002F` | 获取当前的上下文，然后通过模型获取补全结果 |\n| applyInlays        | `TAB`       | 将补全结果展示在 IDE 上        |\n| disposeInlays      | `ESC`       | 取消补全                  |\n| cycleNextInlays    | `Alt` + `]` | 切换到下一个补全结果            |\n| cyclePrevInlays    | `Alt` + `[` | 切换到上一个补全结果            |\n\n**采用自动触发方式**\n\n其主要通过 `EditorFactoryListener` 监听用户的输入，然后：根据不同的输入，触发不同的补全结果。核心代码如下：\n\n```kotlin\nclass AutoDevEditorListener : EditorFactoryListener {\n    override fun editorCreated(event: EditorFactoryEvent) {\n        \u002F\u002F...\n        editor.document.addDocumentListener(AutoDevDocumentListener(editor), editorDisposable)\n        editor.caretModel.addCaretListener(AutoDevCaretListener(editor), editorDisposable)\n        \u002F\u002F...\n    }\n\n    class AutoDevCaretListener(val editor: Editor) : CaretListener {\n        override fun caretPositionChanged(event: CaretEvent) {\n            \u002F\u002F...\n            val wasTypeOver = TypeOverHandler.getPendingTypeOverAndReset(editor)\n            \u002F\u002F...\n            llmInlayManager.disposeInlays(editor, InlayDisposeContext.CaretChange)\n        }\n    }\n\n    class AutoDevDocumentListener(val editor: Editor) : BulkAwareDocumentListener {\n        override fun documentChangedNonBulk(event: DocumentEvent) {\n            \u002F\u002F...\n            val llmInlayManager = LLMInlayManager.getInstance()\n            llmInlayManager\n                .editorModified(editor, changeOffset)\n        }\n    }\n}\n```\n\n再根据不同的输入，触发不同的补全结果，并对结构进行处理。\n\n**渲染补全代码**\n\n随后，我们需要实现一个 Inlay Render，它继承自 `EditorCustomElementRenderer`。\n\n#### 日常辅助功能开发\n\n结合 IDE 的接口能力，我们需要添加对应的 Action，以及对应的 Group，以及对应的 Icon。如下是一个 Action 的示例：\n\n`\u003Cadd-to-group group-id=\"ShowIntentionsGroup\" relative-to-action=\"ShowIntentionActions\" anchor=\"after\"\u002F>`\n\n如下是 AutoDev 的一些 ActionGroup：\n\n| Group ID               | AI 用途               | Description                                                     |\n|------------------------|---------------------|-----------------------------------------------------------------|\n| ShowIntentionsGroup    | 代码重构、代码解释、代码生成、代码测试 | 用于在代码上下文中显示提示，以及通过 `Alt + Enter` 和 macOS 上的 `⌥ + Enter` 快捷键来访问。 |\n| ConsoleEditorPopupMenu | 修复错误                | 在控制台中显示的菜单，如程序运行结构的控制台。                                         |\n| Vcs.MessageActionGroup | 代码信息生成              | 用于在 VCS 中编写提交信息的菜单。                                             |\n| Vcs.Log.ContextMenu    | 代码审查、代码解释、代码生成      | 用于在 VCS 中查看日志的菜单，可实现的功能：AI 检视代码、生成发布日志。                         |\n| EditorPopupMenu        | 皆可                  | 右键菜单，还可添加对应的 ActionGroup                                        |\n\n在编写 ShowIntentionsGroup 时，我们可以参考 AutoDev 的实现来构建对应的 Group：\n\n```xml\n\n\u003Cgroup id=\"AutoDevIntentionsActionGroup\" class=\"cc.unitmesh.devti.intentions.IntentionsActionGroup\"\n       icon=\"cc.unitmesh.devti.AutoDevIcons.AI_COPILOT\" searchable=\"false\">\n    \u003Cadd-to-group group-id=\"ShowIntentionsGroup\" relative-to-action=\"ShowIntentionActions\" anchor=\"after\"\u002F>\n\u003C\u002Fgroup>\n```\n\n#### 多语言上下文架构\n\n由于 Intellij 的平台策略，使得运行于 Java IDE（Intellij IDEA）与在其它 IDE 如 Python\nIDE（Pycharm）之间的差异性变得更大。我们需要提供基于多平台产品的兼容性，详细介绍可以参考：[Plugin Compatibility with IntelliJ Platform Products](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fplugin-compatibility.html)\n\n首先，将插件的架构进一步模块化，即针对于不同的语言，提供不同的模块。如下是 AutoDev 的模块化架构：\n\n```bash\njava\u002F   # Java 语言插件\n  src\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Fautodev\u002F # Java 语言入口\n  src\u002Fmain\u002Fresources\u002FMETA-INF\u002Fplugin.xml\nplugin\u002F # 多平台入口\n  src\u002Fmain\u002Fresources\u002FMETA-INF\u002Fplugin.xml\nsrc\u002F    # 即核心模块\n  main\u002Fresource\u002FMETA-INF\u002Fcore.plugin.xml\n```\n\n在 `plugin\u002Fplugin.xml` 中，我们需要添加对应的 `depends`，以及 `extensions`，如下是一个示例：\n\n```xml\n\u003Cidea-plugin package=\"cc.unitmesh\" xmlns:xi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXInclude\" allow-bundled-update=\"true\">\n    \u003Cxi:include href=\"\u002FMETA-INF\u002Fcore.xml\" xpointer=\"xpointer(\u002Fidea-plugin\u002F*)\"\u002F>\n    \u003Ccontent>\n        \u003Cmodule name=\"cc.unitmesh.java\"\u002F>\n            \u003C!--  其它模块 -->\n    \u003C\u002Fcontent>\n\u003C\u002Fidea-plugin>\n```\n\n而在 `java\u002Fplugin.xml` 中，我们需要添加对应的 `depends`，以及 `extensions`，如下是一个示例：\n\n```xml\n\u003Cidea-plugin package=\"cc.unitmesh.java\">\n  \u003C!--suppress PluginXmlValidity -->\n  \u003Cdependencies>\n    \u003Cplugin id=\"com.intellij.modules.java\"\u002F>\n    \u003Cplugin id=\"org.jetbrains.plugins.gradle\"\u002F>\n  \u003C\u002Fdependencies>\n\u003C\u002Fidea-plugin>\n```\n\n随后，Intellij 会自动加载对应的模块，以实现多语言的支持。根据我们预期支持的不同语言，便需要对应的 `plugin.xml`，诸如于：\n\n```bash\ncc.unitmesh.javascript.xml\ncc.unitmesh.rust.xml\ncc.unitmesh.python.xml\ncc.unitmesh.kotlin.xml\ncc.unitmesh.java.xml\ncc.unitmesh.go.xml\ncc.unitmesh.cpp.xml\n```\n\n最后，在不同的语言模块里，实现对应的功能即可。\n\n### 上下文构建\n\n为了简化这个过程，我们使用 Unit Eval 来展示如何构建两种类似的上下文。\n\n#### 静态代码分析\n\n通过静态代码分析，我们可以得到当前的函数、当前的类、当前的文件等。再结合路径相似性，寻找最贴进的上下文。\n\n```kotlin\nprivate fun findRelatedCode(container: CodeContainer): List\u003CCodeDataStruct> {\n    \u002F\u002F 1. collects all similar data structure by imports if exists in a file tree\n    val byImports = container.Imports\n        .mapNotNull {\n            context.fileTree[it.Source]?.container?.DataStructures\n        }\n        .flatten()\n\n    \u002F\u002F 2. collects by inheritance tree for some node in the same package\n    val byInheritance = container.DataStructures\n        .map {\n            (it.Implements + it.Extend).mapNotNull { i ->\n                context.fileTree[i]?.container?.DataStructures\n            }.flatten()\n        }\n        .flatten()\n\n    val related = (byImports + byInheritance).distinctBy { it.NodeName }\n    \u002F\u002F 3. convert all similar data structure to uml\n    return related\n}\n\nclass RelatedCodeStrategyBuilder(private val context: JobContext) : CodeStrategyBuilder {\n    override fun build(): List\u003CTypedIns> {\n        \u002F\u002F ...\n        val findRelatedCodeDs = findRelatedCode(container)\n        val relatedCodePath = findRelatedCodeDs.map { it.FilePath }\n        val jaccardSimilarity = SimilarChunker.pathLevelJaccardSimilarity(relatedCodePath, currentPath)\n        val relatedCode = jaccardSimilarity.mapIndexed { index, d ->\n            findRelatedCodeDs[index] to d\n        }.sortedByDescending {\n            it.second\n        }.take(3).map {\n            it.first\n        }\n        \u002F\u002F...\n    }\n}\n```\n\n上述的代码，我们可以通过代码的 Imports 信息作为相关代码的一部分。再通过代码的继承关系，来寻找相关的代码。最后，通过再路径相似性，来寻找最贴近的上下文。\n\n#### 相关代码分析\n\n先寻找，再通过代码相似性，来寻找相关的代码。核心逻辑所示：\n\n```kotlin\nfun pathLevelJaccardSimilarity(chunks: List\u003CString>, text: String): List\u003CDouble> {\n    \u002F\u002F...\n}\nfun tokenize(chunk: String): List\u003CString> {\n    return chunk.split(Regex(\"[^a-zA-Z0-9]\")).filter { it.isNotBlank() }\n}\nfun similarityScore(set1: Set\u003CString>, set2: Set\u003CString>): Double {\n    \u002F\u002F...\n}\n```\n\n详细见：[SimilarChunker](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval\u002Fblob\u002Fmaster\u002Funit-core\u002Fsrc\u002Fmain\u002Fkotlin\u002Fcc\u002Funitmesh\u002Fcore\u002Fintelli\u002FSimilarChunker.kt)\n\n### VSCode 插件\n\nTODO\n\n#### TreeSitter\n\n> TreeSitter 是一个用于生成高效的自定义语法分析器的框架，由 GitHub 开发。它使用 LR（1）解析器，这意味着它可以在 O（n）时间内解析任何语言，而不是\nO（n²）时间。它还使用了一种称为“语法树的重用”的技术，该技术使其能够在不重新解析整个文件的情况下更新语法树。\n\n由于 TreeSitter 已经提供了多语言的支持，你可以使用 Node.js、Rust 等语言来构建对应的插件。详细见：[TreeSitter](https:\u002F\u002Ftree-sitter.github.io\u002Ftree-sitter\u002F)。\n\n根据我们的意图不同，使用 TreeSitter 也有不同的方式：\n\n**解析 Symbol**\n\n在代码自然语言搜索引擎 [Bloop](https:\u002F\u002Fgithub.com\u002FBloopAI\u002Fbloop) 中，我们使用 TreeSitter 来解析 Symbol，以实现更好的搜索质量。\n\n```scheme\n;; methods\n(method_declaration \n  name: (identifier) @hoist.definition.method)\n```\n\n随后，根据不同的类型来决定如何显示：\n\n```rust\npub static JAVA: TSLanguageConfig = TSLanguageConfig {\n    language_ids: &[\"Java\"],\n    file_extensions: &[\"java\"],\n    grammar: tree_sitter_java::language,\n    scope_query: MemoizedQuery::new(include_str!(\".\u002Fscopes.scm\")),\n    hoverable_query: MemoizedQuery::new(\n        r#\"\n        [(identifier)\n         (type_identifier)] @hoverable\n        \"#,\n    ),\n    namespaces: &[&[\n        \u002F\u002F variables\n        \"local\",\n        \u002F\u002F functions\n        \"method\",\n        \u002F\u002F namespacing, modules\n        \"package\",\n        \"module\",\n        \u002F\u002F types\n        \"class\",\n        \"enum\",\n        \"enumConstant\",\n        \"record\",\n        \"interface\",\n        \"typedef\",\n        \u002F\u002F misc.\n        \"label\",\n    ]],\n};\n```\n\n**Chunk 代码**\n\n如下是 [Improving LlamaIndex’s Code Chunker\nby Cleaning Tree-Sitter CSTs](https:\u002F\u002Fdocs.sweep.dev\u002Fblogs\u002Fchunking-improvements) 中的\nTreeSitter 的使用方式：\n\n```python\nfrom tree_sitter import Tree\n \ndef chunker(\n\ttree: Tree,\n\tsource_code: bytes,\n\tMAX_CHARS=512 * 3,\n\tcoalesce=50 # Any chunk less than 50 characters long gets coalesced with the next chunk\n) -> list[Span]:\n \n    # 1. Recursively form chunks based on the last post (https:\u002F\u002Fdocs.sweep.dev\u002Fblogs\u002Fchunking-2m-files)\n    def chunk_node(node: Node) -> list[Span]:\n        chunks: list[Span] = []\n        current_chunk: Span = Span(node.start_byte, node.start_byte)\n        node_children = node.children\n        for child in node_children:\n            if child.end_byte - child.start_byte > MAX_CHARS:\n                chunks.append(current_chunk)\n                current_chunk = Span(child.end_byte, child.end_byte)\n                chunks.extend(chunk_node(child))\n            elif child.end_byte - child.start_byte + len(current_chunk) > MAX_CHARS:\n                chunks.append(current_chunk)\n                current_chunk = Span(child.start_byte, child.end_byte)\n            else:\n                current_chunk += Span(child.start_byte, child.end_byte)\n        chunks.append(current_chunk)\n        return chunks\n    chunks = chunk_node(tree.root_node)\n \n    # 2. Filling in the gaps\n    for prev, curr in zip(chunks[:-1], chunks[1:]):\n        prev.end = curr.start\n    curr.start = tree.root_node.end_byte\n \n    # 3. Combining small chunks with bigger ones\n    new_chunks = []\n    current_chunk = Span(0, 0)\n    for chunk in chunks:\n        current_chunk += chunk\n        if non_whitespace_len(current_chunk.extract(source_code)) > coalesce \\\n            and \"\\n\" in current_chunk.extract(source_code):\n            new_chunks.append(current_chunk)\n            current_chunk = Span(chunk.end, chunk.end)\n    if len(current_chunk) > 0:\n        new_chunks.append(current_chunk)\n \n    # 4. Changing line numbers\n    line_chunks = [Span(get_line_number(chunk.start, source_code),\n                    get_line_number(chunk.end, source_code)) for chunk in new_chunks]\n \n    # 5. Eliminating empty chunks\n    line_chunks = [chunk for chunk in line_chunks if len(chunk) > 0]\n \n    return line_chunks\n```\n\n### 度量体系设计\n\n#### 常用指标\n\n**代码接受率**\n\nAI 生成的代码被开发者接受的比例。\n\n**入库率**\n\nAI 生成的代码被开发者入库的比例。\n\n#### 开发者体验驱动\n\n如微软和 GitHub\n所构建的：[DevEx: What Actually Drives Productivity: The developer-centric approach to measuring and improving productivity](https:\u002F\u002Fdl.acm.org\u002Fdoi\u002F10.1145\u002F3595878)\n\n| -                | 反馈回路                                                           | 认知负荷                                         | 流畅状态                                                |\n|------------------|----------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------|\n| 感知 \u003Cbr> 人的态度和观点  | • 对自动化测试速度和输出的满意度\u003Cbr>• 对验证本地更改所需时间的满意度\u003Cbr>• 对部署更改至生产环境所需时间的满意度 | • 对代码库复杂性的感知\u003Cbr>• 调试生产系统的易用性\u003Cbr>• 理解文档的易用性   | • 对专注度和避免中断的感知\u003Cbr>• 对任务或项目目标清晰度的满意度\u003Cbr>• 值班对生产的中断感知 |\n| 工作流 \u003Cbr> 系统和流程行为 | • 生成CI结果所需时间\u003Cbr>• 代码审查周转时间\u003Cbr>• 部署交付时间（将更改发布至生产所需时间）           | • 获取技术问题答案所需时间\u003Cbr>• 部署更改所需的手动步骤\u003Cbr>• 文档改进的频率 | • 无会议或中断的时间块数量\u003Cbr>• 未计划任务或请求的频率\u003Cbr>• 需要团队关注的事故频率    |\n| 绩效指标 \u003Cbr> 北极星指标  | • 传递软件的整体感知轻松度\u003Cbr>• 员工参与度或满意度\u003Cbr>• 感知生产力                       | 同左                                           | 同左                                                  |\n\n## 步骤 2：模型评估体系与微调试验\n\n主流的论文和评估数据集以 [HumanEval](https:\u002F\u002Fgithub.com\u002Fopenai\u002Fhuman-eval) 为主，而我们想构建的是面向企业用途的编码模型。所以，我们暂时\n不会针对于这个数据集进行评估，而是结合我们的业务场景，来构建对应的评估体系。\n\n简单来说，HumanEval 以 Python 语言为主，导致各种模型、数据集在 Python 能力强，而像 Java 的能力弱、少。所以，我们在持续优化自身的数据集，\n并构建更好的数据工程。\n\n我们的微调模型下载：\n\n- [https:\u002F\u002Fhuggingface.co\u002Funit-mesh\u002Fautodev-deepseek-6.7b-finetunes](https:\u002F\u002Fhuggingface.co\u002Funit-mesh\u002Fautodev-deepseek-6.7b-finetunes)\n- OpenBayes: [deepseek-coder-6.7b-instruct-finetune](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fphodal\u002Fmodels\u002FrCmer1KQSgp\u002F9\u002Foverview)\n\n由于我们使用的是国内云 GPU，受限于网络问题，我们在 HuggingFace 上的模型更新速度比较慢（有时速度慢，就懒得更新了）。\n\n### 模型选择与测试\n\n在结合公开 API 的大语言模型之后，我们就可以构建基本的 IDE 功能。随后，应该进一步探索适合于内部的模型，以适合于组织内部的效果。\n\n#### 模型选择\n\n现有的开源模型里采用 LLaMA 架构相对比较多，并且由于其模型的质量比较高，其生态也相对比较完善。因此，我们也采用 LLaMA\n架构来构建，即：[DeepSeek Coder](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-base)。\n\n#### OpenBayes 平台部署与测试\n\n随后，我们需要部署模型，并提供一个对应的 API，这个 API 需要与我们的 IDE 接口保持一致。这里我们采用了 OpenBayes\n平台来部署模型。详细见：`code\u002Fserver` 目录下的相关代码。\n\n```bash\npip install -r requirements.txt\npython server-python38.py\n```\n\n如下是适用于 OpenBayes 的代码，以在后台提供公网 API：\n\n```python\nif __name__ == \"__main__\":\n    try:\n        meta = requests.get('http:\u002F\u002Flocalhost:21999\u002Fgear-status', timeout=5).json()\n        url = meta['links'].get('auxiliary')\n        if url:\n            print(\"打开该链接访问:\", url)\n    except Exception:\n        pass\n\n    uvicorn.run(app, host=\"0.0.0.0\", port=8080)\n```\n\n随后，在 IDE 插件中，我们就可以结合他们来测试功能。\n\n#### 大规模模型部署\n\n结合模型量化技术，如 INT4，可以实现 6B 模型在消费级的显卡上进行本地部署。\n\n（TODO)\n\n### 模型微调\n\n有监督微调（SFT）是指采用预先训练好的神经网络模型，并针对你自己的专门任务在少量的监督数据上对其进行重新训练的技术。\n\n### 数据驱动的微调方法\n\n结合 【[SFT最佳实践](https:\u002F\u002Fcloud.baidu.com\u002Fdoc\u002FWENXINWORKSHOP\u002Fs\u002FXlkb0e6eu)\n】中提供的权衡考虑：\n\n- 样本数量少于 1000 且需注重基座模型的通用能力：优先考虑 LoRA。\n- 如果特定任务数据样本较多且主要注重这些任务效果：使用 SFT。\n- 如果希望结合两者优势：将特定任务的数据与通用任务数据进行混合配比后，再使用这些训练方法能得到更好的效果。\n\n这就意味着：\n\n| 任务类型        | 样本数量      | 通用编码数据集 |\n|-------------|-----------|---------|\n| IDE AI 功能支持 | 少于 1000   | 需要      |\n| 内部代码补全      | 大于 10,000 | 不需要     |\n| IDE + 代码补全  | 大于 10,000 | 需要      |\n\n通常来说，我们测试是结合 IDE 的功能，以及代码补全的功能，因此，我们需要合并两个数据集。\n\n### 数据集构建\n\n根据不同的模型，其所需要的指令也是不同的。如下是一个基于 DeepSeek + DeepSpeed 的数据集示例：\n\n```json\n{\n  \"instruction\": \"Write unit test for following code.\\n\u003CSomeCode>\",\n  \"output\": \"\u003CTestCode>\"\n}\n```\n\n下面是 LLaMA 模型的数据集示例：\n\n```json\n{\n  \"instruction\": \"Write unit test for following code.\",\n  \"input\": \"\u003CSomeCode>\",\n  \"output\": \"\u003CTestCode>\"\n}\n```\n\n#### 数据集构建\n\n我们构建 [Unit Eval](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval) 项目，以生成更适合于 AutoDev 的数据集。\n\n- 代码补全。行内（Inline）、块内（InBlock）、块间（AfterBlock）三种场景。\n- 单元测试生成。生成符合上下文的单元测试。\n\n而为了提供 IDE 中的其他功能支持，我们结合了开源数据集，以及数据蒸馏的方式来构建数据集。\n\n#### 开源数据集\n\n在 GitHub、HuggingFace 等平台上，有一些开源的数据集。\n\n[Magicoder: Source Code Is All You Need](https:\u002F\u002Farxiv.org\u002Fabs\u002F2312.02120) 中开源的两个数据集：\n\n- [https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-OSS-Instruct-75K](https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-OSS-Instruct-75K)\n- [https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-Evol-Instruct-110K](https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-Evol-Instruct-110K)\n\n在 License 合适的情况下，我们可以直接使用这些数据集；在不合适的情况下，我们可以拿来做一些实验。\n\n#### 数据蒸馏\n\n数据蒸馏。过去的定义是，即将大型真实数据集（训练集）作为输入，并输出一个小的合成蒸馏数据集。但是，我们要做的是直接用 OpenAI 这一类公开 API 的模型：\n\n- 生成符合预期的数据集。\n- 对数据集进行筛选，以保证数据集的质量。\n- 对数据集进行扩充，以保证数据集的多样性。\n- 对数据集进行标注，以保证数据集的可用性。\n\n### 微调示例：OpenBayes + DeepSeek \n\n在这里我们使用的是，以及 DeepSeek 官方提供的脚本来进行微调。\n\n- 云 GPU： [OpenBayes](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU)\n- GPU 算力：4090x2 （目测和微调参数有关，但是我试了几次 4090 还是不行）\n- 微调脚本：[https:\u002F\u002Fgithub.com\u002Fdeepseek-ai\u002FDeepSeek-Coder](https:\u002F\u002Fgithub.com\u002Fdeepseek-ai\u002FDeepSeek-Coder)\n- 数据集：6000\n\n我在 OpenBayes 上传了的 DeepSeek 模型：[OpenBayes deepseek-coder-6.7b-instruct](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fphodal\u002Fmodels\u002FzV91IERweWd\u002F1\u002Foverview)，你可以在创建时直接使用这个模型。\n\n![Finetune Model Choice](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_cf80f3ca29d2.jpg)\n\n#### 数据集示例 1\n\n由 Unit Eval + OSS Instruct 数据集构建而来：\n\n- 150 条补全（Inline，InBlock，AfterBlock）数据集。\n- 150 条单元测试数据集。\n- 3700 条 OSS Instruct 数据集。\n\n而从结果来看，如何保持高质量的数据是最大的挑战。\n\n测试视频：[开源 AI 辅助编程方案：Unit Mesh 端到端打通 v0.0.1 版本](https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1si4y1h7Vw\u002F)\n\n在 Unit Eval [0.3.2](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval\u002Freleases\u002Ftag\u002Fv0.3.2) 版本里\n\n组成如下：\n\n```python\n# Merge and shuffle records from different files\nmerge_jsonl(\n    output_file=merged_file,\n    input_files=[oss_instruction, 'code_bugfix_cleaned_5K.json', 'codeGPT_CN_cleaned_20K.json',\n                 'code_summarization_CN_cleaned_10K.json', 'java-code-completion.jsonl', 'java-test-gen.jsonl',\n                 'kotlin-completion-11929.jsonl', 'kotlin-java-comments-3715.jsonl'],\n    lines_per_file=[4000, 4000, 15000, 8000, 5000, 3000, 3000, 2000 ]\n)\n```\n\n#### 参数示例：\n\n```bash\nDATA_PATH=\"\u002Fopenbayes\u002Fhome\u002Fsummary.jsonl\"\nOUTPUT_PATH=\"\u002Fopenbayes\u002Fhome\u002Foutput\"\n\nMODEL_PATH=\"\u002Fopenbayes\u002Finput\u002Finput0\u002F\"\n\n!cd DeepSeek-Coder\u002Ffinetune && deepspeed finetune_deepseekcoder.py \\\n    --model_name_or_path $MODEL_PATH \\\n    --data_path $DATA_PATH \\\n    --output_dir $OUTPUT_PATH \\\n    --num_train_epochs 1 \\\n    --model_max_length 1024 \\\n    --per_device_train_batch_size 8 \\\n    --per_device_eval_batch_size 1 \\\n    --gradient_accumulation_steps 1 \\\n    --evaluation_strategy \"no\" \\\n    --save_strategy \"steps\" \\\n    --save_steps 375 \\\n    --save_total_limit 10 \\\n    --learning_rate 1e-4 \\\n    --warmup_steps 10 \\\n    --logging_steps 1 \\\n    --lr_scheduler_type \"cosine\" \\\n    --gradient_checkpointing True \\\n    --report_to \"tensorboard\" \\\n    --deepspeed configs\u002Fds_config_zero3.json \\\n    --bf16 True\n```\n\n运行日志：\n\n```bash\n`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`...\n  0%|                                                   | 0\u002F375 [00:00\u003C?, ?it\u002Fs]`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`...\n{'loss': 0.6934, 'learning_rate': 0.0, 'epoch': 0.0}                            \n{'loss': 0.3086, 'learning_rate': 3.0102999566398115e-05, 'epoch': 0.01}        \n{'loss': 0.3693, 'learning_rate': 4.771212547196624e-05, 'epoch': 0.01}         \n{'loss': 0.3374, 'learning_rate': 6.020599913279623e-05, 'epoch': 0.01}         \n{'loss': 0.4744, 'learning_rate': 6.989700043360187e-05, 'epoch': 0.01}         \n{'loss': 0.3465, 'learning_rate': 7.781512503836436e-05, 'epoch': 0.02}         \n{'loss': 0.4258, 'learning_rate': 8.450980400142567e-05, 'epoch': 0.02}         \n{'loss': 0.4027, 'learning_rate': 9.030899869919434e-05, 'epoch': 0.02}         \n{'loss': 0.2844, 'learning_rate': 9.542425094393248e-05, 'epoch': 0.02}         \n{'loss': 0.3783, 'learning_rate': 9.999999999999999e-05, 'epoch': 0.03}   \n```\n\n其它：\n\n- 详细的 Notebook 见：[code\u002Ffinetune\u002Ffinetune.ipynb](code\u002Ffinetune\u002Ffinetune.ipynb)\n- 微调参数，详细见：[Trainer](https:\u002F\u002Fhuggingface.co\u002Fdocs\u002Ftransformers\u002Fv4.36.1\u002Fzh\u002Fmain_classes\u002Ftrainer)\n\n### 发布模型\n\n发布到 [Huggingface](https:\u002F\u002Fhuggingface.co\u002Fdocs\u002Fhub\u002Frepositories-getting-started) \n\n先配置 lfs：`git lfs install`\n\n```\ngit init .\ngit lfs track \"*.safetensors\"\ngit add .gitattributes \n\ngit add .\ngit commit -m \"First model version\"\ngit push\n```\n\n## 步骤 3：围绕意图的数据工程与模型演进\n\n![Unit Tools Workflow](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_6e59ac44240c.png)\n\nUnit Eval 是一个针对于构建高质量代码微调的开源工具箱。其三个核心设计原则：\n\n- 统一提示词（Prompt）。统一工具-微调-评估底层的提示词。\n- 代码质量管道。诸如于代码复杂性、代码坏味道、测试坏味道、API 设计味道等。\n- 可扩展的质量阈。自定义规则、自定义阈值、自定义质量类型等。\n\n即要解决易于测试的数据集生成，以及易于评估的模型评估问题。\n\n### IDE 指令设计与演化\n\nAutoDev 早期采用的是 OpenAI API，其模型能力较强，因此在指令设计上比较强大。而当我们需要微调里，我们需要更简单、易于区分的指令来构建。\n\n#### 模板指令\n\n如下是在 AutoDev 中精简化后的 Prompt 示例：\n\n    Write unit test for following code.\n    \n    ${context.testFramework}\n    ${context.coreFramework}\n    ${context.testSpec}\n    \n    ```${context.language}\n    ${context.related_model} \n    ${context.selection}\n    ```\n\n其中包含了：\n\n- 技术栈上下文\n- 测试技术栈上下文\n- 代码块（类、函数）的输入和输出信息\n\n而这个模板指令，也是我们在 Unit Eval 中所采用的指令。\n\n#### 统一指令模板\n\n为了实现统一的指令模板，我们引入了 Apache Velocity 模板引擎来实现，并通过 Chocolate Factory 实现底层的通用逻辑：\n\n- 工具侧。在 IDE 插件中，直接通过 Velocity 模板引擎、基于 Chocolate Factory 来实现指令的生成。\n- 数据集成。在 Unit Eval 中，生成适用于模板的数据集。\n- 结果评估。基于 Chocolate Factory 的实现，对模板的结果进行评估。\n\n### 高质量数据集生成\n\n年初（2023 年 4 月），我们做了一系列的代码微调探索， 在那篇\n《[AI 研发提效的正确姿势：开源 LLM + LoRA](https:\u002F\u002Fwww.phodal.com\u002Fblog\u002Fllm-lora-for-engineering-effectiveness-solution\u002F)\n》里，企业应该开始着力于：\n\n- **规范与流程标准化**\n- **工程化的数据准备**\n- **高质量的脱敏数据**\n\n只有微调是不够的，模型需要与工具紧密相结合。\n\n#### 质量流水线设计示例\n\n![Code Quality Workflow](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_c39765e75224.png)\n\n基于 Thoughtworks 在软件工程的丰富经验，以及 Thoughtworks 的架构治理开源工具 [ArchGuard](https:\u002F\u002Farchguard.org\u002F) 作为基础设施。\n在 UnitEval 中，我们也将代码质量的筛选构建成 pipeline 的方式：\n\n- 代码复杂度。在当前的版本设计里，可以直接通过代码复杂度来决定是否放代码文件进入数据库。\n- 不同的坏味道检查类型。诸如于代码坏味道、测试坏味道等。\n- 特定的规则检查。Controller 的 API 设计、Repository 的 SQL 设计 等。\n\n而基于 ArchGuard 中所提供的丰富代码质量和架构质量分析能力，诸如 OpenAPI、 SCA（软件依赖分析）能力，我们也在思考未来是否也加入相关的设计。\n\n#### 实现高质量数据集生成\n\n如下是 Unit Eval 0.3.0 的主要代码逻辑：\n\n```kotlin\nval codeDir = GitUtil\n    .checkoutCode(config.url, config.branch, tempGitDir, config.gitDepth)\n    .toFile().canonicalFile\n\nlogger.info(\"start walk $codeDir\")\n\nval languageWorker = LanguageWorker()\nval workerManager = WorkerManager(\n    WorkerContext(\n        config.codeContextStrategies,\n        config.codeQualityTypes,\n        config.insOutputConfig,\n        pureDataFileName = config.pureDataFileName(),\n        config.completionTypes,\n        config.maxCompletionEachFile,\n        config.completionTypeSize,\n        qualityThreshold = InsQualityThreshold(\n            complexity = InsQualityThreshold.MAX_COMPLEXITY,\n            fileSize = InsQualityThreshold.MAX_FILE_SIZE,\n            maxLineInCode = config.maxLineInCode,\n            maxCharInCode = config.maxCharInCode,\n            maxTokenLength = config.maxTokenLength,\n        )\n    )\n)\nworkerManager.init(codeDir, config.language)\n```\n\n随后是根据不同的质量门禁，来进行不同的质量检查：\n\n```kotlin\nfun filterByThreshold(job: InstructionFileJob) {\n    val summary = job.fileSummary\n    if (!supportedExtensions.contains(summary.extension)) {\n        return\n    }\n\n    \u002F\u002F limit by complexity\n    if (summary.complexity > context.qualityThreshold.complexity) {\n        logger.info(\"skip file ${summary.location} for complexity ${summary.complexity}\")\n        return\n    }\n\n    \u002F\u002F like js minified file\n    if (summary.binary || summary.generated || summary.minified) {\n        return\n    }\n\n    \u002F\u002F if the file size is too large, we just try 64k\n    if (summary.bytes > context.qualityThreshold.fileSize) {\n        logger.info(\"skip file ${summary.location} for size ${summary.bytes}\")\n        return\n    }\n\n    \u002F\u002F limit by token length\n    val encoded = enc.encode(job.code)\n    val length = encoded.size\n    if (length > context.qualityThreshold.maxTokenLength) {\n        logger.info(\"skip file ${summary.location} for over ${context.qualityThreshold.maxTokenLength} tokens\")\n        println(\"| filename: ${summary.filename} |  tokens: $length | complexity: ${summary.complexity} | code: ${summary.lines} | size: ${summary.bytes} | location: ${summary.location} |\")\n        return\n    }\n\n    val language = SupportedLang.from(summary.language)\n    val worker = workers[language] ?: return\n    worker.addJob(job)\n}\n```\n\n在过虑之后，我们就可以由不同语言的 Worker 来进行处理，诸如 JavaWorker、PythonWorker 等。\n\n```kotlin\nval lists = jobs.map { job ->\n    val jobContext = JobContext(\n        job,\n        context.qualityTypes,\n        fileTree,\n        context.insOutputConfig,\n        context.completionTypes,\n        context.maxCompletionInOneFile,\n        project = ProjectContext(\n            compositionDependency = context.compositionDependency,\n        ),\n        context.qualityThreshold\n    )\n\n    context.codeContextStrategies.map { type ->\n        val codeStrategyBuilder = type.builder(jobContext)\n        codeStrategyBuilder.build()\n    }.flatten()\n}.flatten()\n```\n\n根据用户选择的上下文策略，我们就可以构建出不同的上下文，如：相关上下文、相似上下文等\n\n#### 在上下文策略中检查代码质量\n\nSimilarChunksStrategyBuilder 主要逻辑如下\n\n1. 使用配置中指定的规则检查以识别存在问题的数据结构。\n2. 收集所有具有相似数据结构的数据结构。\n3. 为每个被识别的数据结构中的函数构建完成生成器。\n4. 过滤掉具有空的前置和后置光标的完成生成器。\n5. 使用JavaSimilarChunker计算块补全的相似块。\n6. 为每个完成生成器创建SimilarChunkIns对象，包括语言、前置光标、相似块、后置光标、输出和类型的相关信息。\n7. 返回生成的SimilarChunkIns对象的列表。\n\n在规则检查里，我们可以通过不同的规则来检查不同的代码质量问题，如：代码坏味道、测试坏味道、API 设计味道等。\n\n```kotlin\nfun create(types: List\u003CCodeQualityType>, thresholds: Map\u003CString, Int> = mapOf()): List\u003CQualityAnalyser> {\n    return types.map { type ->\n        when (type) {\n            CodeQualityType.BadSmell -> BadsmellAnalyser(thresholds)\n            CodeQualityType.TestBadSmell -> TestBadsmellAnalyser(thresholds)\n            CodeQualityType.JavaController -> JavaControllerAnalyser(thresholds)\n            CodeQualityType.JavaRepository -> JavaRepositoryAnalyser(thresholds)\n            CodeQualityType.JavaService -> JavaServiceAnalyser(thresholds)\n        }\n    }\n}\n```\n\n## 附：相关资源\n\nTODO\n\n### 开源 AI 辅助工具\n\n### 开源模型\n\n### 开源数据集\n\n","# [AI 研发提效：构建 AI 辅助编码助手](https:\u002F\u002Funit-mesh.github.io\u002Fbuild-your-ai-coding-assistant\u002F)\n\n![Cover](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_79b72214cc92.jpeg)\n\n2023 年，生成式 AI 的火爆，让越来越多的组织开始引入 AI 辅助编码。与在 2021 年发布的 GitHub Copilot 稍有差异的是，代码补全只是众多场景中的一个。\n大量的企业内部在探索结合需求生成完整代码、代码审查等场景，也引入生成式 AI，来提升开发效率。\n\n在这个背景下，我们（Thoughtworks 开源社区）也开源了一系列的 AI 辅助工具，以帮助更多的组织构建自己的 AI 辅助编码助手：\n\n- [AutoDev for Intellij](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev)，基于 JetBrains 平台的全流程 AI 辅助编码工具。\n- [AutoDev for VSCode](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev-vscode)，基于 VSCode 编辑器的全流程 AI 辅助编码工具。\n- [Unit Eval](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval)，代码补全场景下的高质量数据集构建与生成工具。\n- [Unit Minions](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-minions)，在需求生成、测试生成等测试场景下，基于数据蒸馏的数据集构建工具。\n\n由于，我们设计 AutoDev 时，各类开源模型也在不断演进。在这个背景下，它的步骤是：\n\n- 构建 IDE 插件与度量体系设计。基于公开模型 API，编写和丰富 IDE 插件功能。\n- 模型评估体系与微调试验。\n- 围绕意图的数据工程与模型演进。\n\n也因此，这个教程也是围绕于这三个步骤展开的。 除此，基于我们的经验，本教程的示例技术栈：\n\n- 插件：Intellij IDEA。AutoDev 是基于 Intellij IDEA 构建的，并且自带静态代码分析能力，所以基于它作为示例。我们也提供了 VSCode\n  插件版本：[AutoDev for VSCode](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev-vscode)，你可以在这个基础上进行开发。\n- 模型：[DeepSeek Coder 6.7b](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-instruct)。基于 Llama 2 架构，与 Llama\n  生态兼容\n- 微调：Deepspeed + 官方脚本 + Unit Eval。\n- GPU：RTX 4090x2 + [OpenBayes](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU)。（PS: 用我的专用邀请链接，注册\n  OpenBayes，双方各获得 60 分钟 RTX 4090 使用时长，支持累积，永久有效：\n  https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU ）\n\n由于，我们在 AI 方面的经验相对比较有限，难免会有一些错误，所以，我们也希望能够与更多的开发者一起，来构建这个开源项目。\n\n## 功能设计：定义你的 AI 助手\n\n结合 JetBrains 2023《开发者生态系统》报告的[人工智能部分](https:\u002F\u002Fwww.jetbrains.com\u002Fzh-cn\u002Flp\u002Fdevecosystem-2023\u002Fai\u002F)\n，我们可以总结出一些通用的场景，这些场景反映了在开发过程中生成式 AI 可以发挥作用的领域。以下是一些主要的场景：\n\n- 代码自动补全： 在日常编码中，生成式 AI 可以通过分析上下文和学习代码模式，提供智能的代码自动补全建议，从而提高开发效率。\n- 解释代码： 生成式 AI 能够解释代码，帮助开发者理解特定代码片段的功能和实现方式，提供更深层次的代码理解支持。\n- 生成代码： 通过学习大量的代码库和模式，生成式 AI 可以生成符合需求的代码片段，加速开发过程，尤其在重复性工作中发挥重要作用。\n- 代码审查： 生成式 AI 能够进行代码审查，提供高质量的建议和反馈，帮助开发者改进代码质量、遵循最佳实践。\n- 自然语言查询： 开发者可以使用自然语言查询与生成式 AI 进行交互，提出问题或请求，以获取相关代码片段、文档或解释，使得开发者更轻松地获取需要的信息。\n- 其它。诸如于重构、提交信息生成、建模、提交总结等。\n\n而在我们构建 AutoDev 时，也发现了诸如于创建 SQL DDL、生成需求、TDD 等场景。所以。我们提供了自定义场景的能力，以让开发者可以自定义自己的\nAI\n能力，详细见：[https:\u002F\u002Fide.unitmesh.cc\u002Fcustomize](https:\u002F\u002Fide.unitmesh.cc\u002Fcustomize)。\n\n### 场景驱动架构设计：平衡模型速度与能力\n\n在日常编码时，会存在几类不同场景，对于 AI 响应速度的要求也是不同的（仅作为示例）：\n\n| 场景          | 响应速度 | 生成质量要求 | 大小预期 | 说明                                    |\n|-------------|------|--------|------|---------------------------------------|\n| 代码补全        | 快    | 中      | 1~6B   | 代码补全是日常编码中最常用的场景，响应速度至关重要。            |\n| 文档生成        | 中    | 中      | 1~6B~  | 文档生成需要充分理解代码结构，速度和质量同样重要。             |\n| 代码审查        | 快    | 中      | 1~6B~  | 代码审查需要高质量的建议，同时响应速度也需尽可能快。            |\n| 单元测试生成      | 快    | 中      | 6B~  | 单元测试生成的上下文较少，响应速度和AI质量同样重要。           |\n| 代码重构        | 中    | 高      | 32B~ | 代码重构可能需要更多上下文理解，响应速度可适度减缓。            |\n| 需求生成        | 中    | 高      | 32B~ | 需求生成是相对复杂的场景，响应速度可以适度放缓，确保准确性。        |\n| 自然语言代码搜索与解释 | 中-低  | 高      | 32B~ | 自然语言代码搜索与解释是相对复杂的场景，响应速度可以适度放缓，确保准确性。 |                                |\n\nPS：这里的 32B 仅作为一个量级表示，因为在更大的模型下，效果会更好。\n\n因此，我们将其总结为：**一大一中一微**三模型，提供全面 AI 辅助编码：\n\n- 高质量大模型：32B~。用于代码重构、需求生成、自然语言代码搜索与解释等场景。\n- 高响应速度中模型：6B~。用于代码补全、单元测试生成、文档生成、代码审查等场景。\n- 向量化微模型：~100M。用于在 IDE 中进行向量化，诸如：代码相似度、代码相关度等。\n\n#### 重点场景介绍：补全模式\n\nAI 代码补全能结合 IDE 工具分析代码上下文和程序语言的规则，由 AI 自动生成或建议代码片段。在类似于 GitHub Copilot 的代码补全工具中，\n通常会分为三种细分模式：\n\n**行内补全（Inline）**\n\n类似于 FIM（fill in the middle）的模式，补全的内容在当前行中。诸如于：`BlotPost blogpost = new`，补全为：` BlogPost();`，\n以实现：`BlogPost blogpost = new BlogPost();`。\n\n我们可以 [Deepseek Coder](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-base) 作为例子，看在这个场景下的效果：\n\n```bash\n\u003C｜fim▁begin｜>def quick_sort(arr):\n    if len(arr) \u003C= 1:\n        return arr\n    pivot = arr[0]\n    left = []\n    right = []\n\u003C｜fim▁hole｜>\n        if arr[i] \u003C pivot:\n            left.append(arr[i])\n        else:\n            right.append(arr[i])\n    return quick_sort(left) + [pivot] + quick_sort(right)\u003C｜fim▁end｜>\n```\n\n在这里，我们就需要结合光标前和光标后的代码。\n\n**块内补全（InBlock）**\n\n通过上下文学习（In-Context Learning）来实现，补全的内容在当前函数块中。诸如于，原始的代码是：\n\n```kotlin\nfun createBlog(blogDto: CreateBlogDto): BlogPost {\n\n}\n```\n\n补全的代码为：\n\n```kotlin\n    val blogPost = BlogPost(\n    title = blogDto.title,\n    content = blogDto.content,\n    author = blogDto.author\n)\nreturn blogRepository.save(blogPost)\n```\n\n**块间补全（AfterBlock）**\n\n通过上下文学习（In-Context Learning）来实现，在当前函数块之后补全，如：在当前函数块之后补全一个新的函数。诸如于，原始的代码是：\n\n```kotlin\nfun createBlog(blogDto: CreateBlogDto): BlogPost {\n    \u002F\u002F...\n}\n```\n\n补全的代码为：\n\n```kotlin\nfun updateBlog(id: Long, blogDto: CreateBlogDto): BlogPost {\n    \u002F\u002F...\n}\n\nfun deleteBlog(id: Long) {\n    \u002F\u002F...\n}\n```\n\n在我们构建对应的 AI 补全功能时，也需要考虑应用到对应的模式数据集，以提升补全的质量，提供更好的用户体验。\n\n编写本文里的一些相关资源：\n\n- [Why your AI Code Completion tool needs to Fill in the Middle](https:\u002F\u002Fcodeium.com\u002Fblog\u002Fwhy-code-completion-needs-fill-in-the-middle)\n- [Exploring Custom LLM-Based Coding Assistance Functions](https:\u002F\u002Ftransferlab.ai\u002Fblog\u002Fautodev\u002F)\n\n#### 重点场景介绍：代码解释\n\n代码解释旨在帮助开发者更有效地管理和理解大型代码库。这些助手能够回答关于代码库的问题、 提供文档、搜索代码、识别错误源头、减少代码重复等，\n从而提高开发效率、降低错误率，并减轻开发者的工作负担。\n\n在这个场景下，取决于我们预期的生成质量，通常会由一大一微或一中一微两个模型组成，更大的模型在生成的质量上结果更好。结合，我们在\n[Chocolate Factory](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fchocolate-factory) 工具中的设计经验，通常这样的功能可以分为几步：\n\n- 理解用户意图：借助大模型理解用户意图，将其转换为对应的 AI Agent 能力调用或者 function calling 。\n- 转换意图搜索：借助模型将用户意图转换为对应的代码片段、文档或解释，结合传统搜索、路径搜索和向量化搜索等技术，进行搜索及排序。\n- 输出结果：交由大模型对最后的结果进行总结，输出给用户。\n\n作为一个 RAG 应用，其分为 indexing 和 query 两个部分。\n\n在 indexing 阶段，我们需要将代码库进行索引，并涉及到文本分割、向量化、数据库索引等技术。\n其中最有挑战的一个内容是拆分，我们参考的折分规则是：https:\u002F\u002Fdocs.sweep.dev\u002Fblogs\u002Fchunking-2m-files 。即：\n\n- 代码的平均 Token 到字符比例约为1:5（300 个 Token），而嵌入模型的 Token 上限为 512 个。\n- 1500 个字符大约对应于 40 行，大致相当于一个小到中等大小的函数或类。\n- 挑战在于尽可能接近 1500 个字符，同时确保分块在语义上相似且相关上下文连接在一起。\n\n在不同的场景下，我们也可以通过不同的方式进行折分，如在 [Chocolate Factory](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fchocolate-factory)\n是通过 AST 进行折分，以保证生成上下文的质量。\n\n在 querying 阶段，需要结合我们一些传统的搜索技术，如：向量化搜索、路径搜索等，以保证搜索的质量。同时，在中文场景下，我们也需要考虑到转换为中文\n的问题，如：将英文转换为中文，以保证搜索的质量。\n\n- 相关工具：[https:\u002F\u002Fgithub.com\u002FBloopAI\u002Fbloop](https:\u002F\u002Fgithub.com\u002FBloopAI\u002Fbloop)\n- 相关资源：\n    - [Prompt 策略：代码库 AI 助手的语义化搜索设计](https:\u002F\u002Fwww.phodal.com\u002Fblog\u002Fprompt-strategy-code-semantic-search\u002F)\n\n#### 其它：日常辅助\n\n对于日常辅助来说，我们也可以通过生成式 AI 来实现，如：自动创建 SQL DDL、自动创建测试用例、自动创建需求等。这些只需要通过自定义提示词，\n结合特定的领域知识，便可以实现，这里不再赘述。\n\n## 架构设计：上下文工程\n\n除了模型之外，上下文也是影响 AI 辅助能力的重要因素。在我们构建 AutoDev 时，我们也发现了两种不同的上下文模式：\n\n- 相关上下文：基于静态代码分析的上下文生成，可以构建更好质量的上下文，以生成更高质量的代码和测试等，依赖于 IDE 的静态代码分析能力。\n- 相似上下文：基于相似式搜索的上下文，可以构建更多的上下文，以生成更多的代码和测试等，与平台能力无关。\n\n简单对比如下：\n\n|        | 相关上下文            | 相似上下文         |\n|--------|------------------|---------------|\n| 检索技术   | 静态代码分析           | 相似式搜索         |\n| 数据结构信息 | AST、CFG          | Similar Chunk |\n| 跨平台能力  | 依赖于 IDE，或者独立的解析器 | 不依赖具体平台       |\n| 上下文质量  | 极高               | 高             |\n| 生成结果   | 极高               | 高             |\n| 构建成本   | 依赖于语言、平台         | 低             |\n\n在支持 IDE 有限时，相关上下文的才会带来更高的**性价高**。\n\n### 相似上下文架构：GitHub Copilot 案例\n\nGitHub Copilot 采用了相似上下文的架构模式，其精略的架构分层如下：\n\n- 监听用户操作（IDE API）。监听用户的 Run Action、快捷键、UI 操作、输入等，以及最近的文档操作历史（20 个文件）。\n- IDE 胶水层（Plugin）。作为 IDE 与底层 Agent 的胶水层，处理输入和输出。\n- 上下文构建（Agent）。JSON RPC Server，处理 IDE 的各种变化，对源码进行分析，封装为 “prompt” （疑似） 并发送给服务器。\n- 服务端（Server）。处理 prompt 请求，并交给 LLM 服务端处理。\n\n在 “公开” 的 [Copilot-Explorer](https:\u002F\u002Fgithub.com\u002Fthakkarparth007\u002Fcopilot-explorer) 项目的研究资料里，可以看到 Prompt\n是如何构建出来的。如下是发送到的 prompt 请求：\n\n```json\n{\n  \"prefix\": \"# Path: codeviz\\\\app.py\\n#....\",\n  \"suffix\": \"if __name__ == '__main__':\\r\\n    app.run(debug=True)\",\n  \"isFimEnabled\": true,\n  \"promptElementRanges\": [\n    {\n      \"kind\": \"PathMarker\",\n      \"start\": 0,\n      \"end\": 23\n    },\n    {\n      \"kind\": \"SimilarFile\",\n      \"start\": 23,\n      \"end\": 2219\n    },\n    {\n      \"kind\": \"BeforeCursor\",\n      \"start\": 2219,\n      \"end\": 3142\n    }\n  ]\n}\n```\n\n其中：\n\n- 用于构建 prompt 的 `prefix` 部分，是由 promptElements\n  构建了，其中包含了：`BeforeCursor`, `AfterCursor`, `SimilarFile`, `ImportedFile`, `LanguageMarker`, `PathMarker`, `RetrievalSnippet`\n  等类型。从几种 `PromptElementKind` 的名称，我们也可以看出其真正的含义。\n- 用于构建 prompt 的 `suffix` 部分，则是由光标所在的部分决定的，根据 tokens 的上限（2048 ）去计算还有多少位置放下。而这里的\n  Token 计算则是真正的 LLM 的 token 计算，在 Copilot 里是通过 Cushman002 计算的，诸如于中文的字符的 token\n  长度是不一样的，如： `{ context: \"console.log('你好，世界')\", lineCount: 1, tokenLength: 30 }` ，其中 context 中的内容的\n  length 为 20，但是 tokenLength 是 30，中文字符共 5 个（包含 `，` ）的长度，单个字符占的 token 就是 3。\n\n如下是一个更详细的 Java 应用的上下文示例：\n\n```java\n\u002F\u002F Path: src\u002Fmain\u002Fcc\u002Funitmesh\u002Fdemo\u002Finfrastructure\u002Frepositories\u002FProductRepository.java\n\u002F\u002F Compare this snippet from src\u002Fmain\u002Fcc\u002Funitmesh\u002Fdemo\u002Fdomain\u002Fproduct\u002FProduct.java:\n\u002F\u002F ....\n\u002F\u002F Compare this snippet from src\u002Fmain\u002Fcc\u002Funitmesh\u002Fdemo\u002Fapplication\u002FProductService.java:\n\u002F\u002F ...\n\u002F\u002F @Component\n\u002F\u002F public class ProductService {\n\u002F\u002F     \u002F\u002F...\n\u002F\u002F }\n\u002F\u002F \npackage cc.unitmesh.demo.repositories;\n\n\u002F\u002F ...\n\n@Component\npublic class ProductRepository {\n\u002F\u002F...\n```\n\n在计算上下文里，GitHub Copilot 采用的是 [Jaccard 系数](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FJaccard_index) (Jaccard Similarity)\n，这部分的实现是在 Agent 实现，更详细的逻辑可以参考：\n[花了大半个月，我终于逆向分析了Github Copilot](https:\u002F\u002Fgithub.com\u002Fmengjian-github\u002Fcopilot-analysis)。\n\n相关资源：\n\n- [上下文工程：基于 Github Copilot 的实时能力分析与思考](https:\u002F\u002Fwww.phodal.com\u002Fblog\u002Fllm-context-engineering\u002F)\n\n### 相关上下文架构：AutoDev 与 JetBrains AI Assistant 案例\n\n如上所述，相关代码依赖于**静态代码分析**，主要借助于代码的结构信息，如：AST、CFG、DDG 等。在不同的场景和平台之下，我们可以结合不同的静态代码分析工具，\n如下是常见的一些静态代码分析工具：\n\n- [TreeSitter](https:\u002F\u002Ftree-sitter.github.io\u002Ftree-sitter\u002F)，由 GitHub 开发的用于生成高效的自定义语法分析器的框架。\n- [Intellij PSI](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fpsi.html) （Program Structure Interface），由 JetBrains 开发的用于其\n  IDE 的静态代码分析接口。\n- [LSP](https:\u002F\u002Flangserver.org\u002F)（Language Server Protocol），由微软开发的用于 IDE 的通用语言服务器协议。\n- [Chapi](https:\u002F\u002Fgithub.com\u002Fphodal\u002Fchapi) (common hierarchical abstract parser implementation)\n  ，由笔者（@phodal）开发的用于通用的静态代码分析工具。\n\n在补全场景下，通过静态代码分析，我们可以得到当前的上下文，如：当前的函数、当前的类、当前的文件等。如下是一个 AutoDev\n的生成单元测试的上下文示例：\n\n```java\n\u002F\u002F here are related classes:\n\u002F\u002F 'filePath: \u002FUsers\u002Fphodal\u002FIdeaProjects\u002Funtitled\u002Fsrc\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Funtitled\u002Fdemo\u002Fservice\u002FBlogService.java\n\u002F\u002F class BlogService {\n\u002F\u002F   blogRepository\n\u002F\u002F   + public BlogPost createBlog(BlogPost blogDto)\n\u002F\u002F   + public BlogPost getBlogById(Long id)\n\u002F\u002F   + public BlogPost updateBlog(Long id, BlogPost blogDto)\n\u002F\u002F   + public void deleteBlog(Long id)\n\u002F\u002F }\n\u002F\u002F 'filePath: \u002FUsers\u002Fphodal\u002FIdeaProjects\u002Funtitled\u002Fsrc\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Funtitled\u002Fdemo\u002Fdto\u002FCreateBlogRequest.java\n\u002F\u002F class CreateBlogRequest ...\n\u002F\u002F 'filePath: \u002FUsers\u002Fphodal\u002FIdeaProjects\u002Funtitled\u002Fsrc\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Funtitled\u002Fdemo\u002Fentity\u002FBlogPost.java\n\u002F\u002F class BlogPost {...\n@ApiOperation(value = \"Create a new blog\")\n@PostMapping(\"\u002F\")\npublic BlogPost createBlog(@RequestBody CreateBlogRequest request) {\n```\n\n在这个示例中，会分析 `createBlog` 函数的上下文，获取函数的输入和输出类： `CreateBlogRequest`、`BlogPost` 信息，以及\nBlogService 类信息，作为上下文（在注释中提供）提供给模型。在这时，模型会生成更准确的构造函数，以及更准确的测试用例。\n\n由于相关上下文依赖于对不同语言的静态代码分析、不同 IDE 的 API，所以，我们也需要针对不同的语言、不同的 IDE\n进行适配。在构建成本上，相对于相似上下文成本更高。\n\n## 步骤 1：构建 IDE 插件与度量体系设计\n\nIDE、编辑器作为开发者的主要工具，其设计和学习成本也相对比较高。首先，我们可以用官方提供的模板生成：\n\n- [IDEA 插件模板](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-platform-plugin-template)\n- [VSCode 插件生成](https:\u002F\u002Fcode.visualstudio.com\u002Fapi\u002Fget-started\u002Fyour-first-extension)\n\n然后，再往上添加功能（是不是很简单），当然不是。以下是一些可以参考的 IDEA 插件资源：\n\n- [Intellij Community 版本源码](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community)\n- [IntelliJ SDK Docs Code Samples](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-sdk-code-samples)\n- [Intellij Rust](https:\u002F\u002Fgithub.com\u002Fintellij-rust\u002Fintellij-rust)\n\n当然了，更合适的是参考[AutoDev 插件](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev)。\n\n### JetBrains 插件\n\n可以直接使用官方的模板来生成对应的插件：[https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-platform-plugin-template](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-platform-plugin-template)\n\n![Use this template](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_8264c006edf4.png)\n\n对于 IDEA 插件实现来说，主要是通过 Action 和 Listener 来实现的，只需要在 `plugin.xml` 中注册即可。\n详细可以参考官方文档：[IntelliJ Platform Plugin SDK](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fwelcome.html)\n\n#### 版本兼容与兼容架构\n\n由于我们前期未 AutoDev 考虑到对 IDE 版本的兼容问题，后期为了兼容旧版本的 IDE，我们需要对插件进行兼容性处理。所以，如官方文档：[Build Number Ranges](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fbuild-number-ranges.html)\n中所描述，我们可以看到不同版本，对于 JDK 的要求是不一样的，如下是不同版本的要求：\n\n| 分支编号                                                   | IntelliJ 平台版本                                                                                                            |\n|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|\n| [233](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F233) | 2023.3                                                                                                                               |\n| [232](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F232) | 2023.2                                                                                                                               |\n| [231](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F231) | 2023.1                                                                                                                               |\n| [223](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F223) | 2022.3                                                                                                                               |\n| [222](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F222) | 2022.2 注意：现已要求使用 Java 17（[博客文章](https:\u002F\u002Fblog.jetbrains.com\u002Fplatform\u002F2022\u002F08\u002Fintellij-project-migrates-to-java-17\u002F)) |\n| [221](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F221) | 2022.1                                                                                                                               |\n| [213](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F213) | 2021.3                                                                                                                               |\n| [212](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F212) | 2021.2                                                                                                                               |\n| [211](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F211) | 2021.1                                                                                                                               |\n| [203](https:\u002F\u002Fgithub.com\u002FJetBrains\u002Fintellij-community\u002Ftree\u002F203) | 2020.3 注意：现已要求使用 Java 11（[博客文章](https:\u002F\u002Fblog.jetbrains.com\u002Fplatform\u002F2020\u002F09\u002Fintellij-project-migrates-to-java-11\u002F)) |\n\n并配置到 `gradle.properties` 中：\n\n```properties\npluginSinceBuild = 223\npluginUntilBuild = 233.*\n```\n\n后续配置兼容性比较麻烦，可以参考 AutoDev 的设计。\n\n#### 补全模式：Inlay\n\n在自动代码补全上，国内的厂商主要参考的是 GitHub Copilot 的实现，逻辑也不复杂。\n\n**采用快捷键方式触发**\n\n其主要是在 Action 里监听用户的输入，然后:\n\n| 功能                 | 快捷键         | 说明                    |\n|--------------------|-------------|-----------------------|\n| requestCompletions | `Alt` + `\u002F` | 获取当前的上下文，然后通过模型获取补全结果 |\n| applyInlays        | `TAB`       | 将补全结果展示在 IDE 上        |\n| disposeInlays      | `ESC`       | 取消补全                  |\n| cycleNextInlays    | `Alt` + `]` | 切换到下一个补全结果            |\n| cyclePrevInlays    | `Alt` + `[` | 切换到上一个补全结果            |\n\n**采用自动触发方式**\n\n其主要通过 `EditorFactoryListener` 监听用户的输入，然后：根据不同的输入，触发不同的补全结果。核心代码如下：\n\n```kotlin\nclass AutoDevEditorListener : EditorFactoryListener {\n    override fun editorCreated(event: EditorFactoryEvent) {\n        \u002F\u002F...\n        editor.document.addDocumentListener(AutoDevDocumentListener(editor), editorDisposable)\n        editor.caretModel.addCaretListener(AutoDevCaretListener(editor), editorDisposable)\n        \u002F\u002F...\n    }\n\n    class AutoDevCaretListener(val editor: Editor) : CaretListener {\n        override fun caretPositionChanged(event: CaretEvent) {\n            \u002F\u002F...\n            val wasTypeOver = TypeOverHandler.getPendingTypeOverAndReset(editor)\n            \u002F\u002F...\n            llmInlayManager.disposeInlays(editor, InlayDisposeContext.CaretChange)\n        }\n    }\n\n    class AutoDevDocumentListener(val editor: Editor) : BulkAwareDocumentListener {\n        override fun documentChangedNonBulk(event: DocumentEvent) {\n            \u002F\u002F...\n            val llmInlayManager = LLMInlayManager.getInstance()\n            llmInlayManager\n                .editorModified(editor, changeOffset)\n        }\n    }\n}\n```\n\n再根据不同的输入，触发不同的补全结果，并对结构进行处理。\n\n**渲染补全代码**\n\n随后，我们需要实现一个 Inlay Render，它继承自 `EditorCustomElementRenderer`。\n\n#### 日常辅助功能开发\n\n结合 IDE 的接口能力，我们需要添加对应的 Action，以及对应的 Group，以及对应的 Icon。如下是一个 Action 的示例：\n\n`\u003Cadd-to-group group-id=\"ShowIntentionsGroup\" relative-to-action=\"ShowIntentionActions\" anchor=\"after\"\u002F>`\n\n如下是 AutoDev 的一些 ActionGroup：\n\n| Group ID               | AI 用途               | Description                                                     |\n|------------------------|---------------------|-----------------------------------------------------------------|\n| ShowIntentionsGroup    | 代码重构、代码解释、代码生成、代码测试 | 用于在代码上下文中显示提示，以及通过 `Alt + Enter` 和 macOS 上的 `⌥ + Enter` 快捷键来访问。 |\n| ConsoleEditorPopupMenu | 修复错误                | 在控制台中显示的菜单，如程序运行结构的控制台。                                         |\n| Vcs.MessageActionGroup | 代码信息生成              | 用于在 VCS 中编写提交信息的菜单。                                             |\n| Vcs.Log.ContextMenu    | 代码审查、代码解释、代码生成      | 用于在 VCS 中查看日志的菜单，可实现的功能：AI 检视代码、生成发布日志。                         |\n| EditorPopupMenu        | 皆可                  | 右键菜单，还可添加对应的 ActionGroup                                        |\n\n在编写 ShowIntentionsGroup 时，我们可以参考 AutoDev 的实现来构建对应的 Group：\n\n```xml\n\n\u003Cgroup id=\"AutoDevIntentionsActionGroup\" class=\"cc.unitmesh.devti.intentions.IntentionsActionGroup\"\n       icon=\"cc.unitmesh.devti.AutoDevIcons.AI_COPILOT\" searchable=\"false\">\n    \u003Cadd-to-group group-id=\"ShowIntentionsGroup\" relative-to-action=\"ShowIntentionActions\" anchor=\"after\"\u002F>\n\u003C\u002Fgroup>\n```\n\n#### 多语言上下文架构\n\n由于 Intellij 的平台策略，使得运行于 Java IDE（Intellij IDEA）与在其它 IDE 如 Python\nIDE（Pycharm）之间的差异性变得更大。我们需要提供基于多平台产品的兼容性，详细介绍可以参考：[Plugin Compatibility with IntelliJ Platform Products](https:\u002F\u002Fplugins.jetbrains.com\u002Fdocs\u002Fintellij\u002Fplugin-compatibility.html)\n\n首先，将插件的架构进一步模块化，即针对于不同的语言，提供不同的模块。如下是 AutoDev 的模块化架构：\n\n```bash\njava\u002F   # Java 语言插件\n  src\u002Fmain\u002Fjava\u002Fcc\u002Funitmesh\u002Fautodev\u002F # Java 语言入口\n  src\u002Fmain\u002Fresources\u002FMETA-INF\u002Fplugin.xml\nplugin\u002F # 多平台入口\n  src\u002Fmain\u002Fresources\u002FMETA-INF\u002Fplugin.xml\nsrc\u002F    # 即核心模块\n  main\u002Fresource\u002FMETA-INF\u002Fcore.plugin.xml\n```\n\n在 `plugin\u002Fplugin.xml` 中，我们需要添加对应的 `depends`，以及 `extensions`，如下是一个示例：\n\n```xml\n\u003Cidea-plugin package=\"cc.unitmesh\" xmlns:xi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXInclude\" allow-bundled-update=\"true\">\n    \u003Cxi:include href=\"\u002FMETA-INF\u002Fcore.xml\" xpointer=\"xpointer(\u002Fidea-plugin\u002F*)\"\u002F>\n    \u003Ccontent>\n        \u003Cmodule name=\"cc.unitmesh.java\"\u002F>\n            \u003C!--  其它模块 -->\n    \u003C\u002Fcontent>\n\u003C\u002Fidea-plugin>\n```\n\n而在 `java\u002Fplugin.xml` 中，我们需要添加对应的 `depends`，以及 `extensions`，如下是一个示例：\n\n```xml\n\u003Cidea-plugin package=\"cc.unitmesh.java\">\n  \u003C!--suppress PluginXmlValidity -->\n  \u003Cdependencies>\n    \u003Cplugin id=\"com.intellij.modules.java\"\u002F>\n    \u003Cplugin id=\"org.jetbrains.plugins.gradle\"\u002F>\n  \u003C\u002Fdependencies>\n\u003C\u002Fidea-plugin>\n```\n\n随后，Intellij 会自动加载对应的模块，以实现多语言的支持。根据我们预期支持的不同语言，便需要对应的 `plugin.xml`，诸如于：\n\n```bash\ncc.unitmesh.javascript.xml\ncc.unitmesh.rust.xml\ncc.unitmesh.python.xml\ncc.unitmesh.kotlin.xml\ncc.unitmesh.java.xml\ncc.unitmesh.go.xml\ncc.unitmesh.cpp.xml\n```\n\n最后，在不同的语言模块里，实现对应的功能即可。\n\n\n\n### 上下文构建\n\n为了简化这个过程，我们使用 Unit Eval 来展示如何构建两种类似的上下文。\n\n#### 静态代码分析\n\n通过静态代码分析，我们可以得到当前的函数、当前的类、当前的文件等。再结合路径相似性，寻找最贴进的上下文。\n\n```kotlin\nprivate fun findRelatedCode(container: CodeContainer): List\u003CCodeDataStruct> {\n    \u002F\u002F 1. collects all similar data structure by imports if exists in a file tree\n    val byImports = container.Imports\n        .mapNotNull {\n            context.fileTree[it.Source]?.container?.DataStructures\n        }\n        .flatten()\n\n    \u002F\u002F 2. collects by inheritance tree for some node in the same package\n    val byInheritance = container.DataStructures\n        .map {\n            (it.Implements + it.Extend).mapNotNull { i ->\n                context.fileTree[i]?.container?.DataStructures\n            }.flatten()\n        }\n        .flatten()\n\n    val related = (byImports + byInheritance).distinctBy { it.NodeName }\n    \u002F\u002F 3. convert all similar data structure to uml\n    return related\n}\n\nclass RelatedCodeStrategyBuilder(private val context: JobContext) : CodeStrategyBuilder {\n    override fun build(): List\u003CTypedIns> {\n        \u002F\u002F ...\n        val findRelatedCodeDs = findRelatedCode(container)\n        val relatedCodePath = findRelatedCodeDs.map { it.FilePath }\n        val jaccardSimilarity = SimilarChunker.pathLevelJaccardSimilarity(relatedCodePath, currentPath)\n        val relatedCode = jaccardSimilarity.mapIndexed { index, d ->\n            findRelatedCodeDs[index] to d\n        }.sortedByDescending {\n            it.second\n        }.take(3).map {\n            it.first\n        }\n        \u002F\u002F...\n    }\n}\n```\n\n上述的代码，我们可以通过代码的 Imports 信息作为相关代码的一部分。再通过代码的继承关系，来寻找相关的代码。最后，通过再路径相似性，来寻找最贴近的上下文。\n\n#### 相关代码分析\n\n先寻找，再通过代码相似性，来寻找相关的代码。核心逻辑所示：\n\n```kotlin\nfun pathLevelJaccardSimilarity(chunks: List\u003CString>, text: String): List\u003CDouble> {\n    \u002F\u002F...\n}\nfun tokenize(chunk: String): List\u003CString> {\n    return chunk.split(Regex(\"[^a-zA-Z0-9]\")).filter { it.isNotBlank() }\n}\nfun similarityScore(set1: Set\u003CString>, set2: Set\u003CString>): Double {\n    \u002F\u002F...\n}\n```\n\n详细见：[SimilarChunker](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval\u002Fblob\u002Fmaster\u002Funit-core\u002Fsrc\u002Fmain\u002Fkotlin\u002Fcc\u002Funitmesh\u002Fcore\u002Fintelli\u002FSimilarChunker.kt)\n\n### VSCode 插件\n\nTODO\n\n#### TreeSitter\n\n> TreeSitter 是一个用于生成高效的自定义语法分析器的框架，由 GitHub 开发。它使用 LR（1）解析器，这意味着它可以在 O（n）时间内解析任何语言，而不是\nO（n²）时间。它还使用了一种称为“语法树的重用”的技术，该技术使其能够在不重新解析整个文件的情况下更新语法树。\n\n由于 TreeSitter 已经提供了多语言的支持，你可以使用 Node.js、Rust 等语言来构建对应的插件。详细见：[TreeSitter](https:\u002F\u002Ftree-sitter.github.io\u002Ftree-sitter\u002F)。\n\n根据我们的意图不同，使用 TreeSitter 也有不同的方式：\n\n**解析 Symbol**\n\n在代码自然语言搜索引擎 [Bloop](https:\u002F\u002Fgithub.com\u002FBloopAI\u002Fbloop) 中，我们使用 TreeSitter 来解析 Symbol，以实现更好的搜索质量。\n\n```scheme\n;; methods\n(method_declaration \n  name: (identifier) @hoist.definition.method)\n```\n\n随后，根据不同的类型来决定如何显示：\n\n```rust\npub static JAVA: TSLanguageConfig = TSLanguageConfig {\n    language_ids: &[\"Java\"],\n    file_extensions: &[\"java\"],\n    grammar: tree_sitter_java::language,\n    scope_query: MemoizedQuery::new(include_str!(\".\u002Fscopes.scm\")),\n    hoverable_query: MemoizedQuery::new(\n        r#\"\n        [(identifier)\n         (type_identifier)] @hoverable\n        \"#,\n    ),\n    namespaces: &[&[\n        \u002F\u002F variables\n        \"local\",\n        \u002F\u002F functions\n        \"method\",\n        \u002F\u002F namespacing, modules\n        \"package\",\n        \"module\",\n        \u002F\u002F types\n        \"class\",\n        \"enum\",\n        \"enumConstant\",\n        \"record\",\n        \"interface\",\n        \"typedef\",\n        \u002F\u002F misc.\n        \"label\",\n    ]],\n};\n```\n\n**Chunk 代码**\n\n如下是 [Improving LlamaIndex’s Code Chunker\nby Cleaning Tree-Sitter CSTs](https:\u002F\u002Fdocs.sweep.dev\u002Fblogs\u002Fchunking-improvements) 中的\nTreeSitter 的使用方式：\n\n```python\nfrom tree_sitter import Tree\n \ndef chunker(\n\ttree: Tree,\n\tsource_code: bytes,\n\tMAX_CHARS=512 * 3,\n\tcoalesce=50 # Any chunk less than 50 characters long gets coalesced with the next chunk\n) -> list[Span]:\n \n    # 1. Recursively form chunks based on the last post (https:\u002F\u002Fdocs.sweep.dev\u002Fblogs\u002Fchunking-2m-files)\n    def chunk_node(node: Node) -> list[Span]:\n        chunks: list[Span] = []\n        current_chunk: Span = Span(node.start_byte, node.start_byte)\n        node_children = node.children\n        for child in node_children:\n            if child.end_byte - child.start_byte > MAX_CHARS:\n                chunks.append(current_chunk)\n                current_chunk = Span(child.end_byte, child.end_byte)\n                chunks.extend(chunk_node(child))\n            elif child.end_byte - child.start_byte + len(current_chunk) > MAX_CHARS:\n                chunks.append(current_chunk)\n                current_chunk = Span(child.start_byte, child.end_byte)\n            else:\n                current_chunk += Span(child.start_byte, child.end_byte)\n        chunks.append(current_chunk)\n        return chunks\n    chunks = chunk_node(tree.root_node)\n \n    # 2. Filling in the gaps\n    for prev, curr in zip(chunks[:-1], chunks[1:]):\n        prev.end = curr.start\n    curr.start = tree.root_node.end_byte\n \n    # 3. Combining small chunks with bigger ones\n    new_chunks = []\n    current_chunk = Span(0, 0)\n    for chunk in chunks:\n        current_chunk += chunk\n        if non_whitespace_len(current_chunk.extract(source_code)) > coalesce \\\n            and \"\\n\" in current_chunk.extract(source_code):\n            new_chunks.append(current_chunk)\n            current_chunk = Span(chunk.end, chunk.end)\n    if len(current_chunk) > 0:\n        new_chunks.append(current_chunk)\n \n    # 4. Changing line numbers\n    line_chunks = [Span(get_line_number(chunk.start, source_code),\n                    get_line_number(chunk.end, source_code)) for chunk in new_chunks]\n \n    # 5. Eliminating empty chunks\n    line_chunks = [chunk for chunk in line_chunks if len(chunk) > 0]\n \n    return line_chunks\n```\n\n### 度量体系设计\n\n#### 常用指标\n\n**代码接受率**\n\nAI 生成的代码被开发者接受的比例。\n\n**入库率**\n\nAI 生成的代码被开发者入库的比例。\n\n#### 开发者体验驱动\n\n如微软和 GitHub\n所构建的：[DevEx: What Actually Drives Productivity: The developer-centric approach to measuring and improving productivity](https:\u002F\u002Fdl.acm.org\u002Fdoi\u002F10.1145\u002F3595878)\n\n| -                | 反馈回路                                                           | 认知负荷                                         | 流畅状态                                                |\n|------------------|----------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------|\n| 感知 \u003Cbr> 人的态度和观点  | • 对自动化测试速度和输出的满意度\u003Cbr>• 对验证本地更改所需时间的满意度\u003Cbr>• 对部署更改至生产环境所需时间的满意度 | • 对代码库复杂性的感知\u003Cbr>• 调试生产系统的易用性\u003Cbr>• 理解文档的易用性   | • 对专注度和避免中断的感知\u003Cbr>• 对任务或项目目标清晰度的满意度\u003Cbr>• 值班对生产的中断感知 |\n| 工作流 \u003Cbr> 系统和流程行为 | • 生成CI结果所需时间\u003Cbr>• 代码审查周转时间\u003Cbr>• 部署交付时间（将更改发布至生产所需时间）           | • 获取技术问题答案所需时间\u003Cbr>• 部署更改所需的手动步骤\u003Cbr>• 文档改进的频率 | • 无会议或中断的时间块数量\u003Cbr>• 未计划任务或请求的频率\u003Cbr>• 需要团队关注的事故频率    |\n| 绩效指标 \u003Cbr> 北极星指标  | • 传递软件的整体感知轻松度\u003Cbr>• 员工参与度或满意度\u003Cbr>• 感知生产力                       | 同左                                           | 同左                                                  |\n\n## 步骤 2：模型评估体系与微调试验\n\n主流的论文和评估数据集以 [HumanEval](https:\u002F\u002Fgithub.com\u002Fopenai\u002Fhuman-eval) 为主，而我们想构建的是面向企业用途的编码模型。所以，我们暂时\n不会针对于这个数据集进行评估，而是结合我们的业务场景，来构建对应的评估体系。\n\n简单来说，HumanEval 以 Python 语言为主，导致各种模型、数据集在 Python 能力强，而像 Java 的能力弱、少。所以，我们在持续优化自身的数据集，\n并构建更好的数据工程。\n\n我们的微调模型下载：\n\n- [https:\u002F\u002Fhuggingface.co\u002Funit-mesh\u002Fautodev-deepseek-6.7b-finetunes](https:\u002F\u002Fhuggingface.co\u002Funit-mesh\u002Fautodev-deepseek-6.7b-finetunes)\n- OpenBayes: [deepseek-coder-6.7b-instruct-finetune](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fphodal\u002Fmodels\u002FrCmer1KQSgp\u002F9\u002Foverview)\n\n由于我们使用的是国内云 GPU，受限于网络问题，我们在 HuggingFace 上的模型更新速度比较慢（有时速度慢，就懒得更新了）。\n\n### 模型选择与测试\n\n在结合公开 API 的大语言模型之后，我们就可以构建基本的 IDE 功能。随后，应该进一步探索适合于内部的模型，以适合于组织内部的效果。\n\n#### 模型选择\n\n现有的开源模型里采用 LLaMA 架构相对比较多，并且由于其模型的质量比较高，其生态也相对比较完善。因此，我们也采用 LLaMA\n架构来构建，即：[DeepSeek Coder](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-base)。\n\n#### OpenBayes 平台部署与测试\n\n随后，我们需要部署模型，并提供一个对应的 API，这个 API 需要与我们的 IDE 接口保持一致。这里我们采用了 OpenBayes\n平台来部署模型。详细见：`code\u002Fserver` 目录下的相关代码。\n\n```bash\npip install -r requirements.txt\npython server-python38.py\n```\n\n如下是适用于 OpenBayes 的代码，以在后台提供公网 API：\n\n```python\nif __name__ == \"__main__\":\n    try:\n        meta = requests.get('http:\u002F\u002Flocalhost:21999\u002Fgear-status', timeout=5).json()\n        url = meta['links'].get('auxiliary')\n        if url:\n            print(\"打开该链接访问:\", url)\n    except Exception:\n        pass\n\n    uvicorn.run(app, host=\"0.0.0.0\", port=8080)\n```\n\n随后，在 IDE 插件中，我们就可以结合他们来测试功能。\n\n#### 大规模模型部署\n\n结合模型量化技术，如 INT4，可以实现 6B 模型在消费级的显卡上进行本地部署。\n\n（TODO)\n\n### 模型微调\n\n有监督微调（SFT）是指采用预先训练好的神经网络模型，并针对你自己的专门任务在少量的监督数据上对其进行重新训练的技术。\n\n### 数据驱动的微调方法\n\n结合 【[SFT最佳实践](https:\u002F\u002Fcloud.baidu.com\u002Fdoc\u002FWENXINWORKSHOP\u002Fs\u002FXlkb0e6eu)\n】中提供的权衡考虑：\n\n- 样本数量少于 1000 且需注重基座模型的通用能力：优先考虑 LoRA。\n- 如果特定任务数据样本较多且主要注重这些任务效果：使用 SFT。\n- 如果希望结合两者优势：将特定任务的数据与通用任务数据进行混合配比后，再使用这些训练方法能得到更好的效果。\n\n这就意味着：\n\n| 任务类型        | 样本数量      | 通用编码数据集 |\n|-------------|-----------|---------|\n| IDE AI 功能支持 | 少于 1000   | 需要      |\n| 内部代码补全      | 大于 10,000 | 不需要     |\n| IDE + 代码补全  | 大于 10,000 | 需要      |\n\n通常来说，我们测试是结合 IDE 的功能，以及代码补全的功能，因此，我们需要合并两个数据集。\n\n### 数据集构建\n\n根据不同的模型，其所需要的指令也是不同的。如下是一个基于 DeepSeek + DeepSpeed 的数据集示例：\n\n```json\n{\n  \"instruction\": \"Write unit test for following code.\\n\u003CSomeCode>\",\n  \"output\": \"\u003CTestCode>\"\n}\n```\n\n下面是 LLaMA 模型的数据集示例：\n\n```json\n{\n  \"instruction\": \"Write unit test for following code.\",\n  \"input\": \"\u003CSomeCode>\",\n  \"output\": \"\u003CTestCode>\"\n}\n```\n\n#### 数据集构建\n\n我们构建 [Unit Eval](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval) 项目，以生成更适合于 AutoDev 的数据集。\n\n- 代码补全。行内（Inline）、块内（InBlock）、块间（AfterBlock）三种场景。\n- 单元测试生成。生成符合上下文的单元测试。\n\n而为了提供 IDE 中的其他功能支持，我们结合了开源数据集，以及数据蒸馏的方式来构建数据集。\n\n#### 开源数据集\n\n在 GitHub、HuggingFace 等平台上，有一些开源的数据集。\n\n[Magicoder: Source Code Is All You Need](https:\u002F\u002Farxiv.org\u002Fabs\u002F2312.02120) 中开源的两个数据集：\n\n- [https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-OSS-Instruct-75K](https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-OSS-Instruct-75K)\n- [https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-Evol-Instruct-110K](https:\u002F\u002Fhuggingface.co\u002Fdatasets\u002Fise-uiuc\u002FMagicoder-Evol-Instruct-110K)\n\n在 License 合适的情况下，我们可以直接使用这些数据集；在不合适的情况下，我们可以拿来做一些实验。\n\n#### 数据蒸馏\n\n数据蒸馏。过去的定义是，即将大型真实数据集（训练集）作为输入，并输出一个小的合成蒸馏数据集。但是，我们要做的是直接用 OpenAI 这一类公开 API 的模型：\n\n- 生成符合预期的数据集。\n- 对数据集进行筛选，以保证数据集的质量。\n- 对数据集进行扩充，以保证数据集的多样性。\n- 对数据集进行标注，以保证数据集的可用性。\n\n### 微调示例：OpenBayes + DeepSeek \n\n在这里我们使用的是，以及 DeepSeek 官方提供的脚本来进行微调。\n\n- 云 GPU： [OpenBayes](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU)\n- GPU 算力：4090x2 （目测和微调参数有关，但是我试了几次 4090 还是不行）\n- 微调脚本：[https:\u002F\u002Fgithub.com\u002Fdeepseek-ai\u002FDeepSeek-Coder](https:\u002F\u002Fgithub.com\u002Fdeepseek-ai\u002FDeepSeek-Coder)\n- 数据集：6000\n\n我在 OpenBayes 上传了的 DeepSeek 模型：[OpenBayes deepseek-coder-6.7b-instruct](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fphodal\u002Fmodels\u002FzV91IERweWd\u002F1\u002Foverview)，你可以在创建时直接使用这个模型。\n\n![Finetune Model Choice](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_cf80f3ca29d2.jpg)\n\n#### 数据集示例 1\n\n由 Unit Eval + OSS Instruct 数据集构建而来：\n\n- 150 条补全（Inline，InBlock，AfterBlock）数据集。\n- 150 条单元测试数据集。\n- 3700 条 OSS Instruct 数据集。\n\n而从结果来看，如何保持高质量的数据是最大的挑战。\n\n测试视频：[开源 AI 辅助编程方案：Unit Mesh 端到端打通 v0.0.1 版本](https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1si4y1h7Vw\u002F)\n\n在 Unit Eval [0.3.2](https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval\u002Freleases\u002Ftag\u002Fv0.3.2) 版本里\n\n组成如下：\n\n```python\n\n# 合并并打乱来自不同文件的记录\nmerge_jsonl(\n    output_file=merged_file,\n    input_files=[oss_instruction, 'code_bugfix_cleaned_5K.json', 'codeGPT_CN_cleaned_20K.json',\n                 'code_summarization_CN_cleaned_10K.json', 'java-code-completion.jsonl', 'java-test-gen.jsonl',\n                 'kotlin-completion-11929.jsonl', 'kotlin-java-comments-3715.jsonl'],\n    lines_per_file=[4000, 4000, 15000, 8000, 5000, 3000, 3000, 2000 ]\n)\n```\n\n#### 参数示例：\n\n```bash\nDATA_PATH=\"\u002Fopenbayes\u002Fhome\u002Fsummary.jsonl\"\nOUTPUT_PATH=\"\u002Fopenbayes\u002Fhome\u002Foutput\"\n\nMODEL_PATH=\"\u002Fopenbayes\u002Finput\u002Finput0\u002F\"\n\n!cd DeepSeek-Coder\u002Ffinetune && deepspeed finetune_deepseekcoder.py \\\n    --model_name_or_path $MODEL_PATH \\\n    --data_path $DATA_PATH \\\n    --output_dir $OUTPUT_PATH \\\n    --num_train_epochs 1 \\\n    --model_max_length 1024 \\\n    --per_device_train_batch_size 8 \\\n    --per_device_eval_batch_size 1 \\\n    --gradient_accumulation_steps 1 \\\n    --evaluation_strategy \"no\" \\\n    --save_strategy \"steps\" \\\n    --save_steps 375 \\\n    --save_total_limit 10 \\\n    --learning_rate 1e-4 \\\n    --warmup_steps 10 \\\n    --logging_steps 1 \\\n    --lr_scheduler_type \"cosine\" \\\n    --gradient_checkpointing True \\\n    --report_to \"tensorboard\" \\\n    --deepspeed configs\u002Fds_config_zero3.json \\\n    --bf16 True\n```\n\n运行日志：\n\n```bash\n`use_cache=True` 与梯度检查点不兼容。正在设置 `use_cache=False`...\n  0%|                                                   | 0\u002F375 [00:00\u003C?, ?it\u002Fs]`use_cache=True` 与梯度检查点不兼容。正在设置 `use_cache=False`...\n{'loss': 0.6934, 'learning_rate': 0.0, 'epoch': 0.0}                            \n{'loss': 0.3086, 'learning_rate': 3.0102999566398115e-05, 'epoch': 0.01}        \n{'loss': 0.3693, 'learning_rate': 4.771212547196624e-05, 'epoch': 0.01}         \n{'loss': 0.3374, 'learning_rate': 6.020599913279623e-05, 'epoch': 0.01}         \n{'loss': 0.4744, 'learning_rate': 6.989700043360187e-05, 'epoch': 0.01}         \n{'loss': 0.3465, 'learning_rate': 7.781512503836436e-05, 'epoch': 0.02}         \n{'loss': 0.4258, 'learning_rate': 8.450980400142567e-05, 'epoch': 0.02}         \n{'loss': 0.4027, 'learning_rate': 9.030899869919434e-05, 'epoch': 0.02}         \n{'loss': 0.2844, 'learning_rate': 9.542425094393248e-05, 'epoch': 0.02}         \n{'loss': 0.3783, 'learning_rate': 9.999999999999999e-05, 'epoch': 0.03}   \n```\n\n其它：\n\n- 详细的 Notebook 见：[code\u002Ffinetune\u002Ffinetune.ipynb](code\u002Ffinetune\u002Ffinetune.ipynb)\n- 微调参数，详细见：[Trainer](https:\u002F\u002Fhuggingface.co\u002Fdocs\u002Ftransformers\u002Fv4.36.1\u002Fzh\u002Fmain_classes\u002Ftrainer)\n\n### 发布模型\n\n发布到 [Huggingface](https:\u002F\u002Fhuggingface.co\u002Fdocs\u002Fhub\u002Frepositories-getting-started) \n\n先配置 lfs：`git lfs install`\n\n```\ngit init .\ngit lfs track \"*.safetensors\"\ngit add .gitattributes \n\ngit add .\ngit commit -m \"First model version\"\ngit push\n```\n\n## 步骤 3：围绕意图的数据工程与模型演进\n\n![Unit Tools Workflow](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_6e59ac44240c.png)\n\nUnit Eval 是一个针对于构建高质量代码微调的开源工具箱。其三个核心设计原则：\n\n- 统一提示词（Prompt）。统一工具-微调-评估底层的提示词。\n- 代码质量管道。诸如于代码复杂性、代码坏味道、测试坏味道、API 设计味道等。\n- 可扩展的质量阈。自定义规则、自定义阈值、自定义质量类型等。\n\n即要解决易于测试的数据集生成，以及易于评估的模型评估问题。\n\n### IDE 指令设计与演化\n\nAutoDev 早期采用的是 OpenAI API，其模型能力较强，因此在指令设计上比较强大。而当我们需要微调里，我们需要更简单、易于区分的指令来构建。\n\n#### 模板指令\n\n如下是在 AutoDev 中精简化后的 Prompt 示例：\n\n    Write unit test for following code.\n    \n    ${context.testFramework}\n    ${context.coreFramework}\n    ${context.testSpec}\n    \n    ```${context.language}\n    ${context.related_model} \n    ${context.selection}\n    ```\n\n其中包含了：\n\n- 技术栈上下文\n- 测试技术栈上下文\n- 代码块（类、函数）的输入和输出信息\n\n而这个模板指令，也是我们在 Unit Eval 中所采用的指令。\n\n#### 统一指令模板\n\n为了实现统一的指令模板，我们引入了 Apache Velocity 模板引擎来实现，并通过 Chocolate Factory 实现底层的通用逻辑：\n\n- 工具侧。在 IDE 插件中，直接通过 Velocity 模板引擎、基于 Chocolate Factory 来实现指令的生成。\n- 数据集成。在 Unit Eval 中，生成适用于模板的数据集。\n- 结果评估。基于 Chocolate Factory 的实现，对模板的结果进行评估。\n\n### 高质量数据集生成\n\n年初（2023年4月），我们进行了一系列的代码微调探索。在那篇《[AI研发提效的正确姿势：开源LLM + LoRA](https:\u002F\u002Fwww.phodal.com\u002Fblog\u002Fllm-lora-for-engineering-effectiveness-solution\u002F)》中，我们指出企业应当着重于以下三个方面：\n\n- **规范与流程标准化**\n- **工程化的数据准备**\n- **高质量的脱敏数据**\n\n仅仅进行微调是不够的，模型需要与工具紧密结合起来。\n\n#### 质量流水线设计示例\n\n![Code Quality Workflow](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_readme_c39765e75224.png)\n\n基于Thoughtworks在软件工程领域的丰富经验，以及Thoughtworks的架构治理开源工具[ArchGuard](https:\u002F\u002Farchguard.org\u002F)作为基础设施，在UnitEval中，我们将代码质量的筛选构建成流水线的方式：\n\n- 代码复杂度。在当前的版本设计里，可以直接通过代码复杂度来决定是否放代码文件进入数据库。\n- 不同的坏味道检查类型。诸如于代码坏味道、测试坏味道等。\n- 特定的规则检查。Controller的API设计、Repository的SQL设计等。\n\n而基于ArchGuard中所提供的丰富代码质量和架构质量分析能力，诸如OpenAPI、SCA（软件依赖分析）能力，我们也在思考未来是否也加入相关的设计。\n\n#### 实现高质量数据集生成\n\n如下是Unit Eval 0.3.0的主要代码逻辑：\n\n```kotlin\nval codeDir = GitUtil\n    .checkoutCode(config.url, config.branch, tempGitDir, config.gitDepth)\n    .toFile().canonicalFile\n\nlogger.info(\"start walk $codeDir\")\n\nval languageWorker = LanguageWorker()\nval workerManager = WorkerManager(\n    WorkerContext(\n        config.codeContextStrategies,\n        config.codeQualityTypes,\n        config.insOutputConfig,\n        pureDataFileName = config.pureDataFileName(),\n        config.completionTypes,\n        config.maxCompletionEachFile,\n        config.completionTypeSize,\n        qualityThreshold = InsQualityThreshold(\n            complexity = InsQualityThreshold.MAX_COMPLEXITY,\n            fileSize = InsQualityThreshold.MAX_FILE_SIZE,\n            maxLineInCode = config.maxLineInCode,\n            maxCharInCode = config.maxCharInCode,\n            maxTokenLength = config.maxTokenLength,\n        )\n    )\n)\nworkerManager.init(codeDir, config.language)\n```\n\n随后是根据不同的质量门禁，来进行不同的质量检查：\n\n```kotlin\nfun filterByThreshold(job: InstructionFileJob) {\n    val summary = job.fileSummary\n    if (!supportedExtensions.contains(summary.extension)) {\n        return\n    }\n\n    \u002F\u002F limit by complexity\n    if (summary.complexity > context.qualityThreshold.complexity) {\n        logger.info(\"skip file ${summary.location} for complexity ${summary.complexity}\")\n        return\n    }\n\n    \u002F\u002F like js minified file\n    if (summary.binary || summary.generated || summary.minified) {\n        return\n    }\n\n    \u002F\u002F if the file size is too large, we just try 64k\n    if (summary.bytes > context.qualityThreshold.fileSize) {\n        logger.info(\"skip file ${summary.location} for size ${summary.bytes}\")\n        return\n    }\n\n    \u002F\u002F limit by token length\n    val encoded = enc.encode(job.code)\n    val length = encoded.size\n    if (length > context.qualityThreshold.maxTokenLength) {\n        logger.info(\"skip file ${summary.location} for over ${context.qualityThreshold.maxTokenLength} tokens\")\n        println(\"| filename: ${summary.filename} |  tokens: $length | complexity: ${summary.complexity} | code: ${summary.lines} | size: ${summary.bytes} | location: ${summary.location} |\")\n        return\n    }\n\n    val language = SupportedLang.from(summary.language)\n    val worker = workers[language] ?: return\n    worker.addJob(job)\n}\n```\n\n在过滤之后，我们就可以由不同语言的Worker来进行处理，诸如JavaWorker、PythonWorker等。\n\n```kotlin\nval lists = jobs.map { job ->\n    val jobContext = JobContext(\n        job,\n        context.qualityTypes,\n        fileTree,\n        context.insOutputConfig,\n        context.completionTypes,\n        context.maxCompletionInOneFile,\n        project = ProjectContext(\n            compositionDependency = context.compositionDependency,\n        ),\n        context.qualityThreshold\n    )\n\n    context.codeContextStrategies.map { type ->\n        val codeStrategyBuilder = type.builder(jobContext)\n        codeStrategyBuilder.build()\n    }.flatten()\n}.flatten()\n```\n\n根据用户选择的上下文策略，我们就可以构建出不同的上下文，如：相关上下文、相似上下文等。\n\n#### 在上下文策略中检查代码质量\n\nSimilarChunksStrategyBuilder主要逻辑如下：\n\n1. 使用配置中指定的规则检查以识别存在问题的数据结构。\n2. 收集所有具有相似数据结构的数据结构。\n3. 为每个被识别的数据结构中的函数构建完成生成器。\n4. 过滤掉具有空的前置和后置光标的完成生成器。\n5. 使用JavaSimilarChunker计算块补全的相似块。\n6. 为每个完成生成器创建SimilarChunkIns对象，包括语言、前置光标、相似块、后置光标、输出和类型的相关信息。\n7. 返回生成的SimilarChunkIns对象的列表。\n\n在规则检查里，我们可以通过不同的规则来检查不同的代码质量问题，如：代码坏味道、测试坏味道、API设计味道等。\n\n```kotlin\nfun create(types: List\u003CCodeQualityType>, thresholds: Map\u003CString, Int> = mapOf()): List\u003CQualityAnalyser> {\n    return types.map { type ->\n        when (type) {\n            CodeQualityType.BadSmell -> BadsmellAnalyser(thresholds)\n            CodeQualityType.TestBadSmell -> TestBadsmellAnalyser(thresholds)\n            CodeQualityType.JavaController -> JavaControllerAnalyser(thresholds)\n            CodeQualityType.JavaRepository -> JavaRepositoryAnalyser(thresholds)\n            CodeQualityType.JavaService -> JavaServiceAnalyser(thresholds)\n        }\n    }\n}\n```\n\n## 附：相关资源\n\nTODO\n\n### 开源AI辅助工具\n\n### 开源模型\n\n### 开源数据集","# build-your-ai-coding-assistant 快速上手指南\n\n本指南基于 Thoughtworks 开源社区提供的资源，帮助开发者构建属于自己的 AI 辅助编码助手（以 AutoDev 为核心示例）。\n\n## 1. 环境准备\n\n在开始之前，请确保满足以下软硬件及依赖要求：\n\n### 系统要求\n- **操作系统**: Windows, macOS 或 Linux\n- **IDE**: \n  - 推荐：**IntelliJ IDEA** (社区版或旗舰版均可，需安装 JDK)\n  - 备选：VS Code\n- **GPU (可选但推荐用于微调)**: \n  - 推荐配置：2x RTX 4090 或同等算力\n  - 云平台替代方案：[OpenBayes](https:\u002F\u002Fopenbayes.com\u002Fconsole\u002Fsignup?r=phodal_uVxU) (注册可使用 RTX 4090 实例)\n\n### 前置依赖\n- **JDK**: 根据所选 IDE 版本要求安装 (通常 JDK 17+)\n- **Git**: 用于克隆项目代码\n- **Python**: 3.8+ (用于模型微调和数据处理)\n- **深度学习框架**: PyTorch, DeepSpeed (用于模型微调)\n\n### 推荐模型\n本教程示例采用以下开源模型（兼容 Llama 生态）：\n- **模型名称**: DeepSeek Coder 6.7b Instruct\n- **来源**: [Hugging Face](https:\u002F\u002Fhuggingface.co\u002Fdeepseek-ai\u002Fdeepseek-coder-6.7b-instruct)\n- **特点**: 基于 Llama 2 架构，适合代码补全、生成及审查场景。\n\n---\n\n## 2. 安装步骤\n\n### 步骤一：获取插件源码\n选择你使用的 IDE 平台克隆对应的 AutoDev 项目。\n\n**对于 IntelliJ IDEA 用户：**\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev.git\ncd auto-dev\n```\n\n**对于 VS Code 用户：**\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Fauto-dev-vscode.git\ncd auto-dev-vscode\n```\n\n### 步骤二：导入与构建插件 (IntelliJ 示例)\n1. 使用 IntelliJ IDEA 打开 `auto-dev` 目录。\n2. 等待 Gradle\u002FMaven 依赖下载完成。\n3. 运行 Gradle 任务构建插件：\n   ```bash\n   .\u002Fgradlew buildPlugin\n   ```\n   *注：构建完成后，插件包位于 `build\u002Fdistributions\u002F` 目录下。*\n\n4. **安装插件**:\n   - 打开 IDEA -> `Settings` (或 `Preferences`) -> `Plugins`。\n   - 点击齿轮图标 ⚙️ -> `Install Plugin from Disk...`。\n   - 选择上一步生成的 `.zip` 文件并重启 IDE。\n\n### 步骤三：准备模型环境 (微调可选)\n若需使用默认 API 可直接跳过此步。若需本地部署或微调模型：\n\n1. 安装 Python 依赖：\n   ```bash\n   pip install torch deepspeed transformers accelerate\n   ```\n2. 下载模型权重 (建议使用国内镜像加速，如 ModelScope 或 Hugging Face 镜像)：\n   ```python\n   from huggingface_hub import snapshot_download\n\n   snapshot_download(repo_id=\"deepseek-ai\u002Fdeepseek-coder-6.7b-instruct\", local_dir=\".\u002Fmodels\u002Fdeepseek-coder-6.7b\")\n   ```\n3. 配置数据集工具 (Unit Eval):\n   ```bash\n   git clone https:\u002F\u002Fgithub.com\u002Funit-mesh\u002Funit-eval.git\n   cd unit-eval\n   # 按照其 README 准备代码补全数据集\n   ```\n\n---\n\n## 3. 基本使用\n\n安装完成后，AutoDev 将作为你的智能编码助手集成在 IDE 中。\n\n### 场景一：代码自动补全 (Inline Completion)\n这是最核心的功能，类似 GitHub Copilot。\n1. 在编辑器中输入代码，例如定义一个函数开头：\n   ```java\n   public BlogPost createBlog(CreateBlogDto dto) {\n   ```\n2. 暂停输入，AI 会根据上下文（当前类、导入项、项目结构）自动灰色显示建议代码。\n3. 按 `Tab` 键接受建议，或按 `Esc` 拒绝。\n\n### 场景二：自然语言生成代码\n1. 在代码文件中按下快捷键唤起对话框 (默认为 `Alt + \\` 或通过右键菜单选择 \"AutoDev\")。\n2. 输入自然语言指令，例如：\n   > \"为当前的 BlogService 类生成一个单元测试，覆盖创建和删除博客的逻辑。\"\n3. AI 将分析当前文件及关联类（如 `BlogPost`, `BlogRepository`），生成完整的测试代码。\n\n### 场景三：自定义场景配置\n你可以针对特定需求（如生成 SQL DDL、生成提交信息）定制 AI 行为。\n1. 访问配置页面或在插件设置中找到 \"Custom Scenarios\"。\n2. 参考官方文档 [https:\u002F\u002Fide.unitmesh.cc\u002Fcustomize](https:\u002F\u002Fide.unitmesh.cc\u002Fcustomize) 添加自定义 Prompt 模板。\n3. 示例配置（生成 SQL）：\n   ```text\n   Role: Database Expert\n   Task: Generate SQL DDL based on the Java Entity class currently open.\n   Output Format: Standard MySQL CREATE TABLE statement.\n   ```\n\n### 进阶：上下文感知\nAutoDev 利用静态代码分析（PSI）提供高质量上下文。\n- **相关上下文**: 当你处理 `ProductService` 时，它会自动读取 `ProductRepository` 和 `Product` 实体类的结构，而不仅仅是文本相似度。\n- **效果**: 生成的代码更准确，变量名和类型引用错误更少。\n\n---\n\n**提示**: 为了获得最佳体验，建议在拥有良好网络环境或本地 GPU 资源的情况下运行大模型推理。如果是企业内网环境，可结合私有化部署的 DeepSeek Coder 模型使用。","某金融科技公司后端团队正在紧急重构遗留的单体支付系统，需将核心交易逻辑迁移至微服务架构，同时保证高并发下的代码质量与测试覆盖率。\n\n### 没有 build-your-ai-coding-assistant 时\n- **上下文割裂导致补全不准**：通用 AI 助手无法理解公司内部复杂的领域模型（如特定的账务状态机），行内补全经常生成不符合业务规范的代码，开发者需反复手动修正。\n- **单元测试编写耗时巨大**：面对老旧代码，人工编写覆盖边界条件的单元测试极其枯燥且易漏，导致测试覆盖率长期低于 60%，不敢轻易重构。\n- **代码审查流于形式**：资深架构师无暇逐行审查大量迁移代码，只能依赖静态检查工具，难以发现深层的逻辑漏洞或违反内部最佳实践的问题。\n- **需求转代码效率低下**：产品经理的自然语言需求文档无法直接转化为可执行的代码骨架，开发人员需花费大量时间进行“翻译”和样板代码编写。\n- **模型选型与微调门槛高**：团队想定制专属模型，但缺乏从数据集构建（Unit Eval\u002FMinions）到微调（Deepspeed）的全流程指引，陷入“有数据无模型”的困境。\n\n### 使用 build-your-ai-coding-assistant 后\n- **领域感知精准补全**：基于公司私有代码库微调的 6B 中模型，能准确识别内部账务状态机，在 IDE 中提供符合业务规范的行内与块内代码补全，采纳率提升至 85%。\n- **自动化测试生成**：利用 Unit Minions 蒸馏的数据集，AI 能自动为遗留函数生成高覆盖率的单元测试用例，包括复杂边界场景，将测试覆盖率迅速提升至 90% 以上。\n- **智能深度代码审查**：部署的 32B 大模型充当虚拟架构师，在提交前自动审查代码，不仅指出语法错误，还能针对微服务拆分提出具体的重构建议，确保架构一致性。\n- **需求直达代码实现**：通过自定义场景配置，开发者可直接输入自然语言需求，AI 自动生成包含 DTO、Service 及 Controller 的完整代码骨架，大幅减少重复劳动。\n- **端到端自主可控**：依托教程提供的完整链路（从 IDE 插件开发到模型微调），团队成功构建了完全适配自身技术栈的专属 AI 助手，数据不出域且持续进化。\n\nbuild-your-ai-coding-assistant 帮助团队从零构建了懂业务、守规范且数据安全的专属 AI 研发伙伴，将重构周期缩短了 40% 并显著提升了交付质量。","https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Funit-mesh_build-your-ai-coding-assistant_6409ec6a.png","unit-mesh","AI4SE - Asymptotic AI programming","https:\u002F\u002Foss.gittoolsai.com\u002Favatars\u002Funit-mesh_7de67081.jpg","探索 AIGC 时代的新软件架构范式。Exploring NextGen Software Generative Architectural Paradigms  with GenAI",null,"https:\u002F\u002Funitmesh.cc\u002F","https:\u002F\u002Fgithub.com\u002Funit-mesh",[81,85,89],{"name":82,"color":83,"percentage":84},"Kotlin","#A97BFF",37.4,{"name":86,"color":87,"percentage":88},"Python","#3572A5",35.1,{"name":90,"color":91,"percentage":92},"Jupyter Notebook","#DA5B0B",27.5,715,62,"2026-04-09T11:30:38",4,"未说明","必需（用于微调），推荐配置为双路 NVIDIA RTX 4090；支持通过 OpenBayes 云平台使用；模型示例为 DeepSeek Coder 6.7b 及 32B 级别大模型",{"notes":100,"python":97,"dependencies":101},"本项目主要是一套构建 AI 编码助手的教程与开源工具集，而非单一可执行脚本。核心流程包括：1. 构建 IDE 插件（基于 IntelliJ 或 VSCode）；2. 模型评估与微调（使用 Deepspeed + Unit Eval）；3. 数据工程。架构设计建议采用'一大一中一微'三模型策略：32B+ 大模型用于复杂任务（重构、需求生成），6B+ 中模型用于高频任务（补全、单测生成），~100M 微模型用于向量化搜索。微调示例基于 DeepSeek Coder 6.7b 模型。",[102,103,104,105,106,107],"IntelliJ IDEA (或 VSCode)","DeepSeek Coder (6.7b\u002F32b)","Deepspeed","Unit Eval","Unit Minions","AutoDev Plugin",[35,14,16,52],[110,111],"ai-assistants","genai","2026-03-27T02:49:30.150509","2026-04-16T08:12:14.326565",[],[116],{"id":117,"version":118,"summary_zh":77,"released_at":119},280695,"v0.0.2","2023-12-26T03:10:43"]