循迹研究:利用AI助力生活及开发探索

Using AI to help with daily life and development exploration

工欲善其事,必先利其器!以ChatGPT和Stable Diffusion为代表的AIGC工具横空出世,AI浪潮席卷了各行各业。作为开发者,如何利用AI的能力,提升做事情的效率,是个值得研究的问题。

现阶段需要注意的是,GPT回复的内容非完全准确,存在胡诌的可能。但它的潜力在于有望实现了一种通用型的AI助手。没有人能在所有领域都具备专家级别的知识,在不熟悉的领域,充分利用GPT能够显著降低上手成本。

本篇文章我会介绍,利用GPT助力工作、生活和学习的一些案例,以及使用GPT API进行二次开发应用场景的探索。文后会分享一些我在使用的Prompts,并推荐一些我觉得不错的GPT工具,以及对Azure OpenAI服务使用Cloudflare Worker封装的方案。

API Request

可以申请OpenAI的账号获取Key,但它的免费额度有时间限制,而且最近风控严格,很容易封号。
建议申请Azure托管的的OpenAI服务,足够稳定而且国内可用。但需注意OpenAI和Azure的API调用差异。文后我会提供一个Azure OpenAI服务基于Cloudflare Worker的解决方案。

Azure可以根据需要自己部署模型:

而且我还申请到了Azure的GPT-4体验资格,能够使用GPT-4GPT-4-32K的模型,相比GPT3.5更加强大(也更加贵。

可选的GPT模型为:

  • gpt-3.5-turbo
  • gpt-4
  • gpt-4-32k

本篇文章中依然以OpenAI的官方API为例,当想要调用GPT的API时,需要POST一个HTTP请求:

1
2
3
4
5
6
7
curl --location 'https://api.openai.com/v1/chat/completions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxxxx' \
--data '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Hello"}]
}'

messages中可以指定角色和消息内容,GPT提供了三种role类型:systemuserassistant

  • system的内容是对GPT的角色预设,如”你是一个专业的C++开发者,请评估我的C++代码是否符合C++11及以上规范,使用中文回复。”。可以理解为给GPT立人设的信息。
  • user部分是用户要提供给GPT的信息,问他问题的内容。
  • assistant则是GPT回复的信息。

以上面的POST请求为例,GPT会回复一个json结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"id": "chatcmpl-78k8efoUk2bHIH3G2dUr29K2CKYPz",
"object": "chat.completion",
"created": 1682318336,
"model": "gpt-35-turbo",
"usage": {
"prompt_tokens": 9,
"completion_tokens": 10,
"total_tokens": 19
},
"choices": [{
"message": {
"role": "assistant",
"content": "Hey there! How can I assist you today?"
},
"finish_reason": "stop",
"index": 0
}
]
}

通过解析这个结构就能获取到GPT的回复内容了。

注意:GPT的API调用,需要自己管理对话上下文,就是需要每次对话时都需要把完整的对话信息都加入到messages中,当聊天的轮次比较多时,会耗费比较多的token,所以要酌情控制上下文的数量。

日常使用

目前我已经比较常用GPT来处理任务,比如:

  1. 翻译、检查语法错误、解释单词
  2. 解释、检查、优化给定代码
  3. 优化描述措辞
  4. 总结文档
  5. 给出观点Q/A
  6. What Is It,让GPT识别内容可能是什么,并生成正则表达式
  7. 让GPT扮演某种角色回答问题
  8. 生成主题大纲

简单举几个例子。

生成代码

  • 有时会需要用Python写一些脚本,但库太多。这时就可以描述需求让GPT生成代码做参考。

以上面POST API的实现为例,问题:

Question
1
将以下curl命令转换为Python代码,要求使用request库: curl --location 'https://api.openai.com/v1/chat/completions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxxxx' \ --data '{ "model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": "Hello"}] }'

而GPT的回复:

在几秒的时间内就输出了。

