1. LLM이란?

정의

  • LLM (Large Language Model): 대규모 언어 모델로, 대량의 텍스트 데이터를 학습하여 자연어 처리, 생성 및 분석 작업을 수행할 수 있는 모델

실사용 사례

  • 문서 요약: 법률 문서나 기술 매뉴얼을 간결하게 요약.
  • 자동 응답 시스템: 고객 서비스 봇 구현.
  • 코드 분석 및 생성: 코드 리뷰, 오류 검출, 리팩토링 제안 등.

2. 왜 Local LLM인가?

Local LLM의 정의

  • Local LLM: 로컬 환경에서 동작하는 대규모 언어 모델로, 데이터를 외부 서버로 전송하지 않고도 AI 기능을 활용할 수 있다.

Local LLM 선택 이유

  1. 보안
    • 회사의 MR(Merge Request) 검토는 보안 규칙상 외부로 데이터를 전송불가
    • 민감한 소스 데이터를 외부 서버로 전송하지 않고도 작업을 수행 가능.
  2. 비용 절감
    • API 호출 비용을 절감하고 지속 가능한 환경 구축.
  3. 커스터마이징
    • 우리 조직의 니즈에 맞춘 모델로 동작.

3. 자동 코드 리뷰의 필요성

현재 상황

  • MR(Merge Request)는 개발 생산성에 필수적.
  • 그러나 시간과 자원이 한정적이기 때문에 종종 관행적 승인으로 이어지는 경우가 있음.

자동 코드 리뷰로 가능한 작업

  1. 문법 및 구조 검토
  2. 로직 오류 탐지
  3. 리팩토링 제안 검토
  4. 피드백 생성

자동화 가능한 영역은 최소한의 기계적 코드 리뷰로 맡기고, 개발자는 핵심 작업에 집중.


4. 사용 기술 정리

Ollama란?

  • Ollama: OpenAI 출신 개발자가 만든 오픈소스 솔루션으로, 로컬 환경에서 LLM을 쉽게 설치, 실행 및 관리할 수 있도록 지원.

모델 선정 과정

한정된 스펙으로 동작가능한 모델검토 (only cpu )

  • 검토한 모델:
    1. Llama
    2. CodeLlama
    3. Qwen 2.5
  • 최종 선정 모델: Qwen 2.5 (Alibaba 개발)
    • 장점:
      • 자연어 처리 및 코드 리뷰에서 우수한 성능.
      • CPU에서도 원활히 실행 가능.
      • 빠르고 정확한 결과 제공.

5. 구조 설계 및 동작 원리

전체 구조

  1. GitLab Webhook: 이벤트 발생 시 웹서버로 요청 전송.
  2. Webserver: Webhook 요청을 수신하여 Flask로 전달.
  3. Flask: MR 데이터를 수신 및 처리 후 프롬프트 엔지니어링 과정을 거쳐 Ollama API로 전달.
  4. Ollama: 코드 리뷰 결과 생성.
  5. Slack: 리뷰 결과를 알림으로 전달.
GitLab > (Webhook) > Webserver > Flask (MR 수신) > Ollama API > Slack 알림

구조 설계 이유

  • GitLab Webhook은 기본적으로 동일 도메인에서만 동작.
  • 따라서 Webserver를 통해 Flask로 요청을 전달.
  • 프롬프트엔지니어링을 도메인 분리
  • 차후 GPU 서버를 별도로 구축하여 성능 향상을 목표로 설계.

6. 셋팅 가이드

1) GitLab Webhook 설정

  • Webhook URL: Webserver의 엔드포인트.
  • 필요한 데이터:
    • 브랜치
    • 프로젝트 정보

2) Webserver 설정

  • Webserver는 GitLab에서 전달된 데이터를 중계.
  • 필터링된 데이터를 Flask로 전달.

3) Flask 설정

  • Flask를 사용하여 MR 데이터를 처리하고 Ollama API와 통신.
  • Slack으로 결과 반환.

4) Ollama 설치 및 실행


7. 후기 및 개선점

후기

  1. 모델 최적화
    • 프롬프트 작성에 시간이 많이 소요됨.
    • 정확도와 적응성을 높이기 위해 지속적인 튜닝 필요.
  2. 리소스 한계
    • GPU 사용의 필요성을 강하게 느낌.
  3. 권한 문제
    • 방화벽, 슬랙, 서버 권한 등 여러 제약 사항.

앞으로의 계획

  • 회사 코드를 학습시켜 도메인 전문가 AI로 발전.
  • GPU 서버 환경 구축으로 성능 최적화.
  • 프롬프트 최적화를 위한 내부 가이드 제작.

8. 결론

Local LLM을 활용한 AI 코드 리뷰는 보안과 효율성을 모두 잡을 수 있는 도구. 초기 구축 및 운영에는 어려움이 있지만, 지속적인 개선과 튜닝을 통해 개발 생산성을 크게 향상시킬것을 기대해봄.

