tamar-model-client 0.1.27__tar.gz → 0.1.30__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/PKG-INFO +588 -6
  2. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/README.md +585 -5
  3. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/setup.py +3 -1
  4. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/async_client.py +83 -40
  5. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/circuit_breaker.py +6 -3
  6. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/__init__.py +5 -1
  7. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/base_client.py +136 -40
  8. tamar_model_client-0.1.30/tamar_model_client/core/http_fallback.py +531 -0
  9. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/logging_setup.py +15 -1
  10. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/utils.py +27 -1
  11. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/error_handler.py +112 -17
  12. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/json_formatter.py +9 -0
  13. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/sync_client.py +177 -38
  14. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client.egg-info/PKG-INFO +588 -6
  15. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client.egg-info/SOURCES.txt +1 -0
  16. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client.egg-info/requires.txt +2 -0
  17. tamar_model_client-0.1.30/tests/test_circuit_breaker.py +269 -0
  18. tamar_model_client-0.1.30/tests/test_google_azure_final.py +1294 -0
  19. tamar_model_client-0.1.27/tamar_model_client/core/http_fallback.py +0 -249
  20. tamar_model_client-0.1.27/tests/test_google_azure_final.py +0 -710
  21. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/setup.cfg +0 -0
  22. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/__init__.py +0 -0
  23. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/auth.py +0 -0
  24. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/request_builder.py +0 -0
  25. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/request_id_manager.py +0 -0
  26. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/core/response_handler.py +0 -0
  27. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/enums/__init__.py +0 -0
  28. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/enums/channel.py +0 -0
  29. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/enums/invoke.py +0 -0
  30. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/enums/providers.py +0 -0
  31. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/exceptions.py +0 -0
  32. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/generated/__init__.py +0 -0
  33. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/generated/model_service_pb2.py +0 -0
  34. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/generated/model_service_pb2_grpc.py +0 -0
  35. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/logging_icons.py +0 -0
  36. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/schemas/__init__.py +0 -0
  37. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/schemas/inputs.py +0 -0
  38. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/schemas/outputs.py +0 -0
  39. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client/utils.py +0 -0
  40. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client.egg-info/dependency_links.txt +0 -0
  41. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tamar_model_client.egg-info/top_level.txt +0 -0
  42. {tamar_model_client-0.1.27 → tamar_model_client-0.1.30}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tamar-model-client
3
- Version: 0.1.27
3
+ Version: 0.1.30
4
4
  Summary: A Python SDK for interacting with the Model Manager gRPC service
5
5
  Home-page: http://gitlab.tamaredge.top/project-tap/AgentOS/model-manager-client
6
6
  Author: Oscar Ou
@@ -18,6 +18,8 @@ Requires-Dist: PyJWT
18
18
  Requires-Dist: nest_asyncio
19
19
  Requires-Dist: openai
20
20
  Requires-Dist: google-genai
21
+ Requires-Dist: requests>=2.25.0
22
+ Requires-Dist: aiohttp>=3.7.0
21
23
  Dynamic: author
22
24
  Dynamic: author-email
23
25
  Dynamic: classifier
@@ -65,11 +67,15 @@ Dynamic: summary
65
67
  - 🔄 **自动重试** 指数退避策略
66
68
 
67
69
  ### 🛡️ 生产级特性
70
+ - 🛡️ **熔断降级** 服务故障时自动切换到 HTTP
71
+ - 🚀 **快速降级** 失败立即降级,最大化成功率
68
72
  - 🔐 **JWT 认证** 安全可靠
69
73
  - 📊 **使用量追踪** Token 统计与成本计算
70
- - 🆔 **请求追踪** 唯一 request_id
71
- - ⚠️ **完善错误处理** 详细错误信息
74
+ - 🆔 **请求追踪** 唯一 request_id 和 origin_request_id 全链路追踪
75
+ - ⚠️ **完善错误处理** 详细错误信息和异常堆栈追踪
72
76
  - ✅ **类型安全** Pydantic v2 验证
