# LLM Tool Proxy
## 1. 概述 (Overview)
本项目是一个基于 FastAPI 实现的智能LLM(大语言模型)代理服务。其核心功能是拦截发往LLM的API请求,动态地将客户端定义的`tools`(工具)信息注入到提示词(Prompt)中,然后将LLM返回的结果进行解析,将其中可能包含的工具调用(Tool Call)指令提取出来,最后以结构化的格式返回给调用者。
这使得即使底层LLM原生不支持工具调用参数,我们也能通过提示工程的方式赋予其使用工具的能力。
## 2. 设计原则 (Design Principles)
本程序在设计上严格遵循了以下原则:
- **高内聚 (High Cohesion)**: 业务逻辑被集中在服务层 (`app/services.py`) 中,与API路由和数据模型分离。
- **低耦合 (Low Coupling)**:
- API层 (`app/main.py`) 只负责路由和请求校验,不关心业务实现细节。
- 通过依赖注入 (`Depends`) 获取配置,避免了全局状态。
- LLM调用被抽象为独立的函数,方便未来切换不同的LLM后端或在测试中使用模拟(Mock)实现。
- **可测试性 (Testability)**: 项目包含了完整的单元测试和集成测试 (`tests/`),使用 `pytest` 和 `TestClient` 来确保每个模块的正确性和整体流程的稳定性。
## 3. 项目结构 (Project Structure)
```
.
├── app/ # 核心应用代码
│ ├── core/ # 配置管理
│ │ └── config.py
│ ├── main.py # FastAPI 应用实例和 API 路由
│ ├── models.py # Pydantic 数据模型
│ └── services.py # 核心业务逻辑
├── tests/ # 测试代码
│ └── test_main.py
├── .env # 环境变量文件 (需手动创建)
├── .gitignore # Git 忽略文件
├── README.md # 本文档
└── .venv/ # Python 虚拟环境 (由 uv 创建)
```
## 4. 核心逻辑详解 (Core Logic)
### 4.1. 提示词注入 (Prompt Injection)
- **实现函数**: `app.services.inject_tools_into_prompt`
- **策略**:
1. 将客户端请求中 `tools` 列表(JSON数组)序列化为格式化的JSON字符串。
2. 创建一个新的、`role` 为 `system` 的独立消息。
3. 此消息包含明确的指令,告诉LLM它拥有哪些工具以及如何通过特定的格式来调用它们。
4. **调用格式约定**: 指示LLM在需要调用工具时,必须输出一个 `{...}` 的XML标签,其中包含一个带有 `name` 和 `arguments` 字段的JSON对象。
5. 这个系统消息被插入到原始消息列表的第二个位置(索引1),然后整个修改后的消息列表被发送到真实的LLM后端。
- **目的**: 对调用者透明,将工具使用的“契约”通过上下文传递给LLM。
### 4.2. 响应解析 (Response Parsing)
- **实现函数**: `app.services.parse_llm_response`
- **策略**:
1. 使用正则表达式 (`re.search`) 在LLM返回的纯文本响应中查找 `...` 标签。
2. 如果找到,它会提取标签内的JSON字符串,并将其解析为一个结构化的 `ToolCall` 对象。此时,返回给客户端的 `ResponseMessage` 中 `tool_calls` 字段将被填充,而 `content` 字段可能为 `None`。
3. 如果未找到标签,则将LLM的全部响应视为常规的文本内容,填充 `content` 字段。
- **目的**: 将LLM的非结构化(或半结构化)输出,转换为客户端可以轻松处理的、定义良好的结构化数据。
## 5. 配置管理 (Configuration)
- 配置文件为根目录下的 `.env`。
- `app/core/config.py` 中的 `get_settings` 函数通过依赖注入的方式在每次请求时加载环境变量,确保配置的实时性和在测试中的灵活性。
- **必需变量**:
- `REAL_LLM_API_URL`: 真实LLM后端的地址。
- `REAL_LLM_API_KEY`: 用于访问真实LLM的API密钥。
## 6. 如何运行与测试 (Usage)
### 6.1. 环境设置
```bash
# 创建虚拟环境
uv venv
# 安装依赖
uv pip install fastapi uvicorn httpx pytest
```
### 6.2. 运行开发服务器
```bash
uvicorn app.main:app --reload
```
服务将运行在 `http://127.0.0.1:8000`。
### 6.3. 运行测试
```bash
# 使用 .venv 中的 python 解释器执行 pytest
.venv/bin/python -m pytest
```
## 7. API 端点示例 (API Example)
**端点**: `POST /v1/chat/completions`
**请求示例 (带工具)**:
```bash
curl -X POST "http://127.0.0.1:8000/v1/chat/completions" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "What is the weather in San Francisco?"}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather for a city",
"parameters": {}
}
}
]
}'
```
## 8. 未来升级方向 (Future Improvements)
- **支持多种LLM后端**: 修改 `call_llm_api_real` 函数,使其能根据请求参数或配置选择不同的LLM提供商。
- **更灵活的工具调用格式**: 支持除XML标签外的其他格式,例如纯JSON输出模式。
- **流式响应 (Streaming)**: 支持LLM的流式输出,并实时解析和返回给客户端。
- **错误处理增强**: 针对不同的LLM API错误码和网络问题,提供更精细的错误反馈。