# Concept - 각 문서들의 순서대로 순회하면서 답변(Response)을 **정제(Refine)** 하여 최종 답변을 구하는 `Model`이다. - 구현하는데 여러 방법이 있겠지만, 해당 페이지에는 첫 번째 문서를 기준으로 답변을 하나 구한 뒤, 나머지 문서들을 순회하며 답변 내용을 추가하거나 수정하는 방법을 사용한다. - 첫 번째 문서의 답변을 구해주는 `first_chain`과 해당 `Chain`에서 얻은 결과를 바탕으로 나머지 문서를 순회하며 `Refine`하는 `refine_chain`으로 구성되어 있다. [Refine Process 이미지](https://js.langchain.com/v0.1/docs/modules/chains/document/refine/)![[Refine Chain Process.jpg]] # Code - 이 `Code`는 특정 `txt` 문서를 `Summary`하는 Model을 `Refine LCEL Chain`로 구현한 것이다. - 모든 문서를 다 사용하기 때문에 굳이 [[Retrieval]]을 사용할 필요 없이 문서를 `Splitter`로 나눈 뒤 바로 `Chain`에 넣으면 된다. - `first_summary_chain`은 첫 번째 문서의 정보를 받아 이에 대한 답변을 내놓는다. - `refine_chain`에는 참고할 문서인 `context`와 요약된 내용(**정제된 내용**)인 `existing_summary`가 필요하다. - 처음의 `existing_summary`은 `first_summary_chain`에서 얻은 정보이며, 그 다음부턴 나머지 문서의 `context`을 토대로 `existing_summary`을 수정하거나 추가한다. - 모든 문서를 순회하여 얻은 `summary_content`가 `Refine LCEL Chain`의 최종 `Response`이다. ```python from langchain_openai import ChatOpenAI from langchain_community.document_loaders import UnstructuredFileLoader from langchain.prompts import ChatPromptTemplate from langchain.document_loaders import UnstructuredFileLoader from langchain.schema.output_parser import StrOutputParser llm = ChatOpenAI(temperature=0.1) loader = UnstructuredFileLoader("./files/chapter_one.txt") splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(     chunk_size = 500,     chunk_overlap = 100, ) docs = loader.load_and_split(text_splitter=splitter) first_summary_prompt = ChatPromptTemplate.from_template(     """     Write a concise summary of the following:     "{text}"     CONCISE SUMMARY     """ ) first_summary_chain = first_summary_prompt | llm | StrOutputParser() summary_content = first_summary_chain.invoke({"text": docs[0].page_content}) refine_prompt = ChatPromptTemplate.from_template(     """     Your job is to produce a final summary.     We have provied an existing summary up to a certain point : {existing_summary}     We have the opportunity to refine the existing summary (only if needed) with some more context below.     ------     {context}     ------     Given the new context, refine the original summary.     If the context ins't useful, RETURN the original summary.     """ ) refine_chain = refine_prompt | llm | StrOutputParser() for i, doc in enumerate(docs[1:]):     print(f"Progress : {i+1}/{len(docs) - 1}")     summary_content = refine_chain.invoke({"existing_summary" : summary_content, "context" : doc.page_content}) print(summary_content) ```