팀에서 와 WhyHow.AI의 그래프 및 벡터 검색 시스템이 어떻게 함께 작동해서 RAG (Retrieval-Augmented Generation) 시스템을 개선하는지 알아볼 거예요. 재무 보고서 RAG 예시를 사용해서 그래프와 벡터 검색 간의 응답 차이를 살펴보고, 두 가지 유형의 답변 출력을 벤치마킹하고, 그래프 구조를 통해 깊이와 폭을 최적화할 수 있는 방법을 보여주고, 그래프와 벡터 검색을 결합하는 것이 RAG의 미래인 이유를 알아볼게요.
Neo4j와 같은 Graph Database는 `노드`와 `관계`의 모음인 그래프 개념을 기반으로 구축되었어요. `노드`는 개별 데이터 포인트를 나타내고, `관계`는 `노드` 간의 연결을 정의하죠. 각 `노드`는 `노드`에 대한 추가 컨텍스트 또는 속성을 제공하는 키-값 쌍인 `속성`을 가질 수 있어요. 이 접근 방식은 데이터 내의 복잡한 관계와 종속성을 모델링하는 유연하고 직관적인 방법을 제공해요. Knowledge Graph는 흔히 인간의 뇌가 작동하는 방식과 비슷하다고 불리는데요. 그래프를 사용하면 명시적인 `관계`를 저장하고 `쿼리`할 수 있어서 환각을 줄이고 상황 주입을 통해 정확도를 높일 수 있어요.
Knowledge Graph는 데이터와 데이터 포인트 간의 연결을 저장해서 모든 관련 정보에 대한 포괄적인 보기를 제공함으로써 추론 및 추출 기능을 향상시키죠. 이는 또한 그래프 내에서 의존하는 데이터가 표시되고 추적 가능하므로 설명 가능성의 이점을 제공해요. 다음을 확인해 보세요. 개발자 가이드: Knowledge Graph 구축 방법 Knowledge Graph에 대해 자세히 알아보세요.

