{"repo": "bbossgroups/bboss-elasticsearch", "files": {"docs/bboss-ai.md": {"0c55a354137310e65e5d7412bd142c4cd26431a5": {"t": 1785768876.8931015, "n": 111731, "h": "4977324348d69056", "c": "# 多模态AI智能体开发框架使用教程\n\n## 一、概述\n\n**bboss-ai** 是一个轻量级 Java AI Agent 开发客户端,基于 Apache HttpClient5、HttpCore5 以及 Project Reactor 构建,提供了对大语言模型(LLM)和多模态模型的统一对接能力,支持同步调用和流式调用两种模式,并内置智能体工作流编排、会话管理、工具搜索等企业级特性。能够快速集成各大主流 AI 模型平台,实现智能问答、图片识别/生成、语音识别/生成、视频识别/生成等功能。\n\n**ClickHouse 生产级会话存储**:bboss-ai 支持基于 ClickHouse 分布式集群的生产级会话持久化能力。使用时需要指定 ClickHouse 集群名称,并为每个集群节点定义名为 `shard` 和 `replica` 的两个宏变量。ClickHouse 模式下会话续问续答时不会更新最后访问时间(受限于 ClickHouse 不支持高频 UPDATE)。详细使用方式参见 [Clickhouse会话存储管理](#chatper14-122) 章节。\n\n### 核心功能\n\n- **模型能力**:兼容 DeepSeek、Kimi、智谱、阿里百炼通义千问、字节豆包火山引擎、MiniMax、腾讯混元、中国移动九天、chatgpt等主流 MaaS 平台;通过简单的适配和扩展即可支持私有化模型平台\n\n- **流式响应**:基于 Reactor 的响应式编程模型,支持背压控制机制\n\n- **工具能力**:支持工具调用和 MCP 服务发现,提供 MCP SSE 和 Streamable 两种通讯协议,同时提供mcp server协议实现\n\n - 工具调用(Function Calling)\n - MCP(Model Context Protocol)服务发现和调用,支持 SSE 和 Streamable HTTP 两种传输模式\n - 可快速发布供LLM调用的工具服务和MCP服务\n - 多轮工具调用(Loop Tool Call),支持智能体自主决策多步骤任务执行\n - 脚本执行工具(Shell/CLI)和代码执行工具(Python/NodeJS)\n - Skills 技能模块,支持技能注册、加载、调度执行及可观测性监测\n - 工具搜索(Tool Searcher),支持基于关键词和语义的工具过滤\n\n- **多模态支持**:支持文本、图片、音频、视频等多种模态的识别与生成\n\n - 图片识别与生成(Vision/Image Generation)\n - 语音识别与合成(Speech-to-Text/Text-to-Speech)\n - 视频识别与生成(Video Understanding/Generation)\n\n- **检索增强生成(RAG):**内置文本向量化(Embedding)和重排序(Rerank)能力,支持知识库检索增强生成(RAG)\n\n - 向量嵌入(Embedding)\n - 重排序(Rerank)\n - 支持Elasticsearch、Milvus主流向量数据库\n\n- **多智能体协同**:基于有向循环图实现多智能体协同工作流,支持串行、并行、路由、条件分支、裁判评估等丰富的流程编排能力,快速构建复杂多智能体系统\n\n \n\n - 多智能体编排工作流底层基于[bboss jobflow](https://esdoc.bbossgroups.com/#/jobworkflow)实现(一套数据交换作业编排工作流)\n\n- **多轮会话**:支持会话长短期记忆管理,会话消息智能压缩;支持多智能体协同通讯和信息共享;子智能体独立会话空间,彼此隔离,互不干扰;支持内存、关系数据库(MySQL、Oracle、达梦 DM、SQL Server、PostgreSQL、SQLite)、Clickhouse多种会话持久化机制,生产级推荐Clickhouse。\n\n- **Hitl(Human-in-the-Loop):**人工介入功能允许在智能体执行过程中,当遇到需要人工决策的关键节点时,暂停智能体执行并等待人工介入处理,使用参考文档:https://esdoc.bbossgroups.com/#/bboss-ai-hitl\n\n- **智能体任务调度:灵活的智能体工作流任务**定时调度执行能力,可制定节假日或或者特定时间段忽略执行策略\n\n- **全链路监控:**智能体全链路 Trace 可观测性,覆盖 LLM 调用、工具执行、工作流编排;可基于智能体trace api,应用可自主记录智能体流程执行过程中的任何状态信息、数据信息和中间结果信息。\n\n### 支持的平台\n\n- DeepSeek\n- Kimi(Moonshot)\n- 智谱 AI(Zhipu)\n- 阿里百炼/通义千问(Qwen)\n- 字节豆包/火山引擎(Doubao)\n- 百度(Baidu)\n- 硅基流动(Siliconflow)\n- 九天(Jiutian)\n- MiniMax\n- 腾讯混元(TencentHY)\n- Xinference\n- OpenAI 兼容接口\n- ChatGPT\n\n## 二、环境准备\n\n### 2.1 Maven 依赖\n\n```xml\n\n com.bbossgroups\n bboss-ai-flow\n 6.5.5\n\n```\n\n### 2.2 Gradle 依赖\n\n```groovy\nimplementation 'com.bbossgroups:bboss-ai-flow:6.5.5'\n```\n\n### 2.3 maas服务配置\n\n创建配置文件 `application-stream.properties`,配置各模型服务:使用时,需将apiKey替换为实际apiKey\n\n```properties\nhttp.poolNames = deepseek,qwenvlplus,volcengine,kimi,zhipu,minimax,hunyuan\n\n## DeepSeek 配置\ndeepseek.http.maxTotal = 200\ndeepseek.http.defaultMaxPerRoute = 200\ndeepseek.http.hosts=https://api.deepseek.com\ndeepseek.http.apiKeyId = sk-xxxxx\ndeepseek.http.modelType = deepseek\n\n## 阿里百炼通义千问配置\nqwenvlplus.http.maxTotal = 200\nqwenvlplus.http.defaultMaxPerRoute = 200\nqwenvlplus.http.hosts=https://dashscope.aliyuncs.com\nqwenvlplus.http.apiKeyId = sk-xxxxx\nqwenvlplus.http.modelType = qwen\n\n## 火山引擎豆包配置\nvolcengine.http.maxTotal = 200\nvolcengine.http.defaultMaxPerRoute = 200\nvolcengine.http.hosts=https://ark.cn-beijing.volces.com\nvolcengine.http.apiKeyId = xxxxx\nvolcengine.http.modelType = doubao\n\n## Kimi 配置\nkimi.http.maxTotal = 200\nkimi.http.defaultMaxPerRoute = 200\nkimi.http.hosts=https://api.moonshot.cn\nkimi.http.apiKeyId = sk-xxxxx\nkimi.http.modelType = kimi\n\n## 智谱配置\nzhipu.http.maxTotal = 200\nzhipu.http.defaultMaxPerRoute = 200\nzhipu.http.hosts=https://open.bigmodel.cn\nzhipu.http.apiKeyId = xxxxx\n\n## MiniMax 配置\nminimax.http.maxTotal = 200\nminimax.http.defaultMaxPerRoute = 200\nminimax.http.hosts=https://api.minimaxi.com\nminimax.http.apiKeyId = sk-xxxxx\nminimax.http.modelType = minimax\n\n## 腾讯混元配置\nhunyuan.http.maxTotal = 200\nhunyuan.http.defaultMaxPerRoute = 200\nhunyuan.http.hosts=https://api.hunyuan.cloud.tencent.com\nhunyuan.http.apiKeyId = sk-xxxxx\n```\n\n### 2.4 MCP 服务配置\n\n如需使用 MCP 工具服务,配置 `mcpserver.properties`:使用时,需将apiKey替换为实际apiKey\n\n```properties\nhttp.poolNames = aliyun,gaotie,amap,WebParser,visualops,12306,shuqi,feishumcp\n#分析文档,编写一篇简洁实用的bboss ai实用教程\n##aliyun mcp模型服务配置:在代码中引用服务的名称为aliyun\n# 服务连接池参数\naliyun.http.maxTotal = 200\naliyun.http.defaultMaxPerRoute = 200\n# aliyun模型服务地址\naliyun.http.hosts=https://dashscope.aliyuncs.com\n#基于apiKeyId认证配置(主要用于各种大模型服务对接认证)\naliyun.http.apiKeyId = sk-469f01dbb572310d6d6db4fb2f4\n# sse端点:高德地图用户key申请地址,https://console.amap.com/dev/key/app\naliyun.http.extendConfigs.sseendpoint = /api/v1/mcps/amap-maps/sse?key=793b8ba3f45a22fa74cba764a8\n\n##WebParser mcp模型服务配置:在代码中引用服务的名称为WebParser\n# 服务连接池参数\nWebParser.http.maxTotal = 200\nWebParser.http.defaultMaxPerRoute = 200\n# WebParser模型服务地址\nWebParser.http.hosts=https://dashscope.aliyuncs.com\n#基于apiKeyId认证配置(主要用于各种大模型服务对接认证)\nWebParser.http.apiKeyId = sk-469f01e6db310d6d6db4fb2f4\n# sse端点:高德地图用户key申请地址,https://console.amap.com/dev/key/app\nWebParser.http.extendConfigs.sseendpoint = /api/v1/mcps/WebParser/sse\n\n\n##gaode mcp模型服务配置:在代码中引用服务的名称为amap\n# 服务连接池参数\namap.http.maxTotal = 200\namap.http.defaultMaxPerRoute = 200\n# amap模型服务地址\namap.http.hosts=https://mcp.amap.com\n#基于apiKeyId认证配置(主要用于各种大模型服务对接认证)\n#amap.http.apiKeyId = sk-469f6db310d6d6db4fb2f4\n# sse端点:高德地图用户key申请地址,https://console.amap.com/dev/key/app\namap.http.extendConfigs.sseendpoint = /sse?key=793b8b9bab15a22fa74cba764a8\n\n\n##gaotie mcp模型服务配置:在代码中引用服务的名称为gaotie\n# 服务连接池参数\ngaotie.http.maxTotal = 200\ngaotie.http.defaultMaxPerRoute = 200\n# gaotie模型服务地址\ngaotie.http.hosts=127.0.0.1:8000\ngaotie.http.extendConfigs.sseendpoint = /sse\n\n##12306 mcp模型服务配置:在代码中引用服务的名称为12306\n# 服务连接池参数\n12306.http.maxTotal = 200\n12306.http.defaultMaxPerRoute = 200\n# 12306服务地址\n12306.http.hosts=https://dashscope.aliyuncs.com\n12306.http.apiKeyId = sk-469f01db6db310d6d6db4fb2f4\n12306.http.extendConfigs.sseendpoint = /api/v1/mcps/china-railway/sse\n\n##shuqi mcp模型服务配置:在代码中引用服务的名称为shuqi\n# 服务连接池参数\nshuqi.http.maxTotal = 200\nshuqi.http.defaultMaxPerRoute = 200\n# shuqi服务地址\nshuqi.http.hosts=https://dashscope.aliyuncs.com\nshuqi.http.apiKeyId = sk-469f01dbe6db310d6d6db4fb2f4\nshuqi.http.extendConfigs.streamableendpoint = /api/v1/mcps/market-cmapi00072981/mcp\n#shuqi.http.httpResponseInterceptors=org.frameworkset.spi.ai.HttpResponseInterceptorDemo\n\n##visualops mcp模型服务配置:在代码中引用服务的名称为visualops\n# 服务连接池参数\nvisualops.http.maxTotal = 200\nvisualops.http.defaultMaxPerRoute = 200\n# visualops服务地址\n\nvisualops.http.hosts=127.0.0.1:8080\nvisualops.http.apiKeyId = 17689048891086XsDsJVgwiQcmKhOdh23DX4NT\n#visualops.http.extendConfigs.sseendpoint = /mcp/sse.api\nvisualops.http.extendConfigs.streamableendpoint = /mcp/streamable.api\n\n##feishumcp mcp模型服务配置:在代码中引用服务的名称为feishumcp\n# 服务连接池参数\nfeishumcp.http.maxTotal = 200\nfeishumcp.http.defaultMaxPerRoute = 200\n# feishumcp服务地址\nfeishumcp.http.hosts=https://mcp.feishu.cn\nfeishumcp.http.extendConfigs.streamableendpoint = /mcp\n\n\n\n```\n\n---\n\n## 三、基础使用\n\n### 3.1 智能体消息类型\n\n系统内置消息类型定义:[SessionMessage](https://gitee.com/bboss/bboss-ai/blob/main/bboss-ai/src/main/java/org/frameworkset/spi/ai/store/SessionMessage.java)\n\n完整的消息类型对照表,可以参考:\n\n[16.2 消息类型对照表](#chapter16-2)\n\n#### 3.1.1 编码定义\n\n消息类型messageType,对应agent_session_message表中的messageType字段\n\n```java\n /**\n * 智能体输出消息:ASSISTANT中的一种\n */\n public static final String MESSAGE_TYPE_AGENT_RESULTMESSAGE = \"1\";\n /**\n * 智能体用户输入消息:提交给大模型或者其他多模态模型\n */\n public static final String MESSAGE_TYPE_USER_MESSAGE = \"2\";\n\n /**\n * 智能体辅助消息\n */\n public static final String MESSAGE_TYPE_ASSISTANT_MESSAGE = \"0\";\n\n\n /**\n * 智能体系统消息\n */\n public static final String MESSAGE_TYPE_SYSTEM_MESSAGE = \"3\";\n\n /**\n * 智能体辅助消息:工具调用结果消息,需要提交给大模型\n */\n public static final String MESSAGE_TYPE_TOOL_MESSAGE = \"4\";\n\n /**\n * 智能体跟踪消息\n */\n public static final String MESSAGE_TYPE_TRACE_MESSAGE = \"5\";\n\n /**\n * 智能体RAG知识消息\n */\n public static final String MESSAGE_TYPE_RAG_MESSAGE = \"6\";\n\n /**\n * 智能体拒答消息\n */\n public static final String MESSAGE_TYPE_REFUSE_MESSAGE = \"7\";\n /**\n * 智能体用户输入消息:包括用户输入的原始问题、用户上传文件、用户图片描述等\n */\n public static final String MESSAGE_TYPE_USER_INPUTMESSAGE = \"8\";\n\n /**\n * LLM输入消息\n */\n public static final String MESSAGE_TYPE_LLM_INPUTMESSAGE = \"9\";\n\n /**\n * LLM输出消息\n */\n public static final String MESSAGE_TYPE_LLM_OUTPUTMESSAGE = \"10\";\n\n /**\n * 向量模型输入消息\n */\n public static final String MESSAGE_TYPE_EMBEDDING_INPUTMESSAGE = \"11\";\n\n /**\n * RERANK模型输入消息\n */\n public static final String MESSAGE_TYPE_RERANK_INPUTMESSAGE = \"12\";\n\n\n /**\n * 向量模型输入消息\n */\n public static final String MESSAGE_TYPE_EMBEDDING_OUTPUTMESSAGE = \"13\";\n \n /**\n * RERANK模型输入消息\n */\n public static final String MESSAGE_TYPE_RERANK_OUTPUTMESSAGE = \"14\";\n /**\n * 智能体工具搜索匹配消息\n */\n public static final String MESSAGE_TYPE_TOOLSEARCH_MESSAGE = \"15\";\n\n\n /**\n * 智能体mcp服务调用消息\n */\n public static final String MESSAGE_TYPE_MCPCALL_MESSAGE = \"16\";\n\n /**\n * 智能体工具服务调用消息\n */\n public static final String MESSAGE_TYPE_TOOLCALL_MESSAGE = \"17\";\n\n\n /**\n * 智能体工具服务调用消息:其他消息类型,定义的消息名称(role)没有设置对应的编码,返回18\n * 需要在AgentMessageTypeConvertor中建立映射关系\n */\n public static final String MESSAGE_TYPE_OTHER_MESSAGE = \"18\";\n\t\n\t/**\n\t * 智能体Skill调用消息\n\t */\n\tpublic static final String MESSAGE_TYPE_SKILLCALL_MESSAGE = \"19\";\n\t\n\t/**\n\t * 智能体人工介入消息:大模型提供输入内容,需要人工介入处理\n\t */\n\tpublic static final String MESSAGE_TYPE_HITL_MESSAGE = \"20\";\n\t\n\t/**\n\t * 智能体人工介入处理消息:人工介入处理完成后,返回给大模型的消息和数据内容\n\t */\n\tpublic static final String MESSAGE_TYPE_HITL_HANDLE_MESSAGE = \"21\";\n\n\n```\n\n#### 3.1.2 名称定义\n\n消息类型messageType对应的角色名称:\n\n```java\n\n /**\n * 智能体用户输入消息:包括用户输入的原始问题、用户上传文件、用户图片描述等\n */\n public static final String MESSAGE_TYPE_USER_INPUTMESSAGE_NAME = \"userinput\";\n\n /**\n * LLM输入消息\n */\n public static final String MESSAGE_TYPE_LLM_INPUTMESSAGE_NAME = \"llminput\";\n\n /**\n * 向量模型输入消息\n */\n public static final String MESSAGE_TYPE_EMBEDDING_INPUTMESSAGE_NAME = \"embeddinginput\";\n /**\n * RERANK模型输入消息\n */\n public static final String MESSAGE_TYPE_RERANK_INPUTMESSAGE_NAME = \"rerankinput\";\n\n\n /**\n * 向量模型输入消息\n */\n public static final String MESSAGE_TYPE_EMBEDDING_OUTPUTMESSAGE_NAME = \"embeddingoutput\";\n /**\n * RERANK模型输入消息\n */\n public static final String MESSAGE_TYPE_RERANK_OUTPUTMESSAGE_NAME = \"rerankoutput\";\n \n /**\n * LLM输出消息\n */\n public static final String MESSAGE_TYPE_LLM_OUTPUTMESSAGE_NAME = \"llmoutput\";\n /**\n * 智能体输出消息:ASSISTANT中的一种\n */\n public static final String MESSAGE_TYPE_AGENT_RESULTMESSAGE_NAME = \"agentresult\";\n /**\n * 智能体用户输入消息\n */\n public static final String MESSAGE_TYPE_USER_MESSAGE_NAME = \"user\";\n\n /**\n * 智能体辅助消息\n */\n public static final String MESSAGE_TYPE_ASSISTANT_MESSAGE_NAME = \"assistant\";\n\n /**\n * 智能体辅助消息:工具调用结果消息,需要提交给大模型\n */\n public static final String MESSAGE_TYPE_TOOL_MESSAGE_NAME = \"tool\";\n\n\n /**\n * 智能体工具搜索匹配消息\n */\n public static final String MESSAGE_TYPE_TOOLSEARCH_MESSAGE_NAME = \"toolsearch\";\n\n\n /**\n * 智能体系统消息\n */\n public static final String MESSAGE_TYPE_SYSTEM_MESSAGE_NAME = \"system\";\n\n\n\n /**\n * 智能体跟踪消息\n */\n public static final String MESSAGE_TYPE_TRACE_MESSAGE_NAME = \"trace\";\n\n /**\n * 智能体RAG知识消息\n */\n public static final String MESSAGE_TYPE_RAG_MESSAGE_NAME = \"rag\";\n\n /**\n * 智能体拒答消息\n */\n public static final String MESSAGE_TYPE_REFUSE_MESSAGE_NAME = \"refuse\";\n\n /**\n * 智能体mcp服务调用消息名称\n */\n public static final String MESSAGE_TYPE_MCPCALL_MESSAGE_NAME = \"mcpcall\";\n\n /**\n * 智能体工具服务调用消息\n */\n public static final String MESSAGE_TYPE_TOOLCALL_MESSAGE_NAME = \"toolcall\";\n\t\n\t/**\n\t * 智能体Skill调用消息\n\t */\n\tpublic static final String MESSAGE_TYPE_SKILLCALL_MESSAGE_NAME = \"skillcall\";\n\t\n\t/**\n\t * 智能体人工介入消息\n\t */\n\tpublic static final String MESSAGE_TYPE_HITL_MESSAGE_NAME = \"hitltask\";\n\t\n\t\n\t/**\n\t * 智能体人工介入处理消息\n\t */\n\tpublic static final String MESSAGE_TYPE_HITL_HANDLE_MESSAGE_NAME = \"hitlhandle\";\n```\n\n#### 3.1.3 扩展消息类型\n\nAgentMessageTypeConvertor提供以上内置角色名称到消息类型的转换,如果用户需要扩展自己的消息角色和编码,可以继承AgentMessageTypeConvertor类并重写convertMessageType方法,0-100为系统内置编码,如果用户自定义编码请从101开始,示例如下:\n\n```java\npublic class CustomAgentMessageTypeConvertor extends AgentMessageTypeConvertor {\n /**\n * 将角色转换为消息类型messageType,对应agent_session_message表中的messageType字段 \n *\n * @param role\n * @return\n */\n @Override\n public String convertMessageType(String role) {\n if(\"custom\".equals(role)){\n return \"101\";\n }\n return super.convertMessageType(role);\n }\n}\n```\n\n使用自定义转换器:\n\n```java\nStoreContext storeContext = new StoreContext();\nstoreContext.setAgentMessageTypeConvertor(new CustomAgentMessageTypeConvertor());\n```\n\n#### 3.1.3 使用场景\n\n消息类型使用场景:在智能体编排流程中设置消息角色类型\n\n```java\n TraceMessage traceMessage = new TraceMessage(); \n //记录用户输入的原始问题\n traceMessage.setMessage(Map.of(\"question\", question,\"role\",SessionMessage.MESSAGE_TYPE_USERINPUTMESSAGE_NAME));\n //其他用户上传的附件材料信息可以放到metaData中,也可以直接放到上面的消息中\n\n traceMessage.setStartTime(System.currentTimeMillis());\n\n planAgent.recordTraceMessage(traceMessage);\n```\n\n#### 3.1.4 ServerEvent结构\n\n```java\ncontentType:主要用来区分答案正文内容和思维链内容,0表示答案内容,1表示思维链内容, 2 表示工具调用,3 表示mcp服务调用,5 表示监控对象,默认值为0\n\n type 字段:标记消息报文类型 \n /**\n * 数据报文类型:0 数据消息,1表示异常消息,2 trace信息,traceId 3 拒答消息 5 知识库资料消息 6 步骤消息\n * 默认值为0 \n */\ntype = TYPE_DATA;\n数据报文类型常量说明\n /**\n * type:数据消息\n */\n public static final int TYPE_DATA = 0;\n /**\n * type:异常消息\n */\n public static final int TYPE_ERROR = 1;\n\n /**\n * type:trace信息,traceId\n */\n public static final int TYPE_TRACE = 2;\n /**\n * type:拒绝消息:\n */\n public static final int TYPE_REFUSAL = 3;\n \n /**\n * type:知识库资料消息:\n */\n public static final int TYPE_RAG_KNOWLEDGE = 5;\n\n /**\n * type:步骤消息:\n */\n public static final int TYPE_STEP = 6;\n```\n\n#### 3.1.5 属性说明\n\n| 参数 | 说明 |\n| -------------- | ---------------- |\n| `agentId` | 智能体唯一标识 |\n| `agentName` | 智能体名称 |\n| `prompt` | 用户提示词 |\n| `systemPrompt` | 系统提示词 |\n| `model` | 模型名称 |\n| `maas` | MaaS平台服务名 |\n| `stream` | 是否开启流式响应 |\n| `thinking` | 是否开启思考过程 |\n\n---\n\n### \n\n### 3.2 初始化配置\n\n在应用启动时加载配置文件:\n\n```java\nimport org.frameworkset.spi.remote.http.HttpRequestProxy;\n\npublic class Application {\n public void init() {\n // 加载模型服务配置文件\n HttpRequestProxy.startHttpPools(\"application-stream.properties\");\n \n // 加载 MCP 服务配置文件\n HttpRequestProxy.startHttpPools(\"mcpserver.properties\");\n }\n}\n```\n\n### 3.3 同步聊天(非流式)\n\n```java\nimport org.frameworkset.spi.ai.AIAgent;\nimport org.frameworkset.spi.ai.model.ChatAgentMessage;\nimport org.frameworkset.spi.ai.model.ServerEvent;\n\npublic class ChatExample {\n public static void main(String[] args) {\n // 初始化配置\n HttpRequestProxy.startHttpPools(\"application-stream.properties\");\n \n // 创建消息对象\n ChatAgentMessage chatAgentMessage = new ChatAgentMessage();\n chatAgentMessage.setModel(\"deepseek-chat\"); // 模型名称\n chatAgentMessage.setPrompt(\"介绍一下 Java Reactor 编程模式\");\n chatAgentMessage.setSystemPrompt(\"你是一个编程大师\");\n chatAgentMessage.setTemperature(0.7); // 温度参数\n chatAgentMessage.setMaxTokens(8192); // 最大输出 Token\n \n // 创建 AIAgent 并调用\n AIAgent aiAgent = new AIAgent();\n ServerEvent response = aiAgent.chat(\"deepseek\", chatAgentMessage);\n \n // 输出结果\n System.out.println(response.getData());\n }\n}\n```\n\n### 3.4 流式聊天\n\n```java\nimport reactor.core.publisher.Flux;\nimport java.util.concurrent.CountDownLatch;\n\npublic class StreamChatExample {\n public static void main(String[] args) throws InterruptedException {\n // 初始化配置\n HttpRequestProxy.startHttpPools(\"application-stream.properties\");\n\n // 创建消息对象,设置 stream=true\n ChatAgentMessage chatAgentMessage = new ChatAgentMessage();\n chatAgentMessage.setModel(\"deepseek-chat\");\n chatAgentMessage.setPrompt(\"介绍一下 Java Reactor 编程模式\");\n chatAgentMessage.setStream(true);\n chatAgentMessage.setTemperature(0.7);\n chatAgentMessage.setMaxTokens(8192);\n\n CountDownLatch countDownLatch = new CountDownLatch(1);\n\n AIAgent aiAgent = new AIAgent();\n Flux flux = aiAgent.streamChat(\"deepseek\", chatAgentMessage);\n\n flux.doOnSubscribe(subscription -> System.out.println(\"开始订阅流...\"))\n .doOnNext(chunk -> {\n if (chunk.getData() != null) {\n System.out.print(chunk.getData());\n }\n })\n .doOnComplete(() -> {\n System.out.println(\"\\n=== 流完成 ===\");\n countDownLatch.countDown();\n })\n .doOnError(error -> {\n error.printStackTrace();\n countDownLatch.countDown();\n })\n .subscribe();\n\n // 等待异步完成\n countDownLatch.await();\n }\n}\n```\n\n### 3.5 多轮会话\n\n```java\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class SessionChatExample {\n // 静态会话记忆列表\n static List