通义千问 Chat 模型高级用法:Function Calling / Structured Output / 多轮对话

通义千问 Chat 模型高级用法:Function Calling / Structured Output / 多轮对话

本文深入讲解通义千问 Chat 模型的核心高级能力:Function Calling、Structured Output、多轮对话管理,以及流式处理、限流重试、生产级最佳实践和常见踩坑指南。


一、通义千问参数详解

1.1 完整参数列表

参数 类型 范围 默认值 说明
model String - qwen-plus 模型名称:qwen-turbo / qwen-plus / qwen-max / qwen-long / qwen-math-plus / qwen-coder-plus
temperature Double 0.0-2.0 0.7 越高越随机,0.0 返回确定输出
top-p Double 0.0-1.0 0.8 nucleus 采样,1.0 全选
top-k Int 0-100 - top-k 采样,0 关闭
seed Int - - 复现性种子,同 seed 输出一致
max-tokens Int - 1500 输出最大 Token 数
presence-penalty Double -2.0-2.0 0 话题新颖度,正值鼓励新话题
frequency-penalty Double -2.0-2.0 0 字频惩罚,减少重复
stop List - - 停止字符串列表
enable-search Boolean - false 开启联网搜索
incremental-output Boolean - true 流式增量输出
tools List - - 工具定义(JSON Schema)
tool-choice String - auto auto / none / {name}
parallel-tool-calls Boolean - true 是否并行调用多工具
result-format String - text text / json_object / json_schema
response-format Object - - JSON Schema(result-format=json_schema 时有效)

1.2 参数调优指南

核心原则:确定性任务用低温,创意任务用高温。

java 复制代码
// 场景1:代码生成(低温,确定性优先)
DashScopeChatOptions.builder()
    .withModel("qwen-coder-plus")
    .withTemperature(0.1)          // 极低温度,输出稳定
    .withTopP(0.1)                 // 候选集极小,聚焦最可能答案
    .withMaxTokens(2000)
    .withSeed(42)                  // 可复现
    .build();

// 场景2:创意写作(高温,探索多样)
DashScopeChatOptions.builder()
    .withModel("qwen-plus")
    .withTemperature(0.9)          // 高温度,创意丰富
    .withTopP(0.9)
    .withMaxTokens(4000)
    .withPresencePenalty(0.5)      // 鼓励新话题
    .build();

// 场景3:客服问答(启用搜索,精准事实)
DashScopeChatOptions.builder()
    .withModel("qwen-plus")
    .withTemperature(0.3)          // 中等偏低,减少幻觉
    .withEnableSearch(true)        // 联网事实
    .withIncrementalOutput(true)
    .build();

参数组合速查

任务类型 temperature top_p top_k 说明
代码生成 0.0-0.2 0.1-0.3 10-20 确定性优先
数据分析 0.1-0.3 0.3-0.5 20-50 准确优先
通用对话 0.5-0.7 0.7-0.9 50-80 平衡
创意写作 0.8-1.2 0.8-1.0 80-100 多样性优先
头脑风暴 1.0-1.5 0.9-1.0 100 最大随机

注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

1.3 两层参数配置

Spring AI Alibaba 支持 全局默认 + 单次调用动态覆盖 两层配置:

yaml 复制代码
# 全局默认配置
spring:
  ai:
    dashscope:
      chat:
        options:
          model: qwen-plus
          temperature: 0.7
          max-tokens: 1500
java 复制代码
// 单次调用覆盖
String response = chatClient.prompt()
    .user(userMessage)
    .options(DashScopeChatOptions.builder()
        .withModel("qwen-max")        // 覆盖模型
        .withTemperature(0.3)          // 覆盖温度
        .withMaxTokens(3000)           // 覆盖最大 Token
        .withEnableSearch(true)        // 本次开启搜索
        .build())
    .call()
    .content();

二、Function Calling

2.1 三种函数注册方式

Spring AI Alibaba 支持三种 Tool 注册方式:

方式 适用场景 推荐度
@Bean + Function 接口 标准注册,与 Spring 容器解耦 ⭐⭐⭐⭐⭐
@Tool 注解 1.1 版推荐的简化写法 ⭐⭐⭐⭐
ToolCallback 编程式 动态注册、复杂场景 ⭐⭐⭐
java 复制代码
/**
 * 方式一:@Bean + Function 接口(最标准)
 */
