models.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. """
  2. Trace 和 Step 数据模型
  3. Trace: 一次完整的 LLM 交互(单次调用或 Agent 任务)
  4. Step: Trace 中的一个原子操作,形成树结构
  5. """
  6. from dataclasses import dataclass, field
  7. from datetime import datetime
  8. from typing import Dict, Any, List, Optional, Literal
  9. import uuid
  10. # Step 类型
  11. StepType = Literal[
  12. # 计划相关
  13. "goal", # 目标/计划项(可以有子 steps)
  14. # LLM 输出
  15. "thought", # 思考/分析(中间过程)
  16. "evaluation", # 评估总结(需要 summary)
  17. "response", # 最终回复
  18. # 工具相关
  19. "action", # 工具调用(tool_call)
  20. "result", # 工具结果(tool_result)
  21. # 系统相关
  22. "memory_read", # 读取记忆(经验/技能)
  23. "memory_write", # 写入记忆
  24. "feedback", # 人工反馈
  25. ]
  26. # Step 状态
  27. Status = Literal[
  28. "planned", # 计划中(未执行)
  29. "in_progress", # 执行中
  30. "awaiting_approval", # 等待用户确认
  31. "completed", # 已完成
  32. "failed", # 失败
  33. "skipped", # 跳过
  34. ]
  35. @dataclass
  36. class Trace:
  37. """
  38. 执行轨迹 - 一次完整的 LLM 交互
  39. 单次调用: mode="call", 只有 1 个 Step
  40. Agent 模式: mode="agent", 多个 Steps 形成树结构
  41. """
  42. trace_id: str
  43. mode: Literal["call", "agent"]
  44. # Prompt 标识(可选)
  45. prompt_name: Optional[str] = None
  46. # Agent 模式特有
  47. task: Optional[str] = None
  48. agent_type: Optional[str] = None
  49. # 状态
  50. status: Literal["running", "completed", "failed"] = "running"
  51. # 统计
  52. total_steps: int = 0
  53. total_tokens: int = 0
  54. total_cost: float = 0.0
  55. # 上下文
  56. uid: Optional[str] = None
  57. context: Dict[str, Any] = field(default_factory=dict)
  58. # 当前焦点 goal(用于 step 工具)
  59. current_goal_id: Optional[str] = None
  60. # 时间
  61. created_at: datetime = field(default_factory=datetime.now)
  62. completed_at: Optional[datetime] = None
  63. @classmethod
  64. def create(
  65. cls,
  66. mode: Literal["call", "agent"],
  67. **kwargs
  68. ) -> "Trace":
  69. """创建新的 Trace"""
  70. return cls(
  71. trace_id=str(uuid.uuid4()),
  72. mode=mode,
  73. **kwargs
  74. )
  75. def to_dict(self) -> Dict[str, Any]:
  76. """转换为字典"""
  77. return {
  78. "trace_id": self.trace_id,
  79. "mode": self.mode,
  80. "prompt_name": self.prompt_name,
  81. "task": self.task,
  82. "agent_type": self.agent_type,
  83. "status": self.status,
  84. "total_steps": self.total_steps,
  85. "total_tokens": self.total_tokens,
  86. "total_cost": self.total_cost,
  87. "uid": self.uid,
  88. "context": self.context,
  89. "current_goal_id": self.current_goal_id,
  90. "created_at": self.created_at.isoformat() if self.created_at else None,
  91. "completed_at": self.completed_at.isoformat() if self.completed_at else None,
  92. }
  93. @dataclass
  94. class Step:
  95. """
  96. 执行步骤 - Trace 中的一个原子操作
  97. Step 之间通过 parent_id 形成树结构(单父节点)
  98. """
  99. step_id: str
  100. trace_id: str
  101. step_type: StepType
  102. status: Status
  103. sequence: int # 在 Trace 中的顺序
  104. # 树结构(单父节点)
  105. parent_id: Optional[str] = None
  106. # 内容
  107. description: str = "" # 所有节点都有,系统自动提取
  108. # 类型相关数据
  109. data: Dict[str, Any] = field(default_factory=dict)
  110. # 仅 evaluation 类型需要
  111. summary: Optional[str] = None
  112. # 执行指标
  113. duration_ms: Optional[int] = None
  114. tokens: Optional[int] = None
  115. cost: Optional[float] = None
  116. # 时间
  117. created_at: datetime = field(default_factory=datetime.now)
  118. @classmethod
  119. def create(
  120. cls,
  121. trace_id: str,
  122. step_type: StepType,
  123. sequence: int,
  124. status: Status = "completed",
  125. description: str = "",
  126. data: Dict[str, Any] = None,
  127. parent_id: Optional[str] = None,
  128. summary: Optional[str] = None,
  129. duration_ms: Optional[int] = None,
  130. tokens: Optional[int] = None,
  131. cost: Optional[float] = None,
  132. ) -> "Step":
  133. """创建新的 Step"""
  134. return cls(
  135. step_id=str(uuid.uuid4()),
  136. trace_id=trace_id,
  137. step_type=step_type,
  138. status=status,
  139. sequence=sequence,
  140. parent_id=parent_id,
  141. description=description,
  142. data=data or {},
  143. summary=summary,
  144. duration_ms=duration_ms,
  145. tokens=tokens,
  146. cost=cost,
  147. )
  148. def to_dict(self) -> Dict[str, Any]:
  149. """转换为字典"""
  150. return {
  151. "step_id": self.step_id,
  152. "trace_id": self.trace_id,
  153. "step_type": self.step_type,
  154. "status": self.status,
  155. "sequence": self.sequence,
  156. "parent_id": self.parent_id,
  157. "description": self.description,
  158. "data": self.data,
  159. "summary": self.summary,
  160. "duration_ms": self.duration_ms,
  161. "tokens": self.tokens,
  162. "cost": self.cost,
  163. "created_at": self.created_at.isoformat() if self.created_at else None,
  164. }
  165. # Step.data 结构说明
  166. #
  167. # goal:
  168. # {
  169. # "description": "探索代码库",
  170. # }
  171. #
  172. # thought:
  173. # {
  174. # "content": "需要先了解项目结构...",
  175. # }
  176. #
  177. # action:
  178. # {
  179. # "tool_name": "glob_files",
  180. # "arguments": {"pattern": "**/*.py"},
  181. # }
  182. #
  183. # result:
  184. # {
  185. # "tool_name": "glob_files",
  186. # "output": ["src/main.py", ...],
  187. # "title": "找到 15 个文件",
  188. # }
  189. #
  190. # evaluation:
  191. # {
  192. # "content": "分析完成...",
  193. # }
  194. # # summary 字段存储简短总结
  195. #
  196. # response:
  197. # {
  198. # "content": "任务已完成...",
  199. # "is_final": True,
  200. # }
  201. #
  202. # feedback:
  203. # {
  204. # "target_step_id": "...",
  205. # "feedback_type": "positive" | "negative" | "correction",
  206. # "content": "..."
  207. # }
  208. #
  209. # memory_read:
  210. # {
  211. # "skills": [...],
  212. # "experiences": [...],
  213. # "skills_count": 3,
  214. # "experiences_count": 5
  215. # }
  216. #
  217. # memory_write:
  218. # {
  219. # "experience_id": "...",
  220. # "condition": "...",
  221. # "rule": "..."
  222. # }