如果我在rdks100p上部署的模型,我想要兼容langchain框架,也就是初始化出来一个模型,可以适配langchain生态进行开发,前提是使用bpu算力,需要怎么实现呢?

结论

目前 RDK S100P 官方工具链尚未直接提供 LangChain 适配层,但可通过 封装 oellm_run 为 HTTP API 服务 实现兼容。核心思路是:用 Python 快速构建一个符合 OpenAI 格式的 API 服务,LangChain 可直接调用。


实现步骤

1. 封装 oellm_run 为 HTTP 服务(使用 FastAPI)

由于 oellm_run 是命令行工具,你需要编写一个 Python 脚本来启动它并处理请求。

关键点: oellm_run 默认是一次性运行(运行完就退出),为了高性能,建议将其修改为长驻服务模式(如果工具链支持)或者在 Python 中通过 stdin/stdout 与其交互。

这里提供一个基于 子进程调用 的简易实现(适合低频调用):

# app.py
from fastapi import FastAPI
from pydantic import BaseModel
import subprocess
import json

app = FastAPI()

class ChatRequest(BaseModel):
    messages: list
    model: str = "s100p-local"

@app.post("/v1/chat/completions")
async def chat(req: ChatRequest):
    # 提取用户最后一条消息 (简易处理,实际需根据模板拼接历史)
    prompt = req.messages[-1]["content"]
    
    # 构造命令 (注意:需确认 oellm_run 是否支持 stdin 或 --prompt 参数)
    # 如果不支持,可能需要通过临时文件或 pipe 传递
    cmd = [
        "./oellm_run",
        "--hbm_path", "../../model/DeepSeek_R1_Distill_Qwen_7B_1024.hbm",
        "--tokenizer_dir", "../../config/DeepSeek_R1_Distill_Qwen_7B_config/",
        "--template_path", "../../config/DeepSeek_R1_Distill_Qwen_7B_config/DeepSeek_R1_Distill_Qwen_7B.jinja",
        "--model_type", "1",
        "--prompt", prompt  # 假设支持,不支持则需改用 stdin
    ]
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
        content = result.stdout
        if result.returncode != 0:
            content = f"Error: {result.stderr}"
    except Exception as e:
        content = str(e)

    return {
        "choices": [{
            "message": {"role": "assistant", "content": content}
        }]
    }

2. 启动服务

在 RDK S100P 上安装依赖并启动:

# 安装依赖
pip install fastapi uvicorn

# 启动服务(监听 0.0.0.0:8000)
uvicorn app:app --host 0.0.0.0 --port 8000

3. LangChain 调用示例

在你的开发机(或同一网络下的其他设备)上:

from langchain_community.llms import OpenAI

# 指向 S100P 的 IP 地址
llm = OpenAI(
    openai_api_base="http://<S100P_IP>:8000/v1",
    model_name="s100p-local",
    openai_api_key="not-needed" # 本地服务可忽略
)

response = llm.invoke("你好,请介绍下 RDK S100P")
print(response)

关键注意事项与优化建议

  1. 输入格式适配(重要)

    • 需确认 oellm_run 是否支持 --prompt 参数。如果不支持,你可能需要通过 stdin 传递输入,或者修改工具链源码使其支持交互式输入。
    • 多轮对话处理:LangChain 会发送 messages 列表,你需要根据 .jinja 模板的要求,将历史对话拼接到 prompt 中再传给模型。
  2. 性能优化(必须做)

    • 模型预加载:上面的示例每次请求都启动一次 oellm_run,模型加载会非常慢(可能几十秒)。
    • 正确做法:
      • 如果官方支持 Server 模式(长驻进程),请优先使用该模式,并通过 Socket/HTTP 与其通信。
      • 如果只能命令行运行,考虑使用 Python 的 subprocess.Popen 保持进程常驻,通过 stdin/stdout 管道进行通信,避免重复加载模型。
  3. MCP 与 Tools 支持

    • LangChain 的 Tools 功能依赖于模型能返回特定的格式(如 JSON 或特定标记)。
    • 你需要在 Prompt 模板中明确指示模型输出格式,并在 API 层解析返回内容,将其转换为 LangChain 可识别的 ToolCall 对象。

替代方案(推荐优先尝试)

如果官方后续提供 ONNX Runtime 或 Triton 部署支持,可直接通过以下路径集成,性能更好且更稳定:

  1. 将模型转换为 ONNX 格式(需确认 BPU 是否支持)。
  2. 使用 Triton Inference Server 部署,原生支持 LangChain 的 TritonLLM 接口。

社区资源引导

建议: 如果你成功实现了封装,欢迎将代码开源到社区,方便后续开发者复用!目前这是一个比较新的需求,社区可能还在探索中。