오늘은 Opensource에 contribute 하는 방법에 대해서 작성해놓으려고 한다.
사실 아직 반영되지 않았고, 너무 사소하기도해서 반영되지 않을 것 같지만.. 그래도 경험이고 언젠가 하게 될지 모르니 익숙해지고자 작성하려고 한다.
이번에 내가 수정한 부분은 langchain
에 있는 모듈 중 하나libs/community/langchain_community/document_loaders/firecrawl.py
에 기능을 하나 추가했다. Firecrawl
이라는 별도의 모듈이 있는데 여기서 extract
라는 기능이 추가되었는데 아직 langchain
에서 해당 내용을 반영하지 않아서, 내가 쓰고자 추가할 겸 한번 PR을 올려보았다.
다행히 가이드가 제공되어 있어서 가이드 + GPT의 도움을 받아서 PR을 올렸다. 그냥 정리보다는 내가 했던 과정을 그대로 작성해 보겠다.
1. Contribution 가이드 확인하기
우선 해당 오픈소스의 Github나 Docs에 가보면 웬만해서 contributions에 해당하는 부분에 가이드들이 나와있을 것이다.
(나와있지 않다면, 일반적인 규칙을 따르면 되는 것으로 알고 있음.)
나는 Langchain docs에 들어가서 해당 부분을 찾고 확인하였다.

그다음 Contributing
을 누르면 가이드로 이동되었다.
Welcome Contributors | 🦜️🔗 LangChain
Hi there! Thank you for your interest in contributing to LangChain.
python.langchain.com
langchain의 경우는 규모가 커서 방법들이 자세하게 나와있었다.Documentation
, Code
, Integrations
, Standard Tests
등으로 구분되어 있었고, 나는 새로운 기능을 추가하는 것이라서 Code
부분의 가이드를 참조하였다.

2. General guideline
2-1. Fork and Pull request workflow
우선 기본적인 가이드라인은 fork and pull request
workflow를 따르라고 나와있었다. 이 flow는 Github에 작성되어 있는 flow로, 일반적인 방법인가 보다 하였다.
Contributing to a project - GitHub Docs
If you want to contribute to someone else's project but don’t have permission to make changes directly, you can create your own copy of the project, make updates, and then suggest those updates for inclusion in the main project. This process is often cal
docs.github.com
Docs에 잘 나와있으며 간단하게 요약하면 아래와 같은 과정이다.
- 기여하고자 하는 Repository
Fork
하기 Fork
해온 repositroy clone 하기.- 로컬에서 브랜치 생성하기
- 작업 진행
Fork 한
repository에 commit, push 하기- 원본 repository로
Pull Request
보내기
당연하게도 모든 repo마다 가이드가 다를 수 있으니 꼭 해당 repo의 절차를 참고하자.
2-2. Open Pull Request
Pull request를 열면 Langchain에서
정해놓은 템플릿이 나왔고, 해당 내용들을 채워주면 됐다.Langchain
은 아래와 같은 template이 제공됐다.
Thank you for contributing to LangChain!
- [ ] **PR title**: "package: description"
- Where "package" is whichever of langchain, community, core, etc. is being modified. Use "docs: ..." for purely docs changes, "infra: ..." for CI changes.
- Example: "community: add foobar LLM"
- [ ] **PR message**: **_Delete this entire checklist_** and replace with
- **Description:** a description of the change
- **Issue:** the issue # it fixes, if applicable
- **Dependencies:** any dependencies required for this change
- **Twitter handle:** if your PR gets announced, and you'd like a mention, we'll gladly shout you out!
- [ ] **Add tests and docs**: If you're adding a new integration, please include
1. a test for the integration, preferably unit tests that do not rely on network access,
2. an example notebook showing its use. It lives in docs/docs/integrations directory.
- [ ] **Lint and test**: Run make format, make lint and make test from the root of the package(s) you've modified. See contribution guidelines for more: [https://python.langchain.com/docs/contributing/](https://python.langchain.com/docs/contributing/)
Additional guidelines:
- Make sure optional dependencies are imported within a function.
- Please do not add dependencies to pyproject.toml files (even optional ones) unless they are required for unit tests.
- Most PRs should not touch more than one package.
- Changes should be backwards compatible.
- If you are adding something to community, do not re-import it in langchain.
If no one reviews your PR within a few days, please @-mention one of baskaryan, eyurtsev, ccurme, vbarda, hwchase17.

2. Setup
Setup | 🦜️🔗 LangChain
This guide walks through how to run the repository locally and check in your first code.
python.langchain.com
다음으로 setup 과정은 단순히 내가 코드를 수정한 다음 내 마음대로 올리는 것이 아니라, 해당 repo에 정해져 있는 포맷이나 규칙 등을 따라야 하기 때문에 그것들을 쉽게 적용할 수 있는 것이었다.
Langchain
에서는 잘 구현되어 있었기 때문에 가이드에 나와있는 대로 단순하게
make test
make format
make lint
make spell_fix
이렇게 총 4개의 명령어를 수행하면, 어느 부분을 수정해야 하는지에 대한 경고가 뜨고 해당 부분들을 수정해 주면 됐다.
이걸 안 하고 PR을 올리면 봇이 자동으로 실행하는 CI/CD
test에서 실패하게 된다.
이것들을 모두 통과하고 PR을 올리게 되면, 봇이 테스트들을 진행하고 , 모두 통과하면 이제 REVIEW를 기다리게 된다.

