← 返回编程笔记
来源说明:本页是我把 GitHub 开源项目 oraios/serena 的源码(src/serena、src/solidlsp)与随仓库文档通读一遍后的个人消化整理,非官方文档翻译。项目迭代很快,具体行为以官方仓库与文档为准。

之前整理过的 ZCode 扩展机制、DeepSeek Harness、Unity 官方 Skill,其实都在回答同一个问题:怎么给编程 Agent 补能力。Serena 给出的答案是「把 IDE 的语义分析能力做成 MCP 服务器」——让任何 LLM 客户端都能像资深开发者用 IDE 那样,按符号而不是按行号去理解和修改代码。我把整个仓库读了一遍,这一页记下我认为值得记住的点。

一、Serena 是什么:一句话与三条理念

官方口号是「The IDE for Your Coding Agent」:一个基于 MCP 协议的语义代码工具包,通过语言服务器(LSP)或 JetBrains 插件,为 Claude Code、Codex、Cursor 等任何客户端提供符号级的代码检索、编辑与重构能力。三条设计理念贯穿全库:

  • 符号级操作,拒绝行号:LLM 用 name_path(如 MyClass/my_method)定位代码,行号只作为返回元数据,从不作为输入定位手段——因为对模型来说行号既费 token 又容易错位;
  • Agent-first 的工具设计:工具的 docstring 就是提示词,参数描述里写满行为指令(「优先传 relative_path 加速」「include_body 要节制」);
  • 类比 IDE 而非类比编辑器:跨文件重命名、找引用这类原本要 Agent 走 8–12 步易错操作的任务,收敛为一次原子调用。

仓库自带的评测里,不同厂商的 Agent 在不同代码库上独立给出了几乎相同的结论:Serena 最大的价值就是把多文件语义操作压成单次原子调用

二、整体架构:四层堆栈

关键代码职责
MCP 服务器mcp.py(FastMCP)协议暴露层,stdio/HTTP 两种传输
Agent 装配agent.py组装配置、上下文、模式、工具、后端、提示词
工具薄壳tools/ + facade API工具只是壳,逻辑在可复用的 facade 方法里
语义引擎code_editor.py / symbol.py / ls_manager.py符号检索、符号编辑、多语言服务器管理
SolidLSPsolidlsp/(独立 MIT 库)统一各语言服务器的方言,JSON-RPC 通信

两个容易忽略的工程细节:MCP 走 stdio 时日志绝不能写 stdout(协议通道被占用),只能走 stderr、文件和内存;基础工具集在启动时定死(MCP 客户端看到的工具列表固定),之后项目与模式切换只影响运行时的启用集合。

三、工具体系

类别代表工具
符号检索get_symbols_overview(读新文件第一步)、find_symbolfind_referencing_symbolsfind_implementations
符号编辑replace_symbol_bodyinsert_after_symbolrename_symbol(LSP WorkspaceEdit,引用感知)、safe_delete_symbol
文本兜底search_for_pattern(正则)、replace_contentread_fileexecute_shell_command
记忆write_memory / read_memory / list_memories 等五个
工作流activate_projectinitial_instructionsonboarding
  • 工具用 marker 类声明能力(可编辑、可选、beta 等),marker 名还会进系统提示供模板条件渲染;
  • 每个工具有 max_answer_chars(默认 150k)做渐进截断,超时默认 240 秒,语言服务器崩溃会自动重启并重试
  • 在 Claude Code 这类自带文件/shell 工具的宿主里,基础工具默认禁用,避免与内置能力重复——这是「上下文即配置」思路的体现。

四、SolidLSP:语言服务器抽象层

SolidLSP 是 Serena 的底座,单独以 MIT 许可发布(其余主体是 GPL-3.0)。值得记的点:

  • 统一符号模型:把原始 LSP 类型转成带 parent 链、重载索引、懒加载正文的 UnifiedSymbolInformation,各家语言服务器的怪癖在子类覆写钩子里就地吸收;
  • 两级符号缓存:按「文件相对路径 + 内容 MD5」做键持久化到 .serena/cache/,带版本号常量做失效管理,空结果刻意不缓存;
  • 健壮性靠针对性特化:pyright 用 uvx 固定版本、jdtls 下载带 SHA256 校验、TypeScript 监听 $/progress 判断索引完成、ContentModified 错误只对声明了重试支持的服务器重试;
  • 支持 70+ 语言;Angular 是三服务器编排(ngserver + TS + HTML),Godot 通过 TCP 6008 连正在运行的编辑器;
  • 多语言服务器并行启动且 fail-fast:任何一个启动失败就整体报错,绝不悄悄用残缺能力降级。

五、双后端:LSP 与 JetBrains 插件

  • LSP 后端(默认,免费):经 SolidLSP 启动各语言的开源语言服务器;
  • JetBrains 后端(付费插件):复用 IDE 的分析能力,多语言索引、依赖库跳转,还有独家的交互式调试——Agent 能设断点、看变量、控制执行流;
  • 切换后端的机制很巧:后端声明一张工具类替换表,JetBrains 模式自动激活一个内部 mode,把 7 个核心 LSP 工具换成 jet_brains_* 版本,提示词里的工具名同步替换。第三发方扩展也走注册表 + entry point。

六、五层可组合配置

