GitHub Copilot이 코드를 더 잘 이해하는 방법
새로운 Fill-in-the-Middle 패러다임을 통해 GitHub 엔지니어는 GitHub Copilot이 코드를 컨텍스트화하는 방식을 개선했습니다. 고급 검색 알고리즘을 계속 개발하고 테스트함으로써 AI 도구를 더욱 발전시키기 위해 노력하고 있습니다.
작가
2023년 5월 17일 원본기사링크
GitHub Copilot을 사용하여 작업하는 것이 개발자와 페어 프로그래머 간의 만남처럼 느껴지도록 하기 위해 GitHub의 머신 러닝 전문가는 새로운 기능을 연구, 개발 및 테스트하는 데 많은 노력을 기울이고 있으며, 많은 사람들이 AI 페어 프로그래머의 context에 대한 이해를 향상시키는 데 중점을 두고 있습니다. 좋은 의사소통이 페어 프로그래밍의 핵심이고, 좋은 의사소통을 위해서는 맥락을 추론하는 것이 중요하기 때문입니다.
자세한 내용을 설명드리기 위해, 우리는 GitHub의 연구원과 엔지니어들에게 GitHub Copilot이 상황에 대한 이해를 향상시키는 데 도움을 주기 위해 수행 중인 작업에 대해 물었습니다. 우리가 발견한 것은 다음과 같습니다.
OpenAI의 Codex 모델에서 GitHub Copilot까지
OpenAI가 2020년 6월 GPT-3을 출시했을 때 GitHub는 개발자가 코딩을 위해서 모델을 활용하여 제품의 이점을 누릴 수 있다는 것을 알았습니다. 그래서 우리는 GPT-3의 후손이자 GitHub Copilot을 지원하는 LLM인 Codex를 구축하면서 OpenAI에 의견을 제공했습니다. 그리고 페어 프로그래머로서 2021년 6월 technical preview 로 출시되었고, 이후 세계 최초의 대규모 생성형 AI 코딩 도구로 2022년 6월 상용화로(Generally available) 출시 되었습니다.
모델이 속도와 함께 최상의 예측을 할 수 있는 최상의 정보를 갖도록 보장하기 위해 GitHub의 머신 러닝(ML) 연구원은 프롬프트 엔지니어링(아래에서 자세히 설명할 것임)이라는 많은 작업을 수행하여 모델이 context에 맞는 정보를 제공하도록 했습니다. 또, 낮은 지연 시간으로 관련 응답을 제공합니다.
GitHub의 ML 엔지니어인 데이비드 슬레이터는, GitHub는 항상 새로운 모델이 나올 때마다 실험하고 있지만 Codex는 사용 가능한 최초의 강력한 생성형 AI 모델이라고 말했습니다. “모델을 반복하고 즉각적인 개선을 통해 얻은 실무 경험은 매우 귀중했습니다.”
GitHub 내부: GitHub Copilot 뒤의 LLM 작업
GitHub Copilot의 초기 버전을 구축하고 그 이후로 개선해 온 GitHub의 연구원 및 엔지니어들의 내부적인 풀 스토리 도 참조하세요.
그 모든 실험의 결과로 페어 프로그래머가 탄생했으며, 이것은 궁극적으로 개발자가 더 만족스러운 작업에 집중할 수 있는 시간을 확보해 줍니다. GitHub의 ML 연구원인 앨리스 리는, 이 도구는 개발자가 새로운 프로젝트나 새로운 파일을 처음부터 작성할 때에도, 시작시의 출발이 되는 기반을 마련해 줄 수 있으므로 큰 도움이 되는 경우가 많습니다.
“저는 꽤 오랜시간 GitHub Copilot과 함께 개발 했지만, 지금도 여전히 GitHub Copilot이 할 수 있는 작업에 깊은 인상을 받고 매우 놀라워하고 있습니다.
- Alice Li, GitHub의 ML 연구원
Context가 중요한 이유
개발자는 풀 리퀘스트, 프로젝트의 폴더, 오픈되어져 있는 issue 등의 세부 정보를 사용하여 코드를 문맥에 맞게 조정합니다. 생성형 AI 코딩 도구의 경우 동일한 작업을 수행하는 데 사용할 정보를 해당 도구에 가르쳐야 합니다.
Transformer LLM은 점들을 연결하고 큰 그림을 그리는 데 능숙합니다.
생성형 AI 코딩 도구는 대규모 언어 모델(LLM)을 통해 가능해졌습니다. 이러한 모델은 대량의 코드와 인간 언어에 대해 훈련된 알고리즘 세트입니다. 오늘날의 최첨단 LLM은 transformer로서, 사용자 입력의 텍스트와 모델이 이미 생성한 출력을 연결하는 데 능숙하도록 해 줍니다. 이것이 오늘날의 생성형 AI 도구가 이전 AI 모델보다 context에 더 관련성이 높은 응답을 제공하는 이유입니다.
그러나 이러한 도구들은, 어떠한 정보가 여러분의 코드와 관련된 것인지 알려줘야 합니다. 현재 GitHub Copilot을 구동할 만큼 빠른 트랜스포머는 한 번에 약 6,000자를 처리할 수 있습니다. 이는 코드 완성 및 코드 변경 요약과 같은 작업을 진행하고 업무를 가속화하는 데 충분했지만 문자 수가 제한되어 있어 개발자의 코드 전체를 컨텍스트로 사용할 수는 없습니다.
따라서 우리의 과제는 모델에 제공할 데이터를 알아 내는것 뿐만 아니라 개발자에게 최상의 제안을 얻기 위해 데이터를 가장 잘 정렬하고 입력하는 방법도 파악하는 것입니다.
LLM, 생성형 AI 코딩 도구 및 이러한 도구들이 어떻게 개발자들의 업무방식을 혁신하는지에 대해 자세히 알아보세요.
GitHub Copilot이 코드를 이해하는 방법
모든 것은 프롬프트로 귀결됩니다. 프롬프트는 IDE 코드와 모델에 제공되는 관련 컨텍스트의 집합체입니다. 프롬프트는 코딩의 어느 시점에서나 백그라운드에서 알고리즘에 의해 생성됩니다. 이것이 바로 GitHub Copilot이 현재 주석을 작성 중이거나, 주석 작성을 마쳤을 때, 또는 별로 안 좋은 코드를 작성하는 도중에 코딩 제안해 주는 이유입니다.
- 프롬프트가 생성되는 방법은 다음과 같습니다. 먼저 일련의 알고리즘이 현재 파일 및 기타 소스(아래에서 자세히 설명)에서 관련 코드 조각이나 주석을 선택합니다. 그런 다음 이러한 code snippet과 주석의 우선순위를 정하고 필터링한 후 최종 프롬프트로 조합합니다.
GitHub Copilot의 context적인 이해도는 시간이 지남에 따라 지속적으로 성숙해졌습니다. 첫 번째 버전에서는 IDE에서 작업 중인 파일만 context에 맞는 것으로 간주할 수 있었습니다. 그러나 우리는 context가 그 이상이라는 것을 알고 있었습니다. 이제 불과 1년이 지난 지금, 우리는 전체 코드베이스를 고려하여 맞춤형 제안을 생성하는 알고리즘을 실험하고 있습니다.
우리가 여기까지 어떻게 왔는지 살펴보겠습니다.
-
프롬프트 엔지니어링은 모델이 사용자를 위한 가장 유용한 예측을 할 수 있도록 프롬프트를 생성하는 섬세한 기술입니다. 프롬프트는 GitHub Copilot을 포함한 LLM에게 여러분의 코드를 맥락화(contextualize)하기 위해 어떤 데이터를 어떤 순서로 처리할 것인지 알려줍니다. 이 작업의 대부분은 저희의 사내 ML 전문가가 알고리즘을 사용하여 개발자의 context에 대한 다양한 소스의 정보를 추출하고 우선순위를 지정하는 프롬프트 라이브러리라는 곳에서 이루어지며, 이를 통해서 프롬프트를 생성하여 GitHub Copilot 모델이 처리하게 됩니다.
-
Neighboring 탭은 GitHub Copilot이 개발자가 작업 중인 단일 파일이 아닌 개발자의 IDE에 열려 있는 모든 파일을 처리할 수 있도록 하는 기술입니다. 프로젝트와 관련된 모든 파일을 열면 개발자는 자동으로 GitHub Copilot에게, 열려 있는 파일들과 커서 주변의 코드에서 모든 데이터를 샅샅이 조사하여 매치되는 조각을 찾도록 하고, 이러한 일치하는 코드 조각을 프롬프트에 추가합니다.
Neighboring 탭을 개발할 때 GitHub Next 팀과 내부 ML 연구원은 A/B 테스트를 수행하여 IDE의 코드와 열려 있는 탭의 코드 간의 일치 항목을 식별하는 데 가장 적합한 매개 변수를 파악했습니다. 그들은 일치하는 항목을 포함할 시기에 대한 기준을 매우 낮게 설정하는 것이, 실제로 가장 좋은 코드 제안을 해준다는 사실을 발견했습니다.
모든 작은 context를 포함함으로써 neighboring 탭은 GitHub Copilot의 제안에 대한 사용자 수용도를 상대적으로 5% 높이는 데 도움이 되었습니다.
완벽한 일치 항목이 없거나 아주 좋은 일치 항목이 없더라도 우리가 찾은 가장 일치하는 항목을 선택하고 이를 모델의 컨텍스트로 포함하는 것이 아무것도 포함하지 않는 것보다 낫습니다.
- Albert Ziegler, GitHub의 수석 ML 엔지니어
- Fill-In-the-Middle(FIM) 패러다임은 컨텍스트 범위를 더욱 넓혔습니다. FIM 이전에는 커서 뒤의 코드를 무시하고 커서 앞의 코드만 프롬프트에 입력되었습니다. (GitHub에서는 커서 앞의 코드를 prefix, 커서 뒤의 코드를 suffix라고 합니다.) FIM을 사용하면 프롬프트의 어느 부분이 prefix이고 어느 부분이 suffix인지 모델에 알릴 수 있습니다.
처음부터 무언가를 만들기 시작하면서 파일의 뼈대를 갖고 있더라도 코딩이 선형적이거나 순차적이지 않다는 것을 우리는 알고 있습니다. 따라서 여러분들이 개발을 위해 파일을 돌아다니는 동안 FIM은 GitHub Copilot이 파일에서 커서가 위치해 있는 부분, 또는 prefix와 suffix 사이에 들어가야 할 코드에 대해 더 좋은 코드 제안을 해 줄 수 있도록 해 줍니다.
A/B 테스트를 기반으로 FIM은 성능을 상대적으로 10% 향상시켰습니다. 이는 개발자가 제안된 코드를 10% 더 많이 수락했음을 의미합니다. 그리고 최적화된 캐싱 사용 덕분에 neighboring 탭과 FIM이 추가 대기 시간 없이 백그라운드에서 작동합니다.
의미론적 이해 향상
현재 우리는 private 저장소나 소유권이 있는(Proprietary) 코드로 작업하는 개발자를 위한 맞춤형 코딩 경험을 제공할 수 있는 벡터 데이터베이스를 실험하고 있습니다. 생성형 AI 코딩 도구는 임베딩이라는 것을 사용하여 벡터 데이터베이스에서 정보를 가져옵니다.
- 벡터 데이터베이스란 무엇입니까? 고차원 벡터를 색인화하는 데이터베이스입니다.
- 고차원 벡터란 무엇입니까? 이는 객체의 수학적 표현이며 이러한 벡터는 다양한 차원에서 객체를 모델링할 수 있기 때문에 해당 객체의 복잡성을 포착할 수 있습니다. 코드 조각을 표현하는 데 적절하게 사용되면 구문뿐만 아니라 코드의 의미와 의도까지 모두 나타낼 수 있습니다.
- 임베딩이란 무엇입니까? 코딩 및 LLM의 맥락에서 임베딩은 코드 조각을 고차원 벡터로 표현하는 것입니다. LLM은 프로그래밍과 자연어에 대한 “지식”으로 인해 벡터에서 코드의 구문과 의미를 모두 캡처할 수 있습니다.
이 요소들이 모두 함께 작동하는 원리는 다음과 같습니다.
- 알고리즘은 저장소의 모든 조각(잠재적으로 수십억 개)에 대한 임베딩을 생성하고 이를 벡터 데이터베이스에 저장합니다.
- 그런 다음 코딩하는 동안 알고리즘이 IDE에 스니펫을 삽입합니다.
- 그런 다음 알고리즘은 IDE 스니펫에 대해 생성된 임베딩과 벡터 데이터베이스에 이미 저장된 임베딩 간에 실시간으로 대략적인 일치를 만듭니다. 벡터 데이터베이스는 수십억 개의 내장 코드 조각을 저장하고 있더라도, 알고리즘이 저장된 벡터에서 대략적인 일치 항목(정확한 항목뿐만 아니라)을 신속하게 검색할 수 있도록 해줍니다.
개발자는 일반적으로 캐릭터 매치를 통해 정확한 문자 일치를 찾는 해시코드를 사용하여 데이터를 검색하는 데 익숙합니다. GitHub의 선임 ML 연구원인 알리레자 구다르지는, “그러나 임베딩은 방대한 양의 데이터에 대해 훈련된 LLM에서 출발하기 때문에 코드 조각과 자연어 프롬프트 사이의 의미론적 유사성에 대한 감각을 갖출 수 있습니다.”
아래 세 문장을 읽고 의미상 가장 유사한 두 문장을 찾아보세요.
- 문장 A: The king moved and captured the pawn.
- 문장 B: The king was crowned in Westminster Abbey.
- 문장 C: Both white rooks were still in the game.
대답은 문장 A와 C입니다. 둘 다 체스에 관한 것이기 때문입니다. 문장 A와 B는 둘 다 왕을 주어로 사용하기 때문에 구문상 또는 구조적으로 유사하지만 “king”이 다른 문맥에서 사용되기 때문에 의미상 다릅니다.
각 명령문을 Python으로 변환하는 방법은 다음과 같습니다. 의미론적 차이에도 불구하고 조각 A와 B 사이의 구문적 유사성과, 구문론적 차이에도 불구하고 조각 A와 C 사이의 의미론적 유사성에 주목하세요.
스니펫 A:
if king.location() == pawn.location():
board.captures_piece(king, pawn)
스니펫 B:
if king.location() == "Westminster Abbey":
king.crown()
스니펫 C:
if len([ r for r in board.pieces("white") if r.type == "rook" ]) == 2:
return True
위에서 언급했듯이 우리는 여전히 검색 알고리즘을 실험하고 있습니다. 우리는 기업 고객, 특히 private 리포지토리를 통한 맞춤형 코딩 경험을 찾고 있으며 이 기능을 사용하기로 명시적으로 선택한 고객을 염두에 두고 이 기능을 설계하고 있습니다.
Take this with you
작년에 우리는 GitHub Copilot의 정량적 연구를 수행했고, 개발자는 페어 프로그래머를 사용하는 동안 최대 55% 더 빠르게 코딩하는 것으로 나타났습니다. 이는 개발자가 더 생산적이라고 느끼고, 반복적인 작업을 더 빠르게 완료하며, 만족스러운 작업에 더 집중할 수 있음을 의미합니다. 하지만 우리의 일은 거기서 끝나지 않을 것입니다.
GitHub product팀, GitHub Next를 포함한 R&D 팀은 GitHub Copilot의 context에 대한 이해를 지속적으로 개선하기 위해 Microsoft Azure AI 플랫폼과 협력해 왔습니다. GitHub Copilot이 코드를 맥락화(contextualize)하는 데 도움이 되는 많은 작업이 백그라운드에서 발생합니다. 여러분들이 코드를 작성하고 편집하는 동안 GitHub Copilot은 프롬프트를 생성하여 실시간으로 여러분들의 코드작성 및 편집에 응답합니다. 즉, IDE에서의 여러분들의 작업을 기반으로 관련 정보의 우선 순위를 지정하고 모델에 전송하여 계속해서, 여러분들께 최고의 코드를 제안해 드립니다.
더 알아보기
- GitHub Copilot X는 저희가 구상하고 있는 AI 기반 소프트웨어 개발의 미래입니다. 이에 대한 새로운 소식을 알아보세요.
- GitHub Copilot을 지원하는 LLM이 어떻게 발전하고 있는지 알아보세요.
- GitHub Copilot이 개발자 생산성에 어떠한 영향을 미치고 있는지 에 대한 연구 자료를 읽어보세요.