如何向作为工具的LLMCypherGraphChain传递多参数并适配AgentExecutor?
我正在构建一个与Neo4j交互的Agent,采用自定义LLMCypherGraphChain作为工具(已知有现成实现但选择自定义)。当前无法向该工具传递多个任意参数,需要了解如何从Agent/工具创建阶段、AgentExecutor执行阶段传递参数。
代码情况
自定义链定义
class LLMCypherGraphChain(Chain, BaseModel): input_key: List[str] = ["question", "content_type"]
GraphAgent初始化工具与Agent
class GraphAgent(AgentExecutor): @classmethod def initialize(cls,...): cypher_tool = LLMCypherGraphChain( llm=llm, input_key=["question", "content_type"], graph=graph, verbose=verbose, memory=readonlymemory ) # 加载工具配置 tools = [ Tool( name="Cypher search", func=cypher_tool.run, description=""" 用这个工具在数据库内搜索,专门用于回答x类问题。 该工具提供高效搜索能力,帮你轻松找到所需的电影信息。 输入应为完整问题。""", # noqa ) ] agent_chain = initialize_agent( tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=verbose, memory=memory, return_intermediate_steps=True ) def run(self, *args, **kwargs): return super().run(*args, **kwargs)
AgentExecutor调用
self.agent_executor = GraphAgent.initialize( ... ) res = self.agent_executor({"question": "my question", "input": "my question", "random_param": "my other param"})
报错信息
ERROR:root:A single string input was passed in, but this chain expects multiple inputs ({'question', 'content_type'}). When a chain expects multiple inputs, please call it by passing in a dictionary, eg `chain({'foo': 1, 'bar': 2})`
问题根源补充
问题本质是LLMChain生成的输入格式不符合LLMCypherGraphChain的run方法要求。在Agent的plan方法中:
def plan( self, intermediate_steps: List[Tuple[AgentAction, str]], callbacks: Callbacks = None, **kwargs: Any, ) -> Union[AgentAction, AgentFinish]: """Given input, decided what to do. Args: intermediate_steps: Steps the LLM has taken to date, along with observations callbacks: Callbacks to run. **kwargs: User inputs. Returns: Action specifying what tool to use. """ full_inputs = self.get_full_inputs(intermediate_steps, **kwargs) full_output = self.llm_chain.predict(callbacks=callbacks, **full_inputs) return self.output_parser.parse(full_output)
LLM生成的预测结果为:
'Action:\n```\n{\n "action": "Cypher search",\n "action_input": "Who directed the green mile?"\n}\n```\n'
目前不清楚如何修改action_input,使其适配链run方法所需的字典格式,且该字典需包含由run方法传递而非LLM生成的参数。
解决方案
1. 包装工具函数,合并外部参数与LLM输入
不要直接将cypher_tool.run作为Tool的执行函数,编写一个包装函数,把调用Agent时传入的外部参数(如random_param、content_type)与LLM生成的action_input合并为字典,再传递给cypher_tool.run。
修改工具定义部分:
def cypher_tool_wrapper(input_str, **kwargs): # 从kwargs中提取外部传入的参数,可设置默认值 input_dict = { "question": input_str, "content_type": kwargs.get("content_type", "default_content_type"), "random_param": kwargs.get("random_param") } return cypher_tool.run(input_dict) tools = [ Tool( name="Cypher search", func=cypher_tool_wrapper, description=""" 用这个工具在数据库内搜索,专门用于回答x类问题。 该工具提供高效搜索能力,帮你轻松找到所需的电影信息。 输入应为完整问题。""", ) ]
2. 确保Agent传递外部参数到工具
在GraphAgent的run方法中,确保接收到的所有参数都能传递到Agent执行流程。STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION类型的Agent支持传递额外参数,调用AgentExecutor时传入的参数会被Agent的plan方法中的**kwargs捕获,进而传递到工具包装函数。
3. 可选:修改提示词引导LLM生成字典格式输入
如果需要LLM参与生成部分参数,可修改工具的description,明确要求返回字典格式的action_input:
用这个工具在数据库内搜索,专门用于回答x类问题。 输入应为包含question和content_type的字典,格式示例:{"question": "你的问题", "content_type": "movie"} """
若部分参数无需LLM生成,优先使用第一步的包装方法更可靠。
内容的提问来源于stack exchange,提问作者M. Villanueva