이 기능은 재무 지표, 시장 상황, 사업체 간의 복잡한 `관계`를 이해하는 것이 중요한 재무 분석과 같은 분야에서 특히 유용해요.
예를 들어, Graph Database는 실제 상호 작용을 반영하는 일관된 모델에서 임원진술서, 재무 결과, 시장 상황과 같은 다양한 정보를 연결할 수 있어요. 이를 통해 재무 분석가는 그래프를 탐색하여 직간접적인 영향을 확인함으로써 특정 제품 라인에 대한 거시 경제 변화의 영향과 같은 복잡한 시나리오를 탐색할 수 있죠. Neo4j의 그래프 쿼리 언어인 Cypher를 사용하면 Knowledge Graph에서 인플루언서가 제품에 미치는 영향과 같은 복잡한 `관계`를 발견할 수 있어요.
def explore_impact_on_product(graph, product_name):
query = """
MATCH (p:Product {name: $product_name})<-[r:IMPACTS]-(m)
RETURN m.name AS Influencer, r.description AS ImpactDescription
"""
result = graph.run(query, product_name=product_name)
for record in result:
print(f"Influencer: {record['Influencer']}, Impact: {record['ImpactDescription']}")
비즈니스 시나리오에서 의사 결정자는 격리된 데이터 포인트가 어떻게 연결되어 있는지 확인하고 싶어하죠. 그래프는 공급자 역학의 변화가 생산 일정, 재고 수준 및 재무 결과에 어떤 영향을 미치는지 보여줄 수 있어요. 그래프 구조의 유연성 덕분에 기본적인 데이터베이스 스키마를 크게 재설계할 필요 없이 새로운 데이터 유형 및 관계가 도입될 때 동적으로 적응할 수 있다는 점도 매력적이죠.
깊이 및 너비 그래프 검색 사용
일반적으로 사용되는 Retrieval-Augmented Generation (RAG)에서는 Vector Embedding 검색을 통해 의미상 유사한 단어와 문구를 찾아 해당 정보를 Large Language Model (LLM)에 반환하여 질문에 대한 답변을 구성해요. Vector Embedding 검색은 질문과 관련된 일부 유형의 정보를 가져오는 강력한 방법이죠. 예를 들어, “John은 어떤 애완동물을 키웠나요?”라는 질문에 대해 'cat'과 'dog'가 잠재적으로 의미상 'pets'와 유사하다는 것을 추론할 수 있으므로 John의 고양이나 개에 대한 정보를 검색할 수 있어요. 이는 그러한 단어가 검색되기 전에 '애완동물'이라는 개념과 명시적으로 연결될 필요가 없다는 것을 의미하죠. 하지만 많은 정보가 의미상 유사하지만 관련성이 없거나, 관련성이 있지만 의미상 유사하지 않을 수도 있어요.
그래프 검색은 정보 검색을 더욱 세밀하게 제어할 수 있도록 최적화할 수 있는 특정 수단과 패턴을 제공해요. 특정 조사 방향 내에서 더 깊은 수준의 정보 검색이 필요한 쿼리의 경우, 그래프는 관계 계층을 통한 탐색을 용이하게 하여 특정 패턴에 대한 심층 분석을 가능하게 하죠. 반대로 그래프를 사용하면 데이터에 대한 더 넓은 관점을 추구하고 정보의 전체 범위에 초점을 맞추는 쿼리에 대해 광범위한 인접 관계 집합에서 검색할 수 있어요.
이는 그래프 내 수직(깊이/Depth) 및 수평(넓음/Breadth) 순회와 유사하게 볼 수 있어요.
재무 보고서 RAG를 통해 그래프 및 벡터 검색 평가
Apple의 분기별 재무 보고서를 살펴보면서 재무 정보 검색 시스템에서 그래프 및 벡터 검색을 적용하는 방법을 한번 살펴볼까요?
재무 분석가는 회사 성과, 시장 동향, 제품 통찰력에 관한 복잡한 쿼리를 처리하기 위해 고군분투하죠. 여러 분기에 걸쳐 환율이 iPhone 수익에 미치는 영향을 평가하는 임무를 맡은 분석가를 생각해 보세요. 이러한 질문을 하려면 제품 성능, 재무 건전성, 외부 경제 요인에 대한 이해가 필요해요.
수익 보고 기록을 재무 지표, 제품 및 시장 상황 간의 관계를 설명하는 구조화된 형식으로 변환함으로써 Knowledge Graph는 회사 성과에 대한 포괄적인 보기를 제공해요. 이러한 구조화된 접근 방식을 통해 분석가는 빠르고 정확한 분석을 수행하여 다양한 비즈니스 부문이 어떻게 상호 작용하고 서로 영향을 미치는지에 대한 더 깊은 통찰력을 제공하여 전략적 투자 의사 결정을 향상시킬 수 있죠. 그래프 구조를 사용하면 주요 데이터 엔터티와 인접 엔터티를 직접 추출할 수 있어요.
아래 코드를 사용하면 엔터티의 이름을 가져오고, 해당 이웃(관련 Node)을 검색하고 종속성을 설치할 수 있어요.
pip install numpy pyvis neo4j openai
from neo4j import GraphDatabase
from typing import Optional, Union, List, Dict
import numpy as np
from openai import OpenAI
from pyvis.network import Network
def get_embedding(text, model="text-embedding-3-small"):
client = OpenAI()
text = text.replace("n", " ")
return client.embeddings.create(input = [text], model=model).data[0].embedding
def calculate_similarity(embedding1, embedding2):
# Placeholder for similarity calculation, e.g., using cosine similarity
# Ensure both embeddings are numpy arrays for calculation
return np.dot(embedding1, embedding2) / (np.linalg.norm(embedding1) * np.linalg.norm(embedding2))
class NodeSimilaritySearchMan():
def __init__(self, neo4j_driver: GraphDatabase):
"""
Initialize the NodeSimilaritySearchMan with a Neo4j driver instance.
Args:
neo4j_driver (GraphDatabase): The Neo4j driver to facilitate connection to the database.
"""
self.driver = neo4j_driver
def find_relationship_neighbors(self, node_name: str) -> List[Dict[str, Union[int, str]]]:
"""
Finds neighbors of a given node based on direct relationships in the graph.
Args:
node_name (str): The name of the node for which to find neighbors.
Returns:
List[Dict[str, Union[int, str]]]: A list of dictionaries, each representing a neighbor with its ID and name.
"""
result = self.driver.execute_query(
"""
MATCH (n)-[r]->(neighbor)
WHERE n.name = $node_name
RETURN neighbor.name AS name,
type(r) AS relationship_type
""",
{"node_name": node_name}
)
neighbors = [{ "name": record["name"],
"relationship_type": record["relationship_type"]} for record in result]
return neighbors
def visualize_relationship_graph_interactive(self,neighbors, node_name,graph_name, edge_label='relationship_type'):
# Initialize the Network with cdn_resources set to 'remote'
net = Network(notebook=True, cdn_resources='remote')
# Add the main node
net.add_node(node_name, label=node_name, color='red')
# Add neighbors and edges to the network
for neighbor in neighbors:
title = neighbor.get('neighbor_chunks_summary', '')
if edge_label == 'similarity': # Adjust title for similarity
title += f" (Similarity: {neighbor[edge_label]})"
else:
title += f" ({edge_label}: {neighbor[edge_label]})"
net.add_node(neighbor['name'], label=neighbor['name'], title=title)
net.add_edge(node_name, neighbor['name'], title=str(neighbor[edge_label]))
net.show(f'{graph_name}_graph.html')
return net
'Apple'과 관련된 node를 검색해볼까요?
driver = GraphDatabase.driver(uri=url,auth=(user,password))
query_obj = NodeSimilaritySearchMan(driver)
neighbors_by_relationship = query_obj.find_relationship_neighbors("Apple")