@Configuration
public class ToolsConfiguration {

    @Bean
    @Description("获取当前的日期和时间")
    public Function<CurrentTimeRequest, CurrentTimeResponse> getCurrentTime() {
        return request -> {
            String now = LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            return new CurrentTimeResponse(now, "Asia/Shanghai");
        };
    }

    @Bean
    @Description("查询指定城市的实时天气信息")
    public Function<WeatherRequest, WeatherResponse> getWeather() {
        return request -> {
            // 调用天气 API
            return new WeatherResponse(request.city(), "25°C", "晴");
        };
    }
}

/**
 * 方式二:@Tool 注解(简化写法)
 */
@Service
public class TongyiToolService {

    @Tool(description = "查询订单状态,返回订单状态、金额、物流信息")
    public OrderResult queryOrder(@ToolParam(description = "订单号") String orderId) {
        return orderService.query(orderId);
    }

    @Tool(description = "创建退换货工单")
    public RefundResult createRefund(
            @ToolParam(description = "订单号") String orderId,
            @ToolParam(description = "退换货原因") String reason) {
        return refundService.create(orderId, reason);
    }
}

/**
 * 方式三:ChatClient 中注册
 */
@RestController
public class ChatController {

    @PostMapping("/chat")
    public String chat(@RequestBody ChatRequest request) {
        return chatClient.prompt()
            .user(request.message())
            .tools("getCurrentTime", "getWeather")  // 注册工具
            .call()
            .content();
    }
}

2.2 Tool 参数校验(JSR-303)

使用 JSR-303 注解对工具参数进行校验:

java 复制代码
import jakarta.validation.constraints.*;

public class WeatherRequest {
    @NotBlank(message = "城市名称不能为空")
    @Size(min = 2, max = 20, message = "城市名称长度应在2-20之间")
    private String city;

    @Pattern(regexp = "^[A-Z]{2}$", message = "国家代码必须为2位大写字母")
    private String countryCode;

    // getters/setters
}

@Configuration
public class ValidatedToolsConfig {

    @Bean
    @Description("查询指定城市的天气")
    public Function<WeatherRequest, WeatherResponse> getWeather() {
        return request -> {
            // 参数已在进入方法前被 Spring Validation 校验
            return weatherService.query(request.getCity());
        };
    }
}

2.3 工具执行超时控制

java 复制代码
@Configuration
public class TimeoutToolsConfig {

    @Bean
    @Description("查询数据库(可能较慢)")
    public Function<QueryRequest, QueryResponse> slowDatabaseQuery() {
        return request -> {
            // 使用 CompletableFuture + 超时
            CompletableFuture<QueryResponse> future = CompletableFuture.supplyAsync(() ->
                databaseService.complexQuery(request)
            );
            try {
                return future.get(5, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                throw new RuntimeException("查询超时,请稍后重试");
            }
        };
    }
}

2.4 并行工具调用

Qwen 支持并行调用多个工具(parallel_tool_calls: true 时):

java 复制代码
@Service
public class ParallelToolService {

    private final ChatClient chatClient;

