2025-12-31 06:35:08 +00:00

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/),使用 pytestTestClient 来确保每个模块的正确性和整体流程的稳定性。

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. 创建一个新的、rolesystem 的独立消息。
    3. 此消息包含明确的指令告诉LLM它拥有哪些工具以及如何通过特定的格式来调用它们。
    4. 调用格式约定: 指示LLM在需要调用工具时必须输出一个 <tool_call>{...}</tool_call> 的XML标签其中包含一个带有 namearguments 字段的JSON对象。
    5. 这个系统消息被插入到原始消息列表的第二个位置索引1然后整个修改后的消息列表被发送到真实的LLM后端。
  • 目的: 对调用者透明将工具使用的“契约”通过上下文传递给LLM。

4.2. 响应解析 (Response Parsing)

  • 实现函数: app.services.parse_llm_response
  • 策略:
    1. 使用正则表达式 (re.search) 在LLM返回的纯文本响应中查找 <tool_call>...</tool_call> 标签。
    2. 如果找到它会提取标签内的JSON字符串并将其解析为一个结构化的 ToolCall 对象。此时,返回给客户端的 ResponseMessagetool_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. 环境设置

# 创建虚拟环境
uv venv

# 安装依赖
uv pip install fastapi uvicorn httpx pytest

6.2. 运行开发服务器

uvicorn app.main:app --reload

服务将运行在 http://127.0.0.1:8000

6.3. 运行测试

# 使用 .venv 中的 python 解释器执行 pytest
.venv/bin/python -m pytest

7. API 端点示例 (API Example)

端点: POST /v1/chat/completions

请求示例 (带工具):

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错误码和网络问题提供更精细的错误反馈。
Description
No description provided
Readme 129 KiB
Languages
Python 99.7%
Dockerfile 0.3%