OpenAPIServiceToFunctions
OpenAPIServiceToFunctions
OpenAPI 서비스 스펙을 LLM 툴 호출과 호환되는 형식으로 변환하는 컴포넌트예요.
출처: 문서
본문
MCP를 대신 고려해 보세요: 이 OpenAPI 컴포넌트들은 Haystack을 외부 API에 연결하는 레거시 방식이에요. 대부분의 사용 사례에서는
MCPTool을 권장해요. 파이프라인과 에이전트가 외부 툴·서비스를 쓰도록 하는 현대적이고 표준화된 방법이기 때문이죠.
OpenAPIServiceToFunctions는 OpenAPI 서비스 스펙을 LLM 툴 호출에 적합한 함수 호출 형식으로 변환해요. OpenAPI 스펙을 받아 함수 정의를 추출하고, 이 정의를 LLM 툴 호출과 호환되도록 포맷팅하죠.
OpenAPIServiceToFunctions는 OpenAPIServiceConnector 컴포넌트와 함께 쓸 때 특히 유용해요. OpenAPI 스펙을 함수 정의로 변환해서, OpenAPIServiceConnector가 OpenAPI 스펙의 입력 파라미터를 처리하고 REST API 호출에서 쓸 수 있게 해주거든요.
OpenAPIServiceToFunctions를 쓰려면 openapi-haystack 패키지를 설치해야 해요.
pip install openapi-haystack
OpenAPIServiceToFunctions 컴포넌트에는 init 파라미터가 없어요.
더 알아보기 (Learn more)
단독으로 쓰기
이 컴포넌트는 주로 파이프라인에서 쓰도록 만들어졌어요. 단독으로 쓸 때는 OpenAPI 스펙을 함수 정의로 변환해서 파일에 저장한 뒤 나중에 툴 호출에 사용하고 싶을 때 유용해요.
파이프라인에서 쓰기
파이프라인 맥락에서 OpenAPIServiceToFunctions는 OpenAPIServiceConnector와 함께 쓸 때 가장 가치가 커요. 예를 들어 serper.dev 검색 엔진 브리지를 파이프라인에 통합한다고 해 볼게요. OpenAPIServiceToFunctions가 https://bit.ly/serper_dev_spec에서 Serper의 OpenAPI 스펙을 가져와서, 툴 호출 기능이 있는 LLM이 이해할 수 있는 함수 정의로 변환한 뒤, 이 정의를 generation_kwargs로 Chat Generator 컴포넌트에 자연스럽게 넘겨요.
info: 아래 코드 스니펫을 실행하려면 자체 Serper와 OpenAI API 키가 있어야 해요.
import json
import requests
from typing import Any
from haystack import Pipeline
from haystack.components.converters import OutputAdapter
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack.dataclasses.byte_stream import ByteStream
from haystack_integrations.components.connectors.openapi import OpenAPIServiceConnector
from haystack_integrations.components.converters.openapi import (
OpenAPIServiceToFunctions,
)
def prepare_fc_params(openai_functions_schema: dict[str, Any]) -> dict[str, Any]:
return {
"tools": [{"type": "function", "function": openai_functions_schema}],
"tool_choice": {
"type": "function",
"function": {"name": openai_functions_schema["name"]},
},
}
serperdev_spec = requests.get("https://bit.ly/serper_dev_spec").json()
system_prompt = requests.get("https://bit.ly/serper_dev_system").text
user_prompt = "Why was Sam Altman ousted from OpenAI?"
pipe = Pipeline()
pipe.add_component("spec_to_functions", OpenAPIServiceToFunctions())
pipe.add_component(
"prepare_fc_adapter",
OutputAdapter(
"{{functions[0] | prepare_fc}}",
dict[str, Any],
{"prepare_fc": prepare_fc_params},
),
)
pipe.add_component("functions_llm", OpenAIChatGenerator())
pipe.add_component("openapi_connector", OpenAPIServiceConnector())
pipe.add_component(
"message_adapter",
OutputAdapter(
"{{system_message + service_response}}",
list[ChatMessage],
unsafe=True,
),
)
pipe.add_component("llm", OpenAIChatGenerator())
pipe.connect("spec_to_functions.functions", "prepare_fc_adapter.functions")
pipe.connect(
"spec_to_functions.openapi_specs",
"openapi_connector.service_openapi_spec",
)
pipe.connect("prepare_fc_adapter", "functions_llm.generation_kwargs")
pipe.connect("functions_llm.replies", "openapi_connector.messages")
pipe.connect("openapi_connector.service_response", "message_adapter.service_response")
pipe.connect("message_adapter", "llm.messages")
result = pipe.run(
data={
"functions_llm": {
"messages": [
ChatMessage.from_system("Only do tool/function calling"),
ChatMessage.from_user(user_prompt),
],
},
"openapi_connector": {
"service_credentials": serper_dev_key,
},
"spec_to_functions": {
"sources": [ByteStream.from_string(json.dumps(serperdev_spec))],
},
"message_adapter": {
"system_message": [ChatMessage.from_system(system_prompt)],
},
},
)
print(result["llm"]["replies"][0].text)
# Sam Altman was ousted from OpenAI on November 17, 2023, following
# a "deliberative review process" by the board of directors. The board concluded
# that he was not "consistently candid in his communications". However, he
# returned as CEO just days after his ouster.