通过Hugging Face端点调用Mistral AI函数时的循环调用问题
问题解决:Mistral AI函数调用的格式适配与多轮对话处理
核心问题分析
- 格式不兼容:Mistral-7B-Instruct-v0.3要求使用特定对话格式(如
[INST]/[/INST]包裹指令、多轮对话用角色标注结构),LangChain的ChatPromptTemplate默认格式无法被模型正确识别,导致工具调用逻辑失效。 - 工具结果回传失败:直接用
ChatMessage(role='function')追加工具返回结果时,Mistral模型无法识别该角色类型,因此持续触发工具调用而非生成最终回复。
解决方案步骤
1. 自定义符合Mistral要求的对话模板
放弃ChatPromptTemplate,手动构建字符串格式,严格遵循Mistral的Instruct规范:
- 系统提示+初始请求用
[INST]包裹 - 助手回复用
[/INST]引导 - 工具返回结果以明确的补充信息形式加入对话,确保模型能识别这是已获取的外部数据。
2. 调整工具调用后的消息格式
将工具返回的结果转换为模型可理解的文本形式,明确告知模型“已获取所需数据,请生成最终回复”,避免模型重复触发工具调用。
3. 优化工具绑定逻辑
Mistral的工具调用格式与OpenAI存在差异,需手动指定函数调用的输出格式要求,确保模型返回的调用指令能被正确解析。
修改后的完整代码
# Import necessary libraries from langchain_huggingface.chat_models import ChatHuggingFace from langchain_huggingface import HuggingFaceEndpoint from langchain_core.utils.function_calling import convert_to_openai_function from dotenv import load_dotenv, find_dotenv import os import serpapi import json # Load environment variables _ = load_dotenv(find_dotenv()) serp_key = os.getenv('SERP_API_KEY') # Configure the LLM endpoint llm = HuggingFaceEndpoint( repo_id='mistralai/Mistral-7B-Instruct-v0.3', huggingfacehub_api_token='*********', task="text-generation", model_kwargs={ "max_new_tokens": 2000, "temperature": 0.5, "top_p": 0.95, "do_sample": True } ) # Define functions functions = [ { "name": "plan_holiday", "description": "获取指定目的地的旅游景点信息,用于制定旅行计划", "parameters": { "type": "object", "properties": { "destination": { "type": "string", "description": "旅行目的地", }, "duration": { "type": "integer", "description": "旅行天数", }, }, "required": ["destination", "duration"], }, } ] # 转换为OpenAI格式的工具定义 openai_functions = [convert_to_openai_function(f) for f in functions] # 创建带工具绑定的模型 chat_model = ChatHuggingFace(llm=llm) llm_with_tools = chat_model.bind_tools(openai_functions, tool_choice='auto') # 手动构建符合Mistral格式的初始对话 system_prompt = "你是专业旅行规划师,需要根据用户需求制定详细旅行计划。如果需要外部景点信息,调用plan_holiday工具获取,获取后直接生成最终计划,无需再次调用工具。" user_query = "我想在威尼斯度过12天的假期,能帮我规划吗?" # Mistral要求的初始提示格式 initial_prompt = f"""<s>[INST] {system_prompt} 用户请求:{user_query} 可用工具: {str(openai_functions)} 如果需要调用工具,请返回以下格式的JSON: {{"name": "工具名称", "parameters": {{"参数名": "参数值"}}}}[/INST]""" # 第一次调用模型(触发工具调用) response = llm_with_tools.invoke(initial_prompt) print("第一次模型响应:", response) # 解析工具调用请求 tool_call = response.additional_kwargs.get('tool_calls', [])[0] tool_name = tool_call['function']['name'] tool_args = json.loads(tool_call['function']['arguments']) # 调用外部API获取数据 def search_google_for(destination): client = serpapi.Client(api_key=serp_key) result = client.search( params={ "q": f"{destination} 12天旅行景点推荐", "location": "India", "hl": "en", "gl": "IN", "google_domain": "google.com", } ) return result results = search_google_for(tool_args['destination']) # 提取工具返回的信息 info_about_places = "" if results.get("organic_results"): for idx, result in enumerate(results["organic_results"], 1): title = result.get("title", "") snippet = result.get("snippet", "") info_about_places += f"{idx}. {title}\n{snippet}\n\n" # 构建包含工具结果的第二轮对话,符合Mistral格式 second_prompt = f"""<s>[INST] {system_prompt} 用户请求:{user_query} 已调用{tool_name}工具,获取到以下威尼斯旅游信息: {info_about_places} 请基于以上信息生成详细的12天威尼斯旅行计划,无需再调用任何工具。[/INST]""" # 第二次调用模型(生成最终回复) final_response = llm.invoke(second_prompt) print("最终旅行计划:", final_response)
关键修改说明
- 格式适配:采用Mistral官方要求的
<s>[INST] ... [/INST]格式构建提示,确保模型正确解析指令与上下文。 - 工具结果呈现:将工具返回信息直接嵌入提示,明确告知模型无需再次调用工具,引导生成最终回复。
- 逻辑简化:放弃LangChain消息列表管理,改用手动构建字符串的方式,彻底避免格式不兼容问题。
内容的提问来源于stack exchange,提问作者Neo_clown
相关产品推荐
相关产品推荐

