​使用 ChatGPT 控制 Vim,有了新发现!

 

以下为译文:

Vim 是一款基于文本的文本编辑器。作为使用者,你可以从 Vim 中获取的每一项信息都以文本形式表示,你发送给它的每一项信息也都是文本。同样,我们也主要通过文本信息去使用时下流行的 ChatGPT。对于这两款工具而言,都是用文本的形式去使用,那我们是否可以去掉中间的环节,譬如,直接使用 ChatGPT 来控制 Vim?

可在此处获取代码:https://github.com/LachlanGray/vim-agent

d3176d51d5837726620c455518f045b7.png

天作之合

Vim 非常奇特,它的设计使得你知道如何使用该编辑器,也就意味着你知道如何使用编辑器实现自动化。简而言之,你与编辑器的每一次交互都可以转化为一个 VimScript 程序。任何涉及键入、更改、删除、编辑命令、Shell 命令、打开文件等任意组合的操作序列都可以由一个程序完成。这对人类是否有利还有待商榷,但如果你将其和一个语言模型结合起来,那么这个功能就无价了。

VimScript 已经存在很长时间了,互联网上充斥着用于完成各种乏味任务的 VimScript。VimScript 基本上是一种专门用于操作文本的领域特定编程语言。由于它的年代久远和僵化而受到一些批评,但它在其应该做的事情上表现出色。对我们来说,这意味着 ChatGPT 和它搭档将会非常顺利,理论上可以做我能做的一切与编辑器相关的事情。

26d2b654df989fc6357c03072cb72565.png

Neovim API

ChatGPT 将如何实际控制编辑器呢?方便的是,Neovim 拥有一个 Python 客户端(https://pynvim.readthedocs.io/en/latest/),允许你通过 Python API 来控制编辑器。这非常方便。

首先,你可以通过以下方式启动 Neovim 并设置一个监听地址:

1nvim --listen 127.0.0.1:7777

这将启动一个常规的 Neovim 实例,但它将监听连接。现在,通过 Python API,我们可以告诉 Neovim 执行操作。Python API 使用 TCP(传输控制协议)连接到 Neovim,这是一种网络协议,旨在确保数据被完整接收,并按照发送的顺序到达。我们创建一个 vim 对象来管理 Neovim 的状态:

1vim = attach('tcp', address='127.0.0.1', port=7777)

该 vim 对象为我们提供了对 Neovim 的完全访问权限,其中包括对编辑器状态和功能的编程访问。在众多便捷包装器中,它提供了 vim.request(),这是一个全能工具,可以与 API 文档中的所有内容一起使用(https://neovim.io/doc/user/api.html)。它使我们可以做几乎任何事情,例如运行一个命令:

1vim.request('nvim_command', "q!")

以下是我们的计划:封装我们关心的所有功能,并简化它们,以便能够轻松地与语言模型进行交互。我们将称这个包装器为 VimInstance,它将包含 vim 对象,并具有简单的属性来访问信息,以及控制 Vim 实例的方法:

1class VimInstance:
 2    def __init__(self):
 3        self.vim = attach('tcp', address='127.0.0.1', port=7777)
 4
 5    @property
 6    def current_buffer_content(self):
 7        return self.vim.request(
 8                'nvim_buf_get_lines', 
 9                self.vim.current.buffer,
10                0, -1, True)
11
12    # ...
13
14    def input(self, keys):
15        self.vim.input(keys)
16
17    # ...

然后我们可以做类似的事情:

1vim = VimInstance()
2
3# list containing each line of current file
4text = vim.current_buffer_content
5
6# type "hello" at the start of the file and save
7vim.input("ggIhello<Esc>:w<CR>")

35299e3ff16966d3604d4d3de827732e.png

给我代码!

生活中的一个极大的确定性是 ChatGPT 会告诉你它正在做什么。而且通常情况下,即使你不要求,它也会说一些。我们肯定会立刻遇到这个问题。与其哄着模型,不如只是等待代码出现,然后在代码完成时挂断连接可能更容易。

OpenAI 的聊天完成端点的流式传输功能对此很有用。它允许我们在文本块到达时监视它们,并实时决定如何处理。我们可以通过产生类似这样的文本块来迭代处理到达的完成结果:

1import openai
 2
 3def chat_3(messages: list[dict]):
 4    completion = openai.ChatCompletion.create(
 5        model = "gpt-3.5-turbo",
 6        messages = messages,
 7        temperature = 0.9,
 8        stream=True
 9    )
10    for chunk in completion:
11        if "content" in chunk.choices[0].delta:
12            yield chunk.choices[0].delta["content"]

现在我们可以在不等待模型完成的情况下处理模型的响应:

1def filtered_chat(request: str):
2    messages = [{"role":"user"}, {"content": request}]
3    for chunk in chat_3(messages):
4        if <condition>:
5            yield chunk

要收集代码,我们可以在响应滚动到达时进行监视,并等待开头的代码块模式(```.*?(\n.*)))出现。一旦匹配成功,我们就知道是时候开始监听了。然后我们可以继续监听,直到遇到更多的反引号。如果一切顺利,我们应该只有代码。

d9a6a7006b99d579856ad9e3eb88ebd3.png

GPT 接管控制

现在我们已经拥有了将 ChatGPT 接入编辑器所需的一切。对于基本设置,让我们告诉 ChatGPT 该做什么。一个基本的提示策略如下:

  1. 给出一条指令,并提供屏幕内容作为上下文。

  2. 明确要求一个用于完成任务的 VimScript。

  3. 在 Neovim 中执行每一行。

以下是结果。左侧是打开文件的 Neovim,右侧我正在键入指令。它…有点奏效:

对于基本的操作,比如删除和重新排列屏幕上的内容,它表现得相当不错,但在处理更高级的请求方面,比如将注释转换为猪拉丁语(儿童暗语),它的可靠性不高。好消息是,有数以百万计的改进方式,因此自动文本编辑前景看起来很有希望!下一步是制定一个更好的提示策略,而不是采用这种一刀切的制作脚本方式。一旦我们有了一套良好的基本操作,我想构建一个类似"Voyager"(https://github.com/MineDojo/Voyager)的代理程序,看看它能走多远。

4e1cc7ce82b941fad856fb5b42adc2fc.gif

 

首页    ​使用 ChatGPT 控制 Vim,有了新发现!