開発者として LLM を使用する場合、構造化された形式でデータを受信したいことがよくあります。 GPT-3 の初期の時代にはこれが常にうまく機能していたわけではありませんでしたが、関数呼び出しをサポートする現在のモデルでははるかに優れています。
この投稿では、CallClaudeForceTool という単純な関数を共有したいと思います。この関数を使用すると、Claude を呼び出して構造化データ/JSON 出力を受け取ることができます。私の場合、これは Golang で書かれており、必要な任意のタイプの構造体を返します。
まず、構造を定義し、それを JSON スキーマの形式で LLM に提供する必要があります。この例では、データをクエリする関数への入力として機能する構造体型を定義しています。
クエリ関数への入力である構造体は次のとおりです。
type QueryArgs struct { SearchQuery string `json:"searchQuery,omitempty"` TypeFilter string `json:"typeFilter,omitempty"` }
以下は JSON スキーマの定義です。 LLM は JSON データを生成するときにこの情報を使用するため、ここでは適切な名前と説明を追加することが実際に重要です。
var QueryFnSchema = JSONSchema{ Type: ai.DataTypeObject, Properties: map[string]ai.JSONSchema{ "searchQuery": { Type: ai.DataTypeString, Description: "The search text query to use. Any data that contains this text will be searched. If not provided, then no text comparison will be performed.", }, "typeFilter": { Type: ai.DataTypeString, Description: `The type to filter on. If not provided, data of any type will be searched. Can only be one of: "location", "event", "person", "organization".`, Enum: []string{"location", "event", "person", "organization"}, }, }, } type JSONSchema struct { Type DataType `json:"type,omitempty"` Description string `json:"description,omitempty"` Enum []string `json:"enum,omitempty"` Properties map[string]JSONSchema `json:"properties,omitempty"` Required []string `json:"required,omitempty"` Items *JSONSchema `json:"items,omitempty"` } func (d JSONSchema) MarshalJSON() ([]byte, error) { if d.Properties == nil { d.Properties = make(map[string]JSONSchema) } type Alias JSONSchema return json.Marshal(struct { Alias }{ Alias: (Alias)(d), }) } type DataType string const ( DataTypeObject DataType = "object" DataTypeNumber DataType = "number" DataTypeInteger DataType = "integer" DataTypeBoolean DataType = "boolean" DataTypeString DataType = "string" DataTypeArray DataType = "array" DataTypeNull DataType = "null" )
単純な JSON スキーマ構造体を使用しています。そのために依存関係を使用することもできますが、LLM 関数の呼び出しには通常、この構造体で十分です。 Anthropic の Claude および OpenAI の ChatGPT とうまく連携します。
QueryArgs に相当するもの、または必要で LLM に応答させたいデータに基づいて、QueryFnSchema の代わりに独自のスキーマを定義します。
次は CallClaudeForceTool 関数を使用します (これについては投稿の最後で説明します)。
func main() { // ... queryArgs, claudeResponse := CallClaudeForceTool[QueryArgs]([]ClaudeLLMMessage{ {Role: "user", Content: getQueryPrompt(inputMessage)}, }, ToolDefinition{ Name: "search", Description: "Search for data in the database", InputSchema: queryFnSchema, }, ClaudeConfig{ MaxTokens: 4000, Temperature: 0.8, System: SYSTEM_PROMPT, }) result := db.Query(queryArgs) // ... }
getQueryPrompt(inputMessage) 、 SYSTEM_PROMPT およびその他の構成を独自のニーズに置き換えます。
queryArgs 変数には、定義した形式で LLM で生成されたデータが含まれています。これは、私の場合は QueryArgs 構造体です。この時点で、データベースをクエリするための実際の関数呼び出しのパラメーターとしてそれを使用します。ただし、入力またはプロンプトから構造化データを生成し、それをコードで使用することもできます。
最後に、CallClaudeForceTool 関数と補助タイプを示します。その目標は、Claude を呼び出し、提供された 1 つのツールの使用を強制し、後続のツール/関数出力で Claude に応答したり、最終応答テキスト メッセージを受け取ったりすることなく終了することです。クロードに構造化データを 1 回応答してもらいたいだけです。
func CallClaudeForceTool[T any](messages []ClaudeLLMMessage, tool ToolDefinition, config ClaudeConfig) (T, *ClaudeCreateMessageResponse, error) { payload := ClaudeCreateMessagePayload{ Model: "claude-3-5-sonnet-20240620", Messages: messages, Tools: []ToolDefinition{tool}, ToolChoice: ClaudeToolChoice{ Type: ToolChoiceTypeTool, Name: tool.Name, }, MaxTokens: config.MaxTokens, Temperature: config.Temperature, System: config.System, } payloadBytes, err := json.Marshal(payload) if err != nil { return *new(T), nil, fmt.Errorf("impossible to marshal payload: %w", err) } req, err := http.NewRequest( http.MethodPost, "https://api.anthropic.com/v1/messages", bytes.NewReader(payloadBytes), ) if err != nil { return *new(T), nil, fmt.Errorf("impossible to create request: %w", err) } req.Header.Set("x-api-key", os.Getenv("ANTHROPIC_API_KEY")) req.Header.Set("content-type", "application/json") req.Header.Set("anthropic-version", "2023-06-01") // send the request httpClient := http.Client{Timeout: 60 * time.Second} res, err := httpClient.Do(req) if err != nil { return *new(T), nil, fmt.Errorf("impossible to send request: %w", err) } defer res.Body.Close() resBody, err := io.ReadAll(res.Body) if err != nil { return *new(T), nil, fmt.Errorf("impossible to read all body of response: %w", err) } // unmarshal the response var response ClaudeCreateMessageResponse err = json.Unmarshal(resBody, &response) if err != nil { return *new(T), nil, fmt.Errorf("impossible to unmarshal response: %w", err) } // Get the tool response var toolInput T for _, content := range response.Content { if content.Type != ClaudeResponseContentTypeToolUse || content.Name != tool.Name { continue } inputBytes, err := json.Marshal(content.Input) if err != nil { return *new(T), &response, fmt.Errorf("impossible to marshal tool response: %w", err) } err = json.Unmarshal(inputBytes, &toolInput) if err != nil { return *new(T), &response, fmt.Errorf("impossible to unmarshal tool response: %w", err) } return toolInput, &response, nil } return toolInput, &response, fmt.Errorf("impossible to find tool response") } // Auxiliary types type ClaudeLLMMessage struct { Role string `json:"role"` Content string `json:"content"` } type ClaudeConfig struct { MaxTokens int Temperature float64 System string } type ClaudeCreateMessagePayload struct { Model string `json:"model"` MaxTokens int `json:"max_tokens"` Messages []ClaudeLLMMessage `json:"messages"` Stream bool `json:"stream,omitempty"` System string `json:"system,omitempty"` Temperature float64 `json:"temperature,omitempty"` ToolChoice ClaudeToolChoice `json:"tool_choice,omitempty"` Tools []ToolDefinition `json:"tools,omitempty"` } type ClaudeCreateMessageResponse struct { Content []struct { Type ClaudeResponseContentType `json:"type"` Text string `json:"text,omitempty"` ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Input map[string]interface{} `json:"input,omitempty"` } `json:"content"` Id string `json:"id"` Model string `json:"model"` Role string `json:"role"` StopReason string `json:"stop_reason"` StopSequence string `json:"stop_sequence"` Type string `json:"type"` Usage struct { InputTokens int `json:"input_tokens"` OutputTokens int `json:"output_tokens"` } `json:"usage"` } type ClaudeToolChoice struct { Type ToolChoiceType `json:"type"` Name string `json:"name,omitempty"` } type ToolChoiceType string const ( ToolChoiceTypeAuto ToolChoiceType = "auto" ToolChoiceTypeCode ToolChoiceType = "any" ToolChoiceTypeTool ToolChoiceType = "tool" ) type ToolDefinition struct { Name string `json:"name"` Description string `json:"description"` InputSchema JSONSchema `json:"input_schema"` }
これが使用できる例をいくつか示します:
私の例で示した関数の呼び出し。これは、おそらく LLM の「関数呼び出し」の最も明白な使用例です。
API リクエストの構造化データの生成: LLM を使用して、ユーザー入力に基づいて API リクエストの JSON ペイロードを生成し、データが必要なスキーマに準拠していることを確認できます。
データの検証と変換: LLM を使用すると、入力データを検証して構造化形式に変換し、その後の処理やデータベースへの保存に使用できます。
一般に、独自のカスタム分類子をトレーニングせずに、テキストがあり、それを抽出または特定の構造に変換したいときはいつでも使用できます。
それだけです!これが役に立ったかどうかお知らせください。あるいは、アプリケーションで LLM をどのように使用しているかを共有してください。
ビス・デムナクスト!
~ マーティン
メモ:
これはもともと私のブログ (https://blog.embiem.me/unleash-your-home-hardware-processing-long-running-tasks-at-home) に投稿されたものです
すべてのコードは、MIT ライセンスに基づいて現状のまま提供されます。
カバー画像は AI によって生成されました。
以上がGo でクロードから有効な JSON を一貫して取得する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。