1
0

code_plan_agent.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. """Code Plan Agent - 智能代码计划工具,具备Reflection反思功能"""
  2. import json
  3. from typing import Optional, List, Dict, Any, AsyncGenerator
  4. from datetime import datetime
  5. from hello_agents.core.agent import Agent
  6. from hello_agents.core.llm import HelloAgentsLLM
  7. from hello_agents.core.config import Config
  8. from hello_agents.core.message import Message
  9. from hello_agents.core.streaming import StreamEvent, StreamEventType
  10. from hello_agents.core.lifecycle import LifecycleHook
  11. from hello_agents.tools.registry import ToolRegistry
  12. class PlanMemory:
  13. """
  14. 计划记忆模块,用于存储代码计划的生成轨迹和反思记录
  15. """
  16. def __init__(self):
  17. self.records: List[Dict[str, Any]] = []
  18. def add_record(self, record_type: str, content: str, metadata: Optional[Dict] = None):
  19. """向记忆中添加一条新记录"""
  20. self.records.append({
  21. "type": record_type,
  22. "content": content,
  23. "metadata": metadata or {},
  24. "timestamp": datetime.now().isoformat()
  25. })
  26. def get_trajectory(self) -> str:
  27. """将所有记忆记录格式化为一个连贯的字符串文本"""
  28. trajectory = ""
  29. for record in self.records:
  30. if record['type'] == 'plan':
  31. trajectory += f"--- 代码计划 ---\n{record['content']}\n\n"
  32. elif record['type'] == 'reflection':
  33. trajectory += f"--- 反思反馈 ---\n{record['content']}\n\n"
  34. elif record['type'] == 'revision':
  35. trajectory += f"--- 优化后计划 ---\n{record['content']}\n\n"
  36. return trajectory.strip()
  37. def get_last_plan(self) -> str:
  38. """获取最近一次的代码计划"""
  39. for record in reversed(self.records):
  40. if record['type'] in ['plan', 'revision']:
  41. return record['content']
  42. return ""
  43. def get_last_reflection(self) -> str:
  44. """获取最近一次的反思反馈"""
  45. for record in reversed(self.records):
  46. if record['type'] == 'reflection':
  47. return record['content']
  48. return ""
  49. class CodePlanAgent(Agent):
  50. """
  51. Code Plan Agent - 智能代码计划工具,具备Reflection反思功能
  52. 核心能力:
  53. 1. 代码计划生成:根据需求描述生成结构化的代码实现计划
  54. 2. 自我反思:对生成的代码计划进行质量评估和改进建议
  55. 3. 迭代优化:根据反思结果优化代码计划
  56. 4. 支持工具调用(可选)
  57. 输出格式:
  58. - 代码计划采用结构化格式,包含多个步骤
  59. - 每个步骤包含:步骤编号、任务描述、实现要点、预期输出
  60. 反思维度:
  61. - 完整性:计划是否覆盖所有需求
  62. - 可行性:技术方案是否可行
  63. - 效率:是否存在性能优化空间
  64. - 可维护性:代码结构是否清晰
  65. - 安全性:是否存在安全风险
  66. """
  67. def __init__(
  68. self,
  69. name: str,
  70. llm: HelloAgentsLLM,
  71. system_prompt: Optional[str] = None,
  72. config: Optional[Config] = None,
  73. max_reflection_iterations: int = 2,
  74. tool_registry: Optional['ToolRegistry'] = None,
  75. enable_tool_calling: bool = True,
  76. max_tool_iterations: int = 3
  77. ):
  78. """
  79. 初始化CodePlanAgent
  80. Args:
  81. name: Agent名称
  82. llm: LLM实例
  83. system_prompt: 系统提示词(定义角色和行为)
  84. config: 配置对象
  85. max_reflection_iterations: 最大反思迭代次数
  86. tool_registry: 工具注册表(可选)
  87. enable_tool_calling: 是否启用工具调用
  88. max_tool_iterations: 最大工具调用迭代次数
  89. """
  90. # 默认 system_prompt - 代码规划专家
  91. default_system_prompt = """你是一位资深的软件架构师和代码规划专家。
  92. 你擅长将业务需求转化为清晰、可行的代码实现计划。
  93. ## 核心职责
  94. 1. 分析需求并生成结构化的代码实现计划
  95. 2. 确保计划覆盖所有核心功能和边界情况
  96. 3. 设计合理的模块划分和接口定义
  97. 4. 考虑代码的可维护性、扩展性和性能
  98. ## 输出格式要求
  99. 请按照以下结构化格式输出代码计划:
  100. ```code_plan
  101. ## 项目概述
  102. [简要描述项目目标和核心功能]
  103. ## 技术栈
  104. - 语言:[编程语言]
  105. - 框架:[主要框架]
  106. - 数据库:[数据库类型]
  107. - 其他:[关键依赖]
  108. ## 目录结构
  109. ```
  110. [项目目录结构]
  111. ```
  112. ## 实现步骤
  113. 1. [步骤1描述]
  114. - 实现要点:[关键实现细节]
  115. - 文件路径:[涉及文件]
  116. - 预期输出:[预期结果]
  117. 2. [步骤2描述]
  118. - 实现要点:[关键实现细节]
  119. - 文件路径:[涉及文件]
  120. - 预期输出:[预期结果]
  121. ...
  122. ## 关键设计
  123. - [设计决策1]:[说明原因]
  124. - [设计决策2]:[说明原因]
  125. ## 注意事项
  126. - [注意事项1]
  127. - [注意事项2]
  128. ```
  129. 请确保计划详细、清晰、可执行。"""
  130. super().__init__(
  131. name,
  132. llm,
  133. system_prompt or default_system_prompt,
  134. config,
  135. tool_registry=tool_registry
  136. )
  137. self.max_reflection_iterations = max_reflection_iterations
  138. self.memory = PlanMemory()
  139. self.enable_tool_calling = enable_tool_calling
  140. self.max_tool_iterations = max_tool_iterations
  141. def run(self, input_text: str, **kwargs) -> str:
  142. """
  143. 运行CodePlanAgent
  144. Args:
  145. input_text: 需求描述
  146. **kwargs: 其他参数(temperature, max_tokens等)
  147. Returns:
  148. 最终优化后的代码计划
  149. """
  150. print(f"\n🤖 {self.name} 开始处理代码规划任务: {input_text[:50]}...")
  151. # 重置记忆
  152. self.memory = PlanMemory()
  153. # 1. 生成初始代码计划
  154. print("\n--- 阶段1: 生成初始代码计划 ---")
  155. initial_plan = self._generate_code_plan(input_text, **kwargs)
  156. self.memory.add_record("plan", initial_plan, {"phase": "initial"})
  157. print(f"\n✅ 初始计划已生成:\n{initial_plan}")
  158. # 2. 迭代反思与优化
  159. for i in range(self.max_reflection_iterations):
  160. print(f"\n--- 阶段2: 第 {i+1}/{self.max_reflection_iterations} 轮反思优化 ---")
  161. # a. 反思当前计划
  162. print("\n-> 正在进行计划反思...")
  163. last_plan = self.memory.get_last_plan()
  164. reflection = self._reflect_on_plan(input_text, last_plan, **kwargs)
  165. self.memory.add_record("reflection", reflection, {"iteration": i + 1})
  166. print(f"\n💡 反思结果:\n{reflection}")
  167. # b. 检查是否需要停止
  168. if "无需改进" in reflection or "no need for improvement" in reflection.lower():
  169. print("\n✅ 反思认为计划已无需改进,任务完成。")
  170. break
  171. # c. 优化计划
  172. print("\n-> 正在优化代码计划...")
  173. refined_plan = self._refine_plan(input_text, last_plan, reflection, **kwargs)
  174. self.memory.add_record("revision", refined_plan, {"iteration": i + 1})
  175. print(f"\n🔄 优化后的计划:\n{refined_plan}")
  176. final_plan = self.memory.get_last_plan()
  177. print(f"\n--- 🎉 任务完成 ---\n最终代码计划:\n{final_plan}")
  178. # 保存到历史记录
  179. self.add_message(Message(input_text, "user"))
  180. self.add_message(Message(final_plan, "assistant"))
  181. return final_plan
  182. def _generate_code_plan(self, requirements: str, **kwargs) -> str:
  183. """
  184. 生成初始代码计划
  185. Args:
  186. requirements: 需求描述
  187. **kwargs: LLM调用参数
  188. Returns:
  189. 代码计划文本
  190. """
  191. messages = [
  192. {"role": "system", "content": self.system_prompt},
  193. {"role": "user", "content": f"""请根据以下需求描述,生成一份详细的代码实现计划:
  194. ## 需求描述
  195. {requirements}
  196. 请按照指定的格式输出代码计划。"""}
  197. ]
  198. return self._get_llm_response(messages, **kwargs)
  199. def _reflect_on_plan(self, requirements: str, plan: str, **kwargs) -> str:
  200. """
  201. 对代码计划进行反思评估
  202. Args:
  203. requirements: 原始需求
  204. plan: 当前代码计划
  205. **kwargs: LLM调用参数
  206. Returns:
  207. 反思反馈文本
  208. """
  209. reflection_prompt = f"""你是一位资深的技术评审专家。请对以下代码计划进行全面评估:
  210. ## 原始需求
  211. {requirements}
  212. ## 当前代码计划
  213. {plan}
  214. ## 评审维度
  215. 请从以下维度进行评估:
  216. 1. **完整性**:计划是否覆盖了所有核心需求?是否有遗漏的功能?
  217. 2. **可行性**:技术方案是否可行?是否存在技术风险?
  218. 3. **架构合理性**:模块划分是否合理?接口设计是否清晰?
  219. 4. **可维护性**:代码结构是否清晰?是否遵循最佳实践?
  220. 5. **性能考虑**:是否考虑了性能优化?是否存在潜在的性能瓶颈?
  221. 6. **安全性**:是否存在安全风险?是否需要添加安全措施?
  222. 7. **测试覆盖**:是否考虑了测试策略?关键路径是否有测试覆盖?
  223. ## 输出要求
  224. 请给出具体的改进建议。如果计划已经很好,请回答"无需改进"。"""
  225. messages = [
  226. {"role": "system", "content": "你是一位严格的技术评审专家,擅长发现代码计划中的潜在问题并提出改进建议。"},
  227. {"role": "user", "content": reflection_prompt}
  228. ]
  229. return self._get_llm_response(messages, **kwargs)
  230. def _refine_plan(self, requirements: str, current_plan: str, feedback: str, **kwargs) -> str:
  231. """
  232. 根据反馈优化代码计划
  233. Args:
  234. requirements: 原始需求
  235. current_plan: 当前代码计划
  236. feedback: 反思反馈
  237. **kwargs: LLM调用参数
  238. Returns:
  239. 优化后的代码计划
  240. """
  241. refinement_prompt = f"""请根据评审反馈优化以下代码计划:
  242. ## 原始需求
  243. {requirements}
  244. ## 当前代码计划
  245. {current_plan}
  246. ## 评审反馈
  247. {feedback}
  248. ## 优化要求
  249. 请根据反馈意见对代码计划进行修改和完善,确保:
  250. 1. 解决反馈中指出的所有问题
  251. 2. 保持计划的结构化格式
  252. 3. 提供具体的改进方案
  253. 请输出优化后的完整代码计划。"""
  254. messages = [
  255. {"role": "system", "content": self.system_prompt},
  256. {"role": "user", "content": refinement_prompt}
  257. ]
  258. return self._get_llm_response(messages, **kwargs)
  259. def _get_llm_response(self, messages: List[Dict[str, str]], **kwargs) -> str:
  260. """
  261. 调用LLM并获取完整响应(支持 Function Calling)
  262. Args:
  263. messages: 消息列表
  264. **kwargs: 其他参数
  265. Returns:
  266. LLM响应文本
  267. """
  268. # 如果没有启用工具调用,直接返回
  269. if not self.enable_tool_calling or not self.tool_registry:
  270. llm_response = self.llm.invoke(messages, **kwargs)
  271. return llm_response.content if hasattr(llm_response, 'content') else str(llm_response)
  272. # 启用工具调用模式
  273. tool_schemas = self._build_tool_schemas()
  274. current_iteration = 0
  275. while current_iteration < self.max_tool_iterations:
  276. current_iteration += 1
  277. try:
  278. response = self.llm.invoke_with_tools(
  279. messages=messages,
  280. tools=tool_schemas,
  281. tool_choice="auto",
  282. **kwargs
  283. )
  284. except Exception as e:
  285. print(f"❌ LLM 调用失败: {e}")
  286. break
  287. response_message = response.choices[0].message
  288. # 处理工具调用
  289. tool_calls = response_message.tool_calls
  290. if not tool_calls:
  291. # 没有工具调用,返回文本响应
  292. return response_message.content or ""
  293. # 将助手消息添加到历史
  294. messages.append({
  295. "role": "assistant",
  296. "content": response_message.content,
  297. "tool_calls": [
  298. {
  299. "id": tc.id,
  300. "type": "function",
  301. "function": {
  302. "name": tc.function.name,
  303. "arguments": tc.function.arguments
  304. }
  305. }
  306. for tc in tool_calls
  307. ]
  308. })
  309. # 执行所有工具调用
  310. for tool_call in tool_calls:
  311. tool_name = tool_call.function.name
  312. tool_call_id = tool_call.id
  313. try:
  314. arguments = json.loads(tool_call.function.arguments)
  315. except json.JSONDecodeError as e:
  316. print(f"❌ 工具参数解析失败: {e}")
  317. messages.append({
  318. "role": "tool",
  319. "tool_call_id": tool_call_id,
  320. "content": f"错误:参数格式不正确 - {str(e)}"
  321. })
  322. continue
  323. # 执行工具(复用基类方法)
  324. result = self._execute_tool_call(tool_name, arguments)
  325. # 添加工具结果到消息
  326. messages.append({
  327. "role": "tool",
  328. "tool_call_id": tool_call_id,
  329. "content": result
  330. })
  331. # 如果超过最大迭代次数,获取最后一次回答
  332. if current_iteration >= self.max_tool_iterations:
  333. llm_response = self.llm.invoke(messages, **kwargs)
  334. return llm_response.content if hasattr(llm_response, 'content') else str(llm_response)
  335. return ""
  336. async def arun_stream(
  337. self,
  338. input_text: str,
  339. on_start: LifecycleHook = None,
  340. on_finish: LifecycleHook = None,
  341. on_error: LifecycleHook = None,
  342. **kwargs
  343. ) -> AsyncGenerator[StreamEvent, None]:
  344. """
  345. CodePlanAgent 流式执行
  346. 实时返回:
  347. - 计划生成阶段的输出
  348. - 反思阶段的思考过程
  349. - 优化阶段的输出
  350. Args:
  351. input_text: 用户输入
  352. on_start: 开始钩子
  353. on_finish: 完成钩子
  354. on_error: 错误钩子
  355. **kwargs: 其他参数
  356. Yields:
  357. StreamEvent: 流式事件
  358. """
  359. # 发送开始事件
  360. yield StreamEvent.create(
  361. StreamEventType.AGENT_START,
  362. self.name,
  363. input_text=input_text
  364. )
  365. try:
  366. # 阶段 1:生成代码计划
  367. yield StreamEvent.create(
  368. StreamEventType.STEP_START,
  369. self.name,
  370. phase="plan_generation",
  371. description="生成初始代码计划"
  372. )
  373. messages = []
  374. if self.system_prompt:
  375. messages.append({"role": "system", "content": self.system_prompt})
  376. plan_prompt = f"""请根据以下需求描述,生成一份详细的代码实现计划:
  377. ## 需求描述
  378. {input_text}
  379. 请按照指定的格式输出代码计划。"""
  380. messages.append({"role": "user", "content": plan_prompt})
  381. initial_plan = ""
  382. async for chunk in self.llm.astream_invoke(messages, **kwargs):
  383. initial_plan += chunk
  384. yield StreamEvent.create(
  385. StreamEventType.LLM_CHUNK,
  386. self.name,
  387. chunk=chunk,
  388. phase="plan_generation"
  389. )
  390. yield StreamEvent.create(
  391. StreamEventType.STEP_FINISH,
  392. self.name,
  393. phase="plan_generation",
  394. result=initial_plan
  395. )
  396. # 阶段 2:反思与优化循环
  397. current_plan = initial_plan
  398. for iteration in range(self.max_reflection_iterations):
  399. # 反思阶段
  400. yield StreamEvent.create(
  401. StreamEventType.STEP_START,
  402. self.name,
  403. phase="reflection",
  404. iteration=iteration + 1,
  405. description=f"第 {iteration + 1} 次反思"
  406. )
  407. reflection_prompt = f"""你是一位资深的技术评审专家。请对以下代码计划进行全面评估:
  408. ## 原始需求
  409. {input_text}
  410. ## 当前代码计划
  411. {current_plan}
  412. ## 评审维度
  413. 请从以下维度进行评估:
  414. 1. 完整性:计划是否覆盖了所有核心需求?
  415. 2. 可行性:技术方案是否可行?
  416. 3. 架构合理性:模块划分是否合理?
  417. 4. 可维护性:代码结构是否清晰?
  418. 5. 性能考虑:是否考虑了性能优化?
  419. 6. 安全性:是否存在安全风险?
  420. 7. 测试覆盖:是否考虑了测试策略?
  421. 请给出具体的改进建议。如果计划已经很好,请回答"无需改进"。"""
  422. reflection_messages = [{"role": "user", "content": reflection_prompt}]
  423. reflection = ""
  424. async for chunk in self.llm.astream_invoke(reflection_messages, **kwargs):
  425. reflection += chunk
  426. yield StreamEvent.create(
  427. StreamEventType.THINKING,
  428. self.name,
  429. chunk=chunk,
  430. phase="reflection",
  431. iteration=iteration + 1
  432. )
  433. yield StreamEvent.create(
  434. StreamEventType.STEP_FINISH,
  435. self.name,
  436. phase="reflection",
  437. iteration=iteration + 1,
  438. reflection=reflection
  439. )
  440. # 检查是否需要停止
  441. if "无需改进" in reflection or "no need for improvement" in reflection.lower():
  442. break
  443. # 优化阶段
  444. yield StreamEvent.create(
  445. StreamEventType.STEP_START,
  446. self.name,
  447. phase="refinement",
  448. iteration=iteration + 1,
  449. description=f"第 {iteration + 1} 次优化"
  450. )
  451. refinement_prompt = f"""请根据评审反馈优化以下代码计划:
  452. ## 原始需求
  453. {input_text}
  454. ## 当前代码计划
  455. {current_plan}
  456. ## 评审反馈
  457. {reflection}
  458. 请输出优化后的完整代码计划。"""
  459. refinement_messages = [{"role": "user", "content": refinement_prompt}]
  460. refined_plan = ""
  461. async for chunk in self.llm.astream_invoke(refinement_messages, **kwargs):
  462. refined_plan += chunk
  463. yield StreamEvent.create(
  464. StreamEventType.LLM_CHUNK,
  465. self.name,
  466. chunk=chunk,
  467. phase="refinement",
  468. iteration=iteration + 1
  469. )
  470. yield StreamEvent.create(
  471. StreamEventType.STEP_FINISH,
  472. self.name,
  473. phase="refinement",
  474. iteration=iteration + 1,
  475. result=refined_plan
  476. )
  477. current_plan = refined_plan
  478. # 发送完成事件
  479. yield StreamEvent.create(
  480. StreamEventType.AGENT_FINISH,
  481. self.name,
  482. result=current_plan,
  483. total_iterations=self.max_reflection_iterations
  484. )
  485. # 保存到历史
  486. self.add_message(Message(input_text, "user"))
  487. self.add_message(Message(current_plan, "assistant"))
  488. except Exception as e:
  489. # 发送错误事件
  490. yield StreamEvent.create(
  491. StreamEventType.ERROR,
  492. self.name,
  493. error=str(e),
  494. error_type=type(e).__name__
  495. )
  496. raise
  497. def get_plan_trajectory(self) -> str:
  498. """获取完整的计划生成轨迹"""
  499. return self.memory.get_trajectory()
  500. def create_code_plan_agent(llm: HelloAgentsLLM) -> CodePlanAgent:
  501. """
  502. 创建CodePlanAgent实例的便捷工厂函数
  503. Args:
  504. llm: LLM实例
  505. Returns:
  506. CodePlanAgent实例
  507. """
  508. return CodePlanAgent(
  509. name="CodePlanAgent",
  510. llm=llm,
  511. max_reflection_iterations=2
  512. )