我是一个业余机器人爱好者,今天想谈一下我是怎么开发OriginBot的。
其实从标题也能知道,我是利用ChatGPT结伴开发的,但是这个过程中有很多细节,想要详细的说一下的。我想,这个过程应该会对其他人也有有一点帮助。
在本地部署一个ChatGPT
1. 部署ChatGPT
众所周知,OPENAI在国内不能直接访问,而且GPT4要付费才能使用,20美金一个月,3个小时内只能调用25次GPT4。
所以我其实使用的是Azure OPENAI服务,最大的好处就是没有网络限制,国内可以直接访问。
我用的Azure是公司的账户,所以不用自己管理账户和申请Azure OPENAI服务,相关的操作网上有很多资料,我贴两个我觉得写的还不错的博客链接:
Azure自己的OPENAI服务没有历史聊天记录功能,也就是说,每次刷新页面后,之前的聊天记录都没了,这个非常不方便,因为经常需要翻看之前的记录或者代码之类的,所以我基于网上的两个开源项目自己搭建了一个本地的ChatGPT。
- azure-openai-proxy
这个项目的作用是对Azure OPENAI服务的API进行封装,使其跟openai原生的API一致 - https://github.com/Yidadaa/ChatGPT-Next-Web
这个项目的作用是在本地起一个类似chatgpt官网那样的网站,可以让我们在本地跟chatgpt聊天、提问
两个开源项目的文档非常完善,有兴趣的可以去仔细看一下,我在这里提供两行命令,修改一下参数直接运行就能使用了。
# 拉取镜像
docker pull ishadows/azure-openai-proxy:latest
# 运行一个azure-openai-proxy的容器
docker run -d -p 8080:8080 --name=azure-openai-proxy --env AZURE_OPENAI_ENDPOINT=https://xxxxxxxxx.openai.azure.com/ --env AZURE_OPENAI_MODEL_MAPPER=gpt-35-turbo-0301=xxxxxxx,gpt-4=xxxxxx,gpt-4-32k=xxxxx ishadows/azure-openai-proxy:latest
# 拉镜像
docker pull yidadaa/chatgpt-next-web:latest
# 运行一个chatgpt-next-web的容器
docker run -d -p 3000:3000 -e OPENAI_API_KEY="xxxxx" -e CODE="xxxxx" -e BASE_URL=http://ip:8080 yidadaa/chatgpt-next-web:latest
几个参数说明如下:
- AZURE_OPENAI_ENDPOINT=https://xxxxxxxxx.openai.azure.com
这个是自己部署的模型的https地址 - AZURE_OPENAI_MODEL_MAPPER=gpt-35-turbo-0301=xxxxxxx
这是Azure中OPENAI几个模型的匹配关系,gpt-35-turbo-0301 是Azure官方定义好的,后面的xxxxx应该填写自己定义的名字,可以填写多个,用逗号隔开,如命令行中所示 - OPENAI_API_KEY=”xxxxx”
这个就是Azure OPENAI的秘钥, - CODE=”xxxxx”
这是用于在页面上做认证的,防止你部署的chatgpt-next-web被别人访问,建议这个一定要足够长,毕竟一旦被别人访问到,消耗的是自己的钱
上面几个参数配置成功之后,就可以在本地浏览器访问http://127.0.0.1:3000 端口,效果如下:
2. 参数调整
参数调整只有一个参数需要注意,就是Temperature,经常使用ChatGPT的人应该知道这个参数,我不是专业的大模型从业者,所以不想解释这个参数的作用原理,只说一下我的实际使用感受。
Temperature的范围是0~1,值越大,回答越多样性,但是错误也更多,值越小,回答越固定,但是也更可靠。
我自己在OriginBot这个场景下使用的值是0.4,因为我还是希望它更靠谱一点,不要经常出错,因为目前在跟机器人相关的更多场景下,我还没有自己判断它的回答正确与否的能力,只能选择相信它。
但是对于比较专业的人,这个值可以设置的高一点,这样可以获得更加多样性的回答,不过要注意甄别它回答的答案。
如何编写Prompt和如何提问
按照前面的步骤,我们现在有了一个可用的ChatGPT了,现在开始使用它。
使用ChatGPT的时候主要需要注意的就是Prompt和提问两块,我使用的Prompt分为通用Prompt和定制Prompt两部分,下面会按照共用Prompt、提问和定制Prompt的顺序来介绍。
1. 通用Prompt
以下是我使用的Prompt,简单来说就是一个角色赋予,给chatgpt指定一个角色,比如这里的“机器人开发专家”, 然后描述一些对这个角色的期待,比如我希望它熟悉ros2和自动导航,另外,因为我对python比较熟悉,希望它尽量使用Python而不是C++。
你是一名机器人开发专家,熟悉机器人行业的最新技术和现状,熟练掌握机器人开发的必要技能,例如ros2,嵌入式开发、STM32芯片、PCB知识、SLAM、自动导航和驾驶、机器人运动模型等,我会交给你一些任务,请你尽力完成,在完成任务的过程中,你应该结合你的岗位和技能,尽可能做到完善,并且你可以做出你觉得必要的修改和延伸,另外,如果交给你的任务需要写代码,尽量使用Python
2. 如何提问
关于提问,最简单的方法,肯定就是直接跟chatgpt聊天,但是这样效果一般。我的做法是把OriginBot的代码喂给chatgpt,然后再提问题,这样效果会比较好。
我写了一个脚本,可以把本地的代码生成格式化的文件,我们可以生成的文件的内容发送给chatgpt,脚本如下:
import os
def is_code_file(file_path):
extensions = [
'.py',
'.cpp',
'.c',
'.h',
'.java',
'.js',
'.css',
'.html',
'.php',
'.rb',
'.rs',
'.md',
'.txt',
'.yaml',
'.yml',
'.lua',
]
return any(file_path.endswith(ext) for ext in extensions)
def save_structure_and_files(directory, output_file, excluded_directories=None):
if excluded_directories is None:
excluded_directories = []
with open(output_file, 'w') as outfile:
# Save directory structure
outfile.write("Directory Structure:\n")
for root, dirs, files in os.walk(directory):
if any(excluded_dir in root for excluded_dir in excluded_directories):
continue
level = root.replace(directory, '').count(os.sep)
indent = ' ' * 4 * (level)
outfile.write(
'{}{}{}\n'.format(
indent, '|----' if level > 0 else '', os.path.basename(root)
)
)
sub_indent = ' ' * 4 * (level + 1)
for file_name in files:
outfile.write('{}|----{}\n'.format(sub_indent, file_name))
# Save code files content
outfile.write("\n\nFiles Content:\n")
for root, _, files in os.walk(directory):
if any(excluded_dir in root for excluded_dir in excluded_directories):
continue
for file in files:
file_path = os.path.join(root, file)
if is_code_file(file_path):
outfile.write(f"\n\n{file_path}\n")
outfile.write('-' * len(file_path))
outfile.write("\n")
with open(file_path, 'r') as code_file:
content = code_file.read()
outfile.write(f"{content}\n")
# Usage example
directory = "/originbot/originbot_navigation"
output_file = "output.txt"
excluded_directories = ["venv", "send_goal"]
save_structure_and_files(directory, output_file, excluded_directories)
脚本的作用是对directory(/originbot/originbot_navigation)目录中所有文件生成一个目录树,然后再把每一个文件的内容复制到output.txt中。
以/originbot/originbot_navigation目录为例,效果如下:
Directory Structure:
originbot_navigation
|----CMakeLists.txt
|----package.xml
|----param
|----originbot_nav2.yaml
|----config
|----lds_2d.lua
|----ekf.yaml
|----launch
|----occupancy_grid.launch.py
|----cartographer.launch.py
|----ekf.md
|----nav_bringup.launch.py
|----odom_ekf.launch.py
|----maps
|----my_map.yaml
|----my_map.pgm
Files Content:
/home/zhixiang_pan/learningspace/origin/originbot/originbot_navigation/CMakeLists.txt
-------------------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.5)
project(originbot_navigation)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
可以看到,一开始是一个目录树,然后就是具体的代码。
这样做的好处在于可以让ChatGPT更准确地理解OriginBot现有的代码和功能,再让它教我或者开发新的功能时候就更容易理解到我们的需求。
但是,再指定directory参数的时候,directory所指向的目录中,不要包含太多的文件,不然最后生成的output.txt的内容太多,超过了ChatGPT的token上限也不行。
我用的是gpt4-32k,也就是token的上限是32k,现在还有gpt3.5-turbo-120k的,也就是支持120k token,不过我没有使用过,不知道效果如何。
3. 定制Prompt
在“公共Prompt”里面,我提供了一个文字版的Prompt,这里我再提供另一种Prompt,如下:
我会交给你一些信息、要求,请你完成任务。
以下是信息:
1. OriginBot是一个两轮的轮式机器人,基于ROS2 foxy开发
2. 运动速度的topic是/cmd_vel
以下是要求:
1. 代码只能用Python
2. 要基于rclpy.node的Node类拓展
3. 代码中要考虑在合适的地方调用rclpy.shutdown()来销毁当前Node节点,而不是要求手动介入
4. 不管什么场景下,OriginBot的速度不要超过0.4米/s
5. 输出只能包含markdown格式的python代码,格式模板如下:
```python
###---
import rclpy
from geometry_msgs.msg import Twist
from rclpy.node import Node
class OriginBot(Node):
def __init__(self):
...
def xxx_function(self):
...
def main(args=None):
rclpy.init(args=args)
originbot = OriginBot()
rclpy.spin(originbot)
originbot.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
###---
代码开头和结尾的###---都必须要显示的输出,并且最后要调用main函数
以下是任务:
xxxxx
```
可以很明显地看出来两种Prompt的区别。在这个Prompt里面,我会告诉ChatGPT很多具体的信息,比如OriginBot的速度的topic、限定线速度的大小、操作系统的版本等,最重要的是,提供了一个代码模板,要求ChatGPT按照这个模板回答问题。
这种Prompt适用于我们明确地知道我们“想要什么”,只是需要ChatGPT来写代码,提供代码模板可以提高ChatGPT生成的代码的准确率。
从我自己的使用经验来看,提供模板之后,对于单个且具体的任务,ChatGPT生成的代码都是可以直接使用的,不用做任何修改。所谓单个且具体的任务,比如像:让OriginBot画一个半径为0.5米的圆圈。
以上就是我使用ChatGPT结伴开发OriginBot的过程和方法,欢迎大家交流。
评论(5)
您还未登录,请登录后发表或查看评论