만약 check에서 실패하게 되면 로컬에서 해당 부분들을 다시 수정한 다음 git push origin 브랜치명 --force
(여기서의 origin은 fork해온 내 repo) 를 통해서 올리게 되면 자동으로 Pull request에도 반영되게 되니 다시 check를 받으면 된다.
3. 여담
나는 이렇게 PR을 올려봤지만, 아마 Merge
까지는 안될 것 같다. Langchain
자체가 이미 너무 거대해졌고 가이드에도 아래와 같이 단순한 기능에 대한 것은 반영하지 않는다고 나와있다. 그래서 그냥 경험 삼아 올려보는 것으로 만족하려고 한다. 하하
![[image-37.png]]
4. 내가 작업한 내용
community: add 'extract' mode to FireCrawlLoader for structured data extraction by Bae-ChangHyun · Pull Request #30242 · langc
Description: Added an 'extract' mode to FireCrawlLoader that enables structured data extraction from web pages. This feature allows users to Extract structured data from a single URLs, or e...
github.com
내가 한 것은 Firecrawl이라는 오픈소스 웹 페이지 스크랩, 크롤링 패키지에서 새로운 extract
라는 기능이 추가되었고, 기존에 Langchain
에서 FireCrawlLoader
이라는 클래스를 통해서 해당 firecrawl과의 integration이 되어있었는데, 여기다가 extract 기능을 사용할 수 있도록 수정하였다.
코드 수정 자체는 간단했는데, PR을 올리기 위해서 test 코드를 작성해야 해서, 해당 코드를 작성하는 데에는 gpt의 도움을 받았다.
Langchain의 규칙은 내가 수정한 코드를 테스트할 코드를 특정 경로에 만들어둬야 했기 때문에 아래와 같이 작성하여 test를 끝냈다.
libs/community/tests/unit_tests/document_loaders/test_firecrawl.py
"""Test FireCrawlLoader."""
import sys
from typing import Generator, List, Tuple
from unittest.mock import MagicMock
import pytest
from langchain_core.documents import Document
from langchain_community.document_loaders import FireCrawlLoader
@pytest.fixture(autouse=True)
def mock_firecrawl() -> Generator[Tuple[MagicMock, MagicMock], None, None]:
"""Mock firecrawl module for all tests."""
mock_module = MagicMock()
mock_client = MagicMock()
mock_module.FirecrawlApp.return_value = mock_client
response_dict = {
"success": True,
"data": {
"title": "extracted title",
"main contents": "extracted main contents",
},
"status": "completed",
"expiresAt": "2025-03-12T12:42:09.000Z",
}
mock_client.extract.return_value = response_dict
# sys.modules에 모의 모듈 삽입
sys.modules["firecrawl"] = mock_module
yield mock_module, mock_client # 테스트에서 필요할 경우 접근할 수 있도록 yield
# 테스트 후 정리
if "firecrawl" in sys.modules:
del sys.modules["firecrawl"]
class TestFireCrawlLoader:
"""Test FireCrawlLoader."""
def test_load_extract_mode(
self, mock_firecrawl: Tuple[MagicMock, MagicMock]
) -> List[Document]:
"""Test loading in extract mode."""
# fixture에서 모킹된 객체 가져오기
_, mock_client = mock_firecrawl
params = {
"prompt": "extract the title and main contents(write your own prompt here)",
"schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"main contents": {"type": "string"},
},
"required": ["title", "main contents"],
},
"enableWebSearch": False,
"ignoreSitemap": False,
"showSources": False,
"scrapeOptions": {
"formats": ["markdown"],
"onlyMainContent": True,
"headers": {},
"waitFor": 0,
"mobile": False,
"skipTlsVerification": False,
"timeout": 30000,
"removeBase64Images": True,
"blockAds": True,
"proxy": "basic",
},
}
loader = FireCrawlLoader(
url="https://example.com", api_key="fake-key", mode="extract", params=params)
docs = list(loader.lazy_load()) # lazy_load 메서드 호출
assert len(docs) == 1
assert isinstance(docs[0].page_content, str)
# extract 메서드가 올바른 인자로 호출되었는지 확인
mock_client.extract.assert_called_once_with(["https://example.com"], params=params)
# 응답이 문자열로 변환되었으므로 각 속성이 문자열에 포함되어 있는지 확인
assert "extracted title" in docs[0].page_content
assert "extracted main contents" in docs[0].page_content
assert "success" in docs[0].page_content
return docs
'알쓸신잡' 카테고리의 다른 글
Chrome 텍스트 커서 깜박임 오류 해결 가이드 (0) | 2025.03.27 |
---|---|
Git-credential (0) | 2025.03.26 |
Vscode Local Port Forwarding (0) | 2025.03.07 |
ngrok 사용법 (0) | 2025.03.07 |
Docker Install on Ubuntu (0) | 2025.02.21 |