news 2026/8/30 2:34:16

让大模型看懂代码库:LSP与LLM结合的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
让大模型看懂代码库:LSP与LLM结合的完整实战指南

平时写代码的时候,大家可能都有过这种体验:让大模型帮你生成一段调用代码,它给出的方法名看起来头头是道,一查根本不存在;让它补全某个模块里的函数,它完全不知道你当前项目里有哪些符号;让它重构代码,它甚至会把已经过期的 API 继续用下去。

这不是大模型不够聪明,而是它缺少一种“当前项目语义信息”的获取通道。模型只知道通用语法,不熟悉你本地工程里真实存在的类、函数、变量和类型关系。于是这两年出现了一个很有意思的方向——把经典的 LSP(Language Server Protocol,语言服务器协议)接入 LLM,让语言服务器充当大模型的眼睛,帮它看清楚代码库的真实结构。

这篇文章会从 LSP 的原理讲起,说明为什么 LSP 对大模型应用如此重要,然后给出一个可直接运行的“LLM + LSP”最小实战案例,最后总结接入过程中的高频问题和工程建议。无论你是做大模型应用开发、AI 编程助手,还是想给团队内部的代码智能体补充语义能力,这篇文章都能提供一条可以落地的思路。

1. 背景与核心概念

1.1 LSP 到底是什么

LSP 的全称是 Language Server Protocol,也就是语言服务器协议。它最初由微软提出,目的是解决一个非常头疼的问题:以前每种语言都要为每个编辑器单独开发一套插件,VSCode 一套、Vim 一套、Emacs 一套、Sublime 一套,重复造轮子。

协议出现之后,语言的语法分析、补全、跳转、诊断这些重量级逻辑被独立成“语言服务器”,编辑器只需要通过统一的 JSON-RPC 消息和语言服务器通信。协议标准化了,编辑器只需要实现一次客户端,就能对接所有语言服务器。VSCode 能补全 Python,靠的是 Pyright;能补全 Go,靠的是 gopls;能补全 C/C++,靠的是 clangd。这些语言服务器都是 LSP 的具体实现。

我们平时在 IDE 里每天都会用到 LSP,只是多数情况下没有感知。每当你输入代码,编辑器把textDocument/didChange通知给语言服务器,服务器分析完后返回诊断信息;每当你输入一个点,编辑器把textDocument/completion请求发过去,语言服务器就返回当前上下文里可用的成员列表。这些交互都是通过 JSON-RPC 完成的。

1.2 LLM 为什么需要 LSP

大语言模型本质上是一个“文本预测器”,它靠海量训练数据学会了代码的统计规律,但它没有实时看代码库的能力。当模型被问到“当前仓库里UserService有哪些方法”时,它的唯一信息来源是训练数据里的记忆,而不是你项目里真实的代码。这就造成了两个典型问题:

  • 幻觉 API:模型返回了看起来合理但实际不存在的函数名。
  • 上下文缺失:模型不知道当前模块的导入路径、类型别名、重载函数。

LSP 恰好能弥补这一点。语言服务器由本地编译器或静态分析器驱动,它读取真实代码,构建符号表,能准确回答“某个文件里有哪些类”“某个类有哪些方法”“某个位置是什么类型”“某个变量在哪里定义”。如果把这些信息作为工具返回给 LLM,模型就相当于拿到了真实项目的地图,回答准确率会明显提升。

1.3 LSPs for LLMs 的常见形态

现在“LSPs for LLMs”并没有一个严格统一的定义,更多是一种架构思想。常见的落地形态有三种:

第一种是AI 编程助手。IDE 插件在收到用户自然语言指令后,先通过 LSP 拿到光标位置的符号、类型和代码范围,再把这些结构化信息拼进 Prompt,最后让 LLM 生成补全或修改建议,例如 GitHub Copilot Chat 在 VSCode 里做代码解释、修复、重命名时,背后就有 LSP 提供代码上下文。

第二种是Code Agent / 自动化任务。智能体收到一个任务,比如“修复所有文件里的某个 Bug”,Agent 需要定位文件、分析符号引用、修改代码、检查诊断。这些步骤如果全部靠 LLM 猜测会非常不可靠,最稳妥的做法是调 LSP 的textDocument/definitiontextDocument/referencestextDocument/documentSymboltextDocument/diagnostic来获得准确定位。