这是 Serena 适配几十种宿主客户端的关键,从粗到细依次覆盖:

  • 全局配置 ~/.serena/serena_config.yml:后端、超时、忽略路径、基础模式等;
  • CLI 参数:启动时覆盖或追加;
  • Context(单选,会话期固定):运行环境。内置 15 个——claude-code、codex、ide、chatgpt 等,各自排除与宿主重复的工具,并写针对性提示词对抗宿主偏置;
  • Mode(可多选,可运行时叠加):行为修饰。内置 9 个——interactive/editing 默认、planning 只读、onboardingone-shot 等;
  • 项目配置 .serena/project.yml:语言、编码、忽略规则、初始提示,另有 gitignore 掉的 project.local.yml 做本机覆盖。

每层都能增删工具、注入 Jinja2 提示词片段。「同一套工具包,靠配置片段拼出几十种形态」——这个分层思路对我写任何带配置的工具都有参考价值。

七、记忆系统:Markdown + 引用图

  • 存储就是纯 Markdown:项目级 .serena/memories/**.md,全局级 ~/.serena/memories/global/,支持 / 分主题;
  • 亮点是 mem: 交叉引用体系:重命名记忆时全库自动重写引用,还带引用完整性校验命令;
  • Onboarding 引导 Agent 把项目知识写进约定记忆:mem:coremem:tech_stackmem:suggested_commandsmem:conventionsmem:task_completion,写前必读 mem:memory_maintenance(风格规范本身也是一条记忆);
  • 设计准则:人类可读、可版本化、渐进披露(Agent 先拿名单按需读,而不是全部塞进上下文)、有防路径逃逸校验。

没有向量库、没有嵌入模型,就靠 Markdown 和引用把跨会话知识管起来了——简单,但把「人机共读」这件事做对了。

八、提示词系统

  • 所有提示词是 Jinja2 沙箱模板,用户放 ~/.serena/prompt_templates 即可覆盖,工厂类由代码生成器产出类型化访问器;
  • 系统提示组装顺序:资源效率宣言(先符号概览、按需读正文)→ 按工具 marker 条件渲染的区块 → 记忆清单 → context 提示 → 各 mode 提示 → 项目激活消息 → 会话 id;
  • 针对 Claude Code 有专门的提示词覆盖,声明 Serena 工具优先于内置 Read/Edit(原话是「Read 对探索性任务是 FORBIDDEN 的」),再配合提醒钩子对抗「Agent 漂移」——承认宿主有偏置,并主动纠正它,这个自觉很难得。

九、REPL Agent 接口(v2 的新玩法)

  • agent_interface 设为 REPL 后,只暴露 serena_repl 一个工具:Agent 写 Python 代码访问 facade(s.lsps.edits.mems.shell……),像 notebook 一样跨调用持久变量;
  • 经典工具与 REPL 方法是同一实现的两张皮:装饰器双向关联,一份逻辑两种暴露;
  • 返回类型文档渐进披露:LLM 用 s.info("Type") 按需查文档,不用预先塞满上下文。

十、评估方法论:让 Agent 自己当评测者

  • 不用 SWE-bench——文档明确说基准测试不适合评「增强层」;改用Agent 自评:一个一次性会话做约 20 个日常任务(五大类),每个任务同时用两套工具各做一遍,用 git diff 验证、统计调用数与负载大小,并被要求强制报告负面与中性发现;
  • 任务只给类别不给固定题目,避免挑题目美化结果;任何人都能在自己的代码库上复现;
  • 收敛结论值得记住:Serena 赢在多文件语义操作,微小文本编辑和 shell 任务内置工具仍然更好——它不试图取代宿主工具,只补语义缺口。

十一、值得借鉴的工程实践

  1. 分层配置 + 组合片段:context/mode 两个正交维度,解决「一套工具适配几十种宿主」;
  2. fail-fast 优于静默降级:语言服务器启动失败直接报错,不悄悄带病运行;
  3. 内容哈希做缓存键 + 版本号失效:解析类缓存的干净做法;
  4. 记忆即 Markdown + 引用图:比向量库简单,但跨会话、跨项目、人机共读全占了;
  5. 安全边界诚实声明:文档明说工具限制只是「引导」不是安全边界,真隔离要靠 Docker 沙箱;
  6. 许可分层:SolidLSP MIT、应用层 GPL-3.0,既方便生态集成又保护主体。

十二、我的整理理由

读完这个仓库,我最大的感受是:Serena 的成功不在某个算法,而在一连串克制的取舍——符号优先但保留文本兜底、记忆系统简单到只用 Markdown、评测方法把「自夸」的路全部堵死。做工具做到「知道自己的边界在哪,并且把这个边界诚实地写进文档」,大概就是它能让各家 Agent 都「主动要求装上」的原因。之后我会先在自己的项目里试用 find_referencing_symbolsrename_symbol,验证一下「8–12 步收敛为 1 步」到底有多真。

相关笔记:上一篇《DeepSeek Harness 学习笔记》里的 MCP 接入、《ZCode 知识点整理》里的扩展机制,与 Serena 是同一条「给 Agent 补能力」主线的不同侧面。

资料来源:GitHub 开源项目 oraios/serena(本地克隆通读:README、docs/ 全部指南、src/serena 与 src/solidlsp 源码)。主体现为 GPL-3.0-or-later 许可,SolidLSP 子库为 MIT。本页为个人要点整理,功能细节以官方仓库为准。
← 返回编程笔记