그래프 검색과 벡터 검색의 차이점을 이해하기 위해 WhyHow.AI SDK를 사용해서 PDF 파일에서 바로 Knowledge Graph를 생성해볼 수 있어요. WhyHow SDK는 Knowledge Graph 구성을 간소화하도록 설계된 강력한 도구인데요. 이 SDK를 사용하면 광범위한 Knowledge Graph를 효율적으로 생성, 관리, Query할 수 있어서 기업은 원하는 방식으로 데이터를 구성하고 사용할 수 있게 되죠.
WhyHow SDK를 사용하면 미리 정의된 Schema에서 Knowledge Graph를 구성할 수 있어요. 여기서 Schema는 관련된 entity (Node)의 유형, entity를 연결하는 Relationship (Edge)의 종류, 그리고 Relationship이 따라야 하는 패턴을 지정해서 Knowledge Graph의 구조를 정의하는 역할을 해요. 이렇게 하면 높은 수준의 제어가 가능하기 때문에 사용자는 Knowledge Graph를 특정 요구 사항에 맞춰서 커스터마이징하고, 그래프가 원시 데이터에 내재된 관계를 정확하게 반영하도록 만들 수 있죠.
Schema를 정의함으로써 사용자는 Knowledge Graph에 포함되어야 하는 요소와 연결을 정확하게 지정하게 돼요. 예를 들어 문학적 분석에서는 등장인물과 개체, 비즈니스 애플리케이션에서는 제품과 사용자 상호 작용 같은 것들이 포함될 수 있겠죠. Schema는 구성된 그래프가 정의된 컨텍스트에 대한 일관성과 관련성을 유지하도록 보장해서 복잡한 문서에서 의미 있는 통찰력을 추출하는 강력한 도구가 된답니다.
먼저 WhyHow 클라이언트를 초기화하고 그래프에 표현하려는 문서를 Namespace에 추가해볼게요.
from whyhow import WhyHow
import os
from dotenv import load_dotenv
load_dotenv()
user = os.getenv("NEO4J_USERNAME")
password = os.getenv("NEO4J_PASSWORD")
url = os.getenv("NEO4J_URL")
client = WhyHow(neo4j_user=user,neo4j_password=password,neo4j_url=url)
# Define namespace name
namespace = "apple-earning-calls"
documents = [
"earning-calls-apple/Apple (AAPL) Q1 2023 Earnings Call Transcript _ The Motley Fool.pdf",
"earning-calls-apple/Apple (AAPL) Q2 2022 Earnings Call Transcript _ The Motley Fool.pdf",
"earning-calls-apple/Apple (AAPL) Q4 2022 Earnings Call Transcript _ The Motley Fool.pdf"
]
# Add documents to your namespace
documents_response = client.graph.add_documents(
namespace = namespace, documents = documents
)
둘째, 그래프에 대해 원하는 Schema를 정의합니다.
{
"entities": [
{
"name": "Company",
"description": "The company discussed in the document, specifically Apple Inc."
},
{
"name": "Financial_Metric",
"description": "Quantitative measures of Apple's financial performance, including revenue, gross margin, operating expenses, net cash position, etc."
},
{
"name": "Product",
"description": "Physical goods produced by Apple, such as iPhone, Mac, iPad, Apple Watch."
},
{
"name": "Service",
"description": "Services offered by Apple, including Apple TV+, Apple Music, iCloud, Apple Pay."
},
{
"name": "Geographic_Segment",
"description": "Market areas where Apple operates, such as Americas, Europe, Greater China, Japan, Rest of Asia Pacific."
},
{
"name": "Executive",
"description": "Senior leaders of Apple who are often quoted or mentioned in earnings calls, like CEO (Tim Cook), CFO (Luca Maestri)."
},
{
"name": "Market_Condition",
"description": "External economic or market factors affecting Apple's business, such as inflation, foreign exchange rates, geopolitical tensions."
},
{
"name": "Event",
"description": "Significant occurrences influencing the company, including product launches, earnings calls, and global or regional economic events."
},
{
"name": "Time_Period",
"description": "Specific time frames discussed in the document, typically fiscal quarters or years."
}
],
"relations": [
{
"name": "Reports",
"description": "An executive discusses specific financial metrics, typically during an earnings call."
},
{
"name": "Impacts",
"description": "Describes the influence of events or market conditions on financial metrics, products, services, or geographic segments."
},
{
"name": "Operates_In",
"description": "Denotes the geographic areas where Apple's products and services are available."
},
{
"name": "Presents",
"description": "Associates products or services with their financial performance metrics, as presented in earnings calls or official releases."
},
{
"name": "Occurs_During",
"description": "Connects an event with the specific time period in which it took place."
},
{
"name": "Impacted_By",
"description": "Shows the effect of one entity on another, such as a financial metric being impacted by a market condition."
},
{
"name": "Offers",
"description": "Indicates that the company provides certain services."
},
{
"name": "Influences",
"description": "Indicates the effect of strategies or innovations on various aspects of the business."
}
],
"patterns": [
{
"head": "Executive",
"relation": "Reports",
"tail": "Financial_Metric",
"description": "An executive reports on a financial metric, such as revenue growth or operating margin."
},
{
"head": "Event",
"relation": "Impacts",
"tail": "Financial_Metric",
"description": "An event, like a product launch or economic development, impacts a financial metric."
},
{
"head": "Product",
"relation": "Presents",
"tail": "Financial_Metric",
"description": "A product is associated with specific financial metrics during a presentation, such as sales figures or profit margins."
},
{
"head": "Product",
"relation": "Operates_In",
"tail": "Geographic_Segment",
"description": "A product is available in a specific geographic segment."
},
{
"head": "Event",
"relation": "Occurs_During",
"tail": "Time_Period",
"description": "An event such as an earnings call occurs during a specific fiscal quarter or year."
},
{
"head": "Financial_Metric",
"relation": "Impacted_By",
"tail": "Market_Condition",
"description": "A financial metric is affected by a market condition, such as changes in foreign exchange rates."
},
{
"head": "Company",
"relation": "Offers",
"tail": "Service",
"description": "Apple offers a service like Apple Music or Apple TV+."
},
{
"head": "Service",
"relation": "Influences",
"tail": "Market_Condition",
"description": "A service influences market conditions, potentially affecting consumer behavior or competitive dynamics."
}
]
}
그런 다음 방금 정의한 스키마를 사용하여 그래프를 생성할 거예요.
schema = "../schemas/earnings_schema.json"
extracted_graph = client.graph.create_graph_from_schema(
namespace = namespace, schema_file = schema
)
print("Extracted Graph:", extracted_graph)
Neo4j 인스턴스 내에서 다음과 같은 그래프가 생성되는 것을 볼 수 있어요.

