How to Turn Your OpenAPI Specification Into an AI Chatbot With RAG

Причина по которая я захотел поделиться своим опытом простая. В каждой средней компании есть много микросервисов и различных АПИ. Команды пилять микросервисы. Каждая команда взаимодействует друг с другом. Спасибо большое Фастапи и ее создателю за то что сделали прекрасынй фрейморк на основе пайдентика генерирующий все необходимые спеки. Но проблема все еще актуальна, некоторым стартапам не хватает времени писать нормальную документацию – дак может и не надо, если часть кода уже генерируется.

Что я использовал

Стримлит
Хрома
Лангчен
Оламма


Я решил попробовать провести эксперимент и соединить Swagger и с OpenAI и посмотреть что из этого получиться. Это статья туториал / гайд для тех кто хочет узнать чем все кончилось и как я это сделал на основе RAG with ChromaDB and Langchain.


Цель

Fast to find. Information and ask about something “How to create item with API?“


Все шаги в RAG делятся на 3 части

Взять информацию, разбить ее на чанки и положить в векторное хранилище.
Достать во время запроса от клиента и отправить в модель
Сравнить результат и ожидание

Пишем сплиттер

для того чтобы написать сплиттер обычно лангчейн предоставляет много заготовленных штук, но так как в нашем случае спецификация это список запросов которые связаны с моделями лучше всего взять и разбить это на просто запросы. Для этого я написал простой снипет. Это максимально простая функция кторая разделяет всю полученную спеку на простые части. И добавляет связанные модели к патчу.

def get_openapi_spec_paths(specification: dict) -> dict:
paths = []

for p in specification[“paths”]:
for m in specification[“paths”][p]:
path = specification[“paths”][p][m]
path[“method”] = m
path[“path”] = p
paths.append(path)

return paths

Загрузка документов

После того как мы разделили на чанки нам нужно их заэнкодировать в векторное предстовление и загрузить в хрома дб. В дальнейшем перед тем как делать запрос в чат гпт мы сделаем векторный поиск по эмбедингам чтобы достать релевантные документы.

import json
from langchain.docstore.document import Document
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

specification = get_openapi_spec(url)
paths = get_openapi_spec_paths(specification)
dumped_paths = dump_openapi_spec_to_chroma_docs(paths)

# Dump documents to Chroma documents
for p in paths:
dumped_paths.append(
Document(page_content=json.dumps(p), metadata={“source”: “local”})
)

# Init embeddings model
embeddings = OpenAIEmbeddings(
model=”text-embedding-ada-002″
)

# Upload to database
Chroma.from_documents(
documents=dumped_paths,
embedding=embeddings,
persist_directory=”data”,
collection_name=”spec”,
)


В этом примере, мы сохраняем данные локально в директорию ‘data’, но Chroma может работать как и в короткой памяти так и как отдельный инстанс.

Пишем ретривер и чейн

Мы готовы к тому чтобы сделать первый запрос. Я загрузил пример простого API про собачек, который написал на фастапи и добавил ссылку в скрипт.


В качестве модели мы будем использовать chatgpt-4o

embeddings = OpenAIEmbeddings(model=settings.OPENAI_API_EMBEDDINGS_MODEL)
llm = ChatOpenAI(api_key=settings.OPENAI_API_KEY, model=settings.OPEN_API_MODEL)
chroma_db = Chroma(
persist_directory=”data”,
embedding_function=embeddings,
collection_name=”spec”,
)
retriever = chroma_db.as_retriever()

prompt = PromptTemplate.from_template(
“””
System: You are an assistant that converts OpenAPI JSON specs into neatly structured, human-readable
text with summary, description, tags, produces, responses, parameters, method, and curl examples.

EXAMPLE ANSWER:
### GET /dogs
**Summary**: Retrieve a list of dogs
**Description**: Get a filtered list of dogs based on query parameters such as breed, age, or size.
**Tags**: Dogs
**Produces**: application/json
**Parameters**:
– **Query**:
– `breed` (string, optional): Filter by dog breed.
– `age` (integer, optional): Filter by dog age.
– `size` (string, optional): Filter by dog size (small, medium, large).
**Method**: GET
**Curl Example**:
“`sh
curl -X GET “https://api.example.com/dogs?breed=labrador&size=medium” -H “Authorization: Bearer <your_token>”
“`
Now, format the following OpenAPI spec:
{context}
{question}
“””
)

def format_docs(docs):
return “nn”.join(doc.page_content for doc in docs)

chain = (
{“context”: retriever | format_docs, “question”: RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)

chain.invoke((“How to get list of dogs?”)


Я докуртил few shot промп и финальную версию можно увидеть в гитхаб репозитори.

Пример на основе Lamma

Если вы не готовы использовать OpenAPI в целях например безопасности или по другим причнам, всегда есть возможность запустить на Lamma7B для этого установить себе ламу. Спульте и заменить llm на

# pull model before usage
# ollama pull llama3.1

from langchain_ollama import OllamaLLM

llm = OllamaLLM(model=”llama3.1:8b”)

Lets Add StreamLete

куда же без этого молодца? В наших экспериментах? Даа.

import streamlit as st

if “messages” not in st.session_state:
st.session_state.messages = []

for message in st.session_state.messages:
with st.chat_message(message[“role”]):
st.markdown(message[“content”])

if prompt := st.chat_input(“Enter your message.”):
st.session_state.messages.append({“role”: “user”, “content”: prompt})
with st.chat_message(“user”):
st.markdown(prompt)

with st.chat_message(“assistant”):
if (len(st.session_state.messages)):
r = chat_with_model(st.session_state.messages[-1][“content”])
response = st.write(r)
st.session_state.messages.append({“role”: “assistant”, “content”: response})


Пару строк и получаем что то что мы уже можем трогать.

Результаты и тестовая спека

В рещультате я проетстировал


Резудльтаты впечатляют, все зависит от модели. А теперь подумайте сколько времени сэкономит это компаниям?

Заключение

Если вы нашли эту статью и эксперимент полезной для себя, поставьте звезду на гитхаб! RAG помог мне сохранить время и силы разобраться в разных спеках различных команд. В любом случае чем понятнее контекст и так далее тем улчше. Поэтому пишите качесвенно докстринги и документацию Фастапи и пайдентик в этом помогут.


Ссылка на гитхабыч чтобы запустить проект локльно (не забудь нажать на звездочку)

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.