Skip to content

Commit

Permalink
feat: add images for contenxt
Browse files Browse the repository at this point in the history
  • Loading branch information
phodal committed Jun 23, 2023
1 parent a82e4fc commit fe89730
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 87 deletions.
93 changes: 6 additions & 87 deletions src/5-context-engineering.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,18 @@
# LLM 架构设计原则:上下文工程

上个月在计划为 AutoDev 添加多语言支持时候,发现 GitHub Copilot 的插件功能是语言无关的(通过 plugin.xml 分析),便想研究一下它是如何使用
TreeSitter 的。可惜的是,直到最近才有空,研究一下它是如何实现的。

在探索的过程中,发现:Copilot 围绕上下文做了非常之多的工作,便想着写一篇文章总结一下。

## GitHub Copilot 的上下文构建

与 ChatGPT 相比,GitHub Copilot 的强大之处在于,它构建了足够多的上下文,结合其对 LLM 的训练(或微),可以写出非常精准的**生产级代码
**

### Copilot 的可见上下文

在肉眼可见的级别里,即我们自身的使用感受,我们可以发现 Copilot 不仅是读取当前文件的源码,而是一系列相关文件的源码,以构建更详细的上下文。

简单可以先划分三个场景:

- 当前文件。可以感知某个类的属性和方法,并做出自动填充。
- 相近文件。如测试文件,可以知道被测类的信息,并自动编写用例。
- 编辑历史(疑似)。即当我们以某种方式修改多个代码时,它也能识别出这个变化。

而在未来,相信它会获取诸如项目上下文等信息,如 Gradle 依赖、NPM 依赖等信息,避免在打开的 tab 不够用的情况下,引用不存在的依赖。

而针对于企业自身的 AI 编程工具而言,还可以结合服务上下文、业务上下文进行优化。

### Copilot 的不可见过程

结合网上的逆向工程资料,以及自己对代码的 debug 尝试,最后梳理了一个大致的 “四不像” (实在是懒得继续画)架构图。

其作用如下:

- 监听用户操作(IDE API )。监听用户的 Run Action、快捷键、UI 操作、输入等,以及最近的文档操作历史。
- IDE 胶水层(Plugin)。作为 IDE 与底层 Agent 的胶水层,处理输入和输出。
- 上下文构建(Agent)。JSON RPC Server,处理 IDE 的各种变化,对源码进行分析,封装为 “prompt” (疑似) 并发送给服务器。
- 服务端(Server)。处理 prompt 请求,并交给 LLM 服务端处理。

而在整个过程中,最复杂的是在 Agent 部分,从上下文中构建出 prompt。

### Copilot 的 Prompt 与上下文

在 “公开” 的 Copilot-Explorer 项目的研究资料里,可以看到 Prompt 是如何构建出来的。如下是发送到的 prompt 请求:

```kotlin
{
"prefix": "# Path: codeviz\\app.py\n#....",
"suffix": "if __name__ == '__main__':\r\n app.run(debug=True)",
"isFimEnabled": true,
"promptElementRanges": [
{ "kind": "PathMarker", "start": 0, "end": 23 },
{ "kind": "SimilarFile", "start": 23, "end": 2219 },
{ "kind": "BeforeCursor", "start": 2219, "end": 3142 }
]
}
```

其中:

- 用于构建 prompt 的 `prefix` 部分,是由 promptElements
构建了,其中包含了:`BeforeCursor`, `AfterCursor`, `SimilarFile`, `ImportedFile`, `LanguageMarker`, `PathMarker`, `RetrievalSnippet`
等类型。从几种 `PromptElementKind` 的名称,我们也可以看出其真正的含义。
- 用于构建 prompt 的 `suffix` 部分,则是由光标所在的部分决定的,根据 tokens 的上限(2048 )去计算还有多少位置放下。而这里的
Token 计算则是真正的 LLM 的 token 计算,在 Copilot 里是通过 Cushman002 计算的,诸如于中文的字符的 token
长度是不一样的,如: `{ context: "console.log('你好,世界')", lineCount: 1, tokenLength: 30 }` ,其中 context 中的内容的
length 为 20,但是 tokenLength 是 30,中文字符共 5 个(包含 `` )的长度,单个字符占的 token 就是 3。

到这里,我算是解决我感兴趣的部分,Agent 包里的 TreeSitter 则用于分析源码,生成 `RetrievalSnippet` ,其中支持语言是 Agent
自带的 `.wasm` 相关的包,诸如:Go、JavaScript、Python、Ruby、TypeScript 语言。

## LLM 的上下文工程
![Context Engineering](images/context-eng.png)