여기서 `노드`와 `관계`는 각각 스키마에 정의된 엔터티와 관계이고, 패턴은 우리가 관찰한 그래프를 구성하는 실제 관계를 의미해요.
동시에 `Vector Index`를 사용하여 동일한 문서를 벡터 표현으로 저장하는 검색 체인과 이러한 문서에 대한 질문 답변을 위한 GPT-4 모델을 정의했어요. 또한 검색 파이프라인을 최적화하기 위해 Cohere의 Rerank를 구현합니다.
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import OpenAIEmbeddings
from langchain import hub
from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import PyPDFDirectoryLoader
from langchain.retrievers.document_compressors import FlashrankRerank
from langchain.retrievers import ContextualCompressionRetriever
import os
from langchain import PromptTemplate, LLMChain
from langchain_cohere import CohereRerank
from cohere import Client
from dotenv import load_dotenv
load_dotenv()
cohere_api_key = os.getenv("COHERE_API_KEY")
co = Client(cohere_api_key)
class CustomCohereRerank(CohereRerank):
class Config():
arbitrary_types_allowed = True
CustomCohereRerank.update_forward_refs()
def format_docs(docs):
return "nn".join(doc.page_content for doc in docs)
def query_vector_db(query,faiss_index):
retriever = faiss_index.as_retriever()
compressor = CustomCohereRerank(client=co)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor, base_retriever=retriever
)
template = """You are a helpful assistant who is able to answer any question using the provided context. Answer the question using just the context provided to you
question: {question}
context: {context}
Provide a concise response with maximum three sentences"""
prompt = PromptTemplate(template=template,
input_variables=["context","question"])
llm = ChatOpenAI(model="gpt-4")
rag_chain = LLMChain(prompt=prompt,llm=llm)
docs = compression_retriever.invoke(query)
context = format_docs(docs)
answer = rag_chain.invoke({"question":query,"context":context})
return answer
def index_docs_vectordb(path):
loader = PyPDFDirectoryLoader(path)
pages = loader.load_and_split()
faiss_index = FAISS.from_documents(pages, OpenAIEmbeddings())
return faiss_index
# index docs
path = "earning-calls-apple" # the path to the folder containing the PDF documents
index = index_docs_vectordb(path)
마지막으로, `Vector` 저장소와 `Graph`를 각각 쿼리하기 위해 두 개의 함수(`query_Vectordb` 및 `query_graph`)를 정의할 거예요.
def query_vectordb(query):
answer = query_vector_db(query,index)
return answer
def query_graph(query,namespace):
query_response = client.graph.query_graph(namespace, query)
return query_response.answer
`Graph` 및 `Vector` 쿼리의 완전성과 한계
완전성이란 중요한 세부 정보를 놓치지 않고 `Query`에 대한 모든 관련 정보를 제공하는 시스템의 능력을 의미해요. `Graph Database`는 관계형 특성 덕분에 상호 연결된 모든 데이터를 철저하게 검색해서 포괄적인 답변을 제공할 수 있죠. 반대로, 유사한 텍스트 덩어리를 찾는 데는 효율적이지만 `Vector` `Index`는 더 넓은 맥락이나 데이터 포인트 간의 상호 관계에 대한 완전한 보기를 항상 포착하지 못할 수도 있어요. Apple의 Mac 제품 라인에 직접적으로 영향을 미치는 모든 시장 상황을 전체적으로 파악해야 한다고 상상해 보세요. 여기에는 경제적 요인, 공급망 문제, 경쟁 역학 등이 포함될 수 있어요. 이 정보를 검색하기 위해 `GraphQueryManager` 클래스를 정의할 수 있답니다.
from neo4j import GraphDatabase
class GraphQueryManager:
def __init__(self, uri, user, password):
self.driver = GraphDatabase.driver(uri, auth=(user, password))
def close(self):
self.driver.close()
def get_impacting_market_conditions(self, product_name):
with self.driver.session() as session:
result = session.run("""
MATCH (n)-[r:IMPACTS]->(m) WHERE m.name=$product_name AND n.namespace="apple-earning-calls"
RETURN n.name as Condition, r.description as Description, m.name as Product
""", product_name=product_name)
return [{"Condition": record["Condition"], "Description": record["Description"], "Product": record["Product"]} for record in result]
# Usage
graph_manager = GraphQueryManager(url, "neo4j", password)
conditions = graph_manager.get_impacting_market_conditions("Mac")
graph_manager.close()
Graph를 쿼리하면 Apple Mac에 영향을 미친 모든 시장 상황을 검색해서 제품과 관련된 모든 시장 상황을 포함할 수 있어요. 이는 다음과 같은 시장 상황 목록을 생성하죠.
for condition in conditions:
print(f"- {condition['Condition']}","n")
- COVID-19
- foreign exchange
- macro environment
- macroeconomic outlook
- Market Condition
- product
- services
- softening macro
- PC industry
- iPhone
- revenue
- silicon shortage
- strong March results
- product launch
- sellout conditions
- tightness in the supply chain
- COVID disruptions
- foreign currency
- market condition
- macroeconomic headwinds
- macroeconomic outlook
- COVID-related impacts
- FX headwinds
- digital advertising
- gaming

