No description
- 新增温度参数动态处理功能,支持客户端优先级 - 新增 _get_glm_temperature() 方法,智能选择温度参数 - 新增 test_temperature_integration.py 专门的集成测试文件 - 新增36个温度参数相关的测试用例,覆盖所有边界情况 - GLM 请求优先使用客户端温度参数,Kimi 保持配置文件温度参数 - 增强日志记录,明确显示温度参数来源 - 测试结果:182个测试用例全部通过,整体覆盖率达到87% 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|---|---|---|
| src | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| openai-streaming-format.md | ||
| plan.md | ||
| pytest.ini | ||
| README.md | ||
| requirements.txt | ||
| ruff.toml | ||
| TEST.md | ||
KLM - AI 模型融合项目
本项目用于将 GLM-4.6 高质量思维链拼接到文笔较好的 Kimi-K2-Instruct 上,达到较好的角色扮演效果。
项目概述
KLM 项目通过结合两种不同的 AI 模型优势,提供更优质的角色扮演体验:
- GLM-4.6: 提供高质量的思维链(Chain of Thought)
- Kimi-K2-Instruct: 具备优秀的文笔和表达能力
核心功能
- 思维链拼接与融合
- 模型输出优化
- 角色扮演效果增强
技术架构
项目基于 OpenAI 格式的流式返回进行处理,支持思考内容和正文内容的分离传输与重组。
工作流程图
flowchart TD
A[客户端请求<br>/v1/chat/completions] --> B[转发请求至 GLM-4.6]
B --> C{GLM-4.6 流式响应}
C --> D[第一阶段:思考内容非空<br/>正文内容为空]
D --> E[原样返回思维链内容]
E --> F{是否开始返回正文?}
F -->|否| D
F -->|是| G[第二阶段:思考内容为空<br/>正文内容非空]
G --> H[思维链已完成<br/>拼接思维链到请求消息]
H --> I[将思维链包装为<br/><thinking></thinking><br/>拼接到user角色消息]
I --> J[转发拼接后的消息<br/>至 Kimi K2 Instruct]
J --> K[接收 Kimi K2 Instruct<br/>的响应结果]
K --> L[将 Kimi K2 Instruct 结果<br/>作为正文继续返回]
L --> M[完成响应]
时序图
sequenceDiagram
participant Client as 客户端
participant API as KLM接口
participant GLM as GLM-4.6
participant Kimi as Kimi K2 Instruct
Client->>API: POST /v1/chat/completions
API->>GLM: 转发原始请求
Note over GLM: 第一阶段:返回思维链
loop 思考内容非空
GLM-->>API: 思考内容
API-->>Client: 转发思维链
end
Note over GLM: 第二阶段:返回正文
GLM-->>API: 正文内容开始
Note over API: 思维链已完成
API->>API: 将思维链包装为thinking标签
API->>API: 拼接到user角色消息中
API->>Kimi: 转发拼接后的消息
Kimi-->>API: 生成响应结果
API-->>Client: 继续返回正文内容
Note over Client,API: 流式响应完成
消息拼接机制
消息处理流程
KLM 项目的核心是智能的消息拼接机制,将 GLM-4.6 的思维链内容无缝整合到发送给 Kimi 的消息中。
拼接逻辑
当 GLM-4.6 完成思维链生成后,系统会:
- 识别用户消息:在消息列表中找到用户发送的最新消息
- 加载消息模板:从
src/utils/message_template.txt文件加载预定义的模板 - 模板格式化:使用用户输入和思维链内容填充模板中的占位符:
{user_input}:替换为用户的原始消息内容{thinking_content}:替换为 GLM-4.6 的思维链内容
- 替换用户消息:将格式化后的模板内容替换原始用户消息
- 保持其他消息不变:系统消息和助手消息保持原样
模板文件
消息模板存储在 src/utils/message_template.txt 文件中:
用户的原始输入是:
{user_input}
这是另一个模型的思考内容:
{thinking_content}
请遵循以上的思考内容,不得改变角色的心理活动,不得改变角色之间的关系,不得改变故事的情节,对细节加以润色,输出最终的结果。
代码实现
消息拼接的核心逻辑在 src/services/kimi_client.py 中:
def _load_message_template(self) -> str:
"""加载消息模板"""
try:
template_path = Path(__file__).parent.parent / "utils" / "message_template.txt"
with open(template_path, "r", encoding="utf-8") as f:
template = f.read()
return template
except Exception as e:
# 如果模板加载失败,使用默认模板
default_template = "用户的原始输入是:\n{user_input}\n\n..."
return default_template
def _wrap_thinking_content(
self, original_messages: List[ChatMessage], thinking_content: str
) -> List[ChatMessage]:
"""将思维链内容包装到用户消息中"""
for msg in original_messages:
if msg.role == "user":
# 使用模板格式化消息内容
wrapped_content = self.message_template.format(
user_input=msg.content,
thinking_content=thinking_content
)
# 创建新的消息...
消息拼接示例
假设客户端发送了以下对话:
原始对话历史:
[
{"role": "system", "content": "你是一个专业的作家助手"},
{"role": "user", "content": "请帮我写一个关于友谊的小故事"},
{"role": "assistant", "content": "我很乐意帮您写故事。您希望故事有什么特别的主题或风格吗?"}
]
新的用户请求:
{"role": "user", "content": "写一个关于两个朋友在不同城市保持友谊的故事"}
GLM-4.6 思维链生成
GLM-4.6 会生成如下思维链:
我需要写一个关于异地友谊的故事。首先考虑故事的核心要素:
1. 两位主角的背景和性格
2. 他们如何成为朋友
3. 因为什么原因分隔两地
4. 他们如何维持友谊
5. 故事的温馨结尾
我想设计一个关于大学生毕业后分别在不同城市工作,但通过定期视频通话、互相寄送礼物等方式维持深厚友谊的故事...
发送给 Kimi 的最终消息
经过 KLM 系统处理后,发送给 Kimi 的消息会变成:
[
{"role": "system", "content": "你是一个专业的作家助手"},
{"role": "user", "content": "用户的原始输入是:\n写一个关于两个朋友在不同城市保持友谊的故事\n\n这是另一个模型的思考内容:\n我需要写一个关于异地友谊的故事。首先考虑故事的核心要素:\n1. 两位主角的背景和性格\n2. 他们如何成为朋友\n3. 因为什么原因分隔两地\n4. 他们如何维持友谊\n5. 故事的温馨结尾\n\n我想设计一个关于大学生毕业后分别在不同城市工作,但通过定期视频通话、互相寄送礼物等方式维持深厚友谊的故事...\n\n请遵循以上的思考内容,不得改变角色的心理活动,不得改变角色之间的关系,不得改变故事的情节,对细节加以润色,输出最终的结果"},
{"role": "assistant", "content": "我很乐意帮您写故事。您希望故事有什么特别的主题或风格吗?"}
]
设计优势
基于模板的消息拼接方式具有以下优势:
- 模板化管理:消息格式通过模板文件管理,便于维护和修改
- 松耦合设计:代码逻辑与消息内容分离,降低系统耦合度
- 灵活配置:可通过修改模板文件调整消息格式,无需修改代码
- 容错机制:模板加载失败时自动使用默认模板,确保系统稳定性
- 可扩展性:易于添加新的占位符和模板变量
- 多语言支持:模板文件支持 UTF-8 编码,便于多语言场景应用
- 版本控制友好:模板文件可独立进行版本管理和追踪
Python 实现架构设计
推荐技术栈
Web 框架和 HTTP 处理
- FastAPI: 现代异步 Web 框架,原生支持流式响应和 OpenAPI 文档
- httpx: 异步 HTTP 客户端,用于与 GLM 和 Kimi API 通信
- uvicorn: ASGI 服务器,用于部署 FastAPI 应用
数据处理
- pydantic: 数据验证和序列化,处理 OpenAI 格式的请求/响应
- orjson: 高性能 JSON 处理,支持流式数据解析
配置和日志
- python-dotenv: 环境变量管理
- loguru: 现代化日志库
- typer: 现代化命令行界面库,用于创建开发工具和项目管理命令,如服务启动、配置验证、连接测试等
异步处理
- asyncio: Python 原生异步编程
- aiofiles: 异步文件操作
开发工具
- ruff: 代码检查和格式化(已配置)
- mypy: 静态类型检查
- pytest: 测试框架
项目目录结构
klm/
├── src/
│ ├── __init__.py
│ ├── main.py # FastAPI应用入口
│ ├── config/
│ │ ├── __init__.py
│ │ └── settings.py # 配置管理
│ ├── models/
│ │ ├── __init__.py
│ │ ├── openai.py # OpenAI格式数据模型
│ │ └── internal.py # 内部数据结构
│ ├── services/
│ │ ├── __init__.py
│ │ ├── glm_client.py # GLM-4.6客户端
│ │ ├── kimi_client.py # Kimi K2 Instruct客户端
│ │ └── fusion_service.py # 模型融合核心逻辑
│ ├── api/
│ │ ├── __init__.py
│ │ ├── v1/
│ │ │ ├── __init__.py
│ │ │ └── chat.py # /v1/chat/completions端点
│ │ └── middleware.py # 中间件
│ └── utils/
│ ├── __init__.py
│ ├── logger.py # 日志工具
│ └── streaming.py # 流式处理工具
├── tests/
│ ├── __init__.py
│ ├── test_models.py
│ ├── test_services.py
│ └── test_api.py
├── requirements.txt
├── pyproject.toml
├── .env.example
└── README.md
核心模块设计
1. 数据模型层 (models/)
- 定义 OpenAI 格式的请求/响应数据结构
- 使用 pydantic 进行数据验证
- 支持流式数据的增量更新
- 处理 reasoning_content 和 content 字段分离
2. 服务层 (services/)
- GLM 客户端: 处理与 GLM-4.6 的 API 通信,解析思维链
- Kimi 客户端: 处理与 Kimi K2 Instruct 的 API 通信
- 融合服务: 核心业务逻辑,管理两阶段请求流程
3. API 层 (api/)
- 实现 OpenAI 兼容的/v1/chat/completions 端点
- 流式响应处理
- 请求路由和中间件
4. 工具层 (utils/)
- 日志记录和监控
- 流式数据处理工具
- 通用辅助函数
技术实现要点
流式处理架构
- 使用异步生成器处理流式数据
- 实现两阶段响应的状态管理
- 确保数据传输的实时性和完整性
- 支持 reasoning_content 和 content 的无缝切换
错误处理和监控
- 全面的异常捕获和处理
- 请求链路追踪
- 性能监控和日志记录
- 优雅降级机制
配置管理
- 环境变量配置
- API 密钥安全管理
- 运行时配置热重载
技术选择说明
为什么使用 httpx 而不是 OpenAI 客户端库?
对于 KLM 这种 AI 模型融合中间件项目,推荐使用httpx + 自定义逻辑而不是 OpenAI 客户端库,原因如下:
- 完全控制: 可以精确处理每个流式数据块,支持 GLM-4.6 特有的 reasoning_content 字段
- 灵活解析: 支持自定义的数据解析和状态管理逻辑
- 状态管理: 能够实现两阶段响应的状态跟踪和思维链拼接
- 错误处理: 更细粒度的异常处理和重试机制
- 代理架构: 作为中间件,需要深度控制请求转发和响应处理流程
开发流程
代码质量保证
# 运行代码检查和格式化
ruff check --fix . --unsafe-fixes && ruff format .
测试
详细的测试指南请参考 测试文档,包含环境设置、测试命令和覆盖率要求。
快速测试命令:
# 运行所有测试(推荐)
uv run pytest tests/ -v
# 生成覆盖率报告
uv run pytest tests/ -v --cov=src --cov-report=html
# 查看未覆盖的行号
uv run pytest tests/ -v --cov=src --cov-report=term-missing
# 设置覆盖率阈值
uv run pytest tests/ -v --cov=src --cov-fail-under=80
注意: 项目已配置 pytest.ini 文件自动设置 pythonpath = src,无需手动设置 PYTHONPATH。
文档
- OpenAI 流式格式文档
- 测试指南 - 详细的测试环境设置和命令参考
使用方法
具体使用方法请参考项目文档。