上下文工程是一种让 LLM 更好地解决特定问题的方法。它的核心思想是,通过给 LLM
提供一些有关问题的背景信息,比如指令、示例等,来激发它生成我们需要的答案或内容。上下文工程是一种与 LLM 有效沟通的技巧,它可以让
LLM 更准确地把握我们的目的,并且提升它的输出水平。

简而言之,上下文工程是如何在有限的 token 空间内,传递**最相关的上下文信息**

## 上下文工程的原则

所以,我们就需要定义什么是该场景下的,**最相关的上下文信息**

### 基于场景与旅程的上下文设计
### 原则:基于场景与旅程的上下文设计

它的基本思想是,通过分析用户在不同场景下的操作和行为,来获取与当前任务相关的上下文信息,从而指导 LLM 生成最佳的代码提示。

Expand All @@ -87,7 +22,7 @@ LLM 更好地理解用户的意图,并生成更准确、更有用的代码提
例如,在用户编写 JavaScript
代码时,Copilot会分析用户在编辑器中的光标位置、当前文件的内容、变量、函数等信息,以及用户的输入历史和使用习惯等上下文信息,来生成最相关的代码提示。这些代码提示不仅能够提高用户的编码效率,还能够帮助用户避免常见的编程错误。

### 就地矢量化(Vector)与相似度匹配
### 原则:就地矢量化(Vector)与相似度匹配

“众知周知”,在 LLM 领域非常火的一个工具是 LangChain,它的处理过程类似于 langchain-ChatGLM 总结的:

Expand All @@ -101,7 +36,7 @@ LLM 更好地理解用户的意图,并生成更准确、更有用的代码提

除了就地矢量化(Vector)与相似度匹配,Copilot 还使用了本地的相似计算与 token 处理来管理 token,以便更好地处理大规模自然语言处理任务。

### 有限上下文信息的 Token 分配
### 原则:有限上下文信息的 Token 分配

而由于 LLM 的处理能力受到 token 数的限制,如何在有限的 token 范围内提供最相关的上下文信息,便是另外一个重要的问题。

Expand All @@ -110,19 +45,3 @@ suffixPercent,其用于指定在生成代码提示时要用多少 prompt token

通过增加 suffixPercent,可以让 Copilot 更关注当前正在编写的代码片段的上下文信息,从而生成更相关的代码提示。而通过调整
fimSuffixLengthThreshold,可以控制 Fill-in-middle 的使用频率,从而更好地控制生成的代码提示的准确性。

## 结论

GitHub Copilot 可以在有限的 token 范围内提供最相关的上下文信息,从而生成更准确、更有用的代码提示。这些策略提供了一定的灵活性,用户可以根据自己的需要来调整
Copilot 的行为,从而获得更好的代码自动补全体验。

我们跟进未来的路,依旧很长。

Copilot 逆向工程相关资料:

