3P by GN⁺ | ★ favorite | 댓글 1개
  • LLM 0.26은 CLI와 Python 라이브러리에서 OpenAI, Anthropic, Gemini, Ollama 로컬 모델에 Python 함수로 만든 도구를 연결할 수 있게 한 큰 릴리스임
  • 도구는 플러그인으로 설치해 --tool/-T name_of_tool로 불러오거나, --functions임시 Python 함수를 명령줄에서 바로 넘겨 사용할 수 있음
  • 내장 도구 llm_version, llm_time뿐 아니라 simpleeval, QuickJS, SQLite, Datasette 플러그인이 제공되며, 모델은 실패한 호출 뒤 스키마 조회나 다른 표현식으로 재시도할 수 있음
  • Python API의 새 model.chain()은 도구 호출 요청을 감지해 실행하고 결과를 다시 모델에 전달하며, 동기 함수와 asyncio 도구를 모두 지원함
  • 여러 벤더의 도구 사용·함수 호출 방식이 수렴하면서 구현이 가능해졌고, 다음 과제는 플러그인 확장, 더 많은 모델 플러그인 지원, Model Context Protocol 클라이언트 지원임

LLM 0.26의 도구 실행 지원

  • LLM 0.26은 프로젝트 시작 이후 가장 큰 기능으로 도구 지원을 추가함
  • LLM CLIPython 라이브러리에서 OpenAI, Anthropic, Gemini, Ollama 로컬 모델에 Python 함수로 표현 가능한 도구 접근 권한을 줄 수 있음
  • 도구 플러그인을 설치하면 현재 사용하는 모델에 새 기능을 붙일 수 있음
  • 핵심 사용 방식은 네 가지임
    • 플러그인 도구를 설치하고 --tool/-T name_of_tool로 로드함
    • --functions 옵션으로 Python 함수 코드를 명령줄에 직접 전달함
    • Python API에서도 tools=[locals] 같은 방식으로 도구를 넘길 수 있음
    • 도구는 비동기와 동기 컨텍스트 모두에서 동작함

CLI에서 도구 실행하기

  • 최신 LLM은 uv tool install llm로 설치하고, 기존 설치는 uv tool upgrade llm로 업그레이드할 수 있음
  • OpenAI 사용 예시는 llm keys set openai로 API 키를 설정한 뒤 다음처럼 실행함
llm --tool llm_version "What version?" --td
  • llm_version은 LLM에 포함된 간단한 데모 도구이며, --tool llm_version은 해당 도구를 모델에 노출함
  • --tool은 여러 번 지정할 수 있고, 짧은 옵션 -T도 사용할 수 있음
  • --td--tools-debug의 약자로, 도구 호출과 응답 정보를 출력해 내부 동작을 확인하게 해줌
  • 기본 모델은 보통 gpt-4o-mini이며, 예시에서는 llm models default gpt-4.1-minigpt-4.1-mini를 기본값으로 바꿈
  • -m 옵션으로 다른 모델을 지정할 수 있으며, o4-mini와 내장 llm_time 도구를 함께 실행하는 예시도 있음
llm --tool llm_time "What time is it?" --td -m o4-mini
  • llm_time 도구 응답에는 utc_time, utc_time_iso, local_timezone, local_time, timezone_offset, is_dst 같은 필드가 포함됨

여러 모델과 플러그인에서의 동작

  • 도구를 지원하는 모델 플러그인에서도 같은 명령 패턴을 사용할 수 있음
  • Anthropic Claude Sonnet 4 예시는 다음 흐름을 사용함
    • llm install llm-anthropic -U
    • llm keys set anthropic
    • llm --tool llm_version "What version?" --td -m claude-4-sonnet
  • Google Gemini 2.5 Flash 예시는 다음 흐름을 사용함
    • llm install llm-gemini -U
    • llm keys set gemini
    • llm --tool llm_version "What version?" --td -m gemini-2.5-flash-preview-05-20
  • Ollama로 실행하는 qwen3:4b도 간단한 도구를 실행할 수 있음
    • qwen3:4b는 2.6GB 크기의 작은 모델임
    • ollama pull qwen3:4b
    • llm install 'llm-ollama>=0.11a0'
    • llm --tool llm_version "What version?" --td -m qwen3:4b