77
+ - 📦 **批量降级** HTTP 降级支持批量请求
78
+ - 🔍 **结构化日志** JSON 格式日志便于监控分析
73
79
 
74
80
  ### 🚀 高性能设计
75
81
  - 🔗 **gRPC 通信** HTTP/2 长连接
@@ -87,7 +93,14 @@ pip install tamar-model-client
87
93
 
88
94
  - Python ≥ 3.8
89
95
  - 支持 Windows / Linux / macOS
90
- - 依赖项会自动安装(grpcio, pydantic, python-dotenv 等)
96
+ - 依赖项会自动安装(包括以下核心库):
97
+ - `grpcio>=1.67.1` - gRPC 通信协议
98
+ - `pydantic` - 数据验证和序列化
99
+ - `PyJWT` - JWT 认证
100
+ - `requests>=2.25.0` - HTTP 降级功能(同步)
101
+ - `aiohttp>=3.7.0` - HTTP 降级功能(异步)
102
+ - `openai` - OpenAI 服务商支持
103
+ - `google-genai` - Google AI 服务商支持
91
104
 
92
105
  ## 🏗️ 项目架构
93
106
 
@@ -103,10 +116,20 @@ tamar_model_client/
103
116
  │ ├── providers.py # AI 服务商(OpenAI, Google, Azure...)
104
117
  │ ├── invoke.py # 调用类型(generation, images...)
105
118
  │ └── channel.py # 服务通道(openai, vertexai...)
119
+ ├── 📁 core/ # 核心功能模块
120
+ │ ├── base_client.py # 客户端基类(熔断、降级、配置)
121
+ │ ├── http_fallback.py # HTTP 降级功能(支持批量请求)
122
+ │ ├── request_builder.py # 请求构建器
123
+ │ ├── response_handler.py # 响应处理器
124
+ │ ├── logging_setup.py # 结构化日志配置
125
+ │ └── utils.py # 请求ID管理和工具函数
106
126
  ├── 📄 sync_client.py # 同步客户端 TamarModelClient
107
127
  ├── 📄 async_client.py # 异步客户端 AsyncTamarModelClient
128
+ ├── 📄 error_handler.py # 增强错误处理和重试策略
129
+ ├── 📄 circuit_breaker.py # 熔断器实现
108
130
  ├── 📄 exceptions.py # 异常层级定义
109
131
  ├── 📄 auth.py # JWT 认证管理
132
+ ├── 📄 json_formatter.py # JSON 日志格式化器
110
133
  └── 📄 utils.py # 工具函数
111
134
  ```
112
135
 
@@ -339,7 +362,7 @@ async def main():
339
362
  )
340
363
 
341
364
  # 发送请求并获取响应
342
- async for r in await client.invoke(model_request):
365
+ async for r in await client.invoke(request_data):
343
366
  if r.error:
344
367
  print(f"错误: {r.error}")
345
368
  else:
@@ -496,6 +519,305 @@ response = client.invoke(
496
519
  )
497
520
  ```
498
521
 
