reasoning_content)的保留范围从“同一个用户提问轮内”进一步扩展到“跨用户提问轮”。当用户在后续轮次继续追问时,先前的推理草稿仍可保留并延续,从而在 Agent、Coding 等长流程、多轮任务中保持推理连续性、提升模型效果,并因上下文前缀更稳定而提高缓存命中率、节省 token。low / high)+ 工具调用(tool call)的跨轮次场景,例如:
reasoning_content 以延续思维链”这一核心机制,主要差异在于保留的范围不同。开发者对两种模式的操作方式是一致的——都是把模型返回的 reasoning_content 原样回填到下一次请求。概念 | 思考内容的保留范围 | 通俗理解 |
交错式思考(Interleaved) | 同一个用户提问轮(User turn)内 | 类似做同一道题时中途查资料:模型先写一段解题草稿,开发者在工具结果返回时把这份草稿原样带回,模型才能接着刚才的思路继续做。本轮结束后,下一轮用户提问不再带回这道题的草稿。 |
保留式思考(Preserved) | 跨用户提问轮(User turn) | 类似把每道题的解题草稿都收好:后续用户继续追问时,开发者把相关历史草稿原样带回请求里,模型继续参考回答。 |
hy3 协议 | 开关方式 | 参考示例 |
OpenAI Chat Completions | 请求体顶层字段 preserved_thinking | {"reasoning_effort":"high","preserved_thinking":true} |
OpenAI Responses | reasoning 对象内字段 preserved_thinking | {"reasoning":{"effort":"high","preserved_thinking":true}} |
Anthropic | 请求头 HY-Preserved-Thinking取值为 true / false / 为空或不传:明确传 true 为开启、false 为关闭;为空或不传时采用 API 默认策略;传入非法值会报错。 | HY-Preserved-Thinking: true |
preserved_thinking,平台会自动采用最优策略处理。tools(工具调用场景)时:默认开启保留式思考。tools(纯文本对话场景)时:默认关闭。tools 数组注册(如写在 system prompt 中),此时平台无法自动识别为工具调用场景,可手动设置 preserved_thinking: true。更推荐的做法是仍将工具按标准方式注册到 tools 数组中,既能复用平台策略,也能获得最佳的模型效果。preserved_thinking 参数仅控制保留式思考的启停,不会自动处理历史 reasoning_content 的回填。开发者需要将模型上一轮返回的完整、未经修改的 reasoning_content 与工具结果一并原样回填给 API,否则可能影响模型效果,并降低缓存命中率。字段 | 位置 | 说明 |
reasoning_effort | 请求 | 思考深度,取值 no_think / low / high |
preserved_thinking | 请求 | 保留式思考开关, true / false。不传时由平台按默认策略处理 |
reasoning_content | 响应(需回填) | 模型的思考过程,需在后续请求中原样回填 |
tool_calls | 响应(需回填) | 模型输出的工具调用指令 |
content | 响应 | 最终回答内容 |
reasoning_content 必须与模型生成时完全一致,不要改写、截断或重新排序,否则会降低效果并影响缓存命中率。reasoning_content 放回它所属的那条 assistant 消息中(与 content、tool_calls 同级)。reasoning_content。tools 列表),保留式思考默认开启。reasoning_contenttool_callsrole=tool 回填,并将上一步 assistant 消息(含 reasoning_content 与 tool_calls)原样加入 messages 数组,再次发起请求。reasoning_content)原样保留在 messages 中,这是保留式思考与交错式思考最核心的差异。get_user_groups(查用户所属的组)、get_group_permissions(查某个组对各资源的权限)。用户分三轮提问,每一轮都保留此前轮的思考:Alice 属于哪些用户组?这些组分别有什么权限?综合看,Alice 对"生产数据库"到底是什么权限?YOUR_API_KEY 替换为您真实的 API Key。如您还没有 API Key,请参见 创建 API Key。curl -X POST 'https://tokenhub-intl.tencentcloudmaas.com/v1/chat/completions' \\-H 'Content-Type: application/json' \\-H 'Authorization: Bearer YOUR_API_KEY' \\-d '{"model": "hy3","stream": false,"reasoning_effort": "high","tool_choice": "auto","messages": [{ "role": "system", "content": "你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。" },{ "role": "user", "content": "Alice 属于哪些用户组?" }],"tools": [{"type": "function","function": {"name": "get_user_groups","description": "查询某个用户所属的所有用户组。","parameters": {"type": "object","properties": {"user": { "type": "string" }},"required": ["user"]}}},{"type": "function","function": {"name": "get_group_permissions","description": "查询某个用户组对各资源的访问权限。","parameters": {"type": "object","properties": {"group": { "type": "string" }},"required": ["group"]}}}]}'
from openai import OpenAIclient = OpenAI(api_key="YOUR_API_KEY",base_url="https://tokenhub-intl.tencentcloudmaas.com/v1",)tools = [{"type": "function","function": {"name": "get_user_groups","description": "查询某个用户所属的所有用户组。","parameters": {"type": "object","properties": {"user": {"type": "string"},},"required": ["user"],},},},{"type": "function","function": {"name": "get_group_permissions","description": "查询某个用户组对各资源的访问权限。","parameters": {"type": "object","properties": {"group": {"type": "string"},},"required": ["group"],},},},]messages = [{"role": "system", "content": "你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。"},{"role": "user", "content": "Alice 属于哪些用户组?"},]# 携带 tools 时,hy3 默认开启保留式思考。# 如需显式控制,可在 extra_body 中传 preserved_thinking: True/Falseresp1 = client.chat.completions.create(model="hy3",messages=messages,tools=tools,tool_choice="auto",extra_body={"reasoning_effort": "high"},)msg1 = resp1.choices[0].messageprint("第 1 轮 reasoning_content:", getattr(msg1, "reasoning_content", ""))print("第 1 轮 tool_calls:", msg1.tool_calls)
import OpenAI from 'openai';const client = new OpenAI({apiKey: 'YOUR_API_KEY',baseURL: 'https://tokenhub-intl.tencentcloudmaas.com/v1',});const tools = [{type: 'function',function: {name: 'get_user_groups',description: '查询某个用户所属的所有用户组。',parameters: {type: 'object',properties: {user: { type: 'string' },},required: ['user'],},},},{type: 'function',function: {name: 'get_group_permissions',description: '查询某个用户组对各资源的访问权限。',parameters: {type: 'object',properties: {group: { type: 'string' },},required: ['group'],},},},];const messages = [{ role: 'system', content: '你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。' },{ role: 'user', content: 'Alice 属于哪些用户组?' },];const resp1 = await client.chat.completions.create({model: 'hy3',messages,tools,tool_choice: 'auto',reasoning_effort: 'high',});const msg1 = resp1.choices[0].message;console.log('第 1 轮 reasoning_content:', msg1.reasoning_content);console.log('第 1 轮 tool_calls:', msg1.tool_calls);
import okhttp3.*;import com.google.gson.*;import java.util.*;public class PreservedThinking {static final String URL = "https://tokenhub-intl.tencentcloudmaas.com/v1/chat/completions";static final String API_KEY = "YOUR_API_KEY";static final OkHttpClient HTTP = new OkHttpClient();static final Gson GSON = new Gson();/** 通用 chat 调用,返回原始 JSON 响应字符串。 */static String chat(List<Map<String, Object>> messages, List<Map<String, Object>> tools) throws Exception {Map<String, Object> body = new HashMap<>();body.put("model", "hy3");body.put("messages", messages);body.put("tools", tools);body.put("tool_choice", "auto");body.put("reasoning_effort", "high");body.put("stream", false);// 显式控制可加:body.put("preserved_thinking", true);Request req = new Request.Builder().url(URL).header("Authorization", "Bearer " + API_KEY).post(RequestBody.create(GSON.toJson(body), MediaType.parse("application/json"))).build();try (Response resp = HTTP.newCall(req).execute()) {return resp.body().string();}}public static void main(String[] args) throws Exception {List<Map<String, Object>> tools = List.of(Map.of("type", "function","function", Map.of("name", "get_user_groups","description", "查询某个用户所属的所有用户组。","parameters", Map.of("type", "object","properties", Map.of("user", Map.of("type", "string")),"required", List.of("user")))),Map.of("type", "function","function", Map.of("name", "get_group_permissions","description", "查询某个用户组对各资源的访问权限。","parameters", Map.of("type", "object","properties", Map.of("group", Map.of("type", "string")),"required", List.of("group")))));List<Map<String, Object>> messages = new ArrayList<>();messages.add(Map.of("role", "system", "content", "你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。"));messages.add(Map.of("role", "user", "content", "Alice 属于哪些用户组?"));// 第 1 轮:模型决定是否调用工具String r1 = chat(messages, tools);System.out.println("第 1 轮响应:" + r1);// 后续按响应里的 reasoning_content / tool_calls 回填到 messages,见第 2 步}}
package mainimport ("bytes""encoding/json""fmt""io""net/http")const (URL = "https://tokenhub-intl.tencentcloudmaas.com/v1/chat/completions"APIKEY = "YOUR_API_KEY")// 通用 chat 调用func chat(messages []map[string]interface{}, tools []map[string]interface{}) (map[string]interface{}, error) {body, _ := json.Marshal(map[string]interface{}{"model": "hy3","messages": messages,"tools": tools,"tool_choice": "auto","reasoning_effort": "high","stream": false,// 显式控制可加:"preserved_thinking": true,})req, _ := http.NewRequest("POST", URL, bytes.NewBuffer(body))req.Header.Set("Authorization", "Bearer "+APIKEY)req.Header.Set("Content-Type", "application/json")resp, err := http.DefaultClient.Do(req)if err != nil {return nil, err}defer resp.Body.Close()data, _ := io.ReadAll(resp.Body)var out map[string]interface{}json.Unmarshal(data, &out)return out, nil}func main() {tools := []map[string]interface{}{{"type": "function","function": map[string]interface{}{"name": "get_user_groups","description": "查询某个用户所属的所有用户组。","parameters": map[string]interface{}{"type": "object","properties": map[string]interface{}{"user": map[string]string{"type": "string"},},"required": []string{"user"},},},},{"type": "function","function": map[string]interface{}{"name": "get_group_permissions","description": "查询某个用户组对各资源的访问权限。","parameters": map[string]interface{}{"type": "object","properties": map[string]interface{}{"group": map[string]string{"type": "string"},},"required": []string{"group"},},},},}messages := []map[string]interface{}{{"role": "system", "content": "你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。"},{"role": "user", "content": "Alice 属于哪些用户组?"},}// 第 1 轮:模型决定是否调用工具r1, _ := chat(messages, tools)fmt.Printf("第 1 轮响应: %+v\\n", r1)// 后续按响应里的 reasoning_content / tool_calls 回填到 messages,见第 2 步}
get_user_groups。{"id": "REPLACED_ID","object": "chat.completion","created": 1783084572,"model": "hy3","choices": [{"index": 0,"message": {"role": "assistant","content": "我来查询 Alice 所属的用户组。","reasoning_content": "用户问 Alice 属于哪些用户组。我需要调用 get_user_groups 工具来查询 Alice 所属的用户组。只有一个调用,没有依赖。","tool_calls": [{"id": "chatcmpl-tool-93cc85d5f381f88d","type": "function","function": {"name": "get_user_groups","arguments": "{\\"user\\": \\"Alice\\"}"}}]},"finish_reason": "tool_calls"}],"usage": {"prompt_tokens": 289,"completion_tokens": 60,"total_tokens": 349,"completion_tokens_details": { "reasoning_tokens": 31 }}}
reasoning_content)与工具结果一起回填。假设 get_user_groups 返回 ["Engineering","OnCall"]:curl -X POST 'https://tokenhub-intl.tencentcloudmaas.com/v1/chat/completions' \\-H 'Content-Type: application/json' \\-H 'Authorization: Bearer YOUR_API_KEY' \\-d '{"model": "hy3","stream": false,"reasoning_effort": "high","tool_choice": "auto","messages": [{ "role": "system", "content": "你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。" },{ "role": "user", "content": "Alice 属于哪些用户组?" },{ "role": "assistant", "content": "我来查询 Alice 所属的用户组。","reasoning_content": "用户问 Alice 属于哪些用户组。我需要调用 get_user_groups 工具来查询 Alice 所属的用户组。只有一个调用,没有依赖。","tool_calls": [{ "id": "chatcmpl-tool-93cc85d5f381f88d", "type": "function","function": { "name": "get_user_groups", "arguments": "{\\"user\\": \\"Alice\\"}" } }] },{ "role": "tool", "tool_call_id": "chatcmpl-tool-93cc85d5f381f88d","content": "{\\"user\\": \\"Alice\\", \\"groups\\": [\\"Engineering\\", \\"OnCall\\"]}" }],"tools": [ /* 同上,省略 */ ]}'
# 接续 step1:把第 1 轮的 assistant 消息(含 reasoning_content + tool_calls)# 与工具结果一起回填到 messagesimport json# 第 1 轮 assistant 消息的回写:reasoning_content 必须保留assistant_msg = {"role": "assistant","content": msg1.content or "","reasoning_content": getattr(msg1, "reasoning_content", ""),"tool_calls": [{"id": tc.id,"type": tc.type,"function": {"name": tc.function.name,"arguments": tc.function.arguments,},} for tc in (msg1.tool_calls or [])],}messages.append(assistant_msg)# 业务侧执行 get_user_groups,把结果以 role=tool 回填for tc in (msg1.tool_calls or []):# 这里替换为真实业务逻辑tool_result = json.dumps({"user": "Alice", "groups": ["Engineering", "OnCall"]}, ensure_ascii=False)messages.append({"role": "tool","tool_call_id": tc.id,"content": tool_result,})# 第 2 轮:把工具结果送回模型,模型继续思考resp2 = client.chat.completions.create(model="hy3",messages=messages,tools=tools,tool_choice="auto",extra_body={"reasoning_effort": "high"},)msg2 = resp2.choices[0].messageprint("第 2 轮 reasoning_content:", getattr(msg2, "reasoning_content", ""))print("第 2 轮 content:", msg2.content)
// 接续 step1:把第 1 轮 assistant 消息与工具结果回填const assistantMsg = {role: 'assistant',content: msg1.content || '',reasoning_content: msg1.reasoning_content,tool_calls: msg1.tool_calls,};messages.push(assistantMsg);for (const tc of msg1.tool_calls || []) {// 这里替换为真实业务逻辑const toolResult = JSON.stringify({ user: 'Alice', groups: ['Engineering', 'OnCall'] });messages.push({role: 'tool',tool_call_id: tc.id,content: toolResult,});}const resp2 = await client.chat.completions.create({model: 'hy3',messages,tools,tool_choice: 'auto',reasoning_effort: 'high',});const msg2 = resp2.choices[0].message;console.log('第 2 轮 reasoning_content:', msg2.reasoning_content);console.log('第 2 轮 content:', msg2.content);
// 接续 main():把第 1 轮 assistant 消息与工具结果回填,再发起第 2 轮请求// 完整流程示意(仅展示消息构造,HTTP 调用复用 chat() 函数)// 1. 解析第 1 轮响应JsonObject r1Obj = JsonParser.parseString(r1).getAsJsonObject();JsonObject msg1 = r1Obj.getAsJsonArray("choices").get(0).getAsJsonObject().getAsJsonObject("message");// 2. 把 assistant 消息(含 reasoning_content)整体回写到 messagesMap<String, Object> assistantEntry = new LinkedHashMap<>();assistantEntry.put("role", "assistant");assistantEntry.put("content", msg1.has("content") ? msg1.get("content").getAsString() : "");if (msg1.has("reasoning_content")) {assistantEntry.put("reasoning_content", msg1.get("reasoning_content").getAsString());}if (msg1.has("tool_calls")) {assistantEntry.put("tool_calls", GSON.fromJson(msg1.get("tool_calls"), List.class));}messages.add(assistantEntry);// 3. 业务侧执行 get_user_groups,把结果以 role=tool 回填for (JsonElement el : msg1.getAsJsonArray("tool_calls")) {JsonObject call = el.getAsJsonObject();// 这里替换为真实业务逻辑String toolResult = "{\\"user\\": \\"Alice\\", \\"groups\\": [\\"Engineering\\", \\"OnCall\\"]}";messages.add(Map.of("role", "tool","tool_call_id", call.get("id").getAsString(),"content", toolResult));}// 4. 第 2 轮:把工具结果送回模型String r2 = chat(messages, tools);System.out.println("第 2 轮响应:" + r2);
// 接续 main():把第 1 轮 assistant 消息与工具结果回填,再发起第 2 轮请求// 1. 从第 1 轮响应中取出 assistant 消息msg1Wrap := r1["choices"].([]interface{})[0].(map[string]interface{})msg1 := msg1Wrap["message"].(map[string]interface{})// 2. 把 assistant 消息(含 reasoning_content)整体回写到 messagesmessages = append(messages, msg1)// 3. 业务侧执行 get_user_groups,把结果以 role=tool 回填toolCalls, _ := msg1["tool_calls"].([]interface{})for _, c := range toolCalls {call := c.(map[string]interface{})// 这里替换为真实业务逻辑toolResult := `{"user": "Alice", "groups": ["Engineering", "OnCall"]}`messages = append(messages, map[string]interface{}{"role": "tool","tool_call_id": call["id"],"content": toolResult,})}// 4. 第 2 轮:把工具结果送回模型r2, _ := chat(messages, tools)fmt.Printf("第 2 轮响应: %+v\\n", r2)
finish_reason=stop:{"id": "REPLACED_ID","object": "chat.completion","created": 1783084576,"model": "hy3","choices": [{"index": 0,"message": {"role": "assistant","content": "根据查询结果,Alice 属于以下两个用户组:\\n\\n- **Engineering**\\n- **OnCall**\\n\\n所以 Alice 同时是 Engineering 组和 OnCall 组的成员。","reasoning_content": "根据工具返回结果,Alice 属于 Engineering 和 OnCall 两个用户组。"},"finish_reason": "stop"}],"usage": {"prompt_tokens": 375,"completion_tokens": 54,"total_tokens": 429,"prompt_tokens_details": { "cached_tokens": 320 },"completion_tokens_details": { "reasoning_tokens": 18 }}}
reasoning_content 等上下文原样保留再次发起请求:curl -X POST 'https://tokenhub-intl.tencentcloudmaas.com/v1/chat/completions' \\-H 'Content-Type: application/json' \\-H 'Authorization: Bearer YOUR_API_KEY' \\-d '{"model": "hy3","stream": false,"reasoning_effort": "high","tool_choice": "auto","messages": [{ "role": "system", "content": "你是一个企业 IT 权限助理 Agent,通过调用工具查询组织与权限数据来回答问题。请始终用中文进行逐步推理与思考。" },{ "role": "user", "content": "Alice 属于哪些用户组?" },{ "role": "assistant", "content": "我来查询 Alice 所属的用户组。","reasoning_content": "用户问 Alice 属于哪些用户组。我需要调用 get_user_groups 工具来查询 Alice 所属的用户组。只有一个调用,没有依赖。","tool_calls": [{ "id": "chatcmpl-tool-93cc85d5f381f88d", "type": "function","function": { "name": "get_user_groups", "arguments": "{\\"user\\": \\"Alice\\"}" } }] },{ "role": "tool", "tool_call_id": "chatcmpl-tool-93cc85d5f381f88d","content": "{\\"user\\": \\"Alice\\", \\"groups\\": [\\"Engineering\\", \\"OnCall\\"]}" },{ "role": "assistant","content": "根据查询结果,Alice 属于以下两个用户组:\\n\\n- **Engineering**\\n- **OnCall**\\n\\n所以 Alice 同时是 Engineering 组和 OnCall 组的成员。","reasoning_content": "根据工具返回结果,Alice 属于 Engineering 和 OnCall 两个用户组。" },{ "role": "user", "content": "这些组分别有哪些资源的访问权限?" }],"tools": [ /* 同上,省略 */ ]}'
# 接续 step2:把第 2 轮 assistant 消息(含 reasoning_content)追加到 messages,# 然后追加第 2 轮用户提问,再次发起请求messages.append({"role": "assistant","content": msg2.content or "","reasoning_content": getattr(msg2, "reasoning_content", ""),})messages.append({"role": "user", "content": "这些组分别有哪些资源的访问权限?"})resp3 = client.chat.completions.create(model="hy3",messages=messages,tools=tools,tool_choice="auto",extra_body={"reasoning_effort": "high"},)msg3 = resp3.choices[0].messageprint("第 3 轮 reasoning_content:", getattr(msg3, "reasoning_content", ""))print("第 3 轮 tool_calls:", msg3.tool_calls)
// 接续 step2:把第 2 轮 assistant 消息(含 reasoning_content)追加到 messages,// 然后追加第 2 轮用户提问,再次发起请求messages.push({role: 'assistant',content: msg2.content || '',reasoning_content: msg2.reasoning_content,});messages.push({ role: 'user', content: '这些组分别有哪些资源的访问权限?' });const resp3 = await client.chat.completions.create({model: 'hy3',messages,tools,tool_choice: 'auto',reasoning_effort: 'high',});const msg3 = resp3.choices[0].message;console.log('第 3 轮 reasoning_content:', msg3.reasoning_content);console.log('第 3 轮 tool_calls:', msg3.tool_calls);
// 接续第 2 轮响应 r2:把第 2 轮 assistant 消息(含 reasoning_content)追加到 messagesJsonObject r2Obj = JsonParser.parseString(r2).getAsJsonObject();JsonObject msg2 = r2Obj.getAsJsonArray("choices").get(0).getAsJsonObject().getAsJsonObject("message");Map<String, Object> assistant2 = new LinkedHashMap<>();assistant2.put("role", "assistant");assistant2.put("content", msg2.has("content") ? msg2.get("content").getAsString() : "");if (msg2.has("reasoning_content")) {assistant2.put("reasoning_content", msg2.get("reasoning_content").getAsString());}messages.add(assistant2);// 追加第 2 轮用户提问messages.add(Map.of("role", "user", "content", "这些组分别有哪些资源的访问权限?"));// 第 3 轮:把新提问送回模型String r3 = chat(messages, tools);System.out.println("第 3 轮响应:" + r3);
// 接续第 2 轮响应 r2:把第 2 轮 assistant 消息(含 reasoning_content)追加到 messagesmsg2Wrap := r2["choices"].([]interface{})[0].(map[string]interface{})msg2 := msg2Wrap["message"].(map[string]interface{})messages = append(messages, msg2)// 追加第 2 轮用户提问messages = append(messages, map[string]interface{}{"role": "user","content": "这些组分别有哪些资源的访问权限?",})// 第 3 轮:把新提问送回模型r3, _ := chat(messages, tools)fmt.Printf("第 3 轮响应: %+v\\n", r3)
get_group_permissions 调用(本轮并行发起两个工具调用):{"id": "REPLACED_ID","object": "chat.completion","created": 1783084580,"model": "hy3","choices": [{"index": 0,"message": {"role": "assistant","content": "我来查询这两个用户组各自的资源访问权限。","reasoning_content": "用户想知道 Alice 所属的两个组(Engineering 和 OnCall)分别有哪些资源的访问权限。我需要调用 get_group_permissions 工具来查询这两个组的权限。这两个调用之间没有依赖关系,可以同时进行。","tool_calls": [{"id": "chatcmpl-tool-83653bb310744682","type": "function","function": {"name": "get_group_permissions","arguments": "{\\"group\\": \\"Engineering\\"}"}},{"id": "chatcmpl-tool-b2ee9d73aef14658","type": "function","function": {"name": "get_group_permissions","arguments": "{\\"group\\": \\"OnCall\\"}"}}]},"finish_reason": "tool_calls"}],"usage": {"prompt_tokens": 440,"completion_tokens": 94,"total_tokens": 534,"prompt_tokens_details": { "cached_tokens": 400 },"completion_tokens_details": { "reasoning_tokens": 44 }}}
curl -X POST 'https://tokenhub-intl.tencentcloudmaas.com/v1/chat/completions' \\-H 'Content-Type: application/json' \\-H 'Authorization: Bearer YOUR_API_KEY' \\-d '{"model": "hy3","stream": false,"reasoning_effort": "high","tool_choice": "auto","messages": [/* …前 6 条消息同上,保留全部 reasoning_content,省略… */{ "role": "assistant", "content": "我来查询这两个用户组各自的资源访问权限。","reasoning_content": "用户想知道 Alice 所属的两个组(Engineering 和 OnCall)分别有哪些资源的访问权限。……这两个调用之间没有依赖关系,可以同时进行。","tool_calls": [{ "id": "chatcmpl-tool-83653bb310744682", "type": "function","function": { "name": "get_group_permissions", "arguments": "{\\"group\\": \\"Engineering\\"}" } },{ "id": "chatcmpl-tool-b2ee9d73aef14658", "type": "function","function": { "name": "get_group_permissions", "arguments": "{\\"group\\": \\"OnCall\\"}" } }] },{ "role": "tool", "tool_call_id": "chatcmpl-tool-83653bb310744682","content": "{\\"group\\": \\"Engineering\\", \\"permissions\\": [{\\"resource\\": \\"生产数据库\\", \\"access\\": \\"read-only\\"}, {\\"resource\\": \\"staging环境\\", \\"access\\": \\"read-write\\"}, {\\"resource\\": \\"内部Wiki\\", \\"access\\": \\"read-write\\"}]}" },{ "role": "tool", "tool_call_id": "chatcmpl-tool-b2ee9d73aef14658","content": "{\\"group\\": \\"OnCall\\", \\"permissions\\": [{\\"resource\\": \\"告警系统\\", \\"access\\": \\"read-write\\"}, {\\"resource\\": \\"生产数据库\\", \\"access\\": \\"read-write\\"}]}" }],"tools": [ /* 同上,省略 */ ]}'
# 接续 step3:把第 3 轮的 assistant 消息(含 reasoning_content + tool_calls)回写,# 然后对两个 tool_call 并行回填工具结果import jsonassistant_msg3 = {"role": "assistant","content": msg3.content or "","reasoning_content": getattr(msg3, "reasoning_content", ""),"tool_calls": [{"id": tc.id,"type": tc.type,"function": {"name": tc.function.name,"arguments": tc.function.arguments,},} for tc in (msg3.tool_calls or [])],}messages.append(assistant_msg3)# 业务侧并行执行 get_group_permissions,把两个结果依次回填tool_results = {"Engineering": {"group": "Engineering","permissions": [{"resource": "生产数据库", "access": "read-only"},{"resource": "staging环境", "access": "read-write"},{"resource": "内部Wiki", "access": "read-write"},],},"OnCall": {"group": "OnCall","permissions": [{"resource": "告警系统", "access": "read-write"},{"resource": "生产数据库", "access": "read-write"},],},}for tc in (msg3.tool_calls or []):args = json.loads(tc.function.arguments)result = tool_results[args["group"]]messages.append({"role": "tool","tool_call_id": tc.id,"content": json.dumps(result, ensure_ascii=False),})# 第 4 轮:把两个工具结果一起送回模型resp4 = client.chat.completions.create(model="hy3",messages=messages,tools=tools,tool_choice="auto",extra_body={"reasoning_effort": "high"},)msg4 = resp4.choices[0].messageprint("第 4 轮 reasoning_content:", getattr(msg4, "reasoning_content", ""))print("第 4 轮 content:", msg4.content)
// 接续 step3:把第 3 轮 assistant 消息与两个工具结果回填messages.push({role: 'assistant',content: msg3.content || '',reasoning_content: msg3.reasoning_content,tool_calls: msg3.tool_calls,});// 业务侧并行执行 get_group_permissionsconst toolResults = {Engineering: {group: 'Engineering',permissions: [{ resource: '生产数据库', access: 'read-only' },{ resource: 'staging环境', access: 'read-write' },{ resource: '内部Wiki', access: 'read-write' },],},OnCall: {group: 'OnCall',permissions: [{ resource: '告警系统', access: 'read-write' },{ resource: '生产数据库', access: 'read-write' },],},};for (const tc of msg3.tool_calls || []) {const args = JSON.parse(tc.function.arguments);messages.push({role: 'tool',tool_call_id: tc.id,content: JSON.stringify(toolResults[args.group]),});}const resp4 = await client.chat.completions.create({model: 'hy3',messages,tools,tool_choice: 'auto',reasoning_effort: 'high',});const msg4 = resp4.choices[0].message;console.log('第 4 轮 reasoning_content:', msg4.reasoning_content);console.log('第 4 轮 content:', msg4.content);
// 接续第 3 轮响应 r3:把 assistant 消息(含 reasoning_content + tool_calls)回写JsonObject r3Obj = JsonParser.parseString(r3).getAsJsonObject();JsonObject msg3 = r3Obj.getAsJsonArray("choices").get(0).getAsJsonObject().getAsJsonObject("message");Map<String, Object> assistant3 = new LinkedHashMap<>();assistant3.put("role", "assistant");assistant3.put("content", msg3.has("content") ? msg3.get("content").getAsString() : "");if (msg3.has("reasoning_content")) {assistant3.put("reasoning_content", msg3.get("reasoning_content").getAsString());}if (msg3.has("tool_calls")) {assistant3.put("tool_calls", GSON.fromJson(msg3.get("tool_calls"), List.class));}messages.add(assistant3);// 业务侧并行执行 get_group_permissionsMap<String, String> toolResults = Map.of("Engineering", "{\\"group\\": \\"Engineering\\", \\"permissions\\": [{\\"resource\\": \\"生产数据库\\", \\"access\\": \\"read-only\\"}, {\\"resource\\": \\"staging环境\\", \\"access\\": \\"read-write\\"}, {\\"resource\\": \\"内部Wiki\\", \\"access\\": \\"read-write\\"}]}","OnCall", "{\\"group\\": \\"OnCall\\", \\"permissions\\": [{\\"resource\\": \\"告警系统\\", \\"access\\": \\"read-write\\"}, {\\"resource\\": \\"生产数据库\\", \\"access\\": \\"read-write\\"}]}");for (JsonElement el : msg3.getAsJsonArray("tool_calls")) {JsonObject call = el.getAsJsonObject();JsonObject args = JsonParser.parseString(call.getAsJsonObject("function").get("arguments").getAsString()).getAsJsonObject();String group = args.get("group").getAsString();messages.add(Map.of("role", "tool","tool_call_id", call.get("id").getAsString(),"content", toolResults.get(group)));}// 第 4 轮:把两个工具结果一起送回模型String r4 = chat(messages, tools);System.out.println("第 4 轮响应:" + r4);
// 接续第 3 轮响应 r3:把 assistant 消息(含 reasoning_content + tool_calls)回写msg3Wrap := r3["choices"].([]interface{})[0].(map[string]interface{})msg3 := msg3Wrap["message"].(map[string]interface{})messages = append(messages, msg3)// 业务侧并行执行 get_group_permissionstoolResults := map[string]string{"Engineering": `{"group": "Engineering", "permissions": [{"resource": "生产数据库", "access": "read-only"}, {"resource": "staging环境", "access": "read-write"}, {"resource": "内部Wiki", "access": "read-write"}]}`,"OnCall": `{"group": "OnCall", "permissions": [{"resource": "告警系统", "access": "read-write"}, {"resource": "生产数据库", "access": "read-write"}]}`,}toolCalls, _ := msg3["tool_calls"].([]interface{})for _, c := range toolCalls {call := c.(map[string]interface{})fn := call["function"].(map[string]interface{})var args map[string]interface{}json.Unmarshal([]byte(fn["arguments"].(string)), &args)group := args["group"].(string)messages = append(messages, map[string]interface{}{"role": "tool","tool_call_id": call["id"],"content": toolResults[group],})}// 第 4 轮:把两个工具结果一起送回模型r4, _ := chat(messages, tools)fmt.Printf("第 4 轮响应: %+v\\n", r4)
finish_reason=stop:{"id": "REPLACED_ID","object": "chat.completion","created": 1783084585,"model": "hy3","choices": [{"index": 0,"message": {"role": "assistant","content": "根据查询结果,这两个用户组的资源访问权限如下:\\n\\n**Engineering 组**\\n- 生产数据库:只读(read-only)\\n- staging环境:读写(read-write)\\n- 内部Wiki:读写(read-write)\\n\\n**OnCall 组**\\n- 告警系统:读写(read-write)\\n- 生产数据库:读写(read-write)\\n\\n**补充说明:** 两个组都对「生产数据库」拥有权限,但级别不同——Engineering 是只读,而 OnCall 是读写。因为 Alice 同时属于这两个组,所以她实际对生产数据库能享有最高级别的**读写**权限。","reasoning_content": "现在我有了两个组的权限信息:\\n\\nEngineering 组:\\n- 生产数据库: read-only\\n- staging环境: read-write\\n- 内部Wiki: read-write\\n\\nOnCall 组:\\n- 告警系统: read-write\\n- 生产数据库: read-write\\n\\n我需要整理这些信息并回答用户。注意两个组对生产数据库都有权限,但 Engineering 是 read-only,OnCall 是 read-write。由于 Alice 同时属于两个组,实际上她对生产数据库的实际权限应该取并集/最高权限,即 read-write……"},"finish_reason": "stop"}],"usage": {"prompt_tokens": 641,"completion_tokens": 266,"total_tokens": 907,"prompt_tokens_details": { "cached_tokens": 512 },"completion_tokens_details": { "reasoning_tokens": 140 }}}
messages 数组如下,注意每工具轮的 reasoning_content 等内容都被原样保留:[{ "role": "system", "content": "你是一个企业 IT 权限助理 Agent……请始终用中文进行逐步推理与思考。" },{ "role": "user", "content": "Alice 属于哪些用户组?" },{ "role": "assistant", "content": "我来查询 Alice 所属的用户组。","reasoning_content": "用户问 Alice 属于哪些用户组……只有一个调用,没有依赖。","tool_calls": [ { "id": "chatcmpl-tool-93cc85d5f381f88d", "type": "function","function": { "name": "get_user_groups", "arguments": "{\\"user\\": \\"Alice\\"}" } } ] },{ "role": "tool", "tool_call_id": "chatcmpl-tool-93cc85d5f381f88d","content": "{\\"user\\": \\"Alice\\", \\"groups\\": [\\"Engineering\\", \\"OnCall\\"]}" },{ "role": "assistant", "content": "根据查询结果,Alice 属于以下两个用户组:……","reasoning_content": "根据工具返回结果,Alice 属于 Engineering 和 OnCall 两个用户组。" },{ "role": "user", "content": "这些组分别有哪些资源的访问权限?" },{ "role": "assistant", "content": "我来查询这两个用户组各自的资源访问权限。","reasoning_content": "……这两个调用之间没有依赖关系,可以同时进行。","tool_calls": [{ "id": "chatcmpl-tool-83653bb310744682", "type": "function","function": { "name": "get_group_permissions", "arguments": "{\\"group\\": \\"Engineering\\"}" } },{ "id": "chatcmpl-tool-b2ee9d73aef14658", "type": "function","function": { "name": "get_group_permissions", "arguments": "{\\"group\\": \\"OnCall\\"}" } } ] },{ "role": "tool", "tool_call_id": "chatcmpl-tool-83653bb310744682","content": "{\\"group\\": \\"Engineering\\", \\"permissions\\": [{\\"resource\\": \\"生产数据库\\", \\"access\\": \\"read-only\\"}, …]}" },{ "role": "tool", "tool_call_id": "chatcmpl-tool-b2ee9d73aef14658","content": "{\\"group\\": \\"OnCall\\", \\"permissions\\": [{\\"resource\\": \\"生产数据库\\", \\"access\\": \\"read-write\\"}, …]}" },{ "role": "assistant", "content": "根据查询结果,这两个用户组的资源访问权限如下:……(含各组权限表)","reasoning_content": "现在我有了两个组的权限信息:\\nEngineering 组:\\n- 生产数据库: read-only …\\nOnCall 组:\\n- 生产数据库: read-write …" },// 👇 用户第 3 个提问轮:综合追问{ "role": "user", "content": "那么综合来看,Alice 对『生产数据库』到底拥有什么级别的访问权限?" }]
Alice ∈ {Engineering, OnCall} → 推导出两组对生产库的权限为「只读 / 读写」→ 取最高权限 → 即读写权限):{"id": "REPLACED_ID","object": "chat.completion","created": 1783084590,"model": "hy3","choices": [{"index": 0,"message": {"role": "assistant","content": "基于前面查询到的信息,我可以直接综合判断,无需再次调用工具:\\n\\n- **Engineering 组** → 生产数据库:只读(read-only)\\n- **OnCall 组** → 生产数据库:读写(read-write)\\n\\n由于 Alice **同时属于** Engineering 和 OnCall 两个组,当多个组对同一资源拥有不同级别的权限时,通常取**最高级别**(权限取并集)。\\n\\n因此,综合来看,Alice 对「生产数据库」拥有 **读写(read-write)** 级别的访问权限。","reasoning_content": "用户问 Alice 对生产数据库的综合访问权限。根据之前的查询结果:\\n\\n- Engineering 组:生产数据库 - read-only(只读)\\n- OnCall 组:生产数据库 - read-write(读写)\\n\\nAlice 同时属于这两个组。综合来看,她应该拥有最高级别的权限,即读写(read-write)。……我不需要再调用工具,因为之前已经获得了所有必要信息。我可以基于已有数据直接回答。"},"finish_reason": "stop"}],"usage": {"prompt_tokens": 925,"completion_tokens": 283,"total_tokens": 1208,"prompt_tokens_details": { "cached_tokens": 624 },"completion_tokens_details": { "reasoning_tokens": 139 }}}
preserved_thinking 吗?tools 时默认开启,纯文本对话默认关闭。仅在"工具未通过标准 tools 数组注册"等特殊情形下才需要手动设置为 true。reasoning_content 吗?preserved_thinking 仅控制启停,不会自动处理历史思考的回填。开发者需要将模型上一轮返回的完整、未经修改的 reasoning_content 与工具结果一并原样带回,否则可能影响模型效果并降低缓存命中率。hy3-preview 升级到 hy3 需要改造代码吗?reasoning_content)都保留在 messages 数组中。reasoning_content 回填时可以做摘要压缩吗?reasoning_content 必须与模型生成时完全一致,不要改写、截断或重新排序,否则会降低模型效果并影响缓存命中率。文档反馈