run_strict.py 8.0 KB

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