1
0

my_simple_agent.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. # my_simple_agent.py
  2. from typing import Optional, Iterator
  3. from hello_agents import SimpleAgent, HelloAgentsLLM, Config, Message
  4. import re
  5. class MySimpleAgent(SimpleAgent):
  6. """
  7. 重写的简单对话Agent
  8. 展示如何基于框架基类构建自定义Agent
  9. """
  10. def __init__(
  11. self,
  12. name: str,
  13. llm: HelloAgentsLLM,
  14. system_prompt: Optional[str] = None,
  15. config: Optional[Config] = None,
  16. tool_registry: Optional['ToolRegistry'] = None,
  17. enable_tool_calling: bool = True
  18. ):
  19. super().__init__(name, llm, system_prompt, config)
  20. self.tool_registry = tool_registry
  21. self.enable_tool_calling = enable_tool_calling and tool_registry is not None
  22. print(f"✅ {name} 初始化完成,工具调用: {'启用' if self.enable_tool_calling else '禁用'}")
  23. def run(self, input_text: str, max_tool_iterations: int = 3, **kwargs) -> str:
  24. """
  25. 重写的运行方法 - 实现简单对话逻辑,支持可选工具调用
  26. """
  27. print(f"🤖 {self.name} 正在处理: {input_text}")
  28. # 构建消息列表
  29. messages = []
  30. # 添加系统消息(可能包含工具信息)
  31. enhanced_system_prompt = self._get_enhanced_system_prompt()
  32. messages.append({"role": "system", "content": enhanced_system_prompt})
  33. # 添加历史消息
  34. for msg in self._history:
  35. messages.append({"role": msg.role, "content": msg.content})
  36. # 添加当前用户消息
  37. messages.append({"role": "user", "content": input_text})
  38. # 如果没有启用工具调用,使用简单对话逻辑
  39. if not self.enable_tool_calling:
  40. response = self.llm.invoke(messages, **kwargs)
  41. self.add_message(Message(input_text, "user"))
  42. self.add_message(Message(response, "assistant"))
  43. print(f"✅ {self.name} 响应完成")
  44. return response
  45. # 支持多轮工具调用的逻辑
  46. return self._run_with_tools(messages, input_text, max_tool_iterations, **kwargs)
  47. def _get_enhanced_system_prompt(self) -> str:
  48. """构建增强的系统提示词,包含工具信息"""
  49. base_prompt = self.system_prompt or "你是一个有用的AI助手。"
  50. if not self.enable_tool_calling or not self.tool_registry:
  51. return base_prompt
  52. # 获取工具描述
  53. tools_description = self.tool_registry.get_tools_description()
  54. if not tools_description or tools_description == "暂无可用工具":
  55. return base_prompt
  56. tools_section = "\n\n## 可用工具\n"
  57. tools_section += "你可以使用以下工具来帮助回答问题:\n"
  58. tools_section += tools_description + "\n"
  59. tools_section += "\n## 工具调用格式\n"
  60. tools_section += "当需要使用工具时,请使用以下格式:\n"
  61. tools_section += "`[TOOL_CALL:{tool_name}:{parameters}]`\n"
  62. tools_section += "例如:`[TOOL_CALL:search:Python编程]` 或 `[TOOL_CALL:memory:recall=用户信息]`\n\n"
  63. tools_section += "工具调用结果会自动插入到对话中,然后你可以基于结果继续回答。\n"
  64. return base_prompt + tools_section
  65. def _run_with_tools(self, messages: list, input_text: str, max_tool_iterations: int, **kwargs) -> str:
  66. """支持工具调用的运行逻辑"""
  67. current_iteration = 0
  68. final_response = ""
  69. while current_iteration < max_tool_iterations:
  70. # 调用LLM
  71. response = self.llm.invoke(messages, **kwargs)
  72. # 检查是否有工具调用
  73. tool_calls = self._parse_tool_calls(response)
  74. if tool_calls:
  75. print(f"🔧 检测到 {len(tool_calls)} 个工具调用")
  76. # 执行所有工具调用并收集结果
  77. tool_results = []
  78. clean_response = response
  79. for call in tool_calls:
  80. result = self._execute_tool_call(call['tool_name'], call['parameters'])
  81. tool_results.append(result)
  82. # 从响应中移除工具调用标记
  83. clean_response = clean_response.replace(call['original'], "")
  84. # 构建包含工具结果的消息
  85. messages.append({"role": "assistant", "content": clean_response})
  86. # 添加工具结果
  87. tool_results_text = "\n\n".join(tool_results)
  88. messages.append({"role": "user", "content": f"工具执行结果:\n{tool_results_text}\n\n请基于这些结果给出完整的回答。"})
  89. current_iteration += 1
  90. continue
  91. # 没有工具调用,这是最终回答
  92. final_response = response
  93. break
  94. # 如果超过最大迭代次数,获取最后一次回答
  95. if current_iteration >= max_tool_iterations and not final_response:
  96. final_response = self.llm.invoke(messages, **kwargs)
  97. # 保存到历史记录
  98. self.add_message(Message(input_text, "user"))
  99. self.add_message(Message(final_response, "assistant"))
  100. print(f"✅ {self.name} 响应完成")
  101. return final_response
  102. def _parse_tool_calls(self, text: str) -> list:
  103. """解析文本中的工具调用"""
  104. pattern = r'\[TOOL_CALL:([^:]+):([^\]]+)\]'
  105. matches = re.findall(pattern, text)
  106. tool_calls = []
  107. for tool_name, parameters in matches:
  108. tool_calls.append({
  109. 'tool_name': tool_name.strip(),
  110. 'parameters': parameters.strip(),
  111. 'original': f'[TOOL_CALL:{tool_name}:{parameters}]'
  112. })
  113. return tool_calls
  114. def _execute_tool_call(self, tool_name: str, parameters: str) -> str:
  115. """执行工具调用"""
  116. if not self.tool_registry:
  117. return f"❌ 错误:未配置工具注册表"
  118. try:
  119. # 智能参数解析
  120. if tool_name == 'calculator':
  121. # 计算器工具直接传入表达式
  122. result = self.tool_registry.execute_tool(tool_name, parameters)
  123. else:
  124. # 其他工具使用智能参数解析
  125. param_dict = self._parse_tool_parameters(tool_name, parameters)
  126. tool = self.tool_registry.get_tool(tool_name)
  127. if not tool:
  128. return f"❌ 错误:未找到工具 '{tool_name}'"
  129. result = tool.run(param_dict)
  130. return f"🔧 工具 {tool_name} 执行结果:\n{result}"
  131. except Exception as e:
  132. return f"❌ 工具调用失败:{str(e)}"
  133. def _parse_tool_parameters(self, tool_name: str, parameters: str) -> dict:
  134. """智能解析工具参数"""
  135. param_dict = {}
  136. if '=' in parameters:
  137. # 格式: key=value 或 action=search,query=Python
  138. if ',' in parameters:
  139. # 多个参数:action=search,query=Python,limit=3
  140. pairs = parameters.split(',')
  141. for pair in pairs:
  142. if '=' in pair:
  143. key, value = pair.split('=', 1)
  144. param_dict[key.strip()] = value.strip()
  145. else:
  146. # 单个参数:key=value
  147. key, value = parameters.split('=', 1)
  148. param_dict[key.strip()] = value.strip()
  149. else:
  150. # 直接传入参数,根据工具类型智能推断
  151. if tool_name == 'search':
  152. param_dict = {'query': parameters}
  153. elif tool_name == 'memory':
  154. param_dict = {'action': 'search', 'query': parameters}
  155. else:
  156. param_dict = {'input': parameters}
  157. return param_dict
  158. def stream_run(self, input_text: str, **kwargs) -> Iterator[str]:
  159. """
  160. 自定义的流式运行方法
  161. """
  162. print(f"🌊 {self.name} 开始流式处理: {input_text}")
  163. messages = []
  164. if self.system_prompt:
  165. messages.append({"role": "system", "content": self.system_prompt})
  166. for msg in self._history:
  167. messages.append({"role": msg.role, "content": msg.content})
  168. messages.append({"role": "user", "content": input_text})
  169. # 流式调用LLM
  170. full_response = ""
  171. print("📝 实时响应: ", end="")
  172. for chunk in self.llm.stream_invoke(messages, **kwargs):
  173. full_response += chunk
  174. print(chunk, end="", flush=True)
  175. yield chunk
  176. print() # 换行
  177. # 保存完整对话到历史记录
  178. self.add_message(Message(input_text, "user"))
  179. self.add_message(Message(full_response, "assistant"))
  180. print(f"✅ {self.name} 流式响应完成")
  181. def add_tool(self, tool) -> None:
  182. """添加工具到Agent(便利方法)"""
  183. if not self.tool_registry:
  184. from hello_agents import ToolRegistry
  185. self.tool_registry = ToolRegistry()
  186. self.enable_tool_calling = True
  187. self.tool_registry.register_tool(tool)
  188. print(f"🔧 工具 '{tool.name}' 已添加")
  189. def has_tools(self) -> bool:
  190. """检查是否有可用工具"""
  191. return self.enable_tool_calling and self.tool_registry is not None
  192. def remove_tool(self, tool_name: str) -> bool:
  193. """移除工具(便利方法)"""
  194. if self.tool_registry:
  195. self.tool_registry.unregister(tool_name)
  196. return True
  197. return False
  198. def list_tools(self) -> list:
  199. """列出所有可用工具"""
  200. if self.tool_registry:
  201. return self.tool_registry.list_tools()
  202. return []