Coverage for src/refinire/agents/gen_agent.py: 100%

57 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-15 18:51 +0900

1from __future__ import annotations 

2 

3"""GenAgent — Modern LLMPipeline-based Step for Flow workflows. 

4 

5GenAgentはLLMPipelineをStepとして使用するためのモダンなクラスです。 

6生成、評価、リトライ機能をFlow/Stepアーキテクチャ内で提供します。 

7""" 

8 

9import warnings 

10from typing import Any, Callable, List, Dict, Optional, Type 

11 

12from .flow.step import Step 

13from .flow.context import Context 

14from .pipeline.llm_pipeline import LLMPipeline, LLMResult 

15 

16 

17# GenAgent implementation using LLMPipeline 

18# LLMPipelineを使用するGenAgent実装 

19 

20class GenAgent(Step): 

21 """ 

22 Modern Step implementation using LLMPipeline instead of deprecated AgentPipeline 

23 非推奨のAgentPipelineに代わってLLMPipelineを使用するモダンなStep実装 

24  

25 This class provides generation, evaluation, and retry capabilities within Flow workflows 

26 without depending on the deprecated AgentPipeline. 

27 このクラスは非推奨のAgentPipelineに依存することなく、Flowワークフロー内で 

28 生成、評価、リトライ機能を提供します。 

29 """ 

30 

31 def __init__( 

32 self, 

33 name: str, 

34 generation_instructions: str, 

35 evaluation_instructions: Optional[str] = None, 

36 *, 

37 output_model: Optional[Type[Any]] = None, 

38 model: str = "gpt-4o-mini", 

39 evaluation_model: Optional[str] = None, 

40 temperature: float = 0.7, 

41 max_tokens: Optional[int] = None, 

42 timeout: float = 30.0, 

43 threshold: float = 85.0, 

44 max_retries: int = 3, 

45 input_guardrails: Optional[List[Callable[[str], bool]]] = None, 

46 output_guardrails: Optional[List[Callable[[Any], bool]]] = None, 

47 session_history: Optional[List[str]] = None, 

48 history_size: int = 10, 

49 improvement_callback: Optional[Callable[[LLMResult, Any], str]] = None, 

50 locale: str = "en", 

51 next_step: Optional[str] = None, 

52 store_result_key: Optional[str] = None, 

53 tools: Optional[List[Dict]] = None, 

54 mcp_servers: Optional[List[str]] = None, 

55 ) -> None: 

56 """ 

57 Initialize GenAgent with LLMPipeline configuration 

58 LLMPipeline設定でGenAgentを初期化する 

59 

60 Args: 

61 name: Step name / ステップ名 

62 generation_instructions: System prompt for generation / 生成用システムプロンプト 

63 evaluation_instructions: System prompt for evaluation / 評価用システムプロンプト 

64 output_model: Pydantic model for structured output / 構造化出力用Pydanticモデル 

65 model: LLM model name / LLMモデル名 

66 evaluation_model: Optional LLM model name for evaluation / 評価用LLMモデル名(任意) 

67 temperature: Sampling temperature / サンプリング温度 

68 max_tokens: Maximum tokens / 最大トークン数 

69 timeout: Request timeout / リクエストタイムアウト 

70 threshold: Evaluation score threshold / 評価スコア閾値 

71 max_retries: Number of retry attempts / リトライ試行回数 

72 input_guardrails: Input validation functions / 入力検証関数 

73 output_guardrails: Output validation functions / 出力検証関数 

74 session_history: Session history / セッション履歴 

75 history_size: Size of history to keep / 保持する履歴サイズ 

76 improvement_callback: Callback for improvement suggestions / 改善提案用コールバック 

77 locale: Language code for localized messages / ローカライズメッセージ用言語コード 

78 next_step: Next step after pipeline execution / パイプライン実行後の次ステップ 

79 store_result_key: Key to store result in context shared_state / コンテキスト共有状態に結果を格納するキー 

80 """ 

81 # Initialize Step base class 

82 # Step基底クラスを初期化 

83 super().__init__(name) 

84 

85 # Store flow-specific configuration 

86 # フロー固有の設定を保存 

87 self.next_step = next_step 

88 self.store_result_key = store_result_key or f"{name}_result" 

89 

90 # Create internal LLMPipeline instance 

91 # 内部LLMPipelineインスタンスを作成 