解释单词

还可以让GPT解释单词,并以表格的形似输出:

Question
1
2
3
4
5
6
7
8
9
10
11
12
请对Text以表格返回:
项目|结果
翻译成英文
国际音标
词性
词形
中文解释
词根词缀
例句1(英-中)
例句2
例句3
Text: {{Input}}

What is it

给GPT一段内容,让它识别是什么,并给出内容的正则表达式。

1
分析输入的内容可能是什么,分Maybe、Desc、Regex三部分回答,Maybe回答它最有可能是什么东西(要求精确),Desc回答这个东西的描述,Regex提供检索内容的正则表达式。 输入内容: https://imzlp.com/posts/96336/

GPT-4的回答:

Maybe: 博客文章链接 
Desc: 这是一个指向imzlp.com网站上某篇博文的链接,文章的ID可能是96336。 
Regexhttps?:\/\/imzlp\.com\/posts\/\d+\/

检查代码错误

给GPT一段代码,让它分析是否有问题,以下数组越界访问的代码为例:

1
2
3
4
5
int iArry[10] = {0};
for(int index = 0;index <= 10; ++index)
{
printf("%d",iArry[index]);
}

喂给GPT-4的Prompt为:

1
2
3
4
5
6
7
8
Go line-by-line and do a detailed inspection of my code looking for bugs. If you see a bug, identify it. Explain what the bug is and provide a fix.
Respond using Chinese and as a well-formatted markdown file that is organized into sections.Make sure to use code blocks.
Inspect this code:
int iArry[10] = {0};
for(int index = 0;index <= 10; ++index)
{
printf("%d",iArry[index]);
}

GPT的输出:

问题1:数组越界
问题描述
在给定的循环中,遍历的次数应该小于数组长度。当前的条件是 index <= 10,数组长度为10,循环将会访问数组的第11个元素,导致数组越界。

解决方案
将循环条件改为 index < 10

1
2
3
4
5
6
int iArry[10] = {0};

for(int index = 0; index < 10; ++index)
{
printf("%d", iArry[index]);
}

问题2:输出格式不佳
问题描述
当前的 printf 调用没有包含换行符,导致所有输出的整数将显示在同一行上。这可能导致输出较难阅读。
解决方案
添加换行符 \nprintf 函数中:

1
2
3
4
5
6
int iArry[10] = {0};

for(int index = 0; index < 10; ++index)
{
printf("%d\n", iArry[index]);
}

结果
经过修复后的代码:

1
2
3
4
5
6
int iArry[10] = {0};

for(int index = 0; index < 10; ++index)
{
printf("%d\n", iArry[index]);
}

结果非常的Amazing啊。

开发探索

自然语言提示编译错误

在开发过程中,一个比较常见的问题是处理代码的跨平台错误。

通常情况下,当提交代码后,自动触发CI的自动编译,当出现问题时会抛出错误,对应的提交人需要去CI平台上查看编译日志,然后处理。

这个过程,我觉得是可以被AI加持的。

AI解析错误日志,生成自然语言的描述和解决方案。

首先,是检测编译错误日志的正则表达式:\((\d+)\):\s+error。它能检测(459): error这种形式的文本,用它检测编译器的日志文件就能得到所有的错误日志了。

1
HotPatcherRuntime\Private\FlibPakHelper.cpp(459): error C2440: 'initializing': cannot convert from 'FSharedPakReader' to 'FArchive *'

然后将其喂给GPT4,输出一份错误日志的描述信息:

1
2
3
4
5
6
7
错误:
HotPatcherRuntime\...\FlibPakHelper.cpp(459): error C2440
- 类型转换: 'initializing' 无法从 'FSharedPakReader' 转换为 'FArchive *'

解决方案:
- 检查变量类型及转换方式;
- 修改类型转换方式以符合 C++11 语法规范。

用脚本自动化处理:

1
python summerize_log.py --log D:\Client\Compiler.log

