<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://workspace.onionmixer.net/wiki/index.php?action=history&amp;feed=atom&amp;title=Ollama_litellm_continue_cli</id>
	<title>Ollama litellm continue cli - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://workspace.onionmixer.net/wiki/index.php?action=history&amp;feed=atom&amp;title=Ollama_litellm_continue_cli"/>
	<link rel="alternate" type="text/html" href="https://workspace.onionmixer.net/wiki/index.php?title=Ollama_litellm_continue_cli&amp;action=history"/>
	<updated>2026-04-17T22:52:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://workspace.onionmixer.net/wiki/index.php?title=Ollama_litellm_continue_cli&amp;diff=1859&amp;oldid=prev</id>
		<title>Onionmixer: /* 테스트에 사용된 스크립트 */ 양식 오류 수정</title>
		<link rel="alternate" type="text/html" href="https://workspace.onionmixer.net/wiki/index.php?title=Ollama_litellm_continue_cli&amp;diff=1859&amp;oldid=prev"/>
		<updated>2025-10-20T09:02:11Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;테스트에 사용된 스크립트: &lt;/span&gt; 양식 오류 수정&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 09:02, 20 October 2025&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l103&quot;&gt;Line 103:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 103:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;   &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/pre&amp;gt;   &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;    &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;    &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;=&lt;/del&gt;===테스트 1: 기본 tool 호출 트리거(auto)&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;=&lt;/del&gt;===&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;===테스트 1: 기본 tool 호출 트리거(auto)===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* 목적: tools 배열과 tool_choice=auto를 전달해 모델이 함수 호출 의도를 JSON으로 내보내는지 확인한다.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* 목적: tools 배열과 tool_choice=auto를 전달해 모델이 함수 호출 의도를 JSON으로 내보내는지 확인한다.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l254&quot;&gt;Line 254:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 254:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;기대: inbound에는 tools가 존재하지만, outbound(ollama로 나가는 페이로드)에는 tools가 사라지고 JSON 지시가 합성된 흔적이 보인다.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;기대: inbound에는 tools가 존재하지만, outbound(ollama로 나가는 페이로드)에는 tools가 사라지고 JSON 지시가 합성된 흔적이 보인다.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==결론==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==결론==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Onionmixer</name></author>
	</entry>
	<entry>
		<id>https://workspace.onionmixer.net/wiki/index.php?title=Ollama_litellm_continue_cli&amp;diff=1858&amp;oldid=prev</id>
		<title>Onionmixer: ollama 와 litellm, 그리고 continue cli 에 대한 삽질 기록(20251020) 내용 추가</title>
		<link rel="alternate" type="text/html" href="https://workspace.onionmixer.net/wiki/index.php?title=Ollama_litellm_continue_cli&amp;diff=1858&amp;oldid=prev"/>
		<updated>2025-10-20T09:01:40Z</updated>

		<summary type="html">&lt;p&gt;ollama 와 litellm, 그리고 continue cli 에 대한 삽질 기록(20251020) 내용 추가&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;;ollama 와 litellm, 그리고 continue cli 에 대한 삽질 기록(20251020)&lt;br /&gt;
&lt;br /&gt;
==서문==&lt;br /&gt;
&lt;br /&gt;
20251020 글 작성 시점에서 cli 계열의 coding agent 는 tool call 이라는걸 지원해야 한다. 이는 기존의 단순한 대화형이 아니라 좀 더 구체적인 작업을 하기 위한 정해진 규걱? 같은 내용으로 보면 된다.&lt;br /&gt;
&lt;br /&gt;
그런데 공개된 Model 들은 현재 시점에서 claude code 가 요구하는 수준의 tool call 을 처리하지 못한다. 적어도 ollama  는 그렇다(lm studio 는 좀 나은편)&lt;br /&gt;
&lt;br /&gt;
그러다보니 공개된 model 에 tool 관련된 학습을 lora 등으로 진행해서 튜닝한 모델을이 몇가지 존재하는데 그다지 좋다고 볼 수는 없다. 그래서 이를 별도의 방법을 통해 처리하려는 시도를 몇가지 해 보았다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==각 요소들의 설졍==&lt;br /&gt;
&lt;br /&gt;
===litellm : config.yaml===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
model_list:&lt;br /&gt;
  - model_name: qwen3-coder-30b-a3b  # 사용자가 호출할 모델 이름&lt;br /&gt;
    model_info:&lt;br /&gt;
        supports_function_calling: true&lt;br /&gt;
    litellm_params:&lt;br /&gt;
      model: ollama/danielsheep/Qwen3-Coder-30B-A3B-Instruct-1M-Unsloth:UD-Q5_K_XL # 실제 라우팅될될될 모델 (ollama/모&lt;br /&gt;
