앞에서 ChatGPT와 OpenAI API를 이용해 json 형식의 문자열을 출력하는 예제를 살펴봤습니다. LangChain에는 이렇게 원하는 형식의 출력을 얻을 수 있도록 OutputParser 기능을 제공합니다. 앞에서 봤던 예제를 OutputParser를 이용해 구현해보겠습니다.
OutputParser
LangChain의 OutputParser에는 미리 만들어져있는 parser들도 있지만 여기서는 직접 만들어보겠습니다. 아래 예제에서 ResponseSchema는 특정 항목이 어떤 형식으로 출력되어야 하는지 지정하는데 사용하고, StructuredOutputParser는 전체 schema들을 모아 parser를 생성하는데 사용합니다. 여기서는 하나의 항목만 ‘output’이라는 이름으로 추출하려고 합니다. 이 항목의 내용은 {"사람 이름": "영어 색깔 이름"}의 json 형식(파이썬 딕셔너리)으로 만들고 싶습니다.
from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParser
schema = ResponseSchema(name='output', description="json object, key=name, value=color in English")
response_schemas = [schema]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
이렇게 만든 output_parser에서는 get_format_instructions라는 메소드와 parse 메소드를 지원합니다. get_format_instructions는 출력 형식 지정 프롬프트를 만들어주는 메소드입니다. 형식 지정 프롬프트는 LLM에 보낼 전체 프롬프트에 포함시킵니다. parse 메소드는 LLM의 출력이 문자열로 나오니 최종적으로 원하는 형식으로 바꿔주는 메소드입니다. format_instructions를 확인해보죠.
format_instructions: 출력 형식 지정 프롬프트
format_instructions = output_parser.get_format_instructions()
print(format_instructions)
### 출력
The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":
```json
{
"<strong>output</strong>": string // json object, key=name, value=color in English
}
```
위와 같이 json 형식의 문자열을 포함한 마크다운 코드를 출력하라는 내용은 StructuredOutputParser에 미리 입력되어 있고, ResponseSchema에 적은 내용이 json 항목 설명으로 들어가게 됩니다. 그럼 전체 프롬프트를 만들어보죠.
from langchain.prompts import ChatPromptTemplate
template="""
주어진 text로부터 다음 정보를 추출하세요.
"사람 이름": "color in English"
text: ```{text}```
{format_instructions}
"""
prompt = ChatPromptTemplate.from_template(template)
messages = prompt.format_messages(text="영희는 파란색을 좋아하고 영수는 분홍색을 좋아한다.",
format_instructions=format_instructions)
최종 프롬프트 messages의 내용은 다음과 같습니다.
[HumanMessage(content='\n주어진 text로부터 다음 정보를 추출하세요.\n\n"사람 이름": "color in English"\n\ntext: ```영희는 파란색을 좋아하고 영수는 분홍색을 좋아한다.```\n\nThe output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":\n\n```json\n{\n\t"output": string // json object, key=name, value=color in English\n}\n```\n', additional_kwargs={}, example=False)]
이 메시지를 LLM에 보내 응답을 받습니다.
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI(temperature=0.0, model='gpt-3.5-turbo')
response = chat(messages)
response는 다음과 같습니다.
AIMessage(content='```json\n{\n\t"output": {\n\t\t"영희": "blue",\n\t\t"영수": "pink"\n\t}\n}\n```', additional_kwargs={}, example=False)
response.content는 문자열입니다. 최종적으로 원하는 결과를 얻기 위해 이 내용을 output_parser에 전달합니다.
parser: 최종 결과 출력
output = output_parser.parse(response.content)
### 결과
{'output': {'영희': 'blue', '영수': 'pink'}}
그 결과로 딕셔너리를 얻었고, output['output']에 원하는 결과를 얻었습니다.