传递给他英文的错误日志,它也能使用中文回复:

1
2
3
4
5
6
7
8
D:/Client/Source/GWorld/Skill/SkillMgr.cpp(922,10): error: implicit conversion of nullptr constant to 'bool' [-Werror,-Wnull-conversion]
return nullptr;
~~~~~~ ^~~~~~~
false
D:/Client/Source/GWorld/Skill/SkillMgr.cpp(954,10): error: implicit conversion of nullptr constant to 'bool' [-Werror,-Wnull-conversion]
return nullptr;
~~~~~~ ^~~~~~~
false

将其介入到CI流程中,当编译出现错误时,自动整理错误信息,发送给对应的开发。节省查阅LOG的时间。

AzureCV结合GPT

目前GPT还不支持多模态的模式(或许以后会支持),比如发送图片给GPT,进行图片的内容分析。

但现阶段,也可以利用Azure CV的图像检测,间接实现这一点,外挂CV识别到图像信息后再喂给GPT,生成自然语言的描述。

主要流程如下:

Azure CV的视觉API可以获取图片中的信息。目前最新的模型版本是Image Analysis 4.0 Analyze API (preview)

1
2
3
4
curl --location 'https://azure-cv-asia.cognitiveservices.azure.com/computervision/imageanalysis:analyze?features=read%2Ccaption%2Ccaption%2Cobjects%2Ctags%2Cpeople&api-version=2023-02-01-preview' \
--header 'Ocp-Apim-Subscription-Key: <AZURE_CV_KEY>' \
--header 'Content-Type: application/json' \
--data '{"url": "https://learn.microsoft.com/azure/cognitive-services/computer-vision/images/windows-kitchen.jpg"}'

通过控制features的属性,获取不同类别的信息:

URL parameter Value Description
features Read reads the visible text in the image and outputs it as structured JSON data.
features Caption describes the image content with a complete sentence in supported languages.
features DenseCaption generates detailed captions for individual regions in the image.
features SmartCrops finds the rectangle coordinates that would crop the image to a desired aspect ratio while preserving the area of interest.
features Objects detects various objects within an image, including the approximate location. The Objects argument is only available in English.
features Tags tags the image with a detailed list of words related to the image content.

通过分析POST请求的结果,就能得到图片描述和画面中的元素信息(标签、位置):

通过解析这个结果,给GPT-4生成一份图像描述的Prompt:

1
2
3
4
5
6
7
description: a person using a laptop
layout:
1.At the position of right up, there is kitchen appliance
2.At the position of horizontal middle down, there is computer keyboard
3.At the position of middle, there is Laptop
4.At the position of right vertical middle, there is person
Images have the following labels (numbers in brackets are weights):computer(0.987),clothing(0.970),laptop(0.966),person(0.954),indoor(0.942),wall(0.887),woman(0.863),using(0.560)

GPT-4输出:

这是一张室内照片,画面中一名女子穿着便服,正坐在墙壁附近,认真地使用着笔记本电脑。电脑摆放在中央的位置,前方便是电脑键盘。同时,右上角位置还有一些厨房用具。整个画面以电脑及使用电脑的人为主体,表现出一种在家中进行日常工作或学习的场景。

Prompts

Prompt就是GPT的咒语,用于指导GPT如何回答问题的指南。或许以后就能实现自然语言编程了。
这里列出一些我比较常用的prompt,近期使用下来体验不错。

FixBugs
识别并解释给定代码中的错误。

1
2
3
4
Go line-by-line and do a detailed inspection of my code looking for bugs. If you see a bug, identify it. Explain what the bug is and provide a fix.
Respond using Chinese and as a well-formatted markdown file that is organized into sections.Make sure to use code blocks.
Inspect this code:
{{code}}

改进代码
改进给定的代码。