Mockito.when(dao.get(prdNo)).thenAnswer(new Answer<Entity>() {
    @Override
    public Entity answer(InvocationOnMock invocation) throws Throwable {
        Thread.sleep(10000); // 10 seconds delay
        return new Entity();
    }
});

10초 이후에 답변을 준다. 딜레이 체크 가능

	public KafkaClient(String hosts, String group, String topic) {
        HashMap<String, Object> configs = new HashMap<>();
        configs.put("bootstrap.servers", hosts);
        configs.put("group.id", group);
        configs.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
        configs.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");

        this.producer = new KafkaProducer<>(configs);
        log.debug("create kafka client. ");
        this.gson = new Gson();
    }
    
      public void sendMessage(String data) {
        String jsonMsg = gson.toJson(new Message(data, new Date().getTime()));
        log.debug("sendMessage [{}]", jsonMsg);
        producer.send(new ProducerRecord<>(topic, jsonMsg));
    }

설을 맞아 삼성 240 qhd 모니터 s32bg650 모니터를 구매했다.

32인치 qhd 240hz va (hdr600) 

이 스펙에 50만원대 가격이라 더이상 망설일수가 없었다.

 

설치기사가 오는줄 알았는데, 그냥 박스로 툭 놓고 배송완료되어서 뭔가 했는데 스티로폼이 꼼꼼하니 잘왔다.

기존에 모니터암을 사용하고 있어서 설치하려 하니 아답터가 포함되어 있다. 

뒷판의 LED는 설정에 따라 켤수 있다고 한다.

(나사는 기존 스탠드 나사를 사용해야함)

 

배젤은 얇은편이라 보기는 좋으나 부딪히면 깨질거같으니 조심하자

 

스피커 기능도 포함하고 있는데 생각보다 소리가 깔끔하니 좋다.

스마트 기능은 사용하지 않을거 같긴하지만 리모콘이 동봉되어 편리하다.

 

넓직하고 글씨도 큼직하니 눈이 편안..

 

총평:

va패널도 고급라인은 볼만하다.

고주사율에도에도 hdr600은 밝기가 충분하다

커브드 적응은 한시간도 안걸린다.

기능을 좀더 사용해보자.

'근황' 카테고리의 다른 글

Tech Planet 2016  (0) 2016.10.20
2014 JCO . Java Conference  (0) 2014.02.04
제 13회 한국 자바 개발자 컨퍼런스 (13/02/23)  (0) 2013.02.21
갤넥 젤리빈 GPS 문제  (0) 2012.10.12
신기한글자  (0) 2012.04.03

관리하는 서버가 많고, root권한이 없는경우 바꾸기는 매우 귀찮은 일이다. 

따라서 스크립트를 작성, 공유한다.

** serverlist.txt 에는 서버 ip 목록이 줄별로 있다.

#!/bin/bash
i=1
while read line || [ -n "$line" ] ; do
    echo "$line"
    ((i+=1))
    `/home/customuser/chg.sh $line`
done < serverlist.txt

 

#!/usr/bin/expect

set user_name ""
set old_pwd ""
set new_pwd ""
set ip_addr [lindex $argv 0]


spawn ssh $user_name@$ip_addr
expect $user_name
sleep 3

send "passwd\n"
expect "password:"
send "$old_pwd\r"

expect "New password:"
send "$new_pwd\r"
sleep 1
expect "Retype new password:"
send "$new_pwd\r"
sleep 1

expect "$ "
send "exit\n"

 

'linux' 카테고리의 다른 글

grep 여러 키워드 찾기  (0) 2019.05.09
vi 공백제거 :g/^$/d  (0) 2017.08.09
Mysql DB 덤프 쉘 스크립트 (다수 테이블)  (2) 2016.04.29
bad superblock on /dev/sdb1  (0) 2014.11.19
top 5초마다 프로세스 사용량 파악  (0) 2014.02.11

평소처럼 테스트를 실행하는데 그래들로 실행되어 콘솔로그 등 보기가 힘들때 

 

Project Structure (설정) (Ctrl Alt S) or (CMD ;)으로 들어가 기본 빌드 설정을 변경하면 된다.

 

'OS > Tool' 카테고리의 다른 글

