run_same_trace.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. """
  2. 在同一个 Trace 内测试 Prompt Caching
  3. 测试场景:
  4. 1. 第一轮对话:创建缓存(system prompt + 工具定义)
  5. 2. 第二轮对话:命中缓存(system prompt + 工具定义 + 第一轮历史)
  6. 3. 第三轮对话:命中更多缓存(system prompt + 工具定义 + 前两轮历史)
  7. """
  8. import asyncio
  9. import os
  10. import sys
  11. from pathlib import Path
  12. sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  13. from dotenv import load_dotenv
  14. load_dotenv()
  15. import logging
  16. logging.basicConfig(level=logging.DEBUG)
  17. from agent.core.runner import AgentRunner, RunConfig
  18. from agent.trace import FileSystemTraceStore, Trace, Message
  19. from agent.llm import create_openrouter_llm_call
  20. async def main():
  21. print("=" * 60)
  22. print("同一 Trace 内的 Prompt Caching 测试")
  23. print("=" * 60)
  24. print()
  25. base_dir = Path(__file__).parent
  26. project_root = base_dir.parent.parent
  27. trace_dir = project_root / ".trace"
  28. runner = AgentRunner(
  29. trace_store=FileSystemTraceStore(base_path=str(trace_dir)),
  30. llm_call=create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5"),
  31. debug=True
  32. )
  33. # 构造 >1500 tokens 的稳定前缀
  34. stable_prefix = """你是一个专业的 AI 技术顾问,专注于软件工程和系统架构。
  35. ## 核心专业领域
  36. ### 1. 编程语言与框架
  37. - **Python**: Django, Flask, FastAPI, Celery, SQLAlchemy, Pandas, NumPy
  38. - **JavaScript/TypeScript**: React, Vue, Angular, Node.js, Express, NestJS
  39. - **Go**: Gin, Echo, gRPC, Cobra
  40. - **Rust**: Actix, Rocket, Tokio
  41. - **Java**: Spring Boot, Hibernate, Maven, Gradle
  42. ### 2. 数据库技术
  43. - **关系型数据库**: PostgreSQL, MySQL, Oracle, SQL Server
  44. - **NoSQL 数据库**: MongoDB, Redis, Cassandra, DynamoDB
  45. - **时序数据库**: InfluxDB, TimescaleDB
  46. - **图数据库**: Neo4j, ArangoDB
  47. - **搜索引擎**: Elasticsearch, Solr
  48. ### 3. 云平台与基础设施
  49. - **AWS**: EC2, S3, Lambda, RDS, DynamoDB, CloudFormation, ECS, EKS
  50. - **GCP**: Compute Engine, Cloud Storage, Cloud Functions, BigQuery, GKE
  51. - **Azure**: Virtual Machines, Blob Storage, Functions, Cosmos DB, AKS
  52. - **容器化**: Docker, Docker Compose, Podman
  53. - **编排**: Kubernetes, Helm, Istio, Linkerd
  54. ### 4. DevOps 与 CI/CD
  55. - **版本控制**: Git, GitHub, GitLab, Bitbucket
  56. - **CI/CD**: Jenkins, GitLab CI, GitHub Actions, CircleCI, Travis CI
  57. - **配置管理**: Ansible, Terraform, Puppet, Chef
  58. - **监控告警**: Prometheus, Grafana, ELK Stack, Datadog, New Relic
  59. - **日志管理**: Fluentd, Logstash, Loki
  60. ### 5. 架构模式
  61. - **微服务架构**: 服务拆分、API 网关、服务发现、熔断降级
  62. - **事件驱动架构**: 消息队列、事件溯源、CQRS
  63. - **Serverless 架构**: FaaS、BaaS、无服务器框架
  64. - **分布式系统**: CAP 理论、一致性协议、分布式事务
  65. - **高可用设计**: 负载均衡、故障转移、灾备恢复
  66. ### 6. 安全最佳实践
  67. - **认证授权**: OAuth 2.0, JWT, SAML, OpenID Connect
  68. - **加密技术**: TLS/SSL, AES, RSA, 哈希算法
  69. - **安全审计**: 漏洞扫描、渗透测试、安全合规
  70. - **数据保护**: 数据脱敏、访问控制、审计日志
  71. ### 7. 性能优化
  72. - **缓存策略**: Redis, Memcached, CDN, 浏览器缓存
  73. - **数据库优化**: 索引设计、查询优化、分库分表
  74. - **代码优化**: 算法复杂度、并发编程、异步处理
  75. - **系统调优**: 负载测试、性能分析、资源监控
  76. ### 8. 机器学习与 AI
  77. - **深度学习框架**: TensorFlow, PyTorch, Keras
  78. - **模型部署**: TensorFlow Serving, TorchServe, ONNX
  79. - **MLOps**: MLflow, Kubeflow, SageMaker
  80. - **自然语言处理**: Transformers, BERT, GPT, LangChain
  81. ## 工作原则
  82. 1. **准确性优先**: 提供经过验证的技术方案,避免误导
  83. 2. **实用导向**: 给出可直接应用的代码示例和配置
  84. 3. **最佳实践**: 遵循行业标准和社区共识
  85. 4. **安全意识**: 始终考虑安全性和隐私保护
  86. 5. **性能考虑**: 关注系统性能和资源效率
  87. 6. **可维护性**: 代码清晰、文档完善、易于扩展
  88. 7. **成本意识**: 平衡技术方案与成本投入
  89. ## 响应格式
  90. ### 问题分析
  91. - 理解用户需求和上下文
  92. - 识别关键技术挑战
  93. - 评估可行性和风险
  94. ### 解决方案
  95. - 提供清晰的实现步骤
  96. - 包含完整的代码示例
  97. - 解释关键技术点
  98. - 指出潜在问题和注意事项
  99. ### 最佳实践建议
  100. - 性能优化建议
  101. - 安全加固措施
  102. - 可扩展性考虑
  103. - 运维监控方案
  104. ### 替代方案
  105. - 列出其他可行方案
  106. - 对比优缺点
  107. - 给出选择建议
  108. ## 技术栈版本参考
  109. - Python: 3.11+
  110. - Node.js: 20 LTS
  111. - PostgreSQL: 15+
  112. - Redis: 7+
  113. - Kubernetes: 1.28+
  114. - Docker: 24+
  115. 这是一个足够长且稳定的 system prompt,用于测试 Anthropic Prompt Caching。
  116. 此内容在所有请求中保持完全一致,以确保缓存能够命中。
  117. Version: 3.0
  118. """ * 2 # 重复 2 次,确保 >1500 tokens
  119. print(f"System prompt 长度: {len(stable_prefix)} 字符")
  120. print(f"预估 tokens: ~{len(stable_prefix) // 4}")
  121. print()
  122. trace_id = None
  123. # 第一轮对话
  124. print("=" * 60)
  125. print("第 1 轮对话:创建缓存")
  126. print("=" * 60)
  127. async for item in runner.run(
  128. messages=[{"role": "user", "content": "请用一句话介绍 Python"}],
  129. config=RunConfig(
  130. system_prompt=stable_prefix,
  131. model="anthropic/claude-sonnet-4.5",
  132. temperature=0.3,
  133. max_iterations=1,
  134. enable_prompt_caching=True,
  135. name="同一Trace缓存测试"
  136. )
  137. ):
  138. if isinstance(item, Trace):
  139. trace_id = item.trace_id
  140. if item.status == "completed":
  141. print(f"\n✓ 第 1 轮完成")
  142. print(f" Total tokens: {item.total_tokens}")
  143. print(f" Cache write: {item.total_cache_creation_tokens}")
  144. print(f" Cache read: {item.total_cache_read_tokens}")
  145. print(f" Cost: ${item.total_cost:.6f}")
  146. elif isinstance(item, Message) and item.role == "assistant":
  147. print(f"\n[Response] {item.content.get('text', '')[:100]}...")
  148. print(f" Prompt tokens: {item.prompt_tokens}")
  149. print(f" Cache write: {item.cache_creation_tokens}")
  150. print(f" Cache read: {item.cache_read_tokens}")
  151. print("\n等待 2 秒...")
  152. await asyncio.sleep(2)
  153. # 第二轮对话(续跑同一个 trace)
  154. print("\n" + "=" * 60)
  155. print("第 2 轮对话:应该命中缓存(system + 第1轮历史)")
  156. print("=" * 60)
  157. async for item in runner.run(
  158. messages=[{"role": "user", "content": "请用一句话介绍 JavaScript"}],
  159. config=RunConfig(
  160. trace_id=trace_id, # 续跑同一个 trace
  161. system_prompt=stable_prefix,
  162. model="anthropic/claude-sonnet-4.5",
  163. temperature=0.3,
  164. max_iterations=1,
  165. enable_prompt_caching=True,
  166. )
  167. ):
  168. if isinstance(item, Trace) and item.status == "completed":
  169. print(f"\n✓ 第 2 轮完成")
  170. print(f" Total tokens: {item.total_tokens}")
  171. print(f" Cache write: {item.total_cache_creation_tokens}")
  172. print(f" Cache read: {item.total_cache_read_tokens}")
  173. print(f" Cost: ${item.total_cost:.6f}")
  174. elif isinstance(item, Message) and item.role == "assistant":
  175. print(f"\n[Response] {item.content.get('text', '')[:100]}...")
  176. print(f" Prompt tokens: {item.prompt_tokens}")
  177. print(f" Cache write: {item.cache_creation_tokens}")
  178. print(f" Cache read: {item.cache_read_tokens}")
  179. print("\n等待 2 秒...")
  180. await asyncio.sleep(2)
  181. # 第三轮对话(续跑同一个 trace)
  182. print("\n" + "=" * 60)
  183. print("第 3 轮对话:应该命中更多缓存(system + 前2轮历史)")
  184. print("=" * 60)
  185. async for item in runner.run(
  186. messages=[{"role": "user", "content": "请用一句话介绍 Go"}],
  187. config=RunConfig(
  188. trace_id=trace_id, # 续跑同一个 trace
  189. system_prompt=stable_prefix,
  190. model="anthropic/claude-sonnet-4.5",
  191. temperature=0.3,
  192. max_iterations=1,
  193. enable_prompt_caching=True,
  194. )
  195. ):
  196. if isinstance(item, Trace) and item.status == "completed":
  197. print(f"\n✓ 第 3 轮完成")
  198. print(f" Total tokens: {item.total_tokens}")
  199. print(f" Cache write: {item.total_cache_creation_tokens}")
  200. print(f" Cache read: {item.total_cache_read_tokens}")
  201. print(f" Cost: ${item.total_cost:.6f}")
  202. elif isinstance(item, Message) and item.role == "assistant":
  203. print(f"\n[Response] {item.content.get('text', '')[:100]}...")
  204. print(f" Prompt tokens: {item.prompt_tokens}")
  205. print(f" Cache write: {item.cache_creation_tokens}")
  206. print(f" Cache read: {item.cache_read_tokens}")
  207. print("\n" + "=" * 60)
  208. print("测试完成")
  209. print("=" * 60)
  210. print()
  211. print("预期结果:")
  212. print("- 第 1 轮:cache_write > 0(创建缓存)")
  213. print("- 第 2 轮:cache_read > 0(命中 system prompt 缓存)")
  214. print("- 第 3 轮:cache_read 更大(命中 system + 历史消息缓存)")
  215. print()
  216. print(f"Trace ID: {trace_id}")
  217. if __name__ == "__main__":
  218. asyncio.run(main())