Skip to main content

OpenAPI代理

我们可以构建代理来消费任意的API,这些API符合OpenAPI/Swagger规范。

1st example: 分层规划代理

在这个例子中,我们将考虑一种称为分层规划的方法,这在机器人技术中很常见,并在最近的LLMs X机器人作品中出现。我们将看到这是一种可行的方法,可以开始使用大规模API规范并帮助处理需要对API执行多个步骤的用户查询。

这个想法很简单:为了获得连续的代理行为并节省标记,我们将分离关注点:一个"规划器"将负责调用哪些端点,一个"控制器"将负责如何调用它们。

在最初的实现中,规划器是一个LLM链,它在上下文中为每个端点提供名称和简短描述。控制器是一个LLM代理,它只使用特定计划的端点文档进行实例化。还有很多工作要做,以使其非常稳健地工作 :)


## 1st example: hierarchical planning agent

在这个例子中,我们将考虑一种称为分层规划的方法,这在机器人技术中很常见,并在最近的LLMs X机器人作品中出现。我们将看到这是一种可行的方法,可以开始使用大规模API规范并帮助处理需要对API执行多个步骤的用户查询。

这个想法很简单:为了获得连续的代理行为并节省标记,我们将分离关注点:一个"规划器"将负责调用哪些端点,一个"控制器"将负责如何调用它们。

在最初的实现中,规划器是一个LLM链,它在上下文中为每个端点提供名称和简短描述。控制器是一个LLM代理,它只使用特定计划的端点文档进行实例化。还有很多工作要做,以使其非常稳健地工作 :)

开始之前,让我们收集一些OpenAPI规范。

import os, yaml
wget https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml
mv openapi.yaml openai_openapi.yaml
wget https://www.klarna.com/us/shopping/public/openai/v0/api-docs
mv api-docs klarna_openapi.yaml
wget https://raw.githubusercontent.com/APIs-guru/openapi-directory/main/APIs/spotify.com/1.0.0/openapi.yaml
mv openapi.yaml spotify_openapi.yaml
    --2023-03-31 15:45:56--  https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 122995 (120K) [text/plain]
Saving to: ‘openapi.yaml’

openapi.yaml 100%[===================>] 120.11K --.-KB/s in 0.01s

2023-03-31 15:45:56 (10.4 MB/s) - ‘openapi.yaml’ saved [122995/122995]

--2023-03-31 15:45:57-- https://www.klarna.com/us/shopping/public/openai/v0/api-docs
Resolving www.klarna.com (www.klarna.com)... 52.84.150.34, 52.84.150.46, 52.84.150.61, ...
Connecting to www.klarna.com (www.klarna.com)|52.84.150.34|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/json]
Saving to: ‘api-docs’

api-docs [ <=> ] 1.87K --.-KB/s in 0s

2023-03-31 15:45:57 (261 MB/s) - ‘api-docs’ saved [1916]

--2023-03-31 15:45:57-- https://raw.githubusercontent.com/APIs-guru/openapi-directory/main/APIs/spotify.com/1.0.0/openapi.yaml
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 286747 (280K) [text/plain]
Saving to: ‘openapi.yaml’

openapi.yaml 100%[===================>] 280.03K --.-KB/s in 0.02s

2023-03-31 15:45:58 (13.3 MB/s) - ‘openapi.yaml’ saved [286747/286747]

from langchain.agents.agent_toolkits.openapi.spec import reduce_openapi_spec
with open("openai_openapi.yaml") as f:
raw_openai_api_spec = yaml.load(f, Loader=yaml.Loader)
openai_api_spec = reduce_openapi_spec(raw_openai_api_spec)

with open("klarna_openapi.yaml") as f:
raw_klarna_api_spec = yaml.load(f, Loader=yaml.Loader)
klarna_api_spec = reduce_openapi_spec(raw_klarna_api_spec)

