code assistant 사용 소감


💻 Claude Code 사용 후기: 성능과 비용 사이의 고민

이번 연휴를 맞이하여 화제의 도구인 Claude Code를 직접 설치하고 사용해 보았습니다. 실제 업무에 적용해 본 결과, 도구 자체의 성능은 기대만큼이나 훌륭했습니다.

“성능은 만족스럽지만, 무시할 수 없는 토큰 소모량 때문에 실제 상용 도구로 계속 활용해야 할지는 의문입니다.”

⚠️ 에이전트형 AI의 현실적인 문턱: 토큰 비용

Claude Code와 같은 에이전트형 시스템을 사용해 보니, 다음과 같은 현실적인 고민이 뒤따랐습니다.

  • 📌 높은 토큰 소모량: 코드 맥락 파악 과정에서 발생하는 비용이 상당합니다.
  • 📌 지속 가능성 문제: 일상적 작업에 매번 고비용을 지불하는 것이 효율적인지 의문입니다.
  • 📌 sLLM의 필요성: 반복 작업에는 가벼운 모델을 쓰는 경제적 에이전트가 절실합니다.

Claude api

“Claude API는 주피터 노트북을 입력받아 파이썬 코드로 자동 변환하고 분석하는 성능이 탁월합니다. 하지만 무료 버전에서는 입력 데이터가 일정 길이를 초과할 경우 API 호출이 제한되어 진행이 중단됩니다. 이를 해결하려면 세션을 새로 시작하거나 유료 결제를 해야 하지만, 일일 제한 수치가 다음 날이면 리셋되므로 여유 있게 기다리며 사용하기에 나쁘지 않습니다.”


자체 구축

최근 Claude Code나 Cursor 같은 유료 도구가 유행이지만, 내 컴퓨터의 자원을 활용해 개인용 코드 어시스턴트를 구축하는 것은 보안과 비용 측면에서 엄청난 메리트가 있습니다. 직접 사용해 보며 느낀 장단점을 가감 없이 공유합니다.

1. 시스템 구성 (My Setup)

  • GPU: NVIDIA RTX 3060 Ti (VRAM 8GB)
  • RAM: DDR4/D5 32GB
  • SW: Docker + Ollama + Aider
  • Model: Qwen2.5-Coder (7B / 14B / 32B 양자화 버전)

2. 사용자 입장에서 본 장점 (Pros)

  • 비용 제로(Zero Cost): API 사용료 걱정이 없습니다. Claude 3.5 Sonnet처럼 쓰다 보면 금방 소진되는 크레딧 리셋을 기다릴 필요 없이 24시간 무제한으로 질문할 수 있습니다.
  • 데이터 보안: 코드가 외부 서버로 전송되지 않습니다. 사내 보안 규정이 까다로운 프로젝트나 개인적인 아이디어를 다룰 때 심리적 안정감이 큽니다.
  • Aider와의 환상적인 궁합: 단순 채팅이 아니라 Aider가 직접 내 파일을 읽고, 수정하고, diff 형태로 코드를 제안합니다. 터미널 기반이라 개발 흐름이 끊기지 않습니다.
  • 시스템 램(32GB)의 활용성: 8GB VRAM이라는 한계를 32GB 시스템 램이 보완해 줍니다. 덕분에 원래는 돌아가지 않을 32B 같은 대형 모델도 ‘느리지만 똑똑하게’ 구동할 수 있습니다.

3. 직접 겪어본 단점 및 한계 (Cons)

  • 모델 체급별 딜레마 (7B vs 14B vs 32B):
    • 7B: 매우 빠르지만, 연속 질문을 던지면 맥락을 놓치고 엉뚱한 답을 합니다. “저번에 말한 거 수정해줘” 같은 말을 잘 못 알아듣습니다. -> 항상 /clear로 초기화를 해야 함!!
    • 32B: 매우 똑똑하지만, 시스템 램을 쓰기 때문에 응답 속도가 초당 2~3토큰 수준으로 느립니다. (매우 매우 많은 인내심이 필요합니다.)
  • 메모리 관리의 까다로움: 32GB 램도 넉넉해 보이지만, 32B 모델을 올리면 시스템 가용 메모리가 14~15GB 미만일 경우 실행조차 안 되는 ‘메모리 부족(OOM)’ 에러가 발생합니다. 크롬 탭을 끄는 등 관리가 필요합니다.
  • 초기 설정 진입 장벽: Docker 설정, GPU 드라이버 연결, 모델 다운로드(19GB 등) 과정이 초보자에게는 다소 복잡할 수 있습니다.