522
+ ### 🔄 错误处理最佳实践
523
+
524
+ SDK 提供了完善的异常体系,便于精确处理不同类型的错误:
525
+
526
+ ```python
527
+ from tamar_model_client import TamarModelClient
528
+ from tamar_model_client.exceptions import (
529
+ TamarModelException,
530
+ NetworkException,
531
+ AuthenticationException,
532
+ RateLimitException,
533
+ ProviderException,
534
+ TimeoutException
535
+ )
536
+
537
+ client = TamarModelClient()
538
+
539
+ try:
540
+ response = client.invoke(request)
541
+ except TimeoutException as e:
542
+ # 处理超时错误
543
+ logger.warning(f"请求超时: {e.message}, request_id: {e.request_id}")
544
+ # 可以重试或使用更快的模型
545
+ except RateLimitException as e:
546
+ # 处理限流错误
547
+ logger.error(f"触发限流: {e.message}")
548
+ # 等待一段时间后重试
549
+ time.sleep(60)
550
+ except AuthenticationException as e:
551
+ # 处理认证错误
552
+ logger.error(f"认证失败: {e.message}")
553
+ # 检查 JWT 配置
554
+ except NetworkException as e:
555
+ # 处理网络错误(已自动重试后仍失败)
556
+ logger.error(f"网络错误: {e.message}")
557
+ # 可能需要检查网络连接或服务状态
558
+ except ProviderException as e:
559
+ # 处理提供商特定错误
560
+ logger.error(f"提供商错误: {e.message}")
561
+ # 根据错误码进行特定处理
562
+ if "insufficient_quota" in str(e):
563
+ # 切换到其他提供商
564
+ pass
565
+ except TamarModelException as e:
566
+ # 处理其他所有模型相关错误
567
+ logger.error(f"模型错误: {e.message}")
568
+ logger.error(f"错误上下文: {e.error_context}")
569
+ ```
570
+
571
+ ### 🔀 多提供商无缝切换
572
+
573
+ 轻松实现提供商之间的切换和降级:
574
+
575
+ ```python
576
+ from tamar_model_client import TamarModelClient
577
+ from tamar_model_client.schemas import ModelRequest, UserContext
578
+ from tamar_model_client.enums import ProviderType
579
+ from tamar_model_client.exceptions import ProviderException, RateLimitException
580
+
581
+ client = TamarModelClient()
582
+
583
+ # 定义提供商优先级
584
+ providers = [
585
+ (ProviderType.OPENAI, "gpt-4"),
586
+ (ProviderType.GOOGLE, "gemini-pro"),
587
+ (ProviderType.AZURE, "gpt-4o-mini")
588
+ ]
589
+
590
+ user_context = UserContext(
591
+ user_id="test_user",
592
+ org_id="test_org",
593
+ client_type="python-sdk"
594
+ )
595
+
596
+ # 尝试多个提供商直到成功
597
+ for provider, model in providers:
598
+ try:
599
+ request = ModelRequest(
600
+ provider=provider,
601
+ model=model,
602
+ messages=[{"role": "user", "content": "Hello"}] if provider != ProviderType.GOOGLE else None,
603
+ contents=[{"role": "user", "parts": [{"text": "Hello"}]}] if provider == ProviderType.GOOGLE else None,
604
+ user_context=user_context
605
+ )
606
+
607
+ response = client.invoke(request)
608
+ print(f"成功使用 {provider.value} - {model}")
609
+ print(f"响应: {response.content}")
610
+ break
611
+
612
+ except (ProviderException, RateLimitException) as e:
613
+ logger.warning(f"{provider.value} 失败: {e.message}")
614
+ continue
615
+ ```
616
+
617
+ ### 🎯 请求上下文管理
618
+
619
+ 使用上下文管理器确保资源正确释放:
620
+
621
+ ```python
622
+ from tamar_model_client import TamarModelClient, AsyncTamarModelClient
623
+ import asyncio
624
+
625
+ # 同步客户端上下文管理器
626
+ with TamarModelClient() as client:
627
+ response = client.invoke(request)
628
+ print(response.content)
629
+ # 自动调用 client.close()
630
+
631
+ # 异步客户端上下文管理器
632
+ async def async_example():
633
+ async with AsyncTamarModelClient() as client:
634
+ response = await client.invoke(request)
635
+ print(response.content)
636
+ # 自动调用 await client.close()
637
+
638
+ asyncio.run(async_example())
639
+ ```
640
+
641
+ ### ⏱️ 超时控制
642
+
643
+ 通过环境变量或代码控制请求超时:
644
+
645
+ ```python
646
+ import os
647
+ from tamar_model_client import TamarModelClient
648
+
649
+ # 方式一:环境变量设置全局超时
650
+ os.environ['MODEL_MANAGER_SERVER_GRPC_TIMEOUT'] = '30' # 30秒超时
651
+
652
+ # 方式二:创建客户端时设置
653
+ client = TamarModelClient(
654
+ server_address="localhost:50051",
655
+ timeout=30.0 # 30秒超时
656
+ )
657
+
658
+ # 处理超时
659
+ try:
660
+ response = client.invoke(request)
661
+ except TimeoutException as e:
662
+ logger.error(f"请求超时: {e.message}")
663
+ # 可以尝试更小的模型或减少 max_tokens
664
+ ```
665
+
666
+ ### 📊 性能监控与指标
667
+
668
+ 获取详细的性能指标和使用统计:
669
+
670
+ ```python
671
+ from tamar_model_client import TamarModelClient
672
+ import time
673
+
674
+ client = TamarModelClient()
675
+
676
+ # 监控单次请求性能
677
+ start_time = time.time()
678
+ response = client.invoke(request)
679
+ latency = time.time() - start_time
680
+
681
+ print(f"请求延迟: {latency:.2f}秒")
682
+ print(f"Request ID: {response.request_id}")
683
+ if response.usage:
684
+ print(f"输入 Tokens: {response.usage.prompt_tokens}")
685
+ print(f"输出 Tokens: {response.usage.completion_tokens}")
686
+ print(f"总 Tokens: {response.usage.total_tokens}")
687
+ print(f"预估成本: ${response.usage.total_cost:.4f}")
688
+
689
+ # 获取熔断器指标
690
+ metrics = client.get_resilient_metrics()
691
+ if metrics:
692
+ print(f"\n熔断器状态:")
693
+ print(f"- 状态: {metrics['circuit_state']}")
694
+ print(f"- 失败次数: {metrics['failure_count']}")
695
+ print(f"- 上次失败: {metrics['last_failure_time']}")
696
+ print(f"- HTTP降级地址: {metrics['http_fallback_url']}")
697
+ ```
698
+
699
+ ### 🔧 自定义配置示例
700
+
701
+ 灵活的配置选项满足不同场景需求:
702
+
703
+ ```python
704
+ from tamar_model_client import TamarModelClient
705
+
706
+ # 完整配置示例
707
+ client = TamarModelClient(
708
+ # 服务器配置
709
+ server_address="grpc.example.com:443",
710
+ use_tls=True,
711
+ default_authority="grpc.example.com",
712
+
713
+ # 认证配置
714
+ jwt_secret_key="your-secret-key",
715
+ jwt_expiration=3600, # 1小时过期
716
+
717
+ # 重试配置
718
+ max_retries=5,
719
+ retry_delay=1.0,
720
+
721
+ # 超时配置
722
+ timeout=60.0,
723
+
724
+ # 熔断降级配置
725
+ resilient_enabled=True,
726
+ http_fallback_url="https://backup.example.com",
727
+ circuit_breaker_threshold=3,
728
+ circuit_breaker_timeout=30
729
+ )
730
+ ```
731
+
732
+ ### 🔐 安全最佳实践
733
+
734
+ 确保 SDK 使用的安全性:
735
+
736
+ ```python
737
+ import os
738
+ from tamar_model_client import TamarModelClient
739
+
740
+ # 1. 使用环境变量存储敏感信息
741
+ os.environ['MODEL_MANAGER_SERVER_JWT_SECRET_KEY'] = os.getenv('JWT_SECRET')
742
+
743
+ # 2. 启用 TLS 加密
744
+ client = TamarModelClient(
745
+ server_address="grpc.example.com:443",
746
+ use_tls=True
747
+ )
748
+
749
+ # 3. 最小权限原则 - 只请求需要的数据
750
+ request = ModelRequest(
751
+ provider=ProviderType.OPENAI,
752
+ model="gpt-3.5-turbo",
753
+ messages=[{"role": "user", "content": "分析这段文本"}],
754
+ user_context=UserContext(
755
+ user_id="limited_user",
756
+ org_id="restricted_org",
757
+ client_type="analysis-service"
758
+ ),
759
+ max_tokens=100 # 限制输出长度
760
+ )
761
+
762
+ # 4. 审计日志
763
+ response = client.invoke(request)
764
+ logger.info(f"AI请求审计: user={request.user_context.user_id}, model={request.model}, request_id={response.request_id}")
765
+ ```
766
+
767
+ ### 🚀 并发请求优化
768
+
769
+ 高效处理大量并发请求:
770
+
771
+ ```python
772
+ import asyncio
773
+ from tamar_model_client import AsyncTamarModelClient
774
+ from tamar_model_client.schemas import ModelRequest, UserContext
775
+
776
+ async def process_batch_async(questions: list[str]):
777
+ """异步并发处理多个问题"""
778
+ async with AsyncTamarModelClient() as client:
779
+ tasks = []
780
+
781
+ for i, question in enumerate(questions):
782
+ request = ModelRequest(
783
+ provider=ProviderType.OPENAI,
784
+ model="gpt-3.5-turbo",
785
+ messages=[{"role": "user", "content": question}],
786
+ user_context=UserContext(
787
+ user_id="batch_user",
788
+ org_id="test_org",
789
+ client_type="batch-processor"
790
+ )
791
+ )
792
+
793
+ # 创建异步任务
794
+ task = asyncio.create_task(client.invoke(request))
795
+ tasks.append((i, task))
796
+
797
+ # 并发执行所有请求
798
+ results = []
799
+ for i, task in tasks:
800
+ try:
801
+ response = await task
802
+ results.append((i, response.content))
803
+ except Exception as e:
804
+ results.append((i, f"Error: {str(e)}"))
805
+
806
+ return results
807
+
808
+ # 使用示例
809
+ questions = [
810
+ "什么是人工智能?",
811
+ "解释机器学习的原理",
812
+ "深度学习和机器学习的区别",
813
+ "什么是神经网络?"
814
+ ]
815
+
816
+ results = asyncio.run(process_batch_async(questions))
817
+ for i, content in results:
818
+ print(f"问题 {i+1} 的回答: {content[:100]}...")
819
+ ```
820
+
499
821
  ## 🛠️ 高级功能