수학, JavaScript, SQLite, Datasette 도구 플러그인

  • LLM이 약한 큰 숫자 곱셈 같은 작업은 도구 호출로 보완할 수 있음
  • llm-tools-simpleeval은 Daniel Fairhead의 simpleeval 라이브러리를 노출함
    • simpleeval은 “Simple Safe Sandboxed Extensible Expression Evaluator for Python” 라이브러리임
    • 간단한 Python 표현식을 실행하기 위한 충분히 견고한 샌드박스를 제공함
  • 계산 예시는 다음처럼 실행함
llm install llm-tools-simpleeval
llm -T simple_eval 'Calculate 1234 * 4346 / 32414 and square root it' --td
  • 예시 실행에서 모델은 먼저 1234 * 4346 / 32414를 계산해 165.45208860368976을 얻고, sqrt(...)가 정의되지 않아 실패한 뒤 ** 0.5로 바꿔 12.862818066181678을 얻음
  • 공개된 도구 플러그인은 네 가지임

Datasette 툴박스와 오류 후 재시도

  • Datasette 플러그인은 내부에 여러 도구를 가진 툴박스 형태로 동작함
    • 툴박스는 생성자로 구성할 수 있는 플러그인임
  • 사용 예시는 다음과 같음
llm install llm-tools-datasette
llm -T 'Datasette("https://datasette.io/content";)' --td "What has the most stars?"
  • Datasette("https://datasette.io/content";)는 플러그인에 사용할 Datasette 인스턴스 URL을 전달함
  • 이 예시는 Datasette 웹사이트를 구동하는 content database를 대상으로 함
  • 모델은 세 번의 호출을 수행함
    • 처음에는 SELECT name, stars FROM repos ORDER BY stars DESC LIMIT 1를 추측했지만 stars 컬럼이 없어 실패함
    • 오류를 받은 뒤 Datasette_schema() 도구로 데이터베이스 스키마를 조회함
    • 스키마를 바탕으로 올바른 쿼리를 조립하고 실행함
  • 최종 응답에 따르면 별이 가장 많은 저장소는 datasette이며 10,020 stars를 가지고 있음

--functions로 임시 도구 만들기

  • --functions 옵션은 플러그인보다 덜 구조화된 임시 도구 사용 방식을 제공함
  • 명령줄에 Python 코드 블록을 직접 넘기면, 그 안에 정의된 함수들이 모델이 사용할 도구가 됨
  • 블로그 검색 도구 예시는 다음처럼 httpx로 검색 페이지를 호출하고 HTML을 그대로 모델에 반환함
llm --functions '
import httpx

def search_blog(q):
    "Search Simon Willison blog"
    return httpx.get("https://simonwillison.net/search/";, params={"q": q}).content
' --td 'Three features of sqlite-utils' -s 'use Simon search'
  • 구현은 검색 페이지 HTML을 그대로 되돌려주는 방식이지만 동작함
  • GPT-4.1 계열이 100만 토큰을 처리하므로 거친 HTML도 감당할 수 있다고 봄
  • 시스템 프롬프트에 use Simon search를 추가해야 모델이 스스로 답하지 않고 제공된 검색 도구를 사용함
  • 더 나은 검색 도구에는 더 상세한 지침과 검색 결과의 관련 스니펫이 필요함
  • 예시 결과에서 sqlite-utils 기능으로 CLI와 Python 라이브러리 결합, alter=True를 통한 컬럼 자동 추가, 플러그인 지원이 나옴

Python API의 도구 지원

  • LLM은 CLI 도구이면서 Python 라이브러리이며, 0.26에서 Python API에도 도구 지원이 추가됨
  • 예시는 “strawberry” 안의 r 개수를 세는 문제를 함수 도구로 해결함