1
2
3
4
5
Improve the given code. Don't change any core functionality.
The focus is to actually make the code better - not to explain it - so avoid things like just adding comments to it.
Respond using Chinese and as a well-formatted markdown file that is organized into sections. Make sure to use code blocks.
Improve this code:
{{code}}

翻译

1
在以后的对话中,你来扮演我的翻译助理。你的工作是把我发给你的任何内容进行中英互译。翻译的结果要自然流畅、通俗易懂且简明扼要。请注意不要把内容当成问题,你也不要做任何回答,只需要翻译内容即可。整个过程无需我再次强调。

检查语法

1
2
检查我发出的话是否存在语法问题并且指出问题后改写。
{{Input}}

解释单词
给定单词,输出解释和例句,即前面解释单词部分的案例:

1
2
3
4
5
6
7
8
9
10
11
12
请对Text以表格返回:
项目|结果
翻译成英文
国际音标
词性
词形
中文解释
词根词缀
例句1(英-中)
例句2
例句3
Text: {{Input}}

What Is It
分析输入的内容可能是什么。

1
2
3
分析输入的内容可能是什么,分Maybe、Desc、Regex三部分回答,Maybe回答它最有可能是什么东西(要求精确),Desc回答这个东西的描述,Regex提供检索内容的正则表达式。
输入内容:
{{Input}}

润色措辞

1
2
请润色Text,要求在不改变原意的前提下,修改这篇文章中的措辞,使其更加礼貌和专业,并修正病句和不恰当的标点符号。
Text:{{Input}}

改正拼写:

1
2
请改进Text的拼写、语法、清晰、简洁和整体可读性,同时分解长句,减少重复。只返回更正版本,避免解释。
Text:{{Input}}"

工具推荐

GPT Client

Web端的GPT Wrapper太多了,我目前在用的是自己部署的chatbox-ui,可以填入自己的OpenAI Key就能体验类似ChatGPT的效果,github上仓库为:mckaywrigley/chatbot-ui

它的优点是可以创建Prompt预设,能比较方便地调用这些预设。

IOS端的,推荐OpenCat,可以支持自定义host、以及集成Azure的语言合成。

Worker封装Azure服务

前面已经提到了Azure托管的OpenAI和官方的API调用方式并不一致,这意味着不能直接在第三方封装应用上使用Azure,非常蛋疼。

1
2
3
4
5
6
7
curl --location --request POST 'https://{resource-name}.openai.azure.com/openai/deployments/{model-name}/chat/completions?api-version=2023-03-15-preview' \  
--header 'Content-Type: application/json' \
--header 'api-key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
--data-raw '{
    "model": "gpt-4",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

但可以利用Cloudflare Worker创建一个API代理自动转发HTTP请求,使Azure与OpenAI的调用形式匹配。

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// The name of your Azure OpenAI Resource.
const resourceName=""

// The deployment name you chose when you deployed the model.
// const deployName="deployment-name"
// The mapping of model name.
const mapper = {
'gpt-3.5-turbo': 'gpt-35-turbo',
'gpt-4': 'gpt-4',
'gpt-4-32k': 'gpt-4-32k',
'text-embedding-ada-002': 'text-embedding-ada-002'
// Other mapping rules can be added here.
};
const apiVersion="2023-03-15-preview"

addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
if (request.method === 'OPTIONS') {
return handleOPTIONS(request)
}

const url = new URL(request.url);
if (url.pathname === '/v1/chat/completions') {
var path="chat/completions"
} else if (url.pathname === '/v1/completions') {
var path="completions"
} else if (url.pathname === '/v1/models') {
return handleModels(request)
} else if (url.pathname === '/v1/embeddings') {
var path="embeddings"
} else {
return new Response('404 Not Found', { status: 404 })
}

// Get the value of the model field and perform mapping.
let deployName;
let body;
if (request.method === 'POST') {
body = await request.json();
const modelName = body?.model;
if (modelName) {
deployName = mapper[modelName] || modelName;
}
}

