강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

Stanley Choi님의 프로필 이미지
Stanley Choi

작성한 질문수

LangGraph를 활용한 AI Agent 개발 (feat. MCP)

2.4 생성된 답변을 여러번 검증하는 Self-RAG

query 에 대한 answer 결과값이 나오지 않습니다.

작성

·

27

0

image.png

강의 모두 코드 똑같이 돌리고 db만 pinecone 을 사용하였습니다 ! 결과에 강의처럼 answer이 나오지 않는데 원인을 잘 모르겠습니다 ㅜ
gpt 에 검색해보면
전체 코드를 꼼꼼히 검토해본 결과, 질문하신 "결과(answer)가 나오지 않는 이유"는 크게 두 가지입니다. 하나는 데이터가 유실되는 방식의 반환(return) 때문이고, 다른 하나는 무한 루프(Infinite Loop) 가능성 때문입니다.


1. 가장 큰 원인: State 데이터 유실

LangGraph의 각 노드 함수(retrieve, generate, rewrite 등)는 AgentState를 반환할 때, 기존의 데이터를 포함해서 돌려주어야 합니다.

현재 작성하신 코드를 보면:

  • retrieve 함수: return {'context': docs} (이때 query가 사라짐)

  • generate 함수: return {'answer': response.content} (이때 query, context가 모두 사라짐)


    이렇게 나오는데 제가 봤을땐 이게 원인은 아닌것같습니다...!

답변 1

0

제이쓴님의 프로필 이미지
제이쓴
지식공유자

Context만 있고 답변이 나오지 않는 상황인가요? 코드 전체를 올려주시면 디버깅을 시도해 볼 수 있을 것 같습니다~

Stanley Choi님의 프로필 이미지
Stanley Choi
질문자

from langchain_pinecone import PineconeVectorStore
from pinecone import Pinecone
import dotenv
from langchain_openai import OpenAIEmbeddings

dotenv.load_dotenv()
embedding = OpenAIEmbeddings(model='text-embedding-3-large')

pc =Pinecone()

index_name = "tax-index-langgraph"

index = pc.Index(index_name)
vectorstore = PineconeVectorStore(embedding=embedding, index=index)


retriever = vectorstore.as_retriever(search_kwargs={'k':3})
from typing_extensions import List, TypedDict
from langchain_core.documents import Document
from langgraph.graph import StateGraph

class AgentState(TypedDict):
    query: str
    context: List[Document]
    answer: str
    
graph_builder = StateGraph(AgentState)
def retrieve(state: AgentState) -> AgentState:
    
    query = state['query']
    docs = retriever.invoke(query)
    return {'context': docs}
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model='gpt-4o')
# Create a LangSmith API in Settings > API Keys
# Make sure API key env var is set:
# import os; os.environ["LANGSMITH_API_KEY"] = "<your-api-key>"
from langsmith import Client

client = Client()
generate_prompt = client.pull_prompt("rlm/rag-prompt")

# 지정된 매개변수로 언어 모델을 초기화합니다


def generate(state: AgentState) -> AgentState:
    
    # state에서 컨텍스트와 쿼리를 추출합니다
    context = state['context']
    query = state['query']
    
    # 작업 체인을 생성합니다: 먼저 프롬프트를 검색하고, 그 다음 응답을 생성합니다
    rag_chain = generate_prompt | llm
    
    # 쿼리와 컨텍스트로 체인을 호출하여 응답을 얻습니다
    response = rag_chain.invoke({'question': query, 'context': context})
    
    # 생성된 답변을 반환합니다
    return {'answer': response}
# Create a LangSmith API in Settings > API Keys
# Make sure API key env var is set:
# import os; os.environ["LANGSMITH_API_KEY"] = "<your-api-key>"
from langsmith import Client
from typing import Literal

client = Client()
doc_relevance_prompt = client.pull_prompt("langchain-ai/rag-document-relevance")

def check_doc_relevance(state: AgentState) -> Literal['relevant', 'irrelevant']:
   
    query = state['query']
    context = state['context']
    context_text = "\n\n".join([doc.page_content for doc in context])
    doc_relevance_chain = doc_relevance_prompt | llm
    response = doc_relevance_chain.invoke({'question': query, 'documents': context_text})

    print(f'response: {response['Score']}')
    if response['Score'] == 1:
        # 2.3장과 다르게 `relevant`와 `irrelevant`를 반환합니다
        # node를 직접 지정하는 것보다 실제 판단 결과를 리턴하면서 해당 node의 재사용성을 높일 수 있습니다.
        return 'relevant'
    
    return 'irrelevant'
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser

dictionary = ['사람과 관련된 표현 -> 거주자']

rewrite_prompt = PromptTemplate.from_template(f"""
사용자의 질문을 보고, 우리의 사전을 참고해서 사용자의 질문을 변경해주세요 
사전: {dictionary}                                           
질문: {{query}}
""")

