Skip to content

Commit 4984ab8

Browse files
committed
feat: support tool choice
1 parent 83dba6f commit 4984ab8

19 files changed

+342
-77
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Cnblogs.DashScope.Core;
2+
3+
/// <summary>
4+
/// Marks parameter supports setting maximum number of output tokens.
5+
/// </summary>
6+
public interface IMaxTokenParameter
7+
{
8+
/// <summary>
9+
/// The maximum number of tokens the model can generate.
10+
/// </summary>
11+
/// <remarks>
12+
/// Default and maximum number of tokens is 1500(qwen-turbo) or 2000(qwen-max, qwen-max-1201, qwen-max-longcontext, qwen-plus).
13+
/// </remarks>
14+
public int? MaxTokens { get; }
15+
}

src/Cnblogs.DashScope.Core/IMultimodalParameters.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,12 @@
33
/// <summary>
44
/// Optional parameters for multi-model generation request.
55
/// </summary>
6-
public interface IMultimodalParameters : IProbabilityParameter, ISeedParameter, IIncrementalOutputParameter;
6+
public interface IMultimodalParameters
7+
: IProbabilityParameter, ISeedParameter, IIncrementalOutputParameter, IPenaltyParameter, IMaxTokenParameter,
8+
IStopTokenParameter
9+
{
10+
/// <summary>
11+
/// Allow higher resolution for inputs. When setting to <c>true</c>, increases the maximum input token from 1280 to 16384. Defaults to <c>false</c>.
12+
/// </summary>
13+
public bool? VlHighResolutionImages { get; }
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Cnblogs.DashScope.Core;
2+
3+
/// <summary>
4+
/// Marks parameter accepts presence_penalty and repetition_penalty options.
5+
/// </summary>
6+
public interface IPenaltyParameter
7+
{
8+
/// <summary>
9+
/// Increasing the repetition penalty can reduce the amount of repetition in the model’s output. A value of 1.0 indicates no penalty, with the default set at 1.1.
10+
/// </summary>
11+
public float? RepetitionPenalty { get; }
12+
13+
/// <summary>
14+
/// Control the content repetition in text generated by the model.
15+
/// </summary>
16+
/// <remarks>Must be in [-2.0, 2.0]. Use higher penalty for batter creativity.</remarks>
17+
public float? PresencePenalty { get; }
18+
}

src/Cnblogs.DashScope.Core/IProbabilityParameter.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Cnblogs.DashScope.Core;
22

33
/// <summary>
4-
/// Marks parameter accepts top_p and top_k options.
4+
/// Marks parameter accepts top_p, top_k and temperature options.
55
/// </summary>
66
public interface IProbabilityParameter
77
{
@@ -16,4 +16,10 @@ public interface IProbabilityParameter
1616
/// </summary>
1717
/// <remarks>top_k would been disabled if applied null or any value larger than 100.</remarks>
1818
public int? TopK { get; }
19+
20+
/// <summary>
21+
/// Controls the diversity of generations. Lower temperature leads to more consistent result.
22+
/// </summary>
23+
/// <remarks>Must be in [0,2), qwen-max defaults to 0.7.</remarks>
24+
public float? Temperature { get; }
1925
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Cnblogs.DashScope.Core;
2+
3+
/// <summary>
4+
/// Marks parameter supports setting stop tokens.
5+
/// </summary>
6+
public interface IStopTokenParameter
7+
{
8+
/// <summary>
9+
/// Stop generation when next token or string is in given range.
10+
/// </summary>
11+
public TextGenerationStop? Stop { get; }
12+
}

src/Cnblogs.DashScope.Core/ITextGenerationParameters.cs

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
/// <summary>
44
/// The text generation options.
55
/// </summary>
6-
public interface ITextGenerationParameters : IIncrementalOutputParameter, ISeedParameter, IProbabilityParameter
6+
public interface ITextGenerationParameters
7+
: IIncrementalOutputParameter, ISeedParameter, IProbabilityParameter, IPenaltyParameter, IMaxTokenParameter, IStopTokenParameter
78
{
89
/// <summary>
910
/// The format of the result message, must be <c>text</c> or <c>message</c>.
@@ -14,30 +15,6 @@ public interface ITextGenerationParameters : IIncrementalOutputParameter, ISeedP
1415
/// </remarks>
1516
public string? ResultFormat { get; }
1617

17-
/// <summary>
18-
/// The maximum number of tokens the model can generate.
19-
/// </summary>
20-
/// <remarks>
21-
/// Default and maximum number of tokens is 1500(qwen-turbo) or 2000(qwen-max, qwen-max-1201, qwen-max-longcontext, qwen-plus).
22-
/// </remarks>
23-
public int? MaxTokens { get; }
24-
25-
/// <summary>
26-
/// Increasing the repetition penalty can reduce the amount of repetition in the model’s output. A value of 1.0 indicates no penalty, with the default set at 1.1.
27-
/// </summary>
28-
public float? RepetitionPenalty { get; }
29-
30-
/// <summary>
31-
/// Controls the diversity of generations. Lower temperature leads to more consistent result.
32-
/// </summary>
33-
/// <remarks>Must be in [0,2), defaults to 0.85.</remarks>
34-
public float? Temperature { get; }
35-
36-
/// <summary>
37-
/// Stop generation when next token or string is in given range.
38-
/// </summary>
39-
public TextGenerationStop? Stop { get; }
40-
4118
/// <summary>
4219
/// Enable internet search when generation. Defaults to false.
4320
/// </summary>
@@ -49,7 +26,7 @@ public interface ITextGenerationParameters : IIncrementalOutputParameter, ISeedP
4926
public IEnumerable<ToolDefinition>? Tools { get; }
5027

5128
/// <summary>
52-
///
29+
/// Behavior when choosing tools.
5330
/// </summary>
5431
public ToolChoice? ToolChoice { get; }
5532
}

src/Cnblogs.DashScope.Core/MultimodalParameters.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,27 @@ public class MultimodalParameters : IMultimodalParameters
1111
/// <inheritdoc />
1212
public int? TopK { get; set; }
1313

14+
/// <inheritdoc />
15+
public float? Temperature { get; set; }
16+
1417
/// <inheritdoc />
1518
public ulong? Seed { get; set; }
1619

1720
/// <inheritdoc />
1821
public bool? IncrementalOutput { get; set; }
22+
23+
/// <inheritdoc />
24+
public bool? VlHighResolutionImages { get; set; }
25+
26+
/// <inheritdoc />
27+
public float? RepetitionPenalty { get; set; }
28+
29+
/// <inheritdoc />
30+
public float? PresencePenalty { get; set; }
31+
32+
/// <inheritdoc />
33+
public int? MaxTokens { get; set; }
34+
35+
/// <inheritdoc />
36+
public TextGenerationStop? Stop { get; set; }
1937
}

src/Cnblogs.DashScope.Core/TextGenerationParameters.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class TextGenerationParameters : ITextGenerationParameters
2323
/// <inheritdoc />
2424
public float? RepetitionPenalty { get; set; }
2525

26+
/// <inheritdoc />
27+
public float? PresencePenalty { get; set; }
28+
2629
/// <inheritdoc />
2730
public float? Temperature { get; set; }
2831

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,47 @@
1-
namespace Cnblogs.DashScope.Core;
1+
using System.Text.Json.Serialization;
2+
3+
namespace Cnblogs.DashScope.Core;
24

35
/// <summary>
4-
/// Specify behavior when model
6+
/// Specify the behavior for model when tools are applied.
57
/// </summary>
6-
public record ToolChoice();
8+
[JsonConverter(typeof(ToolChoiceJsonConverter))]
9+
public record ToolChoice
10+
{
11+
/// <summary>
12+
/// Make sure tool choices can not be initiated directly.
13+
/// </summary>
14+
private ToolChoice(string type, ToolChoiceFunction? function = null)
15+
{
16+
Type = type;
17+
Function = function;
18+
}
19+
20+
/// <summary>
21+
/// The type of tool choice.
22+
/// </summary>
23+
public string Type { get; }
24+
25+
/// <summary>
26+
/// The function that model must call.
27+
/// </summary>
28+
public ToolChoiceFunction? Function { get; }
29+
30+
/// <summary>
31+
/// Model can not call any tools.
32+
/// </summary>
33+
public static readonly ToolChoice NoneChoice = new("none");
34+
35+
/// <summary>
36+
/// Model can freely pick between generating a message or calling one or more tools.
37+
/// </summary>
38+
public static readonly ToolChoice AutoChoice = new("auto");
39+
40+
/// <summary>
41+
/// Model must call function with specified name.
42+
/// </summary>
43+
/// <param name="functionName">Name of function.</param>
44+
/// <returns></returns>
45+
public static ToolChoice FunctionChoice(string functionName)
46+
=> new("function", new ToolChoiceFunction(functionName));
47+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Cnblogs.DashScope.Core;
2+
3+
/// <summary>
4+
/// Represents functions that model must call.
5+
/// </summary>
6+
/// <param name="Name">The name of the function.</param>
7+
public record ToolChoiceFunction(string Name);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Serialization;
3+
4+
namespace Cnblogs.DashScope.Core;
5+
6+
/// <summary>
7+
/// The converter for <see cref="ToolChoice"/>
8+
/// </summary>
9+
public class ToolChoiceJsonConverter : JsonConverter<ToolChoice>
10+
{
11+
/// <inheritdoc />
12+
public override ToolChoice? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
13+
{
14+
if (reader.TokenType == JsonTokenType.String)
15+
{
16+
var str = reader.GetString();
17+
return str switch
18+
{
19+
"auto" => ToolChoice.AutoChoice,
20+
"none" => ToolChoice.NoneChoice,
21+
_ => throw new JsonException("Unknown tool choice type")
22+
};
23+
}
24+
25+
if (reader.TokenType == JsonTokenType.Null)
26+
{
27+
return null;
28+
}
29+
30+
if (reader.TokenType != JsonTokenType.StartObject)
31+
{
32+
throw new JsonException("Unknown tool choice.");
33+
}
34+
35+
var element = JsonSerializer.Deserialize<JsonElement>(ref reader, options);
36+
var functionValid = element.TryGetProperty("function", out var function);
37+
var typeValid = element.TryGetProperty("type", out var type);
38+
if (functionValid == false || typeValid == false || type.ValueKind != JsonValueKind.String)
39+
{
40+
throw new JsonException("Unknown tool choice type");
41+
}
42+
43+
var toolFunction = function.Deserialize<ToolChoiceFunction>(options);
44+
var toolChoiceType = type.GetString();
45+
if (toolFunction == null || toolChoiceType != "function")
46+
{
47+
throw new JsonException("Unknown tool choice type");
48+
}
49+
50+
return ToolChoice.FunctionChoice(toolFunction.Name);
51+
}
52+
53+
/// <inheritdoc />
54+
public override void Write(Utf8JsonWriter writer, ToolChoice value, JsonSerializerOptions options)
55+
{
56+
if (value.Type != "function")
57+
{
58+
writer.WriteStringValue(value.Type);
59+
}
60+
else
61+
{
62+
writer.WriteStartObject();
63+
writer.WriteString("type", value.Type);
64+
writer.WritePropertyName("function");
65+
JsonSerializer.Serialize(writer, value.Function, options);
66+
writer.WriteEndObject();
67+
}
68+
}
69+
}

test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/multimodal-generation-vl-nosse.request.body.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
"parameters": {
2121
"seed": 1234,
2222
"top_k": 100,
23-
"top_p": 0.81
23+
"top_p": 0.81,
24+
"vl_high_resolution_images": true,
25+
"temperature": 1.1,
26+
"repetition_penalty": 1.3,
27+
"presence_penalty": 1.2,
28+
"max_tokens": 120,
29+
"stop": "你好"
2430
}
2531
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"output":{"choices":[{"finish_reason":"stop","message":{"role":"assistant","content":[{"text":"这张照片显示的是海滩景色,但是无法确定具体的位置信息。图中有一名女子和一只狗在沙滩上互动。背景中有海洋和日出或日落的光线。由于缺乏特定地标或者细节特征,仅凭此图像很难精确识别具体的地点。"}]}}]},"usage":{"output_tokens":58,"input_tokens":1284,"image_tokens":1247},"request_id":"a2a5f2e6-c6d7-9e04-9f92-1d3eee274198"}
1+
{"output":{"choices":[{"finish_reason":"stop","message":{"role":"assistant","content":[{"text":"这是在海滩上。"}]}}]},"usage":{"output_tokens":6,"input_tokens":3613,"image_tokens":3577},"request_id":"e74b364a-034f-9d0d-8e55-8e5b3580045f"}
Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
HTTP/1.1 200 OK
2-
eagleeye-traceid: cf6954f685a19435530858304250b3bc
3-
content-type: application/json
1+
HTTP/1.1 200 OK
2+
eagleeye-traceid: c72728928fd0d00883f6edd204cc6721
3+
Vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Accept-Encoding
4+
X-Request-ID: e74b364a-034f-9d0d-8e55-8e5b3580045f
5+
x-dashscope-timeout: 180
46
x-dashscope-call-gateway: true
5-
req-cost-time: 4359
6-
req-arrive-time: 1709019927268
7-
resp-start-time: 1709019931627
8-
x-envoy-upstream-service-time: 4353
9-
content-encoding: gzip
10-
vary: Accept-Encoding
11-
date: Tue, 27 Feb 2024 07:45:31 GMT
12-
server: istio-envoy
13-
transfer-encoding: chunked
7+
x-dashscope-finished: true
8+
req-cost-time: 3064
9+
req-arrive-time: 1732531979928
10+
resp-start-time: 1732531982993
11+
x-envoy-upstream-service-time: 3054
12+
Set-Cookie: acw_tc=e74b364a-034f-9d0d-8e55-8e5b3580045f47b5c24e3af603d8590358e45e4696a6;path=/;HttpOnly;Max-Age=1800
13+
Date: Mon, 25 Nov 2024 10:53:02 GMT
14+
Server: istio-envoy
15+
Transfer-Encoding: chunked

test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-message-with-tools-nosse.request.body.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
"top_p": 0.8,
1616
"top_k": 100,
1717
"repetition_penalty": 1.1,
18+
"presence_penalty": 1.2,
1819
"temperature": 0.85,
19-
"stop": [[37763, 367]],
20+
"stop": "你好",
2021
"enable_search": false,
2122
"incremental_output": false,
2223
"tools": [
@@ -46,6 +47,12 @@
4647
}
4748
}
4849
}
49-
]
50+
],
51+
"tool_choice": {
52+
"type": "function",
53+
"function": {
54+
"name": "get_current_weather"
55+
}
56+
}
5057
}
5158
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"output":{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","tool_calls":[{"function":{"name":"get_current_weather","arguments":"{\"location\": \"浙江省杭州市\", \"unit\": \"Celsius\"}"},"id":"","type":"function"}],"content":""}}]},"usage":{"total_tokens":36,"output_tokens":31,"input_tokens":5},"request_id":"40b4361e-e936-91b5-879d-355a45d670f8"}
1+
{"output":{"choices":[{"finish_reason":"stop","message":{"role":"assistant","tool_calls":[{"function":{"name":"get_current_weather","arguments":"{\"location\": \"浙江省杭州市\"}"},"index":0,"id":"call_cec4c19d27624537b583af","type":"function"}],"content":""}}]},"usage":{"total_tokens":219,"output_tokens":8,"input_tokens":211},"request_id":"67300049-c108-9987-b1c1-8e0ee2de6b5d"}

0 commit comments

Comments
 (0)