- [https://github.com/thakkarparth007/copilot-explorer](https://github.com/thakkarparth007/copilot-explorer)
- [https://github.com/saschaschramm/github-copilot](https://github.com/saschaschramm/github-copilot)

其它相关资料:

- [https://github.com/imClumsyPanda/langchain-ChatGLM](https://github.com/imClumsyPanda/langchain-ChatGLM)
83 changes: 83 additions & 0 deletions src/5-github-copilot.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,73 @@
# 场景示例:GitHub Copilot 分析


上个月在计划为 AutoDev 添加多语言支持时候,发现 GitHub Copilot 的插件功能是语言无关的(通过 plugin.xml 分析),便想研究一下它是如何使用
TreeSitter 的。可惜的是,直到最近才有空,研究一下它是如何实现的。

在探索的过程中,发现:Copilot 围绕上下文做了非常之多的工作,便想着写一篇文章总结一下。

## GitHub Copilot 的上下文构建

与 ChatGPT 相比,GitHub Copilot 的强大之处在于,它构建了足够多的上下文,结合其对 LLM 的训练(或微),可以写出非常精准的**生产级代码
**

### Copilot 的可见上下文

在肉眼可见的级别里,即我们自身的使用感受,我们可以发现 Copilot 不仅是读取当前文件的源码,而是一系列相关文件的源码,以构建更详细的上下文。

简单可以先划分三个场景:

- 当前文件。可以感知某个类的属性和方法,并做出自动填充。
- 相近文件。如测试文件,可以知道被测类的信息,并自动编写用例。
- 编辑历史(疑似)。即当我们以某种方式修改多个代码时,它也能识别出这个变化。

而在未来,相信它会获取诸如项目上下文等信息,如 Gradle 依赖、NPM 依赖等信息,避免在打开的 tab 不够用的情况下,引用不存在的依赖。

而针对于企业自身的 AI 编程工具而言,还可以结合服务上下文、业务上下文进行优化。

### Copilot 的不可见过程

结合网上的逆向工程资料,以及自己对代码的 debug 尝试,最后梳理了一个大致的 “四不像” (实在是懒得继续画)架构图。

其作用如下:

- 监听用户操作(IDE API )。监听用户的 Run Action、快捷键、UI 操作、输入等,以及最近的文档操作历史。
- IDE 胶水层(Plugin)。作为 IDE 与底层 Agent 的胶水层,处理输入和输出。
- 上下文构建(Agent)。JSON RPC Server,处理 IDE 的各种变化,对源码进行分析,封装为 “prompt” (疑似) 并发送给服务器。
- 服务端(Server)。处理 prompt 请求,并交给 LLM 服务端处理。

而在整个过程中,最复杂的是在 Agent 部分,从上下文中构建出 prompt。

### Copilot 的 Prompt 与上下文

在 “公开” 的 Copilot-Explorer 项目的研究资料里,可以看到 Prompt 是如何构建出来的。如下是发送到的 prompt 请求:

```kotlin
{
"prefix": "# Path: codeviz\\app.py\n#....",
"suffix": "if __name__ == '__main__':\r\n app.run(debug=True)",
"isFimEnabled": true,
"promptElementRanges": [
{ "kind": "PathMarker", "start": 0, "end": 23 },
{ "kind": "SimilarFile", "start": 23, "end": 2219 },
{ "kind": "BeforeCursor", "start": 2219, "end": 3142 }
]
}
```

其中:

- 用于构建 prompt 的 `prefix` 部分,是由 promptElements
构建了,其中包含了:`BeforeCursor`, `AfterCursor`, `SimilarFile`, `ImportedFile`, `LanguageMarker`, `PathMarker`, `RetrievalSnippet`
等类型。从几种 `PromptElementKind` 的名称,我们也可以看出其真正的含义。
- 用于构建 prompt 的 `suffix` 部分,则是由光标所在的部分决定的,根据 tokens 的上限(2048 )去计算还有多少位置放下。而这里的
Token 计算则是真正的 LLM 的 token 计算,在 Copilot 里是通过 Cushman002 计算的,诸如于中文的字符的 token
长度是不一样的,如: `{ context: "console.log('你好,世界')", lineCount: 1, tokenLength: 30 }` ,其中 context 中的内容的
length 为 20,但是 tokenLength 是 30,中文字符共 5 个(包含 `` )的长度,单个字符占的 token 就是 3。

到这里,我算是解决我感兴趣的部分,Agent 包里的 TreeSitter 则用于分析源码,生成 `RetrievalSnippet` ,其中支持语言是 Agent
自带的 `.wasm` 相关的包,诸如:Go、JavaScript、Python、Ruby、TypeScript 语言。

## Copilot 如何构建及时的 Token 响应

为了提供更好的编程体验,代码自动补全工具需要能够快速响应用户的输入,并提供准确的建议。在 Copilot
Expand Down Expand Up @@ -41,3 +109,18 @@ tokens 的使用。

未来,一定也会有滥用 token 程序,诸如于 AutoGPT 就是一直非常好的例子。

## 结论

GitHub Copilot 可以在有限的 token 范围内提供最相关的上下文信息,从而生成更准确、更有用的代码提示。这些策略提供了一定的灵活性,用户可以根据自己的需要来调整
Copilot 的行为,从而获得更好的代码自动补全体验。

我们跟进未来的路,依旧很长。

Copilot 逆向工程相关资料:

- [https://github.com/thakkarparth007/copilot-explorer](https://github.com/thakkarparth007/copilot-explorer)
- [https://github.com/saschaschramm/github-copilot](https://github.com/saschaschramm/github-copilot)

其它相关资料:

- [https://github.com/imClumsyPanda/langchain-ChatGLM](https://github.com/imClumsyPanda/langchain-ChatGLM)
10 changes: 10 additions & 0 deletions src/5-user-intent-oriented-design.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# 用户意图导向设计

![AI 2.0](images/ai-20-ux.png)

通过设计全新的人机交互体验,构建领域特定的 AI 角色,以更好地理解用户的意图。例如,在聊天应用程序中,AI
可以使用自然语言处理来理解用户的意图,从而更好地回答用户的问题。除此之外,还可以探索其他交互方式,如语音识别、手势识别等,以提高用户体验。

## 模式:实时返回

## 模式:请求-生成 UI-确认

Binary file added src/images/ai-20-ux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/context-eng.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fe89730

Please sign in to comment.