각 항목은 Graph Database의 구조화된 관계를 기반으로 Mac에 영향을 미치는 것으로 태그가 지정돼요. 이러한 직접 연결을 통해 정보의 관련성과 쿼리 의도를 정확하게 타겟팅할 수 있죠.
Vector Store 기반 체인에 대해 동일한 쿼리를 실행하면 덜 완전한 답변을 얻을 수 있어요.
vectordb_conditions = query_vectordb(
"what are the market conditions that impact Mac products?")
print(vectordb_conditions)
Mac 제품에 영향을 미치는 시장 상황에는 외환 역풍, 심각한 공급 제약, 거시 경제 환경 등이 있어요.
그래프 검색과는 달리, 벡터 검색은 본질적으로 다양한 시장 상황과 Mac에 미치는 영향 사이의 관계를 명확하게 이해하거나 전달하지 않아요. 연결을 이해하려면 추가적인 분석이 필요한 텍스트 덩어리를 제공하는 거죠. 이는 분석 과정에서 중요한 정보가 간과될 수 있고, 시간이 지남에 따라 일관성 없는 답변이 나올 수 있다는 의미이기도 해요. 포괄적인 관련 개념 세트를 강조하고 나열하는 관계 기반 구조가 없다면, 벡터 검색만으로는 완전한 응답을 생성하기 어려울 수 있어요.
하지만 그래프 전용 검색에도 한계는 존재해요. 그래프는 텍스트의 기본 정보를 트리플(즉, 엔터티 - 관계 - 엔터티)로 단순화해서 표현하거든요. 이렇게 정보를 단순화하고 추상화하는 과정에서 기본적인 맥락의 일부를 잃을 위험이 있는 거죠.

Neo4j의 공동 창립자이자 CEO인 Emil Eifrem은 이렇게 말했어요. "저희는 벡터로 찾아낸 암시적인 관계와 그래프로 찾아낸 명시적이고 사실적인 관계 및 패턴을 결합하는 데 큰 가치가 있다고 생각해요. 고객은 생성 AI로 혁신할 때, 배포 결과가 정확하고 투명하며 설명 가능하다는 점을 신뢰해야 하죠."
심층 질문
Neo4j에서 depth 파라미터를 구현하면 Graph Database 내의 복잡한 관계를 분석하는 메커니즘을 제공하게 돼요. 다음 코드 스니펫에서는 Tim Cook이 보고한 재무 측정항목과 이에 영향을 미치는 시장 상황을 검색하는 쿼리를 실행하는 것을 보여줍니다.
depth 파라미터는 Cypher 쿼리의 관계 패턴에 지정되는데요. 이 경우 depth 파라미터는 [:REPORTS] 및 [:IMPACTED_BY] 관계 모두에서 *1..20 범위로 표시돼요. 이 범위는 시작 Node('임원')에서 대상 Node('재무 지표' 및 '시장 조건')까지 통과하는 최소 및 최대 홉(또는 관계) 수를 나타내죠.
MATCH path = (exec:EXECUTIVE)-[:REPORTS*1..20]->
(metric:FINANCIAL_METRIC)-[:IMPACTED_BY*1..20]->(cond:MARKET_CONDITION)
WHERE exec.name='Tim Cook'
RETURN exec, metric, cond, path
결과적으로 다음과 같은 하위 그래프를 얻게 됩니다.