def rewrite(state: AgentState) -> AgentState:
   
    query = state['query']
    rewrite_chain = rewrite_prompt | llm | StrOutputParser()

    response = rewrite_chain.invoke({'query': query})
    return {'query': response}
# set the LANGCHAIN_API_KEY environment variable (create key in settings)
from langchain_core.output_parsers import StrOutputParser

hallucination_prompt = PromptTemplate.from_template("""
You are a teacher tasked with evaluating whether a student's answer is based on documents or not,
Given documents, which are excerpts from income tax law, and a student's answer;
If the student's answer is based on documents, respond with "not hallucinated",
If the student's answer is not based on documents, respond with "hallucinated".

documents: {documents}
student_answer: {student_answer}
""")

hallucination_llm = ChatOpenAI(model='gpt-4o', temperature=0)

def check_hallucination(state: AgentState) -> Literal['hallucinated', 'not hallucinated']:
    answer = state['answer']
    context = state['context']
    context = [doc.page_content for doc in context]
    hallucination_chain = hallucination_prompt | hallucination_llm | StrOutputParser()
    response = hallucination_chain.invoke({'student_answer': answer, 'documents': context})

    return response
# Create a LangSmith API in Settings > API Keys
# Make sure API key env var is set:
# import os; os.environ["LANGSMITH_API_KEY"] = "<your-api-key>"
from langsmith import Client

client = Client()
helpfulness_prompt = client.pull_prompt("langchain-ai/rag-answer-helpfulness")

def check_helpfulness_grader(state: AgentState) -> str:
   
    # state에서 질문과 답변을 추출합니다
    query = state['query']
    answer = state['answer']

    # 답변의 유용성을 평가하기 위한 체인을 생성합니다
    helpfulness_chain = helpfulness_prompt | llm
    
    # 질문과 답변으로 체인을 호출합니다
    response = helpfulness_chain.invoke({'student_answer': answer, 'question': query})

    # 점수가 1이면 'helpful'을 반환하고, 그렇지 않으면 'unhelpful'을 반환합니다
    if response['Score'] == 1:
        return 'helpful'
    
    return 'unhelpful'

def check_helpfulness(state: AgentState) -> AgentState:
   
    # 이 함수는 현재 아무 작업도 수행하지 않으며 state를 그대로 반환합니다
    return state
graph_builder.add_node('retrieve', retrieve)
graph_builder.add_node('generate', generate)
graph_builder.add_node('rewrite', rewrite)
graph_builder.add_node('check_helpfulness', check_helpfulness)
from langgraph.graph import START, END

graph_builder.add_edge(START, 'retrieve')
graph_builder.add_conditional_edges(
    'retrieve',
    check_doc_relevance, 
    {
        'relevant': 'generate',
        'irrelevant': END
    }
)
graph_builder.add_conditional_edges(
    'generate',
    check_hallucination,
    {
        'not hallucinated': 'check_helpfulness',
        'hallucinated': 'generate'
    }
)

graph_builder.add_conditional_edges(
    'check_helpfulness',
    check_helpfulness_grader,
    {
        'helpful': END,
        'unhelpful': 'rewrite'
    }
)
graph_builder.add_edge('rewrite', 'retrieve')
graph = graph_builder.compile()
from IPython.display import Image, display

display(Image(graph.get_graph().draw_mermaid_png()))
initial_state = {'query': '연봉 5천만원인 거주자가 납부해야 하는 소득세는 얼마인가요?'}
graph.invoke(initial_state)
response: 0
{'query': '연봉 5천만원인 거주자가 납부해야 하는 소득세는 얼마인가요?',
 'context': [Document(id='a6c9015f-092f-4aa3-819b-e23588bb0a0f', metadata={'source': './tax_combined_final.txt'}, page_content='소득세법\n하는 자(제119조제9호에 따른 국내원천 부동산등양도소득을 지급하는 거주자 및 비거주자는 제외한다)는 제127조\n에도 불구하고 그 소득을 지급할 때에 다음 각 호의 금액을 그 비거주자의 국내원천소득에 대한 소득세로서 원천징\n수하여 그 원천징수한 날이 속하는 달의 다음 달 10일까지 대통령령으로 정하는 바에 따라 원천징수 관할 세무서,......


1.질문을 정확하게 LLM이 정확하게 리트리버할수 있게 질문을 한상태인데
판단결과가 irrelevant가 나왔고 엣지에서 질문과 리트리버된 문서와 의 관련도가 없으면 바로 END 되버리는 상황입니다.

정확하게 질문을 했는데 왜 결과가 나오지 않는지 잘 모르겠습니다!

Stanley Choi님의 프로필 이미지
Stanley Choi

작성한 질문수

질문하기