델명 형식)&lt;br /&gt;
      api_base: http://host.docker.internal:11434 # Ollama 컨테이너 주소&lt;br /&gt;
      max_tokens: 8192&lt;br /&gt;
      response_format:&lt;br /&gt;
        type: json_object&lt;br /&gt;
      # 백엔드(ollama)가 네이티브 tool/function calling을 미지원할 때&lt;br /&gt;
      # 혼선을 유발하는 파라미터를 확실히 제거&lt;br /&gt;
      additional_drop_params: []&lt;br /&gt;
        #  - tools&lt;br /&gt;
        #- tool_choice&lt;br /&gt;
        #- functions&lt;br /&gt;
        #- function_call&lt;br /&gt;
&lt;br /&gt;
router_settings:&lt;br /&gt;
  remove_model_name_prefix: true&lt;br /&gt;
  num_retries: 3&lt;br /&gt;
  timeout: 4096&lt;br /&gt;
  retry_policy:&lt;br /&gt;
    retry_on_status_codes: [400,401,402,403,408,429,500,502,503]&lt;br /&gt;
&lt;br /&gt;
litellm_settings:&lt;br /&gt;
  drop_params: false&lt;br /&gt;
  set_verbose: true&lt;br /&gt;
  force_tool_call_emulation: true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
위의 설정을 통해서 litellm 에서 tool 관련된 중간처리를 하도록 설정한다. tool 을 지원하지 않는 model 의 응답을 JSON 형식으로 처리해서 tool 의 형식을 갖추도록 한다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===continue cli : config.yaml===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
name: Local via Ollama&lt;br /&gt;
version: 0.0.1&lt;br /&gt;
schema: v1&lt;br /&gt;
&lt;br /&gt;
models:&lt;br /&gt;
  - name: qwen3-coder-30b-a3b&lt;br /&gt;
    provider: ollama           # 반드시 custom 사용&lt;br /&gt;
    model: danielsheep/Qwen3-Coder-30B-A3B-Instruct-1M-Unsloth:UD-Q5_K_XL&lt;br /&gt;
    apiBase: http://192.168.1.239:11434&lt;br /&gt;
    apiKey: user&lt;br /&gt;
    override:&lt;br /&gt;
      defaultCompletionOptions:&lt;br /&gt;
        # 모델이 처리할 수 있는 최대 입력 토큰 수를 8192로 설정&lt;br /&gt;
        contextLength: 8192&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
이건 최종 설정이다. litellm 을 중간에 사용하고 provider 를 &amp;quot;openai&amp;quot; 로 설정했는데 어차피 그렇게 해도 claude cli 에서 알아먹지 못하는 tool name 이 온다면 claude cli 는 그걸 화면상에 응답받은 JSON 을 바로 출력해버리게 된다. 그럴바에는 provider 를 &amp;quot;ollama&amp;quot; 로 지정하고, 서버의 답변을 continue cli 가 처리하도록 하는것이 낫다&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==테스트에 사용된 스크립트==&lt;br /&gt;
&lt;br /&gt;
===litellm alive check===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -s http://192.168.1.239:3333/health/readiness&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -s http://192.168.1.239:3333/health/liveliness&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -s -H &amp;quot;Authorization: Bearer sk-TEST&amp;quot; http://192.168.1.239:3333/v1/models&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -s http://192.168.1.239:3333/v1/chat/completions \&lt;br /&gt;
  -H &amp;quot;Content-Type: application/json&amp;quot; \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer sk-TEST&amp;quot; \&lt;br /&gt;
  -d &amp;#039;{&lt;br /&gt;
    &amp;quot;model&amp;quot;: &amp;quot;qwen3-coder-30b-a3b&amp;quot;,&lt;br /&gt;
    &amp;quot;response_format&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;json_object&amp;quot;},&lt;br /&gt;
    &amp;quot;messages&amp;quot;: [&lt;br /&gt;
      {&amp;quot;role&amp;quot;:&amp;quot;user&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Return a JSON with {\&amp;quot;city\&amp;quot;:\&amp;quot;Seoul\&amp;quot;,\&amp;quot;unit\&amp;quot;:\&amp;quot;C\&amp;quot;} keys filled appropriately.&amp;quot;}&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;max_tokens&amp;quot;: 50&lt;br /&gt;
  }&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;  &lt;br /&gt;
  &lt;br /&gt;