500
822
 
501
823
  ### 🔥 使用场景和最佳实践
@@ -587,6 +909,156 @@ metrics = client.get_resilient_metrics()
587
909
  # }
588
910
  ```
589
911
 
912
+ ### 🚀 快速降级功能(用户体验优化)
913
+
914
+ 在传统的熔断降级基础上,SDK 新增了快速降级功能,进一步提升用户体验:
915
+
916
+ #### 传统降级 vs 快速降级
917
+
918
+ **传统模式**:
919
+ ```
920
+ gRPC请求 → 失败 → 重试1 → 失败 → 重试2 → 失败 → ... → 重试N → 失败 → HTTP降级
921
+ 耗时:(重试次数 × 退避时间) + 降级时间 // 可能需要十几秒
922
+ ```
923
+
924
+ **快速降级模式**:
925
+ ```
926
+ gRPC请求 → 失败 → 立即HTTP降级 (或重试1次后降级)
927
+ 耗时:降级时间 // 通常1-2秒内完成
928
+ ```
929
+
930
+ #### 降级策略配置
931
+
932
+ - **立即降级错误**:`UNAVAILABLE`, `DEADLINE_EXCEEDED`, `CANCELLED` (网络问题)
933
+ - **延迟降级错误**:其他错误重试指定次数后降级
934
+ - **永不降级错误**:`UNAUTHENTICATED`, `PERMISSION_DENIED`, `INVALID_ARGUMENT` (客户端问题)
935
+
936
+ #### 批量请求降级支持
937
+
938
+ 快速降级同时支持单个请求和批量请求:
939
+
940
+ ```python
941
+ # 单个请求降级
942
+ response = client.invoke(request) # 自动降级到 /v1/invoke
943
+
944
+ # 批量请求降级
945
+ batch_response = client.invoke_batch(batch_request) # 自动降级到 /v1/batch-invoke
946
+ ```
947
+
948
+ #### 使用示例
949
+
950
+ ```python
951
+ from tamar_model_client import TamarModelClient
952
+
953
+ # 启用快速降级(通过环境变量)
954
+ # MODEL_CLIENT_FAST_FALLBACK_ENABLED=true
955
+ # MODEL_CLIENT_FALLBACK_AFTER_RETRIES=1
956
+
957
+ client = TamarModelClient()
958
+
959
+ # 正常使用,快速降级对用户透明
960
+ response = client.invoke(request)
961
+ # 如果gRPC不可用,会在1-2秒内自动切换到HTTP并返回结果
962
+ ```
963
+
964
+ #### 配置选项详解
965
+
966
+ ```bash
967
+ # 启用快速降级(默认false,建议开启)
968
+ MODEL_CLIENT_FAST_FALLBACK_ENABLED=true
969
+
970
+ # 非立即降级的错误,重试多少次后降级(默认1次)
971
+ MODEL_CLIENT_FALLBACK_AFTER_RETRIES=1
972
+
973
+ # 网络错误立即降级(默认配置)
974
+ MODEL_CLIENT_IMMEDIATE_FALLBACK_ERRORS=UNAVAILABLE,DEADLINE_EXCEEDED,CANCELLED
975
+
976
+ # 认证错误永不降级(避免无效降级)
977
+ MODEL_CLIENT_NEVER_FALLBACK_ERRORS=UNAUTHENTICATED,PERMISSION_DENIED,INVALID_ARGUMENT
978
+ ```
979
+
980
+ ### 🔍 请求追踪与监控
981
+
982
+ SDK 提供了完善的请求追踪功能,便于问题排查和性能监控:
983
+
984
+ #### 请求 ID 追踪
985
+
986
+ 每个请求都会自动生成唯一的 `request_id`,用于追踪单次请求:
987
+
988
+ ```python
989
+ from tamar_model_client import TamarModelClient
990
+ from tamar_model_client.core import generate_request_id, set_request_id
991
+
992
+ # 自动生成 request_id
993
+ response = client.invoke(request)
994
+ print(f"Request ID: {response.request_id}")
995
+
996
+ # 手动设置 request_id
997
+ custom_request_id = generate_request_id()
998
+ set_request_id(custom_request_id)
999
+ response = client.invoke(request)
1000
+ ```
1001
+
1002
+ #### 原始请求 ID 追踪
1003
+
1004
+ 对于需要跨多个服务调用的场景,可以使用 `origin_request_id` 进行全链路追踪:
1005
+
1006
+ ```python
1007
+ from tamar_model_client.core import set_origin_request_id
1008
+
1009
+ # 设置原始请求 ID(通常来自上游服务)
1010
+ set_origin_request_id("user-provided-id-123")
1011
+
1012
+ # 所有后续请求都会携带这个 origin_request_id
1013
+ response = client.invoke(request)
1014
+ ```
1015
+
1016
+ #### 结构化日志
1017
+
1018
+ 启用 JSON 日志格式后,每条日志都包含完整的追踪信息:
1019
+
1020
+ ```json
1021
+ {
1022
+ "timestamp": "2025-07-03T14:40:32.729313",
1023
+ "level": "INFO",
1024
+ "type": "request",
1025
+ "uri": "/invoke/openai/chat",
1026
+ "request_id": "448a64f4-3bb0-467c-af15-d4181d0ac499",
1027
+ "data": {
1028
+ "origin_request_id": "user-provided-id-123",
1029
+ "provider": "openai",
1030
+ "model": "gpt-4",
1031
+ "stream": false
1032
+ },
1033
+ "message": "🚀 Invoke request started"
1034
+ }
1035
+ ```
1036
+
1037
+ #### 错误追踪
1038
+
1039
+ 错误日志包含异常堆栈和完整上下文:
1040
+
1041
+ ```json
1042
+ {
1043
+ "timestamp": "2025-07-03T14:40:35.123456",
1044
+ "level": "ERROR",
1045
+ "type": "response",
1046
+ "request_id": "448a64f4-3bb0-467c-af15-d4181d0ac499",
1047
+ "data": {
1048
+ "origin_request_id": "user-provided-id-123",
1049
+ "error_code": "DEADLINE_EXCEEDED",
1050
+ "error_message": "Request timeout after 30 seconds",
1051
+ "retry_count": 2,
1052
+ "fallback_attempted": true
1053
+ },
1054
+ "exception": {
1055
+ "type": "TimeoutException",
1056
+ "message": "Request timeout after 30 seconds",
1057
+ "traceback": ["Traceback (most recent call last):", "..."]
1058
+ }
1059
+ }
1060
+ ```
1061
+
590
1062
  ### ⚠️ 注意事项
591
1063
 
592
1064
  1. **参数说明**
@@ -599,9 +1071,11 @@ metrics = client.get_resilient_metrics()
599
1071
  - 如需多实例,务必调用 `client.close()` 释放资源
600
1072
 
601
1073
  3. **错误处理**
602
- - 所有错误包含 `request_id` 用于问题追踪
1074
+ - 所有错误包含 `request_id` 和 `origin_request_id` 用于全链路问题追踪
603
1075
  - 网络错误会自动重试(指数退避)
604
1076
  - 提供商错误保留原始错误信息
1077
+ - 支持异常堆栈追踪,便于问题排查
1078
+ - 结构化 JSON 日志格式,便于监控系统集成
605
1079
 
606
1080
  ## ⚙️ 环境变量配置(推荐)
607
1081
 
@@ -614,6 +1088,11 @@ export MODEL_MANAGER_SERVER_GRPC_USE_TLS="false"
614
1088
  export MODEL_MANAGER_SERVER_GRPC_DEFAULT_AUTHORITY="localhost"
615
1089
  export MODEL_MANAGER_SERVER_GRPC_MAX_RETRIES="5"
616
1090
  export MODEL_MANAGER_SERVER_GRPC_RETRY_DELAY="1.5"
1091
+
1092
+ # 快速降级配置(可选,优化用户体验)
1093
+ export MODEL_CLIENT_FAST_FALLBACK_ENABLED="true"
1094
+ export MODEL_CLIENT_HTTP_FALLBACK_URL="http://localhost:8080"
1095
+ export MODEL_CLIENT_FALLBACK_AFTER_RETRIES="1"
617
1096
  ```