第三种是对话式代码问答。用户问“这个handle函数为什么报错”,系统先调用 LSP 的 hover 和诊断接口拿到错误信息,再交给 LLM 解释根因、给修复建议。这个模式实现起来最快,也是很多企业知识库问答和代码审计系统采用的路线。

在这三种形态里,LSP 扮演的角色都不是“替 LLM 思考”,而是“替 LLM 感知代码库”。这是两者最核心的分工关系。

2. 环境准备与版本说明

为了让你能够完整跑通后面的实战示例,这里先明确环境需求。

本文的代码示例是基于 Python 写的,理论上支持 Windows、macOS、Linux 三个平台,但更推荐在 macOS 或 Linux 上运行,因为子进程管理、stdio 管道处理在这些系统上更顺畅。

运行环境建议如下:

  • Python 3.9 及以上版本。
  • 需要安装pygls库,用于实现一个极简语言服务器。pygls 是 Python 生态中最流行的 LSP 框架之一,具体版本请以你安装时 pypi 上的最新稳定版为准。本文的 API 用法适配 pygls 较新的主流版本。
  • 需要安装requests库,用于编写客户端向语言服务器发送 JSON-RPC 消息,以及向本地 LLM 服务发送 HTTP 请求。
  • 如果演示 LLM 调用部分,建议本地准备一个 OpenAI 兼容的推理服务,例如 Ollama、vLLM、llama.cpp server 等。你也可以直接改用 OpenAI API,代码里只需要修改base_urlapi_key

需要说明的是,LSP 协议本身的版本目前主流是 3.17,这也是各大语言服务器普遍支持的版本。本文示例只用到其中几个稳定方法,不依赖任何新版本特性,所以即使你用的语言服务器版本较旧,也能正常对齐。

项目结构上,演示时会包含三个文件:

llm-lsp-demo/ ├── demo_lsp_server.py # 基于 pygls 的极简语言服务器 ├── lsp_client.py # 封装 JSON-RPC 客户端 └── llm_agent.py # 将 LSP 结果交给 LLM 的演示入口

如果版本在后续迭代中变化,请优先参考官方文档和项目内 README,本文重点演示的是链路和思路,不是某一版 API 的精确复刻。

3. LSP 协议工作原理解读

3.1 客户端-服务器模型

LSP 的通信模型很简单,只有两个角色:客户端(通常是编辑器或 Agent)和服务器(语言服务器)。

  • 客户端负责收集用户的编辑行为,例如打开文件、修改内容、移动光标,然后把这些事件转成协议消息发给服务器。
  • 服务器负责分析和响应,比如返回补全列表、跳转位置、诊断结果,然后通过 JSON-RPC 消息回给客户端。

在传输层上,LSP 最常见的方式是stdio,也就是客户端启动一个语言服务器子进程,然后往子进程的 stdin 写请求,从 stdout 读响应。这种方式最简单,也是 VSCode 默认采用的通信方式。除了 stdio,LSP 也支持 TCP 或命名管道,但核心交互模型完全一致。

3.2 JSON-RPC 消息格式

LSP 的消息格式基于 JSON-RPC 2.0。每个消息是 JSON 对象,并且传输时外面包了一层Content-Length头,用于告诉接收方这次消息体有多长。一个典型的消息长这样:

