일전에 크롤링을 통해 얻었던 재무제표 데이터를 활용해 로컬에서 postgresql DB를 구축해 자연어 쿼리에서 엔티티를 추출했다는 가정하에, 특정 기업에 대한 데이터를 디비에서 조회해서 LLM에게 context로 제공해 답변을 생성해보도록 하겠습니다.
1. Postgresql 설치
도커 컨테이너를 사용하지않고 가장 기본적인 로컬 환경에서 실행을 할 것이기 때문에 아래 명령어로 먼저 Postgresql 서버가 실행중인지 확인해줍니다.
brew services list
초기엔 당연히 postgresql이 안나올것이고 실행을 위해서는 "brew services start postgresql" 명령어를 입력해줘야합니다.

실행후 사진과같은 에러가 발생했다면, postgresql이 설치되어있지 않아서 생긴 에러이기 때문에 하단 명령어로 설치해줍니다.
brew install postgresql
이후 다시 "brew services start postgresql" 명령어를 입력하고 "brew services list"로 확인해보면 로컬에서 postgresql이 정상적으로 실행되고 있는 모습을 볼 수 있습니다. 나중에는 이렇게 로컬에 다운로드 받아서 실행시키는게 아니라 도커 컨테이너 환경에서 다운로드받아서 실행하는 것도 일반적으로 사용되는 방법입니다.
2. server & DB create
postgresql을 설치하고 실행했으니 이제 내부에 디비를 만들고 테이블을 만들도록 하겠습니다.

좀 더 시각적으로 편하게 작업하기 위해 GUI 도구인 pgAdmin을 설치해고 실행해주었습니다. 가장 처음 실행 시켰을때 화면인데, 여기서 로컬에서 실행한 postgresql 서버를 연결해줍니다. Servers -> Register -> server... 를 클릭해줍니다

서버의 이름은 자신이 하고싶은 이름을 지정해주면됩니다.

로컬에서 실행시킨 postgresql 서버에 연결할 것이기 때문에 Host name은 localhost로 하고 별도의 설정을 해주지 않았기 때문에 Username은 기본적으로 현재 macOS 사용자이름이 기본값이고 Password는 없기때문에 나중에 값을 입력해주면 됩니다.

그러면 이제 "financial_data"라고 하는 새로운 server가 생긴 모습을 볼 수 있습니다.

이제 새 서버에 DB와 Table을 생성해주도록 하겠습니다. 기본적으로 Postgresql은 기본 제공해주는 postgres DB에 먼저 연결한 후, 사용자가 원하는 새로운 DB를 생성한 다음, 해당 데이터베이스에 다시 연결하는 구조입니다. 따라서 먼저 postgres DB에 연결하는 코드를 작성해줍니다.
import psycopg2
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
# 데이터베이스 연결 및 생성
conn = psycopg2.connect(
database="postgres",
user="dongseok",
password="qwe123", # 실제 비밀번호로 변경
host="localhost",
port="5432"
)
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
cursor = conn.cursor()
CREATE DATABASE 명령은 트랜잭션 안에서 실행할 수 없어서 "conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)" 코드로 트랜잭션 자동 커밋 설정을 추가해줘야합니다. 그리고 이제 내가 원하는 DB를 만들어줍니다.
# 데이터베이스 생성
db_name = "financial_data"
cursor.execute(f"CREATE DATABASE {db_name}")
cursor.close()
conn.close()
PostgreSQL에서는 특정 데이터베이스 내부에서 새로운 데이터베이스를 생성하는 것이 아니라, PostgreSQL 서버 자체에서 관리하는 데이터베이스 리스트에 새로운 데이터베이스를 추가하는 방식입니다. 따라서 "CREATE DATABASE financial_data" 명령은 postgres 데이터베이스에 연결된 상태에서 실행하지만, 새로운 financial_data 데이터베이스는 PostgreSQL 서버의 데이터베이스 리스트에 등록됩니다.

이제 새로 만든 financial_data db에 연결하고 테이블을 만들어보도록 하겠습니다.
# 새 데이터베이스에 연결
conn = psycopg2.connect(
database=db_name,
user="dongseok",
password="qwe123", # 실제 비밀번호로 변경
host="localhost",
port="5432",
)
cursor = conn.cursor()
# 테이블 생성
cursor.execute(
"""
CREATE TABLE companies (
ticker VARCHAR(20) PRIMARY KEY,
company_name VARCHAR(200) NOT NULL
);
"""
)
cursor.execute(
"""
CREATE TABLE report_types (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
);
"""
)
cursor.execute(
"""
CREATE TABLE metrics (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
report_type_id INTEGER REFERENCES report_types(id),
UNIQUE(name, report_type_id)
);
"""
)
cursor.execute(
"""
CREATE TABLE financial_data (
id SERIAL PRIMARY KEY,
ticker VARCHAR(20) REFERENCES companies(ticker),
metric_id INTEGER REFERENCES metrics(id),
value TEXT,
report_date DATE,
UNIQUE(ticker, metric_id, report_date)
);
"""
)
# 보고서 유형 초기 데이터 삽입
report_types = ["income_statement", "balance_sheet", "cash_flow", "financial_ratios"]
for rt in report_types:
cursor.execute("INSERT INTO report_types (name) VALUES (%s)", (rt,))
conn.commit()
새로운 테이블들이 잘 생성된 모습을 볼 수 있습니다.

이제 이전에 크롤링했던 재무제표 파일에서 데이터를 파싱해서 테이블에 인덱싱해주면,

쿼리에 따른 테이블 조회가 잘 되는 모습을 볼 수 있습니다. 다음에는 이러한 RDBMS에 저장한 값을 LLM에게 context로 줘서 사용자 쿼리에 대해 답변을 생성해보고 더 나아가 pgvector를 활용해 시맨틱 서치도 진행해보도록 하겠습니다.
'FinAgent Lab' 카테고리의 다른 글
[ESG 투자] ESG 투자란? (0) | 2025.04.02 |
---|---|
[LLM] context 기반 답변 비교 (0) | 2025.03.27 |
[crawling] 해외 기업 재무제표 crawling 해오기 (0) | 2025.03.25 |