그래프는 지정된 그래프 검색 깊이를 탐색해서 쿼리와 관련된 상호 연결된 엔터티를 보여줘요. 또한 그래프의 Node와 관련된 청크를 검색할 수 있는 최신 청크 연결 기능을 활용하면서 WhyHow SDK를 사용하여 구성된 그래프를 쿼리해서 반환된 결과를 사용해 깊이 지향 질문을 탐색하는 그래프의 기능을 확인할 수 있어요.
from langchain.chat_models import ChatOpenAI
from langchain import PromptTemplate, LLMChain
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
def run_chain(question,txt_context):
template = """ You are a helpful assistant who is able to answer any question using the provided context. Answer the question using just the context provided to you
Question : {question},
Context:{context}
Provide a concise response with maximum three sentences"""
prompt = PromptTemplate(template=template,
input_variables=["context","question"])
# load the model
chat = ChatOpenAI(model_name="gpt-4",openai_api_key=OPENAI_API_KEY, temperature=0.0)
chain = LLMChain(llm=chat, prompt=prompt)
answer = chain.invoke({"question":question,'context':txt_context})
def query_graph_with_chain(question):
context = client.graph.query_graph(
query = question,
namespace = "apple-earning-calls",
include_chunks = True
)
txt_context = context.answer
txt = " "
for chunk in context.chunks:
for text in chunk.chunk_texts:
txt += text
txt_context += txt
chain_answer = run_chain(question,txt_context)
return chain_answer['text']
gr = query_graph_with_chain(question['question'])
vc = query_vector_db(question['question'],index)
print("Graph: ", gr)
print("Vector: ", vc['text'])
: 경영진은 팬데믹 기간 동안 소비자 행동 변화가 Apple의 비즈니스 모델에 미치는 영향을 어떻게 설명했나요?
- 그래프 쿼리 답변: 경영진은 팬데믹 기간 동안 소비자 행동 변화가 Apple 제품 및 서비스에 대한 수요 증가로 이어지는 영향을 설명했어요. 특히 원격 근무, 온라인 학습, 디지털 엔터테인먼트 분야에서 두드러졌죠. 따라서 팬데믹은 Apple의 비즈니스 모델에 긍정적인 영향을 미쳤다고 할 수 있어요.
- 벡터 DB 답변: 팬데믹 기간 동안 소비자 행동의 변화는 iPhone 14 Pro 및 iPhone 14 Pro Max의 공급에 큰 영향을 미쳤어요. 이 때문에 Apple이 예상하지 못한 배송 시간이 길어졌죠. 게다가 회사는 Mac과 웨어러블 기기에 가장 큰 영향을 미치고 iPhone에는 가장 적은 영향을 미치는 등 제품과 서비스 전반에 걸쳐 어느 정도 영향을 미쳤다고 해요.
: 그래프 쿼리에서는 소비자 행동의 특정 부문(원격 근무, 온라인 학습, 디지털 엔터테인먼트) 내에서 소비자 행동의 구체적인 영향을 언급했어요. 반면 벡터 쿼리에서는 답변이 팬데믹 관련 영향에 대해 좀 더 일반적으로 말하는 것처럼 보이네요.
: 경영진 논의에서는 중화권 지역 시장 상황과 Apple의 재무 성과 간의 관계를 어떻게 자세히 설명했나요?
- 그래프 쿼리 답변: 경영진 토론에서는 iPhone, Mac, iPad, Wearables와 같은 다양한 Apple 제품의 판매를 조사해서 중화권 시장 상황과 Apple 재무 성과 간의 관계를 자세히 설명했어요. 또한 설치 기반 및 AppleCare와 같은 요소도 고려했고요. iPhone 14 Pro, Apple Watch Series 8과 같은 특정 제품의 인기도 고려되었답니다.
- 벡터 DB 답변: 경영진 토론에서는 코로나19 제한과 공급 제약이 수요와 성장에 미치는 영향을 논의하면서 중화권 지역 시장 상황과 Apple의 재무 성과 사이의 관계를 자세히 설명했어요. 이러한 어려움에도 불구하고 Apple은 12월부터 매장 트래픽과 수요에 뚜렷한 변화를 보였죠. 또한 공급 부족에도 불구하고 "Pro" 제품에 대한 강력한 사이클을 언급하면서 고급 제품에 대한 소비자 선택을 유도할 수 있는 능력을 보여줬어요.
: 그래프 쿼리에서는 특정 제품의 인기도에 대한 내용이 언급되고 탐색되었어요. 벡터 쿼리에서 대답은 특히 중국의 성과와 더 밀접하게 연결되는 것이 아니라 '시장 상황'이라는 용어 때문에 전염병 관련 영향에 대해 더 일반적으로 말하는 것처럼 보이고요.
: Apple은 스마트폰 시장의 경쟁 과제를 해결하기 위해 어떤 세부 전략을 사용했나요?
- 그래프 쿼리 답변: Apple은 지속적인 혁신과 강력한 마케팅 캠페인을 통해 스마트폰 시장의 경쟁 과제를 해결했어요. 또한 독점적인 기능을 활용하고 고객 사이에서 브랜드 충성도를 높였죠. 이러한 전략은 시장에서 경쟁력을 유지하는 데 도움이 되었답니다.
- 벡터 DB 답변: 스마트폰 시장의 경쟁적 과제를 해결하기 위한 Apple의 전략에는 장기적으로 관리하고 통제할 수 없는 상황에 신속하게 적응하는 것이 포함돼요. 그들은 또한 혁신, 사람, 긍정적인 사회적 영향에 투자하고요. 다른 전략에는 고객의 삶을 풍요롭게 하고 고객의 창의적 잠재력을 발휘하는 데 도움이 되는 기술 개발도 있답니다.
: 그래프 쿼리에서는 사용된 전략 유형(독점 기능 및 강력한 마케팅 캠페인)에 대한 답변이 더 구체적이었고, 벡터 쿼리에서는 더 광범위해 보였어요(혁신에 투자).
폭넓은 질문
폭 넓은 질문에는 특정 주제와 관련된 다양한 개념에 대한 통찰력을 추출하는 광범위한 개요가 필요해요. 그래프 쿼리의 폭을 제어한다는 것은 검색을 제한해야 하는 범위를 확장하거나 축소한다는 의미죠. 이를 통해 Node 주변의 즉각적인 연결을 탐색하고 바깥쪽으로 확장해서 시작 Node가 직접 연결된 Node 또는 Node 유형의 수를 확인하는 질문에 답할 수 있어요.