Content-Length: 139\r\n \r\n {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":1234,"rootUri":"file:///path/to/project","capabilities":{}}}

在写客户端时要特别注意这个头部,字节数必须准确,否则服务器会解析失败。实战里最常见的坑就是这个长度算错,导致消息错位。

3.3 常用方法说明

LSP 涉及的方法很多,但面向 LLM 集成的场景,只需要重点关注下面几个:

方法名用途对 LLM 的价值
initialize建立会话,确定能力启动一切的前提
textDocument/hover获取鼠标悬停位置的类型、文档注释解释变量/函数是什么
textDocument/completion获取当前上下文补全项让 LLM 知道你正在编辑的位置能填什么
textDocument/definition找到符号定义位置让 LLM 定位实现
textDocument/references找到所有引用位置分析影响面、批量修改
textDocument/documentSymbol获取文件内符号树让 LLM 快速理解文件结构
textDocument/diagnostic获取诊断、报错信息修复 Bug 时获取真实错误原因

3.4 关键点:LSP 解决的核心问题

LSP 返回的不是自然语言,而是结构化数据。比如completion返回的是一个CompletionItem列表,每一项包含labelkinddetaildocumentation等字段;definition返回的是Location,包含文件和行号。

这意味着我们在接 LLM 的时候,不能直接把原始 JSON 一股脑塞进 Prompt。更好的做法是把结构化结果转换成一段自然语言摘要,比如:

当前文件 src/service/user_service.py 第 42 行,可用补全项: - create_user(params: CreateUserRequest) -> User - delete_user(user_id: int) -> bool - find_user_by_email(email: str) -> User | None

这样 LLM 得到的是一段语义清晰、token 友好的上下文,而不是它不擅长解析的嵌套 JSON。

4. 完整实战案例:用 LSP 给 LLM 提供代码上下文

现在进入核心环节。我们来实现一个最小闭环:启动一个极简语言服务器,客户端发送补全和悬停请求,拿到结果后交给 LLM,让 LLM 基于真实代码符号回答用户问题。这个过程虽然短,但已经跑通了“LLM 通过 LSP 感知代码库”的完整链路。

4.1 创建项目结构

先在任意目录下创建项目文件夹:

mkdir llm-lsp-demo cd llm-lsp-demo

安装依赖:

pip install pygls requests

4.2 编写极简语言服务器

我们用 pygls 写一个非常小巧的语言服务器。它不需要真正解析代码,而是模拟一个“用户注册相关符号”的代码库,返回一些示例补全项和悬停信息。这样能让你快速理解 LSP 交互流程,而不用陷入编译器的复杂逻辑。

文件路径:demo_lsp_server.py

import logging from pygls.lsp import LanguageServer from pygls.lsp.methods import COMPLETION, HOVER, TEXT_DOCUMENT_DID_OPEN from pygls.lsp.types import ( CompletionItem, CompletionItemKind, CompletionList, CompletionParams, Hover, HoverParams, MarkupContent, MarkupKind, Position, Range, TextDocumentItem, DidOpenTextDocumentParams ) logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s") server = LanguageServer("demo-lsp-server", "v0.1") # 模拟符号表 SYMBOLS = { "create_user": { "label": "create_user(user: UserCreateRequest) -> User", "detail": "创建一个新用户并写入数据库", "kind": CompletionItemKind.Function, }, "delete_user": { "label": "delete_user(user_id: int) -> bool", "detail": "根据用户 ID 删除用户", "kind": CompletionItemKind.Function, }, "get_user_by_email": { "label": "get_user_by_email(email: str) -> User | None", "detail": "通过邮箱查询用户,不存在时返回 None", "kind": CompletionItemKind.Function, }, } @server.feature(COMPLETION) def complete(ls: LanguageServer, params: CompletionParams): items = [] prefix = "" # 简单演示:从当前行文本中提取光标前最近的一个标识符 line = params.context.trigger_kind if params.context else None for name, info in SYMBOLS.items(): items.append( CompletionItem( label=info["label"], kind=info["kind"], detail=info["detail"], insert_text=name, ) ) return CompletionList(is_incomplete=False, items=items) @server.feature(HOVER) def hover(ls: LanguageServer, params: HoverParams): doc = ls.workspace.get_document(params.text_document.uri) line = doc.lines[params.position.line] if params.position.line < len(doc.lines) else "" for name, info in SYMBOLS.items(): if name in line: content = f"**{name}** \n{info['detail']}" return Hover( contents=MarkupContent(kind=MarkupKind.Markdown, value=content), range=Range( start=Position(line=params.position.line, character=0), end=Position(line=params.position.line, character=len(name)), ), ) return Hover( contents=MarkupContent(kind=MarkupKind.Markdown, value="未识别符号"), ) if __name__ == "__main__": server.start_io()

这段代码做了三件事:

  • 定义了一个SYMBOLS字典,模拟项目里真实的函数签名。
  • 在收到completion请求时,返回所有模拟函数名和说明。
  • 在收到hover请求时,检查当前行是否包含模拟符号,并返回说明文档。

实际的 pygls API 可能因版本不同略有变化,但整体思路是一致的。你完全可以用 gopls、clangd、Pyright 等成熟服务器替换这个示例服务器,客户端代码不需要大改。

4.3 编写 JSON-RPC 客户端

接下来写客户端。客户端的职责是启动语言服务器子进程,按 LSP 的消息格式发请求、读响应,并封装成好用的接口。

文件路径:lsp_client.py

import json import struct import subprocess from typing import Any, Dict, Optional class LSPClient: def __init__(self, server_command: list, root_uri: str): self.server_command = server_command self.root_uri = root_uri self.process: Optional[subprocess.Popen] = None self.request_id = 0 def start(self): self.process = subprocess.Popen( self.server_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) init_params = { "processId": None, "rootUri": self.root_uri, "capabilities": {}, } response = self.send_request("initialize", init_params) self.send_notification("initialized", {}) return response def _send_data(self, data: bytes): if not self.process or not self.process.stdin: raise RuntimeError("server not started") header = f"Content-Length: {len(data)}\r\n\r\n".encode("utf-8") self.process.stdin.write(header + data) self.process.stdin.flush() def _read_message(self) -> Optional[Dict[str, Any]]: if not self.process or not self.process.stdout: raise RuntimeError("server not started") content_length = None while True: line = self.process.stdout.readline() if not line: return None if line in (b"\r\n", b"\n", b""): break if line.lower().startswith(b"content-length:"): content_length = int(line.split(b":")[1].strip()) if content_length is None: return None payload = self.process.stdout.read(content_length) return json.loads(payload.decode("utf-8")) def send_request(self, method: str, params: Dict[str, Any]) -> Dict[str, Any]: self.request_id += 1 message = { "jsonrpc": "2.0", "id": self.request_id, "method": method, "params": params, } data = json.dumps(message, ensure_ascii=False).encode("utf-8") self._send_data(data) while True: response = self._read_message() if response is None: raise RuntimeError("connection closed early") if response.get("id") == self.request_id: return response def send_notification(self, method: str, params: Dict[str, Any]): message = {"jsonrpc": "2.0", "method": method, "params": params} data = json.dumps(message, ensure_ascii=False).encode("utf-8") self._send_data(data) def request_completion(self, uri: str, line: int, character: int) -> Dict[str, Any]: params = { "textDocument": {"uri": uri}, "position": {"line": line, "character": character}, "context": {"triggerKind": 1}, } return self.send_request("textDocument/completion", params) def request_hover(self, uri: str, line: int, character: int) -> Dict[str, Any]: params = { "textDocument": {"uri": uri}, "position": {"line": line, "character": character}, } return self.send_request("textDocument/hover", params) def stop(self): if self.process: self.process.terminate() self.process.wait()

这个客户端实现了 LSP 通信的完整基础流程:启动进程、握手、发送请求、读取响应。关键点在于_read_message方法,它必须严格按Content-Length头去读取消息体。很多初学 LSP 的人会在这里踩坑,因为如果直接按行读取 JSON,遇到多行 JSON 就会解析失败。

4.4 编写 LLM Agent 入口

现在写主程序。它启动语言服务器,请求补全和悬停信息,然后组织成 Prompt 发给本地 LLM。这里使用 OpenAI 兼容接口作为示例。

文件路径:llm_agent.py

import json import requests from lsp_client import LSPClient # 配置 LLM 服务,这里以本地 Ollama 为例 LLM_BASE_URL = "http://localhost:11434/v1" LLM_MODEL = "qwen2.5-coder:7b" API_KEY = "ollama" # Ollama 本地服务通常不校验 key FILE_URI = "file:///tmp/user_service.py" def call_llm(system_prompt: str, user_prompt: str) -> str: response = requests.post( f"{LLM_BASE_URL}/chat/completions", headers={"Authorization": f"Bearer {API_KEY}"}, json={ "model": LLM_MODEL, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], "temperature": 0.2, }, timeout=30, ) data = response.json() return data["choices"][0]["message"]["content"] def format_lsp_result(completion_result: dict, hover_result: dict) -> str: lines = [] # 处理补全结果 items = [] if "result" in completion_result and completion_result["result"]: raw = completion_result["result"] if isinstance(raw, dict): items = raw.get("items", []) elif isinstance(raw, list): items = raw if items: lines.append("当前上下文中可用的函数/补全项:") for item in items: lines.append(f"- {item.get('label', '')}: {item.get('detail', '')}") else: lines.append("未获取到补全项。") hover_content = "" if "result" in hover_result and hover_result["result"]: raw = hover_result["result"] if isinstance(raw, dict): contents = raw.get("contents", "") if isinstance(contents, dict): hover_content = contents.get("value", "") else: hover_content = str(contents) lines.append("光标位置悬停信息:") lines.append(hover_content) return "\n".join(lines) def main(): client = LSPClient( server_command=["python", "demo_lsp_server.py"], root_uri="file:///tmp", ) try: client.start() print("LSP 初始化完成") completion_result = client.request_completion(FILE_URI, line=3, character=10) hover_result = client.request_hover(FILE_URI, line=5, character=5) context_text = format_lsp_result(completion_result, hover_result) print("----- LSP 返回的上下文 -----") print(context_text) system_prompt = ( "你是一个代码助手。下面给出了从语言服务器获取的真实代码上下文。" "请基于这些信息回答用户问题,不要编造当前代码库中不存在的函数。" ) user_question = "当前代码库里有哪些可用函数?帮我生成一段调用 create_user 的示例。" answer = call_llm(system_prompt, f"代码上下文:\n{context_text}\n\n用户问题:{user_question}") print("----- LLM 回答 -----") print(answer) finally: client.stop() if __name__ == "__main__": main()

这里的call_llm函数使用 OpenAI 兼容接口,方便接入各种本地推理服务。如果你使用的是其他厂商的 API,只需要替换base_urlapi_keymodel参数即可。

4.5 运行与验证

首先在终端启动本地大模型服务,这里以 Ollama 为例:

ollama serve ollama pull qwen2.5-coder:7b

然后运行主程序:

python llm_agent.py

预期会看到类似这样的输出:

LSP 初始化完成 ----- LSP 返回的上下文 ----- 当前上下文中可用的函数/补全项: - create_user(user: UserCreateRequest) -> User: 创建一个新用户并写入数据库 - delete_user(user_id: int) -> bool: 根据用户 ID 删除用户 - get_user_by_email(email: str) -> User | None: 通过邮箱查询用户,不存在时返回 None 光标位置悬停信息: 未识别符号 ----- LLM 回答 ----- 当前代码库里可用的函数有 create_user、delete_user、get_user_by_email。 下面是调用 create_user 的示例: user = create_user(UserCreateRequest(name="张三", email="zhangsan@example.com"))

请注意,这里的关键不在于补全列表本身,而在于:LLM 没有根据自己记忆中的 API 凭空回答,而是严格使用了语言服务器提供的符号。这就从根源上避免了幻觉 API 的问题。

4.6 结果说明

这个 Demo 最核心的链路就是:

  1. LLM Agent 收到用户问题。
  2. Agent 先向语言服务器发起 LSP 请求。
  3. 语言服务器基于真实代码库返回结构化符号信息。
  4. Agent 将符号信息转成自然语言摘要。
  5. LLM 基于摘要生成回答或补全建议。

如果你的语言服务器替换成 Pyright 或 gopls,那么返回的就是你项目里真实符号,整个过程就具备生产落地价值了。

5. 常见问题与排查思路

下面把实践中最常遇到的问题整理成表,每个问题都给出现象、原因和解决思路。

问题现象常见原因解决思路
语言服务器启动后客户端一直收不到响应子进程启动失败,或 JSON-RPC 的 Content-Length 头解析错误先单独运行python demo_lsp_server.py检查是否有报错;检查客户端_read_message的读取逻辑,确认长度读取准确
init 请求返回 error code -32600initialize 参数格式不完整,缺少capabilities检查 JSON-RPC 2.0 格式,确认jsonrpcidmethodparams字段齐全
补全结果为空列表语言服务器没有加载对应文件,或未声明补全能力先通过textDocument/didOpen打开文件;确认服务器 capabilities 里声明了completionProvider
LLM 调用超时本地模型推理慢,或网络连接不通为请求设置超时时间,例如 30 秒;改用更小的模型;确认 LLM 服务地址可访问
LSP 返回数据太大,Prompt 超长较大项目里 references 或 documentSymbol 返回大量节点在转发给 LLM 前做过滤和摘要,只保留符号名、文件路径、行号等核心字段
LLM 仍然编造 API提示词没有强调“只能使用给定符号”在 system prompt 中增加约束,例如“如果上下文中没有该函数,直接说明不存在,不要猜测”
频繁启动语言服务器导致性能差每个请求都新起一个子进程对语言服务器做常驻管理,做成单例服务,只建立一次会话,后续复用连接

排查时建议按这个顺序:先确认服务器能独立启动,再确认 JSON-RPC 消息发送正确,再确认响应能读回,最后才是调 LLM 的逻辑。大多数问题都出在前两步,而不是 LLM 本身。

6. 最佳实践与工程建议

6.1 优先使用成熟语言服务器

不要从零实现一个语言服务器。pyrightclangdgoplsrust-analyzertypescript-language-server这些项目经过了大量实际项目验证,解析准确率高,性能也更好。你的核心工作量应该放在“如何把 LSP 返回的结果组织给 LLM”,而不是重复造语言服务器。

6.2 对 LSP 结果做摘要和缓存

LSP 返回的原始数据往往有很多字段,直接全量塞进 Prompt 既浪费 token 又降低响应质量。建议做两层处理:

  • 摘要层:从 CompletionItem、SymbolInformation 等结构中只提取 label、kind、detail、location,去掉无用元数据。
  • 缓存层:同一个文件、同一个位置、同一段代码内容下的 LSP 响应可以缓存,设置 TTL(比如 30 秒)。代码内容没有变化时,不必重复请求。

6.3 给 LLM 明确指令约束

很多“模型乱编”的问题,不是模型能力不行,而是提示词没有设置边界。在系统提示词里要有类似这样的话:

当前项目符号仅以上下文提供的为准。如果待调用的函数不在列表中,请明确回复“当前上下文中没有该函数”,不要猜测或补全可能不存在的 API。

这条约束能显著减少幻觉。

6.4 注意异步与超时

LSP 是请求-响应模型,LLM 请求也可能很慢。在工程落地时,不要让 Agent 主流程同步等待所有请求完成。更合理的做法是批量并行请求多个 LSP 方法,统一等待结果后合并上下文。同时给所有网络请求设置超时,避免一个慢服务拖垮整个 Agent。

6.5 权限与安全边界

语言服务器本质上是一个可以执行代码、读写文件的高权限进程。如果只在本地 IDE 场景使用,问题不大;但如果要远程部署成 Agent 服务,就必须注意:

  • 不要随便启动不可信的语言服务器。
  • 远程场景建议通过 SSH 隧道或带鉴权的 TCP 端口访问,不要裸暴露 0.0.0.0。
  • Agent 的代码修改动作应该限定在指定工作目录,避免越权写入。
  • 对 LLM 生成的代码建议继续做静态检查,确认没有明显安全风险后再落地。

6.6 引入诊断信息提升修复能力

如果做的是 Bug 修复类 Agent,建议把textDocument/diagnostic也纳入上下文。修复前先拿到真实报错,修复后再请求一次诊断,能自动验证是否修复成功。这个循环比单纯让 LLM 阅读代码更可靠。

7. 总结与下一步学习方向

这篇文章从 LSP 的诞生讲起,分析了 LLM 代码应用为什么需要 LSP,并通过一个可运行的最小 Demo 展示了完整的“LLM + LSP”链路。核心收获有四点:

  • LSP 是 LLM 理解真实代码库的可靠通道,能有效减少 API 幻觉。
  • LLM 负责语义理解和生成,LSP 负责符号定位和结构分析,二者的分工要清晰。
  • 接入 LSP 的关键不是实现协议,而是把结构化结果转换成对 LLM 友好的上下文。
  • 生产落地时要特别关注摘要、缓存、超时、权限这些工程细节。

接下来如果想继续深入,建议按这个顺序学习:

  1. 读 LSP 官方规范,重点看textDocument/*系列方法请求和响应结构。
  2. 尝试把 Demo 里的服务器替换成 Pyright 或 gopls,用真实项目跑一遍。
  3. 研究 pygls 的高级用法,理解workspacediagnosticssettings的机制。
  4. 在开源 Code Agent 框架里接入 LSP,例如给 Agent 增加一个get_symbol_context工具函数。
  5. 如果对性能有追求,可以研究 LSP 的增量同步、多根工作区、语义令牌等进阶能力。

大模型代码应用正在从“背题模式”走向“查阅模式”,LSP 在其中扮演的角色会越来越重要。如果你正准备给自己的 AI 编程工具补充真实代码上下文能力,不妨从今天这个最小闭环开始改造。你自己动手跑通一次,会比看十篇文章更有效果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 2:31:39

70亿token的AI德国军官:监督学习应用的工程拆解

开头我先说一个判断&#xff1a;这大概是我见过最“浪费” token 的项目&#xff0c;但也是最有意思的一类 AI 应用。70 亿 token&#xff0c;不是用来训练模型&#xff0c;不是用来做问答&#xff0c;也不是用来跑什么数据分析。它被拿来做了一个“AI 德国军官”&#xff0c;核…

作者头像 李华
网站建设 2026/8/30 2:30:57

自研内核、引擎与架构:概念边界与最小实践全解析

“自研内核、自研引擎、自研架构”这三个词放在一起&#xff0c;很容易让人热血沸腾。但真正经历过系统底层开发的人会知道&#xff0c;这是一条从“能写代码”到“能掌控计算机”的漫长修行。本文不吹不黑&#xff0c;把这三座山拆开揉碎&#xff0c;从概念边界、环境准备、最…

作者头像 李华
网站建设 2026/8/30 2:30:23

大语言模型在数学研究中的应用:从证明草稿到定理证明辅助

先说明白&#xff1a;这篇文章聊的&#xff0c;不是“AI能不能替代数学家”&#xff0c;而是更具体的“AI&#xff0c;尤其是大语言模型&#xff08;LLM&#xff09;&#xff0c;在重大数学发展里到底有哪些已经成熟、正在尝试&#xff0c;或者至少值得一试的应用示例”。所谓重…

作者头像 李华
网站建设 2026/8/30 2:27:08

STM32蜂鸣器播放旋律全攻略:从PWM原理到代码实现

做嵌入式这些年&#xff0c;我见过太多人卡在"让蜂鸣器唱歌"这个看似入门的需求上。网上demo一搜一大把&#xff0c;可真照着抄&#xff0c;有人拿有源蜂鸣器捅了一下午也出不来半句调子&#xff0c;有人把PWM翻转频率算错一个数量级&#xff0c;还有人让蜂鸣器"…

作者头像 李华
网站建设 2026/8/30 2:27:00

四索并联机器人:从运动学正解到动力学张力分配的工程实践

简介&#xff1a;本资源面向机器人学与机械系统动力学方向的高校研究者、研究生及工程技术人员&#xff0c;聚焦四索并联机构的核心建模与分析问题&#xff0c;提供可直接运行的MATLAB实现方案。资源包含3个核心m文件&#xff0c;总大小仅1KB&#xff0c;轻量紧凑&#xff1a;其…

作者头像 李华
网站建设 2026/8/30 2:25:51

Java零基础学习路线:从JDK环境配置到SpringBoot实战

最近不少人在传一套“200集Java零基础全套教程”&#xff0c;号称小白一周学完就能编程技术猛涨。如果你真信了“一周速成”然后收藏吃灰&#xff0c;结果大概率还是不会写代码。实际上&#xff0c;200集视频的价值在于它把Java入门的完整知识点串了起来&#xff0c;比零散刷短…

作者头像 李华