Code Reader 体验地址:https://chat.openai.com/g/g-c1J88bC63-code-reader Coder Reader Github 地址:https://github.com/sdaaron/github-reader
对不少程序员来说,学习一个新的开源项目是一件挺有难度的事。知名开源项目往往文件众多、结构复杂,往往让人在初上手时一头雾水,不知从何开始。
自动有了ChatGPT,相信很多人在某个时刻都产生过这个想法:「 什么时候ChatGPT 能够帮我一次性阅读整个源码仓库就好了!」
现在,依靠 GPT-4-Turbo 128K 的超长上下文长度和 GPTs 给 ChatGPT 赋予的可定制化能力,我们终于可以实现这个想法了。
另外,相信很多人现在对 GPTs 和 GPT Assistant 的印象是这样的:
GPTs 是给非程序员用的,只能通过prompt定义,最多勾选几项能力。可定制化程度低。
GPT Assisant 是给专业程序员用的,高度可定制化。
其实不然,本文将主要介绍一个奥特曼在发布会上没有讲的一个小细节:GPTs Actions,这项功能让 GPTs 也拥有了等效于函数调用的全部能力。让 GPTs 也成为了一个可以调用任何外部工具的开放性 Agent !
有GPTs访问权限的可以通过 https://chat.openai.com/g/g-c1J88bC63-code-reader 在线体验Code Reader。(注意:128K的窗口让GPT4-Turbo可以阅读大多数Github仓库,但是仍然有很多仓库的长度远远超高128K token限制,甚至长到会超过 web 服务器所能接受的上限,所以尽量不要用Coder Reader 去读那些过于大的项目。)
暂时无法访问GPTs的可以通过以下截图预览下 Code Reader 的使用体验:





太酷了,现在GPT可以阅读整个项目目录,学习开源项目变得前所未有地简单!
进入ChatGPT官方Web界面,如果你是ChatGPT Plus用户,此时应该已经可以看到GPTs的入口「 Explore 」:

进入「 Explore 」,点击「 Create a GPT 」,即可看到山姆奥特曼在发布会上显示的界面:

进入「 Configure 」,我们通过代码配置的方式进入这个GPT的开发,会更便捷一些:

这个界面左边是开发区,右边是预览区,开发完即可在预览区测试,非常方便。
填入你的GPT的名称、描述、指令、和对话开头。以下是我填的信息:

给我们的私人定制GPT接上外部工具:

这里有几种工具可以选:
知识库
OpenAI 内置的三大能力:网页浏览、DallE3 画图、Code Interpreter执行代码
Actions
这里我知识库和内置的三大能力都没有勾选,因为用不上,我们这个源码阅读助手的关键在于需要能让GPT访问到github仓库的源码,这需要 Actions 实现。所以接下来我们进入 Actions 开发。
开发 Actions:

所谓的 Actions, 其实也可以理解为函数调用(Function Calling)的一种具体形式。与函数调用不同的是, Actions 仅限于 GET/ POST/ PUT/ DELETE等有限动作,不像函数调用那样可以调用任意本地函数。当然,这也是理所应当的,毕竟 OpenAI也没有那么多计算资源可以让所有人在他们的硬件上跑云函数。
不过,能够执行 GET/ POST/ PUT/ DELETE 也完全够了,能够调用外部API就等于给GPT接上了无限可能。这里我们仅仅用一个获取Github仓库源码的API做示范,给GPT接上这个能力。
为了告诉GPT怎么调用API,需要定义一个Schema。这里 OpenAI提供了一些实例,这里我们用 OpenAI Profile 这个模版修改一下得到一个能够往请求体中传入 git_url 参数的Schema。

修改完成后的Schema如下:
{ "openapi": "3.1.0", "info": { "title": "Get Repository Content", "description": "get the source code content of an entire github repository.", "version": "v0.0.1" }, "servers": [ { "url": "https://github-reader.onrender.com" } ], "paths": { "/get-repo-content/": { "post": { "description": "get the source code content of an entire github repository.", "operationId": "Get Repository Content", "parameters": [], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Get Repository ContentRequestSchema" } } }, "required": true }, "deprecated": false, "x-openai-isConsequential": true } } }, "components": { "schemas": { "Get Repository ContentRequestSchema": { "properties": { "git_url": { "type": "", "title": "git_url", "description": "get the github repository url from user\u2019s input" } }, "type": "object", "required": [ "git_url" ], "title": "Get Repository ContentRequestSchema" } } } }
在这个Schema里面,我们需要自己定义的就是 Action的名称、描述、服务器url,PATH,每个PATH的描述和需要传入的参数。
(我11月9日第一次尝试开发一个GPTs的时候,OpenAI官方界面上还有一个可视化的配置界面可以配置这个Schema,所以第一次配的时候非常简单。但是截止到11月10日,这个界面已经迅速下线了,现在只能够通过Schema文件配置,非常迷惑,可能OpenAI发现了什么Bug临时下线了,之后大概还会恢复回来)
开发一个 API 来获取Github 仓库的源代码
我们已经告诉GPT应该通过向 https://github-reader.onrender.com POST 一个含有git_url的请求体,来获取某个Github仓库的源代码,但是目前还并不存在这样一个API可用,我们需要自己开发。
用FastAPI来搭建这样一个简单API非常简单,只需要70行代码,让GPT帮你写,1分钟就搞定了。
from fastapi import FastAPI, HTTPException
from git import Repo
import os
import shutil
from pydantic import BaseModel
app = FastAPI()
# 定义请求体的模型
class GitRepo(BaseModel):
git_url: str
@app.get("/")
async def get_main():
return {"message": "Hello World!"}
@app.post("/get-repo-content/")
async def print_repo_url(repo: GitRepo):
print(repo.git_url)
git_url = repo.git_url
base_dir = f"./{git_url.split('/')[-1]}"
try:
# 从URL中解析仓库名称
repo_name = git_url.split("/")[-1]
if repo_name.endswith(".git"):
repo_name = repo_name[:-4]
repo_dir = os.path.join(base_dir, repo_name)
print(repo_dir)
# 如果目录存在,先删除
if os.path.exists(repo_dir):
shutil.rmtree(repo_dir)
# 克隆仓库
Repo.clone_from(git_url, repo_dir)
content = read_all_files(repo_dir)
# 清理克隆的仓库目录
shutil.rmtree(repo_dir)
return {"content": content[:50000]}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
def read_all_files(directory):
all_text = ""
for root, dirs, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)
if os.path.isfile(file_path) and file_path.endswith(".py"):
try:
with open(file_path, "r", encoding="utf-8") as file:
filename = file_path.split("/")[-1]
all_text += f"File: {filename}\n\n" + file.read() + "\n\n"
except UnicodeDecodeError:
# 忽略无法读取的文件(如二进制文件)
pass
return all_text
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=80)
部署 API 服务
这个服务总共就70行代码,为了这点代码整一台云服务器部署实在太麻烦,所以这里我用了一个后端托管服务:render,将这个小脚本托管成了一个web后端服务。具体托管方法我就不浪费口舌了,可以参考https://render.com/docs。或者用其他自己熟悉的方式部署也行。
完整的render部署代码已经上传到 https://github.com/sdaaron/github-reader 了。需要用的话可以叉走一份。
大功告成!
现在你的API已经就绪,GPTs也开发完毕,快测试一下GPT是否能正确调用API吧!
如果成功,那么你已经掌握了一个能执行你自定义动作的私人GPT了!