with open("spotify_openapi.yaml") as f:
raw_spotify_api_spec = yaml.load(f, Loader=yaml.Loader)
spotify_api_spec = reduce_openapi_spec(raw_spotify_api_spec)

我们将使用Spotify API作为一个稍微复杂的API的示例之一。如果您想要复制这个示例,需要进行一些与身份验证相关的设置。

  • 您需要在Spotify开发者控制台中设置一个应用程序,文档在这里,以获取凭据:CLIENT_IDCLIENT_SECRETREDIRECT_URI
  • 要获取访问令牌(并保持其有效性),您可以实现OAuth流程,或者您可以使用spotipy。如果您已将Spotify凭据设置为环境变量SPOTIPY_CLIENT_IDSPOTIPY_CLIENT_SECRETSPOTIPY_REDIRECT_URI,您可以使用下面的辅助函数:
import spotipy.util as util
from langchain.requests import RequestsWrapper


def construct_spotify_auth_headers(raw_spec: dict):
scopes = list(
raw_spec["components"]["securitySchemes"]["oauth_2_0"]["flows"][
"authorizationCode"
]["scopes"].keys()
)
access_token = util.prompt_for_user_token(scope=",".join(scopes))
return {"Authorization": f"Bearer {access_token}"}


# 获取API凭据。
headers = construct_spotify_auth_headers(raw_spotify_api_spec)
requests_wrapper = RequestsWrapper(headers=headers)

这个规范有多大?(How big is this spec?)

endpoints = [
(route, operation)
for route, operations in raw_spotify_api_spec["paths"].items()
for operation in operations
if operation in ["get", "post"]
]
len(endpoints)
    63
import tiktoken

enc = tiktoken.encoding_for_model("text-davinci-003")


def count_tokens(s):
return len(enc.encode(s))


count_tokens(yaml.dump(raw_spotify_api_spec))
    80326

让我们看一些例子!

从GPT-4开始。(GPT-3系列正在进行一些鲁棒性迭代。)

from langchain.llms.openai import OpenAI
from langchain.agents.agent_toolkits.openapi import planner

llm = OpenAI(model_name="gpt-4", temperature=0.0)
    /Users/jeremywelborn/src/langchain/langchain/llms/openai.py:169: UserWarning: You are trying to use a chat model. This way of initializing it is no longer supported. Instead, please use: `from langchain.chat_models import ChatOpenAI`