k8s 강의 후기  (0) 2022.10.25
YouTube 검색 목록 묶어서 재생하기  (0) 2013.10.14
VirtualBox  (0) 2012.08.29
Putty  (2) 2012.03.28
Evernote  (0) 2012.03.28
sudo kill -9 `ps -ef | grep {{process_name}} | awk '{print $2}'`

 

 

  1. devops 와 k8s
    • 개발/운영 을 통합. -> MSA가 등장
      • 통 모놀리스 -> 느슨하게 결합되고 컨테이너화된 요소로 구성
    • 전체 생명주기 통합 관리 : 개발/테스트/배포/운영
    • 컨테이너: 지속적인 개발, 통합 배포에 효과적
  2. k8s와 컨테이너
    • k8s : 컨테이너 기반의 가상화 환경을 운영 관리 기술
    • 개발환경을 컨테이너 기반 가상환경으로 구현
    • CICD 개발도구를 결합
    • 빌드/테스트를 용이하게 하여 개발환경 자동화, 운영환경 배포의 기반 마련
  3. k8s와 오브젝트 모델
    • CNCF 쿠버네티스 생태계 및 도구
    • 마스터(컨트롤러), 노드/미니언(컨테이너)
    • 오브젝트 : 상태를 관리하기 위한 대상
    • basic object
      • pod (컨테이너화된 app)
      • service (LB)-label selector로 하나의endpoint 제공, 어떤pod를 서비스로 묶을지 정의
      • volume(저장소)-마운트하여사용(cloud, NFS 등등) pod과 lifecycle이 같음
      • namespace(패키지명) k8s 클러스트 내 논리적인 분리단위, 접근권한, 리소스할당 등을 할 수 있다.
    • controller
      • RC(Replication Controller), RS(Replication Set), DS(DaemonSet), Job, SafefulSet, Deploymenet
    • object 및 기타정보
  4. k8s 클러스트 아키텍쳐
    • 마스터는 설정환경 저장, 전체 클러스터 관리
    • 노드는 pod, container 처럼 k8s위에서 동작하는 워크로드 호스팅
    • 애드온으로 리소스를 관리 클로스트 구현 (DS, deployment)
  5. k8s 운영
    • volume - 데이터 보존, service - pod집합에 접근 기술 api객체
    • k8s : 컨테이너의 상태체크, 재시작, 제외(pod) 등 기능을 제공
  6. k8s 배포
    • 배포전략
      • blue/green
      • canary
      • rolling update
        • 업데이트된 pod으로 점진적으로 교체, 서비스 중단 없이 제공
    • deployment는 replicated 앱을 관리하는 API객체
    • ConfigMap - 공개 데이터를 key-value 값으로 저장하여 사용 , 환경설정 내용을 컨테이너와 분리/제공
  7. k8s 모니터링
    • layer : node, container, app, k8s
    • k8s 대상 : resource,disk,cpu,memory,pod,network
  8. k8s 보안
    • 계정 role : admin, 일반계정
    • network : pod그룹간 통신, 외부네트워크와의 통신 포인트 (end-point)
    • Security Context - pod의 접근제어, 권한, 정책 정의
  9. k8s network
    • k8s 에서 IP는 컨테이너가 아니라 pod 에 할당 된다.
    • CNI (Container Network Interface) 표준 API 제공

'OS > Tool' 카테고리의 다른 글

intellij 에서 테스트가 gradle로 될때  (0) 2022.12.06
YouTube 검색 목록 묶어서 재생하기  (0) 2013.10.14
VirtualBox  (0) 2012.08.29
Putty  (2) 2012.03.28
Evernote  (0) 2012.03.28

@Entity 어노테이션 붙은 클래스 필드명을 따라 컬럼명 매칭룰을 적용

이를 커스텀으로 변경

CamelCaseToUnderscoresNamingStrategy 를 상속받아 uppercase로 변경

yml 에선언

spring.jpa.hibernate:
  naming:
    physical-strategy
public class CustomColumnUppercaseStrategy extends CamelCaseToUnderscoresNamingStrategy {
    @Override
    protected Identifier getIdentifier(String name, final boolean quoted, final JdbcEnvironment jdbcEnvironment) {
        if (isCaseInsensitive(jdbcEnvironment)) {
            name = name.toUpperCase(Locale.ROOT);
        }
        return new Identifier(name, quoted);
    }
}

 

QueryDSL join 및 subquery 및 case 문 사용 예시

case문 사용시 then 값은 enum값이 들지 않으니 String 으로 변환하여 사용한다. (querydsl 5.0)

(로직적으로 처리하자)

QTbEntity innerME = new QTbEntity("ime");
        return queryFactory
                .select(Projections.constructor(TbEntity.class, tbEntity.memberId, tbEntity.roleGroup, joinBEntity.commId, joinBEntity.enumA))
                .from(tbEntity)
                .leftJoin(joinAEntity).on(tbEntity.memberId.eq(joinAEntity.userId))
                .leftJoin(joinBEntity).on(joinAEntity.commId.eq(joinBEntity.commId))
                .where(tbEntity.roleGroup.ne(
                                JPAExpressions.select(new CaseBuilder()
                                                .when(joinBEntity.enumA.eq(EnumA.EQ)).then("EQ_NAME")
                                                .when(joinBEntity.enumA.eq(EnumA.DIFF)).then("DIFF_NAME")
                                                .otherwise(tbEntity.roleGroup)
                                        ).from(innerME)
                                        .leftJoin(joinAEntity).on(innerME.memberId.eq(joinAEntity.userId))
                                        .leftJoin(joinBEntity).on(joinAEntity.commId.eq(joinBEntity.commId))
                                        .where(innerME.memberId.eq(tbEntity.memberId))
                        )
                );

+ Recent posts