
在實際項目里把一個大模型接進業務系統并不難難的是讓它從一個“你問它答”的問答接口變成一個能查數據、調接口、做決策的自主智能體。阿里云 Qwen千問系列模型在當前的模型版本中已經支持工具調用Function Calling配合阿里云百煉平臺的托管能力和開源部署方案已經可以搭出一條從問答到自主智能體的完整路徑。這篇文章會沿著這條路徑展開先把 Qwen 的最小問答鏈路跑通再解釋 Function Calling 為什么是智能體的核心機制然后補上記憶層Embedding Milvus 檢索最后給出生產環境的落地建議和排錯清單。學完以后你可以在自己的項目里實現一個能查詢業務數據、調用內部接口并且帶檢索記憶的智能體服務。1. 先理解“問答”和“自主智能體”的邊界1.1 問答模型解決的是“生成”不是“行動”一個尚未集成任何工具的 Qwen 問答接口本質上完成的是“文本生成”任務。你給它一段用戶問題它根據訓練時學習到的知識、當前上下文和生成參數返回一段最可能的文本。這個過程的輸入輸出都是文本模型沒有權限去查數據庫、沒有能力去調用 HTTP 接口也不會主動更新自己的知識。這也是很多項目把模型接上線以后發現它只能“聊”不能“干”的原因。在工程上純問答模型適合的場景包括客服話術生成、代碼注釋、文檔摘要、翻譯、規則問答。這些場景的共同點是答案要么藏在模型的參數里要么已經出現在用戶提供的上下文里。一旦問題需要“實時數據”例如“查一下這個訂單現在到哪了”純問答模型就失效了因為它并不知道訂單系統的當前狀態。1.2 自主智能體多了四個能力模塊從問答模型升級到自主智能體不是換一個更大的模型而是要在模型外面補一套決策和執行的機制。業內通常把智能體拆成四個部分大腦負責理解用戶意圖、拆解任務、決定下一步動作。這里仍然是 Qwen 模型但每次請求的輸入不再只是用戶問題而是“系統提示詞 歷史對話 工具定義 當前任務”。工具模型本身不能直接執行動作必須通過一段代碼或一個 API 向模型暴露能力。常見的工具包括查詢訂單接口、天氣接口、數據庫查詢、文件讀寫、網頁檢索。記憶分為短期記憶和長期記憶。短期記憶是對話歷史長期記憶通常用向量數據庫保存業務知識通過檢索把最相關的內容注入上下文。循環智能體不是一次請求就結束。模型先輸出“我準備調用某個工具參數是什么”程序去執行工具把工具結果回填給模型模型再決定繼續調用下一個工具還是給出最終答案。這個“計劃 - 調用 - 觀察 - 再計劃”的循環就是智能體與普通問答的本質區別。1.3 當前工程落地的形態人機協同為主有限自主執行從當前實際落地的項目看完整意義上的“全自主智能體”在大多數業務場景里還很少見。常見形態是“人機協同為主、有限自主執行”系統允許智能體在限定范圍內自主調用只讀查詢類工具但涉及寫操作、支付、刪除、發送消息等高風險動作時必須回到人工確認。這個設計不是技術做不到而是為了可控。你在實現智能體時建議把工具按風險分級風險級別工具示例執行策略低風險只讀查詢訂單狀態、查天氣、檢索知識庫智能體自主執行中風險寫操作修改草稿、發送測試消息記錄日志后執行可回滾高風險動作支付、刪除數據、對外發布生成待確認動作人工確認后執行2. 環境準備Qwen 接入的三種方式2.1 方式一通過阿里云百煉 API 接入阿里云百煉Model Studio是 Qwen 系列模型的托管平臺。它的優勢在于不需要自己準備 GPU 服務器開通服務后拿到 API Key 就可以調用。目前百煉提供兼容 OpenAI Chat Completions 格式的接口因此主流的 Python、Java、Node.js 等語言都能快速接入。接入前需要準備一個阿里云賬號并開通百煉服務。在控制臺創建 API Key。注意 Key 只顯示一次要立即保存。確定調用模型名。常見的有 qwen-plus、qwen-turbo以及工具調用能力更完整的 qwen-max 等。不同模型名對應的上下文長度和費用不同落地前要去百煉控制臺確認最新的模型列表。注意api_key 不要硬編碼在代碼里。學習階段可以放環境變量生產階段必須放到密鑰管理服務或者配置中心。2.2 方式二把 Qwen 部署到自己的服務器如果業務有數據隔離要求或者調用量很大、長期使用可以考慮在自有服務器上部署 Qwen 開源模型。Qwen 提供了多個參數規模的開源版本。參數越小部署越容易但能力越弱參數越大能力越強對 GPU 顯存要求越高。以常見情況為例模型規模顯存需求示例適用場景小參數模型消費級顯卡或小顯存實例學習、原型驗證、簡單問答中等規模單張企業級 GPU專業問答、代碼生成大規模模型多卡部署或分布式推理復雜推理、工具調用、生產環境本地部署需要額外處理模型下載、推理框架、GPU 驅動、并發排隊等問題。建議先在開發機跑通再遷移到云端 GPU 實例。OpenAI 兼容層的部署配置以官方部署文檔為準不要憑記憶猜測版本參數。2.3 方式三Java 項目里配置阿里云 Maven 倉庫和 Spring Initializr如果項目是 Java 技術棧第一個遇到的問題常常不是代碼而是依賴下載。在 Maven 的 settings.xml 中配置阿里云鏡像倉庫可以顯著提升依賴拉取速度mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共倉庫/name urlhttps://maven.aliyun.com/repository/public/url /mirror這段配置的作用是把原本從中央倉庫拉取的依賴改從國內鏡像拉取。需要注意的是鏡像倉庫只是下載源不改變依賴的坐標和版本。不同團隊還可能使用私服這時要結合私服策略調整mirrorOf避免所有倉庫都被鏡像接管。新建 Spring Boot 項目時也可以使用阿里云的 Spring Initializr 服務地址https://start.aliyun.com 。它提供的是經過阿里云適配的初始化模板適合需要快速生成標準工程的情況。如果團隊內部有統一腳手架優先使用內部版本。2.4 三種接入方式的對比接入方式成本數據控制部署難度推薦場景百煉 API按調用量計費數據經云服務處理低快速原型、中小規模、開發測試自建部署硬件加運維成本數據留在自己環境高數據隔離、大規模長期調用Java 生態集成與接入方式疊加與接入方式相關中已有 Spring Boot 體系接入方式之間不是互斥的。常見做法是開發環境用百煉 API 快速跑通生產環境根據數據合規和成本評估是否遷移到自建部署。遷移時代碼層盡量使用兼容接口讓切換成本降到最低。3. 跑通最小問答鏈路3.1 最小 Python 示例先跑通一個最小的問答鏈路再談智能體。這里使用 Python 的 openai SDK通過兼容模式訪問百煉import os from openai import OpenAI client OpenAI( api_keyos.getenv(DASHSCOPE_API_KEY), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) response client.chat.completions.create( modelqwen-plus, messages[ {role: system, content: 你是一名經驗豐富的 Java 架構師。}, {role: user, content: 用三句話解釋什么是 Function Calling。} ], temperature0.7, max_tokens512 ) print(response.choices[0].message.content)運行前確認兩點第一環境變量 DASHSCOPE_API_KEY 已設置第二網絡環境能訪問 base_url。如果網絡策略禁用了外部域名請求需要先確認百煉 endpoint 是否在訪問白名單里。3.2 關鍵參數說明參數含義常見取值調大影響調小影響temperature采樣隨機性0.0 到 1.0回答更多樣可能不穩定回答更確定偏向保守top_p核采樣比例0.1 到 1.0候選詞更多候選詞更集中max_tokens單次最大生成 token 數128 到 4096按模型輸出更長成本更高輸出可能被截斷messages對話消息列表按角色排列上下文更完整但可能超限上下文不足可能導致遺忘在函數調用場景里temperature 建議設置得低一些例如 0.2 到 0.4。工具調用要求模型輸出穩定的 JSON 參數隨機性太大會導致參數格式錯誤或參數值漂移。3.3 運行和驗證運行上面的腳本正常情況下會輸出一段關于 Function Calling 的解釋。這里要驗證的不只是“有輸出”而是輸出是否滿足要求。可以依次驗證修改 system 提示詞觀察回答風格是否變化。修改 temperature比較同一問題的穩定性和多樣性。故意給一個超出 max_tokens 的復雜問題觀察輸出是否被截斷并理解如何通過流式輸出解決。這一步能幫你確認 API Key、網絡、模型名、參數四條鏈路都正常。如果其中任何一環有問題后面的智能體代碼都會失敗所以不要跳過。3.4 這一步最常見的坑第一個坑是模型名寫錯。不同區域、不同賬號可能支持的模型名不同報錯信息里會顯示類似 model not found 的提示。處理方式是去百煉控制臺查看支持列表不要憑記憶猜測。第二個坑是 API Key 設置錯誤。常見現象是 401 或 InvalidApiKey。檢查環境變量是否真的傳入了進程可以在腳本里打印 Key 的前幾位和后幾位用于確認但不要完整打印。第三個坑是把 max_tokens 設太小。問答內容稍長就會被截斷看起來像“回答不完整”。實際上模型輸出被強制停止了需要調大 max_tokens 或改用流式輸出。4. Function Calling問答升級為智能體的核心機制4.1 為什么模型本身不能直接調用工具模型是一個文本生成器它沒有權限訪問你的系統也不會連接外部服務。所謂 Function Calling本質是“模型決定要調用哪個工具并生成調用參數”真正執行工具的是你的代碼。模型輸出的不是最終答案而是一個結構化的“調用請求”。因此實現工具調用必須有兩部分一部分是向模型聲明“你有這些工具可用每個工具的參數長什么樣”另一部分是程序端執行工具后把結果以新的消息形式回傳給模型讓模型生成最終回答。缺了任意一部分工具調用都無法成立。4.2 工具定義的 JSON Schema向模型聲明工具時通常使用 JSON Schema 描述每個工具的名稱、描述、參數類型和必填項。描述寫得越清楚模型越不容易選錯工具。下面是一個查詢訂單狀態的工具定義{ type: function, function: { name: query_order_status, description: 根據訂單號查詢訂單當前狀態。只有用戶明確提供了訂單號時才調用。, parameters: { type: object, properties: { order_id: { type: string, description: 用戶提供的訂單號例如 OD202501010001 } }, required: [order_id] } } }注意幾個細節description 里要說明“何時調用”和“何時不調用”required 里明確必填參數參數類型盡量精確避免讓模型自行猜測。工具定義本身是 prompt 的一部分也會占用上下文 token因此不要無限制地加工具只保留當前任務真正需要的。4.3 一個帶工具循環的智能體實現下面用 Python 寫一個最簡智能體循環。流程是用戶提問 - 模型判斷是否調用工具 - 程序執行工具 - 回傳結果 - 模型生成最終回答。import json import os from openai import OpenAI client OpenAI( api_keyos.getenv(DASHSCOPE_API_KEY), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) def query_order_status(order_id: str) - str: # 實際項目中這里會調用內部訂單服務 return f訂單 {order_id} 的狀態是已發貨預計明天送達。 tools [ { type: function, function: { name: query_order_status, description: 根據訂單號查詢訂單當前狀態, parameters: { type: object, properties: { order_id: { type: string, description: 用戶提供的訂單號 } }, required: [order_id] } } } ] def run_agent(user_message: str, max_steps: int 3) - str: messages [ {role: system, content: 你是訂單助手。用戶詢問訂單狀態時先調用工具查詢再用自然語言回復。}, {role: user, content: user_message} ] for step in range(max_steps): response client.chat.completions.create( modelqwen-plus, messagesmessages, toolstools, tool_choiceauto ) message response.choices[0].message if message.tool_calls: messages.append({ role: assistant, tool_calls: [ { id: tc.id, type: function, function: { name: tc.function.name, arguments: tc.function.arguments } } for tc in message.tool_calls ] }) for tc in message.tool_calls: args json.loads(tc.function.arguments) result query_order_status(args[order_id]) messages.append({ role: tool, tool_call_id: tc.id, content: result }) else: return message.content return 已達到最大執行步數無法完成用戶的請求。 print(run_agent(幫我查一下訂單 OD202501010001 到哪了))這段代碼有四個關鍵點每輪請求都要把之前的消息完整傳給模型尤其是 tool 調用結果。模型需要看到工具返回內容才能繼續推理。程序執行工具后必須使用 tool 角色并帶上 tool_call_id與模型輸出的工具調用請求一一對應。max_steps 是循環上限防止智能體在工具間反復橫跳消耗大量調用成本。每個工具內部要做好異常處理。工具拋異常時要把錯誤信息回傳給模型讓模型決定是換參數重試還是給用戶一個合理答復而不是直接讓整個程序崩潰。注意不要把工具返回結果原樣無限制地回填給模型。工具返回的可能是大段 JSON 或長文本回填前要按需裁剪字段控制上下文 token 消耗。4.4 工具調用流程里最容易出錯的地方工具參數解析很容易踩坑。模型輸出的 arguments 是 JSON 字符串但有時包含多余空格、換行甚至缺失字段。建議使用寬松解析方式解析失敗時回退到正則提取并把整段原文記錄下來方便排查。另外一個常見問題是工具描述不明確導致模型在不需要工具時也調用工具。比如用戶只是閑聊“你好”模型不該去查訂單。解決方式是在工具描述里增加觸發條件并在 system 提示詞里明確“只有用戶提供訂單號時才調用查詢工具”。還需要注意 tool_choice 參數。默認 auto 讓模型自己決定是否調用工具如果業務想強制模型必須調用某個工具可以設為指定工具名。但強制調用會犧牲模型的判斷能力一般只在不需要判斷的場景使用。5. 給智能體加上記憶Qwen Embedding Milvus 檢索5.1 什么時候需要外部記憶智能體在對話中會產生兩類記憶需求。第一類是會話內的短期記憶通過把歷史 messages 傳入模型來實現。第二類是跨會話的長期記憶比如企業知識庫、歷史工單、產品文檔。這些內容不可能全部塞進模型上下文因為 token 有限且成本高所以需要先做檢索只把最相關的片段注入提示詞。當出現以下信號時就該接入外部記憶用戶問題涉及私有文檔、內部知識模型訓練時沒有見過。用戶問題需要綜合多份文檔才能回答。智能體每次回答前都需要相同背景材料重復寫入提示詞太浪費。希望通過業務數據生成個性化回答而不是每次從頭問起。5.2 RAG 工作流程檢索增強生成Retrieval-Augmented Generation的流程分兩步。第一步是離線準備把業務文檔切分成片段對每個片段生成向量寫入向量數據庫。第二步是在線檢索用戶提問時先生成問題的向量再在向量數據庫中查找最相似的片段把片段作為上下文拼到消息里最后讓模型生成回答。切分是決定效果的關鍵。切得太大會引入無關內容切得太小會讓語義不完整。常見做法是按標題和段落語義切分每個片段控制在幾百 token 左右同時保留來源信息方便回答時溯源。5.3 Java LangChain4j Milvus 接入示例在 Java 技術棧里可以使用 LangChain4j 簡化向量檢索的接入。LangChain4j 提供統一 API屏蔽了向量數據庫的差異。下面是一個示例 Maven 依賴片段dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version${langchain4j.version}/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-milvus/artifactId version${langchain4j.version}/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai/artifactId version${langchain4j.version}/version /dependency版本號${langchain4j.version}需要替換為你實際使用的穩定版本并且要與 Spring Boot 版本兼容。依賴下載前確認 Maven 鏡像配置已生效。寫入和檢索的示例結構如下EmbeddingModel embeddingModel OpenAiEmbeddingModel.builder() .baseUrl(https://dashscope.aliyuncs.com/compatible-mode/v1) .apiKey(System.getenv(DASHSCOPE_API_KEY)) .modelName(text-embedding-v3) .build(); MilvusEmbeddingStore embeddingStore MilvusEmbeddingStore.builder() .host(127.0.0.1) .port(19530) .collectionName(qwen_agent_kb) .dimension(1024) .build();先把文檔片段轉成向量并寫入再在回答時按相似度檢索。這里要注意 dimension向量維度必須與 Embedding 模型輸出的維度一致不一致時寫入會報維度錯誤。embedding 模型名和維度參數在不同階段可能調整落地前以當前 API 文檔為準。5.4 集合設計和檢索參數字段作用推薦設置collectionName知識庫集合名按業務域命名如 order_kb、policy_kbdimension向量維度與 embedding 模型輸出一致metricType相似度算法常用 COSINE 或 IP按數據特點選擇id主鍵使用業務側生成的唯一 IDcontent原始文本保存原文方便回填上下文metadata元數據來源、時間、權限域便于過濾檢索時還需要設置 topK 和相似度閾值。topK 控制返回片段數量一般取 3 到 10。閾值過嚴會漏掉相關內容過松會引入噪音。不要只看 topK建議同時輸出得分人工抽樣評估一次找到當前文檔集的合理閾值。6. 運行驗證和常見問題排查6.1 一套可復用的驗證順序智能體項目上線前建議按這個順序驗證單次問答是否正常不攜帶工具時基本問答能正確返回。工具聲明是否生效輸入一個明確需要工具的提問確認模型輸出了 tool_calls。工具執行是否正確查看程序實際調用了哪個函數傳參是否合理。工具結果回填是否成功確認 tool 角色的消息帶上了正確的 tool_call_id。最終回答是否基于工具結果檢查回答內容是否引用了工具返回的數據而不是模型自己編造。異常分支是否可控工具拋錯、模型連續調用工具、上下文超限時程序是否能優雅退出。6.2 問題現象、原因和處理表問題現象常見原因檢查方式處理建議模型回答完全不調用工具工具未傳入、描述不清、模型不支持打印請求中的 tools 字段檢查 model 名確認傳入 tools增強 description換支持工具調用的模型工具調用了但程序沒執行只把工具發給模型沒有寫執行分支檢查代碼是否解析了 message.tool_calls補上 for 循環執行工具的邏輯工具結果回傳后模型仍錯答tool_call_id 不匹配或消息順序錯誤打印 messages 列表檢查角色確保 tool 消息緊跟對應的 assistant tool_calls 消息上下文超限歷史消息或工具結果越來越大查看報錯信息中的 token 數接入摘要機制裁剪歷史限制工具返回長度參數解析失敗模型輸出非法 JSON打印原始 arguments增加容錯解析記錄原文定位模型輸出問題檢索結果與問題無關切分粒度差、embedding 不匹配、閾值不對單獨跑檢索用例檢查召回優化切分、重選 embedding 模型、調整閾值6.3 排查鏈路遇到問題按鏈路從下往上排網絡和 Key先確認 base_url 可達API Key 有效。請求參數打印完整請求體逐字段確認 tools、messages、model 是否符合預期。模型返回查看原始響應區分是沒生成 tool_calls還是生成了