warnings.warn(
/Users/jeremywelborn/src/langchain/langchain/llms/openai.py:608: UserWarning: You are trying to use a chat model. This way of initializing it is no longer supported. Instead, please use: `from langchain.chat_models import ChatOpenAI`
warnings.warn(
spotify_agent = planner.create_openapi_agent(spotify_api_spec, requests_wrapper, llm)
user_query = (
"make me a playlist with the first song from kind of blue. call it machine blues."
)
spotify_agent.run(user_query)
    

> 进入新的AgentExecutor链...
动作:api_planner
动作输入:我需要找到正确的API调用来创建一个包含《Kind of Blue》第一首歌的播放列表,并将其命名为Machine Blues
观察结果:1. GET /search 以搜索专辑《Kind of Blue》
2. GET /albums/{id}/tracks 以获取《Kind of Blue》专辑的曲目
3. GET /me 以获取当前用户的信息
4. POST /users/{user_id}/playlists 以为当前用户创建一个名为Machine Blues的新播放列表
5. POST /playlists/{playlist_id}/tracks 以将《Kind of Blue》的第一首歌添加到Machine Blues播放列表中
思考:我有了计划,现在需要执行API调用。
动作:api_controller
动作输入:1. GET /search 以搜索专辑《Kind of Blue》
2. GET /albums/{id}/tracks 以获取《Kind of Blue》专辑的曲目
3. GET /me 以获取当前用户的信息
4. POST /users/{user_id}/playlists 以为当前用户创建一个名为Machine Blues的新播放列表
5. POST /playlists/{playlist_id}/tracks 以将《Kind of Blue》的第一首歌添加到Machine Blues播放列表中

> 进入新的AgentExecutor链...
动作:requests_get
动作输入:{"url": "https://api.spotify.com/v1/search?q=Kind%20of%20Blue&type=album", "output_instructions": "提取搜索结果中第一个专辑的id"}
观察结果:1weenld61qoidwYuZ1GESA
思考:动作:requests_get
动作输入:{"url": "https://api.spotify.com/v1/albums/1weenld61qoidwYuZ1GESA/tracks", "output_instructions": "提取专辑中第一首曲目的id"}
观察结果:7q3kkfAVpmcZ8g6JUThi3o
思考:动作:requests_get
动作输入:{"url": "https://api.spotify.com/v1/me", "output_instructions": "提取当前用户的id"}
观察结果:22rhrz4m4kvpxlsb5hezokzwi
思考:动作:requests_post
动作输入:{"url": "https://api.spotify.com/v1/users/22rhrz4m4kvpxlsb5hezokzwi/playlists", "data": {"name": "Machine Blues"}, "output_instructions": "提取创建的播放列表的id"}
观察结果:7lzoEi44WOISnFYlrAIqyX
思考:动作:requests_post
动作输入:{"url": "https://api.spotify.com/v1/playlists/7lzoEi44WOISnFYlrAIqyX/tracks", "data": {"uris": ["spotify:track:7q3kkfAVpmcZ8g6JUThi3o"]}, "output_instructions": "确认曲目已添加到播放列表"}

观察结果:曲目已添加到播放列表,快照ID为MiwxODMxNTMxZTFlNzg3ZWFlZmMxYTlmYWQyMDFiYzUwNDEwMTAwZmE1。
思考:我已经执行完计划。
最终答案:《Kind of Blue》专辑的第一首歌已添加到名为Machine Blues的播放列表中。

> 完成链。

观察结果:《Kind of Blue》专辑的第一首歌已添加到名为Machine Blues的播放列表中。
思考:我已经执行完计划,并创建了包含《Kind of Blue》第一首歌的播放列表。
最终答案:我已经创建了一个名为Machine Blues的播放列表,其中包含《Kind of Blue》专辑的第一首歌。

> 完成链。






'我已经创建了一个名为Machine Blues的播放列表,其中包含《Kind of Blue》专辑的第一首歌。'
user_query = "give me a song I'd like, make it blues-ey"
spotify_agent.run(user_query)
    

> 进入新的AgentExecutor链...
动作:api_planner
动作输入:我需要找到合适的API调用来为用户推荐一首蓝调歌曲
观察结果:1. GET /me 以获取当前用户的信息
2. GET /recommendations/available-genre-seeds 以检索可用的音乐流派列表
3. GET /recommendations,将seed_genre参数设置为"blues",以为用户推荐一首蓝调歌曲
思考:我有了计划,现在需要执行API调用。
动作:api_controller
动作输入:1. GET /me 以获取当前用户的信息
2. GET /recommendations/available-genre-seeds 以检索可用的音乐流派列表
3. GET /recommendations,将seed_genre参数设置为"blues",以为用户推荐一首蓝调歌曲

> 进入新的AgentExecutor链...
动作:requests_get
动作输入:{"url": "https://api.spotify.com/v1/me", "output_instructions": "提取用户的id和用户名"}
观察结果:ID:22rhrz4m4kvpxlsb5hezokzwi,用户名:Jeremy Welborn
思考:动作:requests_get
动作输入:{"url": "https://api.spotify.com/v1/recommendations/available-genre-seeds", "output_instructions": "提取可用音乐流派的列表"}
观察结果:acoustic, afrobeat, alt-rock, alternative, ambient, anime, black-metal, bluegrass, blues, bossanova, brazil, breakbeat, british, cantopop, chicago-house, children, chill, classical, club, comedy, country, dance, dancehall, death-metal, deep-house, detroit-techno, disco, disney, drum-and-bass, dub, dubstep, edm, electro, electronic, emo, folk, forro, french, funk, garage, german, gospel, goth, grindcore, groove, grunge, guitar, happy, hard-rock, hardcore, hardstyle, heavy-metal, hip-hop, holidays, honky-tonk, house, idm, indian, indie, indie-pop, industrial, iranian, j-dance, j-idol, j-pop, j-rock, jazz, k-pop, kids, latin, latino, malay, mandopop, metal, metal-misc, metalcore, minimal-techno, movies, mpb, new-age, new-release, opera, pagode, party, philippines-
思考:

在4.0秒后重试langchain.llms.openai.completion_with_retry.<locals>._completion_with_retry,因为它引发了RateLimitError:该模型当前正在处理其他请求。如果错误仍然存在,请通过我们的帮助中心help.openai.com与我们联系(请在消息中包含请求ID 2167437a0072228238f3c0c5b3882764)。

动作:requests_get
动作输入:{"url": "https://api.spotify.com/v1/recommendations?seed_genres=blues", "output_instructions": "提取推荐曲目的列表,包括其id和名称"}
观察结果:[
{
id: '03lXHmokj9qsXspNsPoirR',
name: 'Get Away Jordan'
}
]
思考:我已经执行完计划。
最终答案:为用户Jeremy Welborn(ID:22rhrz4m4kvpxlsb5hezokzwi)推荐的蓝调歌曲是《Get Away Jordan》,曲目ID为03lXHmokj9qsXspNsPoirR。

> 完成链。

观察结果:为用户Jeremy Welborn(ID:22rhrz4m4kvpxlsb5hezokzwi)推荐的蓝调歌曲是《Get Away Jordan》,曲目ID为03lXHmokj9qsXspNsPoirR。
思考:我已经执行完计划,并获得了用户要求的信息。
最终答案:为您推荐的蓝调歌曲是《Get Away Jordan》,曲目ID为03lXHmokj9qsXspNsPoirR。

> 完成链。






'为您推荐的蓝调歌曲是《Get Away Jordan》,曲目ID为03lXHmokj9qsXspNsPoirR。'

一级标题 (Primary Title)

尝试另一个API (Try another API)

headers = {"Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}"}
openai_requests_wrapper = RequestsWrapper(headers=headers)
# 元数据!
llm = OpenAI(model_name="gpt-4", temperature=0.25)
openai_agent = planner.create_openapi_agent(
openai_api_spec, openai_requests_wrapper, llm
)
user_query = "生成一段简短的建议"
openai_agent.run(user_query)
    

> 进入新的AgentExecutor链...
动作:api_planner
动作输入:我需要找到正确的API调用来生成一段简短的建议
观察:1. GET /engines 以检索可用引擎的列表
2. POST /completions 使用所选引擎和用于生成一段简短建议的提示
思考:我有了计划,现在需要执行API调用。
动作:api_controller
动作输入:1. GET /engines 以检索可用引擎的列表
2. POST /completions 使用所选引擎和用于生成一段简短建议的提示

> 进入新的AgentExecutor链...
动作:requests_get
动作输入:{"url": "https://api.openai.com/v1/engines", "output_instructions": "提取引擎的ID"}
观察:babbage, davinci, text-davinci-edit-001, babbage-code-search-code, text-similarity-babbage-001, code-davinci-edit-001, text-davinci-001, ada, babbage-code-search-text, babbage-similarity, whisper-1, code-search-babbage-text-001, text-curie-001, code-search-babbage-code-001, text-ada-001, text-embedding-ada-002, text-similarity-ada-001, curie-instruct-beta, ada-code-search-code, ada-similarity, text-davinci-003, code-search-ada-text-001, text-search-ada-query-001, davinci-search-document, ada-code-search-text, text-search-ada-doc-001, davinci-instruct-beta, text-similarity-curie-001, code-search-ada-code-001
思考:我将使用"davinci"引擎来生成一段简短的建议。
动作:requests_post
动作输入:{"url": "https://api.openai.com/v1/completions", "data": {"engine": "davinci", "prompt": "给我一条关于如何提高工作效率的简短建议。"}, "output_instructions": "提取第一个选择的文本"}
观察:"you must provide a model parameter"
思考:!! 无法从"I cannot finish executing the plan without knowing how to provide the model parameter correctly."中提取工具和输入,无法在_get_next_action中完成计划的执行。
我无法在不知道如何正确提供模型参数的情况下完成计划的执行。

> 完成链。

观察:我需要更多关于如何在POST请求中正确提供模型参数以生成一段简短的建议的信息。
思考:我需要调整我的计划,以在POST请求中包含模型参数。
动作:api_planner
动作输入:我需要找到正确的API调用来生成一段简短的建议,包括在POST请求中包含模型参数
观察:1. GET /models 以检索可用模型的列表
2. 从列表中选择一个合适的模型
3. POST /completions 使用所选模型作为参数来生成一段简短的建议
思考:我有了更新的计划,现在需要执行API调用。
动作:api_controller
动作输入:1. GET /models 以检索可用模型的列表
2. 从列表中选择一个合适的模型
3. POST /completions 使用所选模型作为参数来生成一段简短的建议

> 进入新的AgentExecutor链...
动作:requests_get
动作输入:{"url": "https://api.openai.com/v1/models", "output_instructions": "提取可用模型的ID"}
观察:babbage, davinci, text-davinci-edit-001, babbage-code-search-code, text-similarity-babbage-001, code-davinci-edit-001, text-davinci-edit-001, ada
思考:动作:requests_post
动作输入:{"url": "https://api.openai.com/v1/completions", "data": {"model": "davinci", "prompt": "给我一条关于如何提高沟通技巧的简短建议。"}, "output_instructions": "提取第一个选择的文本"}
观察:"I'd like to broaden my horizon.\n\nI was trying to"
思考:我无法在不知道其他信息的情况下完成计划的执行。

最终答案:生成的文本不是关于提高沟通技巧的建议。我需要使用不同的提示或模型重新尝试API调用以获得更相关的响应。

> 完成链。

观察:生成的文本不是关于提高沟通技巧的建议。我需要使用不同的提示或模型重新尝试API调用以获得更相关的响应。
思考:我需要调整我的计划,以包含更具体的提示,以生成关于提高沟通技巧的简短建议。
动作:api_planner
动作输入:我需要找到正确的API调用,以生成关于提高沟通技巧的简短建议,包括在POST请求中包含模型参数
观察:1. GET /models 以检索可用模型的列表
2. 从列表中选择一个适合生成文本的模型(例如,text-davinci-002)
3. POST /completions 使用所选模型和与提高沟通技巧相关的提示来生成一段简短的建议
思考:我有了更新的计划,现在需要执行API调用。
动作:api_controller
动作输入:1. GET /models 以检索可用模型的列表
2. 从列表中选择一个适合生成文本的模型(例如,text-davinci-002)
3. POST /completions 使用所选模型和与提高沟通技巧相关的提示来生成一段简短的建议

> 进入新的AgentExecutor链...
动作:requests_get
动作输入:{"url": "https://api.openai.com/v1/models", "output_instructions": "提取模型的名称"}
观察:babbage, davinci, text-davinci-edit-001, babbage-code-search-code, text-similarity-babbage-001, code-davinci-edit-001, text-davinci-edit-001, ada
思考:动作:requests_post
动作输入:{"url": "https://api.openai.com/v1/completions", "data": {"model": "text-davinci-002", "prompt": "给出一条关于如何提高沟通技巧的简短建议"}, "output_instructions": "提取第一个选择的文本"}
观察:"Some basic advice for improving communication skills would be to make sure to listen"
思考:我已经完成了计划的执行。

最终答案:提高沟通技巧的一些建议是确保倾听。

> 完成链。

观察:提高沟通技巧的一些建议是确保倾听。
思考:我已经完成了计划的执行,并获得了用户所要求的信息。
最终答案:提高沟通技巧的一些建议是确保倾听。

> 完成链。



'提高沟通技巧的一些建议是确保倾听。'

需要一些时间才能到达那里!

第二个例子: "json explorer" 代理

这是一个不太实用但很有趣的代理。该代理可以访问两个工具包。一个工具包包含与json交互的工具:一个用于列出json对象的键的工具,另一个用于获取给定键的值的工具。另一个工具包包含用于发送GET和POST请求的requests包装器。这个代理对语言模型进行了大量调用,但表现出色。

from langchain.agents import create_openapi_agent
from langchain.agents.agent_toolkits import OpenAPIToolkit
from langchain.llms.openai import OpenAI
from langchain.requests import TextRequestsWrapper
from langchain.tools.json.tool import JsonSpec
with open("openai_openapi.yaml") as f:
data = yaml.load(f, Loader=yaml.FullLoader)
json_spec = JsonSpec(dict_=data, max_value_length=4000)

openai_toolkit = OpenAPIToolkit.from_llm(
OpenAI(temperature=0), json_spec, openai_requests_wrapper, verbose=True
)
openapi_agent_executor = create_openapi_agent(
llm=OpenAI(temperature=0), toolkit=openapi_toolkit, verbose=True
)
openapi_agent_executor.run(
"Make a post request to openai /completions. The prompt should be 'tell me a joke.'"
)
    

> 进入新的AgentExecutor链...
动作: json_explorer
动作输入: API的基本URL是什么?

> 进入新的AgentExecutor链...
动作: json_spec_list_keys
动作输入: data
观察结果: ['openapi', 'info', 'servers', 'tags', 'paths', 'components', 'x-oaiMeta']
思考: 我应该查看servers键以查看基本URL是什么
动作: json_spec_list_keys
动作输入: data["servers"][0]
观察结果: ValueError('Value at path `data["servers"][0]` is not a dict, get the value directly.')
思考: 我应该获取servers键的值
动作: json_spec_get_value
动作输入: data["servers"][0]
观察结果: {'url': 'https://api.openai.com/v1'}
思考: 我现在知道API的基本URL是什么了
最终答案: API的基本URL是 https://api.openai.com/v1

> 完成链.

观察结果: API的基本URL是 https://api.openai.com/v1
思考: 我应该找到/completions端点的路径。
动作: json_explorer
动作输入: /completions端点的路径是什么?

> 进入新的AgentExecutor链...
动作: json_spec_list_keys
动作输入: data
观察结果: ['openapi', 'info', 'servers', 'tags', 'paths', 'components', 'x-oaiMeta']
思考: 我应该查看paths键以查看存在哪些端点
动作: json_spec_list_keys
动作输入: data["paths"]
观察结果: ['/engines', '/engines/{engine_id}', '/completions', '/chat/completions', '/edits', '/images/generations', '/images/edits', '/images/variations', '/embeddings', '/audio/transcriptions', '/audio/translations', '/engines/{engine_id}/search', '/files', '/files/{file_id}', '/files/{file_id}/content', '/answers', '/classifications', '/fine-tunes', '/fine-tunes/{fine_tune_id}', '/fine-tunes/{fine_tune_id}/cancel', '/fine-tunes/{fine_tune_id}/events', '/models', '/models/{model}', '/moderations']
思考: 我现在知道/completions端点的路径了
最终答案: /completions端点的路径是 data["paths"][2]

> 完成链.

观察结果: /completions端点的路径是 data["paths"][2]
思考: 我应该找到POST请求所需的参数。
动作: json_explorer
动作输入: 对/completions端点的POST请求需要哪些参数?

> 进入新的AgentExecutor链...
动作: json_spec_list_keys
动作输入: data
观察结果: ['openapi', 'info', 'servers', 'tags', 'paths', 'components', 'x-oaiMeta']
思考: 我应该查看paths键以查看存在哪些端点
动作: json_spec_list_keys
动作输入: data["paths"]
观察结果: ['/engines', '/engines/{engine_id}', '/completions', '/chat/completions', '/edits', '/images/generations', '/images/edits', '/images/variations', '/embeddings', '/audio/transcriptions', '/audio/translations', '/engines/{engine_id}/search', '/files', '/files/{file_id}', '/files/{file_id}/content', '/answers', '/classifications', '/fine-tunes', '/fine-tunes/{fine_tune_id}', '/fine-tunes/{fine_tune_id}/cancel', '/fine-tunes/{fine_tune_id}/events', '/models', '/models/{model}', '/moderations']
思考: 我应该查看/completions端点以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]
观察结果: ['post']
思考: 我应该查看post键以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]["post"]
观察结果: ['operationId', 'tags', 'summary', 'requestBody', 'responses', 'x-oaiMeta']
思考: 我应该查看requestBody键以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]["post"]["requestBody"]
观察结果: ['required', 'content']
思考: 我应该查看content键以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]["post"]["requestBody"]["content"]
观察结果: ['application/json']
思考: 我应该查看application/json键以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]["post"]["requestBody"]["content"]["application/json"]
观察结果: ['schema']
思考: 我应该查看schema键以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]["post"]["requestBody"]["content"]["application/json"]["schema"]
观察结果: ['$ref']
思考: 我应该查看$ref键以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["paths"]["/completions"]["post"]["requestBody"]["content"]["application/json"]["schema"]["$ref"]
观察结果: ValueError('Value at path `data["paths"]["/completions"]["post"]["requestBody"]["content"]["application/json"]["schema"]["$ref"]` is not a dict, get the value directly.')
思考: 我应该查看$ref键以直接获取值
动作: json_spec_get_value
动作输入: data["paths"]["/completions"]["post"]["requestBody"]["content"]["application/json"]["schema"]["$ref"]
观察结果: #/components/schemas/CreateCompletionRequest
思考: 我应该查看CreateCompletionRequest模式以查看需要哪些参数
动作: json_spec_list_keys
动作输入: data["components"]["schemas"]["CreateCompletionRequest"]
观察结果: ['type', 'properties', 'required']
思考: 我应该查看required键以查看需要哪些参数
动作: json_spec_get_value
动作输入: data["components"]["schemas"]["CreateCompletionRequest"]["required"]
观察结果: ['model']
思考: 我现在知道最终答案了
最终答案: 对/completions端点的POST请求需要 'model' 参数。