4. 실전 운영 꿀팁 (Tips)

  1. 메모리 가성비는 ’14B’ 모델: RTX 3060 Ti 유저에게는 Qwen2.5-Coder 14B가 최고의 선택입니다. 7B보다 훨씬 똑똑하고, 32B보다 훨씬 빠릅니다. (VRAM 8GB에 거의 다 들어갑니다.) 이건 안해봐서 모름
  2. Aider 세션 관리: 모델이 헛소리를 하기 시작하면 /clear로 대화 히스토리를 비워주세요. 모델의 집중력이 다시 살아납니다.
  3. 양자화 모델 활용: 반드시 q4_K_M 같은 양자화 버전을 쓰세요. 지능 손실은 최소화하면서 메모리 점유율을 절반 가까이 줄여줍니다.

5. 한 줄 요약

“RTX 3060 Ti와 32GB 램만 있다면, 약간의 매우 많은 인내심을 더해 나만의 강력하고 비밀스러운 수석 개발자를 무료로 고용할 수 있다.”


Claude code

“Claude Code는 여러 파일에 직접 접근하여 정보를 조회하고, 수정하며, 결론까지 도출해 주는 능력이 매우 뛰어납니다. 하지만 그만큼 토큰 소모 속도가 굉장히 빠르다는 것이 체감됩니다. 특히 무료 크레딧의 경우 시간이 지나도 자동으로 초기화되지 않아 사실상 일회성에 가깝다는 점이 아쉽습니다. 물론 비용을 투자한 만큼 코딩 실력은 확실히 보장되는 것 같지만, 실무에서 본격적으로 쓰기 위해 얼마만큼의 예산을 들여야 할지는 신중한 판단이 필요해 보입니다.

https://research.nvidia.com/labs/lpr/slm-agents

거대 언어 모델(LLM)은 광범위한 작업에서 인간에 가까운 성능을 발휘하고 일반적인 대화를 수행하는 능력으로 많은 찬사를 받아왔습니다. 그러나 ‘에이전트형 AI(Agentic AI)’ 시스템이 부상하면서, 언어 모델이 소수의 특화된 작업을 반복적이고 일관되게 수행하는 애플리케이션들이 대거 등장하고 있습니다. 우리는 **소형 언어 모델(SLM)**이 에이전트 시스템의 수많은 실행 과정에서 충분한 성능을 발휘하며, 본질적으로 더 적합할 뿐만 아니라 경제적 관점에서도 반드시 필요하다는 입장을 밝힙니다. 따라서 SLM이야말로 에이전트형 AI의 미래라고 확신합니다. 우리의 논거는 현재 SLM이 보여주는 역량 수준, 에이전트 시스템의 일반적인 아키텍처, 그리고 언어 모델 배포의 경제성에 기반하고 있습니다. 더 나아가, 범용적인 대화 능력이 필수적인 상황에서는 서로 다른 모델들을 호출하여 사용하는 **이종 에이전트 시스템(Heterogeneous Agentic Systems)**이 자연스러운 선택이 될 것이라고 주장합니다. 또한, 에이전트 시스템에서 SLM 도입을 가로막는 잠재적 장벽들에 대해 논의하며, 기존의 LLM 기반 에이전트를 SLM 기반으로 전환하기 위한 일반적인 알고리즘도 함께 제시합니다. 가치 선언문의 형태로 작성된 우리의 이러한 견해는, LLM에서 SLM으로의 부분적인 전환만으로도 AI 에이전트 산업에 미칠 운영적·경제적 파급력이 상당함을 시사합니다. 우리는 AI 자원의 효율적 활용에 관한 논의를 촉진하고, 오늘날 AI 서비스 비용을 낮추려는 노력을 진전시키고자 합니다. 우리의 입장에 대한 기여와 비판 모두를 환영하며, 관련하여 접수되는 모든 서신은 본 웹사이트에 공개할 것을 약속드립니다.”