618
1097
 
619
1098
  或者本地 `.env` 文件
@@ -667,6 +1146,39 @@ MODEL_CLIENT_CIRCUIT_BREAKER_THRESHOLD=5
667
1146
 
668
1147
  # 熔断器恢复超时(秒,熔断后多久尝试恢复,默认 60)
669
1148
  MODEL_CLIENT_CIRCUIT_BREAKER_TIMEOUT=60
1149
+
1150
+
1151
+ # ========================
1152
+ # 🚀 快速降级配置(可选,优化体验)
1153
+ # ========================
1154
+
1155
+ # 是否启用快速降级功能(默认 false,建议开启)
1156
+ # 启用后,gRPC 请求失败时会立即尝试 HTTP 降级,而不是等待所有重试完成
1157
+ MODEL_CLIENT_FAST_FALLBACK_ENABLED=true
1158
+
1159
+ # 降级前的最大 gRPC 重试次数(默认 1)
1160
+ # 对于非立即降级的错误,重试指定次数后才尝试降级
1161
+ MODEL_CLIENT_FALLBACK_AFTER_RETRIES=1
1162
+
1163
+ # 立即降级的错误类型(逗号分隔,默认网络相关错误)
1164
+ # 这些错误类型会在第一次失败后立即尝试降级
1165
+ MODEL_CLIENT_IMMEDIATE_FALLBACK_ERRORS=UNAVAILABLE,DEADLINE_EXCEEDED,CANCELLED
1166
+
1167
+ # 永不降级的错误类型(逗号分隔,默认认证相关错误)
1168
+ # 这些错误类型不会触发降级,通常是客户端问题而非服务不可用
1169
+ MODEL_CLIENT_NEVER_FALLBACK_ERRORS=UNAUTHENTICATED,PERMISSION_DENIED,INVALID_ARGUMENT
1170
+
1171
+
1172
+ # ========================
1173
+ # 🔍 日志与监控配置(可选)
1174
+ # ========================
1175
+
1176
+ # 启用结构化 JSON 日志格式(默认 false,建议开启)
1177
+ # 启用后日志将以 JSON 格式输出,便于监控系统集成
1178
+ MODEL_CLIENT_ENABLE_JSON_LOGGING=true
1179
+
1180
+ # 日志级别设置(DEBUG, INFO, WARNING, ERROR,默认 INFO)
1181
+ MODEL_CLIENT_LOG_LEVEL=INFO
670
1182
  ```
671
1183
 
672
1184
  加载后,初始化时无需传参:
@@ -740,6 +1252,76 @@ twine upload dist/*
740
1252
  - **并发支持**: 1000+ 并发请求
741
1253
  - **连接复用**: HTTP/2 多路复用
742
1254
  - **自动重试**: 指数退避,最多 5 次
1255
+ - **降级时间**: 快速降级 < 2 秒内完成
1256
+ - **熔断恢复**: 自动恢复检测,60 秒周期
1257
+
1258
+ ## 🔧 故障排除
1259
+
1260
+ ### 常见问题
1261
+
1262
+ #### 1. gRPC 连接失败
1263
+ ```bash
1264
+ # 错误: failed to connect to all addresses
1265
+ # 解决方案: 检查服务地址和网络连接
1266
+ export MODEL_MANAGER_SERVER_ADDRESS="correct-host:port"
1267
+ ```
1268
+
1269
+ #### 2. JWT 认证失败
1270
+ ```bash
1271
+ # 错误: UNAUTHENTICATED
1272
+ # 解决方案: 检查 JWT 密钥或令牌
1273
+ export MODEL_MANAGER_SERVER_JWT_SECRET_KEY="your-secret-key"
1274
+ ```
1275
+
1276
+ #### 3. HTTP 降级失败
1277
+ ```bash
1278
+ # 错误: HTTP fallback URL not configured
1279
+ # 解决方案: 配置 HTTP 降级地址
1280
+ export MODEL_CLIENT_HTTP_FALLBACK_URL="http://backup-server:8080"
1281
+ ```
1282
+
1283
+ #### 4. 依赖包缺失
1284
+ ```bash
1285
+ # 错误: aiohttp library is not installed
1286
+ # 解决方案: 安装 HTTP 客户端依赖
1287
+ pip install aiohttp requests
1288
+ ```
1289
+
1290
+ ### 调试技巧
1291
+
1292
+ #### 启用详细日志
1293
+ ```python
1294
+ import logging
1295
+ logging.basicConfig(level=logging.DEBUG)
1296
+
1297
+ # 或使用环境变量
1298
+ # MODEL_CLIENT_LOG_LEVEL=DEBUG
1299
+ ```
1300
+
1301
+ #### 检查熔断器状态
1302
+ ```python
1303
+ client = TamarModelClient()
1304
+ metrics = client.get_resilient_metrics()
1305
+ print(f"Circuit state: {metrics.get('circuit_state')}")
1306
+ print(f"Failure count: {metrics.get('failure_count')}")
1307
+ ```
1308
+
1309
+ #### 追踪请求流程
1310
+ ```python
1311
+ from tamar_model_client.core import set_origin_request_id
1312
+ set_origin_request_id("debug-trace-001")
1313
+
1314
+ # 在日志中搜索这个 ID 可以看到完整请求流程
1315
+ response = client.invoke(request)
1316
+ ```
1317
+
1318
+ ### 性能优化建议
1319
+
1320
+ 1. **使用单例客户端**:避免频繁创建客户端实例
1321
+ 2. **启用快速降级**:减少用户感知的错误延迟
1322
+ 3. **合理设置超时**:根据业务需求调整超时时间
1323
+ 4. **监控熔断状态**:及时发现服务问题
1324
+ 5. **使用批量 API**:提高批量处理效率
743
1325
 
744
1326
  ## 🤝 支持与贡献
745
1327