import llm

def count_char_in_text(char: str, text: str) -> int:
    "How many times does char appear in text?"
    return text.count(char)

model = llm.get_model("gpt-4.1-mini")
chain_response = model.chain(
    "Rs in strawberry?",
    tools=[count_char_in_text],
    after_call=print
)
for chunk in chain_response:
    print(chunk, end="", flush=True)
  • after_call=print는 앞서의 --td 옵션처럼 도구 호출을 확인하는 방법임
  • model.chain() 메서드는 model.prompt()와 비슷하지만, 반환된 도구 호출 요청을 감지하고 실행한 뒤 결과와 함께 다시 모델을 호출함
  • model.chain()은 최종 답을 주기 전까지 여러 응답을 실행할 수 있음
  • chain_response를 순회하면 여러 응답에 걸쳐 반환되는 토큰을 스트리밍 출력할 수 있음
  • 예시 결과에서는 count_char_in_text 도구가 char='r', text='strawberry'로 호출되고, 결과 3을 바탕으로 strawberryr이 3개 있다고 답함
  • Python 라이브러리는 asyncio도 지원하며, 도구는 async def 함수가 될 수 있음
  • 모델이 여러 비동기 도구를 한 번에 요청하면 라이브러리는 asyncio.gather()로 동시에 실행함
  • 툴박스도 지원되어 tools=[Datasette("https://datasette.io/content";)]chain()에 넘기면 CLI의 --tool 'Datasette(...)'와 같은 효과를 냄

구현 배경과 도구 사용 패턴

  • 도구 사용 패턴은 2022년 10월 처음 공개된 ReAcT paper에서 본 뒤 추적해 온 방식임
  • 기본 패턴은 단순함
    • 모델에 사용할 수 있는 도구가 있다고 알려줌
    • 모델이 JSON, XML, tool_name(arguments) 같은 특수 문법으로 도구 동작을 요청하고 멈춤
    • 코드가 그 출력을 파싱해 요청된 도구를 실행함
    • 실행 결과를 포함해 새 프롬프트를 모델에 보냄
  • 이 방식은 현재 거의 모든 모델에서 동작함
  • 많은 모델은 도구 사용을 위해 별도 학습되어 있으며, Berkeley Function-Calling Leaderboard 같은 리더보드도 있음
  • OpenAI, Anthropic, Google, Mistral, Meta는 API에 도구 사용 또는 함수 호출 기능을 포함하고 있음
  • 로컬 모델 쪽에서도 Ollama는 작년에 도구 지원을 추가했고, llama.cpp 서버에도 포함되어 있음
  • LLM은 2025년 2월 스키마 지원을 먼저 릴리스했고, 이를 도구 지원을 향한 단계로 삼음
  • 여러 모델에서 동작하는 추상화 계층 설계가 과제였으며, 벤더들의 방식이 뚜렷하게 수렴한 현재 구현할 수 있게 됨
  • PyCon US의 Building software on top of Large Language Models 워크숍이 알파 구현을 마무리하는 계기가 됐고, 튜토리얼의 tools section도 제공됨

에이전트와 다음 계획

  • “agents”라는 용어에는 여전히 거부감이 있지만, LLM 세계에서는 tools in a loop로 수렴하고 있으며 LLM 0.26도 그 형태에 가까움
  • 에이전트를 만들고 싶다면 LLM 0.26이 좋은 출발점이 될 수 있음
  • 다음 작업은 LLM tools v2 milestone에 13개 이슈로 정리되어 있음
    • 주로 도구 실행 로그 표시 개선과 이번 릴리스를 막지 않은 작은 이슈들임
    • 추가 이슈는 tools label에 있음
  • 플러그인 가능성이 가장 기대되는 영역임
    • llm-plugin-tools cookiecutter 템플릿을 직접 사용하고 있음
    • 관련 튜토리얼을 만들 계획임
  • 더 많은 모델 플러그인에 도구 지원을 추가하는 작업도 남아 있음
  • Model Context Protocol 지원도 계획에 포함됨
    • MCP는 모델이 도구에 접근하는 표준 방식으로 빠르게 부상 중임
    • 2주 전에는 주요 벤더 API에서 직접 지원되지 않았지만, 최근 8일 사이 OpenAI, Anthropic, Mistral에 추가됨
    • LLM이 MCP 클라이언트로 동작해 사람들이 작성하는 MCP 서버를 LLM의 추가 도구 소스로 쉽게 사용할 수 있게 하는 것이 목표임