    /**
     * 用户:"帮我查下订单 MT2025001 状态,同时查下该商品的退换货政策"
     * → Qwen 返回两个并行 tool_calls
     * → Spring AI 并行执行两个 @Tool 方法
     */
    public String chatWithParallelTools(String userMessage) {
        return chatClient.prompt()
            .user(userMessage)
            .functions("queryOrder", "queryRefundPolicy")
            .options(DashScopeChatOptions.builder()
                .withParallelToolCalls(true)    // 允许并行调用
                .build())
            .call()
            .content();
    }
}

2.5 ToolChoice 强制调用

java 复制代码
/**
 * 强制模型调用指定工具(不询问直接执行)
 */
public String forceToolCall(String orderId) {
    return chatClient.prompt()
        .system("请调用指定工具处理用户请求")
        .user("处理订单 " + orderId)
        .functions("queryOrder")
        .options(DashScopeChatOptions.builder()
            .withToolChoice("queryOrder")       // 强制调用 queryOrder
            .build())
        .call()
        .content();
}

2.6 Tool 描述 Prompt 工程

工具描述的质量直接影响模型选择工具的准确性:

java 复制代码
// ❌ 差:描述模糊
@Tool(description = "查询数据")
public String queryData(String id) { ... }

// ✅ 好:描述具体,包含触发条件
@Tool(description = "查询订单状态。当用户询问'订单到哪了'、'订单状态'、'物流信息'时调用此工具。")
public OrderResult queryOrder(@ToolParam(description = "订单号,格式如 MT2025001") String orderId) { ... }

// ✅ 最佳:包含参数示例
@Tool(description = "查询天气信息。用户询问'天气'、'温度'、'会不会下雨'时调用。")
public WeatherResponse getWeather(
    @ToolParam(description = "城市名称,如'北京'、'上海'") String city,
    @ToolParam(description = "日期,格式 yyyy-MM-dd,默认今天") String date
) { ... }

2.7 Function Calling 完整调用链

复制代码
Java Function ( @Bean / @Tool )
       │
       ▼
Spring AI 转换 tool 定义 (name + description + JSON Schema)
       │
       ▼
TongyiChatModel 发送 messages + tools 参数
       │
       ▼
Qwen 模型 → 返回 tool_calls (function name + args)
       │
       ▼
TongyiChatModel 识别 tool_calls → 调用 Java Method (反射)
       │
       ▼
Java 返回值转 JSON 拼接进 messages
       │
       ▼
模型二次推理 → 最终输出自然语言

三、结构化输出(Structured Output)

3.1 三种结构化模式

Mode 实现方式 适用场景
BeanOutputConverter 定义 POJO,自动 JSON Schema 推断 Java 内部直接消费,类型安全
outputType(Class) ReactAgent 直接传入 Java 类 Agent 场景,自动生成 Schema
outputSchema(String) 手写 JSON Schema 或 BeanOutputConverter 生成 精确字段校验

3.2 Bean 方式(ChatClient)

java 复制代码
@Data
public class ProductReviewAnalysis {
    private String productName;
    private Double sentimentScore;       // 0.0-1.0
    private List<String> positive;       // 优点
    private List<String> negative;       // 缺点
    private String summary;
    private boolean recommend;
}

@Service
public class StructuredOutputService {

    private final ChatClient chatClient;

    /**
     * Bean 方式:Qwen 直接返回符合 Java POJO 结构的 JSON
     * 内部自动完成:(1) prompt 附 JSON Schema (2) 模型返回 JSON (3) Jackson 反序列
     */
    public ProductReviewAnalysis analyzeReview(String productName, String reviewText) {
        var outputConverter = new BeanOutputConverter<>(ProductReviewAnalysis.class);

        return chatClient.prompt()
            .system("分析用户评论,结构化返回评分、优缺点、总结。"
                + outputConverter.getFormat())          // 自动注入 JSON Schema
            .user("商品: %s\n评论: %s".formatted(productName, reviewText))
            .call()
            .entity(ProductReviewAnalysis.class);       // 自动反序列
    }
}

3.3 Agent 场景的结构化输出

在 Spring AI Alibaba 的 ReactAgent 中,通过 outputSchemaoutputType 处理结构化输出:

java 复制代码
/**
 * 方式一:outputType(Class) - 推荐,类型安全
 */
public static class ContactInfo {
    private String name;
    private String email;
    private String phone;
    // getters/setters
}

ReactAgent agent = ReactAgent.builder()
    .name("contact_extractor")
    .model(chatModel)
    .outputType(ContactInfo.class)          // 传入 Java 类,自动转 JSON Schema
    .instruction("从用户消息中提取联系人信息")
    .build();

ContactInfo result = agent.call("我的名字是张三,邮箱 zhangsan@example.com,电话 13800138000");

/**
 * 方式二:outputSchema(String) - 手动指定 Schema
 */
BeanOutputConverter<ContactInfo> converter = new BeanOutputConverter<>(ContactInfo.class);
String schema = converter.getFormat();      // 从 Java 类自动生成

ReactAgent agent = ReactAgent.builder()
    .name("contact_extractor")
    .model(chatModel)
    .outputSchema(schema)                   // 使用生成的 Schema
    .instruction("从用户消息中提取联系人信息")
    .build();

3.4 JsonSchema 精细控制(原生模式)

java 复制代码
@Service
public class JsonSchemaService {