🚀 거대 AI의 시대에서 ‘작고 영리한’ sLLM의 시대로

현재 AI 하드웨어와 전력 인프라에 투입되는 천문학적인 투자 규모를 고려할 때, 과연 일반 개인이 그 혜택을 온전히 누릴 수 있을지는 미지수입니다. 막대한 유지 비용은 결국 사용자 부담으로 돌아올 수밖에 없기 때문입니다.

“우리에게 지금 필요한 것은 모든 것을 아는 거창한 모델이 아닙니다. 당장의 필요를 해결하기 위해 적은 비용으로 편하게 사용할 수 있는 ‘실용적인 모델’이 더 절실합니다.

✅ 왜 sLLM(소형 언어 모델)이 대안인가?

최근 에이전트형 AI(Agentic AI) 시스템은 범용적인 대화보다 소수의 특화된 작업을 정교하게 수행하는 방향으로 진화하고 있습니다. 이러한 흐름 속에서 sLLM은 다음과 같은 명확한 강점을 가집니다.

  • 💰 경제적 접근성: 거대 인프라 없이도 개인이 감당할 수 있는 낮은 비용으로 모델을 구동할 수 있어, AI의 문턱을 낮춥니다.
  • 🎯 실용적 최적화: 모든 분야를 얕게 아는 LLM보다 특정 업무를 전문적으로 수행하는 특화 모델이 개인의 실무에는 훨씬 효율적입니다.
  • 🌱 지속 가능성: 불필요한 연산을 줄임으로써 막대한 전력 소모를 방지하고, 환경적·경제적 지속 가능성을 확보합니다.

결국 미래의 AI 생태계는 거대 모델 하나가 모든 것을 독점하는 구조가 아닐 것입니다. 대신 **다양한 소형 모델들이 유기적으로 결합하여 문제를 해결하는 ‘이종 에이전트 시스템’**이 그 자리를 채울 것입니다. 이제는 기술의 화려함보다, 우리 손에 닿는 실질적인 혜택에 집중해야 할 때입니다.

Foundation of algorithms, p265

def n_queens(i, col):
    n = len(col) -1
    
    if (promising(i, col)):
        if( i == n):
            print(col[1:n+1])
        else:
            for j in range(1, n+1):
                col [i+1] = j
                n_queens(i+1, col) 
                
                
def promising(i, col):
    k = 1
    flag = True
    while(k < i and flag):
        if (col[i] == col[k] or abs(col[i]-col[k]) == (i-k)):
            flag = False
        k += 1
    return flag
n=4
col = [0]*(n+1)
n_queens(0, col)

[2, 4, 1, 3] [3, 1, 4, 2]

ros2 moveit TF 표시

moveit_setup_assistant를 사용하면 대상이 되는 package에서 urdf를 추출한 다음, 필요한 설정 파일을 만든 후 package+moveit_config 디렉토리에 생성한 파일을 저장한다. lanch 디렉토리에 demo.launch.py 파일이 있는데, 코드에는 별 내용은 없고, 같은 디렉토리 launch 파일들을 실행한다. 최소한 어느 부분을 실행해야 rviz에서 로봇이 제대로 보일지 궁금했다

demo.launch.py 파일이 다음을 실행한다.

  • static_virtual_joint_tfs
  • robot_state_publisher
  • move_group
  • rviz
  • ros2_contol_node + controller spawners

robot_state_publisher만 실행하면 로봇이 정확하게 보일 줄 알았다. robot_state_publisher가 입력으로 robot_description을 받아들이고, TF는 robot_description에 있는 링크, 조인트 관계만 읽어들여 알아낼 줄 알았다. move_group은 path를 찾을 때 사용하므로 당장 필요해 보이지 않았다.