====테스트 1: 기본 tool 호출 트리거(auto)====&lt;br /&gt;
&lt;br /&gt;
* 목적: tools 배열과 tool_choice=auto를 전달해 모델이 함수 호출 의도를 JSON으로 내보내는지 확인한다.&lt;br /&gt;
* 기대: 응답의 choices.message.tool_calls에 get_weather가 생성되거나, JSON 형태로 도구 호출 의도가 나타난다(response_format로 구조화 유도).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -sS http://192.168.1.239:3333/v1/chat/completions \&lt;br /&gt;
  -H &amp;#039;Content-Type: application/json&amp;#039; \&lt;br /&gt;
  -H &amp;#039;Authorization: Bearer sk-TEST&amp;#039; \&lt;br /&gt;
  -d &amp;#039;{&lt;br /&gt;
    &amp;quot;model&amp;quot;: &amp;quot;qwen3-coder-30b-a3b&amp;quot;,&lt;br /&gt;
    &amp;quot;response_format&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;json_object&amp;quot; },&lt;br /&gt;
    &amp;quot;messages&amp;quot;: [&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;system&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;You can call tools. If needed, return a JSON object describing the tool and args.&amp;quot; },&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;서울 날씨 알려줘&amp;quot; }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;tools&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;function&amp;quot;: {&lt;br /&gt;
          &amp;quot;name&amp;quot;: &amp;quot;get_weather&amp;quot;,&lt;br /&gt;
          &amp;quot;description&amp;quot;: &amp;quot;Return weather by city&amp;quot;,&lt;br /&gt;
          &amp;quot;parameters&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
            &amp;quot;properties&amp;quot;: { &amp;quot;city&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot; } },&lt;br /&gt;
            &amp;quot;required&amp;quot;: [&amp;quot;city&amp;quot;]&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;tool_choice&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
    &amp;quot;temperature&amp;quot;: 0&lt;br /&gt;
  }&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===테스트 2: 특정 도구 강제 호출===&lt;br /&gt;