92 self.llm_pipeline = LLMPipeline( 

93 name=f"{name}_pipeline", 

94 generation_instructions=generation_instructions, 

95 evaluation_instructions=evaluation_instructions, 

96 output_model=output_model, 

97 model=model, 

98 evaluation_model=evaluation_model, 

99 temperature=temperature, 

100 max_tokens=max_tokens, 

101 timeout=timeout, 

102 threshold=threshold, 

103 max_retries=max_retries, 

104 input_guardrails=input_guardrails, 

105 output_guardrails=output_guardrails, 

106 session_history=session_history, 

107 history_size=history_size, 

108 improvement_callback=improvement_callback, 

109 locale=locale, 

110 tools=tools, 

111 mcp_servers=mcp_servers, 

112 ) 

113 

114 async def run(self, user_input: Optional[str], ctx: Context) -> Context: 

115 """ 

116 Execute GenAgent step using LLMPipeline 

117 LLMPipelineを使用してGenAgentステップを実行する 

118 

119 Args: 

120 user_input: User input for the pipeline / パイプライン用ユーザー入力 

121 ctx: Current workflow context / 現在のワークフローコンテキスト 

122 

123 Returns: 

124 Context: Updated context with pipeline results / パイプライン結果付き更新済みコンテキスト 

125 """ 

126 # English: Update step information in context 

127 # 日本語: コンテキストのステップ情報を更新 

128 ctx.update_step_info(self.name) 

129 

130 try: 

131 # English: Determine input text for pipeline 

132 # 日本語: パイプライン用入力テキストを決定 

133 input_text = user_input or ctx.last_user_input or "" 

134 

135 if not input_text: 

136 # English: If no input available, add system message and continue 

137 # 日本語: 入力がない場合、システムメッセージを追加して続行 

138 ctx.add_system_message(f"GenAgent {self.name}: No input available, skipping pipeline execution") 

139 result = None 

140 else: 

141 # English: Execute LLMPipeline synchronously (no async issues) 

142 # 日本語: LLMPipelineを同期的に実行(非同期問題なし) 

143 llm_result = self.llm_pipeline.run(input_text) 

144 result = llm_result.content if llm_result.success else None 

145 

146 # English: Store result in context 

147 # 日本語: 結果をコンテキストに保存 

148 if result is not None: 

149 # English: Store in shared state for other steps to access 

150 # 日本語: 他のステップがアクセスできるよう共有状態に保存 

151 ctx.shared_state[self.store_result_key] = result 

152 ctx.prev_outputs[self.name] = result 

153 

154 # English: Add result as assistant message 

155 # 日本語: 結果をアシスタントメッセージとして追加 

156 ctx.add_assistant_message(str(result)) 

157 

158 # English: Add success system message 

159 # 日本語: 成功システムメッセージを追加 

160 ctx.add_system_message(f"GenAgent {self.name}: Pipeline executed successfully") 

161 else: 

162 # English: Handle case where pipeline returned None (evaluation failed) 

163 # 日本語: パイプラインがNoneを返した場合(評価失敗)を処理 

164 ctx.shared_state[self.store_result_key] = None 

165 ctx.prev_outputs[self.name] = None 

166 

167 # English: Add failure system message 

168 # 日本語: 失敗システムメッセージを追加 

169 ctx.add_system_message(f"GenAgent {self.name}: Pipeline execution failed (evaluation threshold not met)") 

170 

171 except Exception as e: 

172 # English: Handle execution errors 

173 # 日本語: 実行エラーを処理 

174 error_msg = f"GenAgent {self.name} execution error: {str(e)}" 

175 ctx.add_system_message(error_msg) 

176 ctx.shared_state[self.store_result_key] = None 

177 ctx.prev_outputs[self.name] = None 

178 

179 # English: Log error for debugging 

180 # 日本語: デバッグ用エラーログ 

181 print(f"🚨 {error_msg}") 

182 

183 # English: Set next step if specified 

184 # 日本語: 指定されている場合は次ステップを設定 

185 if self.next_step: 

186 ctx.goto(self.next_step) 

187 

188 return ctx 

189 

190 def get_pipeline_history(self) -> List[Dict[str, Any]]: 

191 """ 

192 Get the internal pipeline history 

193 内部パイプライン履歴を取得する 

194 

195 Returns: 

196 List[Dict[str, Any]]: Pipeline history / パイプライン履歴 

197 """ 

198 return self.llm_pipeline.get_history() 

199 

200 def get_session_history(self) -> Optional[List[str]]: 

201 """ 

202 Get the session history 

203 セッション履歴を取得する 

204 

205 Returns: 

206 Optional[List[str]]: Session history / セッション履歴 

207 """ 

