run.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. """
  2. 测试 Prompt Caching 功能
  3. """
  4. import asyncio
  5. import os
  6. import sys
  7. from pathlib import Path
  8. # 添加项目根目录到 Python 路径
  9. sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  10. from dotenv import load_dotenv
  11. load_dotenv()
  12. import logging
  13. # 开启 DEBUG 日志查看缓存标记
  14. logging.basicConfig(level=logging.DEBUG)
  15. from agent.core.runner import AgentRunner, RunConfig
  16. from agent.trace import FileSystemTraceStore, Trace, Message
  17. from agent.llm import create_openrouter_llm_call
  18. async def main():
  19. print("=" * 60)
  20. print("测试 Prompt Caching 功能")
  21. print("=" * 60)
  22. print()
  23. # 路径配置
  24. base_dir = Path(__file__).parent
  25. project_root = base_dir.parent.parent
  26. trace_dir = project_root / ".trace"
  27. # 创建 Runner
  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. # 准备测试消息(足够长的 system prompt)
  34. system_prompt = """你是一个专业的 AI 助手。
  35. ## 核心能力
  36. - 代码分析和生成
  37. - 问题解决和调试
  38. - 技术文档编写
  39. - 架构设计建议
  40. ## 工作原则
  41. 1. 准确性优先:确保提供的信息和代码是正确的
  42. 2. 清晰表达:用简洁明了的语言解释复杂概念
  43. 3. 实用导向:提供可直接使用的解决方案
  44. 4. 持续学习:根据反馈不断改进
  45. ## 技术栈
  46. - Python, JavaScript, TypeScript
  47. - React, Vue, Node.js
  48. - Docker, Kubernetes
  49. - PostgreSQL, MongoDB, Redis
  50. - AWS, GCP, Azure
  51. 这是一个足够长的 system prompt,用于测试 Anthropic Prompt Caching 功能。
  52. 缓存需要至少 1024 tokens 才能生效,所以我们需要让这个 prompt 足够长。
  53. """ * 3 # 重复 3 次确保足够长
  54. messages = [
  55. {"role": "user", "content": "请简单介绍一下 Python 的特点,用 3 句话概括"}
  56. ]
  57. print("第一次调用(创建缓存)...")
  58. print("-" * 60)
  59. trace_id = None
  60. iteration = 0
  61. async for item in runner.run(
  62. messages=messages,
  63. config=RunConfig(
  64. system_prompt=system_prompt,
  65. model="anthropic/claude-sonnet-4.5",
  66. temperature=0.3,
  67. max_iterations=3,
  68. enable_prompt_caching=True, # 启用缓存
  69. name="缓存测试"
  70. )
  71. ):
  72. if isinstance(item, Trace):
  73. trace_id = item.trace_id
  74. if item.status == "completed":
  75. print(f"\n✓ Trace 完成")
  76. print(f" Total tokens: {item.total_tokens}")
  77. print(f" Total cost: ${item.total_cost:.6f}")
  78. elif isinstance(item, Message):
  79. if item.role == "assistant":
  80. iteration += 1
  81. print(f"\n[Iteration {iteration}]")
  82. print(f" Prompt tokens: {item.prompt_tokens}")
  83. print(f" Completion tokens: {item.completion_tokens}")
  84. print(f" Cache creation: {item.cache_creation_tokens}")
  85. print(f" Cache read: {item.cache_read_tokens}")
  86. print(f" Cost: ${item.cost:.6f}")
  87. content = item.content
  88. if isinstance(content, dict):
  89. text = content.get("text", "")
  90. if text:
  91. preview = text[:100] + "..." if len(text) > 100 else text
  92. print(f" Response: {preview}")
  93. print()
  94. print("=" * 60)
  95. print("测试完成")
  96. print("=" * 60)
  97. print()
  98. if trace_id:
  99. print("验证要点:")
  100. print("1. 第一次调用应该有 cache_creation_tokens > 0")
  101. print("2. 后续调用应该有 cache_read_tokens > 0")
  102. print("3. cache_read_tokens 的成本应该是正常 input tokens 的 10%")
  103. print()
  104. print(f"Trace ID: {trace_id}")
  105. if __name__ == "__main__":
  106. asyncio.run(main())