Llama Index ReActAgent无法同时使用两个Tool Spec问题求助
问题:Llama Index ReActAgent同时启用OpenAPIToolSpec与RequestsToolSpec时忽略前者的解决方案
问题概况
- 单独使用OpenAPIToolSpec时,查询"获取列出我的公司的完整API调用"可返回正确接口地址;
- 单独使用RequestsToolSpec时,调用指定API可返回正确公司数据;
- 同时启用两个Tool Spec时,Agent跳过
load_openapi_spec调用,直接使用RequestsToolSpec的默认配置发起请求导致失败; - Agent能正常列出所有工具,自定义简单工具可协同工作,多次调整系统提示未生效。
相关代码示例
import asyncio import logging import os from dotenv import load_dotenv from llama_index.core.agent import ReActAgent from llama_index.core.agent.workflow import AgentStream from llama_index.core.workflow import Context from llama_index.llms.bedrock_converse import BedrockConverse from llama_index.tools.openapi import OpenAPIToolSpec from llama_index.tools.requests.base import RequestsToolSpec load_dotenv() logger = logging.getLogger('my-agent') logging.basicConfig(level=logging.INFO) model_id = os.getenv("FOUNDATION_MODEL") aws_region = os.getenv("AWS_REGION") llm = BedrockConverse( model=model_id, region_name=aws_region, max_tokens=10000, temperature=0.1 ) openapi_tool = OpenAPIToolSpec( url=os.getenv("API_ENDPOINT") + "/openapi.json", ) requests_tool = RequestsToolSpec( domain_headers={ os.getenv("API_DOMAIN"): { "Authorization": f"Bearer {os.getenv('ACCESS_TOKEN')}", "Content-Type": "application/json", } } ) system_prompt = """ You are an agent with two tools: load_openapi_spec and post_request. - FIRST, use load_openapi_spec to select the correct API endpoint and parameters from the provided OpenAPI specification based on the user's query. - SECOND, use post_request to make the HTTP request to the selected endpoint with the appropriate method and parameters. """ agent = ReActAgent( tools=openapi_tool.to_tool_list() + requests_tool.to_tool_list(['post_request']), llm=llm, verbose=True, system_prompt=system_prompt ) ctx = Context(agent) async def main(user_message: str): handler = agent.run(user_message, ctx=ctx) buffer = "" async for ev in handler.stream_events(): if isinstance(ev, AgentStream): buffer += ev.delta if '\n' in buffer: lines = buffer.split('\n') for line in lines[:-1]: logger.info(line) buffer = lines[-1] response = await handler logger.info(f"Final response: {response}") prompt = "<My prompt here...>" asyncio.run(main(prompt))
错误响应示例
INFO:my-agent:Action Input: {"url_template": "https://api.example.com/api/companies", "body": {}}Thought: ``` INFO:my-agent:Thought: The current language of the user is: English. I cannot answer the question with the provided tools. INFO:my-agent:Answer: I cannot list your companies because the API endpoint provided is not valid. Please provide a valid API endpoint. INFO:my-agent:Final response: I cannot list your companies because the API endpoint provided is not valid. Please provide a valid API endpoint.
自定义工具协同正常示例
def multiply(a: int, b: int) -> int: """Multiply two integers and returns the result integer""" return a * b def add(a: int, b: int) -> int: """Add two integers and returns the result integer""" return a + b agent = ReActAgent(tools=[multiply, add], llm=llm)
解决方案建议
1. 强化工具描述,引导LLM优先选择
给OpenAPIToolSpec的工具添加明确的强制指令描述,让LLM清晰认知调用顺序:
openapi_tools = openapi_tool.to_tool_list() # 给load_openapi_spec工具添加强约束描述 for tool in openapi_tools: if tool.metadata.name == "load_openapi_spec": tool.metadata.description = "【必须优先调用】加载OpenAPI规范,获取与用户查询匹配的正确API端点、请求方法和参数,只有调用此工具后,才能使用post_request发起请求" requests_tools = requests_tool.to_tool_list(['post_request']) # 给post_request添加依赖提示 for tool in requests_tools: tool.metadata.description = "必须在调用load_openapi_spec获取有效API信息后,才能使用此工具发送HTTP请求" # 重新初始化agent agent = ReActAgent( tools=openapi_tools + requests_tools, llm=llm, verbose=True, system_prompt=system_prompt )
2. 自定义工具检索逻辑,强制优先级
通过tool_retriever指定工具选择顺序,确保load_openapi_spec被优先考虑:
from llama_index.core.tools import FixedToolRetriever # 先获取openapi工具,再获取requests工具 all_tools = openapi_tool.to_tool_list() + requests_tool.to_tool_list(['post_request']) # 创建固定顺序的工具检索器,优先返回openapi工具 tool_retriever = FixedToolRetriever(tools=all_tools) agent = ReActAgent( tools=all_tools, llm=llm, verbose=True, system_prompt=system_prompt, tool_retriever=tool_retriever )
3. 封装复合工具,强制执行流程
将两个工具的逻辑封装成一个复合工具,确保先执行load_openapi_spec再发起请求:
from llama_index.core.tools import FunctionTool import json async def fetch_companies(): # 获取load_openapi_spec工具并调用 load_spec_tool = next(t for t in openapi_tool.to_tool_list() if t.metadata.name == "load_openapi_spec") spec_result = await load_spec_tool.call() # 解析OpenAPI规范,提取列出公司的接口信息 spec_data = json.loads(spec_result) # 假设从spec中提取到正确的POST端点 endpoint = spec_data["paths"]["/api/companies"]["post"]["url"] # 获取post_request工具并调用 post_tool = next(t for t in requests_tool.to_tool_list(['post_request']) if t.metadata.name == "post_request") request_result = await post_tool.call(url_template=endpoint, body={}) return request_result # 创建复合工具 fetch_companies_tool = FunctionTool.from_defaults(fn=fetch_companies, name="fetch_companies", description="获取公司列表,自动先加载OpenAPI规范再发起请求") # 用复合工具初始化agent agent = ReActAgent( tools=[fetch_companies_tool], llm=llm, verbose=True )
4. 优化系统提示,增强指令约束
修改系统提示为更具强制性的措辞:
system_prompt = """ 你必须严格遵循以下步骤处理用户请求: 1. 第一步:调用load_openapi_spec工具,加载并解析OpenAPI规范,从中找到与用户查询匹配的API端点、请求方法和参数。 2. 第二步:基于第一步获取的信息,调用post_request工具发起HTTP请求。 绝对不能跳过第一步直接调用post_request,否则请求会失败。 """
5. 降低LLM温度,增强指令遵循性
将temperature调整为0,让LLM更严格执行指令:
llm = BedrockConverse( model=model_id, region_name=aws_region, max_tokens=10000, temperature=0 # 从0.1改为0 )
内容的提问来源于stack exchange,提问作者UserX
相关产品推荐
相关产品推荐