&lt;br /&gt;
* 목적: tool_choice로 특정 함수명을 지정해 강제 호출 경로를 검증한다.&lt;br /&gt;
* 기대: tool_calls에 name=get_weather가 생성되며 arguments에 도시명이 포함된다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -sS http://192.168.1.239:3333/v1/chat/completions \&lt;br /&gt;
  -H &amp;#039;Content-Type: application/json&amp;#039; \&lt;br /&gt;
  -H &amp;#039;Authorization: Bearer sk-TEST&amp;#039; \&lt;br /&gt;
  -d &amp;#039;{&lt;br /&gt;
    &amp;quot;model&amp;quot;: &amp;quot;qwen3-coder-30b-a3b&amp;quot;,&lt;br /&gt;
    &amp;quot;response_format&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;json_object&amp;quot; },&lt;br /&gt;
    &amp;quot;messages&amp;quot;: [&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;부산 날씨 알려줘&amp;quot; }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;tools&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;function&amp;quot;: {&lt;br /&gt;
          &amp;quot;name&amp;quot;: &amp;quot;get_weather&amp;quot;,&lt;br /&gt;
          &amp;quot;description&amp;quot;: &amp;quot;Return weather by city&amp;quot;,&lt;br /&gt;
          &amp;quot;parameters&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
            &amp;quot;properties&amp;quot;: { &amp;quot;city&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot; } },&lt;br /&gt;
            &amp;quot;required&amp;quot;: [&amp;quot;city&amp;quot;]&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;tool_choice&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;, &amp;quot;function&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;get_weather&amp;quot; } },&lt;br /&gt;
    &amp;quot;temperature&amp;quot;: 0&lt;br /&gt;
  }&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====return value====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&amp;quot;id&amp;quot;:&amp;quot;chatcmpl-f8986d1d-71c4-472c-b9e3-e3351a3dccd9&amp;quot;,&amp;quot;created&amp;quot;:1760942417,&amp;quot;model&amp;quot;:&amp;quot;ollama/danielsheep/Qwen3-Coder-30B-A3B-Instruct-1M-Unsloth:UD-Q5_K_XL&amp;quot;,&amp;quot;object&amp;quot;:&amp;quot;chat.completion&amp;quot;,&amp;quot;choices&amp;quot;:[{&amp;quot;finish_reason&amp;quot;:&amp;quot;stop&amp;quot;,&amp;quot;index&amp;quot;:0,&amp;quot;message&amp;quot;:{&amp;quot;content&amp;quot;:&amp;quot;{\&amp;quot;error\&amp;quot;: {\&amp;quot;type\&amp;quot;: \&amp;quot;llm_call_failed\&amp;quot;, \&amp;quot;message\&amp;quot;: \&amp;quot;{\\\&amp;quot;message\\\&amp;quot;:\\\&amp;quot;Operation not allowed\\\&amp;quot;}\\n\&amp;quot;}}&amp;quot;,&amp;quot;role&amp;quot;:&amp;quot;assistant&amp;quot;}}],&amp;quot;usage&amp;quot;:{&amp;quot;completion_tokens&amp;quot;:34,&amp;quot;prompt_tokens&amp;quot;:19,&amp;quot;total_tokens&amp;quot;:53}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===테스트 3: 도구 실행 결과 주입(후속 턴)===&lt;br /&gt;
&lt;br /&gt;
* 목적: 1~2번에서 받은 tool_calls를 그대로 대화 이력에 포함하고, role=tool 메시지로 결과를 전달해 최종 답변 생성까지 확인한다.&lt;br /&gt;
* 방법: 아래 예시에서 &amp;quot;CALL_ID_FROM_PREV&amp;quot; 위치에 이전 응답의 tool_calls.id를 넣는다.&lt;br /&gt;
* 기대: 모델이 tool 결과를 반영한 자연어 답변을 생성한다(프록시가 OpenAI 호환 대화 포맷을 수용).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -sS http://192.168.1.239:3333/v1/chat/completions \&lt;br /&gt;
  -H &amp;#039;Content-Type: application/json&amp;#039; \&lt;br /&gt;
  -H &amp;#039;Authorization: Bearer sk-TEST&amp;#039; \&lt;br /&gt;
  -d &amp;#039;{&lt;br /&gt;
    &amp;quot;model&amp;quot;: &amp;quot;qwen3-coder-30b-a3b&amp;quot;,&lt;br /&gt;
    &amp;quot;messages&amp;quot;: [&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;system&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;You can call tools.&amp;quot; },&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;서울 날씨 알려줘&amp;quot; },&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;assistant&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;tool_calls&amp;quot;: [&lt;br /&gt;
          {&lt;br /&gt;
            &amp;quot;id&amp;quot;: &amp;quot;chatcmpl-b7eacfae-4c87-42e7-96f2-dfd55502d68c&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
            &amp;quot;function&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;get_weather&amp;quot;, &amp;quot;arguments&amp;quot;: &amp;quot;{\&amp;quot;city\&amp;quot;:\&amp;quot;서울\&amp;quot;}&amp;quot; }&lt;br /&gt;
          }&lt;br /&gt;
        ]&lt;br /&gt;
      },&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;tool&amp;quot;, &amp;quot;tool_call_id&amp;quot;: &amp;quot;chatcmpl-b7eacfae-4c87-42e7-96f2-dfd55502d68c&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;{\&amp;quot;temp_c\&amp;quot;:18, \&amp;quot;condition\&amp;quot;:\&amp;quot;cloudy\&amp;quot;}&amp;quot; }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;temperature&amp;quot;: 0&lt;br /&gt;
  }&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===테스트 4: 스트리밍으로 확인===&lt;br /&gt;