from launch import LaunchDescription
from moveit_configs_utils import MoveItConfigsBuilder
from launch_ros.actions import Node
from moveit_configs_utils.launches import generate_rsp_launch, generate_moveit_rviz_launch
from launch.actions import (
        DeclareLaunchArgument,
        IncludeLaunchDescription,
        )
from launch.substitutions import LaunchConfiguration
import os
from ament_index_python.packages import get_package_share_directory
from launch.launch_description_sources import PythonLaunchDescriptionSource


def generate_launch_description():
    moveit_config = MoveItConfigsBuilder("abb_irb2400", package_name="hello_moveit_config").to_moveit_configs()
    #dict2 = moveit_config.to_dict()
    #for key, val in (dict2.items()):
    #    print(key, ":", val) 
    ld = LaunchDescription()
    ld.add_action(DeclareLaunchArgument("publish_frequency", default_value="15.0"))

    rsp_node = Node(
            name = "rsp_node",
            executable = "robot_state_publisher",
            #prefix = "xterm -e gdb run --args",
            package = "robot_state_publisher",
            output = "both",
            respawn = True,
            #namespace = 'my_robot',
            parameters=[
                moveit_config.robot_description,
                {
                    "publish_frequency": LaunchConfiguration("publish_frequency"),
                    },
                #moveit_config.robot_description_semantic,
                #moveit_config.robot_description_kinematics,
                ],
            )
    ld.add_action(rsp_node)
    return ld

launch를 실행하면 tf가 제대로 표시되지 않는다. tf_static은 정확하게 표시된다.

root@rygen3600:/home/ros2_test/ws_root/ws_user# ros2 topic list 
/attached_collision_object
/clicked_point
/display_planned_path
/goal_pose
/initialpose
/joint_states
/parameter_events
/planning_scene
/planning_scene_world
/recognized_object_array
/robot_description
/rosout
/rviz_moveit_motion_planning_display/robot_interaction_interactive_marker_topic/feedback
/rviz_moveit_motion_planning_display/robot_interaction_interactive_marker_topic/update
/tf
/tf_static
/trajectory_execution_event
/visualization_marker_array
root@rygen3600:/home/ros2_test/ws_root/ws_user# ros2 topic echo /tf


^Croot@rygen3600:/home/ros2_test/ws_root/ws_user# ros2 topic echo /tf_static 
transforms:
- header:
    stamp:
      sec: 1691830604
      nanosec: 3856748
    frame_id: base_link
  child_frame_id: base
  transform:
    translation:
      x: 0.0
      y: 0.0
      z: 0.0
    rotation:
      x: 0.0
      y: 0.0
      z: 0.0
      w: 1.0
- header:
    stamp:
      sec: 1691830604
      nanosec: 3856748
    frame_id: link_6
  child_frame_id: tool0
  transform:
    translation:
      x: 0.0
      y: 0.0
      z: 0.0
    rotation:
      x: 0.0
      y: 0.0
      z: 0.0
      w: 1.0
---

왜 이런지 한참 고민하다, 결국 control node와 controller spawner가 실행되어야 TF가 제대로 표시됨을 알았다.

root@rygen3600:/home/ros2_test/ws_root/ws_user# ros2 topic echo /tf
...
- header:
    stamp:
      sec: 1691830991
      nanosec: 709634293
    frame_id: base_link
  child_frame_id: link_1
  transform:
    translation:
      x: 0.0
      y: 0.0
      z: 0.0
    rotation:
      x: 0.0
      y: 0.0
      z: 0.0
      w: 1.0
- header:
    stamp:
      sec: 1691830991
      nanosec: 709634293
    frame_id: link_1
  child_frame_id: link_2
  transform:
    translation:
      x: 0.1
      y: 0.0
      z: 0.615
    rotation:
      x: 0.0
      y: 0.0
      z: 0.0
      w: 1.0
