LangChain에서 OpenAI API의 n 파라미터 사용

반야·2024년 9월 30일
1

🤔 n 파라미터를 사용하려던 이유

  1. 첫 번째 이유는 단순히 가설이었다.

    • n 파리미터를 통해 받는 n개의 응답은 서로 unique하지 않을까?
    • 서로 다른 n개의 응답이 필요한데, 단지 temperature와 top_p를 올리는 것만으로는 해결이 안되었기 때문이다.
    • 결론은 대충 예상하긴 했지만 n번 호출과 비슷하게 작동하는 것으로 보였다. (동일한 응답이 존재했기 때문...)

  2. 두 번째 이유는 input tokens에서의 이점이다.

    • 확인 결과, input tokens는 n 파라미터 사용 시가 1회 호출 시와 동일했기 때문
    • 하지만 당연하게도 completion tokens는 n회 만큼 증가했다.

😥 문제의 배경

  1. LangChain 라이브러리의 JsonOutputParser 사용
    • 지금이야 OpenAI에서 Structured Output을 제공하지만, 몇달 전만해도 그렇지하지 않았기 때문에...
    • 아마 이것도 곧 OpenAI의 Structured Output을 이용하도록 변경할 듯

  1. 공식 문서에서의 JsonOutputParser에 n 파라미터를 붙이는 것으로 n 파라미터가 작동하지 않음
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "***"),
        ("user", "{user_input}"),
    ]
)

llm = ChatGooroomeeAI(model="***")
model = prompt | llm.bind(temperature=1.0, maxTokens=1000, n=4)

async def gen(prompt_template, ***):
    output_parser = JsonOutputParser(pydantic_object=OutputFormat)
    prompt = PromptTemplate(
        template=prompt_template,
        input_variables=[
            "***",
            "***",
            "***",
        ],
        partial_variables={
            "format_instructions": output_parser.get_format_instructions()
        },
    )

    chain = prompt | model | output_parser
    response = chain.invoke(
        {
            "***": ***,
            "***": ***,
            "***": ***,
        }
    )
    return response


class OutputFormat(BaseModel):
    ***: str = Field(description="***")
    ***: str = Field(description="***")
    process: dict[str, str] = Field(
        description="""응답 생성 과정으로, 'Step _'을 key로 하고 해당 Step의 과정을 진행한 내용을 value로 한다.
        응답 예시)
        Step 1: 응답 생성 과정의 첫번째 과정 진행, 
        Step 2: 응답 생성 과정의 두번째 과정 진행,
        ..."""
    )

😎 문제 해결 방법

  1. 먼저 동일한 문제를 겪는 사람을 구글 검색을 통해 찾았다. (경험 상 이런 문제는 GPT가 크게 도움이 되지 않기 때문에...)

  1. 해결 코드 작성 과정은 아래와 같다.

    1. 먼저 위 코드처럼
    chain = prompt | model | output_parser

    이렇게 pipe로 연결된 경우에서 chain._generate()를 호출할 수가 없었다.


    1. 따라서 링크 1의 내용처럼
    response = llm._generate([[message]])

    위의 프롬프트 내용을 message로 변경해야했다.


    1. 그 뒤로는 계속 변수 type 문제 때문에 헤맸었다. (계속 호출이 불가능한 type이네 뭐네 오류 메세지가 떴음) 사실 n개의 응답을 개별로 분리해 parsing하는 부분에서도 헤맸었다.

    1. 결과적으로 해당 문제를 해결한 코드는 아래와 같다.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

llm = ChatOpenAI(model="***", temperature=1.0, max_tokens=2000, n=4)
# max_tokens 값을 올려야 응답이 중간에 끊기는 것을 방지 가능

async def gen(prompt_template, ***):
    output_parser = JsonOutputParser(pydantic_object=OutputFormat)
    prompt = ChatPromptTemplate.from_messages(
        [
            ("system", "***"),
            ("user", prompt_template), # 바로 prompt_template 사용
        ]
    )

    response = llm._generate( # llm._generate 호출
        prompt.invoke( # prompt에 변수 삽입
            {
                "***": ***,
                "***": ***,
                "***": ***,
                "format_instructions": output_parser.get_format_instructions(),
            }
        ).to_messages() # message로 형식으로 변경
    )

	## n개의 응답을 parsing하고 dict으로 분리 ##
    response_dict = {}
    for idx, res in enumerate(response.generations):
        response_dict[idx] = output_parser.parse(res.text) 
        # outputParser를 이용한 parsing

    return response_dict

나와 동일한 방식으로 ChatPromptTemplate을 사용하면서 n 파라미터를 사용하려고 시도한 경우를 찾지 못해서 해결에 난항을 겪었었다.
이 글을 보게 될 다른 이는 금방 해결할 수 있기를 바라며 글을 남긴다.



langchain n param
langchain n param not work

profile
SKKU_CSE_23

0개의 댓글