Skip to content

cyijun/homo-sapiens

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LLM Tool Call Proxy

OpenAI兼容的LLM工具调用转发器,使得不支持原生工具调用的模型可以通过提示词工程实现function calling功能。

功能特性

  • 完全OpenAI API兼容 - 客户端无需修改代码
  • 自动工具转换 - 将tools参数转换为系统提示词(XML格式)
  • XML工具调用解析 - 解析模型输出的<tool_use>标签
  • 标准格式转换 - 转换为OpenAI tool_calls格式
  • 自定义工具占位符 - 支持YAML配置
  • 双向API Key支持 - 上游和下游都支持API Key
  • YAML配置 - 支持环境变量引用(${VAR_NAME}
  • 流式响应 - 完整SSE支持
  • FastAPI高性能 - 异步HTTP服务器
  • Python API - 可作为库使用

工作原理

客户端请求
    ↓
解析 tools 参数
    ↓
转换为XML格式系统提示词
    ↓
转发到上游LLM(如硅基流动)
    ↓
接收模型响应
    ↓
解析 <tool_use> XML标签
    ↓
转换为 OpenAI tool_calls 格式
    ↓
返回给客户端

安装

1. 克隆仓库

git clone https://github.com/your-repo/homo-sapiens.git
cd homo-sapiens

2. 安装依赖

pip install -r requirements.txt

或使用pip安装:

pip install -e .

配置

配置文件位于 config/config.yaml

# 服务器配置
server:
  host: "127.0.0.1"
  port: 8888
  api_key: "${PROXY_API_KEY:default-key}"
  require_api_key: false

# 上游LLM配置
upstream:
  url: "https://api.siliconflow.cn/v1"
  api_key: "${SILICONFLOW_API_KEY:}"
  model: "Qwen/Qwen2-7B-Instruct"
  timeout: 120

# 工具配置
tools:
  placeholder: "{tools_xml}"
  enabled: true

# 响应配置
response:
  stream_enabled: true
  stream_delay: 0

# 日志配置
logging:
  level: "INFO"

环境变量

配置文件支持环境变量引用:

  • ${VAR_NAME} - 必须设置的环境变量
  • ${VAR_NAME:default} - 可选环境变量,有默认值

示例:

# 设置上游API Key(硅基流动)
export SILICONFLOW_API_KEY="sk-xxxxx"

# 设置下游API Key(可选)
export PROXY_API_KEY="my-secret-key"

使用方法

1. 启动服务器

python -m llm_proxy.server

或使用命令:

llm-proxy

服务器将在 http://127.0.0.1:8888 启动。

2. 作为HTTP API使用

使用OpenAI SDK连接:

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8888/v1",
    api_key="default-key"
)

response = client.chat.completions.create(
    model="Qwen/Qwen2-7B-Instruct",
    messages=[
        {"role": "user", "content": "你好!"}
    ]
)

print(response.choices[0].message.content)

3. 使用工具调用

from openai import OpenAI
import json

client = OpenAI(
    base_url="http://127.0.0.1:8888/v1",
    api_key="default-key"
)

# 定义工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的当前天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称"
                    }
                },
                "required": ["city"]
            }
        }
    }
]

# 发送请求
response = client.chat.completions.create(
    model="Qwen/Qwen2-7B-Instruct",
    messages=[
        {"role": "user", "content": "北京现在天气怎么样?"}
    ],
    tools=tools
)

message = response.choices[0].message

# 检查工具调用
if message.tool_calls:
    for tool_call in message.tool_calls:
        print(f"工具: {tool_call.function.name}")
        print(f"参数: {tool_call.function.arguments}")

        # 执行工具
        args = json.loads(tool_call.function.arguments)
        result = execute_get_weather(args['city'])

        # 发送工具结果
        response_2 = client.chat.completions.create(
            model="Qwen/Qwen2-7B-Instruct",
            messages=[
                {"role": "user", "content": "北京现在天气怎么样?"},
                message,
                {
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": result
                }
            ],
            tools=tools
        )

        print(response_2.choices[0].message.content)

4. 流式响应

stream = client.chat.completions.create(
    model="Qwen/Qwen2-7B-Instruct",
    messages=[{"role": "user", "content": "介绍一下Python"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end='', flush=True)

测试

运行完整的测试套件:

# 确保设置了上游API Key
export SILICONFLOW_API_KEY="your-key"

# 启动服务器
python -m llm_proxy.server &

# 运行测试
python examples/test_proxy.py

测试包括:

  1. ✅ 简单聊天(不使用工具)
  2. ✅ 工具调用
  3. ✅ 流式响应
  4. ✅ 工具结果处理

项目结构

homo-sapiens/
├── llm_proxy/              # 主要实现
│   ├── __init__.py        # 包初始化
│   ├── server.py          # FastAPI HTTP服务器
│   ├── proxy.py           # 转发器核心逻辑
│   ├── tool_formatter.py   # 工具格式化器
│   ├── xml_parser.py       # XML解析器
│   ├── models.py          # Pydantic数据模型
│   └── config_loader.py   # YAML配置加载器
├── config/
│   └── config.yaml       # 配置文件
├── examples/              # 示例代码
│   ├── client_example.py  # 客户端示例
│   └── test_proxy.py      # 测试脚本
├── reference/            # 参考实现
│   ├── add_tools_to_prompt.py
│   └── tool_use_by_prompt_chain.txt
├── requirements.txt       # 依赖
└── pyproject.toml        # 项目配置

工具调用格式

输入格式(OpenAI标准)

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "获取天气",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string"}
          }
        }
      }
    }
  ]
}

内部格式(XML提示词)

模型会看到以下格式的提示词:

<tools>

<tool>
  <name>get_weather</name>
  <description>获取天气</description>
  <arguments>
    {"type":"object","properties":{"city":{"type":"string"}}}
  </arguments>
</tool>

</tools>

工具调用格式:
<tool_use>
  <name>{工具名称}</name>
  <arguments>{json格式参数}</arguments>
</tool_use>

输出格式(OpenAI标准)

{
  "message": {
    "role": "assistant",
    "tool_calls": [
      {
        "id": "call_abc123",
        "type": "function",
        "function": {
          "name": "get_weather",
          "arguments": "{\"city\": \"北京\"}"
        }
      }
    ]
  }
}

API端点

GET /

获取服务信息。

GET /v1/models

列出可用模型。

POST /v1/chat/completions

聊天完成接口(OpenAI兼容)。

支持参数:

  • model - 模型名称
  • messages - 消息数组
  • tools - 工具定义(可选)
  • stream - 是否流式响应(默认false)
  • temperature - 温度参数
  • max_tokens - 最大令牌数

支持的上游服务

目前已测试的上游服务:

常见问题

Q: 为什么模型不调用工具?

A: 确保上游模型有足够的上下文长度,并且系统提示词清晰。有些模型可能需要更多的提示词指导。

Q: 如何调试工具调用?

A: 查看服务器日志,可以看到转换后的请求和响应。也可以在测试脚本中添加print语句。

Q: 支持流式工具调用吗?

A: 支持。流式响应会实时解析<tool_use>标签并转换为tool_calls格式。

Q: 可以自定义工具占位符吗?

A: 可以。在config/config.yaml中修改tools.placeholder配置。

许可证

MIT License

贡献

欢迎提交Issue和Pull Request!

About

A framework for LLM without native Tool Use to use tools.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages