Skip to content

fix(agent): Ollama の format に移植スキーマを渡し文法変換失敗を解消#422

Merged
yusuke0610 merged 1 commit into
mainfrom
fix/ollama-format-portable-schema
Jun 28, 2026
Merged

fix(agent): Ollama の format に移植スキーマを渡し文法変換失敗を解消#422
yusuke0610 merged 1 commit into
mainfrom
fix/ollama-format-portable-schema

Conversation

@yusuke0610

@yusuke0610 yusuke0610 commented Jun 28, 2026

Copy link
Copy Markdown
Owner

概要

ローカル Ollama 経路(LLM_LOCAL_OLLAMA=1)で Agent チャットが 502 になっていた不具合を修正する。

原因

OllamaClient/api/chatformat生スキーマbuild_output_schema)を渡しており、その value.maxLength(2000) / suggestions.maxItems(4) を llama.cpp の JSON Schema → GBNF 文法変換が解釈できず、{"error":{"message":"Failed to initialize samplers: failed to parse grammar"}} の 400 を返していた。これが LLMError → 502 になっていた。

実機 curl で切り分け済み:

  • oneOf のみ → 200(無罪)
  • フルスキーマ → 400failed to parse grammar
  • maxLength/maxItems を除去(to_portable_schema 相当)→ 200

変更内容

  • ollama_client.py: formatto_portable_schema(output_schema, drop_additional_properties=False) を渡す(maxLength/maxItems 除去・oneOfenum 平坦化)。Gemini/OpenAI と同じ移植スキーマ経路に揃える。
  • output_schema.py: 「Ollama は maxLength を助言扱い/生スキーマをそのまま使う」という誤った前提のコメントを実態(数値制約で文法変換が壊れる)に修正。ロジックは無変更。
  • tests/test_llm_clients.py: 回帰テスト追加。Ollama に投げる formatoneOf/maxLength/maxItems が残らず、field が enum に畳まれることを検証。

影響範囲

  • 文字数上限の実強制は従来どおり chat_service._parse_response(二重防衛)が担うため品質は不変
  • Anthropic / Gemini / OpenAI 経路は無変更to_portable_schema の本体は触らず、Ollama を相乗りさせただけ)。

検証

  • make lint-backend: pass
  • make test-backend: pass(633 passed)
  • 実機: 移植スキーマ相当のペイロードが Ollama /api/chat で 200 を返すことを curl で確認

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved compatibility when sending structured responses to the AI service by converting schemas into a more portable format before requests are made.
    • Reduced failures caused by schema constraints that are not reliably supported by some model backends.
  • Tests

    • Added coverage to verify the request payload uses the portable schema format and preserves allowed field values.

ローカル Ollama(LLM_LOCAL_OLLAMA=1)経路で /api/chat が
"Failed to initialize samplers: failed to parse grammar" の 400 を返し、
Agent チャットが 502 になっていた。原因は format に渡す JSON Schema の
maxLength / maxItems を llama.cpp の GBNF 文法変換が解釈できないこと
(oneOf は無罪。実機 curl で maxLength/maxItems 除去後は 200 を確認)。

- ollama_client: format に to_portable_schema(..., drop_additional_properties=False)
  を渡す(maxLength/maxItems 除去・oneOf→enum 平坦化)。Gemini/OpenAI と同じ移植経路に揃える
- output_schema: 「Ollama は maxLength を助言扱い/生スキーマを使う」誤コメントを実態へ修正
- test_llm_clients: format に oneOf/maxLength/maxItems が残らないことの回帰テストを追加

文字数上限の実強制は従来どおり _parse_response が担う(二重防衛)。
Anthropic/Gemini/OpenAI 経路は無変更。make lint-backend / make test-backend(633 passed) green。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e66b3fd4-1b6a-4524-843f-878ad8ae8aa1

📥 Commits

Reviewing files that changed from the base of the PR and between 395b512 and fa75ff1.

📒 Files selected for processing (3)
  • backend/app/services/agent/llm/ollama_client.py
  • backend/app/services/agent/output_schema.py
  • backend/tests/test_llm_clients.py

📝 Walkthrough

Walkthrough

OllamaClient.generate now applies to_portable_schema to output_schema before placing it in the Ollama /api/chat request's format field, removing JSON Schema keywords (oneOf, maxLength, maxItems) that break llama.cpp grammar conversion. Docstrings in both files are updated, and a new test verifies the transformed payload.

Changes

Ollama Portable Schema

Layer / File(s) Summary
Schema transformation and docs
backend/app/services/agent/llm/ollama_client.py, backend/app/services/agent/output_schema.py
OllamaClient imports and applies to_portable_schema(output_schema, drop_additional_properties=False) for the format payload field. Docstrings in both files clarify which providers use the portable schema and that length enforcement is delegated to _parse_response.
Payload verification test
backend/tests/test_llm_clients.py
test_ollama_client_sends_portable_schema captures the outgoing request via a monkeypatched httpx.AsyncClient and asserts the format field contains no oneOf, maxLength, or maxItems, and that project.field is folded into an enum.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hop hop, the grammar's clear,
No maxLength to cause llama fear,
oneOf dropped, the schema neat,
Portable format, what a treat!
The rabbit cheers — constraints complete! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Ollama の format に移植スキーマを渡して grammar 変換失敗を解消する内容で、変更の主旨を適切に表しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ollama-format-portable-schema

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@yusuke0610
yusuke0610 merged commit 5c5e5df into main Jun 28, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant