# 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错误码和网络问题,提供更精细的错误反馈。