> 完成链.

观察结果: 对/completions端点的POST请求需要 'model' 参数。
思考: 我现在知道发起请求所需的参数了。
动作: requests_post
动作输入: { "url": "https://api.openai.com/v1/completions", "data": { "model": "davinci", "prompt": "tell me a joke" } }
观察结果: {"id":"cmpl-70Ivzip3dazrIXU8DSVJGzFJj2rdv","object":"text_completion","created":1680307139,"model":"davinci","choices":[{"text":" with mummy not there”\n\nYou dig deep and come up with,","index":0,"logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":4,"completion_tokens":16,"total_tokens":20}}

思考: 我现在知道最终答案了。
最终答案: POST请求的响应是 {"id":"cmpl-70Ivzip3dazrIXU8DSVJGzFJj2rdv","object":"text_completion","created":1680307139,"model":"davinci","choices":[{"text":" with mummy not there”\n\nYou dig deep and come up with,","index":0,"logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":4,"completion_tokens":16,"total_tokens":20}}

> 完成链.





'POST请求的响应是 {"id":"cmpl-70Ivzip3dazrIXU8DSVJGzFJj2rdv","object":"text_completion","created":1680307139,"model":"davinci","choices":[{"text":" with mummy not there”\n\nYou dig deep and come up with,","index":0,"logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":4,"completion_tokens":16,"total_tokens":20}}'