    private final ChatClient chatClient;

    public String queryWithJsonSchema(String naturalLanguageQuery) {
        String schema = """
            {
              "type": "object",
              "properties": {
                "query_type": { "type": "string", "enum": ["order","refund","logistics","other"] },
                "keywords": { "type": "array", "items": { "type": "string" } },
                "needs_human": { "type": "boolean" }
              },
              "required": ["query_type","keywords","needs_human"],
              "additionalProperties": false
            }
            """;

        return chatClient.prompt()
            .system("请把用户口语化请求解析为结构化 query。")
            .user(naturalLanguageQuery)
            .options(DashScopeChatOptions.builder()
                .withResultFormat(DashScopeApi.JsonSchema.builder()
                    .schema(JSON.parseObject(schema))
                    .name("QueryAnalysis")
                    .strict(true)               // 严格模式,不合规输出报错
                    .build())
                .build())
            .call()
            .content();
    }
}

四、多轮对话管理

4.1 ChatMemory 架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    ChatMemory 架构                              │
│                                                                 │
│  ChatClient                                                     │
│      │                                                          │
│      ▼                                                          │
│  MessageChatMemoryAdvisor (拦截器)                    │
│      ├── Before Request: 从 Memory 读取历史 → 注入 Prompt│
│      ├── Call LLM                                              │
│      └── After Response: 将用户提问 + 模型回复写入 Memory│
│                                                                 │
│  ChatMemoryRepository (存储层抽象)                    │
│      ├── InMemoryChatMemoryRepository (内存,开发用)           │
│      ├── RedisChatMemoryRepository (Redis,生产用)    │
│      └── JdbcChatMemoryRepository (数据库)                     │
└─────────────────────────────────────────────────────────────────┘

4.2 内存版多轮对话

java 复制代码
@Configuration
public class MemoryChatConfig {

    @Bean
    public MessageChatMemoryAdvisor memoryAdvisor() {
        return new MessageChatMemoryAdvisor(
            MessageWindowChatMemory.builder()
                .chatMemoryRepository(new InMemoryChatMemoryRepository())
                .maxMessages(20)              // ⚠️ 关键:保留最近20条消息
                .build()
        );
    }
}

@Service
public class MultiTurnService {

    private final ChatClient chatClient;
    private final MessageChatMemoryAdvisor memoryAdvisor;

    public String multiTurn(String sessionId, String userMessage) {
        return chatClient.prompt()
            .user(userMessage)
            .advisors(memoryAdvisor, a -> a.param(ChatMemory.CONVERSATION_ID, sessionId))
            .call()
            .content();
    }
}

4.3 Redis 持久化(生产级)

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-redis</artifactId>
</dependency>
java 复制代码
@Configuration
public class RedisMemoryConfig {

    @Bean
    public RedisChatMemoryRepository redisChatMemoryRepository(
            RedisTemplate<String, Object> redisTemplate) {
        return new RedisChatMemoryRepository(redisTemplate);
    }

    @Bean
    public MessageChatMemoryAdvisor redisMemoryAdvisor(
            RedisChatMemoryRepository repository) {
        return new MessageChatMemoryAdvisor(
            MessageWindowChatMemory.builder()
                .chatMemoryRepository(repository)    // Redis 持久化
                .maxMessages(20)                     // 每会话保留20条消息
                .build()
        );
    }
}

生产级 Redis 配置要点

  • maxMessages 建议 10-50 条,避免 Token 浪费和注意力分散
  • 严格保证 conversationId 唯一性,防止会话越权
  • Redis 持久化支持多实例部署,服务重启不丢失

4.4 Agent 场景的状态持久化

java 复制代码
/**
 * RedisSaver:Agent 状态持久化到 Redis
 */
@Configuration
public class AgentRedisConfig {