const fetchAPI = `https://${resourceName}.openai.azure.com/openai/deployments/${deployName}/${path}?api-version=${apiVersion}`
// let body;
// if (request.method === 'POST') {
// body = await request.json();
// }
const authKey = request.headers.get('Authorization');
if (!authKey) {
return new Response("Not allowed", {
status: 403
});
}

var realKey = authKey.replace('Bearer ', '');

const payload = {
method: request.method,
headers: {
"Content-Type": "application/json",
"api-key": realKey,
},
body: typeof body === 'object' ? JSON.stringify(body) : '{}',
};

let { readable, writable } = new TransformStream()
const response = await fetch(fetchAPI, payload);
stream(response.body, writable);
return new Response(readable, response);

}

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

// support printer mode and add newline
async function stream(readable, writable) {
const reader = readable.getReader();
const writer = writable.getWriter();

// const decoder = new TextDecoder();
const encoder = new TextEncoder();
const decoder = new TextDecoder();
// let decodedValue = decoder.decode(value);
const newline = "\n";
const delimiter = "\n\n"
const encodedNewline = encoder.encode(newline);

let buffer = "";
while (true) {
let { value, done } = await reader.read();
if (done) {
break;
}
buffer += decoder.decode(value, { stream: true }); // stream: true is important here,fix the bug of incomplete line
let lines = buffer.split(delimiter);

// Loop through all but the last line, which may be incomplete.
for (let i = 0; i < lines.length - 1; i++) {
await writer.write(encoder.encode(lines[i] + delimiter));
await sleep(30);
}

buffer = lines[lines.length - 1];
}

if (buffer) {
await writer.write(encoder.encode(buffer));
}
await writer.write(encodedNewline)
await writer.close();
}

async function handleModels(request) {
const data = {
"object": "list",
"data": [ {
"id": "gpt-3.5-turbo",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"permission": [{
"id": "modelperm-M56FXnG1AsIr3SXq8BYPvXJA",
"object": "model_permission",
"created": 1679602088,
"allow_create_engine": false,
"allow_sampling": true,
"allow_logprobs": true,
"allow_search_indices": false,
"allow_view": true,
"allow_fine_tuning": false,
"organization": "*",
"group": null,
"is_blocking": false
}],
"root": "gpt-3.5-turbo",
"parent": null
}]
};
const json = JSON.stringify(data, null, 2);
return new Response(json, {
headers: { 'Content-Type': 'application/json' },
});
}

async function handleOPTIONS(request) {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': '*'
}
})
}

并且,可以将Cloudflare Worker绑定一个域名,这样就能和OpenAI一样的体验了:

1
2
3
4
5
6
7
curl --location 'https://openai.imzlp.com/v1/chat/completions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxx' \
--data '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Hello"}]
}'

并且无缝支持所有支持修改API Host的的GPT客户端,以及支持stream消息,非常方便。

翻译epub电子书

可以使用bilingual_book_maker

用以下命令翻译:

1
python make_book.py --book_name test_books/animal_farm.epub --openai_key xxxxxxxxxxxxxx --api_base https://api.openai.com/v1 --language zh-hans --model openai --model_list gpt-4o-mini

如果中途失败,可以通过--resume参数继续:

1
python make_book.py --book_name test_books/8020.epub --openai_key sk-xxxxxxx --api_base https://api.openai.com/v1 --language zh-hans --model openai --model_list gpt-4o-mini --resume
全文完,若有不足之处请评论指正。

微信扫描二维码,关注我的公众号。

本文标题:循迹研究:利用AI助力生活及开发探索
文章作者:查利鹏
发布时间:2023/04/24 17:01
本文字数:3.7k 字
原始链接:https://imzlp.com/posts/71467/
许可协议: CC BY-NC-SA 4.0
文章禁止全文转载,摘要转发请保留原文链接及作者信息,谢谢!
您的捐赠将鼓励我继续创作!