使用语义路由选择不同的 Prompt 模板

8 阅读2分钟

之前写过逻辑路由,靠 LLM 判断该走哪条链,但这样每次都要多消耗一次 LLM 调用。

语义路由不一样,直接拿向量余弦相似度来判断,不走 LLM,快还省钱。

思路

先把所有 prompt 模板提前算好向量存着,用户问问题的时候,把问题也转成向量,跟模板们挨个算一下相似度,哪个分最高用哪个。

模板预处理(启动时执行一次):
  [物理模板, 数学模板]embed_documents() → 向量列表

每次提问:
  query → embed_query() → cosine_similarity() → argmax() → 选模板 → LLM

代码

先定义两个不同领域的模板:

python

physics_template = """你是一位非常聪明的物理教授。
你擅长以简洁易懂的方式回答物理问题。
当你不知道问题的答案时,你会坦率承认自己不知道。
这是一个问题:{query}"""

math_template = """你是一位非常优秀的数学家。你擅长回答数学问题。
你之所以如此优秀,是因为你能将复杂的问题分解成多个小步骤,
并且回答这些小步骤,然后将它们整合在一起回答更广泛的问题。
这是一个问题:{query}"""

模板向量只需要算一次,放在外面别放函数里,不然每次调用都重新算,浪费:

python

embeddings = QianfanEmbeddingsEndpoint()
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates)  # 提前算好

路由函数,核心就三步:

python

def prompt_router(input) -> ChatPromptTemplate:
    # 1. 算 query 的向量
    query_embedding = embeddings.embed_query(input["query"])

    # 2. 跟模板们算相似度,取最高的
    similarity = cosine_similarity([query_embedding], prompt_embeddings)[0]
    most_similar = prompt_templates[similarity.argmax()]

    print("使用数学模板" if most_similar == math_template else "使用物理模板")
    return ChatPromptTemplate.from_template(most_similar)

最后串成链,注意这里用 RunnableLambda 把普通函数包一下才能塞进 LCEL:

python

chain = (
        {"query": RunnablePassthrough()}
        | RunnableLambda(prompt_router)
        | ChatOpenAI(model="moonshot-v1-8k")
        | StrOutputParser()
)

print(chain.invoke("黑洞是什么?"))
print(chain.invoke("能介绍下余弦计算公式么?"))

和逻辑路由的区别

逻辑路由语义路由
怎么判断LLM 理解后输出分类向量余弦相似度
多一次 LLM 调用
速度
适合场景路由逻辑复杂分类明确、追求低延迟

类别少语义差异明显的时候用语义路由,逻辑复杂的时候再上 LLM 判断。