Files
Antrophic-Qwen3.6-Proxy/doc/proxy-analysis.md

132 lines
4.1 KiB
Markdown
Raw Normal View History

2026-05-10 10:46:41 +02:00
# Proxy Implementierungsanalyse
## Was der Proxy macht
Übersetzt **Anthropic API** (`POST /v1/messages`) → **Ollama API** (`POST /api/chat`)
- Empfängt Anthropic SSE-Format
- Gibt Anthropic SSE-Format zurück
- Routing: `localhost:11435``https://ollama.aquantico.de/api/chat`
---
## Korrekte Implementierungen ✓
### 1. Model-Substitution (korrekt)
```js
if (anthropicBody.model?.startsWith('claude-')) {
anthropicBody.model = 'qwen3.6:35b-a3b-q4_K_M';
}
```
Alle `claude-*` Modelle werden durch das lokale Modell ersetzt.
### 2. Think-Modus deaktiviert (korrekt)
```js
think: false
```
Hardcoded in `convertAnthropicToOllama()`.
### 3. Tool-Schema-Konvertierung (korrekt)
Anthropic `input_schema` → Ollama `function.parameters`:
```js
{ type: 'function', function: { name, description, parameters: sanitizeToolSchema(tool.input_schema) } }
```
### 4. Tool-Call-Parsing in Response (korrekt)
Ollama gibt `tc.function.name` und `tc.function.arguments` zurück — genau das liest der Proxy:
```js
const toolName = tc.function?.name;
const toolInput = parseToolArguments(tc.function?.arguments);
```
### 5. SSE-Event-Sequenz (korrekt)
Ausgabe entspricht Anthropic-Spec:
`message_start``content_block_start``content_block_delta``content_block_stop``message_delta``message_stop`
### 6. stop_reason (korrekt)
```js
stop_reason: emittedToolUse ? 'tool_use' : 'end_turn'
```
### 7. Tool-Deduplizierung (korrekt)
Verhindert doppelte Tool-Calls via `seenToolCalls` Set mit Key `name:args`.
---
## Bekannte Bugs / Schwachstellen ⚠️
### BUG 1: Leerer finaler Buffer-Handler (app.js:350-358)
```js
if (buffer.trim()) {
try {
const data = JSON.parse(buffer.trim());
// gleichen Handling-Code wie oben ausführen ← LEER, nie ausgeführt!
} catch (e) { ... }
}
```
**Problem**: Wenn das letzte NDJSON-Chunk von Ollama nicht mit `\n` endet (was bei einigen Ollama-Versionen vorkommt), bleibt die finale `done: true`-Zeile im Buffer und wird nicht verarbeitet.
**Auswirkung**: `messageFinished` bleibt `false`, Fallback-Code (Zeile 360-381) sendet die Abschluss-Events ohne `eval_count` (output_tokens=0).
**Fix**: Den gleichen Parsing-Code aus der while-Schleife in den finalen Buffer-Handler kopieren.
### BUG 2: message_start ohne usage.input_tokens (app.js:200-209)
```js
res.write(`event: message_start\ndata: ${JSON.stringify({
type: 'message_start',
message: {
id: messageId, type: 'message', role: 'assistant', content: [],
model: anthropicBody.model
// fehlt: stop_reason: null, usage: { input_tokens: 0, output_tokens: 0 }
}
})}\n\n`);
```
**Auswirkung**: Anthropic-kompatible Clients erwarten `usage.input_tokens` in `message_start`. Kann bei strikten Clients zu Parse-Fehlern führen.
### BUG 3: tool_use/tool_result als Text im Nachrichten-Verlauf
Wenn Anthropic-Clients `tool_use` (in Assistant-Nachrichten) und `tool_result` (in User-Nachrichten) im History senden, werden diese als Text-Strings in den Ollama-Messages eingebettet:
```
"Previous assistant tool call already made.\nTool name: ...\n..."
```
**Korrekt wäre**: Assistant-Nachrichten mit `tool_calls` senden, Tool-Results als `role: "tool"` Nachricht.
**Auswirkung**: Das Modell versteht den Tool-Call-Verlauf semantisch nicht korrekt. Die bestehende Deduplizierungs-Logik kompensiert dies teilweise.
---
## Architektur-Übersicht
```
Client (Claude SDK)
│ POST /v1/messages (Anthropic Format)
noThinkProxy :11435
│ convertAnthropicToOllama()
│ - system → messages[0] role:system
│ - tool_use → text string
│ - tool_result → text string
│ - model: claude-* → qwen3.6:35b-a3b-q4_K_M
│ - think: false
│ - options: { num_ctx:131072, num_predict, temperature:0.7 }
│ POST /api/chat (Ollama NDJSON)
Ollama https://ollama.aquantico.de
│ NDJSON stream: {message:{content, tool_calls}, done}
noThinkProxy
│ handleResponse()
│ - text → content_block_delta (text_delta)
│ - tool_calls → content_block_start/delta/stop (tool_use)
│ - done → message_delta + message_stop
Client (Anthropic SSE)
```