이 그래프 내에서 이 정보를 LLM에 제공해서 사후 처리를 수행하고 Semantic Search 유사성을 검색하고 추적하려는 특정 Relationship 유형 또는 특정 Node 유형을 식별해서 가장 관련성이 높은 데이터 포인트를 결정할 수 있어요.
예를 들어, Relationship 유형에 따른 경우:
MATCH (n:PRODUCT)-[r]->(m)
WHERE n.name="iPhone"
RETURN n, r, m

또는 `Node` 유형별로 이렇게도 할 수 있어요:
MATCH (n:PRODUCT)-[r]->(m)
WHERE (m:GEOGRAPHIC_SEGMENT OR m:FINANCIAL_METRIC) AND n.name="iPhone"
RETURN n, r, m

: Apple은 제품 개발에 있어 기술 혁신과 비용 관리의 균형을 어떻게 유지하나요?
- 그래프 쿼리 답변: Apple은 첨단 제품을 만들기 위한 연구 개발에 막대한 투자를 통해 기술 혁신과 비용 관리의 균형을 맞추고 있어요. 또한 공급망 효율성을 최적화해서 비용을 관리하죠. 비용을 낮게 유지하기 위해 공급업체와 유리한 가격을 협상하기도 하고요.
- 벡터 DB 답변: Apple은 부품 비용 상승과 기타 시장 상황에 적응하여 제품 개발에서 기술 혁신과 비용 관리의 균형을 유지합니다. 이들은 구성 요소 비용의 상승 및 하락 순을 관리하여 어려운 환경을 효과적으로 탐색하려고 노력합니다. Apple은 또한 고객의 삶을 풍요롭게 하고 고객의 창의적 잠재력을 발휘하는 데 도움이 되는 기술을 제공하는 데 중점을 두고 혁신과 인력에 지속적으로 투자하고 있습니다.
: 그래프 쿼리 답변에는 공급업체 협상 및 공급망 관리와 같은 구체적인 조치가 언급되어 있어요. 벡터 DB의 대답은 '도전적인 환경 탐색'과 '혁신에 대한 투자'에 대해 더 모호하죠.
깊이와 폭에 대한 질문
그래프의 깊이와 폭을 탐색해야 하는 질문은 실제 시나리오에서 자주 접하게 돼요. 이러한 질문에는 심층적인 개념 정보뿐 아니라 해당 정보가 다른 개념과 어떻게 관련되는지에 대한 이해가 필요하죠.
Graph Database를 사용하면 그래프 `쿼리`에서 두 가지 검색 유형을 결합할 수 있으므로 풍부한 통찰력이 포함된 복잡한 하위 그래프를 더 쉽게 검색할 수 있어요.
사용 사례에서 Apple의 전략적 결정이 일련의 분기에 걸쳐 다양한 지리적 부문에 걸쳐 재무 지표에 어떤 영향을 미치는지, 그리고 이러한 지표가 제품 개발 전략에 어떻게 영향을 미치는지 알아보고 싶다고 가정해 보겠습니다. 이러한 엔터티 간의 상호 연결된 `관계`를 나타내는 그래프 `쿼리`를 구성할 수 있어요.
MATCH (exec:EXECUTIVE)-[r1:REPORTS]->(metric:FINANCIAL_METRIC),
(metric)-[r2:IMPACTED_BY]->(cond:MARKET_CONDITION),
(prod:PRODUCT)-[r3:PRESENTS]->(metric),
(prod)-[r4:OPERATES_IN]->(geo:GEOGRAPHIC_SEGMENT),
(event:EVENT)-[r5:OCCURS_DURING]->(time:TIME_PERIOD),
(event)-[r6:IMPACTS]->(metric)
WHERE exec.name IN ['Tim Cook', 'Luca Maestri'] AND
geo.name IN ['Americas', 'Europe', 'Greater China'] AND
time.name IN ['Q1 2023', 'Q2 2023', 'Q3 2023']
RETURN exec, metric, cond, prod, geo, event, time, r1,r2,r3,r4,r5,r6