    @Bean
    public ReactAgent persistentAgent(ChatModel chatModel, RedissonClient redisson) {
        RedisSaver redisSaver = new RedisSaver(redisson);
        return ReactAgent.builder()
            .name("persistent_agent")
            .model(chatModel)
            .saver(redisSaver)                    // Redis 持久化
            .instruction("你是一个持久化记忆的助手")
            .build();
    }
}

@Service
public class PersistentAgentService {

    private final ReactAgent agent;

    /**
     * 通过 threadId 管理会话
     */
    public String chat(String threadId, String message) {
        return agent.call(message, threadId);     // threadId 隔离不同会话
    }
}

4.5 手动管理消息历史(灵活场景)

java 复制代码
@Service
public class CustomMultiTurnService {

    private final ChatModel chatModel;
    private final Map<String, List<Message>> sessionStore = new ConcurrentHashMap<>();

    /**
     * 手动管理消息列表,实现"回滚某轮"、"编辑历史"等高级功能
     */
    public String chatInSession(String sessionId, String userMessage) {
        List<Message> messages = sessionStore.computeIfAbsent(sessionId, k -> new ArrayList<>());

        // 添加用户消息
        messages.add(new UserMessage(userMessage));

        // 发送完整消息列表
        String response = chatModel.call(new Prompt(messages,
            DashScopeChatOptions.builder().withModel("qwen-plus").build()
        )).getResult().getOutput().getContent();

        // 添加 assistant 回复
        messages.add(new AssistantMessage(response));

        // 限制消息数量,防止超长
        if (messages.size() > 30) {
            // 保留系统消息 + 最近20条
            messages.subList(0, messages.size() - 20).clear();
        }

        return response;
    }

    /**
     * 回滚历史(删除上一轮 user + assistant)
     */
    public void rollbackLast(String sessionId) {
        List<Message> messages = sessionStore.get(sessionId);
        if (messages != null && messages.size() >= 2) {
            messages.removeLast();          // 删 assistant reply
            messages.removeLast();          // 删 user message
        }
    }
}

五、流式处理(Streaming)

5.1 基础流式输出

java 复制代码
@RestController
@RequestMapping("/api/stream")
public class StreamingController {

    private final ChatClient chatClient;

    /**
     * Flux 流式(默认增量输出)
     */
    @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatStream(@RequestParam String message) {
        return chatClient.prompt(message)
            .stream()
            .content();
    }

