Tool-Nutzung: tool_choice pro Agent konfigurierbar (default: any), wiederholte Instruktionen im System-Prompt, MaxIterations in appsettings
This commit is contained in:
1 parent
8c9f54da79
commit
ff67542ba6
10 files changed
+59
-9
No files matched your search
@@ -49,7 +49,8 @@ public static class AgentEndpoint
|
||||
Description = body.TryGetProperty("description", out var d) ? d.GetString() : null,
|
||||
Model = body.TryGetProperty("model", out var m) ? m.GetString() ?? "sonnet" : "sonnet",
|
||||
Persona = body.TryGetProperty("persona", out var p) ? p.GetString() : null,
|
||||
Instructions = body.TryGetProperty("instructions", out var i) ? i.GetString() : null
|
||||
Instructions = body.TryGetProperty("instructions", out var i) ? i.GetString() : null,
|
||||
ToolChoice = body.TryGetProperty("toolChoice", out var tc) ? tc.GetString() ?? "any" : "any"
|
||||
};
|
||||
|
||||
agent = await db.CreateAgent(agent);
|
||||
@@ -72,6 +73,7 @@ public static class AgentEndpoint
|
||||
if (body.TryGetProperty("model", out var m)) agent.Model = m.GetString();
|
||||
if (body.TryGetProperty("persona", out var p)) agent.Persona = p.GetString();
|
||||
if (body.TryGetProperty("instructions", out var i)) agent.Instructions = i.GetString();
|
||||
if (body.TryGetProperty("toolChoice", out var tc)) agent.ToolChoice = tc.GetString();
|
||||
|
||||
await db.UpdateAgent(agent);
|
||||
agent = await db.GetAgent(agentId);
|
||||
|
||||
@@ -151,11 +151,14 @@ public static class ChatEndpoint
|
||||
if (!string.IsNullOrEmpty(workspace))
|
||||
Directory.CreateDirectory(workspace);
|
||||
|
||||
var maxIterations = config.GetValue<int>("MaxIterations", 100);
|
||||
var toolChoice = agent.ToolChoice ?? "any";
|
||||
|
||||
var anthropic = new AnthropicService(httpFactory, token, toolService, db);
|
||||
streamingTracker.Start(sessionId, chainId);
|
||||
try
|
||||
{
|
||||
await anthropic.StreamChat(res, modelId, systemPrompt, messages, chainId, workspace, sessionId, cancellationToken: cancellationToken);
|
||||
await anthropic.StreamChat(res, modelId, systemPrompt, messages, chainId, workspace, sessionId, maxIterations: maxIterations, toolChoice: toolChoice, cancellationToken: cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ public class AgentRecord
|
||||
public string Model { get; set; } // sonnet, opus
|
||||
public string Persona { get; set; }
|
||||
public string Instructions { get; set; }
|
||||
public string ToolChoice { get; set; } // "any" oder "auto"
|
||||
public bool IsDeleted { get; set; }
|
||||
public string CreatedAt { get; set; }
|
||||
public string UpdatedAt { get; set; }
|
||||
|
||||
@@ -35,7 +35,8 @@ public class AnthropicService
|
||||
string chainId,
|
||||
string workspace,
|
||||
string sessionId = null,
|
||||
int maxIterations = 25,
|
||||
int maxIterations = 100,
|
||||
string toolChoice = "any",
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
@@ -67,7 +68,13 @@ public class AnthropicService
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(workspace))
|
||||
{
|
||||
payload["tools"] = _toolService.GetToolDefinitions();
|
||||
// "any" erzwingt Tool-Nutzung, aber nur in der ersten Iteration,
|
||||
// damit Claude nicht endlos Tools aufruft wenn die Aufgabe erledigt ist.
|
||||
var effectiveChoice = (toolChoice == "any" && iterations == 1) ? "any" : "auto";
|
||||
payload["tool_choice"] = new { type = effectiveChoice };
|
||||
}
|
||||
|
||||
var client = CreateClient();
|
||||
var json = JsonSerializer.Serialize(payload);
|
||||
|
||||
@@ -126,6 +126,7 @@ public class DatabaseService
|
||||
TryAddColumn(conn, "chains", "cache_read_tokens", "INTEGER NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "messages", "attachment_count", "INTEGER NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "messages", "attachment_names", "TEXT");
|
||||
TryAddColumn(conn, "agents", "tool_choice", "TEXT DEFAULT 'any'");
|
||||
}
|
||||
|
||||
private void TryAddColumn(SqliteConnection conn, string table, string column, string type)
|
||||
@@ -144,8 +145,8 @@ public class DatabaseService
|
||||
agent.CreatedAt = now;
|
||||
agent.UpdatedAt = now;
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO agents (agent_id, name, avatar, description, model, persona, instructions, is_deleted, created_at, updated_at)
|
||||
VALUES (@AgentId, @Name, @Avatar, @Description, @Model, @Persona, @Instructions, 0, @CreatedAt, @UpdatedAt)
|
||||
INSERT INTO agents (agent_id, name, avatar, description, model, persona, instructions, tool_choice, is_deleted, created_at, updated_at)
|
||||
VALUES (@AgentId, @Name, @Avatar, @Description, @Model, @Persona, @Instructions, @ToolChoice, 0, @CreatedAt, @UpdatedAt)
|
||||
", agent);
|
||||
return agent;
|
||||
}
|
||||
@@ -170,7 +171,7 @@ public class DatabaseService
|
||||
agent.UpdatedAt = DateTime.UtcNow.ToString("o");
|
||||
await conn.ExecuteAsync(@"
|
||||
UPDATE agents SET name = @Name, avatar = @Avatar, description = @Description,
|
||||
model = @Model, persona = @Persona, instructions = @Instructions, updated_at = @UpdatedAt
|
||||
model = @Model, persona = @Persona, instructions = @Instructions, tool_choice = @ToolChoice, updated_at = @UpdatedAt
|
||||
WHERE agent_id = @AgentId
|
||||
", agent);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ public static class SystemPromptBuilder
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(session.Workspace))
|
||||
{
|
||||
parts.Add(@$"## Tools
|
||||
parts.Add(@$"## KRITISCH: Tool-Nutzung
|
||||
JEDE Datei-Operation und JEDER Shell-Befehl MUSS über einen Tool-Aufruf erfolgen. NIEMALS eine Aktion nur beschreiben oder behaupten - IMMER das Tool tatsächlich aufrufen.
|
||||
|
||||
## Tools
|
||||
Du hast Tools zur Verfügung (read_file, write_file, edit_file, list_files, delete_file, execute). Benutze sie um Dateien zu lesen, schreiben und bearbeiten.
|
||||
|
||||
Der Workspace-Pfad ist: `{session.Workspace}`
|
||||
@@ -34,7 +37,10 @@ Wenn der User auf eine bestimmte Zeile in einer Datei verweist (z.B. `[Datei: fo
|
||||
- Wenn du Dateien lesen, schreiben, bearbeiten, erstellen oder löschen willst: IMMER das entsprechende Tool aufrufen. NIEMALS den Inhalt nur in die Antwort schreiben.
|
||||
- Wenn du Shell-Befehle ausführen willst: IMMER das execute-Tool verwenden.
|
||||
- Behaupte NIEMALS etwas getan zu haben (Datei geschrieben, Commit gemacht, Befehl ausgeführt) ohne das entsprechende Tool tatsächlich aufgerufen zu haben. Wenn kein Tool-Aufruf stattgefunden hat, ist nichts passiert.
|
||||
- Plane nicht nur - handle sofort über Tool-Aufrufe.");
|
||||
- Plane nicht nur - handle sofort über Tool-Aufrufe.
|
||||
|
||||
## ERINNERUNG
|
||||
Diese Regel hat höchste Priorität und gilt für JEDE Antwort: Wenn eine Datei gelesen, geschrieben, bearbeitet, erstellt oder gelöscht werden soll, oder ein Befehl ausgeführt werden soll, MUSS der entsprechende Tool-Aufruf erfolgen. Ohne Tool-Aufruf ist NICHTS passiert. Beschreibe keine Änderungen - führe sie durch.");
|
||||
|
||||
return string.Join("\n\n", parts);
|
||||
}
|
||||
|
||||
+2
-1
@@ -5,5 +5,6 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
"AllowedHosts": "*",
|
||||
"MaxIterations": 100
|
||||
}
|
||||
@@ -99,6 +99,28 @@
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
/* ── Checkbox ── */
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--badge-spacing);
|
||||
cursor: pointer;
|
||||
margin-top: var(--box-spacing);
|
||||
}
|
||||
|
||||
.checkbox-label input[type="checkbox"] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
accent-color: var(--accent);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-hint {
|
||||
opacity: 0.5;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.danger-btn {
|
||||
color: var(--dangerous);
|
||||
border-color: var(--dangerous);
|
||||
|
||||
@@ -126,6 +126,10 @@
|
||||
<textarea id="agentPersona" rows="6" placeholder="Persönlichkeit / Seele des Agents"></textarea>
|
||||
<label>Anweisungen</label>
|
||||
<textarea id="agentInstructions" rows="6" placeholder="Technische Anweisungen"></textarea>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="agentToolChoice" checked>
|
||||
Tool-Nutzung erzwingen <span class="checkbox-hint">(tool_choice: any)</span>
|
||||
</label>
|
||||
<div class="form-actions">
|
||||
<button id="agentSaveBtn">Speichern</button>
|
||||
<button id="agentCancelBtn">Abbrechen</button>
|
||||
|
||||
@@ -20,6 +20,7 @@ registerPage('agent', {
|
||||
const modelEl = document.getElementById('agentModel');
|
||||
const personaEl = document.getElementById('agentPersona');
|
||||
const instructionsEl = document.getElementById('agentInstructions');
|
||||
const toolChoiceEl = document.getElementById('agentToolChoice');
|
||||
const avatarPreview = document.getElementById('avatarPreview');
|
||||
const avatarInput = document.getElementById('avatarInput');
|
||||
const avatarBtn = document.getElementById('avatarBtn');
|
||||
@@ -37,6 +38,7 @@ registerPage('agent', {
|
||||
modelEl.value = agent.model || 'sonnet';
|
||||
personaEl.value = agent.persona || '';
|
||||
instructionsEl.value = agent.instructions || '';
|
||||
toolChoiceEl.checked = (agent.toolChoice || 'any') === 'any';
|
||||
_agentAvatarData = agent.avatar || null;
|
||||
deleteBtn.hidden = false;
|
||||
|
||||
@@ -92,6 +94,7 @@ registerPage('agent', {
|
||||
model: modelEl.value,
|
||||
persona: personaEl.value,
|
||||
instructions: instructionsEl.value,
|
||||
toolChoice: toolChoiceEl.checked ? 'any' : 'auto',
|
||||
avatar: _agentAvatarData
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user