WhyHow의 청크 연결 기능은 `노드`와 해당 청크를 모두 사용하여 LLM에 완전한 컨텍스트를 제공함으로써 이러한 유형의 질문에 대해 작동해요.
: 특히 Apple의 제품 혁신 및 시장 확장 계획과 관련하여 기술 지출 성장 둔화에 대한 투자자의 우려를 완화하기 위해 Tim Cook은 Apple 2022년 4분기 Earnings Call에서 어떤 구체적인 전략을 설명했습니까?
- 그래프 쿼리 답변: Apple 2022년 4분기 Earnings Call에서 Tim Cook은 기술 지출 성장 둔화에 대한 투자자의 우려를 완화하기 위한 전략을 제시했어요. 그는 시장 리더십과 고객 관심을 유지하기 위해 iPhone 14 및 iPad Pro와 같은 제품에 새로운 기능을 도입하여 지속적인 혁신을 강조했죠. Cook은 또한 고객 기반과 판매 확대에 중요한 인도 및 라틴 아메리카와 같은 신흥 시장에서의 Apple의 성장을 강조했어요. 또한 그는 Apple Music과 같은 서비스 강화와 탄소 중립을 위한 노력, 재활용 재료 사용 등 환경을 생각하는 이해관계자들의 공감을 불러일으키는 지속 가능성에 대한 회사의 약속을 강조했죠.
- Vector DB 답변: Apple 2022년 4분기 실적 발표에서 Tim Cook은 iPhone 14와 같은 제품의 지속적인 혁신을 강조하고, 신흥 시장으로 확장하고, Apple Music과 같은 서비스를 강화하고, 지속 가능성 노력에 집중함으로써 기술 지출 둔화에 대한 우려를 해결했습니다.
해설: Graph 쿼리 답변에서 언급된 전략이 여러 지역과 제품 라인에 걸쳐 있는 동시에 특정 국가나 특정 전략의 목적에 대해 더 깊이 언급하고 있음을 알 수 있어요. Vector DB 답변에 일부 부분이 언급되어 있지만 답변은 덜 철저하고(폭) 덜 자세합니다(깊이).
Vector Search를 강화하는 Graph Search 레버로서의 깊이와 폭
Graph Search를 사용하면 폭과 깊이가 다중 에이전트 시스템에서 검색을 위한 잠재적인 수단으로 볼 수 있어요. 코디네이터 에이전트는 질문을 평가하여 검색에 더 많은 폭 및/또는 깊이가 필요한지 여부를 결정할 수 있죠. 그런 다음 Graph 쿼리의 일부로 개별 범위(예: 0.0~1.0)를 사용하여 너비 또는 깊이 수준을 구성할 수 있어요. 에재귀 검색 에이전트를 사용하면 그래프를 수평(너비) 또는 수직(깊이)으로 탐색하는 동안 무엇을 유지하고 제거할지 결정하고 추가로 평가하는 데 도움이 될 수 있어요.
이러한 특정 유형의 검색은 특히 Vector RAG만으로는 결정적이고 정확한 방식으로 구축하기 어렵죠. 이러한 유형의 검색 패턴은 그래프 구조를 사용하여 검색용 데이터를 저장하는 새로운 기회를 보여줍니다. 의미 구조를 저장할 뿐만 아니라 정보 탐색을 위해.
폭이나 깊이에 대해 최적화할지 여부는 특정 비즈니스 시나리오 또는 쿼리를 수행하는 사용자 페르소나에 따라 달라지며 이를 기반으로 사용자 정의할 수 있어요. 예를 들어, 소비자를 대상으로 하는 일반 연구 플랫폼은 처음에는 폭 넓은 검색을 최적화하는 데 더 관심이 있을 수 있으며, 사용자가 특정 주제를 더 깊이 탐색하고 있음을 발견하면 점점 더 깊이 있는 검색을 최적화할 수 있어요. 이와 대조적으로 변호사가 사용하는 내부용 법적 RAG 플랫폼은 처음부터 심층 검색에 더 최적화될 수 있죠. RAG의 개별 개인화는 검색 시스템이 사용자의 스타일과 선호도에 따라 폭이나 깊이를 최적화함으로써 구현될 수도 있답니다.
결론
그래프 구조는 답변 검색을 위한 폭과 깊이를 위한 수단을 만드는 데 도움이 돼요. 실제 재무 분석 사례를 사용하여 그래프 구조가 깊이와 폭 모두에서 보다 완전한 답변을 생성하는 데 훨씬 더 많은 영향력을 제공한다는 것을 확인했어요. 또한 정보 검색을 수행하기 위한 의미론적으로 일관되고 정확하며 결정론적인 방법을 만들죠. Vector Search와 함께 그래프 구조를 사용하면 높은 수준의 결정적이고 완전한 검색이 보장되며 이는 기업 작업 흐름에 매우 중요해요.
- rag
에이치시스템즈의 LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.
'GraphRAG' 카테고리의 다른 글
| Python으로 Neo4j GraphRAG 지식 그래프 구축하기 (0) | 2026.05.22 |
|---|---|
| LLM 기반 지식 정합성을 위한 선택: Knowledge Graph vs. Vector Database (1) | 2026.05.22 |
| 짐 웨버와 매트 클로이드: 분쟁 해결에 그래프의 힘 (Neo4j, GraphRAG 활용) (0) | 2026.05.21 |
| Neo4j GraphRAG Python 패키지의 ToolsRetriever를 소개합니다! (0) | 2026.05.21 |
| 금융 분석가를 위한 똑똑한 추천 엔진: Machine Learning과 Neo4j, GraphRAG의 만남 (0) | 2026.05.21 |