- header:
    stamp:
      sec: 1691830991
      nanosec: 709634293
    frame_id: link_2
  child_frame_id: link_3
  transform:
    translation:
      x: 0.0
      y: 0.0
      z: 0.705
    rotation:
      x: 0.0
      y: 0.0
      z: 0.0
      w: 1.0

최소 2개 node가 필요하다. robot_state_publisher와 controller node.이거 알아낸다고 별 짓을 다했다. 다수 로봇을 처리하려면 namespace로 할당하여 불러야 할텐데, 잘 안된다.

rviz 12.7 update 실패->성공

osrf/ros:humble-desktop 도커 이미지를 설치하면 rviz 12.6가 설치된다. 가끔 node를 만들어 robot_description을 입력하면, rviz2가 제대로 표시 안할 경우가 있다. moveit_setup_assistant도 기존 설정 파일을 수정하면 robot_model_loader가 실행되지 않을 경우도 있다. 아마 12.6 버전의 문제인 듯 하여 버전을 올려 보기로 했다. 최신 버전은 12.8인데, humble이 사용할 수 있는 가장 최근 버전은 12.7이다. 12.8을 사용하면 display panel이 안보이는 듯 안정적으로 동작하지 않는다.

now0930@rygen3600:~/ros2/test/ws_root/ws_user$ git clone -b humble https://github.com/ros2/rviz.git
'rviz'에 복제합니다...
remote: Enumerating objects: 30445, done.
remote: Counting objects: 100% (4756/4756), done.
remote: Compressing objects: 100% (1181/1181), done.
remote: Total 30445 (delta 3857), reused 4031 (delta 3399), pack-reused 25689
오브젝트를 받는 중: 100% (30445/30445), 16.45 MiB | 16.27 MiB/s, 완료.
델타를 알아내는 중: 100% (22231/22231), 완료.
now0930@rygen3600:~/ros2/test/ws_root/ws_user$ cd rviz/
now0930@rygen3600:~/ros2/test/ws_root/ws_user/rviz$ git checkout 
브랜치가 'origin/humble'에 맞게 업데이트된 상태입니다.

branch를 선택하지 않고, default 값으로 humble에서 12.8을 컴파일 하고 있었다. 잘 동작되지 않아 2일을 날렸다. work space 구조도 각 패키지에 맞도록 세부적으로 나누어야 한다. 섞이면 컴파일 양도 많고, 각 패키지별로 옵션을 설정할 수 없다. workspace에 대한 내용은 여기에 있다. overlay, underlay를 정확하게 이해하지 않고 가 시간 날렸다.

rviz2 readme를 따라 complie 한다. 컴파일 중 ignition_math6_vendor가 없어 에러로 멈춘다.

CMake Error at CMakeLists.txt:64 (find_package):
  By not providing "Findignition_math6_vendor.cmake" in CMAKE_MODULE_PATH
  this project has asked CMake to find a package configuration file provided
  by "ignition_math6_vendor", but CMake did not find one.

  Could not find a package configuration file provided by
  "ignition_math6_vendor" with any of the following names:

    ignition_math6_vendorConfig.cmake
    ignition_math6_vendor-config.cmake

  Add the installation prefix of "ignition_math6_vendor" to CMAKE_PREFIX_PATH
  or set "ignition_math6_vendor_DIR" to a directory containing one of the
  above files.  If "ignition_math6_vendor" provides a separate development
  package or SDK, be sure it has been installed.

apt-cache로 ros-humble-ignition-math6-vendor를 검색하면, 해당 패키지가 설치되어 있다. dpkg로 어떤 파일들이 있는지 보면, 실재 파일은 없는 듯 하다.

root@rygen3600:/home/ros2_test# dpkg -L ros-humble-ignition-math6-vendor
/.
/opt
/opt/ros
/opt/ros/humble
/opt/ros/humble/share
/opt/ros/humble/share/ignition_math6_vendor
/opt/ros/humble/share/ignition_math6_vendor/package.xml
/usr
/usr/share
/usr/share/doc
/usr/share/doc/ros-humble-ignition-math6-vendor
/usr/share/doc/ros-humble-ignition-math6-vendor/changelog.Debian.gz
/usr/share/doc/ros-humble-ignition-math6-vendor/copyright
root@rygen3600:/home/ros2_test# 