    /**
     * Server-Sent Events 包装
     */
    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> sseStream(@RequestParam String message) {
        return chatClient.prompt(message)
            .stream()
            .content()
            .map(content -> ServerSentEvent.<String>builder()
                .data(content)
                .build());
    }
}

5.2 流式中观测工具调用

java 复制代码
/**
 * 流式过程中透出工具调用中间态(UI 显示"正在查询订单...")
 */
@GetMapping(value = "/stream-with-tools", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamWithToolObservation(@RequestParam String message) {
    return chatClient.prompt(message)
        .functions("queryOrder", "createRefund")
        .stream()
        .chatResponse()
        .flatMap(response -> {
            // 检测是否有工具调用
            if (response.getResult() != null && 
                response.getResult().getOutput() != null &&
                response.getResult().getOutput().getToolCalls() != null) {
                return Flux.just("🔧 正在调用工具: " + 
                    response.getResult().getOutput().getToolCalls().get(0).getName() + "...");
            }
            // 返回文本内容
            String content = response.getResult() != null ? 
                response.getResult().getOutput().getContent() : "";
            if (content != null && !content.isBlank()) {
                return Flux.just(content);
            }
            return Flux.empty();
        });
}

5.3 流式 Function Calling 的坑与解决方案

通义千问的流式响应可能将工具调用的参数(arguments)拆分成多个片段返回,Spring AI 需要正确处理这种分片:

java 复制代码
/**
 * 自定义流式工具调用处理器
 */
@Component
public class StreamingToolCallHandler {

    private final Map<String, StringBuilder> toolArgBuffers = new ConcurrentHashMap<>();

    public Flux<String> handleStreamingToolCalls(Flux<ChatResponse> stream) {
        return stream
            .flatMap(response -> {
                if (response.getResult() == null) return Flux.empty();

                var output = response.getResult().getOutput();
                if (output == null) return Flux.empty();

                // 处理工具调用片段
                if (output.getToolCalls() != null && !output.getToolCalls().isEmpty()) {
                    for (var toolCall : output.getToolCalls()) {
                        String id = toolCall.getId();
                        String arguments = toolCall.getArguments();
                        if (arguments != null) {
                            // 累积参数片段
                            toolArgBuffers.computeIfAbsent(id, k -> new StringBuilder())
                                .append(arguments);
                        }
                    }
                    return Flux.just("🔧 正在处理工具调用...");
                }

                // 输出文本内容
                String content = output.getContent();
                if (content != null && !content.isBlank()) {
                    return Flux.just(content);
                }
                return Flux.empty();
            });
    }
}

六、限流与重试

6.1 DashScope 限流说明

模型 免费版 QPS 付费版 QPS 说明
qwen-turbo 1 50+ 入门模型
qwen-plus 1 50+ 通用推荐
qwen-max 需付费 50+ 最强性能
qwen-long 需付费 20+ 超长上下文

6.2 Resilience4j 限流 + 重试

java 复制代码
@Service
public class RateLimitedChatService {

    private final ChatClient chatClient;
    private final CacheService cacheService;

    @RateLimiter(name = "dashscope", fallbackMethod = "fallbackToCache")
    @Retry(name = "dashscope")
    public String chatWithProtection(String message) {
        return chatClient.prompt(message).call().content();
    }

    public String fallbackToCache(String message, Throwable t) {
        log.warn("Qwen 限流兜底,查询缓存", t);
        return cacheService.getCachedAnswer(message);
    }
}
yaml 复制代码
# application.yml
resilience4j:
  ratelimiter:
    instances:
      dashscope:
        limitForPeriod: 10                    # 每周期 10 次
        limitRefreshPeriod: 1s
        timeoutDuration: 500ms
  retry:
    instances:
      dashscope:
        maxAttempts: 3
        waitDuration: 1s
        retryExceptions:
          - com.alibaba.dashscope.exception.StatusErrorException    # 429 限流重试

6.3 熔断器配置

java 复制代码
@Configuration
public class ResilienceConfig {

    @Bean
    public CircuitBreaker circuitBreaker() {
        return CircuitBreaker.of("dashscope", CircuitBreakerConfig.custom()
            .slidingWindowSize(100)
            .failureRateThreshold(50)         // 失败率 > 50% 触发熔断
            .waitDurationInOpenState(Duration.ofSeconds(30))
            .permittedNumberOfCallsInHalfOpenState(10)
            .build());
    }
}

七、多轮 + Function Calling 组合

多轮叠加 Function Calling 时的注意事项:

java 复制代码
@Service
public class MultiTurnFunctionService {

    private final ChatClient chatClient;
    private final MessageChatMemoryAdvisor memoryAdvisor;

    /**
     * 第1轮:用户"帮我查一下 MT2025001" → 模型调用 tool → 返回订单信息
     * 第2轮:用户"那金额是多少" → 模型记住上一轮订单号,继续用 tool 查
     */
    public String chatMultiTurnWithTools(String sessionId, String userMessage) {
        return chatClient.prompt()
            .user(userMessage)
            .functions("queryOrder", "createRefund")
            .advisors(memoryAdvisor, a -> a.param(ChatMemory.CONVERSATION_ID, sessionId))
            .call()
            .content();
    }
}

注意事项

  1. Function Calling 的 tool_calls 和 tool_results 也会被 ChatMemory 记录
  2. 多次 tool 调用的上下文会自动累积,无需手动管理
  3. 建议将 maxMessages 设大一些(如 30-50),因为工具调用会占用多条消息
  4. 如果工具返回大量数据,考虑只保留关键字段,避免上下文超长

八、常见问题与踩坑指南

8.1 Function Calling 相关

问题 原因 解决方案
模型不调用工具 工具描述不够清晰 优化 @Tool 的 description,包含触发条件
工具参数解析失败 参数类型不匹配 使用 @ToolParam 明确类型和描述
并行调用未生效 parallel-tool-calls 未开启 设置 withParallelToolCalls(true)
流式工具调用报错 参数被拆分成多个片段 使用自定义累积处理器

8.2 结构化输出相关

问题 原因 解决方案
输出包含额外文本 未启用 strict 模式 设置 strict(true)
字段缺失 required 未正确设置 在 Schema 中明确 required 字段
枚举值不匹配 模型输出不在枚举范围内 在 Prompt 中强调枚举值列表
POJO 反序列化失败 JSON 字段名不匹配 使用 @JsonProperty 映射

8.3 多轮对话相关

问题 原因 解决方案
会话串数据 conversationId 不唯一 使用 UUID 或 JWT 中的唯一标识
上下文过长 maxMessages 设置过大 设置 10-50 条,超出后滚动丢弃
重启后记忆丢失 使用内存存储 切换到 Redis 持久化
多实例会话不同步 内存存储无法共享 使用 Redis 共享存储

8.4 流式输出相关

问题 原因 解决方案
流式输出报错 版本兼容性问题 升级到最新版本
前端接收乱码 Content-Type 不正确 使用 text/event-stream
连接超时 响应时间过长 增加超时配置,或使用异步处理

九、最佳实践清单

9.1 参数调优

  • ✅ 确定性任务(代码/数学)用 temperature=0.0-0.2
  • ✅ 创意任务用 temperature=0.8-1.2
  • ✅ 事实问答开启 enable-search=true
  • ✅ 使用 seed 保证可复现性

9.2 Function Calling

  • ✅ 工具描述包含触发条件和参数示例
  • ✅ 使用 JSR-303 校验工具参数
  • ✅ 设置合理的工具执行超时
  • ✅ 并行调用时注意线程安全

9.3 结构化输出

  • ✅ 使用 BeanOutputConverter 从 Java 类自动生成 Schema
  • ✅ Agent 场景使用 outputType(Class) 类型安全
  • ✅ 严格模式确保输出格式精确

9.4 多轮对话

  • ✅ 生产环境使用 Redis 持久化
  • maxMessages 设置 10-50 条
  • conversationId 使用唯一标识
  • ✅ 多实例部署使用 Redis 共享存储

9.5 限流与容错

  • ✅ 接入 Resilience4j 限流和重试
  • ✅ 配置熔断器防止雪崩
  • ✅ 提供降级方案(缓存/默认回复)

9.6 可观测性

  • ✅ 记录每次调用的 Token 用量
  • ✅ 监控限流触发次数和错误率
  • ✅ 使用 MDC 传递 traceId 便于链路追踪

十、总结

本章深入通义千问 Chat 模型四大高级能力及生产级最佳实践:

模块 核心内容 关键点
参数调优 temperature/top_p/top_k 等参数详解 确定性任务低温,创意任务高温
Function Calling @Bean/@Tool 注册、并行调用、ToolChoice 强制、参数校验 工具描述质量决定调用准确性
Structured Output Bean/Agent/JsonSchema 三档模式 outputType 类型安全
多轮对话 ChatMemory + Advisor 架构 Redis 持久化生产必备
流式处理 Flux/SSE 流式输出 注意工具调用参数分片问题
限流容错 Resilience4j 限流/重试/熔断 降级方案保障可用性

参考资源:

相关推荐
实心儿儿44 分钟前
Linux —— epoll(1)
linux·网络
资深技术分享员1 小时前
技术赋能降本增效:Geejing WebBuilder 企业级低代码平台的专业化研发与运维便利价值解析
运维·低代码·架构
s_w.h1 小时前
【 计网 】序列化与反序列化
linux·服务器·网络·算法·bash
Boop_wu1 小时前
[LangGraph] 案例 2 : 支持搜索的智能代理系统
服务器·windows·python·langchain
祖力551 小时前
网络编程:IO多路复用(select、poll、epoll)
linux·服务器·网络
迷路爸爸1801 小时前
在 Ubuntu / Linux 上轻量安装 LaTeX:TinyTeX 使用记录
linux·运维·ubuntu
叱咤少帅(少帅)1 小时前
新版本jenkins的共享库的实现
运维·jenkins
姚不倒1 小时前
Keepalived 系列(二):生产最佳实践与面试考点
运维·keepalived·haproxy
pt10431 小时前
网络自动化Python课程:利用Cisco NSO编排网络服务
运维·网络·自动化