&lt;br /&gt;
* 목적: SSE 스트림으로 tool_calls 또는 구조화 출력을 단계적으로 확인한다.&lt;br /&gt;
* 기대: event: chunk 스트림으로 delta.tool_calls 또는 JSON 파편이 전달되며 최종적으로 finish_reason이 표시된다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl -N http://192.168.1.239:3333/v1/chat/completions \&lt;br /&gt;
  -H &amp;#039;Content-Type: application/json&amp;#039; \&lt;br /&gt;
  -H &amp;#039;Authorization: Bearer sk-TEST&amp;#039; \&lt;br /&gt;
  -d &amp;#039;{&lt;br /&gt;
    &amp;quot;model&amp;quot;: &amp;quot;qwen3-coder-30b-a3b&amp;quot;,&lt;br /&gt;
    &amp;quot;stream&amp;quot;: true,&lt;br /&gt;
    &amp;quot;response_format&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;json_object&amp;quot; },&lt;br /&gt;
    &amp;quot;messages&amp;quot;: [&lt;br /&gt;
      { &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;대전 날씨 알려줘&amp;quot; }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;tools&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,&lt;br /&gt;
        &amp;quot;function&amp;quot;: {&lt;br /&gt;
          &amp;quot;name&amp;quot;: &amp;quot;get_weather&amp;quot;,&lt;br /&gt;
          &amp;quot;description&amp;quot;: &amp;quot;Return weather by city&amp;quot;,&lt;br /&gt;
          &amp;quot;parameters&amp;quot;: {&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
            &amp;quot;properties&amp;quot;: { &amp;quot;city&amp;quot;: { &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot; } },&lt;br /&gt;
            &amp;quot;required&amp;quot;: [&amp;quot;city&amp;quot;]&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;tool_choice&amp;quot;: &amp;quot;auto&amp;quot;,&lt;br /&gt;
    &amp;quot;temperature&amp;quot;: 0&lt;br /&gt;
  }&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===테스트 5: drop_params 동작 확인(로그 기반)===&lt;br /&gt;
&lt;br /&gt;
* 목적: 도구 미지원 백엔드에서 tools 등의 파라미터가 실제로 드롭되고, 시스템 메시지에 주입되는지 로그로 검증한다.&lt;br /&gt;
   &lt;br /&gt;
# 동일한 요청을 실행한 뒤, LiteLLM 프록시 콘솔/JSON 로그에서&lt;br /&gt;
# outbound payload에 tools가 제거되고 system 프롬프트에 함수 정의/JSON 지시가 합성됐는지 확인&lt;br /&gt;
# (프록시 가동 시 set_verbose / JSON logs 활성화 필요)&lt;br /&gt;
&lt;br /&gt;
기대: inbound에는 tools가 존재하지만, outbound(ollama로 나가는 페이로드)에는 tools가 사라지고 JSON 지시가 합성된 흔적이 보인다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==결론==&lt;br /&gt;
&lt;br /&gt;
그럭저럭은 동작하지만 C 로 작업된 프로그램을 개선하는 수즌으로는 분명히 한계가 있는 것으로 보인다. 현시점의 결과이므로 향후 새롭고 좋은 모델들이 나온다면 결과는 바뀔 수 있으니 참고해야 한다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===참고 메모===&lt;br /&gt;
&lt;br /&gt;
* OpenAI 호환 입력 포맷(roles, tools, tool_choice, response_format)은 LiteLLM 프록시가 그대로 수용하며, 백엔드 미지원 항목은 drop_params/변환 레이어로 흡수된다.&lt;br /&gt;
* JSON 강제는 response_format {type: json_object} 사용을 권장하며, 구조화 출력 파싱 안정성 향상에 유용하다.&lt;br /&gt;
* 프록시 엔드포인트/경로와 기동 방식은 LiteLLM “AI Gateway(Proxy)” 가이드의 기본값을 따른다.&lt;br /&gt;
&lt;br /&gt;
위 시나리오로 tool 주입(에뮬레이션) 경로, 강제 호출, 후속 도구 결과 주입, 스트리밍, 파라미터 드롭·주입 로그까지 일련의 동작을 단계적으로 검증할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==참고자료==&lt;br /&gt;
&lt;br /&gt;
https://docs.continue.dev/reference&lt;/div&gt;</summary>
		<author><name>Onionmixer</name></author>
	</entry>
</feed>