208 return self.llm_pipeline.session_history 

209 

210 def update_instructions( 

211 self, 

212 generation_instructions: Optional[str] = None, 

213 evaluation_instructions: Optional[str] = None 

214 ) -> None: 

215 """ 

216 Update pipeline instructions 

217 パイプライン指示を更新する 

218 

219 Args: 

220 generation_instructions: New generation instructions / 新しい生成指示 

221 evaluation_instructions: New evaluation instructions / 新しい評価指示 

222 """ 

223 self.llm_pipeline.update_instructions(generation_instructions, evaluation_instructions) 

224 

225 def clear_history(self) -> None: 

226 """ 

227 Clear pipeline history 

228 パイプライン履歴をクリア 

229 """ 

230 self.llm_pipeline.clear_history() 

231 

232 def set_threshold(self, threshold: float) -> None: 

233 """ 

234 Update evaluation threshold 

235 評価閾値を更新する 

236 

237 Args: 

238 threshold: New threshold value (0-100) / 新しい閾値(0-100) 

239 """ 

240 self.llm_pipeline.set_threshold(threshold) 

241 

242 def __str__(self) -> str: 

243 return f"GenAgent({self.name}, model={self.llm_pipeline.model})" 

244 

245 def __repr__(self) -> str: 

246 return self.__str__() 

247 

248 

249# Modern utility functions for creating GenAgent with common configurations 

250# モダンなGenAgent作成用ユーティリティ関数 

251 

252def create_simple_gen_agent( 

253 name: str, 

254 instructions: str, 

255 model: str = "gpt-4o-mini", 

256 next_step: Optional[str] = None, 

257 threshold: float = 85.0, 

258 retries: int = 3, 

259 tools: Optional[List[Dict]] = None, 

260 mcp_servers: Optional[List[str]] = None 

261) -> GenAgent: 

262 """ 

263 Create a simple GenAgent with basic configuration 

264 基本設定でシンプルなGenAgentを作成 

265 

266 Args: 

267 name: Agent name / エージェント名 

268 instructions: Generation instructions / 生成指示 

269 model: LLM model name / LLMモデル名 

270 next_step: Next step name / 次ステップ名 

271 threshold: Evaluation threshold / 評価閾値 

272 retries: Retry attempts / リトライ回数 

273 tools: OpenAI function tools / OpenAI関数ツール 

274 mcp_servers: MCP server identifiers / MCPサーバー識別子 

275 

276 Returns: 

277 GenAgent: Configured agent / 設定済みエージェント 

278 """ 

279 return GenAgent( 

280 name=name, 

281 generation_instructions=instructions, 

282 model=model, 

283 next_step=next_step, 

284 threshold=threshold, 

285 max_retries=retries, 

286 tools=tools, 

287 mcp_servers=mcp_servers 

288 ) 

289 

290 

291def create_evaluated_gen_agent( 

292 name: str, 

293 generation_instructions: str, 

294 evaluation_instructions: str, 

295 model: str = "gpt-4o-mini", 

296 evaluation_model: Optional[str] = None, 

297 next_step: Optional[str] = None, 

298 threshold: float = 85.0, 

299 retries: int = 3, 

300 tools: Optional[List[Dict]] = None, 

301 mcp_servers: Optional[List[str]] = None 

302) -> GenAgent: 

303 """ 

304 Create a GenAgent with evaluation capabilities 

305 評価機能付きGenAgentを作成 

306 

307 Args: 

308 name: Agent name / エージェント名 

309 generation_instructions: Generation instructions / 生成指示 

310 evaluation_instructions: Evaluation instructions / 評価指示 

311 model: LLM model name / LLMモデル名 

312 evaluation_model: Evaluation model name / 評価モデル名 

313 next_step: Next step name / 次ステップ名 

314 threshold: Evaluation threshold / 評価閾値 

315 retries: Retry attempts / リトライ回数 

316 

317 Returns: 

318 GenAgent: Configured agent with evaluation / 評価機能付き設定済みエージェント 

319 """ 

320 return GenAgent( 

321 name=name, 

322 generation_instructions=generation_instructions, 

323 evaluation_instructions=evaluation_instructions, 

324 model=model, 

325 evaluation_model=evaluation_model, 

326 next_step=next_step, 

327 threshold=threshold, 

328 max_retries=retries, 

329 tools=tools, 

330 mcp_servers=mcp_servers 

331 ) 

332 

333