댓글과 토론

Hacker News 의견들
  • 이 도구를 위해 작성한 스트리밍 Markdown 렌더러도 볼 만함: https://github.com/day50-dev/Streamdown
    배경은 https://github.com/simonw/llm/issues/12에 있고, Simon의 llm 위에 만든 tmux 도구가 들어 있는 https://github.com/day50-dev/llmehelp도 매일 쓰고 있음

    • llm 위에 만든 걸 하나 더 빠뜨렸는데, ZSH 플러그인으로 zle을 써서 키 한 번에 영어를 셸 명령으로 바꿔줌: https://github.com/day50-dev/Zummoner
      오늘도 $ git find out if abcdefg is a descendent of hijklmnop 같은 식으로 썼고, 다른 댓글의 for i in $(seq 1 6); do printf "%${i}sh${i}\n\n-----\n" | tr " " "#"; done | pv -bqL 30도 원래는 훨씬 자연어에 가까운 입력이었음
      ctrl-x x를 누르면 버퍼가 OpenRouter로 보내지고 1초도 안 돼 올바른 문법으로 교체됨
    • 라이브러리가 정말 좋아 보이고, 플러그인이 도구의 콘텐츠 표시 방식을 가져갈 수 있는 훅이 있으면 좋겠음
      이슈를 열어둠: https://github.com/simonw/llm/issues/1112
      설계 선택지를 몇 개 넣었지만 아직 완전히 맞는 느낌은 아니라 피드백을 받고 싶음
    • 스트리밍 LLM 출력을 빠르게 표시하려고 여러 언어로 스트리밍 Markdown 렌더러를 직접 만든 적이 있는데, 나만 그런 게 아니라 반가움
    • 흥미로워서 확인해볼 예정이고, 지금은 llmbat문법 강조를 함께 쓰고 있음
  • 이건 발등 찍기 위험을 크게 키움
    문서 https://llm.datasette.io/en/stable/tools.html는 프롬프트 주입을 경고하지만, 더 그럴듯한 시나리오는 스스로 저지르는 피해라고 봄
    예를 들어 증권 계좌 접근 권한을 도구에 줘서 거래를 자동화하면, 프롬프트 주입이 없어도 봇이 어리석은 거래를 하지 못하게 막을 장치가 없음

    • 맞음, 정말로 위험이 커짐
      LLM에 도구를 붙이기 시작하면, 특히 그 도구 호출이 인증되어 있고 대신 행동까지 할 수 있다면 일이 틀어질 경로가 너무 많음
      MCP 쪽이 지금 이걸 초고속으로 겪고 있고, 어제 GitHub MCP 건도 그 예임: https://news.ycombinator.com/item?id=44097390
      문서에 큰 경고를 넣었고, 초기 도구 플러그인도 피해를 줄 수 없는 것만 내려고 조심했음. 그래서 QuickJS 샌드박스와 SQLite 플러그인도 읽기 전용임
    • llm을 증권 계좌에 연결한다면 멍청한 건 봇이 아니라 그걸 연결한 사람임
    • 샌드박싱이 핵심이 될 것임
      macOS에서는 아주 어렵진 않지만, 지금은 쓰기 쉬운 좋은 도구가 부족함. Claude Code는 사용자 경험을 개선하려고 Seatbelt를 조금씩 쓰기 시작했음
    • 발등 찍기 논의는 핵심을 놓치고 있다고 봄
      스스로 해를 입힐 수 있고 아마 그럴 수도 있지만, 가능성을 평가하지 않는 것도 위험임. 일반인은 발등 찍기 가능성을 과소평가하고, 기술자는 새 가능성을 배우지 않는 위험을 과소평가하는 경향이 있음
      1년 전에도 LLM이 내 노트북에서 로컬 명령을 실행하게 했고, 어느 정도 위험하다고 보지만 해로운 일은 없었음. find out where I am and what weather it is going to be 같은 프롬프트에서 rm -rf /를 실행할 가능성은 있더라도 매우 낮음
      다만 LLM이 어떻게 결정하는지 모른 채 주식 거래를 맡기는 건 내 기준에선 너무 위험함
    • 어떤 도구든 오용될 수 있음
  • Warp 터미널의 터미널 기반 에이전트 아이디어는 마음에 들지만, Cursor처럼 “좋은 프롬프트와 LLM 호출은 우리가 알아서 해줄 테니 믿고 돈을 내라”는 모델은 별로임
    그래서 셸 실력 부족을 메워줄 단순한 CLI 기반 터미널 에이전트를 찾고 있었고, 터미널 도구와 llm 조합이 가벼운 해법으로 좋아 보임
    큰 발등 찍기 위험은 잘 알고 있으니, 다른 에이전트처럼 도구 호출마다 권한을 묻는 방식이 가능한지 궁금함. 예를 들어 “llmrm -rf ./*를 호출하려 합니다. 확인하려면 Y를 누르세요” 같은 식이면 LLM이 터미널에서 폭주하는 걸 어느 정도 막을 수 있음

    • 터미널이 왜 여기저기 광고하고 여러 프로젝트를 후원하는지 궁금했는데, 완전히 무료가 아니라는 걸 이제 알았음
    • 그게 --full-auto를 넘기지 않았을 때 codex CLI가 기본으로 동작하는 방식 아닌가 싶음
  • llm을 쓰는 사람이라면 Gtk-llm-chat도 볼 만함
    llm 명령줄 도구와 데스크톱에 통합되며, 트레이 아이콘과 보기 좋은 채팅 창을 제공함
    최근 3.0.0을 릴리스했고 3대 데스크톱 운영체제용 패키지를 제공함

    • 일반 채팅 외에는 어떤 용도로 쓰는지 궁금함
  • 이 릴리스는 기존 클라이언트의 제한 없이 LLM의 잠재력을 여는 핵심 구성요소라고 봄
    0.26 알파가 나온 뒤 MCP 서버와 상호작용하는 플러그인을 만들려고 했지만 꽤 어려웠음. 지금까지 연결하고 도구를 동적으로 가져와 사용하는 데까지는 됐지만, 아직 매개변수 전달은 못 하고 있음

    • 오늘 아침 MCP로 빠른 플러그인 데모를 만들 수 있는지 실험해봤는데 꽤 까다로웠음
      공식 mcp Python 라이브러리는 asyncio를 실행하고 서버에 연결한 뒤 사용 가능한 도구를 검사하는 흐름을 강하게 전제함
  • llm CLI의 탭 완성을 위한 zsh/omz 플러그인을 거의 바이브 코딩으로 유지하고 있는데, 새 기능 릴리스 속도가 빨라 따라가기 어렵음
    그래도 llm -f README.md -f llm.plugin.zsh -f completions/_llm -f [https://simonwillison.net/2025/May/27/llm-tools/](<https://simonwillison.net/2025/May/27/llm-tools/>;) "implement tab completions for the new tool plugins feature" 정도면 90%는 해결됨
    저장소는 https://github.com/eliyastein/llm-zsh-plugin이고, 가능한 많은 옵션과 플래그를 넣으려다 보니 좀 어수선해서 피드백을 받고 싶음

    • 이게 공상과학이 아니라 그냥 지금의 코딩 방식이라는 게 좀 놀라움
      미래 세대는 우리가 어셈블리 프로그래머를 보며 “어떻게 일을 했지?”라고 생각하듯, 우리가 어떻게 일을 해냈는지 궁금해할 것임
  • Claude Code가 도구를 어떻게 알고 사용하는지 궁금했음
    LLM에 도구와 사용법을 알려줄 수 있고 실행 래퍼가 그걸 관리할 수는 있지만, Claude Code는 래퍼가 쓰는 도구 호출 API에 대해 아주 구체적인 기대를 갖고 있고, 후훈련이나 미세조정으로 강하게 보강됐을 거라고 봤음
    그래서 Claude를 쓰는 서드파티 도구 호출 프레임워크가 Anthropic 자체 프레임워크보다 불리한지 궁금함
    별개로 GitHub MCP “공격” 글에서 말했듯 LLM은 자격 증명의 전체 권한까지 쓰도록 속을 수 있음. GitHub처럼 세밀한 인증 자격 증명이 있고 우리 회사도 그렇기 때문에, 래퍼가 LLM에 넘길 세분화된 자격 증명을 생성하는 프로토콜을 누군가 시도해보면 좋겠음
    애플리케이션에는 더 강한 자격 증명을 주고, 하위 LLM은 특정 작업이나 리소스에 대해 “권한 요청”을 하도록 학습시키는 구조를 상상함. 사용자가 허용하면 프레임워크가 서비스에서 범위가 제한된 자격 증명을 받아 도구 호출에 쓰게 하는 방식임

    • 그 자격 증명 방식은 지금도 LLM의 도구 지원으로 가능함
      “추가 자격 증명 요청” 도구를 노출하고, 호출되면 사용자에게 묻는 꽤 정교한 도구 구성이 필요함
      도구는 자격 증명을 보관하고 실제 토큰을 LLM에 절대 넘기면 안 되며, 대신 creds1 같은 기호를 넘겨서 이후 요청에서 creds1로 호출하라고 알려줄 수 있음
  • 이 논문을 봤는지 궁금함. 보기만큼 중요하다면 이 지표가 모든 시스템 카드에 들어가야 하는 것 아닌가 싶음
    128K 토큰 이상 문맥을 지원한다고 주장하는 인기 LLM 12개를 평가했더니, 짧은 문맥에서는 잘하지만 문맥 길이가 늘수록 성능이 크게 떨어졌다고 함. 32K에서는 10개 모델이 짧은 길이 기준선의 50% 아래로 내려갔고, 예외적으로 성능이 좋은 GPT-4o도 99.3%에서 69.7%로 줄었다고 함
    https://arxiv.org/abs/2502.05167

    • 이 논문은 못 봤는데 정말 흥미로움
      요즘 needle in a haystack 테스트에서는 Gemini 2.5 Pro와 Gemini 2.5 Flash가 다른 모델보다 훨씬 앞서 있다고 알고 있어서, 그 모델들로도 돌려보면 좋겠음
  • 지난주 0.26a0로 독점 데이터 기반 고객용 챗봇 데모를 만들었음
    직접 작성해야 했던 핵심 요소는 시스템 프롬프트, 외부 데이터를 가져오는 도구, 계산을 수행하는 도구였고, 이 라이브러리 덕분에 핵심 기능은 매우 쉽게 만들 수 있었음
    데모에서 대부분의 노력은 배관 작업에 들어갔음. 대화가 유지되고, 연결 문제로 브라우저를 새로고침해도 자연스럽게 갱신되며, 새 채팅 세션을 시작할 수 있는 보기 좋은 웹 UI를 만드는 일이었음
    after_call=print는 몰랐는데 블로그 글을 읽고 알게 되어 좋았음

  • Simon의 도구를 매일 쓰고 있음
    파이프와 로컬 Ollama·원격 모델 간 쉬운 전환 덕분에 작업하기 아주 편함