ROS Index를 찾아보면 rviz2 github를 찾을 수 있는데, 이를 rviz에 있는 디렉토리에 받아주면 된다. ignition-math6-vendor가 gz_math6_vendor로 바뀐 느낌이다. CMakefile을 보면 project로 ignition_math6_vendor로 자기를 명명한다.

oot@rygen3600:/home/ros2_test/rviz# ls -alh
total 92K
drwxrwxr-x 17 1000 1000 4.0K Aug  8 21:43 .
drwxrwxr-x  7 1000 1000 4.0K Aug  6 20:45 ..
drwxrwxr-x  8 1000 1000 4.0K Aug  6 20:45 .git
drwxrwxr-x  3 1000 1000 4.0K Aug  6 20:45 .github
-rw-rw-r--  1 1000 1000   55 Aug  6 20:45 .gitignore
-rw-rw-r--  1 1000 1000   84 Aug  6 20:45 CODEOWNERS
-rw-rw-r--  1 1000 1000 1.7K Aug  6 20:45 LICENSE
-rw-rw-r--  1 1000 1000 8.2K Aug  6 20:45 README.md
drwxr-xr-x 11 root root 4.0K Aug  8 21:49 build
drwxrwxr-x  2 1000 1000 4.0K Aug  6 20:45 docs
drwxrwxr-x  5 1000 1000 4.0K Aug  8 21:43 gz_math6_vendor
drwxr-xr-x  7 root root 4.0K Aug  8 21:49 install
drwxr-xr-x 10 root root 4.0K Aug  8 21:44 log
drwxrwxr-x  6 1000 1000 4.0K Aug  6 20:45 rviz2
drwxrwxr-x  3 1000 1000 4.0K Aug  6 20:45 rviz_assimp_vendor
drwxrwxr-x  8 1000 1000 4.0K Aug  6 20:45 rviz_common
drwxrwxr-x  6 1000 1000 4.0K Aug  8 21:53 rviz_default_plugins
drwxrwxr-x  3 1000 1000 4.0K Aug  6 20:45 rviz_ogre_vendor
drwxrwxr-x  6 1000 1000 4.0K Aug  6 20:45 rviz_rendering
drwxrwxr-x  4 1000 1000 4.0K Aug  6 20:45 rviz_rendering_tests
drwxrwxr-x  7 1000 1000 4.0K Aug  8 20:54 rviz_visual_testing_framework
root@rygen3600:/home/ros2_test/rviz# 
root@rygen3600:/home/ros2_test/rviz# cd gz_math6_vendor/
root@rygen3600:/home/ros2_test/rviz/gz_math6_vendor# ls
CHANGELOG.rst	CONTRIBUTING.md  package.xml
CMakeLists.txt	LICENSE		 patches
root@rygen3600:/home/ros2_test/rviz/gz_math6_vendor# cat CMakeLists.txt 
cmake_minimum_required(VERSION 3.10)
project(ignition_math6_vendor)

find_package(ament_cmake_core REQUIRED)
find_package(ament_cmake_vendor_package REQUIRED)

find_package(ignition-math6 6.9.2 QUIET)

ament_vendor(ignition_math6_vendor
  SATISFIED ${ignition-math6_FOUND}
  VCS_URL https://github.com/ignitionrobotics/ign-math.git
  VCS_VERSION ignition-math6_6.9.2
  PATCHES patches
  CMAKE_ARGS
    -DBUILD_DOCS:BOOL=OFF
  GLOBAL_HOOK
)

find_package(ament_cmake_test REQUIRED)
if(BUILD_TESTING)
  find_package(ament_cmake_lint_cmake REQUIRED)
  find_package(ament_cmake_copyright REQUIRED)
  find_package(ament_cmake_xmllint REQUIRED)

  ament_lint_cmake()
  ament_copyright()
  ament_xmllint()
endif()

ament_package()